Added drawing and undoing
This commit is contained in:
parent
39b71cc5c5
commit
ee571c1b56
3 changed files with 117 additions and 33 deletions
|
@ -92,7 +92,7 @@ void GameRenderer::draw(Client const & client){
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
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(0, client.window_width, client.window_height, 0, -100.0f, 100.0f);
|
||||||
auto modelViewProjectionMatrix = projectionMatrix;
|
auto modelViewProjectionMatrix = projectionMatrix;
|
||||||
|
|
||||||
std::swap(fbo1, fbo2);
|
std::swap(fbo1, fbo2);
|
||||||
|
@ -118,13 +118,13 @@ void GameRenderer::draw(Client const & client){
|
||||||
gl::draw_arrays(GL_POINTS, 0, client.beat.notes.size());
|
gl::draw_arrays(GL_POINTS, 0, client.beat.notes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!client.lines.empty() || client.kick || client.snare){
|
if(!client.lines.empty() || client.kick || client.snare || client.drawing){
|
||||||
moggle::gl::blend_function(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
moggle::gl::blend_function(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
line_shader.s.use();
|
line_shader.s.use();
|
||||||
line_shader.s.uniform<matrix<float, 4>>("modelViewProjectionMatrix").set(modelViewProjectionMatrix);
|
line_shader.s.uniform<matrix<float, 4>>("modelViewProjectionMatrix").set(modelViewProjectionMatrix);
|
||||||
|
|
||||||
lines.clear();
|
lines.clear();
|
||||||
lines.reserve(client.lines.size() * 2 + 2 * 2);
|
lines.reserve(client.lines.size() * 2 + 2 * 2 + 2);
|
||||||
for(auto const & l : client.lines){
|
for(auto const & l : client.lines){
|
||||||
Color color = (l->line_kind == simulation::kFallThrough)
|
Color color = (l->line_kind == simulation::kFallThrough)
|
||||||
? Color{1.0f, l->color_intensity, std::sin(l->color_intensity)}
|
? Color{1.0f, l->color_intensity, std::sin(l->color_intensity)}
|
||||||
|
@ -143,6 +143,14 @@ void GameRenderer::draw(Client const & client){
|
||||||
lines.push_back({client.snare->starting_point, color});
|
lines.push_back({client.snare->starting_point, color});
|
||||||
lines.push_back({client.snare->end_point, color});
|
lines.push_back({client.snare->end_point, color});
|
||||||
}
|
}
|
||||||
|
if(client.drawing){
|
||||||
|
const float color_intensity = 0.0f;
|
||||||
|
Color color = (client.current_kind == simulation::kFallThrough)
|
||||||
|
? Color{1.0f, color_intensity, std::sin(color_intensity)}
|
||||||
|
: Color{std::sin(color_intensity), 0.5f + 0.5f*color_intensity, 1.0f};
|
||||||
|
lines.push_back({to_FloatVec2(client.current_line.starting_point), color});
|
||||||
|
lines.push_back({to_FloatVec2(client.current_line.end_point), color});
|
||||||
|
}
|
||||||
|
|
||||||
if(debug_draw){
|
if(debug_draw){
|
||||||
for(auto const & l : client.sim.lines){
|
for(auto const & l : client.sim.lines){
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace games {
|
||||||
}
|
}
|
||||||
} else if (command == "peeps"){
|
} else if (command == "peeps"){
|
||||||
auto str = from_json<std::string>(object["data"]);
|
auto str = from_json<std::string>(object["data"]);
|
||||||
current_client->update_peeps(str);
|
current_client->set_text("Peeps: " + str);
|
||||||
}
|
}
|
||||||
} catch(std::exception& e){
|
} catch(std::exception& e){
|
||||||
throw websockets::runtime_error(e.what());
|
throw websockets::runtime_error(e.what());
|
||||||
|
@ -115,6 +115,14 @@ namespace games {
|
||||||
lines_changed = true;
|
lines_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::remove_line(std::shared_ptr<Instrument> const & instr){
|
||||||
|
auto& v = sim.lines;
|
||||||
|
v.erase(std::remove_if(v.begin(), v.end(), [instr](line_type const &l2){ return instr.get() == l2.information; }), v.end());
|
||||||
|
|
||||||
|
auto& w = lines;
|
||||||
|
w.erase(std::remove_if(w.begin(), w.end(), [instr](std::shared_ptr<Instrument> const & l){ return instr == l; }), w.end());
|
||||||
|
}
|
||||||
|
|
||||||
void Client::add_drum(){
|
void Client::add_drum(){
|
||||||
kick = std::make_shared<Instrument>(math::Vec2{x1 - 25.0f, window_height - 100.0f}, math::Vec2{x1 + 25.0f, window_height - 50.0f}, 1, -1);
|
kick = std::make_shared<Instrument>(math::Vec2{x1 - 25.0f, window_height - 100.0f}, math::Vec2{x1 + 25.0f, window_height - 50.0f}, 1, -1);
|
||||||
kick->sound.reset(new motor::al::Source(sounds[2]));
|
kick->sound.reset(new motor::al::Source(sounds[2]));
|
||||||
|
@ -188,19 +196,19 @@ namespace games {
|
||||||
info.gid = -1;
|
info.gid = -1;
|
||||||
info.uid = -1;
|
info.uid = -1;
|
||||||
|
|
||||||
context = libwebsocket_create_context(&info);
|
// context = libwebsocket_create_context(&info);
|
||||||
if(!context) throw std::runtime_error("context could not be created.");
|
// if(!context) throw std::runtime_error("context could not be created.");
|
||||||
|
|
||||||
// std::string address = "127.0.0.1";
|
// std::string address = "127.0.0.1";
|
||||||
std::string address = "vadovas-studios.com";
|
std::string address = "vadovas-studios.com";
|
||||||
wsi = libwebsocket_client_connect(context, address.c_str(), 7681, false, "/", address.c_str(), "origin", "uberclient", -1);
|
// wsi = libwebsocket_client_connect(context, address.c_str(), 7681, false, "/", address.c_str(), "origin", "uberclient", -1);
|
||||||
if(!wsi) throw std::runtime_error("socket could not be created.");
|
// if(!wsi) throw std::runtime_error("socket could not be created.");
|
||||||
|
|
||||||
// motor
|
// motor
|
||||||
world.physics.set_gravity({0.0, 0.0, 0.0});
|
world.physics.set_gravity({0.0, 0.0, 0.0});
|
||||||
hud->camera.set_orthographic(-100, 100, -100, 100, 1, -1);
|
hud->camera.set_orthographic(-100, 100, -100, 100, 1, -1);
|
||||||
update_peeps("");
|
set_text("draw mode: guitar");
|
||||||
auto join_lbl = std::make_shared<motor::TextureLabel>("Join at: http://vadovas-studios.com/beats", motor::bundle.get_font_path() + "Arial Rounded Bold.ttf", 72);
|
auto join_lbl = std::make_shared<motor::TextureLabel>("-/+: speed, l: clear lines, b: clear balls, d: toggle drums, k: change drawmode", motor::bundle.get_font_path() + "Arial Rounded Bold.ttf", 72);
|
||||||
join_lbl->get_mesh()->material->diffuse_color = {1.0f, 1.0f, 1.0f, 1.0f};
|
join_lbl->get_mesh()->material->diffuse_color = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
join_lbl->set_position({-95.0, -95.0, 0.0});
|
join_lbl->set_position({-95.0, -95.0, 0.0});
|
||||||
join_lbl->set_scale(motor::scale(0.05));
|
join_lbl->set_scale(motor::scale(0.05));
|
||||||
|
@ -211,6 +219,26 @@ 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.mouse.went_down[Input::Mouse::left]){
|
||||||
|
drawing = true;
|
||||||
|
current_line.starting_point = {input.mouse.position[0], input.mouse.position[1]};
|
||||||
|
current_line.end_point = {input.mouse.position[0], input.mouse.position[1]};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input.mouse.is_pressed[Input::Mouse::left]){
|
||||||
|
current_line.end_point = {input.mouse.position[0], input.mouse.position[1]};
|
||||||
|
current_line.line_kind = current_kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input.mouse.went_up[Input::Mouse::left]){
|
||||||
|
current_line.end_point = {input.mouse.position[0], input.mouse.position[1]};
|
||||||
|
add_line(current_line);
|
||||||
|
while(!undo_stack.empty()){
|
||||||
|
undo_stack.pop();
|
||||||
|
}
|
||||||
|
drawing = false;
|
||||||
|
}
|
||||||
|
|
||||||
if(input.keys_went_down[SDLK_b]){
|
if(input.keys_went_down[SDLK_b]){
|
||||||
sim.balls.clear();
|
sim.balls.clear();
|
||||||
}
|
}
|
||||||
|
@ -227,22 +255,55 @@ namespace games {
|
||||||
music_speed = 2.0;
|
music_speed = 2.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(input.keys_went_down[SDLK_z]){
|
if(input.keys_went_down[SDLK_r]){
|
||||||
sim_speed = 0.5;
|
sim_speed = 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(input.keys_went_down[SDLK_x]){
|
if(input.keys_went_down[SDLK_t]){
|
||||||
sim_speed = 1.0;
|
sim_speed = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(input.keys_went_down[SDLK_c]){
|
if(input.keys_went_down[SDLK_y]){
|
||||||
sim_speed = 2.0;
|
sim_speed = 2.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(input.keys_went_down[SDLK_z] && !lines.empty()){
|
||||||
|
std::shared_ptr<Instrument> line = lines.back();
|
||||||
|
remove_line(line);
|
||||||
|
undo_stack.push(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input.keys_went_down[SDLK_x] && !undo_stack.empty()){
|
||||||
|
std::shared_ptr<Instrument> line = undo_stack.top();
|
||||||
|
undo_stack.pop();
|
||||||
|
lines.push_back(line);
|
||||||
|
|
||||||
|
for(auto & l : line->calculate_lines()){
|
||||||
|
sim.lines.push_back(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const float step = 1.5;
|
||||||
|
if(input.keys_went_down[SDLK_MINUS]){
|
||||||
|
global_speed /= step;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input.keys_went_down[SDLK_EQUALS]){
|
||||||
|
global_speed *= step;
|
||||||
|
}
|
||||||
|
|
||||||
if(input.keys_went_down[SDLK_p]){
|
if(input.keys_went_down[SDLK_p]){
|
||||||
pause = !pause;
|
pause = !pause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(input.keys_went_down[SDLK_k]){
|
||||||
|
switch(current_kind){
|
||||||
|
case simulation::kFallThrough: current_kind = simulation::kOneWay; set_text("draw mode: bouncy"); break;
|
||||||
|
case simulation::kOneWay: current_kind = simulation::kFallThrough; set_text("draw mode: guitar"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if(input.keys_went_down[SDLK_l]){
|
if(input.keys_went_down[SDLK_l]){
|
||||||
bool restore_drum = false;
|
bool restore_drum = false;
|
||||||
if(kick || snare){
|
if(kick || snare){
|
||||||
|
@ -295,10 +356,10 @@ namespace games {
|
||||||
Base::draw();
|
Base::draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::update_peeps(std::string peeps){
|
void Client::set_text(std::string peeps){
|
||||||
if(!peeps_lbl){
|
if(!peeps_lbl){
|
||||||
try {
|
try {
|
||||||
peeps_lbl = std::make_shared<motor::TextureLabel>("Peeps:", motor::bundle.get_font_path() + "Arial Rounded Bold.ttf", 72);
|
peeps_lbl = std::make_shared<motor::TextureLabel>("", motor::bundle.get_font_path() + "Arial Rounded Bold.ttf", 72);
|
||||||
peeps_lbl->get_mesh()->material->diffuse_color = {1.0f, 1.0f, 1.0f, 1.0f};
|
peeps_lbl->get_mesh()->material->diffuse_color = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
peeps_lbl->set_position({-95.0, -90.0, 0.0});
|
peeps_lbl->set_position({-95.0, -90.0, 0.0});
|
||||||
peeps_lbl->set_scale(motor::scale(0.05));
|
peeps_lbl->set_scale(motor::scale(0.05));
|
||||||
|
@ -308,14 +369,12 @@ namespace games {
|
||||||
CERR << e.what() << std::endl;
|
CERR << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(peeps == ""){
|
peeps_lbl->set_text(peeps);
|
||||||
peeps_lbl->set_text("No peeps online :(.");
|
|
||||||
} else {
|
|
||||||
peeps_lbl->set_text("Peeps: " + peeps);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::update(float const dt, Input input){
|
void Client::update(float dt, Input input){
|
||||||
|
dt *= global_speed;
|
||||||
|
|
||||||
// motor
|
// motor
|
||||||
Base::update(dt, input);
|
Base::update(dt, input);
|
||||||
handle_input(dt, input);
|
handle_input(dt, input);
|
||||||
|
@ -361,18 +420,21 @@ namespace games {
|
||||||
const float push_interval = 0.05;
|
const float push_interval = 0.05;
|
||||||
push_time += dt;
|
push_time += dt;
|
||||||
|
|
||||||
int ret = libwebsocket_service(context, 10);
|
if(context && wsi){
|
||||||
if(ret < 0) {
|
int ret = libwebsocket_service(context, 10);
|
||||||
CERR << "ERROR: libwebsocket returns < 0\n";
|
if(ret < 0) {
|
||||||
}
|
CERR << "ERROR: libwebsocket returns < 0\n";
|
||||||
if(push_time >= push_interval){
|
}
|
||||||
libwebsocket_callback_on_writable(context, wsi);
|
if(push_time >= push_interval){
|
||||||
push_time -= push_interval;
|
libwebsocket_callback_on_writable(context, wsi);
|
||||||
|
push_time -= push_interval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Client::~Client(){
|
Client::~Client(){
|
||||||
libwebsocket_context_destroy(context);
|
if(context)
|
||||||
|
libwebsocket_context_destroy(context);
|
||||||
current_client = nullptr;
|
current_client = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
#include <motor/sound/sound.hpp>
|
#include <motor/sound/sound.hpp>
|
||||||
#include <motor/basic/texture_label.hpp>
|
#include <motor/basic/texture_label.hpp>
|
||||||
|
@ -17,12 +18,17 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Controls:
|
Controls:
|
||||||
|
mouse: draw linez
|
||||||
1, .. 9, 0: change chord (will also be done automatically)
|
1, .. 9, 0: change chord (will also be done automatically)
|
||||||
q, w, e: music speed (= generation of balls)
|
k: change line kind
|
||||||
z, x, c: simulation speed
|
|
||||||
a: toggle autopilot
|
a: toggle autopilot
|
||||||
d: toggle drum
|
d: toggle drum
|
||||||
p: pause
|
p: pause
|
||||||
|
|
||||||
|
q, w, e: music speed (= generation of balls)
|
||||||
|
z, x, c: simulation speed
|
||||||
|
-, + (without shift): global speed
|
||||||
|
|
||||||
r: reload scales (aka chords)
|
r: reload scales (aka chords)
|
||||||
s: reload shaders
|
s: reload shaders
|
||||||
b: clear balls
|
b: clear balls
|
||||||
|
@ -32,6 +38,7 @@
|
||||||
namespace games {
|
namespace games {
|
||||||
struct Client : public Base {
|
struct Client : public Base {
|
||||||
static constexpr char bundle_name[] = "client";
|
static constexpr char bundle_name[] = "client";
|
||||||
|
float global_speed = 1.0;
|
||||||
|
|
||||||
// websocket part
|
// websocket part
|
||||||
libwebsocket_context * context{nullptr};
|
libwebsocket_context * context{nullptr};
|
||||||
|
@ -54,6 +61,7 @@ namespace games {
|
||||||
|
|
||||||
void add_line(cheap_line_type const & line);
|
void add_line(cheap_line_type const & line);
|
||||||
void remove_line(int ID);
|
void remove_line(int ID);
|
||||||
|
void remove_line(std::shared_ptr<Instrument> const & instr);
|
||||||
|
|
||||||
void add_drum();
|
void add_drum();
|
||||||
void remove_drum();
|
void remove_drum();
|
||||||
|
@ -62,6 +70,12 @@ namespace games {
|
||||||
float x2;
|
float x2;
|
||||||
float x3;
|
float x3;
|
||||||
|
|
||||||
|
// Input part
|
||||||
|
cheap_line_type current_line;
|
||||||
|
bool drawing = false;
|
||||||
|
simulation::LineKind current_kind = simulation::kFallThrough;
|
||||||
|
std::stack<std::shared_ptr<Instrument>> undo_stack;
|
||||||
|
|
||||||
// Sound part
|
// Sound part
|
||||||
const std::vector<std::string> scale_files{
|
const std::vector<std::string> scale_files{
|
||||||
::bundle.get_sound_path() + "pentatonic.txt", // 0 a
|
::bundle.get_sound_path() + "pentatonic.txt", // 0 a
|
||||||
|
@ -94,13 +108,13 @@ namespace games {
|
||||||
};
|
};
|
||||||
|
|
||||||
float music_speed{1.0};
|
float music_speed{1.0};
|
||||||
bool auto_pilot{false};
|
bool auto_pilot{true};
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
GameRenderer game_renderer;
|
GameRenderer game_renderer;
|
||||||
std::shared_ptr<motor::TextureLabel> peeps_lbl;
|
std::shared_ptr<motor::TextureLabel> peeps_lbl;
|
||||||
|
|
||||||
void update_peeps(std::string peeps);
|
void set_text(std::string peeps);
|
||||||
|
|
||||||
// Base part
|
// Base part
|
||||||
Client(int window_width, int window_height, std::shared_ptr<Base>& active_base);
|
Client(int window_width, int window_height, std::shared_ptr<Base>& active_base);
|
||||||
|
|
Reference in a new issue