diff --git a/dlls/d3drm/meshbuilder.c b/dlls/d3drm/meshbuilder.c index 9d3e67a17c4..4ef2477f1f1 100644 --- a/dlls/d3drm/meshbuilder.c +++ b/dlls/d3drm/meshbuilder.c @@ -59,6 +59,12 @@ typedef struct { D3DVALUE v; } Coords2d; +typedef struct { + D3DCOLOR color; + IDirect3DRMMaterial2 *material; + IDirect3DRMTexture3 *texture; +} mesh_material; + typedef struct { IDirect3DRMMeshBuilder2 IDirect3DRMMeshBuilder2_iface; IDirect3DRMMeshBuilder3 IDirect3DRMMeshBuilder3_iface; @@ -72,10 +78,13 @@ typedef struct { DWORD face_data_size; LPVOID pFaceData; DWORD nb_coords2d; - Coords2d* pCoords2d; + Coords2d *pCoords2d; D3DCOLOR color; - IDirect3DRMMaterial2* material; - IDirect3DRMTexture3* texture; + IDirect3DRMMaterial2 *material; + IDirect3DRMTexture3 *texture; + DWORD nb_materials; + mesh_material *materials; + DWORD *material_indices; } IDirect3DRMMeshBuilderImpl; char templates[] = { @@ -316,6 +325,8 @@ static inline IDirect3DRMMeshBuilderImpl *impl_from_IDirect3DRMMeshBuilder3(IDir static void clean_mesh_builder_data(IDirect3DRMMeshBuilderImpl *mesh_builder) { + int i; + HeapFree(GetProcessHeap(), 0, mesh_builder->name); mesh_builder->name = NULL; HeapFree(GetProcessHeap(), 0, mesh_builder->pVertices); @@ -331,6 +342,16 @@ static void clean_mesh_builder_data(IDirect3DRMMeshBuilderImpl *mesh_builder) HeapFree(GetProcessHeap(), 0, mesh_builder->pCoords2d); mesh_builder->pCoords2d = NULL; mesh_builder->nb_coords2d = 0; + for (i = 0; i < mesh_builder->nb_materials; i++) + { + if (mesh_builder->materials[i].material) + IDirect3DRMMaterial2_Release(mesh_builder->materials[i].material); + if (mesh_builder->materials[i].texture) + IDirect3DRMTexture3_Release(mesh_builder->materials[i].texture); + } + mesh_builder->nb_materials = 0; + HeapFree(GetProcessHeap(), 0, mesh_builder->materials); + HeapFree(GetProcessHeap(), 0, mesh_builder->material_indices); } /*** IUnknown methods ***/ @@ -1251,24 +1272,25 @@ HRESULT load_mesh_data(IDirect3DRMMeshBuilder3* iface, LPDIRECTXFILEDATA pData) if (size != data_size) WARN("Returned size %u does not match expected one %u\n", size, data_size); - if (nb_materials > 1) - FIXME("Only one material per mesh supported, first one applies to all faces\n"); + This->material_indices = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->material_indices) * nb_face_indices); + if (!This->material_indices) + goto end; + memcpy(This->material_indices, ptr + 2 * sizeof(DWORD), sizeof(*This->material_indices) * nb_face_indices), + + This->materials = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->materials) * nb_materials); + if (!This->materials) + { + HeapFree(GetProcessHeap(), 0, This->material_indices); + goto end; + } + This->nb_materials = nb_materials; while (SUCCEEDED(hr = IDirectXFileData_GetNextObject(pData2, &child)) && (i < nb_materials)) { LPDIRECTXFILEDATA data; LPDIRECTXFILEDATAREFERENCE reference; - LPDIRECT3DRMMATERIAL2 material; LPDIRECTXFILEOBJECT material_child; - if (i >= 1) - { - /* FIXME: Only handle first material but enum all of them */ - IDirectXFileObject_Release(child); - i++; - continue; - } - hr = IDirectXFileObject_QueryInterface(child, &IID_IDirectXFileData, (void **)&data); if (FAILED(hr)) { @@ -1287,7 +1309,7 @@ HRESULT load_mesh_data(IDirect3DRMMeshBuilder3* iface, LPDIRECTXFILEDATA pData) IDirectXFileObject_Release(child); } - hr = Direct3DRMMaterial_create(&material); + hr = Direct3DRMMaterial_create(&This->materials[i].material); if (FAILED(hr)) { IDirectXFileData_Release(data); @@ -1306,20 +1328,20 @@ HRESULT load_mesh_data(IDirect3DRMMeshBuilder3* iface, LPDIRECTXFILEDATA pData) values = (float*)ptr; - IDirect3DRMMeshBuilder3_SetColorRGB(iface, values[0], values [1], values[2]); /* Alpha ignored */ + This->materials[i].color = D3DCOLOR_ARGB((BYTE)(values[3] * 255.0f), (BYTE)(values[0] * 255.0f), + (BYTE)(values[1] * 255.0f), (BYTE)(values[2] * 255.0f)); - IDirect3DRMMaterial2_SetAmbient(material, values[0], values [1], values[2]); /* Alpha ignored */ - IDirect3DRMMaterial2_SetPower(material, values[4]); - IDirect3DRMMaterial2_SetSpecular(material, values[5], values[6], values[7]); - IDirect3DRMMaterial2_SetEmissive(material, values[8], values[9], values[10]); + IDirect3DRMMaterial2_SetAmbient(This->materials[i].material, values[0], values [1], values[2]); /* Alpha ignored */ + IDirect3DRMMaterial2_SetPower(This->materials[i].material, values[4]); + IDirect3DRMMaterial2_SetSpecular(This->materials[i].material, values[5], values[6], values[7]); + IDirect3DRMMaterial2_SetEmissive(This->materials[i].material, values[8], values[9], values[10]); - This->material = material; + This->materials[i].texture = NULL; hr = IDirectXFileData_GetNextObject(data, &material_child); if (hr == S_OK) { LPDIRECTXFILEDATA data; - LPDIRECT3DRMTEXTURE3 texture; char** filename; hr = IDirectXFileObject_QueryInterface(material_child, &IID_IDirectXFileData, (void **)&data); @@ -1352,16 +1374,18 @@ HRESULT load_mesh_data(IDirect3DRMMeshBuilder3* iface, LPDIRECTXFILEDATA pData) { HANDLE file; + /* If the texture file is not found, no texture is associated with the material */ file = CreateFileA(*filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (file != INVALID_HANDLE_VALUE) { - hr = Direct3DRMTexture_create(&IID_IDirect3DRMTexture3, (LPUNKNOWN*)&texture); + CloseHandle(file); + + hr = Direct3DRMTexture_create(&IID_IDirect3DRMTexture3, (LPUNKNOWN*)&This->materials[i].texture); if (FAILED(hr)) { IDirectXFileData_Release(data); goto end; } - This->texture = texture; } } } @@ -2048,7 +2072,6 @@ static HRESULT WINAPI IDirect3DRMMeshBuilder3Impl_CreateMesh(IDirect3DRMMeshBuil IDirect3DRMMeshBuilderImpl *This = impl_from_IDirect3DRMMeshBuilder3(iface); HRESULT hr; D3DRMGROUPINDEX group; - ULONG vertex_per_face = 0; TRACE("(%p)->(%p)\n", This, mesh); @@ -2062,10 +2085,7 @@ static HRESULT WINAPI IDirect3DRMMeshBuilder3Impl_CreateMesh(IDirect3DRMMeshBuil /* If there is mesh data, create a group and put data inside */ if (This->nb_vertices) { - unsigned* face_data; - unsigned* out_ptr; - DWORD* in_ptr = This->pFaceData; - int i, j; + int i, j, k; D3DRMVERTEX* vertices; vertices = HeapAlloc(GetProcessHeap(), 0, This->nb_vertices * sizeof(D3DRMVERTEX)); @@ -2079,63 +2099,103 @@ static HRESULT WINAPI IDirect3DRMMeshBuilder3Impl_CreateMesh(IDirect3DRMMeshBuil hr = IDirect3DRMMesh_SetVertices(*mesh, 0, 0, This->nb_vertices, vertices); HeapFree(GetProcessHeap(), 0, vertices); - face_data = HeapAlloc(GetProcessHeap(), 0, This->face_data_size * sizeof(DWORD)); - if (!face_data) + /* Groups are in reverse order compared to materials list in X file */ + for (k = This->nb_materials - 1; k >= 0; k--) { - IDirect3DRMMesh_Release(*mesh); - return E_OUTOFMEMORY; - } - out_ptr = face_data; + unsigned* face_data; + unsigned* out_ptr; + DWORD* in_ptr = This->pFaceData; + ULONG vertex_per_face = 0; + BOOL* used_vertices; + unsigned nb_vertices = 0; + unsigned nb_faces = 0; - /* If all faces have the same number of vertex, set vertex_per_face */ - for (i = 0; i < This->nb_faces; i++) - { - if (vertex_per_face && (vertex_per_face != *in_ptr)) - break; - vertex_per_face = *in_ptr; - in_ptr += 1 + *in_ptr * 2; - } - if (i != This->nb_faces) - vertex_per_face = 0; - - /* Put only vertex indices */ - in_ptr = This->pFaceData; - for (i = 0; i < This->nb_faces; i++) - { - DWORD nb_indices = *in_ptr++; - - /* Don't put nb indices when vertex_per_face is set */ - if (vertex_per_face) - *out_ptr++ = nb_indices; - - for (j = 0; j < nb_indices; j++) + used_vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->face_data_size * sizeof(*used_vertices)); + if (!used_vertices) { - *out_ptr++ = *in_ptr++; - /* Skip normal index */ - in_ptr++; + IDirect3DRMMesh_Release(*mesh); + return E_OUTOFMEMORY; + } + + face_data = HeapAlloc(GetProcessHeap(), 0, This->face_data_size * sizeof(*face_data)); + if (!face_data) + { + IDirect3DRMMesh_Release(*mesh); + return E_OUTOFMEMORY; + } + out_ptr = face_data; + + /* If all faces have the same number of vertex, set vertex_per_face */ + for (i = 0; i < This->nb_faces; i++) + { + /* Process only faces belonging to the group */ + if (This->material_indices[i] == k) + { + if (vertex_per_face && (vertex_per_face != *in_ptr)) + break; + vertex_per_face = *in_ptr; + } + in_ptr += 1 + *in_ptr * 2; + } + if (i != This->nb_faces) + vertex_per_face = 0; + + /* Put only vertex indices */ + in_ptr = This->pFaceData; + for (i = 0; i < This->nb_faces; i++) + { + DWORD nb_indices = *in_ptr++; + + /* Skip faces not belonging to the group */ + if (This->material_indices[i] != k) + { + in_ptr += 2 * nb_indices; + continue; + } + + /* Don't put nb indices when vertex_per_face is set */ + if (vertex_per_face) + *out_ptr++ = nb_indices; + + for (j = 0; j < nb_indices; j++) + { + *out_ptr = *in_ptr++; + used_vertices[*out_ptr++] = TRUE; + /* Skip normal index */ + in_ptr++; + } + + nb_faces++; + } + + for (i = 0; i < This->nb_vertices; i++) + if (used_vertices[i]) + nb_vertices++; + + hr = IDirect3DRMMesh_AddGroup(*mesh, nb_vertices, nb_faces, vertex_per_face, face_data, &group); + HeapFree(GetProcessHeap(), 0, used_vertices); + HeapFree(GetProcessHeap(), 0, face_data); + if (SUCCEEDED(hr)) + hr = IDirect3DRMMesh_SetGroupColor(*mesh, group, This->materials[k].color); + if (SUCCEEDED(hr)) + hr = IDirect3DRMMesh_SetGroupMaterial(*mesh, group, (LPDIRECT3DRMMATERIAL)This->materials[k].material); + if (SUCCEEDED(hr) && This->materials[k].texture) + { + LPDIRECT3DRMTEXTURE texture; + + IDirect3DRMTexture3_QueryInterface(This->materials[k].texture, &IID_IDirect3DRMTexture, (LPVOID*)&texture); + hr = IDirect3DRMMesh_SetGroupTexture(*mesh, group, texture); + IDirect3DRMTexture_Release(texture); + } + if (FAILED(hr)) + { + IDirect3DRMMesh_Release(*mesh); + return hr; } } - - hr = IDirect3DRMMesh_AddGroup(*mesh, This->nb_vertices, This->nb_faces, vertex_per_face, face_data, &group); - HeapFree(GetProcessHeap(), 0, face_data); - - if (SUCCEEDED(hr)) - hr = IDirect3DRMMesh_SetGroupColor(*mesh, 0, This->color); - if (SUCCEEDED(hr)) - hr = IDirect3DRMMesh_SetGroupMaterial(*mesh, 0, (LPDIRECT3DRMMATERIAL)This->material); - if (SUCCEEDED(hr) && This->texture) - { - LPDIRECT3DRMTEXTURE texture; - - IDirect3DRMTexture3_QueryInterface(This->texture, &IID_IDirect3DRMTexture, (LPVOID*)&texture); - hr = IDirect3DRMMesh_SetGroupTexture(*mesh, 0, texture); - IDirect3DRMTexture_Release(texture); - } - if (FAILED(hr)) - IDirect3DRMMesh_Release(*mesh); } - return hr; + return D3DRM_OK; } static HRESULT WINAPI IDirect3DRMMeshBuilder3Impl_GetFace(IDirect3DRMMeshBuilder3* iface, diff --git a/dlls/d3drm/tests/d3drm.c b/dlls/d3drm/tests/d3drm.c index 7fee3e1f7b5..97e047aa73d 100644 --- a/dlls/d3drm/tests/d3drm.c +++ b/dlls/d3drm/tests/d3drm.c @@ -180,6 +180,48 @@ static char data_d3drm_load[] = " 0.9, 1.0, 1.1;;\n" "}\n"; +static char data_frame_mesh_materials[] = +"xof 0302txt 0064\n" +"Header { 1; 0; 1; }\n" +"Frame {\n" +" Mesh mesh1 {\n" +" 5;\n" +" 0.1; 0.2; 0.3;,\n" +" 0.4; 0.5; 0.6;,\n" +" 0.7; 0.8; 0.9;,\n" +" 1.1; 1.2; 1.3;,\n" +" 1.4; 1.5; 1.6;;\n" +" 6;\n" +" 3; 0, 1, 2;,\n" +" 3; 0, 2, 1;,\n" +" 3; 1, 2, 3;,\n" +" 3; 1, 3, 2;,\n" +" 3; 2, 3, 4;,\n" +" 3; 2, 4, 3;;\n" +" MeshMaterialList {\n" +" 3; 6; 0, 1, 1, 2, 2, 2;\n" +" Material mat1 {\n" +" 1.0; 0.0; 0.0; 0.1;;\n" +" 10.0;\n" +" 0.11; 0.12; 0.13;;\n" +" 0.14; 0.15; 0.16;;\n" +" }\n" +" Material mat2 {\n" +" 0.0; 1.0; 0.0; 0.2;;\n" +" 20.0;\n" +" 0.21; 0.22; 0.23;;\n" +" 0.24; 0.25; 0.26;;\n" +" }\n" +" Material mat3 {\n" +" 0.0; 0.0; 1.0; 0.3;;\n" +" 30.0;\n" +" 0.31; 0.32; 0.33;;\n" +" 0.34; 0.35; 0.36;;\n" +" }\n" +" }\n" +" }\n" +"}\n"; + static void test_MeshBuilder(void) { HRESULT hr; @@ -1304,6 +1346,131 @@ static void test_d3drm_load(void) IDirect3DRM_Release(pD3DRM); } +IDirect3DRMMeshBuilder *mesh_builder = NULL; + +static void __cdecl object_load_callback_frame(IDirect3DRMObject *object, REFIID object_guid, void *arg) +{ + HRESULT hr; + IDirect3DRMFrame *frame; + IDirect3DRMVisualArray *array; + IDirect3DRMVisual *visual; + ULONG size; + char name[128]; + + hr = IDirect3DRMObject_QueryInterface(object, &IID_IDirect3DRMFrame, (void**)&frame); + ok(hr == D3DRM_OK, "IDirect3DRMObject_QueryInterface returned %x\n", hr); + + hr = IDirect3DRMFrame_GetVisuals(frame, &array); + ok(hr == D3DRM_OK, "IDirect3DRMFrame_GetVisuals returned %x\n", hr); + + size = IDirect3DRMVisualArray_GetSize(array); + ok(size == 1, "Wrong size %u returned, expected 1\n", size); + + hr = IDirect3DRMVisualArray_GetElement(array, 0, &visual); + ok(hr == D3DRM_OK, "IDirect3DRMVisualArray_GetElement returned %x\n", hr); + + hr = IDirect3DRMVisual_QueryInterface(visual, &IID_IDirect3DRMMeshBuilder, (void**)&mesh_builder); + ok(hr == D3DRM_OK, "IDirect3DRMVisualArray_GetSize returned %x\n", hr); + + size = sizeof(name); + hr = IDirect3DRMMeshBuilder_GetName(mesh_builder, &size, name); + ok(hr == D3DRM_OK, "IDirect3DRMMeshBuilder_GetName returned %x\n", hr); + ok(!strcmp(name, "mesh1"), "Wrong name %s, expected mesh1\n", name); + + IDirect3DRMVisual_Release(visual); + IDirect3DRMVisualArray_Release(array); + IDirect3DRMFrame_Release(frame); +} + +struct { + int vertex_count; + int face_count; + int vertex_per_face; + int face_data_size; + DWORD color; + float power; + float specular[3]; + float emissive[3]; +} groups[3] = { + { 4, 3, 3, 9, 0x4c0000ff, 30.0f, { 0.31f, 0.32f, 0.33f }, { 0.34f, 0.35f, 0.36f } }, + { 4, 2, 3, 6, 0x3300ff00, 20.0f, { 0.21f, 0.22f, 0.23f }, { 0.24f, 0.25f, 0.26f } }, + { 3, 1, 3, 3, 0x19ff0000, 10.0f, { 0.11f, 0.12f, 0.13f }, { 0.14f, 0.15f, 0.16f } } +}; + +static void test_frame_mesh_materials(void) +{ + HRESULT hr; + IDirect3DRM *d3drm; + D3DRMLOADMEMORY info; + const GUID *req_refiids[] = { &IID_IDirect3DRMFrame }; + IDirect3DRMMesh *mesh; + ULONG size; + IDirect3DRMMaterial *material; + IDirect3DRMTexture *texture; + int i; + + hr = pDirect3DRMCreate(&d3drm); + ok(hr == D3DRM_OK, "Direct3DRMCreate returned %x\n", hr); + + info.lpMemory = data_frame_mesh_materials; + info.dSize = strlen(data_frame_mesh_materials); + hr = IDirect3DRM_Load(d3drm, &info, NULL, (GUID**)req_refiids, 1, D3DRMLOAD_FROMMEMORY, object_load_callback_frame, (void*)0xdeadbeef, NULL, NULL, NULL); + ok(hr == D3DRM_OK, "Cannot load data (hr = %x)\n", hr); + + hr = IDirect3DRMMeshBuilder_CreateMesh(mesh_builder, &mesh); + ok(hr == D3DRM_OK, "IDirect3DRMMeshBuilder_CreateMesh returned %x\n", hr); + + size = IDirect3DRMMesh_GetGroupCount(mesh); + ok(size == 3, "Wrong size %u returned, expected 3\n", size); + + for (i = 0; i < size; i++) + { + D3DVALUE red, green, blue, power; + D3DCOLOR color; + unsigned vertex_count, face_count, vertex_per_face; + DWORD face_data_size; + + hr = IDirect3DRMMesh_GetGroup(mesh, i, &vertex_count, &face_count, &vertex_per_face, &face_data_size, NULL); + ok(hr == D3DRM_OK, "Group %d: IDirect3DRMMesh_GetGroup returned %x\n", i, hr); + ok(vertex_count == groups[i].vertex_count, "Group %d: Wrong vertex count %d, expected %d\n", i, vertex_count, groups[i].vertex_count); + ok(face_count == groups[i].face_count, "Group %d: Wrong face count %d; expected %d\n", i, face_count, groups[i].face_count); + ok(vertex_per_face == groups[i].vertex_per_face, "Group %d: Wrong vertex per face %d, expected %d\n", i, vertex_per_face, groups[i].vertex_per_face); + ok(face_data_size == groups[i].face_data_size, "Group %d: Wrong face data size %d, expected %d\n", i, face_data_size, groups[i].face_data_size); + + color = IDirect3DRMMesh_GetGroupColor(mesh, i); + ok(color == groups[i].color, "Group %d: Wrong color %x, expected %x\n", i, color, groups[i].color); + + hr = IDirect3DRMMesh_GetGroupMaterial(mesh, i, &material); + ok(hr == D3DRM_OK, "Group %d: IDirect3DRMMesh_GetGroupMaterial returned %x\n", i, hr); + ok(material != NULL, "Group %d: No material\n", i); + power = IDirect3DRMMaterial_GetPower(material); + ok(power == groups[i].power, "Group %d: Wrong power %f, expected %f\n", i, power, groups[i].power); + hr = IDirect3DRMMaterial_GetSpecular(material, &red, &green, &blue); + ok(hr == D3DRM_OK, "Group %d: IDirect3DRMMaterial_GetSpecular returned %x\n", i, hr); + ok(red == groups[i].specular[0], "Group %d: Wrong specular red %f, expected %f\n", i, red, groups[i].specular[0]); + ok(green == groups[i].specular[1], "Group %d: Wrong specular green %f, pD3DRMexpected %f\n", i, green, groups[i].specular[1]); + ok(blue == groups[i].specular[2], "Group %d: Wrong specular blue %f, expected %f\n", i, blue, groups[i].specular[2]); + hr = IDirect3DRMMaterial_GetEmissive(material, &red, &green, &blue); + ok(hr == D3DRM_OK, "Group %d: IDirect3DRMMaterial_GetEmissive returned %x\n", i, hr); + ok(red == groups[i].emissive[0], "Group %d: Wrong emissive red %f, expected %f\n", i, red, groups[i].emissive[0]); + ok(green == groups[i].emissive[1], "Group %d: Wrong emissive green %f, expected %f\n", i, green, groups[i].emissive[1]); + ok(blue == groups[i].emissive[2], "Group %d: Wrong emissive blue %f, expected %f\n", i, blue, groups[i].emissive[2]); + + hr = IDirect3DRMMesh_GetGroupTexture(mesh, i, &texture); + ok(hr == D3DRM_OK, "Group %d: IDirect3DRMMesh_GetGroupTexture returned %x\n", i, hr); + ok(!texture, "Group %d: Unexpected texture\n", i); + + if (material) + IDirect3DRMMaterial_Release(material); + if (texture) + IDirect3DRMTexture_Release(texture); + } + + IDirect3DRMMesh_Release(mesh); + IDirect3DRMMeshBuilder_Release(mesh_builder); + IDirect3DRM_Release(d3drm); +} + START_TEST(d3drm) { if (!InitFunctionPtrs()) @@ -1320,6 +1487,7 @@ START_TEST(d3drm) test_Texture(); test_frame_transform(); test_d3drm_load(); + test_frame_mesh_materials(); FreeLibrary(d3drm_handle); }