vrshoot

annotate libs/assimp/NFFLoader.cpp @ 3:c179c72369be

rename candy->vr
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 03 Feb 2014 08:52:13 +0200
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 ---------------------------------------------------------------------------
nuclear@0 3 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file Implementation of the STL importer class */
nuclear@0 43
nuclear@0 44 #include "AssimpPCH.h"
nuclear@0 45 #ifndef ASSIMP_BUILD_NO_NFF_IMPORTER
nuclear@0 46
nuclear@0 47 // internal headers
nuclear@0 48 #include "NFFLoader.h"
nuclear@0 49 #include "ParsingUtils.h"
nuclear@0 50 #include "StandardShapes.h"
nuclear@0 51 #include "fast_atof.h"
nuclear@0 52 #include "RemoveComments.h"
nuclear@0 53
nuclear@0 54 using namespace Assimp;
nuclear@0 55
nuclear@0 56 static const aiImporterDesc desc = {
nuclear@0 57 "Neutral File Format Importer",
nuclear@0 58 "",
nuclear@0 59 "",
nuclear@0 60 "",
nuclear@0 61 aiImporterFlags_SupportBinaryFlavour,
nuclear@0 62 0,
nuclear@0 63 0,
nuclear@0 64 0,
nuclear@0 65 0,
nuclear@0 66 "enff nff"
nuclear@0 67 };
nuclear@0 68
nuclear@0 69 // ------------------------------------------------------------------------------------------------
nuclear@0 70 // Constructor to be privately used by Importer
nuclear@0 71 NFFImporter::NFFImporter()
nuclear@0 72 {}
nuclear@0 73
nuclear@0 74 // ------------------------------------------------------------------------------------------------
nuclear@0 75 // Destructor, private as well
nuclear@0 76 NFFImporter::~NFFImporter()
nuclear@0 77 {}
nuclear@0 78
nuclear@0 79 // ------------------------------------------------------------------------------------------------
nuclear@0 80 // Returns whether the class can handle the format of the given file.
nuclear@0 81 bool NFFImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const
nuclear@0 82 {
nuclear@0 83 return SimpleExtensionCheck(pFile,"nff","enff");
nuclear@0 84 }
nuclear@0 85
nuclear@0 86 // ------------------------------------------------------------------------------------------------
nuclear@0 87 // Get the list of all supported file extensions
nuclear@0 88 const aiImporterDesc* NFFImporter::GetInfo () const
nuclear@0 89 {
nuclear@0 90 return &desc;
nuclear@0 91 }
nuclear@0 92
nuclear@0 93 // ------------------------------------------------------------------------------------------------
nuclear@0 94 #define AI_NFF_PARSE_FLOAT(f) \
nuclear@0 95 SkipSpaces(&sz); \
nuclear@0 96 if (!::IsLineEnd(*sz))sz = fast_atoreal_move<float>(sz, (float&)f);
nuclear@0 97
nuclear@0 98 // ------------------------------------------------------------------------------------------------
nuclear@0 99 #define AI_NFF_PARSE_TRIPLE(v) \
nuclear@0 100 AI_NFF_PARSE_FLOAT(v[0]) \
nuclear@0 101 AI_NFF_PARSE_FLOAT(v[1]) \
nuclear@0 102 AI_NFF_PARSE_FLOAT(v[2])
nuclear@0 103
nuclear@0 104 // ------------------------------------------------------------------------------------------------
nuclear@0 105 #define AI_NFF_PARSE_SHAPE_INFORMATION() \
nuclear@0 106 aiVector3D center, radius(1.0f,get_qnan(),get_qnan()); \
nuclear@0 107 AI_NFF_PARSE_TRIPLE(center); \
nuclear@0 108 AI_NFF_PARSE_TRIPLE(radius); \
nuclear@0 109 if (is_qnan(radius.z))radius.z = radius.x; \
nuclear@0 110 if (is_qnan(radius.y))radius.y = radius.x; \
nuclear@0 111 currentMesh.radius = radius; \
nuclear@0 112 currentMesh.center = center;
nuclear@0 113
nuclear@0 114 // ------------------------------------------------------------------------------------------------
nuclear@0 115 #define AI_NFF2_GET_NEXT_TOKEN() \
nuclear@0 116 do \
nuclear@0 117 { \
nuclear@0 118 if (!GetNextLine(buffer,line)) \
nuclear@0 119 {DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read next token");break;} \
nuclear@0 120 SkipSpaces(line,&sz); \
nuclear@0 121 } \
nuclear@0 122 while(IsLineEnd(*sz))
nuclear@0 123
nuclear@0 124
nuclear@0 125 // ------------------------------------------------------------------------------------------------
nuclear@0 126 // Loads the materail table for the NFF2 file format from an external file
nuclear@0 127 void NFFImporter::LoadNFF2MaterialTable(std::vector<ShadingInfo>& output,
nuclear@0 128 const std::string& path, IOSystem* pIOHandler)
nuclear@0 129 {
nuclear@0 130 boost::scoped_ptr<IOStream> file( pIOHandler->Open( path, "rb"));
nuclear@0 131
nuclear@0 132 // Check whether we can read from the file
nuclear@0 133 if( !file.get()) {
nuclear@0 134 DefaultLogger::get()->error("NFF2: Unable to open material library " + path + ".");
nuclear@0 135 return;
nuclear@0 136 }
nuclear@0 137
nuclear@0 138 // get the size of the file
nuclear@0 139 const unsigned int m = (unsigned int)file->FileSize();
nuclear@0 140
nuclear@0 141 // allocate storage and copy the contents of the file to a memory buffer
nuclear@0 142 // (terminate it with zero)
nuclear@0 143 std::vector<char> mBuffer2(m+1);
nuclear@0 144 TextFileToBuffer(file.get(),mBuffer2);
nuclear@0 145 const char* buffer = &mBuffer2[0];
nuclear@0 146
nuclear@0 147 // First of all: remove all comments from the file
nuclear@0 148 CommentRemover::RemoveLineComments("//",&mBuffer2[0]);
nuclear@0 149
nuclear@0 150 // The file should start with the magic sequence "mat"
nuclear@0 151 if (!TokenMatch(buffer,"mat",3)) {
nuclear@0 152 DefaultLogger::get()->error("NFF2: Not a valid material library " + path + ".");
nuclear@0 153 return;
nuclear@0 154 }
nuclear@0 155
nuclear@0 156 ShadingInfo* curShader = NULL;
nuclear@0 157
nuclear@0 158 // No read the file line per line
nuclear@0 159 char line[4096];
nuclear@0 160 const char* sz;
nuclear@0 161 while (GetNextLine(buffer,line))
nuclear@0 162 {
nuclear@0 163 SkipSpaces(line,&sz);
nuclear@0 164
nuclear@0 165 // 'version' defines the version of the file format
nuclear@0 166 if (TokenMatch(sz,"version",7))
nuclear@0 167 {
nuclear@0 168 DefaultLogger::get()->info("NFF (Sense8) material library file format: " + std::string(sz));
nuclear@0 169 }
nuclear@0 170 // 'matdef' starts a new material in the file
nuclear@0 171 else if (TokenMatch(sz,"matdef",6))
nuclear@0 172 {
nuclear@0 173 // add a new material to the list
nuclear@0 174 output.push_back( ShadingInfo() );
nuclear@0 175 curShader = & output.back();
nuclear@0 176
nuclear@0 177 // parse the name of the material
nuclear@0 178 }
nuclear@0 179 else if (!TokenMatch(sz,"valid",5))
nuclear@0 180 {
nuclear@0 181 // check whether we have an active material at the moment
nuclear@0 182 if (!IsLineEnd(*sz))
nuclear@0 183 {
nuclear@0 184 if (!curShader)
nuclear@0 185 {
nuclear@0 186 DefaultLogger::get()->error(std::string("NFF2 material library: Found element ") +
nuclear@0 187 sz + "but there is no active material");
nuclear@0 188 continue;
nuclear@0 189 }
nuclear@0 190 }
nuclear@0 191 else continue;
nuclear@0 192
nuclear@0 193 // now read the material property and determine its type
nuclear@0 194 aiColor3D c;
nuclear@0 195 if (TokenMatch(sz,"ambient",7))
nuclear@0 196 {
nuclear@0 197 AI_NFF_PARSE_TRIPLE(c);
nuclear@0 198 curShader->ambient = c;
nuclear@0 199 }
nuclear@0 200 else if (TokenMatch(sz,"diffuse",7) || TokenMatch(sz,"ambientdiffuse",14) /* correct? */)
nuclear@0 201 {
nuclear@0 202 AI_NFF_PARSE_TRIPLE(c);
nuclear@0 203 curShader->diffuse = curShader->ambient = c;
nuclear@0 204 }
nuclear@0 205 else if (TokenMatch(sz,"specular",8))
nuclear@0 206 {
nuclear@0 207 AI_NFF_PARSE_TRIPLE(c);
nuclear@0 208 curShader->specular = c;
nuclear@0 209 }
nuclear@0 210 else if (TokenMatch(sz,"emission",8))
nuclear@0 211 {
nuclear@0 212 AI_NFF_PARSE_TRIPLE(c);
nuclear@0 213 curShader->emissive = c;
nuclear@0 214 }
nuclear@0 215 else if (TokenMatch(sz,"shininess",9))
nuclear@0 216 {
nuclear@0 217 AI_NFF_PARSE_FLOAT(curShader->shininess);
nuclear@0 218 }
nuclear@0 219 else if (TokenMatch(sz,"opacity",7))
nuclear@0 220 {
nuclear@0 221 AI_NFF_PARSE_FLOAT(curShader->opacity);
nuclear@0 222 }
nuclear@0 223 }
nuclear@0 224 }
nuclear@0 225 }
nuclear@0 226
nuclear@0 227 // ------------------------------------------------------------------------------------------------
nuclear@0 228 // Imports the given file into the given scene structure.
nuclear@0 229 void NFFImporter::InternReadFile( const std::string& pFile,
nuclear@0 230 aiScene* pScene, IOSystem* pIOHandler)
nuclear@0 231 {
nuclear@0 232 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
nuclear@0 233
nuclear@0 234 // Check whether we can read from the file
nuclear@0 235 if( !file.get())
nuclear@0 236 throw DeadlyImportError( "Failed to open NFF file " + pFile + ".");
nuclear@0 237
nuclear@0 238 unsigned int m = (unsigned int)file->FileSize();
nuclear@0 239
nuclear@0 240 // allocate storage and copy the contents of the file to a memory buffer
nuclear@0 241 // (terminate it with zero)
nuclear@0 242 std::vector<char> mBuffer2;
nuclear@0 243 TextFileToBuffer(file.get(),mBuffer2);
nuclear@0 244 const char* buffer = &mBuffer2[0];
nuclear@0 245
nuclear@0 246 // mesh arrays - separate here to make the handling of the pointers below easier.
nuclear@0 247 std::vector<MeshInfo> meshes;
nuclear@0 248 std::vector<MeshInfo> meshesWithNormals;
nuclear@0 249 std::vector<MeshInfo> meshesWithUVCoords;
nuclear@0 250 std::vector<MeshInfo> meshesLocked;
nuclear@0 251
nuclear@0 252 char line[4096];
nuclear@0 253 const char* sz;
nuclear@0 254
nuclear@0 255 // camera parameters
nuclear@0 256 aiVector3D camPos, camUp(0.f,1.f,0.f), camLookAt(0.f,0.f,1.f);
nuclear@0 257 float angle = 45.f;
nuclear@0 258 aiVector2D resolution;
nuclear@0 259
nuclear@0 260 bool hasCam = false;
nuclear@0 261
nuclear@0 262 MeshInfo* currentMeshWithNormals = NULL;
nuclear@0 263 MeshInfo* currentMesh = NULL;
nuclear@0 264 MeshInfo* currentMeshWithUVCoords = NULL;
nuclear@0 265
nuclear@0 266 ShadingInfo s; // current material info
nuclear@0 267
nuclear@0 268 // degree of tesselation
nuclear@0 269 unsigned int iTesselation = 4;
nuclear@0 270
nuclear@0 271 // some temporary variables we need to parse the file
nuclear@0 272 unsigned int sphere = 0,
nuclear@0 273 cylinder = 0,
nuclear@0 274 cone = 0,
nuclear@0 275 numNamed = 0,
nuclear@0 276 dodecahedron = 0,
nuclear@0 277 octahedron = 0,
nuclear@0 278 tetrahedron = 0,
nuclear@0 279 hexahedron = 0;
nuclear@0 280
nuclear@0 281 // lights imported from the file
nuclear@0 282 std::vector<Light> lights;
nuclear@0 283
nuclear@0 284 // check whether this is the NFF2 file format
nuclear@0 285 if (TokenMatch(buffer,"nff",3))
nuclear@0 286 {
nuclear@0 287 const float qnan = get_qnan();
nuclear@0 288 const aiColor4D cQNAN = aiColor4D (qnan,0.f,0.f,1.f);
nuclear@0 289 const aiVector3D vQNAN = aiVector3D(qnan,0.f,0.f);
nuclear@0 290
nuclear@0 291 // another NFF file format ... just a raw parser has been implemented
nuclear@0 292 // no support for further details, I don't think it is worth the effort
nuclear@0 293 // http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/nff/nff2.html
nuclear@0 294 // http://www.netghost.narod.ru/gff/graphics/summary/sense8.htm
nuclear@0 295
nuclear@0 296 // First of all: remove all comments from the file
nuclear@0 297 CommentRemover::RemoveLineComments("//",&mBuffer2[0]);
nuclear@0 298
nuclear@0 299 while (GetNextLine(buffer,line))
nuclear@0 300 {
nuclear@0 301 SkipSpaces(line,&sz);
nuclear@0 302 if (TokenMatch(sz,"version",7))
nuclear@0 303 {
nuclear@0 304 DefaultLogger::get()->info("NFF (Sense8) file format: " + std::string(sz));
nuclear@0 305 }
nuclear@0 306 else if (TokenMatch(sz,"viewpos",7))
nuclear@0 307 {
nuclear@0 308 AI_NFF_PARSE_TRIPLE(camPos);
nuclear@0 309 hasCam = true;
nuclear@0 310 }
nuclear@0 311 else if (TokenMatch(sz,"viewdir",7))
nuclear@0 312 {
nuclear@0 313 AI_NFF_PARSE_TRIPLE(camLookAt);
nuclear@0 314 hasCam = true;
nuclear@0 315 }
nuclear@0 316 // This starts a new object section
nuclear@0 317 else if (!IsSpaceOrNewLine(*sz))
nuclear@0 318 {
nuclear@0 319 unsigned int subMeshIdx = 0;
nuclear@0 320
nuclear@0 321 // read the name of the object, skip all spaces
nuclear@0 322 // at the end of it.
nuclear@0 323 const char* sz3 = sz;
nuclear@0 324 while (!IsSpaceOrNewLine(*sz))++sz;
nuclear@0 325 std::string objectName = std::string(sz3,(unsigned int)(sz-sz3));
nuclear@0 326
nuclear@0 327 const unsigned int objStart = (unsigned int)meshes.size();
nuclear@0 328
nuclear@0 329 // There could be a material table in a separate file
nuclear@0 330 std::vector<ShadingInfo> materialTable;
nuclear@0 331 while (true)
nuclear@0 332 {
nuclear@0 333 AI_NFF2_GET_NEXT_TOKEN();
nuclear@0 334
nuclear@0 335 // material table - an external file
nuclear@0 336 if (TokenMatch(sz,"mtable",6))
nuclear@0 337 {
nuclear@0 338 SkipSpaces(&sz);
nuclear@0 339 sz3 = sz;
nuclear@0 340 while (!IsSpaceOrNewLine(*sz))++sz;
nuclear@0 341 const unsigned int diff = (unsigned int)(sz-sz3);
nuclear@0 342 if (!diff)DefaultLogger::get()->warn("NFF2: Found empty mtable token");
nuclear@0 343 else
nuclear@0 344 {
nuclear@0 345 // The material table has the file extension .mat.
nuclear@0 346 // If it is not there, we need to append it
nuclear@0 347 std::string path = std::string(sz3,diff);
nuclear@0 348 if(std::string::npos == path.find_last_of(".mat"))
nuclear@0 349 {
nuclear@0 350 path.append(".mat");
nuclear@0 351 }
nuclear@0 352
nuclear@0 353 // Now extract the working directory from the path to
nuclear@0 354 // this file and append the material library filename
nuclear@0 355 // to it.
nuclear@0 356 std::string::size_type s;
nuclear@0 357 if ((std::string::npos == (s = path.find_last_of('\\')) || !s) &&
nuclear@0 358 (std::string::npos == (s = path.find_last_of('/')) || !s) )
nuclear@0 359 {
nuclear@0 360 s = pFile.find_last_of('\\');
nuclear@0 361 if (std::string::npos == s)s = pFile.find_last_of('/');
nuclear@0 362 if (std::string::npos != s)
nuclear@0 363 {
nuclear@0 364 path = pFile.substr(0,s+1) + path;
nuclear@0 365 }
nuclear@0 366 }
nuclear@0 367 LoadNFF2MaterialTable(materialTable,path,pIOHandler);
nuclear@0 368 }
nuclear@0 369 }
nuclear@0 370 else break;
nuclear@0 371 }
nuclear@0 372
nuclear@0 373 // read the numbr of vertices
nuclear@0 374 unsigned int num = ::strtoul10(sz,&sz);
nuclear@0 375
nuclear@0 376 // temporary storage
nuclear@0 377 std::vector<aiColor4D> tempColors;
nuclear@0 378 std::vector<aiVector3D> tempPositions,tempTextureCoords,tempNormals;
nuclear@0 379
nuclear@0 380 bool hasNormals = false,hasUVs = false,hasColor = false;
nuclear@0 381
nuclear@0 382 tempPositions.reserve (num);
nuclear@0 383 tempColors.reserve (num);
nuclear@0 384 tempNormals.reserve (num);
nuclear@0 385 tempTextureCoords.reserve (num);
nuclear@0 386 for (unsigned int i = 0; i < num; ++i)
nuclear@0 387 {
nuclear@0 388 AI_NFF2_GET_NEXT_TOKEN();
nuclear@0 389 aiVector3D v;
nuclear@0 390 AI_NFF_PARSE_TRIPLE(v);
nuclear@0 391 tempPositions.push_back(v);
nuclear@0 392
nuclear@0 393 // parse all other attributes in the line
nuclear@0 394 while (true)
nuclear@0 395 {
nuclear@0 396 SkipSpaces(&sz);
nuclear@0 397 if (IsLineEnd(*sz))break;
nuclear@0 398
nuclear@0 399 // color definition
nuclear@0 400 if (TokenMatch(sz,"0x",2))
nuclear@0 401 {
nuclear@0 402 hasColor = true;
nuclear@0 403 register unsigned int numIdx = ::strtoul16(sz,&sz);
nuclear@0 404 aiColor4D clr;
nuclear@0 405 clr.a = 1.f;
nuclear@0 406
nuclear@0 407 // 0xRRGGBB
nuclear@0 408 clr.r = ((numIdx >> 16u) & 0xff) / 255.f;
nuclear@0 409 clr.g = ((numIdx >> 8u) & 0xff) / 255.f;
nuclear@0 410 clr.b = ((numIdx) & 0xff) / 255.f;
nuclear@0 411 tempColors.push_back(clr);
nuclear@0 412 }
nuclear@0 413 // normal vector
nuclear@0 414 else if (TokenMatch(sz,"norm",4))
nuclear@0 415 {
nuclear@0 416 hasNormals = true;
nuclear@0 417 AI_NFF_PARSE_TRIPLE(v);
nuclear@0 418 tempNormals.push_back(v);
nuclear@0 419 }
nuclear@0 420 // UV coordinate
nuclear@0 421 else if (TokenMatch(sz,"uv",2))
nuclear@0 422 {
nuclear@0 423 hasUVs = true;
nuclear@0 424 AI_NFF_PARSE_FLOAT(v.x);
nuclear@0 425 AI_NFF_PARSE_FLOAT(v.y);
nuclear@0 426 v.z = 0.f;
nuclear@0 427 tempTextureCoords.push_back(v);
nuclear@0 428 }
nuclear@0 429 }
nuclear@0 430
nuclear@0 431 // fill in dummies for all attributes that have not been set
nuclear@0 432 if (tempNormals.size() != tempPositions.size())
nuclear@0 433 tempNormals.push_back(vQNAN);
nuclear@0 434
nuclear@0 435 if (tempTextureCoords.size() != tempPositions.size())
nuclear@0 436 tempTextureCoords.push_back(vQNAN);
nuclear@0 437
nuclear@0 438 if (tempColors.size() != tempPositions.size())
nuclear@0 439 tempColors.push_back(cQNAN);
nuclear@0 440 }
nuclear@0 441
nuclear@0 442 AI_NFF2_GET_NEXT_TOKEN();
nuclear@0 443 if (!num)throw DeadlyImportError("NFF2: There are zero vertices");
nuclear@0 444 num = ::strtoul10(sz,&sz);
nuclear@0 445
nuclear@0 446 std::vector<unsigned int> tempIdx;
nuclear@0 447 tempIdx.reserve(10);
nuclear@0 448 for (unsigned int i = 0; i < num; ++i)
nuclear@0 449 {
nuclear@0 450 AI_NFF2_GET_NEXT_TOKEN();
nuclear@0 451 SkipSpaces(line,&sz);
nuclear@0 452 unsigned int numIdx = ::strtoul10(sz,&sz);
nuclear@0 453
nuclear@0 454 // read all faces indices
nuclear@0 455 if (numIdx)
nuclear@0 456 {
nuclear@0 457 // mesh.faces.push_back(numIdx);
nuclear@0 458 // tempIdx.erase(tempIdx.begin(),tempIdx.end());
nuclear@0 459 tempIdx.resize(numIdx);
nuclear@0 460
nuclear@0 461 for (unsigned int a = 0; a < numIdx;++a)
nuclear@0 462 {
nuclear@0 463 SkipSpaces(sz,&sz);
nuclear@0 464 m = ::strtoul10(sz,&sz);
nuclear@0 465 if (m >= (unsigned int)tempPositions.size())
nuclear@0 466 {
nuclear@0 467 DefaultLogger::get()->error("NFF2: Vertex index overflow");
nuclear@0 468 m= 0;
nuclear@0 469 }
nuclear@0 470 // mesh.vertices.push_back (tempPositions[idx]);
nuclear@0 471 tempIdx[a] = m;
nuclear@0 472 }
nuclear@0 473 }
nuclear@0 474
nuclear@0 475 // build a temporary shader object for the face.
nuclear@0 476 ShadingInfo shader;
nuclear@0 477 unsigned int matIdx = 0;
nuclear@0 478
nuclear@0 479 // white material color - we have vertex colors
nuclear@0 480 shader.color = aiColor3D(1.f,1.f,1.f);
nuclear@0 481 aiColor4D c = aiColor4D(1.f,1.f,1.f,1.f);
nuclear@0 482 while (true)
nuclear@0 483 {
nuclear@0 484 SkipSpaces(sz,&sz);
nuclear@0 485 if(IsLineEnd(*sz))break;
nuclear@0 486
nuclear@0 487 // per-polygon colors
nuclear@0 488 if (TokenMatch(sz,"0x",2))
nuclear@0 489 {
nuclear@0 490 hasColor = true;
nuclear@0 491 const char* sz2 = sz;
nuclear@0 492 numIdx = ::strtoul16(sz,&sz);
nuclear@0 493 const unsigned int diff = (unsigned int)(sz-sz2);
nuclear@0 494
nuclear@0 495 // 0xRRGGBB
nuclear@0 496 if (diff > 3)
nuclear@0 497 {
nuclear@0 498 c.r = ((numIdx >> 16u) & 0xff) / 255.f;
nuclear@0 499 c.g = ((numIdx >> 8u) & 0xff) / 255.f;
nuclear@0 500 c.b = ((numIdx) & 0xff) / 255.f;
nuclear@0 501 }
nuclear@0 502 // 0xRGB
nuclear@0 503 else
nuclear@0 504 {
nuclear@0 505 c.r = ((numIdx >> 8u) & 0xf) / 16.f;
nuclear@0 506 c.g = ((numIdx >> 4u) & 0xf) / 16.f;
nuclear@0 507 c.b = ((numIdx) & 0xf) / 16.f;
nuclear@0 508 }
nuclear@0 509 }
nuclear@0 510 // TODO - implement texture mapping here
nuclear@0 511 #if 0
nuclear@0 512 // mirror vertex texture coordinate?
nuclear@0 513 else if (TokenMatch(sz,"mirror",6))
nuclear@0 514 {
nuclear@0 515 }
nuclear@0 516 // texture coordinate scaling
nuclear@0 517 else if (TokenMatch(sz,"scale",5))
nuclear@0 518 {
nuclear@0 519 }
nuclear@0 520 // texture coordinate translation
nuclear@0 521 else if (TokenMatch(sz,"trans",5))
nuclear@0 522 {
nuclear@0 523 }
nuclear@0 524 // texture coordinate rotation angle
nuclear@0 525 else if (TokenMatch(sz,"rot",3))
nuclear@0 526 {
nuclear@0 527 }
nuclear@0 528 #endif
nuclear@0 529
nuclear@0 530 // texture file name for this polygon + mapping information
nuclear@0 531 else if ('_' == sz[0])
nuclear@0 532 {
nuclear@0 533 // get mapping information
nuclear@0 534 switch (sz[1])
nuclear@0 535 {
nuclear@0 536 case 'v':
nuclear@0 537 case 'V':
nuclear@0 538
nuclear@0 539 shader.shaded = false;
nuclear@0 540 break;
nuclear@0 541
nuclear@0 542 case 't':
nuclear@0 543 case 'T':
nuclear@0 544 case 'u':
nuclear@0 545 case 'U':
nuclear@0 546
nuclear@0 547 DefaultLogger::get()->warn("Unsupported NFF2 texture attribute: trans");
nuclear@0 548 };
nuclear@0 549 if (!sz[1] || '_' != sz[2])
nuclear@0 550 {
nuclear@0 551 DefaultLogger::get()->warn("NFF2: Expected underscore after texture attributes");
nuclear@0 552 continue;
nuclear@0 553 }
nuclear@0 554 const char* sz2 = sz+3;
nuclear@0 555 while (!IsSpaceOrNewLine( *sz ))++sz;
nuclear@0 556 const unsigned int diff = (unsigned int)(sz-sz2);
nuclear@0 557 if (diff)shader.texFile = std::string(sz2,diff);
nuclear@0 558 }
nuclear@0 559
nuclear@0 560 // Two-sided material?
nuclear@0 561 else if (TokenMatch(sz,"both",4))
nuclear@0 562 {
nuclear@0 563 shader.twoSided = true;
nuclear@0 564 }
nuclear@0 565
nuclear@0 566 // Material ID?
nuclear@0 567 else if (!materialTable.empty() && TokenMatch(sz,"matid",5))
nuclear@0 568 {
nuclear@0 569 SkipSpaces(&sz);
nuclear@0 570 matIdx = ::strtoul10(sz,&sz);
nuclear@0 571 if (matIdx >= materialTable.size())
nuclear@0 572 {
nuclear@0 573 DefaultLogger::get()->error("NFF2: Material index overflow.");
nuclear@0 574 matIdx = 0;
nuclear@0 575 }
nuclear@0 576
nuclear@0 577 // now combine our current shader with the shader we
nuclear@0 578 // read from the material table.
nuclear@0 579 ShadingInfo& mat = materialTable[matIdx];
nuclear@0 580 shader.ambient = mat.ambient;
nuclear@0 581 shader.diffuse = mat.diffuse;
nuclear@0 582 shader.emissive = mat.emissive;
nuclear@0 583 shader.opacity = mat.opacity;
nuclear@0 584 shader.specular = mat.specular;
nuclear@0 585 shader.shininess = mat.shininess;
nuclear@0 586 }
nuclear@0 587 else SkipToken(sz);
nuclear@0 588 }
nuclear@0 589
nuclear@0 590 // search the list of all shaders we have for this object whether
nuclear@0 591 // there is an identical one. In this case, we append our mesh
nuclear@0 592 // data to it.
nuclear@0 593 MeshInfo* mesh = NULL;
nuclear@0 594 for (std::vector<MeshInfo>::iterator it = meshes.begin() + objStart, end = meshes.end();
nuclear@0 595 it != end; ++it)
nuclear@0 596 {
nuclear@0 597 if ((*it).shader == shader && (*it).matIndex == matIdx)
nuclear@0 598 {
nuclear@0 599 // we have one, we can append our data to it
nuclear@0 600 mesh = &(*it);
nuclear@0 601 }
nuclear@0 602 }
nuclear@0 603 if (!mesh)
nuclear@0 604 {
nuclear@0 605 meshes.push_back(MeshInfo(PatchType_Simple,false));
nuclear@0 606 mesh = &meshes.back();
nuclear@0 607 mesh->matIndex = matIdx;
nuclear@0 608
nuclear@0 609 // We need to add a new mesh to the list. We assign
nuclear@0 610 // an unique name to it to make sure the scene will
nuclear@0 611 // pass the validation step for the moment.
nuclear@0 612 // TODO: fix naming of objects in the scenegraph later
nuclear@0 613 if (objectName.length())
nuclear@0 614 {
nuclear@0 615 ::strcpy(mesh->name,objectName.c_str());
nuclear@0 616 ASSIMP_itoa10(&mesh->name[objectName.length()],30,subMeshIdx++);
nuclear@0 617 }
nuclear@0 618
nuclear@0 619 // copy the shader to the mesh.
nuclear@0 620 mesh->shader = shader;
nuclear@0 621 }
nuclear@0 622
nuclear@0 623 // fill the mesh with data
nuclear@0 624 if (!tempIdx.empty())
nuclear@0 625 {
nuclear@0 626 mesh->faces.push_back((unsigned int)tempIdx.size());
nuclear@0 627 for (std::vector<unsigned int>::const_iterator it = tempIdx.begin(), end = tempIdx.end();
nuclear@0 628 it != end;++it)
nuclear@0 629 {
nuclear@0 630 m = *it;
nuclear@0 631
nuclear@0 632 // copy colors -vertex color specifications override polygon color specifications
nuclear@0 633 if (hasColor)
nuclear@0 634 {
nuclear@0 635 const aiColor4D& clr = tempColors[m];
nuclear@0 636 mesh->colors.push_back((is_qnan( clr.r ) ? c : clr));
nuclear@0 637 }
nuclear@0 638
nuclear@0 639 // positions should always be there
nuclear@0 640 mesh->vertices.push_back (tempPositions[m]);
nuclear@0 641
nuclear@0 642 // copy normal vectors
nuclear@0 643 if (hasNormals)
nuclear@0 644 mesh->normals.push_back (tempNormals[m]);
nuclear@0 645
nuclear@0 646 // copy texture coordinates
nuclear@0 647 if (hasUVs)
nuclear@0 648 mesh->uvs.push_back (tempTextureCoords[m]);
nuclear@0 649 }
nuclear@0 650 }
nuclear@0 651 }
nuclear@0 652 if (!num)throw DeadlyImportError("NFF2: There are zero faces");
nuclear@0 653 }
nuclear@0 654 }
nuclear@0 655 camLookAt = camLookAt + camPos;
nuclear@0 656 }
nuclear@0 657 else // "Normal" Neutral file format that is quite more common
nuclear@0 658 {
nuclear@0 659 while (GetNextLine(buffer,line))
nuclear@0 660 {
nuclear@0 661 sz = line;
nuclear@0 662 if ('p' == line[0] || TokenMatch(sz,"tpp",3))
nuclear@0 663 {
nuclear@0 664 MeshInfo* out = NULL;
nuclear@0 665
nuclear@0 666 // 'tpp' - texture polygon patch primitive
nuclear@0 667 if ('t' == line[0])
nuclear@0 668 {
nuclear@0 669 currentMeshWithUVCoords = NULL;
nuclear@0 670 for (std::vector<MeshInfo>::iterator it = meshesWithUVCoords.begin(), end = meshesWithUVCoords.end();
nuclear@0 671 it != end;++it)
nuclear@0 672 {
nuclear@0 673 if ((*it).shader == s)
nuclear@0 674 {
nuclear@0 675 currentMeshWithUVCoords = &(*it);
nuclear@0 676 break;
nuclear@0 677 }
nuclear@0 678 }
nuclear@0 679
nuclear@0 680 if (!currentMeshWithUVCoords)
nuclear@0 681 {
nuclear@0 682 meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals));
nuclear@0 683 currentMeshWithUVCoords = &meshesWithUVCoords.back();
nuclear@0 684 currentMeshWithUVCoords->shader = s;
nuclear@0 685 }
nuclear@0 686 out = currentMeshWithUVCoords;
nuclear@0 687 }
nuclear@0 688 // 'pp' - polygon patch primitive
nuclear@0 689 else if ('p' == line[1])
nuclear@0 690 {
nuclear@0 691 currentMeshWithNormals = NULL;
nuclear@0 692 for (std::vector<MeshInfo>::iterator it = meshesWithNormals.begin(), end = meshesWithNormals.end();
nuclear@0 693 it != end;++it)
nuclear@0 694 {
nuclear@0 695 if ((*it).shader == s)
nuclear@0 696 {
nuclear@0 697 currentMeshWithNormals = &(*it);
nuclear@0 698 break;
nuclear@0 699 }
nuclear@0 700 }
nuclear@0 701
nuclear@0 702 if (!currentMeshWithNormals)
nuclear@0 703 {
nuclear@0 704 meshesWithNormals.push_back(MeshInfo(PatchType_Normals));
nuclear@0 705 currentMeshWithNormals = &meshesWithNormals.back();
nuclear@0 706 currentMeshWithNormals->shader = s;
nuclear@0 707 }
nuclear@0 708 sz = &line[2];out = currentMeshWithNormals;
nuclear@0 709 }
nuclear@0 710 // 'p' - polygon primitive
nuclear@0 711 else
nuclear@0 712 {
nuclear@0 713 currentMesh = NULL;
nuclear@0 714 for (std::vector<MeshInfo>::iterator it = meshes.begin(), end = meshes.end();
nuclear@0 715 it != end;++it)
nuclear@0 716 {
nuclear@0 717 if ((*it).shader == s)
nuclear@0 718 {
nuclear@0 719 currentMesh = &(*it);
nuclear@0 720 break;
nuclear@0 721 }
nuclear@0 722 }
nuclear@0 723
nuclear@0 724 if (!currentMesh)
nuclear@0 725 {
nuclear@0 726 meshes.push_back(MeshInfo(PatchType_Simple));
nuclear@0 727 currentMesh = &meshes.back();
nuclear@0 728 currentMesh->shader = s;
nuclear@0 729 }
nuclear@0 730 sz = &line[1];out = currentMesh;
nuclear@0 731 }
nuclear@0 732 SkipSpaces(sz,&sz);
nuclear@0 733 m = strtoul10(sz);
nuclear@0 734
nuclear@0 735 // ---- flip the face order
nuclear@0 736 out->vertices.resize(out->vertices.size()+m);
nuclear@0 737 if (out != currentMesh)
nuclear@0 738 {
nuclear@0 739 out->normals.resize(out->vertices.size());
nuclear@0 740 }
nuclear@0 741 if (out == currentMeshWithUVCoords)
nuclear@0 742 {
nuclear@0 743 out->uvs.resize(out->vertices.size());
nuclear@0 744 }
nuclear@0 745 for (unsigned int n = 0; n < m;++n)
nuclear@0 746 {
nuclear@0 747 if(!GetNextLine(buffer,line))
nuclear@0 748 {
nuclear@0 749 DefaultLogger::get()->error("NFF: Unexpected EOF was encountered. Patch definition incomplete");
nuclear@0 750 continue;
nuclear@0 751 }
nuclear@0 752
nuclear@0 753 aiVector3D v; sz = &line[0];
nuclear@0 754 AI_NFF_PARSE_TRIPLE(v);
nuclear@0 755 out->vertices[out->vertices.size()-n-1] = v;
nuclear@0 756
nuclear@0 757 if (out != currentMesh)
nuclear@0 758 {
nuclear@0 759 AI_NFF_PARSE_TRIPLE(v);
nuclear@0 760 out->normals[out->vertices.size()-n-1] = v;
nuclear@0 761 }
nuclear@0 762 if (out == currentMeshWithUVCoords)
nuclear@0 763 {
nuclear@0 764 // FIX: in one test file this wraps over multiple lines
nuclear@0 765 SkipSpaces(&sz);
nuclear@0 766 if (IsLineEnd(*sz))
nuclear@0 767 {
nuclear@0 768 GetNextLine(buffer,line);
nuclear@0 769 sz = line;
nuclear@0 770 }
nuclear@0 771 AI_NFF_PARSE_FLOAT(v.x);
nuclear@0 772 SkipSpaces(&sz);
nuclear@0 773 if (IsLineEnd(*sz))
nuclear@0 774 {
nuclear@0 775 GetNextLine(buffer,line);
nuclear@0 776 sz = line;
nuclear@0 777 }
nuclear@0 778 AI_NFF_PARSE_FLOAT(v.y);
nuclear@0 779 v.y = 1.f - v.y;
nuclear@0 780 out->uvs[out->vertices.size()-n-1] = v;
nuclear@0 781 }
nuclear@0 782 }
nuclear@0 783 out->faces.push_back(m);
nuclear@0 784 }
nuclear@0 785 // 'f' - shading information block
nuclear@0 786 else if (TokenMatch(sz,"f",1))
nuclear@0 787 {
nuclear@0 788 float d;
nuclear@0 789
nuclear@0 790 // read the RGB colors
nuclear@0 791 AI_NFF_PARSE_TRIPLE(s.color);
nuclear@0 792
nuclear@0 793 // read the other properties
nuclear@0 794 AI_NFF_PARSE_FLOAT(s.diffuse.r);
nuclear@0 795 AI_NFF_PARSE_FLOAT(s.specular.r);
nuclear@0 796 AI_NFF_PARSE_FLOAT(d); // skip shininess and transmittance
nuclear@0 797 AI_NFF_PARSE_FLOAT(d);
nuclear@0 798 AI_NFF_PARSE_FLOAT(s.refracti);
nuclear@0 799
nuclear@0 800 // NFF2 uses full colors here so we need to use them too
nuclear@0 801 // although NFF uses simple scaling factors
nuclear@0 802 s.diffuse.g = s.diffuse.b = s.diffuse.r;
nuclear@0 803 s.specular.g = s.specular.b = s.specular.r;
nuclear@0 804
nuclear@0 805 // if the next one is NOT a number we assume it is a texture file name
nuclear@0 806 // this feature is used by some NFF files on the internet and it has
nuclear@0 807 // been implemented as it can be really useful
nuclear@0 808 SkipSpaces(&sz);
nuclear@0 809 if (!IsNumeric(*sz))
nuclear@0 810 {
nuclear@0 811 // TODO: Support full file names with spaces and quotation marks ...
nuclear@0 812 const char* p = sz;
nuclear@0 813 while (!IsSpaceOrNewLine( *sz ))++sz;
nuclear@0 814
nuclear@0 815 unsigned int diff = (unsigned int)(sz-p);
nuclear@0 816 if (diff)
nuclear@0 817 {
nuclear@0 818 s.texFile = std::string(p,diff);
nuclear@0 819 }
nuclear@0 820 }
nuclear@0 821 else
nuclear@0 822 {
nuclear@0 823 AI_NFF_PARSE_FLOAT(s.ambient); // optional
nuclear@0 824 }
nuclear@0 825 }
nuclear@0 826 // 'shader' - other way to specify a texture
nuclear@0 827 else if (TokenMatch(sz,"shader",6))
nuclear@0 828 {
nuclear@0 829 SkipSpaces(&sz);
nuclear@0 830 const char* old = sz;
nuclear@0 831 while (!IsSpaceOrNewLine(*sz))++sz;
nuclear@0 832 s.texFile = std::string(old, (uintptr_t)sz - (uintptr_t)old);
nuclear@0 833 }
nuclear@0 834 // 'l' - light source
nuclear@0 835 else if (TokenMatch(sz,"l",1))
nuclear@0 836 {
nuclear@0 837 lights.push_back(Light());
nuclear@0 838 Light& light = lights.back();
nuclear@0 839
nuclear@0 840 AI_NFF_PARSE_TRIPLE(light.position);
nuclear@0 841 AI_NFF_PARSE_FLOAT (light.intensity);
nuclear@0 842 AI_NFF_PARSE_TRIPLE(light.color);
nuclear@0 843 }
nuclear@0 844 // 's' - sphere
nuclear@0 845 else if (TokenMatch(sz,"s",1))
nuclear@0 846 {
nuclear@0 847 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
nuclear@0 848 MeshInfo& currentMesh = meshesLocked.back();
nuclear@0 849 currentMesh.shader = s;
nuclear@0 850 currentMesh.shader.mapping = aiTextureMapping_SPHERE;
nuclear@0 851
nuclear@0 852 AI_NFF_PARSE_SHAPE_INFORMATION();
nuclear@0 853
nuclear@0 854 // we don't need scaling or translation here - we do it in the node's transform
nuclear@0 855 StandardShapes::MakeSphere(iTesselation, currentMesh.vertices);
nuclear@0 856 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
nuclear@0 857
nuclear@0 858 // generate a name for the mesh
nuclear@0 859 ::sprintf(currentMesh.name,"sphere_%i",sphere++);
nuclear@0 860 }
nuclear@0 861 // 'dod' - dodecahedron
nuclear@0 862 else if (TokenMatch(sz,"dod",3))
nuclear@0 863 {
nuclear@0 864 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
nuclear@0 865 MeshInfo& currentMesh = meshesLocked.back();
nuclear@0 866 currentMesh.shader = s;
nuclear@0 867 currentMesh.shader.mapping = aiTextureMapping_SPHERE;
nuclear@0 868
nuclear@0 869 AI_NFF_PARSE_SHAPE_INFORMATION();
nuclear@0 870
nuclear@0 871 // we don't need scaling or translation here - we do it in the node's transform
nuclear@0 872 StandardShapes::MakeDodecahedron(currentMesh.vertices);
nuclear@0 873 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
nuclear@0 874
nuclear@0 875 // generate a name for the mesh
nuclear@0 876 ::sprintf(currentMesh.name,"dodecahedron_%i",dodecahedron++);
nuclear@0 877 }
nuclear@0 878
nuclear@0 879 // 'oct' - octahedron
nuclear@0 880 else if (TokenMatch(sz,"oct",3))
nuclear@0 881 {
nuclear@0 882 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
nuclear@0 883 MeshInfo& currentMesh = meshesLocked.back();
nuclear@0 884 currentMesh.shader = s;
nuclear@0 885 currentMesh.shader.mapping = aiTextureMapping_SPHERE;
nuclear@0 886
nuclear@0 887 AI_NFF_PARSE_SHAPE_INFORMATION();
nuclear@0 888
nuclear@0 889 // we don't need scaling or translation here - we do it in the node's transform
nuclear@0 890 StandardShapes::MakeOctahedron(currentMesh.vertices);
nuclear@0 891 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
nuclear@0 892
nuclear@0 893 // generate a name for the mesh
nuclear@0 894 ::sprintf(currentMesh.name,"octahedron_%i",octahedron++);
nuclear@0 895 }
nuclear@0 896
nuclear@0 897 // 'tet' - tetrahedron
nuclear@0 898 else if (TokenMatch(sz,"tet",3))
nuclear@0 899 {
nuclear@0 900 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
nuclear@0 901 MeshInfo& currentMesh = meshesLocked.back();
nuclear@0 902 currentMesh.shader = s;
nuclear@0 903 currentMesh.shader.mapping = aiTextureMapping_SPHERE;
nuclear@0 904
nuclear@0 905 AI_NFF_PARSE_SHAPE_INFORMATION();
nuclear@0 906
nuclear@0 907 // we don't need scaling or translation here - we do it in the node's transform
nuclear@0 908 StandardShapes::MakeTetrahedron(currentMesh.vertices);
nuclear@0 909 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
nuclear@0 910
nuclear@0 911 // generate a name for the mesh
nuclear@0 912 ::sprintf(currentMesh.name,"tetrahedron_%i",tetrahedron++);
nuclear@0 913 }
nuclear@0 914
nuclear@0 915 // 'hex' - hexahedron
nuclear@0 916 else if (TokenMatch(sz,"hex",3))
nuclear@0 917 {
nuclear@0 918 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
nuclear@0 919 MeshInfo& currentMesh = meshesLocked.back();
nuclear@0 920 currentMesh.shader = s;
nuclear@0 921 currentMesh.shader.mapping = aiTextureMapping_BOX;
nuclear@0 922
nuclear@0 923 AI_NFF_PARSE_SHAPE_INFORMATION();
nuclear@0 924
nuclear@0 925 // we don't need scaling or translation here - we do it in the node's transform
nuclear@0 926 StandardShapes::MakeHexahedron(currentMesh.vertices);
nuclear@0 927 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
nuclear@0 928
nuclear@0 929 // generate a name for the mesh
nuclear@0 930 ::sprintf(currentMesh.name,"hexahedron_%i",hexahedron++);
nuclear@0 931 }
nuclear@0 932 // 'c' - cone
nuclear@0 933 else if (TokenMatch(sz,"c",1))
nuclear@0 934 {
nuclear@0 935 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
nuclear@0 936 MeshInfo& currentMesh = meshesLocked.back();
nuclear@0 937 currentMesh.shader = s;
nuclear@0 938 currentMesh.shader.mapping = aiTextureMapping_CYLINDER;
nuclear@0 939
nuclear@0 940 if(!GetNextLine(buffer,line))
nuclear@0 941 {
nuclear@0 942 DefaultLogger::get()->error("NFF: Unexpected end of file (cone definition not complete)");
nuclear@0 943 break;
nuclear@0 944 }
nuclear@0 945 sz = line;
nuclear@0 946
nuclear@0 947 // read the two center points and the respective radii
nuclear@0 948 aiVector3D center1, center2; float radius1, radius2;
nuclear@0 949 AI_NFF_PARSE_TRIPLE(center1);
nuclear@0 950 AI_NFF_PARSE_FLOAT(radius1);
nuclear@0 951
nuclear@0 952 if(!GetNextLine(buffer,line))
nuclear@0 953 {
nuclear@0 954 DefaultLogger::get()->error("NFF: Unexpected end of file (cone definition not complete)");
nuclear@0 955 break;
nuclear@0 956 }
nuclear@0 957 sz = line;
nuclear@0 958
nuclear@0 959 AI_NFF_PARSE_TRIPLE(center2);
nuclear@0 960 AI_NFF_PARSE_FLOAT(radius2);
nuclear@0 961
nuclear@0 962 // compute the center point of the cone/cylinder -
nuclear@0 963 // it is its local transformation origin
nuclear@0 964 currentMesh.dir = center2-center1;
nuclear@0 965 currentMesh.center = center1+currentMesh.dir/2.f;
nuclear@0 966
nuclear@0 967 float f;
nuclear@0 968 if (( f = currentMesh.dir.Length()) < 10e-3f )
nuclear@0 969 {
nuclear@0 970 DefaultLogger::get()->error("NFF: Cone height is close to zero");
nuclear@0 971 continue;
nuclear@0 972 }
nuclear@0 973 currentMesh.dir /= f; // normalize
nuclear@0 974
nuclear@0 975 // generate the cone - it consists of simple triangles
nuclear@0 976 StandardShapes::MakeCone(f, radius1, radius2,
nuclear@0 977 integer_pow(4, iTesselation), currentMesh.vertices);
nuclear@0 978
nuclear@0 979 // MakeCone() returns tris
nuclear@0 980 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
nuclear@0 981
nuclear@0 982 // generate a name for the mesh. 'cone' if it a cone,
nuclear@0 983 // 'cylinder' if it is a cylinder. Funny, isn't it?
nuclear@0 984 if (radius1 != radius2)
nuclear@0 985 ::sprintf(currentMesh.name,"cone_%i",cone++);
nuclear@0 986 else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++);
nuclear@0 987 }
nuclear@0 988 // 'tess' - tesselation
nuclear@0 989 else if (TokenMatch(sz,"tess",4))
nuclear@0 990 {
nuclear@0 991 SkipSpaces(&sz);
nuclear@0 992 iTesselation = strtoul10(sz);
nuclear@0 993 }
nuclear@0 994 // 'from' - camera position
nuclear@0 995 else if (TokenMatch(sz,"from",4))
nuclear@0 996 {
nuclear@0 997 AI_NFF_PARSE_TRIPLE(camPos);
nuclear@0 998 hasCam = true;
nuclear@0 999 }
nuclear@0 1000 // 'at' - camera look-at vector
nuclear@0 1001 else if (TokenMatch(sz,"at",2))
nuclear@0 1002 {
nuclear@0 1003 AI_NFF_PARSE_TRIPLE(camLookAt);
nuclear@0 1004 hasCam = true;
nuclear@0 1005 }
nuclear@0 1006 // 'up' - camera up vector
nuclear@0 1007 else if (TokenMatch(sz,"up",2))
nuclear@0 1008 {
nuclear@0 1009 AI_NFF_PARSE_TRIPLE(camUp);
nuclear@0 1010 hasCam = true;
nuclear@0 1011 }
nuclear@0 1012 // 'angle' - (half?) camera field of view
nuclear@0 1013 else if (TokenMatch(sz,"angle",5))
nuclear@0 1014 {
nuclear@0 1015 AI_NFF_PARSE_FLOAT(angle);
nuclear@0 1016 hasCam = true;
nuclear@0 1017 }
nuclear@0 1018 // 'resolution' - used to compute the screen aspect
nuclear@0 1019 else if (TokenMatch(sz,"resolution",10))
nuclear@0 1020 {
nuclear@0 1021 AI_NFF_PARSE_FLOAT(resolution.x);
nuclear@0 1022 AI_NFF_PARSE_FLOAT(resolution.y);
nuclear@0 1023 hasCam = true;
nuclear@0 1024 }
nuclear@0 1025 // 'pb' - bezier patch. Not supported yet
nuclear@0 1026 else if (TokenMatch(sz,"pb",2))
nuclear@0 1027 {
nuclear@0 1028 DefaultLogger::get()->error("NFF: Encountered unsupported ID: bezier patch");
nuclear@0 1029 }
nuclear@0 1030 // 'pn' - NURBS. Not supported yet
nuclear@0 1031 else if (TokenMatch(sz,"pn",2) || TokenMatch(sz,"pnn",3))
nuclear@0 1032 {
nuclear@0 1033 DefaultLogger::get()->error("NFF: Encountered unsupported ID: NURBS");
nuclear@0 1034 }
nuclear@0 1035 // '' - comment
nuclear@0 1036 else if ('#' == line[0])
nuclear@0 1037 {
nuclear@0 1038 const char* sz;SkipSpaces(&line[1],&sz);
nuclear@0 1039 if (!IsLineEnd(*sz))DefaultLogger::get()->info(sz);
nuclear@0 1040 }
nuclear@0 1041 }
nuclear@0 1042 }
nuclear@0 1043
nuclear@0 1044 // copy all arrays into one large
nuclear@0 1045 meshes.reserve (meshes.size()+meshesLocked.size()+meshesWithNormals.size()+meshesWithUVCoords.size());
nuclear@0 1046 meshes.insert (meshes.end(),meshesLocked.begin(),meshesLocked.end());
nuclear@0 1047 meshes.insert (meshes.end(),meshesWithNormals.begin(),meshesWithNormals.end());
nuclear@0 1048 meshes.insert (meshes.end(),meshesWithUVCoords.begin(),meshesWithUVCoords.end());
nuclear@0 1049
nuclear@0 1050 // now generate output meshes. first find out how many meshes we'll need
nuclear@0 1051 std::vector<MeshInfo>::const_iterator it = meshes.begin(), end = meshes.end();
nuclear@0 1052 for (;it != end;++it)
nuclear@0 1053 {
nuclear@0 1054 if (!(*it).faces.empty())
nuclear@0 1055 {
nuclear@0 1056 ++pScene->mNumMeshes;
nuclear@0 1057 if ((*it).name[0])++numNamed;
nuclear@0 1058 }
nuclear@0 1059 }
nuclear@0 1060
nuclear@0 1061 // generate a dummy root node - assign all unnamed elements such
nuclear@0 1062 // as polygons and polygon patches to the root node and generate
nuclear@0 1063 // sub nodes for named objects such as spheres and cones.
nuclear@0 1064 aiNode* const root = new aiNode();
nuclear@0 1065 root->mName.Set("<NFF_Root>");
nuclear@0 1066 root->mNumChildren = numNamed + (hasCam ? 1 : 0) + (unsigned int) lights.size();
nuclear@0 1067 root->mNumMeshes = pScene->mNumMeshes-numNamed;
nuclear@0 1068
nuclear@0 1069 aiNode** ppcChildren = NULL;
nuclear@0 1070 unsigned int* pMeshes = NULL;
nuclear@0 1071 if (root->mNumMeshes)
nuclear@0 1072 pMeshes = root->mMeshes = new unsigned int[root->mNumMeshes];
nuclear@0 1073 if (root->mNumChildren)
nuclear@0 1074 ppcChildren = root->mChildren = new aiNode*[root->mNumChildren];
nuclear@0 1075
nuclear@0 1076 // generate the camera
nuclear@0 1077 if (hasCam)
nuclear@0 1078 {
nuclear@0 1079 aiNode* nd = *ppcChildren = new aiNode();
nuclear@0 1080 nd->mName.Set("<NFF_Camera>");
nuclear@0 1081 nd->mParent = root;
nuclear@0 1082
nuclear@0 1083 // allocate the camera in the scene
nuclear@0 1084 pScene->mNumCameras = 1;
nuclear@0 1085 pScene->mCameras = new aiCamera*[1];
nuclear@0 1086 aiCamera* c = pScene->mCameras[0] = new aiCamera;
nuclear@0 1087
nuclear@0 1088 c->mName = nd->mName; // make sure the names are identical
nuclear@0 1089 c->mHorizontalFOV = AI_DEG_TO_RAD( angle );
nuclear@0 1090 c->mLookAt = camLookAt - camPos;
nuclear@0 1091 c->mPosition = camPos;
nuclear@0 1092 c->mUp = camUp;
nuclear@0 1093
nuclear@0 1094 // If the resolution is not specified in the file, we
nuclear@0 1095 // need to set 1.0 as aspect.
nuclear@0 1096 c->mAspect = (!resolution.y ? 0.f : resolution.x / resolution.y);
nuclear@0 1097 ++ppcChildren;
nuclear@0 1098 }
nuclear@0 1099
nuclear@0 1100 // generate light sources
nuclear@0 1101 if (!lights.empty())
nuclear@0 1102 {
nuclear@0 1103 pScene->mNumLights = (unsigned int)lights.size();
nuclear@0 1104 pScene->mLights = new aiLight*[pScene->mNumLights];
nuclear@0 1105 for (unsigned int i = 0; i < pScene->mNumLights;++i,++ppcChildren)
nuclear@0 1106 {
nuclear@0 1107 const Light& l = lights[i];
nuclear@0 1108
nuclear@0 1109 aiNode* nd = *ppcChildren = new aiNode();
nuclear@0 1110 nd->mParent = root;
nuclear@0 1111
nuclear@0 1112 nd->mName.length = ::sprintf(nd->mName.data,"<NFF_Light%i>",i);
nuclear@0 1113
nuclear@0 1114 // allocate the light in the scene data structure
nuclear@0 1115 aiLight* out = pScene->mLights[i] = new aiLight();
nuclear@0 1116 out->mName = nd->mName; // make sure the names are identical
nuclear@0 1117 out->mType = aiLightSource_POINT;
nuclear@0 1118 out->mColorDiffuse = out->mColorSpecular = l.color * l.intensity;
nuclear@0 1119 out->mPosition = l.position;
nuclear@0 1120 }
nuclear@0 1121 }
nuclear@0 1122
nuclear@0 1123 if (!pScene->mNumMeshes)throw DeadlyImportError("NFF: No meshes loaded");
nuclear@0 1124 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
nuclear@0 1125 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = pScene->mNumMeshes];
nuclear@0 1126 for (it = meshes.begin(), m = 0; it != end;++it)
nuclear@0 1127 {
nuclear@0 1128 if ((*it).faces.empty())continue;
nuclear@0 1129
nuclear@0 1130 const MeshInfo& src = *it;
nuclear@0 1131 aiMesh* const mesh = pScene->mMeshes[m] = new aiMesh();
nuclear@0 1132 mesh->mNumVertices = (unsigned int)src.vertices.size();
nuclear@0 1133 mesh->mNumFaces = (unsigned int)src.faces.size();
nuclear@0 1134
nuclear@0 1135 // Generate sub nodes for named meshes
nuclear@0 1136 if (src.name[0])
nuclear@0 1137 {
nuclear@0 1138 aiNode* const node = *ppcChildren = new aiNode();
nuclear@0 1139 node->mParent = root;
nuclear@0 1140 node->mNumMeshes = 1;
nuclear@0 1141 node->mMeshes = new unsigned int[1];
nuclear@0 1142 node->mMeshes[0] = m;
nuclear@0 1143 node->mName.Set(src.name);
nuclear@0 1144
nuclear@0 1145 // setup the transformation matrix of the node
nuclear@0 1146 aiMatrix4x4::FromToMatrix(aiVector3D(0.f,1.f,0.f),
nuclear@0 1147 src.dir,node->mTransformation);
nuclear@0 1148
nuclear@0 1149 aiMatrix4x4& mat = node->mTransformation;
nuclear@0 1150 mat.a1 *= src.radius.x; mat.b1 *= src.radius.x; mat.c1 *= src.radius.x;
nuclear@0 1151 mat.a2 *= src.radius.y; mat.b2 *= src.radius.y; mat.c2 *= src.radius.y;
nuclear@0 1152 mat.a3 *= src.radius.z; mat.b3 *= src.radius.z; mat.c3 *= src.radius.z;
nuclear@0 1153 mat.a4 = src.center.x;
nuclear@0 1154 mat.b4 = src.center.y;
nuclear@0 1155 mat.c4 = src.center.z;
nuclear@0 1156
nuclear@0 1157 ++ppcChildren;
nuclear@0 1158 }
nuclear@0 1159 else *pMeshes++ = m;
nuclear@0 1160
nuclear@0 1161 // copy vertex positions
nuclear@0 1162 mesh->mVertices = new aiVector3D[mesh->mNumVertices];
nuclear@0 1163 ::memcpy(mesh->mVertices,&src.vertices[0],
nuclear@0 1164 sizeof(aiVector3D)*mesh->mNumVertices);
nuclear@0 1165
nuclear@0 1166 // NFF2: there could be vertex colors
nuclear@0 1167 if (!src.colors.empty())
nuclear@0 1168 {
nuclear@0 1169 ai_assert(src.colors.size() == src.vertices.size());
nuclear@0 1170
nuclear@0 1171 // copy vertex colors
nuclear@0 1172 mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
nuclear@0 1173 ::memcpy(mesh->mColors[0],&src.colors[0],
nuclear@0 1174 sizeof(aiColor4D)*mesh->mNumVertices);
nuclear@0 1175 }
nuclear@0 1176
nuclear@0 1177 if (!src.normals.empty())
nuclear@0 1178 {
nuclear@0 1179 ai_assert(src.normals.size() == src.vertices.size());
nuclear@0 1180
nuclear@0 1181 // copy normal vectors
nuclear@0 1182 mesh->mNormals = new aiVector3D[mesh->mNumVertices];
nuclear@0 1183 ::memcpy(mesh->mNormals,&src.normals[0],
nuclear@0 1184 sizeof(aiVector3D)*mesh->mNumVertices);
nuclear@0 1185 }
nuclear@0 1186
nuclear@0 1187 if (!src.uvs.empty())
nuclear@0 1188 {
nuclear@0 1189 ai_assert(src.uvs.size() == src.vertices.size());
nuclear@0 1190
nuclear@0 1191 // copy texture coordinates
nuclear@0 1192 mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
nuclear@0 1193 ::memcpy(mesh->mTextureCoords[0],&src.uvs[0],
nuclear@0 1194 sizeof(aiVector3D)*mesh->mNumVertices);
nuclear@0 1195 }
nuclear@0 1196
nuclear@0 1197 // generate faces
nuclear@0 1198 unsigned int p = 0;
nuclear@0 1199 aiFace* pFace = mesh->mFaces = new aiFace[mesh->mNumFaces];
nuclear@0 1200 for (std::vector<unsigned int>::const_iterator it2 = src.faces.begin(),
nuclear@0 1201 end2 = src.faces.end();
nuclear@0 1202 it2 != end2;++it2,++pFace)
nuclear@0 1203 {
nuclear@0 1204 pFace->mIndices = new unsigned int [ pFace->mNumIndices = *it2 ];
nuclear@0 1205 for (unsigned int o = 0; o < pFace->mNumIndices;++o)
nuclear@0 1206 pFace->mIndices[o] = p++;
nuclear@0 1207 }
nuclear@0 1208
nuclear@0 1209 // generate a material for the mesh
nuclear@0 1210 aiMaterial* pcMat = (aiMaterial*)(pScene->mMaterials[m] = new aiMaterial());
nuclear@0 1211
nuclear@0 1212 mesh->mMaterialIndex = m++;
nuclear@0 1213
nuclear@0 1214 aiString s;
nuclear@0 1215 s.Set(AI_DEFAULT_MATERIAL_NAME);
nuclear@0 1216 pcMat->AddProperty(&s, AI_MATKEY_NAME);
nuclear@0 1217
nuclear@0 1218 // FIX: Ignore diffuse == 0
nuclear@0 1219 aiColor3D c = src.shader.color * (src.shader.diffuse.r ? src.shader.diffuse : aiColor3D(1.f,1.f,1.f));
nuclear@0 1220 pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE);
nuclear@0 1221 c = src.shader.color * src.shader.specular;
nuclear@0 1222 pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR);
nuclear@0 1223
nuclear@0 1224 // NFF2 - default values for NFF
nuclear@0 1225 pcMat->AddProperty(&src.shader.ambient, 1,AI_MATKEY_COLOR_AMBIENT);
nuclear@0 1226 pcMat->AddProperty(&src.shader.emissive,1,AI_MATKEY_COLOR_EMISSIVE);
nuclear@0 1227 pcMat->AddProperty(&src.shader.opacity, 1,AI_MATKEY_OPACITY);
nuclear@0 1228
nuclear@0 1229 // setup the first texture layer, if existing
nuclear@0 1230 if (src.shader.texFile.length())
nuclear@0 1231 {
nuclear@0 1232 s.Set(src.shader.texFile);
nuclear@0 1233 pcMat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
nuclear@0 1234
nuclear@0 1235 if (aiTextureMapping_UV != src.shader.mapping) {
nuclear@0 1236
nuclear@0 1237 aiVector3D v(0.f,-1.f,0.f);
nuclear@0 1238 pcMat->AddProperty(&v, 1,AI_MATKEY_TEXMAP_AXIS_DIFFUSE(0));
nuclear@0 1239 pcMat->AddProperty((int*)&src.shader.mapping, 1,AI_MATKEY_MAPPING_DIFFUSE(0));
nuclear@0 1240 }
nuclear@0 1241 }
nuclear@0 1242
nuclear@0 1243 // setup the name of the material
nuclear@0 1244 if (src.shader.name.length())
nuclear@0 1245 {
nuclear@0 1246 s.Set(src.shader.texFile);
nuclear@0 1247 pcMat->AddProperty(&s,AI_MATKEY_NAME);
nuclear@0 1248 }
nuclear@0 1249
nuclear@0 1250 // setup some more material properties that are specific to NFF2
nuclear@0 1251 int i;
nuclear@0 1252 if (src.shader.twoSided)
nuclear@0 1253 {
nuclear@0 1254 i = 1;
nuclear@0 1255 pcMat->AddProperty(&i,1,AI_MATKEY_TWOSIDED);
nuclear@0 1256 }
nuclear@0 1257 i = (src.shader.shaded ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
nuclear@0 1258 if (src.shader.shininess)
nuclear@0 1259 {
nuclear@0 1260 i = aiShadingMode_Phong;
nuclear@0 1261 pcMat->AddProperty(&src.shader.shininess,1,AI_MATKEY_SHININESS);
nuclear@0 1262 }
nuclear@0 1263 pcMat->AddProperty(&i,1,AI_MATKEY_SHADING_MODEL);
nuclear@0 1264 }
nuclear@0 1265 pScene->mRootNode = root;
nuclear@0 1266 }
nuclear@0 1267
nuclear@0 1268 #endif // !! ASSIMP_BUILD_NO_NFF_IMPORTER