package com.galvarez.ttw.rendering; import static java.lang.Math.min; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.artemis.ComponentMapper; import com.artemis.Entity; import com.artemis.annotations.Wire; import com.artemis.utils.ImmutableBag; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; import com.galvarez.ttw.model.components.InfluenceSource; import com.galvarez.ttw.model.data.Empire; import com.galvarez.ttw.model.map.GameMap; import com.galvarez.ttw.model.map.Influence; import com.galvarez.ttw.model.map.MapPosition; import com.galvarez.ttw.model.map.MapTools; import com.galvarez.ttw.model.map.MapTools.Border; import com.galvarez.ttw.utils.FloatPair; @Wire public final class InfluenceRenderSystem extends AbstractRendererSystem { private ComponentMapper<Empire> empires; private final GameMap map; private final EnumMap<Border, AtlasRegion> borderTexture = new EnumMap<>(Border.class); private final AtlasRegion blank; public InfluenceRenderSystem(OrthographicCamera camera, SpriteBatch batch, GameMap map) { super(with(InfluenceSource.class), camera, batch); this.map = map; TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("textures/maptiles.atlas"), Gdx.files.internal("textures")); blank = atlas.findRegion("hex_blank"); borderTexture.put(Border.BOTTOM_LEFT, atlas.findRegion("border_bottom_left")); borderTexture.put(Border.BOTTOM_RIGHT, atlas.findRegion("border_bottom_right")); borderTexture.put(Border.BOTTOM, atlas.findRegion("border_bottom")); borderTexture.put(Border.TOP_LEFT, atlas.findRegion("border_top_left")); borderTexture.put(Border.TOP_RIGHT, atlas.findRegion("border_top_right")); borderTexture.put(Border.TOP, atlas.findRegion("border_top")); } @Override protected boolean checkProcessing() { return true; } private final Map<Empire, List<InfluenceBorder>> borders = new HashMap<>(); private static final class InfluenceBorder { private final Border[] borders; private final MapPosition position; public InfluenceBorder(MapPosition position, Border ... borders) { this.position = position; this.borders = borders; } } private final Map<MapPosition, Float> colors = new HashMap<>(); private volatile boolean displayColoredInfluence = true; /** * Collect the borders for every influence source. Should be done only when * the borders changed, meaning after processing a turn. */ public void preprocess() { borders.clear(); colors.clear(); List<Border> tmp = new ArrayList<>(); for (int x = 0; x < map.map.length; x++) { for (int y = 0; y < map.map[0].length; y++) { Influence inf = map.getInfluenceAt(x, y); Entity source = inf.getMainInfluenceSource(world); if (source != null) { Empire empire = empires.get(source); // collect borders for (Border b : Border.values()) { MapPosition neighbor = b.getNeighbor(x, y); Influence neighborTile = map.getInfluenceAt(neighbor); if (neighborTile == null || empire != getMainEmpire(neighborTile)) tmp.add(b); } if (!tmp.isEmpty()) { List<InfluenceBorder> list = borders.get(empire); if (list == null) borders.put(empire, list = new ArrayList<>()); list.add(new InfluenceBorder(map.getPositionAt(x, y), tmp.toArray(new Border[tmp.size()]))); tmp.clear(); } // collect color Color c = empire.color; colors.put(inf.position, Color.toFloatBits(c.r, c.g, c.b, min(0.8f,inf.getMaxInfluence() / 300f))); } } } } private Empire getMainEmpire(Influence tile) { Entity main = tile.getMainInfluenceSource(world); return main == null ? null : empires.get(main); } @Override protected void processEntities(ImmutableBag<Entity> entities) { Color c = batch.getColor(); // draw all the pre-processed borders for (Empire empire : borders.keySet()) { // use source color batch.setColor(empire.color); for (InfluenceBorder ib : borders.get(empire)) for (Border b : ib.borders) draw(borderTexture.get(b), ib.position); } if (displayColoredInfluence) for (Entry<MapPosition, Float> e : colors.entrySet()) { batch.setColor(e.getValue().floatValue()); draw(blank, e.getKey()); } // revert to previous (may be it is the last source?) batch.setColor(c); } private void draw(AtlasRegion reg, MapPosition p) { FloatPair position = MapTools.world2window(p); batch.draw(reg, position.x - reg.getRegionWidth() / 2, position.y - reg.getRegionHeight() / 2); } public void displayColoredInfluence(boolean b) { displayColoredInfluence = b; } public boolean displayColoredInfluence() { return displayColoredInfluence; } }