summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Bergli Heier <snakebite@jvnv.net>2011-05-14 23:22:05 +0200
committerJon Bergli Heier <snakebite@jvnv.net>2011-05-14 23:22:05 +0200
commite7e6a79f8bf2855b5d1d432613151e48d2d685da (patch)
tree147fbe4a4af633427958d1bf1dcbaaaf0c0a1e00
parent07ec7829e75a71fa7b70b513f0a2c7daeaea11d5 (diff)
Implemented terrain chunk caching.
-rw-r--r--Makefile.win323
-rw-r--r--scene.cpp4
-rw-r--r--terrain.cpp122
-rw-r--r--terrain.h13
-rw-r--r--terrain_cache.cpp57
-rw-r--r--terrain_cache.h45
-rw-r--r--terrain_loader.cpp90
-rw-r--r--terrain_loader.h25
8 files changed, 238 insertions, 121 deletions
diff --git a/Makefile.win32 b/Makefile.win32
index 91e3f22..c15c41c 100644
--- a/Makefile.win32
+++ b/Makefile.win32
@@ -11,8 +11,7 @@ else
endif
TARGET=foo.exe
-#OBJECTS=$(shell ls *.cpp | sed 's/cpp/o/')
-OBJECTS=gl.o gui.o main.o terrain.o scene.o shader.o tool.o vector.o video.o
+OBJECTS=gl.o gui.o main.o scene.o shader.o terrain_cache.o terrain.o terrain_loader.o tool.o vector.o video.o
ifeq ($(shell uname), Linux)
OBJECTS+=noiseutils/noiseutils.o
diff --git a/scene.cpp b/scene.cpp
index e371f74..f7db5c4 100644
--- a/scene.cpp
+++ b/scene.cpp
@@ -444,8 +444,8 @@ void Scene::render() {
float height = font->LineHeight();
glColor3f(1, 1, 1);
glTranslatef(0, video::height-height, 0);
- font->Render((boost::format("chunks: %d gravity: %d steps: %d")
- % terrain->chunks.size() % gravity % steps).str().c_str());
+ font->Render((boost::format("chunks: %d cache: %d gravity: %d steps: %d")
+ % terrain->chunks.size() % terrain->tc->get_size() % gravity % steps).str().c_str());
//font->Render((boost::format("%dx%d %d levels %d nodes tree creation time: %f steps: %d update: %d")
// % scene.qt->width % scene.qt->height % scene.qt->levels % scene.qt->nodes % scene.qt->init_time % steps % scene.qt->thread_running).str().c_str());
//glTranslatef(0, height, 0);
diff --git a/terrain.cpp b/terrain.cpp
index 1fd75db..f3f573d 100644
--- a/terrain.cpp
+++ b/terrain.cpp
@@ -3,20 +3,10 @@
#include "gl.h"
-#include <noise/noise.h>
-#include "noiseutils/noiseutils.h"
-#include <boost/format.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-
#include <cmath>
#include <queue>
#include <set>
-using namespace noise;
-
-namespace fs = boost::filesystem;
-
using std::min;
using std::max;
@@ -129,7 +119,7 @@ float Terrain::Node::get_height(float px, float py) {
/* Chunk */
-Terrain::Chunk::Chunk(Terrain *terrain, float x, float y, float width, float height) {
+Terrain::Chunk::Chunk(Terrain *terrain, float x, float y, float width, float height) : cache_obj(terrain->tc->get_chunk(x, y, width+1, height+1)) {
this->terrain = terrain;
this->x = x;
this->y = y;
@@ -139,7 +129,7 @@ Terrain::Chunk::Chunk(Terrain *terrain, float x, float y, float width, float hei
this->h_height = height+1;
this->vbo_object = this->node_count = this->vertices = 0;
this->nodes = NULL;
- heights = terrain->get_chunk(x, y, h_width, h_height);
+ heights = cache_obj->heights;
normals = new Vector3[(int)((h_width)*(h_height))];
calc_normals();
@@ -158,7 +148,6 @@ Terrain::Chunk::~Chunk() {
for(unsigned int i = 0; i < node_count; i++)
delete nodes[i];
delete[] nodes;
- delete[] heights;
delete[] normals;
}
@@ -281,11 +270,16 @@ Terrain::Node* Terrain::Chunk::find(float x, float y) {
void Terrain::Chunk::calc_normals() {
float *right, *left, *up, *down;
- right = left = up = down = NULL;
- right = terrain->get_chunk(this->x - chunk_size, this->y, h_width, h_height);
- left = terrain->get_chunk(this->x + chunk_size, this->y, h_width, h_height);
- up = terrain->get_chunk(this->x, this->y + chunk_size, h_width, h_height);
- down = terrain->get_chunk(this->x, this->y - chunk_size, h_width, h_height);
+
+ TerrainCacheObject::p right_ob = terrain->tc->get_chunk(this->x - chunk_size, this->y, h_width, h_height),
+ left_ob = terrain->tc->get_chunk(this->x + chunk_size, this->y, h_width, h_height),
+ up_ob = terrain->tc->get_chunk(this->x, this->y + chunk_size, h_width, h_height),
+ down_ob = terrain->tc->get_chunk(this->x, this->y - chunk_size, h_width, h_height);
+
+ right = right_ob->heights;
+ left = left_ob->heights;
+ up = up_ob->heights;
+ down = down_ob->heights;
for(int x = 0; x < h_width; x++) {
for(int y = 0; y < h_height; y++) {
@@ -343,98 +337,17 @@ void Terrain::Chunk::calc_normals() {
normals[x*h_height + y] = N;
}
}
-
- if(right)
- delete[] right;
- if(left)
- delete[] left;
- if(up)
- delete[] up;
- if(down)
- delete[] down;
}
Terrain::Terrain() {
+ tc = new TerrainCache(0, "map", 120);
}
Terrain::~Terrain() {
for(std::list<Chunk*>::iterator it = chunks.begin(); it != chunks.end(); it++) {
delete *it;
}
-}
-
-float *Terrain::generate_heights(int x, int y, int width, int height) {
- module::Perlin mod;
- mod.SetSeed(0);
-
- utils::NoiseMap heightmap;
- utils::NoiseMapBuilderPlane heightmap_builder;
-
- heightmap_builder.SetSourceModule(mod);
- heightmap_builder.SetDestNoiseMap(heightmap);
-
- heightmap_builder.SetDestSize(width, height);
- heightmap_builder.SetBounds((double)x / 100, (double)(x+width) / 100, (double)y / 100, (double)(y+height) / 100);
- heightmap_builder.Build();
-
- float *heights = new float[width*height];
- for(int i = 0; i < width; i++) {
- for(int j = 0; j < height; j++) {
- heights[i*height + j] = 10*(1+heightmap.GetValue(i, j));
- }
- }
-
- chunk_indices.insert(std::pair<int, int>(x, y));
- save_chunk(heights, x, y, width, height);
-
- return heights;
-}
-
-float *Terrain::get_chunk(int x, int y, int width, int height) {
- if(has_chunk(x, y))
- return load_chunk(x, y, width, height);
- else
- return generate_heights(x, y, width, height);
-}
-
-bool Terrain::has_chunk(int x, int y) {
- return fs::exists((boost::format("map/%d.%d.chunk") % x % y).str());
- //return chunk_indices.find(std::pair<int, int>(x, y)) != chunk_indices.end();
-}
-
-void Terrain::save_chunk(float *chunk, int x, int y, int width, int height) {
- fs::path p = (boost::format("map/%d.%d.chunk") % x % y).str();
- fs::ofstream os(p);
-
- os << width << std::endl;
- os << height << std::endl;
-
- for(int x = 0; x < width; x++)
- for(int y = 0; y < height; y++)
- os << chunk[x*height + y] << std::endl;
- os.close();
-}
-
-// NOTE: assumes width <= chunk_size+, likewise for height
-float *Terrain::load_chunk(int x, int y, int width, int height) {
- fs::path p = (boost::format("map/%d.%d.chunk") % x % y).str();
- fs::ifstream is(p);
-
- int w, h;
- is >> w;
- is >> h;
-
- float *chunk = new float[width*height];
- for(int x = 0; x < w; x++)
- for(int y = 0; y < h; y++) {
- float v;
- is >> v;
- if(x < width && y < height)
- chunk[x*height + y] = v;
- }
- is.close();
-
- return chunk;
+ delete tc;
}
void Terrain::raise(float x, float z, float radius, float focus, float strength, bool up) {
@@ -498,12 +411,6 @@ void Terrain::raise(float x, float z, float radius, float focus, float strength,
}
}
- // save chunks
- for(std::set<Chunk*>::iterator it = changed_chunks.begin(); it != changed_chunks.end(); it++) {
- Chunk *chunk = *it;
- save_chunk(chunk->heights, chunk->x, chunk->y, chunk->h_width, chunk->h_height);
- }
-
/* recalculate normals */
for(std::set<Chunk*>::iterator it = changed_chunks.begin(); it != changed_chunks.end(); it++) {
(*it)->calc_normals();
@@ -540,6 +447,7 @@ void Terrain::update(float x, float z) {
chunk_indices.erase(ind_it);
}
if((*it)->distance(x, z) > chunk_dist_threshold) {
+ delete *it;
it = chunks.erase(it);
}
}
diff --git a/terrain.h b/terrain.h
index 84abe26..6fa39b3 100644
--- a/terrain.h
+++ b/terrain.h
@@ -2,14 +2,11 @@
#define TERRAIN_H
#include "vector.h"
+#include "terrain_cache.h"
#include <list>
-#include <set>
class Terrain {
- private:
- std::set<std::pair<int, int> > chunk_indices;
-
public:
struct Chunk;
@@ -36,6 +33,7 @@ class Terrain {
float x, y, width, height;
int h_width, h_height;
float *heights;
+ TerrainCacheObject::p cache_obj;
Vector3 *normals;
size_t buf_size;
unsigned int vbo_object;
@@ -55,15 +53,10 @@ class Terrain {
static const int chunk_size = 32;
std::list<Chunk*> chunks;
+ TerrainCache *tc;
Terrain();
virtual ~Terrain();
- float *generate_heights(int x, int y, int width, int height);
- float *get_chunk(int x, int y, int width, int height);
- bool has_chunk(int x, int y);
- void save_chunk(float *chunk, int x, int y, int width, int height);
- float *load_chunk(int x, int y, int width, int height);
-
void raise(float x, float z, float radius, float focus, float strength, bool up = true);
void update(float x, float z);
diff --git a/terrain_cache.cpp b/terrain_cache.cpp
new file mode 100644
index 0000000..c40a1d6
--- /dev/null
+++ b/terrain_cache.cpp
@@ -0,0 +1,57 @@
+#include "terrain_cache.h"
+
+/* TerrainCacheObject */
+
+TerrainCacheObject::TerrainCacheObject(TerrainCache *cache, int x, int y, int width, int height) {
+ this->cache = cache;
+ this->x = x;
+ this->y = y;
+ this->width = width;
+ this->height = height;
+ this->heights = cache->tl->get_chunk(x, y, width, height);
+}
+
+TerrainCacheObject::~TerrainCacheObject() {
+ cache->tl->save_chunk(heights, x, y, width, height);
+ delete[] heights;
+}
+
+/* TerrainCache */
+
+TerrainCache::TerrainCache(int seed, fs::path root, size_t max_size) {
+ this->max_size = max_size;
+ tl = new TerrainLoader(seed, root);
+}
+
+TerrainCache::~TerrainCache() {
+ caches.clear();
+ delete tl;
+}
+
+TerrainCacheObject::p TerrainCache::make_object(int x, int y, int width, int height) {
+ TerrainCacheObject::p ob(new TerrainCacheObject(this, x, y, width, height));
+
+ if(caches.size() >= max_size) {
+ for(cache_map::iterator it = caches.begin(); it != caches.end(); it++) {
+ if(it->second.use_count() == 1) {
+ caches.erase(it);
+ break;
+ }
+ }
+ }
+
+ caches.insert(std::pair<intpair, TerrainCacheObject::p>(intpair(x, y), ob));
+ return ob;
+}
+
+TerrainCacheObject::p TerrainCache::get_chunk(int x, int y, int width, int height) {
+ cache_map::iterator it = caches.find(intpair(x, y));
+ if(it != caches.end())
+ return it->second;
+
+ return make_object(x, y, width, height);
+}
+
+size_t TerrainCache::get_size() {
+ return caches.size();
+}
diff --git a/terrain_cache.h b/terrain_cache.h
new file mode 100644
index 0000000..2ea4e15
--- /dev/null
+++ b/terrain_cache.h
@@ -0,0 +1,45 @@
+#ifndef TERRAIN_CACHE_H
+#define TERRAIN_CACHE_H
+
+#include "terrain_loader.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <map>
+#include <cstddef>
+
+class TerrainCache;
+
+struct TerrainCacheObject {
+ typedef boost::shared_ptr<TerrainCacheObject> p;
+
+ TerrainCache *cache;
+ float *heights;
+ int x, y, width, height;
+
+ TerrainCacheObject(TerrainCache *cache, int x, int y, int width, int height);
+ virtual ~TerrainCacheObject();
+};
+
+class TerrainCache {
+ friend class TerrainCacheObject;
+
+ private:
+ typedef std::pair<int, int> intpair;
+ typedef std::map<intpair, TerrainCacheObject::p> cache_map;
+
+ cache_map caches;
+ TerrainLoader *tl;
+ size_t max_size;
+
+ TerrainCacheObject::p make_object(int x, int y, int width, int height);
+
+ public:
+ TerrainCache(int seed, fs::path root, size_t max_size);
+ virtual ~TerrainCache();
+
+ TerrainCacheObject::p get_chunk(int x, int y, int width, int height);
+ size_t get_size();
+};
+
+#endif
diff --git a/terrain_loader.cpp b/terrain_loader.cpp
new file mode 100644
index 0000000..d908aca
--- /dev/null
+++ b/terrain_loader.cpp
@@ -0,0 +1,90 @@
+#include "terrain_loader.h"
+
+#include <noise/noise.h>
+#include "noiseutils/noiseutils.h"
+#include <boost/format.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+using namespace noise;
+
+TerrainLoader::TerrainLoader(int seed, fs::path root) {
+ this->seed = seed;
+ this->root = root;
+}
+
+TerrainLoader::~TerrainLoader() {
+}
+
+float *TerrainLoader::generate_heights(int x, int y, int width, int height) {
+ module::Perlin mod;
+ mod.SetSeed(seed);
+
+ utils::NoiseMap heightmap;
+ utils::NoiseMapBuilderPlane heightmap_builder;
+
+ heightmap_builder.SetSourceModule(mod);
+ heightmap_builder.SetDestNoiseMap(heightmap);
+
+ heightmap_builder.SetDestSize(width, height);
+ heightmap_builder.SetBounds((double)x / 100, (double)(x+width) / 100, (double)y / 100, (double)(y+height) / 100);
+ heightmap_builder.Build();
+
+ float *heights = new float[width*height];
+ for(int i = 0; i < width; i++) {
+ for(int j = 0; j < height; j++) {
+ heights[i*height + j] = 10*(1+heightmap.GetValue(i, j));
+ }
+ }
+
+ save_chunk(heights, x, y, width, height);
+
+ return heights;
+}
+
+float *TerrainLoader::get_chunk(int x, int y, int width, int height) {
+ float *h;
+ if(has_chunk(x, y))
+ h = load_chunk(x, y, width, height);
+ else
+ h = generate_heights(x, y, width, height);
+ return h;
+}
+
+bool TerrainLoader::has_chunk(int x, int y) {
+ return fs::exists(root / (boost::format("%d.%d.chunk") % x % y).str());
+}
+
+void TerrainLoader::save_chunk(float *chunk, int x, int y, int width, int height) {
+ fs::path p = root / (boost::format("%d.%d.chunk") % x % y).str();
+ fs::ofstream os(p);
+
+ os << width << std::endl;
+ os << height << std::endl;
+
+ for(int x = 0; x < width; x++)
+ for(int y = 0; y < height; y++)
+ os << chunk[x*height + y] << std::endl;
+ os.close();
+}
+
+// NOTE: assumes width <= chunk_size+1, likewise for height
+float *TerrainLoader::load_chunk(int x, int y, int width, int height) {
+ fs::path p = root / (boost::format("%d.%d.chunk") % x % y).str();
+ fs::ifstream is(p);
+
+ int w, h;
+ is >> w;
+ is >> h;
+
+ float *chunk = new float[width*height];
+ for(int x = 0; x < w; x++)
+ for(int y = 0; y < h; y++) {
+ float v;
+ is >> v;
+ if(x < width && y < height)
+ chunk[x*height + y] = v;
+ }
+ is.close();
+
+ return chunk;
+}
diff --git a/terrain_loader.h b/terrain_loader.h
new file mode 100644
index 0000000..7efa596
--- /dev/null
+++ b/terrain_loader.h
@@ -0,0 +1,25 @@
+#ifndef TERRAIN_LOADER_H
+#define TERRAIN_LOADER_H
+
+#include <boost/filesystem.hpp>
+
+namespace fs = boost::filesystem;
+
+class TerrainLoader {
+ private:
+ int seed;
+ fs::path root;
+
+ public:
+ TerrainLoader(int seed, fs::path root);
+ virtual ~TerrainLoader();
+
+ float *generate_heights(int x, int y, int width, int height);
+ float *get_chunk(int x, int y, int width, int height);
+ bool has_chunk(int x, int y);
+ void save_chunk(float *chunk, int x, int y, int width, int height);
+ float *load_chunk(int x, int y, int width, int height);
+
+};
+
+#endif