1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #ifndef __C_COLLADA_MESH_FILE_LOADER_H_INCLUDED__
6 #define __C_COLLADA_MESH_FILE_LOADER_H_INCLUDED__
7 
8 #include "IMeshLoader.h"
9 #include "IFileSystem.h"
10 #include "IVideoDriver.h"
11 #include "irrString.h"
12 #include "SMesh.h"
13 #include "SMeshBuffer.h"
14 #include "ISceneManager.h"
15 #include "irrMap.h"
16 #include "CAttributes.h"
17 
18 namespace irr
19 {
20 namespace scene
21 {
22 
23 #ifdef _DEBUG
24 //#define COLLADA_READER_DEBUG
25 #endif
26 
27 class IColladaPrefab;
28 
29 enum ECOLLADA_PARAM_NAME
30 {
31 	ECPN_COLOR = 0,
32 	ECPN_AMBIENT,
33 	ECPN_DIFFUSE,
34 	ECPN_SPECULAR,
35 	ECPN_SHININESS,
36 	ECPN_TRANSPARENCY,
37 	ECPN_YFOV,
38 	ECPN_ZNEAR,
39 	ECPN_ZFAR,
40 
41 	ECPN_COUNT
42 };
43 
44 enum ECOLLADA_PARAM_TYPE
45 {
46 	ECPT_FLOAT = 0,
47 	ECPT_FLOAT2,
48 	ECPT_FLOAT3,
49 	ECPT_FLOAT4,
50 
51 	ECPT_COUNT
52 };
53 
54 //! Collada Parameter
55 struct SColladaParam
56 {
SColladaParamSColladaParam57 	SColladaParam()
58 		: Name(ECPN_COUNT), Type(ECPT_COUNT)
59 	{
60 		for (int i=0; i<4; ++i) Floats[i] = 0;
61 	}
62 
63 	ECOLLADA_PARAM_NAME Name;
64 	ECOLLADA_PARAM_TYPE Type;
65 
66 	f32 Floats[4];
67 };
68 
69 enum ECOLLADA_INPUT_SEMANTIC
70 {
71 	ECIS_POSITION = 0,
72 	ECIS_VERTEX,
73 	ECIS_NORMAL,
74 	ECIS_TEXCOORD,
75 	ECIS_UV,
76 	ECIS_TANGENT,
77 	ECIS_IMAGE,
78 	ECIS_TEXTURE,
79 
80 	ECIS_COUNT
81 };
82 
83 //! Collada Input
84 struct SColladaInput
85 {
SColladaInputSColladaInput86 	SColladaInput()
87 		: Semantic(ECIS_COUNT), Data(0), Offset(0), Set(0), Stride(1)
88 	{
89 	}
90 
91 	ECOLLADA_INPUT_SEMANTIC Semantic;
92 	core::stringc Source;
93 	f32* Data;
94 	u32 Offset;
95 	u32 Set;
96 	u32 Stride;
97 };
98 
99 //! Collada images
100 struct SColladaImage
101 {
102 	core::stringc Id;
103 	core::stringc Source;
104 	core::dimension2du Dimension;
105 	bool SourceIsFilename;
106 };
107 
108 
109 //! Collada texture
110 struct SColladaTexture
111 {
112 	video::ITexture* Texture;
113 	core::stringc Id;
114 };
115 
116 
117 //! Collada material
118 struct SColladaMaterial
119 {
120 	video::SMaterial Mat;
121 	core::stringc Id;
122 	core::stringc InstanceEffectId;
123 	f32 Transparency;
124 
125 	inline bool operator< (const SColladaMaterial & other) const
126 	{
127 		return Id < other.Id;
128 	}
129 };
130 
131 //! Collada effect (materials, shaders, and programs)
132 struct SColladaEffect
133 {
134 	core::stringc Id;
135 	f32 Transparency;
136 	core::array<core::stringc> Textures;
137 	video::SMaterial Mat;
138 	// TODO: Parameters looks somewhat lazy workaround, I think we should really read all parameters correct.
139 	io::IAttributes * Parameters;
140 
141 	inline bool operator< (const SColladaEffect & other) const
142 	{
143 		return Id < other.Id;
144 	}
145 };
146 
147 
148 struct SNumberArray // for storing float and int arrays
149 {
150 	core::stringc Name;
151 	core::array<f32> Data;
152 };
153 
154 struct SAccessor
155 {
SAccessorSAccessor156 	SAccessor()
157 		: Count(0), Offset(0), Stride(1) {}
158 	// I don't store the source of the accessor here because I assume
159 	// it to use the array of the source this accessor is located in.
160 
161 	int Count;
162 	int Offset;
163 	int Stride;
164 
165 	core::array<SColladaParam> Parameters; // parameters defining the accessor
166 };
167 
168 struct SSource
169 {
170 	core::stringc Id;
171 	SNumberArray Array;
172 	core::array<SAccessor> Accessors;
173 };
174 
175 class CScenePrefab;
176 
177 //! Meshloader capable of loading COLLADA meshes and scene descriptions into Irrlicht.
178 class CColladaFileLoader : public IMeshLoader
179 {
180 public:
181 
182 	//! Constructor
183 	CColladaFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs);
184 
185 	//! destructor
186 	virtual ~CColladaFileLoader();
187 
188 	//! returns true if the file maybe is able to be loaded by this class
189 	//! based on the file extension (e.g. ".cob")
190 	virtual bool isALoadableFileExtension(const io::path& filename) const;
191 
192 	//! creates/loads an animated mesh from the file.
193 	//! \return Pointer to the created mesh. Returns 0 if loading failed.
194 	//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
195 	//! See IReferenceCounted::drop() for more information.
196 	virtual IAnimatedMesh* createMesh(io::IReadFile* file);
197 
198 private:
199 
200 	//! skips an (unknown) section in the collada document
201 	void skipSection(io::IXMLReaderUTF8* reader, bool reportSkipping);
202 
203 	//! reads the <COLLADA> section and its content
204 	void readColladaSection(io::IXMLReaderUTF8* reader);
205 
206 	//! reads a <library> section and its content
207 	void readLibrarySection(io::IXMLReaderUTF8* reader);
208 
209 	//! reads a <visual_scene> element and stores it as a prefab
210 	void readVisualScene(io::IXMLReaderUTF8* reader);
211 
212 	//! reads a <scene> section and its content
213 	void readSceneSection(io::IXMLReaderUTF8* reader);
214 
215 	//! reads a <asset> section and its content
216 	void readAssetSection(io::IXMLReaderUTF8* reader);
217 
218 	//! reads a <node> section and its content
219 	//! if a prefab pointer is passed the nodes are created as scene prefabs children of that prefab
220 	void readNodeSection(io::IXMLReaderUTF8* reader, scene::ISceneNode* parent, CScenePrefab* p=0);
221 
222 	//! reads a <lookat> element and its content and creates a matrix from it
223 	core::matrix4 readLookAtNode(io::IXMLReaderUTF8* reader);
224 
225 	//! reads a <matrix> element and its content and creates a matrix from it
226 	core::matrix4 readMatrixNode(io::IXMLReaderUTF8* reader);
227 
228 	//! reads a <perspective> element and its content and creates a matrix from it
229 	core::matrix4 readPerspectiveNode(io::IXMLReaderUTF8* reader);
230 
231 	//! reads a <rotate> element and its content and creates a matrix from it
232 	core::matrix4 readRotateNode(io::IXMLReaderUTF8* reader);
233 
234 	//! reads a <skew> element and its content and creates a matrix from it
235 	core::matrix4 readSkewNode(io::IXMLReaderUTF8* reader);
236 
237 	//! reads a <boundingbox> element and its content and stores it in bbox
238 	void readBboxNode(io::IXMLReaderUTF8* reader, core::aabbox3df& bbox);
239 
240 	//! reads a <scale> element and its content and creates a matrix from it
241 	core::matrix4 readScaleNode(io::IXMLReaderUTF8* reader);
242 
243 	//! reads a <translate> element and its content and creates a matrix from it
244 	core::matrix4 readTranslateNode(io::IXMLReaderUTF8* reader);
245 
246 	//! reads a <color> element
247 	video::SColorf readColorNode(io::IXMLReaderUTF8* reader);
248 
249 	//! reads a <float> element
250 	f32 readFloatNode(io::IXMLReaderUTF8* reader);
251 
252 	//! reads a <instance> node
253 	void readInstanceNode(io::IXMLReaderUTF8* reader,
254 			scene::ISceneNode* parent, scene::ISceneNode** outNode,
255 			CScenePrefab* p=0, const core::stringc& type=core::stringc());
256 
257 	//! creates a scene node from Prefabs (with name given in 'url')
258 	void instantiateNode(scene::ISceneNode* parent, scene::ISceneNode** outNode=0,
259 			CScenePrefab* p=0, const core::stringc& url="",
260 			const core::stringc& type=core::stringc());
261 
262 	//! reads a <light> element and stores it as prefab
263 	void readLightPrefab(io::IXMLReaderUTF8* reader);
264 
265 	//! reads a <camera> element and stores it as prefab
266 	void readCameraPrefab(io::IXMLReaderUTF8* reader);
267 
268 	//! reads a <image> element and stores it in the image section
269 	void readImage(io::IXMLReaderUTF8* reader);
270 
271 	//! reads a <texture> element and stores it in the texture section
272 	void readTexture(io::IXMLReaderUTF8* reader);
273 
274 	//! reads a <material> element and stores it in the material section
275 	void readMaterial(io::IXMLReaderUTF8* reader);
276 
277 	//! reads a <effect> element and stores it in the effects section
278 	void readEffect(io::IXMLReaderUTF8* reader, SColladaEffect * effect = 0);
279 
280 	//! reads a <geometry> element and stores it as mesh if possible
281 	void readGeometry(io::IXMLReaderUTF8* reader);
282 
283 	//! parses a float from a char pointer and moves the pointer to
284 	//! the end of the parsed float
285 	inline f32 readFloat(const c8** p);
286 
287 	//! parses an int from a char pointer and moves the pointer to
288 	//! the end of the parsed float
289 	inline s32 readInt(const c8** p);
290 
291 	//! places pointer to next begin of a token
292 	void findNextNoneWhiteSpace(const c8** p);
293 
294 	//! reads floats from inside of xml element until end of xml element
295 	void readFloatsInsideElement(io::IXMLReaderUTF8* reader, f32* floats, u32 count);
296 
297 	//! reads ints from inside of xml element until end of xml element
298 	void readIntsInsideElement(io::IXMLReaderUTF8* reader, s32* ints, u32 count);
299 
300 	//! clears all loaded data
301 	void clearData();
302 
303 	//! parses all collada parameters inside an element and stores them in ColladaParameters
304 	void readColladaParameters(io::IXMLReaderUTF8* reader, const core::stringc& parentName);
305 
306 	//! returns a collada parameter or none if not found
307 	SColladaParam* getColladaParameter(ECOLLADA_PARAM_NAME name);
308 
309 	//! parses all collada inputs inside an element and stores them in Inputs. Reads
310 	//! until first tag which is not an input tag or the end of the parent is reached
311 	void readColladaInputs(io::IXMLReaderUTF8* reader, const core::stringc& parentName);
312 
313 	//! reads a collada input tag and adds it to the input parameter
314 	void readColladaInput(io::IXMLReaderUTF8* reader, core::array<SColladaInput>& inputs);
315 
316 	//! returns a collada input or none if not found
317 	SColladaInput* getColladaInput(ECOLLADA_INPUT_SEMANTIC input);
318 
319 	//! read Collada Id, uses id or name if id is missing
320 	core::stringc readId(io::IXMLReaderUTF8* reader);
321 
322 	//! changes the XML URI into an internal id
323 	void uriToId(core::stringc& str);
324 
325 	//! reads a polygons section and creates a mesh from it
326 	void readPolygonSection(io::IXMLReaderUTF8* reader,
327 			core::array<SSource>& sources, scene::SMesh* mesh,
328 			const core::stringc& geometryId);
329 
330 	//! finds a material, possible instancing it
331 	const SColladaMaterial * findMaterial(const core::stringc & materialName);
332 
333 	//! reads and bind materials as given by the symbol->target bind mapping
334 	void readBindMaterialSection(io::IXMLReaderUTF8* reader, const core::stringc & id);
335 
336 	//! create an Irrlicht texture from the SColladaImage
337 	video::ITexture* getTextureFromImage(core::stringc uri, SColladaEffect * effect);
338 
339 	//! read a parameter and value
340 	void readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters);
341 
342 	scene::ISceneManager* SceneManager;
343 	io::IFileSystem* FileSystem;
344 
345 	scene::IAnimatedMesh* DummyMesh;
346 	core::stringc CurrentlyLoadingMesh;
347 
348 	scene::IAnimatedMesh* FirstLoadedMesh;
349 	io::path FirstLoadedMeshName;
350 	s32 LoadedMeshCount;
351 	u32 Version;
352 	bool FlipAxis;
353 
354 	core::array<IColladaPrefab*> Prefabs;
355 	core::array<SColladaParam> ColladaParameters;
356 	core::array<SColladaImage> Images;
357 	core::array<SColladaTexture> Textures;
358 	core::array<SColladaMaterial> Materials;
359 	core::array<SColladaInput> Inputs;
360 	core::array<SColladaEffect> Effects;
361 	//! meshbuffer reference ("geomid/matname") -> index into MeshesToBind
362 	core::map<core::stringc,u32> MaterialsToBind;
363 	//! Array of buffers for each material binding
364 	core::array< core::array<irr::scene::IMeshBuffer*> > MeshesToBind;
365 
366 	bool CreateInstances;
367 };
368 
369 
370 
371 //! following class is for holding and createing instances of library objects,
372 //! named prefabs in this loader.
373 class IColladaPrefab : public virtual IReferenceCounted
374 {
375 public:
376 	//! creates an instance of this prefab
377 	virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent,
378 		scene::ISceneManager* mgr) = 0;
379 
380 	//! returns id of this prefab
381 	virtual const core::stringc& getId() = 0;
382 };
383 
384 
385 } // end namespace scene
386 } // end namespace irr
387 
388 #endif
389 
390