From 2d904495003f65a9fefb96eacf828617f3bb9c30 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Wed, 19 Dec 2007 17:10:02 +0100
Subject: [PATCH] wined3d: Fixed function vertex attribute types are flexible.

---
 dlls/d3d9/tests/visual.c       | 241 +++++++++++++++++++++++++++++++++
 dlls/wined3d/directx.c         | 140 ++++++++++++++++++-
 dlls/wined3d/drawprim.c        |  85 +++++-------
 dlls/wined3d/state.c           |   7 +-
 dlls/wined3d/wined3d_private.h |   7 +
 5 files changed, 425 insertions(+), 55 deletions(-)

diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index 764b5faf030..dd38d553b36 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -5437,6 +5437,246 @@ static void alpha_test(IDirect3DDevice9 *device)
     }
 }
 
+struct vertex_shortcolor {
+    float x, y, z;
+    unsigned short r, g, b, a;
+};
+struct vertex_floatcolor {
+    float x, y, z;
+    float r, g, b, a;
+};
+
+static void fixed_function_decl_test(IDirect3DDevice9 *device)
+{
+    HRESULT hr;
+    DWORD color;
+    void *data;
+    static const D3DVERTEXELEMENT9 decl_elements_d3dcolor[] = {
+        {0,   0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,       0},
+        {0,  12,  D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,          0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 decl_elements_ubyte4n[] = {
+        {0,   0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,       0},
+        {0,  12,  D3DDECLTYPE_UBYTE4N,  D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,          0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 decl_elements_short4[] = {
+        {0,   0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,       0},
+        {0,  12,  D3DDECLTYPE_USHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,          0},
+        D3DDECL_END()
+    };
+    static const D3DVERTEXELEMENT9 decl_elements_float[] = {
+        {0,   0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,       0},
+        {0,  12,  D3DDECLTYPE_FLOAT4,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,          0},
+        D3DDECL_END()
+    };
+    IDirect3DVertexDeclaration9 *dcl_float = NULL, *dcl_short = NULL, *dcl_ubyte = NULL, *dcl_color = NULL;
+    IDirect3DVertexBuffer9 *vb;
+    struct vertex quad1[] =                             /* D3DCOLOR */
+    {
+        {-1.0f, -1.0f,   0.1f,                          0x00ffff00},
+        {-1.0f,  0.0f,   0.1f,                          0x00ffff00},
+        { 0.0f, -1.0f,   0.1f,                          0x00ffff00},
+        { 0.0f,  0.0f,   0.1f,                          0x00ffff00},
+    };
+    struct vertex quad2[] =                             /* UBYTE4N */
+    {
+        {-1.0f,  0.0f,   0.1f,                          0x00ffff00},
+        {-1.0f,  1.0f,   0.1f,                          0x00ffff00},
+        { 0.0f,  0.0f,   0.1f,                          0x00ffff00},
+        { 0.0f,  1.0f,   0.1f,                          0x00ffff00},
+    };
+    struct vertex_shortcolor quad3[] =                  /* short */
+    {
+        { 0.0f, -1.0f,   0.1f,                          0x0000, 0x0000, 0xffff, 0xffff},
+        { 0.0f,  0.0f,   0.1f,                          0x0000, 0x0000, 0xffff, 0xffff},
+        { 1.0f, -1.0f,   0.1f,                          0x0000, 0x0000, 0xffff, 0xffff},
+        { 1.0f,  0.0f,   0.1f,                          0x0000, 0x0000, 0xffff, 0xffff},
+    };
+    struct vertex_floatcolor quad4[] =
+    {
+        { 0.0f,  0.0f,   0.1f,                          1.0, 0.0, 0.0, 0.0},
+        { 0.0f,  1.0f,   0.1f,                          1.0, 0.0, 0.0, 0.0},
+        { 1.0f,  0.0f,   0.1f,                          1.0, 0.0, 0.0, 0.0},
+        { 1.0f,  1.0f,   0.1f,                          1.0, 0.0, 0.0, 0.0},
+    };
+
+    hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xffffffff, 0.0, 0);
+    ok(hr == D3D_OK, "Clear failed, hr = %08x\n", hr);
+
+    hr = IDirect3DDevice9_CreateVertexDeclaration(device, decl_elements_d3dcolor, &dcl_color);
+    ok(SUCCEEDED(hr), "CreateVertexDeclaration failed (%08x)\n", hr);
+    hr = IDirect3DDevice9_CreateVertexDeclaration(device, decl_elements_ubyte4n, &dcl_ubyte);
+    ok(SUCCEEDED(hr), "CreateVertexDeclaration failed (%08x)\n", hr);
+    hr = IDirect3DDevice9_CreateVertexDeclaration(device, decl_elements_short4, &dcl_short);
+    ok(SUCCEEDED(hr) || hr == E_FAIL, "CreateVertexDeclaration failed (%08x)\n", hr);
+    hr = IDirect3DDevice9_CreateVertexDeclaration(device, decl_elements_float, &dcl_float);
+    ok(SUCCEEDED(hr), "CreateVertexDeclaration failed (%08x)\n", hr);
+
+    hr = IDirect3DDevice9_CreateVertexBuffer(device, max(sizeof(quad1), max(sizeof(quad2), max(sizeof(quad3), sizeof(quad4)))),
+                                             0, 0, D3DPOOL_MANAGED, &vb, NULL);
+    ok(hr == D3D_OK, "CreateVertexBuffer failed with %s\n", DXGetErrorString9(hr));
+
+    hr = IDirect3DDevice9_BeginScene(device);
+    ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene failed (%08x)\n", hr);
+    if(SUCCEEDED(hr)) {
+        if(dcl_color) {
+            hr = IDirect3DDevice9_SetVertexDeclaration(device, dcl_color);
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexDeclaration failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad1, sizeof(quad1[0]));
+            ok(hr == D3D_OK, "DrawPrimitiveUP failed, hr = %#08x\n", hr);
+        }
+
+        if(dcl_ubyte) {
+            hr = IDirect3DDevice9_SetVertexDeclaration(device, dcl_ubyte);
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexDeclaration failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad2, sizeof(quad2[0]));
+            ok(hr == D3D_OK, "DrawPrimitiveUP failed, hr = %#08x\n", hr);
+        }
+
+        if(dcl_short) {
+            hr = IDirect3DDevice9_SetVertexDeclaration(device, dcl_short);
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexDeclaration failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad3, sizeof(quad3[0]));
+            ok(hr == D3D_OK, "DrawPrimitiveUP failed, hr = %#08x\n", hr);
+        }
+
+        if(dcl_float) {
+            hr = IDirect3DDevice9_SetVertexDeclaration(device, dcl_float);
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexDeclaration failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad4, sizeof(quad4[0]));
+            ok(hr == D3D_OK, "DrawPrimitiveUP failed, hr = %#08x\n", hr);
+        }
+
+        hr = IDirect3DDevice9_EndScene(device);
+        ok(hr == D3D_OK, "IDirect3DDevice9_EndScene failed, hr = %#08x\n", hr);
+    }
+
+    IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+    if(dcl_short) {
+        color = getPixelColor(device, 480, 360);
+        ok(color == 0x000000ff,
+           "D3DDECLTYPE_USHORT4N returned color %08x, expected 0x000000ff\n", color);
+    }
+    if(dcl_ubyte) {
+        color = getPixelColor(device, 160, 120);
+        ok(color == 0x0000ffff,
+           "D3DDECLTYPE_UBYTE4N returned color %08x, expected 0x0000ffff\n", color);
+    }
+    if(dcl_color) {
+        color = getPixelColor(device, 160, 360);
+        ok(color == 0x00ffff00,
+           "D3DDECLTYPE_D3DCOLOR returned color %08x, expected 0x00ffff00\n", color);
+    }
+    if(dcl_float) {
+        color = getPixelColor(device, 480, 120);
+        ok(color == 0x00ff0000,
+           "D3DDECLTYPE_FLOAT4 returned color %08x, expected 0x00ff0000\n", color);
+    }
+
+    /* The following test with vertex buffers doesn't serve to find out new information from windows.
+     * It is a plain regression test because wined3d uses different codepaths for attribute conversion
+     * with vertex buffers. It makes sure that the vertex buffer one works, while the above tests
+     * wether the immediate mode code works
+     */
+    hr = IDirect3DDevice9_BeginScene(device);
+    ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene failed (%08x)\n", hr);
+    if(SUCCEEDED(hr)) {
+        if(dcl_color) {
+            hr = IDirect3DVertexBuffer9_Lock(vb, 0, sizeof(quad1), (void **) &data, 0);
+            ok(hr == D3D_OK, "IDirect3DVertexBuffer9_Lock failed with %s\n", DXGetErrorString9(hr));
+            memcpy(data, quad1, sizeof(quad1));
+            hr = IDirect3DVertexBuffer9_Unlock(vb);
+            ok(hr == D3D_OK, "IDirect3DVertexBuffer9_Unlock failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_SetVertexDeclaration(device, dcl_color);
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexDeclaration failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_SetStreamSource(device, 0, vb, 0, sizeof(quad1[0]));
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetStreamSource failed with %s\n", DXGetErrorString9(hr));
+            hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, 2);
+            ok(hr == D3D_OK, "IDirect3DDevice9_DrawPrimitive failed, hr = %#08x\n", hr);
+        }
+
+        if(dcl_ubyte) {
+            hr = IDirect3DVertexBuffer9_Lock(vb, 0, sizeof(quad2), (void **) &data, 0);
+            ok(hr == D3D_OK, "IDirect3DVertexBuffer9_Lock failed with %s\n", DXGetErrorString9(hr));
+            memcpy(data, quad2, sizeof(quad2));
+            hr = IDirect3DVertexBuffer9_Unlock(vb);
+            ok(hr == D3D_OK, "IDirect3DVertexBuffer9_Unlock failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_SetVertexDeclaration(device, dcl_ubyte);
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexDeclaration failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_SetStreamSource(device, 0, vb, 0, sizeof(quad2[0]));
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetStreamSource failed with %s\n", DXGetErrorString9(hr));
+            hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, 2);
+            ok(hr == D3D_OK, "IDirect3DDevice9_DrawPrimitive failed, hr = %#08x\n", hr);
+        }
+
+        if(dcl_short) {
+            hr = IDirect3DVertexBuffer9_Lock(vb, 0, sizeof(quad3), (void **) &data, 0);
+            ok(hr == D3D_OK, "IDirect3DVertexBuffer9_Lock failed with %s\n", DXGetErrorString9(hr));
+            memcpy(data, quad3, sizeof(quad3));
+            hr = IDirect3DVertexBuffer9_Unlock(vb);
+            ok(hr == D3D_OK, "IDirect3DVertexBuffer9_Unlock failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_SetVertexDeclaration(device, dcl_short);
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexDeclaration failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_SetStreamSource(device, 0, vb, 0, sizeof(quad3[0]));
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetStreamSource failed with %s\n", DXGetErrorString9(hr));
+            hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, 2);
+            ok(hr == D3D_OK, "IDirect3DDevice9_DrawPrimitive failed, hr = %#08x\n", hr);
+        }
+
+        if(dcl_float) {
+            hr = IDirect3DVertexBuffer9_Lock(vb, 0, sizeof(quad4), (void **) &data, 0);
+            ok(hr == D3D_OK, "IDirect3DVertexBuffer9_Lock failed with %s\n", DXGetErrorString9(hr));
+            memcpy(data, quad4, sizeof(quad4));
+            hr = IDirect3DVertexBuffer9_Unlock(vb);
+            ok(hr == D3D_OK, "IDirect3DVertexBuffer9_Unlock failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_SetVertexDeclaration(device, dcl_float);
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexDeclaration failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_SetStreamSource(device, 0, vb, 0, sizeof(quad4[0]));
+            ok(hr == D3D_OK, "IDirect3DDevice9_SetStreamSource failed with %s\n", DXGetErrorString9(hr));
+            hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, 2);
+            ok(hr == D3D_OK, "IDirect3DDevice9_DrawPrimitive failed, hr = %#08x\n", hr);
+        }
+
+        hr = IDirect3DDevice9_EndScene(device);
+        ok(hr == D3D_OK, "IDirect3DDevice9_EndScene failed, hr = %#08x\n", hr);
+    }
+
+    hr = IDirect3DDevice9_SetStreamSource(device, 0, NULL, 0, 0);
+    ok(hr == D3D_OK, "IDirect3DDevice9_SetStreamSource failed with %s\n", DXGetErrorString9(hr));
+    hr = IDirect3DDevice9_SetVertexDeclaration(device, NULL);
+    ok(hr == D3D_OK, "IDirect3DDevice9_SetVertexDeclaration failed (%08x)\n", hr);
+
+    IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+    if(dcl_short) {
+        color = getPixelColor(device, 480, 360);
+        ok(color == 0x000000ff,
+           "D3DDECLTYPE_USHORT4N returned color %08x, expected 0x000000ff\n", color);
+    }
+    if(dcl_ubyte) {
+        color = getPixelColor(device, 160, 120);
+        ok(color == 0x0000ffff,
+           "D3DDECLTYPE_UBYTE4N returned color %08x, expected 0x0000ffff\n", color);
+    }
+    if(dcl_color) {
+        color = getPixelColor(device, 160, 360);
+        ok(color == 0x00ffff00,
+           "D3DDECLTYPE_D3DCOLOR returned color %08x, expected 0x00ffff00\n", color);
+    }
+    if(dcl_float) {
+        color = getPixelColor(device, 480, 120);
+        ok(color == 0x00ff0000,
+           "D3DDECLTYPE_FLOAT4 returned color %08x, expected 0x00ff0000\n", color);
+    }
+
+    IDirect3DVertexBuffer9_Release(vb);
+    if(dcl_float) IDirect3DVertexDeclaration9_Release(dcl_float);
+    if(dcl_short) IDirect3DVertexDeclaration9_Release(dcl_short);
+    if(dcl_ubyte) IDirect3DVertexDeclaration9_Release(dcl_ubyte);
+    if(dcl_color) IDirect3DVertexDeclaration9_Release(dcl_color);
+}
+
 START_TEST(visual)
 {
     IDirect3DDevice9 *device_ptr;
@@ -5517,6 +5757,7 @@ START_TEST(visual)
     g16r16_texture_test(device_ptr);
     texture_transform_flags_test(device_ptr);
     autogen_mipmap_test(device_ptr);
+    fixed_function_decl_test(device_ptr);
 
     if (caps.VertexShaderVersion >= D3DVS_VERSION(1, 1))
     {
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 7badb4c4ad3..70a21a08949 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -143,6 +143,12 @@ DWORD *stateLookup[MAX_LOOKUPS];
 
 DWORD minMipLookup[WINED3DTEXF_ANISOTROPIC + 1][WINED3DTEXF_LINEAR + 1];
 
+/* drawStridedSlow attributes */
+glAttribFunc position_funcs[WINED3DDECLTYPE_UNUSED];
+glAttribFunc diffuse_funcs[WINED3DDECLTYPE_UNUSED];
+glAttribFunc specular_funcs[WINED3DDECLTYPE_UNUSED];
+glAttribFunc normal_funcs[WINED3DDECLTYPE_UNUSED];
+glTexAttribFunc texcoord_funcs[WINED3DDECLTYPE_UNUSED];
 
 /**
  * Note: GL seems to trap if GetDeviceCaps is called before any HWND's created
@@ -2879,8 +2885,139 @@ static void fixup_extensions(WineD3D_GL_Info *gl_info) {
     }
 }
 
-#define PUSH1(att)        attribs[nAttribs++] = (att);
+void invalid_func(void *data) {
+    ERR("Invalid vertex attribute function called\n");
+    DebugBreak();
+}
+
 #define GLINFO_LOCATION (Adapters[0].gl_info)
+
+/* Helper functions for providing vertex data to opengl. The arrays are initialized based on
+ * the extension detection and are used in drawStridedSlow
+ */
+static void position_d3dcolor(void *data) {
+    DWORD pos = *((DWORD *) data);
+
+    FIXME("Add a test for fixed function position from d3dcolor type\n");
+    glVertex4s(D3DCOLOR_B_R(pos),
+               D3DCOLOR_B_G(pos),
+               D3DCOLOR_B_B(pos),
+               D3DCOLOR_B_A(pos));
+}
+static void position_float4(void *data) {
+    GLfloat *pos = (float *) data;
+    float w = 1.0 / pos[3];
+
+    glVertex4f(pos[0] * w, pos[1] * w, pos[2] * w, w);
+}
+
+static void diffuse_d3dcolor(void *data) {
+    DWORD diffuseColor = *((DWORD *) data);
+
+    glColor4ub(D3DCOLOR_B_R(diffuseColor),
+               D3DCOLOR_B_G(diffuseColor),
+               D3DCOLOR_B_B(diffuseColor),
+               D3DCOLOR_B_A(diffuseColor));
+}
+
+static void specular_d3dcolor(void *data) {
+    DWORD specularColor = *((DWORD *) data);
+
+    GL_EXTCALL(glSecondaryColor3ubEXT)(D3DCOLOR_B_R(specularColor),
+                                       D3DCOLOR_B_G(specularColor),
+                                       D3DCOLOR_B_B(specularColor));
+}
+static void warn_no_specular_func(void *data) {
+    WARN("GL_EXT_secondary_color not supported\n");
+}
+
+void fillGLAttribFuncs(WineD3D_GL_Info *gl_info) {
+    position_funcs[WINED3DDECLTYPE_FLOAT1]      = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_FLOAT2]      = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_FLOAT3]      = (void *) glVertex3fv;
+    position_funcs[WINED3DDECLTYPE_FLOAT4]      = (void *) position_float4;
+    position_funcs[WINED3DDECLTYPE_D3DCOLOR]    = (void *) position_d3dcolor;
+    position_funcs[WINED3DDECLTYPE_UBYTE4]      = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_SHORT2]      = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_SHORT4]      = (void *) glVertex2sv;
+    position_funcs[WINED3DDECLTYPE_UBYTE4N]     = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_SHORT2N]     = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_SHORT4N]     = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_USHORT2N]    = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_USHORT4N]    = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_UDEC3]       = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_DEC3N]       = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_FLOAT16_2]   = (void *) invalid_func;
+    position_funcs[WINED3DDECLTYPE_FLOAT16_4]   = (void *) invalid_func;
+
+    diffuse_funcs[WINED3DDECLTYPE_FLOAT1]       = (void *) invalid_func;
+    diffuse_funcs[WINED3DDECLTYPE_FLOAT2]       = (void *) invalid_func;
+    diffuse_funcs[WINED3DDECLTYPE_FLOAT3]       = (void *) glColor3fv;
+    diffuse_funcs[WINED3DDECLTYPE_FLOAT4]       = (void *) glColor4fv;
+    diffuse_funcs[WINED3DDECLTYPE_D3DCOLOR]     = (void *) diffuse_d3dcolor;
+    diffuse_funcs[WINED3DDECLTYPE_UBYTE4]       = (void *) invalid_func;
+    diffuse_funcs[WINED3DDECLTYPE_SHORT2]       = (void *) invalid_func;
+    diffuse_funcs[WINED3DDECLTYPE_SHORT4]       = (void *) invalid_func;
+    diffuse_funcs[WINED3DDECLTYPE_UBYTE4N]      = (void *) glColor4ubv;
+    diffuse_funcs[WINED3DDECLTYPE_SHORT2N]      = (void *) invalid_func;
+    diffuse_funcs[WINED3DDECLTYPE_SHORT4N]      = (void *) glColor4sv;
+    diffuse_funcs[WINED3DDECLTYPE_USHORT2N]     = (void *) invalid_func;
+    diffuse_funcs[WINED3DDECLTYPE_USHORT4N]     = (void *) glColor4usv;
+    diffuse_funcs[WINED3DDECLTYPE_UDEC3]        = (void *) invalid_func;
+    diffuse_funcs[WINED3DDECLTYPE_DEC3N]        = (void *) invalid_func;
+    diffuse_funcs[WINED3DDECLTYPE_FLOAT16_2]    = (void *) invalid_func;
+    diffuse_funcs[WINED3DDECLTYPE_FLOAT16_4]    = (void *) invalid_func;
+
+    /* No 4 component entry points here */
+    specular_funcs[WINED3DDECLTYPE_FLOAT1]      = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_FLOAT2]      = (void *) invalid_func;
+    if(GL_SUPPORT(EXT_SECONDARY_COLOR)) {
+        specular_funcs[WINED3DDECLTYPE_FLOAT3]      = (void *) GL_EXTCALL(glSecondaryColor3fvEXT);
+    } else {
+        specular_funcs[WINED3DDECLTYPE_FLOAT3]      = (void *) warn_no_specular_func;
+    }
+    specular_funcs[WINED3DDECLTYPE_FLOAT4]      = (void *) invalid_func;
+    if(GL_SUPPORT(EXT_SECONDARY_COLOR)) {
+        specular_funcs[WINED3DDECLTYPE_D3DCOLOR]    = (void *) specular_d3dcolor;
+    } else {
+        specular_funcs[WINED3DDECLTYPE_FLOAT3]      = (void *) warn_no_specular_func;
+    }
+    specular_funcs[WINED3DDECLTYPE_UBYTE4]      = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_SHORT2]      = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_SHORT4]      = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_UBYTE4N]     = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_SHORT2N]     = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_SHORT4N]     = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_USHORT2N]    = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_USHORT4N]    = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_UDEC3]       = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_DEC3N]       = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_FLOAT16_2]   = (void *) invalid_func;
+    specular_funcs[WINED3DDECLTYPE_FLOAT16_4]   = (void *) invalid_func;
+
+    /* Only 3 component entry points here. Test how others behave. Float4 normals are used
+     * by one of our tests, trying to pass it to the pixel shader, which fails on Windows.
+     */
+    normal_funcs[WINED3DDECLTYPE_FLOAT1]         = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_FLOAT2]         = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_FLOAT3]         = (void *) glNormal3fv;
+    normal_funcs[WINED3DDECLTYPE_FLOAT4]         = (void *) glNormal3fv; /* Just ignore the 4th value */
+    normal_funcs[WINED3DDECLTYPE_D3DCOLOR]       = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_UBYTE4]         = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_SHORT2]         = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_SHORT4]         = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_UBYTE4N]        = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_SHORT2N]        = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_SHORT4N]        = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_USHORT2N]       = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_USHORT4N]       = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_UDEC3]          = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_DEC3N]          = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_FLOAT16_2]      = (void *) invalid_func;
+    normal_funcs[WINED3DDECLTYPE_FLOAT16_4]      = (void *) invalid_func;
+}
+
+#define PUSH1(att)        attribs[nAttribs++] = (att);
 BOOL InitAdapters(void) {
     static HMODULE mod_gl;
     BOOL ret;
@@ -3022,6 +3159,7 @@ BOOL InitAdapters(void) {
 
         select_shader_mode(&Adapters[0].gl_info, WINED3DDEVTYPE_HAL, &ps_selected_mode, &vs_selected_mode);
         select_shader_max_constants(ps_selected_mode, vs_selected_mode, &Adapters[0].gl_info);
+        fillGLAttribFuncs(&Adapters[0].gl_info);
 
     }
     numAdapters = 1;
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 59a952f4fca..aa7dd6250f3 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -302,8 +302,6 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData
     const WORD                *pIdxBufS     = NULL;
     const DWORD               *pIdxBufL     = NULL;
     LONG                       vx_index;
-    float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
-    float rhw = 0.0f;                      /* rhw                        */
     DWORD diffuseColor = 0xFFFFFFFF;       /* Diffuse Color              */
     DWORD specularColor = 0;               /* Specular Color             */
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
@@ -353,6 +351,32 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData
         position = sd->u.s.position.lpData + streamOffset[sd->u.s.position.streamNo];
     }
 
+    /* The texture coordinate types are not so easy to map into a common function signature - we're
+     * not using the vector functions here
+     */
+    if(FIXME_ON(d3d_draw)) {
+        for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
+            DWORD type = sd->u.s.texCoords[textureNo].dwType;
+            if (sd->u.s.texCoords[textureNo].lpData &&
+                type != WINED3DDECLTYPE_FLOAT1 &&
+                type != WINED3DDECLTYPE_FLOAT2 &&
+                type != WINED3DDECLTYPE_FLOAT3 &&
+                type != WINED3DDECLTYPE_FLOAT4) {
+                FIXME("Implement fixed function texture coordinates from %s\n", debug_d3ddecltype(type));
+            }
+        }
+        if(specular && This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
+           (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == WINED3DFOG_NONE || sd->u.s.position_transformed )&&
+           This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
+            if(GL_SUPPORT(EXT_FOG_COORD) && sd->u.s.specular.dwType != WINED3DDECLTYPE_D3DCOLOR) {
+                FIXME("Implement fog coordinates from %s\n", debug_d3ddecltype(sd->u.s.specular.dwType));
+            }
+        }
+        if(This->activeContext->num_untracked_materials && sd->u.s.diffuse.dwType != WINED3DDECLTYPE_D3DCOLOR) {
+            FIXME("Implement diffuse color tracking from %s\n", debug_d3ddecltype(sd->u.s.diffuse.dwType));
+        }
+    }
+
     /* Start drawing in GL */
     VTRACE(("glBegin(%x)\n", glPrimType));
     glBegin(glPrimType);
@@ -486,22 +510,13 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData
         /* Diffuse -------------------------------- */
         if (diffuse) {
             DWORD *ptrToCoords = (DWORD *)(diffuse + (SkipnStrides * sd->u.s.diffuse.dwStride));
-            diffuseColor = ptrToCoords[0];
-            VTRACE(("diffuseColor=%lx\n", diffuseColor));
-
-            glColor4ub(D3DCOLOR_B_R(diffuseColor),
-		     D3DCOLOR_B_G(diffuseColor),
-		     D3DCOLOR_B_B(diffuseColor),
-		     D3DCOLOR_B_A(diffuseColor));
-            VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n", 
-                    D3DCOLOR_B_R(diffuseColor),
-		    D3DCOLOR_B_G(diffuseColor),
-		    D3DCOLOR_B_B(diffuseColor),
-		    D3DCOLOR_B_A(diffuseColor)));
 
+            diffuse_funcs[sd->u.s.diffuse.dwType]((void *) ptrToCoords);
             if(This->activeContext->num_untracked_materials) {
                 unsigned char i;
                 float color[4];
+
+                diffuseColor = ptrToCoords[0];
                 color[0] = D3DCOLOR_B_R(diffuseColor) / 255.0;
                 color[1] = D3DCOLOR_B_G(diffuseColor) / 255.0;
                 color[2] = D3DCOLOR_B_B(diffuseColor) / 255.0;
@@ -516,14 +531,13 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData
         /* Specular ------------------------------- */
         if (specular) {
             DWORD *ptrToCoords = (DWORD *)(specular + (SkipnStrides * sd->u.s.specular.dwStride));
-            specularColor = ptrToCoords[0];
-            VTRACE(("specularColor=%lx\n", specularColor));
 
             /* special case where the fog density is stored in the specular alpha channel */
             if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
               (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == WINED3DFOG_NONE || sd->u.s.position.dwType == WINED3DDECLTYPE_FLOAT4 )&&
               This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
                 if(GL_SUPPORT(EXT_FOG_COORD)) {
+                    specularColor = ptrToCoords[0];
                     GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
                 } else {
                     static BOOL warned = FALSE;
@@ -535,52 +549,19 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData
                 }
             }
 
-            VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n", 
-                    D3DCOLOR_B_R(specularColor), 
-                    D3DCOLOR_B_G(specularColor), 
-                    D3DCOLOR_B_B(specularColor)));
-            if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
-                GL_EXTCALL(glSecondaryColor3ubEXT)(
-                           D3DCOLOR_B_R(specularColor),
-                           D3DCOLOR_B_G(specularColor),
-                           D3DCOLOR_B_B(specularColor));
-            } else {
-                /* Do not worry if specular colour missing and disable request */
-                VTRACE(("Specular color extensions not supplied\n"));
-            }
+            specular_funcs[sd->u.s.specular.dwType]((void *) ptrToCoords);
         }
 
         /* Normal -------------------------------- */
         if (normal != NULL) {
             float *ptrToCoords = (float *)(normal + (SkipnStrides * sd->u.s.normal.dwStride));
-
-            VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", ptrToCoords[0], ptrToCoords[1], ptrToCoords[2]));
-            glNormal3f(ptrToCoords[0], ptrToCoords[1], ptrToCoords[2]);
+            normal_funcs[sd->u.s.normal.dwType](ptrToCoords);
         }
 
         /* Position -------------------------------- */
         if (position) {
             float *ptrToCoords = (float *)(position + (SkipnStrides * sd->u.s.position.dwStride));
-            x = ptrToCoords[0];
-            y = ptrToCoords[1];
-            z = ptrToCoords[2];
-            rhw = 1.0;
-            VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
-
-            /* RHW follows, only if transformed, ie 4 floats were provided */
-            if (sd->u.s.position_transformed) {
-                rhw = ptrToCoords[3];
-                VTRACE(("rhw=%f\n", rhw));
-            }
-
-            if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
-                VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
-                glVertex3f(x, y, z);
-            } else {
-                GLfloat w = 1.0 / rhw;
-                VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
-                glVertex4f(x*w, y*w, z*w, w);
-            }
+            position_funcs[sd->u.s.position.dwType](ptrToCoords);
         }
 
         /* For non indexed mode, step onto next parts */
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index d26b91dbebb..39868cfdac2 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -3232,7 +3232,9 @@ static void loadVertexData(IWineD3DStateBlockImpl *stateblock, WineDirect3DVerte
             checkGLcall("glBindBufferARB");
             curVBO = sd->u.s.diffuse.VBO;
         }
-        glColorPointer(4, GL_UNSIGNED_BYTE,
+
+        glColorPointer(WINED3D_ATR_SIZE(sd->u.s.diffuse.dwType),
+                       WINED3D_ATR_GLTYPE(sd->u.s.diffuse.dwType),
                        sd->u.s.diffuse.dwStride,
                        sd->u.s.diffuse.lpData + stateblock->loadBaseVertexIndex * sd->u.s.diffuse.dwStride + offset[sd->u.s.diffuse.streamNo]);
         checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
@@ -3257,7 +3259,8 @@ static void loadVertexData(IWineD3DStateBlockImpl *stateblock, WineDirect3DVerte
                 checkGLcall("glBindBufferARB");
                 curVBO = sd->u.s.specular.VBO;
             }
-            GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
+            GL_EXTCALL(glSecondaryColorPointerEXT)(WINED3D_ATR_SIZE(sd->u.s.specular.dwType),
+                                                   WINED3D_ATR_GLTYPE(sd->u.s.specular.dwType),
                                                    sd->u.s.specular.dwStride,
                                                    sd->u.s.specular.lpData + stateblock->loadBaseVertexIndex * sd->u.s.specular.dwStride + offset[sd->u.s.specular.streamNo]);
             vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index ad8047c7d62..0934080123f 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -410,6 +410,13 @@ void primitiveDeclarationConvertToStridedData(
 
 DWORD get_flexible_vertex_size(DWORD d3dvtVertexType);
 
+typedef void (*glAttribFunc)(void *data);
+typedef void (*glTexAttribFunc)(GLuint unit, void *data);
+extern glAttribFunc position_funcs[WINED3DDECLTYPE_UNUSED];
+extern glAttribFunc diffuse_funcs[WINED3DDECLTYPE_UNUSED];
+extern glAttribFunc specular_funcs[WINED3DDECLTYPE_UNUSED];
+extern glAttribFunc normal_funcs[WINED3DDECLTYPE_UNUSED];
+
 #define eps 1e-8
 
 #define GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_num) \