xref: /reactos/dll/directx/wine/d3drm/meshbuilder.c (revision 845faec4)
1 /*
2  * Implementation of IDirect3DRMMeshBuilderX and IDirect3DRMMesh interfaces
3  *
4  * Copyright 2010, 2012 Christian Costa
5  * Copyright 2011 André Hentschel
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 "wine/port.h"
24 
25 #include "d3drm_private.h"
26 
27 WINE_DEFAULT_DEBUG_CHANNEL(d3drm);
28 
29 struct coords_2d
30 {
31     D3DVALUE u;
32     D3DVALUE v;
33 };
34 
35 struct mesh_material
36 {
37     D3DCOLOR color;
38     IDirect3DRMMaterial2 *material;
39     IDirect3DRMTexture3 *texture;
40 };
41 
42 char templates[] = {
43 "xof 0302txt 0064"
44 "template Header"
45 "{"
46 "<3D82AB43-62DA-11CF-AB39-0020AF71E433>"
47 "WORD major;"
48 "WORD minor;"
49 "DWORD flags;"
50 "}"
51 "template Vector"
52 "{"
53 "<3D82AB5E-62DA-11CF-AB39-0020AF71E433>"
54 "FLOAT x;"
55 "FLOAT y;"
56 "FLOAT z;"
57 "}"
58 "template Coords2d"
59 "{"
60 "<F6F23F44-7686-11CF-8F52-0040333594A3>"
61 "FLOAT u;"
62 "FLOAT v;"
63 "}"
64 "template Matrix4x4"
65 "{"
66 "<F6F23F45-7686-11CF-8F52-0040333594A3>"
67 "array FLOAT matrix[16];"
68 "}"
69 "template ColorRGBA"
70 "{"
71 "<35FF44E0-6C7C-11CF-8F52-0040333594A3>"
72 "FLOAT red;"
73 "FLOAT green;"
74 "FLOAT blue;"
75 "FLOAT alpha;"
76 "}"
77 "template ColorRGB"
78 "{"
79 "<D3E16E81-7835-11CF-8F52-0040333594A3>"
80 "FLOAT red;"
81 "FLOAT green;"
82 "FLOAT blue;"
83 "}"
84 "template IndexedColor"
85 "{"
86 "<1630B820-7842-11CF-8F52-0040333594A3>"
87 "DWORD index;"
88 "ColorRGBA indexColor;"
89 "}"
90 "template Boolean"
91 "{"
92 "<537DA6A0-CA37-11D0-941C-0080C80CFA7B>"
93 "DWORD truefalse;"
94 "}"
95 "template Boolean2d"
96 "{"
97 "<4885AE63-78E8-11CF-8F52-0040333594A3>"
98 "Boolean u;"
99 "Boolean v;"
100 "}"
101 "template MaterialWrap"
102 "{"
103 "<4885AE60-78E8-11CF-8F52-0040333594A3>"
104 "Boolean u;"
105 "Boolean v;"
106 "}"
107 "template TextureFilename"
108 "{"
109 "<A42790E1-7810-11CF-8F52-0040333594A3>"
110 "STRING filename;"
111 "}"
112 "template Material"
113 "{"
114 "<3D82AB4D-62DA-11CF-AB39-0020AF71E433>"
115 "ColorRGBA faceColor;"
116 "FLOAT power;"
117 "ColorRGB specularColor;"
118 "ColorRGB emissiveColor;"
119 "[...]"
120 "}"
121 "template MeshFace"
122 "{"
123 "<3D82AB5F-62DA-11CF-AB39-0020AF71E433>"
124 "DWORD nFaceVertexIndices;"
125 "array DWORD faceVertexIndices[nFaceVertexIndices];"
126 "}"
127 "template MeshFaceWraps"
128 "{"
129 "<ED1EC5C0-C0A8-11D0-941C-0080C80CFA7B>"
130 "DWORD nFaceWrapValues;"
131 "array Boolean2d faceWrapValues[nFaceWrapValues];"
132 "}"
133 "template MeshTextureCoords"
134 "{"
135 "<F6F23F40-7686-11CF-8F52-0040333594A3>"
136 "DWORD nTextureCoords;"
137 "array Coords2d textureCoords[nTextureCoords];"
138 "}"
139 "template MeshMaterialList"
140 "{"
141 "<F6F23F42-7686-11CF-8F52-0040333594A3>"
142 "DWORD nMaterials;"
143 "DWORD nFaceIndexes;"
144 "array DWORD faceIndexes[nFaceIndexes];"
145 "[Material]"
146 "}"
147 "template MeshNormals"
148 "{"
149 "<F6F23F43-7686-11CF-8F52-0040333594A3>"
150 "DWORD nNormals;"
151 "array Vector normals[nNormals];"
152 "DWORD nFaceNormals;"
153 "array MeshFace faceNormals[nFaceNormals];"
154 "}"
155 "template MeshVertexColors"
156 "{"
157 "<1630B821-7842-11CF-8F52-0040333594A3>"
158 "DWORD nVertexColors;"
159 "array IndexedColor vertexColors[nVertexColors];"
160 "}"
161 "template Mesh"
162 "{"
163 "<3D82AB44-62DA-11CF-AB39-0020AF71E433>"
164 "DWORD nVertices;"
165 "array Vector vertices[nVertices];"
166 "DWORD nFaces;"
167 "array MeshFace faces[nFaces];"
168 "[...]"
169 "}"
170 "template FrameTransformMatrix"
171 "{"
172 "<F6F23F41-7686-11CF-8F52-0040333594A3>"
173 "Matrix4x4 frameMatrix;"
174 "}"
175 "template Frame"
176 "{"
177 "<3D82AB46-62DA-11CF-AB39-0020AF71E433>"
178 "[...]"
179 "}"
180 "template FloatKeys"
181 "{"
182 "<10DD46A9-775B-11CF-8F52-0040333594A3>"
183 "DWORD nValues;"
184 "array FLOAT values[nValues];"
185 "}"
186 "template TimedFloatKeys"
187 "{"
188 "<F406B180-7B3B-11CF-8F52-0040333594A3>"
189 "DWORD time;"
190 "FloatKeys tfkeys;"
191 "}"
192 "template AnimationKey"
193 "{"
194 "<10DD46A8-775B-11CF-8F52-0040333594A3>"
195 "DWORD keyType;"
196 "DWORD nKeys;"
197 "array TimedFloatKeys keys[nKeys];"
198 "}"
199 "template AnimationOptions"
200 "{"
201 "<E2BF56C0-840F-11CF-8F52-0040333594A3>"
202 "DWORD openclosed;"
203 "DWORD positionquality;"
204 "}"
205 "template Animation"
206 "{"
207 "<3D82AB4F-62DA-11CF-AB39-0020AF71E433>"
208 "[...]"
209 "}"
210 "template AnimationSet"
211 "{"
212 "<3D82AB50-62DA-11CF-AB39-0020AF71E433>"
213 "[Animation]"
214 "}"
215 "template InlineData"
216 "{"
217 "<3A23EEA0-94B1-11D0-AB39-0020AF71E433>"
218 "[BINARY]"
219 "}"
220 "template Url"
221 "{"
222 "<3A23EEA1-94B1-11D0-AB39-0020AF71E433>"
223 "DWORD nUrls;"
224 "array STRING urls[nUrls];"
225 "}"
226 "template ProgressiveMesh"
227 "{"
228 "<8A63C360-997D-11D0-941C-0080C80CFA7B>"
229 "[Url,InlineData]"
230 "}"
231 "template Guid"
232 "{"
233 "<A42790E0-7810-11CF-8F52-0040333594A3>"
234 "DWORD data1;"
235 "WORD data2;"
236 "WORD data3;"
237 "array UCHAR data4[8];"
238 "}"
239 "template StringProperty"
240 "{"
241 "<7F0F21E0-BFE1-11D1-82C0-00A0C9697271>"
242 "STRING key;"
243 "STRING value;"
244 "}"
245 "template PropertyBag"
246 "{"
247 "<7F0F21E1-BFE1-11D1-82C0-00A0C9697271>"
248 "[StringProperty]"
249 "}"
250 "template ExternalVisual"
251 "{"
252 "<98116AA0-BDBA-11D1-82C0-00A0C9697271>"
253 "Guid guidExternalVisual;"
254 "[...]"
255 "}"
256 "template RightHanded"
257 "{"
258 "<7F5D5EA0-D53A-11D1-82C0-00A0C9697271>"
259 "DWORD bRightHanded;"
260 "}"
261 };
262 
263 BOOL d3drm_array_reserve(void **elements, SIZE_T *capacity, SIZE_T element_count, SIZE_T element_size)
264 {
265     SIZE_T new_capacity, max_capacity;
266     void *new_elements;
267 
268     if (element_count <= *capacity)
269         return TRUE;
270 
271     max_capacity = ~(SIZE_T)0 / element_size;
272     if (max_capacity < element_count)
273         return FALSE;
274 
275     new_capacity = max(*capacity, 4);
276     while (new_capacity < element_count && new_capacity <= max_capacity / 2)
277         new_capacity *= 2;
278 
279     if (new_capacity < element_count)
280         new_capacity = max_capacity;
281 
282     if (!(new_elements = heap_realloc(*elements, new_capacity * element_size)))
283         return FALSE;
284 
285     *elements = new_elements;
286     *capacity = new_capacity;
287     return TRUE;
288 }
289 
290 static inline struct d3drm_mesh *impl_from_IDirect3DRMMesh(IDirect3DRMMesh *iface)
291 {
292     return CONTAINING_RECORD(iface, struct d3drm_mesh, IDirect3DRMMesh_iface);
293 }
294 
295 static inline struct d3drm_mesh_builder *impl_from_IDirect3DRMMeshBuilder2(IDirect3DRMMeshBuilder2 *iface)
296 {
297     return CONTAINING_RECORD(iface, struct d3drm_mesh_builder, IDirect3DRMMeshBuilder2_iface);
298 }
299 
300 static inline struct d3drm_mesh_builder *impl_from_IDirect3DRMMeshBuilder3(IDirect3DRMMeshBuilder3 *iface)
301 {
302     return CONTAINING_RECORD(iface, struct d3drm_mesh_builder, IDirect3DRMMeshBuilder3_iface);
303 }
304 
305 static inline struct d3drm_wrap *impl_from_IDirect3DRMWrap(IDirect3DRMWrap *iface)
306 {
307     return CONTAINING_RECORD(iface, struct d3drm_wrap, IDirect3DRMWrap_iface);
308 }
309 
310 static void clean_mesh_builder_data(struct d3drm_mesh_builder *mesh_builder)
311 {
312     DWORD i;
313 
314     IDirect3DRMMeshBuilder3_SetName(&mesh_builder->IDirect3DRMMeshBuilder3_iface, NULL);
315     heap_free(mesh_builder->vertices);
316     mesh_builder->vertices = NULL;
317     mesh_builder->nb_vertices = 0;
318     mesh_builder->vertices_size = 0;
319     heap_free(mesh_builder->normals);
320     mesh_builder->normals = NULL;
321     mesh_builder->nb_normals = 0;
322     mesh_builder->normals_size = 0;
323     heap_free(mesh_builder->pFaceData);
324     mesh_builder->pFaceData = NULL;
325     mesh_builder->face_data_size = 0;
326     mesh_builder->nb_faces = 0;
327     heap_free(mesh_builder->pCoords2d);
328     mesh_builder->pCoords2d = NULL;
329     mesh_builder->nb_coords2d = 0;
330     for (i = 0; i < mesh_builder->nb_materials; i++)
331     {
332         if (mesh_builder->materials[i].material)
333             IDirect3DRMMaterial2_Release(mesh_builder->materials[i].material);
334         if (mesh_builder->materials[i].texture)
335             IDirect3DRMTexture3_Release(mesh_builder->materials[i].texture);
336     }
337     mesh_builder->nb_materials = 0;
338     heap_free(mesh_builder->materials);
339     mesh_builder->materials = NULL;
340     heap_free(mesh_builder->material_indices);
341     mesh_builder->material_indices = NULL;
342 }
343 
344 static HRESULT WINAPI d3drm_mesh_builder2_QueryInterface(IDirect3DRMMeshBuilder2 *iface, REFIID riid, void **out)
345 {
346     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
347 
348     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
349 
350     if (IsEqualGUID(riid, &IID_IDirect3DRMMeshBuilder2)
351             || IsEqualGUID(riid, &IID_IDirect3DRMMeshBuilder)
352             || IsEqualGUID(riid, &IID_IDirect3DRMVisual)
353             || IsEqualGUID(riid, &IID_IDirect3DRMObject)
354             || IsEqualGUID(riid, &IID_IUnknown))
355     {
356         *out = &mesh_builder->IDirect3DRMMeshBuilder2_iface;
357     }
358     else if (IsEqualGUID(riid, &IID_IDirect3DRMMeshBuilder3))
359     {
360         *out = &mesh_builder->IDirect3DRMMeshBuilder3_iface;
361     }
362     else
363     {
364         *out = NULL;
365         WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
366         return E_NOINTERFACE;
367     }
368 
369     IUnknown_AddRef((IUnknown *)*out);
370     return S_OK;
371 }
372 
373 static ULONG WINAPI d3drm_mesh_builder2_AddRef(IDirect3DRMMeshBuilder2 *iface)
374 {
375     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
376     ULONG refcount = InterlockedIncrement(&mesh_builder->ref);
377 
378     TRACE("%p increasing refcount to %u.\n", mesh_builder, refcount);
379 
380     return refcount;
381 }
382 
383 static ULONG WINAPI d3drm_mesh_builder2_Release(IDirect3DRMMeshBuilder2 *iface)
384 {
385     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
386     ULONG refcount = InterlockedDecrement(&mesh_builder->ref);
387 
388     TRACE("%p decreasing refcount to %u.\n", mesh_builder, refcount);
389 
390     if (!refcount)
391     {
392         d3drm_object_cleanup((IDirect3DRMObject *)iface, &mesh_builder->obj);
393         clean_mesh_builder_data(mesh_builder);
394         if (mesh_builder->material)
395             IDirect3DRMMaterial2_Release(mesh_builder->material);
396         if (mesh_builder->texture)
397             IDirect3DRMTexture3_Release(mesh_builder->texture);
398         IDirect3DRM_Release(mesh_builder->d3drm);
399         heap_free(mesh_builder);
400     }
401 
402     return refcount;
403 }
404 
405 static HRESULT WINAPI d3drm_mesh_builder2_Clone(IDirect3DRMMeshBuilder2 *iface,
406         IUnknown *outer, REFIID iid, void **out)
407 {
408     FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
409 
410     return E_NOTIMPL;
411 }
412 
413 static HRESULT WINAPI d3drm_mesh_builder2_AddDestroyCallback(IDirect3DRMMeshBuilder2 *iface,
414         D3DRMOBJECTCALLBACK cb, void *ctx)
415 {
416     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
417 
418     TRACE("iface %p, cb %p, ctx %p.\n", iface, cb, ctx);
419 
420     return IDirect3DRMMeshBuilder3_AddDestroyCallback(&mesh_builder->IDirect3DRMMeshBuilder3_iface, cb, ctx);
421 }
422 
423 static HRESULT WINAPI d3drm_mesh_builder2_DeleteDestroyCallback(IDirect3DRMMeshBuilder2 *iface,
424         D3DRMOBJECTCALLBACK cb, void *ctx)
425 {
426     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
427 
428     TRACE("iface %p, cb %p, ctx %p.\n", iface, cb, ctx);
429 
430     return IDirect3DRMMeshBuilder3_DeleteDestroyCallback(&mesh_builder->IDirect3DRMMeshBuilder3_iface, cb, ctx);
431 }
432 
433 static HRESULT WINAPI d3drm_mesh_builder3_SetAppData(IDirect3DRMMeshBuilder3 *iface, DWORD data)
434 {
435     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
436 
437     TRACE("iface %p, data %#x.\n", iface, data);
438 
439     mesh_builder->obj.appdata = data;
440 
441     return D3DRM_OK;
442 }
443 
444 static HRESULT WINAPI d3drm_mesh_builder2_SetAppData(IDirect3DRMMeshBuilder2 *iface, DWORD data)
445 {
446     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
447 
448     TRACE("iface %p, data %#x.\n", iface, data);
449 
450     return d3drm_mesh_builder3_SetAppData(&mesh_builder->IDirect3DRMMeshBuilder3_iface, data);
451 }
452 
453 static DWORD WINAPI d3drm_mesh_builder3_GetAppData(IDirect3DRMMeshBuilder3 *iface)
454 {
455     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
456 
457     TRACE("iface %p.\n", iface);
458 
459     return mesh_builder->obj.appdata;
460 }
461 
462 static DWORD WINAPI d3drm_mesh_builder2_GetAppData(IDirect3DRMMeshBuilder2 *iface)
463 {
464     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
465 
466     TRACE("iface %p.\n", iface);
467 
468     return d3drm_mesh_builder3_GetAppData(&mesh_builder->IDirect3DRMMeshBuilder3_iface);
469 }
470 
471 static HRESULT WINAPI d3drm_mesh_builder2_SetName(IDirect3DRMMeshBuilder2 *iface, const char *name)
472 {
473     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
474 
475     TRACE("iface %p, name %s.\n", iface, debugstr_a(name));
476 
477     return IDirect3DRMMeshBuilder3_SetName(&mesh_builder->IDirect3DRMMeshBuilder3_iface, name);
478 }
479 
480 static HRESULT WINAPI d3drm_mesh_builder2_GetName(IDirect3DRMMeshBuilder2 *iface, DWORD *size, char *name)
481 {
482     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
483 
484     TRACE("iface %p, size %p, name %p.\n", iface, size, name);
485 
486     return IDirect3DRMMeshBuilder3_GetName(&mesh_builder->IDirect3DRMMeshBuilder3_iface, size, name);
487 }
488 
489 static HRESULT WINAPI d3drm_mesh_builder2_GetClassName(IDirect3DRMMeshBuilder2 *iface, DWORD *size, char *name)
490 {
491     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
492 
493     TRACE("iface %p, size %p, name %p.\n", iface, size, name);
494 
495     return IDirect3DRMMeshBuilder3_GetClassName(&mesh_builder->IDirect3DRMMeshBuilder3_iface, size, name);
496 }
497 
498 static HRESULT WINAPI d3drm_mesh_builder2_Load(IDirect3DRMMeshBuilder2 *iface, void *filename,
499         void *name, D3DRMLOADOPTIONS flags, D3DRMLOADTEXTURECALLBACK cb, void *ctx)
500 {
501     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
502 
503     TRACE("iface %p, filename %p, name %p, flags %#x, cb %p, ctx %p.\n",
504             iface, filename, name, flags, cb, ctx);
505 
506     if (cb)
507         FIXME("Texture callback is not yet supported\n");
508 
509     return IDirect3DRMMeshBuilder3_Load(&mesh_builder->IDirect3DRMMeshBuilder3_iface,
510             filename, name, flags, NULL, ctx);
511 }
512 
513 static HRESULT WINAPI d3drm_mesh_builder2_Save(IDirect3DRMMeshBuilder2 *iface,
514         const char *filename, D3DRMXOFFORMAT format, D3DRMSAVEOPTIONS flags)
515 {
516     FIXME("iface %p, filename %s, format %#x, flags %#x stub!\n",
517             iface, debugstr_a(filename), format, flags);
518 
519     return E_NOTIMPL;
520 }
521 
522 static HRESULT WINAPI d3drm_mesh_builder2_Scale(IDirect3DRMMeshBuilder2 *iface,
523         D3DVALUE sx, D3DVALUE sy, D3DVALUE sz)
524 {
525     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
526 
527     TRACE("iface %p, sx %.8e, sy %.8e, sz %.8e.\n", iface, sx, sy, sz);
528 
529     return IDirect3DRMMeshBuilder3_Scale(&mesh_builder->IDirect3DRMMeshBuilder3_iface, sx, sy, sz);
530 }
531 
532 static HRESULT WINAPI d3drm_mesh_builder2_Translate(IDirect3DRMMeshBuilder2 *iface,
533         D3DVALUE tx, D3DVALUE ty, D3DVALUE tz)
534 {
535     FIXME("iface %p, tx %.8e, ty %.8e, tz %.8e stub!\n", iface, tx, ty, tz);
536 
537     return E_NOTIMPL;
538 }
539 
540 static HRESULT WINAPI d3drm_mesh_builder2_SetColorSource(IDirect3DRMMeshBuilder2 *iface, D3DRMCOLORSOURCE source)
541 {
542     FIXME("iface %p, source %#x stub!\n", iface, source);
543 
544     return E_NOTIMPL;
545 }
546 
547 static HRESULT WINAPI d3drm_mesh_builder2_GetBox(IDirect3DRMMeshBuilder2 *iface, D3DRMBOX *box)
548 {
549     FIXME("iface %p, box %p stub!\n", iface, box);
550 
551     return E_NOTIMPL;
552 }
553 
554 static HRESULT WINAPI d3drm_mesh_builder2_GenerateNormals(IDirect3DRMMeshBuilder2 *iface)
555 {
556     FIXME("iface %p stub!\n", iface);
557 
558     return E_NOTIMPL;
559 }
560 
561 static D3DRMCOLORSOURCE WINAPI d3drm_mesh_builder2_GetColorSource(IDirect3DRMMeshBuilder2 *iface)
562 {
563     FIXME("iface %p stub!\n", iface);
564 
565     return E_NOTIMPL;
566 }
567 
568 static HRESULT WINAPI d3drm_mesh_builder2_AddMesh(IDirect3DRMMeshBuilder2 *iface, IDirect3DRMMesh *mesh)
569 {
570     FIXME("iface %p, mesh %p stub!\n", iface, mesh);
571 
572     return E_NOTIMPL;
573 }
574 
575 static HRESULT WINAPI d3drm_mesh_builder2_AddMeshBuilder(IDirect3DRMMeshBuilder2 *iface,
576         IDirect3DRMMeshBuilder *mesh_builder)
577 {
578     FIXME("iface %p, mesh_builder %p stub!\n", iface, mesh_builder);
579 
580     return E_NOTIMPL;
581 }
582 
583 static HRESULT WINAPI d3drm_mesh_builder2_AddFrame(IDirect3DRMMeshBuilder2 *iface, IDirect3DRMFrame *frame)
584 {
585     FIXME("iface %p, frame %p stub!\n", iface, frame);
586 
587     return E_NOTIMPL;
588 }
589 
590 static HRESULT WINAPI d3drm_mesh_builder2_AddFace(IDirect3DRMMeshBuilder2 *iface, IDirect3DRMFace *face)
591 {
592     FIXME("iface %p, face %p stub!\n", iface, face);
593 
594     return E_NOTIMPL;
595 }
596 
597 static HRESULT WINAPI d3drm_mesh_builder2_AddFaces(IDirect3DRMMeshBuilder2 *iface,
598         DWORD vertex_count, D3DVECTOR *vertices, DWORD normal_count, D3DVECTOR *normals,
599         DWORD *face_data, IDirect3DRMFaceArray **array)
600 {
601     FIXME("iface %p, vertex_count %u, vertices %p, normal_count %u, normals %p, face_data %p, array %p stub!\n",
602             iface, vertex_count, vertices, normal_count, normals, face_data, array);
603 
604     return E_NOTIMPL;
605 }
606 
607 static HRESULT WINAPI d3drm_mesh_builder2_ReserveSpace(IDirect3DRMMeshBuilder2 *iface,
608         DWORD vertex_count, DWORD normal_count, DWORD face_count)
609 {
610     FIXME("iface %p, vertex_count %u, normal_count %u, face_count %u stub!\n",
611             iface, vertex_count, normal_count, face_count);
612 
613     return E_NOTIMPL;
614 }
615 
616 static HRESULT WINAPI d3drm_mesh_builder2_SetColorRGB(IDirect3DRMMeshBuilder2 *iface,
617         D3DVALUE red, D3DVALUE green, D3DVALUE blue)
618 {
619     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
620 
621     TRACE("iface %p, red %.8e, green %.8e, blue %.8e.\n", iface, red, green, blue);
622 
623     return IDirect3DRMMeshBuilder3_SetColorRGB(&mesh_builder->IDirect3DRMMeshBuilder3_iface, red, green, blue);
624 }
625 
626 static HRESULT WINAPI d3drm_mesh_builder2_SetColor(IDirect3DRMMeshBuilder2 *iface, D3DCOLOR color)
627 {
628     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
629 
630     TRACE("iface %p, color 0x%08x.\n", iface, color);
631 
632     return IDirect3DRMMeshBuilder3_SetColor(&mesh_builder->IDirect3DRMMeshBuilder3_iface, color);
633 }
634 
635 static HRESULT WINAPI d3drm_mesh_builder2_SetTexture(IDirect3DRMMeshBuilder2 *iface,
636         IDirect3DRMTexture *texture)
637 {
638     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
639     IDirect3DRMTexture3 *texture3 = NULL;
640     HRESULT hr = D3DRM_OK;
641 
642     TRACE("iface %p, texture %p.\n", iface, texture);
643 
644     if (texture)
645         hr = IDirect3DRMTexture_QueryInterface(texture, &IID_IDirect3DRMTexture3, (void **)&texture3);
646     if (SUCCEEDED(hr))
647         hr = IDirect3DRMMeshBuilder3_SetTexture(&mesh_builder->IDirect3DRMMeshBuilder3_iface, texture3);
648     if (texture3)
649         IDirect3DRMTexture3_Release(texture3);
650 
651     return hr;
652 }
653 
654 static HRESULT WINAPI d3drm_mesh_builder2_SetMaterial(IDirect3DRMMeshBuilder2 *iface,
655         IDirect3DRMMaterial *material)
656 {
657     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
658 
659     TRACE("iface %p, material %p.\n", iface, material);
660 
661     return IDirect3DRMMeshBuilder3_SetMaterial(&mesh_builder->IDirect3DRMMeshBuilder3_iface,
662             (IDirect3DRMMaterial2 *)material);
663 }
664 
665 static HRESULT WINAPI d3drm_mesh_builder2_SetTextureTopology(IDirect3DRMMeshBuilder2 *iface,
666         BOOL wrap_u, BOOL wrap_v)
667 {
668     FIXME("iface %p, wrap_u %#x, wrap_v %#x stub!\n", iface, wrap_u, wrap_v);
669 
670     return E_NOTIMPL;
671 }
672 
673 static HRESULT WINAPI d3drm_mesh_builder2_SetQuality(IDirect3DRMMeshBuilder2 *iface,
674         D3DRMRENDERQUALITY quality)
675 {
676     FIXME("iface %p, quality %#x stub!\n", iface, quality);
677 
678     return E_NOTIMPL;
679 }
680 
681 static HRESULT WINAPI d3drm_mesh_builder2_SetPerspective(IDirect3DRMMeshBuilder2 *iface, BOOL enable)
682 {
683     FIXME("iface %p, enable %#x stub!\n", iface, enable);
684 
685     return E_NOTIMPL;
686 }
687 
688 static HRESULT WINAPI d3drm_mesh_builder2_SetVertex(IDirect3DRMMeshBuilder2 *iface,
689         DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z)
690 {
691     FIXME("iface %p, index %u, x %.8e, y %.8e, z %.8e stub!\n", iface, index, x, y, z);
692 
693     return E_NOTIMPL;
694 }
695 
696 static HRESULT WINAPI d3drm_mesh_builder2_SetNormal(IDirect3DRMMeshBuilder2 *iface,
697         DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z)
698 {
699     FIXME("iface %p, index %u, x %.8e, y %.8e, z %.8e stub!\n", iface, index, x, y, z);
700 
701     return E_NOTIMPL;
702 }
703 
704 static HRESULT WINAPI d3drm_mesh_builder2_SetTextureCoordinates(IDirect3DRMMeshBuilder2 *iface,
705         DWORD index, D3DVALUE u, D3DVALUE v)
706 {
707     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
708 
709     TRACE("iface %p, index %u, u %.8e, v %.8e.\n", iface, index, u, v);
710 
711     return IDirect3DRMMeshBuilder3_SetTextureCoordinates(&mesh_builder->IDirect3DRMMeshBuilder3_iface,
712             index, u, v);
713 }
714 
715 static HRESULT WINAPI d3drm_mesh_builder2_SetVertexColor(IDirect3DRMMeshBuilder2 *iface,
716         DWORD index, D3DCOLOR color)
717 {
718     FIXME("iface %p, index %u, color 0x%08x stub!\n", iface, index, color);
719 
720     return E_NOTIMPL;
721 }
722 
723 static HRESULT WINAPI d3drm_mesh_builder2_SetVertexColorRGB(IDirect3DRMMeshBuilder2 *iface,
724         DWORD index, D3DVALUE red, D3DVALUE green, D3DVALUE blue)
725 {
726     FIXME("iface %p, index %u, red %.8e, green %.8e, blue %.8e stub!\n",
727             iface, index, red, green, blue);
728 
729     return E_NOTIMPL;
730 }
731 
732 static HRESULT WINAPI d3drm_mesh_builder2_GetFaces(IDirect3DRMMeshBuilder2 *iface,
733         IDirect3DRMFaceArray **array)
734 {
735     FIXME("iface %p, array %p stub!\n", iface, array);
736 
737     return E_NOTIMPL;
738 }
739 
740 static HRESULT WINAPI d3drm_mesh_builder2_GetVertices(IDirect3DRMMeshBuilder2 *iface,
741         DWORD *vertex_count, D3DVECTOR *vertices, DWORD *normal_count, D3DVECTOR *normals,
742         DWORD *face_data_size, DWORD *face_data)
743 {
744     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
745 
746     TRACE("iface %p, vertex_count %p, vertices %p, normal_count %p, normals %p, face_data_size %p, face_data %p.\n",
747             iface, vertex_count, vertices, normal_count, normals, face_data_size, face_data);
748 
749     if (vertices && (!vertex_count || (*vertex_count < mesh_builder->nb_vertices)))
750         return D3DRMERR_BADVALUE;
751     if (vertex_count)
752         *vertex_count = mesh_builder->nb_vertices;
753     if (vertices && mesh_builder->nb_vertices)
754         memcpy(vertices, mesh_builder->vertices, mesh_builder->nb_vertices * sizeof(*vertices));
755 
756     if (normals && (!normal_count || (*normal_count < mesh_builder->nb_normals)))
757         return D3DRMERR_BADVALUE;
758     if (normal_count)
759         *normal_count = mesh_builder->nb_normals;
760     if (normals && mesh_builder->nb_normals)
761         memcpy(normals, mesh_builder->normals, mesh_builder->nb_normals * sizeof(*normals));
762 
763     if (face_data && (!face_data_size || (*face_data_size < mesh_builder->face_data_size)))
764         return D3DRMERR_BADVALUE;
765     if (face_data_size)
766         *face_data_size = mesh_builder->face_data_size;
767     if (face_data && mesh_builder->face_data_size)
768         memcpy(face_data, mesh_builder->pFaceData, mesh_builder->face_data_size * sizeof(*face_data));
769 
770     return D3DRM_OK;
771 }
772 
773 static HRESULT WINAPI d3drm_mesh_builder2_GetTextureCoordinates(IDirect3DRMMeshBuilder2 *iface,
774         DWORD index, D3DVALUE *u, D3DVALUE *v)
775 {
776     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
777 
778     TRACE("iface %p, index %u, u %p, v %p.\n", iface, index, u, v);
779 
780     return IDirect3DRMMeshBuilder3_GetTextureCoordinates(&mesh_builder->IDirect3DRMMeshBuilder3_iface,
781             index, u, v);
782 }
783 
784 static int WINAPI d3drm_mesh_builder2_AddVertex(IDirect3DRMMeshBuilder2 *iface,
785         D3DVALUE x, D3DVALUE y, D3DVALUE z)
786 {
787     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
788 
789     TRACE("iface %p, x %.8e, y %.8e, z %.8e.\n", iface, x, y, z);
790 
791     return IDirect3DRMMeshBuilder3_AddVertex(&mesh_builder->IDirect3DRMMeshBuilder3_iface, x, y, z);
792 }
793 
794 static int WINAPI d3drm_mesh_builder2_AddNormal(IDirect3DRMMeshBuilder2 *iface,
795         D3DVALUE x, D3DVALUE y, D3DVALUE z)
796 {
797     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
798 
799     TRACE("iface %p, x %.8e, y %.8e, z %.8e.\n", iface, x, y, z);
800 
801     return IDirect3DRMMeshBuilder3_AddNormal(&mesh_builder->IDirect3DRMMeshBuilder3_iface, x, y, z);
802 }
803 
804 static HRESULT WINAPI d3drm_mesh_builder2_CreateFace(IDirect3DRMMeshBuilder2 *iface, IDirect3DRMFace **face)
805 {
806     struct d3drm_face *object;
807     HRESULT hr;
808 
809     TRACE("iface %p, face %p.\n", iface, face);
810 
811     if (FAILED(hr = d3drm_face_create(&object)))
812         return hr;
813 
814     *face = &object->IDirect3DRMFace_iface;
815 
816     return S_OK;
817 }
818 
819 static D3DRMRENDERQUALITY WINAPI d3drm_mesh_builder2_GetQuality(IDirect3DRMMeshBuilder2 *iface)
820 {
821     FIXME("iface %p stub!\n", iface);
822 
823     return 0;
824 }
825 
826 static BOOL WINAPI d3drm_mesh_builder2_GetPerspective(IDirect3DRMMeshBuilder2 *iface)
827 {
828     FIXME("iface %p stub!\n", iface);
829 
830     return FALSE;
831 }
832 
833 static int WINAPI d3drm_mesh_builder2_GetFaceCount(IDirect3DRMMeshBuilder2 *iface)
834 {
835     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
836 
837     TRACE("iface %p.\n", iface);
838 
839     return mesh_builder->nb_faces;
840 }
841 
842 static int WINAPI d3drm_mesh_builder2_GetVertexCount(IDirect3DRMMeshBuilder2 *iface)
843 {
844     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
845 
846     TRACE("iface %p.\n", iface);
847 
848     return mesh_builder->nb_vertices;
849 }
850 
851 static D3DCOLOR WINAPI d3drm_mesh_builder2_GetVertexColor(IDirect3DRMMeshBuilder2 *iface, DWORD index)
852 {
853     FIXME("iface %p, index %u stub!\n", iface, index);
854 
855     return 0;
856 }
857 
858 static HRESULT WINAPI d3drm_mesh_builder2_CreateMesh(IDirect3DRMMeshBuilder2 *iface, IDirect3DRMMesh **mesh)
859 {
860     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
861 
862     TRACE("iface %p, mesh %p.\n", iface, mesh);
863 
864     return IDirect3DRMMeshBuilder3_CreateMesh(&mesh_builder->IDirect3DRMMeshBuilder3_iface, mesh);
865 }
866 
867 static HRESULT WINAPI d3drm_mesh_builder2_GenerateNormals2(IDirect3DRMMeshBuilder2 *iface,
868         D3DVALUE crease, DWORD flags)
869 {
870     FIXME("iface %p, crease %.8e, flags %#x stub!\n", iface, crease, flags);
871 
872     return E_NOTIMPL;
873 }
874 
875 static HRESULT WINAPI d3drm_mesh_builder2_GetFace(IDirect3DRMMeshBuilder2 *iface,
876         DWORD index, IDirect3DRMFace **face)
877 {
878     FIXME("iface %p, index %u, face %p stub!\n", iface, index, face);
879 
880     return E_NOTIMPL;
881 }
882 
883 static const struct IDirect3DRMMeshBuilder2Vtbl d3drm_mesh_builder2_vtbl =
884 {
885     d3drm_mesh_builder2_QueryInterface,
886     d3drm_mesh_builder2_AddRef,
887     d3drm_mesh_builder2_Release,
888     d3drm_mesh_builder2_Clone,
889     d3drm_mesh_builder2_AddDestroyCallback,
890     d3drm_mesh_builder2_DeleteDestroyCallback,
891     d3drm_mesh_builder2_SetAppData,
892     d3drm_mesh_builder2_GetAppData,
893     d3drm_mesh_builder2_SetName,
894     d3drm_mesh_builder2_GetName,
895     d3drm_mesh_builder2_GetClassName,
896     d3drm_mesh_builder2_Load,
897     d3drm_mesh_builder2_Save,
898     d3drm_mesh_builder2_Scale,
899     d3drm_mesh_builder2_Translate,
900     d3drm_mesh_builder2_SetColorSource,
901     d3drm_mesh_builder2_GetBox,
902     d3drm_mesh_builder2_GenerateNormals,
903     d3drm_mesh_builder2_GetColorSource,
904     d3drm_mesh_builder2_AddMesh,
905     d3drm_mesh_builder2_AddMeshBuilder,
906     d3drm_mesh_builder2_AddFrame,
907     d3drm_mesh_builder2_AddFace,
908     d3drm_mesh_builder2_AddFaces,
909     d3drm_mesh_builder2_ReserveSpace,
910     d3drm_mesh_builder2_SetColorRGB,
911     d3drm_mesh_builder2_SetColor,
912     d3drm_mesh_builder2_SetTexture,
913     d3drm_mesh_builder2_SetMaterial,
914     d3drm_mesh_builder2_SetTextureTopology,
915     d3drm_mesh_builder2_SetQuality,
916     d3drm_mesh_builder2_SetPerspective,
917     d3drm_mesh_builder2_SetVertex,
918     d3drm_mesh_builder2_SetNormal,
919     d3drm_mesh_builder2_SetTextureCoordinates,
920     d3drm_mesh_builder2_SetVertexColor,
921     d3drm_mesh_builder2_SetVertexColorRGB,
922     d3drm_mesh_builder2_GetFaces,
923     d3drm_mesh_builder2_GetVertices,
924     d3drm_mesh_builder2_GetTextureCoordinates,
925     d3drm_mesh_builder2_AddVertex,
926     d3drm_mesh_builder2_AddNormal,
927     d3drm_mesh_builder2_CreateFace,
928     d3drm_mesh_builder2_GetQuality,
929     d3drm_mesh_builder2_GetPerspective,
930     d3drm_mesh_builder2_GetFaceCount,
931     d3drm_mesh_builder2_GetVertexCount,
932     d3drm_mesh_builder2_GetVertexColor,
933     d3drm_mesh_builder2_CreateMesh,
934     d3drm_mesh_builder2_GenerateNormals2,
935     d3drm_mesh_builder2_GetFace,
936 };
937 
938 static HRESULT WINAPI d3drm_mesh_builder3_QueryInterface(IDirect3DRMMeshBuilder3 *iface, REFIID riid, void **out)
939 {
940     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
941 
942     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
943 
944     return d3drm_mesh_builder2_QueryInterface(&mesh_builder->IDirect3DRMMeshBuilder2_iface, riid, out);
945 }
946 
947 static ULONG WINAPI d3drm_mesh_builder3_AddRef(IDirect3DRMMeshBuilder3 *iface)
948 {
949     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
950 
951     TRACE("iface %p.\n", iface);
952 
953     return d3drm_mesh_builder2_AddRef(&mesh_builder->IDirect3DRMMeshBuilder2_iface);
954 }
955 
956 static ULONG WINAPI d3drm_mesh_builder3_Release(IDirect3DRMMeshBuilder3 *iface)
957 {
958     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
959 
960     TRACE("iface %p.\n", iface);
961 
962     return d3drm_mesh_builder2_Release(&mesh_builder->IDirect3DRMMeshBuilder2_iface);
963 }
964 
965 static HRESULT WINAPI d3drm_mesh_builder3_Clone(IDirect3DRMMeshBuilder3 *iface,
966         IUnknown *outer, REFIID iid, void **out)
967 {
968     FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
969 
970     return E_NOTIMPL;
971 }
972 
973 static HRESULT WINAPI d3drm_mesh_builder3_AddDestroyCallback(IDirect3DRMMeshBuilder3 *iface,
974         D3DRMOBJECTCALLBACK cb, void *ctx)
975 {
976     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
977 
978     TRACE("iface %p, cb %p, ctx %p.\n", iface, cb, ctx);
979 
980     return d3drm_object_add_destroy_callback(&mesh_builder->obj, cb, ctx);
981 }
982 
983 static HRESULT WINAPI d3drm_mesh_builder3_DeleteDestroyCallback(IDirect3DRMMeshBuilder3 *iface,
984         D3DRMOBJECTCALLBACK cb, void *ctx)
985 {
986     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
987 
988     TRACE("iface %p, cb %p, ctx %p.\n", iface, cb, ctx);
989 
990     return d3drm_object_delete_destroy_callback(&mesh_builder->obj, cb, ctx);
991 }
992 
993 static HRESULT WINAPI d3drm_mesh_builder3_SetName(IDirect3DRMMeshBuilder3 *iface, const char *name)
994 {
995     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
996 
997     TRACE("iface %p, name %s.\n", iface, debugstr_a(name));
998 
999     return d3drm_object_set_name(&mesh_builder->obj, name);
1000 }
1001 
1002 static HRESULT WINAPI d3drm_mesh_builder3_GetName(IDirect3DRMMeshBuilder3 *iface,
1003         DWORD *size, char *name)
1004 {
1005     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1006 
1007     TRACE("iface %p, size %p, name %p.\n", iface, size, name);
1008 
1009     return d3drm_object_get_name(&mesh_builder->obj, size, name);
1010 }
1011 
1012 static HRESULT WINAPI d3drm_mesh_builder3_GetClassName(IDirect3DRMMeshBuilder3 *iface,
1013         DWORD *size, char *name)
1014 {
1015     struct d3drm_mesh_builder *meshbuilder = impl_from_IDirect3DRMMeshBuilder3(iface);
1016 
1017     TRACE("iface %p, size %p, name %p.\n", iface, size, name);
1018 
1019     return d3drm_object_get_class_name(&meshbuilder->obj, size, name);
1020 }
1021 
1022 HRESULT load_mesh_data(IDirect3DRMMeshBuilder3 *iface, IDirectXFileData *pData,
1023         D3DRMLOADTEXTURECALLBACK load_texture_proc, void *arg)
1024 {
1025     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1026     IDirectXFileData *pData2 = NULL;
1027     const GUID* guid;
1028     DWORD size;
1029     BYTE *ptr;
1030     HRESULT hr;
1031     HRESULT ret = D3DRMERR_BADOBJECT;
1032     DWORD* faces_vertex_idx_data = NULL;
1033     DWORD* faces_vertex_idx_ptr;
1034     DWORD faces_vertex_idx_size;
1035     DWORD* faces_normal_idx_data = NULL;
1036     DWORD* faces_normal_idx_ptr = NULL;
1037     DWORD* faces_data_ptr;
1038     DWORD faces_data_size = 0;
1039     DWORD i;
1040 
1041     TRACE("(%p)->(%p)\n", mesh_builder, pData);
1042 
1043     hr = IDirectXFileData_GetName(pData, NULL, &size);
1044     if (hr != DXFILE_OK)
1045         return hr;
1046     if (size)
1047     {
1048         char *name;
1049 
1050         if (!(name = heap_alloc(size)))
1051             return E_OUTOFMEMORY;
1052 
1053         if (SUCCEEDED(hr = IDirectXFileData_GetName(pData, name, &size)))
1054             IDirect3DRMMeshBuilder3_SetName(iface, name);
1055         heap_free(name);
1056         if (hr != DXFILE_OK)
1057             return hr;
1058     }
1059 
1060     TRACE("Mesh name is %s\n", debugstr_a(mesh_builder->obj.name));
1061 
1062     mesh_builder->nb_normals = 0;
1063 
1064     hr = IDirectXFileData_GetData(pData, NULL, &size, (void**)&ptr);
1065     if (hr != DXFILE_OK)
1066         goto end;
1067 
1068     mesh_builder->nb_vertices = *(DWORD*)ptr;
1069     mesh_builder->nb_faces = *(DWORD*)(ptr + sizeof(DWORD) + mesh_builder->nb_vertices * sizeof(D3DVECTOR));
1070     faces_vertex_idx_size = size - sizeof(DWORD) - mesh_builder->nb_vertices * sizeof(D3DVECTOR) - sizeof(DWORD);
1071 
1072     TRACE("Mesh: nb_vertices = %lu, nb_faces = %d, faces_vertex_idx_size = %d\n", mesh_builder->nb_vertices,
1073             mesh_builder->nb_faces, faces_vertex_idx_size);
1074 
1075     if (!d3drm_array_reserve((void **)&mesh_builder->vertices, &mesh_builder->vertices_size, mesh_builder->nb_vertices,
1076            sizeof(*mesh_builder->vertices)))
1077     {
1078         hr = E_OUTOFMEMORY;
1079         goto end;
1080     }
1081     memcpy(mesh_builder->vertices, ptr + sizeof(DWORD), mesh_builder->nb_vertices * sizeof(D3DVECTOR));
1082 
1083     faces_vertex_idx_ptr = faces_vertex_idx_data = heap_alloc(faces_vertex_idx_size);
1084     memcpy(faces_vertex_idx_data, ptr + sizeof(DWORD) + mesh_builder->nb_vertices * sizeof(D3DVECTOR) + sizeof(DWORD),
1085             faces_vertex_idx_size);
1086 
1087     /* Each vertex index will have its normal index counterpart so just allocate twice the size */
1088     mesh_builder->pFaceData = heap_alloc(faces_vertex_idx_size * 2);
1089     faces_data_ptr = (DWORD*)mesh_builder->pFaceData;
1090 
1091     while (1)
1092     {
1093         IDirectXFileObject *object;
1094 
1095         hr =  IDirectXFileData_GetNextObject(pData, &object);
1096         if (hr == DXFILEERR_NOMOREOBJECTS)
1097         {
1098             TRACE("No more object\n");
1099             break;
1100         }
1101         if (hr != DXFILE_OK)
1102            goto end;
1103 
1104         hr = IDirectXFileObject_QueryInterface(object, &IID_IDirectXFileData, (void**)&pData2);
1105         IDirectXFileObject_Release(object);
1106         if (hr != DXFILE_OK)
1107             goto end;
1108 
1109         hr = IDirectXFileData_GetType(pData2, &guid);
1110         if (hr != DXFILE_OK)
1111             goto end;
1112 
1113         TRACE("Found object type whose GUID = %s\n", debugstr_guid(guid));
1114 
1115         if (IsEqualGUID(guid, &TID_D3DRMMeshNormals))
1116         {
1117             DWORD nb_faces_normals;
1118             DWORD faces_normal_idx_size;
1119 
1120             hr = IDirectXFileData_GetData(pData2, NULL, &size, (void**)&ptr);
1121             if (hr != DXFILE_OK)
1122                 goto end;
1123 
1124             mesh_builder->nb_normals = *(DWORD*)ptr;
1125             nb_faces_normals = *(DWORD*)(ptr + sizeof(DWORD) + mesh_builder->nb_normals * sizeof(D3DVECTOR));
1126 
1127             TRACE("MeshNormals: nb_normals = %lu, nb_faces_normals = %d\n", mesh_builder->nb_normals, nb_faces_normals);
1128             if (nb_faces_normals != mesh_builder->nb_faces)
1129                 WARN("nb_face_normals (%d) != nb_faces (%d)\n", nb_faces_normals, mesh_builder->nb_faces);
1130 
1131             if (!d3drm_array_reserve((void **)&mesh_builder->normals, &mesh_builder->normals_size,
1132                     mesh_builder->nb_normals, sizeof(*mesh_builder->normals)))
1133             {
1134                 hr = E_OUTOFMEMORY;
1135                 goto end;
1136             }
1137             memcpy(mesh_builder->normals, ptr + sizeof(DWORD), mesh_builder->nb_normals * sizeof(D3DVECTOR));
1138 
1139             faces_normal_idx_size = size - (2 * sizeof(DWORD) + mesh_builder->nb_normals * sizeof(D3DVECTOR));
1140             faces_normal_idx_ptr = faces_normal_idx_data = heap_alloc(faces_normal_idx_size);
1141             memcpy(faces_normal_idx_data, ptr + sizeof(DWORD) + mesh_builder->nb_normals * sizeof(D3DVECTOR)
1142                     + sizeof(DWORD), faces_normal_idx_size);
1143         }
1144         else if (IsEqualGUID(guid, &TID_D3DRMMeshTextureCoords))
1145         {
1146             hr = IDirectXFileData_GetData(pData2, NULL, &size, (void**)&ptr);
1147             if (hr != DXFILE_OK)
1148                 goto end;
1149 
1150             mesh_builder->nb_coords2d = *(DWORD*)ptr;
1151 
1152             TRACE("MeshTextureCoords: nb_coords2d = %d\n", mesh_builder->nb_coords2d);
1153 
1154             mesh_builder->pCoords2d = heap_calloc(mesh_builder->nb_coords2d, sizeof(*mesh_builder->pCoords2d));
1155             memcpy(mesh_builder->pCoords2d, ptr + sizeof(DWORD), mesh_builder->nb_coords2d * sizeof(*mesh_builder->pCoords2d));
1156         }
1157         else if (IsEqualGUID(guid, &TID_D3DRMMeshMaterialList))
1158         {
1159             DWORD nb_materials;
1160             DWORD nb_face_indices;
1161             DWORD data_size;
1162             IDirectXFileObject *child;
1163             DWORD i = 0;
1164             float* values;
1165             struct d3drm_texture *texture_object;
1166 
1167             TRACE("Process MeshMaterialList\n");
1168 
1169             hr = IDirectXFileData_GetData(pData2, NULL, &size, (void**)&ptr);
1170             if (hr != DXFILE_OK)
1171                 goto end;
1172 
1173             nb_materials = *(DWORD*)ptr;
1174             nb_face_indices = *(DWORD*)(ptr + sizeof(DWORD));
1175             data_size = 2 * sizeof(DWORD) + nb_face_indices * sizeof(DWORD);
1176 
1177             TRACE("nMaterials = %u, nFaceIndexes = %u\n", nb_materials, nb_face_indices);
1178 
1179             if (size != data_size)
1180                 WARN("Returned size %u does not match expected one %u\n", size, data_size);
1181 
1182             if (!(mesh_builder->material_indices = heap_calloc(nb_face_indices,
1183                     sizeof(*mesh_builder->material_indices))))
1184                 goto end;
1185             memcpy(mesh_builder->material_indices, ptr + 2 * sizeof(DWORD),
1186                     nb_face_indices * sizeof(*mesh_builder->material_indices));
1187 
1188             if (!(mesh_builder->materials = heap_calloc(nb_materials, sizeof(*mesh_builder->materials))))
1189             {
1190                 heap_free(mesh_builder->material_indices);
1191                 goto end;
1192             }
1193             mesh_builder->nb_materials = nb_materials;
1194 
1195             while (SUCCEEDED(hr = IDirectXFileData_GetNextObject(pData2, &child)) && (i < nb_materials))
1196             {
1197                 IDirectXFileData *data;
1198                 IDirectXFileDataReference *reference;
1199                 IDirectXFileObject *material_child;
1200                 struct d3drm_material *object;
1201 
1202                 hr = IDirectXFileObject_QueryInterface(child, &IID_IDirectXFileData, (void **)&data);
1203                 if (FAILED(hr))
1204                 {
1205                     hr = IDirectXFileObject_QueryInterface(child, &IID_IDirectXFileDataReference, (void **)&reference);
1206                     IDirectXFileObject_Release(child);
1207                     if (FAILED(hr))
1208                         goto end;
1209 
1210                     hr = IDirectXFileDataReference_Resolve(reference, &data);
1211                     IDirectXFileDataReference_Release(reference);
1212                     if (FAILED(hr))
1213                         goto end;
1214                 }
1215                 else
1216                 {
1217                     IDirectXFileObject_Release(child);
1218                 }
1219 
1220                 hr = d3drm_material_create(&object, mesh_builder->d3drm);
1221                 if (FAILED(hr))
1222                 {
1223                     IDirectXFileData_Release(data);
1224                     goto end;
1225                 }
1226                 mesh_builder->materials[i].material = &object->IDirect3DRMMaterial2_iface;
1227 
1228                 hr = IDirectXFileData_GetData(data, NULL, &size, (void**)&ptr);
1229                 if (hr != DXFILE_OK)
1230                 {
1231                     IDirectXFileData_Release(data);
1232                     goto end;
1233                 }
1234 
1235                 if (size != 44)
1236                     WARN("Material size %u does not match expected one %u\n", size, 44);
1237 
1238                 values = (float*)ptr;
1239 
1240                 d3drm_set_color(&mesh_builder->materials[i].color, values[0], values[1], values[2], values[3]);
1241 
1242                 IDirect3DRMMaterial2_SetAmbient(mesh_builder->materials[i].material, values[0], values [1], values[2]); /* Alpha ignored */
1243                 IDirect3DRMMaterial2_SetPower(mesh_builder->materials[i].material, values[4]);
1244                 IDirect3DRMMaterial2_SetSpecular(mesh_builder->materials[i].material, values[5], values[6], values[7]);
1245                 IDirect3DRMMaterial2_SetEmissive(mesh_builder->materials[i].material, values[8], values[9], values[10]);
1246 
1247                 mesh_builder->materials[i].texture = NULL;
1248 
1249                 hr = IDirectXFileData_GetNextObject(data, &material_child);
1250                 if (hr == S_OK)
1251                 {
1252                     IDirectXFileData *data;
1253                     char **filename;
1254 
1255                     if (FAILED(hr = IDirectXFileObject_QueryInterface(material_child,
1256                             &IID_IDirectXFileData, (void **)&data)))
1257                     {
1258                         IDirectXFileDataReference *reference;
1259 
1260                         if (SUCCEEDED(IDirectXFileObject_QueryInterface(material_child,
1261                                 &IID_IDirectXFileDataReference, (void **)&reference)))
1262                         {
1263                             hr = IDirectXFileDataReference_Resolve(reference, &data);
1264                             IDirectXFileDataReference_Release(reference);
1265                         }
1266                     }
1267                     IDirectXFileObject_Release(material_child);
1268                     if (FAILED(hr))
1269                         goto end;
1270 
1271                     hr = IDirectXFileData_GetType(data, &guid);
1272                     if (hr != DXFILE_OK)
1273                         goto end;
1274                     if (!IsEqualGUID(guid, &TID_D3DRMTextureFilename))
1275                     {
1276                          WARN("Not a texture filename\n");
1277                          goto end;
1278                     }
1279 
1280                     size = 4;
1281                     hr = IDirectXFileData_GetData(data, NULL, &size, (void**)&filename);
1282                     if (SUCCEEDED(hr))
1283                     {
1284                         if (load_texture_proc)
1285                         {
1286                             IDirect3DRMTexture *texture;
1287 
1288                             hr = load_texture_proc(*filename, arg, &texture);
1289                             if (SUCCEEDED(hr))
1290                             {
1291                                 hr = IDirect3DTexture_QueryInterface(texture, &IID_IDirect3DRMTexture3,
1292                                         (void **)&mesh_builder->materials[i].texture);
1293                                 IDirect3DTexture_Release(texture);
1294                             }
1295                         }
1296                         else
1297                         {
1298                             HANDLE file;
1299 
1300                             /* If the texture file is not found, no texture is associated with the material */
1301                             file = CreateFileA(*filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
1302                             if (file != INVALID_HANDLE_VALUE)
1303                             {
1304                                 CloseHandle(file);
1305                                 if (FAILED(hr = d3drm_texture_create(&texture_object, NULL)))
1306                                 {
1307                                     IDirectXFileData_Release(data);
1308                                     goto end;
1309                                 }
1310                                 mesh_builder->materials[i].texture = &texture_object->IDirect3DRMTexture3_iface;
1311                             }
1312                         }
1313                     }
1314                     IDirectXFileData_Release(data);
1315                 }
1316                 else if (hr != DXFILEERR_NOMOREOBJECTS)
1317                 {
1318                     goto end;
1319                 }
1320                 hr = S_OK;
1321 
1322                 IDirectXFileData_Release(data);
1323                 i++;
1324             }
1325             if (hr == S_OK)
1326             {
1327                 IDirectXFileObject_Release(child);
1328                 WARN("Found more sub-objects than expected\n");
1329             }
1330             else if (hr != DXFILEERR_NOMOREOBJECTS)
1331             {
1332                 goto end;
1333             }
1334             hr = S_OK;
1335         }
1336         else
1337         {
1338             FIXME("Unknown GUID %s, ignoring...\n", debugstr_guid(guid));
1339         }
1340 
1341         IDirectXFileData_Release(pData2);
1342         pData2 = NULL;
1343     }
1344 
1345     if (!mesh_builder->nb_normals)
1346     {
1347         /* Allocate normals, one per vertex */
1348         if (!d3drm_array_reserve((void **)&mesh_builder->normals, &mesh_builder->normals_size,
1349                 mesh_builder->nb_vertices, sizeof(*mesh_builder->normals)))
1350             goto end;
1351         memset(mesh_builder->normals, 0, mesh_builder->nb_vertices * sizeof(*mesh_builder->normals));
1352     }
1353 
1354     for (i = 0; i < mesh_builder->nb_faces; i++)
1355     {
1356         DWORD j;
1357         DWORD nb_face_indexes;
1358         D3DVECTOR face_normal;
1359 
1360         if (faces_vertex_idx_size < sizeof(DWORD))
1361             WARN("Not enough data to read number of indices of face %d\n", i);
1362 
1363         nb_face_indexes  = *(faces_data_ptr + faces_data_size++) = *(faces_vertex_idx_ptr++);
1364         faces_vertex_idx_size--;
1365         if (faces_normal_idx_data && (*(faces_normal_idx_ptr++) != nb_face_indexes))
1366             WARN("Faces indices number mismatch\n");
1367 
1368         if (faces_vertex_idx_size < (nb_face_indexes * sizeof(DWORD)))
1369             WARN("Not enough data to read all indices of face %d\n", i);
1370 
1371         if (!mesh_builder->nb_normals)
1372         {
1373             /* Compute face normal */
1374             if (nb_face_indexes > 2
1375                     && faces_vertex_idx_ptr[0] < mesh_builder->nb_vertices
1376                     && faces_vertex_idx_ptr[1] < mesh_builder->nb_vertices
1377                     && faces_vertex_idx_ptr[2] < mesh_builder->nb_vertices)
1378             {
1379                 D3DVECTOR a, b;
1380 
1381                 D3DRMVectorSubtract(&a, &mesh_builder->vertices[faces_vertex_idx_ptr[2]], &mesh_builder->vertices[faces_vertex_idx_ptr[1]]);
1382                 D3DRMVectorSubtract(&b, &mesh_builder->vertices[faces_vertex_idx_ptr[0]], &mesh_builder->vertices[faces_vertex_idx_ptr[1]]);
1383                 D3DRMVectorCrossProduct(&face_normal, &a, &b);
1384                 D3DRMVectorNormalize(&face_normal);
1385             }
1386             else
1387             {
1388                 face_normal.u1.x = 0.0f;
1389                 face_normal.u2.y = 0.0f;
1390                 face_normal.u3.z = 0.0f;
1391             }
1392         }
1393 
1394         for (j = 0; j < nb_face_indexes; j++)
1395         {
1396             /* Copy vertex index */
1397             *(faces_data_ptr + faces_data_size++) = *faces_vertex_idx_ptr;
1398             /* Copy normal index */
1399             if (mesh_builder->nb_normals)
1400             {
1401                 /* Read from x file */
1402                 *(faces_data_ptr + faces_data_size++) = *(faces_normal_idx_ptr++);
1403             }
1404             else
1405             {
1406                 DWORD vertex_idx = *faces_vertex_idx_ptr;
1407                 if (vertex_idx >= mesh_builder->nb_vertices)
1408                 {
1409                     WARN("Found vertex index %u but only %lu vertices available => use index 0\n", vertex_idx,
1410                             mesh_builder->nb_vertices);
1411                     vertex_idx = 0;
1412                 }
1413                 *(faces_data_ptr + faces_data_size++) = vertex_idx;
1414                 /* Add face normal to vertex normal */
1415                 D3DRMVectorAdd(&mesh_builder->normals[vertex_idx], &mesh_builder->normals[vertex_idx], &face_normal);
1416             }
1417             faces_vertex_idx_ptr++;
1418         }
1419         faces_vertex_idx_size -= nb_face_indexes;
1420     }
1421 
1422     /* Last DWORD must be 0 */
1423     *(faces_data_ptr + faces_data_size++) = 0;
1424 
1425     /* Set size (in number of DWORD) of all faces data */
1426     mesh_builder->face_data_size = faces_data_size;
1427 
1428     if (!mesh_builder->nb_normals)
1429     {
1430         /* Normalize all normals */
1431         for (i = 0; i < mesh_builder->nb_vertices; i++)
1432         {
1433             D3DRMVectorNormalize(&mesh_builder->normals[i]);
1434         }
1435         mesh_builder->nb_normals = mesh_builder->nb_vertices;
1436     }
1437 
1438     /* If there is no texture coordinates, generate default texture coordinates (0.0f, 0.0f) for each vertex */
1439     if (!mesh_builder->pCoords2d)
1440     {
1441         mesh_builder->nb_coords2d = mesh_builder->nb_vertices;
1442         mesh_builder->pCoords2d = heap_calloc(mesh_builder->nb_coords2d, sizeof(*mesh_builder->pCoords2d));
1443         for (i = 0; i < mesh_builder->nb_coords2d; ++i)
1444         {
1445             mesh_builder->pCoords2d[i].u = 0.0f;
1446             mesh_builder->pCoords2d[i].v = 0.0f;
1447         }
1448     }
1449 
1450     TRACE("Mesh data loaded successfully\n");
1451 
1452     ret = D3DRM_OK;
1453 
1454 end:
1455 
1456     heap_free(faces_normal_idx_data);
1457     heap_free(faces_vertex_idx_data);
1458 
1459     return ret;
1460 }
1461 
1462 static HRESULT WINAPI d3drm_mesh_builder3_Load(IDirect3DRMMeshBuilder3 *iface, void *filename,
1463         void *name, D3DRMLOADOPTIONS loadflags, D3DRMLOADTEXTURE3CALLBACK cb, void *arg)
1464 {
1465     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1466     DXFILELOADOPTIONS load_options;
1467     IDirectXFile *dxfile = NULL;
1468     IDirectXFileEnumObject *enum_object = NULL;
1469     IDirectXFileData *data = NULL;
1470     const GUID* guid;
1471     DWORD size;
1472     struct d3drm_file_header *header;
1473     HRESULT hr;
1474     HRESULT ret = D3DRMERR_BADOBJECT;
1475 
1476     TRACE("iface %p, filename %p, name %p, loadflags %#x, cb %p, arg %p.\n",
1477             iface, filename, name, loadflags, cb, arg);
1478 
1479     clean_mesh_builder_data(mesh_builder);
1480 
1481     if (loadflags == D3DRMLOAD_FROMMEMORY)
1482     {
1483         load_options = DXFILELOAD_FROMMEMORY;
1484     }
1485     else if (loadflags == D3DRMLOAD_FROMFILE)
1486     {
1487         load_options = DXFILELOAD_FROMFILE;
1488         TRACE("Loading from file %s\n", debugstr_a(filename));
1489     }
1490     else
1491     {
1492         FIXME("Load options %d not supported yet\n", loadflags);
1493         return E_NOTIMPL;
1494     }
1495 
1496     hr = DirectXFileCreate(&dxfile);
1497     if (hr != DXFILE_OK)
1498         goto end;
1499 
1500     hr = IDirectXFile_RegisterTemplates(dxfile, templates, strlen(templates));
1501     if (hr != DXFILE_OK)
1502         goto end;
1503 
1504     hr = IDirectXFile_CreateEnumObject(dxfile, filename, load_options, &enum_object);
1505     if (hr != DXFILE_OK)
1506         goto end;
1507 
1508     hr = IDirectXFileEnumObject_GetNextDataObject(enum_object, &data);
1509     if (hr != DXFILE_OK)
1510         goto end;
1511 
1512     hr = IDirectXFileData_GetType(data, &guid);
1513     if (hr != DXFILE_OK)
1514         goto end;
1515 
1516     TRACE("Found object type whose GUID = %s\n", debugstr_guid(guid));
1517 
1518     if (!IsEqualGUID(guid, &TID_DXFILEHeader))
1519     {
1520         ret = D3DRMERR_BADFILE;
1521         goto end;
1522     }
1523 
1524     hr = IDirectXFileData_GetData(data, NULL, &size, (void**)&header);
1525     if ((hr != DXFILE_OK) || (size != sizeof(*header)))
1526         goto end;
1527 
1528     TRACE("Version is %u.%u, flags %#x.\n", header->major, header->minor, header->flags);
1529 
1530     /* Version must be 1.0.x */
1531     if ((header->major != 1) || (header->minor != 0))
1532     {
1533         ret = D3DRMERR_BADFILE;
1534         goto end;
1535     }
1536 
1537     IDirectXFileData_Release(data);
1538     data = NULL;
1539 
1540     hr = IDirectXFileEnumObject_GetNextDataObject(enum_object, &data);
1541     if (hr != DXFILE_OK)
1542     {
1543         ret = D3DRMERR_NOTFOUND;
1544         goto end;
1545     }
1546 
1547     hr = IDirectXFileData_GetType(data, &guid);
1548     if (hr != DXFILE_OK)
1549         goto end;
1550 
1551     TRACE("Found object type whose GUID = %s\n", debugstr_guid(guid));
1552 
1553     if (!IsEqualGUID(guid, &TID_D3DRMMesh))
1554     {
1555         ret = D3DRMERR_NOTFOUND;
1556         goto end;
1557     }
1558 
1559     /* We don't care about the texture interface version since we rely on QueryInterface */
1560     hr = load_mesh_data(iface, data, (D3DRMLOADTEXTURECALLBACK)cb, arg);
1561     if (hr == S_OK)
1562         ret = D3DRM_OK;
1563 
1564 end:
1565 
1566     if (data)
1567         IDirectXFileData_Release(data);
1568     if (enum_object)
1569         IDirectXFileEnumObject_Release(enum_object);
1570     if (dxfile)
1571         IDirectXFile_Release(dxfile);
1572 
1573     if (ret != D3DRM_OK)
1574         clean_mesh_builder_data(mesh_builder);
1575 
1576     return ret;
1577 }
1578 
1579 static HRESULT WINAPI d3drm_mesh_builder3_Save(IDirect3DRMMeshBuilder3 *iface,
1580         const char *filename, D3DRMXOFFORMAT format, D3DRMSAVEOPTIONS flags)
1581 {
1582     FIXME("iface %p, filename %s, format %#x, flags %#x stub!\n",
1583             iface, debugstr_a(filename), format, flags);
1584 
1585     return E_NOTIMPL;
1586 }
1587 
1588 static HRESULT WINAPI d3drm_mesh_builder3_Scale(IDirect3DRMMeshBuilder3 *iface,
1589         D3DVALUE sx, D3DVALUE sy, D3DVALUE sz)
1590 {
1591     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1592     DWORD i;
1593 
1594     TRACE("iface %p, sx %.8e, sy %.8e, sz %.8e.\n", iface, sx, sy, sz);
1595 
1596     for (i = 0; i < mesh_builder->nb_vertices; ++i)
1597     {
1598         mesh_builder->vertices[i].u1.x *= sx;
1599         mesh_builder->vertices[i].u2.y *= sy;
1600         mesh_builder->vertices[i].u3.z *= sz;
1601     }
1602 
1603     /* Normals are not affected by Scale */
1604 
1605     return D3DRM_OK;
1606 }
1607 
1608 static HRESULT WINAPI d3drm_mesh_builder3_Translate(IDirect3DRMMeshBuilder3 *iface,
1609         D3DVALUE tx, D3DVALUE ty, D3DVALUE tz)
1610 {
1611     FIXME("iface %p, tx %.8e, ty %.8e, tz %.8e stub!\n", iface, tx, ty, tz);
1612 
1613     return E_NOTIMPL;
1614 }
1615 
1616 static HRESULT WINAPI d3drm_mesh_builder3_SetColorSource(IDirect3DRMMeshBuilder3 *iface,
1617         D3DRMCOLORSOURCE source)
1618 {
1619     FIXME("iface %p, source %#x stub!\n", iface, source);
1620 
1621     return E_NOTIMPL;
1622 }
1623 
1624 static HRESULT WINAPI d3drm_mesh_builder3_GetBox(IDirect3DRMMeshBuilder3 *iface, D3DRMBOX *box)
1625 {
1626     FIXME("iface %p, box %p stub!\n", iface, box);
1627 
1628     return E_NOTIMPL;
1629 }
1630 
1631 static HRESULT WINAPI d3drm_mesh_builder3_GenerateNormals(IDirect3DRMMeshBuilder3 *iface,
1632         D3DVALUE crease, DWORD flags)
1633 {
1634     FIXME("iface %p, crease %.8e, flags %#x stub!\n", iface, crease, flags);
1635 
1636     return E_NOTIMPL;
1637 }
1638 
1639 static D3DRMCOLORSOURCE WINAPI d3drm_mesh_builder3_GetColorSource(IDirect3DRMMeshBuilder3 *iface)
1640 {
1641     FIXME("iface %p stub!\n", iface);
1642 
1643     return E_NOTIMPL;
1644 }
1645 
1646 static HRESULT WINAPI d3drm_mesh_builder3_AddMesh(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMMesh *mesh)
1647 {
1648     FIXME("iface %p, mesh %p stub!\n", iface, mesh);
1649 
1650     return E_NOTIMPL;
1651 }
1652 
1653 static HRESULT WINAPI d3drm_mesh_builder3_AddMeshBuilder(IDirect3DRMMeshBuilder3 *iface,
1654         IDirect3DRMMeshBuilder3 *mesh_builder, DWORD flags)
1655 {
1656     FIXME("iface %p, mesh_builder %p, flags %#x stub!\n", iface, mesh_builder, flags);
1657 
1658     return E_NOTIMPL;
1659 }
1660 
1661 static HRESULT WINAPI d3drm_mesh_builder3_AddFrame(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMFrame3 *frame)
1662 {
1663     FIXME("iface %p, frame %p stub!\n", iface, frame);
1664 
1665     return E_NOTIMPL;
1666 }
1667 
1668 static HRESULT WINAPI d3drm_mesh_builder3_AddFace(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMFace2 *face)
1669 {
1670     FIXME("iface %p, face %p stub!\n", iface, face);
1671 
1672     return E_NOTIMPL;
1673 }
1674 
1675 static HRESULT WINAPI d3drm_mesh_builder3_AddFaces(IDirect3DRMMeshBuilder3 *iface,
1676         DWORD vertex_count, D3DVECTOR *vertices, DWORD normal_count, D3DVECTOR *normals,
1677         DWORD *face_data, IDirect3DRMFaceArray **array)
1678 {
1679     FIXME("iface %p, vertex_count %u, vertices %p, normal_count %u, normals %p, face_data %p array %p stub!\n",
1680             iface, vertex_count, vertices, normal_count, normals, face_data, array);
1681 
1682     return E_NOTIMPL;
1683 }
1684 
1685 static HRESULT WINAPI d3drm_mesh_builder3_ReserveSpace(IDirect3DRMMeshBuilder3 *iface,
1686         DWORD vertex_count, DWORD normal_count, DWORD face_count)
1687 {
1688     FIXME("iface %p, vertex_count %u, normal_count %u, face_count %u stub!\n",
1689             iface, vertex_count, normal_count, face_count);
1690 
1691     return E_NOTIMPL;
1692 }
1693 
1694 static HRESULT WINAPI d3drm_mesh_builder3_SetColorRGB(IDirect3DRMMeshBuilder3 *iface,
1695         D3DVALUE red, D3DVALUE green, D3DVALUE blue)
1696 {
1697     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1698 
1699     TRACE("iface %p, red %.8e, green %.8e, blue %.8e.\n", iface, red, green, blue);
1700 
1701     d3drm_set_color(&mesh_builder->color, red, green, blue, 1.0f);
1702 
1703     return D3DRM_OK;
1704 }
1705 
1706 static HRESULT WINAPI d3drm_mesh_builder3_SetColor(IDirect3DRMMeshBuilder3 *iface, D3DCOLOR color)
1707 {
1708     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1709 
1710     TRACE("iface %p, color 0x%08x.\n", iface, color);
1711 
1712     mesh_builder->color = color;
1713 
1714     return D3DRM_OK;
1715 }
1716 
1717 static HRESULT WINAPI d3drm_mesh_builder3_SetTexture(IDirect3DRMMeshBuilder3 *iface,
1718         IDirect3DRMTexture3 *texture)
1719 {
1720     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1721 
1722     TRACE("iface %p, texture %p.\n", iface, texture);
1723 
1724     if (texture)
1725         IDirect3DRMTexture3_AddRef(texture);
1726     if (mesh_builder->texture)
1727         IDirect3DRMTexture3_Release(mesh_builder->texture);
1728     mesh_builder->texture = texture;
1729 
1730     return D3DRM_OK;
1731 }
1732 
1733 static HRESULT WINAPI d3drm_mesh_builder3_SetMaterial(IDirect3DRMMeshBuilder3 *iface,
1734         IDirect3DRMMaterial2 *material)
1735 {
1736     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1737 
1738     TRACE("iface %p, material %p.\n", iface, material);
1739 
1740     if (material)
1741         IDirect3DRMTexture2_AddRef(material);
1742     if (mesh_builder->material)
1743         IDirect3DRMTexture2_Release(mesh_builder->material);
1744     mesh_builder->material = material;
1745 
1746     return D3DRM_OK;
1747 }
1748 
1749 static HRESULT WINAPI d3drm_mesh_builder3_SetTextureTopology(IDirect3DRMMeshBuilder3 *iface,
1750         BOOL wrap_u, BOOL wrap_v)
1751 {
1752     FIXME("iface %p, wrap_u %#x, wrap_v %#x stub!\n", iface, wrap_u, wrap_v);
1753 
1754     return E_NOTIMPL;
1755 }
1756 
1757 static HRESULT WINAPI d3drm_mesh_builder3_SetQuality(IDirect3DRMMeshBuilder3 *iface,
1758         D3DRMRENDERQUALITY quality)
1759 {
1760     FIXME("iface %p, quality %#x stub!\n", iface, quality);
1761 
1762     return E_NOTIMPL;
1763 }
1764 
1765 static HRESULT WINAPI d3drm_mesh_builder3_SetPerspective(IDirect3DRMMeshBuilder3 *iface,
1766         BOOL enable)
1767 {
1768     FIXME("iface %p, enable %#x stub!\n", iface, enable);
1769 
1770     return E_NOTIMPL;
1771 }
1772 
1773 static HRESULT WINAPI d3drm_mesh_builder3_SetVertex(IDirect3DRMMeshBuilder3 *iface,
1774         DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z)
1775 {
1776     FIXME("iface %p, index %u, x %.8e, y %.8e, z %.8e stub!\n", iface, index, x, y, z);
1777 
1778     return E_NOTIMPL;
1779 }
1780 
1781 static HRESULT WINAPI d3drm_mesh_builder3_SetNormal(IDirect3DRMMeshBuilder3 *iface,
1782         DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z)
1783 {
1784     FIXME("iface %p, index %u, x %.8e, y %.8e, z %.8e stub!\n", iface, index, x, y, z);
1785 
1786     return E_NOTIMPL;
1787 }
1788 
1789 static HRESULT WINAPI d3drm_mesh_builder3_SetTextureCoordinates(IDirect3DRMMeshBuilder3 *iface,
1790         DWORD index, D3DVALUE u, D3DVALUE v)
1791 {
1792     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1793 
1794     TRACE("iface %p, index %u, u %.8e, v %.8e.\n", iface, index, u, v);
1795 
1796     if (index >= mesh_builder->nb_coords2d)
1797         return D3DRMERR_BADVALUE;
1798 
1799     mesh_builder->pCoords2d[index].u = u;
1800     mesh_builder->pCoords2d[index].v = v;
1801 
1802     return D3DRM_OK;
1803 }
1804 
1805 static HRESULT WINAPI d3drm_mesh_builder3_SetVertexColor(IDirect3DRMMeshBuilder3 *iface,
1806         DWORD index, D3DCOLOR color)
1807 {
1808     FIXME("iface %p, index %u, color 0x%08x stub!\n", iface, index, color);
1809 
1810     return E_NOTIMPL;
1811 }
1812 
1813 static HRESULT WINAPI d3drm_mesh_builder3_SetVertexColorRGB(IDirect3DRMMeshBuilder3 *iface,
1814         DWORD index, D3DVALUE red, D3DVALUE green, D3DVALUE blue)
1815 {
1816     FIXME("iface %p, index %u, red %.8e, green %.8e, blue %.8e stub!\n",
1817             iface, index, red, green, blue);
1818 
1819     return E_NOTIMPL;
1820 }
1821 
1822 static HRESULT WINAPI d3drm_mesh_builder3_GetFaces(IDirect3DRMMeshBuilder3 *iface,
1823         IDirect3DRMFaceArray **array)
1824 {
1825     FIXME("iface %p, array %p stub!\n", iface, array);
1826 
1827     return E_NOTIMPL;
1828 }
1829 
1830 static HRESULT WINAPI d3drm_mesh_builder3_GetGeometry(IDirect3DRMMeshBuilder3 *iface,
1831         DWORD *vertex_count, D3DVECTOR *vertices, DWORD *normal_count, D3DVECTOR *normals,
1832         DWORD *face_data_size, DWORD *face_data)
1833 {
1834     FIXME("iface %p, vertex_count %p, vertices %p, normal_count %p, normals %p, "
1835             "face_data_size %p, face_data %p stub!\n",
1836             iface, vertex_count, vertices, normal_count, normals, face_data_size, face_data);
1837 
1838     return E_NOTIMPL;
1839 }
1840 
1841 static HRESULT WINAPI d3drm_mesh_builder3_GetTextureCoordinates(IDirect3DRMMeshBuilder3 *iface,
1842         DWORD index, D3DVALUE *u, D3DVALUE *v)
1843 {
1844     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1845 
1846     TRACE("iface %p, index %u, u %p, v %p.\n", iface, index, u, v);
1847 
1848     if (index >= mesh_builder->nb_coords2d)
1849         return D3DRMERR_BADVALUE;
1850 
1851     *u = mesh_builder->pCoords2d[index].u;
1852     *v = mesh_builder->pCoords2d[index].v;
1853 
1854     return D3DRM_OK;
1855 }
1856 
1857 static int WINAPI d3drm_mesh_builder3_AddVertex(IDirect3DRMMeshBuilder3 *iface,
1858         D3DVALUE x, D3DVALUE y, D3DVALUE z)
1859 {
1860     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1861 
1862     TRACE("iface %p, x %.8e, y %.8e, z %.8e.\n", iface, x, y, z);
1863 
1864     if (!d3drm_array_reserve((void **)&mesh_builder->vertices, &mesh_builder->vertices_size,
1865             mesh_builder->nb_vertices + 1, sizeof(*mesh_builder->vertices)))
1866         return 0;
1867 
1868     mesh_builder->vertices[mesh_builder->nb_vertices].u1.x = x;
1869     mesh_builder->vertices[mesh_builder->nb_vertices].u2.y = y;
1870     mesh_builder->vertices[mesh_builder->nb_vertices].u3.z = z;
1871 
1872     return mesh_builder->nb_vertices++;
1873 }
1874 
1875 static int WINAPI d3drm_mesh_builder3_AddNormal(IDirect3DRMMeshBuilder3 *iface,
1876         D3DVALUE x, D3DVALUE y, D3DVALUE z)
1877 {
1878     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1879 
1880     TRACE("iface %p, x %.8e, y %.8e, z %.8e.\n", iface, x, y, z);
1881 
1882     if (!d3drm_array_reserve((void **)&mesh_builder->normals, &mesh_builder->normals_size,
1883             mesh_builder->nb_normals + 1, sizeof(*mesh_builder->normals)))
1884         return 0;
1885 
1886     mesh_builder->normals[mesh_builder->nb_normals].u1.x = x;
1887     mesh_builder->normals[mesh_builder->nb_normals].u2.y = y;
1888     mesh_builder->normals[mesh_builder->nb_normals].u3.z = z;
1889 
1890     return mesh_builder->nb_normals++;
1891 }
1892 
1893 static HRESULT WINAPI d3drm_mesh_builder3_CreateFace(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMFace2 **face)
1894 {
1895     struct d3drm_face *object;
1896     HRESULT hr;
1897 
1898     TRACE("iface %p, face %p.\n", iface, face);
1899 
1900     if (FAILED(hr = d3drm_face_create(&object)))
1901         return hr;
1902 
1903     *face = &object->IDirect3DRMFace2_iface;
1904 
1905     return S_OK;
1906 }
1907 
1908 static D3DRMRENDERQUALITY WINAPI d3drm_mesh_builder3_GetQuality(IDirect3DRMMeshBuilder3 *iface)
1909 {
1910     FIXME("iface %p stub!\n", iface);
1911 
1912     return 0;
1913 }
1914 
1915 static BOOL WINAPI d3drm_mesh_builder3_GetPerspective(IDirect3DRMMeshBuilder3 *iface)
1916 {
1917     FIXME("iface %p stub!\n", iface);
1918 
1919     return FALSE;
1920 }
1921 
1922 static int WINAPI d3drm_mesh_builder3_GetFaceCount(IDirect3DRMMeshBuilder3 *iface)
1923 {
1924     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1925 
1926     TRACE("iface %p.\n", iface);
1927 
1928     return mesh_builder->nb_faces;
1929 }
1930 
1931 static int WINAPI d3drm_mesh_builder3_GetVertexCount(IDirect3DRMMeshBuilder3 *iface)
1932 {
1933     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1934 
1935     TRACE("iface %p.\n", iface);
1936 
1937     return mesh_builder->nb_vertices;
1938 }
1939 
1940 static D3DCOLOR WINAPI d3drm_mesh_builder3_GetVertexColor(IDirect3DRMMeshBuilder3 *iface,
1941         DWORD index)
1942 {
1943     FIXME("iface %p, index %u stub!\n", iface, index);
1944 
1945     return 0;
1946 }
1947 
1948 static HRESULT WINAPI d3drm_mesh_builder3_CreateMesh(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMMesh **mesh)
1949 {
1950     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
1951     HRESULT hr;
1952     D3DRMGROUPINDEX group;
1953 
1954     TRACE("iface %p, mesh %p.\n", iface, mesh);
1955 
1956     if (!mesh)
1957         return E_POINTER;
1958 
1959     hr = IDirect3DRM_CreateMesh(mesh_builder->d3drm, mesh);
1960     if (FAILED(hr))
1961         return hr;
1962 
1963     /* If there is mesh data, create a group and put data inside */
1964     if (mesh_builder->nb_vertices)
1965     {
1966         DWORD i, j;
1967         int k;
1968         D3DRMVERTEX* vertices;
1969 
1970         if (!(vertices = heap_calloc(mesh_builder->nb_vertices, sizeof(*vertices))))
1971         {
1972             IDirect3DRMMesh_Release(*mesh);
1973             return E_OUTOFMEMORY;
1974         }
1975         for (i = 0; i < mesh_builder->nb_vertices; i++)
1976             vertices[i].position = mesh_builder->vertices[i];
1977         hr = IDirect3DRMMesh_SetVertices(*mesh, 0, 0, mesh_builder->nb_vertices, vertices);
1978         heap_free(vertices);
1979 
1980         /* Groups are in reverse order compared to materials list in X file */
1981         for (k = mesh_builder->nb_materials - 1; k >= 0; k--)
1982         {
1983             unsigned* face_data;
1984             unsigned* out_ptr;
1985             DWORD* in_ptr = mesh_builder->pFaceData;
1986             ULONG vertex_per_face = 0;
1987             BOOL* used_vertices;
1988             unsigned nb_vertices = 0;
1989             unsigned nb_faces = 0;
1990 
1991             if (!(used_vertices = heap_calloc(mesh_builder->face_data_size, sizeof(*used_vertices))))
1992             {
1993                 IDirect3DRMMesh_Release(*mesh);
1994                 return E_OUTOFMEMORY;
1995             }
1996 
1997             if (!(face_data = heap_calloc(mesh_builder->face_data_size, sizeof(*face_data))))
1998             {
1999                 heap_free(used_vertices);
2000                 IDirect3DRMMesh_Release(*mesh);
2001                 return E_OUTOFMEMORY;
2002             }
2003             out_ptr = face_data;
2004 
2005             /* If all faces have the same number of vertex, set vertex_per_face */
2006             for (i = 0; i < mesh_builder->nb_faces; i++)
2007             {
2008                 /* Process only faces belonging to the group */
2009                 if (mesh_builder->material_indices[i] == k)
2010                 {
2011                     if (vertex_per_face && (vertex_per_face != *in_ptr))
2012                         break;
2013                     vertex_per_face = *in_ptr;
2014                 }
2015                 in_ptr += 1 + *in_ptr * 2;
2016             }
2017             if (i != mesh_builder->nb_faces)
2018                 vertex_per_face = 0;
2019 
2020             /* Put only vertex indices */
2021             in_ptr = mesh_builder->pFaceData;
2022             for (i = 0; i < mesh_builder->nb_faces; i++)
2023             {
2024                 DWORD nb_indices = *in_ptr++;
2025 
2026                 /* Skip faces not belonging to the group */
2027                 if (mesh_builder->material_indices[i] != k)
2028                 {
2029                     in_ptr += 2 * nb_indices;
2030                     continue;
2031                 }
2032 
2033                 /* Don't put nb indices when vertex_per_face is set */
2034                 if (vertex_per_face)
2035                     *out_ptr++ = nb_indices;
2036 
2037                 for (j = 0; j < nb_indices; j++)
2038                 {
2039                     *out_ptr = *in_ptr++;
2040                     used_vertices[*out_ptr++] = TRUE;
2041                     /* Skip normal index */
2042                     in_ptr++;
2043                 }
2044 
2045                 nb_faces++;
2046             }
2047 
2048             for (i = 0; i < mesh_builder->nb_vertices; i++)
2049                 if (used_vertices[i])
2050                     nb_vertices++;
2051 
2052             hr = IDirect3DRMMesh_AddGroup(*mesh, nb_vertices, nb_faces, vertex_per_face, face_data, &group);
2053             heap_free(used_vertices);
2054             heap_free(face_data);
2055             if (SUCCEEDED(hr))
2056                 hr = IDirect3DRMMesh_SetGroupColor(*mesh, group, mesh_builder->materials[k].color);
2057             if (SUCCEEDED(hr))
2058                 hr = IDirect3DRMMesh_SetGroupMaterial(*mesh, group,
2059                         (IDirect3DRMMaterial *)mesh_builder->materials[k].material);
2060             if (SUCCEEDED(hr) && mesh_builder->materials[k].texture)
2061             {
2062                 IDirect3DRMTexture *texture;
2063 
2064                 IDirect3DRMTexture3_QueryInterface(mesh_builder->materials[k].texture,
2065                         &IID_IDirect3DRMTexture, (void **)&texture);
2066                 hr = IDirect3DRMMesh_SetGroupTexture(*mesh, group, texture);
2067                 IDirect3DRMTexture_Release(texture);
2068             }
2069             if (FAILED(hr))
2070             {
2071                 IDirect3DRMMesh_Release(*mesh);
2072                 return hr;
2073             }
2074         }
2075     }
2076 
2077     return D3DRM_OK;
2078 }
2079 
2080 static HRESULT WINAPI d3drm_mesh_builder3_GetFace(IDirect3DRMMeshBuilder3 *iface,
2081         DWORD index, IDirect3DRMFace2 **face)
2082 {
2083     FIXME("iface %p, index %u, face %p stub!\n", iface, index, face);
2084 
2085     return E_NOTIMPL;
2086 }
2087 
2088 static HRESULT WINAPI d3drm_mesh_builder3_GetVertex(IDirect3DRMMeshBuilder3 *iface,
2089         DWORD index, D3DVECTOR *vector)
2090 {
2091     FIXME("iface %p, index %u, vector %p stub!\n", iface, index, vector);
2092 
2093     return E_NOTIMPL;
2094 }
2095 
2096 static HRESULT WINAPI d3drm_mesh_builder3_GetNormal(IDirect3DRMMeshBuilder3 *iface,
2097         DWORD index, D3DVECTOR *vector)
2098 {
2099     FIXME("iface %p, index %u, vector %p stub!\n", iface, index, vector);
2100 
2101     return E_NOTIMPL;
2102 }
2103 
2104 static HRESULT WINAPI d3drm_mesh_builder3_DeleteVertices(IDirect3DRMMeshBuilder3 *iface,
2105         DWORD start_idx, DWORD count)
2106 {
2107     FIXME("iface %p, start_idx %u, count %u stub!\n", iface, start_idx, count);
2108 
2109     return E_NOTIMPL;
2110 }
2111 
2112 static HRESULT WINAPI d3drm_mesh_builder3_DeleteNormals(IDirect3DRMMeshBuilder3 *iface,
2113         DWORD start_idx, DWORD count)
2114 {
2115     FIXME("iface %p, start_idx %u, count %u stub!\n", iface, start_idx, count);
2116 
2117     return E_NOTIMPL;
2118 }
2119 
2120 static HRESULT WINAPI d3drm_mesh_builder3_DeleteFace(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMFace2 *face)
2121 {
2122     FIXME("iface %p, face %p stub!\n", iface, face);
2123 
2124     return E_NOTIMPL;
2125 }
2126 
2127 static HRESULT WINAPI d3drm_mesh_builder3_Empty(IDirect3DRMMeshBuilder3 *iface, DWORD flags)
2128 {
2129     FIXME("iface %p, flags %#x stub!\n", iface, flags);
2130 
2131     return E_NOTIMPL;
2132 }
2133 
2134 static HRESULT WINAPI d3drm_mesh_builder3_Optimize(IDirect3DRMMeshBuilder3 *iface, DWORD flags)
2135 {
2136     FIXME("iface %p, flags %#x stub!\n", iface, flags);
2137 
2138     return E_NOTIMPL;
2139 }
2140 
2141 static HRESULT WINAPI d3drm_mesh_builder3_AddFacesIndexed(IDirect3DRMMeshBuilder3 *iface,
2142         DWORD flags, DWORD *indices, DWORD *start_idx, DWORD *count)
2143 {
2144     FIXME("iface %p, flags %#x, indices %p, start_idx %p, count %p stub!\n",
2145             iface, flags, indices, start_idx, count);
2146 
2147     return E_NOTIMPL;
2148 }
2149 
2150 static HRESULT WINAPI d3drm_mesh_builder3_CreateSubMesh(IDirect3DRMMeshBuilder3 *iface, IUnknown **mesh)
2151 {
2152     FIXME("iface %p, mesh %p stub!\n", iface, mesh);
2153 
2154     return E_NOTIMPL;
2155 }
2156 
2157 static HRESULT WINAPI d3drm_mesh_builder3_GetParentMesh(IDirect3DRMMeshBuilder3 *iface,
2158         DWORD flags, IUnknown **parent)
2159 {
2160     FIXME("iface %p, flags %#x, parent %p stub!\n", iface, flags, parent);
2161 
2162     return E_NOTIMPL;
2163 }
2164 
2165 static HRESULT WINAPI d3drm_mesh_builder3_GetSubMeshes(IDirect3DRMMeshBuilder3 *iface,
2166         DWORD *count, IUnknown **meshes)
2167 {
2168     FIXME("iface %p, count %p, meshes %p stub!\n", iface, count, meshes);
2169 
2170     return E_NOTIMPL;
2171 }
2172 
2173 static HRESULT WINAPI d3drm_mesh_builder3_DeleteSubMesh(IDirect3DRMMeshBuilder3 *iface, IUnknown *mesh)
2174 {
2175     FIXME("iface %p, mesh %p stub!\n", iface, mesh);
2176 
2177     return E_NOTIMPL;
2178 }
2179 
2180 static HRESULT WINAPI d3drm_mesh_builder3_Enable(IDirect3DRMMeshBuilder3 *iface, DWORD index)
2181 {
2182     FIXME("iface %p, index %u stub!\n", iface, index);
2183 
2184     return E_NOTIMPL;
2185 }
2186 
2187 static HRESULT WINAPI d3drm_mesh_builder3_GetEnable(IDirect3DRMMeshBuilder3 *iface, DWORD *indices)
2188 {
2189     FIXME("iface %p, indices %p stub!\n", iface, indices);
2190 
2191     return E_NOTIMPL;
2192 }
2193 
2194 static HRESULT WINAPI d3drm_mesh_builder3_AddTriangles(IDirect3DRMMeshBuilder3 *iface,
2195         DWORD flags, DWORD format, DWORD vertex_count, void *data)
2196 {
2197     FIXME("iface %p, flags %#x, format %#x, vertex_count %u, data %p stub!\n",
2198             iface, flags, format, vertex_count, data);
2199 
2200     return E_NOTIMPL;
2201 }
2202 
2203 static HRESULT WINAPI d3drm_mesh_builder3_SetVertices(IDirect3DRMMeshBuilder3 *iface,
2204         DWORD start_idx, DWORD count, D3DVECTOR *vector)
2205 {
2206     FIXME("iface %p, start_idx %u, count %u, vector %p stub!\n", iface, start_idx, count, vector);
2207 
2208     return E_NOTIMPL;
2209 }
2210 
2211 static HRESULT WINAPI d3drm_mesh_builder3_GetVertices(IDirect3DRMMeshBuilder3 *iface,
2212         DWORD start_idx, DWORD *vertex_count, D3DVECTOR *vertices)
2213 {
2214     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
2215     DWORD count = mesh_builder->nb_vertices - start_idx;
2216 
2217     TRACE("iface %p, start_idx %u, vertex_count %p, vertices %p.\n",
2218             iface, start_idx, vertex_count, vertices);
2219 
2220     if (vertex_count)
2221         *vertex_count = count;
2222     if (vertices && mesh_builder->nb_vertices)
2223         memcpy(vertices, mesh_builder->vertices + start_idx, count * sizeof(*vertices));
2224 
2225     return D3DRM_OK;
2226 }
2227 
2228 static HRESULT WINAPI d3drm_mesh_builder3_SetNormals(IDirect3DRMMeshBuilder3 *iface,
2229         DWORD start_idx, DWORD count, D3DVECTOR *vector)
2230 {
2231     FIXME("iface %p, start_idx %u, count %u, vector %p stub!\n",
2232             iface, start_idx, count, vector);
2233 
2234     return E_NOTIMPL;
2235 }
2236 
2237 static HRESULT WINAPI d3drm_mesh_builder3_GetNormals(IDirect3DRMMeshBuilder3 *iface,
2238         DWORD start_idx, DWORD *normal_count, D3DVECTOR *normals)
2239 {
2240     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
2241     DWORD count = mesh_builder->nb_normals - start_idx;
2242 
2243     TRACE("iface %p, start_idx %u, normal_count %p, normals %p.\n",
2244             iface, start_idx, normal_count, normals);
2245 
2246     if (normal_count)
2247         *normal_count = count;
2248     if (normals && mesh_builder->nb_normals)
2249         memcpy(normals, &mesh_builder->normals[start_idx], count * sizeof(*normals));
2250 
2251     return D3DRM_OK;
2252 }
2253 
2254 static int WINAPI d3drm_mesh_builder3_GetNormalCount(IDirect3DRMMeshBuilder3 *iface)
2255 {
2256     struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
2257 
2258     TRACE("iface %p.\n", iface);
2259 
2260     return mesh_builder->nb_normals;
2261 }
2262 
2263 static const struct IDirect3DRMMeshBuilder3Vtbl d3drm_mesh_builder3_vtbl =
2264 {
2265     d3drm_mesh_builder3_QueryInterface,
2266     d3drm_mesh_builder3_AddRef,
2267     d3drm_mesh_builder3_Release,
2268     d3drm_mesh_builder3_Clone,
2269     d3drm_mesh_builder3_AddDestroyCallback,
2270     d3drm_mesh_builder3_DeleteDestroyCallback,
2271     d3drm_mesh_builder3_SetAppData,
2272     d3drm_mesh_builder3_GetAppData,
2273     d3drm_mesh_builder3_SetName,
2274     d3drm_mesh_builder3_GetName,
2275     d3drm_mesh_builder3_GetClassName,
2276     d3drm_mesh_builder3_Load,
2277     d3drm_mesh_builder3_Save,
2278     d3drm_mesh_builder3_Scale,
2279     d3drm_mesh_builder3_Translate,
2280     d3drm_mesh_builder3_SetColorSource,
2281     d3drm_mesh_builder3_GetBox,
2282     d3drm_mesh_builder3_GenerateNormals,
2283     d3drm_mesh_builder3_GetColorSource,
2284     d3drm_mesh_builder3_AddMesh,
2285     d3drm_mesh_builder3_AddMeshBuilder,
2286     d3drm_mesh_builder3_AddFrame,
2287     d3drm_mesh_builder3_AddFace,
2288     d3drm_mesh_builder3_AddFaces,
2289     d3drm_mesh_builder3_ReserveSpace,
2290     d3drm_mesh_builder3_SetColorRGB,
2291     d3drm_mesh_builder3_SetColor,
2292     d3drm_mesh_builder3_SetTexture,
2293     d3drm_mesh_builder3_SetMaterial,
2294     d3drm_mesh_builder3_SetTextureTopology,
2295     d3drm_mesh_builder3_SetQuality,
2296     d3drm_mesh_builder3_SetPerspective,
2297     d3drm_mesh_builder3_SetVertex,
2298     d3drm_mesh_builder3_SetNormal,
2299     d3drm_mesh_builder3_SetTextureCoordinates,
2300     d3drm_mesh_builder3_SetVertexColor,
2301     d3drm_mesh_builder3_SetVertexColorRGB,
2302     d3drm_mesh_builder3_GetFaces,
2303     d3drm_mesh_builder3_GetGeometry,
2304     d3drm_mesh_builder3_GetTextureCoordinates,
2305     d3drm_mesh_builder3_AddVertex,
2306     d3drm_mesh_builder3_AddNormal,
2307     d3drm_mesh_builder3_CreateFace,
2308     d3drm_mesh_builder3_GetQuality,
2309     d3drm_mesh_builder3_GetPerspective,
2310     d3drm_mesh_builder3_GetFaceCount,
2311     d3drm_mesh_builder3_GetVertexCount,
2312     d3drm_mesh_builder3_GetVertexColor,
2313     d3drm_mesh_builder3_CreateMesh,
2314     d3drm_mesh_builder3_GetFace,
2315     d3drm_mesh_builder3_GetVertex,
2316     d3drm_mesh_builder3_GetNormal,
2317     d3drm_mesh_builder3_DeleteVertices,
2318     d3drm_mesh_builder3_DeleteNormals,
2319     d3drm_mesh_builder3_DeleteFace,
2320     d3drm_mesh_builder3_Empty,
2321     d3drm_mesh_builder3_Optimize,
2322     d3drm_mesh_builder3_AddFacesIndexed,
2323     d3drm_mesh_builder3_CreateSubMesh,
2324     d3drm_mesh_builder3_GetParentMesh,
2325     d3drm_mesh_builder3_GetSubMeshes,
2326     d3drm_mesh_builder3_DeleteSubMesh,
2327     d3drm_mesh_builder3_Enable,
2328     d3drm_mesh_builder3_GetEnable,
2329     d3drm_mesh_builder3_AddTriangles,
2330     d3drm_mesh_builder3_SetVertices,
2331     d3drm_mesh_builder3_GetVertices,
2332     d3drm_mesh_builder3_SetNormals,
2333     d3drm_mesh_builder3_GetNormals,
2334     d3drm_mesh_builder3_GetNormalCount,
2335 };
2336 
2337 HRESULT d3drm_mesh_builder_create(struct d3drm_mesh_builder **mesh_builder, IDirect3DRM *d3drm)
2338 {
2339     static const char classname[] = "Builder";
2340     struct d3drm_mesh_builder *object;
2341 
2342     TRACE("mesh_builder %p.\n", mesh_builder);
2343 
2344     if (!(object = heap_alloc_zero(sizeof(*object))))
2345         return E_OUTOFMEMORY;
2346 
2347     object->IDirect3DRMMeshBuilder2_iface.lpVtbl = &d3drm_mesh_builder2_vtbl;
2348     object->IDirect3DRMMeshBuilder3_iface.lpVtbl = &d3drm_mesh_builder3_vtbl;
2349     object->ref = 1;
2350     object->d3drm = d3drm;
2351     IDirect3DRM_AddRef(object->d3drm);
2352 
2353     d3drm_object_init(&object->obj, classname);
2354 
2355     *mesh_builder = object;
2356 
2357     return S_OK;
2358 }
2359 
2360 static HRESULT WINAPI d3drm_mesh_QueryInterface(IDirect3DRMMesh *iface, REFIID riid, void **out)
2361 {
2362     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
2363 
2364     if (IsEqualGUID(riid, &IID_IDirect3DRMMesh)
2365             || IsEqualGUID(riid, &IID_IDirect3DRMVisual)
2366             || IsEqualGUID(riid, &IID_IDirect3DRMObject)
2367             || IsEqualGUID(riid, &IID_IUnknown))
2368     {
2369         IDirect3DRMMesh_AddRef(iface);
2370         *out = iface;
2371         return S_OK;
2372     }
2373 
2374     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
2375 
2376     *out = NULL;
2377     return E_NOINTERFACE;
2378 }
2379 
2380 static ULONG WINAPI d3drm_mesh_AddRef(IDirect3DRMMesh *iface)
2381 {
2382     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2383     ULONG refcount = InterlockedIncrement(&mesh->ref);
2384 
2385     TRACE("%p increasing refcount to %u.\n", iface, refcount);
2386 
2387     return refcount;
2388 }
2389 
2390 static ULONG WINAPI d3drm_mesh_Release(IDirect3DRMMesh *iface)
2391 {
2392     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2393     ULONG refcount = InterlockedDecrement(&mesh->ref);
2394 
2395     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2396 
2397     if (!refcount)
2398     {
2399         DWORD i;
2400 
2401         d3drm_object_cleanup((IDirect3DRMObject *)iface, &mesh->obj);
2402         IDirect3DRM_Release(mesh->d3drm);
2403         for (i = 0; i < mesh->nb_groups; ++i)
2404         {
2405             heap_free(mesh->groups[i].vertices);
2406             heap_free(mesh->groups[i].face_data);
2407             if (mesh->groups[i].material)
2408                 IDirect3DRMMaterial2_Release(mesh->groups[i].material);
2409             if (mesh->groups[i].texture)
2410                 IDirect3DRMTexture3_Release(mesh->groups[i].texture);
2411         }
2412         heap_free(mesh->groups);
2413         heap_free(mesh);
2414     }
2415 
2416     return refcount;
2417 }
2418 
2419 static HRESULT WINAPI d3drm_mesh_Clone(IDirect3DRMMesh *iface,
2420         IUnknown *outer, REFIID iid, void **out)
2421 {
2422     FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
2423 
2424     return E_NOTIMPL;
2425 }
2426 
2427 static HRESULT WINAPI d3drm_mesh_AddDestroyCallback(IDirect3DRMMesh *iface,
2428         D3DRMOBJECTCALLBACK cb, void *ctx)
2429 {
2430     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2431 
2432     TRACE("iface %p, cb %p, ctx %p.\n", iface, cb, ctx);
2433 
2434     return d3drm_object_add_destroy_callback(&mesh->obj, cb, ctx);
2435 }
2436 
2437 static HRESULT WINAPI d3drm_mesh_DeleteDestroyCallback(IDirect3DRMMesh *iface,
2438         D3DRMOBJECTCALLBACK cb, void *ctx)
2439 {
2440     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2441 
2442     TRACE("iface %p, cb %p, ctx %p.\n", iface, cb, ctx);
2443 
2444     return d3drm_object_delete_destroy_callback(&mesh->obj, cb, ctx);
2445 }
2446 
2447 static HRESULT WINAPI d3drm_mesh_SetAppData(IDirect3DRMMesh *iface, DWORD data)
2448 {
2449     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2450 
2451     TRACE("iface %p, data %#x.\n", iface, data);
2452 
2453     mesh->obj.appdata = data;
2454 
2455     return D3DRM_OK;
2456 }
2457 
2458 static DWORD WINAPI d3drm_mesh_GetAppData(IDirect3DRMMesh *iface)
2459 {
2460     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2461 
2462     TRACE("iface %p.\n", iface);
2463 
2464     return mesh->obj.appdata;
2465 }
2466 
2467 static HRESULT WINAPI d3drm_mesh_SetName(IDirect3DRMMesh *iface, const char *name)
2468 {
2469     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2470 
2471     TRACE("iface %p, name %s.\n", iface, debugstr_a(name));
2472 
2473     return d3drm_object_set_name(&mesh->obj, name);
2474 }
2475 
2476 static HRESULT WINAPI d3drm_mesh_GetName(IDirect3DRMMesh *iface, DWORD *size, char *name)
2477 {
2478     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2479 
2480     TRACE("iface %p, size %p, name %p.\n", iface, size, name);
2481 
2482     return d3drm_object_get_name(&mesh->obj, size, name);
2483 }
2484 
2485 static HRESULT WINAPI d3drm_mesh_GetClassName(IDirect3DRMMesh *iface, DWORD *size, char *name)
2486 {
2487     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2488 
2489     TRACE("iface %p, size %p, name %p.\n", iface, size, name);
2490 
2491     return d3drm_object_get_class_name(&mesh->obj, size, name);
2492 }
2493 
2494 static HRESULT WINAPI d3drm_mesh_Scale(IDirect3DRMMesh *iface,
2495         D3DVALUE sx, D3DVALUE sy, D3DVALUE sz)
2496 {
2497     FIXME("iface %p, sx %.8e, sy %.8e, sz %.8e stub!\n", iface, sx, sy, sz);
2498 
2499     return E_NOTIMPL;
2500 }
2501 
2502 static HRESULT WINAPI d3drm_mesh_Translate(IDirect3DRMMesh *iface,
2503         D3DVALUE tx, D3DVALUE ty, D3DVALUE tz)
2504 {
2505     FIXME("iface %p, tx %.8e, ty %.8e, tz %.8e stub!\n", iface, tx, ty, tz);
2506 
2507     return E_NOTIMPL;
2508 }
2509 
2510 static HRESULT WINAPI d3drm_mesh_GetBox(IDirect3DRMMesh *iface, D3DRMBOX *box)
2511 {
2512     FIXME("iface %p, box %p stub!\n", iface, box);
2513 
2514     return E_NOTIMPL;
2515 }
2516 
2517 static HRESULT WINAPI d3drm_mesh_AddGroup(IDirect3DRMMesh *iface, unsigned vertex_count,
2518         unsigned face_count, unsigned vertex_per_face, unsigned *face_data, D3DRMGROUPINDEX *id)
2519 {
2520     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2521     struct mesh_group *group;
2522 
2523     TRACE("iface %p, vertex_count %u, face_count %u, vertex_per_face %u, face_data %p, id %p.\n",
2524             iface, vertex_count, face_count, vertex_per_face, face_data, id);
2525 
2526     if (!face_data || !id)
2527         return E_POINTER;
2528 
2529     if (!d3drm_array_reserve((void **)&mesh->groups, &mesh->groups_size, mesh->nb_groups + 1, sizeof(*mesh->groups)))
2530         return E_OUTOFMEMORY;
2531 
2532     group = mesh->groups + mesh->nb_groups;
2533 
2534     if (!(group->vertices = heap_calloc(vertex_count, sizeof(*group->vertices))))
2535         return E_OUTOFMEMORY;
2536     group->nb_vertices = vertex_count;
2537     group->nb_faces = face_count;
2538     group->vertex_per_face = vertex_per_face;
2539 
2540     if (vertex_per_face)
2541     {
2542         group->face_data_size = face_count * vertex_per_face;
2543     }
2544     else
2545     {
2546         unsigned i;
2547         unsigned nb_indices;
2548         unsigned* face_data_ptr = face_data;
2549         group->face_data_size = 0;
2550 
2551         for (i = 0; i < face_count; i++)
2552         {
2553             nb_indices = *face_data_ptr;
2554             group->face_data_size += nb_indices + 1;
2555             face_data_ptr += nb_indices;
2556         }
2557     }
2558 
2559     if (!(group->face_data = heap_calloc(group->face_data_size, sizeof(*group->face_data))))
2560     {
2561         heap_free(group->vertices);
2562         return E_OUTOFMEMORY;
2563     }
2564     memcpy(group->face_data, face_data, group->face_data_size * sizeof(*face_data));
2565 
2566     group->material = NULL;
2567     group->texture = NULL;
2568 
2569     *id = mesh->nb_groups++;
2570 
2571     return D3DRM_OK;
2572 }
2573 
2574 static HRESULT WINAPI d3drm_mesh_SetVertices(IDirect3DRMMesh *iface, D3DRMGROUPINDEX group_id,
2575         unsigned int start_idx, unsigned int count, D3DRMVERTEX *values)
2576 {
2577     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2578 
2579     TRACE("iface %p, group_id %#x, start_idx %u, count %u, values %p.\n",
2580             iface, group_id, start_idx, count, values);
2581 
2582     if (group_id >= mesh->nb_groups)
2583         return D3DRMERR_BADVALUE;
2584 
2585     if ((start_idx + count - 1) >= mesh->groups[group_id].nb_vertices)
2586         return D3DRMERR_BADVALUE;
2587 
2588     if (!values)
2589         return E_POINTER;
2590 
2591     memcpy(mesh->groups[group_id].vertices + start_idx, values, count * sizeof(*values));
2592 
2593     return D3DRM_OK;
2594 }
2595 
2596 static HRESULT WINAPI d3drm_mesh_SetGroupColor(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id, D3DCOLOR color)
2597 {
2598     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2599 
2600     TRACE("iface %p, id %#x, color 0x%08x.\n", iface, id, color);
2601 
2602     if (id >= mesh->nb_groups)
2603         return D3DRMERR_BADVALUE;
2604 
2605     mesh->groups[id].color = color;
2606 
2607     return D3DRM_OK;
2608 }
2609 
2610 static HRESULT WINAPI d3drm_mesh_SetGroupColorRGB(IDirect3DRMMesh *iface,
2611         D3DRMGROUPINDEX id, D3DVALUE red, D3DVALUE green, D3DVALUE blue)
2612 {
2613     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2614 
2615     TRACE("iface %p, id %#x, red %.8e, green %.8e, blue %.8e.\n", iface, id, red, green, blue);
2616 
2617     if (id >= mesh->nb_groups)
2618         return D3DRMERR_BADVALUE;
2619 
2620     d3drm_set_color(&mesh->groups[id].color, red, green, blue, 1.0f);
2621 
2622     return D3DRM_OK;
2623 }
2624 
2625 static HRESULT WINAPI d3drm_mesh_SetGroupMapping(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id, D3DRMMAPPING value)
2626 {
2627     FIXME("iface %p, id %#x, value %#x stub!\n", iface, id, value);
2628 
2629     return E_NOTIMPL;
2630 }
2631 
2632 static HRESULT WINAPI d3drm_mesh_SetGroupQuality(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id, D3DRMRENDERQUALITY value)
2633 {
2634     FIXME("iface %p, id %#x, value %#x stub!\n", iface, id, value);
2635 
2636     return E_NOTIMPL;
2637 }
2638 
2639 static HRESULT WINAPI d3drm_mesh_SetGroupMaterial(IDirect3DRMMesh *iface,
2640         D3DRMGROUPINDEX id, IDirect3DRMMaterial *material)
2641 {
2642     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2643 
2644     TRACE("iface %p, id %#x, material %p.\n", iface, id, material);
2645 
2646     if (id >= mesh->nb_groups)
2647         return D3DRMERR_BADVALUE;
2648 
2649     if (mesh->groups[id].material)
2650         IDirect3DRMMaterial2_Release(mesh->groups[id].material);
2651 
2652     mesh->groups[id].material = (IDirect3DRMMaterial2 *)material;
2653 
2654     if (material)
2655         IDirect3DRMMaterial2_AddRef(mesh->groups[id].material);
2656 
2657     return D3DRM_OK;
2658 }
2659 
2660 static HRESULT WINAPI d3drm_mesh_SetGroupTexture(IDirect3DRMMesh *iface,
2661         D3DRMGROUPINDEX id, IDirect3DRMTexture *texture)
2662 {
2663     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2664 
2665     TRACE("iface %p, id %#x, texture %p.\n", iface, id, texture);
2666 
2667     if (id >= mesh->nb_groups)
2668         return D3DRMERR_BADVALUE;
2669 
2670     if (mesh->groups[id].texture)
2671         IDirect3DRMTexture3_Release(mesh->groups[id].texture);
2672 
2673     if (!texture)
2674     {
2675         mesh->groups[id].texture = NULL;
2676         return D3DRM_OK;
2677     }
2678 
2679     return IDirect3DRMTexture3_QueryInterface(texture, &IID_IDirect3DRMTexture, (void **)&mesh->groups[id].texture);
2680 }
2681 
2682 static DWORD WINAPI d3drm_mesh_GetGroupCount(IDirect3DRMMesh *iface)
2683 {
2684     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2685 
2686     TRACE("iface %p.\n", iface);
2687 
2688     return mesh->nb_groups;
2689 }
2690 
2691 static HRESULT WINAPI d3drm_mesh_GetGroup(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id, unsigned *vertex_count,
2692         unsigned *face_count, unsigned *vertex_per_face, DWORD *face_data_size, unsigned *face_data)
2693 {
2694     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2695 
2696     TRACE("iface %p, id %#x, vertex_count %p, face_count %p, vertex_per_face %p, face_data_size %p, face_data %p.\n",
2697             iface, id, vertex_count, face_count, vertex_per_face, face_data_size,face_data);
2698 
2699     if (id >= mesh->nb_groups)
2700         return D3DRMERR_BADVALUE;
2701 
2702     if (vertex_count)
2703         *vertex_count = mesh->groups[id].nb_vertices;
2704     if (face_count)
2705         *face_count = mesh->groups[id].nb_faces;
2706     if (vertex_per_face)
2707         *vertex_per_face = mesh->groups[id].vertex_per_face;
2708     if (face_data_size)
2709         *face_data_size = mesh->groups[id].face_data_size;
2710     if (face_data)
2711         memcpy(face_data, mesh->groups[id].face_data, mesh->groups[id].face_data_size * sizeof(*face_data));
2712 
2713     return D3DRM_OK;
2714 }
2715 
2716 static HRESULT WINAPI d3drm_mesh_GetVertices(IDirect3DRMMesh *iface,
2717         D3DRMGROUPINDEX group_id, DWORD start_idx, DWORD count, D3DRMVERTEX *vertices)
2718 {
2719     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2720 
2721     TRACE("iface %p, group_id %#x, start_idx %u, count %u, vertices %p.\n",
2722             iface, group_id, start_idx, count, vertices);
2723 
2724     if (group_id >= mesh->nb_groups)
2725         return D3DRMERR_BADVALUE;
2726 
2727     if ((start_idx + count - 1) >= mesh->groups[group_id].nb_vertices)
2728         return D3DRMERR_BADVALUE;
2729 
2730     if (!vertices)
2731         return E_POINTER;
2732 
2733     memcpy(vertices, mesh->groups[group_id].vertices + start_idx, count * sizeof(*vertices));
2734 
2735     return D3DRM_OK;
2736 }
2737 
2738 static D3DCOLOR WINAPI d3drm_mesh_GetGroupColor(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id)
2739 {
2740     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2741 
2742     TRACE("iface %p, id %#x.\n", iface, id);
2743 
2744     return mesh->groups[id].color;
2745 }
2746 
2747 static D3DRMMAPPING WINAPI d3drm_mesh_GetGroupMapping(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id)
2748 {
2749     FIXME("iface %p, id %#x stub!\n", iface, id);
2750 
2751     return 0;
2752 }
2753 static D3DRMRENDERQUALITY WINAPI d3drm_mesh_GetGroupQuality(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id)
2754 {
2755     FIXME("iface %p, id %#x stub!\n", iface, id);
2756 
2757     return 0;
2758 }
2759 
2760 static HRESULT WINAPI d3drm_mesh_GetGroupMaterial(IDirect3DRMMesh *iface,
2761         D3DRMGROUPINDEX id, IDirect3DRMMaterial **material)
2762 {
2763     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2764 
2765     TRACE("iface %p, id %#x, material %p.\n", iface, id, material);
2766 
2767     if (id >= mesh->nb_groups)
2768         return D3DRMERR_BADVALUE;
2769 
2770     if (!material)
2771         return E_POINTER;
2772 
2773     if (mesh->groups[id].material)
2774         IDirect3DRMTexture_QueryInterface(mesh->groups[id].material, &IID_IDirect3DRMMaterial, (void **)material);
2775     else
2776         *material = NULL;
2777 
2778     return D3DRM_OK;
2779 }
2780 
2781 static HRESULT WINAPI d3drm_mesh_GetGroupTexture(IDirect3DRMMesh *iface,
2782         D3DRMGROUPINDEX id, IDirect3DRMTexture **texture)
2783 {
2784     struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
2785 
2786     TRACE("iface %p, id %#x, texture %p.\n", iface, id, texture);
2787 
2788     if (id >= mesh->nb_groups)
2789         return D3DRMERR_BADVALUE;
2790 
2791     if (!texture)
2792         return E_POINTER;
2793 
2794     if (mesh->groups[id].texture)
2795         IDirect3DRMTexture_QueryInterface(mesh->groups[id].texture, &IID_IDirect3DRMTexture, (void **)texture);
2796     else
2797         *texture = NULL;
2798 
2799     return D3DRM_OK;
2800 }
2801 
2802 static const struct IDirect3DRMMeshVtbl d3drm_mesh_vtbl =
2803 {
2804     d3drm_mesh_QueryInterface,
2805     d3drm_mesh_AddRef,
2806     d3drm_mesh_Release,
2807     d3drm_mesh_Clone,
2808     d3drm_mesh_AddDestroyCallback,
2809     d3drm_mesh_DeleteDestroyCallback,
2810     d3drm_mesh_SetAppData,
2811     d3drm_mesh_GetAppData,
2812     d3drm_mesh_SetName,
2813     d3drm_mesh_GetName,
2814     d3drm_mesh_GetClassName,
2815     d3drm_mesh_Scale,
2816     d3drm_mesh_Translate,
2817     d3drm_mesh_GetBox,
2818     d3drm_mesh_AddGroup,
2819     d3drm_mesh_SetVertices,
2820     d3drm_mesh_SetGroupColor,
2821     d3drm_mesh_SetGroupColorRGB,
2822     d3drm_mesh_SetGroupMapping,
2823     d3drm_mesh_SetGroupQuality,
2824     d3drm_mesh_SetGroupMaterial,
2825     d3drm_mesh_SetGroupTexture,
2826     d3drm_mesh_GetGroupCount,
2827     d3drm_mesh_GetGroup,
2828     d3drm_mesh_GetVertices,
2829     d3drm_mesh_GetGroupColor,
2830     d3drm_mesh_GetGroupMapping,
2831     d3drm_mesh_GetGroupQuality,
2832     d3drm_mesh_GetGroupMaterial,
2833     d3drm_mesh_GetGroupTexture,
2834 };
2835 
2836 HRESULT d3drm_mesh_create(struct d3drm_mesh **mesh, IDirect3DRM *d3drm)
2837 {
2838     static const char classname[] = "Mesh";
2839     struct d3drm_mesh *object;
2840 
2841     TRACE("mesh %p, d3drm %p.\n", mesh, d3drm);
2842 
2843     if (!(object = heap_alloc_zero(sizeof(*object))))
2844         return E_OUTOFMEMORY;
2845 
2846     object->IDirect3DRMMesh_iface.lpVtbl = &d3drm_mesh_vtbl;
2847     object->ref = 1;
2848     object->d3drm = d3drm;
2849     IDirect3DRM_AddRef(object->d3drm);
2850 
2851     d3drm_object_init(&object->obj, classname);
2852 
2853     *mesh = object;
2854 
2855     return S_OK;
2856 }
2857 
2858 static HRESULT WINAPI d3drm_wrap_QueryInterface(IDirect3DRMWrap *iface, REFIID riid, void **out)
2859 {
2860     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
2861 
2862     if (IsEqualGUID(riid, &IID_IDirect3DRMWrap)
2863             || IsEqualGUID(riid, &IID_IDirect3DRMObject)
2864             || IsEqualGUID(riid, &IID_IUnknown))
2865     {
2866         IDirect3DRMWrap_AddRef(iface);
2867         *out = iface;
2868         return S_OK;
2869     }
2870 
2871     WARN("%s not implemented.\n", debugstr_guid(riid));
2872 
2873     *out = NULL;
2874     return CLASS_E_CLASSNOTAVAILABLE;
2875 }
2876 
2877 static ULONG WINAPI d3drm_wrap_AddRef(IDirect3DRMWrap *iface)
2878 {
2879     struct d3drm_wrap *wrap = impl_from_IDirect3DRMWrap(iface);
2880     ULONG refcount = InterlockedIncrement(&wrap->ref);
2881 
2882     TRACE("%p increasing refcount to %u.\n", iface, refcount);
2883 
2884     return refcount;
2885 }
2886 
2887 static ULONG WINAPI d3drm_wrap_Release(IDirect3DRMWrap *iface)
2888 {
2889     struct d3drm_wrap *wrap = impl_from_IDirect3DRMWrap(iface);
2890     ULONG refcount = InterlockedDecrement(&wrap->ref);
2891 
2892     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
2893 
2894     if (!refcount)
2895     {
2896         d3drm_object_cleanup((IDirect3DRMObject *)iface, &wrap->obj);
2897         heap_free(wrap);
2898     }
2899 
2900     return refcount;
2901 }
2902 
2903 static HRESULT WINAPI d3drm_wrap_Clone(IDirect3DRMWrap *iface,
2904         IUnknown *outer, REFIID iid, void **out)
2905 {
2906     FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
2907 
2908     return E_NOTIMPL;
2909 }
2910 
2911 static HRESULT WINAPI d3drm_wrap_AddDestroyCallback(IDirect3DRMWrap *iface,
2912         D3DRMOBJECTCALLBACK cb, void *ctx)
2913 {
2914     struct d3drm_wrap *wrap = impl_from_IDirect3DRMWrap(iface);
2915 
2916     TRACE("iface %p, cb %p, ctx %p.\n", iface, cb, ctx);
2917 
2918     return d3drm_object_add_destroy_callback(&wrap->obj, cb, ctx);
2919 }
2920 
2921 static HRESULT WINAPI d3drm_wrap_DeleteDestroyCallback(IDirect3DRMWrap *iface,
2922         D3DRMOBJECTCALLBACK cb, void *ctx)
2923 {
2924     struct d3drm_wrap *wrap = impl_from_IDirect3DRMWrap(iface);
2925 
2926     TRACE("iface %p, cb %p, ctx %p.\n", iface, cb, ctx);
2927 
2928     return d3drm_object_delete_destroy_callback(&wrap->obj, cb, ctx);
2929 }
2930 
2931 static HRESULT WINAPI d3drm_wrap_SetAppData(IDirect3DRMWrap *iface, DWORD data)
2932 {
2933     struct d3drm_wrap *wrap = impl_from_IDirect3DRMWrap(iface);
2934 
2935     TRACE("iface %p, data %#x.\n", iface, data);
2936 
2937     wrap->obj.appdata = data;
2938 
2939     return D3DRM_OK;
2940 }
2941 
2942 static DWORD WINAPI d3drm_wrap_GetAppData(IDirect3DRMWrap *iface)
2943 {
2944     struct d3drm_wrap *wrap = impl_from_IDirect3DRMWrap(iface);
2945 
2946     TRACE("iface %p.\n", iface);
2947 
2948     return wrap->obj.appdata;
2949 }
2950 
2951 static HRESULT WINAPI d3drm_wrap_SetName(IDirect3DRMWrap *iface, const char *name)
2952 {
2953     struct d3drm_wrap *wrap = impl_from_IDirect3DRMWrap(iface);
2954 
2955     TRACE("iface %p, name %s.\n", iface, debugstr_a(name));
2956 
2957     return d3drm_object_set_name(&wrap->obj, name);
2958 }
2959 
2960 static HRESULT WINAPI d3drm_wrap_GetName(IDirect3DRMWrap *iface, DWORD *size, char *name)
2961 {
2962     struct d3drm_wrap *wrap = impl_from_IDirect3DRMWrap(iface);
2963 
2964     TRACE("iface %p, size %p, name %p.\n", iface, size, name);
2965 
2966     return d3drm_object_get_name(&wrap->obj, size, name);
2967 }
2968 
2969 static HRESULT WINAPI d3drm_wrap_GetClassName(IDirect3DRMWrap *iface, DWORD *size, char *name)
2970 {
2971     struct d3drm_wrap *wrap = impl_from_IDirect3DRMWrap(iface);
2972 
2973     TRACE("iface %p, size %p, name %p.\n", iface, size, name);
2974 
2975     return d3drm_object_get_class_name(&wrap->obj, size, name);
2976 }
2977 
2978 static HRESULT WINAPI d3drm_wrap_Init(IDirect3DRMWrap *iface, D3DRMWRAPTYPE type, IDirect3DRMFrame *reference,
2979        D3DVALUE ox, D3DVALUE oy, D3DVALUE oz, D3DVALUE dx, D3DVALUE dy, D3DVALUE dz, D3DVALUE ux,
2980        D3DVALUE uy, D3DVALUE uz, D3DVALUE ou, D3DVALUE ov, D3DVALUE su, D3DVALUE sv)
2981 {
2982     FIXME("iface %p, type %d, reference frame %p, ox %.8e, oy %.8e, oz %.8e, dx %.8e, dy %.8e, dz %.8e, ux %.8e, "
2983             "uy %.8e, uz %.8e, ou %.8e, ov %.8e, su %.8e, sv %.8e.\n", iface, type, reference, ox, oy, oz, dx, dy, dz,
2984             ux, uy, uz, ou, ov, su, sv);
2985 
2986     return E_NOTIMPL;
2987 }
2988 
2989 static HRESULT WINAPI d3drm_wrap_Apply(IDirect3DRMWrap *iface, IDirect3DRMObject *object)
2990 {
2991     FIXME("iface %p, object %p.\n", iface, object);
2992 
2993     return E_NOTIMPL;
2994 }
2995 
2996 static HRESULT WINAPI d3drm_wrap_ApplyRelative(IDirect3DRMWrap *iface, IDirect3DRMFrame *frame,
2997        IDirect3DRMObject *object)
2998 {
2999     FIXME("iface %p, frame %p, object %p.\n", iface, frame, object);
3000 
3001     return E_NOTIMPL;
3002 }
3003 
3004 static const struct IDirect3DRMWrapVtbl d3drm_wrap_vtbl =
3005 {
3006     d3drm_wrap_QueryInterface,
3007     d3drm_wrap_AddRef,
3008     d3drm_wrap_Release,
3009     d3drm_wrap_Clone,
3010     d3drm_wrap_AddDestroyCallback,
3011     d3drm_wrap_DeleteDestroyCallback,
3012     d3drm_wrap_SetAppData,
3013     d3drm_wrap_GetAppData,
3014     d3drm_wrap_SetName,
3015     d3drm_wrap_GetName,
3016     d3drm_wrap_GetClassName,
3017     d3drm_wrap_Init,
3018     d3drm_wrap_Apply,
3019     d3drm_wrap_ApplyRelative,
3020 };
3021 
3022 HRESULT d3drm_wrap_create(struct d3drm_wrap **wrap, IDirect3DRM *d3drm)
3023 {
3024     static const char classname[] = "";
3025     struct d3drm_wrap *object;
3026 
3027     TRACE("wrap %p, d3drm %p.\n", wrap, d3drm);
3028 
3029     if (!(object = heap_alloc_zero(sizeof(*object))))
3030         return E_OUTOFMEMORY;
3031 
3032     object->IDirect3DRMWrap_iface.lpVtbl = &d3drm_wrap_vtbl;
3033     object->ref = 1;
3034 
3035     d3drm_object_init(&object->obj, classname);
3036 
3037     *wrap = object;
3038 
3039     return S_OK;
3040 }
3041