diff --git a/src/client/GameRenderer.cpp b/src/client/GameRenderer.cpp index 78a995a..ed10b24 100644 --- a/src/client/GameRenderer.cpp +++ b/src/client/GameRenderer.cpp @@ -4,22 +4,6 @@ #include namespace games { -constexpr static const char* ball_attributes[] = { - "position", - "color", - "speed", - "texture_coordinate" -}; - -constexpr static const char* line_attributes[] = { - "position", - "color" -}; - -constexpr static const char* note_attributes[] = { - "position", - "color" -}; template std::vector from_strarray(const char* const (& strs)[N]) { @@ -32,14 +16,22 @@ std::vector from_strarray(const char* const (& strs)[N]) { using namespace moggle; using namespace motor; -GameRenderer::GameRenderer() +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 { @@ -52,7 +44,7 @@ GameRenderer::GameRenderer() CERR << e.what(); } - for(auto str : ball_attributes){ + for(auto str : attributes){ shader.s.bind_attribute(shader.attribute_location(str), str); } @@ -62,14 +54,51 @@ GameRenderer::GameRenderer() 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(); @@ -133,12 +162,14 @@ void GameRenderer::draw(Client const & client){ 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); + 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); } } \ No newline at end of file diff --git a/src/client/GameRenderer.h b/src/client/GameRenderer.h index e9b5c49..95ee80b 100644 --- a/src/client/GameRenderer.h +++ b/src/client/GameRenderer.h @@ -18,14 +18,14 @@ struct BallQuad { // degenerate std::array quad; BallQuad(ball_type const & b){ - quad = { + quad = {{ Vertex{b.position.x-hsize, b.position.y-hsize, 0.0f, 0.9f, 0.4f, 0.1f, 0.0f, 0.0f}, Vertex{b.position.x-hsize, b.position.y-hsize, 0.0f, 0.9f, 0.4f, 0.1f, 0.0f, 0.0f}, Vertex{b.position.x+hsize, b.position.y-hsize, 0.0f, 0.9f, 0.4f, 0.1f, 1.0f, 0.0f}, Vertex{b.position.x-hsize, b.position.y+hsize, 0.0f, 0.9f, 0.4f, 0.1f, 0.0f, 1.0f}, Vertex{b.position.x+hsize, b.position.y+hsize, 0.0f, 0.9f, 0.4f, 0.1f, 1.0f, 1.0f}, Vertex{b.position.x+hsize, b.position.y+hsize, 0.0f, 0.9f, 0.4f, 0.1f, 1.0f, 1.0f}, - }; + }}; } }; @@ -59,12 +59,19 @@ struct GameRenderer { Shader ball_shader; Shader line_shader; Shader note_shader; + Shader flat_shader; + Shader awe_shader; motor::Texture ball_texture; + + std::shared_ptr fbo1; + std::shared_ptr fbo2; bool debug_draw{false}; - GameRenderer(); + GameRenderer(int w, int h); void draw(Client const & client); + + void load_shaders(); }; } \ No newline at end of file diff --git a/src/client/client.cpp b/src/client/client.cpp index dc99c21..b3c19d5 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -1,6 +1,7 @@ #include "client.hpp" #include +#include #include #include @@ -81,6 +82,7 @@ namespace games { Client::Client(int window_width_, int window_height_, std::shared_ptr& active_base_) : Base(window_width_, window_height_, active_base_) + , game_renderer(window_width_, window_height_) { if(current_client){ CERR << "Warning: global client already defined\n"; @@ -88,14 +90,20 @@ namespace games { current_client = this; // sound - scale = Scale::load_from_file(*current_scale); + for(auto & str : scale_files){ + scales.push_back(Scale::load_from_file(str)); + } + scale = scales[0]; + + chords.notes.emplace_back(note_type::kWholeNote, note_info{100.0f, 100.0f}); // simulation sim.bounds.xmax = window_width_; sim.bounds.ymax = window_height_; - beat.notes.emplace_back(note_type::kQuarterNote, note_info{100.0f, 100.0f}); - cheap_line_type line{{{50.0f, 100.0f}, {150.0f, 200.0f}, simulation::kOneWay}}; - add_line(line); + + beat.notes.emplace_back(note_type::kQuarterNote, note_info{window_width / 5.0f, 10.0f}); + beat.notes.emplace_back(note_type::kWholeNote, note_info{window_width / 2.0f, 10.0f}); + beat.notes.emplace_back(note_type::kHalfNote, note_info{4.0f * window_width / 5.0f, 10.0f}); // websockets lws_context_creation_info info; @@ -127,22 +135,32 @@ namespace games { void Client::handle_input(float dt, Input input){ using motor::Position; - if(input.keys_went_down[SDLK_u]){ - //Iterates over drawing the physics and normal world, drawing only the physics world, and drawing only the normal world. - if(!draw_physics_world){ - draw_physics_world = true; - } else { - if(draw_only_physics_world){ - draw_physics_world = false; - draw_only_physics_world = false; - } else { - draw_only_physics_world = true; - } + if(input.keys_went_down[SDLK_b]){ + sim.balls.clear(); + } + + if(input.keys_went_down[SDLK_l]){ + lines.clear(); + sim.lines.clear(); + } + + if(input.keys_went_down[SDLK_r]){ + scales.clear(); + for(auto & str : scale_files){ + scales.push_back(Scale::load_from_file(str)); } } if(input.keys_went_down[SDLK_k]){ scene->update_shader_pipeline(); + game_renderer.load_shaders(); + } + + for(char n = '0'; n <= '9'; ++n){ + if(input.keys_went_down[n]){ + scale = scales[n - '0']; + update_pitches(*this); + } } } @@ -158,19 +176,36 @@ namespace games { scene->camera.set_position({0, 0, 20}); + float dt2 = dt; + if(dt2 > 1.0/70.0 && dt2 < 1.0/55.0) dt2 = 1.0/60.0; + // simulation for(auto l : lines){ - l->update(dt); + l->update(dt2); } - for(auto x : sim.update(dt)){ + for(auto x : sim.update(dt2)){ x.line.information->play(); } - for(auto n : beat.update(dt)){ + for(auto n : beat.update(music_speed * dt2)){ sim.balls.emplace_back(n.x, n.y, 0, 0, balluid++); } + if(!chords.update(music_speed * dt2).empty()){ + std::cout << std::distance(chord_progression.cbegin(), chord_progression_it) + 1 << "th chord\n"; + scale = scales[*chord_progression_it]; + update_pitches(*this); + + ++chord_progression_it; + if(chord_progression_it == chord_progression.end()){ + int i = rand() % chord_progressions.size(); + std::cout << "Changing progression: " << i << std::endl; + chord_progression = chord_progressions[i]; + chord_progression_it = chord_progression.begin(); + } + } + // websockets const float push_interval = 0.05; push_time += dt; diff --git a/src/client/client.hpp b/src/client/client.hpp index 14ee4bf..545ae90 100644 --- a/src/client/client.hpp +++ b/src/client/client.hpp @@ -15,6 +15,14 @@ #include "client_common.hpp" #include "GameRenderer.h" +/* + Controls: + 1, .. 9, 0: change chord (will also be done automatically) + r: reload scales (aka chords) + k: reload shaders + b: clear balls + l: clear lines + */ namespace games { struct Client : public Base { @@ -32,20 +40,40 @@ namespace games { simu_type sim; beat_type beat; + beat_type chords; void add_line(cheap_line_type const & line); // Sound part - const std::vector scales{ - ::bundle.get_sound_path() + "maj7.txt", - ::bundle.get_sound_path() + "pentatonic" + const std::vector scale_files{ + ::bundle.get_sound_path() + "pentatonic.txt", // 0 a + ::bundle.get_sound_path() + "c.txt", // 1 c + ::bundle.get_sound_path() + "d.txt", // 2 d + ::bundle.get_sound_path() + "em.txt", // 3 e + ::bundle.get_sound_path() + "maj7.txt", // 4 g + ::bundle.get_sound_path() + "noon.txt", // 5 a + ::bundle.get_sound_path() + "cnoon.txt", // 6 c + ::bundle.get_sound_path() + "blues.txt", // 7 a + ::bundle.get_sound_path() + "spanish.txt", // 8 a + ::bundle.get_sound_path() + "f.txt", // 9 f }; + std::vector scales; + Scale scale; + + const std::vector> chord_progressions{ + {1, 2, 3, 3, 1, 2, 3, 4, 1, 2, 3, 3, 1, 2, 3, 4}, + {0, 7, 4, 4, 0, 1, 9, 3}, + {0, 0, 9, 9, 0, 0, 5, 6} + }; + std::vector chord_progression{chord_progressions[0]}; + std::vector::const_iterator chord_progression_it{chord_progression.begin()}; + const std::vector> sounds{ resource_cache.get_sound_buffer(::bundle.get_sound_path() + "guitar440.wav"), resource_cache.get_sound_buffer(::bundle.get_sound_path() + "marimba.wav") }; - std::vector::const_iterator current_scale{scales.begin()}; - Scale scale; + + float music_speed{1.0}; // Graphics GameRenderer game_renderer;