Still far from perfect, but it's a start.
--- /dev/null
+pass "translucent"
+{
+ material
+ {
+ diffuse 1.0 1.0 1.0 0.3;
+ };
+};
+#include <msp/gl/blend.h>
#include <msp/gl/tests.h>
#include "layout.h"
#include "track.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));
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<Track *> &tracks = layout.get_layout().get_all<Track>();
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();
#include "libr2c2/vehicle.h"
#include "controlpanel.h"
#include "engineer.h"
+#include "placementghost.h"
#include "trainview.h"
using namespace std;
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; i<n_vehs; ++i)
+ ghosts.push_back(new PlacementGhost(layout3d, train.get_vehicle(i).get_type()));
}
void ControlPanel::take_clicked()
root->add(*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<PlacementGhost *>::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<GLtk::Root>());
+ Ray ray = engineer.get_main_view().create_ray(rx, ry);
+ Track *track = engineer.get_layout().pick<Track>(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]);
+ }
+ }
+ }
+}
#include <map>
#include <msp/gltk/panel.h>
#include <msp/gltk/toggle.h>
+#include "libr2c2/blockiter.h"
#include "libr2c2/train.h"
class Engineer;
+class PlacementGhost;
class ControlPanel: public Msp::GLtk::Panel
{
std::map<unsigned, Msp::GLtk::Toggle *> tgl_funcs;
sigc::connection pick_conn;
+ bool placing;
+ std::vector<PlacementGhost *> ghosts;
+ R2C2::BlockIter place_location;
+
public:
ControlPanel(Engineer &, R2C2::Train &);
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
--- /dev/null
+#include <msp/gl/box.h>
+#include <msp/gl/meshbuilder.h>
+#include <msp/gl/renderer.h>
+#include <msp/gl/technique.h>
+#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<GL::Technique>("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);
+}
--- /dev/null
+#ifndef PLACEMENTGHOST_H_
+#define PLACEMENTGHOST_H_
+
+#include <msp/gl/mesh.h>
+#include <msp/gl/object.h>
+#include <msp/gl/renderable.h>
+#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