X-Git-Url: http://ecere.com/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ecere%2Fsrc%2Fgfx%2F3D%2Fmodels%2FObject3DSFormat.ec;h=18afb6cee741ab0dd394270adf135022c062c552;hb=185ea6c4399f11804c7cd97cf226879a29f4b4d1;hp=7d6d4bb178086f1df2089c2ea93006154c26182b;hpb=61487a39a6dc3f024ca5a7d6f215ec02d36df755;p=sdk diff --git a/ecere/src/gfx/3D/models/Object3DSFormat.ec b/ecere/src/gfx/3D/models/Object3DSFormat.ec index 7d6d4bb..18afb6c 100644 --- a/ecere/src/gfx/3D/models/Object3DSFormat.ec +++ b/ecere/src/gfx/3D/models/Object3DSFormat.ec @@ -2,160 +2,191 @@ namespace gfx3D::models; 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> matFaces; }; #define SWAP_WORD(word) (((unsigned short)(word) & 0x00ff) << 8) \ @@ -226,7 +257,7 @@ static bool ReadChunks(bool (* chunkParser)(FileInfo * info, void * data), FileI 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); @@ -246,9 +277,9 @@ static bool ReadRGB(FileInfo * info, ColorRGB * rgb) 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) { @@ -274,80 +305,302 @@ static bool ReadAmountOf(FileInfo * info, uint16 * amountOf) 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 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 sharedVertices { }; + Map vertexMap { }; + Array> vertices { size = nVertices }; - VertexConfigList * configLists = new0 VertexConfigList[nVertices]; + MapIterator itShared { map = sharedVertices }; + MapIterator it { map = vertexMap }; nNewVertices = nVertices; + mVertices = mesh->vertices; + for(c = 0; cnFaces; 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; vnumConfig; 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<smoothGroups & (1<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; + } + } + } + } } } } @@ -357,6 +610,7 @@ static void ComputeNormals(Mesh mesh, FileInfo * info, Object object) Vector3Df * oldVertices = mesh.vertices; Pointf * oldTexCoords = mesh.texCoords; + // TODO: Support reallocation? *((void **)&mesh.vertices) = null; *((void **)&mesh.texCoords) = null; *((int *)&mesh.nVertices) = 0; @@ -364,105 +618,43 @@ static void ComputeNormals(Mesh mesh, FileInfo * info, Object object) mesh.Allocate( { vertices = true, normals = true, texCoords1 = oldTexCoords ? true : false }, nNewVertices, info->displaySystem); // Fill in the new vertices - for(index = 0; indexnumConfig; 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; cnFaces; 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; indexScale(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: @@ -479,81 +671,34 @@ static bool ReadSmoothing(FileInfo * info, Object object) 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 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; cf); - 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; cf); - 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; cf); + faces[i + c] = face; + info->faces[face].material = mat; } delete name; break; @@ -614,7 +759,7 @@ static bool ReadTriMesh(FileInfo * info, Object object) { int c; uint16 nFaces = 0; - int count; + uint count; uint pos; info->nFaces = nFaces = ReadWORD(info->f); @@ -625,10 +770,8 @@ static bool ReadTriMesh(FileInfo * info, Object object) { 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); } @@ -636,10 +779,83 @@ static bool ReadTriMesh(FileInfo * info, Object object) 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 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; cfaces[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; cmatFaces.Free(); + delete info->matFaces; + } break; } case TRI_LOCAL: @@ -815,35 +1020,48 @@ static bool ReadMap(FileInfo * info, Material mat) 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 @@ -853,13 +1071,13 @@ static bool ReadMap(FileInfo * info, Material mat) 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; } @@ -912,8 +1130,8 @@ static bool ReadMap(FileInfo * info, Material mat) } 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: @@ -939,7 +1157,13 @@ static bool ReadMaterial(FileInfo * info, Material mat) { 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: @@ -1017,7 +1241,6 @@ static bool ReadMaterial(FileInfo * info, Material mat) // Lights static bool ReadLight(FileInfo * info, Object object) { - Mesh mesh = object.mesh; Light * light = &object.light; switch(info->chunkId) { @@ -1105,7 +1328,6 @@ static bool ReadLight(FileInfo * info, Object object) // Cameras static bool ReadCamera(FileInfo * info, Object object) { - Mesh mesh = object.mesh; switch(info->chunkId) { case CAM_SEECONE: @@ -1114,9 +1336,9 @@ static bool ReadCamera(FileInfo * info, Object object) } 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; @@ -1139,12 +1361,10 @@ static bool ReadEditObject(FileInfo * info, char * name) 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; @@ -1160,12 +1380,10 @@ static bool ReadEditObject(FileInfo * info, char * name) 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; @@ -1187,29 +1405,31 @@ static bool ReadEditObject(FileInfo * info, char * name) 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; @@ -1230,7 +1450,7 @@ static bool ReadEditObject(FileInfo * info, char * name) 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); @@ -1242,8 +1462,6 @@ static bool ReadEditObject(FileInfo * info, char * name) break; } case OBJ_HIDDEN: break; - default: - delete name; } return true; } @@ -1262,7 +1480,7 @@ static bool ReadEditChunks(FileInfo * info, void * data) } case EDIT_MATERIAL: { - Material material { }; + Material material { /*flags = { singleSideLight = true }*/ }; Material mat; ReadChunks(ReadMaterial, info, material); @@ -1289,6 +1507,7 @@ static bool ReadEditChunks(FileInfo * info, void * data) char * name; info->pos += ReadASCIIZ(info->f, &name); ReadChunks(ReadEditObject, info, name); + delete name; break; } } @@ -1306,12 +1525,10 @@ struct ObjectInfoBlock }; // 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) { @@ -1319,10 +1536,10 @@ 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; } @@ -1376,21 +1593,21 @@ static bool ReadFrameInfoBlock(FileInfo * info, ObjectInfoBlock * block) track.keys = new0 FrameKey[track.numKeys]; for(c = 0; cframe = 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) @@ -1493,7 +1710,7 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) case FRM_MESHINFO: { ObjectInfoBlock block { }; - Object object; + Object object = null; ReadChunks(ReadFrameInfoBlock, info, &block); @@ -1527,7 +1744,8 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) } delete block.dummyName; } - object.parent = info->rootObject; + if(object) + object.parent = info->rootObject; } else object = info->rootObject.Find(block.name); @@ -1578,7 +1796,7 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) case FRM_CAMERA: { ObjectInfoBlock block { }; - Object object; + Object object = null; ReadChunks(ReadFrameInfoBlock, info, &block); @@ -1608,7 +1826,8 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) } delete block.dummyName; } - object.parent = info->rootObject; + if(object) + object.parent = info->rootObject; } else object = info->rootObject.Find(block.name); @@ -1642,7 +1861,7 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) case FRM_CAMERATARGET: { ObjectInfoBlock block { }; - Object object; + Object object = null; char targetName[MAXNAMELEN]; ReadChunks(ReadFrameInfoBlock, info, &block); @@ -1674,7 +1893,8 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) } delete block.dummyName; } - object.parent = info->rootObject; + if(object) + object.parent = info->rootObject; } else object = info->rootObject.Find(targetName); @@ -1718,7 +1938,7 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) case FRM_SPOTLIGHT: { ObjectInfoBlock block { }; - Object object; + Object object = null; ReadChunks(ReadFrameInfoBlock, info, &block); @@ -1748,7 +1968,8 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) } delete block.dummyName; } - object.parent = info->rootObject; + if(object) + object.parent = info->rootObject; } else object = info->rootObject.Find(block.name); @@ -1782,7 +2003,7 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) case FRM_SPOTLIGHTTARGET: { ObjectInfoBlock block { }; - Object object; + Object object = null; char targetName[MAXNAMELEN]; ReadChunks(ReadFrameInfoBlock, info, &block); @@ -1806,6 +2027,7 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) { 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; @@ -1814,7 +2036,8 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data) } delete block.dummyName; } - object.parent = info->rootObject; + if(object) + object.parent = info->rootObject; } else object = info->rootObject.Find(targetName); @@ -1893,7 +2116,7 @@ class Object3DSFormat : ObjectFormat { 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) @@ -1903,11 +2126,14 @@ class Object3DSFormat : ObjectFormat 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); @@ -1917,6 +2143,9 @@ class Object3DSFormat : ObjectFormat } delete info.f; } + if(info.matFaces) + info.matFaces.Free(); + delete info.matFaces; } if(!result) object.Free(displaySystem);