fltlib: Add a stub dll.
[wine] / dlls / d3d8 / vertexshader.c
1 /*
2  * IDirect3DVertexShader8 implementation
3  *
4  * Copyright 2002-2003 Jason Edmeades
5  *                     Raphael Junqueira
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "d3d8_private.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d8);
26
27 /* IDirect3DVertexShader8 IUnknown parts follow: */
28 static HRESULT WINAPI IDirect3DVertexShader8Impl_QueryInterface(IDirect3DVertexShader8 *iface, REFIID riid, LPVOID* ppobj) {
29     IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface;
30
31     if (IsEqualGUID(riid, &IID_IUnknown)
32         || IsEqualGUID(riid, &IID_IDirect3DVertexShader8)) {
33         IUnknown_AddRef(iface);
34         *ppobj = This;
35         return S_OK;
36     }
37
38     WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj);
39     *ppobj = NULL;
40     return E_NOINTERFACE;
41 }
42
43 static ULONG WINAPI IDirect3DVertexShader8Impl_AddRef(IDirect3DVertexShader8 *iface) {
44     IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface;
45     ULONG ref = InterlockedIncrement(&This->ref);
46
47     TRACE("(%p) : AddRef from %d\n", This, ref - 1);
48
49     if (ref == 1 && This->wineD3DVertexShader)
50     {
51         wined3d_mutex_lock();
52         IWineD3DVertexShader_AddRef(This->wineD3DVertexShader);
53         wined3d_mutex_unlock();
54     }
55
56     return ref;
57 }
58
59 static void STDMETHODCALLTYPE d3d8_vertexshader_wined3d_object_destroyed(void *parent)
60 {
61     IDirect3DVertexShader8Impl *shader = parent;
62     IDirect3DVertexDeclaration8_Release(shader->vertex_declaration);
63     HeapFree(GetProcessHeap(), 0, shader);
64 }
65
66 static ULONG WINAPI IDirect3DVertexShader8Impl_Release(IDirect3DVertexShader8 *iface) {
67     IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface;
68     ULONG ref = InterlockedDecrement(&This->ref);
69
70     TRACE("(%p) : ReleaseRef to %d\n", This, ref);
71
72     if (ref == 0) {
73         if (This->wineD3DVertexShader)
74         {
75             wined3d_mutex_lock();
76             IWineD3DVertexShader_Release(This->wineD3DVertexShader);
77             wined3d_mutex_unlock();
78         }
79         else
80         {
81             d3d8_vertexshader_wined3d_object_destroyed(This);
82         }
83     }
84     return ref;
85 }
86
87 static const IDirect3DVertexShader8Vtbl Direct3DVertexShader8_Vtbl =
88 {
89     /* IUnknown */
90     IDirect3DVertexShader8Impl_QueryInterface,
91     IDirect3DVertexShader8Impl_AddRef,
92     IDirect3DVertexShader8Impl_Release,
93 };
94
95 static const struct wined3d_parent_ops d3d8_vertexshader_wined3d_parent_ops =
96 {
97     d3d8_vertexshader_wined3d_object_destroyed,
98 };
99
100 static HRESULT vertexshader_create_vertexdeclaration(IDirect3DDevice8Impl *device,
101         const DWORD *declaration, DWORD shader_handle, IDirect3DVertexDeclaration8 **decl_ptr)
102 {
103     IDirect3DVertexDeclaration8Impl *object;
104     HRESULT hr;
105
106     TRACE("device %p, declaration %p, shader_handle %#x, decl_ptr %p.\n",
107             device, declaration, shader_handle, decl_ptr);
108
109     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
110     if (!object) {
111         ERR("Memory allocation failed\n");
112         *decl_ptr = NULL;
113         return D3DERR_OUTOFVIDEOMEMORY;
114     }
115
116     hr = vertexdeclaration_init(object, device, declaration, shader_handle);
117     if (FAILED(hr))
118     {
119         WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
120         HeapFree(GetProcessHeap(), 0, object);
121         return hr;
122     }
123
124     TRACE("Created vertex declaration %p.\n", object);
125     *decl_ptr = (IDirect3DVertexDeclaration8 *)object;
126
127     return D3D_OK;
128 }
129
130 HRESULT vertexshader_init(IDirect3DVertexShader8Impl *shader, IDirect3DDevice8Impl *device,
131         const DWORD *declaration, const DWORD *byte_code, DWORD shader_handle, DWORD usage)
132 {
133     const DWORD *token = declaration;
134     HRESULT hr;
135
136     /* Test if the vertex declaration is valid */
137     while (D3DVSD_END() != *token)
138     {
139         D3DVSD_TOKENTYPE token_type = ((*token & D3DVSD_TOKENTYPEMASK) >> D3DVSD_TOKENTYPESHIFT);
140
141         if (token_type == D3DVSD_TOKEN_STREAMDATA && !(token_type & 0x10000000))
142         {
143             DWORD type = ((*token & D3DVSD_DATATYPEMASK) >> D3DVSD_DATATYPESHIFT);
144             DWORD reg  = ((*token & D3DVSD_VERTEXREGMASK) >> D3DVSD_VERTEXREGSHIFT);
145
146             if (reg == D3DVSDE_NORMAL && type != D3DVSDT_FLOAT3 && !byte_code)
147             {
148                 WARN("Attempt to use a non-FLOAT3 normal with the fixed function function\n");
149                 return D3DERR_INVALIDCALL;
150             }
151         }
152         token += parse_token(token);
153     }
154
155     shader->ref = 1;
156     shader->lpVtbl = &Direct3DVertexShader8_Vtbl;
157
158     hr = vertexshader_create_vertexdeclaration(device, declaration, shader_handle, &shader->vertex_declaration);
159     if (FAILED(hr))
160     {
161         WARN("Failed to create vertex declaration, hr %#x.\n", hr);
162         return hr;
163     }
164
165     if (byte_code)
166     {
167         if (usage) FIXME("Usage %#x not implemented.\n", usage);
168
169         wined3d_mutex_lock();
170         hr = IWineD3DDevice_CreateVertexShader(device->WineD3DDevice, byte_code,
171                 NULL /* output signature */, &shader->wineD3DVertexShader,
172                 (IUnknown *)shader, &d3d8_vertexshader_wined3d_parent_ops);
173         wined3d_mutex_unlock();
174         if (FAILED(hr))
175         {
176             WARN("Failed to create wined3d vertex shader, hr %#x.\n", hr);
177             IDirect3DVertexDeclaration8_Release(shader->vertex_declaration);
178             return hr;
179         }
180
181         load_local_constants(declaration, shader->wineD3DVertexShader);
182     }
183
184     return D3D_OK;
185 }