From 77db8741430ca462e3b624dd42d5ead96be7f264 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 8 Aug 2013 19:13:39 +0300 Subject: [PATCH] Better visualization for placing a train Still far from perfect, but it's a start. --- data/ghost.technique | 7 ++++ source/3d/view.cpp | 19 ++++++++++ source/3d/view.h | 3 ++ source/engineer/controlpanel.cpp | 56 ++++++++++++++++++++++++---- source/engineer/controlpanel.h | 9 +++++ source/engineer/placementghost.cpp | 59 ++++++++++++++++++++++++++++++ source/engineer/placementghost.h | 29 +++++++++++++++ 7 files changed, 175 insertions(+), 7 deletions(-) create mode 100644 data/ghost.technique create mode 100644 source/engineer/placementghost.cpp create mode 100644 source/engineer/placementghost.h diff --git a/data/ghost.technique b/data/ghost.technique new file mode 100644 index 0000000..c019ab0 --- /dev/null +++ b/data/ghost.technique @@ -0,0 +1,7 @@ +pass "translucent" +{ + material + { + diffuse 1.0 1.0 1.0 0.3; + }; +}; diff --git a/source/3d/view.cpp b/source/3d/view.cpp index 8943abc..5779616 100644 --- a/source/3d/view.cpp +++ b/source/3d/view.cpp @@ -1,3 +1,4 @@ +#include #include #include "layout.h" #include "track.h" @@ -16,11 +17,17 @@ View3D::View3D(Layout3D &l, unsigned w, unsigned h): { pipeline.set_camera(&camera); pipeline.add_renderable_for_pass(layout.get_scene(), 0); + pipeline.add_renderable_for_pass(layout.get_scene(), "translucent"); GL::Pipeline::Pass *pass = &pipeline.add_pass(0); pass->set_lighting(&layout.get_lighting()); pass->set_depth_test(&GL::DepthTest::lequal()); + pass = &pipeline.add_pass("translucent"); + pass->set_lighting(&layout.get_lighting()); + pass->set_depth_test(&GL::DepthTest::lequal()); + pass->set_blend(&GL::Blend::alpha()); + camera.set_up_direction(GL::Vector3(0, 0, 1)); // Y+, 60° down camera.set_look_direction(GL::Vector3(0, 0.5, -0.866)); @@ -29,6 +36,18 @@ View3D::View3D(Layout3D &l, unsigned w, unsigned h): view_all(); } +Ray View3D::create_ray(int x, int y) +{ + return create_ray(x*2.0f/width-1.0f, y*2.0f/height-1.0f); +} + +Ray View3D::create_ray(float x, float y) +{ + const GL::Vector3 &start = camera.get_position(); + GL::Vector4 ray = camera.unproject(GL::Vector4(x, y, 0, 0)); + return Ray(start, Vector(ray)); +} + void View3D::view_all(bool tight) { const set &tracks = layout.get_layout().get_all(); diff --git a/source/3d/view.h b/source/3d/view.h index ffe608e..a1bdaf5 100644 --- a/source/3d/view.h +++ b/source/3d/view.h @@ -24,6 +24,9 @@ public: Msp::GL::Camera &get_camera() { return camera; } Msp::GL::Pipeline &get_pipeline() { return pipeline; } + Ray create_ray(int, int); + Ray create_ray(float, float); + void view_all(bool = false); void render(); diff --git a/source/engineer/controlpanel.cpp b/source/engineer/controlpanel.cpp index e81d25c..050b376 100644 --- a/source/engineer/controlpanel.cpp +++ b/source/engineer/controlpanel.cpp @@ -6,6 +6,7 @@ #include "libr2c2/vehicle.h" #include "controlpanel.h" #include "engineer.h" +#include "placementghost.h" #include "trainview.h" using namespace std; @@ -58,14 +59,13 @@ void ControlPanel::train_function_changed(unsigned func, bool value) void ControlPanel::place_clicked() { - pick_conn = engineer.signal_pick_done.connect(sigc::mem_fun(this, &ControlPanel::place_pick_done)); - engineer.pick(true); -} + signal_grab_pointer.emit(); + placing = true; -void ControlPanel::place_pick_done(Track *track, unsigned ep) -{ - pick_conn.disconnect(); - train.place(TrackIter(track, ep).block_iter()); + Layout3D &layout3d = engineer.get_layout_3d(); + unsigned n_vehs = train.get_n_vehicles(); + for(unsigned i=0; iadd(*dlg); dlg->autosize(); } + +void ControlPanel::button_press(int x, int y, unsigned btn) +{ + Panel::button_press(x, y, btn); + + if(placing) + { + signal_ungrab_pointer.emit(); + placing = false; + + for(vector::iterator i=ghosts.begin(); i!=ghosts.end(); ++i) + delete *i; + ghosts.clear(); + + if(btn==1 && place_location) + train.place(place_location); + } +} + +void ControlPanel::pointer_motion(int x, int y) +{ + Panel::pointer_motion(x, y); + + if(placing) + { + int rx = x; + int ry = y; + map_coords_to_ancestor(rx, ry, *find_ancestor()); + Ray ray = engineer.get_main_view().create_ray(rx, ry); + Track *track = engineer.get_layout().pick(ray); + if(track) + { + place_location = TrackIter(track, 0).block_iter(); + if(place_location) + { + ghosts.back()->place(place_location.track_iter()); + for(unsigned i=ghosts.size()-1; i--; ) + ghosts[i]->place_before(*ghosts[i+1]); + } + } + } +} diff --git a/source/engineer/controlpanel.h b/source/engineer/controlpanel.h index c99ca17..23ca8bc 100644 --- a/source/engineer/controlpanel.h +++ b/source/engineer/controlpanel.h @@ -4,9 +4,11 @@ #include #include #include +#include "libr2c2/blockiter.h" #include "libr2c2/train.h" class Engineer; +class PlacementGhost; class ControlPanel: public Msp::GLtk::Panel { @@ -17,6 +19,10 @@ private: std::map tgl_funcs; sigc::connection pick_conn; + bool placing; + std::vector ghosts; + R2C2::BlockIter place_location; + public: ControlPanel(Engineer &, R2C2::Train &); @@ -27,6 +33,9 @@ private: void place_pick_done(R2C2::Track *, unsigned); void take_clicked(); void view_clicked(); + + virtual void button_press(int, int, unsigned); + virtual void pointer_motion(int, int); }; #endif diff --git a/source/engineer/placementghost.cpp b/source/engineer/placementghost.cpp new file mode 100644 index 0000000..e59da68 --- /dev/null +++ b/source/engineer/placementghost.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include "libr2c2/vehicletype.h" +#include "placementghost.h" + +using namespace Msp; +using namespace R2C2; + +PlacementGhost::PlacementGhost(Layout3D &a, const VehicleType &t): + layout(a), + type(t), + placement(type), + mesh(new GL::Mesh((GL::VERTEX3, GL::NORMAL3))), + object(new GL::Object(mesh, &layout.get_catalogue().get("ghost.technique"))) +{ + GL::MeshBuilder bld(*mesh); + float l = type.get_length(); + float w = type.get_width(); + float h = type.get_height(); + GL::BoxBuilder(GL::Vector3(-l/2, -w/2, 0), GL::Vector3(l, w, h)).build(bld); + + layout.get_scene().add(*this); +} + +PlacementGhost::~PlacementGhost() +{ + layout.get_scene().remove(*this); + + delete object; + delete mesh; +} + +void PlacementGhost::place(const TrackOffsetIter &track) +{ + placement.place(track, VehiclePlacement::BACK_BUFFER); +} + +void PlacementGhost::place_before(const PlacementGhost &other) +{ + placement.place_before(other.placement); +} + +void PlacementGhost::render(GL::Renderer &renderer, const GL::Tag &tag) const +{ + if(!object->get_technique()->has_pass(tag)) + return; + + GL::Renderer::Push push(renderer); + + OrientedPoint point = placement.get_point(); + GL::Matrix matrix; + matrix.translate(point.position); + matrix.rotate(point.rotation, 0, 0, 1); + renderer.matrix_stack() *= matrix; + + object->render(renderer, tag); +} diff --git a/source/engineer/placementghost.h b/source/engineer/placementghost.h new file mode 100644 index 0000000..3ae2639 --- /dev/null +++ b/source/engineer/placementghost.h @@ -0,0 +1,29 @@ +#ifndef PLACEMENTGHOST_H_ +#define PLACEMENTGHOST_H_ + +#include +#include +#include +#include "libr2c2/vehicleplacement.h" +#include "3d/layout.h" + +class PlacementGhost: public Msp::GL::Renderable +{ +private: + R2C2::Layout3D &layout; + const R2C2::VehicleType &type; + R2C2::VehiclePlacement placement; + Msp::GL::Mesh *mesh; + Msp::GL::Object *object; + +public: + PlacementGhost(R2C2::Layout3D &, const R2C2::VehicleType &); + virtual ~PlacementGhost(); + + void place(const R2C2::TrackOffsetIter &); + void place_before(const PlacementGhost &); + + virtual void render(Msp::GL::Renderer &, const Msp::GL::Tag &) const; +}; + +#endif -- 2.43.0