gcsx_tileset.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /* GCSx
  2. ** TILESET.CPP
  3. **
  4. ** Tileset 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. const TileSet* TileSet::activeGenTexture = NULL;
  26. TileSet::TileSet(class World* myWorld, int myId) : name(blankString), nameL(blankString) { start_func
  27. if (myId) assert(myWorld);
  28. id = myId;
  29. cached = 0;
  30. lockCount = 0;
  31. lockCountPlay = 0;
  32. cacheFile = NULL;
  33. texture = NULL;
  34. numTiles = 0;
  35. numTilesPerLine = TILE_DEFAULT_PERLINE;
  36. tiles = NULL;
  37. tsPerLine = 0;
  38. isFont = 0;
  39. defaultTransparent = 0;
  40. fontWidths = NULL;
  41. numCollisionMaps = 0;
  42. collisionMaps = NULL;
  43. world = myWorld;
  44. width = height = TILE_DEFAULT_SIZE;
  45. calculateCmSizes();
  46. }
  47. TileSet::~TileSet() { start_func
  48. if (tiles) SDL_FreeSurface(tiles);
  49. delete[] fontWidths;
  50. delete[] collisionMaps;
  51. delete cacheFile;
  52. delete texture;
  53. clipboardClearTileset(this);
  54. }
  55. void TileSet::calculateCmSizes() {
  56. cmHeight = height;
  57. cmWidth = width >> 5;
  58. if (width & 31) ++cmWidth;
  59. }
  60. void TileSet::cacheLoadTiles() throw_File { start_func
  61. // load tiles only
  62. try {
  63. assert(cacheFile);
  64. assert(cacheFile->getVersion() <= 1);
  65. assert(!tiles);
  66. cacheFile->rewind();
  67. if (numTiles) {
  68. int surfaceW = cacheFile->readInt();
  69. int surfaceH = cacheFile->readInt();
  70. int surfaceSize = cacheFile->readInt();
  71. if ((surfaceW != tsPerLine * width) ||
  72. (surfaceH != (numTiles + tsPerLine) / tsPerLine * height) ||
  73. (surfaceSize != surfaceW * surfaceH * 4)) {
  74. throw FileException("Corrupted tileset content");
  75. }
  76. tiles = createSurface32(surfaceW, surfaceH);
  77. // If pitch of created surface is "incorrect", we need to do extra work
  78. if (tiles->pitch == surfaceW * 4) {
  79. cacheFile->read(tiles->pixels, surfaceSize);
  80. }
  81. else {
  82. Uint8* dest = (Uint8*)tiles->pixels;
  83. for (int row = surfaceH; row > 0; --row) {
  84. cacheFile->read(dest, surfaceW * 4);
  85. dest += tiles->pitch;
  86. }
  87. }
  88. }
  89. }
  90. catch (...) {
  91. if (tiles) SDL_FreeSurface(tiles);
  92. tiles = NULL;
  93. throw;
  94. }
  95. }
  96. void TileSet::cacheLoad() throw_File { start_func
  97. if (cached) {
  98. try {
  99. // load into memory
  100. assert(!fontWidths);
  101. assert(!collisionMaps);
  102. // Rewinds for us
  103. cacheLoadTiles();
  104. if (numTiles) {
  105. if (isFont) {
  106. fontWidths = new Uint32[numTiles + 1];
  107. fontWidths[0] = 0; // 0 tile is assumed blank
  108. cacheFile->readIntBulk(fontWidths + 1, numTiles);
  109. // All sizes must be valid
  110. for (int pos = 1; pos <= numTiles; ++pos) {
  111. if (fontWidths[pos] > (Uint32)width) {
  112. throw FileException("Corrupted font width content");
  113. }
  114. }
  115. }
  116. }
  117. if (numCollisionMaps) {
  118. int size = (numCollisionMaps + 1) * cmWidth * cmHeight;
  119. collisionMaps = new Uint32[size];
  120. cacheFile->readIntBulk(collisionMaps, size);
  121. }
  122. // We retain this pointer and reuse it IF we
  123. // unlock to 0 AND aren't modified
  124. cached = 0;
  125. }
  126. catch (...) {
  127. if (tiles) SDL_FreeSurface(tiles);
  128. tiles = NULL;
  129. delete[] collisionMaps;
  130. collisionMaps = NULL;
  131. delete[] fontWidths;
  132. fontWidths = NULL;
  133. throw;
  134. }
  135. }
  136. }
  137. int TileSet::getGlyphWidth(int tile) const { start_func
  138. assert(isFont);
  139. assert(fontWidths);
  140. assert(tile >= 0);
  141. assert(tile <= numTiles);
  142. return fontWidths[tile];
  143. }
  144. void TileSet::loadHeader(FileRead* file) throw_File { start_func
  145. assert(world);
  146. if (file->getVersion() > 1) {
  147. throw FileException("Unsupported tileset version %d", file->getVersion());
  148. }
  149. file->readStr(name);
  150. nameL = name;
  151. toLower(nameL);
  152. width = file->readInt();
  153. height = file->readInt();
  154. calculateCmSizes();
  155. numTiles = file->readInt();
  156. numCollisionMaps = file->readInt();
  157. numTilesPerLine = file->readInt();
  158. tsPerLine = file->readInt();
  159. defaultTransparent = file->readInt();
  160. isFont = file->readInt();
  161. id = file->readInt();
  162. // Check validity
  163. if ((width < MIN_TILESIZE) || (height < MIN_TILESIZE) ||
  164. (width > MAX_TILESIZE) || (height > MAX_TILESIZE) ||
  165. (numTiles < 0) || (numTiles > MAX_TILES) ||
  166. (numTilesPerLine < 0) || (numTilesPerLine > MAX_TILES) ||
  167. (tsPerLine < 0) || (tsPerLine > numTiles) ||
  168. ((numCollisionMaps) && (isFont)) ||
  169. (!id)) {
  170. throw FileException("Corrupted tileset header");
  171. }
  172. }
  173. void TileSet::loadContent(FileRead* file) { start_func
  174. assert(world);
  175. delete cacheFile;
  176. cacheFile = file;
  177. cached = 1;
  178. }
  179. int TileSet::isContentCached() const { start_func
  180. return cached;
  181. }
  182. int TileSet::doLock(int play) throw_File { start_func
  183. // Load everything if this is our first unlock at all
  184. if ((lockCount == 0) && (lockCountPlay == 0))
  185. cacheLoad();
  186. // Otherwise- first play lock- everything is ok
  187. // First non-play lock- we need to reload tiles back in
  188. else if ((lockCount == 0) && (!play))
  189. cacheLoadTiles();
  190. if (play) {
  191. ++lockCountPlay;
  192. if (!texture) {
  193. activeGenTexture = this;
  194. texture = new TextureMap(numTiles, width, height, genTexture);
  195. activeGenTexture = NULL;
  196. }
  197. if ((!lockCount) && (tiles)) {
  198. SDL_FreeSurface(tiles);
  199. tiles = NULL;
  200. }
  201. }
  202. else {
  203. ++lockCount;
  204. }
  205. return lockCount + lockCountPlay;
  206. }
  207. int TileSet::doUnlock(int play) { start_func
  208. if (play) --lockCountPlay;
  209. else --lockCount;
  210. assert(lockCount >= 0);
  211. assert(lockCountPlay >= 0);
  212. if (cacheFile) {
  213. if ((lockCount == 0) && (tiles)) {
  214. SDL_FreeSurface(tiles);
  215. tiles = NULL;
  216. }
  217. if ((lockCountPlay == 0) && (texture)) {
  218. delete texture;
  219. texture = NULL;
  220. }
  221. if ((lockCountPlay == 0) && (lockCount == 0)) {
  222. // Fully recache ourselves
  223. cached = 1;
  224. delete[] fontWidths;
  225. fontWidths = NULL;
  226. }
  227. }
  228. return lockCount + lockCountPlay;
  229. }
  230. int TileSet::isLocked() const { start_func
  231. return lockCount;
  232. }
  233. int TileSet::markLock() throw_File { start_func
  234. return doLock(0);
  235. }
  236. int TileSet::markUnlock() { start_func
  237. return doUnlock(0);
  238. }
  239. int TileSet::markLockPlay() throw_File { start_func
  240. return doLock(1);
  241. }
  242. int TileSet::markUnlockPlay() { start_func
  243. return doUnlock(1);
  244. }
  245. const SDL_Surface* TileSet::getTileSurface(int tile, int& x, int& y) const { start_func
  246. assert(tiles);
  247. assert(!cached);
  248. if (tile < 1) return NULL;
  249. if (tile > numTiles) return NULL;
  250. x = tile % tsPerLine * width;
  251. y = tile / tsPerLine * height;
  252. return tiles;
  253. }
  254. const TextureMap* TileSet::getTexture() { start_func
  255. return texture;
  256. }
  257. void TileSet::genTexture(int position, const SDL_Surface*& src, int& x, int& y) { start_func
  258. assert(!activeGenTexture->cached);
  259. assert(position > 0);
  260. assert(position <= activeGenTexture->numTiles);
  261. assert(activeGenTexture->tiles);
  262. src = activeGenTexture->tiles;
  263. x = position % activeGenTexture->tsPerLine * activeGenTexture->width;
  264. y = position / activeGenTexture->tsPerLine * activeGenTexture->height;
  265. }