1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #ifndef _3DMODEL_H
4 #define _3DMODEL_H
5 
6 #include <vector>
7 #include <string>
8 #include <set>
9 #include <map>
10 #include "Rendering/GL/VBO.h"
11 #include "System/Matrix44f.h"
12 #include "System/creg/creg_cond.h"
13 
14 static const float3 DEF_MIN_SIZE( 10000.0f,  10000.0f,  10000.0f);
15 static const float3 DEF_MAX_SIZE(-10000.0f, -10000.0f, -10000.0f);
16 
17 enum ModelType {
18 	MODELTYPE_3DO   = 0,
19 	MODELTYPE_S3O   = 1,
20 	MODELTYPE_OBJ   = 2,
21 	MODELTYPE_ASS   = 3, // Model loaded by Assimp library
22 	MODELTYPE_OTHER = 4  // For future use. Still used in some parts of code.
23 };
24 enum AxisMappingType {
25 	AXIS_MAPPING_XYZ = 0,
26 	AXIS_MAPPING_ZXY = 1,
27 	AXIS_MAPPING_YZX = 2,
28 	AXIS_MAPPING_XZY = 3,
29 	AXIS_MAPPING_ZYX = 4,
30 	AXIS_MAPPING_YXZ = 5,
31 };
32 
33 struct CollisionVolume;
34 struct S3DModel;
35 struct S3DModelPiece;
36 struct LocalModel;
37 struct LocalModelPiece;
38 
39 typedef std::map<std::string, S3DModelPiece*> ModelPieceMap;
40 
41 
42 /**
43  * S3DModel
44  * A 3D model definition. Holds geometry (vertices/normals) and texture data as well as the piece tree.
45  * The S3DModel is static and shouldn't change once created, instead a LocalModel is used by each agent.
46  */
47 
48 struct S3DModelPiece {
49 	S3DModelPiece();
50 	virtual ~S3DModelPiece();
51 
52 	virtual unsigned int CreateDrawForList() const;
UploadGeometryVBOsS3DModelPiece53 	virtual void UploadGeometryVBOs() {}
54 
GetVertexCountS3DModelPiece55 	virtual unsigned int GetVertexCount() const { return 0; }
GetNormalCountS3DModelPiece56 	virtual unsigned int GetNormalCount() const { return 0; }
GetTxCoorCountS3DModelPiece57 	virtual unsigned int GetTxCoorCount() const { return 0; }
58 
59 	virtual const float3& GetVertexPos(const int) const = 0;
60 	virtual const float3& GetNormal(const int) const = 0;
GetPosOffsetS3DModelPiece61 	virtual float3 GetPosOffset() const { return ZeroVector; }
ShatterS3DModelPiece62 	virtual void Shatter(float, int, int, const float3&, const float3&) const {}
63 
ComposeRotationS3DModelPiece64 	CMatrix44f& ComposeRotation(CMatrix44f& m, const float3& r) const {
65 		// execute rotations in YPR order by default
66 		// note: translating + rotating is faster than
67 		// matrix-multiplying (but the branching hurts)
68 		switch (axisMapType) {
69 			case AXIS_MAPPING_XYZ: {
70 				if (r.y != 0.0f) { m.RotateY(r.y * rotAxisSigns.y); } // yaw
71 				if (r.x != 0.0f) { m.RotateX(r.x * rotAxisSigns.x); } // pitch
72 				if (r.z != 0.0f) { m.RotateZ(r.z * rotAxisSigns.z); } // roll
73 			} break;
74 
75 			case AXIS_MAPPING_XZY: {
76 				if (r.y != 0.0f) { m.RotateZ(r.y * rotAxisSigns.y); } // yaw
77 				if (r.x != 0.0f) { m.RotateX(r.x * rotAxisSigns.x); } // pitch
78 				if (r.z != 0.0f) { m.RotateY(r.z * rotAxisSigns.z); } // roll
79 			} break;
80 
81 			case AXIS_MAPPING_YXZ:
82 			case AXIS_MAPPING_YZX:
83 			case AXIS_MAPPING_ZXY:
84 			case AXIS_MAPPING_ZYX: {
85 				// FIXME: implement
86 			} break;
87 		}
88 
89 		return m;
90 	}
91 
ComposeTransformS3DModelPiece92 	bool ComposeTransform(CMatrix44f& m, const float3& t, const float3& r, const float3& s) const {
93 		bool isIdentity = true;
94 
95 		// NOTE: ORDER MATTERS (T(baked + script) * R(baked) * R(script) * S(baked))
96 		if (t != ZeroVector) { m = m.Translate(t);        isIdentity = false; }
97 		if (!hasIdentityRot) { m *= bakedRotMatrix;       isIdentity = false; }
98 		if (r != ZeroVector) { m = ComposeRotation(m, r); isIdentity = false; }
99 		if (s != OnesVector) { m = m.Scale(s);            isIdentity = false; }
100 
101 		return isIdentity;
102 	}
103 
104 	// draw piece and children statically (ie. without script-transforms)
105 	void DrawStatic() const;
106 
SetCollisionVolumeS3DModelPiece107 	void SetCollisionVolume(CollisionVolume* cv) { colvol = cv; }
GetCollisionVolumeS3DModelPiece108 	const CollisionVolume* GetCollisionVolume() const { return colvol; }
GetCollisionVolumeS3DModelPiece109 	      CollisionVolume* GetCollisionVolume()       { return colvol; }
110 
GetChildCountS3DModelPiece111 	unsigned int GetChildCount() const { return children.size(); }
GetChildS3DModelPiece112 	S3DModelPiece* GetChild(unsigned int i) const { return children[i]; }
113 
GetDisplayListIDS3DModelPiece114 	unsigned int GetDisplayListID() const { return dispListID; }
SetDisplayListIDS3DModelPiece115 	void SetDisplayListID(unsigned int id) { dispListID = id; }
116 
HasGeometryDataS3DModelPiece117 	bool HasGeometryData() const { return hasGeometryData; }
HasIdentityRotationS3DModelPiece118 	bool HasIdentityRotation() const { return hasIdentityRot; }
119 
SetHasGeometryDataS3DModelPiece120 	void SetHasGeometryData(bool b) { hasGeometryData = b; }
SetHasIdentityRotationS3DModelPiece121 	void SetHasIdentityRotation(bool b) { hasIdentityRot = b; }
122 
123 protected:
124 	virtual void DrawForList() const = 0;
125 
126 public:
127 	std::string name;
128 	std::string parentName;
129 
130 	std::vector<S3DModelPiece*> children;
131 
132 	S3DModelPiece* parent;
133 	CollisionVolume* colvol;
134 
135 	AxisMappingType axisMapType;
136 
137 	bool hasGeometryData;      /// if piece contains any geometry data
138 	bool hasIdentityRot;       /// if bakedRotMatrix is identity
139 
140 	CMatrix44f bakedRotMatrix; /// baked local-space rotations (assimp-only)
141 
142 	float3 offset;             /// local (piece-space) offset wrt. parent piece
143 	float3 goffset;            /// global (model-space) offset wrt. root piece
144 	float3 scales;             /// baked uniform scaling factors (assimp-only)
145 	float3 mins;
146 	float3 maxs;
147 	float3 rotAxisSigns;
148 
149 protected:
150 	unsigned int dispListID;
151 
152 	VBO vboIndices;
153 	VBO vboAttributes;
154 };
155 
156 
157 
158 struct S3DModel
159 {
S3DModelS3DModel160 	S3DModel()
161 		: id(-1)
162 		, numPieces(0)
163 		, textureType(-1)
164 
165 		, type(MODELTYPE_OTHER)
166 
167 		, invertTexYAxis(false)
168 		, invertTexAlpha(false)
169 
170 		, radius(0.0f)
171 		, height(0.0f)
172 		, drawRadius(0.0f)
173 
174 		, mins(DEF_MIN_SIZE)
175 		, maxs(DEF_MAX_SIZE)
176 		, relMidPos(ZeroVector)
177 
178 		, rootPiece(NULL)
179 	{
180 	}
181 
GetRootPieceS3DModel182 	S3DModelPiece* GetRootPiece() const { return rootPiece; }
183 	S3DModelPiece* FindPiece(const std::string& name) const;
184 
SetRootPieceS3DModel185 	void SetRootPiece(S3DModelPiece* p) { rootPiece = p; }
DrawStaticS3DModel186 	void DrawStatic() const { rootPiece->DrawStatic(); }
187 	void DeletePieces(S3DModelPiece* piece);
188 
189 public:
190 	std::string name;
191 	std::string tex1;
192 	std::string tex2;
193 
194 	int id;                     /// unsynced ID, starting with 1
195 	int numPieces;
196 	int textureType;            /// FIXME: MAKE S3O ONLY (0 = 3DO, otherwise S3O or OBJ)
197 
198 	ModelType type;
199 
200 	bool invertTexYAxis;        /// Turn both textures upside down before use
201 	bool invertTexAlpha;        /// Invert teamcolor alpha channel in S3O texture 1
202 
203 	float radius;
204 	float height;
205 	float drawRadius;
206 
207 	float3 mins;
208 	float3 maxs;
209 	float3 relMidPos;
210 
211 	S3DModelPiece* rootPiece;   /// The piece at the base of the model hierarchy
212 	ModelPieceMap pieceMap;     /// Lookup table for pieces by name
213 };
214 
215 
216 
217 /**
218  * LocalModel
219  * Instance of S3DModel. Container for the geometric properties & piece visibility status of the agent's instance of a 3d model.
220  */
221 
222 struct LocalModelPiece
223 {
224 	CR_DECLARE_STRUCT(LocalModelPiece)
225 
226 	LocalModelPiece(const S3DModelPiece* piece);
227 	~LocalModelPiece();
228 
AddChildLocalModelPiece229 	void AddChild(LocalModelPiece* c) { children.push_back(c); }
SetParentLocalModelPiece230 	void SetParent(LocalModelPiece* p) { parent = p; }
231 
SetLModelPieceIndexLocalModelPiece232 	void SetLModelPieceIndex(unsigned int idx) { lmodelPieceIndex = idx; }
SetScriptPieceIndexLocalModelPiece233 	void SetScriptPieceIndex(unsigned int idx) { scriptPieceIndex = idx; }
GetLModelPieceIndexLocalModelPiece234 	unsigned int GetLModelPieceIndex() const { return lmodelPieceIndex; }
GetScriptPieceIndexLocalModelPiece235 	unsigned int GetScriptPieceIndex() const { return scriptPieceIndex; }
236 
237 	void Draw() const;
238 	void DrawLOD(unsigned int lod) const;
239 	void SetLODCount(unsigned int count);
240 
241 	bool UpdateMatrix();
242 	void UpdateMatricesRec(bool updateChildMatrices);
243 
244 	bool GetEmitDirPos(float3& pos, float3& dir) const;
245 	float3 GetAbsolutePos() const;
246 
SetPositionLocalModelPiece247 	void SetPosition(const float3& p) { pos = p; ++numUpdatesSynced; }
SetRotationLocalModelPiece248 	void SetRotation(const float3& r) { rot = r; ++numUpdatesSynced; }
SetDirectionLocalModelPiece249 	void SetDirection(const float3& d) { dir = d; } // unused
250 
GetPositionLocalModelPiece251 	const float3& GetPosition() const { return pos; }
GetRotationLocalModelPiece252 	const float3& GetRotation() const { return rot; }
GetDirectionLocalModelPiece253 	const float3& GetDirection() const { return dir; }
254 
GetPieceSpaceMatrixLocalModelPiece255 	const CMatrix44f& GetPieceSpaceMatrix() const { return pieceSpaceMat; }
GetModelSpaceMatrixLocalModelPiece256 	const CMatrix44f& GetModelSpaceMatrix() const { return modelSpaceMat; }
257 
GetCollisionVolumeLocalModelPiece258 	const CollisionVolume* GetCollisionVolume() const { return colvol; }
GetCollisionVolumeLocalModelPiece259 	      CollisionVolume* GetCollisionVolume()       { return colvol; }
260 
261 private:
262 	float3 pos; // translation relative to parent LMP, *INITIALLY* equal to original->offset
263 	float3 rot; // orientation relative to parent LMP, in radians (updated by scripts)
264 	float3 dir; // direction from vertex[0] to vertex[1] (constant!)
265 
266 	CMatrix44f pieceSpaceMat; // transform relative to parent LMP (SYNCED), combines <pos> and <rot>
267 	CMatrix44f modelSpaceMat; // transform relative to root LMP (SYNCED)
268 
269 	CollisionVolume* colvol;
270 
271 	unsigned numUpdatesSynced; // triggers UpdateMatrix (via UpdateMatricesRec) if != lastMatrixUpdate
272 	unsigned lastMatrixUpdate;
273 
274 public:
275 	bool scriptSetVisible;  // TODO: add (visibility) maxradius!
276 	bool identityTransform; // true IFF pieceSpaceMat (!) equals identity
277 
278 	unsigned int lmodelPieceIndex; // index of this piece into LocalModel::pieces
279 	unsigned int scriptPieceIndex; // index of this piece into UnitScript::pieces
280 	unsigned int dispListID;
281 
282 	const S3DModelPiece* original;
283 	const LocalModelPiece* parent;
284 
285 	std::vector<LocalModelPiece*> children;
286 	std::vector<unsigned int> lodDispLists;
287 };
288 
289 
290 struct LocalModel
291 {
292 	CR_DECLARE_STRUCT(LocalModel)
293 
LocalModelLocalModel294 	LocalModel(const S3DModel* model)
295 		: dirtyPieces(model->numPieces)
296 		, lodCount(0)
297 	{
298 		assert(model->numPieces >= 1);
299 		pieces.reserve(model->numPieces);
300 		CreateLocalModelPieces(model->GetRootPiece());
301 		assert(pieces.size() == model->numPieces);
302 	}
303 
~LocalModelLocalModel304 	~LocalModel()
305 	{
306 		// delete the local piece copies
307 		for (std::vector<LocalModelPiece*>::iterator pi = pieces.begin(); pi != pieces.end(); ++pi) {
308 			delete *pi;
309 		}
310 		pieces.clear();
311 	}
312 
HasPieceLocalModel313 	bool HasPiece(unsigned int i) const { return (i < pieces.size()); }
GetPieceLocalModel314 	LocalModelPiece* GetPiece(unsigned int i) const { assert(HasPiece(i)); return pieces[i]; }
GetRootLocalModel315 	LocalModelPiece* GetRoot() const { return GetPiece(0); }
316 
DrawLocalModel317 	void Draw() const { DrawPieces(); }
DrawLODLocalModel318 	void DrawLOD(unsigned int lod) const {
319 		if (lod > lodCount)
320 			return;
321 
322 		DrawPiecesLOD(lod);
323 	}
324 
UpdatePieceMatricesLocalModel325 	void UpdatePieceMatrices() {
326 		if (dirtyPieces > 0) {
327 			pieces[0]->UpdateMatricesRec(false);
328 		}
329 		dirtyPieces = 0;
330 	}
331 
332 
333 
334 	void DrawPieces() const;
335 	void DrawPiecesLOD(unsigned int lod) const;
336 
337 	void SetLODCount(unsigned int count);
PieceUpdatedLocalModel338 	void PieceUpdated(unsigned int pieceIdx) { dirtyPieces += 1; }
339 
340 	void ReloadDisplayLists();
341 
342 	// raw forms, the piece-index must be valid
343 	// NOTE:
344 	//   GetRawPieceDirection is only useful for special pieces (used for emit-sfx)
345 	//   it returns a direction in piece-space, NOT model-space as the "Raw" suggests
346 	//   this direction is vertex[0].pos - vertex[1].pos for pieces with >= 2 vertices
347 	//   only LuaSyncedRead::GetUnitPieceDirection calls it, better mark as DEPRECATED
GetRawEmitDirPosLocalModel348 	void GetRawEmitDirPos(int pieceIdx, float3& emitPos, float3& emitDir) const { pieces[pieceIdx]->GetEmitDirPos(emitPos, emitDir); }
GetRawPiecePosLocalModel349 	float3 GetRawPiecePos(int pieceIdx) const { return pieces[pieceIdx]->GetAbsolutePos(); }
GetRawPieceDirectionLocalModel350 	float3 GetRawPieceDirection(int pieceIdx) const { return pieces[pieceIdx]->GetDirection(); }
GetRawPieceMatrixLocalModel351 	const CMatrix44f& GetRawPieceMatrix(int pieceIdx) const { return pieces[pieceIdx]->GetModelSpaceMatrix(); }
352 
353 private:
354 	LocalModelPiece* CreateLocalModelPieces(const S3DModelPiece* mpParent);
355 
356 public:
357 	// increased by UnitScript whenever a piece is transformed
358 	unsigned int dirtyPieces;
359 	unsigned int lodCount;
360 
361 	std::vector<LocalModelPiece*> pieces;
362 };
363 
364 #endif /* _3DMODEL_H */
365