diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 2dcaa5d909f..4eb6786e7f4 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -414,6 +414,7 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData ptrToCoords = (float *)(texCoords[coordIdx] + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride)); if (texCoords[coordIdx] == NULL) { TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo); + glTexCoord4f(0, 0, 0, 1); continue; } else { int texture_idx = This->texUnitMap[textureNo]; diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index 45261516f97..900e366fc93 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -1859,6 +1859,13 @@ static void transform_texture(DWORD state, IWineD3DStateBlockImpl *stateblock, W DWORD texUnit = state - STATE_TRANSFORM(WINED3DTS_TEXTURE0); DWORD mapped_stage = stateblock->wineD3DDevice->texUnitMap[texUnit]; + /* Ignore this when a vertex shader is used, or if the streams aren't sorted out yet */ + if(stateblock->vertexShader || + isStateDirty(context, STATE_VDECL)) { + TRACE("Using a vertex shader, or stream sources not sorted out yet, skipping\n"); + return; + } + if (mapped_stage < 0) return; if (GL_SUPPORT(ARB_MULTITEXTURE)) { @@ -1876,7 +1883,10 @@ static void transform_texture(DWORD state, IWineD3DStateBlockImpl *stateblock, W set_texture_matrix((float *)&stateblock->transforms[WINED3DTS_TEXTURE0 + texUnit].u.m[0][0], stateblock->textureState[texUnit][WINED3DTSS_TEXTURETRANSFORMFLAGS], (stateblock->textureState[texUnit][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != WINED3DTSS_TCI_PASSTHRU, - context->last_was_rhw); + context->last_was_rhw, + stateblock->wineD3DDevice->strided_streams.u.s.texCoords[texUnit].dwStride ? + stateblock->wineD3DDevice->strided_streams.u.s.texCoords[texUnit].dwType: + WINED3DDECLTYPE_UNUSED); } @@ -3199,7 +3209,7 @@ static inline void handleStreams(IWineD3DStateBlockImpl *stateblock, BOOL useVer } static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { - BOOL useVertexShaderFunction = FALSE, updateFog = FALSE, updateTexMatrices = FALSE; + BOOL useVertexShaderFunction = FALSE, updateFog = FALSE; BOOL usePixelShaderFunction = stateblock->wineD3DDevice->ps_selected_mode != SHADER_NONE && stateblock->pixelShader && ((IWineD3DPixelShaderImpl *)stateblock->pixelShader)->baseShader.function; BOOL transformed; @@ -3228,7 +3238,6 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W if(transformed != context->last_was_rhw && !useVertexShaderFunction) { updateFog = TRUE; - updateTexMatrices = TRUE; } /* Reapply lighting if it is not scheduled for reapplication already */ @@ -3333,7 +3342,7 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W if(updateFog) { state_fog(STATE_RENDER(WINED3DRS_FOGENABLE), stateblock, context); } - if(updateTexMatrices) { + if(!useVertexShaderFunction) { int i; for(i = 0; i < MAX_TEXTURES; i++) { if(!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_TEXTURE0 + i))) { diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 3f9cdd551e0..941705598de 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -2418,14 +2418,14 @@ void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP #endif /* Setup this textures matrix according to the texture flags*/ -void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed) +void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype) { float mat[16]; glMatrixMode(GL_TEXTURE); checkGLcall("glMatrixMode(GL_TEXTURE)"); - if (flags == WINED3DTTFF_DISABLE || transformed) { + if (flags == WINED3DTTFF_DISABLE || flags == WINED3DTTFF_COUNT1 || transformed) { glLoadIdentity(); checkGLcall("glLoadIdentity()"); return; @@ -2438,12 +2438,6 @@ void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, B memcpy(mat, smat, 16 * sizeof(float)); - switch (flags & ~WINED3DTTFF_PROJECTED) { - case WINED3DTTFF_COUNT1: mat[1] = mat[5] = mat[13] = 0; - case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0; - default: mat[3] = mat[7] = mat[11] = 0, mat[15] = 1; - } - if (flags & WINED3DTTFF_PROJECTED) { switch (flags & ~WINED3DTTFF_PROJECTED) { case WINED3DTTFF_COUNT2: @@ -2456,8 +2450,55 @@ void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, B break; } } else if(!calculatedCoords) { /* under directx the R/Z coord can be used for translation, under opengl we use the Q coord instead */ - mat[12] = mat[8]; - mat[13] = mat[9]; + switch(coordtype) { + case WINED3DDECLTYPE_FLOAT1: + /* Direct3D passes the default 1.0 in the 2nd coord, while gl passes it in the 4th. + * swap 2nd and 4th coord. No need to store the value of mat[12] in mat[4] because + * the input value to the transformation will be 0, so the matrix value is irrelevant + */ + mat[12] = mat[4]; + mat[13] = mat[5]; + mat[14] = mat[6]; + mat[15] = mat[7]; + break; + case WINED3DDECLTYPE_FLOAT2: + /* See above, just 3rd and 4th coord + */ + mat[12] = mat[8]; + mat[13] = mat[9]; + mat[14] = mat[10]; + mat[15] = mat[11]; + break; + case WINED3DDECLTYPE_FLOAT3: /* Opengl defaults match dx defaults */ + case WINED3DDECLTYPE_FLOAT4: /* No defaults apply, all app defined */ + + /* This is to prevent swaping the matrix lines and put the default 4th coord = 1.0 + * into a bad place. The division elimination below will apply to make sure the + * 1.0 doesn't do anything bad. The caller will set this value if the stride is 0 + */ + case WINED3DDECLTYPE_UNUSED: /* No texture coords, 0/0/0/1 defaults are passed */ + break; + default: + FIXME("Unexpected fixed function texture coord input\n"); + } + switch (flags & ~WINED3DTTFF_PROJECTED) { + /* case WINED3DTTFF_COUNT1: Won't ever get here */ + case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0; + /* OpenGL divides the first 3 vertex coord by the 4th by default, + * which is essentially the same as D3DTTFF_PROJECTED. Make sure that + * the 4th coord evaluates to 1.0 to eliminate that. + * + * If the fixed function pipeline is used, the 4th value remains unused, + * so there is no danger in doing this. With vertex shaders we have a + * problem. Should an app hit that problem, the code here would have to + * check for pixel shaders, and the shader has to undo the default gl divide. + * + * A more serious problem occurs if the app passes 4 coordinates in, and the + * 4th is != 1.0(opengl default). This would have to be fixed in drawStridedSlow + * or a replacement shader + */ + default: mat[3] = mat[7] = mat[11] = 0; mat[15] = 1; + } } glLoadMatrixf(mat); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 36185a19826..e02aabb9f5d 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1532,7 +1532,7 @@ GLenum StencilOp(DWORD op); GLenum CompareFunc(DWORD func); void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3); void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3, INT texture_idx); -void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed); +void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype); void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height); GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchain);