Last active
March 4, 2019 14:38
-
-
Save nsf/1170424 to your computer and use it in GitHub Desktop.
Perlin noise benchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
rm -rf *.o *.[568] test_* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
gcc -std=c99 -march=native -msse3 -mfpmath=sse -O3 -o test_c test.c -lm | |
dmd -oftest_d -O -noboundscheck -inline -release test.d | |
go build -o test_go test.go | |
rustc --opt-level 3 -o test_rs test.rs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
#include <time.h> | |
#define M_PI 3.1415926535f | |
typedef struct { | |
float x, y; | |
} Vec2; | |
static inline float lerp(float a, float b, float v) | |
{ | |
return a * (1 - v) + b * v; | |
} | |
static inline float smooth(float v) { | |
return v * v * (3 - 2 * v); | |
} | |
static inline Vec2 random_gradient() | |
{ | |
const float v = (float)rand() / RAND_MAX * M_PI * 2.0f; | |
return (Vec2){cosf(v), sinf(v)}; | |
} | |
static inline float gradient(Vec2 orig, Vec2 grad, Vec2 p) | |
{ | |
Vec2 sp = {p.x - orig.x, p.y - orig.y}; | |
return grad.x * sp.x + grad.y * sp.y; | |
} | |
typedef struct { | |
Vec2 rgradients[256]; | |
int permutations[256]; | |
Vec2 gradients[4]; | |
Vec2 origins[4]; | |
} Noise2DContext; | |
static inline Vec2 get_gradient(Noise2DContext *ctx, int x, int y) { | |
int idx = ctx->permutations[x & 255] + ctx->permutations[y & 255]; | |
return ctx->rgradients[idx & 255]; | |
} | |
static inline void get_gradients(Noise2DContext *ctx, float x, float y) { | |
float x0f = floorf(x); | |
float y0f = floorf(y); | |
int x0 = x0f; | |
int y0 = y0f; | |
int x1 = x0 + 1; | |
int y1 = y0 + 1; | |
ctx->gradients[0] = get_gradient(ctx, x0, y0); | |
ctx->gradients[1] = get_gradient(ctx, x1, y0); | |
ctx->gradients[2] = get_gradient(ctx, x0, y1); | |
ctx->gradients[3] = get_gradient(ctx, x1, y1); | |
ctx->origins[0] = (Vec2){x0f + 0.0f, y0f + 0.0f}; | |
ctx->origins[1] = (Vec2){x0f + 1.0f, y0f + 0.0f}; | |
ctx->origins[2] = (Vec2){x0f + 0.0f, y0f + 1.0f}; | |
ctx->origins[3] = (Vec2){x0f + 1.0f, y0f + 1.0f}; | |
} | |
static float noise2d_get(Noise2DContext *ctx, float x, float y) | |
{ | |
Vec2 p = {x, y}; | |
get_gradients(ctx, x, y); | |
float v0 = gradient(ctx->origins[0], ctx->gradients[0], p); | |
float v1 = gradient(ctx->origins[1], ctx->gradients[1], p); | |
float v2 = gradient(ctx->origins[2], ctx->gradients[2], p); | |
float v3 = gradient(ctx->origins[3], ctx->gradients[3], p); | |
float fx = smooth(x - ctx->origins[0].x); | |
float vx0 = lerp(v0, v1, fx); | |
float vx1 = lerp(v2, v3, fx); | |
float fy = smooth(y - ctx->origins[0].y); | |
return lerp(vx0, vx1, fy); | |
} | |
static void init_noise2d(Noise2DContext *ctx) | |
{ | |
for (int i = 0; i < 256; i++) | |
ctx->rgradients[i] = random_gradient(); | |
for (int i = 0; i < 256; i++) { | |
int j = rand() % (i+1); | |
ctx->permutations[i] = ctx->permutations[j]; | |
ctx->permutations[j] = i; | |
} | |
} | |
int main(int argc, char **argv) | |
{ | |
srand(time(NULL)); | |
const char *symbols[] = {" ", "░", "▒", "▓", "█", "█"}; | |
float *pixels = malloc(sizeof(float) * 256 * 256); | |
Noise2DContext n2d; | |
init_noise2d(&n2d); | |
for (int i = 0; i < 100; i++) { | |
for (int y = 0; y < 256; y++) { | |
for (int x = 0; x < 256; x++) { | |
float v = noise2d_get(&n2d, x * 0.1f, y * 0.1f) | |
* 0.5f + 0.5f; | |
pixels[y*256+x] = v; | |
} | |
} | |
} | |
for (int y = 0; y < 256; y++) { | |
for (int x = 0; x < 256; x++) { | |
int idx = pixels[y*256+x] / 0.2f; | |
printf("%s", symbols[idx]); | |
} | |
printf("\n"); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
struct Vec2 { | |
public float x; | |
public float y; | |
} | |
class Noise2DContext { | |
Vec2[] rgradients; | |
int[] permutations; | |
Vec2[] gradients; | |
Vec2[] origins; | |
internal static float lerp(float a, float b, float v) { | |
return a * (1 - v) + b * v; | |
} | |
internal static float smooth(float v) { | |
return v * v * (3 - 2 * v); | |
} | |
internal static Vec2 random_gradient(Random rnd) { | |
var v = rnd.NextDouble() * Math.PI * 2.0; | |
return new Vec2 { x = (float)Math.Cos(v), y = (float)Math.Sin(v) }; | |
} | |
internal static float gradient(Vec2 orig, Vec2 grad, Vec2 p) { | |
var sp = new Vec2 { x = p.x - orig.x, y = p.y - orig.y }; | |
return grad.x * sp.x + grad.y * sp.y; | |
} | |
public Noise2DContext(int seed) { | |
Random rnd = new Random(seed); | |
rgradients = new Vec2[256]; | |
permutations = new int[256]; | |
for (int i = 0; i < 256; i++) { | |
rgradients[i] = random_gradient(rnd); | |
} | |
for (int i = 0; i < 256; i++) { | |
int j = rnd.Next(i + 1); | |
permutations[i] = permutations[j]; | |
permutations[j] = i; | |
} | |
gradients = new Vec2[4]; | |
origins = new Vec2[4]; | |
} | |
internal Vec2 get_gradient(int x, int y) { | |
int idx = permutations[x & 255] + permutations[y & 255]; | |
return rgradients[idx & 255]; | |
} | |
internal void get_gradients(float x, float y) { | |
float x0f = (float)Math.Floor(x); | |
float y0f = (float)Math.Floor(y); | |
int x0 = (int)x0f; | |
int y0 = (int)y0f; | |
int x1 = x0 + 1; | |
int y1 = y0 + 1; | |
gradients[0] = get_gradient(x0, y0); | |
gradients[1] = get_gradient(x1, y0); | |
gradients[2] = get_gradient(x0, y1); | |
gradients[3] = get_gradient(x1, y1); | |
origins[0] = new Vec2 { x = x0f + 0, y = y0f + 0 }; | |
origins[1] = new Vec2 { x = x0f + 1, y = y0f + 0 }; | |
origins[2] = new Vec2 { x = x0f + 0, y = y0f + 1 }; | |
origins[3] = new Vec2 { x = x0f + 1, y = y0f + 1 }; | |
} | |
public float get(float x, float y) { | |
Vec2 p = new Vec2 { x = x, y = y }; | |
get_gradients(x, y); | |
float v0 = gradient(origins[0], gradients[0], p); | |
float v1 = gradient(origins[1], gradients[1], p); | |
float v2 = gradient(origins[2], gradients[2], p); | |
float v3 = gradient(origins[3], gradients[3], p); | |
float fx = smooth(x - origins[0].x); | |
float vx0 = lerp(v0, v1, fx); | |
float vx1 = lerp(v2, v3, fx); | |
float fy = smooth(y - origins[0].y); | |
return lerp(vx0, vx1, fy); | |
} | |
} | |
class Application { | |
static readonly char[] symbols = { ' ', '░', '▒', '▓', '█', '█' }; | |
public static void Main(string[] args) { | |
var n2d = new Noise2DContext((int)DateTime.Now.Ticks); | |
float[] pixels = new float[256 * 256]; | |
for (int i = 0; i < 100; i++) { | |
for (int y = 0; y < 256; y++) { | |
for (int x = 0; x < 256; x++) { | |
float v = n2d.get(x * 0.1f, y * 0.1f) * 0.5f + 0.5f; | |
pixels[y * 256 + x] = v; | |
} | |
} | |
} | |
for (int y = 0; y < 256; y++) { | |
for (int x = 0; x < 256; x++) { | |
int idx = (int)(pixels[y * 256 + x] / 0.2f); | |
Console.Write(symbols[idx]); | |
} | |
Console.WriteLine(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.stdio; | |
import std.random; | |
import std.math; | |
struct Vec2 { | |
float x, y; | |
} | |
float lerp(float a, float b, float v) | |
{ | |
return a * (1 - v) + b * v; | |
} | |
float smooth(float v) | |
{ | |
return v * v * (3 - 2 * v); | |
} | |
Vec2 random_gradient(Random)(ref Random r) | |
{ | |
auto v = uniform(0.0f, cast(float)PI * 2.0f, r); | |
return Vec2(cos(v), sin(v)); | |
} | |
float gradient(Vec2 orig, Vec2 grad, Vec2 p) | |
{ | |
auto sp = Vec2(p.x - orig.x, p.y - orig.y); | |
return grad.x * sp.x + grad.y * sp.y; | |
} | |
class Noise2DContext { | |
Vec2[256] rgradients; | |
uint[256] permutations; | |
Vec2[4] gradients; | |
Vec2[4] origins; | |
private: | |
Vec2 get_gradient(int x, int y) | |
{ | |
auto idx = permutations[x & 255] + permutations[y & 255]; | |
return rgradients[idx & 255]; | |
} | |
void get_gradients(float x, float y) | |
{ | |
float x0f = floor(x); | |
float y0f = floor(y); | |
int x0 = cast(int)x0f; | |
int y0 = cast(int)y0f; | |
int x1 = x0 + 1; | |
int y1 = y0 + 1; | |
gradients[0] = get_gradient(x0, y0); | |
gradients[1] = get_gradient(x1, y0); | |
gradients[2] = get_gradient(x0, y1); | |
gradients[3] = get_gradient(x1, y1); | |
origins[0] = Vec2(x0f + 0.0f, y0f + 0.0f); | |
origins[1] = Vec2(x0f + 1.0f, y0f + 0.0f); | |
origins[2] = Vec2(x0f + 0.0f, y0f + 1.0f); | |
origins[3] = Vec2(x0f + 1.0f, y0f + 1.0f); | |
} | |
public: | |
this(uint seed) | |
{ | |
auto rnd = Random(seed); | |
foreach (ref elem; rgradients) | |
elem = random_gradient(rnd); | |
foreach (i; 0 .. permutations.length) { | |
uint j = uniform(0, i+1, rnd); | |
permutations[i] = permutations[j]; | |
permutations[j] = i; | |
} | |
} | |
float get(float x, float y) | |
{ | |
auto p = Vec2(x, y); | |
get_gradients(x, y); | |
auto v0 = gradient(origins[0], gradients[0], p); | |
auto v1 = gradient(origins[1], gradients[1], p); | |
auto v2 = gradient(origins[2], gradients[2], p); | |
auto v3 = gradient(origins[3], gradients[3], p); | |
auto fx = smooth(x - origins[0].x); | |
auto vx0 = lerp(v0, v1, fx); | |
auto vx1 = lerp(v2, v3, fx); | |
auto fy = smooth(y - origins[0].y); | |
return lerp(vx0, vx1, fy); | |
} | |
} | |
void main() | |
{ | |
immutable symbols = [" ", "░", "▒", "▓", "█", "█"]; | |
auto pixels = new float[256*256]; | |
auto n2d = new Noise2DContext(0); | |
foreach (i; 0..100) { | |
foreach (y; 0..256) { | |
foreach (x; 0..256) { | |
auto v = n2d.get(x * 0.1f, y * 0.1f) * | |
0.5f + 0.5f; | |
pixels[y*256+x] = v; | |
} | |
} | |
} | |
foreach (y; 0..256) { | |
foreach (x; 0..256) { | |
write(symbols[cast(int)(pixels[y*256+x] / 0.2f)]); | |
} | |
writeln(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"math/rand" | |
"math" | |
"bufio" | |
"os" | |
) | |
const PI = 3.1415926535 | |
type Vec2 struct { | |
X, Y float32 | |
} | |
func lerp(a, b, v float32) float32 { | |
return a * (1 - v) + b * v | |
} | |
func smooth(v float32) float32 { | |
return v * v * (3 - 2 * v) | |
} | |
func random_gradient(r *rand.Rand) Vec2 { | |
v := r.Float64() * PI * 2 | |
return Vec2{ | |
float32(math.Cos(v)), | |
float32(math.Sin(v)), | |
} | |
} | |
func gradient(orig, grad, p Vec2) float32 { | |
sp := Vec2{p.X - orig.X, p.Y - orig.Y} | |
return grad.X * sp.X + grad.Y * sp.Y | |
} | |
type Noise2DContext struct { | |
rgradients []Vec2 | |
permutations []int | |
gradients [4]Vec2 | |
origins [4]Vec2 | |
} | |
func NewNoise2DContext(seed int) *Noise2DContext { | |
rnd := rand.New(rand.NewSource(int64(seed))) | |
n2d := new(Noise2DContext) | |
n2d.rgradients = make([]Vec2, 256) | |
n2d.permutations = rand.Perm(256) | |
for i := range n2d.rgradients { | |
n2d.rgradients[i] = random_gradient(rnd) | |
} | |
return n2d | |
} | |
func (n2d *Noise2DContext) get_gradient(x, y int) Vec2 { | |
idx := n2d.permutations[x & 255] + n2d.permutations[y & 255] | |
return n2d.rgradients[idx & 255] | |
} | |
func (n2d *Noise2DContext) get_gradients(x, y float32) { | |
x0f := math.Floor(float64(x)) | |
y0f := math.Floor(float64(y)) | |
x0 := int(x0f) | |
y0 := int(y0f) | |
x1 := x0 + 1 | |
y1 := y0 + 1 | |
n2d.gradients[0] = n2d.get_gradient(x0, y0) | |
n2d.gradients[1] = n2d.get_gradient(x1, y0) | |
n2d.gradients[2] = n2d.get_gradient(x0, y1) | |
n2d.gradients[3] = n2d.get_gradient(x1, y1) | |
n2d.origins[0] = Vec2{float32(x0f + 0.0), float32(y0f + 0.0)} | |
n2d.origins[1] = Vec2{float32(x0f + 1.0), float32(y0f + 0.0)} | |
n2d.origins[2] = Vec2{float32(x0f + 0.0), float32(y0f + 1.0)} | |
n2d.origins[3] = Vec2{float32(x0f + 1.0), float32(y0f + 1.0)} | |
} | |
func (n2d *Noise2DContext) Get(x, y float32) float32 { | |
p := Vec2{x, y} | |
n2d.get_gradients(x, y) | |
v0 := gradient(n2d.origins[0], n2d.gradients[0], p) | |
v1 := gradient(n2d.origins[1], n2d.gradients[1], p) | |
v2 := gradient(n2d.origins[2], n2d.gradients[2], p) | |
v3 := gradient(n2d.origins[3], n2d.gradients[3], p) | |
fx := smooth(x - n2d.origins[0].X) | |
vx0 := lerp(v0, v1, fx) | |
vx1 := lerp(v2, v3, fx) | |
fy := smooth(y - n2d.origins[0].Y) | |
return lerp(vx0, vx1, fy) | |
} | |
func main() { | |
symbols := []string{" ", "░", "▒", "▓", "█", "█"} | |
pixels := make([]float32, 256*256) | |
n2d := NewNoise2DContext(0) | |
for i := 0; i < 100; i++ { | |
for y := 0; y < 256; y++ { | |
for x := 0; x < 256; x++ { | |
v := n2d.Get(float32(x) * 0.1, | |
float32(y) * 0.1) | |
v = v * 0.5 + 0.5 | |
pixels[y*256+x] = v | |
} | |
} | |
} | |
out := bufio.NewWriter(os.Stdout) | |
for y := 0; y < 256; y++ { | |
for x := 0; x < 256; x++ { | |
fmt.Fprint(out, symbols[int(pixels[y*256+x] / 0.2)]) | |
} | |
fmt.Fprintln(out) | |
} | |
out.Flush() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env lua | |
local band = nil | |
if jit ~= nil then -- luajit has a different bitops module name | |
band = bit.band | |
else | |
band = bit32.band | |
end | |
local function lerp(a, b, v) | |
return a * (1 - v) + b * v | |
end | |
local function smooth(v) | |
return v * v * (3 - 2 * v) | |
end | |
local function random_gradient() | |
local v = math.random() * math.pi * 2.0 | |
return {x = math.cos(v), y = math.sin(v)} | |
end | |
local function gradient(orig, grad, p) | |
return grad.x * (p.x - orig.x) + grad.y * (p.y - orig.y) | |
end | |
local Noise2D = {} | |
Noise2D.__index = Noise2D | |
function Noise2D.new(seed) | |
math.randomseed(seed) | |
local rgradients = {} | |
for i = 1, 256 do | |
rgradients[i] = random_gradient() | |
end | |
local permutations = {} | |
for i = 1, 256 do | |
local j = math.random(i) | |
permutations[i] = permutations[j] | |
permutations[j] = i | |
end | |
return setmetatable({ | |
rgradients = rgradients, | |
permutations = permutations, | |
gradients = {}, | |
origins = {}, | |
}, Noise2D) | |
end | |
function Noise2D:get_gradient(x, y) | |
x = band(x, 255)+1 | |
y = band(y, 255)+1 | |
local idx = self.permutations[x] + self.permutations[y] | |
return self.rgradients[band(idx, 255)+1] | |
end | |
function Noise2D:get_gradients_and_origins(x, y) | |
local x0 = math.floor(x) | |
local y0 = math.floor(y) | |
local x1 = x0 + 1 | |
local y1 = y0 + 1 | |
self.gradients[1] = self:get_gradient(x0, y0) | |
self.gradients[2] = self:get_gradient(x1, y0) | |
self.gradients[3] = self:get_gradient(x0, y1) | |
self.gradients[4] = self:get_gradient(x1, y1) | |
self.origins[1] = {x = x0 + 0, y = y0 + 0} | |
self.origins[2] = {x = x0 + 1, y = y0 + 0} | |
self.origins[3] = {x = x0 + 0, y = y0 + 1} | |
self.origins[4] = {x = x0 + 1, y = y0 + 1} | |
end | |
function Noise2D:get(x, y) | |
local p = {x = x, y = y} | |
self:get_gradients_and_origins(x, y) | |
local v1 = gradient(self.origins[1], self.gradients[1], p) | |
local v2 = gradient(self.origins[2], self.gradients[2], p) | |
local v3 = gradient(self.origins[3], self.gradients[3], p) | |
local v4 = gradient(self.origins[4], self.gradients[4], p) | |
local fx = smooth(x - self.origins[1].x) | |
local vx1 = lerp(v1, v2, fx) | |
local vx2 = lerp(v3, v4, fx) | |
local fy = smooth(y - self.origins[1].y) | |
return lerp(vx1, vx2, fy) | |
end | |
local symbols = {' ', '░', '▒', '▓', '█', '█'} | |
local pixels = {} | |
for i = 1, 256*256 do | |
pixels[i] = "" | |
end | |
local n2d = Noise2D.new(os.clock()) | |
for i = 1, 100 do | |
for y = 1, 256 do | |
y = y - 1 | |
for x = 1, 256 do | |
x = x - 1 | |
local v = n2d:get(x * 0.1, y * 0.1) * 0.5 + 0.5 | |
pixels[(y*256+x)+1] = v | |
end | |
end | |
end | |
for y = 1, 256 do | |
y = y - 1 | |
for x = 1, 256 do | |
x = x - 1 | |
local idx = pixels[(y*256+x)+1] / 0.2 | |
io.write(symbols[math.floor(idx)+1]) | |
end | |
print("") | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/pypy | |
# encoding: utf-8 | |
from random import Random | |
import math | |
import sys | |
import time | |
def lerp(a, b, v): | |
return a * (1 - v) + b * v | |
def smooth(v): | |
return v * v * (3 - 2 * v) | |
def random_gradient(r): | |
v = r.random() * math.pi * 2.0 | |
return Vec2(math.cos(v), math.sin(v)) | |
def gradient(orig, grad, p): | |
sp = Vec2(p.x - orig.x, p.y - orig.y) | |
return grad.x * sp.x + grad.y * sp.y | |
class Vec2(object): | |
__slots__ = ('x', 'y') | |
def __init__(self, x, y): | |
self.x = x | |
self.y = y | |
class Noise2DContext(object): | |
__slots__ = ('rgradients', 'permutations', 'gradients', 'origins') | |
def __init__(self, seed): | |
self.rgradients = [] | |
self.permutations = [] | |
self.gradients = [None, None, None, None] | |
self.origins = [None, None, None, None] | |
r = Random(seed) | |
for i in xrange(256): | |
self.rgradients.append(random_gradient(r)) | |
for i in xrange(256): | |
self.permutations.append(i) | |
r.shuffle(self.permutations) | |
def get_gradient(self, x, y): | |
idx = self.permutations[x & 255] + self.permutations[y & 255] | |
return self.rgradients[idx & 255] | |
def get_gradients(self, x, y): | |
x0f = math.floor(x) | |
y0f = math.floor(y) | |
x0 = int(x0f) | |
y0 = int(y0f) | |
x1 = x0 + 1 | |
y1 = y0 + 1 | |
self.gradients[0] = self.get_gradient(x0, y0) | |
self.gradients[1] = self.get_gradient(x1, y0) | |
self.gradients[2] = self.get_gradient(x0, y1) | |
self.gradients[3] = self.get_gradient(x1, y1) | |
self.origins[0] = Vec2(x0f + 0.0, y0f + 0.0) | |
self.origins[1] = Vec2(x0f + 1.0, y0f + 0.0) | |
self.origins[2] = Vec2(x0f + 0.0, y0f + 1.0) | |
self.origins[3] = Vec2(x0f + 1.0, y0f + 1.0) | |
def get(self, x, y): | |
p = Vec2(x, y) | |
self.get_gradients(x, y) | |
v0 = gradient(self.origins[0], self.gradients[0], p) | |
v1 = gradient(self.origins[1], self.gradients[1], p) | |
v2 = gradient(self.origins[2], self.gradients[2], p) | |
v3 = gradient(self.origins[3], self.gradients[3], p) | |
fx = smooth(x - self.origins[0].x) | |
vx0 = lerp(v0, v1, fx) | |
vx1 = lerp(v2, v3, fx) | |
fy = smooth(y - self.origins[0].y) | |
return lerp(vx0, vx1, fy) | |
symbols = [' ', '░', '▒', '▓', '█', '█'] | |
pixels = [['' for i in xrange(256)] for i in xrange(256)] | |
n2d = Noise2DContext(time.time()) | |
for i in xrange(100): | |
for y in xrange(256): | |
for x in xrange(256): | |
v = n2d.get(x * 0.1, (y + (i * 128)) * 0.1) * 0.5 + 0.5 | |
s = symbols[int(v / 0.2)] | |
pixels[y][x] = s | |
for y in xrange(256): | |
for x in xrange(256): | |
sys.stdout.write(pixels[y][x]) | |
sys.stdout.write('\n') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Vec2 { | |
x: f32, | |
y: f32, | |
} | |
fn lerp(a: f32, b: f32, v: f32) -> f32 { | |
a * (1f32 - v) + b * v | |
} | |
fn smooth(v: f32) -> f32 { | |
v * v * (3f32 - 2f32 * v) | |
} | |
fn random_gradient(r: rand::Rng) -> Vec2 { | |
let v = r.gen_float() * float::consts::pi * 2.0; | |
Vec2{ | |
x: float::cos(v) as f32, | |
y: float::sin(v) as f32, | |
} | |
} | |
fn gradient(orig: Vec2, grad: Vec2, p: Vec2) -> f32 { | |
let sp = Vec2{x: p.x - orig.x, y: p.y - orig.y}; | |
grad.x * sp.x + grad.y + sp.y | |
} | |
struct Noise2DContext { | |
rgradients: ~[Vec2], | |
permutations: ~[int], | |
} | |
fn Noise2DContext() -> ~Noise2DContext { | |
let r = rand::Rng(); | |
let rgradients = do vec::from_fn(256) |_i| { random_gradient(r) }; | |
let mut permutations = do vec::from_fn(256) |i| { i as int }; | |
r.shuffle_mut(permutations); | |
~Noise2DContext{ | |
rgradients: move rgradients, | |
permutations: move permutations, | |
} | |
} | |
impl Noise2DContext { | |
fn get_gradient(x: int, y: int) -> Vec2 { | |
let idx = self.permutations[x & 255] + self.permutations[y & 255]; | |
self.rgradients[idx & 255] | |
} | |
fn get_gradients(gradients: &[mut Vec2 * 4], origins: &[mut Vec2 * 4], x: f32, y: f32) { | |
let x0f = float::floor(x as libc::c_double) as f32; | |
let y0f = float::floor(y as libc::c_double) as f32; | |
let x0 = x0f as int; | |
let y0 = y0f as int; | |
let x1 = x0 + 1; | |
let y1 = y0 + 1; | |
gradients[0] = self.get_gradient(x0, y0); | |
gradients[1] = self.get_gradient(x1, y0); | |
gradients[2] = self.get_gradient(x0, y1); | |
gradients[3] = self.get_gradient(x1, y1); | |
origins[0] = Vec2{x: x0f + 0f32, y: y0f + 0f32}; | |
origins[1] = Vec2{x: x0f + 1f32, y: y0f + 0f32}; | |
origins[2] = Vec2{x: x0f + 0f32, y: y0f + 1f32}; | |
origins[3] = Vec2{x: x0f + 1f32, y: y0f + 1f32}; | |
} | |
fn get(x: f32, y: f32) -> f32 { | |
let p = Vec2{x: x, y: y}; | |
let gradients: [mut Vec2 * 4] = [mut | |
Vec2{x:0f32, y:0f32}, | |
Vec2{x:0f32, y:0f32}, | |
Vec2{x:0f32, y:0f32}, | |
Vec2{x:0f32, y:0f32}, | |
]; | |
let origins: [mut Vec2 * 4] = [mut | |
Vec2{x:0f32, y:0f32}, | |
Vec2{x:0f32, y:0f32}, | |
Vec2{x:0f32, y:0f32}, | |
Vec2{x:0f32, y:0f32}, | |
]; | |
self.get_gradients(&gradients, &origins, x, y); | |
let v0 = gradient(origins[0], gradients[0], p); | |
let v1 = gradient(origins[1], gradients[1], p); | |
let v2 = gradient(origins[2], gradients[2], p); | |
let v3 = gradient(origins[3], gradients[3], p); | |
let fx = smooth(x - origins[0].x); | |
let vx0 = lerp(v0, v1, fx); | |
let vx1 = lerp(v2, v3, fx); | |
let fy = smooth(y - origins[0].y); | |
lerp(vx0, vx1, fy) | |
} | |
} | |
fn main() { | |
let symbols = [" ", "░", "▒", "▓", "█", "█"]; | |
let pixels = vec::to_mut(vec::from_elem(256*256, 0f32)); | |
let n2d = Noise2DContext(); | |
for int::range(0, 100) |_i| { | |
for int::range(0, 256) |y| { | |
for int::range(0, 256) |x| { | |
let v = n2d.get( | |
x as f32 * 0.1f32, | |
y as f32 * 0.1f32 | |
) * 0.5f32 + 0.5f32; | |
pixels[y*256+x] = v; | |
}; | |
}; | |
}; | |
for int::range(0, 256) |y| { | |
for int::range(0, 256) |x| { | |
io::print(symbols[pixels[y*256+x] / 0.2f32 as int]); | |
} | |
io::println(""); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/tclsh | |
set PI 3.1415926535 | |
proc lerp {a b v} { | |
return [expr {$a * (1 - $v) + $b * $v}] | |
} | |
proc smooth {v} { | |
return [expr {$v * $v * (3 - 2 * $v)}] | |
} | |
proc random_gradient {} { | |
global PI | |
set v [expr {rand() * $PI * 2}] | |
return [list [expr {cos($v)}] [expr {sin($v)}]] | |
} | |
proc gradient {orig grad p} { | |
set sp [list [expr {[lindex $p 0] - [lindex $orig 0]}]\ | |
[expr {[lindex $p 1] - [lindex $orig 1]}]] | |
return [expr {[lindex $grad 0] * [lindex $sp 0] +\ | |
[lindex $grad 1] * [lindex $sp 1]}] | |
} | |
proc n2d_new {seed} { | |
expr {srand($seed)} | |
set permutations [lrepeat 256 0] | |
set rgradients [lrepeat 256 0] | |
for {set i 0} {$i < 256} {incr i} { | |
lset rgradients $i [random_gradient] | |
} | |
for {set i 0} {$i < 256} {incr i} { | |
set j [expr {round(rand() * 65536) % ($i + 1)}] | |
lset permutations $i [lindex $permutations $j] | |
lset permutations $j $i | |
} | |
set n2d(permutations) $permutations | |
set n2d(rgradients) $rgradients | |
return [array get n2d] | |
} | |
proc n2d_get_gradient {ctx x y} { | |
upvar $ctx n2d | |
set idx [expr {[lindex $n2d(permutations) [expr {$x & 255}]] +\ | |
[lindex $n2d(permutations) [expr {$y & 255}]]}] | |
return [lindex $n2d(rgradients) [expr {$idx & 255}]] | |
} | |
proc n2d_get_gradients {ctx x y} { | |
upvar $ctx n2d | |
set x0f [expr {floor($x)}] | |
set y0f [expr {floor($y)}] | |
set x0 [expr {round($x0f)}] | |
set y0 [expr {round($y0f)}] | |
set x1 [expr {$x0 + 1}] | |
set y1 [expr {$y0 + 1}] | |
set n2d(gradients) [list [n2d_get_gradient n2d $x0 $y0]\ | |
[n2d_get_gradient n2d $x1 $y0]\ | |
[n2d_get_gradient n2d $x0 $y1]\ | |
[n2d_get_gradient n2d $x1 $y1]] | |
set n2d(origins) [list [list [expr {$x0f + 0}] [expr {$y0f + 0}]]\ | |
[list [expr {$x0f + 1}] [expr {$y0f + 0}]]\ | |
[list [expr {$x0f + 0}] [expr {$y0f + 1}]]\ | |
[list [expr {$x0f + 1}] [expr {$y0f + 1}]]] | |
} | |
proc n2d_get {ctx x y} { | |
upvar $ctx n2d | |
set p [list $x $y] | |
n2d_get_gradients n2d $x $y | |
set v0 [gradient [lindex $n2d(origins) 0] [lindex $n2d(gradients) 0] $p] | |
set v1 [gradient [lindex $n2d(origins) 1] [lindex $n2d(gradients) 1] $p] | |
set v2 [gradient [lindex $n2d(origins) 2] [lindex $n2d(gradients) 2] $p] | |
set v3 [gradient [lindex $n2d(origins) 3] [lindex $n2d(gradients) 3] $p] | |
set fx [smooth [expr {$x - [lindex [lindex $n2d(origins) 0] 0]}]] | |
set vx0 [lerp $v0 $v1 $fx] | |
set vx1 [lerp $v2 $v3 $fx] | |
set fy [smooth [expr {$y - [lindex [lindex $n2d(origins) 0] 1]}]] | |
return [lerp $vx0 $vx1 $fy] | |
} | |
proc main {} { | |
set symbols {{ } {░} {▒} {▓} {█} {█}} | |
set pixels [lrepeat [expr 256*256] 0] | |
array set n2d [n2d_new 0] | |
for {set i 0} {$i < 100} {incr i} { | |
for {set y 0} {$y < 256} {incr y} { | |
for {set x 0} {$x < 256} {incr x} { | |
set v [n2d_get n2d [expr {$x * 0.1}] [expr {$y * 0.1}]] | |
set v [expr {$v * 0.5 + 0.5}] | |
lset pixels [expr {$y*256+$x}] $v | |
} | |
} | |
} | |
for {set y 0} {$y < 256} {incr y} { | |
for {set x 0} {$x < 256} {incr x} { | |
set p [lindex $pixels [expr {$y*256+$x}]] | |
puts -nonewline [lindex $symbols [expr {round($p / 0.2)}]] | |
} | |
puts {} | |
} | |
} | |
main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env luajit | |
local ffi = require("ffi") | |
ffi.cdef [[ | |
typedef struct { float x, y; } vec3; | |
]] | |
local band = bit.band -- use luajit bitops always | |
local function lerp(a, b, v) | |
return a * (1 - v) + b * v | |
end | |
local function smooth(v) | |
return v * v * (3 - 2 * v) | |
end | |
local function random_gradient() | |
local v = math.random() * math.pi * 2.0 | |
return ffi.new("vec3", math.cos(v), math.sin(v)) | |
end | |
local function gradient(orig, grad, p) | |
return grad.x * (p.x - orig.x) + grad.y * (p.y - orig.y) | |
end | |
local Noise2D = {} | |
Noise2D.__index = Noise2D | |
function Noise2D.new(seed) | |
math.randomseed(seed) | |
local rgradients = ffi.new("vec3[256]") | |
for i = 0, 255 do | |
rgradients[i] = random_gradient() | |
end | |
local permutations = ffi.new("int[256]") | |
for i = 0, 255 do | |
local j = math.random(i) | |
permutations[i] = permutations[j] | |
permutations[j] = i | |
end | |
return setmetatable({ | |
rgradients = rgradients, | |
permutations = permutations, | |
gradients = ffi.new("vec3[4]"), | |
origins = ffi.new("vec3[4]"), | |
}, Noise2D) | |
end | |
function Noise2D:get_gradient(x, y) | |
x = band(x, 255) | |
y = band(y, 255) | |
local idx = self.permutations[x] + self.permutations[y] | |
return self.rgradients[band(idx, 255)] | |
end | |
function Noise2D:get_gradients_and_origins(x, y) | |
local x0 = math.floor(x) | |
local y0 = math.floor(y) | |
local x1 = x0 + 1 | |
local y1 = y0 + 1 | |
self.gradients[0] = self:get_gradient(x0, y0) | |
self.gradients[1] = self:get_gradient(x1, y0) | |
self.gradients[2] = self:get_gradient(x0, y1) | |
self.gradients[3] = self:get_gradient(x1, y1) | |
self.origins[0] = ffi.new("vec3", x0 + 0, y0 + 0) | |
self.origins[1] = ffi.new("vec3", x0 + 1, y0 + 0) | |
self.origins[2] = ffi.new("vec3", x0 + 0, y0 + 1) | |
self.origins[3] = ffi.new("vec3", x0 + 1, y0 + 1) | |
end | |
function Noise2D:get(x, y) | |
local p = ffi.new("vec3", x, y) | |
self:get_gradients_and_origins(x, y) | |
local v1 = gradient(self.origins[0], self.gradients[0], p) | |
local v2 = gradient(self.origins[1], self.gradients[1], p) | |
local v3 = gradient(self.origins[2], self.gradients[2], p) | |
local v4 = gradient(self.origins[3], self.gradients[3], p) | |
local fx = smooth(x - self.origins[0].x) | |
local vx1 = lerp(v1, v2, fx) | |
local vx2 = lerp(v3, v4, fx) | |
local fy = smooth(y - self.origins[0].y) | |
return lerp(vx1, vx2, fy) | |
end | |
local symbols = {' ', '░', '▒', '▓', '█', '█'} | |
local pixels = ffi.new("float[?]", 256*256) | |
local n2d = Noise2D.new(os.clock()) | |
for i = 1, 100 do | |
for y = 0, 255 do | |
for x = 0, 255 do | |
local v = n2d:get(x * 0.1, y * 0.1) * 0.5 + 0.5 | |
pixels[y*256+x] = v | |
end | |
end | |
end | |
for y = 0, 255 do | |
for x = 0, 255 do | |
local idx = pixels[y*256+x] / 0.2 | |
io.write(symbols[math.floor(idx)+1]) | |
end | |
print("") | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment