1 namespace gfx3D::models;
8 #define RGB_FLOAT 0x0010
9 #define RGB_BYTE 0x0011
10 #define RGB_BYTE_GAMMA 0x0012
11 #define RGB_FLOAT_GAMMA 0x0013
14 #define AMOUNT_OF 0x0030
16 #define MAIN3DS 0x4D4D
17 #define EDIT3DS 0x3D3D
18 #define EDIT_AMBIENT 0x2100
19 #define EDIT_MATERIAL 0xAFFF
20 #define EDIT_OBJECT 0x4000
21 #define OBJ_HIDDEN 0x4010
22 #define OBJ_TRIMESH 0x4100
23 #define OBJ_LIGHT 0x4600
24 #define OBJ_CAMERA 0x4700
26 // Triangular Mesh Chunks
27 #define TRI_VERTEXL 0x4110
28 #define TRI_FACEL1 0x4120
29 #define TRI_MATERIAL 0x4130
30 #define TRI_MAPPINGCOORS 0x4140
31 #define TRI_SMOOTHING 0x4150
32 #define TRI_LOCAL 0x4160
35 #define LIT_SPOT 0x4610
36 #define LIT_ONOFF 0x4620
37 #define LIT_ATTENUATION 0x4625
38 #define LIT_START 0x4659
39 #define LIT_END 0x465A
40 #define LIT_MULTIPLIER 0x465B
43 #define CAM_SEECONE 0x4710
44 #define CAM_RANGES 0x4720
47 #define MAT_NAME 0xA000
48 #define MAT_AMBIENT 0xA010
49 #define MAT_DIFFUSE 0xA020
50 #define MAT_SPECULAR 0xA030
51 #define MAT_SHININESS 0xA040
52 #define MAT_SHINSTRENGTH 0xA041
53 #define MAT_TRANSPARENCY 0xA050
54 #define MAT_DOUBLESIDED 0xA081
55 #define MAT_SELFILLUM 0xA084
56 #define MAT_MAPTEXTURE1 0xA200
57 #define MAT_MAPOPACITY 0xA210
60 #define MAP_FILENAME 0xA300
61 #define MAP_OPTIONS 0xA351
62 #define MAP_1_U_SCALE 0xA354
63 #define MAP_1_V_SCALE 0xA356
64 #define MAP_U_OFFSET 0xA358
65 #define MAP_V_OFFSET 0xA35A
66 #define MAP_ROTATION 0xA35C
69 #define KEYFRAME3DS 0xB000
70 #define FRM_AMBIENT 0xB001
71 #define FRM_MESHINFO 0xB002
72 #define FRM_CAMERA 0xB003
73 #define FRM_CAMERATARGET 0xB004
74 #define FRM_OMNILIGHT 0xB005
75 #define FRM_SPOTLIGHTTARGET 0xB006
76 #define FRM_SPOTLIGHT 0xB007
77 #define FRM_FRAMES 0xB008
78 #define FRM_PARAM 0xB010
79 #define FRM_DUMMYNAME 0xB011
80 #define FRM_PIVOT 0xB013
81 #define FRM_TRACKPOS 0xB020
82 #define FRM_TRACKROT 0xB021
83 #define FRM_TRACKSCALE 0xB022
84 #define FRM_TRACKFOV 0xB023
85 #define FRM_TRACKROLL 0xB024
86 #define FRM_TRACKCOLOR 0xB025
87 #define FRM_TRACKMORPH 0xB026 // What does this do?
88 #define FRM_TRACKHOTSPOT 0xB027
89 #define FRM_TRACKFALLOFF 0xB028
90 #define FRM_TRACKHIDE 0xB029
91 #define FRM_HIERARCHY 0xB030
93 typedef struct FileInfo FileInfo;
106 DisplaySystem displaySystem;
115 char textureDirectory[MAX_DIRECTORY];
118 #define SWAP_WORD(word) (((unsigned short)(word) & 0x00ff) << 8) \
119 | (((unsigned short)(word) & 0xff00) >> 8)
121 #define SWAP_DWORD(dword) ((((unsigned int)(dword) & 0x000000ff) << 24) \
122 | (((unsigned int)(dword) & 0x0000ff00) << 8) \
123 | (((unsigned int)(dword) & 0x00ff0000) >> 8) \
124 | (((unsigned int)(dword) & 0xff000000) >> 24))
126 #ifndef __BIG_ENDIAN__
127 #define BIGENDSWAP_WORD(word)
128 #define BIGENDSWAP_DWORD(dword)
130 #define BIGENDSWAP_WORD(word) (*(uint16 *)(&(word))) = SWAP_WORD((*(uint16 *)(&(word))));
131 #define BIGENDSWAP_DWORD(dword) (*(uint *)(&(dword))) = SWAP_DWORD((*(uint *)(&(dword))));
134 // Zero Terminated String
135 static int ReadASCIIZ(File f, char ** string)
137 // *** Read String ***
139 char temp[1024] = "";
143 if(!temp[c++]) break;
145 *string = new char[c];
147 strcpy(*string, temp);
151 static float ReadFloat(File f)
154 f.Read(&floatValue, sizeof(float), 1);
155 BIGENDSWAP_DWORD(floatValue);
159 static uint16 ReadWORD(File f)
162 f.Read(&wordValue, sizeof(uint16), 1);
163 BIGENDSWAP_WORD(wordValue);
167 static uint ReadDWORD(File f)
170 f.Read(&dwordValue, sizeof(uint), 1);
171 BIGENDSWAP_DWORD(dwordValue);
176 static bool ReadChunks(bool (* chunkParser)(FileInfo * info, void * data), FileInfo * info, void * data)
178 for(;info->pos < info->end;)
180 FileInfo childInfo = *info;
183 childInfo.parent = info;
185 info->f.Seek(info->pos, start);
186 childInfo.chunkId = ReadWORD(info->f);
187 length = ReadDWORD(info->f);
189 childInfo.pos += sizeof(uint16) + sizeof(uint);
190 childInfo.end = info->pos + length;
192 if(!chunkParser(&childInfo, data))
195 info->pos = childInfo.end;
201 static bool ReadRGB(FileInfo * info, ColorRGB * rgb)
203 if(info->chunkId == RGB_BYTE || info->chunkId == RGB_BYTE_GAMMA)
206 info->f.Getc(&value); rgb->r = value / 255.0f;
207 info->f.Getc(&value); rgb->g = value / 255.0f;
208 info->f.Getc(&value); rgb->b = value / 255.0f;
210 else if(info->chunkId == RGB_FLOAT || info->chunkId == RGB_FLOAT_GAMMA)
212 rgb->r = ReadFloat(info->f);
213 rgb->g = ReadFloat(info->f);
214 rgb->b = ReadFloat(info->f);
219 static bool Read3DVertex(File f, Vector3Df vertex)
221 vertex.x = ReadFloat(f);
222 vertex.y = ReadFloat(f);
223 vertex.z = ReadFloat(f);
227 static bool ReadAmountOf(FileInfo * info, uint16 * amountOf)
229 if(info->chunkId == AMOUNT_OF)
230 *amountOf = ReadWORD(info->f);
243 VertexConfig * config;
246 static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
249 Face * faces = info->faces;
250 //int nFaces = info->nFaces;
251 int nVertices = mesh.nVertices;
256 VertexConfigList * configLists = new0 VertexConfigList[nVertices];
258 nNewVertices = nVertices;
259 for(c = 0; c<info->nFaces; c++)
261 Face * face = &faces[c];
266 int index = face->indices[i];
268 VertexConfigList * configList = &configLists[index];
269 VertexConfig * config = null;
270 for(v = 0; v<configList->numConfig; v++)
272 uint smoothGroups = configList->config[v].smoothGroups;
273 if(smoothGroups == face->smoothGroups)
275 config = &configList->config[v];
278 else if(smoothGroups && face->smoothGroups)
281 for(g = 0; g<32; g++)
282 if(smoothGroups & (1<<g) && face->smoothGroups & (1<<g))
284 config = &configList->config[v];
285 config->smoothGroups |= face->smoothGroups;
291 if(!config || !face->smoothGroups)
293 // Duplicate the vertex and make the face use it
294 if(configList->numConfig)
295 index = nNewVertices++;
296 face->indices[i] = (uint16)index;
299 configList->config = renew configList->config VertexConfig[configList->numConfig + 1];
300 config = &configList->config[configList->numConfig++];
301 config->index = index;
302 config->smoothGroups = face->smoothGroups;
307 face->indices[i] = (uint16)config->index;
312 // Allocate some extra vertices
314 Vector3Df * oldVertices = mesh.vertices;
315 Pointf * oldTexCoords = mesh.texCoords;
317 *((void **)&mesh.vertices) = null;
318 *((void **)&mesh.texCoords) = null;
319 *((int *)&mesh.nVertices) = 0;
321 mesh.Allocate( { vertices = true, normals = true, texCoords1 = oldTexCoords ? true : false }, nNewVertices, info->displaySystem);
323 // Fill in the new vertices
324 for(index = 0; index<nVertices; index++)
327 VertexConfigList * configList = &configLists[index];
328 for(v = 0; v<configList->numConfig; v++)
330 VertexConfig * config = &configList->config[v];
332 if(config->smoothGroups)
337 mesh.vertices[config->index] = oldVertices[index]; //mesh.vertices[index];
339 mesh.texCoords[config->index] = oldTexCoords[index]; //mesh.texCoords[index];
344 mesh.vertices[config->index] = oldVertices[index];
346 mesh.texCoords[config->index] = oldTexCoords[index]; //mesh.texCoords[index];
348 normal = &mesh.normals[config->index];
357 numShared = new0 int[nNewVertices];
359 for(c = 0; c<info->nFaces; c++)
361 Face * face = &faces[c];
364 Vector3Df planeNormal;
365 plane.FromPointsf(mesh.vertices[face->oldIndices[2]],
366 mesh.vertices[face->oldIndices[1]],
367 mesh.vertices[face->oldIndices[0]]);
368 planeNormal = { (float)plane.normal.x, (float)plane.normal.y, (float)plane.normal.z };
369 if(face->smoothGroups)
373 int index = face->indices[i];
374 Vector3Df * normal = &mesh.normals[index];
375 normal->Add(normal, planeNormal);
383 int index = face->oldIndices[i];
384 int newIndex = face->indices[i];
385 mesh.normals[newIndex] = planeNormal;
387 if(index != newIndex)
389 mesh.vertices[newIndex] = mesh.vertices[index];
391 mesh.texCoords[newIndex] = mesh.texCoords[index];
393 numShared[newIndex]++;
397 for(index = 0; index<nNewVertices; index++)
399 Vector3Df * normal = &mesh.normals[index];
400 normal->Scale(normal, 1.0f / numShared[index]);
401 normal->Normalize(normal);
404 mesh.Unlock({ normals = true });
406 // Free all the temporary stuff
409 for(index = 0; index < nVertices; index++)
411 VertexConfigList * configList = &configLists[index];
412 if(configList->config) delete configList->config;
420 static bool ReadSmoothing(FileInfo * info, Object object)
422 Mesh mesh = object.mesh;
423 switch(info->chunkId)
428 for(c = 0; c<info->nFaces; c++)
429 info->faces[c].smoothGroups = ReadDWORD(info->f);
436 static bool ReadFacesListChunks(FileInfo * info, Object object)
438 DisplaySystem displaySystem = info->displaySystem;
439 Mesh mesh = object.mesh;
440 switch(info->chunkId)
447 ReadASCIIZ(info->f, &name);
448 mat = displaySystem.GetMaterial(name);
451 if(mat.flags.translucent)
454 uint16 count = ReadWORD(info->f);
455 mesh.primitives = renew mesh.primitives PrimitiveSingle[mesh.nPrimitives + count];
456 for(c = 0; c<count; c++)
458 uint16 face = ReadWORD(info->f);
459 PrimitiveSingle * triangle = &mesh.primitives[mesh.nPrimitives++];
461 if(mesh.AllocatePrimitive(triangle, triangles, 3))
463 triangle->indices[0] = info->faces[face].indices[0];
464 triangle->indices[1] = info->faces[face].indices[1];
465 triangle->indices[2] = info->faces[face].indices[2];
466 triangle->middle.Add(mesh.vertices[triangle->indices[0]], mesh.vertices[triangle->indices[1]]);
467 triangle->middle.Add(triangle->middle, mesh.vertices[triangle->indices[2]]);
468 triangle->plane.FromPointsf(
469 mesh.vertices[triangle->indices[2]],
470 mesh.vertices[triangle->indices[1]],
471 mesh.vertices[triangle->indices[0]]);
473 mesh.UnlockPrimitive(triangle);
475 triangle->middle.x /= 3;
476 triangle->middle.y /= 3;
477 triangle->middle.z /= 3;
479 triangle->material = mat;
481 info->faces[face].done = (byte)bool::true;
483 object.flags.translucent = true;
487 PrimitiveGroup group;
488 uint16 count = ReadWORD(info->f);
489 group = mesh.AddPrimitiveGroup(triangles, count * 3);
493 group.material = mat;
494 for(c = 0; c<count; c++)
496 uint16 face = ReadWORD(info->f);
497 if(object.flags.flipWindings)
499 group.indices[c*3] = info->faces[face].indices[2];
500 group.indices[c*3+1] = info->faces[face].indices[1];
501 group.indices[c*3+2] = info->faces[face].indices[0];
505 group.indices[c*3] = info->faces[face].indices[0];
506 group.indices[c*3+1] = info->faces[face].indices[1];
507 group.indices[c*3+2] = info->faces[face].indices[2];
509 info->faces[face].done = (byte)bool::true;
511 mesh.UnlockPrimitiveGroup(group);
522 static bool ReadTriMesh(FileInfo * info, Object object)
524 Mesh mesh = object.mesh;
525 switch(info->chunkId)
530 uint16 nVertices = ReadWORD(info->f);
531 //if(eMesh_Allocate(mesh, MESH_VERTICES, nVertices, info->display->displaySystem))
532 *((int *) &mesh.nVertices) = nVertices;
533 *((Vector3Df **)&mesh.vertices) = new Vector3Df[mesh.nVertices];
536 for(c = 0; c<mesh.nVertices; c++)
539 Read3DVertex(info->f, vertex);
540 mesh.vertices[c].x = vertex.x;
541 mesh.vertices[c].y =-vertex.z;
542 mesh.vertices[c].z = vertex.y;
549 case TRI_MAPPINGCOORS:
552 uint16 count = ReadWORD(info->f);
553 count = (uint16)Min(mesh.nVertices, count);
555 //if(eMesh_Allocate(mesh, MESH_TEXCOORDS1, mesh.nVertices, null /*info->display->displaySystem*/))
556 *((Pointf **)&mesh.texCoords) = new Pointf[mesh.nVertices];
557 mesh.flags.texCoords1 = true;
560 for(c = 0; c<count; c++)
562 mesh.texCoords[c].x = ReadFloat(info->f);
563 mesh.texCoords[c].y = 1.0f - ReadFloat(info->f);
577 info->nFaces = nFaces = ReadWORD(info->f);
578 info->pos += sizeof(uint16);
580 info->faces = new0 Face[nFaces];
581 for(c = 0; c<nFaces; c++)
586 info->faces[c].oldIndices[i] =
587 info->faces[c].indices[i] = ReadWORD(info->f);
590 info->pos += 4*sizeof(uint16);
593 ReadChunks(ReadSmoothing, info, object);
596 ComputeNormals(mesh, info, object);
598 ReadChunks(ReadFacesListChunks, info, object);
600 // Add faces without a material all together
602 for(c = 0; c<nFaces; c++)
603 if(!info->faces[c].done)
607 PrimitiveGroup group = mesh.AddPrimitiveGroup(triangles, count * 3);
610 for(c = 0; c<nFaces; c++)
611 if(!info->faces[c].done)
613 group.indices[c*3] = info->faces[c].indices[0];
614 group.indices[c*3+1] = info->faces[c].indices[1];
615 group.indices[c*3+2] = info->faces[c].indices[2];
617 mesh.UnlockPrimitiveGroup(group);
624 mesh.ComputeNormals();
626 if(object.flags.flipWindings)
628 if(mesh.Lock({ normals = true }))
630 for(c = 0; c<mesh.nVertices; c++)
632 mesh.normals[c].x *= -1;
633 mesh.normals[c].y *= -1;
634 mesh.normals[c].z *= -1;
636 mesh.Unlock({ normals = true });
640 // could use this instead? : mesh.ApplyTranslucency(object);
646 Vector3Df xAxis, yAxis, zAxis, center;
649 Matrix inverse/*, source = { 0 }*/;
652 Read3DVertex(info->f, xAxis);
653 Read3DVertex(info->f, yAxis);
654 Read3DVertex(info->f, zAxis);
655 Read3DVertex(info->f, center);
657 scaling.x = (float)sqrt(xAxis.x * xAxis.x + xAxis.y * xAxis.y + xAxis.z * xAxis.z);
658 scaling.y = (float)sqrt(zAxis.x * zAxis.x + zAxis.y * zAxis.y + zAxis.z * zAxis.z);
659 scaling.z = (float)sqrt(yAxis.x * yAxis.x + yAxis.y * yAxis.y + yAxis.z * yAxis.z);
661 // Inverse of this doesn't give a good enough result with small numbers (bellrang.3ds)
664 source.m[0][0] = xAxis.x; source.m[0][1] = -xAxis.z; source.m[0][2] = xAxis.y;
665 source.m[1][0] =-zAxis.x; source.m[1][1] = zAxis.z; source.m[1][2] = -zAxis.y;
666 source.m[2][0] = yAxis.x; source.m[2][1] = -yAxis.z; source.m[2][2] = yAxis.y;
667 source.m[3][0] = center.x; source.m[3][1] = -center.z; source.m[3][2] = center.y;
669 inverse.Inverse(source);
672 object.flags.flipWindings = false;
674 xAxis.Normalize(xAxis);
675 yAxis.Normalize(yAxis);
676 zAxis.Normalize(zAxis);
678 orth.CrossProduct(yAxis, zAxis);
679 if((Abs(orth.x) > 0.00001 && Sgn(orth.x) != Sgn(xAxis.x)) ||
680 (Abs(orth.y) > 0.00001 && Sgn(orth.y) != Sgn(xAxis.y)) ||
681 (Abs(orth.z) > 0.00001 && Sgn(orth.z) != Sgn(xAxis.z)))
683 object.flags.flipWindings ^= true;
687 orth.CrossProduct(zAxis, xAxis);
688 if((Abs(orth.x) > 0.00001 && Sgn(orth.x) != Sgn(yAxis.x)) ||
689 (Abs(orth.y) > 0.00001 && Sgn(orth.y) != Sgn(yAxis.y)) ||
690 (Abs(orth.z) > 0.00001 && Sgn(orth.z) != Sgn(yAxis.z)))
692 object.flags.flipWindings ^= true;
696 orth.CrossProduct(xAxis, yAxis);
697 if((Abs(orth.x) > 0.00001 && Sgn(orth.x) != Sgn(zAxis.x)) ||
698 (Abs(orth.y) > 0.00001 && Sgn(orth.y) != Sgn(zAxis.y)) ||
699 (Abs(orth.z) > 0.00001 && Sgn(orth.z) != Sgn(zAxis.z)))
701 object.flags.flipWindings ^= true;
708 rotation.m[0][0] = xAxis.x;
709 rotation.m[0][1] =-xAxis.z;
710 rotation.m[0][2] = xAxis.y;
711 rotation.m[0][3] = 0;
712 rotation.m[1][0] =-zAxis.x;
713 rotation.m[1][1] = zAxis.z;
714 rotation.m[1][2] =-zAxis.y;
715 rotation.m[1][3] = 0;
716 rotation.m[2][0] = yAxis.x;
717 rotation.m[2][1] =-yAxis.z;
718 rotation.m[2][2] = yAxis.y;
719 rotation.m[2][3] = 0;
720 rotation.m[3][0] = 0;
721 rotation.m[3][1] = 0;
722 rotation.m[3][2] = 0;
723 rotation.m[3][3] = 1;
727 inverse.Transpose(rotation);
729 temp.Translate(-center.x, center.z, -center.y);
730 temp2.Multiply(temp, inverse);
731 temp2.Scale(1.0f/scaling.x, 1.0f/scaling.y, 1.0f/scaling.z);
735 object.transform.scaling = scaling;
736 // TODO: Improve language to support deep properties on non constant functions
737 // object.transform.orientation.RotationMatrix(rotation);
739 Quaternion orientation;
740 orientation.RotationMatrix(rotation);
741 object.transform.orientation = orientation;
743 object.transform.position = { center.x, -center.z, center.y };
746 // Localize All Vertices
747 for(c = 0; c<mesh.nVertices; c++)
749 Vector3Df vertex = mesh.vertices[c];
751 mesh.vertices[c].MultMatrix(vertex, inverse);
753 mesh.vertices[c].x -= object.pivot.x;
754 mesh.vertices[c].y -= object.pivot.y;
755 mesh.vertices[c].z -= object.pivot.z;
764 static bool ReadMap(FileInfo * info, Material mat)
766 DisplaySystem displaySystem = info->displaySystem;
767 switch(info->chunkId)
771 Bitmap opacityMap = null;
773 char location[MAX_LOCATION];
775 ReadASCIIZ(info->f, &name);
778 strcpy(location, info->textureDirectory);
779 PathCat(location, name);
783 mat.baseMap = displaySystem.GetTexture(name);
786 mat.baseMap = Bitmap { };
787 if(!mat.baseMap.Load(location, null, null) ||
788 !mat.baseMap.Convert(null, pixelFormat888, null) ||
789 !displaySystem.AddTexture(name, mat.baseMap))
793 opacityMap = mat.baseMap;
796 else if(info->parent->chunkId == MAT_MAPOPACITY)
798 opacityMap = Bitmap { };
799 if(!opacityMap.Load(location, null, null) ||
800 !opacityMap.Convert(null, pixelFormat888, null))
808 if(!mat.baseMap.displaySystem && info->parent->chunkId == MAT_MAPOPACITY && opacityMap)
811 ColorAlpha * picture = (ColorAlpha *)mat.baseMap.picture;
813 for(c = 0; c < opacityMap.width * opacityMap.height; c++)
814 picture[c] = ColorAlpha { ((ColorAlpha *)opacityMap.picture)[c].color.r, picture[c].color };
816 mat.diffuse.r = mat.diffuse.g = mat.diffuse.b =
817 mat.ambient.r = mat.ambient.g = mat.ambient.b = 1.0f;
819 if(opacityMap != mat.baseMap)
826 uint16 options = ReadWORD(info->f);
827 if(!(options & 0x10)) mat.flags.tile = true;
831 mat.uScale = ReadFloat(info->f);
834 mat.vScale = ReadFloat(info->f);
840 static bool ReadMaterial(FileInfo * info, Material mat)
842 switch(info->chunkId)
846 ReadASCIIZ(info->f, &mat.name);
849 case MAT_TRANSPARENCY:
852 ReadChunks(ReadAmountOf, info, &transparency);
853 mat.opacity = 1.0f - transparency / 100.0f;
854 if(mat.opacity < 1.0)
855 mat.flags.translucent = true;
860 ReadChunks(ReadRGB, info, &mat.diffuse);
861 ReadChunks(ReadRGB, info, &mat.diffuse);
866 ReadChunks(ReadRGB, info, &mat.ambient);
867 ReadChunks(ReadRGB, info, &mat.ambient);
872 ReadChunks(ReadRGB, info, &mat.specular);
873 ReadChunks(ReadRGB, info, &mat.specular);
879 ReadChunks(ReadAmountOf, info, &emissive);
880 mat.emissive.r = mat.diffuse.r * emissive / 100.0f;
881 mat.emissive.g = mat.diffuse.g * emissive / 100.0f;
882 mat.emissive.b = mat.diffuse.b * emissive / 100.0f;
885 case MAT_SHINSTRENGTH:
888 ReadChunks(ReadAmountOf, info, &shininess);
889 mat.specular.r *= shininess / 100.0f;
890 mat.specular.g *= shininess / 100.0f;
891 mat.specular.b *= shininess / 100.0f;
897 ReadChunks(ReadAmountOf, info, &power);
901 case MAT_MAPTEXTURE1:
902 ReadChunks(ReadMap, info, mat);
905 ReadChunks(ReadMap, info, mat);
906 mat.flags.translucent = true;
908 case MAT_DOUBLESIDED:
909 mat.flags.doubleSided = true;
916 static bool ReadLight(FileInfo * info, Object object)
918 Mesh mesh = object.mesh;
919 Light * light = &object.light;
920 switch(info->chunkId)
925 case RGB_FLOAT_GAMMA:
926 ReadRGB(info, &light->diffuse);
927 light->specular = light->diffuse;
932 char targetName[MAXNAMELEN];
934 strcpy(targetName, object.name);
935 strcat(targetName, ".target");
937 light->flags.omni = false;
938 light->flags.spot = true;
941 target.name = CopyString(targetName);
942 info->rootObject.children.AddName(target);
943 target.parent = info->rootObject;
945 light->target = target;
947 target.transform.position.x = ReadFloat(info->f);
948 target.transform.position.z = ReadFloat(info->f);
949 target.transform.position.y =-ReadFloat(info->f);
951 light->hotSpot = ReadFloat(info->f);
952 light->fallOff = ReadFloat(info->f);
957 light->flags.off = true;
960 case LIT_ATTENUATION:
964 d = 300, small = 0.001,
966 d * (Kl + Kq * d) = (1 / small) - Kc
968 { Kc, Kl, Kq, small, d });
971 light->flags.attenuation = true;
974 #define MINLIGHT 0.08
975 light->Kq = 1/(light->end*light->end*MINLIGHT);
978 #define MINLIGHT 0.15f
979 // #define MINLIGHT 0.1
980 light->Kl = (float)(1/(light->end*MINLIGHT));
986 light->start = ReadFloat(info->f);
991 light->end = ReadFloat(info->f);
996 light->multiplier = ReadFloat(info->f);
1004 static bool ReadCamera(FileInfo * info, Object object)
1006 Mesh mesh = object.mesh;
1007 switch(info->chunkId)
1015 Camera camera = object.camera;
1016 float nearRange = ReadFloat(info->f);
1017 float farRange = ReadFloat(info->f);
1019 camera.zMin = Max(0.1, nearRange);
1020 camera.zMax = farRange;
1029 static bool ReadEditObject(FileInfo * info, char * name)
1031 DisplaySystem displaySystem = info->displaySystem;
1032 switch(info->chunkId)
1036 Object object = info->rootObject.Find(name);
1039 object = Object { };
1041 info->rootObject.children.AddName(object);
1042 object.parent = info->rootObject;
1046 object.InitializeMesh(displaySystem);
1047 ReadChunks(ReadTriMesh, info, object);
1048 object.flags.mesh = true;
1049 object.mesh.Unlock(0);
1054 Object object = info->rootObject.Find(name);
1060 object = Object { };
1062 info->rootObject.children.AddName(object);
1063 object.parent = info->rootObject;
1067 object.flags.light = true;
1069 light = &object.light;
1070 light->lightObject = object;
1071 light->flags.omni = true;
1072 light->multiplier = 1.0f;
1074 // This is not used?
1075 Read3DVertex(info->f, position);
1076 light->direction = { position.x, position.y, position.z };
1077 info->pos += sizeof(float) * 3;
1079 ReadChunks(ReadLight, info, object);
1084 char targetName[MAXNAMELEN];
1085 Object object = info->rootObject.Find(name);
1088 float bankAngle, focus;
1091 strcpy(targetName, name);
1092 strcat(targetName, ".target");
1096 object = Object { };
1098 info->rootObject.children.AddName(object);
1100 object.parent = info->rootObject;
1101 object.camera = Camera { };
1102 object.camera.type = lookAtObject;
1104 target = Object { };
1105 target.name = CopyString(targetName);
1106 info->rootObject.children.AddName(target);
1107 target.parent = info->rootObject;
1112 object.flags.camera = true;
1113 object.cameraTarget = target;
1115 camera = object.camera;
1116 camera.cameraObject = object;
1117 camera.target = target;
1119 //Read3DVertex(info->f, camera.position);
1120 object.transform.position.x = ReadFloat(info->f);
1121 object.transform.position.z = ReadFloat(info->f);
1122 object.transform.position.y =-ReadFloat(info->f);
1124 info->pos += sizeof(float) * 3;
1125 //Read3DVertex(info->f, object.cameraTarget.position);
1126 target.transform.position.x = ReadFloat(info->f);
1127 target.transform.position.z = ReadFloat(info->f);
1128 target.transform.position.y =-ReadFloat(info->f);
1130 info->pos += sizeof(float) * 3;
1131 bankAngle = ReadFloat(info->f);
1132 info->pos += sizeof(float);
1133 focus = ReadFloat(info->f);
1134 info->pos += sizeof(float);
1136 mm = (focus - 5.05659508373109) / 1.13613250717301;
1137 camera.fov = (float)(1248.58921609766 * pow(mm, -0.895625414990581));
1139 ReadChunks(ReadCamera, info, object);
1142 case OBJ_HIDDEN: break;
1149 #define COPY_NITEM(d, s) CopyBytes(((byte *)(d)) + sizeof(class NamedItem), ((byte *)(s)) + sizeof(class NamedItem), sizeof((*s)) - sizeof(class NamedItem));
1151 static bool ReadEditChunks(FileInfo * info, void * data)
1153 switch(info->chunkId)
1157 // Read the ambient color
1158 ReadChunks(ReadRGB, info, &info->rootObject.ambient);
1163 Material material { };
1165 ReadChunks(ReadMaterial, info, material);
1167 mat = info->displaySystem.AddNamedMaterial(material.name);
1170 if(material.baseMap)
1171 material.baseMap.MakeMipMaps(info->displaySystem);
1172 // COPY_NITEM(mat, material);
1173 CopyBytes(((byte *)(mat)) + sizeof(class NamedItem), ((byte *)(material)) + sizeof(class NamedItem), sizeof(class Material) - sizeof(class NamedItem));
1177 delete material.baseMap;
1179 delete material.name;
1186 info->pos += ReadASCIIZ(info->f, &name);
1187 ReadChunks(ReadEditObject, info, name);
1194 struct ObjectInfoBlock
1204 // Key Framer Chunks
1206 #define ACCFLAG_TENSION 0x00000001
1207 #define ACCFLAG_CONTINUITY 0x00000002
1208 #define ACCFLAG_BIAS 0x00000004
1209 #define ACCFLAG_EASETO 0x00000008
1210 #define ACCFLAG_EASEFROM 0x00000010
1212 static bool ReadFrameInfoBlock(FileInfo * info, ObjectInfoBlock * block)
1214 switch(info->chunkId)
1218 uint16 flags1, flags2;
1219 ReadASCIIZ(info->f, &block->name);
1220 flags1 = ReadWORD(info->f);
1221 flags2 = ReadWORD(info->f);
1222 block->parent = ReadWORD(info->f);
1226 ReadASCIIZ(info->f, &block->dummyName);
1229 Read3DVertex(info->f, block->pivot);
1232 block->hierarchy = ReadWORD(info->f);
1236 case FRM_TRACKSCALE:
1239 case FRM_TRACKCOLOR:
1240 case FRM_TRACKHOTSPOT:
1241 case FRM_TRACKFALLOFF:
1243 FrameTrack track { };
1250 block->tracks.Add(track);
1252 flags = ReadWORD(info->f);
1254 info->f.Read(unknown, sizeof(unknown), 1);
1256 track.numKeys = ReadDWORD(info->f);
1258 switch(info->chunkId)
1260 case FRM_TRACKPOS: track.type.type = position; break;
1261 case FRM_TRACKROT: track.type.type = rotation; break;
1262 case FRM_TRACKSCALE: track.type.type = scaling; break;
1263 case FRM_TRACKROLL: track.type.type = roll; break;
1264 case FRM_TRACKFOV: track.type.type = fov; break;
1265 case FRM_TRACKCOLOR: track.type.type = colorChange; break;
1266 case FRM_TRACKHOTSPOT: track.type.type = hotSpot; break;
1267 case FRM_TRACKFALLOFF: track.type.type = fallOff; break;
1269 if((flags & 0x0003) == 3)
1270 track.type.loop = true;
1272 track.keys = new0 FrameKey[track.numKeys];
1273 for(c = 0; c<track.numKeys; c++)
1275 uint16 accelerationFlags;
1276 FrameKey * key = track.keys + c;
1278 key->frame = ReadDWORD(info->f);
1279 accelerationFlags = ReadWORD(info->f);
1281 if(accelerationFlags & ACCFLAG_TENSION)
1282 key->tension = ReadFloat(info->f);
1283 if(accelerationFlags & ACCFLAG_CONTINUITY)
1284 key->continuity = ReadFloat(info->f);
1285 if(accelerationFlags & ACCFLAG_BIAS)
1286 key->bias = ReadFloat(info->f);
1287 if(accelerationFlags & ACCFLAG_EASETO)
1288 key->easeTo = ReadFloat(info->f);
1289 if(accelerationFlags & ACCFLAG_EASEFROM)
1290 key->easeFrom = ReadFloat(info->f);
1292 switch(info->chunkId)
1297 Read3DVertex(info->f, position);
1298 key->position = { position.x, -position.z, position.y };
1304 Angle angle = ReadFloat(info->f);
1305 Vector3Df fixedAxis;
1307 Read3DVertex(info->f, axis);
1308 fixedAxis.x = axis.x;
1309 fixedAxis.y = -axis.z;
1310 fixedAxis.z = axis.y;
1314 Quaternion rotation;
1315 rotation.RotationAxis(fixedAxis, angle);
1316 key->orientation.Multiply((key - 1)->orientation, rotation);
1319 key->orientation.RotationAxis(fixedAxis, angle);
1322 case FRM_TRACKSCALE:
1325 Read3DVertex(info->f, scaling);
1326 key->scaling = { scaling.x, scaling.z, scaling.y };
1331 key->fov = ReadFloat(info->f);
1336 key->roll = -ReadFloat(info->f);
1339 case FRM_TRACKCOLOR:
1341 FileInfo childInfo = *info;
1342 childInfo.chunkId = RGB_FLOAT;
1343 ReadRGB(&childInfo, &key->color);
1346 case FRM_TRACKHOTSPOT:
1348 key->hotSpot = ReadFloat(info->f);
1351 case FRM_TRACKFALLOFF:
1353 key->fallOff = ReadFloat(info->f);
1365 static Object FindObjectID(Object object, int id)
1367 Object result = null;
1369 for(child = object.children.first; child; child = child.next)
1371 if(child.flags.hierarchy == (uint16) id)
1378 result = FindObjectID(child, id);
1385 static bool ReadKeyFrameChunks(FileInfo * info, void * data)
1387 switch(info->chunkId)
1391 ObjectInfoBlock block { };
1394 ReadChunks(ReadFrameInfoBlock, info, &block);
1396 if(block.dummyName && block.dummyName[0])
1398 if(!strcmp(block.name, "$$$DUMMY"))
1400 object = Object { };
1401 object.name = block.dummyName;
1402 info->rootObject.children.AddName(object);
1403 object.transform.scaling = { 1,1,1 };
1407 Object model = info->rootObject.Find(block.name);
1410 object = Object { };
1411 object.name = new char[strlen(block.dummyName) + strlen(model.name) + 2];
1412 sprintf(object.name, "%s.%s", model.name, block.dummyName);
1413 object.flags = model.flags;
1414 object.flags.ownMesh = false;
1415 object.mesh = model.mesh;
1417 object.min = model.min;
1418 object.max = model.max;
1419 object.radius = model.radius;
1421 object.transform = model.transform;
1422 info->rootObject.children.AddName(object);
1424 delete block.dummyName;
1426 object.parent = info->rootObject;
1429 object = info->rootObject.Find(block.name);
1433 Mesh mesh = object.mesh;
1434 object.flags.hierarchy = block.hierarchy + 1;
1435 if(block.parent != -1)
1437 Object parent = FindObjectID(info->rootObject, block.parent + 1);
1440 object.parent.children.Remove(object);
1441 parent.children.AddName(object);
1442 object.parent = parent;
1445 object.pivot.x = block.pivot.x;
1446 object.pivot.y =-block.pivot.z;
1447 object.pivot.z = block.pivot.y;
1449 if(mesh && object.flags.ownMesh)
1451 if(mesh.Lock({ vertices = true }))
1454 // Take pivot into account
1455 for(c = 0; c<mesh.nVertices; c++)
1457 mesh.vertices[c].x -= object.pivot.x;
1458 mesh.vertices[c].y -= object.pivot.y;
1459 mesh.vertices[c].z -= object.pivot.z;
1461 mesh.Unlock({ vertices = true });
1465 object.tracks = block.tracks;
1466 *&(object.frame) = object.startFrame = info->rootObject.startFrame;
1467 object.endFrame = info->rootObject.endFrame;
1470 Logf("Object not found while loading animation frame: %s\n", block.name);*/
1476 ObjectInfoBlock block { };
1479 ReadChunks(ReadFrameInfoBlock, info, &block);
1481 if(block.dummyName && block.dummyName[0])
1483 if(!strcmp(block.name, "$$$DUMMY"))
1485 object = Object { };
1486 object.name = block.dummyName;
1487 info->rootObject.children.AddName(object);
1488 object.transform.scaling = { 1, 1, 1 };
1489 object.flags.camera = true;
1493 Object model = info->rootObject.Find(block.name);
1496 object = Object { };
1497 object.name = new char[strlen(block.dummyName) + strlen(model.name) + 2];
1498 sprintf(object.name, "%s.%s", model.name, block.dummyName);
1499 object.flags = model.flags;
1500 object.flags.ownMesh = false;
1501 object.camera = model.camera;
1502 object.flags.camera = true;
1503 info->rootObject.children.AddName(object);
1505 delete block.dummyName;
1507 object.parent = info->rootObject;
1510 object = info->rootObject.Find(block.name);
1514 object.flags.hierarchy = block.hierarchy + 1;
1515 if(block.parent != -1)
1517 Object parent = FindObjectID(info->rootObject, block.parent + 1);
1520 object.parent.children.Remove(object);
1521 parent.children.AddName(object);
1522 object.parent = parent;
1525 object.pivot.x = block.pivot.x;
1526 object.pivot.y =-block.pivot.z;
1527 object.pivot.z = block.pivot.y;
1529 object.tracks = block.tracks;
1530 *&(object.frame) = object.startFrame = info->rootObject.startFrame;
1531 object.endFrame = info->rootObject.endFrame;
1534 Logf("Object not found while loading animation frame: %s\n", block.name);*/
1538 case FRM_CAMERATARGET:
1540 ObjectInfoBlock block { };
1542 char targetName[MAXNAMELEN];
1544 ReadChunks(ReadFrameInfoBlock, info, &block);
1546 strcpy(targetName, block.name);
1547 strcat(targetName, ".target");
1549 if(block.dummyName && block.dummyName[0])
1551 if(!strcmp(block.name, "$$$DUMMY"))
1553 object = Object { };
1554 object.name = block.dummyName;
1555 info->rootObject.children.AddName(object);
1556 object.transform.scaling = { 1,1,1 };
1560 Object model = info->rootObject.Find(targetName);
1563 object = Object { };
1564 object.name = new char[strlen(block.dummyName) + strlen(model.name) + 2];
1565 sprintf(object.name, "%s.%s", model.name, block.dummyName);
1566 object.flags = model.flags;
1567 object.flags.ownMesh = false;
1568 object.camera = model.camera;
1569 info->rootObject.children.AddName(object);
1571 delete block.dummyName;
1573 object.parent = info->rootObject;
1576 object = info->rootObject.Find(targetName);
1580 object.flags.hierarchy = block.hierarchy + 1;
1581 if(block.parent != -1)
1583 Object parent = FindObjectID(info->rootObject, block.parent + 1);
1586 object.parent.children.Remove(object);
1587 parent.children.AddName(object);
1588 object.parent = parent;
1591 object.pivot.x = block.pivot.x;
1592 object.pivot.y =-block.pivot.z;
1593 object.pivot.z = block.pivot.y;
1595 object.tracks = block.tracks;
1596 *&(object.frame) = object.startFrame = info->rootObject.startFrame;
1597 object.endFrame = info->rootObject.endFrame;
1600 Logf("Object not found while loading animation frame: %s\n", block.name);*/
1606 ObjectInfoBlock block { };
1608 ReadChunks(ReadFrameInfoBlock, info, &block);
1610 info->rootObject.tracks = block.tracks;
1616 ObjectInfoBlock block { };
1619 ReadChunks(ReadFrameInfoBlock, info, &block);
1621 if(block.dummyName && block.dummyName[0])
1623 if(!strcmp(block.name, "$$$DUMMY"))
1625 object = Object { };
1626 object.name = block.dummyName;
1627 info->rootObject.children.AddName(object);
1628 object.transform.scaling = { 1, 1, 1 };
1629 object.flags.light = true;
1633 Object model = info->rootObject.Find(block.name);
1636 object = Object { };
1637 object.name = new char[strlen(block.dummyName) + strlen(model.name) + 2];
1638 sprintf(object.name, "%s.%s", model.name, block.dummyName);
1639 object.flags = model.flags;
1640 object.flags.ownMesh = false;
1641 object.light = model.light;
1642 object.flags.light = true;
1643 info->rootObject.children.AddName(object);
1645 delete block.dummyName;
1647 object.parent = info->rootObject;
1650 object = info->rootObject.Find(block.name);
1654 object.flags.hierarchy = block.hierarchy + 1;
1655 if(block.parent != -1)
1657 Object parent = FindObjectID(info->rootObject, block.parent + 1);
1660 object.parent.children.Remove(object);
1661 parent.children.AddName(object);
1662 object.parent = parent;
1665 object.pivot.x = block.pivot.x;
1666 object.pivot.y =-block.pivot.z;
1667 object.pivot.z = block.pivot.y;
1669 object.tracks = block.tracks;
1670 *&(object.frame) = object.startFrame = info->rootObject.startFrame;
1671 object.endFrame = info->rootObject.endFrame;
1674 Logf("Object not found while loading animation frame: %s\n", block.name);*/
1678 case FRM_SPOTLIGHTTARGET:
1680 ObjectInfoBlock block { };
1682 char targetName[MAXNAMELEN];
1684 ReadChunks(ReadFrameInfoBlock, info, &block);
1686 strcpy(targetName, block.name);
1687 strcat(targetName, ".target");
1689 if(block.dummyName && block.dummyName[0])
1691 if(!strcmp(block.name, "$$$DUMMY"))
1693 object = Object { };
1694 object.name = block.dummyName;
1695 info->rootObject.children.AddName(object);
1696 object.transform.scaling = { 1,1,1 };
1700 Object model = info->rootObject.Find(targetName);
1703 object = Object { };
1704 object.name = new char[strlen(block.dummyName) + strlen(model.name) + 2];
1705 sprintf(object.name, "%s.%s", model.name, block.dummyName);
1706 object.flags = model.flags;
1707 object.flags.ownMesh = false;
1708 object.light = model.light;
1709 info->rootObject.children.AddName(object);
1711 delete block.dummyName;
1713 object.parent = info->rootObject;
1716 object = info->rootObject.Find(targetName);
1720 object.flags.hierarchy = block.hierarchy + 1;
1721 if(block.parent != -1)
1723 Object parent = FindObjectID(info->rootObject, block.parent + 1);
1726 object.parent.children.Remove(object);
1727 parent.children.AddName(object);
1728 object.parent = parent;
1731 object.pivot.x = block.pivot.x;
1732 object.pivot.y =-block.pivot.z;
1733 object.pivot.z = block.pivot.y;
1735 object.tracks = block.tracks;
1736 *&(object.frame) = object.startFrame = info->rootObject.startFrame;
1737 object.endFrame = info->rootObject.endFrame;
1740 Logf("Object not found while loading animation frame: %s\n", block.name);*/
1746 info->rootObject.startFrame = ReadDWORD(info->f);
1747 info->rootObject.endFrame = ReadDWORD(info->f);
1748 *&(info->rootObject.frame) = info->rootObject.startFrame;
1756 static bool ReadMainChunks(FileInfo * info, void * data)
1758 switch(info->chunkId)
1761 ReadChunks(ReadEditChunks, info, null);
1765 Object object = data;
1766 if(!(object.flags.keysLoaded)) // Don't read key frames on reload
1768 ReadChunks(ReadKeyFrameChunks, info, null);
1769 object.flags.keysLoaded = true;
1777 static bool ReadMain(FileInfo * info, void * data)
1779 switch(info->chunkId)
1782 ReadChunks(ReadMainChunks, info, data);
1788 class Object3DSFormat : ObjectFormat
1790 class_property(extension) = "3ds";
1792 bool Load(Object object, char * fileName, DisplaySystem displaySystem)
1794 bool result = false;
1797 FileInfo info = {0};
1798 info.rootObject = object;
1799 info.displaySystem = displaySystem;
1802 StripLastDirectory(fileName, info.textureDirectory);
1803 info.f = FileOpen(fileName, read);
1806 if(ReadChunks(ReadMain, &info, object) && info.rootObject.children.first)
1808 object.Animate(object.frame);
1809 object.flags.root = true;
1810 object.SetMinMaxRadius(true);
1817 object.Free(displaySystem);