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