wined3d: Move the projection matrix into its own state.

This commit is contained in:
Stefan Dösinger 2007-01-02 22:50:38 +01:00 committed by Alexandre Julliard
parent a0ff9826ad
commit 82bd0790ed
3 changed files with 82 additions and 81 deletions

View File

@ -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)");
}
}
}
}

View File

@ -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 },

View File

@ -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);