vrshoot
view libs/assimp/UnrealLoader.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
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:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
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.
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.
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 */
42 /** @file UnrealLoader.cpp
43 * @brief Implementation of the UNREAL (*.3D) importer class
44 *
45 * Sources:
46 * http://local.wasp.uwa.edu.au/~pbourke/dataformats/unreal/
47 */
49 #include "AssimpPCH.h"
51 #ifndef ASSIMP_BUILD_NO_3D_IMPORTER
53 #include "UnrealLoader.h"
54 #include "StreamReader.h"
55 #include "ParsingUtils.h"
56 #include "fast_atof.h"
57 #include "ConvertToLHProcess.h"
59 using namespace Assimp;
61 static const aiImporterDesc desc = {
62 "Unreal Mesh Importer",
63 "",
64 "",
65 "",
66 aiImporterFlags_SupportTextFlavour,
67 0,
68 0,
69 0,
70 0,
71 "3d uc"
72 };
75 // ------------------------------------------------------------------------------------------------
76 // Constructor to be privately used by Importer
77 UnrealImporter::UnrealImporter()
78 : configFrameID (0)
79 , configHandleFlags (true)
80 {}
82 // ------------------------------------------------------------------------------------------------
83 // Destructor, private as well
84 UnrealImporter::~UnrealImporter()
85 {}
87 // ------------------------------------------------------------------------------------------------
88 // Returns whether the class can handle the format of the given file.
89 bool UnrealImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const
90 {
91 return SimpleExtensionCheck(pFile,"3d","uc");
92 }
94 // ------------------------------------------------------------------------------------------------
95 // Build a string of all file extensions supported
96 const aiImporterDesc* UnrealImporter::GetInfo () const
97 {
98 return &desc;
99 }
101 // ------------------------------------------------------------------------------------------------
102 // Setup configuration properties for the loader
103 void UnrealImporter::SetupProperties(const Importer* pImp)
104 {
105 // The
106 // AI_CONFIG_IMPORT_UNREAL_KEYFRAME option overrides the
107 // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
108 configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_UNREAL_KEYFRAME,-1);
109 if(static_cast<unsigned int>(-1) == configFrameID) {
110 configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
111 }
113 // AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS, default is true
114 configHandleFlags = (0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS,1));
115 }
117 // ------------------------------------------------------------------------------------------------
118 // Imports the given file into the given scene structure.
119 void UnrealImporter::InternReadFile( const std::string& pFile,
120 aiScene* pScene, IOSystem* pIOHandler)
121 {
122 // For any of the 3 files being passed get the three correct paths
123 // First of all, determine file extension
124 std::string::size_type pos = pFile.find_last_of('.');
125 std::string extension = GetExtension(pFile);
127 std::string d_path,a_path,uc_path;
128 if (extension == "3d") {
129 // jjjj_d.3d
130 // jjjj_a.3d
131 pos = pFile.find_last_of('_');
132 if (std::string::npos == pos) {
133 throw DeadlyImportError("UNREAL: Unexpected naming scheme");
134 }
135 extension = pFile.substr(0,pos);
136 }
137 else {
138 extension = pFile.substr(0,pos);
139 }
141 // build proper paths
142 d_path = extension+"_d.3d";
143 a_path = extension+"_a.3d";
144 uc_path = extension+".uc";
146 DefaultLogger::get()->debug("UNREAL: data file is " + d_path);
147 DefaultLogger::get()->debug("UNREAL: aniv file is " + a_path);
148 DefaultLogger::get()->debug("UNREAL: uc file is " + uc_path);
150 // and open the files ... we can't live without them
151 IOStream* p = pIOHandler->Open(d_path);
152 if (!p)
153 throw DeadlyImportError("UNREAL: Unable to open _d file");
154 StreamReaderLE d_reader(pIOHandler->Open(d_path));
156 const uint16_t numTris = d_reader.GetI2();
157 const uint16_t numVert = d_reader.GetI2();
158 d_reader.IncPtr(44);
159 if (!numTris || numVert < 3)
160 throw DeadlyImportError("UNREAL: Invalid number of vertices/triangles");
162 // maximum texture index
163 unsigned int maxTexIdx = 0;
165 // collect triangles
166 std::vector<Unreal::Triangle> triangles(numTris);
167 for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) {
168 Unreal::Triangle& tri = *it;
170 for (unsigned int i = 0; i < 3;++i) {
172 tri.mVertex[i] = d_reader.GetI2();
173 if (tri.mVertex[i] >= numTris) {
174 DefaultLogger::get()->warn("UNREAL: vertex index out of range");
175 tri.mVertex[i] = 0;
176 }
177 }
178 tri.mType = d_reader.GetI1();
180 // handle mesh flagss?
181 if (configHandleFlags)
182 tri.mType = Unreal::MF_NORMAL_OS;
183 else {
184 // ignore MOD and MASKED for the moment, treat them as two-sided
185 if (tri.mType == Unreal::MF_NORMAL_MOD_TS || tri.mType == Unreal::MF_NORMAL_MASKED_TS)
186 tri.mType = Unreal::MF_NORMAL_TS;
187 }
188 d_reader.IncPtr(1);
190 for (unsigned int i = 0; i < 3;++i)
191 for (unsigned int i2 = 0; i2 < 2;++i2)
192 tri.mTex[i][i2] = d_reader.GetI1();
194 tri.mTextureNum = d_reader.GetI1();
195 maxTexIdx = std::max(maxTexIdx,(unsigned int)tri.mTextureNum);
196 d_reader.IncPtr(1);
197 }
199 p = pIOHandler->Open(a_path);
200 if (!p)
201 throw DeadlyImportError("UNREAL: Unable to open _a file");
202 StreamReaderLE a_reader(pIOHandler->Open(a_path));
204 // read number of frames
205 const uint32_t numFrames = a_reader.GetI2();
206 if (configFrameID >= numFrames)
207 throw DeadlyImportError("UNREAL: The requested frame does not exist");
209 uint32_t st = a_reader.GetI2();
210 if (st != numVert*4)
211 throw DeadlyImportError("UNREAL: Unexpected aniv file length");
213 // skip to our frame
214 a_reader.IncPtr(configFrameID *numVert*4);
216 // collect vertices
217 std::vector<aiVector3D> vertices(numVert);
218 for (std::vector<aiVector3D>::iterator it = vertices.begin(), end = vertices.end(); it != end; ++it) {
219 int32_t val = a_reader.GetI4();
220 Unreal::DecompressVertex(*it,val);
221 }
223 // list of textures.
224 std::vector< std::pair<unsigned int, std::string> > textures;
226 // allocate the output scene
227 aiNode* nd = pScene->mRootNode = new aiNode();
228 nd->mName.Set("<UnrealRoot>");
230 // we can live without the uc file if necessary
231 boost::scoped_ptr<IOStream> pb (pIOHandler->Open(uc_path));
232 if (pb.get()) {
234 std::vector<char> _data;
235 TextFileToBuffer(pb.get(),_data);
236 const char* data = &_data[0];
238 std::vector< std::pair< std::string,std::string > > tempTextures;
240 // do a quick search in the UC file for some known, usually texture-related, tags
241 for (;*data;++data) {
242 if (TokenMatchI(data,"#exec",5)) {
243 SkipSpacesAndLineEnd(&data);
245 // #exec TEXTURE IMPORT [...] NAME=jjjjj [...] FILE=jjjj.pcx [...]
246 if (TokenMatchI(data,"TEXTURE",7)) {
247 SkipSpacesAndLineEnd(&data);
249 if (TokenMatchI(data,"IMPORT",6)) {
250 tempTextures.push_back(std::pair< std::string,std::string >());
251 std::pair< std::string,std::string >& me = tempTextures.back();
252 for (;!IsLineEnd(*data);++data) {
253 if (!::ASSIMP_strincmp(data,"NAME=",5)) {
254 const char *d = data+=5;
255 for (;!IsSpaceOrNewLine(*data);++data);
256 me.first = std::string(d,(size_t)(data-d));
257 }
258 else if (!::ASSIMP_strincmp(data,"FILE=",5)) {
259 const char *d = data+=5;
260 for (;!IsSpaceOrNewLine(*data);++data);
261 me.second = std::string(d,(size_t)(data-d));
262 }
263 }
264 if (!me.first.length() || !me.second.length())
265 tempTextures.pop_back();
266 }
267 }
268 // #exec MESHMAP SETTEXTURE MESHMAP=box NUM=1 TEXTURE=Jtex1
269 // #exec MESHMAP SCALE MESHMAP=box X=0.1 Y=0.1 Z=0.2
270 else if (TokenMatchI(data,"MESHMAP",7)) {
271 SkipSpacesAndLineEnd(&data);
273 if (TokenMatchI(data,"SETTEXTURE",10)) {
275 textures.push_back(std::pair<unsigned int, std::string>());
276 std::pair<unsigned int, std::string>& me = textures.back();
278 for (;!IsLineEnd(*data);++data) {
279 if (!::ASSIMP_strincmp(data,"NUM=",4)) {
280 data += 4;
281 me.first = strtoul10(data,&data);
282 }
283 else if (!::ASSIMP_strincmp(data,"TEXTURE=",8)) {
284 data += 8;
285 const char *d = data;
286 for (;!IsSpaceOrNewLine(*data);++data);
287 me.second = std::string(d,(size_t)(data-d));
289 // try to find matching path names, doesn't care if we don't find them
290 for (std::vector< std::pair< std::string,std::string > >::const_iterator it = tempTextures.begin();
291 it != tempTextures.end(); ++it) {
292 if ((*it).first == me.second) {
293 me.second = (*it).second;
294 break;
295 }
296 }
297 }
298 }
299 }
300 else if (TokenMatchI(data,"SCALE",5)) {
302 for (;!IsLineEnd(*data);++data) {
303 if (data[0] == 'X' && data[1] == '=') {
304 data = fast_atoreal_move<float>(data+2,(float&)nd->mTransformation.a1);
305 }
306 else if (data[0] == 'Y' && data[1] == '=') {
307 data = fast_atoreal_move<float>(data+2,(float&)nd->mTransformation.b2);
308 }
309 else if (data[0] == 'Z' && data[1] == '=') {
310 data = fast_atoreal_move<float>(data+2,(float&)nd->mTransformation.c3);
311 }
312 }
313 }
314 }
315 }
316 }
317 }
318 else {
319 DefaultLogger::get()->error("Unable to open .uc file");
320 }
322 std::vector<Unreal::TempMat> materials;
323 materials.reserve(textures.size()*2+5);
325 // find out how many output meshes and materials we'll have and build material indices
326 for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) {
327 Unreal::Triangle& tri = *it;
328 Unreal::TempMat mat(tri);
329 std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(),materials.end(),mat);
330 if (nt == materials.end()) {
331 // add material
332 tri.matIndex = materials.size();
333 mat.numFaces = 1;
334 materials.push_back(mat);
336 ++pScene->mNumMeshes;
337 }
338 else {
339 tri.matIndex = static_cast<unsigned int>(nt-materials.begin());
340 ++nt->numFaces;
341 }
342 }
344 if (!pScene->mNumMeshes) {
345 throw DeadlyImportError("UNREAL: Unable to find valid mesh data");
346 }
348 // allocate meshes and bind them to the node graph
349 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
350 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = pScene->mNumMeshes];
352 nd->mNumMeshes = pScene->mNumMeshes;
353 nd->mMeshes = new unsigned int[nd->mNumMeshes];
354 for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
355 aiMesh* m = pScene->mMeshes[i] = new aiMesh();
356 m->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
358 const unsigned int num = materials[i].numFaces;
359 m->mFaces = new aiFace [num];
360 m->mVertices = new aiVector3D [num*3];
361 m->mTextureCoords[0] = new aiVector3D [num*3];
363 nd->mMeshes[i] = i;
365 // create materials, too
366 aiMaterial* mat = new aiMaterial();
367 pScene->mMaterials[i] = mat;
369 // all white by default - texture rulez
370 aiColor3D color(1.f,1.f,1.f);
372 aiString s;
373 ::sprintf(s.data,"mat%i_tx%i_",i,materials[i].tex);
375 // set the two-sided flag
376 if (materials[i].type == Unreal::MF_NORMAL_TS) {
377 const int twosided = 1;
378 mat->AddProperty(&twosided,1,AI_MATKEY_TWOSIDED);
379 ::strcat(s.data,"ts_");
380 }
381 else ::strcat(s.data,"os_");
383 // make TRANS faces 90% opaque that RemRedundantMaterials won't catch us
384 if (materials[i].type == Unreal::MF_NORMAL_TRANS_TS) {
385 const float opac = 0.9f;
386 mat->AddProperty(&opac,1,AI_MATKEY_OPACITY);
387 ::strcat(s.data,"tran_");
388 }
389 else ::strcat(s.data,"opaq_");
391 // a special name for the weapon attachment point
392 if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) {
393 s.length = ::sprintf(s.data,"$WeaponTag$");
394 color = aiColor3D(0.f,0.f,0.f);
395 }
397 // set color and name
398 mat->AddProperty(&color,1,AI_MATKEY_COLOR_DIFFUSE);
399 s.length = ::strlen(s.data);
400 mat->AddProperty(&s,AI_MATKEY_NAME);
402 // set texture, if any
403 const unsigned int tex = materials[i].tex;
404 for (std::vector< std::pair< unsigned int, std::string > >::const_iterator it = textures.begin();it != textures.end();++it) {
405 if ((*it).first == tex) {
406 s.Set((*it).second);
407 mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
408 break;
409 }
410 }
411 }
413 // fill them.
414 for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) {
415 Unreal::Triangle& tri = *it;
416 Unreal::TempMat mat(tri);
417 std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(),materials.end(),mat);
419 aiMesh* mesh = pScene->mMeshes[nt-materials.begin()];
420 aiFace& f = mesh->mFaces[mesh->mNumFaces++];
421 f.mIndices = new unsigned int[f.mNumIndices = 3];
423 for (unsigned int i = 0; i < 3;++i,mesh->mNumVertices++) {
424 f.mIndices[i] = mesh->mNumVertices;
426 mesh->mVertices[mesh->mNumVertices] = vertices[ tri.mVertex[i] ];
427 mesh->mTextureCoords[0][mesh->mNumVertices] = aiVector3D( tri.mTex[i][0] / 255.f, 1.f - tri.mTex[i][1] / 255.f, 0.f);
428 }
429 }
431 // convert to RH
432 MakeLeftHandedProcess hero;
433 hero.Execute(pScene);
435 FlipWindingOrderProcess flipper;
436 flipper.Execute(pScene);
437 }
439 #endif // !! ASSIMP_BUILD_NO_3D_IMPORTER