|  | /* | 
|  | * D3D8 utils | 
|  | * | 
|  | * Copyright 2002-2004 Jason Edmeades | 
|  | * Copyright 2002-2004 Raphael Junqueira | 
|  | * Copyright 2004 Christian Costa | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #include <math.h> | 
|  | #include <stdarg.h> | 
|  |  | 
|  | #define NONAMELESSUNION | 
|  | #define NONAMELESSSTRUCT | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winuser.h" | 
|  | #include "wingdi.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | #include "d3d8_private.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(d3d); | 
|  | WINE_DECLARE_DEBUG_CHANNEL(d3d_shader); | 
|  |  | 
|  | extern IDirect3DVertexShaderImpl*            VertexShaders[64]; | 
|  | extern IDirect3DVertexShaderDeclarationImpl* VertexShaderDeclarations[64]; | 
|  | extern IDirect3DPixelShaderImpl*             PixelShaders[64]; | 
|  |  | 
|  | /* Useful holding place for 4 floats */ | 
|  | typedef struct _D3DVECTOR_4 { | 
|  | float x; | 
|  | float y; | 
|  | float z; | 
|  | float w; | 
|  | } D3DVECTOR_4; | 
|  |  | 
|  | #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */ | 
|  |  | 
|  | /* Returns bits for what is expected from the fixed function pipeline, and whether | 
|  | a vertex shader will be in use. Note the fvf bits returned may be split over | 
|  | multiple streams only if the vertex shader was created, otherwise it all relates | 
|  | to stream 0                                                                      */ | 
|  | BOOL initializeFVF(LPDIRECT3DDEVICE8 iface, | 
|  | DWORD *FVFbits,                 /* What to expect in the FVF across all streams */ | 
|  | BOOL *useVertexShaderFunction)  /* Should we use the vertex shader              */ | 
|  | { | 
|  |  | 
|  | ICOM_THIS(IDirect3DDevice8Impl,iface); | 
|  |  | 
|  | /* The first thing to work out is if we are using the fixed function pipeline | 
|  | which is either SetVertexShader with < VS_HIGHESTFIXEDFXF - in which case this | 
|  | is the FVF, or with a shader which was created with no function - in which | 
|  | case there is an FVF per declared stream. If this occurs, we also maintain | 
|  | an 'OR' of all the FVF's together so we know what to expect across all the | 
|  | streams                                                                        */ | 
|  |  | 
|  | if (This->UpdateStateBlock->VertexShader <= VS_HIGHESTFIXEDFXF) { | 
|  |  | 
|  | /* Use this as the FVF */ | 
|  | *FVFbits = This->UpdateStateBlock->VertexShader; | 
|  | *useVertexShaderFunction = FALSE; | 
|  | TRACE("FVF explicitally defined, using fixed function pipeline with FVF=%lx\n", *FVFbits); | 
|  |  | 
|  | } else { | 
|  |  | 
|  | /* Use created shader */ | 
|  | IDirect3DVertexShaderImpl* vertex_shader = NULL; | 
|  | vertex_shader = VERTEX_SHADER(This->UpdateStateBlock->VertexShader); | 
|  |  | 
|  | if (vertex_shader == NULL) { | 
|  |  | 
|  | /* Hmm - User pulled figure out of the air? Unlikely, probably a bug */ | 
|  | ERR("trying to use unitialised vertex shader: %lu\n", This->UpdateStateBlock->VertexShader); | 
|  | return TRUE; | 
|  |  | 
|  | } else { | 
|  |  | 
|  | *FVFbits = This->UpdateStateBlock->vertexShaderDecl->allFVF; | 
|  |  | 
|  | if (vertex_shader->function == NULL) { | 
|  | /* No function, so many streams supplied plus FVF definition pre stream */ | 
|  | *useVertexShaderFunction = FALSE; | 
|  | TRACE("vertex shader (%lx) declared without program, using fixed function pipeline with FVF=%lx\n", | 
|  | This->StateBlock->VertexShader, *FVFbits); | 
|  | } else { | 
|  | /* Vertex shader needs calling */ | 
|  | *useVertexShaderFunction = TRUE; | 
|  | TRACE("vertex shader will be used (unusued FVF=%lx)\n", *FVFbits); | 
|  | } | 
|  | } | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /* Issues the glBegin call for gl given the primitive type and count */ | 
|  | DWORD primitiveToGl(D3DPRIMITIVETYPE PrimitiveType, | 
|  | DWORD            NumPrimitives, | 
|  | GLenum          *primType) | 
|  | { | 
|  | DWORD   NumVertexes = NumPrimitives; | 
|  |  | 
|  | switch (PrimitiveType) { | 
|  | case D3DPT_POINTLIST: | 
|  | TRACE("POINTS\n"); | 
|  | *primType = GL_POINTS; | 
|  | NumVertexes = NumPrimitives; | 
|  | break; | 
|  |  | 
|  | case D3DPT_LINELIST: | 
|  | TRACE("LINES\n"); | 
|  | *primType = GL_LINES; | 
|  | NumVertexes = NumPrimitives * 2; | 
|  | break; | 
|  |  | 
|  | case D3DPT_LINESTRIP: | 
|  | TRACE("LINE_STRIP\n"); | 
|  | *primType = GL_LINE_STRIP; | 
|  | NumVertexes = NumPrimitives + 1; | 
|  | break; | 
|  |  | 
|  | case D3DPT_TRIANGLELIST: | 
|  | TRACE("TRIANGLES\n"); | 
|  | *primType = GL_TRIANGLES; | 
|  | NumVertexes = NumPrimitives * 3; | 
|  | break; | 
|  |  | 
|  | case D3DPT_TRIANGLESTRIP: | 
|  | TRACE("TRIANGLE_STRIP\n"); | 
|  | *primType = GL_TRIANGLE_STRIP; | 
|  | NumVertexes = NumPrimitives + 2; | 
|  | break; | 
|  |  | 
|  | case D3DPT_TRIANGLEFAN: | 
|  | TRACE("TRIANGLE_FAN\n"); | 
|  | *primType = GL_TRIANGLE_FAN; | 
|  | NumVertexes = NumPrimitives + 2; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | FIXME("Unhandled primitive\n"); | 
|  | *primType    = GL_POINTS; | 
|  | break; | 
|  | } | 
|  | return NumVertexes; | 
|  | } | 
|  |  | 
|  | /* Ensure the appropriate material states are set up - only change | 
|  | state if really required                                        */ | 
|  | void init_materials(LPDIRECT3DDEVICE8 iface, BOOL isDiffuseSupplied) { | 
|  |  | 
|  | BOOL requires_material_reset = FALSE; | 
|  | ICOM_THIS(IDirect3DDevice8Impl,iface); | 
|  |  | 
|  | if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == TRUE) { | 
|  | /* If we have not set up the material color tracking, do it now as required */ | 
|  | glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/ | 
|  | checkGLcall("glDisable GL_COLOR_MATERIAL"); | 
|  | TRACE("glColorMaterial Parm=%x\n", This->tracking_parm); | 
|  | glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm); | 
|  | checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)"); | 
|  | glEnable(GL_COLOR_MATERIAL); | 
|  | checkGLcall("glEnable GL_COLOR_MATERIAL"); | 
|  | This->tracking_color = IS_TRACKING; | 
|  | requires_material_reset = TRUE; /* Restore material settings as will be used */ | 
|  |  | 
|  | } else if ((This->tracking_color == IS_TRACKING && isDiffuseSupplied == FALSE) || | 
|  | (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == FALSE)) { | 
|  | /* If we are tracking the current color but one isn't supplied, don't! */ | 
|  | glDisable(GL_COLOR_MATERIAL); | 
|  | checkGLcall("glDisable GL_COLOR_MATERIAL"); | 
|  | This->tracking_color = NEEDS_TRACKING; | 
|  | requires_material_reset = TRUE; /* Restore material settings as will be used */ | 
|  |  | 
|  | } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied == TRUE) { | 
|  | /* No need to reset material colors since no change to gl_color_material */ | 
|  | requires_material_reset = FALSE; | 
|  |  | 
|  | } else if (This->tracking_color == NEEDS_DISABLE) { | 
|  | glDisable(GL_COLOR_MATERIAL); | 
|  | checkGLcall("glDisable GL_COLOR_MATERIAL"); | 
|  | This->tracking_color = DISABLED_TRACKING; | 
|  | requires_material_reset = TRUE; /* Restore material settings as will be used */ | 
|  | } | 
|  |  | 
|  | /* Reset the material colors which may have been tracking the color*/ | 
|  | if (requires_material_reset == TRUE) { | 
|  | glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->StateBlock->material.Ambient); | 
|  | checkGLcall("glMaterialfv"); | 
|  | glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->StateBlock->material.Diffuse); | 
|  | checkGLcall("glMaterialfv"); | 
|  | if (This->StateBlock->renderstate[D3DRS_SPECULARENABLE]) { | 
|  | glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->StateBlock->material.Specular); | 
|  | checkGLcall("glMaterialfv"); | 
|  | } else { | 
|  | float black[4] = {0.0f, 0.0f, 0.0f, 0.0f}; | 
|  | glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]); | 
|  | checkGLcall("glMaterialfv"); | 
|  | } | 
|  | glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->StateBlock->material.Emissive); | 
|  | checkGLcall("glMaterialfv"); | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | static GLfloat invymat[16]={ | 
|  | 1.0f, 0.0f, 0.0f, 0.0f, | 
|  | 0.0f, -1.0f, 0.0f, 0.0f, | 
|  | 0.0f, 0.0f, 1.0f, 0.0f, | 
|  | 0.0f, 0.0f, 0.0f, 1.0f}; | 
|  |  | 
|  | /* Setup views - Transformed & lit if RHW, else untransformed. | 
|  | Only unlit if Normals are supplied | 
|  | Returns: Whether to restore lighting afterwards           */ | 
|  | BOOL primitiveInitState(LPDIRECT3DDEVICE8 iface, BOOL vtx_transformed, BOOL vtx_lit, BOOL useVS) { | 
|  |  | 
|  | BOOL isLightingOn = FALSE; | 
|  | ICOM_THIS(IDirect3DDevice8Impl,iface); | 
|  |  | 
|  | /* If no normals, DISABLE lighting otherwise, don't touch lighing as it is | 
|  | set by the appropriate render state. Note Vertex Shader output is already lit */ | 
|  | if (vtx_lit || useVS) { | 
|  | isLightingOn = glIsEnabled(GL_LIGHTING); | 
|  | glDisable(GL_LIGHTING); | 
|  | checkGLcall("glDisable(GL_LIGHTING);"); | 
|  | TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn); | 
|  | } | 
|  |  | 
|  | if (!useVS && vtx_transformed) { | 
|  |  | 
|  | /* If the last draw was transformed as well, no need to reapply all the matrixes */ | 
|  | if (!This->last_was_rhw) { | 
|  |  | 
|  | double X, Y, height, width, minZ, maxZ; | 
|  | This->last_was_rhw = TRUE; | 
|  |  | 
|  | /* Transformed already into viewport coordinates, so we do not need transform | 
|  | matrices. Reset all matrices to identity and leave the default matrix in world | 
|  | mode.                                                                         */ | 
|  | glMatrixMode(GL_MODELVIEW); | 
|  | checkGLcall("glMatrixMode"); | 
|  | glLoadIdentity(); | 
|  | checkGLcall("glLoadIdentity"); | 
|  |  | 
|  | glMatrixMode(GL_PROJECTION); | 
|  | checkGLcall("glMatrixMode"); | 
|  | glLoadIdentity(); | 
|  | checkGLcall("glLoadIdentity"); | 
|  |  | 
|  | /* Set up the viewport to be full viewport */ | 
|  | X      = This->StateBlock->viewport.X; | 
|  | Y      = This->StateBlock->viewport.Y; | 
|  | height = This->StateBlock->viewport.Height; | 
|  | width  = This->StateBlock->viewport.Width; | 
|  | minZ   = This->StateBlock->viewport.MinZ; | 
|  | maxZ   = This->StateBlock->viewport.MaxZ; | 
|  | TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ); | 
|  | glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ); | 
|  | checkGLcall("glOrtho"); | 
|  |  | 
|  | /* Window Coord 0 is the middle of the first pixel, so translate by half | 
|  | a pixel (See comment above glTranslate below)                         */ | 
|  | glTranslatef(0.5, 0.5, 0); | 
|  | checkGLcall("glTranslatef(0.5, 0.5, 0)"); | 
|  | if (This->renderUpsideDown) { | 
|  | glMultMatrixf(invymat); | 
|  | checkGLcall("glMultMatrixf(invymat)"); | 
|  | } | 
|  | } | 
|  |  | 
|  | } else { | 
|  |  | 
|  | /* Untransformed, so relies on the view and projection matrices */ | 
|  |  | 
|  | if (!useVS && (This->last_was_rhw || !This->modelview_valid)) { | 
|  | /* Only reapply when have to */ | 
|  | This->modelview_valid = TRUE; | 
|  | glMatrixMode(GL_MODELVIEW); | 
|  | checkGLcall("glMatrixMode"); | 
|  |  | 
|  | /* In the general case, the view matrix is the identity matrix */ | 
|  | if (This->view_ident) { | 
|  | glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]); | 
|  | checkGLcall("glLoadMatrixf"); | 
|  | } else { | 
|  | glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0]); | 
|  | checkGLcall("glLoadMatrixf"); | 
|  | glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]); | 
|  | checkGLcall("glMultMatrixf"); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!useVS && (This->last_was_rhw || !This->proj_valid)) { | 
|  | /* Only reapply when have to */ | 
|  | This->proj_valid = TRUE; | 
|  | glMatrixMode(GL_PROJECTION); | 
|  | checkGLcall("glMatrixMode"); | 
|  |  | 
|  | /* The rule is that the window coordinate 0 does not correspond to the | 
|  | beginning of the first pixel, but the center of the first pixel. | 
|  | As a consequence if you want to correctly draw one line exactly from | 
|  | the left to the right end of the viewport (with all matrices set to | 
|  | be identity), the x coords of both ends of the line would be not | 
|  | -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width) | 
|  | instead.                                                               */ | 
|  | glLoadIdentity(); | 
|  | glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0); | 
|  | checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)"); | 
|  |  | 
|  | if (This->renderUpsideDown) { | 
|  | glMultMatrixf(invymat); | 
|  | checkGLcall("glMultMatrixf(invymat)"); | 
|  | } | 
|  | glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]); | 
|  | checkGLcall("glLoadMatrixf"); | 
|  | } | 
|  |  | 
|  | /* Vertex Shader output is already transformed, so set up identity matrices */ | 
|  | /* FIXME: Actually, only true for software emulated ones, so when h/w ones | 
|  | come along this needs to take into account whether s/w ones were | 
|  | requested or not                                                       */ | 
|  | if (useVS) { | 
|  | glMatrixMode(GL_MODELVIEW); | 
|  | checkGLcall("glMatrixMode"); | 
|  | glLoadIdentity(); | 
|  | glMatrixMode(GL_PROJECTION); | 
|  | checkGLcall("glMatrixMode"); | 
|  | glLoadIdentity(); | 
|  | /* Window Coord 0 is the middle of the first pixel, so translate by half | 
|  | a pixel (See comment above glTranslate above)                         */ | 
|  | glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0); | 
|  | checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)"); | 
|  | if (This->renderUpsideDown) { | 
|  | glMultMatrixf(invymat); | 
|  | checkGLcall("glMultMatrixf(invymat)"); | 
|  | } | 
|  | This->modelview_valid = FALSE; | 
|  | This->proj_valid = FALSE; | 
|  | } | 
|  | This->last_was_rhw = FALSE; | 
|  | } | 
|  | return isLightingOn; | 
|  | } | 
|  |  | 
|  | void primitiveConvertToStridedData(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *strided, LONG BaseVertexIndex) { | 
|  |  | 
|  | short         LoopThroughTo = 0; | 
|  | short         nStream; | 
|  | BOOL          canDoViaGLPointers = TRUE; | 
|  | int           numBlends; | 
|  | int           numTextures; | 
|  | int           textureNo; | 
|  | int           coordIdxInfo = 0x00;    /* Information on number of coords supplied */ | 
|  | int           numCoords[8];           /* Holding place for D3DFVF_TEXTUREFORMATx  */ | 
|  |  | 
|  | ICOM_THIS(IDirect3DDevice8Impl,iface); | 
|  |  | 
|  | /* OK, Now to setup the data locations | 
|  | For the non-created vertex shaders, the VertexShader var holds the real | 
|  | FVF and only stream 0 matters | 
|  | For the created vertex shaders, there is an FVF per stream              */ | 
|  | if (!This->StateBlock->streamIsUP && (This->UpdateStateBlock->VertexShader > VS_HIGHESTFIXEDFXF)) { | 
|  | LoopThroughTo = MAX_STREAMS; | 
|  | } else { | 
|  | LoopThroughTo = 1; | 
|  | } | 
|  |  | 
|  | /* Work through stream by stream */ | 
|  | for (nStream=0; nStream<LoopThroughTo; nStream++) { | 
|  | DWORD  stride  = This->StateBlock->stream_stride[nStream]; | 
|  | BYTE  *data    = NULL; | 
|  | DWORD  thisFVF = 0; | 
|  |  | 
|  | /* Skip empty streams */ | 
|  | if (This->StateBlock->stream_source[nStream] == NULL) continue; | 
|  |  | 
|  | /* Retrieve appropriate FVF */ | 
|  | if (LoopThroughTo == 1) { /* VertexShader is FVF */ | 
|  | thisFVF = This->UpdateStateBlock->VertexShader; | 
|  | /* Handle memory passed directly as well as vertex buffers */ | 
|  | if (This->StateBlock->streamIsUP == TRUE) { | 
|  | data    = (BYTE *)This->StateBlock->stream_source[nStream]; | 
|  | } else { | 
|  | data    = ((IDirect3DVertexBuffer8Impl *)This->StateBlock->stream_source[nStream])->allocatedMemory; | 
|  | } | 
|  | } else { | 
|  | thisFVF = This->StateBlock->vertexShaderDecl->fvf[nStream]; | 
|  | data    = ((IDirect3DVertexBuffer8Impl *)This->StateBlock->stream_source[nStream])->allocatedMemory; | 
|  | } | 
|  | VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF)); | 
|  | if (thisFVF == 0) continue; | 
|  |  | 
|  | /* Now convert the stream into pointers */ | 
|  |  | 
|  | /* Shuffle to the beginning of the vertexes to render and index from there */ | 
|  | data = data + (BaseVertexIndex * stride); | 
|  |  | 
|  | /* Either 3 or 4 floats depending on the FVF */ | 
|  | /* FIXME: Can blending data be in a different stream to the position data? | 
|  | and if so using the fixed pipeline how do we handle it               */ | 
|  | if (thisFVF & D3DFVF_POSITION_MASK) { | 
|  | strided->u.s.position.lpData    = data; | 
|  | strided->u.s.position.dwType    = D3DVSDT_FLOAT3; | 
|  | strided->u.s.position.dwStride  = stride; | 
|  | data += 3 * sizeof(float); | 
|  | if (thisFVF & D3DFVF_XYZRHW) { | 
|  | strided->u.s.position.dwType = D3DVSDT_FLOAT4; | 
|  | data += sizeof(float); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */ | 
|  | /** do we have to Check This->UpdateStateBlock->renderstate[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */ | 
|  | numBlends = ((thisFVF & D3DFVF_POSITION_MASK) >> 1) - 2 + | 
|  | ((FALSE == (thisFVF & D3DFVF_LASTBETA_UBYTE4)) ? 0 : -1);    /* WARNING can be < 0 because -2 */ | 
|  | if (numBlends > 0) { | 
|  | canDoViaGLPointers = FALSE; | 
|  | strided->u.s.blendWeights.lpData    = data; | 
|  | strided->u.s.blendWeights.dwType    = D3DVSDT_FLOAT1 + (numBlends - 1); | 
|  | strided->u.s.blendWeights.dwStride  = stride; | 
|  | data += numBlends * sizeof(FLOAT); | 
|  |  | 
|  | if (thisFVF & D3DFVF_LASTBETA_UBYTE4) { | 
|  | strided->u.s.blendMatrixIndices.lpData = data; | 
|  | strided->u.s.blendMatrixIndices.dwType  = D3DVSDT_UBYTE4; | 
|  | strided->u.s.blendMatrixIndices.dwStride= stride; | 
|  | data += sizeof(DWORD); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Normal is always 3 floats */ | 
|  | if (thisFVF & D3DFVF_NORMAL) { | 
|  | strided->u.s.normal.lpData    = data; | 
|  | strided->u.s.normal.dwType    = D3DVSDT_FLOAT3; | 
|  | strided->u.s.normal.dwStride  = stride; | 
|  | data += 3 * sizeof(FLOAT); | 
|  | } | 
|  |  | 
|  | /* Pointsize is a single float */ | 
|  | if (thisFVF & D3DFVF_PSIZE) { | 
|  | strided->u.s.pSize.lpData    = data; | 
|  | strided->u.s.pSize.dwType    = D3DVSDT_FLOAT1; | 
|  | strided->u.s.pSize.dwStride  = stride; | 
|  | data += sizeof(FLOAT); | 
|  | } | 
|  |  | 
|  | /* Diffuse is 4 unsigned bytes */ | 
|  | if (thisFVF & D3DFVF_DIFFUSE) { | 
|  | strided->u.s.diffuse.lpData    = data; | 
|  | strided->u.s.diffuse.dwType    = D3DVSDT_SHORT4; | 
|  | strided->u.s.diffuse.dwStride  = stride; | 
|  | data += sizeof(DWORD); | 
|  | } | 
|  |  | 
|  | /* Specular is 4 unsigned bytes */ | 
|  | if (thisFVF & D3DFVF_SPECULAR) { | 
|  | strided->u.s.specular.lpData    = data; | 
|  | strided->u.s.specular.dwType    = D3DVSDT_SHORT4; | 
|  | strided->u.s.specular.dwStride  = stride; | 
|  | data += sizeof(DWORD); | 
|  | } | 
|  |  | 
|  | /* Texture coords */ | 
|  | numTextures   = (thisFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT; | 
|  | coordIdxInfo  = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of D3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */ | 
|  |  | 
|  | /* numTextures indicates the number of texture coordinates supplied */ | 
|  | /* However, the first set may not be for stage 0 texture - it all   */ | 
|  | /*   depends on D3DTSS_TEXCOORDINDEX.                               */ | 
|  | /* The number of bytes for each coordinate set is based off         */ | 
|  | /*   D3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits              */ | 
|  |  | 
|  | /* So, for each supplied texture extract the coords */ | 
|  | for (textureNo = 0; textureNo < numTextures; ++textureNo) { | 
|  |  | 
|  | strided->u.s.texCoords[textureNo].lpData    = data; | 
|  | strided->u.s.texCoords[textureNo].dwType    = D3DVSDT_FLOAT1; | 
|  | strided->u.s.texCoords[textureNo].dwStride  = stride; | 
|  | numCoords[textureNo] = coordIdxInfo & 0x03; | 
|  |  | 
|  | /* Always one set */ | 
|  | data += sizeof(float); | 
|  | if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT1) { | 
|  | strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT2; | 
|  | data += sizeof(float); | 
|  | if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT2) { | 
|  | strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT3; | 
|  | data += sizeof(float); | 
|  | if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT3) { | 
|  | strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT4; | 
|  | data += sizeof(float); | 
|  | } | 
|  | } | 
|  | } | 
|  | coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */ | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Draw a single vertex using this information */ | 
|  | void draw_vertex(LPDIRECT3DDEVICE8 iface,                              /* interface    */ | 
|  | BOOL isXYZ,    float x, float y, float z, float rhw,  /* xyzn position*/ | 
|  | BOOL isNormal, float nx, float ny, float nz,          /* normal       */ | 
|  | BOOL isDiffuse, float *dRGBA,                         /* 1st   colors */ | 
|  | BOOL isSpecular, float *sRGB,                         /* 2ndry colors */ | 
|  | BOOL isPtSize, float ptSize,                       /* pointSize    */ | 
|  | D3DVECTOR_4 *texcoords, int *numcoords)               /* texture info */ | 
|  | { | 
|  | int textureNo; | 
|  | float s, t, r, q; | 
|  | ICOM_THIS(IDirect3DDevice8Impl,iface); | 
|  |  | 
|  | /* Diffuse -------------------------------- */ | 
|  | if (isDiffuse == TRUE) { | 
|  | glColor4fv(dRGBA); | 
|  | VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3])); | 
|  | } | 
|  |  | 
|  | /* Specular Colour ------------------------------------------*/ | 
|  | if (isSpecular == TRUE) { | 
|  | if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { | 
|  | GL_EXTCALL(glSecondaryColor3fvEXT(sRGB)); | 
|  | VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2])); | 
|  | } else { | 
|  | VTRACE(("Specular color extensions not supplied\n")); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Normal -------------------------------- */ | 
|  | if (isNormal == TRUE) { | 
|  | VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz)); | 
|  | glNormal3f(nx, ny, nz); | 
|  | } | 
|  |  | 
|  | /* Point Size ----------------------------------------------*/ | 
|  | if (isPtSize == TRUE) { | 
|  |  | 
|  | /* no such functionality in the fixed function GL pipeline */ | 
|  | FIXME("Cannot change ptSize here in openGl\n"); | 
|  | } | 
|  |  | 
|  | /* Texture coords --------------------------- */ | 
|  | for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) { | 
|  |  | 
|  | if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) { | 
|  | FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); | 
|  | continue ; | 
|  | } | 
|  |  | 
|  | /* Query tex coords */ | 
|  | if (This->StateBlock->textures[textureNo] != NULL) { | 
|  |  | 
|  | int    coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX]; | 
|  | if (coordIdx > 7) { | 
|  | VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo)); | 
|  | continue; | 
|  | } else if (numcoords[coordIdx] == 0) { | 
|  | TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo); | 
|  | continue; | 
|  | } else { | 
|  |  | 
|  | /* Initialize vars */ | 
|  | s = 0.0f; | 
|  | t = 0.0f; | 
|  | r = 0.0f; | 
|  | q = 0.0f; | 
|  |  | 
|  | switch (numcoords[coordIdx]) { | 
|  | case 4: q = texcoords[coordIdx].w; /* drop through */ | 
|  | case 3: r = texcoords[coordIdx].z; /* drop through */ | 
|  | case 2: t = texcoords[coordIdx].y; /* drop through */ | 
|  | case 1: s = texcoords[coordIdx].x; | 
|  | } | 
|  |  | 
|  | switch (numcoords[coordIdx]) {   /* Supply the provided texture coords */ | 
|  | case D3DTTFF_COUNT1: | 
|  | VTRACE(("tex:%d, s=%f\n", textureNo, s)); | 
|  | if (GL_SUPPORT(ARB_MULTITEXTURE)) { | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s); | 
|  | #else | 
|  | glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s); | 
|  | #endif | 
|  | } else { | 
|  | glTexCoord1f(s); | 
|  | } | 
|  | break; | 
|  | case D3DTTFF_COUNT2: | 
|  | VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t)); | 
|  | if (GL_SUPPORT(ARB_MULTITEXTURE)) { | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t); | 
|  | #else | 
|  | glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t); | 
|  | #endif | 
|  | } else { | 
|  | glTexCoord2f(s, t); | 
|  | } | 
|  | break; | 
|  | case D3DTTFF_COUNT3: | 
|  | VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r)); | 
|  | if (GL_SUPPORT(ARB_MULTITEXTURE)) { | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r); | 
|  | #else | 
|  | glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r); | 
|  | #endif | 
|  | } else { | 
|  | glTexCoord3f(s, t, r); | 
|  | } | 
|  | break; | 
|  | case D3DTTFF_COUNT4: | 
|  | VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q)); | 
|  | if (GL_SUPPORT(ARB_MULTITEXTURE)) { | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q); | 
|  | #else | 
|  | glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q); | 
|  | #endif | 
|  | } else { | 
|  | glTexCoord4f(s, t, r, q); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]); | 
|  | } | 
|  | } | 
|  | } | 
|  | } /* End of textures */ | 
|  |  | 
|  | /* Position -------------------------------- */ | 
|  | if (isXYZ == TRUE) { | 
|  | if (1.0f == rhw || rhw < 0.00001f) { | 
|  | VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z)); | 
|  | glVertex3f(x, y, z); | 
|  | } else { | 
|  | /* Cannot optimize by dividing through by rhw as rhw is required | 
|  | later for perspective in the GL pipeline for vertex shaders   */ | 
|  | VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw)); | 
|  | glVertex4f(x,y,z,rhw); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Actually draw using the supplied information. | 
|  | * Faster GL version using pointers to data, harder to debug though | 
|  | * Note does not handle vertex shaders yet | 
|  | */ | 
|  | void drawStridedFast(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd, | 
|  | int PrimitiveType, ULONG NumPrimitives, | 
|  | const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) { | 
|  | int          textureNo   = 0; | 
|  | GLenum       glPrimType  = GL_POINTS; | 
|  | int          NumVertexes = NumPrimitives; | 
|  | ICOM_THIS(IDirect3DDevice8Impl,iface); | 
|  |  | 
|  | TRACE("Using fast vertex array code\n"); | 
|  |  | 
|  | /* Vertex Pointers -----------------------------------------*/ | 
|  | if (sd->u.s.position.lpData != NULL) { | 
|  |  | 
|  | /* Note dwType == float3 or float4 == 2 or 3 */ | 
|  | VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n", | 
|  | sd->u.s.position.dwStride, | 
|  | sd->u.s.position.dwType + 1, | 
|  | sd->u.s.position.lpData)); | 
|  |  | 
|  | /* Disable RHW mode as 'w' coord handling for rhw mode should | 
|  | not impact screen position whereas in GL it does. This may | 
|  | result in very slightly distored textures in rhw mode, but | 
|  | a very minimal different                                   */ | 
|  | glVertexPointer(3, GL_FLOAT,  /* RHW: Was 'sd->u.s.position.dwType + 1' */ | 
|  | sd->u.s.position.dwStride, | 
|  | sd->u.s.position.lpData); | 
|  | checkGLcall("glVertexPointer(...)"); | 
|  | glEnableClientState(GL_VERTEX_ARRAY); | 
|  | checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)"); | 
|  |  | 
|  | } else { | 
|  |  | 
|  | glDisableClientState(GL_VERTEX_ARRAY); | 
|  | checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)"); | 
|  | } | 
|  |  | 
|  | /* Blend Data ----------------------------------------------*/ | 
|  | if ((sd->u.s.blendWeights.lpData != NULL) || | 
|  | (sd->u.s.blendMatrixIndices.lpData != NULL)) { | 
|  | /* FIXME: Won't get here as will drop to slow method        */ | 
|  | FIXME("Blending not supported in fast draw routine\n"); | 
|  |  | 
|  | #if 0 /* Vertex blend support needs to be added */ | 
|  | if (GL_SUPPORT(ARB_VERTEX_BLEND)) { | 
|  | /*FIXME("TODO\n");*/ | 
|  | } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) { | 
|  | /*FIXME("TODO\n");*/ | 
|  | /* | 
|  | GLExtCall(glVertexWeightPointerEXT)(numBlends, GL_FLOAT, skip, curPos); | 
|  | checkGLcall("glVertexWeightPointerEXT(numBlends, ...)"); | 
|  | glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT); | 
|  | checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)"); | 
|  | */ | 
|  | } else { | 
|  | FIXME("unsupported blending in openGl\n"); | 
|  | } | 
|  | } else { | 
|  | if (GL_SUPPORT(ARB_VERTEX_BLEND)) { | 
|  | FIXME("TODO\n"); | 
|  | } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) { | 
|  | FIXME("TODO\n"); | 
|  | /* | 
|  | glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT); | 
|  | checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)"); | 
|  | */ | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* Normals -------------------------------------------------*/ | 
|  | if (sd->u.s.normal.lpData != NULL) { | 
|  |  | 
|  | /* Note dwType == float3 or float4 == 2 or 3 */ | 
|  | VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n", | 
|  | sd->u.s.normal.dwStride, | 
|  | sd->u.s.normal.lpData)); | 
|  | glNormalPointer(GL_FLOAT, | 
|  | sd->u.s.normal.dwStride, | 
|  | sd->u.s.normal.lpData); | 
|  | checkGLcall("glNormalPointer(...)"); | 
|  | glEnableClientState(GL_NORMAL_ARRAY); | 
|  | checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)"); | 
|  |  | 
|  | } else { | 
|  |  | 
|  | glDisableClientState(GL_NORMAL_ARRAY); | 
|  | checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)"); | 
|  | glNormal3f(0, 0, 1); | 
|  | checkGLcall("glNormal3f(0, 0, 1)"); | 
|  | } | 
|  |  | 
|  | /* Point Size ----------------------------------------------*/ | 
|  | if (sd->u.s.pSize.lpData != NULL) { | 
|  |  | 
|  | /* no such functionality in the fixed function GL pipeline */ | 
|  | /* FIXME: Won't get here as will drop to slow method        */ | 
|  | FIXME("Cannot change ptSize here in openGl\n"); | 
|  | } | 
|  |  | 
|  | /* Diffuse Colour ------------------------------------------*/ | 
|  | /*  WARNING: Data here MUST be in RGBA format, so cannot    */ | 
|  | /*     go directly into fast mode from app pgm, because     */ | 
|  | /*     directx requires data in BGRA format.                */ | 
|  | if (sd->u.s.diffuse.lpData != NULL) { | 
|  |  | 
|  | /* Note dwType == float3 or float4 == 2 or 3 */ | 
|  | VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n", | 
|  | sd->u.s.diffuse.dwStride, | 
|  | sd->u.s.diffuse.lpData)); | 
|  | glColorPointer(4, GL_UNSIGNED_BYTE, | 
|  | sd->u.s.diffuse.dwStride, | 
|  | sd->u.s.diffuse.lpData); | 
|  | checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)"); | 
|  | glEnableClientState(GL_COLOR_ARRAY); | 
|  | checkGLcall("glEnableClientState(GL_COLOR_ARRAY)"); | 
|  |  | 
|  | } else { | 
|  |  | 
|  | glDisableClientState(GL_COLOR_ARRAY); | 
|  | checkGLcall("glDisableClientState(GL_COLOR_ARRAY)"); | 
|  | glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | 
|  | checkGLcall("glColor4f(1, 1, 1, 1)"); | 
|  | } | 
|  |  | 
|  | /* Specular Colour ------------------------------------------*/ | 
|  | if (sd->u.s.specular.lpData != NULL) { | 
|  |  | 
|  | /* Note dwType == float3 or float4 == 2 or 3 */ | 
|  | VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n", | 
|  | sd->u.s.specular.dwStride, | 
|  | sd->u.s.specular.lpData)); | 
|  |  | 
|  | if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { | 
|  | GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE, | 
|  | sd->u.s.specular.dwStride, | 
|  | sd->u.s.specular.lpData); | 
|  | vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)"); | 
|  | glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); | 
|  | vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)"); | 
|  | } else { | 
|  | /* Missing specular color is not critical, no warnings */ | 
|  | VTRACE(("Specular colour is not supported in this GL implementation\n")); | 
|  | } | 
|  |  | 
|  | } else { | 
|  |  | 
|  | if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { | 
|  | glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); | 
|  | checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)"); | 
|  | GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0); | 
|  | checkGLcall("glSecondaryColor3fEXT(0, 0, 0)"); | 
|  | } else { | 
|  | /* Missing specular color is not critical, no warnings */ | 
|  | VTRACE(("Specular colour is not supported in this GL implementation\n")); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Texture coords -------------------------------------------*/ | 
|  | for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) { | 
|  |  | 
|  | /* Select the correct texture stage */ | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glClientActiveTexture(GL_TEXTURE0 + textureNo); | 
|  | #else | 
|  | glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo); | 
|  | #endif | 
|  |  | 
|  | /* Query tex coords */ | 
|  | if (This->StateBlock->textures[textureNo] != NULL) { | 
|  | int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX]; | 
|  |  | 
|  | if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) { | 
|  | FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); | 
|  | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord4f(GL_TEXTURE0 + textureNo, 0, 0, 0, 1); | 
|  | #else | 
|  | glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1); | 
|  | #endif | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (coordIdx > 7) { | 
|  | VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo)); | 
|  | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord4f(GL_TEXTURE0 + textureNo, 0, 0, 0, 1); | 
|  | #else | 
|  | glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1); | 
|  | #endif | 
|  | } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) { | 
|  | VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n")); | 
|  | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord4f(GL_TEXTURE0 + textureNo, 0, 0, 0, 1); | 
|  | #else | 
|  | glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1); | 
|  | #endif | 
|  | } else { | 
|  |  | 
|  | /* The coords to supply depend completely on the fvf / vertex shader */ | 
|  | GLint size; | 
|  | GLenum type; | 
|  |  | 
|  | switch (sd->u.s.texCoords[coordIdx].dwType) { | 
|  | case D3DVSDT_FLOAT1: size = 1, type = GL_FLOAT; break; | 
|  | case D3DVSDT_FLOAT2: size = 2, type = GL_FLOAT; break; | 
|  | case D3DVSDT_FLOAT3: size = 3, type = GL_FLOAT; break; | 
|  | case D3DVSDT_FLOAT4: size = 4, type = GL_FLOAT; break; | 
|  | case D3DVSDT_SHORT2: size = 2, type = GL_SHORT; break; | 
|  | case D3DVSDT_SHORT4: size = 4, type = GL_SHORT; break; | 
|  | case D3DVSDT_UBYTE4: size = 4, type = GL_UNSIGNED_BYTE; break; | 
|  | default: FIXME("Unrecognized data type %ld\n", sd->u.s.texCoords[coordIdx].dwType); | 
|  | size = 4; type = GL_UNSIGNED_BYTE; | 
|  | } | 
|  |  | 
|  | glTexCoordPointer(size, type, sd->u.s.texCoords[coordIdx].dwStride, sd->u.s.texCoords[coordIdx].lpData); | 
|  | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | 
|  | } | 
|  | } else { | 
|  | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord4f(GL_TEXTURE0 + textureNo, 0, 0, 0, 1); | 
|  | #else | 
|  | glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1); | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Ok, Work out which primitive is requested and how many vertexes that | 
|  | will be                                                              */ | 
|  | NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType); | 
|  |  | 
|  | /* Finally do the drawing */ | 
|  | if (idxData != NULL) { | 
|  |  | 
|  | TRACE("glElements(%x, %d, %ld, ...)\n", glPrimType, NumVertexes, minIndex); | 
|  | #if 1  /* FIXME: Want to use DrawRangeElements, but wrong calculation! */ | 
|  | glDrawElements(glPrimType, NumVertexes, idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT, | 
|  | (char *)idxData+(idxSize * startIdx)); | 
|  | #else | 
|  | glDrawRangeElements(glPrimType, minIndex, minIndex+NumVertexes-1, NumVertexes, | 
|  | idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT, | 
|  | (char *)idxData+(idxSize * startIdx)); | 
|  | #endif | 
|  | checkGLcall("glDrawRangeElements"); | 
|  |  | 
|  | } else { | 
|  |  | 
|  | /* Note first is now zero as we shuffled along earlier */ | 
|  | TRACE("glDrawArrays(%x, 0, %d)\n", glPrimType, NumVertexes); | 
|  | glDrawArrays(glPrimType, 0, NumVertexes); | 
|  | checkGLcall("glDrawArrays"); | 
|  |  | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Actually draw using the supplied information. | 
|  | * Slower GL version which extracts info about each vertex in turn | 
|  | */ | 
|  | void drawStridedSlow(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd, | 
|  | int PrimitiveType, ULONG NumPrimitives, | 
|  | const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) { | 
|  |  | 
|  | int                        textureNo    = 0; | 
|  | GLenum                     glPrimType   = GL_POINTS; | 
|  | int                        NumVertexes  = NumPrimitives; | 
|  | const short               *pIdxBufS     = NULL; | 
|  | const long                *pIdxBufL     = NULL; | 
|  | LONG                       SkipnStrides = 0; | 
|  | LONG                       vx_index; | 
|  | float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */ | 
|  | float nx = 0.0f, ny = 0.0, nz = 0.0f;  /* normal x,y,z coordinates   */ | 
|  | float rhw = 0.0f;                      /* rhw                        */ | 
|  | float ptSize = 0.0f;                   /* Point size                 */ | 
|  | DWORD diffuseColor = 0xFFFFFFFF;       /* Diffuse Color              */ | 
|  | DWORD specularColor = 0;               /* Specular Color             */ | 
|  | ICOM_THIS(IDirect3DDevice8Impl,iface); | 
|  |  | 
|  | TRACE("Using slow vertex array code\n"); | 
|  |  | 
|  | /* Variable Initialization */ | 
|  | if (idxData != NULL) { | 
|  | if (idxSize == 2) pIdxBufS = (short *) idxData; | 
|  | else pIdxBufL = (long *) idxData; | 
|  | } | 
|  |  | 
|  | /* Ok, Work out which primitive is requested and how many vertexes that will be */ | 
|  | NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType); | 
|  |  | 
|  | /* Start drawing in GL */ | 
|  | VTRACE(("glBegin(%x)\n", glPrimType)); | 
|  | glBegin(glPrimType); | 
|  |  | 
|  | /* For each primitive */ | 
|  | for (vx_index = 0; vx_index < NumVertexes; vx_index++) { | 
|  |  | 
|  | /* Initialize diffuse color */ | 
|  | diffuseColor = 0xFFFFFFFF; | 
|  |  | 
|  | /* For indexed data, we need to go a few more strides in */ | 
|  | if (idxData != NULL) { | 
|  |  | 
|  | /* Indexed so work out the number of strides to skip */ | 
|  | if (idxSize == 2) { | 
|  | VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index])); | 
|  | SkipnStrides = pIdxBufS[startIdx+vx_index]; | 
|  | } else { | 
|  | VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index])); | 
|  | SkipnStrides = pIdxBufL[startIdx+vx_index]; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Position Information ------------------ */ | 
|  | if (sd->u.s.position.lpData != NULL) { | 
|  |  | 
|  | float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride)); | 
|  | x = ptrToCoords[0]; | 
|  | y = ptrToCoords[1]; | 
|  | z = ptrToCoords[2]; | 
|  | rhw = 1.0; | 
|  | VTRACE(("x,y,z=%f,%f,%f\n", x,y,z)); | 
|  |  | 
|  | /* RHW follows, only if transformed, ie 4 floats were provided */ | 
|  | if (sd->u.s.position.dwType == D3DVSDT_FLOAT4) { | 
|  | rhw = ptrToCoords[3]; | 
|  | VTRACE(("rhw=%f\n", rhw)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Blending data -------------------------- */ | 
|  | if (sd->u.s.blendWeights.lpData != NULL) { | 
|  | /*float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride));*/ | 
|  | FIXME("Blending not supported yet\n"); | 
|  |  | 
|  | if (sd->u.s.blendMatrixIndices.lpData != NULL) { | 
|  | /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/ | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Vertex Normal Data (untransformed only)- */ | 
|  | if (sd->u.s.normal.lpData != NULL) { | 
|  |  | 
|  | float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride)); | 
|  | nx = ptrToCoords[0]; | 
|  | ny = ptrToCoords[1]; | 
|  | nz = ptrToCoords[2]; | 
|  | VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz)); | 
|  | } | 
|  |  | 
|  | /* Point Size ----------------------------- */ | 
|  | if (sd->u.s.pSize.lpData != NULL) { | 
|  |  | 
|  | float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride)); | 
|  | ptSize = ptrToCoords[0]; | 
|  | VTRACE(("ptSize=%f\n", ptSize)); | 
|  | FIXME("No support for ptSize yet\n"); | 
|  | } | 
|  |  | 
|  | /* Diffuse -------------------------------- */ | 
|  | if (sd->u.s.diffuse.lpData != NULL) { | 
|  |  | 
|  | DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride)); | 
|  | diffuseColor = ptrToCoords[0]; | 
|  | VTRACE(("diffuseColor=%lx\n", diffuseColor)); | 
|  | } | 
|  |  | 
|  | /* Specular  -------------------------------- */ | 
|  | if (sd->u.s.specular.lpData != NULL) { | 
|  |  | 
|  | DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride)); | 
|  | specularColor = ptrToCoords[0]; | 
|  | VTRACE(("specularColor=%lx\n", specularColor)); | 
|  | } | 
|  |  | 
|  | /* Texture coords --------------------------- */ | 
|  | for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) { | 
|  |  | 
|  | if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) { | 
|  | FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); | 
|  | continue ; | 
|  | } | 
|  |  | 
|  | /* Query tex coords */ | 
|  | if (This->StateBlock->textures[textureNo] != NULL) { | 
|  |  | 
|  | int    coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX]; | 
|  | float *ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride)); | 
|  | float  s = 0.0, t = 0.0, r = 0.0, q = 0.0; | 
|  |  | 
|  | if (coordIdx > 7) { | 
|  | VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo)); | 
|  | continue; | 
|  | } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) { | 
|  | TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo); | 
|  | continue; | 
|  | } else { | 
|  |  | 
|  | int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DVSDT_FLOAT1 etc */ | 
|  |  | 
|  | /* The coords to supply depend completely on the fvf / vertex shader */ | 
|  | switch (coordsToUse) { | 
|  | case 4: q = ptrToCoords[3]; /* drop through */ | 
|  | case 3: r = ptrToCoords[2]; /* drop through */ | 
|  | case 2: t = ptrToCoords[1]; /* drop through */ | 
|  | case 1: s = ptrToCoords[0]; | 
|  | } | 
|  |  | 
|  | /* Projected is more 'fun' - Move the last coord to the 'q' | 
|  | parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */ | 
|  | if ((This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) && | 
|  | (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) { | 
|  |  | 
|  | if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) { | 
|  | switch (coordsToUse) { | 
|  | case 0:  /* Drop Through */ | 
|  | case 1: | 
|  | FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n"); | 
|  | break; | 
|  | case 2: | 
|  | q = t; | 
|  | t = 0.0; | 
|  | coordsToUse = 4; | 
|  | break; | 
|  | case 3: | 
|  | q = r; | 
|  | r = 0.0; | 
|  | coordsToUse = 4; | 
|  | break; | 
|  | case 4:  /* Nop here */ | 
|  | break; | 
|  | default: | 
|  | FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n", | 
|  | This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | switch (coordsToUse) {   /* Supply the provided texture coords */ | 
|  | case D3DTTFF_COUNT1: | 
|  | VTRACE(("tex:%d, s=%f\n", textureNo, s)); | 
|  | if (GL_SUPPORT(ARB_MULTITEXTURE)) { | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s); | 
|  | #else | 
|  | glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s); | 
|  | #endif | 
|  | } else { | 
|  | glTexCoord1f(s); | 
|  | } | 
|  | break; | 
|  | case D3DTTFF_COUNT2: | 
|  | VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t)); | 
|  | if (GL_SUPPORT(ARB_MULTITEXTURE)) { | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t); | 
|  | #else | 
|  | glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t); | 
|  | #endif | 
|  | } else { | 
|  | glTexCoord2f(s, t); | 
|  | } | 
|  | break; | 
|  | case D3DTTFF_COUNT3: | 
|  | VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r)); | 
|  | if (GL_SUPPORT(ARB_MULTITEXTURE)) { | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r); | 
|  | #else | 
|  | glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r); | 
|  | #endif | 
|  | } else { | 
|  | glTexCoord3f(s, t, r); | 
|  | } | 
|  | break; | 
|  | case D3DTTFF_COUNT4: | 
|  | VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q)); | 
|  | if (GL_SUPPORT(ARB_MULTITEXTURE)) { | 
|  | #if defined(GL_VERSION_1_3) | 
|  | glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q); | 
|  | #else | 
|  | glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q); | 
|  | #endif | 
|  | } else { | 
|  | glTexCoord4f(s, t, r, q); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse); | 
|  | } | 
|  | } | 
|  | } | 
|  | } /* End of textures */ | 
|  |  | 
|  | /* Diffuse -------------------------------- */ | 
|  | if (sd->u.s.diffuse.lpData != NULL) { | 
|  | glColor4ub((diffuseColor >> 16) & 0xFF, | 
|  | (diffuseColor >>  8) & 0xFF, | 
|  | (diffuseColor >>  0) & 0xFF, | 
|  | (diffuseColor >> 24) & 0xFF); | 
|  | VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", | 
|  | ((diffuseColor >> 16) & 0xFF) / 255.0f, | 
|  | ((diffuseColor >>  8) & 0xFF) / 255.0f, | 
|  | ((diffuseColor >>  0) & 0xFF) / 255.0f, | 
|  | ((diffuseColor >> 24) & 0xFF) / 255.0f)); | 
|  | } else { | 
|  | if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | 
|  | } | 
|  |  | 
|  | /* Specular ------------------------------- */ | 
|  | if (sd->u.s.diffuse.lpData != NULL) { | 
|  | VTRACE(("glSecondaryColor4ub: r,g,b=%f,%f,%f\n", | 
|  | ((specularColor >> 16) & 0xFF) / 255.0f, | 
|  | ((specularColor >>  8) & 0xFF) / 255.0f, | 
|  | ((specularColor >>  0) & 0xFF) / 255.0f)); | 
|  | if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { | 
|  | GL_EXTCALL(glSecondaryColor3ubEXT)( | 
|  | (specularColor >> 16) & 0xFF, | 
|  | (specularColor >>  8) & 0xFF, | 
|  | (specularColor >>  0) & 0xFF); | 
|  | } else { | 
|  | /* Do not worry if specular colour missing and disable request */ | 
|  | VTRACE(("Specular color extensions not supplied\n")); | 
|  | } | 
|  | } else { | 
|  | if (vx_index == 0) { | 
|  | if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { | 
|  | GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0); | 
|  | } else { | 
|  | /* Do not worry if specular colour missing and disable request */ | 
|  | VTRACE(("Specular color extensions not supplied\n")); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Normal -------------------------------- */ | 
|  | if (sd->u.s.normal.lpData != NULL) { | 
|  | VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz)); | 
|  | glNormal3f(nx, ny, nz); | 
|  | } else { | 
|  | if (vx_index == 0) glNormal3f(0, 0, 1); | 
|  | } | 
|  |  | 
|  | /* Position -------------------------------- */ | 
|  | if (sd->u.s.position.lpData != NULL) { | 
|  | if (1.0f == rhw || ((rhw < 0.0001f) && (rhw > -0.0001f))) { | 
|  | VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z)); | 
|  | glVertex3f(x, y, z); | 
|  | } else { | 
|  | GLfloat w = 1.0 / rhw; | 
|  | VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw)); | 
|  | glVertex4f(x*w, y*w, z*w, w); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* For non indexed mode, step onto next parts */ | 
|  | if (idxData == NULL) { | 
|  | SkipnStrides += 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | glEnd(); | 
|  | checkGLcall("glEnd and previous calls"); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Draw with emulated vertex shaders | 
|  | * Note: strided data is uninitialized, as we need to pass the vertex | 
|  | *     shader directly as ordering irs yet | 
|  | */ | 
|  | void drawStridedSoftwareVS(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd, | 
|  | int PrimitiveType, ULONG NumPrimitives, | 
|  | const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) { | 
|  |  | 
|  | int                        textureNo    = 0; | 
|  | GLenum                     glPrimType   = GL_POINTS; | 
|  | int                        NumVertexes  = NumPrimitives; | 
|  | const short               *pIdxBufS     = NULL; | 
|  | const long                *pIdxBufL     = NULL; | 
|  | LONG                       SkipnStrides = 0; | 
|  | LONG                       vx_index; | 
|  | float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */ | 
|  | float rhw = 0.0f;                      /* rhw                        */ | 
|  | float ptSize = 0.0f;                   /* Point size                 */ | 
|  | D3DVECTOR_4 texcoords[8];              /* Texture Coords             */ | 
|  | int   numcoords[8];                    /* Number of coords           */ | 
|  | ICOM_THIS(IDirect3DDevice8Impl,iface); | 
|  |  | 
|  | IDirect3DVertexShaderImpl* vertex_shader = NULL; | 
|  |  | 
|  | TRACE("Using slow software vertex shader code\n"); | 
|  |  | 
|  | /* Variable Initialization */ | 
|  | if (idxData != NULL) { | 
|  | if (idxSize == 2) pIdxBufS = (short *) idxData; | 
|  | else pIdxBufL = (long *) idxData; | 
|  | } | 
|  |  | 
|  | /* Ok, Work out which primitive is requested and how many vertexes that will be */ | 
|  | NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType); | 
|  |  | 
|  | /* Retrieve the VS information */ | 
|  | vertex_shader = VERTEX_SHADER(This->StateBlock->VertexShader); | 
|  |  | 
|  | /* Start drawing in GL */ | 
|  | VTRACE(("glBegin(%x)\n", glPrimType)); | 
|  | glBegin(glPrimType); | 
|  |  | 
|  | /* For each primitive */ | 
|  | for (vx_index = 0; vx_index < NumVertexes; vx_index++) { | 
|  |  | 
|  | /* For indexed data, we need to go a few more strides in */ | 
|  | if (idxData != NULL) { | 
|  |  | 
|  | /* Indexed so work out the number of strides to skip */ | 
|  | if (idxSize == 2) { | 
|  | VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index])); | 
|  | SkipnStrides = pIdxBufS[startIdx+vx_index]; | 
|  | } else { | 
|  | VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index])); | 
|  | SkipnStrides = pIdxBufL[startIdx+vx_index]; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Fill the vertex shader input */ | 
|  | IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertex_shader, SkipnStrides); | 
|  |  | 
|  | /* Initialize the output fields to the same defaults as it would normally have */ | 
|  | memset(&vertex_shader->output, 0, sizeof(VSHADEROUTPUTDATA8)); | 
|  | vertex_shader->output.oD[0].x = 1.0; | 
|  | vertex_shader->output.oD[0].y = 1.0; | 
|  | vertex_shader->output.oD[0].z = 1.0; | 
|  | vertex_shader->output.oD[0].w = 1.0; | 
|  |  | 
|  | /* Now execute the vertex shader */ | 
|  | IDirect3DVertexShaderImpl_ExecuteSW(vertex_shader, &vertex_shader->input, &vertex_shader->output); | 
|  |  | 
|  | /* | 
|  | TRACE_VECTOR(vertex_shader->output.oPos); | 
|  | TRACE_VECTOR(vertex_shader->output.oD[0]); | 
|  | TRACE_VECTOR(vertex_shader->output.oD[1]); | 
|  | TRACE_VECTOR(vertex_shader->output.oT[0]); | 
|  | TRACE_VECTOR(vertex_shader->output.oT[1]); | 
|  | TRACE_VECTOR(vertex_shader->input.V[0]); | 
|  | TRACE_VECTOR(vertex_shader->data->C[0]); | 
|  | TRACE_VECTOR(vertex_shader->data->C[1]); | 
|  | TRACE_VECTOR(vertex_shader->data->C[2]); | 
|  | TRACE_VECTOR(vertex_shader->data->C[3]); | 
|  | TRACE_VECTOR(vertex_shader->data->C[4]); | 
|  | TRACE_VECTOR(vertex_shader->data->C[5]); | 
|  | TRACE_VECTOR(vertex_shader->data->C[6]); | 
|  | TRACE_VECTOR(vertex_shader->data->C[7]); | 
|  | */ | 
|  |  | 
|  | /* Extract out the output */ | 
|  | /*FIXME: Fog coords? */ | 
|  | x = vertex_shader->output.oPos.x; | 
|  | y = vertex_shader->output.oPos.y; | 
|  | z = vertex_shader->output.oPos.z; | 
|  | rhw = vertex_shader->output.oPos.w; | 
|  | ptSize = vertex_shader->output.oPts.x; /* Fixme - Is this right? */ | 
|  |  | 
|  | /** Update textures coords using vertex_shader->output.oT[0->7] */ | 
|  | memset(texcoords, 0x00, sizeof(texcoords)); | 
|  | memset(numcoords, 0x00, sizeof(numcoords)); | 
|  | for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) { | 
|  | if (This->StateBlock->textures[textureNo] != NULL) { | 
|  | texcoords[textureNo].x   = vertex_shader->output.oT[textureNo].x; | 
|  | texcoords[textureNo].y   = vertex_shader->output.oT[textureNo].y; | 
|  | texcoords[textureNo].z   = vertex_shader->output.oT[textureNo].z; | 
|  | texcoords[textureNo].w   = vertex_shader->output.oT[textureNo].w; | 
|  | if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) { | 
|  | numcoords[textureNo]    = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED; | 
|  | } else { | 
|  | switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->StateBlock->textures[textureNo])) { | 
|  | case D3DRTYPE_TEXTURE:       numcoords[textureNo]    = 2; break; | 
|  | case D3DRTYPE_VOLUMETEXTURE: numcoords[textureNo]    = 3; break; | 
|  | default:                     numcoords[textureNo]    = 4; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | numcoords[textureNo]    = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Draw using this information */ | 
|  | draw_vertex(iface, | 
|  | TRUE, x, y, z, rhw, | 
|  | TRUE, 0.0f, 0.0f, 1.0f, | 
|  | TRUE, (float*) &vertex_shader->output.oD[0], | 
|  | TRUE, (float*) &vertex_shader->output.oD[1], | 
|  | FALSE, ptSize,         /* FIXME: Change back when supported */ | 
|  | texcoords, numcoords); | 
|  |  | 
|  | /* For non indexed mode, step onto next parts */ | 
|  | if (idxData == NULL) { | 
|  | SkipnStrides += 1; | 
|  | } | 
|  |  | 
|  | } /* for each vertex */ | 
|  |  | 
|  | glEnd(); | 
|  | checkGLcall("glEnd and previous calls"); | 
|  | } | 
|  |  | 
|  | void drawStridedHardwareVS(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd, | 
|  | int PrimitiveType, ULONG NumPrimitives, | 
|  | const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) { | 
|  |  | 
|  | IDirect3DVertexShaderImpl* vertex_shader = NULL; | 
|  | int                        i; | 
|  | int                        NumVertexes; | 
|  | int                        glPrimType; | 
|  | int                        maxAttribs; | 
|  |  | 
|  | ICOM_THIS(IDirect3DDevice8Impl,iface); | 
|  | TRACE("Drawing with hardware vertex shaders\n"); | 
|  |  | 
|  | /* Retrieve the VS information */ | 
|  | vertex_shader = VERTEX_SHADER(This->StateBlock->VertexShader); | 
|  |  | 
|  | /* Enable the Vertex Shader */ | 
|  | GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertex_shader->prgId)); | 
|  | checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertex_shader->prgId);"); | 
|  | glEnable(GL_VERTEX_PROGRAM_ARB); | 
|  | checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);"); | 
|  |  | 
|  | /* Update the constants */ | 
|  | for (i=0; i<D3D8_VSHADER_MAX_CONSTANTS; i++) { | 
|  | GL_EXTCALL(glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, i, (GLfloat *)&This->StateBlock->vertexShaderConstant[i])); | 
|  | checkGLcall("glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB"); | 
|  | } | 
|  |  | 
|  | /* Set up the vertex.attr[n] inputs */ | 
|  | IDirect3DDeviceImpl_FillVertexShaderInputArbHW(This, vertex_shader, 0); | 
|  |  | 
|  | /* Ok, Work out which primitive is requested and how many vertexes that | 
|  | will be                                                              */ | 
|  | NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType); | 
|  |  | 
|  | /* Finally do the drawing */ | 
|  | if (idxData != NULL) { | 
|  |  | 
|  | TRACE("glElements(%x, %d, %ld, ...)\n", glPrimType, NumVertexes, minIndex); | 
|  | #if 1  /* FIXME: Want to use DrawRangeElements, but wrong calculation! */ | 
|  | glDrawElements(glPrimType, NumVertexes, idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT, | 
|  | (char *)idxData+(idxSize * startIdx)); | 
|  | #else | 
|  | glDrawRangeElements(glPrimType, minIndex, minIndex+NumVertexes-1, NumVertexes, | 
|  | idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT, | 
|  | (char *)idxData+(idxSize * startIdx)); | 
|  | #endif | 
|  | checkGLcall("glDrawRangeElements"); | 
|  |  | 
|  | } else { | 
|  |  | 
|  | /* Note first is now zero as we shuffled along earlier */ | 
|  | TRACE("glDrawArrays(%x, 0, %d)\n", glPrimType, NumVertexes); | 
|  | glDrawArrays(glPrimType, 0, NumVertexes); | 
|  | checkGLcall("glDrawArrays"); | 
|  |  | 
|  | } | 
|  |  | 
|  | { | 
|  | GLint errPos; | 
|  | glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos ); | 
|  | if (errPos != -1) | 
|  | FIXME("HW VertexShader Error at position: %d\n%s\n", errPos, glGetString( GL_PROGRAM_ERROR_STRING_ARB) ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Leave all the attribs disabled */ | 
|  | glGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs); | 
|  | /* MESA does not support it right not */ | 
|  | if (glGetError() != GL_NO_ERROR) | 
|  | maxAttribs = 16; | 
|  | for (i=0; i<maxAttribs; i++) { | 
|  | GL_EXTCALL(glDisableVertexAttribArrayARB(i)); | 
|  | checkGLcall("glDisableVertexAttribArrayARB(reg);"); | 
|  | } | 
|  |  | 
|  | /* Done */ | 
|  | glDisable(GL_VERTEX_PROGRAM_ARB); | 
|  | } | 
|  |  | 
|  | /* Routine common to the draw primitive and draw indexed primitive routines */ | 
|  | void drawPrimitive(LPDIRECT3DDEVICE8 iface, | 
|  | int PrimitiveType, long NumPrimitives, | 
|  |  | 
|  | /* for Indexed: */ | 
|  | long  StartVertexIndex, | 
|  | long  StartIdx, | 
|  | short idxSize, | 
|  | const void *idxData, | 
|  | int   minIndex) { | 
|  |  | 
|  | BOOL                          rc = FALSE; | 
|  | DWORD                         fvf = 0; | 
|  | IDirect3DVertexShaderImpl    *vertex_shader = NULL; | 
|  | IDirect3DPixelShaderImpl     *pixel_shader = NULL; | 
|  | BOOL                          useVertexShaderFunction = FALSE; | 
|  | BOOL                          isLightingOn = FALSE; | 
|  | Direct3DVertexStridedData     dataLocations; | 
|  | ICOM_THIS(IDirect3DDevice8Impl,iface); | 
|  | int                           i; | 
|  | int                           useHW = FALSE; | 
|  |  | 
|  | /* Work out what the FVF should look like */ | 
|  | rc = initializeFVF(iface, &fvf, &useVertexShaderFunction); | 
|  | if (rc) return; | 
|  |  | 
|  | /* If we will be using a vertex shader, do some initialization for it */ | 
|  | if (useVertexShaderFunction == TRUE) { | 
|  | vertex_shader = VERTEX_SHADER(This->UpdateStateBlock->VertexShader); | 
|  | memset(&vertex_shader->input, 0, sizeof(VSHADERINPUTDATA8)); | 
|  |  | 
|  | useHW = (((vs_mode == VS_HW) && GL_SUPPORT(ARB_VERTEX_PROGRAM)) && | 
|  | This->devType != D3DDEVTYPE_REF && | 
|  | !This->StateBlock->renderstate[D3DRS_SOFTWAREVERTEXPROCESSING] && | 
|  | vertex_shader->usage != D3DUSAGE_SOFTWAREPROCESSING); | 
|  |  | 
|  | /** init Constants */ | 
|  | if (TRUE == This->UpdateStateBlock->Changed.vertexShaderConstant) { | 
|  | TRACE_(d3d_shader)("vertex shader initializing constants\n"); | 
|  | IDirect3DVertexShaderImpl_SetConstantF(vertex_shader, 0, (CONST FLOAT*) &This->UpdateStateBlock->vertexShaderConstant[0], 96); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Ok, we will be updating the screen from here onwards so grab the lock */ | 
|  | ENTER_GL(); | 
|  |  | 
|  | /* If we will be using a pixel, do some initialization for it */ | 
|  | if ((pixel_shader = PIXEL_SHADER(This->UpdateStateBlock->PixelShader))) { | 
|  | TRACE("drawing with pixel shader handle %p\n", pixel_shader); | 
|  | memset(&pixel_shader->input, 0, sizeof(PSHADERINPUTDATA8)); | 
|  |  | 
|  | GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixel_shader->prgId)); | 
|  | checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixel_shader->prgId);"); | 
|  | glEnable(GL_FRAGMENT_PROGRAM_ARB); | 
|  | checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);"); | 
|  |  | 
|  | /* init Constants */ | 
|  | if (TRUE == This->UpdateStateBlock->Changed.pixelShaderConstant) { | 
|  | TRACE_(d3d_shader)("pixel shader initializing constants %p\n",pixel_shader); | 
|  | IDirect3DPixelShaderImpl_SetConstantF(pixel_shader, 0, (CONST FLOAT*) &This->UpdateStateBlock->pixelShaderConstant[0], 8); | 
|  | } | 
|  | /* Update the constants */ | 
|  | for (i=0; i<D3D8_PSHADER_MAX_CONSTANTS; i++) { | 
|  | GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, (GLfloat *)&This->StateBlock->pixelShaderConstant[i])); | 
|  | checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Setup transform matrices and sort out */ | 
|  | if (useHW) { | 
|  | /* Lighting is not completely bypassed with ATI drivers although it should be. Mesa is ok from this respect... | 
|  | So make sure lighting is disabled. */ | 
|  | isLightingOn = glIsEnabled(GL_LIGHTING); | 
|  | glDisable(GL_LIGHTING); | 
|  | checkGLcall("glDisable(GL_LIGHTING);"); | 
|  | TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn); | 
|  | } else | 
|  | isLightingOn = primitiveInitState(iface, | 
|  | fvf & D3DFVF_XYZRHW, | 
|  | !(fvf & D3DFVF_NORMAL), | 
|  | useVertexShaderFunction); | 
|  |  | 
|  | /* Initialize all values to null */ | 
|  | if (useVertexShaderFunction == FALSE) { | 
|  | memset(&dataLocations, 0x00, sizeof(dataLocations)); | 
|  |  | 
|  | /* Convert to strided data */ | 
|  | primitiveConvertToStridedData(iface, &dataLocations, StartVertexIndex); | 
|  |  | 
|  | /* Dump out what parts we have supplied */ | 
|  | TRACE("Strided Data (from FVF/VS): %lx\n", fvf); | 
|  | TRACE_STRIDED((&dataLocations), position); | 
|  | TRACE_STRIDED((&dataLocations), blendWeights); | 
|  | TRACE_STRIDED((&dataLocations), blendMatrixIndices); | 
|  | TRACE_STRIDED((&dataLocations), normal); | 
|  | TRACE_STRIDED((&dataLocations), pSize); | 
|  | TRACE_STRIDED((&dataLocations), diffuse); | 
|  | TRACE_STRIDED((&dataLocations), specular); | 
|  | TRACE_STRIDED((&dataLocations), texCoords[0]); | 
|  | TRACE_STRIDED((&dataLocations), texCoords[1]); | 
|  | TRACE_STRIDED((&dataLocations), texCoords[2]); | 
|  | TRACE_STRIDED((&dataLocations), texCoords[3]); | 
|  | TRACE_STRIDED((&dataLocations), texCoords[4]); | 
|  | TRACE_STRIDED((&dataLocations), texCoords[5]); | 
|  | TRACE_STRIDED((&dataLocations), texCoords[6]); | 
|  | TRACE_STRIDED((&dataLocations), texCoords[7]); | 
|  | } | 
|  |  | 
|  | /* Now initialize the materials state */ | 
|  | init_materials(iface, (dataLocations.u.s.diffuse.lpData != NULL)); | 
|  |  | 
|  | /* And re-upload any dirty textures */ | 
|  | for (i=0; i<GL_LIMITS(textures); i++) { | 
|  |  | 
|  | if ((This->StateBlock->textures[i] != NULL) && | 
|  | (IDirect3DBaseTexture8Impl_IsDirty(This->StateBlock->textures[i]))) | 
|  | { | 
|  | /* Load up the texture now */ | 
|  | IDirect3DTexture8Impl_PreLoad((LPDIRECT3DTEXTURE8) This->StateBlock->textures[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Now draw the graphics to the screen */ | 
|  | if  (useVertexShaderFunction == TRUE) { | 
|  |  | 
|  | /* Ideally, we should have software FV and hardware VS, possibly | 
|  | depending on the device type?                                 */ | 
|  |  | 
|  | if (useHW) { | 
|  | TRACE("Swap HW vertex shader\n"); | 
|  | drawStridedHardwareVS(iface, &dataLocations, PrimitiveType, NumPrimitives, | 
|  | idxData, idxSize, minIndex, StartIdx); | 
|  | } else { | 
|  | /* We will have to use the very, very slow emulation layer */ | 
|  | TRACE("Swap SW vertex shader\n"); | 
|  | drawStridedSoftwareVS(iface, &dataLocations, PrimitiveType, NumPrimitives, | 
|  | idxData, idxSize, minIndex, StartIdx); | 
|  | } | 
|  |  | 
|  | } else if ((dataLocations.u.s.pSize.lpData        != NULL) || | 
|  | (dataLocations.u.s.diffuse.lpData      != NULL) || | 
|  | (dataLocations.u.s.blendWeights.lpData != NULL)) { | 
|  |  | 
|  | /* Fixme, Ideally, only use the per-vertex code for software HAL | 
|  | but until opengl supports all the functions returned to setup | 
|  | vertex arrays, we need to drop down to the slow mechanism for | 
|  | certain functions                                              */ | 
|  |  | 
|  | /* We will have to use the slow version of GL per vertex setup */ | 
|  | drawStridedSlow(iface, &dataLocations, PrimitiveType, NumPrimitives, | 
|  | idxData, idxSize, minIndex, StartIdx); | 
|  |  | 
|  | } else { | 
|  |  | 
|  | /* We can use the fast version of GL pointers */ | 
|  | drawStridedFast(iface, &dataLocations, PrimitiveType, NumPrimitives, | 
|  | idxData, idxSize, minIndex, StartIdx); | 
|  | } | 
|  |  | 
|  | /* If vertex shaders or no normals, restore previous lighting state */ | 
|  | if (useVertexShaderFunction || !(fvf & D3DFVF_NORMAL)) { | 
|  | if (isLightingOn) glEnable(GL_LIGHTING); | 
|  | else glDisable(GL_LIGHTING); | 
|  | TRACE("Restored lighting to original state\n"); | 
|  | } | 
|  |  | 
|  | if (pixel_shader) | 
|  | { | 
|  | #if 0 | 
|  | GLint errPos; | 
|  | glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos ); | 
|  | if (errPos != -1) | 
|  | FIXME("HW PixelShader Error at position: %d\n%s\n", errPos, glGetString( GL_PROGRAM_ERROR_STRING_ARB) ); | 
|  | #endif | 
|  | glDisable(GL_FRAGMENT_PROGRAM_ARB); | 
|  | } | 
|  |  | 
|  | /* Finshed updating the screen, restore lock */ | 
|  | LEAVE_GL(); | 
|  | TRACE("Done all gl drawing\n"); | 
|  |  | 
|  | /* Diagnostics */ | 
|  | #if defined(SHOW_FRAME_MAKEUP) | 
|  | { | 
|  | if (isDumpingFrames == TRUE) { | 
|  | D3DLOCKED_RECT r; | 
|  | char buffer[80]; | 
|  | IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) This->renderTarget, &r, NULL, D3DLOCK_READONLY); | 
|  | sprintf(buffer, "/tmp/backbuffer_%ld.ppm", primCounter); | 
|  | TRACE("Saving screenshot %s\n", buffer); | 
|  | IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This->renderTarget, buffer); | 
|  | IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) This->renderTarget); | 
|  |  | 
|  | #if defined(SHOW_TEXTURE_MAKEUP) | 
|  | { | 
|  | LPDIRECT3DSURFACE8 pSur; | 
|  | int textureNo; | 
|  | for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) { | 
|  | if (This->StateBlock->textures[textureNo] != NULL) { | 
|  | sprintf(buffer, "/tmp/texture_%ld_%d.ppm", primCounter, textureNo); | 
|  | TRACE("Saving texture %s (Format:%s)\n", buffer, debug_d3dformat(((IDirect3DBaseTexture8Impl *)This->StateBlock->textures[textureNo])->format)); | 
|  | IDirect3DTexture8Impl_GetSurfaceLevel((LPDIRECT3DTEXTURE8) This->StateBlock->textures[textureNo], 0, &pSur); | 
|  | IDirect3DSurface8Impl_SaveSnapshot(pSur, buffer); | 
|  | IDirect3DSurface8Impl_Release(pSur); | 
|  | } | 
|  | } | 
|  | } | 
|  | #endif | 
|  | primCounter = primCounter + 1; | 
|  | } | 
|  | } | 
|  | #endif | 
|  | } |