makeMapImages.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /** Simple program to export Anarch maps as isometric images in PPM format.
  2. The code is not very nice, the goal is just to get the images :)
  3. by drummyfish, released under CC0 */
  4. #include <stdio.h>
  5. #include "../game.h"
  6. #define IMAGE_W 4096 // if changed you also have to change PPM header data
  7. #define IMAGE_H 2500
  8. #define CENTER_X (IMAGE_W / 2)
  9. #define CENTER_Y (IMAGE_H / 6)
  10. #define TILE_H 25 // vertical height
  11. #define TILE_TILT 2 // view angle, by how many H pixels we'll shift one down
  12. unsigned char image[IMAGE_H * IMAGE_W * 3];
  13. int maxHeights[4]; // ceiling limits for different quadrants
  14. void drawPixel(int x, int y, unsigned char color, int multiply)
  15. {
  16. if (x < 0 || x >= IMAGE_W || y < 0 || y >= IMAGE_H)
  17. return;
  18. uint16_t rgb = paletteRGB565[color];
  19. int index = (y * IMAGE_W + x) * 3;
  20. image[index] = ((((rgb >> 11) << 3) & 0xff) * multiply) / 128;
  21. image[index + 1] = ((((rgb >> 5) << 2) & 0xff) * multiply) / 128;
  22. image[index + 2] = (((rgb << 3) & 0xff) * multiply) / 128;
  23. }
  24. void drawColum(int x, int y, int z1, int z2, int texture, int doorTexture, const uint8_t *sprite)
  25. {
  26. if (texture == SFG_TILE_TEXTURE_TRANSPARENT)
  27. return;
  28. int inc = z2 > z1 ? 1 : -1;
  29. int minZ = z1 < z2 ? z1 : z2;
  30. int brightness = (minZ / 2) % 128;
  31. if (brightness < 0)
  32. brightness *= -1;
  33. brightness += 30;
  34. for (int i = 0; i < SFG_TEXTURE_SIZE; ++i) // platform
  35. for (int j = -1 * i / TILE_TILT; j <= i / TILE_TILT; ++j)
  36. {
  37. drawPixel(x + i,y + minZ + j,SFG_currentLevel.floorColor,brightness);
  38. drawPixel(x + 2 * SFG_TEXTURE_SIZE - 1 - i,y + minZ + j,SFG_currentLevel.floorColor,brightness);
  39. }
  40. if (sprite != 0)
  41. for (int sy = 0; sy < SFG_TEXTURE_SIZE; ++sy)
  42. for (int sx = 0; sx < SFG_TEXTURE_SIZE; ++sx)
  43. {
  44. uint8_t color = SFG_getTexel(sprite,sx,sy);
  45. if (color != SFG_TRANSPARENT_COLOR)
  46. drawPixel(x + sx + SFG_TEXTURE_SIZE / 2,y + minZ + sy - SFG_TEXTURE_SIZE,color,110);
  47. }
  48. if (z1 == z2)
  49. return;
  50. z1 += inc;
  51. int texY = 0;
  52. while (z1 != z2) // column (walls)
  53. {
  54. int ty = (texY * SFG_TEXTURE_SIZE) / TILE_H;
  55. uint8_t *t = (doorTexture < 0 || ty > SFG_TEXTURE_SIZE) ?
  56. SFG_currentLevel.textures[texture] :
  57. (SFG_wallTextures + doorTexture * SFG_TEXTURE_STORE_SIZE);
  58. for (int i = 0; i < SFG_TEXTURE_SIZE; ++i)
  59. {
  60. uint8_t color = SFG_getTexel(t,i,ty);
  61. if (color != SFG_TRANSPARENT_COLOR)
  62. drawPixel(x + i,y + z1 + i / TILE_TILT,color,75);
  63. color = SFG_getTexel(t,SFG_TEXTURE_SIZE - i,ty);
  64. if (color != SFG_TRANSPARENT_COLOR)
  65. drawPixel(x + 2 * SFG_TEXTURE_SIZE - 1 - i,y + z1 + i / TILE_TILT,
  66. color,128);
  67. }
  68. texY++;
  69. z1 += inc;
  70. }
  71. }
  72. void tileIndexToXY(int n, int *x, int *y)
  73. {
  74. int reverse = 0;
  75. if (n > SFG_MAP_SIZE * SFG_MAP_SIZE / 2)
  76. {
  77. reverse = 1;
  78. n = SFG_MAP_SIZE * SFG_MAP_SIZE - 1 - n;
  79. }
  80. *y = 0;
  81. *x = 0;
  82. while (*y < n)
  83. {
  84. *y += 1;
  85. n -= *y;
  86. }
  87. while (n > 0)
  88. {
  89. *x += 1;
  90. *y -= 1;
  91. n--;
  92. }
  93. if (reverse)
  94. {
  95. *x = SFG_MAP_SIZE - 1 - *x;
  96. *y = SFG_MAP_SIZE - 1 - *y;
  97. }
  98. *x = SFG_MAP_SIZE - 1 - *x;
  99. }
  100. void exportMap(int index)
  101. {
  102. SFG_setAndInitLevel(index);
  103. for (int i = 0; i < IMAGE_H * IMAGE_W * 3; ++i)
  104. image[i] = 0;
  105. unsigned char header[] =
  106. {'P', '6', ' ', '4', '0', '9', '6', ' ', '2', '5', '0', '0', ' ',
  107. '2', '5', '5', '\n'};
  108. char fname[] = "map0.ppm";
  109. fname[3] += index;
  110. FILE *f = fopen(fname,"wb");
  111. fwrite(header,sizeof(header),1,f);
  112. int n = 0;
  113. for (int drawY = 0; drawY < SFG_MAP_SIZE; ++drawY)
  114. {
  115. for (int i = 0; i < 2; ++i)
  116. {
  117. int xLimit = (1 + 2 * drawY + i);
  118. if (drawY >= SFG_MAP_SIZE / 2)
  119. xLimit = SFG_MAP_SIZE * 2 - xLimit;
  120. #define TW (2 * SFG_TEXTURE_SIZE)
  121. #define TH (SFG_TEXTURE_SIZE / TILE_TILT)
  122. int startX = -1 * xLimit * TW / 2;
  123. for (int drawX = 0; drawX < xLimit; ++drawX)
  124. {
  125. uint8_t properties;
  126. int tx, ty;
  127. tileIndexToXY(n,&tx,&ty);
  128. int maxHeightTiles = maxHeights[2 * ((ty * 2) / SFG_MAP_SIZE) +
  129. (tx * 2) / SFG_MAP_SIZE];
  130. SFG_TileDefinition tile =
  131. SFG_getMapTile(SFG_currentLevel.levelPointer,tx,ty,&properties);
  132. int h = SFG_TILE_FLOOR_HEIGHT(tile);
  133. if (properties == SFG_TILE_PROPERTY_ELEVATOR)
  134. {
  135. h += SFG_TILE_CEILING_HEIGHT(tile);
  136. h /= 2;
  137. }
  138. if (maxHeightTiles * 4 < h)
  139. h = maxHeightTiles * 4;
  140. h = (h * SFG_WALL_HEIGHT_STEP * TILE_H) / RCL_UNITS_PER_SQUARE;
  141. const uint8_t *sprite = 0;
  142. for (int i = 0; i < SFG_MAX_LEVEL_ELEMENTS; ++i)
  143. {
  144. SFG_LevelElement e =
  145. SFG_currentLevel.levelPointer->elements[i];
  146. if (e.type == SFG_LEVEL_ELEMENT_NONE)
  147. break;
  148. if (e.coords[0] == tx && e.coords[1] == ty && !(e.type & 0x10))
  149. {
  150. uint8_t ss;
  151. if (e.type & 0x20)
  152. sprite = SFG_getMonsterSprite(e.type,0,0);
  153. else
  154. SFG_getItemSprite(e.type,&sprite,&ss);
  155. break;
  156. }
  157. }
  158. drawColum(
  159. CENTER_X + startX + drawX * TW,
  160. CENTER_Y + (2 * drawY + i) * TH - drawY,-1 * h,
  161. 0,SFG_TILE_FLOOR_TEXTURE(tile),
  162. (properties == SFG_TILE_PROPERTY_DOOR) ?
  163. SFG_currentLevel.levelPointer->doorTextureIndex : -1,
  164. sprite);
  165. int maxH = 16 * TILE_H;
  166. if (maxHeightTiles * TILE_H < maxH)
  167. maxH = maxHeightTiles * TILE_H;
  168. maxH *= -1;
  169. h = SFG_TILE_FLOOR_HEIGHT(tile) + SFG_TILE_CEILING_HEIGHT(tile);
  170. h = -1 * (h * SFG_WALL_HEIGHT_STEP * TILE_H) / RCL_UNITS_PER_SQUARE + 1;
  171. if (SFG_TILE_CEILING_HEIGHT(tile) < 31 &&
  172. maxH < h && properties != SFG_TILE_PROPERTY_ELEVATOR)
  173. {
  174. drawColum(
  175. CENTER_X + startX + drawX * TW,
  176. CENTER_Y + (2 * drawY + i) * TH - drawY,maxH,
  177. h,SFG_TILE_CEILING_TEXTURE(tile),-1,0);
  178. }
  179. n++;
  180. }
  181. }
  182. }
  183. fwrite(image,1,IMAGE_W * IMAGE_H * 3,f);
  184. fclose(f);
  185. }
  186. int main(void)
  187. {
  188. SFG_init();
  189. #define E(m,h1,h2,h3,h4)\
  190. printf("exporting %d\n",m);\
  191. maxHeights[0] = h1;\
  192. maxHeights[1] = h2;\
  193. maxHeights[2] = h3;\
  194. maxHeights[3] = h4;\
  195. exportMap(m);
  196. E(0,100,100,100,100)
  197. E(1,7,5,7,5)
  198. E(2,5,6,5,5)
  199. E(3,7,7,6,6)
  200. E(4,100,6,100,6)
  201. E(5,100,100,100,100)
  202. E(6,5,4,3,3)
  203. E(7,7,7,7,7)
  204. E(8,5,5,5,5)
  205. E(9,100,100,100,100)
  206. return 0;
  207. }
  208. // just create empty functions, game.h requires it:
  209. int8_t SFG_keyPressed(uint8_t key) { return 0; }
  210. void SFG_getMouseOffset(int16_t *x, int16_t *y) { }
  211. uint32_t SFG_getTimeMs() { return 0; }
  212. void SFG_sleepMs(uint16_t timeMs) { }
  213. static inline void SFG_setPixel(uint16_t x, uint16_t y, uint8_t colorIndex) { }
  214. void SFG_playSound(uint8_t soundIndex, uint8_t volume) { }
  215. void SFG_setMusic(uint8_t value) { }
  216. void SFG_processEvent(uint8_t event, uint8_t data) { }
  217. void SFG_save(uint8_t data[SFG_SAVE_SIZE]) { }
  218. uint8_t SFG_load(uint8_t data[SFG_SAVE_SIZE]) { return 0; }