vrshoot
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/UnrealLoader.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,439 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file UnrealLoader.cpp 1.46 + * @brief Implementation of the UNREAL (*.3D) importer class 1.47 + * 1.48 + * Sources: 1.49 + * http://local.wasp.uwa.edu.au/~pbourke/dataformats/unreal/ 1.50 + */ 1.51 + 1.52 +#include "AssimpPCH.h" 1.53 + 1.54 +#ifndef ASSIMP_BUILD_NO_3D_IMPORTER 1.55 + 1.56 +#include "UnrealLoader.h" 1.57 +#include "StreamReader.h" 1.58 +#include "ParsingUtils.h" 1.59 +#include "fast_atof.h" 1.60 +#include "ConvertToLHProcess.h" 1.61 + 1.62 +using namespace Assimp; 1.63 + 1.64 +static const aiImporterDesc desc = { 1.65 + "Unreal Mesh Importer", 1.66 + "", 1.67 + "", 1.68 + "", 1.69 + aiImporterFlags_SupportTextFlavour, 1.70 + 0, 1.71 + 0, 1.72 + 0, 1.73 + 0, 1.74 + "3d uc" 1.75 +}; 1.76 + 1.77 + 1.78 +// ------------------------------------------------------------------------------------------------ 1.79 +// Constructor to be privately used by Importer 1.80 +UnrealImporter::UnrealImporter() 1.81 +: configFrameID (0) 1.82 +, configHandleFlags (true) 1.83 +{} 1.84 + 1.85 +// ------------------------------------------------------------------------------------------------ 1.86 +// Destructor, private as well 1.87 +UnrealImporter::~UnrealImporter() 1.88 +{} 1.89 + 1.90 +// ------------------------------------------------------------------------------------------------ 1.91 +// Returns whether the class can handle the format of the given file. 1.92 +bool UnrealImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const 1.93 +{ 1.94 + return SimpleExtensionCheck(pFile,"3d","uc"); 1.95 +} 1.96 + 1.97 +// ------------------------------------------------------------------------------------------------ 1.98 +// Build a string of all file extensions supported 1.99 +const aiImporterDesc* UnrealImporter::GetInfo () const 1.100 +{ 1.101 + return &desc; 1.102 +} 1.103 + 1.104 +// ------------------------------------------------------------------------------------------------ 1.105 +// Setup configuration properties for the loader 1.106 +void UnrealImporter::SetupProperties(const Importer* pImp) 1.107 +{ 1.108 + // The 1.109 + // AI_CONFIG_IMPORT_UNREAL_KEYFRAME option overrides the 1.110 + // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. 1.111 + configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_UNREAL_KEYFRAME,-1); 1.112 + if(static_cast<unsigned int>(-1) == configFrameID) { 1.113 + configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); 1.114 + } 1.115 + 1.116 + // AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS, default is true 1.117 + configHandleFlags = (0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS,1)); 1.118 +} 1.119 + 1.120 +// ------------------------------------------------------------------------------------------------ 1.121 +// Imports the given file into the given scene structure. 1.122 +void UnrealImporter::InternReadFile( const std::string& pFile, 1.123 + aiScene* pScene, IOSystem* pIOHandler) 1.124 +{ 1.125 + // For any of the 3 files being passed get the three correct paths 1.126 + // First of all, determine file extension 1.127 + std::string::size_type pos = pFile.find_last_of('.'); 1.128 + std::string extension = GetExtension(pFile); 1.129 + 1.130 + std::string d_path,a_path,uc_path; 1.131 + if (extension == "3d") { 1.132 + // jjjj_d.3d 1.133 + // jjjj_a.3d 1.134 + pos = pFile.find_last_of('_'); 1.135 + if (std::string::npos == pos) { 1.136 + throw DeadlyImportError("UNREAL: Unexpected naming scheme"); 1.137 + } 1.138 + extension = pFile.substr(0,pos); 1.139 + } 1.140 + else { 1.141 + extension = pFile.substr(0,pos); 1.142 + } 1.143 + 1.144 + // build proper paths 1.145 + d_path = extension+"_d.3d"; 1.146 + a_path = extension+"_a.3d"; 1.147 + uc_path = extension+".uc"; 1.148 + 1.149 + DefaultLogger::get()->debug("UNREAL: data file is " + d_path); 1.150 + DefaultLogger::get()->debug("UNREAL: aniv file is " + a_path); 1.151 + DefaultLogger::get()->debug("UNREAL: uc file is " + uc_path); 1.152 + 1.153 + // and open the files ... we can't live without them 1.154 + IOStream* p = pIOHandler->Open(d_path); 1.155 + if (!p) 1.156 + throw DeadlyImportError("UNREAL: Unable to open _d file"); 1.157 + StreamReaderLE d_reader(pIOHandler->Open(d_path)); 1.158 + 1.159 + const uint16_t numTris = d_reader.GetI2(); 1.160 + const uint16_t numVert = d_reader.GetI2(); 1.161 + d_reader.IncPtr(44); 1.162 + if (!numTris || numVert < 3) 1.163 + throw DeadlyImportError("UNREAL: Invalid number of vertices/triangles"); 1.164 + 1.165 + // maximum texture index 1.166 + unsigned int maxTexIdx = 0; 1.167 + 1.168 + // collect triangles 1.169 + std::vector<Unreal::Triangle> triangles(numTris); 1.170 + for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) { 1.171 + Unreal::Triangle& tri = *it; 1.172 + 1.173 + for (unsigned int i = 0; i < 3;++i) { 1.174 + 1.175 + tri.mVertex[i] = d_reader.GetI2(); 1.176 + if (tri.mVertex[i] >= numTris) { 1.177 + DefaultLogger::get()->warn("UNREAL: vertex index out of range"); 1.178 + tri.mVertex[i] = 0; 1.179 + } 1.180 + } 1.181 + tri.mType = d_reader.GetI1(); 1.182 + 1.183 + // handle mesh flagss? 1.184 + if (configHandleFlags) 1.185 + tri.mType = Unreal::MF_NORMAL_OS; 1.186 + else { 1.187 + // ignore MOD and MASKED for the moment, treat them as two-sided 1.188 + if (tri.mType == Unreal::MF_NORMAL_MOD_TS || tri.mType == Unreal::MF_NORMAL_MASKED_TS) 1.189 + tri.mType = Unreal::MF_NORMAL_TS; 1.190 + } 1.191 + d_reader.IncPtr(1); 1.192 + 1.193 + for (unsigned int i = 0; i < 3;++i) 1.194 + for (unsigned int i2 = 0; i2 < 2;++i2) 1.195 + tri.mTex[i][i2] = d_reader.GetI1(); 1.196 + 1.197 + tri.mTextureNum = d_reader.GetI1(); 1.198 + maxTexIdx = std::max(maxTexIdx,(unsigned int)tri.mTextureNum); 1.199 + d_reader.IncPtr(1); 1.200 + } 1.201 + 1.202 + p = pIOHandler->Open(a_path); 1.203 + if (!p) 1.204 + throw DeadlyImportError("UNREAL: Unable to open _a file"); 1.205 + StreamReaderLE a_reader(pIOHandler->Open(a_path)); 1.206 + 1.207 + // read number of frames 1.208 + const uint32_t numFrames = a_reader.GetI2(); 1.209 + if (configFrameID >= numFrames) 1.210 + throw DeadlyImportError("UNREAL: The requested frame does not exist"); 1.211 + 1.212 + uint32_t st = a_reader.GetI2(); 1.213 + if (st != numVert*4) 1.214 + throw DeadlyImportError("UNREAL: Unexpected aniv file length"); 1.215 + 1.216 + // skip to our frame 1.217 + a_reader.IncPtr(configFrameID *numVert*4); 1.218 + 1.219 + // collect vertices 1.220 + std::vector<aiVector3D> vertices(numVert); 1.221 + for (std::vector<aiVector3D>::iterator it = vertices.begin(), end = vertices.end(); it != end; ++it) { 1.222 + int32_t val = a_reader.GetI4(); 1.223 + Unreal::DecompressVertex(*it,val); 1.224 + } 1.225 + 1.226 + // list of textures. 1.227 + std::vector< std::pair<unsigned int, std::string> > textures; 1.228 + 1.229 + // allocate the output scene 1.230 + aiNode* nd = pScene->mRootNode = new aiNode(); 1.231 + nd->mName.Set("<UnrealRoot>"); 1.232 + 1.233 + // we can live without the uc file if necessary 1.234 + boost::scoped_ptr<IOStream> pb (pIOHandler->Open(uc_path)); 1.235 + if (pb.get()) { 1.236 + 1.237 + std::vector<char> _data; 1.238 + TextFileToBuffer(pb.get(),_data); 1.239 + const char* data = &_data[0]; 1.240 + 1.241 + std::vector< std::pair< std::string,std::string > > tempTextures; 1.242 + 1.243 + // do a quick search in the UC file for some known, usually texture-related, tags 1.244 + for (;*data;++data) { 1.245 + if (TokenMatchI(data,"#exec",5)) { 1.246 + SkipSpacesAndLineEnd(&data); 1.247 + 1.248 + // #exec TEXTURE IMPORT [...] NAME=jjjjj [...] FILE=jjjj.pcx [...] 1.249 + if (TokenMatchI(data,"TEXTURE",7)) { 1.250 + SkipSpacesAndLineEnd(&data); 1.251 + 1.252 + if (TokenMatchI(data,"IMPORT",6)) { 1.253 + tempTextures.push_back(std::pair< std::string,std::string >()); 1.254 + std::pair< std::string,std::string >& me = tempTextures.back(); 1.255 + for (;!IsLineEnd(*data);++data) { 1.256 + if (!::ASSIMP_strincmp(data,"NAME=",5)) { 1.257 + const char *d = data+=5; 1.258 + for (;!IsSpaceOrNewLine(*data);++data); 1.259 + me.first = std::string(d,(size_t)(data-d)); 1.260 + } 1.261 + else if (!::ASSIMP_strincmp(data,"FILE=",5)) { 1.262 + const char *d = data+=5; 1.263 + for (;!IsSpaceOrNewLine(*data);++data); 1.264 + me.second = std::string(d,(size_t)(data-d)); 1.265 + } 1.266 + } 1.267 + if (!me.first.length() || !me.second.length()) 1.268 + tempTextures.pop_back(); 1.269 + } 1.270 + } 1.271 + // #exec MESHMAP SETTEXTURE MESHMAP=box NUM=1 TEXTURE=Jtex1 1.272 + // #exec MESHMAP SCALE MESHMAP=box X=0.1 Y=0.1 Z=0.2 1.273 + else if (TokenMatchI(data,"MESHMAP",7)) { 1.274 + SkipSpacesAndLineEnd(&data); 1.275 + 1.276 + if (TokenMatchI(data,"SETTEXTURE",10)) { 1.277 + 1.278 + textures.push_back(std::pair<unsigned int, std::string>()); 1.279 + std::pair<unsigned int, std::string>& me = textures.back(); 1.280 + 1.281 + for (;!IsLineEnd(*data);++data) { 1.282 + if (!::ASSIMP_strincmp(data,"NUM=",4)) { 1.283 + data += 4; 1.284 + me.first = strtoul10(data,&data); 1.285 + } 1.286 + else if (!::ASSIMP_strincmp(data,"TEXTURE=",8)) { 1.287 + data += 8; 1.288 + const char *d = data; 1.289 + for (;!IsSpaceOrNewLine(*data);++data); 1.290 + me.second = std::string(d,(size_t)(data-d)); 1.291 + 1.292 + // try to find matching path names, doesn't care if we don't find them 1.293 + for (std::vector< std::pair< std::string,std::string > >::const_iterator it = tempTextures.begin(); 1.294 + it != tempTextures.end(); ++it) { 1.295 + if ((*it).first == me.second) { 1.296 + me.second = (*it).second; 1.297 + break; 1.298 + } 1.299 + } 1.300 + } 1.301 + } 1.302 + } 1.303 + else if (TokenMatchI(data,"SCALE",5)) { 1.304 + 1.305 + for (;!IsLineEnd(*data);++data) { 1.306 + if (data[0] == 'X' && data[1] == '=') { 1.307 + data = fast_atoreal_move<float>(data+2,(float&)nd->mTransformation.a1); 1.308 + } 1.309 + else if (data[0] == 'Y' && data[1] == '=') { 1.310 + data = fast_atoreal_move<float>(data+2,(float&)nd->mTransformation.b2); 1.311 + } 1.312 + else if (data[0] == 'Z' && data[1] == '=') { 1.313 + data = fast_atoreal_move<float>(data+2,(float&)nd->mTransformation.c3); 1.314 + } 1.315 + } 1.316 + } 1.317 + } 1.318 + } 1.319 + } 1.320 + } 1.321 + else { 1.322 + DefaultLogger::get()->error("Unable to open .uc file"); 1.323 + } 1.324 + 1.325 + std::vector<Unreal::TempMat> materials; 1.326 + materials.reserve(textures.size()*2+5); 1.327 + 1.328 + // find out how many output meshes and materials we'll have and build material indices 1.329 + for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) { 1.330 + Unreal::Triangle& tri = *it; 1.331 + Unreal::TempMat mat(tri); 1.332 + std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(),materials.end(),mat); 1.333 + if (nt == materials.end()) { 1.334 + // add material 1.335 + tri.matIndex = materials.size(); 1.336 + mat.numFaces = 1; 1.337 + materials.push_back(mat); 1.338 + 1.339 + ++pScene->mNumMeshes; 1.340 + } 1.341 + else { 1.342 + tri.matIndex = static_cast<unsigned int>(nt-materials.begin()); 1.343 + ++nt->numFaces; 1.344 + } 1.345 + } 1.346 + 1.347 + if (!pScene->mNumMeshes) { 1.348 + throw DeadlyImportError("UNREAL: Unable to find valid mesh data"); 1.349 + } 1.350 + 1.351 + // allocate meshes and bind them to the node graph 1.352 + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; 1.353 + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = pScene->mNumMeshes]; 1.354 + 1.355 + nd->mNumMeshes = pScene->mNumMeshes; 1.356 + nd->mMeshes = new unsigned int[nd->mNumMeshes]; 1.357 + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { 1.358 + aiMesh* m = pScene->mMeshes[i] = new aiMesh(); 1.359 + m->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; 1.360 + 1.361 + const unsigned int num = materials[i].numFaces; 1.362 + m->mFaces = new aiFace [num]; 1.363 + m->mVertices = new aiVector3D [num*3]; 1.364 + m->mTextureCoords[0] = new aiVector3D [num*3]; 1.365 + 1.366 + nd->mMeshes[i] = i; 1.367 + 1.368 + // create materials, too 1.369 + aiMaterial* mat = new aiMaterial(); 1.370 + pScene->mMaterials[i] = mat; 1.371 + 1.372 + // all white by default - texture rulez 1.373 + aiColor3D color(1.f,1.f,1.f); 1.374 + 1.375 + aiString s; 1.376 + ::sprintf(s.data,"mat%i_tx%i_",i,materials[i].tex); 1.377 + 1.378 + // set the two-sided flag 1.379 + if (materials[i].type == Unreal::MF_NORMAL_TS) { 1.380 + const int twosided = 1; 1.381 + mat->AddProperty(&twosided,1,AI_MATKEY_TWOSIDED); 1.382 + ::strcat(s.data,"ts_"); 1.383 + } 1.384 + else ::strcat(s.data,"os_"); 1.385 + 1.386 + // make TRANS faces 90% opaque that RemRedundantMaterials won't catch us 1.387 + if (materials[i].type == Unreal::MF_NORMAL_TRANS_TS) { 1.388 + const float opac = 0.9f; 1.389 + mat->AddProperty(&opac,1,AI_MATKEY_OPACITY); 1.390 + ::strcat(s.data,"tran_"); 1.391 + } 1.392 + else ::strcat(s.data,"opaq_"); 1.393 + 1.394 + // a special name for the weapon attachment point 1.395 + if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) { 1.396 + s.length = ::sprintf(s.data,"$WeaponTag$"); 1.397 + color = aiColor3D(0.f,0.f,0.f); 1.398 + } 1.399 + 1.400 + // set color and name 1.401 + mat->AddProperty(&color,1,AI_MATKEY_COLOR_DIFFUSE); 1.402 + s.length = ::strlen(s.data); 1.403 + mat->AddProperty(&s,AI_MATKEY_NAME); 1.404 + 1.405 + // set texture, if any 1.406 + const unsigned int tex = materials[i].tex; 1.407 + for (std::vector< std::pair< unsigned int, std::string > >::const_iterator it = textures.begin();it != textures.end();++it) { 1.408 + if ((*it).first == tex) { 1.409 + s.Set((*it).second); 1.410 + mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); 1.411 + break; 1.412 + } 1.413 + } 1.414 + } 1.415 + 1.416 + // fill them. 1.417 + for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) { 1.418 + Unreal::Triangle& tri = *it; 1.419 + Unreal::TempMat mat(tri); 1.420 + std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(),materials.end(),mat); 1.421 + 1.422 + aiMesh* mesh = pScene->mMeshes[nt-materials.begin()]; 1.423 + aiFace& f = mesh->mFaces[mesh->mNumFaces++]; 1.424 + f.mIndices = new unsigned int[f.mNumIndices = 3]; 1.425 + 1.426 + for (unsigned int i = 0; i < 3;++i,mesh->mNumVertices++) { 1.427 + f.mIndices[i] = mesh->mNumVertices; 1.428 + 1.429 + mesh->mVertices[mesh->mNumVertices] = vertices[ tri.mVertex[i] ]; 1.430 + mesh->mTextureCoords[0][mesh->mNumVertices] = aiVector3D( tri.mTex[i][0] / 255.f, 1.f - tri.mTex[i][1] / 255.f, 0.f); 1.431 + } 1.432 + } 1.433 + 1.434 + // convert to RH 1.435 + MakeLeftHandedProcess hero; 1.436 + hero.Execute(pScene); 1.437 + 1.438 + FlipWindingOrderProcess flipper; 1.439 + flipper.Execute(pScene); 1.440 +} 1.441 + 1.442 +#endif // !! ASSIMP_BUILD_NO_3D_IMPORTER