| /* |
| * 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 |
| } |