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
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
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 */
42 /* Issues the glBegin call for gl given the primitive type and count */
43 static DWORD primitiveToGl(WINED3DPRIMITIVETYPE PrimitiveType,
47 DWORD NumVertexes = NumPrimitives;
49 switch (PrimitiveType) {
50 case WINED3DPT_POINTLIST:
52 *primType = GL_POINTS;
53 NumVertexes = NumPrimitives;
56 case WINED3DPT_LINELIST:
59 NumVertexes = NumPrimitives * 2;
62 case WINED3DPT_LINESTRIP:
63 TRACE("LINE_STRIP\n");
64 *primType = GL_LINE_STRIP;
65 NumVertexes = NumPrimitives + 1;
68 case WINED3DPT_TRIANGLELIST:
70 *primType = GL_TRIANGLES;
71 NumVertexes = NumPrimitives * 3;
74 case WINED3DPT_TRIANGLESTRIP:
75 TRACE("TRIANGLE_STRIP\n");
76 *primType = GL_TRIANGLE_STRIP;
77 NumVertexes = NumPrimitives + 2;
80 case WINED3DPT_TRIANGLEFAN:
81 TRACE("TRIANGLE_FAN\n");
82 *primType = GL_TRIANGLE_FAN;
83 NumVertexes = NumPrimitives + 2;
87 FIXME("Unhandled primitive\n");
88 *primType = GL_POINTS;
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");
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 const 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
169 glMatrixMode(GL_MODELVIEW);
170 checkGLcall("glMatrixMode(GL_MODELVIEW)");
172 checkGLcall("glLoadIdentity");
174 glMatrixMode(GL_PROJECTION);
175 checkGLcall("glMatrixMode(GL_PROJECTION)");
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);
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");
223 /* Disable GL fog, handle this in software in drawStridedSlow */
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,
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;
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);
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");
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)
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 */
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;
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) {
335 /* Reapply the fog */
336 StateTable[STATE_RENDER(WINED3DRS_FOGENABLE)].apply(STATE_RENDER(WINED3DRS_FOGSTART), This->stateBlock);
341 static BOOL fixed_get_input(
342 BYTE usage, BYTE usage_idx,
343 unsigned int* regnum) {
347 /* Those positions must have the order in the
348 * named part of the strided data */
350 if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 0)
352 else if (usage == D3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
354 else if (usage == D3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
356 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 0)
358 else if (usage == D3DDECLUSAGE_PSIZE && usage_idx == 0)
360 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 0)
362 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 1)
364 else if (usage == D3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
365 *regnum = 7 + usage_idx;
366 else if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 1)
367 *regnum = 7 + WINED3DDP_MAXTEXCOORD;
368 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 1)
369 *regnum = 8 + WINED3DDP_MAXTEXCOORD;
370 else if (usage == D3DDECLUSAGE_TANGENT && usage_idx == 0)
371 *regnum = 9 + WINED3DDP_MAXTEXCOORD;
372 else if (usage == D3DDECLUSAGE_BINORMAL && usage_idx == 0)
373 *regnum = 10 + WINED3DDP_MAXTEXCOORD;
374 else if (usage == D3DDECLUSAGE_TESSFACTOR && usage_idx == 0)
375 *regnum = 11 + WINED3DDP_MAXTEXCOORD;
376 else if (usage == D3DDECLUSAGE_FOG && usage_idx == 0)
377 *regnum = 12 + WINED3DDP_MAXTEXCOORD;
378 else if (usage == D3DDECLUSAGE_DEPTH && usage_idx == 0)
379 *regnum = 13 + WINED3DDP_MAXTEXCOORD;
380 else if (usage == D3DDECLUSAGE_SAMPLE && usage_idx == 0)
381 *regnum = 14 + WINED3DDP_MAXTEXCOORD;
384 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n",
385 debug_d3ddeclusage(usage), usage_idx);
391 void primitiveDeclarationConvertToStridedData(
392 IWineD3DDevice *iface,
393 BOOL useVertexShaderFunction,
394 WineDirect3DVertexStridedData *strided,
395 LONG BaseVertexIndex,
398 /* We need to deal with frequency data!*/
401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
402 IWineD3DVertexDeclarationImpl* vertexDeclaration = NULL;
404 WINED3DVERTEXELEMENT *element;
408 /* Locate the vertex declaration */
409 if (This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration) {
410 TRACE("Using vertex declaration from shader\n");
411 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration;
413 TRACE("Using vertex declaration\n");
414 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
417 /* Translate the declaration into strided data */
418 for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
423 element = vertexDeclaration->pDeclarationWine + i;
424 TRACE("%p Element %p (%d of %d)\n", vertexDeclaration->pDeclarationWine,
425 element, i + 1, vertexDeclaration->declarationWNumElements - 1);
427 if (This->stateBlock->streamSource[element->Stream] == NULL)
430 if (This->stateBlock->streamIsUP) {
431 TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
433 data = (BYTE *)This->stateBlock->streamSource[element->Stream];
434 if(fixup && *fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
436 TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
437 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[element->Stream]);
438 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
440 if( streamVBO != 0) *fixup = TRUE;
441 else if(*fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
444 stride = This->stateBlock->streamStride[element->Stream];
445 data += (BaseVertexIndex * stride);
446 data += element->Offset;
449 TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex);
451 if (useVertexShaderFunction)
452 stride_used = vshader_get_input(This->stateBlock->vertexShader,
453 element->Usage, element->UsageIndex, &idx);
455 stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
458 TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
459 "stream=%u, offset=%u, stride=%u, VBO=%u]\n",
460 useVertexShaderFunction? "shader": "fixed function", idx,
461 debug_d3ddeclusage(element->Usage), element->UsageIndex,
462 element->Stream, element->Offset, stride, streamVBO);
464 strided->u.input[idx].lpData = data;
465 strided->u.input[idx].dwType = element->Type;
466 strided->u.input[idx].dwStride = stride;
467 strided->u.input[idx].VBO = streamVBO;
468 if (!useVertexShaderFunction) {
469 if (element->Usage == D3DDECLUSAGE_POSITION)
470 strided->u.s.position_transformed = FALSE;
471 else if (element->Usage == D3DDECLUSAGE_POSITIONT)
472 strided->u.s.position_transformed = TRUE;
478 void primitiveConvertFVFtoOffset(DWORD thisFVF, DWORD stride, BYTE *data, WineDirect3DVertexStridedData *strided, GLint streamVBO) {
482 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
483 int numCoords[8]; /* Holding place for WINED3DFVF_TEXTUREFORMATx */
485 /* Either 3 or 4 floats depending on the FVF */
486 /* FIXME: Can blending data be in a different stream to the position data?
487 and if so using the fixed pipeline how do we handle it */
488 if (thisFVF & WINED3DFVF_POSITION_MASK) {
489 strided->u.s.position.lpData = data;
490 strided->u.s.position.dwType = WINED3DDECLTYPE_FLOAT3;
491 strided->u.s.position.dwStride = stride;
492 strided->u.s.position.VBO = streamVBO;
493 data += 3 * sizeof(float);
494 if (thisFVF & WINED3DFVF_XYZRHW) {
495 strided->u.s.position.dwType = WINED3DDECLTYPE_FLOAT4;
496 strided->u.s.position_transformed = TRUE;
497 data += sizeof(float);
499 strided->u.s.position_transformed = FALSE;
502 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
503 /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
504 numBlends = 1 + (((thisFVF & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
505 if(thisFVF & WINED3DFVF_LASTBETA_UBYTE4) numBlends--;
507 if ((thisFVF & WINED3DFVF_XYZB5 ) > WINED3DFVF_XYZRHW) {
508 TRACE("Setting blend Weights to %p\n", data);
509 strided->u.s.blendWeights.lpData = data;
510 strided->u.s.blendWeights.dwType = WINED3DDECLTYPE_FLOAT1 + numBlends - 1;
511 strided->u.s.blendWeights.dwStride = stride;
512 strided->u.s.blendWeights.VBO = streamVBO;
513 data += numBlends * sizeof(FLOAT);
515 if (thisFVF & WINED3DFVF_LASTBETA_UBYTE4) {
516 strided->u.s.blendMatrixIndices.lpData = data;
517 strided->u.s.blendMatrixIndices.dwType = WINED3DDECLTYPE_UBYTE4;
518 strided->u.s.blendMatrixIndices.dwStride= stride;
519 strided->u.s.blendMatrixIndices.VBO = streamVBO;
520 data += sizeof(DWORD);
524 /* Normal is always 3 floats */
525 if (thisFVF & WINED3DFVF_NORMAL) {
526 strided->u.s.normal.lpData = data;
527 strided->u.s.normal.dwType = WINED3DDECLTYPE_FLOAT3;
528 strided->u.s.normal.dwStride = stride;
529 strided->u.s.normal.VBO = streamVBO;
530 data += 3 * sizeof(FLOAT);
533 /* Pointsize is a single float */
534 if (thisFVF & WINED3DFVF_PSIZE) {
535 strided->u.s.pSize.lpData = data;
536 strided->u.s.pSize.dwType = WINED3DDECLTYPE_FLOAT1;
537 strided->u.s.pSize.dwStride = stride;
538 strided->u.s.pSize.VBO = streamVBO;
539 data += sizeof(FLOAT);
542 /* Diffuse is 4 unsigned bytes */
543 if (thisFVF & WINED3DFVF_DIFFUSE) {
544 strided->u.s.diffuse.lpData = data;
545 strided->u.s.diffuse.dwType = WINED3DDECLTYPE_SHORT4;
546 strided->u.s.diffuse.dwStride = stride;
547 strided->u.s.diffuse.VBO = streamVBO;
548 data += sizeof(DWORD);
551 /* Specular is 4 unsigned bytes */
552 if (thisFVF & WINED3DFVF_SPECULAR) {
553 strided->u.s.specular.lpData = data;
554 strided->u.s.specular.dwType = WINED3DDECLTYPE_SHORT4;
555 strided->u.s.specular.dwStride = stride;
556 strided->u.s.specular.VBO = streamVBO;
557 data += sizeof(DWORD);
561 numTextures = (thisFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
562 coordIdxInfo = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of WINED3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
564 /* numTextures indicates the number of texture coordinates supplied */
565 /* However, the first set may not be for stage 0 texture - it all */
566 /* depends on WINED3DTSS_TEXCOORDINDEX. */
567 /* The number of bytes for each coordinate set is based off */
568 /* WINED3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
570 /* So, for each supplied texture extract the coords */
571 for (textureNo = 0; textureNo < numTextures; ++textureNo) {
573 strided->u.s.texCoords[textureNo].lpData = data;
574 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT1;
575 strided->u.s.texCoords[textureNo].dwStride = stride;
576 strided->u.s.texCoords[textureNo].VBO = streamVBO;
577 numCoords[textureNo] = coordIdxInfo & 0x03;
580 data += sizeof(float);
581 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT1) {
582 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT2;
583 data += sizeof(float);
584 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT2) {
585 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT3;
586 data += sizeof(float);
587 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT3) {
588 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT4;
589 data += sizeof(float);
593 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
597 void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *strided, LONG BaseVertexIndex, BOOL *fixup) {
599 short LoopThroughTo = 0;
603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
605 /* OK, Now to setup the data locations
606 For the non-created vertex shaders, the VertexShader var holds the real
607 FVF and only stream 0 matters
608 For the created vertex shaders, there is an FVF per stream */
609 if (!This->stateBlock->streamIsUP && !(This->stateBlock->vertexShader == NULL)) {
610 LoopThroughTo = MAX_STREAMS;
615 /* Work through stream by stream */
616 for (nStream=0; nStream<LoopThroughTo; ++nStream) {
617 DWORD stride = This->stateBlock->streamStride[nStream];
621 /* Skip empty streams */
622 if (This->stateBlock->streamSource[nStream] == NULL) continue;
624 /* Retrieve appropriate FVF */
625 if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
626 thisFVF = This->stateBlock->fvf;
627 /* Handle memory passed directly as well as vertex buffers */
628 if (This->stateBlock->streamIsUP) {
630 data = (BYTE *)This->stateBlock->streamSource[nStream];
632 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[nStream]);
633 /* GetMemory binds the VBO */
634 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0, &streamVBO);
636 if(streamVBO != 0 ) *fixup = TRUE;
640 #if 0 /* TODO: Vertex shader support */
641 thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
642 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
645 VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
646 if (thisFVF == 0) continue;
648 /* Now convert the stream into pointers */
650 /* Shuffle to the beginning of the vertexes to render and index from there */
651 data = data + (BaseVertexIndex * stride);
653 primitiveConvertFVFtoOffset(thisFVF, stride, data, strided, streamVBO);
657 #if 0 /* TODO: Software Shaders */
658 /* Draw a single vertex using this information */
659 static void draw_vertex(IWineD3DDevice *iface, /* interface */
660 BOOL isXYZ, float x, float y, float z, float rhw, /* xyzn position*/
661 BOOL isNormal, float nx, float ny, float nz, /* normal */
662 BOOL isDiffuse, float *dRGBA, /* 1st colors */
663 BOOL isSpecular, float *sRGB, /* 2ndry colors */
664 BOOL isPtSize, float ptSize, /* pointSize */
665 WINED3DVECTOR_4 *texcoords, int *numcoords) /* texture info */
667 unsigned int textureNo;
669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
671 /* Diffuse -------------------------------- */
674 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
677 /* Specular Colour ------------------------------------------*/
679 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
680 GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
681 VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
683 VTRACE(("Specular color extensions not supplied\n"));
687 /* Normal -------------------------------- */
689 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
690 glNormal3f(nx, ny, nz);
693 /* Point Size ----------------------------------------------*/
696 /* no such functionality in the fixed function GL pipeline */
697 FIXME("Cannot change ptSize here in openGl\n");
700 /* Texture coords --------------------------- */
701 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
703 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
704 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
708 /* Query tex coords */
709 if (This->stateBlock->textures[textureNo] != NULL) {
711 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
712 if (coordIdx >= MAX_TEXTURES) {
713 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
715 } else if (numcoords[coordIdx] == 0) {
716 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
720 /* Initialize vars */
726 switch (numcoords[coordIdx]) {
727 case 4: q = texcoords[coordIdx].w; /* drop through */
728 case 3: r = texcoords[coordIdx].z; /* drop through */
729 case 2: t = texcoords[coordIdx].y; /* drop through */
730 case 1: s = texcoords[coordIdx].x;
733 switch (numcoords[coordIdx]) { /* Supply the provided texture coords */
734 case WINED3DTTFF_COUNT1:
735 VTRACE(("tex:%d, s=%f\n", textureNo, s));
736 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
737 GLMULTITEXCOORD1F(textureNo, s);
742 case WINED3DTTFF_COUNT2:
743 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
744 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
745 GLMULTITEXCOORD2F(textureNo, s, t);
750 case WINED3DTTFF_COUNT3:
751 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
752 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
753 GLMULTITEXCOORD3F(textureNo, s, t, r);
755 glTexCoord3f(s, t, r);
758 case WINED3DTTFF_COUNT4:
759 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
760 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
761 GLMULTITEXCOORD4F(textureNo, s, t, r, q);
763 glTexCoord4f(s, t, r, q);
767 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
771 } /* End of textures */
773 /* Position -------------------------------- */
775 if (1.0f == rhw || rhw < 0.00001f) {
776 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
779 /* Cannot optimize by dividing through by rhw as rhw is required
780 later for perspective in the GL pipeline for vertex shaders */
781 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
782 glVertex4f(x,y,z,rhw);
786 #endif /* TODO: Software shaders */
788 /* This should match any arrays loaded in loadNumberedArrays. */
789 /* TODO: Only load / unload arrays if we have to. */
790 static void unloadNumberedArrays(IWineD3DDevice *iface) {
791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
793 /* disable any attribs (this is the same for both GLSL and ARB modes) */
797 /* Leave all the attribs disabled */
798 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
799 /* MESA does not support it right not */
800 if (glGetError() != GL_NO_ERROR)
802 for (i = 0; i < maxAttribs; ++i) {
803 GL_EXTCALL(glDisableVertexAttribArrayARB(i));
804 checkGLcall("glDisableVertexAttribArrayARB(reg);");
808 /* TODO: Only load / unload arrays if we have to. */
809 static void loadNumberedArrays(
810 IWineD3DDevice *iface,
811 IWineD3DVertexShader *shader,
812 WineDirect3DVertexStridedData *strided) {
814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
815 GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0;
818 for (i = 0; i < MAX_ATTRIBS; i++) {
820 if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
823 TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
825 if(curVBO != strided->u.input[i].VBO) {
826 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, strided->u.input[i].VBO));
827 checkGLcall("glBindBufferARB");
828 curVBO = strided->u.input[i].VBO;
830 GL_EXTCALL(glVertexAttribPointerARB(i,
831 WINED3D_ATR_SIZE(strided->u.input[i].dwType),
832 WINED3D_ATR_GLTYPE(strided->u.input[i].dwType),
833 WINED3D_ATR_NORMALIZED(strided->u.input[i].dwType),
834 strided->u.input[i].dwStride,
835 strided->u.input[i].lpData));
836 GL_EXTCALL(glEnableVertexAttribArrayARB(i));
840 /* This should match any arrays loaded in loadVertexData. */
841 /* TODO: Only load / unload arrays if we have to. */
842 static void unloadVertexData(IWineD3DDevice *iface) {
843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
846 glDisableClientState(GL_VERTEX_ARRAY);
847 glDisableClientState(GL_NORMAL_ARRAY);
848 glDisableClientState(GL_COLOR_ARRAY);
849 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
850 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
852 for (texture_idx = 0; texture_idx < GL_LIMITS(textures); ++texture_idx) {
853 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
854 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
858 /* TODO: Only load / unload arrays if we have to. */
859 static void loadVertexData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd) {
860 unsigned int textureNo = 0;
861 unsigned int texture_idx = 0;
862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
863 GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0;
865 TRACE("Using fast vertex array code\n");
866 /* Blend Data ---------------------------------------------- */
867 if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) ||
868 (sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) {
871 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
874 glEnableClientState(GL_WEIGHT_ARRAY_ARB);
875 checkGLcall("glEnableClientState(GL_WEIGHT_ARRAY_ARB)");
878 TRACE("Blend %d %p %d\n", WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
879 sd->u.s.blendWeights.lpData, sd->u.s.blendWeights.dwStride);
880 /* FIXME("TODO\n");*/
881 /* Note dwType == float3 or float4 == 2 or 3 */
884 /* with this on, the normals appear to be being modified,
885 but the vertices aren't being translated as they should be
886 Maybe the world matrix aren't being setup properly? */
887 glVertexBlendARB(WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) + 1);
891 VTRACE(("glWeightPointerARB(%d, GL_FLOAT, %d, %p)\n",
892 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) ,
893 sd->u.s.blendWeights.dwStride,
894 sd->u.s.blendWeights.lpData));
896 if(curVBO != sd->u.s.blendWeights.VBO) {
897 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.blendWeights.VBO));
898 checkGLcall("glBindBufferARB");
899 curVBO = sd->u.s.blendWeights.VBO;
902 GL_EXTCALL(glWeightPointerARB)(
903 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
904 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
905 sd->u.s.blendWeights.dwStride,
906 sd->u.s.blendWeights.lpData);
908 checkGLcall("glWeightPointerARB");
910 if((sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO)){
911 static BOOL showfixme = TRUE;
913 FIXME("blendMatrixIndices support\n");
918 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
919 /* FIXME("TODO\n");*/
922 GL_EXTCALL(glVertexWeightPointerEXT)(
923 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
924 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
925 sd->u.s.blendWeights.dwStride,
926 sd->u.s.blendWeights.lpData);
927 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
928 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
929 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
933 /* TODO: support blends in fixupVertices */
934 FIXME("unsupported blending in openGl\n");
937 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
938 #if 0 /* TODO: Vertex blending */
939 glDisable(GL_VERTEX_BLEND_ARB);
941 TRACE("ARB_VERTEX_BLEND\n");
942 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
943 TRACE(" EXT_VERTEX_WEIGHTING\n");
944 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
945 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
950 #if 0 /* FOG ----------------------------------------------*/
951 if (sd->u.s.fog.lpData || sd->u.s.fog.VBO) {
953 if (GL_SUPPORT(EXT_FOG_COORD) {
954 glEnableClientState(GL_FOG_COORDINATE_EXT);
955 (GL_EXTCALL)(FogCoordPointerEXT)(
956 WINED3D_ATR_GLTYPE(sd->u.s.fog.dwType),
957 sd->u.s.fog.dwStride,
960 /* don't bother falling back to 'slow' as we don't support software FOG yet. */
961 /* FIXME: fixme once */
962 TRACE("Hardware support for FOG is not avaiable, FOG disabled.\n");
965 if (GL_SUPPRT(EXT_FOR_COORD) {
966 /* make sure fog is disabled */
967 glDisableClientState(GL_FOG_COORDINATE_EXT);
972 #if 0 /* tangents ----------------------------------------------*/
973 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO ||
974 sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
976 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
977 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO) {
978 glEnable(GL_TANGENT_ARRAY_EXT);
979 (GL_EXTCALL)(TangentPointerEXT)(
980 WINED3D_ATR_GLTYPE(sd->u.s.tangent.dwType),
981 sd->u.s.tangent.dwStride,
982 sd->u.s.tangent.lpData);
984 glDisable(GL_TANGENT_ARRAY_EXT);
986 if (sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
987 glEnable(GL_BINORMAL_ARRAY_EXT);
988 (GL_EXTCALL)(BinormalPointerEXT)(
989 WINED3D_ATR_GLTYPE(sd->u.s.binormal.dwType),
990 sd->u.s.binormal.dwStride,
991 sd->u.s.binormal.lpData);
993 glDisable(GL_BINORMAL_ARRAY_EXT);
997 /* don't bother falling back to 'slow' as we don't support software tangents and binormals yet . */
998 /* FIXME: fixme once */
999 TRACE("Hardware support for tangents and binormals is not avaiable, tangents and binormals disabled.\n");
1002 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
1003 /* make sure fog is disabled */
1004 glDisable(GL_TANGENT_ARRAY_EXT);
1005 glDisable(GL_BINORMAL_ARRAY_EXT);
1010 /* Point Size ----------------------------------------------*/
1011 if (sd->u.s.pSize.lpData || sd->u.s.pSize.VBO) {
1013 /* no such functionality in the fixed function GL pipeline */
1014 TRACE("Cannot change ptSize here in openGl\n");
1015 /* TODO: Implement this function in using shaders if they are available */
1019 /* Vertex Pointers -----------------------------------------*/
1020 if (sd->u.s.position.lpData != NULL || sd->u.s.position.VBO != 0) {
1021 /* Note dwType == float3 or float4 == 2 or 3 */
1022 VTRACE(("glVertexPointer(%d, GL_FLOAT, %d, %p)\n",
1023 sd->u.s.position.dwStride,
1024 sd->u.s.position.dwType + 1,
1025 sd->u.s.position.lpData));
1027 if(curVBO != sd->u.s.position.VBO) {
1028 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.position.VBO));
1029 checkGLcall("glBindBufferARB");
1030 curVBO = sd->u.s.position.VBO;
1033 /* min(WINED3D_ATR_SIZE(position),3) to Disable RHW mode as 'w' coord
1034 handling for rhw mode should not impact screen position whereas in GL it does.
1035 This may result in very slightly distored textures in rhw mode, but
1036 a very minimal different. There's always the other option of
1037 fixing the view matrix to prevent w from having any effect
1039 This only applies to user pointer sources, in VBOs the vertices are fixed up
1041 if(sd->u.s.position.VBO == 0) {
1042 glVertexPointer(3 /* min(WINED3D_ATR_SIZE(sd->u.s.position.dwType),3) */,
1043 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1044 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1047 WINED3D_ATR_SIZE(sd->u.s.position.dwType),
1048 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1049 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1051 checkGLcall("glVertexPointer(...)");
1052 glEnableClientState(GL_VERTEX_ARRAY);
1053 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
1056 glDisableClientState(GL_VERTEX_ARRAY);
1057 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
1060 /* Normals -------------------------------------------------*/
1061 if (sd->u.s.normal.lpData || sd->u.s.normal.VBO) {
1062 /* Note dwType == float3 or float4 == 2 or 3 */
1063 VTRACE(("glNormalPointer(GL_FLOAT, %d, %p)\n",
1064 sd->u.s.normal.dwStride,
1065 sd->u.s.normal.lpData));
1066 if(curVBO != sd->u.s.normal.VBO) {
1067 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.normal.VBO));
1068 checkGLcall("glBindBufferARB");
1069 curVBO = sd->u.s.normal.VBO;
1072 WINED3D_ATR_GLTYPE(sd->u.s.normal.dwType),
1073 sd->u.s.normal.dwStride,
1074 sd->u.s.normal.lpData);
1075 checkGLcall("glNormalPointer(...)");
1076 glEnableClientState(GL_NORMAL_ARRAY);
1077 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
1080 glDisableClientState(GL_NORMAL_ARRAY);
1081 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
1082 glNormal3f(0, 0, 1);
1083 checkGLcall("glNormal3f(0, 0, 1)");
1086 /* Diffuse Colour --------------------------------------------*/
1087 /* WARNING: Data here MUST be in RGBA format, so cannot */
1088 /* go directly into fast mode from app pgm, because */
1089 /* directx requires data in BGRA format. */
1090 /* currently fixupVertices swizels the format, but this isn't */
1091 /* very practical when using VBOS */
1092 /* NOTE: Unless we write a vertex shader to swizel the colour */
1093 /* , or the user doesn't care and wants the speed advantage */
1095 if (sd->u.s.diffuse.lpData || sd->u.s.diffuse.VBO) {
1096 /* Note dwType == float3 or float4 == 2 or 3 */
1097 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %d, %p)\n",
1098 sd->u.s.diffuse.dwStride,
1099 sd->u.s.diffuse.lpData));
1101 if(curVBO != sd->u.s.diffuse.VBO) {
1102 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.diffuse.VBO));
1103 checkGLcall("glBindBufferARB");
1104 curVBO = sd->u.s.diffuse.VBO;
1106 glColorPointer(4, GL_UNSIGNED_BYTE,
1107 sd->u.s.diffuse.dwStride,
1108 sd->u.s.diffuse.lpData);
1109 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
1110 glEnableClientState(GL_COLOR_ARRAY);
1111 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
1114 glDisableClientState(GL_COLOR_ARRAY);
1115 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
1116 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1117 checkGLcall("glColor4f(1, 1, 1, 1)");
1120 /* Specular Colour ------------------------------------------*/
1121 if (sd->u.s.specular.lpData || sd->u.s.specular.VBO) {
1122 TRACE("setting specular colour\n");
1123 /* Note dwType == float3 or float4 == 2 or 3 */
1124 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %d, %p)\n",
1125 sd->u.s.specular.dwStride,
1126 sd->u.s.specular.lpData));
1127 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1128 if(curVBO != sd->u.s.specular.VBO) {
1129 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.specular.VBO));
1130 checkGLcall("glBindBufferARB");
1131 curVBO = sd->u.s.specular.VBO;
1133 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
1134 sd->u.s.specular.dwStride,
1135 sd->u.s.specular.lpData);
1136 vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
1137 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1138 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1141 /* Missing specular color is not critical, no warnings */
1142 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1146 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1148 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1149 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1150 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1151 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
1154 /* Missing specular color is not critical, no warnings */
1155 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1159 /* Texture coords -------------------------------------------*/
1161 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1162 /* The code below uses glClientActiveTexture and glMultiTexCoord* which are all part of the GL_ARB_multitexture extension. */
1163 /* Abort if we don't support the extension. */
1164 if (!GL_SUPPORT(ARB_MULTITEXTURE)) {
1165 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1169 if (/*!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]*/ TRUE) {
1170 /* Select the correct texture stage */
1171 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1174 if (This->stateBlock->textures[textureNo] != NULL) {
1175 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
1177 if (coordIdx >= MAX_TEXTURES) {
1178 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1179 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1180 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1182 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL && sd->u.s.texCoords[coordIdx].VBO == 0) {
1183 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
1184 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1185 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1188 TRACE("Setting up texture %u, idx %d, cordindx %u, data %p\n",
1189 textureNo, texture_idx, coordIdx, sd->u.s.texCoords[coordIdx].lpData);
1190 if(curVBO != sd->u.s.texCoords[coordIdx].VBO) {
1191 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.texCoords[coordIdx].VBO));
1192 checkGLcall("glBindBufferARB");
1193 curVBO = sd->u.s.texCoords[coordIdx].VBO;
1195 /* The coords to supply depend completely on the fvf / vertex shader */
1197 WINED3D_ATR_SIZE(sd->u.s.texCoords[coordIdx].dwType),
1198 WINED3D_ATR_GLTYPE(sd->u.s.texCoords[coordIdx].dwType),
1199 sd->u.s.texCoords[coordIdx].dwStride,
1200 sd->u.s.texCoords[coordIdx].lpData);
1201 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1203 } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1204 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1205 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1207 if (/*!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]*/ TRUE) ++texture_idx;
1209 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1210 for (textureNo = texture_idx; textureNo < GL_LIMITS(textures); ++textureNo) {
1211 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo));
1212 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1213 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1218 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
1219 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1222 if (idxData != NULL /* This crashes sometimes!*/) {
1223 TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
1224 idxData = idxData == (void *)-1 ? NULL : idxData;
1227 glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
1228 glEnableClientState(GL_INDEX_ARRAY);
1230 glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1231 (const char *)idxData+(idxSize * startIdx));
1232 #else /* using drawRangeElements may be faster */
1234 glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
1235 idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1236 (const char *)idxData+(idxSize * startIdx));
1238 checkGLcall("glDrawRangeElements");
1242 /* Note first is now zero as we shuffled along earlier */
1243 TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
1244 glDrawArrays(glPrimitiveType, 0, numberOfVertices);
1245 checkGLcall("glDrawArrays");
1253 * Actually draw using the supplied information.
1254 * Slower GL version which extracts info about each vertex in turn
1257 static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1258 UINT NumVertexes, GLenum glPrimType,
1259 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1261 unsigned int textureNo = 0;
1262 unsigned int texture_idx = 0;
1263 const short *pIdxBufS = NULL;
1264 const long *pIdxBufL = NULL;
1265 LONG SkipnStrides = 0;
1267 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1268 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
1269 float rhw = 0.0f; /* rhw */
1270 float ptSize = 0.0f; /* Point size */
1271 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
1272 DWORD specularColor = 0; /* Specular Color */
1273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1275 TRACE("Using slow vertex array code\n");
1277 /* Variable Initialization */
1278 if (idxData != NULL) {
1279 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1280 else pIdxBufL = (const long *) idxData;
1283 /* Start drawing in GL */
1284 VTRACE(("glBegin(%x)\n", glPrimType));
1285 glBegin(glPrimType);
1287 /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
1288 * Guess it's not necessary(we crash then anyway) and would only eat CPU time
1291 /* For each primitive */
1292 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1294 /* Initialize diffuse color */
1295 diffuseColor = 0xFFFFFFFF;
1297 /* For indexed data, we need to go a few more strides in */
1298 if (idxData != NULL) {
1300 /* Indexed so work out the number of strides to skip */
1302 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1303 SkipnStrides = pIdxBufS[startIdx + vx_index];
1305 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
1306 SkipnStrides = pIdxBufL[startIdx + vx_index];
1310 /* Position Information ------------------ */
1311 if (sd->u.s.position.lpData != NULL) {
1313 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
1318 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
1320 /* RHW follows, only if transformed, ie 4 floats were provided */
1321 if (sd->u.s.position_transformed) {
1322 rhw = ptrToCoords[3];
1323 VTRACE(("rhw=%f\n", rhw));
1327 /* Blending data -------------------------- */
1328 if (sd->u.s.blendWeights.lpData != NULL) {
1329 /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
1330 FIXME("Blending not supported yet\n");
1332 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
1333 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
1337 /* Vertex Normal Data (untransformed only)- */
1338 if (sd->u.s.normal.lpData != NULL) {
1340 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
1341 nx = ptrToCoords[0];
1342 ny = ptrToCoords[1];
1343 nz = ptrToCoords[2];
1344 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
1347 /* Point Size ----------------------------- */
1348 if (sd->u.s.pSize.lpData != NULL) {
1350 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1351 ptSize = ptrToCoords[0];
1352 VTRACE(("ptSize=%f\n", ptSize));
1353 FIXME("No support for ptSize yet\n");
1356 /* Diffuse -------------------------------- */
1357 if (sd->u.s.diffuse.lpData != NULL) {
1359 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1360 diffuseColor = ptrToCoords[0];
1361 VTRACE(("diffuseColor=%lx\n", diffuseColor));
1364 /* Specular -------------------------------- */
1365 if (sd->u.s.specular.lpData != NULL) {
1367 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1368 specularColor = ptrToCoords[0];
1369 VTRACE(("specularColor=%lx\n", specularColor));
1372 /* Texture coords --------------------------- */
1373 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1375 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1376 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1380 /* Query tex coords */
1381 if (This->stateBlock->textures[textureNo] != NULL) {
1383 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
1384 float *ptrToCoords = NULL;
1385 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1388 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1391 } else if (coordIdx < 0) {
1392 FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
1397 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1398 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1399 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1404 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == WINED3DDECLTYPE_FLOAT1 etc */
1406 /* The coords to supply depend completely on the fvf / vertex shader */
1407 switch (coordsToUse) {
1408 case 4: q = ptrToCoords[3]; /* drop through */
1409 case 3: r = ptrToCoords[2]; /* drop through */
1410 case 2: t = ptrToCoords[1]; /* drop through */
1411 case 1: s = ptrToCoords[0];
1414 /* Projected is more 'fun' - Move the last coord to the 'q'
1415 parameter (see comments under WINED3DTSS_TEXTURETRANSFORMFLAGS */
1416 if ((This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) &&
1417 (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED)) {
1419 if (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED) {
1420 switch (coordsToUse) {
1421 case 0: /* Drop Through */
1423 FIXME("WINED3DTTFF_PROJECTED but only zero or one coordinate?\n");
1435 case 4: /* Nop here */
1438 FIXME("Unexpected WINED3DTSS_TEXTURETRANSFORMFLAGS value of %d\n",
1439 This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED);
1444 switch (coordsToUse) { /* Supply the provided texture coords */
1445 case WINED3DTTFF_COUNT1:
1446 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1447 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1448 GL_EXTCALL(glMultiTexCoord1fARB(texture_idx, s));
1453 case WINED3DTTFF_COUNT2:
1454 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1455 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1456 GL_EXTCALL(glMultiTexCoord2fARB(texture_idx, s, t));
1461 case WINED3DTTFF_COUNT3:
1462 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1463 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1464 GL_EXTCALL(glMultiTexCoord3fARB(texture_idx, s, t, r));
1466 glTexCoord3f(s, t, r);
1469 case WINED3DTTFF_COUNT4:
1470 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1471 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1472 GL_EXTCALL(glMultiTexCoord4fARB(texture_idx, s, t, r, q));
1474 glTexCoord4f(s, t, r, q);
1478 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1482 if (/*!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]*/TRUE) ++texture_idx;
1483 } /* End of textures */
1485 /* Diffuse -------------------------------- */
1486 if (sd->u.s.diffuse.lpData != NULL) {
1487 glColor4ub(D3DCOLOR_B_R(diffuseColor),
1488 D3DCOLOR_B_G(diffuseColor),
1489 D3DCOLOR_B_B(diffuseColor),
1490 D3DCOLOR_B_A(diffuseColor));
1491 VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n",
1492 D3DCOLOR_B_R(diffuseColor),
1493 D3DCOLOR_B_G(diffuseColor),
1494 D3DCOLOR_B_B(diffuseColor),
1495 D3DCOLOR_B_A(diffuseColor)));
1497 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1500 /* Specular ------------------------------- */
1501 if (sd->u.s.specular.lpData != NULL) {
1502 /* special case where the fog density is stored in the diffuse alpha channel */
1503 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
1504 (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == WINED3DFOG_NONE || sd->u.s.position.dwType == WINED3DDECLTYPE_FLOAT4 )&&
1505 This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
1506 if(GL_SUPPORT(EXT_FOG_COORD)) {
1507 GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
1509 static BOOL warned = FALSE;
1511 /* TODO: Use the fog table code from old ddraw */
1512 FIXME("Implement fog for transformed vertices in software\n");
1518 VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n",
1519 D3DCOLOR_B_R(specularColor),
1520 D3DCOLOR_B_G(specularColor),
1521 D3DCOLOR_B_B(specularColor)));
1522 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1523 GL_EXTCALL(glSecondaryColor3ubEXT)(
1524 D3DCOLOR_B_R(specularColor),
1525 D3DCOLOR_B_G(specularColor),
1526 D3DCOLOR_B_B(specularColor));
1528 /* Do not worry if specular colour missing and disable request */
1529 VTRACE(("Specular color extensions not supplied\n"));
1532 if (vx_index == 0) {
1533 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1534 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1536 /* Do not worry if specular colour missing and disable request */
1537 VTRACE(("Specular color extensions not supplied\n"));
1542 /* Normal -------------------------------- */
1543 if (sd->u.s.normal.lpData != NULL) {
1544 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1545 glNormal3f(nx, ny, nz);
1547 if (vx_index == 0) glNormal3f(0, 0, 1);
1550 /* Position -------------------------------- */
1551 if (sd->u.s.position.lpData != NULL) {
1552 if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
1553 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1554 glVertex3f(x, y, z);
1556 GLfloat w = 1.0 / rhw;
1557 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1558 glVertex4f(x*w, y*w, z*w, w);
1562 /* For non indexed mode, step onto next parts */
1563 if (idxData == NULL) {
1569 checkGLcall("glEnd and previous calls");
1572 #if 0 /* TODO: Software/Hardware vertex blending support */
1574 * Draw with emulated vertex shaders
1575 * Note: strided data is uninitialized, as we need to pass the vertex
1576 * shader directly as ordering irs yet
1578 void drawStridedSoftwareVS(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1579 int PrimitiveType, ULONG NumPrimitives,
1580 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1582 unsigned int textureNo = 0;
1583 GLenum glPrimType = GL_POINTS;
1584 int NumVertexes = NumPrimitives;
1585 const short *pIdxBufS = NULL;
1586 const long *pIdxBufL = NULL;
1587 LONG SkipnStrides = 0;
1589 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1590 float rhw = 0.0f; /* rhw */
1591 float ptSize = 0.0f; /* Point size */
1592 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1593 int numcoords[8]; /* Number of coords */
1594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1596 IDirect3DVertexShaderImpl* vertexShader = NULL;
1598 TRACE("Using slow software vertex shader code\n");
1600 /* Variable Initialization */
1601 if (idxData != NULL) {
1602 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1603 else pIdxBufL = (const long *) idxData;
1606 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1607 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1609 /* Retrieve the VS information */
1610 vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
1612 /* Start drawing in GL */
1613 VTRACE(("glBegin(%x)\n", glPrimType));
1614 glBegin(glPrimType);
1616 /* For each primitive */
1617 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1619 /* For indexed data, we need to go a few more strides in */
1620 if (idxData != NULL) {
1622 /* Indexed so work out the number of strides to skip */
1624 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1625 SkipnStrides = pIdxBufS[startIdx+vx_index];
1627 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
1628 SkipnStrides = pIdxBufL[startIdx+vx_index];
1632 /* Fill the vertex shader input */
1633 IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1635 /* Initialize the output fields to the same defaults as it would normally have */
1636 memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1637 vertexShader->output.oD[0].x = 1.0;
1638 vertexShader->output.oD[0].y = 1.0;
1639 vertexShader->output.oD[0].z = 1.0;
1640 vertexShader->output.oD[0].w = 1.0;
1642 /* Now execute the vertex shader */
1643 IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1646 TRACE_VECTOR(vertexShader->output.oPos);
1647 TRACE_VECTOR(vertexShader->output.oD[0]);
1648 TRACE_VECTOR(vertexShader->output.oD[1]);
1649 TRACE_VECTOR(vertexShader->output.oT[0]);
1650 TRACE_VECTOR(vertexShader->output.oT[1]);
1651 TRACE_VECTOR(vertexShader->input.V[0]);
1652 TRACE_VECTOR(vertexShader->data->C[0]);
1653 TRACE_VECTOR(vertexShader->data->C[1]);
1654 TRACE_VECTOR(vertexShader->data->C[2]);
1655 TRACE_VECTOR(vertexShader->data->C[3]);
1656 TRACE_VECTOR(vertexShader->data->C[4]);
1657 TRACE_VECTOR(vertexShader->data->C[5]);
1658 TRACE_VECTOR(vertexShader->data->C[6]);
1659 TRACE_VECTOR(vertexShader->data->C[7]);
1662 /* Extract out the output */
1663 /* FIXME: Fog coords? */
1664 x = vertexShader->output.oPos.x;
1665 y = vertexShader->output.oPos.y;
1666 z = vertexShader->output.oPos.z;
1667 rhw = vertexShader->output.oPos.w;
1668 ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1670 /** Update textures coords using vertexShader->output.oT[0->7] */
1671 memset(texcoords, 0x00, sizeof(texcoords));
1672 memset(numcoords, 0x00, sizeof(numcoords));
1673 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1674 if (This->stateBlock->textures[textureNo] != NULL) {
1675 texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1676 texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1677 texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1678 texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1679 if (This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) {
1680 numcoords[textureNo] = This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & ~WINED3DTTFF_PROJECTED;
1682 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1683 case WINED3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1684 case WINED3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1685 default: numcoords[textureNo] = 4;
1689 numcoords[textureNo] = 0;
1693 /* Draw using this information */
1696 TRUE, 0.0f, 0.0f, 1.0f,
1697 TRUE, (float*) &vertexShader->output.oD[0],
1698 TRUE, (float*) &vertexShader->output.oD[1],
1699 FALSE, ptSize, /* FIXME: Change back when supported */
1700 texcoords, numcoords);
1702 /* For non indexed mode, step onto next parts */
1703 if (idxData == NULL) {
1707 } /* for each vertex */
1710 checkGLcall("glEnd and previous calls");
1715 inline static void drawPrimitiveDrawStrided(
1716 IWineD3DDevice *iface,
1717 BOOL useVertexShaderFunction,
1718 BOOL usePixelShaderFunction,
1719 WineDirect3DVertexStridedData *dataLocations,
1720 UINT numberOfvertices,
1721 UINT numberOfIndicies,
1723 const void *idxData,
1729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1730 BOOL useDrawStridedSlow;
1732 int startStride = idxData == NULL ? 0 :
1733 idxData == (void *) -1 ? 0 :
1734 (idxSize == 2 ? *(((const short *) idxData) + StartIdx) : *((const int *) idxData) + StartIdx);
1735 int endStride = startStride;
1736 TRACE("begin Start stride %d, end stride %d, number of indices%d, number of vertices%d\n",
1737 startStride, endStride, numberOfIndicies, numberOfvertices);
1739 /* Generate some fixme's if unsupported functionality is being used */
1740 #define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData
1741 /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */
1742 if (!useVertexShaderFunction && (BUFFER_OR_DATA(blendMatrixIndices) || BUFFER_OR_DATA(blendWeights))) {
1743 FIXME("Blending data is only valid with vertex shaders %p %p\n",dataLocations->u.s.blendWeights.lpData,dataLocations->u.s.blendWeights.lpData);
1745 if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) {
1746 FIXME("Tweening is only valid with vertex shaders\n");
1748 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) {
1749 FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n");
1751 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) {
1752 FIXME("Extended attributes are only valid with vertex shaders\n");
1754 #undef BUFFER_OR_DATA
1756 /* Fixed pipeline, no fixups required - load arrays */
1757 if (!useVertexShaderFunction &&
1758 ((dataLocations->u.s.pSize.lpData == NULL &&
1759 dataLocations->u.s.diffuse.lpData == NULL &&
1760 dataLocations->u.s.specular.lpData == NULL) ||
1763 /* Load the vertex data using named arrays */
1764 TRACE("(%p) Loading vertex data\n", This);
1765 loadVertexData(iface, dataLocations);
1766 useDrawStridedSlow = FALSE;
1768 /* Shader pipeline - load attribute arrays */
1769 } else if(useVertexShaderFunction) {
1771 loadNumberedArrays(iface, This->stateBlock->vertexShader, dataLocations);
1772 useDrawStridedSlow = FALSE;
1774 /* We compile the shader here because we need the vertex declaration
1775 * in order to determine if we need to do any swizzling for D3DCOLOR
1776 * registers. If the shader is already compiled this call will do nothing. */
1777 IWineD3DVertexShader_CompileShader(This->stateBlock->vertexShader);
1778 /* Draw vertex by vertex */
1780 TRACE("Not loading vertex data\n");
1781 useDrawStridedSlow = TRUE;
1784 /* Make any shaders active */
1785 This->shader_backend->shader_select(iface, usePixelShaderFunction, useVertexShaderFunction);
1787 /* Load any global constants/uniforms that may have been set by the application */
1788 This->shader_backend->shader_load_constants(iface, usePixelShaderFunction, useVertexShaderFunction);
1790 /* Draw vertex-by-vertex */
1791 if (useDrawStridedSlow)
1792 drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1794 drawStridedFast(iface, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1796 /* Cleanup any shaders */
1797 This->shader_backend->shader_cleanup(usePixelShaderFunction, useVertexShaderFunction);
1799 /* Unload vertex data */
1800 if (useVertexShaderFunction) {
1801 unloadNumberedArrays(iface);
1803 unloadVertexData(iface);
1807 inline void drawPrimitiveTraceDataLocations(
1808 WineDirect3DVertexStridedData *dataLocations) {
1810 /* Dump out what parts we have supplied */
1811 TRACE("Strided Data:\n");
1812 TRACE_STRIDED((dataLocations), position);
1813 TRACE_STRIDED((dataLocations), blendWeights);
1814 TRACE_STRIDED((dataLocations), blendMatrixIndices);
1815 TRACE_STRIDED((dataLocations), normal);
1816 TRACE_STRIDED((dataLocations), pSize);
1817 TRACE_STRIDED((dataLocations), diffuse);
1818 TRACE_STRIDED((dataLocations), specular);
1819 TRACE_STRIDED((dataLocations), texCoords[0]);
1820 TRACE_STRIDED((dataLocations), texCoords[1]);
1821 TRACE_STRIDED((dataLocations), texCoords[2]);
1822 TRACE_STRIDED((dataLocations), texCoords[3]);
1823 TRACE_STRIDED((dataLocations), texCoords[4]);
1824 TRACE_STRIDED((dataLocations), texCoords[5]);
1825 TRACE_STRIDED((dataLocations), texCoords[6]);
1826 TRACE_STRIDED((dataLocations), texCoords[7]);
1827 TRACE_STRIDED((dataLocations), position2);
1828 TRACE_STRIDED((dataLocations), normal2);
1829 TRACE_STRIDED((dataLocations), tangent);
1830 TRACE_STRIDED((dataLocations), binormal);
1831 TRACE_STRIDED((dataLocations), tessFactor);
1832 TRACE_STRIDED((dataLocations), fog);
1833 TRACE_STRIDED((dataLocations), depth);
1834 TRACE_STRIDED((dataLocations), sample);
1840 static void check_fbo_status(IWineD3DDevice *iface) {
1841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1843 GLenum status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
1845 case GL_FRAMEBUFFER_COMPLETE_EXT: TRACE("FBO complete.\n"); break;
1846 default: TRACE("FBO status %#x.\n", status); break;
1850 static void depth_blt(IWineD3DDevice *iface, GLuint texture) {
1851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1852 GLint old_binding = 0;
1854 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
1856 glDisable(GL_CULL_FACE);
1857 glDisable(GL_BLEND);
1858 glDisable(GL_ALPHA_TEST);
1859 glDisable(GL_STENCIL_TEST);
1860 glEnable(GL_DEPTH_TEST);
1861 glDepthFunc(GL_ALWAYS);
1863 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1864 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
1865 glBindTexture(GL_TEXTURE_2D, texture);
1866 glEnable(GL_TEXTURE_2D);
1868 This->shader_backend->shader_select_depth_blt(iface);
1870 glBegin(GL_TRIANGLE_STRIP);
1871 glVertex2f(-1.0f, -1.0f);
1872 glVertex2f(1.0f, -1.0f);
1873 glVertex2f(-1.0f, 1.0f);
1874 glVertex2f(1.0f, 1.0f);
1877 glBindTexture(GL_TEXTURE_2D, old_binding);
1882 static void depth_copy(IWineD3DDevice *iface) {
1883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1884 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *)This->depthStencilBuffer;
1886 /* Only copy the depth buffer if there is one. */
1887 if (!depth_stencil) return;
1889 /* TODO: Make this work for modes other than FBO */
1890 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
1892 if (This->render_offscreen) {
1893 static GLuint tmp_texture = 0;
1894 GLint old_binding = 0;
1896 TRACE("Copying onscreen depth buffer to offscreen surface\n");
1899 glGenTextures(1, &tmp_texture);
1902 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
1903 * directly on the FBO texture. That's because we need to flip. */
1904 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
1905 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
1906 glBindTexture(GL_TEXTURE_2D, tmp_texture);
1907 glCopyTexImage2D(depth_stencil->glDescription.target,
1908 depth_stencil->glDescription.level,
1909 depth_stencil->glDescription.glFormatInternal,
1912 depth_stencil->currentDesc.Width,
1913 depth_stencil->currentDesc.Height,
1915 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1916 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1917 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
1918 glBindTexture(GL_TEXTURE_2D, old_binding);
1920 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
1921 checkGLcall("glBindFramebuffer()");
1922 depth_blt(iface, tmp_texture);
1923 checkGLcall("depth_blt");
1925 TRACE("Copying offscreen surface to onscreen depth buffer\n");
1927 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
1928 checkGLcall("glBindFramebuffer()");
1929 depth_blt(iface, depth_stencil->glDescription.textureName);
1930 checkGLcall("depth_blt");
1934 /* Routine common to the draw primitive and draw indexed primitive routines */
1935 void drawPrimitive(IWineD3DDevice *iface,
1939 long StartVertexIndex,
1940 UINT numberOfVertices,
1943 const void *idxData,
1945 WineDirect3DVertexStridedData *DrawPrimStrideData) {
1947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1948 BOOL useVertexShaderFunction = FALSE;
1949 BOOL usePixelShaderFunction = FALSE;
1950 WineDirect3DVertexStridedData *dataLocations;
1951 IWineD3DSwapChainImpl *swapchain;
1954 DWORD dirtyState, idx;
1957 BOOL lighting_changed, lighting_original = FALSE;
1959 /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
1960 * here simply check whether a shader was set, or the user disabled shaders */
1961 if (This->vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
1962 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL)
1963 useVertexShaderFunction = TRUE;
1965 if (This->ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
1966 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function)
1967 usePixelShaderFunction = TRUE;
1969 /* Invalidate the back buffer memory so LockRect will read it the next time */
1970 for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
1971 IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
1973 if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer[0])->Flags |= SFLAG_GLDIRTY;
1974 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1978 /* Ok, we will be updating the screen from here onwards so grab the lock */
1981 /* Apply dirty states */
1982 for(i=0; i < This->numDirtyEntries; i++) {
1983 dirtyState = This->dirtyArray[i];
1984 idx = dirtyState >> 5;
1985 shift = dirtyState & 0x1f;
1986 This->isStateDirty[idx] &= ~(1 << shift);
1987 StateTable[dirtyState].apply(dirtyState, This->stateBlock);
1989 This->numDirtyEntries = 0; /* This makes the whole list clean */
1991 if (TRACE_ON(d3d_draw) && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1992 check_fbo_status(iface);
1995 if (This->depth_copy_state == WINED3D_DCS_COPY) {
1998 This->depth_copy_state = WINED3D_DCS_INITIAL;
2000 if(DrawPrimStrideData) {
2002 /* Note: this is a ddraw fixed-function code path */
2004 TRACE("================ Strided Input ===================\n");
2005 dataLocations = DrawPrimStrideData;
2006 drawPrimitiveTraceDataLocations(dataLocations);
2010 else if (This->stateBlock->vertexDecl || This->stateBlock->vertexShader) {
2012 /* Note: This is a fixed function or shader codepath.
2013 * This means it must handle both types of strided data.
2014 * Shaders must go through here to zero the strided data, even if they
2015 * don't set any declaration at all */
2017 TRACE("================ Vertex Declaration ===================\n");
2018 dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2019 if(!dataLocations) {
2020 ERR("Out of memory!\n");
2024 if (This->stateBlock->vertexDecl != NULL ||
2025 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration != NULL)
2027 primitiveDeclarationConvertToStridedData(iface, useVertexShaderFunction,
2028 dataLocations, StartVertexIndex, &fixup);
2032 /* Note: This codepath is not reachable from d3d9 (see fvf->decl9 conversion)
2033 * It is reachable through d3d8, but only for fixed-function.
2034 * It will not work properly for shaders. */
2036 TRACE("================ FVF ===================\n");
2037 dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2038 if(!dataLocations) {
2039 ERR("Out of memory!\n");
2042 primitiveConvertToStridedData(iface, dataLocations, StartVertexIndex, &fixup);
2043 drawPrimitiveTraceDataLocations(dataLocations);
2046 /* Setup transform matrices and sort out */
2047 primitiveInitState(iface, dataLocations, useVertexShaderFunction, &lighting_changed, &lighting_original);
2049 /* Now initialize the materials state */
2050 init_materials(iface, (dataLocations->u.s.diffuse.lpData != NULL || dataLocations->u.s.diffuse.VBO != 0));
2054 /* Ok, Work out which primitive is requested and how many vertexes that
2056 UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
2057 if (numberOfVertices == 0 )
2058 numberOfVertices = calculatedNumberOfindices;
2060 drawPrimitiveDrawStrided(iface, useVertexShaderFunction, usePixelShaderFunction,
2061 dataLocations, numberOfVertices, calculatedNumberOfindices, glPrimType,
2062 idxData, idxSize, minIndex, StartIdx, fixup);
2065 if(!DrawPrimStrideData) HeapFree(GetProcessHeap(), 0, dataLocations);
2067 /* If vertex shaders or no normals, restore previous lighting state */
2068 if (lighting_changed) {
2069 if (lighting_original) glEnable(GL_LIGHTING);
2070 else glDisable(GL_LIGHTING);
2071 TRACE("Restored lighting to original state\n");
2074 /* Finshed updating the screen, restore lock */
2076 TRACE("Done all gl drawing\n");
2079 #ifdef SHOW_FRAME_MAKEUP
2081 static long int primCounter = 0;
2082 /* NOTE: set primCounter to the value reported by drawprim
2083 before you want to to write frame makeup to /tmp */
2084 if (primCounter >= 0) {
2085 WINED3DLOCKED_RECT r;
2087 IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY);
2088 sprintf(buffer, "/tmp/backbuffer_%d.tga", primCounter);
2089 TRACE("Saving screenshot %s\n", buffer);
2090 IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
2091 IWineD3DSurface_UnlockRect(This->renderTarget);
2093 #ifdef SHOW_TEXTURE_MAKEUP
2095 IWineD3DSurface *pSur;
2097 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
2098 if (This->stateBlock->textures[textureNo] != NULL) {
2099 sprintf(buffer, "/tmp/texture_%p_%d_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
2100 TRACE("Saving texture %s\n", buffer);
2101 if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
2102 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
2103 IWineD3DSurface_SaveSnapshot(pSur, buffer);
2104 IWineD3DSurface_Release(pSur);
2106 FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
2113 TRACE("drawprim #%d\n", primCounter);