4 * Copyright 2002-2004 Jason Edmeades
5 * Copyright 2002-2004 Raphael Junqueira
6 * Copyright 2004 Christian Costa
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
34 #include "wine/debug.h"
36 #include "d3d8_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
39 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
41 extern IDirect3DVertexShaderImpl* VertexShaders[64];
42 extern IDirect3DVertexShaderDeclarationImpl* VertexShaderDeclarations[64];
43 extern IDirect3DPixelShaderImpl* PixelShaders[64];
45 /* Useful holding place for 4 floats */
46 typedef struct _D3DVECTOR_4 {
53 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
55 /* Returns bits for what is expected from the fixed function pipeline, and whether
56 a vertex shader will be in use. Note the fvf bits returned may be split over
57 multiple streams only if the vertex shader was created, otherwise it all relates
59 static BOOL initializeFVF(LPDIRECT3DDEVICE8 iface,
60 DWORD *FVFbits, /* What to expect in the FVF across all streams */
61 BOOL *useVertexShaderFunction) /* Should we use the vertex shader */
64 IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
66 /* The first thing to work out is if we are using the fixed function pipeline
67 which is either SetVertexShader with < VS_HIGHESTFIXEDFXF - in which case this
68 is the FVF, or with a shader which was created with no function - in which
69 case there is an FVF per declared stream. If this occurs, we also maintain
70 an 'OR' of all the FVF's together so we know what to expect across all the
73 if (This->UpdateStateBlock->VertexShader <= VS_HIGHESTFIXEDFXF) {
75 /* Use this as the FVF */
76 *FVFbits = This->UpdateStateBlock->VertexShader;
77 *useVertexShaderFunction = FALSE;
78 TRACE("FVF explicitally defined, using fixed function pipeline with FVF=%lx\n", *FVFbits);
82 /* Use created shader */
83 IDirect3DVertexShaderImpl* vertex_shader = NULL;
84 vertex_shader = VERTEX_SHADER(This->UpdateStateBlock->VertexShader);
86 if (vertex_shader == NULL) {
88 /* Hmm - User pulled figure out of the air? Unlikely, probably a bug */
89 ERR("trying to use unitialised vertex shader: %lu\n", This->UpdateStateBlock->VertexShader);
94 *FVFbits = This->UpdateStateBlock->vertexShaderDecl->allFVF;
96 if (vertex_shader->function == NULL) {
97 /* No function, so many streams supplied plus FVF definition pre stream */
98 *useVertexShaderFunction = FALSE;
99 TRACE("vertex shader (%lx) declared without program, using fixed function pipeline with FVF=%lx\n",
100 This->StateBlock->VertexShader, *FVFbits);
102 /* Vertex shader needs calling */
103 *useVertexShaderFunction = TRUE;
104 TRACE("vertex shader will be used (unusued FVF=%lx)\n", *FVFbits);
111 /* Issues the glBegin call for gl given the primitive type and count */
112 static DWORD primitiveToGl(D3DPRIMITIVETYPE PrimitiveType,
116 DWORD NumVertexes = NumPrimitives;
118 switch (PrimitiveType) {
119 case D3DPT_POINTLIST:
121 *primType = GL_POINTS;
122 NumVertexes = NumPrimitives;
127 *primType = GL_LINES;
128 NumVertexes = NumPrimitives * 2;
131 case D3DPT_LINESTRIP:
132 TRACE("LINE_STRIP\n");
133 *primType = GL_LINE_STRIP;
134 NumVertexes = NumPrimitives + 1;
137 case D3DPT_TRIANGLELIST:
138 TRACE("TRIANGLES\n");
139 *primType = GL_TRIANGLES;
140 NumVertexes = NumPrimitives * 3;
143 case D3DPT_TRIANGLESTRIP:
144 TRACE("TRIANGLE_STRIP\n");
145 *primType = GL_TRIANGLE_STRIP;
146 NumVertexes = NumPrimitives + 2;
149 case D3DPT_TRIANGLEFAN:
150 TRACE("TRIANGLE_FAN\n");
151 *primType = GL_TRIANGLE_FAN;
152 NumVertexes = NumPrimitives + 2;
156 FIXME("Unhandled primitive\n");
157 *primType = GL_POINTS;
163 /* Ensure the appropriate material states are set up - only change
164 state if really required */
165 static void init_materials(LPDIRECT3DDEVICE8 iface, BOOL isDiffuseSupplied) {
167 BOOL requires_material_reset = FALSE;
168 IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
170 if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied) {
171 /* If we have not set up the material color tracking, do it now as required */
172 glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
173 checkGLcall("glDisable GL_COLOR_MATERIAL");
174 TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
175 glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
176 checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
177 glEnable(GL_COLOR_MATERIAL);
178 checkGLcall("glEnable GL_COLOR_MATERIAL");
179 This->tracking_color = IS_TRACKING;
180 requires_material_reset = TRUE; /* Restore material settings as will be used */
182 } else if ((This->tracking_color == IS_TRACKING && isDiffuseSupplied == FALSE) ||
183 (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == FALSE)) {
184 /* If we are tracking the current color but one isn't supplied, don't! */
185 glDisable(GL_COLOR_MATERIAL);
186 checkGLcall("glDisable GL_COLOR_MATERIAL");
187 This->tracking_color = NEEDS_TRACKING;
188 requires_material_reset = TRUE; /* Restore material settings as will be used */
190 } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied) {
191 /* No need to reset material colors since no change to gl_color_material */
192 requires_material_reset = FALSE;
194 } else if (This->tracking_color == NEEDS_DISABLE) {
195 glDisable(GL_COLOR_MATERIAL);
196 checkGLcall("glDisable GL_COLOR_MATERIAL");
197 This->tracking_color = DISABLED_TRACKING;
198 requires_material_reset = TRUE; /* Restore material settings as will be used */
201 /* Reset the material colors which may have been tracking the color*/
202 if (requires_material_reset) {
203 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->StateBlock->material.Ambient);
204 checkGLcall("glMaterialfv");
205 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->StateBlock->material.Diffuse);
206 checkGLcall("glMaterialfv");
207 if (This->StateBlock->renderstate[D3DRS_SPECULARENABLE]) {
208 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->StateBlock->material.Specular);
209 checkGLcall("glMaterialfv");
211 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
212 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
213 checkGLcall("glMaterialfv");
215 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->StateBlock->material.Emissive);
216 checkGLcall("glMaterialfv");
221 static GLfloat invymat[16]={
222 1.0f, 0.0f, 0.0f, 0.0f,
223 0.0f, -1.0f, 0.0f, 0.0f,
224 0.0f, 0.0f, 1.0f, 0.0f,
225 0.0f, 0.0f, 0.0f, 1.0f};
227 /* Setup views - Transformed & lit if RHW, else untransformed.
228 Only unlit if Normals are supplied
229 Returns: Whether to restore lighting afterwards */
230 static BOOL primitiveInitState(LPDIRECT3DDEVICE8 iface, BOOL vtx_transformed, BOOL vtx_lit, BOOL useVS) {
232 BOOL isLightingOn = FALSE;
233 IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
235 /* If no normals, DISABLE lighting otherwise, don't touch lighing as it is
236 set by the appropriate render state. Note Vertex Shader output is already lit */
237 if (vtx_lit || useVS) {
238 isLightingOn = glIsEnabled(GL_LIGHTING);
239 glDisable(GL_LIGHTING);
240 checkGLcall("glDisable(GL_LIGHTING);");
241 TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn);
244 if (!useVS && vtx_transformed) {
246 /* If the last draw was transformed as well, no need to reapply all the matrixes */
247 if (!This->last_was_rhw) {
249 double X, Y, height, width, minZ, maxZ;
250 This->last_was_rhw = TRUE;
252 /* Transformed already into viewport coordinates, so we do not need transform
253 matrices. Reset all matrices to identity and leave the default matrix in world
255 glMatrixMode(GL_MODELVIEW);
256 checkGLcall("glMatrixMode");
258 checkGLcall("glLoadIdentity");
260 glMatrixMode(GL_PROJECTION);
261 checkGLcall("glMatrixMode");
263 checkGLcall("glLoadIdentity");
265 /* Set up the viewport to be full viewport */
266 X = This->StateBlock->viewport.X;
267 Y = This->StateBlock->viewport.Y;
268 height = This->StateBlock->viewport.Height;
269 width = This->StateBlock->viewport.Width;
270 minZ = This->StateBlock->viewport.MinZ;
271 maxZ = This->StateBlock->viewport.MaxZ;
272 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
273 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
274 checkGLcall("glOrtho");
276 /* Window Coord 0 is the middle of the first pixel, so translate by half
277 a pixel (See comment above glTranslate below) */
278 glTranslatef(0.5, 0.5, 0);
279 checkGLcall("glTranslatef(0.5, 0.5, 0)");
280 if (This->renderUpsideDown) {
281 glMultMatrixf(invymat);
282 checkGLcall("glMultMatrixf(invymat)");
288 /* Untransformed, so relies on the view and projection matrices */
290 if (!useVS && (This->last_was_rhw || !This->modelview_valid)) {
291 /* Only reapply when have to */
292 This->modelview_valid = TRUE;
293 glMatrixMode(GL_MODELVIEW);
294 checkGLcall("glMatrixMode");
296 /* In the general case, the view matrix is the identity matrix */
297 if (This->view_ident) {
298 glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
299 checkGLcall("glLoadMatrixf");
301 glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
302 checkGLcall("glLoadMatrixf");
303 glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
304 checkGLcall("glMultMatrixf");
308 if (!useVS && (This->last_was_rhw || !This->proj_valid)) {
309 /* Only reapply when have to */
310 This->proj_valid = TRUE;
311 glMatrixMode(GL_PROJECTION);
312 checkGLcall("glMatrixMode");
314 /* The rule is that the window coordinate 0 does not correspond to the
315 beginning of the first pixel, but the center of the first pixel.
316 As a consequence if you want to correctly draw one line exactly from
317 the left to the right end of the viewport (with all matrices set to
318 be identity), the x coords of both ends of the line would be not
319 -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
322 glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0);
323 checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
325 if (This->renderUpsideDown) {
326 glMultMatrixf(invymat);
327 checkGLcall("glMultMatrixf(invymat)");
329 glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]);
330 checkGLcall("glLoadMatrixf");
333 /* Vertex Shader output is already transformed, so set up identity matrices */
334 /* FIXME: Actually, only true for software emulated ones, so when h/w ones
335 come along this needs to take into account whether s/w ones were
338 glMatrixMode(GL_MODELVIEW);
339 checkGLcall("glMatrixMode");
341 glMatrixMode(GL_PROJECTION);
342 checkGLcall("glMatrixMode");
344 /* Window Coord 0 is the middle of the first pixel, so translate by half
345 a pixel (See comment above glTranslate above) */
346 glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0);
347 checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
348 if (This->renderUpsideDown) {
349 glMultMatrixf(invymat);
350 checkGLcall("glMultMatrixf(invymat)");
352 This->modelview_valid = FALSE;
353 This->proj_valid = FALSE;
355 This->last_was_rhw = FALSE;
360 static void primitiveConvertToStridedData(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *strided, LONG BaseVertexIndex) {
362 short LoopThroughTo = 0;
364 BOOL canDoViaGLPointers = TRUE;
368 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
369 int numCoords[8]; /* Holding place for D3DFVF_TEXTUREFORMATx */
371 IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
373 /* OK, Now to setup the data locations
374 For the non-created vertex shaders, the VertexShader var holds the real
375 FVF and only stream 0 matters
376 For the created vertex shaders, there is an FVF per stream */
377 if (!This->StateBlock->streamIsUP && (This->UpdateStateBlock->VertexShader > VS_HIGHESTFIXEDFXF)) {
378 LoopThroughTo = MAX_STREAMS;
383 /* Work through stream by stream */
384 for (nStream=0; nStream<LoopThroughTo; nStream++) {
385 DWORD stride = This->StateBlock->stream_stride[nStream];
389 /* Skip empty streams */
390 if (This->StateBlock->stream_source[nStream] == NULL) continue;
392 /* Retrieve appropriate FVF */
393 if (LoopThroughTo == 1) { /* VertexShader is FVF */
394 thisFVF = This->UpdateStateBlock->VertexShader;
395 /* Handle memory passed directly as well as vertex buffers */
396 if (This->StateBlock->streamIsUP) {
397 data = (BYTE *)This->StateBlock->stream_source[nStream];
399 data = ((IDirect3DVertexBuffer8Impl *)This->StateBlock->stream_source[nStream])->allocatedMemory;
402 thisFVF = This->StateBlock->vertexShaderDecl->fvf[nStream];
403 data = ((IDirect3DVertexBuffer8Impl *)This->StateBlock->stream_source[nStream])->allocatedMemory;
405 VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
406 if (thisFVF == 0) continue;
408 /* Now convert the stream into pointers */
410 /* Shuffle to the beginning of the vertexes to render and index from there */
411 data = data + (BaseVertexIndex * stride);
413 /* Either 3 or 4 floats depending on the FVF */
414 /* FIXME: Can blending data be in a different stream to the position data?
415 and if so using the fixed pipeline how do we handle it */
416 if (thisFVF & D3DFVF_POSITION_MASK) {
417 strided->u.s.position.lpData = data;
418 strided->u.s.position.dwType = D3DVSDT_FLOAT3;
419 strided->u.s.position.dwStride = stride;
420 data += 3 * sizeof(float);
421 if (thisFVF & D3DFVF_XYZRHW) {
422 strided->u.s.position.dwType = D3DVSDT_FLOAT4;
423 data += sizeof(float);
427 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
428 /** do we have to Check This->UpdateStateBlock->renderstate[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
429 numBlends = ((thisFVF & D3DFVF_POSITION_MASK) >> 1) - 2 +
430 ((FALSE == (thisFVF & D3DFVF_LASTBETA_UBYTE4)) ? 0 : -1); /* WARNING can be < 0 because -2 */
432 canDoViaGLPointers = FALSE;
433 strided->u.s.blendWeights.lpData = data;
434 strided->u.s.blendWeights.dwType = D3DVSDT_FLOAT1 + (numBlends - 1);
435 strided->u.s.blendWeights.dwStride = stride;
436 data += numBlends * sizeof(FLOAT);
438 if (thisFVF & D3DFVF_LASTBETA_UBYTE4) {
439 strided->u.s.blendMatrixIndices.lpData = data;
440 strided->u.s.blendMatrixIndices.dwType = D3DVSDT_UBYTE4;
441 strided->u.s.blendMatrixIndices.dwStride= stride;
442 data += sizeof(DWORD);
446 /* Normal is always 3 floats */
447 if (thisFVF & D3DFVF_NORMAL) {
448 strided->u.s.normal.lpData = data;
449 strided->u.s.normal.dwType = D3DVSDT_FLOAT3;
450 strided->u.s.normal.dwStride = stride;
451 data += 3 * sizeof(FLOAT);
454 /* Pointsize is a single float */
455 if (thisFVF & D3DFVF_PSIZE) {
456 strided->u.s.pSize.lpData = data;
457 strided->u.s.pSize.dwType = D3DVSDT_FLOAT1;
458 strided->u.s.pSize.dwStride = stride;
459 data += sizeof(FLOAT);
462 /* Diffuse is 4 unsigned bytes */
463 if (thisFVF & D3DFVF_DIFFUSE) {
464 strided->u.s.diffuse.lpData = data;
465 strided->u.s.diffuse.dwType = D3DVSDT_SHORT4;
466 strided->u.s.diffuse.dwStride = stride;
467 data += sizeof(DWORD);
470 /* Specular is 4 unsigned bytes */
471 if (thisFVF & D3DFVF_SPECULAR) {
472 strided->u.s.specular.lpData = data;
473 strided->u.s.specular.dwType = D3DVSDT_SHORT4;
474 strided->u.s.specular.dwStride = stride;
475 data += sizeof(DWORD);
479 numTextures = (thisFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
480 coordIdxInfo = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of D3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
482 /* numTextures indicates the number of texture coordinates supplied */
483 /* However, the first set may not be for stage 0 texture - it all */
484 /* depends on D3DTSS_TEXCOORDINDEX. */
485 /* The number of bytes for each coordinate set is based off */
486 /* D3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
488 /* So, for each supplied texture extract the coords */
489 for (textureNo = 0; textureNo < numTextures; ++textureNo) {
491 strided->u.s.texCoords[textureNo].lpData = data;
492 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT1;
493 strided->u.s.texCoords[textureNo].dwStride = stride;
494 numCoords[textureNo] = coordIdxInfo & 0x03;
497 data += sizeof(float);
498 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT1) {
499 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT2;
500 data += sizeof(float);
501 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT2) {
502 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT3;
503 data += sizeof(float);
504 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT3) {
505 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT4;
506 data += sizeof(float);
510 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
515 /* Draw a single vertex using this information */
516 static void draw_vertex(LPDIRECT3DDEVICE8 iface, /* interface */
517 BOOL isXYZ, float x, float y, float z, float rhw, /* xyzn position*/
518 BOOL isNormal, float nx, float ny, float nz, /* normal */
519 BOOL isDiffuse, float *dRGBA, /* 1st colors */
520 BOOL isSpecular, float *sRGB, /* 2ndry colors */
521 BOOL isPtSize, float ptSize, /* pointSize */
522 D3DVECTOR_4 *texcoords, int *numcoords) /* texture info */
524 unsigned int textureNo;
526 IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
528 /* Diffuse -------------------------------- */
531 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
534 /* Specular Colour ------------------------------------------*/
536 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
537 GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
538 VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
540 VTRACE(("Specular color extensions not supplied\n"));
544 /* Normal -------------------------------- */
546 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
547 glNormal3f(nx, ny, nz);
550 /* Point Size ----------------------------------------------*/
553 /* no such functionality in the fixed function GL pipeline */
554 FIXME("Cannot change ptSize here in openGl\n");
557 /* Texture coords --------------------------- */
558 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
560 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
561 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
565 /* Query tex coords */
566 if (This->StateBlock->textures[textureNo] != NULL) {
568 int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
570 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
572 } else if (numcoords[coordIdx] == 0) {
573 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
577 /* Initialize vars */
583 switch (numcoords[coordIdx]) {
584 case 4: q = texcoords[coordIdx].w; /* drop through */
585 case 3: r = texcoords[coordIdx].z; /* drop through */
586 case 2: t = texcoords[coordIdx].y; /* drop through */
587 case 1: s = texcoords[coordIdx].x;
590 switch (numcoords[coordIdx]) { /* Supply the provided texture coords */
592 VTRACE(("tex:%d, s=%f\n", textureNo, s));
593 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
594 #if defined(GL_VERSION_1_3)
595 glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s);
597 glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s);
604 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
605 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
606 #if defined(GL_VERSION_1_3)
607 glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t);
609 glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t);
616 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
617 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
618 #if defined(GL_VERSION_1_3)
619 glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r);
621 glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r);
624 glTexCoord3f(s, t, r);
628 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
629 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
630 #if defined(GL_VERSION_1_3)
631 glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q);
633 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q);
636 glTexCoord4f(s, t, r, q);
640 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
644 } /* End of textures */
646 /* Position -------------------------------- */
648 if (1.0f == rhw || rhw < 0.00001f) {
649 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
652 /* Cannot optimize by dividing through by rhw as rhw is required
653 later for perspective in the GL pipeline for vertex shaders */
654 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
655 glVertex4f(x,y,z,rhw);
661 * Actually draw using the supplied information.
662 * Faster GL version using pointers to data, harder to debug though
663 * Note does not handle vertex shaders yet
665 static void drawStridedFast(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd,
666 int PrimitiveType, ULONG NumPrimitives,
667 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
668 unsigned int textureNo = 0;
669 GLenum glPrimType = GL_POINTS;
670 int NumVertexes = NumPrimitives;
671 IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
673 TRACE("Using fast vertex array code\n");
675 /* Vertex Pointers -----------------------------------------*/
676 if (sd->u.s.position.lpData != NULL) {
678 /* Note dwType == float3 or float4 == 2 or 3 */
679 VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n",
680 sd->u.s.position.dwStride,
681 sd->u.s.position.dwType + 1,
682 sd->u.s.position.lpData));
684 /* Disable RHW mode as 'w' coord handling for rhw mode should
685 not impact screen position whereas in GL it does. This may
686 result in very slightly distored textures in rhw mode, but
687 a very minimal different */
688 glVertexPointer(3, GL_FLOAT, /* RHW: Was 'sd->u.s.position.dwType + 1' */
689 sd->u.s.position.dwStride,
690 sd->u.s.position.lpData);
691 checkGLcall("glVertexPointer(...)");
692 glEnableClientState(GL_VERTEX_ARRAY);
693 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
697 glDisableClientState(GL_VERTEX_ARRAY);
698 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
701 /* Blend Data ----------------------------------------------*/
702 if ((sd->u.s.blendWeights.lpData != NULL) ||
703 (sd->u.s.blendMatrixIndices.lpData != NULL)) {
704 /* FIXME: Won't get here as will drop to slow method */
705 FIXME("Blending not supported in fast draw routine\n");
707 #if 0 /* Vertex blend support needs to be added */
708 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
710 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
713 GLExtCall(glVertexWeightPointerEXT)(numBlends, GL_FLOAT, skip, curPos);
714 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
715 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
716 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
719 FIXME("unsupported blending in openGl\n");
722 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
724 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
727 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
728 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
734 /* Normals -------------------------------------------------*/
735 if (sd->u.s.normal.lpData != NULL) {
737 /* Note dwType == float3 or float4 == 2 or 3 */
738 VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n",
739 sd->u.s.normal.dwStride,
740 sd->u.s.normal.lpData));
741 glNormalPointer(GL_FLOAT,
742 sd->u.s.normal.dwStride,
743 sd->u.s.normal.lpData);
744 checkGLcall("glNormalPointer(...)");
745 glEnableClientState(GL_NORMAL_ARRAY);
746 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
750 glDisableClientState(GL_NORMAL_ARRAY);
751 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
753 checkGLcall("glNormal3f(0, 0, 1)");
756 /* Point Size ----------------------------------------------*/
757 if (sd->u.s.pSize.lpData != NULL) {
759 /* no such functionality in the fixed function GL pipeline */
760 /* FIXME: Won't get here as will drop to slow method */
761 FIXME("Cannot change ptSize here in openGl\n");
764 /* Diffuse Colour ------------------------------------------*/
765 /* WARNING: Data here MUST be in RGBA format, so cannot */
766 /* go directly into fast mode from app pgm, because */
767 /* directx requires data in BGRA format. */
768 if (sd->u.s.diffuse.lpData != NULL) {
770 /* Note dwType == float3 or float4 == 2 or 3 */
771 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
772 sd->u.s.diffuse.dwStride,
773 sd->u.s.diffuse.lpData));
774 glColorPointer(4, GL_UNSIGNED_BYTE,
775 sd->u.s.diffuse.dwStride,
776 sd->u.s.diffuse.lpData);
777 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
778 glEnableClientState(GL_COLOR_ARRAY);
779 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
783 glDisableClientState(GL_COLOR_ARRAY);
784 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
785 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
786 checkGLcall("glColor4f(1, 1, 1, 1)");
789 /* Specular Colour ------------------------------------------*/
790 if (sd->u.s.specular.lpData != NULL) {
792 /* Note dwType == float3 or float4 == 2 or 3 */
793 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
794 sd->u.s.specular.dwStride,
795 sd->u.s.specular.lpData));
797 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
798 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
799 sd->u.s.specular.dwStride,
800 sd->u.s.specular.lpData);
801 vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
802 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
803 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
805 /* Missing specular color is not critical, no warnings */
806 VTRACE(("Specular colour is not supported in this GL implementation\n"));
811 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
812 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
813 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
814 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
815 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
817 /* Missing specular color is not critical, no warnings */
818 VTRACE(("Specular colour is not supported in this GL implementation\n"));
822 /* Texture coords -------------------------------------------*/
823 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
825 /* Select the correct texture stage */
826 #if defined(GL_VERSION_1_3)
827 glClientActiveTexture(GL_TEXTURE0 + textureNo);
829 glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo);
832 /* Query tex coords */
833 if (This->StateBlock->textures[textureNo] != NULL) {
834 int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
836 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
837 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
838 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
839 #if defined(GL_VERSION_1_3)
840 glMultiTexCoord4f(GL_TEXTURE0 + textureNo, 0, 0, 0, 1);
842 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
848 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
849 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
850 #if defined(GL_VERSION_1_3)
851 glMultiTexCoord4f(GL_TEXTURE0 + textureNo, 0, 0, 0, 1);
853 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
855 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
856 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
857 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
858 #if defined(GL_VERSION_1_3)
859 glMultiTexCoord4f(GL_TEXTURE0 + textureNo, 0, 0, 0, 1);
861 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
865 /* The coords to supply depend completely on the fvf / vertex shader */
869 switch (sd->u.s.texCoords[coordIdx].dwType) {
870 case D3DVSDT_FLOAT1: size = 1, type = GL_FLOAT; break;
871 case D3DVSDT_FLOAT2: size = 2, type = GL_FLOAT; break;
872 case D3DVSDT_FLOAT3: size = 3, type = GL_FLOAT; break;
873 case D3DVSDT_FLOAT4: size = 4, type = GL_FLOAT; break;
874 case D3DVSDT_SHORT2: size = 2, type = GL_SHORT; break;
875 case D3DVSDT_SHORT4: size = 4, type = GL_SHORT; break;
876 case D3DVSDT_UBYTE4: size = 4, type = GL_UNSIGNED_BYTE; break;
877 default: FIXME("Unrecognized data type %ld\n", sd->u.s.texCoords[coordIdx].dwType);
878 size = 4; type = GL_UNSIGNED_BYTE;
881 glTexCoordPointer(size, type, sd->u.s.texCoords[coordIdx].dwStride, sd->u.s.texCoords[coordIdx].lpData);
882 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
885 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
886 #if defined(GL_VERSION_1_3)
887 glMultiTexCoord4f(GL_TEXTURE0 + textureNo, 0, 0, 0, 1);
889 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
894 /* Ok, Work out which primitive is requested and how many vertexes that
896 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
898 /* Finally do the drawing */
899 if (idxData != NULL) {
901 TRACE("glElements(%x, %d, %ld, ...)\n", glPrimType, NumVertexes, minIndex);
902 #if 1 /* FIXME: Want to use DrawRangeElements, but wrong calculation! */
903 glDrawElements(glPrimType, NumVertexes, idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
904 (const char *)idxData+(idxSize * startIdx));
906 glDrawRangeElements(glPrimType, minIndex, minIndex+NumVertexes-1, NumVertexes,
907 idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
908 (const char *)idxData+(idxSize * startIdx));
910 checkGLcall("glDrawRangeElements");
914 /* Note first is now zero as we shuffled along earlier */
915 TRACE("glDrawArrays(%x, 0, %d)\n", glPrimType, NumVertexes);
916 glDrawArrays(glPrimType, 0, NumVertexes);
917 checkGLcall("glDrawArrays");
923 * Actually draw using the supplied information.
924 * Slower GL version which extracts info about each vertex in turn
926 static void drawStridedSlow(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd,
927 int PrimitiveType, ULONG NumPrimitives,
928 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
930 unsigned int textureNo = 0;
931 GLenum glPrimType = GL_POINTS;
932 int NumVertexes = NumPrimitives;
933 const short *pIdxBufS = NULL;
934 const long *pIdxBufL = NULL;
935 LONG SkipnStrides = 0;
937 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
938 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
939 float rhw = 0.0f; /* rhw */
940 float ptSize = 0.0f; /* Point size */
941 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
942 DWORD specularColor = 0; /* Specular Color */
943 IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
945 TRACE("Using slow vertex array code\n");
947 /* Variable Initialization */
948 if (idxData != NULL) {
949 if (idxSize == 2) pIdxBufS = (const short *) idxData;
950 else pIdxBufL = (const long *) idxData;
953 /* Ok, Work out which primitive is requested and how many vertexes that will be */
954 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
956 /* Start drawing in GL */
957 VTRACE(("glBegin(%x)\n", glPrimType));
960 /* For each primitive */
961 for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
963 /* Initialize diffuse color */
964 diffuseColor = 0xFFFFFFFF;
966 /* For indexed data, we need to go a few more strides in */
967 if (idxData != NULL) {
969 /* Indexed so work out the number of strides to skip */
971 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
972 SkipnStrides = pIdxBufS[startIdx+vx_index];
974 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
975 SkipnStrides = pIdxBufL[startIdx+vx_index];
979 /* Position Information ------------------ */
980 if (sd->u.s.position.lpData != NULL) {
982 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
987 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
989 /* RHW follows, only if transformed, ie 4 floats were provided */
990 if (sd->u.s.position.dwType == D3DVSDT_FLOAT4) {
991 rhw = ptrToCoords[3];
992 VTRACE(("rhw=%f\n", rhw));
996 /* Blending data -------------------------- */
997 if (sd->u.s.blendWeights.lpData != NULL) {
998 /*float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride));*/
999 FIXME("Blending not supported yet\n");
1001 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
1002 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
1006 /* Vertex Normal Data (untransformed only)- */
1007 if (sd->u.s.normal.lpData != NULL) {
1009 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
1010 nx = ptrToCoords[0];
1011 ny = ptrToCoords[1];
1012 nz = ptrToCoords[2];
1013 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
1016 /* Point Size ----------------------------- */
1017 if (sd->u.s.pSize.lpData != NULL) {
1019 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1020 ptSize = ptrToCoords[0];
1021 VTRACE(("ptSize=%f\n", ptSize));
1022 FIXME("No support for ptSize yet\n");
1025 /* Diffuse -------------------------------- */
1026 if (sd->u.s.diffuse.lpData != NULL) {
1028 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1029 diffuseColor = ptrToCoords[0];
1030 VTRACE(("diffuseColor=%lx\n", diffuseColor));
1033 /* Specular -------------------------------- */
1034 if (sd->u.s.specular.lpData != NULL) {
1036 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1037 specularColor = ptrToCoords[0];
1038 VTRACE(("specularColor=%lx\n", specularColor));
1041 /* Texture coords --------------------------- */
1042 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1044 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1045 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1049 /* Query tex coords */
1050 if (This->StateBlock->textures[textureNo] != NULL) {
1052 int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
1055 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1057 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1058 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1062 float* ptrToCoords = (float*) (sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1063 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DVSDT_FLOAT1 etc */
1064 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1066 /* The coords to supply depend completely on the fvf / vertex shader */
1067 switch (coordsToUse) {
1068 case 4: q = ptrToCoords[3]; /* drop through */
1069 case 3: r = ptrToCoords[2]; /* drop through */
1070 case 2: t = ptrToCoords[1]; /* drop through */
1071 case 1: s = ptrToCoords[0];
1074 /* Projected is more 'fun' - Move the last coord to the 'q'
1075 parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1076 if ((This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1077 (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1079 if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1080 switch (coordsToUse) {
1081 case 0: /* Drop Through */
1083 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1095 case 4: /* Nop here */
1098 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n",
1099 This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1104 switch (coordsToUse) { /* Supply the provided texture coords */
1105 case D3DTTFF_COUNT1:
1106 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1107 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1108 #if defined(GL_VERSION_1_3)
1109 glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s);
1111 glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s);
1117 case D3DTTFF_COUNT2:
1118 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1119 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1120 #if defined(GL_VERSION_1_3)
1121 glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t);
1123 glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t);
1129 case D3DTTFF_COUNT3:
1130 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1131 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1132 #if defined(GL_VERSION_1_3)
1133 glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r);
1135 glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r);
1138 glTexCoord3f(s, t, r);
1141 case D3DTTFF_COUNT4:
1142 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1143 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1144 #if defined(GL_VERSION_1_3)
1145 glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q);
1147 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q);
1150 glTexCoord4f(s, t, r, q);
1154 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1158 } /* End of textures */
1160 /* Diffuse -------------------------------- */
1161 if (sd->u.s.diffuse.lpData != NULL) {
1162 glColor4ub((diffuseColor >> 16) & 0xFF,
1163 (diffuseColor >> 8) & 0xFF,
1164 (diffuseColor >> 0) & 0xFF,
1165 (diffuseColor >> 24) & 0xFF);
1166 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n",
1167 ((diffuseColor >> 16) & 0xFF) / 255.0f,
1168 ((diffuseColor >> 8) & 0xFF) / 255.0f,
1169 ((diffuseColor >> 0) & 0xFF) / 255.0f,
1170 ((diffuseColor >> 24) & 0xFF) / 255.0f));
1172 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1175 /* Specular ------------------------------- */
1176 if (sd->u.s.diffuse.lpData != NULL) {
1177 VTRACE(("glSecondaryColor4ub: r,g,b=%f,%f,%f\n",
1178 ((specularColor >> 16) & 0xFF) / 255.0f,
1179 ((specularColor >> 8) & 0xFF) / 255.0f,
1180 ((specularColor >> 0) & 0xFF) / 255.0f));
1181 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1182 GL_EXTCALL(glSecondaryColor3ubEXT)(
1183 (specularColor >> 16) & 0xFF,
1184 (specularColor >> 8) & 0xFF,
1185 (specularColor >> 0) & 0xFF);
1187 /* Do not worry if specular colour missing and disable request */
1188 VTRACE(("Specular color extensions not supplied\n"));
1191 if (vx_index == 0) {
1192 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1193 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1195 /* Do not worry if specular colour missing and disable request */
1196 VTRACE(("Specular color extensions not supplied\n"));
1201 /* Normal -------------------------------- */
1202 if (sd->u.s.normal.lpData != NULL) {
1203 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1204 glNormal3f(nx, ny, nz);
1206 if (vx_index == 0) glNormal3f(0, 0, 1);
1209 /* Position -------------------------------- */
1210 if (sd->u.s.position.lpData != NULL) {
1211 if (1.0f == rhw || ((rhw < 0.0001f) && (rhw > -0.0001f))) {
1212 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1213 glVertex3f(x, y, z);
1215 GLfloat w = 1.0 / rhw;
1216 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1217 glVertex4f(x*w, y*w, z*w, w);
1221 /* For non indexed mode, step onto next parts */
1222 if (idxData == NULL) {
1228 checkGLcall("glEnd and previous calls");
1232 * Draw with emulated vertex shaders
1233 * Note: strided data is uninitialized, as we need to pass the vertex
1234 * shader directly as ordering irs yet
1236 static void drawStridedSoftwareVS(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd,
1237 int PrimitiveType, ULONG NumPrimitives,
1238 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1240 unsigned int textureNo = 0;
1241 GLenum glPrimType = GL_POINTS;
1242 int NumVertexes = NumPrimitives;
1243 const short *pIdxBufS = NULL;
1244 const long *pIdxBufL = NULL;
1245 LONG SkipnStrides = 0;
1247 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1248 float rhw = 0.0f; /* rhw */
1249 float ptSize = 0.0f; /* Point size */
1250 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1251 int numcoords[8]; /* Number of coords */
1252 IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
1254 IDirect3DVertexShaderImpl* vertex_shader = NULL;
1256 TRACE("Using slow software vertex shader code\n");
1258 /* Variable Initialization */
1259 if (idxData != NULL) {
1260 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1261 else pIdxBufL = (const long *) idxData;
1264 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1265 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1267 /* Retrieve the VS information */
1268 vertex_shader = VERTEX_SHADER(This->StateBlock->VertexShader);
1270 /* Start drawing in GL */
1271 VTRACE(("glBegin(%x)\n", glPrimType));
1272 glBegin(glPrimType);
1274 /* For each primitive */
1275 for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
1277 /* For indexed data, we need to go a few more strides in */
1278 if (idxData != NULL) {
1280 /* Indexed so work out the number of strides to skip */
1282 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1283 SkipnStrides = pIdxBufS[startIdx+vx_index];
1285 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1286 SkipnStrides = pIdxBufL[startIdx+vx_index];
1290 /* Fill the vertex shader input */
1291 IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertex_shader, SkipnStrides);
1293 /* Initialize the output fields to the same defaults as it would normally have */
1294 memset(&vertex_shader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1295 vertex_shader->output.oD[0].x = 1.0;
1296 vertex_shader->output.oD[0].y = 1.0;
1297 vertex_shader->output.oD[0].z = 1.0;
1298 vertex_shader->output.oD[0].w = 1.0;
1300 /* Now execute the vertex shader */
1301 IDirect3DVertexShaderImpl_ExecuteSW(vertex_shader, &vertex_shader->input, &vertex_shader->output);
1304 TRACE_VECTOR(vertex_shader->output.oPos);
1305 TRACE_VECTOR(vertex_shader->output.oD[0]);
1306 TRACE_VECTOR(vertex_shader->output.oD[1]);
1307 TRACE_VECTOR(vertex_shader->output.oT[0]);
1308 TRACE_VECTOR(vertex_shader->output.oT[1]);
1309 TRACE_VECTOR(vertex_shader->input.V[0]);
1310 TRACE_VECTOR(vertex_shader->data->C[0]);
1311 TRACE_VECTOR(vertex_shader->data->C[1]);
1312 TRACE_VECTOR(vertex_shader->data->C[2]);
1313 TRACE_VECTOR(vertex_shader->data->C[3]);
1314 TRACE_VECTOR(vertex_shader->data->C[4]);
1315 TRACE_VECTOR(vertex_shader->data->C[5]);
1316 TRACE_VECTOR(vertex_shader->data->C[6]);
1317 TRACE_VECTOR(vertex_shader->data->C[7]);
1320 /* Extract out the output */
1321 /*FIXME: Fog coords? */
1322 x = vertex_shader->output.oPos.x;
1323 y = vertex_shader->output.oPos.y;
1324 z = vertex_shader->output.oPos.z;
1325 rhw = vertex_shader->output.oPos.w;
1326 ptSize = vertex_shader->output.oPts.x; /* Fixme - Is this right? */
1328 /** Update textures coords using vertex_shader->output.oT[0->7] */
1329 memset(texcoords, 0x00, sizeof(texcoords));
1330 memset(numcoords, 0x00, sizeof(numcoords));
1331 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1332 if (This->StateBlock->textures[textureNo] != NULL) {
1333 texcoords[textureNo].x = vertex_shader->output.oT[textureNo].x;
1334 texcoords[textureNo].y = vertex_shader->output.oT[textureNo].y;
1335 texcoords[textureNo].z = vertex_shader->output.oT[textureNo].z;
1336 texcoords[textureNo].w = vertex_shader->output.oT[textureNo].w;
1337 if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1338 numcoords[textureNo] = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1340 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->StateBlock->textures[textureNo])) {
1341 case D3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1342 case D3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1343 default: numcoords[textureNo] = 4;
1347 numcoords[textureNo] = 0;
1351 /* Draw using this information */
1354 TRUE, 0.0f, 0.0f, 1.0f,
1355 TRUE, (float*) &vertex_shader->output.oD[0],
1356 TRUE, (float*) &vertex_shader->output.oD[1],
1357 FALSE, ptSize, /* FIXME: Change back when supported */
1358 texcoords, numcoords);
1360 /* For non indexed mode, step onto next parts */
1361 if (idxData == NULL) {
1365 } /* for each vertex */
1368 checkGLcall("glEnd and previous calls");
1371 static void drawStridedHardwareVS(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd,
1372 int PrimitiveType, ULONG NumPrimitives,
1373 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1375 IDirect3DVertexShaderImpl* vertex_shader = NULL;
1381 IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
1382 TRACE("Drawing with hardware vertex shaders\n");
1384 /* Retrieve the VS information */
1385 vertex_shader = VERTEX_SHADER(This->StateBlock->VertexShader);
1387 /* Enable the Vertex Shader */
1388 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertex_shader->prgId));
1389 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertex_shader->prgId);");
1390 glEnable(GL_VERTEX_PROGRAM_ARB);
1391 checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
1393 /* Update the constants */
1394 for (i=0; i<D3D8_VSHADER_MAX_CONSTANTS; i++) {
1395 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, i, (GLfloat *)&This->StateBlock->vertexShaderConstant[i]));
1396 checkGLcall("glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB");
1399 /* Set up the vertex.attr[n] inputs */
1400 IDirect3DDeviceImpl_FillVertexShaderInputArbHW(This, vertex_shader, 0);
1402 /* Ok, Work out which primitive is requested and how many vertexes that
1404 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1406 /* Finally do the drawing */
1407 if (idxData != NULL) {
1409 TRACE("glElements(%x, %d, %ld, ...)\n", glPrimType, NumVertexes, minIndex);
1410 #if 1 /* FIXME: Want to use DrawRangeElements, but wrong calculation! */
1411 glDrawElements(glPrimType, NumVertexes, idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
1412 (const char *)idxData+(idxSize * startIdx));
1414 glDrawRangeElements(glPrimType, minIndex, minIndex+NumVertexes-1, NumVertexes,
1415 idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
1416 (const char *)idxData+(idxSize * startIdx));
1418 checkGLcall("glDrawRangeElements");
1422 /* Note first is now zero as we shuffled along earlier */
1423 TRACE("glDrawArrays(%x, 0, %d)\n", glPrimType, NumVertexes);
1424 glDrawArrays(glPrimType, 0, NumVertexes);
1425 checkGLcall("glDrawArrays");
1431 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
1433 FIXME("HW VertexShader Error at position: %d\n%s\n", errPos, glGetString( GL_PROGRAM_ERROR_STRING_ARB) );
1437 /* Leave all the attribs disabled */
1438 glGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
1439 /* MESA does not support it right not */
1440 if (glGetError() != GL_NO_ERROR)
1442 for (i=0; i<maxAttribs; i++) {
1443 GL_EXTCALL(glDisableVertexAttribArrayARB(i));
1444 checkGLcall("glDisableVertexAttribArrayARB(reg);");
1448 glDisable(GL_VERTEX_PROGRAM_ARB);
1451 /* Routine common to the draw primitive and draw indexed primitive routines */
1452 void drawPrimitive(LPDIRECT3DDEVICE8 iface,
1453 int PrimitiveType, long NumPrimitives,
1456 long StartVertexIndex,
1459 const void *idxData,
1464 IDirect3DVertexShaderImpl *vertex_shader = NULL;
1465 IDirect3DPixelShaderImpl *pixel_shader = NULL;
1466 BOOL useVertexShaderFunction = FALSE;
1467 BOOL isLightingOn = FALSE;
1468 Direct3DVertexStridedData dataLocations;
1469 IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
1473 /* Work out what the FVF should look like */
1474 rc = initializeFVF(iface, &fvf, &useVertexShaderFunction);
1477 /* If we will be using a vertex shader, do some initialization for it */
1478 if (useVertexShaderFunction) {
1479 vertex_shader = VERTEX_SHADER(This->UpdateStateBlock->VertexShader);
1480 memset(&vertex_shader->input, 0, sizeof(VSHADERINPUTDATA8));
1482 useHW = (((vs_mode == VS_HW) && GL_SUPPORT(ARB_VERTEX_PROGRAM)) &&
1483 This->devType != D3DDEVTYPE_REF &&
1484 !This->StateBlock->renderstate[D3DRS_SOFTWAREVERTEXPROCESSING] &&
1485 vertex_shader->usage != D3DUSAGE_SOFTWAREPROCESSING);
1487 /** init Constants */
1488 if (This->UpdateStateBlock->Changed.vertexShaderConstant) {
1489 TRACE_(d3d_shader)("vertex shader initializing constants\n");
1490 IDirect3DVertexShaderImpl_SetConstantF(vertex_shader, 0, (CONST FLOAT*) &This->UpdateStateBlock->vertexShaderConstant[0], 96);
1494 /* Ok, we will be updating the screen from here onwards so grab the lock */
1497 /* If we will be using a pixel, do some initialization for it */
1498 if ((pixel_shader = PIXEL_SHADER(This->UpdateStateBlock->PixelShader))) {
1499 TRACE("drawing with pixel shader handle %p\n", pixel_shader);
1500 memset(&pixel_shader->input, 0, sizeof(PSHADERINPUTDATA8));
1502 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixel_shader->prgId));
1503 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixel_shader->prgId);");
1504 glEnable(GL_FRAGMENT_PROGRAM_ARB);
1505 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
1507 /* init Constants */
1508 if (This->UpdateStateBlock->Changed.pixelShaderConstant) {
1509 TRACE_(d3d_shader)("pixel shader initializing constants %p\n",pixel_shader);
1510 IDirect3DPixelShaderImpl_SetConstantF(pixel_shader, 0, (CONST FLOAT*) &This->UpdateStateBlock->pixelShaderConstant[0], 8);
1512 /* Update the constants */
1513 for (i=0; i<D3D8_PSHADER_MAX_CONSTANTS; i++) {
1514 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, (GLfloat *)&This->StateBlock->pixelShaderConstant[i]));
1515 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB");
1519 /* Setup transform matrices and sort out */
1521 /* Lighting is not completely bypassed with ATI drivers although it should be. Mesa is ok from this respect...
1522 So make sure lighting is disabled. */
1523 isLightingOn = glIsEnabled(GL_LIGHTING);
1524 glDisable(GL_LIGHTING);
1525 checkGLcall("glDisable(GL_LIGHTING);");
1526 TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn);
1528 isLightingOn = primitiveInitState(iface,
1529 fvf & D3DFVF_XYZRHW,
1530 !(fvf & D3DFVF_NORMAL),
1531 useVertexShaderFunction);
1533 /* Initialize all values to null */
1534 if (useVertexShaderFunction == FALSE) {
1535 memset(&dataLocations, 0x00, sizeof(dataLocations));
1537 /* Convert to strided data */
1538 primitiveConvertToStridedData(iface, &dataLocations, StartVertexIndex);
1540 /* Dump out what parts we have supplied */
1541 TRACE("Strided Data (from FVF/VS): %lx\n", fvf);
1542 TRACE_STRIDED((&dataLocations), position);
1543 TRACE_STRIDED((&dataLocations), blendWeights);
1544 TRACE_STRIDED((&dataLocations), blendMatrixIndices);
1545 TRACE_STRIDED((&dataLocations), normal);
1546 TRACE_STRIDED((&dataLocations), pSize);
1547 TRACE_STRIDED((&dataLocations), diffuse);
1548 TRACE_STRIDED((&dataLocations), specular);
1549 TRACE_STRIDED((&dataLocations), texCoords[0]);
1550 TRACE_STRIDED((&dataLocations), texCoords[1]);
1551 TRACE_STRIDED((&dataLocations), texCoords[2]);
1552 TRACE_STRIDED((&dataLocations), texCoords[3]);
1553 TRACE_STRIDED((&dataLocations), texCoords[4]);
1554 TRACE_STRIDED((&dataLocations), texCoords[5]);
1555 TRACE_STRIDED((&dataLocations), texCoords[6]);
1556 TRACE_STRIDED((&dataLocations), texCoords[7]);
1559 /* Now initialize the materials state */
1560 init_materials(iface, (dataLocations.u.s.diffuse.lpData != NULL));
1562 /* And re-upload any dirty textures */
1563 for (i=0; i<GL_LIMITS(textures); i++) {
1565 if ((This->StateBlock->textures[i] != NULL) &&
1566 (IDirect3DBaseTexture8Impl_IsDirty(This->StateBlock->textures[i])))
1568 /* Load up the texture now */
1569 IDirect3DTexture8Impl_PreLoad((LPDIRECT3DTEXTURE8) This->StateBlock->textures[i]);
1573 /* Now draw the graphics to the screen */
1574 if (useVertexShaderFunction) {
1576 /* Ideally, we should have software FV and hardware VS, possibly
1577 depending on the device type? */
1580 TRACE("Swap HW vertex shader\n");
1581 drawStridedHardwareVS(iface, &dataLocations, PrimitiveType, NumPrimitives,
1582 idxData, idxSize, minIndex, StartIdx);
1584 /* We will have to use the very, very slow emulation layer */
1585 TRACE("Swap SW vertex shader\n");
1586 drawStridedSoftwareVS(iface, &dataLocations, PrimitiveType, NumPrimitives,
1587 idxData, idxSize, minIndex, StartIdx);
1590 } else if ((dataLocations.u.s.pSize.lpData != NULL) ||
1591 (dataLocations.u.s.diffuse.lpData != NULL) ||
1592 (dataLocations.u.s.blendWeights.lpData != NULL)) {
1594 /* Fixme, Ideally, only use the per-vertex code for software HAL
1595 but until opengl supports all the functions returned to setup
1596 vertex arrays, we need to drop down to the slow mechanism for
1597 certain functions */
1599 /* We will have to use the slow version of GL per vertex setup */
1600 drawStridedSlow(iface, &dataLocations, PrimitiveType, NumPrimitives,
1601 idxData, idxSize, minIndex, StartIdx);
1605 /* We can use the fast version of GL pointers */
1606 drawStridedFast(iface, &dataLocations, PrimitiveType, NumPrimitives,
1607 idxData, idxSize, minIndex, StartIdx);
1610 /* If vertex shaders or no normals, restore previous lighting state */
1611 if (useVertexShaderFunction || !(fvf & D3DFVF_NORMAL)) {
1612 if (isLightingOn) glEnable(GL_LIGHTING);
1613 else glDisable(GL_LIGHTING);
1614 TRACE("Restored lighting to original state\n");
1621 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
1623 FIXME("HW PixelShader Error at position: %d\n%s\n", errPos, glGetString( GL_PROGRAM_ERROR_STRING_ARB) );
1625 glDisable(GL_FRAGMENT_PROGRAM_ARB);
1628 /* Finshed updating the screen, restore lock */
1630 TRACE("Done all gl drawing\n");
1633 #if defined(SHOW_FRAME_MAKEUP)
1635 if (isDumpingFrames) {
1638 IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) This->renderTarget, &r, NULL, D3DLOCK_READONLY);
1639 sprintf(buffer, "/tmp/backbuffer_%ld.ppm", primCounter);
1640 TRACE("Saving screenshot %s\n", buffer);
1641 IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This->renderTarget, buffer);
1642 IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) This->renderTarget);
1644 #if defined(SHOW_TEXTURE_MAKEUP)
1646 LPDIRECT3DSURFACE8 pSur;
1648 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1649 if (This->StateBlock->textures[textureNo] != NULL) {
1650 sprintf(buffer, "/tmp/texture_%ld_%d.ppm", primCounter, textureNo);
1651 TRACE("Saving texture %s (Format:%s)\n", buffer, debug_d3dformat(((IDirect3DBaseTexture8Impl *)This->StateBlock->textures[textureNo])->format));
1652 IDirect3DTexture8Impl_GetSurfaceLevel((LPDIRECT3DTEXTURE8) This->StateBlock->textures[textureNo], 0, &pSur);
1653 IDirect3DSurface8Impl_SaveSnapshot(pSur, buffer);
1654 IDirect3DSurface8Impl_Release(pSur);
1659 primCounter = primCounter + 1;