diff --git a/core/src/main/assets/splashes/title/archs.png b/core/src/main/assets/splashes/title/archs.png
new file mode 100644
index 000000000..cefda217e
Binary files /dev/null and b/core/src/main/assets/splashes/title/archs.png differ
diff --git a/core/src/main/assets/splashes/title/back_clusters.png b/core/src/main/assets/splashes/title/back_clusters.png
new file mode 100644
index 000000000..73e1f7492
Binary files /dev/null and b/core/src/main/assets/splashes/title/back_clusters.png differ
diff --git a/core/src/main/assets/splashes/title/front_small.png b/core/src/main/assets/splashes/title/front_small.png
new file mode 100644
index 000000000..547078333
Binary files /dev/null and b/core/src/main/assets/splashes/title/front_small.png differ
diff --git a/core/src/main/assets/splashes/title/mid_mixed.png b/core/src/main/assets/splashes/title/mid_mixed.png
new file mode 100644
index 000000000..30c31b9dc
Binary files /dev/null and b/core/src/main/assets/splashes/title/mid_mixed.png differ
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java
index c20806af6..00a58af68 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java
@@ -249,6 +249,13 @@ public class Assets {
public static final String CAVES = "splashes/caves.jpg";
public static final String CITY = "splashes/city.jpg";
public static final String HALLS = "splashes/halls.jpg";
+
+ public static class Title {
+ public static final String ARCHS = "splashes/title/archs.png";
+ public static final String BACK_CLUSTERS = "splashes/title/back_clusters.png";
+ public static final String MID_MIXED = "splashes/title/mid_mixed.png";
+ public static final String FRONT_SMALL = "splashes/title/front_small.png";
+ }
}
public static class Sprites {
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java
index a06c3f435..49470e0b8 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java
@@ -23,9 +23,9 @@ package com.shatteredpixel.shatteredpixeldungeon.scenes;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.effects.Flare;
-import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollPane;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
@@ -52,9 +52,8 @@ public class AboutScene extends PixelScene {
RectF insets = getCommonInsets();
- Archs archs = new Archs();
- archs.setSize( w, h );
- add( archs );
+ TitleBackground BG = new TitleBackground( w, h );
+ add( BG );
//darkens the arches
add(new ColorBlock(w, h, 0x88000000));
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java
index ab762c1b2..3361a6106 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java
@@ -27,9 +27,9 @@ import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.messages.Languages;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
-import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollPane;
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
@@ -82,9 +82,8 @@ public class ChangesScene extends PixelScene {
RectF insets = getCommonInsets();
- Archs archs = new Archs();
- archs.setSize(w, h);
- //archs added later
+ TitleBackground BG = new TitleBackground(w, h);
+ //background added later
w -= insets.left + insets.right;
h -= insets.top + insets.bottom;
@@ -350,7 +349,7 @@ public class ChangesScene extends PixelScene {
btnOld.setRect(btn0_6.right()-2, btn0_8.top(), 22, changesSelected == 7 ? 19 : 15);
addToBack(btnOld);
- addToBack( archs );
+ addToBack( BG );
fadeIn();
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java
index 96a19ac09..1221b955a 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java
@@ -44,6 +44,7 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.ui.GameLog;
import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndError;
@@ -164,6 +165,7 @@ public class InterlevelScene extends PixelScene {
int region = (int)Math.ceil(loadingDepth / 5f);
if (region != lastRegion){
TextureCache.clear();
+ TitleBackground.reset();
lastRegion = region;
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java
index 361374e07..b73b8808a 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java
@@ -34,10 +34,10 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.tiles.TerrainFeaturesTilemap;
-import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
import com.shatteredpixel.shatteredpixeldungeon.windows.IconTitle;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndJournal;
@@ -82,9 +82,8 @@ public class JournalScene extends PixelScene {
RectF insets = getCommonInsets();
- Archs archs = new Archs();
- archs.setSize( w, h );
- //archs added later
+ TitleBackground BG = new TitleBackground(w, h);
+ //BG added later
w -= insets.left + insets.right;
h -= insets.top + insets.bottom;
@@ -228,7 +227,7 @@ public class JournalScene extends PixelScene {
if (lastIDX != 3) btnAlchemy.icon().brightness(0.6f);
addToBack(btnAlchemy);
- addToBack(archs);
+ addToBack(BG);
ExitButton btnExit = new ExitButton();
btnExit.setPos( insets.left + w - btnExit.width(), insets.top );
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java
index 5fabd82a0..14014647c 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java
@@ -29,9 +29,9 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.services.news.News;
import com.shatteredpixel.shatteredpixeldungeon.services.news.NewsArticle;
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
-import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
@@ -64,9 +64,8 @@ public class NewsScene extends PixelScene {
int h = Camera.main.height;
RectF insets = getCommonInsets();
- Archs archs = new Archs();
- archs.setSize(w, h);
- add(archs);
+ TitleBackground BG = new TitleBackground(w, h);
+ add(BG);
w -= insets.left + insets.right;
h -= insets.top + insets.bottom;
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java
index f29552080..16187363c 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java
@@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
import com.shatteredpixel.shatteredpixeldungeon.effects.BadgeBanner;
import com.shatteredpixel.shatteredpixeldungeon.messages.Languages;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.Tooltip;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
@@ -102,6 +103,7 @@ public class PixelScene extends Scene {
if (!inGameScene && InterlevelScene.lastRegion != -1){
InterlevelScene.lastRegion = -1;
TextureCache.clear();
+ TitleBackground.reset();
//good time to clear holiday cache as well
Holiday.clearCachedHoliday();
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java
index e54c0e8ea..d6b730a1b 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java
@@ -32,12 +32,12 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.Flare;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
-import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.Button;
import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
import com.shatteredpixel.shatteredpixeldungeon.windows.IconTitle;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndDailies;
@@ -58,8 +58,6 @@ public class RankingsScene extends PixelScene {
private static final float MAX_ROW_WIDTH = 160;
private static final float GAP = 4;
-
- private Archs archs;
@Override
public void create() {
@@ -77,9 +75,8 @@ public class RankingsScene extends PixelScene {
int h = Camera.main.height;
RectF insets = getCommonInsets();
- archs = new Archs();
- archs.setSize( w, h );
- add( archs );
+ TitleBackground BG = new TitleBackground(w, h);
+ add( BG );
w -= insets.left + insets.right;
h -= insets.top + insets.bottom;
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java
index 9086f0dd7..0c61dc106 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java
@@ -29,10 +29,10 @@ import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
import com.shatteredpixel.shatteredpixeldungeon.journal.Journal;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
-import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.Button;
import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
@@ -64,10 +64,9 @@ public class StartScene extends PixelScene {
int w = Camera.main.width;
int h = Camera.main.height;
RectF insets = getCommonInsets();
-
- Archs archs = new Archs();
- archs.setSize( w, h );
- add( archs );
+
+ TitleBackground BG = new TitleBackground(w, h);
+ add( BG );
w -= insets.left + insets.right;
h -= insets.top + insets.bottom;
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java
index f7f9213f6..0ed8f1db5 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java
@@ -25,9 +25,9 @@ import com.shatteredpixel.shatteredpixeldungeon.Chrome;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.messages.Languages;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
-import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
@@ -56,9 +56,8 @@ public class SupporterScene extends PixelScene {
int elementWidth = PixelScene.landscape() ? 202 : 120;
- Archs archs = new Archs();
- archs.setSize(w, h);
- add(archs);
+ TitleBackground BG = new TitleBackground(w, h);
+ add(BG);
w -= insets.right + insets.left;
h -= insets.top + insets.bottom;
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java
index 04097f055..cddd1244f 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java
@@ -36,7 +36,7 @@ import com.shatteredpixel.shatteredpixeldungeon.sprites.EarthGuardianSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.GhostSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.RatSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.WardSprite;
-import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton;
import com.watabou.gltextures.SmartTexture;
import com.watabou.gltextures.TextureCache;
@@ -98,11 +98,9 @@ public class SurfaceScene extends PixelScene {
int h = Camera.main.height;
RectF insets = getCommonInsets();
-
- Archs archs = new Archs();
- archs.reversed = true;
- archs.setSize( w, h );
- add( archs );
+
+ TitleBackground BG = new TitleBackground(w, h);
+ add( BG );
w -= insets.left + insets.right;
h -= insets.top + insets.bottom;
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java
index 9f2a52151..80eb580dd 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java
@@ -36,10 +36,10 @@ import com.shatteredpixel.shatteredpixeldungeon.services.news.News;
import com.shatteredpixel.shatteredpixeldungeon.services.updates.AvailableUpdateData;
import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates;
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
-import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndSettings;
@@ -75,9 +75,8 @@ public class TitleScene extends PixelScene {
RectF insets = getCommonInsets();
- Archs archs = new Archs();
- archs.setSize( w, h );
- add( archs );
+ TitleBackground BG = new TitleBackground( w, h );
+ add( BG );
w -= insets.left + insets.right;
h -= insets.top + insets.bottom;
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java
index 429af253b..569fd07c1 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java
@@ -34,8 +34,8 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.Fireball;
import com.shatteredpixel.shatteredpixeldungeon.journal.Document;
import com.shatteredpixel.shatteredpixeldungeon.journal.Journal;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
-import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
+import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndError;
@@ -97,9 +97,8 @@ public class WelcomeScene extends PixelScene {
int h = Camera.main.height;
RectF insets = getCommonInsets();
- Archs archs = new Archs();
- archs.setSize( w, h );
- add( archs );
+ TitleBackground BG = new TitleBackground(w, h);
+ add( BG );
//darkens the arches
add(new ColorBlock(w, h, 0x88000000));
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java
new file mode 100644
index 000000000..7b6840df5
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java
@@ -0,0 +1,570 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2025 Evan Debenham
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ */
+
+package com.shatteredpixel.shatteredpixeldungeon.ui;
+
+import com.shatteredpixel.shatteredpixeldungeon.Assets;
+import com.watabou.gltextures.TextureCache;
+import com.watabou.noosa.Game;
+import com.watabou.noosa.Group;
+import com.watabou.noosa.Image;
+import com.watabou.noosa.TextureFilm;
+import com.watabou.noosa.ui.Component;
+import com.watabou.utils.Random;
+import com.watabou.utils.RectF;
+
+import java.util.ArrayList;
+
+public class TitleBackground extends Component {
+
+ public static float SCROLL_SPEED = 15f;
+
+ private float density = 1f;
+
+ //Arch back layer
+ private static final TextureFilm ARCH_FILM = new TextureFilm(Assets.Splashes.Title.ARCHS, 333, 100);
+ private static Group archLayer;
+ private static ArrayList archs;
+
+ //Cluster far layer
+ private static TextureFilm CLUSTER_FILM = new TextureFilm(Assets.Splashes.Title.BACK_CLUSTERS, 450, 250);
+ private static ArrayList clusters;
+ private static Group clusterLayer;
+
+ //Mixed Item middle layer 1
+ private static TextureFilm MID_FILM = new TextureFilm(Assets.Splashes.Title.MID_MIXED, 273, 242);
+ private static ArrayList mids1;
+ private static Group mids1Layer;
+ //Mixed Item middle layer 2
+ private static ArrayList mids2;
+ private static Group mids2Layer;
+
+ //Small Item front layer
+ private static TextureFilm SMALL_FILM = new TextureFilm(Assets.Splashes.Title.FRONT_SMALL, 112, 116);
+ private static ArrayList smalls;
+ private static Group smallLayer;
+
+ private static boolean wasLandscape;
+ private static float oldBaseScale = 1;
+ private static float oldWidth = 0;
+
+ public static void reset(){
+ archs = null;
+ clusters = null;
+ mids1 = null;
+ mids2 = null;
+ smalls = null;
+ }
+
+ public TitleBackground(int width, int height){
+ super();
+ x = y = 0;
+ this.width = width;
+ this.height = height;
+ setupObjects();
+ }
+
+ protected void setupObjects() {
+
+ boolean landscape = width > height;
+
+ float scale = height / 450f;
+
+ //we reset in this case as scale changes
+ if (archs != null && (landscape != wasLandscape)){
+ archs = null;
+ clusters = null;
+ mids1 = null;
+ mids2 = null;
+ smalls = null;
+ }
+ wasLandscape = landscape;
+
+ archLayer = new Group();
+ if (archs == null) {
+ archs = new ArrayList<>();
+ } else {
+ convertArchLayer(archs, archLayer, scale);
+ }
+ add(archLayer);
+
+ Image darkness = new Image(TextureCache.createGradient(0x00000000, 0x11000000, 0x22000000, 0x33000000, 0x44000000, 0x88000000));
+ darkness.angle = 90;
+ darkness.x = width;
+ darkness.scale.x = height/6f;
+ darkness.scale.y = width;
+ add(darkness);
+
+ if (!landscape){
+ scale /= 1.5f;
+ oldBaseScale /= 1.5f;
+ }
+
+ density = width / (800f * scale);
+ density = (density+0.5f)/1.5f; //pull density 33% of the way toward 1 if it is beyond it
+
+ clusterLayer = new Group();
+ if (clusters == null) {
+ clusters = new ArrayList<>();
+ } else {
+ convertFloatingLayer(clusters, clusterLayer, scale, oldWidth);
+ }
+ add(clusterLayer);
+
+ mids1Layer = new Group();
+ if (mids1 == null){
+ mids1 = new ArrayList<>();
+ } else {
+ convertFloatingLayer(mids1, mids1Layer, scale, oldWidth);
+ }
+ add(mids1Layer);
+
+ mids2Layer = new Group();
+ if (mids2 == null){
+ mids2 = new ArrayList<>();
+ } else {
+ convertFloatingLayer(mids2, mids2Layer, scale, oldWidth);
+ }
+ add(mids2Layer);
+
+ smallLayer = new Group();
+ if (smalls == null){
+ smalls = new ArrayList<>();
+ } else {
+ convertFloatingLayer(smalls, smallLayer, scale, oldWidth);
+ }
+ add(smallLayer);
+
+ oldWidth = width/scale;
+ if (!landscape){
+ scale *= 1.5f;
+ }
+ oldBaseScale = scale;
+
+ }
+
+ //*** Logic for converting images between scene resets. ***
+
+ //creates a new instance of a disposed of image, for recreation of this component after scene transition
+ protected Image convertImage(Image oldImg, float newBaseScale){
+ Image newImg = new Image(oldImg.texture);
+ newImg.frame(oldImg.frame());
+ float oldScale = oldImg.scale.x / oldBaseScale;
+ newImg.scale.set(newBaseScale*oldScale);
+ newImg.brightness(oldImg.rm);
+ float scaleDiff = newImg.scale.y / oldImg.scale.y;
+ newImg.x = oldImg.x * scaleDiff;
+ newImg.y = oldImg.y * scaleDiff;
+ newImg.angle = oldImg.angle;
+ return newImg;
+ }
+
+ protected void convertArchLayer(ArrayList layerList, Group layerGroup, float newBaseScale){
+ ArrayList oldImages = new ArrayList<>(layerList);
+ layerList.clear();
+ float rightMost = 0;
+ for (int i = 0; i < oldImages.size(); i++){
+ Image oldArch = oldImages.get(i);
+ Image newArch = convertImage(oldArch, newBaseScale);
+ layerList.add(newArch);
+ layerGroup.add(newArch);
+ rightMost = Math.max(rightMost, newArch.x + newArch.width());
+ //if we're at the end of a row and haven't hit the end yet, add more archs!
+ while (newArch.x+newArch.width() < width
+ && (i == oldImages.size()-1 || oldImages.get(i+1).y > oldArch.y)){
+ Image extraArch = new Image(Assets.Splashes.Title.ARCHS);
+ extraArch.frame(getArchFrame());
+ extraArch.scale.set(newBaseScale);
+ extraArch.x = newArch.x + newArch.width();
+ extraArch.x -= 9 * newArch.scale.x; //still want to inset here
+ extraArch.y = newArch.y; //y inset already done
+ layerList.add(extraArch);
+ layerGroup.add(extraArch);
+ newArch = extraArch;
+ }
+ }
+ }
+
+ protected void convertFloatingLayer(ArrayList layerList, Group layerGroup, float newBaseScale, float oldWidth){
+ ArrayList oldImages = new ArrayList<>(layerList);
+ layerList.clear();
+
+ float xShift = (width()/newBaseScale)/oldWidth;
+ for (int i = 0; i < oldImages.size(); i++){
+ Image oldImage = oldImages.get(i);
+ Image newImage = convertImage(oldImage, newBaseScale);
+ if (newImage.x > 0) {
+ newImage.x *= xShift;
+ }
+ layerList.add(newImage);
+ layerGroup.add(newImage);
+ }
+ }
+
+ ArrayList toMove = new ArrayList<>();
+
+ @Override
+ public synchronized void update() {
+ super.update();
+
+ float scale = height / 450f;
+ float shift = Game.elapsed * SCROLL_SPEED * scale;
+
+ updateArchLayer(scale, shift);
+ if (width <= height){
+ scale /= 1.5f;
+ }
+ shift *= 2f;
+ updateClusterLayer(scale, shift);
+ shift *= 1.5f;
+ updateMid1Layer(scale, shift);
+ shift *= 1.5f;
+ updateMid2Layer(scale, shift);
+ shift *= 1.5f;
+ updateFrontLayer(scale, shift);
+
+ }
+
+ //*** Arch layer logic ***
+
+ private static final float[] INIT_ARCH_CHANCES = {5, 5, 2, 2, 2, 2};
+ private static float[] arch_chances = INIT_ARCH_CHANCES.clone();
+
+ public RectF getArchFrame(){
+
+ int tile = Random.chances(arch_chances);
+ if (tile == -1){
+ arch_chances = INIT_ARCH_CHANCES.clone();
+ tile = Random.chances(arch_chances);
+ }
+ arch_chances[tile]--;
+
+ return ARCH_FILM.get(tile);
+ }
+
+ private void updateArchLayer(float scale, float shift){
+ float bottom = 0;
+
+ //pass over existing archs, raise them
+ for (Image arch : archs){
+ arch.y -= shift;
+ if (arch.y + arch.height() < 0){
+ toMove.add(arch);
+ } else if (arch.y + arch.height() > bottom){
+ bottom = arch.y + arch.height();
+ }
+ }
+
+ //move any archs that scrolled off camera to the bottom
+ if (!toMove.isEmpty()){
+ //we know it'll be one row
+ for (Image arch : toMove){
+ arch.frame(getArchFrame());
+ arch.y = bottom - 5*scale;
+ }
+ bottom += 100*scale; //arch height
+ toMove.clear();
+ }
+
+ //if we aren't low enough, add more arch layers
+ while (bottom < height){
+ float left = archs.isEmpty() ? -Random.IntRange(5, 100) : archs.get(0).x;
+ while (left < width){
+ Image arch = new Image(Assets.Splashes.Title.ARCHS);
+ arch.frame(getArchFrame());
+ arch.scale.set(scale);
+ arch.x = left;
+ arch.y = bottom - 5*scale;
+ archLayer.add(arch);
+ archs.add(arch);
+ left += arch.width() - (9 * scale);
+ }
+ bottom += 100*scale; //arch height
+ }
+
+ }
+
+ //*** Cluster layer logic ***
+
+ private static final float[] INIT_CLUSTER_CHANCES = {2, 2};
+ private static float[] cluster_chances = INIT_CLUSTER_CHANCES.clone();
+
+ public RectF getClusterFrame(){
+
+ int tile = Random.chances(cluster_chances);
+ if (tile == -1){
+ cluster_chances = INIT_CLUSTER_CHANCES.clone();
+ tile = Random.chances(cluster_chances);
+ }
+ cluster_chances[tile]--;
+
+ return CLUSTER_FILM.get(tile);
+ }
+
+ private void updateClusterLayer(float scale, float shift){
+ float bottom = 0;
+ float lastX = 0;
+
+ for (Image cluster : clusters){
+ cluster.y -= shift;
+ if (cluster.y + cluster.height() < -20){
+ toMove.add(cluster);
+ } else if (cluster.y + cluster.height() > bottom){
+ bottom = cluster.y + cluster.height();
+ lastX = cluster.x;
+ }
+ }
+
+ if (!toMove.isEmpty()){
+ for (Image cluster : toMove){
+ cluster.frame(getClusterFrame());
+ float flex = 0;
+ do {
+ cluster.x = Random.Float(-cluster.width()/3f, width - 2*cluster.width()/3f);
+ flex += 1;
+ } while (Math.abs(cluster.x - lastX) < density*(cluster.width()/2f - flex));
+ cluster.y = bottom - cluster.height() + Random.Float(cluster.height()/2f, cluster.height())/density;
+ cluster.angle = Random.Float(-20, 20);
+ bottom = cluster.y + cluster.height();
+ lastX = cluster.x;
+ }
+ toMove.clear();
+ }
+
+ //clusters are 250 tall, add a bit for safety
+ float padding = 300 - (300/2f / density);
+ while (bottom < (height + padding)){
+ Image cluster = new Image(Assets.Splashes.Title.BACK_CLUSTERS);
+ cluster.frame(getClusterFrame());
+ cluster.scale.set(scale);
+
+ float flex = 0;
+ do {
+ cluster.x = Random.Float(-cluster.width()/3f, width - 2*cluster.width()/3f);
+ flex += 1;
+ } while (Math.abs(cluster.x - lastX) < density*(cluster.width()/2f - flex));
+ cluster.y = bottom - cluster.height() + Random.Float(cluster.height()/2f, cluster.height())/density;
+ cluster.angle = Random.Float(-20, 20);
+
+ cluster.brightness(0.75f);
+
+ clusters.add(cluster);
+ clusterLayer.add(cluster);
+
+ bottom = cluster.y + cluster.height();
+ lastX = cluster.x;
+ }
+ }
+
+ //*** Mid layer (1 and 2) logic ***
+
+ private static final float[] INIT_MID_CHANCES = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
+ private static float[] mid_chances = INIT_MID_CHANCES.clone();
+
+ public RectF getMidFrame(){
+
+ int tile = Random.chances(mid_chances);
+ if (tile == -1){
+ mid_chances = INIT_MID_CHANCES.clone();
+ tile = Random.chances(mid_chances);
+ }
+ mid_chances[tile]--;
+
+ return MID_FILM.get(tile);
+ }
+
+ private void updateMid1Layer(float scale, float shift){
+ float bottom = 0;
+ float lastX = 0;
+
+ for (Image mid : mids1){
+ mid.y -= shift;
+ if (mid.y + mid.height() < -20){
+ toMove.add(mid);
+ } else if (mid.y + mid.height() > bottom){
+ bottom = mid.y + mid.height();
+ lastX = mid.x;
+ }
+ }
+
+ if (!toMove.isEmpty()){
+ for (Image mid : toMove){
+ mid.frame(getMidFrame());
+ float flex = 0;
+ do {
+ mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f);
+ flex += 1;
+ } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex));
+ mid.y = bottom - mid.height() + Random.Float(mid.height()*0.75f, mid.height())/density;
+ mid.angle = Random.Float(-20, 20);
+ bottom = mid.y + mid.height();
+ lastX = mid.x;
+ }
+ toMove.clear();
+ }
+
+ //mids are ~250 tall, add a bit for safety
+ float padding = 300 - (300/2f / density);
+ while (bottom < (height + padding)){
+ Image mid = new Image(Assets.Splashes.Title.MID_MIXED);
+ mid.frame(getMidFrame());
+ mid.scale.set(scale * Random.Float(0.75f, 1.25f));
+
+ float flex = 0;
+ do {
+ mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f);
+ flex += 1;
+ } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex));
+ mid.y = bottom - mid.height() + Random.Float(mid.height()/2f, mid.height())/density;
+ mid.angle = Random.Float(-20, 20);
+
+ mids1.add(mid);
+ mids1Layer.add(mid);
+
+ bottom = mid.y + mid.height();
+ lastX = mid.x;
+ }
+ }
+
+ private void updateMid2Layer(float scale, float shift){
+ float bottom = 0;
+ float lastX = 0;
+
+ for (Image mid : mids2){
+ mid.y -= shift;
+ if (mid.y + mid.height() < -20){
+ toMove.add(mid);
+ } else if (mid.y + mid.height() > bottom){
+ bottom = mid.y + mid.height();
+ lastX = mid.x;
+ }
+ }
+
+ if (!toMove.isEmpty()){
+ for (Image mid : toMove){
+ mid.frame(getMidFrame());
+ float flex = 0;
+ do {
+ mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f);
+ flex += 1;
+ } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex));
+ mid.y = bottom - mid.height() + Random.Float(mid.height()/2f, mid.height())/density;
+ mid.angle = Random.Float(-20, 20);
+ bottom = mid.y + mid.height();
+ lastX = mid.x;
+ }
+ toMove.clear();
+ }
+
+ //mids are ~250 tall, add a bit for safety
+ float padding = 300 - (300/2f / density);
+ while (bottom < (height + padding)){
+ Image mid = new Image(Assets.Splashes.Title.MID_MIXED);
+ mid.frame(getMidFrame());
+ mid.scale.set(scale * Random.Float(1.25f, 1.75f));
+
+ float flex = 0;
+ do {
+ mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f);
+ flex += 1;
+ } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex));
+ mid.y = bottom - mid.height() + Random.Float(mid.height()/2f, mid.height())/density;
+ mid.angle = Random.Float(-20, 20);
+
+ mids2.add(mid);
+ mids2Layer.add(mid);
+
+ bottom = mid.y + mid.height();
+ lastX = mid.x;
+ }
+ }
+
+ //*** Small front layer logic ***
+
+ private static final float[] INIT_SMALL_CHANCES = {1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2};
+ private static float[] small_chances = INIT_SMALL_CHANCES.clone();
+
+ public RectF getSmallFrame(){
+
+ int tile = Random.chances(small_chances);
+ if (tile == -1){
+ small_chances = INIT_SMALL_CHANCES.clone();
+ tile = Random.chances(small_chances);
+ }
+ small_chances[tile]--;
+
+ return SMALL_FILM.get(tile);
+ }
+
+ private void updateFrontLayer(float scale, float shift){
+ float bottom = 0;
+ float lastX = 0;
+
+ for (Image small : smalls){
+ small.y -= shift;
+ if (small.y + small.height() < -20){
+ toMove.add(small);
+ } else if (small.y + small.height() > bottom){
+ bottom = small.y + small.height();
+ lastX = small.x;
+ }
+ }
+
+ if (!toMove.isEmpty()){
+ for (Image small : toMove){
+ small.frame(getSmallFrame());
+ float flex = 0;
+ do {
+ small.x = Random.Float(-small.width()/3f, width - 2*small.width()/3f);
+ flex += 1;
+ } while (Math.abs(small.x - lastX) < density*(small.width() - flex));
+ small.y = bottom - small.height() + Random.Float(small.height()/2f, small.height())/density;
+ small.angle = Random.Float(-20, 20);
+ bottom = small.y + small.height();
+ lastX = small.x;
+ }
+ toMove.clear();
+ }
+
+ //smalls are ~115 tall, add a bit for safety
+ float padding = 150 - (150/2f / density);
+ while (bottom < (height + padding)){
+ Image small = new Image(Assets.Splashes.Title.FRONT_SMALL);
+ small.frame(getSmallFrame());
+ small.scale.set(scale * Random.Float(1.75f, 2.25f));
+
+ float flex = 0;
+ do {
+ small.x = Random.Float(-small.width()/3f, width - 2*small.width()/3f);
+ flex += 1;
+ } while (Math.abs(small.x - lastX) < density*(small.width() - flex));
+ small.y = bottom - small.height() + Random.Float(small.height()/2f, small.height())/density;
+ small.angle = Random.Float(-20, 20);
+
+ smalls.add(small);
+ smallLayer.add(small);
+
+ bottom = small.y + small.height();
+ lastX = small.x;
+ }
+ }
+
+}