diff options
-rw-r--r-- | messages.cpp | 129 | ||||
-rw-r--r-- | messages.h | 65 | ||||
-rw-r--r-- | terrain_cache.cpp | 73 | ||||
-rw-r--r-- | terrain_cache.h | 51 | ||||
-rw-r--r-- | terrain_loader.cpp | 58 | ||||
-rw-r--r-- | terrain_loader.h | 27 | ||||
-rw-r--r-- | vector.cpp | 150 | ||||
-rw-r--r-- | vector.h | 50 |
8 files changed, 603 insertions, 0 deletions
diff --git a/messages.cpp b/messages.cpp new file mode 100644 index 0000000..7bff612 --- /dev/null +++ b/messages.cpp @@ -0,0 +1,129 @@ +#include "messages.h" + +using namespace message; + +/* MessageBase */ + +MessageBase::MessageBase() { + type = MSG_TYPE_NONE; +} + +void MessageBase::send(boost::asio::ip::tcp::socket& socket) { + boost::asio::write(socket, boost::asio::buffer(&type, sizeof(type))); + boost::asio::write(socket, b); +} + +std::size_t MessageBase::payload_size() { + return 0; +} + +void MessageBase::read(boost::asio::ip::tcp::socket& socket) { + boost::asio::streambuf::mutable_buffers_type buf = b.prepare(payload_size()); + std::size_t size = boost::asio::read(socket, buf); + b.commit(size); +} + +uint8_t MessageBase::read_type(boost::asio::ip::tcp::socket& socket) { + uint8_t type; + boost::asio::read(socket, boost::asio::buffer(&type, sizeof(uint8_t))); + + return type; +} + +/* Hello */ + +Hello::Hello() { + type = MSG_TYPE_HELLO; +} + +Hello::Hello(uint8_t version) { + type = MSG_TYPE_HELLO; + + std::ostream os(&b); + os.write((const char*)&version, sizeof(version)); +} + +std::size_t Hello::payload_size() { + return sizeof(uint8_t); +} + +uint8_t Hello::read_version() { + std::istream is(&b); + uint8_t version; + is.read((char*)&version, sizeof(version)); + b.consume(sizeof(version)); + + return version; +} + +/* Pos */ + +Pos::Pos() { + type = MSG_TYPE_POS; +} + +Pos::Pos(float x, float y, float z) { + type = MSG_TYPE_POS; + + std::ostream os(&b); + os.write((const char*)&x, sizeof(x)); + os.write((const char*)&y, sizeof(y)); + os.write((const char*)&z, sizeof(z)); +} + +std::size_t Pos::payload_size() { + return sizeof(float)*3; +} + +void Pos::get_pos(float& x, float& y, float& z) { + std::istream is(&b); + is.read((char*)&x, sizeof(x)); + is.read((char*)&y, sizeof(y)); + is.read((char*)&z, sizeof(z)); +} + +/* Chunk */ + +Chunk::Chunk() { + type = MSG_TYPE_CHUNK; + + got_coords = false; +} + +Chunk::Chunk(int64_t x, int64_t y) { + type = MSG_TYPE_CHUNK; + + std::ostream os(&b); + os.write((const char*)&x, sizeof(x)); + os.write((const char*)&y, sizeof(y)); + + got_coords = true; +} + +// TODO: move this elsewhere +const int chunk_size = 32; +const int chunk_size_total = chunk_size + 3; + +std::size_t Chunk::payload_size() { + return (got_coords ? sizeof(float)*chunk_size_total*chunk_size_total : sizeof(int64_t)*2); +} + +void Chunk::set_data(float *data) { + std::ostream os(&b); + os.write((const char*)data, sizeof(float)*chunk_size_total*chunk_size_total); +} + +float* Chunk::get_data() { + float *data = new float[chunk_size_total*chunk_size_total]; + std::istream is(&b); + is.read((char*)data, sizeof(float)*chunk_size_total*chunk_size_total); + + return data; +} + +void Chunk::get_coords(int64_t& x, int64_t& y) { + std::istream is(&b); + is.read((char*)&x, sizeof(x)); + is.read((char*)&y, sizeof(y)); + got_coords = true; +} diff --git a/messages.h b/messages.h new file mode 100644 index 0000000..021c175 --- /dev/null +++ b/messages.h @@ -0,0 +1,65 @@ +#ifndef MESSAGES_H +#define MESSAGES_H + +#include <boost/asio.hpp> + +namespace message { + +enum MessageType { + MSG_TYPE_NONE = 0, + MSG_TYPE_HELLO, + MSG_TYPE_POS, + MSG_TYPE_CHUNK +}; + +class MessageBase { + protected: + uint8_t type; + boost::asio::streambuf b; + + public: + MessageBase(); + virtual ~MessageBase() {}; + + void send(boost::asio::ip::tcp::socket& socket); + virtual std::size_t payload_size(); + virtual void read(boost::asio::ip::tcp::socket& socket); + + static uint8_t read_type(boost::asio::ip::tcp::socket& socket); +}; + +class Hello : public MessageBase { + public: + Hello(); + Hello(uint8_t version); + + virtual std::size_t payload_size(); + uint8_t read_version(); +}; + +class Pos : public MessageBase { + public: + Pos(); + Pos(float x, float y, float z); + + virtual std::size_t payload_size(); + void get_pos(float& x, float& y, float& z); +}; + +class Chunk : public MessageBase { + protected: + bool got_coords; + + public: + Chunk(); + Chunk(int64_t x, int64_t y); + + virtual std::size_t payload_size(); + void set_data(float *data); + float* get_data(); + void get_coords(int64_t& x, int64_t& y); +}; + +} + +#endif diff --git a/terrain_cache.cpp b/terrain_cache.cpp new file mode 100644 index 0000000..01cc161 --- /dev/null +++ b/terrain_cache.cpp @@ -0,0 +1,73 @@ +#include "terrain_cache.h" + +/* TerrainCacheObject */ + +TerrainCacheObject::TerrainCacheObject(TerrainCache *cache, int64_t x, int64_t y, unsigned int width, unsigned int height, float *heights) { + this->cache = cache; + this->x = x; + this->y = y; + this->width = width; + this->height = height; + if(heights) + this->heights = heights; + else + 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(fs::path root, size_t max_size) { + this->max_size = max_size; + tl = TerrainLoader::p(new TerrainLoader(root)); +} + +TerrainCache::TerrainCache(TerrainLoader::p loader, size_t max_size) { + this->max_size = max_size; + tl = loader; +} + +TerrainCache::~TerrainCache() { + caches.clear(); +} + +TerrainCacheObject::p TerrainCache::make_object(int64_t x, int64_t y, unsigned int width, unsigned int height, float *heights) { + TerrainCacheObject::p ob(new TerrainCacheObject(this, x, y, width, height, heights)); + + 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(int64_t x, int64_t y, unsigned int width, unsigned 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); +} + +void TerrainCache::add_chunk(float *heights, int64_t x, int64_t y, unsigned int width, unsigned int height) { + cache_map::iterator it = caches.find(intpair(x, y)); + if(it != caches.end()) + caches.erase(it); + + tl->save_chunk(heights, x, y, width, height); + make_object(x, y, width, height, heights); +} + +size_t TerrainCache::get_size() { + return caches.size(); +} diff --git a/terrain_cache.h b/terrain_cache.h new file mode 100644 index 0000000..dcc4f34 --- /dev/null +++ b/terrain_cache.h @@ -0,0 +1,51 @@ +#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; + int64_t x, y; + unsigned int width, height; + + TerrainCacheObject(TerrainCache *cache, int64_t x, int64_t y, unsigned int width, unsigned int height, float *heights = NULL); + virtual ~TerrainCacheObject(); +}; + +class TerrainCache { + friend class TerrainCacheObject; + + private: + typedef std::pair<int64_t, int64_t> intpair; + typedef std::map<intpair, TerrainCacheObject::p> cache_map; + + cache_map caches; + size_t max_size; + + TerrainCacheObject::p make_object(int64_t x, int64_t y, unsigned int width, unsigned int height, float *heights = NULL); + + public: + typedef boost::shared_ptr<TerrainCache> p; + + TerrainCache(fs::path root, size_t max_size); + TerrainCache(TerrainLoader::p loader, size_t max_size); + virtual ~TerrainCache(); + + TerrainLoader::p tl; + + TerrainCacheObject::p get_chunk(int64_t x, int64_t y, unsigned int width, unsigned int height); + void add_chunk(float *heights, int64_t x, int64_t y, unsigned int width, unsigned int height); + size_t get_size(); +}; + +#endif diff --git a/terrain_loader.cpp b/terrain_loader.cpp new file mode 100644 index 0000000..ef61e1e --- /dev/null +++ b/terrain_loader.cpp @@ -0,0 +1,58 @@ +#include "terrain_loader.h" + +#include <boost/format.hpp> +#include <boost/filesystem/fstream.hpp> + +#include <stdexcept> + +TerrainLoader::TerrainLoader(fs::path root) { + this->root = root; +} + +TerrainLoader::~TerrainLoader() { +} +float *TerrainLoader::get_chunk(int64_t x, int64_t y, unsigned int width, unsigned int height) { + if(has_chunk(x, y)) + return load_chunk(x, y, width, height); + return NULL; +} + +bool TerrainLoader::has_chunk(int64_t x, int64_t y) { + return fs::exists(root / (boost::format("%d.%d.chunk") % x % y).str()); +} + +// TODO: Handle big-endian platforms +void TerrainLoader::save_chunk(float *chunk, int64_t x, int64_t y, unsigned int width, unsigned int height) { + fs::path p = root / (boost::format("%d.%d.chunk") % x % y).str(); + fs::ofstream os(p, std::ios::out | std::ios::binary); + + uint64_t w = width; + uint64_t h = height; + os.write((const char*)&w, sizeof(w)); + os.write((const char*)&h, sizeof(h)); + + os.write((const char*)chunk, width*height * sizeof(float)); + os.close(); +} + +// TODO: Handle big-endian platforms +// NOTE: assumes width <= chunk_size+1, likewise for height +float *TerrainLoader::load_chunk(int64_t x, int64_t y, unsigned int width, unsigned int height) { + fs::path p = root / (boost::format("%d.%d.chunk") % x % y).str(); + fs::ifstream is(p, std::ios::in | std::ios::binary); + + uint64_t w, h; + w = h = 0; + is.read((char*)&w, sizeof(w)); + is.read((char*)&h, sizeof(h)); + + // TODO: should return w and h, fix calling code + if(w != width || h != height) + throw std::runtime_error("width or height doesn't match"); + + float *chunk = new float[width*height]; + is.read((char*)chunk, width*height*sizeof(float)); + is.close(); + + return chunk; +} diff --git a/terrain_loader.h b/terrain_loader.h new file mode 100644 index 0000000..f99fb09 --- /dev/null +++ b/terrain_loader.h @@ -0,0 +1,27 @@ +#ifndef TERRAIN_LOADER_H +#define TERRAIN_LOADER_H + +#include <boost/filesystem.hpp> +#include <boost/shared_ptr.hpp> + +namespace fs = boost::filesystem; + +class TerrainLoader { + private: + fs::path root; + + public: + typedef boost::shared_ptr<TerrainLoader> p; + + TerrainLoader(fs::path root); + virtual ~TerrainLoader(); + + float *generate_heights(int64_t x, int64_t y, unsigned int width, unsigned int height); + virtual float *get_chunk(int64_t x, int64_t y, unsigned int width, unsigned int height); + bool has_chunk(int64_t x, int64_t y); + void save_chunk(float *chunk, int64_t x, int64_t y, unsigned int width, unsigned int height); + float *load_chunk(int64_t x, int64_t y, unsigned int width, unsigned int height); + +}; + +#endif diff --git a/vector.cpp b/vector.cpp new file mode 100644 index 0000000..cf2c164 --- /dev/null +++ b/vector.cpp @@ -0,0 +1,150 @@ +#include "vector.h" + +#include <boost/format.hpp> + +#include <cmath> +#include <string> + +Vector2::Vector2() { + x = y = 0; +} + +Vector2::Vector2(const Vector2& v) { + x = v.x; + y = v.y; +} + +Vector2::Vector2(float x, float y) { + this->x = x; + this->y = y; +} + +bool Vector2::operator==(const Vector2& v) const { + return x == v.x && y == v.y; +} + +Vector2& Vector2::operator+=(const Vector2& v) { + x += v.x; + y += v.y; + return *this; +} + +Vector2 Vector2::operator+(const Vector2& v) { + return Vector2(*this) += v; +} + +Vector2& Vector2::operator-=(const Vector2& v) { + x -= v.x; + y -= v.y; + return *this; +} + +Vector2 Vector2::operator-(const Vector2& v) { + return Vector2(*this) -= v; +} + +Vector2& Vector2::operator*=(const float f) { + x *= f; + y *= f; + return *this; +} + +Vector2& Vector2::operator/=(const float f) { + x /= f; + y /= f; + return *this; +} + +float Vector2::length() { + return sqrtf(x*x + y*y); +} + +std::string Vector2::str() { + return (boost::format("[%.2f %.2f]") % x % y).str(); +} + +/** + * Vector3 + */ + +Vector3::Vector3() { + x = y = z = 0; +} + +Vector3::Vector3(const Vector3& v) : Vector2(v) { + z = v.z; +} + +Vector3::Vector3(float x, float y, float z) : Vector2(x, y) { + this->z = z; +} + +bool Vector3::operator==(const Vector3& v) { + return x == v.x && y == v.y && z == v.z; +} + +Vector3& Vector3::operator+=(const Vector3& v) { + x += v.x; + y += v.y; + z += v.z; + return *this; +} + +Vector3 Vector3::operator+(const Vector3& v) { + return Vector3(*this) += v; +} + +Vector3& Vector3::operator-=(const Vector3& v) { + x -= v.x; + y -= v.y; + z -= v.z; + return *this; +} + +Vector3 Vector3::operator-(const Vector3& v) { + return Vector3(*this) -= v; +} + +Vector3& Vector3::operator*=(const float f) { + x *= f; + y *= f; + z *= f; + return *this; +} + +Vector3 Vector3::operator*(const float f) { + return Vector3(*this) *= f; +} + +Vector3& Vector3::operator/=(const float f) { + x /= f; + y /= f; + z /= f; + return *this; +} + +Vector3 Vector3::operator/(const float f) { + return Vector3(*this) /= f; +} + +Vector3 Vector3::cross(const Vector3& v) { + return Vector3(y*v.z - z*v.y, + z*v.x - x*v.z, + x*v.y - y*v.x); +} + +float Vector3::dot(const Vector3& v) { + return x*v.x + y*v.y + z*v.z; +} + +Vector2 Vector3::xz() { + return Vector2(x, z); +} + +float Vector3::length() { + return sqrtf(x*x + y*y + z*z); +} + +std::string Vector3::str() { + return (boost::format("[%.2f %.2f %.2f]") % x % y % z).str(); +} diff --git a/vector.h b/vector.h new file mode 100644 index 0000000..a2a3192 --- /dev/null +++ b/vector.h @@ -0,0 +1,50 @@ +#ifndef VECTOR_H +#define VECTOR_H + +#include <boost/shared_ptr.hpp> + +#include <string> + +class Vector2 { + public: + float x, y; + + Vector2(); + Vector2(const Vector2& v); + Vector2(float x, float y); + bool operator==(const Vector2& v) const; + Vector2& operator+=(const Vector2& v); + Vector2 operator+(const Vector2& v); + Vector2& operator-=(const Vector2& v); + Vector2 operator-(const Vector2& v); + Vector2& operator*=(const float f); + Vector2& operator/=(const float f); + float length(); + std::string str(); +}; + +class Vector3 : public Vector2 { + public: + typedef boost::shared_ptr<Vector3> p; + float z; + + Vector3(); + Vector3(const Vector3& v); + Vector3(float x, float y, float z); + bool operator==(const Vector3& v); + Vector3& operator+=(const Vector3& v); + Vector3 operator+(const Vector3& v); + Vector3& operator-=(const Vector3& v); + Vector3 operator-(const Vector3& v); + Vector3& operator*=(const float f); + Vector3 operator*(const float f); + Vector3& operator/=(const float f); + Vector3 operator/(const float f); + Vector3 cross(const Vector3& v); + float dot(const Vector3& v); + Vector2 xz(); + float length(); + std::string str(); +}; + +#endif |