mirror of
https://github.com/leozide/leocad
synced 2024-12-27 21:58:37 +01:00
1699 lines
52 KiB
C++
1699 lines
52 KiB
C++
#include "lc_global.h"
|
|
#include "lc_meshloader.h"
|
|
#include "lc_file.h"
|
|
#include "lc_colors.h"
|
|
#include "lc_library.h"
|
|
#include "lc_application.h"
|
|
#include "lc_texture.h"
|
|
|
|
static lcVector2 lcCalculateTexCoord(const lcVector3& Position, const lcLibraryTextureMap* TextureMap)
|
|
{
|
|
switch (TextureMap->Type)
|
|
{
|
|
case lcLibraryTextureMapType::PLANAR:
|
|
return lcVector2(lcDot3(Position, TextureMap->Params.Planar.Planes[0]) + TextureMap->Params.Planar.Planes[0].w, lcDot3(Position, TextureMap->Params.Planar.Planes[1]) + TextureMap->Params.Planar.Planes[1].w);
|
|
|
|
case lcLibraryTextureMapType::CYLINDRICAL:
|
|
{
|
|
const lcVector4& FrontPlane = TextureMap->Params.Cylindrical.FrontPlane;
|
|
const lcVector4& Plane1 = TextureMap->Params.Cylindrical.Plane1;
|
|
const lcVector4& Plane2 = TextureMap->Params.Cylindrical.Plane2;
|
|
lcVector2 TexCoord;
|
|
|
|
float DotPlane1 = lcDot(lcVector4(Position, 1.0f), Plane1);
|
|
lcVector3 PointInPlane1 = Position - lcVector3(Plane1) * DotPlane1;
|
|
float DotFrontPlane = lcDot(lcVector4(PointInPlane1, 1.0f), FrontPlane);
|
|
float DotPlane2 = lcDot(lcVector4(PointInPlane1, 1.0f), Plane2);
|
|
|
|
float Angle1 = atan2f(DotPlane2, DotFrontPlane) / LC_PI * TextureMap->Angle1;
|
|
TexCoord.x = lcClamp(0.5f + 0.5f * Angle1, 0.0f, 1.0f);
|
|
|
|
TexCoord.y = DotPlane1 / TextureMap->Params.Cylindrical.UpLength;
|
|
|
|
return TexCoord;
|
|
}
|
|
|
|
case lcLibraryTextureMapType::SPHERICAL:
|
|
{
|
|
const lcVector4& FrontPlane = TextureMap->Params.Spherical.FrontPlane;
|
|
const lcVector3& Center = TextureMap->Params.Spherical.Center;
|
|
const lcVector4& Plane1 = TextureMap->Params.Spherical.Plane1;
|
|
const lcVector4& Plane2 = TextureMap->Params.Spherical.Plane2;
|
|
lcVector2 TexCoord;
|
|
|
|
lcVector3 VertexDir = Position - Center;
|
|
|
|
float DotPlane1 = lcDot(lcVector4(Position, 1.0f), Plane1);
|
|
lcVector3 PointInPlane1 = Position - lcVector3(Plane1) * DotPlane1;
|
|
float DotFrontPlane = lcDot(lcVector4(PointInPlane1, 1.0f), FrontPlane);
|
|
float DotPlane2 = lcDot(lcVector4(PointInPlane1, 1.0f), Plane2);
|
|
|
|
float Angle1 = atan2f(DotPlane2, DotFrontPlane) / LC_PI * TextureMap->Angle1;
|
|
TexCoord.x = 0.5f + 0.5f * Angle1;
|
|
|
|
float Angle2 = asinf(DotPlane1 / lcLength(VertexDir)) / LC_PI * TextureMap->Angle2;
|
|
TexCoord.y = 0.5f - Angle2;
|
|
|
|
return TexCoord;
|
|
}
|
|
}
|
|
|
|
return lcVector2(0.0f, 0.0f);
|
|
}
|
|
|
|
void lcLibraryMeshData::ResequenceQuad(int* Indices, int a, int b, int c, int d)
|
|
{
|
|
Indices[0] = a;
|
|
Indices[1] = b;
|
|
Indices[2] = c;
|
|
Indices[3] = d;
|
|
}
|
|
|
|
void lcLibraryMeshData::TestQuad(int* QuadIndices, const lcVector3* Vertices)
|
|
{
|
|
lcVector3 v01 = Vertices[1] - Vertices[0];
|
|
lcVector3 v02 = Vertices[2] - Vertices[0];
|
|
lcVector3 v03 = Vertices[3] - Vertices[0];
|
|
lcVector3 cp1 = lcCross(v01, v02);
|
|
lcVector3 cp2 = lcCross(v02, v03);
|
|
|
|
if (lcDot(cp1, cp2) > 0.0f)
|
|
return;
|
|
|
|
lcVector3 v12 = Vertices[2] - Vertices[1];
|
|
lcVector3 v13 = Vertices[3] - Vertices[1];
|
|
lcVector3 v23 = Vertices[3] - Vertices[2];
|
|
|
|
if (lcDot(lcCross(v12, v01), lcCross(v01, v13)) > 0.0f)
|
|
{
|
|
if (-lcDot(lcCross(v02, v12), lcCross(v12, v23)) > 0.0f)
|
|
ResequenceQuad(QuadIndices, 1, 2, 3, 0);
|
|
else
|
|
ResequenceQuad(QuadIndices, 0, 3, 1, 2);
|
|
}
|
|
else
|
|
{
|
|
if (-lcDot(lcCross(v02, v12), lcCross(v12, v23)) > 0.0f)
|
|
ResequenceQuad(QuadIndices, 0, 1, 3, 2);
|
|
else
|
|
ResequenceQuad(QuadIndices, 1, 2, 3, 0);
|
|
}
|
|
}
|
|
|
|
lcLibraryMeshSection* lcLibraryMeshData::AddSection(lcMeshDataType MeshDataType, lcMeshPrimitiveType PrimitiveType, quint32 ColorCode, lcTexture* Texture)
|
|
{
|
|
lcArray<lcLibraryMeshSection*>& Sections = mSections[MeshDataType];
|
|
lcLibraryMeshSection* Section;
|
|
|
|
for (int SectionIdx = 0; SectionIdx < Sections.GetSize(); SectionIdx++)
|
|
{
|
|
Section = Sections[SectionIdx];
|
|
|
|
if (Section->mColor == ColorCode && Section->mPrimitiveType == PrimitiveType && Section->mTexture == Texture)
|
|
return Section;
|
|
}
|
|
|
|
Section = new lcLibraryMeshSection(PrimitiveType, ColorCode, Texture);
|
|
Sections.Add(Section);
|
|
|
|
return Section;
|
|
}
|
|
|
|
void lcLibraryMeshData::AddVertices(lcMeshDataType MeshDataType, int VertexCount, int* BaseVertex, lcLibraryMeshVertex** VertexBuffer)
|
|
{
|
|
lcArray<lcLibraryMeshVertex>& Vertices = mVertices[MeshDataType];
|
|
int CurrentSize = Vertices.GetSize();
|
|
|
|
Vertices.SetSize(CurrentSize + VertexCount);
|
|
|
|
*BaseVertex = CurrentSize;
|
|
*VertexBuffer = &Vertices[CurrentSize];
|
|
}
|
|
|
|
const float lcDistanceEpsilon = 0.01f; // Maximum value for 50591.dat
|
|
const float lcTexCoordEpsilon = 0.01f;
|
|
|
|
inline bool lcCompareVertices(const lcVector3& Position1, const lcVector3& Position2)
|
|
{
|
|
return fabsf(Position1.x - Position2.x) < lcDistanceEpsilon && fabsf(Position1.y - Position2.y) < lcDistanceEpsilon && fabsf(Position1.z - Position2.z) < lcDistanceEpsilon;
|
|
}
|
|
|
|
inline bool lcCompareVertices(const lcVector3& Position1, const lcVector2& TexCoord1, const lcVector3& Position2, const lcVector2& TexCoord2)
|
|
{
|
|
return fabsf(Position1.x - Position2.x) < lcDistanceEpsilon && fabsf(Position1.y - Position2.y) < lcDistanceEpsilon && fabsf(Position1.z - Position2.z) < lcDistanceEpsilon &&
|
|
fabsf(TexCoord1.x - TexCoord2.x) < lcTexCoordEpsilon && fabsf(TexCoord1.y - TexCoord2.y) < lcTexCoordEpsilon;
|
|
}
|
|
|
|
quint32 lcLibraryMeshData::AddVertex(lcMeshDataType MeshDataType, const lcVector3& Position, bool Optimize)
|
|
{
|
|
lcArray<lcLibraryMeshVertex>& VertexArray = mVertices[MeshDataType];
|
|
|
|
if (Optimize)
|
|
{
|
|
for (int VertexIdx = VertexArray.GetSize() - 1; VertexIdx >= 0; VertexIdx--)
|
|
{
|
|
lcLibraryMeshVertex& Vertex = VertexArray[VertexIdx];
|
|
|
|
if (lcCompareVertices(Position, Vertex.Position))
|
|
{
|
|
Vertex.Usage |= LC_LIBRARY_VERTEX_UNTEXTURED;
|
|
return VertexIdx;
|
|
}
|
|
}
|
|
}
|
|
|
|
lcLibraryMeshVertex& Vertex = VertexArray.Add();
|
|
Vertex.Position = Position;
|
|
Vertex.Normal = lcVector3(0.0f, 0.0f, 0.0f);
|
|
Vertex.NormalWeight = 0.0f;
|
|
Vertex.TexCoord = lcVector2(0.0f, 0.0f);
|
|
Vertex.Usage = LC_LIBRARY_VERTEX_UNTEXTURED;
|
|
|
|
return VertexArray.GetSize() - 1;
|
|
}
|
|
|
|
quint32 lcLibraryMeshData::AddVertex(lcMeshDataType MeshDataType, const lcVector3& Position, const lcVector3& Normal, bool Optimize)
|
|
{
|
|
lcArray<lcLibraryMeshVertex>& VertexArray = mVertices[MeshDataType];
|
|
|
|
if (Optimize)
|
|
{
|
|
for (int VertexIdx = VertexArray.GetSize() - 1; VertexIdx >= 0; VertexIdx--)
|
|
{
|
|
lcLibraryMeshVertex& Vertex = VertexArray[VertexIdx];
|
|
|
|
if (lcCompareVertices(Position, Vertex.Position))
|
|
{
|
|
if (Vertex.NormalWeight == 0.0f)
|
|
{
|
|
Vertex.Normal = Normal;
|
|
Vertex.NormalWeight = 1.0f;
|
|
Vertex.Usage |= LC_LIBRARY_VERTEX_UNTEXTURED;
|
|
return VertexIdx;
|
|
}
|
|
else if (lcDot(Normal, Vertex.Normal) > 0.707f)
|
|
{
|
|
Vertex.Normal = lcNormalize(Vertex.Normal * Vertex.NormalWeight + Normal);
|
|
Vertex.NormalWeight += 1.0f;
|
|
Vertex.Usage |= LC_LIBRARY_VERTEX_UNTEXTURED;
|
|
return VertexIdx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lcLibraryMeshVertex& Vertex = VertexArray.Add();
|
|
Vertex.Position = Position;
|
|
Vertex.Normal = Normal;
|
|
Vertex.NormalWeight = 1.0f;
|
|
Vertex.TexCoord = lcVector2(0.0f, 0.0f);
|
|
Vertex.Usage = LC_LIBRARY_VERTEX_UNTEXTURED;
|
|
|
|
return VertexArray.GetSize() - 1;
|
|
}
|
|
|
|
quint32 lcLibraryMeshData::AddTexturedVertex(lcMeshDataType MeshDataType, const lcVector3& Position, const lcVector2& TexCoord, bool Optimize)
|
|
{
|
|
mHasTextures = true;
|
|
|
|
lcArray<lcLibraryMeshVertex>& VertexArray = mVertices[MeshDataType];
|
|
|
|
if (Optimize)
|
|
{
|
|
for (int VertexIdx = VertexArray.GetSize() - 1; VertexIdx >= 0; VertexIdx--)
|
|
{
|
|
lcLibraryMeshVertex& Vertex = VertexArray[VertexIdx];
|
|
|
|
if (Vertex.Usage & LC_LIBRARY_VERTEX_TEXTURED)
|
|
{
|
|
if (lcCompareVertices(Position, TexCoord, Vertex.Position, Vertex.TexCoord))
|
|
return VertexIdx;
|
|
}
|
|
else
|
|
{
|
|
if (lcCompareVertices(Position, Vertex.Position))
|
|
{
|
|
Vertex.TexCoord = TexCoord;
|
|
Vertex.Usage |= LC_LIBRARY_VERTEX_TEXTURED;
|
|
return VertexIdx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lcLibraryMeshVertex& Vertex = VertexArray.Add();
|
|
Vertex.Position = Position;
|
|
Vertex.Normal = lcVector3(0.0f, 0.0f, 0.0f);
|
|
Vertex.NormalWeight = 0.0f;
|
|
Vertex.TexCoord = TexCoord;
|
|
Vertex.Usage = LC_LIBRARY_VERTEX_TEXTURED;
|
|
|
|
return VertexArray.GetSize() - 1;
|
|
}
|
|
|
|
quint32 lcLibraryMeshData::AddTexturedVertex(lcMeshDataType MeshDataType, const lcVector3& Position, const lcVector3& Normal, const lcVector2& TexCoord, bool Optimize)
|
|
{
|
|
mHasTextures = true;
|
|
|
|
lcArray<lcLibraryMeshVertex>& VertexArray = mVertices[MeshDataType];
|
|
|
|
if (Optimize)
|
|
{
|
|
for (int VertexIdx = VertexArray.GetSize() - 1; VertexIdx >= 0; VertexIdx--)
|
|
{
|
|
lcLibraryMeshVertex& Vertex = VertexArray[VertexIdx];
|
|
|
|
if (Vertex.Usage & LC_LIBRARY_VERTEX_TEXTURED)
|
|
{
|
|
if (lcCompareVertices(Position, TexCoord, Vertex.Position, Vertex.TexCoord))
|
|
{
|
|
if (Vertex.NormalWeight == 0.0f)
|
|
{
|
|
Vertex.Normal = Normal;
|
|
Vertex.NormalWeight = 1.0f;
|
|
return VertexIdx;
|
|
}
|
|
else if (lcDot(Normal, Vertex.Normal) > 0.707f)
|
|
{
|
|
Vertex.Normal = lcNormalize(Vertex.Normal * Vertex.NormalWeight + Normal);
|
|
Vertex.NormalWeight += 1.0f;
|
|
return VertexIdx;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (lcCompareVertices(Position, Vertex.Position))
|
|
{
|
|
if (Vertex.NormalWeight == 0.0f)
|
|
{
|
|
Vertex.Normal = Normal;
|
|
Vertex.NormalWeight = 1.0f;
|
|
Vertex.TexCoord = TexCoord;
|
|
Vertex.Usage |= LC_LIBRARY_VERTEX_TEXTURED;
|
|
return VertexIdx;
|
|
}
|
|
else if (lcDot(Normal, Vertex.Normal) > 0.707f)
|
|
{
|
|
Vertex.Normal = lcNormalize(Vertex.Normal * Vertex.NormalWeight + Normal);
|
|
Vertex.NormalWeight += 1.0f;
|
|
Vertex.TexCoord = TexCoord;
|
|
Vertex.Usage |= LC_LIBRARY_VERTEX_TEXTURED;
|
|
return VertexIdx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lcLibraryMeshVertex& Vertex = VertexArray.Add();
|
|
Vertex.Position = Position;
|
|
Vertex.Normal = Normal;
|
|
Vertex.NormalWeight = 1.0f;
|
|
Vertex.TexCoord = TexCoord;
|
|
Vertex.Usage = LC_LIBRARY_VERTEX_TEXTURED;
|
|
|
|
return VertexArray.GetSize() - 1;
|
|
}
|
|
|
|
void lcLibraryMeshData::AddIndices(lcMeshDataType MeshDataType, lcMeshPrimitiveType PrimitiveType, quint32 ColorCode, int IndexCount, quint32** IndexBuffer)
|
|
{
|
|
lcLibraryMeshSection* Section = AddSection(MeshDataType, PrimitiveType, ColorCode, nullptr);
|
|
lcArray<quint32>& Indices = Section->mIndices;
|
|
int CurrentSize = Indices.GetSize();
|
|
|
|
Indices.SetSize(CurrentSize + IndexCount);
|
|
|
|
*IndexBuffer = &Indices[CurrentSize];
|
|
}
|
|
|
|
void lcLibraryMeshData::AddLine(lcMeshDataType MeshDataType, int LineType, quint32 ColorCode, bool WindingCCW, const lcVector3* Vertices, bool Optimize)
|
|
{
|
|
lcMeshPrimitiveType PrimitiveTypes[4] = { LC_MESH_LINES, LC_MESH_TRIANGLES, LC_MESH_TRIANGLES, LC_MESH_CONDITIONAL_LINES };
|
|
lcMeshPrimitiveType PrimitiveType = PrimitiveTypes[LineType - 2];
|
|
lcLibraryMeshSection* Section = AddSection(MeshDataType, PrimitiveType, ColorCode, nullptr);
|
|
|
|
int QuadIndices[4] = { 0, 1, 2, 3 };
|
|
int Indices[4] = { -1, -1, -1, -1 };
|
|
|
|
if (LineType == 3 || LineType == 4)
|
|
{
|
|
if (LineType == 4)
|
|
TestQuad(QuadIndices, Vertices);
|
|
|
|
lcVector3 Normal = lcNormalize(lcCross(Vertices[1] - Vertices[0], Vertices[2] - Vertices[0]));
|
|
|
|
if (!WindingCCW)
|
|
Normal = -Normal;
|
|
|
|
for (int IndexIdx = 0; IndexIdx < lcMin(LineType, 4); IndexIdx++)
|
|
{
|
|
const lcVector3& Position = Vertices[QuadIndices[IndexIdx]];
|
|
Indices[IndexIdx] = AddVertex(MeshDataType, Position, Normal, Optimize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int IndexIdx = 0; IndexIdx < lcMin(LineType, 4); IndexIdx++)
|
|
{
|
|
const lcVector3& Position = Vertices[QuadIndices[IndexIdx]];
|
|
Indices[IndexIdx] = AddVertex(MeshDataType, Position, Optimize);
|
|
}
|
|
}
|
|
|
|
switch (LineType)
|
|
{
|
|
case 5:
|
|
if (Indices[0] != Indices[1] && Indices[0] != Indices[2] && Indices[0] != Indices[3] && Indices[1] != Indices[2] && Indices[1] != Indices[3] && Indices[2] != Indices[3])
|
|
{
|
|
Section->mIndices.Add(Indices[0]);
|
|
Section->mIndices.Add(Indices[1]);
|
|
Section->mIndices.Add(Indices[2]);
|
|
Section->mIndices.Add(Indices[3]);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
if (Indices[0] != Indices[2] && Indices[0] != Indices[3] && Indices[2] != Indices[3])
|
|
{
|
|
if (WindingCCW)
|
|
{
|
|
Section->mIndices.Add(Indices[2]);
|
|
Section->mIndices.Add(Indices[3]);
|
|
Section->mIndices.Add(Indices[0]);
|
|
}
|
|
else
|
|
{
|
|
Section->mIndices.Add(Indices[0]);
|
|
Section->mIndices.Add(Indices[3]);
|
|
Section->mIndices.Add(Indices[2]);
|
|
}
|
|
}
|
|
Q_FALLTHROUGH();
|
|
|
|
case 3:
|
|
if (Indices[0] != Indices[1] && Indices[0] != Indices[2] && Indices[1] != Indices[2])
|
|
{
|
|
if (WindingCCW)
|
|
{
|
|
Section->mIndices.Add(Indices[0]);
|
|
Section->mIndices.Add(Indices[1]);
|
|
Section->mIndices.Add(Indices[2]);
|
|
}
|
|
else
|
|
{
|
|
Section->mIndices.Add(Indices[2]);
|
|
Section->mIndices.Add(Indices[1]);
|
|
Section->mIndices.Add(Indices[0]);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
if (Indices[0] != Indices[1])
|
|
{
|
|
Section->mIndices.Add(Indices[0]);
|
|
Section->mIndices.Add(Indices[1]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void lcLibraryMeshData::AddTexturedLine(lcMeshDataType MeshDataType, int LineType, quint32 ColorCode, bool WindingCCW, const lcLibraryTextureMap& TextureMap, const lcVector3* Vertices, bool Optimize)
|
|
{
|
|
lcMeshPrimitiveType PrimitiveType = LC_MESH_TEXTURED_TRIANGLES;
|
|
lcLibraryMeshSection* Section = AddSection(MeshDataType, PrimitiveType, ColorCode, TextureMap.Texture);
|
|
|
|
int QuadIndices[4] = { 0, 1, 2, 3 };
|
|
int Indices[4] = { -1, -1, -1, -1 };
|
|
|
|
if (LineType == 4)
|
|
TestQuad(QuadIndices, Vertices);
|
|
|
|
lcVector3 Normal = lcNormalize(lcCross(Vertices[1] - Vertices[0], Vertices[2] - Vertices[0]));
|
|
|
|
if (!WindingCCW)
|
|
Normal = -Normal;
|
|
|
|
lcVector2 TexCoords[4];
|
|
|
|
for (int IndexIdx = 0; IndexIdx < lcMin(LineType, 4); IndexIdx++)
|
|
{
|
|
const lcVector3& Position = Vertices[QuadIndices[IndexIdx]];
|
|
TexCoords[QuadIndices[IndexIdx]] = lcCalculateTexCoord(Position, &TextureMap);
|
|
}
|
|
|
|
if (TextureMap.Type == lcLibraryTextureMapType::CYLINDRICAL || TextureMap.Type == lcLibraryTextureMapType::SPHERICAL)
|
|
{
|
|
auto CheckTexCoordsWrap = [&TexCoords, &Vertices, &TextureMap](int Index1, int Index2, int Index3)
|
|
{
|
|
float u12 = fabsf(TexCoords[Index1].x - TexCoords[Index2].x);
|
|
float u13 = fabsf(TexCoords[Index1].x - TexCoords[Index3].x);
|
|
float u23 = fabsf(TexCoords[Index2].x - TexCoords[Index3].x);
|
|
|
|
if (u12 < 0.5f && u13 < 0.5f && u23 < 0.5f)
|
|
return;
|
|
|
|
const lcVector4& Plane2 = (TextureMap.Type == lcLibraryTextureMapType::CYLINDRICAL) ? TextureMap.Params.Cylindrical.Plane2 : TextureMap.Params.Spherical.Plane2;
|
|
float Dot1 = fabsf(lcDot(Plane2, lcVector4(Vertices[Index1], 1.0f)));
|
|
float Dot2 = fabsf(lcDot(Plane2, lcVector4(Vertices[Index2], 1.0f)));
|
|
float Dot3 = fabsf(lcDot(Plane2, lcVector4(Vertices[Index3], 1.0f)));
|
|
|
|
if (Dot1 > Dot2)
|
|
{
|
|
if (Dot1 > Dot3)
|
|
{
|
|
if (u12 > 0.5f)
|
|
TexCoords[Index2].x += TexCoords[Index2].x < 0.5f ? 1.0f : -1.0f;
|
|
|
|
if (u13 > 0.5f)
|
|
TexCoords[Index3].x += TexCoords[Index3].x < 0.5f ? 1.0f : -1.0f;
|
|
}
|
|
else
|
|
{
|
|
if (u13 > 0.5f)
|
|
TexCoords[Index1].x += TexCoords[Index1].x < 0.5f ? 1.0f : -1.0f;
|
|
|
|
if (u23 > 0.5f)
|
|
TexCoords[Index2].x += TexCoords[Index2].x < 0.5f ? 1.0f : -1.0f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Dot2 > Dot3)
|
|
{
|
|
if (u12 > 0.5f)
|
|
TexCoords[Index1].x += TexCoords[Index1].x < 0.5f ? 1.0f : -1.0f;
|
|
|
|
if (u23 > 0.5f)
|
|
TexCoords[Index3].x += TexCoords[Index3].x < 0.5f ? 1.0f : -1.0f;
|
|
}
|
|
else
|
|
{
|
|
if (u13 > 0.5f)
|
|
TexCoords[Index1].x += TexCoords[Index1].x < 0.5f ? 1.0f : -1.0f;
|
|
|
|
if (u23 > 0.5f)
|
|
TexCoords[Index2].x += TexCoords[Index2].x < 0.5f ? 1.0f : -1.0f;
|
|
}
|
|
}
|
|
};
|
|
|
|
CheckTexCoordsWrap(QuadIndices[0], QuadIndices[1], QuadIndices[2]);
|
|
|
|
if (LineType == 4)
|
|
CheckTexCoordsWrap(QuadIndices[2], QuadIndices[3], QuadIndices[0]);
|
|
}
|
|
|
|
if (TextureMap.Type == lcLibraryTextureMapType::SPHERICAL)
|
|
{
|
|
auto CheckTexCoordsPole = [&TexCoords, &Vertices, &TextureMap](int Index1, int Index2, int Index3)
|
|
{
|
|
const lcVector4& FrontPlane = TextureMap.Params.Spherical.FrontPlane;
|
|
const lcVector4& Plane2 = TextureMap.Params.Spherical.Plane2;
|
|
int PoleIndex;
|
|
int EdgeIndex1, EdgeIndex2;
|
|
|
|
if (fabsf(lcDot(lcVector4(Vertices[Index1], 1.0f), FrontPlane)) < 0.01f && fabsf(lcDot(lcVector4(Vertices[Index1], 1.0f), Plane2)) < 0.01f)
|
|
{
|
|
PoleIndex = Index1;
|
|
EdgeIndex1 = Index2;
|
|
EdgeIndex2 = Index3;
|
|
}
|
|
else if (fabsf(lcDot(lcVector4(Vertices[Index2], 1.0f), FrontPlane)) < 0.01f && fabsf(lcDot(lcVector4(Vertices[Index2], 1.0f), Plane2)) < 0.01f)
|
|
{
|
|
PoleIndex = Index2;
|
|
EdgeIndex1 = Index1;
|
|
EdgeIndex2 = Index3;
|
|
}
|
|
else if (fabsf(lcDot(lcVector4(Vertices[Index3], 1.0f), FrontPlane)) < 0.01f && fabsf(lcDot(lcVector4(Vertices[Index3], 1.0f), Plane2)) < 0.01f)
|
|
{
|
|
PoleIndex = Index3;
|
|
EdgeIndex1 = Index1;
|
|
EdgeIndex2 = Index2;
|
|
}
|
|
else
|
|
return;
|
|
|
|
lcVector3 OppositeEdge = Vertices[EdgeIndex2] - Vertices[EdgeIndex1];
|
|
lcVector3 SideEdge = Vertices[PoleIndex] - Vertices[EdgeIndex1];
|
|
|
|
float OppositeLength = lcLength(OppositeEdge);
|
|
float Projection = lcDot(OppositeEdge, SideEdge) / (OppositeLength * OppositeLength);
|
|
|
|
TexCoords[PoleIndex].x = TexCoords[EdgeIndex1].x + (TexCoords[EdgeIndex2].x - TexCoords[EdgeIndex1].x) * Projection;
|
|
};
|
|
|
|
CheckTexCoordsPole(QuadIndices[0], QuadIndices[1], QuadIndices[2]);
|
|
|
|
if (LineType == 4)
|
|
CheckTexCoordsPole(QuadIndices[2], QuadIndices[3], QuadIndices[0]);
|
|
}
|
|
|
|
for (int IndexIdx = 0; IndexIdx < lcMin(LineType, 4); IndexIdx++)
|
|
{
|
|
const lcVector3& Position = Vertices[QuadIndices[IndexIdx]];
|
|
Indices[IndexIdx] = AddTexturedVertex(MeshDataType, Position, Normal, TexCoords[QuadIndices[IndexIdx]], Optimize);
|
|
}
|
|
|
|
if (LineType == 4)
|
|
{
|
|
if (Indices[0] != Indices[2] && Indices[0] != Indices[3] && Indices[2] != Indices[3])
|
|
{
|
|
if (WindingCCW)
|
|
{
|
|
Section->mIndices.Add(Indices[2]);
|
|
Section->mIndices.Add(Indices[3]);
|
|
Section->mIndices.Add(Indices[0]);
|
|
}
|
|
else
|
|
{
|
|
Section->mIndices.Add(Indices[0]);
|
|
Section->mIndices.Add(Indices[3]);
|
|
Section->mIndices.Add(Indices[2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Indices[0] != Indices[1] && Indices[0] != Indices[2] && Indices[1] != Indices[2])
|
|
{
|
|
if (WindingCCW)
|
|
{
|
|
Section->mIndices.Add(Indices[0]);
|
|
Section->mIndices.Add(Indices[1]);
|
|
Section->mIndices.Add(Indices[2]);
|
|
}
|
|
else
|
|
{
|
|
Section->mIndices.Add(Indices[2]);
|
|
Section->mIndices.Add(Indices[1]);
|
|
Section->mIndices.Add(Indices[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void lcLibraryMeshData::AddMeshData(const lcLibraryMeshData& Data, const lcMatrix44& Transform, quint32 CurrentColorCode, bool InvertWinding, bool InvertNormals, lcLibraryTextureMap* TextureMap, lcMeshDataType OverrideDestIndex)
|
|
{
|
|
for (int MeshDataIdx = 0; MeshDataIdx < LC_NUM_MESHDATA_TYPES; MeshDataIdx++)
|
|
{
|
|
int DestIndex = OverrideDestIndex == LC_MESHDATA_SHARED ? MeshDataIdx : OverrideDestIndex;
|
|
const lcArray<lcLibraryMeshVertex>& DataVertices = Data.mVertices[MeshDataIdx];
|
|
lcArray<lcLibraryMeshVertex>& Vertices = mVertices[DestIndex];
|
|
|
|
int VertexCount = DataVertices.GetSize();
|
|
lcArray<quint32> IndexRemap(VertexCount);
|
|
|
|
if (!TextureMap)
|
|
{
|
|
Vertices.AllocGrow(VertexCount);
|
|
|
|
for (int SrcVertexIdx = 0; SrcVertexIdx < VertexCount; SrcVertexIdx++)
|
|
{
|
|
lcVector3 Position = lcMul31(DataVertices[SrcVertexIdx].Position, Transform);
|
|
int Index;
|
|
|
|
if ((DataVertices[SrcVertexIdx].Usage & LC_LIBRARY_VERTEX_TEXTURED) == 0)
|
|
{
|
|
if (DataVertices[SrcVertexIdx].NormalWeight == 0.0f)
|
|
Index = AddVertex((lcMeshDataType)DestIndex, Position, true);
|
|
else
|
|
{
|
|
lcVector3 Normal = lcNormalize(lcMul30(DataVertices[SrcVertexIdx].Normal, Transform));
|
|
if (InvertNormals)
|
|
Normal = -Normal;
|
|
Index = AddVertex((lcMeshDataType)DestIndex, Position, Normal, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mHasTextures = true;
|
|
|
|
if (DataVertices[SrcVertexIdx].NormalWeight == 0.0f)
|
|
Index = AddTexturedVertex((lcMeshDataType)DestIndex, Position, DataVertices[SrcVertexIdx].TexCoord, true);
|
|
else
|
|
{
|
|
lcVector3 Normal = lcNormalize(lcMul30(DataVertices[SrcVertexIdx].Normal, Transform));
|
|
if (InvertNormals)
|
|
Normal = -Normal;
|
|
Index = AddTexturedVertex((lcMeshDataType)DestIndex, Position, Normal, DataVertices[SrcVertexIdx].TexCoord, true);
|
|
}
|
|
|
|
Vertices[Index].Usage = DataVertices[SrcVertexIdx].Usage;
|
|
}
|
|
|
|
IndexRemap.Add(Index);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mHasTextures = true;
|
|
|
|
for (int SrcVertexIdx = 0; SrcVertexIdx < VertexCount; SrcVertexIdx++)
|
|
{
|
|
const lcLibraryMeshVertex& SrcVertex = DataVertices[SrcVertexIdx];
|
|
lcVector3 Position = lcMul31(SrcVertex.Position, Transform);
|
|
lcVector2 TexCoord = lcCalculateTexCoord(Position, TextureMap);
|
|
int Index;
|
|
|
|
if (DataVertices[SrcVertexIdx].NormalWeight == 0.0f)
|
|
Index = AddTexturedVertex((lcMeshDataType)DestIndex, Position, TexCoord, true);
|
|
else
|
|
{
|
|
lcVector3 Normal = lcNormalize(lcMul30(DataVertices[SrcVertexIdx].Normal, Transform));
|
|
if (InvertNormals)
|
|
Normal = -Normal;
|
|
Index = AddTexturedVertex((lcMeshDataType)DestIndex, Position, Normal, TexCoord, true);
|
|
}
|
|
|
|
IndexRemap.Add(Index);
|
|
}
|
|
}
|
|
|
|
const lcArray<lcLibraryMeshSection*>& DataSections = Data.mSections[MeshDataIdx];
|
|
lcArray<lcLibraryMeshSection*>& Sections = mSections[DestIndex];
|
|
|
|
for (int SrcSectionIdx = 0; SrcSectionIdx < DataSections.GetSize(); SrcSectionIdx++)
|
|
{
|
|
lcLibraryMeshSection* SrcSection = DataSections[SrcSectionIdx];
|
|
lcLibraryMeshSection* DstSection = nullptr;
|
|
quint32 ColorCode = SrcSection->mColor == 16 ? CurrentColorCode : SrcSection->mColor;
|
|
lcTexture* Texture;
|
|
lcMeshPrimitiveType PrimitiveType = SrcSection->mPrimitiveType;
|
|
|
|
if (SrcSection->mTexture)
|
|
Texture = SrcSection->mTexture;
|
|
else if (TextureMap && SrcSection->mPrimitiveType == LC_MESH_TRIANGLES)
|
|
{
|
|
Texture = TextureMap->Texture;
|
|
PrimitiveType = LC_MESH_TEXTURED_TRIANGLES;
|
|
}
|
|
else
|
|
Texture = nullptr;
|
|
|
|
for (int DstSectionIdx = 0; DstSectionIdx < Sections.GetSize(); DstSectionIdx++)
|
|
{
|
|
lcLibraryMeshSection* Section = Sections[DstSectionIdx];
|
|
|
|
if (Section->mColor == ColorCode && Section->mPrimitiveType == PrimitiveType && Section->mTexture == Texture)
|
|
{
|
|
DstSection = Section;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!DstSection)
|
|
{
|
|
DstSection = new lcLibraryMeshSection(PrimitiveType, ColorCode, Texture);
|
|
|
|
Sections.Add(DstSection);
|
|
}
|
|
|
|
DstSection->mIndices.AllocGrow(SrcSection->mIndices.GetSize());
|
|
|
|
if (!InvertWinding || (PrimitiveType != LC_MESH_TRIANGLES && PrimitiveType != LC_MESH_TEXTURED_TRIANGLES))
|
|
{
|
|
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
|
|
DstSection->mIndices.Add(IndexRemap[SrcSection->mIndices[IndexIdx]]);
|
|
}
|
|
else
|
|
{
|
|
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx += 3)
|
|
{
|
|
DstSection->mIndices.Add(IndexRemap[SrcSection->mIndices[IndexIdx + 2]]);
|
|
DstSection->mIndices.Add(IndexRemap[SrcSection->mIndices[IndexIdx + 1]]);
|
|
DstSection->mIndices.Add(IndexRemap[SrcSection->mIndices[IndexIdx + 0]]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void lcLibraryMeshData::AddMeshDataNoDuplicateCheck(const lcLibraryMeshData& Data, const lcMatrix44& Transform, quint32 CurrentColorCode, bool InvertWinding, bool InvertNormals, lcLibraryTextureMap* TextureMap, lcMeshDataType OverrideDestIndex)
|
|
{
|
|
for (int MeshDataIdx = 0; MeshDataIdx < LC_NUM_MESHDATA_TYPES; MeshDataIdx++)
|
|
{
|
|
int DestIndex = OverrideDestIndex == LC_MESHDATA_SHARED ? MeshDataIdx : OverrideDestIndex;
|
|
const lcArray<lcLibraryMeshVertex>& DataVertices = Data.mVertices[MeshDataIdx];
|
|
lcArray<lcLibraryMeshVertex>& Vertices = mVertices[DestIndex];
|
|
quint32 BaseIndex;
|
|
|
|
if (!TextureMap)
|
|
{
|
|
BaseIndex = Vertices.GetSize();
|
|
|
|
Vertices.SetGrow(lcMin(Vertices.GetSize(), 8 * 1024 * 1024));
|
|
Vertices.AllocGrow(DataVertices.GetSize());
|
|
|
|
for (int SrcVertexIdx = 0; SrcVertexIdx < DataVertices.GetSize(); SrcVertexIdx++)
|
|
{
|
|
const lcLibraryMeshVertex& SrcVertex = DataVertices[SrcVertexIdx];
|
|
lcLibraryMeshVertex& DstVertex = Vertices.Add();
|
|
DstVertex.Position = lcMul31(SrcVertex.Position, Transform);
|
|
DstVertex.Normal = lcNormalize(lcMul30(SrcVertex.Normal, Transform));
|
|
if (InvertNormals)
|
|
DstVertex.Normal = -DstVertex.Normal;
|
|
DstVertex.NormalWeight = SrcVertex.NormalWeight;
|
|
DstVertex.TexCoord = SrcVertex.TexCoord;
|
|
DstVertex.Usage = SrcVertex.Usage;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mHasTextures = true;
|
|
BaseIndex = Vertices.GetSize();
|
|
|
|
Vertices.AllocGrow(DataVertices.GetSize());
|
|
|
|
for (int SrcVertexIdx = 0; SrcVertexIdx < DataVertices.GetSize(); SrcVertexIdx++)
|
|
{
|
|
const lcLibraryMeshVertex& SrcVertex = DataVertices[SrcVertexIdx];
|
|
lcLibraryMeshVertex& DstVertex = Vertices.Add();
|
|
|
|
lcVector3 Position = lcMul31(SrcVertex.Position, Transform);
|
|
lcVector2 TexCoord = lcCalculateTexCoord(Position, TextureMap);
|
|
|
|
DstVertex.Position = Position;
|
|
DstVertex.Normal = lcNormalize(lcMul30(SrcVertex.Normal, Transform));
|
|
if (InvertNormals)
|
|
DstVertex.Normal = -DstVertex.Normal;
|
|
DstVertex.NormalWeight = SrcVertex.NormalWeight;
|
|
DstVertex.TexCoord = TexCoord;
|
|
DstVertex.Usage = LC_LIBRARY_VERTEX_TEXTURED;
|
|
}
|
|
}
|
|
|
|
const lcArray<lcLibraryMeshSection*>& DataSections = Data.mSections[MeshDataIdx];
|
|
lcArray<lcLibraryMeshSection*>& Sections = mSections[DestIndex];
|
|
|
|
for (int SrcSectionIdx = 0; SrcSectionIdx < DataSections.GetSize(); SrcSectionIdx++)
|
|
{
|
|
lcLibraryMeshSection* SrcSection = DataSections[SrcSectionIdx];
|
|
lcLibraryMeshSection* DstSection = nullptr;
|
|
quint32 ColorCode = SrcSection->mColor == 16 ? CurrentColorCode : SrcSection->mColor;
|
|
lcTexture* Texture;
|
|
|
|
if (SrcSection->mTexture)
|
|
Texture = SrcSection->mTexture;
|
|
else if (TextureMap)
|
|
Texture = TextureMap->Texture;
|
|
else
|
|
Texture = nullptr;
|
|
|
|
for (int DstSectionIdx = 0; DstSectionIdx < Sections.GetSize(); DstSectionIdx++)
|
|
{
|
|
lcLibraryMeshSection* Section = Sections[DstSectionIdx];
|
|
|
|
if (Section->mColor == ColorCode && Section->mPrimitiveType == SrcSection->mPrimitiveType && Section->mTexture == Texture)
|
|
{
|
|
DstSection = Section;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!DstSection)
|
|
{
|
|
DstSection = new lcLibraryMeshSection(SrcSection->mPrimitiveType, ColorCode, Texture);
|
|
|
|
Sections.Add(DstSection);
|
|
}
|
|
|
|
DstSection->mIndices.SetGrow(lcMin(DstSection->mIndices.GetSize(), 8 * 1024 * 1024));
|
|
DstSection->mIndices.AllocGrow(SrcSection->mIndices.GetSize());
|
|
|
|
if (!InvertWinding || (SrcSection->mPrimitiveType != LC_MESH_TRIANGLES && SrcSection->mPrimitiveType != LC_MESH_TEXTURED_TRIANGLES))
|
|
{
|
|
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
|
|
DstSection->mIndices.Add(BaseIndex + SrcSection->mIndices[IndexIdx]);
|
|
}
|
|
else
|
|
{
|
|
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx += 3)
|
|
{
|
|
DstSection->mIndices.Add(BaseIndex + SrcSection->mIndices[IndexIdx + 2]);
|
|
DstSection->mIndices.Add(BaseIndex + SrcSection->mIndices[IndexIdx + 1]);
|
|
DstSection->mIndices.Add(BaseIndex + SrcSection->mIndices[IndexIdx + 0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct lcMergeSection
|
|
{
|
|
lcLibraryMeshSection* Shared;
|
|
lcLibraryMeshSection* Lod;
|
|
};
|
|
|
|
static bool lcLibraryMeshSectionCompare(const lcMergeSection& First, const lcMergeSection& Second)
|
|
{
|
|
lcLibraryMeshSection* a = First.Lod ? First.Lod : First.Shared;
|
|
lcLibraryMeshSection* b = Second.Lod ? Second.Lod : Second.Shared;
|
|
|
|
if (a->mPrimitiveType != b->mPrimitiveType)
|
|
{
|
|
int PrimitiveOrder[LC_MESH_NUM_PRIMITIVE_TYPES] =
|
|
{
|
|
LC_MESH_TRIANGLES,
|
|
LC_MESH_TEXTURED_TRIANGLES,
|
|
LC_MESH_LINES,
|
|
LC_MESH_CONDITIONAL_LINES
|
|
};
|
|
|
|
for (int PrimitiveType = 0; PrimitiveType < LC_MESH_NUM_PRIMITIVE_TYPES; PrimitiveType++)
|
|
{
|
|
int Primitive = PrimitiveOrder[PrimitiveType];
|
|
|
|
if (a->mPrimitiveType == Primitive)
|
|
return true;
|
|
|
|
if (b->mPrimitiveType == Primitive)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool TranslucentA = lcIsColorTranslucent(a->mColor);
|
|
bool TranslucentB = lcIsColorTranslucent(b->mColor);
|
|
|
|
if (TranslucentA != TranslucentB)
|
|
return !TranslucentA;
|
|
|
|
return a->mColor > b->mColor;
|
|
}
|
|
|
|
lcMesh* lcLibraryMeshData::CreateMesh()
|
|
{
|
|
lcMesh* Mesh = new lcMesh();
|
|
|
|
int BaseVertices[LC_NUM_MESHDATA_TYPES];
|
|
int BaseTexturedVertices[LC_NUM_MESHDATA_TYPES];
|
|
int NumVertices = 0;
|
|
int NumTexturedVertices = 0;
|
|
std::vector<quint32> IndexRemap[LC_NUM_MESHDATA_TYPES];
|
|
std::vector<quint32> TexturedIndexRemap[LC_NUM_MESHDATA_TYPES];
|
|
|
|
if (!mHasTextures)
|
|
{
|
|
for (int MeshDataIdx = 0; MeshDataIdx < LC_NUM_MESHDATA_TYPES; MeshDataIdx++)
|
|
{
|
|
lcArray<lcLibraryMeshSection*>& Sections = mSections[MeshDataIdx];
|
|
|
|
for (int SectionIdx = 0; SectionIdx < Sections.GetSize(); SectionIdx++)
|
|
{
|
|
lcLibraryMeshSection* Section = Sections[SectionIdx];
|
|
Section->mColor = lcGetColorIndex(Section->mColor);
|
|
}
|
|
|
|
BaseVertices[MeshDataIdx] = NumVertices;
|
|
NumVertices += mVertices[MeshDataIdx].GetSize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int MeshDataIdx = 0; MeshDataIdx < LC_NUM_MESHDATA_TYPES; MeshDataIdx++)
|
|
{
|
|
lcArray<lcLibraryMeshSection*>& Sections = mSections[MeshDataIdx];
|
|
|
|
for (int SectionIdx = 0; SectionIdx < Sections.GetSize(); SectionIdx++)
|
|
{
|
|
lcLibraryMeshSection* Section = Sections[SectionIdx];
|
|
Section->mColor = lcGetColorIndex(Section->mColor);
|
|
}
|
|
|
|
BaseVertices[MeshDataIdx] = NumVertices;
|
|
BaseTexturedVertices[MeshDataIdx] = NumTexturedVertices;
|
|
|
|
const lcArray<lcLibraryMeshVertex>& Vertices = mVertices[MeshDataIdx];
|
|
IndexRemap[MeshDataIdx].resize(Vertices.GetSize());
|
|
TexturedIndexRemap[MeshDataIdx].resize(Vertices.GetSize());
|
|
|
|
for (int VertexIdx = 0; VertexIdx < Vertices.GetSize(); VertexIdx++)
|
|
{
|
|
const lcLibraryMeshVertex& Vertex = Vertices[VertexIdx];
|
|
|
|
if (Vertex.Usage & LC_LIBRARY_VERTEX_UNTEXTURED)
|
|
{
|
|
IndexRemap[MeshDataIdx][VertexIdx] = NumVertices;
|
|
NumVertices++;
|
|
}
|
|
|
|
if (Vertex.Usage & LC_LIBRARY_VERTEX_TEXTURED)
|
|
{
|
|
TexturedIndexRemap[MeshDataIdx][VertexIdx] = NumTexturedVertices;
|
|
NumTexturedVertices++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
quint16 NumSections[LC_NUM_MESH_LODS];
|
|
int NumIndices = 0;
|
|
|
|
lcArray<lcMergeSection> MergeSections[LC_NUM_MESH_LODS];
|
|
|
|
for (int LodIdx = 0; LodIdx < LC_NUM_MESH_LODS; LodIdx++)
|
|
{
|
|
const lcArray<lcLibraryMeshSection*>& SharedSections = mSections[LC_MESHDATA_SHARED];
|
|
const lcArray<lcLibraryMeshSection*>& Sections = mSections[LodIdx];
|
|
|
|
for (int SharedSectionIdx = 0; SharedSectionIdx < SharedSections.GetSize(); SharedSectionIdx++)
|
|
{
|
|
lcLibraryMeshSection* SharedSection = SharedSections[SharedSectionIdx];
|
|
NumIndices += SharedSection->mIndices.GetSize();
|
|
|
|
lcMergeSection& MergeSection = MergeSections[LodIdx].Add();
|
|
MergeSection.Shared = SharedSection;
|
|
MergeSection.Lod = nullptr;
|
|
}
|
|
|
|
for (int SectionIdx = 0; SectionIdx < Sections.GetSize(); SectionIdx++)
|
|
{
|
|
lcLibraryMeshSection* Section = Sections[SectionIdx];
|
|
bool Found = false;
|
|
|
|
NumIndices += Section->mIndices.GetSize();
|
|
|
|
for (int SharedSectionIdx = 0; SharedSectionIdx < SharedSections.GetSize(); SharedSectionIdx++)
|
|
{
|
|
lcLibraryMeshSection* SharedSection = SharedSections[SharedSectionIdx];
|
|
|
|
if (SharedSection->mColor == Section->mColor && SharedSection->mPrimitiveType == Section->mPrimitiveType && SharedSection->mTexture == Section->mTexture)
|
|
{
|
|
lcMergeSection& MergeSection = MergeSections[LodIdx][SharedSectionIdx];
|
|
MergeSection.Lod = Section;
|
|
Found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Found)
|
|
{
|
|
lcMergeSection& MergeSection = MergeSections[LodIdx].Add();
|
|
MergeSection.Shared = nullptr;
|
|
MergeSection.Lod = Section;
|
|
}
|
|
}
|
|
|
|
NumSections[LodIdx] = MergeSections[LodIdx].GetSize();
|
|
std::sort(MergeSections[LodIdx].begin(), MergeSections[LodIdx].end(), lcLibraryMeshSectionCompare);
|
|
}
|
|
|
|
Mesh->Create(NumSections, NumVertices, NumTexturedVertices, NumIndices);
|
|
|
|
lcVertex* DstVerts = (lcVertex*)Mesh->mVertexData;
|
|
|
|
if (!mHasTextures)
|
|
{
|
|
for (int MeshDataIdx = 0; MeshDataIdx < LC_NUM_MESHDATA_TYPES; MeshDataIdx++)
|
|
{
|
|
const lcArray<lcLibraryMeshVertex>& Vertices = mVertices[MeshDataIdx];
|
|
|
|
for (const lcLibraryMeshVertex& SrcVertex : Vertices)
|
|
{
|
|
lcVertex& DstVertex = *DstVerts++;
|
|
|
|
DstVertex.Position = lcVector3LDrawToLeoCAD(SrcVertex.Position);
|
|
DstVertex.Normal = lcPackNormal(lcVector3LDrawToLeoCAD(SrcVertex.Normal));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int MeshDataIdx = 0; MeshDataIdx < LC_NUM_MESHDATA_TYPES; MeshDataIdx++)
|
|
{
|
|
for (const lcLibraryMeshVertex& SrcVertex : mVertices[MeshDataIdx])
|
|
{
|
|
if ((SrcVertex.Usage & LC_LIBRARY_VERTEX_UNTEXTURED) == 0)
|
|
continue;
|
|
|
|
lcVertex& DstVertex = *DstVerts++;
|
|
|
|
DstVertex.Position = lcVector3LDrawToLeoCAD(SrcVertex.Position);
|
|
DstVertex.Normal = lcPackNormal(lcVector3LDrawToLeoCAD(SrcVertex.Normal));
|
|
}
|
|
}
|
|
|
|
lcVertexTextured* DstTexturedVerts = (lcVertexTextured*)DstVerts;
|
|
|
|
for (int MeshDataIdx = 0; MeshDataIdx < LC_NUM_MESHDATA_TYPES; MeshDataIdx++)
|
|
{
|
|
for (const lcLibraryMeshVertex& SrcVertex : mVertices[MeshDataIdx])
|
|
{
|
|
if ((SrcVertex.Usage & LC_LIBRARY_VERTEX_TEXTURED) == 0)
|
|
continue;
|
|
|
|
lcVertexTextured& DstVertex = *DstTexturedVerts++;
|
|
|
|
DstVertex.Position = lcVector3LDrawToLeoCAD(SrcVertex.Position);
|
|
DstVertex.Normal = lcPackNormal(lcVector3LDrawToLeoCAD(SrcVertex.Normal));
|
|
DstVertex.TexCoord = SrcVertex.TexCoord;
|
|
}
|
|
}
|
|
|
|
for (int MeshDataIdx = 0; MeshDataIdx < LC_NUM_MESHDATA_TYPES; MeshDataIdx++)
|
|
{
|
|
for (lcLibraryMeshSection* Section : mSections[MeshDataIdx])
|
|
{
|
|
if (Section->mPrimitiveType == LC_MESH_TRIANGLES)
|
|
{
|
|
for (quint32& Index : Section->mIndices)
|
|
Index = IndexRemap[MeshDataIdx][Index];
|
|
}
|
|
else
|
|
{
|
|
if (!Section->mTexture)
|
|
{
|
|
for (quint32& Index : Section->mIndices)
|
|
Index = IndexRemap[MeshDataIdx][Index];
|
|
}
|
|
else
|
|
{
|
|
for (quint32& Index : Section->mIndices)
|
|
Index = TexturedIndexRemap[MeshDataIdx][Index];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NumIndices = 0;
|
|
|
|
for (int LodIdx = 0; LodIdx < LC_NUM_MESH_LODS; LodIdx++)
|
|
{
|
|
for (int SectionIdx = 0; SectionIdx < MergeSections[LodIdx].GetSize(); SectionIdx++)
|
|
{
|
|
lcMergeSection& MergeSection = MergeSections[LodIdx][SectionIdx];
|
|
lcMeshSection& DstSection = Mesh->mLods[LodIdx].Sections[SectionIdx];
|
|
|
|
lcLibraryMeshSection* SetupSection = MergeSection.Shared ? MergeSection.Shared : MergeSection.Lod;
|
|
|
|
DstSection.ColorIndex = SetupSection->mColor;
|
|
DstSection.PrimitiveType = SetupSection->mPrimitiveType;
|
|
DstSection.NumIndices = 0;
|
|
DstSection.Texture = SetupSection->mTexture;
|
|
|
|
if (DstSection.Texture)
|
|
DstSection.Texture->AddRef();
|
|
|
|
if (Mesh->mNumVertices < 0x10000)
|
|
{
|
|
DstSection.IndexOffset = NumIndices * 2;
|
|
|
|
quint16* Index = (quint16*)Mesh->mIndexData + NumIndices;
|
|
|
|
if (MergeSection.Shared)
|
|
{
|
|
lcLibraryMeshSection* SrcSection = MergeSection.Shared;
|
|
|
|
if (!mHasTextures)
|
|
{
|
|
quint16 BaseVertex = DstSection.Texture ? BaseTexturedVertices[LC_MESHDATA_SHARED] : BaseVertices[LC_MESHDATA_SHARED];
|
|
|
|
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
|
|
*Index++ = BaseVertex + SrcSection->mIndices[IndexIdx];
|
|
}
|
|
else
|
|
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
|
|
*Index++ = SrcSection->mIndices[IndexIdx];
|
|
|
|
DstSection.NumIndices += SrcSection->mIndices.GetSize();
|
|
}
|
|
|
|
if (MergeSection.Lod)
|
|
{
|
|
lcLibraryMeshSection* SrcSection = MergeSection.Lod;
|
|
|
|
if (!mHasTextures)
|
|
{
|
|
quint16 BaseVertex = DstSection.Texture ? BaseTexturedVertices[LodIdx] : BaseVertices[LodIdx];
|
|
|
|
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
|
|
*Index++ = BaseVertex + SrcSection->mIndices[IndexIdx];
|
|
}
|
|
else
|
|
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
|
|
*Index++ = SrcSection->mIndices[IndexIdx];
|
|
|
|
DstSection.NumIndices += SrcSection->mIndices.GetSize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DstSection.IndexOffset = NumIndices * 4;
|
|
|
|
quint32* Index = (quint32*)Mesh->mIndexData + NumIndices;
|
|
|
|
if (MergeSection.Shared)
|
|
{
|
|
quint32 BaseVertex = DstSection.Texture ? BaseTexturedVertices[LC_MESHDATA_SHARED] : BaseVertices[LC_MESHDATA_SHARED];
|
|
lcLibraryMeshSection* SrcSection = MergeSection.Shared;
|
|
|
|
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
|
|
*Index++ = BaseVertex + SrcSection->mIndices[IndexIdx];
|
|
|
|
DstSection.NumIndices += SrcSection->mIndices.GetSize();
|
|
}
|
|
|
|
if (MergeSection.Lod)
|
|
{
|
|
quint32 BaseVertex = DstSection.Texture ? BaseTexturedVertices[LodIdx] : BaseVertices[LodIdx];
|
|
lcLibraryMeshSection* SrcSection = MergeSection.Lod;
|
|
|
|
for (int IndexIdx = 0; IndexIdx < SrcSection->mIndices.GetSize(); IndexIdx++)
|
|
*Index++ = BaseVertex + SrcSection->mIndices[IndexIdx];
|
|
|
|
DstSection.NumIndices += SrcSection->mIndices.GetSize();
|
|
}
|
|
}
|
|
|
|
if (DstSection.PrimitiveType == LC_MESH_TRIANGLES || DstSection.PrimitiveType == LC_MESH_TEXTURED_TRIANGLES)
|
|
{
|
|
if (DstSection.ColorIndex == gDefaultColor)
|
|
Mesh->mFlags |= lcMeshFlag::HasDefault;
|
|
else
|
|
{
|
|
if (lcIsColorTranslucent(DstSection.ColorIndex))
|
|
Mesh->mFlags |= lcMeshFlag::HasTranslucent;
|
|
else
|
|
Mesh->mFlags |= lcMeshFlag::HasSolid;
|
|
}
|
|
}
|
|
else
|
|
Mesh->mFlags |= lcMeshFlag::HasLines;
|
|
|
|
if (DstSection.PrimitiveType == LC_MESH_TEXTURED_TRIANGLES)
|
|
Mesh->mFlags |= lcMeshFlag::HasTexture;
|
|
|
|
NumIndices += DstSection.NumIndices;
|
|
}
|
|
}
|
|
|
|
if (mHasLogoStud)
|
|
Mesh->mFlags |= lcMeshFlag::HasLogoStud;
|
|
|
|
lcVector3 MeshMin(FLT_MAX, FLT_MAX, FLT_MAX), MeshMax(-FLT_MAX, -FLT_MAX, -FLT_MAX);
|
|
bool UpdatedBoundingBox = false;
|
|
|
|
for (int LodIdx = 0; LodIdx < LC_NUM_MESH_LODS; LodIdx++)
|
|
{
|
|
lcMeshLod& Lod = Mesh->mLods[LodIdx];
|
|
|
|
for (int SectionIdx = 0; SectionIdx < Lod.NumSections; SectionIdx++)
|
|
{
|
|
lcMeshSection& Section = Lod.Sections[SectionIdx];
|
|
lcVector3 SectionMin(FLT_MAX, FLT_MAX, FLT_MAX), SectionMax(-FLT_MAX, -FLT_MAX, -FLT_MAX);
|
|
|
|
if (Mesh->mNumVertices < 0x10000)
|
|
{
|
|
const quint16* IndexBuffer = static_cast<quint16*>(Mesh->mIndexData) + Section.IndexOffset / 2;
|
|
|
|
if (!Section.Texture)
|
|
{
|
|
const lcVertex* VertexBuffer = static_cast<lcVertex*>(Mesh->mVertexData);
|
|
|
|
for (int Index = 0; Index < Section.NumIndices; Index++)
|
|
{
|
|
const lcVector3& Position = VertexBuffer[IndexBuffer[Index]].Position;
|
|
SectionMin = lcMin(SectionMin, Position);
|
|
SectionMax = lcMax(SectionMax, Position);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const lcVertexTextured* VertexBuffer = reinterpret_cast<lcVertexTextured*>(static_cast<char*>(Mesh->mVertexData) + Mesh->mNumVertices * sizeof(lcVertex));
|
|
|
|
for (int Index = 0; Index < Section.NumIndices; Index++)
|
|
{
|
|
const lcVector3& Position = VertexBuffer[IndexBuffer[Index]].Position;
|
|
SectionMin = lcMin(SectionMin, Position);
|
|
SectionMax = lcMax(SectionMax, Position);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const quint32* IndexBuffer = static_cast<quint32*>(Mesh->mIndexData) + Section.IndexOffset / 4;
|
|
|
|
if (!Section.Texture)
|
|
{
|
|
const lcVertex* VertexBuffer = static_cast<lcVertex*>(Mesh->mVertexData);
|
|
|
|
for (int Index = 0; Index < Section.NumIndices; Index++)
|
|
{
|
|
const lcVector3& Position = VertexBuffer[IndexBuffer[Index]].Position;
|
|
SectionMin = lcMin(SectionMin, Position);
|
|
SectionMax = lcMax(SectionMax, Position);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const lcVertexTextured* VertexBuffer = static_cast<lcVertexTextured*>(Mesh->mVertexData);
|
|
|
|
for (int Index = 0; Index < Section.NumIndices; Index++)
|
|
{
|
|
const lcVector3& Position = VertexBuffer[IndexBuffer[Index]].Position;
|
|
SectionMin = lcMin(SectionMin, Position);
|
|
SectionMax = lcMax(SectionMax, Position);
|
|
}
|
|
}
|
|
}
|
|
|
|
Section.BoundingBox.Max = SectionMax;
|
|
Section.BoundingBox.Min = SectionMin;
|
|
Section.Radius = lcLength((SectionMax - SectionMin) / 2.0f);
|
|
|
|
if (Section.PrimitiveType == LC_MESH_TRIANGLES || Section.PrimitiveType == LC_MESH_TEXTURED_TRIANGLES)
|
|
{
|
|
UpdatedBoundingBox = true;
|
|
MeshMin = lcMin(SectionMin, MeshMin);
|
|
MeshMax = lcMax(SectionMax, MeshMax);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!UpdatedBoundingBox)
|
|
MeshMin = MeshMax = lcVector3(0.0f, 0.0f, 0.0f);
|
|
|
|
Mesh->mBoundingBox.Max = MeshMax;
|
|
Mesh->mBoundingBox.Min = MeshMin;
|
|
Mesh->mRadius = lcLength((MeshMax - MeshMin) / 2.0f);
|
|
|
|
return Mesh;
|
|
}
|
|
|
|
lcMeshLoader::lcMeshLoader(lcLibraryMeshData& MeshData, bool Optimize, Project* CurrentProject, bool SearchProjectFolder)
|
|
: mMeshData(MeshData), mOptimize(Optimize), mCurrentProject(CurrentProject), mSearchProjectFolder(SearchProjectFolder)
|
|
{
|
|
}
|
|
|
|
bool lcMeshLoader::LoadMesh(lcFile& File, lcMeshDataType MeshDataType)
|
|
{
|
|
lcArray<lcLibraryTextureMap> TextureStack;
|
|
|
|
return ReadMeshData(File, lcMatrix44Identity(), 16, false, TextureStack, MeshDataType);
|
|
}
|
|
|
|
bool lcMeshLoader::ReadMeshData(lcFile& File, const lcMatrix44& CurrentTransform, quint32 CurrentColorCode, bool InvertWinding, lcArray<lcLibraryTextureMap>& TextureStack, lcMeshDataType MeshDataType)
|
|
{
|
|
char Buffer[1024];
|
|
char* Line;
|
|
bool InvertNext = false;
|
|
bool WindingCCW = !InvertWinding;
|
|
lcPiecesLibrary* Library = lcGetPiecesLibrary();
|
|
|
|
while (File.ReadLine(Buffer, sizeof(Buffer)))
|
|
{
|
|
if (Library->ShouldCancelLoading())
|
|
return false;
|
|
|
|
quint32 ColorCode, ColorCodeHex;
|
|
bool LastToken = false;
|
|
int LineType;
|
|
|
|
Line = Buffer;
|
|
|
|
if (sscanf(Line, "%d", &LineType) != 1)
|
|
continue;
|
|
|
|
if (LineType == 0)
|
|
{
|
|
char* Token = Line;
|
|
|
|
while (*Token && *Token <= 32)
|
|
Token++;
|
|
|
|
Token++;
|
|
|
|
while (*Token && *Token <= 32)
|
|
Token++;
|
|
|
|
char* End = Token;
|
|
while (*End && *End > 32)
|
|
End++;
|
|
|
|
LastToken = (*End == 0);
|
|
*End = 0;
|
|
|
|
if (!strcmp(Token, "!TEXMAP"))
|
|
{
|
|
Token += 8;
|
|
|
|
while (*Token && *Token <= 32)
|
|
Token++;
|
|
|
|
End = Token;
|
|
while (*End && *End > 32)
|
|
End++;
|
|
*End = 0;
|
|
|
|
bool Start = false;
|
|
bool Next = false;
|
|
|
|
if (!strcmp(Token, "START"))
|
|
{
|
|
Token += 6;
|
|
Start = true;
|
|
}
|
|
else if (!strcmp(Token, "NEXT"))
|
|
{
|
|
Token += 5;
|
|
Next = true;
|
|
}
|
|
|
|
if (Start || Next)
|
|
{
|
|
while (*Token && *Token <= 32)
|
|
Token++;
|
|
|
|
End = Token;
|
|
while (*End && *End > 32)
|
|
End++;
|
|
*End = 0;
|
|
|
|
auto CleanTextureName = [](char* FileName)
|
|
{
|
|
char* Ch;
|
|
for (Ch = FileName; *Ch; Ch++)
|
|
{
|
|
if (*Ch >= 'a' && *Ch <= 'z')
|
|
*Ch = *Ch + 'A' - 'a';
|
|
else if (*Ch == '\\')
|
|
*Ch = '/';
|
|
}
|
|
|
|
if (Ch - FileName > 4)
|
|
{
|
|
Ch -= 4;
|
|
if (!memcmp(Ch, ".PNG", 4))
|
|
*Ch = 0;
|
|
}
|
|
};
|
|
|
|
if (!strcmp(Token, "PLANAR"))
|
|
{
|
|
Token += 7;
|
|
|
|
char FileName[LC_MAXPATH];
|
|
lcVector3 Points[3];
|
|
|
|
sscanf(Token, "%f %f %f %f %f %f %f %f %f %s", &Points[0].x, &Points[0].y, &Points[0].z, &Points[1].x, &Points[1].y, &Points[1].z, &Points[2].x, &Points[2].y, &Points[2].z, FileName);
|
|
|
|
Points[0] = lcMul31(Points[0], CurrentTransform);
|
|
Points[1] = lcMul31(Points[1], CurrentTransform);
|
|
Points[2] = lcMul31(Points[2], CurrentTransform);
|
|
|
|
CleanTextureName(FileName);
|
|
|
|
lcLibraryTextureMap& Map = TextureStack.Add();
|
|
Map.Next = false;
|
|
Map.Fallback = false;
|
|
Map.Texture = Library->FindTexture(FileName, mCurrentProject, mSearchProjectFolder);
|
|
Map.Type = lcLibraryTextureMapType::PLANAR;
|
|
|
|
for (int EdgeIdx = 0; EdgeIdx < 2; EdgeIdx++)
|
|
{
|
|
lcVector3 Normal = Points[EdgeIdx + 1] - Points[0];
|
|
float Length = lcLength(Normal);
|
|
Normal /= Length;
|
|
|
|
Map.Params.Planar.Planes[EdgeIdx].x = Normal.x / Length;
|
|
Map.Params.Planar.Planes[EdgeIdx].y = Normal.y / Length;
|
|
Map.Params.Planar.Planes[EdgeIdx].z = Normal.z / Length;
|
|
Map.Params.Planar.Planes[EdgeIdx].w = -lcDot(Normal, Points[0]) / Length;
|
|
}
|
|
}
|
|
else if (!strcmp(Token, "CYLINDRICAL"))
|
|
{
|
|
Token += 12;
|
|
|
|
char FileName[LC_MAXPATH];
|
|
lcVector3 Points[3];
|
|
float Angle;
|
|
|
|
sscanf(Token, "%f %f %f %f %f %f %f %f %f %f %s", &Points[0].x, &Points[0].y, &Points[0].z, &Points[1].x, &Points[1].y, &Points[1].z, &Points[2].x, &Points[2].y, &Points[2].z, &Angle, FileName);
|
|
|
|
Points[0] = lcMul31(Points[0], CurrentTransform);
|
|
Points[1] = lcMul31(Points[1], CurrentTransform);
|
|
Points[2] = lcMul31(Points[2], CurrentTransform);
|
|
|
|
CleanTextureName(FileName);
|
|
|
|
lcLibraryTextureMap& Map = TextureStack.Add();
|
|
Map.Next = false;
|
|
Map.Fallback = false;
|
|
Map.Texture = Library->FindTexture(FileName, mCurrentProject, mSearchProjectFolder);
|
|
|
|
Map.Type = lcLibraryTextureMapType::CYLINDRICAL;
|
|
lcVector3 Up = Points[0] - Points[1];
|
|
float UpLength = lcLength(Up);
|
|
lcVector3 Front = lcNormalize(Points[2] - Points[1]);
|
|
lcVector3 Plane1Normal = Up / UpLength;
|
|
lcVector3 Plane2Normal = lcNormalize(lcCross(Front, Up));
|
|
Map.Params.Cylindrical.FrontPlane = lcVector4(Front, -lcDot(Front, Points[1]));
|
|
Map.Params.Cylindrical.UpLength = UpLength;
|
|
Map.Params.Cylindrical.Plane1 = lcVector4(Plane1Normal, -lcDot(Plane1Normal, Points[1]));
|
|
Map.Params.Cylindrical.Plane2 = lcVector4(Plane2Normal, -lcDot(Plane2Normal, Points[1]));
|
|
Map.Angle1 = 360.0f / Angle;
|
|
}
|
|
else if (!strcmp(Token, "SPHERICAL"))
|
|
{
|
|
Token += 10;
|
|
|
|
char FileName[LC_MAXPATH];
|
|
lcVector3 Points[3];
|
|
float Angle1, Angle2;
|
|
|
|
sscanf(Token, "%f %f %f %f %f %f %f %f %f %f %f %s", &Points[0].x, &Points[0].y, &Points[0].z, &Points[1].x, &Points[1].y, &Points[1].z, &Points[2].x, &Points[2].y, &Points[2].z, &Angle1, &Angle2, FileName);
|
|
|
|
Points[0] = lcMul31(Points[0], CurrentTransform);
|
|
Points[1] = lcMul31(Points[1], CurrentTransform);
|
|
Points[2] = lcMul31(Points[2], CurrentTransform);
|
|
|
|
CleanTextureName(FileName);
|
|
|
|
lcLibraryTextureMap& Map = TextureStack.Add();
|
|
Map.Next = false;
|
|
Map.Fallback = false;
|
|
Map.Texture = Library->FindTexture(FileName, mCurrentProject, mSearchProjectFolder);
|
|
Map.Type = lcLibraryTextureMapType::SPHERICAL;
|
|
|
|
lcVector3 Front = lcNormalize(Points[1] - Points[0]);
|
|
lcVector3 Plane1Normal = lcNormalize(lcCross(Front, Points[2] - Points[0]));
|
|
lcVector3 Plane2Normal = lcNormalize(lcCross(Plane1Normal, Front));
|
|
Map.Params.Spherical.FrontPlane = lcVector4(Front, -lcDot(Front, Points[0]));
|
|
Map.Params.Spherical.Center = Points[0];
|
|
Map.Params.Spherical.Plane1 = lcVector4(Plane1Normal, -lcDot(Plane1Normal, Points[0]));
|
|
Map.Params.Spherical.Plane2 = lcVector4(Plane2Normal, -lcDot(Plane2Normal, Points[0]));
|
|
Map.Angle1 = 360.0f / Angle1;
|
|
Map.Angle2 = 180.0f / Angle2;
|
|
}
|
|
}
|
|
else if (!strcmp(Token, "FALLBACK"))
|
|
{
|
|
if (TextureStack.GetSize())
|
|
TextureStack[TextureStack.GetSize() - 1].Fallback = true;
|
|
}
|
|
else if (!strcmp(Token, "END"))
|
|
{
|
|
if (TextureStack.GetSize())
|
|
TextureStack.RemoveIndex(TextureStack.GetSize() - 1);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if (!strcmp(Token, "BFC"))
|
|
{
|
|
while (!LastToken)
|
|
{
|
|
Token = End + 1;
|
|
|
|
while (*Token && *Token <= 32)
|
|
Token++;
|
|
|
|
End = Token;
|
|
while (*End && *End > 32)
|
|
End++;
|
|
|
|
LastToken = (*End == 0);
|
|
*End = 0;
|
|
|
|
if (!strcmp(Token, "INVERTNEXT"))
|
|
InvertNext = true;
|
|
else if (!strcmp(Token, "CCW"))
|
|
WindingCCW = !InvertWinding;
|
|
else if (!strcmp(Token, "CW"))
|
|
WindingCCW = InvertWinding;
|
|
}
|
|
}
|
|
else if (!strcmp(Token, "!:"))
|
|
{
|
|
Token += 3;
|
|
|
|
Line = Token;
|
|
|
|
if (!TextureStack.GetSize())
|
|
continue;
|
|
}
|
|
else
|
|
continue;
|
|
}
|
|
|
|
if (sscanf(Line, "%d %d", &LineType, &ColorCode) != 2)
|
|
continue;
|
|
|
|
if (LineType < 1 || LineType > 5)
|
|
continue;
|
|
|
|
if (ColorCode == 0)
|
|
{
|
|
sscanf(Line, "%d %i", &LineType, &ColorCodeHex);
|
|
|
|
if (ColorCode != ColorCodeHex)
|
|
ColorCode = ColorCodeHex | LC_COLOR_DIRECT;
|
|
}
|
|
|
|
if (ColorCode == 16)
|
|
ColorCode = CurrentColorCode;
|
|
|
|
lcLibraryTextureMap* TextureMap = nullptr;
|
|
|
|
if (TextureStack.GetSize())
|
|
{
|
|
TextureMap = &TextureStack[TextureStack.GetSize() - 1];
|
|
|
|
if (TextureMap->Texture)
|
|
{
|
|
if (TextureMap->Fallback)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (!TextureMap->Fallback)
|
|
continue;
|
|
|
|
TextureMap = nullptr;
|
|
}
|
|
}
|
|
|
|
int Dummy;
|
|
lcVector3 Points[4];
|
|
|
|
switch (LineType)
|
|
{
|
|
case 1:
|
|
{
|
|
char OriginalFileName[LC_MAXPATH];
|
|
float fm[12];
|
|
|
|
sscanf(Line, "%d %i %f %f %f %f %f %f %f %f %f %f %f %f %s", &LineType, &Dummy, &fm[0], &fm[1], &fm[2], &fm[3], &fm[4], &fm[5], &fm[6], &fm[7], &fm[8], &fm[9], &fm[10], &fm[11], OriginalFileName);
|
|
|
|
char FileName[LC_MAXPATH];
|
|
strcpy(FileName, OriginalFileName);
|
|
|
|
char* Ch;
|
|
for (Ch = FileName; *Ch; Ch++)
|
|
{
|
|
if (*Ch >= 'a' && *Ch <= 'z')
|
|
*Ch = *Ch + 'A' - 'a';
|
|
else if (*Ch == '\\')
|
|
*Ch = '/';
|
|
}
|
|
|
|
lcLibraryPrimitive* Primitive = !TextureMap ? Library->FindPrimitive(FileName) : nullptr;
|
|
lcMatrix44 IncludeTransform(lcVector4(fm[3], fm[6], fm[9], 0.0f), lcVector4(fm[4], fm[7], fm[10], 0.0f), lcVector4(fm[5], fm[8], fm[11], 0.0f), lcVector4(fm[0], fm[1], fm[2], 1.0f));
|
|
IncludeTransform = lcMul(IncludeTransform, CurrentTransform);
|
|
bool Mirror = IncludeTransform.Determinant() < 0.0f;
|
|
|
|
auto FileCallback = [this, &IncludeTransform, &ColorCode, &Mirror, &InvertNext, &TextureStack, &MeshDataType](lcFile& File)
|
|
{
|
|
ReadMeshData(File, IncludeTransform, ColorCode, Mirror ^ InvertNext, TextureStack, MeshDataType);
|
|
};
|
|
|
|
if (Primitive)
|
|
{
|
|
if (Primitive->mState != lcPrimitiveState::LOADED && !Library->LoadPrimitive(Primitive))
|
|
break;
|
|
|
|
if (Primitive->mStud)
|
|
mMeshData.AddMeshDataNoDuplicateCheck(Primitive->mMeshData, IncludeTransform, ColorCode, Mirror ^ InvertNext, InvertNext, TextureMap, MeshDataType);
|
|
else if (!Primitive->mSubFile)
|
|
{
|
|
if (mOptimize)
|
|
mMeshData.AddMeshData(Primitive->mMeshData, IncludeTransform, ColorCode, Mirror ^ InvertNext, InvertNext, TextureMap, MeshDataType);
|
|
else
|
|
mMeshData.AddMeshDataNoDuplicateCheck(Primitive->mMeshData, IncludeTransform, ColorCode, Mirror ^ InvertNext, InvertNext, TextureMap, MeshDataType);
|
|
}
|
|
else
|
|
Library->GetPrimitiveFile(Primitive, FileCallback);
|
|
|
|
mMeshData.mHasLogoStud |= Primitive->mMeshData.mHasLogoStud;
|
|
}
|
|
else
|
|
Library->GetPieceFile(FileName, FileCallback);
|
|
} break;
|
|
|
|
case 2:
|
|
sscanf(Line, "%d %i %f %f %f %f %f %f", &LineType, &Dummy, &Points[0].x, &Points[0].y, &Points[0].z, &Points[1].x, &Points[1].y, &Points[1].z);
|
|
|
|
Points[0] = lcMul31(Points[0], CurrentTransform);
|
|
Points[1] = lcMul31(Points[1], CurrentTransform);
|
|
|
|
mMeshData.AddLine(MeshDataType, LineType, ColorCode, WindingCCW, Points, mOptimize);
|
|
break;
|
|
|
|
case 3:
|
|
sscanf(Line, "%d %i %f %f %f %f %f %f %f %f %f", &LineType, &Dummy, &Points[0].x, &Points[0].y, &Points[0].z,
|
|
&Points[1].x, &Points[1].y, &Points[1].z, &Points[2].x, &Points[2].y, &Points[2].z);
|
|
|
|
Points[0] = lcMul31(Points[0], CurrentTransform);
|
|
Points[1] = lcMul31(Points[1], CurrentTransform);
|
|
Points[2] = lcMul31(Points[2], CurrentTransform);
|
|
|
|
if (TextureMap)
|
|
{
|
|
mMeshData.AddTexturedLine(MeshDataType, LineType, ColorCode, WindingCCW, *TextureMap, Points, mOptimize);
|
|
|
|
if (TextureMap->Next)
|
|
TextureStack.RemoveIndex(TextureStack.GetSize() - 1);
|
|
}
|
|
else
|
|
mMeshData.AddLine(MeshDataType, LineType, ColorCode, WindingCCW, Points, mOptimize);
|
|
break;
|
|
|
|
case 4:
|
|
sscanf(Line, "%d %i %f %f %f %f %f %f %f %f %f %f %f %f", &LineType, &Dummy, &Points[0].x, &Points[0].y, &Points[0].z,
|
|
&Points[1].x, &Points[1].y, &Points[1].z, &Points[2].x, &Points[2].y, &Points[2].z, &Points[3].x, &Points[3].y, &Points[3].z);
|
|
|
|
Points[0] = lcMul31(Points[0], CurrentTransform);
|
|
Points[1] = lcMul31(Points[1], CurrentTransform);
|
|
Points[2] = lcMul31(Points[2], CurrentTransform);
|
|
Points[3] = lcMul31(Points[3], CurrentTransform);
|
|
|
|
if (TextureMap)
|
|
{
|
|
mMeshData.AddTexturedLine(MeshDataType, LineType, ColorCode, WindingCCW, *TextureMap, Points, mOptimize);
|
|
|
|
if (TextureMap->Next)
|
|
TextureStack.RemoveIndex(TextureStack.GetSize() - 1);
|
|
}
|
|
else
|
|
mMeshData.AddLine(MeshDataType, LineType, ColorCode, WindingCCW, Points, mOptimize);
|
|
break;
|
|
|
|
case 5:
|
|
sscanf(Line, "%d %i %f %f %f %f %f %f %f %f %f %f %f %f", &LineType, &Dummy, &Points[0].x, &Points[0].y, &Points[0].z,
|
|
&Points[1].x, &Points[1].y, &Points[1].z, &Points[2].x, &Points[2].y, &Points[2].z, &Points[3].x, &Points[3].y, &Points[3].z);
|
|
|
|
Points[0] = lcMul31(Points[0], CurrentTransform);
|
|
Points[1] = lcMul31(Points[1], CurrentTransform);
|
|
Points[2] = lcMul31(Points[2], CurrentTransform);
|
|
Points[3] = lcMul31(Points[3], CurrentTransform);
|
|
|
|
mMeshData.AddLine(MeshDataType, LineType, ColorCode, WindingCCW, Points, mOptimize);
|
|
break;
|
|
}
|
|
|
|
InvertNext = false;
|
|
}
|
|
|
|
return true;
|
|
}
|