images, better shaders, etc
This commit is contained in:
parent
799fd1c7dc
commit
52dd65b64e
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "src/stb"]
|
||||||
|
path = src/stb
|
||||||
|
url = https://github.com/nothings/stb
|
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
|
|
||||||
project(NuclearPlantSim VERSION 1.0)
|
project(NuclearPlantSim LANGUAGES C CXX)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 927 B |
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
layout (binding = TEX_ATLAS) uniform sampler2DArray tex_atlas;
|
||||||
|
|
||||||
|
struct AtlasPart {
|
||||||
|
vec2 uv0;
|
||||||
|
vec2 uv1;
|
||||||
|
int zpos;
|
||||||
|
int edges; // 0 = repeat, 1 = clamp
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140, binding = SSBO_ATLAS_BUFFER) readonly buffer AtlasBuffer {
|
||||||
|
AtlasPart atlas[];
|
||||||
|
};
|
||||||
|
|
||||||
|
vec4 atlas_read_texture(uint tex, vec2 uv) {
|
||||||
|
AtlasPart a = atlas[tex];
|
||||||
|
uv = (a.edges == 0 ? fract(uv) : clamp(uv, 0.f, 1.f)) * (a.uv1 - a.uv0) + a.uv0;
|
||||||
|
return texture(tex_atlas, vec3(uv, a.zpos));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#version 430 core
|
||||||
|
|
||||||
|
#define SSBO_ATLAS_BUFFER 1
|
||||||
|
#define TEX_ATLAS 1
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
|
|
||||||
#include "version.glsl"
|
#include "header.glsl"
|
||||||
|
#include "atlas.glsl"
|
||||||
|
|
||||||
out vec4 f_colour;
|
out vec4 f_colour;
|
||||||
|
|
||||||
in VS_OUT {
|
in VS_OUT {
|
||||||
vec4 pos;
|
vec4 pos;
|
||||||
vec4 colour;
|
vec4 colour;
|
||||||
|
vec2 uv;
|
||||||
|
flat uint texid;
|
||||||
} vin;
|
} vin;
|
||||||
|
|
||||||
uniform mat4 u_colour = mat4(1);
|
uniform mat4 u_colour = mat4(1);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
f_colour = u_colour * vin.colour;
|
f_colour = u_colour * vin.colour * atlas_read_texture(vin.texid, vin.uv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
|
|
||||||
#include "version.glsl"
|
#include "header.glsl"
|
||||||
|
|
||||||
layout (location = 0) in vec3 v_pos;
|
layout (location = 0) in vec4 v_pos;
|
||||||
layout (location = 1) in vec4 v_colour;
|
layout (location = 1) in vec4 v_colour;
|
||||||
|
layout (location = 2) in vec2 v_uv;
|
||||||
|
layout (location = 3) in uint v_texid;
|
||||||
|
|
||||||
out VS_OUT {
|
out VS_OUT {
|
||||||
vec4 pos;
|
vec4 pos;
|
||||||
vec4 colour;
|
vec4 colour;
|
||||||
|
vec2 uv;
|
||||||
|
flat uint texid;
|
||||||
} vout;
|
} vout;
|
||||||
|
|
||||||
uniform mat4 u_model = mat4(1);
|
uniform mat4 u_model = mat4(1);
|
||||||
|
@ -15,8 +19,10 @@ uniform mat4 u_projection = mat4(1);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
mat4 mat_mv = u_view * u_model;
|
mat4 mat_mv = u_view * u_model;
|
||||||
vout.pos = mat_mv * vec4(v_pos, 1);
|
vout.pos = mat_mv * v_pos;
|
||||||
vout.colour = v_colour;
|
vout.colour = v_colour;
|
||||||
|
vout.uv = v_uv;
|
||||||
|
vout.texid = v_texid;
|
||||||
vec4 p = u_projection * vout.pos;
|
vec4 p = u_projection * vout.pos;
|
||||||
gl_Position = vec4(p.xy, 2 / (p.z + 2) - 1, p.w);
|
gl_Position = vec4(p.xy, 2 / (p.z + 2) - 1, p.w);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
|
|
||||||
#version 430 core
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
file(GLOB SOURCES ${SOURCES} src/*.cpp)
|
file(GLOB SOURCES ${SOURCES} src/*.cpp)
|
||||||
|
|
||||||
|
include(src/stb/files.cmake)
|
||||||
include(src/graphics/files.cmake)
|
include(src/graphics/files.cmake)
|
||||||
include(src/util/files.cmake)
|
include(src/util/files.cmake)
|
||||||
include(src/world/files.cmake)
|
include(src/world/files.cmake)
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
using Graphics::Context;
|
using Graphics::Context;
|
||||||
|
|
||||||
Context::Context(GLFWwindow* window, unsigned int program) {
|
Context::Context(GLFWwindow* window, unsigned int program) {
|
||||||
|
assert(window);
|
||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
m_u_model = glGetUniformLocation(program, "u_model");
|
m_u_model = glGetUniformLocation(program, "u_model");
|
||||||
m_u_view = glGetUniformLocation(program, "u_view");
|
m_u_view = glGetUniformLocation(program, "u_view");
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
file(GLOB SOURCES ${SOURCES} src/graphics/*.cpp)
|
file(GLOB SOURCES ${SOURCES} src/graphics/*.cpp)
|
||||||
|
|
||||||
|
include(src/graphics/texture/files.cmake)
|
||||||
include(src/graphics/shader/files.cmake)
|
include(src/graphics/shader/files.cmake)
|
||||||
include(src/graphics/gl/files.cmake)
|
include(src/graphics/gl/files.cmake)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,17 @@ namespace Graphics {
|
||||||
void add_primitive(const Primitive<VERTICES, INDICES>& p) {
|
void add_primitive(const Primitive<VERTICES, INDICES>& p) {
|
||||||
unsigned int index_at = m_vertices.size();
|
unsigned int index_at = m_vertices.size();
|
||||||
for(int i = 0; i < VERTICES; i++) {
|
for(int i = 0; i < VERTICES; i++) {
|
||||||
m_vertices.push_back(p.m_vertices[i]);
|
Vertex v = p.m_vertices[i];
|
||||||
|
if(p.m_colour.has_value()) {
|
||||||
|
v.m_colour *= p.m_colour.value();
|
||||||
|
}
|
||||||
|
if(p.m_offset.has_value()) {
|
||||||
|
v.m_pos += p.m_offset.value();
|
||||||
|
}
|
||||||
|
if(p.m_texid.has_value()) {
|
||||||
|
v.m_texid = p.m_texid.value();
|
||||||
|
}
|
||||||
|
m_vertices.push_back(v);
|
||||||
}
|
}
|
||||||
for(int i = 0; i < INDICES; i++) {
|
for(int i = 0; i < INDICES; i++) {
|
||||||
m_indices.push_back(p.m_indices[i] + index_at);
|
m_indices.push_back(p.m_indices[i] + index_at);
|
||||||
|
|
|
@ -12,8 +12,8 @@ using Graphics::Pipeline;
|
||||||
Pipeline::Pipeline() {
|
Pipeline::Pipeline() {
|
||||||
Graphics::GL::Shader model_vert(GL_VERTEX_SHADER);
|
Graphics::GL::Shader model_vert(GL_VERTEX_SHADER);
|
||||||
Graphics::GL::Shader model_frag(GL_FRAGMENT_SHADER);
|
Graphics::GL::Shader model_frag(GL_FRAGMENT_SHADER);
|
||||||
Graphics::Shader::compile(model_vert, "../assets/shader/model.vert");
|
Graphics::Shader::compile(model_vert, "model.vert");
|
||||||
Graphics::Shader::compile(model_frag, "../assets/shader/model.frag");
|
Graphics::Shader::compile(model_frag, "model.frag");
|
||||||
Graphics::Shader::link(m_program_model, {model_vert, model_frag});
|
Graphics::Shader::link(m_program_model, {model_vert, model_frag});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,20 +3,17 @@
|
||||||
|
|
||||||
#include "vertex.hpp"
|
#include "vertex.hpp"
|
||||||
#include <glm/matrix.hpp>
|
#include <glm/matrix.hpp>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace Graphics {
|
namespace Graphics {
|
||||||
template <int VERTICES, int INDICES>
|
template <int VERTICES, int INDICES>
|
||||||
struct Primitive {
|
struct Primitive {
|
||||||
Vertex m_vertices[VERTICES];
|
Vertex m_vertices[VERTICES];
|
||||||
unsigned int m_indices[INDICES];
|
int m_indices[INDICES];
|
||||||
|
|
||||||
constexpr Primitive with_colour(glm::vec4 colour) const {
|
std::optional<unsigned int> m_texid;
|
||||||
Primitive p = *this;
|
std::optional<glm::vec4> m_colour;
|
||||||
for(Vertex& v : p.m_vertices) {
|
std::optional<glm::vec4> m_offset;
|
||||||
v.m_colour *= colour;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Primitive with_matrix(glm::mat4 mat) const {
|
constexpr Primitive with_matrix(glm::mat4 mat) const {
|
||||||
Primitive p = *this;
|
Primitive p = *this;
|
||||||
|
@ -25,14 +22,6 @@ namespace Graphics {
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Primitive with_translation(glm::vec3 vec) const {
|
|
||||||
Primitive p = *this;
|
|
||||||
for(Vertex& v : p.m_vertices) {
|
|
||||||
v.m_pos += glm::vec4(vec, 0);
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Graphics::Shader {
|
||||||
|
constexpr int SSBO_ATLAS_BUFFER = 1;
|
||||||
|
constexpr int TEX_ATLAS = 1;
|
||||||
|
};
|
||||||
|
|
|
@ -105,7 +105,8 @@ static bool parse(std::vector<char>& source, const std::filesystem::path& path)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::Shader::compile(unsigned int shader, const std::filesystem::path& path) {
|
void Graphics::Shader::compile(unsigned int shader, const char* filename) {
|
||||||
|
std::filesystem::path path = std::filesystem::path("../assets/shader/").append(filename);
|
||||||
std::vector<char> source;
|
std::vector<char> source;
|
||||||
|
|
||||||
if(!parse(source, path)) {
|
if(!parse(source, path)) {
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
namespace Graphics::Shader {
|
namespace Graphics::Shader {
|
||||||
void compile(unsigned int shader, const std::filesystem::path& path);
|
void compile(unsigned int shader, const char* path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "texture/image.hpp"
|
||||||
|
|
||||||
|
namespace Graphics::Texture {
|
||||||
|
inline Image YELLOW_BRICK_WALL {"yellow_brick_wall.png", Image::Edge::CLAMP};
|
||||||
|
|
||||||
|
inline Image* const IMAGES[] {
|
||||||
|
&YELLOW_BRICK_WALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void generate_atlas();
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
|
||||||
|
#include "atlas.hpp"
|
||||||
|
#include "image.hpp"
|
||||||
|
#include <GL/gl.h>
|
||||||
|
|
||||||
|
using Graphics::Texture::Atlas;
|
||||||
|
using Graphics::Texture::Image;
|
||||||
|
|
||||||
|
Atlas::Pixel::Pixel(const Pixel& p) {
|
||||||
|
for(int i = 0; i < N; i++) {
|
||||||
|
m_data[i] = p.m_data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Atlas::Pixel::Pixel(const uint8_t* p) {
|
||||||
|
for(int i = 0; i < N; i++) {
|
||||||
|
m_data[i] = p[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Atlas::Pixel::operator == (const Pixel& p) const {
|
||||||
|
for(int i = 0; i < N; i++) {
|
||||||
|
if(m_data[i] != p.m_data[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Atlas::Pixel::operator != (const Pixel& p) const {
|
||||||
|
return !(*this == p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Atlas::Pixel& Atlas::Pixel::operator = (const Pixel& p) {
|
||||||
|
for(int i = 0; i < N; i++) {
|
||||||
|
m_data[i] = p.m_data[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Atlas::Pixel& Atlas::Pixel::operator = (const uint8_t* p) {
|
||||||
|
for(int i = 0; i < N; i++) {
|
||||||
|
m_data[i] = p[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t& Atlas::Pixel::operator [] (int i) {
|
||||||
|
return m_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t& Atlas::Pixel::operator [] (int i) const {
|
||||||
|
return m_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Atlas::Atlas(glm::vec<2, int> size) : m_size({size, 1}), m_data(size.x * size.y) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Atlas::Atlas(glm::vec<3, int> size) : m_size(size), m_data(size.x * size.y * size.z) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Atlas::Pixel& Atlas::get(glm::vec<3, int> p) {
|
||||||
|
int z_off = p.z * m_size.x * m_size.y;
|
||||||
|
|
||||||
|
if(z_off >= m_data.size()) {
|
||||||
|
m_size.z = p.z + 1;
|
||||||
|
m_data.resize(m_size.x * m_size.y * m_size.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_data[z_off + p.y * m_size.x + p.x];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Atlas::Pixel& Atlas::get(glm::vec<3, int> p) const {
|
||||||
|
static const Atlas::Pixel empty;
|
||||||
|
int z_off = p.z * m_size.x * m_size.y;
|
||||||
|
|
||||||
|
if(z_off >= m_data.size()) {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_data[z_off + p.y * m_size.x + p.x];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DrawSrcImage {
|
||||||
|
glm::vec<2, int> m_size;
|
||||||
|
const Image* m_image;
|
||||||
|
|
||||||
|
DrawSrcImage(const Image& image) {
|
||||||
|
m_size = image.m_size;
|
||||||
|
m_image = ℑ
|
||||||
|
}
|
||||||
|
|
||||||
|
Atlas::Pixel get(glm::vec<2, int> pos) const {
|
||||||
|
const uint8_t* pixel_ptr = m_image->get(pos);
|
||||||
|
Atlas::Pixel pixel;
|
||||||
|
|
||||||
|
for(int i = 0; i < 4; i++) {
|
||||||
|
switch(m_image->m_mapping[i]) {
|
||||||
|
case GL_ZERO:
|
||||||
|
pixel[i] = 0;
|
||||||
|
break;
|
||||||
|
case GL_ONE:
|
||||||
|
pixel[i] = 255;
|
||||||
|
break;
|
||||||
|
case GL_RED:
|
||||||
|
pixel[i] = pixel_ptr[0];
|
||||||
|
break;
|
||||||
|
case GL_GREEN:
|
||||||
|
pixel[i] = pixel_ptr[1];
|
||||||
|
break;
|
||||||
|
case GL_BLUE:
|
||||||
|
pixel[i] = pixel_ptr[2];
|
||||||
|
break;
|
||||||
|
case GL_ALPHA:
|
||||||
|
pixel[i] = pixel_ptr[3];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pixel;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DrawSrcAtlas {
|
||||||
|
glm::vec<2, int> m_size;
|
||||||
|
const Atlas* m_atlas;
|
||||||
|
|
||||||
|
DrawSrcAtlas(const Atlas& atlas) {
|
||||||
|
m_size = atlas.m_size;
|
||||||
|
m_atlas = &atlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
Atlas::Pixel get(glm::vec<2, int> pos) const {
|
||||||
|
return m_atlas->get({pos, 0});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void draw_to(const T& src, Atlas& dst, glm::vec<3, int> p) {
|
||||||
|
|
||||||
|
for(int i = 0; i < src.m_size.y; i++) {
|
||||||
|
for(int j = 0; j < src.m_size.x; j++) {
|
||||||
|
dst.get({p.x + j, p.y + i, p.z}) = src.get({j, i});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dst.m_padding) {
|
||||||
|
for(int i = 0; i < src.m_size.y; i++) {
|
||||||
|
dst.get({p.x - 1, p.y + i, p.z}) = src.get({0, i});
|
||||||
|
dst.get({p.x + src.m_size.x, p.y + i, p.z}) = src.get({src.m_size.x - 1, i});
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < src.m_size.x; i++) {
|
||||||
|
dst.get({p.x + i, p.y - 1, p.z}) = src.get({i, 0});
|
||||||
|
dst.get({p.x + i, p.y + src.m_size.y, p.z}) = src.get({i, src.m_size.y - 1});
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.get({p.x - 1, p.y - 1, p.z}) = src.get({0, 0});
|
||||||
|
dst.get({p.x + src.m_size.x, p.y - 1, p.z}) = src.get({src.m_size.x - 1, 0});
|
||||||
|
dst.get({p.x - 1, p.y + src.m_size.y, p.z}) = src.get({0, src.m_size.y - 1});
|
||||||
|
dst.get({p.x + src.m_size.x, p.y + src.m_size.y, p.z}) = src.get({src.m_size.x - 1, src.m_size.y - 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Atlas::draw(const Atlas& src, glm::vec<3, int> p) {
|
||||||
|
draw_to(DrawSrcAtlas(src), *this, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Atlas::draw(const Image& src, glm::vec<3, int> p) {
|
||||||
|
draw_to(DrawSrcImage(src), *this, p);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "image.hpp"
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <glm/matrix.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Graphics::Texture {
|
||||||
|
struct Atlas {
|
||||||
|
static constexpr int N = 4;
|
||||||
|
struct Pixel {
|
||||||
|
uint8_t m_data[N] = {0};
|
||||||
|
|
||||||
|
Pixel() = default;
|
||||||
|
Pixel(const Pixel& p);
|
||||||
|
Pixel(const uint8_t* p);
|
||||||
|
|
||||||
|
bool operator == (const Pixel& p) const;
|
||||||
|
bool operator != (const Pixel& p) const;
|
||||||
|
Pixel& operator = (const Pixel& p);
|
||||||
|
Pixel& operator = (const uint8_t* p);
|
||||||
|
uint8_t& operator [] (int i);
|
||||||
|
const uint8_t& operator [] (int i) const;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr operator glm::vec<N, T>() {
|
||||||
|
glm::vec<N, T> vec;
|
||||||
|
for(int i = 0; i < N; i++) {
|
||||||
|
vec[i] = (T)m_data[i] / 255.0;
|
||||||
|
}
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr Pixel& operator = (const glm::vec<N, T>& vec) {
|
||||||
|
for(int i = 0; i < N; i++) {
|
||||||
|
m_data[i] = (uint8_t)(std::round(vec[i] * 255));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr Pixel(const glm::vec<N, T>& vec) {
|
||||||
|
*this = vec;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
glm::vec<3, int> m_size;
|
||||||
|
std::vector<Pixel> m_data;
|
||||||
|
bool m_padding = false;
|
||||||
|
|
||||||
|
Atlas() = default;
|
||||||
|
Atlas(glm::vec<2, int> size);
|
||||||
|
Atlas(glm::vec<3, int> size);
|
||||||
|
Pixel& get(glm::vec<3, int> pos);
|
||||||
|
const Pixel& get(glm::vec<3, int> pos) const;
|
||||||
|
void draw(const Atlas& src, glm::vec<3, int> pos);
|
||||||
|
void draw(const Image& src, glm::vec<3, int> pos);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
file(GLOB SOURCES ${SOURCES} src/graphics/texture/*.cpp)
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
|
||||||
|
#include "../texture.hpp"
|
||||||
|
#include "../shader.hpp"
|
||||||
|
#include "atlas.hpp"
|
||||||
|
#include "image.hpp"
|
||||||
|
#include "uv.hpp"
|
||||||
|
#include "../gl/array_buffer.hpp"
|
||||||
|
#include "../gl/texture.hpp"
|
||||||
|
#include <iterator>
|
||||||
|
#include <stb/stb_rect_pack.h>
|
||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
void Graphics::Texture::generate_atlas() {
|
||||||
|
int total_area = 0;
|
||||||
|
int min_size = 1;
|
||||||
|
int padding = 0;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
for(const Image* i : IMAGES) {
|
||||||
|
int w = i->m_size.x + padding;
|
||||||
|
int h = i->m_size.y + padding;
|
||||||
|
if(w > min_size) min_size = w;
|
||||||
|
if(h > min_size) min_size = h;
|
||||||
|
total_area += w * h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find an approximate size for the atlas that can hold all the textures
|
||||||
|
int size = std::pow(2, std::ceil(std::log2(std::max((double)min_size, std::pow(total_area, 1.0/3.0)))));
|
||||||
|
|
||||||
|
std::vector<stbrp_rect> rects;
|
||||||
|
std::vector<UV> uvs(std::size(IMAGES));
|
||||||
|
rects.reserve(std::size(IMAGES));
|
||||||
|
|
||||||
|
for(int i = 0; i < std::size(IMAGES); i++) {
|
||||||
|
const Image* a = IMAGES[i];
|
||||||
|
stbrp_rect rect;
|
||||||
|
rect.id = i;
|
||||||
|
rect.w = a->m_size.x + padding;
|
||||||
|
rect.h = a->m_size.y + padding;
|
||||||
|
rects.push_back(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
stbrp_context context;
|
||||||
|
std::vector<stbrp_node> nodes(size);
|
||||||
|
Atlas atlas({size, size});
|
||||||
|
int zpos;
|
||||||
|
|
||||||
|
for(zpos = 0; rects.size() > 0; zpos++) {
|
||||||
|
stbrp_init_target(&context, size, size, nodes.data(), nodes.size());
|
||||||
|
stbrp_pack_rects(&context, rects.data(), rects.size());
|
||||||
|
|
||||||
|
for(auto it = rects.begin(); it != rects.end();) {
|
||||||
|
if(!it->was_packed) {
|
||||||
|
it++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image* src = IMAGES[it->id];
|
||||||
|
atlas.draw(*src, {it->x + offset, it->y + offset, zpos});
|
||||||
|
src->m_id = it->id;
|
||||||
|
src->clear_host();
|
||||||
|
|
||||||
|
uvs[it->id] = {
|
||||||
|
.uv0={(it->x + offset + 0.5f) / size, (it->y + offset + 0.5f) / size},
|
||||||
|
.uv1={(it->x + offset + src->m_size.x - 0.5f) / size, (it->y + offset + src->m_size.y - 0.5f) / size},
|
||||||
|
.zpos=zpos,
|
||||||
|
.edges=src->m_edges,
|
||||||
|
};
|
||||||
|
|
||||||
|
it = rects.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GL::ArrayBuffer ssbo_id;
|
||||||
|
static GL::Texture tex_id;
|
||||||
|
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id);
|
||||||
|
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(UV) * uvs.size(), uvs.data(), GL_STATIC_DRAW);
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, Graphics::Shader::SSBO_ATLAS_BUFFER, ssbo_id);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + Graphics::Shader::TEX_ATLAS);
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, tex_id);
|
||||||
|
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, atlas.m_size.x, atlas.m_size.y, atlas.m_size.z, 0, GL_RGBA, GL_UNSIGNED_BYTE, atlas.m_data.data());
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
|
||||||
|
#include "image.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stb/stb_image.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using Graphics::Texture::Image;
|
||||||
|
|
||||||
|
Image::Image(const char* filename, Edge edge_behaviour) {
|
||||||
|
std::string path = std::string("../assets/image/") + filename;
|
||||||
|
m_data = stbi_load(path.c_str(), &m_size.x, &m_size.y, &m_channels, 0);
|
||||||
|
m_edges = edge_behaviour;
|
||||||
|
std::cout << "Loaded " << filename << std::endl;
|
||||||
|
|
||||||
|
switch(m_channels) {
|
||||||
|
case 1:
|
||||||
|
m_mapping = {GL_RED, GL_RED, GL_RED, GL_ONE};
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
m_mapping = {GL_RED, GL_GREEN, GL_ZERO, GL_ONE};
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
m_mapping = {GL_RED, GL_GREEN, GL_BLUE, GL_ONE};
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
m_mapping = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::Image(Image&& o) : Image(o) {
|
||||||
|
o.m_data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::~Image() {
|
||||||
|
if(m_data) {
|
||||||
|
free(m_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* Image::get(glm::vec<2, int> pos) const {
|
||||||
|
return &m_data[(pos.y * m_size.x + pos.x) * m_channels];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::clear_host() {
|
||||||
|
assert(m_data);
|
||||||
|
free(m_data);
|
||||||
|
m_data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::operator unsigned int() {
|
||||||
|
assert(m_id != -1);
|
||||||
|
return m_id;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/matrix.hpp>
|
||||||
|
|
||||||
|
namespace Graphics::Texture {
|
||||||
|
struct Image {
|
||||||
|
enum Edge : int {
|
||||||
|
CLAMP = 0,
|
||||||
|
REPEATING = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned char* m_data;
|
||||||
|
glm::vec<2, int> m_size;
|
||||||
|
glm::vec<4, int> m_mapping;
|
||||||
|
int m_channels;
|
||||||
|
Edge m_edges;
|
||||||
|
int m_id = -1;
|
||||||
|
|
||||||
|
Image(const char* path, Edge edge_behaviour);
|
||||||
|
Image(Image&&);
|
||||||
|
~Image();
|
||||||
|
|
||||||
|
unsigned char* get(glm::vec<2, int> pos) const;
|
||||||
|
void clear_host();
|
||||||
|
|
||||||
|
operator unsigned int();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Image(const Image&) = default;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "image.hpp"
|
||||||
|
#include <glm/ext/vector_float2.hpp>
|
||||||
|
|
||||||
|
namespace Graphics::Texture {
|
||||||
|
struct UV {
|
||||||
|
glm::vec2 uv0;
|
||||||
|
glm::vec2 uv1;
|
||||||
|
int zpos;
|
||||||
|
Image::Edge edges;
|
||||||
|
int padding[2];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -8,10 +8,12 @@ using Graphics::Vertex;
|
||||||
void Vertex::set_vertex_attribs() {
|
void Vertex::set_vertex_attribs() {
|
||||||
Vertex v;
|
Vertex v;
|
||||||
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(v), (void*)Util::pointer_diff(&v, &v.m_pos));
|
glVertexAttribPointer(0, 4, GL_FLOAT, false, sizeof(v), (void*)Util::pointer_diff(&v, &v.m_pos));
|
||||||
glVertexAttribPointer(1, 4, GL_FLOAT, false, sizeof(v), (void*)Util::pointer_diff(&v, &v.m_colour));
|
glVertexAttribPointer(1, 4, GL_FLOAT, false, sizeof(v), (void*)Util::pointer_diff(&v, &v.m_colour));
|
||||||
|
glVertexAttribPointer(2, 2, GL_FLOAT, false, sizeof(v), (void*)Util::pointer_diff(&v, &v.m_uv));
|
||||||
|
glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, sizeof(v), (void*)Util::pointer_diff(&v, &v.m_texid));
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++) {
|
for(int i = 0; i < 4; i++) {
|
||||||
glEnableVertexAttribArray(i);
|
glEnableVertexAttribArray(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
namespace Graphics {
|
namespace Graphics {
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
glm::vec4 m_pos;
|
glm::vec4 m_pos;
|
||||||
glm::vec4 m_colour;
|
glm::vec4 m_colour = {1, 1, 1, 1};
|
||||||
|
glm::vec2 m_uv;
|
||||||
|
unsigned int m_texid = 0;
|
||||||
|
|
||||||
static void set_vertex_attribs();
|
static void set_vertex_attribs();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
|
|
||||||
#include "graphics/context.hpp"
|
#include "graphics/context.hpp"
|
||||||
#include "graphics/pipeline.hpp"
|
#include "graphics/pipeline.hpp"
|
||||||
|
#include "graphics/texture.hpp"
|
||||||
#include "world/state.hpp"
|
#include "world/state.hpp"
|
||||||
#include <glm/ext/matrix_clip_space.hpp>
|
#include <glm/ext/matrix_clip_space.hpp>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
Graphics::Pipeline pipeline;
|
Graphics::Pipeline pipeline;
|
||||||
|
Graphics::Texture::generate_atlas();
|
||||||
World::State state;
|
World::State state;
|
||||||
|
|
||||||
while(!pipeline.should_close()) {
|
while(!pipeline.should_close()) {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 013ac3beddff3dbffafd5177e7972067cd2b5083
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Util::Math {
|
||||||
|
constexpr auto mod(auto a, auto b) {
|
||||||
|
return (a % b + b) % b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
|
||||||
#include "pointer_diff.hpp"
|
#include "pointer_diff.hpp"
|
||||||
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
uint64_t Util::pointer_diff(void* a, void* b) {
|
uint64_t Util::pointer_diff(void* a, void* b) {
|
||||||
|
assert(a);
|
||||||
|
assert(b);
|
||||||
return std::abs((int64_t)a - (int64_t)b);
|
return std::abs((int64_t)a - (int64_t)b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
|
||||||
#include "builder.hpp"
|
#include "builder.hpp"
|
||||||
#include "../graphics/window.hpp"
|
#include "../graphics/window.hpp"
|
||||||
|
#include "../graphics/texture.hpp"
|
||||||
#include "chunk.hpp"
|
#include "chunk.hpp"
|
||||||
#include "map.hpp"
|
#include "map.hpp"
|
||||||
#include "tile/empty.hpp"
|
#include "tile/empty.hpp"
|
||||||
|
#include "tile/tile_base.hpp"
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <glm/common.hpp>
|
#include <glm/common.hpp>
|
||||||
|
@ -15,10 +17,14 @@ using World::Builder;
|
||||||
|
|
||||||
Builder::Builder() {
|
Builder::Builder() {
|
||||||
Graphics::Mesh mesh;
|
Graphics::Mesh mesh;
|
||||||
mesh.add_primitive(Chunk::PRIMITIVE_0);
|
auto prim = Chunk::PRIMITIVE_B;
|
||||||
|
prim.m_texid = Graphics::Texture::YELLOW_BRICK_WALL;
|
||||||
|
mesh.add_primitive(prim);
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++) {
|
for(int i = 0; i < 4; i++) {
|
||||||
mesh.add_primitive(Chunk::PRIMITIVE_S[i]);
|
prim = Chunk::PRIMITIVE_S[i];
|
||||||
|
prim.m_texid = Graphics::Texture::YELLOW_BRICK_WALL;
|
||||||
|
mesh.add_primitive(prim);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_model.bind();
|
m_model.bind();
|
||||||
|
@ -38,32 +44,35 @@ void Builder::update(Map& map, const Graphics::Context& ctx) {
|
||||||
glm::vec<3, double> near = glm::unProject<float>(glm::vec3(mpos, -1), ctx.m_view, ctx.m_projection, glm::vec4(0, 0, Graphics::Window::size));
|
glm::vec<3, double> near = glm::unProject<float>(glm::vec3(mpos, -1), ctx.m_view, ctx.m_projection, glm::vec4(0, 0, Graphics::Window::size));
|
||||||
glm::vec<3, double> far = glm::unProject<float>(glm::vec3(mpos, 1), ctx.m_view, ctx.m_projection, glm::vec4(0, 0, Graphics::Window::size));
|
glm::vec<3, double> far = glm::unProject<float>(glm::vec3(mpos, 1), ctx.m_view, ctx.m_projection, glm::vec4(0, 0, Graphics::Window::size));
|
||||||
glm::vec<3, double> direction = far - near;
|
glm::vec<3, double> direction = far - near;
|
||||||
|
const glm::vec<2, double> CHECK_TILES[] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
if(direction.z >= 0) {
|
if(direction.z >= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_intersect = glm::round(glm::vec<2, double>(near - direction / direction.z * near.z) + ctx.m_transform);
|
m_intersect = glm::round(glm::vec<2, double>(near - direction / direction.z * near.z) + ctx.m_transform);
|
||||||
|
m_has_intersect = true;
|
||||||
|
|
||||||
if(map.get_tile(m_intersect)) {
|
if(map.get_tile(m_intersect)) {
|
||||||
|
m_mode = Mode::CLEAR;
|
||||||
|
} else {
|
||||||
|
m_mode = Mode::SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!m_has_intersect || !Graphics::Window::clicked) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const glm::vec<2, double> CHECK_TILES[] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
|
std::unique_ptr<Tile::TileBase> tile;
|
||||||
bool found = false;
|
switch(m_mode) {
|
||||||
|
case Mode::SET:
|
||||||
for(const glm::vec<2, double>& off : CHECK_TILES) {
|
tile = std::make_unique<Tile::Empty>();
|
||||||
if(map.get_tile(m_intersect + off)) {
|
break;
|
||||||
m_has_intersect = true;
|
default:
|
||||||
break;
|
tile = nullptr;
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!m_has_intersect) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(Graphics::Window::clicked) {
|
|
||||||
map.set_tile(m_intersect, std::make_unique<Tile::Empty>());
|
|
||||||
}
|
}
|
||||||
|
map.set_tile(m_intersect, std::move(tile));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::render(const Graphics::Context& ctx) const {
|
void Builder::render(const Graphics::Context& ctx) const {
|
||||||
|
@ -73,12 +82,16 @@ void Builder::render(const Graphics::Context& ctx) const {
|
||||||
|
|
||||||
glm::vec<2, double> pos = glm::round(m_intersect);
|
glm::vec<2, double> pos = glm::round(m_intersect);
|
||||||
ctx.set_model_matrix(glm::translate(glm::mat4(1), {pos - ctx.m_transform, 0}));
|
ctx.set_model_matrix(glm::translate(glm::mat4(1), {pos - ctx.m_transform, 0}));
|
||||||
ctx.set_colour_matrix({
|
|
||||||
0.5, 0.5, 0, 0,
|
switch(m_mode) {
|
||||||
0, 1, 0, 0,
|
case Mode::CLEAR:
|
||||||
0, 0.5, 0.5, 0,
|
ctx.set_colour_matrix(glm::mat4(1, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1));
|
||||||
0, 0, 0, 1,
|
break;
|
||||||
});
|
case Mode::SET:
|
||||||
|
ctx.set_colour_matrix(glm::mat4(0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
m_model.bind();
|
m_model.bind();
|
||||||
m_model.render(GL_TRIANGLES);
|
m_model.render(GL_TRIANGLES);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,15 @@
|
||||||
|
|
||||||
namespace World {
|
namespace World {
|
||||||
struct Builder {
|
struct Builder {
|
||||||
|
enum Mode {
|
||||||
|
SET,
|
||||||
|
CLEAR,
|
||||||
|
};
|
||||||
|
|
||||||
Graphics::GL::Model m_model;
|
Graphics::GL::Model m_model;
|
||||||
glm::vec<2, double> m_intersect;
|
glm::vec<2, double> m_intersect;
|
||||||
bool m_has_intersect = false;
|
bool m_has_intersect = false;
|
||||||
|
Mode m_mode;
|
||||||
|
|
||||||
Builder();
|
Builder();
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include "chunk.hpp"
|
#include "chunk.hpp"
|
||||||
#include "tile/tile_base.hpp"
|
#include "tile/tile_base.hpp"
|
||||||
#include <glm/detail/qualifier.hpp>
|
#include "../graphics/texture.hpp"
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
#include <glm/ext/quaternion_transform.hpp>
|
#include <glm/ext/quaternion_transform.hpp>
|
||||||
#include <glm/ext/scalar_constants.hpp>
|
#include <glm/ext/scalar_constants.hpp>
|
||||||
|
#include <glm/ext/vector_float3.hpp>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
using World::Chunk;
|
using World::Chunk;
|
||||||
using World::Tile::TileBase;
|
using World::Tile::TileBase;
|
||||||
|
@ -36,7 +36,15 @@ const TileBase* Chunk::get(glm::vec<2, int> p) const {
|
||||||
TileBase* Chunk::set(glm::vec<2, int> p, std::unique_ptr<TileBase> v) {
|
TileBase* Chunk::set(glm::vec<2, int> p, std::unique_ptr<TileBase> v) {
|
||||||
TileBase* r = v.get();
|
TileBase* r = v.get();
|
||||||
p = get_pos_mod(p);
|
p = get_pos_mod(p);
|
||||||
m_tiles[p.x * N + p.y] = std::move(v);
|
m_tiles[p.x * N + p.y].swap(v);
|
||||||
|
|
||||||
|
if(r && !v) {
|
||||||
|
m_used_tiles += 1;
|
||||||
|
}
|
||||||
|
else if(!r && v) {
|
||||||
|
m_used_tiles -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -71,7 +79,10 @@ void Chunk::update(Map& map) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh.add_primitive(PRIMITIVE_B.with_translation({t_off, 0}));
|
auto prim = PRIMITIVE_B;
|
||||||
|
prim.m_offset = {t_off, 0, 0};
|
||||||
|
prim.m_texid = Graphics::Texture::YELLOW_BRICK_WALL;
|
||||||
|
mesh.add_primitive(prim);
|
||||||
|
|
||||||
for(int i = 0; i < std::size(neighbours); i++) {
|
for(int i = 0; i < std::size(neighbours); i++) {
|
||||||
glm::vec<2, int> n_off = neighbours[i] + t_off;
|
glm::vec<2, int> n_off = neighbours[i] + t_off;
|
||||||
|
@ -86,7 +97,10 @@ void Chunk::update(Map& map) {
|
||||||
chunk_check = chunks[3];
|
chunk_check = chunks[3];
|
||||||
}
|
}
|
||||||
if(!chunk_check || !chunk_check->get(n_off)) {
|
if(!chunk_check || !chunk_check->get(n_off)) {
|
||||||
mesh.add_primitive(PRIMITIVE_S[i].with_translation({t_off, 0}));
|
prim = PRIMITIVE_S[i];
|
||||||
|
prim.m_offset = {t_off, 0, 0};
|
||||||
|
prim.m_texid = Graphics::Texture::YELLOW_BRICK_WALL;
|
||||||
|
mesh.add_primitive(prim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,26 +17,26 @@ namespace World {
|
||||||
struct Chunk {
|
struct Chunk {
|
||||||
static constexpr int N = 16;
|
static constexpr int N = 16;
|
||||||
|
|
||||||
static constexpr Graphics::Primitive<4, 6> PRIMITIVE_B = {
|
static const inline Graphics::Primitive<4, 6> PRIMITIVE_B = {
|
||||||
.m_vertices = {
|
.m_vertices={
|
||||||
{.m_pos = {-0.5, -0.5, 0, 1}, .m_colour = {1, 0, 0, 1}},
|
{.m_pos={-0.5, -0.5, 0, 1}, .m_uv={0, 0}},
|
||||||
{.m_pos = {-0.5, +0.5, 0, 1}, .m_colour = {1, 1, 0, 1}},
|
{.m_pos={-0.5, +0.5, 0, 1}, .m_uv={0, 2}},
|
||||||
{.m_pos = {+0.5, -0.5, 0, 1}, .m_colour = {0, 1, 0, 1}},
|
{.m_pos={+0.5, -0.5, 0, 1}, .m_uv={2, 0}},
|
||||||
{.m_pos = {+0.5, +0.5, 0, 1}, .m_colour = {0, 0, 1, 1}},
|
{.m_pos={+0.5, +0.5, 0, 1}, .m_uv={2, 2}},
|
||||||
},
|
},
|
||||||
.m_indices = {
|
.m_indices={
|
||||||
0, 2, 3,
|
0, 2, 3,
|
||||||
0, 3, 1,
|
0, 3, 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
static constexpr Graphics::Primitive<4, 6> PRIMITIVE_0 = {
|
static const inline Graphics::Primitive<4, 6> PRIMITIVE_0 = {
|
||||||
.m_vertices = {
|
.m_vertices={
|
||||||
{.m_pos = {-0.5, -0.5, 0.5, 1}, .m_colour = {1, 0, 0, 1}},
|
{.m_pos={-0.5, -0.5, 0.75, 1}, .m_uv={0, 0}},
|
||||||
{.m_pos = {-0.5, -0.5, 0, 1}, .m_colour = {1, 1, 0, 1}},
|
{.m_pos={-0.5, -0.5, 0, 1}, .m_uv={0, 2}},
|
||||||
{.m_pos = {+0.5, -0.5, 0.5, 1}, .m_colour = {0, 1, 0, 1}},
|
{.m_pos={+0.5, -0.5, 0.75, 1}, .m_uv={2, 0}},
|
||||||
{.m_pos = {+0.5, -0.5, 0, 1}, .m_colour = {0, 0, 1, 1}},
|
{.m_pos={+0.5, -0.5, 0, 1}, .m_uv={2, 2}},
|
||||||
},
|
},
|
||||||
.m_indices = {
|
.m_indices={
|
||||||
0, 2, 3,
|
0, 2, 3,
|
||||||
0, 3, 1,
|
0, 3, 1,
|
||||||
},
|
},
|
||||||
|
@ -52,6 +52,7 @@ namespace World {
|
||||||
std::unique_ptr<Tile::TileBase> m_tiles[N*N];
|
std::unique_ptr<Tile::TileBase> m_tiles[N*N];
|
||||||
Graphics::GL::Model m_model;
|
Graphics::GL::Model m_model;
|
||||||
glm::vec<2, int> m_pos;
|
glm::vec<2, int> m_pos;
|
||||||
|
int m_used_tiles = 0;
|
||||||
bool m_dirty = false;
|
bool m_dirty = false;
|
||||||
|
|
||||||
Chunk(glm::vec<2, int> pos);
|
Chunk(glm::vec<2, int> pos);
|
||||||
|
|
|
@ -49,6 +49,13 @@ const Chunk* Map::get_chunk(glm::vec<2, int> pos) const {
|
||||||
return &it->second;
|
return &it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Map::mark_chunk_dirty(glm::vec<2, int> pos) {
|
||||||
|
Chunk* c = get_chunk(pos);
|
||||||
|
if(c) {
|
||||||
|
c->m_dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TileBase* Map::get_tile(glm::vec<2, int> pos) {
|
TileBase* Map::get_tile(glm::vec<2, int> pos) {
|
||||||
Chunk* c = get_chunk(pos);
|
Chunk* c = get_chunk(pos);
|
||||||
return c ? c->get(pos) : nullptr;
|
return c ? c->get(pos) : nullptr;
|
||||||
|
@ -60,8 +67,28 @@ const TileBase* Map::get_tile(glm::vec<2, int> pos) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
TileBase* Map::set_tile(glm::vec<2, int> pos, std::unique_ptr<TileBase> tile) {
|
TileBase* Map::set_tile(glm::vec<2, int> pos, std::unique_ptr<TileBase> tile) {
|
||||||
tile->m_pos = pos;
|
uint64_t cid = get_chunk_id(pos);
|
||||||
return get_or_generate_chunk(pos)->set(pos, std::move(tile));
|
auto it = m_chunks.find(cid);
|
||||||
|
if(tile) {
|
||||||
|
tile->m_pos = pos;
|
||||||
|
if(it == m_chunks.end()) {
|
||||||
|
it = m_chunks.try_emplace(cid, pos - get_pos_mod(pos)).first;
|
||||||
|
}
|
||||||
|
} else if(it == m_chunks.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
Chunk* c = &it->second;
|
||||||
|
TileBase* tile_p = c->set(pos, std::move(tile));
|
||||||
|
mark_chunk_dirty(pos + glm::vec<2, int>(1, 0));
|
||||||
|
mark_chunk_dirty(pos + glm::vec<2, int>(0, 1));
|
||||||
|
mark_chunk_dirty(pos + glm::vec<2, int>(-1, 0));
|
||||||
|
mark_chunk_dirty(pos + glm::vec<2, int>(0, -1));
|
||||||
|
|
||||||
|
if(!tile_p && c->m_used_tiles == 0) {
|
||||||
|
m_chunks.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tile_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::update() {
|
void Map::update() {
|
||||||
|
|
|
@ -28,6 +28,10 @@ namespace World {
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
void render(const Graphics::Context& ctx) const;
|
void render(const Graphics::Context& ctx) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void mark_chunk_dirty(glm::vec<2, int> pos);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
|
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
#include "../graphics/window.hpp"
|
#include "../graphics/window.hpp"
|
||||||
|
#include "../util/math/mod.hpp"
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
#include <glm/detail/qualifier.hpp>
|
#include <glm/detail/qualifier.hpp>
|
||||||
#include <glm/detail/type_quat.hpp>
|
#include <glm/detail/type_quat.hpp>
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
|
@ -54,7 +57,8 @@ void Player::update() {
|
||||||
m_cursor_last = cursor;
|
m_cursor_last = cursor;
|
||||||
|
|
||||||
if(Graphics::Window::mouse_locked) {
|
if(Graphics::Window::mouse_locked) {
|
||||||
m_pitch += cursor_diff.x * 0.0025;
|
m_pitch = std::fmod(m_pitch + cursor_diff.x * 0.0025, glm::pi<double>() * 2);
|
||||||
|
m_yaw = std::clamp(m_yaw - cursor_diff.y * 0.0025, 0.0, glm::pi<double>() * 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_vel += m_accel;
|
m_vel += m_accel;
|
||||||
|
|
Loading…
Reference in New Issue