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