Fixed header dependencies to be fully compatible with the Windows
[wine/multimedia.git] / dlls / d3d8 / drawprim.c
blob31f9f5378bfc30c8dd8494385150d278f17488e7
1 /*
2 * D3D8 utils
4 * Copyright 2002-2003 Jason Edmeades
5 * Raphael Junqueira
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
24 #include <math.h>
25 #include <stdarg.h>
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "wingdi.h"
33 #include "wine/debug.h"
35 #include "d3d8_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
40 extern IDirect3DVertexShaderImpl* VertexShaders[64];
41 extern IDirect3DVertexShaderDeclarationImpl* VertexShaderDeclarations[64];
42 extern IDirect3DPixelShaderImpl* PixelShaders[64];
44 /* Useful holding place for 4 floats */
45 typedef struct _D3DVECTOR_4 {
46 float x;
47 float y;
48 float z;
49 float w;
50 } D3DVECTOR_4;
52 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
54 /* Returns bits for what is expected from the fixed function pipeline, and whether
55 a vertex shader will be in use. Note the fvf bits returned may be split over
56 multiple streams only if the vertex shader was created, otherwise it all relates
57 to stream 0 */
58 BOOL initializeFVF(LPDIRECT3DDEVICE8 iface,
59 DWORD *FVFbits, /* What to expect in the FVF across all streams */
60 BOOL *useVertexShaderFunction) /* Should we use the vertex shader */
63 ICOM_THIS(IDirect3DDevice8Impl,iface);
65 /* The first thing to work out is if we are using the fixed function pipeline
66 which is either SetVertexShader with < VS_HIGHESTFIXEDFXF - in which case this
67 is the FVF, or with a shader which was created with no function - in which
68 case there is an FVF per declared stream. If this occurs, we also maintain
69 an 'OR' of all the FVF's together so we know what to expect across all the
70 streams */
72 if (This->UpdateStateBlock->VertexShader <= VS_HIGHESTFIXEDFXF) {
74 /* Use this as the FVF */
75 *FVFbits = This->UpdateStateBlock->VertexShader;
76 *useVertexShaderFunction = FALSE;
77 TRACE("FVF explicitally defined, using fixed function pipeline with FVF=%lx\n", *FVFbits);
79 } else {
81 /* Use created shader */
82 IDirect3DVertexShaderImpl* vertex_shader = NULL;
83 vertex_shader = VERTEX_SHADER(This->UpdateStateBlock->VertexShader);
85 if (vertex_shader == NULL) {
87 /* Hmm - User pulled figure out of the air? Unlikely, probably a bug */
88 ERR("trying to use unitialised vertex shader: %lu\n", This->UpdateStateBlock->VertexShader);
89 return TRUE;
91 } else {
93 *FVFbits = This->UpdateStateBlock->vertexShaderDecl->allFVF;
95 if (vertex_shader->function == NULL) {
96 /* No function, so many streams supplied plus FVF definition pre stream */
97 *useVertexShaderFunction = FALSE;
98 TRACE("vertex shader (%lx) declared without program, using fixed function pipeline with FVF=%lx\n",
99 This->StateBlock->VertexShader, *FVFbits);
100 } else {
101 /* Vertex shader needs calling */
102 *useVertexShaderFunction = TRUE;
103 TRACE("vertex shader will be used (unusued FVF=%lx)\n", *FVFbits);
107 return FALSE;
110 /* Issues the glBegin call for gl given the primitive type and count */
111 DWORD primitiveToGl(D3DPRIMITIVETYPE PrimitiveType,
112 DWORD NumPrimitives,
113 GLenum *primType)
115 DWORD NumVertexes = NumPrimitives;
117 switch (PrimitiveType) {
118 case D3DPT_POINTLIST:
119 TRACE("POINTS\n");
120 *primType = GL_POINTS;
121 NumVertexes = NumPrimitives;
122 break;
124 case D3DPT_LINELIST:
125 TRACE("LINES\n");
126 *primType = GL_LINES;
127 NumVertexes = NumPrimitives * 2;
128 break;
130 case D3DPT_LINESTRIP:
131 TRACE("LINE_STRIP\n");
132 *primType = GL_LINE_STRIP;
133 NumVertexes = NumPrimitives + 1;
134 break;
136 case D3DPT_TRIANGLELIST:
137 TRACE("TRIANGLES\n");
138 *primType = GL_TRIANGLES;
139 NumVertexes = NumPrimitives * 3;
140 break;
142 case D3DPT_TRIANGLESTRIP:
143 TRACE("TRIANGLE_STRIP\n");
144 *primType = GL_TRIANGLE_STRIP;
145 NumVertexes = NumPrimitives + 2;
146 break;
148 case D3DPT_TRIANGLEFAN:
149 TRACE("TRIANGLE_FAN\n");
150 *primType = GL_TRIANGLE_FAN;
151 NumVertexes = NumPrimitives + 2;
152 break;
154 default:
155 FIXME("Unhandled primitive\n");
156 *primType = GL_POINTS;
157 break;
159 return NumVertexes;
162 /* Ensure the appropriate material states are set up - only change
163 state if really required */
164 void init_materials(LPDIRECT3DDEVICE8 iface, BOOL isDiffuseSupplied) {
166 BOOL requires_material_reset = FALSE;
167 ICOM_THIS(IDirect3DDevice8Impl,iface);
169 if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == TRUE) {
170 /* If we have not set up the material color tracking, do it now as required */
171 glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
172 checkGLcall("glDisable GL_COLOR_MATERIAL");
173 TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
174 glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
175 checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
176 glEnable(GL_COLOR_MATERIAL);
177 checkGLcall("glEnable GL_COLOR_MATERIAL");
178 This->tracking_color = IS_TRACKING;
179 requires_material_reset = TRUE; /* Restore material settings as will be used */
181 } else if ((This->tracking_color == IS_TRACKING && isDiffuseSupplied == FALSE) ||
182 (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == FALSE)) {
183 /* If we are tracking the current color but one isnt supplied, dont! */
184 glDisable(GL_COLOR_MATERIAL);
185 checkGLcall("glDisable GL_COLOR_MATERIAL");
186 This->tracking_color = NEEDS_TRACKING;
187 requires_material_reset = TRUE; /* Restore material settings as will be used */
189 } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied == TRUE) {
190 /* No need to reset material colors since no change to gl_color_material */
191 requires_material_reset = FALSE;
193 } else if (This->tracking_color == NEEDS_DISABLE) {
194 glDisable(GL_COLOR_MATERIAL);
195 checkGLcall("glDisable GL_COLOR_MATERIAL");
196 This->tracking_color = DISABLED_TRACKING;
197 requires_material_reset = TRUE; /* Restore material settings as will be used */
200 /* Reset the material colors which may have been tracking the color*/
201 if (requires_material_reset == TRUE) {
202 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->StateBlock->material.Ambient);
203 checkGLcall("glMaterialfv");
204 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->StateBlock->material.Diffuse);
205 checkGLcall("glMaterialfv");
206 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->StateBlock->material.Specular);
207 checkGLcall("glMaterialfv");
208 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->StateBlock->material.Emissive);
209 checkGLcall("glMaterialfv");
214 /* Setup views - Transformed & lit if RHW, else untransformed.
215 Only unlit if Normals are supplied
216 Returns: Whether to restore lighting afterwards */
217 BOOL primitiveInitState(LPDIRECT3DDEVICE8 iface, BOOL vtx_transformed, BOOL vtx_lit) {
219 BOOL isLightingOn = FALSE;
220 ICOM_THIS(IDirect3DDevice8Impl,iface);
222 /* If no normals, DISABLE lighting otherwise, dont touch lighing as it is
223 set by the appropriate render state */
224 if (vtx_lit) {
225 isLightingOn = glIsEnabled(GL_LIGHTING);
226 glDisable(GL_LIGHTING);
227 checkGLcall("glDisable(GL_LIGHTING);");
228 TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn);
231 if (vtx_transformed) {
233 /* If the last draw was transformed as well, no need to reapply all the matrixes */
234 if (!This->last_was_rhw) {
236 double X, Y, height, width, minZ, maxZ;
237 This->last_was_rhw = TRUE;
239 /* Transformed already into viewport coordinates, so we do not need transform
240 matrices. Reset all matrices to identity and leave the default matrix in world
241 mode. */
242 glMatrixMode(GL_MODELVIEW);
243 checkGLcall("glMatrixMode");
244 glLoadIdentity();
245 checkGLcall("glLoadIdentity");
247 glMatrixMode(GL_PROJECTION);
248 checkGLcall("glMatrixMode");
249 glLoadIdentity();
250 checkGLcall("glLoadIdentity");
252 /* Set up the viewport to be full viewport */
253 X = This->StateBlock->viewport.X;
254 Y = This->StateBlock->viewport.Y;
255 height = This->StateBlock->viewport.Height;
256 width = This->StateBlock->viewport.Width;
257 minZ = This->StateBlock->viewport.MinZ;
258 maxZ = This->StateBlock->viewport.MaxZ;
259 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
260 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
261 checkGLcall("glOrtho");
263 /* Window Coord 0 is the middle of the first pixel, so translate by half
264 a pixel (See comment above glTranslate below) */
265 glTranslatef(0.5, 0.5, 0);
266 checkGLcall("glTranslatef(0.5, 0.5, 0)");
269 } else {
271 /* Untransformed, so relies on the view and projection matrices */
273 if (This->last_was_rhw || !This->modelview_valid) {
274 /* Only reapply when have to */
275 This->modelview_valid = TRUE;
276 glMatrixMode(GL_MODELVIEW);
277 checkGLcall("glMatrixMode");
279 /* In the general case, the view matrix is the identity matrix */
280 if (This->view_ident) {
281 glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
282 checkGLcall("glLoadMatrixf");
283 } else {
284 glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
285 checkGLcall("glLoadMatrixf");
286 glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
287 checkGLcall("glMultMatrixf");
291 if (This->last_was_rhw || !This->proj_valid) {
292 /* Only reapply when have to */
293 This->proj_valid = TRUE;
294 glMatrixMode(GL_PROJECTION);
295 checkGLcall("glMatrixMode");
297 /* The rule is that the window coordinate 0 does not correspond to the
298 beginning of the first pixel, but the center of the first pixel.
299 As a consequence if you want to correctly draw one line exactly from
300 the left to the right end of the viewport (with all matrices set to
301 be identity), the x coords of both ends of the line would be not
302 -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
303 instead. */
304 glLoadIdentity();
305 glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0);
306 checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
307 glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]);
308 checkGLcall("glLoadMatrixf");
311 This->last_was_rhw = FALSE;
313 return isLightingOn;
316 void primitiveConvertToStridedData(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *strided, LONG BaseVertexIndex) {
318 short LoopThroughTo = 0;
319 short nStream;
320 BOOL canDoViaGLPointers = TRUE;
321 int numBlends;
322 int numTextures;
323 int textureNo;
324 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
325 int numCoords[8]; /* Holding place for D3DFVF_TEXTUREFORMATx */
327 ICOM_THIS(IDirect3DDevice8Impl,iface);
329 /* OK, Now to setup the data locations
330 For the non-created vertex shaders, the VertexShader var holds the real
331 FVF and only stream 0 matters
332 For the created vertex shaders, there is an FVF per stream */
333 if (This->UpdateStateBlock->VertexShader > VS_HIGHESTFIXEDFXF) {
334 LoopThroughTo = MAX_STREAMS;
335 } else {
336 LoopThroughTo = 1;
339 /* Work through stream by stream */
340 for (nStream=0; nStream<LoopThroughTo; nStream++) {
341 DWORD stride = This->StateBlock->stream_stride[nStream];
342 BYTE *data = NULL;
343 DWORD thisFVF = 0;
345 /* Skip empty streams */
346 if (This->StateBlock->stream_source[nStream] == NULL) continue;
348 /* Retrieve appropriate FVF */
349 if (LoopThroughTo == 1) { /* VertexShader is FVF */
350 thisFVF = This->UpdateStateBlock->VertexShader;
351 /* Handle memory passed directly as well as vertex buffers */
352 if (This->StateBlock->streamIsUP == TRUE) {
353 data = (BYTE *)This->StateBlock->stream_source[nStream];
354 } else {
355 data = ((IDirect3DVertexBuffer8Impl *)This->StateBlock->stream_source[nStream])->allocatedMemory;
357 } else {
358 thisFVF = This->StateBlock->vertexShaderDecl->fvf[nStream];
359 data = ((IDirect3DVertexBuffer8Impl *)This->StateBlock->stream_source[nStream])->allocatedMemory;
361 VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
362 if (thisFVF == 0) continue;
364 /* Now convert the stream into pointers */
366 /* Shuffle to the beginning of the vertexes to render and index from there */
367 data = data + (BaseVertexIndex * stride);
369 /* Either 3 or 4 floats depending on the FVF */
370 /* FIXME: Can blending data be in a different stream to the position data?
371 and if so using the fixed pipeline how do we handle it */
372 if (thisFVF & D3DFVF_POSITION_MASK) {
373 strided->u.s.position.lpData = data;
374 strided->u.s.position.dwType = D3DVSDT_FLOAT3;
375 strided->u.s.position.dwStride = stride;
376 data += 3 * sizeof(float);
377 if (thisFVF & D3DFVF_XYZRHW) {
378 strided->u.s.position.dwType = D3DVSDT_FLOAT4;
379 data += sizeof(float);
383 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
384 /** do we have to Check This->UpdateStateBlock->renderstate[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
385 numBlends = ((thisFVF & D3DFVF_POSITION_MASK) >> 1) - 2 +
386 ((FALSE == (thisFVF & D3DFVF_LASTBETA_UBYTE4)) ? 0 : -1); /* WARNING can be < 0 because -2 */
387 if (numBlends > 0) {
388 canDoViaGLPointers = FALSE;
389 strided->u.s.blendWeights.lpData = data;
390 strided->u.s.blendWeights.dwType = D3DVSDT_FLOAT1 + (numBlends - 1);
391 strided->u.s.blendWeights.dwStride = stride;
392 data += numBlends * sizeof(FLOAT);
394 if (thisFVF & D3DFVF_LASTBETA_UBYTE4) {
395 strided->u.s.blendMatrixIndices.lpData = data;
396 strided->u.s.blendMatrixIndices.dwType = D3DVSDT_UBYTE4;
397 strided->u.s.blendMatrixIndices.dwStride= stride;
398 data += sizeof(DWORD);
402 /* Normal is always 3 floats */
403 if (thisFVF & D3DFVF_NORMAL) {
404 strided->u.s.normal.lpData = data;
405 strided->u.s.normal.dwType = D3DVSDT_FLOAT3;
406 strided->u.s.normal.dwStride = stride;
407 data += 3 * sizeof(FLOAT);
410 /* Pointsize is a single float */
411 if (thisFVF & D3DFVF_PSIZE) {
412 strided->u.s.pSize.lpData = data;
413 strided->u.s.pSize.dwType = D3DVSDT_FLOAT1;
414 strided->u.s.pSize.dwStride = stride;
415 data += sizeof(FLOAT);
418 /* Diffuse is 4 unsigned bytes */
419 if (thisFVF & D3DFVF_DIFFUSE) {
420 strided->u.s.diffuse.lpData = data;
421 strided->u.s.diffuse.dwType = D3DVSDT_SHORT4;
422 strided->u.s.diffuse.dwStride = stride;
423 data += sizeof(DWORD);
426 /* Specular is 4 unsigned bytes */
427 if (thisFVF & D3DFVF_SPECULAR) {
428 strided->u.s.specular.lpData = data;
429 strided->u.s.specular.dwType = D3DVSDT_SHORT4;
430 strided->u.s.specular.dwStride = stride;
431 data += sizeof(DWORD);
434 /* Texture coords */
435 numTextures = (thisFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
436 coordIdxInfo = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of D3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
438 /* numTextures indicates the number of texture coordinates supplied */
439 /* However, the first set may not be for stage 0 texture - it all */
440 /* depends on D3DTSS_TEXCOORDINDEX. */
441 /* The number of bytes for each coordinate set is based off */
442 /* D3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
444 /* So, for each supplied texture extract the coords */
445 for (textureNo = 0; textureNo < numTextures; ++textureNo) {
447 strided->u.s.texCoords[textureNo].lpData = data;
448 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT1;
449 strided->u.s.texCoords[textureNo].dwStride = stride;
450 numCoords[textureNo] = coordIdxInfo & 0x03;
452 /* Always one set */
453 data += sizeof(float);
454 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT1) {
455 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT2;
456 data += sizeof(float);
457 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT2) {
458 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT3;
459 data += sizeof(float);
460 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT3) {
461 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT4;
462 data += sizeof(float);
466 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
471 /* Draw a single vertex using this information */
472 void draw_vertex(LPDIRECT3DDEVICE8 iface, /* interface */
473 BOOL isXYZ, float x, float y, float z, float rhw, /* xyzn position*/
474 BOOL isNormal, float nx, float ny, float nz, /* normal */
475 BOOL isDiffuse, float *dRGBA, /* 1st colors */
476 BOOL isSpecular, float *sRGB, /* 2ndry colors */
477 BOOL isPtSize, float ptSize, /* pointSize */
478 D3DVECTOR_4 *texcoords, int *numcoords) /* texture info */
480 int textureNo;
481 float s, t, r, q;
482 ICOM_THIS(IDirect3DDevice8Impl,iface);
484 /* Diffuse -------------------------------- */
485 if (isDiffuse == TRUE) {
486 glColor4fv(dRGBA);
487 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
490 /* Specular Colour ------------------------------------------*/
491 if (isSpecular == TRUE) {
492 #if defined(GL_EXT_secondary_color)
493 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
494 GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
495 VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
497 #endif
500 /* Normal -------------------------------- */
501 if (isNormal == TRUE) {
502 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
503 glNormal3f(nx, ny, nz);
506 /* Point Size ----------------------------------------------*/
507 if (isPtSize == TRUE) {
509 /* no such functionality in the fixed function GL pipeline */
510 FIXME("Cannot change ptSize here in openGl\n");
513 /* Texture coords --------------------------- */
514 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
516 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
517 FIXME("Program using multiple concurrent textures which this opengl implementation doesnt support\n");
518 continue ;
521 /* Query tex coords */
522 if (This->StateBlock->textures[textureNo] != NULL) {
524 int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
525 if (coordIdx > 7) {
526 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
527 continue;
528 } else if (numcoords[coordIdx] == 0) {
529 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
530 continue;
531 } else {
533 /* Initialize vars */
534 s = 0.0f;
535 t = 0.0f;
536 r = 0.0f;
537 q = 0.0f;
539 switch (numcoords[coordIdx]) {
540 case 4: q = texcoords[coordIdx].w; /* drop through */
541 case 3: r = texcoords[coordIdx].z; /* drop through */
542 case 2: t = texcoords[coordIdx].y; /* drop through */
543 case 1: s = texcoords[coordIdx].x;
546 switch (numcoords[coordIdx]) { /* Supply the provided texture coords */
547 case D3DTTFF_COUNT1:
548 VTRACE(("tex:%d, s=%f\n", textureNo, s));
549 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
550 #if defined(GL_VERSION_1_3)
551 glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s);
552 #else
553 glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s);
554 #endif
555 } else {
556 glTexCoord1f(s);
558 break;
559 case D3DTTFF_COUNT2:
560 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
561 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
562 #if defined(GL_VERSION_1_3)
563 glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t);
564 #else
565 glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t);
566 #endif
567 } else {
568 glTexCoord2f(s, t);
570 break;
571 case D3DTTFF_COUNT3:
572 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
573 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
574 #if defined(GL_VERSION_1_3)
575 glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r);
576 #else
577 glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r);
578 #endif
579 } else {
580 glTexCoord3f(s, t, r);
582 break;
583 case D3DTTFF_COUNT4:
584 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
585 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
586 #if defined(GL_VERSION_1_3)
587 glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q);
588 #else
589 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q);
590 #endif
591 } else {
592 glTexCoord4f(s, t, r, q);
594 break;
595 default:
596 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
600 } /* End of textures */
602 /* Position -------------------------------- */
603 if (isXYZ == TRUE) {
604 if (1.0f == rhw || rhw < 0.01f) {
605 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
606 glVertex3f(x, y, z);
607 } else {
608 GLfloat w = 1.0f / rhw;
609 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
610 glVertex4f(x * w, y * w, z * w, 1.0f);
616 * Actually draw using the supplied information.
617 * Faster GL version using pointers to data, harder to debug though
618 * Note does not handle vertex shaders yet
620 void drawStridedFast(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd,
621 int PrimitiveType, ULONG NumPrimitives,
622 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
623 int textureNo = 0;
624 GLenum glPrimType = GL_POINTS;
625 int NumVertexes = NumPrimitives;
626 ICOM_THIS(IDirect3DDevice8Impl,iface);
628 TRACE("Using fast vertex array code\n");
630 /* Vertex Pointers -----------------------------------------*/
631 if (sd->u.s.position.lpData != NULL) {
633 /* Note dwType == float3 or float4 == 2 or 3 */
634 VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n",
635 sd->u.s.position.dwStride,
636 sd->u.s.position.dwType + 1,
637 sd->u.s.position.lpData));
638 glVertexPointer(sd->u.s.position.dwType + 1, GL_FLOAT,
639 sd->u.s.position.dwStride,
640 sd->u.s.position.lpData);
641 checkGLcall("glVertexPointer(...)");
642 glEnableClientState(GL_VERTEX_ARRAY);
643 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
645 } else {
647 glDisableClientState(GL_VERTEX_ARRAY);
648 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
651 /* Blend Data ----------------------------------------------*/
652 if ((sd->u.s.blendWeights.lpData != NULL) ||
653 (sd->u.s.blendMatrixIndices.lpData != NULL)) {
654 /* FIXME: Wont get here as will drop to slow method */
655 FIXME("Blending not supported in fast draw routine\n");
657 #if 0 /* Vertex blend support needs to be added */
658 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
659 /*FIXME("TODO\n");*/
660 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
661 /*FIXME("TODO\n");*/
663 GLExtCall(glVertexWeightPointerEXT)(numBlends, GL_FLOAT, skip, curPos);
664 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
665 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
666 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
668 } else {
669 FIXME("unsupported blending in openGl\n");
671 } else {
672 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
673 FIXME("TODO\n");
674 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
675 FIXME("TODO\n");
677 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
678 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
681 #endif
684 /* Normals -------------------------------------------------*/
685 if (sd->u.s.normal.lpData != NULL) {
687 /* Note dwType == float3 or float4 == 2 or 3 */
688 VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n",
689 sd->u.s.normal.dwStride,
690 sd->u.s.normal.lpData));
691 glNormalPointer(GL_FLOAT,
692 sd->u.s.normal.dwStride,
693 sd->u.s.normal.lpData);
694 checkGLcall("glNormalPointer(...)");
695 glEnableClientState(GL_NORMAL_ARRAY);
696 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
698 } else {
700 glDisableClientState(GL_NORMAL_ARRAY);
701 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
702 glNormal3f(0, 0, 1);
703 checkGLcall("glNormal3f(0, 0, 1)");
706 /* Point Size ----------------------------------------------*/
707 if (sd->u.s.pSize.lpData != NULL) {
709 /* no such functionality in the fixed function GL pipeline */
710 /* FIXME: Wont get here as will drop to slow method */
711 FIXME("Cannot change ptSize here in openGl\n");
714 /* Diffuse Colour ------------------------------------------*/
715 /* WARNING: Data here MUST be in RGBA format, so cannot */
716 /* go directly into fast mode from app pgm, because */
717 /* directx requires data in BGRA format. */
718 if (sd->u.s.diffuse.lpData != NULL) {
720 /* Note dwType == float3 or float4 == 2 or 3 */
721 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
722 sd->u.s.diffuse.dwStride,
723 sd->u.s.diffuse.lpData));
724 glColorPointer(4, GL_UNSIGNED_BYTE,
725 sd->u.s.diffuse.dwStride,
726 sd->u.s.diffuse.lpData);
727 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
728 glEnableClientState(GL_COLOR_ARRAY);
729 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
731 } else {
733 glDisableClientState(GL_COLOR_ARRAY);
734 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
735 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
736 checkGLcall("glColor4f(1, 1, 1, 1)");
739 /* Specular Colour ------------------------------------------*/
740 if (sd->u.s.specular.lpData != NULL) {
742 /* Note dwType == float3 or float4 == 2 or 3 */
743 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
744 sd->u.s.specular.dwStride,
745 sd->u.s.specular.lpData));
747 #if defined(GL_VERSION_1_4)
748 glSecondaryColorPointer(4, GL_UNSIGNED_BYTE,
749 sd->u.s.specular.dwStride,
750 sd->u.s.specular.lpData);
751 vcheckGLcall("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, ...)");
752 glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
753 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY)");
754 #elif defined(GL_EXT_secondary_color)
755 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
756 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
757 sd->u.s.specular.dwStride,
758 sd->u.s.specular.lpData);
759 checkGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
760 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
761 checkGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
763 #else
764 /* Missing specular color is not critical, no warnings */
765 VTRACE(("Specular colour is not supported in this GL implementation\n"));
766 #endif
768 } else {
770 #if defined(GL_VERSION_1_4)
771 glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
772 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY)");
773 glSecondaryColor3f(0, 0, 0);
774 checkGLcall("glSecondaryColor3f(0, 0, 0)");
775 #elif defined(GL_EXT_secondary_color)
776 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
777 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
778 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
779 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
780 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
782 #else
783 /* Do not worry if specular colour missing and disable request */
784 #endif
787 /* Texture coords -------------------------------------------*/
788 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
790 /* Select the correct texture stage */
791 #if defined(GL_VERSION_1_3)
792 glClientActiveTexture(GL_TEXTURE0 + textureNo);
793 #else
794 glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo);
795 #endif
797 /* Query tex coords */
798 if (This->StateBlock->textures[textureNo] != NULL) {
799 int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
801 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
802 FIXME("Program using multiple concurrent textures which this opengl implementation doesnt support\n");
803 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
804 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
805 continue;
808 if (coordIdx > 7) {
809 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
810 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
811 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
812 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
813 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
814 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
815 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
816 } else {
818 /* The coords to supply depend completely on the fvf / vertex shader */
819 GLint size;
820 GLenum type;
822 switch (sd->u.s.texCoords[coordIdx].dwType) {
823 case D3DVSDT_FLOAT1: size = 1, type = GL_FLOAT; break;
824 case D3DVSDT_FLOAT2: size = 2, type = GL_FLOAT; break;
825 case D3DVSDT_FLOAT3: size = 3, type = GL_FLOAT; break;
826 case D3DVSDT_FLOAT4: size = 4, type = GL_FLOAT; break;
827 case D3DVSDT_SHORT2: size = 2, type = GL_SHORT; break;
828 case D3DVSDT_SHORT4: size = 4, type = GL_SHORT; break;
829 case D3DVSDT_UBYTE4: size = 4, type = GL_UNSIGNED_BYTE; break;
830 default: FIXME("Unrecognized data type %ld\n", sd->u.s.texCoords[coordIdx].dwType);
831 size = 4; type = GL_UNSIGNED_BYTE;
834 glTexCoordPointer(size, type, sd->u.s.texCoords[coordIdx].dwStride, sd->u.s.texCoords[coordIdx].lpData);
835 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
837 } else {
838 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
839 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
843 /* Ok, Work out which primitive is requested and how many vertexes that
844 will be */
845 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
847 /* Finally do the drawing */
848 if (idxData != NULL) {
850 TRACE("glElements(%x, %d, %ld, ...)\n", glPrimType, NumVertexes, minIndex);
851 #if 1 /* FIXME: Want to use DrawRangeElements, but wrong calculation! */
852 glDrawElements(glPrimType, NumVertexes, idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
853 (char *)idxData+(idxSize * startIdx));
854 #else
855 glDrawRangeElements(glPrimType, minIndex, minIndex+NumVertexes-1, NumVertexes,
856 idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
857 (char *)idxData+(idxSize * startIdx));
858 #endif
859 checkGLcall("glDrawRangeElements");
861 } else {
863 /* Note first is now zero as we shuffled along earlier */
864 TRACE("glDrawArrays(%x, 0, %d)\n", glPrimType, NumVertexes);
865 glDrawArrays(glPrimType, 0, NumVertexes);
866 checkGLcall("glDrawArrays");
872 * Actually draw using the supplied information.
873 * Slower GL version which extracts info about each vertex in turn
875 void drawStridedSlow(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd,
876 int PrimitiveType, ULONG NumPrimitives,
877 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
879 int textureNo = 0;
880 GLenum glPrimType = GL_POINTS;
881 int NumVertexes = NumPrimitives;
882 const short *pIdxBufS = NULL;
883 const long *pIdxBufL = NULL;
884 LONG SkipnStrides = 0;
885 LONG vx_index;
886 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
887 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
888 float rhw = 0.0f; /* rhw */
889 float ptSize = 0.0f; /* Point size */
890 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
891 DWORD specularColor = 0; /* Specular Color */
892 ICOM_THIS(IDirect3DDevice8Impl,iface);
894 TRACE("Using slow vertex array code\n");
896 /* Variable Initialization */
897 if (idxData != NULL) {
898 if (idxSize == 2) pIdxBufS = (short *) idxData;
899 else pIdxBufL = (long *) idxData;
902 /* Ok, Work out which primitive is requested and how many vertexes that will be */
903 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
905 /* Start drawing in GL */
906 VTRACE(("glBegin(%x)\n", glPrimType));
907 glBegin(glPrimType);
909 /* For each primitive */
910 for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
912 /* Initialize diffuse color */
913 diffuseColor = 0xFFFFFFFF;
915 /* For indexed data, we need to go a few more strides in */
916 if (idxData != NULL) {
918 /* Indexed so work out the number of strides to skip */
919 if (idxSize == 2) {
920 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
921 SkipnStrides = pIdxBufS[startIdx+vx_index];
922 } else {
923 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
924 SkipnStrides = pIdxBufL[startIdx+vx_index];
928 /* Position Information ------------------ */
929 if (sd->u.s.position.lpData != NULL) {
931 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
932 x = ptrToCoords[0];
933 y = ptrToCoords[1];
934 z = ptrToCoords[2];
935 rhw = 1.0;
936 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
938 /* RHW follows, only if transformed, ie 4 floats were provided */
939 if (sd->u.s.position.dwType == D3DVSDT_FLOAT4) {
940 rhw = ptrToCoords[3];
941 VTRACE(("rhw=%f\n", rhw));
945 /* Blending data -------------------------- */
946 if (sd->u.s.blendWeights.lpData != NULL) {
947 /*float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride));*/
948 FIXME("Blending not supported yet\n");
950 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
951 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
955 /* Vertex Normal Data (untransformed only)- */
956 if (sd->u.s.normal.lpData != NULL) {
958 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
959 nx = ptrToCoords[0];
960 ny = ptrToCoords[1];
961 nz = ptrToCoords[2];
962 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
965 /* Point Size ----------------------------- */
966 if (sd->u.s.pSize.lpData != NULL) {
968 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
969 ptSize = ptrToCoords[0];
970 VTRACE(("ptSize=%f\n", ptSize));
971 FIXME("No support for ptSize yet\n");
974 /* Diffuse -------------------------------- */
975 if (sd->u.s.diffuse.lpData != NULL) {
977 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
978 diffuseColor = ptrToCoords[0];
979 VTRACE(("diffuseColor=%lx\n", diffuseColor));
982 /* Specular -------------------------------- */
983 if (sd->u.s.specular.lpData != NULL) {
985 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
986 specularColor = ptrToCoords[0];
987 VTRACE(("specularColor=%lx\n", specularColor));
990 /* Texture coords --------------------------- */
991 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
993 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
994 FIXME("Program using multiple concurrent textures which this opengl implementation doesnt support\n");
995 continue ;
998 /* Query tex coords */
999 if (This->StateBlock->textures[textureNo] != NULL) {
1001 int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
1002 float *ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1003 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1005 if (coordIdx > 7) {
1006 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1007 continue;
1008 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1009 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1010 continue;
1011 } else {
1013 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DVSDT_FLOAT1 etc */
1015 /* The coords to supply depend completely on the fvf / vertex shader */
1016 switch (coordsToUse) {
1017 case 4: q = ptrToCoords[3]; /* drop through */
1018 case 3: r = ptrToCoords[2]; /* drop through */
1019 case 2: t = ptrToCoords[1]; /* drop through */
1020 case 1: s = ptrToCoords[0];
1023 /* Projected is more 'fun' - Move the last coord to the 'q'
1024 parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1025 if ((This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1026 (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1028 if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1029 switch (coordsToUse) {
1030 case 0: /* Drop Through */
1031 case 1:
1032 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1033 break;
1034 case 2:
1035 q = t;
1036 t = 0.0;
1037 coordsToUse = 4;
1038 break;
1039 case 3:
1040 q = r;
1041 r = 0.0;
1042 coordsToUse = 4;
1043 break;
1044 case 4: /* Nop here */
1045 break;
1046 default:
1047 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n",
1048 This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1053 switch (coordsToUse) { /* Supply the provided texture coords */
1054 case D3DTTFF_COUNT1:
1055 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1056 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1057 #if defined(GL_VERSION_1_3)
1058 glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s);
1059 #else
1060 glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s);
1061 #endif
1062 } else {
1063 glTexCoord1f(s);
1065 break;
1066 case D3DTTFF_COUNT2:
1067 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1068 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1069 #if defined(GL_VERSION_1_3)
1070 glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t);
1071 #else
1072 glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t);
1073 #endif
1074 } else {
1075 glTexCoord2f(s, t);
1077 break;
1078 case D3DTTFF_COUNT3:
1079 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1080 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1081 #if defined(GL_VERSION_1_3)
1082 glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r);
1083 #else
1084 glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r);
1085 #endif
1086 } else {
1087 glTexCoord3f(s, t, r);
1089 break;
1090 case D3DTTFF_COUNT4:
1091 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1092 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1093 #if defined(GL_VERSION_1_3)
1094 glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q);
1095 #else
1096 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q);
1097 #endif
1098 } else {
1099 glTexCoord4f(s, t, r, q);
1101 break;
1102 default:
1103 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1107 } /* End of textures */
1109 /* Diffuse -------------------------------- */
1110 if (sd->u.s.diffuse.lpData != NULL) {
1111 glColor4ub((diffuseColor >> 16) & 0xFF,
1112 (diffuseColor >> 8) & 0xFF,
1113 (diffuseColor >> 0) & 0xFF,
1114 (diffuseColor >> 24) & 0xFF);
1115 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n",
1116 ((diffuseColor >> 16) & 0xFF) / 255.0f,
1117 ((diffuseColor >> 8) & 0xFF) / 255.0f,
1118 ((diffuseColor >> 0) & 0xFF) / 255.0f,
1119 ((diffuseColor >> 24) & 0xFF) / 255.0f));
1120 } else {
1121 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1124 #if 1
1125 /* Specular ------------------------------- */
1126 if (sd->u.s.diffuse.lpData != NULL) {
1127 VTRACE(("glSecondaryColor4ub: r,g,b=%f,%f,%f\n",
1128 ((specularColor >> 16) & 0xFF) / 255.0f,
1129 ((specularColor >> 8) & 0xFF) / 255.0f,
1130 ((specularColor >> 0) & 0xFF) / 255.0f));
1131 #if defined(GL_VERSION_1_4)
1132 glSecondaryColor3ub((specularColor >> 16) & 0xFF,
1133 (specularColor >> 8) & 0xFF,
1134 (specularColor >> 0) & 0xFF);
1135 #elif defined(GL_EXT_secondary_color)
1136 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1137 GL_EXTCALL(glSecondaryColor3ubEXT)(
1138 (specularColor >> 16) & 0xFF,
1139 (specularColor >> 8) & 0xFF,
1140 (specularColor >> 0) & 0xFF);
1142 #else
1143 /* Do not worry if specular colour missing and disable request */
1144 VTRACE(("Specular color extensions not supplied\n"));
1145 #endif
1146 } else {
1147 #if defined(GL_VERSION_1_4)
1148 if (vx_index == 0) glSecondaryColor3f(0, 0, 0);
1149 #elif defined(GL_EXT_secondary_color)
1150 if (vx_index == 0 && GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1151 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1153 #else
1154 /* Do not worry if specular colour missing and disable request */
1155 #endif
1157 #endif
1159 /* Normal -------------------------------- */
1160 if (sd->u.s.normal.lpData != NULL) {
1161 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1162 glNormal3f(nx, ny, nz);
1163 } else {
1164 if (vx_index == 0) glNormal3f(0, 0, 1);
1167 /* Position -------------------------------- */
1168 if (sd->u.s.position.lpData != NULL) {
1169 if (1.0f == rhw || rhw < 0.01f) {
1170 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1171 glVertex3f(x, y, z);
1172 } else {
1173 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1174 glVertex4f(x / rhw, y / rhw, z / rhw, 1.0f / rhw);
1178 /* For non indexed mode, step onto next parts */
1179 if (idxData == NULL) {
1180 SkipnStrides += 1;
1184 glEnd();
1185 checkGLcall("glEnd and previous calls");
1189 * Draw with emulated vertex shaders
1190 * Note: strided data is uninitialized, as we need to pass the vertex
1191 * shader directly as ordering irs yet
1193 void drawStridedSoftwareVS(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd,
1194 int PrimitiveType, ULONG NumPrimitives,
1195 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1197 int textureNo = 0;
1198 GLenum glPrimType = GL_POINTS;
1199 int NumVertexes = NumPrimitives;
1200 const short *pIdxBufS = NULL;
1201 const long *pIdxBufL = NULL;
1202 LONG SkipnStrides = 0;
1203 LONG vx_index;
1204 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1205 float rhw = 0.0f; /* rhw */
1206 float ptSize = 0.0f; /* Point size */
1207 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1208 int numcoords[8]; /* Number of coords */
1209 ICOM_THIS(IDirect3DDevice8Impl,iface);
1211 IDirect3DVertexShaderImpl* vertex_shader = NULL;
1213 TRACE("Using slow software vertex shader code\n");
1215 /* Variable Initialization */
1216 if (idxData != NULL) {
1217 if (idxSize == 2) pIdxBufS = (short *) idxData;
1218 else pIdxBufL = (long *) idxData;
1221 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1222 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1224 /* Retrieve the VS information */
1225 vertex_shader = VERTEX_SHADER(This->StateBlock->VertexShader);
1227 /* Start drawing in GL */
1228 VTRACE(("glBegin(%x)\n", glPrimType));
1229 glBegin(glPrimType);
1231 /* For each primitive */
1232 for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
1234 /* For indexed data, we need to go a few more strides in */
1235 if (idxData != NULL) {
1237 /* Indexed so work out the number of strides to skip */
1238 if (idxSize == 2) {
1239 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1240 SkipnStrides = pIdxBufS[startIdx+vx_index];
1241 } else {
1242 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1243 SkipnStrides = pIdxBufL[startIdx+vx_index];
1247 /* Fill the vertex shader input */
1248 IDirect3DDeviceImpl_FillVertexShaderInput(This, vertex_shader, SkipnStrides);
1250 /* Now execute the vertex shader */
1251 memset(&vertex_shader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1252 IDirect3DVertexShaderImpl_ExecuteSW(vertex_shader, &vertex_shader->input, &vertex_shader->output);
1255 TRACE_VECTOR(vertex_shader->output.oPos);
1256 TRACE_VECTOR(vertex_shader->output.oD[0]);
1257 TRACE_VECTOR(vertex_shader->output.oD[1]);
1258 TRACE_VECTOR(vertex_shader->output.oT[0]);
1259 TRACE_VECTOR(vertex_shader->output.oT[1]);
1260 TRACE_VECTOR(vertex_shader->input.V[0]);
1261 TRACE_VECTOR(vertex_shader->data->C[0]);
1262 TRACE_VECTOR(vertex_shader->data->C[1]);
1263 TRACE_VECTOR(vertex_shader->data->C[2]);
1264 TRACE_VECTOR(vertex_shader->data->C[3]);
1265 TRACE_VECTOR(vertex_shader->data->C[4]);
1266 TRACE_VECTOR(vertex_shader->data->C[5]);
1267 TRACE_VECTOR(vertex_shader->data->C[6]);
1268 TRACE_VECTOR(vertex_shader->data->C[7]);
1271 /* Extract out the output */
1272 /*FIXME: Fog coords? */
1273 x = vertex_shader->output.oPos.x;
1274 y = vertex_shader->output.oPos.y;
1275 z = vertex_shader->output.oPos.z;
1276 rhw = vertex_shader->output.oPos.w;
1277 ptSize = vertex_shader->output.oPts.x; /* Fixme - Is this right? */
1279 /** Update textures coords using vertex_shader->output.oT[0->7] */
1280 memset(texcoords, 0x00, sizeof(texcoords));
1281 memset(numcoords, 0x00, sizeof(numcoords));
1282 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1283 if (This->StateBlock->textures[textureNo] != NULL) {
1284 texcoords[textureNo].x = vertex_shader->output.oT[textureNo].x;
1285 texcoords[textureNo].y = vertex_shader->output.oT[textureNo].y;
1286 texcoords[textureNo].z = vertex_shader->output.oT[textureNo].z;
1287 texcoords[textureNo].w = vertex_shader->output.oT[textureNo].w;
1288 if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1289 numcoords[textureNo] = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1290 } else {
1291 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->StateBlock->textures[textureNo])) {
1292 case D3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1293 case D3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1294 default: numcoords[textureNo] = 4;
1297 } else {
1298 numcoords[textureNo] = 0;
1302 /* Draw using this information */
1303 draw_vertex(iface,
1304 TRUE, x, y, z, rhw,
1305 FALSE, 0.0f, 0.0f, 0.0f,
1306 TRUE, (float*) &vertex_shader->output.oD[0],
1307 TRUE, (float*) &vertex_shader->output.oD[1],
1308 FALSE, ptSize, /* FIXME: Change back when supported */
1309 texcoords, numcoords);
1311 /* For non indexed mode, step onto next parts */
1312 if (idxData == NULL) {
1313 SkipnStrides += 1;
1316 } /* for each vertex */
1318 glEnd();
1319 checkGLcall("glEnd and previous calls");
1322 /* Routine common to the draw primitive and draw indexed primitive routines */
1323 void drawPrimitive(LPDIRECT3DDEVICE8 iface,
1324 int PrimitiveType, long NumPrimitives,
1326 /* for Indexed: */
1327 long StartVertexIndex,
1328 long StartIdx,
1329 short idxSize,
1330 const void *idxData,
1331 int minIndex) {
1333 BOOL rc = FALSE;
1334 DWORD fvf = 0;
1335 IDirect3DVertexShaderImpl *vertex_shader = NULL;
1336 BOOL useVertexShaderFunction = FALSE;
1337 BOOL isLightingOn = FALSE;
1338 Direct3DVertexStridedData dataLocations;
1339 ICOM_THIS(IDirect3DDevice8Impl,iface);
1342 /* Work out what the FVF should look like */
1343 rc = initializeFVF(iface, &fvf, &useVertexShaderFunction);
1344 if (rc) return;
1346 /* If we will be using a vertex shader, do some initialization for it */
1347 if (useVertexShaderFunction == TRUE) {
1348 vertex_shader = VERTEX_SHADER(This->UpdateStateBlock->VertexShader);
1349 memset(&vertex_shader->input, 0, sizeof(VSHADERINPUTDATA8));
1351 /** init Constants */
1352 if (TRUE == This->UpdateStateBlock->Changed.vertexShaderConstant) {
1353 TRACE_(d3d_shader)("vertex shader init Constant\n");
1354 IDirect3DVertexShaderImpl_SetConstantF(vertex_shader, 0, (CONST FLOAT*) &This->UpdateStateBlock->vertexShaderConstant[0], 96);
1358 /* Ok, we will be updating the screen from here onwards so grab the lock */
1359 ENTER_GL();
1361 /* Setup transform matrices and sort out */
1362 isLightingOn = primitiveInitState(iface,
1363 fvf & D3DFVF_XYZRHW,
1364 !(fvf & D3DFVF_NORMAL));
1366 /* Initialize all values to null */
1367 if (useVertexShaderFunction == FALSE) {
1368 memset(&dataLocations, 0x00, sizeof(dataLocations));
1370 /* Convert to strided data */
1371 primitiveConvertToStridedData(iface, &dataLocations, StartVertexIndex);
1373 /* Dump out what parts we have supplied */
1374 TRACE("Strided Data (from FVF/VS): %lx\n", fvf);
1375 TRACE_STRIDED((&dataLocations), position);
1376 TRACE_STRIDED((&dataLocations), blendWeights);
1377 TRACE_STRIDED((&dataLocations), blendMatrixIndices);
1378 TRACE_STRIDED((&dataLocations), normal);
1379 TRACE_STRIDED((&dataLocations), pSize);
1380 TRACE_STRIDED((&dataLocations), diffuse);
1381 TRACE_STRIDED((&dataLocations), specular);
1382 TRACE_STRIDED((&dataLocations), texCoords[0]);
1383 TRACE_STRIDED((&dataLocations), texCoords[1]);
1384 TRACE_STRIDED((&dataLocations), texCoords[2]);
1385 TRACE_STRIDED((&dataLocations), texCoords[3]);
1386 TRACE_STRIDED((&dataLocations), texCoords[4]);
1387 TRACE_STRIDED((&dataLocations), texCoords[5]);
1388 TRACE_STRIDED((&dataLocations), texCoords[6]);
1389 TRACE_STRIDED((&dataLocations), texCoords[7]);
1392 /* Now initialize the materials state */
1393 init_materials(iface, (dataLocations.u.s.diffuse.lpData != NULL));
1395 /* Now draw the graphics to the screen */
1396 if (useVertexShaderFunction == TRUE) {
1398 /* Ideally, we should have software FV and hardware VS, possibly
1399 depending on the device type? */
1401 /* We will have to use the very, very slow emulation layer */
1402 drawStridedSoftwareVS(iface, &dataLocations, PrimitiveType, NumPrimitives,
1403 idxData, idxSize, minIndex, StartIdx);
1405 } else if ((dataLocations.u.s.pSize.lpData != NULL) ||
1406 (dataLocations.u.s.diffuse.lpData != NULL) ||
1407 (dataLocations.u.s.blendWeights.lpData != NULL)) {
1409 /* Fixme, Ideally, only use the per-vertex code for software HAL
1410 but until opengl supports all the functions returned to setup
1411 vertex arrays, we need to drop down to the slow mechanism for
1412 certain functions */
1414 /* We will have to use the slow version of GL per vertex setup */
1415 drawStridedSlow(iface, &dataLocations, PrimitiveType, NumPrimitives,
1416 idxData, idxSize, minIndex, StartIdx);
1418 } else {
1420 /* We can use the fast version of GL pointers */
1421 drawStridedFast(iface, &dataLocations, PrimitiveType, NumPrimitives,
1422 idxData, idxSize, minIndex, StartIdx);
1425 /* If no normals, restore previous lighting state */
1426 if (!(fvf & D3DFVF_NORMAL)) {
1427 if (isLightingOn) glEnable(GL_LIGHTING);
1428 else glDisable(GL_LIGHTING);
1429 TRACE("Restored lighting to original state\n");
1432 /* Finshed updating the screen, restore lock */
1433 LEAVE_GL();
1434 TRACE("Done all gl drawing\n");
1436 /* Diagnostics */
1437 #if defined(SHOW_FRAME_MAKEUP)
1439 if (isDumpingFrames == TRUE) {
1440 D3DLOCKED_RECT r;
1441 char buffer[80];
1442 IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) This->backBuffer, &r, NULL, D3DLOCK_READONLY);
1443 sprintf(buffer, "/tmp/backbuffer_%ld.ppm", primCounter);
1444 TRACE("Saving screenshot %s\n", buffer);
1445 IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This->backBuffer, buffer);
1446 IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) This->backBuffer);
1448 #if defined(SHOW_TEXTURE_MAKEUP)
1450 LPDIRECT3DSURFACE8 pSur;
1451 int textureNo;
1452 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1453 if (This->StateBlock->textures[textureNo] != NULL) {
1454 sprintf(buffer, "/tmp/texture_%ld_%d.ppm", primCounter, textureNo);
1455 TRACE("Saving texture %s\n", buffer);
1456 IDirect3DTexture8Impl_GetSurfaceLevel((LPDIRECT3DTEXTURE8) This->StateBlock->textures[textureNo], 0, &pSur);
1457 IDirect3DSurface8Impl_SaveSnapshot(pSur, buffer);
1461 #endif
1462 primCounter = primCounter + 1;
1465 #endif