wined3d: Rename IWineD3DDevice::SetIndices() to IWineD3DDevice::SetIndexBuffer().
[wine] / dlls / wined3d / vertexdeclaration.c
1 /*
2  * vertex declaration implementation
3  *
4  * Copyright 2002-2005 Raphael Junqueira
5  * Copyright 2004 Jason Edmeades
6  * Copyright 2004 Christian Costa
7  * Copyright 2005 Oliver Stieber
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wined3d_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_decl);
28
29 #define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info
30
31 static void dump_wined3dvertexelement(const WINED3DVERTEXELEMENT *element) {
32     TRACE("     format: %s (%#x)\n", debug_d3dformat(element->format), element->format);
33     TRACE(" input_slot: %u\n", element->input_slot);
34     TRACE("     offset: %u\n", element->offset);
35     TRACE("output_slot: %u\n", element->output_slot);
36     TRACE("     method: %s (%#x)\n", debug_d3ddeclmethod(element->method), element->method);
37     TRACE("      usage: %s (%#x)\n", debug_d3ddeclusage(element->usage), element->usage);
38     TRACE("  usage_idx: %u\n", element->usage_idx);
39 }
40
41 /* *******************************************
42    IWineD3DVertexDeclaration IUnknown parts follow
43    ******************************************* */
44 static HRESULT WINAPI IWineD3DVertexDeclarationImpl_QueryInterface(IWineD3DVertexDeclaration *iface, REFIID riid, LPVOID *ppobj)
45 {
46     IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
47     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
48     if (IsEqualGUID(riid, &IID_IUnknown)
49         || IsEqualGUID(riid, &IID_IWineD3DBase)
50         || IsEqualGUID(riid, &IID_IWineD3DVertexDeclaration)){
51         IUnknown_AddRef(iface);
52         *ppobj = This;
53         return S_OK;
54     }
55     *ppobj = NULL;
56     return E_NOINTERFACE;
57 }
58
59 static ULONG WINAPI IWineD3DVertexDeclarationImpl_AddRef(IWineD3DVertexDeclaration *iface) {
60     IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
61     TRACE("(%p) : AddRef increasing from %d\n", This, This->ref);
62     return InterlockedIncrement(&This->ref);
63 }
64
65 static ULONG WINAPI IWineD3DVertexDeclarationImpl_Release(IWineD3DVertexDeclaration *iface) {
66     IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
67     ULONG ref;
68     TRACE("(%p) : Releasing from %d\n", This, This->ref);
69     ref = InterlockedDecrement(&This->ref);
70     if (ref == 0) {
71         if(iface == This->wineD3DDevice->stateBlock->vertexDecl) {
72             /* See comment in PixelShader::Release */
73             IWineD3DDeviceImpl_MarkStateDirty(This->wineD3DDevice, STATE_VDECL);
74         }
75
76         HeapFree(GetProcessHeap(), 0, This->elements);
77         This->parent_ops->wined3d_object_destroyed(This->parent);
78         HeapFree(GetProcessHeap(), 0, This);
79     }
80     return ref;
81 }
82
83 /* *******************************************
84    IWineD3DVertexDeclaration parts follow
85    ******************************************* */
86
87 static HRESULT WINAPI IWineD3DVertexDeclarationImpl_GetParent(IWineD3DVertexDeclaration *iface, IUnknown** parent){
88     IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
89
90     *parent= This->parent;
91     IUnknown_AddRef(*parent);
92     TRACE("(%p) : returning %p\n", This, *parent);
93     return WINED3D_OK;
94 }
95
96 static HRESULT WINAPI IWineD3DVertexDeclarationImpl_GetDevice(IWineD3DVertexDeclaration *iface, IWineD3DDevice** ppDevice) {
97     IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
98     TRACE("(%p) : returning %p\n", This, This->wineD3DDevice);
99
100     *ppDevice = (IWineD3DDevice *) This->wineD3DDevice;
101     IWineD3DDevice_AddRef(*ppDevice);
102
103     return WINED3D_OK;
104 }
105
106 static BOOL declaration_element_valid_ffp(const WINED3DVERTEXELEMENT *element)
107 {
108     switch(element->usage)
109     {
110         case WINED3DDECLUSAGE_POSITION:
111         case WINED3DDECLUSAGE_POSITIONT:
112             switch(element->format)
113             {
114                 case WINED3DFMT_R32G32_FLOAT:
115                 case WINED3DFMT_R32G32B32_FLOAT:
116                 case WINED3DFMT_R32G32B32A32_FLOAT:
117                 case WINED3DFMT_R16G16_SINT:
118                 case WINED3DFMT_R16G16B16A16_SINT:
119                 case WINED3DFMT_R16G16_FLOAT:
120                 case WINED3DFMT_R16G16B16A16_FLOAT:
121                     return TRUE;
122                 default:
123                     return FALSE;
124             }
125
126         case WINED3DDECLUSAGE_BLENDWEIGHT:
127             switch(element->format)
128             {
129                 case WINED3DFMT_R32_FLOAT:
130                 case WINED3DFMT_R32G32_FLOAT:
131                 case WINED3DFMT_R32G32B32_FLOAT:
132                 case WINED3DFMT_R32G32B32A32_FLOAT:
133                 case WINED3DFMT_A8R8G8B8:
134                 case WINED3DFMT_R8G8B8A8_UINT:
135                 case WINED3DFMT_R16G16_SINT:
136                 case WINED3DFMT_R16G16B16A16_SINT:
137                 case WINED3DFMT_R16G16_FLOAT:
138                 case WINED3DFMT_R16G16B16A16_FLOAT:
139                     return TRUE;
140                 default:
141                     return FALSE;
142             }
143
144         case WINED3DDECLUSAGE_NORMAL:
145             switch(element->format)
146             {
147                 case WINED3DFMT_R32G32B32_FLOAT:
148                 case WINED3DFMT_R32G32B32A32_FLOAT:
149                 case WINED3DFMT_R16G16B16A16_SINT:
150                 case WINED3DFMT_R16G16B16A16_FLOAT:
151                     return TRUE;
152                 default:
153                     return FALSE;
154             }
155
156         case WINED3DDECLUSAGE_TEXCOORD:
157             switch(element->format)
158             {
159                 case WINED3DFMT_R32_FLOAT:
160                 case WINED3DFMT_R32G32_FLOAT:
161                 case WINED3DFMT_R32G32B32_FLOAT:
162                 case WINED3DFMT_R32G32B32A32_FLOAT:
163                 case WINED3DFMT_R16G16_SINT:
164                 case WINED3DFMT_R16G16B16A16_SINT:
165                 case WINED3DFMT_R16G16_FLOAT:
166                 case WINED3DFMT_R16G16B16A16_FLOAT:
167                     return TRUE;
168                 default:
169                     return FALSE;
170             }
171
172         case WINED3DDECLUSAGE_COLOR:
173             switch(element->format)
174             {
175                 case WINED3DFMT_R32G32B32_FLOAT:
176                 case WINED3DFMT_R32G32B32A32_FLOAT:
177                 case WINED3DFMT_A8R8G8B8:
178                 case WINED3DFMT_R8G8B8A8_UINT:
179                 case WINED3DFMT_R16G16B16A16_SINT:
180                 case WINED3DFMT_R8G8B8A8_UNORM:
181                 case WINED3DFMT_R16G16B16A16_SNORM:
182                 case WINED3DFMT_R16G16B16A16_UNORM:
183                 case WINED3DFMT_R16G16B16A16_FLOAT:
184                     return TRUE;
185                 default:
186                     return FALSE;
187             }
188
189         default:
190             return FALSE;
191     }
192 }
193
194 static const IWineD3DVertexDeclarationVtbl IWineD3DVertexDeclaration_Vtbl =
195 {
196     /* IUnknown */
197     IWineD3DVertexDeclarationImpl_QueryInterface,
198     IWineD3DVertexDeclarationImpl_AddRef,
199     IWineD3DVertexDeclarationImpl_Release,
200     /* IWineD3DVertexDeclaration */
201     IWineD3DVertexDeclarationImpl_GetParent,
202     IWineD3DVertexDeclarationImpl_GetDevice,
203 };
204
205 HRESULT vertexdeclaration_init(IWineD3DVertexDeclarationImpl *declaration, IWineD3DDeviceImpl *device,
206         const WINED3DVERTEXELEMENT *elements, UINT element_count,
207         IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
208 {
209     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
210     WORD preloaded = 0; /* MAX_STREAMS, 16 */
211     unsigned int i;
212
213     if (TRACE_ON(d3d_decl))
214     {
215         for (i = 0; i < element_count; ++i)
216         {
217             dump_wined3dvertexelement(elements + i);
218         }
219     }
220
221     declaration->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
222     declaration->ref = 1;
223     declaration->parent = parent;
224     declaration->parent_ops = parent_ops;
225     declaration->wineD3DDevice = device;
226     declaration->elements = HeapAlloc(GetProcessHeap(), 0, sizeof(*declaration->elements) * element_count);
227     if (!declaration->elements)
228     {
229         ERR("Failed to allocate elements memory.\n");
230         return E_OUTOFMEMORY;
231     }
232     declaration->element_count = element_count;
233
234     /* Do some static analysis on the elements to make reading the
235      * declaration more comfortable for the drawing code. */
236     for (i = 0; i < element_count; ++i)
237     {
238         struct wined3d_vertex_declaration_element *e = &declaration->elements[i];
239
240         e->format_desc = getFormatDescEntry(elements[i].format, gl_info);
241         e->ffp_valid = declaration_element_valid_ffp(&elements[i]);
242         e->input_slot = elements[i].input_slot;
243         e->offset = elements[i].offset;
244         e->output_slot = elements[i].output_slot;
245         e->method = elements[i].method;
246         e->usage = elements[i].usage;
247         e->usage_idx = elements[i].usage_idx;
248
249         if (e->usage == WINED3DDECLUSAGE_POSITIONT) declaration->position_transformed = TRUE;
250
251         /* Find the streams used in the declaration. The vertex buffers have
252          * to be loaded when drawing, but filter tesselation pseudo streams. */
253         if (e->input_slot >= MAX_STREAMS) continue;
254
255         if (!e->format_desc->gl_vtx_format)
256         {
257             FIXME("The application tries to use an unsupported format (%s), returning E_FAIL.\n",
258                     debug_d3dformat(elements[i].format));
259             HeapFree(GetProcessHeap(), 0, declaration->elements);
260             return E_FAIL;
261         }
262
263         if (e->offset & 0x3)
264         {
265             WARN("Declaration element %u is not 4 byte aligned(%u), returning E_FAIL.\n", i, e->offset);
266             HeapFree(GetProcessHeap(), 0, declaration->elements);
267             return E_FAIL;
268         }
269
270         if (!(preloaded & (1 << e->input_slot)))
271         {
272             declaration->streams[declaration->num_streams] = e->input_slot;
273             ++declaration->num_streams;
274             preloaded |= 1 << e->input_slot;
275         }
276
277         if (elements[i].format == WINED3DFMT_R16G16_FLOAT || elements[i].format == WINED3DFMT_R16G16B16A16_FLOAT)
278         {
279             if (!gl_info->supported[ARB_HALF_FLOAT_VERTEX]) declaration->half_float_conv_needed = TRUE;
280         }
281     }
282
283     return WINED3D_OK;
284 }