1 /*
2 * This file is part of EasyRPG Player.
3 *
4 * EasyRPG Player is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * EasyRPG Player is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 // Headers
19 #include <cstring>
20 #include <cmath>
21 #include "tilemap_layer.h"
22 #include "output.h"
23 #include "player.h"
24 #include "map_data.h"
25 #include "main_data.h"
26 #include "bitmap.h"
27 #include "compiler.h"
28 #include "game_map.h"
29 #include "game_system.h"
30 #include "drawable_mgr.h"
31 #include "baseui.h"
32
33 // Blocks subtiles IDs
34 // Mess with this code and you will die in 3 days...
35 // [tile-id][row][col]
36 static constexpr int8_t BlockA_Subtiles_IDS[47][2][2] = {
37 #define N -1
38 {{N, N}, {N, N}},
39 {{3, N}, {N, N}},
40 {{N, 3}, {N, N}},
41 {{3, 3}, {N, N}},
42 {{N, N}, {N, 3}},
43 {{3, N}, {N, 3}},
44 {{N, 3}, {N, 3}},
45 {{3, 3}, {N, 3}},
46 {{N, N}, {3, N}},
47 {{3, N}, {3, N}},
48 {{N, 3}, {3, N}},
49 {{3, 3}, {3, N}},
50 {{N, N}, {3, 3}},
51 {{3, N}, {3, 3}},
52 {{N, 3}, {3, 3}},
53 {{3, 3}, {3, 3}},
54 {{1, N}, {1, N}},
55 {{1, 3}, {1, N}},
56 {{1, N}, {1, 3}},
57 {{1, 3}, {1, 3}},
58 {{2, 2}, {N, N}},
59 {{2, 2}, {N, 3}},
60 {{2, 2}, {3, N}},
61 {{2, 2}, {3, 3}},
62 {{N, 1}, {N, 1}},
63 {{N, 1}, {3, 1}},
64 {{3, 1}, {N, 1}},
65 {{3, 1}, {3, 1}},
66 {{N, N}, {2, 2}},
67 {{3, N}, {2, 2}},
68 {{N, 3}, {2, 2}},
69 {{3, 3}, {2, 2}},
70 {{1, 1}, {1, 1}},
71 {{2, 2}, {2, 2}},
72 {{0, 2}, {1, N}},
73 {{0, 2}, {1, 3}},
74 {{2, 0}, {N, 1}},
75 {{2, 0}, {3, 1}},
76 {{N, 1}, {2, 0}},
77 {{3, 1}, {2, 0}},
78 {{1, N}, {0, 2}},
79 {{1, 3}, {0, 2}},
80 {{0, 0}, {1, 1}},
81 {{0, 2}, {0, 2}},
82 {{1, 1}, {0, 0}},
83 {{2, 0}, {2, 0}},
84 {{0, 0}, {0, 0}}
85 #undef N
86 };
87
88 // [tile-id][row][col][x/y]
89 static constexpr uint8_t BlockD_Subtiles_IDS[50][2][2][2] = {
90 // T-L T-R B-L B-R
91 {{{1, 2}, {1, 2}}, {{1, 2}, {1, 2}}},
92 {{{2, 0}, {1, 2}}, {{1, 2}, {1, 2}}},
93 {{{1, 2}, {2, 0}}, {{1, 2}, {1, 2}}},
94 {{{2, 0}, {2, 0}}, {{1, 2}, {1, 2}}},
95 {{{1, 2}, {1, 2}}, {{1, 2}, {2, 0}}},
96 {{{2, 0}, {1, 2}}, {{1, 2}, {2, 0}}},
97 {{{1, 2}, {2, 0}}, {{1, 2}, {2, 0}}},
98 {{{2, 0}, {2, 0}}, {{1, 2}, {2, 0}}},
99 {{{1, 2}, {1, 2}}, {{2, 0}, {1, 2}}},
100 {{{2, 0}, {1, 2}}, {{2, 0}, {1, 2}}},
101 {{{1, 2}, {2, 0}}, {{2, 0}, {1, 2}}},
102 {{{2, 0}, {2, 0}}, {{2, 0}, {1, 2}}},
103 {{{1, 2}, {1, 2}}, {{2, 0}, {2, 0}}},
104 {{{2, 0}, {1, 2}}, {{2, 0}, {2, 0}}},
105 {{{1, 2}, {2, 0}}, {{2, 0}, {2, 0}}},
106 {{{2, 0}, {2, 0}}, {{2, 0}, {2, 0}}},
107 {{{0, 2}, {0, 2}}, {{0, 2}, {0, 2}}},
108 {{{0, 2}, {2, 0}}, {{0, 2}, {0, 2}}},
109 {{{0, 2}, {0, 2}}, {{0, 2}, {2, 0}}},
110 {{{0, 2}, {2, 0}}, {{0, 2}, {2, 0}}},
111 {{{1, 1}, {1, 1}}, {{1, 1}, {1, 1}}},
112 {{{1, 1}, {1, 1}}, {{1, 1}, {2, 0}}},
113 {{{1, 1}, {1, 1}}, {{2, 0}, {1, 1}}},
114 {{{1, 1}, {1, 1}}, {{2, 0}, {2, 0}}},
115 {{{2, 2}, {2, 2}}, {{2, 2}, {2, 2}}},
116 {{{2, 2}, {2, 2}}, {{2, 0}, {2, 2}}},
117 {{{2, 0}, {2, 2}}, {{2, 2}, {2, 2}}},
118 {{{2, 0}, {2, 2}}, {{2, 0}, {2, 2}}},
119 {{{1, 3}, {1, 3}}, {{1, 3}, {1, 3}}},
120 {{{2, 0}, {1, 3}}, {{1, 3}, {1, 3}}},
121 {{{1, 3}, {2, 0}}, {{1, 3}, {1, 3}}},
122 {{{2, 0}, {2, 0}}, {{1, 3}, {1, 3}}},
123 {{{0, 2}, {2, 2}}, {{0, 2}, {2, 2}}},
124 {{{1, 1}, {1, 1}}, {{1, 3}, {1, 3}}},
125 {{{0, 1}, {0, 1}}, {{0, 1}, {0, 1}}},
126 {{{0, 1}, {0, 1}}, {{0, 1}, {2, 0}}},
127 {{{2, 1}, {2, 1}}, {{2, 1}, {2, 1}}},
128 {{{2, 1}, {2, 1}}, {{2, 0}, {2, 1}}},
129 {{{2, 3}, {2, 3}}, {{2, 3}, {2, 3}}},
130 {{{2, 0}, {2, 3}}, {{2, 3}, {2, 3}}},
131 {{{0, 3}, {0, 3}}, {{0, 3}, {0, 3}}},
132 {{{0, 3}, {2, 0}}, {{0, 3}, {0, 3}}},
133 {{{0, 1}, {2, 1}}, {{0, 1}, {2, 1}}},
134 {{{0, 1}, {0, 1}}, {{0, 3}, {0, 3}}},
135 {{{0, 3}, {2, 3}}, {{0, 3}, {2, 3}}},
136 {{{2, 1}, {2, 1}}, {{2, 3}, {2, 3}}},
137 {{{0, 1}, {2, 1}}, {{0, 3}, {2, 3}}},
138 {{{1, 2}, {1, 2}}, {{1, 2}, {1, 2}}},
139 {{{1, 2}, {1, 2}}, {{1, 2}, {1, 2}}},
140 {{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}}
141 };
142
TilemapLayer(int ilayer)143 TilemapLayer::TilemapLayer(int ilayer) :
144 substitutions(Game_Map::GetTilesLayer(ilayer)),
145 layer(ilayer),
146 // SubLayer for the tiles without Wall or Above passability
147 // Its z-value should be under z of the events in the lower layer
148 lower_layer(this, Priority_TilesetBelow + layer),
149 // SubLayer for the tiles with Wall or Above passability
150 // Its z-value should be between the z of the events in the upper layer and the hero
151 upper_layer(this, Priority_TilesetAbove + layer)
152 {
153 }
154
155 // This setup of having an always inlined DrawTile() which dispatches to DrawTileImpl()
156 // was created intentionally. Inlining the transparency check was measured and shown
157 // to provide a performance improvement
158 EP_ALWAYS_INLINE
DrawTile(Bitmap & dst,Bitmap & tileset,Bitmap & tone_tileset,int x,int y,int row,int col,uint32_t tone_hash,bool allow_fast_blit)159 void TilemapLayer::DrawTile(Bitmap& dst, Bitmap& tileset, Bitmap& tone_tileset, int x, int y, int row, int col, uint32_t tone_hash, bool allow_fast_blit) {
160 auto op = tileset.GetTileOpacity(col, row);
161 if (op != ImageOpacity::Transparent) {
162 DrawTileImpl(dst, tileset, tone_tileset, x, y, row, col, tone_hash, op, allow_fast_blit);
163 }
164 }
165
DrawTileImpl(Bitmap & dst,Bitmap & tileset,Bitmap & tone_tileset,int x,int y,int row,int col,uint32_t tone_hash,ImageOpacity op,bool allow_fast_blit)166 void TilemapLayer::DrawTileImpl(Bitmap& dst, Bitmap& tileset, Bitmap& tone_tileset, int x, int y, int row, int col, uint32_t tone_hash, ImageOpacity op, bool allow_fast_blit) {
167
168 auto rect = Rect{ col * TILE_SIZE, row * TILE_SIZE, TILE_SIZE, TILE_SIZE };
169
170 auto* src = &tileset;
171
172 // Create tone changed tile
173 if (tone != Tone()) {
174 if (chipset_tone_tiles.insert(tone_hash).second) {
175 tone_tileset.ToneBlit(col * TILE_SIZE, row * TILE_SIZE, tileset, rect, tone, Opacity::Opaque());
176 }
177 src = &tone_tileset;
178 }
179
180 bool use_fast_blit = fast_blit && allow_fast_blit;
181 if (op == ImageOpacity::Opaque || use_fast_blit) {
182 dst.BlitFast(x, y, *src, rect, 255);
183 } else {
184 dst.Blit(x, y, *src, rect, 255);
185 }
186 }
187
MakeFTileHash(int id)188 static uint32_t MakeFTileHash(int id) {
189 return static_cast<uint32_t>(id);
190 }
191
MakeETileHash(int id)192 static uint32_t MakeETileHash(int id) {
193 return static_cast<uint32_t>(id | (1 << 24));
194 }
195
MakeDTileHash(int id)196 static uint32_t MakeDTileHash(int id) {
197 return static_cast<uint32_t>(id | (2 << 24));
198 }
199
MakeCTileHash(int id,int anim_step)200 static uint32_t MakeCTileHash(int id, int anim_step) {
201 return static_cast<uint32_t>((id + (anim_step << 12)) | (3 << 24));
202 }
203
MakeAbTileHash(int id,int anim_step)204 static uint32_t MakeAbTileHash(int id, int anim_step) {
205 return static_cast<uint32_t>((id + (anim_step << 12)) | (4 << 24));
206 }
207
Draw(Bitmap & dst,int z_order)208 void TilemapLayer::Draw(Bitmap& dst, int z_order) {
209 // Get the number of tiles that can be displayed on window
210 int tiles_x = (int)ceil(DisplayUi->GetWidth() / (float)TILE_SIZE);
211 int tiles_y = (int)ceil(DisplayUi->GetHeight() / (float)TILE_SIZE);
212
213 // If ox or oy are not equal to the tile size draw the next tile too
214 // to prevent black (empty) tiles at the borders
215 if (ox % TILE_SIZE != 0) {
216 ++tiles_x;
217 }
218 if (oy % TILE_SIZE != 0) {
219 ++tiles_y;
220 }
221
222 const bool loop_h = Game_Map::LoopHorizontal();
223 const bool loop_v = Game_Map::LoopVertical();
224
225 auto div_rounding_down = [](int n, int m) {
226 if (n >= 0) return n / m;
227 return (n - m + 1) / m;
228 };
229 auto mod = [](int n, int m) {
230 int rem = n % m;
231 return rem >= 0 ? rem : m + rem;
232 };
233
234 // FIXME: When Game_Map singleton is made an object we can remove this null check
235 const auto frames = Main_Data::game_system ? Main_Data::game_system->GetFrameCounter() : 0;
236 auto animation_step_c = (frames / 6) % 4;
237 auto animation_step_ab = frames / animation_speed;
238 if (animation_type) {
239 animation_step_ab %= 3;
240 } else {
241 animation_step_ab %= 4;
242 if (animation_step_ab == 3) {
243 animation_step_ab = 1;
244 }
245 }
246
247 const int div_ox = div_rounding_down(ox, TILE_SIZE);
248 const int div_oy = div_rounding_down(oy, TILE_SIZE);
249
250 const int mod_ox = mod(ox, TILE_SIZE);
251 const int mod_oy = mod(oy, TILE_SIZE);
252
253 for (int y = 0; y < tiles_y; y++) {
254 for (int x = 0; x < tiles_x; x++) {
255
256 // Get the real maps tile coordinates
257 int map_x = div_ox + x;
258 int map_y = div_oy + y;
259 if (loop_h) map_x = mod(map_x, width);
260 if (loop_v) map_y = mod(map_y, height);
261
262 int map_draw_x = x * TILE_SIZE - mod_ox;
263 int map_draw_y = y * TILE_SIZE - mod_oy;
264
265 bool out_of_bounds =
266 map_x < 0 || map_x >= width ||
267 map_y < 0 || map_y >= height;
268
269 if (out_of_bounds) {
270 continue;
271 }
272
273 // Get the tile data
274 TileData &tile = GetDataCache(map_x, map_y);
275
276 // Draw the sublayer if its z is being draw now
277 if (z_order == tile.z) {
278 if (layer == 0) {
279 // If lower layer
280 bool allow_fast_blit = (tile.z == Priority_TilesetBelow);
281
282 if (tile.ID >= BLOCK_E && tile.ID < BLOCK_E + BLOCK_E_TILES) {
283 int id = substitutions[tile.ID - BLOCK_E];
284 // If Block E
285
286 int row, col;
287
288 // Get the tile coordinates from chipset
289 if (id < 96) {
290 // If from first column of the block
291 col = 12 + id % 6;
292 row = id / 6;
293 } else {
294 // If from second column of the block
295 col = 18 + (id - 96) % 6;
296 row = (id - 96) / 6;
297 }
298
299 auto tone_hash = MakeETileHash(id);
300 DrawTile(dst, *chipset, *chipset_effect, map_draw_x, map_draw_y, row, col, tone_hash, allow_fast_blit);
301 } else if (tile.ID >= BLOCK_C && tile.ID < BLOCK_D) {
302 // If Block C
303
304 // Get the tile coordinates from chipset
305 int col = 3 + (tile.ID - BLOCK_C) / 50;
306 int row = 4 + animation_step_c;
307
308 auto tone_hash = MakeCTileHash(tile.ID, animation_step_c);
309 DrawTile(dst, *chipset, *chipset_effect, map_draw_x, map_draw_y, row, col, tone_hash, allow_fast_blit);
310 } else if (tile.ID < BLOCK_C) {
311 // If Blocks A1, A2, B
312
313 // Draw the tile from autotile cache
314 TileXY pos = GetCachedAutotileAB(tile.ID, animation_step_ab);
315
316 int col = pos.x;
317 int row = pos.y;
318
319 // Create tone changed tile
320 auto tone_hash = MakeAbTileHash(tile.ID, animation_step_ab);
321 DrawTile(dst, *autotiles_ab_screen, *autotiles_ab_screen_effect, map_draw_x, map_draw_y, row, col, tone_hash, allow_fast_blit);
322 } else {
323 // If blocks D1-D12
324
325 // Draw the tile from autotile cache
326 TileXY pos = GetCachedAutotileD(tile.ID);
327
328 int col = pos.x;
329 int row = pos.y;
330
331 auto tone_hash = MakeDTileHash(tile.ID);
332 DrawTile(dst, *autotiles_d_screen, *autotiles_d_screen_effect, map_draw_x, map_draw_y, row, col, tone_hash, allow_fast_blit);
333 }
334 } else {
335 // If upper layer
336
337 // Check that block F is being drawn
338 if (tile.ID >= BLOCK_F && tile.ID < BLOCK_F + BLOCK_F_TILES) {
339 int id = substitutions[tile.ID - BLOCK_F];
340 int row, col;
341
342 // Get the tile coordinates from chipset
343 if (id < 48) {
344 // If from first column of the block
345 col = 18 + id % 6;
346 row = 8 + id / 6;
347 } else {
348 // If from second column of the block
349 col = 24 + (id - 48) % 6;
350 row = (id - 48) / 6;
351 }
352
353 auto tone_hash = MakeFTileHash(id);
354 DrawTile(dst, *chipset, *chipset_effect, map_draw_x, map_draw_y, row, col, tone_hash);
355 }
356 }
357 }
358 }
359 }
360 }
361
GetCachedAutotileAB(short ID,short animID)362 TilemapLayer::TileXY TilemapLayer::GetCachedAutotileAB(short ID, short animID) {
363 short block = ID / 1000;
364 short b_subtile = (ID - block * 1000) / 50;
365 short a_subtile = ID - block * 1000 - b_subtile * 50;
366 return autotiles_ab[animID][block][b_subtile][a_subtile];
367 }
368
GetCachedAutotileD(short ID)369 TilemapLayer::TileXY TilemapLayer::GetCachedAutotileD(short ID) {
370 short block = (ID - 4000) / 50;
371 short subtile = ID - 4000 - block * 50;
372 return autotiles_d[block][subtile];
373 }
374
CreateTileCache(const std::vector<short> & nmap_data)375 void TilemapLayer::CreateTileCache(const std::vector<short>& nmap_data) {
376 data_cache_vec.resize(width * height);
377 for (int x = 0; x < width; x++) {
378 for (int y = 0; y < height; y++) {
379 TileData tile;
380
381 // Get the tile ID
382 tile.ID = nmap_data[x + y * width];
383
384 tile.z = Priority_TilesetBelow;
385
386 // Calculate the tile Z
387 if (!passable.empty()) {
388 if (tile.ID >= BLOCK_F) { // Upper layer
389 if ((passable[substitutions[tile.ID - BLOCK_F]] & Passable::Above) != 0)
390 tile.z = Priority_TilesetAbove + 1; // Upper sublayer
391 else
392 tile.z = Priority_TilesetBelow + 1; // Lower sublayer
393
394 } else { // Lower layer
395 int chip_index =
396 tile.ID >= BLOCK_E ? substitutions[tile.ID - BLOCK_E] + 18 :
397 tile.ID >= BLOCK_D ? (tile.ID - BLOCK_D) / 50 + 6 :
398 tile.ID >= BLOCK_C ? (tile.ID - BLOCK_C) / 50 + 3 :
399 tile.ID / 1000;
400 if ((passable[chip_index] & (Passable::Wall | Passable::Above)) != 0)
401 tile.z = Priority_TilesetAbove; // Upper sublayer
402 else
403 tile.z = Priority_TilesetBelow; // Lower sublayer
404
405 }
406 }
407 GetDataCache(x, y) = tile;
408 }
409 }
410 }
411
GenerateAutotileAB(short ID,short animID)412 void TilemapLayer::GenerateAutotileAB(short ID, short animID) {
413 // Calculate the block to use
414 // 1: A1 + Upper B (Grass + Coast)
415 // 2: A2 + Upper B (Snow + Coast)
416 // 3: A1 + Lower B (Grass + Ocean/Deep water)
417 short block = ID / 1000;
418
419 // Calculate the B block combination
420 short b_subtile = (ID - block * 1000) / 50;
421 if (b_subtile >= TILE_SIZE) {
422 Output::Warning("Invalid AB autotile ID: {} (b_subtile = {})",
423 ID, b_subtile);
424 return;
425 }
426
427 // Calculate the A block combination
428 short a_subtile = ID - block * 1000 - b_subtile * 50;
429 if (a_subtile >= 47) {
430 Output::Warning("Invalid AB autotile ID: {} (a_subtile = {})",
431 ID, a_subtile);
432 return;
433 }
434
435 if (autotiles_ab[animID][block][b_subtile][a_subtile].valid)
436 return;
437
438 uint8_t quarters[2][2][2];
439
440 // Determine block B subtiles
441 for (int j = 0; j < 2; j++) {
442 for (int i = 0; i < 2; i++) {
443 // Skip the subtile if it will be used one from A block instead
444 if (BlockA_Subtiles_IDS[a_subtile][j][i] != -1) continue;
445
446 // Get the block B subtiles ids and get their coordinates on the chipset
447 int t = (b_subtile >> (j * 2 + i)) & 1;
448 if (block == 2) t ^= 3;
449
450 quarters[j][i][0] = animID;
451 quarters[j][i][1] = 4 + t;
452 }
453 }
454
455 // Determine block A subtiles
456 for (int j = 0; j < 2; j++) {
457 for (int i = 0; i < 2; i++) {
458 // Skip the subtile if it was used one from B block
459 if (BlockA_Subtiles_IDS[a_subtile][j][i] == -1) continue;
460
461 // Get the block A subtiles ids and get their coordinates on the chipset
462 quarters[j][i][0] = animID + (block == 1 ? 3 : 0);
463 quarters[j][i][1] = BlockA_Subtiles_IDS[a_subtile][j][i];
464 }
465 }
466
467 // Determine block B subtiles when combining A and B
468 if (b_subtile != 0 && a_subtile != 0) {
469 for (int j = 0; j < 2; j++) {
470 for (int i = 0; i < 2; i++) {
471 // calculate tile (row 0..3)
472 int t = (b_subtile >> (j * 2 + i)) & 1;
473 if (block == 2) t *= 2;
474
475 // Skip the subtile if not used
476 if (t == 0) continue;
477
478 // Get the coordinates on the chipset
479 quarters[j][i][0] = animID;
480 quarters[j][i][1] = 4 + t;
481 }
482 }
483 }
484
485 // pack the quarters data into a word
486 uint32_t quarters_hash = 0;
487 for (int j = 0; j < 2; j++)
488 for (int i = 0; i < 2; i++)
489 for (int k = 0; k < 2; k++) {
490 quarters_hash <<= 4;
491 quarters_hash |= quarters[j][i][k];
492 }
493
494 // check whether we have already generated this tile
495 auto it = autotiles_ab_map.find(quarters_hash);
496 if (it != autotiles_ab_map.end()) {
497 autotiles_ab[animID][block][b_subtile][a_subtile] = it->second;
498 return;
499 }
500
501 int id = autotiles_ab_next++;
502 int dst_x = id % TILES_PER_ROW;
503 int dst_y = id / TILES_PER_ROW;
504
505 TileXY tile_xy(dst_x, dst_y);
506 autotiles_ab_map[quarters_hash] = tile_xy;
507 autotiles_ab[animID][block][b_subtile][a_subtile] = tile_xy;
508 }
509
GenerateAutotileD(short ID)510 void TilemapLayer::GenerateAutotileD(short ID) {
511 // Calculate the D block id
512 short block = (ID - 4000) / 50;
513
514 // Calculate the D block combination
515 short subtile = ID - 4000 - block * 50;
516
517 if (block >= 12 || subtile >= 50 || block < 0 || subtile < 0) {
518 Output::Warning("Tilemap index out of range: {} {}", block, subtile);
519 return;
520 }
521
522 if (autotiles_d[block][subtile].valid)
523 return;
524
525 uint8_t quarters[2][2][2];
526
527 // Get Block chipset coords
528 short block_x, block_y;
529 if (block < 4) {
530 // If from first column
531 block_x = (block % 2) * 3;
532 block_y = 8 + (block / 2) * 4;
533 } else {
534 // If from second column
535 block_x = 6 + (block % 2) * 3;
536 block_y = ((block - 4) / 2) * 4;
537 }
538
539 // Calculate D block subtiles
540 for (int j = 0; j < 2; j++) {
541 for (int i = 0; i < 2; i++) {
542 // Get the block D subtiles ids and get their coordinates on the chipset
543 quarters[j][i][0] = block_x + BlockD_Subtiles_IDS[subtile][j][i][0];
544 quarters[j][i][1] = block_y + BlockD_Subtiles_IDS[subtile][j][i][1];
545 }
546 }
547
548 // pack the quarters data into a word
549 uint32_t quarters_hash = 0;
550 for (int j = 0; j < 2; j++)
551 for (int i = 0; i < 2; i++)
552 for (int k = 0; k < 2; k++) {
553 quarters_hash <<= 4;//multiply 16
554 quarters_hash |= quarters[j][i][k];
555 }
556
557 // check whether we have already generated this tile
558 auto it = autotiles_d_map.find(quarters_hash);
559 if (it != autotiles_d_map.end()) {
560 autotiles_d[block][subtile] = it->second;
561 return;
562 }
563
564 int id = autotiles_d_next++;
565 int dst_x = id % TILES_PER_ROW;
566 int dst_y = id / TILES_PER_ROW;
567
568 TileXY tile_xy(dst_x, dst_y);
569 autotiles_d_map[quarters_hash] = tile_xy;
570 autotiles_d[block][subtile] = tile_xy;
571 }
572
GenerateAutotiles(int count,const std::unordered_map<uint32_t,TileXY> & map)573 BitmapRef TilemapLayer::GenerateAutotiles(int count, const std::unordered_map<uint32_t, TileXY>& map) {
574 int rows = (count + TILES_PER_ROW - 1) / TILES_PER_ROW;
575 BitmapRef tiles = Bitmap::Create(TILES_PER_ROW * TILE_SIZE, rows * TILE_SIZE);
576 tiles->Clear();
577 Rect rect(0, 0, TILE_SIZE/2, TILE_SIZE/2);
578
579 for (auto& p: map) {
580 uint32_t quarters_hash = p.first;
581 TileXY dst = p.second;
582
583 // unpack the quarters data
584 for (int j = 0; j < 2; j++) {
585 for (int i = 0; i < 2; i++) {
586 int x = quarters_hash >> 28;
587 quarters_hash <<= 4;
588
589 int y = quarters_hash >> 28;
590 quarters_hash <<= 4;
591
592 rect.x = (x * 2 + i) * (TILE_SIZE/2);
593 rect.y = (y * 2 + j) * (TILE_SIZE/2);
594
595 tiles->BlitFast((dst.x * 2 + i) * (TILE_SIZE / 2), (dst.y * 2 + j) * (TILE_SIZE / 2), *chipset, rect, 255);
596 }
597 }
598 }
599
600 if (rows > 0) {
601 tiles->CheckPixels(Bitmap::Flag_Chipset | Bitmap::Flag_ReadOnly);
602 }
603
604 return tiles;
605 }
606
SetChipset(BitmapRef const & nchipset)607 void TilemapLayer::SetChipset(BitmapRef const& nchipset) {
608 chipset = nchipset;
609 chipset_effect = Bitmap::Create(chipset->width(), chipset->height());
610 chipset_tone_tiles.clear();
611
612 if (autotiles_ab_next != 0 && autotiles_d_screen != nullptr && layer == 0) {
613 autotiles_ab_screen = GenerateAutotiles(autotiles_ab_next, autotiles_ab_map);
614 autotiles_d_screen = GenerateAutotiles(autotiles_d_next, autotiles_d_map);
615
616 autotiles_ab_screen_effect = Bitmap::Create(autotiles_ab_screen->width(), autotiles_ab_screen->height());
617 autotiles_d_screen_effect = Bitmap::Create(autotiles_d_screen->width(), autotiles_d_screen->height());
618 }
619 }
620
SetMapData(std::vector<short> nmap_data)621 void TilemapLayer::SetMapData(std::vector<short> nmap_data) {
622 // Create the tiles data cache
623 CreateTileCache(nmap_data);
624 memset(autotiles_ab, 0, sizeof(autotiles_ab));
625 memset(autotiles_d, 0, sizeof(autotiles_d));
626
627 if (layer == 0) {
628 autotiles_ab_map.clear();
629 autotiles_d_map.clear();
630 autotiles_ab_next = 0;
631 autotiles_d_next = 0;
632 for (int y = 0; y < height; y++) {
633 for (int x = 0; x < width; x++) {
634
635 if (GetDataCache(x, y).ID < BLOCK_C) {
636 // If blocks A and B
637
638 GenerateAutotileAB(GetDataCache(x, y).ID, 0);
639 GenerateAutotileAB(GetDataCache(x, y).ID, 1);
640 GenerateAutotileAB(GetDataCache(x, y).ID, 2);
641 } else if (GetDataCache(x, y).ID >= BLOCK_D && GetDataCache(x, y).ID < BLOCK_E) {
642 // If block D
643
644 GenerateAutotileD(GetDataCache(x, y).ID);
645 }
646 }
647 }
648 autotiles_ab_screen = GenerateAutotiles(autotiles_ab_next, autotiles_ab_map);
649 autotiles_d_screen = GenerateAutotiles(autotiles_d_next, autotiles_d_map);
650
651 autotiles_ab_screen_effect = Bitmap::Create(autotiles_ab_screen->width(), autotiles_ab_screen->height());
652 autotiles_d_screen_effect = Bitmap::Create(autotiles_d_screen->width(), autotiles_d_screen->height());
653
654 chipset_tone_tiles.clear();
655 }
656
657 map_data = std::move(nmap_data);
658 }
659
SetPassable(std::vector<unsigned char> npassable)660 void TilemapLayer::SetPassable(std::vector<unsigned char> npassable) {
661 passable = std::move(npassable);
662
663 // Recalculate z values of all tiles
664 CreateTileCache(map_data);
665 }
666
OnSubstitute()667 void TilemapLayer::OnSubstitute() {
668 // Recalculate z values of all tiles
669 CreateTileCache(map_data);
670 }
671
TilemapSubLayer(TilemapLayer * tilemap,int z)672 TilemapSubLayer::TilemapSubLayer(TilemapLayer* tilemap, int z) :
673 Drawable(z),
674 tilemap(tilemap)
675 {
676 DrawableMgr::Register(this);
677 }
678
Draw(Bitmap & dst)679 void TilemapSubLayer::Draw(Bitmap& dst) {
680 if (!tilemap->GetChipset()) {
681 return;
682 }
683
684 tilemap->Draw(dst, GetZ());
685 }
686
SetTone(Tone tone)687 void TilemapLayer::SetTone(Tone tone) {
688 if (tone == this->tone) {
689 return;
690 }
691
692 this->tone = tone;
693
694 if (autotiles_d_screen_effect) {
695 autotiles_d_screen_effect->Clear();
696 }
697 if (autotiles_ab_screen_effect) {
698 autotiles_ab_screen_effect->Clear();
699 }
700 if (chipset_effect) {
701 chipset_effect->Clear();
702 }
703 chipset_tone_tiles.clear();
704 }
705