wined3d: Correctly draw transformed and untransformed vertices in the same scene.
[wine/multimedia.git] / dlls / wined3d / drawprim.c
blobc2ed58ccf6bdb3f864df323525a76c5fdd872012
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
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wined3d_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw);
28 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
29 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
31 #include <stdio.h>
33 #if 0 /* TODO */
34 extern IWineD3DVertexShaderImpl* VertexShaders[64];
35 extern IWineD3DVertexDeclarationImpl* VertexShaderDeclarations[64];
36 extern IWineD3DPixelShaderImpl* PixelShaders[64];
38 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
39 #endif
41 /* Issues the glBegin call for gl given the primitive type and count */
42 static DWORD primitiveToGl(D3DPRIMITIVETYPE PrimitiveType,
43 DWORD NumPrimitives,
44 GLenum *primType)
46 DWORD NumVertexes = NumPrimitives;
48 switch (PrimitiveType) {
49 case D3DPT_POINTLIST:
50 TRACE("POINTS\n");
51 *primType = GL_POINTS;
52 NumVertexes = NumPrimitives;
53 break;
55 case D3DPT_LINELIST:
56 TRACE("LINES\n");
57 *primType = GL_LINES;
58 NumVertexes = NumPrimitives * 2;
59 break;
61 case D3DPT_LINESTRIP:
62 TRACE("LINE_STRIP\n");
63 *primType = GL_LINE_STRIP;
64 NumVertexes = NumPrimitives + 1;
65 break;
67 case D3DPT_TRIANGLELIST:
68 TRACE("TRIANGLES\n");
69 *primType = GL_TRIANGLES;
70 NumVertexes = NumPrimitives * 3;
71 break;
73 case D3DPT_TRIANGLESTRIP:
74 TRACE("TRIANGLE_STRIP\n");
75 *primType = GL_TRIANGLE_STRIP;
76 NumVertexes = NumPrimitives + 2;
77 break;
79 case D3DPT_TRIANGLEFAN:
80 TRACE("TRIANGLE_FAN\n");
81 *primType = GL_TRIANGLE_FAN;
82 NumVertexes = NumPrimitives + 2;
83 break;
85 default:
86 FIXME("Unhandled primitive\n");
87 *primType = GL_POINTS;
88 break;
90 return NumVertexes;
93 /* Ensure the appropriate material states are set up - only change
94 state if really required */
95 static void init_materials(IWineD3DDevice *iface, BOOL isDiffuseSupplied) {
97 BOOL requires_material_reset = FALSE;
98 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
100 if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied) {
101 /* If we have not set up the material color tracking, do it now as required */
102 glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
103 checkGLcall("glDisable GL_COLOR_MATERIAL");
104 TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
105 glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
106 checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
107 glEnable(GL_COLOR_MATERIAL);
108 checkGLcall("glEnable GL_COLOR_MATERIAL");
109 This->tracking_color = IS_TRACKING;
110 requires_material_reset = TRUE; /* Restore material settings as will be used */
112 } else if ((This->tracking_color == IS_TRACKING && isDiffuseSupplied == FALSE) ||
113 (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == FALSE)) {
114 /* If we are tracking the current color but one isn't supplied, don't! */
115 glDisable(GL_COLOR_MATERIAL);
116 checkGLcall("glDisable GL_COLOR_MATERIAL");
117 This->tracking_color = NEEDS_TRACKING;
118 requires_material_reset = TRUE; /* Restore material settings as will be used */
120 } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied) {
121 /* No need to reset material colors since no change to gl_color_material */
122 requires_material_reset = FALSE;
124 } else if (This->tracking_color == NEEDS_DISABLE) {
125 glDisable(GL_COLOR_MATERIAL);
126 checkGLcall("glDisable GL_COLOR_MATERIAL");
127 This->tracking_color = DISABLED_TRACKING;
128 requires_material_reset = TRUE; /* Restore material settings as will be used */
131 /* Reset the material colors which may have been tracking the color*/
132 if (requires_material_reset) {
133 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->stateBlock->material.Ambient);
134 checkGLcall("glMaterialfv");
135 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->stateBlock->material.Diffuse);
136 checkGLcall("glMaterialfv");
137 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
138 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->stateBlock->material.Specular);
139 checkGLcall("glMaterialfv");
140 } else {
141 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
142 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
143 checkGLcall("glMaterialfv");
145 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->stateBlock->material.Emissive);
146 checkGLcall("glMaterialfv");
151 static GLfloat invymat[16] = {
152 1.0f, 0.0f, 0.0f, 0.0f,
153 0.0f, -1.0f, 0.0f, 0.0f,
154 0.0f, 0.0f, 1.0f, 0.0f,
155 0.0f, 0.0f, 0.0f, 1.0f};
157 void d3ddevice_set_ortho(IWineD3DDeviceImpl *This) {
158 /* If the last draw was transformed as well, no need to reapply all the matrixes */
159 if ( (!This->last_was_rhw) || (This->viewport_changed) ) {
161 double X, Y, height, width, minZ, maxZ;
162 This->last_was_rhw = TRUE;
163 This->viewport_changed = FALSE;
165 /* Transformed already into viewport coordinates, so we do not need transform
166 matrices. Reset all matrices to identity and leave the default matrix in world
167 mode. */
168 glMatrixMode(GL_MODELVIEW);
169 checkGLcall("glMatrixMode(GL_MODELVIEW)");
170 glLoadIdentity();
171 checkGLcall("glLoadIdentity");
173 glMatrixMode(GL_PROJECTION);
174 checkGLcall("glMatrixMode(GL_PROJECTION)");
175 glLoadIdentity();
176 checkGLcall("glLoadIdentity");
178 /* Set up the viewport to be full viewport */
179 X = This->stateBlock->viewport.X;
180 Y = This->stateBlock->viewport.Y;
181 height = This->stateBlock->viewport.Height;
182 width = This->stateBlock->viewport.Width;
183 minZ = This->stateBlock->viewport.MinZ;
184 maxZ = This->stateBlock->viewport.MaxZ;
185 if(!This->untransformed) {
186 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
187 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
188 } else {
189 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, 1.0, -1.0);
190 glOrtho(X, X + width, Y + height, Y, 1.0, -1.0);
192 checkGLcall("glOrtho");
194 /* Window Coord 0 is the middle of the first pixel, so translate by half
195 a pixel (See comment above glTranslate below) */
196 glTranslatef(0.375, 0.375, 0);
197 checkGLcall("glTranslatef(0.375, 0.375, 0)");
198 if (This->renderUpsideDown) {
199 glMultMatrixf(invymat);
200 checkGLcall("glMultMatrixf(invymat)");
203 /* Vertex fog on transformed vertices? Use the calculated fog factor stored in the specular color */
204 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != D3DFOG_NONE) {
205 if(GL_SUPPORT(EXT_FOG_COORD)) {
206 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
207 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)");
208 glFogi(GL_FOG_MODE, GL_LINEAR);
209 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
210 /* The dx fog range in this case is fixed to 0 - 255,
211 * but in GL it still depends on the fog start and end (according to the ext)
212 * Use this to turn around the fog as it's needed. That prevents some
213 * calculations during drawing :-)
215 glFogf(GL_FOG_START, (float) 0xff);
216 checkGLcall("glFogfv GL_FOG_END");
217 glFogf(GL_FOG_END, 0.0);
218 checkGLcall("glFogfv GL_FOG_START");
219 } else {
220 /* Disable GL fog, handle this in software in drawStridedSlow */
221 glDisable(GL_FOG);
222 checkGLcall("glDisable(GL_FOG)");
227 /* Setup views - Transformed & lit if RHW, else untransformed.
228 Only unlit if Normals are supplied
229 Returns: Whether to restore lighting afterwards */
230 static void primitiveInitState(
231 IWineD3DDevice *iface,
232 WineDirect3DVertexStridedData* strided,
233 BOOL useVS,
234 BOOL* lighting_changed,
235 BOOL* lighting_original) {
237 BOOL fixed_vtx_transformed =
238 (strided->u.s.position.lpData != NULL || strided->u.s.position.VBO != 0 ||
239 strided->u.s.position2.lpData != NULL || strided->u.s.position2.VBO != 0) &&
240 strided->u.s.position_transformed;
242 BOOL fixed_vtx_lit =
243 strided->u.s.normal.lpData == NULL && strided->u.s.normal.VBO == 0 &&
244 strided->u.s.normal2.lpData == NULL && strided->u.s.normal2.VBO == 0;
246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
248 *lighting_changed = FALSE;
250 /* If no normals, DISABLE lighting otherwise, don't touch lighing as it is
251 set by the appropriate render state. Note Vertex Shader output is already lit */
252 if (fixed_vtx_lit || useVS) {
253 *lighting_changed = TRUE;
254 *lighting_original = glIsEnabled(GL_LIGHTING);
255 glDisable(GL_LIGHTING);
256 checkGLcall("glDisable(GL_LIGHTING);");
257 TRACE("Disabled lighting, old state = %d\n", *lighting_original);
260 if (!useVS && fixed_vtx_transformed) {
261 d3ddevice_set_ortho(This);
263 } else {
265 /* Untransformed, so relies on the view and projection matrices */
266 This->untransformed = TRUE;
268 if (!useVS && (This->last_was_rhw || !This->modelview_valid)) {
269 /* Only reapply when have to */
270 This->modelview_valid = TRUE;
271 glMatrixMode(GL_MODELVIEW);
272 checkGLcall("glMatrixMode");
274 /* In the general case, the view matrix is the identity matrix */
275 if (This->view_ident) {
276 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]);
277 checkGLcall("glLoadMatrixf");
278 } else {
279 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
280 checkGLcall("glLoadMatrixf");
281 glMultMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]);
282 checkGLcall("glMultMatrixf");
286 if (!useVS && (This->last_was_rhw || !This->proj_valid)) {
287 /* Only reapply when have to */
288 This->proj_valid = TRUE;
289 glMatrixMode(GL_PROJECTION);
290 checkGLcall("glMatrixMode");
292 /* The rule is that the window coordinate 0 does not correspond to the
293 beginning of the first pixel, but the center of the first pixel.
294 As a consequence if you want to correctly draw one line exactly from
295 the left to the right end of the viewport (with all matrices set to
296 be identity), the x coords of both ends of the line would be not
297 -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
298 instead. */
299 glLoadIdentity();
301 glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
302 checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
304 if (This->renderUpsideDown) {
305 glMultMatrixf(invymat);
306 checkGLcall("glMultMatrixf(invymat)");
308 glMultMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_PROJECTION].u.m[0][0]);
309 checkGLcall("glLoadMatrixf");
312 /* Vertex Shader output is already transformed, so set up identity matrices */
313 if (useVS) {
314 glMatrixMode(GL_MODELVIEW);
315 checkGLcall("glMatrixMode");
316 glLoadIdentity();
317 glMatrixMode(GL_PROJECTION);
318 checkGLcall("glMatrixMode");
319 glLoadIdentity();
320 /* Window Coord 0 is the middle of the first pixel, so translate by half
321 a pixel (See comment above glTranslate above) */
322 glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
323 checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
324 if (This->renderUpsideDown) {
325 glMultMatrixf(invymat);
326 checkGLcall("glMultMatrixf(invymat)");
328 This->modelview_valid = FALSE;
329 This->proj_valid = FALSE;
331 This->last_was_rhw = FALSE;
333 /* Setup fogging */
334 if (useVS && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->usesFog) {
335 /* In D3D vertex shader return the 'final' fog value, while in OpenGL it is the 'input' fog value.
336 * The code below 'disables' the OpenGL postprocessing by setting the formula to '1'. */
337 glFogi(GL_FOG_MODE, GL_LINEAR);
338 glFogf(GL_FOG_START, 1.0f);
339 glFogf(GL_FOG_END, 0.0f);
341 } else if(This->stateBlock->renderState[WINED3DRS_FOGENABLE]
342 && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != D3DFOG_NONE) {
344 if(GL_SUPPORT(EXT_FOG_COORD)) {
345 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
346 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT)\n");
347 /* Reapply the fog range */
348 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
349 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
350 /* Restore the fog mode */
351 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGTABLEMODE, This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
352 } else {
353 /* Enable GL_FOG again because we disabled it above */
354 glEnable(GL_FOG);
355 checkGLcall("glEnable(GL_FOG)");
361 static BOOL fixed_get_input(
362 BYTE usage, BYTE usage_idx,
363 unsigned int* regnum) {
365 *regnum = -1;
367 /* Those positions must have the order in the
368 * named part of the strided data */
370 if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 0)
371 *regnum = 0;
372 else if (usage == D3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
373 *regnum = 1;
374 else if (usage == D3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
375 *regnum = 2;
376 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 0)
377 *regnum = 3;
378 else if (usage == D3DDECLUSAGE_PSIZE && usage_idx == 0)
379 *regnum = 4;
380 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 0)
381 *regnum = 5;
382 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 1)
383 *regnum = 6;
384 else if (usage == D3DDECLUSAGE_TEXCOORD && usage_idx < D3DDP_MAXTEXCOORD)
385 *regnum = 7 + usage_idx;
386 else if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 1)
387 *regnum = 7 + D3DDP_MAXTEXCOORD;
388 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 1)
389 *regnum = 8 + D3DDP_MAXTEXCOORD;
390 else if (usage == D3DDECLUSAGE_TANGENT && usage_idx == 0)
391 *regnum = 9 + D3DDP_MAXTEXCOORD;
392 else if (usage == D3DDECLUSAGE_BINORMAL && usage_idx == 0)
393 *regnum = 10 + D3DDP_MAXTEXCOORD;
394 else if (usage == D3DDECLUSAGE_TESSFACTOR && usage_idx == 0)
395 *regnum = 11 + D3DDP_MAXTEXCOORD;
396 else if (usage == D3DDECLUSAGE_FOG && usage_idx == 0)
397 *regnum = 12 + D3DDP_MAXTEXCOORD;
398 else if (usage == D3DDECLUSAGE_DEPTH && usage_idx == 0)
399 *regnum = 13 + D3DDP_MAXTEXCOORD;
400 else if (usage == D3DDECLUSAGE_SAMPLE && usage_idx == 0)
401 *regnum = 14 + D3DDP_MAXTEXCOORD;
403 if (*regnum < 0) {
404 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n",
405 debug_d3ddeclusage(usage), usage_idx);
406 return FALSE;
408 return TRUE;
411 void primitiveDeclarationConvertToStridedData(
412 IWineD3DDevice *iface,
413 BOOL useVertexShaderFunction,
414 WineDirect3DVertexStridedData *strided,
415 LONG BaseVertexIndex,
416 BOOL *fixup) {
418 /* We need to deal with frequency data!*/
420 BYTE *data = NULL;
421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
422 IWineD3DVertexDeclarationImpl* vertexDeclaration = NULL;
423 int i;
424 WINED3DVERTEXELEMENT *element;
425 DWORD stride;
426 int reg;
428 /* Locate the vertex declaration */
429 if (This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration) {
430 TRACE("Using vertex declaration from shader\n");
431 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration;
432 } else {
433 TRACE("Using vertex declaration\n");
434 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
437 /* Translate the declaration into strided data */
438 for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
439 GLint streamVBO = 0;
440 BOOL stride_used;
441 unsigned int idx;
443 element = vertexDeclaration->pDeclarationWine + i;
444 TRACE("%p Elements %p %d or %d\n", vertexDeclaration->pDeclarationWine, element, i, vertexDeclaration->declarationWNumElements);
445 if (This->stateBlock->streamIsUP) {
446 TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
447 streamVBO = 0;
448 data = (BYTE *)This->stateBlock->streamSource[element->Stream];
449 if(fixup && *fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
450 } else {
451 TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
452 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[element->Stream]);
453 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
454 if(fixup) {
455 if( streamVBO != 0) *fixup = TRUE;
456 else if(*fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
459 stride = This->stateBlock->streamStride[element->Stream];
460 data += (BaseVertexIndex * stride);
461 data += element->Offset;
462 reg = element->Reg;
464 TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex);
466 if (useVertexShaderFunction)
467 stride_used = vshader_get_input(This->stateBlock->vertexShader,
468 element->Usage, element->UsageIndex, &idx);
469 else
470 stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
472 if (stride_used) {
473 TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
474 "stream=%u, offset=%u, stride=%lu, VBO=%u]\n",
475 useVertexShaderFunction? "shader": "fixed function", idx,
476 debug_d3ddeclusage(element->Usage), element->UsageIndex,
477 element->Stream, element->Offset, stride, streamVBO);
479 strided->u.input[idx].lpData = data;
480 strided->u.input[idx].dwType = element->Type;
481 strided->u.input[idx].dwStride = stride;
482 strided->u.input[idx].VBO = streamVBO;
483 if (!useVertexShaderFunction) {
484 if (element->Usage == D3DDECLUSAGE_POSITION)
485 strided->u.s.position_transformed = FALSE;
486 else if (element->Usage == D3DDECLUSAGE_POSITIONT)
487 strided->u.s.position_transformed = TRUE;
493 void primitiveConvertFVFtoOffset(DWORD thisFVF, DWORD stride, BYTE *data, WineDirect3DVertexStridedData *strided, GLint streamVBO) {
494 int numBlends;
495 int numTextures;
496 int textureNo;
497 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
498 int numCoords[8]; /* Holding place for D3DFVF_TEXTUREFORMATx */
500 /* Either 3 or 4 floats depending on the FVF */
501 /* FIXME: Can blending data be in a different stream to the position data?
502 and if so using the fixed pipeline how do we handle it */
503 if (thisFVF & D3DFVF_POSITION_MASK) {
504 strided->u.s.position.lpData = data;
505 strided->u.s.position.dwType = D3DDECLTYPE_FLOAT3;
506 strided->u.s.position.dwStride = stride;
507 strided->u.s.position.VBO = streamVBO;
508 data += 3 * sizeof(float);
509 if (thisFVF & D3DFVF_XYZRHW) {
510 strided->u.s.position.dwType = D3DDECLTYPE_FLOAT4;
511 strided->u.s.position_transformed = TRUE;
512 data += sizeof(float);
513 } else
514 strided->u.s.position_transformed = FALSE;
517 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
518 /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
519 numBlends = 1 + (((thisFVF & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1);
520 if(thisFVF & D3DFVF_LASTBETA_UBYTE4) numBlends--;
522 if ((thisFVF & D3DFVF_XYZB5 ) > D3DFVF_XYZRHW) {
523 TRACE("Setting blend Weights to %p\n", data);
524 strided->u.s.blendWeights.lpData = data;
525 strided->u.s.blendWeights.dwType = D3DDECLTYPE_FLOAT1 + numBlends - 1;
526 strided->u.s.blendWeights.dwStride = stride;
527 strided->u.s.blendWeights.VBO = streamVBO;
528 data += numBlends * sizeof(FLOAT);
530 if (thisFVF & D3DFVF_LASTBETA_UBYTE4) {
531 strided->u.s.blendMatrixIndices.lpData = data;
532 strided->u.s.blendMatrixIndices.dwType = D3DDECLTYPE_UBYTE4;
533 strided->u.s.blendMatrixIndices.dwStride= stride;
534 strided->u.s.blendMatrixIndices.VBO = streamVBO;
535 data += sizeof(DWORD);
539 /* Normal is always 3 floats */
540 if (thisFVF & D3DFVF_NORMAL) {
541 strided->u.s.normal.lpData = data;
542 strided->u.s.normal.dwType = D3DDECLTYPE_FLOAT3;
543 strided->u.s.normal.dwStride = stride;
544 strided->u.s.normal.VBO = streamVBO;
545 data += 3 * sizeof(FLOAT);
548 /* Pointsize is a single float */
549 if (thisFVF & D3DFVF_PSIZE) {
550 strided->u.s.pSize.lpData = data;
551 strided->u.s.pSize.dwType = D3DDECLTYPE_FLOAT1;
552 strided->u.s.pSize.dwStride = stride;
553 strided->u.s.pSize.VBO = streamVBO;
554 data += sizeof(FLOAT);
557 /* Diffuse is 4 unsigned bytes */
558 if (thisFVF & D3DFVF_DIFFUSE) {
559 strided->u.s.diffuse.lpData = data;
560 strided->u.s.diffuse.dwType = D3DDECLTYPE_SHORT4;
561 strided->u.s.diffuse.dwStride = stride;
562 strided->u.s.diffuse.VBO = streamVBO;
563 data += sizeof(DWORD);
566 /* Specular is 4 unsigned bytes */
567 if (thisFVF & D3DFVF_SPECULAR) {
568 strided->u.s.specular.lpData = data;
569 strided->u.s.specular.dwType = D3DDECLTYPE_SHORT4;
570 strided->u.s.specular.dwStride = stride;
571 strided->u.s.specular.VBO = streamVBO;
572 data += sizeof(DWORD);
575 /* Texture coords */
576 numTextures = (thisFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
577 coordIdxInfo = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of D3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
579 /* numTextures indicates the number of texture coordinates supplied */
580 /* However, the first set may not be for stage 0 texture - it all */
581 /* depends on D3DTSS_TEXCOORDINDEX. */
582 /* The number of bytes for each coordinate set is based off */
583 /* D3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
585 /* So, for each supplied texture extract the coords */
586 for (textureNo = 0; textureNo < numTextures; ++textureNo) {
588 strided->u.s.texCoords[textureNo].lpData = data;
589 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT1;
590 strided->u.s.texCoords[textureNo].dwStride = stride;
591 strided->u.s.texCoords[textureNo].VBO = streamVBO;
592 numCoords[textureNo] = coordIdxInfo & 0x03;
594 /* Always one set */
595 data += sizeof(float);
596 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT1) {
597 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT2;
598 data += sizeof(float);
599 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT2) {
600 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT3;
601 data += sizeof(float);
602 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT3) {
603 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT4;
604 data += sizeof(float);
608 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
612 void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *strided, LONG BaseVertexIndex, BOOL *fixup) {
614 short LoopThroughTo = 0;
615 short nStream;
616 GLint streamVBO = 0;
618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
620 /* OK, Now to setup the data locations
621 For the non-created vertex shaders, the VertexShader var holds the real
622 FVF and only stream 0 matters
623 For the created vertex shaders, there is an FVF per stream */
624 if (!This->stateBlock->streamIsUP && !(This->stateBlock->vertexShader == NULL)) {
625 LoopThroughTo = MAX_STREAMS;
626 } else {
627 LoopThroughTo = 1;
630 /* Work through stream by stream */
631 for (nStream=0; nStream<LoopThroughTo; ++nStream) {
632 DWORD stride = This->stateBlock->streamStride[nStream];
633 BYTE *data = NULL;
634 DWORD thisFVF = 0;
636 /* Skip empty streams */
637 if (This->stateBlock->streamSource[nStream] == NULL) continue;
639 /* Retrieve appropriate FVF */
640 if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
641 thisFVF = This->stateBlock->fvf;
642 /* Handle memory passed directly as well as vertex buffers */
643 if (This->stateBlock->streamIsUP) {
644 streamVBO = 0;
645 data = (BYTE *)This->stateBlock->streamSource[nStream];
646 } else {
647 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[nStream]);
648 /* GetMemory binds the VBO */
649 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0, &streamVBO);
650 if(fixup) {
651 if(streamVBO != 0 ) *fixup = TRUE;
654 } else {
655 #if 0 /* TODO: Vertex shader support */
656 thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
657 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
658 #endif
660 VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
661 if (thisFVF == 0) continue;
663 /* Now convert the stream into pointers */
665 /* Shuffle to the beginning of the vertexes to render and index from there */
666 data = data + (BaseVertexIndex * stride);
668 primitiveConvertFVFtoOffset(thisFVF, stride, data, strided, streamVBO);
672 #if 0 /* TODO: Software Shaders */
673 /* Draw a single vertex using this information */
674 static void draw_vertex(IWineD3DDevice *iface, /* interface */
675 BOOL isXYZ, float x, float y, float z, float rhw, /* xyzn position*/
676 BOOL isNormal, float nx, float ny, float nz, /* normal */
677 BOOL isDiffuse, float *dRGBA, /* 1st colors */
678 BOOL isSpecular, float *sRGB, /* 2ndry colors */
679 BOOL isPtSize, float ptSize, /* pointSize */
680 WINED3DVECTOR_4 *texcoords, int *numcoords) /* texture info */
682 unsigned int textureNo;
683 float s, t, r, q;
684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
686 /* Diffuse -------------------------------- */
687 if (isDiffuse) {
688 glColor4fv(dRGBA);
689 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
692 /* Specular Colour ------------------------------------------*/
693 if (isSpecular) {
694 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
695 GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
696 VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
697 } else {
698 VTRACE(("Specular color extensions not supplied\n"));
702 /* Normal -------------------------------- */
703 if (isNormal) {
704 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
705 glNormal3f(nx, ny, nz);
708 /* Point Size ----------------------------------------------*/
709 if (isPtSize) {
711 /* no such functionality in the fixed function GL pipeline */
712 FIXME("Cannot change ptSize here in openGl\n");
715 /* Texture coords --------------------------- */
716 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
718 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
719 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
720 continue ;
723 /* Query tex coords */
724 if (This->stateBlock->textures[textureNo] != NULL) {
726 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
727 if (coordIdx >= MAX_TEXTURES) {
728 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
729 continue;
730 } else if (numcoords[coordIdx] == 0) {
731 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
732 continue;
733 } else {
735 /* Initialize vars */
736 s = 0.0f;
737 t = 0.0f;
738 r = 0.0f;
739 q = 0.0f;
741 switch (numcoords[coordIdx]) {
742 case 4: q = texcoords[coordIdx].w; /* drop through */
743 case 3: r = texcoords[coordIdx].z; /* drop through */
744 case 2: t = texcoords[coordIdx].y; /* drop through */
745 case 1: s = texcoords[coordIdx].x;
748 switch (numcoords[coordIdx]) { /* Supply the provided texture coords */
749 case D3DTTFF_COUNT1:
750 VTRACE(("tex:%d, s=%f\n", textureNo, s));
751 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
752 GLMULTITEXCOORD1F(textureNo, s);
753 } else {
754 glTexCoord1f(s);
756 break;
757 case D3DTTFF_COUNT2:
758 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
759 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
760 GLMULTITEXCOORD2F(textureNo, s, t);
761 } else {
762 glTexCoord2f(s, t);
764 break;
765 case D3DTTFF_COUNT3:
766 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
767 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
768 GLMULTITEXCOORD3F(textureNo, s, t, r);
769 } else {
770 glTexCoord3f(s, t, r);
772 break;
773 case D3DTTFF_COUNT4:
774 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
775 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
776 GLMULTITEXCOORD4F(textureNo, s, t, r, q);
777 } else {
778 glTexCoord4f(s, t, r, q);
780 break;
781 default:
782 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
786 } /* End of textures */
788 /* Position -------------------------------- */
789 if (isXYZ) {
790 if (1.0f == rhw || rhw < 0.00001f) {
791 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
792 glVertex3f(x, y, z);
793 } else {
794 /* Cannot optimize by dividing through by rhw as rhw is required
795 later for perspective in the GL pipeline for vertex shaders */
796 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
797 glVertex4f(x,y,z,rhw);
801 #endif /* TODO: Software shaders */
803 /* This should match any arrays loaded in loadNumberedArrays. */
804 /* TODO: Only load / unload arrays if we have to. */
805 static void unloadNumberedArrays(IWineD3DDevice *iface) {
806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
808 /* disable any attribs (this is the same for both GLSL and ARB modes) */
809 GLint maxAttribs;
810 int i;
812 /* Leave all the attribs disabled */
813 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
814 /* MESA does not support it right not */
815 if (glGetError() != GL_NO_ERROR)
816 maxAttribs = 16;
817 for (i = 0; i < maxAttribs; ++i) {
818 GL_EXTCALL(glDisableVertexAttribArrayARB(i));
819 checkGLcall("glDisableVertexAttribArrayARB(reg);");
823 /* TODO: Only load / unload arrays if we have to. */
824 static void loadNumberedArrays(
825 IWineD3DDevice *iface,
826 IWineD3DVertexShader *shader,
827 WineDirect3DVertexStridedData *strided) {
829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
830 GLint curVBO = -1;
831 int i;
833 for (i = 0; i < MAX_ATTRIBS; i++) {
835 if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
836 continue;
838 TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
840 if(curVBO != strided->u.input[i].VBO) {
841 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, strided->u.input[i].VBO));
842 checkGLcall("glBindBufferARB");
843 curVBO = strided->u.input[i].VBO;
845 GL_EXTCALL(glVertexAttribPointerARB(i,
846 WINED3D_ATR_SIZE(strided->u.input[i].dwType),
847 WINED3D_ATR_GLTYPE(strided->u.input[i].dwType),
848 WINED3D_ATR_NORMALIZED(strided->u.input[i].dwType),
849 strided->u.input[i].dwStride,
850 strided->u.input[i].lpData));
851 GL_EXTCALL(glEnableVertexAttribArrayARB(i));
855 /* This should match any arrays loaded in loadVertexData. */
856 /* TODO: Only load / unload arrays if we have to. */
857 static void unloadVertexData(IWineD3DDevice *iface) {
858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
859 int texture_idx;
861 glDisableClientState(GL_VERTEX_ARRAY);
862 glDisableClientState(GL_NORMAL_ARRAY);
863 glDisableClientState(GL_COLOR_ARRAY);
864 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
865 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
867 for (texture_idx = 0; texture_idx < GL_LIMITS(textures); ++texture_idx) {
868 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
869 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
873 /* TODO: Only load / unload arrays if we have to. */
874 static void loadVertexData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd) {
875 unsigned int textureNo = 0;
876 unsigned int texture_idx = 0;
877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
878 GLint curVBO = -1;
880 TRACE("Using fast vertex array code\n");
881 /* Blend Data ---------------------------------------------- */
882 if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) ||
883 (sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) {
886 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
888 #if 1
889 glEnableClientState(GL_WEIGHT_ARRAY_ARB);
890 checkGLcall("glEnableClientState(GL_WEIGHT_ARRAY_ARB)");
891 #endif
893 TRACE("Blend %d %p %ld\n", WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
894 sd->u.s.blendWeights.lpData, sd->u.s.blendWeights.dwStride);
895 /* FIXME("TODO\n");*/
896 /* Note dwType == float3 or float4 == 2 or 3 */
898 #if 0
899 /* with this on, the normals appear to be being modified,
900 but the vertices aren't being translated as they should be
901 Maybe the world matrix aren't being setup properly? */
902 glVertexBlendARB(WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) + 1);
903 #endif
906 VTRACE(("glWeightPointerARB(%d, GL_FLOAT, %ld, %p)\n",
907 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) ,
908 sd->u.s.blendWeights.dwStride,
909 sd->u.s.blendWeights.lpData));
911 if(curVBO != sd->u.s.blendWeights.VBO) {
912 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.blendWeights.VBO));
913 checkGLcall("glBindBufferARB");
914 curVBO = sd->u.s.blendWeights.VBO;
917 GL_EXTCALL(glWeightPointerARB)(
918 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
919 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
920 sd->u.s.blendWeights.dwStride,
921 sd->u.s.blendWeights.lpData);
923 checkGLcall("glWeightPointerARB");
925 if((sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO)){
926 static BOOL showfixme = TRUE;
927 if(showfixme){
928 FIXME("blendMatrixIndices support\n");
929 showfixme = FALSE;
933 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
934 /* FIXME("TODO\n");*/
935 #if 0
937 GL_EXTCALL(glVertexWeightPointerEXT)(
938 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
939 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
940 sd->u.s.blendWeights.dwStride,
941 sd->u.s.blendWeights.lpData);
942 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
943 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
944 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
945 #endif
947 } else {
948 /* TODO: support blends in fixupVertices */
949 FIXME("unsupported blending in openGl\n");
951 } else {
952 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
953 #if 0 /* TODO: Vertex blending */
954 glDisable(GL_VERTEX_BLEND_ARB);
955 #endif
956 TRACE("ARB_VERTEX_BLEND\n");
957 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
958 TRACE(" EXT_VERTEX_WEIGHTING\n");
959 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
960 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
965 #if 0 /* FOG ----------------------------------------------*/
966 if (sd->u.s.fog.lpData || sd->u.s.fog.VBO) {
967 /* TODO: fog*/
968 if (GL_SUPPORT(EXT_FOG_COORD) {
969 glEnableClientState(GL_FOG_COORDINATE_EXT);
970 (GL_EXTCALL)(FogCoordPointerEXT)(
971 WINED3D_ATR_GLTYPE(sd->u.s.fog.dwType),
972 sd->u.s.fog.dwStride,
973 sd->u.s.fog.lpData);
974 } else {
975 /* don't bother falling back to 'slow' as we don't support software FOG yet. */
976 /* FIXME: fixme once */
977 TRACE("Hardware support for FOG is not avaiable, FOG disabled.\n");
979 } else {
980 if (GL_SUPPRT(EXT_FOR_COORD) {
981 /* make sure fog is disabled */
982 glDisableClientState(GL_FOG_COORDINATE_EXT);
985 #endif
987 #if 0 /* tangents ----------------------------------------------*/
988 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO ||
989 sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
990 /* TODO: tangents*/
991 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
992 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO) {
993 glEnable(GL_TANGENT_ARRAY_EXT);
994 (GL_EXTCALL)(TangentPointerEXT)(
995 WINED3D_ATR_GLTYPE(sd->u.s.tangent.dwType),
996 sd->u.s.tangent.dwStride,
997 sd->u.s.tangent.lpData);
998 } else {
999 glDisable(GL_TANGENT_ARRAY_EXT);
1001 if (sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
1002 glEnable(GL_BINORMAL_ARRAY_EXT);
1003 (GL_EXTCALL)(BinormalPointerEXT)(
1004 WINED3D_ATR_GLTYPE(sd->u.s.binormal.dwType),
1005 sd->u.s.binormal.dwStride,
1006 sd->u.s.binormal.lpData);
1007 } else{
1008 glDisable(GL_BINORMAL_ARRAY_EXT);
1011 } else {
1012 /* don't bother falling back to 'slow' as we don't support software tangents and binormals yet . */
1013 /* FIXME: fixme once */
1014 TRACE("Hardware support for tangents and binormals is not avaiable, tangents and binormals disabled.\n");
1016 } else {
1017 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
1018 /* make sure fog is disabled */
1019 glDisable(GL_TANGENT_ARRAY_EXT);
1020 glDisable(GL_BINORMAL_ARRAY_EXT);
1023 #endif
1025 /* Point Size ----------------------------------------------*/
1026 if (sd->u.s.pSize.lpData || sd->u.s.pSize.VBO) {
1028 /* no such functionality in the fixed function GL pipeline */
1029 TRACE("Cannot change ptSize here in openGl\n");
1030 /* TODO: Implement this function in using shaders if they are available */
1034 /* Vertex Pointers -----------------------------------------*/
1035 if (sd->u.s.position.lpData != NULL || sd->u.s.position.VBO != 0) {
1036 /* Note dwType == float3 or float4 == 2 or 3 */
1037 VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n",
1038 sd->u.s.position.dwStride,
1039 sd->u.s.position.dwType + 1,
1040 sd->u.s.position.lpData));
1042 if(curVBO != sd->u.s.position.VBO) {
1043 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.position.VBO));
1044 checkGLcall("glBindBufferARB");
1045 curVBO = sd->u.s.position.VBO;
1048 /* min(WINED3D_ATR_SIZE(position),3) to Disable RHW mode as 'w' coord
1049 handling for rhw mode should not impact screen position whereas in GL it does.
1050 This may result in very slightly distored textures in rhw mode, but
1051 a very minimal different. There's always the other option of
1052 fixing the view matrix to prevent w from having any effect
1054 This only applies to user pointer sources, in VBOs the vertices are fixed up
1056 if(sd->u.s.position.VBO == 0) {
1057 glVertexPointer(3 /* min(WINED3D_ATR_SIZE(sd->u.s.position.dwType),3) */,
1058 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1059 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1060 } else {
1061 glVertexPointer(
1062 WINED3D_ATR_SIZE(sd->u.s.position.dwType),
1063 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1064 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1066 checkGLcall("glVertexPointer(...)");
1067 glEnableClientState(GL_VERTEX_ARRAY);
1068 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
1070 } else {
1071 glDisableClientState(GL_VERTEX_ARRAY);
1072 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
1075 /* Normals -------------------------------------------------*/
1076 if (sd->u.s.normal.lpData || sd->u.s.normal.VBO) {
1077 /* Note dwType == float3 or float4 == 2 or 3 */
1078 VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n",
1079 sd->u.s.normal.dwStride,
1080 sd->u.s.normal.lpData));
1081 if(curVBO != sd->u.s.normal.VBO) {
1082 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.normal.VBO));
1083 checkGLcall("glBindBufferARB");
1084 curVBO = sd->u.s.normal.VBO;
1086 glNormalPointer(
1087 WINED3D_ATR_GLTYPE(sd->u.s.normal.dwType),
1088 sd->u.s.normal.dwStride,
1089 sd->u.s.normal.lpData);
1090 checkGLcall("glNormalPointer(...)");
1091 glEnableClientState(GL_NORMAL_ARRAY);
1092 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
1094 } else {
1095 glDisableClientState(GL_NORMAL_ARRAY);
1096 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
1097 glNormal3f(0, 0, 1);
1098 checkGLcall("glNormal3f(0, 0, 1)");
1101 /* Diffuse Colour --------------------------------------------*/
1102 /* WARNING: Data here MUST be in RGBA format, so cannot */
1103 /* go directly into fast mode from app pgm, because */
1104 /* directx requires data in BGRA format. */
1105 /* currently fixupVertices swizels the format, but this isn't */
1106 /* very practical when using VBOS */
1107 /* NOTE: Unless we write a vertex shader to swizel the colour */
1108 /* , or the user doesn't care and wants the speed advantage */
1110 if (sd->u.s.diffuse.lpData || sd->u.s.diffuse.VBO) {
1111 /* Note dwType == float3 or float4 == 2 or 3 */
1112 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
1113 sd->u.s.diffuse.dwStride,
1114 sd->u.s.diffuse.lpData));
1116 if(curVBO != sd->u.s.diffuse.VBO) {
1117 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.diffuse.VBO));
1118 checkGLcall("glBindBufferARB");
1119 curVBO = sd->u.s.diffuse.VBO;
1121 glColorPointer(4, GL_UNSIGNED_BYTE,
1122 sd->u.s.diffuse.dwStride,
1123 sd->u.s.diffuse.lpData);
1124 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
1125 glEnableClientState(GL_COLOR_ARRAY);
1126 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
1128 } else {
1129 glDisableClientState(GL_COLOR_ARRAY);
1130 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
1131 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1132 checkGLcall("glColor4f(1, 1, 1, 1)");
1135 /* Specular Colour ------------------------------------------*/
1136 if (sd->u.s.specular.lpData || sd->u.s.specular.VBO) {
1137 TRACE("setting specular colour\n");
1138 /* Note dwType == float3 or float4 == 2 or 3 */
1139 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
1140 sd->u.s.specular.dwStride,
1141 sd->u.s.specular.lpData));
1142 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1143 if(curVBO != sd->u.s.specular.VBO) {
1144 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.specular.VBO));
1145 checkGLcall("glBindBufferARB");
1146 curVBO = sd->u.s.specular.VBO;
1148 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
1149 sd->u.s.specular.dwStride,
1150 sd->u.s.specular.lpData);
1151 vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
1152 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1153 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1154 } else {
1156 /* Missing specular color is not critical, no warnings */
1157 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1160 } else {
1161 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1163 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1164 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1165 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1166 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
1167 } else {
1169 /* Missing specular color is not critical, no warnings */
1170 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1174 /* Texture coords -------------------------------------------*/
1176 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1177 /* The code below uses glClientActiveTexture and glMultiTexCoord* which are all part of the GL_ARB_multitexture extension. */
1178 /* Abort if we don't support the extension. */
1179 if (!GL_SUPPORT(ARB_MULTITEXTURE)) {
1180 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1181 continue;
1184 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) {
1185 /* Select the correct texture stage */
1186 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1189 if (This->stateBlock->textures[textureNo] != NULL) {
1190 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1192 if (coordIdx >= MAX_TEXTURES) {
1193 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1194 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1195 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1197 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL && sd->u.s.texCoords[coordIdx].VBO == 0) {
1198 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
1199 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1200 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1202 } else {
1203 TRACE("Setting up texture %u, idx %d, cordindx %u, data %p\n",
1204 textureNo, texture_idx, coordIdx, sd->u.s.texCoords[coordIdx].lpData);
1205 if(curVBO != sd->u.s.texCoords[coordIdx].VBO) {
1206 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.texCoords[coordIdx].VBO));
1207 checkGLcall("glBindBufferARB");
1208 curVBO = sd->u.s.texCoords[coordIdx].VBO;
1210 /* The coords to supply depend completely on the fvf / vertex shader */
1211 glTexCoordPointer(
1212 WINED3D_ATR_SIZE(sd->u.s.texCoords[coordIdx].dwType),
1213 WINED3D_ATR_GLTYPE(sd->u.s.texCoords[coordIdx].dwType),
1214 sd->u.s.texCoords[coordIdx].dwStride,
1215 sd->u.s.texCoords[coordIdx].lpData);
1216 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1218 } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1219 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1220 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1222 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1224 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1225 for (textureNo = texture_idx; textureNo < GL_LIMITS(textures); ++textureNo) {
1226 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo));
1227 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1228 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1233 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
1234 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 if (idxData != NULL /* This crashes sometimes!*/) {
1238 TRACE("(%p) : glElements(%x, %d, %ld, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
1239 idxData = idxData == (void *)-1 ? NULL : idxData;
1240 #if 1
1241 #if 0
1242 glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
1243 glEnableClientState(GL_INDEX_ARRAY);
1244 #endif
1245 glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1246 (const char *)idxData+(idxSize * startIdx));
1247 #else /* using drawRangeElements may be faster */
1249 glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
1250 idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1251 (const char *)idxData+(idxSize * startIdx));
1252 #endif
1253 checkGLcall("glDrawRangeElements");
1255 } else {
1257 /* Note first is now zero as we shuffled along earlier */
1258 TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
1259 glDrawArrays(glPrimitiveType, 0, numberOfVertices);
1260 checkGLcall("glDrawArrays");
1264 return;
1268 * Actually draw using the supplied information.
1269 * Slower GL version which extracts info about each vertex in turn
1272 static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1273 UINT NumVertexes, GLenum glPrimType,
1274 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1276 unsigned int textureNo = 0;
1277 unsigned int texture_idx = 0;
1278 const short *pIdxBufS = NULL;
1279 const long *pIdxBufL = NULL;
1280 LONG SkipnStrides = 0;
1281 LONG vx_index;
1282 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1283 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
1284 float rhw = 0.0f; /* rhw */
1285 float ptSize = 0.0f; /* Point size */
1286 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
1287 DWORD specularColor = 0; /* Specular Color */
1288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1290 TRACE("Using slow vertex array code\n");
1292 /* Variable Initialization */
1293 if (idxData != NULL) {
1294 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1295 else pIdxBufL = (const long *) idxData;
1298 /* Start drawing in GL */
1299 VTRACE(("glBegin(%x)\n", glPrimType));
1300 glBegin(glPrimType);
1302 /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
1303 * Guess it's not necessary(we crash then anyway) and would only eat CPU time
1306 /* For each primitive */
1307 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1309 /* Initialize diffuse color */
1310 diffuseColor = 0xFFFFFFFF;
1312 /* For indexed data, we need to go a few more strides in */
1313 if (idxData != NULL) {
1315 /* Indexed so work out the number of strides to skip */
1316 if (idxSize == 2) {
1317 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1318 SkipnStrides = pIdxBufS[startIdx + vx_index];
1319 } else {
1320 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1321 SkipnStrides = pIdxBufL[startIdx + vx_index];
1325 /* Position Information ------------------ */
1326 if (sd->u.s.position.lpData != NULL) {
1328 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
1329 x = ptrToCoords[0];
1330 y = ptrToCoords[1];
1331 z = ptrToCoords[2];
1332 rhw = 1.0;
1333 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
1335 /* RHW follows, only if transformed, ie 4 floats were provided */
1336 if (sd->u.s.position_transformed) {
1337 rhw = ptrToCoords[3];
1338 VTRACE(("rhw=%f\n", rhw));
1342 /* Blending data -------------------------- */
1343 if (sd->u.s.blendWeights.lpData != NULL) {
1344 /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
1345 FIXME("Blending not supported yet\n");
1347 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
1348 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
1352 /* Vertex Normal Data (untransformed only)- */
1353 if (sd->u.s.normal.lpData != NULL) {
1355 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
1356 nx = ptrToCoords[0];
1357 ny = ptrToCoords[1];
1358 nz = ptrToCoords[2];
1359 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
1362 /* Point Size ----------------------------- */
1363 if (sd->u.s.pSize.lpData != NULL) {
1365 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1366 ptSize = ptrToCoords[0];
1367 VTRACE(("ptSize=%f\n", ptSize));
1368 FIXME("No support for ptSize yet\n");
1371 /* Diffuse -------------------------------- */
1372 if (sd->u.s.diffuse.lpData != NULL) {
1374 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1375 diffuseColor = ptrToCoords[0];
1376 VTRACE(("diffuseColor=%lx\n", diffuseColor));
1379 /* Specular -------------------------------- */
1380 if (sd->u.s.specular.lpData != NULL) {
1382 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1383 specularColor = ptrToCoords[0];
1384 VTRACE(("specularColor=%lx\n", specularColor));
1387 /* Texture coords --------------------------- */
1388 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1390 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1391 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1392 continue ;
1395 /* Query tex coords */
1396 if (This->stateBlock->textures[textureNo] != NULL) {
1398 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1399 float *ptrToCoords = NULL;
1400 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1402 if (coordIdx > 7) {
1403 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1404 ++texture_idx;
1405 continue;
1406 } else if (coordIdx < 0) {
1407 FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
1408 ++texture_idx;
1409 continue;
1412 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1413 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1414 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1415 ++texture_idx;
1416 continue;
1417 } else {
1419 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DDECLTYPE_FLOAT1 etc */
1421 /* The coords to supply depend completely on the fvf / vertex shader */
1422 switch (coordsToUse) {
1423 case 4: q = ptrToCoords[3]; /* drop through */
1424 case 3: r = ptrToCoords[2]; /* drop through */
1425 case 2: t = ptrToCoords[1]; /* drop through */
1426 case 1: s = ptrToCoords[0];
1429 /* Projected is more 'fun' - Move the last coord to the 'q'
1430 parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1431 if ((This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1432 (This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1434 if (This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1435 switch (coordsToUse) {
1436 case 0: /* Drop Through */
1437 case 1:
1438 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1439 break;
1440 case 2:
1441 q = t;
1442 t = 0.0;
1443 coordsToUse = 4;
1444 break;
1445 case 3:
1446 q = r;
1447 r = 0.0;
1448 coordsToUse = 4;
1449 break;
1450 case 4: /* Nop here */
1451 break;
1452 default:
1453 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n",
1454 This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1459 switch (coordsToUse) { /* Supply the provided texture coords */
1460 case D3DTTFF_COUNT1:
1461 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1462 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1463 GL_EXTCALL(glMultiTexCoord1fARB(texture_idx, s));
1464 } else {
1465 glTexCoord1f(s);
1467 break;
1468 case D3DTTFF_COUNT2:
1469 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1470 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1471 GL_EXTCALL(glMultiTexCoord2fARB(texture_idx, s, t));
1472 } else {
1473 glTexCoord2f(s, t);
1475 break;
1476 case D3DTTFF_COUNT3:
1477 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1478 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1479 GL_EXTCALL(glMultiTexCoord3fARB(texture_idx, s, t, r));
1480 } else {
1481 glTexCoord3f(s, t, r);
1483 break;
1484 case D3DTTFF_COUNT4:
1485 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1486 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1487 GL_EXTCALL(glMultiTexCoord4fARB(texture_idx, s, t, r, q));
1488 } else {
1489 glTexCoord4f(s, t, r, q);
1491 break;
1492 default:
1493 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1497 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1498 } /* End of textures */
1500 /* Diffuse -------------------------------- */
1501 if (sd->u.s.diffuse.lpData != NULL) {
1502 glColor4ub(D3DCOLOR_B_R(diffuseColor),
1503 D3DCOLOR_B_G(diffuseColor),
1504 D3DCOLOR_B_B(diffuseColor),
1505 D3DCOLOR_B_A(diffuseColor));
1506 VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n",
1507 D3DCOLOR_B_R(diffuseColor),
1508 D3DCOLOR_B_G(diffuseColor),
1509 D3DCOLOR_B_B(diffuseColor),
1510 D3DCOLOR_B_A(diffuseColor)));
1511 } else {
1512 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1515 /* Specular ------------------------------- */
1516 if (sd->u.s.specular.lpData != NULL) {
1517 /* special case where the fog density is stored in the diffuse alpha channel */
1518 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
1519 (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == D3DFOG_NONE || sd->u.s.position.dwType == D3DDECLTYPE_FLOAT4 )&&
1520 This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
1521 if(GL_SUPPORT(EXT_FOG_COORD)) {
1522 GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
1523 } else {
1524 static BOOL warned = FALSE;
1525 if(!warned) {
1526 /* TODO: Use the fog table code from old ddraw */
1527 FIXME("Implement fog for transformed vertices in software\n");
1528 warned = TRUE;
1533 VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n",
1534 D3DCOLOR_B_R(specularColor),
1535 D3DCOLOR_B_G(specularColor),
1536 D3DCOLOR_B_B(specularColor)));
1537 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1538 GL_EXTCALL(glSecondaryColor3ubEXT)(
1539 D3DCOLOR_B_R(specularColor),
1540 D3DCOLOR_B_G(specularColor),
1541 D3DCOLOR_B_B(specularColor));
1542 } else {
1543 /* Do not worry if specular colour missing and disable request */
1544 VTRACE(("Specular color extensions not supplied\n"));
1546 } else {
1547 if (vx_index == 0) {
1548 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1549 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1550 } else {
1551 /* Do not worry if specular colour missing and disable request */
1552 VTRACE(("Specular color extensions not supplied\n"));
1557 /* Normal -------------------------------- */
1558 if (sd->u.s.normal.lpData != NULL) {
1559 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1560 glNormal3f(nx, ny, nz);
1561 } else {
1562 if (vx_index == 0) glNormal3f(0, 0, 1);
1565 /* Position -------------------------------- */
1566 if (sd->u.s.position.lpData != NULL) {
1567 if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
1568 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1569 glVertex3f(x, y, z);
1570 } else {
1571 GLfloat w = 1.0 / rhw;
1572 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1573 glVertex4f(x*w, y*w, z*w, w);
1577 /* For non indexed mode, step onto next parts */
1578 if (idxData == NULL) {
1579 ++SkipnStrides;
1583 glEnd();
1584 checkGLcall("glEnd and previous calls");
1587 #if 0 /* TODO: Software/Hardware vertex blending support */
1589 * Draw with emulated vertex shaders
1590 * Note: strided data is uninitialized, as we need to pass the vertex
1591 * shader directly as ordering irs yet
1593 void drawStridedSoftwareVS(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1594 int PrimitiveType, ULONG NumPrimitives,
1595 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1597 unsigned int textureNo = 0;
1598 GLenum glPrimType = GL_POINTS;
1599 int NumVertexes = NumPrimitives;
1600 const short *pIdxBufS = NULL;
1601 const long *pIdxBufL = NULL;
1602 LONG SkipnStrides = 0;
1603 LONG vx_index;
1604 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1605 float rhw = 0.0f; /* rhw */
1606 float ptSize = 0.0f; /* Point size */
1607 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1608 int numcoords[8]; /* Number of coords */
1609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1611 IDirect3DVertexShaderImpl* vertexShader = NULL;
1613 TRACE("Using slow software vertex shader code\n");
1615 /* Variable Initialization */
1616 if (idxData != NULL) {
1617 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1618 else pIdxBufL = (const long *) idxData;
1621 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1622 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1624 /* Retrieve the VS information */
1625 vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
1627 /* Start drawing in GL */
1628 VTRACE(("glBegin(%x)\n", glPrimType));
1629 glBegin(glPrimType);
1631 /* For each primitive */
1632 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1634 /* For indexed data, we need to go a few more strides in */
1635 if (idxData != NULL) {
1637 /* Indexed so work out the number of strides to skip */
1638 if (idxSize == 2) {
1639 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1640 SkipnStrides = pIdxBufS[startIdx+vx_index];
1641 } else {
1642 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1643 SkipnStrides = pIdxBufL[startIdx+vx_index];
1647 /* Fill the vertex shader input */
1648 IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1650 /* Initialize the output fields to the same defaults as it would normally have */
1651 memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1652 vertexShader->output.oD[0].x = 1.0;
1653 vertexShader->output.oD[0].y = 1.0;
1654 vertexShader->output.oD[0].z = 1.0;
1655 vertexShader->output.oD[0].w = 1.0;
1657 /* Now execute the vertex shader */
1658 IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1661 TRACE_VECTOR(vertexShader->output.oPos);
1662 TRACE_VECTOR(vertexShader->output.oD[0]);
1663 TRACE_VECTOR(vertexShader->output.oD[1]);
1664 TRACE_VECTOR(vertexShader->output.oT[0]);
1665 TRACE_VECTOR(vertexShader->output.oT[1]);
1666 TRACE_VECTOR(vertexShader->input.V[0]);
1667 TRACE_VECTOR(vertexShader->data->C[0]);
1668 TRACE_VECTOR(vertexShader->data->C[1]);
1669 TRACE_VECTOR(vertexShader->data->C[2]);
1670 TRACE_VECTOR(vertexShader->data->C[3]);
1671 TRACE_VECTOR(vertexShader->data->C[4]);
1672 TRACE_VECTOR(vertexShader->data->C[5]);
1673 TRACE_VECTOR(vertexShader->data->C[6]);
1674 TRACE_VECTOR(vertexShader->data->C[7]);
1677 /* Extract out the output */
1678 /* FIXME: Fog coords? */
1679 x = vertexShader->output.oPos.x;
1680 y = vertexShader->output.oPos.y;
1681 z = vertexShader->output.oPos.z;
1682 rhw = vertexShader->output.oPos.w;
1683 ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1685 /** Update textures coords using vertexShader->output.oT[0->7] */
1686 memset(texcoords, 0x00, sizeof(texcoords));
1687 memset(numcoords, 0x00, sizeof(numcoords));
1688 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1689 if (This->stateBlock->textures[textureNo] != NULL) {
1690 texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1691 texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1692 texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1693 texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1694 if (This->stateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1695 numcoords[textureNo] = This->stateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1696 } else {
1697 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1698 case WINED3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1699 case WINED3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1700 default: numcoords[textureNo] = 4;
1703 } else {
1704 numcoords[textureNo] = 0;
1708 /* Draw using this information */
1709 draw_vertex(iface,
1710 TRUE, x, y, z, rhw,
1711 TRUE, 0.0f, 0.0f, 1.0f,
1712 TRUE, (float*) &vertexShader->output.oD[0],
1713 TRUE, (float*) &vertexShader->output.oD[1],
1714 FALSE, ptSize, /* FIXME: Change back when supported */
1715 texcoords, numcoords);
1717 /* For non indexed mode, step onto next parts */
1718 if (idxData == NULL) {
1719 ++SkipnStrides;
1722 } /* for each vertex */
1724 glEnd();
1725 checkGLcall("glEnd and previous calls");
1728 #endif
1730 inline static void drawPrimitiveDrawStrided(
1731 IWineD3DDevice *iface,
1732 BOOL useVertexShaderFunction,
1733 BOOL usePixelShaderFunction,
1734 WineDirect3DVertexStridedData *dataLocations,
1735 UINT numberOfvertices,
1736 UINT numberOfIndicies,
1737 GLenum glPrimType,
1738 const void *idxData,
1739 short idxSize,
1740 int minIndex,
1741 long StartIdx,
1742 BOOL fixup) {
1744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1745 BOOL useDrawStridedSlow;
1747 int startStride = idxData == NULL ? 0 :
1748 idxData == (void *) -1 ? 0 :
1749 (idxSize == 2 ? *(((const short *) idxData) + StartIdx) : *((const int *) idxData) + StartIdx);
1750 int endStride = startStride;
1751 TRACE("begin Start stride %d, end stride %d, number of indices%d, number of vertices%d\n",
1752 startStride, endStride, numberOfIndicies, numberOfvertices);
1754 /* Generate some fixme's if unsupported functionality is being used */
1755 #define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData
1756 /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */
1757 if (!useVertexShaderFunction && (BUFFER_OR_DATA(blendMatrixIndices) || BUFFER_OR_DATA(blendWeights))) {
1758 FIXME("Blending data is only valid with vertex shaders %p %p\n",dataLocations->u.s.blendWeights.lpData,dataLocations->u.s.blendWeights.lpData);
1760 if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) {
1761 FIXME("Tweening is only valid with vertex shaders\n");
1763 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) {
1764 FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n");
1766 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) {
1767 FIXME("Extended attributes are only valid with vertex shaders\n");
1769 #undef BUFFER_OR_DATA
1771 /* Fixed pipeline, no fixups required - load arrays */
1772 if (!useVertexShaderFunction &&
1773 ((dataLocations->u.s.pSize.lpData == NULL &&
1774 dataLocations->u.s.diffuse.lpData == NULL &&
1775 dataLocations->u.s.specular.lpData == NULL) ||
1776 fixup) ) {
1778 /* Load the vertex data using named arrays */
1779 TRACE("(%p) Loading vertex data\n", This);
1780 loadVertexData(iface, dataLocations);
1781 useDrawStridedSlow = FALSE;
1783 /* Shader pipeline - load attribute arrays */
1784 } else if(useVertexShaderFunction) {
1786 loadNumberedArrays(iface, This->stateBlock->vertexShader, dataLocations);
1787 useDrawStridedSlow = FALSE;
1789 /* We compile the shader here because we need the vertex declaration
1790 * in order to determine if we need to do any swizzling for D3DCOLOR
1791 * registers. If the shader is already compiled this call will do nothing. */
1792 IWineD3DVertexShader_CompileShader(This->stateBlock->vertexShader);
1793 /* Draw vertex by vertex */
1794 } else {
1795 TRACE("Not loading vertex data\n");
1796 useDrawStridedSlow = TRUE;
1799 /* If GLSL is used for either pixel or vertex shaders, make a GLSL program
1800 * Otherwise set NULL, to restore fixed function */
1801 if ((wined3d_settings.vs_selected_mode == SHADER_GLSL && useVertexShaderFunction) ||
1802 (wined3d_settings.ps_selected_mode == SHADER_GLSL && usePixelShaderFunction))
1803 set_glsl_shader_program(iface);
1804 else
1805 This->stateBlock->glsl_program = NULL;
1807 /* If GLSL is used now, or might have been used before, (re)set the program */
1808 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
1809 wined3d_settings.ps_selected_mode == SHADER_GLSL) {
1811 GLhandleARB progId = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->programId : 0;
1812 if (progId)
1813 TRACE_(d3d_shader)("Using GLSL program %u\n", progId);
1814 GL_EXTCALL(glUseProgramObjectARB(progId));
1815 checkGLcall("glUseProgramObjectARB");
1818 if (useVertexShaderFunction) {
1820 TRACE("Using vertex shader\n");
1822 if (wined3d_settings.vs_selected_mode == SHADER_ARB) {
1823 /* Bind the vertex program */
1824 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB,
1825 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId));
1826 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
1828 /* Enable OpenGL vertex programs */
1829 glEnable(GL_VERTEX_PROGRAM_ARB);
1830 checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
1831 TRACE_(d3d_shader)("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n",
1832 This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId);
1836 if (usePixelShaderFunction) {
1838 TRACE("Using pixel shader\n");
1840 if (wined3d_settings.ps_selected_mode == SHADER_ARB) {
1841 /* Bind the fragment program */
1842 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,
1843 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId));
1844 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
1846 /* Enable OpenGL fragment programs */
1847 glEnable(GL_FRAGMENT_PROGRAM_ARB);
1848 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
1849 TRACE_(d3d_shader)("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n",
1850 This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId);
1854 /* Load any global constants/uniforms that may have been set by the application */
1855 if (wined3d_settings.vs_selected_mode == SHADER_GLSL || wined3d_settings.ps_selected_mode == SHADER_GLSL)
1856 shader_glsl_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
1857 else if (wined3d_settings.vs_selected_mode== SHADER_ARB || wined3d_settings.ps_selected_mode == SHADER_ARB)
1858 shader_arb_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
1860 /* Draw vertex-by-vertex */
1861 if (useDrawStridedSlow)
1862 drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1863 else
1864 drawStridedFast(iface, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1866 /* Cleanup vertex program */
1867 if (useVertexShaderFunction) {
1868 unloadNumberedArrays(iface);
1870 if (wined3d_settings.vs_selected_mode == SHADER_ARB)
1871 glDisable(GL_VERTEX_PROGRAM_ARB);
1872 } else {
1873 unloadVertexData(iface);
1876 /* Cleanup fragment program */
1877 if (usePixelShaderFunction && wined3d_settings.ps_selected_mode == SHADER_ARB)
1878 glDisable(GL_FRAGMENT_PROGRAM_ARB);
1881 inline void drawPrimitiveTraceDataLocations(
1882 WineDirect3DVertexStridedData *dataLocations) {
1884 /* Dump out what parts we have supplied */
1885 TRACE("Strided Data:\n");
1886 TRACE_STRIDED((dataLocations), position);
1887 TRACE_STRIDED((dataLocations), blendWeights);
1888 TRACE_STRIDED((dataLocations), blendMatrixIndices);
1889 TRACE_STRIDED((dataLocations), normal);
1890 TRACE_STRIDED((dataLocations), pSize);
1891 TRACE_STRIDED((dataLocations), diffuse);
1892 TRACE_STRIDED((dataLocations), specular);
1893 TRACE_STRIDED((dataLocations), texCoords[0]);
1894 TRACE_STRIDED((dataLocations), texCoords[1]);
1895 TRACE_STRIDED((dataLocations), texCoords[2]);
1896 TRACE_STRIDED((dataLocations), texCoords[3]);
1897 TRACE_STRIDED((dataLocations), texCoords[4]);
1898 TRACE_STRIDED((dataLocations), texCoords[5]);
1899 TRACE_STRIDED((dataLocations), texCoords[6]);
1900 TRACE_STRIDED((dataLocations), texCoords[7]);
1901 TRACE_STRIDED((dataLocations), position2);
1902 TRACE_STRIDED((dataLocations), normal2);
1903 TRACE_STRIDED((dataLocations), tangent);
1904 TRACE_STRIDED((dataLocations), binormal);
1905 TRACE_STRIDED((dataLocations), tessFactor);
1906 TRACE_STRIDED((dataLocations), fog);
1907 TRACE_STRIDED((dataLocations), depth);
1908 TRACE_STRIDED((dataLocations), sample);
1910 return;
1914 static void drawPrimitiveUploadTexturesPS(IWineD3DDeviceImpl* This) {
1915 INT i;
1917 for (i = 0; i < GL_LIMITS(samplers); ++i) {
1918 /* Pixel shader support should imply multitexture support. */
1919 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1920 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1921 checkGLcall("glActiveTextureARB");
1922 } else if (i) {
1923 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1926 if (!This->stateBlock->textures[i]) continue;
1928 /* Enable the correct target. Is this required for GLSL? For ARB_fragment_program it isn't, afaik. */
1929 glDisable(GL_TEXTURE_1D);
1930 This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1931 switch(This->stateBlock->textureDimensions[i]) {
1932 case GL_TEXTURE_2D:
1933 glDisable(GL_TEXTURE_3D);
1934 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1935 break;
1936 case GL_TEXTURE_3D:
1937 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1938 glDisable(GL_TEXTURE_2D);
1939 break;
1940 case GLTEXTURECUBEMAP:
1941 glDisable(GL_TEXTURE_2D);
1942 glDisable(GL_TEXTURE_3D);
1943 break;
1945 glEnable(This->stateBlock->textureDimensions[i]);
1947 /* Upload texture, apply states */
1948 IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
1949 IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, i, REAPPLY_ALPHAOP);
1950 IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
1954 /* uploads textures and setup texture states ready for rendering */
1955 static void drawPrimitiveUploadTextures(IWineD3DDeviceImpl* This) {
1956 INT current_sampler = 0;
1957 float constant_color[4];
1958 unsigned int i;
1960 /* ARB_texture_env_combine is limited to GL_MAX_TEXTURE_UNITS stages. On
1961 * nVidia cards GL_MAX_TEXTURE_UNITS is generally not larger than 4.
1962 * Register combiners however provide up to 8 combiner stages. In order to
1963 * take advantage of this, we need to be separate D3D texture stages from
1964 * GL texture units. When using register combiners GL_MAX_TEXTURE_UNITS
1965 * corresponds to MaxSimultaneousTextures and GL_MAX_GENERAL_COMBINERS_NV
1966 * corresponds to MaxTextureBlendStages in the caps. */
1968 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1969 glEnable(GL_REGISTER_COMBINERS_NV);
1970 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], constant_color);
1971 GL_EXTCALL(glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, &constant_color[0]));
1974 for (i = 0; i < GL_LIMITS(texture_stages); ++i) {
1975 INT texture_idx = -1;
1977 /* D3DTOP_DISABLE disables the current & any higher texture stages */
1978 if (This->stateBlock->textureState[i][WINED3DTSS_COLOROP] == D3DTOP_DISABLE) break;
1980 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[i]) {
1981 texture_idx = current_sampler++;
1983 /* Active the texture unit corresponding to the current texture stage */
1984 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1985 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1986 checkGLcall("glActiveTextureARB");
1987 } else if (i) {
1988 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1992 if (This->stateBlock->textures[i]) {
1993 /* Enable the correct target. */
1994 glDisable(GL_TEXTURE_1D);
1995 This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1996 switch(This->stateBlock->textureDimensions[i]) {
1997 case GL_TEXTURE_2D:
1998 glDisable(GL_TEXTURE_3D);
1999 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2000 break;
2001 case GL_TEXTURE_3D:
2002 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2003 glDisable(GL_TEXTURE_2D);
2004 break;
2005 case GLTEXTURECUBEMAP:
2006 glDisable(GL_TEXTURE_2D);
2007 glDisable(GL_TEXTURE_3D);
2008 break;
2011 /* imply GL_SUPPORT(NV_TEXTURE_SHADER) when setting texture_shader_active */
2012 if (This->texture_shader_active && This->stateBlock->textureDimensions[i] == GL_TEXTURE_2D) {
2013 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
2014 } else {
2015 glEnable(This->stateBlock->textureDimensions[i]);
2018 /* Upload texture, apply states */
2019 IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
2020 IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, texture_idx, REAPPLY_ALPHAOP);
2021 IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
2022 } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2023 /* ARB_texture_env_combine needs a valid texture bound to the
2024 * texture unit, even if it isn't used. Bind a dummy texture. */
2025 glDisable(GL_TEXTURE_2D);
2026 glDisable(GL_TEXTURE_3D);
2027 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2028 glEnable(GL_TEXTURE_1D);
2029 This->stateBlock->textureDimensions[i] = GL_TEXTURE_1D;
2030 glBindTexture(GL_TEXTURE_1D, This->dummyTextureName[i]);
2033 /** these ops apply to the texture unit, so they are preserved between texture changes, but for now brute force and reapply all
2034 dx9_1pass_emboss_bump_mapping and dx9_2pass_emboss_bump_mapping are good texts to make sure the states are being applied when needed **/
2035 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2036 set_tex_op_nvrc((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
2037 This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
2038 This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
2039 This->stateBlock->textureState[i][WINED3DTSS_COLORARG0],
2040 texture_idx);
2041 /* alphaop */
2042 set_tex_op_nvrc((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2043 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2044 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2045 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0],
2046 texture_idx);
2047 } else {
2048 set_tex_op((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
2049 This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
2050 This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
2051 This->stateBlock->textureState[i][WINED3DTSS_COLORARG0]);
2052 /* alphaop */
2053 set_tex_op((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2054 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2055 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2056 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0]);
2060 /* If we're using register combiners, set the amount of *used* combiners.
2061 * Ie, the number of stages below the first stage to have a color op of
2062 * D3DTOP_DISABLE. */
2063 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2064 /* NUM_GENERAL_COMBINERS_NV should be > 0 */
2065 if (!i) glDisable(GL_REGISTER_COMBINERS_NV);
2066 else GL_EXTCALL(glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, i));
2069 /* Disable the remaining texture units. */
2070 for (i = current_sampler; i < GL_LIMITS(textures); ++i) {
2071 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2072 glDisable(GL_TEXTURE_1D);
2073 glDisable(GL_TEXTURE_2D);
2074 glDisable(GL_TEXTURE_3D);
2075 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2079 /* Routine common to the draw primitive and draw indexed primitive routines */
2080 void drawPrimitive(IWineD3DDevice *iface,
2081 int PrimitiveType,
2082 long NumPrimitives,
2083 /* for Indexed: */
2084 long StartVertexIndex,
2085 UINT numberOfVertices,
2086 long StartIdx,
2087 short idxSize,
2088 const void *idxData,
2089 int minIndex,
2090 WineDirect3DVertexStridedData *DrawPrimStrideData) {
2092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2093 BOOL useVertexShaderFunction = FALSE;
2094 BOOL usePixelShaderFunction = FALSE;
2095 WineDirect3DVertexStridedData *dataLocations;
2096 IWineD3DSwapChainImpl *swapchain;
2097 int i;
2098 BOOL fixup = FALSE;
2100 BOOL lighting_changed, lighting_original = FALSE;
2102 /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
2103 * here simply check whether a shader was set, or the user disabled shaders */
2104 if (wined3d_settings.vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
2105 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL)
2106 useVertexShaderFunction = TRUE;
2108 if (wined3d_settings.ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
2109 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function)
2110 usePixelShaderFunction = TRUE;
2112 /* Invalidate the back buffer memory so LockRect will read it the next time */
2113 for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
2114 IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
2115 if(swapchain) {
2116 if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer[0])->Flags |= SFLAG_GLDIRTY;
2117 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2121 /* Ok, we will be updating the screen from here onwards so grab the lock */
2122 ENTER_GL();
2124 if(DrawPrimStrideData) {
2126 /* Note: this is a ddraw fixed-function code path */
2128 TRACE("================ Strided Input ===================\n");
2129 dataLocations = DrawPrimStrideData;
2130 drawPrimitiveTraceDataLocations(dataLocations);
2131 fixup = FALSE;
2134 else if (This->stateBlock->vertexDecl || This->stateBlock->vertexShader) {
2136 /* Note: This is a fixed function or shader codepath.
2137 * This means it must handle both types of strided data.
2138 * Shaders must go through here to zero the strided data, even if they
2139 * don't set any declaration at all */
2141 TRACE("================ Vertex Declaration ===================\n");
2142 dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2143 if(!dataLocations) {
2144 ERR("Out of memory!\n");
2145 return;
2148 if (This->stateBlock->vertexDecl != NULL ||
2149 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration != NULL)
2151 primitiveDeclarationConvertToStridedData(iface, useVertexShaderFunction,
2152 dataLocations, StartVertexIndex, &fixup);
2154 } else {
2156 /* Note: This codepath is not reachable from d3d9 (see fvf->decl9 conversion)
2157 * It is reachable through d3d8, but only for fixed-function.
2158 * It will not work properly for shaders. */
2160 TRACE("================ FVF ===================\n");
2161 dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2162 if(!dataLocations) {
2163 ERR("Out of memory!\n");
2164 return;
2166 primitiveConvertToStridedData(iface, dataLocations, StartVertexIndex, &fixup);
2167 drawPrimitiveTraceDataLocations(dataLocations);
2170 /* Setup transform matrices and sort out */
2171 primitiveInitState(iface, dataLocations, useVertexShaderFunction, &lighting_changed, &lighting_original);
2173 /* Now initialize the materials state */
2174 init_materials(iface, (dataLocations->u.s.diffuse.lpData != NULL || dataLocations->u.s.diffuse.VBO != 0));
2176 if (usePixelShaderFunction) {
2177 drawPrimitiveUploadTexturesPS(This);
2178 } else {
2179 drawPrimitiveUploadTextures(This);
2183 GLenum glPrimType;
2184 /* Ok, Work out which primitive is requested and how many vertexes that
2185 will be */
2186 UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
2187 if (numberOfVertices == 0 )
2188 numberOfVertices = calculatedNumberOfindices;
2190 drawPrimitiveDrawStrided(iface, useVertexShaderFunction, usePixelShaderFunction,
2191 dataLocations, numberOfVertices, calculatedNumberOfindices, glPrimType,
2192 idxData, idxSize, minIndex, StartIdx, fixup);
2195 if(!DrawPrimStrideData) HeapFree(GetProcessHeap(), 0, dataLocations);
2197 /* If vertex shaders or no normals, restore previous lighting state */
2198 if (lighting_changed) {
2199 if (lighting_original) glEnable(GL_LIGHTING);
2200 else glDisable(GL_LIGHTING);
2201 TRACE("Restored lighting to original state\n");
2204 /* Finshed updating the screen, restore lock */
2205 LEAVE_GL();
2206 TRACE("Done all gl drawing\n");
2208 /* Diagnostics */
2209 #ifdef SHOW_FRAME_MAKEUP
2211 static long int primCounter = 0;
2212 /* NOTE: set primCounter to the value reported by drawprim
2213 before you want to to write frame makeup to /tmp */
2214 if (primCounter >= 0) {
2215 WINED3DLOCKED_RECT r;
2216 char buffer[80];
2217 IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY);
2218 sprintf(buffer, "/tmp/backbuffer_%ld.tga", primCounter);
2219 TRACE("Saving screenshot %s\n", buffer);
2220 IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
2221 IWineD3DSurface_UnlockRect(This->renderTarget);
2223 #ifdef SHOW_TEXTURE_MAKEUP
2225 IWineD3DSurface *pSur;
2226 int textureNo;
2227 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
2228 if (This->stateBlock->textures[textureNo] != NULL) {
2229 sprintf(buffer, "/tmp/texture_%p_%ld_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
2230 TRACE("Saving texture %s\n", buffer);
2231 if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
2232 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
2233 IWineD3DSurface_SaveSnapshot(pSur, buffer);
2234 IWineD3DSurface_Release(pSur);
2235 } else {
2236 FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
2241 #endif
2243 TRACE("drawprim #%ld\n", primCounter);
2244 ++primCounter;
2246 #endif