Initial commit: Theriapolis baseline at port/godot branch point
Captures the pre-Godot-port state of the codebase. This is the rollback anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md). All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Theriapolis.Core.Data;
|
||||
using Theriapolis.Core.World;
|
||||
|
||||
namespace Theriapolis.Game.Rendering;
|
||||
|
||||
/// <summary>
|
||||
/// Manages the biome tile textures used by the world-map renderer.
|
||||
/// For Phase 0/1, all tiles are generated at runtime as flat-colour 32×32 squares
|
||||
/// with a 1px darker border and a single centered letter.
|
||||
/// Final art will replace these by swapping file contents; no code changes needed.
|
||||
/// </summary>
|
||||
public sealed class TileAtlas : IDisposable
|
||||
{
|
||||
private readonly GraphicsDevice _gd;
|
||||
private readonly Dictionary<BiomeId, Texture2D> _textures = new();
|
||||
private readonly Dictionary<int, Texture2D> _settlementIcons = new(); // keyed by tier
|
||||
private SpriteFont? _font;
|
||||
private bool _disposed;
|
||||
|
||||
public GraphicsDevice GraphicsDevice => _gd;
|
||||
|
||||
// Fallback solid-color texture for any biome that has no dedicated entry
|
||||
private Texture2D? _fallback;
|
||||
|
||||
public TileAtlas(GraphicsDevice gd)
|
||||
{
|
||||
_gd = gd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate all placeholder textures from the loaded BiomeDef array.
|
||||
/// Call once after content is loaded.
|
||||
/// </summary>
|
||||
public void GeneratePlaceholders(BiomeDef[] biomes, SpriteFont? font = null)
|
||||
{
|
||||
_font = font;
|
||||
foreach (var def in biomes)
|
||||
{
|
||||
var biomeId = BiomeAssignHelper.ParseBiomeId(def.Id);
|
||||
if (_textures.ContainsKey(biomeId)) continue;
|
||||
_textures[biomeId] = MakeTile(def);
|
||||
}
|
||||
_fallback = MakeSolidColor(Color.HotPink); // obvious "missing art" colour
|
||||
GenerateSettlementIcons();
|
||||
}
|
||||
|
||||
/// <summary>Returns the settlement icon texture for the given tier (1–5).</summary>
|
||||
public Texture2D GetSettlementIcon(int tier)
|
||||
{
|
||||
if (_settlementIcons.TryGetValue(tier, out var tex)) return tex;
|
||||
return _fallback ?? _textures.Values.First();
|
||||
}
|
||||
|
||||
private void GenerateSettlementIcons()
|
||||
{
|
||||
// Tier 1: large gold diamond (capital)
|
||||
_settlementIcons[1] = MakeSettlementIcon(20, new Color(255, 215, 0), diamond: true);
|
||||
// Tier 2: white square (city)
|
||||
_settlementIcons[2] = MakeSettlementIcon(14, new Color(230, 230, 230), diamond: false);
|
||||
// Tier 3: light-blue circle (town)
|
||||
_settlementIcons[3] = MakeSettlementIcon(10, new Color(150, 200, 255), diamond: false);
|
||||
// Tier 4: pale dot (village)
|
||||
_settlementIcons[4] = MakeSettlementIcon(6, new Color(200, 200, 200), diamond: false);
|
||||
// Tier 5 (PoI): small red circle
|
||||
_settlementIcons[5] = MakeSettlementIcon(5, new Color(200, 60, 60), diamond: false);
|
||||
}
|
||||
|
||||
private Texture2D MakeSettlementIcon(int size, Color fill, bool diamond)
|
||||
{
|
||||
var tex = new Texture2D(_gd, size, size);
|
||||
var pixels = new Color[size * size];
|
||||
float cx = (size - 1) * 0.5f;
|
||||
float cy = (size - 1) * 0.5f;
|
||||
|
||||
for (int py = 0; py < size; py++)
|
||||
for (int px = 0; px < size; px++)
|
||||
{
|
||||
float nx = px - cx, ny = py - cy;
|
||||
bool inside = diamond
|
||||
? (MathF.Abs(nx) + MathF.Abs(ny)) <= size * 0.5f
|
||||
: (nx * nx + ny * ny) <= (cx * cx);
|
||||
pixels[py * size + px] = inside ? fill : Color.Transparent;
|
||||
}
|
||||
|
||||
tex.SetData(pixels);
|
||||
return tex;
|
||||
}
|
||||
|
||||
/// <summary>Returns the texture for the given biome, falling back to the error texture.</summary>
|
||||
public Texture2D GetTile(BiomeId biome)
|
||||
{
|
||||
if (_textures.TryGetValue(biome, out var tex)) return tex;
|
||||
return _fallback ?? _textures.Values.First();
|
||||
}
|
||||
|
||||
// ── Texture generation helpers ────────────────────────────────────────────
|
||||
|
||||
private Texture2D MakeTile(BiomeDef def)
|
||||
{
|
||||
int size = Theriapolis.Core.C.WORLD_TILE_PIXELS;
|
||||
var (r, g, b) = def.ParsedColor();
|
||||
var fillColor = new Color(r, g, b);
|
||||
|
||||
var tex = new Texture2D(_gd, size, size);
|
||||
var pixels = new Color[size * size];
|
||||
Array.Fill(pixels, fillColor);
|
||||
|
||||
tex.SetData(pixels);
|
||||
return tex;
|
||||
}
|
||||
|
||||
private Texture2D MakeSolidColor(Color color)
|
||||
{
|
||||
int size = Theriapolis.Core.C.WORLD_TILE_PIXELS;
|
||||
var tex = new Texture2D(_gd, size, size);
|
||||
var pixels = new Color[size * size];
|
||||
Array.Fill(pixels, color);
|
||||
tex.SetData(pixels);
|
||||
return tex;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
foreach (var tex in _textures.Values) tex.Dispose();
|
||||
foreach (var tex in _settlementIcons.Values) tex.Dispose();
|
||||
_fallback?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Internal helper to avoid exposing the private static method on BiomeAssignStage.</summary>
|
||||
internal static class BiomeAssignHelper
|
||||
{
|
||||
public static BiomeId ParseBiomeId(string id)
|
||||
=> Theriapolis.Core.World.Generation.Stages.BiomeAssignStage.ParseBiomeId(id);
|
||||
}
|
||||
Reference in New Issue
Block a user