wined3d: Reverse semantics maps for shaders.
diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index e4d7e4d..a8f92fc 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -340,18 +340,9 @@
     break;
   case D3DSPR_INPUT:
 
-    if (This->semantics_in[WINED3DSHADERDECLUSAGE_DIFFUSE] &&
-        reg == (This->semantics_in[WINED3DSHADERDECLUSAGE_DIFFUSE] & D3DSP_REGNUM_MASK))
+    if (vshader_input_is_color((IWineD3DVertexShader*) This, reg))
         is_color = TRUE;
 
-    if (This->semantics_in[WINED3DSHADERDECLUSAGE_SPECULAR] &&
-        reg == (This->semantics_in[WINED3DSHADERDECLUSAGE_SPECULAR] & D3DSP_REGNUM_MASK))
-        is_color = TRUE;
-
-    /* FIXME: Shaders in 8.1 appear to not require a dcl statement - use
-     * the reg value from the vertex declaration. However, semantics are not initialized
-     * in that case - how can we know if an input contains color data or not? */
-
     sprintf(tmpReg, "vertex.attrib[%lu]", reg);
     strcat(hwLine, tmpReg);
     break;
diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index 8ed85ef..b7aa45f 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -171,132 +171,14 @@
      }
 }
 
-static void shader_parse_decl_usage(
-    DWORD *semantics_map,
-    DWORD usage_token, DWORD param) {
-
-    unsigned int usage = (usage_token & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
-    unsigned int usage_idx = (usage_token & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
-    unsigned int regnum = param & D3DSP_REGNUM_MASK;
-
-    switch(usage) {
-        case D3DDECLUSAGE_POSITION:
-            if (usage_idx == 0) { /* tween data */
-                TRACE("Setting position to %d\n", regnum);
-                semantics_map[WINED3DSHADERDECLUSAGE_POSITION] = param;
-            } else {
-                /* TODO: position indexes go from 0-8!!*/
-                TRACE("Setting position 2 to %d because usage_idx = %d\n", regnum, usage_idx);
-                /* robots uses positions up to 8, the position arrays are just packed.*/
-                if (usage_idx > 1) {
-                    TRACE("Loaded for position %d (greater than 2)\n", usage_idx);
-                }
-                semantics_map[WINED3DSHADERDECLUSAGE_POSITION2 + usage_idx-1] = param;
-            }
-            break;
-
-        case D3DDECLUSAGE_BLENDINDICES:
-            TRACE("Setting BLENDINDICES to %d\n", regnum);
-            semantics_map[WINED3DSHADERDECLUSAGE_BLENDINDICES] = param;
-            if (usage_idx != 0) FIXME("Extended BLENDINDICES\n");
-            break;
-
-        case D3DDECLUSAGE_BLENDWEIGHT:
-            TRACE("Setting BLENDWEIGHT to %d\n", regnum);
-            semantics_map[WINED3DSHADERDECLUSAGE_BLENDWEIGHT] = param;
-            if (usage_idx != 0) FIXME("Extended blend weights\n");
-            break;
-
-        case D3DDECLUSAGE_NORMAL:
-            if (usage_idx == 0) { /* tween data */
-                TRACE("Setting normal to %d\n", regnum);
-                semantics_map[WINED3DSHADERDECLUSAGE_NORMAL] = param;
-            } else {
-                TRACE("Setting normal 2 to %d because usage = %d\n", regnum, usage_idx);
-                semantics_map[WINED3DSHADERDECLUSAGE_NORMAL2] = param;
-            }
-            break;
-
-        case D3DDECLUSAGE_PSIZE:
-            TRACE("Setting PSIZE to %d\n", regnum);
-            semantics_map[WINED3DSHADERDECLUSAGE_PSIZE] = param;
-            if (usage_idx != 0) FIXME("Extended PSIZE\n");
-            break;
-
-        case D3DDECLUSAGE_COLOR:
-            if (usage_idx == 0)  {
-                TRACE("Setting DIFFUSE to %d\n", regnum);
-                semantics_map[WINED3DSHADERDECLUSAGE_DIFFUSE] = param;
-            } else {
-                TRACE("Setting SPECULAR to %d\n", regnum);
-                semantics_map[WINED3DSHADERDECLUSAGE_SPECULAR] = param;
-            }
-            break;
-
-        case D3DDECLUSAGE_TEXCOORD:
-            if (usage_idx > 7) {
-                FIXME("Program uses texture coordinate %d but only 0-7 have been "
-                    "implemented\n", usage_idx);
-            } else {
-                TRACE("Setting TEXCOORD %d  to %d\n", usage_idx, regnum);
-                semantics_map[WINED3DSHADERDECLUSAGE_TEXCOORD0 + usage_idx] = param;
-            }
-            break;
-
-        case D3DDECLUSAGE_TANGENT:
-            TRACE("Setting TANGENT to %d\n", regnum);
-            semantics_map[WINED3DSHADERDECLUSAGE_TANGENT] = param;
-            break;
-
-        case D3DDECLUSAGE_BINORMAL:
-            TRACE("Setting BINORMAL to %d\n", regnum);
-            semantics_map[WINED3DSHADERDECLUSAGE_BINORMAL] = param;
-            break;
-
-        case D3DDECLUSAGE_TESSFACTOR:
-            TRACE("Setting TESSFACTOR to %d\n", regnum);
-            semantics_map[WINED3DSHADERDECLUSAGE_TESSFACTOR] = param;
-            break;
-
-        case D3DDECLUSAGE_POSITIONT:
-            if (usage_idx == 0) { /* tween data */
-                FIXME("Setting positiont to %d\n", regnum);
-                semantics_map[WINED3DSHADERDECLUSAGE_POSITIONT] = param;
-            } else {
-                FIXME("Setting positiont 2 to %d because usage = %d\n", regnum, usage_idx);
-                semantics_map[WINED3DSHADERDECLUSAGE_POSITIONT2] = param;
-                if (usage_idx != 0) FIXME("Extended positiont\n");
-            }
-            break;
-
-        case D3DDECLUSAGE_FOG:
-            TRACE("Setting FOG to %d\n", regnum);
-            semantics_map[WINED3DSHADERDECLUSAGE_FOG] = param;
-            break;
-
-        case D3DDECLUSAGE_DEPTH:
-            TRACE("Setting DEPTH to %d\n", regnum);
-            semantics_map[WINED3DSHADERDECLUSAGE_DEPTH] = param;
-            break;
-
-        case D3DDECLUSAGE_SAMPLE:
-            TRACE("Setting SAMPLE to %d\n", regnum);
-            semantics_map[WINED3DSHADERDECLUSAGE_SAMPLE] = param;
-            break;
-
-        default:
-            FIXME("Unrecognised dcl %#x", usage);
-    }
-}
-
 /* Note that this does not count the loop register
  * as an address register. */
 
 void shader_get_registers_used(
     IWineD3DBaseShader *iface,
     shader_reg_maps* reg_maps,
-    DWORD* semantics_in,
-    DWORD* semantics_out,
+    semantic* semantics_in,
+    semantic* semantics_out,
     CONST DWORD* pToken) {
 
     IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
@@ -350,12 +232,14 @@
                 else
                     reg_maps->packed_input[regnum] = 1;
 
-                shader_parse_decl_usage(semantics_in, usage, param);
+                semantics_in[regnum].usage = usage;
+                semantics_in[regnum].reg = param;
 
             /* Vshader: mark 3.0 output registers used, save token */
             } else if (D3DSPR_OUTPUT == regtype) {
                 reg_maps->packed_output[regnum] = 1;
-                shader_parse_decl_usage(semantics_out, usage, param);
+                semantics_out[regnum].usage = usage;
+                semantics_out[regnum].reg = param;
 
             /* Save sampler usage token */
             } else if (D3DSPR_SAMPLER == regtype)
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 67efd03..25e2c1e 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -464,7 +464,12 @@
             checkGLcall("glEnableVertexAttribArrayARB");
         }
 
-        stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
+        if (useVertexShaderFunction)
+            stride_used = vshader_get_input(This->stateBlock->vertexShader,
+                element->Usage, element->UsageIndex, &idx);
+        else
+            stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
+
         if (stride_used) {
            TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
                  "stream=%u, offset=%u, stride=%lu, VBO=%u]\n",
@@ -476,10 +481,12 @@
            strided->u.input[idx].dwType = element->Type;
            strided->u.input[idx].dwStride = stride;
            strided->u.input[idx].VBO = streamVBO;
-           if (element->Usage == D3DDECLUSAGE_POSITION)
-               strided->u.s.position_transformed = FALSE;
-           else if (element->Usage == D3DDECLUSAGE_POSITIONT)
-               strided->u.s.position_transformed = TRUE;
+           if (!useVertexShaderFunction) {
+               if (element->Usage == D3DDECLUSAGE_POSITION)
+                   strided->u.s.position_transformed = FALSE;
+               else if (element->Usage == D3DDECLUSAGE_POSITIONT)
+                   strided->u.s.position_transformed = TRUE;
+           }
         }
     };
 }
@@ -794,105 +801,35 @@
 }
 #endif /* TODO: Software shaders */
 
-void loadNumberedArrays(
-    IWineD3DDevice *iface, 
-    WineDirect3DVertexStridedData *sd, 
-    DWORD arrayUsageMap[WINED3DSHADERDECLUSAGE_MAX_USAGE]) {
+static void loadNumberedArrays(
+    IWineD3DDevice *iface,
+    IWineD3DVertexShader *shader,
+    WineDirect3DVertexStridedData *strided) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
     GLint curVBO = -1;
+    int i;
 
-#define LOAD_NUMBERED_ARRAY(_arrayName, _lookupName) \
-    if ((sd->u.s._arrayName.lpData != NULL || sd->u.s._arrayName.VBO != 0) && arrayUsageMap[WINED3DSHADERDECLUSAGE_##_lookupName]) { \
-        unsigned int idx = arrayUsageMap[WINED3DSHADERDECLUSAGE_##_lookupName] & D3DSP_REGNUM_MASK; \
-        TRACE_(d3d_shader)("Loading array %u with data from %s\n", idx,  #_arrayName); \
-        if(curVBO != sd->u.s._arrayName.VBO) { \
-            GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s._arrayName.VBO)); \
-            checkGLcall("glBindBufferARB"); \
-            curVBO = sd->u.s._arrayName.VBO; \
-        } \
-        GL_EXTCALL(glVertexAttribPointerARB(idx, \
-                        WINED3D_ATR_SIZE(sd->u.s._arrayName.dwType), \
-                        WINED3D_ATR_GLTYPE(sd->u.s._arrayName.dwType), \
-                        WINED3D_ATR_NORMALIZED(sd->u.s._arrayName.dwType), \
-                        sd->u.s._arrayName.dwStride, \
-                        sd->u.s._arrayName.lpData)); \
-        GL_EXTCALL(glEnableVertexAttribArrayARB(idx)); \
-    }
+    for (i = 0; i < MAX_ATTRIBS; i++) {
 
+        if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
+            continue;
 
-#define LOAD_NUMBERED_POSITION_ARRAY(_lookupNumber) \
-    if ((sd->u.s.position2.lpData != NULL  || sd->u.s.position2.VBO != 0)&& arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITION2 + _lookupNumber]) { \
-        unsigned int idx = arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITION2 + _lookupNumber] & D3DSP_REGNUM_MASK; \
-        TRACE_(d3d_shader)("Loading array %u with data from %s\n", idx, "position2"); \
-        if(curVBO != sd->u.s.position2.VBO) { \
-            GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.position2.VBO)); \
-            checkGLcall("glBindBufferARB"); \
-            curVBO = sd->u.s.position2.VBO; \
-        } \
-        GL_EXTCALL(glVertexAttribPointerARB(idx, \
-                        WINED3D_ATR_SIZE(sd->u.s.position2.dwType), \
-                        WINED3D_ATR_GLTYPE(sd->u.s.position2.dwType), \
-                        WINED3D_ATR_NORMALIZED(sd->u.s.position2.dwType), \
-                        sd->u.s.position2.dwStride, \
-                        ((char *)sd->u.s.position2.lpData) + \
-                           WINED3D_ATR_SIZE(sd->u.s.position2.dwType) * \
-                           WINED3D_ATR_TYPESIZE(sd->u.s.position2.dwType) * _lookupNumber)); \
-        GL_EXTCALL(glEnableVertexAttribArrayARB(idx)); \
-    }
+        TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
 
-/* Generate some lookup tables */
-    /* drop the RHW coord, there must be a nicer way of doing this. */
-    sd->u.s.position.dwType  = min(D3DDECLTYPE_FLOAT3, sd->u.s.position.dwType);
-    sd->u.s.position2.dwType = min(D3DDECLTYPE_FLOAT3, sd->u.s.position2.dwType);
-
-    LOAD_NUMBERED_ARRAY(blendWeights,BLENDWEIGHT);
-    LOAD_NUMBERED_ARRAY(blendMatrixIndices,BLENDINDICES);
-    LOAD_NUMBERED_ARRAY(position,POSITION);
-    LOAD_NUMBERED_ARRAY(normal,NORMAL);
-    LOAD_NUMBERED_ARRAY(pSize,PSIZE);
-    LOAD_NUMBERED_ARRAY(diffuse,DIFFUSE);
-    LOAD_NUMBERED_ARRAY(specular,SPECULAR);
-    LOAD_NUMBERED_ARRAY(texCoords[0],TEXCOORD0);
-    LOAD_NUMBERED_ARRAY(texCoords[1],TEXCOORD1);
-    LOAD_NUMBERED_ARRAY(texCoords[2],TEXCOORD2);
-    LOAD_NUMBERED_ARRAY(texCoords[3],TEXCOORD3);
-    LOAD_NUMBERED_ARRAY(texCoords[4],TEXCOORD4);
-    LOAD_NUMBERED_ARRAY(texCoords[5],TEXCOORD5);
-    LOAD_NUMBERED_ARRAY(texCoords[6],TEXCOORD6);
-    LOAD_NUMBERED_ARRAY(texCoords[7],TEXCOORD7);
-#if 0   /* TODO: Samplers may allow for more texture coords */
-    LOAD_NUMBERED_ARRAY(texCoords[8],TEXCOORD8);
-    LOAD_NUMBERED_ARRAY(texCoords[9],TEXCOORD9);
-    LOAD_NUMBERED_ARRAY(texCoords[10],TEXCOORD10);
-    LOAD_NUMBERED_ARRAY(texCoords[11],TEXCOORD11);
-    LOAD_NUMBERED_ARRAY(texCoords[12],TEXCOORD12);
-    LOAD_NUMBERED_ARRAY(texCoords[13],TEXCOORD13);
-    LOAD_NUMBERED_ARRAY(texCoords[14],TEXCOORD14);
-    LOAD_NUMBERED_ARRAY(texCoords[15],TEXCOORD15);
-#endif
-    LOAD_NUMBERED_ARRAY(position,POSITIONT);
-    /* d3d9 types */
-    LOAD_NUMBERED_ARRAY(tangent,TANGENT);
-    LOAD_NUMBERED_ARRAY(binormal,BINORMAL);
-    LOAD_NUMBERED_ARRAY(tessFactor,TESSFACTOR);
-    LOAD_NUMBERED_ARRAY(position2,POSITION2);
-    /* there can be lots of position arrays */
-    LOAD_NUMBERED_POSITION_ARRAY(0);
-    LOAD_NUMBERED_POSITION_ARRAY(1);
-    LOAD_NUMBERED_POSITION_ARRAY(2);
-    LOAD_NUMBERED_POSITION_ARRAY(3);
-    LOAD_NUMBERED_POSITION_ARRAY(4);
-    LOAD_NUMBERED_POSITION_ARRAY(5);
-    LOAD_NUMBERED_POSITION_ARRAY(6);
-    LOAD_NUMBERED_POSITION_ARRAY(7);
-    LOAD_NUMBERED_ARRAY(position2,POSITIONT2);
-    LOAD_NUMBERED_ARRAY(normal2,NORMAL2);
-    LOAD_NUMBERED_ARRAY(fog,FOG);
-    LOAD_NUMBERED_ARRAY(depth,DEPTH);
-    LOAD_NUMBERED_ARRAY(sample,SAMPLE);
-
-#undef LOAD_NUMBERED_ARRAY
+        if(curVBO != strided->u.input[i].VBO) {
+            GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, strided->u.input[i].VBO));
+            checkGLcall("glBindBufferARB");
+            curVBO = strided->u.input[i].VBO;
+        }
+        GL_EXTCALL(glVertexAttribPointerARB(i,
+                        WINED3D_ATR_SIZE(strided->u.input[i].dwType),
+                        WINED3D_ATR_GLTYPE(strided->u.input[i].dwType),
+                        WINED3D_ATR_NORMALIZED(strided->u.input[i].dwType),
+                        strided->u.input[i].dwStride,
+                        strided->u.input[i].lpData));
+        GL_EXTCALL(glEnableVertexAttribArrayARB(i));
+   }
 }
 
 static void loadVertexData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd) {
@@ -1803,8 +1740,7 @@
     /* Shader pipeline - load attribute arrays */
     } else if(useVertexShaderFunction) {
 
-        loadNumberedArrays(iface, dataLocations, 
-            ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->semantics_in);
+        loadNumberedArrays(iface, This->stateBlock->vertexShader, dataLocations);
         useDrawStridedSlow = FALSE;
 
     /* Draw vertex by vertex */
@@ -2147,11 +2083,21 @@
     ENTER_GL();
 
     if(DrawPrimStrideData) {
+
+        /* Note: this is a ddraw fixed-function code path */
+
         TRACE("================ Strided Input ===================\n");
         dataLocations = DrawPrimStrideData;
+        drawPrimitiveTraceDataLocations(dataLocations);
         fixup = FALSE;
     }
-    else if (This->stateBlock->vertexDecl != NULL || (useVertexShaderFunction  && NULL != ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration)) {
+
+    else if (This->stateBlock->vertexDecl != NULL || useVertexShaderFunction) {
+
+        /* Note: This is a fixed function or shader codepath.
+         * This means it must handle both types of strided data.
+         * Shaders must go through here to zero the strided data, even if they
+         * don't set any declaration at all */
 
         TRACE("================ Vertex Declaration  ===================\n");
         dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
@@ -2159,9 +2105,19 @@
             ERR("Out of memory!\n");
             return;
         }
-        primitiveDeclarationConvertToStridedData(iface, useVertexShaderFunction, dataLocations, StartVertexIndex, &fixup);
+
+        if (This->stateBlock->vertexDecl != NULL ||
+            ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration != NULL)            
+
+            primitiveDeclarationConvertToStridedData(iface, useVertexShaderFunction, 
+                dataLocations, StartVertexIndex, &fixup);
 
     } else {
+
+        /* Note: This codepath is not reachable from d3d9 (see fvf->decl9 conversion)
+         * It is reachable through d3d8, but only for fixed-function.
+         * It will not work properly for shaders. */
+
         TRACE("================ FVF ===================\n");
         dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
         if(!dataLocations) {
@@ -2169,11 +2125,9 @@
             return;
         }
         primitiveConvertToStridedData(iface, dataLocations, StartVertexIndex, &fixup);
+        drawPrimitiveTraceDataLocations(dataLocations);
     }
 
-    /* write out some debug information*/
-    drawPrimitiveTraceDataLocations(dataLocations);
-
     /* Setup transform matrices and sort out */
     primitiveInitState(iface, dataLocations, useVertexShaderFunction, &lighting_changed, &lighting_original);
 
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index e7ba349..215090c 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -501,20 +501,8 @@
                     strcpy(tmpStr, "gl_SecondaryColor");
             }
         } else {
-            IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl*) arg->shader;
-
-            if (This->semantics_in[WINED3DSHADERDECLUSAGE_DIFFUSE] &&
-                reg == (This->semantics_in[WINED3DSHADERDECLUSAGE_DIFFUSE] & D3DSP_REGNUM_MASK))
-                *is_color = TRUE;
-
-            if (This->semantics_in[WINED3DSHADERDECLUSAGE_SPECULAR] &&
-                reg == (This->semantics_in[WINED3DSHADERDECLUSAGE_SPECULAR] & D3DSP_REGNUM_MASK))
-                *is_color = TRUE;
-
-            /* FIXME: Shaders in 8.1 appear to not require a dcl statement - use
-             * the reg value from the vertex declaration. However, semantics are not initialized
-              * in that case - how can we know if an input contains color data or not? */
-
+            if (vshader_input_is_color((IWineD3DVertexShader*) This, reg))
+               *is_color = TRUE;
             sprintf(tmpStr, "attrib%lu", reg);
         } 
         break;
@@ -1390,53 +1378,50 @@
 
 void pshader_glsl_input_pack(
    SHADER_BUFFER* buffer,
-   DWORD* semantics_in) {
+   semantic* semantics_in) {
 
    unsigned int i;
 
-   for (i = 0; i < WINED3DSHADERDECLUSAGE_MAX_USAGE; i++) {
+   for (i = 0; i < MAX_REG_INPUT; i++) {
 
-       DWORD reg = semantics_in[i];
-       unsigned int regnum = reg & D3DSP_REGNUM_MASK;
+       DWORD usage_token = semantics_in[i].usage;
+       DWORD register_token = semantics_in[i].reg;
+       DWORD usage, usage_idx;
        char reg_mask[6];
 
        /* Uninitialized */
-       if (!reg) continue;
+       if (!usage_token) continue;
+       usage = (usage_token & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
+       usage_idx = (usage_token & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
+       shader_glsl_get_output_register_swizzle(register_token, reg_mask);
 
-       shader_glsl_get_output_register_swizzle(reg, reg_mask);
+       switch(usage) {
 
-       switch(i) {
-
-           case WINED3DSHADERDECLUSAGE_DIFFUSE:
-               shader_addline(buffer, "IN%lu%s = vec4(gl_Color)%s;\n",
-                   regnum, reg_mask, reg_mask);
+           case D3DDECLUSAGE_COLOR:
+               if (usage_idx == 0)
+                   shader_addline(buffer, "IN%lu%s = vec4(gl_Color)%s;\n",
+                       i, reg_mask, reg_mask);
+               if (usage_idx == 1)
+                   shader_addline(buffer, "IN%lu%s = vec4(gl_SecondaryColor)%s;\n",
+                       i, reg_mask, reg_mask);
+               else
+                   shader_addline(buffer, "IN%lu%s = vec4(unsupported_color_input)%s;\n",
+                       i, reg_mask, reg_mask);
                break;
 
-           case WINED3DSHADERDECLUSAGE_SPECULAR:
-               shader_addline(buffer, "IN%lu%s = vec4(gl_SecondaryColor)%s;\n",
-                   regnum, reg_mask, reg_mask);
-               break;
-
-           case WINED3DSHADERDECLUSAGE_TEXCOORD0:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD1:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD2:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD3:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD4:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD5:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD6:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD7:
+           case D3DDECLUSAGE_TEXCOORD:
                shader_addline(buffer, "IN%lu%s = vec4(gl_TexCoord[%lu])%s;\n",
-                   regnum, reg_mask, i - WINED3DSHADERDECLUSAGE_TEXCOORD0, reg_mask );
+                   i, reg_mask, usage_idx, reg_mask );
                break;
 
-           case WINED3DSHADERDECLUSAGE_FOG:
+           case D3DDECLUSAGE_FOG:
                shader_addline(buffer, "IN%lu%s = vec4(gl_FogFragCoord)%s;\n",
-                   regnum, reg_mask, reg_mask);
+                   i, reg_mask, reg_mask);
                break;
 
            default:
                shader_addline(buffer, "IN%lu%s = vec4(unsupported_input)%s;\n",
-                   regnum, reg_mask, reg_mask);
+                   i, reg_mask, reg_mask);
         }
     }
 }
@@ -1447,57 +1432,54 @@
 
 void vshader_glsl_output_unpack(
    SHADER_BUFFER* buffer,
-   DWORD* semantics_out) {
+   semantic* semantics_out) {
 
    unsigned int i;
 
-   for (i = 0; i < WINED3DSHADERDECLUSAGE_MAX_USAGE; i++) {
+   for (i = 0; i < MAX_REG_OUTPUT; i++) {
 
-       DWORD reg = semantics_out[i];
-       unsigned int regnum = reg & D3DSP_REGNUM_MASK;
+       DWORD usage_token = semantics_out[i].usage;
+       DWORD register_token = semantics_out[i].reg;
+       DWORD usage, usage_idx;
        char reg_mask[6];
 
        /* Uninitialized */
-       if (!reg) continue;
+       if (!usage_token) continue;
 
-       shader_glsl_get_output_register_swizzle(reg, reg_mask);
+       usage = (usage_token & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
+       usage_idx = (usage_token & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
+       shader_glsl_get_output_register_swizzle(register_token, reg_mask);
 
-       switch(i) {
+       switch(usage) {
 
-           case WINED3DSHADERDECLUSAGE_DIFFUSE:
-               shader_addline(buffer, "gl_FrontColor%s = OUT%lu%s;\n", reg_mask, regnum, reg_mask);
+           case D3DDECLUSAGE_COLOR:
+               if (usage_idx == 0)
+                   shader_addline(buffer, "gl_FrontColor%s = OUT%lu%s;\n", reg_mask, i, reg_mask);
+               else if (usage_idx == 1)
+                   shader_addline(buffer, "gl_FrontSecondaryColor%s = OUT%lu%s;\n", reg_mask, i, reg_mask);
+               else
+                   shader_addline(buffer, "unsupported_color_output%s = OUT%lu%s;\n", reg_mask, i, reg_mask);
                break;
 
-           case WINED3DSHADERDECLUSAGE_SPECULAR:
-               shader_addline(buffer, "gl_FrontSecondaryColor%s = OUT%lu%s;\n", reg_mask, regnum, reg_mask);
+           case D3DDECLUSAGE_POSITION:
+               shader_addline(buffer, "gl_Position%s = OUT%lu%s;\n", reg_mask, i, reg_mask);
                break;
-
-           case WINED3DSHADERDECLUSAGE_POSITION:
-               shader_addline(buffer, "gl_Position%s = OUT%lu%s;\n", reg_mask, regnum, reg_mask);
-               break;
-
-           case WINED3DSHADERDECLUSAGE_TEXCOORD0:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD1:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD2:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD3:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD4:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD5:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD6:
-           case WINED3DSHADERDECLUSAGE_TEXCOORD7:
+ 
+           case D3DDECLUSAGE_TEXCOORD:
                shader_addline(buffer, "gl_TexCoord[%lu]%s = OUT%lu%s;\n",
-                   i - WINED3DSHADERDECLUSAGE_TEXCOORD0, reg_mask, regnum, reg_mask);
+                   usage_idx, reg_mask, i, reg_mask);
                break;
 
            case WINED3DSHADERDECLUSAGE_PSIZE:
-               shader_addline(buffer, "gl_PointSize = OUT%lu.x;\n", regnum);
+               shader_addline(buffer, "gl_PointSize = OUT%lu.x;\n", i);
                break;
 
            case WINED3DSHADERDECLUSAGE_FOG:
-               shader_addline(buffer, "gl_FogFragCoord%s = OUT%lu%s;\n", reg_mask, regnum, reg_mask);
+               shader_addline(buffer, "gl_FogFragCoord%s = OUT%lu%s;\n", reg_mask, i, reg_mask);
                break;
 
            default:
-               shader_addline(buffer, "unsupported_output%s = OUT%lu%s;\n", reg_mask, regnum, reg_mask);
-      }
-   }
+               shader_addline(buffer, "unsupported_output%s = OUT%lu%s;\n", reg_mask, i, reg_mask);
+       }
+    }
 }
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index df0fd99..7d452d2 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -609,6 +609,37 @@
       }
 }
 
+BOOL vshader_get_input(
+    IWineD3DVertexShader* iface,
+    BYTE usage_req, BYTE usage_idx_req,
+    unsigned int* regnum) {
+
+    IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) iface;
+    int i;
+
+    for (i = 0; i < MAX_ATTRIBS; i++) {
+        DWORD usage_token = This->semantics_in[i].usage;
+        DWORD usage = (usage_token & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
+        DWORD usage_idx = (usage_token & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
+
+        if (usage_token && (usage == usage_req && usage_idx == usage_idx_req)) {
+            *regnum = i;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+BOOL vshader_input_is_color(
+    IWineD3DVertexShader* iface,
+    unsigned int regnum) {
+
+    IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) iface;
+    DWORD usage_token = This->semantics_in[regnum].usage;
+    DWORD usage = (usage_token & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
+    return usage == D3DDECLUSAGE_COLOR;
+}
+
 /** Generate a vertex shader string using either GL_VERTEX_PROGRAM_ARB
     or GLSL and send it to the card */
 static VOID IWineD3DVertexShaderImpl_GenerateShader(
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b8a7c03..0f6d85e 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1283,6 +1283,11 @@
 #define MAX_CONST_I 16
 #define MAX_CONST_B 16
 
+typedef struct semantic {
+    DWORD usage;
+    DWORD reg;
+} semantic;
+
 typedef struct shader_reg_maps {
 
     char texcoord[MAX_REG_TEXCRD];          /* pixel < 3.0 */
@@ -1367,6 +1372,16 @@
     IWineD3DBaseShader *iface, 
     const DWORD code);
 
+/* Vertex shader utility functions */
+extern BOOL vshader_get_input(
+    IWineD3DVertexShader* iface,
+    BYTE usage_req, BYTE usage_idx_req,
+    unsigned int* regnum);
+
+extern BOOL vshader_input_is_color(
+    IWineD3DVertexShader* iface,
+    unsigned int regnum);
+
 /* ARB_[vertex/fragment]_program helper functions */
 extern void shader_arb_load_constants(
     IWineD3DStateBlock* iface,
@@ -1437,12 +1452,12 @@
 extern void pshader_glsl_dp2add(SHADER_OPCODE_ARG* arg);
 extern void pshader_glsl_input_pack(
    SHADER_BUFFER* buffer,
-   DWORD* semantics_out);
+   semantic* semantics_out);
 
 /** GLSL Vertex Shader Prototypes */
 extern void vshader_glsl_output_unpack(
    SHADER_BUFFER* buffer,
-   DWORD* semantics_out);
+   semantic* semantics_out);
 
 /*****************************************************************************
  * IDirect3DBaseShader implementation structure
@@ -1474,8 +1489,8 @@
 extern void shader_get_registers_used(
     IWineD3DBaseShader *iface,
     shader_reg_maps* reg_maps,
-    DWORD* semantics_in,
-    DWORD* semantics_out,
+    semantic* semantics_in,
+    semantic* semantics_out,
     CONST DWORD* pToken);
 
 extern void shader_generate_glsl_declarations(
@@ -1558,8 +1573,8 @@
     DWORD usage;
 
     /* Vertex shader input and output semantics */
-    DWORD semantics_in [WINED3DSHADERDECLUSAGE_MAX_USAGE];
-    DWORD semantics_out [WINED3DSHADERDECLUSAGE_MAX_USAGE];
+    semantic semantics_in [MAX_ATTRIBS];
+    semantic semantics_out [MAX_REG_OUTPUT];
 
     /* run time datas...  */
     VSHADERDATA                *data;
@@ -1589,7 +1604,7 @@
     IWineD3DDeviceImpl         *wineD3DDevice;
 
     /* Pixel shader input semantics */
-    DWORD semantics_in [WINED3DSHADERDECLUSAGE_MAX_USAGE];
+    semantic semantics_in [MAX_REG_INPUT];
 
     /* run time data */
     PSHADERDATA                *data;