Search in sources :

Example 1 with Level

use of com.demod.dcba.CommandReporting.Level in project Factorio-FBSR by demodude4u.

the class FBSR method applyRendering.

private static BufferedImage applyRendering(CommandReporting reporting, int tileSize, List<Renderer> renderers, ArrayListMultimap<Direction, PanelRenderer> borderPanels, JSONObject options) throws JSONException {
    Rectangle2D.Double worldBounds = computeBounds(renderers);
    worldBounds.setFrameFromDiagonal(Math.floor(worldBounds.getMinX() + 0.4) - 1, Math.floor(worldBounds.getMinY() + 0.4) - 1, Math.ceil(worldBounds.getMaxX() - 0.4) + 1, Math.ceil(worldBounds.getMaxY() - 0.4) + 1);
    Rectangle2D.Double centerBounds = new Rectangle2D.Double(worldBounds.x, worldBounds.y, worldBounds.width, worldBounds.height);
    for (Entry<Direction, PanelRenderer> entry : borderPanels.entries()) {
        Direction dir = entry.getKey();
        PanelRenderer panel = entry.getValue();
        switch(dir) {
            case NORTH:
            case SOUTH:
                centerBounds.width = Math.max(centerBounds.width, panel.minWidth);
                break;
            case EAST:
            case WEST:
                centerBounds.height = Math.max(centerBounds.height, panel.minHeight);
                break;
            default:
                System.err.println("INVALID BORDER DIRECTION: " + dir);
                break;
        }
    }
    float worldRenderScale = 1;
    while (((long) (centerBounds.getWidth() * worldRenderScale * tileSize) * (long) (centerBounds.getHeight() * worldRenderScale * tileSize)) > MAX_WORLD_RENDER_PIXELS) {
        worldRenderScale /= 2;
    }
    double borderTop = 0, borderRight = 0, borderBottom = 0, borderLeft = 0;
    double borderRightBudget = 0;
    for (Entry<Direction, PanelRenderer> entry : borderPanels.entries()) {
        Direction dir = entry.getKey();
        PanelRenderer panel = entry.getValue();
        switch(dir) {
            case NORTH:
                borderTop += panel.minHeight;
                break;
            case EAST:
                if (borderRightBudget + panel.minHeight > centerBounds.height) {
                    borderRightBudget = 0;
                }
                if (borderRightBudget == 0) {
                    borderRight += panel.minWidth;
                }
                borderRightBudget += panel.minHeight;
                break;
            case SOUTH:
                borderBottom += panel.minHeight;
                break;
            case WEST:
                borderLeft += panel.minWidth;
                break;
            default:
                System.err.println("INVALID BORDER DIRECTION: " + dir);
                break;
        }
    }
    if (options.has("max-width")) {
        int width = (int) ((centerBounds.width + borderLeft / worldRenderScale + borderRight / worldRenderScale) * worldRenderScale * tileSize);
        int maxWidth = options.getInt("max-width");
        if (maxWidth < 10) {
            maxWidth = 10;
        }
        if (width > maxWidth) {
            worldRenderScale = (float) ((maxWidth - tileSize * (borderLeft + borderRight)) / (centerBounds.width * tileSize));
        }
    }
    if (options.has("max-height")) {
        int height = (int) ((centerBounds.height + borderTop / worldRenderScale + borderBottom / worldRenderScale) * worldRenderScale * tileSize);
        int maxHeight = options.getInt("max-height");
        if (maxHeight < 10) {
            maxHeight = 10;
        }
        if (height > maxHeight) {
            worldRenderScale = (float) ((maxHeight - tileSize * (borderTop + borderBottom)) / (centerBounds.height * tileSize));
        }
    }
    Rectangle2D.Double totalBounds = new Rectangle2D.Double(centerBounds.x - borderLeft / worldRenderScale, centerBounds.y - borderTop / worldRenderScale, centerBounds.width + borderLeft / worldRenderScale + borderRight / worldRenderScale, centerBounds.height + borderTop / worldRenderScale + borderBottom / worldRenderScale);
    // System.out.println("IMAGE SCALE: " + worldRenderScale);
    // System.out.println("IMAGE DIM: " + (int) (totalBounds.getWidth() *
    // worldRenderScale * tileSize) + ","
    // + (int) (totalBounds.getHeight() * worldRenderScale * tileSize));
    int imageWidth = (int) (totalBounds.getWidth() * worldRenderScale * tileSize);
    int imageHeight = (int) (totalBounds.getHeight() * worldRenderScale * tileSize);
    System.out.println("\t" + imageWidth + "x" + imageHeight + " (" + worldRenderScale + ")");
    BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
    Graphics2D g = image.createGraphics();
    BufferedImage shadowImage = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
    Graphics2D shadowG = shadowImage.createGraphics();
    AffineTransform noXform = g.getTransform();
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    g.scale(image.getWidth() / totalBounds.getWidth(), image.getHeight() / totalBounds.getHeight());
    g.translate(-totalBounds.getX(), -totalBounds.getY());
    AffineTransform worldXform = g.getTransform();
    shadowG.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    shadowG.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    shadowG.setTransform(worldXform);
    // Background
    g.setColor(GROUND_COLOR);
    g.fill(totalBounds);
    // Grid Lines
    g.setStroke(GRID_STROKE);
    g.setColor(GRID_COLOR);
    for (double x = Math.round(worldBounds.getMinX()); x <= worldBounds.getMaxX(); x++) {
        g.draw(new Line2D.Double(x, worldBounds.getMinY(), x, worldBounds.getMaxY()));
    }
    for (double y = Math.round(worldBounds.getMinY()); y <= worldBounds.getMaxY(); y++) {
        g.draw(new Line2D.Double(worldBounds.getMinX(), y, worldBounds.getMaxX(), y));
    }
    renderers.stream().filter(r -> r instanceof EntityRenderer).map(r -> (EntityRenderer) r).forEach(r -> {
        try {
            r.renderShadows(shadowG);
        } catch (Exception e) {
            reporting.addException(e);
        }
    });
    shadowG.dispose();
    RenderUtils.halveAlpha(shadowImage);
    renderers.add(new Renderer(Layer.SHADOW_BUFFER, worldBounds) {

        @Override
        public void render(Graphics2D g) throws Exception {
            AffineTransform tempXform = g.getTransform();
            g.setTransform(noXform);
            g.drawImage(shadowImage, 0, 0, null);
            g.setTransform(tempXform);
        }
    });
    boolean debugBounds = options.optBoolean("debug-bounds");
    renderers.stream().sorted((r1, r2) -> {
        int ret;
        ret = r1.getLayer().compareTo(r2.getLayer());
        if (ret != 0) {
            return ret;
        }
        Rectangle2D.Double b1 = r1.getBounds();
        Rectangle2D.Double b2 = r2.getBounds();
        ret = Double.compare(b1.getMinY(), b2.getMinY());
        if (ret != 0) {
            return ret;
        }
        ret = Double.compare(b1.getMinX(), b2.getMinX());
        if (ret != 0) {
            return ret;
        }
        ret = r1.getLayer().compareTo(r2.getLayer());
        return ret;
    }).forEach(r -> {
        try {
            r.render(g);
            if (debugBounds) {
                g.setStroke(new BasicStroke(1f / 32f));
                g.setColor(Color.magenta);
                g.draw(r.bounds);
            }
        } catch (Exception e) {
            reporting.addException(e);
        }
    });
    g.setTransform(worldXform);
    // Grid Numbers
    g.setColor(GRID_COLOR);
    g.setFont(new Font("Monospaced", Font.BOLD, 1).deriveFont(0.6f));
    for (double x = Math.round(worldBounds.getMinX()) + 1, i = 1; x <= worldBounds.getMaxX() - 2; x++, i++) {
        g.drawString(String.format("%02d", (int) Math.round(i) % 100), (float) x + 0.2f, (float) (worldBounds.getMaxY() - 1 + 0.65f));
        g.drawString(String.format("%02d", (int) Math.round(i) % 100), (float) x + 0.2f, (float) (worldBounds.getMinY() + 0.65f));
    }
    for (double y = Math.round(worldBounds.getMinY()) + 1, i = 1; y <= worldBounds.getMaxY() - 2; y++, i++) {
        g.drawString(String.format("%02d", (int) Math.round(i) % 100), (float) (worldBounds.getMaxX() - 1 + 0.2f), (float) y + 0.65f);
        g.drawString(String.format("%02d", (int) Math.round(i) % 100), (float) (worldBounds.getMinX() + 0.2f), (float) y + 0.65f);
    }
    {
        Rectangle2D.Double bounds = new Rectangle2D.Double(centerBounds.getMinX(), centerBounds.getMinY(), 0, 0);
        for (PanelRenderer panel : borderPanels.get(Direction.NORTH)) {
            g.setTransform(worldXform);
            bounds.y -= panel.minHeight / worldRenderScale;
            bounds.width = centerBounds.width;
            bounds.height = panel.minHeight;
            g.translate(bounds.x, bounds.y);
            g.scale(1 / worldRenderScale, 1 / worldRenderScale);
            try {
                panel.render(g, bounds.width, bounds.height);
            } catch (Exception e) {
                reporting.addException(e);
            }
        }
    }
    {
        Rectangle2D.Double bounds = new Rectangle2D.Double(centerBounds.getMaxX(), centerBounds.getMinY(), 0, 0);
        for (PanelRenderer panel : borderPanels.get(Direction.EAST)) {
            g.setTransform(worldXform);
            if (bounds.y + panel.minHeight > centerBounds.getMaxY()) {
                bounds.y = centerBounds.getMinY();
                bounds.x += panel.minWidth;
            }
            bounds.width = panel.minWidth;
            bounds.height = panel.minHeight;
            g.translate(bounds.x, bounds.y);
            g.scale(1 / worldRenderScale, 1 / worldRenderScale);
            try {
                panel.render(g, bounds.width, bounds.height);
            } catch (Exception e) {
                reporting.addException(e);
            }
            bounds.y += panel.minHeight / worldRenderScale;
        }
    }
    {
        Rectangle2D.Double bounds = new Rectangle2D.Double(centerBounds.getMinX(), centerBounds.getMaxY(), 0, 0);
        for (PanelRenderer panel : borderPanels.get(Direction.SOUTH)) {
            g.setTransform(worldXform);
            bounds.width = centerBounds.width;
            bounds.height = panel.minHeight;
            g.translate(bounds.x, bounds.y);
            g.scale(1 / worldRenderScale, 1 / worldRenderScale);
            try {
                panel.render(g, bounds.width, bounds.height);
            } catch (Exception e) {
                reporting.addException(e);
            }
            bounds.y += panel.minHeight / worldRenderScale;
        }
    }
    {
        Rectangle2D.Double bounds = new Rectangle2D.Double(centerBounds.getMinX(), centerBounds.getMinY(), 0, 0);
        for (PanelRenderer panel : borderPanels.get(Direction.WEST)) {
            g.setTransform(worldXform);
            bounds.x -= panel.minWidth / worldRenderScale;
            bounds.width = panel.minWidth;
            bounds.height = centerBounds.height;
            g.translate(bounds.x, bounds.y);
            g.scale(1 / worldRenderScale, 1 / worldRenderScale);
            try {
                panel.render(g, bounds.width, bounds.height);
            } catch (Exception e) {
                reporting.addException(e);
            }
        }
    }
    Level level = reporting.getLevel();
    if (level != Level.INFO) {
        g.setTransform(worldXform);
        g.setStroke(GRID_STROKE);
        g.setColor(level.getColor().darker());
        g.draw(centerBounds);
    }
    g.dispose();
    return image;
}
Also used : Color(java.awt.Color) ArrayListMultimap(com.google.common.collect.ArrayListMultimap) Point2D(java.awt.geom.Point2D) Level(com.demod.dcba.CommandReporting.Level) Rectangle2D(java.awt.geom.Rectangle2D) RenderingHints(java.awt.RenderingHints) DataTable(com.demod.factorio.DataTable) JSONException(org.json.JSONException) RailEdge(com.demod.fbsr.WorldMap.RailEdge) JSONObject(org.json.JSONObject) Ellipse2D(java.awt.geom.Ellipse2D) Map(java.util.Map) ImageIO(javax.imageio.ImageIO) LinkedHashMultiset(com.google.common.collect.LinkedHashMultiset) Shape(java.awt.Shape) BufferedImage(java.awt.image.BufferedImage) Font(java.awt.Font) DataPrototype(com.demod.factorio.prototype.DataPrototype) Collection(java.util.Collection) Set(java.util.Set) AffineTransform(java.awt.geom.AffineTransform) CubicCurve2D(java.awt.geom.CubicCurve2D) ItemPrototype(com.demod.factorio.prototype.ItemPrototype) List(java.util.List) ModInfo(com.demod.factorio.ModInfo) FactorioData(com.demod.factorio.FactorioData) Entry(java.util.Map.Entry) Optional(java.util.Optional) BasicStroke(java.awt.BasicStroke) Queue(java.util.Queue) EntityPrototype(com.demod.factorio.prototype.EntityPrototype) Rectangle(java.awt.Rectangle) Multiset(com.google.common.collect.Multiset) HashMap(java.util.HashMap) RecipePrototype(com.demod.factorio.prototype.RecipePrototype) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) RailNode(com.demod.fbsr.WorldMap.RailNode) ImmutableList(com.google.common.collect.ImmutableList) Graphics2D(java.awt.Graphics2D) SimpleEntry(java.util.AbstractMap.SimpleEntry) Layer(com.demod.fbsr.Renderer.Layer) Stroke(java.awt.Stroke) TilePrototype(com.demod.factorio.prototype.TilePrototype) Line2D(java.awt.geom.Line2D) CommandReporting(com.demod.dcba.CommandReporting) IOException(java.io.IOException) FileInputStream(java.io.FileInputStream) File(java.io.File) Consumer(java.util.function.Consumer) Utils(com.demod.factorio.Utils) ArrayDeque(java.util.ArrayDeque) TotalRawCalculator(com.demod.factorio.TotalRawCalculator) Table(com.google.common.collect.Table) BasicStroke(java.awt.BasicStroke) Rectangle2D(java.awt.geom.Rectangle2D) Line2D(java.awt.geom.Line2D) BufferedImage(java.awt.image.BufferedImage) JSONException(org.json.JSONException) IOException(java.io.IOException) Font(java.awt.Font) Graphics2D(java.awt.Graphics2D) AffineTransform(java.awt.geom.AffineTransform) Level(com.demod.dcba.CommandReporting.Level)

Aggregations

CommandReporting (com.demod.dcba.CommandReporting)1 Level (com.demod.dcba.CommandReporting.Level)1 DataTable (com.demod.factorio.DataTable)1 FactorioData (com.demod.factorio.FactorioData)1 ModInfo (com.demod.factorio.ModInfo)1 TotalRawCalculator (com.demod.factorio.TotalRawCalculator)1 Utils (com.demod.factorio.Utils)1 DataPrototype (com.demod.factorio.prototype.DataPrototype)1 EntityPrototype (com.demod.factorio.prototype.EntityPrototype)1 ItemPrototype (com.demod.factorio.prototype.ItemPrototype)1 RecipePrototype (com.demod.factorio.prototype.RecipePrototype)1 TilePrototype (com.demod.factorio.prototype.TilePrototype)1 Layer (com.demod.fbsr.Renderer.Layer)1 RailEdge (com.demod.fbsr.WorldMap.RailEdge)1 RailNode (com.demod.fbsr.WorldMap.RailNode)1 ArrayListMultimap (com.google.common.collect.ArrayListMultimap)1 ImmutableList (com.google.common.collect.ImmutableList)1 LinkedHashMultiset (com.google.common.collect.LinkedHashMultiset)1 Multiset (com.google.common.collect.Multiset)1 Table (com.google.common.collect.Table)1