From 564f5828b0fa4e4612802498df688b0e43840f34 Mon Sep 17 00:00:00 2001 From: Jason Edmeades Date: Sat, 19 Jul 2003 03:02:42 +0000 Subject: [PATCH] Add fps debug channel, so we can see how the d3d code is performing and their impact of performance changes. SetTransform almost rewritten in a much neater way, and in coordination with drawprim it significantly reduces the number of times that we reload the matrixes. --- dlls/d3d8/d3d8_private.h | 9 +- dlls/d3d8/device.c | 397 ++++++++++++++------------------------- dlls/d3d8/directx.c | 6 + dlls/d3d8/drawprim.c | 117 +++++++----- 4 files changed, 218 insertions(+), 311 deletions(-) diff --git a/dlls/d3d8/d3d8_private.h b/dlls/d3d8/d3d8_private.h index 1e494acda65..d207e5d2898 100644 --- a/dlls/d3d8/d3d8_private.h +++ b/dlls/d3d8/d3d8_private.h @@ -326,10 +326,11 @@ struct IDirect3DDevice8Impl UINT currentPalette; /* Optimization */ - D3DMATRIX lastProj; - D3DMATRIX lastView; - D3DMATRIX lastWorld0; - D3DMATRIX lastTexTrans[8]; + BOOL modelview_valid; + BOOL proj_valid; + BOOL view_ident; /* true iff view matrix is identity */ + BOOL last_was_rhw; /* true iff last draw_primitive was in xyzrhw mode */ + /* OpenGL related */ GLXContext glCtx; diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index 4c5876188a5..eb1b84aeba0 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -40,11 +40,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d); WINE_DECLARE_DEBUG_CHANNEL(d3d_shader); +WINE_DECLARE_DEBUG_CHANNEL(fps); IDirect3DVertexShaderImpl* VertexShaders[64]; IDirect3DVertexShaderDeclarationImpl* VertexShaderDeclarations[64]; IDirect3DPixelShaderImpl* PixelShaders[64]; +/* Debugging aids: */ #ifdef FRAME_DEBUGGING BOOL isOn = FALSE; BOOL isDumpingFrames = FALSE; @@ -109,6 +111,47 @@ void setupTextureStates(LPDIRECT3DDEVICE8 iface, DWORD Stage) { TRACE("-----------------------> Updated the texture at stage %ld to have new texture state information\n", Stage); } +/* Setup this textures matrix */ +static void set_texture_matrix(float *smat, DWORD flags) +{ + float mat[16]; + + glMatrixMode(GL_TEXTURE); + + if (flags == D3DTTFF_DISABLE) { + glLoadIdentity(); + checkGLcall("glLoadIdentity()"); + return; + } + + if (flags == (D3DTTFF_COUNT1|D3DTTFF_PROJECTED)) { + ERR("Invalid texture transform flags: D3DTTFF_COUNT1|D3DTTFF_PROJECTED\n"); + checkGLcall("glLoadIdentity()"); + return; + } + + memcpy(mat, smat, 16*sizeof(float)); + + switch (flags & ~D3DTTFF_PROJECTED) { + case D3DTTFF_COUNT1: mat[1] = mat[5] = mat[9] = mat[13] = 0; + case D3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0; + default: mat[3] = mat[7] = mat[11] = 0, mat[15] = 1; + } + + if (flags & D3DTTFF_PROJECTED) switch (flags & ~D3DTTFF_PROJECTED) { + case D3DTTFF_COUNT2: + mat[3] = mat[1], mat[7] = mat[5], mat[11] = mat[9], mat[15] = mat[13]; + mat[1] = mat[5] = mat[9] = mat[13] = 0; + break; + case D3DTTFF_COUNT3: + mat[3] = mat[2], mat[7] = mat[6], mat[11] = mat[10], mat[15] = mat[14]; + mat[2] = mat[6] = mat[10] = mat[14] = 0; + break; + } + glLoadMatrixf(mat); + checkGLcall("glLoadMatrixf(mat)"); +} + /* IDirect3D IUnknown parts follow: */ HRESULT WINAPI IDirect3DDevice8Impl_QueryInterface(LPDIRECT3DDEVICE8 iface,REFIID riid,LPVOID *ppobj) { @@ -322,6 +365,21 @@ HRESULT WINAPI IDirect3DDevice8Impl_Present(LPDIRECT3DDEVICE8 iface, CONST REC /* Dont call checkGLcall, as glGetError is not applicable here */ TRACE("glXSwapBuffers called, Starting new frame\n"); + /* FPS support */ + if (TRACE_ON(fps)) + { + static long prev_time, frames; + + DWORD time = GetTickCount(); + frames++; + /* every 1.5 seconds */ + if (time - prev_time > 1500) { + TRACE_(fps)("@@@ %.2ffps\n", 1000.0*frames/(time - prev_time)); + prev_time = time; + frames = 0; + } + } + #if defined(FRAME_DEBUGGING) { if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) { @@ -1244,268 +1302,110 @@ HRESULT WINAPI IDirect3DDevice8Impl_Clear(LPDIRECT3DDEVICE8 iface, DWORD Count } HRESULT WINAPI IDirect3DDevice8Impl_SetTransform(LPDIRECT3DDEVICE8 iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) { ICOM_THIS(IDirect3DDevice8Impl,iface); - D3DMATRIX m; int k; - float f; - BOOL viewChanged = TRUE; - int Stage; /* Most of this routine, comments included copied from ddraw tree initially: */ TRACE("(%p) : State=%d\n", This, d3dts); - This->UpdateStateBlock->Changed.transform[d3dts] = TRUE; - This->UpdateStateBlock->Set.transform[d3dts] = TRUE; - memcpy(&This->UpdateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX)); - /* Handle recording of state blocks */ if (This->isRecordingState) { TRACE("Recording... not performing anything\n"); + This->UpdateStateBlock->Changed.transform[d3dts] = TRUE; + This->UpdateStateBlock->Set.transform[d3dts] = TRUE; + memcpy(&This->UpdateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX)); return D3D_OK; } /* - ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord - - where ViewMat = Camera space, WorldMat = world space. - - In OpenGL, camera and world space is combined into GL_MODELVIEW - matrix. The Projection matrix stay projection matrix. */ - - /* After reading through both OpenGL and Direct3D documentations, I - thought that D3D matrices were written in 'line major mode' transposed - from OpenGL's 'column major mode'. But I found out that a simple memcpy - works fine to transfer one matrix format to the other (it did not work - when transposing).... - - So : - 1) are the documentations wrong - 2) does the matrix work even if they are not read correctly - 3) is Mesa's implementation of OpenGL not compliant regarding Matrix - loading using glLoadMatrix ? - - Anyway, I always use 'conv_mat' to transfer the matrices from one format - to the other so that if I ever find out that I need to transpose them, I - will able to do it quickly, only by changing the macro conv_mat. */ - - if (d3dts < 256) { - switch (d3dts) { - case D3DTS_VIEW: - conv_mat(lpmatrix, &This->StateBlock->transforms[D3DTS_VIEW]); - break; - - case D3DTS_PROJECTION: - conv_mat(lpmatrix, &This->StateBlock->transforms[D3DTS_PROJECTION]); - break; - - case D3DTS_TEXTURE0: - case D3DTS_TEXTURE1: - case D3DTS_TEXTURE2: - case D3DTS_TEXTURE3: - case D3DTS_TEXTURE4: - case D3DTS_TEXTURE5: - case D3DTS_TEXTURE6: - case D3DTS_TEXTURE7: - conv_mat(lpmatrix, &This->StateBlock->transforms[d3dts]); - break; - - default: - FIXME("Unhandled transform state!!\n"); - break; - } + * if the new matrix is the same as the current one, + * we cut off any further processing. this seems to be a reasonable + * optimization because as was noticed, some apps (warcraft3 for example) + * tend towards setting the same matrix repeatedly for some dumb reason. + * + * From here on we assume that the new matrix is different, wherever it matters + * but note + */ + if (!memcmp(&This->StateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) { + TRACE("The app is setting the same matrix over again\n"); + return D3D_OK; } else { - /** - * Indexed Vertex Blending Matrices 256 -> 511 - * where WORLDMATRIX(0) == 256! - */ - /** store it */ - conv_mat(lpmatrix, &This->StateBlock->transforms[d3dts]); -#if 0 - if (GL_SUPPORT(ARB_VERTEX_BLEND)) { - FIXME("TODO\n"); - } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) { - FIXME("TODO\n"); - } -#endif + conv_mat(lpmatrix, &This->StateBlock->transforms[d3dts].u.m[0][0]); } /* - * Move the GL operation to outside of switch to make it work - * regardless of transform set order. + ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord + where ViewMat = Camera space, WorldMat = world space. + + In OpenGL, camera and world space is combined into GL_MODELVIEW + matrix. The Projection matrix stay projection matrix. */ + + /* Capture the times we can just ignore the change */ + if (d3dts == D3DTS_WORLDMATRIX(0)) { + This->modelview_valid = FALSE; + return D3D_OK; + + } else if (d3dts == D3DTS_PROJECTION) { + This->proj_valid = FALSE; + return D3D_OK; + + } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) { /* Indexed Vertex Blending Matrices 256 -> 511 */ + /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */ + FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n"); + return D3D_OK; + } + + /* Chances are we really are going to have to change a matrix */ ENTER_GL(); - if (memcmp(&This->lastProj, &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0], sizeof(D3DMATRIX))) { - glMatrixMode(GL_PROJECTION); - checkGLcall("glMatrixMode"); - glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]); - checkGLcall("glLoadMatrixf"); - memcpy(&This->lastProj, &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0], sizeof(D3DMATRIX)); - } else { - TRACE("Skipping as projection already correct\n"); - } - glMatrixMode(GL_MODELVIEW); - checkGLcall("glMatrixMode"); - viewChanged = FALSE; - if (memcmp(&This->lastView, &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0], sizeof(D3DMATRIX))) { - glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0]); - checkGLcall("glLoadMatrixf"); - memcpy(&This->lastView, &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0], sizeof(D3DMATRIX)); - viewChanged = TRUE; - - /* If we are changing the View matrix, reset the light and clipping planes to the new view */ - if (d3dts == D3DTS_VIEW) { - - /* NOTE: We have to reset the positions even if the light/plane is not currently - enabled, since the call to enable it will not reset the position. */ - - /* Reset lights */ - for (k = 0; k < GL_LIMITS(lights); k++) { - glLightfv(GL_LIGHT0 + k, GL_POSITION, &This->lightPosn[k][0]); - checkGLcall("glLightfv posn"); - glLightfv(GL_LIGHT0 + k, GL_SPOT_DIRECTION, &This->lightDirn[k][0]); - checkGLcall("glLightfv dirn"); - } - - /* Reset Clipping Planes if clipping is enabled */ - for (k = 0; k < GL_LIMITS(clipplanes); k++) { - glClipPlane(GL_CLIP_PLANE0 + k, This->StateBlock->clipplane[k]); - checkGLcall("glClipPlane"); - } - - /* Reapply texture transforms as based off modelview when applied */ - for (Stage = 0; Stage < GL_LIMITS(textures); Stage++) { - - /* Only applicable if the transforms are not disabled */ - if (This->UpdateStateBlock->texture_state[Stage][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) - { - /* Now apply texture transforms if not applying to the dummy textures */ + if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */ + if (d3dts < GL_LIMITS(textures)) { + int tex = d3dts - D3DTS_TEXTURE0; #if defined(GL_VERSION_1_3) - glActiveTexture(GL_TEXTURE0 + Stage); + glActiveTexture(GL_TEXTURE0 + tex); #else - glActiveTextureARB(GL_TEXTURE0_ARB + Stage); + glActiveTextureARB(GL_TEXTURE0_ARB + tex); #endif - checkGLcall("glActiveTexture(GL_TEXTURE0 + Stage);"); - - glMatrixMode(GL_TEXTURE); - if (This->StateBlock->textureDimensions[Stage] == GL_TEXTURE_1D) { - glLoadIdentity(); - } else { - D3DMATRIX fred; - conv_mat(&This->StateBlock->transforms[D3DTS_TEXTURE0+Stage], &fred); - glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_TEXTURE0+Stage].u.m[0][0]); - } - } - checkGLcall("Load matrix for texture"); - } - glMatrixMode(GL_MODELVIEW); /* Always leave in model view */ - } - } else if ((d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) && - (This->UpdateStateBlock->texture_state[d3dts - D3DTS_TEXTURE0][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE)) { - /* Now apply texture transforms if not applying to the dummy textures */ - Stage = d3dts - D3DTS_TEXTURE0; - - if (memcmp(&This->lastTexTrans[Stage], &This->StateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], sizeof(D3DMATRIX))) { - memcpy(&This->lastTexTrans[Stage], &This->StateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], sizeof(D3DMATRIX)); - -#if defined(GL_VERSION_1_3) - glActiveTexture(GL_TEXTURE0 + Stage); -#else - glActiveTextureARB(GL_TEXTURE0_ARB + Stage); -#endif - checkGLcall("glActiveTexture(GL_TEXTURE0 + Stage)"); - - glMatrixMode(GL_TEXTURE); - if (This->StateBlock->textureDimensions[Stage] == GL_TEXTURE_1D) { - glLoadIdentity(); - } else { - D3DMATRIX fred; - conv_mat(&This->StateBlock->transforms[D3DTS_TEXTURE0+Stage], &fred); - glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_TEXTURE0+Stage].u.m[0][0]); - } - checkGLcall("Load matrix for texture"); - glMatrixMode(GL_MODELVIEW); /* Always leave in model view */ - } else { - TRACE("Skipping texture transform as already correct\n"); + set_texture_matrix((float *)lpmatrix, This->UpdateStateBlock->texture_state[tex][D3DTSS_TEXTURETRANSFORMFLAGS]); } - } else { - TRACE("Skipping view setup as view already correct\n"); - } - - /** - * Vertex Blending as described - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/enums/d3dvertexblendflags.asp - */ - switch (This->UpdateStateBlock->vertex_blend) { - case D3DVBF_DISABLE: - { - if (viewChanged == TRUE || - (memcmp(&This->lastWorld0, &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0], sizeof(D3DMATRIX)))) { - memcpy(&This->lastWorld0, &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0], sizeof(D3DMATRIX)); - if (viewChanged == FALSE) { - 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"); - } else { - TRACE("Skipping as world already correct\n"); - } - } - break; - case D3DVBF_1WEIGHTS: - case D3DVBF_2WEIGHTS: - case D3DVBF_3WEIGHTS: - { - FIXME("valid/correct D3DVBF_[1..3]WEIGHTS\n"); - /* - * doc seems to say that the weight values must be in vertex data (specified in FVF by D3DFVF_XYZB*) - * so waiting for the values before matrix work - for (k = 0; k < This->UpdateStateBlock->vertex_blend; ++k) { - glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(k)].u.m[0][0]); - checkGLcall("glMultMatrixf"); - } - */ - } - break; - case D3DVBF_TWEENING: - { - FIXME("valid/correct D3DVBF_TWEENING\n"); - f = This->UpdateStateBlock->tween_factor; - m.u.s._11 = f; m.u.s._12 = f; m.u.s._13 = f; m.u.s._14 = f; - m.u.s._21 = f; m.u.s._22 = f; m.u.s._23 = f; m.u.s._24 = f; - m.u.s._31 = f; m.u.s._32 = f; m.u.s._33 = f; m.u.s._34 = f; - m.u.s._41 = f; m.u.s._42 = f; m.u.s._43 = f; m.u.s._44 = f; - if (viewChanged == FALSE) { - glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0]); - checkGLcall("glLoadMatrixf"); - } - glMultMatrixf((float *) &m.u.m[0][0]); - checkGLcall("glMultMatrixf"); - } - break; - case D3DVBF_0WEIGHTS: - { - FIXME("valid/correct D3DVBF_0WEIGHTS\n"); - /* single matrix of weight 1.0f */ - m.u.s._11 = 1.0f; m.u.s._12 = 1.0f; m.u.s._13 = 1.0f; m.u.s._14 = 1.0f; - m.u.s._21 = 1.0f; m.u.s._22 = 1.0f; m.u.s._23 = 1.0f; m.u.s._24 = 1.0f; - m.u.s._31 = 1.0f; m.u.s._32 = 1.0f; m.u.s._33 = 1.0f; m.u.s._34 = 1.0f; - m.u.s._41 = 1.0f; m.u.s._42 = 1.0f; m.u.s._43 = 1.0f; m.u.s._44 = 1.0f; - if (viewChanged == FALSE) { - glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0]); - checkGLcall("glLoadMatrixf"); - } - glMultMatrixf((float *) &m.u.m[0][0]); - checkGLcall("glMultMatrixf"); - } - break; - default: - break; /* stupid compilator */ + } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */ + float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; + This->modelview_valid = FALSE; + This->view_ident = !memcmp(lpmatrix, identity, 16*sizeof(float)); + glMatrixMode(GL_MODELVIEW); + checkGLcall("glMatrixMode(GL_MODELVIEW)"); + glPushMatrix(); + glLoadMatrixf((float *)lpmatrix); + checkGLcall("glLoadMatrixf(...)"); + + /* If we are changing the View matrix, reset the light and clipping planes to the new view + * NOTE: We have to reset the positions even if the light/plane is not currently + * enabled, since the call to enable it will not reset the position. + * NOTE2: Apparently texture transforms do NOT need reapplying + */ + + /* Reset lights */ + for (k = 0; k < GL_LIMITS(lights); k++) { + glLightfv(GL_LIGHT0 + k, GL_POSITION, This->lightPosn[k]); + checkGLcall("glLightfv posn"); + glLightfv(GL_LIGHT0 + k, GL_SPOT_DIRECTION, This->lightDirn[k]); + checkGLcall("glLightfv dirn"); + } + /* Reset Clipping Planes if clipping is enabled */ + for (k = 0; k < GL_LIMITS(clipplanes); k++) { + glClipPlane(GL_CLIP_PLANE0 + k, This->StateBlock->clipplane[k]); + checkGLcall("glClipPlane"); + } + glPopMatrix(); + + } else { /* What was requested!?? */ + WARN("invalid matrix specified: %i\n", d3dts); + } + /* Release lock, all done */ LEAVE_GL(); - return D3D_OK; } @@ -1887,9 +1787,9 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetClipPlane(LPDIRECT3DDEVICE8 iface, DWOR This->UpdateStateBlock->clipplane[Index][2], This->UpdateStateBlock->clipplane[Index][3]); glClipPlane(GL_CLIP_PLANE0 + Index, This->UpdateStateBlock->clipplane[Index]); + checkGLcall("glClipPlane"); glPopMatrix(); - checkGLcall("glClipPlane"); LEAVE_GL(); @@ -3278,30 +3178,7 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetTextureStageState(LPDIRECT3DDEVICE8 ifa break; case D3DTSS_TEXTURETRANSFORMFLAGS : - { - switch (Value & ~D3DTTFF_PROJECTED) - { - case D3DTTFF_DISABLE: /* Disable transform matrix for this texture by setting up the identity matrix */ - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - checkGLcall("Load identity matrix for texture"); - glMatrixMode(GL_MODELVIEW); /* Always leave in model view */ - break; - - default: /* Enable it */ - IDirect3DDevice8Impl_SetTransform(iface, D3DTS_TEXTURE0+Stage, &This->UpdateStateBlock->transforms[D3DTS_TEXTURE0+Stage]); - break; - } - - /* From web: - I interpret this as we can implement projected transforms in slow vertex mode - by moving the last coord to the 'q' coord and using one less dimension. The only - way to do it in TexCoordPtr would be to massage the data stream to insert extra - coords */ - } + set_texture_matrix((float *)&This->StateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], Value); break; case D3DTSS_MIPMAPLODBIAS : diff --git a/dlls/d3d8/directx.c b/dlls/d3d8/directx.c index 8ede01b3875..251c1eb81dc 100644 --- a/dlls/d3d8/directx.c +++ b/dlls/d3d8/directx.c @@ -1083,6 +1083,12 @@ HRESULT WINAPI IDirect3D8Impl_CreateDevice (LPDIRECT3D8 iface, IDirect3DDevice8Impl_SetViewport((LPDIRECT3DDEVICE8) object, &vp); } + /* Initialize the current view state */ + object->modelview_valid = 1; + object->proj_valid = 0; + object->view_ident = 1; + object->last_was_rhw = 0; + TRACE("(%p,%d) All defaults now set up, leaving CreateDevice\n", This, Adapter); return D3D_OK; } diff --git a/dlls/d3d8/drawprim.c b/dlls/d3d8/drawprim.c index f9993bceaf6..c534575d4d5 100644 --- a/dlls/d3d8/drawprim.c +++ b/dlls/d3d8/drawprim.c @@ -172,67 +172,90 @@ BOOL primitiveInitState(LPDIRECT3DDEVICE8 iface, BOOL vtx_transformed, BOOL vtx_ isLightingOn = glIsEnabled(GL_LIGHTING); glDisable(GL_LIGHTING); checkGLcall("glDisable(GL_LIGHTING);"); - TRACE("Enabled lighting as no normals supplied, old state = %d\n", isLightingOn); + TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn); } if (vtx_transformed) { - double X, Y, height, width, minZ, maxZ; - /* 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"); + /* If the last draw was transformed as well, no need to reapply all the matrixes */ + if (!This->last_was_rhw) { - glMatrixMode(GL_PROJECTION); - checkGLcall("glMatrixMode"); - glLoadIdentity(); - checkGLcall("glLoadIdentity"); + double X, Y, height, width, minZ, maxZ; + This->last_was_rhw = TRUE; - /* 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"); + /* 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"); - /* 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)"); + 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)"); + } } else { /* Untransformed, so relies on the view and projection matrices */ - glMatrixMode(GL_MODELVIEW); - checkGLcall("glMatrixMode"); - 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"); - glMatrixMode(GL_PROJECTION); - checkGLcall("glMatrixMode"); + if (This->last_was_rhw || !This->modelview_valid) { + /* Only reapply when have to */ + This->modelview_valid = TRUE; + glMatrixMode(GL_MODELVIEW); + 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)"); - glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]); - checkGLcall("glLoadMatrixf"); + /* 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 (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)"); + glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]); + checkGLcall("glLoadMatrixf"); + } + + This->last_was_rhw = FALSE; } return isLightingOn; }