add texture atlas for gpus without bindless textures
This commit is contained in:
parent
e2b16e0591
commit
2d69bb3c78
Binary file not shown.
BIN
assets/scene.blend (Stored with Git LFS)
BIN
assets/scene.blend (Stored with Git LFS)
Binary file not shown.
BIN
assets/scene.glb (Stored with Git LFS)
BIN
assets/scene.glb (Stored with Git LFS)
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -39,17 +39,18 @@ 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)
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Sim::Graphics::Data
|
||||
{
|
||||
|
||||
template <int N>
|
||||
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<Pixel> 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<N>& 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -2,16 +2,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <glm/matrix.hpp>
|
||||
#include <string>
|
||||
|
||||
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;
|
||||
|
|
|
@ -8,25 +8,27 @@
|
|||
#include <glm/vec2.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <format>
|
||||
|
||||
#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<glm::vec<4, unsigned char>> 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<uint8_t> 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<Arrays::Vertex> vertices;
|
||||
std::vector<unsigned int> indices;
|
||||
}
|
||||
|
||||
float x = 0, y = size;
|
||||
unsigned int at = 0;
|
||||
Mesh Font::load_text(const std::string& text, float size) const
|
||||
{
|
||||
Mesh m;
|
||||
|
||||
if(text[0] == '\0')
|
||||
{
|
||||
this->vertices.clear();
|
||||
this->indices.clear();
|
||||
return *this;
|
||||
return m;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; text[i] != '\0'; i++)
|
||||
float x = 0, y = size;
|
||||
unsigned int at = 0;
|
||||
float t0 = 0;
|
||||
float t1 = 1;
|
||||
/*
|
||||
if(!Shader::USE_BINDLESS_TEXTURES)
|
||||
{
|
||||
t0 += texel_size / 2;
|
||||
t1 -= texel_size / 2;
|
||||
}*/
|
||||
|
||||
|
||||
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;
|
||||
Mesh m = load_text(text, size);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,56 @@
|
|||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace Sim::Graphics::Data::Font
|
||||
#include <glm/vec2.hpp>
|
||||
|
||||
namespace Sim::Graphics::Data
|
||||
{
|
||||
|
||||
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 <class T>
|
||||
void load_text(const char* header, T& item, double size)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << header << item;
|
||||
load_text(ss.str(), size);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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 <class T>
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -2,33 +2,199 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <stb/stb_image.h>
|
||||
#include <stb/stb_rect_pack.h>
|
||||
|
||||
#include <glm/matrix.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
#include "texture.hpp"
|
||||
#include "atlas.hpp"
|
||||
#include "../shader.hpp"
|
||||
|
||||
using namespace Sim::Graphics::Data;
|
||||
|
||||
static std::unordered_map<std::string, uint64_t> 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<std::string, uint32_t> loaded;
|
||||
static std::vector<Atlas<4>> 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<stbrp_rect> rects;
|
||||
std::vector<glm::mat2> 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<stbrp_node> 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);
|
||||
|
||||
|
|
|
@ -4,17 +4,19 @@
|
|||
#include <GL/glew.h>
|
||||
|
||||
#include <string>
|
||||
#include <glm/vec2.hpp>
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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<FocusCCTV>(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);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <glm/matrix.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
|
@ -27,6 +29,7 @@ class CCTV : public Data::MeshGen
|
|||
|
||||
public:
|
||||
|
||||
glm::mat4 mat;
|
||||
std::vector<Data::Camera> 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();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "../data/texture.hpp"
|
||||
#include "../../system.hpp"
|
||||
#include "../../util/streams.hpp"
|
||||
#include "../data/font.hpp"
|
||||
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
|
||||
|
@ -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)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "../../coolant/valve.hpp"
|
||||
#include "../input/focus.hpp"
|
||||
#include "../../util/streams.hpp"
|
||||
#include "../data/font.hpp"
|
||||
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <iostream>
|
||||
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "../../coolant/valve.hpp"
|
||||
#include "../input/focus.hpp"
|
||||
#include "../../util/streams.hpp"
|
||||
#include "../data/font.hpp"
|
||||
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <iostream>
|
||||
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "../input/focus.hpp"
|
||||
#include "../../util/streams.hpp"
|
||||
#include "../../util/math.hpp"
|
||||
#include "../data/font.hpp"
|
||||
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <iostream>
|
||||
|
@ -69,13 +70,11 @@ void Turbine::get_static_transforms(std::vector<glm::mat4>& 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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "../../reactor/control/boron_rod.hpp"
|
||||
#include "../../system.hpp"
|
||||
#include "../../util/streams.hpp"
|
||||
#include "../data/font.hpp"
|
||||
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <sstream>
|
||||
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <format>
|
||||
|
||||
#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<std::string> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <GL/glew.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
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();
|
||||
|
||||
|
|
|
@ -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";
|
|
@ -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";
|
|
@ -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";
|
|
@ -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";
|
|
@ -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";
|
|
@ -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"
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
#include <stb/stb_rect_pack.h>
|
||||
|
|
@ -48,5 +48,11 @@ constexpr A mod(A a, auto b)
|
|||
return v;
|
||||
}
|
||||
|
||||
template <typename A>
|
||||
constexpr A ramp(A v, auto imin, auto imax, auto omin, auto omax)
|
||||
{
|
||||
return clamp(map(v, imin, imax, omin, omax), omin, omax);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue