diff options
Diffstat (limited to 'Magic2/l3ds.cpp')
-rw-r--r-- | Magic2/l3ds.cpp | 1793 |
1 files changed, 1793 insertions, 0 deletions
diff --git a/Magic2/l3ds.cpp b/Magic2/l3ds.cpp new file mode 100644 index 0000000..3cbdcfa --- /dev/null +++ b/Magic2/l3ds.cpp @@ -0,0 +1,1793 @@ +// copyright (c) 2001 Lev Povalahev + + +#include "stdafx.h" + +#include "l3ds.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +//using namespace std; + +//------------------------------------------------------- +// generic stuff +//------------------------------------------------------- + +typedef unsigned long ulong; + +#define SEEK_START 1900 +#define SEEK_CURSOR 1901 + +// common chunks +// colors +#define COLOR_F 0x0010 +#define COLOR_24 0x0011 +#define LIN_COLOR_24 0x0012 +#define LIN_COLOR_F 0x0013 +// percentage +#define INT_PERCENTAGE 0x0030 +#define FLOAT_PERCENTAGE 0x0031 +// ambient light +#define AMBIENT_LIGHT 0x2100 + + +#define MAIN3DS 0x4D4D +#define EDIT3DS 0x3D3D // this is the start of the editor config + +// keyframer chunk ids +#define KFDATA 0xB000 // the keyframer section +#define KFHDR 0xB00A +#define OBJECT_NODE_TAG 0xB002 +#define NODE_HDR 0xB010 +#define PIVOT 0xB013 +#define POS_TRACK_TAG 0xB020 +#define ROT_TRACK_TAG 0xB021 +#define SCL_TRACK_TAG 0xB022 + +// material entries +#define MAT_ENTRY 0xAFFF +#define MAT_NAME 0xA000 +#define MAT_AMBIENT 0xA010 +#define MAT_DIFFUSE 0xA020 +#define MAT_SPECULAR 0xA030 +#define MAT_SHININESS 0xA040 +#define MAT_SHIN2PCT 0xA041 +#define MAT_TRANSPARENCY 0xA050 +#define MAT_SHADING 0xA100 +#define MAT_TWO_SIDE 0xA081 +#define MAT_ADDITIVE 0xA083 +#define MAT_WIRE 0xA085 +#define MAT_FACEMAP 0xA088 +#define MAT_WIRESIZE 0xA087 +#define MAT_DECAL 0xA082 +#define MAT_TEXMAP 0xA200 +#define MAT_MAPNAME 0xA300 +#define MAT_MAP_TILING 0xA351 +#define MAT_MAP_USCALE 0xA354 +#define MAT_MAP_VSCALE 0xA356 +#define MAT_MAP_UOFFSET 0xA358 +#define MAT_MAP_VOFFSET 0xA35A +#define MAT_MAP_ANG 0xA35C +#define MAT_TEX2MAP 0xA33A +#define MAT_OPACMAP 0xA210 +#define MAT_BUMPMAP 0xA230 +#define MAT_SPECMAP 0xA204 +#define MAT_SHINMAP 0xA33C +#define MAT_REFLMAP 0xA220 +#define MAT_ACUBIC 0xA310 + +#define EDIT_OBJECT 0x4000 +#define OBJ_TRIMESH 0x4100 +#define OBJ_LIGHT 0x4600 +#define OBJ_CAMERA 0x4700 +#define LIT_OFF 0x4620 +#define LIT_SPOT 0x4610 +#define TRI_VERTEXLIST 0x4110 +#define TRI_VERTEXOPTIONS 0x4111 + +#define TRI_FACELIST 0x4120 + #define TRI_MAT_GROUP 0x4130 + #define TRI_SMOOTH_GROUP 0x4150 + +#define TRI_FACEMAPPING 0x4140 +#define TRI_MATRIX 0x4160 + +#define SPOTLIGHT 0x4610 + +//---------------------------------- + +#define MAX_SHARED_TRIS 100 + +// the error reporting routine + +void ErrorMsg(const char *msg) +{ + +} + +struct LChunk +{ + unsigned short id; + uint start; + uint end; +}; + +struct LTri +{ + unsigned short a; + unsigned short b; + unsigned short c; + ulong smoothingGroups; + LVector3 normal; + LVector3 tangent; + LVector3 binormal; + uint materialId; +}; + +// globals + +LColor3 black = {0, 0, 0}; + +LVector3 zero3 = {0, 0, 0}; + +LVector4 zero4 = {0, 0, 0, 0}; + +LMap emptyMap = {0, "", 1, 1, 0, 0, 0}; + +LVector3 _4to3(const LVector4 &vec) +{ + LVector3 t; + t.x = vec.x; + t.y = vec.y; + t.z = vec.z; + return t; +} + +LVector3 AddVectors(const LVector3 &a, const LVector3 &b) +{ + LVector3 t; + t.x = a.x+b.x; + t.y = a.y+b.y; + t.z = a.z+b.z; + return t; +} + +LVector3 SubtractVectors(const LVector3 &a, const LVector3 &b) +{ + LVector3 t; + t.x = a.x-b.x; + t.y = a.y-b.y; + t.z = a.z-b.z; + return t; +} + +float VectorLength(const LVector3 &vec) +{ + return (float)sqrt(vec.x*vec.x + vec.y*vec.y+vec.z*vec.z); +} + +LVector3 NormalizeVector(const LVector3 &vec) +{ + float a = VectorLength(vec); + if (a == 0) + return vec; + float b = 1/a; + LVector3 v; + v.x = vec.x*b; + v.y = vec.y*b; + v.z = vec.z*b; + return v; +} + +LVector3 CrossProduct(const LVector3 &a, const LVector3 &b) +{ + LVector3 v; + v.x = a.y*b.z - a.z*b.y; + v.y = a.z*b.x - a.x*b.z; + v.z = a.x*b.y - a.y*b.x; + return v; +} + +void LoadIdentityMatrix(LMatrix4 &m) +{ + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + m.m[i][j] = (i==j) ? 1.0f : 0.0f; +} + +LVector4 VectorByMatrix(const LMatrix4 &m, const LVector4 &vec) +{ + LVector4 res; + + res.x = m.m[0][0]*vec.x + m.m[1][0]*vec.y + m.m[2][0]*vec.z + m.m[3][0]*vec.w; + res.y = m.m[0][1]*vec.x + m.m[1][1]*vec.y + m.m[2][1]*vec.z + m.m[3][1]*vec.w; + res.z = m.m[0][2]*vec.x + m.m[1][2]*vec.y + m.m[2][2]*vec.z + m.m[3][2]*vec.w; + res.w = m.m[0][3]*vec.x + m.m[1][3]*vec.y + m.m[2][3]*vec.z + m.m[3][3]*vec.w; + + if (res.w != 0) { + float b = 1/res.w; + res.x *= b; + res.y *= b; + res.z *= b; + res.w = 1; + } + else { + res.w = 1; + } + + return res; +} + +void QuatToMatrix(const LVector4 &quat, LMatrix4 &m) +{ + +} + +//------------------------------------------------------- +// LObject implementation +//------------------------------------------------------- + +LObject::LObject() +{ + m_name = "";//.clear(); +} + +LObject::~LObject() +{ + // nothing here +} + +void LObject::SetName(const std::string& value) +{ + m_name = value; +} + +const std::string& LObject::GetName() +{ + return m_name; +} + +bool LObject::IsObject(const std::string &name) +{ + return (m_name == name); +} + + +//------------------------------------------------------- +// LMaterial implementation +//------------------------------------------------------- + +LMaterial::LMaterial() +: LObject() +{ + m_id = 0; + m_texMap1 = emptyMap; + m_texMap2 = emptyMap; + m_opacMap = emptyMap; + m_bumpMap = emptyMap; + m_reflMap = emptyMap; + m_specMap = emptyMap; + m_ambient = black; + m_diffuse = black; + m_specular = black; + m_shading = sGouraud; + m_shininess = 0; + m_transparency = 0; +} + +LMaterial::~LMaterial() +{ + +} + +uint LMaterial::GetID() +{ + return m_id; +} + +LMap& LMaterial::GetTextureMap1() +{ + return m_texMap1; +} + +LMap& LMaterial::GetTextureMap2() +{ + return m_texMap2; +} + +LMap& LMaterial::GetOpacityMap() +{ + return m_opacMap; +} + +LMap& LMaterial::GetSpecularMap() +{ + return m_specMap; +} + +LMap& LMaterial::GetBumpMap() +{ + return m_bumpMap; +} + +LMap& LMaterial::GetReflectionMap() +{ + return m_reflMap; +} + +LColor3 LMaterial::GetAmbientColor() +{ + return m_ambient; +} + +LColor3 LMaterial::GetDiffuseColor() +{ + return m_diffuse; +} + +LColor3 LMaterial::GetSpecularColor() +{ + return m_specular; +} + +float LMaterial::GetShininess() +{ + return m_shininess; +} + +float LMaterial::GetTransparency() +{ + return m_transparency; +} + +LShading LMaterial::GetShadingType() +{ + return m_shading; +} + +void LMaterial::SetID(uint value) +{ + m_id = value; +} + +void LMaterial::SetAmbientColor(const LColor3 &color) +{ + m_ambient = color; +} + +void LMaterial::SetDiffuseColor(const LColor3 &color) +{ + m_diffuse = color; +} + +void LMaterial::SetSpecularColor(const LColor3 &color) +{ + m_specular = color; +} + +void LMaterial::SetShininess(float value) +{ + m_shininess = value; + if (m_shininess < 0) + m_shininess = 0; + if (m_shininess > 1) + m_shininess = 1; +} + +void LMaterial::SetTransparency(float value) +{ + m_transparency = value; + if (m_transparency < 0) + m_transparency = 0; + if (m_transparency > 1) + m_transparency = 1; +} + +void LMaterial::SetShadingType(LShading shading) +{ + m_shading = shading; +} + +//------------------------------------------------------- +// LMesh implementation +//------------------------------------------------------- + +LMesh::LMesh() +: LObject() +{ + Clear(); +} + +LMesh::~LMesh() +{ + Clear(); +} + +void LMesh::Clear() +{ + m_vertices.clear(); + m_normals.clear(); + m_uv.clear(); + m_tangents.clear(); + m_binormals.clear(); + m_triangles.clear(); + m_tris.clear(); + m_materials.clear(); + LoadIdentityMatrix(m_matrix); +} + +uint LMesh::GetVertexCount() +{ + return m_vertices.size(); +} + +void LMesh::SetVertexArraySize(uint value) +{ + m_vertices.resize(value); + m_normals.resize(value); + m_uv.resize(value); + m_tangents.resize(value); + m_binormals.resize(value); +} + +uint LMesh::GetTriangleCount() +{ + return m_triangles.size(); +} + +void LMesh::SetTriangleArraySize(uint value) +{ + m_triangles.resize(value); + m_tris.resize(value); +} + +const LVector4& LMesh::GetVertex(uint index) +{ + return m_vertices[index]; +} + +const LVector3& LMesh::GetNormal(uint index) +{ + return m_normals[index]; +} + +const LVector2& LMesh::GetUV(uint index) +{ + return m_uv[index]; +} + +const LVector3& LMesh::GetTangent(uint index) +{ + return m_tangents[index]; +} + +const LVector3& LMesh::GetBinormal(uint index) +{ + return m_binormals[index]; +} + +void LMesh::SetVertex(const LVector4 &vec, uint index) +{ + if (index >= m_vertices.size()) + return; + m_vertices[index] = vec; +} + +void LMesh::SetNormal(const LVector3 &vec, uint index) +{ + if (index >= m_vertices.size()) + return; + m_normals[index] = vec; +} + +void LMesh::SetUV(const LVector2 &vec, uint index) +{ + if (index >= m_vertices.size()) + return; + m_uv[index] = vec; +} + +void LMesh::SetTangent(const LVector3 &vec, uint index) +{ + if (index >= m_vertices.size()) + return; + m_tangents[index] = vec; +} + +void LMesh::SetBinormal(const LVector3 &vec, uint index) +{ + if (index >= m_vertices.size()) + return; + m_binormals[index] = vec; +} + +const LTriangle& LMesh::GetTriangle(uint index) +{ + return m_triangles[index]; +} + +LTriangle2 LMesh::GetTriangle2(uint index) +{ + LTriangle2 f; + LTriangle t = GetTriangle(index); + f.vertices[0] = GetVertex(t.a); + f.vertices[1] = GetVertex(t.b); + f.vertices[2] = GetVertex(t.c); + + f.vertexNormals[0] = GetNormal(t.a); + f.vertexNormals[1] = GetNormal(t.b); + f.vertexNormals[2] = GetNormal(t.c); + + f.textureCoords[0] = GetUV(t.a); + f.textureCoords[1] = GetUV(t.b); + f.textureCoords[2] = GetUV(t.c); + + LVector3 a, b; + + a = SubtractVectors(_4to3(f.vertices[1]), _4to3(f.vertices[0])); + b = SubtractVectors(_4to3(f.vertices[1]), _4to3(f.vertices[2])); + + f.faceNormal = CrossProduct(b, a); + + f.faceNormal = NormalizeVector(f.faceNormal); + + f.materialId = m_tris[index].materialId; + + return f; +} + +LMatrix4 LMesh::GetMatrix() +{ + return m_matrix; +} + +void LMesh::SetMatrix(LMatrix4 m) +{ + m_matrix = m; +} + +void LMesh::TransformVertices() +{ + for (uint i=0; i<m_vertices.size(); i++) + m_vertices[i] = VectorByMatrix(m_matrix, m_vertices[i]); + + LoadIdentityMatrix(m_matrix); +} + +void LMesh::CalcNormals(bool useSmoothingGroups) +{ + uint i; + // first calculate the face normals + for (i=0; i<m_triangles.size(); i++) + { + LVector3 a, b; + a = SubtractVectors(_4to3(m_vertices[m_tris[i].b]), _4to3(m_vertices[m_tris[i].a])); + b = SubtractVectors(_4to3(m_vertices[m_tris[i].b]), _4to3(m_vertices[m_tris[i].c])); + m_tris[i].normal = NormalizeVector(CrossProduct(b, a)); + } + + std::vector< std::vector<int> > array; + array.resize(m_vertices.size()); + for (i=0; i<m_triangles.size(); i++) + { + uint k = m_tris[i].a; + array[k].push_back(i); + + k = m_tris[i].b; + array[k].push_back(i); + + k = m_tris[i].c; + array[k].push_back(i); + } + + LVector3 temp; + + if (!useSmoothingGroups) + { + // now calculate the normals without using smoothing groups + for (i=0; i<m_vertices.size(); i++) + { + temp = zero3; + int t = array[i].size(); + + for (int k=0; k<t; k++) + { + temp.x += m_tris[array[i][k]].normal.x; + temp.y += m_tris[array[i][k]].normal.y; + temp.z += m_tris[array[i][k]].normal.z; + } + m_normals[i] = NormalizeVector(temp); + } + } + else + { + // now calculate the normals _USING_ smoothing groups + // I'm assuming a triangle can only belong to one smoothing group at a time! + std::vector<ulong> smGroups; + std::vector< std::vector <uint> > smList; + + uint loop_size = m_vertices.size(); + + for (i=0; i<loop_size; i++) + { + int t = array[i].size(); + + if (t == 0) + continue; + + smGroups.clear(); + smList.clear(); + smGroups.push_back(m_tris[array[i][0]].smoothingGroups); + smList.resize(smGroups.size()); + smList[smGroups.size()-1].push_back(array[i][0]); + + // first build a list of smoothing groups for the vertex + for (int k=0; k<t; k++) + { + bool found = false; + for (uint j=0; j<smGroups.size(); j++) + { + if (m_tris[array[i][k]].smoothingGroups == smGroups[j]) + { + smList[j].push_back(array[i][k]); + found = true; + } + } + if (!found) + { + smGroups.push_back(m_tris[array[i][k]].smoothingGroups); + smList.resize(smGroups.size()); + smList[smGroups.size()-1].push_back(array[i][k]); + } + } + // now we have the list of faces for the vertex sorted by smoothing groups + + + // now duplicate the vertices so that there's only one smoothing group "per vertex" + if (smGroups.size() > 1) + for (uint j=1; j< smGroups.size(); j++) + { + m_vertices.push_back(m_vertices[i]); + m_normals.push_back(m_normals[i]); + m_uv.push_back(m_uv[i]); + m_tangents.push_back(m_tangents[i]); + m_binormals.push_back(m_binormals[i]); + + uint t = m_vertices.size()-1; + for (uint h=0; h<smList[j].size(); h++) + { + if (m_tris[smList[j][h]].a == i) + m_tris[smList[j][h]].a = t; + if (m_tris[smList[j][h]].b == i) + m_tris[smList[j][h]].b = t; + if (m_tris[smList[j][h]].c == i) + m_tris[smList[j][h]].c = t; + } + } + } + + // now rebuild a face list for each vertex, since the old one is invalidated + for (i=0; i<array.size(); i++) + array[i].clear(); + array.clear(); + array.resize(m_vertices.size()); + for (i=0; i<m_triangles.size(); i++) + { + uint k = m_tris[i].a; + array[k].push_back(i); + + k = m_tris[i].b; + array[k].push_back(i); + + k = m_tris[i].c; + array[k].push_back(i); + } + + // now compute the normals + for (i=0; i<m_vertices.size(); i++) + { + temp = zero3; + int t = array[i].size(); + + for (int k=0; k<t; k++) + { + temp.x += m_tris[array[i][k]].normal.x; + temp.y += m_tris[array[i][k]].normal.y; + temp.z += m_tris[array[i][k]].normal.z; + } + m_normals[i] = NormalizeVector(temp); + } + + } + + // copy m_tris to m_triangles + for (i=0; i<m_triangles.size(); i++) + { + m_triangles[i].a = m_tris[i].a; + m_triangles[i].b = m_tris[i].b; + m_triangles[i].c = m_tris[i].c; + } + +} + +void LMesh::CalcTextureSpace() +{ + // a understandable description of how to do that can be found here: + // http://members.rogers.com/deseric/tangentspace.htm + // first calculate the tangent for each triangle + LVector3 x_vec, + y_vec, + z_vec; + LVector3 v1, v2; + for (uint i=0; i<m_triangles.size(); i++) + { + v1.x = m_vertices[m_tris[i].b].x - m_vertices[m_tris[i].a].x; + v1.y = m_uv[m_tris[i].b].x - m_uv[m_tris[i].a].x; + v1.z = m_uv[m_tris[i].b].y - m_uv[m_tris[i].a].y; + + v2.x = m_vertices[m_tris[i].c].x - m_vertices[m_tris[i].a].x; + v2.y = m_uv[m_tris[i].c].x - m_uv[m_tris[i].a].x; + v2.z = m_uv[m_tris[i].c].y - m_uv[m_tris[i].a].y; + + x_vec = CrossProduct(v1, v2); + + v1.x = m_vertices[m_tris[i].b].y - m_vertices[m_tris[i].a].y; + v1.y = m_uv[m_tris[i].b].x - m_uv[m_tris[i].a].x; + v1.z = m_uv[m_tris[i].b].y - m_uv[m_tris[i].a].y; + + v2.x = m_vertices[m_tris[i].c].y - m_vertices[m_tris[i].a].y; + v2.y = m_uv[m_tris[i].c].x - m_uv[m_tris[i].a].x; + v2.z = m_uv[m_tris[i].c].y - m_uv[m_tris[i].a].y; + + y_vec = CrossProduct(v1, v2); + + v1.x = m_vertices[m_tris[i].b].z - m_vertices[m_tris[i].a].z; + v1.y = m_uv[m_tris[i].b].x - m_uv[m_tris[i].a].x; + v1.z = m_uv[m_tris[i].b].y - m_uv[m_tris[i].a].y; + + v2.x = m_vertices[m_tris[i].c].z - m_vertices[m_tris[i].a].z; + v2.y = m_uv[m_tris[i].c].x - m_uv[m_tris[i].a].x; + v2.z = m_uv[m_tris[i].c].y - m_uv[m_tris[i].a].y; + + z_vec = CrossProduct(v1, v2); + + m_tris[i].tangent.x = -(x_vec.y/x_vec.x); + m_tris[i].tangent.y = -(y_vec.y/y_vec.x); + m_tris[i].tangent.z = -(z_vec.y/z_vec.x); + + m_tris[i].binormal.x = -(x_vec.z/x_vec.x); + m_tris[i].binormal.y = -(y_vec.z/y_vec.x); + m_tris[i].binormal.z = -(z_vec.z/z_vec.x); + + } + + // now for each vertex build a list of face that share this vertex + std::vector< std::vector<int> > array; + array.resize(m_vertices.size()); + for (int i=0; i<(int)m_triangles.size(); i++) + { + uint k = m_tris[i].a; + array[k].push_back(i); + + k = m_tris[i].b; + array[k].push_back(i); + + k = m_tris[i].c; + array[k].push_back(i); + } + + // now average the tangents and compute the binormals as (tangent X normal) + for (int i=0; i<(int)m_vertices.size(); i++) + { + v1 = zero3; + v2 = zero3; + int t = array[i].size(); + + for (int k=0; k<t; k++) + { + v1.x += m_tris[array[i][k]].tangent.x; + v1.y += m_tris[array[i][k]].tangent.y; + v1.z += m_tris[array[i][k]].tangent.z; + + v2.x += m_tris[array[i][k]].binormal.x; + v2.y += m_tris[array[i][k]].binormal.y; + v2.z += m_tris[array[i][k]].binormal.z; + } + m_tangents[i] = NormalizeVector(v1); + //m_binormals[i] = NormalizeVector(v2); + + m_binormals[i] = NormalizeVector(CrossProduct(m_tangents[i], m_normals[i])); + } +} + +void LMesh::Optimize(LOptimizationLevel value) +{ + switch (value) + { + case oNone: + TransformVertices(); + break; + case oSimple: + TransformVertices(); + CalcNormals(false); + break; + case oFull: + TransformVertices(); + CalcNormals(true); + CalcTextureSpace(); + break; + } +} + +void LMesh::SetTri(const LTri &tri, uint index) +{ + if (index >= m_triangles.size()) + return; + m_tris[index] = tri; +} + +LTri& LMesh::GetTri(uint index) +{ + return m_tris[index]; +} + +uint LMesh::GetMaterial(uint index) +{ + return m_materials[index]; +} + +uint LMesh::AddMaterial(uint id) +{ + m_materials.push_back(id); + return m_materials.size()-1; +} + +uint LMesh::GetMaterialCount() +{ + return m_materials.size(); +} + +//------------------------------------------------------- +// LLight implementation +//------------------------------------------------------- + +LLight::LLight() +: LObject() +{ + Clear(); +} + +LLight::~LLight() +{ + +} + +void LLight::Clear() +{ + m_pos.x = m_pos.y = m_pos.z = 0.0f; + m_color.r = m_color.g = m_color.b = 0.0f; + m_spotlight = false; +} + +void LLight::SetPosition(LVector3 vec) +{ + m_pos = vec; +} + +LVector3 LLight::GetPosition() +{ + return m_pos; +} + +void LLight::SetColor(LColor3 color) +{ + m_color = color; +} + +LColor3 LLight::GetColor() +{ + return m_color; +} + +void LLight::SetSpotlight(bool value) +{ + m_spotlight = value; +} + +bool LLight::GetSpotlight() +{ + return m_spotlight; +} + +void LLight::SetTarget(LVector3 target) +{ + m_target = target; +} + +LVector3 LLight::GetTarget() +{ + return m_target; +} + +void LLight::SetHotspot(float value) +{ + m_hotspot = value; +} + +float LLight::GetHotspot() +{ + return m_hotspot; +} + +void LLight::SetFalloff(float value) +{ + m_falloff = value; +} + +float LLight::GetFalloff() +{ + return m_falloff; +} + +//------------------------------------------------------- +// LImporter implementation +//------------------------------------------------------- + +LImporter::LImporter() +{ + Clear(); +} + +LImporter::~LImporter() +{ + Clear(); +} + +uint LImporter::GetMeshCount() +{ + return m_meshes.size(); +} + +uint LImporter::GetLightCount() +{ + return m_lights.size(); +} + +uint LImporter::GetMaterialCount() +{ + return m_materials.size(); +} + +LMesh& LImporter::GetMesh(uint index) +{ + return m_meshes[index]; +} + +LLight& LImporter::GetLight(uint index) +{ + return m_lights[index]; +} + +LMaterial& LImporter::GetMaterial(uint index) +{ + return m_materials[index]; +} + +LMaterial* LImporter::FindMaterial(const std::string& name) +{ + for (uint i=0; i<m_materials.size(); i++) + if (m_materials[i].IsObject(name)) + return &m_materials[i]; + return 0; +} + +LMesh* LImporter::FindMesh(const std::string& name) +{ + for (uint i=0; i<m_meshes.size(); i++) + if (m_meshes[i].IsObject(name)) + return &m_meshes[i]; + return 0; +} + +LLight* LImporter::FindLight(const std::string& name) +{ + for (uint i=0; i<m_lights.size(); i++) + if (m_lights[i].IsObject(name)) + return &m_lights[i]; + return 0; +} + +void LImporter::Clear() +{ + m_meshes.clear(); + m_lights.clear(); + m_materials.clear(); + m_optLevel = oFull; +} + +void LImporter::SetOptimizationLevel(LOptimizationLevel value) +{ + m_optLevel = value; +} + +LOptimizationLevel LImporter::GetOptimizationLevel() +{ + return m_optLevel; +} + +//------------------------------------------------------- +// L3DS implementation +//------------------------------------------------------- + +L3DS::L3DS() +: LImporter() +{ + m_buffer = 0; + m_bufferSize = 0; + m_pos = 0; + m_eof = false; +} + +L3DS::L3DS(const char *filename) +: LImporter() +{ + m_buffer = 0; + m_bufferSize = 0; + m_pos = 0; + m_eof = false; + LoadFile(filename); +} + +L3DS::~L3DS() +{ + if (m_bufferSize > 0) + free(m_buffer); +} + +bool L3DS::LoadFile(const char *filename) +{ + FILE *f; + f = fopen(filename, "rb"); + if (f == 0) + { + ErrorMsg("L3DS::LoadFile - cannot open file"); + return false; + } + fseek(f, 0, SEEK_END); + m_bufferSize = ftell(f); + fseek(f, 0, SEEK_SET); + m_buffer = (unsigned char*) calloc(m_bufferSize, 1); + if (m_buffer == 0) + { + ErrorMsg("L3DS::LoadFile - not enough memory (malloc failed)"); + return false; + } + if (fread(m_buffer, m_bufferSize, 1, f) != 1) + { + fclose(f); + free(m_buffer); + m_bufferSize = 0; + ErrorMsg("L3DS::LoadFile - error reading from file"); + return false; + } + fclose(f); + Clear(); + bool res = Read3DS(); + free(m_buffer); + m_buffer = 0; + m_bufferSize = 0; + return res; +} + +short L3DS::ReadShort() +{ + if ((m_buffer!=0) && (m_bufferSize != 0) && ((m_pos+2)<m_bufferSize)) + { + short *w = (short*)(m_buffer+m_pos); + short s = *w;//(short)*(m_buffer+m_pos); + m_pos += 2; + return s; + } + m_eof = true; + return 0; +} + +int L3DS::ReadInt() +{ + if ((m_buffer!=0) && (m_bufferSize != 0) && ((m_pos+4)<m_bufferSize)) + { + int *w = (int*)(m_buffer+m_pos); + int s = *w;//(int)*(m_buffer+m_pos); + m_pos += 4; + return s; + } + m_eof = true; + return 0; +} + +char L3DS::ReadChar() +{ + if ((m_buffer!=0) && (m_bufferSize != 0) && ((m_pos+1)<m_bufferSize)) + { + char s = (char)*(m_buffer+m_pos); + m_pos += 1; + return s; + } + m_eof = true; + return 0; +} + +float L3DS::ReadFloat() +{ + if ((m_buffer!=0) && (m_bufferSize != 0) && ((m_pos+4)<m_bufferSize)) + { + float *w = (float*)(m_buffer+m_pos); + float s = *w;//(float)*(m_buffer+m_pos); + m_pos += 4; + return s; + } + m_eof = true; + return 0.0; +} + +byte L3DS::ReadByte() +{ + if ((m_buffer!=0) && (m_bufferSize != 0) && ((m_pos+1)<m_bufferSize)) + { + byte s = (byte)*(m_buffer+m_pos); + m_pos += 1; + return s; + } + m_eof = true; + return 0; +} + +int L3DS::ReadASCIIZ(char *buf, int max_count) +{ + int count; + if ((m_buffer==0) || (m_bufferSize == 0) || (m_pos>=m_bufferSize)) + { + count = 0; + m_eof = true; + return count; + } + count = 0; + char c = ReadChar(); + while ((c!=0) && (count<max_count-1)) + { + buf[count] = c; + count ++; + c = ReadChar(); + } + buf[count] = 0; + return count; +} + +void L3DS::Seek(int offset, int origin) +{ + if (origin == SEEK_START) + m_pos = offset; + if (origin == SEEK_CURSOR) + m_pos += offset; + if (m_pos >= m_bufferSize) + m_pos = m_bufferSize-1; + m_eof = false; +} + +uint L3DS::Pos() +{ + return m_pos; +} + +LChunk L3DS::ReadChunk() +{ + LChunk chunk; + chunk.id = ReadShort(); + int a = ReadInt(); + chunk.start = Pos(); + chunk.end = chunk.start+a-6; + return chunk; +} + +bool L3DS::FindChunk(LChunk &target, const LChunk &parent) +{ + if (Pos() >= parent.end) + return false; + LChunk chunk; + chunk = ReadChunk(); + while (( chunk.id != target.id) && (chunk.end <= parent.end)) + { + SkipChunk(chunk); + if (chunk.end >= parent.end) + break; + chunk = ReadChunk(); + } + if (chunk.id == target.id) + { + target.start = chunk.start; + target.end = chunk.end; + return true; + } + return false; +} + +void L3DS::SkipChunk(const LChunk &chunk) +{ + Seek(chunk.end, SEEK_START); +} + +void L3DS::GotoChunk(const LChunk &chunk) +{ + Seek(chunk.start, SEEK_START); +} + +LColor3 L3DS::ReadColor(const LChunk &chunk) +{ + LColor3 col = black; + GotoChunk(chunk); + switch (chunk.id) + { + case COLOR_F: + col.r = ReadFloat(); + col.g = ReadFloat(); + col.b = ReadFloat(); + break; + case COLOR_24: + col.r = ReadByte()/255.0f; + col.g = ReadByte()/255.0f; + col.b = ReadByte()/255.0f; + break; + case LIN_COLOR_F: + col.r = ReadFloat(); + col.g = ReadFloat(); + col.b = ReadFloat(); + break; + case LIN_COLOR_24: + col.r = ReadByte()/255.0f; + col.g = ReadByte()/255.0f; + col.b = ReadByte()/255.0f; + break; + default: + ErrorMsg("L3DS::ReadColor - error this is not a color chunk"); + } + return col; +} + +float L3DS::ReadPercentage(const LChunk &chunk) +{ + GotoChunk(chunk); + switch (chunk.id) + { + case INT_PERCENTAGE: + return (ReadShort()/100.0f); + case FLOAT_PERCENTAGE: + return ReadFloat(); + } + ErrorMsg("L3DS::ReadPercentage - error, the chunk is not a percentage chunk"); + return 0; +} + +bool L3DS::Read3DS() +{ + LChunk mainchunk; + LChunk edit; + edit.id = EDIT3DS; + mainchunk = ReadChunk(); + if (mainchunk.id != MAIN3DS) + { + ErrorMsg("L3DS::Read3DS - wrong file format"); + return false; + } + if (!FindChunk(edit, mainchunk)) + return false; + LChunk obj; + LChunk ml; + + GotoChunk(edit); + obj.id = MAT_ENTRY; + while (FindChunk(obj, edit)) + { + ReadMaterial(obj); + SkipChunk(obj); + } + GotoChunk(edit); + + obj.id = EDIT_OBJECT; + { + while (FindChunk(obj, edit)) + { + ReadASCIIZ(m_objName, 99); + ml = ReadChunk(); + if (ml.id == OBJ_TRIMESH) + ReadMesh(ml); + if (ml.id == OBJ_LIGHT) + ReadLight(ml); + SkipChunk(obj); + } + } + + // read the keyframer data here to find out correct object orientation + + LChunk keyframer; + keyframer.id = KFDATA; + + LChunk objtrack; + objtrack.id = OBJECT_NODE_TAG; + + GotoChunk(mainchunk); + if (FindChunk(keyframer, mainchunk)) + { // keyframer chunk is present + GotoChunk(keyframer); + while (FindChunk(objtrack, keyframer)) + { + ReadKeyframeData(objtrack); + SkipChunk(objtrack); + } + } + + for (uint i=0; i<m_meshes.size(); i++) { + m_meshes[i].Optimize(m_optLevel); + } + + m_pos = 0; + strcpy(m_objName, ""); + return true; +} + +void L3DS::ReadLight(const LChunk &parent) +{ + float t; + LVector3 v; + LLight light; + light.SetName(m_objName); + GotoChunk(parent); + LChunk chunk = ReadChunk(); + if (chunk.id == OBJ_LIGHT) + { + v.x = ReadFloat(); + v.y = ReadFloat(); + v.z = ReadFloat(); + if (chunk.end < parent.end) + chunk = ReadChunk(); + while (chunk.end <= parent.end) + { + switch (chunk.id) + { + case COLOR_24: + case COLOR_F: + case LIN_COLOR_F: + case LIN_COLOR_24: + light.SetColor(ReadColor(chunk)); + break; + case SPOTLIGHT: + v.x = ReadFloat(); + v.y = ReadFloat(); + v.z = ReadFloat(); + light.SetTarget(v); + t = ReadFloat(); + light.SetHotspot(t); + t = ReadFloat(); + light.SetFalloff(t); + break; + default: + break; + } + SkipChunk(chunk); + if (chunk.end >= parent.end) + break; + chunk = ReadChunk(); + + } + } + m_lights.push_back(light); +} + +void L3DS::ReadMesh(const LChunk &parent) +{ + unsigned short count, i; + LVector4 p; + LMatrix4 m; + LVector2 t; + p.w = 1.0f; + LMesh mesh; + mesh.SetName(m_objName); + GotoChunk(parent); + LChunk chunk = ReadChunk(); + while (chunk.end <= parent.end) + { + switch (chunk.id) + { + case TRI_VERTEXLIST: + count = ReadShort(); + mesh.SetVertexArraySize(count); + for (i=0; i < count; i++) + { + p.x = ReadFloat(); + p.y = ReadFloat(); + p.z = ReadFloat(); + mesh.SetVertex(p, i); + } + break; + case TRI_FACEMAPPING: + count = ReadShort(); + if (mesh.GetVertexCount() == 0) + mesh.SetVertexArraySize(count); + for (i=0; i < count; i++) + { + t.x = ReadFloat(); + t.y = ReadFloat(); + mesh.SetUV(t, i); + } + break; + case TRI_FACELIST: + ReadFaceList(chunk, mesh); + break; + case TRI_MATRIX: + { + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + m.m[i][j] = ReadFloat(); + + m.m[0][3] = 0.0f; + m.m[1][3] = 0.0f; + m.m[2][3] = 0.0f; + m.m[3][3] = 1.0f; + + mesh.SetMatrix(m); + } + break; + default: + break; + } + SkipChunk(chunk); + if (chunk.end >= parent.end) + break; + chunk = ReadChunk(); + } + m_meshes.push_back(mesh); +} + +void L3DS::ReadFaceList(const LChunk &chunk, LMesh &mesh) +{ + // variables + unsigned short count, t; + uint i; + LTri tri; + LChunk ch; + char str[20]; + //uint mat; + + // consistency checks + if (chunk.id != TRI_FACELIST) + { + ErrorMsg("L3DS::ReadFaceList - internal error: wrong chunk passed as parameter"); + return; + } + GotoChunk(chunk); + tri.smoothingGroups = 1; + // read the number of faces + count = ReadShort(); + mesh.SetTriangleArraySize(count); + for (i=0; i<count; i++) + { + tri.a = ReadShort(); + tri.b = ReadShort(); + tri.c = ReadShort(); + ReadShort(); + mesh.SetTri(tri, i); + } + // now read the optional chunks + ch = ReadChunk(); + while (ch.end <= chunk.end) + { + switch (ch.id) + { + case TRI_MAT_GROUP: { + ReadASCIIZ(str, 20); + int mat_id = FindMaterial(str)->GetID(); + mesh.AddMaterial(mat_id); + count = ReadShort(); + for (i=0; i<count; i++) { + t = ReadShort(); + mesh.GetTri(t).materialId = mat_id; + } + } + break; + + case TRI_SMOOTH_GROUP: + for (i=0; i<mesh.GetTriangleCount(); i++) + mesh.GetTri(i).smoothingGroups = (ulong) ReadInt(); + break; + } + SkipChunk(ch); + ch = ReadChunk(); + } +} + +void L3DS::ReadMaterial(const LChunk &parent) +{ + // variables + LChunk chunk; + LChunk child; + char str[30]; + LMaterial mat; + short sh; + + GotoChunk(parent); + + chunk = ReadChunk(); + while (chunk.end <= parent.end) + { + switch (chunk.id) + { + case MAT_NAME: + ReadASCIIZ(str, 30); + mat.SetName(str); + break; + case MAT_AMBIENT: + child = ReadChunk(); + mat.SetAmbientColor(ReadColor(child)); + break; + case MAT_DIFFUSE: + child = ReadChunk(); + mat.SetDiffuseColor(ReadColor(child)); + break; + case MAT_SPECULAR: + child = ReadChunk(); + mat.SetSpecularColor(ReadColor(child)); + break; + case MAT_SHININESS: + child = ReadChunk(); + mat.SetShininess(ReadPercentage(child)); + break; + case MAT_TRANSPARENCY: + child = ReadChunk(); + mat.SetTransparency(ReadPercentage(child)); + break; + case MAT_SHADING: + sh = ReadShort(); + switch (sh) + { + case 0: + mat.SetShadingType(sWireframe); + break; + case 1: + mat.SetShadingType(sFlat); + break; + case 2: + mat.SetShadingType(sGouraud); + break; + case 3: + mat.SetShadingType(sPhong); + break; + case 4: + mat.SetShadingType(sMetal); + break; + } + break; + case MAT_WIRE: + mat.SetShadingType(sWireframe); + break; + case MAT_TEXMAP: + ReadMap(chunk, mat.GetTextureMap1()); + break; + case MAT_TEX2MAP: + ReadMap(chunk, mat.GetTextureMap2()); + break; + case MAT_OPACMAP: + ReadMap(chunk, mat.GetOpacityMap()); + break; + case MAT_BUMPMAP: + ReadMap(chunk, mat.GetBumpMap()); + break; + case MAT_SPECMAP: + ReadMap(chunk, mat.GetSpecularMap()); + break; + case MAT_REFLMAP: + child = ReadChunk(); + mat.GetReflectionMap().strength = ReadPercentage(child); + SkipChunk(child); + child = ReadChunk(); + if (child.id != MAT_MAPNAME) + { + ErrorMsg("L3DS::ReadMaterial - error, expected chunk not found"); + return; + } + ReadASCIIZ(str, 30); + if (strcmp(str, "") == 0) + strcpy(mat.GetReflectionMap().mapName, "auto"); + break; + } + + SkipChunk(chunk); + chunk = ReadChunk(); + } + m_materials.push_back(mat); + m_materials[m_materials.size()-1].SetID(m_materials.size()-1); +} + +void L3DS::ReadMap(const LChunk &chunk, LMap& map) +{ + LChunk child; + char str[20]; + GotoChunk(chunk); + child = ReadChunk(); + while (child.end <= chunk.end) + { + switch (child.id) + { + case INT_PERCENTAGE: + map.strength = ReadPercentage(child); + break; + case MAT_MAPNAME: + ReadASCIIZ(str, 20); + strcpy(map.mapName, str); + break; + case MAT_MAP_USCALE: + map.uScale = ReadFloat(); + break; + case MAT_MAP_VSCALE: + map.vScale = ReadFloat(); + break; + case MAT_MAP_UOFFSET: + map.uOffset = ReadFloat(); + break; + case MAT_MAP_VOFFSET: + map.vOffset = ReadFloat(); + break; + case MAT_MAP_ANG: + map.angle = ReadFloat(); + break; + } + SkipChunk(child); + child = ReadChunk(); + } +} + +void L3DS::ReadKeyframeData(const LChunk &parent) +{ + uint frames = 0; + + LChunk node_hdr; + node_hdr.id = NODE_HDR; + + char str[20]; + LMesh *mesh; + + GotoChunk(parent); + if (!FindChunk(node_hdr, parent)) + return; + GotoChunk(node_hdr); + ReadASCIIZ(str, 19); + mesh = FindMesh(str); + if (mesh == 0) + return; + GotoChunk(parent); + + // read the pivot + LVector3 pivot = zero3; + + LChunk pivotchunk; + pivotchunk.id = PIVOT; + if (FindChunk(pivotchunk, parent)) + { + GotoChunk(pivotchunk); + pivot.x = ReadFloat(); + pivot.y = ReadFloat(); + pivot.z = ReadFloat(); + } + GotoChunk(parent); + + // read frame 0 from the position track + LVector3 pos = zero3; + + frames = 0; + + LChunk poschunk; + poschunk.id = POS_TRACK_TAG; + if (FindChunk(poschunk, parent)) + { + GotoChunk(poschunk); + // read the trackheader structure + ReadShort(); + ReadInt(); + ReadInt(); + frames = ReadInt(); + if (frames > 0) + { + ReadKeyheader(); + pos.x = ReadFloat(); + pos.y = ReadFloat(); + pos.z = ReadFloat(); + } + } + GotoChunk(parent); + + // now read the rotation track + LVector4 rot = zero4; + + LChunk rotchunk; + rotchunk.id = ROT_TRACK_TAG; + + frames = 0; + if (FindChunk(rotchunk, parent)) + { + GotoChunk(rotchunk); + // read the trackheader structure + ReadShort(); + ReadInt(); + ReadInt(); + frames = ReadInt(); + if (frames > 0) + { + ReadKeyheader(); + rot.x = ReadFloat(); + rot.y = ReadFloat(); + rot.z = ReadFloat(); + rot.w = ReadFloat(); + } + } + GotoChunk(parent); + + // now read the scaling chunk + LVector3 scale; + scale.x = 1; + scale.y = 1; + scale.z = 1; + + LChunk scalechunk; + scalechunk.id = SCL_TRACK_TAG; + + frames = 0; + + if (FindChunk(scalechunk, parent)) + { + GotoChunk(scalechunk); + // read the trackheader structure + ReadShort(); + ReadInt(); + ReadInt(); + frames = ReadInt(); + if (frames > 0) + { + ReadKeyheader(); + scale.x = ReadFloat(); + scale.y = ReadFloat(); + scale.z = ReadFloat(); + } + } + GotoChunk(parent); + + +} + +long L3DS::ReadKeyheader() +{ + long frame; + frame = ReadInt(); + short opts = ReadShort(); + if (opts & 32768) // 32768 is 1000000000000000 binary + { // tension is present + ReadFloat(); + } + if (opts & 16384) // 16384 is 0100000000000000 binary + { // continuity is present + ReadFloat(); + } + if (opts & 8192) + { // bias info present + ReadFloat(); + } + if (opts & 4096) + { // "ease to" present + ReadFloat(); + } + if (opts & 2048) + { // "ease from" present + ReadFloat(); + } + return frame; +}
\ No newline at end of file |