From c3258b0160c57f724832be89721f94d1fe1c69b3 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 16 Jan 2011 21:43:42 +0000 Subject: [PATCH] Functioning noise texture but underlying grid is visible --- include/ITexture.hpp | 2 +- include/Maths.hpp | 8 +-- src/Map.cpp | 13 +++-- src/NoiseTexture.cpp | 117 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 116 insertions(+), 24 deletions(-) diff --git a/include/ITexture.hpp b/include/ITexture.hpp index 3c298ef..a94a664 100644 --- a/include/ITexture.hpp +++ b/include/ITexture.hpp @@ -45,6 +45,6 @@ ITexturePtr load_texture(const string& a_file_name); ITexturePtr load_texture(IResourcePtr a_res, const string& a_file_name); // Generate Perlin noise -ITexturePtr make_noise_texture(int width, int height); +ITexturePtr make_noise_texture(int size, int resolution); #endif diff --git a/include/Maths.hpp b/include/Maths.hpp index 246bbf1..98951db 100644 --- a/include/Maths.hpp +++ b/include/Maths.hpp @@ -90,12 +90,12 @@ inline bool approx_equal(T a, T b) // A generic 3D vector template struct Vector { - inline Vector(T x = 0, T y = 0, T z = 0) + explicit inline Vector(T x = 0, T y = 0, T z = 0) { packed = Packed::pack(x, y, z); } - inline Vector(const typename Packed::Type& v) + explicit inline Vector(const typename Packed::Type& v) { packed = v; } @@ -124,7 +124,7 @@ struct Vector { // Scalar product inline T dot(const Vector&v) const { - const Vector tmp = packed * v.packed; + const Vector tmp(packed * v.packed); return tmp.x + tmp.y + tmp.z; } @@ -174,7 +174,7 @@ struct Vector { const typename Packed::Type diff = rhs.packed - packed; const T delta2 = EqTolerance::Value * EqTolerance::Value; - const Vector squared = diff * diff; + const Vector squared(diff * diff); return (squared.x <= delta2) && (squared.y <= delta2) diff --git a/src/Map.cpp b/src/Map.cpp index c47ad7b..18b83b9 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -650,7 +650,10 @@ void Map::build_mesh(int id, Point bot_left, Point top_right) // the meshes are built on the same frame ++frame_num; - buf->bind(make_noise_texture(256, 256)); + static ITexturePtr noise = make_noise_texture(50, 1024); + buf->bind(noise); + + const float tmul = 1.0f / float(top_right.x - bot_left.x + 1); for (int x = top_right.x-1; x >= bot_left.x; x--) { for (int y = bot_left.y; y < top_right.y; y++) { @@ -663,10 +666,10 @@ void Map::build_mesh(int id, Point bot_left, Point top_right) }; const IMeshBuffer::TexCoord tex_coords[4] = { - make_point(0.0f, 1.0f), - make_point(1.0f, 1.0f), - make_point(1.0f, 0.0f), - make_point(0.0f, 0.0f) + make_point(x * tmul, (y + 1) * tmul), + make_point((x + 1) * tmul, (y + 1) * tmul), + make_point((x + 1) * tmul, y * tmul), + make_point(x * tmul, y * tmul) }; const IMeshBuffer::TexCoord tex_order[6] = { diff --git a/src/NoiseTexture.cpp b/src/NoiseTexture.cpp index 19320aa..354b19a 100644 --- a/src/NoiseTexture.cpp +++ b/src/NoiseTexture.cpp @@ -18,34 +18,60 @@ #include "ITexture.hpp" #include "ILogger.hpp" #include "OpenGLHelper.hpp" +#include "Random.hpp" #include // XXX class NoiseTexture : public ITexture { public: - NoiseTexture(int w, int h); + NoiseTexture(int size, int res); ~NoiseTexture(); // ITexture interface void bind(); - int width() const { return width_; } - int height() const { return height_; } + int width() const { return resolution; } + int height() const { return resolution; } private: - const int width_, height_; + void build_gradients(); + float noise2d(float x, float y) const; + const VectorF& gradient(int x, int y) const; + float ease_curve(float t) const; + + const int size, resolution; GLuint texture; + VectorF *gradients; }; -NoiseTexture::NoiseTexture(int w, int h) - : width_(w), height_(h) +NoiseTexture::NoiseTexture(int size, int res) + : size(size), resolution(res), gradients(NULL) { - GLubyte* pixels = new GLubyte[w * h]; + GLubyte* pixels = new GLubyte[res * res]; - for (int x = 0; x < w; x++) { - for (int y = 0; y < h; y++) - pixels[x + (y*w)] = 127 + (random() % 32) - 16; - } + const int range = 40; + + build_gradients(); + const float step = float(size) / float(res); + + float xf, yf; + int x, y; + for (x = 0, xf = 0.0f; x < res; x++, xf += step) { + for (y = 0, yf = 0.0f; y < res; y++, yf += step) { + + float freq = 1.0f; + float sum = 0.0f; + + for (int i = 0; i < 8; i++) { + sum += noise2d(xf * freq, yf * freq) / freq; + freq *= 2.0f; + } + + const int ni = min(255, max(0, 150 + int(float(range) * sum))); + pixels[x + (y * res)] = ni; + } + } + glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); @@ -55,9 +81,12 @@ NoiseTexture::NoiseTexture(int w, int h) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Load the surface's data into the texture - glTexImage2D(GL_TEXTURE_2D, 0, 3, w, h, 0, + glTexImage2D(GL_TEXTURE_2D, 0, 3, res, res, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels); + delete[] gradients; + gradients = NULL; + delete[] pixels; } @@ -66,12 +95,72 @@ NoiseTexture::~NoiseTexture() glDeleteTextures(1, &texture); } +void NoiseTexture::build_gradients() +{ + static Uniform rnd(0.1f, 1.0f); + + gradients = new VectorF[size * size]; + + for (int x = 0; x < size; x++) { + for (int y = 0; y < size; y++) { + VectorF& v = gradients[x + y*size]; + + v.x = rnd(); + v.y = rnd(); + v.z = 0.0f; + + v.normalise(); + } + } +} + +float NoiseTexture::ease_curve(float t) const +{ + assert(t >= 0.0f && t <= 1.0f); + return (3 * t * t) - (2 * t * t * t); +} + +float NoiseTexture::noise2d(float x, float y) const +{ + // Perlin noise function + + const int ix = floorf(x); + const int iy = floorf(y); + + const VectorF xy = make_vector(x, y, 0.0f); + const VectorF x0y0 = make_vector(float(ix), float(iy), 0.0f); + const VectorF x1y0 = make_vector(float(ix + 1), float(iy), 0.0f); + const VectorF x0y1 = make_vector(float(ix), float(iy + 1), 0.0f); + const VectorF x1y1 = make_vector(float(ix + 1), float(iy + 1), 0.0f); + + const float s = gradient(ix, iy).dot(xy - x0y0); + const float t = gradient(ix + 1, iy).dot(xy - x1y0); + const float u = gradient(ix, iy + 1).dot(xy - x0y1); + const float v = gradient(ix + 1, iy + 1).dot(xy - x1y1); + + const float sx = ease_curve(x - float(ix)); + const float sy = ease_curve(y - float(iy)); + + const float a = s + sx * (t - s); + const float b = u + sx * (v - u); + + return (a + sy * (b - a)); +} + +const VectorF& NoiseTexture::gradient(int x, int y) const +{ + x = x % size; + y = y % size; + + return gradients[x + (y * size)]; +} + void NoiseTexture::bind() { glBindTexture(GL_TEXTURE_2D, texture); } -ITexturePtr make_noise_texture(int width, int height) +ITexturePtr make_noise_texture(int size, int resolution) { - return ITexturePtr(new NoiseTexture(width, height)); + return ITexturePtr(new NoiseTexture(size, resolution)); } -- 2.39.2