TileMapRenderer.java 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. package pathgame.rendering;
  2. import me.hammerle.snuviengine.api.FontRenderer;
  3. import me.hammerle.snuviengine.api.Renderer;
  4. import me.hammerle.snuviengine.api.Texture;
  5. import me.hammerle.snuviengine.api.TextureRenderer;
  6. import pathgame.gameplay.Keys;
  7. import pathgame.gameplay.Player;
  8. import pathgame.tilemap.Tile;
  9. import pathgame.tilemap.TileMap;
  10. import pathgame.tilemap.TileRenderType;
  11. /**
  12. * A renderer for tile maps.
  13. *
  14. * @author kajetan
  15. */
  16. public class TileMapRenderer
  17. {
  18. // prevents rendering artifacts especially on different zoom levels
  19. private final static float ERROR = 1.0f / 512.0F;
  20. private final static float T_ERROR = 1.0f / 4096.0F;
  21. private final Texture tileTexture = new Texture("resources/tiles.png");
  22. private final TextureRenderer textureRenderer = new TextureRenderer(20 * 20 * 2); // default to 20x20 map
  23. private final TextureRenderer swampWaterOverlayRenderer = new TextureRenderer(20 * 20 * 2); // default to 20x20 map
  24. private final TextureRenderer grassOverlayRenderer = new TextureRenderer(20 * 20 * 2); // default to 20x20 map
  25. private float scale = 1.0f;
  26. private final static String[] OVERLAY = new String[]
  27. {
  28. "&a1", "&a2", "&a3", "&e4", "&e5", "&66", "&67", "&68", "&c9"
  29. };
  30. /**
  31. * Creates a new tile map renderer.
  32. *
  33. */
  34. public TileMapRenderer()
  35. {
  36. }
  37. /**
  38. * Sets the scale of the map.
  39. *
  40. * @param scale the scale of the map
  41. */
  42. public void setScale(float scale)
  43. {
  44. this.scale = scale;
  45. }
  46. /**
  47. * Returns the scale of the map.
  48. *
  49. * @return the scale of the map
  50. */
  51. public float getScale()
  52. {
  53. return scale;
  54. }
  55. /**
  56. * Returns the scaled render width of a map.
  57. *
  58. * @param map a map
  59. * @return the scaled render width of a map
  60. */
  61. public float getWidth(TileMap map)
  62. {
  63. return map.getWidth() * TileRenderer.TILE_SIZE * scale;
  64. }
  65. /**
  66. * Returns the scaled render height of a map.
  67. *
  68. * @param map a map
  69. * @return the scaled render height of a map
  70. */
  71. public float getHeight(TileMap map)
  72. {
  73. return map.getHeight() * TileRenderer.TILE_SIZE * scale;
  74. }
  75. private float toTexture(int x)
  76. {
  77. return x * TileRenderer.TILE_SIZE / TileTexture.TEXTURE_SIZE;
  78. }
  79. private void addTile(TextureRenderer tr, int x, int y, float tMinX, float tMinY, float tMaxX, float tMaxY)
  80. {
  81. tr.addRectangle(
  82. x * TileRenderer.TILE_SIZE - ERROR, y * TileRenderer.TILE_SIZE - ERROR,
  83. (x + 1) * TileRenderer.TILE_SIZE + ERROR, (y + 1) * TileRenderer.TILE_SIZE + ERROR,
  84. tMinX + T_ERROR, tMinY + T_ERROR,
  85. tMaxX - T_ERROR, tMaxY - T_ERROR);
  86. }
  87. private void addTileOverlay(TextureRenderer tr, int x, int y, int ox, int oy)
  88. {
  89. addTile(tr, x, y, toTexture(ox), toTexture(oy), toTexture(ox + 1), toTexture(oy + 1));
  90. }
  91. private boolean isInRange(TileMap map, int x, int y)
  92. {
  93. return x >= 0 && y >= 0 && x < map.getWidth() && y < map.getHeight();
  94. }
  95. private boolean isSwamp(TileMap map, int x, int y)
  96. {
  97. return isInRange(map, x, y) && map.getTile(x, y).getRenderType() == TileRenderType.SWAMP;
  98. }
  99. private boolean isSwampOrWaterOrBorder(TileMap map, int x, int y)
  100. {
  101. if(!isInRange(map, x, y))
  102. {
  103. return true;
  104. }
  105. TileRenderType type = map.getTile(x, y).getRenderType();
  106. return type == TileRenderType.SWAMP || type == TileRenderType.WATER;
  107. }
  108. private void addWaterSwampOverlay(TileMap map, int x, int y)
  109. {
  110. boolean n = isSwamp(map, x, y - 1);
  111. boolean e = isSwamp(map, x + 1, y);
  112. boolean s = isSwamp(map, x, y + 1);
  113. boolean w = isSwamp(map, x - 1, y);
  114. if(!n && !w && isSwamp(map, x - 1, y - 1)) // upper, left corner
  115. {
  116. addTileOverlay(swampWaterOverlayRenderer, x, y, 7, 13);
  117. }
  118. if(!n && !e && isSwamp(map, x + 1, y - 1)) // upper, right corner
  119. {
  120. addTileOverlay(swampWaterOverlayRenderer, x, y, 6, 13);
  121. }
  122. if(!s && !w && isSwamp(map, x - 1, y + 1)) // lower, left corner
  123. {
  124. addTileOverlay(swampWaterOverlayRenderer, x, y, 5, 13);
  125. }
  126. if(!s && !e && isSwamp(map, x + 1, y + 1)) // lower, right corner
  127. {
  128. addTileOverlay(swampWaterOverlayRenderer, x, y, 4, 13);
  129. }
  130. int index = 0;
  131. index += n ? 0 : 8;
  132. index += e ? 0 : 4;
  133. index += s ? 0 : 2;
  134. index += w ? 0 : 1;
  135. if(index == 15)
  136. {
  137. return;
  138. }
  139. addTileOverlay(swampWaterOverlayRenderer, x, y, index, 15);
  140. }
  141. private void addGrassOverlay(TileMap map, int x, int y)
  142. {
  143. boolean n = isSwampOrWaterOrBorder(map, x, y - 1);
  144. boolean e = isSwampOrWaterOrBorder(map, x + 1, y);
  145. boolean s = isSwampOrWaterOrBorder(map, x, y + 1);
  146. boolean w = isSwampOrWaterOrBorder(map, x - 1, y);
  147. if(n && w && !isSwampOrWaterOrBorder(map, x - 1, y - 1)) // upper, left corner
  148. {
  149. addTileOverlay(grassOverlayRenderer, x, y, 3, 13);
  150. }
  151. if(n && e && !isSwampOrWaterOrBorder(map, x + 1, y - 1)) // upper, right corner
  152. {
  153. addTileOverlay(grassOverlayRenderer, x, y, 2, 13);
  154. }
  155. if(s && w && !isSwampOrWaterOrBorder(map, x - 1, y + 1)) // lower, left corner
  156. {
  157. addTileOverlay(grassOverlayRenderer, x, y, 1, 13);
  158. }
  159. if(s && e && !isSwampOrWaterOrBorder(map, x + 1, y + 1)) // lower, right corner
  160. {
  161. addTileOverlay(grassOverlayRenderer, x, y, 0, 13);
  162. }
  163. int index = 0;
  164. index += !n ? 0 : 8;
  165. index += !e ? 0 : 4;
  166. index += !s ? 0 : 2;
  167. index += !w ? 0 : 1;
  168. if(index == 15)
  169. {
  170. return;
  171. }
  172. addTileOverlay(grassOverlayRenderer, x, y, index, 14);
  173. }
  174. private void updateData(TileMap map)
  175. {
  176. textureRenderer.clear();
  177. swampWaterOverlayRenderer.clear();
  178. grassOverlayRenderer.clear();
  179. for(int x = 0; x < map.getWidth(); x++)
  180. {
  181. for(int y = 0; y < map.getHeight(); y++)
  182. {
  183. Tile t = map.getTile(x, y);
  184. TileTexture tt = TileRenderer.getTileTexture(map, t, x, y);
  185. if(tt == null)
  186. {
  187. continue;
  188. }
  189. if(t.getRenderType() == TileRenderType.WATER)
  190. {
  191. addWaterSwampOverlay(map, x, y);
  192. addGrassOverlay(map, x, y);
  193. }
  194. else if(t.getRenderType() == TileRenderType.SWAMP)
  195. {
  196. addGrassOverlay(map, x, y);
  197. }
  198. addTile(textureRenderer, x, y, tt.getMinX(), tt.getMinY(), tt.getMaxX(), tt.getMaxY());
  199. }
  200. }
  201. textureRenderer.build();
  202. swampWaterOverlayRenderer.build();
  203. grassOverlayRenderer.build();
  204. }
  205. /**
  206. * Ticks the renderer. Used for animated tiles.
  207. *
  208. */
  209. public void tick()
  210. {
  211. // tick tile animations here
  212. }
  213. /**
  214. * Draws the given map at the given offset.
  215. *
  216. * @param map a map
  217. * @param r the renderer given by the engine
  218. * @param forceUpdate whether an update of the render data should be forced
  219. * @param offX the x coordinate of the offset
  220. * @param offY the y coordinate of the offset
  221. */
  222. public void renderTick(TileMap map, Renderer r, Player p, boolean forceUpdate, float offX, float offY)
  223. {
  224. r.setTextureEnabled(true);
  225. r.setColorEnabled(false);
  226. r.setMixColorEnabled(false);
  227. tileTexture.bind();
  228. if(forceUpdate || map.isDirty())
  229. {
  230. updateData(map);
  231. map.clean();
  232. }
  233. float viewScale = r.getViewScale();
  234. offX = (int) (offX * viewScale) / viewScale;
  235. offY = (int) (offY * viewScale) / viewScale;
  236. r.translateTo(offX, offY);
  237. r.scale(scale, scale);
  238. r.updateMatrix();
  239. textureRenderer.draw();
  240. swampWaterOverlayRenderer.draw();
  241. grassOverlayRenderer.draw();
  242. if(Keys.OVERLAY_KEY.isDown())
  243. {
  244. r.translateTo(0.0f, 0.0f);
  245. r.updateMatrix();
  246. r.setTextureEnabled(false);
  247. r.getColorRenderer().drawRectangle(0, 0, r.getViewWidth(), r.getViewHeight(), 0x44000000);
  248. r.setTextureEnabled(true);
  249. r.setColorEnabled(true);
  250. r.translateTo(offX, offY);
  251. r.scale(scale * 2.0f, scale * 2.0f);
  252. r.updateMatrix();
  253. FontRenderer fr = r.getFontRenderer();
  254. float midX = (TileRenderer.TILE_SIZE - fr.getWidth() * 2) * 0.5f * 0.5f;
  255. float midY = (TileRenderer.TILE_SIZE - (fr.getHeight() - 1) * 2) * 0.5f * 0.5f;
  256. for(int x = 0; x < map.getWidth(); x++)
  257. {
  258. for(int y = 0; y < map.getHeight(); y++)
  259. {
  260. Tile t = map.getTile(x, y);
  261. float tx = midX + TileRenderer.TILE_SIZE * x * 0.5f;
  262. float ty = midY + TileRenderer.TILE_SIZE * y * 0.5f;
  263. if(t.isBlockingMovement(p))
  264. {
  265. fr.drawString(tx, ty, true, "&4-");
  266. }
  267. else
  268. {
  269. fr.drawString(tx, ty, true, OVERLAY[map.getTile(x, y).getEnergyCost(p) - 1]);
  270. }
  271. }
  272. }
  273. }
  274. }
  275. }