2 * WINED3D draw functions
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
24 #include "wined3d_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
27 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
28 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
31 extern IDirect3DVertexShaderImpl* VertexShaders[64];
32 extern IDirect3DVertexShaderDeclarationImpl* VertexShaderDeclarations[64];
33 extern IDirect3DPixelShaderImpl* PixelShaders[64];
35 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
38 /* Useful internal structure, holding place for 4 floats */
39 typedef struct _D3DVECTOR_4 {
47 /* Returns bits for what is expected from the fixed function pipeline, and whether
48 a vertex shader will be in use. Note the fvf bits returned may be split over
49 multiple streams only if the vertex shader was created, otherwise it all relates
51 BOOL initializeFVF(IWineD3DDevice *iface,
52 DWORD *FVFbits, /* What to expect in the FVF across all streams */
53 BOOL *useVertexShaderFunction) /* Should we use the vertex shader */
56 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
58 #if 0 /* TODO: d3d8 call setvertexshader needs to set the FVF in the state block when implemented */
59 /* The first thing to work out is if we are using the fixed function pipeline
60 which is either SetVertexShader with < VS_HIGHESTFIXEDFXF - in which case this
61 is the FVF, or with a shader which was created with no function - in which
62 case there is an FVF per declared stream. If this occurs, we also maintain
63 an 'OR' of all the FVF's together so we know what to expect across all the
67 if (This->updateStateBlock->vertexShader == NULL) {
69 /* Use this as the FVF */
70 *FVFbits = This->updateStateBlock->fvf;
71 *useVertexShaderFunction = FALSE;
72 TRACE("FVF explicitally defined, using fixed function pipeline with FVF=%lx\n", *FVFbits);
77 /* Use created shader */
78 IDirect3DVertexShaderImpl* vertex_shader = NULL;
79 vertex_shader = VERTEX_SHADER(This->updateStateBlock->VertexShader);
81 if (vertex_shader == NULL) {
83 /* Hmm - User pulled figure out of the air? Unlikely, probably a bug */
84 ERR("trying to use unitialised vertex shader: %lu\n", This->updateStateBlock->VertexShader);
89 *FVFbits = This->updateStateBlock->vertexShaderDecl->allFVF;
91 if (vertex_shader->function == NULL) {
92 /* No function, so many streams supplied plus FVF definition pre stream */
93 *useVertexShaderFunction = FALSE;
94 TRACE("vertex shader (%lx) declared without program, using fixed function pipeline with FVF=%lx\n",
95 This->stateBlock->VertexShader, *FVFbits);
97 /* Vertex shader needs calling */
98 *useVertexShaderFunction = TRUE;
99 TRACE("vertex shader will be used (unusued FVF=%lx)\n", *FVFbits);
103 FIXME("Vertex Shaders not moved into wined3d yet\n");
109 /* Issues the glBegin call for gl given the primitive type and count */
110 DWORD primitiveToGl(D3DPRIMITIVETYPE PrimitiveType,
114 DWORD NumVertexes = NumPrimitives;
116 switch (PrimitiveType) {
117 case D3DPT_POINTLIST:
119 *primType = GL_POINTS;
120 NumVertexes = NumPrimitives;
125 *primType = GL_LINES;
126 NumVertexes = NumPrimitives * 2;
129 case D3DPT_LINESTRIP:
130 TRACE("LINE_STRIP\n");
131 *primType = GL_LINE_STRIP;
132 NumVertexes = NumPrimitives + 1;
135 case D3DPT_TRIANGLELIST:
136 TRACE("TRIANGLES\n");
137 *primType = GL_TRIANGLES;
138 NumVertexes = NumPrimitives * 3;
141 case D3DPT_TRIANGLESTRIP:
142 TRACE("TRIANGLE_STRIP\n");
143 *primType = GL_TRIANGLE_STRIP;
144 NumVertexes = NumPrimitives + 2;
147 case D3DPT_TRIANGLEFAN:
148 TRACE("TRIANGLE_FAN\n");
149 *primType = GL_TRIANGLE_FAN;
150 NumVertexes = NumPrimitives + 2;
154 FIXME("Unhandled primitive\n");
155 *primType = GL_POINTS;
161 /* Ensure the appropriate material states are set up - only change
162 state if really required */
163 void init_materials(IWineD3DDevice *iface, BOOL isDiffuseSupplied) {
165 BOOL requires_material_reset = FALSE;
166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
168 if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied) {
169 /* If we have not set up the material color tracking, do it now as required */
170 glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
171 checkGLcall("glDisable GL_COLOR_MATERIAL");
172 TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
173 glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
174 checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
175 glEnable(GL_COLOR_MATERIAL);
176 checkGLcall("glEnable GL_COLOR_MATERIAL");
177 This->tracking_color = IS_TRACKING;
178 requires_material_reset = TRUE; /* Restore material settings as will be used */
180 } else if ((This->tracking_color == IS_TRACKING && isDiffuseSupplied == FALSE) ||
181 (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == FALSE)) {
182 /* If we are tracking the current color but one isn't supplied, don't! */
183 glDisable(GL_COLOR_MATERIAL);
184 checkGLcall("glDisable GL_COLOR_MATERIAL");
185 This->tracking_color = NEEDS_TRACKING;
186 requires_material_reset = TRUE; /* Restore material settings as will be used */
188 } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied) {
189 /* No need to reset material colors since no change to gl_color_material */
190 requires_material_reset = FALSE;
192 } else if (This->tracking_color == NEEDS_DISABLE) {
193 glDisable(GL_COLOR_MATERIAL);
194 checkGLcall("glDisable GL_COLOR_MATERIAL");
195 This->tracking_color = DISABLED_TRACKING;
196 requires_material_reset = TRUE; /* Restore material settings as will be used */
199 /* Reset the material colors which may have been tracking the color*/
200 if (requires_material_reset) {
201 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->stateBlock->material.Ambient);
202 checkGLcall("glMaterialfv");
203 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->stateBlock->material.Diffuse);
204 checkGLcall("glMaterialfv");
205 if (This->stateBlock->renderState[D3DRS_SPECULARENABLE]) {
206 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->stateBlock->material.Specular);
207 checkGLcall("glMaterialfv");
209 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
210 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
211 checkGLcall("glMaterialfv");
213 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->stateBlock->material.Emissive);
214 checkGLcall("glMaterialfv");
219 static GLfloat invymat[16]={
220 1.0f, 0.0f, 0.0f, 0.0f,
221 0.0f, -1.0f, 0.0f, 0.0f,
222 0.0f, 0.0f, 1.0f, 0.0f,
223 0.0f, 0.0f, 0.0f, 1.0f};
225 /* Setup views - Transformed & lit if RHW, else untransformed.
226 Only unlit if Normals are supplied
227 Returns: Whether to restore lighting afterwards */
228 BOOL primitiveInitState(IWineD3DDevice *iface, BOOL vtx_transformed, BOOL vtx_lit, BOOL useVS) {
230 BOOL isLightingOn = FALSE;
231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
233 /* If no normals, DISABLE lighting otherwise, don't touch lighing as it is
234 set by the appropriate render state. Note Vertex Shader output is already lit */
235 if (vtx_lit || useVS) {
236 isLightingOn = glIsEnabled(GL_LIGHTING);
237 glDisable(GL_LIGHTING);
238 checkGLcall("glDisable(GL_LIGHTING);");
239 TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn);
242 if (!useVS && vtx_transformed) {
244 /* If the last draw was transformed as well, no need to reapply all the matrixes */
245 if (!This->last_was_rhw) {
247 double X, Y, height, width, minZ, maxZ;
248 This->last_was_rhw = TRUE;
250 /* Transformed already into viewport coordinates, so we do not need transform
251 matrices. Reset all matrices to identity and leave the default matrix in world
253 glMatrixMode(GL_MODELVIEW);
254 checkGLcall("glMatrixMode");
256 checkGLcall("glLoadIdentity");
258 glMatrixMode(GL_PROJECTION);
259 checkGLcall("glMatrixMode");
261 checkGLcall("glLoadIdentity");
263 /* Set up the viewport to be full viewport */
264 X = This->stateBlock->viewport.X;
265 Y = This->stateBlock->viewport.Y;
266 height = This->stateBlock->viewport.Height;
267 width = This->stateBlock->viewport.Width;
268 minZ = This->stateBlock->viewport.MinZ;
269 maxZ = This->stateBlock->viewport.MaxZ;
270 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
271 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
272 checkGLcall("glOrtho");
274 /* Window Coord 0 is the middle of the first pixel, so translate by half
275 a pixel (See comment above glTranslate below) */
276 glTranslatef(0.5, 0.5, 0);
277 checkGLcall("glTranslatef(0.5, 0.5, 0)");
278 if (This->renderUpsideDown) {
279 glMultMatrixf(invymat);
280 checkGLcall("glMultMatrixf(invymat)");
286 /* Untransformed, so relies on the view and projection matrices */
288 if (!useVS && (This->last_was_rhw || !This->modelview_valid)) {
289 /* Only reapply when have to */
290 This->modelview_valid = TRUE;
291 glMatrixMode(GL_MODELVIEW);
292 checkGLcall("glMatrixMode");
294 /* In the general case, the view matrix is the identity matrix */
295 if (This->view_ident) {
296 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
297 checkGLcall("glLoadMatrixf");
299 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
300 checkGLcall("glLoadMatrixf");
301 glMultMatrixf((float *) &This->stateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
302 checkGLcall("glMultMatrixf");
306 if (!useVS && (This->last_was_rhw || !This->proj_valid)) {
307 /* Only reapply when have to */
308 This->proj_valid = TRUE;
309 glMatrixMode(GL_PROJECTION);
310 checkGLcall("glMatrixMode");
312 /* The rule is that the window coordinate 0 does not correspond to the
313 beginning of the first pixel, but the center of the first pixel.
314 As a consequence if you want to correctly draw one line exactly from
315 the left to the right end of the viewport (with all matrices set to
316 be identity), the x coords of both ends of the line would be not
317 -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
320 glTranslatef(1.0/This->stateBlock->viewport.Width, -1.0/This->stateBlock->viewport.Height, 0);
321 checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
323 if (This->renderUpsideDown) {
324 glMultMatrixf(invymat);
325 checkGLcall("glMultMatrixf(invymat)");
327 glMultMatrixf((float *) &This->stateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]);
328 checkGLcall("glLoadMatrixf");
331 /* Vertex Shader output is already transformed, so set up identity matrices */
332 /* FIXME: Actually, only true for software emulated ones, so when h/w ones
333 come along this needs to take into account whether s/w ones were
336 glMatrixMode(GL_MODELVIEW);
337 checkGLcall("glMatrixMode");
339 glMatrixMode(GL_PROJECTION);
340 checkGLcall("glMatrixMode");
342 /* Window Coord 0 is the middle of the first pixel, so translate by half
343 a pixel (See comment above glTranslate above) */
344 glTranslatef(1.0/This->stateBlock->viewport.Width, -1.0/This->stateBlock->viewport.Height, 0);
345 checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
346 if (This->renderUpsideDown) {
347 glMultMatrixf(invymat);
348 checkGLcall("glMultMatrixf(invymat)");
350 This->modelview_valid = FALSE;
351 This->proj_valid = FALSE;
353 This->last_was_rhw = FALSE;
358 void primitiveConvertToStridedData(IWineD3DDevice *iface, Direct3DVertexStridedData *strided, LONG BaseVertexIndex) {
360 short LoopThroughTo = 0;
362 BOOL canDoViaGLPointers = TRUE;
366 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
367 int numCoords[8]; /* Holding place for D3DFVF_TEXTUREFORMATx */
369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
371 /* OK, Now to setup the data locations
372 For the non-created vertex shaders, the VertexShader var holds the real
373 FVF and only stream 0 matters
374 For the created vertex shaders, there is an FVF per stream */
375 if (!This->stateBlock->streamIsUP && !(This->updateStateBlock->vertexShader == NULL)) {
376 LoopThroughTo = MAX_STREAMS;
381 /* Work through stream by stream */
382 for (nStream=0; nStream<LoopThroughTo; nStream++) {
383 DWORD stride = This->stateBlock->stream_stride[nStream];
387 /* Skip empty streams */
388 if (This->stateBlock->stream_source[nStream] == NULL) continue;
390 /* Retrieve appropriate FVF */
391 if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
392 thisFVF = This->updateStateBlock->fvf;
393 /* Handle memory passed directly as well as vertex buffers */
394 if (This->stateBlock->streamIsUP) {
395 data = (BYTE *)This->stateBlock->stream_source[nStream];
397 data = ((IWineD3DVertexBufferImpl *)This->stateBlock->stream_source[nStream])->allocatedMemory;
400 #if 0 /* TODO: Vertex shader support */
401 thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
402 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 = D3DDECLTYPE_FLOAT3;
419 strided->u.s.position.dwStride = stride;
420 data += 3 * sizeof(float);
421 if (thisFVF & D3DFVF_XYZRHW) {
422 strided->u.s.position.dwType = D3DDECLTYPE_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 = D3DDECLTYPE_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 = D3DDECLTYPE_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 = D3DDECLTYPE_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 = D3DDECLTYPE_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 = D3DDECLTYPE_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 = D3DDECLTYPE_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 = D3DDECLTYPE_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 = D3DDECLTYPE_FLOAT2;
500 data += sizeof(float);
501 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT2) {
502 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT3;
503 data += sizeof(float);
504 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT3) {
505 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT4;
506 data += sizeof(float);
510 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
515 /* Draw a single vertex using this information */
516 void draw_vertex(IWineD3DDevice *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 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)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->textureState[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 GLMULTITEXCOORD1F(textureNo, s);
600 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
601 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
602 GLMULTITEXCOORD2F(textureNo, s, t);
608 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
609 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
610 GLMULTITEXCOORD3F(textureNo, s, t, r);
612 glTexCoord3f(s, t, r);
616 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
617 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
618 GLMULTITEXCOORD4F(textureNo, s, t, r, q);
620 glTexCoord4f(s, t, r, q);
624 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
628 } /* End of textures */
630 /* Position -------------------------------- */
632 if (1.0f == rhw || rhw < 0.00001f) {
633 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
636 /* Cannot optimize by dividing through by rhw as rhw is required
637 later for perspective in the GL pipeline for vertex shaders */
638 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
639 glVertex4f(x,y,z,rhw);
645 * Actually draw using the supplied information.
646 * Faster GL version using pointers to data, harder to debug though
647 * Note does not handle vertex shaders yet
649 void drawStridedFast(IWineD3DDevice *iface, Direct3DVertexStridedData *sd,
650 int PrimitiveType, ULONG NumPrimitives,
651 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
652 unsigned int textureNo = 0;
653 GLenum glPrimType = GL_POINTS;
654 int NumVertexes = NumPrimitives;
655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
657 TRACE("Using fast vertex array code\n");
659 /* Vertex Pointers -----------------------------------------*/
660 if (sd->u.s.position.lpData != NULL) {
662 /* Note dwType == float3 or float4 == 2 or 3 */
663 VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n",
664 sd->u.s.position.dwStride,
665 sd->u.s.position.dwType + 1,
666 sd->u.s.position.lpData));
668 /* Disable RHW mode as 'w' coord handling for rhw mode should
669 not impact screen position whereas in GL it does. This may
670 result in very slightly distored textures in rhw mode, but
671 a very minimal different */
672 glVertexPointer(3, GL_FLOAT, /* RHW: Was 'sd->u.s.position.dwType + 1' */
673 sd->u.s.position.dwStride,
674 sd->u.s.position.lpData);
675 checkGLcall("glVertexPointer(...)");
676 glEnableClientState(GL_VERTEX_ARRAY);
677 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
681 glDisableClientState(GL_VERTEX_ARRAY);
682 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
685 /* Blend Data ----------------------------------------------*/
686 if ((sd->u.s.blendWeights.lpData != NULL) ||
687 (sd->u.s.blendMatrixIndices.lpData != NULL)) {
688 #if 1 /* Vertex blend support needs to be added */
689 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
690 DWORD fvf = (sd->u.s.blendWeights.dwType - D3DDECLTYPE_FLOAT1) + 1;
691 int numBlends = ((fvf & D3DFVF_POSITION_MASK) >> 1) - 2 + ((FALSE == (fvf & D3DFVF_LASTBETA_UBYTE4)) ? 0 : -1);
694 /* Note dwType == float3 or float4 == 2 or 3 */
695 VTRACE(("glWeightPointerARB(%ld, GL_FLOAT, %ld, %p)\n",
697 sd->u.s.blendWeights.dwStride,
698 sd->u.s.blendWeights.lpData));
699 GL_EXTCALL(glWeightPointerARB)(numBlends, GL_FLOAT,
700 sd->u.s.blendWeights.dwStride,
701 sd->u.s.blendWeights.lpData);
702 checkGLcall("glWeightPointerARB(...)");
703 glEnableClientState(GL_WEIGHT_ARRAY_ARB);
704 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
705 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
708 GLExtCall(glVertexWeightPointerEXT)(numBlends, GL_FLOAT, skip, curPos);
709 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
710 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
711 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
714 FIXME("unsupported blending in openGl\n");
717 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
719 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
722 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
723 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
727 /* FIXME: Won't get here as will drop to slow method */
728 FIXME("Blending not supported in fast draw routine\n");
732 /* Normals -------------------------------------------------*/
733 if (sd->u.s.normal.lpData != NULL) {
735 /* Note dwType == float3 or float4 == 2 or 3 */
736 VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n",
737 sd->u.s.normal.dwStride,
738 sd->u.s.normal.lpData));
739 glNormalPointer(GL_FLOAT,
740 sd->u.s.normal.dwStride,
741 sd->u.s.normal.lpData);
742 checkGLcall("glNormalPointer(...)");
743 glEnableClientState(GL_NORMAL_ARRAY);
744 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
748 glDisableClientState(GL_NORMAL_ARRAY);
749 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
751 checkGLcall("glNormal3f(0, 0, 1)");
754 /* Point Size ----------------------------------------------*/
755 if (sd->u.s.pSize.lpData != NULL) {
757 /* no such functionality in the fixed function GL pipeline */
758 /* FIXME: Won't get here as will drop to slow method */
759 FIXME("Cannot change ptSize here in openGl\n");
762 /* Diffuse Colour ------------------------------------------*/
763 /* WARNING: Data here MUST be in RGBA format, so cannot */
764 /* go directly into fast mode from app pgm, because */
765 /* directx requires data in BGRA format. */
766 if (sd->u.s.diffuse.lpData != NULL) {
768 /* Note dwType == float3 or float4 == 2 or 3 */
769 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
770 sd->u.s.diffuse.dwStride,
771 sd->u.s.diffuse.lpData));
772 glColorPointer(4, GL_UNSIGNED_BYTE,
773 sd->u.s.diffuse.dwStride,
774 sd->u.s.diffuse.lpData);
775 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
776 glEnableClientState(GL_COLOR_ARRAY);
777 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
781 glDisableClientState(GL_COLOR_ARRAY);
782 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
783 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
784 checkGLcall("glColor4f(1, 1, 1, 1)");
787 /* Specular Colour ------------------------------------------*/
788 if (sd->u.s.specular.lpData != NULL) {
790 /* Note dwType == float3 or float4 == 2 or 3 */
791 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
792 sd->u.s.specular.dwStride,
793 sd->u.s.specular.lpData));
795 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
796 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
797 sd->u.s.specular.dwStride,
798 sd->u.s.specular.lpData);
799 vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
800 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
801 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
803 /* Missing specular color is not critical, no warnings */
804 VTRACE(("Specular colour is not supported in this GL implementation\n"));
809 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
810 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
811 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
812 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
813 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
815 /* Missing specular color is not critical, no warnings */
816 VTRACE(("Specular colour is not supported in this GL implementation\n"));
820 /* Texture coords -------------------------------------------*/
821 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
823 /* Select the correct texture stage */
824 GLCLIENTACTIVETEXTURE(textureNo);
826 /* Query tex coords */
827 if (This->stateBlock->textures[textureNo] != NULL) {
828 int coordIdx = This->updateStateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
830 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
831 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
832 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
833 GLMULTITEXCOORD4F(textureNo, 0, 0, 0, 1);
838 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
839 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
840 GLMULTITEXCOORD4F(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 GLMULTITEXCOORD4F(textureNo, 0, 0, 0, 1);
849 /* The coords to supply depend completely on the fvf / vertex shader */
853 switch (sd->u.s.texCoords[coordIdx].dwType) {
854 case D3DDECLTYPE_FLOAT1: size = 1, type = GL_FLOAT; break;
855 case D3DDECLTYPE_FLOAT2: size = 2, type = GL_FLOAT; break;
856 case D3DDECLTYPE_FLOAT3: size = 3, type = GL_FLOAT; break;
857 case D3DDECLTYPE_FLOAT4: size = 4, type = GL_FLOAT; break;
858 case D3DDECLTYPE_SHORT2: size = 2, type = GL_SHORT; break;
859 case D3DDECLTYPE_SHORT4: size = 4, type = GL_SHORT; break;
860 case D3DDECLTYPE_UBYTE4: size = 4, type = GL_UNSIGNED_BYTE; break;
861 default: FIXME("Unrecognized data type %ld\n", sd->u.s.texCoords[coordIdx].dwType);
862 size = 4; type = GL_UNSIGNED_BYTE;
865 glTexCoordPointer(size, type, sd->u.s.texCoords[coordIdx].dwStride, sd->u.s.texCoords[coordIdx].lpData);
866 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
869 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
870 GLMULTITEXCOORD4F(textureNo, 0, 0, 0, 1);
874 /* Ok, Work out which primitive is requested and how many vertexes that
876 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
878 /* Finally do the drawing */
879 if (idxData != NULL) {
881 TRACE("glElements(%x, %d, %ld, ...)\n", glPrimType, NumVertexes, minIndex);
882 #if 1 /* FIXME: Want to use DrawRangeElements, but wrong calculation! */
883 glDrawElements(glPrimType, NumVertexes, idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
884 (const char *)idxData+(idxSize * startIdx));
886 glDrawRangeElements(glPrimType, minIndex, minIndex+NumVertexes-1, NumVertexes,
887 idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
888 (const char *)idxData+(idxSize * startIdx));
890 checkGLcall("glDrawRangeElements");
894 /* Note first is now zero as we shuffled along earlier */
895 TRACE("glDrawArrays(%x, 0, %d)\n", glPrimType, NumVertexes);
896 glDrawArrays(glPrimType, 0, NumVertexes);
897 checkGLcall("glDrawArrays");
903 * Actually draw using the supplied information.
904 * Slower GL version which extracts info about each vertex in turn
906 void drawStridedSlow(IWineD3DDevice *iface, Direct3DVertexStridedData *sd,
907 int PrimitiveType, ULONG NumPrimitives,
908 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
910 unsigned int textureNo = 0;
911 GLenum glPrimType = GL_POINTS;
912 int NumVertexes = NumPrimitives;
913 const short *pIdxBufS = NULL;
914 const long *pIdxBufL = NULL;
915 LONG SkipnStrides = 0;
917 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
918 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
919 float rhw = 0.0f; /* rhw */
920 float ptSize = 0.0f; /* Point size */
921 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
922 DWORD specularColor = 0; /* Specular Color */
923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
925 TRACE("Using slow vertex array code\n");
927 /* Variable Initialization */
928 if (idxData != NULL) {
929 if (idxSize == 2) pIdxBufS = (const short *) idxData;
930 else pIdxBufL = (const long *) idxData;
933 /* Ok, Work out which primitive is requested and how many vertexes that will be */
934 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
936 /* Start drawing in GL */
937 VTRACE(("glBegin(%x)\n", glPrimType));
940 /* For each primitive */
941 for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
943 /* Initialize diffuse color */
944 diffuseColor = 0xFFFFFFFF;
946 /* For indexed data, we need to go a few more strides in */
947 if (idxData != NULL) {
949 /* Indexed so work out the number of strides to skip */
951 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
952 SkipnStrides = pIdxBufS[startIdx+vx_index];
954 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
955 SkipnStrides = pIdxBufL[startIdx+vx_index];
959 /* Position Information ------------------ */
960 if (sd->u.s.position.lpData != NULL) {
962 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
967 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
969 /* RHW follows, only if transformed, ie 4 floats were provided */
970 if (sd->u.s.position.dwType == D3DDECLTYPE_FLOAT4) {
971 rhw = ptrToCoords[3];
972 VTRACE(("rhw=%f\n", rhw));
976 /* Blending data -------------------------- */
977 if (sd->u.s.blendWeights.lpData != NULL) {
978 /*float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride));*/
979 FIXME("Blending not supported yet\n");
981 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
982 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
986 /* Vertex Normal Data (untransformed only)- */
987 if (sd->u.s.normal.lpData != NULL) {
989 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
993 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
996 /* Point Size ----------------------------- */
997 if (sd->u.s.pSize.lpData != NULL) {
999 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1000 ptSize = ptrToCoords[0];
1001 VTRACE(("ptSize=%f\n", ptSize));
1002 FIXME("No support for ptSize yet\n");
1005 /* Diffuse -------------------------------- */
1006 if (sd->u.s.diffuse.lpData != NULL) {
1008 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1009 diffuseColor = ptrToCoords[0];
1010 VTRACE(("diffuseColor=%lx\n", diffuseColor));
1013 /* Specular -------------------------------- */
1014 if (sd->u.s.specular.lpData != NULL) {
1016 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1017 specularColor = ptrToCoords[0];
1018 VTRACE(("specularColor=%lx\n", specularColor));
1021 /* Texture coords --------------------------- */
1022 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1024 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1025 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1029 /* Query tex coords */
1030 if (This->stateBlock->textures[textureNo] != NULL) {
1032 int coordIdx = This->updateStateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1033 float *ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1034 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1037 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1039 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1040 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1044 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DDECLTYPE_FLOAT1 etc */
1046 /* The coords to supply depend completely on the fvf / vertex shader */
1047 switch (coordsToUse) {
1048 case 4: q = ptrToCoords[3]; /* drop through */
1049 case 3: r = ptrToCoords[2]; /* drop through */
1050 case 2: t = ptrToCoords[1]; /* drop through */
1051 case 1: s = ptrToCoords[0];
1054 /* Projected is more 'fun' - Move the last coord to the 'q'
1055 parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1056 if ((This->updateStateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1057 (This->updateStateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1059 if (This->updateStateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1060 switch (coordsToUse) {
1061 case 0: /* Drop Through */
1063 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1075 case 4: /* Nop here */
1078 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n",
1079 This->updateStateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1084 switch (coordsToUse) { /* Supply the provided texture coords */
1085 case D3DTTFF_COUNT1:
1086 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1087 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1088 GLMULTITEXCOORD1F(textureNo, s);
1093 case D3DTTFF_COUNT2:
1094 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1095 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1096 GLMULTITEXCOORD2F(textureNo, s, t);
1101 case D3DTTFF_COUNT3:
1102 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1103 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1104 GLMULTITEXCOORD3F(textureNo, s, t, r);
1106 glTexCoord3f(s, t, r);
1109 case D3DTTFF_COUNT4:
1110 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1111 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1112 GLMULTITEXCOORD4F(textureNo, s, t, r, q);
1114 glTexCoord4f(s, t, r, q);
1118 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1122 } /* End of textures */
1124 /* Diffuse -------------------------------- */
1125 if (sd->u.s.diffuse.lpData != NULL) {
1126 glColor4ub((diffuseColor >> 16) & 0xFF,
1127 (diffuseColor >> 8) & 0xFF,
1128 (diffuseColor >> 0) & 0xFF,
1129 (diffuseColor >> 24) & 0xFF);
1130 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n",
1131 ((diffuseColor >> 16) & 0xFF) / 255.0f,
1132 ((diffuseColor >> 8) & 0xFF) / 255.0f,
1133 ((diffuseColor >> 0) & 0xFF) / 255.0f,
1134 ((diffuseColor >> 24) & 0xFF) / 255.0f));
1136 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1139 /* Specular ------------------------------- */
1140 if (sd->u.s.diffuse.lpData != NULL) {
1141 VTRACE(("glSecondaryColor4ub: r,g,b=%f,%f,%f\n",
1142 ((specularColor >> 16) & 0xFF) / 255.0f,
1143 ((specularColor >> 8) & 0xFF) / 255.0f,
1144 ((specularColor >> 0) & 0xFF) / 255.0f));
1145 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1146 GL_EXTCALL(glSecondaryColor3ubEXT)(
1147 (specularColor >> 16) & 0xFF,
1148 (specularColor >> 8) & 0xFF,
1149 (specularColor >> 0) & 0xFF);
1151 /* Do not worry if specular colour missing and disable request */
1152 VTRACE(("Specular color extensions not supplied\n"));
1155 if (vx_index == 0) {
1156 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1157 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1159 /* Do not worry if specular colour missing and disable request */
1160 VTRACE(("Specular color extensions not supplied\n"));
1165 /* Normal -------------------------------- */
1166 if (sd->u.s.normal.lpData != NULL) {
1167 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1168 glNormal3f(nx, ny, nz);
1170 if (vx_index == 0) glNormal3f(0, 0, 1);
1173 /* Position -------------------------------- */
1174 if (sd->u.s.position.lpData != NULL) {
1175 if (1.0f == rhw || ((rhw < 0.0001f) && (rhw > -0.0001f))) {
1176 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1177 glVertex3f(x, y, z);
1179 GLfloat w = 1.0 / rhw;
1180 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1181 glVertex4f(x*w, y*w, z*w, w);
1185 /* For non indexed mode, step onto next parts */
1186 if (idxData == NULL) {
1192 checkGLcall("glEnd and previous calls");
1195 #if 0 /* TODO: Software/Hardware vertex blending support */
1197 * Draw with emulated vertex shaders
1198 * Note: strided data is uninitialized, as we need to pass the vertex
1199 * shader directly as ordering irs yet
1201 void drawStridedSoftwareVS(IWineD3DDevice *iface, Direct3DVertexStridedData *sd,
1202 int PrimitiveType, ULONG NumPrimitives,
1203 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1205 unsigned int textureNo = 0;
1206 GLenum glPrimType = GL_POINTS;
1207 int NumVertexes = NumPrimitives;
1208 const short *pIdxBufS = NULL;
1209 const long *pIdxBufL = NULL;
1210 LONG SkipnStrides = 0;
1212 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1213 float rhw = 0.0f; /* rhw */
1214 float ptSize = 0.0f; /* Point size */
1215 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1216 int numcoords[8]; /* Number of coords */
1217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1219 IDirect3DVertexShaderImpl* vertex_shader = NULL;
1221 TRACE("Using slow software vertex shader code\n");
1223 /* Variable Initialization */
1224 if (idxData != NULL) {
1225 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1226 else pIdxBufL = (const long *) idxData;
1229 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1230 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1232 /* Retrieve the VS information */
1233 vertex_shader = VERTEX_SHADER(This->stateBlock->VertexShader);
1235 /* Start drawing in GL */
1236 VTRACE(("glBegin(%x)\n", glPrimType));
1237 glBegin(glPrimType);
1239 /* For each primitive */
1240 for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
1242 /* For indexed data, we need to go a few more strides in */
1243 if (idxData != NULL) {
1245 /* Indexed so work out the number of strides to skip */
1247 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1248 SkipnStrides = pIdxBufS[startIdx+vx_index];
1250 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1251 SkipnStrides = pIdxBufL[startIdx+vx_index];
1255 /* Fill the vertex shader input */
1256 IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertex_shader, SkipnStrides);
1258 /* Initialize the output fields to the same defaults as it would normally have */
1259 memset(&vertex_shader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1260 vertex_shader->output.oD[0].x = 1.0;
1261 vertex_shader->output.oD[0].y = 1.0;
1262 vertex_shader->output.oD[0].z = 1.0;
1263 vertex_shader->output.oD[0].w = 1.0;
1265 /* Now execute the vertex shader */
1266 IDirect3DVertexShaderImpl_ExecuteSW(vertex_shader, &vertex_shader->input, &vertex_shader->output);
1269 TRACE_VECTOR(vertex_shader->output.oPos);
1270 TRACE_VECTOR(vertex_shader->output.oD[0]);
1271 TRACE_VECTOR(vertex_shader->output.oD[1]);
1272 TRACE_VECTOR(vertex_shader->output.oT[0]);
1273 TRACE_VECTOR(vertex_shader->output.oT[1]);
1274 TRACE_VECTOR(vertex_shader->input.V[0]);
1275 TRACE_VECTOR(vertex_shader->data->C[0]);
1276 TRACE_VECTOR(vertex_shader->data->C[1]);
1277 TRACE_VECTOR(vertex_shader->data->C[2]);
1278 TRACE_VECTOR(vertex_shader->data->C[3]);
1279 TRACE_VECTOR(vertex_shader->data->C[4]);
1280 TRACE_VECTOR(vertex_shader->data->C[5]);
1281 TRACE_VECTOR(vertex_shader->data->C[6]);
1282 TRACE_VECTOR(vertex_shader->data->C[7]);
1285 /* Extract out the output */
1286 /*FIXME: Fog coords? */
1287 x = vertex_shader->output.oPos.x;
1288 y = vertex_shader->output.oPos.y;
1289 z = vertex_shader->output.oPos.z;
1290 rhw = vertex_shader->output.oPos.w;
1291 ptSize = vertex_shader->output.oPts.x; /* Fixme - Is this right? */
1293 /** Update textures coords using vertex_shader->output.oT[0->7] */
1294 memset(texcoords, 0x00, sizeof(texcoords));
1295 memset(numcoords, 0x00, sizeof(numcoords));
1296 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1297 if (This->stateBlock->textures[textureNo] != NULL) {
1298 texcoords[textureNo].x = vertex_shader->output.oT[textureNo].x;
1299 texcoords[textureNo].y = vertex_shader->output.oT[textureNo].y;
1300 texcoords[textureNo].z = vertex_shader->output.oT[textureNo].z;
1301 texcoords[textureNo].w = vertex_shader->output.oT[textureNo].w;
1302 if (This->updateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1303 numcoords[textureNo] = This->updateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1305 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1306 case D3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1307 case D3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1308 default: numcoords[textureNo] = 4;
1312 numcoords[textureNo] = 0;
1316 /* Draw using this information */
1319 TRUE, 0.0f, 0.0f, 1.0f,
1320 TRUE, (float*) &vertex_shader->output.oD[0],
1321 TRUE, (float*) &vertex_shader->output.oD[1],
1322 FALSE, ptSize, /* FIXME: Change back when supported */
1323 texcoords, numcoords);
1325 /* For non indexed mode, step onto next parts */
1326 if (idxData == NULL) {
1330 } /* for each vertex */
1333 checkGLcall("glEnd and previous calls");
1336 void drawStridedHardwareVS(IWineD3DDevice *iface, Direct3DVertexStridedData *sd,
1337 int PrimitiveType, ULONG NumPrimitives,
1338 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1340 IDirect3DVertexShaderImpl* vertex_shader = NULL;
1346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1347 TRACE("Drawing with hardware vertex shaders\n");
1349 /* Retrieve the VS information */
1350 vertex_shader = VERTEX_SHADER(This->stateBlock->VertexShader);
1352 /* Enable the Vertex Shader */
1353 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertex_shader->prgId));
1354 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertex_shader->prgId);");
1355 glEnable(GL_VERTEX_PROGRAM_ARB);
1356 checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
1358 /* Update the constants */
1359 for (i=0; i<D3D8_VSHADER_MAX_CONSTANTS; i++) {
1360 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, i, (GLfloat *)&This->stateBlock->vertexShaderConstant[i]));
1361 checkGLcall("glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB");
1364 /* Set up the vertex.attr[n] inputs */
1365 IDirect3DDeviceImpl_FillVertexShaderInputArbHW(This, vertex_shader, 0);
1367 /* Ok, Work out which primitive is requested and how many vertexes that
1369 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1371 /* Finally do the drawing */
1372 if (idxData != NULL) {
1374 TRACE("glElements(%x, %d, %ld, ...)\n", glPrimType, NumVertexes, minIndex);
1375 #if 1 /* FIXME: Want to use DrawRangeElements, but wrong calculation! */
1376 glDrawElements(glPrimType, NumVertexes, idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
1377 (const char *)idxData+(idxSize * startIdx));
1379 glDrawRangeElements(glPrimType, minIndex, minIndex+NumVertexes-1, NumVertexes,
1380 idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
1381 (const char *)idxData+(idxSize * startIdx));
1383 checkGLcall("glDrawRangeElements");
1387 /* Note first is now zero as we shuffled along earlier */
1388 TRACE("glDrawArrays(%x, 0, %d)\n", glPrimType, NumVertexes);
1389 glDrawArrays(glPrimType, 0, NumVertexes);
1390 checkGLcall("glDrawArrays");
1396 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
1398 FIXME("HW VertexShader Error at position: %d\n%s\n", errPos, glGetString( GL_PROGRAM_ERROR_STRING_ARB) );
1402 /* Leave all the attribs disabled */
1403 glGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
1404 /* MESA does not support it right not */
1405 if (glGetError() != GL_NO_ERROR)
1407 for (i=0; i<maxAttribs; i++) {
1408 GL_EXTCALL(glDisableVertexAttribArrayARB(i));
1409 checkGLcall("glDisableVertexAttribArrayARB(reg);");
1413 glDisable(GL_VERTEX_PROGRAM_ARB);
1417 /* Routine common to the draw primitive and draw indexed primitive routines */
1418 void drawPrimitive(IWineD3DDevice *iface,
1419 int PrimitiveType, long NumPrimitives,
1422 long StartVertexIndex,
1425 const void *idxData,
1430 #if 0 /* TODO: vertex and pixel shaders */
1431 IDirect3DVertexShaderImpl *vertex_shader = NULL;
1432 IDirect3DPixelShaderImpl *pixel_shader = NULL;
1434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1436 BOOL useVertexShaderFunction = FALSE;
1437 BOOL isLightingOn = FALSE;
1438 Direct3DVertexStridedData dataLocations;
1441 /* Work out what the FVF should look like */
1442 rc = initializeFVF(iface, &fvf, &useVertexShaderFunction);
1445 /* If we will be using a vertex shader, do some initialization for it */
1446 if (useVertexShaderFunction) {
1447 #if 0 /* TODO: vertex and pixel shaders */
1448 vertex_shader = VERTEX_SHADER(This->updateStateBlock->VertexShader);
1449 memset(&vertex_shader->input, 0, sizeof(VSHADERINPUTDATA8));
1451 useHW = (((vs_mode == VS_HW) && GL_SUPPORT(ARB_VERTEX_PROGRAM)) &&
1452 This->devType != D3DDEVTYPE_REF &&
1453 !This->stateBlock->renderState[D3DRS_SOFTWAREVERTEXPROCESSING] &&
1454 vertex_shader->usage != D3DUSAGE_SOFTWAREPROCESSING);
1456 /** init Constants */
1457 if (This->updateStateBlock->Changed.vertexShaderConstant) {
1458 TRACE_(d3d_shader)("vertex shader initializing constants\n");
1459 IDirect3DVertexShaderImpl_SetConstantF(vertex_shader, 0, (CONST FLOAT*) &This->updateStateBlock->vertexShaderConstant[0], 96);
1461 #endif /* TODO: vertex and pixel shaders */
1464 /* Ok, we will be updating the screen from here onwards so grab the lock */
1467 #if 0 /* TODO: vertex and pixel shaders */
1468 /* If we will be using a pixel, do some initialization for it */
1469 if ((pixel_shader = PIXEL_SHADER(This->updateStateBlock->PixelShader))) {
1470 TRACE("drawing with pixel shader handle %p\n", pixel_shader);
1471 memset(&pixel_shader->input, 0, sizeof(PSHADERINPUTDATA8));
1473 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixel_shader->prgId));
1474 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixel_shader->prgId);");
1475 glEnable(GL_FRAGMENT_PROGRAM_ARB);
1476 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
1478 /* init Constants */
1479 if (This->updateStateBlock->Changed.pixelShaderConstant) {
1480 TRACE_(d3d_shader)("pixel shader initializing constants %p\n",pixel_shader);
1481 IDirect3DPixelShaderImpl_SetConstantF(pixel_shader, 0, (CONST FLOAT*) &This->updateStateBlock->pixelShaderConstant[0], 8);
1483 /* Update the constants */
1484 for (i=0; i<D3D8_PSHADER_MAX_CONSTANTS; i++) {
1485 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, (GLfloat *)&This->stateBlock->pixelShaderConstant[i]));
1486 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB");
1489 #endif /* TODO: vertex and pixel shaders */
1491 /* Setup transform matrices and sort out */
1493 /* Lighting is not completely bypassed with ATI drivers although it should be. Mesa is ok from this respect...
1494 So make sure lighting is disabled. */
1495 isLightingOn = glIsEnabled(GL_LIGHTING);
1496 glDisable(GL_LIGHTING);
1497 checkGLcall("glDisable(GL_LIGHTING);");
1498 TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn);
1500 isLightingOn = primitiveInitState(iface,
1501 fvf & D3DFVF_XYZRHW,
1502 !(fvf & D3DFVF_NORMAL),
1503 useVertexShaderFunction);
1505 /* Initialize all values to null */
1506 if (useVertexShaderFunction == FALSE) {
1507 memset(&dataLocations, 0x00, sizeof(dataLocations));
1509 /* Convert to strided data */
1510 primitiveConvertToStridedData(iface, &dataLocations, StartVertexIndex);
1512 /* Dump out what parts we have supplied */
1513 TRACE("Strided Data (from FVF/VS): %lx\n", fvf);
1514 TRACE_STRIDED((&dataLocations), position);
1515 TRACE_STRIDED((&dataLocations), blendWeights);
1516 TRACE_STRIDED((&dataLocations), blendMatrixIndices);
1517 TRACE_STRIDED((&dataLocations), normal);
1518 TRACE_STRIDED((&dataLocations), pSize);
1519 TRACE_STRIDED((&dataLocations), diffuse);
1520 TRACE_STRIDED((&dataLocations), specular);
1521 TRACE_STRIDED((&dataLocations), texCoords[0]);
1522 TRACE_STRIDED((&dataLocations), texCoords[1]);
1523 TRACE_STRIDED((&dataLocations), texCoords[2]);
1524 TRACE_STRIDED((&dataLocations), texCoords[3]);
1525 TRACE_STRIDED((&dataLocations), texCoords[4]);
1526 TRACE_STRIDED((&dataLocations), texCoords[5]);
1527 TRACE_STRIDED((&dataLocations), texCoords[6]);
1528 TRACE_STRIDED((&dataLocations), texCoords[7]);
1531 /* Now initialize the materials state */
1532 init_materials(iface, (dataLocations.u.s.diffuse.lpData != NULL));
1535 /* And re-upload any dirty textures */
1536 for (i=0; i<GL_LIMITS(textures); i++) {
1538 if ((This->stateBlock->textures[i] != NULL) &&
1539 (IWineD3DBaseTexture_GetDirty(This->stateBlock->textures[i])))
1541 /* Load up the texture now */
1542 IWineD3DTexture_PreLoad((IWineD3DTexture *) This->stateBlock->textures[i]);
1543 /* TODO: Is this right, as its cast all texture types to texture8... checkme */
1547 /* Now draw the graphics to the screen */
1548 if (useVertexShaderFunction) {
1550 /* Ideally, we should have software FV and hardware VS, possibly
1551 depending on the device type? */
1554 TRACE("Swap HW vertex shader\n");
1555 #if 0 /* TODO: vertex and pixel shaders */
1556 drawStridedHardwareVS(iface, &dataLocations, PrimitiveType, NumPrimitives,
1557 idxData, idxSize, minIndex, StartIdx);
1560 /* We will have to use the very, very slow emulation layer */
1561 TRACE("Swap SW vertex shader\n");
1562 #if 0 /* TODO: vertex and pixel shaders */
1563 drawStridedSoftwareVS(iface, &dataLocations, PrimitiveType, NumPrimitives,
1564 idxData, idxSize, minIndex, StartIdx);
1568 } else if ((dataLocations.u.s.pSize.lpData != NULL)
1569 || (dataLocations.u.s.diffuse.lpData != NULL)
1570 /*|| (dataLocations.u.s.blendWeights.lpData != NULL)*/) {
1572 /* Fixme, Ideally, only use the per-vertex code for software HAL
1573 but until opengl supports all the functions returned to setup
1574 vertex arrays, we need to drop down to the slow mechanism for
1575 certain functions */
1577 /* We will have to use the slow version of GL per vertex setup */
1578 drawStridedSlow(iface, &dataLocations, PrimitiveType, NumPrimitives,
1579 idxData, idxSize, minIndex, StartIdx);
1583 /* We can use the fast version of GL pointers */
1584 drawStridedFast(iface, &dataLocations, PrimitiveType, NumPrimitives,
1585 idxData, idxSize, minIndex, StartIdx);
1588 /* If vertex shaders or no normals, restore previous lighting state */
1589 if (useVertexShaderFunction || !(fvf & D3DFVF_NORMAL)) {
1590 if (isLightingOn) glEnable(GL_LIGHTING);
1591 else glDisable(GL_LIGHTING);
1592 TRACE("Restored lighting to original state\n");
1595 #if 0 /* TODO: vertex and pixel shaders */
1600 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
1602 FIXME("HW PixelShader Error at position: %d\n%s\n", errPos, glGetString( GL_PROGRAM_ERROR_STRING_ARB) );
1604 glDisable(GL_FRAGMENT_PROGRAM_ARB);
1608 /* Finshed updating the screen, restore lock */
1610 TRACE("Done all gl drawing\n");
1613 #if defined(SHOW_FRAME_MAKEUP)
1615 if (isDumpingFrames) {
1618 IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) This->renderTarget, &r, NULL, D3DLOCK_READONLY);
1619 sprintf(buffer, "/tmp/backbuffer_%ld.ppm", primCounter);
1620 TRACE("Saving screenshot %s\n", buffer);
1621 IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This->renderTarget, buffer);
1622 IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) This->renderTarget);
1624 #if defined(SHOW_TEXTURE_MAKEUP)
1626 LPDIRECT3DSURFACE8 pSur;
1628 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1629 if (This->stateBlock->textures[textureNo] != NULL) {
1630 sprintf(buffer, "/tmp/texture_%ld_%d.ppm", primCounter, textureNo);
1631 TRACE("Saving texture %s (Format:%s)\n", buffer, debug_d3dformat(((IDirect3DBaseTexture8Impl *)This->stateBlock->textures[textureNo])->format));
1632 IDirect3DTexture8Impl_GetSurfaceLevel((LPDIRECT3DTEXTURE8) This->stateBlock->textures[textureNo], 0, &pSur);
1633 IDirect3DSurface8Impl_SaveSnapshot(pSur, buffer);
1634 IDirect3DSurface8Impl_Release(pSur);
1639 primCounter = primCounter + 1;