Initial commit

EmmaTheMartian f8373acd

+8
.editorconfig
··· 1 + root = true 2 + 3 + [*.cs] 4 + charset = utf-8 5 + end_of_line = lf 6 + insert_final_newline = true 7 + trim_trailing_whitespace = true 8 + indent_style = tab
+2
.gitignore
··· 1 + **/obj/ 2 + **/bin/
+26
.vscode/launch.json
··· 1 + { 2 + "version": "0.2.0", 3 + "configurations": [ 4 + { 5 + // Use IntelliSense to find out which attributes exist for C# debugging 6 + // Use hover for the description of the existing attributes 7 + // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md 8 + "name": ".NET Core Launch (console)", 9 + "type": "coreclr", 10 + "request": "launch", 11 + "preLaunchTask": "build", 12 + // If you have changed target frameworks, make sure to update the program path. 13 + "program": "${workspaceFolder}/Electropunk/bin/Debug/net9.0/Electropunk.dll", 14 + "args": [], 15 + "cwd": "${workspaceFolder}/", 16 + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console 17 + "console": "internalConsole", 18 + "stopAtEntry": false 19 + }, 20 + { 21 + "name": ".NET Core Attach", 22 + "type": "coreclr", 23 + "request": "attach" 24 + } 25 + ] 26 + }
+13
.vscode/settings.json
··· 1 + { 2 + "files.exclude": { 3 + "**/obj/": true, 4 + "**/bin/": true 5 + }, 6 + "cSpell.words": [ 7 + "Electropunk", 8 + "Lerp", 9 + "Raylib", 10 + "Raymath" 11 + ], 12 + "vscord.enabled": false 13 + }
+41
.vscode/tasks.json
··· 1 + { 2 + "version": "2.0.0", 3 + "tasks": [ 4 + { 5 + "label": "build", 6 + "command": "dotnet", 7 + "type": "process", 8 + "args": [ 9 + "build", 10 + "${workspaceFolder}/Electropunk/Electropunk.csproj", 11 + "/property:GenerateFullPaths=true", 12 + "/consoleloggerparameters:NoSummary;ForceNoAlign" 13 + ], 14 + "problemMatcher": "$msCompile" 15 + }, 16 + { 17 + "label": "publish", 18 + "command": "dotnet", 19 + "type": "process", 20 + "args": [ 21 + "publish", 22 + "${workspaceFolder}/Electropunk/Electropunk.csproj", 23 + "/property:GenerateFullPaths=true", 24 + "/consoleloggerparameters:NoSummary;ForceNoAlign" 25 + ], 26 + "problemMatcher": "$msCompile" 27 + }, 28 + { 29 + "label": "watch", 30 + "command": "dotnet", 31 + "type": "process", 32 + "args": [ 33 + "watch", 34 + "run", 35 + "--project", 36 + "${workspaceFolder}/Electropunk/Electropunk.csproj" 37 + ], 38 + "problemMatcher": "$msCompile" 39 + } 40 + ] 41 + }
Assets/Biomes/desert.png

This is a binary file and will not be displayed.

Assets/Biomes/forest.png

This is a binary file and will not be displayed.

Assets/Biomes/mountain.png

This is a binary file and will not be displayed.

Assets/Biomes/ocean.png

This is a binary file and will not be displayed.

Assets/Biomes/taiga.png

This is a binary file and will not be displayed.

Assets/Biomes/void.png

This is a binary file and will not be displayed.

Assets/Biomes/wastes.png

This is a binary file and will not be displayed.

Assets/Items/bow.png

This is a binary file and will not be displayed.

Assets/Items/copper.png

This is a binary file and will not be displayed.

Assets/Items/copper_gear.png

This is a binary file and will not be displayed.

Assets/Items/destructor.png

This is a binary file and will not be displayed.

Assets/Items/hammer.png

This is a binary file and will not be displayed.

Assets/Items/iron.png

This is a binary file and will not be displayed.

Assets/Items/iron_gear.png

This is a binary file and will not be displayed.

Assets/Items/mace.png

This is a binary file and will not be displayed.

Assets/Items/stone.png

This is a binary file and will not be displayed.

Assets/Items/sword.png

This is a binary file and will not be displayed.

Assets/Items/wand.png

This is a binary file and will not be displayed.

Assets/Items/wood.png

This is a binary file and will not be displayed.

+18
Assets/Lang/en_us.kdl
··· 1 + item { 2 + air "Air" 3 + destructor "Destructor" 4 + destructor.desc "Destroys tiles" 5 + hammer "Hammer" 6 + hammer.desc "Smashes tile and items" 7 + wood "Wood" 8 + wood_grains "Wood Pulp" 9 + stone "Pebble" 10 + iron "Iron" 11 + copper "Copper" 12 + iron_gear "Iron Gear" 13 + copper_gear "Copper Gear" 14 + } 15 + 16 + menu { 17 + inventory "Inventory" 18 + }
Assets/Tiles/rock.png

This is a binary file and will not be displayed.

Assets/Tiles/tree.png

This is a binary file and will not be displayed.

Assets/UI/cursor.png

This is a binary file and will not be displayed.

Assets/UI/jim.png

This is a binary file and will not be displayed.

Assets/UI/select.png

This is a binary file and will not be displayed.

+4
Data/Crafting/item_smashing.kdl
··· 1 + recipe { 2 + in "wood" 3 + out "wood_grains" 4 + }
+8
Data/Crafting/tile_smashing.kdl
··· 1 + recipe { 2 + in "rock" 3 + 4 + out-tile "air" 5 + 6 + out-item "stone" 7 + out-item "stone" 8 + }
+6
Electropunk/Containers/IInventory.cs
··· 1 + namespace Electropunk.Containers; 2 + 3 + public interface IInventory 4 + { 5 + public Slot? GetSlot(int i); 6 + }
+38
Electropunk/Containers/ItemInstance.cs
··· 1 + using System.Text.Json; 2 + using System.Text.Json.Serialization; 3 + using Electropunk.Content.Items; 4 + using Electropunk.World; 5 + 6 + namespace Electropunk.Containers; 7 + 8 + public class ItemInstance(ushort id, Dictionary<string, object>? data = null) 9 + { 10 + public ushort ItemID = id; 11 + public Dictionary<string, object> Data = data ?? []; 12 + 13 + [JsonIgnore] 14 + public Item Item 15 + { 16 + get => Item.Items[ItemID]; 17 + set => ItemID = value.ID; 18 + } 19 + 20 + public ItemInstance(Item item, Dictionary<string, object>? data = null) : this(item.ID, data) 21 + { 22 + } 23 + 24 + public bool Matches(ItemInstance other) => other.ItemID == ItemID; 25 + public bool Matches(Item other) => other.ID == ItemID; 26 + public bool Matches(ushort otherID) => otherID == ItemID; 27 + 28 + public bool IsEmpty() => Matches(GameItems.Air); 29 + public bool IsSomething() => !Matches(GameItems.Air); 30 + 31 + public ItemInstance Copy() => new(ItemID, new(Data)); 32 + public void Clear() => Item = GameItems.Air; 33 + 34 + public string Serialize() => JsonSerializer.Serialize(this); 35 + 36 + public static ItemInstance Deserialize(string json) => 37 + JsonSerializer.Deserialize<ItemInstance>(json)!; 38 + }
+55
Electropunk/Containers/Slot.cs
··· 1 + using Electropunk.Content.Items; 2 + using Electropunk.Misc; 3 + using Electropunk.World; 4 + 5 + namespace Electropunk.Containers; 6 + 7 + public class Slot(Func<ItemInstance> getter, Action<ItemInstance> setter) : Ref<ItemInstance>(getter, setter) 8 + { 9 + public Item Item 10 + { 11 + get => Value.Item; 12 + set => Value.Item = value; 13 + } 14 + 15 + public ushort ItemID 16 + { 17 + get => Value.ItemID; 18 + set => Value.ItemID = value; 19 + } 20 + 21 + public Dictionary<string, object> Data 22 + { 23 + get => Value.Data; 24 + set => Value.Data = value; 25 + } 26 + 27 + public bool Matches(ItemInstance other) => other.ItemID == ItemID; 28 + public bool Matches(Item other) => other.ID == ItemID; 29 + public bool Matches(ushort otherID) => otherID == ItemID; 30 + 31 + public bool IsEmpty() => Matches(GameItems.Air); 32 + public bool IsSomething() => !Matches(GameItems.Air); 33 + 34 + public ItemInstance Copy() => new(ItemID, new(Data)); 35 + public void Clear() => Item = GameItems.Air; 36 + 37 + public void SetItem(ushort itemID) 38 + { 39 + ItemID = itemID; 40 + Data.Clear(); 41 + } 42 + 43 + public void SetItem(Item item) 44 + { 45 + Item = item; 46 + Data.Clear(); 47 + } 48 + 49 + public void SetItem(ItemInstance item) 50 + { 51 + Item = item.Item; 52 + Data = item.Data; 53 + Data.Clear(); 54 + } 55 + }
+18
Electropunk/Content/Biomes/GameBiomes.cs
··· 1 + using Electropunk.World; 2 + 3 + namespace Electropunk.Content.Biomes; 4 + 5 + public static class GameBiomes 6 + { 7 + public static readonly Biome 8 + Void = new Biome("void").Register(), 9 + Forest = new Biome("forest").Register(), 10 + Desert = new Biome("desert").Register(), 11 + Mountain = new Biome("mountain").Register(), 12 + Taiga = new Biome("taiga").Register(), 13 + Ocean = new Biome("ocean").Register(), 14 + Wastes = new Biome("wastes").Register() 15 + ; 16 + 17 + public static void NoOp() { } 18 + }
+25
Electropunk/Content/Entities/EntityItem.cs
··· 1 + using Electropunk.Containers; 2 + using Electropunk.Content.Items; 3 + using Electropunk.World; 4 + 5 + namespace Electropunk.Content.Entities; 6 + 7 + public class EntityItem : Entity 8 + { 9 + public ItemInstance Item = new(GameItems.Air); 10 + 11 + public EntityItem() 12 + { 13 + MoveMode = MovementMode.None; 14 + Width = 16; 15 + Height = 16; 16 + } 17 + 18 + public override void Render(Level level, View view) 19 + { 20 + if (!Item.IsEmpty()) 21 + { 22 + Item.Item.Render(Program.Level!, Program.View, new(Pos.X, Pos.Y, Width, Height), new(Width / 2f, Height / 2f)); 23 + } 24 + } 25 + }
+191
Electropunk/Content/Entities/EntityPlayer.cs
··· 1 + using System.Numerics; 2 + using System.Text.Json; 3 + using Electropunk.Containers; 4 + using Electropunk.Content.Items; 5 + using Electropunk.Input; 6 + using Electropunk.World; 7 + using Raylib_cs; 8 + 9 + namespace Electropunk.Content.Entities; 10 + 11 + public class EntityPlayer : Entity 12 + { 13 + public PlayerInventory Inv = new(); 14 + 15 + private const int ItemBounceFrames = 16; 16 + private const float BounceDegreesPerFrame = 2f; 17 + private int itemBounceFrames = 0; 18 + 19 + public EntityPlayer() 20 + { 21 + Width = 8; 22 + Height = 8; 23 + Inv.Held = new(GameItems.Hammer); 24 + Inv.Slot1 = new(GameItems.Destructor); 25 + } 26 + 27 + public override void Update(Level level) 28 + { 29 + bool inMenu = Program.Menu != null; 30 + 31 + /* Jetpack */ 32 + if (Bindings.Fly.IsPressed()) 33 + MoveMode = MovementMode.Flying; 34 + else if (Bindings.Fly.IsReleased()) 35 + MoveMode = MovementMode.Default; 36 + 37 + if (!inMenu && Bindings.UseItem.IsPressed()) 38 + OnUse(level); 39 + else if (!inMenu && Bindings.DropItem.IsPressed() && !Inv.Held.IsEmpty()) 40 + { 41 + EntityItem ei = new() { Item = Inv.Held.Copy(), Pos = Pos }; 42 + Inv.Held.Clear(); 43 + level.EnqueueEntity(ei); 44 + } 45 + 46 + if (!inMenu && Bindings.SwapToItem1.IsPressed()) 47 + (Inv.Held, Inv.Slot1) = (Inv.Slot1, Inv.Held); 48 + else if (!inMenu && Bindings.SwapToItem2.IsPressed()) 49 + (Inv.Held, Inv.Slot2) = (Inv.Slot2, Inv.Held); 50 + 51 + /* Movement */ 52 + bool 53 + north = Bindings.MoveNorth.IsDown(), 54 + south = Bindings.MoveSouth.IsDown(), 55 + east = Bindings.MoveEast.IsDown(), 56 + west = Bindings.MoveWest.IsDown(); 57 + 58 + if (north && south) 59 + Vel.Y = 0; 60 + else if (north) 61 + Vel.Y = -1; 62 + else if (south) 63 + Vel.Y = 1; 64 + 65 + if (east && west) 66 + Vel.X = 0; 67 + else if (east) 68 + Vel.X = -1; 69 + else if (west) 70 + Vel.X = 1; 71 + 72 + /* Normalize */ 73 + if (Vel.X != 0 && Vel.Y != 0) 74 + { 75 + Vel.X /= 1.4f; 76 + Vel.Y /= 1.4f; 77 + } 78 + 79 + base.Update(level); 80 + } 81 + 82 + private bool OnUse(Level level) 83 + { 84 + if (Inv.Held.IsEmpty()) 85 + { 86 + /* Attempt to pick up an item */ 87 + Entity? e = level.GetSelectedEntity(Program.View); 88 + if (e != null && e is EntityItem ei) 89 + { 90 + Inv.Held = ei.Item.Copy(); 91 + ei.Item.Clear(); 92 + ei.Dead = true; 93 + return true; 94 + } 95 + 96 + /* Attempt to use a tile */ 97 + (int x, int y) = level.GetSelectedTile(Program.View) ?? (-1, -1); 98 + if (x != -1) 99 + { 100 + level.GetTileAt(x, y).Use(level, x, y, this); 101 + return true; 102 + } 103 + } 104 + else 105 + { 106 + /* Attempt to use the item on an entity */ 107 + Entity? e = level.GetSelectedEntity(Program.View); 108 + if (e != null) 109 + { 110 + Inv.Held.Item.UseOnEntity(level, this, new(() => Inv.Held, s => Inv.Held = s), e); 111 + itemBounceFrames = ItemBounceFrames; 112 + return true; 113 + } 114 + 115 + /* Attempt to use the item on a tile */ 116 + (int x, int y) = level.GetSelectedTile(Program.View) ?? (-1, -1); 117 + if (x != -1) 118 + { 119 + Inv.Held.Item.UseOnTile(level, this, new(() => Inv.Held, s => Inv.Held = s), x, y); 120 + itemBounceFrames = ItemBounceFrames; 121 + return true; 122 + } 123 + } 124 + return false; 125 + } 126 + 127 + public override void Render(Level level, View view) 128 + { 129 + Rectangle rect = GetRectangle(); 130 + 131 + if ( 132 + (level.Step == RenderStep.Entities && MoveMode == MovementMode.Default) || 133 + (level.Step == RenderStep.FlyingEntities && MoveMode == MovementMode.Flying) 134 + ) 135 + { 136 + Raylib.DrawRectangleRec(rect, Color.Blue); 137 + view.GoalTarget = Pos; 138 + } 139 + 140 + if (level.Step == RenderStep.FlyingEntities) 141 + { 142 + if (itemBounceFrames > 0) 143 + itemBounceFrames--; 144 + 145 + if (Inv.Held.IsSomething()) 146 + { 147 + float x = rect.X + rect.Width / 2; 148 + float y = rect.Y + rect.Height / 2; 149 + 150 + Vector2 mp = Raylib.GetScreenToWorld2D(Raylib.GetMousePosition(), view.Camera); 151 + float angle = (float)Math.Atan2((mp - Pos).Y, (mp - Pos).X) * Raylib.RAD2DEG; 152 + bool isOnLeft = (angle <= -90 && angle >= -180) || (angle <= 180 && angle >= 90); 153 + 154 + Vector2 p = Raymath.Vector2MoveTowards(new(x, y), mp, 12f); 155 + Rectangle dest = new(p.X, p.Y, 16, -16); 156 + 157 + if (isOnLeft) 158 + angle -= itemBounceFrames * BounceDegreesPerFrame; 159 + else 160 + angle += itemBounceFrames * BounceDegreesPerFrame; 161 + 162 + Inv.Held.Item.Render(level, view, dest, new(8, 8), angle, vFlip: isOnLeft); 163 + } 164 + } 165 + } 166 + 167 + public class PlayerInventory : IInventory 168 + { 169 + public ItemInstance Held = new(GameItems.Air); 170 + public ItemInstance Armour = new(GameItems.Air); 171 + public ItemInstance Slot1 = new(GameItems.Air); 172 + public ItemInstance Slot2 = new(GameItems.Air); 173 + 174 + public Slot? GetSlot(int i) 175 + { 176 + return i switch 177 + { 178 + 0 => new(() => Held, v => Held = v), 179 + 1 => new(() => Armour, v => Armour = v), 180 + 2 => new(() => Slot1, v => Slot1 = v), 181 + 3 => new(() => Slot2, v => Slot2 = v), 182 + _ => null 183 + }; 184 + } 185 + 186 + public string Serialize() => JsonSerializer.Serialize(this); 187 + 188 + public static PlayerInventory Deserialize(string json) => 189 + JsonSerializer.Deserialize<PlayerInventory>(json)!; 190 + } 191 + }
+66
Electropunk/Content/Generators/BasicLevelGenerator.cs
··· 1 + using Electropunk.Content.Biomes; 2 + using Electropunk.Content.Tiles; 3 + using Electropunk.World; 4 + 5 + namespace Electropunk.Content.Generators; 6 + 7 + public class BasicLevelGenerator : LevelGenerator 8 + { 9 + private readonly FastNoiseLite biomeNoise; 10 + 11 + public BasicLevelGenerator() 12 + { 13 + biomeNoise = new(); 14 + biomeNoise.SetSeed(new Random().Next()); 15 + biomeNoise.SetNoiseType(FastNoiseLite.NoiseType.Cellular); 16 + biomeNoise.SetFrequency(0.008f); 17 + biomeNoise.SetCellularDistanceFunction(FastNoiseLite.CellularDistanceFunction.Hybrid); 18 + biomeNoise.SetCellularReturnType(FastNoiseLite.CellularReturnType.CellValue); 19 + biomeNoise.SetCellularJitter(2.000f); 20 + biomeNoise.SetDomainWarpType(FastNoiseLite.DomainWarpType.OpenSimplex2); 21 + biomeNoise.SetDomainWarpAmp(200.000f); 22 + biomeNoise.SetFractalType(FastNoiseLite.FractalType.DomainWarpIndependent); 23 + biomeNoise.SetFractalOctaves(3); 24 + biomeNoise.SetFractalLacunarity(2.500f); 25 + biomeNoise.SetFractalGain(0.750f); 26 + } 27 + 28 + public override Biome PickBiome(Level level, int x, int y) 29 + { 30 + float fx = x, fy = y; 31 + biomeNoise.DomainWarp(ref fx, ref fy); 32 + float noise = biomeNoise.GetNoise(fx, fy); 33 + int biomes = 5; 34 + int normalized = (int)Math.Round((noise + 1.0f) / 2.0f * biomes); 35 + return normalized switch { 36 + 0 => GameBiomes.Forest, 37 + 1 => GameBiomes.Desert, 38 + 2 => GameBiomes.Mountain, 39 + 3 => GameBiomes.Taiga, 40 + 4 => GameBiomes.Ocean, 41 + 5 => GameBiomes.Wastes, 42 + _ => GameBiomes.Void, 43 + }; 44 + } 45 + 46 + public override Tile Pick(Level level, Biome biome, int x, int y) 47 + { 48 + float s = level.Random.NextSingle(); 49 + 50 + if (biome.ID != GameBiomes.Ocean.ID && s <= 1/30f) 51 + return GameTiles.Rock; 52 + 53 + if (biome.ID == GameBiomes.Forest.ID) 54 + { 55 + if (s <= 1/10f) 56 + return GameTiles.Tree; 57 + } 58 + else if (biome.ID == GameBiomes.Mountain.ID) 59 + { 60 + if (s <= 1/5f) 61 + return GameTiles.Rock; 62 + } 63 + 64 + return GameTiles.Air; 65 + } 66 + }
+21
Electropunk/Content/Items/GameItems.cs
··· 1 + using Electropunk.World; 2 + 3 + namespace Electropunk.Content.Items; 4 + 5 + public static class GameItems 6 + { 7 + public static readonly Item 8 + Air = new Item("air").Register(), 9 + Destructor = new ItemDestructor("destructor").Register(), 10 + Hammer = new ItemHammer("hammer").Register(), 11 + Wood = new Item("wood").Register(), 12 + WoodGrains = new Item("wood_grains").Register(), 13 + Stone = new Item("stone").Register(), 14 + Iron = new Item("iron").Register(), 15 + Copper = new Item("copper").Register(), 16 + IronGear = new Item("iron_gear").Register(), 17 + CopperGear = new Item("copper_gear").Register() 18 + ; 19 + 20 + public static void NoOp() { } 21 + }
+13
Electropunk/Content/Items/ItemDestructor.cs
··· 1 + using Electropunk.Containers; 2 + using Electropunk.Content.Entities; 3 + using Electropunk.World; 4 + 5 + namespace Electropunk.Content.Items; 6 + 7 + public class ItemDestructor(string key) : Item(key) 8 + { 9 + public override void UseOnTile(Level level, EntityPlayer user, Slot item, int x, int y) 10 + { 11 + level.GetTileAt(x, y).Break(level, x, y); 12 + } 13 + }
+20
Electropunk/Content/Items/ItemHammer.cs
··· 1 + using Electropunk.Containers; 2 + using Electropunk.Content.Entities; 3 + using Electropunk.World; 4 + using Electropunk.World.Crafting; 5 + 6 + namespace Electropunk.Content.Items; 7 + 8 + public class ItemHammer(string key) : Item(key) 9 + { 10 + public override void UseOnTile(Level level, EntityPlayer user, Slot item, int x, int y) 11 + { 12 + RecipeTileSmashing.TryCraft(level, x, y); 13 + } 14 + 15 + public override void UseOnEntity(Level level, EntityPlayer user, Slot item, Entity target) 16 + { 17 + if (target is EntityItem ei) 18 + RecipeItemSmashing.TryCraft(level, ei); 19 + } 20 + }
+16
Electropunk/Content/Tiles/GameTiles.cs
··· 1 + using Electropunk.Content.Items; 2 + using Electropunk.World; 3 + 4 + namespace Electropunk.Content.Tiles; 5 + 6 + public static class GameTiles 7 + { 8 + public static readonly Tile 9 + Air = new Tile("air") { RenderStep = RenderStep.None, Collides = false }.Register(), 10 + Rock = new Tile("rock") { Drops = [GameItems.Stone], RenderStep = RenderStep.TilesAbove, CollisionRect = new(0, 4, View.TileSize, View.TileSize - 4) }.Register(), 11 + Tree = new Tile("tree") { Drops = [GameItems.Wood], RenderStep = RenderStep.TilesAbove, CollisionRect = new(3, 4, View.TileSize - 6, View.TileSize - 4) }.Register(), 12 + Furnace = new Tile("furnace").Register() 13 + ; 14 + 15 + public static void NoOp() { } 16 + }
+35
Electropunk/Content/Tiles/TileFurnace.cs
··· 1 + using System.Text.Json; 2 + using Electropunk.Containers; 3 + using Electropunk.Content.Items; 4 + using Electropunk.World; 5 + 6 + namespace Electropunk.Content.Tiles; 7 + 8 + public class TileFurnace(string key) : Tile(key) 9 + { 10 + public override void Place(Level level, int x, int y) 11 + { 12 + base.Place(level, x, y); 13 + 14 + level.SetTileDataAt(x, y, new FurnaceData()); 15 + } 16 + 17 + protected class FurnaceData : TileData 18 + { 19 + public ItemInstance Input = new(GameItems.Air); 20 + public ItemInstance Output = new(GameItems.Air); 21 + public int TicksLeft = 0; 22 + public int FuelLeft = 0; 23 + 24 + public override void Load(string json) 25 + { 26 + FurnaceData data = JsonSerializer.Deserialize<FurnaceData>(json)!; 27 + Input = data.Input; 28 + Output = data.Output; 29 + TicksLeft = data.TicksLeft; 30 + FuelLeft = data.FuelLeft; 31 + } 32 + 33 + public override string Save() => JsonSerializer.Serialize(this); 34 + } 35 + }
+44
Electropunk/Content/UI/MenuInventory.cs
··· 1 + using Electropunk.Content.Entities; 2 + using Electropunk.Graphics; 3 + using Electropunk.I18n; 4 + using Electropunk.UI; 5 + using Raylib_cs; 6 + 7 + namespace Electropunk.Content.UI; 8 + 9 + public class MenuInventory : UINode 10 + { 11 + public static readonly int Scale = 4; 12 + 13 + private int openFrames = 0; 14 + 15 + public MenuInventory(EntityPlayer.PlayerInventory inventory) : base(0, 0) 16 + { 17 + int padding = 8; 18 + 19 + Width = (80 + padding * 2) * Scale; 20 + Height = (16 + padding * 2) * Scale; 21 + 22 + LocalX = Raylib.GetScreenWidth() / 2 - Width / 2; 23 + LocalY = Raylib.GetScreenHeight() / 2 - Height / 2; 24 + 25 + AddChild(new UIItemSlot(inventory.GetSlot(0)!, (padding + 0) * Scale, padding * Scale, this) { Width = 16 * Scale, Height = 16 * Scale }); 26 + AddChild(new UIItemSlot(inventory.GetSlot(1)!, (padding + 16) * Scale, padding * Scale, this) { Width = 16 * Scale, Height = 16 * Scale }); 27 + AddChild(new UIItemSlot(inventory.GetSlot(2)!, (padding + 48) * Scale, padding * Scale, this) { Width = 16 * Scale, Height = 16 * Scale }); 28 + AddChild(new UIItemSlot(inventory.GetSlot(3)!, (padding + 64) * Scale, padding * Scale, this) { Width = 16 * Scale, Height = 16 * Scale }); 29 + } 30 + 31 + public override void Render() 32 + { 33 + openFrames++; 34 + 35 + Raylib.DrawRectangle(0, 0, Raylib.GetScreenWidth(), Raylib.GetScreenHeight(), new(0, 0, 0, Math.Min(120, openFrames * 10))); 36 + 37 + Raylib.DrawText(Lang.T("menu.inventory"), LocalX, LocalY - 20, 20, Color.White); 38 + 39 + Raylib.DrawRectangleRec(GetRectangle(), Color.DarkBlue); 40 + Raylib.DrawRectangleLinesEx(GetRectangle(), 2f, Color.Blue); 41 + 42 + base.Render(); 43 + } 44 + }
+15
Electropunk/Electropunk.csproj
··· 1 + <Project Sdk="Microsoft.NET.Sdk"> 2 + 3 + <PropertyGroup> 4 + <OutputType>Exe</OutputType> 5 + <TargetFramework>net9.0</TargetFramework> 6 + <ImplicitUsings>enable</ImplicitUsings> 7 + <Nullable>enable</Nullable> 8 + </PropertyGroup> 9 + 10 + <ItemGroup> 11 + <PackageReference Include="Kadlet" Version="0.1.0" /> 12 + <PackageReference Include="Raylib-cs" Version="7.0.2" /> 13 + </ItemGroup> 14 + 15 + </Project>
+9
Electropunk/Graphics/Shaders.cs
··· 1 + using Raylib_cs; 2 + 3 + namespace Electropunk.Graphics; 4 + 5 + public static class Shaders 6 + { 7 + public static readonly Shader 8 + Blur = Raylib.LoadShader(null, "Assets/Shaders/blur.fs"); 9 + }
+11
Electropunk/Graphics/TextureUtil.cs
··· 1 + using Raylib_cs; 2 + 3 + namespace Electropunk.Graphics; 4 + 5 + public static class TextureUtil 6 + { 7 + public static Rectangle GetSourceRect(Texture2D texture) 8 + { 9 + return new(0, 0, texture.Width, texture.Height); 10 + } 11 + }
+60
Electropunk/I18n/Lang.cs
··· 1 + using System.Runtime.CompilerServices; 2 + using Kadlet; 3 + 4 + namespace Electropunk.I18n; 5 + 6 + public class Lang 7 + { 8 + public static Lang L = new("en_us"); 9 + 10 + private readonly Dictionary<string, string> Translations = []; 11 + 12 + public Lang(string key) 13 + { 14 + KdlReader reader = new(new KdlReaderOptions()); 15 + using FileStream fs = File.OpenRead($"Assets/Lang/{key}.kdl"); 16 + KdlDocument doc = reader.Parse(fs); 17 + Process(doc); 18 + } 19 + 20 + [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 + public string TranslateKey(string key) => Translations[key]; 22 + 23 + [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 + public bool HasKey(string key) => Translations.ContainsKey(key); 25 + 26 + private void Process(KdlDocument doc, string prefix = "") 27 + { 28 + foreach (var node in doc.Nodes) 29 + { 30 + foreach (var prop in node.Properties) 31 + Translations[$"{prefix}{node.Identifier}.{prop.Key}"] = prop.Value.ToKdlString().Trim('"', '\''); 32 + 33 + if (node.Arguments.Count == 1) 34 + Translations[$"{prefix}{node.Identifier}"] = node.Arguments[0].ToKdlString().Trim('"', '\''); 35 + if (node.Arguments.Count > 1) 36 + { 37 + foreach (var (i, arg) in node.Arguments.Index()) 38 + Translations[$"{prefix}{node.Identifier}.{i}"] = arg.ToKdlString().Trim('"', '\''); 39 + } 40 + 41 + if (node.Children != null) 42 + Process(node.Children, $"{prefix}{node.Identifier}."); 43 + } 44 + } 45 + 46 + [MethodImpl(MethodImplOptions.AggressiveInlining)] 47 + public static string Translate(string key) => L.Translations[key]; 48 + [MethodImpl(MethodImplOptions.AggressiveInlining)] 49 + public static string T(string key) => L.Translations[key]; 50 + 51 + [MethodImpl(MethodImplOptions.AggressiveInlining)] 52 + public static bool Exists(string key) => L.Translations.ContainsKey(key); 53 + [MethodImpl(MethodImplOptions.AggressiveInlining)] 54 + public static bool E(string key) => L.Translations.ContainsKey(key); 55 + 56 + [MethodImpl(MethodImplOptions.AggressiveInlining)] 57 + public static bool TranslateIfExists(string key, out string? value) => L.Translations.TryGetValue(key, out value); 58 + [MethodImpl(MethodImplOptions.AggressiveInlining)] 59 + public static bool TE(string key, out string? value) => L.Translations.TryGetValue(key, out value); 60 + }
+26
Electropunk/Input/Bindings.cs
··· 1 + using Raylib_cs; 2 + 3 + namespace Electropunk.Input; 4 + 5 + public static class Bindings 6 + { 7 + public static readonly InputBinding 8 + MoveNorth = new(KeyboardKey.W), 9 + MoveSouth = new(KeyboardKey.S), 10 + MoveEast = new(KeyboardKey.A), 11 + MoveWest = new(KeyboardKey.D), 12 + Fly = new(KeyboardKey.Space), 13 + DropItem = new(KeyboardKey.Q), 14 + UseItem = new(mouse: MouseButton.Left), 15 + OpenInventory = new(KeyboardKey.Tab), 16 + CloseMenu = new(KeyboardKey.Escape), 17 + SwapToItem1 = new(KeyboardKey.One), 18 + SwapToItem2 = new(KeyboardKey.Two), 19 + 20 + ToggleFullscreen = new(KeyboardKey.F11), 21 + ZoomIn = new(KeyboardKey.Equal), 22 + ZoomOut = new(KeyboardKey.Minus), 23 + ResetZoom = new(KeyboardKey.Zero), 24 + 25 + UIClick = new(mouse: MouseButton.Left); 26 + }
+30
Electropunk/Input/InputBinding.cs
··· 1 + using Raylib_cs; 2 + 3 + namespace Electropunk.Input; 4 + 5 + public class InputBinding(KeyboardKey? key = null, MouseButton? mouse = null, GamepadButton? gamepad = null) 6 + { 7 + public KeyboardKey? Key = key; 8 + public MouseButton? Mouse = mouse; 9 + public GamepadButton? Gamepad = gamepad; 10 + 11 + public bool IsDown() => 12 + (Key != null && Raylib.IsKeyDown((KeyboardKey)Key)) || 13 + (Mouse != null && Raylib.IsMouseButtonDown((MouseButton)Mouse)) || 14 + (Gamepad != null && Raylib.IsGamepadButtonDown(0, (GamepadButton)Gamepad)); 15 + 16 + public bool IsUp() => 17 + (Key != null && Raylib.IsKeyUp((KeyboardKey)Key)) || 18 + (Mouse != null && Raylib.IsMouseButtonUp((MouseButton)Mouse)) || 19 + (Gamepad != null && Raylib.IsGamepadButtonUp(0, (GamepadButton)Gamepad)); 20 + 21 + public bool IsPressed() => 22 + (Key != null && Raylib.IsKeyPressed((KeyboardKey)Key)) || 23 + (Mouse != null && Raylib.IsMouseButtonPressed((MouseButton)Mouse)) || 24 + (Gamepad != null && Raylib.IsGamepadButtonPressed(0, (GamepadButton)Gamepad)); 25 + 26 + public bool IsReleased() => 27 + (Key != null && Raylib.IsKeyReleased((KeyboardKey)Key)) || 28 + (Mouse != null && Raylib.IsMouseButtonReleased((MouseButton)Mouse)) || 29 + (Gamepad != null && Raylib.IsGamepadButtonReleased(0, (GamepadButton)Gamepad)); 30 + }
+2506
Electropunk/Mathematics/FastNoiseLite.cs
··· 1 + // MIT License 2 + // 3 + // Copyright(c) 2023 Jordan Peck (jordan.me2@gmail.com) 4 + // Copyright(c) 2023 Contributors 5 + // 6 + // Permission is hereby granted, free of charge, to any person obtaining a copy 7 + // of this software and associated documentation files(the "Software"), to deal 8 + // in the Software without restriction, including without limitation the rights 9 + // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 10 + // copies of the Software, and to permit persons to whom the Software is 11 + // furnished to do so, subject to the following conditions : 12 + // 13 + // The above copyright notice and this permission notice shall be included in all 14 + // copies or substantial portions of the Software. 15 + // 16 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 19 + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 + // SOFTWARE. 23 + // 24 + // .'',;:cldxkO00KKXXNNWWWNNXKOkxdollcc::::::;:::ccllloooolllllllllooollc:,'... ...........',;cldxkO000Okxdlc::;;;,,;;;::cclllllll 25 + // ..',;:ldxO0KXXNNNNNNNNXXK0kxdolcc::::::;;;,,,,,,;;;;;;;;;;:::cclllllc:;'.... ...........',;:ldxO0KXXXK0Okxdolc::;;;;::cllodddddo 26 + // ...',:loxO0KXNNNNNXXKK0Okxdolc::;::::::::;;;,,'''''.....''',;:clllllc:;,'............''''''''',;:loxO0KXNNNNNXK0Okxdollccccllodxxxxxxd 27 + // ....';:ldkO0KXXXKK00Okxdolcc:;;;;;::cclllcc:;;,''..... ....',;clooddolcc:;;;;,,;;;;;::::;;;;;;:cloxk0KXNWWWWWWNXKK0Okxddoooddxxkkkkkxx 28 + // .....';:ldxkOOOOOkxxdolcc:;;;,,,;;:cllooooolcc:;'... ..,:codxkkkxddooollloooooooollcc:::::clodkO0KXNWWWWWWNNXK00Okxxxxxxxxkkkkxxx 29 + // . ....';:cloddddo___________,,,,;;:clooddddoolc:,... ..,:ldx__00OOOkkk___kkkkkkxxdollc::::cclodkO0KXXNNNNNNXXK0OOkxxxxxxxxxxxxddd 30 + // .......',;:cccc:| |,,,;;:cclooddddoll:;'.. ..';cox| \KKK000| |KK00OOkxdocc___;::clldxxkO0KKKKK00Okkxdddddddddddddddoo 31 + // .......'',,,,,''| ________|',,;;::cclloooooolc:;'......___:ldk| \KK000| |XKKK0Okxolc| |;;::cclodxxkkkkxxdoolllcclllooodddooooo 32 + // ''......''''....| | ....'',,,,;;;::cclloooollc:;,''.'| |oxk| \OOO0| |KKK00Oxdoll|___|;;;;;::ccllllllcc::;;,,;;;:cclloooooooo 33 + // ;;,''.......... | |_____',,;;;____:___cllo________.___| |___| \xkk| |KK_______ool___:::;________;;;_______...'',;;:ccclllloo 34 + // c:;,''......... | |:::/ ' |lo/ | | \dx| |0/ \d| |cc/ |'/ \......',,;;:ccllo 35 + // ol:;,'..........| _____|ll/ __ |o/ ______|____ ___| | \o| |/ ___ \| |o/ ______|/ ___ \ .......'',;:clo 36 + // dlc;,...........| |::clooo| / | |x\___ \KXKKK0| |dol| |\ \| | | | | |d\___ \..| | / / ....',:cl 37 + // xoc;'... .....'| |llodddd| \__| |_____\ \KKK0O| |lc:| |'\ | |___| | |_____\ \.| |_/___/... ...',;:c 38 + // dlc;'... ....',;| |oddddddo\ | |Okkx| |::;| |..\ |\ /| | | \ |... ....',;:c 39 + // ol:,'.......',:c|___|xxxddollc\_____,___|_________/ddoll|___|,,,|___|...\_____|:\ ______/l|___|_________/...\________|'........',;::cc 40 + // c:;'.......';:codxxkkkkxxolc::;::clodxkOO0OOkkxdollc::;;,,''''',,,,''''''''''',,'''''',;:loxkkOOkxol:;,'''',,;:ccllcc:;,'''''',;::ccll 41 + // ;,'.......',:codxkOO0OOkxdlc:;,,;;:cldxxkkxxdolc:;;,,''.....'',;;:::;;,,,'''''........,;cldkO0KK0Okdoc::;;::cloodddoolc:;;;;;::ccllooo 42 + // .........',;:lodxOO0000Okdoc:,,',,;:clloddoolc:;,''.......'',;:clooollc:;;,,''.......',:ldkOKXNNXX0Oxdolllloddxxxxxxdolccccccllooodddd 43 + // . .....';:cldxkO0000Okxol:;,''',,;::cccc:;,,'.......'',;:cldxxkkxxdolc:;;,'.......';coxOKXNWWWNXKOkxddddxxkkkkkkxdoollllooddxxxxkkk 44 + // ....',;:codxkO000OOxdoc:;,''',,,;;;;,''.......',,;:clodkO00000Okxolc::;,,''..',;:ldxOKXNWWWNNK0OkkkkkkkkkkkxxddooooodxxkOOOOO000 45 + // ....',;;clodxkkOOOkkdolc:;,,,,,,,,'..........,;:clodxkO0KKXKK0Okxdolcc::;;,,,;;:codkO0XXNNNNXKK0OOOOOkkkkxxdoollloodxkO0KKKXXXXX 46 + // 47 + // VERSION: 1.1.1 48 + // https://github.com/Auburn/FastNoiseLite 49 + 50 + using System; 51 + using System.Runtime.CompilerServices; 52 + 53 + // Switch between using floats or doubles for input position 54 + using FNLfloat = System.Single; 55 + //using FNLfloat = System.Double; 56 + 57 + public class FastNoiseLite 58 + { 59 + private const short INLINE = 256; // MethodImplOptions.AggressiveInlining; 60 + private const short OPTIMISE = 512; // MethodImplOptions.AggressiveOptimization; 61 + 62 + public enum NoiseType 63 + { 64 + OpenSimplex2, 65 + OpenSimplex2S, 66 + Cellular, 67 + Perlin, 68 + ValueCubic, 69 + Value 70 + }; 71 + 72 + public enum RotationType3D 73 + { 74 + None, 75 + ImproveXYPlanes, 76 + ImproveXZPlanes 77 + }; 78 + 79 + public enum FractalType 80 + { 81 + None, 82 + FBm, 83 + Ridged, 84 + PingPong, 85 + DomainWarpProgressive, 86 + DomainWarpIndependent 87 + }; 88 + 89 + public enum CellularDistanceFunction 90 + { 91 + Euclidean, 92 + EuclideanSq, 93 + Manhattan, 94 + Hybrid 95 + }; 96 + 97 + public enum CellularReturnType 98 + { 99 + CellValue, 100 + Distance, 101 + Distance2, 102 + Distance2Add, 103 + Distance2Sub, 104 + Distance2Mul, 105 + Distance2Div 106 + }; 107 + 108 + public enum DomainWarpType 109 + { 110 + OpenSimplex2, 111 + OpenSimplex2Reduced, 112 + BasicGrid 113 + }; 114 + 115 + private enum TransformType3D 116 + { 117 + None, 118 + ImproveXYPlanes, 119 + ImproveXZPlanes, 120 + DefaultOpenSimplex2 121 + }; 122 + 123 + private int mSeed = 1337; 124 + private float mFrequency = 0.01f; 125 + private NoiseType mNoiseType = NoiseType.OpenSimplex2; 126 + private RotationType3D mRotationType3D = RotationType3D.None; 127 + private TransformType3D mTransformType3D = TransformType3D.DefaultOpenSimplex2; 128 + 129 + private FractalType mFractalType = FractalType.None; 130 + private int mOctaves = 3; 131 + private float mLacunarity = 2.0f; 132 + private float mGain = 0.5f; 133 + private float mWeightedStrength = 0.0f; 134 + private float mPingPongStrength = 2.0f; 135 + 136 + private float mFractalBounding = 1 / 1.75f; 137 + 138 + private CellularDistanceFunction mCellularDistanceFunction = CellularDistanceFunction.EuclideanSq; 139 + private CellularReturnType mCellularReturnType = CellularReturnType.Distance; 140 + private float mCellularJitterModifier = 1.0f; 141 + 142 + private DomainWarpType mDomainWarpType = DomainWarpType.OpenSimplex2; 143 + private TransformType3D mWarpTransformType3D = TransformType3D.DefaultOpenSimplex2; 144 + private float mDomainWarpAmp = 1.0f; 145 + 146 + /// <summary> 147 + /// Create new FastNoise object with optional seed 148 + /// </summary> 149 + public FastNoiseLite(int seed = 1337) 150 + { 151 + SetSeed(seed); 152 + } 153 + 154 + /// <summary> 155 + /// Sets seed used for all noise types 156 + /// </summary> 157 + /// <remarks> 158 + /// Default: 1337 159 + /// </remarks> 160 + public void SetSeed(int seed) { mSeed = seed; } 161 + 162 + /// <summary> 163 + /// Sets frequency for all noise types 164 + /// </summary> 165 + /// <remarks> 166 + /// Default: 0.01 167 + /// </remarks> 168 + public void SetFrequency(float frequency) { mFrequency = frequency; } 169 + 170 + /// <summary> 171 + /// Sets noise algorithm used for GetNoise(...) 172 + /// </summary> 173 + /// <remarks> 174 + /// Default: OpenSimplex2 175 + /// </remarks> 176 + public void SetNoiseType(NoiseType noiseType) 177 + { 178 + mNoiseType = noiseType; 179 + UpdateTransformType3D(); 180 + } 181 + 182 + /// <summary> 183 + /// Sets domain rotation type for 3D Noise and 3D DomainWarp. 184 + /// Can aid in reducing directional artifacts when sampling a 2D plane in 3D 185 + /// </summary> 186 + /// <remarks> 187 + /// Default: None 188 + /// </remarks> 189 + public void SetRotationType3D(RotationType3D rotationType3D) 190 + { 191 + mRotationType3D = rotationType3D; 192 + UpdateTransformType3D(); 193 + UpdateWarpTransformType3D(); 194 + } 195 + 196 + /// <summary> 197 + /// Sets method for combining octaves in all fractal noise types 198 + /// </summary> 199 + /// <remarks> 200 + /// Default: None 201 + /// Note: FractalType.DomainWarp... only affects DomainWarp(...) 202 + /// </remarks> 203 + public void SetFractalType(FractalType fractalType) { mFractalType = fractalType; } 204 + 205 + /// <summary> 206 + /// Sets octave count for all fractal noise types 207 + /// </summary> 208 + /// <remarks> 209 + /// Default: 3 210 + /// </remarks> 211 + public void SetFractalOctaves(int octaves) 212 + { 213 + mOctaves = octaves; 214 + CalculateFractalBounding(); 215 + } 216 + 217 + /// <summary> 218 + /// Sets octave lacunarity for all fractal noise types 219 + /// </summary> 220 + /// <remarks> 221 + /// Default: 2.0 222 + /// </remarks> 223 + public void SetFractalLacunarity(float lacunarity) { mLacunarity = lacunarity; } 224 + 225 + /// <summary> 226 + /// Sets octave gain for all fractal noise types 227 + /// </summary> 228 + /// <remarks> 229 + /// Default: 0.5 230 + /// </remarks> 231 + public void SetFractalGain(float gain) 232 + { 233 + mGain = gain; 234 + CalculateFractalBounding(); 235 + } 236 + 237 + /// <summary> 238 + /// Sets octave weighting for all none DomainWarp fratal types 239 + /// </summary> 240 + /// <remarks> 241 + /// Default: 0.0 242 + /// Note: Keep between 0...1 to maintain -1...1 output bounding 243 + /// </remarks> 244 + public void SetFractalWeightedStrength(float weightedStrength) { mWeightedStrength = weightedStrength; } 245 + 246 + /// <summary> 247 + /// Sets strength of the fractal ping pong effect 248 + /// </summary> 249 + /// <remarks> 250 + /// Default: 2.0 251 + /// </remarks> 252 + public void SetFractalPingPongStrength(float pingPongStrength) { mPingPongStrength = pingPongStrength; } 253 + 254 + 255 + /// <summary> 256 + /// Sets distance function used in cellular noise calculations 257 + /// </summary> 258 + /// <remarks> 259 + /// Default: Distance 260 + /// </remarks> 261 + public void SetCellularDistanceFunction(CellularDistanceFunction cellularDistanceFunction) { mCellularDistanceFunction = cellularDistanceFunction; } 262 + 263 + /// <summary> 264 + /// Sets return type from cellular noise calculations 265 + /// </summary> 266 + /// <remarks> 267 + /// Default: EuclideanSq 268 + /// </remarks> 269 + public void SetCellularReturnType(CellularReturnType cellularReturnType) { mCellularReturnType = cellularReturnType; } 270 + 271 + /// <summary> 272 + /// Sets the maximum distance a cellular point can move from it's grid position 273 + /// </summary> 274 + /// <remarks> 275 + /// Default: 1.0 276 + /// Note: Setting this higher than 1 will cause artifacts 277 + /// </remarks> 278 + public void SetCellularJitter(float cellularJitter) { mCellularJitterModifier = cellularJitter; } 279 + 280 + 281 + /// <summary> 282 + /// Sets the warp algorithm when using DomainWarp(...) 283 + /// </summary> 284 + /// <remarks> 285 + /// Default: OpenSimplex2 286 + /// </remarks> 287 + public void SetDomainWarpType(DomainWarpType domainWarpType) 288 + { 289 + mDomainWarpType = domainWarpType; 290 + UpdateWarpTransformType3D(); 291 + } 292 + 293 + 294 + /// <summary> 295 + /// Sets the maximum warp distance from original position when using DomainWarp(...) 296 + /// </summary> 297 + /// <remarks> 298 + /// Default: 1.0 299 + /// </remarks> 300 + public void SetDomainWarpAmp(float domainWarpAmp) { mDomainWarpAmp = domainWarpAmp; } 301 + 302 + 303 + /// <summary> 304 + /// 2D noise at given position using current settings 305 + /// </summary> 306 + /// <returns> 307 + /// Noise output bounded between -1...1 308 + /// </returns> 309 + [MethodImpl(OPTIMISE)] 310 + public float GetNoise(FNLfloat x, FNLfloat y) 311 + { 312 + TransformNoiseCoordinate(ref x, ref y); 313 + 314 + switch (mFractalType) 315 + { 316 + default: 317 + return GenNoiseSingle(mSeed, x, y); 318 + case FractalType.FBm: 319 + return GenFractalFBm(x, y); 320 + case FractalType.Ridged: 321 + return GenFractalRidged(x, y); 322 + case FractalType.PingPong: 323 + return GenFractalPingPong(x, y); 324 + } 325 + } 326 + 327 + /// <summary> 328 + /// 3D noise at given position using current settings 329 + /// </summary> 330 + /// <returns> 331 + /// Noise output bounded between -1...1 332 + /// </returns> 333 + [MethodImpl(OPTIMISE)] 334 + public float GetNoise(FNLfloat x, FNLfloat y, FNLfloat z) 335 + { 336 + TransformNoiseCoordinate(ref x, ref y, ref z); 337 + 338 + switch (mFractalType) 339 + { 340 + default: 341 + return GenNoiseSingle(mSeed, x, y, z); 342 + case FractalType.FBm: 343 + return GenFractalFBm(x, y, z); 344 + case FractalType.Ridged: 345 + return GenFractalRidged(x, y, z); 346 + case FractalType.PingPong: 347 + return GenFractalPingPong(x, y, z); 348 + } 349 + } 350 + 351 + 352 + /// <summary> 353 + /// 2D warps the input position using current domain warp settings 354 + /// </summary> 355 + /// <example> 356 + /// Example usage with GetNoise 357 + /// <code>DomainWarp(ref x, ref y) 358 + /// noise = GetNoise(x, y)</code> 359 + /// </example> 360 + [MethodImpl(OPTIMISE)] 361 + public void DomainWarp(ref FNLfloat x, ref FNLfloat y) 362 + { 363 + switch (mFractalType) 364 + { 365 + default: 366 + DomainWarpSingle(ref x, ref y); 367 + break; 368 + case FractalType.DomainWarpProgressive: 369 + DomainWarpFractalProgressive(ref x, ref y); 370 + break; 371 + case FractalType.DomainWarpIndependent: 372 + DomainWarpFractalIndependent(ref x, ref y); 373 + break; 374 + } 375 + } 376 + 377 + /// <summary> 378 + /// 3D warps the input position using current domain warp settings 379 + /// </summary> 380 + /// <example> 381 + /// Example usage with GetNoise 382 + /// <code>DomainWarp(ref x, ref y, ref z) 383 + /// noise = GetNoise(x, y, z)</code> 384 + /// </example> 385 + [MethodImpl(OPTIMISE)] 386 + public void DomainWarp(ref FNLfloat x, ref FNLfloat y, ref FNLfloat z) 387 + { 388 + switch (mFractalType) 389 + { 390 + default: 391 + DomainWarpSingle(ref x, ref y, ref z); 392 + break; 393 + case FractalType.DomainWarpProgressive: 394 + DomainWarpFractalProgressive(ref x, ref y, ref z); 395 + break; 396 + case FractalType.DomainWarpIndependent: 397 + DomainWarpFractalIndependent(ref x, ref y, ref z); 398 + break; 399 + } 400 + } 401 + 402 + 403 + private static readonly float[] Gradients2D = 404 + { 405 + 0.130526192220052f, 0.99144486137381f, 0.38268343236509f, 0.923879532511287f, 0.608761429008721f, 0.793353340291235f, 0.793353340291235f, 0.608761429008721f, 406 + 0.923879532511287f, 0.38268343236509f, 0.99144486137381f, 0.130526192220051f, 0.99144486137381f, -0.130526192220051f, 0.923879532511287f, -0.38268343236509f, 407 + 0.793353340291235f, -0.60876142900872f, 0.608761429008721f, -0.793353340291235f, 0.38268343236509f, -0.923879532511287f, 0.130526192220052f, -0.99144486137381f, 408 + -0.130526192220052f, -0.99144486137381f, -0.38268343236509f, -0.923879532511287f, -0.608761429008721f, -0.793353340291235f, -0.793353340291235f, -0.608761429008721f, 409 + -0.923879532511287f, -0.38268343236509f, -0.99144486137381f, -0.130526192220052f, -0.99144486137381f, 0.130526192220051f, -0.923879532511287f, 0.38268343236509f, 410 + -0.793353340291235f, 0.608761429008721f, -0.608761429008721f, 0.793353340291235f, -0.38268343236509f, 0.923879532511287f, -0.130526192220052f, 0.99144486137381f, 411 + 0.130526192220052f, 0.99144486137381f, 0.38268343236509f, 0.923879532511287f, 0.608761429008721f, 0.793353340291235f, 0.793353340291235f, 0.608761429008721f, 412 + 0.923879532511287f, 0.38268343236509f, 0.99144486137381f, 0.130526192220051f, 0.99144486137381f, -0.130526192220051f, 0.923879532511287f, -0.38268343236509f, 413 + 0.793353340291235f, -0.60876142900872f, 0.608761429008721f, -0.793353340291235f, 0.38268343236509f, -0.923879532511287f, 0.130526192220052f, -0.99144486137381f, 414 + -0.130526192220052f, -0.99144486137381f, -0.38268343236509f, -0.923879532511287f, -0.608761429008721f, -0.793353340291235f, -0.793353340291235f, -0.608761429008721f, 415 + -0.923879532511287f, -0.38268343236509f, -0.99144486137381f, -0.130526192220052f, -0.99144486137381f, 0.130526192220051f, -0.923879532511287f, 0.38268343236509f, 416 + -0.793353340291235f, 0.608761429008721f, -0.608761429008721f, 0.793353340291235f, -0.38268343236509f, 0.923879532511287f, -0.130526192220052f, 0.99144486137381f, 417 + 0.130526192220052f, 0.99144486137381f, 0.38268343236509f, 0.923879532511287f, 0.608761429008721f, 0.793353340291235f, 0.793353340291235f, 0.608761429008721f, 418 + 0.923879532511287f, 0.38268343236509f, 0.99144486137381f, 0.130526192220051f, 0.99144486137381f, -0.130526192220051f, 0.923879532511287f, -0.38268343236509f, 419 + 0.793353340291235f, -0.60876142900872f, 0.608761429008721f, -0.793353340291235f, 0.38268343236509f, -0.923879532511287f, 0.130526192220052f, -0.99144486137381f, 420 + -0.130526192220052f, -0.99144486137381f, -0.38268343236509f, -0.923879532511287f, -0.608761429008721f, -0.793353340291235f, -0.793353340291235f, -0.608761429008721f, 421 + -0.923879532511287f, -0.38268343236509f, -0.99144486137381f, -0.130526192220052f, -0.99144486137381f, 0.130526192220051f, -0.923879532511287f, 0.38268343236509f, 422 + -0.793353340291235f, 0.608761429008721f, -0.608761429008721f, 0.793353340291235f, -0.38268343236509f, 0.923879532511287f, -0.130526192220052f, 0.99144486137381f, 423 + 0.130526192220052f, 0.99144486137381f, 0.38268343236509f, 0.923879532511287f, 0.608761429008721f, 0.793353340291235f, 0.793353340291235f, 0.608761429008721f, 424 + 0.923879532511287f, 0.38268343236509f, 0.99144486137381f, 0.130526192220051f, 0.99144486137381f, -0.130526192220051f, 0.923879532511287f, -0.38268343236509f, 425 + 0.793353340291235f, -0.60876142900872f, 0.608761429008721f, -0.793353340291235f, 0.38268343236509f, -0.923879532511287f, 0.130526192220052f, -0.99144486137381f, 426 + -0.130526192220052f, -0.99144486137381f, -0.38268343236509f, -0.923879532511287f, -0.608761429008721f, -0.793353340291235f, -0.793353340291235f, -0.608761429008721f, 427 + -0.923879532511287f, -0.38268343236509f, -0.99144486137381f, -0.130526192220052f, -0.99144486137381f, 0.130526192220051f, -0.923879532511287f, 0.38268343236509f, 428 + -0.793353340291235f, 0.608761429008721f, -0.608761429008721f, 0.793353340291235f, -0.38268343236509f, 0.923879532511287f, -0.130526192220052f, 0.99144486137381f, 429 + 0.130526192220052f, 0.99144486137381f, 0.38268343236509f, 0.923879532511287f, 0.608761429008721f, 0.793353340291235f, 0.793353340291235f, 0.608761429008721f, 430 + 0.923879532511287f, 0.38268343236509f, 0.99144486137381f, 0.130526192220051f, 0.99144486137381f, -0.130526192220051f, 0.923879532511287f, -0.38268343236509f, 431 + 0.793353340291235f, -0.60876142900872f, 0.608761429008721f, -0.793353340291235f, 0.38268343236509f, -0.923879532511287f, 0.130526192220052f, -0.99144486137381f, 432 + -0.130526192220052f, -0.99144486137381f, -0.38268343236509f, -0.923879532511287f, -0.608761429008721f, -0.793353340291235f, -0.793353340291235f, -0.608761429008721f, 433 + -0.923879532511287f, -0.38268343236509f, -0.99144486137381f, -0.130526192220052f, -0.99144486137381f, 0.130526192220051f, -0.923879532511287f, 0.38268343236509f, 434 + -0.793353340291235f, 0.608761429008721f, -0.608761429008721f, 0.793353340291235f, -0.38268343236509f, 0.923879532511287f, -0.130526192220052f, 0.99144486137381f, 435 + 0.38268343236509f, 0.923879532511287f, 0.923879532511287f, 0.38268343236509f, 0.923879532511287f, -0.38268343236509f, 0.38268343236509f, -0.923879532511287f, 436 + -0.38268343236509f, -0.923879532511287f, -0.923879532511287f, -0.38268343236509f, -0.923879532511287f, 0.38268343236509f, -0.38268343236509f, 0.923879532511287f, 437 + }; 438 + 439 + private static readonly float[] RandVecs2D = 440 + { 441 + -0.2700222198f, -0.9628540911f, 0.3863092627f, -0.9223693152f, 0.04444859006f, -0.999011673f, -0.5992523158f, -0.8005602176f, -0.7819280288f, 0.6233687174f, 0.9464672271f, 0.3227999196f, -0.6514146797f, -0.7587218957f, 0.9378472289f, 0.347048376f, 442 + -0.8497875957f, -0.5271252623f, -0.879042592f, 0.4767432447f, -0.892300288f, -0.4514423508f, -0.379844434f, -0.9250503802f, -0.9951650832f, 0.0982163789f, 0.7724397808f, -0.6350880136f, 0.7573283322f, -0.6530343002f, -0.9928004525f, -0.119780055f, 443 + -0.0532665713f, 0.9985803285f, 0.9754253726f, -0.2203300762f, -0.7665018163f, 0.6422421394f, 0.991636706f, 0.1290606184f, -0.994696838f, 0.1028503788f, -0.5379205513f, -0.84299554f, 0.5022815471f, -0.8647041387f, 0.4559821461f, -0.8899889226f, 444 + -0.8659131224f, -0.5001944266f, 0.0879458407f, -0.9961252577f, -0.5051684983f, 0.8630207346f, 0.7753185226f, -0.6315704146f, -0.6921944612f, 0.7217110418f, -0.5191659449f, -0.8546734591f, 0.8978622882f, -0.4402764035f, -0.1706774107f, 0.9853269617f, 445 + -0.9353430106f, -0.3537420705f, -0.9992404798f, 0.03896746794f, -0.2882064021f, -0.9575683108f, -0.9663811329f, 0.2571137995f, -0.8759714238f, -0.4823630009f, -0.8303123018f, -0.5572983775f, 0.05110133755f, -0.9986934731f, -0.8558373281f, -0.5172450752f, 446 + 0.09887025282f, 0.9951003332f, 0.9189016087f, 0.3944867976f, -0.2439375892f, -0.9697909324f, -0.8121409387f, -0.5834613061f, -0.9910431363f, 0.1335421355f, 0.8492423985f, -0.5280031709f, -0.9717838994f, -0.2358729591f, 0.9949457207f, 0.1004142068f, 447 + 0.6241065508f, -0.7813392434f, 0.662910307f, 0.7486988212f, -0.7197418176f, 0.6942418282f, -0.8143370775f, -0.5803922158f, 0.104521054f, -0.9945226741f, -0.1065926113f, -0.9943027784f, 0.445799684f, -0.8951327509f, 0.105547406f, 0.9944142724f, 448 + -0.992790267f, 0.1198644477f, -0.8334366408f, 0.552615025f, 0.9115561563f, -0.4111755999f, 0.8285544909f, -0.5599084351f, 0.7217097654f, -0.6921957921f, 0.4940492677f, -0.8694339084f, -0.3652321272f, -0.9309164803f, -0.9696606758f, 0.2444548501f, 449 + 0.08925509731f, -0.996008799f, 0.5354071276f, -0.8445941083f, -0.1053576186f, 0.9944343981f, -0.9890284586f, 0.1477251101f, 0.004856104961f, 0.9999882091f, 0.9885598478f, 0.1508291331f, 0.9286129562f, -0.3710498316f, -0.5832393863f, -0.8123003252f, 450 + 0.3015207509f, 0.9534596146f, -0.9575110528f, 0.2883965738f, 0.9715802154f, -0.2367105511f, 0.229981792f, 0.9731949318f, 0.955763816f, -0.2941352207f, 0.740956116f, 0.6715534485f, -0.9971513787f, -0.07542630764f, 0.6905710663f, -0.7232645452f, 451 + -0.290713703f, -0.9568100872f, 0.5912777791f, -0.8064679708f, -0.9454592212f, -0.325740481f, 0.6664455681f, 0.74555369f, 0.6236134912f, 0.7817328275f, 0.9126993851f, -0.4086316587f, -0.8191762011f, 0.5735419353f, -0.8812745759f, -0.4726046147f, 452 + 0.9953313627f, 0.09651672651f, 0.9855650846f, -0.1692969699f, -0.8495980887f, 0.5274306472f, 0.6174853946f, -0.7865823463f, 0.8508156371f, 0.52546432f, 0.9985032451f, -0.05469249926f, 0.1971371563f, -0.9803759185f, 0.6607855748f, -0.7505747292f, 453 + -0.03097494063f, 0.9995201614f, -0.6731660801f, 0.739491331f, -0.7195018362f, -0.6944905383f, 0.9727511689f, 0.2318515979f, 0.9997059088f, -0.0242506907f, 0.4421787429f, -0.8969269532f, 0.9981350961f, -0.061043673f, -0.9173660799f, -0.3980445648f, 454 + -0.8150056635f, -0.5794529907f, -0.8789331304f, 0.4769450202f, 0.0158605829f, 0.999874213f, -0.8095464474f, 0.5870558317f, -0.9165898907f, -0.3998286786f, -0.8023542565f, 0.5968480938f, -0.5176737917f, 0.8555780767f, -0.8154407307f, -0.5788405779f, 455 + 0.4022010347f, -0.9155513791f, -0.9052556868f, -0.4248672045f, 0.7317445619f, 0.6815789728f, -0.5647632201f, -0.8252529947f, -0.8403276335f, -0.5420788397f, -0.9314281527f, 0.363925262f, 0.5238198472f, 0.8518290719f, 0.7432803869f, -0.6689800195f, 456 + -0.985371561f, -0.1704197369f, 0.4601468731f, 0.88784281f, 0.825855404f, 0.5638819483f, 0.6182366099f, 0.7859920446f, 0.8331502863f, -0.553046653f, 0.1500307506f, 0.9886813308f, -0.662330369f, -0.7492119075f, -0.668598664f, 0.743623444f, 457 + 0.7025606278f, 0.7116238924f, -0.5419389763f, -0.8404178401f, -0.3388616456f, 0.9408362159f, 0.8331530315f, 0.5530425174f, -0.2989720662f, -0.9542618632f, 0.2638522993f, 0.9645630949f, 0.124108739f, -0.9922686234f, -0.7282649308f, -0.6852956957f, 458 + 0.6962500149f, 0.7177993569f, -0.9183535368f, 0.3957610156f, -0.6326102274f, -0.7744703352f, -0.9331891859f, -0.359385508f, -0.1153779357f, -0.9933216659f, 0.9514974788f, -0.3076565421f, -0.08987977445f, -0.9959526224f, 0.6678496916f, 0.7442961705f, 459 + 0.7952400393f, -0.6062947138f, -0.6462007402f, -0.7631674805f, -0.2733598753f, 0.9619118351f, 0.9669590226f, -0.254931851f, -0.9792894595f, 0.2024651934f, -0.5369502995f, -0.8436138784f, -0.270036471f, -0.9628500944f, -0.6400277131f, 0.7683518247f, 460 + -0.7854537493f, -0.6189203566f, 0.06005905383f, -0.9981948257f, -0.02455770378f, 0.9996984141f, -0.65983623f, 0.751409442f, -0.6253894466f, -0.7803127835f, -0.6210408851f, -0.7837781695f, 0.8348888491f, 0.5504185768f, -0.1592275245f, 0.9872419133f, 461 + 0.8367622488f, 0.5475663786f, -0.8675753916f, -0.4973056806f, -0.2022662628f, -0.9793305667f, 0.9399189937f, 0.3413975472f, 0.9877404807f, -0.1561049093f, -0.9034455656f, 0.4287028224f, 0.1269804218f, -0.9919052235f, -0.3819600854f, 0.924178821f, 462 + 0.9754625894f, 0.2201652486f, -0.3204015856f, -0.9472818081f, -0.9874760884f, 0.1577687387f, 0.02535348474f, -0.9996785487f, 0.4835130794f, -0.8753371362f, -0.2850799925f, -0.9585037287f, -0.06805516006f, -0.99768156f, -0.7885244045f, -0.6150034663f, 463 + 0.3185392127f, -0.9479096845f, 0.8880043089f, 0.4598351306f, 0.6476921488f, -0.7619021462f, 0.9820241299f, 0.1887554194f, 0.9357275128f, -0.3527237187f, -0.8894895414f, 0.4569555293f, 0.7922791302f, 0.6101588153f, 0.7483818261f, 0.6632681526f, 464 + -0.7288929755f, -0.6846276581f, 0.8729032783f, -0.4878932944f, 0.8288345784f, 0.5594937369f, 0.08074567077f, 0.9967347374f, 0.9799148216f, -0.1994165048f, -0.580730673f, -0.8140957471f, -0.4700049791f, -0.8826637636f, 0.2409492979f, 0.9705377045f, 465 + 0.9437816757f, -0.3305694308f, -0.8927998638f, -0.4504535528f, -0.8069622304f, 0.5906030467f, 0.06258973166f, 0.9980393407f, -0.9312597469f, 0.3643559849f, 0.5777449785f, 0.8162173362f, -0.3360095855f, -0.941858566f, 0.697932075f, -0.7161639607f, 466 + -0.002008157227f, -0.9999979837f, -0.1827294312f, -0.9831632392f, -0.6523911722f, 0.7578824173f, -0.4302626911f, -0.9027037258f, -0.9985126289f, -0.05452091251f, -0.01028102172f, -0.9999471489f, -0.4946071129f, 0.8691166802f, -0.2999350194f, 0.9539596344f, 467 + 0.8165471961f, 0.5772786819f, 0.2697460475f, 0.962931498f, -0.7306287391f, -0.6827749597f, -0.7590952064f, -0.6509796216f, -0.907053853f, 0.4210146171f, -0.5104861064f, -0.8598860013f, 0.8613350597f, 0.5080373165f, 0.5007881595f, -0.8655698812f, 468 + -0.654158152f, 0.7563577938f, -0.8382755311f, -0.545246856f, 0.6940070834f, 0.7199681717f, 0.06950936031f, 0.9975812994f, 0.1702942185f, -0.9853932612f, 0.2695973274f, 0.9629731466f, 0.5519612192f, -0.8338697815f, 0.225657487f, -0.9742067022f, 469 + 0.4215262855f, -0.9068161835f, 0.4881873305f, -0.8727388672f, -0.3683854996f, -0.9296731273f, -0.9825390578f, 0.1860564427f, 0.81256471f, 0.5828709909f, 0.3196460933f, -0.9475370046f, 0.9570913859f, 0.2897862643f, -0.6876655497f, -0.7260276109f, 470 + -0.9988770922f, -0.047376731f, -0.1250179027f, 0.992154486f, -0.8280133617f, 0.560708367f, 0.9324863769f, -0.3612051451f, 0.6394653183f, 0.7688199442f, -0.01623847064f, -0.9998681473f, -0.9955014666f, -0.09474613458f, -0.81453315f, 0.580117012f, 471 + 0.4037327978f, -0.9148769469f, 0.9944263371f, 0.1054336766f, -0.1624711654f, 0.9867132919f, -0.9949487814f, -0.100383875f, -0.6995302564f, 0.7146029809f, 0.5263414922f, -0.85027327f, -0.5395221479f, 0.841971408f, 0.6579370318f, 0.7530729462f, 472 + 0.01426758847f, -0.9998982128f, -0.6734383991f, 0.7392433447f, 0.639412098f, -0.7688642071f, 0.9211571421f, 0.3891908523f, -0.146637214f, -0.9891903394f, -0.782318098f, 0.6228791163f, -0.5039610839f, -0.8637263605f, -0.7743120191f, -0.6328039957f, 473 + }; 474 + 475 + private static readonly float[] Gradients3D = 476 + { 477 + 0, 1, 1, 0, 0,-1, 1, 0, 0, 1,-1, 0, 0,-1,-1, 0, 478 + 1, 0, 1, 0, -1, 0, 1, 0, 1, 0,-1, 0, -1, 0,-1, 0, 479 + 1, 1, 0, 0, -1, 1, 0, 0, 1,-1, 0, 0, -1,-1, 0, 0, 480 + 0, 1, 1, 0, 0,-1, 1, 0, 0, 1,-1, 0, 0,-1,-1, 0, 481 + 1, 0, 1, 0, -1, 0, 1, 0, 1, 0,-1, 0, -1, 0,-1, 0, 482 + 1, 1, 0, 0, -1, 1, 0, 0, 1,-1, 0, 0, -1,-1, 0, 0, 483 + 0, 1, 1, 0, 0,-1, 1, 0, 0, 1,-1, 0, 0,-1,-1, 0, 484 + 1, 0, 1, 0, -1, 0, 1, 0, 1, 0,-1, 0, -1, 0,-1, 0, 485 + 1, 1, 0, 0, -1, 1, 0, 0, 1,-1, 0, 0, -1,-1, 0, 0, 486 + 0, 1, 1, 0, 0,-1, 1, 0, 0, 1,-1, 0, 0,-1,-1, 0, 487 + 1, 0, 1, 0, -1, 0, 1, 0, 1, 0,-1, 0, -1, 0,-1, 0, 488 + 1, 1, 0, 0, -1, 1, 0, 0, 1,-1, 0, 0, -1,-1, 0, 0, 489 + 0, 1, 1, 0, 0,-1, 1, 0, 0, 1,-1, 0, 0,-1,-1, 0, 490 + 1, 0, 1, 0, -1, 0, 1, 0, 1, 0,-1, 0, -1, 0,-1, 0, 491 + 1, 1, 0, 0, -1, 1, 0, 0, 1,-1, 0, 0, -1,-1, 0, 0, 492 + 1, 1, 0, 0, 0,-1, 1, 0, -1, 1, 0, 0, 0,-1,-1, 0 493 + }; 494 + 495 + private static readonly float[] RandVecs3D = 496 + { 497 + -0.7292736885f, -0.6618439697f, 0.1735581948f, 0, 0.790292081f, -0.5480887466f, -0.2739291014f, 0, 0.7217578935f, 0.6226212466f, -0.3023380997f, 0, 0.565683137f, -0.8208298145f, -0.0790000257f, 0, 0.760049034f, -0.5555979497f, -0.3370999617f, 0, 0.3713945616f, 0.5011264475f, 0.7816254623f, 0, -0.1277062463f, -0.4254438999f, -0.8959289049f, 0, -0.2881560924f, -0.5815838982f, 0.7607405838f, 0, 498 + 0.5849561111f, -0.662820239f, -0.4674352136f, 0, 0.3307171178f, 0.0391653737f, 0.94291689f, 0, 0.8712121778f, -0.4113374369f, -0.2679381538f, 0, 0.580981015f, 0.7021915846f, 0.4115677815f, 0, 0.503756873f, 0.6330056931f, -0.5878203852f, 0, 0.4493712205f, 0.601390195f, 0.6606022552f, 0, -0.6878403724f, 0.09018890807f, -0.7202371714f, 0, -0.5958956522f, -0.6469350577f, 0.475797649f, 0, 499 + -0.5127052122f, 0.1946921978f, -0.8361987284f, 0, -0.9911507142f, -0.05410276466f, -0.1212153153f, 0, -0.2149721042f, 0.9720882117f, -0.09397607749f, 0, -0.7518650936f, -0.5428057603f, 0.3742469607f, 0, 0.5237068895f, 0.8516377189f, -0.02107817834f, 0, 0.6333504779f, 0.1926167129f, -0.7495104896f, 0, -0.06788241606f, 0.3998305789f, 0.9140719259f, 0, -0.5538628599f, -0.4729896695f, -0.6852128902f, 0, 500 + -0.7261455366f, -0.5911990757f, 0.3509933228f, 0, -0.9229274737f, -0.1782808786f, 0.3412049336f, 0, -0.6968815002f, 0.6511274338f, 0.3006480328f, 0, 0.9608044783f, -0.2098363234f, -0.1811724921f, 0, 0.06817146062f, -0.9743405129f, 0.2145069156f, 0, -0.3577285196f, -0.6697087264f, -0.6507845481f, 0, -0.1868621131f, 0.7648617052f, -0.6164974636f, 0, -0.6541697588f, 0.3967914832f, 0.6439087246f, 0, 501 + 0.6993340405f, -0.6164538506f, 0.3618239211f, 0, -0.1546665739f, 0.6291283928f, 0.7617583057f, 0, -0.6841612949f, -0.2580482182f, -0.6821542638f, 0, 0.5383980957f, 0.4258654885f, 0.7271630328f, 0, -0.5026987823f, -0.7939832935f, -0.3418836993f, 0, 0.3202971715f, 0.2834415347f, 0.9039195862f, 0, 0.8683227101f, -0.0003762656404f, -0.4959995258f, 0, 0.791120031f, -0.08511045745f, 0.6057105799f, 0, 502 + -0.04011016052f, -0.4397248749f, 0.8972364289f, 0, 0.9145119872f, 0.3579346169f, -0.1885487608f, 0, -0.9612039066f, -0.2756484276f, 0.01024666929f, 0, 0.6510361721f, -0.2877799159f, -0.7023778346f, 0, -0.2041786351f, 0.7365237271f, 0.644859585f, 0, -0.7718263711f, 0.3790626912f, 0.5104855816f, 0, -0.3060082741f, -0.7692987727f, 0.5608371729f, 0, 0.454007341f, -0.5024843065f, 0.7357899537f, 0, 503 + 0.4816795475f, 0.6021208291f, -0.6367380315f, 0, 0.6961980369f, -0.3222197429f, 0.641469197f, 0, -0.6532160499f, -0.6781148932f, 0.3368515753f, 0, 0.5089301236f, -0.6154662304f, -0.6018234363f, 0, -0.1635919754f, -0.9133604627f, -0.372840892f, 0, 0.52408019f, -0.8437664109f, 0.1157505864f, 0, 0.5902587356f, 0.4983817807f, -0.6349883666f, 0, 0.5863227872f, 0.494764745f, 0.6414307729f, 0, 504 + 0.6779335087f, 0.2341345225f, 0.6968408593f, 0, 0.7177054546f, -0.6858979348f, 0.120178631f, 0, -0.5328819713f, -0.5205125012f, 0.6671608058f, 0, -0.8654874251f, -0.0700727088f, -0.4960053754f, 0, -0.2861810166f, 0.7952089234f, 0.5345495242f, 0, -0.04849529634f, 0.9810836427f, -0.1874115585f, 0, -0.6358521667f, 0.6058348682f, 0.4781800233f, 0, 0.6254794696f, -0.2861619734f, 0.7258696564f, 0, 505 + -0.2585259868f, 0.5061949264f, -0.8227581726f, 0, 0.02136306781f, 0.5064016808f, -0.8620330371f, 0, 0.200111773f, 0.8599263484f, 0.4695550591f, 0, 0.4743561372f, 0.6014985084f, -0.6427953014f, 0, 0.6622993731f, -0.5202474575f, -0.5391679918f, 0, 0.08084972818f, -0.6532720452f, 0.7527940996f, 0, -0.6893687501f, 0.0592860349f, 0.7219805347f, 0, -0.1121887082f, -0.9673185067f, 0.2273952515f, 0, 506 + 0.7344116094f, 0.5979668656f, -0.3210532909f, 0, 0.5789393465f, -0.2488849713f, 0.7764570201f, 0, 0.6988182827f, 0.3557169806f, -0.6205791146f, 0, -0.8636845529f, -0.2748771249f, -0.4224826141f, 0, -0.4247027957f, -0.4640880967f, 0.777335046f, 0, 0.5257722489f, -0.8427017621f, 0.1158329937f, 0, 0.9343830603f, 0.316302472f, -0.1639543925f, 0, -0.1016836419f, -0.8057303073f, -0.5834887393f, 0, 507 + -0.6529238969f, 0.50602126f, -0.5635892736f, 0, -0.2465286165f, -0.9668205684f, -0.06694497494f, 0, -0.9776897119f, -0.2099250524f, -0.007368825344f, 0, 0.7736893337f, 0.5734244712f, 0.2694238123f, 0, -0.6095087895f, 0.4995678998f, 0.6155736747f, 0, 0.5794535482f, 0.7434546771f, 0.3339292269f, 0, -0.8226211154f, 0.08142581855f, 0.5627293636f, 0, -0.510385483f, 0.4703667658f, 0.7199039967f, 0, 508 + -0.5764971849f, -0.07231656274f, -0.8138926898f, 0, 0.7250628871f, 0.3949971505f, -0.5641463116f, 0, -0.1525424005f, 0.4860840828f, -0.8604958341f, 0, -0.5550976208f, -0.4957820792f, 0.667882296f, 0, -0.1883614327f, 0.9145869398f, 0.357841725f, 0, 0.7625556724f, -0.5414408243f, -0.3540489801f, 0, -0.5870231946f, -0.3226498013f, -0.7424963803f, 0, 0.3051124198f, 0.2262544068f, -0.9250488391f, 0, 509 + 0.6379576059f, 0.577242424f, -0.5097070502f, 0, -0.5966775796f, 0.1454852398f, -0.7891830656f, 0, -0.658330573f, 0.6555487542f, -0.3699414651f, 0, 0.7434892426f, 0.2351084581f, 0.6260573129f, 0, 0.5562114096f, 0.8264360377f, -0.0873632843f, 0, -0.3028940016f, -0.8251527185f, 0.4768419182f, 0, 0.1129343818f, -0.985888439f, -0.1235710781f, 0, 0.5937652891f, -0.5896813806f, 0.5474656618f, 0, 510 + 0.6757964092f, -0.5835758614f, -0.4502648413f, 0, 0.7242302609f, -0.1152719764f, 0.6798550586f, 0, -0.9511914166f, 0.0753623979f, -0.2992580792f, 0, 0.2539470961f, -0.1886339355f, 0.9486454084f, 0, 0.571433621f, -0.1679450851f, -0.8032795685f, 0, -0.06778234979f, 0.3978269256f, 0.9149531629f, 0, 0.6074972649f, 0.733060024f, -0.3058922593f, 0, -0.5435478392f, 0.1675822484f, 0.8224791405f, 0, 511 + -0.5876678086f, -0.3380045064f, -0.7351186982f, 0, -0.7967562402f, 0.04097822706f, -0.6029098428f, 0, -0.1996350917f, 0.8706294745f, 0.4496111079f, 0, -0.02787660336f, -0.9106232682f, -0.4122962022f, 0, -0.7797625996f, -0.6257634692f, 0.01975775581f, 0, -0.5211232846f, 0.7401644346f, -0.4249554471f, 0, 0.8575424857f, 0.4053272873f, -0.3167501783f, 0, 0.1045223322f, 0.8390195772f, -0.5339674439f, 0, 512 + 0.3501822831f, 0.9242524096f, -0.1520850155f, 0, 0.1987849858f, 0.07647613266f, 0.9770547224f, 0, 0.7845996363f, 0.6066256811f, -0.1280964233f, 0, 0.09006737436f, -0.9750989929f, -0.2026569073f, 0, -0.8274343547f, -0.542299559f, 0.1458203587f, 0, -0.3485797732f, -0.415802277f, 0.840000362f, 0, -0.2471778936f, -0.7304819962f, -0.6366310879f, 0, -0.3700154943f, 0.8577948156f, 0.3567584454f, 0, 513 + 0.5913394901f, -0.548311967f, -0.5913303597f, 0, 0.1204873514f, -0.7626472379f, -0.6354935001f, 0, 0.616959265f, 0.03079647928f, 0.7863922953f, 0, 0.1258156836f, -0.6640829889f, -0.7369967419f, 0, -0.6477565124f, -0.1740147258f, -0.7417077429f, 0, 0.6217889313f, -0.7804430448f, -0.06547655076f, 0, 0.6589943422f, -0.6096987708f, 0.4404473475f, 0, -0.2689837504f, -0.6732403169f, -0.6887635427f, 0, 514 + -0.3849775103f, 0.5676542638f, 0.7277093879f, 0, 0.5754444408f, 0.8110471154f, -0.1051963504f, 0, 0.9141593684f, 0.3832947817f, 0.131900567f, 0, -0.107925319f, 0.9245493968f, 0.3654593525f, 0, 0.377977089f, 0.3043148782f, 0.8743716458f, 0, -0.2142885215f, -0.8259286236f, 0.5214617324f, 0, 0.5802544474f, 0.4148098596f, -0.7008834116f, 0, -0.1982660881f, 0.8567161266f, -0.4761596756f, 0, 515 + -0.03381553704f, 0.3773180787f, -0.9254661404f, 0, -0.6867922841f, -0.6656597827f, 0.2919133642f, 0, 0.7731742607f, -0.2875793547f, -0.5652430251f, 0, -0.09655941928f, 0.9193708367f, -0.3813575004f, 0, 0.2715702457f, -0.9577909544f, -0.09426605581f, 0, 0.2451015704f, -0.6917998565f, -0.6792188003f, 0, 0.977700782f, -0.1753855374f, 0.1155036542f, 0, -0.5224739938f, 0.8521606816f, 0.02903615945f, 0, 516 + -0.7734880599f, -0.5261292347f, 0.3534179531f, 0, -0.7134492443f, -0.269547243f, 0.6467878011f, 0, 0.1644037271f, 0.5105846203f, -0.8439637196f, 0, 0.6494635788f, 0.05585611296f, 0.7583384168f, 0, -0.4711970882f, 0.5017280509f, -0.7254255765f, 0, -0.6335764307f, -0.2381686273f, -0.7361091029f, 0, -0.9021533097f, -0.270947803f, -0.3357181763f, 0, -0.3793711033f, 0.872258117f, 0.3086152025f, 0, 517 + -0.6855598966f, -0.3250143309f, 0.6514394162f, 0, 0.2900942212f, -0.7799057743f, -0.5546100667f, 0, -0.2098319339f, 0.85037073f, 0.4825351604f, 0, -0.4592603758f, 0.6598504336f, -0.5947077538f, 0, 0.8715945488f, 0.09616365406f, -0.4807031248f, 0, -0.6776666319f, 0.7118504878f, -0.1844907016f, 0, 0.7044377633f, 0.312427597f, 0.637304036f, 0, -0.7052318886f, -0.2401093292f, -0.6670798253f, 0, 518 + 0.081921007f, -0.7207336136f, -0.6883545647f, 0, -0.6993680906f, -0.5875763221f, -0.4069869034f, 0, -0.1281454481f, 0.6419895885f, 0.7559286424f, 0, -0.6337388239f, -0.6785471501f, -0.3714146849f, 0, 0.5565051903f, -0.2168887573f, -0.8020356851f, 0, -0.5791554484f, 0.7244372011f, -0.3738578718f, 0, 0.1175779076f, -0.7096451073f, 0.6946792478f, 0, -0.6134619607f, 0.1323631078f, 0.7785527795f, 0, 519 + 0.6984635305f, -0.02980516237f, -0.715024719f, 0, 0.8318082963f, -0.3930171956f, 0.3919597455f, 0, 0.1469576422f, 0.05541651717f, -0.9875892167f, 0, 0.708868575f, -0.2690503865f, 0.6520101478f, 0, 0.2726053183f, 0.67369766f, -0.68688995f, 0, -0.6591295371f, 0.3035458599f, -0.6880466294f, 0, 0.4815131379f, -0.7528270071f, 0.4487723203f, 0, 0.9430009463f, 0.1675647412f, -0.2875261255f, 0, 520 + 0.434802957f, 0.7695304522f, -0.4677277752f, 0, 0.3931996188f, 0.594473625f, 0.7014236729f, 0, 0.7254336655f, -0.603925654f, 0.3301814672f, 0, 0.7590235227f, -0.6506083235f, 0.02433313207f, 0, -0.8552768592f, -0.3430042733f, 0.3883935666f, 0, -0.6139746835f, 0.6981725247f, 0.3682257648f, 0, -0.7465905486f, -0.5752009504f, 0.3342849376f, 0, 0.5730065677f, 0.810555537f, -0.1210916791f, 0, 521 + -0.9225877367f, -0.3475211012f, -0.167514036f, 0, -0.7105816789f, -0.4719692027f, -0.5218416899f, 0, -0.08564609717f, 0.3583001386f, 0.929669703f, 0, -0.8279697606f, -0.2043157126f, 0.5222271202f, 0, 0.427944023f, 0.278165994f, 0.8599346446f, 0, 0.5399079671f, -0.7857120652f, -0.3019204161f, 0, 0.5678404253f, -0.5495413974f, -0.6128307303f, 0, -0.9896071041f, 0.1365639107f, -0.04503418428f, 0, 522 + -0.6154342638f, -0.6440875597f, 0.4543037336f, 0, 0.1074204368f, -0.7946340692f, 0.5975094525f, 0, -0.3595449969f, -0.8885529948f, 0.28495784f, 0, -0.2180405296f, 0.1529888965f, 0.9638738118f, 0, -0.7277432317f, -0.6164050508f, -0.3007234646f, 0, 0.7249729114f, -0.00669719484f, 0.6887448187f, 0, -0.5553659455f, -0.5336586252f, 0.6377908264f, 0, 0.5137558015f, 0.7976208196f, -0.3160000073f, 0, 523 + -0.3794024848f, 0.9245608561f, -0.03522751494f, 0, 0.8229248658f, 0.2745365933f, -0.4974176556f, 0, -0.5404114394f, 0.6091141441f, 0.5804613989f, 0, 0.8036581901f, -0.2703029469f, 0.5301601931f, 0, 0.6044318879f, 0.6832968393f, 0.4095943388f, 0, 0.06389988817f, 0.9658208605f, -0.2512108074f, 0, 0.1087113286f, 0.7402471173f, -0.6634877936f, 0, -0.713427712f, -0.6926784018f, 0.1059128479f, 0, 524 + 0.6458897819f, -0.5724548511f, -0.5050958653f, 0, -0.6553931414f, 0.7381471625f, 0.159995615f, 0, 0.3910961323f, 0.9188871375f, -0.05186755998f, 0, -0.4879022471f, -0.5904376907f, 0.6429111375f, 0, 0.6014790094f, 0.7707441366f, -0.2101820095f, 0, -0.5677173047f, 0.7511360995f, 0.3368851762f, 0, 0.7858573506f, 0.226674665f, 0.5753666838f, 0, -0.4520345543f, -0.604222686f, -0.6561857263f, 0, 525 + 0.002272116345f, 0.4132844051f, -0.9105991643f, 0, -0.5815751419f, -0.5162925989f, 0.6286591339f, 0, -0.03703704785f, 0.8273785755f, 0.5604221175f, 0, -0.5119692504f, 0.7953543429f, -0.3244980058f, 0, -0.2682417366f, -0.9572290247f, -0.1084387619f, 0, -0.2322482736f, -0.9679131102f, -0.09594243324f, 0, 0.3554328906f, -0.8881505545f, 0.2913006227f, 0, 0.7346520519f, -0.4371373164f, 0.5188422971f, 0, 526 + 0.9985120116f, 0.04659011161f, -0.02833944577f, 0, -0.3727687496f, -0.9082481361f, 0.1900757285f, 0, 0.91737377f, -0.3483642108f, 0.1925298489f, 0, 0.2714911074f, 0.4147529736f, -0.8684886582f, 0, 0.5131763485f, -0.7116334161f, 0.4798207128f, 0, -0.8737353606f, 0.18886992f, -0.4482350644f, 0, 0.8460043821f, -0.3725217914f, 0.3814499973f, 0, 0.8978727456f, -0.1780209141f, -0.4026575304f, 0, 527 + 0.2178065647f, -0.9698322841f, -0.1094789531f, 0, -0.1518031304f, -0.7788918132f, -0.6085091231f, 0, -0.2600384876f, -0.4755398075f, -0.8403819825f, 0, 0.572313509f, -0.7474340931f, -0.3373418503f, 0, -0.7174141009f, 0.1699017182f, -0.6756111411f, 0, -0.684180784f, 0.02145707593f, -0.7289967412f, 0, -0.2007447902f, 0.06555605789f, -0.9774476623f, 0, -0.1148803697f, -0.8044887315f, 0.5827524187f, 0, 528 + -0.7870349638f, 0.03447489231f, 0.6159443543f, 0, -0.2015596421f, 0.6859872284f, 0.6991389226f, 0, -0.08581082512f, -0.10920836f, -0.9903080513f, 0, 0.5532693395f, 0.7325250401f, -0.396610771f, 0, -0.1842489331f, -0.9777375055f, -0.1004076743f, 0, 0.0775473789f, -0.9111505856f, 0.4047110257f, 0, 0.1399838409f, 0.7601631212f, -0.6344734459f, 0, 0.4484419361f, -0.845289248f, 0.2904925424f, 0 529 + }; 530 + 531 + 532 + [MethodImpl(INLINE)] 533 + private static float FastMin(float a, float b) { return a < b ? a : b; } 534 + 535 + [MethodImpl(INLINE)] 536 + private static float FastMax(float a, float b) { return a > b ? a : b; } 537 + 538 + [MethodImpl(INLINE)] 539 + private static float FastAbs(float f) { return f < 0 ? -f : f; } 540 + 541 + [MethodImpl(INLINE)] 542 + private static float FastSqrt(float f) { return (float)Math.Sqrt(f); } 543 + 544 + [MethodImpl(INLINE)] 545 + private static int FastFloor(FNLfloat f) { return f >= 0 ? (int)f : (int)f - 1; } 546 + 547 + [MethodImpl(INLINE)] 548 + private static int FastRound(FNLfloat f) { return f >= 0 ? (int)(f + 0.5f) : (int)(f - 0.5f); } 549 + 550 + [MethodImpl(INLINE)] 551 + private static float Lerp(float a, float b, float t) { return a + t * (b - a); } 552 + 553 + [MethodImpl(INLINE)] 554 + private static float InterpHermite(float t) { return t * t * (3 - 2 * t); } 555 + 556 + [MethodImpl(INLINE)] 557 + private static float InterpQuintic(float t) { return t * t * t * (t * (t * 6 - 15) + 10); } 558 + 559 + [MethodImpl(INLINE)] 560 + private static float CubicLerp(float a, float b, float c, float d, float t) 561 + { 562 + float p = (d - c) - (a - b); 563 + return t * t * t * p + t * t * ((a - b) - p) + t * (c - a) + b; 564 + } 565 + 566 + [MethodImpl(INLINE)] 567 + private static float PingPong(float t) 568 + { 569 + t -= (int)(t * 0.5f) * 2; 570 + return t < 1 ? t : 2 - t; 571 + } 572 + 573 + private void CalculateFractalBounding() 574 + { 575 + float gain = FastAbs(mGain); 576 + float amp = gain; 577 + float ampFractal = 1.0f; 578 + for (int i = 1; i < mOctaves; i++) 579 + { 580 + ampFractal += amp; 581 + amp *= gain; 582 + } 583 + mFractalBounding = 1 / ampFractal; 584 + } 585 + 586 + // Hashing 587 + private const int PrimeX = 501125321; 588 + private const int PrimeY = 1136930381; 589 + private const int PrimeZ = 1720413743; 590 + 591 + [MethodImpl(INLINE)] 592 + private static int Hash(int seed, int xPrimed, int yPrimed) 593 + { 594 + int hash = seed ^ xPrimed ^ yPrimed; 595 + 596 + hash *= 0x27d4eb2d; 597 + return hash; 598 + } 599 + 600 + [MethodImpl(INLINE)] 601 + private static int Hash(int seed, int xPrimed, int yPrimed, int zPrimed) 602 + { 603 + int hash = seed ^ xPrimed ^ yPrimed ^ zPrimed; 604 + 605 + hash *= 0x27d4eb2d; 606 + return hash; 607 + } 608 + 609 + [MethodImpl(INLINE)] 610 + private static float ValCoord(int seed, int xPrimed, int yPrimed) 611 + { 612 + int hash = Hash(seed, xPrimed, yPrimed); 613 + 614 + hash *= hash; 615 + hash ^= hash << 19; 616 + return hash * (1 / 2147483648.0f); 617 + } 618 + 619 + [MethodImpl(INLINE)] 620 + private static float ValCoord(int seed, int xPrimed, int yPrimed, int zPrimed) 621 + { 622 + int hash = Hash(seed, xPrimed, yPrimed, zPrimed); 623 + 624 + hash *= hash; 625 + hash ^= hash << 19; 626 + return hash * (1 / 2147483648.0f); 627 + } 628 + 629 + [MethodImpl(INLINE)] 630 + private static float GradCoord(int seed, int xPrimed, int yPrimed, float xd, float yd) 631 + { 632 + int hash = Hash(seed, xPrimed, yPrimed); 633 + hash ^= hash >> 15; 634 + hash &= 127 << 1; 635 + 636 + float xg = Gradients2D[hash]; 637 + float yg = Gradients2D[hash | 1]; 638 + 639 + return xd * xg + yd * yg; 640 + } 641 + 642 + [MethodImpl(INLINE)] 643 + private static float GradCoord(int seed, int xPrimed, int yPrimed, int zPrimed, float xd, float yd, float zd) 644 + { 645 + int hash = Hash(seed, xPrimed, yPrimed, zPrimed); 646 + hash ^= hash >> 15; 647 + hash &= 63 << 2; 648 + 649 + float xg = Gradients3D[hash]; 650 + float yg = Gradients3D[hash | 1]; 651 + float zg = Gradients3D[hash | 2]; 652 + 653 + return xd * xg + yd * yg + zd * zg; 654 + } 655 + 656 + [MethodImpl(INLINE)] 657 + private static void GradCoordOut(int seed, int xPrimed, int yPrimed, out float xo, out float yo) 658 + { 659 + int hash = Hash(seed, xPrimed, yPrimed) & (255 << 1); 660 + 661 + xo = RandVecs2D[hash]; 662 + yo = RandVecs2D[hash | 1]; 663 + } 664 + 665 + [MethodImpl(INLINE)] 666 + private static void GradCoordOut(int seed, int xPrimed, int yPrimed, int zPrimed, out float xo, out float yo, out float zo) 667 + { 668 + int hash = Hash(seed, xPrimed, yPrimed, zPrimed) & (255 << 2); 669 + 670 + xo = RandVecs3D[hash]; 671 + yo = RandVecs3D[hash | 1]; 672 + zo = RandVecs3D[hash | 2]; 673 + } 674 + 675 + [MethodImpl(INLINE)] 676 + private static void GradCoordDual(int seed, int xPrimed, int yPrimed, float xd, float yd, out float xo, out float yo) 677 + { 678 + int hash = Hash(seed, xPrimed, yPrimed); 679 + int index1 = hash & (127 << 1); 680 + int index2 = (hash >> 7) & (255 << 1); 681 + 682 + float xg = Gradients2D[index1]; 683 + float yg = Gradients2D[index1 | 1]; 684 + float value = xd * xg + yd * yg; 685 + 686 + float xgo = RandVecs2D[index2]; 687 + float ygo = RandVecs2D[index2 | 1]; 688 + 689 + xo = value * xgo; 690 + yo = value * ygo; 691 + } 692 + 693 + [MethodImpl(INLINE)] 694 + private static void GradCoordDual(int seed, int xPrimed, int yPrimed, int zPrimed, float xd, float yd, float zd, out float xo, out float yo, out float zo) 695 + { 696 + int hash = Hash(seed, xPrimed, yPrimed, zPrimed); 697 + int index1 = hash & (63 << 2); 698 + int index2 = (hash >> 6) & (255 << 2); 699 + 700 + float xg = Gradients3D[index1]; 701 + float yg = Gradients3D[index1 | 1]; 702 + float zg = Gradients3D[index1 | 2]; 703 + float value = xd * xg + yd * yg + zd * zg; 704 + 705 + float xgo = RandVecs3D[index2]; 706 + float ygo = RandVecs3D[index2 | 1]; 707 + float zgo = RandVecs3D[index2 | 2]; 708 + 709 + xo = value * xgo; 710 + yo = value * ygo; 711 + zo = value * zgo; 712 + } 713 + 714 + 715 + // Generic noise gen 716 + 717 + private float GenNoiseSingle(int seed, FNLfloat x, FNLfloat y) 718 + { 719 + switch (mNoiseType) 720 + { 721 + case NoiseType.OpenSimplex2: 722 + return SingleSimplex(seed, x, y); 723 + case NoiseType.OpenSimplex2S: 724 + return SingleOpenSimplex2S(seed, x, y); 725 + case NoiseType.Cellular: 726 + return SingleCellular(seed, x, y); 727 + case NoiseType.Perlin: 728 + return SinglePerlin(seed, x, y); 729 + case NoiseType.ValueCubic: 730 + return SingleValueCubic(seed, x, y); 731 + case NoiseType.Value: 732 + return SingleValue(seed, x, y); 733 + default: 734 + return 0; 735 + } 736 + } 737 + 738 + private float GenNoiseSingle(int seed, FNLfloat x, FNLfloat y, FNLfloat z) 739 + { 740 + switch (mNoiseType) 741 + { 742 + case NoiseType.OpenSimplex2: 743 + return SingleOpenSimplex2(seed, x, y, z); 744 + case NoiseType.OpenSimplex2S: 745 + return SingleOpenSimplex2S(seed, x, y, z); 746 + case NoiseType.Cellular: 747 + return SingleCellular(seed, x, y, z); 748 + case NoiseType.Perlin: 749 + return SinglePerlin(seed, x, y, z); 750 + case NoiseType.ValueCubic: 751 + return SingleValueCubic(seed, x, y, z); 752 + case NoiseType.Value: 753 + return SingleValue(seed, x, y, z); 754 + default: 755 + return 0; 756 + } 757 + } 758 + 759 + 760 + // Noise Coordinate Transforms (frequency, and possible skew or rotation) 761 + 762 + [MethodImpl(INLINE)] 763 + private void TransformNoiseCoordinate(ref FNLfloat x, ref FNLfloat y) 764 + { 765 + x *= mFrequency; 766 + y *= mFrequency; 767 + 768 + switch (mNoiseType) 769 + { 770 + case NoiseType.OpenSimplex2: 771 + case NoiseType.OpenSimplex2S: 772 + { 773 + const FNLfloat SQRT3 = (FNLfloat)1.7320508075688772935274463415059; 774 + const FNLfloat F2 = 0.5f * (SQRT3 - 1); 775 + FNLfloat t = (x + y) * F2; 776 + x += t; 777 + y += t; 778 + } 779 + break; 780 + default: 781 + break; 782 + } 783 + } 784 + 785 + [MethodImpl(INLINE)] 786 + private void TransformNoiseCoordinate(ref FNLfloat x, ref FNLfloat y, ref FNLfloat z) 787 + { 788 + x *= mFrequency; 789 + y *= mFrequency; 790 + z *= mFrequency; 791 + 792 + switch (mTransformType3D) 793 + { 794 + case TransformType3D.ImproveXYPlanes: 795 + { 796 + FNLfloat xy = x + y; 797 + FNLfloat s2 = xy * -(FNLfloat)0.211324865405187; 798 + z *= (FNLfloat)0.577350269189626; 799 + x += s2 - z; 800 + y = y + s2 - z; 801 + z += xy * (FNLfloat)0.577350269189626; 802 + } 803 + break; 804 + case TransformType3D.ImproveXZPlanes: 805 + { 806 + FNLfloat xz = x + z; 807 + FNLfloat s2 = xz * -(FNLfloat)0.211324865405187; 808 + y *= (FNLfloat)0.577350269189626; 809 + x += s2 - y; 810 + z += s2 - y; 811 + y += xz * (FNLfloat)0.577350269189626; 812 + } 813 + break; 814 + case TransformType3D.DefaultOpenSimplex2: 815 + { 816 + const FNLfloat R3 = (FNLfloat)(2.0 / 3.0); 817 + FNLfloat r = (x + y + z) * R3; // Rotation, not skew 818 + x = r - x; 819 + y = r - y; 820 + z = r - z; 821 + } 822 + break; 823 + default: 824 + break; 825 + } 826 + } 827 + 828 + private void UpdateTransformType3D() 829 + { 830 + switch (mRotationType3D) 831 + { 832 + case RotationType3D.ImproveXYPlanes: 833 + mTransformType3D = TransformType3D.ImproveXYPlanes; 834 + break; 835 + case RotationType3D.ImproveXZPlanes: 836 + mTransformType3D = TransformType3D.ImproveXZPlanes; 837 + break; 838 + default: 839 + switch (mNoiseType) 840 + { 841 + case NoiseType.OpenSimplex2: 842 + case NoiseType.OpenSimplex2S: 843 + mTransformType3D = TransformType3D.DefaultOpenSimplex2; 844 + break; 845 + default: 846 + mTransformType3D = TransformType3D.None; 847 + break; 848 + } 849 + break; 850 + } 851 + } 852 + 853 + 854 + // Domain Warp Coordinate Transforms 855 + 856 + [MethodImpl(INLINE)] 857 + private void TransformDomainWarpCoordinate(ref FNLfloat x, ref FNLfloat y) 858 + { 859 + switch (mDomainWarpType) 860 + { 861 + case DomainWarpType.OpenSimplex2: 862 + case DomainWarpType.OpenSimplex2Reduced: 863 + { 864 + const FNLfloat SQRT3 = (FNLfloat)1.7320508075688772935274463415059; 865 + const FNLfloat F2 = 0.5f * (SQRT3 - 1); 866 + FNLfloat t = (x + y) * F2; 867 + x += t; y += t; 868 + } 869 + break; 870 + default: 871 + break; 872 + } 873 + } 874 + 875 + [MethodImpl(INLINE)] 876 + private void TransformDomainWarpCoordinate(ref FNLfloat x, ref FNLfloat y, ref FNLfloat z) 877 + { 878 + switch (mWarpTransformType3D) 879 + { 880 + case TransformType3D.ImproveXYPlanes: 881 + { 882 + FNLfloat xy = x + y; 883 + FNLfloat s2 = xy * -(FNLfloat)0.211324865405187; 884 + z *= (FNLfloat)0.577350269189626; 885 + x += s2 - z; 886 + y = y + s2 - z; 887 + z += xy * (FNLfloat)0.577350269189626; 888 + } 889 + break; 890 + case TransformType3D.ImproveXZPlanes: 891 + { 892 + FNLfloat xz = x + z; 893 + FNLfloat s2 = xz * -(FNLfloat)0.211324865405187; 894 + y *= (FNLfloat)0.577350269189626; 895 + x += s2 - y; z += s2 - y; 896 + y += xz * (FNLfloat)0.577350269189626; 897 + } 898 + break; 899 + case TransformType3D.DefaultOpenSimplex2: 900 + { 901 + const FNLfloat R3 = (FNLfloat)(2.0 / 3.0); 902 + FNLfloat r = (x + y + z) * R3; // Rotation, not skew 903 + x = r - x; 904 + y = r - y; 905 + z = r - z; 906 + } 907 + break; 908 + default: 909 + break; 910 + } 911 + } 912 + 913 + private void UpdateWarpTransformType3D() 914 + { 915 + switch (mRotationType3D) 916 + { 917 + case RotationType3D.ImproveXYPlanes: 918 + mWarpTransformType3D = TransformType3D.ImproveXYPlanes; 919 + break; 920 + case RotationType3D.ImproveXZPlanes: 921 + mWarpTransformType3D = TransformType3D.ImproveXZPlanes; 922 + break; 923 + default: 924 + switch (mDomainWarpType) 925 + { 926 + case DomainWarpType.OpenSimplex2: 927 + case DomainWarpType.OpenSimplex2Reduced: 928 + mWarpTransformType3D = TransformType3D.DefaultOpenSimplex2; 929 + break; 930 + default: 931 + mWarpTransformType3D = TransformType3D.None; 932 + break; 933 + } 934 + break; 935 + } 936 + } 937 + 938 + 939 + // Fractal FBm 940 + 941 + private float GenFractalFBm(FNLfloat x, FNLfloat y) 942 + { 943 + int seed = mSeed; 944 + float sum = 0; 945 + float amp = mFractalBounding; 946 + 947 + for (int i = 0; i < mOctaves; i++) 948 + { 949 + float noise = GenNoiseSingle(seed++, x, y); 950 + sum += noise * amp; 951 + amp *= Lerp(1.0f, FastMin(noise + 1, 2) * 0.5f, mWeightedStrength); 952 + 953 + x *= mLacunarity; 954 + y *= mLacunarity; 955 + amp *= mGain; 956 + } 957 + 958 + return sum; 959 + } 960 + 961 + private float GenFractalFBm(FNLfloat x, FNLfloat y, FNLfloat z) 962 + { 963 + int seed = mSeed; 964 + float sum = 0; 965 + float amp = mFractalBounding; 966 + 967 + for (int i = 0; i < mOctaves; i++) 968 + { 969 + float noise = GenNoiseSingle(seed++, x, y, z); 970 + sum += noise * amp; 971 + amp *= Lerp(1.0f, (noise + 1) * 0.5f, mWeightedStrength); 972 + 973 + x *= mLacunarity; 974 + y *= mLacunarity; 975 + z *= mLacunarity; 976 + amp *= mGain; 977 + } 978 + 979 + return sum; 980 + } 981 + 982 + 983 + // Fractal Ridged 984 + 985 + private float GenFractalRidged(FNLfloat x, FNLfloat y) 986 + { 987 + int seed = mSeed; 988 + float sum = 0; 989 + float amp = mFractalBounding; 990 + 991 + for (int i = 0; i < mOctaves; i++) 992 + { 993 + float noise = FastAbs(GenNoiseSingle(seed++, x, y)); 994 + sum += (noise * -2 + 1) * amp; 995 + amp *= Lerp(1.0f, 1 - noise, mWeightedStrength); 996 + 997 + x *= mLacunarity; 998 + y *= mLacunarity; 999 + amp *= mGain; 1000 + } 1001 + 1002 + return sum; 1003 + } 1004 + 1005 + private float GenFractalRidged(FNLfloat x, FNLfloat y, FNLfloat z) 1006 + { 1007 + int seed = mSeed; 1008 + float sum = 0; 1009 + float amp = mFractalBounding; 1010 + 1011 + for (int i = 0; i < mOctaves; i++) 1012 + { 1013 + float noise = FastAbs(GenNoiseSingle(seed++, x, y, z)); 1014 + sum += (noise * -2 + 1) * amp; 1015 + amp *= Lerp(1.0f, 1 - noise, mWeightedStrength); 1016 + 1017 + x *= mLacunarity; 1018 + y *= mLacunarity; 1019 + z *= mLacunarity; 1020 + amp *= mGain; 1021 + } 1022 + 1023 + return sum; 1024 + } 1025 + 1026 + 1027 + // Fractal PingPong 1028 + 1029 + private float GenFractalPingPong(FNLfloat x, FNLfloat y) 1030 + { 1031 + int seed = mSeed; 1032 + float sum = 0; 1033 + float amp = mFractalBounding; 1034 + 1035 + for (int i = 0; i < mOctaves; i++) 1036 + { 1037 + float noise = PingPong((GenNoiseSingle(seed++, x, y) + 1) * mPingPongStrength); 1038 + sum += (noise - 0.5f) * 2 * amp; 1039 + amp *= Lerp(1.0f, noise, mWeightedStrength); 1040 + 1041 + x *= mLacunarity; 1042 + y *= mLacunarity; 1043 + amp *= mGain; 1044 + } 1045 + 1046 + return sum; 1047 + } 1048 + 1049 + private float GenFractalPingPong(FNLfloat x, FNLfloat y, FNLfloat z) 1050 + { 1051 + int seed = mSeed; 1052 + float sum = 0; 1053 + float amp = mFractalBounding; 1054 + 1055 + for (int i = 0; i < mOctaves; i++) 1056 + { 1057 + float noise = PingPong((GenNoiseSingle(seed++, x, y, z) + 1) * mPingPongStrength); 1058 + sum += (noise - 0.5f) * 2 * amp; 1059 + amp *= Lerp(1.0f, noise, mWeightedStrength); 1060 + 1061 + x *= mLacunarity; 1062 + y *= mLacunarity; 1063 + z *= mLacunarity; 1064 + amp *= mGain; 1065 + } 1066 + 1067 + return sum; 1068 + } 1069 + 1070 + 1071 + // Simplex/OpenSimplex2 Noise 1072 + 1073 + private float SingleSimplex(int seed, FNLfloat x, FNLfloat y) 1074 + { 1075 + // 2D OpenSimplex2 case uses the same algorithm as ordinary Simplex. 1076 + 1077 + const float SQRT3 = 1.7320508075688772935274463415059f; 1078 + const float G2 = (3 - SQRT3) / 6; 1079 + 1080 + /* 1081 + * --- Skew moved to TransformNoiseCoordinate method --- 1082 + * const FNfloat F2 = 0.5f * (SQRT3 - 1); 1083 + * FNfloat s = (x + y) * F2; 1084 + * x += s; y += s; 1085 + */ 1086 + 1087 + int i = FastFloor(x); 1088 + int j = FastFloor(y); 1089 + float xi = (float)(x - i); 1090 + float yi = (float)(y - j); 1091 + 1092 + float t = (xi + yi) * G2; 1093 + float x0 = (float)(xi - t); 1094 + float y0 = (float)(yi - t); 1095 + 1096 + i *= PrimeX; 1097 + j *= PrimeY; 1098 + 1099 + float n0, n1, n2; 1100 + 1101 + float a = 0.5f - x0 * x0 - y0 * y0; 1102 + if (a <= 0) n0 = 0; 1103 + else 1104 + { 1105 + n0 = (a * a) * (a * a) * GradCoord(seed, i, j, x0, y0); 1106 + } 1107 + 1108 + float c = (float)(2 * (1 - 2 * G2) * (1 / G2 - 2)) * t + ((float)(-2 * (1 - 2 * G2) * (1 - 2 * G2)) + a); 1109 + if (c <= 0) n2 = 0; 1110 + else 1111 + { 1112 + float x2 = x0 + (2 * (float)G2 - 1); 1113 + float y2 = y0 + (2 * (float)G2 - 1); 1114 + n2 = (c * c) * (c * c) * GradCoord(seed, i + PrimeX, j + PrimeY, x2, y2); 1115 + } 1116 + 1117 + if (y0 > x0) 1118 + { 1119 + float x1 = x0 + (float)G2; 1120 + float y1 = y0 + ((float)G2 - 1); 1121 + float b = 0.5f - x1 * x1 - y1 * y1; 1122 + if (b <= 0) n1 = 0; 1123 + else 1124 + { 1125 + n1 = (b * b) * (b * b) * GradCoord(seed, i, j + PrimeY, x1, y1); 1126 + } 1127 + } 1128 + else 1129 + { 1130 + float x1 = x0 + ((float)G2 - 1); 1131 + float y1 = y0 + (float)G2; 1132 + float b = 0.5f - x1 * x1 - y1 * y1; 1133 + if (b <= 0) n1 = 0; 1134 + else 1135 + { 1136 + n1 = (b * b) * (b * b) * GradCoord(seed, i + PrimeX, j, x1, y1); 1137 + } 1138 + } 1139 + 1140 + return (n0 + n1 + n2) * 99.83685446303647f; 1141 + } 1142 + 1143 + private float SingleOpenSimplex2(int seed, FNLfloat x, FNLfloat y, FNLfloat z) 1144 + { 1145 + // 3D OpenSimplex2 case uses two offset rotated cube grids. 1146 + 1147 + /* 1148 + * --- Rotation moved to TransformNoiseCoordinate method --- 1149 + * const FNfloat R3 = (FNfloat)(2.0 / 3.0); 1150 + * FNfloat r = (x + y + z) * R3; // Rotation, not skew 1151 + * x = r - x; y = r - y; z = r - z; 1152 + */ 1153 + 1154 + int i = FastRound(x); 1155 + int j = FastRound(y); 1156 + int k = FastRound(z); 1157 + float x0 = (float)(x - i); 1158 + float y0 = (float)(y - j); 1159 + float z0 = (float)(z - k); 1160 + 1161 + int xNSign = (int)(-1.0f - x0) | 1; 1162 + int yNSign = (int)(-1.0f - y0) | 1; 1163 + int zNSign = (int)(-1.0f - z0) | 1; 1164 + 1165 + float ax0 = xNSign * -x0; 1166 + float ay0 = yNSign * -y0; 1167 + float az0 = zNSign * -z0; 1168 + 1169 + i *= PrimeX; 1170 + j *= PrimeY; 1171 + k *= PrimeZ; 1172 + 1173 + float value = 0; 1174 + float a = (0.6f - x0 * x0) - (y0 * y0 + z0 * z0); 1175 + 1176 + for (int l = 0; ; l++) 1177 + { 1178 + if (a > 0) 1179 + { 1180 + value += (a * a) * (a * a) * GradCoord(seed, i, j, k, x0, y0, z0); 1181 + } 1182 + 1183 + if (ax0 >= ay0 && ax0 >= az0) 1184 + { 1185 + float b = a + ax0 + ax0; 1186 + if (b > 1) { 1187 + b -= 1; 1188 + value += (b * b) * (b * b) * GradCoord(seed, i - xNSign * PrimeX, j, k, x0 + xNSign, y0, z0); 1189 + } 1190 + } 1191 + else if (ay0 > ax0 && ay0 >= az0) 1192 + { 1193 + float b = a + ay0 + ay0; 1194 + if (b > 1) 1195 + { 1196 + b -= 1; 1197 + value += (b * b) * (b * b) * GradCoord(seed, i, j - yNSign * PrimeY, k, x0, y0 + yNSign, z0); 1198 + } 1199 + } 1200 + else 1201 + { 1202 + float b = a + az0 + az0; 1203 + if (b > 1) 1204 + { 1205 + b -= 1; 1206 + value += (b * b) * (b * b) * GradCoord(seed, i, j, k - zNSign * PrimeZ, x0, y0, z0 + zNSign); 1207 + } 1208 + } 1209 + 1210 + if (l == 1) break; 1211 + 1212 + ax0 = 0.5f - ax0; 1213 + ay0 = 0.5f - ay0; 1214 + az0 = 0.5f - az0; 1215 + 1216 + x0 = xNSign * ax0; 1217 + y0 = yNSign * ay0; 1218 + z0 = zNSign * az0; 1219 + 1220 + a += (0.75f - ax0) - (ay0 + az0); 1221 + 1222 + i += (xNSign >> 1) & PrimeX; 1223 + j += (yNSign >> 1) & PrimeY; 1224 + k += (zNSign >> 1) & PrimeZ; 1225 + 1226 + xNSign = -xNSign; 1227 + yNSign = -yNSign; 1228 + zNSign = -zNSign; 1229 + 1230 + seed = ~seed; 1231 + } 1232 + 1233 + return value * 32.69428253173828125f; 1234 + } 1235 + 1236 + 1237 + // OpenSimplex2S Noise 1238 + 1239 + private float SingleOpenSimplex2S(int seed, FNLfloat x, FNLfloat y) 1240 + { 1241 + // 2D OpenSimplex2S case is a modified 2D simplex noise. 1242 + 1243 + const FNLfloat SQRT3 = (FNLfloat)1.7320508075688772935274463415059; 1244 + const FNLfloat G2 = (3 - SQRT3) / 6; 1245 + 1246 + /* 1247 + * --- Skew moved to TransformNoiseCoordinate method --- 1248 + * const FNfloat F2 = 0.5f * (SQRT3 - 1); 1249 + * FNfloat s = (x + y) * F2; 1250 + * x += s; y += s; 1251 + */ 1252 + 1253 + int i = FastFloor(x); 1254 + int j = FastFloor(y); 1255 + float xi = (float)(x - i); 1256 + float yi = (float)(y - j); 1257 + 1258 + i *= PrimeX; 1259 + j *= PrimeY; 1260 + int i1 = i + PrimeX; 1261 + int j1 = j + PrimeY; 1262 + 1263 + float t = (xi + yi) * (float)G2; 1264 + float x0 = xi - t; 1265 + float y0 = yi - t; 1266 + 1267 + float a0 = (2.0f / 3.0f) - x0 * x0 - y0 * y0; 1268 + float value = (a0 * a0) * (a0 * a0) * GradCoord(seed, i, j, x0, y0); 1269 + 1270 + float a1 = (float)(2 * (1 - 2 * G2) * (1 / G2 - 2)) * t + ((float)(-2 * (1 - 2 * G2) * (1 - 2 * G2)) + a0); 1271 + float x1 = x0 - (float)(1 - 2 * G2); 1272 + float y1 = y0 - (float)(1 - 2 * G2); 1273 + value += (a1 * a1) * (a1 * a1) * GradCoord(seed, i1, j1, x1, y1); 1274 + 1275 + // Nested conditionals were faster than compact bit logic/arithmetic. 1276 + float xmyi = xi - yi; 1277 + if (t > G2) 1278 + { 1279 + if (xi + xmyi > 1) 1280 + { 1281 + float x2 = x0 + (float)(3 * G2 - 2); 1282 + float y2 = y0 + (float)(3 * G2 - 1); 1283 + float a2 = (2.0f / 3.0f) - x2 * x2 - y2 * y2; 1284 + if (a2 > 0) 1285 + { 1286 + value += (a2 * a2) * (a2 * a2) * GradCoord(seed, i + (PrimeX << 1), j + PrimeY, x2, y2); 1287 + } 1288 + } 1289 + else 1290 + { 1291 + float x2 = x0 + (float)G2; 1292 + float y2 = y0 + (float)(G2 - 1); 1293 + float a2 = (2.0f / 3.0f) - x2 * x2 - y2 * y2; 1294 + if (a2 > 0) 1295 + { 1296 + value += (a2 * a2) * (a2 * a2) * GradCoord(seed, i, j + PrimeY, x2, y2); 1297 + } 1298 + } 1299 + 1300 + if (yi - xmyi > 1) 1301 + { 1302 + float x3 = x0 + (float)(3 * G2 - 1); 1303 + float y3 = y0 + (float)(3 * G2 - 2); 1304 + float a3 = (2.0f / 3.0f) - x3 * x3 - y3 * y3; 1305 + if (a3 > 0) 1306 + { 1307 + value += (a3 * a3) * (a3 * a3) * GradCoord(seed, i + PrimeX, j + (PrimeY << 1), x3, y3); 1308 + } 1309 + } 1310 + else 1311 + { 1312 + float x3 = x0 + (float)(G2 - 1); 1313 + float y3 = y0 + (float)G2; 1314 + float a3 = (2.0f / 3.0f) - x3 * x3 - y3 * y3; 1315 + if (a3 > 0) 1316 + { 1317 + value += (a3 * a3) * (a3 * a3) * GradCoord(seed, i + PrimeX, j, x3, y3); 1318 + } 1319 + } 1320 + } 1321 + else 1322 + { 1323 + if (xi + xmyi < 0) 1324 + { 1325 + float x2 = x0 + (float)(1 - G2); 1326 + float y2 = y0 - (float)G2; 1327 + float a2 = (2.0f / 3.0f) - x2 * x2 - y2 * y2; 1328 + if (a2 > 0) 1329 + { 1330 + value += (a2 * a2) * (a2 * a2) * GradCoord(seed, i - PrimeX, j, x2, y2); 1331 + } 1332 + } 1333 + else 1334 + { 1335 + float x2 = x0 + (float)(G2 - 1); 1336 + float y2 = y0 + (float)G2; 1337 + float a2 = (2.0f / 3.0f) - x2 * x2 - y2 * y2; 1338 + if (a2 > 0) 1339 + { 1340 + value += (a2 * a2) * (a2 * a2) * GradCoord(seed, i + PrimeX, j, x2, y2); 1341 + } 1342 + } 1343 + 1344 + if (yi < xmyi) 1345 + { 1346 + float x2 = x0 - (float)G2; 1347 + float y2 = y0 - (float)(G2 - 1); 1348 + float a2 = (2.0f / 3.0f) - x2 * x2 - y2 * y2; 1349 + if (a2 > 0) 1350 + { 1351 + value += (a2 * a2) * (a2 * a2) * GradCoord(seed, i, j - PrimeY, x2, y2); 1352 + } 1353 + } 1354 + else 1355 + { 1356 + float x2 = x0 + (float)G2; 1357 + float y2 = y0 + (float)(G2 - 1); 1358 + float a2 = (2.0f / 3.0f) - x2 * x2 - y2 * y2; 1359 + if (a2 > 0) 1360 + { 1361 + value += (a2 * a2) * (a2 * a2) * GradCoord(seed, i, j + PrimeY, x2, y2); 1362 + } 1363 + } 1364 + } 1365 + 1366 + return value * 18.24196194486065f; 1367 + } 1368 + 1369 + private float SingleOpenSimplex2S(int seed, FNLfloat x, FNLfloat y, FNLfloat z) 1370 + { 1371 + // 3D OpenSimplex2S case uses two offset rotated cube grids. 1372 + 1373 + /* 1374 + * --- Rotation moved to TransformNoiseCoordinate method --- 1375 + * const FNfloat R3 = (FNfloat)(2.0 / 3.0); 1376 + * FNfloat r = (x + y + z) * R3; // Rotation, not skew 1377 + * x = r - x; y = r - y; z = r - z; 1378 + */ 1379 + 1380 + int i = FastFloor(x); 1381 + int j = FastFloor(y); 1382 + int k = FastFloor(z); 1383 + float xi = (float)(x - i); 1384 + float yi = (float)(y - j); 1385 + float zi = (float)(z - k); 1386 + 1387 + i *= PrimeX; 1388 + j *= PrimeY; 1389 + k *= PrimeZ; 1390 + int seed2 = seed + 1293373; 1391 + 1392 + int xNMask = (int)(-0.5f - xi); 1393 + int yNMask = (int)(-0.5f - yi); 1394 + int zNMask = (int)(-0.5f - zi); 1395 + 1396 + float x0 = xi + xNMask; 1397 + float y0 = yi + yNMask; 1398 + float z0 = zi + zNMask; 1399 + float a0 = 0.75f - x0 * x0 - y0 * y0 - z0 * z0; 1400 + float value = (a0 * a0) * (a0 * a0) * GradCoord(seed, 1401 + i + (xNMask & PrimeX), j + (yNMask & PrimeY), k + (zNMask & PrimeZ), x0, y0, z0); 1402 + 1403 + float x1 = xi - 0.5f; 1404 + float y1 = yi - 0.5f; 1405 + float z1 = zi - 0.5f; 1406 + float a1 = 0.75f - x1 * x1 - y1 * y1 - z1 * z1; 1407 + value += (a1 * a1) * (a1 * a1) * GradCoord(seed2, 1408 + i + PrimeX, j + PrimeY, k + PrimeZ, x1, y1, z1); 1409 + 1410 + float xAFlipMask0 = ((xNMask | 1) << 1) * x1; 1411 + float yAFlipMask0 = ((yNMask | 1) << 1) * y1; 1412 + float zAFlipMask0 = ((zNMask | 1) << 1) * z1; 1413 + float xAFlipMask1 = (-2 - (xNMask << 2)) * x1 - 1.0f; 1414 + float yAFlipMask1 = (-2 - (yNMask << 2)) * y1 - 1.0f; 1415 + float zAFlipMask1 = (-2 - (zNMask << 2)) * z1 - 1.0f; 1416 + 1417 + bool skip5 = false; 1418 + float a2 = xAFlipMask0 + a0; 1419 + if (a2 > 0) 1420 + { 1421 + float x2 = x0 - (xNMask | 1); 1422 + float y2 = y0; 1423 + float z2 = z0; 1424 + value += (a2 * a2) * (a2 * a2) * GradCoord(seed, 1425 + i + (~xNMask & PrimeX), j + (yNMask & PrimeY), k + (zNMask & PrimeZ), x2, y2, z2); 1426 + } 1427 + else 1428 + { 1429 + float a3 = yAFlipMask0 + zAFlipMask0 + a0; 1430 + if (a3 > 0) 1431 + { 1432 + float x3 = x0; 1433 + float y3 = y0 - (yNMask | 1); 1434 + float z3 = z0 - (zNMask | 1); 1435 + value += (a3 * a3) * (a3 * a3) * GradCoord(seed, 1436 + i + (xNMask & PrimeX), j + (~yNMask & PrimeY), k + (~zNMask & PrimeZ), x3, y3, z3); 1437 + } 1438 + 1439 + float a4 = xAFlipMask1 + a1; 1440 + if (a4 > 0) 1441 + { 1442 + float x4 = (xNMask | 1) + x1; 1443 + float y4 = y1; 1444 + float z4 = z1; 1445 + value += (a4 * a4) * (a4 * a4) * GradCoord(seed2, 1446 + i + (xNMask & (PrimeX * 2)), j + PrimeY, k + PrimeZ, x4, y4, z4); 1447 + skip5 = true; 1448 + } 1449 + } 1450 + 1451 + bool skip9 = false; 1452 + float a6 = yAFlipMask0 + a0; 1453 + if (a6 > 0) 1454 + { 1455 + float x6 = x0; 1456 + float y6 = y0 - (yNMask | 1); 1457 + float z6 = z0; 1458 + value += (a6 * a6) * (a6 * a6) * GradCoord(seed, 1459 + i + (xNMask & PrimeX), j + (~yNMask & PrimeY), k + (zNMask & PrimeZ), x6, y6, z6); 1460 + } 1461 + else 1462 + { 1463 + float a7 = xAFlipMask0 + zAFlipMask0 + a0; 1464 + if (a7 > 0) 1465 + { 1466 + float x7 = x0 - (xNMask | 1); 1467 + float y7 = y0; 1468 + float z7 = z0 - (zNMask | 1); 1469 + value += (a7 * a7) * (a7 * a7) * GradCoord(seed, 1470 + i + (~xNMask & PrimeX), j + (yNMask & PrimeY), k + (~zNMask & PrimeZ), x7, y7, z7); 1471 + } 1472 + 1473 + float a8 = yAFlipMask1 + a1; 1474 + if (a8 > 0) 1475 + { 1476 + float x8 = x1; 1477 + float y8 = (yNMask | 1) + y1; 1478 + float z8 = z1; 1479 + value += (a8 * a8) * (a8 * a8) * GradCoord(seed2, 1480 + i + PrimeX, j + (yNMask & (PrimeY << 1)), k + PrimeZ, x8, y8, z8); 1481 + skip9 = true; 1482 + } 1483 + } 1484 + 1485 + bool skipD = false; 1486 + float aA = zAFlipMask0 + a0; 1487 + if (aA > 0) 1488 + { 1489 + float xA = x0; 1490 + float yA = y0; 1491 + float zA = z0 - (zNMask | 1); 1492 + value += (aA * aA) * (aA * aA) * GradCoord(seed, 1493 + i + (xNMask & PrimeX), j + (yNMask & PrimeY), k + (~zNMask & PrimeZ), xA, yA, zA); 1494 + } 1495 + else 1496 + { 1497 + float aB = xAFlipMask0 + yAFlipMask0 + a0; 1498 + if (aB > 0) 1499 + { 1500 + float xB = x0 - (xNMask | 1); 1501 + float yB = y0 - (yNMask | 1); 1502 + float zB = z0; 1503 + value += (aB * aB) * (aB * aB) * GradCoord(seed, 1504 + i + (~xNMask & PrimeX), j + (~yNMask & PrimeY), k + (zNMask & PrimeZ), xB, yB, zB); 1505 + } 1506 + 1507 + float aC = zAFlipMask1 + a1; 1508 + if (aC > 0) 1509 + { 1510 + float xC = x1; 1511 + float yC = y1; 1512 + float zC = (zNMask | 1) + z1; 1513 + value += (aC * aC) * (aC * aC) * GradCoord(seed2, 1514 + i + PrimeX, j + PrimeY, k + (zNMask & (PrimeZ << 1)), xC, yC, zC); 1515 + skipD = true; 1516 + } 1517 + } 1518 + 1519 + if (!skip5) 1520 + { 1521 + float a5 = yAFlipMask1 + zAFlipMask1 + a1; 1522 + if (a5 > 0) 1523 + { 1524 + float x5 = x1; 1525 + float y5 = (yNMask | 1) + y1; 1526 + float z5 = (zNMask | 1) + z1; 1527 + value += (a5 * a5) * (a5 * a5) * GradCoord(seed2, 1528 + i + PrimeX, j + (yNMask & (PrimeY << 1)), k + (zNMask & (PrimeZ << 1)), x5, y5, z5); 1529 + } 1530 + } 1531 + 1532 + if (!skip9) 1533 + { 1534 + float a9 = xAFlipMask1 + zAFlipMask1 + a1; 1535 + if (a9 > 0) 1536 + { 1537 + float x9 = (xNMask | 1) + x1; 1538 + float y9 = y1; 1539 + float z9 = (zNMask | 1) + z1; 1540 + value += (a9 * a9) * (a9 * a9) * GradCoord(seed2, 1541 + i + (xNMask & (PrimeX * 2)), j + PrimeY, k + (zNMask & (PrimeZ << 1)), x9, y9, z9); 1542 + } 1543 + } 1544 + 1545 + if (!skipD) 1546 + { 1547 + float aD = xAFlipMask1 + yAFlipMask1 + a1; 1548 + if (aD > 0) 1549 + { 1550 + float xD = (xNMask | 1) + x1; 1551 + float yD = (yNMask | 1) + y1; 1552 + float zD = z1; 1553 + value += (aD * aD) * (aD * aD) * GradCoord(seed2, 1554 + i + (xNMask & (PrimeX << 1)), j + (yNMask & (PrimeY << 1)), k + PrimeZ, xD, yD, zD); 1555 + } 1556 + } 1557 + 1558 + return value * 9.046026385208288f; 1559 + } 1560 + 1561 + 1562 + // Cellular Noise 1563 + 1564 + private float SingleCellular(int seed, FNLfloat x, FNLfloat y) 1565 + { 1566 + int xr = FastRound(x); 1567 + int yr = FastRound(y); 1568 + 1569 + float distance0 = float.MaxValue; 1570 + float distance1 = float.MaxValue; 1571 + int closestHash = 0; 1572 + 1573 + float cellularJitter = 0.43701595f * mCellularJitterModifier; 1574 + 1575 + int xPrimed = (xr - 1) * PrimeX; 1576 + int yPrimedBase = (yr - 1) * PrimeY; 1577 + 1578 + switch (mCellularDistanceFunction) 1579 + { 1580 + default: 1581 + case CellularDistanceFunction.Euclidean: 1582 + case CellularDistanceFunction.EuclideanSq: 1583 + for (int xi = xr - 1; xi <= xr + 1; xi++) 1584 + { 1585 + int yPrimed = yPrimedBase; 1586 + 1587 + for (int yi = yr - 1; yi <= yr + 1; yi++) 1588 + { 1589 + int hash = Hash(seed, xPrimed, yPrimed); 1590 + int idx = hash & (255 << 1); 1591 + 1592 + float vecX = (float)(xi - x) + RandVecs2D[idx] * cellularJitter; 1593 + float vecY = (float)(yi - y) + RandVecs2D[idx | 1] * cellularJitter; 1594 + 1595 + float newDistance = vecX * vecX + vecY * vecY; 1596 + 1597 + distance1 = FastMax(FastMin(distance1, newDistance), distance0); 1598 + if (newDistance < distance0) 1599 + { 1600 + distance0 = newDistance; 1601 + closestHash = hash; 1602 + } 1603 + yPrimed += PrimeY; 1604 + } 1605 + xPrimed += PrimeX; 1606 + } 1607 + break; 1608 + case CellularDistanceFunction.Manhattan: 1609 + for (int xi = xr - 1; xi <= xr + 1; xi++) 1610 + { 1611 + int yPrimed = yPrimedBase; 1612 + 1613 + for (int yi = yr - 1; yi <= yr + 1; yi++) 1614 + { 1615 + int hash = Hash(seed, xPrimed, yPrimed); 1616 + int idx = hash & (255 << 1); 1617 + 1618 + float vecX = (float)(xi - x) + RandVecs2D[idx] * cellularJitter; 1619 + float vecY = (float)(yi - y) + RandVecs2D[idx | 1] * cellularJitter; 1620 + 1621 + float newDistance = FastAbs(vecX) + FastAbs(vecY); 1622 + 1623 + distance1 = FastMax(FastMin(distance1, newDistance), distance0); 1624 + if (newDistance < distance0) 1625 + { 1626 + distance0 = newDistance; 1627 + closestHash = hash; 1628 + } 1629 + yPrimed += PrimeY; 1630 + } 1631 + xPrimed += PrimeX; 1632 + } 1633 + break; 1634 + case CellularDistanceFunction.Hybrid: 1635 + for (int xi = xr - 1; xi <= xr + 1; xi++) 1636 + { 1637 + int yPrimed = yPrimedBase; 1638 + 1639 + for (int yi = yr - 1; yi <= yr + 1; yi++) 1640 + { 1641 + int hash = Hash(seed, xPrimed, yPrimed); 1642 + int idx = hash & (255 << 1); 1643 + 1644 + float vecX = (float)(xi - x) + RandVecs2D[idx] * cellularJitter; 1645 + float vecY = (float)(yi - y) + RandVecs2D[idx | 1] * cellularJitter; 1646 + 1647 + float newDistance = (FastAbs(vecX) + FastAbs(vecY)) + (vecX * vecX + vecY * vecY); 1648 + 1649 + distance1 = FastMax(FastMin(distance1, newDistance), distance0); 1650 + if (newDistance < distance0) 1651 + { 1652 + distance0 = newDistance; 1653 + closestHash = hash; 1654 + } 1655 + yPrimed += PrimeY; 1656 + } 1657 + xPrimed += PrimeX; 1658 + } 1659 + break; 1660 + } 1661 + 1662 + if (mCellularDistanceFunction == CellularDistanceFunction.Euclidean && mCellularReturnType >= CellularReturnType.Distance) 1663 + { 1664 + distance0 = FastSqrt(distance0); 1665 + 1666 + if (mCellularReturnType >= CellularReturnType.Distance2) 1667 + { 1668 + distance1 = FastSqrt(distance1); 1669 + } 1670 + } 1671 + 1672 + switch (mCellularReturnType) 1673 + { 1674 + case CellularReturnType.CellValue: 1675 + return closestHash * (1 / 2147483648.0f); 1676 + case CellularReturnType.Distance: 1677 + return distance0 - 1; 1678 + case CellularReturnType.Distance2: 1679 + return distance1 - 1; 1680 + case CellularReturnType.Distance2Add: 1681 + return (distance1 + distance0) * 0.5f - 1; 1682 + case CellularReturnType.Distance2Sub: 1683 + return distance1 - distance0 - 1; 1684 + case CellularReturnType.Distance2Mul: 1685 + return distance1 * distance0 * 0.5f - 1; 1686 + case CellularReturnType.Distance2Div: 1687 + return distance0 / distance1 - 1; 1688 + default: 1689 + return 0; 1690 + } 1691 + } 1692 + 1693 + private float SingleCellular(int seed, FNLfloat x, FNLfloat y, FNLfloat z) 1694 + { 1695 + int xr = FastRound(x); 1696 + int yr = FastRound(y); 1697 + int zr = FastRound(z); 1698 + 1699 + float distance0 = float.MaxValue; 1700 + float distance1 = float.MaxValue; 1701 + int closestHash = 0; 1702 + 1703 + float cellularJitter = 0.39614353f * mCellularJitterModifier; 1704 + 1705 + int xPrimed = (xr - 1) * PrimeX; 1706 + int yPrimedBase = (yr - 1) * PrimeY; 1707 + int zPrimedBase = (zr - 1) * PrimeZ; 1708 + 1709 + switch (mCellularDistanceFunction) 1710 + { 1711 + case CellularDistanceFunction.Euclidean: 1712 + case CellularDistanceFunction.EuclideanSq: 1713 + for (int xi = xr - 1; xi <= xr + 1; xi++) 1714 + { 1715 + int yPrimed = yPrimedBase; 1716 + 1717 + for (int yi = yr - 1; yi <= yr + 1; yi++) 1718 + { 1719 + int zPrimed = zPrimedBase; 1720 + 1721 + for (int zi = zr - 1; zi <= zr + 1; zi++) 1722 + { 1723 + int hash = Hash(seed, xPrimed, yPrimed, zPrimed); 1724 + int idx = hash & (255 << 2); 1725 + 1726 + float vecX = (float)(xi - x) + RandVecs3D[idx] * cellularJitter; 1727 + float vecY = (float)(yi - y) + RandVecs3D[idx | 1] * cellularJitter; 1728 + float vecZ = (float)(zi - z) + RandVecs3D[idx | 2] * cellularJitter; 1729 + 1730 + float newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ; 1731 + 1732 + distance1 = FastMax(FastMin(distance1, newDistance), distance0); 1733 + if (newDistance < distance0) 1734 + { 1735 + distance0 = newDistance; 1736 + closestHash = hash; 1737 + } 1738 + zPrimed += PrimeZ; 1739 + } 1740 + yPrimed += PrimeY; 1741 + } 1742 + xPrimed += PrimeX; 1743 + } 1744 + break; 1745 + case CellularDistanceFunction.Manhattan: 1746 + for (int xi = xr - 1; xi <= xr + 1; xi++) 1747 + { 1748 + int yPrimed = yPrimedBase; 1749 + 1750 + for (int yi = yr - 1; yi <= yr + 1; yi++) 1751 + { 1752 + int zPrimed = zPrimedBase; 1753 + 1754 + for (int zi = zr - 1; zi <= zr + 1; zi++) 1755 + { 1756 + int hash = Hash(seed, xPrimed, yPrimed, zPrimed); 1757 + int idx = hash & (255 << 2); 1758 + 1759 + float vecX = (float)(xi - x) + RandVecs3D[idx] * cellularJitter; 1760 + float vecY = (float)(yi - y) + RandVecs3D[idx | 1] * cellularJitter; 1761 + float vecZ = (float)(zi - z) + RandVecs3D[idx | 2] * cellularJitter; 1762 + 1763 + float newDistance = FastAbs(vecX) + FastAbs(vecY) + FastAbs(vecZ); 1764 + 1765 + distance1 = FastMax(FastMin(distance1, newDistance), distance0); 1766 + if (newDistance < distance0) 1767 + { 1768 + distance0 = newDistance; 1769 + closestHash = hash; 1770 + } 1771 + zPrimed += PrimeZ; 1772 + } 1773 + yPrimed += PrimeY; 1774 + } 1775 + xPrimed += PrimeX; 1776 + } 1777 + break; 1778 + case CellularDistanceFunction.Hybrid: 1779 + for (int xi = xr - 1; xi <= xr + 1; xi++) 1780 + { 1781 + int yPrimed = yPrimedBase; 1782 + 1783 + for (int yi = yr - 1; yi <= yr + 1; yi++) 1784 + { 1785 + int zPrimed = zPrimedBase; 1786 + 1787 + for (int zi = zr - 1; zi <= zr + 1; zi++) 1788 + { 1789 + int hash = Hash(seed, xPrimed, yPrimed, zPrimed); 1790 + int idx = hash & (255 << 2); 1791 + 1792 + float vecX = (float)(xi - x) + RandVecs3D[idx] * cellularJitter; 1793 + float vecY = (float)(yi - y) + RandVecs3D[idx | 1] * cellularJitter; 1794 + float vecZ = (float)(zi - z) + RandVecs3D[idx | 2] * cellularJitter; 1795 + 1796 + float newDistance = (FastAbs(vecX) + FastAbs(vecY) + FastAbs(vecZ)) + (vecX * vecX + vecY * vecY + vecZ * vecZ); 1797 + 1798 + distance1 = FastMax(FastMin(distance1, newDistance), distance0); 1799 + if (newDistance < distance0) 1800 + { 1801 + distance0 = newDistance; 1802 + closestHash = hash; 1803 + } 1804 + zPrimed += PrimeZ; 1805 + } 1806 + yPrimed += PrimeY; 1807 + } 1808 + xPrimed += PrimeX; 1809 + } 1810 + break; 1811 + default: 1812 + break; 1813 + } 1814 + 1815 + if (mCellularDistanceFunction == CellularDistanceFunction.Euclidean && mCellularReturnType >= CellularReturnType.Distance) 1816 + { 1817 + distance0 = FastSqrt(distance0); 1818 + 1819 + if (mCellularReturnType >= CellularReturnType.Distance2) 1820 + { 1821 + distance1 = FastSqrt(distance1); 1822 + } 1823 + } 1824 + 1825 + switch (mCellularReturnType) 1826 + { 1827 + case CellularReturnType.CellValue: 1828 + return closestHash * (1 / 2147483648.0f); 1829 + case CellularReturnType.Distance: 1830 + return distance0 - 1; 1831 + case CellularReturnType.Distance2: 1832 + return distance1 - 1; 1833 + case CellularReturnType.Distance2Add: 1834 + return (distance1 + distance0) * 0.5f - 1; 1835 + case CellularReturnType.Distance2Sub: 1836 + return distance1 - distance0 - 1; 1837 + case CellularReturnType.Distance2Mul: 1838 + return distance1 * distance0 * 0.5f - 1; 1839 + case CellularReturnType.Distance2Div: 1840 + return distance0 / distance1 - 1; 1841 + default: 1842 + return 0; 1843 + } 1844 + } 1845 + 1846 + 1847 + // Perlin Noise 1848 + 1849 + private float SinglePerlin(int seed, FNLfloat x, FNLfloat y) 1850 + { 1851 + int x0 = FastFloor(x); 1852 + int y0 = FastFloor(y); 1853 + 1854 + float xd0 = (float)(x - x0); 1855 + float yd0 = (float)(y - y0); 1856 + float xd1 = xd0 - 1; 1857 + float yd1 = yd0 - 1; 1858 + 1859 + float xs = InterpQuintic(xd0); 1860 + float ys = InterpQuintic(yd0); 1861 + 1862 + x0 *= PrimeX; 1863 + y0 *= PrimeY; 1864 + int x1 = x0 + PrimeX; 1865 + int y1 = y0 + PrimeY; 1866 + 1867 + float xf0 = Lerp(GradCoord(seed, x0, y0, xd0, yd0), GradCoord(seed, x1, y0, xd1, yd0), xs); 1868 + float xf1 = Lerp(GradCoord(seed, x0, y1, xd0, yd1), GradCoord(seed, x1, y1, xd1, yd1), xs); 1869 + 1870 + return Lerp(xf0, xf1, ys) * 1.4247691104677813f; 1871 + } 1872 + 1873 + private float SinglePerlin(int seed, FNLfloat x, FNLfloat y, FNLfloat z) 1874 + { 1875 + int x0 = FastFloor(x); 1876 + int y0 = FastFloor(y); 1877 + int z0 = FastFloor(z); 1878 + 1879 + float xd0 = (float)(x - x0); 1880 + float yd0 = (float)(y - y0); 1881 + float zd0 = (float)(z - z0); 1882 + float xd1 = xd0 - 1; 1883 + float yd1 = yd0 - 1; 1884 + float zd1 = zd0 - 1; 1885 + 1886 + float xs = InterpQuintic(xd0); 1887 + float ys = InterpQuintic(yd0); 1888 + float zs = InterpQuintic(zd0); 1889 + 1890 + x0 *= PrimeX; 1891 + y0 *= PrimeY; 1892 + z0 *= PrimeZ; 1893 + int x1 = x0 + PrimeX; 1894 + int y1 = y0 + PrimeY; 1895 + int z1 = z0 + PrimeZ; 1896 + 1897 + float xf00 = Lerp(GradCoord(seed, x0, y0, z0, xd0, yd0, zd0), GradCoord(seed, x1, y0, z0, xd1, yd0, zd0), xs); 1898 + float xf10 = Lerp(GradCoord(seed, x0, y1, z0, xd0, yd1, zd0), GradCoord(seed, x1, y1, z0, xd1, yd1, zd0), xs); 1899 + float xf01 = Lerp(GradCoord(seed, x0, y0, z1, xd0, yd0, zd1), GradCoord(seed, x1, y0, z1, xd1, yd0, zd1), xs); 1900 + float xf11 = Lerp(GradCoord(seed, x0, y1, z1, xd0, yd1, zd1), GradCoord(seed, x1, y1, z1, xd1, yd1, zd1), xs); 1901 + 1902 + float yf0 = Lerp(xf00, xf10, ys); 1903 + float yf1 = Lerp(xf01, xf11, ys); 1904 + 1905 + return Lerp(yf0, yf1, zs) * 0.964921414852142333984375f; 1906 + } 1907 + 1908 + 1909 + // Value Cubic Noise 1910 + 1911 + private float SingleValueCubic(int seed, FNLfloat x, FNLfloat y) 1912 + { 1913 + int x1 = FastFloor(x); 1914 + int y1 = FastFloor(y); 1915 + 1916 + float xs = (float)(x - x1); 1917 + float ys = (float)(y - y1); 1918 + 1919 + x1 *= PrimeX; 1920 + y1 *= PrimeY; 1921 + int x0 = x1 - PrimeX; 1922 + int y0 = y1 - PrimeY; 1923 + int x2 = x1 + PrimeX; 1924 + int y2 = y1 + PrimeY; 1925 + int x3 = x1 + unchecked(PrimeX * 2); 1926 + int y3 = y1 + unchecked(PrimeY * 2); 1927 + 1928 + return CubicLerp( 1929 + CubicLerp(ValCoord(seed, x0, y0), ValCoord(seed, x1, y0), ValCoord(seed, x2, y0), ValCoord(seed, x3, y0), 1930 + xs), 1931 + CubicLerp(ValCoord(seed, x0, y1), ValCoord(seed, x1, y1), ValCoord(seed, x2, y1), ValCoord(seed, x3, y1), 1932 + xs), 1933 + CubicLerp(ValCoord(seed, x0, y2), ValCoord(seed, x1, y2), ValCoord(seed, x2, y2), ValCoord(seed, x3, y2), 1934 + xs), 1935 + CubicLerp(ValCoord(seed, x0, y3), ValCoord(seed, x1, y3), ValCoord(seed, x2, y3), ValCoord(seed, x3, y3), 1936 + xs), 1937 + ys) * (1 / (1.5f * 1.5f)); 1938 + } 1939 + 1940 + private float SingleValueCubic(int seed, FNLfloat x, FNLfloat y, FNLfloat z) 1941 + { 1942 + int x1 = FastFloor(x); 1943 + int y1 = FastFloor(y); 1944 + int z1 = FastFloor(z); 1945 + 1946 + float xs = (float)(x - x1); 1947 + float ys = (float)(y - y1); 1948 + float zs = (float)(z - z1); 1949 + 1950 + x1 *= PrimeX; 1951 + y1 *= PrimeY; 1952 + z1 *= PrimeZ; 1953 + 1954 + int x0 = x1 - PrimeX; 1955 + int y0 = y1 - PrimeY; 1956 + int z0 = z1 - PrimeZ; 1957 + int x2 = x1 + PrimeX; 1958 + int y2 = y1 + PrimeY; 1959 + int z2 = z1 + PrimeZ; 1960 + int x3 = x1 + unchecked(PrimeX * 2); 1961 + int y3 = y1 + unchecked(PrimeY * 2); 1962 + int z3 = z1 + unchecked(PrimeZ * 2); 1963 + 1964 + 1965 + return CubicLerp( 1966 + CubicLerp( 1967 + CubicLerp(ValCoord(seed, x0, y0, z0), ValCoord(seed, x1, y0, z0), ValCoord(seed, x2, y0, z0), ValCoord(seed, x3, y0, z0), xs), 1968 + CubicLerp(ValCoord(seed, x0, y1, z0), ValCoord(seed, x1, y1, z0), ValCoord(seed, x2, y1, z0), ValCoord(seed, x3, y1, z0), xs), 1969 + CubicLerp(ValCoord(seed, x0, y2, z0), ValCoord(seed, x1, y2, z0), ValCoord(seed, x2, y2, z0), ValCoord(seed, x3, y2, z0), xs), 1970 + CubicLerp(ValCoord(seed, x0, y3, z0), ValCoord(seed, x1, y3, z0), ValCoord(seed, x2, y3, z0), ValCoord(seed, x3, y3, z0), xs), 1971 + ys), 1972 + CubicLerp( 1973 + CubicLerp(ValCoord(seed, x0, y0, z1), ValCoord(seed, x1, y0, z1), ValCoord(seed, x2, y0, z1), ValCoord(seed, x3, y0, z1), xs), 1974 + CubicLerp(ValCoord(seed, x0, y1, z1), ValCoord(seed, x1, y1, z1), ValCoord(seed, x2, y1, z1), ValCoord(seed, x3, y1, z1), xs), 1975 + CubicLerp(ValCoord(seed, x0, y2, z1), ValCoord(seed, x1, y2, z1), ValCoord(seed, x2, y2, z1), ValCoord(seed, x3, y2, z1), xs), 1976 + CubicLerp(ValCoord(seed, x0, y3, z1), ValCoord(seed, x1, y3, z1), ValCoord(seed, x2, y3, z1), ValCoord(seed, x3, y3, z1), xs), 1977 + ys), 1978 + CubicLerp( 1979 + CubicLerp(ValCoord(seed, x0, y0, z2), ValCoord(seed, x1, y0, z2), ValCoord(seed, x2, y0, z2), ValCoord(seed, x3, y0, z2), xs), 1980 + CubicLerp(ValCoord(seed, x0, y1, z2), ValCoord(seed, x1, y1, z2), ValCoord(seed, x2, y1, z2), ValCoord(seed, x3, y1, z2), xs), 1981 + CubicLerp(ValCoord(seed, x0, y2, z2), ValCoord(seed, x1, y2, z2), ValCoord(seed, x2, y2, z2), ValCoord(seed, x3, y2, z2), xs), 1982 + CubicLerp(ValCoord(seed, x0, y3, z2), ValCoord(seed, x1, y3, z2), ValCoord(seed, x2, y3, z2), ValCoord(seed, x3, y3, z2), xs), 1983 + ys), 1984 + CubicLerp( 1985 + CubicLerp(ValCoord(seed, x0, y0, z3), ValCoord(seed, x1, y0, z3), ValCoord(seed, x2, y0, z3), ValCoord(seed, x3, y0, z3), xs), 1986 + CubicLerp(ValCoord(seed, x0, y1, z3), ValCoord(seed, x1, y1, z3), ValCoord(seed, x2, y1, z3), ValCoord(seed, x3, y1, z3), xs), 1987 + CubicLerp(ValCoord(seed, x0, y2, z3), ValCoord(seed, x1, y2, z3), ValCoord(seed, x2, y2, z3), ValCoord(seed, x3, y2, z3), xs), 1988 + CubicLerp(ValCoord(seed, x0, y3, z3), ValCoord(seed, x1, y3, z3), ValCoord(seed, x2, y3, z3), ValCoord(seed, x3, y3, z3), xs), 1989 + ys), 1990 + zs) * (1 / (1.5f * 1.5f * 1.5f)); 1991 + } 1992 + 1993 + 1994 + // Value Noise 1995 + 1996 + private float SingleValue(int seed, FNLfloat x, FNLfloat y) 1997 + { 1998 + int x0 = FastFloor(x); 1999 + int y0 = FastFloor(y); 2000 + 2001 + float xs = InterpHermite((float)(x - x0)); 2002 + float ys = InterpHermite((float)(y - y0)); 2003 + 2004 + x0 *= PrimeX; 2005 + y0 *= PrimeY; 2006 + int x1 = x0 + PrimeX; 2007 + int y1 = y0 + PrimeY; 2008 + 2009 + float xf0 = Lerp(ValCoord(seed, x0, y0), ValCoord(seed, x1, y0), xs); 2010 + float xf1 = Lerp(ValCoord(seed, x0, y1), ValCoord(seed, x1, y1), xs); 2011 + 2012 + return Lerp(xf0, xf1, ys); 2013 + } 2014 + 2015 + private float SingleValue(int seed, FNLfloat x, FNLfloat y, FNLfloat z) 2016 + { 2017 + int x0 = FastFloor(x); 2018 + int y0 = FastFloor(y); 2019 + int z0 = FastFloor(z); 2020 + 2021 + float xs = InterpHermite((float)(x - x0)); 2022 + float ys = InterpHermite((float)(y - y0)); 2023 + float zs = InterpHermite((float)(z - z0)); 2024 + 2025 + x0 *= PrimeX; 2026 + y0 *= PrimeY; 2027 + z0 *= PrimeZ; 2028 + int x1 = x0 + PrimeX; 2029 + int y1 = y0 + PrimeY; 2030 + int z1 = z0 + PrimeZ; 2031 + 2032 + float xf00 = Lerp(ValCoord(seed, x0, y0, z0), ValCoord(seed, x1, y0, z0), xs); 2033 + float xf10 = Lerp(ValCoord(seed, x0, y1, z0), ValCoord(seed, x1, y1, z0), xs); 2034 + float xf01 = Lerp(ValCoord(seed, x0, y0, z1), ValCoord(seed, x1, y0, z1), xs); 2035 + float xf11 = Lerp(ValCoord(seed, x0, y1, z1), ValCoord(seed, x1, y1, z1), xs); 2036 + 2037 + float yf0 = Lerp(xf00, xf10, ys); 2038 + float yf1 = Lerp(xf01, xf11, ys); 2039 + 2040 + return Lerp(yf0, yf1, zs); 2041 + } 2042 + 2043 + 2044 + // Domain Warp 2045 + 2046 + private void DoSingleDomainWarp(int seed, float amp, float freq, FNLfloat x, FNLfloat y, ref FNLfloat xr, ref FNLfloat yr) 2047 + { 2048 + switch (mDomainWarpType) 2049 + { 2050 + case DomainWarpType.OpenSimplex2: 2051 + SingleDomainWarpSimplexGradient(seed, amp * 38.283687591552734375f, freq, x, y, ref xr, ref yr, false); 2052 + break; 2053 + case DomainWarpType.OpenSimplex2Reduced: 2054 + SingleDomainWarpSimplexGradient(seed, amp * 16.0f, freq, x, y, ref xr, ref yr, true); 2055 + break; 2056 + case DomainWarpType.BasicGrid: 2057 + SingleDomainWarpBasicGrid(seed, amp, freq, x, y, ref xr, ref yr); 2058 + break; 2059 + } 2060 + } 2061 + 2062 + private void DoSingleDomainWarp(int seed, float amp, float freq, FNLfloat x, FNLfloat y, FNLfloat z, ref FNLfloat xr, ref FNLfloat yr, ref FNLfloat zr) 2063 + { 2064 + switch (mDomainWarpType) 2065 + { 2066 + case DomainWarpType.OpenSimplex2: 2067 + SingleDomainWarpOpenSimplex2Gradient(seed, amp * 32.69428253173828125f, freq, x, y, z, ref xr, ref yr, ref zr, false); 2068 + break; 2069 + case DomainWarpType.OpenSimplex2Reduced: 2070 + SingleDomainWarpOpenSimplex2Gradient(seed, amp * 7.71604938271605f, freq, x, y, z, ref xr, ref yr, ref zr, true); 2071 + break; 2072 + case DomainWarpType.BasicGrid: 2073 + SingleDomainWarpBasicGrid(seed, amp, freq, x, y, z, ref xr, ref yr, ref zr); 2074 + break; 2075 + } 2076 + } 2077 + 2078 + 2079 + // Domain Warp Single Wrapper 2080 + 2081 + private void DomainWarpSingle(ref FNLfloat x, ref FNLfloat y) 2082 + { 2083 + int seed = mSeed; 2084 + float amp = mDomainWarpAmp * mFractalBounding; 2085 + float freq = mFrequency; 2086 + 2087 + FNLfloat xs = x; 2088 + FNLfloat ys = y; 2089 + TransformDomainWarpCoordinate(ref xs, ref ys); 2090 + 2091 + DoSingleDomainWarp(seed, amp, freq, xs, ys, ref x, ref y); 2092 + } 2093 + 2094 + private void DomainWarpSingle(ref FNLfloat x, ref FNLfloat y, ref FNLfloat z) 2095 + { 2096 + int seed = mSeed; 2097 + float amp = mDomainWarpAmp * mFractalBounding; 2098 + float freq = mFrequency; 2099 + 2100 + FNLfloat xs = x; 2101 + FNLfloat ys = y; 2102 + FNLfloat zs = z; 2103 + TransformDomainWarpCoordinate(ref xs, ref ys, ref zs); 2104 + 2105 + DoSingleDomainWarp(seed, amp, freq, xs, ys, zs, ref x, ref y, ref z); 2106 + } 2107 + 2108 + 2109 + // Domain Warp Fractal Progressive 2110 + 2111 + private void DomainWarpFractalProgressive(ref FNLfloat x, ref FNLfloat y) 2112 + { 2113 + int seed = mSeed; 2114 + float amp = mDomainWarpAmp * mFractalBounding; 2115 + float freq = mFrequency; 2116 + 2117 + for (int i = 0; i < mOctaves; i++) 2118 + { 2119 + FNLfloat xs = x; 2120 + FNLfloat ys = y; 2121 + TransformDomainWarpCoordinate(ref xs, ref ys); 2122 + 2123 + DoSingleDomainWarp(seed, amp, freq, xs, ys, ref x, ref y); 2124 + 2125 + seed++; 2126 + amp *= mGain; 2127 + freq *= mLacunarity; 2128 + } 2129 + } 2130 + 2131 + private void DomainWarpFractalProgressive(ref FNLfloat x, ref FNLfloat y, ref FNLfloat z) 2132 + { 2133 + int seed = mSeed; 2134 + float amp = mDomainWarpAmp * mFractalBounding; 2135 + float freq = mFrequency; 2136 + 2137 + for (int i = 0; i < mOctaves; i++) 2138 + { 2139 + FNLfloat xs = x; 2140 + FNLfloat ys = y; 2141 + FNLfloat zs = z; 2142 + TransformDomainWarpCoordinate(ref xs, ref ys, ref zs); 2143 + 2144 + DoSingleDomainWarp(seed, amp, freq, xs, ys, zs, ref x, ref y, ref z); 2145 + 2146 + seed++; 2147 + amp *= mGain; 2148 + freq *= mLacunarity; 2149 + } 2150 + } 2151 + 2152 + 2153 + // Domain Warp Fractal Independant 2154 + private void DomainWarpFractalIndependent(ref FNLfloat x, ref FNLfloat y) 2155 + { 2156 + FNLfloat xs = x; 2157 + FNLfloat ys = y; 2158 + TransformDomainWarpCoordinate(ref xs, ref ys); 2159 + 2160 + int seed = mSeed; 2161 + float amp = mDomainWarpAmp * mFractalBounding; 2162 + float freq = mFrequency; 2163 + 2164 + for (int i = 0; i < mOctaves; i++) 2165 + { 2166 + DoSingleDomainWarp(seed, amp, freq, xs, ys, ref x, ref y); 2167 + 2168 + seed++; 2169 + amp *= mGain; 2170 + freq *= mLacunarity; 2171 + } 2172 + } 2173 + 2174 + private void DomainWarpFractalIndependent(ref FNLfloat x, ref FNLfloat y, ref FNLfloat z) 2175 + { 2176 + FNLfloat xs = x; 2177 + FNLfloat ys = y; 2178 + FNLfloat zs = z; 2179 + TransformDomainWarpCoordinate(ref xs, ref ys, ref zs); 2180 + 2181 + int seed = mSeed; 2182 + float amp = mDomainWarpAmp * mFractalBounding; 2183 + float freq = mFrequency; 2184 + 2185 + for (int i = 0; i < mOctaves; i++) 2186 + { 2187 + DoSingleDomainWarp(seed, amp, freq, xs, ys, zs, ref x, ref y, ref z); 2188 + 2189 + seed++; 2190 + amp *= mGain; 2191 + freq *= mLacunarity; 2192 + } 2193 + } 2194 + 2195 + 2196 + // Domain Warp Basic Grid 2197 + 2198 + private void SingleDomainWarpBasicGrid(int seed, float warpAmp, float frequency, FNLfloat x, FNLfloat y, ref FNLfloat xr, ref FNLfloat yr) 2199 + { 2200 + FNLfloat xf = x * frequency; 2201 + FNLfloat yf = y * frequency; 2202 + 2203 + int x0 = FastFloor(xf); 2204 + int y0 = FastFloor(yf); 2205 + 2206 + float xs = InterpHermite((float)(xf - x0)); 2207 + float ys = InterpHermite((float)(yf - y0)); 2208 + 2209 + x0 *= PrimeX; 2210 + y0 *= PrimeY; 2211 + int x1 = x0 + PrimeX; 2212 + int y1 = y0 + PrimeY; 2213 + 2214 + int hash0 = Hash(seed, x0, y0) & (255 << 1); 2215 + int hash1 = Hash(seed, x1, y0) & (255 << 1); 2216 + 2217 + float lx0x = Lerp(RandVecs2D[hash0], RandVecs2D[hash1], xs); 2218 + float ly0x = Lerp(RandVecs2D[hash0 | 1], RandVecs2D[hash1 | 1], xs); 2219 + 2220 + hash0 = Hash(seed, x0, y1) & (255 << 1); 2221 + hash1 = Hash(seed, x1, y1) & (255 << 1); 2222 + 2223 + float lx1x = Lerp(RandVecs2D[hash0], RandVecs2D[hash1], xs); 2224 + float ly1x = Lerp(RandVecs2D[hash0 | 1], RandVecs2D[hash1 | 1], xs); 2225 + 2226 + xr += Lerp(lx0x, lx1x, ys) * warpAmp; 2227 + yr += Lerp(ly0x, ly1x, ys) * warpAmp; 2228 + } 2229 + 2230 + private void SingleDomainWarpBasicGrid(int seed, float warpAmp, float frequency, FNLfloat x, FNLfloat y, FNLfloat z, ref FNLfloat xr, ref FNLfloat yr, ref FNLfloat zr) 2231 + { 2232 + FNLfloat xf = x * frequency; 2233 + FNLfloat yf = y * frequency; 2234 + FNLfloat zf = z * frequency; 2235 + 2236 + int x0 = FastFloor(xf); 2237 + int y0 = FastFloor(yf); 2238 + int z0 = FastFloor(zf); 2239 + 2240 + float xs = InterpHermite((float)(xf - x0)); 2241 + float ys = InterpHermite((float)(yf - y0)); 2242 + float zs = InterpHermite((float)(zf - z0)); 2243 + 2244 + x0 *= PrimeX; 2245 + y0 *= PrimeY; 2246 + z0 *= PrimeZ; 2247 + int x1 = x0 + PrimeX; 2248 + int y1 = y0 + PrimeY; 2249 + int z1 = z0 + PrimeZ; 2250 + 2251 + int hash0 = Hash(seed, x0, y0, z0) & (255 << 2); 2252 + int hash1 = Hash(seed, x1, y0, z0) & (255 << 2); 2253 + 2254 + float lx0x = Lerp(RandVecs3D[hash0], RandVecs3D[hash1], xs); 2255 + float ly0x = Lerp(RandVecs3D[hash0 | 1], RandVecs3D[hash1 | 1], xs); 2256 + float lz0x = Lerp(RandVecs3D[hash0 | 2], RandVecs3D[hash1 | 2], xs); 2257 + 2258 + hash0 = Hash(seed, x0, y1, z0) & (255 << 2); 2259 + hash1 = Hash(seed, x1, y1, z0) & (255 << 2); 2260 + 2261 + float lx1x = Lerp(RandVecs3D[hash0], RandVecs3D[hash1], xs); 2262 + float ly1x = Lerp(RandVecs3D[hash0 | 1], RandVecs3D[hash1 | 1], xs); 2263 + float lz1x = Lerp(RandVecs3D[hash0 | 2], RandVecs3D[hash1 | 2], xs); 2264 + 2265 + float lx0y = Lerp(lx0x, lx1x, ys); 2266 + float ly0y = Lerp(ly0x, ly1x, ys); 2267 + float lz0y = Lerp(lz0x, lz1x, ys); 2268 + 2269 + hash0 = Hash(seed, x0, y0, z1) & (255 << 2); 2270 + hash1 = Hash(seed, x1, y0, z1) & (255 << 2); 2271 + 2272 + lx0x = Lerp(RandVecs3D[hash0], RandVecs3D[hash1], xs); 2273 + ly0x = Lerp(RandVecs3D[hash0 | 1], RandVecs3D[hash1 | 1], xs); 2274 + lz0x = Lerp(RandVecs3D[hash0 | 2], RandVecs3D[hash1 | 2], xs); 2275 + 2276 + hash0 = Hash(seed, x0, y1, z1) & (255 << 2); 2277 + hash1 = Hash(seed, x1, y1, z1) & (255 << 2); 2278 + 2279 + lx1x = Lerp(RandVecs3D[hash0], RandVecs3D[hash1], xs); 2280 + ly1x = Lerp(RandVecs3D[hash0 | 1], RandVecs3D[hash1 | 1], xs); 2281 + lz1x = Lerp(RandVecs3D[hash0 | 2], RandVecs3D[hash1 | 2], xs); 2282 + 2283 + xr += Lerp(lx0y, Lerp(lx0x, lx1x, ys), zs) * warpAmp; 2284 + yr += Lerp(ly0y, Lerp(ly0x, ly1x, ys), zs) * warpAmp; 2285 + zr += Lerp(lz0y, Lerp(lz0x, lz1x, ys), zs) * warpAmp; 2286 + } 2287 + 2288 + 2289 + // Domain Warp Simplex/OpenSimplex2 2290 + private void SingleDomainWarpSimplexGradient(int seed, float warpAmp, float frequency, FNLfloat x, FNLfloat y, ref FNLfloat xr, ref FNLfloat yr, bool outGradOnly) 2291 + { 2292 + const float SQRT3 = 1.7320508075688772935274463415059f; 2293 + const float G2 = (3 - SQRT3) / 6; 2294 + 2295 + x *= frequency; 2296 + y *= frequency; 2297 + 2298 + /* 2299 + * --- Skew moved to TransformNoiseCoordinate method --- 2300 + * const FNfloat F2 = 0.5f * (SQRT3 - 1); 2301 + * FNfloat s = (x + y) * F2; 2302 + * x += s; y += s; 2303 + */ 2304 + 2305 + int i = FastFloor(x); 2306 + int j = FastFloor(y); 2307 + float xi = (float)(x - i); 2308 + float yi = (float)(y - j); 2309 + 2310 + float t = (xi + yi) * G2; 2311 + float x0 = (float)(xi - t); 2312 + float y0 = (float)(yi - t); 2313 + 2314 + i *= PrimeX; 2315 + j *= PrimeY; 2316 + 2317 + float vx, vy; 2318 + vx = vy = 0; 2319 + 2320 + float a = 0.5f - x0 * x0 - y0 * y0; 2321 + if (a > 0) 2322 + { 2323 + float aaaa = (a * a) * (a * a); 2324 + float xo, yo; 2325 + if (outGradOnly) 2326 + GradCoordOut(seed, i, j, out xo, out yo); 2327 + else 2328 + GradCoordDual(seed, i, j, x0, y0, out xo, out yo); 2329 + vx += aaaa * xo; 2330 + vy += aaaa * yo; 2331 + } 2332 + 2333 + float c = (float)(2 * (1 - 2 * G2) * (1 / G2 - 2)) * t + ((float)(-2 * (1 - 2 * G2) * (1 - 2 * G2)) + a); 2334 + if (c > 0) 2335 + { 2336 + float x2 = x0 + (2 * (float)G2 - 1); 2337 + float y2 = y0 + (2 * (float)G2 - 1); 2338 + float cccc = (c * c) * (c * c); 2339 + float xo, yo; 2340 + if (outGradOnly) 2341 + GradCoordOut(seed, i + PrimeX, j + PrimeY, out xo, out yo); 2342 + else 2343 + GradCoordDual(seed, i + PrimeX, j + PrimeY, x2, y2, out xo, out yo); 2344 + vx += cccc * xo; 2345 + vy += cccc * yo; 2346 + } 2347 + 2348 + if (y0 > x0) 2349 + { 2350 + float x1 = x0 + (float)G2; 2351 + float y1 = y0 + ((float)G2 - 1); 2352 + float b = 0.5f - x1 * x1 - y1 * y1; 2353 + if (b > 0) 2354 + { 2355 + float bbbb = (b * b) * (b * b); 2356 + float xo, yo; 2357 + if (outGradOnly) 2358 + GradCoordOut(seed, i, j + PrimeY, out xo, out yo); 2359 + else 2360 + GradCoordDual(seed, i, j + PrimeY, x1, y1, out xo, out yo); 2361 + vx += bbbb * xo; 2362 + vy += bbbb * yo; 2363 + } 2364 + } 2365 + else 2366 + { 2367 + float x1 = x0 + ((float)G2 - 1); 2368 + float y1 = y0 + (float)G2; 2369 + float b = 0.5f - x1 * x1 - y1 * y1; 2370 + if (b > 0) 2371 + { 2372 + float bbbb = (b * b) * (b * b); 2373 + float xo, yo; 2374 + if (outGradOnly) 2375 + GradCoordOut(seed, i + PrimeX, j, out xo, out yo); 2376 + else 2377 + GradCoordDual(seed, i + PrimeX, j, x1, y1, out xo, out yo); 2378 + vx += bbbb * xo; 2379 + vy += bbbb * yo; 2380 + } 2381 + } 2382 + 2383 + xr += vx * warpAmp; 2384 + yr += vy * warpAmp; 2385 + } 2386 + 2387 + private void SingleDomainWarpOpenSimplex2Gradient(int seed, float warpAmp, float frequency, FNLfloat x, FNLfloat y, FNLfloat z, ref FNLfloat xr, ref FNLfloat yr, ref FNLfloat zr, bool outGradOnly) 2388 + { 2389 + x *= frequency; 2390 + y *= frequency; 2391 + z *= frequency; 2392 + 2393 + /* 2394 + * --- Rotation moved to TransformDomainWarpCoordinate method --- 2395 + * const FNfloat R3 = (FNfloat)(2.0 / 3.0); 2396 + * FNfloat r = (x + y + z) * R3; // Rotation, not skew 2397 + * x = r - x; y = r - y; z = r - z; 2398 + */ 2399 + 2400 + int i = FastRound(x); 2401 + int j = FastRound(y); 2402 + int k = FastRound(z); 2403 + float x0 = (float)x - i; 2404 + float y0 = (float)y - j; 2405 + float z0 = (float)z - k; 2406 + 2407 + int xNSign = (int)(-x0 - 1.0f) | 1; 2408 + int yNSign = (int)(-y0 - 1.0f) | 1; 2409 + int zNSign = (int)(-z0 - 1.0f) | 1; 2410 + 2411 + float ax0 = xNSign * -x0; 2412 + float ay0 = yNSign * -y0; 2413 + float az0 = zNSign * -z0; 2414 + 2415 + i *= PrimeX; 2416 + j *= PrimeY; 2417 + k *= PrimeZ; 2418 + 2419 + float vx, vy, vz; 2420 + vx = vy = vz = 0; 2421 + 2422 + float a = (0.6f - x0 * x0) - (y0 * y0 + z0 * z0); 2423 + for (int l = 0; ; l++) 2424 + { 2425 + if (a > 0) 2426 + { 2427 + float aaaa = (a * a) * (a * a); 2428 + float xo, yo, zo; 2429 + if (outGradOnly) 2430 + GradCoordOut(seed, i, j, k, out xo, out yo, out zo); 2431 + else 2432 + GradCoordDual(seed, i, j, k, x0, y0, z0, out xo, out yo, out zo); 2433 + vx += aaaa * xo; 2434 + vy += aaaa * yo; 2435 + vz += aaaa * zo; 2436 + } 2437 + 2438 + float b = a; 2439 + int i1 = i; 2440 + int j1 = j; 2441 + int k1 = k; 2442 + float x1 = x0; 2443 + float y1 = y0; 2444 + float z1 = z0; 2445 + 2446 + if (ax0 >= ay0 && ax0 >= az0) 2447 + { 2448 + x1 += xNSign; 2449 + b = b + ax0 + ax0; 2450 + i1 -= xNSign * PrimeX; 2451 + } 2452 + else if (ay0 > ax0 && ay0 >= az0) 2453 + { 2454 + y1 += yNSign; 2455 + b = b + ay0 + ay0; 2456 + j1 -= yNSign * PrimeY; 2457 + } 2458 + else 2459 + { 2460 + z1 += zNSign; 2461 + b = b + az0 + az0; 2462 + k1 -= zNSign * PrimeZ; 2463 + } 2464 + 2465 + if (b > 1) 2466 + { 2467 + b -= 1; 2468 + float bbbb = (b * b) * (b * b); 2469 + float xo, yo, zo; 2470 + if (outGradOnly) 2471 + GradCoordOut(seed, i1, j1, k1, out xo, out yo, out zo); 2472 + else 2473 + GradCoordDual(seed, i1, j1, k1, x1, y1, z1, out xo, out yo, out zo); 2474 + vx += bbbb * xo; 2475 + vy += bbbb * yo; 2476 + vz += bbbb * zo; 2477 + } 2478 + 2479 + if (l == 1) break; 2480 + 2481 + ax0 = 0.5f - ax0; 2482 + ay0 = 0.5f - ay0; 2483 + az0 = 0.5f - az0; 2484 + 2485 + x0 = xNSign * ax0; 2486 + y0 = yNSign * ay0; 2487 + z0 = zNSign * az0; 2488 + 2489 + a += (0.75f - ax0) - (ay0 + az0); 2490 + 2491 + i += (xNSign >> 1) & PrimeX; 2492 + j += (yNSign >> 1) & PrimeY; 2493 + k += (zNSign >> 1) & PrimeZ; 2494 + 2495 + xNSign = -xNSign; 2496 + yNSign = -yNSign; 2497 + zNSign = -zNSign; 2498 + 2499 + seed += 1293373; 2500 + } 2501 + 2502 + xr += vx * warpAmp; 2503 + yr += vy * warpAmp; 2504 + zr += vz * warpAmp; 2505 + } 2506 + }
+25
Electropunk/Misc/DateHelper.cs
··· 1 + namespace Electropunk.Misc; 2 + 3 + public static class DateHelper 4 + { 5 + public static bool IsDate(Month month, int day) 6 + { 7 + return DateTime.Now.Month == (int)month && DateTime.Now.Day == day; 8 + } 9 + } 10 + 11 + public enum Month 12 + { 13 + Jan = 1, 14 + Feb = 2, 15 + Mar = 3, 16 + Apr = 4, 17 + May = 5, 18 + Jun = 6, 19 + Jul = 7, 20 + Aug = 8, 21 + Sep = 9, 22 + Oct = 10, 23 + Nov = 11, 24 + Dec = 12, 25 + }
+13
Electropunk/Misc/Ref.cs
··· 1 + namespace Electropunk.Misc; 2 + 3 + public class Ref<T>(Func<T> getter, Action<T> setter) 4 + { 5 + private readonly Func<T> _getter = getter; 6 + private readonly Action<T> _setter = setter; 7 + 8 + public T Value 9 + { 10 + get => _getter(); 11 + set => _setter(value); 12 + } 13 + }
+130
Electropunk/Program.cs
··· 1 + using System.Numerics; 2 + using Electropunk.Containers; 3 + using Electropunk.Content.Biomes; 4 + using Electropunk.Content.Entities; 5 + using Electropunk.Content.Generators; 6 + using Electropunk.Content.Items; 7 + using Electropunk.Content.Tiles; 8 + using Electropunk.Content.UI; 9 + using Electropunk.Input; 10 + using Electropunk.Misc; 11 + using Electropunk.UI; 12 + using Electropunk.World; 13 + using Electropunk.World.Crafting; 14 + using Raylib_cs; 15 + 16 + namespace Electropunk; 17 + 18 + public static class Program 19 + { 20 + public static View View { get; set; } = new(); 21 + 22 + public static float DeltaTime 23 + { 24 + get => Raylib.GetFrameTime() * 1000; 25 + private set { } 26 + } 27 + 28 + public static Level? Level { get; set; } 29 + public static EntityPlayer? Player { get; set; } 30 + public static ItemInstance MouseItem { get; set; } = new(GameItems.Air); 31 + 32 + public static UINode? Menu { get; set; } 33 + public static UINode RootUI { get; private set; } = new(0, 0); 34 + 35 + public static Random Rand { get; set; } = new(); 36 + 37 + public static bool UseBorderlessFullscreen { get; set; } = true; 38 + 39 + private static Texture2D Cursor; 40 + private static float CursorRotation = 0; 41 + 42 + 43 + public static void Main() 44 + { 45 + Raylib.SetTargetFPS(60); 46 + Raylib.InitWindow(800, 600, "Electropunk"); 47 + Raylib.HideCursor(); 48 + // Raylib.SetExitKey(KeyboardKey.Null); 49 + 50 + Cursor = Raylib.LoadTexture("Assets/UI/cursor.png"); 51 + 52 + GameBiomes.NoOp(); 53 + GameTiles.NoOp(); 54 + 55 + RecipeTileSmashing.Load("Data/Crafting/tile_smashing.kdl"); 56 + RecipeItemSmashing.Load("Data/Crafting/item_smashing.kdl"); 57 + 58 + RootUI.AddChild(p => new UISelection(p)); 59 + RootUI.AddChild(p => new UIFps(0, 0, p)); 60 + /* November 5 - Jim's Birthday */ 61 + if (new Random().Next(1_000_000) == 1 || DateHelper.IsDate(Month.Nov, 5)) 62 + RootUI.AddChild(p => new UIJim(p)); 63 + 64 + int size = 1_000; 65 + Level = new(size, size); 66 + Level.Generate(new BasicLevelGenerator()); 67 + Vector2 centre = new(size / 2 * View.TileSize, size / 2 * View.TileSize); 68 + Player = new EntityPlayer() { Pos = centre }; 69 + View.Camera.Target = centre; 70 + View.Camera.Zoom = 1.5f; 71 + Level.AddEntity(Player); 72 + 73 + RootUI.AddChild(p => new UIInvPreview(Player.Inv, p)); 74 + 75 + while (!Raylib.WindowShouldClose()) 76 + { 77 + if (Bindings.ToggleFullscreen.IsPressed()) 78 + { 79 + if (UseBorderlessFullscreen) 80 + Raylib.ToggleBorderlessWindowed(); 81 + else 82 + Raylib.ToggleFullscreen(); 83 + } 84 + else if (Bindings.ZoomOut.IsPressed() && View.GoalZoom > 1.00f) 85 + View.GoalZoom -= 0.25f; 86 + else if (Bindings.ZoomIn.IsPressed() && View.GoalZoom < 3.00f) 87 + View.GoalZoom += 0.25f; 88 + else if (Bindings.ResetZoom.IsPressed()) 89 + View.GoalZoom = 2f; 90 + else if (Raylib.IsKeyPressed(KeyboardKey.Eight)) 91 + View.GoalZoom = 0.1f; 92 + else if (Bindings.OpenInventory.IsPressed()) 93 + { 94 + if (Menu == null) 95 + Menu = new MenuInventory(Player.Inv); 96 + else 97 + Menu = null; 98 + } 99 + 100 + Level.Update(); 101 + RootUI.Update(); 102 + Menu?.Update(); 103 + 104 + Raylib.BeginDrawing(); 105 + { 106 + Level.Render(View); 107 + 108 + RootUI.Render(); 109 + Menu?.Render(); 110 + 111 + RootUI.RenderHoverBox(); 112 + Menu?.RenderHoverBox(); 113 + 114 + Vector2 delta = Raylib.GetMouseDelta(); 115 + if ((delta.X > 0 || delta.Y > 0) && CursorRotation < 30) 116 + CursorRotation += 2; 117 + else if ((delta.X < 0 || delta.Y < 0) && CursorRotation > -30) 118 + CursorRotation -= 2; 119 + CursorRotation = Raymath.LerpAngle(CursorRotation, 0, 0.2f); 120 + Raylib.DrawTextureEx(Cursor, Raylib.GetMousePosition(), CursorRotation, 2f, Color.White); 121 + 122 + if (!MouseItem.IsEmpty()) 123 + MouseItem.Item.Render(Level, View, new(Raylib.GetMouseX(), Raylib.GetMouseY(), 32, 32)); 124 + } 125 + Raylib.EndDrawing(); 126 + 127 + View.Update(); 128 + } 129 + } 130 + }
+13
Electropunk/UI/UIFps.cs
··· 1 + using Raylib_cs; 2 + 3 + namespace Electropunk.UI; 4 + 5 + public class UIFps(int x, int y, UINode parent) : UINode(x, y, parent) 6 + { 7 + public override void Render() 8 + { 9 + Raylib.DrawFPS(RelativeX, RelativeY); 10 + Raylib.DrawText($"Entities: {Program.Level!.GetEntities().Count}", RelativeX, RelativeY + 20, 20, Color.White); 11 + base.Render(); 12 + } 13 + }
+36
Electropunk/UI/UIInvPreview.cs
··· 1 + using Electropunk.Content.Entities; 2 + using Raylib_cs; 3 + 4 + namespace Electropunk.UI; 5 + 6 + public class UIInvPreview : UINode 7 + { 8 + public static readonly int Scale = 2; 9 + 10 + public UIInvPreview(EntityPlayer.PlayerInventory inv, UINode? parent = null) : base(0, 0, parent) 11 + { 12 + int padding = 4; 13 + 14 + Width = (32 + padding * 2) * Scale; 15 + Height = (16 + padding * 2) * Scale; 16 + 17 + AddChild(new UIItemSlot(inv.GetSlot(2)!, padding * Scale, padding * Scale, this) { Width = 16 * Scale, Height = 16 * Scale }); 18 + AddChild(new UIItemSlot(inv.GetSlot(3)!, (padding + 16) * Scale, padding * Scale, this) { Width = 16 * Scale, Height = 16 * Scale }); 19 + 20 + Reposition(); 21 + } 22 + 23 + public override void Render() 24 + { 25 + Raylib.DrawRectangleRec(GetRectangle(), Color.DarkBlue); 26 + Raylib.DrawRectangleLinesEx(GetRectangle(), 2f, Color.Blue); 27 + 28 + base.Render(); 29 + } 30 + 31 + public override void Reposition() 32 + { 33 + LocalX = Raylib.GetScreenWidth() / 2 - Width / 2; 34 + LocalY = Raylib.GetScreenHeight() - Height - 8; 35 + } 36 + }
+85
Electropunk/UI/UIItemSlot.cs
··· 1 + using Electropunk.Containers; 2 + using Electropunk.I18n; 3 + using Raylib_cs; 4 + 5 + namespace Electropunk.UI; 6 + 7 + public class UIItemSlot : UINode 8 + { 9 + public Slot Item; 10 + public bool RenderSlot = true; 11 + 12 + public UIItemSlot(Slot item, int x, int y, UINode? parent = null) : base(x, y, parent) 13 + { 14 + Item = item; 15 + Width = 16; 16 + Height = 16; 17 + } 18 + 19 + public override void Update() 20 + { 21 + if (IsClicked() && (Program.MouseItem.IsSomething() || Item.IsSomething())) 22 + { 23 + if (Program.MouseItem.IsSomething() && Item.IsSomething()) 24 + { 25 + (Program.MouseItem, Item.Value) = (Item.Value, Program.MouseItem); 26 + } 27 + if (Program.MouseItem.IsEmpty()) 28 + { 29 + Program.MouseItem = Item.Copy(); 30 + Item.Clear(); 31 + } 32 + else if (Item.IsEmpty()) 33 + { 34 + Item.SetItem(Program.MouseItem.Copy()); 35 + Program.MouseItem.Clear(); 36 + } 37 + } 38 + 39 + base.Update(); 40 + } 41 + 42 + public override void Render() 43 + { 44 + if (RenderSlot) 45 + { 46 + Raylib.DrawRectangleRec(GetRectangle(), Color.Blue); 47 + Raylib.DrawRectangleLinesEx(GetRectangle(), 2f, Color.SkyBlue); 48 + } 49 + 50 + if (Item.IsSomething()) 51 + Item.Item.Render( 52 + Program.Level!, 53 + Program.View, 54 + new(RelativeX, RelativeY, Width, Height) 55 + ); 56 + 57 + base.Render(); 58 + } 59 + 60 + public override bool RenderHoverBox() 61 + { 62 + if (IsHovered() && Item.IsSomething()) 63 + { 64 + string name = Lang.T($"item.{Item.Item.Key}"); 65 + Lang.TE($"item.{Item.Item.Key}.desc", out string? desc); 66 + 67 + Rectangle rect = new( 68 + Raylib.GetMouseX() + 8, 69 + Raylib.GetMouseY() + 8, 70 + Math.Max(Raylib.MeasureText(name, 20), desc != null ? Raylib.MeasureText(desc, 20) : 0) + 16, 71 + 20 + (desc != null ? 20 : 0) + 16 72 + ); 73 + Raylib.DrawRectangleRec(rect, Color.Blue); 74 + Raylib.DrawRectangleLinesEx(rect, 2f, Color.SkyBlue); 75 + 76 + Raylib.DrawText(name, (int)rect.X + 8, (int)rect.Y + 8, 20, Color.White); 77 + if (desc != null) 78 + Raylib.DrawText(desc, (int)rect.X + 8, (int)rect.Y + 28, 20, Color.White); 79 + 80 + return true; 81 + } 82 + 83 + return base.RenderHoverBox(); 84 + } 85 + }
+29
Electropunk/UI/UIJim.cs
··· 1 + using System.Numerics; 2 + using Raylib_cs; 3 + 4 + namespace Electropunk.UI; 5 + 6 + /* Jim was drawn by Collie as a joke on the Wand.png 7 + texture. I decided it make it a UI element because it's 8 + silly. */ 9 + public class UIJim(UINode? parent = null) : UINode(0, 0, parent) 10 + { 11 + private static readonly Texture2D Jim = Raylib.LoadTexture("Assets/UI/jim.png"); 12 + 13 + private int i = 0; 14 + private Vector2 pos = Vector2.Zero; 15 + 16 + public override void Update() 17 + { 18 + pos = Vector2.Lerp(pos, Raylib.GetMousePosition(), 0.2f); 19 + 20 + base.Update(); 21 + } 22 + 23 + public override void Render() 24 + { 25 + Raylib.DrawTexturePro(Jim, new(0, 0, Jim.Width, Jim.Height), new(pos.X, pos.Y, Jim.Width * 2, Jim.Height * 2), new(Jim.Width, Jim.Height), i++, Color.White); 26 + 27 + base.Render(); 28 + } 29 + }
+82
Electropunk/UI/UINode.cs
··· 1 + using Electropunk.Input; 2 + using Raylib_cs; 3 + 4 + namespace Electropunk.UI; 5 + 6 + public class UINode 7 + { 8 + protected List<UINode> Children = []; 9 + protected UINode? Parent; 10 + 11 + public int LocalX, LocalY; 12 + public int Width = 0, Height = 0; 13 + public bool Visible = true; 14 + 15 + public int RelativeX 16 + { 17 + get => (Parent?.RelativeX ?? 0) + LocalX; 18 + } 19 + 20 + public int RelativeY 21 + { 22 + get => (Parent?.RelativeY ?? 0) + LocalY; 23 + } 24 + 25 + public UINode(int x, int y, UINode? parent = null) 26 + { 27 + LocalX = x; 28 + LocalY = y; 29 + Parent = parent; 30 + 31 + Reposition(); 32 + } 33 + 34 + public Rectangle GetRectangle() => new(RelativeX, RelativeY, Width, Height); 35 + 36 + public bool IsHovered() => Raylib.CheckCollisionPointRec(Raylib.GetMousePosition(), GetRectangle()); 37 + public bool IsClicked() => Bindings.UIClick.IsPressed() && IsHovered(); 38 + 39 + public void AddChild(UINode node) 40 + { 41 + Children.Add(node); 42 + node.Parent = this; 43 + } 44 + 45 + public void AddChild(Func<UINode, UINode> node) => Children.Add(node(this)); 46 + 47 + public virtual void Reposition() 48 + { } 49 + 50 + public virtual void Update() 51 + { 52 + if (Raylib.IsWindowResized()) 53 + Reposition(); 54 + 55 + if (!Visible) 56 + return; 57 + 58 + foreach (UINode node in Children) 59 + node.Update(); 60 + } 61 + 62 + public virtual void Render() 63 + { 64 + if (!Visible) 65 + return; 66 + 67 + foreach (UINode node in Children) 68 + node.Render(); 69 + } 70 + 71 + public virtual bool RenderHoverBox() 72 + { 73 + if (!Visible) 74 + return false; 75 + 76 + foreach (UINode node in Children) 77 + if (node.RenderHoverBox()) 78 + return true; 79 + 80 + return false; 81 + } 82 + }
+44
Electropunk/UI/UISelection.cs
··· 1 + using System.Numerics; 2 + using Electropunk.Content.Entities; 3 + using Electropunk.Content.Tiles; 4 + using Electropunk.World; 5 + using Raylib_cs; 6 + 7 + namespace Electropunk.UI; 8 + 9 + public class UISelection(UINode parent) : UINode(0, 0, parent) 10 + { 11 + private Texture2D Texture = Raylib.LoadTexture("Assets/UI/select.png"); 12 + 13 + public override void Render() 14 + { 15 + if (Program.Level == null) 16 + goto done; 17 + 18 + /* Check for an item */ 19 + Entity? e = Program.Level.GetSelectedEntity(Program.View); 20 + if (e != null && e is EntityItem) 21 + { 22 + Raylib.BeginMode2D(Program.View.Camera); 23 + Raylib.DrawTextureEx(Texture, new(e.Pos.X - e.Width / 2f, e.Pos.Y - e.Height / 2f), 0, 1, Color.White); 24 + Raylib.EndMode2D(); 25 + goto done; 26 + } 27 + 28 + /* Check for a tile */ 29 + (int x, int y) = Program.Level.GetSelectedTile(Program.View) ?? (-1, -1); 30 + if (x == -1 || y == -1) 31 + goto done; 32 + 33 + if (Program.Level.GetTileIDAt(x, y) != GameTiles.Air.ID) 34 + { 35 + Vector2 pos = View.LevelPosToWorldPos(x, y); 36 + Raylib.BeginMode2D(Program.View.Camera); 37 + Raylib.DrawTextureEx(Texture, pos, 0, 1, Color.White); 38 + Raylib.EndMode2D(); 39 + } 40 + 41 + done: /* OH NOOOOOO; BAD PRACTICE!!! yeah no, i dont care. code is code. */ 42 + base.Render(); 43 + } 44 + }
+38
Electropunk/World/Biome.cs
··· 1 + using System.Numerics; 2 + using Raylib_cs; 3 + 4 + namespace Electropunk.World; 5 + 6 + public class Biome(string key) 7 + { 8 + public const int MaxBiomes = 1024; 9 + 10 + private static ushort _nextBiomeID = 0; 11 + public static Biome[] Biomes { get; private set; } = new Biome[MaxBiomes]; 12 + 13 + public ushort ID { get; private set; } 14 + public bool Visible { get; set; } = true; 15 + 16 + public Texture2D Texture = Raylib.LoadTexture($"Assets/Biomes/{key}.png"); 17 + 18 + public virtual void Render(Level level, View view, int levelX, int levelY) 19 + { 20 + if (level.Step != RenderStep.Biomes) 21 + return; 22 + 23 + Vector2 pos = View.LevelPosToWorldPos(levelX, levelY); 24 + Raylib.DrawTextureEx(Texture, pos, 0, 1, Color.White); 25 + } 26 + 27 + public Biome Register() 28 + { 29 + return Register(this); 30 + } 31 + 32 + public static Biome Register(Biome biome) 33 + { 34 + biome.ID = _nextBiomeID++; 35 + Biomes[biome.ID] = biome; 36 + return biome; 37 + } 38 + }
+69
Electropunk/World/Crafting/RecipeItemSmashing.cs
··· 1 + using System.Numerics; 2 + using Electropunk.Containers; 3 + using Electropunk.Content.Entities; 4 + using Electropunk.Content.Tiles; 5 + using Kadlet; 6 + 7 + namespace Electropunk.World.Crafting; 8 + 9 + public class RecipeItemSmashing(ushort inputItemID, List<ItemInstance> results) 10 + { 11 + public static readonly List<RecipeItemSmashing> Recipes = []; 12 + 13 + public bool Matches(EntityItem entity) => entity.Item.Matches(inputItemID); 14 + 15 + public bool Craft(Level level, EntityItem entity) 16 + { 17 + if (!Matches(entity)) 18 + return false; 19 + 20 + foreach (ItemInstance item in results) 21 + level.EnqueueEntity(new EntityItem() { 22 + Item = item.Copy(), 23 + Pos = entity.Pos + new Vector2(Program.Rand.Next(-4, 4), Program.Rand.Next(-4, 4)) 24 + }); 25 + 26 + entity.Dead = true; 27 + 28 + return true; 29 + } 30 + 31 + public static RecipeItemSmashing? GetRecipe(EntityItem entity) 32 + { 33 + foreach (RecipeItemSmashing recipe in Recipes) 34 + if (recipe.Matches(entity)) 35 + return recipe; 36 + return null; 37 + } 38 + 39 + public static bool TryCraft(Level level, EntityItem entity) 40 + { 41 + var r = GetRecipe(entity); 42 + if (r == null) 43 + return false; 44 + return r!.Craft(level, entity); 45 + } 46 + 47 + public static void Load(string filepath) 48 + { 49 + KdlReader reader = new(new KdlReaderOptions()); 50 + using FileStream fs = File.OpenRead(filepath); 51 + KdlDocument doc = reader.Parse(fs); 52 + 53 + foreach (var node in doc.Nodes) 54 + { 55 + ushort inputTileID = GameTiles.Air.ID; 56 + List<ItemInstance> results = []; 57 + foreach (var child in node.Children!.Nodes) 58 + { 59 + if (child.Identifier == "in") 60 + inputTileID = Item.FindByKey(child.Arguments[0].ToKdlString().Trim('\'', '"'))!.ID; 61 + else if (child.Identifier == "out") 62 + results.Add(new(Item.FindByKey(child.Arguments[0].ToKdlString().Trim('\'', '"'))!)); 63 + else 64 + throw new($"Unexpected key: {child.Identifier}"); 65 + } 66 + Recipes.Add(new(inputTileID, results)); 67 + } 68 + } 69 + }
+75
Electropunk/World/Crafting/RecipeTileSmashing.cs
··· 1 + using System.Numerics; 2 + using Electropunk.Containers; 3 + using Electropunk.Content.Entities; 4 + using Electropunk.Content.Tiles; 5 + using Kadlet; 6 + 7 + namespace Electropunk.World.Crafting; 8 + 9 + public class RecipeTileSmashing(ushort inputTileID, ushort outputTileID, List<ItemInstance> results) 10 + { 11 + public static readonly List<RecipeTileSmashing> Recipes = []; 12 + 13 + public bool Matches(Level level, int levelX, int levelY) => 14 + level.GetTileIDAt(levelX, levelY) == inputTileID; 15 + 16 + public bool Craft(Level level, int levelX, int levelY) 17 + { 18 + if (!Matches(level, levelX, levelY)) 19 + return false; 20 + 21 + level.SetTileIDAt(levelX, levelY, outputTileID); 22 + foreach (ItemInstance item in results) 23 + level.EnqueueEntity(new EntityItem() { 24 + Item = item.Copy(), 25 + Pos = 26 + View.LevelPosToWorldPos(levelX, levelY) + 27 + new Vector2(View.TileSize / 2, View.TileSize / 2) + 28 + new Vector2(Program.Rand.Next(-4, 4), Program.Rand.Next(-4, 4)) 29 + }); 30 + 31 + return true; 32 + } 33 + 34 + public static RecipeTileSmashing? GetRecipe(Level level, int levelX, int levelY) 35 + { 36 + foreach (RecipeTileSmashing recipe in Recipes) 37 + if (recipe.Matches(level, levelX, levelY)) 38 + return recipe; 39 + return null; 40 + } 41 + 42 + public static bool TryCraft(Level level, int levelX, int levelY) 43 + { 44 + var r = GetRecipe(level, levelX, levelY); 45 + if (r == null) 46 + return false; 47 + return r!.Craft(level, levelX, levelY); 48 + } 49 + 50 + public static void Load(string filepath) 51 + { 52 + KdlReader reader = new(new KdlReaderOptions()); 53 + using FileStream fs = File.OpenRead(filepath); 54 + KdlDocument doc = reader.Parse(fs); 55 + 56 + foreach (var node in doc.Nodes) 57 + { 58 + ushort inputTileID = GameTiles.Air.ID; 59 + ushort outputTileID = GameTiles.Air.ID; 60 + List<ItemInstance> results = []; 61 + foreach (var child in node.Children!.Nodes) 62 + { 63 + if (child.Identifier == "in") 64 + inputTileID = Tile.FindByKey(child.Arguments[0].ToKdlString().Trim('\'', '"'))!.ID; 65 + else if (child.Identifier == "out-tile") 66 + outputTileID = Tile.FindByKey(child.Arguments[0].ToKdlString().Trim('\'', '"'))!.ID; 67 + else if (child.Identifier == "out-item") 68 + results.Add(new(Item.FindByKey(child.Arguments[0].ToKdlString().Trim('\'', '"'))!)); 69 + else 70 + throw new($"Unexpected key: {child.Identifier}"); 71 + } 72 + Recipes.Add(new(inputTileID, outputTileID, results)); 73 + } 74 + } 75 + }
+52
Electropunk/World/Entity.cs
··· 1 + using System.Numerics; 2 + using Raylib_cs; 3 + 4 + namespace Electropunk.World; 5 + 6 + public class Entity 7 + { 8 + public Vector2 Pos = Vector2.Zero, Vel = Vector2.Zero; 9 + public float Speed = 0.100f; 10 + public bool Dead = false; 11 + public float Width = 0, Height = 0; 12 + public MovementMode MoveMode = MovementMode.Default; 13 + public RenderStep Step = RenderStep.Entities; 14 + public bool Selectable = true; 15 + 16 + public Rectangle GetRectangle() => new(Pos.X - Width / 2, Pos.Y - Height / 2, Width, Height); 17 + 18 + public bool IsVisible(View view) => Raylib.CheckCollisionRecs(GetRectangle(), view.GetWorldBoundsRec()); 19 + 20 + public bool CanMoveInDirection(Level level, Vector2 direction) 21 + { 22 + Rectangle rect = GetRectangle(); 23 + rect.X += direction.X; 24 + rect.Y += direction.Y; 25 + 26 + /* Get a range of tiles to check */ 27 + int sx = (int)Math.Max(Math.Floor(rect.X / View.TileSize), 0); 28 + int sy = (int)Math.Max(Math.Floor(rect.Y / View.TileSize), 0); 29 + int ex = (int)Math.Min(Math.Max(rect.Width, View.TileSize) + sx, level.Width); 30 + int ey = (int)Math.Min(Math.Max(rect.Height, View.TileSize) + sy, level.Height); 31 + 32 + /* Check if any tiles will collide with the future rect */ 33 + Tile tile; 34 + for (int x = sx; x <= ex; x++) 35 + for (int y = sy; y <= ey; y++) 36 + { 37 + tile = level.GetTileAt(x, y); 38 + if (tile.Collides && Raylib.CheckCollisionRecs(tile.GetRectangle(level, x, y), rect)) 39 + return false; /* We're colliding with a tile */ 40 + } 41 + 42 + return true; 43 + } 44 + 45 + public virtual void Update(Level level) 46 + { 47 + MoveMode.Move(level, this); 48 + } 49 + 50 + public virtual void Render(Level level, View view) 51 + { } 52 + }
+63
Electropunk/World/Item.cs
··· 1 + using System.Numerics; 2 + using Electropunk.Containers; 3 + using Electropunk.Content.Entities; 4 + using Electropunk.Graphics; 5 + using Raylib_cs; 6 + 7 + namespace Electropunk.World; 8 + 9 + public class Item(string key) 10 + { 11 + public const int MaxItems = 2048; 12 + 13 + private static ushort _nextItemID = 0; 14 + public static Item[] Items { get; private set; } = new Item[MaxItems]; 15 + 16 + public readonly string Key = key; 17 + public ushort ID { get; private set; } 18 + 19 + public Texture2D Texture = Raylib.LoadTexture($"Assets/Items/{key}.png"); 20 + 21 + public virtual void UseOnTile(Level level, EntityPlayer user, Slot item, int tileX, int tileY) 22 + { } 23 + 24 + public virtual void UseOnEntity(Level level, EntityPlayer user, Slot item, Entity target) 25 + { } 26 + 27 + public virtual void Render(Level level, View view, Rectangle dest, Vector2? origin = null, float rotation = 0, bool hFlip = false, bool vFlip = false) 28 + { 29 + Rectangle src = TextureUtil.GetSourceRect(Texture); 30 + if (hFlip) 31 + src.Width = -src.Width; 32 + if (vFlip) 33 + src.Height = -src.Height; 34 + Raylib.DrawTexturePro( 35 + Texture, 36 + src, 37 + dest, 38 + origin ?? Vector2.Zero, 39 + rotation, 40 + Color.White 41 + ); 42 + } 43 + 44 + public Item Register() 45 + { 46 + return Register(this); 47 + } 48 + 49 + public static Item Register(Item item) 50 + { 51 + item.ID = _nextItemID++; 52 + Items[item.ID] = item; 53 + return item; 54 + } 55 + 56 + public static Item? FindByKey(string key) 57 + { 58 + foreach (Item item in Items) 59 + if (item.Key == key) 60 + return item; 61 + return null; 62 + } 63 + }
+232
Electropunk/World/Level.cs
··· 1 + using System.Numerics; 2 + using Electropunk.Misc; 3 + using Raylib_cs; 4 + 5 + namespace Electropunk.World; 6 + 7 + public class Level(int width, int height) 8 + { 9 + public readonly int Width = width, Height = height; 10 + 11 + private readonly ushort[,] BiomeGrid = new ushort[width, height]; 12 + private readonly ushort[,] Grid = new ushort[width, height]; 13 + private readonly List<Entity> Entities = []; 14 + private readonly Queue<Entity> EntityQueue = []; 15 + private readonly Dictionary<(int x, int y), TileData> TileData = []; 16 + 17 + public RenderStep Step { get; private set; } = RenderStep.None; 18 + public Random Random { get; private set; } = new(); 19 + public ulong Frame { get; private set; } = 0; 20 + public ulong Tick { get; private set; } = 0; 21 + public const int FramesPerTick = 3; 22 + 23 + public bool RenderHitboxes { get; set; } = false; 24 + 25 + public ushort GetBiomeIDAt(int x, int y) => BiomeGrid[x, y]; 26 + public Biome GetBiomeAt(int x, int y) => Biome.Biomes[BiomeGrid[x, y]]; 27 + 28 + public ushort GetTileIDAt(int x, int y) => Grid[x, y]; 29 + public Tile GetTileAt(int x, int y) => Tile.Tiles[Grid[x, y]]; 30 + 31 + private void RawSetTileIDAt(int x, int y, ushort tileID) 32 + { 33 + if (HasTileDataAt(x, y)) 34 + RemoveTileDataAt(x, y); 35 + Grid[x, y] = tileID; 36 + } 37 + 38 + public void SetTileIDAt(int x, int y, ushort tileID) => RawSetTileIDAt(x, y, tileID); 39 + public void SetTileAt(int x, int y, Tile tile) => RawSetTileIDAt(x, y, tile.ID); 40 + 41 + public void PlaceTileIDAt(int x, int y, ushort tileID) => Tile.Tiles[tileID].Place(this, x, y); 42 + public void PlaceTileAt(int x, int y, Tile tile) => tile.Place(this, x, y); 43 + 44 + public Ref<T> GetTileDataAt<T>(int x, int y) where T : TileData => 45 + new(() => (T)TileData[(x, y)], v => TileData[(x, y)] = v); 46 + public void SetTileDataAt(int x, int y, TileData data) => TileData[(x, y)] = data; 47 + public void RemoveTileDataAt(int x, int y) => TileData.Remove((x, y)); 48 + public bool HasTileDataAt(int x, int y) => TileData.ContainsKey((x, y)); 49 + 50 + public List<Entity> GetEntities() => Entities; 51 + public void AddEntity(Entity entity) => Entities.Add(entity); 52 + public void EnqueueEntity(Entity entity) => EntityQueue.Enqueue(entity); 53 + 54 + public IEnumerable<Entity> GetVisibleEntities(View view) 55 + { 56 + foreach (Entity entity in Entities) 57 + { 58 + if (entity.IsVisible(view)) 59 + { 60 + yield return entity; 61 + } 62 + } 63 + } 64 + 65 + public IEnumerable<T> GetVisibleEntitiesOfType<T>(View view) 66 + { 67 + foreach (Entity entity in Entities) 68 + { 69 + if (entity is T t && entity.IsVisible(view)) 70 + { 71 + yield return t; 72 + } 73 + } 74 + } 75 + 76 + public (int x, int y)? GetSelectedTile(View view) 77 + { 78 + Vector2 pos = Raylib.GetScreenToWorld2D(Raylib.GetMousePosition(), view.Camera); 79 + int x = (int)Math.Floor(pos.X / View.TileSize); 80 + int y = (int)Math.Floor(pos.Y / View.TileSize); 81 + if (x < 0 || y < 0 || x >= Width || y >= Height) 82 + return null; 83 + else 84 + return (x, y); 85 + } 86 + 87 + public Entity? GetSelectedEntity(View view) 88 + { 89 + Vector2 m = Raylib.GetScreenToWorld2D(Raylib.GetMousePosition(), Program.View.Camera); /* mouse pos */ 90 + foreach (Entity entity in GetVisibleEntities(view)) 91 + { 92 + if (entity.Selectable && Raylib.CheckCollisionPointRec(m, entity.GetRectangle())) 93 + { 94 + return entity; 95 + } 96 + } 97 + return null; 98 + } 99 + 100 + public void Generate(LevelGenerator generator) 101 + { 102 + for (int y = 0; y < Width; y++) 103 + for (int x = 0; x < Height; x++) 104 + BiomeGrid[x, y] = generator.PickBiome(this, x, y).ID; 105 + 106 + for (int y = 0; y < Width; y++) 107 + for (int x = 0; x < Height; x++) 108 + Grid[x, y] = generator.Pick(this, Biome.Biomes[BiomeGrid[x, y]], x, y).ID; 109 + } 110 + 111 + public void Update() 112 + { 113 + Frame++; 114 + 115 + if (Frame % FramesPerTick == 0) 116 + { 117 + Tick++; 118 + 119 + for (int y = 0; y < Width; y++) 120 + for (int x = 0; x < Height; x++) 121 + if (GetTileAt(x, y).Updates) 122 + GetTileAt(x, y).Update(this, x, y); 123 + } 124 + 125 + while (EntityQueue.Count > 0) 126 + Entities.Add(EntityQueue.Dequeue()); 127 + 128 + foreach (Entity entity in Entities) 129 + entity.Update(this); 130 + 131 + Entities.RemoveAll(entity => entity.Dead); 132 + } 133 + 134 + public void Render(View view) 135 + { 136 + (Vector2 start, Vector2 end) = view.GetWorldBounds(); 137 + /* We render a few tiles out of bounds to band-aid fix an edge case: 138 + If we have a tile with a sprite larger than 16x16 (trees), they'll still get culled like default. 139 + Rendering a few excess tiles out "fixes" that. */ 140 + int excess = 3; 141 + int sx = Math.Max((int)((Math.Floor(start.X) / View.TileSize) - excess), 0); 142 + int sy = Math.Max((int)((Math.Floor(start.Y) / View.TileSize) - excess), 0); 143 + int ex = Math.Min((int)((Math.Ceiling(end.X) / View.TileSize) + excess), Width); 144 + int ey = Math.Min((int)((Math.Ceiling(end.Y) / View.TileSize) + excess), Height); 145 + 146 + Raylib.BeginMode2D(view.Camera); 147 + 148 + Step = RenderStep.None; 149 + /* This loop/switch tree ensures that if I add a render step in 150 + the future, I'll remember to add it here. */ 151 + while (Step != RenderStep.Done) 152 + { 153 + Step++; 154 + switch (Step) 155 + { 156 + case RenderStep.Sky: 157 + Raylib.EndMode2D(); 158 + RenderSky(view); 159 + Raylib.BeginMode2D(view.Camera); 160 + break; 161 + case RenderStep.Entities: 162 + case RenderStep.FlyingEntities: 163 + RenderEntities(view, start, end); 164 + break; 165 + case RenderStep.Particles: 166 + RenderParticles(view, start, end); 167 + break; 168 + case RenderStep.Biomes: 169 + RenderBiomes(view, sx, sy, ex, ey); 170 + break; 171 + case RenderStep.Tiles: 172 + case RenderStep.TilesAbove: 173 + RenderTiles(view, sx, sy, ex, ey); 174 + break; 175 + case RenderStep.Weather: 176 + RenderWeather(view); 177 + break; 178 + case RenderStep.Done: 179 + break; 180 + default: 181 + throw new($"Unhandled render step: {Step}"); 182 + } 183 + } 184 + 185 + Raylib.EndMode2D(); 186 + } 187 + 188 + private void RenderSky(View view) 189 + { 190 + Raylib.ClearBackground(Color.SkyBlue); 191 + } 192 + 193 + private void RenderBiomes(View view, int sx, int sy, int ex, int ey) 194 + { 195 + for (int y = sy; y < ey; y++) 196 + for (int x = sx; x < ex; x++) 197 + GetBiomeAt(x, y).Render(this, view, x, y); 198 + } 199 + 200 + private void RenderTiles(View view, int sx, int sy, int ex, int ey) 201 + { 202 + Tile tile; 203 + for (int y = sy; y < ey; y++) 204 + for (int x = sx; x < ex; x++) 205 + { 206 + tile = GetTileAt(x, y); 207 + tile.Render(this, view, x, y); 208 + if (RenderHitboxes && tile.Collides) 209 + Raylib.DrawRectangleLinesEx(tile.GetRectangle(this, x, y), 1f, Color.Black); 210 + } 211 + } 212 + 213 + private void RenderEntities(View view, Vector2 start, Vector2 end) 214 + { 215 + /* TODO: Cull */ 216 + foreach (Entity entity in Entities) 217 + { 218 + entity.Render(this, view); 219 + 220 + if (RenderHitboxes) 221 + Raylib.DrawRectangleLinesEx(entity.GetRectangle(), 1f, Color.Red); 222 + } 223 + } 224 + 225 + private void RenderParticles(View view, Vector2 start, Vector2 end) 226 + { 227 + } 228 + 229 + private void RenderWeather(View view) 230 + { 231 + } 232 + }
+8
Electropunk/World/LevelGenerator.cs
··· 1 + namespace Electropunk.World; 2 + 3 + public abstract class LevelGenerator 4 + { 5 + public abstract Biome PickBiome(Level level, int x, int y); 6 + 7 + public abstract Tile Pick(Level level, Biome biome, int x, int y); 8 + }
+48
Electropunk/World/MovementMode.cs
··· 1 + using System.Numerics; 2 + 3 + namespace Electropunk.World; 4 + 5 + public class MovementMode 6 + { 7 + public bool Frozen = false; 8 + public bool Collides = true; 9 + public float MinSpeed = 0.10f; 10 + public float Friction = 1.50f; 11 + public float SpeedMod = 0.00f; 12 + 13 + public void Move(Level level, Entity e) 14 + { 15 + if (Frozen) 16 + return; 17 + 18 + Vector2 delta = e.Vel * (e.Speed + SpeedMod) * Program.DeltaTime; 19 + 20 + if (Collides) 21 + { 22 + if (delta.X != 0 && !e.CanMoveInDirection(level, new(delta.X, 0))) 23 + delta.X = 0; 24 + if (delta.Y != 0 && !e.CanMoveInDirection(level, new(0, delta.Y))) 25 + delta.Y = 0; 26 + } 27 + 28 + e.Pos += delta; 29 + 30 + if (e.Vel.X > -MinSpeed && e.Vel.X < MinSpeed) 31 + e.Vel.X = 0; 32 + else if (e.Vel.X != 0) 33 + e.Vel.X /= Friction; 34 + 35 + if (e.Vel.Y > -MinSpeed && e.Vel.Y < MinSpeed) 36 + e.Vel.Y = 0; 37 + else if (e.Vel.Y != 0) 38 + e.Vel.Y /= Friction; 39 + } 40 + 41 + public static readonly MovementMode None = new() { Frozen = true }; 42 + public static readonly MovementMode Default = new(); 43 + public static readonly MovementMode Flying = new() { 44 + Collides = false, 45 + Friction = 1.05f, 46 + SpeedMod = 0.25f 47 + }; 48 + }
+15
Electropunk/World/RenderStep.cs
··· 1 + namespace Electropunk.World; 2 + 3 + public enum RenderStep 4 + { 5 + None, /* Sentinel */ 6 + Sky, /* Sky effects, such as clouds when you're on the edge of a floating island. */ 7 + Biomes, /* Biome tiles */ 8 + Tiles, /* Most tiles */ 9 + Entities, /* Entities */ 10 + Particles, /* Particles */ 11 + TilesAbove, /* Trees, large rocks, etc */ 12 + FlyingEntities, /* Birds, players with jetpacks, etc */ 13 + Weather, /* Cloud shadows, rain, puddles, snow cover, etc */ 14 + Done, /* Sentinel */ 15 + }
+109
Electropunk/World/Tile.cs
··· 1 + using System.Numerics; 2 + using Electropunk.Content.Entities; 3 + using Electropunk.Content.Tiles; 4 + using Raylib_cs; 5 + 6 + namespace Electropunk.World; 7 + 8 + public class Tile(string key) 9 + { 10 + public const int MaxTiles = 1024; 11 + 12 + private static ushort _nextTileID = 0; 13 + public static Tile[] Tiles { get; private set; } = new Tile[MaxTiles]; 14 + 15 + public readonly string Key = key; 16 + public ushort ID { get; private set; } 17 + 18 + public RenderStep RenderStep = RenderStep.Tiles; 19 + public Texture2D Texture = Raylib.LoadTexture($"Assets/Tiles/{key}.png"); 20 + public bool Collides = true; /* TODO: Make this a function */ 21 + public Rectangle? CollisionRect = null; 22 + public List<Item> Drops = []; 23 + public bool Updates = false; 24 + 25 + public virtual void Place(Level level, int x, int y) 26 + { 27 + level.SetTileAt(x, y, this); 28 + } 29 + 30 + public virtual void Remove(Level level, int x, int y) 31 + { 32 + level.SetTileAt(x, y, GameTiles.Air); 33 + } 34 + 35 + public virtual void Break(Level level, int x, int y) 36 + { 37 + Remove(level, x, y); 38 + 39 + foreach (Item item in Drops) 40 + level.EnqueueEntity(new EntityItem() { 41 + Item = new(item), 42 + Pos = 43 + View.LevelPosToWorldPos(x, y) + 44 + new Vector2(View.TileSize / 2, View.TileSize / 2) + 45 + new Vector2(Program.Rand.Next(-4, 4), Program.Rand.Next(-4, 4)) 46 + }); 47 + } 48 + 49 + public virtual void Use(Level level, int x, int y, EntityPlayer user) 50 + { } 51 + 52 + public virtual Rectangle GetRectangle(Level level, int x, int y) 53 + { 54 + Rectangle box = new(x * View.TileSize, y * View.TileSize, View.TileSize, View.TileSize); 55 + if (CollisionRect != null) 56 + { 57 + box.X += ((Rectangle)CollisionRect!).X; 58 + box.Y += ((Rectangle)CollisionRect!).Y; 59 + box.Width = ((Rectangle)CollisionRect!).Width; 60 + box.Height = ((Rectangle)CollisionRect!).Height; 61 + } 62 + return box; 63 + } 64 + 65 + public virtual void Update(Level level, int x, int y) 66 + { } 67 + 68 + public virtual void Render(Level level, View view, int x, int y) 69 + { 70 + if (level.Step != RenderStep) 71 + return; 72 + 73 + Vector2 pos = View.LevelPosToWorldPos(x, y); 74 + 75 + if (Texture.Width > View.TileSize) 76 + pos.X -= View.TileSize; 77 + if (Texture.Height > View.TileSize) 78 + pos.Y -= View.TileSize; 79 + 80 + Raylib.DrawTextureEx(Texture, pos, 0, 1, Color.White); 81 + } 82 + 83 + public Tile Register() 84 + { 85 + return Register(this); 86 + } 87 + 88 + public static Tile Register(Tile tile) 89 + { 90 + tile.ID = _nextTileID++; 91 + Tiles[tile.ID] = tile; 92 + return tile; 93 + } 94 + 95 + public static Tile? FindByKey(string key) 96 + { 97 + foreach (Tile tile in Tiles) 98 + if (tile.Key == key) 99 + return tile; 100 + return null; 101 + } 102 + } 103 + 104 + public abstract class TileData 105 + { 106 + public abstract string Save(); 107 + 108 + public abstract void Load(string json); 109 + }
+40
Electropunk/World/View.cs
··· 1 + using System.Numerics; 2 + using Raylib_cs; 3 + 4 + namespace Electropunk.World; 5 + 6 + public class View 7 + { 8 + /* Never ever change this. This is the size that we render tiles at. */ 9 + public const int TileSize = 16; 10 + 11 + public Vector2 GoalTarget = Vector2.Zero; 12 + public float GoalZoom = 2f; 13 + 14 + public Camera2D Camera = new(new Vector2(400, 300), new Vector2(0, 0), 0f, 2f); 15 + 16 + public void Update() 17 + { 18 + if (Raylib.IsWindowResized()) 19 + Camera.Offset = Raylib.GetScreenCenter(); 20 + 21 + Camera.Target = Vector2.Lerp(Camera.Target, GoalTarget, 0.20f); 22 + Camera.Zoom = Vector2.Lerp(new(0, Camera.Zoom), new(0, GoalZoom), 0.20f).Y; /* cursed? yes. very. */ 23 + } 24 + 25 + public (Vector2, Vector2) GetWorldBounds() 26 + { 27 + Vector2 first = Raylib.GetScreenToWorld2D(new(0, 0), Camera); 28 + Vector2 second = Raylib.GetScreenToWorld2D(new(Raylib.GetScreenWidth(), Raylib.GetScreenHeight()), Camera); 29 + return (first, second); 30 + } 31 + 32 + public Rectangle GetWorldBoundsRec() 33 + { 34 + Vector2 first = Raylib.GetScreenToWorld2D(new(0, 0), Camera); 35 + Vector2 second = Raylib.GetScreenToWorld2D(new(Raylib.GetScreenWidth(), Raylib.GetScreenHeight()), Camera); 36 + return new(first, second - first); 37 + } 38 + 39 + public static Vector2 LevelPosToWorldPos(int x, int y) => new(x * TileSize, y * TileSize); 40 + }
+22
electropunk.sln
··· 1 +  2 + Microsoft Visual Studio Solution File, Format Version 12.00 3 + # Visual Studio Version 17 4 + VisualStudioVersion = 17.0.31903.59 5 + MinimumVisualStudioVersion = 10.0.40219.1 6 + Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Electropunk", "Electropunk\Electropunk.csproj", "{1B9AD174-1BA7-4FD1-A4BA-6209E6A2CB81}" 7 + EndProject 8 + Global 9 + GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 + Debug|Any CPU = Debug|Any CPU 11 + Release|Any CPU = Release|Any CPU 12 + EndGlobalSection 13 + GlobalSection(SolutionProperties) = preSolution 14 + HideSolutionNode = FALSE 15 + EndGlobalSection 16 + GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 + {1B9AD174-1BA7-4FD1-A4BA-6209E6A2CB81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 + {1B9AD174-1BA7-4FD1-A4BA-6209E6A2CB81}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 + {1B9AD174-1BA7-4FD1-A4BA-6209E6A2CB81}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 + {1B9AD174-1BA7-4FD1-A4BA-6209E6A2CB81}.Release|Any CPU.Build.0 = Release|Any CPU 21 + EndGlobalSection 22 + EndGlobal
+33
licenses
··· 1 + 2 + === Electropunk === 3 + 4 + Currently All Rights Reserved. I'm looking into open-source 5 + licenses that'll prevent other people from publishing the 6 + game under their name without credit. I.e, the MIT license 7 + would allow anyone to publish Electropunk on Steam, which I 8 + don't want. 9 + 10 + === FastNoiseLite === 11 + 12 + MIT License 13 + 14 + Copyright(c) 2020 Jordan Peck (jordan.me2@gmail.com) 15 + Copyright(c) 2020 Contributors 16 + 17 + Permission is hereby granted, free of charge, to any person obtaining a copy 18 + of this software and associated documentation files (the "Software"), to deal 19 + in the Software without restriction, including without limitation the rights 20 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 + copies of the Software, and to permit persons to whom the Software is 22 + furnished to do so, subject to the following conditions: 23 + 24 + The above copyright notice and this permission notice shall be included in all 25 + copies or substantial portions of the Software. 26 + 27 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33 + SOFTWARE.
misc/bigshot.png

This is a binary file and will not be displayed.

+36
misc/fantasy.gpl
··· 1 + GIMP Palette 2 + #Palette Name: fantasy_ 3 + #Description: designed for the fantasy_ tilesets and sprites @itch.io [https://itch.io/c/1507436/fantasy-] 4 + #Colors: 32 5 + 237 228 218 ede4da 6 + 191 184 180 bfb8b4 7 + 145 141 141 918d8d 8 + 99 97 103 636167 9 + 53 53 64 353540 10 + 169 73 73 a94949 11 + 202 89 84 ca5954 12 + 229 111 75 e56f4b 13 + 227 147 71 e39347 14 + 238 181 81 eeb551 15 + 232 198 91 e8c65b 16 + 189 163 81 bda351 17 + 139 145 80 8b9150 18 + 85 125 85 557d55 19 + 68 99 80 446350 20 + 62 85 76 3e554c 21 + 139 176 173 8bb0ad 22 + 118 159 166 769fa6 23 + 102 141 169 668da9 24 + 92 105 159 5c699f 25 + 90 88 136 5a5888 26 + 124 109 162 7c6da2 27 + 148 122 157 947a9d 28 + 188 135 165 bc87a5 29 + 217 166 166 d9a6a6 30 + 212 194 182 d4c2b6 31 + 189 170 151 bdaa97 32 + 134 115 91 86735b 33 + 126 103 76 7e674c 34 + 115 91 66 735b42 35 + 96 75 61 604b3d 36 + 77 63 56 4d3f38
+67
misc/gora63.gpl
··· 1 + GIMP Palette 2 + #Palette Name: GORA63 3 + #Description: A big pallete with 7 colors and 9 shades, equalling a total of 63 colors. I made this pallete for a RPG game where color diversity was a must, so it is great for many things. The pallete is inspired by AdamCYounis, that's why the base colors are the same as Apollo. Hope you like it. :) (ALSO, check out AdamCYounis. Lospec: https://lospec.com/adamcyounis Twitter: https://twitter.com/AdamCYounis?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor) 4 + #Colors: 63 5 + 20 27 39 141b27 6 + 30 39 52 1e2734 7 + 43 53 69 2b3545 8 + 58 73 89 3a4959 9 + 80 98 117 506275 10 + 108 130 148 6c8294 11 + 133 154 169 859aa9 12 + 179 194 202 b3c2ca 13 + 218 225 229 dae1e5 14 + 18 21 50 121532 15 + 27 35 67 1b2343 16 + 32 52 87 203457 17 + 38 74 113 264a71 18 + 45 91 133 2d5b85 19 + 52 131 176 3483b0 20 + 73 178 211 49b2d3 21 + 130 216 233 82d8e9 22 + 189 238 247 bdeef7 23 + 20 36 39 142427 24 + 28 48 48 1c3030 25 + 34 70 53 224635 26 + 40 99 69 286345 27 + 42 113 72 2a7148 28 + 44 159 76 2c9f4c 29 + 104 209 80 68d150 30 + 197 245 125 c5f57d 31 + 232 250 182 e8fab6 32 + 43 20 36 2b1424 33 + 54 27 40 361b28 34 + 78 44 50 4e2c32 35 + 117 68 66 754442 36 + 136 78 72 884e48 37 + 155 97 79 9b614f 38 + 187 136 90 bb885a 39 + 223 187 137 dfbb89 40 + 240 224 184 f0e0b8 41 + 48 23 35 301723 42 + 61 31 40 3d1f28 43 + 77 40 44 4d282c 44 + 111 59 49 6f3b31 45 + 142 78 48 8e4e30 46 + 180 106 41 b46a29 47 + 225 159 62 e19f3e 48 + 240 192 105 f0c069 49 + 247 225 152 f7e198 50 + 44 19 41 2c1329 51 + 54 22 48 361630 52 + 82 30 58 521e3a 53 + 123 37 54 7b2536 54 + 168 55 45 a8372d 55 + 216 95 40 d85f28 56 + 240 142 57 f08e39 57 + 251 200 94 fbc85e 58 + 252 232 134 fce886 59 + 28 23 41 1c1729 60 + 42 33 53 2a2135 61 + 62 42 73 3e2a49 62 + 101 51 95 65335f 63 + 157 58 120 9d3a78 64 + 198 71 130 c64782 65 + 216 106 159 d86a9f 66 + 231 160 180 e7a0b4 67 + 242 205 206 f2cdce
+36
misc/nanner-32.gpl
··· 1 + GIMP Palette 2 + #Palette Name: Nanner 32 3 + #Description: NOTE: An improved version of this palette can be found here: https://www.pixilart.com/palettes/nanner-32-9538 4 + #Colors: 32 5 + 96 116 171 6074ab 6 + 107 154 207 6b9acf 7 + 139 189 230 8bbde6 8 + 170 224 243 aae0f3 9 + 200 237 237 c8eded 10 + 250 255 224 faffe0 11 + 221 230 224 dde6e0 12 + 180 190 194 b4bec2 13 + 148 157 168 949da8 14 + 122 122 153 7a7a99 15 + 91 82 128 5b5280 16 + 78 49 97 4e3161 17 + 66 30 66 421e42 18 + 97 36 71 612447 19 + 122 55 87 7a3757 20 + 150 72 91 96485b 21 + 189 104 104 bd6868 22 + 209 139 121 d18b79 23 + 219 172 140 dbac8c 24 + 230 207 161 e6cfa1 25 + 231 235 188 e7ebbc 26 + 178 219 160 b2dba0 27 + 135 194 147 87c293 28 + 112 161 143 70a18f 29 + 99 124 143 637c8f 30 + 181 110 117 b56e75 31 + 201 143 143 c98f8f 32 + 223 182 174 dfb6ae 33 + 237 213 202 edd5ca 34 + 189 113 130 bd7182 35 + 158 84 118 9e5476 36 + 117 60 106 753c6a
+19
misc/palettes.txt
··· 1 + 2 + A list of colour palettes I'm considering for Electropunk 3 + 4 + "Phase 1" (just finding some fancy palettes, disregarding Electropunk's theme) 5 + 6 + Waldgeist <https://lospec.com/palette-list/waldgeist> 7 + Nanner 32 <https://lospec.com/palette-list/nanner-32> 8 + Fantasy <https://lospec.com/palette-list/fantasy> 9 + Paper Pixels <https://lospec.com/palette-list/paper-pixels> 10 + Poisson 23 <https://lospec.com/palette-list/poisson-23> 11 + Gora63 <https://lospec.com/palette-list/gora63> 12 + Sweet24 <https://lospec.com/palette-list/sweet24> 13 + Vinik24 <https://lospec.com/palette-list/vinik24> 14 + 15 + "Phase 2" (matching palettes to Electropunk's theme [cyber/steam/solarpunk]) 16 + 17 + Nanner 32 <https://lospec.com/palette-list/nanner-32> 18 + Fantasy <https://lospec.com/palette-list/fantasy> 19 + Gora63 <https://lospec.com/palette-list/gora63>
misc/screenshots/2025-11-03_13-04-47.png

This is a binary file and will not be displayed.

misc/screenshots/2025-11-03_17-07-01.png

This is a binary file and will not be displayed.

+18
readme
··· 1 + 2 + Electropunk 3 + =========== 4 + 5 + A WIP automation game. 6 + 7 + Run 8 + --- 9 + 10 + Requires .NET 9.0 11 + 12 + dotnet run --project Electropunk 13 + 14 + Misc 15 + ---- 16 + 17 + Electropunk's birthday is November 1st, 2025. 18 + Jim's birthday is November 5th, 2025.