From 82bd0790ed1c294b96e330d5800e8a54fb81566d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Tue, 2 Jan 2007 22:50:38 +0100 Subject: [PATCH] wined3d: Move the projection matrix into its own state. --- dlls/wined3d/drawprim.c | 57 ----------------------- dlls/wined3d/state.c | 100 ++++++++++++++++++++++++++++++---------- dlls/wined3d/surface.c | 6 +++ 3 files changed, 82 insertions(+), 81 deletions(-) diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 487a418da30..d6e60bcaba0 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -158,8 +158,6 @@ static const GLfloat invymat[16] = { void d3ddevice_set_ortho(IWineD3DDeviceImpl *This) { /* If the last draw was transformed as well, no need to reapply all the matrixes */ if ( (!This->last_was_rhw) || (This->viewport_changed) ) { - - double X, Y, height, width, minZ, maxZ; This->last_was_rhw = TRUE; This->viewport_changed = FALSE; @@ -170,61 +168,6 @@ void d3ddevice_set_ortho(IWineD3DDeviceImpl *This) { checkGLcall("glMatrixMode(GL_MODELVIEW)"); glLoadIdentity(); checkGLcall("glLoadIdentity"); - - glMatrixMode(GL_PROJECTION); - checkGLcall("glMatrixMode(GL_PROJECTION)"); - 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; - if(!This->untransformed) { - TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ); - glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ); - } else { - TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, 1.0, -1.0); - glOrtho(X, X + width, Y + height, Y, 1.0, -1.0); - } - 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.375, 0.375, 0); - checkGLcall("glTranslatef(0.375, 0.375, 0)"); - /* D3D texture coordinates are flipped compared to OpenGL ones, so - * render everything upside down when rendering offscreen. */ - if (This->render_offscreen) { - glMultMatrixf(invymat); - checkGLcall("glMultMatrixf(invymat)"); - } - - /* Vertex fog on transformed vertices? Use the calculated fog factor stored in the specular color */ - if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != WINED3DFOG_NONE) { - if(GL_SUPPORT(EXT_FOG_COORD)) { - glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT); - checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)"); - glFogi(GL_FOG_MODE, GL_LINEAR); - checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)"); - /* The dx fog range in this case is fixed to 0 - 255, - * but in GL it still depends on the fog start and end (according to the ext) - * Use this to turn around the fog as it's needed. That prevents some - * calculations during drawing :-) - */ - glFogf(GL_FOG_START, (float) 0xff); - checkGLcall("glFogfv GL_FOG_END"); - glFogf(GL_FOG_END, 0.0); - checkGLcall("glFogfv GL_FOG_START"); - } else { - /* Disable GL fog, handle this in software in drawStridedSlow */ - glDisable(GL_FOG); - checkGLcall("glDisable(GL_FOG)"); - } - } } } diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index e8a594e460a..1898839a628 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -1900,6 +1900,74 @@ static const GLfloat invymat[16] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; +static void transform_projection(DWORD state, IWineD3DStateBlockImpl *stateblock) { + glMatrixMode(GL_PROJECTION); + checkGLcall("glMatrixMode(GL_PROJECTION)"); + glLoadIdentity(); + checkGLcall("glLoadIdentity"); + + if(stateblock->wineD3DDevice->last_was_rhw) { + double X, Y, height, width, minZ, maxZ; + + X = stateblock->viewport.X; + Y = stateblock->viewport.Y; + height = stateblock->viewport.Height; + width = stateblock->viewport.Width; + minZ = stateblock->viewport.MinZ; + maxZ = stateblock->viewport.MaxZ; + + if(!stateblock->wineD3DDevice->untransformed) { + /* Transformed vertices are supposed to bypass the whole transform pipeline including + * frustum clipping. This can't be done in opengl, so this code adjusts the Z range to + * suppress depth clipping. This can be done because it is an orthogonal projection and + * the Z coordinate does not affect the size of the primitives + */ + TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ); + glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ); + } else { + /* If the app mixes transformed and untransformed primitives we can't use the coordinate system + * trick above because this would mess up transformed and untransformed Z order. Pass the z position + * unmodified to opengl. + * + * If the app depends on mixed types and disabled clipping we're out of luck without a pipeline + * replacement shader. + */ + TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, 1.0, -1.0); + glOrtho(X, X + width, Y + height, Y, 1.0, -1.0); + } + checkGLcall("glOrtho"); + + /* Window Coord 0 is the middle of the first pixel, so translate by 3/8 pixels */ + glTranslatef(0.375, 0.375, 0); + checkGLcall("glTranslatef(0.375, 0.375, 0)"); + /* D3D texture coordinates are flipped compared to OpenGL ones, so + * render everything upside down when rendering offscreen. */ + if (stateblock->wineD3DDevice->render_offscreen) { + glMultMatrixf(invymat); + checkGLcall("glMultMatrixf(invymat)"); + } + } else { + /* 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. */ + glTranslatef(0.9 / stateblock->viewport.Width, -0.9 / stateblock->viewport.Height, 0); + checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)"); + + /* D3D texture coordinates are flipped compared to OpenGL ones, so + * render everything upside down when rendering offscreen. */ + if (stateblock->wineD3DDevice->render_offscreen) { + glMultMatrixf(invymat); + checkGLcall("glMultMatrixf(invymat)"); + } + glMultMatrixf((float *) &stateblock->transforms[WINED3DTS_PROJECTION].u.m[0][0]); + checkGLcall("glLoadMatrixf"); + } +} + static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock) { BOOL useVertexShaderFunction = FALSE, updateFog = FALSE; BOOL transformed; @@ -1993,29 +2061,6 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock) { if (!useVertexShaderFunction) { device->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(0.9 / stateblock->viewport.Width, -0.9 / stateblock->viewport.Height, 0); - checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)"); - - /* D3D texture coordinates are flipped compared to OpenGL ones, so - * render everything upside down when rendering offscreen. */ - if (device->render_offscreen) { - glMultMatrixf(invymat); - checkGLcall("glMultMatrixf(invymat)"); - } - glMultMatrixf((float *) &stateblock->transforms[WINED3DTS_PROJECTION].u.m[0][0]); - checkGLcall("glLoadMatrixf"); } /* Vertex Shader output is already transformed, so set up identity matrices */ @@ -2027,6 +2072,13 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock) { device->last_was_rhw = FALSE; } + /* TODO: Move this mainly to the viewport state and only apply when the vp has changed + * or transformed / untransformed was switched + */ + if(!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(WINED3DTS_PROJECTION))) { + transform_projection(STATE_TRANSFORM(WINED3DTS_PROJECTION), stateblock); + } + /* Setup fogging */ if(updateFog) { state_fog(STATE_RENDER(WINED3DRS_FOGENABLE), stateblock); @@ -2535,7 +2587,7 @@ const struct StateEntry StateTable[] = /* Transform states follow */ { /* 1, undefined */ 0, state_undefined }, { /* 2, WINED3DTS_VIEW */ STATE_TRANSFORM(WINED3DTS_VIEW), transform_view }, - { /* 3, WINED3DTS_PROJECTION */ STATE_VDECL, vertexdeclaration }, + { /* 3, WINED3DTS_PROJECTION */ STATE_TRANSFORM(WINED3DTS_PROJECTION), transform_projection}, { /* 4, undefined */ 0, state_undefined }, { /* 5, undefined */ 0, state_undefined }, { /* 6, undefined */ 0, state_undefined }, diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 200b52ea50d..189550ebcd4 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -1150,6 +1150,9 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) { we want to draw at screen position 0,0 - Set up ortho (rhw) mode as per drawprim (and leave set - it will sort itself out due to last_was_rhw */ d3ddevice_set_ortho(This->resource.wineD3DDevice); + /* Apply the projection matrix, it sets up orthogonal projection due to last_was_rhw */ + StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock); + /* Will reapply the projection matrix too */ IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL); if (iface == implSwapChain->frontBuffer) { @@ -2474,6 +2477,9 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * /* Draw a textured quad */ d3ddevice_set_ortho(This->resource.wineD3DDevice); + /* Apply the projection matrix, it sets up orthogonal projection due to last_was_rhw */ + StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock); + /* That will reapply the projection matrix too */ IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL); glBegin(GL_QUADS);