#include "pch.h"
class XToken : public IObjectSingle {
public:
virtual bool EnterSection(ZString& strType, ZString& strName) = 0;
virtual bool LeaveSection() = 0;
virtual bool ReadFloat(float& value) = 0;
virtual bool ReadInt(int& value) = 0;
virtual bool ReadString(ZString& str) = 0;
virtual bool ReadReference(ZString& str) = 0;
virtual bool Error() = 0;
virtual void SetError(const ZString& str) = 0;
};
const WORD TOKEN_TEMPLATE = 31;
const WORD TOKEN_NAME = 1;
const WORD TOKEN_INTEGER_LIST = 6;
const WORD TOKEN_REALNUM_LIST = 7;
const WORD TOKEN_OBRACE = 10;
const WORD TOKEN_CBRACE = 11;
class XBinaryToken : public XToken {
private:
PCC m_p;
PCC m_pend;
int m_intCount;
int m_floatCount;
ZString m_strError;
bool MoreTokens()
{
return m_p < m_pend;
}
bool Is(WORD id)
{
if (*(WORD*)m_p == id) {
m_p += sizeof(WORD);
return true;
}
return false;
}
int GetInt()
{
int value = *((int*)m_p);
m_p += sizeof(int);
return value;
}
bool ReadString(ZString& str)
{
if (Is(TOKEN_NAME)) {
int length = GetInt();
str = ZString(m_p, length);
m_p += length;
return true;
}
return false;
}
public:
XBinaryToken(PCC p, int length) :
m_p(p),
m_pend(p + length),
m_intCount(0),
m_floatCount(0)
{
}
bool EnterSection(ZString& strType, ZString& strName)
{
while (Is(TOKEN_TEMPLATE)) {
while (!Is(TOKEN_CBRACE)) m_p += 2;
}
if (ReadString(strType)) {
ReadString(strName);
return Is(TOKEN_OBRACE);
}
return false;
}
bool LeaveSection()
{
int level = 1;
ZString str;
while (MoreTokens() && level > 0) {
while (ReadString(str));
if (Is(TOKEN_REALNUM_LIST)) {
m_p += sizeof(float) * GetInt();
} else if (Is(TOKEN_INTEGER_LIST)) {
m_p += sizeof(int) * GetInt();
} else if (Is(TOKEN_OBRACE)) {
level++;
} else if (Is(TOKEN_CBRACE)) {
level--;
} else {
m_p += 2;
}
}
return level == 0;
}
bool ReadFloat(float& value)
{
ZAssert(m_intCount == 0);
if (m_floatCount == 0) {
if (Is(TOKEN_REALNUM_LIST)) {
m_floatCount = GetInt();
} else {
return false;
}
}
m_floatCount--;
value = *((float*)m_p);
m_p += sizeof(float);
return true;
}
bool ReadInt(int& value)
{
ZAssert(m_floatCount == 0);
if (m_intCount == 0) {
if (Is(TOKEN_INTEGER_LIST)) {
m_intCount = GetInt();
} else {
return false;
}
}
m_intCount--;
value = *((int*)m_p);
m_p += sizeof(int);
return true;
}
bool ReadReference(ZString& str)
{
ZUnimplemented();
return false;
}
bool Error()
{
return !m_strError.IsEmpty();
}
void SetError(const ZString& str)
{
m_strError = str;
}
};
class XTextToken : public XToken, public TextTokenImpl {
private:
int Comma ;
int SemiColon ;
int LeftParen ;
int RightParen ;
int LeftBracket ;
int RightBracket;
int LeftBrace ;
int RightBrace ;
int Minus ;
int Dummy ;
public:
XTextToken(PCC pcc, int length) :
TextTokenImpl(pcc, length)
{
Comma = AddToken("','");
SemiColon = AddToken("';'");
LeftParen = AddToken("'('");
RightParen = AddToken("')'");
LeftBracket = AddToken("'['");
RightBracket = AddToken("']'");
LeftBrace = AddToken("'{'");
RightBrace = AddToken("'}'");
Minus = AddToken("'-'");
Dummy = AddToken("dummy");
Next();
}
int ParseToken(PCC& pcc)
{
switch (pcc[0]) {
case '[': pcc++; return LeftBracket;
case ']': pcc++; return RightBracket;
case '{': pcc++; return LeftBrace;
case '}': pcc++; return RightBrace;
case '(': pcc++; return LeftParen;
case ')': pcc++; return RightParen;
case ',': pcc++; return Comma;
case ';': pcc++; return SemiColon;
case '-': pcc++; return Minus;
case '<':
case '>': pcc++; return Dummy;
}
return 0;
}
bool IsSymbolChar(char ch)
{
return TextTokenImpl::IsSymbolChar(ch) || ch == '-' || ch == '.';
}
bool Error()
{
return TextTokenImpl::Error();
}
void SetError(const ZString& str)
{
TextTokenImpl::SetError(str);
}
bool EnterSection(ZString& strType, ZString& strName)
{
if (IsSymbol(strType, false)) {
IsSymbol(strName, false);
return Is(LeftBrace, true);
}
return false;
}
bool LeaveSection()
{
int level = 1;
while (MoreTokens() && level > 0) {
if (Is(LeftBrace, false)) {
level++;
} else if (Is(RightBrace, false)) {
level--;
} else {
Next();
}
}
return level == 0;
}
bool ReadFloat(float& value)
{
bool fMinus = Is(Minus, false);
if (IsNumber(value, true)) {
while (Is(Comma, false) || Is(SemiColon, false));
if (fMinus) {
value = -value;
}
return true;
}
return false;
}
bool ReadInt(int& i)
{
float value;
if (ReadFloat(value)) {
i = (int)value;
return true;
}
return false;
}
bool ReadString(ZString& str)
{
return IsString(str, true);
}
bool ReadReference(ZString& str)
{
if (Is(TOKEN_OBRACE, true)) {
if (IsSymbol(str, true)) {
if (Is(TOKEN_CBRACE, true)) {
return true;
}
}
}
return false;
}
};
class XParser {
TRef<Modeler> m_pmodeler;
TRef<XToken> m_ptoken;
TMap<ZString, TRef<TransformGeo> > m_namedFrames;
int m_countMesh;
int m_countFrame;
public:
XParser(
Modeler* pmodeler,
PCC pcc,
int length
) :
m_pmodeler(pmodeler),
m_countMesh(0),
m_countFrame(0)
{
if (pcc[8] == 't') {
m_ptoken = new XTextToken(pcc + 17, length - 17);
} else if (pcc[8] == 'b') {
m_ptoken = new XBinaryToken(pcc + 16, length - 16);
}
}
~XParser()
{
}
bool ReadTransform(TRef<Transform>& ptrans)
{
ZString strType;
ZString strName;
if (m_ptoken->EnterSection(strType, strName)) {
float m00, m01, m02, m03;
float m10, m11, m12, m13;
float m20, m21, m22, m23;
float m30, m31, m32, m33;
if (
m_ptoken->ReadFloat(m00)
&& m_ptoken->ReadFloat(m10)
&& m_ptoken->ReadFloat(m20)
&& m_ptoken->ReadFloat(m30)
&& m_ptoken->ReadFloat(m01)
&& m_ptoken->ReadFloat(m11)
&& m_ptoken->ReadFloat(m21)
&& m_ptoken->ReadFloat(m31)
&& m_ptoken->ReadFloat(m02)
&& m_ptoken->ReadFloat(m12)
&& m_ptoken->ReadFloat(m22)
&& m_ptoken->ReadFloat(m32)
&& m_ptoken->ReadFloat(m03)
&& m_ptoken->ReadFloat(m13)
&& m_ptoken->ReadFloat(m23)
&& m_ptoken->ReadFloat(m33)
) {
Matrix
mat(
m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m32, m33
);
ptrans = new Transform(mat);
m_ptoken->LeaveSection();
return true;
}
}
return false;
}
bool ReadMesh(const ZString strMeshName, TRef<Geo>& pgeo)
{
m_countMesh++;
int vcount;
if (!m_ptoken->ReadInt(vcount)) {
return false;
}
TVector<Vertex> ppositions(vcount, vcount);
int index;
for(index = 0; index < vcount; index++) {
Vertex& vertex = ppositions.Get(index);
float z;
if (
!m_ptoken->ReadFloat(vertex.x)
|| !m_ptoken->ReadFloat(vertex.y)
|| !m_ptoken->ReadFloat(z)
) {
return false;
}
vertex.z = -z;
vertex.u = 0;
vertex.v = 0;
}
int countFace;
if (!m_ptoken->ReadInt(countFace)) {
return false;
}
TVector<WORD> pvi;
TVector<int> pfaceVCounts(countFace, countFace);
for(index = 0; index < countFace; index++) {
int firstIndex ;
int secondIndex;
if (
!m_ptoken->ReadInt(pfaceVCounts.Get(index))
|| !m_ptoken->ReadInt(firstIndex )
|| !m_ptoken->ReadInt(secondIndex)
) {
return false;
}
for (int faceVIndex = 0; faceVIndex < pfaceVCounts[index] - 2; faceVIndex++) {
int thirdIndex;
if (!m_ptoken->ReadInt(thirdIndex)) {
return false;
}
pvi.PushEnd(firstIndex);
pvi.PushEnd(secondIndex);
pvi.PushEnd(thirdIndex);
secondIndex = thirdIndex;
}
}
int mcount = 0;
int matCountFace = 0;
TVector<TRef<Material> > pmaterials;
TVector<TRef<Image> > pimageTextures;
TVector<WORD> pmi;
int ncount = 0;
TVector<Vector> pnormals;
TVector<WORD> pni;
ZString strType;
ZString strName;
while (m_ptoken->EnterSection(strType, strName)) {
if (strType == "MeshMaterialList") {
if (
!m_ptoken->ReadInt(mcount)
|| !m_ptoken->ReadInt(matCountFace)
) {
return false;
}
ZAssert(matCountFace == 1 || countFace == matCountFace);
for(index = 0; index < matCountFace; index++) {
int mi;
if (!m_ptoken->ReadInt(mi)) {
return false;
}
pmi.PushEnd(mi);
}
for (index = 0; index < mcount; index++) {
ZVerify(m_ptoken->EnterSection(strType, strName));
ZAssert(strType == "Material");
float rd, gd, bd, ad;
float power;
float rs, gs, bs;
float re, ge, be;
if (
!m_ptoken->ReadFloat(rd)
|| !m_ptoken->ReadFloat(gd)
|| !m_ptoken->ReadFloat(bd)
|| !m_ptoken->ReadFloat(ad)
|| !m_ptoken->ReadFloat(power)
|| !m_ptoken->ReadFloat(rs)
|| !m_ptoken->ReadFloat(gs)
|| !m_ptoken->ReadFloat(bs)
|| !m_ptoken->ReadFloat(re)
|| !m_ptoken->ReadFloat(ge)
|| !m_ptoken->ReadFloat(be)
) {
return false;
}
Color colorDiffuse(rd, gd, bd, ad);
Color colorSpecular(rs, gs, bs);
Color colorEmissive(re, ge, be);
TRef<Image> pimageTexture;
if (m_ptoken->EnterSection(strType, strName)) {
ZAssert(strType == "TextureFilename");
PathString strFilename;
if (!m_ptoken->ReadString(strFilename)) {
return false;
}
ZAssert(
strFilename.GetExtension() == "ppm"
|| strFilename.GetExtension() == "bmp"
);
strFilename = strFilename.LeftOf(4).ToLower() + "bmp";
pimageTexture = m_pmodeler->LoadImage(strFilename, false);
m_ptoken->LeaveSection();
} else if (m_ptoken->Error()) {
return false;
}
pmaterials.PushEnd(
CreateMaterial(
colorDiffuse,
colorSpecular,
colorEmissive,
power
)
);
pimageTextures.PushEnd(pimageTexture);
m_ptoken->LeaveSection();
}
} else if (strType == "MeshVertexColors" ) {
} else if (strType == "MeshFaceWraps" ) {
} else if (strType == "MeshTextureCoords") {
int vcountTextureCoords;
if (!m_ptoken->ReadInt(vcountTextureCoords)) {
return false;
}
ZAssert(vcount == vcountTextureCoords);
for(index = 0; index < vcount; index++) {
Vertex& vertex = ppositions.Get(index);
if (
!m_ptoken->ReadFloat(vertex.u)
|| !m_ptoken->ReadFloat(vertex.v)
) {
return false;
}
}
} else if (strType == "MeshNormals") {
if (!m_ptoken->ReadInt(ncount)) {
return false;
}
pnormals.SetCount(ncount);
for(index = 0; index < ncount; index++) {
float x, y, z;
if (
!m_ptoken->ReadFloat(x)
|| !m_ptoken->ReadFloat(y)
|| !m_ptoken->ReadFloat(z)
) {
return false;
}
pnormals.Get(index) = Vector(x, y, -z);
}
int countFaceNormals;
if (!m_ptoken->ReadInt(countFaceNormals)) {
return false;
}
ZAssert(countFace == countFaceNormals);
for(index = 0; index < countFace; index++) {
int faceVCount ;
int firstIndex ;
int secondIndex;
if (
!m_ptoken->ReadInt(faceVCount )
|| !m_ptoken->ReadInt(firstIndex )
|| !m_ptoken->ReadInt(secondIndex)
) {
return false;
}
for (int faceVIndex = 0; faceVIndex < faceVCount - 2; faceVIndex++) {
int thirdIndex;
if (!m_ptoken->ReadInt(thirdIndex)) {
return false;
}
pni.PushEnd(firstIndex);
pni.PushEnd(secondIndex);
pni.PushEnd(thirdIndex);
secondIndex = thirdIndex;
}
}
}
m_ptoken->LeaveSection();
}
if (m_ptoken->Error()) {
return false;
}
TVector<Vertex> vertices;
TVector<WORD> indices;
if (ncount > 0) {
TVector<TList<WORD> > vertexTree(vcount, vcount);
int count = pvi.GetCount();
for (index = 0; index < count; index++) {
int iVertex = pvi[index];
int iNormal = pni[index];
TList<WORD>::Iterator iter(vertexTree.Get(iVertex));
do {
if (iter.End()) {
Vertex vertex;
vertex.x = ppositions[iVertex].x;
vertex.y = ppositions[iVertex].y;
vertex.z = ppositions[iVertex].z;
vertex.u = ppositions[iVertex].u;
vertex.v = ppositions[iVertex].v;
vertex.nx = pnormals[iNormal].X();
vertex.ny = pnormals[iNormal].Y();
vertex.nz = pnormals[iNormal].Z();
vertices.PushEnd(vertex);
indices.PushEnd(vertices.GetCount() - 1);
vertexTree.Get(iVertex).PushFront(vertices.GetCount() - 1);
break;
}
Vertex& vertex = vertices.Get(iter.Value());
if (
vertex.nx == pnormals[iNormal].X()
&& vertex.ny == pnormals[iNormal].Y()
&& vertex.nz == pnormals[iNormal].Z()
) {
indices.PushEnd(iter.Value());
break;
}
iter.Next();
} while (true);
}
} else {
vertices = ppositions;
indices = pvi;
}
if (mcount == 0) {
pgeo = Geo::CreateMesh(vertices, indices);
return true;
} else if (matCountFace == 1 || mcount == 1) {
if (pimageTextures[0]) {
pgeo =
new TextureGeo(
new MaterialGeo(
Geo::CreateMesh(vertices, indices),
pmaterials[0]
),
pimageTextures[0]
);
return true;
} else {
pgeo =
new MaterialGeo(
Geo::CreateMesh(vertices, indices),
pmaterials[0]
);
return true;
}
}
TRef<GroupGeo> pgroup = GroupGeo::Create();
TVector<Vertex> componentVertices;
TVector<WORD> componentIndices;
TVector<WORD> map(vertices.GetCount(), vertices.GetCount());
for (int indexMaterial = 0; indexMaterial < mcount; indexMaterial++) {
for (index = 0; index < map.GetCount(); index++) {
map.Set(index, 0xffff);
}
componentVertices.SetCount(0);
componentIndices.SetCount(0);
int indexStart = 0;
for (int indexFace = 0; indexFace < countFace; indexFace++) {
int indexEnd = indexStart + (pfaceVCounts[indexFace] - 2) * 3;
if (pmi[indexFace] == indexMaterial) {
for (
index = indexStart;
index < indexEnd;
index++
) {
int indexVertex = indices[index];
if (map[indexVertex] == 0xffff) {
map.Set(indexVertex, componentVertices.GetCount());
componentVertices.PushEnd(vertices[indexVertex]);
}
componentIndices.PushEnd(map[indexVertex]);
}
}
indexStart = indexEnd;
}
if (pimageTextures[indexMaterial]) {
pgroup->AddGeo(
new TextureGeo(
new MaterialGeo(
Geo::CreateMesh(componentVertices, componentIndices),
pmaterials[indexMaterial]
),
pimageTextures[indexMaterial]
)
);
} else {
pgroup->AddGeo(
new MaterialGeo(
Geo::CreateMesh(componentVertices, componentIndices),
pmaterials[indexMaterial]
)
);
}
}
pgeo = pgroup;
return true;
}
bool ReadFrame(const ZString& strFrameName, TRef<Geo>& pgeo)
{
m_countFrame++;
TRef<GroupGeo> pgeoGroup = GroupGeo::Create();
pgeoGroup->SetName(strFrameName);
TRef<Transform> ptrans;
if (!ReadTransform(ptrans)) {
if (m_ptoken->Error()) {
return false;
}
ptrans = new Transform();
}
TRef<TransformGeo> ptransformGeo = new TransformGeo(pgeoGroup, ptrans);
pgeo = ptransformGeo;
m_namedFrames.Set(strFrameName, ptransformGeo);
ZString strType;
ZString strName;
while (m_ptoken->EnterSection(strType, strName)) {
TRef<Geo> pgeoChild;
if (strType == "Frame") {
if (!ReadFrame(strName, pgeoChild)) {
return false;
}
} else if (strType == "Mesh") {
if (!ReadMesh(strName, pgeoChild)) {
return false;
}
} else {
m_ptoken->SetError("Unknown Section Type");
return false;
}
pgeoGroup->AddGeo(pgeoChild);
m_ptoken->LeaveSection();
}
return !m_ptoken->Error();
}
bool ReadAnimationKey(
Number* pnumberFrame,
TRef<Transform>& ptransformTranslate,
TRef<Transform>& ptransformScale,
TRef<Transform>& ptransformRotate
) {
int type ;
int count;
if (
!m_ptoken->ReadInt(type )
|| !m_ptoken->ReadInt(count)
) {
return false;
}
switch (type) {
case 0:
{
TRef<KeyFramedRotateTransform> ptrans = CreateKeyFramedRotateTransform(pnumberFrame);
ptransformRotate = ptrans;
for (int index = 0; index < count; index++) {
int time;
int count;
float s;
float x;
float y;
float z;
if (
!m_ptoken->ReadInt(time)
|| !m_ptoken->ReadInt(count)
|| !m_ptoken->ReadFloat(s)
|| !m_ptoken->ReadFloat(x)
|| !m_ptoken->ReadFloat(y)
|| !m_ptoken->ReadFloat(z)
) {
return false;
}
ZAssert(count == 4);
ptrans->AddKey((float)time, Quaternion(s, x, y, -z));
}
}
break;
case 1:
{
TRef<KeyFramedScaleTransform> ptrans = CreateKeyFramedScaleTransform(pnumberFrame);
ptransformScale = ptrans;
for (int index = 0; index < count; index++) {
int time;
int count;
float x;
float y;
float z;
if (
!m_ptoken->ReadInt(time)
|| !m_ptoken->ReadInt(count)
|| !m_ptoken->ReadFloat(x)
|| !m_ptoken->ReadFloat(y)
|| !m_ptoken->ReadFloat(z)
) {
return false;
}
ZAssert(count == 3);
ptrans->AddKey((float)time, Vector(x, y, z));
}
}
break;
case 2:
{
TRef<KeyFramedTranslateTransform> ptrans = CreateKeyFramedTranslateTransform(pnumberFrame);
ptransformTranslate = ptrans;
for (int index = 0; index < count; index++) {
int time;
int count;
float x;
float y;
float z;
if (
!m_ptoken->ReadInt(time)
|| !m_ptoken->ReadInt(count)
|| !m_ptoken->ReadFloat(x)
|| !m_ptoken->ReadFloat(y)
|| !m_ptoken->ReadFloat(z)
) {
return false;
}
ZAssert(count == 3);
ptrans->AddKey((float)time, Vector(x, y, -z));
}
}
break;
default:
m_ptoken->SetError("Invalid key type");
return false;
}
return true;
}
bool ReadAnimation(Number* pnumberFrame)
{
ZString strFrameName;
if (m_ptoken->ReadReference(strFrameName)) {
TRef<Transform> ptransformTranslate;
TRef<Transform> ptransformRotate;
TRef<Transform> ptransformScale;
ZString strType;
ZString strName;
while (m_ptoken->EnterSection(strType, strName)) {
if (strType == "AnimationKey") {
if (!ReadAnimationKey(pnumberFrame, ptransformTranslate, ptransformScale, ptransformRotate)) {
return false;
}
} else if (strType == "AnimationOptions") {
ZError("Not Implemented");
}
m_ptoken->LeaveSection();
}
if (!m_ptoken->Error()) {
if (ptransformRotate || ptransformScale || ptransformTranslate) {
TRef<TransformGeo> ptransformGeo;
ZVerify(m_namedFrames.Find(strFrameName, ptransformGeo));
TRef<Geo> pgeo = ptransformGeo->GetGeo();
if (ptransformRotate) {
pgeo = new TransformGeo(pgeo, ptransformRotate);
}
if (ptransformScale) {
pgeo = new TransformGeo(pgeo, ptransformScale);
}
if (ptransformTranslate) {
pgeo = new TransformGeo(pgeo, ptransformTranslate);
}
ptransformGeo->ChangeTo(pgeo);
}
return true;
}
}
return false;
}
bool ReadAnimationSet(Number* pnumberFrame)
{
ZString strType;
ZString strName;
while (m_ptoken->EnterSection(strType, strName)) {
if (strType == "Animation") {
if (!ReadAnimation(pnumberFrame)) {
return false;
}
}
m_ptoken->LeaveSection();
}
return !m_ptoken->Error();
}
TRef<Geo> ReadFile(Number* pnumberFrame, bool& bAnimation)
{
TRef<GroupGeo> pgroup = GroupGeo::Create();
ZString strType;
ZString strName;
while (m_ptoken->EnterSection(strType, strName)) {
TRef<Geo> pgeoChild;
if (strType == "Frame") {
if (!ReadFrame(strName, pgeoChild)) {
return false;
}
} else if (strType == "Mesh") {
if (!ReadMesh(strName, pgeoChild)) {
return false;
}
} else if (strType == "AnimationSet") {
ZAssert(!bAnimation);
bAnimation = true;
if (!ReadAnimationSet(pnumberFrame)) {
return false;
}
}
if (pgeoChild) {
pgroup->AddGeo(pgeoChild);
}
m_ptoken->LeaveSection();
}
if (m_ptoken->Error()) {
return NULL;
} else {
return pgroup;
}
}
};
TRef<Geo> ImportXFile(Modeler* pmodeler, ZFile* pfile, Number* pnumberFrame, bool& bAnimation)
{
XParser parser(pmodeler, (PCC)pfile->GetPointer(), pfile->GetLength());
bAnimation = false;
return parser.ReadFile(pnumberFrame, bAnimation);
}