Replaced the --mode winebuild option by a --subsystem option for
[wine/hacks.git] / dlls / d3d8 / drawprim.c
blob1afff076fd7a03426b4a3c5672a315a7165262ec
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 isn't supplied, don't! */
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 if (This->StateBlock->renderstate[D3DRS_SPECULARENABLE]) {
207 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->StateBlock->material.Specular);
208 checkGLcall("glMaterialfv");
209 } else {
210 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
211 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
212 checkGLcall("glMaterialfv");
214 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->StateBlock->material.Emissive);
215 checkGLcall("glMaterialfv");
220 /* Setup views - Transformed & lit if RHW, else untransformed.
221 Only unlit if Normals are supplied
222 Returns: Whether to restore lighting afterwards */
223 BOOL primitiveInitState(LPDIRECT3DDEVICE8 iface, BOOL vtx_transformed, BOOL vtx_lit, BOOL useVS) {
225 BOOL isLightingOn = FALSE;
226 ICOM_THIS(IDirect3DDevice8Impl,iface);
228 /* If no normals, DISABLE lighting otherwise, don't touch lighing as it is
229 set by the appropriate render state. Note Vertex Shader output is already lit */
230 if (vtx_lit || useVS) {
231 isLightingOn = glIsEnabled(GL_LIGHTING);
232 glDisable(GL_LIGHTING);
233 checkGLcall("glDisable(GL_LIGHTING);");
234 TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn);
237 if (!useVS && vtx_transformed) {
239 /* If the last draw was transformed as well, no need to reapply all the matrixes */
240 if (!This->last_was_rhw) {
242 double X, Y, height, width, minZ, maxZ;
243 This->last_was_rhw = TRUE;
245 /* Transformed already into viewport coordinates, so we do not need transform
246 matrices. Reset all matrices to identity and leave the default matrix in world
247 mode. */
248 glMatrixMode(GL_MODELVIEW);
249 checkGLcall("glMatrixMode");
250 glLoadIdentity();
251 checkGLcall("glLoadIdentity");
253 glMatrixMode(GL_PROJECTION);
254 checkGLcall("glMatrixMode");
255 glLoadIdentity();
256 checkGLcall("glLoadIdentity");
258 /* Set up the viewport to be full viewport */
259 X = This->StateBlock->viewport.X;
260 Y = This->StateBlock->viewport.Y;
261 height = This->StateBlock->viewport.Height;
262 width = This->StateBlock->viewport.Width;
263 minZ = This->StateBlock->viewport.MinZ;
264 maxZ = This->StateBlock->viewport.MaxZ;
265 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
266 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
267 checkGLcall("glOrtho");
269 /* Window Coord 0 is the middle of the first pixel, so translate by half
270 a pixel (See comment above glTranslate below) */
271 glTranslatef(0.5, 0.5, 0);
272 checkGLcall("glTranslatef(0.5, 0.5, 0)");
275 } else {
277 /* Untransformed, so relies on the view and projection matrices */
279 if (!useVS && (This->last_was_rhw || !This->modelview_valid)) {
280 /* Only reapply when have to */
281 This->modelview_valid = TRUE;
282 glMatrixMode(GL_MODELVIEW);
283 checkGLcall("glMatrixMode");
285 /* In the general case, the view matrix is the identity matrix */
286 if (This->view_ident) {
287 glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
288 checkGLcall("glLoadMatrixf");
289 } else {
290 glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
291 checkGLcall("glLoadMatrixf");
292 glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
293 checkGLcall("glMultMatrixf");
297 if (!useVS && (This->last_was_rhw || !This->proj_valid)) {
298 /* Only reapply when have to */
299 This->proj_valid = TRUE;
300 glMatrixMode(GL_PROJECTION);
301 checkGLcall("glMatrixMode");
303 /* The rule is that the window coordinate 0 does not correspond to the
304 beginning of the first pixel, but the center of the first pixel.
305 As a consequence if you want to correctly draw one line exactly from
306 the left to the right end of the viewport (with all matrices set to
307 be identity), the x coords of both ends of the line would be not
308 -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
309 instead. */
310 glLoadIdentity();
311 glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0);
312 checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
313 glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]);
314 checkGLcall("glLoadMatrixf");
317 /* Vertex Shader output is already transformed, so set up identity matrices */
318 /* FIXME: Actually, only true for software emulated ones, so when h/w ones
319 come along this needs to take into account whether s/w ones were
320 requested or not */
321 if (useVS) {
322 glMatrixMode(GL_MODELVIEW);
323 checkGLcall("glMatrixMode");
324 glLoadIdentity();
325 glMatrixMode(GL_PROJECTION);
326 checkGLcall("glMatrixMode");
327 glLoadIdentity();
328 /* Window Coord 0 is the middle of the first pixel, so translate by half
329 a pixel (See comment above glTranslate above) */
330 glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0);
331 checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
332 This->modelview_valid = FALSE;
333 This->proj_valid = FALSE;
335 This->last_was_rhw = FALSE;
337 return isLightingOn;
340 void primitiveConvertToStridedData(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *strided, LONG BaseVertexIndex) {
342 short LoopThroughTo = 0;
343 short nStream;
344 BOOL canDoViaGLPointers = TRUE;
345 int numBlends;
346 int numTextures;
347 int textureNo;
348 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
349 int numCoords[8]; /* Holding place for D3DFVF_TEXTUREFORMATx */
351 ICOM_THIS(IDirect3DDevice8Impl,iface);
353 /* OK, Now to setup the data locations
354 For the non-created vertex shaders, the VertexShader var holds the real
355 FVF and only stream 0 matters
356 For the created vertex shaders, there is an FVF per stream */
357 if (!This->StateBlock->streamIsUP && (This->UpdateStateBlock->VertexShader > VS_HIGHESTFIXEDFXF)) {
358 LoopThroughTo = MAX_STREAMS;
359 } else {
360 LoopThroughTo = 1;
363 /* Work through stream by stream */
364 for (nStream=0; nStream<LoopThroughTo; nStream++) {
365 DWORD stride = This->StateBlock->stream_stride[nStream];
366 BYTE *data = NULL;
367 DWORD thisFVF = 0;
369 /* Skip empty streams */
370 if (This->StateBlock->stream_source[nStream] == NULL) continue;
372 /* Retrieve appropriate FVF */
373 if (LoopThroughTo == 1) { /* VertexShader is FVF */
374 thisFVF = This->UpdateStateBlock->VertexShader;
375 /* Handle memory passed directly as well as vertex buffers */
376 if (This->StateBlock->streamIsUP == TRUE) {
377 data = (BYTE *)This->StateBlock->stream_source[nStream];
378 } else {
379 data = ((IDirect3DVertexBuffer8Impl *)This->StateBlock->stream_source[nStream])->allocatedMemory;
381 } else {
382 thisFVF = This->StateBlock->vertexShaderDecl->fvf[nStream];
383 data = ((IDirect3DVertexBuffer8Impl *)This->StateBlock->stream_source[nStream])->allocatedMemory;
385 VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
386 if (thisFVF == 0) continue;
388 /* Now convert the stream into pointers */
390 /* Shuffle to the beginning of the vertexes to render and index from there */
391 data = data + (BaseVertexIndex * stride);
393 /* Either 3 or 4 floats depending on the FVF */
394 /* FIXME: Can blending data be in a different stream to the position data?
395 and if so using the fixed pipeline how do we handle it */
396 if (thisFVF & D3DFVF_POSITION_MASK) {
397 strided->u.s.position.lpData = data;
398 strided->u.s.position.dwType = D3DVSDT_FLOAT3;
399 strided->u.s.position.dwStride = stride;
400 data += 3 * sizeof(float);
401 if (thisFVF & D3DFVF_XYZRHW) {
402 strided->u.s.position.dwType = D3DVSDT_FLOAT4;
403 data += sizeof(float);
407 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
408 /** do we have to Check This->UpdateStateBlock->renderstate[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
409 numBlends = ((thisFVF & D3DFVF_POSITION_MASK) >> 1) - 2 +
410 ((FALSE == (thisFVF & D3DFVF_LASTBETA_UBYTE4)) ? 0 : -1); /* WARNING can be < 0 because -2 */
411 if (numBlends > 0) {
412 canDoViaGLPointers = FALSE;
413 strided->u.s.blendWeights.lpData = data;
414 strided->u.s.blendWeights.dwType = D3DVSDT_FLOAT1 + (numBlends - 1);
415 strided->u.s.blendWeights.dwStride = stride;
416 data += numBlends * sizeof(FLOAT);
418 if (thisFVF & D3DFVF_LASTBETA_UBYTE4) {
419 strided->u.s.blendMatrixIndices.lpData = data;
420 strided->u.s.blendMatrixIndices.dwType = D3DVSDT_UBYTE4;
421 strided->u.s.blendMatrixIndices.dwStride= stride;
422 data += sizeof(DWORD);
426 /* Normal is always 3 floats */
427 if (thisFVF & D3DFVF_NORMAL) {
428 strided->u.s.normal.lpData = data;
429 strided->u.s.normal.dwType = D3DVSDT_FLOAT3;
430 strided->u.s.normal.dwStride = stride;
431 data += 3 * sizeof(FLOAT);
434 /* Pointsize is a single float */
435 if (thisFVF & D3DFVF_PSIZE) {
436 strided->u.s.pSize.lpData = data;
437 strided->u.s.pSize.dwType = D3DVSDT_FLOAT1;
438 strided->u.s.pSize.dwStride = stride;
439 data += sizeof(FLOAT);
442 /* Diffuse is 4 unsigned bytes */
443 if (thisFVF & D3DFVF_DIFFUSE) {
444 strided->u.s.diffuse.lpData = data;
445 strided->u.s.diffuse.dwType = D3DVSDT_SHORT4;
446 strided->u.s.diffuse.dwStride = stride;
447 data += sizeof(DWORD);
450 /* Specular is 4 unsigned bytes */
451 if (thisFVF & D3DFVF_SPECULAR) {
452 strided->u.s.specular.lpData = data;
453 strided->u.s.specular.dwType = D3DVSDT_SHORT4;
454 strided->u.s.specular.dwStride = stride;
455 data += sizeof(DWORD);
458 /* Texture coords */
459 numTextures = (thisFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
460 coordIdxInfo = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of D3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
462 /* numTextures indicates the number of texture coordinates supplied */
463 /* However, the first set may not be for stage 0 texture - it all */
464 /* depends on D3DTSS_TEXCOORDINDEX. */
465 /* The number of bytes for each coordinate set is based off */
466 /* D3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
468 /* So, for each supplied texture extract the coords */
469 for (textureNo = 0; textureNo < numTextures; ++textureNo) {
471 strided->u.s.texCoords[textureNo].lpData = data;
472 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT1;
473 strided->u.s.texCoords[textureNo].dwStride = stride;
474 numCoords[textureNo] = coordIdxInfo & 0x03;
476 /* Always one set */
477 data += sizeof(float);
478 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT1) {
479 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT2;
480 data += sizeof(float);
481 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT2) {
482 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT3;
483 data += sizeof(float);
484 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT3) {
485 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT4;
486 data += sizeof(float);
490 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
495 /* Draw a single vertex using this information */
496 void draw_vertex(LPDIRECT3DDEVICE8 iface, /* interface */
497 BOOL isXYZ, float x, float y, float z, float rhw, /* xyzn position*/
498 BOOL isNormal, float nx, float ny, float nz, /* normal */
499 BOOL isDiffuse, float *dRGBA, /* 1st colors */
500 BOOL isSpecular, float *sRGB, /* 2ndry colors */
501 BOOL isPtSize, float ptSize, /* pointSize */
502 D3DVECTOR_4 *texcoords, int *numcoords) /* texture info */
504 int textureNo;
505 float s, t, r, q;
506 ICOM_THIS(IDirect3DDevice8Impl,iface);
508 /* Diffuse -------------------------------- */
509 if (isDiffuse == TRUE) {
510 glColor4fv(dRGBA);
511 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
514 /* Specular Colour ------------------------------------------*/
515 if (isSpecular == TRUE) {
516 #if defined(GL_EXT_secondary_color)
517 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
518 GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
519 VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
521 #endif
524 /* Normal -------------------------------- */
525 if (isNormal == TRUE) {
526 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
527 glNormal3f(nx, ny, nz);
530 /* Point Size ----------------------------------------------*/
531 if (isPtSize == TRUE) {
533 /* no such functionality in the fixed function GL pipeline */
534 FIXME("Cannot change ptSize here in openGl\n");
537 /* Texture coords --------------------------- */
538 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
540 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
541 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
542 continue ;
545 /* Query tex coords */
546 if (This->StateBlock->textures[textureNo] != NULL) {
548 int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
549 if (coordIdx > 7) {
550 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
551 continue;
552 } else if (numcoords[coordIdx] == 0) {
553 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
554 continue;
555 } else {
557 /* Initialize vars */
558 s = 0.0f;
559 t = 0.0f;
560 r = 0.0f;
561 q = 0.0f;
563 switch (numcoords[coordIdx]) {
564 case 4: q = texcoords[coordIdx].w; /* drop through */
565 case 3: r = texcoords[coordIdx].z; /* drop through */
566 case 2: t = texcoords[coordIdx].y; /* drop through */
567 case 1: s = texcoords[coordIdx].x;
570 switch (numcoords[coordIdx]) { /* Supply the provided texture coords */
571 case D3DTTFF_COUNT1:
572 VTRACE(("tex:%d, s=%f\n", textureNo, s));
573 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
574 #if defined(GL_VERSION_1_3)
575 glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s);
576 #else
577 glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s);
578 #endif
579 } else {
580 glTexCoord1f(s);
582 break;
583 case D3DTTFF_COUNT2:
584 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
585 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
586 #if defined(GL_VERSION_1_3)
587 glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t);
588 #else
589 glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t);
590 #endif
591 } else {
592 glTexCoord2f(s, t);
594 break;
595 case D3DTTFF_COUNT3:
596 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
597 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
598 #if defined(GL_VERSION_1_3)
599 glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r);
600 #else
601 glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r);
602 #endif
603 } else {
604 glTexCoord3f(s, t, r);
606 break;
607 case D3DTTFF_COUNT4:
608 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
609 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
610 #if defined(GL_VERSION_1_3)
611 glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q);
612 #else
613 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q);
614 #endif
615 } else {
616 glTexCoord4f(s, t, r, q);
618 break;
619 default:
620 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
624 } /* End of textures */
626 /* Position -------------------------------- */
627 if (isXYZ == TRUE) {
628 if (1.0f == rhw || rhw < 0.00001f) {
629 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
630 glVertex3f(x, y, z);
631 } else {
632 /* Cannot optimize by dividing through by rhw as rhw is required
633 later for perspective in the GL pipeline for vertex shaders */
634 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
635 glVertex4f(x,y,z,rhw);
641 * Actually draw using the supplied information.
642 * Faster GL version using pointers to data, harder to debug though
643 * Note does not handle vertex shaders yet
645 void drawStridedFast(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd,
646 int PrimitiveType, ULONG NumPrimitives,
647 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
648 int textureNo = 0;
649 GLenum glPrimType = GL_POINTS;
650 int NumVertexes = NumPrimitives;
651 ICOM_THIS(IDirect3DDevice8Impl,iface);
653 TRACE("Using fast vertex array code\n");
655 /* Vertex Pointers -----------------------------------------*/
656 if (sd->u.s.position.lpData != NULL) {
658 /* Note dwType == float3 or float4 == 2 or 3 */
659 VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n",
660 sd->u.s.position.dwStride,
661 sd->u.s.position.dwType + 1,
662 sd->u.s.position.lpData));
664 /* Disable RHW mode as 'w' coord handling for rhw mode should
665 not impact screen position whereas in GL it does. This may
666 result in very slightly distored textures in rhw mode, but
667 a very minimal different */
668 glVertexPointer(3, GL_FLOAT, /* RHW: Was 'sd->u.s.position.dwType + 1' */
669 sd->u.s.position.dwStride,
670 sd->u.s.position.lpData);
671 checkGLcall("glVertexPointer(...)");
672 glEnableClientState(GL_VERTEX_ARRAY);
673 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
675 } else {
677 glDisableClientState(GL_VERTEX_ARRAY);
678 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
681 /* Blend Data ----------------------------------------------*/
682 if ((sd->u.s.blendWeights.lpData != NULL) ||
683 (sd->u.s.blendMatrixIndices.lpData != NULL)) {
684 /* FIXME: Won't get here as will drop to slow method */
685 FIXME("Blending not supported in fast draw routine\n");
687 #if 0 /* Vertex blend support needs to be added */
688 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
689 /*FIXME("TODO\n");*/
690 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
691 /*FIXME("TODO\n");*/
693 GLExtCall(glVertexWeightPointerEXT)(numBlends, GL_FLOAT, skip, curPos);
694 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
695 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
696 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
698 } else {
699 FIXME("unsupported blending in openGl\n");
701 } else {
702 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
703 FIXME("TODO\n");
704 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
705 FIXME("TODO\n");
707 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
708 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
711 #endif
714 /* Normals -------------------------------------------------*/
715 if (sd->u.s.normal.lpData != NULL) {
717 /* Note dwType == float3 or float4 == 2 or 3 */
718 VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n",
719 sd->u.s.normal.dwStride,
720 sd->u.s.normal.lpData));
721 glNormalPointer(GL_FLOAT,
722 sd->u.s.normal.dwStride,
723 sd->u.s.normal.lpData);
724 checkGLcall("glNormalPointer(...)");
725 glEnableClientState(GL_NORMAL_ARRAY);
726 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
728 } else {
730 glDisableClientState(GL_NORMAL_ARRAY);
731 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
732 glNormal3f(0, 0, 1);
733 checkGLcall("glNormal3f(0, 0, 1)");
736 /* Point Size ----------------------------------------------*/
737 if (sd->u.s.pSize.lpData != NULL) {
739 /* no such functionality in the fixed function GL pipeline */
740 /* FIXME: Won't get here as will drop to slow method */
741 FIXME("Cannot change ptSize here in openGl\n");
744 /* Diffuse Colour ------------------------------------------*/
745 /* WARNING: Data here MUST be in RGBA format, so cannot */
746 /* go directly into fast mode from app pgm, because */
747 /* directx requires data in BGRA format. */
748 if (sd->u.s.diffuse.lpData != NULL) {
750 /* Note dwType == float3 or float4 == 2 or 3 */
751 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
752 sd->u.s.diffuse.dwStride,
753 sd->u.s.diffuse.lpData));
754 glColorPointer(4, GL_UNSIGNED_BYTE,
755 sd->u.s.diffuse.dwStride,
756 sd->u.s.diffuse.lpData);
757 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
758 glEnableClientState(GL_COLOR_ARRAY);
759 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
761 } else {
763 glDisableClientState(GL_COLOR_ARRAY);
764 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
765 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
766 checkGLcall("glColor4f(1, 1, 1, 1)");
769 /* Specular Colour ------------------------------------------*/
770 if (sd->u.s.specular.lpData != NULL) {
772 /* Note dwType == float3 or float4 == 2 or 3 */
773 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
774 sd->u.s.specular.dwStride,
775 sd->u.s.specular.lpData));
777 #if defined(GL_VERSION_1_4)
778 glSecondaryColorPointer(4, GL_UNSIGNED_BYTE,
779 sd->u.s.specular.dwStride,
780 sd->u.s.specular.lpData);
781 vcheckGLcall("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, ...)");
782 glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
783 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY)");
784 #elif defined(GL_EXT_secondary_color)
785 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
786 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
787 sd->u.s.specular.dwStride,
788 sd->u.s.specular.lpData);
789 checkGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
790 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
791 checkGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
793 #else
794 /* Missing specular color is not critical, no warnings */
795 VTRACE(("Specular colour is not supported in this GL implementation\n"));
796 #endif
798 } else {
800 #if defined(GL_VERSION_1_4)
801 glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
802 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY)");
803 glSecondaryColor3f(0, 0, 0);
804 checkGLcall("glSecondaryColor3f(0, 0, 0)");
805 #elif defined(GL_EXT_secondary_color)
806 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
807 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
808 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
809 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
810 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
812 #else
813 /* Do not worry if specular colour missing and disable request */
814 #endif
817 /* Texture coords -------------------------------------------*/
818 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
820 /* Select the correct texture stage */
821 #if defined(GL_VERSION_1_3)
822 glClientActiveTexture(GL_TEXTURE0 + textureNo);
823 #else
824 glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo);
825 #endif
827 /* Query tex coords */
828 if (This->StateBlock->textures[textureNo] != NULL) {
829 int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
831 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
832 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
833 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
834 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
835 continue;
838 if (coordIdx > 7) {
839 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
840 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
841 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
842 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
843 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
844 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
845 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
846 } else {
848 /* The coords to supply depend completely on the fvf / vertex shader */
849 GLint size;
850 GLenum type;
852 switch (sd->u.s.texCoords[coordIdx].dwType) {
853 case D3DVSDT_FLOAT1: size = 1, type = GL_FLOAT; break;
854 case D3DVSDT_FLOAT2: size = 2, type = GL_FLOAT; break;
855 case D3DVSDT_FLOAT3: size = 3, type = GL_FLOAT; break;
856 case D3DVSDT_FLOAT4: size = 4, type = GL_FLOAT; break;
857 case D3DVSDT_SHORT2: size = 2, type = GL_SHORT; break;
858 case D3DVSDT_SHORT4: size = 4, type = GL_SHORT; break;
859 case D3DVSDT_UBYTE4: size = 4, type = GL_UNSIGNED_BYTE; break;
860 default: FIXME("Unrecognized data type %ld\n", sd->u.s.texCoords[coordIdx].dwType);
861 size = 4; type = GL_UNSIGNED_BYTE;
864 glTexCoordPointer(size, type, sd->u.s.texCoords[coordIdx].dwStride, sd->u.s.texCoords[coordIdx].lpData);
865 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
867 } else {
868 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
869 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
873 /* Ok, Work out which primitive is requested and how many vertexes that
874 will be */
875 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
877 /* Finally do the drawing */
878 if (idxData != NULL) {
880 TRACE("glElements(%x, %d, %ld, ...)\n", glPrimType, NumVertexes, minIndex);
881 #if 1 /* FIXME: Want to use DrawRangeElements, but wrong calculation! */
882 glDrawElements(glPrimType, NumVertexes, idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
883 (char *)idxData+(idxSize * startIdx));
884 #else
885 glDrawRangeElements(glPrimType, minIndex, minIndex+NumVertexes-1, NumVertexes,
886 idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
887 (char *)idxData+(idxSize * startIdx));
888 #endif
889 checkGLcall("glDrawRangeElements");
891 } else {
893 /* Note first is now zero as we shuffled along earlier */
894 TRACE("glDrawArrays(%x, 0, %d)\n", glPrimType, NumVertexes);
895 glDrawArrays(glPrimType, 0, NumVertexes);
896 checkGLcall("glDrawArrays");
902 * Actually draw using the supplied information.
903 * Slower GL version which extracts info about each vertex in turn
905 void drawStridedSlow(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd,
906 int PrimitiveType, ULONG NumPrimitives,
907 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
909 int textureNo = 0;
910 GLenum glPrimType = GL_POINTS;
911 int NumVertexes = NumPrimitives;
912 const short *pIdxBufS = NULL;
913 const long *pIdxBufL = NULL;
914 LONG SkipnStrides = 0;
915 LONG vx_index;
916 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
917 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
918 float rhw = 0.0f; /* rhw */
919 float ptSize = 0.0f; /* Point size */
920 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
921 DWORD specularColor = 0; /* Specular Color */
922 ICOM_THIS(IDirect3DDevice8Impl,iface);
924 TRACE("Using slow vertex array code\n");
926 /* Variable Initialization */
927 if (idxData != NULL) {
928 if (idxSize == 2) pIdxBufS = (short *) idxData;
929 else pIdxBufL = (long *) idxData;
932 /* Ok, Work out which primitive is requested and how many vertexes that will be */
933 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
935 /* Start drawing in GL */
936 VTRACE(("glBegin(%x)\n", glPrimType));
937 glBegin(glPrimType);
939 /* For each primitive */
940 for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
942 /* Initialize diffuse color */
943 diffuseColor = 0xFFFFFFFF;
945 /* For indexed data, we need to go a few more strides in */
946 if (idxData != NULL) {
948 /* Indexed so work out the number of strides to skip */
949 if (idxSize == 2) {
950 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
951 SkipnStrides = pIdxBufS[startIdx+vx_index];
952 } else {
953 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
954 SkipnStrides = pIdxBufL[startIdx+vx_index];
958 /* Position Information ------------------ */
959 if (sd->u.s.position.lpData != NULL) {
961 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
962 x = ptrToCoords[0];
963 y = ptrToCoords[1];
964 z = ptrToCoords[2];
965 rhw = 1.0;
966 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
968 /* RHW follows, only if transformed, ie 4 floats were provided */
969 if (sd->u.s.position.dwType == D3DVSDT_FLOAT4) {
970 rhw = ptrToCoords[3];
971 VTRACE(("rhw=%f\n", rhw));
975 /* Blending data -------------------------- */
976 if (sd->u.s.blendWeights.lpData != NULL) {
977 /*float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride));*/
978 FIXME("Blending not supported yet\n");
980 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
981 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
985 /* Vertex Normal Data (untransformed only)- */
986 if (sd->u.s.normal.lpData != NULL) {
988 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
989 nx = ptrToCoords[0];
990 ny = ptrToCoords[1];
991 nz = ptrToCoords[2];
992 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
995 /* Point Size ----------------------------- */
996 if (sd->u.s.pSize.lpData != NULL) {
998 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
999 ptSize = ptrToCoords[0];
1000 VTRACE(("ptSize=%f\n", ptSize));
1001 FIXME("No support for ptSize yet\n");
1004 /* Diffuse -------------------------------- */
1005 if (sd->u.s.diffuse.lpData != NULL) {
1007 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1008 diffuseColor = ptrToCoords[0];
1009 VTRACE(("diffuseColor=%lx\n", diffuseColor));
1012 /* Specular -------------------------------- */
1013 if (sd->u.s.specular.lpData != NULL) {
1015 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1016 specularColor = ptrToCoords[0];
1017 VTRACE(("specularColor=%lx\n", specularColor));
1020 /* Texture coords --------------------------- */
1021 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1023 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1024 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1025 continue ;
1028 /* Query tex coords */
1029 if (This->StateBlock->textures[textureNo] != NULL) {
1031 int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
1032 float *ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1033 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1035 if (coordIdx > 7) {
1036 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1037 continue;
1038 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1039 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1040 continue;
1041 } else {
1043 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DVSDT_FLOAT1 etc */
1045 /* The coords to supply depend completely on the fvf / vertex shader */
1046 switch (coordsToUse) {
1047 case 4: q = ptrToCoords[3]; /* drop through */
1048 case 3: r = ptrToCoords[2]; /* drop through */
1049 case 2: t = ptrToCoords[1]; /* drop through */
1050 case 1: s = ptrToCoords[0];
1053 /* Projected is more 'fun' - Move the last coord to the 'q'
1054 parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1055 if ((This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1056 (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1058 if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1059 switch (coordsToUse) {
1060 case 0: /* Drop Through */
1061 case 1:
1062 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1063 break;
1064 case 2:
1065 q = t;
1066 t = 0.0;
1067 coordsToUse = 4;
1068 break;
1069 case 3:
1070 q = r;
1071 r = 0.0;
1072 coordsToUse = 4;
1073 break;
1074 case 4: /* Nop here */
1075 break;
1076 default:
1077 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n",
1078 This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1083 switch (coordsToUse) { /* Supply the provided texture coords */
1084 case D3DTTFF_COUNT1:
1085 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1086 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1087 #if defined(GL_VERSION_1_3)
1088 glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s);
1089 #else
1090 glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s);
1091 #endif
1092 } else {
1093 glTexCoord1f(s);
1095 break;
1096 case D3DTTFF_COUNT2:
1097 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1098 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1099 #if defined(GL_VERSION_1_3)
1100 glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t);
1101 #else
1102 glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t);
1103 #endif
1104 } else {
1105 glTexCoord2f(s, t);
1107 break;
1108 case D3DTTFF_COUNT3:
1109 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1110 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1111 #if defined(GL_VERSION_1_3)
1112 glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r);
1113 #else
1114 glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r);
1115 #endif
1116 } else {
1117 glTexCoord3f(s, t, r);
1119 break;
1120 case D3DTTFF_COUNT4:
1121 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1122 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1123 #if defined(GL_VERSION_1_3)
1124 glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q);
1125 #else
1126 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q);
1127 #endif
1128 } else {
1129 glTexCoord4f(s, t, r, q);
1131 break;
1132 default:
1133 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1137 } /* End of textures */
1139 /* Diffuse -------------------------------- */
1140 if (sd->u.s.diffuse.lpData != NULL) {
1141 glColor4ub((diffuseColor >> 16) & 0xFF,
1142 (diffuseColor >> 8) & 0xFF,
1143 (diffuseColor >> 0) & 0xFF,
1144 (diffuseColor >> 24) & 0xFF);
1145 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n",
1146 ((diffuseColor >> 16) & 0xFF) / 255.0f,
1147 ((diffuseColor >> 8) & 0xFF) / 255.0f,
1148 ((diffuseColor >> 0) & 0xFF) / 255.0f,
1149 ((diffuseColor >> 24) & 0xFF) / 255.0f));
1150 } else {
1151 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1154 #if 1
1155 /* Specular ------------------------------- */
1156 if (sd->u.s.diffuse.lpData != NULL) {
1157 VTRACE(("glSecondaryColor4ub: r,g,b=%f,%f,%f\n",
1158 ((specularColor >> 16) & 0xFF) / 255.0f,
1159 ((specularColor >> 8) & 0xFF) / 255.0f,
1160 ((specularColor >> 0) & 0xFF) / 255.0f));
1161 #if defined(GL_VERSION_1_4)
1162 glSecondaryColor3ub((specularColor >> 16) & 0xFF,
1163 (specularColor >> 8) & 0xFF,
1164 (specularColor >> 0) & 0xFF);
1165 #elif defined(GL_EXT_secondary_color)
1166 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1167 GL_EXTCALL(glSecondaryColor3ubEXT)(
1168 (specularColor >> 16) & 0xFF,
1169 (specularColor >> 8) & 0xFF,
1170 (specularColor >> 0) & 0xFF);
1172 #else
1173 /* Do not worry if specular colour missing and disable request */
1174 VTRACE(("Specular color extensions not supplied\n"));
1175 #endif
1176 } else {
1177 #if defined(GL_VERSION_1_4)
1178 if (vx_index == 0) glSecondaryColor3f(0, 0, 0);
1179 #elif defined(GL_EXT_secondary_color)
1180 if (vx_index == 0 && GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1181 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1183 #else
1184 /* Do not worry if specular colour missing and disable request */
1185 #endif
1187 #endif
1189 /* Normal -------------------------------- */
1190 if (sd->u.s.normal.lpData != NULL) {
1191 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1192 glNormal3f(nx, ny, nz);
1193 } else {
1194 if (vx_index == 0) glNormal3f(0, 0, 1);
1197 /* Position -------------------------------- */
1198 if (sd->u.s.position.lpData != NULL) {
1199 if (1.0f == rhw || rhw < 0.0001f) {
1200 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1201 glVertex3f(x, y, z);
1202 } else {
1203 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1204 /* Disable RHW mode as 'w' coord handling for rhw mode should
1205 not impact screen position whereas in GL it does. This may
1206 result in very slightly distored textures in rhw mode, but
1207 a very minimal different. In slow mode a possible 'fix' is
1208 glVertex4f(x*rhw,y*rhw,z*rhw,rhw) but not sure this is right */
1209 glVertex3f(x,y,z);
1213 /* For non indexed mode, step onto next parts */
1214 if (idxData == NULL) {
1215 SkipnStrides += 1;
1219 glEnd();
1220 checkGLcall("glEnd and previous calls");
1224 * Draw with emulated vertex shaders
1225 * Note: strided data is uninitialized, as we need to pass the vertex
1226 * shader directly as ordering irs yet
1228 void drawStridedSoftwareVS(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd,
1229 int PrimitiveType, ULONG NumPrimitives,
1230 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1232 int textureNo = 0;
1233 GLenum glPrimType = GL_POINTS;
1234 int NumVertexes = NumPrimitives;
1235 const short *pIdxBufS = NULL;
1236 const long *pIdxBufL = NULL;
1237 LONG SkipnStrides = 0;
1238 LONG vx_index;
1239 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1240 float rhw = 0.0f; /* rhw */
1241 float ptSize = 0.0f; /* Point size */
1242 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1243 int numcoords[8]; /* Number of coords */
1244 ICOM_THIS(IDirect3DDevice8Impl,iface);
1246 IDirect3DVertexShaderImpl* vertex_shader = NULL;
1248 TRACE("Using slow software vertex shader code\n");
1250 /* Variable Initialization */
1251 if (idxData != NULL) {
1252 if (idxSize == 2) pIdxBufS = (short *) idxData;
1253 else pIdxBufL = (long *) idxData;
1256 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1257 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1259 /* Retrieve the VS information */
1260 vertex_shader = VERTEX_SHADER(This->StateBlock->VertexShader);
1262 /* Start drawing in GL */
1263 VTRACE(("glBegin(%x)\n", glPrimType));
1264 glBegin(glPrimType);
1266 /* For each primitive */
1267 for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
1269 /* For indexed data, we need to go a few more strides in */
1270 if (idxData != NULL) {
1272 /* Indexed so work out the number of strides to skip */
1273 if (idxSize == 2) {
1274 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1275 SkipnStrides = pIdxBufS[startIdx+vx_index];
1276 } else {
1277 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1278 SkipnStrides = pIdxBufL[startIdx+vx_index];
1282 /* Fill the vertex shader input */
1283 IDirect3DDeviceImpl_FillVertexShaderInput(This, vertex_shader, SkipnStrides);
1285 /* Initialize the output fields to the same defaults as it would normally have */
1286 memset(&vertex_shader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1287 vertex_shader->output.oD[0].x = 1.0;
1288 vertex_shader->output.oD[0].y = 1.0;
1289 vertex_shader->output.oD[0].z = 1.0;
1290 vertex_shader->output.oD[0].w = 1.0;
1292 /* Now execute the vertex shader */
1293 IDirect3DVertexShaderImpl_ExecuteSW(vertex_shader, &vertex_shader->input, &vertex_shader->output);
1296 TRACE_VECTOR(vertex_shader->output.oPos);
1297 TRACE_VECTOR(vertex_shader->output.oD[0]);
1298 TRACE_VECTOR(vertex_shader->output.oD[1]);
1299 TRACE_VECTOR(vertex_shader->output.oT[0]);
1300 TRACE_VECTOR(vertex_shader->output.oT[1]);
1301 TRACE_VECTOR(vertex_shader->input.V[0]);
1302 TRACE_VECTOR(vertex_shader->data->C[0]);
1303 TRACE_VECTOR(vertex_shader->data->C[1]);
1304 TRACE_VECTOR(vertex_shader->data->C[2]);
1305 TRACE_VECTOR(vertex_shader->data->C[3]);
1306 TRACE_VECTOR(vertex_shader->data->C[4]);
1307 TRACE_VECTOR(vertex_shader->data->C[5]);
1308 TRACE_VECTOR(vertex_shader->data->C[6]);
1309 TRACE_VECTOR(vertex_shader->data->C[7]);
1312 /* Extract out the output */
1313 /*FIXME: Fog coords? */
1314 x = vertex_shader->output.oPos.x;
1315 y = vertex_shader->output.oPos.y;
1316 z = vertex_shader->output.oPos.z;
1317 rhw = vertex_shader->output.oPos.w;
1318 ptSize = vertex_shader->output.oPts.x; /* Fixme - Is this right? */
1320 /** Update textures coords using vertex_shader->output.oT[0->7] */
1321 memset(texcoords, 0x00, sizeof(texcoords));
1322 memset(numcoords, 0x00, sizeof(numcoords));
1323 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1324 if (This->StateBlock->textures[textureNo] != NULL) {
1325 texcoords[textureNo].x = vertex_shader->output.oT[textureNo].x;
1326 texcoords[textureNo].y = vertex_shader->output.oT[textureNo].y;
1327 texcoords[textureNo].z = vertex_shader->output.oT[textureNo].z;
1328 texcoords[textureNo].w = vertex_shader->output.oT[textureNo].w;
1329 if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1330 numcoords[textureNo] = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1331 } else {
1332 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->StateBlock->textures[textureNo])) {
1333 case D3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1334 case D3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1335 default: numcoords[textureNo] = 4;
1338 } else {
1339 numcoords[textureNo] = 0;
1343 /* Draw using this information */
1344 draw_vertex(iface,
1345 TRUE, x, y, z, rhw,
1346 TRUE, 0.0f, 0.0f, 1.0f,
1347 TRUE, (float*) &vertex_shader->output.oD[0],
1348 TRUE, (float*) &vertex_shader->output.oD[1],
1349 FALSE, ptSize, /* FIXME: Change back when supported */
1350 texcoords, numcoords);
1352 /* For non indexed mode, step onto next parts */
1353 if (idxData == NULL) {
1354 SkipnStrides += 1;
1357 } /* for each vertex */
1359 glEnd();
1360 checkGLcall("glEnd and previous calls");
1363 /* Routine common to the draw primitive and draw indexed primitive routines */
1364 void drawPrimitive(LPDIRECT3DDEVICE8 iface,
1365 int PrimitiveType, long NumPrimitives,
1367 /* for Indexed: */
1368 long StartVertexIndex,
1369 long StartIdx,
1370 short idxSize,
1371 const void *idxData,
1372 int minIndex) {
1374 BOOL rc = FALSE;
1375 DWORD fvf = 0;
1376 IDirect3DVertexShaderImpl *vertex_shader = NULL;
1377 BOOL useVertexShaderFunction = FALSE;
1378 BOOL isLightingOn = FALSE;
1379 Direct3DVertexStridedData dataLocations;
1380 ICOM_THIS(IDirect3DDevice8Impl,iface);
1383 /* Work out what the FVF should look like */
1384 rc = initializeFVF(iface, &fvf, &useVertexShaderFunction);
1385 if (rc) return;
1387 /* If we will be using a vertex shader, do some initialization for it */
1388 if (useVertexShaderFunction == TRUE) {
1389 vertex_shader = VERTEX_SHADER(This->UpdateStateBlock->VertexShader);
1390 memset(&vertex_shader->input, 0, sizeof(VSHADERINPUTDATA8));
1392 /** init Constants */
1393 if (TRUE == This->UpdateStateBlock->Changed.vertexShaderConstant) {
1394 TRACE_(d3d_shader)("vertex shader initializing constants\n");
1395 IDirect3DVertexShaderImpl_SetConstantF(vertex_shader, 0, (CONST FLOAT*) &This->UpdateStateBlock->vertexShaderConstant[0], 96);
1399 /* Ok, we will be updating the screen from here onwards so grab the lock */
1400 ENTER_GL();
1402 /* Setup transform matrices and sort out */
1403 isLightingOn = primitiveInitState(iface,
1404 fvf & D3DFVF_XYZRHW,
1405 !(fvf & D3DFVF_NORMAL),
1406 useVertexShaderFunction);
1408 /* Initialize all values to null */
1409 if (useVertexShaderFunction == FALSE) {
1410 memset(&dataLocations, 0x00, sizeof(dataLocations));
1412 /* Convert to strided data */
1413 primitiveConvertToStridedData(iface, &dataLocations, StartVertexIndex);
1415 /* Dump out what parts we have supplied */
1416 TRACE("Strided Data (from FVF/VS): %lx\n", fvf);
1417 TRACE_STRIDED((&dataLocations), position);
1418 TRACE_STRIDED((&dataLocations), blendWeights);
1419 TRACE_STRIDED((&dataLocations), blendMatrixIndices);
1420 TRACE_STRIDED((&dataLocations), normal);
1421 TRACE_STRIDED((&dataLocations), pSize);
1422 TRACE_STRIDED((&dataLocations), diffuse);
1423 TRACE_STRIDED((&dataLocations), specular);
1424 TRACE_STRIDED((&dataLocations), texCoords[0]);
1425 TRACE_STRIDED((&dataLocations), texCoords[1]);
1426 TRACE_STRIDED((&dataLocations), texCoords[2]);
1427 TRACE_STRIDED((&dataLocations), texCoords[3]);
1428 TRACE_STRIDED((&dataLocations), texCoords[4]);
1429 TRACE_STRIDED((&dataLocations), texCoords[5]);
1430 TRACE_STRIDED((&dataLocations), texCoords[6]);
1431 TRACE_STRIDED((&dataLocations), texCoords[7]);
1434 /* Now initialize the materials state */
1435 init_materials(iface, (dataLocations.u.s.diffuse.lpData != NULL));
1437 /* Now draw the graphics to the screen */
1438 if (useVertexShaderFunction == TRUE) {
1440 /* Ideally, we should have software FV and hardware VS, possibly
1441 depending on the device type? */
1443 /* We will have to use the very, very slow emulation layer */
1444 drawStridedSoftwareVS(iface, &dataLocations, PrimitiveType, NumPrimitives,
1445 idxData, idxSize, minIndex, StartIdx);
1447 } else if ((dataLocations.u.s.pSize.lpData != NULL) ||
1448 (dataLocations.u.s.diffuse.lpData != NULL) ||
1449 (dataLocations.u.s.blendWeights.lpData != NULL)) {
1451 /* Fixme, Ideally, only use the per-vertex code for software HAL
1452 but until opengl supports all the functions returned to setup
1453 vertex arrays, we need to drop down to the slow mechanism for
1454 certain functions */
1456 /* We will have to use the slow version of GL per vertex setup */
1457 drawStridedSlow(iface, &dataLocations, PrimitiveType, NumPrimitives,
1458 idxData, idxSize, minIndex, StartIdx);
1460 } else {
1462 /* We can use the fast version of GL pointers */
1463 drawStridedFast(iface, &dataLocations, PrimitiveType, NumPrimitives,
1464 idxData, idxSize, minIndex, StartIdx);
1467 /* If vertex shaders or no normals, restore previous lighting state */
1468 if (useVertexShaderFunction || !(fvf & D3DFVF_NORMAL)) {
1469 if (isLightingOn) glEnable(GL_LIGHTING);
1470 else glDisable(GL_LIGHTING);
1471 TRACE("Restored lighting to original state\n");
1474 /* Finshed updating the screen, restore lock */
1475 LEAVE_GL();
1476 TRACE("Done all gl drawing\n");
1478 /* Diagnostics */
1479 #if defined(SHOW_FRAME_MAKEUP)
1481 if (isDumpingFrames == TRUE) {
1482 D3DLOCKED_RECT r;
1483 char buffer[80];
1484 IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) This->backBuffer, &r, NULL, D3DLOCK_READONLY);
1485 sprintf(buffer, "/tmp/backbuffer_%ld.ppm", primCounter);
1486 TRACE("Saving screenshot %s\n", buffer);
1487 IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This->backBuffer, buffer);
1488 IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) This->backBuffer);
1490 #if defined(SHOW_TEXTURE_MAKEUP)
1492 LPDIRECT3DSURFACE8 pSur;
1493 int textureNo;
1494 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1495 if (This->StateBlock->textures[textureNo] != NULL) {
1496 sprintf(buffer, "/tmp/texture_%ld_%d.ppm", primCounter, textureNo);
1497 TRACE("Saving texture %s (Format:%s)\n", buffer, debug_d3dformat(((IDirect3DBaseTexture8Impl *)This->StateBlock->textures[textureNo])->format));
1498 IDirect3DTexture8Impl_GetSurfaceLevel((LPDIRECT3DTEXTURE8) This->StateBlock->textures[textureNo], 0, &pSur);
1499 IDirect3DSurface8Impl_SaveSnapshot(pSur, buffer);
1500 IDirect3DSurface8Impl_Release(pSur);
1504 #endif
1505 primCounter = primCounter + 1;
1508 #endif