working renderering

main
Brett 2023-12-28 16:14:12 -05:00
parent cec16931f2
commit f9766d1a84
10 changed files with 265 additions and 99 deletions

View File

@ -41,14 +41,20 @@ namespace blt::gfx
{ {
GLuint bufferID_ = 0; GLuint bufferID_ = 0;
GLsizeiptr size_ = 0; GLsizeiptr size_ = 0;
GLint buffer_type; GLint buffer_type = 0;
GLint memory_type; GLint memory_type = 0;
void create(GLint type); void create(GLint type = GL_ARRAY_BUFFER);
void bind() const; void bind() const;
void allocate(GLsizeiptr size, GLint memory_type = GL_STATIC_DRAW, void* data = nullptr); void allocate(GLsizeiptr size, GLint mem_type = GL_STATIC_DRAW, const void* data = nullptr);
template<typename T>
void allocate(GLsizeiptr size, const T* data, GLint mem_type = GL_STATIC_DRAW)
{
allocate(size, mem_type, static_cast<const void*>(data));
}
void sub_update(GLsizeiptr offset, GLsizeiptr size, void* data); void sub_update(GLsizeiptr offset, GLsizeiptr size, void* data);
@ -105,7 +111,7 @@ namespace blt::gfx
private: private:
GLuint vaoID; GLuint vaoID;
static_dynamic_array VBOs; static_dynamic_array VBOs;
HASHSET<GLuint> used_attributes; HASHSET <GLuint> used_attributes;
vbo_t element; vbo_t element;
public: public:
vertex_array(); vertex_array();
@ -125,10 +131,24 @@ namespace blt::gfx
* @param coordinate_size size of the data (number of * @param coordinate_size size of the data (number of
* @param type type of data * @param type type of data
* @param stride how many bytes this data takes (for the entire per-vertex data structure) 0 will assume packed data * @param stride how many bytes this data takes (for the entire per-vertex data structure) 0 will assume packed data
* This is in effect how many bytes until the next block of data
* @param offset offset into the data structure to where the data is stored * @param offset offset into the data structure to where the data is stored
*/ */
void bindVBO(const vbo_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset); void bindVBO(const vbo_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
inline void bindElement(const vbo_t& vbo)
{
bind();
element = vbo;
vbo.bind();
unbind();
}
inline vbo_t& getElement()
{
return element;
}
/** /**
* Returns a non-owning reference to a vbo allowing for updating the VBO * Returns a non-owning reference to a vbo allowing for updating the VBO
* The VBO is considered invalid if its ID is 0 * The VBO is considered invalid if its ID is 0
@ -143,6 +163,11 @@ namespace blt::gfx
glBindVertexArray(vaoID); glBindVertexArray(vaoID);
} }
static inline void unbind()
{
glBindVertexArray(0);
}
~vertex_array(); ~vertex_array();
}; };

View File

@ -64,7 +64,7 @@ namespace blt::gfx
} }
}; };
class shader_base class shader_base_t
{ {
friend uniform_buffer; friend uniform_buffer;
protected: protected:
@ -139,12 +139,12 @@ namespace blt::gfx
/** /**
* a basic computer shader class, contains the functions and resources required to use compute shaders! * a basic computer shader class, contains the functions and resources required to use compute shaders!
*/ */
class compute_shader : public shader_base class compute_shader_t : public shader_base_t
{ {
private: private:
GLuint shaderID = 0; GLuint shaderID = 0;
public: public:
explicit compute_shader(const std::string& shader_source, bool loadAsString = true); explicit compute_shader_t(const std::string& shader_source, bool loadAsString = true);
inline void execute(int x, int y, int z) const inline void execute(int x, int y, int z) const
{ {
@ -152,10 +152,10 @@ namespace blt::gfx
glDispatchCompute(x, y, z); glDispatchCompute(x, y, z);
} }
~compute_shader(); ~compute_shader_t();
}; };
class shader : public shader_base class shader_t : public shader_base_t
{ {
private: private:
GLuint vertexShaderID = 0; GLuint vertexShaderID = 0;
@ -171,9 +171,9 @@ namespace blt::gfx
* @param geometry geometry shader source or file (optional) * @param geometry geometry shader source or file (optional)
* @param load_as_string load the shader as a string (true) or use the string to load the shader as a file (false) * @param load_as_string load the shader as a string (true) or use the string to load the shader as a file (false)
*/ */
shader(const std::string& vertex, const std::string& fragment, bool load_as_string = true); shader_t(const std::string& vertex, const std::string& fragment, bool load_as_string = true);
shader(shader&& move) noexcept; shader_t(shader_t&& move) noexcept;
// used to set the location of VAOs to the in variables in opengl shaders. // used to set the location of VAOs to the in variables in opengl shaders.
void bindAttribute(int attribute, const std::string& name) const; void bindAttribute(int attribute, const std::string& name) const;
@ -181,7 +181,7 @@ namespace blt::gfx
// used to set location of shared UBOs like the perspective and view matrix // used to set location of shared UBOs like the perspective and view matrix
void setUniformBlockLocation(const std::string& name, int location) const; void setUniformBlockLocation(const std::string& name, int location) const;
~shader(); ~shader_t();
}; };
} }

View File

@ -42,7 +42,7 @@ namespace blt::gfx
texture_data(int width, int height, int channels = 4): m_width(width), m_height(height), m_channels(channels) texture_data(int width, int height, int channels = 4): m_width(width), m_height(height), m_channels(channels)
{ {
m_data = static_cast<unsigned char*>(STBI_MALLOC(width * height * channels)); m_data = static_cast<unsigned char*>(std::malloc(width * height * channels));
} }
texture_data() = default; texture_data() = default;
@ -74,7 +74,7 @@ namespace blt::gfx
~texture_data() ~texture_data()
{ {
STBI_FREE(m_data); std::free(m_data);
} }
}; };
@ -127,12 +127,8 @@ namespace blt::gfx
GLint textureColorMode; GLint textureColorMode;
int m_width, m_height; int m_width, m_height;
texture_gl( texture_gl(int width, int height, GLint bind_type = GL_TEXTURE_2D, GLint color_mode = GL_RGBA):
int width, int height, GLint bind_type = GL_TEXTURE_2D, textureBindType(bind_type), textureColorMode(color_mode), m_width(width), m_height(height)
GLint color_mode = GL_RGBA
):
textureBindType(bind_type), textureColorMode(color_mode), m_width(width),
m_height(height)
{ {
glGenTextures(1, &textureID); glGenTextures(1, &textureID);
} }
@ -144,6 +140,7 @@ namespace blt::gfx
{ {
glGenerateMipmap(textureBindType); glGenerateMipmap(textureBindType);
} }
public: public:
inline void bind() const inline void bind() const
{ {
@ -169,51 +166,19 @@ namespace blt::gfx
struct texture_gl2D : public texture_gl struct texture_gl2D : public texture_gl
{ {
public: public:
texture_gl2D(int width, int height, GLint colorMode = GL_RGBA): texture_gl2D(const texture_data& data);
texture_gl(width, height, GL_TEXTURE_2D, colorMode)
{ texture_gl2D(int width, int height, GLint colorMode = GL_RGBA8);
bind();
setDefaults();
// TODO:
const int MIPMAP_LEVELS = 4;
glTexStorage2D(
textureBindType, MIPMAP_LEVELS, colorMode,
width, height
);
}
void upload(void* data, GLint dataColorMode = GL_RGBA, int level = 0, int x_offset = 0, int y_offset = 0, int sub_width = -1, void upload(void* data, GLint dataColorMode = GL_RGBA, int level = 0, int x_offset = 0, int y_offset = 0, int sub_width = -1,
int sub_height = -1) const int sub_height = -1) const;
{
if (sub_width < 0)
sub_width = m_width;
if (sub_height < 0)
sub_height = m_height;
bind();
glTexSubImage2D(
textureBindType, level, x_offset, y_offset, sub_width, sub_height,
dataColorMode, GL_UNSIGNED_BYTE, data
);
generateMipmaps();
unbind();
}
void upload(const texture_file& tex_file) const void upload(const texture_file& tex_file) const;
{
upload(tex_file.texture().data(), tex_file.channels() == 4 ? GL_RGBA : GL_RGB, 0, 0, 0, tex_file.width(), tex_file.height());
}
/** /**
* Resizes the internal memory for the texture but does NOT resize the texture image stored * Resizes the internal memory for the texture but does NOT resize the texture image stored
*/ */
inline void resize(int width, int height) inline void resize(int width, int height);
{
m_width = width;
m_height = height;
bind();
glTexStorage2D(textureBindType, 0, textureColorMode, m_width, m_height);
unbind();
}
}; };
struct gl_texture2D_array : public texture_gl struct gl_texture2D_array : public texture_gl
@ -221,31 +186,10 @@ namespace blt::gfx
protected: protected:
int m_layers; int m_layers;
public: public:
gl_texture2D_array(int width, int height, int layers, GLint colorMode = GL_RGBA8): gl_texture2D_array(int width, int height, int layers, GLint colorMode = GL_RGBA8);
texture_gl(width, height, GL_TEXTURE_2D_ARRAY, colorMode), m_layers(layers)
{
bind();
setDefaults();
// 6+ mipmaps is about where I stop noticing any difference (size is 4x4 pixels, so that makes sense)
glTexStorage3D(textureBindType, 6, colorMode, width, height, layers);
BLT_DEBUG("Creating 2D Texture Array with ID: %d", textureID);
}
void upload(void* data, int index, GLint dataColorMode = GL_RGBA, int level = 0, int x_offset = 0, int y_offset = 0, int sub_width = -1, void upload(void* data, int index, GLint dataColorMode = GL_RGBA, int level = 0, int x_offset = 0, int y_offset = 0, int sub_width = -1,
int sub_height = -1) const int sub_height = -1) const;
{
if (sub_width < 0)
sub_width = m_width;
if (sub_height < 0)
sub_height = m_height;
bind();
glTexSubImage3D(
textureBindType, level, x_offset, y_offset, index, sub_width, sub_height, 1,
dataColorMode, GL_UNSIGNED_BYTE, data
);
generateMipmaps();
unbind();
}
}; };
class gl_buffer_texture : public texture_gl2D class gl_buffer_texture : public texture_gl2D

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -29,21 +29,19 @@ namespace blt::gfx
if (std::holds_alternative<vbo_t*>(data_)) if (std::holds_alternative<vbo_t*>(data_))
{ {
auto* ptr = std::get<vbo_t*>(data_); auto* ptr = std::get<vbo_t*>(data_);
std::memcpy(new_data, ptr, size_); std::memcpy(new_data, ptr, sizeof(vbo_t) * size_);
delete[] ptr; delete[] ptr;
} else { } else
{
auto data = std::get<array_t>(data_); auto data = std::get<array_t>(data_);
std::memcpy(new_data, data.data(), DATA_SIZE); std::memcpy(new_data, data.data(), sizeof(vbo_t) * DATA_SIZE);
} }
data_ = new_data; data_ = new_data;
size_ = next_size; size_ = next_size;
} }
static_dynamic_array::static_dynamic_array() static_dynamic_array::static_dynamic_array()
{ {}
auto ptr = std::get<array_t>(data_);
std::memset(ptr.data(), 0, DATA_SIZE);
}
vbo_t& static_dynamic_array::operator[](size_t index) vbo_t& static_dynamic_array::operator[](size_t index)
{ {
@ -72,8 +70,9 @@ namespace blt::gfx
glDeleteBuffers(1, &bufferID_); glDeleteBuffers(1, &bufferID_);
} }
void vbo_t::allocate(GLsizeiptr size, GLint mem_type, void* data) void vbo_t::allocate(GLsizeiptr size, GLint mem_type, const void* data)
{ {
bind();
size_ = size; size_ = size;
glBufferData(buffer_type, size, data, mem_type); glBufferData(buffer_type, size, data, mem_type);
memory_type = mem_type; memory_type = mem_type;
@ -90,6 +89,7 @@ namespace blt::gfx
void vbo_t::sub_update(GLsizeiptr offset, GLsizeiptr size, void* data) void vbo_t::sub_update(GLsizeiptr offset, GLsizeiptr size, void* data)
{ {
bind();
glBufferSubData(buffer_type, offset, size, data); glBufferSubData(buffer_type, offset, size, data);
} }
@ -131,5 +131,7 @@ namespace blt::gfx
glEnableVertexAttribArray(attribute_number); glEnableVertexAttribArray(attribute_number);
VBOs[attribute_number] = vbo; VBOs[attribute_number] = vbo;
unbind();
} }
} }

View File

@ -34,7 +34,7 @@ namespace blt::gfx
return new_source_string; return new_source_string;
} }
unsigned int shader::createShader(const std::string& source, int type) { unsigned int shader_t::createShader(const std::string& source, int type) {
const char* shader_code = source.c_str(); const char* shader_code = source.c_str();
// creates a Shader // creates a Shader
unsigned int shaderID = glCreateShader(type); unsigned int shaderID = glCreateShader(type);
@ -68,7 +68,7 @@ namespace blt::gfx
return shaderID; return shaderID;
} }
shader::shader(const std::string& vertex, const std::string& fragment, bool load_as_string) { shader_t::shader_t(const std::string& vertex, const std::string& fragment, bool load_as_string) {
// load shader sources // load shader sources
std::string vertex_source = vertex; std::string vertex_source = vertex;
std::string fragment_source = fragment; std::string fragment_source = fragment;
@ -118,12 +118,12 @@ namespace blt::gfx
glUseProgram(0); glUseProgram(0);
} }
void shader::bindAttribute(int attribute, const std::string &name) const { void shader_t::bindAttribute(int attribute, const std::string &name) const {
bind(); bind();
glBindAttribLocation(programID, attribute, name.c_str()); glBindAttribLocation(programID, attribute, name.c_str());
} }
void shader::setUniformBlockLocation(const std::string &name, int location) const { void shader_t::setUniformBlockLocation(const std::string &name, int location) const {
bind(); bind();
auto blockID = glGetUniformBlockIndex(programID, name.c_str()); auto blockID = glGetUniformBlockIndex(programID, name.c_str());
if (blockID != GL_INVALID_INDEX) if (blockID != GL_INVALID_INDEX)
@ -132,7 +132,7 @@ namespace blt::gfx
BLT_WARN("Unable to find uniform buffer '%s'. Did you forget to declare it?", name.c_str()); BLT_WARN("Unable to find uniform buffer '%s'. Did you forget to declare it?", name.c_str());
} }
shader::~shader() { shader_t::~shader_t() {
glUseProgram(0); glUseProgram(0);
// shader was moved // shader was moved
if (programID <= 0) if (programID <= 0)
@ -149,7 +149,7 @@ namespace blt::gfx
glDeleteProgram(programID); glDeleteProgram(programID);
} }
shader::shader(shader&& move) noexcept { shader_t::shader_t(shader_t&& move) noexcept {
// the move constructor doesn't need to construct a new shader but it does need to ensure all old variables are moved over // the move constructor doesn't need to construct a new shader but it does need to ensure all old variables are moved over
programID = move.programID; programID = move.programID;
vertexShaderID = move.vertexShaderID; vertexShaderID = move.vertexShaderID;

View File

@ -21,20 +21,25 @@
#define STB_PERLIN_IMPLEMENTATION #define STB_PERLIN_IMPLEMENTATION
#include <blt/gfx/stb/stb_image_write.h> #include <blt/gfx/stb/stb_image_write.h>
#if defined(__GNUC__) || defined(__GNUG__) #if defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds" #pragma GCC diagnostic ignored "-Warray-bounds"
#include <blt/gfx/stb/stb_image_resize2.h> #include <blt/gfx/stb/stb_image_resize2.h>
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#else #else
#include <blt/gfx/stb/stb_image_resize2.h> #include <blt/gfx/stb/stb_image_resize2.h>
#endif #endif
#include <blt/gfx/stb/stb_image.h> #include <blt/gfx/stb/stb_image.h>
#include <blt/gfx/stb/stb_perlin.h> #include <blt/gfx/stb/stb_perlin.h>
#include <blt/gfx/texture.h> #include <blt/gfx/texture.h>
blt::gfx::texture_file::texture_file(const std::string& path, const std::string& name): m_name(name.empty() ? path : name), m_path(path) blt::gfx::texture_file::texture_file(const std::string& path, const std::string& name): m_name(name.empty() ? path : name), m_path(path)
{ {
stbi_set_flip_vertically_on_load(true);
m_texture.m_data = stbi_load( m_texture.m_data = stbi_load(
m_path.c_str(), m_path.c_str(),
reinterpret_cast<int*>(&m_texture.m_width), reinterpret_cast<int*>(&m_texture.m_height), reinterpret_cast<int*>(&m_texture.m_width), reinterpret_cast<int*>(&m_texture.m_height),
@ -89,3 +94,74 @@ void blt::gfx::texture_gl::setDefaults() const
glTexParameterf(textureBindType, GL_TEXTURE_MAX_ANISOTROPY_EXT, a); glTexParameterf(textureBindType, GL_TEXTURE_MAX_ANISOTROPY_EXT, a);
#endif #endif
} }
void blt::gfx::texture_gl2D::upload(void* data, GLint dataColorMode, int level, int x_offset, int y_offset, int sub_width, int sub_height) const
{
if (sub_width < 0)
sub_width = m_width;
if (sub_height < 0)
sub_height = m_height;
bind();
glTexSubImage2D(textureBindType, level, x_offset, y_offset, sub_width, sub_height, dataColorMode, GL_UNSIGNED_BYTE, data);
unbind();
}
void blt::gfx::texture_gl2D::upload(const blt::gfx::texture_file& tex_file) const
{
upload(tex_file.texture().data(), tex_file.channels() == 4 ? GL_RGBA : GL_RGB, 0, 0, 0, tex_file.width(), tex_file.height());
}
void blt::gfx::texture_gl2D::resize(int width, int height)
{
m_width = width;
m_height = height;
bind();
glTexStorage2D(textureBindType, 0, textureColorMode, m_width, m_height);
unbind();
}
blt::gfx::texture_gl2D::texture_gl2D(int width, int height, GLint colorMode): texture_gl(width, height, GL_TEXTURE_2D, colorMode)
{
bind();
setDefaults();
// TODO:
const int MIPMAP_LEVELS = 4;
glTexStorage2D(textureBindType, MIPMAP_LEVELS, colorMode, width, height);
}
blt::gfx::texture_gl2D::texture_gl2D(const blt::gfx::texture_data& data): texture_gl(data.width(), data.height(), GL_TEXTURE_2D, GL_RGBA8)
{
bind();
setDefaults();
glTexStorage2D(textureBindType, 4, GL_RGBA8, data.width(), data.height());
upload((void*) data.data(), data.channels() == 4 ? GL_RGBA : GL_RGB, 0, 0, 0, data.width(), data.height());
bind();
//glTexImage2D(textureBindType, 0, GL_RGBA, data.width(), data.height(), 0, data.channels() == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, (void*)data.data());
generateMipmaps();
unbind();
}
void blt::gfx::gl_texture2D_array::upload(void* data, int index, GLint dataColorMode, int level, int x_offset, int y_offset, int sub_width,
int sub_height) const
{
if (sub_width < 0)
sub_width = m_width;
if (sub_height < 0)
sub_height = m_height;
bind();
glTexSubImage3D(
textureBindType, level, x_offset, y_offset, index, sub_width, sub_height, 1,
dataColorMode, GL_UNSIGNED_BYTE, data
);
generateMipmaps();
unbind();
}
blt::gfx::gl_texture2D_array::gl_texture2D_array(int width, int height, int layers, GLint colorMode): texture_gl(width, height, layers, colorMode)
{
bind();
setDefaults();
// 6+ mipmaps is about where I stop noticing any difference (size is 4x4 pixels, so that makes sense)
glTexStorage3D(textureBindType, 6, colorMode, width, height, layers);
BLT_DEBUG("Creating 2D Texture Array with ID: %d", textureID);
}

View File

@ -0,0 +1,23 @@
#ifdef __cplusplus
#include <string>
std::string shader_test_frag = R"("
#version 300 es
precision mediump float;
out vec4 FragColor;
in vec2 uv;
in vec2 pos;
uniform sampler2D tex;
vec4 linear_iter(vec4 i, vec4 p, float factor){
return (i + p) * factor;
}
void main() {
//FragColor = vec4(pos, 0.0, 1.0f);
FragColor = linear_iter(texture(tex, uv), vec4(pos, 0.0, 1.0), (uv.x + uv.y + 1.0) / 3.0);
}
")";
#endif

View File

@ -0,0 +1,29 @@
#ifdef __cplusplus
#include <string>
std::string shader_test_vert = R"("
#version 300 es
precision mediump float;
layout (location = 0) in vec3 vertex;
layout (location = 1) in vec2 uv_in;
out vec2 pos;
out vec2 uv;
layout (std140) uniform GlobalMatrices
{
mat4 projection;
mat4 view;
// projection view matrix
mat4 pvm;
};
void main() {
//gl_Position = projection * view * vec4(vertex.x, vertex.y, vertex.z, 1.0);
gl_Position = vec4(vertex, 1.0);
pos = vertex.xy;
uv = uv_in;
}
")";
#endif

View File

@ -1,12 +1,65 @@
#include <iostream>
#include <blt/gfx/window.h> #include <blt/gfx/window.h>
#include <blt/gfx/shader.h>
#include <blt/gfx/texture.h>
#include <blt/gfx/model.h>
#include <blt/std/logging.h>
#include <imgui.h> #include <imgui.h>
#include "blt/gfx/imgui/IconsFontAwesome5.h" #include "blt/gfx/imgui/IconsFontAwesome5.h"
#include <shaders/test.vert>
#include <shaders/test.frag>
const float raw_vertices[18] = {
// first triangle
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, 0.5f, 0.0f, // top left
// second triangle
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
float vertices[20] = {
// positions // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left
};
const unsigned int indices[6] = { // note that we start from 0!
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
blt::gfx::vertex_array* vao;
blt::gfx::shader_t* shader;
blt::gfx::texture_gl2D* texture;
void init() void init()
{ {
using namespace blt::gfx;
vbo_t vertices_vbo;
vbo_t indices_vbo;
vertices_vbo.create();
indices_vbo.create(GL_ELEMENT_ARRAY_BUFFER);
vertices_vbo.allocate(sizeof(vertices), vertices);
indices_vbo.allocate(sizeof(indices), indices);
vao = new vertex_array();
vao->bindVBO(vertices_vbo, 0, 3, GL_FLOAT, 5 * sizeof(float), 0);
vao->bindVBO(vertices_vbo, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
vao->bindElement(indices_vbo);
shader = new shader_t(shader_test_vert, shader_test_frag);
shader->bindAttribute(0, "vertex");
shader->bindAttribute(1, "uv_in");
texture_file file("../resources/textures/cumdollar.jpg");
texture = new texture_gl2D(file.texture());
} }
void update(std::int32_t width, std::int32_t height) void update(std::int32_t width, std::int32_t height)
@ -15,11 +68,25 @@ void update(std::int32_t width, std::int32_t height)
ImGui::Text("%s among %d items", ICON_FA_FILE, 0); ImGui::Text("%s among %d items", ICON_FA_FILE, 0);
ImGui::Button(ICON_FA_SEARCH " Search"); ImGui::Button(ICON_FA_SEARCH " Search");
ImGui::End(); ImGui::End();
shader->bind();
glActiveTexture(GL_TEXTURE0);
texture->bind();
vao->bind();
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
} }
int main() int main()
{ {
blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update}.setSyncInterval(1)); blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update}.setSyncInterval(1));
delete vao;
delete shader;
delete texture;
blt::gfx::cleanup(); blt::gfx::cleanup();
return 0; return 0;
} }