psemek/libs/gfx/source/renderer/simple.cpp

180 lines
3.5 KiB
C++

#include <psemek/gfx/renderer/simple.hpp>
#include <psemek/gfx/program.hpp>
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<render_object *> objects;
std::vector<render_state> attrib_color_states;
std::vector<render_state> uniform_color_states;
std::vector<render_state> textured_states;
};
simple_renderer::simple_renderer()
: pimpl_{make_impl()}
{}
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();
}
}
}