#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 color_fragment_source[] = R"(#version 330 in vec4 color; out vec4 out_color; void main() { out_color = color; } )"; static char const textured_vertex_source[] = R"(#version 330 uniform mat4 u_transform; layout (location = 0) in vec4 in_position; layout (location = 2) in vec2 in_texcoord; out vec2 texcoord; void main() { gl_Position = u_transform * in_position; texcoord = in_texcoord; } )"; static char const textured_fragment_source[] = R"(#version 330 uniform sampler2D u_texture; in vec2 texcoord; out vec4 out_color; void main() { out_color = texture(u_texture, texcoord); } )"; struct simple_renderer::impl { program attrib_color_program{attrib_color_vertex_source, color_fragment_source}; program uniform_color_program{uniform_color_vertex_source, color_fragment_source}; program textured_program{textured_vertex_source, textured_fragment_source}; std::vector objects; std::vector attrib_color_states; std::vector uniform_color_states; std::vector textured_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.texture) impl().textured_states.push_back(s); else 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(); } if (!impl().textured_states.empty()) { impl().textured_program.bind(); impl().textured_program["u_transform"] = opts.transform; impl().textured_program["u_texture"] = 0; gl::ActiveTexture(gl::TEXTURE0); for (auto const & s : impl().textured_states) { s.texture->bind(); s.mesh->draw(); } impl().textured_states.clear(); } } }