From 359adda883afb52deafcc04bc7089409e086dc6f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 17 Jan 2011 22:02:40 +0000 Subject: [PATCH] Cache noise data --- include/ITexture.hpp | 2 +- include/Paths.hpp | 28 +++++++++++ src/Config.cpp | 44 ++++------------- src/Map.cpp | 2 +- src/NoiseTexture.cpp | 111 ++++++++++++++++++++++++++++++++----------- src/Paths.cpp | 82 ++++++++++++++++++++++++++++++++ 6 files changed, 203 insertions(+), 66 deletions(-) create mode 100644 include/Paths.hpp create mode 100644 src/Paths.cpp diff --git a/include/ITexture.hpp b/include/ITexture.hpp index a94a664..d3ed1cd 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 size, int resolution); +ITexturePtr make_noise_texture(int size, int resolution, int base, int range); #endif diff --git a/include/Paths.hpp b/include/Paths.hpp new file mode 100644 index 0000000..227bb86 --- /dev/null +++ b/include/Paths.hpp @@ -0,0 +1,28 @@ +// +// Copyright (C) 2011 Nick Gasson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INC_PATHS_HPP +#define INC_PATHS_HPP + +#include "Platform.hpp" + +#include + +const boost::filesystem::path& get_cache_dir(); +const boost::filesystem::path& get_config_dir(); + +#endif diff --git a/src/Config.cpp b/src/Config.cpp index 715eeb8..3f09840 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -1,5 +1,5 @@ // -// Copyright (C) 2009 Nick Gasson +// Copyright (C) 2009-2011 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include "ILogger.hpp" #include "IXMLParser.hpp" #include "XMLBuilder.hpp" +#include "Paths.hpp" #include #include @@ -57,7 +58,7 @@ public: void text(const string& local_name, const string& a_string); private: - static string config_file_name(); + static boost::filesystem::path config_file_name(); template void set_from_string(const string& a_key, const string& a_string); @@ -68,7 +69,7 @@ private: typedef map ConfigMap; ConfigMap config_map; - string config_file; + boost::filesystem::path config_file; bool am_dirty; // Used by the XML parser @@ -88,7 +89,7 @@ Config::Config() log() << "Reading config from " << config_file; IXMLParserPtr parser = make_xml_parser("schemas/config.xsd"); - parser->parse(config_file, *this); + parser->parse(config_file.file_string(), *this); // Ignore all the set() calls made by the XML parser am_dirty = false; @@ -107,36 +108,9 @@ Config::~Config() } // Find the config file location on this platform -string Config::config_file_name() +boost::filesystem::path Config::config_file_name() { -#ifdef WIN32 - throw runtime_error("TODO: find config dir on Win32"); - -#else // #ifdef WIN32 - - // This is based on the XDG standard - // See: http://standards.freedesktop.org/basedir-spec/latest/ - - ostringstream ss; - - char* XDG_CONFIG_HOME = getenv("XDG_CONFIG_HOME"); - if (XDG_CONFIG_HOME == NULL || *XDG_CONFIG_HOME == '\0') { - warn() << "XDG_CONFIG_HOME not set: using ~/.config"; - - char* HOME = getenv("HOME"); - if (HOME == NULL) - throw runtime_error("$HOME not set"); - - ss << HOME << "/.config"; - } - else - ss << XDG_CONFIG_HOME; - - ss << "/" PACKAGE "/config.xml"; - - return ss.str(); - -#endif // #ifdef WIN32 + return get_config_dir() / "config.xml"; } void Config::start_element(const string& local_name, const AttributeSet& attrs) @@ -174,9 +148,7 @@ void Config::flush() log() << "Saving config to " << config_file; - create_directories(path(config_file).remove_filename()); - - ofstream ofs(config_file.c_str()); + ofstream ofs(config_file.file_string().c_str()); if (!ofs.good()) throw runtime_error("Failed to write to config file"); diff --git a/src/Map.cpp b/src/Map.cpp index 0be30bd..eabc0e7 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -650,7 +650,7 @@ void Map::build_mesh(int id, Point bot_left, Point top_right) // the meshes are built on the same frame ++frame_num; - static ITexturePtr noise = make_noise_texture(25, 512); + static ITexturePtr noise = make_noise_texture(25, 512, 190, 15); buf->bind(noise); const float tmul = 1.0f / float(top_right.x - bot_left.x + 1); diff --git a/src/NoiseTexture.cpp b/src/NoiseTexture.cpp index 9c6ba5b..4059853 100644 --- a/src/NoiseTexture.cpp +++ b/src/NoiseTexture.cpp @@ -19,12 +19,14 @@ #include "ILogger.hpp" #include "OpenGLHelper.hpp" #include "Random.hpp" +#include "Paths.hpp" -#include // XXX +#include +#include class NoiseTexture : public ITexture { public: - NoiseTexture(int size, int res); + NoiseTexture(int size, int res, int base, int range); ~NoiseTexture(); // ITexture interface @@ -33,40 +35,36 @@ public: int height() const { return resolution; } private: - void build_gradients(); + void build_noise(GLubyte *pixels); + void save_noise(const GLubyte *pixels); + void load_noise(GLubyte *pixels); float noise2d(float x, float y) const; - const VectorF& gradient(int x, int y) const; - float ease_curve(float t) const; + + boost::filesystem::path cache_name(); - const int size, resolution; + const int size, resolution, base, range; GLuint texture; }; -NoiseTexture::NoiseTexture(int size, int res) - : size(size), resolution(res) +NoiseTexture::NoiseTexture(int size, int res, int base, int range) + : size(size), resolution(res), base(base), range(range) { + using namespace boost::filesystem; + GLubyte* pixels = new GLubyte[res * res]; - const int range = 15; - - 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; + const path file = cache_name(); + + if (exists(file)) { + log() << "Loading cached noise from " << file; - for (int i = 0; i < 4; i++) { - sum += noise2d(xf * freq, yf * freq) / freq; - freq *= 2.0f; - } + load_noise(pixels); + } + else { + log() << "Caching noise texture in " << file; - const int ni = min(255, max(0, 190 + int(float(range) * sum))); - pixels[x + (y * res)] = ni; - } + build_noise(pixels); + save_noise(pixels); } glGenTextures(1, &texture); @@ -89,6 +87,63 @@ NoiseTexture::~NoiseTexture() glDeleteTextures(1, &texture); } +void NoiseTexture::build_noise(GLubyte* pixels) +{ + const float step = float(size) / float(resolution); + + float xf, yf; + int x, y; + for (x = 0, xf = 0.0f; x < resolution; x++, xf += step) { + for (y = 0, yf = 0.0f; y < resolution; 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, base + int(float(range) * sum))); + pixels[x + (y * resolution)] = ni; + } + } + +} + +void NoiseTexture::save_noise(const GLubyte* pixels) +{ + const string fname = cache_name().file_string(); + + ofstream f; + f.open(fname.c_str(), ios::out | ios::binary); + if (!f.is_open()) + throw runtime_error("Failed to create " + fname); + + f.write(reinterpret_cast(pixels), resolution * resolution); +} + +void NoiseTexture::load_noise(GLubyte *pixels) +{ + const string fname = cache_name().file_string(); + + ifstream f; + f.open(fname.c_str(), ios::in | ios::binary); + if (!f.is_open()) + throw runtime_error("Failed to open " + fname); + + f.read(reinterpret_cast(pixels), resolution * resolution); +} + +boost::filesystem::path NoiseTexture::cache_name() +{ + ostringstream ss; + ss << "noise_" << size << "_" << resolution << "_" + << base << "_" << range << ".dat"; + + return get_cache_dir() / ss.str(); +} + static inline float fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); @@ -177,7 +232,7 @@ void NoiseTexture::bind() glBindTexture(GL_TEXTURE_2D, texture); } -ITexturePtr make_noise_texture(int size, int resolution) +ITexturePtr make_noise_texture(int size, int resolution, int base, int range) { - return ITexturePtr(new NoiseTexture(size, resolution)); + return ITexturePtr(new NoiseTexture(size, resolution, base, range)); } diff --git a/src/Paths.cpp b/src/Paths.cpp new file mode 100644 index 0000000..a86f585 --- /dev/null +++ b/src/Paths.cpp @@ -0,0 +1,82 @@ +// +// Copyright (C) 2011 Nick Gasson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "Paths.hpp" +#include "ILogger.hpp" + +#include +#include + +#include + +using namespace boost::filesystem; + +#ifdef WIN32 +#error "Implement path functions for Win32" +#endif + +// The UNIX code is based on the XDG standard +// See: http://standards.freedesktop.org/basedir-spec/latest/ + +static void xdg_dir(ostream& os, const char* env, const char *def) +{ + const char* env_value = getenv(env); + if (env_value == NULL || *env_value == '\0') { + warn() << env << " not set: using ~/" << def; + + const char* home = getenv("HOME"); + if (home == NULL) + throw runtime_error("$HOME not set"); + + os << home << "/" << def; + } + else + os << env_value; +} + +const path& get_config_dir() +{ + static boost::optional cached_path; + + if (!cached_path) { + ostringstream ss; + xdg_dir(ss, "XDG_CONFIG_HOME", ".config"); + ss << "/" << PACKAGE; + + cached_path.reset(ss.str()); + create_directories(*cached_path); + + } + + return *cached_path; +} + +const path& get_cache_dir() +{ + static boost::optional cached_path; + + if (!cached_path) { + ostringstream ss; + xdg_dir(ss, "XDG_CACHE_HOME", ".cache"); + ss << "/" << PACKAGE; + + cached_path.reset(ss.str()); + create_directories(*cached_path); + } + + return *cached_path; +} -- 2.39.2