http://bugs.winehq.org/show_bug.cgi?id=25298
--- Comment #26 from Vadim vadim.home@gmail.com 2011-02-05 13:30:39 CST --- (From update of attachment 33150) diff -Naur a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c --- a/dlls/wined3d/directx.c 2011-02-03 14:37:38.000000000 +0300 +++ b/dlls/wined3d/directx.c 2011-02-05 22:04:50.000000000 +0300 @@ -4489,8 +4489,13 @@ caps->MaxUserClipPlanes = gl_info->limits.clipplanes; caps->MaxActiveLights = gl_info->limits.lights;
- caps->MaxVertexBlendMatrices = gl_info->limits.blends; - caps->MaxVertexBlendMatrixIndex = 0; + if (gl_info->supported[ARB_VERTEX_BLEND]) { + caps->MaxVertexBlendMatrices = gl_info->limits.blends; + caps->MaxVertexBlendMatrixIndex = 0; + } else { + caps->MaxVertexBlendMatrices = 4; + caps->MaxVertexBlendMatrixIndex = 255; + }
caps->MaxAnisotropy = gl_info->limits.anisotropy; caps->MaxPointSize = gl_info->limits.pointsize_max; diff -Naur a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c --- a/dlls/wined3d/drawprim.c 2011-01-29 03:46:55.000000000 +0300 +++ b/dlls/wined3d/drawprim.c 2011-02-05 22:04:50.000000000 +0300 @@ -50,6 +50,75 @@ }
/* + * Emit a vertex using swoftware vertex blending + */ +static void emitBlendedVertex(struct wined3d_stateblock *stateBlock, + const float *weights, int nweights, const BYTE *indices, + const float *pos, const float *norm) +{ + const float *m; + float vec[4]; + float mat[4*4]; + float last = 1.f; + int i, j; + + /* compute the weighted sum of the matrices */ + m = &stateBlock->state.transforms[WINED3DTS_WORLDMATRIX((indices ? indices[0] : 0))].u.m[0][0]; + for (j = 0; j < 16; j++) + mat[j] = m[j] * weights[0]; + last -= weights[0]; + + for (i = 1; i < nweights; i++) { + if (weights[i]) { + m = &stateBlock->state.transforms[WINED3DTS_WORLDMATRIX((indices ? indices[i] : i))].u.m[0][0]; + for (j = 0; j < 16; j++) + mat[j] += m[j] * weights[i]; + last -= weights[i]; + } + } + + /* do the last */ + if (last) { + m = &stateBlock->state.transforms[WINED3DTS_WORLDMATRIX((indices ? indices[i] : i))].u.m[0][0]; + for (j = 0; j < 16; j++) + mat[j] += m[j] * last; + } + + if (norm) { + /* compute the resulting normal */ + vec[0] = norm[0] * mat[0] + norm[1] * mat[4] + norm[2] * mat[8]; + vec[1] = norm[0] * mat[1] + norm[1] * mat[5] + norm[2] * mat[9]; + vec[2] = norm[0] * mat[2] + norm[1] * mat[6] + norm[2] * mat[10]; + /* normalize */ + vec[3] = vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]; + if (vec[3]) { + vec[3] = 1.f / sqrtf(vec[3]); + vec[0] *= vec[3]; + vec[1] *= vec[3]; + vec[2] *= vec[3]; + } + + glNormal3fv(vec); + } + + if (pos) { + /* compute the resulting position */ + vec[0] = pos[0] * mat[0] + pos[1] * mat[4] + pos[2] * mat[8] + mat[12]; + vec[1] = pos[0] * mat[1] + pos[1] * mat[5] + pos[2] * mat[9] + mat[13]; + vec[2] = pos[0] * mat[2] + pos[1] * mat[6] + pos[2] * mat[10] + mat[14]; + vec[3] = pos[0] * mat[3] + pos[1] * mat[7] + pos[2] * mat[11] + mat[15]; + /* normalize */ + if (vec[3]) { + vec[0] /= vec[3]; + vec[1] /= vec[3]; + vec[2] /= vec[3]; + } + + glVertex3fv(vec); + } +} + +/* * Actually draw using the supplied information. * Slower GL version which extracts info about each vertex in turn */ @@ -69,7 +138,8 @@ BOOL pixelShader = use_ps(state); BOOL specular_fog = FALSE; const BYTE *texCoords[WINED3DDP_MAXTEXCOORD]; - const BYTE *diffuse = NULL, *specular = NULL, *normal = NULL, *position = NULL; + const BYTE *diffuse = NULL, *specular = NULL, *normal = NULL, *position = NULL, *weights = NULL, *indices = NULL; + int nweights = 0; const struct wined3d_gl_info *gl_info = context->gl_info; UINT texture_stages = gl_info->limits.texture_stages; const struct wined3d_stream_info_element *element; @@ -161,6 +231,31 @@ { GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0); } + + if (device->vertexBlendSW) { + if (!si->elements[WINED3D_FFP_BLENDWEIGHT].data) { + WARN("vertex blending enabled but blendWeights.data=NULL\n"); + } else if (si->elements[WINED3D_FFP_BLENDWEIGHT].format->gl_vtx_type != GL_FLOAT) { + FIXME("unsupported blend weights datatype (%d)\n", si->elements[WINED3D_FFP_BLENDWEIGHT].format->id); + } else if (position && si->elements[WINED3D_FFP_POSITION].format->emit_idx != WINED3D_FFP_EMIT_FLOAT3) { + FIXME("unsupported postion datatype (%d)\n", si->elements[WINED3D_FFP_POSITION].format->id); + } else if (normal && si->elements[WINED3D_FFP_NORMAL].format->emit_idx != WINED3D_FFP_EMIT_FLOAT3) { + FIXME("unsupported normal datatype (%d)\n", si->elements[WINED3D_FFP_NORMAL].format->id); + } else { + element = &si->elements[WINED3D_FFP_BLENDWEIGHT]; + weights = element->data + streams[element->stream_idx].offset; + nweights = element->format->gl_vtx_format; + } + + if (si->elements[WINED3D_FFP_BLENDINDICES].data) { + if (si->elements[WINED3D_FFP_BLENDINDICES].format->emit_idx != WINED3D_FFP_EMIT_UBYTE4) { + FIXME("unsupported blend indices datatype (%d)\n", si->elements[WINED3D_FFP_BLENDINDICES].format->id); + } else { + element = &si->elements[WINED3D_FFP_BLENDINDICES]; + indices = element->data + streams[element->stream_idx].offset; + } + } + }
for (textureNo = 0; textureNo < texture_stages; ++textureNo) { @@ -278,17 +373,24 @@ } }
- /* Normal -------------------------------- */ - if (normal) - { - const void *ptrToCoords = normal + SkipnStrides * si->elements[WINED3D_FFP_NORMAL].stride; - normal_funcs[si->elements[WINED3D_FFP_NORMAL].format->emit_idx](ptrToCoords); - } - - /* Position -------------------------------- */ - if (position) { - const void *ptrToCoords = position + SkipnStrides * si->elements[WINED3D_FFP_POSITION].stride; - position_funcs[si->elements[WINED3D_FFP_POSITION].format->emit_idx](ptrToCoords); + if (weights) { + emitBlendedVertex(device->stateBlock, + (const float*)(weights + SkipnStrides * si->elements[WINED3D_FFP_BLENDWEIGHT].stride), nweights, + indices ? (indices + SkipnStrides * si->elements[WINED3D_FFP_BLENDINDICES].stride) : NULL, + (const float*)(position ? (position + SkipnStrides * si->elements[WINED3D_FFP_POSITION].stride) : NULL), + (const float*)(normal ? (normal + SkipnStrides * si->elements[WINED3D_FFP_NORMAL].stride) : NULL)); + } else { + /* Normal -------------------------------- */ + if (normal != NULL) { + const void *ptrToCoords = normal + SkipnStrides * si->elements[WINED3D_FFP_NORMAL].stride; + normal_funcs[si->elements[WINED3D_FFP_NORMAL].format->emit_idx](ptrToCoords); + } + + /* Position -------------------------------- */ + if (position) { + const void *ptrToCoords = position + SkipnStrides * si->elements[WINED3D_FFP_POSITION].stride; + position_funcs[si->elements[WINED3D_FFP_POSITION].format->emit_idx](ptrToCoords); + } }
/* For non indexed mode, step onto next parts */ @@ -678,6 +780,17 @@ } emulation = TRUE; } + else if (device->vertexBlendSW) + { + static BOOL warned; + if (!warned) { + FIXME("Using software emulation because vertex blending is enabled\n"); + warned = TRUE; + } else { + TRACE("Using software emulation because vertex blending is enabled\n"); + } + emulation = TRUE; + }
if(emulation) { stream_info = &stridedlcl; diff -Naur a/dlls/wined3d/state.c b/dlls/wined3d/state.c --- a/dlls/wined3d/state.c 2011-02-01 16:17:23.000000000 +0300 +++ b/dlls/wined3d/state.c 2011-02-05 22:18:26.000000000 +0300 @@ -3771,7 +3771,7 @@ if(context->last_was_rhw) { glLoadIdentity(); checkGLcall("glLoadIdentity()"); - } else { + } else if (!stateblock->device->vertexBlendSW) { /* In the general case, the view matrix is the identity matrix */ if (stateblock->device->view_ident) { @@ -3785,6 +3785,9 @@
glMultMatrixf(&stateblock->state.transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]); checkGLcall("glMultMatrixf"); } + } else { + glLoadMatrixf(&stateblock->state.transforms[WINED3DTS_VIEW].u.m[0][0]); + checkGLcall("glLoadMatrixf"); } }
@@ -3874,13 +3877,33 @@
static void state_vertexblend_w(DWORD state, struct wined3d_stateblock *stateblock, struct wined3d_context *context) { - WINED3DVERTEXBLENDFLAGS f = stateblock->state.render_states[WINED3DRS_VERTEXBLEND]; + WINED3DVERTEXBLENDFLAGS val = stateblock->state.render_states[WINED3DRS_VERTEXBLEND]; static unsigned int once;
- if (f == WINED3DVBF_DISABLE) return; - - if (!once++) FIXME("Vertex blend flags %#x not supported.\n", f); - else WARN("Vertex blend flags %#x not supported.\n", f); + switch (val) { + case WINED3DVBF_0WEIGHTS: + case WINED3DVBF_1WEIGHTS: + case WINED3DVBF_2WEIGHTS: + case WINED3DVBF_3WEIGHTS: + if(!once) { + once = TRUE; + FIXME("Vertex blending enabled, but not supported by hardware. Using software emulation.\n"); + } + if (!stateblock->device->vertexBlendSW) { + stateblock->device->vertexBlendSW = TRUE; + transform_world(state, stateblock, context); + } + break; + case WINED3DVBF_TWEENING: + WARN("Vertex blend flags %#x not supported.\n", val); + /* fall through */ + default: + if (stateblock->device->vertexBlendSW) { + stateblock->device->vertexBlendSW = FALSE; + transform_world(state, stateblock, context); + } + break; + } }
static void state_vertexblend(DWORD state, struct wined3d_stateblock *stateblock, struct wined3d_context *context) diff -Naur a/dlls/wined3d/vertexdeclaration.c b/dlls/wined3d/vertexdeclaration.c --- a/dlls/wined3d/vertexdeclaration.c 2011-02-05 15:14:05.000000000 +0300 +++ b/dlls/wined3d/vertexdeclaration.c 2011-02-05 22:04:50.000000000 +0300 @@ -106,6 +106,15 @@ default: return FALSE; } + + case WINED3DDECLUSAGE_BLENDINDICES: + switch(element->format) + { + case WINED3DFMT_R8G8B8A8_UINT: + return TRUE; + default: + return FALSE; + }
case WINED3DDECLUSAGE_NORMAL: switch(element->format) diff -Naur a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h --- a/dlls/wined3d/wined3d_private.h 2011-02-05 15:14:05.000000000 +0300 +++ b/dlls/wined3d/wined3d_private.h 2011-02-05 22:04:50.000000000 +0300 @@ -1670,6 +1670,7 @@ WORD view_ident : 1; /* true iff view matrix is identity */ WORD untransformed : 1; WORD vertexBlendUsed : 1; /* To avoid needless setting of the blend matrices */ + WORD vertexBlendSW : 1; /* vertexBlend software fallback used */ WORD isRecordingState : 1; WORD isInDraw : 1; WORD bCursorVisible : 1;