IColladaMeshWriter.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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. #ifndef __IRR_I_COLLADA_MESH_WRITER_H_INCLUDED__
  5. #define __IRR_I_COLLADA_MESH_WRITER_H_INCLUDED__
  6. #include "IMeshWriter.h"
  7. #include "ISceneNode.h"
  8. #include "IAnimatedMesh.h"
  9. #include "SMaterial.h"
  10. namespace irr
  11. {
  12. namespace io
  13. {
  14. class IWriteFile;
  15. } // end namespace io
  16. namespace scene
  17. {
  18. //! Lighting models - more or less the way Collada categorizes materials
  19. enum E_COLLADA_TECHNIQUE_FX
  20. {
  21. //! Blinn-phong which is default for opengl and dx fixed function pipelines.
  22. //! But several well-known renderers don't support it and prefer phong.
  23. ECTF_BLINN,
  24. //! Phong shading, default in many external renderers.
  25. ECTF_PHONG,
  26. //! diffuse shaded surface that is independent of lighting.
  27. ECTF_LAMBERT,
  28. // constantly shaded surface that is independent of lighting.
  29. ECTF_CONSTANT
  30. };
  31. //! How to interpret the opacity in collada
  32. enum E_COLLADA_TRANSPARENT_FX
  33. {
  34. //! default - only alpha channel of color or texture is used.
  35. ECOF_A_ONE = 0,
  36. //! Alpha values for each RGB channel of color or texture are used.
  37. ECOF_RGB_ZERO = 1
  38. };
  39. //! Color names collada uses in it's color samplers
  40. enum E_COLLADA_COLOR_SAMPLER
  41. {
  42. ECCS_DIFFUSE,
  43. ECCS_AMBIENT,
  44. ECCS_EMISSIVE,
  45. ECCS_SPECULAR,
  46. ECCS_TRANSPARENT,
  47. ECCS_REFLECTIVE
  48. };
  49. //! Irrlicht colors which can be mapped to E_COLLADA_COLOR_SAMPLER values
  50. enum E_COLLADA_IRR_COLOR
  51. {
  52. //! Don't write this element at all
  53. ECIC_NONE,
  54. //! Check IColladaMeshWriterProperties for custom color
  55. ECIC_CUSTOM,
  56. //! Use SMaterial::DiffuseColor
  57. ECIC_DIFFUSE,
  58. //! Use SMaterial::AmbientColor
  59. ECIC_AMBIENT,
  60. //! Use SMaterial::EmissiveColor
  61. ECIC_EMISSIVE,
  62. //! Use SMaterial::SpecularColor
  63. ECIC_SPECULAR
  64. };
  65. //! Control when geometry elements are created
  66. enum E_COLLADA_GEOMETRY_WRITING
  67. {
  68. //! Default - write each mesh exactly once to collada. Optimal but will not work with many tools.
  69. ECGI_PER_MESH,
  70. //! Write each mesh as often as it's used with different materials-names in the scene.
  71. //! Material names which are used here are created on export, so using the IColladaMeshWriterNames
  72. //! interface you have some control over how many geometries are written.
  73. ECGI_PER_MESH_AND_MATERIAL
  74. };
  75. //! Callback interface for properties which can be used to influence collada writing
  76. class IColladaMeshWriterProperties : public virtual IReferenceCounted
  77. {
  78. public:
  79. virtual ~IColladaMeshWriterProperties () {}
  80. //! Which lighting model should be used in the technique (FX) section when exporting effects (materials)
  81. virtual E_COLLADA_TECHNIQUE_FX getTechniqueFx(const video::SMaterial& material) const = 0;
  82. //! Which texture index should be used when writing the texture of the given sampler color.
  83. /** \return the index to the texture-layer or -1 if that texture should never be exported
  84. Note: for ECCS_TRANSPARENT by default the alpha channel is used, if you want to use RGB you have to set
  85. also the ECOF_RGB_ZERO flag in getTransparentFx. */
  86. virtual s32 getTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const = 0;
  87. //! Return which color from Irrlicht should be used for the color requested by collada
  88. /** Note that collada allows exporting either texture or color, not both.
  89. So color mapping is only checked if we have no valid texture already.
  90. By default we try to return best fits when possible. For example ECCS_DIFFUSE is mapped to ECIC_DIFFUSE.
  91. When ECIC_CUSTOM is returned then the result of getCustomColor will be used. */
  92. virtual E_COLLADA_IRR_COLOR getColorMapping(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const = 0;
  93. //! Return custom colors for certain color types requested by collada.
  94. /** Only used when getColorMapping returns ECIC_CUSTOM for the same parameters. */
  95. virtual video::SColor getCustomColor(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const = 0;
  96. //! Return the transparence color interpretation.
  97. /** Not this is only about ECCS_TRANSPARENT and does not affect getTransparency. */
  98. virtual E_COLLADA_TRANSPARENT_FX getTransparentFx(const video::SMaterial& material) const = 0;
  99. //! Transparency value for that material.
  100. /** This value is additional to transparent settings, if both are set they will be multiplicated.
  101. \return 1.0 for fully transparent, 0.0 for not transparent and not written at all when < 0.f */
  102. virtual f32 getTransparency(const video::SMaterial& material) const = 0;
  103. //! Reflectivity value for that material
  104. /** The amount of perfect mirror reflection to be added to the reflected light
  105. \return 0.0 - 1.0 for reflectivity and element is not written at all when < 0.f */
  106. virtual f32 getReflectivity(const video::SMaterial& material) const = 0;
  107. //! Return index of refraction for that material
  108. /** By default we don't write that.
  109. \return a value greater equal 0.f to write \<index_of_refraction\> when it is lesser than 0 nothing will be written */
  110. virtual f32 getIndexOfRefraction(const video::SMaterial& material) const = 0;
  111. //! Should node be used in scene export? (only needed for scene-writing, ignored in mesh-writing)
  112. //! By default all visible nodes are exported.
  113. virtual bool isExportable(const irr::scene::ISceneNode * node) const = 0;
  114. //! Return the mesh for the given node. If it has no mesh or shouldn't export it's mesh
  115. //! you can return 0 in which case only the transformation matrix of the node will be used.
  116. // TODO: Function is not const because there is no const getMesh() function for several Irrlicht nodes.
  117. virtual IMesh* getMesh(irr::scene::ISceneNode * node) = 0;
  118. //! Return if the node has it's own material overwriting the mesh-materials
  119. /** Usually true except for mesh-nodes which have isReadOnlyMaterials set.
  120. This is mostly important for naming (as ISceneNode::getMaterial() already returns the correct material).
  121. You have to override it when exporting custom scenenodes with own materials.
  122. \return true => The node's own material is used, false => ignore node material and use the one from the mesh */
  123. virtual bool useNodeMaterial(const scene::ISceneNode* node) const = 0;
  124. };
  125. //! Callback interface to use custom names on collada writing.
  126. /** You can either modify names and id's written to collada or you can use
  127. this interface to just find out which names are used on writing.
  128. Names are often used later as xs:anyURI, so avoid whitespace, '#' and '%' in the names.
  129. */
  130. class IColladaMeshWriterNames : public virtual IReferenceCounted
  131. {
  132. public:
  133. virtual ~IColladaMeshWriterNames () {}
  134. //! Return a unique name for the given mesh
  135. /** Note that names really must be unique here per mesh-pointer, so
  136. mostly it's a good idea to return the nameForMesh from
  137. IColladaMeshWriter::getDefaultNameGenerator(). Also names must follow
  138. the xs:NCName standard to be valid, you can run them through
  139. IColladaMeshWriter::toNCName to ensure that.
  140. \param mesh Pointer to the mesh which needs a name
  141. \param instance When E_COLLADA_GEOMETRY_WRITING is not ECGI_PER_MESH then
  142. several instances of the same mesh can be written and this counts them.
  143. */
  144. virtual irr::core::stringc nameForMesh(const scene::IMesh* mesh, int instance) = 0;
  145. //! Return a unique name for the given node
  146. /** Note that names really must be unique here per node-pointer, so
  147. mostly it's a good idea to return the nameForNode from
  148. IColladaMeshWriter::getDefaultNameGenerator(). Also names must follow
  149. the xs:NCName standard to be valid, you can run them through
  150. IColladaMeshWriter::toNCName to ensure that.
  151. */
  152. virtual irr::core::stringc nameForNode(const scene::ISceneNode* node) = 0;
  153. //! Return a name for the material
  154. /** There is one material created in the writer for each unique name.
  155. So you can use this to control the number of materials which get written.
  156. For example Irrlicht does by default write one material for each material
  157. instanced by a node. So if you know that in your application material
  158. instances per node are identical between different nodes you can reduce
  159. the number of exported materials using that knowledge by using identical
  160. names for such shared materials.
  161. Names must follow the xs:NCName standard to be valid, you can run them
  162. through IColladaMeshWriter::toNCName to ensure that.
  163. */
  164. virtual irr::core::stringc nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) = 0;
  165. };
  166. //! Interface for writing meshes
  167. class IColladaMeshWriter : public IMeshWriter
  168. {
  169. public:
  170. IColladaMeshWriter()
  171. : Properties(0), DefaultProperties(0), NameGenerator(0), DefaultNameGenerator(0)
  172. , WriteTextures(true), WriteDefaultScene(true), ExportSMaterialOnce(true)
  173. , AmbientLight(0.f, 0.f, 0.f, 1.f)
  174. , UnitMeter(1.f), UnitName("meter")
  175. , GeometryWriting(ECGI_PER_MESH)
  176. {
  177. ParamNamesUV[0] = "U";
  178. ParamNamesUV[1] = "V";
  179. }
  180. //! Destructor
  181. virtual ~IColladaMeshWriter()
  182. {
  183. if ( Properties )
  184. Properties->drop();
  185. if ( DefaultProperties )
  186. DefaultProperties->drop();
  187. if ( NameGenerator )
  188. NameGenerator->drop();
  189. if ( DefaultNameGenerator )
  190. DefaultNameGenerator->drop();
  191. }
  192. //! writes a scene starting with the given node
  193. //\param writeRoot: 0 = no, 1=yes unless root is scenemanager, 2=yes
  194. virtual bool writeScene(io::IWriteFile* file, scene::ISceneNode* root, int writeRoot=1) = 0;
  195. //! Set if texture information should be written
  196. virtual void setWriteTextures(bool write)
  197. {
  198. WriteTextures = write;
  199. }
  200. //! Get if texture information should be written
  201. virtual bool getWriteTextures() const
  202. {
  203. return WriteTextures;
  204. }
  205. //! Set if a default scene should be written when writing meshes.
  206. /** Many collada readers fail to read a mesh if the collada files doesn't contain a scene as well.
  207. The scene is doing an instantiation of the mesh.
  208. When using writeScene this flag is ignored (as we have scene there already)
  209. */
  210. virtual void setWriteDefaultScene(bool write)
  211. {
  212. WriteDefaultScene = write;
  213. }
  214. //! Get if a default scene should be written
  215. virtual bool getWriteDefaultScene() const
  216. {
  217. return WriteDefaultScene;
  218. }
  219. //! Sets ambient color of the scene to write
  220. virtual void setAmbientLight(const video::SColorf &ambientColor)
  221. {
  222. AmbientLight = ambientColor;
  223. }
  224. //! Return ambient light of the scene which is written
  225. virtual video::SColorf getAmbientLight() const
  226. {
  227. return AmbientLight;
  228. }
  229. //! Set the unit distances for all elements and objects
  230. /**
  231. \param meter: Real-world meters to use per unit. Default 1 unit = 1 meter. For 1 unit = 1cm you would set to 0.01
  232. \param name: Name to use for distance unit. Default is "meter". */
  233. virtual void setUnit(irr::f32 meter, const irr::core::stringc& name)
  234. {
  235. UnitMeter = meter;
  236. UnitName = name;
  237. }
  238. //! Return real world meters to use per unit for all elements and objects
  239. virtual irr::f32 getUnitMeter() const
  240. {
  241. return UnitMeter;
  242. }
  243. //! Return name to use for distance units. Like p.E. "meter".
  244. virtual irr::core::stringc getUnitName() const
  245. {
  246. return UnitName;
  247. }
  248. //! Control when and how often a mesh is written
  249. /** Optimally ECGI_PER_MESH would be always sufficient - writing geometry once per mesh.
  250. Unfortunately many tools (at the time of writing this nearly all of them) have trouble
  251. on import when different materials are used per node. So when you override materials
  252. per node and importing the resulting collada has materials problems in other tools try
  253. using other values here.
  254. \param writeStyle One of the E_COLLADA_GEOMETRY_WRITING settings.
  255. */
  256. virtual void setGeometryWriting(E_COLLADA_GEOMETRY_WRITING writeStyle)
  257. {
  258. GeometryWriting = writeStyle;
  259. }
  260. //! Get the current style of geometry writing.
  261. virtual E_COLLADA_GEOMETRY_WRITING getGeometryWriting() const
  262. {
  263. return GeometryWriting;
  264. }
  265. //! Make certain there is only one collada material generated per Irrlicht material
  266. /** Checks before creating a collada material-name if an identical
  267. irr:::video::SMaterial has been exported already. If so don't export it with
  268. another name. This is set by default and leads to way smaller .dae files.
  269. Note that if you need to disable this flag for some reason you can still
  270. get a similar effect using the IColladaMeshWriterNames::nameForMaterial
  271. by returning identical names for identical materials there.
  272. */
  273. virtual void setExportSMaterialsOnlyOnce(bool exportOnce)
  274. {
  275. ExportSMaterialOnce = exportOnce;
  276. }
  277. virtual bool getExportSMaterialsOnlyOnce() const
  278. {
  279. return ExportSMaterialOnce;
  280. }
  281. //! Set properties to use by the meshwriter instead of it's default properties.
  282. /** Overloading properties with an own class allows modifying the writing process in certain ways.
  283. By default properties are set to the DefaultProperties. */
  284. virtual void setProperties(IColladaMeshWriterProperties * p)
  285. {
  286. if ( p == Properties )
  287. return;
  288. if ( p )
  289. p->grab();
  290. if ( Properties )
  291. Properties->drop();
  292. Properties = p;
  293. }
  294. //! Get properties which are currently used.
  295. virtual IColladaMeshWriterProperties * getProperties() const
  296. {
  297. return Properties;
  298. }
  299. //! Return the original default properties of the writer.
  300. /** You can use this pointer in your own properties to access and return default values. */
  301. IColladaMeshWriterProperties * getDefaultProperties() const
  302. {
  303. return DefaultProperties;
  304. }
  305. //! Install a generator to create custom names on export.
  306. virtual void setNameGenerator(IColladaMeshWriterNames * nameGenerator)
  307. {
  308. if ( nameGenerator == NameGenerator )
  309. return;
  310. if ( nameGenerator )
  311. nameGenerator->grab();
  312. if ( NameGenerator )
  313. NameGenerator->drop();
  314. NameGenerator = nameGenerator;
  315. }
  316. //! Get currently used name generator
  317. virtual IColladaMeshWriterNames * getNameGenerator() const
  318. {
  319. return NameGenerator;
  320. }
  321. //! Return the original default name generator of the writer.
  322. /** You can use this pointer in your own generator to access and return default values. */
  323. IColladaMeshWriterNames * getDefaultNameGenerator() const
  324. {
  325. return DefaultNameGenerator;
  326. }
  327. //! Restrict the characters of oldString a set of allowed characters in xs:NCName and add the prefix.
  328. /** A tool function to help when using a custom name generator to generative valid names for collada names and id's. */
  329. virtual irr::core::stringc toNCName(const irr::core::stringc& oldString, const irr::core::stringc& prefix=irr::core::stringc("_NC_")) const = 0;
  330. //! After export you can find out which name had been used for writing the geometry for this node.
  331. /** The name comes from IColladaMeshWriterNames::nameForMesh, but you can't access the node there.
  332. \return Either a pointer to the name or NULL */
  333. // TODO: Function is not const because there is no const getMesh() function for several Irrlicht nodes.
  334. virtual const irr::core::stringc* findGeometryNameForNode(ISceneNode* node) = 0;
  335. //! Change param name used for UV's.
  336. /** Param names for UV's have a name. By default it's "U" and "V".
  337. Usually it doesn't matter as names are optional in Collada anyway.
  338. But unfortunately some tools insist on specific names.
  339. So if "U", "V" does not work then try to export by setting this to "S", "T".
  340. One tool which insists on "S", "T" is for example SketchUp.
  341. */
  342. void SetParamNamesUV(const core::stringc& u, const core::stringc& v)
  343. {
  344. ParamNamesUV[0] = u;
  345. ParamNamesUV[1] = v;
  346. }
  347. protected:
  348. // NOTE: You usually should also call setProperties with the same parameter when using setDefaultProperties
  349. virtual void setDefaultProperties(IColladaMeshWriterProperties * p)
  350. {
  351. if ( p == DefaultProperties )
  352. return;
  353. if ( p )
  354. p->grab();
  355. if ( DefaultProperties )
  356. DefaultProperties->drop();
  357. DefaultProperties = p;
  358. }
  359. // NOTE: You usually should also call setNameGenerator with the same parameter when using setDefaultProperties
  360. virtual void setDefaultNameGenerator(IColladaMeshWriterNames * p)
  361. {
  362. if ( p == DefaultNameGenerator )
  363. return;
  364. if ( p )
  365. p->grab();
  366. if ( DefaultNameGenerator )
  367. DefaultNameGenerator->drop();
  368. DefaultNameGenerator = p;
  369. }
  370. protected:
  371. irr::core::stringc ParamNamesUV[2];
  372. private:
  373. IColladaMeshWriterProperties * Properties;
  374. IColladaMeshWriterProperties * DefaultProperties;
  375. IColladaMeshWriterNames * NameGenerator;
  376. IColladaMeshWriterNames * DefaultNameGenerator;
  377. bool WriteTextures;
  378. bool WriteDefaultScene;
  379. bool ExportSMaterialOnce;
  380. video::SColorf AmbientLight;
  381. irr::f32 UnitMeter;
  382. irr::core::stringc UnitName;
  383. E_COLLADA_GEOMETRY_WRITING GeometryWriting;
  384. };
  385. } // end namespace
  386. } // end namespace
  387. #endif