/src/assimp/code/AssetLib/MDC/MDCLoader.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | --------------------------------------------------------------------------- |
3 | | Open Asset Import Library (assimp) |
4 | | --------------------------------------------------------------------------- |
5 | | |
6 | | Copyright (c) 2006-2025, assimp team |
7 | | |
8 | | All rights reserved. |
9 | | |
10 | | Redistribution and use of this software in source and binary forms, |
11 | | with or without modification, are permitted provided that the following |
12 | | conditions are met: |
13 | | |
14 | | * Redistributions of source code must retain the above |
15 | | copyright notice, this list of conditions and the |
16 | | following disclaimer. |
17 | | |
18 | | * Redistributions in binary form must reproduce the above |
19 | | copyright notice, this list of conditions and the |
20 | | following disclaimer in the documentation and/or other |
21 | | materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the assimp team, nor the names of its |
24 | | contributors may be used to endorse or promote products |
25 | | derived from this software without specific prior |
26 | | written permission of the assimp team. |
27 | | |
28 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
29 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
31 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
32 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
33 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
34 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
35 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
36 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
37 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
38 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
39 | | --------------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | /** @file Implementation of the MDC importer class */ |
43 | | |
44 | | #ifndef ASSIMP_BUILD_NO_MDC_IMPORTER |
45 | | |
46 | | // internal headers |
47 | | #include "MDCLoader.h" |
48 | | #include "AssetLib/MD3/MD3FileData.h" |
49 | | #include "MDCNormalTable.h" // shouldn't be included by other units |
50 | | |
51 | | #include <assimp/importerdesc.h> |
52 | | #include <assimp/scene.h> |
53 | | #include <assimp/DefaultLogger.hpp> |
54 | | #include <assimp/IOSystem.hpp> |
55 | | #include <assimp/Importer.hpp> |
56 | | #include <assimp/StringUtils.h> |
57 | | |
58 | | #include <memory> |
59 | | |
60 | | using namespace Assimp; |
61 | | using namespace Assimp::MDC; |
62 | | |
63 | | static constexpr aiImporterDesc desc = { |
64 | | "Return To Castle Wolfenstein Mesh Importer", |
65 | | "", |
66 | | "", |
67 | | "", |
68 | | aiImporterFlags_SupportBinaryFlavour, |
69 | | 0, |
70 | | 0, |
71 | | 0, |
72 | | 0, |
73 | | "mdc" |
74 | | }; |
75 | | |
76 | | // ------------------------------------------------------------------------------------------------ |
77 | | void MDC::BuildVertex(const Frame &frame, |
78 | | const BaseVertex &bvert, |
79 | | const CompressedVertex &cvert, |
80 | | aiVector3D &vXYZOut, |
81 | 0 | aiVector3D &vNorOut) { |
82 | | // compute the position |
83 | 0 | const float xd = (cvert.xd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING; |
84 | 0 | const float yd = (cvert.yd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING; |
85 | 0 | const float zd = (cvert.zd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING; |
86 | 0 | vXYZOut.x = frame.localOrigin.x + AI_MDC_BASE_SCALING * (bvert.x + xd); |
87 | 0 | vXYZOut.y = frame.localOrigin.y + AI_MDC_BASE_SCALING * (bvert.y + yd); |
88 | 0 | vXYZOut.z = frame.localOrigin.z + AI_MDC_BASE_SCALING * (bvert.z + zd); |
89 | | |
90 | | // compute the normal vector .. ehm ... lookup it in the table :-) |
91 | 0 | vNorOut.x = mdcNormals[cvert.nd][0]; |
92 | 0 | vNorOut.y = mdcNormals[cvert.nd][1]; |
93 | 0 | vNorOut.z = mdcNormals[cvert.nd][2]; |
94 | 0 | } |
95 | | |
96 | | // ------------------------------------------------------------------------------------------------ |
97 | | // Constructor to be privately used by Importer |
98 | | MDCImporter::MDCImporter() : |
99 | | configFrameID(), |
100 | | pcHeader(), |
101 | | mBuffer(), |
102 | 414 | fileSize() { |
103 | | // empty |
104 | 414 | } |
105 | | |
106 | | // ------------------------------------------------------------------------------------------------ |
107 | | // Returns whether the class can handle the format of the given file. |
108 | 221 | bool MDCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { |
109 | 221 | static constexpr uint32_t tokens[] = { AI_MDC_MAGIC_NUMBER_LE }; |
110 | 221 | return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); |
111 | 221 | } |
112 | | |
113 | | // ------------------------------------------------------------------------------------------------ |
114 | 422 | const aiImporterDesc *MDCImporter::GetInfo() const { |
115 | 422 | return &desc; |
116 | 422 | } |
117 | | |
118 | | // ------------------------------------------------------------------------------------------------ |
119 | | // Validate the header of the given MDC file |
120 | 0 | void MDCImporter::ValidateHeader() { |
121 | 0 | AI_SWAP4(this->pcHeader->ulVersion); |
122 | 0 | AI_SWAP4(this->pcHeader->ulFlags); |
123 | 0 | AI_SWAP4(this->pcHeader->ulNumFrames); |
124 | 0 | AI_SWAP4(this->pcHeader->ulNumTags); |
125 | 0 | AI_SWAP4(this->pcHeader->ulNumSurfaces); |
126 | 0 | AI_SWAP4(this->pcHeader->ulNumSkins); |
127 | 0 | AI_SWAP4(this->pcHeader->ulOffsetBorderFrames); |
128 | |
|
129 | 0 | if (pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_BE && |
130 | 0 | pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_LE) { |
131 | 0 | throw DeadlyImportError("Invalid MDC magic word: expected IDPC, found ", |
132 | 0 | ai_str_toprintable((char *)&pcHeader->ulIdent, 4)); |
133 | 0 | } |
134 | | |
135 | 0 | if (pcHeader->ulVersion != AI_MDC_VERSION) { |
136 | 0 | ASSIMP_LOG_WARN("Unsupported MDC file version (2 (AI_MDC_VERSION) was expected)"); |
137 | 0 | } |
138 | |
|
139 | 0 | if (pcHeader->ulOffsetBorderFrames + pcHeader->ulNumFrames * sizeof(MDC::Frame) > this->fileSize || |
140 | 0 | pcHeader->ulOffsetSurfaces + pcHeader->ulNumSurfaces * sizeof(MDC::Surface) > this->fileSize) { |
141 | 0 | throw DeadlyImportError("Some of the offset values in the MDC header are invalid " |
142 | 0 | "and point to something behind the file."); |
143 | 0 | } |
144 | | |
145 | 0 | if (this->configFrameID >= this->pcHeader->ulNumFrames) { |
146 | 0 | throw DeadlyImportError("The requested frame is not available"); |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | | // ------------------------------------------------------------------------------------------------ |
151 | | // Validate the header of a given MDC file surface |
152 | 0 | void MDCImporter::ValidateSurfaceHeader(BE_NCONST MDC::Surface *pcSurf) { |
153 | 0 | AI_SWAP4(pcSurf->ulFlags); |
154 | 0 | AI_SWAP4(pcSurf->ulNumCompFrames); |
155 | 0 | AI_SWAP4(pcSurf->ulNumBaseFrames); |
156 | 0 | AI_SWAP4(pcSurf->ulNumShaders); |
157 | 0 | AI_SWAP4(pcSurf->ulNumVertices); |
158 | 0 | AI_SWAP4(pcSurf->ulNumTriangles); |
159 | 0 | AI_SWAP4(pcSurf->ulOffsetTriangles); |
160 | 0 | AI_SWAP4(pcSurf->ulOffsetTexCoords); |
161 | 0 | AI_SWAP4(pcSurf->ulOffsetBaseVerts); |
162 | 0 | AI_SWAP4(pcSurf->ulOffsetCompVerts); |
163 | 0 | AI_SWAP4(pcSurf->ulOffsetFrameBaseFrames); |
164 | 0 | AI_SWAP4(pcSurf->ulOffsetFrameCompFrames); |
165 | 0 | AI_SWAP4(pcSurf->ulOffsetEnd); |
166 | |
|
167 | 0 | const unsigned int iMax = this->fileSize - (unsigned int)((int8_t *)pcSurf - (int8_t *)pcHeader); |
168 | |
|
169 | 0 | if (pcSurf->ulOffsetBaseVerts + pcSurf->ulNumVertices * sizeof(MDC::BaseVertex) > iMax || |
170 | 0 | (pcSurf->ulNumCompFrames && pcSurf->ulOffsetCompVerts + pcSurf->ulNumVertices * sizeof(MDC::CompressedVertex) > iMax) || |
171 | 0 | pcSurf->ulOffsetTriangles + pcSurf->ulNumTriangles * sizeof(MDC::Triangle) > iMax || |
172 | 0 | pcSurf->ulOffsetTexCoords + pcSurf->ulNumVertices * sizeof(MDC::TexturCoord) > iMax || |
173 | 0 | pcSurf->ulOffsetShaders + pcSurf->ulNumShaders * sizeof(MDC::Shader) > iMax || |
174 | 0 | pcSurf->ulOffsetFrameBaseFrames + pcSurf->ulNumBaseFrames * 2 > iMax || |
175 | 0 | (pcSurf->ulNumCompFrames && pcSurf->ulOffsetFrameCompFrames + pcSurf->ulNumCompFrames * 2 > iMax)) { |
176 | 0 | throw DeadlyImportError("Some of the offset values in the MDC surface header " |
177 | 0 | "are invalid and point somewhere behind the file."); |
178 | 0 | } |
179 | 0 | } |
180 | | |
181 | | // ------------------------------------------------------------------------------------------------ |
182 | | // Setup configuration properties |
183 | 0 | void MDCImporter::SetupProperties(const Importer *pImp) { |
184 | | // The AI_CONFIG_IMPORT_MDC_KEYFRAME option overrides the |
185 | | // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. |
186 | 0 | if (static_cast<unsigned int>(-1) == (configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MDC_KEYFRAME, -1))) { |
187 | 0 | configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME, 0); |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | | // ------------------------------------------------------------------------------------------------ |
192 | | // Imports the given file into the given scene structure. |
193 | | void MDCImporter::InternReadFile( |
194 | 0 | const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { |
195 | 0 | std::unique_ptr<IOStream> file(pIOHandler->Open(pFile)); |
196 | | |
197 | | // Check whether we can read from the file |
198 | 0 | if (file == nullptr) { |
199 | 0 | throw DeadlyImportError("Failed to open MDC file ", pFile, "."); |
200 | 0 | } |
201 | | |
202 | | // check whether the mdc file is large enough to contain the file header |
203 | 0 | fileSize = static_cast<unsigned int>(file->FileSize()); |
204 | 0 | if (fileSize < sizeof(MDC::Header)) { |
205 | 0 | throw DeadlyImportError("MDC File is too small."); |
206 | 0 | } |
207 | | |
208 | 0 | std::vector<unsigned char> mBuffer2(fileSize); |
209 | 0 | file->Read(&mBuffer2[0], 1, fileSize); |
210 | 0 | mBuffer = &mBuffer2[0]; |
211 | | |
212 | | // validate the file header |
213 | 0 | this->pcHeader = (BE_NCONST MDC::Header *)this->mBuffer; |
214 | 0 | this->ValidateHeader(); |
215 | |
|
216 | 0 | std::vector<std::string> aszShaders; |
217 | | |
218 | | // get a pointer to the frame we want to read |
219 | 0 | BE_NCONST MDC::Frame *pcFrame = (BE_NCONST MDC::Frame *)(this->mBuffer + |
220 | 0 | this->pcHeader->ulOffsetBorderFrames); |
221 | | |
222 | | // no need to swap the other members, we won't need them |
223 | 0 | pcFrame += configFrameID; |
224 | 0 | AI_SWAP4(pcFrame->localOrigin[0]); |
225 | 0 | AI_SWAP4(pcFrame->localOrigin[1]); |
226 | 0 | AI_SWAP4(pcFrame->localOrigin[2]); |
227 | | |
228 | | // get the number of valid surfaces |
229 | 0 | BE_NCONST MDC::Surface *pcSurface, *pcSurface2; |
230 | 0 | pcSurface = pcSurface2 = reinterpret_cast<BE_NCONST MDC::Surface *>(mBuffer + pcHeader->ulOffsetSurfaces); |
231 | 0 | unsigned int iNumShaders = 0; |
232 | 0 | for (unsigned int i = 0; i < pcHeader->ulNumSurfaces; ++i) { |
233 | | // validate the surface header |
234 | 0 | this->ValidateSurfaceHeader(pcSurface2); |
235 | |
|
236 | 0 | if (pcSurface2->ulNumVertices && pcSurface2->ulNumTriangles) { |
237 | 0 | ++pScene->mNumMeshes; |
238 | 0 | } |
239 | 0 | iNumShaders += pcSurface2->ulNumShaders; |
240 | 0 | pcSurface2 = reinterpret_cast<BE_NCONST MDC::Surface *>((BE_NCONST int8_t *)pcSurface2 + pcSurface2->ulOffsetEnd); |
241 | 0 | } |
242 | 0 | aszShaders.reserve(iNumShaders); |
243 | 0 | pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; |
244 | | |
245 | | // necessary that we don't crash if an exception occurs |
246 | 0 | for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { |
247 | 0 | pScene->mMeshes[i] = nullptr; |
248 | 0 | } |
249 | | |
250 | | // now read all surfaces |
251 | 0 | unsigned int iDefaultMatIndex = UINT_MAX; |
252 | 0 | for (unsigned int i = 0, iNum = 0; i < pcHeader->ulNumSurfaces; ++i) { |
253 | 0 | if (!pcSurface->ulNumVertices || !pcSurface->ulNumTriangles) continue; |
254 | 0 | aiMesh *pcMesh = pScene->mMeshes[iNum++] = new aiMesh(); |
255 | |
|
256 | 0 | pcMesh->mNumFaces = pcSurface->ulNumTriangles; |
257 | 0 | pcMesh->mNumVertices = pcMesh->mNumFaces * 3; |
258 | | |
259 | | // store the name of the surface for use as node name. |
260 | 0 | pcMesh->mName.Set(std::string(pcSurface->ucName, strnlen(pcSurface->ucName, AI_MDC_MAXQPATH - 1))); |
261 | | |
262 | | // go to the first shader in the file. ignore the others. |
263 | 0 | if (pcSurface->ulNumShaders) { |
264 | 0 | const MDC::Shader *pcShader = (const MDC::Shader *)((int8_t *)pcSurface + pcSurface->ulOffsetShaders); |
265 | 0 | pcMesh->mMaterialIndex = (unsigned int)aszShaders.size(); |
266 | | |
267 | | // create a new shader |
268 | 0 | aszShaders.emplace_back(pcShader->ucName, |
269 | 0 | ::strnlen(pcShader->ucName, sizeof(pcShader->ucName))); |
270 | 0 | } |
271 | | // need to create a default material |
272 | 0 | else if (UINT_MAX == iDefaultMatIndex) { |
273 | 0 | pcMesh->mMaterialIndex = iDefaultMatIndex = (unsigned int)aszShaders.size(); |
274 | 0 | aszShaders.emplace_back(); |
275 | 0 | } |
276 | | // otherwise assign a reference to the default material |
277 | 0 | else |
278 | 0 | pcMesh->mMaterialIndex = iDefaultMatIndex; |
279 | | |
280 | | // allocate output storage for the mesh |
281 | 0 | aiVector3D *pcVertCur = pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; |
282 | 0 | aiVector3D *pcNorCur = pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; |
283 | 0 | aiVector3D *pcUVCur = pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; |
284 | 0 | aiFace *pcFaceCur = pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; |
285 | | |
286 | | // create all vertices/faces |
287 | 0 | BE_NCONST MDC::Triangle *pcTriangle = (BE_NCONST MDC::Triangle *)((int8_t *)pcSurface + pcSurface->ulOffsetTriangles); |
288 | |
|
289 | 0 | BE_NCONST MDC::TexturCoord *const pcUVs = (BE_NCONST MDC::TexturCoord *)((int8_t *)pcSurface + pcSurface->ulOffsetTexCoords); |
290 | | |
291 | | // get a pointer to the uncompressed vertices |
292 | 0 | int16_t iOfs = *((int16_t *)((int8_t *)pcSurface + |
293 | 0 | pcSurface->ulOffsetFrameBaseFrames) + |
294 | 0 | this->configFrameID); |
295 | |
|
296 | 0 | AI_SWAP2(iOfs); |
297 | |
|
298 | 0 | BE_NCONST MDC::BaseVertex *const pcVerts = (BE_NCONST MDC::BaseVertex *)((int8_t *)pcSurface + pcSurface->ulOffsetBaseVerts) + |
299 | 0 | ((int)iOfs * pcSurface->ulNumVertices * 4); |
300 | | |
301 | | // do the main swapping stuff ... |
302 | | #if (defined AI_BUILD_BIG_ENDIAN) |
303 | | |
304 | | // swap all triangles |
305 | | for (unsigned int i = 0; i < pcSurface->ulNumTriangles; ++i) { |
306 | | AI_SWAP4(pcTriangle[i].aiIndices[0]); |
307 | | AI_SWAP4(pcTriangle[i].aiIndices[1]); |
308 | | AI_SWAP4(pcTriangle[i].aiIndices[2]); |
309 | | } |
310 | | |
311 | | // swap all vertices |
312 | | for (unsigned int i = 0; i < pcSurface->ulNumVertices * pcSurface->ulNumBaseFrames; ++i) { |
313 | | AI_SWAP2(pcVerts->normal); |
314 | | AI_SWAP2(pcVerts->x); |
315 | | AI_SWAP2(pcVerts->y); |
316 | | AI_SWAP2(pcVerts->z); |
317 | | } |
318 | | |
319 | | // swap all texture coordinates |
320 | | for (unsigned int i = 0; i < pcSurface->ulNumVertices; ++i) { |
321 | | AI_SWAP4(pcUVs->u); |
322 | | AI_SWAP4(pcUVs->v); |
323 | | } |
324 | | |
325 | | #endif |
326 | |
|
327 | 0 | const MDC::CompressedVertex *pcCVerts = nullptr; |
328 | 0 | int16_t *mdcCompVert = nullptr; |
329 | | |
330 | | // access compressed frames for large frame numbers, but never for the first |
331 | 0 | if (this->configFrameID && pcSurface->ulNumCompFrames > 0) { |
332 | 0 | mdcCompVert = (int16_t *)((int8_t *)pcSurface + pcSurface->ulOffsetFrameCompFrames) + this->configFrameID; |
333 | 0 | AI_SWAP2P(mdcCompVert); |
334 | 0 | if (*mdcCompVert >= 0) { |
335 | 0 | pcCVerts = (const MDC::CompressedVertex *)((int8_t *)pcSurface + |
336 | 0 | pcSurface->ulOffsetCompVerts) + |
337 | 0 | *mdcCompVert * pcSurface->ulNumVertices; |
338 | 0 | } else |
339 | 0 | mdcCompVert = nullptr; |
340 | 0 | } |
341 | | |
342 | | // copy all faces |
343 | 0 | for (unsigned int iFace = 0; iFace < pcSurface->ulNumTriangles; ++iFace, |
344 | 0 | ++pcTriangle, ++pcFaceCur) { |
345 | 0 | const unsigned int iOutIndex = iFace * 3; |
346 | 0 | pcFaceCur->mNumIndices = 3; |
347 | 0 | pcFaceCur->mIndices = new unsigned int[3]; |
348 | |
|
349 | 0 | for (unsigned int iIndex = 0; iIndex < 3; ++iIndex, |
350 | 0 | ++pcVertCur, ++pcUVCur, ++pcNorCur) { |
351 | 0 | uint32_t quak = pcTriangle->aiIndices[iIndex]; |
352 | 0 | if (quak >= pcSurface->ulNumVertices) { |
353 | 0 | ASSIMP_LOG_ERROR("MDC vertex index is out of range"); |
354 | 0 | quak = pcSurface->ulNumVertices - 1; |
355 | 0 | } |
356 | | |
357 | | // compressed vertices? |
358 | 0 | if (mdcCompVert) { |
359 | 0 | MDC::BuildVertex(*pcFrame, pcVerts[quak], pcCVerts[quak], |
360 | 0 | *pcVertCur, *pcNorCur); |
361 | 0 | } else { |
362 | | // copy position |
363 | 0 | pcVertCur->x = pcVerts[quak].x * AI_MDC_BASE_SCALING; |
364 | 0 | pcVertCur->y = pcVerts[quak].y * AI_MDC_BASE_SCALING; |
365 | 0 | pcVertCur->z = pcVerts[quak].z * AI_MDC_BASE_SCALING; |
366 | | |
367 | | // copy normals |
368 | 0 | MD3::LatLngNormalToVec3(pcVerts[quak].normal, &pcNorCur->x); |
369 | | |
370 | | // copy texture coordinates |
371 | 0 | pcUVCur->x = pcUVs[quak].u; |
372 | 0 | pcUVCur->y = ai_real(1.0) - pcUVs[quak].v; // DX to OGL |
373 | 0 | } |
374 | 0 | pcVertCur->x += pcFrame->localOrigin[0]; |
375 | 0 | pcVertCur->y += pcFrame->localOrigin[1]; |
376 | 0 | pcVertCur->z += pcFrame->localOrigin[2]; |
377 | 0 | } |
378 | | |
379 | | // swap the face order - DX to OGL |
380 | 0 | pcFaceCur->mIndices[0] = iOutIndex + 2; |
381 | 0 | pcFaceCur->mIndices[1] = iOutIndex + 1; |
382 | 0 | pcFaceCur->mIndices[2] = iOutIndex + 0; |
383 | 0 | } |
384 | |
|
385 | 0 | pcSurface = reinterpret_cast<BE_NCONST MDC::Surface *>((BE_NCONST int8_t *)pcSurface + pcSurface->ulOffsetEnd); |
386 | 0 | } |
387 | | |
388 | | // create a flat node graph with a root node and one child for each surface |
389 | 0 | if (!pScene->mNumMeshes) |
390 | 0 | throw DeadlyImportError("Invalid MDC file: File contains no valid mesh"); |
391 | 0 | else if (1 == pScene->mNumMeshes) { |
392 | 0 | pScene->mRootNode = new aiNode(); |
393 | 0 | if (nullptr != pScene->mMeshes[0]) { |
394 | 0 | pScene->mRootNode->mName = pScene->mMeshes[0]->mName; |
395 | 0 | pScene->mRootNode->mNumMeshes = 1; |
396 | 0 | pScene->mRootNode->mMeshes = new unsigned int[1]; |
397 | 0 | pScene->mRootNode->mMeshes[0] = 0; |
398 | 0 | } |
399 | 0 | } else { |
400 | 0 | pScene->mRootNode = new aiNode(); |
401 | 0 | pScene->mRootNode->mNumChildren = pScene->mNumMeshes; |
402 | 0 | pScene->mRootNode->mChildren = new aiNode *[pScene->mNumMeshes]; |
403 | 0 | pScene->mRootNode->mName.Set("<root>"); |
404 | 0 | for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { |
405 | 0 | aiNode *pcNode = pScene->mRootNode->mChildren[i] = new aiNode(); |
406 | 0 | pcNode->mParent = pScene->mRootNode; |
407 | 0 | pcNode->mName = pScene->mMeshes[i]->mName; |
408 | 0 | pcNode->mNumMeshes = 1; |
409 | 0 | pcNode->mMeshes = new unsigned int[1]; |
410 | 0 | pcNode->mMeshes[0] = i; |
411 | 0 | } |
412 | 0 | } |
413 | | |
414 | | // create materials |
415 | 0 | pScene->mNumMaterials = (unsigned int)aszShaders.size(); |
416 | 0 | pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials]; |
417 | 0 | for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) { |
418 | 0 | aiMaterial *pcMat = new aiMaterial(); |
419 | 0 | pScene->mMaterials[i] = pcMat; |
420 | |
|
421 | 0 | const std::string &name = aszShaders[i]; |
422 | |
|
423 | 0 | int iMode = (int)aiShadingMode_Gouraud; |
424 | 0 | pcMat->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL); |
425 | | |
426 | | // add a small ambient color value - RtCW seems to have one |
427 | 0 | aiColor3D clr; |
428 | 0 | clr.b = clr.g = clr.r = 0.05f; |
429 | 0 | pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT); |
430 | |
|
431 | 0 | if (name.length()) |
432 | 0 | clr.b = clr.g = clr.r = 1.0f; |
433 | 0 | else |
434 | 0 | clr.b = clr.g = clr.r = 0.6f; |
435 | |
|
436 | 0 | pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); |
437 | 0 | pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR); |
438 | |
|
439 | 0 | if (name.length()) { |
440 | 0 | aiString path; |
441 | 0 | path.Set(name); |
442 | 0 | pcMat->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0)); |
443 | 0 | } |
444 | 0 | } |
445 | | |
446 | | // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system |
447 | 0 | pScene->mRootNode->mTransformation = aiMatrix4x4( |
448 | 0 | 1.f, 0.f, 0.f, 0.f, |
449 | 0 | 0.f, 0.f, 1.f, 0.f, |
450 | 0 | 0.f, -1.f, 0.f, 0.f, |
451 | 0 | 0.f, 0.f, 0.f, 1.f); |
452 | 0 | } |
453 | | |
454 | | #endif // !! ASSIMP_BUILD_NO_MDC_IMPORTER |