diff --git a/assets/font/DroidSansMono.ttf b/assets/font/DroidSansMono.ttf new file mode 100644 index 0000000..a007071 Binary files /dev/null and b/assets/font/DroidSansMono.ttf differ diff --git a/assets/scene.blend b/assets/scene.blend index b618e75..4f2dddb 100644 --- a/assets/scene.blend +++ b/assets/scene.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0cb597b1f61b1eb72ef1177aa55082c7ffa5bfaf8af87cbc6e1f04510e840e8 -size 16472105 +oid sha256:e1c416005df3ca027aa5bdef6fb640c03da7ae0ff103ca95699a4730b9fa04e4 +size 16478545 diff --git a/assets/scene.glb b/assets/scene.glb index a59a67a..c159f68 100644 --- a/assets/scene.glb +++ b/assets/scene.glb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc51cad04148d0f57916c3d7041776998fc93e50dca0ba4fc5fb47e6b4eadc46 -size 2044764 +oid sha256:92aa9a64ebb38b96942dd913809ffe9a1ed2364bb8042df62988740a2c4720b9 +size 2044756 diff --git a/assets/shader/blur.fsh b/assets/shader/blur.fsh deleted file mode 100644 index b44da61..0000000 --- a/assets/shader/blur.fsh +++ /dev/null @@ -1,26 +0,0 @@ - -#version 460 core - -uniform sampler2D tex; -uniform vec2 direction; -uniform int samples; - -in vec2 FragPos; -out vec4 FragColour; - -void main() -{ - int radius = (samples - 1) / 2; - ivec2 size = textureSize(tex, 0); - vec2 step = direction / size; - vec4 sum = vec4(0.f); - - for(int i = -radius; i <= radius; i++) - { - vec2 offset = vec2(i) * step; - sum += texture(tex, FragPos + offset); - } - - FragColour = sum / float(samples); -} - diff --git a/assets/shader/post_base.vsh b/assets/shader/post_base.vsh deleted file mode 100644 index 6891ada..0000000 --- a/assets/shader/post_base.vsh +++ /dev/null @@ -1,21 +0,0 @@ - -#version 460 core - -const vec2 QuadVertices[6] = vec2[6]( - vec2(-1.0, 1.0), - vec2(-1.0, -1.0), - vec2( 1.0, -1.0), - vec2(-1.0, 1.0), - vec2( 1.0, -1.0), - vec2( 1.0, 1.0) -); - -out vec2 FragPos; - -void main() -{ - vec2 vertex = QuadVertices[gl_VertexID]; - FragPos = vertex * 0.5f + 0.5f; - gl_Position = vec4(vertex, 0.f, 1.f); -} - diff --git a/src/graphics/data/arrays.cpp b/src/graphics/data/arrays.cpp index 3b7dba8..689dce3 100644 --- a/src/graphics/data/arrays.cpp +++ b/src/graphics/data/arrays.cpp @@ -38,18 +38,19 @@ void Arrays::vertex_attrib_pointers() glVertexAttribPointer(5, 3, GL_FLOAT, true, sizeof(v), ptr_diff(&v.tbn[2], &v)); glEnableVertexAttribArray(5); - - glVertexAttribIPointer(6, 1, GL_INT, sizeof(v), ptr_diff(&v.transform_id, &v)); + + glVertexAttribPointer(6, 3, GL_FLOAT, false, sizeof(v), ptr_diff(&v.material, &v)); glEnableVertexAttribArray(6); - glVertexAttribIPointer(7, 1, GL_UNSIGNED_INT, sizeof(v), ptr_diff(&v.tex_diffuse, &v)); + glVertexAttribIPointer(7, 1, GL_INT, sizeof(v), ptr_diff(&v.transform_id, &v)); glEnableVertexAttribArray(7); - glVertexAttribIPointer(8, 1, GL_UNSIGNED_INT, sizeof(v), ptr_diff(&v.tex_normal, &v)); + glVertexAttribIPointer(8, 1, GL_UNSIGNED_INT, sizeof(v), ptr_diff(&v.tex_diffuse, &v)); glEnableVertexAttribArray(8); - glVertexAttribPointer(9, 3, GL_FLOAT, false, sizeof(v), ptr_diff(&v.material, &v)); + glVertexAttribIPointer(9, 1, GL_UNSIGNED_INT, sizeof(v), ptr_diff(&v.tex_normal, &v)); glEnableVertexAttribArray(9); + } std::ostream& Arrays::operator<<(std::ostream& os, const Vertex& v) diff --git a/src/graphics/data/atlas.hpp b/src/graphics/data/atlas.hpp new file mode 100644 index 0000000..1c44039 --- /dev/null +++ b/src/graphics/data/atlas.hpp @@ -0,0 +1,138 @@ + +#pragma once + +#include + +namespace Sim::Graphics::Data +{ + +template +struct Atlas +{ + struct Pixel + { + uint8_t data[N] = {0}; + + constexpr Pixel() = default; + + constexpr Pixel(const Pixel& p) + { + for(int i = 0; i < N; i++) + { + data[i] = p.data[i]; + } + } + + constexpr Pixel(const uint8_t* p) + { + for(int i = 0; i < N; i++) + { + data[i] = p[i]; + } + } + + constexpr bool operator == (const Pixel& p) const + { + for(int i = 0; i < N; i++) + { + if(data[i] != p.data[i]) + { + return false; + } + } + + return true; + } + + constexpr bool operator != (const Pixel& p) const + { + return !(*this == p); + } + + constexpr Pixel& operator = (const Pixel& p) + { + for(int i = 0; i < N; i++) + { + data[i] = p.data[i]; + } + + return *this; + } + + constexpr Pixel& operator = (const uint8_t* p) + { + for(int i = 0; i < N; i++) + { + data[i] = p[i]; + } + + return *this; + } + + constexpr uint8_t& operator [] (int i) + { + return data[i]; + } + + constexpr const uint8_t& operator [] (int i) const + { + return data[i]; + } + }; + + const int width; + const int height; + + std::vector data; + + Atlas(int width, int height) + : width(width) + , height(height) + , data(width * height) + { + } + + Pixel& operator()(int x, int y) + { + return data[y * width + x]; + } + + const Pixel& operator()(int x, int y) const + { + return data[y * width + x]; + } + + void draw(const Atlas& src, int x, int y, bool padding = false) + { + for(int i = 0; i < src.height; i++) + { + for(int j = 0; j < src.width; j++) + { + (*this)(x + j, y + i) = src(j, i); + } + } + + if(padding) + { + for(int i = 0; i < src.height; i++) + { + (*this)(x - 1, y + i) = src(0, i); + (*this)(x + src.width, y + i) = src(src.width - 1, i); + } + + for(int i = 0; i < src.width; i++) + { + (*this)(x + i, y - 1) = src(i, 0); + (*this)(x + i, y + src.height) = src(i, src.height - 1); + } + + (*this)(x - 1, y - 1) = src(0, 0); + (*this)(x + src.width, y - 1) = src(src.width - 1, 0); + (*this)(x - 1, y + src.height) = src(0, src.height - 1); + (*this)(x + src.width, y + src.height) = src(src.width - 1, src.height - 1); + } + } +}; + +}; + diff --git a/src/graphics/data/camera.hpp b/src/graphics/data/camera.hpp index c1e4fce..17ba6d0 100644 --- a/src/graphics/data/camera.hpp +++ b/src/graphics/data/camera.hpp @@ -2,16 +2,18 @@ #pragma once #include +#include namespace Sim::Graphics::Data { struct Camera { - glm::vec3 pos; - glm::vec3 look; - glm::vec3 up; - float fov; + const std::string name; + const glm::vec3 pos; + const glm::vec3 look; + const glm::vec3 up; + const float fov; float pitch = 0; float yaw = 0; diff --git a/src/graphics/data/font.cpp b/src/graphics/data/font.cpp index cb78c28..0adfdea 100644 --- a/src/graphics/data/font.cpp +++ b/src/graphics/data/font.cpp @@ -8,25 +8,27 @@ #include #include #include +#include +#include "../shader.hpp" #include "mesh.hpp" #include "arrays.hpp" #include "material.hpp" +#include "texture.hpp" #include "font.hpp" using namespace Sim::Graphics::Data; -struct Character +Font Fonts::BASE; +Font Fonts::MONO; + +void Fonts::init() { - uint32_t handle; - float advance; - glm::vec2 size; - glm::vec2 bearing; -}; + BASE.init("DroidSans", 64); + MONO.init("DroidSansMono", 64); +} -static Character chars[128]; - -void Font::init() +void Font::init(const std::string& name, int size) { FT_Library ft; FT_Face face; @@ -37,22 +39,15 @@ void Font::init() return; } - if(FT_New_Face(ft, "../assets/font/DroidSans.ttf", 0, &face)) + if(FT_New_Face(ft, std::format("../assets/font/{}.ttf", name).c_str(), 0, &face)) { std::cout << "Error: failed to load freetype font\n"; return; } - int size = 256; - float m = 1.0f / size; - + texel_size = 1.0f / size; FT_Set_Pixel_Sizes(face, 0, size); - GLuint texids[128]; - std::vector> pixels; - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - for(int i = 0; i < 128; i++) { if(FT_Load_Char(face, (char)i, FT_LOAD_RENDER)) @@ -65,61 +60,59 @@ void Font::init() int offx = face->glyph->bitmap_left; int offy = face->glyph->bitmap_top; - Character& c = chars[i]; - c.advance = face->glyph->advance.x * m / 64.0; - c.size = {width * m, height * m}; - c.bearing = {offx * m, offy * m}; + Character& c = characters[i]; + c.advance = face->glyph->advance.x * texel_size / 64.0; + c.size = {width * texel_size, height * texel_size}; + c.bearing = {offx * texel_size, offy * texel_size}; if(c.size.x == 0 || c.size.y == 0) { - c.handle = 0; continue; } - pixels.resize(width * height); + std::vector buffer(width * height); for(int i = 0; i < width * height; i++) { - pixels[i] = glm::vec<4, unsigned char>(face->glyph->bitmap.buffer[i]); + buffer[i] = face->glyph->bitmap.buffer[i]; } - glCreateTextures(GL_TEXTURE_2D, 1, &texids[i]); - - glTextureStorage2D(texids[i], 1, GL_RGBA8, width, height); - glTextureSubImage2D(texids[i], 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]); - - glTextureParameteri(texids[i], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTextureParameteri(texids[i], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTextureParameteri(texids[i], GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTextureParameteri(texids[i], GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - c.handle = glGetTextureHandleARB(texids[i]); - glMakeTextureHandleResidentARB(c.handle); - chars[i] = c; + int swizzleMask[] = {GL_RED, GL_RED, GL_RED, GL_RED}; + c.handle = Texture::load_mem(buffer.data(), width, height, 1, swizzleMask); } FT_Done_FreeType(ft); } -Mesh& Mesh::load_text(const char* text, double size) +Font::Font() { - std::vector vertices; - std::vector indices; +} + +Mesh Font::load_text(const std::string& text, float size) const +{ + Mesh m; + + if(text[0] == '\0') + { + return m; + } float x = 0, y = size; unsigned int at = 0; - - if(text[0] == '\0') + float t0 = 0; + float t1 = 1; +/* + if(!Shader::USE_BINDLESS_TEXTURES) { - this->vertices.clear(); - this->indices.clear(); - return *this; - } + t0 += texel_size / 2; + t1 -= texel_size / 2; + }*/ - for(unsigned int i = 0; text[i] != '\0'; i++) + + for(unsigned int i = 0; i < text.size(); i++) { char c = text[i]; - Character ch = chars[c]; + const Character& ch = characters[c]; if(c == '\n') { @@ -144,30 +137,25 @@ Mesh& Mesh::load_text(const char* text, double size) float ex = sx + ch.size.x * size; float ey = sy + ch.size.y * size; - vertices.push_back(Arrays::Vertex{.texpos={0, 0}, .pos={sx, sy, 0}, .tex_diffuse=ch.handle, .material={0, 0, 1}}); - vertices.push_back(Arrays::Vertex{.texpos={0, 1}, .pos={sx, ey, 0}, .tex_diffuse=ch.handle, .material={0, 0, 1}}); - vertices.push_back(Arrays::Vertex{.texpos={1, 0}, .pos={ex, sy, 0}, .tex_diffuse=ch.handle, .material={0, 0, 1}}); - vertices.push_back(Arrays::Vertex{.texpos={1, 1}, .pos={ex, ey, 0}, .tex_diffuse=ch.handle, .material={0, 0, 1}}); - indices.insert(indices.end(), &index[0], &index[6]); + m.vertices.push_back(Arrays::Vertex{.texpos={t0, t0}, .pos={sx, sy, 0}, .tex_diffuse=ch.handle, .material={0, 0, 1}}); + m.vertices.push_back(Arrays::Vertex{.texpos={t0, t1}, .pos={sx, ey, 0}, .tex_diffuse=ch.handle, .material={0, 0, 1}}); + m.vertices.push_back(Arrays::Vertex{.texpos={t1, t0}, .pos={ex, sy, 0}, .tex_diffuse=ch.handle, .material={0, 0, 1}}); + m.vertices.push_back(Arrays::Vertex{.texpos={t1, t1}, .pos={ex, ey, 0}, .tex_diffuse=ch.handle, .material={0, 0, 1}}); + m.indices.insert(m.indices.end(), &index[0], &index[6]); at += 4; x += ch.advance * size; } - this->vertices = std::move(vertices); - this->indices = std::move(indices); - this->transforms.clear(); - - return *this; + return m; } -Mesh& Mesh::load_text(const char* text, double size, glm::vec2 align) +Mesh Font::load_text(const std::string& text, float size, glm::vec2 align) const { glm::vec2 max; - - load_text(text, size); + Mesh m = load_text(text, size); - for(Arrays::Vertex& v : vertices) + for(Arrays::Vertex& v : m.vertices) { if(v.pos.x > max.x) { @@ -182,12 +170,12 @@ Mesh& Mesh::load_text(const char* text, double size, glm::vec2 align) align *= max; - for(Arrays::Vertex& v : vertices) + for(Arrays::Vertex& v : m.vertices) { v.pos.x -= align.x; v.pos.y -= align.y; } - return *this; + return m; } diff --git a/src/graphics/data/font.hpp b/src/graphics/data/font.hpp index 552e9a1..a82c68f 100644 --- a/src/graphics/data/font.hpp +++ b/src/graphics/data/font.hpp @@ -6,10 +6,56 @@ #include #include -namespace Sim::Graphics::Data::Font +#include + +namespace Sim::Graphics::Data { -void init(); +class Font +{ + struct Character + { + uint32_t handle; + glm::vec2 size; + glm::vec2 bearing; + float advance; + }; + + float texel_size; + Character characters[128]; + +public: + + Font(); + + void init(const std::string& name, int size); + Mesh load_text(const std::string& text, float size, glm::vec2 align) const; + Mesh load_text(const std::string& text, float size) const; + + template + void load_text(const char* header, T& item, double size) + { + std::stringstream ss; + ss << header << item; + load_text(ss.str(), size); + } + + template + void load_text(const char* header, T& item, double size, glm::vec2 align) + { + std::stringstream ss; + ss << header << item; + load_text(ss.str(), size, align); + } +}; + +namespace Fonts +{ + void init(); + + extern Font BASE; + extern Font MONO; +} }; diff --git a/src/graphics/data/font_new.cpp b/src/graphics/data/font_new.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/graphics/data/mesh.hpp b/src/graphics/data/mesh.hpp index 3ffbd8e..8837079 100644 --- a/src/graphics/data/mesh.hpp +++ b/src/graphics/data/mesh.hpp @@ -28,8 +28,6 @@ struct Mesh Mesh& set_blank_transform(); Mesh& set_normal_id(unsigned int id); Mesh& set_diffuse_id(unsigned int id); - Mesh& load_text(const char* text, double size); - Mesh& load_text(const char* text, double size, glm::vec2 align); Mesh& add(const Mesh& o, glm::mat4 mat = glm::mat4(1), bool bake = false); Mesh to_lines() const; @@ -40,14 +38,6 @@ struct Mesh bool operator==(const Mesh&) const = default; - template - void load_text(const char* header, T& item, double size) - { - std::stringstream ss; - ss << header << item; - load_text(ss.str().c_str(), size); - } - friend std::ostream& operator<<(std::ostream& os, const Mesh& m); }; diff --git a/src/graphics/data/model.cpp b/src/graphics/data/model.cpp index 057f493..1f521b7 100644 --- a/src/graphics/data/model.cpp +++ b/src/graphics/data/model.cpp @@ -252,7 +252,13 @@ Model::Model(std::string base, std::string filename) : base(base) glm::vec3 look = glm::normalize(glm::mat3(mat) * glm::vec3(dx, dy, dz)); glm::vec3 up = glm::normalize(glm::mat3(mat) * glm::vec3(ux, uy, uz)); - cameras.push_back({.pos=glm::vec3(pos), .look=look, .up=up, .fov=camera->mHorizontalFOV}); + cameras.push_back(Camera { + .name={camera->mName.C_Str()}, + .pos=glm::vec3(pos), + .look=look, + .up=up, + .fov=camera->mHorizontalFOV + }); } for(int i = 0; i < scene->mNumMaterials; i++) diff --git a/src/graphics/data/texture.cpp b/src/graphics/data/texture.cpp index 7c82836..2013a7b 100644 --- a/src/graphics/data/texture.cpp +++ b/src/graphics/data/texture.cpp @@ -2,33 +2,199 @@ #include #include #include +#include + +#include #include #include +#include #include "texture.hpp" +#include "atlas.hpp" +#include "../shader.hpp" using namespace Sim::Graphics::Data; -static std::unordered_map loaded; -uint64_t Texture::handle_white; -uint64_t Texture::handle_normal; +static bool is_done = false; +static uint32_t atlas_texid; +static uint32_t atlas_uv_ssbo; +static std::unordered_map loaded; +static std::vector> texture_atlas_queue; + +uint32_t Texture::handle_white; +uint32_t Texture::handle_normal; void Texture::init() { - unsigned char pixels_white[] = {255, 255, 255}; - unsigned char pixels_normal[] = {128, 128, 255}; - handle_white = load_mem(pixels_white, 1, 1, 3); - handle_normal = load_mem(pixels_normal, 1, 1, 3); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + unsigned char pixels_white[] = {255}; + unsigned char pixels_normal[] = {128, 255}; + int swizzle_white[] = {GL_RED, GL_RED, GL_RED, GL_RED}; + int swizzle_normal[] = {GL_RED, GL_RED, GL_GREEN, GL_GREEN}; + handle_white = load_mem(pixels_white, 1, 1, 1, swizzle_white); + handle_normal = load_mem(pixels_normal, 1, 1, 2, swizzle_normal); } -uint64_t Texture::load_mem(const void* data, int width, int height, int channels) +void Texture::generate_atlas() { + // if we are using bindless textures, we don't need to generate an atlas + if(Shader::USE_BINDLESS_TEXTURES) + { + return; + } + + int total_area = 0; + int padding = 2; + int offset = 1; + + for(const Atlas<4>& atlas : texture_atlas_queue) + { + total_area += (atlas.width + padding) * (atlas.height + padding); + } + + int size = std::pow(2, std::ceil(std::log2(std::sqrt(total_area)))); + + std::vector rects; + std::vector uvs; + + rects.reserve(texture_atlas_queue.size()); + uvs.reserve(texture_atlas_queue.size()); + + for(int i = 0; i < texture_atlas_queue.size(); i++) + { + const Atlas<4>& atlas = texture_atlas_queue[i]; + stbrp_rect rect; + rect.id = i; + rect.w = atlas.width + padding; + rect.h = atlas.height + padding; + rects.push_back(rect); + } + + stbrp_context context; + std::vector nodes(size); + + for(;;) + { + stbrp_init_target(&context, size, size, nodes.data(), nodes.size()); + + if(stbrp_pack_rects(&context, rects.data(), rects.size()) == 1) + { + break; + } + + size *= 2; + nodes.resize(size); + std::cout << "Error: failed to pack textures, trying again with size " << size << "\n"; + } + + Atlas<4> atlas(size, size); + + for(const stbrp_rect& rect : rects) + { + const Atlas<4>& src = texture_atlas_queue[rect.id]; + atlas.draw(src, rect.x + offset, rect.y + offset, true); + + uvs.emplace_back(glm::mat2( + (rect.x + offset + 0.5f) / size, (rect.y + offset + 0.5f) / size, + (rect.x + offset + src.width - 0.5f) / size, (rect.y + offset + src.height - 0.5f) / size + )); + } + + std::cout << "Finished stitching " << size << "x" << size << " texture atlas\n"; + + glGenTextures(1, &atlas_texid); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, atlas_texid); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, atlas.data.data()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenerateMipmap(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + + glGenBuffers(1, &atlas_uv_ssbo); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, atlas_uv_ssbo); + glBufferData(GL_SHADER_STORAGE_BUFFER, uvs.size() * sizeof(uvs[0]), uvs.data(), GL_STATIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, atlas_uv_ssbo); + + glUniform1i(Shader::MAIN["tex_atlas"], 1); + + is_done = true; +} + +uint32_t Texture::load_mem(const uint8_t* data, int width, int height, int channels, int* swizzleMask) +{ + if(is_done) + { + throw std::runtime_error("Texture loading is done"); + } + if(!data) { return 0; } + int swizzleMaskDefault[] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; + + if(!swizzleMask) + { + swizzleMask = swizzleMaskDefault; + + switch(channels) + { + case 1: + swizzleMask[1] = GL_ONE; + case 2: + swizzleMask[2] = GL_ONE; + case 3: + swizzleMask[3] = GL_ONE; + } + } + + if(!Shader::USE_BINDLESS_TEXTURES) + { + Atlas<4> atlas(width, height); + + for(int i = 0; i < width * height; i++) + { + int pixel_pos = i * channels; + Atlas<4>::Pixel pixel; + + for(int j = 0; j < 4; j++) + { + switch(swizzleMask[j]) + { + case GL_RED: + pixel[j] = data[pixel_pos]; + break; + case GL_GREEN: + pixel[j] = data[pixel_pos + 1]; + break; + case GL_BLUE: + pixel[j] = data[pixel_pos + 2]; + break; + case GL_ALPHA: + pixel[j] = data[pixel_pos + 3]; + break; + case GL_ZERO: + pixel[j] = 0; + break; + case GL_ONE: + pixel[j] = 255; + break; + } + } + + atlas.data[i] = pixel; + } + + texture_atlas_queue.push_back(std::move(atlas)); + return texture_atlas_queue.size() - 1; + } + GLenum format; GLenum format_in; @@ -56,22 +222,22 @@ uint64_t Texture::load_mem(const void* data, int width, int height, int channels unsigned int texid; - glCreateTextures(GL_TEXTURE_2D, 1, &texid); - glTextureStorage2D(texid, 1, format_in, width, height); - glTextureSubImage2D(texid, 0, 0, 0, width, height, format, GL_UNSIGNED_BYTE, data); + glGenTextures(1, &texid); + glBindTexture(GL_TEXTURE_2D, texid); + glTexImage2D(GL_TEXTURE_2D, 0, format_in, width, height, 0, format, GL_UNSIGNED_BYTE, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTextureParameteriv(texid, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + glGenerateMipmap(GL_TEXTURE_2D); - glTextureParameteri(texid, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTextureParameteri(texid, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTextureParameteri(texid, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTextureParameteri(texid, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glGenerateTextureMipmap(texid); - - uint64_t handle = glGetTextureHandleARB(texid); + uint32_t handle = glGetTextureHandleARB(texid); glMakeTextureHandleResidentARB(handle); return handle; } -uint64_t Texture::load_mem(const unsigned char* filedata, size_t len) +uint32_t Texture::load_mem(const uint8_t* filedata, size_t len) { int width, height, channels; unsigned char* data = stbi_load_from_memory(filedata, len, &width, &height, &channels, 0); @@ -80,7 +246,7 @@ uint64_t Texture::load_mem(const unsigned char* filedata, size_t len) return handle; } -uint64_t Texture::load(std::string path) +uint32_t Texture::load(std::string path) { const auto it = loaded.find(path); diff --git a/src/graphics/data/texture.hpp b/src/graphics/data/texture.hpp index 3a3af33..101ea71 100644 --- a/src/graphics/data/texture.hpp +++ b/src/graphics/data/texture.hpp @@ -4,17 +4,19 @@ #include #include +#include namespace Sim::Graphics::Data::Texture { -extern uint64_t handle_white; -extern uint64_t handle_normal; +extern uint32_t handle_white; +extern uint32_t handle_normal; void init(); -uint64_t load(std::string path); -uint64_t load_mem(const void* data, int width, int height, int channels); -uint64_t load_mem(const unsigned char* data, size_t len); +void generate_atlas(); +uint32_t load(std::string path); +uint32_t load_mem(const uint8_t* data, int width, int height, int channels, int* swizzleMask = nullptr); +uint32_t load_mem(const uint8_t* data, size_t len); }; diff --git a/src/graphics/monitor/cctv.cpp b/src/graphics/monitor/cctv.cpp index 12f1244..0c061e0 100644 --- a/src/graphics/monitor/cctv.cpp +++ b/src/graphics/monitor/cctv.cpp @@ -13,6 +13,7 @@ #include "../camera.hpp" #include "../input/focus.hpp" #include "../data/texture.hpp" +#include "../data/font.hpp" #include "../../system.hpp" #include "../../util/math.hpp" #include "../../util/streams.hpp" @@ -49,7 +50,7 @@ public: if(zoom) { Data::Camera& active = parent->cameras[parent->camera_at]; - active.zoom = Util::Math::clamp(1.f / (1.f / active.zoom - zoom * dt * 0.5f), 1.f, 4.f); + active.zoom = Util::Math::clamp(active.zoom - zoom * dt * 0.5f, 0.25, 1); } } @@ -63,7 +64,7 @@ public: parent->camera_at = (parent->camera_at + parent->cameras.size() - 1) % parent->cameras.size(); break; case GLFW_KEY_KP_2: - rot_pitch -= 1; + parent->powered = !parent->powered; break; case GLFW_KEY_KP_3: parent->camera_at = (parent->camera_at + 1) % parent->cameras.size(); @@ -72,7 +73,7 @@ public: rot_yaw += 1; break; case GLFW_KEY_KP_5: - parent->powered = !parent->powered; + rot_pitch -= 1; break; case GLFW_KEY_KP_6: rot_yaw -= 1; @@ -93,12 +94,12 @@ public: { switch(key) { - case GLFW_KEY_KP_2: - rot_pitch += 1; - break; case GLFW_KEY_KP_4: rot_yaw -= 1; break; + case GLFW_KEY_KP_5: + rot_pitch += 1; + break; case GLFW_KEY_KP_6: rot_yaw += 1; break; @@ -150,6 +151,7 @@ CCTV::CCTV(Model& model) handle = glGetTextureHandleARB(texture); glMakeTextureHandleResidentARB(handle); + mat = model.load_matrix("translation_monitor_1"); m_screen.vertices = { {.texpos={0, 1}, .pos={0, 0, 0}, .transform_id=0, .tex_diffuse=handle, .material={0, 0, 1}}, {.texpos={0, 0}, .pos={0, 1, 0}, .transform_id=0, .tex_diffuse=handle, .material={0, 0, 1}}, @@ -157,7 +159,7 @@ CCTV::CCTV(Model& model) {.texpos={1, 0}, .pos={1, 1, 0}, .transform_id=0, .tex_diffuse=handle, .material={0, 0, 1}}, }; m_screen.indices = {0, 1, 3, 0, 3, 2}; - m_screen.transforms = {model.load_matrix("translation_monitor_1")}; + m_screen.transforms = {mat}; m_screen.bake_transforms(); gm_screen.bind(); @@ -194,12 +196,50 @@ CCTV::CCTV(CCTV&& o) void CCTV::rotate(double dt, float pitch, float yaw) { Data::Camera& active = cameras[camera_at]; - float m = float(M_PI) * dt * 0.5f / active.zoom; + float m = float(M_PI) * dt * 0.5f * active.zoom; active.pitch = Util::Math::clamp(active.pitch + pitch * m, -M_PI / 4, M_PI / 4); active.yaw = Util::Math::clamp(active.yaw + yaw * m, -M_PI / 4, M_PI / 4); } +void CCTV::remesh_slow(Data::Mesh& rmesh) +{ + if(!powered) + { + return; + } + + const Data::Camera& active = cameras[camera_at]; + std::stringstream ss; + + ss << "- "; + + for(int i = 0; i < cameras.size(); i++) + { + if(i == camera_at) + { + ss << "[" << cameras[i].name << "] "; + } + + else + { + ss << " " << cameras[i].name << " "; + } + } + + ss << "-\n"; + + rmesh.add(Data::Fonts::MONO.load_text(ss.str(), 0.02, {0.5, 0}), glm::translate(mat, {0.5, 0.95, 0}), true); + + char zoom_chars[] = " "; + zoom_chars[(int)std::round(Util::Math::ramp(active.zoom, 1, 0.25, 0, 9))] = '#'; + + ss.str(""); + ss << "Zoom: [" << zoom_chars << "]"; + + rmesh.add(Data::Fonts::MONO.load_text(ss.str(), 0.02), glm::translate(mat, {0.0125, 0.0125, 0}), true); +} + void CCTV::update(double dt) { Data::Camera& active = cameras[camera_at]; @@ -207,21 +247,21 @@ void CCTV::update(double dt) if(m_screen.check_focus()) Focus::set(std::make_unique(this)); if(m_buttons[0].check_focus_hold()) - active.zoom = Util::Math::clamp(1.f / (1.f / active.zoom - dt * 0.5f), 1.f, 4.f); + active.zoom = Util::Math::clamp(active.zoom - dt * 0.5f, 0.25, 1); if(m_buttons[1].check_focus_hold()) rotate(dt, 1, 0); if(m_buttons[2].check_focus_hold()) - active.zoom = Util::Math::clamp(1.f / (1.f / active.zoom + dt * 0.5f), 1.f, 4.f); + active.zoom = Util::Math::clamp(active.zoom + dt * 0.5f, 0.25, 1); if(m_buttons[3].check_focus_hold()) rotate(dt, 0, -1); - if(m_buttons[4].check_focus()) - powered = !powered; + if(m_buttons[4].check_focus_hold()) + rotate(dt, -1, 0); if(m_buttons[5].check_focus_hold()) rotate(dt, 0, 1); if(m_buttons[6].check_focus()) camera_at = (camera_at + cameras.size() - 1) % cameras.size(); - if(m_buttons[7].check_focus_hold()) - rotate(dt, -1, 0); + if(m_buttons[7].check_focus()) + powered = !powered; if(m_buttons[8].check_focus()) camera_at = (camera_at + 1) % cameras.size(); } @@ -239,7 +279,7 @@ void CCTV::render_view() rot = glm::rotate(rot, active.pitch, right); glm::mat4 view = glm::lookAt(active.pos, active.pos + glm::mat3(rot) * active.look, active.up); - glm::mat4 proj = glm::perspective(active.fov / active.zoom, (float)width / height, 0.1f, 100.0f); + glm::mat4 proj = glm::perspective(active.fov * active.zoom, (float)width / height, 0.1f, 100.0f); glm::vec3 brightness = glm::vec3(System::active->grid.get_light_intensity()); glBindFramebuffer(GL_FRAMEBUFFER, fbo); diff --git a/src/graphics/monitor/cctv.hpp b/src/graphics/monitor/cctv.hpp index 678698f..a17b7ab 100644 --- a/src/graphics/monitor/cctv.hpp +++ b/src/graphics/monitor/cctv.hpp @@ -1,6 +1,8 @@ #pragma once +#include + #include #include @@ -27,6 +29,7 @@ class CCTV : public Data::MeshGen public: + glm::mat4 mat; std::vector cameras; int camera_at = 0; bool powered = false; @@ -37,6 +40,7 @@ public: ~CCTV(); void update(double dt) override; + void remesh_slow(Data::Mesh& rmesh) override; void rotate(double dt, float pitch, float yaw); void render_view(); void render_screen(); diff --git a/src/graphics/monitor/core.cpp b/src/graphics/monitor/core.cpp index 54494c4..6bb4099 100644 --- a/src/graphics/monitor/core.cpp +++ b/src/graphics/monitor/core.cpp @@ -8,6 +8,7 @@ #include "../data/texture.hpp" #include "../../system.hpp" #include "../../util/streams.hpp" +#include "../data/font.hpp" #include @@ -66,7 +67,7 @@ struct CoreMonitor : public Focus::FocusType sys.reactor.move_cursor(-1); break; case GLFW_KEY_KP_5: - sys.reactor.toggle_selected(); + sys.reactor.move_cursor(sys.reactor.height); break; case GLFW_KEY_KP_6: sys.reactor.move_cursor(1); @@ -75,7 +76,7 @@ struct CoreMonitor : public Focus::FocusType sys.reactor.reset_rod_speed(); break; case GLFW_KEY_KP_2: - sys.reactor.move_cursor(sys.reactor.height); + sys.reactor.toggle_selected(); break; default: return; @@ -135,9 +136,7 @@ Core::Core(const Model& model) void Core::remesh_static(Mesh& rmesh) { - Data::Mesh mesh; - mesh.load_text("Reactor Core", 0.04); - rmesh.add(mesh, mat, true); + rmesh.add(Data::Fonts::BASE.load_text("Reactor Core", 0.04), mat, true); } static Data::Mesh add_dot(glm::mat4 model_mat, glm::vec4 colour) @@ -174,13 +173,13 @@ void Core::update(double dt) if(m_buttons[3].check_focus()) sys.reactor.move_cursor(-1); if(m_buttons[4].check_focus()) - sys.reactor.toggle_selected(); + sys.reactor.move_cursor(sys.reactor.height); if(m_buttons[5].check_focus()) sys.reactor.move_cursor(1); if(m_buttons[6].check_focus()) sys.reactor.reset_rod_speed(); if(m_buttons[7].check_focus()) - sys.reactor.move_cursor(sys.reactor.height); + sys.reactor.toggle_selected(); } void Core::remesh_slow(Mesh& rmesh) diff --git a/src/graphics/monitor/primary_loop.cpp b/src/graphics/monitor/primary_loop.cpp index a3f820c..5ff32d9 100644 --- a/src/graphics/monitor/primary_loop.cpp +++ b/src/graphics/monitor/primary_loop.cpp @@ -7,6 +7,7 @@ #include "../../coolant/valve.hpp" #include "../input/focus.hpp" #include "../../util/streams.hpp" +#include "../data/font.hpp" #include #include @@ -67,7 +68,6 @@ PrimaryLoop::PrimaryLoop(const Model& model) void PrimaryLoop::remesh_static(Mesh& rmesh) { std::stringstream ss; - Data::Mesh mesh; ss << "Turbine Bypass Valve\n\n"; ss << "Opened\nFlow\nSetpoint\n\n"; @@ -81,8 +81,7 @@ void PrimaryLoop::remesh_static(Mesh& rmesh) ss << "Pressure\n"; ss << "Level\n"; - mesh.load_text(ss.str().c_str(), 0.04); - rmesh.add(mesh, mat, true); + rmesh.add(Data::Fonts::BASE.load_text(ss.str(), 0.04), mat, true); rmesh.add(g_switch_pump); rmesh.add(g_switch_bypass); @@ -108,7 +107,6 @@ void PrimaryLoop::update(double dt) void PrimaryLoop::remesh_slow(Mesh& rmesh) { std::stringstream ss; - Sim::Graphics::Data::Mesh mesh; System& sys = *System::active; ss << "\n\n"; @@ -149,7 +147,7 @@ void PrimaryLoop::remesh_slow(Mesh& rmesh) show_units( ss, sys.loop.condenser.get_pressure() ) << "Pa\n"; ss << show( sys.loop.condenser.get_level() / 1000 ) << " / " << show( sys.loop.condenser.get_volume() / 1000 ) << " kL\n"; - mesh.load_text(ss.str().c_str(), 0.04); + Mesh mesh = Data::Fonts::BASE.load_text(ss.str(), 0.04); rmesh.add(mesh, glm::translate(mat, glm::vec3(0.5, 0, 0))); } diff --git a/src/graphics/monitor/secondary_loop.cpp b/src/graphics/monitor/secondary_loop.cpp index 230f916..a3ade1f 100644 --- a/src/graphics/monitor/secondary_loop.cpp +++ b/src/graphics/monitor/secondary_loop.cpp @@ -7,6 +7,7 @@ #include "../../coolant/valve.hpp" #include "../input/focus.hpp" #include "../../util/streams.hpp" +#include "../data/font.hpp" #include #include @@ -42,7 +43,6 @@ void SecondaryLoop::update(double dt) void SecondaryLoop::remesh_static(Mesh& rmesh) { std::stringstream ss; - Data::Mesh mesh; ss << "Cooling Tower\n\n"; ss << "Heat\nSteam\nPressure\nLevel\n\n"; @@ -51,8 +51,7 @@ void SecondaryLoop::remesh_static(Mesh& rmesh) ss << "Freight Pump\n\n"; ss << "Power\nSpeed\nFlow\n\n"; - mesh.load_text(ss.str().c_str(), 0.04); - rmesh.add(mesh, mat, true); + rmesh.add(Data::Fonts::BASE.load_text(ss.str(), 0.04), mat, true); rmesh.add(g_switch_2); rmesh.add(g_switch_3); } @@ -60,7 +59,6 @@ void SecondaryLoop::remesh_static(Mesh& rmesh) void SecondaryLoop::remesh_slow(Mesh& rmesh) { std::stringstream ss; - Sim::Graphics::Data::Mesh mesh; System& sys = *System::active; ss << "\n\n"; @@ -77,7 +75,7 @@ void SecondaryLoop::remesh_slow(Mesh& rmesh) ss << show( sys.freight_pump.get_rpm() ) << " r/min\n"; show_units( ss, sys.freight_pump.get_flow_mass() ) << "g/s\n"; - mesh.load_text(ss.str().c_str(), 0.04); + Mesh mesh = Data::Fonts::BASE.load_text(ss.str().c_str(), 0.04); rmesh.add(mesh, glm::translate(mat, glm::vec3(0.5, 0, 0))); } diff --git a/src/graphics/monitor/turbine.cpp b/src/graphics/monitor/turbine.cpp index e87f465..dbbdbb0 100644 --- a/src/graphics/monitor/turbine.cpp +++ b/src/graphics/monitor/turbine.cpp @@ -8,6 +8,7 @@ #include "../input/focus.hpp" #include "../../util/streams.hpp" #include "../../util/math.hpp" +#include "../data/font.hpp" #include #include @@ -69,13 +70,11 @@ void Turbine::get_static_transforms(std::vector& transforms) void Turbine::remesh_static(Mesh& rmesh) { std::stringstream ss; - Sim::Graphics::Data::Mesh mesh; ss << "Turbine\n\n"; ss << "Heat\nPressure\nSpeed\n\n"; - mesh.load_text(ss.str().c_str(), 0.04); - rmesh.add(mesh, mat, true); + rmesh.add(Data::Fonts::BASE.load_text(ss.str(), 0.04), mat, true); rmesh.add(g_dial_phase); rmesh.add(g_dial_voltage); @@ -87,7 +86,6 @@ void Turbine::remesh_static(Mesh& rmesh) void Turbine::remesh_slow(Mesh& rmesh) { std::stringstream ss; - Sim::Graphics::Data::Mesh mesh; System& sys = *System::active; ss << "\n\n"; @@ -95,7 +93,7 @@ void Turbine::remesh_slow(Mesh& rmesh) ss << show( sys.loop.turbine.get_pressure() / 1000 ) << " kPa\n"; ss << show( sys.loop.generator.get_rpm() ) << " r/min\n"; - mesh.load_text(ss.str().c_str(), 0.04); + Mesh mesh = Data::Fonts::BASE.load_text(ss.str(), 0.04); rmesh.add(mesh, glm::translate(mat, glm::vec3(0.5, 0, 0))); } diff --git a/src/graphics/monitor/vessel.cpp b/src/graphics/monitor/vessel.cpp index f288d70..cad5d96 100644 --- a/src/graphics/monitor/vessel.cpp +++ b/src/graphics/monitor/vessel.cpp @@ -7,6 +7,7 @@ #include "../../reactor/control/boron_rod.hpp" #include "../../system.hpp" #include "../../util/streams.hpp" +#include "../data/font.hpp" #include #include @@ -23,7 +24,6 @@ Vessel::Vessel(const Model& model) void Vessel::remesh_static(Mesh& rmesh) { std::stringstream ss; - Sim::Graphics::Data::Mesh mesh; ss << "Reactor Vessel\n\n"; ss << "Heat\n"; @@ -37,14 +37,12 @@ void Vessel::remesh_static(Mesh& rmesh) ss << "Temperature\nMin\nMax\n\n"; ss << "Control Rods\nMin\nMax\nSpeed\n"; - mesh.load_text(ss.str().c_str(), 0.04); - rmesh.add(mesh, mat, true); + rmesh.add(Data::Fonts::BASE.load_text(ss.str(), 0.04), mat, true); } void Vessel::remesh_slow(Mesh& rmesh) { std::stringstream ss; - Sim::Graphics::Data::Mesh mesh; Sim::System& sys = *System::active; double temp_min, temp_max; @@ -92,7 +90,7 @@ void Vessel::remesh_slow(Mesh& rmesh) if(sys.reactor.rod_speed == 0) ss << " (Stopped)"; ss << "\n"; - mesh.load_text(ss.str().c_str(), 0.04); + Mesh mesh = Data::Fonts::BASE.load_text(ss.str(), 0.04); rmesh.add(mesh, glm::translate(mat, glm::vec3(0.5, 0, 0))); } diff --git a/src/graphics/shader.cpp b/src/graphics/shader.cpp index cd29c22..52e8a11 100644 --- a/src/graphics/shader.cpp +++ b/src/graphics/shader.cpp @@ -8,6 +8,7 @@ #include #include "shader.hpp" +#include "shadersource.hpp" #include "window.hpp" using namespace Sim::Graphics; @@ -16,40 +17,54 @@ Shader Shader::MAIN; Shader Shader::LIGHT; Shader* Shader::ACTIVE; -static std::string read_shader(const char* path) +bool Shader::USE_BINDLESS_TEXTURES = false; + +static std::vector shader_compiler_flags; + +void Shader::add_define(const std::string& flag) +{ + shader_compiler_flags.push_back(flag); +} + +void Shader::init() +{ + Shader::Source sources_main[] = { + {ShaderSource::MAIN_VSH, "main.vsh", GL_VERTEX_SHADER}, + {ShaderSource::MAIN_FSH, "main.fsh", GL_FRAGMENT_SHADER} + }; + + Shader::Source sources_light[] = { + {ShaderSource::LIGHT_VSH, "light.vsh", GL_VERTEX_SHADER}, + {ShaderSource::LIGHT_GSH, "light.gsh", GL_GEOMETRY_SHADER}, + {ShaderSource::LIGHT_FSH, "light.fsh", GL_FRAGMENT_SHADER} + }; + + Shader::MAIN.load(sources_main, "main", 2); + Shader::LIGHT.load(sources_light, "light", 3); +} + +std::string apply_shader_compiler_flags(const char* source) { std::stringstream ss; - std::ifstream file(path, std::ios::binary); - char buff[1024]; + ss << "#version 430 core\n"; - if(!file.is_open()) + for(const auto& flag : shader_compiler_flags) { - throw std::runtime_error(std::format("Shader Read Error: {0}", path)); - } - - while(!file.eof()) - { - file.read(buff, 1024); - ss.write(buff, file.gcount()); + ss << "#define " << flag << "\n"; } + ss << source; return ss.str(); } -static std::string read_shader(const char* base, const char* file) -{ - std::string path = std::string(base) + "/" + std::string(file); - return read_shader(path.c_str()); -} - -Shader::Source::Source(const char* path, GLenum type) +Shader::Source::Source(const char* data, const char* name, GLenum type) { int success; - std::string src = read_shader(path); - const char* c_src = src.c_str(); + std::string source = apply_shader_compiler_flags(data); + data = source.c_str(); id = glCreateShader(type); - glShaderSource(id, 1, &c_src, nullptr); + glShaderSource(id, 1, &data, nullptr); glCompileShader(id); glGetShaderiv(id, GL_COMPILE_STATUS, &success); @@ -57,7 +72,7 @@ Shader::Source::Source(const char* path, GLenum type) { char infoLog[512]; glGetShaderInfoLog(id, 512, NULL, infoLog); - std::string entry = std::format("Shader Compile Error ({0}): {1}", path, infoLog); + std::string entry = std::format("Shader Compile Error ({0}): {1}", name, infoLog); throw std::runtime_error(entry); } } @@ -92,7 +107,7 @@ Shader::~Shader() } } -void Shader::load(const Source* sources, int count) +void Shader::load(const Source* sources, const char* name, int count) { int success; prog_id = glCreateProgram(); @@ -109,7 +124,7 @@ void Shader::load(const Source* sources, int count) { char infoLog[512]; glGetProgramInfoLog(prog_id, 512, NULL, infoLog); - std::string entry = std::format("Shader Link Error: {0}", infoLog); + std::string entry = std::format("Shader Link Error {0}: {1}", name, infoLog); throw std::runtime_error(entry); } } diff --git a/src/graphics/shader.hpp b/src/graphics/shader.hpp index 2846a92..c31f9b7 100644 --- a/src/graphics/shader.hpp +++ b/src/graphics/shader.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace Sim::Graphics { @@ -22,7 +23,7 @@ public: { unsigned int id; - Source(const char* path, GLenum type); + Source(const char* data, const char* name, GLenum type); Source(const Source& o) = delete; Source(Source&& o); ~Source(); @@ -33,12 +34,17 @@ public: static Shader* ACTIVE; + static bool USE_BINDLESS_TEXTURES; + Shader(); Shader(const Shader& o) = delete; Shader(Shader&& o); ~Shader(); - void load(const Source* sources, int count); + static void add_define(const std::string& flag); + static void init(); + + void load(const Source* sources, const char* name, int count); void block_binding(const char* name, unsigned int index); void use(); diff --git a/assets/shader/light.fsh b/src/graphics/shaders/light.fsh similarity index 87% rename from assets/shader/light.fsh rename to src/graphics/shaders/light.fsh index 464c614..2d72e0d 100644 --- a/assets/shader/light.fsh +++ b/src/graphics/shaders/light.fsh @@ -1,5 +1,4 @@ - -#version 460 core +R"GLSL( in vec3 frag_pos; @@ -11,3 +10,4 @@ void main() gl_FragDepth = distance / far_plane; } +)GLSL"; diff --git a/assets/shader/light.gsh b/src/graphics/shaders/light.gsh similarity index 96% rename from assets/shader/light.gsh rename to src/graphics/shaders/light.gsh index 950f2c5..56df36e 100644 --- a/assets/shader/light.gsh +++ b/src/graphics/shaders/light.gsh @@ -1,5 +1,4 @@ - -#version 460 core +R"GLSL( layout (triangles) in; layout (triangle_strip, max_vertices=18) out; @@ -33,3 +32,4 @@ void main() } } +)GLSL"; diff --git a/assets/shader/light.vsh b/src/graphics/shaders/light.vsh similarity index 85% rename from assets/shader/light.vsh rename to src/graphics/shaders/light.vsh index e0eabc8..93fb634 100644 --- a/assets/shader/light.vsh +++ b/src/graphics/shaders/light.vsh @@ -1,11 +1,8 @@ - -#version 460 core - -#define MAX_LIGHTS 6 +R"GLSL( layout (location = 1) in vec3 aPos; layout (location = 2) in vec4 aColour; -layout (location = 6) in int aTransformIndex; +layout (location = 7) in int aTransformIndex; layout (binding = 3) readonly buffer TransformBuffer { @@ -31,3 +28,4 @@ void main() should_ignore = int(aColour.a < 1.f); } +)GLSL"; diff --git a/assets/shader/main.fsh b/src/graphics/shaders/main.fsh similarity index 85% rename from assets/shader/main.fsh rename to src/graphics/shaders/main.fsh index e693221..42ce5dc 100644 --- a/assets/shader/main.fsh +++ b/src/graphics/shaders/main.fsh @@ -1,6 +1,8 @@ +R"GLSL( -#version 460 core +#ifdef USE_BINDLESS_TEXTURES #extension GL_ARB_bindless_texture : require +#endif const float PI = 3.141592f; @@ -23,9 +25,40 @@ layout(std140, binding = 2) readonly buffer LightBuffer Light lights[]; }; +#ifdef USE_BINDLESS_TEXTURES + in flat sampler2D frag_tex_diffuse; in flat sampler2D frag_tex_normal; +#define ReadTexture(tex, uv) texture(tex, uv) + +#else + +in flat uint frag_tex_diffuse; +in flat uint frag_tex_normal; + +uniform sampler2D tex_atlas; + +struct AtlasPart +{ + vec2 uv_min; + vec2 uv_max; +}; + +layout(std140, binding = 5) readonly buffer AtlasBuffer +{ + AtlasPart atlas[]; +}; + +vec4 ReadTexture(uint tex, vec2 uv) +{ + AtlasPart a = atlas[tex]; + uv = mod(uv, 1.f) * (a.uv_max - a.uv_min) + a.uv_min; + return texture(tex_atlas, uv); +} + +#endif + out vec4 frag_colour; uniform vec3 brightness; @@ -107,10 +140,10 @@ vec3 sRGB_To_LinRGB(vec3 c) void main() { - vec4 albedo = texture2D(frag_tex_diffuse, vin.tex_pos); + vec4 albedo = ReadTexture(frag_tex_diffuse, vin.tex_pos); if(albedo.a == 0.f) discard; - vec3 tangent = texture2D(frag_tex_normal, vin.tex_pos).rgb * 2.f - 1.f; + vec3 tangent = ReadTexture(frag_tex_normal, vin.tex_pos).rgb * 2.f - 1.f; vec3 albedo_lin = sRGB_To_LinRGB(albedo.rgb) * vin.colour.rgb; albedo *= vin.colour; @@ -180,3 +213,4 @@ void main() frag_colour = vec4(light, albedo.a); } +)GLSL"; diff --git a/assets/shader/main.vsh b/src/graphics/shaders/main.vsh similarity index 74% rename from assets/shader/main.vsh rename to src/graphics/shaders/main.vsh index f976320..ca11f9e 100644 --- a/assets/shader/main.vsh +++ b/src/graphics/shaders/main.vsh @@ -1,6 +1,8 @@ +R"GLSL( -#version 460 core +#ifdef USE_BINDLESS_TEXTURES #extension GL_ARB_bindless_texture : require +#endif layout (location = 0) in vec2 aTexPos; layout (location = 1) in vec3 aPos; @@ -8,10 +10,26 @@ layout (location = 2) in vec4 aColour; layout (location = 3) in vec3 aTangent; layout (location = 4) in vec3 aBitangent; layout (location = 5) in vec3 aNormal; -layout (location = 6) in int aTransformIndex; -layout (location = 7) in sampler2D aTexDiffuse; -layout (location = 8) in sampler2D aTexNormal; -layout (location = 9) in vec3 aMaterial; +layout (location = 6) in vec3 aMaterial; +layout (location = 7) in int aTransformIndex; + +#ifdef USE_BINDLESS_TEXTURES + +layout (location = 8) in sampler2D aTexDiffuse; +layout (location = 9) in sampler2D aTexNormal; + +out flat sampler2D frag_tex_diffuse; +out flat sampler2D frag_tex_normal; + +#else + +layout (location = 8) in uint aTexDiffuse; +layout (location = 9) in uint aTexNormal; + +out flat uint frag_tex_diffuse; +out flat uint frag_tex_normal; + +#endif uniform mat4 camera; uniform mat4 projection; @@ -29,9 +47,6 @@ out VS_OUT { flat vec3 material; } vout; -out flat sampler2D frag_tex_diffuse; -out flat sampler2D frag_tex_normal; - mat4 load_model_mat(int index) { return index < 0 ? mat4(1.f) : transforms[index]; @@ -60,3 +75,4 @@ void main() gl_Position = mvp * pos; } +)GLSL"; diff --git a/src/graphics/shadersource.cpp b/src/graphics/shadersource.cpp new file mode 100644 index 0000000..84c3fcf --- /dev/null +++ b/src/graphics/shadersource.cpp @@ -0,0 +1,17 @@ + +#include "shadersource.hpp" + +using namespace Sim::Graphics; + +const char* ShaderSource::LIGHT_VSH = +#include "shaders/light.vsh" +const char* ShaderSource::LIGHT_GSH = +#include "shaders/light.gsh" +const char* ShaderSource::LIGHT_FSH = +#include "shaders/light.fsh" + +const char* ShaderSource::MAIN_VSH = +#include "shaders/main.vsh" +const char* ShaderSource::MAIN_FSH = +#include "shaders/main.fsh" + diff --git a/src/graphics/shadersource.hpp b/src/graphics/shadersource.hpp new file mode 100644 index 0000000..9d5c300 --- /dev/null +++ b/src/graphics/shadersource.hpp @@ -0,0 +1,12 @@ + +#pragma once + +namespace Sim::Graphics::ShaderSource +{ + extern const char* LIGHT_VSH; + extern const char* LIGHT_GSH; + extern const char* LIGHT_FSH; + extern const char* MAIN_VSH; + extern const char* MAIN_FSH; +}; + diff --git a/src/graphics/widget/clock.cpp b/src/graphics/widget/clock.cpp index a7273ce..9b9dbb6 100644 --- a/src/graphics/widget/clock.cpp +++ b/src/graphics/widget/clock.cpp @@ -27,7 +27,6 @@ void Clock::update(double dt) void Clock::remesh_slow(Mesh& rmesh) { - Mesh m; double at = System::active->clock; glm::vec2 wsize(Resize::get_size() / 2); std::stringstream ss; @@ -42,7 +41,7 @@ void Clock::remesh_slow(Mesh& rmesh) ss << std::setfill('0') << std::setw(2) << t_s << "\n"; ss << "Day: " << std::floor(at / (3600 * 24)) << "\n"; - m.load_text(ss.str().c_str(), 20); + Mesh m = Fonts::BASE.load_text(ss.str(), 20); rmesh.add(m, glm::translate(glm::mat4(1), glm::vec3(-wsize + glm::vec2(2, 2), 0))); } diff --git a/src/graphics/window.cpp b/src/graphics/window.cpp index 2c9a403..061a6f4 100644 --- a/src/graphics/window.cpp +++ b/src/graphics/window.cpp @@ -105,7 +105,7 @@ void Window::create() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true); glfwWindowHint(GLFW_VISIBLE, false); @@ -129,17 +129,15 @@ void Window::create() return; } - if(!glGetTextureHandleARB || !glMakeTextureHandleResidentARB) + if(glGetTextureHandleARB && glMakeTextureHandleResidentARB) { - std::cerr << "Fatal: Bindless textures not supported\n"; + Shader::add_define("USE_BINDLESS_TEXTURES"); + Shader::USE_BINDLESS_TEXTURES = true; + } - if(!glGetTextureHandleARB) - std::cerr << " Missing: glGetTextureHandleARB\n"; - if(!glMakeTextureHandleResidentARB) - std::cerr << " Missing: glMakeTextureHandleResidentARB\n"; - - close(); - return; + else + { + std::cout << "Warning: Bindless textures are not supported. Using texture atlas instead.\n"; } glEnable(GL_MULTISAMPLE); @@ -156,21 +154,9 @@ void Window::create() Mouse::init(); Resize::init(); Texture::init(); - Font::init(); + Fonts::init(); UI::init(); - - // load all the shaders - Shader::Source sources_main[] = { - {"../assets/shader/main.vsh", GL_VERTEX_SHADER}, - {"../assets/shader/main.fsh", GL_FRAGMENT_SHADER}, - }; - Shader::Source sources_light[] = { - {"../assets/shader/light.vsh", GL_VERTEX_SHADER}, - {"../assets/shader/light.gsh", GL_GEOMETRY_SHADER}, - {"../assets/shader/light.fsh", GL_FRAGMENT_SHADER}, - }; - Shader::MAIN.load(sources_main, 2); - Shader::LIGHT.load(sources_light, 3); + Shader::init(); Shader::MAIN.use(); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -204,6 +190,8 @@ void Window::create() equipment.push_back(new Equipment::Generator(model)); equipment.push_back(new Equipment::Pool(model)); + Texture::generate_atlas(); + remesh_static(); glfwShowWindow(win); diff --git a/src/stb/stb_rect_pack.cpp b/src/stb/stb_rect_pack.cpp new file mode 100644 index 0000000..0e08e8b --- /dev/null +++ b/src/stb/stb_rect_pack.cpp @@ -0,0 +1,4 @@ + +#define STB_RECT_PACK_IMPLEMENTATION +#include + diff --git a/src/util/math.hpp b/src/util/math.hpp index 0b30f01..1559f0c 100644 --- a/src/util/math.hpp +++ b/src/util/math.hpp @@ -48,5 +48,11 @@ constexpr A mod(A a, auto b) return v; } +template +constexpr A ramp(A v, auto imin, auto imax, auto omin, auto omax) +{ + return clamp(map(v, imin, imax, omin, omax), omin, omax); +} + };