absence_thelab

annotate src/3deng/sceneloader.cpp @ 0:1cffe3409164

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 23 Oct 2014 01:46:07 +0300
parents
children
rev   line source
nuclear@0 1 //#include <fstream>
nuclear@0 2 #include <windows.h>
nuclear@0 3 #include <string>
nuclear@0 4 #include <cassert>
nuclear@0 5 #include "sceneloader.h"
nuclear@0 6 #include "3dschunks.h"
nuclear@0 7 #include "typedefs.h"
nuclear@0 8
nuclear@0 9 using std::ifstream;
nuclear@0 10 using std::string;
nuclear@0 11
nuclear@0 12 namespace SceneLoader {
nuclear@0 13 GraphicsContext *gc;
nuclear@0 14 dword ReadCounter;
nuclear@0 15 Material *mat;
nuclear@0 16 dword MatCount;
nuclear@0 17
nuclear@0 18 bool eof = false;
nuclear@0 19
nuclear@0 20 string datapath = "";
nuclear@0 21
nuclear@0 22 string SceneFileName;
nuclear@0 23 string ObjectName;
nuclear@0 24
nuclear@0 25 bool SaveNormalFile = false;
nuclear@0 26 }
nuclear@0 27
nuclear@0 28 using namespace SceneLoader;
nuclear@0 29
nuclear@0 30 struct ChunkHeader {
nuclear@0 31 ChunkID id;
nuclear@0 32 dword size;
nuclear@0 33 };
nuclear@0 34
nuclear@0 35 struct Percent {
nuclear@0 36 int IntPercent;
nuclear@0 37 float FloatPercent;
nuclear@0 38
nuclear@0 39 Percent(int p = 0) {IntPercent = p; FloatPercent = (float)p / 100.0f; }
nuclear@0 40 Percent(float p) {FloatPercent = p; IntPercent = (int)(p * 100.0f); }
nuclear@0 41 };
nuclear@0 42
nuclear@0 43 struct TexMap {
nuclear@0 44 string filename;
nuclear@0 45 TextureType type;
nuclear@0 46 float intensity;
nuclear@0 47 float rotation;
nuclear@0 48 Vector2 offset;
nuclear@0 49 Vector2 scale;
nuclear@0 50 };
nuclear@0 51
nuclear@0 52 const dword HeaderSize = 6;
nuclear@0 53
nuclear@0 54 enum {OBJ_MESH, OBJ_PTLIGHT, OBJ_SPLIGHT, OBJ_CAMERA, OBJ_CURVE};
nuclear@0 55
nuclear@0 56 // local function prototypes
nuclear@0 57 byte ReadByte(HANDLE file);
nuclear@0 58 word ReadWord(HANDLE file);
nuclear@0 59 dword ReadDword(HANDLE file);
nuclear@0 60 float ReadFloat(HANDLE file);
nuclear@0 61 Vector3 ReadVector(HANDLE file, bool FlipYZ = true);
nuclear@0 62 string ReadString(HANDLE file);
nuclear@0 63 Color ReadColor(HANDLE file);
nuclear@0 64 Percent ReadPercent(HANDLE file);
nuclear@0 65 ChunkHeader ReadChunkHeader(HANDLE file);
nuclear@0 66 void SkipChunk(HANDLE file, const ChunkHeader &chunk);
nuclear@0 67 void SkipBytes(HANDLE file, dword bytes);
nuclear@0 68
nuclear@0 69 int ReadObject(HANDLE file, const ChunkHeader &ch, void **obj);
nuclear@0 70 int ReadLight(HANDLE file, const ChunkHeader &ch, Light **lt);
nuclear@0 71 Material ReadMaterial(HANDLE file, const ChunkHeader &ch);
nuclear@0 72 TexMap ReadTextureMap(HANDLE file, const ChunkHeader &ch);
nuclear@0 73
nuclear@0 74 Material *FindMaterial(string name);
nuclear@0 75
nuclear@0 76 bool LoadNormalsFromFile(const char *fname, Scene *scene);
nuclear@0 77 void SaveNormalsToFile(const char *fname, Scene *scene);
nuclear@0 78
nuclear@0 79
nuclear@0 80 void SceneLoader::SetGraphicsContext(GraphicsContext *gfx) {
nuclear@0 81 gc = gfx;
nuclear@0 82 }
nuclear@0 83
nuclear@0 84
nuclear@0 85 void SceneLoader::SetDataPath(const char *path) {
nuclear@0 86 datapath = path;
nuclear@0 87 }
nuclear@0 88
nuclear@0 89 void SceneLoader::SetNormalFileSaving(bool enable) {
nuclear@0 90 SaveNormalFile = enable;
nuclear@0 91 }
nuclear@0 92
nuclear@0 93
nuclear@0 94
nuclear@0 95 ////////////////////////////////////////
nuclear@0 96 // --==( function LoadScene )==-- //
nuclear@0 97 // ---------------------------------- //
nuclear@0 98 // Creates a Scene instance and loads //
nuclear@0 99 // the data from specified file //
nuclear@0 100 ////////////////////////////////////////
nuclear@0 101
nuclear@0 102 bool SceneLoader::LoadScene(const char *fname, Scene **scene) {
nuclear@0 103 if(!gc) return false;
nuclear@0 104
nuclear@0 105 if(!LoadMaterials(fname, &mat)) return false;
nuclear@0 106
nuclear@0 107 //ifstream file(fname);
nuclear@0 108 //if(!file.is_open()) return false;
nuclear@0 109 HANDLE file = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
nuclear@0 110 assert(file != NULL);
nuclear@0 111 eof = false;
nuclear@0 112
nuclear@0 113 SceneFileName = string(fname);
nuclear@0 114
nuclear@0 115 ChunkHeader chunk;
nuclear@0 116 Scene *scn = new Scene(gc); // new scene instance
nuclear@0 117
nuclear@0 118 chunk = ReadChunkHeader(file);
nuclear@0 119 if(chunk.id != Chunk_3DSMain) {
nuclear@0 120 CloseHandle(file);
nuclear@0 121 return false;
nuclear@0 122 }
nuclear@0 123
nuclear@0 124 //while(!file.eof()) {
nuclear@0 125 while(!eof) {
nuclear@0 126
nuclear@0 127 chunk = ReadChunkHeader(file);
nuclear@0 128
nuclear@0 129 void *objptr;
nuclear@0 130 int type;
nuclear@0 131
nuclear@0 132 switch(chunk.id) {
nuclear@0 133 case Chunk_Main_3DEditor:
nuclear@0 134 break; // dont skip
nuclear@0 135
nuclear@0 136 case Chunk_Edit_AmbientColor:
nuclear@0 137 scn->SetAmbientLight(ReadColor(file));
nuclear@0 138 break;
nuclear@0 139
nuclear@0 140 case Chunk_Edit_Fog:
nuclear@0 141 // **TODO** find out chunk structure
nuclear@0 142 break;
nuclear@0 143
nuclear@0 144 case Chunk_Edit_Object:
nuclear@0 145 type = ReadObject(file, chunk, &objptr);
nuclear@0 146 switch(type) {
nuclear@0 147 case OBJ_MESH:
nuclear@0 148 {
nuclear@0 149 Object *object = (Object*)objptr;
nuclear@0 150 scn->AddObject(object);
nuclear@0 151 }
nuclear@0 152 break;
nuclear@0 153
nuclear@0 154 case OBJ_CAMERA:
nuclear@0 155 {
nuclear@0 156 Camera *cam = (Camera*)objptr;
nuclear@0 157 scn->AddCamera(cam);
nuclear@0 158 }
nuclear@0 159 break;
nuclear@0 160
nuclear@0 161 case OBJ_PTLIGHT:
nuclear@0 162 {
nuclear@0 163 PointLight *lt = (PointLight*)objptr;
nuclear@0 164 scn->AddLight(lt);
nuclear@0 165 }
nuclear@0 166 break;
nuclear@0 167
nuclear@0 168 case OBJ_SPLIGHT:
nuclear@0 169 {
nuclear@0 170 SpotLight *lt = (SpotLight*)objptr;
nuclear@0 171 scn->AddLight(lt);
nuclear@0 172 }
nuclear@0 173 break;
nuclear@0 174
nuclear@0 175 case OBJ_CURVE:
nuclear@0 176 {
nuclear@0 177 CatmullRomSpline *spline = (CatmullRomSpline*)objptr;
nuclear@0 178 scn->AddCurve(spline);
nuclear@0 179 }
nuclear@0 180 break;
nuclear@0 181 }
nuclear@0 182
nuclear@0 183 break;
nuclear@0 184
nuclear@0 185 default:
nuclear@0 186 SkipChunk(file, chunk);
nuclear@0 187 }
nuclear@0 188 }
nuclear@0 189
nuclear@0 190 CloseHandle(file);
nuclear@0 191
nuclear@0 192
nuclear@0 193 // check if there is a normals file in the same dir and load them, or else calculate them
nuclear@0 194 if(!LoadNormalsFromFile((SceneFileName + string(".normals")).c_str(), scn)) {
nuclear@0 195 std::list<Object*>::iterator objiter = scn->GetObjectsList()->begin();
nuclear@0 196 while(objiter != scn->GetObjectsList()->end()) {
nuclear@0 197 (*objiter++)->GetTriMesh()->CalculateNormals();
nuclear@0 198 }
nuclear@0 199 if(SaveNormalFile) SaveNormalsToFile((SceneFileName + string(".normals")).c_str(), scn);
nuclear@0 200 }
nuclear@0 201
nuclear@0 202 *scene = scn;
nuclear@0 203 return true;
nuclear@0 204 }
nuclear@0 205
nuclear@0 206
nuclear@0 207
nuclear@0 208 bool SceneLoader::LoadObject(const char *fname, const char *ObjectName, Object **obj) {
nuclear@0 209 if(!gc) return false;
nuclear@0 210
nuclear@0 211 if(!LoadMaterials(fname, &mat)) return false;
nuclear@0 212
nuclear@0 213 //ifstream file(fname);
nuclear@0 214 //if(!file.is_open()) return false;
nuclear@0 215 HANDLE file = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
nuclear@0 216 assert(file != NULL);
nuclear@0 217 eof = false;
nuclear@0 218
nuclear@0 219 ChunkHeader chunk = ReadChunkHeader(file);
nuclear@0 220 if(chunk.id != Chunk_3DSMain) {
nuclear@0 221 CloseHandle(file);
nuclear@0 222 return false;
nuclear@0 223 }
nuclear@0 224
nuclear@0 225 while(!eof) {
nuclear@0 226
nuclear@0 227 chunk = ReadChunkHeader(file);
nuclear@0 228
nuclear@0 229 void *objptr;
nuclear@0 230 int type;
nuclear@0 231
nuclear@0 232 switch(chunk.id) {
nuclear@0 233 case Chunk_Main_3DEditor:
nuclear@0 234 break; // dont skip
nuclear@0 235
nuclear@0 236 case Chunk_Edit_Object:
nuclear@0 237 type = ReadObject(file, chunk, &objptr);
nuclear@0 238 if(type == OBJ_MESH) {
nuclear@0 239 Object *object = (Object*)objptr;
nuclear@0 240 if(!strcmp(object->name.c_str(), ObjectName)) {
nuclear@0 241 object->GetTriMesh()->CalculateNormals();
nuclear@0 242 *obj = object;
nuclear@0 243 CloseHandle(file);
nuclear@0 244 return true;
nuclear@0 245 }
nuclear@0 246 }
nuclear@0 247 break;
nuclear@0 248
nuclear@0 249 default:
nuclear@0 250 SkipChunk(file, chunk);
nuclear@0 251 }
nuclear@0 252 }
nuclear@0 253
nuclear@0 254 CloseHandle(file);
nuclear@0 255 return false;
nuclear@0 256 }
nuclear@0 257
nuclear@0 258
nuclear@0 259
nuclear@0 260 bool FindChunk(HANDLE file, word ChunkID) {
nuclear@0 261
nuclear@0 262 ChunkHeader chunk = ReadChunkHeader(file);
nuclear@0 263
nuclear@0 264 while(chunk.id != ChunkID) {
nuclear@0 265 SkipChunk(file, chunk);
nuclear@0 266 chunk = ReadChunkHeader(file);
nuclear@0 267 }
nuclear@0 268
nuclear@0 269 return chunk.id == ChunkID;
nuclear@0 270 }
nuclear@0 271
nuclear@0 272
nuclear@0 273
nuclear@0 274 bool SceneLoader::LoadMaterials(const char *fname, Material **materials) {
nuclear@0 275 if(!materials) return false;
nuclear@0 276
nuclear@0 277 //ifstream file(fname);
nuclear@0 278 //if(!file.is_open()) return false;
nuclear@0 279 HANDLE file = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
nuclear@0 280 assert(file != NULL);
nuclear@0 281 eof = false;
nuclear@0 282
nuclear@0 283 ChunkHeader chunk;
nuclear@0 284
nuclear@0 285 chunk = ReadChunkHeader(file);
nuclear@0 286 if(chunk.id != Chunk_3DSMain) {
nuclear@0 287 CloseHandle(file);
nuclear@0 288 return false;
nuclear@0 289 }
nuclear@0 290
nuclear@0 291 if(!FindChunk(file, Chunk_Main_3DEditor)) {
nuclear@0 292 CloseHandle(file);
nuclear@0 293 return false;
nuclear@0 294 }
nuclear@0 295
nuclear@0 296 std::vector<Material> mats;
nuclear@0 297
nuclear@0 298 while(!eof) {
nuclear@0 299
nuclear@0 300 chunk = ReadChunkHeader(file);
nuclear@0 301
nuclear@0 302 if(chunk.id == Chunk_Edit_Material) {
nuclear@0 303 Material mat = ReadMaterial(file, chunk);
nuclear@0 304 mats.push_back(mat);
nuclear@0 305 } else {
nuclear@0 306 SkipChunk(file, chunk);
nuclear@0 307 }
nuclear@0 308 }
nuclear@0 309
nuclear@0 310 MatCount = (dword)mats.size();
nuclear@0 311
nuclear@0 312 if(*materials) delete [] *materials;
nuclear@0 313 Material *m = new Material[MatCount];
nuclear@0 314
nuclear@0 315 for(dword i=0; i<MatCount; i++) {
nuclear@0 316 m[i] = mats[i];
nuclear@0 317 }
nuclear@0 318
nuclear@0 319 *materials = m;
nuclear@0 320
nuclear@0 321 CloseHandle(file);
nuclear@0 322 return true;
nuclear@0 323 }
nuclear@0 324
nuclear@0 325
nuclear@0 326 TexMap ReadTextureMap(HANDLE file, const ChunkHeader &ch) {
nuclear@0 327 assert(ch.id == Chunk_Mat_TextureMap || ch.id == Chunk_Mat_TextureMap2 || ch.id == Chunk_Mat_OpacityMap || ch.id == Chunk_Mat_BumpMap || ch.id == Chunk_Mat_ReflectionMap || ch.id == Chunk_Mat_SelfIlluminationMap);
nuclear@0 328
nuclear@0 329 TexMap map;
nuclear@0 330 Percent p = ReadPercent(file);
nuclear@0 331 map.intensity = p.FloatPercent;
nuclear@0 332
nuclear@0 333 switch(ch.id) {
nuclear@0 334 case Chunk_Mat_TextureMap:
nuclear@0 335 map.type = TextureMap;
nuclear@0 336 break;
nuclear@0 337
nuclear@0 338 case Chunk_Mat_TextureMap2:
nuclear@0 339 map.type = DetailMap;
nuclear@0 340 break;
nuclear@0 341
nuclear@0 342 case Chunk_Mat_OpacityMap:
nuclear@0 343 map.type = OpacityMap;
nuclear@0 344 break;
nuclear@0 345
nuclear@0 346 case Chunk_Mat_BumpMap:
nuclear@0 347 map.type = BumpMap;
nuclear@0 348 break;
nuclear@0 349
nuclear@0 350 case Chunk_Mat_ReflectionMap:
nuclear@0 351 map.type = EnvironmentMap;
nuclear@0 352 break;
nuclear@0 353
nuclear@0 354 case Chunk_Mat_SelfIlluminationMap:
nuclear@0 355 map.type = LightMap;
nuclear@0 356 break;
nuclear@0 357 default:
nuclear@0 358 assert(0);
nuclear@0 359 }
nuclear@0 360
nuclear@0 361 ChunkHeader chunk = ReadChunkHeader(file);
nuclear@0 362 assert(chunk.id == Chunk_Map_FileName);
nuclear@0 363
nuclear@0 364 map.filename = ReadString(file);
nuclear@0 365 return map;
nuclear@0 366 }
nuclear@0 367
nuclear@0 368
nuclear@0 369
nuclear@0 370
nuclear@0 371
nuclear@0 372 Material ReadMaterial(HANDLE file, const ChunkHeader &ch) {
nuclear@0 373
nuclear@0 374 Material mat;
nuclear@0 375
nuclear@0 376 assert(ch.id == Chunk_Edit_Material);
nuclear@0 377
nuclear@0 378 ReadCounter = HeaderSize;
nuclear@0 379 dword ChunkSize = ch.size;
nuclear@0 380
nuclear@0 381 while(ReadCounter < ChunkSize) {
nuclear@0 382 ChunkHeader chunk = ReadChunkHeader(file);
nuclear@0 383
nuclear@0 384 Percent p;
nuclear@0 385 TexMap map;
nuclear@0 386
nuclear@0 387 switch(chunk.id) {
nuclear@0 388 case Chunk_Mat_Name:
nuclear@0 389 mat.name = ReadString(file);
nuclear@0 390 break;
nuclear@0 391
nuclear@0 392 case Chunk_Mat_AmbientColor:
nuclear@0 393 mat.Ambient = ReadColor(file);
nuclear@0 394 break;
nuclear@0 395
nuclear@0 396 case Chunk_Mat_DiffuseColor:
nuclear@0 397 mat.Diffuse = ReadColor(file);
nuclear@0 398 break;
nuclear@0 399
nuclear@0 400 case Chunk_Mat_SpecularColor:
nuclear@0 401 mat.Specular = ReadColor(file);
nuclear@0 402 break;
nuclear@0 403
nuclear@0 404 case Chunk_Mat_Specular:
nuclear@0 405 p = ReadPercent(file);
nuclear@0 406 mat.Power = (float)p.IntPercent;
nuclear@0 407 if(mat.Power > 0.0f) mat.SpecularEnable = true;
nuclear@0 408 break;
nuclear@0 409
nuclear@0 410 case Chunk_Mat_SpecularIntensity:
nuclear@0 411 p = ReadPercent(file);
nuclear@0 412 mat.Specular.r *= p.FloatPercent;
nuclear@0 413 mat.Specular.g *= p.FloatPercent;
nuclear@0 414 mat.Specular.b *= p.FloatPercent;
nuclear@0 415 break;
nuclear@0 416
nuclear@0 417 case Chunk_Mat_Transparency:
nuclear@0 418 p = ReadPercent(file);
nuclear@0 419 mat.Alpha = 1.0f - p.FloatPercent;
nuclear@0 420 break;
nuclear@0 421
nuclear@0 422 case Chunk_Mat_SelfIllumination:
nuclear@0 423 p = ReadPercent(file);
nuclear@0 424 mat.Emissive = Color(p.FloatPercent);
nuclear@0 425 break;
nuclear@0 426
nuclear@0 427 case Chunk_Mat_TextureMap:
nuclear@0 428 case Chunk_Mat_TextureMap2:
nuclear@0 429 case Chunk_Mat_OpacityMap:
nuclear@0 430 case Chunk_Mat_SelfIlluminationMap:
nuclear@0 431 map = ReadTextureMap(file, chunk);
nuclear@0 432 mat.SetTexture(gc->texman->LoadTexture((datapath + map.filename).c_str()), map.type);
nuclear@0 433 break;
nuclear@0 434
nuclear@0 435 case Chunk_Mat_ReflectionMap:
nuclear@0 436 map = ReadTextureMap(file, chunk);
nuclear@0 437 mat.SetTexture(gc->texman->LoadTexture((datapath + map.filename).c_str()), map.type);
nuclear@0 438 mat.EnvBlend = map.intensity;
nuclear@0 439 break;
nuclear@0 440
nuclear@0 441 case Chunk_Mat_BumpMap:
nuclear@0 442 map = ReadTextureMap(file, chunk);
nuclear@0 443 mat.SetTexture(gc->texman->LoadTexture((datapath + map.filename).c_str()), map.type);
nuclear@0 444 mat.BumpIntensity = map.intensity;
nuclear@0 445 break;
nuclear@0 446
nuclear@0 447 default:
nuclear@0 448 SkipChunk(file, chunk);
nuclear@0 449 }
nuclear@0 450 }
nuclear@0 451
nuclear@0 452 return mat;
nuclear@0 453 }
nuclear@0 454
nuclear@0 455
nuclear@0 456
nuclear@0 457
nuclear@0 458
nuclear@0 459 ////////////////////////////////////////////////////
nuclear@0 460 byte ReadByte(HANDLE file) {
nuclear@0 461 byte val;
nuclear@0 462 dword numread;
nuclear@0 463 ReadFile(file, &val, sizeof(byte), &numread, NULL);
nuclear@0 464 if(numread < sizeof(byte)) eof = true;
nuclear@0 465 ReadCounter++;
nuclear@0 466 return val;
nuclear@0 467 }
nuclear@0 468
nuclear@0 469 word ReadWord(HANDLE file) {
nuclear@0 470 word val;
nuclear@0 471 dword numread;
nuclear@0 472 ReadFile(file, &val, sizeof(word), &numread, NULL);
nuclear@0 473 if(numread < sizeof(word)) eof = true;
nuclear@0 474 ReadCounter += sizeof(word);
nuclear@0 475 return val;
nuclear@0 476 }
nuclear@0 477
nuclear@0 478 dword ReadDword(HANDLE file) {
nuclear@0 479 dword val;
nuclear@0 480 dword numread;
nuclear@0 481 ReadFile(file, &val, sizeof(dword), &numread, NULL);
nuclear@0 482 if(numread < sizeof(dword)) eof = true;
nuclear@0 483 ReadCounter += sizeof(dword);
nuclear@0 484 return val;
nuclear@0 485 }
nuclear@0 486
nuclear@0 487 float ReadFloat(HANDLE file) {
nuclear@0 488 float val;
nuclear@0 489 dword numread;
nuclear@0 490 ReadFile(file, &val, sizeof(float), &numread, NULL);
nuclear@0 491 if(numread < sizeof(float)) eof = true;
nuclear@0 492 ReadCounter += sizeof(float);
nuclear@0 493 return val;
nuclear@0 494 }
nuclear@0 495 /*
nuclear@0 496 byte ReadByte(HANDLE file) {
nuclear@0 497 byte val;
nuclear@0 498 file.read((char*)&val, 1);
nuclear@0 499 ReadCounter++;
nuclear@0 500 return val;
nuclear@0 501 }
nuclear@0 502
nuclear@0 503 word ReadWord(HANDLE file) {
nuclear@0 504 word val;
nuclear@0 505 file.read((char*)&val, sizeof(word));
nuclear@0 506 ReadCounter += sizeof(word);
nuclear@0 507 return val;
nuclear@0 508 }
nuclear@0 509
nuclear@0 510 dword ReadDword(HANDLE file) {
nuclear@0 511 dword val;
nuclear@0 512 file.read((char*)&val, sizeof(dword));
nuclear@0 513 ReadCounter += sizeof(dword);
nuclear@0 514 return val;
nuclear@0 515 }
nuclear@0 516
nuclear@0 517 float ReadFloat(HANDLE file) {
nuclear@0 518 float val;
nuclear@0 519 file.read((char*)&val, sizeof(float));
nuclear@0 520 ReadCounter += sizeof(float);
nuclear@0 521 return val;
nuclear@0 522 }
nuclear@0 523 */
nuclear@0 524 Vector3 ReadVector(HANDLE file, bool FlipYZ) {
nuclear@0 525 Vector3 vector;
nuclear@0 526 vector.x = ReadFloat(file);
nuclear@0 527 if(!FlipYZ) vector.y = ReadFloat(file);
nuclear@0 528 vector.z = ReadFloat(file);
nuclear@0 529 if(FlipYZ) vector.y = ReadFloat(file);
nuclear@0 530 return vector;
nuclear@0 531 }
nuclear@0 532
nuclear@0 533 string ReadString(HANDLE file) {
nuclear@0 534 string str;
nuclear@0 535 char c;
nuclear@0 536 while(c = (char)ReadByte(file)) {
nuclear@0 537 str.push_back(c);
nuclear@0 538 }
nuclear@0 539 str.push_back('\0');
nuclear@0 540 ReadCounter++;
nuclear@0 541
nuclear@0 542 return str;
nuclear@0 543 }
nuclear@0 544 /*
nuclear@0 545 string ReadString(HANDLE file) {
nuclear@0 546 string str;
nuclear@0 547 char c;
nuclear@0 548 while(c = file.get()) {
nuclear@0 549 str.push_back(c);
nuclear@0 550 ReadCounter++;
nuclear@0 551 }
nuclear@0 552 str.push_back('\0');
nuclear@0 553 ReadCounter++;
nuclear@0 554
nuclear@0 555 return str;
nuclear@0 556 }
nuclear@0 557 */
nuclear@0 558
nuclear@0 559 Color ReadColor(HANDLE file) {
nuclear@0 560 ChunkHeader chunk = ReadChunkHeader(file);
nuclear@0 561 if(chunk.id < 0x0010 || chunk.id > 0x0013) return Color(-1.0f, -1.0f, -1.0f);
nuclear@0 562
nuclear@0 563 Color color;
nuclear@0 564
nuclear@0 565 if(chunk.id == Chunk_Color_Byte3 || chunk.id == Chunk_Color_GammaByte3) {
nuclear@0 566 byte r = ReadByte(file);
nuclear@0 567 byte g = ReadByte(file);
nuclear@0 568 byte b = ReadByte(file);
nuclear@0 569 color = Color(r, g, b);
nuclear@0 570 } else {
nuclear@0 571 color.r = ReadFloat(file);
nuclear@0 572 color.g = ReadFloat(file);
nuclear@0 573 color.b = ReadFloat(file);
nuclear@0 574 }
nuclear@0 575
nuclear@0 576 return color;
nuclear@0 577 }
nuclear@0 578
nuclear@0 579 Percent ReadPercent(HANDLE file) {
nuclear@0 580 ChunkHeader chunk = ReadChunkHeader(file);
nuclear@0 581 Percent p;
nuclear@0 582 if(chunk.id != Chunk_PercentInt && chunk.id != Chunk_PercentFloat) return p;
nuclear@0 583
nuclear@0 584 if(chunk.id == Chunk_PercentInt) {
nuclear@0 585 p = Percent(ReadWord(file));
nuclear@0 586 } else {
nuclear@0 587 p = Percent(ReadFloat(file));
nuclear@0 588 }
nuclear@0 589
nuclear@0 590 return p;
nuclear@0 591 }
nuclear@0 592
nuclear@0 593
nuclear@0 594 ChunkHeader ReadChunkHeader(HANDLE file) {
nuclear@0 595 ChunkHeader chunk;
nuclear@0 596 chunk.id = (ChunkID)ReadWord(file);
nuclear@0 597 chunk.size = ReadDword(file);
nuclear@0 598 return chunk;
nuclear@0 599 }
nuclear@0 600
nuclear@0 601 void SkipChunk(HANDLE file, const ChunkHeader &chunk) {
nuclear@0 602 //file.ignore(chunk.size - HeaderSize);
nuclear@0 603 SetFilePointer(file, chunk.size - HeaderSize, 0, FILE_CURRENT);
nuclear@0 604 ReadCounter += chunk.size - HeaderSize;
nuclear@0 605 }
nuclear@0 606
nuclear@0 607 void SkipBytes(HANDLE file, dword bytes) {
nuclear@0 608 SetFilePointer(file, bytes, 0, FILE_CURRENT);
nuclear@0 609 ReadCounter += bytes;
nuclear@0 610 }
nuclear@0 611
nuclear@0 612 Material *FindMaterial(string name) {
nuclear@0 613 dword i=0;
nuclear@0 614 while(i < MatCount) {
nuclear@0 615 if(mat[i].name == name) return &mat[i];
nuclear@0 616 i++;
nuclear@0 617 }
nuclear@0 618
nuclear@0 619 return 0;
nuclear@0 620 }
nuclear@0 621
nuclear@0 622 ///////////////////// Read Object Function //////////////////////
nuclear@0 623 int ReadObject(HANDLE file, const ChunkHeader &ch, void **obj) {
nuclear@0 624 if(!obj || !gc) return -1;
nuclear@0 625
nuclear@0 626 ReadCounter = HeaderSize; // reset the global read counter
nuclear@0 627
nuclear@0 628 string name = ReadString(file);
nuclear@0 629
nuclear@0 630 ChunkHeader chunk;
nuclear@0 631 chunk = ReadChunkHeader(file);
nuclear@0 632 if(chunk.id == Chunk_Obj_TriMesh) {
nuclear@0 633 // object is a trimesh... load it
nuclear@0 634 Vertex *varray;
nuclear@0 635 Triangle *tarray;
nuclear@0 636 dword VertexCount=0, TriCount=0;
nuclear@0 637 Material mat;
nuclear@0 638 Base base;
nuclear@0 639 Vector3 translation;
nuclear@0 640
nuclear@0 641 bool curve = true;
nuclear@0 642
nuclear@0 643 dword ObjChunkSize = ch.size;
nuclear@0 644
nuclear@0 645 while(ReadCounter < ObjChunkSize) { // make sure we only read subchunks of this object chunk
nuclear@0 646 //assert(!file.eof());
nuclear@0 647 assert(!eof);
nuclear@0 648 chunk = ReadChunkHeader(file);
nuclear@0 649
nuclear@0 650 switch(chunk.id) {
nuclear@0 651 case Chunk_TriMesh_VertexList:
nuclear@0 652 VertexCount = (dword)ReadWord(file);
nuclear@0 653 varray = new Vertex[VertexCount];
nuclear@0 654
nuclear@0 655 for(dword i=0; i<VertexCount; i++) {
nuclear@0 656 varray[i].pos = ReadVector(file);
nuclear@0 657 }
nuclear@0 658
nuclear@0 659 break;
nuclear@0 660
nuclear@0 661 case Chunk_TriMesh_FaceDesc:
nuclear@0 662 curve = false; // it is a real object not a curve since it has triangles
nuclear@0 663 TriCount = (dword)ReadWord(file);
nuclear@0 664 tarray = new Triangle[TriCount];
nuclear@0 665
nuclear@0 666 for(dword i=0; i<TriCount; i++) {
nuclear@0 667 tarray[i].vertices[0] = (Index)ReadWord(file); //
nuclear@0 668 tarray[i].vertices[2] = (Index)ReadWord(file); // flip order to CW
nuclear@0 669 tarray[i].vertices[1] = (Index)ReadWord(file); //
nuclear@0 670 ReadWord(file); // discard edge visibility flags
nuclear@0 671 }
nuclear@0 672 break;
nuclear@0 673
nuclear@0 674 case Chunk_Face_Material:
nuclear@0 675 mat = *FindMaterial(ReadString(file));
nuclear@0 676
nuclear@0 677 SkipBytes(file, ReadWord(file)<<1);
nuclear@0 678 break;
nuclear@0 679
nuclear@0 680 case Chunk_TriMesh_TexCoords:
nuclear@0 681 assert((dword)ReadWord(file) == VertexCount);
nuclear@0 682
nuclear@0 683 for(dword i=0; i<VertexCount; i++) {
nuclear@0 684 varray[i].tex[0].u = varray[i].tex[1].u = ReadFloat(file);
nuclear@0 685 varray[i].tex[0].v = varray[i].tex[1].v = -ReadFloat(file);
nuclear@0 686 }
nuclear@0 687 break;
nuclear@0 688
nuclear@0 689 case Chunk_TriMesh_SmoothingGroup:
nuclear@0 690 // **TODO** abide by smoothing groups duplicate vertices, weld others etc
nuclear@0 691 SkipChunk(file, chunk);
nuclear@0 692 break;
nuclear@0 693
nuclear@0 694 case Chunk_TriMesh_WorldTransform:
nuclear@0 695 base.i = ReadVector(file);
nuclear@0 696 base.k = ReadVector(file); // flip
nuclear@0 697 base.j = ReadVector(file);
nuclear@0 698 translation = ReadVector(file);
nuclear@0 699 break;
nuclear@0 700
nuclear@0 701 default:
nuclear@0 702 SkipChunk(file, chunk);
nuclear@0 703 }
nuclear@0 704 }
nuclear@0 705
nuclear@0 706 if(curve) {
nuclear@0 707 CatmullRomSpline *spline = new CatmullRomSpline;
nuclear@0 708 spline->name = name;
nuclear@0 709 for(dword i=0; i<VertexCount; i++) {
nuclear@0 710 spline->AddControlPoint(varray[i].pos);
nuclear@0 711 }
nuclear@0 712
nuclear@0 713 *obj = spline;
nuclear@0 714 return OBJ_CURVE;
nuclear@0 715 } else {
nuclear@0 716
nuclear@0 717 base.i.Normalize();
nuclear@0 718 base.j.Normalize();
nuclear@0 719 base.k.Normalize();
nuclear@0 720 Matrix3x3 RotXForm = base.CreateRotationMatrix();
nuclear@0 721 RotXForm.OrthoNormalize();
nuclear@0 722
nuclear@0 723 for(dword i=0; i<VertexCount; i++) {
nuclear@0 724 varray[i].pos.Translate(-translation.x, -translation.y, -translation.z);
nuclear@0 725 varray[i].pos.Transform(RotXForm.Transposed());
nuclear@0 726 }
nuclear@0 727
nuclear@0 728 Object *object = new Object(gc);
nuclear@0 729 object->name = name;
nuclear@0 730 object->GetTriMesh()->SetData(varray, tarray, VertexCount, TriCount);
nuclear@0 731 object->material = mat;
nuclear@0 732 object->SetRotation(RotXForm);
nuclear@0 733 object->SetTranslation(translation.x, translation.y, translation.z);
nuclear@0 734 *obj = object;
nuclear@0 735
nuclear@0 736 return OBJ_MESH;
nuclear@0 737 }
nuclear@0 738 } else {
nuclear@0 739
nuclear@0 740 if(chunk.id == Chunk_Obj_Light) {
nuclear@0 741
nuclear@0 742 dword ObjChunkSize = ch.size;
nuclear@0 743
nuclear@0 744 Vector3 pos = ReadVector(file);
nuclear@0 745 Color color = ReadColor(file);
nuclear@0 746
nuclear@0 747 Vector3 SpotTarget;
nuclear@0 748 float InnerCone, OuterCone;
nuclear@0 749 bool spot = false;
nuclear@0 750 bool att = false;
nuclear@0 751 bool CastShadows = false;
nuclear@0 752 float AttEnd = 10000.0f;
nuclear@0 753 float Intensity = 1.0f;
nuclear@0 754
nuclear@0 755 while(ReadCounter < ObjChunkSize) {
nuclear@0 756
nuclear@0 757 chunk = ReadChunkHeader(file);
nuclear@0 758
nuclear@0 759 switch(chunk.id) {
nuclear@0 760 case Chunk_Light_SpotLight:
nuclear@0 761 spot = true;
nuclear@0 762 SpotTarget = ReadVector(file);
nuclear@0 763 InnerCone = ReadFloat(file) / 180.0f;
nuclear@0 764 OuterCone = ReadFloat(file) / 180.0f;
nuclear@0 765 break;
nuclear@0 766
nuclear@0 767 case Chunk_Light_Attenuation:
nuclear@0 768 att = true;
nuclear@0 769 break;
nuclear@0 770
nuclear@0 771 case Chunk_Light_AttenuationEnd:
nuclear@0 772 AttEnd = ReadFloat(file);
nuclear@0 773 break;
nuclear@0 774
nuclear@0 775 case Chunk_Light_Intensity:
nuclear@0 776 Intensity = ReadFloat(file);
nuclear@0 777 break;
nuclear@0 778
nuclear@0 779 case Chunk_Spot_CastShadows:
nuclear@0 780 CastShadows = true;
nuclear@0 781 break;
nuclear@0 782
nuclear@0 783 default:
nuclear@0 784 SkipChunk(file, chunk);
nuclear@0 785 }
nuclear@0 786 }
nuclear@0 787
nuclear@0 788 Light *light;
nuclear@0 789 if(spot) {
nuclear@0 790 light = new TargetSpotLight(pos, SpotTarget, InnerCone, OuterCone);
nuclear@0 791 } else {
nuclear@0 792 light = new PointLight(pos);
nuclear@0 793 }
nuclear@0 794 light->SetColor(color);
nuclear@0 795 light->SetShadowCasting(CastShadows);
nuclear@0 796 light->SetIntensity(Intensity);
nuclear@0 797 light->name = name;
nuclear@0 798
nuclear@0 799 *obj = light;
nuclear@0 800 return spot ? OBJ_SPLIGHT : OBJ_PTLIGHT;
nuclear@0 801 }
nuclear@0 802
nuclear@0 803 if(chunk.id == Chunk_Obj_Camera) {
nuclear@0 804 Camera *cam = new Camera;
nuclear@0 805 Vector3 pos = ReadVector(file);
nuclear@0 806 Vector3 targ = ReadVector(file);
nuclear@0 807 float roll = ReadFloat(file);
nuclear@0 808 float FOV = ReadFloat(file);
nuclear@0 809
nuclear@0 810 Vector3 up = VECTOR3_J;
nuclear@0 811 Vector3 view = targ - pos;
nuclear@0 812 up.Rotate(view.Normalized(), roll);
nuclear@0 813
nuclear@0 814 cam->SetCamera(pos, targ, up);
nuclear@0 815 cam->name = name;
nuclear@0 816 cam->SetFOV(DEGTORAD(FOV) / 1.33333f);
nuclear@0 817
nuclear@0 818 *obj = cam;
nuclear@0 819 return OBJ_CAMERA;
nuclear@0 820 }
nuclear@0 821 }
nuclear@0 822
nuclear@0 823 return -1; // should have already left by now, if not something is wrong
nuclear@0 824 }
nuclear@0 825
nuclear@0 826
nuclear@0 827 ////////////////////////////////////////////////////////////////////////////////
nuclear@0 828 // functions to save/load normals from file
nuclear@0 829
nuclear@0 830 void WriteByte(HANDLE file, byte val) {
nuclear@0 831 dword junk;
nuclear@0 832 WriteFile(file, &val, sizeof(byte), &junk, 0);
nuclear@0 833 }
nuclear@0 834
nuclear@0 835 void WriteDword(HANDLE file, dword val) {
nuclear@0 836 dword junk;
nuclear@0 837 WriteFile(file, &val, sizeof(dword), &junk, 0);
nuclear@0 838 assert(junk == sizeof(dword));
nuclear@0 839 }
nuclear@0 840
nuclear@0 841 void WriteFloat(HANDLE file, float val) {
nuclear@0 842 dword junk;
nuclear@0 843 WriteFile(file, &val, sizeof(float), &junk, 0);
nuclear@0 844 assert(junk == sizeof(float));
nuclear@0 845 }
nuclear@0 846
nuclear@0 847 void WriteString(HANDLE file, string str) {
nuclear@0 848 dword junk;
nuclear@0 849 for(dword i=0; i<(dword)str.size(); i++) {
nuclear@0 850 WriteFile(file, &str[i], sizeof(char), &junk, 0);
nuclear@0 851 }
nuclear@0 852 }
nuclear@0 853
nuclear@0 854
nuclear@0 855 void SaveNormalsToFile(const char *fname, Scene *scene) {
nuclear@0 856
nuclear@0 857 HANDLE file = CreateFile(fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
nuclear@0 858 assert(file);
nuclear@0 859
nuclear@0 860 WriteDword(file, (dword)scene->GetObjectsList()->size());
nuclear@0 861
nuclear@0 862 std::list<Object*>::iterator objiter = scene->GetObjectsList()->begin();
nuclear@0 863 while(objiter != scene->GetObjectsList()->end()) {
nuclear@0 864 WriteString(file, (*objiter)->name);
nuclear@0 865 dword VertexCount = (*objiter)->GetTriMesh()->GetVertexCount();
nuclear@0 866 WriteDword(file, VertexCount);
nuclear@0 867
nuclear@0 868 const Vertex *varray = (*objiter)->GetTriMesh()->GetVertexArray();
nuclear@0 869 for(dword i=0; i<VertexCount; i++) {
nuclear@0 870 WriteFloat(file, varray[i].normal.x);
nuclear@0 871 WriteFloat(file, varray[i].normal.y);
nuclear@0 872 WriteFloat(file, varray[i].normal.z);
nuclear@0 873 }
nuclear@0 874
nuclear@0 875 objiter++;
nuclear@0 876 }
nuclear@0 877
nuclear@0 878 CloseHandle(file);
nuclear@0 879 }
nuclear@0 880
nuclear@0 881 bool LoadNormalsFromFile(const char *fname, Scene *scene) {
nuclear@0 882
nuclear@0 883 HANDLE file = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
nuclear@0 884 if(!file) return false;
nuclear@0 885
nuclear@0 886 eof = false;
nuclear@0 887 ReadCounter = 0;
nuclear@0 888
nuclear@0 889 dword FileSize = SetFilePointer(file, 0, 0, FILE_END) - SetFilePointer(file, 0, 0, FILE_BEGIN);
nuclear@0 890
nuclear@0 891 SetFilePointer(file, 0, 0, FILE_BEGIN);
nuclear@0 892
nuclear@0 893 dword ObjectCount = ReadDword(file);
nuclear@0 894 if(ObjectCount != scene->GetObjectsList()->size()) { // detect changes
nuclear@0 895 CloseHandle(file);
nuclear@0 896 return false;
nuclear@0 897 }
nuclear@0 898
nuclear@0 899 while(SceneLoader::ReadCounter < FileSize) {
nuclear@0 900 string name = ReadString(file);
nuclear@0 901 dword VertexCount = ReadDword(file);
nuclear@0 902
nuclear@0 903 Object *obj = scene->GetObject(name.c_str());
nuclear@0 904 if(!obj) {
nuclear@0 905 CloseHandle(file);
nuclear@0 906 return false;
nuclear@0 907 }
nuclear@0 908
nuclear@0 909 if(VertexCount != obj->GetTriMesh()->GetVertexCount()) { // again detect changes
nuclear@0 910 CloseHandle(file);
nuclear@0 911 return false;
nuclear@0 912 }
nuclear@0 913
nuclear@0 914 Vertex *varray = obj->GetTriMesh()->GetModVertexArray();
nuclear@0 915 for(dword i=0; i<VertexCount; i++) {
nuclear@0 916 varray[i].normal = ReadVector(file, false);
nuclear@0 917 }
nuclear@0 918 }
nuclear@0 919
nuclear@0 920 CloseHandle(file);
nuclear@0 921 return true;
nuclear@0 922 }
nuclear@0 923