Compare commits

...

7 Commits

Author SHA1 Message Date
Jay Robson 2d69bb3c78 add texture atlas for gpus without bindless textures 2024-03-22 01:12:48 +11:00
Jay Robson e2b16e0591 improvements to renderer 2024-03-21 01:45:08 +11:00
Jay Robson c85984fc7f added cameras 2024-03-18 21:57:06 +11:00
Jay Robson ddec7eeb9d add optimisations 2024-03-17 13:07:44 +11:00
Jay Robson 25861bbf16 more models 2024-03-16 23:36:00 +11:00
Jay Robson e2f8eefe5b improved how model matrices are done 2024-03-06 22:32:54 +11:00
Jay Robson 1b317e9ff6 more dials, better models 2024-03-03 22:50:13 +11:00
96 changed files with 2671 additions and 1369 deletions

Binary file not shown.

BIN
assets/scene.blend (Stored with Git LFS)

Binary file not shown.

BIN
assets/scene.glb (Stored with Git LFS)

Binary file not shown.

View File

@ -1,26 +0,0 @@
#version 460 core
uniform int samples;
uniform sampler2D tex;
in vec2 texPos;
out vec4 FragColour;
void main()
{
vec2 texel_size = 1.f / vec2(textureSize(tex, 0));
float samples_n = pow(samples * 2 + 1, 2);
vec4 colour;
for(int x = -samples; x <= samples; x++)
for(int y = -samples; y <= samples; y++)
{
vec2 off = texel_size * vec2(x, y);
colour += texture2D(tex, texPos + off);
}
FragColour = vec4((colour / samples_n).rgb, 1);
}

View File

@ -1,14 +0,0 @@
#version 460 core
layout (location = 1) in vec2 aTexPos;
layout (location = 2) in vec4 aPos;
out vec2 texPos;
void main()
{
texPos = aTexPos;
gl_Position = aPos;
}

View File

@ -1,19 +0,0 @@
#version 460 core
layout (location = 2) in vec4 aPos;
layout (location = 4) in vec4 aColour;
layout (location = 5) in vec3 aMaterial;
layout (location = 6) in float aTransformIndex;
uniform mat4 model;
uniform mat4 camera;
out flat int should_ignore;
void main()
{
gl_Position = camera * model * aPos;
should_ignore = int(aTransformIndex >= 0.f || aMaterial[2] > 0.f || aColour.a < 1.f);
}

View File

@ -1,47 +0,0 @@
#version 460 core
#extension GL_ARB_bindless_texture : require
layout (location = 0) in sampler2D aTex;
layout (location = 1) in vec2 aTexPos;
layout (location = 2) in vec4 aPos;
layout (location = 3) in vec3 aNormal;
layout (location = 4) in vec4 aColour;
layout (location = 5) in vec3 aMaterial;
layout (location = 6) in float aTransformIndex;
uniform mat4 model;
uniform mat4 camera;
uniform mat4 projection;
layout (binding = 3) readonly buffer TransformBuffer
{
mat4 transforms[];
};
out VS_OUT {
vec3 normal;
vec4 colour;
vec3 pos;
vec2 tex_pos;
vec3 material;
} vout;
out flat sampler2D frag_tex;
void main()
{
mat4 m = (aTransformIndex >= 0.f ? transforms[int(aTransformIndex)] : mat4(1.f)) * model;
mat4 mvp = camera * m;
vec4 pos = mvp * aPos;
vout.normal = mat3(m) * aNormal;
vout.pos = (m * aPos).xyz;
vout.colour = aColour;
vout.tex_pos = aTexPos;
vout.material = aMaterial;
frag_tex = aTex;
gl_Position = projection * pos;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -14,18 +14,20 @@ constexpr static double calc_cylinder(double h, double d)
return M_PI * r * r * h * 1000;
}
Evaporator::Evaporator(Fluid type, double height, double diameter, double mass, double level) :
height(height),
diameter(diameter),
FluidHolder(type, calc_cylinder(height, diameter), mass)
Evaporator::Evaporator(Fluid type, double volume, double mass, double level)
: FluidHolder(type, volume, mass)
{
this->level = level;
}
Evaporator::Evaporator(const Json::Value& node) :
height(node["height"].asDouble()),
diameter(node["diameter"].asDouble()),
FluidHolder(node)
Evaporator::Evaporator(Fluid type, double height, double diameter, double mass, double level)
: FluidHolder(type, calc_cylinder(height, diameter), mass)
{
this->level = level;
}
Evaporator::Evaporator(const Json::Value& node)
: FluidHolder(node)
{
steam_output = node["steam_output"].asDouble();
}
@ -70,8 +72,6 @@ Evaporator::operator Json::Value() const
{
Json::Value node(FluidHolder::operator::Json::Value());
node["height"] = height;
node["diameter"] = diameter;
node["steam_output"] = steam_output;
return node;

View File

@ -8,13 +8,11 @@ namespace Sim::Coolant
class Evaporator : public FluidHolder
{
const double height;
const double diameter;
double steam_output = 0;
public:
Evaporator(Fluid type, double volume, double mass, double level);
Evaporator(Fluid type, double height, double diameter, double mass, double level);
Evaporator(const Json::Value& node);

35
src/coolant/pool.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "pool.hpp"
using namespace Sim::Coolant;
Pool::Pool(const Json::Value& node)
: Evaporator(node)
, dimensions(node["dimensions"]["x"].asDouble(), node["dimensions"]["y"].asDouble(), node["dimensions"]["z"].asDouble())
{
}
Pool::Pool(Fluid fluid, const glm::vec3& dimensions, double heat, double mass, double level)
: Evaporator(fluid, dimensions.x * dimensions.y * dimensions.z * 1000, mass, level)
, dimensions(dimensions)
{
this->heat = heat;
this->level = level;
}
Pool::operator Json::Value() const
{
Json::Value node = Evaporator::operator Json::Value();
node["dimensions"]["x"] = dimensions.x;
node["dimensions"]["y"] = dimensions.y;
node["dimensions"]["z"] = dimensions.z;
return node;
}
double Pool::get_level_height() const
{
double ratio = level / volume;
return dimensions.z * ratio;
}

23
src/coolant/pool.hpp Normal file
View File

@ -0,0 +1,23 @@
#include "evaporator.hpp"
#include <glm/vec3.hpp>
namespace Sim::Coolant
{
class Pool : public Evaporator
{
public:
const glm::vec3 dimensions;
Pool(Fluid fluid, const glm::vec3& dimensions, double temperature, double mass, double level);
Pool(const Json::Value& node);
operator Json::Value() const;
double get_level_height() const;
};
};

View File

@ -33,7 +33,7 @@ void Generator::update(double dt)
double energy_input = turbine->extract_energy();
double energy_friction = get_rpm() / 60 * dt * friction;
double work = Util::Math::j_to_ms2(energy_input - energy_friction, mass);
phase = std::fmod(phase + Util::Math::map( get_rpm(), 0, 3600, 0, 120 * M_PI ) * dt, 2 * M_PI);
phase = std::fmod(phase + Util::Math::map( get_rpm(), 0, 3600, 0, 120 * M_PI ) * dt, 4 * M_PI);
// do energy transfer stuff here
if(breaker_closed)
@ -121,6 +121,22 @@ double Generator::get_phase_diff() const
return Util::Math::mod(phase - grid->get_phase() + M_PI, 2*M_PI) - M_PI;
}
double Generator::get_frequency() const
{
return get_rpm() / 60;
}
double Generator::get_power() const
{
return energy_generated;
}
double Generator::get_voltage() const
{
// TODO: implement this
return get_frequency() / 60 * 20e3;
}
Generator::operator Json::Value() const
{
Json::Value node;

View File

@ -34,11 +34,13 @@ public:
void update(double dt);
double get_rpm() const;
double get_frequency() const;
double get_power() const;
double get_voltage() const;
double get_phase_diff() const;
operator Json::Value() const;
constexpr double get_energy_generated() const { return energy_generated; }
constexpr double get_phase() const { return phase; }
};

View File

@ -3,7 +3,7 @@
#include <GLFW/glfw3.h>
#include "camera.hpp"
#include "mesh/mesh.hpp"
#include "data/mesh.hpp"
#include "input/keyboard.hpp"
#include "../util/math.hpp"
@ -19,7 +19,7 @@ static bool on_ground = false;
static double yaw = 0, pitch = 0;
static glm::vec<3, double> pos(0, 0, 2);
static glm::vec<3, double> velocity(0);
static Mesh collision_scene;
static Data::Mesh collision_scene;
static glm::mat4 camera_mat;
Json::Value Camera::serialize()
@ -79,7 +79,12 @@ glm::vec<3, double> Camera::get_pos()
return pos;
}
void Camera::init(const Model& model)
glm::vec<3, double> Camera::get_pos_base()
{
return pos - glm::vec<3, double>(0, 0, 1.5);
}
void Camera::init(const Data::Model& model)
{
collision_scene = model.load("collision");
}

View File

@ -5,13 +5,14 @@
#include <json/json.h>
#include "../system.hpp"
#include "mesh/model.hpp"
#include "data/model.hpp"
namespace Sim::Graphics::Camera
{
glm::vec<3, double> get_normal();
glm::vec<3, double> get_pos();
glm::vec<3, double> get_pos_base();
glm::mat4 get_matrix();
double get_pitch();
double get_yaw();
@ -19,7 +20,7 @@ double get_yaw();
Json::Value serialize();
void load(const Json::Value& node);
void init(const Model& model);
void init(const Data::Model& model);
void rotate(double pitch, double yaw);
void move(double x, double y, double z);
void update(double dt);

View File

@ -0,0 +1,70 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <assimp/Importer.hpp>
#include "../shader.hpp"
#include "../../util/streams.hpp"
#include "arrays.hpp"
#include "font.hpp"
using namespace Sim::Graphics::Data;
static void* ptr_diff(void* a, void* b)
{
return (void*)((size_t)a - (size_t)b);
}
void Arrays::vertex_attrib_pointers()
{
Vertex v;
glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(v), ptr_diff(&v.texpos, &v));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, false, sizeof(v), ptr_diff(&v.pos, &v));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 4, GL_FLOAT, false, sizeof(v), ptr_diff(&v.colour, &v));
glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 3, GL_FLOAT, true, sizeof(v), ptr_diff(&v.tbn[0], &v));
glEnableVertexAttribArray(3);
glVertexAttribPointer(4, 3, GL_FLOAT, true, sizeof(v), ptr_diff(&v.tbn[1], &v));
glEnableVertexAttribArray(4);
glVertexAttribPointer(5, 3, GL_FLOAT, true, sizeof(v), ptr_diff(&v.tbn[2], &v));
glEnableVertexAttribArray(5);
glVertexAttribPointer(6, 3, GL_FLOAT, false, sizeof(v), ptr_diff(&v.material, &v));
glEnableVertexAttribArray(6);
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_diffuse, &v));
glEnableVertexAttribArray(8);
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)
{
os << "Vertex{";
os << "texpos=" << v.texpos << ", ";
os << "pos=" << v.pos << ", ";
os << "colour=" << v.colour << ", ";
os << "tbn=" << v.tbn << ", ";
os << "transform_id=" << v.transform_id << ", ";
os << "tex_diffuse=" << v.tex_diffuse << ", ";
os << "tex_normal=" << v.tex_normal << ", ";
os << "material=" << v.material;
os << "}";
return os;
}

View File

@ -0,0 +1,32 @@
#pragma once
#include "texture.hpp"
#include <glm/matrix.hpp>
#include <ostream>
namespace Sim::Graphics::Data::Arrays
{
struct Vertex
{
glm::vec2 texpos = {0, 0};
glm::vec3 pos = {0, 0, 0};
glm::vec4 colour = {1, 1, 1, 1};
glm::mat3 tbn = glm::mat3(1);
int transform_id = -1;
unsigned int tex_diffuse = Texture::handle_white;
unsigned int tex_normal = Texture::handle_normal;
glm::vec3 material = {0.5, 0, 0};
constexpr bool operator==(const Vertex&) const = default;
friend std::ostream& operator<<(std::ostream& os, const Vertex& v);
};
void vertex_attrib_pointers();
};

138
src/graphics/data/atlas.hpp Normal file
View File

@ -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);
}
}
};
};

View File

@ -0,0 +1,24 @@
#pragma once
#include <glm/matrix.hpp>
#include <string>
namespace Sim::Graphics::Data
{
struct Camera
{
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;
float zoom = 1;
};
};

181
src/graphics/data/font.cpp Normal file
View File

@ -0,0 +1,181 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#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;
Font Fonts::BASE;
Font Fonts::MONO;
void Fonts::init()
{
BASE.init("DroidSans", 64);
MONO.init("DroidSansMono", 64);
}
void Font::init(const std::string& name, int size)
{
FT_Library ft;
FT_Face face;
if(FT_Init_FreeType(&ft))
{
std::cout << "Error: failed to init freetype\n";
return;
}
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;
}
texel_size = 1.0f / size;
FT_Set_Pixel_Sizes(face, 0, size);
for(int i = 0; i < 128; i++)
{
if(FT_Load_Char(face, (char)i, FT_LOAD_RENDER))
{
std::cout << "Error: failed to load glyph " << i << "\n";
}
int width = face->glyph->bitmap.width;
int height = face->glyph->bitmap.rows;
int offx = face->glyph->bitmap_left;
int offy = face->glyph->bitmap_top;
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)
{
continue;
}
std::vector<uint8_t> buffer(width * height);
for(int i = 0; i < width * height; i++)
{
buffer[i] = face->glyph->bitmap.buffer[i];
}
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);
}
Font::Font()
{
}
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;
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];
const Character& ch = characters[c];
if(c == '\n')
{
x = 0;
y += size;
continue;
}
if(ch.handle == 0)
{
x += ch.advance * size;
continue;
}
unsigned int index[6] = {
at, at + 1, at + 3,
at, at + 3, at + 2
};
float sx = x + ch.bearing.x * size;
float sy = y - ch.bearing.y * size;
float ex = sx + ch.size.x * size;
float ey = sy + ch.size.y * size;
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;
}
return m;
}
Mesh Font::load_text(const std::string& text, float size, glm::vec2 align) const
{
glm::vec2 max;
Mesh m = load_text(text, size);
for(Arrays::Vertex& v : m.vertices)
{
if(v.pos.x > max.x)
{
max.x = v.pos.x;
}
if(v.pos.y > max.y)
{
max.y = v.pos.y;
}
}
align *= max;
for(Arrays::Vertex& v : m.vertices)
{
v.pos.x -= align.x;
v.pos.y -= align.y;
}
return m;
}

View File

@ -0,0 +1,61 @@
#pragma once
#include "mesh.hpp"
#include <string>
#include <sstream>
#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;
}
};

View File

View File

@ -0,0 +1,88 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "gllights.hpp"
#include "../shader.hpp"
#include "../window.hpp"
#include "texture.hpp"
#include <glm/ext/matrix_transform.hpp>
#include <glm/ext/matrix_clip_space.hpp>
using namespace Sim::Graphics::Data;
static glm::mat4 shadow_mats[6];
GLLights::GLLights(std::vector<Light>&& _lights) : lights(_lights), size(1024)
{
glGenTextures(1, &texid);
glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, texid);
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_DEPTH_COMPONENT, size, size, 6 * lights.size(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texid, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(Light) * lights.size(), lights.data(), GL_STATIC_COPY);
}
GLLights::GLLights(GLLights&& o) : lights(o.lights), size(o.size)
{
texid = o.texid;
fbo = o.fbo;
o.texid = 0;
o.fbo = 0;
}
GLLights::~GLLights()
{
if(fbo)
glDeleteFramebuffers(1, &fbo);
if(texid)
glDeleteTextures(1, &texid);
}
void GLLights::render()
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glViewport(0, 0, size, size);
Window::bind_scene_ssbo();
for(int i = 0; i < lights.size(); i++)
{
glUniform3fv(Shader::LIGHT["light_pos"], 1, &lights[i].pos[0]);
glUniform1i(Shader::LIGHT["light_pass"], i);
Window::render_scene();
}
}
void GLLights::init()
{
glm::mat4 shadow_proj = glm::perspective<float>(M_PI * 0.5f, 1.0f, 0.01f, 100.f);
shadow_mats[0] = shadow_proj * glm::lookAt(glm::vec3(0), { 1, 0, 0}, {0,-1, 0});
shadow_mats[1] = shadow_proj * glm::lookAt(glm::vec3(0), {-1, 0, 0}, {0,-1, 0});
shadow_mats[2] = shadow_proj * glm::lookAt(glm::vec3(0), { 0, 1, 0}, {0, 0, 1});
shadow_mats[3] = shadow_proj * glm::lookAt(glm::vec3(0), { 0,-1, 0}, {0, 0,-1});
shadow_mats[4] = shadow_proj * glm::lookAt(glm::vec3(0), { 0, 0, 1}, {0,-1, 0});
shadow_mats[5] = shadow_proj * glm::lookAt(glm::vec3(0), { 0, 0,-1}, {0,-1, 0});
glUniformMatrix4fv(Shader::LIGHT["shadow_mats"], 6, false, &shadow_mats[0][0][0]);
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <vector>
#include "light.hpp"
namespace Sim::Graphics::Data
{
struct GLLights
{
const int size;
unsigned int texid, fbo, ssbo;
std::vector<Light> lights;
GLLights(std::vector<Light>&& lights);
GLLights(GLLights&& o);
GLLights(const GLLights& o) = delete;
~GLLights();
static void init();
void render();
};
};

View File

@ -6,8 +6,9 @@
#include "arrays.hpp"
#include "../shader.hpp"
#include "../camera.hpp"
#include "../../util/streams.hpp"
using namespace Sim::Graphics;
using namespace Sim::Graphics::Data;
constexpr static void init(GLMesh* m)
{
@ -32,18 +33,22 @@ GLMesh::GLMesh(GLMesh&& o)
vbo = o.vbo;
ebo = o.ebo;
vao = o.vao;
size = o.size;
model_matrix = o.model_matrix;
ssbo = o.ssbo;
o.vbo = 0;
o.ebo = 0;
o.vao = 0;
o.ssbo = 0;
size = o.size;
ssbo_size = o.ssbo_size;
}
GLMesh::~GLMesh()
{
if(vbo) glDeleteBuffers(1, &vbo);
if(ebo) glDeleteBuffers(1, &ebo);
if(ssbo) glDeleteBuffers(1, &ssbo);
if(vao) glDeleteVertexArrays(1, &vao);
}
@ -54,9 +59,15 @@ void GLMesh::bind()
glBindVertexArray(vao);
}
void GLMesh::uniform()
void GLMesh::bind_ssbo()
{
glUniformMatrix4fv(Shader::ACTIVE->get("model"), 1, false, &model_matrix[0][0]);
if(!ssbo)
{
glGenBuffers(1, &ssbo);
}
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo);
}
void GLMesh::set(const Mesh& m, int mode)
@ -65,7 +76,9 @@ void GLMesh::set(const Mesh& m, int mode)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ARRAY_BUFFER, m.vertices.size() * sizeof(m.vertices[0]), &m.vertices[0], mode);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m.indices.size() * sizeof(m.indices[0]), &m.indices[0], mode);
this->size = m.indices.size();
this->ssbo_size = m.transforms.size();
}
void GLMesh::render()

View File

@ -8,14 +8,14 @@
#include <glm/matrix.hpp>
namespace Sim::Graphics
namespace Sim::Graphics::Data
{
struct GLMesh
{
unsigned int vao = 0, vbo = 0, ebo = 0, size = 0;
glm::mat4 model_matrix {1.0f};
unsigned int vao = 0, vbo = 0, ebo = 0, ssbo = 0;
int ssbo_size = 0;
int size = 0;
constexpr GLMesh() { }
@ -24,7 +24,7 @@ struct GLMesh
~GLMesh();
void bind();
void uniform();
void bind_ssbo();
void set(const Mesh& m, int mode);
void render(int type);
void render();

View File

@ -3,7 +3,7 @@
#include <glm/matrix.hpp>
namespace Sim::Graphics
namespace Sim::Graphics::Data
{
struct Light

View File

@ -0,0 +1,27 @@
#pragma once
#include <glm/vec4.hpp>
namespace Sim::Graphics::Data
{
struct Material
{
uint32_t diffuse = Texture::handle_white;
uint32_t normal = Texture::handle_normal;
glm::vec4 colour = {1, 1, 1, 1};
float roughness = 0.5;
float metalness = 0;
float luminance = 0;
// float padding = 0;
/* static void init();
static int create(Material m);
static void destroy(int id);
static Material get(int id);
static void sync();*/
};
};

View File

@ -5,81 +5,143 @@
#include "../camera.hpp"
#include "../input/focus.hpp"
#include "../../util/math.hpp"
#include "../../util/streams.hpp"
#include <iostream>
using namespace Sim::Graphics;
using namespace Sim::Graphics::Data;
Mesh::Mesh()
{
}
void Mesh::set_transform_id()
Mesh& Mesh::set_diffuse_id(unsigned int id)
{
for(unsigned int i = 0; i < vertices.size(); i++)
{
vertices[i].tex_diffuse = id;
}
return *this;
}
Mesh& Mesh::set_normal_id(unsigned int id)
{
for(unsigned int i = 0; i < vertices.size(); i++)
{
vertices[i].tex_normal = id;
}
return *this;
}
Mesh& Mesh::set_blank_transform()
{
transforms = {glm::mat4(1)};
for(unsigned int i = 0; i < vertices.size(); i++)
{
vertices[i].transform_id = 0;
}
max_transform_id = 0;
return *this;
}
void Mesh::add(const Mesh& o, glm::mat4 mat)
Mesh& Mesh::add(const Mesh& o, glm::mat4 mat, bool bake)
{
unsigned int off = vertices.size();
float t_off = max_transform_id + 1;
int off = vertices.size();
glm::mat3 mat3(mat);
vertices.reserve(vertices.size() + o.vertices.size());
indices.reserve(indices.size() + o.indices.size());
vertices.reserve(vertices.size() + o.vertices.size());
for(unsigned int i = 0; i < o.vertices.size(); i++)
if(bake)
{
for(int i = 0; i < o.vertices.size(); i++)
{
Arrays::Vertex v = o.vertices[i];
int t_id = v.transform_id;
glm::mat4 t_mat = t_id >= 0 ? transforms[t_id] : glm::mat4(1);
t_mat = mat * t_mat;
v.pos = t_mat * glm::vec4(v.pos, 1);
v.tbn = glm::mat3(t_mat) * v.tbn;
v.transform_id = -1;
vertices.push_back(v);
}
for(int i = 0; i < o.indices.size(); i++)
{
indices.push_back(o.indices[i] + off);
}
return *this;
}
glm::mat3 mat3(mat);
int t_off = transforms.size();
int t_new = -1;
if(mat != glm::mat4(1))
{
t_new = transforms.size() + o.transforms.size();
}
transforms.reserve(transforms.size() + o.transforms.size() + (t_new >= 0 ? 1 : 0));
for(int i = 0; i < o.vertices.size(); i++)
{
Arrays::Vertex v = o.vertices[i];
v.normal = mat3 * v.normal;
v.pos = mat * v.pos;
if(v.transform_id >= 0)
{
v.transform_id += t_off;
max_transform_id = std::max(max_transform_id, v.transform_id);
}
else
{
v.transform_id = t_new;
}
vertices.push_back(v);
}
for(unsigned int i = 0; i < o.indices.size(); i++)
for(int i = 0; i < o.transforms.size(); i++)
{
transforms.push_back(o.transforms[i] * mat);
}
for(int i = 0; i < o.indices.size(); i++)
{
indices.push_back(o.indices[i] + off);
}
if(t_new >= 0)
{
transforms.push_back(mat);
}
void Mesh::add(const Mesh& o)
{
add(o, glm::mat4(1));
return *this;
}
void Mesh::set_vertices(const Arrays::Vertex* data, size_t size)
Mesh& Mesh::bake_transforms()
{
vertices.clear();
vertices.reserve(size);
for(unsigned int i = 0; i < vertices.size(); i++)
{
int id = vertices[i].transform_id;
for(unsigned int i = 0; i < size; i++)
if(id >= 0)
{
vertices.push_back(data[i]);
glm::mat4 transform = transforms[id];
vertices[i].pos = glm::vec3(transform * glm::vec4(vertices[i].pos, 1));
vertices[i].tbn = glm::mat3(transform) * vertices[i].tbn;
vertices[i].transform_id = -1;
}
}
void Mesh::set_indices(const unsigned int* data, size_t size)
{
indices.clear();
indices.reserve(size);
transforms.clear();
for(unsigned int i = 0; i < size; i++)
{
indices.push_back(data[i]);
}
return *this;
}
typedef glm::vec<3, double> vec3;
@ -126,15 +188,28 @@ bool ray_intersects_triangle(vec3 ray_origin,
bool Mesh::check_focus(double len) const
{
if(!Focus::is_triggered())
{
return false;
}
auto near = Focus::get_trigger_near();
auto far = Focus::get_trigger_far();
return Focus::is_triggered() && check_intersect(near, glm::normalize(far - near) * len);
return check_intersect(near, glm::normalize(far - near) * len);
}
bool Mesh::check_focus() const
bool Mesh::check_focus_hold(double len)
{
return check_focus(2.5);
if(!Focus::is_triggered() && (!focus || Focus::is_triggered_release()))
{
return focus = false;
}
auto near = Focus::get_trigger_near();
auto far = Focus::get_trigger_far();
return focus = check_intersect(near, glm::normalize(far - near) * len);
}
bool Mesh::check_intersect(vec3 pos, vec3 path) const
@ -150,12 +225,22 @@ bool Mesh::check_intersect(vec3 pos, vec3 path) const
for(unsigned int i = 0; i < indices.size(); i += 3)
{
vec3 v[3] = {
vec3(this->vertices[indices[i]].pos),
vec3(this->vertices[indices[i + 1]].pos),
vec3(this->vertices[indices[i + 2]].pos)
Arrays::Vertex verts[3] = {
vertices[indices[i]],
vertices[indices[i + 1]],
vertices[indices[i + 2]]
};
vec3 v[3];
for(int j = 0; j < 3; j++)
{
int t_id = verts[j].transform_id;
glm::mat4 t_mat = t_id >= 0 ? transforms[t_id] : glm::mat4(1);
v[j] = vec3(t_mat * glm::vec4(verts[j].pos, 1));
}
vec3 ipoint;
vec3 normal = glm::normalize(glm::cross(v[1] - v[0], v[2] - v[0]));
double d = glm::dot(normal, path);
@ -218,12 +303,22 @@ vec3 Mesh::calc_intersect(vec3 pos, vec3 path) const
for(unsigned int i = 0; i < indices.size(); i += 3)
{
vec3 v[3] = {
vec3(this->vertices[indices[i]].pos),
vec3(this->vertices[indices[i + 1]].pos),
vec3(this->vertices[indices[i + 2]].pos)
Arrays::Vertex verts[3] = {
vertices[indices[i]],
vertices[indices[i + 1]],
vertices[indices[i + 2]]
};
vec3 v[3];
for(int j = 0; j < 3; j++)
{
int t_id = verts[j].transform_id;
glm::mat4 t_mat = t_id >= 0 ? transforms[t_id] : glm::mat4(1);
v[j] = vec3(t_mat * glm::vec4(verts[j].pos, 1));
}
if(calc_intercept_vert(v, pos, path, path_n, l))
{
changing = true;
@ -257,4 +352,33 @@ Mesh Mesh::to_lines() const
return m;
}
std::ostream& Sim::Graphics::Data::operator<<(std::ostream& os, const Mesh& m)
{
os << "Mesh(\n";
os << " Vertices(\n";
for(int i = 0; i < m.vertices.size(); i++)
{
os << " " << m.vertices[i] << "\n";
}
os << " )\n";
for(int i = 0; i < m.indices.size(); i += 3)
{
os << " " << m.indices[i] << " " << m.indices[i + 1] << " " << m.indices[i + 2] << "\n";
}
os << " Transforms(\n";
for(int i = 0; i < m.transforms.size(); i++)
{
os << " " << m.transforms[i] << "\n";
}
os << " )\n";
os << ")\n";
return os;
}

View File

@ -0,0 +1,45 @@
#pragma once
#include <string>
#include <sstream>
#include <unordered_map>
#include <string>
#include <vector>
#include <glm/matrix.hpp>
#include "arrays.hpp"
#include "light.hpp"
namespace Sim::Graphics::Data
{
struct Mesh
{
std::vector<Arrays::Vertex> vertices;
std::vector<unsigned int> indices;
std::vector<glm::mat4> transforms;
bool focus = false;
Mesh();
Mesh& bake_transforms();
Mesh& set_blank_transform();
Mesh& set_normal_id(unsigned int id);
Mesh& set_diffuse_id(unsigned int id);
Mesh& add(const Mesh& o, glm::mat4 mat = glm::mat4(1), bool bake = false);
Mesh to_lines() const;
bool check_focus(double len = 2.5) const;
bool check_focus_hold(double len = 2.5);
bool check_intersect(glm::vec<3, double> pos, glm::vec<3, double> path) const;
glm::vec<3, double> calc_intersect(glm::vec<3, double> pos, glm::vec<3, double> path) const;
bool operator==(const Mesh&) const = default;
friend std::ostream& operator<<(std::ostream& os, const Mesh& m);
};
};

View File

@ -1,9 +1,9 @@
#pragma once
#include "../mesh/model.hpp"
#include "model.hpp"
namespace Sim::Graphics
namespace Sim::Graphics::Data
{
class MeshGen

View File

@ -6,6 +6,7 @@
#include <unordered_map>
#include <iostream>
#include <sstream>
#include <vector>
#include "mesh.hpp"
@ -14,7 +15,7 @@
#include "model.hpp"
#include "../../util/streams.hpp"
using namespace Sim::Graphics;
using namespace Sim::Graphics::Data;
struct ProcState
{
@ -23,107 +24,18 @@ struct ProcState
std::string base;
std::vector<Arrays::Vertex> vertices;
std::vector<unsigned int> indices;
std::unordered_map<const aiTexture*, unsigned int> handles;
std::vector<glm::mat4> transforms;
const std::vector<Material>& materials;
};
static unsigned int proc_texture(const ProcState& state, aiMaterial* mat, const aiScene* scene, aiTextureType type, int index)
static void proc_mesh(ProcState& state, aiMesh* mesh, const aiScene* scene)
{
aiString str;
mat->GetTexture(type, index, &str);
if(str.C_Str()[0] == '\0')
{
return 0;
}
const aiTexture* tex = scene->GetEmbeddedTexture(str.C_Str());
if(tex != nullptr)
{
unsigned int handle = state.handles.find(tex)->second;
std::cout << "Using preloaded texture: " << tex->mFilename.C_Str() << "\n";
return handle;
}
std::string filename(str.C_Str());
std::replace(filename.begin(), filename.end(), '\\', '/');
return Texture::load(state.base + "/" + filename);
}
static void proc_mesh(ProcState& state, glm::mat4 mat, aiMesh* mesh, const aiScene* scene)
{
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
aiString name;
material->Get(AI_MATKEY_NAME, name);
/*
std::cout << "Material " << name.C_Str() << " has " << material->mNumProperties << " properties\n";
for(int i = 0; i < material->mNumProperties; i++)
{
aiMaterialProperty* prop = material->mProperties[i];
std::cout << " " << prop->mKey.C_Str() << ": type=" << prop->mType << " index=" << prop->mIndex << " length=" << prop->mDataLength;
if(prop->mType == 1)
{
float* v = (float*)prop->mData;
std::cout << " value=";
switch(prop->mDataLength)
{
case 4:
std::cout << v[0];
break;
case 8:
std::cout << "{" << v[0] << ", " << v[1] << "}";
break;
case 12:
std::cout << "{" << v[0] << ", " << v[1] << ", " << v[2] << "}";
break;
case 16:
std::cout << "{" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << "}";
break;
default:
std::cout << "unknown";
}
}
std::cout << "\n";
}*/
glm::vec3 matv(0);
aiColor4D ai_cb;
aiColor4D ai_em;
material->Get(AI_MATKEY_ROUGHNESS_FACTOR, matv[0]);
material->Get(AI_MATKEY_METALLIC_FACTOR, matv[1]);
material->Get(AI_MATKEY_EMISSIVE_INTENSITY, matv[2]);
material->Get(AI_MATKEY_COLOR_EMISSIVE, ai_em);
material->Get(AI_MATKEY_BASE_COLOR, ai_cb);
glm::vec4 cb = {ai_cb[0], ai_cb[1], ai_cb[2], ai_cb[3]};
glm::vec4 em = {ai_em[0], ai_em[1], ai_em[2], ai_em[3]};
if(em.x > 0 || em.y > 0 || em.z > 0)
{
cb = em;
}
unsigned int handle = proc_texture(state, material, scene, aiTextureType_BASE_COLOR, 0);
Material mat = state.materials[mesh->mMaterialIndex];
unsigned int offset = state.offset;
glm::mat3 mat3(mat);
if(!handle)
if(!mesh->HasNormals())
{
handle = proc_texture(state, material, scene, aiTextureType_DIFFUSE, 0);
}
if(!handle)
{
handle = Texture::handle_white;
throw std::runtime_error("Mesh has no normals");
}
for(unsigned int i = 0; i < mesh->mNumVertices; i++)
@ -131,24 +43,12 @@ static void proc_mesh(ProcState& state, glm::mat4 mat, aiMesh* mesh, const aiSce
Arrays::Vertex vertex;
auto [x, y, z] = mesh->mVertices[i];
vertex.pos = glm::vec4(x, y, z, 1) * mat;
vertex.material = matv;
vertex.texid = handle;
vertex.colour = cb;
if(mesh->HasNormals())
{
auto [x, y, z] = mesh->mNormals[i];
vertex.normal = glm::vec3(x, y, z) * mat3;
}
/*if(mesh->HasTangentsAndBitangents())
{
auto [x1, y1, z1] = mesh->mTangents[i];
auto [x2, y2, z2] = mesh->mBitangents[i];
vertex.tangent = {x1, y1, z1};
vertex.bitangent = {x2, y2, z2};
}*/
vertex.transform_id = state.transforms.size();
vertex.pos = glm::vec3(x, y, z);
vertex.colour = mat.colour;
vertex.tex_diffuse = mat.diffuse;
vertex.tex_normal = mat.normal;
vertex.material = {mat.roughness, mat.metalness, mat.luminance};
if(mesh->mTextureCoords[0])
{
@ -156,6 +56,30 @@ static void proc_mesh(ProcState& state, glm::mat4 mat, aiMesh* mesh, const aiSce
vertex.texpos = {x, y};
}
if(mesh->HasTangentsAndBitangents())
{
auto [x1, y1, z1] = mesh->mTangents[i];
auto [x2, y2, z2] = mesh->mBitangents[i];
auto [x3, y3, z3] = mesh->mNormals[i];
vertex.tbn = {
{x1, y1, z1},
{x2, y2, z2},
{x3, y3, z3},
};
}
else
{
auto [x, y, z] = mesh->mNormals[i];
glm::vec3 normal = {x, y, z};
glm::vec3 tangent = glm::normalize(glm::cross(normal, {-y, z, x}));
glm::vec3 bitangent = glm::normalize(glm::cross(normal, tangent));
vertex.tbn = {tangent, bitangent, normal};
}
state.vertices.push_back(vertex);
}
@ -175,10 +99,10 @@ static void proc_mesh(ProcState& state, glm::mat4 mat, aiMesh* mesh, const aiSce
glm::mat4 convert_mat(aiMatrix4x4 m)
{
return {
m.a1, m.a2, m.a3, m.a4,
m.b1, m.b2, m.b3, m.b4,
m.c1, m.c2, m.c3, m.c4,
m.d1, m.d2, m.d3, m.d4
m.a1, m.b1, m.c1, m.d1,
m.a2, m.b2, m.c2, m.d2,
m.a3, m.b3, m.c3, m.d3,
m.a4, m.b4, m.c4, m.d4
};
}
@ -207,7 +131,12 @@ static void proc_node(ProcState& state, glm::mat4 mat, aiNode* node, const aiSce
for(size_t i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
proc_mesh(state, mat, mesh, scene);
proc_mesh(state, mesh, scene);
}
if(node->mNumMeshes > 0)
{
state.transforms.push_back(mat);
}
}
@ -217,7 +146,7 @@ static void proc_node(ProcState& state, glm::mat4 mat, aiNode* node, const aiSce
}
}
static unsigned int proc_embedded_texture(aiTexture* tex)
static uint64_t proc_embedded_texture(aiTexture* tex)
{
std::cout << "Loading embedded data: " << tex->mFilename.C_Str() << "\n";
@ -252,50 +181,138 @@ glm::mat4 get_transforms(const aiNode* node)
return mat;
}
glm::mat4 Model::get_matrix(const char* name) const
glm::mat4 Model::load_matrix(const char* name) const
{
return get_transforms(scene->mRootNode->FindNode(name));
}
static uint32_t proc_texture(
const std::string& path_base,
aiMaterial* mat,
const aiScene* scene,
aiTextureType type,
int index,
uint64_t handle_fail=0)
{
aiString str;
mat->GetTexture(type, index, &str);
if(str.C_Str()[0] == '\0')
{
return handle_fail;
}
std::string filename(str.C_Str());
std::replace(filename.begin(), filename.end(), '\\', '/');
return Texture::load(path_base + "/" + filename);
}
Model::Model(std::string base, std::string filename) : base(base)
{
std::string path = base + "/" + filename;
scene = importer.ReadFile(path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs);
scene = importer.ReadFile(path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
textures.reserve(scene->mNumTextures);
materials.reserve(scene->mNumMaterials);
for(int i = 0; i < scene->mNumTextures; i++)
{
aiTexture* tex = scene->mTextures[i];
unsigned int handle = proc_embedded_texture(tex);
uint64_t handle = proc_embedded_texture(tex);
textures.push_back(handle);
}
for(int i = 0; i < scene->mNumLights; i++)
{
aiLight* light = scene->mLights[i];
glm::mat4 mat = get_matrix(light->mName.C_Str());
glm::mat4 mat = load_matrix(light->mName.C_Str());
auto [x, y, z] = light->mPosition;
auto [r, g, b] = light->mColorDiffuse;
glm::vec4 pos = glm::vec4(x, y, z, 1) * mat;
glm::vec4 pos = mat * glm::vec4(x, y, z, 1);
lights.push_back({
glm::vec3(pos),
{r, g, b},
});
}
for(int i = 0; i < scene->mNumCameras; i++)
{
aiCamera* camera = scene->mCameras[i];
glm::mat4 mat = load_matrix(camera->mName.C_Str());
auto [x, y, z] = camera->mPosition;
auto [dx, dy, dz] = camera->mLookAt;
auto [ux, uy, uz] = camera->mUp;
glm::vec4 pos = mat * glm::vec4(x, y, z, 1);
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(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++)
{
aiMaterial* ai_mat = scene->mMaterials[i];
glm::vec3 matv(0);
aiColor4D ai_cb;
aiColor4D ai_em;
ai_mat->Get(AI_MATKEY_COLOR_EMISSIVE, ai_em);
ai_mat->Get(AI_MATKEY_BASE_COLOR, ai_cb);
glm::vec4 cb = {ai_cb[0], ai_cb[1], ai_cb[2], ai_cb[3]};
glm::vec4 em = {ai_em[0], ai_em[1], ai_em[2], ai_em[3]};
if(em.x > 0 || em.y > 0 || em.z > 0)
{
cb = em;
}
ai_mat->Get(AI_MATKEY_ROUGHNESS_FACTOR, matv[0]);
ai_mat->Get(AI_MATKEY_METALLIC_FACTOR, matv[1]);
ai_mat->Get(AI_MATKEY_EMISSIVE_INTENSITY, matv[2]);
uint32_t handle_diffuse = proc_texture(base, ai_mat, scene, aiTextureType_BASE_COLOR, 0, Texture::handle_white);
uint32_t handle_normal = proc_texture(base, ai_mat, scene, aiTextureType_NORMALS, 0, Texture::handle_normal);
Material mat = {
.diffuse = handle_diffuse,
.normal = handle_normal,
.colour = cb,
.roughness = matv[0],
.metalness = matv[1],
.luminance = matv[2],
};
materials.push_back(mat);
}
}
Mesh Model::load(const char* name, glm::mat4 mat) const
{
Mesh mesh;
ProcState state {.base = base};
ProcState state {
.base = base,
.materials = materials,
};
proc_node(state, mat, scene->mRootNode, scene, name);
mesh.vertices = std::move(state.vertices);
mesh.indices = std::move(state.indices);
mesh.transforms = std::move(state.transforms);
return mesh;
}

View File

@ -3,6 +3,8 @@
#include "mesh.hpp"
#include "light.hpp"
#include "camera.hpp"
#include "material.hpp"
#include <string>
#include <vector>
@ -14,7 +16,7 @@
#include <assimp/material.h>
#include <assimp/postprocess.h>
namespace Sim::Graphics
namespace Sim::Graphics::Data
{
class Model
@ -25,7 +27,9 @@ class Model
public:
std::vector<uint64_t> textures;
std::vector<uint32_t> textures;
std::vector<Material> materials;
std::vector<Camera> cameras;
std::vector<Light> lights;
Model(std::string base, std::string filename);
@ -35,7 +39,7 @@ public:
Mesh load_root(glm::mat4 mat) const;
Mesh load(const char* name) const;
Mesh load(const char* name, glm::mat4 mat) const;
glm::mat4 get_matrix(const char* name) const;
glm::mat4 load_matrix(const char* name) const;
};
};

View File

@ -0,0 +1,273 @@
#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 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()
{
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);
}
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;
switch(channels)
{
case 1:
format = GL_RED;
format_in = GL_R8;
break;
case 2:
format = GL_RG;
format_in = GL_RG8;
break;
case 3:
format = GL_RGB;
format_in = GL_RGB8;
break;
case 4:
format = GL_RGBA;
format_in = GL_RGBA8;
break;
default:
throw std::runtime_error("Invalid number of channels: " + std::to_string(channels));
}
unsigned int texid;
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);
uint32_t handle = glGetTextureHandleARB(texid);
glMakeTextureHandleResidentARB(handle);
return handle;
}
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);
uint64_t handle = load_mem(data, width, height, channels);
stbi_image_free(data);
return handle;
}
uint32_t Texture::load(std::string path)
{
const auto it = loaded.find(path);
if(it != loaded.end())
{
return it->second;
}
int width, height, channels;
unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, 0);
uint64_t handle = load_mem(data, width, height, channels);
stbi_image_free(data);
if(handle == 0)
{
throw std::runtime_error("Failed to load path: " + path);
}
std::cout << "Loaded image: " << path << "\n";
loaded[path] = handle;
return handle;
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <GL/glew.h>
#include <string>
#include <glm/vec2.hpp>
namespace Sim::Graphics::Data::Texture
{
extern uint32_t handle_white;
extern uint32_t handle_normal;
void init();
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);
};

View File

@ -0,0 +1,26 @@
#include "generator.hpp"
#include "../../system.hpp"
#include <glm/gtc/matrix_transform.hpp>
using namespace Sim::Graphics::Equipment;
using namespace Sim::Graphics::Data;
Generator::Generator(const Model& model)
{
g_rotor = model.load("visual_generator_rotor");
}
void Generator::remesh_static(Mesh& rmesh)
{
rmesh.add(g_rotor);
}
void Generator::get_static_transforms(std::vector<glm::mat4>& transforms)
{
Sim::System& sys = *Sim::System::active;
glm::mat4 rot = glm::rotate(glm::mat4(1), (float)sys.loop.generator.get_phase() * 0.5f, glm::vec3(0, 0, 1));
transforms.push_back(rot);
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "../data/meshgen.hpp"
namespace Sim::Graphics::Equipment
{
class Generator : public Data::MeshGen
{
Data::Mesh g_rotor;
public:
Generator(const Data::Model& model);
void get_static_transforms(std::vector<glm::mat4>& transforms) override;
void remesh_static(Data::Mesh& rmesh) override;
};
};

View File

@ -0,0 +1,36 @@
#include "pool.hpp"
#include "../../system.hpp"
#include <glm/gtc/matrix_transform.hpp>
using namespace Sim::Graphics::Equipment;
using namespace Sim::Graphics::Data;
Pool::Pool(const Model& model)
{
g_pool = model.load("visual_water");
}
void Pool::remesh_static(Mesh& rmesh)
{
rmesh.add(g_pool);
}
void Pool::get_static_transforms(std::vector<glm::mat4>& transforms)
{
Sim::System& sys = *Sim::System::active;
double z = sys.pool.get_level_height();
if(z > 0.1)
{
transforms.push_back(glm::translate(glm::mat4(1), glm::vec3(0, 0, z - sys.pool.dimensions.z)));
}
else
{
// hacky solution to prevent z fighting with the bottom of the pool
transforms.push_back(glm::mat4(0));
}
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "../data/meshgen.hpp"
namespace Sim::Graphics::Equipment
{
class Pool : public Data::MeshGen
{
Data::Mesh g_pool;
public:
Pool(const Data::Model& model);
void get_static_transforms(std::vector<glm::mat4>& transforms) override;
void remesh_static(Data::Mesh& rmesh) override;
};
};

View File

@ -8,42 +8,23 @@
#include <glm/gtc/matrix_transform.hpp>
using namespace Sim::Graphics::Equipment;
using namespace Sim::Graphics::Data;
Reactor::Reactor(const Model& model)
{
g_control_rod = model.load("visual_control_rod");
g_control_rod_lift = model.load("visual_control_rod_lift");
g_control_rod_base = model.load("visual_control_rod_base");
}
void Reactor::remesh_static(Mesh& rmesh)
{
Sim::System& sys = *Sim::System::active;
for(int i = 0; i < sys.reactor.size; i++)
{
Sim::Reactor::Rod* r = sys.reactor.rods[i].get();
if(!r->should_display())
{
continue;
}
if(r->get_colour()[3] != 0)
{
Mesh m = g_control_rod;
m.set_transform_id();
rmesh.add(m);
}
}
}
void Reactor::get_static_transforms(std::vector<glm::mat4>& transforms)
{
Sim::System& sys = *Sim::System::active;
double t_step = sys.reactor.cell_width;
double t_sx = -(sys.reactor.width - 1) * t_step / 2.0;
double t_sy = -(sys.reactor.height - 1) * t_step / 2.0;
glm::mat4 mat_scale = glm::scale(glm::mat4(1), glm::vec3(t_step / 0.4));
for(int i = 0; i < sys.reactor.size; i++)
{
int x = i % sys.reactor.width;
@ -60,7 +41,44 @@ void Reactor::get_static_transforms(std::vector<glm::mat4>& transforms)
if(r->get_colour()[3] != 0)
{
transforms.push_back(glm::translate(glm::mat4(1), glm::vec3(ox, oy, (1 - r->get_colour().r) * sys.reactor.cell_height)));
Mesh m1, m2;
glm::mat4 m = glm::translate(glm::mat4(1), glm::vec3(ox, oy, 0)) * mat_scale;
m1.add(g_control_rod_base, m);
m2.add(g_control_rod_lift, m);
m1.bake_transforms();
m2.bake_transforms();
m2.set_blank_transform();
for(int i = 0; i < m2.vertices.size(); i++)
{
if(g_control_rod_lift.vertices[i].pos.z == 0)
{
m2.vertices[i].transform_id = -1;
}
}
rmesh.add(m1);
rmesh.add(m2);
}
}
}
void Reactor::get_static_transforms(std::vector<glm::mat4>& transforms)
{
Sim::System& sys = *Sim::System::active;
for(int i = 0; i < sys.reactor.size; i++)
{
Sim::Reactor::Rod* r = sys.reactor.rods[i].get();
if(!r->should_display())
{
continue;
}
if(r->get_colour()[3] != 0)
{
transforms.push_back(glm::translate(glm::mat4(1), glm::vec3(0, 0, (1 - r->get_colour().r) * sys.reactor.cell_height)));
}
}
}

View File

@ -1,20 +1,20 @@
#pragma once
#include "../mesh/meshgen.hpp"
#include "../data/meshgen.hpp"
namespace Sim::Graphics::Equipment
{
class Reactor : public MeshGen
class Reactor : public Data::MeshGen
{
Mesh g_control_rod;
Data::Mesh g_control_rod_lift, g_control_rod_base;
public:
Reactor(const Model& model);
virtual void get_static_transforms(std::vector<glm::mat4>& transforms);
virtual void remesh_static(Mesh& rmesh);
Reactor(const Data::Model& model);
void get_static_transforms(std::vector<glm::mat4>& transforms) override;
void remesh_static(Data::Mesh& rmesh) override;
};
};

View File

@ -24,6 +24,7 @@ static std::unique_ptr<Focus::FocusType> state = nullptr;
static bool mouse_visible = false;
static bool mouse_locked = false;
static bool triggered = false;
static bool triggered_release = false;
void Focus::on_keypress(int key, int sc, int action, int mods)
{
@ -53,8 +54,10 @@ void Focus::on_mouse_button(int button, int action, int mods)
state->on_mouse_button(button, action, mods);
}
if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
if(button == GLFW_MOUSE_BUTTON_LEFT && (action == GLFW_RELEASE || action == GLFW_PRESS))
{
bool t = false;
if(is_mouse_locked() && mouse_visible)
{
double mx, my;
@ -66,14 +69,21 @@ void Focus::on_mouse_button(int button, int action, int mods)
trigger_near = glm::unProject(glm::vec3(mouse, -1), Camera::get_matrix(), Window::projection_matrix, viewport);
trigger_far = glm::unProject(glm::vec3(mouse, 1), Camera::get_matrix(), Window::projection_matrix, viewport);
triggered = true;
t = true;
}
else if(!mouse_visible)
{
trigger_near = Camera::get_pos();
trigger_far = trigger_near + Camera::get_normal();
triggered = true;
t = true;
}
if(t)
{
t = (action == GLFW_PRESS);
triggered_release = !t;
triggered = t;
}
}
}
@ -107,6 +117,7 @@ glm::vec<3, double> Focus::get_trigger_far()
void Focus::update(double dt)
{
triggered = false;
triggered_release = false;
bool c = is_mouse_locked();
@ -194,3 +205,8 @@ bool Focus::is_triggered()
return triggered;
}
bool Focus::is_triggered_release()
{
return triggered_release;
}

View File

@ -24,6 +24,7 @@ struct FocusType
bool is_focused();
void clear_focus();
bool is_triggered();
bool is_triggered_release();
bool is_mouse_locked();
void clear_mouse_locked();
glm::vec<3, double> get_trigger_near();

View File

@ -1,47 +0,0 @@
#include "locations.hpp"
#include <glm/ext/matrix_transform.hpp>
using namespace Sim::Graphics;
const glm::mat4 Locations::monitors[7] = {
(
glm::translate(glm::mat4(1), glm::vec3(-2.9475, -1.7778 + 0.05, 3 - 0.05)) *
glm::rotate(glm::mat4(1), glm::radians<float>(-90), glm::vec3(1, 0, 0)) *
glm::rotate(glm::mat4(1), glm::radians<float>(-90), glm::vec3(0, 1, 0)) *
glm::scale(glm::mat4(1), glm::vec3(1.9, 1.9, 1.9))
),
(
glm::translate(glm::mat4(1), glm::vec3(-1.5 + 0.05, 3.9475, 3 - 0.05)) *
glm::rotate(glm::mat4(1), glm::radians<float>(-90), glm::vec3(1, 0, 0)) *
glm::scale(glm::mat4(1), glm::vec3(1.9, 1.9, 1.9))
),
(
glm::translate(glm::mat4(1), glm::vec3(1 + 0.05, 3.9475, 3 - 0.05)) *
glm::rotate(glm::mat4(1), glm::radians<float>(-90), glm::vec3(1, 0, 0)) *
glm::scale(glm::mat4(1), glm::vec3(1.9, 1.9, 1.9))
),
(
glm::translate(glm::mat4(1), glm::vec3(3.5 + 0.05, 3.9475, 3 - 0.05)) *
glm::rotate(glm::mat4(1), glm::radians<float>(-90), glm::vec3(1, 0, 0)) *
glm::scale(glm::mat4(1), glm::vec3(1.9, 1.9, 1.9))
),
(
glm::translate(glm::mat4(1), glm::vec3(6 + 0.05, 3.9475, 3 - 0.05)) *
glm::rotate(glm::mat4(1), glm::radians<float>(-90), glm::vec3(1, 0, 0)) *
glm::scale(glm::mat4(1), glm::vec3(1.9, 1.9, 1.9))
),
(
glm::translate(glm::mat4(1), glm::vec3(8.9475, 7.0/3.0 - 0.05, 3 - 0.05)) *
glm::rotate(glm::mat4(1), glm::radians<float>(-90), glm::vec3(1, 0, 0)) *
glm::rotate(glm::mat4(1), glm::radians<float>(90), glm::vec3(0, 1, 0)) *
glm::scale(glm::mat4(1), glm::vec3(1.9, 1.9, 1.9))
),
(
glm::translate(glm::mat4(1), glm::vec3(8.9475, -1.0/3.0 - 0.05, 3 - 0.05)) *
glm::rotate(glm::mat4(1), glm::radians<float>(-90), glm::vec3(1, 0, 0)) *
glm::rotate(glm::mat4(1), glm::radians<float>(90), glm::vec3(0, 1, 0)) *
glm::scale(glm::mat4(1), glm::vec3(1.9, 1.9, 1.9))
)
};

View File

@ -1,12 +0,0 @@
#pragma once
#include <glm/matrix.hpp>
namespace Sim::Graphics::Locations
{
extern const glm::mat4 monitors[7];
};

View File

@ -1,43 +0,0 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <assimp/Importer.hpp>
#include "../shader.hpp"
#include "arrays.hpp"
#include "font.hpp"
using namespace Sim::Graphics;
static void* ptr_diff(void* a, void* b)
{
return (void*)((size_t)a - (size_t)b);
}
void Arrays::vertex_attrib_pointers()
{
Vertex v;
glVertexAttribLPointer(0, 1, GL_UNSIGNED_INT64_ARB, sizeof(v), ptr_diff(&v.texid, &v));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(v), ptr_diff(&v.texpos, &v));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 4, GL_FLOAT, false, sizeof(v), ptr_diff(&v.pos, &v));
glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 3, GL_FLOAT, false, sizeof(v), ptr_diff(&v.normal, &v));
glEnableVertexAttribArray(3);
glVertexAttribPointer(4, 4, GL_FLOAT, false, sizeof(v), ptr_diff(&v.colour, &v));
glEnableVertexAttribArray(4);
glVertexAttribPointer(5, 3, GL_FLOAT, false, sizeof(v), ptr_diff(&v.material, &v));
glEnableVertexAttribArray(5);
glVertexAttribPointer(6, 1, GL_FLOAT, false, sizeof(v), ptr_diff(&v.transform_id, &v));
glEnableVertexAttribArray(6);
}

View File

@ -1,26 +0,0 @@
#pragma once
#include <glm/matrix.hpp>
namespace Sim::Graphics::Arrays
{
struct Vertex
{
unsigned long texid = 0;
glm::vec2 texpos = {0, 0};
glm::vec4 pos = {0, 0, 0, 1};
glm::vec3 normal = {0, 0, 0};
glm::vec4 colour = {1, 1, 1, 1};
glm::vec3 material = {0, 0, 0};
float transform_id = -1;
constexpr bool operator==(const Vertex&) const = default;
} __attribute__((packed));
void vertex_attrib_pointers();
};

View File

@ -1,188 +0,0 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <glm/vec2.hpp>
#include <iostream>
#include <vector>
#include "mesh.hpp"
#include "arrays.hpp"
#include "font.hpp"
using namespace Sim::Graphics;
struct Character
{
unsigned long handle;
float advance;
glm::vec2 size;
glm::vec2 bearing;
};
static Character chars[128];
void Font::init()
{
FT_Library ft;
FT_Face face;
if(FT_Init_FreeType(&ft))
{
std::cout << "Error: failed to init freetype\n";
return;
}
if(FT_New_Face(ft, "../assets/font/DroidSans.ttf", 0, &face))
{
std::cout << "Error: failed to load freetype font\n";
return;
}
int size = 256;
float m = 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))
{
std::cout << "Error: failed to load glyph " << i << "\n";
}
int width = face->glyph->bitmap.width;
int height = face->glyph->bitmap.rows;
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};
if(c.size.x == 0 || c.size.y == 0)
{
c.handle = 0;
continue;
}
pixels.resize(width * height);
for(int i = 0; i < width * height; i++)
{
pixels[i] = glm::vec<4, unsigned char>(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;
}
FT_Done_FreeType(ft);
}
void Mesh::load_text(const char* text, double size)
{
std::vector<Arrays::Vertex> vertices;
std::vector<unsigned int> indices;
float x = 0, y = size;
unsigned int at = 0;
if(text[0] == '\0')
{
this->vertices.clear();
this->indices.clear();
return;
}
for(unsigned int i = 0; text[i] != '\0'; i++)
{
char c = text[i];
Character ch = chars[c];
if(c == '\n')
{
x = 0;
y += size;
continue;
}
if(ch.handle == 0)
{
x += ch.advance * size;
continue;
}
unsigned int index[6] = {
at, at + 1, at + 3,
at, at + 3, at + 2
};
float sx = x + ch.bearing.x * size;
float sy = y - ch.bearing.y * size;
float ex = sx + ch.size.x * size;
float ey = sy + ch.size.y * size;
vertices.push_back(Arrays::Vertex{.texid=ch.handle, .texpos={0, 0}, .pos={sx, sy, 0, 1}, .normal={0, 0, -1}, .material={0, 0, 1}});
vertices.push_back(Arrays::Vertex{.texid=ch.handle, .texpos={0, 1}, .pos={sx, ey, 0, 1}, .normal={0, 0, -1}, .material={0, 0, 1}});
vertices.push_back(Arrays::Vertex{.texid=ch.handle, .texpos={1, 0}, .pos={ex, sy, 0, 1}, .normal={0, 0, -1}, .material={0, 0, 1}});
vertices.push_back(Arrays::Vertex{.texid=ch.handle, .texpos={1, 1}, .pos={ex, ey, 0, 1}, .normal={0, 0, -1}, .material={0, 0, 1}});
indices.insert(indices.end(), &index[0], &index[6]);
at += 4;
x += ch.advance * size;
}
this->vertices = std::move(vertices);
this->indices = std::move(indices);
}
void Mesh::load_text(const char* text, double size, glm::vec2 align)
{
glm::vec2 max;
load_text(text, size);
for(Arrays::Vertex& v : vertices)
{
if(v.pos.x > max.x)
{
max.x = v.pos.x;
}
if(v.pos.y > max.y)
{
max.y = v.pos.y;
}
}
align *= max;
for(Arrays::Vertex& v : vertices)
{
v.pos.x -= align.x;
v.pos.y -= align.y;
}
}

View File

@ -1,15 +0,0 @@
#pragma once
#include "mesh.hpp"
#include <string>
#include <sstream>
namespace Sim::Graphics::Font
{
void init();
};

View File

@ -1,86 +0,0 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "gllight.hpp"
#include "../shader.hpp"
#include "../window.hpp"
#include "texture.hpp"
#include <glm/ext/matrix_transform.hpp>
#include <glm/ext/matrix_clip_space.hpp>
using namespace Sim::Graphics;
static glm::mat4 shadow_mats[6];
GLLight::GLLight(Light light) : light(light), size(1024)
{
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
for(int i = 0; i < 6; i++)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, size, size, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, id, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
handle = glGetTextureHandleARB(id);
glMakeTextureHandleResidentARB(handle);
}
GLLight::GLLight(GLLight&& o) : light(o.light), size(o.size)
{
id = o.id;
handle = o.handle;
fbo = o.fbo;
o.id = 0;
o.handle = 0;
o.fbo = 0;
}
GLLight::~GLLight()
{
if(fbo)
glDeleteFramebuffers(1, &fbo);
if(id)
glDeleteTextures(1, &id);
}
void GLLight::render()
{
glm::mat4 camera_mat = glm::translate(glm::mat4(1), -light.pos);
glUniformMatrix4fv(Shader::LIGHT["camera"], 1, false, &camera_mat[0][0]);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glViewport(0, 0, size, size);
Window::render_scene();
}
void GLLight::init()
{
glm::mat4 shadow_proj = glm::perspective<float>(M_PI * 0.5f, 1.0f, 0.01f, 100.f);
shadow_mats[0] = shadow_proj * glm::lookAt(glm::vec3(0), { 1, 0, 0}, {0,-1, 0});
shadow_mats[1] = shadow_proj * glm::lookAt(glm::vec3(0), {-1, 0, 0}, {0,-1, 0});
shadow_mats[2] = shadow_proj * glm::lookAt(glm::vec3(0), { 0, 1, 0}, {0, 0, 1});
shadow_mats[3] = shadow_proj * glm::lookAt(glm::vec3(0), { 0,-1, 0}, {0, 0,-1});
shadow_mats[4] = shadow_proj * glm::lookAt(glm::vec3(0), { 0, 0, 1}, {0,-1, 0});
shadow_mats[5] = shadow_proj * glm::lookAt(glm::vec3(0), { 0, 0,-1}, {0,-1, 0});
glUniformMatrix4fv(Shader::LIGHT["shadow_mats"], 6, false, &shadow_mats[0][0][0]);
}

View File

@ -1,28 +0,0 @@
#pragma once
#include "light.hpp"
namespace Sim::Graphics
{
struct GLLight
{
const int size;
unsigned int id, fbo;
unsigned long handle;
Light light;
GLLight(Light light);
GLLight(GLLight&& o);
GLLight(const GLLight& o) = delete;
~GLLight();
static void init();
void render();
};
};

View File

@ -1,52 +0,0 @@
#pragma once
#include <string>
#include <sstream>
#include <unordered_map>
#include <string>
#include <vector>
#include <glm/matrix.hpp>
#include "arrays.hpp"
#include "light.hpp"
namespace Sim::Graphics
{
struct Mesh
{
std::vector<Arrays::Vertex> vertices;
std::vector<unsigned int> indices;
float max_transform_id = -1;
Mesh();
void set_transform_id();
void set_vertices(const Arrays::Vertex* data, size_t size);
void set_indices(const unsigned int* data, size_t size);
void load_text(const char* text, double size);
void load_text(const char* text, double size, glm::vec2 align);
void add(const Mesh& o, glm::mat4 mat);
void add(const Mesh& o);
Mesh to_lines() const;
bool check_focus() const;
bool check_focus(double len) const;
bool check_intersect(glm::vec<3, double> pos, glm::vec<3, double> path) const;
glm::vec<3, double> calc_intersect(glm::vec<3, double> pos, glm::vec<3, double> path) const;
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);
}
};
};

View File

@ -1,100 +0,0 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stb/stb_image.h>
#include <unordered_map>
#include <iostream>
#include "texture.hpp"
using namespace Sim::Graphics;
static std::unordered_map<std::string, unsigned int> loaded;
unsigned int Texture::handle_white;
void Texture::init()
{
unsigned char pixels[] = {255, 255, 255, 255};
handle_white = load_mem(pixels, 1, 1, 4);
}
unsigned int Texture::load_mem(const unsigned char* data, int width, int height, int channels)
{
if(!data)
{
return 0;
}
GLenum format, format_in;
switch(channels)
{
case 1:
format = GL_RED;
format_in = GL_R8;
break;
case 2:
format = GL_RG;
format_in = GL_RG8;
break;
case 3:
format = GL_RGB;
format_in = GL_RGB8;
break;
case 4:
format = GL_RGBA;
format_in = GL_RGBA8;
break;
}
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);
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);
unsigned int handle = glGetTextureHandleARB(texid);
glMakeTextureHandleResidentARB(handle);
return handle;
}
unsigned int Texture::load_mem(const unsigned char* filedata, size_t len)
{
int width, height, channels;
unsigned char* data = stbi_load_from_memory(filedata, len, &width, &height, &channels, 0);
unsigned int handle = load_mem(data, width, height, channels);
stbi_image_free(data);
return handle;
}
unsigned int Texture::load(std::string path)
{
const auto it = loaded.find(path);
if(it != loaded.end())
{
return it->second;
}
int width, height, channels;
unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, 0);
unsigned int handle = load_mem(data, width, height, channels);
stbi_image_free(data);
if(handle == 0)
{
throw std::runtime_error("Failed to load path: " + path);
}
std::cout << "Loaded image: " << path << "\n";
loaded[path] = handle;
return handle;
}

View File

@ -1,17 +0,0 @@
#pragma once
#include <string>
namespace Sim::Graphics::Texture
{
extern unsigned int handle_white;
void init();
unsigned int load(std::string path);
unsigned int load_mem(const unsigned char* data, int width, int height, int channels);
unsigned int load_mem(const unsigned char* data, size_t len);
};

View File

@ -0,0 +1,313 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/ext/matrix_transform.hpp>
#include <glm/ext/matrix_clip_space.hpp>
#include <cmath>
#include "cctv.hpp"
#include "../shader.hpp"
#include "../window.hpp"
#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"
#define HEIGHT 512
using namespace Sim::Graphics::Monitor;
using namespace Sim::Graphics::Data;
using namespace Sim::Graphics;
using namespace Sim;
class FocusCCTV : public Focus::FocusType
{
CCTV* parent;
int zoom = 0;
int rot_pitch = 0;
int rot_yaw = 0;
public:
FocusCCTV(CCTV* parent)
{
this->parent = parent;
}
virtual void update(double dt)
{
if(rot_pitch || rot_yaw)
{
parent->rotate(dt, rot_pitch, -rot_yaw);
}
if(zoom)
{
Data::Camera& active = parent->cameras[parent->camera_at];
active.zoom = Util::Math::clamp(active.zoom - zoom * dt * 0.5f, 0.25, 1);
}
}
virtual void on_keypress(int key, int sc, int action, int mods)
{
if(action == GLFW_PRESS)
{
switch(key)
{
case GLFW_KEY_KP_1:
parent->camera_at = (parent->camera_at + parent->cameras.size() - 1) % parent->cameras.size();
break;
case GLFW_KEY_KP_2:
parent->powered = !parent->powered;
break;
case GLFW_KEY_KP_3:
parent->camera_at = (parent->camera_at + 1) % parent->cameras.size();
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;
case GLFW_KEY_KP_7:
zoom += 1;
break;
case GLFW_KEY_KP_8:
rot_pitch += 1;
break;
case GLFW_KEY_KP_9:
zoom -= 1;
break;
}
}
else if(action == GLFW_RELEASE)
{
switch(key)
{
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;
case GLFW_KEY_KP_7:
zoom -= 1;
break;
case GLFW_KEY_KP_8:
rot_pitch -= 1;
break;
case GLFW_KEY_KP_9:
zoom += 1;
break;
}
}
}
};
CCTV::CCTV(Model& model)
: height(HEIGHT)
, width(HEIGHT * 16 / 9)
, cameras(model.cameras)
{
m_buttons[0] = model.load("click_cctv_numpad_1");
m_buttons[1] = model.load("click_cctv_numpad_2");
m_buttons[2] = model.load("click_cctv_numpad_3");
m_buttons[3] = model.load("click_cctv_numpad_4");
m_buttons[4] = model.load("click_cctv_numpad_5");
m_buttons[5] = model.load("click_cctv_numpad_6");
m_buttons[6] = model.load("click_cctv_numpad_7");
m_buttons[7] = model.load("click_cctv_numpad_8");
m_buttons[8] = model.load("click_cctv_numpad_9");
glGenFramebuffers(1, &fbo);
glGenTextures(1, &texture);
glGenRenderbuffers(1, &rbo_depth);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_depth);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
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}},
{.texpos={1, 1}, .pos={1, 0, 0}, .transform_id=0, .tex_diffuse=handle, .material={0, 0, 1}},
{.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 = {mat};
m_screen.bake_transforms();
gm_screen.bind();
gm_screen.set(m_screen, GL_STATIC_DRAW);
}
CCTV::~CCTV()
{
if(fbo) glDeleteFramebuffers(1, &fbo);
if(texture) glDeleteTextures(1, &texture);
if(rbo_depth) glDeleteRenderbuffers(1, &rbo_depth);
}
CCTV::CCTV(CCTV&& o)
: width(o.width)
, height(o.height)
, cameras(std::move(o.cameras))
, gm_screen(std::move(o.gm_screen))
, m_screen(std::move(o.m_screen))
, m_buttons(std::move(o.m_buttons))
, powered(o.powered)
{
fbo = o.fbo;
texture = o.texture;
rbo_depth = o.rbo_depth;
handle = o.handle;
o.fbo = 0;
o.texture = 0;
o.rbo_depth = 0;
o.handle = 0;
}
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;
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];
if(m_screen.check_focus())
Focus::set(std::make_unique<FocusCCTV>(this));
if(m_buttons[0].check_focus_hold())
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(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_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())
powered = !powered;
if(m_buttons[8].check_focus())
camera_at = (camera_at + 1) % cameras.size();
}
void CCTV::render_view()
{
if(!powered)
return;
Data::Camera& active = cameras[camera_at];
glm::mat4 rot = glm::mat4(1);
glm::vec3 right = glm::normalize(glm::cross(active.look, active.up));
rot = glm::rotate(rot, -active.yaw, active.up);
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::vec3 brightness = glm::vec3(System::active->grid.get_light_intensity());
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glFrontFace(GL_CCW);
glUniformMatrix4fv(Shader::MAIN["projection"], 1, false, &proj[0][0]);
glUniformMatrix4fv(Shader::MAIN["camera"], 1, false, &view[0][0]);
glUniform3fv(Shader::MAIN["camera_pos"], 1, &active.pos[0]);
Window::bind_scene_ssbo();
Window::render_scene();
Window::render_dynamic();
Window::render_player();
}
void CCTV::render_screen()
{
if(!powered)
return;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBlendFunc(GL_SRC_COLOR, GL_ONE);
gm_screen.bind();
gm_screen.render();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

View File

@ -0,0 +1,50 @@
#pragma once
#include <glm/matrix.hpp>
#include <vector>
#include <array>
#include "../data/meshgen.hpp"
#include "../data/camera.hpp"
#include "../data/glmesh.hpp"
namespace Sim::Graphics::Monitor
{
class CCTV : public Data::MeshGen
{
Data::GLMesh gm_screen;
Data::Mesh m_screen;
std::array<Data::Mesh, 9> m_buttons;
unsigned int fbo;
unsigned int texture;
unsigned int rbo_depth;
unsigned int handle;
const int width;
const int height;
public:
glm::mat4 mat;
std::vector<Data::Camera> cameras;
int camera_at = 0;
bool powered = false;
CCTV(Data::Model& model);
CCTV(const CCTV&) = delete;
CCTV(CCTV&&);
~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();
};
};

View File

@ -3,12 +3,12 @@
#include <GLFW/glfw3.h>
#include "core.hpp"
#include "../locations.hpp"
#include "../input/focus.hpp"
#include "../mesh/arrays.hpp"
#include "../mesh/texture.hpp"
#include "../data/arrays.hpp"
#include "../data/texture.hpp"
#include "../../system.hpp"
#include "../../util/streams.hpp"
#include "../data/font.hpp"
#include <glm/ext/matrix_transform.hpp>
@ -18,6 +18,7 @@
using namespace Sim;
using namespace Sim::Graphics;
using namespace Sim::Graphics::Monitor;
using namespace Sim::Graphics::Data;
using namespace Sim::Util::Streams;
static void set_all(bool state)
@ -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;
@ -118,16 +119,16 @@ struct CoreJoystick : public Focus::FocusType
Core::Core(const Model& model)
{
mat = Locations::monitors[2];
m_buttons[0] = model.load("click_numpad_1");
m_buttons[1] = model.load("click_numpad_2");
m_buttons[2] = model.load("click_numpad_3");
m_buttons[3] = model.load("click_numpad_4");
m_buttons[4] = model.load("click_numpad_5");
m_buttons[5] = model.load("click_numpad_6");
m_buttons[6] = model.load("click_numpad_7");
m_buttons[7] = model.load("click_numpad_8");
m_buttons[8] = model.load("click_numpad_9");
mat = model.load_matrix("translation_monitor_3");
m_buttons[0] = model.load("click_reactor_numpad_1");
m_buttons[1] = model.load("click_reactor_numpad_2");
m_buttons[2] = model.load("click_reactor_numpad_3");
m_buttons[3] = model.load("click_reactor_numpad_4");
m_buttons[4] = model.load("click_reactor_numpad_5");
m_buttons[5] = model.load("click_reactor_numpad_6");
m_buttons[6] = model.load("click_reactor_numpad_7");
m_buttons[7] = model.load("click_reactor_numpad_8");
m_buttons[8] = model.load("click_reactor_numpad_9");
m_joystick = model.load("click_reactor_joystick");
m_monitor = model.load("translation_monitor_3");
m_scram = model.load("click_scram");
@ -135,24 +136,21 @@ Core::Core(const Model& model)
void Core::remesh_static(Mesh& rmesh)
{
Mesh mesh;
mesh.load_text("Reactor Core", 0.04);
rmesh.add(mesh, mat);
rmesh.add(Data::Fonts::BASE.load_text("Reactor Core", 0.04), mat, true);
}
static Mesh add_dot(glm::mat4 model_mat, glm::vec4 colour)
static Data::Mesh add_dot(glm::mat4 model_mat, glm::vec4 colour)
{
unsigned int indices[] = {0, 1, 3, 0, 3, 2};
Arrays::Vertex vertices[] = {
{.texid=Texture::handle_white, .texpos={0, 0}, .pos=model_mat * glm::vec4(-0.75, -0.75, 0, 1), .normal={0, 0, -1}, .colour=colour, .material={0, 0, 1}},
{.texid=Texture::handle_white, .texpos={0, 1}, .pos=model_mat * glm::vec4(-0.75, 0.75, 0, 1), .normal={0, 0, -1}, .colour=colour, .material={0, 0, 1}},
{.texid=Texture::handle_white, .texpos={1, 0}, .pos=model_mat * glm::vec4( 0.75, -0.75, 0, 1), .normal={0, 0, -1}, .colour=colour, .material={0, 0, 1}},
{.texid=Texture::handle_white, .texpos={1, 1}, .pos=model_mat * glm::vec4( 0.75, 0.75, 0, 1), .normal={0, 0, -1}, .colour=colour, .material={0, 0, 1}},
Data::Mesh mesh;
mesh.indices = {0, 1, 3, 0, 3, 2};
mesh.vertices = {
{.texpos={0, 0}, .pos=glm::vec3(model_mat * glm::vec4(-0.75, -0.75, 0, 1)), .colour=colour, .material={0, 0, 1}},
{.texpos={0, 1}, .pos=glm::vec3(model_mat * glm::vec4(-0.75, 0.75, 0, 1)), .colour=colour, .material={0, 0, 1}},
{.texpos={1, 0}, .pos=glm::vec3(model_mat * glm::vec4( 0.75, -0.75, 0, 1)), .colour=colour, .material={0, 0, 1}},
{.texpos={1, 1}, .pos=glm::vec3(model_mat * glm::vec4( 0.75, 0.75, 0, 1)), .colour=colour, .material={0, 0, 1}},
};
Mesh mesh;
mesh.set_indices(indices, 6);
mesh.set_vertices(vertices, 4);
return mesh;
}
@ -175,21 +173,21 @@ 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)
{
Sim::System& sys = *System::active;
Sim::Graphics::Mesh mesh;
Sim::Graphics::Data::Mesh mesh;
double step = 1 / (sys.vessel.diameter / sys.reactor.cell_width * 0.8);
double step = sys.reactor.cell_width / sys.vessel.diameter * 0.8;
double sx = 0.5 - (sys.reactor.width - 1) * step / 2.0;
double sy = 0.5 - (sys.reactor.height - 1) * step / 2.0;

View File

@ -1,27 +1,27 @@
#pragma once
#include "../mesh/model.hpp"
#include "../mesh/meshgen.hpp"
#include "../data/model.hpp"
#include "../data/meshgen.hpp"
namespace Sim::Graphics::Monitor
{
class Core : public MeshGen
class Core : public Data::MeshGen
{
glm::mat4 mat;
Mesh m_monitor;
Mesh m_buttons[9];
Mesh m_joystick;
Mesh m_scram;
Data::Mesh m_monitor;
Data::Mesh m_buttons[9];
Data::Mesh m_joystick;
Data::Mesh m_scram;
public:
Core(const Model& model);
virtual void update(double dt);
virtual void remesh_static(Mesh& rmesh);
virtual void remesh_slow(Mesh& rmesh);
Core(const Data::Model& model);
void update(double dt) override;
void remesh_static(Data::Mesh& rmesh) override;
void remesh_slow(Data::Mesh& rmesh) override;
};
};

View File

@ -3,17 +3,18 @@
#include <GLFW/glfw3.h>
#include "primary_loop.hpp"
#include "../locations.hpp"
#include "../../system.hpp"
#include "../../coolant/valve.hpp"
#include "../input/focus.hpp"
#include "../../util/streams.hpp"
#include "../data/font.hpp"
#include <glm/ext/matrix_transform.hpp>
#include <iostream>
using namespace Sim::Graphics;
using namespace Sim::Graphics::Monitor;
using namespace Sim::Graphics::Data;
using namespace Sim::Util::Streams;
struct ValveJoystick : public Focus::FocusType
@ -51,7 +52,7 @@ struct ValveJoystick : public Focus::FocusType
PrimaryLoop::PrimaryLoop(const Model& model)
{
mat = Locations::monitors[3];
mat = model.load_matrix("translation_monitor_4");
g_switch_pump = model.load("visual_pump_switch_1");
g_switch_bypass = model.load("visual_bypass_switch");
@ -62,16 +63,11 @@ PrimaryLoop::PrimaryLoop(const Model& model)
m_switch_pump = model.load("click_pump_switch_1");
m_switch_bypass = model.load("click_bypass_switch");
m_switch_inlet = model.load("click_inlet_switch");
g_switch_pump.set_transform_id();
g_switch_bypass.set_transform_id();
g_switch_inlet.set_transform_id();
}
void PrimaryLoop::remesh_static(Mesh& rmesh)
{
std::stringstream ss;
Mesh mesh;
ss << "Turbine Bypass Valve\n\n";
ss << "Opened\nFlow\nSetpoint\n\n";
@ -85,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);
rmesh.add(Data::Fonts::BASE.load_text(ss.str(), 0.04), mat, true);
rmesh.add(g_switch_pump);
rmesh.add(g_switch_bypass);
@ -112,7 +107,6 @@ void PrimaryLoop::update(double dt)
void PrimaryLoop::remesh_slow(Mesh& rmesh)
{
std::stringstream ss;
Sim::Graphics::Mesh mesh;
System& sys = *System::active;
ss << "\n\n";
@ -153,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)));
}

View File

@ -1,34 +1,34 @@
#pragma once
#include "../mesh/model.hpp"
#include "../mesh/meshgen.hpp"
#include "../data/model.hpp"
#include "../data/meshgen.hpp"
namespace Sim::Graphics::Monitor
{
class PrimaryLoop : public MeshGen
class PrimaryLoop : public Data::MeshGen
{
glm::mat4 mat;
Mesh m_joystick_turbine_bypass;
Mesh m_joystick_turbine_inlet;
Data::Mesh m_joystick_turbine_bypass;
Data::Mesh m_joystick_turbine_inlet;
Mesh g_switch_pump;
Mesh g_switch_bypass;
Mesh g_switch_inlet;
Data::Mesh g_switch_pump;
Data::Mesh g_switch_bypass;
Data::Mesh g_switch_inlet;
Mesh m_switch_pump;
Mesh m_switch_bypass;
Mesh m_switch_inlet;
Data::Mesh m_switch_pump;
Data::Mesh m_switch_bypass;
Data::Mesh m_switch_inlet;
public:
PrimaryLoop(const Model& model);
virtual void update(double dt);
virtual void get_static_transforms(std::vector<glm::mat4>& transforms);
virtual void remesh_static(Mesh& rmesh);
virtual void remesh_slow(Mesh& rmesh);
PrimaryLoop(const Data::Model& model);
void update(double dt) override;
void get_static_transforms(std::vector<glm::mat4>& transforms) override;
void remesh_static(Data::Mesh& rmesh) override;
void remesh_slow(Data::Mesh& rmesh) override;
};
};

View File

@ -3,23 +3,23 @@
#include <GLFW/glfw3.h>
#include "secondary_loop.hpp"
#include "../locations.hpp"
#include "../../system.hpp"
#include "../../coolant/valve.hpp"
#include "../input/focus.hpp"
#include "../../util/streams.hpp"
#include "../data/font.hpp"
#include <glm/ext/matrix_transform.hpp>
#include <iostream>
using namespace Sim::Graphics;
using namespace Sim::Graphics::Monitor;
using namespace Sim::Graphics::Data;
using namespace Sim::Util::Streams;
SecondaryLoop::SecondaryLoop(const Model& model)
{
mat = Locations::monitors[5];
mat = model.load_matrix("translation_monitor_6");
g_switch_2 = model.load("visual_pump_switch_2");
g_switch_3 = model.load("visual_pump_switch_3");
@ -28,9 +28,6 @@ SecondaryLoop::SecondaryLoop(const Model& model)
m_joystick_turbine_inlet = model.load("click_inlet_joystick");
m_switch_2 = model.load("click_pump_switch_2");
m_switch_3 = model.load("click_pump_switch_3");
g_switch_2.set_transform_id();
g_switch_3.set_transform_id();
}
void SecondaryLoop::update(double dt)
@ -46,7 +43,6 @@ void SecondaryLoop::update(double dt)
void SecondaryLoop::remesh_static(Mesh& rmesh)
{
std::stringstream ss;
Mesh mesh;
ss << "Cooling Tower\n\n";
ss << "Heat\nSteam\nPressure\nLevel\n\n";
@ -55,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);
rmesh.add(Data::Fonts::BASE.load_text(ss.str(), 0.04), mat, true);
rmesh.add(g_switch_2);
rmesh.add(g_switch_3);
}
@ -64,7 +59,6 @@ void SecondaryLoop::remesh_static(Mesh& rmesh)
void SecondaryLoop::remesh_slow(Mesh& rmesh)
{
std::stringstream ss;
Sim::Graphics::Mesh mesh;
System& sys = *System::active;
ss << "\n\n";
@ -81,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)));
}

View File

@ -1,31 +1,31 @@
#pragma once
#include "../mesh/model.hpp"
#include "../mesh/meshgen.hpp"
#include "../data/model.hpp"
#include "../data/meshgen.hpp"
namespace Sim::Graphics::Monitor
{
class SecondaryLoop : public MeshGen
class SecondaryLoop : public Data::MeshGen
{
glm::mat4 mat;
Mesh g_switch_2;
Mesh g_switch_3;
Data::Mesh g_switch_2;
Data::Mesh g_switch_3;
Mesh m_joystick_turbine_bypass;
Mesh m_joystick_turbine_inlet;
Mesh m_switch_2;
Mesh m_switch_3;
Data::Mesh m_joystick_turbine_bypass;
Data::Mesh m_joystick_turbine_inlet;
Data::Mesh m_switch_2;
Data::Mesh m_switch_3;
public:
SecondaryLoop(const Model& model);
virtual void update(double dt);
virtual void get_static_transforms(std::vector<glm::mat4>& transforms);
virtual void remesh_static(Mesh& rmesh);
virtual void remesh_slow(Mesh& rmesh);
SecondaryLoop(const Data::Model& model);
void update(double dt) override;
void get_static_transforms(std::vector<glm::mat4>& transforms) override;
void remesh_static(Data::Mesh& rmesh) override;
void remesh_slow(Data::Mesh& rmesh) override;
};
};

View File

@ -3,29 +3,32 @@
#include <GLFW/glfw3.h>
#include "turbine.hpp"
#include "../locations.hpp"
#include "../../system.hpp"
#include "../../coolant/valve.hpp"
#include "../input/focus.hpp"
#include "../../util/streams.hpp"
#include "../../util/math.hpp"
#include "../data/font.hpp"
#include <glm/ext/matrix_transform.hpp>
#include <iostream>
using namespace Sim::Graphics;
using namespace Sim::Graphics::Monitor;
using namespace Sim::Graphics::Data;
using namespace Sim::Util::Streams;
Turbine::Turbine(const Model& model)
{
mat = Locations::monitors[4];
mat = model.load_matrix("translation_monitor_5");
g_dial_phase = model.load("visual_dial_phase");
g_dial_voltage = model.load("visual_dial_voltage");
g_dial_power = model.load("visual_dial_power");
g_dial_frequency = model.load("visual_dial_frequency");
g_synchroscope_dial = model.load("visual_synchroscope_dial");
g_switch_breaker = model.load("visual_breaker_switch");
m_switch_breaker = model.load("click_breaker_switch");
g_synchroscope_dial.set_transform_id();
g_switch_breaker.set_transform_id();
}
void Turbine::update(double dt)
@ -40,40 +43,49 @@ void Turbine::get_static_transforms(std::vector<glm::mat4>& transforms)
{
System& sys = *System::active;
double rpm = sys.loop.generator.get_rpm();
glm::mat4 mat(1);
glm::mat4 mat_phase(1);
glm::mat4 mat_voltage(1);
glm::mat4 mat_power(1);
glm::mat4 mat_frequency(1);
if(rpm > 3570 && rpm < 3630)
{
mat = glm::translate(mat, glm::vec3(6.35, 3.949, 1.35));
mat = glm::rotate(mat, float(sys.loop.generator.get_phase_diff()), glm::vec3(0, 1, 0));
mat = glm::translate(mat, glm::vec3(-6.35, -3.949, -1.35));
mat_phase = glm::rotate(mat_phase, float(sys.loop.generator.get_phase_diff()), glm::vec3(0, 1, 0));
}
mat_voltage = glm::rotate(mat_voltage, float(Util::Math::map(sys.loop.generator.get_voltage(), 0, 24e3, 0, M_PI)), glm::vec3(0, 1, 0));
mat_power = glm::rotate(mat_power, float(Util::Math::map(sys.loop.generator.get_power(), 0, 600e6, 0, M_PI)), glm::vec3(0, 1, 0));
mat_frequency = glm::rotate(mat_frequency, float(Util::Math::map(sys.loop.generator.get_frequency(), 0, 120, 0, M_PI)), glm::vec3(0, 1, 0));
transforms.push_back(mat_phase);
transforms.push_back(mat_voltage);
transforms.push_back(mat_power);
transforms.push_back(mat_frequency);
float off1 = sys.loop.generator.breaker_closed ? 0.07 : 0;
transforms.push_back(mat);
transforms.push_back(glm::translate(glm::mat4(1), glm::vec3(0, off1, 0)));
}
void Turbine::remesh_static(Mesh& rmesh)
{
std::stringstream ss;
Sim::Graphics::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);
rmesh.add(Data::Fonts::BASE.load_text(ss.str(), 0.04), mat, true);
rmesh.add(g_synchroscope_dial);
rmesh.add(g_dial_phase);
rmesh.add(g_dial_voltage);
rmesh.add(g_dial_power);
rmesh.add(g_dial_frequency);
rmesh.add(g_switch_breaker);
}
void Turbine::remesh_slow(Mesh& rmesh)
{
std::stringstream ss;
Sim::Graphics::Mesh mesh;
System& sys = *System::active;
ss << "\n\n";
@ -81,24 +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)));
ss = std::stringstream();
ss << "Local\n\n";
ss << show( sys.loop.generator.get_rpm() / 60 ) << " Hz\n";
Util::Streams::show_units( ss, sys.loop.generator.get_energy_generated() ) << "W\n";
mesh.load_text(ss.str().c_str(), 0.04);
rmesh.add(mesh, glm::translate(mat, glm::vec3(0.4, 0.75, 0)));
ss = std::stringstream();
ss << "Grid\n\n";
ss << show( sys.grid.frequency ) << " Hz\n";
mesh.load_text(ss.str().c_str(), 0.04);
rmesh.add(mesh, glm::translate(mat, glm::vec3(0.7, 0.75, 0)));
}

View File

@ -1,28 +1,31 @@
#pragma once
#include "../mesh/model.hpp"
#include "../mesh/glmesh.hpp"
#include "../mesh/meshgen.hpp"
#include "../data/model.hpp"
#include "../data/glmesh.hpp"
#include "../data/meshgen.hpp"
namespace Sim::Graphics::Monitor
{
class Turbine : public MeshGen
class Turbine : public Data::MeshGen
{
glm::mat4 mat;
Mesh g_synchroscope_dial;
Mesh g_switch_breaker;
Mesh m_switch_breaker;
Data::Mesh g_dial_phase;
Data::Mesh g_dial_voltage;
Data::Mesh g_dial_power;
Data::Mesh g_dial_frequency;
Data::Mesh g_switch_breaker;
Data::Mesh m_switch_breaker;
public:
Turbine(const Model& model);
virtual void update(double dt);
virtual void get_static_transforms(std::vector<glm::mat4>& transforms);
virtual void remesh_static(Mesh& rmesh);
virtual void remesh_slow(Mesh& rmesh);
Turbine(const Data::Model& model);
void update(double dt) override;
void get_static_transforms(std::vector<glm::mat4>& transforms) override;
void remesh_static(Data::Mesh& rmesh) override;
void remesh_slow(Data::Mesh& rmesh) override;
};
};

View File

@ -5,25 +5,25 @@
#include "vessel.hpp"
#include "../../reactor/rod.hpp"
#include "../../reactor/control/boron_rod.hpp"
#include "../locations.hpp"
#include "../../system.hpp"
#include "../../util/streams.hpp"
#include "../data/font.hpp"
#include <glm/ext/matrix_transform.hpp>
#include <sstream>
using namespace Sim::Graphics::Monitor;
using namespace Sim::Graphics::Data;
using namespace Sim::Util::Streams;
Vessel::Vessel(const Model& model)
{
mat = Locations::monitors[1];
mat = model.load_matrix("translation_monitor_2");
}
void Vessel::remesh_static(Mesh& rmesh)
{
std::stringstream ss;
Sim::Graphics::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);
rmesh.add(Data::Fonts::BASE.load_text(ss.str(), 0.04), mat, true);
}
void Vessel::remesh_slow(Mesh& rmesh)
{
std::stringstream ss;
Sim::Graphics::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)));
}

View File

@ -1,21 +1,21 @@
#pragma once
#include "../mesh/model.hpp"
#include "../mesh/meshgen.hpp"
#include "../data/model.hpp"
#include "../data/meshgen.hpp"
namespace Sim::Graphics::Monitor
{
class Vessel : public MeshGen
class Vessel : public Data::MeshGen
{
glm::mat4 mat;
public:
Vessel(const Model& model);
virtual void remesh_static(Mesh& rmesh);
virtual void remesh_slow(Mesh& rmesh);
Vessel(const Data::Model& model);
void remesh_static(Data::Mesh& rmesh) override;
void remesh_slow(Data::Mesh& rmesh) override;
};
};

View File

@ -7,6 +7,7 @@
using namespace Sim::Graphics;
using namespace Sim::Graphics::Resize;
using namespace Sim::Graphics::Window;
static bool is_fullscreen = false;

View File

@ -5,46 +5,87 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <format>
#include "shader.hpp"
#include "shadersource.hpp"
#include "window.hpp"
using namespace Sim::Graphics;
Shader Shader::MAIN;
Shader Shader::BLUR;
Shader Shader::LIGHT;
Shader* Shader::ACTIVE;
static int load_shader(const char* src, int type)
bool Shader::USE_BINDLESS_TEXTURES = false;
static std::vector<std::string> shader_compiler_flags;
void Shader::add_define(const std::string& flag)
{
int id = glCreateShader(type);
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
return id;
shader_compiler_flags.push_back(flag);
}
static std::string read_shader(const char* path)
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";
while(!file.eof())
for(const auto& flag : shader_compiler_flags)
{
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)
Shader::Source::Source(const char* data, const char* name, GLenum type)
{
std::string path = std::string(base) + "/" + std::string(file);
return read_shader(path.c_str());
int success;
std::string source = apply_shader_compiler_flags(data);
data = source.c_str();
id = glCreateShader(type);
glShaderSource(id, 1, &data, nullptr);
glCompileShader(id);
glGetShaderiv(id, GL_COMPILE_STATUS, &success);
if(!success)
{
char infoLog[512];
glGetShaderInfoLog(id, 512, NULL, infoLog);
std::string entry = std::format("Shader Compile Error ({0}): {1}", name, infoLog);
throw std::runtime_error(entry);
}
}
Shader::Source::Source(Source&& o)
{
id = o.id;
o.id = 0;
}
Shader::Source::~Source()
{
if(id) glDeleteShader(id);
}
Shader::Shader()
@ -66,30 +107,15 @@ Shader::~Shader()
}
}
void Shader::load(const char* path, const char* file_vsh, const char* file_fsh)
void Shader::load(const Source* sources, const char* name, int count)
{
load(path, file_vsh, nullptr, file_fsh);
}
void Shader::load(const char* path, const char* file_vsh, const char* file_gsh, const char* file_fsh)
{
std::string shader_vsh = file_vsh ? read_shader(path, file_vsh) : "";
std::string shader_gsh = file_gsh ? read_shader(path, file_gsh) : "";
std::string shader_fsh = file_fsh ? read_shader(path, file_fsh) : "";
int success;
int vsh_id = file_vsh ? load_shader(shader_vsh.c_str(), GL_VERTEX_SHADER) : 0;
int gsh_id = file_gsh ? load_shader(shader_gsh.c_str(), GL_GEOMETRY_SHADER) : 0;
int fsh_id = file_fsh ? load_shader(shader_fsh.c_str(), GL_FRAGMENT_SHADER) : 0;
prog_id = glCreateProgram();
if(file_vsh)
glAttachShader(prog_id, vsh_id);
if(file_gsh)
glAttachShader(prog_id, gsh_id);
if(file_fsh)
glAttachShader(prog_id, fsh_id);
for(int i = 0; i < count; i++)
{
glAttachShader(prog_id, sources[i].id);
}
glLinkProgram(prog_id);
glGetProgramiv(prog_id, GL_LINK_STATUS, &success);
@ -98,21 +124,9 @@ void Shader::load(const char* path, const char* file_vsh, const char* file_gsh,
{
char infoLog[512];
glGetProgramInfoLog(prog_id, 512, NULL, infoLog);
std::cout << "Shader Link Error (" << path << "," << file_vsh << "," << file_fsh << "): " << infoLog << std::endl;
Window::close();
return;
std::string entry = std::format("Shader Link Error {0}: {1}", name, infoLog);
throw std::runtime_error(entry);
}
glUseProgram(prog_id);
if(file_vsh)
glDeleteShader(vsh_id);
if(file_gsh)
glDeleteShader(gsh_id);
if(file_fsh)
glDeleteShader(fsh_id);
ACTIVE = this;
}
void Shader::use()

View File

@ -1,11 +1,15 @@
#pragma once
#include <GL/glew.h>
#include <unordered_map>
#include <string>
namespace Sim::Graphics
{
class Shader
{
unsigned int prog_id = 0;
@ -15,19 +19,32 @@ class Shader
public:
struct Source
{
unsigned int id;
Source(const char* data, const char* name, GLenum type);
Source(const Source& o) = delete;
Source(Source&& o);
~Source();
};
static Shader MAIN;
static Shader BLUR;
static Shader LIGHT;
static Shader* ACTIVE;
static bool USE_BINDLESS_TEXTURES;
Shader();
Shader(const Shader& o) = delete;
Shader(Shader&& o);
~Shader();
void load(const char* path, const char* file_vsh, const char* file_gsh, const char* file_fsh);
void load(const char* path, const char* file_vsh, const char* file_fsh);
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();

View File

@ -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";

View File

@ -1,10 +1,10 @@
#version 460 core
R"GLSL(
layout (triangles) in;
layout (triangle_strip, max_vertices=18) out;
uniform mat4 shadow_mats[6];
uniform int light_pass;
in flat int should_ignore[];
out vec3 frag_pos;
@ -13,9 +13,11 @@ void main()
{
if(should_ignore[0] != 0) return;
int pass_offset = light_pass * 6;
for(int i = 0; i < 6; i++)
{
gl_Layer = i;
gl_Layer = i + pass_offset;
for(int j = 0; j < 3; j++)
{
@ -30,3 +32,4 @@ void main()
}
}
)GLSL";

View File

@ -0,0 +1,31 @@
R"GLSL(
layout (location = 1) in vec3 aPos;
layout (location = 2) in vec4 aColour;
layout (location = 7) in int aTransformIndex;
layout (binding = 3) readonly buffer TransformBuffer
{
mat4 transforms[];
};
out flat int should_ignore;
uniform vec3 light_pos;
uniform int light_pass;
mat4 load_model_mat(int index)
{
return index < 0 ? mat4(1.f) : transforms[index];
}
void main()
{
vec4 pos = vec4(aPos, 1.f);
mat4 model = load_model_mat(aTransformIndex);
gl_Position = model * pos - vec4(light_pos, 0.f);
should_ignore = int(aColour.a < 1.f);
}
)GLSL";

View File

@ -1,15 +1,17 @@
R"GLSL(
#version 460 core
#ifdef USE_BINDLESS_TEXTURES
#extension GL_ARB_bindless_texture : require
#endif
const float PI = 3.141592f;
in VS_OUT {
vec3 normal;
vec4 colour;
mat3 tbn;
vec3 pos;
vec2 tex_pos;
vec3 material;
flat vec4 colour;
flat vec3 material;
} vin;
struct Light
@ -18,24 +20,65 @@ struct Light
vec4 colour;
};
layout(std140, binding = 1) readonly buffer LightBuffer
layout(std140, binding = 2) readonly buffer LightBuffer
{
Light lights[];
};
layout(std430, binding = 2) readonly buffer ShadowMapBuffer
#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
{
samplerCube shadow_maps[];
vec2 uv_min;
vec2 uv_max;
};
in flat sampler2D frag_tex;
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;
uniform vec3 camera_pos;
uniform int lights_count;
uniform float far_plane;
uniform bool shadows_enabled;
uniform int lights_count;
uniform samplerCubeArrayShadow shadow_maps;
float Map(float v, float i_min, float i_max, float o_min, float o_max)
{
return o_min + (o_max - o_min) * (v - i_min) / (i_max - i_min);
}
float Ramp(float v, float i_min, float i_max, float o_min, float o_max)
{
float t = clamp(v, i_min, i_max);
return Map(t, i_min, i_max, o_min, o_max);
}
vec3 FresnelSchlick(float cosTheta, vec3 F0)
{
@ -97,9 +140,10 @@ vec3 sRGB_To_LinRGB(vec3 c)
void main()
{
vec4 albedo = texture2D(frag_tex, vin.tex_pos);
vec4 albedo = ReadTexture(frag_tex_diffuse, vin.tex_pos);
if(albedo.a == 0.f) discard;
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;
@ -107,21 +151,41 @@ void main()
float metalness = vin.material[1];
float luminance = min(vin.material[2], 1.f);
vec3 N = normalize(vin.normal);
vec3 N = normalize(vin.tbn * tangent);
vec3 V = normalize(camera_pos - vin.pos.xyz);
vec3 F0 = vec3(0.04f);
F0 = mix(F0, albedo_lin, metalness);
vec3 F0 = mix(vec3(0.04f), albedo_lin, metalness);
vec3 ambient = vec3(Map(dot(N, vec3(0.f, 0.f, 1.f)), -1.f, 1.f, 0.2f, 0.25f)) * albedo_lin * brightness;
vec3 Lo = vec3(0.f);
vec3 Lo = vec3(0.0f);
for(int i = 0; i < lights_count; i++)
{
Light l = lights[i];
vec3 L = normalize(l.pos.xyz - vin.pos);
vec3 H = normalize(V + L);
float d = length(vin.pos - l.pos.xyz);
vec3 L = (l.pos.xyz - vin.pos) / d;
float light_m;
if(shadows_enabled)
{
if(dot(vin.tbn[2], L) < 0.f)
{
continue;
}
light_m = texture(shadow_maps, vec4(-L, i), d / far_plane);
if(light_m <= 0.f)
{
continue;
}
}
else
{
light_m = 1.f;
}
vec3 H = normalize(V + L);
float atten = 1.f / (d*d);
vec3 radiance = l.colour.rgb * atten;
@ -138,31 +202,15 @@ void main()
float denominator = 4.f * max(dot(N, V), 0.f) * max(dot(N, L), 0.f) + 1e-4f;
vec3 specular = numerator / denominator;
float light_m;
float spec_m;
if(shadows_enabled)
{
float max_d = texture(shadow_maps[i], -L).r * far_plane + 1e-2f;
spec_m = max_d > d ? 1.f : 0.f;
light_m = spec_m * 0.25f + 0.75f;
}
else
{
light_m = 1.f;
spec_m = 1.f;
}
// add to outgoing radiance Lo
float NdotL = max(dot(N, L), 0.f);
Lo += (kD * albedo_lin / PI + specular * spec_m) * radiance * NdotL * light_m;
Lo += (kD * albedo_lin / PI + specular) * radiance * NdotL * light_m;
}
vec3 ambient = vec3(0.03f) * albedo_lin * brightness;
vec3 light = LinRGB_To_sRGB(ambient + Lo);
light = mix(light, albedo.rgb, luminance);
frag_colour = vec4(light, albedo.a);
}
)GLSL";

View File

@ -0,0 +1,78 @@
R"GLSL(
#ifdef USE_BINDLESS_TEXTURES
#extension GL_ARB_bindless_texture : require
#endif
layout (location = 0) in vec2 aTexPos;
layout (location = 1) in vec3 aPos;
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 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;
layout (std430, binding = 3) readonly buffer TransformBuffer
{
mat4 transforms[];
};
out VS_OUT {
mat3 tbn;
vec3 pos;
vec2 tex_pos;
flat vec4 colour;
flat vec3 material;
} vout;
mat4 load_model_mat(int index)
{
return index < 0 ? mat4(1.f) : transforms[index];
}
float Map(float v, float i_min, float i_max, float o_min, float o_max)
{
return o_min + (o_max - o_min) * (v - i_min) / (i_max - i_min);
}
void main()
{
vec4 pos = vec4(aPos, 1.f);
mat4 model = load_model_mat(aTransformIndex);
mat4 mv = camera * model;
mat4 mvp = projection * mv;
vout.tbn = mat3(model) * mat3(aTangent, aBitangent, aNormal);
vout.pos = (model * pos).xyz;
vout.tex_pos = aTexPos;
vout.colour = aColour;
vout.material = aMaterial.xyz;
frag_tex_diffuse = aTexDiffuse;
frag_tex_normal = aTexNormal;
gl_Position = mvp * pos;
}
)GLSL";

View File

@ -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"

View File

@ -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;
};

View File

@ -6,11 +6,11 @@
#include <glm/ext/matrix_transform.hpp>
#include "mesh/mesh.hpp"
#include "mesh/glmesh.hpp"
#include "mesh/arrays.hpp"
#include "mesh/font.hpp"
#include "mesh/texture.hpp"
#include "data/mesh.hpp"
#include "data/glmesh.hpp"
#include "data/arrays.hpp"
#include "data/font.hpp"
#include "data/texture.hpp"
#include "resize.hpp"
#include "shader.hpp"
@ -18,31 +18,22 @@
using namespace Sim::Graphics;
static GLMesh gm_ui;
static GLMesh gm_dynamic_slow[2];
static Data::Mesh g_ui;
static Data::GLMesh gm_dynamic_slow[2];
static Widget::Clock w_clock;
static int gm_dynamic_slow_at = 0;
void UI::init()
{
Mesh m;
unsigned int handle = Texture::handle_white;
const unsigned int indices[] = {0, 1, 3, 0, 3, 2};
const Arrays::Vertex vertices[] = {
{.texid=handle, .texpos={0, 0}, .pos={-1, -1, 0, 1}, .normal={0, 0, -1}, .colour={1, 1, 1, 1}, .material={0, 0, 1}},
{.texid=handle, .texpos={0, 1}, .pos={-1, 1, 0, 1}, .normal={0, 0, -1}, .colour={1, 1, 1, 1}, .material={0, 0, 1}},
{.texid=handle, .texpos={1, 0}, .pos={ 1, -1, 0, 1}, .normal={0, 0, -1}, .colour={1, 1, 1, 1}, .material={0, 0, 1}},
{.texid=handle, .texpos={1, 1}, .pos={ 1, 1, 0, 1}, .normal={0, 0, -1}, .colour={1, 1, 1, 1}, .material={0, 0, 1}},
g_ui.indices = {0, 1, 3, 0, 3, 2};
g_ui.vertices = {
{.texpos={0, 0}, .pos={-1, -1, 0}, .material={0, 0, 1}},
{.texpos={0, 1}, .pos={-1, 1, 0}, .material={0, 0, 1}},
{.texpos={1, 0}, .pos={ 1, -1, 0}, .material={0, 0, 1}},
{.texpos={1, 1}, .pos={ 1, 1, 0}, .material={0, 0, 1}},
};
m.set_indices(indices, 6);
m.set_vertices(vertices, 4);
gm_ui.bind();
gm_ui.set(m, GL_STATIC_DRAW);
g_ui.bake_transforms();
}
void UI::update(double dt)
@ -52,12 +43,15 @@ void UI::update(double dt)
void UI::update_slow()
{
Mesh mesh;
Data::Mesh mesh;
w_clock.remesh_slow(mesh);
mesh.add(g_ui);
mesh.bake_transforms();
gm_dynamic_slow[gm_dynamic_slow_at].bind();
gm_dynamic_slow[gm_dynamic_slow_at].set(mesh, GL_DYNAMIC_DRAW);
gm_dynamic_slow[gm_dynamic_slow_at].set(mesh, GL_STREAM_DRAW);
gm_dynamic_slow_at = (gm_dynamic_slow_at + 1) % 2;
}
@ -72,14 +66,7 @@ void UI::render()
glUniformMatrix4fv(Shader::MAIN["projection"], 1, false, &mat_projection[0][0]);
glUniformMatrix4fv(Shader::MAIN["camera"], 1, false, &mat_camera[0][0]);
gm_ui.bind();
gm_ui.uniform();
gm_ui.render();
gm_dynamic_slow[gm_dynamic_slow_at].bind();
gm_dynamic_slow[gm_dynamic_slow_at].uniform();
gm_dynamic_slow[gm_dynamic_slow_at].render();
w_clock.render();
}

View File

@ -10,13 +10,15 @@
#include <sstream>
#include <cmath>
#include "../mesh/arrays.hpp"
#include "../mesh/font.hpp"
#include "../mesh/arrays.hpp"
#include "../data/arrays.hpp"
#include "../data/font.hpp"
#include "../data/arrays.hpp"
#include "../resize.hpp"
#include "../../system.hpp"
#include "../../util/streams.hpp"
using namespace Sim::Graphics::Widget;
using namespace Sim::Graphics::Data;
void Clock::update(double dt)
{
@ -25,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;
@ -40,11 +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)));
}
void Clock::render()
{
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "../mesh/glmesh.hpp"
#include "../data/glmesh.hpp"
namespace Sim::Graphics::Widget
{
@ -11,8 +11,7 @@ struct Clock
double dt;
void update(double dt);
void remesh_slow(Mesh& rmesh);
void render();
void remesh_slow(Data::Mesh& rmesh);
};
};

View File

@ -10,8 +10,8 @@
#include <vector>
#include <memory>
#include "mesh/mesh.hpp"
#include "mesh/arrays.hpp"
#include "data/mesh.hpp"
#include "data/arrays.hpp"
#include "input/keyboard.hpp"
#include "input/mouse.hpp"
#include "input/focus.hpp"
@ -19,44 +19,51 @@
#include "resize.hpp"
#include "window.hpp"
#include "shader.hpp"
#include "mesh/font.hpp"
#include "locations.hpp"
#include "data/font.hpp"
#include "monitor/vessel.hpp"
#include "monitor/core.hpp"
#include "monitor/primary_loop.hpp"
#include "monitor/secondary_loop.hpp"
#include "monitor/turbine.hpp"
#include "mesh/texture.hpp"
#include "mesh/model.hpp"
#include "mesh/gllight.hpp"
#include "mesh/meshgen.hpp"
#include "monitor/cctv.hpp"
#include "data/texture.hpp"
#include "data/model.hpp"
#include "data/gllights.hpp"
#include "data/meshgen.hpp"
#include "data/material.hpp"
#include "equipment/reactor.hpp"
#include "equipment/generator.hpp"
#include "equipment/pool.hpp"
#include "../system.hpp"
#include "../util/streams.hpp"
#include "ui.hpp"
using namespace Sim;
using namespace Sim::Graphics;
using namespace Sim::Graphics::Data;
constexpr int SSBO_TRANSFORMS_LEN = 2;
static GLFWwindow* win;
static bool win_should_close = false;
static unsigned int ssbo_lights;
static unsigned int ssbo_shadow_maps;
static unsigned int ssbo_transforms[SSBO_TRANSFORMS_LEN];
static double secs_wait_at = 0;
static double secs_wait_now = 0;
static unsigned int wait_at = 0;
static int gm_dynamic_slow_at = 0;
static int ssbo_transforms_at = 0;
static Mesh g_scene;
static std::vector<glm::mat4> g_scene_transforms;
static GLMesh gm_scene;
static GLMesh gm_transparent;
static GLMesh gm_player;
static GLMesh gm_dynamic_slow[2];
static std::vector<GLLight> lights;
static std::vector<std::unique_ptr<MeshGen>> monitors;
static std::vector<std::unique_ptr<MeshGen>> equipment;
static std::unique_ptr<GLLights> lights;
static std::vector<MeshGen*> monitors;
static std::vector<MeshGen*> equipment;
static Monitor::CCTV* monitor_cctv;
glm::mat4 Window::projection_matrix;
@ -73,11 +80,32 @@ static void GLAPIENTRY cb_debug_message(GLenum source, GLenum type, GLuint id, G
}
}
void remesh_static()
{
Mesh mesh(g_scene);
for(auto& monitor : monitors)
{
monitor->remesh_static(mesh);
}
for(auto& equipment : equipment)
{
equipment->remesh_static(mesh);
}
gm_scene.bind();
gm_scene.set(mesh, GL_STATIC_DRAW);
g_scene_transforms = std::move(mesh.transforms);
std::cout << "Total triangle count: " << mesh.indices.size() / 3 << "\n";
}
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);
@ -101,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);
@ -128,80 +154,60 @@ void Window::create()
Mouse::init();
Resize::init();
Texture::init();
Font::init();
Fonts::init();
UI::init();
Shader::init();
Shader::MAIN.load("../assets/shader", "main.vsh", "main.fsh");
Shader::MAIN.use();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Sim::System& sys = *System::active;
Mesh m_scene, m_transparent;
Model model("../assets", "scene.glb");
m_transparent = model.load("visual_water");
m_scene = model.load("scene");
Mesh m_player = model.load("visual_player");
gm_player.bind();
gm_player.bind_ssbo();
gm_player.set(m_player, GL_STATIC_DRAW);
g_scene.add(model.load("cr"));
g_scene.add(model.load("cb"));
g_scene.add(model.load("hw"));
g_scene.bake_transforms();
Camera::init(model);
// send all the light data
glGenBuffers(1, &ssbo_lights);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_lights);
glBufferData(GL_SHADER_STORAGE_BUFFER, model.lights.size() * sizeof(model.lights[0]), &model.lights[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo_lights);
glUniform1i(Shader::MAIN["lights_count"], model.lights.size());
monitors.push_back(std::make_unique<Monitor::Core>(model));
monitors.push_back(std::make_unique<Monitor::Vessel>(model));
monitors.push_back(std::make_unique<Monitor::PrimaryLoop>(model));
monitors.push_back(std::make_unique<Monitor::SecondaryLoop>(model));
monitors.push_back(std::make_unique<Monitor::Turbine>(model));
equipment.push_back(std::make_unique<Equipment::Reactor>(model));
monitors.push_back(new Monitor::Core(model));
monitors.push_back(new Monitor::Vessel(model));
monitors.push_back(new Monitor::PrimaryLoop(model));
monitors.push_back(new Monitor::SecondaryLoop(model));
monitors.push_back(new Monitor::Turbine(model));
monitors.push_back(monitor_cctv = new Monitor::CCTV(model));
for(auto& monitor : monitors)
{
monitor->remesh_static(m_scene);
}
equipment.push_back(new Equipment::Reactor(model));
equipment.push_back(new Equipment::Generator(model));
equipment.push_back(new Equipment::Pool(model));
for(auto& equipment : equipment)
{
equipment->remesh_static(m_scene);
}
Texture::generate_atlas();
gm_scene.bind();
gm_scene.set(m_scene, GL_STATIC_DRAW);
gm_transparent.bind();
gm_transparent.set(m_transparent, GL_STATIC_DRAW);
remesh_static();
glfwShowWindow(win);
// setup lighting and prerender shadows
Shader::LIGHT.load("../assets/shader", "light.vsh", "light.gsh", "light.fsh");
Shader::LIGHT.use();
glUniform1f(Shader::LIGHT["far_plane"], 100.0f);
GLLight::init();
GLLights::init();
std::vector<unsigned long> light_handles;
for(int i = 0; i < model.lights.size(); i++)
{
GLLight light(model.lights[i]);
light.render();
light_handles.push_back(light.handle);
lights.push_back(std::move(light));
}
lights = std::make_unique<GLLights>(std::move(model.lights));
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, lights->ssbo);
Shader::MAIN.use();
glUniform1f(Shader::MAIN["far_plane"], 100.0f);
glUniform1i(Shader::MAIN["shadows_enabled"], 1);
// send all the light shadow map handles
glGenBuffers(1, &ssbo_shadow_maps);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_shadow_maps);
glBufferData(GL_SHADER_STORAGE_BUFFER, light_handles.size() * sizeof(light_handles[0]), &light_handles[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssbo_shadow_maps);
// setup the transforms ssbos and their initial values
std::vector<glm::mat4> transforms;
@ -239,6 +245,8 @@ void update_slow()
equipment->remesh_slow(mesh);
}
mesh.bake_transforms();
gm_dynamic_slow[gm_dynamic_slow_at].bind();
gm_dynamic_slow[gm_dynamic_slow_at].set(mesh, GL_DYNAMIC_DRAW);
gm_dynamic_slow_at = (gm_dynamic_slow_at + 1) % 2;
@ -246,6 +254,11 @@ void update_slow()
UI::update_slow();
}
void Window::reload()
{
remesh_static();
}
void Window::update(double dt)
{
Mesh mesh;
@ -265,69 +278,108 @@ void Window::update(double dt)
equipment->get_static_transforms(transforms);
}
for(int i = 0; i < transforms.size(); i++)
{
transforms[i] = g_scene_transforms[i] * transforms[i];
}
if(transforms.size() != g_scene_transforms.size())
{
std::cerr << "Transforms size mismatch! " << transforms.size() << " != " << g_scene_transforms.size() << "\n";
close();
}
UI::update(dt);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo_transforms[ssbo_transforms_at]);
ssbo_transforms_at = (ssbo_transforms_at + 1) % SSBO_TRANSFORMS_LEN;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_transforms[ssbo_transforms_at]);
glBufferData(GL_SHADER_STORAGE_BUFFER, transforms.size() * sizeof(transforms[0]), &transforms[0], GL_DYNAMIC_DRAW);
glBufferData(GL_SHADER_STORAGE_BUFFER, transforms.size() * sizeof(transforms[0]), &transforms[0], GL_STREAM_DRAW);
ssbo_transforms_at = (ssbo_transforms_at + 1) % SSBO_TRANSFORMS_LEN;
secs_wait_now += dt;
if(secs_wait_now > secs_wait_at + 1.0/30.0)
if(wait_at++ % 4 == 0)
{
secs_wait_at += 1.0/30.0;
update_slow();
}
}
void Window::render_player()
{
gm_player.bind();
gm_player.bind_ssbo();
gm_player.render();
}
void Window::bind_scene_ssbo()
{
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo_transforms[ssbo_transforms_at]);
}
void Window::render_scene()
{
gm_scene.bind();
gm_scene.uniform();
gm_scene.render();
gm_dynamic_slow[gm_dynamic_slow_at].bind();
gm_dynamic_slow[gm_dynamic_slow_at].uniform();
gm_dynamic_slow[gm_dynamic_slow_at].render();
gm_transparent.bind();
gm_transparent.uniform();
gm_transparent.render();
Focus::render();
}
void Window::render_dynamic()
{
gm_dynamic_slow[gm_dynamic_slow_at].bind();
gm_dynamic_slow[gm_dynamic_slow_at].render();
}
void Window::render()
{
glFrontFace(GL_CCW);
glm::vec<2, int> size = Resize::get_size();
glm::vec3 camera_pos = Camera::get_pos();
glm::mat4 mat_camera = Camera::get_matrix();
Shader::MAIN.use();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, size.x, size.y);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, lights->texid);
glUniform1i(Shader::MAIN["shadow_maps"], 0);
glm::vec3 brightness = glm::vec3(System::active->grid.get_light_intensity());
glm::mat4 mat_projection = glm::perspective(glm::radians(90.0f), Resize::get_aspect(), 0.01f, 100.f);
glUniformMatrix4fv(Shader::MAIN["projection"], 1, false, &mat_projection[0][0]);
glUniform3fv(Shader::MAIN["brightness"], 1, &brightness[0]);
glm::mat4 mat_player = glm::mat4(1);
mat_player = glm::translate(mat_player, glm::vec3(Camera::get_pos_base()));
mat_player = glm::rotate(mat_player, (float)glm::radians(90 - Camera::get_yaw()), glm::vec3(0, 0, 1));
glBindBuffer(GL_SHADER_STORAGE_BUFFER, gm_player.ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(glm::mat4), &mat_player, GL_STREAM_DRAW);
monitor_cctv->render_view();
glUniformMatrix4fv(Shader::MAIN["camera"], 1, false, &mat_camera[0][0]);
glUniform3fv(Shader::MAIN["camera_pos"], 1, &camera_pos[0]);
glUniform3fv(Shader::MAIN["brightness"], 1, &brightness[0]);
glUniformMatrix4fv(Shader::MAIN["projection"], 1, false, &mat_projection[0][0]);
projection_matrix = mat_projection;
glFrontFace(GL_CCW);
glClearColor(0, 0, 0, 1.0f);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glViewport(0, 0, size.x, size.y);
bind_scene_ssbo();
render_scene();
render_dynamic();
monitor_cctv->render_screen();
brightness = glm::vec3(1);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUniform3fv(Shader::MAIN["brightness"], 1, &brightness[0]);
UI::render();
Focus::render_ui();
glfwSwapBuffers(win);
Shader::LIGHT.use();
glFrontFace(GL_CW);
lights->render();
}
bool Window::should_close()

View File

@ -1,11 +1,12 @@
#pragma once
#include <GLFW/glfw3.h>
#include <glm/matrix.hpp>
#include "../system.hpp"
struct GLFWwindow;
namespace Sim::Graphics::Window
{
@ -13,10 +14,13 @@ extern glm::mat4 projection_matrix;
bool should_close();
void create();
void remesh();
void reload();
void update(double dt);
void render();
void bind_scene_ssbo();
void render_scene();
void render_dynamic();
void render_player();
void destroy();
void close();

View File

@ -10,7 +10,6 @@
#include "coolant/valve.hpp"
#include "coolant/pump.hpp"
#include "graphics/mesh/mesh.hpp"
#include "graphics/input/focus.hpp"
#include "graphics/window.hpp"

View File

@ -10,12 +10,14 @@
namespace Sim::Reactor
{
struct Reactor;
class Rod
{
public:
bool selected = false;
void* reactor = nullptr;
Reactor* reactor = nullptr;
static const int VAL_N = 3;
enum val_t

View File

@ -0,0 +1,4 @@
#define STB_RECT_PACK_IMPLEMENTATION
#include <stb/stb_rect_pack.h>

View File

@ -9,6 +9,7 @@
#include "reactor/coolant/pipe.hpp"
#include "reactor/coolant/heater.hpp"
#include "graphics/camera.hpp"
#include "graphics/window.hpp"
using namespace Sim;
@ -38,8 +39,9 @@ const char* CORE_LAYOUT[] = {
System::System() :
vessel(Coolant::WATER, 8, 10, 6e6, 5e5, 10),
reactor(Reactor::Builder(19, 19, 1.0 / 4.0, 4, Reactor::Fuel::FuelRod(0.5), &vessel, CORE_LAYOUT)),
reactor(Reactor::Builder(19, 19, 0.4, 4, Reactor::Fuel::FuelRod(0.5), &vessel, CORE_LAYOUT)),
evaporator(Coolant::WATER, 2, 30, 0, 1000),
pool(Coolant::WATER, {16, 32, 11.3}, 16, 1e5, 0),
sink(Coolant::WATER, 11, 0, 0),
grid(),
freight_pump(&sink, &evaporator, 1e5, 1, 1e4, 0.1, 10, Coolant::Pump::mode_t::DST, 1e6),
@ -54,6 +56,7 @@ System::System(const Json::Value& node) :
reactor(node["reactor"], &vessel),
grid(node["grid"]),
evaporator(node["evaporator"]),
pool(node["pool"]),
sink(evaporator.fluid, 11, 0, 0),
freight_pump(node["pump"]["freight"], &sink, &evaporator),
loop(node, &vessel, &evaporator, &grid)
@ -81,6 +84,7 @@ System::operator Json::Value() const
node["grid"] = grid;
node["vessel"] = vessel;
node["evaporator"] = evaporator;
node["pool"] = pool;
node["pump"]["freight"] = freight_pump;
node["reactor"] = reactor;
node["clock"] = clock;
@ -113,6 +117,8 @@ void System::load(const char* path)
Graphics::Camera::load(root["camera"]);
std::unique_ptr<System> sys = std::make_unique<System>(root);
active = std::move(sys);
Graphics::Window::reload();
}
void System::save()

View File

@ -8,6 +8,7 @@
#include "reactor/reactor.hpp"
#include "electric/grid.hpp"
#include "coolant/loop.hpp"
#include "coolant/pool.hpp"
namespace Sim
{
@ -20,6 +21,7 @@ struct System
Reactor::Reactor reactor;
Reactor::Coolant::Vessel vessel;
Coolant::Evaporator evaporator;
Coolant::Pool pool;
Coolant::Pump freight_pump;
Coolant::Sink sink;
Coolant::Loop loop;

View File

@ -19,13 +19,24 @@ constexpr double j_to_ms2(double j, double mass)
return m*std::sqrt(m * j / (mass * 0.001));
}
constexpr float map(float v, float imin, float imax, float omin, float omax)
template <typename A>
constexpr A map(A v, auto imin, auto imax, auto omin, auto omax)
{
return (v - imin) * (omax - omin) / (imax - imin) + omin;
}
template<typename A, typename B>
constexpr A mod(A a, B b)
template <typename A>
constexpr A clamp(A v, auto min, auto max)
{
if(v < min)
return min;
if(v > max)
return max;
return v;
}
template <typename A>
constexpr A mod(A a, auto b)
{
A v = std::fmod(a, b);
@ -37,5 +48,11 @@ constexpr A mod(A a, B 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);
}
};

View File

@ -5,6 +5,39 @@
#include <ostream>
#include <glm/matrix.hpp>
namespace glm
{
template <int N, typename T, glm::qualifier Q>
std::ostream& operator<<(std::ostream& o, const glm::vec<N, T, Q>& v)
{
o << "{";
for(int i = 0; i < N - 1; i++)
{
o << v[i] << ", ";
}
o << v[N - 1] << "}";
return o;
}
template <int N, int M, typename T, glm::qualifier Q>
std::ostream& operator<<(std::ostream& o, const glm::mat<N, M, T, Q>& m)
{
o << "{";
for(int i = 0; i < N - 1; i++)
{
o << " " << m[i] << ", ";
}
o << " " << m[N - 1] << "}";
return o;
}
};
namespace Sim::Util::Streams
{
@ -23,17 +56,3 @@ std::ostream& show_units(std::ostream& o, double v);
};
template <int N, typename T>
std::ostream& operator<<(std::ostream& o, const glm::vec<N, T>& v)
{
o << "{";
for(int i = 0; i < N - 1; i++)
{
o << v[i] << ", ";
}
o << v[N - 1] << "}";
return o;
}