#include "GameRenderer.h" #include "client.hpp" #include namespace games { template std::vector from_strarray(const char* const (& strs)[N]) { std::vector v(N); for(size_t i = 0; i < N; ++i){ v.push_back(strs[i]); } return v; } using namespace moggle; using namespace motor; GameRenderer::GameRenderer(int w, int h) : ball_texture(::bundle.get_texture_path() + "bol.png") { gl::enable(GL_LINE_SMOOTH); glLineWidth(1.5f); glPointSize(4.0f); load_shaders(); fbo1 = std::make_shared(w, h); fbo2 = std::make_shared(w, h); } void GameRenderer::load_shaders(){ auto load_shader = [](Shader & shader, std::string file, std::vector attributes){ shader.s.clear(); shader.a = attributes; try { auto v = shader::from_file(shader_type::vertex, ::bundle.get_shader_path() + file + ".vsh"); auto f = shader::from_file(shader_type::fragment, ::bundle.get_shader_path() + file + ".fsh"); shader.s.attach(v); shader.s.attach(f); } catch (std::exception & e){ CERR << e.what(); } for(auto str : attributes){ shader.s.bind_attribute(shader.attribute_location(str), str); } shader.s.link(); }; load_shader(ball_shader, "ball", {"position", "color", "texture_coordinate"}); load_shader(line_shader, "line", {"position", "color"}); load_shader(note_shader, "note", {"position"}); load_shader(flat_shader, "flat", {"position", "texture_coordinate"}); load_shader(awe_shader, "awe", {"position", "texture_coordinate"}); } void draw_square(GameRenderer::Shader & shader, std::shared_ptr read_fbo){ shader.s.use(); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, read_fbo->get_texture_id()); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); shader.s.uniform("texture").set(0); typedef GLfloat Quad[4]; static Quad quad [] = { {-1, 1, 0, 1}, { 1, 1, 1, 1}, {-1, -1, 0, 0}, { 1, -1, 1, 0} }; gl::enable_vertex_attribute_array(shader.attribute_location("position")); gl::vertex_attribute_pointer(shader.attribute_location("position"), 2, GL_FLOAT, GL_FALSE, sizeof(Quad), &quad[0][0]); gl::enable_vertex_attribute_array(shader.attribute_location("texture_coordinate")); gl::vertex_attribute_pointer(shader.attribute_location("texture_coordinate"), 2, GL_FLOAT, GL_FALSE, sizeof(Quad), &quad[0][2]); gl::draw_arrays(GL_TRIANGLE_STRIP, 0, 4); } void GameRenderer::draw(Client const & client){ gl::disable(GL_DEPTH_TEST); gl::disable(GL_CULL_FACE); auto projectionMatrix = projection_matrices::orthographic(client.sim.bounds.xmin, client.sim.bounds.xmax, client.sim.bounds.ymax, client.sim.bounds.ymin, -100.0f, 100.0f); auto modelViewProjectionMatrix = projectionMatrix; std::swap(fbo1, fbo2); fbo1->bind(); { awe_shader.s.use(); awe_shader.s.uniform("time").set(client.time); awe_shader.s.uniform("beat").set(client.beat.time); awe_shader.s.uniform>("inv_wh").set({1.0 / fbo1->get_width(), 1.0 / fbo1->get_height()}); draw_square(awe_shader, fbo2); } if(!client.beat.notes.empty()){ moggle::gl::blend_function(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); note_shader.s.use(); note_shader.s.uniform>("modelViewProjectionMatrix").set(modelViewProjectionMatrix); // glVertexAttribPointer(it->second, size, type, normalized, stride, ptr); gl::enable_vertex_attribute_array(note_shader.attribute_location("position")); gl::vertex_attribute_pointer(note_shader.attribute_location("position"), 2, GL_FLOAT, GL_FALSE, sizeof(note_type), &client.beat.notes[0].information); gl::draw_arrays(GL_POINTS, 0, client.beat.notes.size()); } if(!client.lines.empty() || client.kick || client.snare){ moggle::gl::blend_function(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); line_shader.s.use(); line_shader.s.uniform>("modelViewProjectionMatrix").set(modelViewProjectionMatrix); lines.clear(); lines.reserve(client.lines.size() * 2 + 2 * 2); for(auto const & l : client.lines){ Color color = (l->line_kind == simulation::kFallThrough) ? Color{1.0f, l->color_intensity, std::sin(l->color_intensity)} : Color{std::sin(l->color_intensity), 0.5f + 0.5f*l->color_intensity, 1.0f}; lines.push_back({l->starting_point, color}); lines.push_back({l->end_point, color}); } if(client.kick){ Color color{0.6f + client.kick->color_intensity, 0.5f, 0.4f}; lines.push_back({client.kick->starting_point, color}); lines.push_back({client.kick->end_point, color}); } if(client.snare){ Color color{0.6f + client.snare->color_intensity, 0.7f, 0.8f}; lines.push_back({client.snare->starting_point, color}); lines.push_back({client.snare->end_point, color}); } if(debug_draw){ for(auto const & l : client.sim.lines){ Color color = (l.line_kind == simulation::kFallThrough) ? Color{1.0, 0.0, 0.0} : Color{0.0, 0.5, 1.0}; lines.push_back({l.starting_point, color}); lines.push_back({l.end_point, color}); } } gl::enable_vertex_attribute_array(line_shader.attribute_location("position")); gl::vertex_attribute_pointer(line_shader.attribute_location("position"), 2, GL_FLOAT, GL_FALSE, sizeof(LineVertex), &lines[0]); gl::enable_vertex_attribute_array(line_shader.attribute_location("color")); gl::vertex_attribute_pointer(line_shader.attribute_location("color"), 3, GL_FLOAT, GL_FALSE, sizeof(LineVertex), &lines[0].color); gl::draw_arrays(GL_LINES, 0, lines.size()); } if(!client.sim.balls.empty()){ gl::blend_function(GL_ONE, GL_ONE); ball_shader.s.use(); ball_shader.s.uniform>("modelViewProjectionMatrix").set(modelViewProjectionMatrix); balls.clear(); balls.reserve(client.sim.balls.size()); for(auto const & b : client.sim.balls){ balls.emplace_back(b); } gl::enable_vertex_attribute_array(ball_shader.attribute_location("position")); gl::vertex_attribute_pointer(ball_shader.attribute_location("position"), 3, GL_FLOAT, GL_FALSE, sizeof(BallQuad::Vertex), &balls[0].quad[0].x); gl::enable_vertex_attribute_array(ball_shader.attribute_location("color")); gl::vertex_attribute_pointer(ball_shader.attribute_location("color"), 3, GL_FLOAT, GL_FALSE, sizeof(BallQuad::Vertex), &balls[0].quad[0].r); gl::enable_vertex_attribute_array(ball_shader.attribute_location("texture_coordinate")); gl::vertex_attribute_pointer(ball_shader.attribute_location("texture_coordinate"), 2, GL_FLOAT, GL_FALSE, sizeof(BallQuad::Vertex), &balls[0].quad[0].s); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, ball_texture.get_id()); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ball_shader.s.uniform("texture").set(0); gl::draw_arrays(GL_TRIANGLE_STRIP, 0, balls.size() * 6); } fbo1->unbind(); draw_square(flat_shader, fbo1); } }