From ccc57ec2d2b897e5b93252e8e5d3a95d55774357 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sat, 21 Jun 2014 02:46:50 +1000 Subject: [PATCH] Basic perlin noise is working --- mapgen/map_generator.cpp | 100 ++++++++++++++++++++------------------- mapgen/map_generator.hpp | 8 +++- pseudocode.txt | 1 - src/shell_scene.cpp | 38 ++++++++++++--- utils/simple_rng.hpp | 15 +++--- 5 files changed, 98 insertions(+), 64 deletions(-) delete mode 100644 pseudocode.txt diff --git a/mapgen/map_generator.cpp b/mapgen/map_generator.cpp index 31ced51..49ca22e 100644 --- a/mapgen/map_generator.cpp +++ b/mapgen/map_generator.cpp @@ -21,70 +21,74 @@ */ #include "map_generator.hpp" -#include "maths.hpp" +#include "vector2.hpp" #include -//it's either this, or dealing with floating points -struct Coord { - int x, y; -}; +//------------------------- +//Utility functions +//------------------------- -//std::abs() only uses floating points -int absolute(int i) { - return i > 0 ? i : -i; +//snap to a grid (floating point version) +static double snap(double x, double base) { + return floor(x / base) * base; } -//calculate how far away a query point is from a grid point -Coord calcDist(Coord gridPoint, Coord queryPoint) { - int i = absolute(queryPoint.x - gridPoint.x); - int j = absolute(queryPoint.y - gridPoint.y); - return {i, j}; +//A.K.A.: the dot product +static double scalarProduct(Vector2 lhs, Vector2 rhs) { + return lhs.x * rhs.x + lhs.y * rhs.y; } -//calculate the amount of influence a distance will have within a certain sized area -int calcInfluence(Coord dist, int width, int height) { - //inverted distance - Coord i = {width - dist.x, height - dist.y}; - //essentially calculating the length - return sqrt(i.x*i.x + i.y*i.y); +//curved interpolation +static double curve(double x) { + //param: 0 to 1 inclusive + return 3.0 * pow(x, 2.0) - 2.0 * pow(x, 3.0); } -//determine the scaled value from the grid point -int calcScale(int influence, int gridValue, int pointValue) { - /* TODO - * (influence / {width, height}.Length()) //percentage to interpolate - * poingValue - gridValue //difference - * return percentage * difference //scale - */ - return gridValue; +//------------------------- +//Public methods +//------------------------- + +Vector2 MapGenerator::RawNoise(Vector2 const& gridPoint) { + double angle = rng(gridPoint.x * 0xffff + gridPoint.y); + Vector2 v = {cos(angle), sin(angle)}; + v.Normalize(); + return v; } -int MapGenerator::Noise(int x, int y, int width, int height) { - Coord queryPoint = {x, y}; +double MapGenerator::Influence(Vector2 const& gridPoint, Vector2 const& queryPoint, double width, double height) { + //note: inverting the distance here, so the smaller the distance the more influence it has + Vector2 distance = queryPoint - gridPoint; + Vector2 inverted = {width - distance.x, height - distance.y}; + double ret = scalarProduct(RawNoise(gridPoint), inverted); + return ret > 0 ? ret : -ret; +} + +double MapGenerator::ScaledNoise(double x, double y, double width, double height) { + Vector2 queryPoint = {x, y}; //the "grid points" - Coord tl = {snap(x, width), snap(y, height)}; - Coord tr = {tl.x + width, tl.y}; - Coord bl = {tl.x, tl.y + height}; - Coord br = {tl.x + width, tl.y + height}; + Vector2 tl = {snap(x, width), snap(y, height)}; + Vector2 tr = {tl.x + width, tl.y}; + Vector2 bl = {tl.x, tl.y + height}; + Vector2 br = {tl.x + width, tl.y + height}; - //get the distance from the query, and subsequently the influence - int tlInfluence = calcInfluence(calcDist(tl, queryPoint), width, height); - int trInfluence = calcInfluence(calcDist(tr, queryPoint), width, height); - int blInfluence = calcInfluence(calcDist(bl, queryPoint), width, height); - int brInfluence = calcInfluence(calcDist(br, queryPoint), width, height); + //influence equasion + double s = Influence(tl, queryPoint, width, height); + double t = Influence(tr, queryPoint, width, height); + double u = Influence(bl, queryPoint, width, height); + double v = Influence(br, queryPoint, width, height); - //now combine the grid's values with the influence values - int tlScale = calcScale(tlInfluence, RawNoise(tl.x, tl.y), RawNoise(queryPoint.x, queryPoint.y)); - int trScale = calcScale(trInfluence, RawNoise(tr.x, tr.y), RawNoise(queryPoint.x, queryPoint.y)); - int blScale = calcScale(blInfluence, RawNoise(bl.x, bl.y), RawNoise(queryPoint.x, queryPoint.y)); - int brScale = calcScale(brInfluence, RawNoise(br.x, br.y), RawNoise(queryPoint.x, queryPoint.y)); - - //Finally, apply each scale to the raw value, resulting in the height map - return tlScale + trScale + blScale + brScale + RawNoise(queryPoint.x, queryPoint.y); + //Finally, calc the value + double a = s + curve((t - s) / width); + double b = u + curve((v - u) / width); + return curve((b - a) / height); } -int MapGenerator::RawNoise(int x, int y) { - return (x * 11235 + y * 81321 + 3455) % 256; +double MapGenerator::ScaleOctave(double x, double y, double width, double height, double octave) { + double ret = 0; + if (octave > 1) { + ret += ScaleOctave(x, y, width/2, height/2, octave-1); + } + return ret / octave + ScaledNoise(x, y, width, height); } \ No newline at end of file diff --git a/mapgen/map_generator.hpp b/mapgen/map_generator.hpp index 49cdb72..faf429b 100644 --- a/mapgen/map_generator.hpp +++ b/mapgen/map_generator.hpp @@ -24,13 +24,17 @@ #include "simple_rng.hpp" +#include "vector2.hpp" + class MapGenerator { public: MapGenerator() = default; ~MapGenerator() = default; - int Noise(int x, int y, int width, int height); - int RawNoise(int x, int y); + Vector2 RawNoise(Vector2 const&); + double Influence(Vector2 const& gridPoint, Vector2 const& queryPoint, double width, double height); + double ScaledNoise(double x, double y, double width, double height); + double ScaleOctave(double x, double y, double width, double height, double octave); private: SimpleRNG rng; diff --git a/pseudocode.txt b/pseudocode.txt deleted file mode 100644 index 25391a9..0000000 --- a/pseudocode.txt +++ /dev/null @@ -1 +0,0 @@ -All coordinates have a random value assigned to them \ No newline at end of file diff --git a/src/shell_scene.cpp b/src/shell_scene.cpp index c8a62ac..7cf9468 100644 --- a/src/shell_scene.cpp +++ b/src/shell_scene.cpp @@ -27,27 +27,53 @@ //Public access members //------------------------- +static double max = 0; +static double min = 0; + void setPixel(SDL_Surface* const dest, int x, int y, int colour) { *(static_cast(dest->pixels) + dest->w * y + x) = colour; } +int convertToColour(SDL_PixelFormat* format, double x) { + //track the max value + max = x > max ? x : max; + min = x < min ? x : min; + + if (x > 1) { + return SDL_MapRGB(format, 255, 0, 0); + } + + if (x < 0) { + return SDL_MapRGB(format, 0, 255, 0); + } + + if (x == 0) { + return SDL_MapRGB(format, 0, 0, 255); + } + + return SDL_MapRGB(format, 255*x, 255*x, 255*x); +} + ShellScene::ShellScene() { //test the generator - int width = 80; - int height = 80; + int width = 256; + int height = 256; image.CreateSurface(GetScreen()->w, GetScreen()->h); - int value = 0; - int colour = 0; + double value; + int colour; + std::cout << "Beggining generation" << std::endl; for (int i = 0; i < image.GetSurface()->w; i++) { for (int j = 0; j < image.GetSurface()->h; j++) { - value = generator.Noise(i, j, width, height); - colour = SDL_MapRGB(image.GetSurface()->format, value, value, value); + value = generator.ScaleOctave(i, j, width, height, 8); + colour = convertToColour(image.GetSurface()->format, value); setPixel(image.GetSurface(), i, j, colour); } } std::cout << "Finished generation" << std::endl; + std::cout << "Max: " << max << std::endl; + std::cout << "Min: " << min << std::endl; } ShellScene::~ShellScene() { diff --git a/utils/simple_rng.hpp b/utils/simple_rng.hpp index 35cf08f..52ca91b 100644 --- a/utils/simple_rng.hpp +++ b/utils/simple_rng.hpp @@ -22,20 +22,21 @@ #ifndef SIMPLERNG_HPP_ #define SIMPLERNG_HPP_ +//a simple, stateless, random number generator class SimpleRNG { public: - SimpleRNG() { SetSeed(8891); } - SimpleRNG(int x) { SetSeed(x); } + SimpleRNG() { SetSeed(8891.0); } + SimpleRNG(double x) { SetSeed(x); } - int SetSeed(int s) { return seed = s & 0xFFFF; } - int GetSeed() { return seed; } + double SetSeed(double s) { return seed = s; } + double GetSeed() { return seed; } - int operator()(int x) { - return SetSeed((x + seed) * 11235 + 81321); + double operator()(double x) { + return (x + seed) * 11235.0 + 81321.0; }; private: - int seed; + double seed; }; #endif \ No newline at end of file