wined3d: Only copy the depth buffer if there is one.
[wine/multimedia.git] / dlls / wined3d / drawprim.c
blobb3ee4ce45b7fc508fbf32df3d231f6a8de310694
1 /*
2 * WINED3D draw functions
4 * Copyright 2002-2004 Jason Edmeades
5 * Copyright 2002-2004 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
8 * Copyright 2006 Henri Verbeet
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wined3d_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw);
29 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
30 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
32 #include <stdio.h>
34 #if 0 /* TODO */
35 extern IWineD3DVertexShaderImpl* VertexShaders[64];
36 extern IWineD3DVertexDeclarationImpl* VertexShaderDeclarations[64];
37 extern IWineD3DPixelShaderImpl* PixelShaders[64];
39 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
40 #endif
42 /* Issues the glBegin call for gl given the primitive type and count */
43 static DWORD primitiveToGl(WINED3DPRIMITIVETYPE PrimitiveType,
44 DWORD NumPrimitives,
45 GLenum *primType)
47 DWORD NumVertexes = NumPrimitives;
49 switch (PrimitiveType) {
50 case WINED3DPT_POINTLIST:
51 TRACE("POINTS\n");
52 *primType = GL_POINTS;
53 NumVertexes = NumPrimitives;
54 break;
56 case WINED3DPT_LINELIST:
57 TRACE("LINES\n");
58 *primType = GL_LINES;
59 NumVertexes = NumPrimitives * 2;
60 break;
62 case WINED3DPT_LINESTRIP:
63 TRACE("LINE_STRIP\n");
64 *primType = GL_LINE_STRIP;
65 NumVertexes = NumPrimitives + 1;
66 break;
68 case WINED3DPT_TRIANGLELIST:
69 TRACE("TRIANGLES\n");
70 *primType = GL_TRIANGLES;
71 NumVertexes = NumPrimitives * 3;
72 break;
74 case WINED3DPT_TRIANGLESTRIP:
75 TRACE("TRIANGLE_STRIP\n");
76 *primType = GL_TRIANGLE_STRIP;
77 NumVertexes = NumPrimitives + 2;
78 break;
80 case WINED3DPT_TRIANGLEFAN:
81 TRACE("TRIANGLE_FAN\n");
82 *primType = GL_TRIANGLE_FAN;
83 NumVertexes = NumPrimitives + 2;
84 break;
86 default:
87 FIXME("Unhandled primitive\n");
88 *primType = GL_POINTS;
89 break;
91 return NumVertexes;
94 /* Ensure the appropriate material states are set up - only change
95 state if really required */
96 static void init_materials(IWineD3DDevice *iface, BOOL isDiffuseSupplied) {
98 BOOL requires_material_reset = FALSE;
99 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
101 if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied) {
102 /* If we have not set up the material color tracking, do it now as required */
103 glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
104 checkGLcall("glDisable GL_COLOR_MATERIAL");
105 TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
106 glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
107 checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
108 glEnable(GL_COLOR_MATERIAL);
109 checkGLcall("glEnable GL_COLOR_MATERIAL");
110 This->tracking_color = IS_TRACKING;
111 requires_material_reset = TRUE; /* Restore material settings as will be used */
113 } else if ((This->tracking_color == IS_TRACKING && !isDiffuseSupplied) ||
114 (This->tracking_color == NEEDS_TRACKING && !isDiffuseSupplied)) {
115 /* If we are tracking the current color but one isn't supplied, don't! */
116 glDisable(GL_COLOR_MATERIAL);
117 checkGLcall("glDisable GL_COLOR_MATERIAL");
118 This->tracking_color = NEEDS_TRACKING;
119 requires_material_reset = TRUE; /* Restore material settings as will be used */
121 } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied) {
122 /* No need to reset material colors since no change to gl_color_material */
123 requires_material_reset = FALSE;
125 } else if (This->tracking_color == NEEDS_DISABLE) {
126 glDisable(GL_COLOR_MATERIAL);
127 checkGLcall("glDisable GL_COLOR_MATERIAL");
128 This->tracking_color = DISABLED_TRACKING;
129 requires_material_reset = TRUE; /* Restore material settings as will be used */
132 /* Reset the material colors which may have been tracking the color*/
133 if (requires_material_reset) {
134 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->stateBlock->material.Ambient);
135 checkGLcall("glMaterialfv");
136 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->stateBlock->material.Diffuse);
137 checkGLcall("glMaterialfv");
138 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
139 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->stateBlock->material.Specular);
140 checkGLcall("glMaterialfv");
141 } else {
142 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
143 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
144 checkGLcall("glMaterialfv");
146 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->stateBlock->material.Emissive);
147 checkGLcall("glMaterialfv");
152 static GLfloat invymat[16] = {
153 1.0f, 0.0f, 0.0f, 0.0f,
154 0.0f, -1.0f, 0.0f, 0.0f,
155 0.0f, 0.0f, 1.0f, 0.0f,
156 0.0f, 0.0f, 0.0f, 1.0f};
158 void d3ddevice_set_ortho(IWineD3DDeviceImpl *This) {
159 /* If the last draw was transformed as well, no need to reapply all the matrixes */
160 if ( (!This->last_was_rhw) || (This->viewport_changed) ) {
162 double X, Y, height, width, minZ, maxZ;
163 This->last_was_rhw = TRUE;
164 This->viewport_changed = FALSE;
166 /* Transformed already into viewport coordinates, so we do not need transform
167 matrices. Reset all matrices to identity and leave the default matrix in world
168 mode. */
169 glMatrixMode(GL_MODELVIEW);
170 checkGLcall("glMatrixMode(GL_MODELVIEW)");
171 glLoadIdentity();
172 checkGLcall("glLoadIdentity");
174 glMatrixMode(GL_PROJECTION);
175 checkGLcall("glMatrixMode(GL_PROJECTION)");
176 glLoadIdentity();
177 checkGLcall("glLoadIdentity");
179 /* Set up the viewport to be full viewport */
180 X = This->stateBlock->viewport.X;
181 Y = This->stateBlock->viewport.Y;
182 height = This->stateBlock->viewport.Height;
183 width = This->stateBlock->viewport.Width;
184 minZ = This->stateBlock->viewport.MinZ;
185 maxZ = This->stateBlock->viewport.MaxZ;
186 if(!This->untransformed) {
187 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
188 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
189 } else {
190 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, 1.0, -1.0);
191 glOrtho(X, X + width, Y + height, Y, 1.0, -1.0);
193 checkGLcall("glOrtho");
195 /* Window Coord 0 is the middle of the first pixel, so translate by half
196 a pixel (See comment above glTranslate below) */
197 glTranslatef(0.375, 0.375, 0);
198 checkGLcall("glTranslatef(0.375, 0.375, 0)");
199 /* D3D texture coordinates are flipped compared to OpenGL ones, so
200 * render everything upside down when rendering offscreen. */
201 if (This->render_offscreen) {
202 glMultMatrixf(invymat);
203 checkGLcall("glMultMatrixf(invymat)");
206 /* Vertex fog on transformed vertices? Use the calculated fog factor stored in the specular color */
207 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != WINED3DFOG_NONE) {
208 if(GL_SUPPORT(EXT_FOG_COORD)) {
209 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
210 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)");
211 glFogi(GL_FOG_MODE, GL_LINEAR);
212 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
213 /* The dx fog range in this case is fixed to 0 - 255,
214 * but in GL it still depends on the fog start and end (according to the ext)
215 * Use this to turn around the fog as it's needed. That prevents some
216 * calculations during drawing :-)
218 glFogf(GL_FOG_START, (float) 0xff);
219 checkGLcall("glFogfv GL_FOG_END");
220 glFogf(GL_FOG_END, 0.0);
221 checkGLcall("glFogfv GL_FOG_START");
222 } else {
223 /* Disable GL fog, handle this in software in drawStridedSlow */
224 glDisable(GL_FOG);
225 checkGLcall("glDisable(GL_FOG)");
230 /* Setup views - Transformed & lit if RHW, else untransformed.
231 Only unlit if Normals are supplied
232 Returns: Whether to restore lighting afterwards */
233 static void primitiveInitState(
234 IWineD3DDevice *iface,
235 WineDirect3DVertexStridedData* strided,
236 BOOL useVS,
237 BOOL* lighting_changed,
238 BOOL* lighting_original) {
240 BOOL fixed_vtx_transformed =
241 (strided->u.s.position.lpData != NULL || strided->u.s.position.VBO != 0 ||
242 strided->u.s.position2.lpData != NULL || strided->u.s.position2.VBO != 0) &&
243 strided->u.s.position_transformed;
245 BOOL fixed_vtx_lit =
246 strided->u.s.normal.lpData == NULL && strided->u.s.normal.VBO == 0 &&
247 strided->u.s.normal2.lpData == NULL && strided->u.s.normal2.VBO == 0;
249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 *lighting_changed = FALSE;
253 /* If no normals, DISABLE lighting otherwise, don't touch lighing as it is
254 set by the appropriate render state. Note Vertex Shader output is already lit */
255 if (fixed_vtx_lit || useVS) {
256 *lighting_changed = TRUE;
257 *lighting_original = glIsEnabled(GL_LIGHTING);
258 glDisable(GL_LIGHTING);
259 checkGLcall("glDisable(GL_LIGHTING);");
260 TRACE("Disabled lighting, old state = %d\n", *lighting_original);
263 if (!useVS && fixed_vtx_transformed) {
264 d3ddevice_set_ortho(This);
266 } else {
268 /* Untransformed, so relies on the view and projection matrices */
269 This->untransformed = TRUE;
271 if (!useVS && (This->last_was_rhw || !This->modelview_valid)) {
272 /* Only reapply when have to */
273 This->modelview_valid = TRUE;
274 glMatrixMode(GL_MODELVIEW);
275 checkGLcall("glMatrixMode");
277 /* In the general case, the view matrix is the identity matrix */
278 if (This->view_ident) {
279 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]);
280 checkGLcall("glLoadMatrixf");
281 } else {
282 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
283 checkGLcall("glLoadMatrixf");
284 glMultMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]);
285 checkGLcall("glMultMatrixf");
289 if (!useVS && (This->last_was_rhw || !This->proj_valid)) {
290 /* Only reapply when have to */
291 This->proj_valid = TRUE;
292 glMatrixMode(GL_PROJECTION);
293 checkGLcall("glMatrixMode");
295 /* The rule is that the window coordinate 0 does not correspond to the
296 beginning of the first pixel, but the center of the first pixel.
297 As a consequence if you want to correctly draw one line exactly from
298 the left to the right end of the viewport (with all matrices set to
299 be identity), the x coords of both ends of the line would be not
300 -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
301 instead. */
302 glLoadIdentity();
304 glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
305 checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
307 /* D3D texture coordinates are flipped compared to OpenGL ones, so
308 * render everything upside down when rendering offscreen. */
309 if (This->render_offscreen) {
310 glMultMatrixf(invymat);
311 checkGLcall("glMultMatrixf(invymat)");
313 glMultMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_PROJECTION].u.m[0][0]);
314 checkGLcall("glLoadMatrixf");
317 /* Vertex Shader output is already transformed, so set up identity matrices */
318 if (useVS) {
319 This->posFixup[1] = This->render_offscreen ? -1.0 : 1.0;
320 This->posFixup[2] = 0.9 / This->stateBlock->viewport.Width;
321 This->posFixup[3] = -0.9 / This->stateBlock->viewport.Height;
323 This->last_was_rhw = FALSE;
325 /* Setup fogging */
326 if (useVS && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->usesFog) {
327 /* In D3D vertex shader return the 'final' fog value, while in OpenGL it is the 'input' fog value.
328 * The code below 'disables' the OpenGL postprocessing by setting the formula to '1'. */
329 glFogi(GL_FOG_MODE, GL_LINEAR);
330 glFogf(GL_FOG_START, 1.0f);
331 glFogf(GL_FOG_END, 0.0f);
333 } else if(This->stateBlock->renderState[WINED3DRS_FOGENABLE]
334 && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != WINED3DFOG_NONE) {
336 if(GL_SUPPORT(EXT_FOG_COORD)) {
337 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
338 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT)\n");
339 /* Reapply the fog range */
340 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
341 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
342 /* Restore the fog mode */
343 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGTABLEMODE, This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
344 } else {
345 /* Enable GL_FOG again because we disabled it above */
346 glEnable(GL_FOG);
347 checkGLcall("glEnable(GL_FOG)");
353 static BOOL fixed_get_input(
354 BYTE usage, BYTE usage_idx,
355 unsigned int* regnum) {
357 *regnum = -1;
359 /* Those positions must have the order in the
360 * named part of the strided data */
362 if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 0)
363 *regnum = 0;
364 else if (usage == D3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
365 *regnum = 1;
366 else if (usage == D3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
367 *regnum = 2;
368 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 0)
369 *regnum = 3;
370 else if (usage == D3DDECLUSAGE_PSIZE && usage_idx == 0)
371 *regnum = 4;
372 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 0)
373 *regnum = 5;
374 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 1)
375 *regnum = 6;
376 else if (usage == D3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
377 *regnum = 7 + usage_idx;
378 else if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 1)
379 *regnum = 7 + WINED3DDP_MAXTEXCOORD;
380 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 1)
381 *regnum = 8 + WINED3DDP_MAXTEXCOORD;
382 else if (usage == D3DDECLUSAGE_TANGENT && usage_idx == 0)
383 *regnum = 9 + WINED3DDP_MAXTEXCOORD;
384 else if (usage == D3DDECLUSAGE_BINORMAL && usage_idx == 0)
385 *regnum = 10 + WINED3DDP_MAXTEXCOORD;
386 else if (usage == D3DDECLUSAGE_TESSFACTOR && usage_idx == 0)
387 *regnum = 11 + WINED3DDP_MAXTEXCOORD;
388 else if (usage == D3DDECLUSAGE_FOG && usage_idx == 0)
389 *regnum = 12 + WINED3DDP_MAXTEXCOORD;
390 else if (usage == D3DDECLUSAGE_DEPTH && usage_idx == 0)
391 *regnum = 13 + WINED3DDP_MAXTEXCOORD;
392 else if (usage == D3DDECLUSAGE_SAMPLE && usage_idx == 0)
393 *regnum = 14 + WINED3DDP_MAXTEXCOORD;
395 if (*regnum < 0) {
396 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n",
397 debug_d3ddeclusage(usage), usage_idx);
398 return FALSE;
400 return TRUE;
403 void primitiveDeclarationConvertToStridedData(
404 IWineD3DDevice *iface,
405 BOOL useVertexShaderFunction,
406 WineDirect3DVertexStridedData *strided,
407 LONG BaseVertexIndex,
408 BOOL *fixup) {
410 /* We need to deal with frequency data!*/
412 BYTE *data = NULL;
413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
414 IWineD3DVertexDeclarationImpl* vertexDeclaration = NULL;
415 int i;
416 WINED3DVERTEXELEMENT *element;
417 DWORD stride;
418 int reg;
420 /* Locate the vertex declaration */
421 if (This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration) {
422 TRACE("Using vertex declaration from shader\n");
423 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration;
424 } else {
425 TRACE("Using vertex declaration\n");
426 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
429 /* Translate the declaration into strided data */
430 for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
431 GLint streamVBO = 0;
432 BOOL stride_used;
433 unsigned int idx;
435 element = vertexDeclaration->pDeclarationWine + i;
436 TRACE("%p Element %p (%d of %d)\n", vertexDeclaration->pDeclarationWine,
437 element, i + 1, vertexDeclaration->declarationWNumElements - 1);
439 if (This->stateBlock->streamSource[element->Stream] == NULL)
440 continue;
442 if (This->stateBlock->streamIsUP) {
443 TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
444 streamVBO = 0;
445 data = (BYTE *)This->stateBlock->streamSource[element->Stream];
446 if(fixup && *fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
447 } else {
448 TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
449 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[element->Stream]);
450 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
451 if(fixup) {
452 if( streamVBO != 0) *fixup = TRUE;
453 else if(*fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
456 stride = This->stateBlock->streamStride[element->Stream];
457 data += (BaseVertexIndex * stride);
458 data += element->Offset;
459 reg = element->Reg;
461 TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex);
463 if (useVertexShaderFunction)
464 stride_used = vshader_get_input(This->stateBlock->vertexShader,
465 element->Usage, element->UsageIndex, &idx);
466 else
467 stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
469 if (stride_used) {
470 TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
471 "stream=%u, offset=%u, stride=%u, VBO=%u]\n",
472 useVertexShaderFunction? "shader": "fixed function", idx,
473 debug_d3ddeclusage(element->Usage), element->UsageIndex,
474 element->Stream, element->Offset, stride, streamVBO);
476 strided->u.input[idx].lpData = data;
477 strided->u.input[idx].dwType = element->Type;
478 strided->u.input[idx].dwStride = stride;
479 strided->u.input[idx].VBO = streamVBO;
480 if (!useVertexShaderFunction) {
481 if (element->Usage == D3DDECLUSAGE_POSITION)
482 strided->u.s.position_transformed = FALSE;
483 else if (element->Usage == D3DDECLUSAGE_POSITIONT)
484 strided->u.s.position_transformed = TRUE;
490 void primitiveConvertFVFtoOffset(DWORD thisFVF, DWORD stride, BYTE *data, WineDirect3DVertexStridedData *strided, GLint streamVBO) {
491 int numBlends;
492 int numTextures;
493 int textureNo;
494 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
495 int numCoords[8]; /* Holding place for WINED3DFVF_TEXTUREFORMATx */
497 /* Either 3 or 4 floats depending on the FVF */
498 /* FIXME: Can blending data be in a different stream to the position data?
499 and if so using the fixed pipeline how do we handle it */
500 if (thisFVF & WINED3DFVF_POSITION_MASK) {
501 strided->u.s.position.lpData = data;
502 strided->u.s.position.dwType = WINED3DDECLTYPE_FLOAT3;
503 strided->u.s.position.dwStride = stride;
504 strided->u.s.position.VBO = streamVBO;
505 data += 3 * sizeof(float);
506 if (thisFVF & WINED3DFVF_XYZRHW) {
507 strided->u.s.position.dwType = WINED3DDECLTYPE_FLOAT4;
508 strided->u.s.position_transformed = TRUE;
509 data += sizeof(float);
510 } else
511 strided->u.s.position_transformed = FALSE;
514 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
515 /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
516 numBlends = 1 + (((thisFVF & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
517 if(thisFVF & WINED3DFVF_LASTBETA_UBYTE4) numBlends--;
519 if ((thisFVF & WINED3DFVF_XYZB5 ) > WINED3DFVF_XYZRHW) {
520 TRACE("Setting blend Weights to %p\n", data);
521 strided->u.s.blendWeights.lpData = data;
522 strided->u.s.blendWeights.dwType = WINED3DDECLTYPE_FLOAT1 + numBlends - 1;
523 strided->u.s.blendWeights.dwStride = stride;
524 strided->u.s.blendWeights.VBO = streamVBO;
525 data += numBlends * sizeof(FLOAT);
527 if (thisFVF & WINED3DFVF_LASTBETA_UBYTE4) {
528 strided->u.s.blendMatrixIndices.lpData = data;
529 strided->u.s.blendMatrixIndices.dwType = WINED3DDECLTYPE_UBYTE4;
530 strided->u.s.blendMatrixIndices.dwStride= stride;
531 strided->u.s.blendMatrixIndices.VBO = streamVBO;
532 data += sizeof(DWORD);
536 /* Normal is always 3 floats */
537 if (thisFVF & WINED3DFVF_NORMAL) {
538 strided->u.s.normal.lpData = data;
539 strided->u.s.normal.dwType = WINED3DDECLTYPE_FLOAT3;
540 strided->u.s.normal.dwStride = stride;
541 strided->u.s.normal.VBO = streamVBO;
542 data += 3 * sizeof(FLOAT);
545 /* Pointsize is a single float */
546 if (thisFVF & WINED3DFVF_PSIZE) {
547 strided->u.s.pSize.lpData = data;
548 strided->u.s.pSize.dwType = WINED3DDECLTYPE_FLOAT1;
549 strided->u.s.pSize.dwStride = stride;
550 strided->u.s.pSize.VBO = streamVBO;
551 data += sizeof(FLOAT);
554 /* Diffuse is 4 unsigned bytes */
555 if (thisFVF & WINED3DFVF_DIFFUSE) {
556 strided->u.s.diffuse.lpData = data;
557 strided->u.s.diffuse.dwType = WINED3DDECLTYPE_SHORT4;
558 strided->u.s.diffuse.dwStride = stride;
559 strided->u.s.diffuse.VBO = streamVBO;
560 data += sizeof(DWORD);
563 /* Specular is 4 unsigned bytes */
564 if (thisFVF & WINED3DFVF_SPECULAR) {
565 strided->u.s.specular.lpData = data;
566 strided->u.s.specular.dwType = WINED3DDECLTYPE_SHORT4;
567 strided->u.s.specular.dwStride = stride;
568 strided->u.s.specular.VBO = streamVBO;
569 data += sizeof(DWORD);
572 /* Texture coords */
573 numTextures = (thisFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
574 coordIdxInfo = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of WINED3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
576 /* numTextures indicates the number of texture coordinates supplied */
577 /* However, the first set may not be for stage 0 texture - it all */
578 /* depends on WINED3DTSS_TEXCOORDINDEX. */
579 /* The number of bytes for each coordinate set is based off */
580 /* WINED3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
582 /* So, for each supplied texture extract the coords */
583 for (textureNo = 0; textureNo < numTextures; ++textureNo) {
585 strided->u.s.texCoords[textureNo].lpData = data;
586 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT1;
587 strided->u.s.texCoords[textureNo].dwStride = stride;
588 strided->u.s.texCoords[textureNo].VBO = streamVBO;
589 numCoords[textureNo] = coordIdxInfo & 0x03;
591 /* Always one set */
592 data += sizeof(float);
593 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT1) {
594 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT2;
595 data += sizeof(float);
596 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT2) {
597 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT3;
598 data += sizeof(float);
599 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT3) {
600 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT4;
601 data += sizeof(float);
605 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
609 void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *strided, LONG BaseVertexIndex, BOOL *fixup) {
611 short LoopThroughTo = 0;
612 short nStream;
613 GLint streamVBO = 0;
615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
617 /* OK, Now to setup the data locations
618 For the non-created vertex shaders, the VertexShader var holds the real
619 FVF and only stream 0 matters
620 For the created vertex shaders, there is an FVF per stream */
621 if (!This->stateBlock->streamIsUP && !(This->stateBlock->vertexShader == NULL)) {
622 LoopThroughTo = MAX_STREAMS;
623 } else {
624 LoopThroughTo = 1;
627 /* Work through stream by stream */
628 for (nStream=0; nStream<LoopThroughTo; ++nStream) {
629 DWORD stride = This->stateBlock->streamStride[nStream];
630 BYTE *data = NULL;
631 DWORD thisFVF = 0;
633 /* Skip empty streams */
634 if (This->stateBlock->streamSource[nStream] == NULL) continue;
636 /* Retrieve appropriate FVF */
637 if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
638 thisFVF = This->stateBlock->fvf;
639 /* Handle memory passed directly as well as vertex buffers */
640 if (This->stateBlock->streamIsUP) {
641 streamVBO = 0;
642 data = (BYTE *)This->stateBlock->streamSource[nStream];
643 } else {
644 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[nStream]);
645 /* GetMemory binds the VBO */
646 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0, &streamVBO);
647 if(fixup) {
648 if(streamVBO != 0 ) *fixup = TRUE;
651 } else {
652 #if 0 /* TODO: Vertex shader support */
653 thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
654 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
655 #endif
657 VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
658 if (thisFVF == 0) continue;
660 /* Now convert the stream into pointers */
662 /* Shuffle to the beginning of the vertexes to render and index from there */
663 data = data + (BaseVertexIndex * stride);
665 primitiveConvertFVFtoOffset(thisFVF, stride, data, strided, streamVBO);
669 #if 0 /* TODO: Software Shaders */
670 /* Draw a single vertex using this information */
671 static void draw_vertex(IWineD3DDevice *iface, /* interface */
672 BOOL isXYZ, float x, float y, float z, float rhw, /* xyzn position*/
673 BOOL isNormal, float nx, float ny, float nz, /* normal */
674 BOOL isDiffuse, float *dRGBA, /* 1st colors */
675 BOOL isSpecular, float *sRGB, /* 2ndry colors */
676 BOOL isPtSize, float ptSize, /* pointSize */
677 WINED3DVECTOR_4 *texcoords, int *numcoords) /* texture info */
679 unsigned int textureNo;
680 float s, t, r, q;
681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
683 /* Diffuse -------------------------------- */
684 if (isDiffuse) {
685 glColor4fv(dRGBA);
686 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
689 /* Specular Colour ------------------------------------------*/
690 if (isSpecular) {
691 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
692 GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
693 VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
694 } else {
695 VTRACE(("Specular color extensions not supplied\n"));
699 /* Normal -------------------------------- */
700 if (isNormal) {
701 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
702 glNormal3f(nx, ny, nz);
705 /* Point Size ----------------------------------------------*/
706 if (isPtSize) {
708 /* no such functionality in the fixed function GL pipeline */
709 FIXME("Cannot change ptSize here in openGl\n");
712 /* Texture coords --------------------------- */
713 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
715 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
716 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
717 continue ;
720 /* Query tex coords */
721 if (This->stateBlock->textures[textureNo] != NULL) {
723 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
724 if (coordIdx >= MAX_TEXTURES) {
725 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
726 continue;
727 } else if (numcoords[coordIdx] == 0) {
728 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
729 continue;
730 } else {
732 /* Initialize vars */
733 s = 0.0f;
734 t = 0.0f;
735 r = 0.0f;
736 q = 0.0f;
738 switch (numcoords[coordIdx]) {
739 case 4: q = texcoords[coordIdx].w; /* drop through */
740 case 3: r = texcoords[coordIdx].z; /* drop through */
741 case 2: t = texcoords[coordIdx].y; /* drop through */
742 case 1: s = texcoords[coordIdx].x;
745 switch (numcoords[coordIdx]) { /* Supply the provided texture coords */
746 case WINED3DTTFF_COUNT1:
747 VTRACE(("tex:%d, s=%f\n", textureNo, s));
748 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
749 GLMULTITEXCOORD1F(textureNo, s);
750 } else {
751 glTexCoord1f(s);
753 break;
754 case WINED3DTTFF_COUNT2:
755 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
756 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
757 GLMULTITEXCOORD2F(textureNo, s, t);
758 } else {
759 glTexCoord2f(s, t);
761 break;
762 case WINED3DTTFF_COUNT3:
763 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
764 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
765 GLMULTITEXCOORD3F(textureNo, s, t, r);
766 } else {
767 glTexCoord3f(s, t, r);
769 break;
770 case WINED3DTTFF_COUNT4:
771 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
772 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
773 GLMULTITEXCOORD4F(textureNo, s, t, r, q);
774 } else {
775 glTexCoord4f(s, t, r, q);
777 break;
778 default:
779 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
783 } /* End of textures */
785 /* Position -------------------------------- */
786 if (isXYZ) {
787 if (1.0f == rhw || rhw < 0.00001f) {
788 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
789 glVertex3f(x, y, z);
790 } else {
791 /* Cannot optimize by dividing through by rhw as rhw is required
792 later for perspective in the GL pipeline for vertex shaders */
793 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
794 glVertex4f(x,y,z,rhw);
798 #endif /* TODO: Software shaders */
800 /* This should match any arrays loaded in loadNumberedArrays. */
801 /* TODO: Only load / unload arrays if we have to. */
802 static void unloadNumberedArrays(IWineD3DDevice *iface) {
803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
805 /* disable any attribs (this is the same for both GLSL and ARB modes) */
806 GLint maxAttribs;
807 int i;
809 /* Leave all the attribs disabled */
810 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
811 /* MESA does not support it right not */
812 if (glGetError() != GL_NO_ERROR)
813 maxAttribs = 16;
814 for (i = 0; i < maxAttribs; ++i) {
815 GL_EXTCALL(glDisableVertexAttribArrayARB(i));
816 checkGLcall("glDisableVertexAttribArrayARB(reg);");
820 /* TODO: Only load / unload arrays if we have to. */
821 static void loadNumberedArrays(
822 IWineD3DDevice *iface,
823 IWineD3DVertexShader *shader,
824 WineDirect3DVertexStridedData *strided) {
826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
827 GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0;
828 int i;
830 for (i = 0; i < MAX_ATTRIBS; i++) {
832 if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
833 continue;
835 TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
837 if(curVBO != strided->u.input[i].VBO) {
838 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, strided->u.input[i].VBO));
839 checkGLcall("glBindBufferARB");
840 curVBO = strided->u.input[i].VBO;
842 GL_EXTCALL(glVertexAttribPointerARB(i,
843 WINED3D_ATR_SIZE(strided->u.input[i].dwType),
844 WINED3D_ATR_GLTYPE(strided->u.input[i].dwType),
845 WINED3D_ATR_NORMALIZED(strided->u.input[i].dwType),
846 strided->u.input[i].dwStride,
847 strided->u.input[i].lpData));
848 GL_EXTCALL(glEnableVertexAttribArrayARB(i));
852 /* This should match any arrays loaded in loadVertexData. */
853 /* TODO: Only load / unload arrays if we have to. */
854 static void unloadVertexData(IWineD3DDevice *iface) {
855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
856 int texture_idx;
858 glDisableClientState(GL_VERTEX_ARRAY);
859 glDisableClientState(GL_NORMAL_ARRAY);
860 glDisableClientState(GL_COLOR_ARRAY);
861 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
862 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
864 for (texture_idx = 0; texture_idx < GL_LIMITS(textures); ++texture_idx) {
865 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
866 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
870 /* TODO: Only load / unload arrays if we have to. */
871 static void loadVertexData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd) {
872 unsigned int textureNo = 0;
873 unsigned int texture_idx = 0;
874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
875 GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0;
877 TRACE("Using fast vertex array code\n");
878 /* Blend Data ---------------------------------------------- */
879 if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) ||
880 (sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) {
883 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
885 #if 1
886 glEnableClientState(GL_WEIGHT_ARRAY_ARB);
887 checkGLcall("glEnableClientState(GL_WEIGHT_ARRAY_ARB)");
888 #endif
890 TRACE("Blend %d %p %d\n", WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
891 sd->u.s.blendWeights.lpData, sd->u.s.blendWeights.dwStride);
892 /* FIXME("TODO\n");*/
893 /* Note dwType == float3 or float4 == 2 or 3 */
895 #if 0
896 /* with this on, the normals appear to be being modified,
897 but the vertices aren't being translated as they should be
898 Maybe the world matrix aren't being setup properly? */
899 glVertexBlendARB(WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) + 1);
900 #endif
903 VTRACE(("glWeightPointerARB(%d, GL_FLOAT, %d, %p)\n",
904 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) ,
905 sd->u.s.blendWeights.dwStride,
906 sd->u.s.blendWeights.lpData));
908 if(curVBO != sd->u.s.blendWeights.VBO) {
909 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.blendWeights.VBO));
910 checkGLcall("glBindBufferARB");
911 curVBO = sd->u.s.blendWeights.VBO;
914 GL_EXTCALL(glWeightPointerARB)(
915 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
916 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
917 sd->u.s.blendWeights.dwStride,
918 sd->u.s.blendWeights.lpData);
920 checkGLcall("glWeightPointerARB");
922 if((sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO)){
923 static BOOL showfixme = TRUE;
924 if(showfixme){
925 FIXME("blendMatrixIndices support\n");
926 showfixme = FALSE;
930 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
931 /* FIXME("TODO\n");*/
932 #if 0
934 GL_EXTCALL(glVertexWeightPointerEXT)(
935 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
936 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
937 sd->u.s.blendWeights.dwStride,
938 sd->u.s.blendWeights.lpData);
939 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
940 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
941 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
942 #endif
944 } else {
945 /* TODO: support blends in fixupVertices */
946 FIXME("unsupported blending in openGl\n");
948 } else {
949 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
950 #if 0 /* TODO: Vertex blending */
951 glDisable(GL_VERTEX_BLEND_ARB);
952 #endif
953 TRACE("ARB_VERTEX_BLEND\n");
954 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
955 TRACE(" EXT_VERTEX_WEIGHTING\n");
956 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
957 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
962 #if 0 /* FOG ----------------------------------------------*/
963 if (sd->u.s.fog.lpData || sd->u.s.fog.VBO) {
964 /* TODO: fog*/
965 if (GL_SUPPORT(EXT_FOG_COORD) {
966 glEnableClientState(GL_FOG_COORDINATE_EXT);
967 (GL_EXTCALL)(FogCoordPointerEXT)(
968 WINED3D_ATR_GLTYPE(sd->u.s.fog.dwType),
969 sd->u.s.fog.dwStride,
970 sd->u.s.fog.lpData);
971 } else {
972 /* don't bother falling back to 'slow' as we don't support software FOG yet. */
973 /* FIXME: fixme once */
974 TRACE("Hardware support for FOG is not avaiable, FOG disabled.\n");
976 } else {
977 if (GL_SUPPRT(EXT_FOR_COORD) {
978 /* make sure fog is disabled */
979 glDisableClientState(GL_FOG_COORDINATE_EXT);
982 #endif
984 #if 0 /* tangents ----------------------------------------------*/
985 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO ||
986 sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
987 /* TODO: tangents*/
988 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
989 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO) {
990 glEnable(GL_TANGENT_ARRAY_EXT);
991 (GL_EXTCALL)(TangentPointerEXT)(
992 WINED3D_ATR_GLTYPE(sd->u.s.tangent.dwType),
993 sd->u.s.tangent.dwStride,
994 sd->u.s.tangent.lpData);
995 } else {
996 glDisable(GL_TANGENT_ARRAY_EXT);
998 if (sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
999 glEnable(GL_BINORMAL_ARRAY_EXT);
1000 (GL_EXTCALL)(BinormalPointerEXT)(
1001 WINED3D_ATR_GLTYPE(sd->u.s.binormal.dwType),
1002 sd->u.s.binormal.dwStride,
1003 sd->u.s.binormal.lpData);
1004 } else{
1005 glDisable(GL_BINORMAL_ARRAY_EXT);
1008 } else {
1009 /* don't bother falling back to 'slow' as we don't support software tangents and binormals yet . */
1010 /* FIXME: fixme once */
1011 TRACE("Hardware support for tangents and binormals is not avaiable, tangents and binormals disabled.\n");
1013 } else {
1014 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
1015 /* make sure fog is disabled */
1016 glDisable(GL_TANGENT_ARRAY_EXT);
1017 glDisable(GL_BINORMAL_ARRAY_EXT);
1020 #endif
1022 /* Point Size ----------------------------------------------*/
1023 if (sd->u.s.pSize.lpData || sd->u.s.pSize.VBO) {
1025 /* no such functionality in the fixed function GL pipeline */
1026 TRACE("Cannot change ptSize here in openGl\n");
1027 /* TODO: Implement this function in using shaders if they are available */
1031 /* Vertex Pointers -----------------------------------------*/
1032 if (sd->u.s.position.lpData != NULL || sd->u.s.position.VBO != 0) {
1033 /* Note dwType == float3 or float4 == 2 or 3 */
1034 VTRACE(("glVertexPointer(%d, GL_FLOAT, %d, %p)\n",
1035 sd->u.s.position.dwStride,
1036 sd->u.s.position.dwType + 1,
1037 sd->u.s.position.lpData));
1039 if(curVBO != sd->u.s.position.VBO) {
1040 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.position.VBO));
1041 checkGLcall("glBindBufferARB");
1042 curVBO = sd->u.s.position.VBO;
1045 /* min(WINED3D_ATR_SIZE(position),3) to Disable RHW mode as 'w' coord
1046 handling for rhw mode should not impact screen position whereas in GL it does.
1047 This may result in very slightly distored textures in rhw mode, but
1048 a very minimal different. There's always the other option of
1049 fixing the view matrix to prevent w from having any effect
1051 This only applies to user pointer sources, in VBOs the vertices are fixed up
1053 if(sd->u.s.position.VBO == 0) {
1054 glVertexPointer(3 /* min(WINED3D_ATR_SIZE(sd->u.s.position.dwType),3) */,
1055 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1056 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1057 } else {
1058 glVertexPointer(
1059 WINED3D_ATR_SIZE(sd->u.s.position.dwType),
1060 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1061 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1063 checkGLcall("glVertexPointer(...)");
1064 glEnableClientState(GL_VERTEX_ARRAY);
1065 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
1067 } else {
1068 glDisableClientState(GL_VERTEX_ARRAY);
1069 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
1072 /* Normals -------------------------------------------------*/
1073 if (sd->u.s.normal.lpData || sd->u.s.normal.VBO) {
1074 /* Note dwType == float3 or float4 == 2 or 3 */
1075 VTRACE(("glNormalPointer(GL_FLOAT, %d, %p)\n",
1076 sd->u.s.normal.dwStride,
1077 sd->u.s.normal.lpData));
1078 if(curVBO != sd->u.s.normal.VBO) {
1079 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.normal.VBO));
1080 checkGLcall("glBindBufferARB");
1081 curVBO = sd->u.s.normal.VBO;
1083 glNormalPointer(
1084 WINED3D_ATR_GLTYPE(sd->u.s.normal.dwType),
1085 sd->u.s.normal.dwStride,
1086 sd->u.s.normal.lpData);
1087 checkGLcall("glNormalPointer(...)");
1088 glEnableClientState(GL_NORMAL_ARRAY);
1089 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
1091 } else {
1092 glDisableClientState(GL_NORMAL_ARRAY);
1093 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
1094 glNormal3f(0, 0, 1);
1095 checkGLcall("glNormal3f(0, 0, 1)");
1098 /* Diffuse Colour --------------------------------------------*/
1099 /* WARNING: Data here MUST be in RGBA format, so cannot */
1100 /* go directly into fast mode from app pgm, because */
1101 /* directx requires data in BGRA format. */
1102 /* currently fixupVertices swizels the format, but this isn't */
1103 /* very practical when using VBOS */
1104 /* NOTE: Unless we write a vertex shader to swizel the colour */
1105 /* , or the user doesn't care and wants the speed advantage */
1107 if (sd->u.s.diffuse.lpData || sd->u.s.diffuse.VBO) {
1108 /* Note dwType == float3 or float4 == 2 or 3 */
1109 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %d, %p)\n",
1110 sd->u.s.diffuse.dwStride,
1111 sd->u.s.diffuse.lpData));
1113 if(curVBO != sd->u.s.diffuse.VBO) {
1114 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.diffuse.VBO));
1115 checkGLcall("glBindBufferARB");
1116 curVBO = sd->u.s.diffuse.VBO;
1118 glColorPointer(4, GL_UNSIGNED_BYTE,
1119 sd->u.s.diffuse.dwStride,
1120 sd->u.s.diffuse.lpData);
1121 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
1122 glEnableClientState(GL_COLOR_ARRAY);
1123 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
1125 } else {
1126 glDisableClientState(GL_COLOR_ARRAY);
1127 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
1128 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1129 checkGLcall("glColor4f(1, 1, 1, 1)");
1132 /* Specular Colour ------------------------------------------*/
1133 if (sd->u.s.specular.lpData || sd->u.s.specular.VBO) {
1134 TRACE("setting specular colour\n");
1135 /* Note dwType == float3 or float4 == 2 or 3 */
1136 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %d, %p)\n",
1137 sd->u.s.specular.dwStride,
1138 sd->u.s.specular.lpData));
1139 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1140 if(curVBO != sd->u.s.specular.VBO) {
1141 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.specular.VBO));
1142 checkGLcall("glBindBufferARB");
1143 curVBO = sd->u.s.specular.VBO;
1145 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
1146 sd->u.s.specular.dwStride,
1147 sd->u.s.specular.lpData);
1148 vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
1149 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1150 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1151 } else {
1153 /* Missing specular color is not critical, no warnings */
1154 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1157 } else {
1158 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1160 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1161 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1162 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1163 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
1164 } else {
1166 /* Missing specular color is not critical, no warnings */
1167 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1171 /* Texture coords -------------------------------------------*/
1173 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1174 /* The code below uses glClientActiveTexture and glMultiTexCoord* which are all part of the GL_ARB_multitexture extension. */
1175 /* Abort if we don't support the extension. */
1176 if (!GL_SUPPORT(ARB_MULTITEXTURE)) {
1177 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1178 continue;
1181 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) {
1182 /* Select the correct texture stage */
1183 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1186 if (This->stateBlock->textures[textureNo] != NULL) {
1187 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
1189 if (coordIdx >= MAX_TEXTURES) {
1190 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1191 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1192 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1194 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL && sd->u.s.texCoords[coordIdx].VBO == 0) {
1195 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
1196 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1197 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1199 } else {
1200 TRACE("Setting up texture %u, idx %d, cordindx %u, data %p\n",
1201 textureNo, texture_idx, coordIdx, sd->u.s.texCoords[coordIdx].lpData);
1202 if(curVBO != sd->u.s.texCoords[coordIdx].VBO) {
1203 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.texCoords[coordIdx].VBO));
1204 checkGLcall("glBindBufferARB");
1205 curVBO = sd->u.s.texCoords[coordIdx].VBO;
1207 /* The coords to supply depend completely on the fvf / vertex shader */
1208 glTexCoordPointer(
1209 WINED3D_ATR_SIZE(sd->u.s.texCoords[coordIdx].dwType),
1210 WINED3D_ATR_GLTYPE(sd->u.s.texCoords[coordIdx].dwType),
1211 sd->u.s.texCoords[coordIdx].dwStride,
1212 sd->u.s.texCoords[coordIdx].lpData);
1213 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1215 } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1216 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1217 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1219 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1221 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1222 for (textureNo = texture_idx; textureNo < GL_LIMITS(textures); ++textureNo) {
1223 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo));
1224 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1225 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1230 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
1231 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1234 if (idxData != NULL /* This crashes sometimes!*/) {
1235 TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
1236 idxData = idxData == (void *)-1 ? NULL : idxData;
1237 #if 1
1238 #if 0
1239 glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
1240 glEnableClientState(GL_INDEX_ARRAY);
1241 #endif
1242 glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1243 (const char *)idxData+(idxSize * startIdx));
1244 #else /* using drawRangeElements may be faster */
1246 glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
1247 idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1248 (const char *)idxData+(idxSize * startIdx));
1249 #endif
1250 checkGLcall("glDrawRangeElements");
1252 } else {
1254 /* Note first is now zero as we shuffled along earlier */
1255 TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
1256 glDrawArrays(glPrimitiveType, 0, numberOfVertices);
1257 checkGLcall("glDrawArrays");
1261 return;
1265 * Actually draw using the supplied information.
1266 * Slower GL version which extracts info about each vertex in turn
1269 static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1270 UINT NumVertexes, GLenum glPrimType,
1271 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1273 unsigned int textureNo = 0;
1274 unsigned int texture_idx = 0;
1275 const short *pIdxBufS = NULL;
1276 const long *pIdxBufL = NULL;
1277 LONG SkipnStrides = 0;
1278 LONG vx_index;
1279 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1280 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
1281 float rhw = 0.0f; /* rhw */
1282 float ptSize = 0.0f; /* Point size */
1283 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
1284 DWORD specularColor = 0; /* Specular Color */
1285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1287 TRACE("Using slow vertex array code\n");
1289 /* Variable Initialization */
1290 if (idxData != NULL) {
1291 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1292 else pIdxBufL = (const long *) idxData;
1295 /* Start drawing in GL */
1296 VTRACE(("glBegin(%x)\n", glPrimType));
1297 glBegin(glPrimType);
1299 /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
1300 * Guess it's not necessary(we crash then anyway) and would only eat CPU time
1303 /* For each primitive */
1304 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1306 /* Initialize diffuse color */
1307 diffuseColor = 0xFFFFFFFF;
1309 /* For indexed data, we need to go a few more strides in */
1310 if (idxData != NULL) {
1312 /* Indexed so work out the number of strides to skip */
1313 if (idxSize == 2) {
1314 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1315 SkipnStrides = pIdxBufS[startIdx + vx_index];
1316 } else {
1317 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
1318 SkipnStrides = pIdxBufL[startIdx + vx_index];
1322 /* Position Information ------------------ */
1323 if (sd->u.s.position.lpData != NULL) {
1325 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
1326 x = ptrToCoords[0];
1327 y = ptrToCoords[1];
1328 z = ptrToCoords[2];
1329 rhw = 1.0;
1330 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
1332 /* RHW follows, only if transformed, ie 4 floats were provided */
1333 if (sd->u.s.position_transformed) {
1334 rhw = ptrToCoords[3];
1335 VTRACE(("rhw=%f\n", rhw));
1339 /* Blending data -------------------------- */
1340 if (sd->u.s.blendWeights.lpData != NULL) {
1341 /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
1342 FIXME("Blending not supported yet\n");
1344 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
1345 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
1349 /* Vertex Normal Data (untransformed only)- */
1350 if (sd->u.s.normal.lpData != NULL) {
1352 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
1353 nx = ptrToCoords[0];
1354 ny = ptrToCoords[1];
1355 nz = ptrToCoords[2];
1356 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
1359 /* Point Size ----------------------------- */
1360 if (sd->u.s.pSize.lpData != NULL) {
1362 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1363 ptSize = ptrToCoords[0];
1364 VTRACE(("ptSize=%f\n", ptSize));
1365 FIXME("No support for ptSize yet\n");
1368 /* Diffuse -------------------------------- */
1369 if (sd->u.s.diffuse.lpData != NULL) {
1371 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1372 diffuseColor = ptrToCoords[0];
1373 VTRACE(("diffuseColor=%lx\n", diffuseColor));
1376 /* Specular -------------------------------- */
1377 if (sd->u.s.specular.lpData != NULL) {
1379 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1380 specularColor = ptrToCoords[0];
1381 VTRACE(("specularColor=%lx\n", specularColor));
1384 /* Texture coords --------------------------- */
1385 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1387 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1388 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1389 continue ;
1392 /* Query tex coords */
1393 if (This->stateBlock->textures[textureNo] != NULL) {
1395 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
1396 float *ptrToCoords = NULL;
1397 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1399 if (coordIdx > 7) {
1400 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1401 ++texture_idx;
1402 continue;
1403 } else if (coordIdx < 0) {
1404 FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
1405 ++texture_idx;
1406 continue;
1409 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1410 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1411 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1412 ++texture_idx;
1413 continue;
1414 } else {
1416 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == WINED3DDECLTYPE_FLOAT1 etc */
1418 /* The coords to supply depend completely on the fvf / vertex shader */
1419 switch (coordsToUse) {
1420 case 4: q = ptrToCoords[3]; /* drop through */
1421 case 3: r = ptrToCoords[2]; /* drop through */
1422 case 2: t = ptrToCoords[1]; /* drop through */
1423 case 1: s = ptrToCoords[0];
1426 /* Projected is more 'fun' - Move the last coord to the 'q'
1427 parameter (see comments under WINED3DTSS_TEXTURETRANSFORMFLAGS */
1428 if ((This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) &&
1429 (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED)) {
1431 if (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED) {
1432 switch (coordsToUse) {
1433 case 0: /* Drop Through */
1434 case 1:
1435 FIXME("WINED3DTTFF_PROJECTED but only zero or one coordinate?\n");
1436 break;
1437 case 2:
1438 q = t;
1439 t = 0.0;
1440 coordsToUse = 4;
1441 break;
1442 case 3:
1443 q = r;
1444 r = 0.0;
1445 coordsToUse = 4;
1446 break;
1447 case 4: /* Nop here */
1448 break;
1449 default:
1450 FIXME("Unexpected WINED3DTSS_TEXTURETRANSFORMFLAGS value of %d\n",
1451 This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED);
1456 switch (coordsToUse) { /* Supply the provided texture coords */
1457 case WINED3DTTFF_COUNT1:
1458 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1459 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1460 GL_EXTCALL(glMultiTexCoord1fARB(texture_idx, s));
1461 } else {
1462 glTexCoord1f(s);
1464 break;
1465 case WINED3DTTFF_COUNT2:
1466 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1467 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1468 GL_EXTCALL(glMultiTexCoord2fARB(texture_idx, s, t));
1469 } else {
1470 glTexCoord2f(s, t);
1472 break;
1473 case WINED3DTTFF_COUNT3:
1474 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1475 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1476 GL_EXTCALL(glMultiTexCoord3fARB(texture_idx, s, t, r));
1477 } else {
1478 glTexCoord3f(s, t, r);
1480 break;
1481 case WINED3DTTFF_COUNT4:
1482 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1483 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1484 GL_EXTCALL(glMultiTexCoord4fARB(texture_idx, s, t, r, q));
1485 } else {
1486 glTexCoord4f(s, t, r, q);
1488 break;
1489 default:
1490 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1494 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1495 } /* End of textures */
1497 /* Diffuse -------------------------------- */
1498 if (sd->u.s.diffuse.lpData != NULL) {
1499 glColor4ub(D3DCOLOR_B_R(diffuseColor),
1500 D3DCOLOR_B_G(diffuseColor),
1501 D3DCOLOR_B_B(diffuseColor),
1502 D3DCOLOR_B_A(diffuseColor));
1503 VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n",
1504 D3DCOLOR_B_R(diffuseColor),
1505 D3DCOLOR_B_G(diffuseColor),
1506 D3DCOLOR_B_B(diffuseColor),
1507 D3DCOLOR_B_A(diffuseColor)));
1508 } else {
1509 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1512 /* Specular ------------------------------- */
1513 if (sd->u.s.specular.lpData != NULL) {
1514 /* special case where the fog density is stored in the diffuse alpha channel */
1515 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
1516 (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == WINED3DFOG_NONE || sd->u.s.position.dwType == WINED3DDECLTYPE_FLOAT4 )&&
1517 This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
1518 if(GL_SUPPORT(EXT_FOG_COORD)) {
1519 GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
1520 } else {
1521 static BOOL warned = FALSE;
1522 if(!warned) {
1523 /* TODO: Use the fog table code from old ddraw */
1524 FIXME("Implement fog for transformed vertices in software\n");
1525 warned = TRUE;
1530 VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n",
1531 D3DCOLOR_B_R(specularColor),
1532 D3DCOLOR_B_G(specularColor),
1533 D3DCOLOR_B_B(specularColor)));
1534 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1535 GL_EXTCALL(glSecondaryColor3ubEXT)(
1536 D3DCOLOR_B_R(specularColor),
1537 D3DCOLOR_B_G(specularColor),
1538 D3DCOLOR_B_B(specularColor));
1539 } else {
1540 /* Do not worry if specular colour missing and disable request */
1541 VTRACE(("Specular color extensions not supplied\n"));
1543 } else {
1544 if (vx_index == 0) {
1545 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1546 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1547 } else {
1548 /* Do not worry if specular colour missing and disable request */
1549 VTRACE(("Specular color extensions not supplied\n"));
1554 /* Normal -------------------------------- */
1555 if (sd->u.s.normal.lpData != NULL) {
1556 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1557 glNormal3f(nx, ny, nz);
1558 } else {
1559 if (vx_index == 0) glNormal3f(0, 0, 1);
1562 /* Position -------------------------------- */
1563 if (sd->u.s.position.lpData != NULL) {
1564 if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
1565 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1566 glVertex3f(x, y, z);
1567 } else {
1568 GLfloat w = 1.0 / rhw;
1569 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1570 glVertex4f(x*w, y*w, z*w, w);
1574 /* For non indexed mode, step onto next parts */
1575 if (idxData == NULL) {
1576 ++SkipnStrides;
1580 glEnd();
1581 checkGLcall("glEnd and previous calls");
1584 #if 0 /* TODO: Software/Hardware vertex blending support */
1586 * Draw with emulated vertex shaders
1587 * Note: strided data is uninitialized, as we need to pass the vertex
1588 * shader directly as ordering irs yet
1590 void drawStridedSoftwareVS(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1591 int PrimitiveType, ULONG NumPrimitives,
1592 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1594 unsigned int textureNo = 0;
1595 GLenum glPrimType = GL_POINTS;
1596 int NumVertexes = NumPrimitives;
1597 const short *pIdxBufS = NULL;
1598 const long *pIdxBufL = NULL;
1599 LONG SkipnStrides = 0;
1600 LONG vx_index;
1601 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1602 float rhw = 0.0f; /* rhw */
1603 float ptSize = 0.0f; /* Point size */
1604 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1605 int numcoords[8]; /* Number of coords */
1606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1608 IDirect3DVertexShaderImpl* vertexShader = NULL;
1610 TRACE("Using slow software vertex shader code\n");
1612 /* Variable Initialization */
1613 if (idxData != NULL) {
1614 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1615 else pIdxBufL = (const long *) idxData;
1618 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1619 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1621 /* Retrieve the VS information */
1622 vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
1624 /* Start drawing in GL */
1625 VTRACE(("glBegin(%x)\n", glPrimType));
1626 glBegin(glPrimType);
1628 /* For each primitive */
1629 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1631 /* For indexed data, we need to go a few more strides in */
1632 if (idxData != NULL) {
1634 /* Indexed so work out the number of strides to skip */
1635 if (idxSize == 2) {
1636 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1637 SkipnStrides = pIdxBufS[startIdx+vx_index];
1638 } else {
1639 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
1640 SkipnStrides = pIdxBufL[startIdx+vx_index];
1644 /* Fill the vertex shader input */
1645 IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1647 /* Initialize the output fields to the same defaults as it would normally have */
1648 memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1649 vertexShader->output.oD[0].x = 1.0;
1650 vertexShader->output.oD[0].y = 1.0;
1651 vertexShader->output.oD[0].z = 1.0;
1652 vertexShader->output.oD[0].w = 1.0;
1654 /* Now execute the vertex shader */
1655 IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1658 TRACE_VECTOR(vertexShader->output.oPos);
1659 TRACE_VECTOR(vertexShader->output.oD[0]);
1660 TRACE_VECTOR(vertexShader->output.oD[1]);
1661 TRACE_VECTOR(vertexShader->output.oT[0]);
1662 TRACE_VECTOR(vertexShader->output.oT[1]);
1663 TRACE_VECTOR(vertexShader->input.V[0]);
1664 TRACE_VECTOR(vertexShader->data->C[0]);
1665 TRACE_VECTOR(vertexShader->data->C[1]);
1666 TRACE_VECTOR(vertexShader->data->C[2]);
1667 TRACE_VECTOR(vertexShader->data->C[3]);
1668 TRACE_VECTOR(vertexShader->data->C[4]);
1669 TRACE_VECTOR(vertexShader->data->C[5]);
1670 TRACE_VECTOR(vertexShader->data->C[6]);
1671 TRACE_VECTOR(vertexShader->data->C[7]);
1674 /* Extract out the output */
1675 /* FIXME: Fog coords? */
1676 x = vertexShader->output.oPos.x;
1677 y = vertexShader->output.oPos.y;
1678 z = vertexShader->output.oPos.z;
1679 rhw = vertexShader->output.oPos.w;
1680 ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1682 /** Update textures coords using vertexShader->output.oT[0->7] */
1683 memset(texcoords, 0x00, sizeof(texcoords));
1684 memset(numcoords, 0x00, sizeof(numcoords));
1685 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1686 if (This->stateBlock->textures[textureNo] != NULL) {
1687 texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1688 texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1689 texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1690 texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1691 if (This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) {
1692 numcoords[textureNo] = This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & ~WINED3DTTFF_PROJECTED;
1693 } else {
1694 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1695 case WINED3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1696 case WINED3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1697 default: numcoords[textureNo] = 4;
1700 } else {
1701 numcoords[textureNo] = 0;
1705 /* Draw using this information */
1706 draw_vertex(iface,
1707 TRUE, x, y, z, rhw,
1708 TRUE, 0.0f, 0.0f, 1.0f,
1709 TRUE, (float*) &vertexShader->output.oD[0],
1710 TRUE, (float*) &vertexShader->output.oD[1],
1711 FALSE, ptSize, /* FIXME: Change back when supported */
1712 texcoords, numcoords);
1714 /* For non indexed mode, step onto next parts */
1715 if (idxData == NULL) {
1716 ++SkipnStrides;
1719 } /* for each vertex */
1721 glEnd();
1722 checkGLcall("glEnd and previous calls");
1725 #endif
1727 inline static void drawPrimitiveDrawStrided(
1728 IWineD3DDevice *iface,
1729 BOOL useVertexShaderFunction,
1730 BOOL usePixelShaderFunction,
1731 WineDirect3DVertexStridedData *dataLocations,
1732 UINT numberOfvertices,
1733 UINT numberOfIndicies,
1734 GLenum glPrimType,
1735 const void *idxData,
1736 short idxSize,
1737 int minIndex,
1738 long StartIdx,
1739 BOOL fixup) {
1741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1742 BOOL useDrawStridedSlow;
1744 int startStride = idxData == NULL ? 0 :
1745 idxData == (void *) -1 ? 0 :
1746 (idxSize == 2 ? *(((const short *) idxData) + StartIdx) : *((const int *) idxData) + StartIdx);
1747 int endStride = startStride;
1748 TRACE("begin Start stride %d, end stride %d, number of indices%d, number of vertices%d\n",
1749 startStride, endStride, numberOfIndicies, numberOfvertices);
1751 /* Generate some fixme's if unsupported functionality is being used */
1752 #define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData
1753 /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */
1754 if (!useVertexShaderFunction && (BUFFER_OR_DATA(blendMatrixIndices) || BUFFER_OR_DATA(blendWeights))) {
1755 FIXME("Blending data is only valid with vertex shaders %p %p\n",dataLocations->u.s.blendWeights.lpData,dataLocations->u.s.blendWeights.lpData);
1757 if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) {
1758 FIXME("Tweening is only valid with vertex shaders\n");
1760 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) {
1761 FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n");
1763 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) {
1764 FIXME("Extended attributes are only valid with vertex shaders\n");
1766 #undef BUFFER_OR_DATA
1768 /* Fixed pipeline, no fixups required - load arrays */
1769 if (!useVertexShaderFunction &&
1770 ((dataLocations->u.s.pSize.lpData == NULL &&
1771 dataLocations->u.s.diffuse.lpData == NULL &&
1772 dataLocations->u.s.specular.lpData == NULL) ||
1773 fixup) ) {
1775 /* Load the vertex data using named arrays */
1776 TRACE("(%p) Loading vertex data\n", This);
1777 loadVertexData(iface, dataLocations);
1778 useDrawStridedSlow = FALSE;
1780 /* Shader pipeline - load attribute arrays */
1781 } else if(useVertexShaderFunction) {
1783 loadNumberedArrays(iface, This->stateBlock->vertexShader, dataLocations);
1784 useDrawStridedSlow = FALSE;
1786 /* We compile the shader here because we need the vertex declaration
1787 * in order to determine if we need to do any swizzling for D3DCOLOR
1788 * registers. If the shader is already compiled this call will do nothing. */
1789 IWineD3DVertexShader_CompileShader(This->stateBlock->vertexShader);
1790 /* Draw vertex by vertex */
1791 } else {
1792 TRACE("Not loading vertex data\n");
1793 useDrawStridedSlow = TRUE;
1796 if(usePixelShaderFunction) {
1797 /* We compile the shader here because it depends on the texture stage state
1798 * setup of the bound textures. If the shader is already compiled and the texture stage
1799 * state setup matches the program this function will do nothing
1801 IWineD3DPixelShader_CompileShader(This->stateBlock->pixelShader);
1803 /* If GLSL is used for either pixel or vertex shaders, make a GLSL program
1804 * Otherwise set NULL, to restore fixed function */
1805 if ((This->vs_selected_mode == SHADER_GLSL && useVertexShaderFunction) ||
1806 (This->ps_selected_mode == SHADER_GLSL && usePixelShaderFunction))
1807 set_glsl_shader_program(iface);
1808 else
1809 This->stateBlock->glsl_program = NULL;
1811 /* If GLSL is used now, or might have been used before, (re)set the program */
1812 if (This->vs_selected_mode == SHADER_GLSL || This->ps_selected_mode == SHADER_GLSL) {
1814 GLhandleARB progId = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->programId : 0;
1815 if (progId)
1816 TRACE_(d3d_shader)("Using GLSL program %u\n", progId);
1817 GL_EXTCALL(glUseProgramObjectARB(progId));
1818 checkGLcall("glUseProgramObjectARB");
1821 if (useVertexShaderFunction) {
1823 TRACE("Using vertex shader\n");
1825 if (This->vs_selected_mode == SHADER_ARB) {
1826 /* Bind the vertex program */
1827 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB,
1828 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId));
1829 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
1831 /* Enable OpenGL vertex programs */
1832 glEnable(GL_VERTEX_PROGRAM_ARB);
1833 checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
1834 TRACE_(d3d_shader)("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n",
1835 This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId);
1839 if (usePixelShaderFunction) {
1841 TRACE("Using pixel shader\n");
1843 if (This->ps_selected_mode == SHADER_ARB) {
1844 /* Bind the fragment program */
1845 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,
1846 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId));
1847 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
1849 /* Enable OpenGL fragment programs */
1850 glEnable(GL_FRAGMENT_PROGRAM_ARB);
1851 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
1852 TRACE_(d3d_shader)("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n",
1853 This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId);
1857 /* Load any global constants/uniforms that may have been set by the application */
1858 if (This->vs_selected_mode == SHADER_GLSL || This->ps_selected_mode == SHADER_GLSL)
1859 shader_glsl_load_constants(iface, usePixelShaderFunction, useVertexShaderFunction);
1860 else if (This->vs_selected_mode == SHADER_ARB || This->ps_selected_mode == SHADER_ARB)
1861 shader_arb_load_constants(iface, usePixelShaderFunction, useVertexShaderFunction);
1863 /* Draw vertex-by-vertex */
1864 if (useDrawStridedSlow)
1865 drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1866 else
1867 drawStridedFast(iface, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1869 /* Cleanup vertex program */
1870 if (useVertexShaderFunction) {
1871 unloadNumberedArrays(iface);
1873 if (This->vs_selected_mode == SHADER_ARB)
1874 glDisable(GL_VERTEX_PROGRAM_ARB);
1875 } else {
1876 unloadVertexData(iface);
1879 /* Cleanup fragment program */
1880 if (usePixelShaderFunction && This->ps_selected_mode == SHADER_ARB)
1881 glDisable(GL_FRAGMENT_PROGRAM_ARB);
1884 inline void drawPrimitiveTraceDataLocations(
1885 WineDirect3DVertexStridedData *dataLocations) {
1887 /* Dump out what parts we have supplied */
1888 TRACE("Strided Data:\n");
1889 TRACE_STRIDED((dataLocations), position);
1890 TRACE_STRIDED((dataLocations), blendWeights);
1891 TRACE_STRIDED((dataLocations), blendMatrixIndices);
1892 TRACE_STRIDED((dataLocations), normal);
1893 TRACE_STRIDED((dataLocations), pSize);
1894 TRACE_STRIDED((dataLocations), diffuse);
1895 TRACE_STRIDED((dataLocations), specular);
1896 TRACE_STRIDED((dataLocations), texCoords[0]);
1897 TRACE_STRIDED((dataLocations), texCoords[1]);
1898 TRACE_STRIDED((dataLocations), texCoords[2]);
1899 TRACE_STRIDED((dataLocations), texCoords[3]);
1900 TRACE_STRIDED((dataLocations), texCoords[4]);
1901 TRACE_STRIDED((dataLocations), texCoords[5]);
1902 TRACE_STRIDED((dataLocations), texCoords[6]);
1903 TRACE_STRIDED((dataLocations), texCoords[7]);
1904 TRACE_STRIDED((dataLocations), position2);
1905 TRACE_STRIDED((dataLocations), normal2);
1906 TRACE_STRIDED((dataLocations), tangent);
1907 TRACE_STRIDED((dataLocations), binormal);
1908 TRACE_STRIDED((dataLocations), tessFactor);
1909 TRACE_STRIDED((dataLocations), fog);
1910 TRACE_STRIDED((dataLocations), depth);
1911 TRACE_STRIDED((dataLocations), sample);
1913 return;
1917 static void drawPrimitiveUploadTexturesPS(IWineD3DDeviceImpl* This) {
1918 INT i;
1920 for (i = 0; i < GL_LIMITS(samplers); ++i) {
1921 /* Pixel shader support should imply multitexture support. */
1922 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1923 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1924 checkGLcall("glActiveTextureARB");
1925 } else if (i) {
1926 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1929 if (!This->stateBlock->textures[i]) continue;
1931 /* Enable the correct target. Is this required for GLSL? For ARB_fragment_program it isn't, afaik. */
1932 glDisable(GL_TEXTURE_1D);
1933 This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1934 switch(This->stateBlock->textureDimensions[i]) {
1935 case GL_TEXTURE_2D:
1936 glDisable(GL_TEXTURE_3D);
1937 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1938 break;
1939 case GL_TEXTURE_3D:
1940 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1941 glDisable(GL_TEXTURE_2D);
1942 break;
1943 case GL_TEXTURE_CUBE_MAP_ARB:
1944 glDisable(GL_TEXTURE_2D);
1945 glDisable(GL_TEXTURE_3D);
1946 break;
1948 glEnable(This->stateBlock->textureDimensions[i]);
1950 /* Upload texture, apply states */
1951 IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
1952 IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, i, REAPPLY_ALPHAOP);
1953 IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
1957 /* uploads textures and setup texture states ready for rendering */
1958 static void drawPrimitiveUploadTextures(IWineD3DDeviceImpl* This) {
1959 INT current_sampler = 0;
1960 float constant_color[4];
1961 unsigned int i;
1963 /* ARB_texture_env_combine is limited to GL_MAX_TEXTURE_UNITS stages. On
1964 * nVidia cards GL_MAX_TEXTURE_UNITS is generally not larger than 4.
1965 * Register combiners however provide up to 8 combiner stages. In order to
1966 * take advantage of this, we need to be separate D3D texture stages from
1967 * GL texture units. When using register combiners GL_MAX_TEXTURE_UNITS
1968 * corresponds to MaxSimultaneousTextures and GL_MAX_GENERAL_COMBINERS_NV
1969 * corresponds to MaxTextureBlendStages in the caps. */
1971 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1972 glEnable(GL_REGISTER_COMBINERS_NV);
1973 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], constant_color);
1974 GL_EXTCALL(glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, &constant_color[0]));
1977 for (i = 0; i < GL_LIMITS(texture_stages); ++i) {
1978 INT texture_idx = -1;
1980 /* WINED3DTOP_DISABLE disables the current & any higher texture stages */
1981 if (This->stateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) break;
1983 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[i]) {
1984 texture_idx = current_sampler++;
1986 /* Active the texture unit corresponding to the current texture stage */
1987 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1988 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1989 checkGLcall("glActiveTextureARB");
1990 } else if (i) {
1991 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1995 if (This->stateBlock->textures[i]) {
1996 /* Enable the correct target. */
1997 glDisable(GL_TEXTURE_1D);
1998 This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1999 switch(This->stateBlock->textureDimensions[i]) {
2000 case GL_TEXTURE_2D:
2001 glDisable(GL_TEXTURE_3D);
2002 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2003 break;
2004 case GL_TEXTURE_3D:
2005 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2006 glDisable(GL_TEXTURE_2D);
2007 break;
2008 case GL_TEXTURE_CUBE_MAP_ARB:
2009 glDisable(GL_TEXTURE_2D);
2010 glDisable(GL_TEXTURE_3D);
2011 break;
2014 /* imply GL_SUPPORT(NV_TEXTURE_SHADER) when setting texture_shader_active */
2015 if (This->texture_shader_active && This->stateBlock->textureDimensions[i] == GL_TEXTURE_2D) {
2016 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
2017 } else {
2018 glEnable(This->stateBlock->textureDimensions[i]);
2021 /* Upload texture, apply states */
2022 IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
2023 IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, texture_idx, REAPPLY_ALPHAOP);
2024 IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
2025 } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2026 /* ARB_texture_env_combine needs a valid texture bound to the
2027 * texture unit, even if it isn't used. Bind a dummy texture. */
2028 glDisable(GL_TEXTURE_2D);
2029 glDisable(GL_TEXTURE_3D);
2030 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2031 glEnable(GL_TEXTURE_1D);
2032 This->stateBlock->textureDimensions[i] = GL_TEXTURE_1D;
2033 glBindTexture(GL_TEXTURE_1D, This->dummyTextureName[i]);
2036 /** these ops apply to the texture unit, so they are preserved between texture changes, but for now brute force and reapply all
2037 dx9_1pass_emboss_bump_mapping and dx9_2pass_emboss_bump_mapping are good texts to make sure the states are being applied when needed **/
2038 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2039 set_tex_op_nvrc((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
2040 This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
2041 This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
2042 This->stateBlock->textureState[i][WINED3DTSS_COLORARG0],
2043 texture_idx);
2044 /* alphaop */
2045 set_tex_op_nvrc((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2046 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2047 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2048 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0],
2049 texture_idx);
2050 } else {
2051 set_tex_op((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
2052 This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
2053 This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
2054 This->stateBlock->textureState[i][WINED3DTSS_COLORARG0]);
2055 /* alphaop */
2056 set_tex_op((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2057 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2058 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2059 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0]);
2063 /* If we're using register combiners, set the amount of *used* combiners.
2064 * Ie, the number of stages below the first stage to have a color op of
2065 * WINED3DTOP_DISABLE. */
2066 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2067 /* NUM_GENERAL_COMBINERS_NV should be > 0 */
2068 if (!i) glDisable(GL_REGISTER_COMBINERS_NV);
2069 else GL_EXTCALL(glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, i));
2072 /* Disable the remaining texture units. */
2073 for (i = current_sampler; i < GL_LIMITS(textures); ++i) {
2074 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2075 glDisable(GL_TEXTURE_1D);
2076 glDisable(GL_TEXTURE_2D);
2077 glDisable(GL_TEXTURE_3D);
2078 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2082 static void check_fbo_status(IWineD3DDevice *iface) {
2083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2085 GLenum status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
2086 switch(status) {
2087 case GL_FRAMEBUFFER_COMPLETE_EXT: TRACE("FBO complete.\n"); break;
2088 default: TRACE("FBO status %#x.\n", status); break;
2092 static GLuint create_arb_blt_vertex_program(IWineD3DDevice *iface) {
2093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2095 GLuint program_id = 0;
2096 const char *blt_vprogram =
2097 "!!ARBvp1.0\n"
2098 "PARAM c[1] = { { 1, 0.5 } };\n"
2099 "MOV result.position, vertex.position;\n"
2100 "MOV result.color, c[0].x;\n"
2101 "MAD result.texcoord[0].y, -vertex.position, c[0], c[0];\n"
2102 "MAD result.texcoord[0].x, vertex.position, c[0].y, c[0].y;\n"
2103 "END\n";
2105 GL_EXTCALL(glGenProgramsARB(1, &program_id));
2106 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, program_id));
2107 GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(blt_vprogram), blt_vprogram));
2109 if (glGetError() == GL_INVALID_OPERATION) {
2110 GLint pos;
2111 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
2112 FIXME("Vertex program error at position %d: %s\n", pos,
2113 debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
2116 return program_id;
2119 static GLuint create_arb_blt_fragment_program(IWineD3DDevice *iface) {
2120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2122 GLuint program_id = 0;
2123 const char *blt_fprogram =
2124 "!!ARBfp1.0\n"
2125 "TEMP R0;\n"
2126 "TEX R0.x, fragment.texcoord[0], texture[0], 2D;\n"
2127 "MOV result.depth.z, R0.x;\n"
2128 "END\n";
2130 GL_EXTCALL(glGenProgramsARB(1, &program_id));
2131 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program_id));
2132 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(blt_fprogram), blt_fprogram));
2134 if (glGetError() == GL_INVALID_OPERATION) {
2135 GLint pos;
2136 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
2137 FIXME("Fragment program error at position %d: %s\n", pos,
2138 debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
2141 return program_id;
2144 static GLhandleARB create_glsl_blt_shader(IWineD3DDevice *iface) {
2145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2147 GLhandleARB program_id;
2148 GLhandleARB vshader_id, pshader_id;
2149 const char *blt_vshader[] = {
2150 "void main(void)\n"
2151 "{\n"
2152 " gl_Position = gl_Vertex;\n"
2153 " gl_FrontColor = vec4(1.0);\n"
2154 " gl_TexCoord[0].x = (gl_Vertex.x * 0.5) + 0.5;\n"
2155 " gl_TexCoord[0].y = (-gl_Vertex.y * 0.5) + 0.5;\n"
2156 "}\n"
2159 const char *blt_pshader[] = {
2160 "uniform sampler2D sampler;\n"
2161 "void main(void)\n"
2162 "{\n"
2163 " gl_FragDepth = texture2D(sampler, gl_TexCoord[0].xy).x;\n"
2164 "}\n"
2167 vshader_id = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB));
2168 GL_EXTCALL(glShaderSourceARB(vshader_id, 1, blt_vshader, NULL));
2169 GL_EXTCALL(glCompileShaderARB(vshader_id));
2171 pshader_id = GL_EXTCALL(glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB));
2172 GL_EXTCALL(glShaderSourceARB(pshader_id, 1, blt_pshader, NULL));
2173 GL_EXTCALL(glCompileShaderARB(pshader_id));
2175 program_id = GL_EXTCALL(glCreateProgramObjectARB());
2176 GL_EXTCALL(glAttachObjectARB(program_id, vshader_id));
2177 GL_EXTCALL(glAttachObjectARB(program_id, pshader_id));
2178 GL_EXTCALL(glLinkProgramARB(program_id));
2180 print_glsl_info_log(&GLINFO_LOCATION, program_id);
2182 return program_id;
2185 static void depth_blt(IWineD3DDevice *iface, GLuint texture) {
2186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2187 BOOL glsl_mode = This->vs_selected_mode == SHADER_GLSL || This->ps_selected_mode == SHADER_GLSL;
2189 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
2191 glDisable(GL_CULL_FACE);
2192 glDisable(GL_BLEND);
2193 glDisable(GL_ALPHA_TEST);
2194 glDisable(GL_STENCIL_TEST);
2195 glEnable(GL_DEPTH_TEST);
2196 glDepthFunc(GL_ALWAYS);
2198 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2199 glBindTexture(GL_TEXTURE_2D, texture);
2200 glEnable(GL_TEXTURE_2D);
2202 if (glsl_mode) {
2203 static GLhandleARB program_id = 0;
2204 static GLhandleARB loc = -1;
2206 if (!program_id) {
2207 program_id = create_glsl_blt_shader(iface);
2208 loc = GL_EXTCALL(glGetUniformLocationARB(program_id, "sampler"));
2211 GL_EXTCALL(glUseProgramObjectARB(program_id));
2212 GL_EXTCALL(glUniform1iARB(loc, 0));
2213 } else {
2214 static GLuint vprogram_id = 0;
2215 static GLuint fprogram_id = 0;
2217 if (!vprogram_id) vprogram_id = create_arb_blt_vertex_program(iface);
2218 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vprogram_id));
2219 glEnable(GL_VERTEX_PROGRAM_ARB);
2221 if (!fprogram_id) fprogram_id = create_arb_blt_fragment_program(iface);
2222 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fprogram_id));
2223 glEnable(GL_FRAGMENT_PROGRAM_ARB);
2226 glBegin(GL_TRIANGLE_STRIP);
2227 glVertex2f(-1.0f, -1.0f);
2228 glVertex2f(1.0f, -1.0f);
2229 glVertex2f(-1.0f, 1.0f);
2230 glVertex2f(1.0f, 1.0f);
2231 glEnd();
2233 glPopAttrib();
2236 static void depth_copy(IWineD3DDevice *iface) {
2237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2238 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *)This->depthStencilBuffer;
2240 /* Only copy the depth buffer if there is one. */
2241 if (!depth_stencil) return;
2243 /* TODO: Make this work for modes other than FBO */
2244 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
2246 if (This->render_offscreen) {
2247 static GLuint tmp_texture = 0;
2249 TRACE("Copying onscreen depth buffer to offscreen surface\n");
2251 if (!tmp_texture) {
2252 glGenTextures(1, &tmp_texture);
2255 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
2256 * directly on the FBO texture. That's because we need to flip. */
2257 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
2258 glBindTexture(GL_TEXTURE_2D, tmp_texture);
2259 glCopyTexImage2D(depth_stencil->glDescription.target,
2260 depth_stencil->glDescription.level,
2261 depth_stencil->glDescription.glFormatInternal,
2264 depth_stencil->currentDesc.Width,
2265 depth_stencil->currentDesc.Height,
2267 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2268 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2269 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
2271 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
2272 checkGLcall("glBindFramebuffer()");
2273 depth_blt(iface, tmp_texture);
2274 checkGLcall("depth_blt");
2275 } else {
2276 TRACE("Copying offscreen surface to onscreen depth buffer\n");
2278 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
2279 checkGLcall("glBindFramebuffer()");
2280 depth_blt(iface, depth_stencil->glDescription.textureName);
2281 checkGLcall("depth_blt");
2285 /* Routine common to the draw primitive and draw indexed primitive routines */
2286 void drawPrimitive(IWineD3DDevice *iface,
2287 int PrimitiveType,
2288 long NumPrimitives,
2289 /* for Indexed: */
2290 long StartVertexIndex,
2291 UINT numberOfVertices,
2292 long StartIdx,
2293 short idxSize,
2294 const void *idxData,
2295 int minIndex,
2296 WineDirect3DVertexStridedData *DrawPrimStrideData) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2299 BOOL useVertexShaderFunction = FALSE;
2300 BOOL usePixelShaderFunction = FALSE;
2301 WineDirect3DVertexStridedData *dataLocations;
2302 IWineD3DSwapChainImpl *swapchain;
2303 int i;
2304 BOOL fixup = FALSE;
2306 BOOL lighting_changed, lighting_original = FALSE;
2308 if (TRACE_ON(d3d_draw) && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2309 check_fbo_status(iface);
2312 if (This->depth_copy_state == WINED3D_DCS_COPY) {
2313 depth_copy(iface);
2315 This->depth_copy_state = WINED3D_DCS_INITIAL;
2317 /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
2318 * here simply check whether a shader was set, or the user disabled shaders */
2319 if (This->vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
2320 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL)
2321 useVertexShaderFunction = TRUE;
2323 if (This->ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
2324 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function)
2325 usePixelShaderFunction = TRUE;
2327 /* Invalidate the back buffer memory so LockRect will read it the next time */
2328 for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
2329 IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
2330 if(swapchain) {
2331 if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer[0])->Flags |= SFLAG_GLDIRTY;
2332 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2336 /* Ok, we will be updating the screen from here onwards so grab the lock */
2337 ENTER_GL();
2339 if(DrawPrimStrideData) {
2341 /* Note: this is a ddraw fixed-function code path */
2343 TRACE("================ Strided Input ===================\n");
2344 dataLocations = DrawPrimStrideData;
2345 drawPrimitiveTraceDataLocations(dataLocations);
2346 fixup = FALSE;
2349 else if (This->stateBlock->vertexDecl || This->stateBlock->vertexShader) {
2351 /* Note: This is a fixed function or shader codepath.
2352 * This means it must handle both types of strided data.
2353 * Shaders must go through here to zero the strided data, even if they
2354 * don't set any declaration at all */
2356 TRACE("================ Vertex Declaration ===================\n");
2357 dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2358 if(!dataLocations) {
2359 ERR("Out of memory!\n");
2360 return;
2363 if (This->stateBlock->vertexDecl != NULL ||
2364 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration != NULL)
2366 primitiveDeclarationConvertToStridedData(iface, useVertexShaderFunction,
2367 dataLocations, StartVertexIndex, &fixup);
2369 } else {
2371 /* Note: This codepath is not reachable from d3d9 (see fvf->decl9 conversion)
2372 * It is reachable through d3d8, but only for fixed-function.
2373 * It will not work properly for shaders. */
2375 TRACE("================ FVF ===================\n");
2376 dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2377 if(!dataLocations) {
2378 ERR("Out of memory!\n");
2379 return;
2381 primitiveConvertToStridedData(iface, dataLocations, StartVertexIndex, &fixup);
2382 drawPrimitiveTraceDataLocations(dataLocations);
2385 /* Setup transform matrices and sort out */
2386 primitiveInitState(iface, dataLocations, useVertexShaderFunction, &lighting_changed, &lighting_original);
2388 /* Now initialize the materials state */
2389 init_materials(iface, (dataLocations->u.s.diffuse.lpData != NULL || dataLocations->u.s.diffuse.VBO != 0));
2391 if (usePixelShaderFunction) {
2392 drawPrimitiveUploadTexturesPS(This);
2393 } else {
2394 drawPrimitiveUploadTextures(This);
2398 GLenum glPrimType;
2399 /* Ok, Work out which primitive is requested and how many vertexes that
2400 will be */
2401 UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
2402 if (numberOfVertices == 0 )
2403 numberOfVertices = calculatedNumberOfindices;
2405 drawPrimitiveDrawStrided(iface, useVertexShaderFunction, usePixelShaderFunction,
2406 dataLocations, numberOfVertices, calculatedNumberOfindices, glPrimType,
2407 idxData, idxSize, minIndex, StartIdx, fixup);
2410 if(!DrawPrimStrideData) HeapFree(GetProcessHeap(), 0, dataLocations);
2412 /* If vertex shaders or no normals, restore previous lighting state */
2413 if (lighting_changed) {
2414 if (lighting_original) glEnable(GL_LIGHTING);
2415 else glDisable(GL_LIGHTING);
2416 TRACE("Restored lighting to original state\n");
2419 /* Finshed updating the screen, restore lock */
2420 LEAVE_GL();
2421 TRACE("Done all gl drawing\n");
2423 /* Diagnostics */
2424 #ifdef SHOW_FRAME_MAKEUP
2426 static long int primCounter = 0;
2427 /* NOTE: set primCounter to the value reported by drawprim
2428 before you want to to write frame makeup to /tmp */
2429 if (primCounter >= 0) {
2430 WINED3DLOCKED_RECT r;
2431 char buffer[80];
2432 IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY);
2433 sprintf(buffer, "/tmp/backbuffer_%d.tga", primCounter);
2434 TRACE("Saving screenshot %s\n", buffer);
2435 IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
2436 IWineD3DSurface_UnlockRect(This->renderTarget);
2438 #ifdef SHOW_TEXTURE_MAKEUP
2440 IWineD3DSurface *pSur;
2441 int textureNo;
2442 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
2443 if (This->stateBlock->textures[textureNo] != NULL) {
2444 sprintf(buffer, "/tmp/texture_%p_%d_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
2445 TRACE("Saving texture %s\n", buffer);
2446 if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
2447 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
2448 IWineD3DSurface_SaveSnapshot(pSur, buffer);
2449 IWineD3DSurface_Release(pSur);
2450 } else {
2451 FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
2456 #endif
2458 TRACE("drawprim #%d\n", primCounter);
2459 ++primCounter;
2461 #endif