diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/bo/rendering/G2DDrawBackground.java b/src/main/java/de/extio/game_engine/renderer/g2d/bo/rendering/G2DDrawBackground.java index 7df1c02..7011b8f 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/bo/rendering/G2DDrawBackground.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/bo/rendering/G2DDrawBackground.java @@ -17,6 +17,7 @@ import org.springframework.stereotype.Component; import de.extio.game_engine.renderer.RendererControl; import de.extio.game_engine.renderer.g2d.G2DRendererCondition; import de.extio.game_engine.renderer.g2d.G2DRendererControl; +import de.extio.game_engine.renderer.g2d.theme.G2DThemeManager; import de.extio.game_engine.renderer.model.RenderingBo; import de.extio.game_engine.renderer.model.RenderingBoLayer; import de.extio.game_engine.renderer.model.color.ImmutableRgbaColor; @@ -39,12 +40,6 @@ public class G2DDrawBackground extends G2DAbstractRenderingBo { private final static int[] BUILTIN_SCROLL_OFFSET_X = new int[2]; - private final static List STARS = new ArrayList<>(); - - private final static List REFERENCE_STARS = new ArrayList<>(); - - private static CoordI2 STARS_LAST_VIEWPORT = ImmutableCoordI2.create(); - private final CoordI2 bgrOffset = MutableCoordI2.create(); private final CoordI2 sourceOffset = MutableCoordI2.create(); @@ -97,7 +92,7 @@ public class G2DDrawBackground extends G2DAbstractRenderingBo { this.bgrOffset.setXY(this.rendererData.getUiOptions().getBackgroundOffset0()).add(BUILTIN_SCROLL_OFFSET_X[0], 0), windowDim); this.scroll(1, this.rendererData.getUiOptions().isBackgroundScrolling1(), this.rendererData.getUiOptions().isBackgroundScrollingReverse1(), windowDim); - this.drawStars(graphics, this.bgrOffset.setXY(this.rendererData.getUiOptions().getBackgroundOffset1()).add(BUILTIN_SCROLL_OFFSET_X[1], 0), windowDim); + ((G2DThemeManager) this.rendererData.getThemeManager()).getCurrentPatternRenderer().drawBackgroundPattern(graphics, this.bgrOffset.setXY(this.rendererData.getUiOptions().getBackgroundOffset1()).add(BUILTIN_SCROLL_OFFSET_X[1], 0), windowDim); } private void tileBackground(final Graphics2D graphics, final int index, final StaticResource backgroundResource, final CoordI2 offset, final CoordI2 viewPort) { @@ -146,19 +141,6 @@ public class G2DDrawBackground extends G2DAbstractRenderingBo { } while (this.destPosition.getY() < viewPort.getY()); } - private void drawStars(final Graphics2D graphics, final CoordI2 offset, final CoordI2 viewPort) { - this.generateStars(viewPort); - - for (final Star element : STARS) { - graphics.setColor(element.color.toAwtColor()); - graphics.fillOval( - Math.floorMod(element.position.getX() - offset.getX(), viewPort.getX()), - Math.floorMod(element.position.getY() - offset.getY(), viewPort.getY()), - element.radius.getX(), - element.radius.getY()); - } - } - private void scroll(final int index, final boolean scrolling, final boolean reverse, final CoordI2 viewPort) { if (!scrolling) { BUILTIN_SCROLL_OFFSET_X[index] = 0; @@ -235,50 +217,4 @@ public class G2DDrawBackground extends G2DAbstractRenderingBo { } } - private void generateStars(final CoordI2 viewPort) { - if (REFERENCE_STARS.isEmpty()) { - final var rand = ThreadLocalXorShift128Random.current(); - - for (var i = 0; i < 350; i++) { - final var position = ImmutableCoordI2.create(rand.nextInt(RendererControl.REFERENCE_RESOLUTION.getX()), rand.nextInt(RendererControl.REFERENCE_RESOLUTION.getY())); - final var radius = ImmutableCoordI2.create(rand.nextInt(3) + 2, rand.nextInt(3) + 2); - final var color = new ImmutableRgbaColor(rand.nextInt(30) + 100, rand.nextInt(30) + 100, rand.nextInt(30) + 130); - - REFERENCE_STARS.add(new Star(position, radius, color)); - STARS.add(new Star(position, radius, color)); - } - } - - if (!viewPort.equals(STARS_LAST_VIEWPORT)) { - final double scaleX = (double) viewPort.getX() / RendererControl.REFERENCE_RESOLUTION.getX(); - final double scaleY = (double) viewPort.getY() / RendererControl.REFERENCE_RESOLUTION.getY(); - - for (int i = 0; i < REFERENCE_STARS.size(); i++) { - final var refStar = REFERENCE_STARS.get(i); - final var star = STARS.get(i); - - star.position = ImmutableCoordI2.create( - (int) (refStar.position.getX() * scaleX), - (int) (refStar.position.getY() * scaleY)); - } - STARS_LAST_VIEWPORT = viewPort.toImmutableCoordI2(); - } - } - - private static class Star { - - CoordI2 position; - - CoordI2 radius; - - RgbaColor color; - - Star(final CoordI2 position, final CoordI2 radius, final RgbaColor color) { - super(); - this.position = position; - this.radius = radius; - this.color = color; - } - - } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/BevelPatternRenderer.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/BevelPatternRenderer.java index f6ace41..79a961a 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/BevelPatternRenderer.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/BevelPatternRenderer.java @@ -7,6 +7,7 @@ import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; import de.extio.game_engine.renderer.g2d.G2DRendererCondition; +import de.extio.game_engine.spatial2.model.CoordI2; /** * Implementation of PatternRenderer that draws borders and panels in a classic "Bevel" style. @@ -27,11 +28,12 @@ public class BevelPatternRenderer implements PatternRenderer { if (hsb[2] < 0.5f) { light = color.brighter(); dark = color; - } else { + } + else { light = color; dark = color.darker(); } - + // Outer bevel (raised) drawBevel(g2d, x, y, width, height, strength + 1, true, light, dark); } @@ -71,14 +73,16 @@ public class BevelPatternRenderer implements PatternRenderer { // Button bevel int bevelStrength = (int) (2 * scaleFactor); - if (bevelStrength < 1) bevelStrength = 1; + if (bevelStrength < 1) + bevelStrength = 1; final Color highlight = theme.getBorderOuter().toColor(); final Color shadow = theme.getBorderInner().toColor(); if (pressed) { drawBevel(g2d, 0, 0, width, height, bevelStrength, false, highlight, shadow); - } else { + } + else { drawBevel(g2d, 0, 0, width, height, bevelStrength, true, highlight, shadow); } @@ -88,14 +92,14 @@ public class BevelPatternRenderer implements PatternRenderer { final int offset = pressed ? 1 : 0; // Draw a simple X - final int padding = (int)(4 * scaleFactor); + final int padding = (int) (4 * scaleFactor); final int x1 = padding + offset; final int y1 = padding + offset; final int x2 = width - padding + offset; final int y2 = height - padding + offset; final Graphics2D g2 = (Graphics2D) g2d.create(); - g2.setStroke(new java.awt.BasicStroke((float)(2 * scaleFactor))); + g2.setStroke(new java.awt.BasicStroke((float) (2 * scaleFactor))); g2.drawLine(x1, y1, x2, y2); g2.drawLine(x1, y2, x2, y1); g2.dispose(); @@ -118,4 +122,18 @@ public class BevelPatternRenderer implements PatternRenderer { g2d.drawLine(x + width - 1 - i, y + i, x + width - 1 - i, y + height - 1 - i); // Right } } + + @Override + public void drawBackgroundPattern(final Graphics2D g2d, final CoordI2 offset, final CoordI2 viewPort) { + g2d.setColor(new Color(255, 255, 255, 35)); + final int spacing = 20; + final int offX = Math.floorMod(offset.getX(), spacing); + final int offY = Math.floorMod(offset.getY(), spacing); + + for (int x = -spacing; x < viewPort.getX() + spacing; x += spacing) { + for (int y = -spacing; y < viewPort.getY() + spacing; y += spacing) { + g2d.fillRect(x + offX, y + offY, 2, 2); + } + } + } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/BlueprintPatternRenderer.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/BlueprintPatternRenderer.java index a0e74f6..0f6e96f 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/BlueprintPatternRenderer.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/BlueprintPatternRenderer.java @@ -4,12 +4,14 @@ import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Stroke; +import java.awt.image.BufferedImage; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; import de.extio.game_engine.renderer.g2d.G2DRendererCondition; import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont; +import de.extio.game_engine.spatial2.model.CoordI2; /** * Implementation of PatternRenderer that draws a technical "Blueprint" style with grids and measurement markers. @@ -126,4 +128,41 @@ public class BlueprintPatternRenderer implements PatternRenderer { g2.dispose(); } } + + private java.awt.image.BufferedImage patternCache; + + private java.awt.image.BufferedImage getPatternCache() { + if (this.patternCache == null) { + final int gridSize = 50; + this.patternCache = new BufferedImage(gridSize, gridSize, java.awt.image.BufferedImage.TYPE_INT_ARGB); + final Graphics2D g2d = this.patternCache.createGraphics(); + + g2d.setBackground(new Color(0, 0, 0, 0)); + g2d.clearRect(0, 0, gridSize, gridSize); + + g2d.setColor(new Color(255, 255, 255, 35)); + g2d.setStroke(new BasicStroke(1f)); + + g2d.drawLine(0, 0, 0, gridSize); + g2d.drawLine(0, 0, gridSize, 0); + + g2d.dispose(); + } + return this.patternCache; + } + + @Override + public void drawBackgroundPattern(final Graphics2D g2d, final CoordI2 offset, final CoordI2 viewPort) { + final var cache = this.getPatternCache(); + final int gridSize = cache.getWidth(); + + final int offX = Math.floorMod(offset.getX(), gridSize); + final int offY = Math.floorMod(offset.getY(), gridSize); + + for (int x = -gridSize; x <= viewPort.getX() + gridSize; x += gridSize) { + for (int y = -gridSize; y <= viewPort.getY() + gridSize; y += gridSize) { + g2d.drawImage(cache, x + offX, y + offY, null); + } + } + } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/DreamPatternRenderer.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/DreamPatternRenderer.java index cb0e80e..a8f8ca9 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/DreamPatternRenderer.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/DreamPatternRenderer.java @@ -2,12 +2,14 @@ package de.extio.game_engine.renderer.g2d.theme; import java.awt.Color; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; import de.extio.game_engine.renderer.g2d.G2DRendererCondition; import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont; +import de.extio.game_engine.spatial2.model.CoordI2; @Conditional(G2DRendererCondition.class) @Component @@ -96,4 +98,41 @@ public class DreamPatternRenderer implements PatternRenderer { final var textDim = G2DDrawFont.getTextDimensions("X", g2d, 15, scaleFactor); G2DDrawFont.renderText(g2d, textDim, 1.0, ((width - textDim.getX()) / 2), ((height - textDim.getY()) / 2), fontSize, "X"); } + + private java.awt.image.BufferedImage patternCache; + + private java.awt.image.BufferedImage getPatternCache() { + if (this.patternCache == null) { + final int cellSize = 100; + this.patternCache = new BufferedImage(cellSize, cellSize, java.awt.image.BufferedImage.TYPE_INT_ARGB); + final Graphics2D g2d = this.patternCache.createGraphics(); + + // Clear background (transparent) + g2d.setBackground(new Color(0, 0, 0, 0)); + g2d.clearRect(0, 0, cellSize, cellSize); + + // Draw pattern + g2d.setColor(new Color(255, 255, 255, 35)); + g2d.fillOval(20, 20, 40, 40); + g2d.fillOval(70, 80, 15, 15); + + g2d.dispose(); + } + return this.patternCache; + } + + @Override + public void drawBackgroundPattern(final Graphics2D g2d, final CoordI2 offset, final CoordI2 viewPort) { + final var cache = this.getPatternCache(); + final int cellSize = cache.getWidth(); + + final int offX = Math.floorMod(offset.getX(), cellSize); + final int offY = Math.floorMod(offset.getY(), cellSize); + + for (int x = -cellSize; x < viewPort.getX() + cellSize; x += cellSize) { + for (int y = -cellSize; y < viewPort.getY() + cellSize; y += cellSize) { + g2d.drawImage(cache, x + offX, y + offY, null); + } + } + } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/FantasyPatternRenderer.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/FantasyPatternRenderer.java index a5a47dc..f9c4161 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/FantasyPatternRenderer.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/FantasyPatternRenderer.java @@ -2,11 +2,13 @@ package de.extio.game_engine.renderer.g2d.theme; import java.awt.Color; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; import de.extio.game_engine.renderer.g2d.G2DRendererCondition; +import de.extio.game_engine.spatial2.model.CoordI2; @Conditional(G2DRendererCondition.class) @Component @@ -105,4 +107,40 @@ public class FantasyPatternRenderer implements PatternRenderer { g2d.fillRect(centerX - crossSize / 2, centerY - t / 2, crossSize, t); g2d.fillRect(centerX - t / 2, centerY - crossSize / 2, t, crossSize); } + + private java.awt.image.BufferedImage patternCache; + + private java.awt.image.BufferedImage getPatternCache() { + if (this.patternCache == null) { + final int cellSize = 80; + this.patternCache = new BufferedImage(cellSize, cellSize, java.awt.image.BufferedImage.TYPE_INT_ARGB); + final Graphics2D g2d = this.patternCache.createGraphics(); + + g2d.setBackground(new Color(0, 0, 0, 0)); + g2d.clearRect(0, 0, cellSize, cellSize); + + g2d.setColor(new Color(255, 255, 255, 35)); + g2d.fillRect(10, 10, 2, 2); + g2d.fillRect(50, 60, 3, 3); + g2d.fillRect(30, 50, 1, 1); + + g2d.dispose(); + } + return this.patternCache; + } + + @Override + public void drawBackgroundPattern(final Graphics2D g2d, final CoordI2 offset, final CoordI2 viewPort) { + final var cache = this.getPatternCache(); + final int cellSize = cache.getWidth(); + + final int offX = Math.floorMod(offset.getX(), cellSize); + final int offY = Math.floorMod(offset.getY(), cellSize); + + for (int x = -cellSize; x < viewPort.getX() + cellSize; x += cellSize) { + for (int y = -cellSize; y < viewPort.getY() + cellSize; y += cellSize) { + g2d.drawImage(cache, x + offX, y + offY, null); + } + } + } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/G2DThemeManager.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/G2DThemeManager.java index 87ea1f2..94401f3 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/G2DThemeManager.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/G2DThemeManager.java @@ -169,6 +169,7 @@ public class G2DThemeManager implements ThemeManager { this.applyTheme(persistedTheme.get()); this.registerTheme(this.currentTheme); LOGGER.info("Loaded last used theme: {}", this.currentTheme.getName()); + return; } this.applyTheme(this.defaultTheme); @@ -215,4 +216,8 @@ public class G2DThemeManager implements ThemeManager { public PatternRenderer getPatternRenderer(final String rendererName) { return this.patternRenderers.get(rendererName); } + + public PatternRenderer getCurrentPatternRenderer() { + return this.patternRenderers.get(this.currentTheme.getPatternRendererName()); + } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/MetroPatternRenderer.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/MetroPatternRenderer.java index 0aee664..47bc130 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/MetroPatternRenderer.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/MetroPatternRenderer.java @@ -2,11 +2,13 @@ package de.extio.game_engine.renderer.g2d.theme; import java.awt.Color; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; import de.extio.game_engine.renderer.g2d.G2DRendererCondition; +import de.extio.game_engine.spatial2.model.CoordI2; @Conditional(G2DRendererCondition.class) @Component @@ -109,4 +111,38 @@ public class MetroPatternRenderer implements PatternRenderer { g2d.fillRect(centerX - crossSize / 2, centerY - t / 2, crossSize, t); g2d.fillRect(centerX - t / 2, centerY - crossSize / 2, t, crossSize); } + + private java.awt.image.BufferedImage patternCache; + + private java.awt.image.BufferedImage getPatternCache() { + if (this.patternCache == null) { + final int spacing = 40; + this.patternCache = new BufferedImage(spacing, spacing, java.awt.image.BufferedImage.TYPE_INT_ARGB); + final Graphics2D g2d = this.patternCache.createGraphics(); + + g2d.setBackground(new Color(0, 0, 0, 0)); + g2d.clearRect(0, 0, spacing, spacing); + + g2d.setColor(new Color(255, 255, 255, 35)); + g2d.drawLine(0, 0, spacing, spacing); + + g2d.dispose(); + } + return this.patternCache; + } + + @Override + public void drawBackgroundPattern(final Graphics2D g2d, final CoordI2 offset, final CoordI2 viewPort) { + final var cache = this.getPatternCache(); + final int spacing = cache.getWidth(); + + final int offX = Math.floorMod(offset.getX(), spacing); + final int offY = Math.floorMod(offset.getY(), spacing); + + for (int x = -spacing; x < viewPort.getX() + spacing; x += spacing) { + for (int y = -spacing; y < viewPort.getY() + spacing; y += spacing) { + g2d.drawImage(cache, x + offX, y + offY, null); + } + } + } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/ModernPatternRenderer.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/ModernPatternRenderer.java index f9d0444..1265143 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/ModernPatternRenderer.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/ModernPatternRenderer.java @@ -2,12 +2,14 @@ package de.extio.game_engine.renderer.g2d.theme; import java.awt.Color; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; import de.extio.game_engine.renderer.g2d.G2DRendererCondition; import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont; +import de.extio.game_engine.spatial2.model.CoordI2; @Conditional(G2DRendererCondition.class) @Component @@ -96,4 +98,42 @@ public class ModernPatternRenderer implements PatternRenderer { final var textDim = G2DDrawFont.getTextDimensions("X", g2d, 14, scaleFactor); G2DDrawFont.renderText(g2d, textDim, 1.0, ((width - textDim.getX()) / 2), ((height - textDim.getY()) / 2), fontSize, "X"); } + + private java.awt.image.BufferedImage patternCache; + + private java.awt.image.BufferedImage getPatternCache() { + if (this.patternCache == null) { + final int spacing = 60; + this.patternCache = new BufferedImage(spacing, spacing, java.awt.image.BufferedImage.TYPE_INT_ARGB); + final Graphics2D g2d = this.patternCache.createGraphics(); + + g2d.setBackground(new Color(0, 0, 0, 0)); + g2d.clearRect(0, 0, spacing, spacing); + + g2d.setColor(new Color(255, 255, 255, 35)); + final int len = 10; + final int cx = spacing / 2; + final int cy = spacing / 2; + g2d.drawLine(cx - len, cy, cx + len, cy); + g2d.drawLine(cx, cy - len, cx, cy + len); + + g2d.dispose(); + } + return this.patternCache; + } + + @Override + public void drawBackgroundPattern(final Graphics2D g2d, final CoordI2 offset, final CoordI2 viewPort) { + final var cache = this.getPatternCache(); + final int spacing = cache.getWidth(); + + final int offX = Math.floorMod(offset.getX(), spacing); + final int offY = Math.floorMod(offset.getY(), spacing); + + for (int x = -spacing; x < viewPort.getX() + spacing; x += spacing) { + for (int y = -spacing; y < viewPort.getY() + spacing; y += spacing) { + g2d.drawImage(cache, x + offX, y + offY, null); + } + } + } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/PatternRenderer.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/PatternRenderer.java index 7dafa0d..4937bfd 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/PatternRenderer.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/PatternRenderer.java @@ -3,6 +3,8 @@ package de.extio.game_engine.renderer.g2d.theme; import java.awt.Color; import java.awt.Graphics2D; +import de.extio.game_engine.spatial2.model.CoordI2; + /** * Interface for rendering common UI patterns like borders, backgrounds, shadows, etc. * Different implementations can provide different visual styles. @@ -64,4 +66,13 @@ public interface PatternRenderer { * @param theme Theme to use for colors */ void drawCloseButton(Graphics2D g2d, int width, int height, boolean enabled, int state, Color backgroundColor, double scaleFactor, Theme theme); + + /** + * Draws a background pattern for the UI on layer BACKGROUND1 + * + * @param g2d The graphics context + * @param offset Offset for pattern alignment + * @param viewPort Viewport size + */ + void drawBackgroundPattern(final Graphics2D g2d, final CoordI2 offset, final CoordI2 viewPort); } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/SpacecraftPatternRenderer.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/SpacecraftPatternRenderer.java index 39ce609..cf1c264 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/SpacecraftPatternRenderer.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/SpacecraftPatternRenderer.java @@ -2,13 +2,20 @@ package de.extio.game_engine.renderer.g2d.theme; import java.awt.Color; import java.awt.Graphics2D; +import java.util.ArrayList; +import java.util.List; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; +import de.extio.game_engine.renderer.RendererControl; import de.extio.game_engine.renderer.g2d.G2DRendererCondition; import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont; +import de.extio.game_engine.renderer.model.color.ImmutableRgbaColor; import de.extio.game_engine.renderer.model.color.RgbaColor; +import de.extio.game_engine.spatial2.model.CoordI2; +import de.extio.game_engine.spatial2.model.ImmutableCoordI2; +import de.extio.game_engine.util.rng.ThreadLocalXorShift128Random; /** * Default implementation of PatternRenderer that draws borders and panels in a decorative style. @@ -18,6 +25,12 @@ import de.extio.game_engine.renderer.model.color.RgbaColor; @Component public class SpacecraftPatternRenderer implements PatternRenderer { + private final static List STARS = new ArrayList<>(); + + private final static List REFERENCE_STARS = new ArrayList<>(); + + private static CoordI2 STARS_LAST_VIEWPORT = ImmutableCoordI2.create(); + @Override public void drawDecorativeBorder(final Graphics2D g2d, final int x, final int y, final int width, final int height, final int strength, final Color color) { final var strength2 = strength * 2; @@ -99,4 +112,65 @@ public class SpacecraftPatternRenderer implements PatternRenderer { G2DDrawFont.renderText(g2d, textDim, 1.0, ((width - textDim.getX()) / 2), ((height - textDim.getY()) / 2), (int) (16 * scaleFactor), "X"); } } + + @Override + public void drawBackgroundPattern(final Graphics2D g2d, final CoordI2 offset, final CoordI2 viewPort) { + this.generateStars(viewPort); + + for (final Star element : STARS) { + g2d.setColor(element.color.toAwtColor()); + g2d.fillOval( + Math.floorMod(element.position.getX() - offset.getX(), viewPort.getX()), + Math.floorMod(element.position.getY() - offset.getY(), viewPort.getY()), + element.radius.getX(), + element.radius.getY()); + } + } + + private void generateStars(final CoordI2 viewPort) { + if (REFERENCE_STARS.isEmpty()) { + final var rand = ThreadLocalXorShift128Random.current(); + + for (var i = 0; i < 350; i++) { + final var position = ImmutableCoordI2.create(rand.nextInt(RendererControl.REFERENCE_RESOLUTION.getX()), rand.nextInt(RendererControl.REFERENCE_RESOLUTION.getY())); + final var radius = ImmutableCoordI2.create(rand.nextInt(3) + 2, rand.nextInt(3) + 2); + final var color = new ImmutableRgbaColor(rand.nextInt(30) + 100, rand.nextInt(30) + 100, rand.nextInt(30) + 130); + + REFERENCE_STARS.add(new Star(position, radius, color)); + STARS.add(new Star(position, radius, color)); + } + } + + if (!viewPort.equals(STARS_LAST_VIEWPORT)) { + final double scaleX = (double) viewPort.getX() / RendererControl.REFERENCE_RESOLUTION.getX(); + final double scaleY = (double) viewPort.getY() / RendererControl.REFERENCE_RESOLUTION.getY(); + + for (int i = 0; i < REFERENCE_STARS.size(); i++) { + final var refStar = REFERENCE_STARS.get(i); + final var star = STARS.get(i); + + star.position = ImmutableCoordI2.create( + (int) (refStar.position.getX() * scaleX), + (int) (refStar.position.getY() * scaleY)); + } + STARS_LAST_VIEWPORT = viewPort.toImmutableCoordI2(); + } + } + + private static class Star { + + CoordI2 position; + + CoordI2 radius; + + RgbaColor color; + + Star(final CoordI2 position, final CoordI2 radius, final RgbaColor color) { + super(); + this.position = position; + this.radius = radius; + this.color = color; + } + + } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/UrbanPatternRenderer.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/UrbanPatternRenderer.java index 0d1ea4e..f7eb12d 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/UrbanPatternRenderer.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/UrbanPatternRenderer.java @@ -7,6 +7,7 @@ import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; import de.extio.game_engine.renderer.g2d.G2DRendererCondition; +import de.extio.game_engine.spatial2.model.CoordI2; @Conditional(G2DRendererCondition.class) @Component @@ -110,4 +111,20 @@ public class UrbanPatternRenderer implements PatternRenderer { g2d.fillRect(centerX - crossSize / 2, centerY - t / 2, crossSize, t); g2d.fillRect(centerX - t / 2, centerY - crossSize / 2, t, crossSize); } + + @Override + public void drawBackgroundPattern(final Graphics2D g2d, final CoordI2 offset, final CoordI2 viewPort) { + g2d.setColor(new Color(255, 255, 255, 35)); + final int cellSize = 60; + final int offX = Math.floorMod(offset.getX(), cellSize); + final int offY = Math.floorMod(offset.getY(), cellSize); + + for (int x = -cellSize; x < viewPort.getX() + cellSize; x += cellSize) { + for (int y = -cellSize; y < viewPort.getY() + cellSize; y += cellSize) { + // Vertical streaks + g2d.fillRect(x + offX + 10, y + offY + 5, 2, 15); + g2d.fillRect(x + offX + 40, y + offY + 35, 2, 10); + } + } + } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/theme/VintagePatternRenderer.java b/src/main/java/de/extio/game_engine/renderer/g2d/theme/VintagePatternRenderer.java index ff03fe4..3f5731e 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/theme/VintagePatternRenderer.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/theme/VintagePatternRenderer.java @@ -2,11 +2,13 @@ package de.extio.game_engine.renderer.g2d.theme; import java.awt.Color; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; import de.extio.game_engine.renderer.g2d.G2DRendererCondition; +import de.extio.game_engine.spatial2.model.CoordI2; @Conditional(G2DRendererCondition.class) @Component @@ -146,4 +148,40 @@ public class VintagePatternRenderer implements PatternRenderer { g2d.fillRect(centerX - crossThickness / 2, centerY - crossSize / 2, crossThickness, crossSize); } } + + private java.awt.image.BufferedImage patternCache; + + private java.awt.image.BufferedImage getPatternCache() { + if (this.patternCache == null) { + final int cellSize = 150; + this.patternCache = new BufferedImage(cellSize, cellSize, java.awt.image.BufferedImage.TYPE_INT_ARGB); + final Graphics2D g2d = this.patternCache.createGraphics(); + + g2d.setBackground(new Color(0, 0, 0, 0)); + g2d.clearRect(0, 0, cellSize, cellSize); + + g2d.setColor(new Color(255, 255, 255, 35)); + g2d.drawLine(10, 10, 20, 30); + g2d.drawLine(60, 50, 55, 70); + g2d.fillOval(80, 20, 2, 2); + + g2d.dispose(); + } + return this.patternCache; + } + + @Override + public void drawBackgroundPattern(final Graphics2D g2d, final CoordI2 offset, final CoordI2 viewPort) { + final var cache = this.getPatternCache(); + final int cellSize = cache.getWidth(); + + final int offX = Math.floorMod(offset.getX(), cellSize); + final int offY = Math.floorMod(offset.getY(), cellSize); + + for (int x = -cellSize; x < viewPort.getX() + cellSize; x += cellSize) { + for (int y = -cellSize; y < viewPort.getY() + cellSize; y += cellSize) { + g2d.drawImage(cache, x + offX, y + offY, null); + } + } + } } diff --git a/src/main/java/de/extio/game_engine/renderer/model/options/UiOptions.java b/src/main/java/de/extio/game_engine/renderer/model/options/UiOptions.java index ce2eba6..1d18173 100644 --- a/src/main/java/de/extio/game_engine/renderer/model/options/UiOptions.java +++ b/src/main/java/de/extio/game_engine/renderer/model/options/UiOptions.java @@ -16,7 +16,7 @@ public final class UiOptions { private boolean backgroundScrollingReverse0; - private boolean backgroundScrolling1 = true; + private boolean backgroundScrolling1; private boolean backgroundScrollingReverse1;