CTestTestfile.cmake
_deps
libdragonblocks.so
-dragonblockslauncher
+dragonblocks.bin
oprofile_data/
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
-add_subdirectory("${PROJECT_SOURCE_DIR}/src/dragonblocks/")
-add_subdirectory("${PROJECT_SOURCE_DIR}/src/dragonblockslauncher/")
+add_library(dragonblocks SHARED
+ src/animations.cpp
+ src/async_mgr.cpp
+ src/block.cpp
+ src/block_def.cpp
+ src/box_vertices.cpp
+ src/camera.cpp
+ src/chunk.cpp
+ src/client.cpp
+ src/entity.cpp
+ src/face_dir.cpp
+ src/game.cpp
+ src/gl.cpp
+ src/input_handler.cpp
+ src/local_entity.cpp
+ src/local_player.cpp
+ src/map.cpp
+ src/mapgen.cpp
+ src/mesh.cpp
+ src/render_engine.cpp
+ src/scene.cpp
+ src/shader_program.cpp
+ src/texture.cpp
+ src/tile_def.cpp
+ src/window.cpp
+)
+
+target_link_libraries(dragonblocks
+ GL
+ GLEW
+ glfw
+)
+
+target_include_directories(dragonblocks PUBLIC
+ "${PROJECT_SOURCE_DIR}/lib/"
+)
+
+add_executable(dragonblocks.bin src/launcher/main.c)
+
+target_link_libraries(dragonblocks.bin dl)
--- /dev/null
+// Just some code to use later when C++ Runtime Mods are introduced
+
+class DynamicLibrary
+{
+ public:
+ std::string filename;
+ std::string error;
+ bool success;
+ void *handle;
+ DynamicLibrary(std::string);
+};
+DynamicLibrary *loadDynamicLibrary(std::string);
+
+DynamicLibrary::DynamicLibrary(std::string f)
+{
+ filename = f;
+
+ handle = dlmopen(LM_ID_BASE, filename.c_str(), RTLD_NOW | RTLD_GLOBAL);
+
+ if (handle) {
+ success = true;
+ } else {
+ error = dlerror();
+ success = false;
+ }
+}
--- /dev/null
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+#include <queue>
+#include "udp_socket.hpp"
+
+namespace dragonblocks
+{
+ class NetworkMgr
+ {
+ public:
+ class IPeer
+ {
+ public:
+ UDPSocket::Address *address;
+ NetworkMgr *network_mgr;
+ };
+
+ class INamespace
+ {
+ public:
+ virtual void handle(Packet *);
+ };
+
+ UDPSocket *socket;
+ std::queue<Packet *> out_queue;
+ std::set<IPeer *> peers_set;
+ std::map<Address *, IPeer *> peers;
+ void sendPacket(Packet *);
+ void disconnectPeer(IPeer *);
+ std::map<std::string, INamespace *> namespaces;
+ };
+}
--- /dev/null
+#pragma once
+
+#include <sstream>
+
+namespace dragonblocks
+{
+ class Connection;
+
+ class NetworkPacket
+ {
+ public:
+ enum Type
+ {
+ INVALID,
+ TOSERVER_HELLO,
+ TOCLIENT_HELLO,
+ TOSERVER_BYE,
+ TOCLIENT_BYE,
+ TYPE_COUNT,
+ };
+
+ std::stringstream content;
+
+ NetworkPacket() = default;
+ NetworkPacket(const Type &);
+ NetworkPacket(const NetworkPacket &) = default;
+
+ private:
+ Type type = INVALID;
+ };
+}
--- /dev/null
+#include <stdexcept>
+#include "connection.hpp"
+
+using namespace std;
+using namespace dragonblocks;
+
+void Connection::setAddress(const string &addr)
+{
+ if(inet_pton(AF_INET, addr.c_str(), &address.sin_addr) <= 0)
+ throw runtime_error(string("Invalid address: ") + addr);
+}
+
+
--- /dev/null
+#pragma once
+
+#include <string>
+#include <queue>
+#include "network_packet.hpp"
+
+namespace dragonblocks
+{
+ std::queue<NetworkPacket> in_packets;
+ std::queue<NetworkPacket> out_packets;
+}
--- /dev/null
+#include <stdexcept>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include "udp_socket.hpp"
+
+#define PACKSIZE DRAGONBLOCKS_UPD_SOCKET_PACKAGE_SIZE
+
+using namespace std;
+using namespace dragonblocks;
+
+UDPSocket::Address::Address(const string &adr, int port)
+{
+ address.sin_family = AF_INET;
+ address.sin_port = htons(port);
+ inet_pton(AF_INET, adr.c_str(), &address.sin_addr);
+}
+void UDPSocket::connect()
+{
+ if (::connect(sockfd, (struct sockaddr *)&address.address, address.length) < 0)
+ throw runtime_error("Connection failed");
+}
+
+void UDPSocket::bind()
+{
+ if (::bind(sockfd, (struct sockaddr *)&address.address, address.length) < 0)
+ throw runtime_error("Bind failed");
+}
+
+void UDPSocket::close()
+{
+ ::close(sockfd);
+}
+
+void UDPSocket::send(const std::string &str, Address *addr)
+{
+ if (! addr) {
+ addr = &address;
+ }
+ sendto(sockfd, str.c_str(), min((int)str.size(), PACKSIZE), MSG_CONFIRM, (struct sockaddr *)&addr->address, addr->length);
+}
+
+string UDPSocket::recv(Address *addr)
+{
+ if (! addr) {
+ addr = &address;
+ }
+ char buffer[PACKSIZE + 1] = {0}; // include \0 at the end
+ recvfrom(sockfd, buffer, PACKSIZE, MSG_WAITALL, (struct sockaddr *)&addr->address, (socklen_t *)&addr->length);
+ return buffer;
+}
+
+UDPSocket::UDPSocket(const string &adr, int port) : address(adr, port)
+{
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+}
--- /dev/null
+#pragma once
+
+#include <string>
+#include <netinet/in.h>
+
+#define DRAGONBLOCKS_UPD_SOCKET_PACKAGE_SIZE 1024
+
+namespace dragonblocks
+{
+ class UDPSocket
+ {
+ public:
+ class Address
+ {
+ public:
+ struct sockaddr_in address;
+ int length;
+
+ Address() = default;
+ Address(const std::string &, int);
+ };
+
+ void connect();
+ void bind();
+ void close();
+ void send(const std::string &, Address * = nullptr); // server specifies address
+ std::string recv(Address * = nullptr); // server provides a buffer for the address
+
+ UDPSocket(const std::string &, int);
+
+ private:
+ int sockfd;
+ Address address; // for client, this is the address of the server; for server it is the own address.
+ };
+}
gl_Position = projection * cameraRelCoords;\r
ourTexCoord = aTexCoord;\r
}\r
+\r
--- /dev/null
+#include <glm/gtc/constants.hpp>
+#include "animations.hpp"
+
+using namespace glm;
+using namespace dragonblocks;
+
+vec3 FlyInAnimation::getPos(vec3 pos)
+{
+ pos.y -= offset * time_left / last_for;
+ return pos;
+}
+
+FlyInAnimation::FlyInAnimation(double l, double o, void (*on)(void *), void *e) : Mesh::IAnimation(l, on, e), last_for(l), offset(o)
+{
+}
+
+vec3 GrowAnimation::getSize(vec3 size)
+{
+ size *= 1 - time_left / last_for;
+ return size;
+}
+
+GrowAnimation::GrowAnimation(double l, void (*o)(void *), void *e) : Mesh::IAnimation(l, o, e), last_for(l)
+{
+}
+
+float RotateAnimation::getRotationAngle(float rotation_angle)
+{
+ rotation_angle += glfwGetTime() * speed * pi<float>() * 2;
+ return rotation_angle;
+}
+
+RotateAnimation::RotateAnimation(double s) : speed(s)
+{
+}
--- /dev/null
+#pragma once
+
+#include "gl.hpp"
+#include "mesh.hpp"
+
+namespace dragonblocks
+{
+ class FlyInAnimation : public Mesh::IAnimation
+ {
+ public:
+ double last_for;
+ double offset;
+
+ glm::vec3 getPos(glm::vec3);
+
+ FlyInAnimation(double = 0.4, double = 20.0, void (*)(void *) = nullptr, void * = nullptr);
+ };
+
+ class GrowAnimation : public Mesh::IAnimation
+ {
+ public:
+ double last_for;
+
+ glm::vec3 getSize(glm::vec3);
+
+ GrowAnimation(double = 0.25, void (*)(void *) = nullptr, void * = nullptr);
+ };
+
+ class RotateAnimation : public Mesh::IAnimation
+ {
+ public:
+ double speed;
+
+ float getRotationAngle(float);
+
+ RotateAnimation(double = 1.0);
+ };
+}
--- /dev/null
+#include <iostream>
+#include <set>
+#include "async_mgr.hpp"
+
+using namespace std;
+using namespace dragonblocks;
+
+void AsyncMgr::ITask::doAsyncTask()
+{
+}
+
+void AsyncMgr::addTask(AsyncMgr::ITask *t)
+{
+ mtx.lock();
+ queued_jobs.push_back(t);
+ mtx.unlock();
+}
+
+void AsyncMgr::run()
+{
+ while (true) {
+ set<AsyncMgr::ITask *> active_set;
+ mtx.lock();
+ vector<AsyncMgr::ITask *> active = queued_jobs;
+ queued_jobs.clear();
+ mtx.unlock();
+ for (auto it = active.begin(); it != active.end(); it++) {
+ AsyncMgr::ITask *t = *it;
+ if (active_set.find(t) == active_set.end()) {
+ t->doAsyncTask();
+ }
+ }
+ }
+}
+
+
+
+void AsyncMgr::start()
+{
+ async_thread = thread(&AsyncMgr::run, this);
+}
--- /dev/null
+#pragma once
+
+#include <mutex>
+#include <thread>
+#include <vector>
+
+namespace dragonblocks
+{
+ class AsyncMgr : public std::thread
+ {
+ public:
+ class ITask
+ {
+ public:
+ virtual void doAsyncTask();
+ };
+
+ void addTask(ITask *);
+ void run();
+ void start();
+
+ private:
+ std::mutex mtx;
+ std::vector<ITask *> queued_jobs;
+ std::thread async_thread;
+ };
+}
--- /dev/null
+#include "block.hpp"
+
+using namespace dragonblocks;
+
+BlockDef *Block::getDef() const
+{
+ return def;
+}
+
+Block::Block(BlockDef *d) : def(d)
+{
+}
--- /dev/null
+#pragma once
+
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ class BlockDef;
+ class Block
+ {
+ public:
+ BlockDef *getDef() const;
+
+ Block() = default;
+ Block(const Block &) = default;
+ Block(BlockDef *);
+
+ private:
+ BlockDef *def = nullptr;
+ };
+}
+
--- /dev/null
+#include "block_def.hpp"
+
+using namespace std;
+using namespace dragonblocks;
+
+BlockDef::BlockDef(const string &n, const TileDef &t) : name(n), tile_def(t)
+{
+ if (tile_def.size() == 0) {
+ drawable = false;
+ }
+}
+
+BlockDef::BlockDef(const string &n) : BlockDef(n, TileDef())
+{
+}
--- /dev/null
+#pragma once
+
+#include <string>
+#include "gl.hpp"
+#include "tile_def.hpp"
+
+namespace dragonblocks
+{
+ class BlockDef
+ {
+ public:
+ std::string name;
+ TileDef tile_def;
+ bool drawable = true;
+
+ BlockDef(const std::string &);
+ BlockDef(const std::string &, const TileDef &);
+ };
+}
--- /dev/null
+#include "box_vertices.hpp"
+
+GLfloat dragonblocks::box_vertices[6][6][5] = {
+// x y z s t
+ -0.5, -0.5, -0.5, +0.0, +0.0,
+ +0.5, -0.5, -0.5, +1.0, +0.0,
+ +0.5, +0.5, -0.5, +1.0, +1.0,
+ +0.5, +0.5, -0.5, +1.0, +1.0,
+ -0.5, +0.5, -0.5, +0.0, +1.0,
+ -0.5, -0.5, -0.5, +0.0, +0.0,
+
+ -0.5, -0.5, +0.5, +0.0, +0.0,
+ +0.5, +0.5, +0.5, +1.0, +1.0,
+ +0.5, -0.5, +0.5, +1.0, +0.0,
+ +0.5, +0.5, +0.5, +1.0, +1.0,
+ -0.5, -0.5, +0.5, +0.0, +0.0,
+ -0.5, +0.5, +0.5, +0.0, +1.0,
+
+ -0.5, +0.5, +0.5, +1.0, +1.0,
+ -0.5, -0.5, -0.5, +0.0, +0.0,
+ -0.5, +0.5, -0.5, +0.0, +1.0,
+ -0.5, -0.5, -0.5, +0.0, +0.0,
+ -0.5, +0.5, +0.5, +1.0, +1.0,
+ -0.5, -0.5, +0.5, +1.0, +0.0,
+
+ +0.5, +0.5, +0.5, +1.0, +1.0,
+ +0.5, +0.5, -0.5, +0.0, +1.0,
+ +0.5, -0.5, -0.5, +0.0, +0.0,
+ +0.5, -0.5, -0.5, +0.0, +0.0,
+ +0.5, -0.5, +0.5, +1.0, +0.0,
+ +0.5, +0.5, +0.5, +1.0, +1.0,
+
+ -0.5, -0.5, -0.5, +0.0, +1.0,
+ +0.5, -0.5, -0.5, +1.0, +1.0,
+ +0.5, -0.5, +0.5, +1.0, +0.0,
+ +0.5, -0.5, +0.5, +1.0, +0.0,
+ -0.5, -0.5, +0.5, +0.0, +0.0,
+ -0.5, -0.5, -0.5, +0.0, +1.0,
+
+ -0.5, +0.5, -0.5, +0.0, +1.0,
+ +0.5, +0.5, -0.5, +1.0, +1.0,
+ +0.5, +0.5, +0.5, +1.0, +0.0,
+ +0.5, +0.5, +0.5, +1.0, +0.0,
+ -0.5, +0.5, +0.5, +0.0, +0.0,
+ -0.5, +0.5, -0.5, +0.0, +1.0,
+};
--- /dev/null
+#pragma once
+
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ extern GLfloat box_vertices[6][6][5];
+}
--- /dev/null
+#include <glm/gtc/matrix_transform.hpp>
+#include "camera.hpp"
+
+using namespace glm;
+using namespace dragonblocks;
+
+mat4 Camera::getViewMatrix() const
+{
+ return lookAt(pos, pos + m_front, m_up);
+}
+
+void Camera::toggleMode()
+{
+ m_third_person = ! m_third_person;
+}
+
+void Camera::update(double yaw, double pitch, const vec3 &p)
+{
+ yaw = radians(yaw);
+ pitch = radians(pitch);
+
+ m_front = normalize(vec3(cos(yaw) * cos(pitch), sin(pitch), sin(yaw) * cos(pitch)));
+ m_right = normalize(cross(m_front, m_world_up));
+ m_up = normalize(cross(m_right, m_front));
+
+ pos = p;
+
+ if (m_third_person) {
+ pos -= m_front * 2.0f;
+ }
+}
+
+vec3 Camera::up() const
+{
+ return m_up;
+}
+
+vec3 Camera::front() const
+{
+ return m_front;
+}
+
+vec3 Camera::right() const
+{
+ return m_right;
+}
+
+bool Camera::thirdPerson() const
+{
+ return m_third_person;
+}
+
+Camera::Camera() : pos(0, 0, 0), m_up(0, 1, 0), m_world_up(0, 1, 0), m_front(0, 0, -1)
+{
+}
--- /dev/null
+#pragma once
+
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ class Camera
+ {
+ public:
+ glm::mat4 getViewMatrix() const;
+ void toggleMode();
+ void update(double, double, const glm::vec3 &);
+ glm::vec3 up() const;
+ glm::vec3 front() const;
+ glm::vec3 right() const;
+ bool thirdPerson() const;
+
+ Camera();
+
+ private:
+ glm::vec3 pos;
+ bool m_third_person;
+ glm::vec3 m_up;
+ glm::vec3 m_world_up;
+ glm::vec3 m_front;
+ glm::vec3 m_right;
+ };
+}
--- /dev/null
+#include <iostream>
+#include <stdexcept>
+#include "animations.hpp"
+#include "block_def.hpp"
+#include "box_vertices.hpp"
+#include "chunk.hpp"
+#include "face_dir.hpp"
+#include "map.hpp"
+#include "mesh.hpp"
+#include "texture.hpp"
+
+#define SIZE DRAGONBLOCKS_CHUNK_SIZE
+
+using namespace std;
+using namespace glm;
+using namespace dragonblocks;
+
+bool Chunk::checkPos(const ivec3 &pos)
+{
+ return pos.x >= 0 && pos.y >= 0 && pos.z >= 0 && pos.x < SIZE && pos.y < SIZE && pos.z < SIZE;
+}
+
+const Block *Chunk::getBlock(const ivec3 &pos) const
+{
+ const Block *b = getBlockNoEx(pos);
+ if (! b) {
+ throw out_of_range("Block position out of range");
+ }
+ return b;
+}
+
+const Block *Chunk::getBlockNoEx(const ivec3 &pos) const
+{
+ return Chunk::checkPos(pos) ? &data.blocks[pos.x][pos.y][pos.z] : nullptr;
+}
+
+void Chunk::setBlock(const ivec3 &pos, const Block &block)
+{
+ if (! Chunk::checkPos(pos)) {
+ throw out_of_range("Block position out of range");
+ }
+ data.blocks[pos.x][pos.y][pos.z] = block;
+}
+
+void Chunk::setBlockNoEx(const ivec3 &pos, const Block &block)
+{
+ try {
+ setBlock(pos, block);
+ } catch (out_of_range &) {
+ }
+}
+
+void Chunk::addMeshUpdateTask()
+{
+ async_mgr->addTask(this);
+}
+
+void Chunk::addMeshUpdateTaskWithEdge()
+{
+ addMeshUpdateTask();
+ for (int i = 0; i < 6; i++) {
+ if (Chunk *neighbor = map->getChunk(pos + face_dir[i])) {
+ neighbor->addMeshUpdateTask();
+ }
+ }
+}
+
+void Chunk::updateMesh()
+{
+ cout << "Update Chunk Mesh at " << pos.x << " " << pos.y << " " << pos.z << endl;
+
+ if (mesh_created && ! animation_finished)
+ return;
+
+ bool mesh_created_before = mesh_created;
+ mesh_created = true;
+
+ vector<GLfloat> vertices;
+ vector<Texture> textures;
+ bool any_drawable_block = false;
+
+ for (int x = 0; x < SIZE; x++) {
+ for (int y = 0; y < SIZE; y++) {
+ for (int z = 0; z < SIZE; z++) {
+ Block *block = &data.blocks[x][y][z];
+ BlockDef *def = block->getDef();
+ if (! def->drawable)
+ continue;
+ ivec3 bpos(x, y, z);
+ vec3 pos_from_mesh_origin = vec3(bpos) - vec3(SIZE / 2 + 0.5);
+ for (int facenr = 0; facenr < 6; facenr++) {
+ ivec3 npos = bpos + face_dir[facenr];
+ const Block *neighbor_own, *neighbor;
+ neighbor_own = neighbor = getBlockNoEx(npos);
+ if (! neighbor)
+ neighbor = map->getBlock(pos * SIZE + npos);
+ if (neighbor && ! neighbor->getDef()->drawable)
+ any_drawable_block = true;
+ if (! mesh_created_before)
+ neighbor = neighbor_own;
+ if (! mesh_created_before && ! neighbor || neighbor && ! neighbor->getDef()->drawable) {
+ textures.push_back(def->tile_def.get(facenr));
+ for (int vertex_index = 0; vertex_index < 6; vertex_index++) {
+ for (int attribute_index = 0; attribute_index < 5; attribute_index++) {
+ GLdouble value = box_vertices[facenr][vertex_index][attribute_index];
+ switch (attribute_index) {
+ case 0:
+ value += pos_from_mesh_origin.x;
+ break;
+ case 1:
+ value += pos_from_mesh_origin.y;
+ break;
+ case 2:
+ value += pos_from_mesh_origin.z;
+ break;
+ }
+ vertices.push_back(value);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (! any_drawable_block) {
+ if (! mesh_created_before) {
+ afterAnimation();
+ } else if (mesh) {
+ mesh->die();
+ mesh = nullptr;
+ }
+ return;
+ }
+
+ Mesh *oldmesh = mesh;
+
+ mesh = new Mesh(scene, shader_program, &vertices[0], vertices.size());
+ mesh->pos = pos * SIZE + SIZE / 2;
+ mesh->minp = vec3(- SIZE / 2);
+ mesh->maxp = vec3(+ SIZE / 2);
+ mesh->textures = textures;
+ mesh->vertices_per_texture = 6;
+ if (! mesh_created_before) {
+ mesh->animation = new FlyInAnimation(0.4, 20.0, Chunk::staticAfterAnimation, this);
+ }
+
+ if (oldmesh) {
+ oldmesh->die();
+ }
+}
+
+void Chunk::doAsyncTask()
+{
+ updateMesh();
+}
+
+Chunk::Chunk(Map *m, const ivec3 &p, const Data &d, AsyncMgr *a, Scene *s, ShaderProgram *sh) : map(m), data(d), pos(p), async_mgr(a), scene(s), shader_program(sh)
+{
+ addMeshUpdateTask();
+}
+
+Chunk::~Chunk()
+{
+ if (mesh) {
+ mesh->die();
+ }
+}
+
+void Chunk::staticAfterAnimation(void *chunk)
+{
+ if (chunk) {
+ ((Chunk *)chunk)->afterAnimation();
+ }
+}
+
+void Chunk::afterAnimation()
+{
+ animation_finished = true;
+ addMeshUpdateTaskWithEdge();
+}
--- /dev/null
+#pragma once
+
+#include "block.hpp"
+#include "gl.hpp"
+#include "async_mgr.hpp"
+
+#define DRAGONBLOCKS_CHUNK_SIZE 16
+
+namespace dragonblocks
+{
+ class Map;
+ class Mesh;
+ class Scene;
+ class ShaderProgram;
+
+ class Chunk : public AsyncMgr::ITask
+ {
+ public:
+ static bool checkPos(const glm::ivec3 &);
+
+ class Data
+ {
+ public:
+ Block blocks[DRAGONBLOCKS_CHUNK_SIZE][DRAGONBLOCKS_CHUNK_SIZE][DRAGONBLOCKS_CHUNK_SIZE];
+ Data() = default;
+ Data(const Data &) = default;
+ };
+
+ glm::ivec3 pos;
+
+ const Block *getBlock(const glm::ivec3 &) const;
+ const Block *getBlockNoEx(const glm::ivec3 &) const;
+ void setBlock(const glm::ivec3 &, const Block &);
+ void setBlockNoEx(const glm::ivec3 &, const Block &);
+ void addMeshUpdateTask();
+ void addMeshUpdateTaskWithEdge();
+ void updateMesh();
+ void doAsyncTask();
+
+ Chunk(Map *, const glm::ivec3 &, const Data &, AsyncMgr *, Scene *, ShaderProgram *);
+ ~Chunk();
+
+ private:
+ static void staticAfterAnimation(void *);
+
+ Map *map;
+ AsyncMgr *async_mgr;
+ Scene *scene;
+ ShaderProgram *shader_program;
+ Mesh *mesh = nullptr;
+ Data data;
+ bool animation_finished = false;
+ bool mesh_created = false;
+
+ void afterAnimation();
+ };
+};
--- /dev/null
+#include <iostream>
+#include <stdexcept>
+#include "async_mgr.hpp"
+#include "client.hpp"
+#include "game.hpp"
+#include "gl.hpp"
+#include "input_handler.hpp"
+#include "local_player.hpp"
+#include "map.hpp"
+#include "mapgen.hpp"
+#include "render_engine.hpp"
+#include "shader_program.hpp"
+#include "texture.hpp"
+#include "window.hpp"
+
+using namespace std;
+using namespace glm;
+using namespace dragonblocks;
+
+void Client::run()
+{
+ async_mgr->start();
+ while (render_engine->running()) {
+ double dtime = glfwGetTime() - last_time;
+ last_time = glfwGetTime();
+
+ player->step(dtime);
+
+ render_engine->render(dtime);
+
+ input_handler->processInput(dtime);
+
+ // process keys
+ if (input_handler->wasKeyDown(GLFW_KEY_F11)) {
+ render_engine->window->toggleFullscreen();
+ }
+ }
+}
+
+Client::Client()
+{
+ cout << "Initalizing Client..." << endl;
+
+ Texture::mipmap = true;
+ Texture::bilinear_filter = false;
+ Texture::initArgs();
+
+ async_mgr = new AsyncMgr;
+
+ input_handler = new InputHandler();
+ input_handler->mouse_sensitivity = 20;
+ input_handler->listenFor(GLFW_KEY_F11);
+
+ render_engine = new RenderEngine;
+ render_engine->render_distance = 1000;
+ render_engine->fov = 86.1;
+ render_engine->sky = vec3(0.52941176470588, 0.8078431372549, 0.92156862745098); // HTML skyblue
+ render_engine->window->setSize(1250, 750);
+ render_engine->window->setPos(0, 0);
+ render_engine->window->setTitle("Dragonblocks");
+
+ input_handler->setWindow(render_engine->window);
+
+ shader_program = new ShaderProgram("shaders");
+
+ mapgen = new Mapgen;
+
+ map = new Map(mapgen, async_mgr, render_engine->scene, shader_program);
+
+ Texture player_texture;
+ player_texture.load("textures/stone.png");
+
+ player = new LocalPlayer(map, render_engine->scene, player_texture, shader_program, render_engine->camera, input_handler);
+ player->pitch_move = false;
+ player->speed = 10;
+ player->setSize(vec3(0.75, 1.5, 0.75));
+
+ game = new Game(mapgen);
+
+ last_time = glfwGetTime();
+
+ cout << "Initialisation done." << endl;
+}
+
+extern "C" void _dragonblocks_start_client()
+{
+ Client().run();
+}
--- /dev/null
+#pragma once
+
+namespace dragonblocks
+{
+ class AsyncMgr;
+ class Game;
+ class InputHandler;
+ class Map;
+ class LocalPlayer;
+ class Mapgen;
+ class RenderEngine;
+ class ShaderProgram;
+
+ class Client
+ {
+ public:
+ AsyncMgr *async_mgr;
+ Game *game;
+ InputHandler *input_handler;
+ LocalPlayer *player;
+ Map *map;
+ Mapgen *mapgen;
+ RenderEngine *render_engine;
+ ShaderProgram *shader_program;
+
+ void run();
+
+ Client();
+
+ private:
+ double last_time;
+ };
+}
+++ /dev/null
-cmake_minimum_required(VERSION 3.0)
-
-set(srcpath "${PROJECT_SOURCE_DIR}/src/dragonblocks")
-
-add_library(dragonblocks SHARED
- block.cpp
- block_def.cpp
- camera.cpp
- chunk.cpp
- client.cpp
- core.cpp
- cube.cpp
- face_dir.cpp
- game.cpp
- gldebug.cpp
- input_handler.cpp
- log.cpp
- map.cpp
- mapgen.cpp
- mesh.cpp
- mesh_gen_mgr.cpp
- player.cpp
- render_engine.cpp
- scene.cpp
- shader_program.cpp
- texture.cpp
- window.cpp
- world.cpp
-)
-
-target_link_libraries(dragonblocks
- GL
- GLEW
- glfw
-)
-
-target_include_directories(dragonblocks PUBLIC
- "${PROJECT_SOURCE_DIR}/lib/"
- "${PROJECT_SOURCE_DIR}/src/"
-)
-
+++ /dev/null
-#include "block.hpp"
-
-using namespace dragonblocks;
-
-BlockDef *Block::getDef() const
-{
- return def;
-}
-
-Block::Block(BlockDef *d) : def(d)
-{
-}
+++ /dev/null
-#pragma once
-
-#include "gl.hpp"
-
-namespace dragonblocks
-{
- class BlockDef;
- class Block
- {
- public:
- BlockDef *getDef() const;
-
- Block() = default;
- Block(const Block &) = default;
- Block(BlockDef *);
-
- private:
- BlockDef *def = nullptr;
- };
-}
-
+++ /dev/null
-#include "block_def.hpp"
-
-using namespace std;
-using namespace dragonblocks;
-
-BlockDef::BlockDef(const string &n, const vector<Texture> &t) : name(n), tiles(t)
-{
- int s = tiles.size();
- if (s == 0) {
- drawable = false;
- } else {
- for (int i = 0; s < 6; i += s) {
- for (int j = 0; j < i && j + i < 6; j++) {
- tiles[i + j] = tiles[j];
- }
- }
- }
-}
-
-BlockDef::BlockDef(const string &n, const Texture &t) : BlockDef(n, {t, t, t, t, t, t})
-{
-}
-
-BlockDef::BlockDef(const string &n) : BlockDef(n, vector<Texture>())
-{
-}
+++ /dev/null
-#pragma once
-
-#include <string>
-#include <vector>
-#include "gl.hpp"
-#include "texture.hpp"
-
-namespace dragonblocks
-{
- class BlockDef
- {
- public:
- std::string name;
- std::vector<Texture> tiles;
- bool drawable = true;
-
- BlockDef(const std::string &);
- BlockDef(const std::string &, const Texture &);
- BlockDef(const std::string &, const std::vector<Texture> &);
- };
-}
+++ /dev/null
-#include <glm/gtc/matrix_transform.hpp>
-#include "camera.hpp"
-
-using namespace glm;
-using namespace dragonblocks;
-
-mat4 Camera::getViewMatrix() const
-{
- return lookAt(pos, pos + m_front, m_up);
-}
-
-void Camera::update(double yaw, double pitch)
-{
- yaw = radians(yaw);
- pitch = radians(pitch);
-
- m_front = normalize(vec3(cos(yaw) * cos(pitch), sin(pitch), sin(yaw) * cos(pitch)));
- m_right = normalize(cross(m_front, m_world_up));
- m_up = normalize(cross(m_right, m_front));
-}
-
-vec3 Camera::up() const
-{
- return m_up;
-}
-
-vec3 Camera::front() const
-{
- return m_front;
-}
-
-vec3 Camera::right() const
-{
- return m_right;
-}
-
-Camera::Camera() : pos(0, 0, 0), m_up(0, 1, 0), m_world_up(0, 1, 0), m_front(0, 0, -1)
-{
-}
+++ /dev/null
-#pragma once
-
-#include "gl.hpp"
-
-namespace dragonblocks
-{
- class Camera
- {
- public:
- glm::vec3 pos;
-
- glm::mat4 getViewMatrix() const;
- void update(double, double);
- glm::vec3 up() const;
- glm::vec3 front() const;
- glm::vec3 right() const;
-
- Camera();
-
- private:
- glm::vec3 m_up;
- glm::vec3 m_world_up;
- glm::vec3 m_front;
- glm::vec3 m_right;
- };
-}
+++ /dev/null
-#include <stdexcept>
-#include "block_def.hpp"
-#include "chunk.hpp"
-#include "cube.hpp"
-#include "face_dir.hpp"
-#include "log.hpp"
-#include "map.hpp"
-#include "mesh.hpp"
-#include "texture.hpp"
-
-#define SIZE DRAGONBLOCKS_CHUNK_SIZE
-
-using namespace std;
-using namespace glm;
-using namespace dragonblocks;
-
-void Chunk::checkPos(const ivec3 &pos)
-{
- if (pos.x < 0 || pos.y < 0 || pos.z < 0 || pos.x >= SIZE || pos.y >= SIZE || pos.z >= SIZE)
- throw out_of_range("Block position out of range");
-}
-
-const Block *Chunk::getBlock(const ivec3 &pos) const
-{
- Chunk::checkPos(pos);
- return &data.blocks[pos.x][pos.y][pos.z];
-}
-
-const Block *Chunk::getBlockNoEx(const ivec3 &pos) const
-{
- try {
- return getBlock(pos);
- } catch (out_of_range &) {
- return nullptr;
- }
-}
-
-void Chunk::setBlock(const ivec3 &pos, const Block &block)
-{
- Chunk::checkPos(pos);
- data.blocks[pos.x][pos.y][pos.z] = block;
-}
-
-void Chunk::setBlockNoEx(const ivec3 &pos, const Block &block)
-{
- try {
- setBlock(pos, block);
- } catch (out_of_range &) {
- }
-}
-
-void Chunk::addMeshUpdateTask()
-{
- mesh_gen_mgr->addTask(this);
-}
-
-void Chunk::addMeshUpdateTaskWithEdge()
-{
- addMeshUpdateTask();
- for (int i = 0; i < 6; i++) {
- if (Chunk *neighbor = map->getChunk(pos + face_dir[i])) {
- neighbor->addMeshUpdateTask();
- }
- }
-}
-
-void Chunk::updateMesh()
-{
- log(string("Update Chunk Mesh at ") + to_string(pos.x) + " " + to_string(pos.y) + " " + to_string(pos.z));
-
- if (mesh_created && ! animation_finished)
- return;
-
- bool mesh_created_before = mesh_created;
- mesh_created = true;
-
- vector<GLfloat> vertices;
- vector<Texture> textures;
- bool any_drawable_block = false;
-
- for (int x = 0; x < SIZE; x++) {
- for (int y = 0; y < SIZE; y++) {
- for (int z = 0; z < SIZE; z++) {
- Block *block = &data.blocks[x][y][z];
- BlockDef *def = block->getDef();
- if (! def->drawable)
- continue;
- ivec3 bpos(x, y, z);
- vec3 pos_from_mesh_origin = vec3(bpos) - vec3(SIZE / 2 + 0.5);
- for (int facenr = 0; facenr < 6; facenr++) {
- ivec3 npos = bpos + face_dir[facenr];
- const Block *neighbor_own, *neighbor;
- neighbor_own = neighbor = getBlockNoEx(npos);
- if (! neighbor)
- neighbor = map->getBlock(pos * SIZE + npos);
- if (neighbor && ! neighbor->getDef()->drawable)
- any_drawable_block = true;
- if (! mesh_created_before)
- neighbor = neighbor_own;
- if (! mesh_created_before && ! neighbor || neighbor && ! neighbor->getDef()->drawable) {
- textures.push_back(def->tiles[facenr]);
- for (int vertex_index = 0; vertex_index < 6; vertex_index++) {
- for (int attribute_index = 0; attribute_index < 5; attribute_index++) {
- int index = facenr * 6 * 5 + vertex_index * 5 + attribute_index;
- GLdouble value = cube[index];
- switch (attribute_index) {
- case 0:
- value += pos_from_mesh_origin.x;
- break;
- case 1:
- value += pos_from_mesh_origin.y;
- break;
- case 2:
- value += pos_from_mesh_origin.z;
- break;
- }
- vertices.push_back(value);
- }
- }
- }
- }
- }
- }
- }
-
- if (! any_drawable_block) {
- if (! mesh_created_before) {
- afterAnimation();
- } else if (mesh) {
- delete mesh;
- mesh = nullptr;
- }
- return;
- }
-
- Mesh *oldmesh = mesh;
-
- mesh = new Mesh(scene, &vertices[0], vertices.size() * sizeof(GLfloat));
- mesh->pos = pos * SIZE + SIZE / 2;
- mesh->minp = vec3(- SIZE / 2 - 1);
- mesh->maxp = vec3(+ SIZE / 2 + 1);
- mesh->textures = textures;
- mesh->vertices_per_texture = 6;
- if (! mesh_created_before) {
- mesh->animation = Mesh::Animation(Mesh::Animation::Type::FLYIN, Chunk::staticAfterAnimation, this);
- }
-
- if (oldmesh) {
- oldmesh->die();
- }
-}
-
-Chunk::Chunk(Map *m, const glm::ivec3 &p, const Data &d, MeshGenMgr *mg, Scene *s) : map(m), data(d), pos(p), mesh_gen_mgr(mg), scene(s)
-{
- addMeshUpdateTask();
-}
-
-Chunk::~Chunk()
-{
- if (mesh) {
- delete mesh;
- }
-}
-
-void Chunk::staticAfterAnimation(void *chunk)
-{
- if (chunk) {
- ((Chunk *)chunk)->afterAnimation();
- }
-}
-
-void Chunk::afterAnimation()
-{
- animation_finished = true;
- addMeshUpdateTaskWithEdge();
-}
+++ /dev/null
-#pragma once
-
-#include "block.hpp"
-#include "gl.hpp"
-#include "mesh_gen_mgr.hpp"
-
-#define DRAGONBLOCKS_CHUNK_SIZE 16
-
-namespace dragonblocks
-{
- class Map;
- class Mesh;
- class Scene;
-
- class Chunk : public MeshGenMgr::MeshGenerator
- {
- public:
- static void checkPos(const glm::ivec3 &);
-
- class Data
- {
- public:
- Block blocks[DRAGONBLOCKS_CHUNK_SIZE][DRAGONBLOCKS_CHUNK_SIZE][DRAGONBLOCKS_CHUNK_SIZE];
- Data() = default;
- Data(const Data &) = default;
- };
-
- glm::ivec3 pos;
-
- const Block *getBlock(const glm::ivec3 &) const;
- const Block *getBlockNoEx(const glm::ivec3 &) const;
- void setBlock(const glm::ivec3 &, const Block &);
- void setBlockNoEx(const glm::ivec3 &, const Block &);
- void addMeshUpdateTask();
- void addMeshUpdateTaskWithEdge();
- void updateMesh();
-
- Chunk(Map *, const glm::ivec3 &, const Data &, MeshGenMgr *, Scene *);
- ~Chunk();
-
- private:
- static void staticAfterAnimation(void *);
-
- Map *map;
- Mesh *mesh = nullptr;
- MeshGenMgr *mesh_gen_mgr;
- Scene *scene;
- Data data;
- bool animation_finished = false;
- bool mesh_created = false;
-
- void afterAnimation();
- };
-};
+++ /dev/null
-#include "camera.hpp"
-#include "client.hpp"
-#include "game.hpp"
-#include "gl.hpp"
-#include "input_handler.hpp"
-#include "log.hpp"
-#include "map.hpp"
-#include "mapgen.hpp"
-#include "player.hpp"
-#include "render_engine.hpp"
-#include "texture.hpp"
-#include "window.hpp"
-
-using namespace glm;
-using namespace dragonblocks;
-
-Client::Client()
-{
- log("Initalizing...");
-
- Texture::mipmap = true;
- Texture::bilinear_filter = false;
- Texture::initArgs();
-
- render_engine = new RenderEngine;
-
- render_engine->window->setSize(1250, 750);
- render_engine->window->setPos(0, 0);
- render_engine->window->setTitle("Dragonblocks");
- render_engine->window->toggleFullscreen();
- render_engine->input_handler->mouse_sensitivity = 20;
-
- render_engine->setSky(vec3(0.52941176470588, 0.8078431372549, 0.92156862745098));
- render_engine->setRenderDistance(1000);
- render_engine->setFov(86.1);
-
- mapgen = new Mapgen;
-
- map = new Map(mapgen, render_engine->mesh_gen_mgr, render_engine->scene);
-
- player = Player::createLocalplayer(render_engine->camera, render_engine->input_handler, map);
-
- player->pitch_move = false;
- player->yaw = 0;
- player->pitch = 0;
- player->speed = 10;
- player->pos = vec3(8, 8, 8);
-
- game = new Game(mapgen);
-
- log("Initialisation complete.");
-}
-
-void Client::start()
-{
- render_engine->startMeshGenMgr();
- while (render_engine->running()) {
- render_engine->render();
- }
-}
+++ /dev/null
-#pragma once
-
-namespace dragonblocks
-{
- class Game;
- class Map;
- class Mapgen;
- class Player;
- class RenderEngine;
-
- class Client
- {
- public:
- Game *game;
- Map *map;
- Mapgen *mapgen;
- Player *player;
- RenderEngine *render_engine;
-
- void start();
-
- Client();
- ~Client();
- };
-}
+++ /dev/null
-#include "core.hpp"
-#include "client.hpp"
-#include "render_engine.hpp"
-
-using namespace dragonblocks;
-
-Gametype dragonblocks::gametype;
-Client *dragonblocks::client = nullptr;
-
-extern "C" void _dragonblocks_start_client()
-{
- gametype = Gametype::CLIENT;
- client = new Client();
- client->start();
-}
+++ /dev/null
-#pragma once
-
-namespace dragonblocks
-{
- class Client;
-
- enum Gametype
- {
- CLIENT
- };
-
- extern Gametype gametype;
- extern Client *client;
-}
+++ /dev/null
-#include "cube.hpp"
-
-GLfloat dragonblocks::cube[DRAGONBLOCKS_CUBE_VERTEX_COUNT] = {
-// x y z s t
- -0.5, -0.5, -0.5, +0.0, +0.0,
- +0.5, -0.5, -0.5, +1.0, +0.0,
- +0.5, +0.5, -0.5, +1.0, +1.0,
- +0.5, +0.5, -0.5, +1.0, +1.0,
- -0.5, +0.5, -0.5, +0.0, +1.0,
- -0.5, -0.5, -0.5, +0.0, +0.0,
-
- -0.5, -0.5, +0.5, +0.0, +0.0,
- +0.5, +0.5, +0.5, +1.0, +1.0,
- +0.5, -0.5, +0.5, +1.0, +0.0,
- +0.5, +0.5, +0.5, +1.0, +1.0,
- -0.5, -0.5, +0.5, +0.0, +0.0,
- -0.5, +0.5, +0.5, +0.0, +1.0,
-
- -0.5, +0.5, +0.5, +1.0, +1.0,
- -0.5, -0.5, -0.5, +0.0, +0.0,
- -0.5, +0.5, -0.5, +0.0, +1.0,
- -0.5, -0.5, -0.5, +0.0, +0.0,
- -0.5, +0.5, +0.5, +1.0, +1.0,
- -0.5, -0.5, +0.5, +1.0, +0.0,
-
- +0.5, +0.5, +0.5, +1.0, +1.0,
- +0.5, +0.5, -0.5, +0.0, +1.0,
- +0.5, -0.5, -0.5, +0.0, +0.0,
- +0.5, -0.5, -0.5, +0.0, +0.0,
- +0.5, -0.5, +0.5, +1.0, +0.0,
- +0.5, +0.5, +0.5, +1.0, +1.0,
-
- -0.5, -0.5, -0.5, +0.0, +1.0,
- +0.5, -0.5, -0.5, +1.0, +1.0,
- +0.5, -0.5, +0.5, +1.0, +0.0,
- +0.5, -0.5, +0.5, +1.0, +0.0,
- -0.5, -0.5, +0.5, +0.0, +0.0,
- -0.5, -0.5, -0.5, +0.0, +1.0,
-
- -0.5, +0.5, -0.5, +0.0, +1.0,
- +0.5, +0.5, -0.5, +1.0, +1.0,
- +0.5, +0.5, +0.5, +1.0, +0.0,
- +0.5, +0.5, +0.5, +1.0, +0.0,
- -0.5, +0.5, +0.5, +0.0, +0.0,
- -0.5, +0.5, -0.5, +0.0, +1.0,
-};
+++ /dev/null
-#pragma once
-
-#include "gl.hpp"
-
-#define DRAGONBLOCKS_CUBE_VERTEX_COUNT 5 * 6 * 6 // 5 floats per vertex, 6 vertices per face, 6 faces
-
-namespace dragonblocks
-{
- extern GLfloat cube[DRAGONBLOCKS_CUBE_VERTEX_COUNT];
-}
+++ /dev/null
-#include "face_dir.hpp"
-
-using namespace glm;
-
-ivec3 dragonblocks::face_dir[6] = {
- {+0, +0, -1},
- {+0, +0, +1},
- {-1, +0, +0},
- {+1, +0, +0},
- {+0, -1, +0},
- {+0, +1, +0},
-};
+++ /dev/null
-#pragma once
-
-#include "gl.hpp"
-
-namespace dragonblocks
-{
- extern glm::ivec3 face_dir[6];
-}
+++ /dev/null
-#include "block_def.hpp"
-#include "game.hpp"
-#include "mapgen.hpp"
-
-using namespace dragonblocks;
-
-Game::Game(Mapgen *m) : mapgen(m)
-{
- grass_texture.load("textures/grass.png");
- grass_side_texture.load("textures/grass_side.png");
- dirt_texture.load("textures/dirt.png");
- stone_texture.load("textures/stone.png");
-
- air = new BlockDef("dragonblocks:air");
- grass = new BlockDef("dragonblocks:grass", {grass_side_texture, grass_side_texture, grass_side_texture, grass_side_texture, dirt_texture, grass_texture});
- dirt = new BlockDef("dragonblocks:dirt", dirt_texture);
- stone = new BlockDef("dragonblocks:stone", stone_texture);
-
- mapgen->air_def = air;
- mapgen->grass_def = grass;
- mapgen->dirt_def = dirt;
- mapgen->stone_def = stone;
-}
+++ /dev/null
-#pragma once
-
-#include "texture.hpp"
-
-namespace dragonblocks
-{
- class BlockDef;
- class Mapgen;
-
- class Game
- {
- public:
- BlockDef *air, *grass, *dirt, *stone;
- Mapgen *mapgen;
- Texture grass_texture, grass_side_texture, dirt_texture, stone_texture;
-
- Game(Mapgen *);
- };
-}
+++ /dev/null
-#pragma once
-
-#include <GL/glew.h>
-#include <GL/gl.h>
-#include <GLFW/glfw3.h>
-#include <glm/glm.hpp>
+++ /dev/null
-#include <string>
-#include "gldebug.hpp"
-#include "log.hpp"
-
-using namespace std;
-using namespace dragonblocks;
-
-GLenum dragonblocks::checkGLError(const char *file, int line)
-{
- GLenum errorCode;
- if ((errorCode = glGetError()) != GL_NO_ERROR)
- {
- string error;
- switch (errorCode)
- {
- case GL_INVALID_ENUM: error = "INVALID_ENUM"; break;
- case GL_INVALID_VALUE: error = "INVALID_VALUE"; break;
- case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break;
- case GL_STACK_OVERFLOW: error = "STACK_OVERFLOW"; break;
- case GL_STACK_UNDERFLOW: error = "STACK_UNDERFLOW"; break;
- case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break;
- case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break;
- }
- log(string("OpenGL Error: ") + error + " | " + file + " (" + to_string(line) + ")");
- }
- return errorCode;
-}
+++ /dev/null
-#pragma once
-
-#include "gl.hpp"
-
-#define CHECKERR dragonblocks::checkGLError(__FILE__, __LINE__);
-
-namespace dragonblocks
-{
- GLenum checkGLError(const char *file, int line);
-}
+++ /dev/null
-#include "camera.hpp"
-#include "input_handler.hpp"
-#include "window.hpp"
-
-using namespace std;
-using namespace glm;
-using namespace dragonblocks;
-
-void InputHandler::processInput(double dtime)
-{
- processMouseInput(dtime);
- processKeyInput(dtime);
-}
-
-void InputHandler::listenFor(int key)
-{
- listened_keys.insert(key);
-}
-
-void InputHandler::dontListenFor(int key)
-{
- listened_keys.erase(key);
-}
-
-void InputHandler::addMouseHandler(void (*callback)(double, double, double))
-{
- mouse_handlers.insert(callback);
-}
-
-void InputHandler::removeMouseHandler(void (*callback)(double, double, double))
-{
- mouse_handlers.erase(callback);
-}
-
-void InputHandler::addKeyHandler(void (*callback)(double, set<int>))
-{
- key_handlers.insert(callback);
-}
-
-void InputHandler::removeKeyHandler(void (*callback)(double, set<int>))
-{
- key_handlers.erase(callback);
-}
-
-InputHandler::InputHandler(Window *w) : window(w)
-{
-}
-
-void InputHandler::processMouseInput(double dtime)
-{
- vec2 cursor_delta = vec2(mouse_sensitivity * dtime) * (vec2)window->getCursorDelta();
- double x, y;
- x = cursor_delta.x;
- y = cursor_delta.y;
- if (x != 0 && y != 0) {
- for (auto it = mouse_handlers.begin(); it != mouse_handlers.end(); it++) {
- (**it)(dtime, x, y);
- }
- }
-}
-
-void InputHandler::processKeyInput(double dtime)
-{
- set<int> keysDown;
- for (auto it = listened_keys.begin(); it != listened_keys.end(); it++) {
- int key = *it;
- if (window->wasKeyDown(key)) {
- keysDown.insert(key);
- }
- }
- if (keysDown.begin() != keysDown.end()) {
- for (auto it = key_handlers.begin(); it != key_handlers.end(); it++) {
- (**it)(dtime, keysDown);
- }
- }
-}
+++ /dev/null
-#pragma once
-
-#include <set>
-#include "gl.hpp"
-
-namespace dragonblocks
-{
- class Camera;
- class Window;
-
- class InputHandler
- {
- public:
- void processInput(double);
- void listenFor(int);
- void dontListenFor(int);
- void addMouseHandler(void (*)(double, double, double));
- void removeMouseHandler(void (*)(double, double, double));
- void addKeyHandler(void (*)(double, std::set<int>));
- void removeKeyHandler(void (*)(double, std::set<int>));
-
- double mouse_sensitivity;
-
- InputHandler(Window *);
-
- private:
- void processMouseInput(double);
- void processKeyInput(double);
-
- Window *window;
- std::set<int> listened_keys;
- std::set<void (*)(double, double, double)> mouse_handlers;
- std::set<void (*)(double, std::set<int>)> key_handlers;
- };
-}
+++ /dev/null
-#include <iostream>
-#include "core.hpp"
-#include "log.hpp"
-
-using namespace std;
-using namespace dragonblocks;
-
-void dragonblocks::log(const string &l)
-{
- string gt;
- switch (gametype) {
- case Gametype::CLIENT:
- gt = "Client";
- break;
- }
- cout << "[" << gt << "] " << l << endl;
-}
+++ /dev/null
-#pragma once
-
-#include <string>
-
-namespace dragonblocks
-{
- void log(const std::string &);
-}
+++ /dev/null
-#include <stdexcept>
-#include "map.hpp"
-#include "mapgen.hpp"
-
-using namespace std;
-using namespace glm;
-using namespace dragonblocks;
-
-ivec3 Map::getChunkPos(const vec3 &p)
-{
- return floor(p / (float)DRAGONBLOCKS_CHUNK_SIZE);
-}
-
-ivec3 Map::getBlockPos(const ivec3 &p)
-{
- return ((p % DRAGONBLOCKS_CHUNK_SIZE) + ivec3(DRAGONBLOCKS_CHUNK_SIZE)) % DRAGONBLOCKS_CHUNK_SIZE;
-}
-
-uint16_t Map::getChunkPosHash(const ivec3 &p)
-{
- return (uint16_t)p.x + (uint16_t)p.y * DRAGONBLOCKS_MAP_SIZE + (uint16_t)p.z * DRAGONBLOCKS_MAP_SIZE * DRAGONBLOCKS_MAP_SIZE;
-}
-
-const Block *Map::getBlock(const glm::ivec3 &p)
-{
-
- Chunk *chunk = getChunk(Map::getChunkPos(p));
- if (chunk)
- return chunk->getBlock(Map::getBlockPos(p));
- return nullptr;
-}
-
-void Map::setBlock(const glm::ivec3 &p, BlockDef *def)
-{
- Chunk *chunk = getChunk(Map::getChunkPos(p));
- if (chunk)
- chunk->setBlock(Map::getBlockPos(p), def);
-}
-
-void Map::createChunk(const glm::ivec3 &p, const Chunk::Data &data)
-{
- uint64_t poshash = Map::getChunkPosHash(p);
-
- if (chunks[poshash])
- return;
-
- chunks[poshash] = new Chunk(this, p, data, mesh_gen_mgr, scene);
-}
-
-void Map::createChunk(const glm::ivec3 &p)
-{
- if (! chunks[Map::getChunkPosHash(p)])
- createChunk(p, mapgen->generate(p));
-}
-
-Chunk *Map::getChunk(const glm::ivec3 &p)
-{
- return chunks[Map::getChunkPosHash(p)];
-}
-
-void Map::clear()
-{
- for (auto it = chunks.begin(); it != chunks.end(); it++)
- delete it->second;
- chunks.clear();
-}
-
-Map::Map(Mapgen *m, MeshGenMgr *mg, Scene *s) : mapgen(m), mesh_gen_mgr(mg), scene(s)
-{
-}
-
-Map::~Map()
-{
- clear();
-}
+++ /dev/null
-#pragma once
-
-#include <map>
-#include "chunk.hpp"
-#include "gl.hpp"
-
-#define DRAGONBLOCKS_MAP_SIZE 1000
-
-namespace dragonblocks
-{
- class BlockDef;
- class Block;
- class Mapgen;
- class MeshGenMgr;
- class Scene;
-
- class Map
- {
- public:
- static glm::ivec3 getChunkPos(const glm::vec3 &);
- static glm::ivec3 getBlockPos(const glm::ivec3 &);
- static uint16_t getChunkPosHash(const glm::ivec3 &);
-
- const Block *getBlock(const glm::ivec3 &);
- const Block *getBlockRelativePos(Chunk *, const glm::ivec3 &);
- void setBlock(const glm::ivec3 &, BlockDef *);
- void createChunk(const glm::ivec3 &, const Chunk::Data &);
- void createChunk(const glm::ivec3 &);
- Chunk *getChunk(const glm::ivec3 &);
- void clear();
-
- Map(Mapgen *, MeshGenMgr *, Scene *);
- ~Map();
-
- private:
- std::map<uint16_t, Chunk*> chunks;
- Mapgen *mapgen;
- MeshGenMgr *mesh_gen_mgr;
- Scene *scene;
- };
-}
+++ /dev/null
-#include <glm/gtc/noise.hpp>
-#include "mapgen.hpp"
-
-using namespace glm;
-using namespace dragonblocks;
-
-Chunk::Data Mapgen::generate(const ivec3 &chunkp) const
-{
- Chunk::Data data;
- vec3 minp = chunkp * ivec3(DRAGONBLOCKS_CHUNK_SIZE);
- vec3 maxp = minp + vec3(DRAGONBLOCKS_CHUNK_SIZE);
- int minx = minp.x, miny = minp.y, minz = minp.z, maxx = maxp.x, maxy = maxp.y, maxz = maxp.z;
- for (int x = minx; x < maxx; x++) {
- int rx = x - minx;
- for (int z = minz; z < maxz; z++) {
- int rz = z - minz;
- int grass_layer = grass_layer_middle + grass_layer_range * perlin(vec2((float)x / 128, (float)z / 128));
- for (int y = miny; y < maxy; y++) {
- int ry = y - miny;
- BlockDef *blockdef;
- if (y < grass_layer - 4)
- blockdef = stone_def;
- else if (y < grass_layer - 1)
- blockdef = dirt_def;
- else if (y < grass_layer)
- blockdef = grass_def;
- else
- blockdef = air_def;
- data.blocks[rx][ry][rz] = blockdef;
- }
- }
- }
- return data;
-}
+++ /dev/null
-#pragma once
-
-#include "chunk.hpp"
-#include "gl.hpp"
-
-namespace dragonblocks
-{
- class BlockDef;
-
- class Mapgen
- {
- public:
- float grass_layer_middle = 0, grass_layer_range = 64;
- BlockDef *air_def, *stone_def, *dirt_def, *grass_def;
-
- Chunk::Data generate(const glm::ivec3 &) const;
- };
-};
+++ /dev/null
-#include <stdexcept>
-#include <cstdlib>
-#include <cstring>
-#include <glm/gtc/matrix_transform.hpp>
-#include <glm/gtc/constants.hpp>
-#include "FrustumCull.h"
-#include "gldebug.hpp"
-#include "mesh.hpp"
-#include "scene.hpp"
-#include "shader_program.hpp"
-
-using namespace std;
-using namespace glm;
-using namespace dragonblocks;
-
-double Mesh::Animation::grow_time = 0.25; // s
-double Mesh::Animation::flyin_time = 0.4; // s
-double Mesh::Animation::flyin_offset = 20; // m
-double Mesh::Animation::rotate_speed = 1; // turns/s
-
-mat4 Mesh::Animation::getModelMatrix(double dtime, vec3 pos, vec3 size, vec3 rotation_axis, float rotation_angle)
-{
- mat4 trans = mat4(1.0);
-
- if (type == Mesh::Animation::Type::NONE)
- goto finish;
-
- if (expires) {
- time_left -= dtime;
- if (time_left < 0) {
- type = Mesh::Animation::Type::NONE;
- if (on_finish) {
- (*on_finish)(extra_data);
- }
- goto finish;
- }
- }
-
- switch (type) {
- case Mesh::Animation::Type::FLYIN:
- pos.y -= Mesh::Animation::flyin_offset * time_left / Mesh::Animation::flyin_time;
- break;
-
- case Mesh::Animation::Type::GROW:
- size *= 1 - time_left / Mesh::Animation::grow_time;
- break;
-
- case Mesh::Animation::Type::ROTATE:
- rotation_angle += glfwGetTime() * Mesh::Animation::rotate_speed * pi<float>() * 2;
- }
-
- finish:
-
- trans = translate(trans, pos);
- trans = rotate(trans, rotation_angle, rotation_axis);
- trans = scale(trans, size);
-
- return trans;
-}
-
-Mesh::Animation::Animation(Mesh::Animation::Type t, void (*o)(void *), void *e) : type(t), on_finish(o), extra_data(e)
-{
- switch(type) {
- case Mesh::Animation::Type::FLYIN:
- expires = true;
- time_left = Mesh::Animation::flyin_time;
- break;
-
- case Mesh::Animation::Type::GROW:
- expires = true;
- time_left = Mesh::Animation::grow_time;
- break;
-
- case Mesh::Animation::Type::ROTATE:
- expires = false;
- break;
- }
-}
-
-void Mesh::render(double dtime, ShaderProgram *shader_program, Frustum *frustum)
-{
- rendering = true;
-
- if (do_delete) {
- delete this;
- return;
- } else if (prepare_death) {
- do_delete = true;
- }
-
- if (! configured) {
- configure();
- }
-
- shader_program->use(); CHECKERR
-
- mat4 model_matrix = animation.getModelMatrix(dtime, pos, size, rotation_axis, rotation_angle); CHECKERR
-
- if (! frustum->IsBoxVisible(model_matrix * vec4(minp, 1.0), model_matrix * vec4(maxp, 1.0)))
- return;
-
- shader_program->set("model", model_matrix); CHECKERR
-
- glBindVertexArray(VAO); CHECKERR
- for (int i = 0; i < textures.size(); i++) {
- textures[i].bind(); CHECKERR
- glDrawArrays(GL_TRIANGLES, i * vertices_per_texture, vertices_per_texture); CHECKERR
- }
- glBindVertexArray(0); CHECKERR
- glBindTexture(GL_TEXTURE_2D, 0); CHECKERR
-
- rendering = false;
-}
-
-bool Mesh::isRendering()
-{
- return rendering;
-}
-
-void Mesh::die()
-{
- prepare_death = true;
-}
-
-Mesh::Mesh(Scene *s, const GLvoid *v, GLsizei vs): pos(0), size(1), rotation_axis(0, 1, 0), scene(s), vertices_size(vs)
-{
- if (! v || ! vs)
- throw runtime_error("Invalid Mesh configuration");
- vertices = malloc(vs);
- memcpy(vertices, v, vs);
- scene->add(this);
-}
-
-Mesh::~Mesh()
-{
- scene->remove(this);
- if (VAO) {
- glDeleteVertexArrays(1, &VAO); CHECKERR
- }
- if (VBO) {
- glDeleteBuffers(1, &VAO); CHECKERR
- }
-}
-
-void Mesh::configure()
-{
- glGenVertexArrays(1, &VAO); CHECKERR
- glGenBuffers(1, &VBO); CHECKERR
-
- glBindVertexArray(VAO); CHECKERR
- glBindBuffer(GL_ARRAY_BUFFER, VBO); CHECKERR
-
- glBufferData(GL_ARRAY_BUFFER, vertices_size, vertices, GL_STATIC_DRAW); CHECKERR
-
- GLsizei stride = 5 * sizeof(GLfloat); CHECKERR
-
- glVertexAttribPointer(0, 3, GL_FLOAT, false, stride, (GLvoid *)(0 * sizeof(GLfloat))); CHECKERR
- glEnableVertexAttribArray(0); CHECKERR
- glVertexAttribPointer(1, 2, GL_FLOAT, false, stride, (GLvoid *)(3 * sizeof(GLfloat))); CHECKERR
- glEnableVertexAttribArray(1); CHECKERR
-
- glBindBuffer(GL_ARRAY_BUFFER, 0); CHECKERR
- glBindVertexArray(0); CHECKERR
-
- free(vertices);
- vertices = NULL;
- configured = true;
-}
+++ /dev/null
-#pragma once
-
-#include <vector>
-#include "gl.hpp"
-#include "texture.hpp"
-
-class Frustum;
-
-namespace dragonblocks
-{
- class Scene;
- class ShaderProgram;
-
- class Mesh
- {
- public:
- class Animation
- {
- public:
- static double grow_time;
- static double flyin_time;
- static double flyin_offset;
- static double rotate_speed;
-
- enum Type
- {
- NONE,
- FLYIN,
- GROW,
- ROTATE
- };
-
- glm::mat4 getModelMatrix(double, glm::vec3, glm::vec3, glm::vec3, float);
-
- Animation() = default;
- Animation(Type, void (*)(void *) = nullptr, void * = nullptr);
- Animation(const Animation &) = default;
-
- private:
- Type type = Type::NONE;
- double time_left;
- void (*on_finish)(void *);
- void *extra_data;
- bool expires;
- };
-
- int vertices_per_texture;
- glm::vec3 pos, size, rotation_axis;
- glm::vec3 minp, maxp;
- float rotation_angle = 0;
- std::vector<Texture> textures;
- Animation animation;
-
- void render(double dtime, ShaderProgram *, Frustum *);
- bool isRendering();
- void die();
-
- Mesh(Scene *, const GLvoid *, GLsizei);
- ~Mesh();
-
- private:
- GLuint VAO = 0, VBO = 0;
- Scene *scene;
- GLvoid *vertices = NULL;
- GLsizeiptr vertices_size;
- bool configured = false;
- bool rendering = false;
- bool prepare_death = false;
- bool do_delete = false;
-
- void configure();
- };
-}
+++ /dev/null
-#include <set>
-#include "mesh_gen_mgr.hpp"
-#include "window.hpp"
-
-using namespace std;
-using namespace dragonblocks;
-
-void MeshGenMgr::MeshGenerator::updateMesh()
-{
-}
-
-void MeshGenMgr::addTask(MeshGenMgr::MeshGenerator *gen)
-{
- queued_jobs.push(gen);
-}
-
-void MeshGenMgr::step()
-{
- if (! runJob()) {
- generateJobList();
- }
-}
-
-void MeshGenMgr::run()
-{
- while (true) {
- step();
- }
-}
-
-void MeshGenMgr::generateJobList()
-{
- set<MeshGenMgr::MeshGenerator *> active_jobs_set;
- while (! queued_jobs.empty()) {
- MeshGenMgr::MeshGenerator *gen = queued_jobs.front();
- queued_jobs.pop();
- if (active_jobs_set.find(gen) == active_jobs_set.end()) {
- active_jobs_set.insert(gen);
- active_jobs.push(gen);
- }
- }
-}
-
-
-bool MeshGenMgr::runJob()
-{
- if (active_jobs.empty())
- return false;
- MeshGenMgr::MeshGenerator *gen = active_jobs.front();
- active_jobs.pop();
- if (gen) {
- gen->updateMesh();
- }
- return true;
-}
-
-void MeshGenMgr::start()
-{
- mesh_gen_thread = thread(&MeshGenMgr::run, this);
-}
+++ /dev/null
-#pragma once
-
-#include <thread>
-#include <queue>
-
-namespace dragonblocks
-{
- class Window;
-
- class MeshGenMgr : public std::thread
- {
- public:
- class MeshGenerator
- {
- public:
- virtual void updateMesh();
- };
-
- void addTask(MeshGenerator *);
- void step();
- void run();
- void start();
-
- private:
- void generateJobList();
- bool runJob();
-
- std::queue<MeshGenerator *> queued_jobs;
- std::queue<MeshGenerator *> active_jobs;
- std::thread mesh_gen_thread;
- };
-}
+++ /dev/null
-#include <stdexcept>
-#include "camera.hpp"
-#include "input_handler.hpp"
-#include "map.hpp"
-#include "player.hpp"
-
-using namespace std;
-using namespace glm;
-using namespace dragonblocks;
-
-Player* Player::localplayer = nullptr;
-
-Player *Player::createLocalplayer(Camera *c, InputHandler *i, Map *m)
-{
- if (localplayer)
- throw runtime_error("Localplayer already exists");
- return localplayer = new Player(c, i, m);
-}
-
-void Player::staticMouseHandler(double dtime, double x, double y)
-{
- localplayer->mouseHandler(dtime, x, y);
-}
-
-void Player::staticKeyHandler(double dtime, set<int> keys)
-{
- localplayer->keyHandler(dtime, keys);
-}
-
-void Player::mouseHandler(double dtime, double x, double y)
-{
- yaw += x;
- pitch -= y;
- pitch = clamp(pitch, -89.0, 89.0);
- camera->update(yaw, pitch);
-}
-
-void Player::keyHandler(double dtime, set<int> keys)
-{
- vec3 vel = vec3(speed * dtime);
- vec3 front = camera->front(), right = camera->right(), up = camera->up();
- if (! pitch_move) {
- front = normalize(vec3(front.x, 0, front.z));
- up = normalize(vec3(0, up.y, 0));
- }
- if (keys.find(GLFW_KEY_W) != keys.end()) {
- pos += vel * front;
- } else if (keys.find(GLFW_KEY_S) != keys.end()) {
- pos -= vel * front;
- }
- if (keys.find(GLFW_KEY_D) != keys.end()) {
- pos += vel * right;
- } else if (keys.find(GLFW_KEY_A) != keys.end()) {
- pos -= vel * right;
- }
- if (keys.find(GLFW_KEY_SPACE) != keys.end()) {
- pos += vel * up;
- } else if (keys.find(GLFW_KEY_LEFT_SHIFT) != keys.end()) {
- pos -= vel * up;
- }
- camera->pos = pos;
- loadChunks();
-}
-
-void Player::loadChunks()
-{
- ivec3 chunkp = Map::getChunkPos(pos);
- for (int x = chunkp.x - 1; x <= chunkp.x + 1; x++) {
- for (int y = chunkp.y - 1; y < chunkp.y + 1; y++) {
- for (int z = chunkp.z - 1; z <= chunkp.z + 1; z++) {
- map->createChunk(ivec3(x, y, z));
- }
- }
- }
-}
-
-Player::Player(Camera *c, InputHandler *i, Map *m) : camera(c), input_handler(i), map(m)
-{
- input_handler->listenFor(GLFW_KEY_W);
- input_handler->listenFor(GLFW_KEY_A);
- input_handler->listenFor(GLFW_KEY_S);
- input_handler->listenFor(GLFW_KEY_D);
- input_handler->listenFor(GLFW_KEY_SPACE);
- input_handler->listenFor(GLFW_KEY_LEFT_SHIFT);
-
- input_handler->addMouseHandler(Player::staticMouseHandler);
- input_handler->addKeyHandler(Player::staticKeyHandler);
-}
+++ /dev/null
-#pragma once
-
-#include <vector>
-#include "gl.hpp"
-
-namespace dragonblocks
-{
- class Camera;
- class InputHandler;
- class Map;
-
- class Player
- {
- public:
- static Player *createLocalplayer(Camera *, InputHandler *, Map *);
-
- glm::vec3 pos;
- bool pitch_move;
- double yaw, pitch;
- double speed;
-
- private:
- static Player *localplayer;
-
- static void staticMouseHandler(double, double, double);
- static void staticKeyHandler(double, std::set<int>);
-
- Camera *camera;
- InputHandler *input_handler;
- Map *map;
-
- void mouseHandler(double, double, double);
- void keyHandler(double, std::set<int>);
- void loadChunks();
-
- Player(Camera *, InputHandler *, Map *);
- };
-}
+++ /dev/null
-#include <stdexcept>
-#include <glm/gtc/matrix_transform.hpp>
-#include "FrustumCull.h"
-#include "camera.hpp"
-#include "gldebug.hpp"
-#include "input_handler.hpp"
-#include "mesh_gen_mgr.hpp"
-#include "render_engine.hpp"
-#include "scene.hpp"
-#include "shader_program.hpp"
-#include "window.hpp"
-
-using namespace std;
-using namespace glm;
-using namespace dragonblocks;
-
-void RenderEngine::render()
-{
- double dtime = glfwGetTime() - last_time;
- last_time = glfwGetTime();
-
- input_handler->processInput(dtime);
-
- glEnable(GL_DEPTH_TEST); CHECKERR
- glEnable(GL_CULL_FACE); CHECKERR
- glCullFace(GL_BACK); CHECKERR
- glFrontFace(GL_CW); CHECKERR
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); CHECKERR
-
- updateViewMatrix(); CHECKERR
-
- Frustum frustum(projection_matrix * view_matrix);
-
- scene->render(dtime, shader_program, &frustum);
-
- window->swapBuffers(); CHECKERR
- glfwPollEvents(); CHECKERR
-}
-
-bool RenderEngine::running()
-{
- return ! window->shouldClose();
-}
-
-void RenderEngine::updateProjectionMatrix()
-{
- dvec2 bounds = window->getSize();
- projection_matrix = perspective(radians(fov), bounds.x / bounds.y, 0.01, render_distance);
- shader_program->set("projection", projection_matrix); CHECKERR
-}
-
-void RenderEngine::updateViewMatrix()
-{
- view_matrix = camera->getViewMatrix();
- shader_program->set("view", view_matrix); CHECKERR
-}
-
-void RenderEngine::setSky(vec3 sky)
-{
- glClearColor(sky.r, sky.g, sky.b, 1.0); CHECKERR
- shader_program->set("sky", sky); CHECKERR
-}
-
-void RenderEngine::setRenderDistance(double d)
-{
- render_distance = d;
- updateProjectionMatrix();
-}
-
-void RenderEngine::setFov(double f)
-{
- fov = f;
- updateProjectionMatrix();
-}
-
-void RenderEngine::startMeshGenMgr()
-{
- mesh_gen_mgr->start();
-}
-
-RenderEngine::RenderEngine()
-{
- if (! glfwInit())
- throw runtime_error("Failed to initialize GLFW");
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-
- window = Window::create(this);
- camera = new Camera;
- input_handler = new InputHandler(window);
- mesh_gen_mgr = new MeshGenMgr;
- scene = new Scene;
-
- GLenum glew_init_err = glewInit();
- if (glew_init_err != GLEW_OK)
- throw runtime_error("Failed to initialize GLEW");
-
- shader_program = new ShaderProgram("shaders");
-
- setSky(vec3(1.0, 1.0, 1.0));
- setRenderDistance(16);
- setFov(45);
-
- last_time = glfwGetTime();
-}
-
-RenderEngine::~RenderEngine()
-{
- delete window;
- delete camera;
- delete input_handler;
- delete mesh_gen_mgr;
- delete scene;
- delete shader_program;
-}
+++ /dev/null
-#pragma once
-
-#include "gl.hpp"
-
-namespace dragonblocks
-{
- class Camera;
- class InputHandler;
- class MeshGenMgr;
- class ShaderProgram;
- class Scene;
- class Window;
-
- class RenderEngine
- {
- public:
- Camera *camera;
- InputHandler *input_handler;
- MeshGenMgr *mesh_gen_mgr;
- Scene *scene;
- ShaderProgram *shader_program;
- Window *window;
-
- void render();
- bool running();
- void updateViewMatrix();
- void updateProjectionMatrix();
- void setSky(glm::vec3);
- void setRenderDistance(double);
- void setFov(double);
- void startMeshGenMgr();
-
-
- RenderEngine();
- ~RenderEngine();
-
- private:
- glm::mat4 view_matrix, projection_matrix;
- double last_time;
- double render_distance;
- double fov;
- };
-}
+++ /dev/null
-#include "mesh.hpp"
-#include "scene.hpp"
-
-using namespace std;
-using namespace dragonblocks;
-
-void Scene::add(Mesh *m)
-{
- meshes.insert(m);
-}
-
-void Scene::remove(Mesh *m)
-{
- meshes.erase(m);
-}
-
-void Scene::render(double dtime, ShaderProgram *shader_program, Frustum *frustum)
-{
- auto renderlist = meshes;
- for (auto it = renderlist.begin(); it != renderlist.end(); it++) {
- Mesh *mesh = *it;
- mesh->render(dtime, shader_program, frustum);
- }
-}
-
-void Scene::clear()
-{
- meshes.clear();
-}
-
-Scene::~Scene()
-{
- clear();
-}
+++ /dev/null
-#pragma once
-
-#include <set>
-
-class Frustum;
-
-namespace dragonblocks
-{
- class Mesh;
- class ShaderProgram;
-
- class Scene {
- public:
- void add(Mesh *);
- void remove(Mesh *);
- void render(double, ShaderProgram *, Frustum *);
- void clear();
- void run();
-
- ~Scene();
-
- private:
- std::set<Mesh *> meshes;
- };
-}
+++ /dev/null
-#include <fstream>
-#include <sstream>
-#include <stdexcept>
-#include <vector>
-#include <glm/gtc/type_ptr.hpp>
-#include "shader_program.hpp"
-
-using namespace std;
-using namespace glm;
-using namespace dragonblocks;
-
-map<string, GLenum> ShaderProgram::shadertypes = {
- {"vertex", GL_VERTEX_SHADER},
- {"fragment", GL_FRAGMENT_SHADER},
-};
-
-ShaderProgram::ShaderProgram(const string &global_path)
-{
- int success;
- char buffer[1024] = {};
- vector<GLuint> shaders;
-
- id = glCreateProgram();
-
- for (auto it = ShaderProgram::shadertypes.begin(); it != ShaderProgram::shadertypes.end(); it++) {
- const char *c_code;
- GLuint shader;
- string path, code;
- ifstream file;
- stringstream stream;
-
- path = global_path + "/" + it->first + ".glsl";
- file.exceptions(ifstream::failbit | ifstream::badbit);
- file.open(path);
- stream << file.rdbuf();
- code = stream.str();
- c_code = code.c_str();
-
- shader = glCreateShader(it->second);
- shaders.push_back(shader);
- glShaderSource(shader, 1, &c_code, NULL);
- glCompileShader(shader);
- glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
- if (! success) {
- glGetShaderInfoLog(shader, 1024, NULL, buffer);
- throw runtime_error("Failed to compile " + it->first + " shader: " + buffer);
- }
- glAttachShader(id, shader);
- }
-
- glLinkProgram(id);
- glGetProgramiv(id, GL_LINK_STATUS, &success);
- if (! success) {
- glGetProgramInfoLog(id, 1024, NULL, buffer);
- throw runtime_error(string("Failed to link shader program: ") + buffer);
- }
-
- for (auto it = shaders.begin(); it != shaders.end(); it++) {
- glDeleteShader(*it);
- }
-}
-
-void ShaderProgram::use() const
-{
- glUseProgram(id);
-}
-
-void ShaderProgram::set(const string &name, bool value)
-{
- use();
- glUniform1i(glGetUniformLocation(id, name.c_str()), (int) value);
-}
-
-void ShaderProgram::set(const string &name, int value)
-{
- use();
- glUniform1i(glGetUniformLocation(id, name.c_str()), value);
-}
-
-void ShaderProgram::set(const string &name, float value)
-{
- use();
- glUniform1f(glGetUniformLocation(id, name.c_str()), value);
-}
-
-void ShaderProgram::set(const string &name, mat4 value)
-{
- use();
- glUniformMatrix4fv(glGetUniformLocation(id, name.c_str()), 1, GL_FALSE, value_ptr(value));
-}
-
-void ShaderProgram::set(const string &name, vec3 value)
-{
- use();
- glUniform3f(glGetUniformLocation(id, name.c_str()), value.x, value.y, value.z);
-}
-
-ShaderProgram::~ShaderProgram()
-{
- glDeleteProgram(id);
-}
+++ /dev/null
-#pragma once
-
-#include <map>
-#include <string>
-#include "gl.hpp"
-
-namespace dragonblocks
-{
- class ShaderProgram
- {
- public:
- static std::map<std::string, GLenum> shadertypes;
-
- void use() const;
- void set(const std::string &, bool);
- void set(const std::string &, int);
- void set(const std::string &, float);
- void set(const std::string &, glm::mat4);
- void set(const std::string &, glm::vec3);
-
- ShaderProgram(const std::string &);
- ~ShaderProgram();
-
- private:
- GLuint id;
- };
-}
+++ /dev/null
-#include <stdexcept>
-#define STB_IMAGE_IMPLEMENTATION
-#include "stb_image.h"
-#include "gldebug.hpp"
-#include "log.hpp"
-#include "texture.hpp"
-
-using namespace std;
-using namespace dragonblocks;
-
-bool Texture::mipmap;
-bool Texture::bilinear_filter;
-GLenum Texture::min_filter, Texture::mag_filter;
-
-void Texture::initArgs()
-{
- min_filter = mag_filter = bilinear_filter ? GL_LINEAR : GL_NEAREST;
- if (mipmap) {
- if (min_filter == GL_NEAREST) {
- min_filter = GL_NEAREST_MIPMAP_NEAREST;
- } else {
- min_filter = GL_LINEAR_MIPMAP_NEAREST;
- }
- }
- stbi_set_flip_vertically_on_load(true);
-}
-
-void Texture::bind() const
-{
- glBindTexture(GL_TEXTURE_2D, id); CHECKERR
-}
-
-void Texture::load(const string &path)
-{
- int width, height, nrChannels;
- unsigned char *data = stbi_load(path.c_str(), &width, &height, &nrChannels, 0);
- if (! data)
- throw runtime_error("Failed to load texture " + path);
- glGenTextures(1, &id); CHECKERR
- bind();
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Texture::min_filter); CHECKERR
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Texture::mag_filter); CHECKERR
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); CHECKERR
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); CHECKERR
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); CHECKERR
- if (Texture::mipmap)
- glGenerateMipmap(GL_TEXTURE_2D); CHECKERR
- stbi_image_free(data);
- glBindTexture(GL_TEXTURE_2D, 0); CHECKERR
- log("Loaded texture " + path);
-}
-
+++ /dev/null
-#pragma once
-
-#include <string>
-#include "gl.hpp"
-
-namespace dragonblocks
-{
- class Texture
- {
- public:
- static bool mipmap;
- static bool bilinear_filter;
-
- static void initArgs();
-
- void bind() const;
- void load(const std::string &);
- Texture() = default;
- Texture(const Texture &) = default;
-
- private:
- static GLenum min_filter, mag_filter;
-
- GLuint id;
- };
-}
+++ /dev/null
-#include <stdexcept>
-#include "render_engine.hpp"
-#include "window.hpp"
-
-using namespace std;
-using namespace glm;
-using namespace dragonblocks;
-
-Window *Window::singleton = nullptr;
-
-Window *Window::create(RenderEngine *r)
-{
- if (singleton)
- throw runtime_error("Window already exists");
- return singleton = new Window(r);
-}
-
-void Window::windowPosCallback(GLFWwindow *id, int x, int y)
-{
- singleton->posInput(x, y);
-}
-
-void Window::framebufferSizeCallback(GLFWwindow *id, int width, int height)
-{
- glViewport(0, 0, width, height);
- singleton->render_engine->updateProjectionMatrix();
- singleton->sizeInput(width, height);
-}
-
-void Window::cursorPosCallback(GLFWwindow *id, double x, double y)
-{
- singleton->cursorInput(x, y);
-}
-
-void Window::setTitle(const string &title)
-{
- glfwSetWindowTitle(id, title.c_str());
-}
-
-void Window::setSize(int width, int height)
-{
- glfwSetWindowSize(id, width, height);
-}
-
-void Window::setPos(int x, int y)
-{
- glfwSetWindowPos(id, x, y);
-}
-
-void Window::toggleFullscreen()
-{
- fullscreen = ! fullscreen;
-
- if (fullscreen) {
- GLFWmonitor *monitor = glfwGetPrimaryMonitor();
- const GLFWvidmode *vidmode = glfwGetVideoMode(monitor);
- glfwSetWindowMonitor(id, monitor, 0, 0, vidmode->width, vidmode->height, 0);
- }
- else
- glfwSetWindowMonitor(id, nullptr, nfs_x, nfs_y, nfs_width, nfs_height, 0);
-}
-
-void Window::close()
-{
- glfwDestroyWindow(id);
-}
-
-void Window::swapBuffers()
-{
- glfwSwapBuffers(id);
-}
-
-bool Window::shouldClose() const
-{
- return glfwWindowShouldClose(id);
-}
-
-bool Window::wasKeyDown(int key) const
-{
- return glfwGetKey(id, key) == GLFW_PRESS;
-}
-
-void Window::makeContextCurrent() const
-{
- glfwMakeContextCurrent(id);
-}
-
-ivec2 Window::getSize() const
-{
- return ivec2(width, height);
-}
-
-ivec2 Window::getCursorPos() const
-{
- return ivec2(cursor_x, cursor_y);
-}
-
-ivec2 Window::getCursorDelta()
-{
- ivec2 delta(cursor_delta_x, cursor_delta_y);
- cursor_delta_x = cursor_delta_y = 0;
- return delta;
-}
-
-void Window::posInput(int x, int y)
-{
- if (! fullscreen) {
- nfs_x = x;
- nfs_y = y;
- }
-}
-
-void Window::sizeInput(int w, int h)
-{
- width = w;
- height = h;
- if (! fullscreen) {
- nfs_width = width;
- nfs_height = height;
- }
-}
-
-void Window::cursorInput(int x, int y)
-{
- int lx = cursor_x;
- int ly = cursor_y;
- cursor_delta_x = x - lx;
- cursor_delta_y = y - ly;
- cursor_x = x;
- cursor_y = y;
-}
-
-Window::~Window()
-{
- close();
-}
-
-Window::Window(RenderEngine *r) : render_engine(r)
-{
- fullscreen = false;
- width = nfs_width = 100;
- height = nfs_height = 100;
- cursor_x = cursor_y = cursor_delta_x = cursor_delta_y = 0;
- id = glfwCreateWindow(width, height, "libdragonblocks.so", NULL, NULL);
- if (! id) {
- glfwTerminate();
- throw runtime_error("Failed to create GLFW window");
- }
- makeContextCurrent();
- glfwSetInputMode(id, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
- glfwSetWindowPosCallback(id, Window::windowPosCallback);
- glfwSetFramebufferSizeCallback(id, Window::framebufferSizeCallback);
- glfwSetCursorPosCallback(id, Window::cursorPosCallback);
-}
-
-
+++ /dev/null
-#pragma once
-
-#include <string>
-#include "gl.hpp"
-
-namespace dragonblocks
-{
- class RenderEngine;
-
- class Window
- {
- public:
- static Window *create(RenderEngine *);
- static void windowPosCallback(GLFWwindow *, int, int);
- static void framebufferSizeCallback(GLFWwindow *, int, int);
- static void cursorPosCallback(GLFWwindow *, double, double);
-
- void setTitle(const std::string &);
- void setPos(int, int);
- void setSize(int, int);
- void toggleFullscreen();
- void close();
- void swapBuffers();
- bool shouldClose() const;
- bool wasKeyDown(int) const;
- void makeContextCurrent() const;
- glm::ivec2 getSize() const;
- glm::ivec2 getCursorPos() const;
- glm::ivec2 getCursorDelta();
-
- ~Window();
-
- private:
- static Window *singleton;
-
- RenderEngine *render_engine;
- GLFWwindow *id;
- bool fullscreen;
- int width, height;
- int nfs_width, nfs_height, nfs_x, nfs_y;
- int cursor_x, cursor_y, cursor_delta_x, cursor_delta_y;
-
- void posInput(int, int);
- void sizeInput(int, int);
- void cursorInput(int, int);
-
- Window(RenderEngine *);
- };
-}
-
+++ /dev/null
-#include "world.hpp"
+++ /dev/null
-#pragma once
-
-#include "map.hpp"
-
-namespace dragonblocks
-{
- class World
- {
- public:
- Map map;
- };
-}
+++ /dev/null
-cmake_minimum_required(VERSION 3.0)
-
-add_executable(dragonblockslauncher
- launcher.cpp
- main.cpp
-)
-
-target_link_libraries(dragonblockslauncher dl)
-
-target_include_directories(dragonblockslauncher PUBLIC
- "${PROJECT_SOURCE_DIR}/lib/"
- "${PROJECT_SOURCE_DIR}/src/"
-)
+++ /dev/null
-#include <iostream>
-#include <dlfcn.h>
-#include <stdlib.h>
-#include "dragonblockslauncher/launcher.hpp"
-
-using namespace dragonblockslauncher;
-
-void dragonblockslauncher::log(std::string message)
-{
- std::cout << "[Launcher] " << message << std::endl;
-}
-
-void dragonblockslauncher::fail(std::string error, std::string details)
-{
- std::cerr
- << "Unable to launch dragonblocks: " << error << std::endl
- << "Details: " << details << std::endl;
- abort();
-}
-
-void dragonblockslauncher::launchDragonblocks(std::string gametype)
-{
- void* handle;
- std::string filename;
- std::string start_function_name;
- void (*start_function)();
-
- filename = "./libdragonblocks.so";
-
- log("Opening dynamic library at " + filename);
-
- handle = dlmopen(LM_ID_BASE, filename.c_str(), RTLD_NOW | RTLD_GLOBAL);
-
- if (!handle)
- fail("Failed to load " + filename, dlerror());
-
- if (gametype != "server" && gametype != "client" && gametype != "mainmenu")
- fail("Trying to start dragonblocks with unknown gametype", "gameype = " + gametype);
-
- start_function_name = "_dragonblocks_start_" + gametype;
-
- log("Obtaining start function pointer");
-
- start_function = (void (*)())dlsym(handle, start_function_name.c_str());
-
- if (!start_function)
- fail("Failed to obtain dragonblocks start function pointer", dlerror());
-
- log("Launching dragonblocks");
-
- (*start_function)();
-}
+++ /dev/null
-#pragma once
-
-#include <string>
-
-namespace dragonblockslauncher
-{
- void log(std::string);
- void fail(std::string, std::string);
- void launchDragonblocks(std::string);
-}
+++ /dev/null
-#include "dragonblockslauncher/launcher.hpp"
-
-int main(int argc, char *argv[])
-{
- dragonblockslauncher::launchDragonblocks("client");
-}
--- /dev/null
+#include "entity.hpp"
+
+using namespace glm;
+using namespace dragonblocks;
+
+void IEntity::setPos(vec3 p)
+{
+}
+
+vec3 IEntity::getPos()
+{
+ return vec3(0);
+}
+
+void IEntity::setSize(vec3 s)
+{
+}
+
+vec3 IEntity::getSize()
+{
+ return vec3(0);
+}
+
+void IEntity::setRotationAxis(vec3 r)
+{
+}
+
+vec3 IEntity::getRotationAxis()
+{
+ return vec3(0);
+}
+
+void IEntity::setRotationAngle(double r)
+{
+}
+
+double IEntity::getRotationAngle()
+{
+ return 0.0;
+}
+
+void IEntity::setVisible(bool v)
+{
+}
+
+bool IEntity::isVisible()
+{
+ return false;
+}
+
+IEntity::IEntity(Map *m) : map(m)
+{
+}
--- /dev/null
+#pragma once
+
+#include "async_mgr.hpp"
+#include "gl.hpp"
+#include "tile_def.hpp"
+
+namespace dragonblocks
+{
+ class Map;
+
+ class IEntity
+ {
+ public:
+ /*double vertical_speed;
+ double vertical_acceleration;
+ double horizontal_speed;
+ double horizontal_max_speed;
+ double horizontal_acceleration;
+ glm::vec3 horizontal_move_dir;
+ glm::vec3 vertical_move_dir;
+ */
+ double speed;
+
+ virtual void setPos(glm::vec3);
+ virtual glm::vec3 getPos();
+ virtual void setSize(glm::vec3);
+ virtual glm::vec3 getSize();
+ virtual void setRotationAxis(glm::vec3);
+ virtual glm::vec3 getRotationAxis();
+ virtual void setRotationAngle(double);
+ virtual double getRotationAngle();
+ virtual void setVisible(bool);
+ virtual bool isVisible();
+
+ protected:
+ Map *map;
+
+ IEntity(Map *);
+ };
+}
--- /dev/null
+#include "face_dir.hpp"
+
+using namespace glm;
+
+ivec3 dragonblocks::face_dir[6] = {
+ {+0, +0, -1},
+ {+0, +0, +1},
+ {-1, +0, +0},
+ {+1, +0, +0},
+ {+0, -1, +0},
+ {+0, +1, +0},
+};
--- /dev/null
+#pragma once
+
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ extern glm::ivec3 face_dir[6];
+}
--- /dev/null
+#include "block_def.hpp"
+#include "game.hpp"
+#include "mapgen.hpp"
+#include "tile_def.hpp"
+
+using namespace dragonblocks;
+
+Game::Game(Mapgen *m) : mapgen(m)
+{
+ grass_texture.load("textures/grass.png");
+ grass_side_texture.load("textures/grass_side.png");
+ dirt_texture.load("textures/dirt.png");
+ stone_texture.load("textures/stone.png");
+
+ air = new BlockDef("dragonblocks:air");
+ grass = new BlockDef("dragonblocks:grass", TileDef({grass_side_texture, grass_side_texture, grass_side_texture, grass_side_texture, dirt_texture, grass_texture}));
+ dirt = new BlockDef("dragonblocks:dirt", dirt_texture);
+ stone = new BlockDef("dragonblocks:stone", stone_texture);
+
+ mapgen->air_def = air;
+ mapgen->grass_def = grass;
+ mapgen->dirt_def = dirt;
+ mapgen->stone_def = stone;
+}
--- /dev/null
+#pragma once
+
+#include "texture.hpp"
+
+namespace dragonblocks
+{
+ class BlockDef;
+ class Mapgen;
+
+ class Game
+ {
+ public:
+ BlockDef *air, *grass, *dirt, *stone;
+ Mapgen *mapgen;
+ Texture grass_texture, grass_side_texture, dirt_texture, stone_texture;
+
+ Game(Mapgen *);
+ };
+}
--- /dev/null
+#include <iostream>
+#include <string>
+#include "gl.hpp"
+
+using namespace std;
+using namespace dragonblocks;
+
+GLenum dragonblocks::checkGLError(const char *file, int line)
+{
+ GLenum errorCode;
+ if ((errorCode = glGetError()) != GL_NO_ERROR)
+ {
+ string error;
+ switch (errorCode)
+ {
+ case GL_INVALID_ENUM: error = "INVALID_ENUM"; break;
+ case GL_INVALID_VALUE: error = "INVALID_VALUE"; break;
+ case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break;
+ case GL_STACK_OVERFLOW: error = "STACK_OVERFLOW"; break;
+ case GL_STACK_UNDERFLOW: error = "STACK_UNDERFLOW"; break;
+ case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break;
+ case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break;
+ }
+ cout << "OpenGL Error: " << error << " | " << file << " (" << line << ")" << endl;
+ }
+ return errorCode;
+}
--- /dev/null
+#pragma once
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <GLFW/glfw3.h>
+#include <glm/glm.hpp>
+
+//#define CHECKERR dragonblocks::checkGLError(__FILE__, __LINE__);
+#define CHECKERR
+
+namespace dragonblocks
+{
+ GLenum checkGLError(const char *file, int line);
+}
--- /dev/null
+#include "camera.hpp"
+#include "input_handler.hpp"
+#include "window.hpp"
+
+using namespace std;
+using namespace glm;
+using namespace dragonblocks;
+
+void InputHandler::processInput(double dtime)
+{
+ cursor_delta = vec2(mouse_sensitivity * dtime) * (vec2)window->getCursorDelta();
+ was_down.clear();
+ for (auto it = is_down.begin(); it != is_down.end(); it++) {
+ int key = *it;
+ if (! window->isKeyDown(key)) {
+ was_down.insert(key);
+ }
+ }
+ is_down.clear();
+ for (auto it = listened_keys.begin(); it != listened_keys.end(); it++) {
+ int key = *it;
+ if (window->isKeyDown(key)) {
+ is_down.insert(key);
+ }
+ }
+}
+
+void InputHandler::listenFor(int key)
+{
+ listened_keys.insert(key);
+}
+
+void InputHandler::dontListenFor(int key)
+{
+ listened_keys.erase(key);
+}
+
+bool InputHandler::isKeyDown(int key)
+{
+ return is_down.find(key) != is_down.end();
+}
+
+bool InputHandler::wasKeyDown(int key)
+{
+ return was_down.find(key) != was_down.end();
+}
+
+vec2 InputHandler::getCursorDelta()
+{
+ return cursor_delta;
+}
+
+void InputHandler::setWindow(Window *w)
+{
+ if (! window) {
+ window = w;
+ }
+}
--- /dev/null
+#pragma once
+
+#include <set>
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ class Camera;
+ class Window;
+
+ class InputHandler
+ {
+ public:
+ double mouse_sensitivity;
+
+ void processInput(double);
+ void listenFor(int);
+ void dontListenFor(int);
+ bool isKeyDown(int);
+ bool wasKeyDown(int);
+ glm::vec2 getCursorDelta();
+ void setWindow(Window *);
+
+ private:
+ Window *window;
+ std::set<int> listened_keys;
+ std::set<int> is_down;
+ std::set<int> was_down;
+ glm::vec2 cursor_delta;
+ };
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define __USE_GNU
+#include <dlfcn.h>
+
+void launch_dragonblocks(const char *gametype)
+{
+ void* handle;
+ const char *filename;
+ char *start_function_name;
+ void (*start_function)();
+
+ filename = "./libdragonblocks.so";
+
+ printf("Opening %s\n", filename);
+
+ handle = dlmopen(LM_ID_BASE, filename, RTLD_NOW | RTLD_GLOBAL);
+
+ if (! handle) {
+ printf("Failed to load %s\n\tDetails: %s\n", filename, dlerror());
+ abort();
+ }
+
+ if (strcmp(gametype, "client")) { // && strcmp(gametype, "server") && strcmp(gametype, "menu")
+ printf("Trying to start dragonblocks with unknown gametype (\"%s\")\n", gametype);
+ abort();
+ }
+
+ start_function_name = malloc(strlen("_dragonblocks_start_") + strlen(gametype) + 1);
+ strcpy(start_function_name, "_dragonblocks_start_");
+ strcat(start_function_name, gametype);
+
+ printf("Obtaing pointer to start function\n");
+
+ start_function = (void (*)())dlsym(handle, start_function_name);
+
+ free(start_function_name);
+
+ if (! start_function) {
+ printf("Failed to obtain dragonblocks start function pointer\n\tDetails: %s\n", dlerror());
+ abort();
+ }
+
+ printf("Starting dragonblocks\n");
+
+ (*start_function)();
+}
+
+int main(int argc, char *argv[])
+{
+ launch_dragonblocks("client");
+}
--- /dev/null
+#include "animations.hpp"
+#include "box_vertices.hpp"
+#include "local_entity.hpp"
+#include "mesh.hpp"
+
+using namespace glm;
+using namespace dragonblocks;
+
+void LocalEntity::setPos(vec3 p)
+{
+ mesh->pos = p;
+}
+
+vec3 LocalEntity::getPos()
+{
+ return mesh->pos;
+}
+
+void LocalEntity::setSize(vec3 s)
+{
+ mesh->minp = -(s / 2.0f);
+ mesh->maxp = +(s / 2.0f);
+ mesh->size = s;
+}
+
+vec3 LocalEntity::getSize()
+{
+ return mesh->size;
+}
+
+void LocalEntity::setRotationAxis(vec3 r)
+{
+ mesh->rotation_axis = r;
+}
+
+vec3 LocalEntity::getRotationAxis()
+{
+ return mesh->rotation_axis;
+}
+
+void LocalEntity::setRotationAngle(double r)
+{
+ mesh->rotation_angle = r;
+}
+
+double LocalEntity::getRotationAngle()
+{
+ return mesh->rotation_angle;
+}
+
+void LocalEntity::setVisible(bool v)
+{
+ mesh->visible = v;
+}
+
+bool LocalEntity::isVisible()
+{
+ return mesh->visible;
+}
+
+LocalEntity::LocalEntity(Map *m, Scene *s, const TileDef &t, ShaderProgram *sh) : IEntity(m), tile_def(t)
+{
+ mesh = new Mesh(s, sh, &box_vertices[0][0][0], 6 * 6 * 5);
+ mesh->textures = tile_def.tiles;
+ mesh->vertices_per_texture = 6;
+}
+
+LocalEntity::~LocalEntity()
+{
+ mesh->die();
+}
--- /dev/null
+#pragma once
+
+#include "async_mgr.hpp"
+#include "entity.hpp"
+#include "gl.hpp"
+#include "tile_def.hpp"
+
+namespace dragonblocks
+{
+ class Map;
+ class Mesh;
+ class Scene;
+ class ShaderProgram;
+
+ class LocalEntity : public IEntity
+ {
+ public:
+ void setPos(glm::vec3);
+ glm::vec3 getPos();
+ void setSize(glm::vec3);
+ glm::vec3 getSize();
+ void setRotationAxis(glm::vec3);
+ glm::vec3 getRotationAxis();
+ void setRotationAngle(double);
+ double getRotationAngle();
+ void setVisible(bool);
+ bool isVisible();
+ void step(double);
+
+ LocalEntity(Map *, Scene *, const TileDef &, ShaderProgram *);
+ ~LocalEntity();
+
+ protected:
+ TileDef tile_def;
+ Mesh *mesh;
+ };
+}
--- /dev/null
+#include <stdexcept>
+#include "camera.hpp"
+#include "input_handler.hpp"
+#include "local_player.hpp"
+#include "map.hpp"
+
+using namespace std;
+using namespace glm;
+using namespace dragonblocks;
+
+void LocalPlayer::step(double dtime)
+{
+ // Cursor input
+ vec2 cd = input_handler->getCursorDelta();
+ yaw += cd.x;
+ pitch -= cd.y;
+ pitch = clamp(pitch, -89.0, 89.0);
+
+ // Key input
+ vec3 pos = getPos();
+ vec3 vel = vec3(speed * dtime);
+ vec3 front = camera->front(), right = camera->right(), up = camera->up();
+ if (! pitch_move) {
+ front = normalize(vec3(front.x, 0, front.z));
+ up = normalize(vec3(0, up.y, 0));
+ }
+ if (input_handler->isKeyDown(GLFW_KEY_W)) {
+ pos += vel * front;
+ } else if (input_handler->isKeyDown(GLFW_KEY_S)) {
+ pos -= vel * front;
+ }
+ if (input_handler->isKeyDown(GLFW_KEY_D)) {
+ pos += vel * right;
+ } else if (input_handler->isKeyDown(GLFW_KEY_A)) {
+ pos -= vel * right;
+ }
+ if (input_handler->isKeyDown(GLFW_KEY_SPACE)) {
+ pos += vel * up;
+ } else if (input_handler->isKeyDown(GLFW_KEY_LEFT_SHIFT)) {
+ pos -= vel * up;
+ }
+
+ if (input_handler->wasKeyDown(GLFW_KEY_C)) {
+ camera->toggleMode();
+ }
+
+ camera->update(yaw, pitch, pos);
+ setPos(pos);
+ setVisible(camera->thirdPerson());
+ loadChunks();
+}
+
+void LocalPlayer::loadChunks()
+{
+ int dist = 4;
+ ivec3 chunkp = Map::getChunkPos(getPos());
+ for (int x = chunkp.x - dist; x <= chunkp.x + dist; x++) {
+ for (int y = chunkp.y - dist; y < chunkp.y + dist; y++) {
+ for (int z = chunkp.z - dist; z <= chunkp.z + dist; z++) {
+ map->createChunk(ivec3(x, y, z));
+ }
+ }
+ }
+}
+
+LocalPlayer::LocalPlayer(Map *m, Scene *s, const TileDef &t, ShaderProgram *sh, Camera *c, InputHandler *i) : LocalEntity(m, s, t, sh), camera(c), input_handler(i)
+{
+ input_handler->listenFor(GLFW_KEY_W);
+ input_handler->listenFor(GLFW_KEY_A);
+ input_handler->listenFor(GLFW_KEY_S);
+ input_handler->listenFor(GLFW_KEY_D);
+ input_handler->listenFor(GLFW_KEY_SPACE);
+ input_handler->listenFor(GLFW_KEY_LEFT_SHIFT);
+ input_handler->listenFor(GLFW_KEY_C);
+}
--- /dev/null
+#pragma once
+
+#include <vector>
+#include "local_entity.hpp"
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ class Camera;
+ class InputHandler;
+ class Map;
+ class Scene;
+ class ShaderProgram;
+
+ class LocalPlayer : public LocalEntity
+ {
+ public:
+ bool pitch_move;
+ double yaw, pitch;
+
+ void step(double);
+
+ LocalPlayer(Map *, Scene *, const TileDef &, ShaderProgram *, Camera *, InputHandler *);
+
+ private:
+ static void staticMouseHandler(double, double, double);
+ static void staticKeyHandler(double, std::set<int>);
+
+ Camera *camera;
+ InputHandler *input_handler;
+
+ void keyHandler(double, std::set<int>);
+ void loadChunks();
+ };
+}
--- /dev/null
+#include <stdexcept>
+#include "map.hpp"
+#include "mapgen.hpp"
+
+using namespace std;
+using namespace glm;
+using namespace dragonblocks;
+
+ivec3 Map::getChunkPos(const vec3 &p)
+{
+ return floor(p / (float)DRAGONBLOCKS_CHUNK_SIZE);
+}
+
+ivec3 Map::getBlockPos(const ivec3 &p)
+{
+ return ((p % DRAGONBLOCKS_CHUNK_SIZE) + ivec3(DRAGONBLOCKS_CHUNK_SIZE)) % DRAGONBLOCKS_CHUNK_SIZE;
+}
+
+uint16_t Map::getChunkPosHash(const ivec3 &p)
+{
+ return (uint16_t)p.x + (uint16_t)p.y * DRAGONBLOCKS_MAP_SIZE + (uint16_t)p.z * DRAGONBLOCKS_MAP_SIZE * DRAGONBLOCKS_MAP_SIZE;
+}
+
+const Block *Map::getBlock(const glm::ivec3 &p)
+{
+
+ Chunk *chunk = getChunk(Map::getChunkPos(p));
+ if (chunk)
+ return chunk->getBlock(Map::getBlockPos(p));
+ return nullptr;
+}
+
+void Map::setBlock(const glm::ivec3 &p, BlockDef *def)
+{
+ Chunk *chunk = getChunk(Map::getChunkPos(p));
+ if (chunk)
+ chunk->setBlock(Map::getBlockPos(p), def);
+}
+
+void Map::createChunk(const glm::ivec3 &p, const Chunk::Data &data)
+{
+ uint64_t poshash = Map::getChunkPosHash(p);
+
+ if (chunks[poshash])
+ return;
+
+ chunks[poshash] = new Chunk(this, p, data, async_mgr, scene, shader_program);
+}
+
+void Map::createChunk(const glm::ivec3 &p)
+{
+ if (! chunks[Map::getChunkPosHash(p)])
+ createChunk(p, mapgen->generate(p));
+}
+
+Chunk *Map::getChunk(const glm::ivec3 &p)
+{
+ return chunks[Map::getChunkPosHash(p)];
+}
+
+void Map::clear()
+{
+ for (auto it = chunks.begin(); it != chunks.end(); it++)
+ delete it->second;
+ chunks.clear();
+}
+
+Map::Map(Mapgen *m, AsyncMgr *a, Scene *s, ShaderProgram *sh) : mapgen(m), async_mgr(a), scene(s), shader_program(sh)
+{
+}
+
+Map::~Map()
+{
+ clear();
+}
--- /dev/null
+#pragma once
+
+#include <map>
+#include "chunk.hpp"
+#include "gl.hpp"
+
+#define DRAGONBLOCKS_MAP_SIZE 1000
+
+namespace dragonblocks
+{
+ class AsyncMgr;
+ class BlockDef;
+ class Block;
+ class Mapgen;
+ class Scene;
+ class ShaderProgram;
+
+ class Map
+ {
+ public:
+ static glm::ivec3 getChunkPos(const glm::vec3 &);
+ static glm::ivec3 getBlockPos(const glm::ivec3 &);
+ static uint16_t getChunkPosHash(const glm::ivec3 &);
+
+ const Block *getBlock(const glm::ivec3 &);
+ const Block *getBlockRelativePos(Chunk *, const glm::ivec3 &);
+ void setBlock(const glm::ivec3 &, BlockDef *);
+ void createChunk(const glm::ivec3 &, const Chunk::Data &);
+ void createChunk(const glm::ivec3 &);
+ Chunk *getChunk(const glm::ivec3 &);
+ void clear();
+
+ Map(Mapgen *, AsyncMgr *, Scene *, ShaderProgram *);
+ ~Map();
+
+ private:
+ std::map<uint16_t, Chunk*> chunks;
+ Mapgen *mapgen;
+ AsyncMgr *async_mgr;
+ Scene *scene;
+ ShaderProgram *shader_program;
+ };
+}
--- /dev/null
+#include <iostream>
+#include <glm/gtc/noise.hpp>
+#include "mapgen.hpp"
+
+using namespace glm;
+using namespace dragonblocks;
+
+Chunk::Data Mapgen::generate(const ivec3 &chunkp) const
+{
+ Chunk::Data data;
+ vec3 minp = chunkp * ivec3(DRAGONBLOCKS_CHUNK_SIZE);
+ vec3 maxp = minp + vec3(DRAGONBLOCKS_CHUNK_SIZE);
+ int minx = minp.x, miny = minp.y, minz = minp.z, maxx = maxp.x, maxy = maxp.y, maxz = maxp.z;
+ for (int x = minx; x < maxx; x++) {
+ int rx = x - minx;
+ for (int z = minz; z < maxz; z++) {
+ int rz = z - minz;
+ int grass_layer = grass_layer_middle + grass_layer_range * perlin(vec2((float)x / 64, (float)z / 64));
+ for (int y = miny; y < maxy; y++) {
+ int ry = y - miny;
+ BlockDef *blockdef;
+ if (y < grass_layer - 4)
+ blockdef = stone_def;
+ else if (y < grass_layer - 1)
+ blockdef = dirt_def;
+ else if (y < grass_layer)
+ blockdef = grass_def;
+ else
+ blockdef = air_def;
+ data.blocks[rx][ry][rz] = blockdef;
+ }
+ }
+ }
+ return data;
+}
--- /dev/null
+#pragma once
+
+#include "chunk.hpp"
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ class BlockDef;
+
+ class Mapgen
+ {
+ public:
+ float grass_layer_middle = 0, grass_layer_range = 32;
+ BlockDef *air_def, *stone_def, *dirt_def, *grass_def;
+
+ Chunk::Data generate(const glm::ivec3 &) const;
+ };
+};
--- /dev/null
+#include <iostream>
+#include <stdexcept>
+#include <cstdlib>
+#include <cstring>
+#include <glm/gtc/matrix_transform.hpp>
+#include "FrustumCull.h"
+#include "mesh.hpp"
+#include "scene.hpp"
+#include "shader_program.hpp"
+
+using namespace std;
+using namespace glm;
+using namespace dragonblocks;
+
+bool Mesh::IAnimation::expired(double dtime)
+{
+ if (expires) {
+ time_left -= dtime;
+ if (time_left < 0) {
+ if (on_finish) {
+ (*on_finish)(extra_data);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+vec3 Mesh::IAnimation::getPos(vec3 p)
+{
+ return p;
+}
+
+vec3 Mesh::IAnimation::getSize(vec3 s)
+{
+ return s;
+}
+
+vec3 Mesh::IAnimation::getRotationAxis(vec3 r)
+{
+ return r;
+}
+
+float Mesh::IAnimation::getRotationAngle(float r)
+{
+ return r;
+}
+
+Mesh::IAnimation::IAnimation(double t, void (*o)(void *), void *e) : time_left(t), on_finish(o), extra_data(e)
+{
+ expires = true;
+}
+
+void Mesh::render(double dtime, Frustum *frustum, mat4 projection_matrix, mat4 view_matrix, vec3 sky)
+{
+ rendering = true;
+
+ if (do_delete) {
+ delete this;
+ return;
+ } else if (prepare_death) {
+ do_delete = true;
+ }
+
+ if (! configured) {
+ configure();
+ }
+
+ shader_program->use(); CHECKERR
+
+ mat4 model_matrix = identity<mat4>();
+
+ vec3 n_pos = pos, n_size = size, n_rotation_axis = rotation_axis;
+ float n_rotation_angle = rotation_angle;
+
+ if (animation) {
+ if (animation->expired(dtime)) {
+ delete animation;
+ animation = nullptr;
+ } else {
+ n_pos = animation->getPos(n_pos);
+ n_size = animation->getSize(n_size);
+ n_rotation_axis = animation->getRotationAxis(n_rotation_axis);
+ n_rotation_angle = animation->getRotationAngle(n_rotation_angle);
+ }
+ }
+
+ model_matrix = translate(model_matrix, n_pos);
+ model_matrix = rotate(model_matrix, n_rotation_angle, n_rotation_axis);
+ model_matrix = scale(model_matrix, n_size);
+
+ if (! visible || ! frustum->IsBoxVisible(model_matrix * vec4(minp - vec3(1.0), 1.0), model_matrix * vec4(maxp + vec3(1.0), 1.0)))
+ return;
+
+ shader_program->set("model", model_matrix); CHECKERR
+ shader_program->set("view", view_matrix); CHECKERR
+ shader_program->set("projection", projection_matrix); CHECKERR
+ shader_program->set("sky", sky); CHECKERR
+
+ glBindVertexArray(VAO); CHECKERR
+ for (int i = 0; i < textures.size(); i++) {
+ textures[i].bind(); CHECKERR
+ glDrawArrays(GL_TRIANGLES, i * vertices_per_texture, vertices_per_texture); CHECKERR
+ }
+ glBindVertexArray(0); CHECKERR
+ glBindTexture(GL_TEXTURE_2D, 0); CHECKERR
+
+ rendering = false;
+}
+
+bool Mesh::isRendering()
+{
+ return rendering;
+}
+
+void Mesh::die()
+{
+ prepare_death = true;
+}
+
+Mesh::Mesh(Scene *s, ShaderProgram *sh, const GLfloat *v, GLsizei vs): pos(0), size(1), rotation_axis(0, 1, 0), scene(s), shader_program(sh), vertices_size(vs * sizeof(GLfloat))
+{
+ if (! v || ! vs)
+ throw runtime_error("Invalid Mesh configuration");
+ vertices = malloc(vertices_size);
+ memcpy(vertices, v, vertices_size);
+ scene->add(this);
+}
+
+Mesh::~Mesh()
+{
+ scene->remove(this);
+ if (VAO) {
+ glDeleteVertexArrays(1, &VAO); CHECKERR
+ }
+ if (VBO) {
+ glDeleteBuffers(1, &VAO); CHECKERR
+ }
+ if (animation) {
+ delete animation;
+ }
+}
+
+void Mesh::configure()
+{
+ glGenVertexArrays(1, &VAO); CHECKERR
+ glGenBuffers(1, &VBO); CHECKERR
+
+ glBindVertexArray(VAO); CHECKERR
+ glBindBuffer(GL_ARRAY_BUFFER, VBO); CHECKERR
+
+ glBufferData(GL_ARRAY_BUFFER, vertices_size, vertices, GL_STATIC_DRAW); CHECKERR
+
+ GLsizei stride = 5 * sizeof(GLfloat); CHECKERR
+
+ glVertexAttribPointer(0, 3, GL_FLOAT, false, stride, (GLvoid *)(0 * sizeof(GLfloat))); CHECKERR
+ glEnableVertexAttribArray(0); CHECKERR
+ glVertexAttribPointer(1, 2, GL_FLOAT, false, stride, (GLvoid *)(3 * sizeof(GLfloat))); CHECKERR
+ glEnableVertexAttribArray(1); CHECKERR
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0); CHECKERR
+ glBindVertexArray(0); CHECKERR
+
+ free(vertices);
+ vertices = NULL;
+ configured = true;
+}
--- /dev/null
+#pragma once
+
+#include <vector>
+#include "gl.hpp"
+#include "texture.hpp"
+
+class Frustum;
+
+namespace dragonblocks
+{
+ class Scene;
+ class ShaderProgram;
+
+ class Mesh
+ {
+ public:
+ class IAnimation
+ {
+ public:
+ bool expired(double);
+ virtual glm::vec3 getPos(glm::vec3);
+ virtual glm::vec3 getSize(glm::vec3);
+ virtual glm::vec3 getRotationAxis(glm::vec3);
+ virtual float getRotationAngle(float);
+
+ protected:
+ bool expires = false;
+ double time_left;
+ void (*on_finish)(void *);
+ void *extra_data;
+
+ IAnimation() = default;
+ IAnimation(double, void (*)(void *), void *);
+ };
+
+ int vertices_per_texture;
+ glm::vec3 pos, size, rotation_axis;
+ glm::vec3 minp, maxp;
+ float rotation_angle = 0;
+ std::vector<Texture> textures;
+ IAnimation *animation = nullptr;
+ bool visible = true;
+
+ void render(double dtime, Frustum *, glm::mat4, glm::mat4, glm::vec3);
+ bool isRendering();
+ void die();
+
+ Mesh(Scene *, ShaderProgram *, const GLfloat *, GLsizei);
+
+ private:
+ GLuint VAO = 0, VBO = 0;
+ Scene *scene;
+ ShaderProgram *shader_program;
+ GLvoid *vertices = NULL;
+ GLsizeiptr vertices_size;
+ bool configured = false;
+ bool rendering = false;
+ bool prepare_death = false;
+ bool do_delete = false;
+
+ void configure();
+
+ ~Mesh();
+ };
+}
--- /dev/null
+#include <stdexcept>
+#include <glm/gtc/matrix_transform.hpp>
+#include "FrustumCull.h"
+#include "camera.hpp"
+#include "input_handler.hpp"
+#include "render_engine.hpp"
+#include "scene.hpp"
+#include "shader_program.hpp"
+#include "window.hpp"
+
+using namespace std;
+using namespace glm;
+using namespace dragonblocks;
+
+void RenderEngine::render(double dtime)
+{
+ glClearColor(sky.r, sky.g, sky.b, 1.0); CHECKERR
+
+ /*
+ glEnable(GL_CULL_FACE); CHECKERR
+ glCullFace(GL_BACK); CHECKERR
+ glFrontFace(GL_CW); CHECKERR
+ */
+
+ glEnable(GL_DEPTH_TEST); CHECKERR
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); CHECKERR
+
+
+ dvec2 window_size = window->getSize();
+ mat4 projection_matrix = perspective(radians(fov), window_size.x / window_size.y, 0.01, render_distance);
+
+ mat4 view_matrix = camera->getViewMatrix();
+
+ Frustum frustum(projection_matrix * view_matrix);
+
+ scene->render(dtime, &frustum, projection_matrix, view_matrix, sky);
+
+ window->swapBuffers(); CHECKERR
+ glfwPollEvents(); CHECKERR
+}
+
+bool RenderEngine::running()
+{
+ return ! window->shouldClose();
+}
+
+RenderEngine::RenderEngine()
+{
+ if (! glfwInit()) {
+ throw runtime_error("Failed to initialize GLFW");
+ }
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+
+ window = Window::create(this);
+ camera = new Camera;
+ scene = new Scene;
+
+ GLenum glew_init_err = glewInit();
+ if (glew_init_err != GLEW_OK) {
+ throw runtime_error("Failed to initialize GLEW");
+ }
+}
+
+RenderEngine::~RenderEngine()
+{
+ delete window;
+ delete camera;
+ delete scene;
+}
--- /dev/null
+#pragma once
+
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ class Camera;
+ class InputHandler;
+ class Scene;
+ class Window;
+
+ class RenderEngine
+ {
+ public:
+ Camera *camera;
+ Scene *scene;
+ Window *window;
+ double render_distance = 16;
+ double fov = 45;
+ glm::vec3 sky;
+
+ void render(double);
+ bool running();
+
+ RenderEngine();
+ ~RenderEngine();
+ };
+}
--- /dev/null
+#include "mesh.hpp"
+#include "scene.hpp"
+
+using namespace std;
+using namespace glm;
+using namespace dragonblocks;
+
+void Scene::add(Mesh *m)
+{
+ meshes.insert(m);
+}
+
+void Scene::remove(Mesh *m)
+{
+ meshes.erase(m);
+}
+
+void Scene::render(double dtime, Frustum *frustum, mat4 projection_matrix, mat4 view_matrix, vec3 sky)
+{
+ auto renderlist = meshes;
+ for (auto it = renderlist.begin(); it != renderlist.end(); it++) {
+ Mesh *mesh = *it;
+ mesh->render(dtime, frustum, projection_matrix, view_matrix, sky);
+ }
+}
+
+void Scene::clear()
+{
+ meshes.clear();
+}
+
+Scene::~Scene()
+{
+ clear();
+}
--- /dev/null
+#pragma once
+
+#include <set>
+#include "gl.hpp"
+
+class Frustum;
+
+namespace dragonblocks
+{
+ class Mesh;
+ class ShaderProgram;
+
+ class Scene {
+ public:
+ void add(Mesh *);
+ void remove(Mesh *);
+ void render(double, Frustum *, glm::mat4, glm::mat4, glm::vec3);
+ void clear();
+ void run();
+
+ ~Scene();
+
+ private:
+ std::set<Mesh *> meshes;
+ };
+}
--- /dev/null
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+#include <vector>
+#include <glm/gtc/type_ptr.hpp>
+#include "shader_program.hpp"
+
+using namespace std;
+using namespace glm;
+using namespace dragonblocks;
+
+map<string, GLenum> ShaderProgram::shadertypes = {
+ {"vertex", GL_VERTEX_SHADER},
+ {"fragment", GL_FRAGMENT_SHADER},
+};
+
+ShaderProgram::ShaderProgram(const string &global_path)
+{
+ int success;
+ char buffer[1024] = {};
+ vector<GLuint> shaders;
+
+ id = glCreateProgram();
+
+ for (auto it = ShaderProgram::shadertypes.begin(); it != ShaderProgram::shadertypes.end(); it++) {
+ const char *c_code;
+ GLuint shader;
+ string path, code;
+ ifstream file;
+ stringstream stream;
+
+ path = global_path + "/" + it->first + ".glsl";
+ file.exceptions(ifstream::failbit | ifstream::badbit);
+ file.open(path);
+ stream << file.rdbuf();
+ code = stream.str();
+ c_code = code.c_str();
+
+ shader = glCreateShader(it->second);
+ shaders.push_back(shader);
+ glShaderSource(shader, 1, &c_code, NULL);
+ glCompileShader(shader);
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
+ if (! success) {
+ glGetShaderInfoLog(shader, 1024, NULL, buffer);
+ throw runtime_error("Failed to compile " + it->first + " shader: " + buffer);
+ }
+ glAttachShader(id, shader);
+ }
+
+ glLinkProgram(id);
+ glGetProgramiv(id, GL_LINK_STATUS, &success);
+ if (! success) {
+ glGetProgramInfoLog(id, 1024, NULL, buffer);
+ throw runtime_error(string("Failed to link shader program: ") + buffer);
+ }
+
+ for (auto it = shaders.begin(); it != shaders.end(); it++) {
+ glDeleteShader(*it);
+ }
+}
+
+void ShaderProgram::use() const
+{
+ glUseProgram(id);
+}
+
+void ShaderProgram::set(const string &name, bool value)
+{
+ use();
+ glUniform1i(glGetUniformLocation(id, name.c_str()), (int) value);
+}
+
+void ShaderProgram::set(const string &name, int value)
+{
+ use();
+ glUniform1i(glGetUniformLocation(id, name.c_str()), value);
+}
+
+void ShaderProgram::set(const string &name, float value)
+{
+ use();
+ glUniform1f(glGetUniformLocation(id, name.c_str()), value);
+}
+
+void ShaderProgram::set(const string &name, mat4 value)
+{
+ use();
+ glUniformMatrix4fv(glGetUniformLocation(id, name.c_str()), 1, GL_FALSE, value_ptr(value));
+}
+
+void ShaderProgram::set(const string &name, vec3 value)
+{
+ use();
+ glUniform3f(glGetUniformLocation(id, name.c_str()), value.x, value.y, value.z);
+}
+
+ShaderProgram::~ShaderProgram()
+{
+ glDeleteProgram(id);
+}
--- /dev/null
+#pragma once
+
+#include <map>
+#include <string>
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ class ShaderProgram
+ {
+ public:
+ static std::map<std::string, GLenum> shadertypes;
+
+ void use() const;
+ void set(const std::string &, bool);
+ void set(const std::string &, int);
+ void set(const std::string &, float);
+ void set(const std::string &, glm::mat4);
+ void set(const std::string &, glm::vec3);
+
+ ShaderProgram(const std::string &);
+ ~ShaderProgram();
+
+ private:
+ GLuint id;
+ };
+}
--- /dev/null
+#include <iostream>
+#include <stdexcept>
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+#include "texture.hpp"
+
+using namespace std;
+using namespace dragonblocks;
+
+bool Texture::mipmap;
+bool Texture::bilinear_filter;
+GLenum Texture::min_filter, Texture::mag_filter;
+
+void Texture::initArgs()
+{
+ min_filter = mag_filter = bilinear_filter ? GL_LINEAR : GL_NEAREST;
+ if (mipmap) {
+ if (min_filter == GL_NEAREST) {
+ min_filter = GL_NEAREST_MIPMAP_NEAREST;
+ } else {
+ min_filter = GL_LINEAR_MIPMAP_NEAREST;
+ }
+ }
+ stbi_set_flip_vertically_on_load(true);
+}
+
+void Texture::bind() const
+{
+ glBindTexture(GL_TEXTURE_2D, id); CHECKERR
+}
+
+void Texture::load(const string &path)
+{
+ int width, height, nrChannels;
+ unsigned char *data = stbi_load(path.c_str(), &width, &height, &nrChannels, 0);
+ if (! data)
+ throw runtime_error("Failed to load texture " + path);
+ glGenTextures(1, &id); CHECKERR
+ bind();
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Texture::min_filter); CHECKERR
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Texture::mag_filter); CHECKERR
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); CHECKERR
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); CHECKERR
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); CHECKERR
+ if (Texture::mipmap)
+ glGenerateMipmap(GL_TEXTURE_2D); CHECKERR
+ stbi_image_free(data);
+ glBindTexture(GL_TEXTURE_2D, 0); CHECKERR
+ cout << "Loaded texture " << path << endl;
+}
+
--- /dev/null
+#pragma once
+
+#include <string>
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ class Texture
+ {
+ public:
+ static bool mipmap;
+ static bool bilinear_filter;
+
+ static void initArgs();
+
+ void bind() const;
+ void load(const std::string &);
+ Texture() = default;
+ Texture(const Texture &) = default;
+
+ private:
+ static GLenum min_filter, mag_filter;
+
+ GLuint id;
+ };
+}
--- /dev/null
+#include "tile_def.hpp"
+
+using namespace std;
+using namespace dragonblocks;
+
+Texture TileDef::get(int i) const
+{
+ return tiles[i];
+}
+
+int TileDef::size() const
+{
+ return tiles.size();
+}
+
+TileDef::TileDef(const vector<Texture> &t) : tiles(t)
+{
+ int s = size();
+ for (int i = 0; s < 6; i += s) {
+ for (int j = 0; j < i && j + i < 6; j++) {
+ tiles[i + j] = tiles[j];
+ }
+ }
+}
+
+TileDef::TileDef(const Texture &t) : TileDef({t, t, t, t, t, t})
+{
+}
+
+
--- /dev/null
+#pragma once
+
+#include <vector>
+#include "texture.hpp"
+
+namespace dragonblocks
+{
+ class TileDef
+ {
+ public:
+ std::vector<Texture> tiles;
+
+ Texture get(int) const;
+ int size() const;
+
+ TileDef() = default;
+ TileDef(const Texture &);
+ TileDef(const std::vector<Texture> &);
+ };
+}
--- /dev/null
+#include <stdexcept>
+#include "render_engine.hpp"
+#include "window.hpp"
+
+using namespace std;
+using namespace glm;
+using namespace dragonblocks;
+
+Window *Window::singleton = nullptr;
+
+Window *Window::create(RenderEngine *r)
+{
+ if (singleton) {
+ throw runtime_error("Window already exists");
+ }
+ return singleton = new Window(r);
+}
+
+void Window::windowPosCallback(GLFWwindow *id, int x, int y)
+{
+ singleton->posInput(x, y);
+}
+
+void Window::framebufferSizeCallback(GLFWwindow *id, int width, int height)
+{
+ glViewport(0, 0, width, height);
+ singleton->sizeInput(width, height);
+}
+
+void Window::cursorPosCallback(GLFWwindow *id, double x, double y)
+{
+ singleton->cursorInput(x, y);
+}
+
+void Window::setTitle(const string &title)
+{
+ glfwSetWindowTitle(id, title.c_str());
+}
+
+void Window::setSize(int width, int height)
+{
+ glfwSetWindowSize(id, width, height);
+}
+
+void Window::setPos(int x, int y)
+{
+ glfwSetWindowPos(id, x, y);
+}
+
+void Window::toggleFullscreen()
+{
+ fullscreen = ! fullscreen;
+
+ if (fullscreen) {
+ GLFWmonitor *monitor = glfwGetPrimaryMonitor();
+ const GLFWvidmode *vidmode = glfwGetVideoMode(monitor);
+ glfwSetWindowMonitor(id, monitor, 0, 0, vidmode->width, vidmode->height, 0);
+ }
+ else
+ glfwSetWindowMonitor(id, nullptr, nfs_x, nfs_y, nfs_width, nfs_height, 0);
+}
+
+void Window::close()
+{
+ glfwDestroyWindow(id);
+}
+
+void Window::swapBuffers()
+{
+ glfwSwapBuffers(id);
+}
+
+bool Window::shouldClose() const
+{
+ return glfwWindowShouldClose(id);
+}
+
+bool Window::isKeyDown(int key) const
+{
+ return glfwGetKey(id, key) == GLFW_PRESS;
+}
+
+void Window::makeContextCurrent() const
+{
+ glfwMakeContextCurrent(id);
+}
+
+ivec2 Window::getSize() const
+{
+ return ivec2(width, height);
+}
+
+ivec2 Window::getCursorPos() const
+{
+ return ivec2(cursor_x, cursor_y);
+}
+
+ivec2 Window::getCursorDelta()
+{
+ ivec2 delta(cursor_delta_x, cursor_delta_y);
+ cursor_delta_x = cursor_delta_y = 0;
+ return delta;
+}
+
+void Window::posInput(int x, int y)
+{
+ if (! fullscreen) {
+ nfs_x = x;
+ nfs_y = y;
+ }
+}
+
+void Window::sizeInput(int w, int h)
+{
+ width = w;
+ height = h;
+ if (! fullscreen) {
+ nfs_width = width;
+ nfs_height = height;
+ }
+}
+
+void Window::cursorInput(int x, int y)
+{
+ int lx = cursor_x;
+ int ly = cursor_y;
+ cursor_delta_x = x - lx;
+ cursor_delta_y = y - ly;
+ cursor_x = x;
+ cursor_y = y;
+}
+
+Window::~Window()
+{
+ close();
+}
+
+Window::Window(RenderEngine *r) : render_engine(r)
+{
+ fullscreen = false;
+ width = nfs_width = 100;
+ height = nfs_height = 100;
+ cursor_x = cursor_y = cursor_delta_x = cursor_delta_y = 0;
+ id = glfwCreateWindow(width, height, "libdragonblocks.so", NULL, NULL);
+ if (! id) {
+ glfwTerminate();
+ throw runtime_error("Failed to create GLFW window");
+ }
+ makeContextCurrent();
+ glfwSetInputMode(id, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+ glfwSetWindowPosCallback(id, Window::windowPosCallback);
+ glfwSetFramebufferSizeCallback(id, Window::framebufferSizeCallback);
+ glfwSetCursorPosCallback(id, Window::cursorPosCallback);
+}
+
+
--- /dev/null
+#pragma once
+
+#include <string>
+#include "gl.hpp"
+
+namespace dragonblocks
+{
+ class RenderEngine;
+
+ class Window
+ {
+ public:
+ static Window *create(RenderEngine *);
+ static void windowPosCallback(GLFWwindow *, int, int);
+ static void framebufferSizeCallback(GLFWwindow *, int, int);
+ static void cursorPosCallback(GLFWwindow *, double, double);
+
+ void setTitle(const std::string &);
+ void setPos(int, int);
+ void setSize(int, int);
+ void toggleFullscreen();
+ void close();
+ void swapBuffers();
+ bool shouldClose() const;
+ bool isKeyDown(int) const;
+ void makeContextCurrent() const;
+ glm::ivec2 getSize() const;
+ glm::ivec2 getCursorPos() const;
+ glm::ivec2 getCursorDelta();
+
+ ~Window();
+
+ private:
+ static Window *singleton;
+
+ RenderEngine *render_engine;
+ GLFWwindow *id;
+ bool fullscreen;
+ int width, height;
+ int nfs_width, nfs_height, nfs_x, nfs_y;
+ int cursor_x, cursor_y, cursor_delta_x, cursor_delta_y;
+
+ void posInput(int, int);
+ void sizeInput(int, int);
+ void cursorInput(int, int);
+
+ Window(RenderEngine *);
+ };
+}
+