diff --git a/libs/gfx/include/psemek/gfx/renderer/simple.hpp b/libs/gfx/include/psemek/gfx/renderer/simple.hpp new file mode 100644 index 00000000..75e712a1 --- /dev/null +++ b/libs/gfx/include/psemek/gfx/renderer/simple.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include + +#include +#include + +namespace psemek::gfx +{ + + struct simple_renderer + { + // Attributes: + // 0: vec3 position + // 1: vec4 color (if uniform color is not set) + + struct render_state + { + drawable const * mesh = nullptr; + std::optional color; + }; + + struct render_object + { + virtual std::vector get_render_states() = 0; + + virtual ~render_object() {} + }; + + struct render_options + { + geom::matrix transform; + }; + + simple_renderer(); + ~simple_renderer(); + + void add(render_object * o); + void remove(render_object * o); + + void push(render_state s); + + void render(render_options const & opts); + + private: + struct impl; + std::unique_ptr pimpl_; + struct impl & impl() { return *pimpl_; } + struct impl const & impl() const { return *pimpl_; } + }; + +} diff --git a/libs/gfx/source/renderer/simple.cpp b/libs/gfx/source/renderer/simple.cpp new file mode 100644 index 00000000..e0a0f608 --- /dev/null +++ b/libs/gfx/source/renderer/simple.cpp @@ -0,0 +1,129 @@ +#include + +#include + +namespace psemek::gfx +{ + + static char const attrib_color_vertex_source[] = +R"(#version 330 + +uniform mat4 u_transform; + +layout (location = 0) in vec4 in_position; +layout (location = 1) in vec4 in_color; + +out vec4 color; + +void main() +{ + gl_Position = u_transform * in_position; + color = in_color; +} +)"; + + static char const uniform_color_vertex_source[] = +R"(#version 330 + +uniform mat4 u_transform; +uniform vec4 u_color; + +layout (location = 0) in vec4 in_position; + +out vec4 color; + +void main() +{ + gl_Position = u_transform * in_position; + color = u_color; +} +)"; + + static char const fragment_source[] = +R"(#version 330 + +in vec4 color; +out vec4 out_color; + +void main() +{ + out_color = color; +} +)"; + + struct simple_renderer::impl + { + program attrib_color_program{attrib_color_vertex_source, fragment_source}; + program uniform_color_program{uniform_color_vertex_source, fragment_source}; + + std::vector objects; + std::vector attrib_color_states; + std::vector uniform_color_states; + }; + + simple_renderer::simple_renderer() + : pimpl_{std::make_unique()} + {} + + simple_renderer::~simple_renderer() = default; + + void simple_renderer::add(render_object * o) + { + impl().objects.push_back(o); + } + + void simple_renderer::remove(render_object * o) + { + auto it = std::find(impl().objects.begin(), impl().objects.end(), o); + if (it != impl().objects.end()) + impl().objects.erase(it); + } + + void simple_renderer::push(render_state s) + { + if (s.mesh) + { + if (s.color) + impl().uniform_color_states.push_back(s); + else + impl().attrib_color_states.push_back(s); + } + } + + void simple_renderer::render(render_options const & opts) + { + for (auto o : impl().objects) + { + for (auto const & s : o->get_render_states()) + push(s); + } + + if (!impl().attrib_color_states.empty()) + { + impl().attrib_color_program.bind(); + impl().attrib_color_program["u_transform"] = opts.transform; + + for (auto const & s : impl().attrib_color_states) + { + s.mesh->draw(); + } + + impl().attrib_color_states.clear(); + } + + if (!impl().uniform_color_states.empty()) + { + impl().uniform_color_program.bind(); + impl().uniform_color_program["u_transform"] = opts.transform; + + for (auto const & s : impl().uniform_color_states) + { + impl().uniform_color_program["u_color"] = to_colorf(*s.color); + s.mesh->draw(); + } + + impl().uniform_color_states.clear(); + } + } + +}