import "Object"
+#if defined(__EMSCRIPTEN__)
+#if !defined(_GLES2)
+#define _GLES2
+#endif
+#endif
+
+#if (defined(__ANDROID__) || defined(__ODROID__)) && !defined(_GLES)
+#define _GLES
+#endif
+
+#if !defined(_GLES) && !defined(_GLES2)
+#define USE_32_BIT_INDICES true
+#define indicesMember indices32
+#define uintindex uint32
+#else
+#define USE_32_BIT_INDICES false
+#define indicesMember indices
+#define uintindex uint16
+#endif
+
#define MAXNAMELEN 64
-// RGB Chunks
-#define RGB_FLOAT 0x0010
-#define RGB_BYTE 0x0011
-#define RGB_BYTE_GAMMA 0x0012
-#define RGB_FLOAT_GAMMA 0x0013
-
-// Amount Of Chunks
-#define AMOUNT_OF 0x0030
-
-#define MAIN3DS 0x4D4D
-#define EDIT3DS 0x3D3D
-#define EDIT_AMBIENT 0x2100
-#define EDIT_MATERIAL 0xAFFF
-#define EDIT_OBJECT 0x4000
-#define OBJ_HIDDEN 0x4010
-#define OBJ_TRIMESH 0x4100
-#define OBJ_LIGHT 0x4600
-#define OBJ_CAMERA 0x4700
-
-// Triangular Mesh Chunks
-#define TRI_VERTEXL 0x4110
-#define TRI_FACEL1 0x4120
-#define TRI_MATERIAL 0x4130
-#define TRI_MAPPINGCOORS 0x4140
-#define TRI_SMOOTHING 0x4150
-#define TRI_LOCAL 0x4160
-
-// Light Chunks
-#define LIT_SPOT 0x4610
-#define LIT_ONOFF 0x4620
-#define LIT_ATTENUATION 0x4625
-#define LIT_START 0x4659
-#define LIT_END 0x465A
-#define LIT_MULTIPLIER 0x465B
-
-// Camera Chunks
-#define CAM_SEECONE 0x4710
-#define CAM_RANGES 0x4720
-
-// Material Chunks
-#define MAT_NAME 0xA000
-#define MAT_AMBIENT 0xA010
-#define MAT_DIFFUSE 0xA020
-#define MAT_SPECULAR 0xA030
-#define MAT_SHININESS 0xA040
-#define MAT_SHINSTRENGTH 0xA041
-#define MAT_SHIN3PC 0xA042
-#define MAT_TRANSPARENCY 0xA050
-#define MAT_XPFALL 0xA052
-#define MAT_REFBLUR 0xA053
-#define MAT_SELFILLUM 0xA080
-#define MAT_DOUBLESIDED 0xA081
-#define MAT_ADDITIVE 0xA083
-#define MAT_SELFILPCT 0xA084
-#define MAT_WIRE 0xA085
-#define MAT_SUPERSMP 0xA086
-#define MAT_WIRETHICKNESS 0xA087
-#define MAT_FACEMAP 0xA088
-#define MAT_XPFALLIN 0xA08A
-#define MAT_PHONG 0xA08C
-#define MAT_WIREABS 0xA08E
-#define MAT_SHADING 0xA100
-#define MAT_MAPTEXTURE1 0xA200
-#define MAT_SPECULARMAP 0xA204
-#define MAT_MAPOPACITY 0xA210
-#define MAT_REFLECTIONMAP 0xA220
-#define MAT_BUMPMAP 0xA230
-
-// Map Chunks
-#define MAP_FILENAME 0xA300
-
-#define MAT_SHININESSMAP 0xA33C
-#define MAT_EMISSIVEMAP 0xA33D
-#define MAP_OPTIONS 0xA351
-#define MAP_1_U_SCALE 0xA354
-#define MAP_1_V_SCALE 0xA356
-#define MAP_U_OFFSET 0xA358
-#define MAP_V_OFFSET 0xA35A
-#define MAP_ROTATION 0xA35C
-
-#define MAP_OPTIONS_DECAL 0x0001 // (related to MAP_OPTIONS_DONTTILE)
-#define MAP_OPTIONS_MIRROR 0x0002
-#define MAP_OPTIONS_NEGATIVE 0x0008
-#define MAP_OPTIONS_DONTTILE 0x0010
-#define MAP_OPTIONS_SUMMEDFILTERING 0x0020
-#define MAP_OPTIONS_USEALPHA 0x0040
-#define MAP_OPTIONS_LUMORALPHATINT 0x0080
-#define MAP_OPTIONS_IGNOREALPHA 0x0100
-#define MAP_OPTIONS_RGBTINT 0x0200
-
-#define MAP_FILTERBLUR 0xA353
-#define MAP_1_U_SCALE 0xA354
-#define MAP_1_V_SCALE 0xA356
-#define MAP_U_OFFSET 0xA358
-#define MAP_V_OFFSET 0xA35A
-#define MAP_ROTATION 0xA35C
-
-#define MAP_LUMTINT1 0xA360
-#define MAP_LUMTINT2 0xA362
-
-#define MAP_TINTR 0xA364
-#define MAP_TINTG 0xA366
-#define MAP_TINTB 0xA368
-
-// Keyframer Chunks
-#define KEYFRAME3DS 0xB000
-#define FRM_AMBIENT 0xB001
-#define FRM_MESHINFO 0xB002
-#define FRM_CAMERA 0xB003
-#define FRM_CAMERATARGET 0xB004
-#define FRM_OMNILIGHT 0xB005
-#define FRM_SPOTLIGHTTARGET 0xB006
-#define FRM_SPOTLIGHT 0xB007
-#define FRM_FRAMES 0xB008
-#define FRM_PARAM 0xB010
-#define FRM_DUMMYNAME 0xB011
-#define FRM_PIVOT 0xB013
-#define FRM_TRACKPOS 0xB020
-#define FRM_TRACKROT 0xB021
-#define FRM_TRACKSCALE 0xB022
-#define FRM_TRACKFOV 0xB023
-#define FRM_TRACKROLL 0xB024
-#define FRM_TRACKCOLOR 0xB025
-#define FRM_TRACKMORPH 0xB026 // What does this do?
-#define FRM_TRACKHOTSPOT 0xB027
-#define FRM_TRACKFALLOFF 0xB028
-#define FRM_TRACKHIDE 0xB029
-#define FRM_HIERARCHY 0xB030
+static enum ChunkID3DS : uint16
+{
+ // RGB Chunks
+ RGB_FLOAT = 0x0010,
+ RGB_BYTE = 0x0011,
+ RGB_BYTE_GAMMA = 0x0012,
+ RGB_FLOAT_GAMMA = 0x0013,
+
+ // Amount Of Chunks
+ AMOUNT_OF = 0x0030,
+
+ MAIN3DS = 0x4D4D,
+ EDIT3DS = 0x3D3D,
+ EDIT_AMBIENT = 0x2100,
+ EDIT_MATERIAL = 0xAFFF,
+ EDIT_OBJECT = 0x4000,
+ OBJ_HIDDEN = 0x4010,
+ OBJ_TRIMESH = 0x4100,
+ OBJ_LIGHT = 0x4600,
+ OBJ_CAMERA = 0x4700,
+
+ // Triangular Mesh Chunks
+ TRI_VERTEXL = 0x4110,
+ TRI_FACEL1 = 0x4120,
+ TRI_MATERIAL = 0x4130,
+ TRI_MAPPINGCOORS = 0x4140,
+ TRI_SMOOTHING = 0x4150,
+ TRI_LOCAL = 0x4160,
+
+ // Light Chunks
+ LIT_SPOT = 0x4610,
+ LIT_ONOFF = 0x4620,
+ LIT_ATTENUATION = 0x4625,
+ LIT_START = 0x4659,
+ LIT_END = 0x465A,
+ LIT_MULTIPLIER = 0x465B,
+
+ // Camera Chunks
+ CAM_SEECONE = 0x4710,
+ CAM_RANGES = 0x4720,
+
+ // Material Chunks
+ MAT_NAME = 0xA000,
+ MAT_AMBIENT = 0xA010,
+ MAT_DIFFUSE = 0xA020,
+ MAT_SPECULAR = 0xA030,
+ MAT_SHININESS = 0xA040,
+ MAT_SHINSTRENGTH = 0xA041,
+ MAT_SHIN3PC = 0xA042,
+ MAT_TRANSPARENCY = 0xA050,
+ MAT_XPFALL = 0xA052,
+ MAT_REFBLUR = 0xA053,
+ MAT_SELFILLUM = 0xA080,
+ MAT_DOUBLESIDED = 0xA081,
+ MAT_ADDITIVE = 0xA083,
+ MAT_SELFILPCT = 0xA084,
+ MAT_WIRE = 0xA085,
+ MAT_SUPERSMP = 0xA086,
+ MAT_WIRETHICKNESS = 0xA087,
+ MAT_FACEMAP = 0xA088,
+ MAT_XPFALLIN = 0xA08A,
+ MAT_PHONG = 0xA08C,
+ MAT_WIREABS = 0xA08E,
+ MAT_SHADING = 0xA100,
+ MAT_MAPTEXTURE1 = 0xA200,
+ MAT_SPECULARMAP = 0xA204,
+ MAT_MAPOPACITY = 0xA210,
+ MAT_REFLECTIONMAP = 0xA220,
+ MAT_BUMPMAP = 0xA230,
+
+ // Map Chunks
+ MAP_FILENAME = 0xA300,
+
+ MAT_SHININESSMAP = 0xA33C,
+ MAT_EMISSIVEMAP = 0xA33D,
+
+ MAP_OPTIONS = 0xA351,
+ MAP_1_U_SCALE = 0xA354,
+ MAP_1_V_SCALE = 0xA356,
+ MAP_U_OFFSET = 0xA358,
+ MAP_V_OFFSET = 0xA35A,
+ MAP_ROTATION = 0xA35C,
+
+ MAP_FILTERBLUR = 0xA353,
+ MAP_1_U_SCALE = 0xA354,
+ MAP_1_V_SCALE = 0xA356,
+ MAP_U_OFFSET = 0xA358,
+ MAP_V_OFFSET = 0xA35A,
+ MAP_ROTATION = 0xA35C,
+
+ MAP_LUMTINT1 = 0xA360,
+ MAP_LUMTINT2 = 0xA362,
+
+ MAP_TINTR = 0xA364,
+ MAP_TINTG = 0xA366,
+ MAP_TINTB = 0xA368,
+
+ // Keyframer Chunks
+ KEYFRAME3DS = 0xB000,
+ FRM_AMBIENT = 0xB001,
+ FRM_MESHINFO = 0xB002,
+ FRM_CAMERA = 0xB003,
+ FRM_CAMERATARGET = 0xB004,
+ FRM_OMNILIGHT = 0xB005,
+ FRM_SPOTLIGHTTARGET = 0xB006,
+ FRM_SPOTLIGHT = 0xB007,
+ FRM_FRAMES = 0xB008,
+ FRM_PARAM = 0xB010,
+ FRM_DUMMYNAME = 0xB011,
+ FRM_PIVOT = 0xB013,
+ FRM_TRACKPOS = 0xB020,
+ FRM_TRACKROT = 0xB021,
+ FRM_TRACKSCALE = 0xB022,
+ FRM_TRACKFOV = 0xB023,
+ FRM_TRACKROLL = 0xB024,
+ FRM_TRACKCOLOR = 0xB025,
+ FRM_TRACKMORPH = 0xB026, // What does this do?
+ FRM_TRACKHOTSPOT = 0xB027,
+ FRM_TRACKFALLOFF = 0xB028,
+ FRM_TRACKHIDE = 0xB029,
+ FRM_HIERARCHY = 0xB030
+};
+
+static class MapOptions : uint32
+{
+ bool decal:1; // (related to dontTile)
+ bool mirror:1;
+ bool negative:1;
+ bool dontTile:1;
+ bool summedFiltering:1;
+ bool useAlpha:1;
+ bool lumOrAlphaTint:1;
+ bool ignoreAlpha:1;
+ bool rgbTint:1;
+};
typedef struct FileInfo FileInfo;
typedef struct
{
- uint16 indices[3];
- uint16 oldIndices[3];
+ uint indices[3];
+ uint origIndices[3];
uint smoothGroups;
+ Material material;
+ Vector3Df normal;
bool done:1;
} Face;
-struct FileInfo
+static struct FileInfo
{
File f;
DisplaySystem displaySystem;
Object rootObject;
+ const String fileName;
- uint16 chunkId;
+ ChunkID3DS chunkId;
uint pos, end;
FileInfo * parent;
int nFaces;
Face * faces;
char textureDirectory[MAX_DIRECTORY];
+ Map<uintptr, Array<int>> matFaces;
};
#define SWAP_WORD(word) (((unsigned short)(word) & 0x00ff) << 8) \
childInfo.parent = info;
info->f.Seek(info->pos, start);
- childInfo.chunkId = ReadWORD(info->f);
+ childInfo.chunkId = (ChunkID3DS)ReadWORD(info->f);
length = ReadDWORD(info->f);
childInfo.pos += sizeof(uint16) + sizeof(uint);
if(info->chunkId == RGB_BYTE || info->chunkId == RGB_BYTE_GAMMA)
{
byte value;
- info->f.Getc(&value); rgb->r = value / 255.0f;
- info->f.Getc(&value); rgb->g = value / 255.0f;
- info->f.Getc(&value); rgb->b = value / 255.0f;
+ info->f.Getc((char *)&value); rgb->r = value / 255.0f;
+ info->f.Getc((char *)&value); rgb->g = value / 255.0f;
+ info->f.Getc((char *)&value); rgb->b = value / 255.0f;
}
else if(info->chunkId == RGB_FLOAT || info->chunkId == RGB_FLOAT_GAMMA)
{
return true;
}
-typedef struct
+#define WELD_TRESHOLD 0.000001
+#define SMOOTH_CUTOFF 0 // 45
+
+struct SharedSourceVertexInfo
{
- uint smoothGroups;
int index;
-} VertexConfig;
+ Vector3Df value;
+ uint unique;
+ Face * face;
-typedef struct
+ int OnCompare(SharedSourceVertexInfo b)
+ {
+ if(unique < b.unique) return -1;
+ if(unique > b.unique) return 1;
+
+ if(unique)
+ {
+ if(face < b.face) return -1;
+ if(face > b.face) return 1;
+ }
+ if(index == b.index) return 0;
+ if(WELD_TRESHOLD)
+ {
+ if(value.x < b.value.x - WELD_TRESHOLD) return -1;
+ if(value.x > b.value.x + WELD_TRESHOLD) return 1;
+ if(value.y < b.value.y - WELD_TRESHOLD) return -1;
+ if(value.y > b.value.y + WELD_TRESHOLD) return 1;
+ if(value.z < b.value.z - WELD_TRESHOLD) return -1;
+ if(value.z > b.value.z + WELD_TRESHOLD) return 1;
+ }
+ else
+ {
+ if(index < b.index) return -1;
+ if(index > b.index) return 1;
+ }
+ return 0;
+ }
+};
+
+class SharedDestVertexInfo
+{
+ Array<int> faces { };
+};
+
+struct SourceVertexInfo
+{
+ SharedSourceVertexInfo * shared;
+ Pointf texCoord;
+ uint smoothGroups;
+
+ int OnCompare(SourceVertexInfo b)
+ {
+ int r = (*shared).OnCompare(*b.shared);
+ if(!r) r = texCoord.OnCompare(b.texCoord);
+ if(!r) r = smoothGroups.OnCompare(b.smoothGroups);
+ return r;
+ }
+};
+
+class DestVertexInfo
{
- int numConfig;
- VertexConfig * config;
-} VertexConfigList;
+ int index, copyFromIndex;
+ Vector3Df normal;
+};
static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
{
int c;
Face * faces = info->faces;
- //int nFaces = info->nFaces;
int nVertices = mesh.nVertices;
int index;
int nNewVertices;
- int * numShared;
+ Vector3Df * mVertices;
+ double cutOff = cos(Degrees { SMOOTH_CUTOFF });
+
+ Map<SharedSourceVertexInfo, SharedDestVertexInfo> sharedVertices { };
+ Map<SourceVertexInfo, DestVertexInfo> vertexMap { };
+ Array<MapNode<SourceVertexInfo, DestVertexInfo>> vertices { size = nVertices };
- VertexConfigList * configLists = new0 VertexConfigList[nVertices];
+ MapIterator<SharedSourceVertexInfo, SharedDestVertexInfo> itShared { map = sharedVertices };
+ MapIterator<SourceVertexInfo, DestVertexInfo> it { map = vertexMap };
nNewVertices = nVertices;
+ mVertices = mesh->vertices;
+
for(c = 0; c<info->nFaces; c++)
{
Face * face = &faces[c];
+ Plane plane;
+ plane.FromPointsf(mesh.vertices[face->indices[2]],
+ mesh.vertices[face->indices[1]],
+ mesh.vertices[face->indices[0]]);
+ face->normal = { (float)plane.normal.x, (float)plane.normal.y, (float)plane.normal.z };
+ }
+
+ for(c = 0; c < info->nFaces; c++)
+ {
+ Face * face = &faces[c];
int i;
+ // Zero space points
+ if(!mVertices[face->indices[0]].OnCompare(mVertices[face->indices[1]]) &&
+ !mVertices[face->indices[0]].OnCompare(mVertices[face->indices[2]]))
+ continue;
+
for(i = 0; i<3; i++)
{
- int index = face->indices[i];
- int v;
- VertexConfigList * configList = &configLists[index];
- VertexConfig * config = null;
- for(v = 0; v<configList->numConfig; v++)
+ SharedSourceVertexInfo * source;
+ SharedDestVertexInfo svInfo;
+ DestVertexInfo vInfo;
+
+ index = face->indices[i];
+
+ if(face->smoothGroups)
+ itShared.Index({ index = index, mVertices[index], face = face }, true);
+ else
+ itShared.Index({ index = index, { }, unique = index + 1, face = face }, true);
+ svInfo = itShared.data;
+ if(!svInfo) itShared.data = svInfo = { };
+ svInfo.faces.Add(c);
+
+ source = (SharedSourceVertexInfo *)&(((AVLNode)itShared.pointer).key);
+ // TODO: Allow obtaining address of MapIterator::key
+ // it.Index({ &itShared.key, mesh->texCoords[index] }, true);
+ it.Index({ source, mesh->texCoords ? mesh->texCoords[index] : { }, face->smoothGroups }, true);
+ vInfo = it.data;
+ if(!vInfo)
{
- uint smoothGroups = configList->config[v].smoothGroups;
- if(smoothGroups == face->smoothGroups)
- {
- config = &configList->config[v];
- break;
- }
- else if(smoothGroups && face->smoothGroups)
+ vInfo = { };
+ it.data = vInfo;
+ vInfo.copyFromIndex = index;
+ vInfo.index = index;
+ }
+
+ if(!vertices[index])
+ vertices[index] = (void *)it.pointer;
+ else if(vertices[index] != it.pointer)
+ {
+ // If it's a different smoothing group, we'll need extra vertices
+ index = vertices.size;
+ vInfo.index = index;
+ vertices.Add((void *)it.pointer);
+ nNewVertices++;
+ }
+ face->indices[i] = vInfo.index;
+ }
+ }
+
+ for(index = 0; index < nNewVertices; index++)
+ {
+ int numShared = 0;
+ it.pointer = vertices[index];
+ if(it.pointer)
+ {
+ DestVertexInfo vInfo = it.data;
+ Vector3Df normal { };
+ SourceVertexInfo * inf = (SourceVertexInfo *)&(((AVLNode)it.pointer).key);
+ uint smoothing = inf->smoothGroups;
+ bool added = true;
+ SharedSourceVertexInfo * shared = inf->shared;
+ SharedDestVertexInfo svInfo = sharedVertices[*shared];
+ int origIndex;
+ if(!svInfo || vInfo.index != index)
+ continue;
+
+ for(i : svInfo.faces)
+ {
+ Face * face = &info->faces[i];
+ face->done = false;
+ if(smoothing & face->smoothGroups)
+ smoothing |= face->smoothGroups;
+ }
+
+ // Optional code to compensate auto-welding with a limit angle cutoff between faces of same smoothing group
+ if(SMOOTH_CUTOFF && WELD_TRESHOLD)
+ {
+ for(i : svInfo.faces)
{
- int g;
- for(g = 0; g<32; g++)
- if(smoothGroups & (1<<g) && face->smoothGroups & (1<<g))
+ Face * face = &info->faces[i];
+ if((smoothing & face->smoothGroups) || (!smoothing && !face->smoothGroups))
+ {
+ int j;
+ for(j = 0; j < 3; j++)
{
- config = &configList->config[v];
- config->smoothGroups |= face->smoothGroups;
- break;
+ if(face->indices[j] == vInfo.index)
+ {
+ origIndex = face->origIndices[j];
+ face->done = true;
+ normal.x += face->normal.x;
+ normal.y += face->normal.y;
+ normal.z += face->normal.z;
+ numShared++;
+ break;
+ }
}
+ }
+ if(numShared) break;
}
}
- if(!config || !face->smoothGroups)
+ while(added)
{
- // Duplicate the vertex and make the face use it
- if(configList->numConfig)
- index = nNewVertices++;
- face->indices[i] = (uint16)index;
- if(!config)
+ added = false;
+ for(i : svInfo.faces)
{
- configList->config = renew configList->config VertexConfig[configList->numConfig + 1];
- config = &configList->config[configList->numConfig++];
- config->index = index;
- config->smoothGroups = face->smoothGroups;
+ Face * face = &info->faces[i];
+ if(!face->done && ((smoothing & face->smoothGroups) || (!smoothing && !face->smoothGroups)))
+ {
+ bool valid = true;
+
+ if(SMOOTH_CUTOFF && WELD_TRESHOLD)
+ {
+ int origIndexB = -1;
+ int k;
+
+ for(k = 0; k < 3; k++)
+ {
+ if(face->indices[k] == vInfo.index)
+ {
+ origIndexB = face->origIndices[k];
+ break;
+ }
+ }
+ valid = origIndex == origIndexB;
+ if(!valid)
+ {
+ for(j : svInfo.faces)
+ {
+ if(info->faces[j].done)
+ {
+ double dot = info->faces[j].normal.DotProduct(face->normal);
+ if(dot > 1) dot = 1; else if(dot < -1) dot = -1;
+ valid = fabs(dot) > cutOff;
+ if(valid) break;
+ }
+ }
+ }
+ }
+
+ if(valid)
+ {
+ normal.x += face->normal.x;
+ normal.y += face->normal.y;
+ normal.z += face->normal.z;
+ numShared++;
+ added = true;
+ face->done = true;
+ }
+ }
}
+ if(!SMOOTH_CUTOFF || !WELD_TRESHOLD) break;
}
- else
+ normal.Scale(normal, 1.0f / numShared);
+ if(vInfo.index == index)
+ vInfo.normal.Normalize(normal);
+
+ // Auto welding/smoothing requires extra vertices because angle is too steep
+ if(SMOOTH_CUTOFF && WELD_TRESHOLD)
{
- face->indices[i] = (uint16)config->index;
+ SharedDestVertexInfo newSharedInfo = null;
+ int index;
+ for(i : svInfo.faces)
+ {
+ Face * face = &info->faces[i];
+ if(!face->done && ((smoothing & face->smoothGroups) || (!smoothing && !face->smoothGroups)))
+ {
+ int j;
+ for(j = 0; j < 3; j++)
+ {
+ if(face->indices[j] == vInfo.index)
+ {
+ if(!newSharedInfo)
+ {
+ DestVertexInfo newVert;
+ SharedSourceVertexInfo * source;
+
+ index = nNewVertices++;
+ itShared.Index({ index = index, { }, unique = index + 1, face = face }, true);
+ source = (SharedSourceVertexInfo *)&(((AVLNode)itShared.pointer).key);
+ itShared.data = newSharedInfo = { };
+
+ it.Index({ source, mesh->texCoords ? mesh->texCoords[vInfo.copyFromIndex] : { }, face->smoothGroups }, true);
+ newVert = { };
+ it.data = newVert;
+ newVert.copyFromIndex = vInfo.copyFromIndex;
+ newVert.index = index;
+
+ vertices.Add((void *)it.pointer);
+ }
+ face->indices[j] = index;
+ newSharedInfo.faces.Add(i);
+ break;
+ }
+ }
+ }
+ }
}
}
}
Vector3Df * oldVertices = mesh.vertices;
Pointf * oldTexCoords = mesh.texCoords;
+ // TODO: Support reallocation?
*((void **)&mesh.vertices) = null;
*((void **)&mesh.texCoords) = null;
*((int *)&mesh.nVertices) = 0;
mesh.Allocate( { vertices = true, normals = true, texCoords1 = oldTexCoords ? true : false }, nNewVertices, info->displaySystem);
// Fill in the new vertices
- for(index = 0; index<nVertices; index++)
+ for(index = 0; index < nNewVertices; index++)
{
- int v;
- VertexConfigList * configList = &configLists[index];
- for(v = 0; v<configList->numConfig; v++)
- {
- VertexConfig * config = &configList->config[v];
- Vector3Df * normal;
- if(config->smoothGroups)
- {
- //if(v > 0)
- {
- // Duplicate vertex
- mesh.vertices[config->index] = oldVertices[index]; //mesh.vertices[index];
- if(mesh.texCoords)
- mesh.texCoords[config->index] = oldTexCoords[index]; //mesh.texCoords[index];
- }
- }
- else
- {
- mesh.vertices[config->index] = oldVertices[index];
- if(mesh.texCoords)
- mesh.texCoords[config->index] = oldTexCoords[index]; //mesh.texCoords[index];
- }
- normal = &mesh.normals[config->index];
- *normal = { 0,0,0 };
- }
+ DestVertexInfo vInfo;
+ it.pointer = vertices[index];
+ vInfo = it.data;
+
+ // Duplicate vertex
+ mesh.normals[index] = vInfo ? vInfo.normal : { };
+ mesh.vertices[index] = oldVertices[vInfo ? vInfo.copyFromIndex : index];
+ if(mesh.texCoords)
+ mesh.texCoords[index] = oldTexCoords[vInfo ? vInfo.copyFromIndex : index];
}
delete oldVertices;
delete oldTexCoords;
}
- numShared = new0 int[nNewVertices];
-
- for(c = 0; c<info->nFaces; c++)
{
- Face * face = &faces[c];
int i;
- Plane plane;
- Vector3Df planeNormal;
- plane.FromPointsf(mesh.vertices[face->oldIndices[2]],
- mesh.vertices[face->oldIndices[1]],
- mesh.vertices[face->oldIndices[0]]);
- planeNormal = { (float)plane.normal.x, (float)plane.normal.y, (float)plane.normal.z };
- if(face->smoothGroups)
- {
- for(i = 0; i<3; i++)
- {
- int index = face->indices[i];
- Vector3Df * normal = &mesh.normals[index];
- normal->Add(normal, planeNormal);
- numShared[index]++;
- }
- }
- else
- {
- for(i = 0; i<3; i++)
- {
- int index = face->oldIndices[i];
- int newIndex = face->indices[i];
- mesh.normals[newIndex] = planeNormal;
- // Duplicate vertex
- if(index != newIndex)
- {
- mesh.vertices[newIndex] = mesh.vertices[index];
- if(mesh.texCoords)
- mesh.texCoords[newIndex] = mesh.texCoords[index];
- }
- numShared[newIndex]++;
- }
- }
- }
- for(index = 0; index<nNewVertices; index++)
- {
- Vector3Df * normal = &mesh.normals[index];
- normal->Scale(normal, 1.0f / numShared[index]);
- normal->Normalize(normal);
+ for(i = 0; i < info->nFaces; i++)
+ info->faces[i].done = false;
}
mesh.Unlock({ normals = true });
// Free all the temporary stuff
- if(configLists)
- {
- for(index = 0; index < nVertices; index++)
- {
- VertexConfigList * configList = &configLists[index];
- if(configList->config) delete configList->config;
- }
- delete configLists;
- }
- delete numShared;
+
+ delete vertices;
+ vertexMap.Free();
+ delete vertexMap;
+ sharedVertices.Free();
+ delete sharedVertices;
}
// Meshes
static bool ReadSmoothing(FileInfo * info, Object object)
{
- Mesh mesh = object.mesh;
switch(info->chunkId)
{
case TRI_SMOOTHING:
static bool ReadFacesListChunks(FileInfo * info, Object object)
{
DisplaySystem displaySystem = info->displaySystem;
- Mesh mesh = object.mesh;
switch(info->chunkId)
{
case TRI_MATERIAL:
{
char * name;
Material mat;
+ int i, c;
+ int count;
+ Array<int> faces;
+ char matName[MAX_LOCATION + 100];
+ strcpy(matName, info->fileName);
ReadASCIIZ(info->f, &name);
- mat = displaySystem.GetMaterial(name);
- if(mat)
- {
- if(mat.flags.translucent)
- {
- int c;
- uint16 count = ReadWORD(info->f);
- mesh.primitives = renew mesh.primitives PrimitiveSingle[mesh.nPrimitives + count];
- for(c = 0; c<count; c++)
- {
- uint16 face = ReadWORD(info->f);
- PrimitiveSingle * triangle = &mesh.primitives[mesh.nPrimitives++];
+ count = ReadWORD(info->f);
+ strcat(matName, name);
- if(mesh.AllocatePrimitive(triangle, triangles, 3))
- {
- triangle->indices[0] = info->faces[face].indices[0];
- triangle->indices[1] = info->faces[face].indices[1];
- triangle->indices[2] = info->faces[face].indices[2];
- triangle->middle.Add(mesh.vertices[triangle->indices[0]], mesh.vertices[triangle->indices[1]]);
- triangle->middle.Add(triangle->middle, mesh.vertices[triangle->indices[2]]);
- triangle->plane.FromPointsf(
- mesh.vertices[triangle->indices[2]],
- mesh.vertices[triangle->indices[1]],
- mesh.vertices[triangle->indices[0]]);
+ mat = displaySystem.GetMaterial(matName);
+ faces = info->matFaces[(uintptr)mat];
+ if(!faces)
+ info->matFaces[(uintptr)mat] = faces = { };
+ i = faces.size;
+ faces.size += count;
- mesh.UnlockPrimitive(triangle);
- }
- triangle->middle.x /= 3;
- triangle->middle.y /= 3;
- triangle->middle.z /= 3;
-
- triangle->material = mat;
-
- info->faces[face].done = (byte)bool::true;
- }
- object.flags.translucent = true;
- }
- else
- {
- PrimitiveGroup group;
- uint16 count = ReadWORD(info->f);
- group = mesh.AddPrimitiveGroup(triangles, count * 3);
- if(group)
- {
- int c;
- group.material = mat;
- for(c = 0; c<count; c++)
- {
- uint16 face = ReadWORD(info->f);
- if(object.flags.flipWindings)
- {
- group.indices[c*3] = info->faces[face].indices[2];
- group.indices[c*3+1] = info->faces[face].indices[1];
- group.indices[c*3+2] = info->faces[face].indices[0];
- }
- else
- {
- group.indices[c*3] = info->faces[face].indices[0];
- group.indices[c*3+1] = info->faces[face].indices[1];
- group.indices[c*3+2] = info->faces[face].indices[2];
- }
- info->faces[face].done = (byte)bool::true;
- }
- mesh.UnlockPrimitiveGroup(group);
- }
- }
+ for(c = 0; c<count; c++)
+ {
+ uint16 face = ReadWORD(info->f);
+ faces[i + c] = face;
+ info->faces[face].material = mat;
}
delete name;
break;
{
int c;
uint16 nFaces = 0;
- int count;
+ uint count;
uint pos;
info->nFaces = nFaces = ReadWORD(info->f);
{
int i;
for(i = 0; i<3; i++)
- {
- info->faces[c].oldIndices[i] =
+ info->faces[c].origIndices[i] =
info->faces[c].indices[i] = ReadWORD(info->f);
- }
ReadWORD(info->f);
info->pos += 4*sizeof(uint16);
}
ReadChunks(ReadSmoothing, info, object);
info->pos = pos;
- ComputeNormals(mesh, info, object);
+ if(info->matFaces)
+ info->matFaces.Free();
+ info->matFaces = { };
ReadChunks(ReadFacesListChunks, info, object);
+ ComputeNormals(mesh, info, object);
+
+ // Create Groups
+ for(m : info->matFaces)
+ {
+ Material mat = (Material)&m;
+ Array<int> faces = m;
+ if(mat.flags.translucent)
+ {
+ mesh.primitives = renew mesh.primitives PrimitiveSingle[mesh.nPrimitives + faces.count];
+ for(i : faces)
+ {
+ Face * face = &info->faces[i];
+ PrimitiveSingle * triangle;
+
+ triangle = &mesh.primitives[mesh.nPrimitives++];
+ if(mesh.AllocatePrimitive(triangle, { triangles, indices32bit = USE_32_BIT_INDICES }, 3))
+ {
+ triangle->indicesMember[0] = (uintindex)face->indices[0];
+ triangle->indicesMember[1] = (uintindex)face->indices[1];
+ triangle->indicesMember[2] = (uintindex)face->indices[2];
+ triangle->middle.Add(mesh.vertices[triangle->indicesMember[0]], mesh.vertices[triangle->indicesMember[1]]);
+ triangle->middle.Add(triangle->middle, mesh.vertices[triangle->indicesMember[2]]);
+ triangle->plane.FromPointsf(
+ mesh.vertices[triangle->indicesMember[2]],
+ mesh.vertices[triangle->indicesMember[1]],
+ mesh.vertices[triangle->indicesMember[0]]);
+
+ mesh.UnlockPrimitive(triangle);
+ }
+ triangle->middle.x /= 3;
+ triangle->middle.y /= 3;
+ triangle->middle.z /= 3;
+
+ triangle->material = mat;
+
+ face->done = true;
+ object.flags.translucent = true;
+ }
+ }
+ else
+ {
+ PrimitiveGroup group = mesh.AddPrimitiveGroup({ triangles, indices32bit = USE_32_BIT_INDICES }, faces.count * 3);
+ if(group)
+ {
+ c = 0;
+ group.material = mat;
+ for(i : faces)
+ {
+ Face * face = &info->faces[i];
+
+ if(object.flags.flipWindings)
+ {
+ group.indicesMember[c*3] = (uintindex)face->indices[2];
+ group.indicesMember[c*3+1] = (uintindex)face->indices[1];
+ group.indicesMember[c*3+2] = (uintindex)face->indices[0];
+ }
+ else
+ {
+ group.indicesMember[c*3] = (uintindex)face->indices[0];
+ group.indicesMember[c*3+1] = (uintindex)face->indices[1];
+ group.indicesMember[c*3+2] = (uintindex)face->indices[2];
+ }
+ face->done = true;
+ c++;
+ }
+ mesh.UnlockPrimitiveGroup(group);
+ }
+ }
+ }
+
// Add faces without a material all together
count = 0;
for(c = 0; c<nFaces; c++)
count++;
if(count)
{
- PrimitiveGroup group = mesh.AddPrimitiveGroup(triangles, count * 3);
+ PrimitiveGroup group = mesh.AddPrimitiveGroup({ triangles, indices32bit = USE_32_BIT_INDICES }, count * 3);
if(group)
{
for(c = 0; c<nFaces; c++)
- if(!info->faces[c].done)
+ {
+ Face * face = &info->faces[c];
+ if(!face->done)
{
- group.indices[c*3] = info->faces[c].indices[0];
- group.indices[c*3+1] = info->faces[c].indices[1];
- group.indices[c*3+2] = info->faces[c].indices[2];
+ group.indicesMember[c*3] = (uintindex)face->indices[0];
+ group.indicesMember[c*3+1] = (uintindex)face->indices[1];
+ group.indicesMember[c*3+2] = (uintindex)face->indices[2];
}
+ }
mesh.UnlockPrimitiveGroup(group);
}
}
delete info->faces;
-
- /*
- mesh.ComputeNormals();
-
- if(object.flags.flipWindings)
+ if(info->matFaces)
{
- if(mesh.Lock({ normals = true }))
- {
- for(c = 0; c<mesh.nVertices; c++)
- {
- mesh.normals[c].x *= -1;
- mesh.normals[c].y *= -1;
- mesh.normals[c].z *= -1;
- }
- mesh.Unlock({ normals = true });
- }
- }*/
-
- // could use this instead? : mesh.ApplyTranslucency(object);
+ info->matFaces.Free();
+ delete info->matFaces;
+ }
break;
}
case TRI_LOCAL:
char location[MAX_LOCATION];
ReadASCIIZ(info->f, &name);
- strlwr(name);
strcpy(location, info->textureDirectory);
PathCat(location, name);
+ if(!FileExists(location))
+ {
+ // Attempt all lowercase if original case does not exist
+ strlwr(name);
+ strcpy(location, info->textureDirectory);
+ PathCat(location, name);
+ }
if(info->parent->chunkId == MAT_BUMPMAP)
{
- mat.bumpMap = displaySystem.GetTexture(name);
+ // To avoid messing up the diffuse texture if same bitmap is specified by mistake...
+ char bumpName[MAX_LOCATION+5];
+ strcpy(bumpName, "BUMP:");
+ strcat(bumpName, location);
if(!mat.bumpMap)
{
- mat.bumpMap = Bitmap { };
- if(!mat.bumpMap.Load(location, null, null) ||
- !mat.bumpMap.Convert(null, pixelFormat888, null) ||
- !displaySystem.AddTexture(name, mat.bumpMap))
- delete mat.bumpMap;
- }
- if(mat.bumpMap)
- {
- ColorAlpha * picture = (ColorAlpha *)mat.bumpMap.picture;
- int bw = mat.bumpMap.width, bh = mat.bumpMap.height;
- int y, x;
-
- for(y = 0; y < bh; y++)
- for(x = 0; x < bw; x++)
+ mat.bumpMap = displaySystem.GetTexture(bumpName);
+ if(!mat.bumpMap)
+ {
+ mat.bumpMap = Bitmap { };
+ if(!mat.bumpMap.Load(location, null, null) ||
+ !mat.bumpMap.Convert(null, pixelFormat888, null) ||
+ !displaySystem.AddTexture(bumpName, mat.bumpMap))
+ delete mat.bumpMap;
+ if(mat.bumpMap)
{
- uint bc = y * bw + x;
- Color color = picture[bc].color;
- picture[bc] = { 255, { color.r, 255 - color.b, color.g } };
+ ColorAlpha * picture = (ColorAlpha *)mat.bumpMap.picture;
+ int bw = mat.bumpMap.width, bh = mat.bumpMap.height;
+ int y, x;
+
+ for(y = 0; y < bh; y++)
+ for(x = 0; x < bw; x++)
+ {
+ uint bc = y * bw + x;
+ Color color = picture[bc].color;
+ picture[bc] = { 255, { color.r, 255 - color.b, color.g } };
+ }
}
+ }
}
}
else
bool translucent = false;
if(!mat.baseMap)
{
- mat.baseMap = displaySystem.GetTexture(name);
+ mat.baseMap = displaySystem.GetTexture(location);
if(!mat.baseMap)
{
mat.baseMap = Bitmap { };
if(!mat.baseMap.Load(location, null, null) ||
!mat.baseMap.Convert(null, pixelFormat888, null) ||
- !displaySystem.AddTexture(name, mat.baseMap))
+ !displaySystem.AddTexture(location, mat.baseMap))
{
delete mat.baseMap;
}
}
case MAP_OPTIONS:
{
- uint16 options = ReadWORD(info->f);
- if(!(options & MAP_OPTIONS_DONTTILE)) mat.flags.tile = true;
+ MapOptions options = (MapOptions)ReadWORD(info->f);
+ if(!options.dontTile) mat.flags.tile = true;
break;
}
case MAP_1_U_SCALE:
{
case MAT_NAME:
{
- ReadASCIIZ(info->f, &mat.name);
+ String name;
+ char matName[MAX_LOCATION + 100];
+ strcpy(matName, info->fileName);
+ ReadASCIIZ(info->f, &name);
+ strcat(matName, name);
+ mat.name = CopyString(matName);
+ delete name;
break;
}
case MAT_TRANSPARENCY:
// Lights
static bool ReadLight(FileInfo * info, Object object)
{
- Mesh mesh = object.mesh;
Light * light = &object.light;
switch(info->chunkId)
{
// Cameras
static bool ReadCamera(FileInfo * info, Object object)
{
- Mesh mesh = object.mesh;
switch(info->chunkId)
{
case CAM_SEECONE:
}
case CAM_RANGES:
{
- Camera camera = object.camera;
- float nearRange = ReadFloat(info->f);
- float farRange = ReadFloat(info->f);
+ //Camera camera = object.camera;
+ /*float nearRange = */ReadFloat(info->f);
+ /*float farRange = */ReadFloat(info->f);
/*
camera.zMin = Max(0.1, nearRange);
camera.zMax = farRange;
if(!object)
{
object = Object { };
- object.name = name;
+ object.name = CopyString(name);
info->rootObject.children.AddName(object);
object.parent = info->rootObject;
}
- else
- delete name;
object.InitializeMesh(displaySystem);
ReadChunks(ReadTriMesh, info, object);
object.flags.mesh = true;
if(!object)
{
object = Object { };
- object.name = name;
+ object.name = CopyString(name);
info->rootObject.children.AddName(object);
object.parent = info->rootObject;
}
- else
- delete name;
object.flags.light = true;
light = &object.light;
Object object = info->rootObject.Find(name);
Object target;
Camera camera;
- float bankAngle, focus;
+ float /*bankAngle, */focus;
double mm;
strcpy(targetName, name);
strcat(targetName, ".target");
+ target = info->rootObject.Find(targetName);
if(!object)
{
object = Object { };
- object.name = name;
+ object.name = CopyString(name);
info->rootObject.children.AddName(object);
object.parent = info->rootObject;
object.camera = Camera { };
object.camera.type = lookAtObject;
+ }
+ if(!target)
+ {
target = Object { };
target.name = CopyString(targetName);
info->rootObject.children.AddName(target);
target.parent = info->rootObject;
}
- else
- delete name;
object.flags.camera = true;
object.cameraTarget = target;
target.transform.position.y =-ReadFloat(info->f);
info->pos += sizeof(float) * 3;
- bankAngle = ReadFloat(info->f);
+ /*bankAngle = */ReadFloat(info->f);
info->pos += sizeof(float);
focus = ReadFloat(info->f);
info->pos += sizeof(float);
break;
}
case OBJ_HIDDEN: break;
- default:
- delete name;
}
return true;
}
}
case EDIT_MATERIAL:
{
- Material material { };
+ Material material { /*flags = { singleSideLight = true }*/ };
Material mat;
ReadChunks(ReadMaterial, info, material);
char * name;
info->pos += ReadASCIIZ(info->f, &name);
ReadChunks(ReadEditObject, info, name);
+ delete name;
break;
}
}
};
// Key Framer Chunks
-
-#define ACCFLAG_TENSION 0x00000001
-#define ACCFLAG_CONTINUITY 0x00000002
-#define ACCFLAG_BIAS 0x00000004
-#define ACCFLAG_EASETO 0x00000008
-#define ACCFLAG_EASEFROM 0x00000010
+static class AccelerationFlags : uint32
+{
+ bool tension:1, continuity:1, bias:1, easeTo:1, easeFrom:1;
+};
static bool ReadFrameInfoBlock(FileInfo * info, ObjectInfoBlock * block)
{
{
case FRM_PARAM:
{
- uint16 flags1, flags2;
+ //uint16 flags1, flags2;
ReadASCIIZ(info->f, &block->name);
- flags1 = ReadWORD(info->f);
- flags2 = ReadWORD(info->f);
+ /*flags1 = */ReadWORD(info->f);
+ /*flags2 = */ReadWORD(info->f);
block->parent = ReadWORD(info->f);
break;
}
track.keys = new0 FrameKey[track.numKeys];
for(c = 0; c<track.numKeys; c++)
{
- uint16 accelerationFlags;
+ AccelerationFlags accelerationFlags;
FrameKey * key = track.keys + c;
key->frame = ReadDWORD(info->f);
- accelerationFlags = ReadWORD(info->f);
+ accelerationFlags = (AccelerationFlags)ReadWORD(info->f);
- if(accelerationFlags & ACCFLAG_TENSION)
+ if(accelerationFlags.tension)
key->tension = ReadFloat(info->f);
- if(accelerationFlags & ACCFLAG_CONTINUITY)
+ if(accelerationFlags.continuity)
key->continuity = ReadFloat(info->f);
- if(accelerationFlags & ACCFLAG_BIAS)
+ if(accelerationFlags.bias)
key->bias = ReadFloat(info->f);
- if(accelerationFlags & ACCFLAG_EASETO)
+ if(accelerationFlags.easeTo)
key->easeTo = ReadFloat(info->f);
- if(accelerationFlags & ACCFLAG_EASEFROM)
+ if(accelerationFlags.easeFrom)
key->easeFrom = ReadFloat(info->f);
switch(info->chunkId)
case FRM_MESHINFO:
{
ObjectInfoBlock block { };
- Object object;
+ Object object = null;
ReadChunks(ReadFrameInfoBlock, info, &block);
}
delete block.dummyName;
}
- object.parent = info->rootObject;
+ if(object)
+ object.parent = info->rootObject;
}
else
object = info->rootObject.Find(block.name);
case FRM_CAMERA:
{
ObjectInfoBlock block { };
- Object object;
+ Object object = null;
ReadChunks(ReadFrameInfoBlock, info, &block);
}
delete block.dummyName;
}
- object.parent = info->rootObject;
+ if(object)
+ object.parent = info->rootObject;
}
else
object = info->rootObject.Find(block.name);
case FRM_CAMERATARGET:
{
ObjectInfoBlock block { };
- Object object;
+ Object object = null;
char targetName[MAXNAMELEN];
ReadChunks(ReadFrameInfoBlock, info, &block);
}
delete block.dummyName;
}
- object.parent = info->rootObject;
+ if(object)
+ object.parent = info->rootObject;
}
else
object = info->rootObject.Find(targetName);
case FRM_SPOTLIGHT:
{
ObjectInfoBlock block { };
- Object object;
+ Object object = null;
ReadChunks(ReadFrameInfoBlock, info, &block);
}
delete block.dummyName;
}
- object.parent = info->rootObject;
+ if(object)
+ object.parent = info->rootObject;
}
else
object = info->rootObject.Find(block.name);
case FRM_SPOTLIGHTTARGET:
{
ObjectInfoBlock block { };
- Object object;
+ Object object = null;
char targetName[MAXNAMELEN];
ReadChunks(ReadFrameInfoBlock, info, &block);
{
object = Object { };
object.name = new char[strlen(block.dummyName) + strlen(model.name) + 2];
+ // TODO: When passing a String to a const String, use member if property is const String but member is String
sprintf(object.name, "%s.%s", model.name, block.dummyName);
object.flags = model.flags;
object.flags.ownMesh = false;
}
delete block.dummyName;
}
- object.parent = info->rootObject;
+ if(object)
+ object.parent = info->rootObject;
}
else
object = info->rootObject.Find(targetName);
{
class_property(extension) = "3ds";
- bool Load(Object object, char * fileName, DisplaySystem displaySystem)
+ bool Load(Object object, const char * fileName, DisplaySystem displaySystem)
{
bool result = false;
if(fileName)
info.displaySystem = displaySystem;
info.pos = 0;
info.end = 1;
+ info.fileName = fileName;
StripLastDirectory(fileName, info.textureDirectory);
info.f = FileOpen(fileName, read);
if(info.f)
{
- if(ReadChunks(ReadMain, &info, object) && info.rootObject.children.first)
+ // TOFIX: eC reorders that badly
+ // if(ReadChunks(ReadMain, &info, object) && info.rootObject.children.first)
+ if(ReadChunks(ReadMain, &info, object) && info.rootObject.firstChild)
{
object.flags.root = true;
object.SetMinMaxRadius(true);
}
delete info.f;
}
+ if(info.matFaces)
+ info.matFaces.Free();
+ delete info.matFaces;
}
if(!result)
object.Free(displaySystem);