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