wined3d: Improve float constant loading a bit.
[wine/multimedia.git] / dlls / wined3d / drawprim.c
blob5eb71f1ed17820fb2d62d9b0dcdfa765a9aa9e1b
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 /* This should match any arrays loaded in loadNumberedArrays. */
798 /* TODO: Only load / unload arrays if we have to. */
799 static void unloadNumberedArrays(IWineD3DDevice *iface) {
800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
802 /* disable any attribs (this is the same for both GLSL and ARB modes) */
803 GLint maxAttribs;
804 int i;
806 /* Leave all the attribs disabled */
807 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
808 /* MESA does not support it right not */
809 if (glGetError() != GL_NO_ERROR)
810 maxAttribs = 16;
811 for (i = 0; i < maxAttribs; ++i) {
812 GL_EXTCALL(glDisableVertexAttribArrayARB(i));
813 checkGLcall("glDisableVertexAttribArrayARB(reg);");
817 /* TODO: Only load / unload arrays if we have to. */
818 static void loadNumberedArrays(
819 IWineD3DDevice *iface,
820 IWineD3DVertexShader *shader,
821 WineDirect3DVertexStridedData *strided) {
823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
824 GLint curVBO = -1;
825 int i;
827 for (i = 0; i < MAX_ATTRIBS; i++) {
829 if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
830 continue;
832 TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
834 if(curVBO != strided->u.input[i].VBO) {
835 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, strided->u.input[i].VBO));
836 checkGLcall("glBindBufferARB");
837 curVBO = strided->u.input[i].VBO;
839 GL_EXTCALL(glVertexAttribPointerARB(i,
840 WINED3D_ATR_SIZE(strided->u.input[i].dwType),
841 WINED3D_ATR_GLTYPE(strided->u.input[i].dwType),
842 WINED3D_ATR_NORMALIZED(strided->u.input[i].dwType),
843 strided->u.input[i].dwStride,
844 strided->u.input[i].lpData));
845 GL_EXTCALL(glEnableVertexAttribArrayARB(i));
849 /* This should match any arrays loaded in loadVertexData. */
850 /* TODO: Only load / unload arrays if we have to. */
851 static void unloadVertexData(IWineD3DDevice *iface) {
852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
853 int texture_idx;
855 glDisableClientState(GL_VERTEX_ARRAY);
856 glDisableClientState(GL_NORMAL_ARRAY);
857 glDisableClientState(GL_COLOR_ARRAY);
858 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
859 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
861 for (texture_idx = 0; texture_idx < GL_LIMITS(textures); ++texture_idx) {
862 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
863 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
867 /* TODO: Only load / unload arrays if we have to. */
868 static void loadVertexData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd) {
869 unsigned int textureNo = 0;
870 unsigned int texture_idx = 0;
871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
872 GLint curVBO = -1;
874 TRACE("Using fast vertex array code\n");
875 /* Blend Data ---------------------------------------------- */
876 if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) ||
877 (sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) {
880 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
882 #if 1
883 glEnableClientState(GL_WEIGHT_ARRAY_ARB);
884 checkGLcall("glEnableClientState(GL_WEIGHT_ARRAY_ARB)");
885 #endif
887 TRACE("Blend %d %p %ld\n", WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
888 sd->u.s.blendWeights.lpData, sd->u.s.blendWeights.dwStride);
889 /* FIXME("TODO\n");*/
890 /* Note dwType == float3 or float4 == 2 or 3 */
892 #if 0
893 /* with this on, the normals appear to be being modified,
894 but the vertices aren't being translated as they should be
895 Maybe the world matrix aren't being setup properly? */
896 glVertexBlendARB(WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) + 1);
897 #endif
900 VTRACE(("glWeightPointerARB(%d, GL_FLOAT, %ld, %p)\n",
901 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) ,
902 sd->u.s.blendWeights.dwStride,
903 sd->u.s.blendWeights.lpData));
905 if(curVBO != sd->u.s.blendWeights.VBO) {
906 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.blendWeights.VBO));
907 checkGLcall("glBindBufferARB");
908 curVBO = sd->u.s.blendWeights.VBO;
911 GL_EXTCALL(glWeightPointerARB)(
912 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
913 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
914 sd->u.s.blendWeights.dwStride,
915 sd->u.s.blendWeights.lpData);
917 checkGLcall("glWeightPointerARB");
919 if((sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO)){
920 static BOOL showfixme = TRUE;
921 if(showfixme){
922 FIXME("blendMatrixIndices support\n");
923 showfixme = FALSE;
927 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
928 /* FIXME("TODO\n");*/
929 #if 0
931 GL_EXTCALL(glVertexWeightPointerEXT)(
932 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
933 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
934 sd->u.s.blendWeights.dwStride,
935 sd->u.s.blendWeights.lpData);
936 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
937 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
938 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
939 #endif
941 } else {
942 /* TODO: support blends in fixupVertices */
943 FIXME("unsupported blending in openGl\n");
945 } else {
946 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
947 #if 0 /* TODO: Vertex blending */
948 glDisable(GL_VERTEX_BLEND_ARB);
949 #endif
950 TRACE("ARB_VERTEX_BLEND\n");
951 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
952 TRACE(" EXT_VERTEX_WEIGHTING\n");
953 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
954 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
959 #if 0 /* FOG ----------------------------------------------*/
960 if (sd->u.s.fog.lpData || sd->u.s.fog.VBO) {
961 /* TODO: fog*/
962 if (GL_SUPPORT(EXT_FOG_COORD) {
963 glEnableClientState(GL_FOG_COORDINATE_EXT);
964 (GL_EXTCALL)(FogCoordPointerEXT)(
965 WINED3D_ATR_GLTYPE(sd->u.s.fog.dwType),
966 sd->u.s.fog.dwStride,
967 sd->u.s.fog.lpData);
968 } else {
969 /* don't bother falling back to 'slow' as we don't support software FOG yet. */
970 /* FIXME: fixme once */
971 TRACE("Hardware support for FOG is not avaiable, FOG disabled.\n");
973 } else {
974 if (GL_SUPPRT(EXT_FOR_COORD) {
975 /* make sure fog is disabled */
976 glDisableClientState(GL_FOG_COORDINATE_EXT);
979 #endif
981 #if 0 /* tangents ----------------------------------------------*/
982 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO ||
983 sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
984 /* TODO: tangents*/
985 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
986 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO) {
987 glEnable(GL_TANGENT_ARRAY_EXT);
988 (GL_EXTCALL)(TangentPointerEXT)(
989 WINED3D_ATR_GLTYPE(sd->u.s.tangent.dwType),
990 sd->u.s.tangent.dwStride,
991 sd->u.s.tangent.lpData);
992 } else {
993 glDisable(GL_TANGENT_ARRAY_EXT);
995 if (sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
996 glEnable(GL_BINORMAL_ARRAY_EXT);
997 (GL_EXTCALL)(BinormalPointerEXT)(
998 WINED3D_ATR_GLTYPE(sd->u.s.binormal.dwType),
999 sd->u.s.binormal.dwStride,
1000 sd->u.s.binormal.lpData);
1001 } else{
1002 glDisable(GL_BINORMAL_ARRAY_EXT);
1005 } else {
1006 /* don't bother falling back to 'slow' as we don't support software tangents and binormals yet . */
1007 /* FIXME: fixme once */
1008 TRACE("Hardware support for tangents and binormals is not avaiable, tangents and binormals disabled.\n");
1010 } else {
1011 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
1012 /* make sure fog is disabled */
1013 glDisable(GL_TANGENT_ARRAY_EXT);
1014 glDisable(GL_BINORMAL_ARRAY_EXT);
1017 #endif
1019 /* Point Size ----------------------------------------------*/
1020 if (sd->u.s.pSize.lpData || sd->u.s.pSize.VBO) {
1022 /* no such functionality in the fixed function GL pipeline */
1023 TRACE("Cannot change ptSize here in openGl\n");
1024 /* TODO: Implement this function in using shaders if they are available */
1028 /* Vertex Pointers -----------------------------------------*/
1029 if (sd->u.s.position.lpData != NULL || sd->u.s.position.VBO != 0) {
1030 /* Note dwType == float3 or float4 == 2 or 3 */
1031 VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n",
1032 sd->u.s.position.dwStride,
1033 sd->u.s.position.dwType + 1,
1034 sd->u.s.position.lpData));
1036 if(curVBO != sd->u.s.position.VBO) {
1037 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.position.VBO));
1038 checkGLcall("glBindBufferARB");
1039 curVBO = sd->u.s.position.VBO;
1042 /* min(WINED3D_ATR_SIZE(position),3) to Disable RHW mode as 'w' coord
1043 handling for rhw mode should not impact screen position whereas in GL it does.
1044 This may result in very slightly distored textures in rhw mode, but
1045 a very minimal different. There's always the other option of
1046 fixing the view matrix to prevent w from having any effect
1048 This only applies to user pointer sources, in VBOs the vertices are fixed up
1050 if(sd->u.s.position.VBO == 0) {
1051 glVertexPointer(3 /* min(WINED3D_ATR_SIZE(sd->u.s.position.dwType),3) */,
1052 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1053 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1054 } else {
1055 glVertexPointer(
1056 WINED3D_ATR_SIZE(sd->u.s.position.dwType),
1057 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1058 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1060 checkGLcall("glVertexPointer(...)");
1061 glEnableClientState(GL_VERTEX_ARRAY);
1062 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
1064 } else {
1065 glDisableClientState(GL_VERTEX_ARRAY);
1066 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
1069 /* Normals -------------------------------------------------*/
1070 if (sd->u.s.normal.lpData || sd->u.s.normal.VBO) {
1071 /* Note dwType == float3 or float4 == 2 or 3 */
1072 VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n",
1073 sd->u.s.normal.dwStride,
1074 sd->u.s.normal.lpData));
1075 if(curVBO != sd->u.s.normal.VBO) {
1076 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.normal.VBO));
1077 checkGLcall("glBindBufferARB");
1078 curVBO = sd->u.s.normal.VBO;
1080 glNormalPointer(
1081 WINED3D_ATR_GLTYPE(sd->u.s.normal.dwType),
1082 sd->u.s.normal.dwStride,
1083 sd->u.s.normal.lpData);
1084 checkGLcall("glNormalPointer(...)");
1085 glEnableClientState(GL_NORMAL_ARRAY);
1086 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
1088 } else {
1089 glDisableClientState(GL_NORMAL_ARRAY);
1090 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
1091 glNormal3f(0, 0, 1);
1092 checkGLcall("glNormal3f(0, 0, 1)");
1095 /* Diffuse Colour --------------------------------------------*/
1096 /* WARNING: Data here MUST be in RGBA format, so cannot */
1097 /* go directly into fast mode from app pgm, because */
1098 /* directx requires data in BGRA format. */
1099 /* currently fixupVertices swizels the format, but this isn't */
1100 /* very practical when using VBOS */
1101 /* NOTE: Unless we write a vertex shader to swizel the colour */
1102 /* , or the user doesn't care and wants the speed advantage */
1104 if (sd->u.s.diffuse.lpData || sd->u.s.diffuse.VBO) {
1105 /* Note dwType == float3 or float4 == 2 or 3 */
1106 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
1107 sd->u.s.diffuse.dwStride,
1108 sd->u.s.diffuse.lpData));
1110 if(curVBO != sd->u.s.diffuse.VBO) {
1111 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.diffuse.VBO));
1112 checkGLcall("glBindBufferARB");
1113 curVBO = sd->u.s.diffuse.VBO;
1115 glColorPointer(4, GL_UNSIGNED_BYTE,
1116 sd->u.s.diffuse.dwStride,
1117 sd->u.s.diffuse.lpData);
1118 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
1119 glEnableClientState(GL_COLOR_ARRAY);
1120 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
1122 } else {
1123 glDisableClientState(GL_COLOR_ARRAY);
1124 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
1125 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1126 checkGLcall("glColor4f(1, 1, 1, 1)");
1129 /* Specular Colour ------------------------------------------*/
1130 if (sd->u.s.specular.lpData || sd->u.s.specular.VBO) {
1131 TRACE("setting specular colour\n");
1132 /* Note dwType == float3 or float4 == 2 or 3 */
1133 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
1134 sd->u.s.specular.dwStride,
1135 sd->u.s.specular.lpData));
1136 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1137 if(curVBO != sd->u.s.specular.VBO) {
1138 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.specular.VBO));
1139 checkGLcall("glBindBufferARB");
1140 curVBO = sd->u.s.specular.VBO;
1142 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
1143 sd->u.s.specular.dwStride,
1144 sd->u.s.specular.lpData);
1145 vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
1146 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1147 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1148 } else {
1150 /* Missing specular color is not critical, no warnings */
1151 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1154 } else {
1155 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1157 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1158 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1159 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1160 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
1161 } else {
1163 /* Missing specular color is not critical, no warnings */
1164 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1168 /* Texture coords -------------------------------------------*/
1170 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1171 /* The code below uses glClientActiveTexture and glMultiTexCoord* which are all part of the GL_ARB_multitexture extension. */
1172 /* Abort if we don't support the extension. */
1173 if (!GL_SUPPORT(ARB_MULTITEXTURE)) {
1174 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1175 continue;
1178 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) {
1179 /* Select the correct texture stage */
1180 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1183 if (This->stateBlock->textures[textureNo] != NULL) {
1184 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1186 if (coordIdx >= MAX_TEXTURES) {
1187 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1188 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1189 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1191 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL && sd->u.s.texCoords[coordIdx].VBO == 0) {
1192 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
1193 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1194 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1196 } else {
1197 TRACE("Setting up texture %u, idx %d, cordindx %u, data %p\n",
1198 textureNo, texture_idx, coordIdx, sd->u.s.texCoords[coordIdx].lpData);
1199 if(curVBO != sd->u.s.texCoords[coordIdx].VBO) {
1200 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.texCoords[coordIdx].VBO));
1201 checkGLcall("glBindBufferARB");
1202 curVBO = sd->u.s.texCoords[coordIdx].VBO;
1204 /* The coords to supply depend completely on the fvf / vertex shader */
1205 glTexCoordPointer(
1206 WINED3D_ATR_SIZE(sd->u.s.texCoords[coordIdx].dwType),
1207 WINED3D_ATR_GLTYPE(sd->u.s.texCoords[coordIdx].dwType),
1208 sd->u.s.texCoords[coordIdx].dwStride,
1209 sd->u.s.texCoords[coordIdx].lpData);
1210 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1212 } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1213 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1214 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1216 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1218 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1219 for (textureNo = texture_idx; textureNo < GL_LIMITS(textures); ++textureNo) {
1220 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo));
1221 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1222 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1227 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
1228 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1231 if (idxData != NULL /* This crashes sometimes!*/) {
1232 TRACE("(%p) : glElements(%x, %d, %ld, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
1233 idxData = idxData == (void *)-1 ? NULL : idxData;
1234 #if 1
1235 #if 0
1236 glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
1237 glEnableClientState(GL_INDEX_ARRAY);
1238 #endif
1239 glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1240 (const char *)idxData+(idxSize * startIdx));
1241 #else /* using drawRangeElements may be faster */
1243 glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
1244 idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1245 (const char *)idxData+(idxSize * startIdx));
1246 #endif
1247 checkGLcall("glDrawRangeElements");
1249 } else {
1251 /* Note first is now zero as we shuffled along earlier */
1252 TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
1253 glDrawArrays(glPrimitiveType, 0, numberOfVertices);
1254 checkGLcall("glDrawArrays");
1258 return;
1262 * Actually draw using the supplied information.
1263 * Slower GL version which extracts info about each vertex in turn
1266 static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1267 UINT NumVertexes, GLenum glPrimType,
1268 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1270 unsigned int textureNo = 0;
1271 unsigned int texture_idx = 0;
1272 const short *pIdxBufS = NULL;
1273 const long *pIdxBufL = NULL;
1274 LONG SkipnStrides = 0;
1275 LONG vx_index;
1276 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1277 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
1278 float rhw = 0.0f; /* rhw */
1279 float ptSize = 0.0f; /* Point size */
1280 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
1281 DWORD specularColor = 0; /* Specular Color */
1282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1284 TRACE("Using slow vertex array code\n");
1286 /* Variable Initialization */
1287 if (idxData != NULL) {
1288 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1289 else pIdxBufL = (const long *) idxData;
1292 /* Start drawing in GL */
1293 VTRACE(("glBegin(%x)\n", glPrimType));
1294 glBegin(glPrimType);
1296 /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
1297 * Guess it's not necessary(we crash then anyway) and would only eat CPU time
1300 /* For each primitive */
1301 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1303 /* Initialize diffuse color */
1304 diffuseColor = 0xFFFFFFFF;
1306 /* For indexed data, we need to go a few more strides in */
1307 if (idxData != NULL) {
1309 /* Indexed so work out the number of strides to skip */
1310 if (idxSize == 2) {
1311 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1312 SkipnStrides = pIdxBufS[startIdx + vx_index];
1313 } else {
1314 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1315 SkipnStrides = pIdxBufL[startIdx + vx_index];
1319 /* Position Information ------------------ */
1320 if (sd->u.s.position.lpData != NULL) {
1322 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
1323 x = ptrToCoords[0];
1324 y = ptrToCoords[1];
1325 z = ptrToCoords[2];
1326 rhw = 1.0;
1327 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
1329 /* RHW follows, only if transformed, ie 4 floats were provided */
1330 if (sd->u.s.position_transformed) {
1331 rhw = ptrToCoords[3];
1332 VTRACE(("rhw=%f\n", rhw));
1336 /* Blending data -------------------------- */
1337 if (sd->u.s.blendWeights.lpData != NULL) {
1338 /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
1339 FIXME("Blending not supported yet\n");
1341 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
1342 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
1346 /* Vertex Normal Data (untransformed only)- */
1347 if (sd->u.s.normal.lpData != NULL) {
1349 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
1350 nx = ptrToCoords[0];
1351 ny = ptrToCoords[1];
1352 nz = ptrToCoords[2];
1353 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
1356 /* Point Size ----------------------------- */
1357 if (sd->u.s.pSize.lpData != NULL) {
1359 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1360 ptSize = ptrToCoords[0];
1361 VTRACE(("ptSize=%f\n", ptSize));
1362 FIXME("No support for ptSize yet\n");
1365 /* Diffuse -------------------------------- */
1366 if (sd->u.s.diffuse.lpData != NULL) {
1368 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1369 diffuseColor = ptrToCoords[0];
1370 VTRACE(("diffuseColor=%lx\n", diffuseColor));
1373 /* Specular -------------------------------- */
1374 if (sd->u.s.specular.lpData != NULL) {
1376 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1377 specularColor = ptrToCoords[0];
1378 VTRACE(("specularColor=%lx\n", specularColor));
1381 /* Texture coords --------------------------- */
1382 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1384 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1385 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1386 continue ;
1389 /* Query tex coords */
1390 if (This->stateBlock->textures[textureNo] != NULL) {
1392 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1393 float *ptrToCoords = NULL;
1394 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1396 if (coordIdx > 7) {
1397 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1398 ++texture_idx;
1399 continue;
1400 } else if (coordIdx < 0) {
1401 FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
1402 ++texture_idx;
1403 continue;
1406 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1407 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1408 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1409 ++texture_idx;
1410 continue;
1411 } else {
1413 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DDECLTYPE_FLOAT1 etc */
1415 /* The coords to supply depend completely on the fvf / vertex shader */
1416 switch (coordsToUse) {
1417 case 4: q = ptrToCoords[3]; /* drop through */
1418 case 3: r = ptrToCoords[2]; /* drop through */
1419 case 2: t = ptrToCoords[1]; /* drop through */
1420 case 1: s = ptrToCoords[0];
1423 /* Projected is more 'fun' - Move the last coord to the 'q'
1424 parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1425 if ((This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1426 (This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1428 if (This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1429 switch (coordsToUse) {
1430 case 0: /* Drop Through */
1431 case 1:
1432 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1433 break;
1434 case 2:
1435 q = t;
1436 t = 0.0;
1437 coordsToUse = 4;
1438 break;
1439 case 3:
1440 q = r;
1441 r = 0.0;
1442 coordsToUse = 4;
1443 break;
1444 case 4: /* Nop here */
1445 break;
1446 default:
1447 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n",
1448 This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1453 switch (coordsToUse) { /* Supply the provided texture coords */
1454 case D3DTTFF_COUNT1:
1455 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1456 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1457 GL_EXTCALL(glMultiTexCoord1fARB(texture_idx, s));
1458 } else {
1459 glTexCoord1f(s);
1461 break;
1462 case D3DTTFF_COUNT2:
1463 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1464 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1465 GL_EXTCALL(glMultiTexCoord2fARB(texture_idx, s, t));
1466 } else {
1467 glTexCoord2f(s, t);
1469 break;
1470 case D3DTTFF_COUNT3:
1471 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1472 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1473 GL_EXTCALL(glMultiTexCoord3fARB(texture_idx, s, t, r));
1474 } else {
1475 glTexCoord3f(s, t, r);
1477 break;
1478 case D3DTTFF_COUNT4:
1479 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1480 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1481 GL_EXTCALL(glMultiTexCoord4fARB(texture_idx, s, t, r, q));
1482 } else {
1483 glTexCoord4f(s, t, r, q);
1485 break;
1486 default:
1487 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1491 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1492 } /* End of textures */
1494 /* Diffuse -------------------------------- */
1495 if (sd->u.s.diffuse.lpData != NULL) {
1496 glColor4ub(D3DCOLOR_B_R(diffuseColor),
1497 D3DCOLOR_B_G(diffuseColor),
1498 D3DCOLOR_B_B(diffuseColor),
1499 D3DCOLOR_B_A(diffuseColor));
1500 VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n",
1501 D3DCOLOR_B_R(diffuseColor),
1502 D3DCOLOR_B_G(diffuseColor),
1503 D3DCOLOR_B_B(diffuseColor),
1504 D3DCOLOR_B_A(diffuseColor)));
1505 } else {
1506 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1509 /* Specular ------------------------------- */
1510 if (sd->u.s.specular.lpData != NULL) {
1511 /* special case where the fog density is stored in the diffuse alpha channel */
1512 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
1513 (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == D3DFOG_NONE || sd->u.s.position.dwType == D3DDECLTYPE_FLOAT4 )&&
1514 This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
1515 if(GL_SUPPORT(EXT_FOG_COORD)) {
1516 GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
1517 } else {
1518 static BOOL warned = FALSE;
1519 if(!warned) {
1520 /* TODO: Use the fog table code from old ddraw */
1521 FIXME("Implement fog for transformed vertices in software\n");
1522 warned = TRUE;
1527 VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n",
1528 D3DCOLOR_B_R(specularColor),
1529 D3DCOLOR_B_G(specularColor),
1530 D3DCOLOR_B_B(specularColor)));
1531 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1532 GL_EXTCALL(glSecondaryColor3ubEXT)(
1533 D3DCOLOR_B_R(specularColor),
1534 D3DCOLOR_B_G(specularColor),
1535 D3DCOLOR_B_B(specularColor));
1536 } else {
1537 /* Do not worry if specular colour missing and disable request */
1538 VTRACE(("Specular color extensions not supplied\n"));
1540 } else {
1541 if (vx_index == 0) {
1542 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1543 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1544 } else {
1545 /* Do not worry if specular colour missing and disable request */
1546 VTRACE(("Specular color extensions not supplied\n"));
1551 /* Normal -------------------------------- */
1552 if (sd->u.s.normal.lpData != NULL) {
1553 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1554 glNormal3f(nx, ny, nz);
1555 } else {
1556 if (vx_index == 0) glNormal3f(0, 0, 1);
1559 /* Position -------------------------------- */
1560 if (sd->u.s.position.lpData != NULL) {
1561 if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
1562 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1563 glVertex3f(x, y, z);
1564 } else {
1565 GLfloat w = 1.0 / rhw;
1566 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1567 glVertex4f(x*w, y*w, z*w, w);
1571 /* For non indexed mode, step onto next parts */
1572 if (idxData == NULL) {
1573 ++SkipnStrides;
1577 glEnd();
1578 checkGLcall("glEnd and previous calls");
1581 #if 0 /* TODO: Software/Hardware vertex blending support */
1583 * Draw with emulated vertex shaders
1584 * Note: strided data is uninitialized, as we need to pass the vertex
1585 * shader directly as ordering irs yet
1587 void drawStridedSoftwareVS(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1588 int PrimitiveType, ULONG NumPrimitives,
1589 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1591 unsigned int textureNo = 0;
1592 GLenum glPrimType = GL_POINTS;
1593 int NumVertexes = NumPrimitives;
1594 const short *pIdxBufS = NULL;
1595 const long *pIdxBufL = NULL;
1596 LONG SkipnStrides = 0;
1597 LONG vx_index;
1598 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1599 float rhw = 0.0f; /* rhw */
1600 float ptSize = 0.0f; /* Point size */
1601 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1602 int numcoords[8]; /* Number of coords */
1603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1605 IDirect3DVertexShaderImpl* vertexShader = NULL;
1607 TRACE("Using slow software vertex shader code\n");
1609 /* Variable Initialization */
1610 if (idxData != NULL) {
1611 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1612 else pIdxBufL = (const long *) idxData;
1615 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1616 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1618 /* Retrieve the VS information */
1619 vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
1621 /* Start drawing in GL */
1622 VTRACE(("glBegin(%x)\n", glPrimType));
1623 glBegin(glPrimType);
1625 /* For each primitive */
1626 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1628 /* For indexed data, we need to go a few more strides in */
1629 if (idxData != NULL) {
1631 /* Indexed so work out the number of strides to skip */
1632 if (idxSize == 2) {
1633 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1634 SkipnStrides = pIdxBufS[startIdx+vx_index];
1635 } else {
1636 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1637 SkipnStrides = pIdxBufL[startIdx+vx_index];
1641 /* Fill the vertex shader input */
1642 IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1644 /* Initialize the output fields to the same defaults as it would normally have */
1645 memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1646 vertexShader->output.oD[0].x = 1.0;
1647 vertexShader->output.oD[0].y = 1.0;
1648 vertexShader->output.oD[0].z = 1.0;
1649 vertexShader->output.oD[0].w = 1.0;
1651 /* Now execute the vertex shader */
1652 IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1655 TRACE_VECTOR(vertexShader->output.oPos);
1656 TRACE_VECTOR(vertexShader->output.oD[0]);
1657 TRACE_VECTOR(vertexShader->output.oD[1]);
1658 TRACE_VECTOR(vertexShader->output.oT[0]);
1659 TRACE_VECTOR(vertexShader->output.oT[1]);
1660 TRACE_VECTOR(vertexShader->input.V[0]);
1661 TRACE_VECTOR(vertexShader->data->C[0]);
1662 TRACE_VECTOR(vertexShader->data->C[1]);
1663 TRACE_VECTOR(vertexShader->data->C[2]);
1664 TRACE_VECTOR(vertexShader->data->C[3]);
1665 TRACE_VECTOR(vertexShader->data->C[4]);
1666 TRACE_VECTOR(vertexShader->data->C[5]);
1667 TRACE_VECTOR(vertexShader->data->C[6]);
1668 TRACE_VECTOR(vertexShader->data->C[7]);
1671 /* Extract out the output */
1672 /* FIXME: Fog coords? */
1673 x = vertexShader->output.oPos.x;
1674 y = vertexShader->output.oPos.y;
1675 z = vertexShader->output.oPos.z;
1676 rhw = vertexShader->output.oPos.w;
1677 ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1679 /** Update textures coords using vertexShader->output.oT[0->7] */
1680 memset(texcoords, 0x00, sizeof(texcoords));
1681 memset(numcoords, 0x00, sizeof(numcoords));
1682 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1683 if (This->stateBlock->textures[textureNo] != NULL) {
1684 texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1685 texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1686 texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1687 texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1688 if (This->stateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1689 numcoords[textureNo] = This->stateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1690 } else {
1691 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1692 case WINED3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1693 case WINED3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1694 default: numcoords[textureNo] = 4;
1697 } else {
1698 numcoords[textureNo] = 0;
1702 /* Draw using this information */
1703 draw_vertex(iface,
1704 TRUE, x, y, z, rhw,
1705 TRUE, 0.0f, 0.0f, 1.0f,
1706 TRUE, (float*) &vertexShader->output.oD[0],
1707 TRUE, (float*) &vertexShader->output.oD[1],
1708 FALSE, ptSize, /* FIXME: Change back when supported */
1709 texcoords, numcoords);
1711 /* For non indexed mode, step onto next parts */
1712 if (idxData == NULL) {
1713 ++SkipnStrides;
1716 } /* for each vertex */
1718 glEnd();
1719 checkGLcall("glEnd and previous calls");
1722 #endif
1724 inline static void drawPrimitiveDrawStrided(
1725 IWineD3DDevice *iface,
1726 BOOL useVertexShaderFunction,
1727 BOOL usePixelShaderFunction,
1728 WineDirect3DVertexStridedData *dataLocations,
1729 UINT numberOfvertices,
1730 UINT numberOfIndicies,
1731 GLenum glPrimType,
1732 const void *idxData,
1733 short idxSize,
1734 int minIndex,
1735 long StartIdx,
1736 BOOL fixup) {
1738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1739 BOOL useDrawStridedSlow;
1741 int startStride = idxData == NULL ? 0 :
1742 idxData == (void *) -1 ? 0 :
1743 (idxSize == 2 ? *(((const short *) idxData) + StartIdx) : *((const int *) idxData) + StartIdx);
1744 int endStride = startStride;
1745 TRACE("begin Start stride %d, end stride %d, number of indices%d, number of vertices%d\n",
1746 startStride, endStride, numberOfIndicies, numberOfvertices);
1748 /* Generate some fixme's if unsupported functionality is being used */
1749 #define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData
1750 /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */
1751 if (!useVertexShaderFunction && (BUFFER_OR_DATA(blendMatrixIndices) || BUFFER_OR_DATA(blendWeights))) {
1752 FIXME("Blending data is only valid with vertex shaders %p %p\n",dataLocations->u.s.blendWeights.lpData,dataLocations->u.s.blendWeights.lpData);
1754 if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) {
1755 FIXME("Tweening is only valid with vertex shaders\n");
1757 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) {
1758 FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n");
1760 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) {
1761 FIXME("Extended attributes are only valid with vertex shaders\n");
1763 #undef BUFFER_OR_DATA
1765 /* Fixed pipeline, no fixups required - load arrays */
1766 if (!useVertexShaderFunction &&
1767 ((dataLocations->u.s.pSize.lpData == NULL &&
1768 dataLocations->u.s.diffuse.lpData == NULL &&
1769 dataLocations->u.s.specular.lpData == NULL) ||
1770 fixup) ) {
1772 /* Load the vertex data using named arrays */
1773 TRACE("(%p) Loading vertex data\n", This);
1774 loadVertexData(iface, dataLocations);
1775 useDrawStridedSlow = FALSE;
1777 /* Shader pipeline - load attribute arrays */
1778 } else if(useVertexShaderFunction) {
1780 loadNumberedArrays(iface, This->stateBlock->vertexShader, dataLocations);
1781 useDrawStridedSlow = FALSE;
1783 /* We compile the shader here because we need the vertex declaration
1784 * in order to determine if we need to do any swizzling for D3DCOLOR
1785 * registers. If the shader is already compiled this call will do nothing. */
1786 IWineD3DVertexShader_CompileShader(This->stateBlock->vertexShader);
1787 /* Draw vertex by vertex */
1788 } else {
1789 TRACE("Not loading vertex data\n");
1790 useDrawStridedSlow = TRUE;
1793 /* If GLSL is used for either pixel or vertex shaders, make a GLSL program
1794 * Otherwise set NULL, to restore fixed function */
1795 if ((wined3d_settings.vs_selected_mode == SHADER_GLSL && useVertexShaderFunction) ||
1796 (wined3d_settings.ps_selected_mode == SHADER_GLSL && usePixelShaderFunction))
1797 set_glsl_shader_program(iface);
1798 else
1799 This->stateBlock->glsl_program = NULL;
1801 /* If GLSL is used now, or might have been used before, (re)set the program */
1802 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
1803 wined3d_settings.ps_selected_mode == SHADER_GLSL) {
1805 GLhandleARB progId = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->programId : 0;
1806 if (progId)
1807 TRACE_(d3d_shader)("Using GLSL program %u\n", progId);
1808 GL_EXTCALL(glUseProgramObjectARB(progId));
1809 checkGLcall("glUseProgramObjectARB");
1812 if (useVertexShaderFunction) {
1814 TRACE("Using vertex shader\n");
1816 if (wined3d_settings.vs_selected_mode == SHADER_ARB) {
1817 /* Bind the vertex program */
1818 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB,
1819 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId));
1820 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
1822 /* Enable OpenGL vertex programs */
1823 glEnable(GL_VERTEX_PROGRAM_ARB);
1824 checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
1825 TRACE_(d3d_shader)("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n",
1826 This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId);
1830 if (usePixelShaderFunction) {
1832 TRACE("Using pixel shader\n");
1834 if (wined3d_settings.ps_selected_mode == SHADER_ARB) {
1835 /* Bind the fragment program */
1836 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,
1837 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId));
1838 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
1840 /* Enable OpenGL fragment programs */
1841 glEnable(GL_FRAGMENT_PROGRAM_ARB);
1842 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
1843 TRACE_(d3d_shader)("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n",
1844 This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId);
1848 /* Load any global constants/uniforms that may have been set by the application */
1849 if (wined3d_settings.vs_selected_mode == SHADER_GLSL || wined3d_settings.ps_selected_mode == SHADER_GLSL)
1850 shader_glsl_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
1851 else if (wined3d_settings.vs_selected_mode== SHADER_ARB || wined3d_settings.ps_selected_mode == SHADER_ARB)
1852 shader_arb_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
1854 /* Draw vertex-by-vertex */
1855 if (useDrawStridedSlow)
1856 drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1857 else
1858 drawStridedFast(iface, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1860 /* Cleanup vertex program */
1861 if (useVertexShaderFunction) {
1862 unloadNumberedArrays(iface);
1864 if (wined3d_settings.vs_selected_mode == SHADER_ARB)
1865 glDisable(GL_VERTEX_PROGRAM_ARB);
1866 } else {
1867 unloadVertexData(iface);
1870 /* Cleanup fragment program */
1871 if (usePixelShaderFunction && wined3d_settings.ps_selected_mode == SHADER_ARB)
1872 glDisable(GL_FRAGMENT_PROGRAM_ARB);
1875 inline void drawPrimitiveTraceDataLocations(
1876 WineDirect3DVertexStridedData *dataLocations) {
1878 /* Dump out what parts we have supplied */
1879 TRACE("Strided Data:\n");
1880 TRACE_STRIDED((dataLocations), position);
1881 TRACE_STRIDED((dataLocations), blendWeights);
1882 TRACE_STRIDED((dataLocations), blendMatrixIndices);
1883 TRACE_STRIDED((dataLocations), normal);
1884 TRACE_STRIDED((dataLocations), pSize);
1885 TRACE_STRIDED((dataLocations), diffuse);
1886 TRACE_STRIDED((dataLocations), specular);
1887 TRACE_STRIDED((dataLocations), texCoords[0]);
1888 TRACE_STRIDED((dataLocations), texCoords[1]);
1889 TRACE_STRIDED((dataLocations), texCoords[2]);
1890 TRACE_STRIDED((dataLocations), texCoords[3]);
1891 TRACE_STRIDED((dataLocations), texCoords[4]);
1892 TRACE_STRIDED((dataLocations), texCoords[5]);
1893 TRACE_STRIDED((dataLocations), texCoords[6]);
1894 TRACE_STRIDED((dataLocations), texCoords[7]);
1895 TRACE_STRIDED((dataLocations), position2);
1896 TRACE_STRIDED((dataLocations), normal2);
1897 TRACE_STRIDED((dataLocations), tangent);
1898 TRACE_STRIDED((dataLocations), binormal);
1899 TRACE_STRIDED((dataLocations), tessFactor);
1900 TRACE_STRIDED((dataLocations), fog);
1901 TRACE_STRIDED((dataLocations), depth);
1902 TRACE_STRIDED((dataLocations), sample);
1904 return;
1908 static void drawPrimitiveUploadTexturesPS(IWineD3DDeviceImpl* This) {
1909 INT i;
1911 for (i = 0; i < GL_LIMITS(samplers); ++i) {
1912 /* Pixel shader support should imply multitexture support. */
1913 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1914 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1915 checkGLcall("glActiveTextureARB");
1916 } else if (i) {
1917 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1920 if (!This->stateBlock->textures[i]) continue;
1922 /* Enable the correct target. Is this required for GLSL? For ARB_fragment_program it isn't, afaik. */
1923 glDisable(GL_TEXTURE_1D);
1924 This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1925 switch(This->stateBlock->textureDimensions[i]) {
1926 case GL_TEXTURE_2D:
1927 glDisable(GL_TEXTURE_3D);
1928 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1929 break;
1930 case GL_TEXTURE_3D:
1931 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1932 glDisable(GL_TEXTURE_2D);
1933 break;
1934 case GLTEXTURECUBEMAP:
1935 glDisable(GL_TEXTURE_2D);
1936 glDisable(GL_TEXTURE_3D);
1937 break;
1939 glEnable(This->stateBlock->textureDimensions[i]);
1941 /* Upload texture, apply states */
1942 IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
1943 IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, i, REAPPLY_ALPHAOP);
1944 IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
1948 /* uploads textures and setup texture states ready for rendering */
1949 static void drawPrimitiveUploadTextures(IWineD3DDeviceImpl* This) {
1950 INT current_sampler = 0;
1951 float constant_color[4];
1952 unsigned int i;
1954 /* ARB_texture_env_combine is limited to GL_MAX_TEXTURE_UNITS stages. On
1955 * nVidia cards GL_MAX_TEXTURE_UNITS is generally not larger than 4.
1956 * Register combiners however provide up to 8 combiner stages. In order to
1957 * take advantage of this, we need to be separate D3D texture stages from
1958 * GL texture units. When using register combiners GL_MAX_TEXTURE_UNITS
1959 * corresponds to MaxSimultaneousTextures and GL_MAX_GENERAL_COMBINERS_NV
1960 * corresponds to MaxTextureBlendStages in the caps. */
1962 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1963 glEnable(GL_REGISTER_COMBINERS_NV);
1964 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], constant_color);
1965 GL_EXTCALL(glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, &constant_color[0]));
1968 for (i = 0; i < GL_LIMITS(texture_stages); ++i) {
1969 INT texture_idx = -1;
1971 /* D3DTOP_DISABLE disables the current & any higher texture stages */
1972 if (This->stateBlock->textureState[i][WINED3DTSS_COLOROP] == D3DTOP_DISABLE) break;
1974 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[i]) {
1975 texture_idx = current_sampler++;
1977 /* Active the texture unit corresponding to the current texture stage */
1978 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1979 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1980 checkGLcall("glActiveTextureARB");
1981 } else if (i) {
1982 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1986 if (This->stateBlock->textures[i]) {
1987 /* Enable the correct target. */
1988 glDisable(GL_TEXTURE_1D);
1989 This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1990 switch(This->stateBlock->textureDimensions[i]) {
1991 case GL_TEXTURE_2D:
1992 glDisable(GL_TEXTURE_3D);
1993 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1994 break;
1995 case GL_TEXTURE_3D:
1996 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1997 glDisable(GL_TEXTURE_2D);
1998 break;
1999 case GLTEXTURECUBEMAP:
2000 glDisable(GL_TEXTURE_2D);
2001 glDisable(GL_TEXTURE_3D);
2002 break;
2005 /* imply GL_SUPPORT(NV_TEXTURE_SHADER) when setting texture_shader_active */
2006 if (This->texture_shader_active && This->stateBlock->textureDimensions[i] == GL_TEXTURE_2D) {
2007 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
2008 } else {
2009 glEnable(This->stateBlock->textureDimensions[i]);
2012 /* Upload texture, apply states */
2013 IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
2014 IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, texture_idx, REAPPLY_ALPHAOP);
2015 IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
2016 } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2017 /* ARB_texture_env_combine needs a valid texture bound to the
2018 * texture unit, even if it isn't used. Bind a dummy texture. */
2019 glDisable(GL_TEXTURE_2D);
2020 glDisable(GL_TEXTURE_3D);
2021 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2022 glEnable(GL_TEXTURE_1D);
2023 This->stateBlock->textureDimensions[i] = GL_TEXTURE_1D;
2024 glBindTexture(GL_TEXTURE_1D, This->dummyTextureName[i]);
2027 /** these ops apply to the texture unit, so they are preserved between texture changes, but for now brute force and reapply all
2028 dx9_1pass_emboss_bump_mapping and dx9_2pass_emboss_bump_mapping are good texts to make sure the states are being applied when needed **/
2029 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2030 set_tex_op_nvrc((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
2031 This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
2032 This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
2033 This->stateBlock->textureState[i][WINED3DTSS_COLORARG0],
2034 texture_idx);
2035 /* alphaop */
2036 set_tex_op_nvrc((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2037 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2038 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2039 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0],
2040 texture_idx);
2041 } else {
2042 set_tex_op((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
2043 This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
2044 This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
2045 This->stateBlock->textureState[i][WINED3DTSS_COLORARG0]);
2046 /* alphaop */
2047 set_tex_op((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2048 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2049 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2050 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0]);
2054 /* If we're using register combiners, set the amount of *used* combiners.
2055 * Ie, the number of stages below the first stage to have a color op of
2056 * D3DTOP_DISABLE. */
2057 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2058 /* NUM_GENERAL_COMBINERS_NV should be > 0 */
2059 if (!i) glDisable(GL_REGISTER_COMBINERS_NV);
2060 else GL_EXTCALL(glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, i));
2063 /* Disable the remaining texture units. */
2064 for (i = current_sampler; i < GL_LIMITS(textures); ++i) {
2065 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2066 glDisable(GL_TEXTURE_1D);
2067 glDisable(GL_TEXTURE_2D);
2068 glDisable(GL_TEXTURE_3D);
2069 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2073 /* Routine common to the draw primitive and draw indexed primitive routines */
2074 void drawPrimitive(IWineD3DDevice *iface,
2075 int PrimitiveType,
2076 long NumPrimitives,
2077 /* for Indexed: */
2078 long StartVertexIndex,
2079 UINT numberOfVertices,
2080 long StartIdx,
2081 short idxSize,
2082 const void *idxData,
2083 int minIndex,
2084 WineDirect3DVertexStridedData *DrawPrimStrideData) {
2086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2087 BOOL useVertexShaderFunction = FALSE;
2088 BOOL usePixelShaderFunction = FALSE;
2089 WineDirect3DVertexStridedData *dataLocations;
2090 IWineD3DSwapChainImpl *swapchain;
2091 int i;
2092 BOOL fixup = FALSE;
2094 BOOL lighting_changed, lighting_original = FALSE;
2096 /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
2097 * here simply check whether a shader was set, or the user disabled shaders */
2098 if (wined3d_settings.vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
2099 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL)
2100 useVertexShaderFunction = TRUE;
2102 if (wined3d_settings.ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
2103 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function)
2104 usePixelShaderFunction = TRUE;
2106 /* Invalidate the back buffer memory so LockRect will read it the next time */
2107 for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
2108 IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
2109 if(swapchain) {
2110 if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer[0])->Flags |= SFLAG_GLDIRTY;
2111 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2115 /* Ok, we will be updating the screen from here onwards so grab the lock */
2116 ENTER_GL();
2118 if(DrawPrimStrideData) {
2120 /* Note: this is a ddraw fixed-function code path */
2122 TRACE("================ Strided Input ===================\n");
2123 dataLocations = DrawPrimStrideData;
2124 drawPrimitiveTraceDataLocations(dataLocations);
2125 fixup = FALSE;
2128 else if (This->stateBlock->vertexDecl || This->stateBlock->vertexShader) {
2130 /* Note: This is a fixed function or shader codepath.
2131 * This means it must handle both types of strided data.
2132 * Shaders must go through here to zero the strided data, even if they
2133 * don't set any declaration at all */
2135 TRACE("================ Vertex Declaration ===================\n");
2136 dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2137 if(!dataLocations) {
2138 ERR("Out of memory!\n");
2139 return;
2142 if (This->stateBlock->vertexDecl != NULL ||
2143 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration != NULL)
2145 primitiveDeclarationConvertToStridedData(iface, useVertexShaderFunction,
2146 dataLocations, StartVertexIndex, &fixup);
2148 } else {
2150 /* Note: This codepath is not reachable from d3d9 (see fvf->decl9 conversion)
2151 * It is reachable through d3d8, but only for fixed-function.
2152 * It will not work properly for shaders. */
2154 TRACE("================ FVF ===================\n");
2155 dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2156 if(!dataLocations) {
2157 ERR("Out of memory!\n");
2158 return;
2160 primitiveConvertToStridedData(iface, dataLocations, StartVertexIndex, &fixup);
2161 drawPrimitiveTraceDataLocations(dataLocations);
2164 /* Setup transform matrices and sort out */
2165 primitiveInitState(iface, dataLocations, useVertexShaderFunction, &lighting_changed, &lighting_original);
2167 /* Now initialize the materials state */
2168 init_materials(iface, (dataLocations->u.s.diffuse.lpData != NULL || dataLocations->u.s.diffuse.VBO != 0));
2170 if (usePixelShaderFunction) {
2171 drawPrimitiveUploadTexturesPS(This);
2172 } else {
2173 drawPrimitiveUploadTextures(This);
2177 GLenum glPrimType;
2178 /* Ok, Work out which primitive is requested and how many vertexes that
2179 will be */
2180 UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
2181 if (numberOfVertices == 0 )
2182 numberOfVertices = calculatedNumberOfindices;
2184 drawPrimitiveDrawStrided(iface, useVertexShaderFunction, usePixelShaderFunction,
2185 dataLocations, numberOfVertices, calculatedNumberOfindices, glPrimType,
2186 idxData, idxSize, minIndex, StartIdx, fixup);
2189 if(!DrawPrimStrideData) HeapFree(GetProcessHeap(), 0, dataLocations);
2191 /* If vertex shaders or no normals, restore previous lighting state */
2192 if (lighting_changed) {
2193 if (lighting_original) glEnable(GL_LIGHTING);
2194 else glDisable(GL_LIGHTING);
2195 TRACE("Restored lighting to original state\n");
2198 /* Finshed updating the screen, restore lock */
2199 LEAVE_GL();
2200 TRACE("Done all gl drawing\n");
2202 /* Diagnostics */
2203 #ifdef SHOW_FRAME_MAKEUP
2205 static long int primCounter = 0;
2206 /* NOTE: set primCounter to the value reported by drawprim
2207 before you want to to write frame makeup to /tmp */
2208 if (primCounter >= 0) {
2209 WINED3DLOCKED_RECT r;
2210 char buffer[80];
2211 IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY);
2212 sprintf(buffer, "/tmp/backbuffer_%ld.tga", primCounter);
2213 TRACE("Saving screenshot %s\n", buffer);
2214 IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
2215 IWineD3DSurface_UnlockRect(This->renderTarget);
2217 #ifdef SHOW_TEXTURE_MAKEUP
2219 IWineD3DSurface *pSur;
2220 int textureNo;
2221 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
2222 if (This->stateBlock->textures[textureNo] != NULL) {
2223 sprintf(buffer, "/tmp/texture_%p_%ld_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
2224 TRACE("Saving texture %s\n", buffer);
2225 if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
2226 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
2227 IWineD3DSurface_SaveSnapshot(pSur, buffer);
2228 IWineD3DSurface_Release(pSur);
2229 } else {
2230 FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
2235 #endif
2237 TRACE("drawprim #%ld\n", primCounter);
2238 ++primCounter;
2240 #endif