3ac5799bd0f5817a1b99354644c5c1dbd6260675
[reactos.git] / reactos / dll / directx / wine / d3dx9_36 / skin.c
1 /*
2 * Skin Info operations specific to D3DX9.
3 *
4 * Copyright (C) 2011 Dylan Smith
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "d3dx9_36_private.h"
22
23 struct bone
24 {
25 char *name;
26 D3DXMATRIX transform;
27 DWORD num_influences;
28 DWORD *vertices;
29 FLOAT *weights;
30 };
31
32 typedef struct ID3DXSkinInfoImpl
33 {
34 ID3DXSkinInfo ID3DXSkinInfo_iface;
35 LONG ref;
36
37 DWORD fvf;
38 D3DVERTEXELEMENT9 vertex_declaration[MAX_FVF_DECL_SIZE];
39 DWORD num_vertices;
40 DWORD num_bones;
41 struct bone *bones;
42 } ID3DXSkinInfoImpl;
43
44 static inline struct ID3DXSkinInfoImpl *impl_from_ID3DXSkinInfo(ID3DXSkinInfo *iface)
45 {
46 return CONTAINING_RECORD(iface, struct ID3DXSkinInfoImpl, ID3DXSkinInfo_iface);
47 }
48
49 static HRESULT WINAPI ID3DXSkinInfoImpl_QueryInterface(ID3DXSkinInfo *iface, REFIID riid, void **ppobj)
50 {
51 TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), ppobj);
52
53 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ID3DXSkinInfo))
54 {
55 IUnknown_AddRef(iface);
56 *ppobj = iface;
57 return D3D_OK;
58 }
59
60 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
61
62 return E_NOINTERFACE;
63 }
64
65 static ULONG WINAPI ID3DXSkinInfoImpl_AddRef(ID3DXSkinInfo *iface)
66 {
67 struct ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
68 ULONG ref = InterlockedIncrement(&This->ref);
69
70 TRACE("%p increasing refcount to %u\n", This, ref);
71
72 return ref;
73 }
74
75 static ULONG WINAPI ID3DXSkinInfoImpl_Release(ID3DXSkinInfo *iface)
76 {
77 struct ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
78 ULONG ref = InterlockedDecrement(&This->ref);
79
80 TRACE("%p decreasing refcount to %u\n", This, ref);
81
82 if (ref == 0) {
83 DWORD i;
84 for (i = 0; i < This->num_bones; i++) {
85 HeapFree(GetProcessHeap(), 0, This->bones[i].name);
86 HeapFree(GetProcessHeap(), 0, This->bones[i].vertices);
87 HeapFree(GetProcessHeap(), 0, This->bones[i].weights);
88 }
89 HeapFree(GetProcessHeap(), 0, This->bones);
90 HeapFree(GetProcessHeap(), 0, This);
91 }
92
93 return ref;
94 }
95
96 static HRESULT WINAPI ID3DXSkinInfoImpl_SetBoneInfluence(ID3DXSkinInfo *iface, DWORD bone_num, DWORD num_influences, CONST DWORD *vertices, CONST FLOAT *weights)
97 {
98 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
99 struct bone *bone;
100 DWORD *new_vertices = NULL;
101 FLOAT *new_weights = NULL;
102
103 TRACE("(%p, %u, %u, %p, %p)\n", This, bone_num, num_influences, vertices, weights);
104
105 if (bone_num >= This->num_bones || !vertices || !weights)
106 return D3DERR_INVALIDCALL;
107
108 if (num_influences) {
109 new_vertices = HeapAlloc(GetProcessHeap(), 0, num_influences * sizeof(*vertices));
110 if (!new_vertices)
111 return E_OUTOFMEMORY;
112 new_weights = HeapAlloc(GetProcessHeap(), 0, num_influences * sizeof(*weights));
113 if (!new_weights) {
114 HeapFree(GetProcessHeap(), 0, new_vertices);
115 return E_OUTOFMEMORY;
116 }
117 memcpy(new_vertices, vertices, num_influences * sizeof(*vertices));
118 memcpy(new_weights, weights, num_influences * sizeof(*weights));
119 }
120 bone = &This->bones[bone_num];
121 bone->num_influences = num_influences;
122 HeapFree(GetProcessHeap(), 0, bone->vertices);
123 HeapFree(GetProcessHeap(), 0, bone->weights);
124 bone->vertices = new_vertices;
125 bone->weights = new_weights;
126
127 return D3D_OK;
128 }
129
130 static HRESULT WINAPI ID3DXSkinInfoImpl_SetBoneVertexInfluence(ID3DXSkinInfo *iface, DWORD bone_num, DWORD influence_num, float weight)
131 {
132 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
133
134 FIXME("(%p, %u, %u, %g): stub\n", This, bone_num, influence_num, weight);
135
136 return E_NOTIMPL;
137 }
138
139 static DWORD WINAPI ID3DXSkinInfoImpl_GetNumBoneInfluences(ID3DXSkinInfo *iface, DWORD bone_num)
140 {
141 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
142
143 TRACE("(%p, %u)\n", This, bone_num);
144
145 if (bone_num >= This->num_bones)
146 return 0;
147
148 return This->bones[bone_num].num_influences;
149 }
150
151 static HRESULT WINAPI ID3DXSkinInfoImpl_GetBoneInfluence(ID3DXSkinInfo *iface, DWORD bone_num, DWORD *vertices, FLOAT *weights)
152 {
153 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
154 struct bone *bone;
155
156 TRACE("(%p, %u, %p, %p)\n", This, bone_num, vertices, weights);
157
158 if (bone_num >= This->num_bones || !vertices)
159 return D3DERR_INVALIDCALL;
160
161 bone = &This->bones[bone_num];
162 if (!bone->num_influences)
163 return D3D_OK;
164
165 memcpy(vertices, bone->vertices, bone->num_influences * sizeof(*vertices));
166 if (weights)
167 memcpy(weights, bone->weights, bone->num_influences * sizeof(*weights));
168
169 return D3D_OK;
170 }
171
172 static HRESULT WINAPI ID3DXSkinInfoImpl_GetBoneVertexInfluence(ID3DXSkinInfo *iface, DWORD bone_num,
173 DWORD influence_num, float *weight, DWORD *vertex_num)
174 {
175 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
176
177 FIXME("(%p, %u, %u, %p, %p): stub\n", This, bone_num, influence_num, weight, vertex_num);
178
179 return E_NOTIMPL;
180 }
181
182 static HRESULT WINAPI ID3DXSkinInfoImpl_GetMaxVertexInfluences(ID3DXSkinInfo *iface, DWORD *max_vertex_influences)
183 {
184 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
185
186 FIXME("(%p, %p): stub\n", This, max_vertex_influences);
187
188 return E_NOTIMPL;
189 }
190
191 static DWORD WINAPI ID3DXSkinInfoImpl_GetNumBones(ID3DXSkinInfo *iface)
192 {
193 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
194
195 TRACE("(%p)\n", This);
196
197 return This->num_bones;
198 }
199
200 static HRESULT WINAPI ID3DXSkinInfoImpl_FindBoneVertexInfluenceIndex(ID3DXSkinInfo *iface, DWORD bone_num,
201 DWORD vertex_num, DWORD *influence_index)
202 {
203 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
204
205 FIXME("(%p, %u, %u, %p): stub\n", This, bone_num, vertex_num, influence_index);
206
207 return E_NOTIMPL;
208 }
209
210 static HRESULT WINAPI ID3DXSkinInfoImpl_GetMaxFaceInfluences(struct ID3DXSkinInfo *iface,
211 struct IDirect3DIndexBuffer9 *index_buffer, DWORD num_faces, DWORD *max_face_influences)
212 {
213 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
214
215 FIXME("(%p, %p, %u, %p): stub\n", This, index_buffer, num_faces, max_face_influences);
216
217 return E_NOTIMPL;
218 }
219
220 static HRESULT WINAPI ID3DXSkinInfoImpl_SetMinBoneInfluence(ID3DXSkinInfo *iface, FLOAT min_influence)
221 {
222 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
223
224 FIXME("(%p, %g): stub\n", This, min_influence);
225
226 return E_NOTIMPL;
227 }
228
229 static FLOAT WINAPI ID3DXSkinInfoImpl_GetMinBoneInfluence(ID3DXSkinInfo *iface)
230 {
231 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
232
233 FIXME("(%p): stub\n", This);
234
235 return 0.0f;
236 }
237
238 static HRESULT WINAPI ID3DXSkinInfoImpl_SetBoneName(ID3DXSkinInfo *iface, DWORD bone_num, LPCSTR name)
239 {
240 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
241 char *new_name;
242 size_t size;
243
244 TRACE("(%p, %u, %s)\n", This, bone_num, debugstr_a(name));
245
246 if (bone_num >= This->num_bones || !name)
247 return D3DERR_INVALIDCALL;
248
249 size = strlen(name) + 1;
250 new_name = HeapAlloc(GetProcessHeap(), 0, size);
251 if (!new_name)
252 return E_OUTOFMEMORY;
253 memcpy(new_name, name, size);
254 HeapFree(GetProcessHeap(), 0, This->bones[bone_num].name);
255 This->bones[bone_num].name = new_name;
256
257 return D3D_OK;
258 }
259
260 static LPCSTR WINAPI ID3DXSkinInfoImpl_GetBoneName(ID3DXSkinInfo *iface, DWORD bone_num)
261 {
262 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
263
264 TRACE("(%p, %u)\n", This, bone_num);
265
266 if (bone_num >= This->num_bones)
267 return NULL;
268
269 return This->bones[bone_num].name;
270 }
271
272 static HRESULT WINAPI ID3DXSkinInfoImpl_SetBoneOffsetMatrix(ID3DXSkinInfo *iface, DWORD bone_num, CONST D3DXMATRIX *bone_transform)
273 {
274 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
275
276 TRACE("(%p, %u, %p)\n", This, bone_num, bone_transform);
277
278 if (bone_num >= This->num_bones || !bone_transform)
279 return D3DERR_INVALIDCALL;
280
281 This->bones[bone_num].transform = *bone_transform;
282 return D3D_OK;
283 }
284
285 static D3DXMATRIX * WINAPI ID3DXSkinInfoImpl_GetBoneOffsetMatrix(ID3DXSkinInfo *iface, DWORD bone_num)
286 {
287 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
288
289 TRACE("(%p, %u)\n", This, bone_num);
290
291 if (bone_num >= This->num_bones)
292 return NULL;
293
294 return &This->bones[bone_num].transform;
295 }
296
297 static HRESULT WINAPI ID3DXSkinInfoImpl_Clone(ID3DXSkinInfo *iface, ID3DXSkinInfo **skin_info)
298 {
299 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
300
301 FIXME("(%p, %p): stub\n", This, skin_info);
302
303 return E_NOTIMPL;
304 }
305
306 static HRESULT WINAPI ID3DXSkinInfoImpl_Remap(ID3DXSkinInfo *iface, DWORD num_vertices, DWORD *vertex_remap)
307 {
308 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
309
310 FIXME("(%p, %u, %p): stub\n", This, num_vertices, vertex_remap);
311
312 return E_NOTIMPL;
313 }
314
315 static HRESULT WINAPI ID3DXSkinInfoImpl_SetFVF(ID3DXSkinInfo *iface, DWORD fvf)
316 {
317 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
318 HRESULT hr;
319 D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
320
321 TRACE("(%p, %x)\n", This, fvf);
322
323 hr = D3DXDeclaratorFromFVF(fvf, declaration);
324 if (FAILED(hr)) return hr;
325
326 return iface->lpVtbl->SetDeclaration(iface, declaration);
327 }
328
329 static HRESULT WINAPI ID3DXSkinInfoImpl_SetDeclaration(ID3DXSkinInfo *iface, CONST D3DVERTEXELEMENT9 *declaration)
330 {
331 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
332 HRESULT hr;
333 int count;
334
335 TRACE("(%p, %p)\n", This, declaration);
336
337 if (!declaration)
338 return D3DERR_INVALIDCALL;
339 for (count = 0; declaration[count].Stream != 0xff; count++) {
340 if (declaration[count].Stream != 0) {
341 WARN("Invalid vertex element %u; contains non-zero stream %u\n",
342 count, declaration[count].Stream);
343 return D3DERR_INVALIDCALL;
344 }
345 }
346 count++;
347
348 memcpy(This->vertex_declaration, declaration, count * sizeof(*declaration));
349
350 hr = D3DXFVFFromDeclarator(This->vertex_declaration, &This->fvf);
351 if (FAILED(hr))
352 This->fvf = 0;
353
354 return D3D_OK;
355 }
356
357 static DWORD WINAPI ID3DXSkinInfoImpl_GetFVF(ID3DXSkinInfo *iface)
358 {
359 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
360
361 TRACE("(%p)\n", This);
362
363 return This->fvf;
364 }
365
366 static HRESULT WINAPI ID3DXSkinInfoImpl_GetDeclaration(ID3DXSkinInfo *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
367 {
368 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
369 UINT count = 0;
370
371 TRACE("(%p)\n", This);
372
373 while (This->vertex_declaration[count++].Stream != 0xff);
374 memcpy(declaration, This->vertex_declaration, count * sizeof(declaration[0]));
375 return D3D_OK;
376 }
377
378 static HRESULT WINAPI ID3DXSkinInfoImpl_UpdateSkinnedMesh(ID3DXSkinInfo *iface, CONST D3DXMATRIX *bone_transforms,
379 CONST D3DXMATRIX *bone_inv_transpose_transforms, LPCVOID vertices_src, PVOID vertices_dest)
380 {
381 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
382
383 FIXME("(%p, %p, %p, %p, %p): stub\n", This, bone_transforms, bone_inv_transpose_transforms, vertices_src, vertices_dest);
384
385 return E_NOTIMPL;
386 }
387
388 static HRESULT WINAPI ID3DXSkinInfoImpl_ConvertToBlendedMesh(ID3DXSkinInfo *iface, ID3DXMesh *mesh_in,
389 DWORD options, const DWORD *adjacency_in, DWORD *adjacency_out, DWORD *face_remap,
390 ID3DXBuffer **vertex_remap, DWORD *max_face_infl, DWORD *num_bone_combinations,
391 ID3DXBuffer **bone_combination_table, ID3DXMesh **mesh_out)
392 {
393 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
394
395 FIXME("(%p, %p, %x, %p, %p, %p, %p, %p, %p, %p, %p): stub\n",
396 This, mesh_in, options, adjacency_in, adjacency_out, face_remap, vertex_remap,
397 max_face_infl, num_bone_combinations, bone_combination_table, mesh_out);
398
399 return E_NOTIMPL;
400 }
401
402 static HRESULT WINAPI ID3DXSkinInfoImpl_ConvertToIndexedBlendedMesh(ID3DXSkinInfo *iface, ID3DXMesh *mesh_in,
403 DWORD options, const DWORD *adjacency_in, DWORD *adjacency_out, DWORD *face_remap,
404 ID3DXBuffer **vertex_remap, DWORD *max_face_infl, DWORD *num_bone_combinations,
405 ID3DXBuffer **bone_combination_table, ID3DXMesh **mesh_out)
406 {
407 ID3DXSkinInfoImpl *This = impl_from_ID3DXSkinInfo(iface);
408
409 FIXME("(%p, %p, %x, %p, %p, %p, %p, %p, %p, %p, %p): stub\n",
410 This, mesh_in, options, adjacency_in, adjacency_out, face_remap, vertex_remap,
411 max_face_infl, num_bone_combinations, bone_combination_table, mesh_out);
412
413 return E_NOTIMPL;
414 }
415
416 static const struct ID3DXSkinInfoVtbl ID3DXSkinInfoImpl_Vtbl =
417 {
418 /* IUnknown methods */
419 ID3DXSkinInfoImpl_QueryInterface,
420 ID3DXSkinInfoImpl_AddRef,
421 ID3DXSkinInfoImpl_Release,
422 /* ID3DXSkinInfo */
423 ID3DXSkinInfoImpl_SetBoneInfluence,
424 ID3DXSkinInfoImpl_SetBoneVertexInfluence,
425 ID3DXSkinInfoImpl_GetNumBoneInfluences,
426 ID3DXSkinInfoImpl_GetBoneInfluence,
427 ID3DXSkinInfoImpl_GetBoneVertexInfluence,
428 ID3DXSkinInfoImpl_GetMaxVertexInfluences,
429 ID3DXSkinInfoImpl_GetNumBones,
430 ID3DXSkinInfoImpl_FindBoneVertexInfluenceIndex,
431 ID3DXSkinInfoImpl_GetMaxFaceInfluences,
432 ID3DXSkinInfoImpl_SetMinBoneInfluence,
433 ID3DXSkinInfoImpl_GetMinBoneInfluence,
434 ID3DXSkinInfoImpl_SetBoneName,
435 ID3DXSkinInfoImpl_GetBoneName,
436 ID3DXSkinInfoImpl_SetBoneOffsetMatrix,
437 ID3DXSkinInfoImpl_GetBoneOffsetMatrix,
438 ID3DXSkinInfoImpl_Clone,
439 ID3DXSkinInfoImpl_Remap,
440 ID3DXSkinInfoImpl_SetFVF,
441 ID3DXSkinInfoImpl_SetDeclaration,
442 ID3DXSkinInfoImpl_GetFVF,
443 ID3DXSkinInfoImpl_GetDeclaration,
444 ID3DXSkinInfoImpl_UpdateSkinnedMesh,
445 ID3DXSkinInfoImpl_ConvertToBlendedMesh,
446 ID3DXSkinInfoImpl_ConvertToIndexedBlendedMesh
447 };
448
449 HRESULT WINAPI D3DXCreateSkinInfo(DWORD num_vertices, const D3DVERTEXELEMENT9 *declaration,
450 DWORD num_bones, ID3DXSkinInfo **skin_info)
451 {
452 HRESULT hr;
453 ID3DXSkinInfoImpl *object = NULL;
454 static const D3DVERTEXELEMENT9 empty_declaration = D3DDECL_END();
455
456 TRACE("(%u, %p, %u, %p)\n", num_vertices, declaration, num_bones, skin_info);
457
458 if (!skin_info || !declaration)
459 return D3DERR_INVALIDCALL;
460
461 object = HeapAlloc(GetProcessHeap(), 0, sizeof(*object));
462 if (!object)
463 return E_OUTOFMEMORY;
464
465 object->ID3DXSkinInfo_iface.lpVtbl = &ID3DXSkinInfoImpl_Vtbl;
466 object->ref = 1;
467 object->num_vertices = num_vertices;
468 object->num_bones = num_bones;
469 object->vertex_declaration[0] = empty_declaration;
470 object->fvf = 0;
471
472 object->bones = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_bones * sizeof(*object->bones));
473 if (!object->bones) {
474 hr = E_OUTOFMEMORY;
475 goto error;
476 }
477
478 hr = ID3DXSkinInfoImpl_SetDeclaration(&object->ID3DXSkinInfo_iface, declaration);
479 if (FAILED(hr)) goto error;
480
481 *skin_info = &object->ID3DXSkinInfo_iface;
482
483 return D3D_OK;
484 error:
485 HeapFree(GetProcessHeap(), 0, object->bones);
486 HeapFree(GetProcessHeap(), 0, object);
487 return hr;
488 }
489
490 HRESULT WINAPI D3DXCreateSkinInfoFVF(DWORD num_vertices, DWORD fvf, DWORD num_bones, ID3DXSkinInfo **skin_info)
491 {
492 HRESULT hr;
493 D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
494
495 TRACE("(%u, %x, %u, %p)\n", num_vertices, fvf, num_bones, skin_info);
496
497 hr = D3DXDeclaratorFromFVF(fvf, declaration);
498 if (FAILED(hr))
499 return hr;
500
501 return D3DXCreateSkinInfo(num_vertices, declaration, num_bones, skin_info);
502 }