gcsx_animgroup.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /* GCSx
  2. ** ANIMGROUP.CPP
  3. **
  4. ** Animation group support, objects and drawing
  5. ** Non-EDITOR members
  6. */
  7. /*****************************************************************************
  8. ** Copyright (C) 2003-2006 Janson
  9. **
  10. ** This program is free software; you can redistribute it and/or modify
  11. ** it under the terms of the GNU General Public License as published by
  12. ** the Free Software Foundation; either version 2 of the License, or
  13. ** (at your option) any later version.
  14. **
  15. ** This program is distributed in the hope that it will be useful,
  16. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ** GNU General Public License for more details.
  19. **
  20. ** You should have received a copy of the GNU General Public License
  21. ** along with this program; if not, write to the Free Software
  22. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  23. *****************************************************************************/
  24. #include "all.h"
  25. // Animation group components
  26. AnimComponent::AnimComponent() { start_func
  27. tileset = NULL;
  28. index = 0;
  29. effects = 0;
  30. x = y = 0;
  31. }
  32. AnimFrame::AnimFrame() { start_func
  33. count = 0;
  34. xOrigin = yOrigin = 0;
  35. comps = NULL;
  36. xOffs = yOffs = 0;
  37. delay = 1;
  38. }
  39. AnimFrame::~AnimFrame() { start_func
  40. delete[] comps;
  41. }
  42. const AnimFrame& AnimFrame::operator=(const AnimFrame& from) { start_func
  43. count = from.count;
  44. xOrigin = from.xOrigin;
  45. yOrigin = from.yOrigin;
  46. xOffs = from.xOffs;
  47. yOffs = from.yOffs;
  48. delay = from.delay;
  49. delete[] comps;
  50. comps = NULL;
  51. if (count) {
  52. comps = new AnimComponent[count];
  53. memcpy(comps, from.comps, sizeof(AnimComponent[count]));
  54. }
  55. return from;
  56. }
  57. void AnimFrame::setCount(int newCount) { start_func
  58. AnimComponent* newComps = NULL;
  59. if (newCount) {
  60. newComps = new AnimComponent[newCount];
  61. // Copy existing
  62. memcpy(newComps, comps, sizeof(AnimComponent[min(count, newCount)]));
  63. // (any empty spaces initialized already)
  64. }
  65. delete[] comps;
  66. comps = newComps;
  67. count = newCount;
  68. }
  69. AnimSequence::AnimSequence() : name(blankString) { start_func
  70. count = 0;
  71. width = 0;
  72. height = 0;
  73. loopType = LOOP_NONE;
  74. frames = NULL;
  75. }
  76. AnimSequence::~AnimSequence() { start_func
  77. delete[] frames;
  78. }
  79. const AnimSequence& AnimSequence::operator=(const AnimSequence& from) { start_func
  80. width = from.width;
  81. height = from.height;
  82. count = from.count;
  83. loopType = from.loopType;
  84. delete[] frames;
  85. frames = NULL;
  86. if (count) {
  87. frames = new AnimFrame[count];
  88. for (int pos = 0; pos < count; ++pos) {
  89. frames[pos] = from.frames[pos];
  90. }
  91. }
  92. return from;
  93. }
  94. void AnimSequence::setCount(int newCount) { start_func
  95. AnimFrame* newFrames = NULL;
  96. if (newCount) {
  97. newFrames = new AnimFrame[newCount];
  98. // Copy existing
  99. for (int pos = min(count, newCount) - 1; pos >= 0; --pos) {
  100. newFrames[pos] = frames[pos];
  101. }
  102. // (any empty spaces initialized already)
  103. }
  104. delete[] frames;
  105. frames = newFrames;
  106. count = newCount;
  107. }
  108. // Animation groups
  109. AnimGroup::AnimGroup(class World* myWorld, int myId) : name(blankString), nameL(blankString) { start_func
  110. assert(myWorld);
  111. id = myId;
  112. cached = 0;
  113. lockCount = 0;
  114. cacheFile = NULL;
  115. anims = NULL;
  116. numAnim = 0;
  117. defWidth = defHeight = IMAGE_DEFAULT_SIZE;
  118. world = myWorld;
  119. }
  120. AnimGroup::~AnimGroup() { start_func
  121. delete cacheFile;
  122. }
  123. int AnimGroup::usesTileSet(const class TileSet* tileset) const { start_func
  124. for (int pos = 0; pos < numAnim; ++pos) {
  125. for (int subpos = 0; subpos < anims[pos].count; ++subpos) {
  126. for (int subsubpos = 0; subsubpos < anims[pos].frames[subpos].count; ++subsubpos) {
  127. if (anims[pos].frames[subpos].comps[subsubpos].tileset == tileset) return 1;
  128. }
  129. }
  130. }
  131. return 0;
  132. }
  133. void AnimGroup::cacheLoad() throw_File { start_func
  134. if (cached) {
  135. // load into memory
  136. assert(cacheFile);
  137. assert(cacheFile->getVersion() <= 1);
  138. assert(anims == NULL);
  139. cacheFile->rewind();
  140. try {
  141. if (numAnim) {
  142. anims = new AnimSequence[numAnim];
  143. for (int pos = 0; pos < numAnim; ++pos) {
  144. cacheFile->readStr(anims[pos].name);
  145. anims[pos].count = cacheFile->readInt();
  146. anims[pos].width = cacheFile->readInt();
  147. anims[pos].height = cacheFile->readInt();
  148. anims[pos].loopType = (AnimSequence::AnimLoop)cacheFile->readInt8();
  149. // Validity checks
  150. if ((anims[pos].count < 1) || (anims[pos].count > MAX_ANIMFRAME) ||
  151. ((anims[pos].loopType != AnimSequence::LOOP_NONE) && (anims[pos].loopType != AnimSequence::LOOP_FORWARD) && (anims[pos].loopType != AnimSequence::LOOP_PINGPONG)) ||
  152. (anims[pos].width < MIN_SPRITESIZE) || (anims[pos].width > MAX_SPRITESIZE) ||
  153. (anims[pos].height < MIN_SPRITESIZE) || (anims[pos].height > MAX_SPRITESIZE)) {
  154. throw FileException("Corrupted animation group content");
  155. }
  156. // Frames
  157. anims[pos].frames = new AnimFrame[anims[pos].count];
  158. for (int subpos = 0; subpos < anims[pos].count; ++subpos) {
  159. anims[pos].frames[subpos].count = cacheFile->readInt();
  160. anims[pos].frames[subpos].xOrigin = cacheFile->readInt16();
  161. anims[pos].frames[subpos].yOrigin = cacheFile->readInt16();
  162. anims[pos].frames[subpos].xOffs = cacheFile->readInt16();
  163. anims[pos].frames[subpos].yOffs = cacheFile->readInt16();
  164. anims[pos].frames[subpos].delay = cacheFile->readInt8();
  165. // Validity checks
  166. if ((anims[pos].frames[subpos].count < 0) || (anims[pos].frames[subpos].count > MAX_ANIMCOMP) ||
  167. (anims[pos].frames[subpos].delay < 1)) {
  168. throw FileException("Corrupted animation group content");
  169. }
  170. // Components
  171. // (no count- .comps is already NULL)
  172. if (anims[pos].frames[subpos].count) {
  173. anims[pos].frames[subpos].comps = new AnimComponent[anims[pos].frames[subpos].count];
  174. for (int subsubpos = 0; subsubpos < anims[pos].frames[subpos].count; ++subsubpos) {
  175. int tilesetId = cacheFile->readInt();
  176. anims[pos].frames[subpos].comps[subsubpos].tileset = world->findTileSet(tilesetId);
  177. // Ensure tileset exists
  178. if (!anims[pos].frames[subpos].comps[subsubpos].tileset) {
  179. throw FileException("Corrupted animation group content");
  180. }
  181. anims[pos].frames[subpos].comps[subsubpos].index = cacheFile->readInt16();
  182. anims[pos].frames[subpos].comps[subsubpos].x = cacheFile->readInt16();
  183. anims[pos].frames[subpos].comps[subsubpos].y = cacheFile->readInt16();
  184. anims[pos].frames[subpos].comps[subsubpos].r = cacheFile->readInt8();
  185. anims[pos].frames[subpos].comps[subsubpos].g = cacheFile->readInt8();
  186. anims[pos].frames[subpos].comps[subsubpos].b = cacheFile->readInt8();
  187. anims[pos].frames[subpos].comps[subsubpos].alpha = cacheFile->readInt8();
  188. anims[pos].frames[subpos].comps[subsubpos].effects = cacheFile->readInt8();
  189. // Validity checks
  190. if ((anims[pos].frames[subpos].comps[subsubpos].x >= anims[pos].width) ||
  191. (anims[pos].frames[subpos].comps[subsubpos].y >= anims[pos].height) ||
  192. (anims[pos].frames[subpos].comps[subsubpos].effects > AnimComponent::EFFECTS_ALL)) {
  193. throw FileException("Corrupted animation group content");
  194. }
  195. }
  196. }
  197. }
  198. }
  199. }
  200. }
  201. catch (...) {
  202. // Recache ourselves
  203. delete[] anims;
  204. anims = NULL;
  205. throw;
  206. }
  207. // We retain this pointer and reuse it IF we
  208. // unlock to 0 AND aren't modified
  209. cached = 0;
  210. }
  211. }
  212. void AnimGroup::loadHeader(FileRead* file) throw_File { start_func
  213. if (file->getVersion() > 1) {
  214. throw FileException("Unsupported animation group version %d", file->getVersion());
  215. }
  216. file->readStr(name);
  217. nameL = name;
  218. toLower(nameL);
  219. id = file->readInt();
  220. defWidth = file->readInt();
  221. defHeight = file->readInt();
  222. numAnim = file->readInt();
  223. // Check validity
  224. if ((defWidth < MIN_SPRITESIZE) || (defHeight < MIN_SPRITESIZE) ||
  225. (defWidth > MAX_SPRITESIZE) || (defHeight > MAX_SPRITESIZE) ||
  226. (numAnim < 0) || (numAnim > MAX_ANIMGROUP) ||
  227. (!id)) {
  228. throw FileException("Corrupted animation group header");
  229. }
  230. }
  231. void AnimGroup::loadContent(FileRead* file) { start_func
  232. delete cacheFile;
  233. cacheFile = file;
  234. cached = 1;
  235. }
  236. int AnimGroup::isContentCached() const { start_func
  237. return cached;
  238. }
  239. int AnimGroup::markLock() throw_File { start_func
  240. cacheLoad();
  241. return ++lockCount;
  242. }
  243. int AnimGroup::markUnlock() { start_func
  244. --lockCount;
  245. assert(lockCount >= 0);
  246. if ((lockCount == 0) && (cacheFile)) {
  247. // Recache ourselves
  248. cached = 1;
  249. delete[] anims;
  250. anims = NULL;
  251. }
  252. return lockCount;
  253. }
  254. int AnimGroup::isLocked() const { start_func
  255. return lockCount;
  256. }