1 /** 2 * Retrograde Engine 3 * 4 * Authors: 5 * Mike Bierlee, m.bierlee@lostmoment.com 6 * Copyright: 2014-2021 Mike Bierlee 7 * License: 8 * This software is licensed under the terms of the MIT license. 9 * The full terms of the license can be found in the LICENSE.txt file. 10 */ 11 12 module retrograde.sdl2.tilemap; 13 14 version(Have_derelict_sdl2) { 15 16 import retrograde.tiles; 17 import retrograde.graphics.twodee.sdl2.rendering; 18 import retrograde.math; 19 20 import poodinis; 21 22 import derelict.sdl2.sdl; 23 import derelict.sdl2.image; 24 25 import std.string; 26 import std.experimental.logger; 27 28 class Sdl2TilemapComposer { 29 private SDL_Surface*[const(Tileset)] tilesetSurfaces; 30 31 @Autowire 32 private Sdl2RenderSystem renderer; 33 34 @Autowire 35 private Logger logger; 36 37 @Autowire 38 private CompositionStrategyFactory compositionStrategyFactory; 39 40 public SDL_Texture* composeTilemapTexture(Tilemap tilemap) { 41 cleanState(); 42 loadTilesetSurfaces(tilemap.tilesets); 43 SDL_Surface* composedSurface = blitLayers(tilemap); 44 if (!composedSurface) { 45 throw new TileCompositionException("Unable to compose composite surface of tilemap."); 46 } 47 SDL_Texture* composedTexture = renderer.createTextureFromSurface(composedSurface); 48 SDL_FreeSurface(composedSurface); 49 freeTilesetSurfaces(); 50 return composedTexture; 51 } 52 53 private SDL_Surface* blitLayers(Tilemap tilemap) { 54 auto compositionStrategy = compositionStrategyFactory.createStrategy(tilemap); 55 auto tilemapDimensions = compositionStrategy.getDimensions(tilemap); 56 57 SDL_Surface* composedSurface = SDL_CreateRGBSurface(0, cast(int) tilemapDimensions.width, cast(int) tilemapDimensions.height, 32, 0, 0, 0, 0); 58 SDL_Rect destinationRectangle; 59 SDL_Rect sourceRectangle; 60 foreach (layer; tilemap.layers) { 61 ulong currentRow = 1; 62 ulong currentColumn = 1; 63 64 foreach (tile; layer.tileData) { 65 if (!tile.empty) { 66 SDL_Surface* tilesetSurface = tilesetSurfaces[cast(const(Tileset)) tile.parentTileset]; 67 sourceRectangle.x = cast(int) tile.positionInTileset.x; 68 sourceRectangle.y = cast(int) tile.positionInTileset.y; 69 sourceRectangle.w = cast(int) tile.parentTileset.tileWidth; 70 sourceRectangle.h = cast(int) tile.parentTileset.tileHeight; 71 72 auto tileDestination = compositionStrategy.getTileDestination(tilemap, currentRow, currentColumn); 73 destinationRectangle.x = cast(int) tileDestination.x; 74 destinationRectangle.y = cast(int) tileDestination.y; 75 76 SDL_BlitSurface(tilesetSurface, &sourceRectangle, composedSurface, &destinationRectangle); 77 } 78 79 currentColumn += 1; 80 if (currentColumn > tilemap.width) { 81 currentRow += 1; 82 currentColumn = 1; 83 } 84 } 85 } 86 87 return composedSurface; 88 } 89 90 private void cleanState() { 91 tilesetSurfaces.destroy(); 92 } 93 94 private void loadTilesetSurfaces(Tileset[] tilesets) { 95 foreach (tileset; tilesets) { 96 SDL_Surface* surface = IMG_Load(tileset.imageName.toStringz()); 97 if (!surface) { 98 logger.errorf("Could not load tileset image %s", tileset.imageName); 99 continue; 100 } 101 102 tilesetSurfaces[tileset] = surface; 103 } 104 } 105 106 private void freeTilesetSurfaces() { 107 foreach (surface; tilesetSurfaces) { 108 SDL_FreeSurface(surface); 109 } 110 } 111 } 112 113 }