skin.c 16 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * Skin Info operations specific to D3DX9.
 *
 * Copyright (C) 2011 Dylan Smith
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

21 22 23 24
#include "config.h"
#include "wine/port.h"

#include "d3dx9_private.h"
25 26 27

WINE_DEFAULT_DEBUG_CHANNEL(d3dx);

28 29
struct bone
{
30
    char *name;
31
    D3DXMATRIX transform;
32 33 34 35 36
    DWORD num_influences;
    DWORD *vertices;
    FLOAT *weights;
};

37
struct d3dx9_skin_info
38 39 40 41 42 43 44 45
{
    ID3DXSkinInfo ID3DXSkinInfo_iface;
    LONG ref;

    DWORD fvf;
    D3DVERTEXELEMENT9 vertex_declaration[MAX_FVF_DECL_SIZE];
    DWORD num_vertices;
    DWORD num_bones;
46
    struct bone *bones;
47
};
48

49
static inline struct d3dx9_skin_info *impl_from_ID3DXSkinInfo(ID3DXSkinInfo *iface)
50
{
51
    return CONTAINING_RECORD(iface, struct d3dx9_skin_info, ID3DXSkinInfo_iface);
52 53
}

54
static HRESULT WINAPI d3dx9_skin_info_QueryInterface(ID3DXSkinInfo *iface, REFIID riid, void **out)
55
{
56
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
57 58 59 60

    if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ID3DXSkinInfo))
    {
        IUnknown_AddRef(iface);
61
        *out = iface;
62 63 64 65 66 67 68 69
        return D3D_OK;
    }

    WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));

    return E_NOINTERFACE;
}

70
static ULONG WINAPI d3dx9_skin_info_AddRef(ID3DXSkinInfo *iface)
71
{
72 73
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
    ULONG refcount = InterlockedIncrement(&skin->ref);
74

75
    TRACE("%p increasing refcount to %u.\n", skin, refcount);
76

77
    return refcount;
78 79
}

80
static ULONG WINAPI d3dx9_skin_info_Release(ID3DXSkinInfo *iface)
81
{
82 83
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
    ULONG refcount = InterlockedDecrement(&skin->ref);
84

85
    TRACE("%p decreasing refcount to %u.\n", skin, refcount);
86

87 88
    if (!refcount)
    {
89
        DWORD i;
90 91 92 93 94 95

        for (i = 0; i < skin->num_bones; ++i)
        {
            HeapFree(GetProcessHeap(), 0, skin->bones[i].name);
            HeapFree(GetProcessHeap(), 0, skin->bones[i].vertices);
            HeapFree(GetProcessHeap(), 0, skin->bones[i].weights);
96
        }
97 98
        HeapFree(GetProcessHeap(), 0, skin->bones);
        HeapFree(GetProcessHeap(), 0, skin);
99 100
    }

101
    return refcount;
102 103
}

104
static HRESULT WINAPI d3dx9_skin_info_SetBoneInfluence(ID3DXSkinInfo *iface,
Henri Verbeet's avatar
Henri Verbeet committed
105
        DWORD bone_num, DWORD num_influences, const DWORD *vertices, const float *weights)
106
{
107
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
108 109 110
    struct bone *bone;
    DWORD *new_vertices = NULL;
    FLOAT *new_weights = NULL;
111

Henri Verbeet's avatar
Henri Verbeet committed
112 113
    TRACE("iface %p, bone_num %u, num_influences %u, vertices %p, weights %p.\n",
            iface, bone_num, num_influences, vertices, weights);
114

115
    if (bone_num >= skin->num_bones || !vertices || !weights)
116 117 118 119 120 121 122 123 124 125 126 127 128 129
        return D3DERR_INVALIDCALL;

    if (num_influences) {
        new_vertices = HeapAlloc(GetProcessHeap(), 0, num_influences * sizeof(*vertices));
        if (!new_vertices)
            return E_OUTOFMEMORY;
        new_weights = HeapAlloc(GetProcessHeap(), 0, num_influences * sizeof(*weights));
        if (!new_weights) {
            HeapFree(GetProcessHeap(), 0, new_vertices);
            return E_OUTOFMEMORY;
        }
        memcpy(new_vertices, vertices, num_influences * sizeof(*vertices));
        memcpy(new_weights, weights, num_influences * sizeof(*weights));
    }
130
    bone = &skin->bones[bone_num];
131 132 133 134 135 136 137
    bone->num_influences = num_influences;
    HeapFree(GetProcessHeap(), 0, bone->vertices);
    HeapFree(GetProcessHeap(), 0, bone->weights);
    bone->vertices = new_vertices;
    bone->weights = new_weights;

    return D3D_OK;
138 139
}

140 141
static HRESULT WINAPI d3dx9_skin_info_SetBoneVertexInfluence(ID3DXSkinInfo *iface,
        DWORD bone_num, DWORD influence_num, float weight)
142
{
143 144
    FIXME("iface %p, bone_num %u, influence_num %u, weight %.8e stub!\n",
            iface, bone_num, influence_num, weight);
145 146 147 148

    return E_NOTIMPL;
}

149
static DWORD WINAPI d3dx9_skin_info_GetNumBoneInfluences(ID3DXSkinInfo *iface, DWORD bone_num)
150
{
151
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
152

153
    TRACE("iface %p, bone_num %u.\n", iface, bone_num);
154

155
    if (bone_num >= skin->num_bones)
156 157
        return 0;

158
    return skin->bones[bone_num].num_influences;
159 160
}

161 162
static HRESULT WINAPI d3dx9_skin_info_GetBoneInfluence(ID3DXSkinInfo *iface,
        DWORD bone_num, DWORD *vertices, float *weights)
163
{
164
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
165
    struct bone *bone;
166

167 168
    TRACE("iface %p, bone_num %u, vertices %p, weights %p.\n",
            iface, bone_num, vertices, weights);
169

170
    if (bone_num >= skin->num_bones || !vertices)
171 172
        return D3DERR_INVALIDCALL;

173
    bone = &skin->bones[bone_num];
174 175 176 177 178 179 180 181
    if (!bone->num_influences)
        return D3D_OK;

    memcpy(vertices, bone->vertices, bone->num_influences * sizeof(*vertices));
    if (weights)
        memcpy(weights, bone->weights, bone->num_influences * sizeof(*weights));

    return D3D_OK;
182 183
}

184 185
static HRESULT WINAPI d3dx9_skin_info_GetBoneVertexInfluence(ID3DXSkinInfo *iface,
        DWORD bone_num, DWORD influence_num, float *weight, DWORD *vertex_num)
186
{
187 188
    FIXME("iface %p, bone_num %u, influence_num %u, weight %p, vertex_num %p stub!\n",
            iface, bone_num, influence_num, weight, vertex_num);
189 190 191 192

    return E_NOTIMPL;
}

193
static HRESULT WINAPI d3dx9_skin_info_GetMaxVertexInfluences(ID3DXSkinInfo *iface, DWORD *max_vertex_influences)
194
{
195
    FIXME("iface %p, max_vertex_influences %p stub!\n", iface, max_vertex_influences);
196 197 198 199

    return E_NOTIMPL;
}

200
static DWORD WINAPI d3dx9_skin_info_GetNumBones(ID3DXSkinInfo *iface)
201
{
202
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
203

204
    TRACE("iface %p.\n", iface);
205

206
    return skin->num_bones;
207 208
}

209 210
static HRESULT WINAPI d3dx9_skin_info_FindBoneVertexInfluenceIndex(ID3DXSkinInfo *iface,
        DWORD bone_num, DWORD vertex_num, DWORD *influence_index)
211
{
212 213
    FIXME("iface %p, bone_num %u, vertex_num %u, influence_index %p stub!\n",
            iface, bone_num, vertex_num, influence_index);
214 215 216 217

    return E_NOTIMPL;
}

218
static HRESULT WINAPI d3dx9_skin_info_GetMaxFaceInfluences(struct ID3DXSkinInfo *iface,
219
        struct IDirect3DIndexBuffer9 *index_buffer, DWORD num_faces, DWORD *max_face_influences)
220
{
221 222
    FIXME("iface %p, index_buffer %p, num_faces %u, max_face_influences %p stub!\n",
            iface, index_buffer, num_faces, max_face_influences);
223 224 225 226

    return E_NOTIMPL;
}

227
static HRESULT WINAPI d3dx9_skin_info_SetMinBoneInfluence(ID3DXSkinInfo *iface, float min_influence)
228
{
229
    FIXME("iface %p, min_influence %.8e stub!\n", iface, min_influence);
230 231 232 233

    return E_NOTIMPL;
}

234
static float WINAPI d3dx9_skin_info_GetMinBoneInfluence(ID3DXSkinInfo *iface)
235
{
236
    FIXME("iface %p stub!\n", iface);
237 238 239 240

    return 0.0f;
}

241
static HRESULT WINAPI d3dx9_skin_info_SetBoneName(ID3DXSkinInfo *iface, DWORD bone_idx, const char *name)
242
{
243
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
244 245
    char *new_name;
    size_t size;
246

Henri Verbeet's avatar
Henri Verbeet committed
247
    TRACE("iface %p, bone_idx %u, name %s.\n", iface, bone_idx, debugstr_a(name));
248

249
    if (bone_idx >= skin->num_bones || !name)
250 251 252 253 254 255 256
        return D3DERR_INVALIDCALL;

    size = strlen(name) + 1;
    new_name = HeapAlloc(GetProcessHeap(), 0, size);
    if (!new_name)
        return E_OUTOFMEMORY;
    memcpy(new_name, name, size);
257 258
    HeapFree(GetProcessHeap(), 0, skin->bones[bone_idx].name);
    skin->bones[bone_idx].name = new_name;
259 260

    return D3D_OK;
261 262
}

263
static const char * WINAPI d3dx9_skin_info_GetBoneName(ID3DXSkinInfo *iface, DWORD bone_idx)
264
{
265
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
266

Henri Verbeet's avatar
Henri Verbeet committed
267
    TRACE("iface %p, bone_idx %u.\n", iface, bone_idx);
268

269
    if (bone_idx >= skin->num_bones)
270
        return NULL;
271

272
    return skin->bones[bone_idx].name;
273 274
}

275
static HRESULT WINAPI d3dx9_skin_info_SetBoneOffsetMatrix(ID3DXSkinInfo *iface,
Henri Verbeet's avatar
Henri Verbeet committed
276
        DWORD bone_num, const D3DXMATRIX *bone_transform)
277
{
278
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
279

Henri Verbeet's avatar
Henri Verbeet committed
280
    TRACE("iface %p, bone_num %u, bone_transform %p.\n", iface, bone_num, bone_transform);
281

282
    if (bone_num >= skin->num_bones || !bone_transform)
283 284
        return D3DERR_INVALIDCALL;

285
    skin->bones[bone_num].transform = *bone_transform;
286
    return D3D_OK;
287 288
}

289
static D3DXMATRIX * WINAPI d3dx9_skin_info_GetBoneOffsetMatrix(ID3DXSkinInfo *iface, DWORD bone_num)
290
{
291
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
292

293
    TRACE("iface %p, bone_num %u.\n", iface, bone_num);
294

295
    if (bone_num >= skin->num_bones)
296
        return NULL;
297

298
    return &skin->bones[bone_num].transform;
299 300
}

301
static HRESULT WINAPI d3dx9_skin_info_Clone(ID3DXSkinInfo *iface, ID3DXSkinInfo **skin_info)
302
{
303
    FIXME("iface %p, skin_info %p stub!\n", iface, skin_info);
304 305 306 307

    return E_NOTIMPL;
}

308
static HRESULT WINAPI d3dx9_skin_info_Remap(ID3DXSkinInfo *iface, DWORD num_vertices, DWORD *vertex_remap)
309
{
310
    FIXME("iface %p, num_vertices %u, vertex_remap %p stub!\n", iface, num_vertices, vertex_remap);
311 312 313 314

    return E_NOTIMPL;
}

315
static HRESULT WINAPI d3dx9_skin_info_SetFVF(ID3DXSkinInfo *iface, DWORD fvf)
316 317 318 319
{
    HRESULT hr;
    D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];

320
    TRACE("iface %p, fvf %#x.\n", iface, fvf);
321 322 323 324 325 326 327

    hr = D3DXDeclaratorFromFVF(fvf, declaration);
    if (FAILED(hr)) return hr;

    return iface->lpVtbl->SetDeclaration(iface, declaration);
}

328
static HRESULT WINAPI d3dx9_skin_info_SetDeclaration(ID3DXSkinInfo *iface, const D3DVERTEXELEMENT9 *declaration)
329
{
330
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
331 332 333
    HRESULT hr;
    int count;

Henri Verbeet's avatar
Henri Verbeet committed
334
    TRACE("iface %p, declaration %p.\n", iface, declaration);
335 336 337 338 339 340 341 342 343 344 345 346

    if (!declaration)
        return D3DERR_INVALIDCALL;
    for (count = 0; declaration[count].Stream != 0xff; count++) {
        if (declaration[count].Stream != 0) {
            WARN("Invalid vertex element %u; contains non-zero stream %u\n",
                 count, declaration[count].Stream);
            return D3DERR_INVALIDCALL;
        }
    }
    count++;

347
    memcpy(skin->vertex_declaration, declaration, count * sizeof(*declaration));
348

349 350
    if (FAILED(hr = D3DXFVFFromDeclarator(skin->vertex_declaration, &skin->fvf)))
        skin->fvf = 0;
351 352 353 354

    return D3D_OK;
}

355
static DWORD WINAPI d3dx9_skin_info_GetFVF(ID3DXSkinInfo *iface)
356
{
357
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
358

359
    TRACE("iface %p.\n", iface);
360

361
    return skin->fvf;
362 363
}

364 365
static HRESULT WINAPI d3dx9_skin_info_GetDeclaration(ID3DXSkinInfo *iface,
        D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
366
{
367
    struct d3dx9_skin_info *skin = impl_from_ID3DXSkinInfo(iface);
368 369
    UINT count = 0;

370
    TRACE("iface %p, declaration %p.\n", iface, declaration);
371

372 373
    while (skin->vertex_declaration[count++].Stream != 0xff);
    memcpy(declaration, skin->vertex_declaration, count * sizeof(declaration[0]));
374 375 376
    return D3D_OK;
}

377
static HRESULT WINAPI d3dx9_skin_info_UpdateSkinnedMesh(ID3DXSkinInfo *iface, const D3DXMATRIX *bone_transforms,
Henri Verbeet's avatar
Henri Verbeet committed
378
        const D3DXMATRIX *bone_inv_transpose_transforms, const void *src_vertices, void *dst_vertices)
379
{
Henri Verbeet's avatar
Henri Verbeet committed
380 381
    FIXME("iface %p, bone_transforms %p, bone_inv_transpose_transforms %p, src_vertices %p, dst_vertices %p stub!\n",
            iface, bone_transforms, bone_inv_transpose_transforms, src_vertices, dst_vertices);
382 383 384 385

    return E_NOTIMPL;
}

386
static HRESULT WINAPI d3dx9_skin_info_ConvertToBlendedMesh(ID3DXSkinInfo *iface, ID3DXMesh *mesh_in,
Henri Verbeet's avatar
Henri Verbeet committed
387 388 389
        DWORD options, const DWORD *adjacency_in, DWORD *adjacency_out, DWORD *face_remap,
        ID3DXBuffer **vertex_remap, DWORD *max_face_infl, DWORD *num_bone_combinations,
        ID3DXBuffer **bone_combination_table, ID3DXMesh **mesh_out)
390
{
391 392 393 394
    FIXME("iface %p, mesh_in %p, options %#x, adjacency_in %p, adjacency_out %p, face_remap %p, vertex_remap %p, "
            "max_face_infl %p, num_bone_combinations %p, bone_combination_table %p, mesh_out %p stub!\n",
            iface, mesh_in, options, adjacency_in, adjacency_out, face_remap, vertex_remap,
            max_face_infl, num_bone_combinations, bone_combination_table, mesh_out);
395 396 397 398

    return E_NOTIMPL;
}

399
static HRESULT WINAPI d3dx9_skin_info_ConvertToIndexedBlendedMesh(ID3DXSkinInfo *iface, ID3DXMesh *mesh_in,
400
        DWORD options, DWORD palette_size, const DWORD *adjacency_in, DWORD *adjacency_out, DWORD *face_remap,
Henri Verbeet's avatar
Henri Verbeet committed
401 402
        ID3DXBuffer **vertex_remap, DWORD *max_face_infl, DWORD *num_bone_combinations,
        ID3DXBuffer **bone_combination_table, ID3DXMesh **mesh_out)
403
{
404
    FIXME("iface %p, mesh_in %p, options %#x, palette_size %u, adjacency_in %p, adjacency_out %p, face_remap %p, vertex_remap %p, "
405
            "max_face_infl %p, num_bone_combinations %p, bone_combination_table %p, mesh_out %p stub!\n",
406
            iface, mesh_in, options, palette_size, adjacency_in, adjacency_out, face_remap, vertex_remap,
407
            max_face_infl, num_bone_combinations, bone_combination_table, mesh_out);
408 409 410 411

    return E_NOTIMPL;
}

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
static const struct ID3DXSkinInfoVtbl d3dx9_skin_info_vtbl =
{
    d3dx9_skin_info_QueryInterface,
    d3dx9_skin_info_AddRef,
    d3dx9_skin_info_Release,
    d3dx9_skin_info_SetBoneInfluence,
    d3dx9_skin_info_SetBoneVertexInfluence,
    d3dx9_skin_info_GetNumBoneInfluences,
    d3dx9_skin_info_GetBoneInfluence,
    d3dx9_skin_info_GetBoneVertexInfluence,
    d3dx9_skin_info_GetMaxVertexInfluences,
    d3dx9_skin_info_GetNumBones,
    d3dx9_skin_info_FindBoneVertexInfluenceIndex,
    d3dx9_skin_info_GetMaxFaceInfluences,
    d3dx9_skin_info_SetMinBoneInfluence,
    d3dx9_skin_info_GetMinBoneInfluence,
    d3dx9_skin_info_SetBoneName,
    d3dx9_skin_info_GetBoneName,
    d3dx9_skin_info_SetBoneOffsetMatrix,
    d3dx9_skin_info_GetBoneOffsetMatrix,
    d3dx9_skin_info_Clone,
    d3dx9_skin_info_Remap,
    d3dx9_skin_info_SetFVF,
    d3dx9_skin_info_SetDeclaration,
    d3dx9_skin_info_GetFVF,
    d3dx9_skin_info_GetDeclaration,
    d3dx9_skin_info_UpdateSkinnedMesh,
    d3dx9_skin_info_ConvertToBlendedMesh,
    d3dx9_skin_info_ConvertToIndexedBlendedMesh,
441 442
};

443 444
HRESULT WINAPI D3DXCreateSkinInfo(DWORD num_vertices, const D3DVERTEXELEMENT9 *declaration,
        DWORD num_bones, ID3DXSkinInfo **skin_info)
445
{
446 447
    HRESULT hr;
    static const D3DVERTEXELEMENT9 empty_declaration = D3DDECL_END();
448
    struct d3dx9_skin_info *object = NULL;
449

450 451
    TRACE("num_vertices %u, declaration %p, num_bones %u, skin_info %p.\n",
            num_vertices, declaration, num_bones, skin_info);
452 453 454 455 456 457 458 459

    if (!skin_info || !declaration)
        return D3DERR_INVALIDCALL;

    object = HeapAlloc(GetProcessHeap(), 0, sizeof(*object));
    if (!object)
        return E_OUTOFMEMORY;

460
    object->ID3DXSkinInfo_iface.lpVtbl = &d3dx9_skin_info_vtbl;
461 462 463 464 465 466
    object->ref = 1;
    object->num_vertices = num_vertices;
    object->num_bones = num_bones;
    object->vertex_declaration[0] = empty_declaration;
    object->fvf = 0;

467 468 469 470
    object->bones = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_bones * sizeof(*object->bones));
    if (!object->bones) {
        hr = E_OUTOFMEMORY;
        goto error;
471 472
    }

473 474
    if (FAILED(hr = d3dx9_skin_info_SetDeclaration(&object->ID3DXSkinInfo_iface, declaration)))
        goto error;
475

476 477 478
    *skin_info = &object->ID3DXSkinInfo_iface;

    return D3D_OK;
479 480 481 482
error:
    HeapFree(GetProcessHeap(), 0, object->bones);
    HeapFree(GetProcessHeap(), 0, object);
    return hr;
483 484
}

485
HRESULT WINAPI D3DXCreateSkinInfoFVF(DWORD num_vertices, DWORD fvf, DWORD num_bones, ID3DXSkinInfo **skin_info)
486
{
487 488
    HRESULT hr;
    D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
489

490 491 492 493 494 495 496
    TRACE("(%u, %x, %u, %p)\n", num_vertices, fvf, num_bones, skin_info);

    hr = D3DXDeclaratorFromFVF(fvf, declaration);
    if (FAILED(hr))
        return hr;

    return D3DXCreateSkinInfo(num_vertices, declaration, num_bones, skin_info);
497
}