Properties.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. #ifndef PROPERTIES_H_
  2. #define PROPERTIES_H_
  3. #include "Base.h"
  4. #include "Matrix.h"
  5. #include "Vector2.h"
  6. namespace gameplay
  7. {
  8. /**
  9. * Defines a utility for loading text files in the GamePlay "properties" files
  10. * and reading primitive types and GamePlay math classes out of them.
  11. *
  12. * This class is used by ParticleEmitter, Animation and Materials to create objects
  13. * of these types from text files.
  14. *
  15. * A properties file has very simple syntax and can contain only namespaces and
  16. * name/value pairs (the properties of a namespace).
  17. * The file can have any file extension a user specifies.
  18. *
  19. * Here's an example of a simple
  20. * file that uses all the available features of the markup language:
  21. @verbatim
  22. // This is a comment.
  23. // This property is in the default namespace:
  24. integerProperty = 5
  25. // This line defines a namespace of type "mynamespace" without an ID:
  26. mynamespace
  27. {
  28. // This namespace can be retrieved by searching for its ID, "spriteTexture",
  29. // or by its name "texture":
  30. texture spriteTexture
  31. {
  32. fileName = sprite.png
  33. width = 64
  34. height = 64
  35. }
  36. // This property is in the "space" namespace:
  37. booleanProperty = true
  38. // It's legal to have a name without a value if you leave out the '=' character:
  39. foo
  40. // In fact, the '=' character is optional if you'd rather write:
  41. bar 23
  42. // But don't write this or you'll get an error:
  43. // illegalProperty =
  44. // Or this:
  45. // = 15
  46. // Properties objects let you retrieve values as various types.
  47. floatProperty = 3.333
  48. stringProperty = This is a string.
  49. vector3Property = 1.0, 5.0, 3.55
  50. colorProperty = 1.0, 0.4, 0.0, 1.0
  51. }
  52. @endverbatim
  53. * Retrieving information out of a file like this could be done in two ways. If the
  54. * available namespaces and name/value pairs are known in advance they can be queried by ID or name.
  55. * For example, if the namespace "spriteTexture" and its properties are required then they can
  56. * be retrieved with a call to getNamespace() followed by calls to getString() and getInt().
  57. * A namespace is stored and retrieved as a Properties object.
  58. * Reading the spriteTexture properties out of the file above in this way could be done with the following code:
  59. @verbatim
  60. // Create the top-level Properties object.
  61. Properties* properties = Properties::create("example.properties");
  62. // Retrieve the "spriteTexture" namespace.
  63. Properties* spriteTexture = properties->getNamespace("spriteTexture");
  64. // Get the values of known texture properties out of the namespace.
  65. const char* fileName = spriteTexture->getString("fileName");
  66. int width = spriteTexture->getInt("width");
  67. int height = spriteTexture->getInt("height");
  68. // Deleting the top-level Properties object will clean up all nested namespaces.
  69. SAFE_DELETE(properties);
  70. @endverbatim
  71. * On the other hand, if the structure of the file is not known in advance its
  72. * namespaces and name/value pairs can be retrieved one by one using the getNextNamespace()
  73. * and getNextProperty() methods. The following method prints the contents of any properties file
  74. * to the console:
  75. @verbatim
  76. void printProperties(Properties* properties)
  77. {
  78. // Print the name and ID of the current namespace.
  79. const char* spacename = properties->getNamespace();
  80. const char* id = properties->getId();
  81. GP_WARN("Namespace: %s ID: %s\n{", spacename, id);
  82. // Print all properties in this namespace.
  83. const char* name = properties->getNextProperty();
  84. const char* value = NULL;
  85. while (name != NULL)
  86. {
  87. value = properties->getString(name);
  88. GP_WARN("%s = %s", name, value);
  89. name = properties->getNextProperty();
  90. }
  91. GP_WARN("}\n");
  92. // Print the properties of every namespace within this one.
  93. Properties* space = properties->getNextNamespace();
  94. while (space != NULL)
  95. {
  96. printProperties(space);
  97. space = properties->getNextNamespace();
  98. }
  99. }
  100. @endverbatim
  101. * Note that this method does not keep track of the namespace hierarchy, but could be
  102. * modified to do so. Also note that nothing in a properties file indicates the type
  103. * of a property. If the type is unknown, its string can be retrieved and interpreted
  104. * as necessary.
  105. */
  106. class Properties
  107. {
  108. friend class Game;
  109. public:
  110. /**
  111. * Data types supported by the properties class.
  112. */
  113. enum Type
  114. {
  115. NONE,
  116. STRING,
  117. NUMBER,
  118. VECTOR2,
  119. VECTOR3,
  120. VECTOR4,
  121. MATRIX
  122. };
  123. /**
  124. * Creates a Properties runtime settings from the specified URL, where the URL is of
  125. * the format "<file-path>.<extension>#<namespace-id>/<namespace-id>/.../<namespace-id>"
  126. * (and "#<namespace-id>/<namespace-id>/.../<namespace-id>" is optional).
  127. *
  128. * @param url The URL to create the properties from.
  129. */
  130. static Properties* create(const char* url);
  131. /**
  132. * Destructor.
  133. */
  134. ~Properties();
  135. /**
  136. * Get the name of the next property.
  137. *
  138. * @param value Optional pointer to a const char* to store the value of the next property in.
  139. *
  140. * @return The name of the next property, or NULL if there are no properties remaining.
  141. */
  142. const char* getNextProperty(char** value = NULL);
  143. /**
  144. * Get the next namespace.
  145. */
  146. Properties* getNextNamespace();
  147. /**
  148. * Rewind the getNextProperty() and getNextNamespace() iterators
  149. * to the beginning of the file.
  150. */
  151. void rewind();
  152. /**
  153. * Get a specific namespace by ID or name. This method will perform
  154. * a depth-first search on all namespaces and inner namespaces within
  155. * this Property.
  156. *
  157. * @param id The ID or name of the namespace to find.
  158. * @param searchNames If true, namespace names are used in the search,
  159. * instead of namespace IDs. By default this parameter is false
  160. * and namespace IDs are searched.
  161. *
  162. * @return A properties object with the given ID or name.
  163. */
  164. Properties* getNamespace(const char* id, bool searchNames = false) const;
  165. /**
  166. * Get the name of this Property's namespace.
  167. *
  168. * @return The name of this Property's namespace.
  169. */
  170. const char* getNamespace() const;
  171. /**
  172. * Get the ID of this Property's namespace. The ID should be a unique identifier,
  173. * but its uniqueness is not enforced.
  174. *
  175. * @return The ID of this Property's namespace.
  176. */
  177. const char* getId() const;
  178. /**
  179. * Check if a property with the given name is specified in this Properties object.
  180. *
  181. * @param name The name of the property to query.
  182. *
  183. * @return True if the property exists, false otherwise.
  184. */
  185. bool exists(const char* name) const;
  186. /**
  187. * Returns the type of a property.
  188. *
  189. * @param name The name of hte property to interpret, or NULL to return the current property's type.
  190. *
  191. * @return The type of the property.
  192. */
  193. Type getType(const char* name = NULL) const;
  194. /**
  195. * Get the value of the given property as a string. This can always be retrieved,
  196. * whatever the intended type of the property.
  197. *
  198. * @param name The name of the property to interpret, or NULL to return the current property's value.
  199. *
  200. * @return The value of the given property as a string, or the empty string if no property with that name exists.
  201. */
  202. const char* getString(const char* name = NULL) const;
  203. /**
  204. * Interpret the value of the given property as a boolean.
  205. *
  206. * @param name The name of the property to interpret, or NULL to return the current property's value.
  207. *
  208. * @return true if the property exists and its value is "true", otherwise false.
  209. */
  210. bool getBool(const char* name = NULL) const;
  211. /**
  212. * Interpret the value of the given property as an integer.
  213. * If the property does not exist, zero will be returned.
  214. * If the property exists but could not be scanned, an error will be logged and zero will be returned.
  215. *
  216. * @param name The name of the property to interpret, or NULL to return the current property's value.
  217. *
  218. * @return The value of the given property interpreted as an integer.
  219. * Zero if the property does not exist or could not be scanned.
  220. */
  221. int getInt(const char* name = NULL) const;
  222. /**
  223. * Interpret the value of the given property as a floating-point number.
  224. * If the property does not exist, zero will be returned.
  225. * If the property exists but could not be scanned, an error will be logged and zero will be returned.
  226. *
  227. * @param name The name of the property to interpret, or NULL to return the current property's value.
  228. *
  229. * @return The value of the given property interpreted as a float.
  230. * Zero if the property does not exist or could not be scanned.
  231. */
  232. float getFloat(const char* name = NULL) const;
  233. /**
  234. * Interpret the value of the given property as a long integer.
  235. * If the property does not exist, zero will be returned.
  236. * If the property exists but could not be scanned, an error will be logged and zero will be returned.
  237. *
  238. * @param name The name of the property to interpret, or NULL to return the current property's value.
  239. *
  240. * @return The value of the given property interpreted as a long.
  241. * Zero if the property does not exist or could not be scanned.
  242. */
  243. long getLong(const char* name = NULL) const;
  244. /**
  245. * Interpret the value of the given property as a Matrix.
  246. * If the property does not exist, out will be set to the identity matrix.
  247. * If the property exists but could not be scanned, an error will be logged and out will be set
  248. * to the identity matrix.
  249. *
  250. * @param name The name of the property to interpret, or NULL to return the current property's value.
  251. * @param out The matrix to set to this property's interpreted value.
  252. *
  253. * @return True on success, false if the property does not exist or could not be scanned.
  254. */
  255. bool getMatrix(const char* name, Matrix* out) const;
  256. /**
  257. * Interpret the value of the given property as a Vector2.
  258. * If the property does not exist, out will be set to Vector2(0.0f, 0.0f).
  259. * If the property exists but could not be scanned, an error will be logged and out will be set
  260. * to Vector2(0.0f, 0.0f).
  261. *
  262. * @param name The name of the property to interpret, or NULL to return the current property's value.
  263. * @param out The vector to set to this property's interpreted value.
  264. *
  265. * @return True on success, false if the property does not exist or could not be scanned.
  266. */
  267. bool getVector2(const char* name, Vector2* out) const;
  268. /**
  269. * Interpret the value of the given property as a Vector3.
  270. * If the property does not exist, out will be set to Vector3(0.0f, 0.0f, 0.0f).
  271. * If the property exists but could not be scanned, an error will be logged and out will be set
  272. * to Vector3(0.0f, 0.0f, 0.0f).
  273. *
  274. * @param name The name of the property to interpret, or NULL to return the current property's value.
  275. * @param out The vector to set to this property's interpreted value.
  276. *
  277. * @return True on success, false if the property does not exist or could not be scanned.
  278. */
  279. bool getVector3(const char* name, Vector3* out) const;
  280. /**
  281. * Interpret the value of the given property as a Vector4.
  282. * If the property does not exist, out will be set to Vector4(0.0f, 0.0f, 0.0f, 0.0f).
  283. * If the property exists but could not be scanned, an error will be logged and out will be set
  284. * to Vector4(0.0f, 0.0f, 0.0f, 0.0f).
  285. *
  286. * @param name The name of the property to interpret, or NULL to return the current property's value.
  287. * @param out The vector to set to this property's interpreted value.
  288. *
  289. * @return True on success, false if the property does not exist or could not be scanned.
  290. */
  291. bool getVector4(const char* name, Vector4* out) const;
  292. /**
  293. * Interpret the value of the given property as a Quaternion specified as an axis angle.
  294. * If the property does not exist, out will be set to Quaternion().
  295. * If the property exists but could not be scanned, an error will be logged and out will be set
  296. * to Quaternion().
  297. *
  298. * @param name The name of the property to interpret, or NULL to return the current property's value.
  299. * @param out The quaternion to set to this property's interpreted value.
  300. *
  301. * @return True on success, false if the property does not exist or could not be scanned.
  302. */
  303. bool getQuaternionFromAxisAngle(const char* name, Quaternion* out) const;
  304. /**
  305. * Interpret the value of the given property as an RGB color in hex and write this color to a Vector3.
  306. * E.g. 0xff0000 represents red and sets the vector to (1, 0, 0).
  307. * If the property does not exist, out will be set to Vector3(0.0f, 0.0f, 0.0f).
  308. * If the property exists but could not be scanned, an error will be logged and out will be set
  309. * to Vector3(0.0f, 0.0f, 0.0f).
  310. *
  311. * @param name The name of the property to interpret, or NULL to return the current property's value.
  312. * @param out The vector to set to this property's interpreted value.
  313. *
  314. * @return True on success, false if the property does not exist or could not be scanned.
  315. */
  316. bool getColor(const char* name, Vector3* out) const;
  317. /**
  318. * Interpret the value of the given property as an RGBA color in hex and write this color to a Vector4.
  319. * E.g. 0xff0000ff represents opaque red and sets the vector to (1, 0, 0, 1).
  320. * If the property does not exist, out will be set to Vector4(0.0f, 0.0f, 0.0f, 0.0f).
  321. * If the property exists but could not be scanned, an error will be logged and out will be set
  322. * to Vector4(0.0f, 0.0f, 0.0f, 0.0f).
  323. *
  324. * @param name The name of the property to interpret, or NULL to return the current property's value.
  325. * @param out The vector to set to this property's interpreted value.
  326. *
  327. * @return True on success, false if the property does not exist or could not be scanned.
  328. */
  329. bool getColor(const char* name, Vector4* out) const;
  330. private:
  331. /**
  332. * Constructors.
  333. */
  334. Properties();
  335. Properties(FILE* file);
  336. Properties(const Properties& copy);
  337. /**
  338. * Constructor. Read from the beginning of namespace specified
  339. */
  340. Properties(FILE* file, const char* name, const char* id = NULL, const char* parentID = NULL);
  341. void readProperties(FILE* file);
  342. void skipWhiteSpace(FILE* file);
  343. char* trimWhiteSpace(char* str);
  344. // Called after create(); copies info from parents into derived namespaces.
  345. void resolveInheritance(const char* id = NULL);
  346. // Called by resolveInheritance().
  347. void mergeWith(Properties* overrides);
  348. // Clones the Properties object.
  349. Properties* clone();
  350. std::string _namespace;
  351. std::string _id;
  352. std::string _parentID;
  353. std::map<std::string, std::string> _properties;
  354. std::map<std::string, std::string>::const_iterator _propertiesItr;
  355. std::vector<Properties*> _namespaces;
  356. std::vector<Properties*>::const_iterator _namespacesItr;
  357. };
  358. }
  359. #endif