tilepane.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. #include "eruta.h"
  2. #include "mem.h"
  3. #include "tile.h"
  4. #include "camera.h"
  5. #include "tilepane.h"
  6. #include "pointergrid.h"
  7. #include "monolog.h"
  8. /* Tile blending direction constants. */
  9. #define TILE_BLEND_NORTHWEST 0
  10. #define TILE_BLEND_NORTH 1
  11. #define TILE_BLEND_NORTHEAST 2
  12. #define TILE_BLEND_WEST 3
  13. #define TILE_BLEND_EAST 4
  14. #define TILE_BLEND_SOUTHWEST 5
  15. #define TILE_BLEND_SOUTH 6
  16. #define TILE_BLEND_SOUTHEAST 7
  17. #define TILE_BLEND_DIRECTION_MAX 8
  18. #define TILE_BLEND_CORNER 0
  19. #define TILE_BLEND_SIDE 1
  20. #define TILE_BLEND_SHAPE_MAX 2
  21. /* Tile blending types. */
  22. #define TILE_BLEND_SHARP 0
  23. #define TILE_BLEND_GRADUAL 1
  24. #define TILE_BLEND_FUZZY 2
  25. #define TILE_BLEND_FUZZY_GRADUAL 3
  26. #define TILE_BLEND_TYPE_MAX 4
  27. #define TILE_BLEND_BITMAPS_MAX 255
  28. /* A cache of generated generic blending masks. */
  29. static Image * tile_blend_masks[TILE_BLEND_TYPE_MAX][TILE_BLEND_SHAPE_MAX];
  30. /* How the mask should be applied, i. e. flipped. */
  31. static int tile_blend_flags[TILE_BLEND_DIRECTION_MAX] = {
  32. 0,
  33. 0,
  34. ALLEGRO_FLIP_HORIZONTAL,
  35. 0,
  36. ALLEGRO_FLIP_HORIZONTAL,
  37. ALLEGRO_FLIP_VERTICAL,
  38. ALLEGRO_FLIP_VERTICAL,
  39. ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL
  40. };
  41. /* Which "side" mask should be used mask should be used. */
  42. static int tile_blend_sides[TILE_BLEND_DIRECTION_MAX] = {
  43. TILE_BLEND_CORNER,
  44. TILE_BLEND_SIDE ,
  45. TILE_BLEND_CORNER,
  46. TILE_BLEND_SIDE ,
  47. TILE_BLEND_SIDE ,
  48. TILE_BLEND_CORNER,
  49. TILE_BLEND_SIDE ,
  50. TILE_BLEND_CORNER
  51. };
  52. /* How the mask should be turned, i. e. rotated. */
  53. static float tile_blend_angles[TILE_BLEND_DIRECTION_MAX] = {
  54. 0.0,
  55. 0.0,
  56. 0.0,
  57. 3 * ALLEGRO_PI / 2.0f,
  58. ALLEGRO_PI / 2.0f,
  59. 0.0,
  60. 0.0,
  61. 0.0
  62. };
  63. /*
  64. In the simple case where there are only 2 different kinds of tiles,
  65. then for a tile somewhere in the map, that tile has 8 neighbours, and thus
  66. there are 8**2 or 256 different possible layouts of these neighbours around that
  67. single tile, and 256 different blends would be needed.
  68. Of course, this is a staggering amount for hand drawn graphics, and even for
  69. automatically generated mask images, this takes up a hefty chunk of memory,
  70. so some kind of simplification is needed.
  71. The first simplification is the use of the tile's blend value as a blend *priority*
  72. value. The tile with the lower blend priority will be blended with the
  73. tile with the higher blend priority blending over it. Tiles with equal blend
  74. priority will simply not blend. This reduces the possibilities because in
  75. cases where 3 or more tyle types must blend, without priorities,
  76. the number of possible blends would become even larger.
  77. Let's consider the possibilities takng symmetry in account. If only 2 tiles
  78. that will blend are adjacent, there are 8 psossibilities. Howevere there ar 4
  79. symmetric rotations of the 2 cases of the 2 tiles being either side-to-side
  80. or corner to corner. In case of side-to side, the blend should go rougmly like
  81. this: (scaled down to 8x8
  82. ..........OOOOOOOO ................OO
  83. ..........OOOOOOOO ..............OOOO
  84. ..........OOOOOOOO ............OOOOOO
  85. ..........OOOOOOOO ............OOOOOO
  86. ..........OOOOOOOO => ............OOOOOO
  87. ..........OOOOOOOO ............OOOOOO
  88. ..........OOOOOOOO ...........OOOOOOO
  89. ..........OOOOOOOO ..........OOOOOOOO
  90. And corner to corner:
  91. OOOOOOOO OOOOOOOO
  92. OOOOOOOO OOOOOOOO
  93. OOOOOOOO OOOOOOOO
  94. OOOOOOOO OOOOOOOO
  95. OOOOOOOO => OOOOOOOO
  96. OOOOOOOO OOOOOOOO
  97. OOOOOOOO .OOOOOOO
  98. OOOOOOOO ..OOOOOO
  99. .......... ..........
  100. .......... ..........
  101. .......... ..........
  102. .......... ..........
  103. .......... => ..........
  104. .......... ..........
  105. .......... ..........
  106. .......... ..........
  107. If the masks are judiciouly chosen, and all align correctly,
  108. then it will suffice to have just 2 mask images which get rotated as needed,
  109. one mask for the side to side, and one for corner to corner.
  110. Each of the masks follows a strict pattern, that is, the side by side
  111. has a \__/ - like shape were the depth of the overlap is at most 1/4th of the
  112. tile height. (Or is it 1/3, let's check it out).
  113. Then, for everyoverlapping tile
  114. */
  115. Image * tilepane_prepare_blend
  116. (Image * blend, Tile * tile, Tile * blendtile, int direction) {
  117. Image * mask = NULL;
  118. int side = tile_blend_sides[direction];
  119. float angle = tile_blend_angles[direction];
  120. int flags = tile_blend_flags[direction];
  121. int maskid = tile_blend_mask(tile);
  122. if (!blend) return NULL;
  123. if (maskid > TILE_BLEND_TYPE_MAX) return NULL;
  124. if (maskid < 0) return NULL;
  125. mask = tile_blend_masks[maskid][side];
  126. if (!mask) return NULL;
  127. tile_draw_masked_to(blend, blendtile, mask, angle, flags);
  128. return blend;
  129. }
  130. /**
  131. * A Tilepane is a pane or layer of tiles for use in a tile map or tiled
  132. * background. A Tilepane consists of individual tiles from the same
  133. * tile set. Different panes may have different tile sets.
  134. */
  135. struct Tilepane_ {
  136. Tileset * set;
  137. PointerGrid * tiles;
  138. int gridwide; // Width of the tile map in grid points (tiles)
  139. int gridhigh; // Height of the tile map in grid points (tiles)
  140. int realwide; // Width of whole tile map in pixels
  141. int realhigh; // Height of whole tile map in pixels
  142. PointerGrid * blends; // Blend bitmaps for the layer, generated at loading of the pane.
  143. PointerGrid * flags; // Drawing flags for the tiles, to allow flipped tiles. Does not cooperatewell with autoblending.
  144. };
  145. void * tilepane_blends_destructor(void * ptr) {
  146. Image * bmp = ptr;
  147. al_destroy_bitmap(bmp);
  148. return NULL;
  149. }
  150. /**
  151. * Cleans up a pane by freeing the memory references it holds internally,
  152. * but does not free the pane itself.
  153. */
  154. Tilepane * tilepane_done(Tilepane * pane) {
  155. int index;
  156. if (!pane) return NULL;
  157. pointergrid_free(pane->tiles);
  158. pointergrid_nullall(pane->blends, tilepane_blends_destructor);
  159. pointergrid_free(pane->blends);
  160. pointergrid_zero_all(pane->flags);
  161. pointergrid_free(pane->flags);
  162. // Size is now zero.
  163. pane->gridhigh = 0;
  164. pane->gridwide = 0;
  165. return pane;
  166. }
  167. /** Deallocates a Tilepane. */
  168. Tilepane * tilepane_free(Tilepane * pane) {
  169. tilepane_done(pane);
  170. mem_free(pane);
  171. return NULL;
  172. }
  173. /** Initializes a tile pane.
  174. * The pane will not clean up the tile set itself!
  175. */
  176. Tilepane * tilepane_init(Tilepane * pane, Tileset * set,
  177. int gridwide, int gridhigh) {
  178. int x, y, index;
  179. if (!pane) { perror("Could not allocate pane "); return NULL; }
  180. tilepane_tileset_(pane, set);
  181. pane->gridwide = gridwide;
  182. pane->gridhigh = gridhigh;
  183. pane->realwide = TILE_W * pane->gridwide;
  184. pane->realhigh = TILE_H * pane->gridhigh;
  185. // declare background, etc, empty
  186. // Precalculate dimensions...
  187. // And allocate space for the tiles and tile indices.
  188. pane->tiles = pointergrid_new(gridwide, gridhigh);
  189. if(!pane->tiles) {
  190. perror("Could not allocate tiles matrix ");
  191. return NULL;
  192. }
  193. pane->blends = pointergrid_new(gridwide, gridhigh);
  194. if(!pane->blends) {
  195. perror("Could not allocate blends matrix ");
  196. return NULL;
  197. }
  198. pane->flags = pointergrid_new(gridwide, gridhigh);
  199. if(!pane->flags) {
  200. perror("Could not allocate flagss matrix ");
  201. return NULL;
  202. }
  203. // null the tiles and blends
  204. pointergrid_nullall(pane->tiles, NULL);
  205. pointergrid_nullall(pane->blends, NULL);
  206. // Zero the flags
  207. pointergrid_zero_all(pane->flags);
  208. return pane;
  209. }
  210. /** Makes new gy pane. */
  211. Tilepane * tilepane_new(Tileset * set, int gridwide, int gridhigh) {
  212. Tilepane * pane = STRUCT_ALLOC(Tilepane);
  213. return tilepane_init(pane, set, gridwide, gridhigh);
  214. }
  215. /** Returns the width of the pane in grid units. Returns -1 on error. */
  216. int tilepane_gridwide(Tilepane * pane) {
  217. if(!pane) return -1;
  218. return pane->gridwide;
  219. }
  220. /** Returns the height of the pane in grid units. Returns -1 on error. */
  221. int tilepane_gridhigh(Tilepane * pane) {
  222. if(!pane) return -1;
  223. return pane->gridhigh;
  224. }
  225. /** Returns the width of the pane's tiles in pixels. Returns -1 on error. */
  226. int tilepane_tilewide(Tilepane * pane) {
  227. if(!pane) return -1;
  228. return TILE_W;
  229. }
  230. /** Returns the height of the pane's tiles in pixels. Returns -1 on error. */
  231. int tilepane_tilehigh(Tilepane * pane) {
  232. if(!pane) return -1;
  233. return TILE_H;
  234. }
  235. /** Returns the width of the pane in pixels. Returns -1 on error. */
  236. int tilepane_wide(Tilepane * pane) {
  237. if(!pane) return -1;
  238. return pane->realwide;
  239. }
  240. /** Returns the height of the pane in pixels. Returns -1 on error. */
  241. int tilepane_high(Tilepane * pane) {
  242. if(!pane) return -1;
  243. return pane->realhigh;
  244. }
  245. /** Returns TRUE if the given gridx and gridy are outside the grid
  246. * Returns FALSE if inside the grid.
  247. */
  248. int tilepane_outsidegrid(Tilepane * pane, int gridx, int gridy) {
  249. if (!pane) return TRUE;
  250. if ((gridx < 0) || (gridy < 0)) return TRUE;
  251. if ((gridx >= pane->gridwide) || (gridx >= pane->gridhigh)) return TRUE;
  252. return FALSE;
  253. }
  254. /** Sets the tile at the given location to the given Tile pointer,
  255. * which may be NULL. Returns the tile thus set, or NULL on error.
  256. */
  257. Tile * tilepane_set(Tilepane * pane,
  258. int gridx, int gridy, Tile * tile) {
  259. if (tilepane_outsidegrid(pane, gridx, gridy)) return NULL;
  260. pointergrid_put(pane->tiles, gridx, gridy, tile);
  261. return tile;
  262. }
  263. /** Returns the tile in the pane's grid at the given grid coordinates,
  264. * returns NULL if the fcoordinates are out of bounds or if it was an empty tile.
  265. */
  266. Tile * tilepane_get(Tilepane * pane, int gridx, int gridy) {
  267. if (pointergrid_outofrange(pane->tiles, gridx, gridy)) return NULL;
  268. return pointergrid_getraw(pane->tiles, gridx, gridy);
  269. }
  270. /** Returns the ile index in the pane's grid at the given grid coordinates,
  271. * Returns -1 on error or if no tile is there, and a nonnegative index if a
  272. * tile was found.
  273. */
  274. int tilepane_getindex(Tilepane * pane, int gridx, int gridy) {
  275. Tile * tile = tilepane_get(pane, gridx, gridy);
  276. return tile_index(tile);
  277. }
  278. /** Sets the drawing flags at the given location. Returns the flags thus set,
  279. * or -1 on error.
  280. */
  281. int tilepane_set_flags(Tilepane * pane,
  282. int gridx, int gridy, int flags) {
  283. if (tilepane_outsidegrid(pane, gridx, gridy)) return -1;
  284. pointergrid_put_int(pane->flags, gridx, gridy, flags);
  285. return flags;
  286. }
  287. /** Gets the flags for the given tile coords.
  288. */
  289. int tilepane_get_flags(Tilepane * pane, int gridx, int gridy) {
  290. if (pointergrid_outofrange(pane->tiles, gridx, gridy)) return -1;
  291. return pointergrid_get_raw_int(pane->tiles, gridx, gridy);
  292. }
  293. /** Sets the drawing flags at the given location. Does no error checking
  294. * whatsoever, use only in speed critical parts where the inputs are
  295. * guaranteed to be correct.
  296. */
  297. void tilepane_set_raw_flags(Tilepane * pane, int gridx, int gridy, int flags) {
  298. pointergrid_put_raw_int(pane->flags, gridx, gridy, flags);
  299. }
  300. /** Gets the flags for the given tile coords.
  301. * Does no error checking
  302. * whatsoever, use only in speed critical parts where the inputs are
  303. * guaranteed to be correct.
  304. */
  305. int tilepane_get_raw_flags(Tilepane * pane, int gridx, int gridy) {
  306. return pointergrid_get_raw_int(pane->flags, gridx, gridy);
  307. }
  308. /** Sets the tile in the given rectangle to the given Tile pointer,
  309. * which may be NULL. Returns the tuile set, or NULL on error.
  310. */
  311. Tile * tilepane_rect(Tilepane * pane,
  312. int gridx, int gridy, int gridw, int gridh,
  313. Tile * tile) {
  314. int ii, jj;
  315. for (jj = gridy; jj < (gridy + gridh) ; jj++){
  316. for (ii = gridx; ii < (gridx + gridw) ; ii++) {
  317. tilepane_set(pane, ii, jj, tile);
  318. }
  319. }
  320. return tile;
  321. }
  322. /** Fills the while tile pane with the given tile.
  323. Returns tile if ok, or NULL on error. */
  324. Tile * tilepane_fill(Tilepane * pane, Tile * tile) {
  325. int ww = tilepane_gridwide(pane);
  326. int hh = tilepane_gridhigh(pane);
  327. return tilepane_rect(pane, 0, 0, ww, hh, tile);
  328. }
  329. /** Gets the current autogenerated blend image for this tile pane. */
  330. Image * tilepane_get_blend(Tilepane * pane, int tx, int ty) {
  331. return (Image*) pointergrid_fetch(pane->blends, tx, ty);
  332. }
  333. /** Sets the current autogenerated blend image for this tile pane.
  334. * Mercilessly overwrites (and leaks) the previous image at the same location if
  335. * any.
  336. */
  337. Image * tilepane_set_blend_raw(Tilepane * pane, int tx, int ty, Image * blend) {
  338. return (Image*) pointergrid_store(pane->blends, tx, ty, blend);
  339. }
  340. // Since tile size is 32, shifts can be used in stead of multiplications.
  341. #define TIMES_TILEWIDE(V) ((V) << 5)
  342. #define TIMES_TILEHIGH(V) ((V) << 5)
  343. /* Set up a perspective transform. We make the screen span
  344. * 180 vertical units with square pixel aspect and 90° vertical
  345. * FoV.
  346. */
  347. static void setup_3d_projection()
  348. {
  349. ALLEGRO_DISPLAY *display = al_get_current_display();
  350. int dw = al_get_display_width(display);
  351. int dh = al_get_display_height(display);
  352. ALLEGRO_TRANSFORM projection;
  353. float x, y, c;
  354. al_identity_transform(&projection);
  355. /* Then we tilt everything backwards 90 degrees. */
  356. al_rotate_transform_3d(&projection, 1, 0, 0,
  357. 90 * ALLEGRO_PI / 180.0);
  358. /* And finally move it down so the 0 position ends up
  359. * at the bottom of the screen.
  360. */
  361. al_translate_transform_3d(&projection, 0, 180, 0);
  362. al_perspective_transform(&projection, -180 * dw / dh, -180, 180,
  363. 180 * dw / dh, 180, 3000);
  364. al_use_projection_transform(&projection);
  365. }
  366. static void end_3d_projection()
  367. {
  368. ALLEGRO_DISPLAY *display = al_get_current_display();
  369. ALLEGRO_TRANSFORM projection;
  370. al_identity_transform(&projection);
  371. al_use_projection_transform(&projection);
  372. }
  373. /** Draws the blends of the tile pane, with the part that camera describes in view
  374. * to the current active display.
  375. */
  376. void tilepane_draw_blends(Tilepane * pane, Camera * camera) {
  377. // Copy everything to the stack since that should be faster than always
  378. // referring to pointers.
  379. int gridwide = pane->gridwide;
  380. int gridhigh = pane->gridhigh;
  381. int tilewide = TILE_W;
  382. int tilehigh = TILE_H;
  383. int x = (int) camera_at_x(camera);
  384. int y = (int) camera_at_y(camera);
  385. int txstart = x / tilewide;
  386. int tystart = y / tilehigh;
  387. int xtilestop = (camera_w(camera) / tilewide) + 1;
  388. int ytilestop = (camera_h(camera) / tilehigh) + 1;
  389. int txstop = xtilestop + txstart;
  390. int tystop = ytilestop + tystart;
  391. int drawx = 0;
  392. int drawy = 0;
  393. int ty_index = 0;
  394. int tx_index = 0;
  395. int realwide = pane->realwide;
  396. int realhigh = pane->realhigh;
  397. void * row = NULL;
  398. Tile * tile = NULL;
  399. Image* blend = NULL;
  400. if (txstart >= realwide) return;
  401. if (tystart >= realhigh) return;
  402. // hold drawing since all tile draws come from the same tile sheet
  403. // al_hold_bitmap_drawing(TRUE);
  404. txstart = (txstart < 0) ? 0 : txstart;
  405. tystart = (tystart < 0) ? 0 : tystart;
  406. txstop = (txstop > gridwide) ? gridwide : txstop;
  407. tystop = (tystop > gridhigh) ? gridhigh : tystop;
  408. drawy = -y + TIMES_TILEHIGH(tystart-1);
  409. for (ty_index = tystart; ty_index < tystop ; ty_index++) {
  410. drawy += tilehigh;
  411. drawx = -x + TIMES_TILEWIDE(txstart-1);
  412. row = pointergrid_rowraw(pane->tiles, ty_index);
  413. if (!row) continue;
  414. for(tx_index = txstart; tx_index < txstop ; tx_index++) {
  415. drawx += tilewide;
  416. blend = pointergrid_getraw(pane->blends, tx_index, ty_index);
  417. if (blend) {
  418. al_draw_bitmap(blend, drawx, drawy, 0);
  419. }
  420. }
  421. }
  422. }
  423. /** Draws the tile pane, with x and y as the top left corner,
  424. * to the current active display X and y may be negative.
  425. */
  426. void tilepane_draw(Tilepane * pane, Camera * camera) {
  427. // Copy everything to the stack since that should be faster than always
  428. // referring to pointers.
  429. int gridwide = pane->gridwide;
  430. int gridhigh = pane->gridhigh;
  431. int tilewide = TILE_W;
  432. int tilehigh = TILE_H;
  433. int x = (int) camera_at_x(camera);
  434. int y = (int) camera_at_y(camera);
  435. int txstart = x / tilewide;
  436. int tystart = y / tilehigh;
  437. int xtilestop = (camera_w(camera) / tilewide) + 1;
  438. int ytilestop = (camera_h(camera) / tilehigh) + 1;
  439. int txstop = xtilestop + txstart;
  440. int tystop = ytilestop + tystart;
  441. int drawx = 0;
  442. int drawy = 0;
  443. int ty_index = 0;
  444. int tx_index = 0;
  445. int realwide = pane->realwide;
  446. int realhigh = pane->realhigh;
  447. int drawflags = 0;
  448. void * row = NULL;
  449. Tile * tile = NULL;
  450. Image* blend = NULL;
  451. Color color = al_map_rgb(200,200,200);
  452. Color color2 = al_map_rgb(0,50,0);
  453. if (txstart >= realwide) return;
  454. if (tystart >= realhigh) return;
  455. // hold drawing since all tile draws come from the same tile sheet
  456. al_hold_bitmap_drawing(TRUE);
  457. txstart = (txstart < 0) ? 0 : txstart;
  458. tystart = (tystart < 0) ? 0 : tystart;
  459. txstop = (txstop > gridwide) ? gridwide : txstop;
  460. tystop = (tystop > gridhigh) ? gridhigh : tystop;
  461. drawy = -y + TIMES_TILEHIGH(tystart-1);
  462. for (ty_index = tystart; ty_index < tystop ; ty_index++) {
  463. drawy += tilehigh;
  464. drawx = -x + TIMES_TILEWIDE(txstart-1);
  465. row = pointergrid_rowraw(pane->tiles, ty_index);
  466. if(!row) continue;
  467. for(tx_index = txstart; tx_index < txstop ; tx_index++) {
  468. drawx += tilewide;
  469. tile = pointergrid_getraw(pane->tiles, tx_index, ty_index);
  470. // row[tx_index];
  471. // Null tile will not be drawn by tile_draw
  472. /* tile_draw(tile, drawx, drawy); */
  473. if(tile) {
  474. drawflags = tilepane_get_raw_flags(pane, tx_index, ty_index);
  475. tile_draw(tile, drawx, drawy, drawflags);
  476. }
  477. }
  478. }
  479. // Let go of hold
  480. al_hold_bitmap_drawing(FALSE);
  481. }
  482. /** Draws the shadows that tile pane pane casts onto the pane pane_below
  483. * with the camera delimiting the view.
  484. * On a classic tile map the bottom is to the south, so this function draws
  485. * "classic" shadows cast as if the sun were in the south-west,
  486. * with the shadows pointing north-east.
  487. */
  488. void tilepane_draw_shadows_of(Tilepane * pane, Tilepane * pane_below, Camera * camera) {
  489. // Copy everything to the stack since that should be faster than always
  490. // referring to pointers.
  491. int gridwide = pane->gridwide;
  492. int gridhigh = pane->gridhigh;
  493. int tilewide = TILE_W;
  494. int tilehigh = TILE_H;
  495. int x = (int) camera_at_x(camera);
  496. int y = (int) camera_at_y(camera);
  497. int txstart = -1 + x / tilewide;
  498. int tystart = -1 + y / tilehigh;
  499. int xtilestop = (camera_w(camera) / tilewide) + 3;
  500. int ytilestop = (camera_h(camera) / tilehigh) + 3;
  501. int txstop = xtilestop + txstart;
  502. int tystop = ytilestop + tystart;
  503. int drawx = 0;
  504. int drawy = 0;
  505. int ty_index = 0;
  506. int tx_index = 0;
  507. int realwide = pane->realwide;
  508. int realhigh = pane->realhigh;
  509. int shadowtype = 0;
  510. void * row = NULL;
  511. Tile * tile = NULL;
  512. Tile * aid_tile = NULL;
  513. Tile * edge_tile= NULL;
  514. Tile * low_tile = NULL;
  515. float polygon[8];
  516. Color shadowcol = al_map_rgba(0, 0, 16, 64);
  517. if (txstart >= realwide) return;
  518. if (tystart >= realhigh) return;
  519. txstart = (txstart < 0) ? 0 : txstart;
  520. tystart = (tystart < 0) ? 0 : tystart;
  521. txstop = (txstop > gridwide) ? gridwide : txstop;
  522. tystop = (tystop > gridhigh) ? gridhigh : tystop;
  523. drawy = -y + TIMES_TILEHIGH(tystart-1);
  524. for (ty_index = tystart; ty_index < tystop ; ty_index++) {
  525. drawy += tilehigh;
  526. drawx = -x + TIMES_TILEWIDE(txstart-1);
  527. row = pointergrid_rowraw(pane->tiles, ty_index);
  528. if (!row) continue;
  529. for (tx_index = txstart; tx_index < txstop ; tx_index++) {
  530. drawx += tilewide;
  531. tile = pointergrid_getraw(pane->tiles, tx_index, ty_index);
  532. aid_tile = tilepane_get(pane, tx_index - 1, ty_index + 1);
  533. /* Cast no shadow if not set to do so */
  534. if ((!tile) || (!tile_shadow(tile))) {
  535. continue;
  536. }
  537. edge_tile = tilepane_get(pane, tx_index + 1, ty_index - 1);
  538. aid_tile = tilepane_get(pane, tx_index + 1, ty_index);
  539. if (edge_tile && (tile_isflag(edge_tile, TILE_WALL))) {
  540. /* different shadow shape in this case (trapezium, no paralellogram) */
  541. shadowtype = 1;
  542. } else {
  543. shadowtype = 0;
  544. }
  545. /* Only cast a shadow to the east if no solid tile next to self.
  546. * Shadow is a parallelogram to simplify overlaps.
  547. */
  548. if (!aid_tile || !(tile_isflag(aid_tile, TILE_WALL))) {
  549. low_tile = tilepane_get(pane_below, tx_index + 1, ty_index);
  550. if (low_tile && (tile_shadow_mask(low_tile) != 1)) {
  551. polygon[0] = drawx + 32; polygon[1] = drawy;
  552. polygon[2] = drawx + 32; polygon[3] = drawy + 32;
  553. polygon[4] = drawx + 48; polygon[5] = drawy + 16;
  554. polygon[6] = drawx + 48; polygon[7] = drawy - 16;
  555. if (shadowtype == 1) {
  556. polygon[7] = drawy;
  557. }
  558. al_draw_filled_polygon(polygon, 4, shadowcol);
  559. }
  560. }
  561. aid_tile = tilepane_get(pane, tx_index, ty_index - 1);
  562. /* Only cast a shadow to the north if no solid tile above to self.
  563. * Shadow is a parallelogram to simplify overlaps.
  564. */
  565. if (!aid_tile || !(tile_isflag(aid_tile, TILE_WALL))) {
  566. low_tile = tilepane_get(pane_below, tx_index + 1, ty_index);
  567. if (low_tile && (tile_shadow_mask(low_tile) != 1)) {
  568. polygon[0] = drawx ; polygon[1] = drawy;
  569. polygon[2] = drawx + 32; polygon[3] = drawy;
  570. polygon[4] = drawx + 48; polygon[5] = drawy - 16;
  571. polygon[6] = drawx + 16; polygon[7] = drawy - 16;
  572. if (shadowtype == 1) {
  573. polygon[4] = drawx + 32;
  574. }
  575. al_draw_filled_polygon(polygon, 4, shadowcol);
  576. }
  577. }
  578. }
  579. }
  580. // Now, after the hold are released , draw the blends.
  581. // tilepane_draw_blends(pane, camera);
  582. }
  583. /** Updates the tile pane. Curently does nothing, but this may change. */
  584. void tilepane_update(Tilepane * pane, double dt) {
  585. (void) pane;
  586. (void) dt;
  587. }
  588. /** Sets this Tilepane's tile set. */
  589. Tileset * tilepane_tileset_(Tilepane * pane, Tileset * set) {
  590. if (!pane) return NULL;
  591. return pane->set = set;
  592. }
  593. /** Gets this Tilepane's tile set. */
  594. Tileset * tilepane_tileset(Tilepane * pane) {
  595. if (!pane) return NULL;
  596. return pane->set;
  597. }
  598. /** Gets a tile from a the tilepane's tile set by it's tile id. **/
  599. Tile * tilepane_getfromset(Tilepane * pane, int index) {
  600. Tileset * set = tilepane_tileset(pane);
  601. if (!set) return NULL;
  602. if (index < 0) return NULL;
  603. return tileset_get(set, index);
  604. }
  605. /** Sets the tile at the given location to tile at index index in the
  606. * Tilepane's Tileset, in index < 0, sets NULL; Returns the Tile * object
  607. * thus set.
  608. */
  609. Tile* tilepane_setindex(Tilepane * pane,
  610. int gridx, int gridy, int index) {
  611. Tile * tile = tilepane_getfromset(pane, index);
  612. return tilepane_set(pane, gridx, gridy, tile);
  613. }
  614. /** Sets the tile in the given rectangle to the given Tile index,
  615. * Returns the tile thus set, or NULL on error or if the index was negative.
  616. */
  617. Tile * tilepane_rectindex(Tilepane * pane,
  618. int gridx, int gridy, int gridw, int gridh,
  619. int index) {
  620. Tile * tile = tilepane_getfromset(pane, index);
  621. return tilepane_rect(pane, gridx, gridy, gridw, gridh, tile);
  622. }
  623. /** Fills the while tile pane with the given tile index */
  624. Tile * tilepane_fillindex(Tilepane * pane, int index) {
  625. Tile * tile = tilepane_getfromset(pane, index);
  626. return tilepane_fill(pane, tile);
  627. }
  628. struct TileblendOffset {
  629. int tx;
  630. int ty;
  631. };
  632. static struct TileblendOffset tile_blend_offsets[] = {
  633. {-1, -1}, /* TILE_BLEND_NORTHWEST 0 */
  634. { 0, -1}, /* TILE_BLEND_NORTH 1 */
  635. { 1, -1}, /* TILE_BLEND_NORTHEAST 2 */
  636. {-1, 0}, /* TILE_BLEND_WEST 3 */
  637. { 1, 0}, /* TILE_BLEND_EAST 4 */
  638. {-1, 1}, /* TILE_BLEND_SOUTHWEST 5 */
  639. { 0, 1}, /* TILE_BLEND_SOUTH 6 */
  640. { 1, 1}, /* TILE_BLEND_SOUTHEAST 7 */
  641. };
  642. /*
  643. Wrapper around Allegro bitmap creation.
  644. */
  645. ALLEGRO_BITMAP *
  646. eruta_create_bitmap(int w, int h, int flags) {
  647. ALLEGRO_BITMAP * result;
  648. int oldbflags, oldformat;
  649. oldbflags = al_get_new_bitmap_flags();
  650. oldformat = al_get_new_bitmap_format();
  651. al_set_new_bitmap_flags(flags);
  652. // al_set_new_bitmap_format(al_get_display_format(al_get_current_display()));
  653. /* Somehow, al_create_bitmap is very slow here... */
  654. result = al_create_bitmap(w, h);
  655. al_set_new_bitmap_flags(oldbflags);
  656. al_set_new_bitmap_format(oldformat);
  657. return result;
  658. }
  659. /** Sets up automatic blending for this pane and this tile in the pane. */
  660. bool
  661. tilepane_init_blend_tile(Tilepane * self, int index, int x, int y, Tile * tile) {
  662. int bindex, yn, xn;
  663. void * aid = NULL;
  664. Image * target= NULL;
  665. Image * blend = NULL;
  666. Image * result = NULL;
  667. Tile * aidtile;
  668. int oldbflags, oldformat;
  669. int tileprio, aidprio;
  670. static int created = 0;
  671. (void) index;
  672. blend = tilepane_get_blend(self, x, y);
  673. /* Destroy old blend if any */
  674. if (blend) {
  675. al_destroy_bitmap(blend);
  676. blend = NULL;
  677. tilepane_set_blend_raw(self, x, y, NULL);
  678. }
  679. target = al_get_target_bitmap();
  680. tileprio = tile_blend(tile);
  681. /* Look for the tiles around self. */
  682. for (bindex = 0; bindex < TILE_BLEND_DIRECTION_MAX ; bindex++) {
  683. struct TileblendOffset offset = tile_blend_offsets[bindex];
  684. /* Begin by setting NULL to mean "no blend tile there" */
  685. yn = y + offset.ty;
  686. xn = x + offset.tx;
  687. aidtile = tilepane_get(self, xn, yn);
  688. /* No tile there, no blend. */
  689. if (!aidtile) continue;
  690. aidprio = tile_blend(aidtile);
  691. /* Only blend if blend priority of other is higher. */
  692. if (aidprio <= tileprio) continue;
  693. /* If we get here, create a blend bitmap.
  694. * This is done on demand, because this function is called once for every
  695. * tile in the tile map.
  696. */
  697. if (!blend) {
  698. blend = eruta_create_bitmap(TILE_W, TILE_H, ALLEGRO_CONVERT_BITMAP);
  699. if (!blend) return FALSE;
  700. /* Set resulting bitmap as blend tile. */
  701. tilepane_set_blend_raw(self, x, y, blend);
  702. al_set_target_bitmap(blend);
  703. al_clear_to_color(al_map_rgba_f(0,0,0,0));
  704. }
  705. tilepane_prepare_blend(blend, tile, aidtile, bindex);
  706. /* break; Interestingly enough, this break doesn't speed up
  707. * blend generation AT ALL. The slowdown seems to be due to
  708. * setting up the video bitmap, or perhaps the iteration?.
  709. */
  710. }
  711. /* Restore original target bitmap. */
  712. al_set_target_bitmap(target);
  713. /* That's it. */
  714. /* I tried to speed this by using an extra memory bitmap
  715. for the intermediate blits, but that interestingly enough
  716. slowed down the generation by about 3 times (from 2 to 6 seconds) */
  717. return TRUE;
  718. }
  719. /* For the sake of loading the masks. */
  720. ALLEGRO_BITMAP * fifi_load_bitmap(const char * vpath);
  721. #define MASK_SIDE_W 16
  722. #define MASK_SIDE_H 16
  723. #define MASK_CORNER_W 16
  724. #define MASK_CORNER_H 16
  725. #define MASK_W 8
  726. #define MASK_H 8
  727. /* Sets up the tile blend masks if needed. */
  728. bool tilepane_init_masks() {
  729. int index;
  730. char buf[64];
  731. Image * image1, * image2, *target;
  732. Color solid, transparent, color;
  733. /* Already initialized. */
  734. if (tile_blend_masks[0][0]) return TRUE;
  735. /* Load the masks */
  736. for (index = 0; index < TILE_BLEND_TYPE_MAX; index ++) {
  737. sprintf(buf, "/image/masks/corner_mask_%d.png", index);
  738. image1 = fifi_load_bitmap(buf);
  739. sprintf(buf, "/image/masks/side_mask_%d.png", index);
  740. image2 = fifi_load_bitmap(buf);
  741. tile_blend_masks[index][TILE_BLEND_CORNER] = image1;
  742. tile_blend_masks[index][TILE_BLEND_SIDE] = image2;
  743. }
  744. return TRUE;
  745. };
  746. /** Sets up automatic blending for this tile pane. */
  747. bool tilepane_init_blend(Tilepane * self, int index) {
  748. double stop, start;
  749. int x, y, w, h;
  750. if (!self) return FALSE;
  751. if (!self->blends) return FALSE;
  752. /* Only blend some levels... */
  753. if (index > 4) return FALSE;
  754. w = tilepane_gridwide(self);
  755. h = tilepane_gridhigh(self);
  756. start = al_get_time();
  757. /* Load the masks. */
  758. tilepane_init_masks();
  759. stop = al_get_time();
  760. LOG_NOTE("Loading masks op pane %p took %f seconds\n", self, stop - start);
  761. start = al_get_time();
  762. /* And do the blends. */
  763. for (y = 0 ; y < h; y++) {
  764. for (x = 0; x < w; x++) {
  765. Tile * tile = tilepane_get(self, x, y);
  766. if (!tile) continue;
  767. if(tile_blend(tile) < 1) continue;
  768. tilepane_init_blend_tile(self, index, x, y, tile);
  769. }
  770. }
  771. stop = al_get_time();
  772. LOG_NOTE("Preparing blends of pane %p took %f seconds\n", self, stop - start);
  773. return TRUE;
  774. }
  775. /* Generic blend masks for every tile map. */