Line data Source code
1 : /* Copyright (C) 2021 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : /*
19 : * Defines a raw 3d model.
20 : */
21 :
22 : #ifndef INCLUDED_MODELDEF
23 : #define INCLUDED_MODELDEF
24 :
25 : #include "maths/BoundingBoxAligned.h"
26 : #include "maths/Matrix3D.h"
27 : #include "maths/Quaternion.h"
28 : #include "maths/Vector2D.h"
29 : #include "maths/Vector3D.h"
30 : #include "lib/file/vfs/vfs_path.h"
31 : #include "ps/CStr.h"
32 : #include "renderer/VertexArray.h"
33 :
34 : #include <cstring>
35 : #include <map>
36 : #include <unordered_map>
37 : #include <vector>
38 :
39 : class CBoneState;
40 : class CSkeletonAnimDef;
41 :
42 : /**
43 : * Describes the position of a prop point within its parent model. A prop point is the location within a parent model
44 : * where the prop's origin will be attached.
45 : *
46 : * A prop point is specified by its transformation matrix (or separately by its position and rotation), which
47 : * can be relative to either the parent model's origin, or one of the parent's bones. If the parent model is boned,
48 : * then the @ref m_BoneIndex field may specify a bone to which the transformation matrix is relative (see
49 : * @ref CModel::m_BoneMatrices). Otherwise, the transformation matrix is assumed to be relative to the parent model's
50 : * origin.
51 : *
52 : * @see CModel::m_BoneMatrices
53 : */
54 6 : struct SPropPoint
55 : {
56 : /// Name of the prop point
57 : CStr m_Name;
58 :
59 : /**
60 : * Position of the point within the parent model, relative to either the parent model's origin or one of the parent
61 : * model's bones if applicable. Also specified as part of @ref m_Transform.
62 : * @see m_Transform
63 : */
64 : CVector3D m_Position;
65 :
66 : /**
67 : * Rotation of the prop model that will be attached at this point. Also specified as part of @ref m_Transform.
68 : * @see m_Transform
69 : */
70 : CQuaternion m_Rotation;
71 :
72 : /**
73 : * Object to parent space transformation. Combines both @ref m_Position and @ref m_Rotation in a single
74 : * transformation matrix. This transformation is relative to either the parent model's origin, or one of its
75 : * bones, depending on whether it is skeletal. If relative to a bone, then the bone in the parent model to
76 : * which this transformation is relative may be found by m_BoneIndex.
77 : * @see m_Position, m_Rotation
78 : */
79 : CMatrix3D m_Transform;
80 :
81 : /**
82 : * Index of parent bone to which this prop point is relative, if any. The value 0xFF specifies that either the parent
83 : * model is unboned, or that this prop point is relative to the parent model's origin rather than one if its bones.
84 : */
85 : u8 m_BoneIndex;
86 : };
87 :
88 : ///////////////////////////////////////////////////////////////////////////////
89 : // SVertexBlend: structure containing the necessary data for blending vertices
90 : // with multiple bones
91 : struct SVertexBlend
92 : {
93 : enum { SIZE = 4 };
94 : // index of the influencing bone, or 0xff if none
95 : u8 m_Bone[SIZE];
96 : // weight of the influence; all weights sum to 1
97 : float m_Weight[SIZE];
98 :
99 0 : bool operator==(const SVertexBlend& o) const
100 : {
101 0 : return !memcmp(m_Bone, o.m_Bone, sizeof(m_Bone)) && !memcmp(m_Weight, o.m_Weight, sizeof(m_Weight));
102 : }
103 : };
104 :
105 : ///////////////////////////////////////////////////////////////////////////////
106 : // SModelVertex: structure containing per-vertex data
107 746 : struct SModelVertex
108 : {
109 : // vertex position
110 : CVector3D m_Coords;
111 : // vertex normal
112 : CVector3D m_Norm;
113 : // vertex blend data
114 : SVertexBlend m_Blend;
115 : };
116 :
117 :
118 : ///////////////////////////////////////////////////////////////////////////////
119 : // SModelFace: structure containing per-face data
120 : struct SModelFace
121 : {
122 : // indices of the 3 vertices on this face
123 : u16 m_Verts[3];
124 : };
125 :
126 :
127 : ////////////////////////////////////////////////////////////////////////////////////////
128 : // CModelDefRPrivate
129 : class CModelDefRPrivate
130 : {
131 : public:
132 0 : CModelDefRPrivate() { }
133 0 : virtual ~CModelDefRPrivate() { }
134 : };
135 :
136 :
137 : ////////////////////////////////////////////////////////////////////////////////////////
138 : // CModelDef: a raw 3D model; describes the vertices, faces, skinning and skeletal
139 : // information of a model
140 : class CModelDef
141 : {
142 : NONCOPYABLE(CModelDef);
143 :
144 : public:
145 : // current file version given to saved animations
146 : enum { FILE_VERSION = 3 };
147 : // supported file read version - files with a version less than this will be rejected
148 : enum { FILE_READ_VERSION = 1 };
149 :
150 :
151 : public:
152 : CModelDef();
153 : ~CModelDef();
154 :
155 : // model I/O functions
156 :
157 : static void Save(const VfsPath& filename,const CModelDef* mdef);
158 :
159 : /**
160 : * Loads a PMD file.
161 : * @param filename VFS path of .pmd file to load
162 : * @param name arbitrary name to give the model for debugging purposes (usually pathname)
163 : * @return the model - always non-NULL
164 : * @throw PSERROR_File if it can't load the model
165 : */
166 : static CModelDef* Load(const VfsPath& filename, const VfsPath& name);
167 :
168 : public:
169 : // accessor: get vertex data
170 0 : size_t GetNumVertices() const { return m_NumVertices; }
171 0 : SModelVertex* GetVertices() const { return m_pVertices; }
172 :
173 : // accessor: get number of UV sets
174 0 : size_t GetNumUVsPerVertex() const { return m_NumUVsPerVertex; }
175 :
176 0 : const std::vector<CVector2D>& GetUVCoordinates() const { return m_UVCoordinates; }
177 :
178 : // accessor: get face data
179 0 : size_t GetNumFaces() const { return m_NumFaces; }
180 0 : SModelFace* GetFaces() const { return m_pFaces; }
181 :
182 : // accessor: get bone data
183 0 : size_t GetNumBones() const { return m_NumBones; }
184 6 : CBoneState* GetBones() const { return m_Bones; }
185 0 : CMatrix3D* GetInverseBindBoneMatrices() { return m_InverseBindBoneMatrices; }
186 :
187 : // accessor: get blend data
188 0 : size_t GetNumBlends() const { return m_NumBlends; }
189 : SVertexBlend* GetBlends() const { return m_pBlends; }
190 0 : size_t* GetBlendIndices() const { return m_pBlendIndices; }
191 :
192 : // find and return pointer to prop point matching given name; return
193 : // null if no match (case insensitive search)
194 : const SPropPoint* FindPropPoint(const char* name) const;
195 :
196 : /**
197 : * @param anim may be null
198 : */
199 : void GetMaxBounds(CSkeletonAnimDef* anim, bool loop, CBoundingBoxAligned& result);
200 :
201 : /**
202 : * Transform the given vertex's position from the bind pose into the new pose.
203 : *
204 : * @return new world-space vertex coordinates
205 : */
206 : static CVector3D SkinPoint(const SModelVertex& vtx,
207 : const CMatrix3D newPoseMatrices[]);
208 :
209 : /**
210 : * Transform the given vertex's normal from the bind pose into the new pose.
211 : *
212 : * @return new world-space vertex normal
213 : */
214 : static CVector3D SkinNormal(const SModelVertex& vtx,
215 : const CMatrix3D newPoseMatrices[]);
216 :
217 : /**
218 : * Transform vertices' positions and normals.
219 : * (This is equivalent to looping over SkinPoint and SkinNormal,
220 : * but slightly more efficient.)
221 : */
222 : static void(*SkinPointsAndNormals)(
223 : size_t numVertices,
224 : const VertexArrayIterator<CVector3D>& Position,
225 : const VertexArrayIterator<CVector3D>& Normal,
226 : const SModelVertex* vertices,
227 : const size_t* blendIndices,
228 : const CMatrix3D newPoseMatrices[]);
229 :
230 : /**
231 : * Blend bone matrices together to fill bone palette.
232 : */
233 : void BlendBoneMatrices(CMatrix3D boneMatrices[]);
234 :
235 : /**
236 : * Register renderer private data. Use the key to
237 : * distinguish between private data used by different render paths.
238 : * The private data will be managed by this CModelDef object:
239 : * It will be deleted when CModelDef is destructed or when private
240 : * data is registered using the same key.
241 : *
242 : * @param key The opaque key that is used to identify the caller.
243 : * The given private data can be retrieved by passing key to GetRenderData.
244 : * @param data The private data.
245 : *
246 : * postconditions : data is bound to the lifetime of this CModelDef
247 : * object.
248 : */
249 : void SetRenderData(const void* key, CModelDefRPrivate* data);
250 :
251 : // accessor: render data
252 : CModelDefRPrivate* GetRenderData(const void* key) const;
253 :
254 : // accessor: get model name (for debugging)
255 4 : const VfsPath& GetName() const { return m_Name; }
256 :
257 : public:
258 : // vertex data
259 : size_t m_NumVertices;
260 : SModelVertex* m_pVertices;
261 : std::vector<CVector2D> m_UVCoordinates;
262 : size_t m_NumUVsPerVertex; // number of UV pairs per vertex
263 : // face data
264 : size_t m_NumFaces;
265 : SModelFace* m_pFaces;
266 : // bone data - default model pose
267 : size_t m_NumBones;
268 : CBoneState* m_Bones;
269 : CMatrix3D* m_InverseBindBoneMatrices;
270 : // blend data
271 : size_t m_NumBlends;
272 : SVertexBlend *m_pBlends;
273 : size_t* m_pBlendIndices;
274 : // prop point data
275 : std::vector<SPropPoint> m_PropPoints;
276 :
277 : private:
278 : VfsPath m_Name; // filename
279 :
280 : // Maximal bounding box of this mesh for a given animation.
281 : std::unordered_map<u32, CBoundingBoxAligned> m_MaxBoundsPerAnimDef;
282 :
283 : // renderdata shared by models of the same modeldef,
284 : // by render path
285 : typedef std::map<const void*, CModelDefRPrivate*> RenderDataMap;
286 : RenderDataMap m_RenderData;
287 : };
288 :
289 : /**
290 : * Detects CPU caps and activates the best possible codepath.
291 : */
292 : extern void ModelDefActivateFastImpl();
293 :
294 : #endif
295 :
|