/* * Copyright (c) 2012. HappyDroids LLC, All rights reserved. */ package com.happydroids.droidtowers.grid; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.GLCommon; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.SpriteCache; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.utils.Array; import com.google.common.base.Function; import com.google.common.collect.Lists; import com.google.common.eventbus.Subscribe; import com.happydroids.droidtowers.TowerConsts; import com.happydroids.droidtowers.achievements.TutorialEngine; import com.happydroids.droidtowers.entities.GameLayer; import com.happydroids.droidtowers.entities.GridObject; import com.happydroids.droidtowers.events.SwitchToolEvent; import com.happydroids.droidtowers.graphics.Overlays; import com.happydroids.droidtowers.graphics.TransitLine; import java.util.HashMap; import java.util.List; import java.util.Map; import static com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import static com.happydroids.droidtowers.TowerConsts.GRID_UNIT_SIZE; import static com.happydroids.droidtowers.graphics.Overlays.POPULATION_LEVEL; import static com.happydroids.droidtowers.input.GestureTool.PLACEMENT; public class GameGridRenderer extends GameLayer { protected GameGrid gameGrid; protected final OrthographicCamera camera; protected boolean shouldRenderGridLines; protected final ShapeRenderer shapeRenderer; private Overlays activeOverlay; private Map<Overlays, Function<GridObject, Float>> overlayFunctions; private Function<GridObject, Integer> objectRenderSortFunction; private List<GridObject> objectsRenderOrder; private List<TransitLine> transitLines; private boolean shouldRenderTransitLines; protected Color renderTintColor; private final SpriteCache spriteCache; public GameGridRenderer(GameGrid gameGrid, OrthographicCamera camera) { this.gameGrid = gameGrid; this.camera = camera; renderTintColor = Color.WHITE; shouldRenderGridLines = false; shapeRenderer = new ShapeRenderer(); transitLines = Lists.newArrayList(); activeOverlay = null; makeOverlayFunctions(); spriteCache = new SpriteCache(); gameGrid.events().register(this); } @Override public void render(SpriteBatch spriteBatch, OrthographicCamera camera) { shapeRenderer.setProjectionMatrix(this.camera.combined); if (shouldRenderGridLines) { renderGridLines(); } renderGridObjects(spriteBatch); Gdx.graphics.getGLCommon().glEnable(GL10.GL_BLEND); if (activeOverlay == Overlays.NOISE_LEVEL) { renderNoiseLevelOverlay(); } else if (activeOverlay != null) { renderGenericOverlay(activeOverlay); } if (shouldRenderTransitLines && transitLines.size() > 0) { for (TransitLine transitLine : transitLines) { transitLine.render(shapeRenderer); } } Gdx.graphics.getGLCommon().glDisable(GL10.GL_BLEND); } private void makeOverlayFunctions() { overlayFunctions = new HashMap<Overlays, Function<GridObject, Float>>(); overlayFunctions.put(Overlays.CRIME_LEVEL, Overlays.CRIME_LEVEL.getMethod()); overlayFunctions.put(Overlays.EMPLOYMENT_LEVEL, Overlays.EMPLOYMENT_LEVEL.getMethod()); overlayFunctions.put(Overlays.POPULATION_LEVEL, Overlays.POPULATION_LEVEL.getMethod()); overlayFunctions.put(Overlays.DESIRABILITY_LEVEL, Overlays.DESIRABILITY_LEVEL.getMethod()); overlayFunctions.put(Overlays.DIRT_LEVEL, Overlays.DIRT_LEVEL.getMethod()); } private void renderGenericOverlay(Overlays overlay) { Function<GridObject, Float> function = overlayFunctions.get(overlay); Color baseColor = overlay.getColor(1f); shapeRenderer.begin(ShapeType.Filled); Array<GridObject> objects = gameGrid.getObjects(); for (int i = 0, objectsSize = objects.size; i < objectsSize; i++) { GridObject gridObject = objects.get(i); tmp.set(gridObject.getWorldCenter().x, gridObject.getWorldCenter().y, 0); if (camera.frustum .sphereInFrustum(tmp, Math.max(gridObject.getWorldBounds().width, gridObject.getWorldBounds().height))) { Float returnValue = function.apply(gridObject); if (returnValue != null) { baseColor.a = returnValue; shapeRenderer.setColor(baseColor); shapeRenderer.rect( gridObject.getPosition().getWorldX(), gridObject.getPosition().getWorldY(), gridObject.getSize().getWorldX(), gridObject.getSize().getWorldY() ); } } } shapeRenderer.end(); } private void renderNoiseLevelOverlay() { shapeRenderer.begin(ShapeType.Filled); for (int x = 0; x < gameGrid.gridSize.x; x++) { for (int y = 0; y < gameGrid.gridSize.y; y++) { GridPosition position = gameGrid.positionCache().getPosition(x, y); if (position.getNoiseLevel() > 0.01f) { tmp.set(position.worldPoint().x, position.worldPoint().y, 0); if (camera.frustum.sphereInFrustum(tmp, TowerConsts.GRID_UNIT_SIZE)) { shapeRenderer.setColor(Overlays.NOISE_LEVEL.getColor(position.getNoiseLevel())); shapeRenderer.rect(x * GRID_UNIT_SIZE, y * GRID_UNIT_SIZE, GRID_UNIT_SIZE, GRID_UNIT_SIZE); } } } } shapeRenderer.end(); } private void renderGridObjects(SpriteBatch spriteBatch) { Gdx.gl.glEnable(GL10.GL_BLEND); spriteCache.setProjectionMatrix(camera.combined); spriteCache.begin(); for (GridObject gridObject : gameGrid.getObjects()) { if (gridObject.shouldUseSpriteCache() && gridObject.getSpriteCacheId() != -1) { tmp.set(gridObject.getWorldCenter().x, gridObject.getWorldCenter().y, 0); if (camera.frustum .sphereInFrustum(tmp, Math.max(gridObject.getWorldBounds().width, gridObject.getWorldBounds().height))) { spriteCache.draw(gridObject.getSpriteCacheId()); } } } spriteCache.end(); spriteBatch.begin(); for (GridObject gridObject : gameGrid.getObjects()) { tmp.set(gridObject.getWorldCenter().x, gridObject.getWorldCenter().y, 0); if (camera.frustum .sphereInFrustum(tmp, Math.max(gridObject.getWorldBounds().width, gridObject.getWorldBounds().height))) { if (!gridObject.shouldUseSpriteCache() || gridObject.getSpriteCacheId() == -1) { gridObject.render(spriteBatch, spriteCache, renderTintColor); } if (gridObject.hasDecals()) { gridObject.renderDecals(spriteBatch); } } } spriteBatch.end(); } private void renderGridLines() { GLCommon gl = Gdx.graphics.getGLCommon(); gl.glEnable(GL10.GL_BLEND); shapeRenderer.begin(ShapeType.Line); shapeRenderer.setColor(1f, 1f, 1f, 0.15f); for (int i = 0; i <= gameGrid.getGridSize().x; i++) { shapeRenderer.line(i * GRID_UNIT_SIZE, 0, i * GRID_UNIT_SIZE, gameGrid.getGridSize().y * GRID_UNIT_SIZE); } for (int i = 0; i <= gameGrid.getGridSize().y; i++) { shapeRenderer.line(0, i * GRID_UNIT_SIZE, gameGrid.getGridSize().x * GRID_UNIT_SIZE, i * GRID_UNIT_SIZE); } shapeRenderer.end(); gl.glDisable(GL10.GL_BLEND); } public void toggleGridLines() { shouldRenderGridLines = !shouldRenderGridLines; } public void setActiveOverlay(Overlays overlay) { if (activeOverlay == null && overlay == POPULATION_LEVEL) { TutorialEngine.instance().moveToStepWhenReady("tutorial-turn-off-population-overlay"); } if (activeOverlay == POPULATION_LEVEL && overlay == null) { TutorialEngine.instance().moveToStepWhenReady("tutorial-finished"); } activeOverlay = overlay; } public void removeTransitLine(TransitLine transitLine) { transitLines.remove(transitLine); } public void addTransitLine(TransitLine transitLine) { transitLines.add(transitLine); } public void toggleTransitLines() { shouldRenderTransitLines = !shouldRenderTransitLines; } public void setRenderTintColor(Color renderTintColor) { this.renderTintColor = renderTintColor; } public Color getRenderTintColor() { return renderTintColor; } @Subscribe public void InputSystem_onSwitchTool(SwitchToolEvent event) { shouldRenderGridLines = event.selectedTool == PLACEMENT; } }