TileMapRenderer.java 12 KB

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