wined3d: Fix some upside-down rendering issues for shaders.
[wine/multimedia.git] / dlls / wined3d / drawprim.c
blobab6162c14d5cd13ee1e4686b0f23f39ae905e6aa
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 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
186 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
187 checkGLcall("glOrtho");
189 /* Window Coord 0 is the middle of the first pixel, so translate by half
190 a pixel (See comment above glTranslate below) */
191 glTranslatef(0.375, 0.375, 0);
192 checkGLcall("glTranslatef(0.375, 0.375, 0)");
193 if (This->renderUpsideDown) {
194 glMultMatrixf(invymat);
195 checkGLcall("glMultMatrixf(invymat)");
198 /* Vertex fog on transformed vertices? Use the calculated fog factor stored in the specular color */
199 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != D3DFOG_NONE) {
200 if(GL_SUPPORT(EXT_FOG_COORD)) {
201 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
202 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)");
203 glFogi(GL_FOG_MODE, GL_LINEAR);
204 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
205 /* The dx fog range in this case is fixed to 0 - 255,
206 * but in GL it still depends on the fog start and end (according to the ext)
207 * Use this to turn around the fog as it's needed. That prevents some
208 * calculations during drawing :-)
210 glFogf(GL_FOG_START, (float) 0xff);
211 checkGLcall("glFogfv GL_FOG_END");
212 glFogf(GL_FOG_END, 0.0);
213 checkGLcall("glFogfv GL_FOG_START");
214 } else {
215 /* Disable GL fog, handle this in software in drawStridedSlow */
216 glDisable(GL_FOG);
217 checkGLcall("glDisable(GL_FOG)");
222 /* Setup views - Transformed & lit if RHW, else untransformed.
223 Only unlit if Normals are supplied
224 Returns: Whether to restore lighting afterwards */
225 static void primitiveInitState(
226 IWineD3DDevice *iface,
227 WineDirect3DVertexStridedData* strided,
228 BOOL useVS,
229 BOOL* lighting_changed,
230 BOOL* lighting_original) {
232 BOOL fixed_vtx_transformed =
233 (strided->u.s.position.lpData != NULL || strided->u.s.position.VBO != 0 ||
234 strided->u.s.position2.lpData != NULL || strided->u.s.position2.VBO != 0) &&
235 strided->u.s.position_transformed;
237 BOOL fixed_vtx_lit =
238 strided->u.s.normal.lpData == NULL && strided->u.s.normal.VBO == 0 &&
239 strided->u.s.normal2.lpData == NULL && strided->u.s.normal2.VBO == 0;
241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
243 *lighting_changed = FALSE;
245 /* If no normals, DISABLE lighting otherwise, don't touch lighing as it is
246 set by the appropriate render state. Note Vertex Shader output is already lit */
247 if (fixed_vtx_lit || useVS) {
248 *lighting_changed = TRUE;
249 *lighting_original = glIsEnabled(GL_LIGHTING);
250 glDisable(GL_LIGHTING);
251 checkGLcall("glDisable(GL_LIGHTING);");
252 TRACE("Disabled lighting, old state = %d\n", *lighting_original);
255 if (!useVS && fixed_vtx_transformed) {
256 d3ddevice_set_ortho(This);
258 } else {
260 /* Untransformed, so relies on the view and projection matrices */
262 if (!useVS && (This->last_was_rhw || !This->modelview_valid)) {
263 /* Only reapply when have to */
264 This->modelview_valid = TRUE;
265 glMatrixMode(GL_MODELVIEW);
266 checkGLcall("glMatrixMode");
268 /* In the general case, the view matrix is the identity matrix */
269 if (This->view_ident) {
270 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]);
271 checkGLcall("glLoadMatrixf");
272 } else {
273 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
274 checkGLcall("glLoadMatrixf");
275 glMultMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]);
276 checkGLcall("glMultMatrixf");
280 if (!useVS && (This->last_was_rhw || !This->proj_valid)) {
281 /* Only reapply when have to */
282 This->proj_valid = TRUE;
283 glMatrixMode(GL_PROJECTION);
284 checkGLcall("glMatrixMode");
286 /* The rule is that the window coordinate 0 does not correspond to the
287 beginning of the first pixel, but the center of the first pixel.
288 As a consequence if you want to correctly draw one line exactly from
289 the left to the right end of the viewport (with all matrices set to
290 be identity), the x coords of both ends of the line would be not
291 -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
292 instead. */
293 glLoadIdentity();
295 glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
296 checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
298 if (This->renderUpsideDown) {
299 glMultMatrixf(invymat);
300 checkGLcall("glMultMatrixf(invymat)");
302 glMultMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_PROJECTION].u.m[0][0]);
303 checkGLcall("glLoadMatrixf");
306 /* Vertex Shader output is already transformed, so set up identity matrices */
307 if (useVS) {
308 glMatrixMode(GL_MODELVIEW);
309 checkGLcall("glMatrixMode");
310 glLoadIdentity();
311 glMatrixMode(GL_PROJECTION);
312 checkGLcall("glMatrixMode");
313 glLoadIdentity();
314 /* Window Coord 0 is the middle of the first pixel, so translate by half
315 a pixel (See comment above glTranslate above) */
316 glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
317 checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
318 if (This->renderUpsideDown) {
319 glMultMatrixf(invymat);
320 checkGLcall("glMultMatrixf(invymat)");
322 This->modelview_valid = FALSE;
323 This->proj_valid = FALSE;
325 This->last_was_rhw = FALSE;
327 /* Setup fogging */
328 if (useVS && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->usesFog) {
329 /* In D3D vertex shader return the 'final' fog value, while in OpenGL it is the 'input' fog value.
330 * The code below 'disables' the OpenGL postprocessing by setting the formula to '1'. */
331 glFogi(GL_FOG_MODE, GL_LINEAR);
332 glFogf(GL_FOG_START, 1.0f);
333 glFogf(GL_FOG_END, 0.0f);
335 } else if(This->stateBlock->renderState[WINED3DRS_FOGENABLE]
336 && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != D3DFOG_NONE) {
338 if(GL_SUPPORT(EXT_FOG_COORD)) {
339 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
340 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT)\n");
341 /* Reapply the fog range */
342 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
343 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
344 /* Restore the fog mode */
345 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGTABLEMODE, This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
346 } else {
347 /* Enable GL_FOG again because we disabled it above */
348 glEnable(GL_FOG);
349 checkGLcall("glEnable(GL_FOG)");
355 static BOOL fixed_get_input(
356 BYTE usage, BYTE usage_idx,
357 unsigned int* regnum) {
359 *regnum = -1;
361 /* Those positions must have the order in the
362 * named part of the strided data */
364 if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 0)
365 *regnum = 0;
366 else if (usage == D3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
367 *regnum = 1;
368 else if (usage == D3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
369 *regnum = 2;
370 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 0)
371 *regnum = 3;
372 else if (usage == D3DDECLUSAGE_PSIZE && usage_idx == 0)
373 *regnum = 4;
374 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 0)
375 *regnum = 5;
376 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 1)
377 *regnum = 6;
378 else if (usage == D3DDECLUSAGE_TEXCOORD && usage_idx < D3DDP_MAXTEXCOORD)
379 *regnum = 7 + usage_idx;
380 else if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 1)
381 *regnum = 7 + D3DDP_MAXTEXCOORD;
382 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 1)
383 *regnum = 8 + D3DDP_MAXTEXCOORD;
384 else if (usage == D3DDECLUSAGE_TANGENT && usage_idx == 0)
385 *regnum = 9 + D3DDP_MAXTEXCOORD;
386 else if (usage == D3DDECLUSAGE_BINORMAL && usage_idx == 0)
387 *regnum = 10 + D3DDP_MAXTEXCOORD;
388 else if (usage == D3DDECLUSAGE_TESSFACTOR && usage_idx == 0)
389 *regnum = 11 + D3DDP_MAXTEXCOORD;
390 else if (usage == D3DDECLUSAGE_FOG && usage_idx == 0)
391 *regnum = 12 + D3DDP_MAXTEXCOORD;
392 else if (usage == D3DDECLUSAGE_DEPTH && usage_idx == 0)
393 *regnum = 13 + D3DDP_MAXTEXCOORD;
394 else if (usage == D3DDECLUSAGE_SAMPLE && usage_idx == 0)
395 *regnum = 14 + D3DDP_MAXTEXCOORD;
397 if (*regnum < 0) {
398 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n",
399 debug_d3ddeclusage(usage), usage_idx);
400 return FALSE;
402 return TRUE;
405 void primitiveDeclarationConvertToStridedData(
406 IWineD3DDevice *iface,
407 BOOL useVertexShaderFunction,
408 WineDirect3DVertexStridedData *strided,
409 LONG BaseVertexIndex,
410 BOOL *fixup) {
412 /* We need to deal with frequency data!*/
414 BYTE *data = NULL;
415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
416 IWineD3DVertexDeclarationImpl* vertexDeclaration = NULL;
417 int i;
418 WINED3DVERTEXELEMENT *element;
419 DWORD stride;
420 int reg;
422 /* Locate the vertex declaration */
423 if (This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration) {
424 TRACE("Using vertex declaration from shader\n");
425 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration;
426 } else {
427 TRACE("Using vertex declaration\n");
428 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
431 /* Translate the declaration into strided data */
432 for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
433 GLint streamVBO = 0;
434 BOOL stride_used;
435 unsigned int idx;
437 element = vertexDeclaration->pDeclarationWine + i;
438 TRACE("%p Elements %p %d or %d\n", vertexDeclaration->pDeclarationWine, element, i, vertexDeclaration->declarationWNumElements);
439 if (This->stateBlock->streamIsUP) {
440 TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
441 streamVBO = 0;
442 data = (BYTE *)This->stateBlock->streamSource[element->Stream];
443 if(fixup && *fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
444 } else {
445 TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
446 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[element->Stream]);
447 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
448 if(fixup) {
449 if( streamVBO != 0) *fixup = TRUE;
450 else if(*fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
453 stride = This->stateBlock->streamStride[element->Stream];
454 data += (BaseVertexIndex * stride);
455 data += element->Offset;
456 reg = element->Reg;
458 TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex);
460 if (useVertexShaderFunction)
461 stride_used = vshader_get_input(This->stateBlock->vertexShader,
462 element->Usage, element->UsageIndex, &idx);
463 else
464 stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
466 if (stride_used) {
467 TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
468 "stream=%u, offset=%u, stride=%lu, VBO=%u]\n",
469 useVertexShaderFunction? "shader": "fixed function", idx,
470 debug_d3ddeclusage(element->Usage), element->UsageIndex,
471 element->Stream, element->Offset, stride, streamVBO);
473 strided->u.input[idx].lpData = data;
474 strided->u.input[idx].dwType = element->Type;
475 strided->u.input[idx].dwStride = stride;
476 strided->u.input[idx].VBO = streamVBO;
477 if (!useVertexShaderFunction) {
478 if (element->Usage == D3DDECLUSAGE_POSITION)
479 strided->u.s.position_transformed = FALSE;
480 else if (element->Usage == D3DDECLUSAGE_POSITIONT)
481 strided->u.s.position_transformed = TRUE;
487 void primitiveConvertFVFtoOffset(DWORD thisFVF, DWORD stride, BYTE *data, WineDirect3DVertexStridedData *strided, GLint streamVBO) {
488 int numBlends;
489 int numTextures;
490 int textureNo;
491 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
492 int numCoords[8]; /* Holding place for D3DFVF_TEXTUREFORMATx */
494 /* Either 3 or 4 floats depending on the FVF */
495 /* FIXME: Can blending data be in a different stream to the position data?
496 and if so using the fixed pipeline how do we handle it */
497 if (thisFVF & D3DFVF_POSITION_MASK) {
498 strided->u.s.position.lpData = data;
499 strided->u.s.position.dwType = D3DDECLTYPE_FLOAT3;
500 strided->u.s.position.dwStride = stride;
501 strided->u.s.position.VBO = streamVBO;
502 data += 3 * sizeof(float);
503 if (thisFVF & D3DFVF_XYZRHW) {
504 strided->u.s.position.dwType = D3DDECLTYPE_FLOAT4;
505 strided->u.s.position_transformed = TRUE;
506 data += sizeof(float);
507 } else
508 strided->u.s.position_transformed = FALSE;
511 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
512 /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
513 numBlends = 1 + (((thisFVF & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1);
514 if(thisFVF & D3DFVF_LASTBETA_UBYTE4) numBlends--;
516 if ((thisFVF & D3DFVF_XYZB5 ) > D3DFVF_XYZRHW) {
517 TRACE("Setting blend Weights to %p\n", data);
518 strided->u.s.blendWeights.lpData = data;
519 strided->u.s.blendWeights.dwType = D3DDECLTYPE_FLOAT1 + numBlends - 1;
520 strided->u.s.blendWeights.dwStride = stride;
521 strided->u.s.blendWeights.VBO = streamVBO;
522 data += numBlends * sizeof(FLOAT);
524 if (thisFVF & D3DFVF_LASTBETA_UBYTE4) {
525 strided->u.s.blendMatrixIndices.lpData = data;
526 strided->u.s.blendMatrixIndices.dwType = D3DDECLTYPE_UBYTE4;
527 strided->u.s.blendMatrixIndices.dwStride= stride;
528 strided->u.s.blendMatrixIndices.VBO = streamVBO;
529 data += sizeof(DWORD);
533 /* Normal is always 3 floats */
534 if (thisFVF & D3DFVF_NORMAL) {
535 strided->u.s.normal.lpData = data;
536 strided->u.s.normal.dwType = D3DDECLTYPE_FLOAT3;
537 strided->u.s.normal.dwStride = stride;
538 strided->u.s.normal.VBO = streamVBO;
539 data += 3 * sizeof(FLOAT);
542 /* Pointsize is a single float */
543 if (thisFVF & D3DFVF_PSIZE) {
544 strided->u.s.pSize.lpData = data;
545 strided->u.s.pSize.dwType = D3DDECLTYPE_FLOAT1;
546 strided->u.s.pSize.dwStride = stride;
547 strided->u.s.pSize.VBO = streamVBO;
548 data += sizeof(FLOAT);
551 /* Diffuse is 4 unsigned bytes */
552 if (thisFVF & D3DFVF_DIFFUSE) {
553 strided->u.s.diffuse.lpData = data;
554 strided->u.s.diffuse.dwType = D3DDECLTYPE_SHORT4;
555 strided->u.s.diffuse.dwStride = stride;
556 strided->u.s.diffuse.VBO = streamVBO;
557 data += sizeof(DWORD);
560 /* Specular is 4 unsigned bytes */
561 if (thisFVF & D3DFVF_SPECULAR) {
562 strided->u.s.specular.lpData = data;
563 strided->u.s.specular.dwType = D3DDECLTYPE_SHORT4;
564 strided->u.s.specular.dwStride = stride;
565 strided->u.s.specular.VBO = streamVBO;
566 data += sizeof(DWORD);
569 /* Texture coords */
570 numTextures = (thisFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
571 coordIdxInfo = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of D3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
573 /* numTextures indicates the number of texture coordinates supplied */
574 /* However, the first set may not be for stage 0 texture - it all */
575 /* depends on D3DTSS_TEXCOORDINDEX. */
576 /* The number of bytes for each coordinate set is based off */
577 /* D3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
579 /* So, for each supplied texture extract the coords */
580 for (textureNo = 0; textureNo < numTextures; ++textureNo) {
582 strided->u.s.texCoords[textureNo].lpData = data;
583 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT1;
584 strided->u.s.texCoords[textureNo].dwStride = stride;
585 strided->u.s.texCoords[textureNo].VBO = streamVBO;
586 numCoords[textureNo] = coordIdxInfo & 0x03;
588 /* Always one set */
589 data += sizeof(float);
590 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT1) {
591 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT2;
592 data += sizeof(float);
593 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT2) {
594 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT3;
595 data += sizeof(float);
596 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT3) {
597 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT4;
598 data += sizeof(float);
602 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
606 void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *strided, LONG BaseVertexIndex, BOOL *fixup) {
608 short LoopThroughTo = 0;
609 short nStream;
610 GLint streamVBO = 0;
612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
614 /* OK, Now to setup the data locations
615 For the non-created vertex shaders, the VertexShader var holds the real
616 FVF and only stream 0 matters
617 For the created vertex shaders, there is an FVF per stream */
618 if (!This->stateBlock->streamIsUP && !(This->stateBlock->vertexShader == NULL)) {
619 LoopThroughTo = MAX_STREAMS;
620 } else {
621 LoopThroughTo = 1;
624 /* Work through stream by stream */
625 for (nStream=0; nStream<LoopThroughTo; ++nStream) {
626 DWORD stride = This->stateBlock->streamStride[nStream];
627 BYTE *data = NULL;
628 DWORD thisFVF = 0;
630 /* Skip empty streams */
631 if (This->stateBlock->streamSource[nStream] == NULL) continue;
633 /* Retrieve appropriate FVF */
634 if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
635 thisFVF = This->stateBlock->fvf;
636 /* Handle memory passed directly as well as vertex buffers */
637 if (This->stateBlock->streamIsUP) {
638 streamVBO = 0;
639 data = (BYTE *)This->stateBlock->streamSource[nStream];
640 } else {
641 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[nStream]);
642 /* GetMemory binds the VBO */
643 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0, &streamVBO);
644 if(fixup) {
645 if(streamVBO != 0 ) *fixup = TRUE;
648 } else {
649 #if 0 /* TODO: Vertex shader support */
650 thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
651 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
652 #endif
654 VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
655 if (thisFVF == 0) continue;
657 /* Now convert the stream into pointers */
659 /* Shuffle to the beginning of the vertexes to render and index from there */
660 data = data + (BaseVertexIndex * stride);
662 primitiveConvertFVFtoOffset(thisFVF, stride, data, strided, streamVBO);
666 #if 0 /* TODO: Software Shaders */
667 /* Draw a single vertex using this information */
668 static void draw_vertex(IWineD3DDevice *iface, /* interface */
669 BOOL isXYZ, float x, float y, float z, float rhw, /* xyzn position*/
670 BOOL isNormal, float nx, float ny, float nz, /* normal */
671 BOOL isDiffuse, float *dRGBA, /* 1st colors */
672 BOOL isSpecular, float *sRGB, /* 2ndry colors */
673 BOOL isPtSize, float ptSize, /* pointSize */
674 WINED3DVECTOR_4 *texcoords, int *numcoords) /* texture info */
676 unsigned int textureNo;
677 float s, t, r, q;
678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
680 /* Diffuse -------------------------------- */
681 if (isDiffuse) {
682 glColor4fv(dRGBA);
683 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
686 /* Specular Colour ------------------------------------------*/
687 if (isSpecular) {
688 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
689 GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
690 VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
691 } else {
692 VTRACE(("Specular color extensions not supplied\n"));
696 /* Normal -------------------------------- */
697 if (isNormal) {
698 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
699 glNormal3f(nx, ny, nz);
702 /* Point Size ----------------------------------------------*/
703 if (isPtSize) {
705 /* no such functionality in the fixed function GL pipeline */
706 FIXME("Cannot change ptSize here in openGl\n");
709 /* Texture coords --------------------------- */
710 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
712 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
713 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
714 continue ;
717 /* Query tex coords */
718 if (This->stateBlock->textures[textureNo] != NULL) {
720 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
721 if (coordIdx >= MAX_TEXTURES) {
722 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
723 continue;
724 } else if (numcoords[coordIdx] == 0) {
725 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
726 continue;
727 } else {
729 /* Initialize vars */
730 s = 0.0f;
731 t = 0.0f;
732 r = 0.0f;
733 q = 0.0f;
735 switch (numcoords[coordIdx]) {
736 case 4: q = texcoords[coordIdx].w; /* drop through */
737 case 3: r = texcoords[coordIdx].z; /* drop through */
738 case 2: t = texcoords[coordIdx].y; /* drop through */
739 case 1: s = texcoords[coordIdx].x;
742 switch (numcoords[coordIdx]) { /* Supply the provided texture coords */
743 case D3DTTFF_COUNT1:
744 VTRACE(("tex:%d, s=%f\n", textureNo, s));
745 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
746 GLMULTITEXCOORD1F(textureNo, s);
747 } else {
748 glTexCoord1f(s);
750 break;
751 case D3DTTFF_COUNT2:
752 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
753 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
754 GLMULTITEXCOORD2F(textureNo, s, t);
755 } else {
756 glTexCoord2f(s, t);
758 break;
759 case D3DTTFF_COUNT3:
760 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
761 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
762 GLMULTITEXCOORD3F(textureNo, s, t, r);
763 } else {
764 glTexCoord3f(s, t, r);
766 break;
767 case D3DTTFF_COUNT4:
768 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
769 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
770 GLMULTITEXCOORD4F(textureNo, s, t, r, q);
771 } else {
772 glTexCoord4f(s, t, r, q);
774 break;
775 default:
776 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
780 } /* End of textures */
782 /* Position -------------------------------- */
783 if (isXYZ) {
784 if (1.0f == rhw || rhw < 0.00001f) {
785 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
786 glVertex3f(x, y, z);
787 } else {
788 /* Cannot optimize by dividing through by rhw as rhw is required
789 later for perspective in the GL pipeline for vertex shaders */
790 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
791 glVertex4f(x,y,z,rhw);
795 #endif /* TODO: Software shaders */
797 static void loadNumberedArrays(
798 IWineD3DDevice *iface,
799 IWineD3DVertexShader *shader,
800 WineDirect3DVertexStridedData *strided) {
802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
803 GLint curVBO = -1;
804 int i;
806 for (i = 0; i < MAX_ATTRIBS; i++) {
808 if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
809 continue;
811 TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
813 if(curVBO != strided->u.input[i].VBO) {
814 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, strided->u.input[i].VBO));
815 checkGLcall("glBindBufferARB");
816 curVBO = strided->u.input[i].VBO;
818 GL_EXTCALL(glVertexAttribPointerARB(i,
819 WINED3D_ATR_SIZE(strided->u.input[i].dwType),
820 WINED3D_ATR_GLTYPE(strided->u.input[i].dwType),
821 WINED3D_ATR_NORMALIZED(strided->u.input[i].dwType),
822 strided->u.input[i].dwStride,
823 strided->u.input[i].lpData));
824 GL_EXTCALL(glEnableVertexAttribArrayARB(i));
828 static void loadVertexData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd) {
829 unsigned int textureNo = 0;
830 unsigned int texture_idx = 0;
831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
832 GLint curVBO = -1;
834 TRACE("Using fast vertex array code\n");
835 /* Blend Data ---------------------------------------------- */
836 if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) ||
837 (sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) {
840 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
842 #if 1
843 glEnableClientState(GL_WEIGHT_ARRAY_ARB);
844 checkGLcall("glEnableClientState(GL_WEIGHT_ARRAY_ARB)");
845 #endif
847 TRACE("Blend %d %p %ld\n", WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
848 sd->u.s.blendWeights.lpData, sd->u.s.blendWeights.dwStride);
849 /* FIXME("TODO\n");*/
850 /* Note dwType == float3 or float4 == 2 or 3 */
852 #if 0
853 /* with this on, the normals appear to be being modified,
854 but the vertices aren't being translated as they should be
855 Maybe the world matrix aren't being setup properly? */
856 glVertexBlendARB(WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) + 1);
857 #endif
860 VTRACE(("glWeightPointerARB(%d, GL_FLOAT, %ld, %p)\n",
861 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) ,
862 sd->u.s.blendWeights.dwStride,
863 sd->u.s.blendWeights.lpData));
865 if(curVBO != sd->u.s.blendWeights.VBO) {
866 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.blendWeights.VBO));
867 checkGLcall("glBindBufferARB");
868 curVBO = sd->u.s.blendWeights.VBO;
871 GL_EXTCALL(glWeightPointerARB)(
872 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
873 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
874 sd->u.s.blendWeights.dwStride,
875 sd->u.s.blendWeights.lpData);
877 checkGLcall("glWeightPointerARB");
879 if((sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO)){
880 static BOOL showfixme = TRUE;
881 if(showfixme){
882 FIXME("blendMatrixIndices support\n");
883 showfixme = FALSE;
887 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
888 /* FIXME("TODO\n");*/
889 #if 0
891 GL_EXTCALL(glVertexWeightPointerEXT)(
892 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
893 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
894 sd->u.s.blendWeights.dwStride,
895 sd->u.s.blendWeights.lpData);
896 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
897 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
898 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
899 #endif
901 } else {
902 /* TODO: support blends in fixupVertices */
903 FIXME("unsupported blending in openGl\n");
905 } else {
906 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
907 #if 0 /* TODO: Vertex blending */
908 glDisable(GL_VERTEX_BLEND_ARB);
909 #endif
910 TRACE("ARB_VERTEX_BLEND\n");
911 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
912 TRACE(" EXT_VERTEX_WEIGHTING\n");
913 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
914 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
919 #if 0 /* FOG ----------------------------------------------*/
920 if (sd->u.s.fog.lpData || sd->u.s.fog.VBO) {
921 /* TODO: fog*/
922 if (GL_SUPPORT(EXT_FOG_COORD) {
923 glEnableClientState(GL_FOG_COORDINATE_EXT);
924 (GL_EXTCALL)(FogCoordPointerEXT)(
925 WINED3D_ATR_GLTYPE(sd->u.s.fog.dwType),
926 sd->u.s.fog.dwStride,
927 sd->u.s.fog.lpData);
928 } else {
929 /* don't bother falling back to 'slow' as we don't support software FOG yet. */
930 /* FIXME: fixme once */
931 TRACE("Hardware support for FOG is not avaiable, FOG disabled.\n");
933 } else {
934 if (GL_SUPPRT(EXT_FOR_COORD) {
935 /* make sure fog is disabled */
936 glDisableClientState(GL_FOG_COORDINATE_EXT);
939 #endif
941 #if 0 /* tangents ----------------------------------------------*/
942 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO ||
943 sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
944 /* TODO: tangents*/
945 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
946 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO) {
947 glEnable(GL_TANGENT_ARRAY_EXT);
948 (GL_EXTCALL)(TangentPointerEXT)(
949 WINED3D_ATR_GLTYPE(sd->u.s.tangent.dwType),
950 sd->u.s.tangent.dwStride,
951 sd->u.s.tangent.lpData);
952 } else {
953 glDisable(GL_TANGENT_ARRAY_EXT);
955 if (sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
956 glEnable(GL_BINORMAL_ARRAY_EXT);
957 (GL_EXTCALL)(BinormalPointerEXT)(
958 WINED3D_ATR_GLTYPE(sd->u.s.binormal.dwType),
959 sd->u.s.binormal.dwStride,
960 sd->u.s.binormal.lpData);
961 } else{
962 glDisable(GL_BINORMAL_ARRAY_EXT);
965 } else {
966 /* don't bother falling back to 'slow' as we don't support software tangents and binormals yet . */
967 /* FIXME: fixme once */
968 TRACE("Hardware support for tangents and binormals is not avaiable, tangents and binormals disabled.\n");
970 } else {
971 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
972 /* make sure fog is disabled */
973 glDisable(GL_TANGENT_ARRAY_EXT);
974 glDisable(GL_BINORMAL_ARRAY_EXT);
977 #endif
979 /* Point Size ----------------------------------------------*/
980 if (sd->u.s.pSize.lpData || sd->u.s.pSize.VBO) {
982 /* no such functionality in the fixed function GL pipeline */
983 TRACE("Cannot change ptSize here in openGl\n");
984 /* TODO: Implement this function in using shaders if they are available */
988 /* Vertex Pointers -----------------------------------------*/
989 if (sd->u.s.position.lpData != NULL || sd->u.s.position.VBO != 0) {
990 /* Note dwType == float3 or float4 == 2 or 3 */
991 VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n",
992 sd->u.s.position.dwStride,
993 sd->u.s.position.dwType + 1,
994 sd->u.s.position.lpData));
996 if(curVBO != sd->u.s.position.VBO) {
997 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.position.VBO));
998 checkGLcall("glBindBufferARB");
999 curVBO = sd->u.s.position.VBO;
1002 /* min(WINED3D_ATR_SIZE(position),3) to Disable RHW mode as 'w' coord
1003 handling for rhw mode should not impact screen position whereas in GL it does.
1004 This may result in very slightly distored textures in rhw mode, but
1005 a very minimal different. There's always the other option of
1006 fixing the view matrix to prevent w from having any effect
1008 This only applies to user pointer sources, in VBOs the vertices are fixed up
1010 if(sd->u.s.position.VBO == 0) {
1011 glVertexPointer(3 /* min(WINED3D_ATR_SIZE(sd->u.s.position.dwType),3) */,
1012 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1013 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1014 } else {
1015 glVertexPointer(
1016 WINED3D_ATR_SIZE(sd->u.s.position.dwType),
1017 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1018 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1020 checkGLcall("glVertexPointer(...)");
1021 glEnableClientState(GL_VERTEX_ARRAY);
1022 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
1024 } else {
1025 glDisableClientState(GL_VERTEX_ARRAY);
1026 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
1029 /* Normals -------------------------------------------------*/
1030 if (sd->u.s.normal.lpData || sd->u.s.normal.VBO) {
1031 /* Note dwType == float3 or float4 == 2 or 3 */
1032 VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n",
1033 sd->u.s.normal.dwStride,
1034 sd->u.s.normal.lpData));
1035 if(curVBO != sd->u.s.normal.VBO) {
1036 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.normal.VBO));
1037 checkGLcall("glBindBufferARB");
1038 curVBO = sd->u.s.normal.VBO;
1040 glNormalPointer(
1041 WINED3D_ATR_GLTYPE(sd->u.s.normal.dwType),
1042 sd->u.s.normal.dwStride,
1043 sd->u.s.normal.lpData);
1044 checkGLcall("glNormalPointer(...)");
1045 glEnableClientState(GL_NORMAL_ARRAY);
1046 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
1048 } else {
1049 glDisableClientState(GL_NORMAL_ARRAY);
1050 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
1051 glNormal3f(0, 0, 1);
1052 checkGLcall("glNormal3f(0, 0, 1)");
1055 /* Diffuse Colour --------------------------------------------*/
1056 /* WARNING: Data here MUST be in RGBA format, so cannot */
1057 /* go directly into fast mode from app pgm, because */
1058 /* directx requires data in BGRA format. */
1059 /* currently fixupVertices swizels the format, but this isn't */
1060 /* very practical when using VBOS */
1061 /* NOTE: Unless we write a vertex shader to swizel the colour */
1062 /* , or the user doesn't care and wants the speed advantage */
1064 if (sd->u.s.diffuse.lpData || sd->u.s.diffuse.VBO) {
1065 /* Note dwType == float3 or float4 == 2 or 3 */
1066 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
1067 sd->u.s.diffuse.dwStride,
1068 sd->u.s.diffuse.lpData));
1070 if(curVBO != sd->u.s.diffuse.VBO) {
1071 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.diffuse.VBO));
1072 checkGLcall("glBindBufferARB");
1073 curVBO = sd->u.s.diffuse.VBO;
1075 glColorPointer(4, GL_UNSIGNED_BYTE,
1076 sd->u.s.diffuse.dwStride,
1077 sd->u.s.diffuse.lpData);
1078 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
1079 glEnableClientState(GL_COLOR_ARRAY);
1080 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
1082 } else {
1083 glDisableClientState(GL_COLOR_ARRAY);
1084 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
1085 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1086 checkGLcall("glColor4f(1, 1, 1, 1)");
1089 /* Specular Colour ------------------------------------------*/
1090 if (sd->u.s.specular.lpData || sd->u.s.specular.VBO) {
1091 TRACE("setting specular colour\n");
1092 /* Note dwType == float3 or float4 == 2 or 3 */
1093 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
1094 sd->u.s.specular.dwStride,
1095 sd->u.s.specular.lpData));
1096 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1097 if(curVBO != sd->u.s.specular.VBO) {
1098 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.specular.VBO));
1099 checkGLcall("glBindBufferARB");
1100 curVBO = sd->u.s.specular.VBO;
1102 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
1103 sd->u.s.specular.dwStride,
1104 sd->u.s.specular.lpData);
1105 vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
1106 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1107 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1108 } else {
1110 /* Missing specular color is not critical, no warnings */
1111 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1114 } else {
1115 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1117 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1118 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1119 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1120 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
1121 } else {
1123 /* Missing specular color is not critical, no warnings */
1124 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1128 /* Texture coords -------------------------------------------*/
1130 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1131 /* The code below uses glClientActiveTexture and glMultiTexCoord* which are all part of the GL_ARB_multitexture extension. */
1132 /* Abort if we don't support the extension. */
1133 if (!GL_SUPPORT(ARB_MULTITEXTURE)) {
1134 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1135 continue;
1138 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) {
1139 /* Select the correct texture stage */
1140 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1143 if (This->stateBlock->textures[textureNo] != NULL) {
1144 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1146 if (coordIdx >= MAX_TEXTURES) {
1147 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1148 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1149 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1151 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL && sd->u.s.texCoords[coordIdx].VBO == 0) {
1152 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
1153 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1154 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1156 } else {
1157 TRACE("Setting up texture %u, idx %d, cordindx %u, data %p\n",
1158 textureNo, texture_idx, coordIdx, sd->u.s.texCoords[coordIdx].lpData);
1159 if(curVBO != sd->u.s.texCoords[coordIdx].VBO) {
1160 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.texCoords[coordIdx].VBO));
1161 checkGLcall("glBindBufferARB");
1162 curVBO = sd->u.s.texCoords[coordIdx].VBO;
1164 /* The coords to supply depend completely on the fvf / vertex shader */
1165 glTexCoordPointer(
1166 WINED3D_ATR_SIZE(sd->u.s.texCoords[coordIdx].dwType),
1167 WINED3D_ATR_GLTYPE(sd->u.s.texCoords[coordIdx].dwType),
1168 sd->u.s.texCoords[coordIdx].dwStride,
1169 sd->u.s.texCoords[coordIdx].lpData);
1170 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1172 } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1173 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1174 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1176 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1178 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1179 for (textureNo = texture_idx; textureNo < GL_LIMITS(textures); ++textureNo) {
1180 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo));
1181 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1182 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1187 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
1188 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1191 if (idxData != NULL /* This crashes sometimes!*/) {
1192 TRACE("(%p) : glElements(%x, %d, %ld, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
1193 idxData = idxData == (void *)-1 ? NULL : idxData;
1194 #if 1
1195 #if 0
1196 glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
1197 glEnableClientState(GL_INDEX_ARRAY);
1198 #endif
1199 glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1200 (const char *)idxData+(idxSize * startIdx));
1201 #else /* using drawRangeElements may be faster */
1203 glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
1204 idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1205 (const char *)idxData+(idxSize * startIdx));
1206 #endif
1207 checkGLcall("glDrawRangeElements");
1209 } else {
1211 /* Note first is now zero as we shuffled along earlier */
1212 TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
1213 glDrawArrays(glPrimitiveType, 0, numberOfVertices);
1214 checkGLcall("glDrawArrays");
1218 return;
1222 * Actually draw using the supplied information.
1223 * Slower GL version which extracts info about each vertex in turn
1226 static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1227 UINT NumVertexes, GLenum glPrimType,
1228 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1230 unsigned int textureNo = 0;
1231 unsigned int texture_idx = 0;
1232 const short *pIdxBufS = NULL;
1233 const long *pIdxBufL = NULL;
1234 LONG SkipnStrides = 0;
1235 LONG vx_index;
1236 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1237 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
1238 float rhw = 0.0f; /* rhw */
1239 float ptSize = 0.0f; /* Point size */
1240 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
1241 DWORD specularColor = 0; /* Specular Color */
1242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1244 TRACE("Using slow vertex array code\n");
1246 /* Variable Initialization */
1247 if (idxData != NULL) {
1248 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1249 else pIdxBufL = (const long *) idxData;
1252 /* Start drawing in GL */
1253 VTRACE(("glBegin(%x)\n", glPrimType));
1254 glBegin(glPrimType);
1256 /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
1257 * Guess it's not necessary(we crash then anyway) and would only eat CPU time
1260 /* For each primitive */
1261 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1263 /* Initialize diffuse color */
1264 diffuseColor = 0xFFFFFFFF;
1266 /* For indexed data, we need to go a few more strides in */
1267 if (idxData != NULL) {
1269 /* Indexed so work out the number of strides to skip */
1270 if (idxSize == 2) {
1271 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1272 SkipnStrides = pIdxBufS[startIdx + vx_index];
1273 } else {
1274 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1275 SkipnStrides = pIdxBufL[startIdx + vx_index];
1279 /* Position Information ------------------ */
1280 if (sd->u.s.position.lpData != NULL) {
1282 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
1283 x = ptrToCoords[0];
1284 y = ptrToCoords[1];
1285 z = ptrToCoords[2];
1286 rhw = 1.0;
1287 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
1289 /* RHW follows, only if transformed, ie 4 floats were provided */
1290 if (sd->u.s.position_transformed) {
1291 rhw = ptrToCoords[3];
1292 VTRACE(("rhw=%f\n", rhw));
1296 /* Blending data -------------------------- */
1297 if (sd->u.s.blendWeights.lpData != NULL) {
1298 /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
1299 FIXME("Blending not supported yet\n");
1301 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
1302 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
1306 /* Vertex Normal Data (untransformed only)- */
1307 if (sd->u.s.normal.lpData != NULL) {
1309 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
1310 nx = ptrToCoords[0];
1311 ny = ptrToCoords[1];
1312 nz = ptrToCoords[2];
1313 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
1316 /* Point Size ----------------------------- */
1317 if (sd->u.s.pSize.lpData != NULL) {
1319 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1320 ptSize = ptrToCoords[0];
1321 VTRACE(("ptSize=%f\n", ptSize));
1322 FIXME("No support for ptSize yet\n");
1325 /* Diffuse -------------------------------- */
1326 if (sd->u.s.diffuse.lpData != NULL) {
1328 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1329 diffuseColor = ptrToCoords[0];
1330 VTRACE(("diffuseColor=%lx\n", diffuseColor));
1333 /* Specular -------------------------------- */
1334 if (sd->u.s.specular.lpData != NULL) {
1336 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1337 specularColor = ptrToCoords[0];
1338 VTRACE(("specularColor=%lx\n", specularColor));
1341 /* Texture coords --------------------------- */
1342 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1344 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1345 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1346 continue ;
1349 /* Query tex coords */
1350 if (This->stateBlock->textures[textureNo] != NULL) {
1352 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1353 float *ptrToCoords = NULL;
1354 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1356 if (coordIdx > 7) {
1357 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1358 ++texture_idx;
1359 continue;
1360 } else if (coordIdx < 0) {
1361 FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
1362 ++texture_idx;
1363 continue;
1366 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1367 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1368 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1369 ++texture_idx;
1370 continue;
1371 } else {
1373 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DDECLTYPE_FLOAT1 etc */
1375 /* The coords to supply depend completely on the fvf / vertex shader */
1376 switch (coordsToUse) {
1377 case 4: q = ptrToCoords[3]; /* drop through */
1378 case 3: r = ptrToCoords[2]; /* drop through */
1379 case 2: t = ptrToCoords[1]; /* drop through */
1380 case 1: s = ptrToCoords[0];
1383 /* Projected is more 'fun' - Move the last coord to the 'q'
1384 parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1385 if ((This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1386 (This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1388 if (This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1389 switch (coordsToUse) {
1390 case 0: /* Drop Through */
1391 case 1:
1392 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1393 break;
1394 case 2:
1395 q = t;
1396 t = 0.0;
1397 coordsToUse = 4;
1398 break;
1399 case 3:
1400 q = r;
1401 r = 0.0;
1402 coordsToUse = 4;
1403 break;
1404 case 4: /* Nop here */
1405 break;
1406 default:
1407 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n",
1408 This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1413 switch (coordsToUse) { /* Supply the provided texture coords */
1414 case D3DTTFF_COUNT1:
1415 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1416 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1417 GL_EXTCALL(glMultiTexCoord1fARB(texture_idx, s));
1418 } else {
1419 glTexCoord1f(s);
1421 break;
1422 case D3DTTFF_COUNT2:
1423 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1424 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1425 GL_EXTCALL(glMultiTexCoord2fARB(texture_idx, s, t));
1426 } else {
1427 glTexCoord2f(s, t);
1429 break;
1430 case D3DTTFF_COUNT3:
1431 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1432 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1433 GL_EXTCALL(glMultiTexCoord3fARB(texture_idx, s, t, r));
1434 } else {
1435 glTexCoord3f(s, t, r);
1437 break;
1438 case D3DTTFF_COUNT4:
1439 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1440 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1441 GL_EXTCALL(glMultiTexCoord4fARB(texture_idx, s, t, r, q));
1442 } else {
1443 glTexCoord4f(s, t, r, q);
1445 break;
1446 default:
1447 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1451 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1452 } /* End of textures */
1454 /* Diffuse -------------------------------- */
1455 if (sd->u.s.diffuse.lpData != NULL) {
1456 glColor4ub(D3DCOLOR_B_R(diffuseColor),
1457 D3DCOLOR_B_G(diffuseColor),
1458 D3DCOLOR_B_B(diffuseColor),
1459 D3DCOLOR_B_A(diffuseColor));
1460 VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n",
1461 D3DCOLOR_B_R(diffuseColor),
1462 D3DCOLOR_B_G(diffuseColor),
1463 D3DCOLOR_B_B(diffuseColor),
1464 D3DCOLOR_B_A(diffuseColor)));
1465 } else {
1466 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1469 /* Specular ------------------------------- */
1470 if (sd->u.s.specular.lpData != NULL) {
1471 /* special case where the fog density is stored in the diffuse alpha channel */
1472 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
1473 (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == D3DFOG_NONE || sd->u.s.position.dwType == D3DDECLTYPE_FLOAT4 )&&
1474 This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
1475 if(GL_SUPPORT(EXT_FOG_COORD)) {
1476 GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
1477 } else {
1478 static BOOL warned = FALSE;
1479 if(!warned) {
1480 /* TODO: Use the fog table code from old ddraw */
1481 FIXME("Implement fog for transformed vertices in software\n");
1482 warned = TRUE;
1487 VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n",
1488 D3DCOLOR_B_R(specularColor),
1489 D3DCOLOR_B_G(specularColor),
1490 D3DCOLOR_B_B(specularColor)));
1491 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1492 GL_EXTCALL(glSecondaryColor3ubEXT)(
1493 D3DCOLOR_B_R(specularColor),
1494 D3DCOLOR_B_G(specularColor),
1495 D3DCOLOR_B_B(specularColor));
1496 } else {
1497 /* Do not worry if specular colour missing and disable request */
1498 VTRACE(("Specular color extensions not supplied\n"));
1500 } else {
1501 if (vx_index == 0) {
1502 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1503 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1504 } else {
1505 /* Do not worry if specular colour missing and disable request */
1506 VTRACE(("Specular color extensions not supplied\n"));
1511 /* Normal -------------------------------- */
1512 if (sd->u.s.normal.lpData != NULL) {
1513 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1514 glNormal3f(nx, ny, nz);
1515 } else {
1516 if (vx_index == 0) glNormal3f(0, 0, 1);
1519 /* Position -------------------------------- */
1520 if (sd->u.s.position.lpData != NULL) {
1521 if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
1522 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1523 glVertex3f(x, y, z);
1524 } else {
1525 GLfloat w = 1.0 / rhw;
1526 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1527 glVertex4f(x*w, y*w, z*w, w);
1531 /* For non indexed mode, step onto next parts */
1532 if (idxData == NULL) {
1533 ++SkipnStrides;
1537 glEnd();
1538 checkGLcall("glEnd and previous calls");
1541 #if 0 /* TODO: Software/Hardware vertex blending support */
1543 * Draw with emulated vertex shaders
1544 * Note: strided data is uninitialized, as we need to pass the vertex
1545 * shader directly as ordering irs yet
1547 void drawStridedSoftwareVS(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1548 int PrimitiveType, ULONG NumPrimitives,
1549 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1551 unsigned int textureNo = 0;
1552 GLenum glPrimType = GL_POINTS;
1553 int NumVertexes = NumPrimitives;
1554 const short *pIdxBufS = NULL;
1555 const long *pIdxBufL = NULL;
1556 LONG SkipnStrides = 0;
1557 LONG vx_index;
1558 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1559 float rhw = 0.0f; /* rhw */
1560 float ptSize = 0.0f; /* Point size */
1561 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1562 int numcoords[8]; /* Number of coords */
1563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1565 IDirect3DVertexShaderImpl* vertexShader = NULL;
1567 TRACE("Using slow software vertex shader code\n");
1569 /* Variable Initialization */
1570 if (idxData != NULL) {
1571 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1572 else pIdxBufL = (const long *) idxData;
1575 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1576 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1578 /* Retrieve the VS information */
1579 vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
1581 /* Start drawing in GL */
1582 VTRACE(("glBegin(%x)\n", glPrimType));
1583 glBegin(glPrimType);
1585 /* For each primitive */
1586 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1588 /* For indexed data, we need to go a few more strides in */
1589 if (idxData != NULL) {
1591 /* Indexed so work out the number of strides to skip */
1592 if (idxSize == 2) {
1593 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1594 SkipnStrides = pIdxBufS[startIdx+vx_index];
1595 } else {
1596 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1597 SkipnStrides = pIdxBufL[startIdx+vx_index];
1601 /* Fill the vertex shader input */
1602 IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1604 /* Initialize the output fields to the same defaults as it would normally have */
1605 memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1606 vertexShader->output.oD[0].x = 1.0;
1607 vertexShader->output.oD[0].y = 1.0;
1608 vertexShader->output.oD[0].z = 1.0;
1609 vertexShader->output.oD[0].w = 1.0;
1611 /* Now execute the vertex shader */
1612 IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1615 TRACE_VECTOR(vertexShader->output.oPos);
1616 TRACE_VECTOR(vertexShader->output.oD[0]);
1617 TRACE_VECTOR(vertexShader->output.oD[1]);
1618 TRACE_VECTOR(vertexShader->output.oT[0]);
1619 TRACE_VECTOR(vertexShader->output.oT[1]);
1620 TRACE_VECTOR(vertexShader->input.V[0]);
1621 TRACE_VECTOR(vertexShader->data->C[0]);
1622 TRACE_VECTOR(vertexShader->data->C[1]);
1623 TRACE_VECTOR(vertexShader->data->C[2]);
1624 TRACE_VECTOR(vertexShader->data->C[3]);
1625 TRACE_VECTOR(vertexShader->data->C[4]);
1626 TRACE_VECTOR(vertexShader->data->C[5]);
1627 TRACE_VECTOR(vertexShader->data->C[6]);
1628 TRACE_VECTOR(vertexShader->data->C[7]);
1631 /* Extract out the output */
1632 /* FIXME: Fog coords? */
1633 x = vertexShader->output.oPos.x;
1634 y = vertexShader->output.oPos.y;
1635 z = vertexShader->output.oPos.z;
1636 rhw = vertexShader->output.oPos.w;
1637 ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1639 /** Update textures coords using vertexShader->output.oT[0->7] */
1640 memset(texcoords, 0x00, sizeof(texcoords));
1641 memset(numcoords, 0x00, sizeof(numcoords));
1642 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1643 if (This->stateBlock->textures[textureNo] != NULL) {
1644 texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1645 texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1646 texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1647 texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1648 if (This->stateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1649 numcoords[textureNo] = This->stateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1650 } else {
1651 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1652 case WINED3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1653 case WINED3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1654 default: numcoords[textureNo] = 4;
1657 } else {
1658 numcoords[textureNo] = 0;
1662 /* Draw using this information */
1663 draw_vertex(iface,
1664 TRUE, x, y, z, rhw,
1665 TRUE, 0.0f, 0.0f, 1.0f,
1666 TRUE, (float*) &vertexShader->output.oD[0],
1667 TRUE, (float*) &vertexShader->output.oD[1],
1668 FALSE, ptSize, /* FIXME: Change back when supported */
1669 texcoords, numcoords);
1671 /* For non indexed mode, step onto next parts */
1672 if (idxData == NULL) {
1673 ++SkipnStrides;
1676 } /* for each vertex */
1678 glEnd();
1679 checkGLcall("glEnd and previous calls");
1682 #endif
1684 inline static void drawPrimitiveDrawStrided(
1685 IWineD3DDevice *iface,
1686 BOOL useVertexShaderFunction,
1687 BOOL usePixelShaderFunction,
1688 WineDirect3DVertexStridedData *dataLocations,
1689 UINT numberOfvertices,
1690 UINT numberOfIndicies,
1691 GLenum glPrimType,
1692 const void *idxData,
1693 short idxSize,
1694 int minIndex,
1695 long StartIdx,
1696 BOOL fixup) {
1698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1699 BOOL useDrawStridedSlow;
1701 int startStride = idxData == NULL ? 0 :
1702 idxData == (void *) -1 ? 0 :
1703 (idxSize == 2 ? *(((const short *) idxData) + StartIdx) : *((const int *) idxData) + StartIdx);
1704 int endStride = startStride;
1705 TRACE("begin Start stride %d, end stride %d, number of indices%d, number of vertices%d\n",
1706 startStride, endStride, numberOfIndicies, numberOfvertices);
1708 /* Generate some fixme's if unsupported functionality is being used */
1709 #define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData
1710 /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */
1711 if (!useVertexShaderFunction && (BUFFER_OR_DATA(blendMatrixIndices) || BUFFER_OR_DATA(blendWeights))) {
1712 FIXME("Blending data is only valid with vertex shaders %p %p\n",dataLocations->u.s.blendWeights.lpData,dataLocations->u.s.blendWeights.lpData);
1714 if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) {
1715 FIXME("Tweening is only valid with vertex shaders\n");
1717 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) {
1718 FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n");
1720 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) {
1721 FIXME("Extended attributes are only valid with vertex shaders\n");
1723 #undef BUFFER_OR_DATA
1725 /* Fixed pipeline, no fixups required - load arrays */
1726 if (!useVertexShaderFunction &&
1727 ((dataLocations->u.s.pSize.lpData == NULL &&
1728 dataLocations->u.s.diffuse.lpData == NULL &&
1729 dataLocations->u.s.specular.lpData == NULL) ||
1730 fixup) ) {
1732 /* Load the vertex data using named arrays */
1733 TRACE("(%p) Loading vertex data\n", This);
1734 loadVertexData(iface, dataLocations);
1735 useDrawStridedSlow = FALSE;
1737 /* Shader pipeline - load attribute arrays */
1738 } else if(useVertexShaderFunction) {
1740 loadNumberedArrays(iface, This->stateBlock->vertexShader, dataLocations);
1741 useDrawStridedSlow = FALSE;
1743 /* Draw vertex by vertex */
1744 } else {
1745 TRACE("Not loading vertex data\n");
1746 useDrawStridedSlow = TRUE;
1749 /* If GLSL is used for either pixel or vertex shaders, make a GLSL program
1750 * Otherwise set 0, which restores fixed function */
1751 if ((wined3d_settings.vs_selected_mode == SHADER_GLSL && useVertexShaderFunction) ||
1752 (wined3d_settings.ps_selected_mode == SHADER_GLSL && usePixelShaderFunction))
1753 set_glsl_shader_program(iface);
1754 else
1755 This->stateBlock->shaderPrgId = 0;
1757 /* If GLSL is used now, or might have been used before, (re)set the program */
1758 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
1759 wined3d_settings.ps_selected_mode == SHADER_GLSL) {
1761 if (This->stateBlock->shaderPrgId)
1762 TRACE_(d3d_shader)("Using GLSL program %u\n", This->stateBlock->shaderPrgId);
1763 GL_EXTCALL(glUseProgramObjectARB(This->stateBlock->shaderPrgId));
1764 checkGLcall("glUseProgramObjectARB");
1767 if (useVertexShaderFunction) {
1769 TRACE("Using vertex shader\n");
1771 if (wined3d_settings.vs_selected_mode == SHADER_ARB) {
1772 /* Bind the vertex program */
1773 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB,
1774 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId));
1775 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
1777 /* Enable OpenGL vertex programs */
1778 glEnable(GL_VERTEX_PROGRAM_ARB);
1779 checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
1780 TRACE_(d3d_shader)("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n",
1781 This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId);
1785 if (usePixelShaderFunction) {
1787 TRACE("Using pixel shader\n");
1789 if (wined3d_settings.ps_selected_mode == SHADER_ARB) {
1790 /* Bind the fragment program */
1791 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,
1792 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId));
1793 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
1795 /* Enable OpenGL fragment programs */
1796 glEnable(GL_FRAGMENT_PROGRAM_ARB);
1797 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
1798 TRACE_(d3d_shader)("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n",
1799 This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId);
1803 /* Load any global constants/uniforms that may have been set by the application */
1804 if (wined3d_settings.vs_selected_mode == SHADER_GLSL || wined3d_settings.ps_selected_mode == SHADER_GLSL)
1805 shader_glsl_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
1806 else if (wined3d_settings.vs_selected_mode== SHADER_ARB || wined3d_settings.ps_selected_mode == SHADER_ARB)
1807 shader_arb_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
1809 /* Draw vertex-by-vertex */
1810 if (useDrawStridedSlow)
1811 drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1812 else
1813 drawStridedFast(iface, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1815 /* Cleanup vertex program */
1816 if (useVertexShaderFunction) {
1817 /* disable any attribs (this is the same for both GLSL and ARB modes) */
1818 GLint maxAttribs;
1819 int i;
1820 /* Leave all the attribs disabled */
1821 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
1822 /* MESA does not support it right not */
1823 if (glGetError() != GL_NO_ERROR)
1824 maxAttribs = 16;
1825 for (i = 0; i < maxAttribs; ++i) {
1826 GL_EXTCALL(glDisableVertexAttribArrayARB(i));
1827 checkGLcall("glDisableVertexAttribArrayARB(reg);");
1830 if (wined3d_settings.vs_selected_mode == SHADER_ARB)
1831 glDisable(GL_VERTEX_PROGRAM_ARB);
1834 /* Cleanup fragment program */
1835 if (usePixelShaderFunction && wined3d_settings.ps_selected_mode == SHADER_ARB)
1836 glDisable(GL_FRAGMENT_PROGRAM_ARB);
1839 inline void drawPrimitiveTraceDataLocations(
1840 WineDirect3DVertexStridedData *dataLocations) {
1842 /* Dump out what parts we have supplied */
1843 TRACE("Strided Data:\n");
1844 TRACE_STRIDED((dataLocations), position);
1845 TRACE_STRIDED((dataLocations), blendWeights);
1846 TRACE_STRIDED((dataLocations), blendMatrixIndices);
1847 TRACE_STRIDED((dataLocations), normal);
1848 TRACE_STRIDED((dataLocations), pSize);
1849 TRACE_STRIDED((dataLocations), diffuse);
1850 TRACE_STRIDED((dataLocations), specular);
1851 TRACE_STRIDED((dataLocations), texCoords[0]);
1852 TRACE_STRIDED((dataLocations), texCoords[1]);
1853 TRACE_STRIDED((dataLocations), texCoords[2]);
1854 TRACE_STRIDED((dataLocations), texCoords[3]);
1855 TRACE_STRIDED((dataLocations), texCoords[4]);
1856 TRACE_STRIDED((dataLocations), texCoords[5]);
1857 TRACE_STRIDED((dataLocations), texCoords[6]);
1858 TRACE_STRIDED((dataLocations), texCoords[7]);
1859 TRACE_STRIDED((dataLocations), position2);
1860 TRACE_STRIDED((dataLocations), normal2);
1861 TRACE_STRIDED((dataLocations), tangent);
1862 TRACE_STRIDED((dataLocations), binormal);
1863 TRACE_STRIDED((dataLocations), tessFactor);
1864 TRACE_STRIDED((dataLocations), fog);
1865 TRACE_STRIDED((dataLocations), depth);
1866 TRACE_STRIDED((dataLocations), sample);
1868 return;
1872 static void drawPrimitiveUploadTexturesPS(IWineD3DDeviceImpl* This) {
1873 INT i;
1875 for (i = 0; i < GL_LIMITS(samplers); ++i) {
1876 /* Pixel shader support should imply multitexture support. */
1877 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1878 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1879 checkGLcall("glActiveTextureARB");
1880 } else if (i) {
1881 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1884 if (!This->stateBlock->textures[i]) continue;
1886 /* Enable the correct target. Is this required for GLSL? For ARB_fragment_program it isn't, afaik. */
1887 glDisable(GL_TEXTURE_1D);
1888 This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1889 switch(This->stateBlock->textureDimensions[i]) {
1890 case GL_TEXTURE_2D:
1891 glDisable(GL_TEXTURE_3D);
1892 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1893 break;
1894 case GL_TEXTURE_3D:
1895 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1896 glDisable(GL_TEXTURE_2D);
1897 break;
1898 case GLTEXTURECUBEMAP:
1899 glDisable(GL_TEXTURE_2D);
1900 glDisable(GL_TEXTURE_3D);
1901 break;
1903 glEnable(This->stateBlock->textureDimensions[i]);
1905 /* Upload texture, apply states */
1906 IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
1907 IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, i, REAPPLY_ALPHAOP);
1908 IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
1912 /* uploads textures and setup texture states ready for rendering */
1913 static void drawPrimitiveUploadTextures(IWineD3DDeviceImpl* This) {
1914 INT current_sampler = 0;
1915 float constant_color[4];
1916 unsigned int i;
1918 /* ARB_texture_env_combine is limited to GL_MAX_TEXTURE_UNITS stages. On
1919 * nVidia cards GL_MAX_TEXTURE_UNITS is generally not larger than 4.
1920 * Register combiners however provide up to 8 combiner stages. In order to
1921 * take advantage of this, we need to be separate D3D texture stages from
1922 * GL texture units. When using register combiners GL_MAX_TEXTURE_UNITS
1923 * corresponds to MaxSimultaneousTextures and GL_MAX_GENERAL_COMBINERS_NV
1924 * corresponds to MaxTextureBlendStages in the caps. */
1926 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1927 glEnable(GL_REGISTER_COMBINERS_NV);
1928 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], constant_color);
1929 GL_EXTCALL(glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, &constant_color[0]));
1932 for (i = 0; i < GL_LIMITS(texture_stages); ++i) {
1933 INT texture_idx = -1;
1935 /* D3DTOP_DISABLE disables the current & any higher texture stages */
1936 if (This->stateBlock->textureState[i][WINED3DTSS_COLOROP] == D3DTOP_DISABLE) break;
1938 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[i]) {
1939 texture_idx = current_sampler++;
1941 /* Active the texture unit corresponding to the current texture stage */
1942 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1943 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1944 checkGLcall("glActiveTextureARB");
1945 } else if (i) {
1946 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1950 if (This->stateBlock->textures[i]) {
1951 /* Enable the correct target. */
1952 glDisable(GL_TEXTURE_1D);
1953 This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1954 switch(This->stateBlock->textureDimensions[i]) {
1955 case GL_TEXTURE_2D:
1956 glDisable(GL_TEXTURE_3D);
1957 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1958 break;
1959 case GL_TEXTURE_3D:
1960 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1961 glDisable(GL_TEXTURE_2D);
1962 break;
1963 case GLTEXTURECUBEMAP:
1964 glDisable(GL_TEXTURE_2D);
1965 glDisable(GL_TEXTURE_3D);
1966 break;
1969 /* imply GL_SUPPORT(NV_TEXTURE_SHADER) when setting texture_shader_active */
1970 if (This->texture_shader_active && This->stateBlock->textureDimensions[i] == GL_TEXTURE_2D) {
1971 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
1972 } else {
1973 glEnable(This->stateBlock->textureDimensions[i]);
1976 /* Upload texture, apply states */
1977 IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
1978 IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, texture_idx, REAPPLY_ALPHAOP);
1979 IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
1980 } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1981 /* ARB_texture_env_combine needs a valid texture bound to the
1982 * texture unit, even if it isn't used. Bind a dummy texture. */
1983 glDisable(GL_TEXTURE_2D);
1984 glDisable(GL_TEXTURE_3D);
1985 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1986 glEnable(GL_TEXTURE_1D);
1987 This->stateBlock->textureDimensions[i] = GL_TEXTURE_1D;
1988 glBindTexture(GL_TEXTURE_1D, This->dummyTextureName[i]);
1991 /** these ops apply to the texture unit, so they are preserved between texture changes, but for now brute force and reapply all
1992 dx9_1pass_emboss_bump_mapping and dx9_2pass_emboss_bump_mapping are good texts to make sure the states are being applied when needed **/
1993 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1994 set_tex_op_nvrc((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
1995 This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
1996 This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
1997 This->stateBlock->textureState[i][WINED3DTSS_COLORARG0],
1998 texture_idx);
1999 /* alphaop */
2000 set_tex_op_nvrc((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2001 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2002 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2003 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0],
2004 texture_idx);
2005 } else {
2006 set_tex_op((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
2007 This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
2008 This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
2009 This->stateBlock->textureState[i][WINED3DTSS_COLORARG0]);
2010 /* alphaop */
2011 set_tex_op((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2012 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2013 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2014 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0]);
2018 /* If we're using register combiners, set the amount of *used* combiners.
2019 * Ie, the number of stages below the first stage to have a color op of
2020 * D3DTOP_DISABLE. */
2021 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2022 /* NUM_GENERAL_COMBINERS_NV should be > 0 */
2023 if (!i) glDisable(GL_REGISTER_COMBINERS_NV);
2024 else GL_EXTCALL(glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, i));
2027 /* Disable the remaining texture units. */
2028 for (i = current_sampler; i < GL_LIMITS(textures); ++i) {
2029 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2030 glDisable(GL_TEXTURE_1D);
2031 glDisable(GL_TEXTURE_2D);
2032 glDisable(GL_TEXTURE_3D);
2033 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2037 /* Routine common to the draw primitive and draw indexed primitive routines */
2038 void drawPrimitive(IWineD3DDevice *iface,
2039 int PrimitiveType,
2040 long NumPrimitives,
2041 /* for Indexed: */
2042 long StartVertexIndex,
2043 UINT numberOfVertices,
2044 long StartIdx,
2045 short idxSize,
2046 const void *idxData,
2047 int minIndex,
2048 WineDirect3DVertexStridedData *DrawPrimStrideData) {
2050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2051 BOOL useVertexShaderFunction = FALSE;
2052 BOOL usePixelShaderFunction = FALSE;
2053 WineDirect3DVertexStridedData *dataLocations;
2054 IWineD3DSwapChainImpl *swapchain;
2055 int i;
2056 BOOL fixup = FALSE;
2058 BOOL lighting_changed, lighting_original = FALSE;
2060 /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
2061 * here simply check whether a shader was set, or the user disabled shaders */
2062 if (wined3d_settings.vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
2063 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL)
2064 useVertexShaderFunction = TRUE;
2066 if (wined3d_settings.ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
2067 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function)
2068 usePixelShaderFunction = TRUE;
2070 /* Invalidate the back buffer memory so LockRect will read it the next time */
2071 for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
2072 IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
2073 if(swapchain) {
2074 if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer[0])->Flags |= SFLAG_GLDIRTY;
2075 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2079 /* Ok, we will be updating the screen from here onwards so grab the lock */
2080 ENTER_GL();
2082 if(DrawPrimStrideData) {
2084 /* Note: this is a ddraw fixed-function code path */
2086 TRACE("================ Strided Input ===================\n");
2087 dataLocations = DrawPrimStrideData;
2088 drawPrimitiveTraceDataLocations(dataLocations);
2089 fixup = FALSE;
2092 else if (This->stateBlock->vertexDecl || This->stateBlock->vertexShader) {
2094 /* Note: This is a fixed function or shader codepath.
2095 * This means it must handle both types of strided data.
2096 * Shaders must go through here to zero the strided data, even if they
2097 * don't set any declaration at all */
2099 TRACE("================ Vertex Declaration ===================\n");
2100 dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2101 if(!dataLocations) {
2102 ERR("Out of memory!\n");
2103 return;
2106 if (This->stateBlock->vertexDecl != NULL ||
2107 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration != NULL)
2109 primitiveDeclarationConvertToStridedData(iface, useVertexShaderFunction,
2110 dataLocations, StartVertexIndex, &fixup);
2112 } else {
2114 /* Note: This codepath is not reachable from d3d9 (see fvf->decl9 conversion)
2115 * It is reachable through d3d8, but only for fixed-function.
2116 * It will not work properly for shaders. */
2118 TRACE("================ FVF ===================\n");
2119 dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2120 if(!dataLocations) {
2121 ERR("Out of memory!\n");
2122 return;
2124 primitiveConvertToStridedData(iface, dataLocations, StartVertexIndex, &fixup);
2125 drawPrimitiveTraceDataLocations(dataLocations);
2128 /* Setup transform matrices and sort out */
2129 primitiveInitState(iface, dataLocations, useVertexShaderFunction, &lighting_changed, &lighting_original);
2131 /* Now initialize the materials state */
2132 init_materials(iface, (dataLocations->u.s.diffuse.lpData != NULL || dataLocations->u.s.diffuse.VBO != 0));
2134 if (usePixelShaderFunction) {
2135 drawPrimitiveUploadTexturesPS(This);
2136 } else {
2137 drawPrimitiveUploadTextures(This);
2141 GLenum glPrimType;
2142 /* Ok, Work out which primitive is requested and how many vertexes that
2143 will be */
2144 UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
2145 if (numberOfVertices == 0 )
2146 numberOfVertices = calculatedNumberOfindices;
2148 drawPrimitiveDrawStrided(iface, useVertexShaderFunction, usePixelShaderFunction,
2149 dataLocations, numberOfVertices, calculatedNumberOfindices, glPrimType,
2150 idxData, idxSize, minIndex, StartIdx, fixup);
2153 if(!DrawPrimStrideData) HeapFree(GetProcessHeap(), 0, dataLocations);
2155 /* If vertex shaders or no normals, restore previous lighting state */
2156 if (lighting_changed) {
2157 if (lighting_original) glEnable(GL_LIGHTING);
2158 else glDisable(GL_LIGHTING);
2159 TRACE("Restored lighting to original state\n");
2162 /* Finshed updating the screen, restore lock */
2163 LEAVE_GL();
2164 TRACE("Done all gl drawing\n");
2166 /* Diagnostics */
2167 #ifdef SHOW_FRAME_MAKEUP
2169 static long int primCounter = 0;
2170 /* NOTE: set primCounter to the value reported by drawprim
2171 before you want to to write frame makeup to /tmp */
2172 if (primCounter >= 0) {
2173 WINED3DLOCKED_RECT r;
2174 char buffer[80];
2175 IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY);
2176 sprintf(buffer, "/tmp/backbuffer_%ld.tga", primCounter);
2177 TRACE("Saving screenshot %s\n", buffer);
2178 IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
2179 IWineD3DSurface_UnlockRect(This->renderTarget);
2181 #ifdef SHOW_TEXTURE_MAKEUP
2183 IWineD3DSurface *pSur;
2184 int textureNo;
2185 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
2186 if (This->stateBlock->textures[textureNo] != NULL) {
2187 sprintf(buffer, "/tmp/texture_%p_%ld_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
2188 TRACE("Saving texture %s\n", buffer);
2189 if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
2190 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
2191 IWineD3DSurface_SaveSnapshot(pSur, buffer);
2192 IWineD3DSurface_Release(pSur);
2193 } else {
2194 FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
2199 #endif
2201 TRACE("drawprim #%ld\n", primCounter);
2202 ++primCounter;
2204 #endif