reorganized repo to show clear module boundaries
|
@ -1,36 +1,4 @@
|
||||||
|
add_subdirectory(lib)
|
||||||
|
|
||||||
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
|
|
||||||
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
|
||||||
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
|
||||||
|
|
||||||
|
|
||||||
add_subdirectory(vendor/glad)
|
|
||||||
add_subdirectory(vendor/glfw-3.3.8)
|
|
||||||
|
|
||||||
find_package(OpenGL REQUIRED)
|
|
||||||
|
|
||||||
|
|
||||||
add_library(paradiso_core
|
|
||||||
lib/bitmap.hpp
|
|
||||||
lib/geometry.hpp
|
|
||||||
lib/sprite.hpp
|
|
||||||
lib/shader.hpp
|
|
||||||
lib/shader.cpp
|
|
||||||
lib/window.hpp
|
|
||||||
lib/window.cpp
|
|
||||||
lib/renderer.hpp
|
|
||||||
lib/renderer.cpp
|
|
||||||
lib/context.hpp
|
|
||||||
lib/context.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(
|
|
||||||
paradiso_core
|
|
||||||
PRIVATE
|
|
||||||
glfw
|
|
||||||
glad
|
|
||||||
)
|
|
||||||
|
|
||||||
set(paradiso_src
|
set(paradiso_src
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|
45
src/lib/CMakeLists.txt
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
|
||||||
|
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
|
add_subdirectory(src/vendor/glad)
|
||||||
|
add_subdirectory(src/vendor/glfw-3.3.8)
|
||||||
|
|
||||||
|
# find_package(OpenGL REQUIRED)
|
||||||
|
|
||||||
|
set(paradiso_srcs
|
||||||
|
src/shader.cpp
|
||||||
|
src/window.cpp
|
||||||
|
src/renderer.cpp
|
||||||
|
src/context.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(paradiso_incs
|
||||||
|
include/paradiso/bitmap.hpp
|
||||||
|
include/paradiso/geometry.hpp
|
||||||
|
include/paradiso/sprite.hpp
|
||||||
|
include/paradiso/shader.hpp
|
||||||
|
include/paradiso/window.hpp
|
||||||
|
include/paradiso/renderer.hpp
|
||||||
|
include/paradiso/context.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(paradiso_core
|
||||||
|
${paradiso_incs}
|
||||||
|
${paradiso_srcs}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
paradiso_core
|
||||||
|
PUBLIC
|
||||||
|
include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
paradiso_core
|
||||||
|
PRIVATE
|
||||||
|
glfw
|
||||||
|
glad
|
||||||
|
)
|
|
@ -5,7 +5,9 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace paradiso {
|
namespace paradiso {
|
||||||
|
|
||||||
struct Sprite;
|
struct Sprite;
|
||||||
|
struct Shader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief a Renderer2D for sprites
|
* @brief a Renderer2D for sprites
|
||||||
|
@ -16,7 +18,7 @@ struct Renderer final {
|
||||||
~Renderer();
|
~Renderer();
|
||||||
Renderer(const Renderer&) = delete;
|
Renderer(const Renderer&) = delete;
|
||||||
|
|
||||||
bool draw(const Sprite& m);
|
bool draw(const Sprite& sprite, const Shader& shader);
|
||||||
|
|
||||||
bool ready() const;
|
bool ready() const;
|
||||||
|
|
|
@ -23,11 +23,13 @@ struct Shader final {
|
||||||
void set_source(Type t, const std::string& c) { source_[t] = c; }
|
void set_source(Type t, const std::string& c) { source_[t] = c; }
|
||||||
std::string source(Type t) const { return source_.at(t); }
|
std::string source(Type t) const { return source_.at(t); }
|
||||||
|
|
||||||
bool ready() const;
|
|
||||||
|
|
||||||
bool build();
|
bool build();
|
||||||
|
|
||||||
void use();
|
bool ready() const;
|
||||||
|
|
||||||
|
void use() const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Shader& set_uniform_at_location(int location,
|
Shader& set_uniform_at_location(int location,
|
||||||
float v); //!< sets a float in a shader
|
float v); //!< sets a float in a shader
|
|
@ -1,308 +0,0 @@
|
||||||
#include "shader.hpp"
|
|
||||||
|
|
||||||
#include "glad/glad.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace paradiso
|
|
||||||
{
|
|
||||||
|
|
||||||
struct Shader::impl
|
|
||||||
{
|
|
||||||
std::reference_wrapper<Shader> _shader;
|
|
||||||
|
|
||||||
GLuint _shader_program;
|
|
||||||
std::vector<GLuint> _shader_stages;
|
|
||||||
|
|
||||||
impl(Shader &s)
|
|
||||||
: _shader(s)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~impl()
|
|
||||||
{
|
|
||||||
destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_valid()
|
|
||||||
{
|
|
||||||
// we potentially haul in is_valid while no context is given
|
|
||||||
return glIsProgram != nullptr && glIsProgram(_shader_program);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool build()
|
|
||||||
{
|
|
||||||
// if (!is_valid()) return false;
|
|
||||||
|
|
||||||
for (const auto &[type, code] : _shader.get().source_)
|
|
||||||
{
|
|
||||||
GLuint shader_type = 0;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case Shader::Type::Vertex:
|
|
||||||
shader_type = GL_VERTEX_SHADER;
|
|
||||||
break;
|
|
||||||
case Shader::Type::Compute:
|
|
||||||
shader_type = GL_COMPUTE_SHADER;
|
|
||||||
break;
|
|
||||||
case Shader::Type::Geometry:
|
|
||||||
shader_type = GL_GEOMETRY_SHADER;
|
|
||||||
break;
|
|
||||||
case Shader::Type::Fragment:
|
|
||||||
shader_type = GL_FRAGMENT_SHADER;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
std::cerr << " unknown shader type";
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint shaderId = glCreateShader(shader_type);
|
|
||||||
|
|
||||||
char *src = const_cast<char *>(code.c_str());
|
|
||||||
GLint size = static_cast<GLint>(code.length());
|
|
||||||
|
|
||||||
glShaderSource(shaderId, 1, &src, &size);
|
|
||||||
|
|
||||||
glCompileShader(shaderId);
|
|
||||||
|
|
||||||
GLint is_compiled = GL_FALSE;
|
|
||||||
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &is_compiled);
|
|
||||||
if (is_compiled == GL_FALSE)
|
|
||||||
{
|
|
||||||
|
|
||||||
GLint log_length;
|
|
||||||
|
|
||||||
glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &log_length);
|
|
||||||
|
|
||||||
std::vector<char> log_buffer(static_cast<size_t>(log_length));
|
|
||||||
|
|
||||||
glGetShaderInfoLog(shaderId, log_length, &log_length, log_buffer.data());
|
|
||||||
|
|
||||||
// TODO - handle errors!
|
|
||||||
std::cerr << log_buffer.data();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_shader_stages.push_back(shaderId);
|
|
||||||
}
|
|
||||||
|
|
||||||
_shader_program = glCreateProgram();
|
|
||||||
|
|
||||||
for (auto s : _shader_stages)
|
|
||||||
glAttachShader(_shader_program, s);
|
|
||||||
|
|
||||||
// TODO attribute binding ...
|
|
||||||
|
|
||||||
/* Bind attribute index 0 (coordinates) to in_Position and attribute index 1 (color) to in_Color */
|
|
||||||
/* Attribute locations must be setup before calling glLinkProgram. */
|
|
||||||
// glBindAttribLocation(shaderprogram, 0, "in_Position");
|
|
||||||
// glBindAttribLocation(shaderprogram, 1, "in_Color");
|
|
||||||
|
|
||||||
glLinkProgram(_shader_program);
|
|
||||||
|
|
||||||
GLint is_linked = 0;
|
|
||||||
glGetProgramiv(_shader_program, GL_LINK_STATUS, &is_linked);
|
|
||||||
if (is_linked == GL_FALSE)
|
|
||||||
{
|
|
||||||
|
|
||||||
GLint log_length;
|
|
||||||
|
|
||||||
/* Noticed that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv. */
|
|
||||||
glGetProgramiv(_shader_program, GL_INFO_LOG_LENGTH, &log_length);
|
|
||||||
|
|
||||||
/* The maxLength includes the NULL character */
|
|
||||||
std::vector<char> info_log(static_cast<size_t>(log_length));
|
|
||||||
|
|
||||||
/* Notice that glGetProgramInfoLog, not glGetShaderInfoLog. */
|
|
||||||
glGetProgramInfoLog(_shader_program, log_length, &log_length, info_log.data());
|
|
||||||
|
|
||||||
std::cerr << info_log.data();
|
|
||||||
|
|
||||||
/* Handle the error in an appropriate way such as displaying a message or writing to a log file. */
|
|
||||||
/* In this simple program, we'll just leave */
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void use()
|
|
||||||
{
|
|
||||||
glUseProgram(_shader_program);
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy()
|
|
||||||
{
|
|
||||||
// potentially the GL driver hasn't been loaded
|
|
||||||
if (is_valid())
|
|
||||||
{
|
|
||||||
|
|
||||||
// deleting and detaching should happen much earlier
|
|
||||||
|
|
||||||
for (auto s : _shader_stages)
|
|
||||||
{
|
|
||||||
glDeleteShader(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// only program needs to be deleted
|
|
||||||
|
|
||||||
glDeleteProgram(_shader_program);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int uniform_location(std::string const &name) const
|
|
||||||
{
|
|
||||||
return glGetUniformLocation(_shader_program, name.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// void bind(int location,const matrix3x3f& m)
|
|
||||||
// {
|
|
||||||
// glUniformMatrix3fv(location,1,GL_FALSE,m.ptr());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// void bind(int location,const matrix4x4f& m)
|
|
||||||
// {
|
|
||||||
// glUniformMatrix4fv(location,1,GL_FALSE,m.ptr());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// void bind(int location,const vector4f& v)
|
|
||||||
// {
|
|
||||||
// glUniform4fv(location,1,v.ptr());
|
|
||||||
// }
|
|
||||||
|
|
||||||
void bind(int location, const float &v)
|
|
||||||
{
|
|
||||||
glUniform1f(location, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bind(int location, const uint32_t &i)
|
|
||||||
{
|
|
||||||
glUniform1ui(location, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bind(int location, const int32_t &i)
|
|
||||||
{
|
|
||||||
glUniform1i(location, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// void bind(int location,const texture& v)
|
|
||||||
// {
|
|
||||||
// this->bind(location,(int)v.native_handle());
|
|
||||||
|
|
||||||
// }
|
|
||||||
};
|
|
||||||
|
|
||||||
Shader::Shader()
|
|
||||||
{
|
|
||||||
impl_ = std::make_unique<impl>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
Shader::~Shader()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Shader::ready() const
|
|
||||||
{
|
|
||||||
return impl_->is_valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
Shader &Shader::set_uniform_at_location(int location, float v)
|
|
||||||
{
|
|
||||||
impl_->bind(location, v);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Shader &Shader::set_uniform_at_location(int location, uint32_t v)
|
|
||||||
{
|
|
||||||
impl_->bind(location, v);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Shader &Shader::set_uniform_at_location(int location, int32_t v)
|
|
||||||
{
|
|
||||||
impl_->bind(location, v);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shader &Shader::set_uniform_at_location(int location, vector4f const &v)
|
|
||||||
// {
|
|
||||||
// impl_->bind(location, v);
|
|
||||||
// return *this;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Shader &Shader::set_uniform_at_location(int location, matrix4x4f const &v)
|
|
||||||
// {
|
|
||||||
// impl_->bind(location, v);
|
|
||||||
// return *this;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Shader &Shader::set_uniform_at_location(int location, texture const &v)
|
|
||||||
// {
|
|
||||||
// impl_->bind(location, v);
|
|
||||||
// return *this;
|
|
||||||
// }
|
|
||||||
|
|
||||||
bool Shader::build()
|
|
||||||
{
|
|
||||||
return impl_->build();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shader::use()
|
|
||||||
{
|
|
||||||
impl_->use();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shader::set_uniforms(uniform_cache_t c)
|
|
||||||
{
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// TODO rewrite in proper C++17
|
|
||||||
|
|
||||||
for (auto &u : c)
|
|
||||||
{
|
|
||||||
// get name
|
|
||||||
std::string name = std::get<0>(u);
|
|
||||||
// get location
|
|
||||||
GLint loc = std::get<2>(u);
|
|
||||||
|
|
||||||
// if lower 0 check for location
|
|
||||||
if (loc < 0)
|
|
||||||
{
|
|
||||||
loc = impl_->uniform_location(name);
|
|
||||||
std::get<2>(u) = loc; // cache location
|
|
||||||
}
|
|
||||||
|
|
||||||
auto var = std::get<1>(u);
|
|
||||||
|
|
||||||
std::visit([this, loc](auto &&arg)
|
|
||||||
{
|
|
||||||
|
|
||||||
using T = std::decay_t<decltype(arg)>;
|
|
||||||
|
|
||||||
// TODO query the std::variant of uniform_t
|
|
||||||
|
|
||||||
if constexpr ((std::is_same_v<T, vector4f>) ||
|
|
||||||
(std::is_same_v<T, matrix4x4f>) ||
|
|
||||||
(std::is_same_v<T, float>) ) {
|
|
||||||
set_uniform_at_location( loc, std::forward<T>(arg));
|
|
||||||
} else {
|
|
||||||
debug::e() << "unknown uniform type";
|
|
||||||
} },
|
|
||||||
var);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Shader::native_handle() const
|
|
||||||
{
|
|
||||||
return impl_->_shader_program;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Shader::uniform_location(const std::string &name) const
|
|
||||||
{
|
|
||||||
return impl_->uniform_location(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,10 +1,9 @@
|
||||||
|
|
||||||
#include "context.hpp"
|
#include "paradiso/context.hpp"
|
||||||
|
#include "paradiso/geometry.hpp"
|
||||||
|
|
||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
|
|
||||||
#include "geometry.hpp"
|
|
||||||
|
|
||||||
namespace paradiso {
|
namespace paradiso {
|
||||||
|
|
||||||
//
|
//
|
|
@ -1,15 +1,16 @@
|
||||||
|
|
||||||
#include "renderer.hpp"
|
#include "paradiso/renderer.hpp"
|
||||||
#include "bitmap.hpp"
|
#include "paradiso/bitmap.hpp"
|
||||||
#include "sprite.hpp"
|
#include "paradiso/sprite.hpp"
|
||||||
|
#include "paradiso/shader.hpp"
|
||||||
|
|
||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vector>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace paradiso {
|
namespace paradiso {
|
||||||
|
|
||||||
|
@ -52,8 +53,8 @@ struct Renderer::impl {
|
||||||
// indices -> elements
|
// indices -> elements
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer_obj);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer_obj);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||||
sprite.indices.size() * sizeof(uint32_t), sprite.indices.data(),
|
sprite.indices.size() * sizeof(uint32_t),
|
||||||
GL_STATIC_DRAW);
|
sprite.indices.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
vertex_buffer_ob.resize(vertex_buffer_ob.size() + 1);
|
vertex_buffer_ob.resize(vertex_buffer_ob.size() + 1);
|
||||||
glGenBuffers(1, &vertex_buffer_ob.back());
|
glGenBuffers(1, &vertex_buffer_ob.back());
|
||||||
|
@ -62,7 +63,8 @@ struct Renderer::impl {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_ob.back());
|
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_ob.back());
|
||||||
glVertexAttribPointer(vertex_buffer_ob.size() - 1, 3, GL_FLOAT,
|
glVertexAttribPointer(vertex_buffer_ob.size() - 1, 3, GL_FLOAT,
|
||||||
GL_FALSE, 0, nullptr);
|
GL_FALSE, 0, nullptr);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sprite.vertices.size() * sizeof(float) * 3,
|
glBufferData(GL_ARRAY_BUFFER,
|
||||||
|
sprite.vertices.size() * sizeof(float) * 3,
|
||||||
sprite.vertices.data(), GL_STATIC_DRAW);
|
sprite.vertices.data(), GL_STATIC_DRAW);
|
||||||
glEnableVertexAttribArray(vertex_buffer_ob.size() - 1);
|
glEnableVertexAttribArray(vertex_buffer_ob.size() - 1);
|
||||||
|
|
||||||
|
@ -92,9 +94,6 @@ struct Renderer::impl {
|
||||||
// stop binding
|
// stop binding
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
change_count = sprite.change_count;
|
change_count = sprite.change_count;
|
||||||
|
|
||||||
return ready();
|
return ready();
|
||||||
|
@ -117,11 +116,11 @@ struct Renderer::impl {
|
||||||
// setup new texture
|
// setup new texture
|
||||||
glTexImage2D(GL_TEXTURE_2D, // target
|
glTexImage2D(GL_TEXTURE_2D, // target
|
||||||
0, // level
|
0, // level
|
||||||
GL_RGB8, // internal format
|
GL_RGB, // internal format
|
||||||
image.size.width, // width
|
image.size.width, // width
|
||||||
image.size.height, // height
|
image.size.height, // height
|
||||||
0, // border
|
0, // border
|
||||||
GL_RGB, // format
|
GL_RGBA, // format
|
||||||
GL_UNSIGNED_BYTE, // type
|
GL_UNSIGNED_BYTE, // type
|
||||||
image.data.data() // pointer to data
|
image.data.data() // pointer to data
|
||||||
);
|
);
|
||||||
|
@ -145,7 +144,7 @@ struct Renderer::impl {
|
||||||
0, // y-offset
|
0, // y-offset
|
||||||
image.size.width, // width
|
image.size.width, // width
|
||||||
image.size.height, // height
|
image.size.height, // height
|
||||||
GL_RGB, // format
|
GL_RGBA, // format
|
||||||
GL_UNSIGNED_BYTE, // type
|
GL_UNSIGNED_BYTE, // type
|
||||||
image.data.data()); // pointer
|
image.data.data()); // pointer
|
||||||
}
|
}
|
||||||
|
@ -164,10 +163,10 @@ struct Renderer::impl {
|
||||||
// glDeleteTextures(1, &texture_id);
|
// glDeleteTextures(1, &texture_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void just_draw(const Sprite& sprite)
|
void just_draw(const Sprite& sprite) {
|
||||||
{
|
|
||||||
glBindVertexArray(vertex_array_obj);
|
glBindVertexArray(vertex_array_obj);
|
||||||
glDrawElements(GL_TRIANGLES, sprite.indices.size(), GL_UNSIGNED_INT, nullptr);
|
glDrawElements(GL_TRIANGLES, sprite.indices.size(), GL_UNSIGNED_INT,
|
||||||
|
nullptr);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,23 +189,24 @@ Renderer::~Renderer() {}
|
||||||
|
|
||||||
bool Renderer::ready() const { return impl_->ready(); }
|
bool Renderer::ready() const { return impl_->ready(); }
|
||||||
|
|
||||||
bool Renderer::draw(const Sprite& m)
|
bool Renderer::draw(const Sprite& sprite, const Shader& shader) {
|
||||||
{
|
|
||||||
if (!impl_->ready() || m.change_count != impl_->change_count)
|
// if interna are not ready or sprite has been altered - rebuild
|
||||||
{
|
if (!impl_->ready() || sprite.change_count != impl_->change_count) {
|
||||||
impl_->build(m);
|
impl_->build(sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// render the sprite with the shader
|
||||||
|
if (impl_->ready() && sprite.change_count == impl_->change_count) {
|
||||||
|
|
||||||
if (impl_->ready() && m.change_count == impl_->change_count) {
|
shader.use();
|
||||||
|
|
||||||
impl_->just_draw(m);
|
impl_->just_draw(sprite);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace paradiso
|
} // namespace paradiso
|
261
src/lib/src/shader.cpp
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
#include "paradiso/shader.hpp"
|
||||||
|
|
||||||
|
#include "glad/glad.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace paradiso {
|
||||||
|
|
||||||
|
struct Shader::impl {
|
||||||
|
std::reference_wrapper<Shader> _shader;
|
||||||
|
|
||||||
|
GLuint _shader_program;
|
||||||
|
std::vector<GLuint> _shader_stages;
|
||||||
|
|
||||||
|
impl(Shader& s) : _shader(s) {}
|
||||||
|
|
||||||
|
~impl() { destroy(); }
|
||||||
|
|
||||||
|
bool is_valid() {
|
||||||
|
// we potentially haul in is_valid while no context is given
|
||||||
|
return glIsProgram != nullptr && glIsProgram(_shader_program);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool build() {
|
||||||
|
// if (!is_valid()) return false;
|
||||||
|
|
||||||
|
for (const auto& [type, code] : _shader.get().source_) {
|
||||||
|
GLuint shader_type = 0;
|
||||||
|
switch (type) {
|
||||||
|
case Shader::Type::Vertex:
|
||||||
|
shader_type = GL_VERTEX_SHADER;
|
||||||
|
break;
|
||||||
|
case Shader::Type::Compute:
|
||||||
|
shader_type = GL_COMPUTE_SHADER;
|
||||||
|
break;
|
||||||
|
case Shader::Type::Geometry:
|
||||||
|
shader_type = GL_GEOMETRY_SHADER;
|
||||||
|
break;
|
||||||
|
case Shader::Type::Fragment:
|
||||||
|
shader_type = GL_FRAGMENT_SHADER;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cerr << " unknown shader type";
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint shaderId = glCreateShader(shader_type);
|
||||||
|
|
||||||
|
char* src = const_cast<char*>(code.c_str());
|
||||||
|
GLint size = static_cast<GLint>(code.length());
|
||||||
|
|
||||||
|
glShaderSource(shaderId, 1, &src, &size);
|
||||||
|
|
||||||
|
glCompileShader(shaderId);
|
||||||
|
|
||||||
|
GLint is_compiled = GL_FALSE;
|
||||||
|
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &is_compiled);
|
||||||
|
if (is_compiled == GL_FALSE) {
|
||||||
|
|
||||||
|
GLint log_length;
|
||||||
|
|
||||||
|
glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
|
||||||
|
std::vector<char> log_buffer(static_cast<size_t>(log_length));
|
||||||
|
|
||||||
|
glGetShaderInfoLog(shaderId, log_length, &log_length,
|
||||||
|
log_buffer.data());
|
||||||
|
|
||||||
|
// TODO - handle errors!
|
||||||
|
std::cerr << log_buffer.data();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_shader_stages.push_back(shaderId);
|
||||||
|
}
|
||||||
|
|
||||||
|
_shader_program = glCreateProgram();
|
||||||
|
|
||||||
|
for (auto s : _shader_stages)
|
||||||
|
glAttachShader(_shader_program, s);
|
||||||
|
|
||||||
|
// TODO attribute binding ...
|
||||||
|
|
||||||
|
/* Bind attribute index 0 (coordinates) to in_Position and attribute
|
||||||
|
* index 1 (color) to in_Color */
|
||||||
|
/* Attribute locations must be setup before calling glLinkProgram. */
|
||||||
|
// glBindAttribLocation(shaderprogram, 0, "in_Position");
|
||||||
|
// glBindAttribLocation(shaderprogram, 1, "in_Color");
|
||||||
|
|
||||||
|
glLinkProgram(_shader_program);
|
||||||
|
|
||||||
|
GLint is_linked = 0;
|
||||||
|
glGetProgramiv(_shader_program, GL_LINK_STATUS, &is_linked);
|
||||||
|
if (is_linked == GL_FALSE) {
|
||||||
|
|
||||||
|
GLint log_length;
|
||||||
|
|
||||||
|
/* Noticed that glGetProgramiv is used to get the length for a
|
||||||
|
* shader program, not glGetShaderiv. */
|
||||||
|
glGetProgramiv(_shader_program, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
|
||||||
|
/* The maxLength includes the NULL character */
|
||||||
|
std::vector<char> info_log(static_cast<size_t>(log_length));
|
||||||
|
|
||||||
|
/* Notice that glGetProgramInfoLog, not glGetShaderInfoLog. */
|
||||||
|
glGetProgramInfoLog(_shader_program, log_length, &log_length,
|
||||||
|
info_log.data());
|
||||||
|
|
||||||
|
std::cerr << info_log.data();
|
||||||
|
|
||||||
|
/* Handle the error in an appropriate way such as displaying a
|
||||||
|
* message or writing to a log file. */
|
||||||
|
/* In this simple program, we'll just leave */
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void use() const { glUseProgram(_shader_program); }
|
||||||
|
|
||||||
|
void destroy() {
|
||||||
|
// potentially the GL driver hasn't been loaded
|
||||||
|
if (is_valid()) {
|
||||||
|
|
||||||
|
// deleting and detaching should happen much earlier
|
||||||
|
|
||||||
|
for (auto s : _shader_stages) {
|
||||||
|
glDeleteShader(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// only program needs to be deleted
|
||||||
|
|
||||||
|
glDeleteProgram(_shader_program);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int uniform_location(std::string const& name) const {
|
||||||
|
return glGetUniformLocation(_shader_program, name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// void bind(int location,const matrix3x3f& m)
|
||||||
|
// {
|
||||||
|
// glUniformMatrix3fv(location,1,GL_FALSE,m.ptr());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void bind(int location,const matrix4x4f& m)
|
||||||
|
// {
|
||||||
|
// glUniformMatrix4fv(location,1,GL_FALSE,m.ptr());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void bind(int location,const vector4f& v)
|
||||||
|
// {
|
||||||
|
// glUniform4fv(location,1,v.ptr());
|
||||||
|
// }
|
||||||
|
|
||||||
|
void bind(int location, const float& v) { glUniform1f(location, v); }
|
||||||
|
|
||||||
|
void bind(int location, const uint32_t& i) { glUniform1ui(location, i); }
|
||||||
|
|
||||||
|
void bind(int location, const int32_t& i) { glUniform1i(location, i); }
|
||||||
|
|
||||||
|
// void bind(int location,const texture& v)
|
||||||
|
// {
|
||||||
|
// this->bind(location,(int)v.native_handle());
|
||||||
|
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
Shader::Shader() { impl_ = std::make_unique<impl>(*this); }
|
||||||
|
|
||||||
|
Shader::~Shader() {}
|
||||||
|
|
||||||
|
bool Shader::ready() const { return impl_->is_valid(); }
|
||||||
|
|
||||||
|
Shader& Shader::set_uniform_at_location(int location, float v) {
|
||||||
|
impl_->bind(location, v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader& Shader::set_uniform_at_location(int location, uint32_t v) {
|
||||||
|
impl_->bind(location, v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader& Shader::set_uniform_at_location(int location, int32_t v) {
|
||||||
|
impl_->bind(location, v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shader &Shader::set_uniform_at_location(int location, vector4f const &v)
|
||||||
|
// {
|
||||||
|
// impl_->bind(location, v);
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Shader &Shader::set_uniform_at_location(int location, matrix4x4f const &v)
|
||||||
|
// {
|
||||||
|
// impl_->bind(location, v);
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Shader &Shader::set_uniform_at_location(int location, texture const &v)
|
||||||
|
// {
|
||||||
|
// impl_->bind(location, v);
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
|
||||||
|
bool Shader::build() { return impl_->build(); }
|
||||||
|
|
||||||
|
void Shader::use() const { impl_->use(); }
|
||||||
|
|
||||||
|
void Shader::set_uniforms(uniform_cache_t c) {
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO rewrite in proper C++17
|
||||||
|
|
||||||
|
for (auto &u : c)
|
||||||
|
{
|
||||||
|
// get name
|
||||||
|
std::string name = std::get<0>(u);
|
||||||
|
// get location
|
||||||
|
GLint loc = std::get<2>(u);
|
||||||
|
|
||||||
|
// if lower 0 check for location
|
||||||
|
if (loc < 0)
|
||||||
|
{
|
||||||
|
loc = impl_->uniform_location(name);
|
||||||
|
std::get<2>(u) = loc; // cache location
|
||||||
|
}
|
||||||
|
|
||||||
|
auto var = std::get<1>(u);
|
||||||
|
|
||||||
|
std::visit([this, loc](auto &&arg)
|
||||||
|
{
|
||||||
|
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
|
||||||
|
// TODO query the std::variant of uniform_t
|
||||||
|
|
||||||
|
if constexpr ((std::is_same_v<T, vector4f>) ||
|
||||||
|
(std::is_same_v<T, matrix4x4f>) ||
|
||||||
|
(std::is_same_v<T, float>) ) {
|
||||||
|
set_uniform_at_location( loc, std::forward<T>(arg));
|
||||||
|
} else {
|
||||||
|
debug::e() << "unknown uniform type";
|
||||||
|
} },
|
||||||
|
var);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Shader::native_handle() const { return impl_->_shader_program; }
|
||||||
|
|
||||||
|
int Shader::uniform_location(const std::string& name) const {
|
||||||
|
return impl_->uniform_location(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace paradiso
|
Before Width: | Height: | Size: 676 B After Width: | Height: | Size: 676 B |
Before Width: | Height: | Size: 147 B After Width: | Height: | Size: 147 B |
Before Width: | Height: | Size: 132 B After Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 746 B After Width: | Height: | Size: 746 B |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 616 B After Width: | Height: | Size: 616 B |
Before Width: | Height: | Size: 597 B After Width: | Height: | Size: 597 B |