#include "pch.h"
class EmptyGeo : public Geo {
public:
EmptyGeo() : Geo()
{
}
ZString GetString(int indent) { return "emptyGeo"; }
ZString GetFunctionName()
{
return "emptyGeo";
}
void Write(IMDLBinaryFile* pfile)
{
pfile->WriteReference("emptyGeo");
}
};
static TRef<Geo> g_pemptyGeo = new EmptyGeo();
Geo* Geo::GetEmpty()
{
return g_pemptyGeo;
}
void Geo::SetEmpty()
{
ChangeTo(GetEmpty());
}
void Geo::Render(Context* pcontext)
{
}
bool Geo::AnyChildGroups(bool bHead)
{
return false;
}
TRef<Geo> Geo::RemoveMaterial()
{
return NULL;
}
TRef<Geo> Geo::FoldTexture()
{
return NULL;
}
MeshGeo* Geo::GetMeshGeo()
{
return NULL;
}
GroupGeo* Geo::GetGroupGeo()
{
return NULL;
}
TextureGeo* Geo::GetTextureGeo()
{
return NULL;
}
Image* Geo::FindTexture()
{
return NULL;
}
void Geo::CallGroupGeoCallback(const Matrix& mat, GroupGeoCallback* pcallback)
{
}
float Geo::GetRadius(const Matrix& mat)
{
return 0;
}
void Geo::RemoveCapture()
{
}
bool Geo::HitTest(const Vector& vecOrigin, const Vector& vecRay, HitData3D& hitData, bool bCaptured)
{
return false;
}
void Geo::MouseMove(const Vector& vec, bool bCaptured, bool bInside)
{
}
void Geo::MouseEnter(const Vector& vec)
{
}
void Geo::MouseLeave()
{
}
MouseResult Geo::Button(const Vector& vec, int button, bool bCaptured, bool bInside, bool bDown)
{
return MouseResult();
}
TRef<Geo> Geo::ApplyTransform(Transform* ptrans)
{
return NULL;
}
int Geo::GetTriangleCount()
{
return 0;
}
ZString GetString(const Vertex& v)
{
return
ZString(v.x) + ", "
+ ZString(v.y) + ", "
+ ZString(v.z) + ", "
+ ZString(v.nx) + ", "
+ ZString(v.ny) + ", "
+ ZString(v.nz) + ", "
+ ZString(v.u) + ", "
+ ZString(v.v);
}
ZString GetString(const VertexL& v)
{
return
ZString(v.x) + ", "
+ ZString(v.y) + ", "
+ ZString(v.z) + ", "
+ ZString(v.u) + ", "
+ ZString(v.v);
}
class MeshGeo : public Geo {
public:
virtual TRef<MeshGeo> Combine(MeshGeo* pmesh) = 0;
};
template<class VertexType>
class TMeshGeo : public MeshGeo {
TRef<IObject> m_pobjectMemory;
TVector<VertexType> m_vertices;
TVector<MeshIndex> m_indices;
public:
TMeshGeo(VertexType* pvertices, int vcount, MeshIndex* pindices, int icount, IObject* pobjectMemory = NULL) :
m_pobjectMemory(pobjectMemory),
m_vertices(vcount, pvertices, pobjectMemory != NULL),
m_indices(icount, pindices, pobjectMemory != NULL)
{
}
TMeshGeo(const TVector<VertexType>& vertices, const TVector<MeshIndex>& indices) :
m_vertices(vertices),
m_indices(indices)
{
}
void Render(Context* pcontext)
{
pcontext->DrawTriangles(m_vertices, m_indices);
}
void CallGroupGeoCallback(const Matrix& mat, GroupGeoCallback* pcallback)
{
pcallback->ReportTriangles(mat, m_vertices, m_indices);
}
MeshGeo* GetMeshGeo()
{
return this;
}
TRef<MeshGeo> Combine(MeshGeo* pmeshArg)
{
TMeshGeo* pmesh; CastTo(pmesh, pmeshArg);
TVector<VertexType> vertices(pmesh->m_vertices);
TVector<MeshIndex> indices(pmesh->m_indices);
int countSource = m_vertices.GetCount();
int indexSource;
TVector<MeshIndex> indexMap(countSource, countSource);
for(indexSource = 0; indexSource < countSource; indexSource++) {
int count = vertices.GetCount();
int index = 0;
while (true) {
if (m_vertices[indexSource] == vertices[index]) {
indexMap.Set(indexSource, index);
break;
}
index++;
if (index == count) {
indexMap.Set(indexSource, count);
vertices.PushEnd(m_vertices[indexSource]);
break;
}
}
}
countSource = m_indices.GetCount();
for(indexSource = 0; indexSource < countSource; indexSource++) {
indices.PushEnd(indexMap[m_indices[indexSource]]);
}
return new TMeshGeo(vertices, indices);
}
TRef<Geo> ApplyTransform(Transform* ptrans)
{
Matrix mat = ptrans->GetValue();
Matrix matNormal;
matNormal.SetInverse(mat);
matNormal.Transpose();
TVector<VertexType> vertices(m_vertices);
int count = m_vertices.GetCount();
for(int index = 0; index < count; index++) {
vertices.Get(index).SetPosition(
mat.Transform(
m_vertices[index].GetPosition()
)
);
vertices.Get(index).SetNormal(
matNormal.Transform(
m_vertices[index].GetNormal()
)
);
}
return new TMeshGeo(vertices, m_indices);
}
int GetTriangleCount()
{
return m_indices.GetCount() / 3;
}
float GetRadius(const Matrix& mat)
{
float radius = 0;
int count = m_vertices.GetCount();
for(int index = 0; index < count; index++) {
Vector vec = mat.Transform(m_vertices[index].GetPosition());
radius = max(radius, vec.Length());
}
return radius;
}
ZString GetString(int indent)
{
ZString str = "MeshGeo([\n";
int count = m_vertices.GetCount();
for(int index = 0; index < count; index++) {
str += Indent(indent + 1) + ::GetString(m_vertices[index]);
if (index + 1 == count) {
str += "\n";
} else {
str += ",\n";
}
}
str += Indent(indent) + "], [\n";
count = m_indices.GetCount();
for(int index = 0; index < count; index += 3) {
str +=
Indent(indent + 1)
+ ZString((int)m_indices[index]) + ", "
+ ZString((int)m_indices[index + 1]) + ", "
+ ZString((int)m_indices[index + 2]);
if (index + 3 == count) {
str += "\n";
} else {
str += ",\n";
}
}
return str + Indent(indent) + "])";
}
bool IsConstant()
{
return true;
}
ZString GetFunctionName() { return "MeshGeo"; }
void Write(IMDLBinaryFile* pmdlFile)
{
pmdlFile->WriteReference("MeshGeo");
TRef<ZFile> pfile = pmdlFile->WriteBinary();
pfile->Write(m_vertices.GetCount());
pfile->Write(m_indices.GetCount());
pfile->Write((void*)&(m_vertices[0]), sizeof(VertexType) * m_vertices.GetCount());
pfile->Write((void*)&(m_indices[0]), sizeof(MeshIndex) * m_indices.GetCount());
}
};
TRef<Geo> Geo::CreateMesh(
Vertex* pvertices,
int vcount,
MeshIndex* pindices,
int icount,
IObject* pobjectMemory
)
{
return new TMeshGeo<Vertex>(pvertices, vcount, pindices, icount, pobjectMemory);
}
TRef<Geo> Geo::CreateMesh(
D3DVertex* pvertices,
int vcount,
MeshIndex* pindices,
int icount,
IObject* pobjectMemory
)
{
return new TMeshGeo<D3DVertex>(pvertices, vcount, pindices, icount, pobjectMemory);
}
TRef<Geo> Geo::CreateMesh(const TVector<Vertex>& vertices, const TVector<MeshIndex>& indices)
{
return new TMeshGeo<Vertex>(vertices, indices);
}
TRef<Geo> Geo::CreateMesh(const TVector<VertexL>& vertices, const TVector<MeshIndex>& indices)
{
return new TMeshGeo<VertexL>(vertices, indices);
}
TRef<Geo> Geo::CreateMesh(const TVector<D3DVertex>& vertices, const TVector<MeshIndex>& indices)
{
return new TMeshGeo<D3DVertex>(vertices, indices);
}
template<class VertexType>
TRef<Geo> CreateStaticMesh(VertexType* pvertices, int vcount, MeshIndex* pindices, int icount)
{
return new TMeshGeo<VertexType>(pvertices, vcount, pindices, icount);
}
TRef<Geo> g_pmeshSquare;
TRef<Geo> g_pmeshIcosahedron;
TRef<Geo> g_pmeshWhiteEmissiveSquare;
Geo* Geo::GetWhiteEmissiveSquare()
{
if (g_pmeshWhiteEmissiveSquare == NULL) {
static VertexL vertices[4] =
{
VertexL(-1, 1, 0, 1, 1, 1, 1, 0, 0),
VertexL(-1, -1, 0, 1, 1, 1, 1, 0, 1),
VertexL( 1, -1, 0, 1, 1, 1, 1, 1, 1),
VertexL( 1, 1, 0, 1, 1, 1, 1, 1, 0)
};
static MeshIndex indices[12] = {
0, 2, 1, 0, 3, 2,
0, 1, 2, 0, 2, 3
};
g_pmeshWhiteEmissiveSquare = CreateStaticMesh(vertices, 4, indices, 12);
}
return g_pmeshWhiteEmissiveSquare;
}
Geo* Geo::GetSquare()
{
if (g_pmeshSquare == NULL) {
static Vertex vertices[4] =
{
Vertex(-1, 1, 0, 0, 0, 1, 0, 0),
Vertex(-1, -1, 0, 0, 0, 1, 0, 1),
Vertex( 1, -1, 0, 0, 0, 1, 1, 1),
Vertex( 1, 1, 0, 0, 0, 1, 1, 0)
};
static MeshIndex indices[12] = {
0, 2, 1, 0, 3, 2,
0, 1, 2, 0, 2, 3
};
g_pmeshSquare = CreateStaticMesh(vertices, 4, indices, 12);
}
return g_pmeshSquare;
}
Geo* Geo::GetIcosahedron()
{
if (g_pmeshIcosahedron == NULL) {
const float x = 0.5256f;
const float z = 0.8506f;
Vertex pvertices[] =
{
Vertex( -x, 0.0f, z, -x, 0.0f, z),
Vertex( x, 0.0f, z, x, 0.0f, z),
Vertex( -x, 0.0f, -z, -x, 0.0f, -z),
Vertex( x, 0.0f, -z, x, 0.0f, -z),
Vertex(0.0f, z, x, 0.0f, z, x),
Vertex(0.0f, z, -x, 0.0f, z, -x),
Vertex(0.0f, -z, x, 0.0f, -z, x),
Vertex(0.0f, -z, -x, 0.0f, -z, -x),
Vertex( z, x, 0.0f, z, x, 0.0f),
Vertex( -z, x, 0.0f, -z, x, 0.0f),
Vertex( z, -x, 0.0f, z, -x, 0.0f),
Vertex( -z, -x, 0.0f, -z, -x, 0.0f)
};
MeshIndex pindices[] = {
0, 4, 1,
0, 9, 4,
9, 5, 4,
4, 5, 8,
4, 8, 1,
8, 10, 1,
8, 3, 10,
5, 3, 8,
5, 2, 3,
2, 7, 3,
7, 10, 3,
7, 6, 10,
7, 11, 6,
11, 0, 6,
0, 1, 6,
6, 1, 10,
9, 0, 11,
9, 11, 2,
9, 2, 5,
7, 2, 11
};
g_pmeshIcosahedron =
CreateStaticMesh(
pvertices,
ArrayCount(pvertices),
pindices,
ArrayCount(pindices)
);
}
return g_pmeshIcosahedron;
}
WrapGeo::WrapGeo(Geo* pgeo) :
Geo(pgeo)
{
}
WrapGeo::WrapGeo(Geo* pgeo, Value* pvalue1) :
Geo(pgeo, pvalue1)
{
}
TRef<WrapGeo> WrapGeo::Duplicate(Geo* pgeo)
{
return new WrapGeo(pgeo);
}
TRef<Geo> WrapGeo::ApplyTransform(Transform* ptrans)
{
TRef<Geo> pgeo = GetGeo()->ApplyTransform(ptrans);
if (pgeo) {
return Duplicate(pgeo);
}
return NULL;
}
bool WrapGeo::AnyChildGroups(bool bHead)
{
return GetGeo()->AnyChildGroups(false);
}
TRef<Geo> WrapGeo::RemoveMaterial()
{
TRef<Geo> pgeo = GetGeo()->RemoveMaterial();
if (pgeo) {
SetGeo(pgeo);
return this;
}
return NULL;
}
TRef<Geo> WrapGeo::FoldTexture()
{
bool bAnyFold = false;
TRef<Geo> pgeo = GetGeo();
TRef<Geo> pgeoFold = pgeo->FoldTexture();
if (pgeoFold) {
bAnyFold = true;
SetGeo(pgeoFold);
} else {
pgeoFold = pgeo;
}
TRef<TextureGeo> ptextureGeo = pgeoFold->GetTextureGeo();
if (ptextureGeo) {
return
new TextureGeo(
Duplicate(ptextureGeo->GetGeo()),
ptextureGeo->GetTexture(),
false
);
}
if (bAnyFold) {
return this;
} else {
return NULL;
}
}
TRef<Value> WrapGeo::Fold()
{
if (GetGeo() == Geo::GetEmpty()) {
return Geo::GetEmpty();
}
return NULL;
}
void WrapGeo::Render(Context* pcontext)
{
GetGeo()->Render(pcontext);
}
Image* WrapGeo::FindTexture()
{
return GetGeo()->FindTexture();
}
void WrapGeo::CallGroupGeoCallback(const Matrix& mat, GroupGeoCallback* pcallback)
{
GetGeo()->CallGroupGeoCallback(mat, pcallback);
}
float WrapGeo::GetRadius(const Matrix& mat)
{
return GetGeo()->GetRadius(mat);
}
int WrapGeo::GetTriangleCount()
{
return GetGeo()->GetTriangleCount();
}
void WrapGeo::RemoveCapture()
{
GetGeo()->RemoveCapture();
}
bool WrapGeo::HitTest(const Vector& vecOrigin, const Vector& vecRay, HitData3D& hitData, bool bCaptured)
{
return GetGeo()->HitTest(vecOrigin, vecRay, hitData, bCaptured);
}
void WrapGeo::MouseMove(const Vector& vec, bool bCaptured, bool bInside)
{
GetGeo()->MouseMove(vec, bCaptured, bInside);
}
void WrapGeo::MouseEnter(const Vector& vec)
{
GetGeo()->MouseEnter(vec);
}
void WrapGeo::MouseLeave()
{
GetGeo()->MouseLeave();
}
MouseResult WrapGeo::Button(const Vector& vec, int button, bool bCaptured, bool bInside, bool bDown)
{
return GetGeo()->Button(vec, button, bCaptured, bInside, bDown);
}
DecalGeo::DecalGeo(
Image* pimage,
const Color& color,
const Vector& vecPosition,
const Vector& vecForward,
const Vector& vecRight,
float scale,
float angle
) :
Geo(pimage),
m_color(color),
m_vecPosition(vecPosition),
m_vecForward(vecForward),
m_vecRight(vecRight),
m_scale(scale),
m_angle(0)
{
}
void DecalGeo::Render(Context* pcontext)
{
TRef<Surface> psurface = GetImage()->GetSurface();
pcontext->DrawDecal(
psurface,
m_color,
m_vecPosition,
m_vecForward,
m_vecRight,
m_scale,
m_angle
);
}
VisibleGeo::VisibleGeo(Geo* pgeo) :
WrapGeo(pgeo),
m_bVisible(true)
{
}
TRef<WrapGeo> VisibleGeo::Duplicate(Geo* pgeo)
{
return new VisibleGeo(pgeo);
}
void VisibleGeo::Render(Context* pcontext)
{
if (m_bVisible) {
GetGeo()->Render(pcontext);
}
}
void VisibleGeo::SetVisible(bool bVisible)
{
m_bVisible = bVisible;
}
ClipGeo::ClipGeo(Geo* pgeo) :
WrapGeo(pgeo),
m_bClip(true)
{
}
TRef<WrapGeo> ClipGeo::Duplicate(Geo* pgeo)
{
return new ClipGeo(pgeo);
}
void ClipGeo::Render(Context* pcontext)
{
bool bClipSave = pcontext->GetClipping();
pcontext->SetClipping(m_bClip);
GetGeo()->Render(pcontext);
pcontext->SetClipping(bClipSave);
}
void ClipGeo::SetClip(bool bClip)
{
m_bClip = bClip;
}
ClipPlaneGeo::ClipPlaneGeo(Geo* pgeo, const Plane& plane) :
WrapGeo(pgeo),
m_plane(plane)
{
}
TRef<WrapGeo> ClipPlaneGeo::Duplicate(Geo* pgeo)
{
return new ClipPlaneGeo(pgeo, m_plane);
}
void ClipPlaneGeo::Render(Context* pcontext)
{
pcontext->SetCullMode(CullModeNone);
pcontext->AddClipPlane(m_plane);
GetGeo()->Render(pcontext);
}
void ClipPlaneGeo::SetClipPlane(const Plane& plane)
{
m_plane = plane;
}
TransformGeo::TransformGeo(Geo* pgeo, Transform* ptrans) :
WrapGeo(pgeo, ptrans)
{
}
TRef<WrapGeo> TransformGeo::Duplicate(Geo* pgeo)
{
return new TransformGeo(pgeo, GetTransform());
}
void TransformGeo::Render(Context* pcontext)
{
pcontext->Multiply(GetTransform()->GetValue());
GetGeo()->Render(pcontext);
}
float TransformGeo::GetRadius(const Matrix& matArg)
{
Matrix mat;
mat.SetMultiply(GetTransform()->GetValue(), matArg);
return GetGeo()->GetRadius(mat);
}
void TransformGeo::CallGroupGeoCallback(const Matrix& matArg, GroupGeoCallback* pcallback)
{
Matrix mat;
mat.SetMultiply(GetTransform()->GetValue(), matArg);
GetGeo()->CallGroupGeoCallback(mat, pcallback);
}
TRef<Value> TransformGeo::Fold()
{
TRef<Geo> pgeo = GetGeo();
TRef<Transform> ptrans = GetTransform();
if (ptrans->IsConstant()) {
if (ptrans->IsIdentity()) {
return pgeo;
} else {
TRef<Geo> pgeoNew = pgeo->ApplyTransform(ptrans);
if (pgeoNew) {
return pgeoNew;
}
}
}
return WrapGeo::Fold();
}
MaterialGeo::MaterialGeo(Geo* pgeo, Material* pmaterial, bool bOverride) :
WrapGeo(pgeo, pmaterial),
m_bOverride(bOverride)
{
}
TRef<WrapGeo> MaterialGeo::Duplicate(Geo* pgeo)
{
return new MaterialGeo(pgeo, GetMaterial(), m_bOverride);
}
TRef<Geo> MaterialGeo::RemoveMaterial()
{
return GetGeo();
}
void MaterialGeo::Render(Context* pcontext)
{
pcontext->SetMaterial(GetMaterial(), m_bOverride);
GetGeo()->Render(pcontext);
}
TextureGeo::TextureGeo(Geo* pgeo, Image* pimageTexture, bool bOverride) :
WrapGeo(pgeo, pimageTexture),
m_bOverride(bOverride)
{
}
TRef<WrapGeo> TextureGeo::Duplicate(Geo* pgeo)
{
return new TextureGeo(pgeo, GetTexture(), m_bOverride);
}
TRef<Geo> TextureGeo::FoldTexture()
{
bool bAnyFold = false;
TRef<Geo> pgeo = GetGeo();
TRef<Geo> pgeoFold = pgeo->FoldTexture();
if (pgeoFold) {
bAnyFold = true;
SetGeo(pgeoFold);
} else {
pgeoFold = pgeo;
}
TRef<TextureGeo> ptextureGeo = pgeoFold->GetTextureGeo();
if (ptextureGeo) {
bAnyFold = true;
SetGeo(ptextureGeo->GetGeo());
}
if (bAnyFold) {
return this;
} else {
return NULL;
}
}
TextureGeo* TextureGeo::GetTextureGeo()
{
return this;
}
Image* TextureGeo::FindTexture()
{
if (GetTexture()) {
return GetTexture();
} else {
return GetGeo()->FindTexture();
}
}
void TextureGeo::Render(Context* pcontext)
{
pcontext->SetTexture(GetTexture()->GetSurface(), m_bOverride);
WrapGeo::Render(pcontext);
}
TimedGeo::TimedGeo(Geo* pgeo, Number* ptime, float lifespan) :
WrapGeo(pgeo, ptime),
m_lifespan(lifespan)
{
}
TRef<WrapGeo> TimedGeo::Duplicate(Geo* pgeo)
{
return new TimedGeo(pgeo, GetTime(), m_lifespan);
}
void TimedGeo::Evaluate()
{
if (GetTime()->GetValue() > m_lifespan) {
Trigger();
SetEmpty();
}
}
class GroupGeoImpl : public GroupGeo, private ValueList::Site {
private:
TRef<Geo> m_pgeoHit;
TRef<Geo> m_pgeoCapture;
ZString m_strName;
ValueList* GetValueList() { return ValueList::Cast(GetChild(0)); }
public:
GroupGeoImpl() :
GroupGeo(new ValueList(this))
{
}
bool RemoveValue(Value* pvalue)
{
return pvalue == Geo::GetEmpty();
}
TRef<Geo> ApplyTransform(Transform* ptrans)
{
ValueList* plist = GetValueList();
TRef<GroupGeo> pgroupNew = new GroupGeoImpl();
Geo* pgeo = Geo::Cast(plist->GetFirst());
while (pgeo) {
TRef<Geo> pgeoNew = pgeo->ApplyTransform(ptrans);
if (pgeoNew == NULL) {
return NULL;
}
pgroupNew->AddGeo(pgeoNew);
pgeo = Geo::Cast(plist->GetNext());
}
return pgroupNew;
}
bool AnyChildGroups(bool bHead)
{
if (bHead) {
TRef<ValueList> plist = GetValueList();
Geo* pgeo = Geo::Cast(plist->GetFirst());
while (pgeo) {
if (pgeo->AnyChildGroups(false)) {
return true;
}
pgeo = Geo::Cast(plist->GetNext());
}
return false;
}
return true;
}
TRef<Geo> RemoveMaterial()
{
bool bAnyFold = false;
TRef<ValueList> plist = GetValueList();
TRef<GroupGeo> pgroupNew = new GroupGeoImpl();
Geo* pgeo = Geo::Cast(plist->GetFirst());
while (pgeo) {
TRef<Geo> pgeoFold = pgeo->RemoveMaterial();
if (pgeoFold) {
bAnyFold = true;
pgroupNew->AddGeo(pgeoFold);
} else {
pgroupNew->AddGeo(pgeo);
}
pgeo = Geo::Cast(plist->GetNext());
}
if (bAnyFold) {
return pgroupNew;
}
return NULL;
}
TRef<Geo> RemoveTextures()
{
TRef<ValueList> plist = GetValueList();
TRef<GroupGeo> pgroupNew = new GroupGeoImpl();
TRef<Geo> pgeo = Geo::Cast(plist->GetFirst());
while(pgeo) {
pgroupNew->AddGeo(pgeo->GetTextureGeo()->GetGeo());
pgeo = Geo::Cast(plist->GetNext());
}
return pgroupNew;
}
class TextureData : public IObject {
public:
TRef<Geo> m_pgeo;
TRef<GroupGeoImpl> m_pgroup;
TRef<TextureGeo> m_ptextureGeo;
int m_count;
};
typedef TMap<TRef<Surface>, TRef<TextureData> > MapType;
TRef<Geo> FoldTexture()
{
bool bAnyFold = false;
TRef<ValueList> plist = GetValueList();
MapType map;
TRef<GroupGeoImpl> pgroupNew = new GroupGeoImpl();
TRef<Geo> pgeo = Geo::Cast(plist->GetFirst());
while (pgeo) {
TRef<Geo> pgeoFold = pgeo->FoldTexture();
if (pgeoFold) {
bAnyFold = true;
} else {
pgeoFold = pgeo;
}
TRef<TextureGeo> ptextureGeo = pgeoFold->GetTextureGeo();
if (ptextureGeo) {
TRef<Image> pimage = ptextureGeo->GetTexture();
TRef<Surface> psurface = pimage->GetSurface();
TRef<TextureData> pdata;
if (!map.Find(psurface, pdata)) {
pdata = new TextureData();
pdata->m_pgeo = ptextureGeo;
pdata->m_pgroup = new GroupGeoImpl();
pdata->m_ptextureGeo = new TextureGeo(pdata->m_pgroup, pimage, false);
pdata->m_count = 0;
map.Set(psurface, pdata);
}
pdata->m_count++;
pdata->m_pgroup->AddGeo(ptextureGeo->GetGeo());
} else {
pgroupNew->AddGeo(pgeoFold);
}
pgeo = Geo::Cast(plist->GetNext());
}
if (bAnyFold || map.Count() != 0) {
MapType::Iterator iter(map);
while (!iter.End()) {
TRef<TextureData> pdata = iter.Value();
if (pdata->m_count == 1) {
pgroupNew->AddGeo(pdata->m_pgeo);
} else {
bAnyFold = true;
pgroupNew->AddGeo(pdata->m_ptextureGeo);
}
iter.Next();
}
if (bAnyFold) {
return pgroupNew;
}
}
return NULL;
}
TRef<Value> Fold()
{
bool bAnyFold = false;
TRef<ValueList> plist = GetValueList();
TRef<Geo> pgeo = Geo::Cast(plist->GetFirst());
while (pgeo) {
if (pgeo == Geo::GetEmpty()) {
bAnyFold = true;
pgeo = Geo::Cast(plist->RemoveCurrent());
} else {
pgeo = Geo::Cast(plist->GetNext());
}
}
pgeo = Geo::Cast(plist->GetFirst());
while (pgeo) {
TRef<GroupGeoImpl> pgroupChild;
CastTo(pgroupChild, pgeo->GetGroupGeo());
if (pgroupChild != NULL) {
bAnyFold = true;
pgeo = Geo::Cast(plist->RemoveCurrent());
TRef<ValueList> plistChild = pgroupChild->GetValueList();
TRef<Geo> pgeoChild = Geo::Cast(plistChild->GetFirst());
while (pgeoChild) {
plist->PushFront(pgeoChild);
pgeoChild = Geo::Cast(plistChild->GetNext());
}
} else {
pgeo = Geo::Cast(plist->GetNext());
}
}
TRef<MeshGeo> pmeshGeo;
pgeo = Geo::Cast(plist->GetFirst());
while (pgeo) {
TRef<MeshGeo> pmeshGeoChild = pgeo->GetMeshGeo();
if (pmeshGeoChild != NULL) {
if (pmeshGeo != NULL) {
bAnyFold = true;
pmeshGeo = pmeshGeo->Combine(pmeshGeoChild);
} else {
pmeshGeo = pmeshGeoChild;
}
pgeo = Geo::Cast(plist->RemoveCurrent());
} else {
pgeo = Geo::Cast(plist->GetNext());
}
}
if (pmeshGeo) {
plist->PushFront(pmeshGeo);
}
int count = plist->GetCount();
if (count == 0) {
return Geo::GetEmpty();
} else if (count == 1) {
return Geo::Cast(plist->GetFirst());
} else {
if (bAnyFold) {
return this;
} else {
return NULL;
}
}
}
void SetName(const ZString& strName)
{
m_strName = strName;
}
const ZString& GetName()
{
return m_strName;
}
void AddGeo(Geo* pgeo)
{
GetValueList()->PushFront(pgeo);
}
void RemoveGeo(Geo* pgeo)
{
GetValueList()->Remove(pgeo);
}
ValueList* GetList()
{
return GetValueList();
}
GroupGeo* GetGroupGeo()
{
return this;
}
void Render(Context* pcontext)
{
Geo* pgeo = Geo::Cast(GetValueList()->GetFirst());
while (pgeo) {
if (GetValueList()->IsLast()) {
pgeo->Render(pcontext);
} else {
pcontext->PushState();
pgeo->Render(pcontext);
pcontext->PopState();
}
pgeo = Geo::Cast(GetValueList()->GetNext());
}
}
Image* FindTexture()
{
Geo* pgeo = Geo::Cast(GetValueList()->GetFirst());
while (pgeo) {
Image* pimage = pgeo->FindTexture();
if (pimage) {
return pimage;
}
pgeo = Geo::Cast(GetValueList()->GetNext());
}
return NULL;
}
int GetTriangleCount()
{
int tcount = 0;
Geo* pgeo = Geo::Cast(GetValueList()->GetFirst());
while (pgeo) {
tcount += pgeo->GetTriangleCount();
pgeo = Geo::Cast(GetValueList()->GetNext());
}
return tcount;
}
float GetRadius(const Matrix& mat)
{
float radius = 0;
Geo* pgeo = Geo::Cast(GetValueList()->GetFirst());
while (pgeo) {
radius = max(radius, pgeo->GetRadius(mat));
pgeo = Geo::Cast(GetValueList()->GetNext());
}
return radius;
}
void CallGroupGeoCallback(const Matrix& mat, GroupGeoCallback* pcallback)
{
TRef<Geo> pgeoReplace = pcallback->Execute(mat, this);
if (pgeoReplace) {
ChangeTo(pgeoReplace);
} else {
Geo* pgeo = Geo::Cast(GetValueList()->GetFirst());
while (pgeo) {
pgeo->CallGroupGeoCallback(mat, pcallback);
pgeo = Geo::Cast(GetValueList()->GetNext());
}
}
}
void RemoveCapture()
{
if (m_pgeoCapture) {
m_pgeoCapture->RemoveCapture();
m_pgeoCapture = NULL;
}
}
bool HitTest(const Vector& vecOrigin, const Vector& vecRay, HitData3D& hitData, bool bCaptured)
{
return false;
}
MouseResult Button(
const Vector& vec,
int button,
bool bCaptured,
bool bInside,
bool bDown
) {
MouseResult mouseResult;
if (m_pgeoCapture) {
mouseResult =
m_pgeoCapture->Button(
vec,
button,
true,
m_pgeoHit != NULL,
bDown
);
if (mouseResult.Test(MouseResultRelease())) {
m_pgeoCapture = NULL;
}
} else {
mouseResult = m_pgeoHit->Button(vec, button, false, true, bDown);
if (mouseResult.Test(MouseResultCapture())) {
m_pgeoCapture = m_pgeoHit;
}
}
return mouseResult;
}
};
TRef<GroupGeo> GroupGeo::Create()
{
return new GroupGeoImpl();
}
TRef<GroupGeo> GroupGeo::Create(Geo* pgeo)
{
TRef<GroupGeo> pgroup = new GroupGeoImpl();
pgroup->AddGeo(pgeo);
return pgroup;
}
TRef<GroupGeo> GroupGeo::Create(Geo* pgeo, Geo* pgeo2)
{
TRef<GroupGeo> pgroup = new GroupGeoImpl();
pgroup->AddGeo(pgeo);
pgroup->AddGeo(pgeo2);
return pgroup;
}
TRef<GroupGeo> GroupGeo::Create(Geo* pgeo, Geo* pgeo2, Geo* pgeo3)
{
TRef<GroupGeo> pgroup = new GroupGeoImpl();
pgroup->AddGeo(pgeo);
pgroup->AddGeo(pgeo2);
pgroup->AddGeo(pgeo3);
return pgroup;
}
class LODGeoImpl : public LODGeo {
private:
friend class LODGeo;
TVector<float> m_radii;
public:
LODGeoImpl(Geo* pgeo) :
LODGeo(pgeo)
{
pgeo->Update();
}
TRef<Geo> RemoveTextures()
{
TRef<LODGeoImpl> plodGeoNew = new LODGeoImpl(Geo::GetEmpty());
int count = GetChildCount();
for (int index = 0; index < count; index++) {
TRef<Geo> pgeo = Geo::Cast(GetChild(index))->GetTextureGeo()->GetGeo();
if (index == 0) {
plodGeoNew->SetGeo(pgeo);
} else {
plodGeoNew->AddGeo(pgeo, m_radii[index - 1]);
}
}
return plodGeoNew;
}
void AddGeo(Geo* pgeo, float radius)
{
int count = GetChildCount();
int index;
for (index = 0; index < count - 1; index++) {
if (radius > m_radii[index]) {
break;
}
}
if (index == count - 1) {
AddChild(pgeo);
m_radii.PushEnd(radius);
} else {
AddChild(GetChild(count - 1));
m_radii.PushEnd();
for (int inew = count - 1; inew > index; inew--) {
m_radii.Set(inew, m_radii[inew - 1]);
}
m_radii.Set(index, radius);
for (int inew = count - 1; inew > index + 1; inew--) {
SetChild(inew, GetChild(inew - 1));
}
SetChild(index + 1, pgeo);
}
}
ZString GetInfo()
{
int count = GetChildCount();
ZString str = "LODGeo with " + ZString(count) + " levels\n";
for (int index = 0; index < count; index++) {
TRef<Geo> pgeo = Geo::Cast(GetChild(index));
int ctriangle = pgeo->GetTriangleCount();
str += "level " + ZString(index) + " has " + ZString(ctriangle) + " triangles.\n";
}
return str;
}
int GetTriangleCount()
{
int tcount = 0;
int count = GetChildCount();
for (int index = 0; index < count; index++) {
tcount += Geo::Cast(GetChild(index))->GetTriangleCount();
}
return tcount;
}
float GetRadius(const Matrix& mat)
{
float radius = 0;
int count = GetChildCount();
for (int index = 0; index < count; index++) {
radius = max(radius, Geo::Cast(GetChild(index))->GetRadius(mat));
}
return radius;
}
void Render(Context* pcontext)
{
float radius = pcontext->GetLOD();
int count = GetChildCount();
int index;
for (index = 0; index < count - 1; index++) {
if (radius > m_radii[index]) {
break;
}
}
Geo::Cast(GetChild(index))->Render(pcontext);
}
bool AnyChildGroups(bool bHead)
{
int count = GetChildCount();
for (int index = 0; index < count; index++) {
TRef<Geo> pgeo = Geo::Cast(GetChild(index));
if (pgeo->AnyChildGroups(false)) {
return true;
}
}
return false;
}
TRef<Geo> RemoveMaterial()
{
bool bAnyFold = false;
int count = GetChildCount();
for (int index = 0; index < count; index++) {
TRef<Geo> pgeo = Geo::Cast(GetChild(index));
TRef<Geo> pgeoFold = pgeo->RemoveMaterial();
if (pgeoFold) {
bAnyFold = true;
SetChild(index, pgeoFold);
} else {
SetChild(index, pgeo);
}
}
if (bAnyFold) {
return this;
}
return NULL;
}
TRef<Geo> FoldTexture()
{
bool bAnyFold = false;
TRef<LODGeoImpl> plodGeoNew = new LODGeoImpl(Geo::GetEmpty());
bool bTexturesMatch = true;
TRef<Image> pimage;
TRef<Surface> psurface;
int count = GetChildCount();
for (int index = 0; index < count; index++) {
TRef<Geo> pgeo = Geo::Cast(GetChild(index));
TRef<Geo> pgeoFold = pgeo->FoldTexture();
if (pgeoFold) {
bAnyFold = true;
} else {
pgeoFold = pgeo;
}
if (index == 0) {
plodGeoNew->SetGeo(pgeoFold);
} else {
plodGeoNew->AddGeo(pgeoFold, m_radii[index - 1]);
}
TRef<TextureGeo> ptextureGeo = pgeoFold->GetTextureGeo();
if (ptextureGeo) {
if (pimage == NULL) {
pimage = ptextureGeo->GetTexture();
psurface = pimage->GetSurface();
} else {
if (ptextureGeo->GetTexture()->GetSurface() != psurface) {
bTexturesMatch = false;
}
}
} else {
bTexturesMatch = false;
}
}
if (bTexturesMatch) {
return
new TextureGeo(
plodGeoNew->RemoveTextures(),
pimage,
false
);
}
if (bAnyFold) {
return plodGeoNew;
}
return NULL;
}
TRef<WrapGeo> Duplicate(Geo* pgeo)
{
TRef<LODGeoImpl> pgeoNew = new LODGeoImpl(pgeo);
int count = GetChildCount();
for (int index = 1; index < count; index++) {
pgeoNew->AddGeo(
Geo::Cast(GetChild(index)),
m_radii[index - 1]
);
}
return pgeoNew;
}
TRef<Value> Fold()
{
if (GetChildCount() == 1) {
return GetGeo();
}
return NULL;
}
ZString GetFunctionName()
{
return "LODGeo";
}
ZString GetString(int indent)
{
ZString str = "LODGeo(\n";
str += Indent(indent + 1) + GetGeo()->GetString(indent + 1) + ",\n";
str += Indent(indent + 1) + "[\n";
int count = GetChildCount();
for (int index = 1; index < count; index++) {
Geo* pgeo = Geo::Cast(GetChild(index));
str += Indent(indent + 2) + "(\n";
str += Indent(indent + 3) + ZString(m_radii[index - 1]) + ",\n";
str += Indent(indent + 3) + pgeo->GetString(indent + 3) + "\n";
if (index == count - 1) {
str += Indent(indent + 2) + ")\n";
} else {
str += Indent(indent + 2) + "),\n";
}
}
str += Indent(indent + 1) + "]\n";
str += Indent(indent) + ")";
return str;
}
void Write(IMDLBinaryFile* pmdlFile)
{
int count = GetChildCount();
pmdlFile->WriteList(count - 1);
for (int index = count - 1; index > 0; index--) {
Geo* pgeo = Geo::Cast(GetChild(index));
pgeo->Write(pmdlFile);
pmdlFile->WriteNumber(m_radii[index - 1]);
pmdlFile->WritePair();
pmdlFile->WriteEnd();
}
GetGeo()->Write(pmdlFile);
pmdlFile->WriteReference("LODGeo");
pmdlFile->WriteApply();
}
};
TRef<LODGeo> LODGeo::Create(Geo* pgeo)
{
return new LODGeoImpl(pgeo);
}
CallbackGeo::CallbackGeo(Geo* pgeo) :
WrapGeo(pgeo)
{
}
TRef<WrapGeo> CallbackGeo::Duplicate(Geo* pgeo)
{
return new CallbackGeo(pgeo);
}
void CallbackGeo::Render(Context* pcontext)
{
pcontext->DrawCallbackGeo(this, false);
}
void CallbackGeo::RenderCallback(Context* pcontext)
{
GetGeo()->Render(pcontext);
}
class BlendGeo : public CallbackGeo {
private:
BlendMode m_blendMode;
public:
BlendGeo(Geo* pgeo, BlendMode blendMode) :
CallbackGeo(pgeo),
m_blendMode(blendMode)
{
}
TRef<WrapGeo> Duplicate(Geo* pgeo)
{
return new BlendGeo(pgeo, m_blendMode);
}
void RenderCallback(Context* pcontext)
{
pcontext->SetBlendMode(m_blendMode);
pcontext->SetZWrite(false);
GetGeo()->Render(pcontext);
}
};
TRef<Geo> CreateBlendGeo(Geo* pgeo, BlendMode blendMode)
{
return new BlendGeo(pgeo, blendMode);
}