1
Fork 0

Made a more awesome renderer

This commit is contained in:
Joshua Moerman 2013-04-22 17:52:23 +02:00
parent 76e3b7854e
commit f9015fe05d
4 changed files with 147 additions and 46 deletions

View file

@ -4,22 +4,6 @@
#include <moggle/math/projection.hpp> #include <moggle/math/projection.hpp>
namespace games { 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 <size_t N> template <size_t N>
std::vector<std::string> from_strarray(const char* const (& strs)[N]) { std::vector<std::string> from_strarray(const char* const (& strs)[N]) {
@ -32,14 +16,22 @@ std::vector<std::string> from_strarray(const char* const (& strs)[N]) {
using namespace moggle; using namespace moggle;
using namespace motor; using namespace motor;
GameRenderer::GameRenderer() GameRenderer::GameRenderer(int w, int h)
: ball_texture(::bundle.get_texture_path() + "bol.png") : ball_texture(::bundle.get_texture_path() + "bol.png")
{ {
gl::enable(GL_LINE_SMOOTH); gl::enable(GL_LINE_SMOOTH);
glLineWidth(1.5f); glLineWidth(1.5f);
glPointSize(4.0f); glPointSize(4.0f);
load_shaders();
fbo1 = std::make_shared<motor::Fbo>(w, h);
fbo2 = std::make_shared<motor::Fbo>(w, h);
}
void GameRenderer::load_shaders(){
auto load_shader = [](Shader & shader, std::string file, std::vector<std::string> attributes){ auto load_shader = [](Shader & shader, std::string file, std::vector<std::string> attributes){
shader.s.clear();
shader.a = attributes; shader.a = attributes;
try { try {
@ -52,7 +44,7 @@ GameRenderer::GameRenderer()
CERR << e.what(); CERR << e.what();
} }
for(auto str : ball_attributes){ for(auto str : attributes){
shader.s.bind_attribute(shader.attribute_location(str), str); 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(ball_shader, "ball", {"position", "color", "texture_coordinate"});
load_shader(line_shader, "line", {"position", "color"}); load_shader(line_shader, "line", {"position", "color"});
load_shader(note_shader, "note", {"position"}); 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<motor::Fbo> 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<GLint>("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){ void GameRenderer::draw(Client const & client){
gl::disable(GL_DEPTH_TEST); 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 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; auto modelViewProjectionMatrix = projectionMatrix;
std::swap(fbo1, fbo2);
fbo1->bind();
{
awe_shader.s.use();
awe_shader.s.uniform<GLfloat>("time").set(client.time);
awe_shader.s.uniform<GLfloat>("beat").set(client.beat.time);
awe_shader.s.uniform<moggle::vector2<GLfloat>>("inv_wh").set({1.0 / fbo1->get_width(), 1.0 / fbo1->get_height()});
draw_square(awe_shader, fbo2);
}
if(!client.beat.notes.empty()){ if(!client.beat.notes.empty()){
moggle::gl::blend_function(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); moggle::gl::blend_function(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
note_shader.s.use(); note_shader.s.use();
@ -133,12 +162,14 @@ void GameRenderer::draw(Client const & client){
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, ball_texture.get_id()); glBindTexture(GL_TEXTURE_2D, ball_texture.get_id());
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 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_MIN_FILTER, GL_LINEAR);
ball_shader.s.uniform<GLint>("texture").set(0); ball_shader.s.uniform<GLint>("texture").set(0);
gl::draw_arrays(GL_TRIANGLE_STRIP, 0, balls.size() * 6); gl::draw_arrays(GL_TRIANGLE_STRIP, 0, balls.size() * 6);
} }
fbo1->unbind();
draw_square(flat_shader, fbo1);
} }
} }

View file

@ -18,14 +18,14 @@ struct BallQuad {
// degenerate // degenerate
std::array<Vertex, 6> quad; std::array<Vertex, 6> quad;
BallQuad(ball_type const & b){ 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, 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, 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, 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},
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 ball_shader;
Shader line_shader; Shader line_shader;
Shader note_shader; Shader note_shader;
Shader flat_shader;
Shader awe_shader;
motor::Texture ball_texture; motor::Texture ball_texture;
std::shared_ptr<motor::Fbo> fbo1;
std::shared_ptr<motor::Fbo> fbo2;
bool debug_draw{false}; bool debug_draw{false};
GameRenderer(); GameRenderer(int w, int h);
void draw(Client const & client); void draw(Client const & client);
void load_shaders();
}; };
} }

View file

@ -1,6 +1,7 @@
#include "client.hpp" #include "client.hpp"
#include <cmath> #include <cmath>
#include <algorithm>
#include <stdexcept> #include <stdexcept>
#include <lib/libwebsockets.h> #include <lib/libwebsockets.h>
@ -81,6 +82,7 @@ namespace games {
Client::Client(int window_width_, int window_height_, std::shared_ptr<Base>& active_base_) Client::Client(int window_width_, int window_height_, std::shared_ptr<Base>& active_base_)
: Base(window_width_, window_height_, active_base_) : Base(window_width_, window_height_, active_base_)
, game_renderer(window_width_, window_height_)
{ {
if(current_client){ if(current_client){
CERR << "Warning: global client already defined\n"; CERR << "Warning: global client already defined\n";
@ -88,14 +90,20 @@ namespace games {
current_client = this; current_client = this;
// sound // 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 // simulation
sim.bounds.xmax = window_width_; sim.bounds.xmax = window_width_;
sim.bounds.ymax = window_height_; 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}}; beat.notes.emplace_back(note_type::kQuarterNote, note_info{window_width / 5.0f, 10.0f});
add_line(line); 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 // websockets
lws_context_creation_info info; lws_context_creation_info info;
@ -127,22 +135,32 @@ namespace games {
void Client::handle_input(float dt, Input input){ void Client::handle_input(float dt, Input input){
using motor::Position; using motor::Position;
if(input.keys_went_down[SDLK_u]){ if(input.keys_went_down[SDLK_b]){
//Iterates over drawing the physics and normal world, drawing only the physics world, and drawing only the normal world. sim.balls.clear();
if(!draw_physics_world){ }
draw_physics_world = true;
} else { if(input.keys_went_down[SDLK_l]){
if(draw_only_physics_world){ lines.clear();
draw_physics_world = false; sim.lines.clear();
draw_only_physics_world = false; }
} else {
draw_only_physics_world = true; 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]){ if(input.keys_went_down[SDLK_k]){
scene->update_shader_pipeline(); 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}); 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 // simulation
for(auto l : lines){ 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(); 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++); 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 // websockets
const float push_interval = 0.05; const float push_interval = 0.05;
push_time += dt; push_time += dt;

View file

@ -15,6 +15,14 @@
#include "client_common.hpp" #include "client_common.hpp"
#include "GameRenderer.h" #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 { namespace games {
struct Client : public Base { struct Client : public Base {
@ -32,20 +40,40 @@ namespace games {
simu_type sim; simu_type sim;
beat_type beat; beat_type beat;
beat_type chords;
void add_line(cheap_line_type const & line); void add_line(cheap_line_type const & line);
// Sound part // Sound part
const std::vector<std::string> scales{ const std::vector<std::string> scale_files{
::bundle.get_sound_path() + "maj7.txt", ::bundle.get_sound_path() + "pentatonic.txt", // 0 a
::bundle.get_sound_path() + "pentatonic" ::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<Scale> scales;
Scale scale;
const std::vector<std::vector<int>> 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<int> chord_progression{chord_progressions[0]};
std::vector<int>::const_iterator chord_progression_it{chord_progression.begin()};
const std::vector<std::shared_ptr<motor::al::Buffer>> sounds{ const std::vector<std::shared_ptr<motor::al::Buffer>> sounds{
resource_cache.get_sound_buffer(::bundle.get_sound_path() + "guitar440.wav"), resource_cache.get_sound_buffer(::bundle.get_sound_path() + "guitar440.wav"),
resource_cache.get_sound_buffer(::bundle.get_sound_path() + "marimba.wav") resource_cache.get_sound_buffer(::bundle.get_sound_path() + "marimba.wav")
}; };
std::vector<std::string>::const_iterator current_scale{scales.begin()};
Scale scale; float music_speed{1.0};
// Graphics // Graphics
GameRenderer game_renderer; GameRenderer game_renderer;