Skip to content
Merged
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
2 changes: 2 additions & 0 deletions C7/Lua/texture_configs/civ3/terrain.lua
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ terrain.marsh = {

terrain.river = TERRAIN .. "mtnRivers.pcx"

terrain.river_delta = TERRAIN .. "deltaRivers.pcx"

terrain.tnt = TERRAIN .. "tnt.pcx"

terrain.jungle = {
Expand Down
84 changes: 62 additions & 22 deletions C7/MapView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -361,44 +361,84 @@ public override void drawObject(LooseView looseView, GameData gameData, Tile til
public partial class RiverLayer : LooseLayer {
public static readonly Vector2 riverSize = new Vector2(128, 64);
public static readonly Vector2 riverCenterOffset = new Vector2(riverSize.X / 2, 0);
private ImageTexture riverTexture;
private ImageTexture narrowTexture;
private ImageTexture broadTexture;

public RiverLayer() {
riverTexture = TextureLoader.Load("terrain.river");
// Both textures are 4x4 grids of equal dimensions
// The narrow texture has four river deltas and 12 narrow river segments
// The broad texture has 16 broad river segments with more meandering
narrowTexture = TextureLoader.Load("terrain.river_delta");
broadTexture = TextureLoader.Load("terrain.river");
}

public override void drawObject(LooseView looseView, GameData gameData, Tile tile, Vector2 tileCenter) {
//The "point" is the easternmost point of the tile for which we are drawing rivers.
//Which river graphics to used is calculated by evaluating the tiles that neighbor
//that point.
// The point where four terrain tiles meet and where we want to center our river texture.
// It is the easternmost point of the current tile.
Vector2 thePoint = tileCenter + riverCenterOffset;

// We draw the texture centered on the point by starting the draw from half of its width away
Vector2 drawOffset = -0.5f * riverSize;

// The right river texture is calculated by evaluating the tiles around the point
Tile northOfPoint = tile.neighbors[TileDirection.NORTHEAST];
Tile eastOfPoint = tile.neighbors[TileDirection.EAST];
Tile westOfPoint = tile;
Tile southOfPoint = tile.neighbors[TileDirection.SOUTHEAST];
Tile westOfPoint = tile;

int riverGraphicsIndex = 0;
var (row, col, idx) = DeriveTextureIndex(northOfPoint, eastOfPoint, southOfPoint, westOfPoint);
if (row < 0 || col < 0 || idx < 0)
return;

Rect2 riverRectangle = new Rect2(col * riverSize.X, row * riverSize.Y, riverSize);
Rect2 screenTarget = new Rect2(thePoint + drawOffset, riverSize);

// Draw a river texture from one of the textures, depending on terrain.
// The placement calculation is the same for both river textures.

if (idx is 1 or 2 or 4 or 8) {
// Narrow set has deltas at these indexes
if (HasWater(northOfPoint, eastOfPoint, southOfPoint, westOfPoint))
looseView.DrawTextureRectRegion(narrowTexture, screenTarget, riverRectangle);
else
looseView.DrawTextureRectRegion(broadTexture, screenTarget, riverRectangle);
} else {
// TODO: When to draw from the broad texture? Is it semi-random? Is it based on elevation?

if (northOfPoint.riverSouthwest) {
riverGraphicsIndex++;
// Default: narrow rivers, less meandering
looseView.DrawTextureRectRegion(narrowTexture, screenTarget, riverRectangle);
}
if (eastOfPoint.riverNorthwest) {
riverGraphicsIndex += 2;
}

private static (int, int, int) DeriveTextureIndex(Tile north, Tile east, Tile south, Tile west) {
var textureIndex = 0;

if (north.riverSouthwest || west.riverNortheast) {
textureIndex += 1;
}
if (westOfPoint.riverSoutheast) {
riverGraphicsIndex += 4;
if (east.riverNorthwest || north.riverSoutheast) {
textureIndex += 2;
}
if (southOfPoint.riverNortheast) {
riverGraphicsIndex += 8;
if (west.riverSoutheast || south.riverNorthwest) {
textureIndex += 4;
}
if (riverGraphicsIndex == 0) {
return;
if (south.riverNortheast || east.riverSouthwest) {
textureIndex += 8;
}
int riverRow = riverGraphicsIndex / 4;
int riverColumn = riverGraphicsIndex % 4;

Rect2 riverRectangle = new Rect2(riverColumn * riverSize.X, riverRow * riverSize.Y, riverSize);
Rect2 screenTarget = new Rect2(tileCenter - (float)0.5 * riverSize + riverCenterOffset, riverSize);
looseView.DrawTextureRectRegion(riverTexture, screenTarget, riverRectangle);
// Passes "The Point" only: an oasis
if (textureIndex == 0 && (north.riverSouth || east.riverWest || west.riverEast || south.riverNorth))
return (0, 0, 0);

if (textureIndex == 0)
return (-1, -1, -1);

// We will index into a 4x4 texture matrix
return (textureIndex / 4, textureIndex % 4, textureIndex);
}

private bool HasWater(Tile north, Tile east, Tile south, Tile west) {
return north.IsWater() || east.IsWater() || south.IsWater() || west.IsWater();
}
}

Expand Down