Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions C7/Animations/AnimationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ public static string AnimationKey(UnitPrototype unit, MapUnit.AnimatedAction act
return AnimationKey(BaseAnimationKey(unit, action), direction);
}

public static readonly Dictionary<string, ImageTexture> AnimationThumbnails = new();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we ensure these caches are cleared when we clear the other caches? Otherwise we might carry things over between scenarios or when switching the textures being used.

public static readonly Dictionary<string, ImageTexture> AnimationTintThumbnails = new();

private const int thumbnailFrame = 0;
private const TileDirection thumbnailDirection = TileDirection.SOUTHEAST;
private const MapUnit.AnimatedAction thumbnailAction = MapUnit.AnimatedAction.DEFAULT;

private AudioStreamPlayer audioPlayer;

public SpriteFrames spriteFrames;
Expand All @@ -62,6 +69,32 @@ public IniData getINIData(string pathKey) {
return tr;
}

public static string GetUnitDefaultThumbnailKey(UnitPrototype unit) {
return $"{unit.artName}_{thumbnailDirection}_{thumbnailAction}_{thumbnailFrame}";
}

public (ImageTexture baseFrame, ImageTexture tintFrame) GetAnimationFrameAndTintTextures(UnitPrototype unit) {

string key = GetUnitDefaultThumbnailKey(unit);

if (AnimationThumbnails.TryGetValue(key, out ImageTexture baseImage)
&& AnimationTintThumbnails.TryGetValue(key, out ImageTexture tintImage)) {
return (baseImage, tintImage);
}

string filepath = getUnitFlicFilepath(unit, thumbnailAction);

Flic flic = Util.LoadFlic(filepath);

byte[] rawFrame = flic.Images[flicAnimationDirectionToRow(thumbnailDirection), thumbnailFrame];
// This actually doesn't return the tint frame with the civ color applied. The shader still needs to be applied.
(ImageTexture baseFrame, ImageTexture tintFrame) = Util.LoadTextureFromFlicData(rawFrame, flic.Palette, flic.Width, flic.Height);
AnimationThumbnails[key] = baseFrame;
AnimationTintThumbnails[key] = tintFrame;

return (baseFrame, tintFrame);
}

// Looks up the name of the flic file associated with a given action in an animation INI. If there is no flic file listed for the action,
// returns instead the file name for the default action, and if that's missing too, throws an exception.
public string getFlicFileName(IniData iniData, MapUnit.AnimatedAction action) {
Expand Down Expand Up @@ -104,6 +137,20 @@ private static TileDirection flicRowToAnimationDirection(int row) {
return TileDirection.NORTH;
}

private static int flicAnimationDirectionToRow(TileDirection tileDirection) {
switch (tileDirection) {
case TileDirection.SOUTHWEST: return 0;
case TileDirection.SOUTH: return 1;
case TileDirection.SOUTHEAST: return 2;
case TileDirection.EAST: return 3;
case TileDirection.NORTHEAST: return 4;
case TileDirection.NORTH: return 5;
case TileDirection.NORTHWEST: return 6;
case TileDirection.WEST: return 7;
}
return 2;
}

public static void loadFlicAnimation(string path, string name, ref SpriteFrames frames, ref SpriteFrames tint) {
Flic flic = Util.LoadFlic(path);

Expand Down Expand Up @@ -170,6 +217,11 @@ public C7Animation forUnit(UnitPrototype unit, MapUnit.AnimatedAction action) {
public C7Animation forEffect(AnimatedEffect effect) {
return new C7Animation(this, effect);
}

public static void ClearCache() {
AnimationThumbnails.Clear();
AnimationTintThumbnails.Clear();
}
}

public partial class C7Animation {
Expand Down
21 changes: 19 additions & 2 deletions C7/MapView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
using System.Linq;
using C7.Map;
using Godot;
using ConvertCiv3Media;
using C7GameData;
using C7Engine;
using Serilog;
using Serilog.Events;
using System.Diagnostics;

// Loose layers are for drawing things on the map on a per-tile basis. (Historical aside: There used to be another kind of layer called a TileLayer
Expand Down Expand Up @@ -556,6 +554,8 @@ public Vector2 scaledCellSize {

public Game game;

public MapView() { }

public int mapWidth { get; private set; }
public int mapHeight { get; private set; }
public bool wrapHorizontally { get; private set; }
Expand Down Expand Up @@ -598,6 +598,16 @@ public int getRowStartX(int y) {
const float MIN_SCALE = 0.1f;
const float MAX_SCALE = 4.0f;

private LowerRightInfoBox lowerRightInfoBox;
public override void _Ready() {
lowerRightInfoBox = GetNode<LowerRightInfoBox>("/root/C7Game/CanvasLayer/Control/GameStatus/LowerRightInfoBox");
lowerRightInfoBox.CenterCameraOnActiveUnit += OnCenterCameraOnUnit;
}

public override void _ExitTree() {
lowerRightInfoBox.CenterCameraOnActiveUnit -= OnCenterCameraOnUnit;
}

public MapView(Game game, int mapWidth, int mapHeight, bool wrapHorizontally, bool wrapVertically) {
this.game = game;
this.mapWidth = mapWidth;
Expand Down Expand Up @@ -804,4 +814,11 @@ public void centerCameraOnTile(Tile t) {
var tileCenter = new Vector2(t.XCoordinate + 1, t.YCoordinate + 1) * scaledCellSize;
setCameraLocation(tileCenter - (float)0.5 * getVisibleAreaSize());
}

public void OnCenterCameraOnUnit() {
MapUnit currentlySelectedUnit = game.CurrentlySelectedUnit;
if (currentlySelectedUnit == MapUnit.NONE || currentlySelectedUnit == null)
return;
centerCameraOnTile(currentlySelectedUnit.location);
}
}
14 changes: 14 additions & 0 deletions C7/Textures/TextureLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public ConfigEntry() {
private static Dictionary<string, Pcx> PcxCache = [];
private static Dictionary<string, Image> PngCache = [];
private static Dictionary<string, Color> colorCache = [];
private static Dictionary<int, ShaderMaterial> materialCache = [];

private static Dictionary<string, ImageTexture> configKeyCache = [];
private static Dictionary<(string configKey, object obj), ImageTexture> objectMappingCache = [];
Expand Down Expand Up @@ -458,6 +459,18 @@ private static Image LoadPNG(string relPath) {
return png;
}

public static ShaderMaterial GetShaderMaterialForUnit(int civIndex) {
if (materialCache.TryGetValue(civIndex, out ShaderMaterial material)) {
return material;
}
material = new();
material.Shader = GD.Load<Shader>("res://UnitTint.gdshader");
Color civColor = LoadColor(civIndex);
material.SetShaderParameter("tintColor", new Vector3(civColor.R, civColor.G, civColor.B));
materialCache[civIndex] = material;
return material;
}

public static void ClearCache() {
PcxCache.Clear();
PngCache.Clear();
Expand All @@ -466,5 +479,6 @@ public static void ClearCache() {
objectMappingCache.Clear();
animationCache.Clear();
colorCache.Clear();
materialCache.Clear();
}
}
22 changes: 3 additions & 19 deletions C7/UIElements/CityScreen/CityScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -594,25 +594,9 @@ private void RenderProductionDetails(GameData gameData, City city) {
}

if (city.itemBeingProduced is UnitPrototype up) {
// Get the flic data for the unit we're producing.
string path = new AnimationManager(null).getUnitFlicFilepath(up, MapUnit.AnimatedAction.DEFAULT);
ConvertCiv3Media.Flic flic = Util.LoadFlic(path);

// Set up a shader we can use to color the "tint" portion of the
// animation frame below.
ShaderMaterial material = new();
material.Shader = GD.Load<Shader>("res://UnitTint.gdshader");
Color civColor = TextureLoader.LoadColor(city.owner.colorIndex);
material.SetShaderParameter("tintColor", new Vector3(civColor.R, civColor.G, civColor.B));

// See flicRowToAnimationDirection for the mapping, row 2 is facing
// southeast, and we're just grabbing frame 0.
byte[] frame = flic.Images[2, 0];

// Each frame is split in two parts, the base image, and the "tint"
// of the image, which is the part of the unit that has civ-specific
// colors.
(ImageTexture baseImage, ImageTexture imageTint) = Util.LoadTextureFromFlicData(frame, flic.Palette, flic.Width, flic.Height);
AnimationManager animationManager = mapView.game.animationController.civ3AnimData.forUnit(up, MapUnit.AnimatedAction.DEFAULT).animationManager;
ShaderMaterial material = TextureLoader.GetShaderMaterialForUnit(city.owner.colorIndex);
(ImageTexture baseImage, ImageTexture imageTint) = animationManager.GetAnimationFrameAndTintTextures(up);

// Add the base sprite.
Sprite2D baseImageSprite = new();
Expand Down
Loading