ImageAsset.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. #pragma once
  2. //-----------------------------------------------------------------------------
  3. // Copyright (c) 2013 GarageGames, LLC
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to
  7. // deal in the Software without restriction, including without limitation the
  8. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9. // sell copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. // IN THE SOFTWARE.
  22. //-----------------------------------------------------------------------------
  23. #pragma once
  24. #ifndef _ASSET_BASE_H_
  25. #include "assets/assetBase.h"
  26. #endif
  27. #ifndef _ASSET_DEFINITION_H_
  28. #include "assets/assetDefinition.h"
  29. #endif
  30. #ifndef _STRINGUNIT_H_
  31. #include "string/stringUnit.h"
  32. #endif
  33. #ifndef _ASSET_FIELD_TYPES_H_
  34. #include "assets/assetFieldTypes.h"
  35. #endif
  36. #ifndef _ASSET_PTR_H_
  37. #include "assets/assetPtr.h"
  38. #endif
  39. #include "gfx/bitmap/gBitmap.h"
  40. #include "gfx/gfxTextureHandle.h"
  41. #include "sim/netConnection.h"
  42. #include <string>
  43. #include "assetMacroHelpers.h"
  44. #include "gfx/gfxDevice.h"
  45. //-----------------------------------------------------------------------------
  46. class ImageAsset : public AssetBase
  47. {
  48. typedef AssetBase Parent;
  49. typedef AssetPtr<ImageAsset> ConcreteAssetPtr;
  50. public:
  51. /// The different types of image use cases
  52. enum ImageTypes
  53. {
  54. Albedo = 0,
  55. Normal = 1,
  56. ORMConfig = 2,
  57. GUI = 3,
  58. Roughness = 4,
  59. AO = 5,
  60. Metalness = 6,
  61. Glow = 7,
  62. Particle = 8,
  63. Decal = 9,
  64. Cubemap = 10,
  65. ImageTypeCount = 11
  66. };
  67. static StringTableEntry smNoImageAssetFallback;
  68. enum ImageAssetErrCode
  69. {
  70. TooManyMips = AssetErrCode::Extended,
  71. Extended
  72. };
  73. static const String mErrCodeStrings[U32(ImageAssetErrCode::Extended) - U32(Parent::Extended) + 1];
  74. static U32 getAssetErrCode(ConcreteAssetPtr checkAsset) { if (checkAsset) return checkAsset->mLoadedState; else return 0; }
  75. static String getAssetErrstrn(U32 errCode)
  76. {
  77. if (errCode < Parent::Extended) return Parent::getAssetErrstrn(errCode);
  78. if (errCode > ImageAssetErrCode::Extended) return "undefined error";
  79. return mErrCodeStrings[errCode - Parent::Extended];
  80. };
  81. protected:
  82. StringTableEntry mImageFileName;
  83. StringTableEntry mImagePath;
  84. bool mIsValidImage;
  85. bool mUseMips;
  86. bool mIsHDRImage;
  87. ImageTypes mImageType;
  88. HashMap<GFXTextureProfile*, GFXTexHandle> mResourceMap;
  89. typedef Signal<void()> ImageAssetChanged;
  90. ImageAssetChanged mChangeSignal;
  91. typedef Signal<void(S32 index)> ImageAssetArrayChanged;
  92. ImageAssetArrayChanged mChangeArraySignal;
  93. public:
  94. ImageAsset();
  95. virtual ~ImageAsset();
  96. /// Set up some global script interface stuff.
  97. static void consoleInit();
  98. /// Engine.
  99. static void initPersistFields();
  100. void copyTo(SimObject* object) override;
  101. /// Declare Console Object.
  102. DECLARE_CONOBJECT(ImageAsset);
  103. void _onResourceChanged(const Torque::Path& path);
  104. ImageAssetChanged& getChangedSignal() { return mChangeSignal; }
  105. ImageAssetArrayChanged& getChangedArraySignal() { return mChangeArraySignal; }
  106. void setImageFileName(StringTableEntry pScriptFile);
  107. inline StringTableEntry getImageFileName(void) const { return mImageFileName; };
  108. inline StringTableEntry getImagePath(void) const { return mImagePath; };
  109. bool isValid() { return mIsValidImage; }
  110. GFXTexHandle getTexture(GFXTextureProfile* requestedProfile);
  111. StringTableEntry getImageInfo();
  112. static StringTableEntry getImageTypeNameFromType(ImageTypes type);
  113. static ImageTypes getImageTypeFromName(StringTableEntry name);
  114. void setImageType(ImageTypes type) { mImageType = type; }
  115. ImageTypes getImageType() { return mImageType; }
  116. static U32 getAssetByFilename(StringTableEntry fileName, AssetPtr<ImageAsset>* imageAsset);
  117. static StringTableEntry getAssetIdByFilename(StringTableEntry fileName);
  118. static U32 getAssetById(StringTableEntry assetId, AssetPtr<ImageAsset>* imageAsset);
  119. static U32 getAssetById(String assetId, AssetPtr<ImageAsset>* imageAsset) { return getAssetById(assetId.c_str(), imageAsset); };
  120. U32 load() override;
  121. protected:
  122. void initializeAsset(void) override;
  123. void onAssetRefresh(void) override;
  124. static bool setImageFileName(void* obj, StringTableEntry index, StringTableEntry data) { static_cast<ImageAsset*>(obj)->setImageFileName(data); return false; }
  125. static StringTableEntry getImageFileName(void* obj, StringTableEntry data) { return static_cast<ImageAsset*>(obj)->getImageFileName(); }
  126. };
  127. DefineConsoleType(TypeImageAssetPtr, ImageAsset)
  128. DefineConsoleType(TypeImageAssetId, String)
  129. typedef ImageAsset::ImageTypes ImageAssetType;
  130. DefineEnumType(ImageAssetType);
  131. #pragma region Singular Asset Macros
  132. //Singular assets
  133. /// <Summary>
  134. /// Declares an image asset
  135. /// This establishes the assetId, asset and legacy filepath fields, along with supplemental getter and setter functions
  136. /// </Summary>
  137. #define DECLARE_IMAGEASSET(className, name, changeFunc, profile) public: \
  138. GFXTexHandle m##name = NULL;\
  139. StringTableEntry m##name##Name; \
  140. StringTableEntry m##name##AssetId;\
  141. AssetPtr<ImageAsset> m##name##Asset;\
  142. GFXTextureProfile* m##name##Profile = &profile;\
  143. public: \
  144. const StringTableEntry get##name##File() const { return m##name##Name; }\
  145. void set##name##File(const FileName &_in) { m##name##Name = StringTable->insert(_in.c_str());}\
  146. const AssetPtr<ImageAsset> & get##name##Asset() const { return m##name##Asset; }\
  147. void set##name##Asset(const AssetPtr<ImageAsset> &_in) { m##name##Asset = _in;}\
  148. \
  149. bool _set##name(StringTableEntry _in)\
  150. {\
  151. if(m##name##AssetId != _in || m##name##Name != _in)\
  152. {\
  153. if (m##name##Asset.notNull())\
  154. {\
  155. m##name##Asset->getChangedSignal().remove(this, &className::changeFunc);\
  156. }\
  157. if (_in == NULL || _in == StringTable->EmptyString())\
  158. {\
  159. m##name##Name = StringTable->EmptyString();\
  160. m##name##AssetId = StringTable->EmptyString();\
  161. m##name##Asset = NULL;\
  162. m##name.free();\
  163. m##name = NULL;\
  164. return true;\
  165. }\
  166. else if(_in[0] == '$' || _in[0] == '#')\
  167. {\
  168. m##name##Name = _in;\
  169. m##name##AssetId = StringTable->EmptyString();\
  170. m##name##Asset = NULL;\
  171. m##name.free();\
  172. m##name = NULL;\
  173. return true;\
  174. }\
  175. \
  176. if (AssetDatabase.isDeclaredAsset(_in))\
  177. {\
  178. m##name##AssetId = _in;\
  179. \
  180. U32 assetState = ImageAsset::getAssetById(m##name##AssetId, &m##name##Asset);\
  181. \
  182. if (ImageAsset::Ok == assetState)\
  183. {\
  184. m##name##Name = StringTable->EmptyString();\
  185. }\
  186. }\
  187. else\
  188. {\
  189. StringTableEntry assetId = ImageAsset::getAssetIdByFilename(_in);\
  190. if (assetId != StringTable->EmptyString())\
  191. {\
  192. m##name##AssetId = assetId;\
  193. if (ImageAsset::getAssetById(m##name##AssetId, &m##name##Asset) == ImageAsset::Ok)\
  194. {\
  195. m##name##Name = StringTable->EmptyString();\
  196. }\
  197. }\
  198. else\
  199. {\
  200. m##name##Name = _in;\
  201. m##name##AssetId = StringTable->EmptyString();\
  202. m##name##Asset = NULL;\
  203. }\
  204. }\
  205. }\
  206. if (get##name() != StringTable->EmptyString() && m##name##Name != StringTable->insert("texhandle"))\
  207. {\
  208. if (m##name##Asset.notNull())\
  209. {\
  210. m##name##Asset->getChangedSignal().notify(this, &className::changeFunc);\
  211. }\
  212. \
  213. m##name.set(get##name(), m##name##Profile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));\
  214. }\
  215. else\
  216. {\
  217. m##name.free();\
  218. m##name = NULL;\
  219. }\
  220. \
  221. if(get##name() == StringTable->EmptyString())\
  222. return true;\
  223. \
  224. if (m##name##Asset.notNull() && m##name##Asset->getStatus() != ImageAsset::Ok)\
  225. {\
  226. Con::errorf("%s(%s)::_set%s() - image asset failure\"%s\" due to [%s]", macroText(className), getName(), macroText(name), _in, ImageAsset::getAssetErrstrn(m##name##Asset->getStatus()).c_str());\
  227. return false; \
  228. }\
  229. else if (!m##name)\
  230. {\
  231. if (GFX->getAdapterType() != NullDevice)\
  232. Con::errorf("%s(%s)::_set%s() - Couldn't load image \"%s\"", macroText(className), getName(), macroText(name), _in);\
  233. return false;\
  234. }\
  235. return true;\
  236. }\
  237. \
  238. const StringTableEntry get##name() const\
  239. {\
  240. if (m##name##Asset && (m##name##Asset->getImageFileName() != StringTable->EmptyString()))\
  241. return Platform::makeRelativePathName(m##name##Asset->getImagePath(), Platform::getMainDotCsDir());\
  242. else if (m##name##AssetId != StringTable->EmptyString())\
  243. return m##name##AssetId;\
  244. else if (m##name##Name != StringTable->EmptyString())\
  245. return StringTable->insert(Platform::makeRelativePathName(m##name##Name, Platform::getMainDotCsDir()));\
  246. else\
  247. return StringTable->EmptyString();\
  248. }\
  249. GFXTexHandle get##name##Resource() \
  250. {\
  251. return m##name;\
  252. }\
  253. bool name##Valid() {return (get##name() != StringTable->EmptyString() && m##name##Asset->getStatus() == AssetBase::Ok); }
  254. #ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS
  255. #define INITPERSISTFIELD_IMAGEASSET(name, consoleClass, docs) \
  256. addProtectedField(#name, TypeImageFilename, Offset(m##name##Name, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, docs)); \
  257. addProtectedField(assetText(name, Asset), TypeImageAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.));
  258. #else
  259. #define INITPERSISTFIELD_IMAGEASSET(name, consoleClass, docs) \
  260. addProtectedField(#name, TypeImageFilename, Offset(m##name##Name, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, docs), AbstractClassRep::FIELD_HideInInspectors); \
  261. addProtectedField(assetText(name, Asset), TypeImageAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.));
  262. #endif // SHOW_LEGACY_FILE_FIELDS
  263. #define LOAD_IMAGEASSET(name)\
  264. if (m##name##AssetId != StringTable->EmptyString())\
  265. {\
  266. S32 assetState = ImageAsset::getAssetById(m##name##AssetId, &m##name##Asset);\
  267. if (assetState == ImageAsset::Ok )\
  268. {\
  269. m##name##Name = StringTable->EmptyString();\
  270. }\
  271. else Con::warnf("Warning: %s::LOAD_IMAGEASSET(%s)-%s", mClassName, m##name##AssetId, ImageAsset::getAssetErrstrn(assetState).c_str());\
  272. }
  273. #pragma endregion
  274. #pragma region Arrayed Asset Macros
  275. //Arrayed Assets
  276. #define DECLARE_IMAGEASSET_ARRAY(className, name, max) public: \
  277. static const U32 sm##name##Count = max;\
  278. GFXTexHandle m##name[max];\
  279. StringTableEntry m##name##Name[max]; \
  280. StringTableEntry m##name##AssetId[max];\
  281. AssetPtr<ImageAsset> m##name##Asset[max];\
  282. GFXTextureProfile * m##name##Profile[max];\
  283. public: \
  284. const StringTableEntry get##name##File(const U32& index) const { return m##name##Name[index]; }\
  285. void set##name##File(const FileName &_in, const U32& index) { m##name##Name[index] = StringTable->insert(_in.c_str());}\
  286. const AssetPtr<ImageAsset> & get##name##Asset(const U32& index) const { return m##name##Asset[index]; }\
  287. void set##name##Asset(const AssetPtr<ImageAsset> &_in, const U32& index) { m##name##Asset[index] = _in;}\
  288. \
  289. bool _set##name(StringTableEntry _in, const U32& index)\
  290. {\
  291. if(m##name##AssetId[index] != _in || m##name##Name[index] != _in)\
  292. {\
  293. if(index >= sm##name##Count || index < 0)\
  294. return false;\
  295. if (_in == NULL || _in == StringTable->EmptyString())\
  296. {\
  297. m##name##Name[index] = StringTable->EmptyString();\
  298. m##name##AssetId[index] = StringTable->EmptyString();\
  299. m##name##Asset[index] = NULL;\
  300. m##name[index].free();\
  301. m##name[index] = NULL;\
  302. return true;\
  303. }\
  304. else if(_in[0] == '$' || _in[0] == '#')\
  305. {\
  306. m##name##Name[index] = _in;\
  307. m##name##AssetId[index] = StringTable->EmptyString();\
  308. m##name##Asset[index] = NULL;\
  309. m##name[index].free();\
  310. m##name[index] = NULL;\
  311. return true;\
  312. }\
  313. \
  314. if (AssetDatabase.isDeclaredAsset(_in))\
  315. {\
  316. m##name##AssetId[index] = _in;\
  317. \
  318. U32 assetState = ImageAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]);\
  319. \
  320. if (ImageAsset::Ok == assetState)\
  321. {\
  322. m##name##Name[index] = StringTable->EmptyString();\
  323. }\
  324. }\
  325. else\
  326. {\
  327. StringTableEntry assetId = ImageAsset::getAssetIdByFilename(_in);\
  328. if (assetId != StringTable->EmptyString())\
  329. {\
  330. m##name##AssetId[index] = assetId;\
  331. if (ImageAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]) == ImageAsset::Ok)\
  332. {\
  333. m##name##Name[index] = StringTable->EmptyString();\
  334. }\
  335. }\
  336. else\
  337. {\
  338. m##name##Name[index] = _in;\
  339. m##name##AssetId[index] = StringTable->EmptyString();\
  340. m##name##Asset[index] = NULL;\
  341. }\
  342. }\
  343. }\
  344. if (get##name(index) != StringTable->EmptyString() && m##name##Name[index] != StringTable->insert("texhandle"))\
  345. {\
  346. m##name[index].set(get##name(index), m##name##Profile[index], avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));\
  347. }\
  348. else\
  349. {\
  350. m##name[index].free();\
  351. m##name[index] = NULL;\
  352. }\
  353. \
  354. if(get##name(index) == StringTable->EmptyString())\
  355. return true;\
  356. \
  357. if (m##name##Asset[index].notNull() && m##name##Asset[index]->getStatus() != ImageAsset::Ok)\
  358. {\
  359. Con::errorf("%s(%s)::_set%s(%i) - image asset failure\"%s\" due to [%s]", macroText(className), getName(), macroText(name), index, _in, ImageAsset::getAssetErrstrn(m##name##Asset[index]->getStatus()).c_str());\
  360. return false; \
  361. }\
  362. else if (!m##name[index])\
  363. {\
  364. if (GFX->getAdapterType() != NullDevice)\
  365. Con::errorf("%s(%s)::_set%s(%i) - Couldn't load image \"%s\"", macroText(className), getName(), macroText(name), index, _in);\
  366. return false; \
  367. }\
  368. return true;\
  369. }\
  370. \
  371. const StringTableEntry get##name(const U32& index) const\
  372. {\
  373. if (m##name##Asset[index] && (m##name##Asset[index]->getImageFileName() != StringTable->EmptyString()))\
  374. return Platform::makeRelativePathName(m##name##Asset[index]->getImagePath(), Platform::getMainDotCsDir());\
  375. else if (m##name##AssetId[index] != StringTable->EmptyString())\
  376. return m##name##AssetId[index];\
  377. else if (m##name##Name[index] != StringTable->EmptyString())\
  378. {\
  379. if (String(m##name##Name[index]).startsWith("#") || String(m##name##Name[index]).startsWith("$"))\
  380. return StringTable->insert(m##name##Name[index]);\
  381. else\
  382. return StringTable->insert(Platform::makeRelativePathName(m##name##Name[index], Platform::getMainDotCsDir()));\
  383. }\
  384. else\
  385. return StringTable->EmptyString();\
  386. }\
  387. GFXTexHandle get##name##Resource(const U32& index) \
  388. {\
  389. if(index >= sm##name##Count || index < 0)\
  390. return nullptr;\
  391. return m##name[index];\
  392. }\
  393. bool name##Valid(const U32& id) {return (get##name(id) != StringTable->EmptyString() && m##name##Asset[id]->getStatus() == AssetBase::Ok); }
  394. #define DECLARE_IMAGEASSET_ARRAY_SETGET(className, name)\
  395. static bool _set##name##Data(void* obj, const char* index, const char* data)\
  396. {\
  397. if (!index) return false;\
  398. U32 idx = dAtoi(index);\
  399. if (idx >= sm##name##Count)\
  400. return false;\
  401. bool ret = false;\
  402. className* object = static_cast<className*>(obj);\
  403. ret = object->_set##name(StringTable->insert(data),idx);\
  404. return ret;\
  405. }
  406. #define DECLARE_IMAGEASSET_ARRAY_NET_SETGET(className, name, bitmask)\
  407. static bool _set##name##Data(void* obj, const char* index, const char* data)\
  408. {\
  409. if (!index) return false;\
  410. U32 idx = dAtoi(index);\
  411. if (idx >= sm##name##Count)\
  412. return false;\
  413. bool ret = false;\
  414. className* object = static_cast<className*>(obj);\
  415. ret = object->_set##name(StringTable->insert(data),idx);\
  416. if(ret)\
  417. object->setMaskBits(bitmask);\
  418. return ret;\
  419. }
  420. #define INIT_IMAGEASSET_ARRAY(name, profile, index) \
  421. {\
  422. m##name##Name[index] = StringTable->EmptyString(); \
  423. m##name##AssetId[index] = StringTable->EmptyString(); \
  424. m##name##Asset[index] = NULL;\
  425. m##name[index] = NULL;\
  426. m##name##Profile[index] = &profile;\
  427. }
  428. #define DEF_IMAGEASSET_ARRAY_BINDS(className,name)\
  429. DefineEngineMethod(className, get##name, const char*, (S32 index), , "get name")\
  430. {\
  431. return object->get##name(index); \
  432. }\
  433. DefineEngineMethod(className, get##name##Asset, const char*, (S32 index), , assetText(name, asset reference))\
  434. {\
  435. if(index >= className::sm##name##Count || index < 0)\
  436. return "";\
  437. return object->m##name##AssetId[index]; \
  438. }\
  439. DefineEngineMethod(className, set##name, bool, (const char* map, S32 index), , assetText(name,assignment. first tries asset then flat file.))\
  440. {\
  441. return object->_set##name(StringTable->insert(map), index);\
  442. }
  443. #ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS
  444. #define INITPERSISTFIELD_IMAGEASSET_ARRAY(name, arraySize, consoleClass, docs) \
  445. addProtectedField(#name, TypeImageFilename, Offset(m##name##Name, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, docs)); \
  446. addProtectedField(assetText(name, Asset), TypeImageAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.));
  447. #else
  448. #define INITPERSISTFIELD_IMAGEASSET_ARRAY(name, arraySize, consoleClass, docs) \
  449. addProtectedField(#name, TypeImageFilename, Offset(m##name##Name, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, docs), AbstractClassRep::FIELD_HideInInspectors); \
  450. addProtectedField(assetText(name, Asset), TypeImageAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.));
  451. #endif
  452. #define LOAD_IMAGEASSET_ARRAY(name, index)\
  453. if (m##name##AssetId[index] != StringTable->EmptyString())\
  454. {\
  455. S32 assetState = ImageAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]);\
  456. if (assetState == ImageAsset::Ok )\
  457. {\
  458. m##name##Name[index] = StringTable->EmptyString();\
  459. }\
  460. else Con::warnf("Warning: %s::LOAD_IMAGEASSET(%s)-%s", mClassName, m##name##AssetId[index], ImageAsset::getAssetErrstrn(assetState).c_str());\
  461. }
  462. #pragma endregion