#include "pch.h" ////////////////////////////////////////////////////////////////////////////// // // Empty Geo // ////////////////////////////////////////////////////////////////////////////// class EmptyGeo : public Geo { public: EmptyGeo() : Geo() { } // // Value members // ZString GetString(int indent) { return "emptyGeo"; } ZString GetFunctionName() { return "emptyGeo"; } void Write(IMDLBinaryFile* pfile) { pfile->WriteReference("emptyGeo"); } }; static TRef g_pemptyGeo = new EmptyGeo(); Geo* Geo::GetEmpty() { return g_pemptyGeo; } ////////////////////////////////////////////////////////////////////////////// // // Geo // ////////////////////////////////////////////////////////////////////////////// void Geo::SetEmpty() { ChangeTo(GetEmpty()); } void Geo::Render(Context* pcontext) { } bool Geo::AnyChildGroups(bool bHead) { return false; } TRef Geo::RemoveMaterial() { return NULL; } TRef 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::ApplyTransform(Transform* ptrans) { return NULL; } int Geo::GetTriangleCount() { return 0; } ////////////////////////////////////////////////////////////////////////////// // // TMeshGeo // ////////////////////////////////////////////////////////////////////////////// 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); } ////////////////////////////////////////////////////////////////////////////// // // TMeshGeo // ////////////////////////////////////////////////////////////////////////////// class MeshGeo : public Geo { public: virtual TRef Combine(MeshGeo* pmesh) = 0; }; template class TMeshGeo : public MeshGeo { TRef m_pobjectMemory; TVector m_vertices; TVector 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& vertices, const TVector& 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 Combine(MeshGeo* pmeshArg) { TMeshGeo* pmesh; CastTo(pmesh, pmeshArg); TVector vertices(pmesh->m_vertices); TVector indices(pmesh->m_indices); int countSource = m_vertices.GetCount(); int indexSource; TVector indexMap(countSource, countSource); // // Combine any common vertices // 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; } } } // // Map the indices to the new vertex list // countSource = m_indices.GetCount(); for(indexSource = 0; indexSource < countSource; indexSource++) { indices.PushEnd(indexMap[m_indices[indexSource]]); } // // Create the new Geo // return new TMeshGeo(vertices, indices); } TRef ApplyTransform(Transform* ptrans) { Matrix mat = ptrans->GetValue(); Matrix matNormal; matNormal.SetInverse(mat); matNormal.Transpose(); TVector 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) { // Mesh( [(vertices, normals, texture coordinates)], [indices]) 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(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) + "])"; } // // Value members // bool IsConstant() { return true; } ZString GetFunctionName() { return "MeshGeo"; } void Write(IMDLBinaryFile* pmdlFile) { pmdlFile->WriteReference("MeshGeo"); TRef 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()); } }; ////////////////////////////////////////////////////////////////////////////// // // TMeshGeo // ////////////////////////////////////////////////////////////////////////////// TRef Geo::CreateMesh( Vertex* pvertices, int vcount, MeshIndex* pindices, int icount, IObject* pobjectMemory ) { return new TMeshGeo(pvertices, vcount, pindices, icount, pobjectMemory); } TRef Geo::CreateMesh( D3DVertex* pvertices, int vcount, MeshIndex* pindices, int icount, IObject* pobjectMemory ) { return new TMeshGeo(pvertices, vcount, pindices, icount, pobjectMemory); } TRef Geo::CreateMesh(const TVector& vertices, const TVector& indices) { return new TMeshGeo(vertices, indices); } TRef Geo::CreateMesh(const TVector& vertices, const TVector& indices) { return new TMeshGeo(vertices, indices); } TRef Geo::CreateMesh(const TVector& vertices, const TVector& indices) { return new TMeshGeo(vertices, indices); } template TRef CreateStaticMesh(VertexType* pvertices, int vcount, MeshIndex* pindices, int icount) { return new TMeshGeo(pvertices, vcount, pindices, icount); } ////////////////////////////////////////////////////////////////////////////// // // Mesh Objects // ////////////////////////////////////////////////////////////////////////////// TRef g_pmeshSquare; TRef g_pmeshIcosahedron; TRef 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) ); /* Vertex pvertices[] = { Vertex(-1, 0, 1, 0, 0, 1), Vertex(-1, -1, 1, 0, 0, 1), Vertex( 1, 0, -1, 0, 0, 1) }; MeshIndex pindices[] = { 0, 2, 1 }; g_pmeshIcosahedron = CreateStaticMesh( pvertices, 3, pindices, 3 ); */ } return g_pmeshIcosahedron; } ////////////////////////////////////////////////////////////////////////////// // // Wrap Geo // ////////////////////////////////////////////////////////////////////////////// WrapGeo::WrapGeo(Geo* pgeo) : Geo(pgeo) { } WrapGeo::WrapGeo(Geo* pgeo, Value* pvalue1) : Geo(pgeo, pvalue1) { } TRef WrapGeo::Duplicate(Geo* pgeo) { return new WrapGeo(pgeo); } TRef WrapGeo::ApplyTransform(Transform* ptrans) { TRef pgeo = GetGeo()->ApplyTransform(ptrans); if (pgeo) { return Duplicate(pgeo); } return NULL; } bool WrapGeo::AnyChildGroups(bool bHead) { return GetGeo()->AnyChildGroups(false); } TRef WrapGeo::RemoveMaterial() { TRef pgeo = GetGeo()->RemoveMaterial(); if (pgeo) { SetGeo(pgeo); return this; } return NULL; } TRef WrapGeo::FoldTexture() { bool bAnyFold = false; TRef pgeo = GetGeo(); TRef pgeoFold = pgeo->FoldTexture(); if (pgeoFold) { bAnyFold = true; SetGeo(pgeoFold); } else { pgeoFold = pgeo; } TRef ptextureGeo = pgeoFold->GetTextureGeo(); if (ptextureGeo) { return new TextureGeo( Duplicate(ptextureGeo->GetGeo()), ptextureGeo->GetTexture(), false ); } if (bAnyFold) { return this; } else { return NULL; } } TRef 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::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 psurface = GetImage()->GetSurface(); pcontext->DrawDecal( psurface, m_color, m_vecPosition, m_vecForward, m_vecRight, m_scale, m_angle ); } ////////////////////////////////////////////////////////////////////////////// // // Visible Geo // ////////////////////////////////////////////////////////////////////////////// VisibleGeo::VisibleGeo(Geo* pgeo) : WrapGeo(pgeo), m_bVisible(true) { } TRef 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; } ////////////////////////////////////////////////////////////////////////////// // // Clip Geo // ////////////////////////////////////////////////////////////////////////////// ClipGeo::ClipGeo(Geo* pgeo) : WrapGeo(pgeo), m_bClip(true) { } TRef 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; } ////////////////////////////////////////////////////////////////////////////// // // ClipPlane Geo // ////////////////////////////////////////////////////////////////////////////// ClipPlaneGeo::ClipPlaneGeo(Geo* pgeo, const Plane& plane) : WrapGeo(pgeo), m_plane(plane) { } TRef 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; } ////////////////////////////////////////////////////////////////////////////// // // Transform Geo // ////////////////////////////////////////////////////////////////////////////// TransformGeo::TransformGeo(Geo* pgeo, Transform* ptrans) : WrapGeo(pgeo, ptrans) { } TRef 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 TransformGeo::Fold() { TRef pgeo = GetGeo(); TRef ptrans = GetTransform(); if (ptrans->IsConstant()) { if (ptrans->IsIdentity()) { return pgeo; } else { TRef pgeoNew = pgeo->ApplyTransform(ptrans); if (pgeoNew) { return pgeoNew; } } } return WrapGeo::Fold(); } ////////////////////////////////////////////////////////////////////////////// // // Material Geo // ////////////////////////////////////////////////////////////////////////////// MaterialGeo::MaterialGeo(Geo* pgeo, Material* pmaterial, bool bOverride) : WrapGeo(pgeo, pmaterial), m_bOverride(bOverride) { } TRef MaterialGeo::Duplicate(Geo* pgeo) { return new MaterialGeo(pgeo, GetMaterial(), m_bOverride); } TRef MaterialGeo::RemoveMaterial() { return GetGeo(); } void MaterialGeo::Render(Context* pcontext) { pcontext->SetMaterial(GetMaterial(), m_bOverride); GetGeo()->Render(pcontext); } ////////////////////////////////////////////////////////////////////////////// // // Texture Geo // ////////////////////////////////////////////////////////////////////////////// TextureGeo::TextureGeo(Geo* pgeo, Image* pimageTexture, bool bOverride) : WrapGeo(pgeo, pimageTexture), m_bOverride(bOverride) { } TRef TextureGeo::Duplicate(Geo* pgeo) { return new TextureGeo(pgeo, GetTexture(), m_bOverride); } TRef TextureGeo::FoldTexture() { bool bAnyFold = false; TRef pgeo = GetGeo(); TRef pgeoFold = pgeo->FoldTexture(); if (pgeoFold) { bAnyFold = true; SetGeo(pgeoFold); } else { pgeoFold = pgeo; } TRef 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); } ////////////////////////////////////////////////////////////////////////////// // // Timed Geo // ////////////////////////////////////////////////////////////////////////////// TimedGeo::TimedGeo(Geo* pgeo, Number* ptime, float lifespan) : WrapGeo(pgeo, ptime), m_lifespan(lifespan) { } TRef TimedGeo::Duplicate(Geo* pgeo) { return new TimedGeo(pgeo, GetTime(), m_lifespan); } void TimedGeo::Evaluate() { if (GetTime()->GetValue() > m_lifespan) { Trigger(); SetEmpty(); } } ////////////////////////////////////////////////////////////////////////////// // // Group Geo // ////////////////////////////////////////////////////////////////////////////// class GroupGeoImpl : public GroupGeo, private ValueList::Site { private: TRef m_pgeoHit; TRef m_pgeoCapture; ZString m_strName; ValueList* GetValueList() { return ValueList::Cast(GetChild(0)); } public: GroupGeoImpl() : GroupGeo(new ValueList(this)) { } ////////////////////////////////////////////////////////////////////////////// // // ValueList::Site members // ////////////////////////////////////////////////////////////////////////////// bool RemoveValue(Value* pvalue) { return pvalue == Geo::GetEmpty(); } ////////////////////////////////////////////////////////////////////////////// // // Value members // ////////////////////////////////////////////////////////////////////////////// TRef ApplyTransform(Transform* ptrans) { ValueList* plist = GetValueList(); TRef pgroupNew = new GroupGeoImpl(); Geo* pgeo = Geo::Cast(plist->GetFirst()); while (pgeo) { TRef 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 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 RemoveMaterial() { bool bAnyFold = false; TRef plist = GetValueList(); TRef pgroupNew = new GroupGeoImpl(); Geo* pgeo = Geo::Cast(plist->GetFirst()); while (pgeo) { TRef 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 RemoveTextures() { TRef plist = GetValueList(); TRef pgroupNew = new GroupGeoImpl(); TRef 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 m_pgeo; TRef m_pgroup; TRef m_ptextureGeo; int m_count; }; typedef TMap, TRef > MapType; TRef FoldTexture() { bool bAnyFold = false; TRef plist = GetValueList(); // // Fold the children // MapType map; TRef pgroupNew = new GroupGeoImpl(); TRef pgeo = Geo::Cast(plist->GetFirst()); while (pgeo) { TRef pgeoFold = pgeo->FoldTexture(); if (pgeoFold) { bAnyFold = true; } else { pgeoFold = pgeo; } TRef ptextureGeo = pgeoFold->GetTextureGeo(); if (ptextureGeo) { TRef pimage = ptextureGeo->GetTexture(); TRef psurface = pimage->GetSurface(); TRef 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()); } // // Fix up the group if any folding happened // if (bAnyFold || map.Count() != 0) { MapType::Iterator iter(map); while (!iter.End()) { TRef 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 Fold() { bool bAnyFold = false; TRef plist = GetValueList(); // // Remove EmptyGeos // TRef pgeo = Geo::Cast(plist->GetFirst()); while (pgeo) { if (pgeo == Geo::GetEmpty()) { bAnyFold = true; pgeo = Geo::Cast(plist->RemoveCurrent()); } else { pgeo = Geo::Cast(plist->GetNext()); } } // // Fold any of the child groups into the group // pgeo = Geo::Cast(plist->GetFirst()); while (pgeo) { TRef pgroupChild; CastTo(pgroupChild, pgeo->GetGroupGeo()); if (pgroupChild != NULL) { bAnyFold = true; pgeo = Geo::Cast(plist->RemoveCurrent()); TRef plistChild = pgroupChild->GetValueList(); TRef pgeoChild = Geo::Cast(plistChild->GetFirst()); while (pgeoChild) { // !!! should this be push end? plist->PushFront(pgeoChild); pgeoChild = Geo::Cast(plistChild->GetNext()); } } else { pgeo = Geo::Cast(plist->GetNext()); } } // // Combine meshes // TRef pmeshGeo; pgeo = Geo::Cast(plist->GetFirst()); while (pgeo) { TRef 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); } // // Fold this node depending on the number of children // 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; } } } ////////////////////////////////////////////////////////////////////////////// // // GroupGeo members // ////////////////////////////////////////////////////////////////////////////// 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(); } ////////////////////////////////////////////////////////////////////////////// // // Geo members // ////////////////////////////////////////////////////////////////////////////// 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 pgeoReplace = pcallback->Execute(mat, this); if (pgeoReplace) { ChangeTo(pgeoReplace); } else { // // recurse over the children // 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) { /* !!! this isn't exactly right m_pgeoHit = NULL; if (m_pgeoCapture) { if (m_pgeoCapture->HitTest(vecOrigin, vecRay, hitData, bCaptured)) { m_pgeoHit = m_pgeoCapture; } } else { Geo* pgeo = Geo::Cast(GetValueList()->GetFirst()); while (pgeo) { if (pgeo->HitTest(vecOrigin, vecRay, hitData, bCaptured)) { m_pgeoHit = pgeo; } pgeo = Geo::Cast(GetValueList()->GetNext()); } } return m_pgeoHit != NULL; */ 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::Create() { return new GroupGeoImpl(); } TRef GroupGeo::Create(Geo* pgeo) { TRef pgroup = new GroupGeoImpl(); pgroup->AddGeo(pgeo); return pgroup; } TRef GroupGeo::Create(Geo* pgeo, Geo* pgeo2) { TRef pgroup = new GroupGeoImpl(); pgroup->AddGeo(pgeo); pgroup->AddGeo(pgeo2); return pgroup; } TRef GroupGeo::Create(Geo* pgeo, Geo* pgeo2, Geo* pgeo3) { TRef pgroup = new GroupGeoImpl(); pgroup->AddGeo(pgeo); pgroup->AddGeo(pgeo2); pgroup->AddGeo(pgeo3); return pgroup; } ////////////////////////////////////////////////////////////////////////////// // // LODGeo // ////////////////////////////////////////////////////////////////////////////// class LODGeoImpl : public LODGeo { private: // // types // friend class LODGeo; // // members // TVector m_radii; public: LODGeoImpl(Geo* pgeo) : LODGeo(pgeo) { pgeo->Update(); } TRef RemoveTextures() { TRef plodGeoNew = new LODGeoImpl(Geo::GetEmpty()); int count = GetChildCount(); for (int index = 0; index < count; index++) { TRef pgeo = Geo::Cast(GetChild(index))->GetTextureGeo()->GetGeo(); if (index == 0) { plodGeoNew->SetGeo(pgeo); } else { plodGeoNew->AddGeo(pgeo, m_radii[index - 1]); } } return plodGeoNew; } ////////////////////////////////////////////////////////////////////////////// // // LODGeo members // ////////////////////////////////////////////////////////////////////////////// void AddGeo(Geo* pgeo, float radius) { // // Insert in sorted order // int count = GetChildCount(); for (int index = 0; index < count - 1; index++) { if (radius > m_radii[index]) { break; } } if (index == count - 1) { // // Insert in the last slot // AddChild(pgeo); m_radii.PushEnd(radius); } else { // // move the last geo // AddChild(GetChild(count - 1)); m_radii.PushEnd(); // // Insert before index // for (int inew = count - 1; inew > index; inew--) { m_radii.Set(inew, m_radii[inew - 1]); } m_radii.Set(index, radius); for (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 pgeo = Geo::Cast(GetChild(index)); int ctriangle = pgeo->GetTriangleCount(); str += "level " + ZString(index) + " has " + ZString(ctriangle) + " triangles.\n"; } return str; } ////////////////////////////////////////////////////////////////////////////// // // Geo members // ////////////////////////////////////////////////////////////////////////////// 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(); for (int 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 pgeo = Geo::Cast(GetChild(index)); if (pgeo->AnyChildGroups(false)) { return true; } } return false; } TRef RemoveMaterial() { bool bAnyFold = false; int count = GetChildCount(); for (int index = 0; index < count; index++) { TRef pgeo = Geo::Cast(GetChild(index)); TRef pgeoFold = pgeo->RemoveMaterial(); if (pgeoFold) { bAnyFold = true; SetChild(index, pgeoFold); } else { SetChild(index, pgeo); } } if (bAnyFold) { return this; } return NULL; } TRef FoldTexture() { bool bAnyFold = false; TRef plodGeoNew = new LODGeoImpl(Geo::GetEmpty()); bool bTexturesMatch = true; TRef pimage; TRef psurface; int count = GetChildCount(); for (int index = 0; index < count; index++) { TRef pgeo = Geo::Cast(GetChild(index)); TRef 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 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 the textures match colapse the TextureGeos // if (bTexturesMatch) { return new TextureGeo( plodGeoNew->RemoveTextures(), pimage, false ); } if (bAnyFold) { return plodGeoNew; } return NULL; } TRef Duplicate(Geo* pgeo) { TRef 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; } ////////////////////////////////////////////////////////////////////////////// // // Value members // ////////////////////////////////////////////////////////////////////////////// TRef Fold() { if (GetChildCount() == 1) { return GetGeo(); } return NULL; } ZString GetFunctionName() { return "LODGeo"; } ZString GetString(int indent) { // LODGeo (baseGeo, [(pixels, geo)]) 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::Create(Geo* pgeo) { return new LODGeoImpl(pgeo); } ////////////////////////////////////////////////////////////////////////////// // // Callback Geo // ////////////////////////////////////////////////////////////////////////////// CallbackGeo::CallbackGeo(Geo* pgeo) : WrapGeo(pgeo) { } TRef 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); } ////////////////////////////////////////////////////////////////////////////// // // Blend Add Geo // ////////////////////////////////////////////////////////////////////////////// class BlendGeo : public CallbackGeo { private: BlendMode m_blendMode; public: BlendGeo(Geo* pgeo, BlendMode blendMode) : CallbackGeo(pgeo), m_blendMode(blendMode) { } // // WrapGeo members // TRef Duplicate(Geo* pgeo) { return new BlendGeo(pgeo, m_blendMode); } // // Geo members // void RenderCallback(Context* pcontext) { pcontext->SetBlendMode(m_blendMode); pcontext->SetZWrite(false); GetGeo()->Render(pcontext); } }; TRef CreateBlendGeo(Geo* pgeo, BlendMode blendMode) { return new BlendGeo(pgeo, blendMode); }