leocad/common/pieceinf.cpp

1038 lines
28 KiB
C++
Raw Normal View History

2011-09-07 23:06:51 +02:00
// Information about how to draw a piece and some more stuff.
//
#include "lc_global.h"
2012-03-29 03:10:55 +02:00
#include "lc_math.h"
2012-04-14 01:41:58 +02:00
#include "lc_mesh.h"
#include "lc_colors.h"
2011-09-07 23:06:51 +02:00
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "opengl.h"
#include "texture.h"
#include "pieceinf.h"
#include "project.h"
#include "globals.h"
#include "matrix.h"
#include "library.h"
#include "lc_application.h"
#define SIDES 16
static float sintbl[SIDES];
static float costbl[SIDES];
#define LC_MESH 1
#define LC_STUD 2
#define LC_STUD2 3
#define LC_STUD3 4
#define LC_STUD4 5
// measurements (in centimeters)
//#define LC_FLAT_HEIGHT 0.32f
//#define LC_BRICK_HEIGHT (3*LC_FLAT_HEIGHT)
//#define LC_BASEPLATE_HEIGHT (LC_FLAT_HEIGHT/2)
//#define LC_HALF_WIDE 0.4f
//#define LC_ONE_WIDE 0.8f
//#define LC_BRICK_WALL 0.125f
#define LC_STUD_HEIGHT 0.16f
#define LC_STUD_RADIUS 0.24f
#define LC_KNOB_RADIUS 0.32f
//#define LC_STUD_TECH_RADIUS (LC_FLAT_HEIGHT/2)
static void GetFrustumPlanes (float planes[6][4])
{
// Storage for the Modelview, Projection and their multiplication (Frustum) matrix.
float mv[16], pj[16], fm[16];
glGetFloatv(GL_MODELVIEW_MATRIX, mv);
glGetFloatv(GL_PROJECTION_MATRIX, pj);
fm[0] = pj[0] * mv[0] + pj[4] * mv[1] + pj[8] * mv[2] + pj[12] * mv[3];
fm[4] = pj[0] * mv[4] + pj[4] * mv[5] + pj[8] * mv[6] + pj[12] * mv[7];
fm[8] = pj[0] * mv[8] + pj[4] * mv[9] + pj[8] * mv[10] + pj[12] * mv[11];
fm[12] = pj[0] * mv[12] + pj[4] * mv[13] + pj[8] * mv[14] + pj[12] * mv[15];
fm[1] = pj[1] * mv[0] + pj[5] * mv[1] + pj[9] * mv[2] + pj[13] * mv[3];
fm[5] = pj[1] * mv[4] + pj[5] * mv[5] + pj[9] * mv[6] + pj[13] * mv[7];
fm[9] = pj[1] * mv[8] + pj[5] * mv[9] + pj[9] * mv[10] + pj[13] * mv[11];
fm[13] = pj[1] * mv[12] + pj[5] * mv[13] + pj[9] * mv[14] + pj[13] * mv[15];
fm[2] = pj[2] * mv[0] + pj[6] * mv[1] + pj[10] * mv[2] + pj[14] * mv[3];
fm[6] = pj[2] * mv[4] + pj[6] * mv[5] + pj[10] * mv[6] + pj[14] * mv[7];
fm[10] = pj[2] * mv[8] + pj[6] * mv[9] + pj[10] * mv[10] + pj[14] * mv[11];
fm[14] = pj[2] * mv[12] + pj[6] * mv[13] + pj[10] * mv[14] + pj[14] * mv[15];
fm[3] = pj[3] * mv[0] + pj[7] * mv[1] + pj[11] * mv[2] + pj[15] * mv[3];
fm[7] = pj[3] * mv[4] + pj[7] * mv[5] + pj[11] * mv[6] + pj[15] * mv[7];
fm[11] = pj[3] * mv[8] + pj[7] * mv[9] + pj[11] * mv[10] + pj[15] * mv[11];
fm[15] = pj[3] * mv[12] + pj[7] * mv[13] + pj[11] * mv[14] + pj[15] * mv[15];
planes[0][0] = (fm[0] - fm[3]) * -1;
planes[0][1] = (fm[4] - fm[7]) * -1;
planes[0][2] = (fm[8] - fm[11]) * -1;
planes[0][3] = (fm[12] - fm[15]) * -1;
planes[1][0] = fm[0] + fm[3];
planes[1][1] = fm[4] + fm[7];
planes[1][2] = fm[8] + fm[11];
planes[1][3] = fm[12] + fm[15];
planes[2][0] = (fm[1] - fm[3]) * -1;
planes[2][1] = (fm[5] - fm[7]) * -1;
planes[2][2] = (fm[9] - fm[11]) * -1;
planes[2][3] = (fm[13] - fm[15]) * -1;
planes[3][0] = fm[1] + fm[3];
planes[3][1] = fm[5] + fm[7];
planes[3][2] = fm[9] + fm[11];
planes[3][3] = fm[13] + fm[15];
planes[4][0] = (fm[2] - fm[3]) * -1;
planes[4][1] = (fm[6] - fm[7]) * -1;
planes[4][2] = (fm[10] - fm[11]) * -1;
planes[4][3] = (fm[14] - fm[15]) * -1;
planes[5][0] = fm[2] + fm[3];
planes[5][1] = fm[6] + fm[7];
planes[5][2] = fm[10] + fm[11];
planes[5][3] = fm[14] + fm[15];
}
bool BoxOutsideFrustum (float Dimensions[6])
{
float d, planes[6][4], verts[8][3] = {
{ Dimensions[0], Dimensions[1], Dimensions[5] },
{ Dimensions[3], Dimensions[1], Dimensions[5] },
{ Dimensions[0], Dimensions[1], Dimensions[2] },
{ Dimensions[3], Dimensions[4], Dimensions[5] },
{ Dimensions[3], Dimensions[4], Dimensions[2] },
{ Dimensions[0], Dimensions[4], Dimensions[2] },
{ Dimensions[0], Dimensions[4], Dimensions[5] },
{ Dimensions[3], Dimensions[1], Dimensions[2] } };
GetFrustumPlanes (planes);
for (int i = 0; i < 6; i++)
for (int j = 0; j < 8; j++)
{
d = verts[j][0]*planes[i][0] + verts[j][1]*planes[i][1] + verts[j][2]*planes[i][2] + planes[i][3];
if (d < -0.001f)
return true;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
// PieceInfo construction/destruction
2012-04-14 01:41:58 +02:00
PieceInfo::PieceInfo()
2011-09-07 23:06:51 +02:00
{
2012-04-14 01:41:58 +02:00
mMesh = NULL;
2011-09-07 23:06:51 +02:00
}
2012-04-14 01:41:58 +02:00
PieceInfo::~PieceInfo()
2011-09-07 23:06:51 +02:00
{
2012-04-14 01:41:58 +02:00
FreeInformation();
2011-09-07 23:06:51 +02:00
}
/////////////////////////////////////////////////////////////////////////////
// File I/O
2012-03-23 00:44:56 +01:00
void PieceInfo::LoadIndex(lcFile& file)
2011-09-07 23:06:51 +02:00
{
static bool init = false;
short sh[6];
short scale;
// Initialize sin/cos table
if (!init)
{
for (int i = 0; i < SIDES; i++)
{
sintbl[i] = (float)sin((PI2*i)/(SIDES));
costbl[i] = (float)cos((PI2*i)/(SIDES));
}
init = true;
}
// TODO: don't change ref. if we're reloading ?
m_nRef = 0;
m_nBoxList = 0;
2012-03-23 00:44:56 +01:00
file.ReadBuffer(m_strName, LC_PIECE_NAME_LEN);
file.ReadBuffer(m_strDescription, 64);
2011-09-07 23:06:51 +02:00
m_strDescription[64] = '\0';
2012-03-23 00:44:56 +01:00
file.ReadS16(sh, 6);
lcuint8 Flags;
file.ReadU8(&Flags, 1);
m_nFlags = Flags;
2012-03-23 00:44:56 +01:00
lcuint32 Groups; file.ReadU32(&Groups, 1);
file.ReadU32(&m_nOffset, 1);
file.ReadU32(&m_nSize, 1);
2011-09-07 23:06:51 +02:00
if (m_nFlags & LC_PIECE_SMALL)
scale = 10000;
else if (m_nFlags & LC_PIECE_MEDIUM)
scale = 1000;
else
scale = 100;
m_fDimensions[0] = (float)sh[0]/scale;
m_fDimensions[1] = (float)sh[1]/scale;
m_fDimensions[2] = (float)sh[2]/scale;
m_fDimensions[3] = (float)sh[3]/scale;
m_fDimensions[4] = (float)sh[4]/scale;
m_fDimensions[5] = (float)sh[5]/scale;
}
void PieceInfo::CreatePlaceholder(const char* Name)
{
m_nRef = 0;
m_nBoxList = 0;
strncpy(m_strName, Name, sizeof(m_strName));
m_strName[sizeof(m_strName)-1] = 0;
strncpy(m_strDescription, Name, sizeof(m_strDescription));
m_strDescription[sizeof(m_strDescription)-1] = 0;
m_nFlags = LC_PIECE_PLACEHOLDER;
m_nOffset = 0;
m_nSize = 0;
m_fDimensions[0] = 0.4f;
m_fDimensions[1] = 0.4f;
m_fDimensions[2] = 0.16f;
m_fDimensions[3] = -0.4f;
m_fDimensions[4] = -0.4f;
m_fDimensions[5] = -0.96f;
}
2011-09-07 23:06:51 +02:00
void PieceInfo::AddRef()
{
if (m_nRef == 0)
LoadInformation();
m_nRef++;
}
void PieceInfo::DeRef()
{
m_nRef--;
if (m_nRef == 0)
FreeInformation();
}
void PieceInfo::CreateBoxDisplayList()
{
if (m_nBoxList)
return;
// Create a display for the bounding box.
m_nBoxList = glGenLists(1);
glNewList(m_nBoxList, GL_COMPILE);
glEnableClientState(GL_VERTEX_ARRAY);
float box[24][3] =
{
{ m_fDimensions[0], m_fDimensions[1], m_fDimensions[2] },
{ m_fDimensions[3], m_fDimensions[1], m_fDimensions[2] },
{ m_fDimensions[3], m_fDimensions[4], m_fDimensions[2] },
{ m_fDimensions[0], m_fDimensions[4], m_fDimensions[2] },
{ m_fDimensions[0], m_fDimensions[1], m_fDimensions[5] },
{ m_fDimensions[0], m_fDimensions[4], m_fDimensions[5] },
{ m_fDimensions[3], m_fDimensions[4], m_fDimensions[5] },
{ m_fDimensions[3], m_fDimensions[1], m_fDimensions[5] },
{ m_fDimensions[3], m_fDimensions[4], m_fDimensions[2] },
{ m_fDimensions[3], m_fDimensions[1], m_fDimensions[2] },
{ m_fDimensions[3], m_fDimensions[1], m_fDimensions[5] },
{ m_fDimensions[3], m_fDimensions[4], m_fDimensions[5] },
{ m_fDimensions[0], m_fDimensions[4], m_fDimensions[5] },
{ m_fDimensions[0], m_fDimensions[1], m_fDimensions[5] },
{ m_fDimensions[0], m_fDimensions[1], m_fDimensions[2] },
{ m_fDimensions[0], m_fDimensions[4], m_fDimensions[2] },
{ m_fDimensions[0], m_fDimensions[1], m_fDimensions[5] },
{ m_fDimensions[3], m_fDimensions[1], m_fDimensions[5] },
{ m_fDimensions[3], m_fDimensions[1], m_fDimensions[2] },
{ m_fDimensions[0], m_fDimensions[1], m_fDimensions[2] },
{ m_fDimensions[0], m_fDimensions[4], m_fDimensions[2] },
{ m_fDimensions[3], m_fDimensions[4], m_fDimensions[2] },
{ m_fDimensions[3], m_fDimensions[4], m_fDimensions[5] },
{ m_fDimensions[0], m_fDimensions[4], m_fDimensions[5] }
};
glVertexPointer(3, GL_FLOAT, 0, box);
glDrawArrays(GL_QUADS, 0, 24);
glEndList();
}
2012-04-14 01:41:58 +02:00
inline lcuint16 EndianSwap(lcuint16 Val)
{
return LCUINT16(Val);
}
inline lcuint32 EndianSwap(lcuint32 Val)
{
return LCUINT32(Val);
}
template<typename SrcType, typename DstType>
static void WriteMeshDrawInfo(lcuint32*& Data, lcMesh* Mesh, float*& OutVertex, int* SectionIndices, lcMeshSection** DstSections)
2012-04-14 01:41:58 +02:00
{
int NumColors = EndianSwap(*Data);
Data++;
2012-04-14 01:41:58 +02:00
for (int Color = 0; Color < NumColors; Color++)
{
int ColorIdx = lcGetColorIndex(EndianSwap(*Data));
Data++;
2012-04-14 01:41:58 +02:00
SrcType* SrcPtr = (SrcType*)Data;
2012-04-14 01:41:58 +02:00
int NumQuads = EndianSwap(*SrcPtr);
SrcPtr++;
int NumTris = EndianSwap(*(SrcPtr + NumQuads));
if (NumTris || NumQuads)
{
lcMeshSection* Section = DstSections[ColorIdx * 2 + 0];
DstType* OutIndex = (DstType*)Mesh->mIndexBuffer.mData + Section->IndexOffset / sizeof(DstType) + Section->NumIndices;
for (int i = 0; i < NumQuads; i += 4)
{
*OutIndex++ = EndianSwap(SrcPtr[0]);
*OutIndex++ = EndianSwap(SrcPtr[1]);
*OutIndex++ = EndianSwap(SrcPtr[2]);
*OutIndex++ = EndianSwap(SrcPtr[0]);
*OutIndex++ = EndianSwap(SrcPtr[2]);
*OutIndex++ = EndianSwap(SrcPtr[3]);
SrcPtr += 4;
}
SrcPtr++;
for (int i = 0; i < NumTris; i++)
{
*OutIndex++ = EndianSwap(*SrcPtr);
SrcPtr++;
}
Section->NumIndices += NumQuads / 4 * 6 + NumTris;
}
else
SrcPtr++;
int NumLines = EndianSwap(*SrcPtr);
SrcPtr++;
if (NumLines)
{
lcMeshSection* Section = DstSections[ColorIdx * 2 + 1];
DstType* OutIndex = (DstType*)Mesh->mIndexBuffer.mData + Section->IndexOffset / sizeof(DstType) + Section->NumIndices;
for (int i = 0; i < NumLines; i++)
{
*OutIndex++ = EndianSwap(*SrcPtr);
SrcPtr++;
}
Section->NumIndices += NumLines;
}
Data = (lcuint32*)SrcPtr;
}
2012-04-14 01:41:58 +02:00
}
template<class DstType>
static void WriteStudDrawInfo(int ColorIdx, const Matrix44& Mat, lcMesh* Mesh, float*& OutVertex, float Radius, int* SectionIndices, lcMeshSection** DstSections)
{
// Build vertices.
int BaseVertex = (OutVertex - (float*)Mesh->mVertexBuffer.mData) / 3;
Vector3 Vert;
for (int i = 0; i < SIDES; i++)
{
Vert = Mul31(Vector3(Radius * costbl[i], Radius * sintbl[i], 0.0f), Mat);
*OutVertex++ = Vert[0];
*OutVertex++ = Vert[1];
*OutVertex++ = Vert[2];
Vert = Mul31(Vector3(Radius * costbl[i], Radius * sintbl[i], LC_STUD_HEIGHT), Mat);
*OutVertex++ = Vert[0];
*OutVertex++ = Vert[1];
*OutVertex++ = Vert[2];
}
Vert = Mul31(Vector3(0.0f, 0.0f, LC_STUD_HEIGHT), Mat);
*OutVertex++ = Vert[0];
*OutVertex++ = Vert[1];
*OutVertex++ = Vert[2];
int v0 = BaseVertex + 2 * SIDES;
// Triangles.
lcMeshSection* Section = DstSections[ColorIdx * 2 + 0];
DstType* OutIndex = (DstType*)Mesh->mIndexBuffer.mData + Section->IndexOffset / sizeof(DstType) + Section->NumIndices;
for (int i = 0; i < SIDES; i++)
{
int i1 = BaseVertex + (i % SIDES) * 2;
int i2 = BaseVertex + ((i + 1) % SIDES) * 2;
int v1 = i1;
int v2 = i1 + 1;
int v3 = i2;
int v4 = i2 + 1;
*OutIndex++ = v0;
*OutIndex++ = v2;
*OutIndex++ = v4;
*OutIndex++ = v1;
*OutIndex++ = v3;
*OutIndex++ = v2;
*OutIndex++ = v3;
*OutIndex++ = v4;
*OutIndex++ = v2;
}
Section->NumIndices += 9 * SIDES;
// Lines.
Section = DstSections[gEdgeColor * 2 + 1];
OutIndex = (DstType*)Mesh->mIndexBuffer.mData + Section->IndexOffset / sizeof(DstType) + Section->NumIndices;
for (int i = 0; i < SIDES; i++)
{
int i1 = BaseVertex + (i % SIDES) * 2;
int i2 = BaseVertex + ((i + 1) % SIDES) * 2;
int v1 = i1;
int v2 = i1 + 1;
int v3 = i2;
int v4 = i2 + 1;
*OutIndex++ = v1;
*OutIndex++ = v3;
*OutIndex++ = v2;
*OutIndex++ = v4;
}
Section->NumIndices += 4 * SIDES;
}
template<class DstType>
static void WriteHollowStudDrawInfo(int ColorIdx, const Matrix44& Mat, lcMesh* Mesh, float*& OutVertex, float InnerRadius, float OuterRadius, int* SectionIndices, lcMeshSection** DstSections)
{
// Build vertices.
int BaseVertex = (OutVertex - (float*)Mesh->mVertexBuffer.mData) / 3;
Vector3 Vert;
for (int i = 0; i < SIDES; i++)
{
// Outside.
Vert = Mul31(Vector3(OuterRadius * costbl[i], OuterRadius * sintbl[i], 0.0f), Mat);
*OutVertex++ = Vert[0];
*OutVertex++ = Vert[1];
*OutVertex++ = Vert[2];
Vert = Mul31(Vector3(OuterRadius * costbl[i], OuterRadius * sintbl[i], LC_STUD_HEIGHT), Mat);
*OutVertex++ = Vert[0];
*OutVertex++ = Vert[1];
*OutVertex++ = Vert[2];
// Inside.
Vert = Mul31(Vector3(InnerRadius * costbl[i], InnerRadius * sintbl[i], LC_STUD_HEIGHT), Mat);
*OutVertex++ = Vert[0];
*OutVertex++ = Vert[1];
*OutVertex++ = Vert[2];
Vert = Mul31(Vector3(InnerRadius * costbl[i], InnerRadius * sintbl[i], 0.0f), Mat);
*OutVertex++ = Vert[0];
*OutVertex++ = Vert[1];
*OutVertex++ = Vert[2];
}
// Triangles.
lcMeshSection* Section = DstSections[ColorIdx * 2 + 0];
DstType* OutIndex = (DstType*)Mesh->mIndexBuffer.mData + Section->IndexOffset / sizeof(DstType) + Section->NumIndices;
for (int i = 0; i < SIDES; i++)
{
int i1 = BaseVertex + (i % SIDES) * 4;
int i2 = BaseVertex + ((i + 1) % SIDES) * 4;
int v1 = i1;
int v2 = i1 + 1;
int v3 = i1 + 2;
int v4 = i1 + 3;
int v5 = i2;
int v6 = i2 + 1;
int v7 = i2 + 2;
int v8 = i2 + 3;
*OutIndex++ = v1;
*OutIndex++ = v5;
*OutIndex++ = v2;
*OutIndex++ = v5;
*OutIndex++ = v6;
*OutIndex++ = v2;
*OutIndex++ = v2;
*OutIndex++ = v6;
*OutIndex++ = v3;
*OutIndex++ = v6;
*OutIndex++ = v7;
*OutIndex++ = v3;
*OutIndex++ = v3;
*OutIndex++ = v7;
*OutIndex++ = v4;
*OutIndex++ = v7;
*OutIndex++ = v8;
*OutIndex++ = v4;
}
Section->NumIndices += 18 * SIDES;
// Lines.
Section = DstSections[gEdgeColor * 2 + 1];
OutIndex = (DstType*)Mesh->mIndexBuffer.mData + Section->IndexOffset / sizeof(DstType) + Section->NumIndices;
for (int i = 0; i < SIDES; i++)
{
int i1 = BaseVertex + (i % SIDES) * 4;
int i2 = BaseVertex + ((i + 1) % SIDES) * 4;
int v1 = i1;
int v2 = i1 + 1;
int v3 = i1 + 2;
int v4 = i1 + 3;
int v5 = i2;
int v6 = i2 + 1;
int v7 = i2 + 2;
int v8 = i2 + 3;
*OutIndex++ = v1;
*OutIndex++ = v5;
*OutIndex++ = v2;
*OutIndex++ = v6;
*OutIndex++ = v3;
*OutIndex++ = v7;
*OutIndex++ = v4;
*OutIndex++ = v8;
}
Section->NumIndices += 8 * SIDES;
}
template<typename DstType>
void PieceInfo::BuildMesh(void* Data, int* SectionIndices)
{
// Create empty sections.
lcMeshSection** DstSections = new lcMeshSection*[gColorList.GetSize() * 2];
memset(DstSections, 0, sizeof(DstSections[0]) * gColorList.GetSize() * 2);
2012-04-14 01:41:58 +02:00
int IndexOffset = 0;
int NumSections = 0;
for (int ColorIdx = 0; ColorIdx < gColorList.GetSize(); ColorIdx++)
2012-04-14 01:41:58 +02:00
{
if (SectionIndices[ColorIdx * 2 + 0])
{
lcMeshSection* Section = &mMesh->mSections[NumSections];
DstSections[ColorIdx * 2 + 0] = Section;
Section->PrimitiveType = GL_TRIANGLES;
Section->ColorIndex = ColorIdx;
Section->IndexOffset = IndexOffset;
Section->NumIndices = 0;
IndexOffset += SectionIndices[ColorIdx * 2 + 0] * sizeof(DstType);
NumSections++;
if (ColorIdx == gDefaultColor)
m_nFlags |= LC_PIECE_HAS_DEFAULT;
else
{
if (lcIsColorTranslucent(ColorIdx))
m_nFlags |= LC_PIECE_HAS_TRANSLUCENT;
else
m_nFlags |= LC_PIECE_HAS_SOLID;
}
2012-04-14 01:41:58 +02:00
}
if (SectionIndices[ColorIdx * 2 + 1])
{
lcMeshSection* Section = &mMesh->mSections[NumSections];
DstSections[ColorIdx * 2 + 1] = Section;
Section->PrimitiveType = GL_LINES;
Section->ColorIndex = ColorIdx;
Section->IndexOffset = IndexOffset;
Section->NumIndices = 0;
IndexOffset += SectionIndices[ColorIdx * 2 + 1] * sizeof(DstType);
NumSections++;
m_nFlags |= LC_PIECE_HAS_LINES;
2012-04-14 01:41:58 +02:00
}
}
// Read groups
lcuint32* longs = (lcuint32*)Data;
int NumVertices = LCUINT32(*longs);
float* OutVertex = (float*)mMesh->mVertexBuffer.mData + NumVertices * 3;
lcuint8* bytes = (lcuint8*)(longs + 1);
bytes += NumVertices * sizeof(lcint16) * 3;
lcuint16 ConnectionCount = LCUINT16(*((lcuint16*)bytes));
bytes += 2 + (1 + 6 * 2) * ConnectionCount;
bytes++; // TextureCount
2012-04-14 19:05:55 +02:00
lcuint16 GroupCount = LCUINT16(*((lcuint16*)bytes));
bytes += sizeof(lcuint16);
2012-04-14 01:41:58 +02:00
2012-04-14 19:05:55 +02:00
while (GroupCount--)
2012-04-14 01:41:58 +02:00
{
bytes += 1 + 2 * *bytes;
lcuint32* info = (lcuint32*)bytes;
2012-04-14 01:41:58 +02:00
switch (*info)
2012-04-14 01:41:58 +02:00
{
case LC_MESH:
{
info++;
2012-04-14 01:41:58 +02:00
if (m_nFlags & LC_PIECE_LONGDATA_FILE)
WriteMeshDrawInfo<lcuint32, DstType>(info, mMesh, OutVertex, SectionIndices, DstSections);
2012-04-14 01:41:58 +02:00
else
WriteMeshDrawInfo<lcuint16, DstType>(info, mMesh, OutVertex, SectionIndices, DstSections);
2012-04-14 01:41:58 +02:00
} break;
case LC_STUD:
case LC_STUD3:
{
info++;
int ColorIdx = lcGetColorIndex(LCUINT32(*info));
float* MatFloats = (float*)(info + 1);
info += 1 + 12;
2012-04-14 01:41:58 +02:00
for (int i = 0; i < 12; i++)
MatFloats[i] = LCFLOAT(MatFloats[i]);
Matrix44 Mat(Vector4(MatFloats[0], MatFloats[1], MatFloats[2], 0.0f),
Vector4(MatFloats[3], MatFloats[4], MatFloats[5], 0.0f),
Vector4(MatFloats[6], MatFloats[7], MatFloats[8], 0.0f),
Vector4(MatFloats[9], MatFloats[10], MatFloats[11], 1.0f));
WriteStudDrawInfo<DstType>(ColorIdx, Mat, mMesh, OutVertex, LC_STUD_RADIUS, SectionIndices, DstSections);
} break;
case LC_STUD2:
case LC_STUD4:
{
info++;
int ColorIdx = lcGetColorIndex(LCUINT32(*info));
float* MatFloats = (float*)(info + 1);
info += 1 + 12;
2012-04-14 01:41:58 +02:00
for (int i = 0; i < 12; i++)
MatFloats[i] = LCFLOAT(MatFloats[i]);
Matrix44 Mat(Vector4(MatFloats[0], MatFloats[1], MatFloats[2], 0.0f),
Vector4(MatFloats[3], MatFloats[4], MatFloats[5], 0.0f),
Vector4(MatFloats[6], MatFloats[7], MatFloats[8], 0.0f),
Vector4(MatFloats[9], MatFloats[10], MatFloats[11], 1.0f));
WriteHollowStudDrawInfo<DstType>(ColorIdx, Mat, mMesh, OutVertex, 0.16f, LC_STUD_RADIUS, SectionIndices, DstSections);
} break;
}
info++; // should be 0
bytes = (lcuint8*)info;
2012-04-14 01:41:58 +02:00
}
delete[] DstSections;
}
2011-09-07 23:06:51 +02:00
void PieceInfo::LoadInformation()
{
if (m_nFlags & LC_PIECE_PLACEHOLDER)
{
mMesh->CreateBox();
return;
}
lcDiskFile bin;
char filename[LC_MAXPATH];
void* buf;
lcuint32 verts, *longs, fixverts;
lcuint8 *bytes, *tmp, bt;
float scale, shift;
lcint16* shorts;
FreeInformation();
// Open pieces.bin and buffer the information we need.
strcpy (filename, lcGetPiecesLibrary()->GetLibraryPath());
strcat (filename, "pieces.bin");
if (!bin.Open (filename, "rb"))
return;
buf = malloc(m_nSize);
bin.Seek(m_nOffset, SEEK_SET);
bin.ReadBuffer(buf, m_nSize);
shift = 1.0f/(1<<14);
scale = 0.01f;
if (m_nFlags & LC_PIECE_MEDIUM) scale = 0.001f;
if (m_nFlags & LC_PIECE_SMALL) scale = 0.0001f;
longs = (lcuint32*)buf;
fixverts = verts = LCUINT32(*longs);
bytes = (unsigned char*)(longs + 1);
bytes += verts * sizeof(lcint16) * 3;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
lcuint16 ConnectionCount = LCUINT16(*((lcuint16*)bytes));
bytes += 2 + (1 + 6 * 2) * ConnectionCount;
bytes++; // TextureCount
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
// Read groups.
2012-04-14 19:05:55 +02:00
lcuint16 GroupCount = LCUINT16(*((lcuint16*)bytes));
2012-04-14 01:41:58 +02:00
bytes += sizeof(lcuint16);
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
// Count sections, vertices and indices.
tmp = bytes;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
int NumSections = 0;
int NumVertices = fixverts;
int NumIndices = 0;
ObjArray<int> SectionIndices(gColorList.GetSize() * 2);
SectionIndices.SetSize(gColorList.GetSize() * 2);
memset(&SectionIndices[0], 0, SectionIndices.GetSize() * sizeof(int));
2011-09-07 23:06:51 +02:00
2012-04-14 19:05:55 +02:00
while (GroupCount--)
2012-04-14 01:41:58 +02:00
{
bt = *bytes;
bytes++;
bytes += bt*sizeof(lcuint16);
2011-09-07 23:06:51 +02:00
lcuint32* info = (lcuint32*)bytes;
while (*info)
2011-09-07 23:06:51 +02:00
{
if (*info == LC_MESH)
{
info++;
lcuint32 NumColors = LCUINT32(*info);
info++;
while (NumColors--)
2011-09-07 23:06:51 +02:00
{
int ColorIndex = lcGetColorIndex(LCUINT32(*info));
info++;
2011-09-07 23:06:51 +02:00
if (SectionIndices.GetSize() < (ColorIndex + 1) * 2)
{
int OldSize = SectionIndices.GetSize();
SectionIndices.SetSize((ColorIndex + 1) * 2);
memset(&SectionIndices[OldSize], 0, (SectionIndices.GetSize() - OldSize) * sizeof(int));
}
if (m_nFlags & LC_PIECE_LONGDATA_FILE)
2011-09-07 23:06:51 +02:00
{
lcuint32* Indices = (lcuint32*)info;
int Triangles = LCUINT32(*Indices) / 4 * 6;
Indices += LCUINT32(*Indices) + 1;
Triangles += LCUINT32(*Indices);
Indices += LCUINT32(*Indices) + 1;
2012-04-14 01:41:58 +02:00
if (Triangles)
{
if (!SectionIndices[ColorIndex * 2 + 0])
NumSections++;
SectionIndices[ColorIndex * 2 + 0] += Triangles;
NumIndices += Triangles;
}
int Lines = LCUINT32(*Indices);
Indices += LCUINT32(*Indices) + 1;
2012-04-14 01:41:58 +02:00
if (Lines)
{
if (!SectionIndices[ColorIndex * 2 + 1])
NumSections++;
SectionIndices[ColorIndex * 2 + 1] += Lines;
NumIndices += Lines;
}
2011-09-07 23:06:51 +02:00
info = (lcuint32*)Indices;
}
else
2011-09-07 23:06:51 +02:00
{
lcuint16* Indices = (lcuint16*)info;
int Triangles = LCUINT16(*Indices) / 4 * 6;
Indices += LCUINT16(*Indices) + 1;
Triangles += LCUINT16(*Indices);
Indices += LCUINT16(*Indices) + 1;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
if (Triangles)
{
if (!SectionIndices[ColorIndex * 2 + 0])
NumSections++;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
SectionIndices[ColorIndex * 2 + 0] += Triangles;
NumIndices += Triangles;
}
2011-09-07 23:06:51 +02:00
int Lines = LCUINT16(*Indices);
Indices += LCUINT16(*Indices) + 1;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
if (Lines)
{
if (!SectionIndices[ColorIndex * 2 + 1])
NumSections++;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
SectionIndices[ColorIndex * 2 + 1] += Lines;
NumIndices += Lines;
}
2011-09-07 23:06:51 +02:00
info = (lcuint32*)Indices;
}
}
}
else if ((*info == LC_STUD) || (*info == LC_STUD3))
{
info++;
int ColorIndex = lcGetColorIndex(LCUINT32(*info));
info += 1 + 12;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
NumVertices += (2 * SIDES) + 1;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
if (!SectionIndices[ColorIndex * 2 + 0])
NumSections++;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
SectionIndices[ColorIndex * 2 + 0] += 9 * SIDES;
NumIndices += 9 * SIDES;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
if (!SectionIndices[gEdgeColor * 2 + 1])
NumSections++;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
SectionIndices[gEdgeColor * 2 + 1] += 4 * SIDES;
NumIndices += 4 * SIDES;
}
else if ((*info == LC_STUD2) || (*info == LC_STUD4))
{
info++;
int ColorIndex = lcGetColorIndex(LCUINT32(*info));
info += 1 + 12;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
NumVertices += 4 * SIDES;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
if (!SectionIndices[ColorIndex * 2 + 0])
NumSections++;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
SectionIndices[ColorIndex * 2 + 0] += 18 * SIDES;
NumIndices += 18 * SIDES;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
if (!SectionIndices[gEdgeColor * 2 + 1])
NumSections++;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
SectionIndices[gEdgeColor * 2 + 1] += 8 * SIDES;
NumIndices += 8 * SIDES;
}
2012-04-14 01:41:58 +02:00
}
info++; // should be 0
bytes = (lcuint8*)info;
2012-04-14 01:41:58 +02:00
}
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
mMesh = new lcMesh();
mMesh->Create(NumSections, NumVertices, NumIndices);
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
float* OutVertex = (float*)mMesh->mVertexBuffer.mData;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
shorts = (lcint16*)(longs + 1);
for (verts = 0; verts < LCUINT32(*longs); verts++)
{
*OutVertex++ = (float)LCINT16(*shorts)*scale;
shorts++;
*OutVertex++ = (float)LCINT16(*shorts)*scale;
shorts++;
*OutVertex++ = (float)LCINT16(*shorts)*scale;
shorts++;
}
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
if (NumVertices < 0x10000)
BuildMesh<GLushort>(buf, &SectionIndices[0]);
2012-04-14 01:41:58 +02:00
else
BuildMesh<GLuint>(buf, &SectionIndices[0]);
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
mMesh->UpdateBuffers();
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
free(buf);
2011-09-07 23:06:51 +02:00
}
void PieceInfo::FreeInformation()
{
2012-04-14 01:41:58 +02:00
delete mMesh;
mMesh = NULL;
2011-09-07 23:06:51 +02:00
2012-04-14 01:41:58 +02:00
if (m_nBoxList != 0)
glDeleteLists(m_nBoxList, 1);
m_nBoxList = 0;
2011-09-07 23:06:51 +02:00
}
// Zoom extents for the preview window and print catalog
void PieceInfo::ZoomExtents(float Fov, float Aspect, float* EyePos) const
{
float Eye[3] = { -100.0f, -100.0f, 50.0f };
if (EyePos)
{
Eye[0] = EyePos[0];
Eye[1] = EyePos[1];
Eye[2] = EyePos[2];
}
// Get perspective information.
float Alpha = Fov / 2.0f;
float HalfFovY = Fov / 2.0f;
HalfFovY = HalfFovY * 3.1415f / 180.0f;
float HalfFovX = (float)atan(tan(HalfFovY) * Aspect);
HalfFovX = HalfFovX * 180.0f / 3.1415f;
float Beta = HalfFovX;
// Get vectors from the position.
float NonOrthoTop[3] = { 0.0f, 0.0f, 1.0f };
float Target[3] = { (m_fDimensions[0] + m_fDimensions[3])*0.5f, (m_fDimensions[1] + m_fDimensions[4])*0.5f,
(m_fDimensions[2] + m_fDimensions[5])*0.5f };
float Front[3] = { Target[0] - Eye[0], Target[1] - Eye[1], Target[2] - Eye[2]};
float Side[3];
Side[0] = NonOrthoTop[1]*Front[2] - NonOrthoTop[2]*Front[1];
Side[1] = NonOrthoTop[2]*Front[0] - NonOrthoTop[0]*Front[2];
Side[2] = NonOrthoTop[0]*Front[1] - NonOrthoTop[1]*Front[0];
// Make sure the up vector is orthogonal.
float Top[3];
Top[0] = Front[1]*Side[2] - Front[2]*Side[1];
Top[1] = Front[2]*Side[0] - Front[0]*Side[2];
Top[2] = Front[0]*Side[1] - Front[1]*Side[0];
// Calculate the plane normals.
Matrix Mat;
float TopNormal[3] = { -Top[0], -Top[1], -Top[2] };
Mat.FromAxisAngle(Side, -Alpha);
Mat.TransformPoints(TopNormal, 1);
float BottomNormal[3] = { Top[0], Top[1], Top[2] };
Mat.FromAxisAngle(Side, Alpha);
Mat.TransformPoints(BottomNormal, 1);
float RightNormal[3] = { Side[0], Side[1], Side[2] };
Mat.FromAxisAngle(Top, -Beta);
Mat.TransformPoints(RightNormal, 1);
float LeftNormal[3] = { -Side[0], -Side[1], -Side[2] };
Mat.FromAxisAngle(Top, Beta);
Mat.TransformPoints(LeftNormal, 1);
// Calculate the plane offsets from the normals and the eye position.
float TopD = Eye[0]*-TopNormal[0] + Eye[1]*-TopNormal[1] + Eye[2]*-TopNormal[2];
float BottomD = Eye[0]*-BottomNormal[0] + Eye[1]*-BottomNormal[1] + Eye[2]*-BottomNormal[2];
float LeftD = Eye[0]*-LeftNormal[0] + Eye[1]*-LeftNormal[1] + Eye[2]*-LeftNormal[2];
float RightD = Eye[0]*-RightNormal[0] + Eye[1]*-RightNormal[1] + Eye[2]*-RightNormal[2];
// Now generate the planes
float Inv;
Inv = 1.0f/(float)sqrt(TopNormal[0]*TopNormal[0]+TopNormal[1]*TopNormal[1]+TopNormal[2]*TopNormal[2]);
float TopPlane[4] = { TopNormal[0]*Inv, TopNormal[1]*Inv, TopNormal[2]*Inv, TopD*Inv };
Inv = 1.0f/(float)sqrt(BottomNormal[0]*BottomNormal[0]+BottomNormal[1]*BottomNormal[1]+BottomNormal[2]*BottomNormal[2]);
float BottomPlane[4] = { BottomNormal[0]*Inv, BottomNormal[1]*Inv, BottomNormal[2]*Inv, BottomD*Inv };
Inv = 1.0f/(float)sqrt(LeftNormal[0]*LeftNormal[0]+LeftNormal[1]*LeftNormal[1]+LeftNormal[2]*LeftNormal[2]);
float LeftPlane[4] = { LeftNormal[0]*Inv, LeftNormal[1]*Inv, LeftNormal[2]*Inv, LeftD*Inv };
Inv = 1.0f/(float)sqrt(RightNormal[0]*RightNormal[0]+RightNormal[1]*RightNormal[1]+RightNormal[2]*RightNormal[2]);
float RightPlane[4] = { RightNormal[0]*Inv, RightNormal[1]*Inv, RightNormal[2]*Inv, RightD*Inv };
float Verts[8][3] = {
{ m_fDimensions[0], m_fDimensions[1], m_fDimensions[5] },
{ m_fDimensions[3], m_fDimensions[1], m_fDimensions[5] },
{ m_fDimensions[0], m_fDimensions[1], m_fDimensions[2] },
{ m_fDimensions[3], m_fDimensions[4], m_fDimensions[5] },
{ m_fDimensions[3], m_fDimensions[4], m_fDimensions[2] },
{ m_fDimensions[0], m_fDimensions[4], m_fDimensions[2] },
{ m_fDimensions[0], m_fDimensions[4], m_fDimensions[5] },
{ m_fDimensions[3], m_fDimensions[1], m_fDimensions[2] } };
float SmallestU = 10000.0f;
for (int i = 0; i < 4; i++)
{
float* Plane;
switch (i)
{
case 0: Plane = TopPlane; break;
case 1: Plane = BottomPlane; break;
case 2: Plane = LeftPlane; break;
case 3: Plane = RightPlane; break;
}
for (int j = 0; j < 8; j++)
{
Plane[3] = Verts[j][0]*-Plane[0] + Verts[j][1]*-Plane[1] + Verts[j][2]*-Plane[2];
// Intersect the eye line with the plane, NewEye = Eye + u * (Target - Eye)
float u = Eye[0] * Plane[0] + Eye[1] * Plane[1] + Eye[2] * Plane[2] + Plane[3];
u /= Front[0] * -Plane[0] + Front[1] * -Plane[1] + Front[2] * -Plane[2];
if (u < SmallestU)
SmallestU = u;
}
}
float NewEye[3];
NewEye[0] = Eye[0] + Front[0] * SmallestU;
NewEye[1] = Eye[1] + Front[1] * SmallestU;
NewEye[2] = Eye[2] + Front[2] * SmallestU;
if (EyePos)
{
EyePos[0] = NewEye[0];
EyePos[1] = NewEye[1];
EyePos[2] = NewEye[2];
}
2012-03-29 03:10:55 +02:00
lcVector3 FrontVec, RightVec, UpVec;
2011-09-07 23:06:51 +02:00
// Calculate view matrix.
2012-03-29 03:10:55 +02:00
UpVec = lcVector3(Top[0], Top[1], Top[2]);
2011-09-07 23:06:51 +02:00
UpVec.Normalize();
2012-03-29 03:10:55 +02:00
FrontVec = lcVector3(Front[0], Front[1], Front[2]);
2011-09-07 23:06:51 +02:00
FrontVec.Normalize();
2012-03-29 03:10:55 +02:00
RightVec = lcVector3(Side[0], Side[1], Side[2]);
2011-09-07 23:06:51 +02:00
RightVec.Normalize();
2012-03-29 03:10:55 +02:00
float ViewMat[16];
ViewMat[0] = -RightVec[0]; ViewMat[4] = -RightVec[1]; ViewMat[8] = -RightVec[2]; ViewMat[12] = 0.0;
ViewMat[1] = UpVec[0]; ViewMat[5] = UpVec[1]; ViewMat[9] = UpVec[2]; ViewMat[13] = 0.0;
ViewMat[2] = -FrontVec[0]; ViewMat[6] = -FrontVec[1]; ViewMat[10] = -FrontVec[2]; ViewMat[14] = 0.0;
ViewMat[3] = 0.0; ViewMat[7] = 0.0; ViewMat[11] = 0.0; ViewMat[15] = 1.0;
// Load ViewMatrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(ViewMat);
glTranslatef(-NewEye[0], -NewEye[1], -NewEye[2]);
2011-09-07 23:06:51 +02:00
}
// Used by the print catalog and HTML instructions functions.
void PieceInfo::RenderOnce(int nColor)
{
AddRef();
RenderPiece(nColor);
DeRef();
}
// Called by the piece preview and from RenderOnce()
void PieceInfo::RenderPiece(int nColor)
{
2012-04-14 01:41:58 +02:00
mMesh->Render(nColor, false, false);
2011-09-07 23:06:51 +02:00
}