Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //---------------------------------------------------------------------------
- #ifndef UModelH
- #define UModelH
- //---------------------------------------------------------------------------
- #include <Ray.h>
- #include <Documents.h>
- #include <DocNodes.h>
- #include <Pair.h>
- //---------------------------------------------------------------------------
- // Forward class declarations
- class CTexture;
- //---------------------------------------------------------------------------
- // Radius for a vertex sphere used by ray hit checks
- #define VERTEX_RADIUS 0.06f
- //---------------------------------------------------------------------------
- // Selection mode
- enum ESelectionMode
- {
- SM_VERTEX,
- SM_FACE,
- SM_OBJECT
- };
- //---------------------------------------------------------------------------
- // Selection action
- enum ESelectionAction
- {
- SA_SELECT,
- SA_DESELECT,
- SA_TOGGLE
- };
- //---------------------------------------------------------------------------
- // Coordinate restriction for operations
- enum ECoordinateRestriction
- {
- CR_NONE, // Do not restrict
- CR_XAXIS, // Restrict to X axis
- CR_YAXIS, // Restrict to Y axis
- CR_ZAXIS // Restrict to Z axis
- };
- //---------------------------------------------------------------------------
- // Geometries available for adding to a model
- enum EGeometry
- {
- G_PLANE,
- G_CUBE,
- G_OCTAGON,
- G_CONE,
- G_CYLINDER,
- G_SPHERE,
- G_ISOSPHERE
- };
- //---------------------------------------------------------------------------
- // A single vertex for a mesh
- struct SVertex
- {
- AVector P;
- AVector N;
- float S, T;
- bool Selected:1;
- bool Marked:1;
- bool Mask:1;
- // Empty constructor
- inline SVertex()
- : P(0.0f, 0.0f, 0.0f)
- , N(0.0f, 0.0f, 0.0f)
- , S(0.0f)
- , T(0.0f)
- , Selected(false)
- , Marked(false)
- , Mask(false)
- {
- }
- // Copy constructor
- inline SVertex(const SVertex& src)
- {
- operator=(src);
- }
- // Full values constructor
- inline SVertex(const AVector& p, const AVector& n, float s, float t)
- : P(p)
- , N(n)
- , S(s)
- , T(t)
- , Selected(false)
- , Marked(false)
- , Mask(false)
- {
- }
- // Assignment operator
- inline const SVertex& operator=(const SVertex& rhs)
- {
- if (&rhs != this) {
- P = rhs.P;
- N = rhs.N;
- S = rhs.S;
- T = rhs.T;
- Selected = rhs.Selected;
- Marked = rhs.Marked;
- Mask = rhs.Mask;
- }
- return *this;
- }
- // Equality operator (needed for TDynArray usage)
- inline bool operator==(const SVertex& rhs) const
- {
- return P==rhs.P && N==rhs.N && S==rhs.S && T==rhs.T;
- }
- // Inequality operator
- inline bool operator!=(const SVertex& rhs) const
- {
- return P!=rhs.P || N!=rhs.N || S!=rhs.S || T!=rhs.T;
- }
- };
- //---------------------------------------------------------------------------
- // A single face for a mesh
- struct SFace
- {
- unsigned A, B, C; // Vertex indices
- bool Selected;
- // Empty constructor
- inline SFace()
- : Selected(false)
- {
- }
- // Copy constructor
- inline SFace(const SFace& src)
- : A(src.A), B(src.B), C(src.C)
- , Selected(false)
- {
- }
- // Full values constructor
- inline SFace(unsigned a, unsigned b, unsigned c)
- : A(a), B(b), C(c)
- , Selected(false)
- {
- }
- // Assignment operator
- inline const SFace& operator=(const SFace& rhs)
- {
- if (&rhs != this) {
- A = rhs.A;
- B = rhs.B;
- C = rhs.C;
- Selected = rhs.Selected;
- }
- return *this;
- }
- // Equality operator (needed for TDynArray usage)
- inline bool operator==(const SFace& rhs) const
- {
- return A==rhs.A && B==rhs.B && C==rhs.C;
- }
- // Inequality operator
- inline bool operator!=(const SFace& rhs) const
- {
- return A!=rhs.A || B!=rhs.B || C!=rhs.C;
- }
- };
- //---------------------------------------------------------------------------
- // A mesh in the model
- class CMesh : public CDocNode
- {
- public:
- CMesh();
- virtual ~CMesh();
- // Adds a new vertex to this mesh and returns its index
- unsigned AddVertex(const SVertex& v);
- // Removes the vertex at the given index in the vertex array any faces that
- // refer to that vertex
- void RemoveVertex(unsigned idx);
- // Removes all vertices and faces from this mesh
- void RemoveAll();
- // Searches for the index of a vertex in the vertex array that matches the
- // given one and returns true if the vertex was found
- bool FindVertex(const SVertex& v, unsigned& index) const;
- // Searches for the index of a vertex in the vertex array that is at the
- // given position and returns true if the vertex was found
- bool FindVertexAt(const AVector& p, unsigned& index) const;
- // Searches for the vertices near the given position fills the given array
- // with the vertex indices, returns false if no vertices were found
- bool FindVerticesNear(const AVector& p, float distance, TDynArray<unsigned>& indices) const;
- // Returns the face indices using the given vertex, returns false if the
- // vertex has no faces associated with it
- bool FindVertexUsers(unsigned vidx, TDynArray<unsigned>& fidx) const;
- // Adds the given new face and returns the index in the faces array
- unsigned AddFace(const SFace& face);
- // Removes the face at the given index
- void RemoveFace(unsigned idx);
- // Returns true if the given ray hits a vertex while treating each vertex
- // as sphere with the given radius and fills the vertex index and
- // intersection point if so
- bool RayVertexHit(const ARay& ray, float radius, unsigned& vidx, AVector& ip) const;
- // Returns true if the given ray hits a face and fills the face index and
- // intersection point if so
- bool RayFaceHit(const ARay& ray, unsigned& fidx, AVector& ip) const;
- // Merge nearby selected vertices in this mesh
- void MergeVertices(float distance, bool maskOnly);
- // Clear the mask flag from all vertices
- void ClearMask();
- // Set the selected flag
- inline void SetSelected(bool selected) { m_selected = selected; }
- // Returns the texture this mesh is using
- inline const CTexture* GetTexture() const { return m_texture; }
- // Returns the vertices in this mesh
- inline TDynArray<SVertex>& GetVertices() { return m_vertices; }
- // Returns the faces in this mesh
- inline TDynArray<SFace>& GetFaces() { return m_faces; }
- // Returns true if this mesh is selected
- inline bool IsSelected() const { return m_selected; }
- private:
- TDynArray<SVertex> m_vertices; // Mesh vertices
- TDynArray<SFace> m_faces; // Mesh faces
- CTexture* m_texture; // Mesh texture
- bool m_selected; // The mesh is selected
- };
- //---------------------------------------------------------------------------
- // Model document class, contains the data for the edited model
- class CModel : public CDocument, public CDocRootNode
- {
- public:
- CModel();
- virtual ~CModel();
- // Creates a new mesh in this model
- CMesh* CreateMesh();
- // Returns true if the given ray hits a node and fills the node and
- // intersection point if so
- bool RayNodeHit(const ARay& ray, CDocNode*& node, AVector& ip) const;
- // Set the selection mode
- void SetSelectionMode(ESelectionMode selectionMode);
- // Clear the current selection
- void ClearSelection();
- // Select an element using the given ray
- void SelectByRay(const ARay& ray, ESelectionAction& action);
- // Select everything
- void SelectAll();
- // Collect pointers to selected vertices
- void CollectSelectedVertices(TDynArray< TPair<CMesh*,unsigned> >& vertices) const;
- // Clear the target mesh for new geometry
- void ClearTargetMesh();
- // Set the target mesh from the selection, returns false on empty selection
- bool SetTargetMeshFromSelection();
- // Returns the target mesh used to add new geometry
- CMesh* GetTargetMesh(bool createNewIfNone);
- // Set the 3D cursor
- void SetCursor(const AVector& cursor);
- // Set the 3D cursor from the selection, returns false on invalid selection
- bool SetCursorFromSelection();
- // Set the lockplane to the given plane
- void SetLockPlane(const APlane& plane);
- // Set the lockplane from the selection, returns false on invalid selection
- bool SetLockPlaneFromSelection();
- // Clear the lockplane
- void ClearLockPlane();
- // Set the coordinate restriction
- void SetCoordinateRestriction(ECoordinateRestriction coordRestrict);
- // Searches for the vertices near the given position fills the given array
- // with the mesh and vertex index pairs, returns false if no vertices were
- // found
- bool FindVerticesNear(const AVector& p, float distance, TDynArray< TPair<CMesh*,unsigned> >& vertices) const;
- // Weld (move at the same spot) selected vertices
- void WeldVertices(float distance);
- // Merge nearby selected vertices in all selected meshes
- void MergeVertices(float distance);
- // Split the selected vertices so that no selected face shares vertices
- // with another face
- void SplitVertices();
- // Flip the selected faces
- void FlipFaces();
- // Flip the selected vertex normals
- void FlipNormals();
- // Recalculate the normals for the selected vertices
- void RecalcNormals();
- // Select the vertices that are nearby to the already selected vertices
- void SelectNearbyVertices(float distance);
- // Add the given geometry either as a new mesh or as geometry to the
- // current target mesh (use ClearTargetMesh to force a new mesh), returns
- // the mesh that was used for the new geometry
- CMesh* AddGeometry(EGeometry geo);
- // Delete the selection
- void DeleteSelection();
- // Delete the selected faces only
- void DeleteSelectedFaces();
- // Returns the current selection mode
- inline ESelectionMode GetSelectionMode() const { return m_selectionMode; }
- // Returns the 3D cursor
- inline const AVector& GetCursor() const { return m_cursor; }
- // Returns the lockplane
- inline const APlane& GetLockPlane() const { return m_lockPlane; }
- // Returns true if there is a lockplane
- inline bool HasLockPlane() const { return m_lockPlane != APlane(0.0f, 0.0f, 0.0f, 0.0f); }
- // Returns the current coordinate restriction
- inline ECoordinateRestriction GetCoordinateRestriction() const { return m_coordRestrict; }
- private:
- TDynArray< TPair<CDocNode*,unsigned> > m_selection; // Currently selected elements
- ESelectionMode m_selectionMode; // Current selection mode
- CMesh* m_targetMesh; // Mesh to use as a target for new geometry
- AVector m_cursor; // 3D cursor
- APlane m_lockPlane; // Lockplane (used by tools)
- ECoordinateRestriction m_coordRestrict; // Current coordinate restriction
- protected:
- // CDocument
- virtual CDocView* CreateView(int);
- protected:
- // CNode
- virtual void OnChildRemoved(CNode* node);
- };
- //---------------------------------------------------------------------------
- #endif
- //---------------------------------------------------------------------------
- #pragma hdrstop
- #include <HashMap.h>
- #include "UModelView.h"
- #include "UModel.h"
- #include "UTools.h"
- //---------------------------------------------------------------------------
- // Mesh data used for primitives
- #include "MeshData.inc"
- //---------------------------------------------------------------------------
- // CMesh implementation
- CMesh::CMesh()
- : m_texture(NULL)
- , m_selected(false)
- {
- }
- //---------------------------------------------------------------------------
- CMesh::~CMesh()
- {
- GTool->ObjectDestroyed(this);
- }
- //---------------------------------------------------------------------------
- unsigned CMesh::AddVertex(const SVertex& v)
- {
- m_vertices.Add(v);
- MarkModified();
- return m_vertices.GetSize() - 1;
- }
- //---------------------------------------------------------------------------
- void CMesh::RemoveVertex(unsigned idx)
- {
- DEBUG_ASSERT(idx < m_vertices.GetSize(), "invalid vertex index");
- m_vertices.RemoveAt(idx);
- // Remove any faces that refer to this index
- if (m_faces.HasItems())
- {
- for (unsigned i=m_faces.GetSize() - 1;;i--)
- {
- if (m_faces[i].A == idx || m_faces[i].B == idx || m_faces[i].C == idx)
- {
- m_faces.RemoveAt(i);
- }
- if (!i) break;
- }
- // Adjust remaining indices
- for (unsigned i=0; i < m_faces.GetSize(); ++i)
- {
- if (m_faces[i].A > idx) m_faces[i].A--;
- if (m_faces[i].B > idx) m_faces[i].B--;
- if (m_faces[i].C > idx) m_faces[i].C--;
- }
- }
- MarkModified();
- }
- //---------------------------------------------------------------------------
- void CMesh::RemoveFace(unsigned idx)
- {
- DEBUG_ASSERT(idx < m_faces.GetSize(), "invalid face index");
- m_faces.RemoveAt(idx);
- MarkModified();
- }
- //---------------------------------------------------------------------------
- void CMesh::RemoveAll()
- {
- m_vertices.Clear();
- m_faces.Clear();
- MarkModified();
- }
- //---------------------------------------------------------------------------
- bool CMesh::FindVertex(const SVertex& v, unsigned& index) const
- {
- for (unsigned i=0; i < m_vertices.GetSize(); ++i)
- {
- if (v == m_vertices[i])
- {
- index = i;
- return true;
- }
- }
- return false;
- }
- //---------------------------------------------------------------------------
- bool CMesh::FindVertexAt(const AVector& p, unsigned& index) const
- {
- for (unsigned i=0; i < m_vertices.GetSize(); ++i)
- {
- if (p == m_vertices[i].P)
- {
- index = i;
- return true;
- }
- }
- return false;
- }
- //---------------------------------------------------------------------------
- bool CMesh::FindVerticesNear(const AVector& p, float distance, TDynArray<unsigned>& indices) const
- {
- unsigned start = indices.GetSize();
- distance = distance*distance;
- for (unsigned i=0; i < m_vertices.GetSize(); ++i)
- {
- if (NVector::TDistanceSquared3D(p, m_vertices[i].P) <= distance)
- {
- indices.AddUnique(i);
- }
- }
- return start < indices.GetSize();
- }
- //---------------------------------------------------------------------------
- bool CMesh::FindVertexUsers(unsigned vidx, TDynArray<unsigned>& fidx) const
- {
- unsigned start = fidx.GetSize();
- for (unsigned i=0; i < m_faces.GetSize(); ++i)
- {
- if (m_faces[i].A == vidx) fidx.Add(i);
- if (m_faces[i].B == vidx) fidx.Add(i);
- if (m_faces[i].C == vidx) fidx.Add(i);
- }
- return start < fidx.GetSize();
- }
- //---------------------------------------------------------------------------
- unsigned CMesh::AddFace(const SFace& face)
- {
- DEBUG_ASSERT(face.A < m_vertices.GetSize(), "invalid A vertex index");
- DEBUG_ASSERT(face.B < m_vertices.GetSize(), "invalid B vertex index");
- DEBUG_ASSERT(face.C < m_vertices.GetSize(), "invalid C vertex index");
- m_faces.Add(face);
- return m_faces.GetSize() - 1;
- }
- //---------------------------------------------------------------------------
- bool CMesh::RayVertexHit(const ARay& ray, float radius, unsigned& vidx, AVector& ip) const
- {
- AVector tmpIP;
- float distance, bestDistance = 0xFFFFFFFF;
- vidx = -1;
- for (unsigned i=0; i < m_vertices.GetSize(); ++i)
- {
- if (NRay::TSphereHit3D(ray, m_vertices[i].P, radius, tmpIP))
- {
- distance = NVector::TDistanceSquared3D(ray.O, tmpIP);
- if (vidx == -1 || distance < bestDistance)
- {
- bestDistance = distance;
- ip = tmpIP;
- vidx = i;
- }
- }
- }
- return vidx != -1;
- }
- //---------------------------------------------------------------------------
- bool CMesh::RayFaceHit(const ARay& ray, unsigned& fidx, AVector& ip) const
- {
- AVector tmpIP;
- float distance, bestDistance = 0xFFFFFFFF;
- fidx = -1;
- for (unsigned i=0; i < m_faces.GetSize(); ++i)
- {
- const SFace& face = m_faces[i];
- if (NRay::TTriangleHit3D(ray,
- m_vertices[face.A].P, m_vertices[face.B].P, m_vertices[face.C].P, tmpIP))
- {
- distance = NVector::TDistanceSquared3D(ray.O, tmpIP);
- if (fidx == -1 || distance < bestDistance)
- {
- bestDistance = distance;
- ip = tmpIP;
- fidx = i;
- }
- }
- }
- return fidx != -1;
- }
- //---------------------------------------------------------------------------
- void CMesh::MergeVertices(float distance, bool maskOnly)
- {
- TDynArray<unsigned> toDelete;
- if (m_vertices.GetSize() == 0) return;
- for (unsigned i=m_vertices.GetSize() - 1;; --i)
- {
- if (maskOnly && !m_vertices[i].Mask)
- {
- if (!i) break;
- continue;
- }
- if (!toDelete.Contains(i))
- {
- unsigned base = toDelete.GetSize();
- FindVerticesNear(m_vertices[i].P, distance, toDelete);
- toDelete.Remove(i);
- if (maskOnly && toDelete.HasItems())
- {
- for (unsigned j=toDelete.GetSize() - 1;; --j)
- {
- if (!m_vertices[toDelete[j]].Mask) toDelete.RemoveAt(j);
- if (!j) break;
- }
- }
- for (unsigned j=0; j < m_faces.GetSize(); ++j)
- {
- SFace& face = m_faces[j];
- for (unsigned k=base; k < toDelete.GetSize(); ++k)
- {
- if (face.A == toDelete[k]) face.A = i;
- if (face.B == toDelete[k]) face.B = i;
- if (face.C == toDelete[k]) face.C = i;
- }
- }
- }
- if (!i) break;
- }
- toDelete.Sort(NDynArray::TDescending);
- if (toDelete.HasItems())
- {
- for (unsigned i=0; i < toDelete.GetSize(); ++i)
- RemoveVertex(toDelete[i]);
- MarkModified();
- }
- }
- //---------------------------------------------------------------------------
- void CMesh::ClearMask()
- {
- for (unsigned i=0; i < m_vertices.GetSize(); ++i) m_vertices[i].Mask = false;
- }
- //---------------------------------------------------------------------------
- // CModel implementation
- CModel::CModel()
- : CDocument()
- , CDocRootNode(this)
- , m_selectionMode(SM_FACE)
- , m_targetMesh(NULL)
- , m_cursor(0, 0, 0)
- , m_lockPlane(0, 0, 0, 0)
- , m_coordRestrict(CR_NONE)
- {
- }
- //---------------------------------------------------------------------------
- CModel::~CModel()
- {
- GTool->ObjectDestroyed(this);
- }
- //---------------------------------------------------------------------------
- CMesh* CModel::CreateMesh()
- {
- DEBUG_ASSERT(CanModify(), "Tried to create a mesh in an unmodifiable model");
- CMesh* mesh = new CMesh();
- AddChild(mesh);
- CDocument::MarkModified();
- return mesh;
- }
- //---------------------------------------------------------------------------
- void CModel::SetSelectionMode(ESelectionMode selectionMode)
- {
- TDynArray< TPair<CMesh*,unsigned> > vertices;
- if (m_selectionMode == selectionMode) return;
- CollectSelectedVertices(vertices);
- ClearSelection();
- m_selectionMode = selectionMode;
- if (vertices.HasItems())
- {
- unsigned i;
- switch (selectionMode)
- {
- case SM_VERTEX:
- for (i=0; i < vertices.GetSize(); ++i)
- {
- vertices[i].First->GetVertices()[vertices[i].Second].Selected = true;
- m_selection.Add(TPair<CDocNode*,unsigned>(vertices[i].First, vertices[i].Second));
- }
- break;
- case SM_FACE:
- for (i=0; i < vertices.GetSize(); ++i)
- {
- vertices[i].First->GetVertices()[vertices[i].Second].Mask = true;
- }
- for (i=0; i < GetChildCount(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(GetChild(i));
- if (!mesh) continue;
- TDynArray<SFace>& faces = mesh->GetFaces();
- for (unsigned j=0; j < faces.GetSize(); ++j)
- {
- if (mesh->GetVertices()[faces[j].A].Mask &&
- mesh->GetVertices()[faces[j].B].Mask &&
- mesh->GetVertices()[faces[j].C].Mask)
- {
- faces[j].Selected = true;
- m_selection.Add(TPair<CDocNode*,unsigned>(mesh, j));
- }
- }
- }
- for (i=0; i < vertices.GetSize(); ++i)
- {
- vertices[i].First->GetVertices()[vertices[i].Second].Mask = false;
- }
- break;
- case SM_OBJECT:
- {} // TODO
- }
- }
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- void CModel::ClearSelection()
- {
- unsigned i;
- switch (m_selectionMode)
- {
- case SM_VERTEX:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- DEBUG_ASSERT(dynamic_cast<CMesh*>(m_selection[i].First), "Selected vertex is not associated with a mesh");
- static_cast<CMesh*>(m_selection[i].First)->GetVertices()[m_selection[i].Second].Selected = false;
- }
- break;
- case SM_FACE:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- DEBUG_ASSERT(dynamic_cast<CMesh*>(m_selection[i].First), "Selected face is not associated with a mesh");
- static_cast<CMesh*>(m_selection[i].First)->GetFaces()[m_selection[i].Second].Selected = false;
- }
- break;
- case SM_OBJECT:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(m_selection[i].First);
- if (!mesh) continue;
- mesh->SetSelected(false);
- }
- break;
- }
- m_selection.Clear();
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- bool CModel::RayNodeHit(const ARay& ray, CDocNode*& node, AVector& ip) const
- {
- AVector tmpIP;
- float distance, bestDistance = 0xFFFFFFFF;
- unsigned index;
- node = NULL;
- for (unsigned i=0; i < GetChildCount(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(GetChild(i));
- if (!mesh) continue;
- if (mesh->RayFaceHit(ray, index, tmpIP))
- {
- distance = NVector::TDistanceSquared3D(ray.O, tmpIP);
- if (!node || bestDistance > distance)
- {
- bestDistance = distance;
- node = mesh;
- ip = tmpIP;
- }
- }
- }
- if (!node)
- {
- for (unsigned i=0; i < GetChildCount(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(GetChild(i));
- if (!mesh) continue;
- if (mesh->RayVertexHit(ray, VERTEX_RADIUS, index, tmpIP))
- {
- distance = NVector::TDistanceSquared3D(ray.O, tmpIP);
- if (!node || bestDistance > distance)
- {
- bestDistance = distance;
- node = mesh;
- ip = tmpIP;
- }
- }
- }
- }
- return node != NULL;
- }
- //---------------------------------------------------------------------------
- void CModel::SelectByRay(const ARay& ray, ESelectionAction& action)
- {
- CDocNode* node;
- CMesh* mesh;
- AVector ip;
- unsigned index;
- if (!RayNodeHit(ray, node, ip)) return;
- mesh = dynamic_cast<CMesh*>(node);
- if (!mesh) return;
- switch (m_selectionMode)
- {
- case SM_VERTEX:
- if (!mesh->RayVertexHit(ray, VERTEX_RADIUS, index, ip)) return;
- if (action == SA_TOGGLE)
- action = mesh->GetVertices()[index].Selected ? SA_DESELECT : SA_SELECT;
- if (action == SA_SELECT)
- {
- m_selection.AddUnique(TPair<CDocNode*,unsigned>(mesh, index));
- mesh->GetVertices()[index].Selected = true;
- }
- else
- {
- m_selection.Remove(TPair<CDocNode*,unsigned>(mesh, index));
- mesh->GetVertices()[index].Selected = false;
- }
- if (!m_targetMesh) m_targetMesh = mesh;
- break;
- case SM_FACE:
- if (!mesh->RayFaceHit(ray, index, ip)) return;
- if (action == SA_TOGGLE)
- action = mesh->GetFaces()[index].Selected ? SA_DESELECT : SA_SELECT;
- if (action == SA_SELECT)
- {
- m_selection.AddUnique(TPair<CDocNode*,unsigned>(mesh, index));
- mesh->GetFaces()[index].Selected = true;
- }
- else
- {
- m_selection.Remove(TPair<CDocNode*,unsigned>(mesh, index));
- mesh->GetFaces()[index].Selected = false;
- }
- if (!m_targetMesh) m_targetMesh = mesh;
- break;
- case SM_OBJECT:
- if (action == SA_TOGGLE)
- action = mesh->IsSelected() ? SA_DESELECT : SA_SELECT;
- if (action == SA_SELECT)
- {
- m_selection.AddUnique(TPair<CDocNode*,unsigned>(mesh, 0));
- mesh->SetSelected(true);
- }
- else
- {
- m_selection.Remove(TPair<CDocNode*,unsigned>(mesh, 0));
- mesh->SetSelected(false);
- }
- if (!m_targetMesh) m_targetMesh = mesh;
- break;
- default:
- DEBUG_FAIL("Invalid selection mode");
- }
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- void CModel::SelectAll()
- {
- unsigned i, j;
- ClearSelection();
- switch (m_selectionMode)
- {
- case SM_VERTEX:
- for (i=0; i < GetChildCount(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(GetChild(i));
- if (!mesh) continue;
- for (j=0; j < mesh->GetVertices().GetSize(); ++j)
- {
- mesh->GetVertices()[j].Selected = true;
- m_selection.Add(TPair<CDocNode*,unsigned>(mesh, j));
- }
- }
- break;
- case SM_FACE:
- for (i=0; i < GetChildCount(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(GetChild(i));
- if (!mesh) continue;
- for (j=0; j < mesh->GetFaces().GetSize(); ++j)
- {
- mesh->GetFaces()[j].Selected = true;
- m_selection.Add(TPair<CDocNode*,unsigned>(mesh, j));
- }
- }
- break;
- case SM_OBJECT:
- for (i=0; i < GetChildCount(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(GetChild(i));
- if (!mesh) continue;
- mesh->SetSelected(true);
- m_selection.Add(TPair<CDocNode*,unsigned>(mesh, 0));
- }
- break;
- }
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- void CModel::CollectSelectedVertices(TDynArray< TPair<CMesh*,unsigned> >& vertices) const
- {
- // NOTE: it might be a good idea to update the selected flag in vertices
- // regardless of selection mode so that this method only has to go through
- // all vertices once instead
- unsigned i;
- switch (m_selectionMode)
- {
- case SM_VERTEX:
- vertices.SetCapacity(m_selection.GetSize());
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- vertices.Add(TPair<CMesh*,unsigned>(
- static_cast<CMesh*>(m_selection[i].First),
- m_selection[i].Second));
- }
- break;
- case SM_FACE:
- vertices.SetCapacity(m_selection.GetSize()*3);
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- CMesh* mesh = static_cast<CMesh*>(m_selection[i].First);
- const SFace& face = mesh->GetFaces()[m_selection[i].Second];
- vertices.AddUnique(TPair<CMesh*,unsigned>(mesh, face.A));
- vertices.AddUnique(TPair<CMesh*,unsigned>(mesh, face.B));
- vertices.AddUnique(TPair<CMesh*,unsigned>(mesh, face.C));
- }
- break;
- case SM_OBJECT:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(m_selection[i].First);
- if (!mesh) continue;
- for (unsigned j=0; j < mesh->GetVertices().GetSize(); ++j)
- vertices.Add(TPair<CMesh*,unsigned>(mesh, j));
- }
- break;
- }
- }
- //---------------------------------------------------------------------------
- void CModel::ClearTargetMesh()
- {
- if (!m_targetMesh) return;
- m_targetMesh = NULL;
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- bool CModel::SetTargetMeshFromSelection()
- {
- if (m_selection.IsEmpty()) return false;
- CMesh* targetMesh = dynamic_cast<CMesh*>(m_selection[0].First);
- if (!targetMesh) return false;
- if (targetMesh != m_targetMesh)
- {
- m_targetMesh = targetMesh;
- InvalidateViews();
- }
- return true;
- }
- //---------------------------------------------------------------------------
- CMesh* CModel::GetTargetMesh(bool createNewIfNone)
- {
- if (m_targetMesh) return m_targetMesh;
- if (createNewIfNone)
- {
- m_targetMesh = CreateMesh();
- InvalidateViews();
- return m_targetMesh;
- }
- return NULL;
- }
- //---------------------------------------------------------------------------
- void CModel::SetCursor(const AVector& cursor)
- {
- if (cursor == m_cursor) return;
- m_cursor = cursor;
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- bool CModel::SetCursorFromSelection()
- {
- if (m_selection.IsEmpty()) return false;
- TDynArray< TPair<CMesh*,unsigned> > vertices;
- CollectSelectedVertices(vertices);
- ABox box;
- box.Min = box.Max = vertices[0].First->GetVertices()[vertices[0].Second].P;
- for (unsigned i=1; i < vertices.GetSize(); ++i)
- {
- box.Include(vertices[i].First->GetVertices()[vertices[i].Second].P);
- }
- SetCursor(box.GetCenter3D());
- return true;
- }
- //---------------------------------------------------------------------------
- void CModel::SetLockPlane(const APlane& plane)
- {
- m_lockPlane = plane;
- }
- //---------------------------------------------------------------------------
- bool CModel::SetLockPlaneFromSelection()
- {
- if (m_selection.IsEmpty()) return false;
- switch (m_selectionMode)
- {
- case SM_VERTEX:
- if (m_selection.GetSize() < 3) return false;
- SetLockPlane(APlane(
- static_cast<CMesh*>(m_selection[0].First)->GetVertices()[m_selection[0].Second].P,
- static_cast<CMesh*>(m_selection[1].First)->GetVertices()[m_selection[1].Second].P,
- static_cast<CMesh*>(m_selection[2].First)->GetVertices()[m_selection[2].Second].P));
- break;
- case SM_FACE:
- if (m_selection.GetSize() < 1) return false;
- {
- const SFace& face = static_cast<CMesh*>(m_selection[0].First)->GetFaces()[m_selection[0].Second];
- SetLockPlane(APlane(
- static_cast<CMesh*>(m_selection[0].First)->GetVertices()[face.A].P,
- static_cast<CMesh*>(m_selection[0].First)->GetVertices()[face.B].P,
- static_cast<CMesh*>(m_selection[0].First)->GetVertices()[face.C].P));
- }
- break;
- case SM_OBJECT:
- return false;
- }
- return true;
- }
- //---------------------------------------------------------------------------
- void CModel::ClearLockPlane()
- {
- m_lockPlane.X = m_lockPlane.Y = m_lockPlane.Z = m_lockPlane.W = 0.0f;
- }
- //---------------------------------------------------------------------------
- void CModel::SetCoordinateRestriction(ECoordinateRestriction coordRestrict)
- {
- if (coordRestrict == m_coordRestrict) return;
- m_coordRestrict = coordRestrict;
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- bool CModel::FindVerticesNear(const AVector& p, float distance, TDynArray< TPair<CMesh*,unsigned> >& vertices) const
- {
- unsigned start = vertices.GetSize();
- for (unsigned i=0; i < GetChildCount(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(GetChild(i));
- if (!mesh) continue;
- TDynArray<unsigned> indices;
- if (mesh->FindVerticesNear(p, distance, indices))
- {
- for (unsigned j=0; j < indices.GetSize(); ++j)
- {
- vertices.Add(TPair<CMesh*,unsigned>(mesh, indices[j]));
- }
- }
- }
- return start < vertices.GetSize();
- }
- //---------------------------------------------------------------------------
- void CModel::WeldVertices(float distance)
- {
- TDynArray< TPair<CMesh*,unsigned> > vertices, cluster;
- bool modified = false;
- CollectSelectedVertices(vertices);
- if (!vertices.HasItems()) return;
- distance = distance*distance;
- for (unsigned i=0; i < vertices.GetSize(); ++i)
- {
- SVertex& vtx = vertices[i].First->GetVertices()[vertices[i].Second];
- if (!vtx.Mask)
- {
- TVector<double> avg(NVector::ToDouble(vtx.P));
- cluster.Reset();
- vtx.Mask = true;
- for (unsigned j=i + 1; j < vertices.GetSize(); ++j)
- {
- SVertex& ovtx = vertices[j].First->GetVertices()[vertices[j].Second];
- if (!ovtx.Mask && NVector::TDistanceSquared3D(vtx.P, ovtx.P) <= distance)
- {
- cluster.Add(vertices[j]);
- avg += NVector::ToDouble(ovtx.P);
- ovtx.Mask = true;
- }
- }
- if (cluster.HasItems())
- {
- double scale = 1.0/(cluster.GetSize() + 1);
- avg *= scale;
- AVector avgf = NVector::ToSingle(avg);
- vtx.P = avgf;
- for (unsigned j=0; j < cluster.GetSize(); ++j)
- {
- cluster[j].First->GetVertices()[cluster[j].Second].P = avgf;
- }
- modified = true;
- }
- }
- }
- for (unsigned i=0; i < vertices.GetSize(); ++i)
- {
- vertices[i].First->GetVertices()[vertices[i].Second].Mask = false;
- }
- if (modified)
- {
- CDocument::MarkModified();
- InvalidateViews();
- }
- }
- //---------------------------------------------------------------------------
- void CModel::MergeVertices(float distance)
- {
- TDynArray<CMesh*> meshes;
- unsigned i;
- ESelectionMode oldMode = m_selectionMode;
- switch (m_selectionMode)
- {
- case SM_VERTEX:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- CMesh* mesh = static_cast<CMesh*>(m_selection[i].First);
- meshes.AddUnique(mesh);
- mesh->GetVertices()[m_selection[i].Second].Mask = true;
- }
- break;
- case SM_FACE:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- CMesh* mesh = static_cast<CMesh*>(m_selection[i].First);
- meshes.AddUnique(mesh);
- const SFace& face = mesh->GetFaces()[m_selection[i].Second];
- mesh->GetVertices()[face.A].Mask = true;
- mesh->GetVertices()[face.B].Mask = true;
- mesh->GetVertices()[face.C].Mask = true;
- }
- break;
- case SM_OBJECT:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(m_selection[i].First);
- if (mesh)
- {
- for (unsigned j=0; j < mesh->GetVertices().GetSize(); ++j)
- {
- mesh->GetVertices()[j].Mask = true;
- }
- meshes.AddUnique(mesh);
- }
- }
- break;
- }
- ClearSelection();
- SetSelectionMode(SM_VERTEX);
- for (unsigned i=0; i < meshes.GetSize(); ++i)
- {
- CMesh* mesh = meshes[i];
- mesh->MergeVertices(distance, m_selectionMode != SM_OBJECT);
- for (unsigned j=0; j < mesh->GetVertices().GetSize(); ++j)
- {
- if (mesh->GetVertices()[j].Mask)
- {
- mesh->GetVertices()[j].Mask = false;
- mesh->GetVertices()[j].Selected = true;
- m_selection.Add(TPair<CDocNode*,unsigned>(mesh, j));
- }
- }
- }
- SetSelectionMode(oldMode);
- }
- //---------------------------------------------------------------------------
- void CModel::SplitVertices()
- {
- DEBUG_ASSERT(m_selectionMode == SM_FACE, "Can only split vertices in face mode");
- TDynArray<unsigned> fidx;
- for (unsigned i=0; i < m_selection.GetSize(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(m_selection[i].First);
- if (!mesh) continue;
- SFace& face = mesh->GetFaces()[m_selection[i].Second];
- // Split vertex A if needed
- fidx.Reset();
- mesh->FindVertexUsers(face.A, fidx);
- if (fidx.GetSize() > 1)
- {
- face.A = mesh->AddVertex(mesh->GetVertices()[face.A]);
- }
- // Split vertex B if needed
- fidx.Reset();
- mesh->FindVertexUsers(face.B, fidx);
- if (fidx.GetSize() > 1)
- {
- face.B = mesh->AddVertex(mesh->GetVertices()[face.B]);
- }
- // Split vertex C if needed
- fidx.Reset();
- mesh->FindVertexUsers(face.C, fidx);
- if (fidx.GetSize() > 1)
- {
- face.C = mesh->AddVertex(mesh->GetVertices()[face.C]);
- }
- }
- }
- //---------------------------------------------------------------------------
- void CModel::FlipFaces()
- {
- DEBUG_ASSERT(m_selectionMode == SM_FACE, "Can only flip faces in face mode");
- if (!m_selection.HasItems()) return;
- for (unsigned i=0; i < m_selection.GetSize(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(m_selection[i].First);
- if (!mesh) continue;
- SFace& face = mesh->GetFaces()[m_selection[i].Second];
- TSwap(face.B, face.C);
- }
- CDocument::MarkModified();
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- void CModel::FlipNormals()
- {
- TDynArray< TPair<CMesh*,unsigned> > vertices;
- CollectSelectedVertices(vertices);
- if (!vertices.HasItems()) return;
- for (unsigned i=0; i < vertices.GetSize(); ++i)
- {
- vertices[i].First->GetVertices()[vertices[i].Second].N = -vertices[i].First->GetVertices()[vertices[i].Second].N;
- }
- CDocument::MarkModified();
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- void CModel::RecalcNormals()
- {
- TDynArray< TPair<CMesh*,unsigned> > vertices, cluster;
- TDynArray<unsigned> fidx;
- bool modified = false;
- CollectSelectedVertices(vertices);
- if (!vertices.HasItems()) return;
- for (unsigned i=0; i < vertices.GetSize(); ++i)
- {
- CMesh* mesh = vertices[i].First;
- fidx.Reset();
- if (mesh->FindVertexUsers(vertices[i].Second, fidx))
- {
- SVertex& vtx = mesh->GetVertices()[vertices[i].Second];
- AVector vn(0, 0, 0);
- for (unsigned j=0; j < fidx.GetSize(); ++j)
- {
- const SFace& face = mesh->GetFaces()[fidx[j]];
- vn += NVector::TCalcTriangleNormal3D(
- mesh->GetVertices()[face.A].P,
- mesh->GetVertices()[face.B].P,
- mesh->GetVertices()[face.C].P);
- }
- vtx.N = vn.GetNormalized3D();
- modified = true;
- }
- }
- if (modified)
- {
- CDocument::MarkModified();
- InvalidateViews();
- }
- }
- //---------------------------------------------------------------------------
- void CModel::SelectNearbyVertices(float distance)
- {
- TDynArray< TPair<CMesh*,unsigned> > vertices;
- DEBUG_ASSERT(m_selectionMode == SM_VERTEX, "Can only select vertices in vertex mode");
- for (unsigned i=0; i < m_selection.GetSize(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(m_selection[i].First);
- if (!mesh) continue;
- FindVerticesNear(mesh->GetVertices()[m_selection[i].Second].P, distance, vertices);
- }
- if (!vertices.HasItems()) return;
- for (unsigned i=0; i < vertices.GetSize(); ++i)
- {
- if (!vertices[i].First->GetVertices()[vertices[i].Second].Selected)
- {
- vertices[i].First->GetVertices()[vertices[i].Second].Selected = true;
- m_selection.Add(TPair<CDocNode*,unsigned>(vertices[i].First, vertices[i].Second));
- }
- }
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- CMesh* CModel::AddGeometry(EGeometry geo)
- {
- const float* data;
- size_t count;
- switch (geo)
- {
- case G_PLANE:
- data = LPlane;
- count = sizeof(LPlane)/sizeof(LPlane[0]);
- break;
- case G_CUBE:
- data = LCube;
- count = sizeof(LCube)/sizeof(LCube[0]);
- break;
- case G_OCTAGON:
- data = LOctagon;
- count = sizeof(LOctagon)/sizeof(LOctagon[0]);
- break;
- case G_CONE:
- data = LCone;
- count = sizeof(LCone)/sizeof(LCone[0]);
- break;
- case G_CYLINDER:
- data = LCylinder;
- count = sizeof(LCylinder)/sizeof(LCylinder[0]);
- break;
- case G_SPHERE:
- data = LSphere;
- count = sizeof(LSphere)/sizeof(LSphere[0]);
- break;
- case G_ISOSPHERE:
- data = LIsosphere;
- count = sizeof(LIsosphere)/sizeof(LIsosphere[0]);
- break;
- default:
- DEBUG_FAIL("Invalid parameter passed for geometry");
- }
- CMesh* target = m_targetMesh ? m_targetMesh : CreateMesh();
- AMatrix m = NMatrix::GetRotation(-90*3.1415/180.0, AVector(1, 0, 0));
- for (size_t i=0; i < count; i += 9)
- {
- AVector va(data[i], data[i + 1], data[i + 2]);
- AVector vb(data[i + 3], data[i + 4], data[i + 5]);
- AVector vc(data[i + 6], data[i + 7], data[i + 8]);
- va = m.Transform3D(va);
- vb = m.Transform3D(vb);
- vc = m.Transform3D(vc);
- AVector n(NVector::TCalcTriangleNormal3D(va, vb, vc));
- int a = target->AddVertex(SVertex(va, n, 0, 0));
- int b = target->AddVertex(SVertex(vb, n, 0, 0));
- int c = target->AddVertex(SVertex(vc, n, 0, 0));
- target->AddFace(SFace(a, b, c));
- }
- if (!m_targetMesh) m_targetMesh = target;
- CDocument::MarkModified();
- InvalidateViews();
- return target;
- }
- //---------------------------------------------------------------------------
- void CModel::DeleteSelection()
- {
- unsigned i;
- THashMap< CMesh*,TDynArray<unsigned> > mvMap;
- TDynArray<CMesh*> meshes;
- switch (m_selectionMode)
- {
- case SM_VERTEX:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- DEBUG_ASSERT(dynamic_cast<CMesh*>(m_selection[i].First), "Selected vertex is not associated with a mesh");
- mvMap[static_cast<CMesh*>(m_selection[i].First)].Add(m_selection[i].Second);
- }
- ClearSelection();
- mvMap.GetKeys(meshes);
- for (i=0; i < meshes.GetSize(); ++i)
- {
- TDynArray<unsigned>& indices = mvMap[meshes[i]];
- indices.Sort(NDynArray::TDescending);
- for (unsigned j=0; j < indices.GetSize(); ++j)
- {
- meshes[i]->RemoveVertex(indices[j]);
- }
- }
- break;
- case SM_FACE:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- DEBUG_ASSERT(dynamic_cast<CMesh*>(m_selection[i].First), "Selected face is not associated with a mesh");
- CMesh* mesh = static_cast<CMesh*>(m_selection[i].First);
- mvMap[mesh].Add(mesh->GetFaces()[m_selection[i].Second].A);
- mvMap[mesh].Add(mesh->GetFaces()[m_selection[i].Second].B);
- mvMap[mesh].Add(mesh->GetFaces()[m_selection[i].Second].C);
- }
- ClearSelection();
- mvMap.GetKeys(meshes);
- for (i=0; i < meshes.GetSize(); ++i)
- {
- TDynArray<unsigned>& indices = mvMap[meshes[i]];
- indices.Sort(NDynArray::TDescending);
- for (unsigned j=0; j < indices.GetSize(); ++j)
- {
- meshes[i]->RemoveVertex(indices[j]);
- }
- }
- break;
- case SM_OBJECT:
- // TODO
- break;
- }
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- void CModel::DeleteSelectedFaces()
- {
- TDynArray<unsigned> faces;
- TDynArray<CMesh*> meshes;
- THashMap< CMesh*,TDynArray<unsigned> > mvMap;
- unsigned i;
- switch (m_selectionMode)
- {
- case SM_VERTEX:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- DEBUG_ASSERT(dynamic_cast<CMesh*>(m_selection[i].First), "Selected vertex is not associated with a mesh");
- meshes.AddUnique(static_cast<CMesh*>(m_selection[i].First));
- }
- for (i=0; i < meshes.GetSize(); ++i)
- {
- if (!meshes[i]->GetFaces().HasItems()) continue;
- faces.Reset();
- for (unsigned j=meshes[i]->GetFaces().GetSize() - 1;; --j)
- {
- if (meshes[i]->GetVertices()[meshes[i]->GetFaces()[j].A].Selected &&
- meshes[i]->GetVertices()[meshes[i]->GetFaces()[j].B].Selected &&
- meshes[i]->GetVertices()[meshes[i]->GetFaces()[j].C].Selected)
- {
- faces.Add(j);
- }
- if (!j) break;
- }
- for (unsigned j=0; j < faces.GetSize(); ++j)
- {
- meshes[i]->RemoveFace(faces[j]);
- }
- }
- ClearSelection();
- break;
- case SM_FACE:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- DEBUG_ASSERT(dynamic_cast<CMesh*>(m_selection[i].First), "Selected face is not associated with a mesh");
- mvMap[static_cast<CMesh*>(m_selection[i].First)].Add(m_selection[i].Second);
- }
- ClearSelection();
- mvMap.GetKeys(meshes);
- for (i=0; i < meshes.GetSize(); ++i)
- {
- TDynArray<unsigned>& indices = mvMap[meshes[i]];
- indices.Sort(NDynArray::TDescending);
- for (unsigned j=0; j < indices.GetSize(); ++j)
- {
- meshes[i]->RemoveFace(indices[j]);
- }
- }
- break;
- case SM_OBJECT:
- for (i=0; i < m_selection.GetSize(); ++i)
- {
- CMesh* mesh = dynamic_cast<CMesh*>(m_selection[i].First);
- if (!mesh) continue;
- mesh->GetFaces().Clear();
- }
- ClearSelection();
- CDocument::MarkModified();
- break;
- }
- InvalidateViews();
- }
- //---------------------------------------------------------------------------
- CDocView* CModel::CreateView(int)
- {
- return CModelViewCreator::Create(this);
- }
- //---------------------------------------------------------------------------
- void CModel::OnChildRemoved(CNode* node)
- {
- if (node == m_targetMesh) m_targetMesh = NULL;
- }
- //---------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment