ecere: Clang warning fixes
[sdk] / ecere / src / gfx / 3D / models / Object3DSFormat.ec
index 7e8a3bc..5866f22 100644 (file)
@@ -2,136 +2,163 @@ 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;
 
@@ -141,18 +168,19 @@ typedef struct
    uint origIndices[3];
    uint smoothGroups;
    Material material;
-   Vector3Df normal;
+   Vector3D normal;
+   double dots[3];
    bool done:1;
 } Face;
 
-struct FileInfo
+static struct FileInfo
 {
    File f;
    DisplaySystem displaySystem;
    Object rootObject;
-   String fileName;
+   const String fileName;
 
-   uint16 chunkId;
+   ChunkID3DS chunkId;
    uint pos, end;
 
    FileInfo * parent;
@@ -197,7 +225,7 @@ static int ReadASCIIZ(File f, char ** string)
 
 static float ReadFloat(File f)
 {
-   float floatValue;
+   float floatValue = 0;
    f.Read(&floatValue, sizeof(float), 1);
    BIGENDSWAP_DWORD(floatValue);
    return floatValue;
@@ -205,7 +233,7 @@ static float ReadFloat(File f)
 
 static uint16 ReadWORD(File f)
 {
-   uint16 wordValue;
+   uint16 wordValue = 0;
    f.Read(&wordValue, sizeof(uint16), 1);
    BIGENDSWAP_WORD(wordValue);
    return wordValue;
@@ -213,7 +241,7 @@ static uint16 ReadWORD(File f)
 
 static uint ReadDWORD(File f)
 {
-   uint dwordValue;
+   uint dwordValue = 0;
    f.Read(&dwordValue, sizeof(uint), 1);
    BIGENDSWAP_DWORD(dwordValue);
    return dwordValue;
@@ -230,7 +258,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);
@@ -249,7 +277,7 @@ static bool ReadRGB(FileInfo * info, ColorRGB * rgb)
 {
    if(info->chunkId == RGB_BYTE || info->chunkId == RGB_BYTE_GAMMA)
    {
-      byte value;
+      byte value = 0;
       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;
@@ -299,7 +327,7 @@ struct SharedSourceVertexInfo
          if(face > b.face) return 1;
       }
       if(index == b.index) return 0;
-      if(WELD_TRESHOLD)
+      if(WELD_TRESHOLD > 0)
       {
          if(value.x < b.value.x - WELD_TRESHOLD) return -1;
          if(value.x > b.value.x + WELD_TRESHOLD) return 1;
@@ -340,7 +368,7 @@ struct SourceVertexInfo
 class DestVertexInfo
 {
    int index, copyFromIndex;
-   Vector3Df normal;
+   Vector3Df normal, tangent1, tangent2;
 };
 
 static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
@@ -367,9 +395,11 @@ static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
    {
       Face * face = &faces[c];
       Plane plane;
-      plane.FromPointsf(mesh.vertices[face->indices[2]],
-                        mesh.vertices[face->indices[1]],
-                        mesh.vertices[face->indices[0]]);
+      uint * indices = face->indices;
+      Vector3D edges[3], rEdges[3];
+      computeNormalWeights(3, mVertices, indices, true, 0, face->dots, edges, rEdges);
+
+      plane.FromPointsf(mVertices[indices[2]], mVertices[indices[1]], mVertices[indices[0]]);
       face->normal = { (float)plane.normal.x, (float)plane.normal.y, (float)plane.normal.z };
    }
 
@@ -428,12 +458,15 @@ static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
 
    for(index = 0; index < nNewVertices; index++)
    {
-      int numShared = 0;
       it.pointer = vertices[index];
       if(it.pointer)
       {
+         int numShared = 0;
+         double dotSum = 0;
          DestVertexInfo vInfo = it.data;
-         Vector3Df normal { };
+         Vector3D normal { };
+         Vector3D tangent1 { };
+         Vector3D tangent2 { };
          SourceVertexInfo * inf = (SourceVertexInfo *)&(((AVLNode)it.pointer).key);
          uint smoothing = inf->smoothGroups;
          bool added = true;
@@ -452,7 +485,7 @@ static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
          }
 
          // Optional code to compensate auto-welding with a limit angle cutoff between faces of same smoothing group
-         if(SMOOTH_CUTOFF && WELD_TRESHOLD)
+         if(SMOOTH_CUTOFF && WELD_TRESHOLD > 0)
          {
             for(i : svInfo.faces)
             {
@@ -488,7 +521,7 @@ static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
                {
                   bool valid = true;
 
-                  if(SMOOTH_CUTOFF && WELD_TRESHOLD)
+                  if(SMOOTH_CUTOFF && WELD_TRESHOLD > 0)
                   {
                      int origIndexB = -1;
                      int k;
@@ -519,23 +552,68 @@ static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
 
                   if(valid)
                   {
-                     normal.x += face->normal.x;
-                     normal.y += face->normal.y;
-                     normal.z += face->normal.z;
+                     uint * indices = face->origIndices;
+                     uint ix = vInfo.copyFromIndex;
+                     uint ix0 = indices[0], ix1 = indices[1], ix2 = indices[2];
+                     double dot = ix == ix0 ? face->dots[0] : ix == ix1 ? face->dots[1] : ix == ix2 ? face->dots[2] : 1;
+                     if(ix != indices[0] && ix != indices[1] && ix != indices[2])
+                     {
+                             if(!mVertices[ix0].OnCompare(mVertices[ix])) dot = face->dots[0];
+                        else if(!mVertices[ix1].OnCompare(mVertices[ix])) dot = face->dots[1];
+                        else if(!mVertices[ix2].OnCompare(mVertices[ix])) dot = face->dots[2];
+                     }
+                     normal.x += face->normal.x * dot;
+                     normal.y += face->normal.y * dot;
+                     normal.z += face->normal.z * dot;
+
+                     if(mesh.texCoords)
+                     {
+                        Vector3Df * p0 = &mVertices[ix0], * p1 = &mVertices[ix1], * p2 = &mVertices[ix2];
+                        Pointf * t0 = &mesh->texCoords[ix0], * t1 = &mesh->texCoords[ix1], * t2 = &mesh->texCoords[ix2];
+                        Vector3D v01 { (double)p1->x - (double)p0->x, (double)p1->y - (double)p0->y, (double)p1->z - (double)p0->z };
+                        Vector3D v02 { (double)p2->x - (double)p0->x, (double)p2->y - (double)p0->y, (double)p2->z - (double)p0->z };
+
+                        Vector3D t01 { (double)t1->x - (double)t0->x, (double)t1->y - (double)t0->y };
+                        Vector3D t02 { (double)t2->x - (double)t0->x, (double)t2->y - (double)t0->y };
+                        double f = dot / (t01.x * t02.y - t02.x * t01.y);
+
+                        tangent1.x += f * (v01.x * t02.y - v02.x * t01.y);
+                        tangent1.y += f * (v01.y * t02.y - v02.y * t01.y);
+                        tangent1.z += f * (v01.z * t02.y - v02.z * t01.y);
+
+                        tangent2.x += f * (v02.x * t01.x - v01.x * t02.x);
+                        tangent2.y += f * (v02.y * t01.x - v01.y * t02.x);
+                        tangent2.z += f * (v02.z * t01.x - v01.z * t02.x);
+                     }
+
+                     dotSum += dot;
                      numShared++;
                      added = true;
                      face->done = true;
                   }
                }
             }
-            if(!SMOOTH_CUTOFF || !WELD_TRESHOLD) break;
+            if(!SMOOTH_CUTOFF || !(WELD_TRESHOLD > 0)) break;
          }
-         normal.Scale(normal, 1.0f / numShared);
+         // normal.Scale(normal, 1.0f / numShared);
+         normal.Scale(normal, 1.0 / dotSum);
+         normal.Normalize(normal);
+
+         //tangent1.Scale(tangent1, 1.0 / dotSum);
+         tangent1.Normalize(tangent1);
+
+         //tangent2.Scale(tangent2, 1.0 / dotSum);
+         tangent2.Normalize(tangent2);
+
          if(vInfo.index == index)
-            vInfo.normal.Normalize(normal);
+         {
+            vInfo.normal = { (float)normal.x, (float)normal.y, (float)normal.z };
+            vInfo.tangent1 = { (float)tangent1.x, (float)tangent1.y, (float)tangent1.z };
+            vInfo.tangent2 = { (float)tangent2.x, (float)tangent2.y, (float)tangent2.z };
+         }
 
          // Auto welding/smoothing requires extra vertices because angle is too steep
-         if(SMOOTH_CUTOFF && WELD_TRESHOLD)
+         if(SMOOTH_CUTOFF && WELD_TRESHOLD > 0)
          {
             SharedDestVertexInfo newSharedInfo = null;
             int index;
@@ -588,7 +666,7 @@ static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
       *((void **)&mesh.texCoords) = null;
       *((int *)&mesh.nVertices) = 0;
 
-      mesh.Allocate( { vertices = true, normals = true, texCoords1 = oldTexCoords ? true : false }, nNewVertices, info->displaySystem);
+      mesh.Allocate( { vertices = true, normals = true, tangents = oldTexCoords ? true : false, texCoords1 = oldTexCoords ? true : false }, nNewVertices, info->displaySystem);
 
       // Fill in the new vertices
       for(index = 0; index < nNewVertices; index++)
@@ -600,6 +678,11 @@ static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
          // Duplicate vertex
          mesh.normals[index] = vInfo ? vInfo.normal : { };
          mesh.vertices[index] = oldVertices[vInfo ? vInfo.copyFromIndex : index];
+         if(mesh.tangents)
+         {
+            mesh.tangents[2*index+0] = vInfo ? vInfo.tangent1 : { };
+            mesh.tangents[2*index+1] = vInfo ? vInfo.tangent2 : { };
+         }
          if(mesh.texCoords)
             mesh.texCoords[index] = oldTexCoords[vInfo ? vInfo.copyFromIndex : index];
       }
@@ -614,7 +697,7 @@ static void ComputeNormals(Mesh mesh, FileInfo * info, Object object)
          info->faces[i].done = false;
    }
 
-   mesh.Unlock({ normals = true });
+   mesh.Unlock({ normals = true, tangents = true });
 
    // Free all the temporary stuff
 
@@ -774,17 +857,17 @@ static bool ReadTriMesh(FileInfo * info, Object object)
                   PrimitiveSingle * triangle;
 
                   triangle = &mesh.primitives[mesh.nPrimitives++];
-                  if(mesh.AllocatePrimitive(triangle, { triangles, indices32bit = true }, 3))
+                  if(mesh.AllocatePrimitive(triangle, { triangles, indices32bit = USE_32_BIT_INDICES }, 3))
                   {
-                     triangle->indices32[0] = face->indices[0];
-                     triangle->indices32[1] = face->indices[1];
-                     triangle->indices32[2] = face->indices[2];
-                     triangle->middle.Add(mesh.vertices[triangle->indices32[0]], mesh.vertices[triangle->indices32[1]]);
-                     triangle->middle.Add(triangle->middle, mesh.vertices[triangle->indices32[2]]);
+                     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->indices32[2]],
-                        mesh.vertices[triangle->indices32[1]],
-                        mesh.vertices[triangle->indices32[0]]);
+                        mesh.vertices[triangle->indicesMember[2]],
+                        mesh.vertices[triangle->indicesMember[1]],
+                        mesh.vertices[triangle->indicesMember[0]]);
 
                      mesh.UnlockPrimitive(triangle);
                   }
@@ -800,7 +883,7 @@ static bool ReadTriMesh(FileInfo * info, Object object)
             }
             else
             {
-               PrimitiveGroup group = mesh.AddPrimitiveGroup({ triangles, indices32bit = true }, faces.count * 3);
+               PrimitiveGroup group = mesh.AddPrimitiveGroup({ triangles, indices32bit = USE_32_BIT_INDICES }, faces.count * 3);
                if(group)
                {
                   c = 0;
@@ -811,15 +894,15 @@ static bool ReadTriMesh(FileInfo * info, Object object)
 
                      if(object.flags.flipWindings)
                      {
-                        group.indices32[c*3]   = face->indices[2];
-                        group.indices32[c*3+1] = face->indices[1];
-                        group.indices32[c*3+2] = face->indices[0];
+                        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.indices32[c*3]   = face->indices[0];
-                        group.indices32[c*3+1] = face->indices[1];
-                        group.indices32[c*3+2] = face->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];
                      }
                      face->done = true;
                      c++;
@@ -836,7 +919,7 @@ static bool ReadTriMesh(FileInfo * info, Object object)
                count++;
          if(count)
          {
-            PrimitiveGroup group = mesh.AddPrimitiveGroup({ triangles, indices32bit = true }, count * 3);
+            PrimitiveGroup group = mesh.AddPrimitiveGroup({ triangles, indices32bit = USE_32_BIT_INDICES }, count * 3);
             if(group)
             {
                for(c = 0; c<nFaces; c++)
@@ -844,9 +927,9 @@ static bool ReadTriMesh(FileInfo * info, Object object)
                   Face * face = &info->faces[c];
                   if(!face->done)
                   {
-                     group.indices32[c*3]   = face->indices[0];
-                     group.indices32[c*3+1] = face->indices[1];
-                     group.indices32[c*3+2] = face->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);
@@ -1031,7 +1114,40 @@ static bool ReadMap(FileInfo * info, Material mat)
                         {
                            uint bc = y * bw + x;
                            Color color = picture[bc].color;
-                           picture[bc] = { 255, { color.r, 255 - color.b, color.g } };
+                           picture[bc] = { 255, { color.r, color.g, color.b } };
+                        }
+                  }
+               }
+            }
+         }
+         else if(info->parent->chunkId == MAT_SPECULARMAP)
+         {
+            // To avoid messing up the diffuse texture if same bitmap is specified by mistake...
+            char specName[MAX_LOCATION+5];
+            strcpy(specName, "SPEC:");
+            strcat(specName, location);
+            if(!mat.specularMap)
+            {
+               mat.specularMap = displaySystem.GetTexture(specName);
+               if(!mat.specularMap)
+               {
+                  mat.specularMap = Bitmap { };
+                  if(!mat.specularMap.Load(location, null, null) ||
+                     !mat.specularMap.Convert(null, pixelFormat888, null) ||
+                     !displaySystem.AddTexture(specName, mat.specularMap))
+                     delete mat.specularMap;
+                  if(mat.specularMap)
+                  {
+                     ColorAlpha * picture = (ColorAlpha *)mat.specularMap.picture;
+                     int bw = mat.specularMap.width, bh = mat.specularMap.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, color.g, color.b } };
                         }
                   }
                }
@@ -1103,8 +1219,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:
@@ -1179,9 +1295,12 @@ static bool ReadMaterial(FileInfo * info, Material mat)
       {
          uint16 shininess;
          ReadChunks(ReadAmountOf, info, &shininess);
+         mat.reflectivity = shininess / 100.0f;
+         /*
          mat.specular.r *= shininess / 100.0f;
          mat.specular.g *= shininess / 100.0f;
          mat.specular.b *= shininess / 100.0f;
+         */
          break;
       }
       case MAT_SHININESS:
@@ -1266,8 +1385,6 @@ static bool ReadLight(FileInfo * info, Object object)
             { Kc, Kl, Kq, small, d });
          */
 
-         light->flags.attenuation = true;
-
          /*
          #define MINLIGHT     0.08
          light->Kq = 1/(light->end*light->end*MINLIGHT);
@@ -1275,8 +1392,13 @@ static bool ReadLight(FileInfo * info, Object object)
 
          #define MINLIGHT     0.15f
          // #define MINLIGHT     0.1
-         light->Kl = (float)(1/(light->end*MINLIGHT));
+         //light->Kl = (float)(1/(light->end*MINLIGHT));
 
+         float c = 1.0, l = 0.005, q = 0.0005, small = 500, end = light->end;
+         light->Kc = (c + l * end + q * end * end) / small;
+         light->Kl = light->Kc * l/c;
+         light->Kq = light->Kc * q/c;
+         light->flags.attenuation = true;
          break;
       }
       case LIT_START:
@@ -1498,12 +1620,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)
 {
@@ -1568,21 +1688,21 @@ static bool ReadFrameInfoBlock(FileInfo * info, ObjectInfoBlock * block)
             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)
@@ -1598,12 +1718,10 @@ static bool ReadFrameInfoBlock(FileInfo * info, ObjectInfoBlock * block)
                   {
                      Vector3Df axis;
                      Angle angle = ReadFloat(info->f);
-                     Vector3Df fixedAxis;
+                     Vector3D fixedAxis;
 
                      Read3DVertex(info->f, axis);
-                     fixedAxis.x = axis.x;
-                     fixedAxis.y = -axis.z;
-                     fixedAxis.z = axis.y;
+                     fixedAxis = { axis.x, -axis.z, axis.y };
 
                      if(c > 0)
                      {
@@ -1685,7 +1803,7 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data)
       case FRM_MESHINFO:
       {
          ObjectInfoBlock block { };
-         Object object;
+         Object object = null;
 
          ReadChunks(ReadFrameInfoBlock, info, &block);
 
@@ -1719,7 +1837,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);
@@ -1770,7 +1889,7 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data)
       case FRM_CAMERA:
       {
          ObjectInfoBlock block { };
-         Object object;
+         Object object = null;
 
          ReadChunks(ReadFrameInfoBlock, info, &block);
 
@@ -1800,7 +1919,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);
@@ -1834,7 +1954,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);
@@ -1866,7 +1986,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);
@@ -1910,7 +2031,7 @@ static bool ReadKeyFrameChunks(FileInfo * info, void * data)
       case FRM_SPOTLIGHT:
       {
          ObjectInfoBlock block { };
-         Object object;
+         Object object = null;
 
          ReadChunks(ReadFrameInfoBlock, info, &block);
 
@@ -1940,7 +2061,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);
@@ -1974,7 +2096,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);
@@ -1998,6 +2120,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;
@@ -2006,7 +2129,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);
@@ -2085,7 +2209,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)
@@ -2100,7 +2224,9 @@ class Object3DSFormat : ObjectFormat
          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);