Broken character models in dx8/9 games in wined3d

Jason Green jave27 at gmail.com
Mon Jul 24 21:21:27 CDT 2006


I've spent a couple of days researching the issue of
broken/upside-down character/object models in Wine in almost all newer
games when you have vertex shaders enabled (Civ4, Half Life 2,
Oblivion, Max Payne 2, etc.).  I think I've boiled it down to a single
case:  When "device->renderUpsideDown" is set in the case where vertex
shaders are enabled.  That flag gets set in device.c:7395 when the
current renderTarget is not on the current swapchain.  The comments in
the source say that the upside-downedness is produced by
glCopyTexImage, so it sets a flag to flip everything over.

In the case w/o shaders, there is code in drawprim.c which loads the
WORLDVIEW and PROJECTION matrices and then multiplies those matrices
by one which inverts the y coordinates when that flag is set. That
seems to work in the case without vertex shaders, but when shaders are
enabled, they bypass the WORLD, VIEW, and PROJECTION matrices
entirely.  The shader case was written when only software shaders
worked, but that is no longer true.   It loads identity matrices and
performs the y flip, but that code is entirely irrelevant since the
vertex shader doesn't reference those matrices; it only uses constants
that are passed by the app, which we can't perform any type of fixup
on since we don't know which constants will be used for which
calculation.

So, I think what we need to do is prevent ourselves from having to do
any flipping whatsoever.  That's the part that I'm not sure how to do
and is the reason for this email.  Can we load the textures in system
memory first, perform a software reversing process, then load that up
with glCopyTexImage instead?  Will we need to do that type of fixup
every time the app locks/unlocks/changes part of the texture?  Or, is
there a better way?

I think I've figured out the problem, it's just the next step of
fixing it that I'm unsure of.  :-)

>From a few hackish tests, I've been able to fix some of the issues
where the only thing wrong was that the images were upside-down with
this hack (for GLSL shader mode only):


diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index 84f90f5..d0325d9 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -719,6 +719,7 @@ #endif
             shader_addline(&buffer, "gl_FogFragCoord =
clamp(gl_FogFragCoord, 0.0, 1.0);\n");
         }

+        shader_addline(&buffer, "gl_Position = gl_Position *
gl_ModelViewProjectionMatrix;\n");
         shader_addline(&buffer, "}\n\0");

         TRACE("Compiling shader object %u\n", shader_obj);


This works because the gl_ModelViewProjectionMatrix is just a matrix
which reverses the y position when This->renderUpsideDown == TRUE,
otherwise it's the identity matrix.  Here are a few comparison
screenshots:

Oblvion:
---------
Before: http://www.cmhousing.net/wine/oblivion2.png
After:  http://www.cmhousing.net/wine/oblivion_sortacorrect3.png

Civ4:
-----
Before: http://www.cmhousing.net/wine/civ4_before.png
After: http://www.cmhousing.net/wine/civ4_leaderhead.png

Half Life 2:
-------------
After: http://www.cmhousing.net/wine/hl2_rightsideup.png  (the bottom
got screwed up, but normally the guy on the picture is upside-down)

Many of the character models and other objects are still broken even
with that hack, but that's because we should be flipping more than
just the final position - we should be flipping a whole row of
constants that the app is using before it starts its calculations.
Instead of trying to do that, we should fix the root of the problem
IMHO.

Anyway, any ideas are welcome.  :-)

Jason



More information about the wine-devel mailing list