+ static float &z(Triple &triple)
+ {
+ return triple.x();
+ }
+};
+
+template<typename Triple>
+class TripleRemapZXY {
+public:
+ static float &x(Triple &triple)
+ {
+ return triple.z();
+ }
+
+ static float &y(Triple &triple)
+ {
+ return triple.x();
+ }
+
+ static float &z(Triple &triple)
+ {
+ return triple.y();
+ }
+};
+
+void vector3_print(const Vector3 &v)
+{
+ globalOutputStream() << "( " << v.x() << " " << v.y() << " " << v.z() << " )";
+}
+
+class TranslateManipulator : public Manipulator {
+ struct RenderableArrowLine : public OpenGLRenderable {
+ PointVertex m_line[2];
+
+ RenderableArrowLine()
+ {
+ }
+
+ void render(RenderStateFlags state) const
+ {
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_line[0].colour);
+ glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_line[0].vertex);
+ glDrawArrays(GL_LINES, 0, 2);
+ }
+
+ void setColour(const Colour4b &colour)
+ {
+ m_line[0].colour = colour;
+ m_line[1].colour = colour;
+ }
+ };
+
+ struct RenderableArrowHead : public OpenGLRenderable {
+ Array<FlatShadedVertex> m_vertices;
+
+ RenderableArrowHead(std::size_t size)
+ : m_vertices(size)
+ {
+ }
+
+ void render(RenderStateFlags state) const
+ {
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(FlatShadedVertex), &m_vertices.data()->colour);
+ glVertexPointer(3, GL_FLOAT, sizeof(FlatShadedVertex), &m_vertices.data()->vertex);
+ glNormalPointer(GL_FLOAT, sizeof(FlatShadedVertex), &m_vertices.data()->normal);
+ glDrawArrays(GL_TRIANGLES, 0, GLsizei(m_vertices.size()));
+ }
+
+ void setColour(const Colour4b &colour)
+ {
+ for (Array<FlatShadedVertex>::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i) {
+ (*i).colour = colour;
+ }
+ }
+ };
+
+ struct RenderableQuad : public OpenGLRenderable {
+ PointVertex m_quad[4];
+
+ void render(RenderStateFlags state) const
+ {
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_quad[0].colour);
+ glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_quad[0].vertex);
+ glDrawArrays(GL_LINE_LOOP, 0, 4);
+ }
+
+ void setColour(const Colour4b &colour)
+ {
+ m_quad[0].colour = colour;
+ m_quad[1].colour = colour;
+ m_quad[2].colour = colour;
+ m_quad[3].colour = colour;
+ }
+ };
+
+ TranslateFree m_free;
+ TranslateAxis m_axis;
+ RenderableArrowLine m_arrow_x;
+ RenderableArrowLine m_arrow_y;
+ RenderableArrowLine m_arrow_z;
+ RenderableArrowHead m_arrow_head_x;
+ RenderableArrowHead m_arrow_head_y;
+ RenderableArrowHead m_arrow_head_z;
+ RenderableQuad m_quad_screen;
+ SelectableBool m_selectable_x;
+ SelectableBool m_selectable_y;
+ SelectableBool m_selectable_z;
+ SelectableBool m_selectable_screen;
+ Pivot2World m_pivot;
+public:
+ static Shader *m_state_wire;
+ static Shader *m_state_fill;
+
+ TranslateManipulator(Translatable &translatable, std::size_t segments, float length) :
+ m_free(translatable),
+ m_axis(translatable),
+ m_arrow_head_x(3 * 2 * (segments << 3)),
+ m_arrow_head_y(3 * 2 * (segments << 3)),
+ m_arrow_head_z(3 * 2 * (segments << 3))
+ {
+ draw_arrowline(length, m_arrow_x.m_line, 0);
+ draw_arrowhead(segments, length, m_arrow_head_x.m_vertices.data(), TripleRemapXYZ<Vertex3f>(),
+ TripleRemapXYZ<Normal3f>());
+ draw_arrowline(length, m_arrow_y.m_line, 1);
+ draw_arrowhead(segments, length, m_arrow_head_y.m_vertices.data(), TripleRemapYZX<Vertex3f>(),
+ TripleRemapYZX<Normal3f>());
+ draw_arrowline(length, m_arrow_z.m_line, 2);
+ draw_arrowhead(segments, length, m_arrow_head_z.m_vertices.data(), TripleRemapZXY<Vertex3f>(),
+ TripleRemapZXY<Normal3f>());
+
+ draw_quad(16, m_quad_screen.m_quad);
+ }
+
+ void UpdateColours()
+ {
+ m_arrow_x.setColour(colourSelected(g_colour_x, m_selectable_x.isSelected()));
+ m_arrow_head_x.setColour(colourSelected(g_colour_x, m_selectable_x.isSelected()));
+ m_arrow_y.setColour(colourSelected(g_colour_y, m_selectable_y.isSelected()));
+ m_arrow_head_y.setColour(colourSelected(g_colour_y, m_selectable_y.isSelected()));
+ m_arrow_z.setColour(colourSelected(g_colour_z, m_selectable_z.isSelected()));
+ m_arrow_head_z.setColour(colourSelected(g_colour_z, m_selectable_z.isSelected()));
+ m_quad_screen.setColour(colourSelected(g_colour_screen, m_selectable_screen.isSelected()));
+ }
+
+ bool manipulator_show_axis(const Pivot2World &pivot, const Vector3 &axis)
+ {
+ return fabs(vector3_dot(pivot.m_axis_screen, axis)) < 0.95;
+ }
+
+ void render(Renderer &renderer, const VolumeTest &volume, const Matrix4 &pivot2world)
+ {
+ m_pivot.update(pivot2world, volume.GetModelview(), volume.GetProjection(), volume.GetViewport());
+
+ // temp hack
+ UpdateColours();
+
+ Vector3 x = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.x()));
+ bool show_x = manipulator_show_axis(m_pivot, x);
+
+ Vector3 y = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.y()));
+ bool show_y = manipulator_show_axis(m_pivot, y);
+
+ Vector3 z = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.z()));
+ bool show_z = manipulator_show_axis(m_pivot, z);
+
+ renderer.SetState(m_state_wire, Renderer::eWireframeOnly);
+ renderer.SetState(m_state_wire, Renderer::eFullMaterials);
+
+ if (show_x) {
+ renderer.addRenderable(m_arrow_x, m_pivot.m_worldSpace);
+ }
+ if (show_y) {
+ renderer.addRenderable(m_arrow_y, m_pivot.m_worldSpace);
+ }
+ if (show_z) {
+ renderer.addRenderable(m_arrow_z, m_pivot.m_worldSpace);
+ }
+
+ renderer.addRenderable(m_quad_screen, m_pivot.m_viewplaneSpace);
+
+ renderer.SetState(m_state_fill, Renderer::eWireframeOnly);
+ renderer.SetState(m_state_fill, Renderer::eFullMaterials);
+
+ if (show_x) {
+ renderer.addRenderable(m_arrow_head_x, m_pivot.m_worldSpace);
+ }
+ if (show_y) {
+ renderer.addRenderable(m_arrow_head_y, m_pivot.m_worldSpace);
+ }
+ if (show_z) {
+ renderer.addRenderable(m_arrow_head_z, m_pivot.m_worldSpace);
+ }
+ }
+
+ void testSelect(const View &view, const Matrix4 &pivot2world)
+ {
+ m_pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport());
+
+ SelectionPool selector;
+
+ Vector3 x = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.x()));
+ bool show_x = manipulator_show_axis(m_pivot, x);
+
+ Vector3 y = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.y()));
+ bool show_y = manipulator_show_axis(m_pivot, y);
+
+ Vector3 z = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.z()));
+ bool show_z = manipulator_show_axis(m_pivot, z);
+
+ {
+ Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_viewpointSpace));
+
+ {
+ SelectionIntersection best;
+ Quad_BestPoint(local2view, eClipCullCW, m_quad_screen.m_quad, best);
+ if (best.valid()) {
+ best = SelectionIntersection(0, 0);
+ selector.addSelectable(best, &m_selectable_screen);
+ }
+ }
+ }
+
+ {
+ Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_worldSpace));