From a6d543ced563b95a678cd6329cebe2e65b3b15f0 Mon Sep 17 00:00:00 2001 From: Ivory Date: Thu, 22 Aug 2024 02:55:37 -0400 Subject: [PATCH] Entities --- src/Entity.zig | 36 ++ src/Scene.zig | 30 +- src/Terrain.zig | 25 ++ src/assets.zig | 8 + src/engine.zig | 6 +- src/noise.c | 920 ++++++++++++++++++++++++++++++++++++++++++++++++ textures.png | Bin 29484 -> 36967 bytes 7 files changed, 1023 insertions(+), 2 deletions(-) create mode 100644 src/Entity.zig create mode 100644 src/Terrain.zig create mode 100644 src/noise.c diff --git a/src/Entity.zig b/src/Entity.zig new file mode 100644 index 0000000..f73f10b --- /dev/null +++ b/src/Entity.zig @@ -0,0 +1,36 @@ +const assets = @import("assets.zig"); +const Layer = @import("Layer.zig"); +const Color = @import("Color.zig"); +const Recti = @import("geometry/Recti.zig"); + +const Entity = @This(); + + +ptr: *const anyopaque, +drawFn: *const fn(*const anyopaque) void, + + +pub fn init(ptr: anytype) Entity { + const type_info = @typeInfo(@TypeOf(ptr)); + + if(type_info != .Pointer) @compileError("Entity implementation must be a pointer"); + if(type_info.Pointer.size != .One) @compileError("Entity pointer must be a single item pointer"); + + const gen = struct { + pub fn drawImpl(pointer: *const anyopaque) void { + const self: @TypeOf(ptr) = @ptrCast(@alignCast(pointer)); + type_info.Pointer.child.draw(self); + // @call(.{ .modifier = .always_inline }, ptr_info.Pointer.child.draw, .{ self }); + // draw(self); + } + }; + + return .{ + .ptr = ptr, + .drawFn = gen.drawImpl, + }; +} + +pub fn draw(self: *const Entity) void { + self.drawFn(self.ptr); +} diff --git a/src/Scene.zig b/src/Scene.zig index 721b390..e0520de 100644 --- a/src/Scene.zig +++ b/src/Scene.zig @@ -2,7 +2,10 @@ const assets = @import("assets.zig"); const Recti = @import("geometry/Recti.zig"); const Layer = @import("Layer.zig"); const Color = @import("Color.zig"); +const Entity = @import("Entity.zig"); +const Terrain = @import("Terrain.zig"); const std = @import("std"); +const ArrayList = std.ArrayList; const Scene = @This(); // const DrawFunction = fn() void; @@ -11,7 +14,32 @@ const Scene = @This(); // draw: DrawFunction, // update: -pub fn draw() void { +entities: ArrayList(Entity), + +pub fn new() Scene { + const e: ArrayList(Entity) = ArrayList(Entity).init(std.heap.page_allocator); + return .{ + .entities = e + }; +} + +pub fn destroy(self: *Scene) void { + self.entities.deinit(); +} + +pub fn start(self: *Scene) !void { + const terrain = Terrain.new(); + // terrain.entity(); + + try self.entities.append(terrain.entity()); +} + +pub fn draw(self: *Scene) void { + + for (self.entities.items) |entity| { + entity.draw(); + } + assets.heart.draw(&Recti.from_xywh(120, 100, 32, 64), Layer.ENTITIES, Color.LIGHT_BLUE); assets.heart.draw(&Recti.from_xywh(100, 100, 32, 64), Layer.FLOOR, Color.WHITE); assets.heart.draw(&Recti.from_xywh(80, 100, 32, 64), Layer.ENTITIES, Color.INDIGO); diff --git a/src/Terrain.zig b/src/Terrain.zig new file mode 100644 index 0000000..6836222 --- /dev/null +++ b/src/Terrain.zig @@ -0,0 +1,25 @@ +const Terrain = @This(); + +const assets = @import("assets.zig"); +const Layer = @import("Layer.zig"); +const Color = @import("Color.zig"); +const Recti = @import("geometry/Recti.zig"); +const Entity = @import("Entity.zig"); +const std = @import("std"); +var prng = std.rand.DefaultPrng.init(0); + +size: u32 = 24, +draw: u8 = 4, + +pub fn new() Terrain { + return .{}; +} + +pub fn draw(_: *const Terrain) void { + const idx: usize = @intFromFloat(@floor(prng.random().float(f32) * 4)); + assets.terrain[idx].draw(&Recti.from_xywh(200, 100, 64, 64), Layer.FLOOR, Color.WHITE); +} + +pub fn entity(self: *const Terrain) Entity { + return Entity.init(self); +} diff --git a/src/assets.zig b/src/assets.zig index 4a58470..54f9cad 100644 --- a/src/assets.zig +++ b/src/assets.zig @@ -6,6 +6,7 @@ const std = @import("std"); const Assets = struct { tree: Sprite, heart: Sprite, + terrain: [4]Sprite, }; var assets: Assets = undefined; @@ -17,8 +18,15 @@ pub fn load() !void { assets = .{ .tree = Sprite.create(&texture, Recti.from_xywh(8*27, 8*4, 8, 16)), .heart = Sprite.create(&texture, Recti.from_xywh(8*27, 8*4, 8, 16)), + .terrain = [_]Sprite { + Sprite.create(&texture, Recti.from_xywh(8*3, 8*8, 8, 8)), + Sprite.create(&texture, Recti.from_xywh(8*3, 8*9, 8, 8)), + Sprite.create(&texture, Recti.from_xywh(8*4, 8*8, 8, 8)), + Sprite.create(&texture, Recti.from_xywh(8*4, 8*9, 8, 8)), + } }; } pub const tree: *const Sprite = &assets.tree; pub const heart: *const Sprite = &assets.heart; +pub const terrain:[]const Sprite = &assets.terrain; diff --git a/src/engine.zig b/src/engine.zig index bc442a8..0ed5d93 100644 --- a/src/engine.zig +++ b/src/engine.zig @@ -87,11 +87,15 @@ pub fn run() !void { const projection = Matrix4f.orthographic(0, @floatFromInt(width), @floatFromInt(height), 0, 0, 100); + var scene = Scene.new(); + defer scene.destroy(); + try scene.start(); + // run the main loop while (c.glfwWindowShouldClose(window) == 0) { shaders.set_projection_matrix(&projection); c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT); - Scene.draw(); + scene.draw(); // game.render(); // game.update(1.0); diff --git a/src/noise.c b/src/noise.c new file mode 100644 index 0000000..ca56e09 --- /dev/null +++ b/src/noise.c @@ -0,0 +1,920 @@ +/** + * K.jpg's OpenSimplex 2, faster variant + * + * - 2D is standard simplex implemented using a lookup table. + * - 3D is "Re-oriented 4-point BCC noise" which constructs a + * congruent BCC lattice in a much different way than usual. + * - 4D constructs the lattice as a union of five copies of its + * reciprocal. It successively finds the closest point on each. + * + * Multiple versions of each function are provided. See the + * documentation above each, for more info. + */ +#include +#include +#include +#include + +#include "OpenSimplex2F.h" + +#define PSIZE (2048) +#define PMASK (2047) +static const double N2 = 0.01001634121365712; +static const double N3 = 0.030485933181293584; +static const double N4 = 0.009202377986303158; + +#define B0000 0x00 +#define B0001 0x01 +#define B0010 0x02 +#define B0011 0x03 +#define B0100 0x04 +#define B0101 0x05 +#define B0110 0x06 +#define B0111 0x07 +#define B1000 0x08 +#define B1001 0x09 +#define B1010 0x0a +#define B1011 0x0b +#define B1100 0x0c +#define B1101 0x0d +#define B1110 0x0e +#define B1111 0x0f + +struct Grad2 { + double dx, dy; +}; + +struct Grad3 { + double dx, dy, dz; +}; + +struct Grad4 { + double dx, dy, dz, dw; +}; + +struct LatticePoint2D { + int xsv, ysv; + double dx, dy; +}; + +static struct LatticePoint2D *new_LatticePoint2D(int xsv, int ysv) +{ + struct LatticePoint2D *this = calloc(1, sizeof(*this)); + + this->xsv = xsv; this->ysv = ysv; + double ssv = (xsv + ysv) * -0.211324865405187; + this->dx = -xsv - ssv; + this->dy = -ysv - ssv; + return this; +} + +struct LatticePoint3D { + double dxr, dyr, dzr; + int xrv, yrv, zrv; + struct LatticePoint3D *nextOnFailure, *nextOnSuccess; +}; + +static struct LatticePoint3D *new_LatticePoint3D(int xrv, int yrv, int zrv, int lattice) +{ + struct LatticePoint3D *this = calloc(1, sizeof(*this)); + + this->dxr = -xrv + lattice * 0.5; this->dyr = -yrv + lattice * 0.5; this->dzr = -zrv + lattice * 0.5; + this->xrv = xrv + lattice * 1024; this->yrv = yrv + lattice * 1024; this->zrv = zrv + lattice * 1024; + return this; +} + +static void find_unique_pointers(struct LatticePoint3D *tree, struct LatticePoint3D *list[], int *n) +{ + if (!tree) + return; + int i, found; + + found = 0; + for (i = 0; i < *n; i++) { + if (list[i] == tree) { + found = 1; + break; + } + } + if (!found) { + list[*n] = tree; + (*n)++; + } + find_unique_pointers(tree->nextOnFailure, list, n); + find_unique_pointers(tree->nextOnSuccess, list, n); +} + +static void free_LatticePoint3D(struct LatticePoint3D *list[], int n) +{ + int i; + + for (i = 0; i < n; i++) + free(list[i]); +} + +struct LatticePoint4D { + int xsv, ysv, zsv, wsv; + double dx, dy, dz, dw; + double xsi, ysi, zsi, wsi; + double ssiDelta; +}; + +static struct LatticePoint4D *new_LatticePoint4D(int xsv, int ysv, int zsv, int wsv) +{ + struct LatticePoint4D *this = calloc(1, sizeof(*this)); + + this->xsv = xsv + 409; this->ysv = ysv + 409; this->zsv = zsv + 409; this->wsv = wsv + 409; + double ssv = (xsv + ysv + zsv + wsv) * 0.309016994374947; + this->dx = -xsv - ssv; + this->dy = -ysv - ssv; + this->dz = -zsv - ssv; + this->dw = -wsv - ssv; + this->xsi = 0.2 - xsv; + this->ysi = 0.2 - ysv; + this->zsi = 0.2 - zsv; + this->wsi = 0.2 - wsv; + this->ssiDelta = (0.8 - xsv - ysv - zsv - wsv) * 0.309016994374947; + return this; +} + +struct OpenSimplex2F_context { + int16_t *perm; + struct Grad2 *permGrad2; + struct Grad3 *permGrad3; + struct Grad4 *permGrad4; +}; + +#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) + +static struct Grad2 GRADIENTS_2D[PSIZE]; +static struct Grad3 GRADIENTS_3D[PSIZE]; +static struct Grad4 GRADIENTS_4D[PSIZE]; +static struct LatticePoint2D *LOOKUP_2D[4]; +static struct LatticePoint3D *LOOKUP_3D[8]; +static struct LatticePoint4D *VERTICES_4D[16]; + +static struct Grad2 grad2[] = { + { 0.130526192220052, 0.99144486137381}, + { 0.38268343236509, 0.923879532511287}, + { 0.608761429008721, 0.793353340291235}, + { 0.793353340291235, 0.608761429008721}, + { 0.923879532511287, 0.38268343236509}, + { 0.99144486137381, 0.130526192220051}, + { 0.99144486137381, -0.130526192220051}, + { 0.923879532511287, -0.38268343236509}, + { 0.793353340291235, -0.60876142900872}, + { 0.608761429008721, -0.793353340291235}, + { 0.38268343236509, -0.923879532511287}, + { 0.130526192220052, -0.99144486137381}, + {-0.130526192220052, -0.99144486137381}, + {-0.38268343236509, -0.923879532511287}, + {-0.608761429008721, -0.793353340291235}, + {-0.793353340291235, -0.608761429008721}, + {-0.923879532511287, -0.38268343236509}, + {-0.99144486137381, -0.130526192220052}, + {-0.99144486137381, 0.130526192220051}, + {-0.923879532511287, 0.38268343236509}, + {-0.793353340291235, 0.608761429008721}, + {-0.608761429008721, 0.793353340291235}, + {-0.38268343236509, 0.923879532511287}, + {-0.130526192220052, 0.99144486137381} +}; + +static struct Grad3 grad3[] = { + {-2.22474487139, -2.22474487139, -1.0}, + {-2.22474487139, -2.22474487139, 1.0}, + {-3.0862664687972017, -1.1721513422464978, 0.0}, + {-1.1721513422464978, -3.0862664687972017, 0.0}, + {-2.22474487139, -1.0, -2.22474487139}, + {-2.22474487139, 1.0, -2.22474487139}, + {-1.1721513422464978, 0.0, -3.0862664687972017}, + {-3.0862664687972017, 0.0, -1.1721513422464978}, + {-2.22474487139, -1.0, 2.22474487139}, + {-2.22474487139, 1.0, 2.22474487139}, + {-3.0862664687972017, 0.0, 1.1721513422464978}, + {-1.1721513422464978, 0.0, 3.0862664687972017}, + {-2.22474487139, 2.22474487139, -1.0}, + {-2.22474487139, 2.22474487139, 1.0}, + {-1.1721513422464978, 3.0862664687972017, 0.0}, + {-3.0862664687972017, 1.1721513422464978, 0.0}, + {-1.0, -2.22474487139, -2.22474487139}, + { 1.0, -2.22474487139, -2.22474487139}, + { 0.0, -3.0862664687972017, -1.1721513422464978}, + { 0.0, -1.1721513422464978, -3.0862664687972017}, + {-1.0, -2.22474487139, 2.22474487139}, + { 1.0, -2.22474487139, 2.22474487139}, + { 0.0, -1.1721513422464978, 3.0862664687972017}, + { 0.0, -3.0862664687972017, 1.1721513422464978}, + {-1.0, 2.22474487139, -2.22474487139}, + { 1.0, 2.22474487139, -2.22474487139}, + { 0.0, 1.1721513422464978, -3.0862664687972017}, + { 0.0, 3.0862664687972017, -1.1721513422464978}, + {-1.0, 2.22474487139, 2.22474487139}, + { 1.0, 2.22474487139, 2.22474487139}, + { 0.0, 3.0862664687972017, 1.1721513422464978}, + { 0.0, 1.1721513422464978, 3.0862664687972017}, + { 2.22474487139, -2.22474487139, -1.0}, + { 2.22474487139, -2.22474487139, 1.0}, + { 1.1721513422464978, -3.0862664687972017, 0.0}, + { 3.0862664687972017, -1.1721513422464978, 0.0}, + { 2.22474487139, -1.0, -2.22474487139}, + { 2.22474487139, 1.0, -2.22474487139}, + { 3.0862664687972017, 0.0, -1.1721513422464978}, + { 1.1721513422464978, 0.0, -3.0862664687972017}, + { 2.22474487139, -1.0, 2.22474487139}, + { 2.22474487139, 1.0, 2.22474487139}, + { 1.1721513422464978, 0.0, 3.0862664687972017}, + { 3.0862664687972017, 0.0, 1.1721513422464978}, + { 2.22474487139, 2.22474487139, -1.0}, + { 2.22474487139, 2.22474487139, 1.0}, + { 3.0862664687972017, 1.1721513422464978, 0.0}, + { 1.1721513422464978, 3.0862664687972017, 0.0} +}; + +static struct Grad4 grad4[] = { + {-0.753341017856078, -0.37968289875261624, -0.37968289875261624, -0.37968289875261624}, + {-0.7821684431180708, -0.4321472685365301, -0.4321472685365301, 0.12128480194602098}, + {-0.7821684431180708, -0.4321472685365301, 0.12128480194602098, -0.4321472685365301}, + {-0.7821684431180708, 0.12128480194602098, -0.4321472685365301, -0.4321472685365301}, + {-0.8586508742123365, -0.508629699630796, 0.044802370851755174, 0.044802370851755174}, + {-0.8586508742123365, 0.044802370851755174, -0.508629699630796, 0.044802370851755174}, + {-0.8586508742123365, 0.044802370851755174, 0.044802370851755174, -0.508629699630796}, + {-0.9982828964265062, -0.03381941603233842, -0.03381941603233842, -0.03381941603233842}, + {-0.37968289875261624, -0.753341017856078, -0.37968289875261624, -0.37968289875261624}, + {-0.4321472685365301, -0.7821684431180708, -0.4321472685365301, 0.12128480194602098}, + {-0.4321472685365301, -0.7821684431180708, 0.12128480194602098, -0.4321472685365301}, + { 0.12128480194602098, -0.7821684431180708, -0.4321472685365301, -0.4321472685365301}, + {-0.508629699630796, -0.8586508742123365, 0.044802370851755174, 0.044802370851755174}, + { 0.044802370851755174, -0.8586508742123365, -0.508629699630796, 0.044802370851755174}, + { 0.044802370851755174, -0.8586508742123365, 0.044802370851755174, -0.508629699630796}, + {-0.03381941603233842, -0.9982828964265062, -0.03381941603233842, -0.03381941603233842}, + {-0.37968289875261624, -0.37968289875261624, -0.753341017856078, -0.37968289875261624}, + {-0.4321472685365301, -0.4321472685365301, -0.7821684431180708, 0.12128480194602098}, + {-0.4321472685365301, 0.12128480194602098, -0.7821684431180708, -0.4321472685365301}, + { 0.12128480194602098, -0.4321472685365301, -0.7821684431180708, -0.4321472685365301}, + {-0.508629699630796, 0.044802370851755174, -0.8586508742123365, 0.044802370851755174}, + { 0.044802370851755174, -0.508629699630796, -0.8586508742123365, 0.044802370851755174}, + { 0.044802370851755174, 0.044802370851755174, -0.8586508742123365, -0.508629699630796}, + {-0.03381941603233842, -0.03381941603233842, -0.9982828964265062, -0.03381941603233842}, + {-0.37968289875261624, -0.37968289875261624, -0.37968289875261624, -0.753341017856078}, + {-0.4321472685365301, -0.4321472685365301, 0.12128480194602098, -0.7821684431180708}, + {-0.4321472685365301, 0.12128480194602098, -0.4321472685365301, -0.7821684431180708}, + { 0.12128480194602098, -0.4321472685365301, -0.4321472685365301, -0.7821684431180708}, + {-0.508629699630796, 0.044802370851755174, 0.044802370851755174, -0.8586508742123365}, + { 0.044802370851755174, -0.508629699630796, 0.044802370851755174, -0.8586508742123365}, + { 0.044802370851755174, 0.044802370851755174, -0.508629699630796, -0.8586508742123365}, + {-0.03381941603233842, -0.03381941603233842, -0.03381941603233842, -0.9982828964265062}, + {-0.6740059517812944, -0.3239847771997537, -0.3239847771997537, 0.5794684678643381}, + {-0.7504883828755602, -0.4004672082940195, 0.15296486218853164, 0.5029860367700724}, + {-0.7504883828755602, 0.15296486218853164, -0.4004672082940195, 0.5029860367700724}, + {-0.8828161875373585, 0.08164729285680945, 0.08164729285680945, 0.4553054119602712}, + {-0.4553054119602712, -0.08164729285680945, -0.08164729285680945, 0.8828161875373585}, + {-0.5029860367700724, -0.15296486218853164, 0.4004672082940195, 0.7504883828755602}, + {-0.5029860367700724, 0.4004672082940195, -0.15296486218853164, 0.7504883828755602}, + {-0.5794684678643381, 0.3239847771997537, 0.3239847771997537, 0.6740059517812944}, + {-0.3239847771997537, -0.6740059517812944, -0.3239847771997537, 0.5794684678643381}, + {-0.4004672082940195, -0.7504883828755602, 0.15296486218853164, 0.5029860367700724}, + { 0.15296486218853164, -0.7504883828755602, -0.4004672082940195, 0.5029860367700724}, + { 0.08164729285680945, -0.8828161875373585, 0.08164729285680945, 0.4553054119602712}, + {-0.08164729285680945, -0.4553054119602712, -0.08164729285680945, 0.8828161875373585}, + {-0.15296486218853164, -0.5029860367700724, 0.4004672082940195, 0.7504883828755602}, + { 0.4004672082940195, -0.5029860367700724, -0.15296486218853164, 0.7504883828755602}, + { 0.3239847771997537, -0.5794684678643381, 0.3239847771997537, 0.6740059517812944}, + {-0.3239847771997537, -0.3239847771997537, -0.6740059517812944, 0.5794684678643381}, + {-0.4004672082940195, 0.15296486218853164, -0.7504883828755602, 0.5029860367700724}, + { 0.15296486218853164, -0.4004672082940195, -0.7504883828755602, 0.5029860367700724}, + { 0.08164729285680945, 0.08164729285680945, -0.8828161875373585, 0.4553054119602712}, + {-0.08164729285680945, -0.08164729285680945, -0.4553054119602712, 0.8828161875373585}, + {-0.15296486218853164, 0.4004672082940195, -0.5029860367700724, 0.7504883828755602}, + { 0.4004672082940195, -0.15296486218853164, -0.5029860367700724, 0.7504883828755602}, + { 0.3239847771997537, 0.3239847771997537, -0.5794684678643381, 0.6740059517812944}, + {-0.6740059517812944, -0.3239847771997537, 0.5794684678643381, -0.3239847771997537}, + {-0.7504883828755602, -0.4004672082940195, 0.5029860367700724, 0.15296486218853164}, + {-0.7504883828755602, 0.15296486218853164, 0.5029860367700724, -0.4004672082940195}, + {-0.8828161875373585, 0.08164729285680945, 0.4553054119602712, 0.08164729285680945}, + {-0.4553054119602712, -0.08164729285680945, 0.8828161875373585, -0.08164729285680945}, + {-0.5029860367700724, -0.15296486218853164, 0.7504883828755602, 0.4004672082940195}, + {-0.5029860367700724, 0.4004672082940195, 0.7504883828755602, -0.15296486218853164}, + {-0.5794684678643381, 0.3239847771997537, 0.6740059517812944, 0.3239847771997537}, + {-0.3239847771997537, -0.6740059517812944, 0.5794684678643381, -0.3239847771997537}, + {-0.4004672082940195, -0.7504883828755602, 0.5029860367700724, 0.15296486218853164}, + { 0.15296486218853164, -0.7504883828755602, 0.5029860367700724, -0.4004672082940195}, + { 0.08164729285680945, -0.8828161875373585, 0.4553054119602712, 0.08164729285680945}, + {-0.08164729285680945, -0.4553054119602712, 0.8828161875373585, -0.08164729285680945}, + {-0.15296486218853164, -0.5029860367700724, 0.7504883828755602, 0.4004672082940195}, + { 0.4004672082940195, -0.5029860367700724, 0.7504883828755602, -0.15296486218853164}, + { 0.3239847771997537, -0.5794684678643381, 0.6740059517812944, 0.3239847771997537}, + {-0.3239847771997537, -0.3239847771997537, 0.5794684678643381, -0.6740059517812944}, + {-0.4004672082940195, 0.15296486218853164, 0.5029860367700724, -0.7504883828755602}, + { 0.15296486218853164, -0.4004672082940195, 0.5029860367700724, -0.7504883828755602}, + { 0.08164729285680945, 0.08164729285680945, 0.4553054119602712, -0.8828161875373585}, + {-0.08164729285680945, -0.08164729285680945, 0.8828161875373585, -0.4553054119602712}, + {-0.15296486218853164, 0.4004672082940195, 0.7504883828755602, -0.5029860367700724}, + { 0.4004672082940195, -0.15296486218853164, 0.7504883828755602, -0.5029860367700724}, + { 0.3239847771997537, 0.3239847771997537, 0.6740059517812944, -0.5794684678643381}, + {-0.6740059517812944, 0.5794684678643381, -0.3239847771997537, -0.3239847771997537}, + {-0.7504883828755602, 0.5029860367700724, -0.4004672082940195, 0.15296486218853164}, + {-0.7504883828755602, 0.5029860367700724, 0.15296486218853164, -0.4004672082940195}, + {-0.8828161875373585, 0.4553054119602712, 0.08164729285680945, 0.08164729285680945}, + {-0.4553054119602712, 0.8828161875373585, -0.08164729285680945, -0.08164729285680945}, + {-0.5029860367700724, 0.7504883828755602, -0.15296486218853164, 0.4004672082940195}, + {-0.5029860367700724, 0.7504883828755602, 0.4004672082940195, -0.15296486218853164}, + {-0.5794684678643381, 0.6740059517812944, 0.3239847771997537, 0.3239847771997537}, + {-0.3239847771997537, 0.5794684678643381, -0.6740059517812944, -0.3239847771997537}, + {-0.4004672082940195, 0.5029860367700724, -0.7504883828755602, 0.15296486218853164}, + { 0.15296486218853164, 0.5029860367700724, -0.7504883828755602, -0.4004672082940195}, + { 0.08164729285680945, 0.4553054119602712, -0.8828161875373585, 0.08164729285680945}, + {-0.08164729285680945, 0.8828161875373585, -0.4553054119602712, -0.08164729285680945}, + {-0.15296486218853164, 0.7504883828755602, -0.5029860367700724, 0.4004672082940195}, + { 0.4004672082940195, 0.7504883828755602, -0.5029860367700724, -0.15296486218853164}, + { 0.3239847771997537, 0.6740059517812944, -0.5794684678643381, 0.3239847771997537}, + {-0.3239847771997537, 0.5794684678643381, -0.3239847771997537, -0.6740059517812944}, + {-0.4004672082940195, 0.5029860367700724, 0.15296486218853164, -0.7504883828755602}, + { 0.15296486218853164, 0.5029860367700724, -0.4004672082940195, -0.7504883828755602}, + { 0.08164729285680945, 0.4553054119602712, 0.08164729285680945, -0.8828161875373585}, + {-0.08164729285680945, 0.8828161875373585, -0.08164729285680945, -0.4553054119602712}, + {-0.15296486218853164, 0.7504883828755602, 0.4004672082940195, -0.5029860367700724}, + { 0.4004672082940195, 0.7504883828755602, -0.15296486218853164, -0.5029860367700724}, + { 0.3239847771997537, 0.6740059517812944, 0.3239847771997537, -0.5794684678643381}, + { 0.5794684678643381, -0.6740059517812944, -0.3239847771997537, -0.3239847771997537}, + { 0.5029860367700724, -0.7504883828755602, -0.4004672082940195, 0.15296486218853164}, + { 0.5029860367700724, -0.7504883828755602, 0.15296486218853164, -0.4004672082940195}, + { 0.4553054119602712, -0.8828161875373585, 0.08164729285680945, 0.08164729285680945}, + { 0.8828161875373585, -0.4553054119602712, -0.08164729285680945, -0.08164729285680945}, + { 0.7504883828755602, -0.5029860367700724, -0.15296486218853164, 0.4004672082940195}, + { 0.7504883828755602, -0.5029860367700724, 0.4004672082940195, -0.15296486218853164}, + { 0.6740059517812944, -0.5794684678643381, 0.3239847771997537, 0.3239847771997537}, + { 0.5794684678643381, -0.3239847771997537, -0.6740059517812944, -0.3239847771997537}, + { 0.5029860367700724, -0.4004672082940195, -0.7504883828755602, 0.15296486218853164}, + { 0.5029860367700724, 0.15296486218853164, -0.7504883828755602, -0.4004672082940195}, + { 0.4553054119602712, 0.08164729285680945, -0.8828161875373585, 0.08164729285680945}, + { 0.8828161875373585, -0.08164729285680945, -0.4553054119602712, -0.08164729285680945}, + { 0.7504883828755602, -0.15296486218853164, -0.5029860367700724, 0.4004672082940195}, + { 0.7504883828755602, 0.4004672082940195, -0.5029860367700724, -0.15296486218853164}, + { 0.6740059517812944, 0.3239847771997537, -0.5794684678643381, 0.3239847771997537}, + { 0.5794684678643381, -0.3239847771997537, -0.3239847771997537, -0.6740059517812944}, + { 0.5029860367700724, -0.4004672082940195, 0.15296486218853164, -0.7504883828755602}, + { 0.5029860367700724, 0.15296486218853164, -0.4004672082940195, -0.7504883828755602}, + { 0.4553054119602712, 0.08164729285680945, 0.08164729285680945, -0.8828161875373585}, + { 0.8828161875373585, -0.08164729285680945, -0.08164729285680945, -0.4553054119602712}, + { 0.7504883828755602, -0.15296486218853164, 0.4004672082940195, -0.5029860367700724}, + { 0.7504883828755602, 0.4004672082940195, -0.15296486218853164, -0.5029860367700724}, + { 0.6740059517812944, 0.3239847771997537, 0.3239847771997537, -0.5794684678643381}, + { 0.03381941603233842, 0.03381941603233842, 0.03381941603233842, 0.9982828964265062}, + {-0.044802370851755174, -0.044802370851755174, 0.508629699630796, 0.8586508742123365}, + {-0.044802370851755174, 0.508629699630796, -0.044802370851755174, 0.8586508742123365}, + {-0.12128480194602098, 0.4321472685365301, 0.4321472685365301, 0.7821684431180708}, + { 0.508629699630796, -0.044802370851755174, -0.044802370851755174, 0.8586508742123365}, + { 0.4321472685365301, -0.12128480194602098, 0.4321472685365301, 0.7821684431180708}, + { 0.4321472685365301, 0.4321472685365301, -0.12128480194602098, 0.7821684431180708}, + { 0.37968289875261624, 0.37968289875261624, 0.37968289875261624, 0.753341017856078}, + { 0.03381941603233842, 0.03381941603233842, 0.9982828964265062, 0.03381941603233842}, + {-0.044802370851755174, 0.044802370851755174, 0.8586508742123365, 0.508629699630796}, + {-0.044802370851755174, 0.508629699630796, 0.8586508742123365, -0.044802370851755174}, + {-0.12128480194602098, 0.4321472685365301, 0.7821684431180708, 0.4321472685365301}, + { 0.508629699630796, -0.044802370851755174, 0.8586508742123365, -0.044802370851755174}, + { 0.4321472685365301, -0.12128480194602098, 0.7821684431180708, 0.4321472685365301}, + { 0.4321472685365301, 0.4321472685365301, 0.7821684431180708, -0.12128480194602098}, + { 0.37968289875261624, 0.37968289875261624, 0.753341017856078, 0.37968289875261624}, + { 0.03381941603233842, 0.9982828964265062, 0.03381941603233842, 0.03381941603233842}, + {-0.044802370851755174, 0.8586508742123365, -0.044802370851755174, 0.508629699630796}, + {-0.044802370851755174, 0.8586508742123365, 0.508629699630796, -0.044802370851755174}, + {-0.12128480194602098, 0.7821684431180708, 0.4321472685365301, 0.4321472685365301}, + { 0.508629699630796, 0.8586508742123365, -0.044802370851755174, -0.044802370851755174}, + { 0.4321472685365301, 0.7821684431180708, -0.12128480194602098, 0.4321472685365301}, + { 0.4321472685365301, 0.7821684431180708, 0.4321472685365301, -0.12128480194602098}, + { 0.37968289875261624, 0.753341017856078, 0.37968289875261624, 0.37968289875261624}, + { 0.9982828964265062, 0.03381941603233842, 0.03381941603233842, 0.03381941603233842}, + { 0.8586508742123365, -0.044802370851755174, -0.044802370851755174, 0.508629699630796}, + { 0.8586508742123365, -0.044802370851755174, 0.508629699630796, -0.044802370851755174}, + { 0.7821684431180708, -0.12128480194602098, 0.4321472685365301, 0.4321472685365301}, + { 0.8586508742123365, 0.508629699630796, -0.044802370851755174, -0.044802370851755174}, + { 0.7821684431180708, 0.4321472685365301, -0.12128480194602098, 0.4321472685365301}, + { 0.7821684431180708, 0.4321472685365301, 0.4321472685365301, -0.12128480194602098}, + { 0.753341017856078, 0.37968289875261624, 0.37968289875261624, 0.37968289875261624} +}; + + +static void setup_gradients(void) +{ + static int already_did = 0; + int i; + + if (already_did) + return; + already_did = 1; + + for (i = 0; (size_t) i < ARRAYSIZE(grad2); i++) { + grad2[i].dx /= N2; grad2[i].dy /= N2; + } + for (int i = 0; i < PSIZE; i++) { + GRADIENTS_2D[i] = grad2[i % ARRAYSIZE(grad2)]; + } + + for (i = 0; (size_t) i < ARRAYSIZE(grad3); i++) { + grad3[i].dx /= N3; grad3[i].dy /= N3; grad3[i].dz /= N3; + } + for (i = 0; i < PSIZE; i++) { + GRADIENTS_3D[i] = grad3[i % ARRAYSIZE(grad3)]; + } + + for (i = 0; (size_t) i < ARRAYSIZE(grad4); i++) { + grad4[i].dx /= N4; grad4[i].dy /= N4; grad4[i].dz /= N4; grad4[i].dw /= N4; + } + for (i = 0; i < PSIZE; i++) { + GRADIENTS_4D[i] = grad4[i % ARRAYSIZE(grad4)]; + } +} + +static void setup_lattice_points(void) +{ + static int already_did = 0; + int i; + + if (already_did) + return; + already_did = 1; + + LOOKUP_2D[0] = new_LatticePoint2D(1, 0); + LOOKUP_2D[1] = new_LatticePoint2D(0, 0); + LOOKUP_2D[2] = new_LatticePoint2D(1, 1); + LOOKUP_2D[3] = new_LatticePoint2D(0, 1); + + for (i = 0; i < 8; i++) { + int i1, j1, k1, i2, j2, k2; + i1 = (i >> 0) & 1; j1 = (i >> 1) & 1; k1 = (i >> 2) & 1; + i2 = i1 ^ 1; j2 = j1 ^ 1; k2 = k1 ^ 1; + + // The two points within this octant, one from each of the two cubic half-lattices. + struct LatticePoint3D *c0 = new_LatticePoint3D(i1, j1, k1, 0); + struct LatticePoint3D *c1 = new_LatticePoint3D(i1 + i2, j1 + j2, k1 + k2, 1); + + // Each single step away on the first half-lattice. + struct LatticePoint3D *c2 = new_LatticePoint3D(i1 ^ 1, j1, k1, 0); + struct LatticePoint3D *c3 = new_LatticePoint3D(i1, j1 ^ 1, k1, 0); + struct LatticePoint3D *c4 = new_LatticePoint3D(i1, j1, k1 ^ 1, 0); + + // Each single step away on the second half-lattice. + struct LatticePoint3D *c5 = new_LatticePoint3D(i1 + (i2 ^ 1), j1 + j2, k1 + k2, 1); + struct LatticePoint3D *c6 = new_LatticePoint3D(i1 + i2, j1 + (j2 ^ 1), k1 + k2, 1); + struct LatticePoint3D *c7 = new_LatticePoint3D(i1 + i2, j1 + j2, k1 + (k2 ^ 1), 1); + + // First two are guaranteed. + c0->nextOnFailure = c0->nextOnSuccess = c1; + c1->nextOnFailure = c1->nextOnSuccess = c2; + + // Once we find one on the first half-lattice, the rest are out. + // In addition, knowing c2 rules out c5. + c2->nextOnFailure = c3; c2->nextOnSuccess = c6; + c3->nextOnFailure = c4; c3->nextOnSuccess = c5; + c4->nextOnFailure = c4->nextOnSuccess = c5; + + // Once we find one on the second half-lattice, the rest are out. + c5->nextOnFailure = c6; c5->nextOnSuccess = NULL; + c6->nextOnFailure = c7; c6->nextOnSuccess = NULL; + c7->nextOnFailure = c7->nextOnSuccess = NULL; + + LOOKUP_3D[i] = c0; + } + + for (i = 0; i < 16; i++) { + VERTICES_4D[i] = new_LatticePoint4D((i >> 0) & 1, (i >> 1) & 1, (i >> 2) & 1, (i >> 3) & 1); + } +} + +/* Free up all the LatticePoint stuff allocated in setup_lattice_points() */ +void OpenSimplex2F_shutdown(void) +{ + int i; + struct LatticePoint3D *list[8]; + int count = 0; + + for (i = 0; (size_t) i < ARRAYSIZE(LOOKUP_2D); i++) { + if (LOOKUP_2D[i]) { + free(LOOKUP_2D[i]); + LOOKUP_2D[i] = NULL; + } + } + + for (i = 0; (size_t) i < ARRAYSIZE(LOOKUP_3D); i++) { + if (LOOKUP_3D[i]) { + /* There are cycles in the tree LOOKUP_3D[i], so we have to + * make a list of unique pointers within the tree to free them. + * We know there are only 8 unique pointers in the tree. + */ + count = 0; + memset(list, 0, sizeof(list)); + find_unique_pointers(LOOKUP_3D[i], list, &count); + free_LatticePoint3D(list, count); + LOOKUP_3D[i] = NULL; + } + } + + for (i = 0; (size_t) i < ARRAYSIZE(VERTICES_4D); i++) { + if (VERTICES_4D[i]) { + free(VERTICES_4D[i]); + VERTICES_4D[i] = NULL; + } + } +} + +void OpenSimplex2F_free(struct OpenSimplex2F_context *ctx) +{ + if (ctx->perm) + free(ctx->perm); + if (ctx->permGrad2) + free(ctx->permGrad2); + if (ctx->permGrad3) + free(ctx->permGrad3); + if (ctx->permGrad4) + free(ctx->permGrad4); + free(ctx); +} + +int OpenSimplex2F(int64_t seed, struct OpenSimplex2F_context **ctx) +{ + struct OpenSimplex2F_context *c; + int i, *source; + + setup_gradients(); + setup_lattice_points(); + + source = calloc(1, sizeof(*source) * PSIZE); + if (!source) + return -1; + + c = calloc(1, sizeof(**ctx)); + if (!c) { + free(source); + return -1; + } + *ctx = c; + + c->perm = calloc(1, sizeof(*c->perm) * PSIZE); + c->permGrad2 = calloc(1, sizeof(*c->permGrad2) * PSIZE); + c->permGrad3 = calloc(1, sizeof(*c->permGrad3) * PSIZE); + c->permGrad4 = calloc(1, sizeof(*c->permGrad4) * PSIZE); + + if (!c->perm || !c->permGrad2 || !c->permGrad3 || !c->permGrad4) { + OpenSimplex2F_free(*ctx); + *ctx = NULL; + free(source); + return -1; + } + + for (i = 0; i < PSIZE; i++) + source[i] = (int16_t) i; + + for (int i = PSIZE - 1; i >= 0; i--) { + seed = (uint64_t) seed * (uint64_t) 6364136223846793005LL + (uint64_t) 1442695040888963407LL; + int r = (int)((seed + 31) % (i + 1)); + if (r < 0) + r += (i + 1); + c->perm[i] = source[r]; + c->permGrad2[i] = GRADIENTS_2D[c->perm[i]]; + c->permGrad3[i] = GRADIENTS_3D[c->perm[i]]; + c->permGrad4[i] = GRADIENTS_4D[c->perm[i]]; + source[r] = source[i]; + } + free(source); + return 0; +} + +static int fastFloor(double x) +{ + int xi = (int)x; + return x < xi ? xi - 1 : xi; +} + +/* + * 2D Simplex noise base. + * Lookup table implementation inspired by DigitalShadow. + */ +static double noise2_Base(struct OpenSimplex2F_context *ctx, double xs, double ys) +{ + double value = 0; + int i; + + // Get base points and offsets + int xsb = fastFloor(xs), ysb = fastFloor(ys); + double xsi = xs - xsb, ysi = ys - ysb; + + // Index to point list + int index = (int)((ysi - xsi) / 2 + 1); + + double ssi = (xsi + ysi) * -0.211324865405187; + double xi = xsi + ssi, yi = ysi + ssi; + + // Point contributions + for (i = 0; i < 3; i++) { + struct LatticePoint2D c = *(LOOKUP_2D[index + i]); + + double dx = xi + c.dx, dy = yi + c.dy; + double attn = 0.5 - dx * dx - dy * dy; + if (attn <= 0) continue; + + int pxm = (xsb + c.xsv) & PMASK, pym = (ysb + c.ysv) & PMASK; + struct Grad2 grad = ctx->permGrad2[ctx->perm[pxm] ^ pym]; + double extrapolation = grad.dx * dx + grad.dy * dy; + + attn *= attn; + value += attn * attn * extrapolation; + } + + return value; +} + +/** + * Generate overlapping cubic lattices for 3D Re-oriented BCC noise. + * Lookup table implementation inspired by DigitalShadow. + * It was actually faster to narrow down the points in the loop itself, + * than to build up the index with enough info to isolate 4 points. + */ +static double noise3_BCC(struct OpenSimplex2F_context *ctx, double xr, double yr, double zr) +{ + // Get base and offsets inside cube of first lattice. + int xrb = fastFloor(xr), yrb = fastFloor(yr), zrb = fastFloor(zr); + double xri = xr - xrb, yri = yr - yrb, zri = zr - zrb; + + // Identify which octant of the cube we're in. This determines which cell + // in the other cubic lattice we're in, and also narrows down one point on each. + int xht = (int)(xri + 0.5), yht = (int)(yri + 0.5), zht = (int)(zri + 0.5); + int index = (xht << 0) | (yht << 1) | (zht << 2); + + // Point contributions + double value = 0; + struct LatticePoint3D *c = LOOKUP_3D[index]; + while (c != NULL) { + double dxr = xri + c->dxr, dyr = yri + c->dyr, dzr = zri + c->dzr; + double attn = 0.5 - dxr * dxr - dyr * dyr - dzr * dzr; + if (attn < 0) { + c = c->nextOnFailure; + } else { + int pxm = (xrb + c->xrv) & PMASK, pym = (yrb + c->yrv) & PMASK, pzm = (zrb + c->zrv) & PMASK; + struct Grad3 grad = ctx->permGrad3[ctx->perm[ctx->perm[pxm] ^ pym] ^ pzm]; + double extrapolation = grad.dx * dxr + grad.dy * dyr + grad.dz * dzr; + + attn *= attn; + value += attn * attn * extrapolation; + c = c->nextOnSuccess; + } + } + return value; +} + +/** + * 2D Simplex noise, standard lattice orientation. + */ +double OpenSimplex2F_noise2(struct OpenSimplex2F_context *ctx, double x, double y) +{ + // Get points for A2* lattice + double s = 0.366025403784439 * (x + y); + double xs = x + s, ys = y + s; + + return noise2_Base(ctx, xs, ys); +} + +/** + * 2D Simplex noise, with Y pointing down the main diagonal. + * Might be better for a 2D sandbox style game, where Y is vertical. + * Probably slightly less optimal for heightmaps or continent maps. + */ +double OpenSimplex2F_noise2_XBeforeY(struct OpenSimplex2F_context *ctx, double x, double y) +{ + // Skew transform and rotation baked into one. + double xx = x * 0.7071067811865476; + double yy = y * 1.224744871380249; + + return noise2_Base(ctx, yy + xx, yy - xx); +} + +/** + * 3D Re-oriented 4-point BCC noise, classic orientation. + * Proper substitute for 3D Simplex in light of Forbidden Formulae. + * Use noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate. + */ +double OpenSimplex2F_noise3_Classic(struct OpenSimplex2F_context *ctx, double x, double y, double z) +{ + // Re-orient the cubic lattices via rotation, to produce the expected look on cardinal planar slices. + // If texturing objects that don't tend to have cardinal plane faces, you could even remove this. + // Orthonormal rotation. Not a skew transform. + double r = (2.0 / 3.0) * (x + y + z); + double xr = r - x, yr = r - y, zr = r - z; + + // Evaluate both lattices to form a BCC lattice. + return noise3_BCC(ctx, xr, yr, zr); +} + +/** + * 3D Re-oriented 4-point BCC noise, with better visual isotropy in (X, Y). + * Recommended for 3D terrain and time-varied animations. + * The Z coordinate should always be the "different" coordinate in your use case. + * If Y is vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use noise3_XZBeforeY. + * If Z is vertical in world coordinates, call noise3_XYBeforeZ(x, y, Z). + * For a time varied animation, call noise3_XYBeforeZ(x, y, T). + */ +double OpenSimplex2F_noise3_XYBeforeZ(struct OpenSimplex2F_context *ctx, double x, double y, double z) +{ + // Re-orient the cubic lattices without skewing, to make X and Y triangular like 2D. + // Orthonormal rotation. Not a skew transform. + double xy = x + y; + double s2 = xy * -0.211324865405187; + double zz = z * 0.577350269189626; + double xr = x + s2 - zz, yr = y + s2 - zz; + double zr = xy * 0.577350269189626 + zz; + + // Evaluate both lattices to form a BCC lattice. + return noise3_BCC(ctx, xr, yr, zr); +} + +/** + * 3D Re-oriented 4-point BCC noise, with better visual isotropy in (X, Z). + * Recommended for 3D terrain and time-varied animations. + * The Y coordinate should always be the "different" coordinate in your use case. + * If Y is vertical in world coordinates, call noise3_XZBeforeY(x, Y, z). + * If Z is vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use noise3_XYBeforeZ. + * For a time varied animation, call noise3_XZBeforeY(x, T, y) or use noise3_XYBeforeZ. + */ +double OpenSimplex2F_noise3_XZBeforeY(struct OpenSimplex2F_context *ctx, double x, double y, double z) +{ + // Re-orient the cubic lattices without skewing, to make X and Z triangular like 2D. + // Orthonormal rotation. Not a skew transform. + double xz = x + z; + double s2 = xz * -0.211324865405187; + double yy = y * 0.577350269189626; + double xr = x + s2 - yy; double zr = z + s2 - yy; + double yr = xz * 0.577350269189626 + yy; + + // Evaluate both lattices to form a BCC lattice. + return noise3_BCC(ctx, xr, yr, zr); +} + +/** + * 4D OpenSimplex2F noise base. + * Current implementation not fully optimized by lookup tables. + * But still comes out slightly ahead of Gustavson's Simplex in tests. + */ +static double noise4_Base(struct OpenSimplex2F_context *ctx, double xs, double ys, double zs, double ws) +{ + double value = 0; + + // Get base points and offsets + int xsb = fastFloor(xs), ysb = fastFloor(ys), zsb = fastFloor(zs), wsb = fastFloor(ws); + double xsi = xs - xsb, ysi = ys - ysb, zsi = zs - zsb, wsi = ws - wsb; + + // If we're in the lower half, flip so we can repeat the code for the upper half. We'll flip back later. + double siSum = xsi + ysi + zsi + wsi; + double ssi = siSum * 0.309016994374947; // Prep for vertex contributions. + bool inLowerHalf = (siSum < 2); + if (inLowerHalf) { + xsi = 1 - xsi; ysi = 1 - ysi; zsi = 1 - zsi; wsi = 1 - wsi; + siSum = 4 - siSum; + } + + // Consider opposing vertex pairs of the octahedron formed by the central cross-section of the stretched tesseract + double aabb = xsi + ysi - zsi - wsi, abab = xsi - ysi + zsi - wsi, abba = xsi - ysi - zsi + wsi; + double aabbScore = fabs(aabb), ababScore = fabs(abab), abbaScore = fabs(abba); + + // Find the closest point on the stretched tesseract as if it were the upper half + int vertexIndex, via, vib; + double asi, bsi; + if (aabbScore > ababScore && aabbScore > abbaScore) { + if (aabb > 0) { + asi = zsi; bsi = wsi; vertexIndex = B0011; via = B0111; vib = B1011; + } else { + asi = xsi; bsi = ysi; vertexIndex = B1100; via = B1101; vib = B1110; + } + } else if (ababScore > abbaScore) { + if (abab > 0) { + asi = ysi; bsi = wsi; vertexIndex = B0101; via = B0111; vib = B1101; + } else { + asi = xsi; bsi = zsi; vertexIndex = B1010; via = B1011; vib = B1110; + } + } else { + if (abba > 0) { + asi = ysi; bsi = zsi; vertexIndex = B1001; via = B1011; vib = B1101; + } else { + asi = xsi; bsi = wsi; vertexIndex = B0110; via = B0111; vib = B1110; + } + } + if (bsi > asi) { + via = vib; + double temp = bsi; + bsi = asi; + asi = temp; + } + if (siSum + asi > 3) { + vertexIndex = via; + if (siSum + bsi > 4) { + vertexIndex = B1111; + } + } + + // Now flip back if we're actually in the lower half. + if (inLowerHalf) { + xsi = 1 - xsi; ysi = 1 - ysi; zsi = 1 - zsi; wsi = 1 - wsi; + vertexIndex ^= B1111; + } + + // Five points to add, total, from five copies of the A4 lattice. + for (int i = 0; i < 5; i++) { + + // Update xsb/etc. and add the lattice point's contribution. + struct LatticePoint4D c = *(VERTICES_4D[vertexIndex]); + xsb += c.xsv; ysb += c.ysv; zsb += c.zsv; wsb += c.wsv; + double xi = xsi + ssi, yi = ysi + ssi, zi = zsi + ssi, wi = wsi + ssi; + double dx = xi + c.dx, dy = yi + c.dy, dz = zi + c.dz, dw = wi + c.dw; + double attn = 0.5 - dx * dx - dy * dy - dz * dz - dw * dw; + if (attn > 0) { + int pxm = xsb & PMASK, pym = ysb & PMASK, pzm = zsb & PMASK, pwm = wsb & PMASK; + struct Grad4 grad = ctx->permGrad4[ctx->perm[ctx->perm[ctx->perm[pxm] ^ pym] ^ pzm] ^ pwm]; + double ramped = grad.dx * dx + grad.dy * dy + grad.dz * dz + grad.dw * dw; + + attn *= attn; + value += attn * attn * ramped; + } + + // Maybe this helps the compiler/JVM/LLVM/etc. know we can end the loop here. Maybe not. + if (i == 4) break; + + // Update the relative skewed coordinates to reference the vertex we just added. + // Rather, reference its counterpart on the lattice copy that is shifted down by + // the vector <-0.2, -0.2, -0.2, -0.2> + xsi += c.xsi; ysi += c.ysi; zsi += c.zsi; wsi += c.wsi; + ssi += c.ssiDelta; + + // Next point is the closest vertex on the 4-simplex whose base vertex is the aforementioned vertex. + double score0 = 1.0 + ssi * (-1.0 / 0.309016994374947); // Seems slightly faster than 1.0-xsi-ysi-zsi-wsi + vertexIndex = B0000; + if (xsi >= ysi && xsi >= zsi && xsi >= wsi && xsi >= score0) { + vertexIndex = B0001; + } + else if (ysi > xsi && ysi >= zsi && ysi >= wsi && ysi >= score0) { + vertexIndex = B0010; + } + else if (zsi > xsi && zsi > ysi && zsi >= wsi && zsi >= score0) { + vertexIndex = B0100; + } + else if (wsi > xsi && wsi > ysi && wsi > zsi && wsi >= score0) { + vertexIndex = B1000; + } + } + + return value; +} + +/** + * 4D OpenSimplex2F noise, classic lattice orientation. + */ + double OpenSimplex2F_noise4_Classic(struct OpenSimplex2F_context *ctx, double x, double y, double z, double w) +{ + // Get points for A4 lattice + double s = -0.138196601125011 * (x + y + z + w); + double xs = x + s, ys = y + s, zs = z + s, ws = w + s; + + return noise4_Base(ctx, xs, ys, zs, ws); +} + +/** + * 4D OpenSimplex2F noise, with XY and ZW forming orthogonal triangular-based planes. + * Recommended for 3D terrain, where X and Y (or Z and W) are horizontal. + * Recommended for noise(x, y, sin(time), cos(time)) trick. + */ +double OpenSimplex2F_noise4_XYBeforeZW(struct OpenSimplex2F_context *ctx, double x, double y, double z, double w) +{ + + double s2 = (x + y) * -0.178275657951399372 + (z + w) * 0.215623393288842828; + double t2 = (z + w) * -0.403949762580207112 + (x + y) * -0.375199083010075342; + double xs = x + s2, ys = y + s2, zs = z + t2, ws = w + t2; + + return noise4_Base(ctx, xs, ys, zs, ws); +} + +/** + * 4D OpenSimplex2F noise, with XZ and YW forming orthogonal triangular-based planes. + * Recommended for 3D terrain, where X and Z (or Y and W) are horizontal. + */ +double OpenSimplex2F_noise4_XZBeforeYW(struct OpenSimplex2F_context *ctx, double x, double y, double z, double w) +{ + double s2 = (x + z) * -0.178275657951399372 + (y + w) * 0.215623393288842828; + double t2 = (y + w) * -0.403949762580207112 + (x + z) * -0.375199083010075342; + double xs = x + s2, ys = y + t2, zs = z + s2, ws = w + t2; + + return noise4_Base(ctx, xs, ys, zs, ws); +} + +/** + * 4D OpenSimplex2F noise, with XYZ oriented like noise3_Classic, + * and W for an extra degree of freedom. W repeats eventually. + * Recommended for time-varied animations which texture a 3D object (W=time) + */ +double OpenSimplex2F_noise4_XYZBeforeW(struct OpenSimplex2F_context *ctx, double x, double y, double z, double w) +{ + double xyz = x + y + z; + double ww = w * 0.2236067977499788; + double s2 = xyz * -0.16666666666666666 + ww; + double xs = x + s2, ys = y + s2, zs = z + s2, ws = -0.5 * xyz + ww; + + return noise4_Base(ctx, xs, ys, zs, ws); +} + diff --git a/textures.png b/textures.png index 311d2587a68f778bb7a7adcca214c3c58dfecd27..14ad769cf7f18e4acedcfad6bcd3ee77feac072c 100644 GIT binary patch literal 36967 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 delta 25787 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