2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "selection.h"
24 #include "debugging/debugging.h"
30 #include "windowobserver.h"
34 #include "renderable.h"
35 #include "selectable.h"
38 #include "math/frustum.h"
39 #include "signal/signal.h"
40 #include "generic/object.h"
41 #include "selectionlib.h"
45 #include "stream/stringstream.h"
46 #include "eclasslib.h"
47 #include "generic/bitfield.h"
48 #include "generic/static.h"
51 #include "container/container.h"
55 TextOutputStream& ostream_write(TextOutputStream& t, const Vector4& v)
57 return t << "[ " << v.x() << " " << v.y() << " " << v.z() << " " << v.w() << " ]";
60 TextOutputStream& ostream_write(TextOutputStream& t, const Matrix4& m)
62 return t << "[ " << m.x() << " " << m.y() << " " << m.z() << " " << m.t() << " ]";
68 Matrix4 m_viewpointSpace;
69 Matrix4 m_viewplaneSpace;
70 Vector3 m_axis_screen;
72 void update(const Matrix4& pivot2world, const Matrix4& modelview, const Matrix4& projection, const Matrix4& viewport)
74 Pivot2World_worldSpace(m_worldSpace, pivot2world, modelview, projection, viewport);
75 Pivot2World_viewpointSpace(m_viewpointSpace, m_axis_screen, pivot2world, modelview, projection, viewport);
76 Pivot2World_viewplaneSpace(m_viewplaneSpace, pivot2world, modelview, projection, viewport);
81 void point_for_device_point(Vector3& point, const Matrix4& device2object, const float x, const float y, const float z)
83 // transform from normalised device coords to object coords
84 point = vector4_projected(matrix4_transformed_vector4(device2object, Vector4(x, y, z, 1)));
87 void ray_for_device_point(Ray& ray, const Matrix4& device2object, const float x, const float y)
89 // point at x, y, zNear
90 point_for_device_point(ray.origin, device2object, x, y, -1);
92 // point at x, y, zFar
93 point_for_device_point(ray.direction, device2object, x, y, 1);
96 vector3_subtract(ray.direction, ray.origin);
97 vector3_normalise(ray.direction);
100 bool sphere_intersect_ray(const Vector3& origin, float radius, const Ray& ray, Vector3& intersection)
102 intersection = vector3_subtracted(origin, ray.origin);
103 const double a = vector3_dot(intersection, ray.direction);
104 const double d = radius * radius - (vector3_dot(intersection, intersection) - a * a);
108 intersection = vector3_added(ray.origin, vector3_scaled(ray.direction, a - sqrt(d)));
113 intersection = vector3_added( ray.origin, vector3_scaled(ray.direction, a));
118 void ray_intersect_ray(const Ray& ray, const Ray& other, Vector3& intersection)
120 intersection = vector3_subtracted(ray.origin, other.origin);
121 //float a = 1;//vector3_dot(ray.direction, ray.direction); // always >= 0
122 double dot = vector3_dot(ray.direction, other.direction);
123 //float c = 1;//vector3_dot(other.direction, other.direction); // always >= 0
124 double d = vector3_dot(ray.direction, intersection);
125 double e = vector3_dot(other.direction, intersection);
126 double D = 1 - dot*dot;//a*c - dot*dot; // always >= 0
130 // the lines are almost parallel
131 intersection = vector3_added(other.origin, vector3_scaled(other.direction, e));
135 intersection = vector3_added(other.origin, vector3_scaled(other.direction, (e - dot*d) / D));
139 const Vector3 g_origin(0, 0, 0);
140 const float g_radius = 64;
142 void point_on_sphere(Vector3& point, const Matrix4& device2object, const float x, const float y)
145 ray_for_device_point(ray, device2object, x, y);
146 sphere_intersect_ray(g_origin, g_radius, ray, point);
149 void point_on_axis(Vector3& point, const Vector3& axis, const Matrix4& device2object, const float x, const float y)
152 ray_for_device_point(ray, device2object, x, y);
153 ray_intersect_ray(ray, Ray(Vector3(0, 0, 0), axis), point);
156 void point_on_plane(Vector3& point, const Matrix4& device2object, const float x, const float y)
158 Matrix4 object2device(matrix4_full_inverse(device2object));
159 point = vector4_projected(matrix4_transformed_vector4(device2object, Vector4(x, y, object2device[14] / object2device[15], 1)));
162 //! a and b are unit vectors .. returns angle in radians
163 inline float angle_between(const Vector3& a, const Vector3& b)
165 return static_cast<float>(2.0 * atan2(
166 vector3_length(vector3_subtracted(a, b)),
167 vector3_length(vector3_added(a, b))
176 test_quat(const Vector3& from, const Vector3& to)
178 Vector4 quaternion(quaternion_for_unit_vectors(from, to));
179 Matrix4 matrix(matrix4_rotation_for_quaternion(quaternion_multiplied_by_quaternion(quaternion, c_quaternion_identity)));
184 static test_quat bleh(g_vector3_axis_x, g_vector3_axis_y);
187 //! axis is a unit vector
188 inline void constrain_to_axis(Vector3& vec, const Vector3& axis)
190 vec = vector3_normalised(vector3_added(vec, vector3_scaled(axis, -vector3_dot(vec, axis))));
193 //! a and b are unit vectors .. a and b must be orthogonal to axis .. returns angle in radians
194 float angle_for_axis(const Vector3& a, const Vector3& b, const Vector3& axis)
196 if(vector3_dot(axis, vector3_cross(a, b)) > 0.0)
197 return angle_between(a, b);
199 return -angle_between(a, b);
202 float distance_for_axis(const Vector3& a, const Vector3& b, const Vector3& axis)
204 return static_cast<float>(vector3_dot(b, axis) - vector3_dot(a, axis));
210 virtual void Construct(const Matrix4& device2manip, const float x, const float y) = 0;
211 virtual void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y) = 0;
214 void transform_local2object(Matrix4& object, const Matrix4& local, const Matrix4& local2object)
216 object = matrix4_multiplied_by_matrix4(
217 matrix4_multiplied_by_matrix4(local2object, local),
218 matrix4_full_inverse(local2object)
225 virtual void rotate(const Quaternion& rotation) = 0;
228 class RotateFree : public Manipulatable
231 Rotatable& m_rotatable;
233 RotateFree(Rotatable& rotatable)
234 : m_rotatable(rotatable)
237 void Construct(const Matrix4& device2manip, const float x, const float y)
239 point_on_sphere(m_start, device2manip, x, y);
240 vector3_normalise(m_start);
242 void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
246 point_on_sphere(current, device2manip, x, y);
247 vector3_normalise(current);
249 m_rotatable.rotate(quaternion_for_unit_vectors(m_start, current));
253 class RotateAxis : public Manipulatable
257 Rotatable& m_rotatable;
259 RotateAxis(Rotatable& rotatable)
260 : m_rotatable(rotatable)
263 void Construct(const Matrix4& device2manip, const float x, const float y)
265 point_on_sphere(m_start, device2manip, x, y);
266 constrain_to_axis(m_start, m_axis);
268 /// \brief Converts current position to a normalised vector orthogonal to axis.
269 void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
272 point_on_sphere(current, device2manip, x, y);
273 constrain_to_axis(current, m_axis);
275 m_rotatable.rotate(quaternion_for_axisangle(m_axis, angle_for_axis(m_start, current, m_axis)));
278 void SetAxis(const Vector3& axis)
284 void translation_local2object(Vector3& object, const Vector3& local, const Matrix4& local2object)
286 object = matrix4_get_translation_vec3(
287 matrix4_multiplied_by_matrix4(
288 matrix4_translated_by_vec3(local2object, local),
289 matrix4_full_inverse(local2object)
297 virtual void translate(const Vector3& translation) = 0;
300 class TranslateAxis : public Manipulatable
304 Translatable& m_translatable;
306 TranslateAxis(Translatable& translatable)
307 : m_translatable(translatable)
310 void Construct(const Matrix4& device2manip, const float x, const float y)
312 point_on_axis(m_start, m_axis, device2manip, x, y);
314 void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
317 point_on_axis(current, m_axis, device2manip, x, y);
318 current = vector3_scaled(m_axis, distance_for_axis(m_start, current, m_axis));
320 translation_local2object(current, current, manip2object);
321 vector3_snap(current, GetGridSize());
323 m_translatable.translate(current);
326 void SetAxis(const Vector3& axis)
332 class TranslateFree : public Manipulatable
336 Translatable& m_translatable;
338 TranslateFree(Translatable& translatable)
339 : m_translatable(translatable)
342 void Construct(const Matrix4& device2manip, const float x, const float y)
344 point_on_plane(m_start, device2manip, x, y);
346 void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
349 point_on_plane(current, device2manip, x, y);
350 current = vector3_subtracted(current, m_start);
352 translation_local2object(current, current, manip2object);
353 vector3_snap(current, GetGridSize());
355 m_translatable.translate(current);
363 virtual void scale(const Vector3& scaling) = 0;
367 class ScaleAxis : public Manipulatable
372 Scalable& m_scalable;
374 ScaleAxis(Scalable& scalable)
375 : m_scalable(scalable)
378 void Construct(const Matrix4& device2manip, const float x, const float y)
380 point_on_axis(m_start, m_axis, device2manip, x, y);
382 void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
385 point_on_axis(current, m_axis, device2manip, x, y);
386 Vector3 delta = vector3_subtracted(current, m_start);
388 translation_local2object(delta, delta, manip2object);
389 vector3_snap(delta, GetGridSize());
391 Vector3 start(vector3_snapped(m_start, GetGridSize()));
393 start[0] == 0 ? 1 : 1 + delta[0] / start[0],
394 start[1] == 0 ? 1 : 1 + delta[1] / start[1],
395 start[2] == 0 ? 1 : 1 + delta[2] / start[2]
397 m_scalable.scale(scale);
400 void SetAxis(const Vector3& axis)
406 class ScaleFree : public Manipulatable
410 Scalable& m_scalable;
412 ScaleFree(Scalable& scalable)
413 : m_scalable(scalable)
416 void Construct(const Matrix4& device2manip, const float x, const float y)
418 point_on_plane(m_start, device2manip, x, y);
420 void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
423 point_on_plane(current, device2manip, x, y);
424 Vector3 delta = vector3_subtracted(current, m_start);
426 translation_local2object(delta, delta, manip2object);
427 vector3_snap(delta, GetGridSize());
429 Vector3 start(vector3_snapped(m_start, GetGridSize()));
431 start[0] == 0 ? 1 : 1 + delta[0] / start[0],
432 start[1] == 0 ? 1 : 1 + delta[1] / start[1],
433 start[2] == 0 ? 1 : 1 + delta[2] / start[2]
435 m_scalable.scale(scale);
448 class RenderableClippedPrimitive : public OpenGLRenderable
452 PointVertex m_points[9];
456 std::vector<primitive_t> m_primitives;
460 void render(RenderStateFlags state) const
462 for(std::size_t i=0; i<m_primitives.size(); ++i)
464 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_primitives[i].m_points[0].colour);
465 glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_primitives[i].m_points[0].vertex);
466 switch(m_primitives[i].m_count)
469 case 2: glDrawArrays(GL_LINES, 0, GLsizei(m_primitives[i].m_count)); break;
470 default: glDrawArrays(GL_POLYGON, 0, GLsizei(m_primitives[i].m_count)); break;
475 void construct(const Matrix4& world2device)
477 m_inverse = matrix4_full_inverse(world2device);
478 m_world = g_matrix4_identity;
481 void insert(const Vector4 clipped[9], std::size_t count)
485 m_primitives.back().m_count = count;
486 for(std::size_t i=0; i<count; ++i)
488 Vector3 world_point(vector4_projected(matrix4_transformed_vector4(m_inverse, clipped[i])));
489 m_primitives.back().m_points[i].vertex = vertex3f_for_vector3(world_point);
495 m_primitives.clear();
500 m_primitives.push_back(primitive_t());
502 const Colour4b colour_clipped(255, 127, 0, 255);
504 for(std::size_t i=0; i<9; ++i)
505 m_primitives.back().m_points[i].colour = colour_clipped;
510 #define DEBUG_SELECTION
513 #if defined(DEBUG_SELECTION)
514 Shader* g_state_clipped;
515 RenderableClippedPrimitive g_render_clipped;
520 // dist_Point_to_Line(): get the distance of a point to a line.
521 // Input: a Point P and a Line L (in any dimension)
522 // Return: the shortest distance from P to L
524 dist_Point_to_Line( Point P, Line L)
526 Vector v = L.P1 - L.P0;
529 double c1 = dot(w,v);
530 double c2 = dot(v,v);
533 Point Pb = L.P0 + b * v;
540 typedef Vector3 point_type;
542 Segment3D(const point_type& _p0, const point_type& _p1)
550 typedef Vector3 Point3D;
552 inline double vector3_distance_squared(const Point3D& a, const Point3D& b)
554 return vector3_length_squared(b - a);
557 // get the distance of a point to a segment.
558 Point3D segment_closest_point_to_point(const Segment3D& segment, const Point3D& point)
560 Vector3 v = segment.p1 - segment.p0;
561 Vector3 w = point - segment.p0;
563 double c1 = vector3_dot(w,v);
567 double c2 = vector3_dot(v,v);
571 return Point3D(segment.p0 + v * (c1 / c2));
574 double segment_dist_to_point_3d(const Segment3D& segment, const Point3D& point)
576 return vector3_distance_squared(point, segment_closest_point_to_point(segment, point));
579 typedef Vector3 point_t;
580 typedef const Vector3* point_iterator_t;
582 // crossing number test for a point in a polygon
583 // This code is patterned after [Franklin, 2000]
584 bool point_test_polygon_2d( const point_t& P, point_iterator_t start, point_iterator_t finish )
586 std::size_t crossings = 0;
588 // loop through all edges of the polygon
589 for(point_iterator_t prev = finish-1, cur = start; cur != finish; prev = cur, ++cur)
590 { // edge from (*prev) to (*cur)
591 if ((((*prev)[1] <= P[1]) && ((*cur)[1] > P[1])) // an upward crossing
592 || (((*prev)[1] > P[1]) && ((*cur)[1] <= P[1])))
593 { // a downward crossing
594 // compute the actual edge-ray intersect x-coordinate
595 float vt = (float)(P[1] - (*prev)[1]) / ((*cur)[1] - (*prev)[1]);
596 if (P[0] < (*prev)[0] + vt * ((*cur)[0] - (*prev)[0])) // P[0] < intersect
598 ++crossings; // a valid crossing of y=P[1] right of P[0]
602 return (crossings & 0x1) != 0; // 0 if even (out), and 1 if odd (in)
605 inline double triangle_signed_area_XY(const Vector3& p0, const Vector3& p1, const Vector3& p2)
607 return ((p1[0] - p0[0]) * (p2[1] - p0[1])) - ((p2[0] - p0[0]) * (p1[1] - p0[1]));
618 inline SelectionIntersection select_point_from_clipped(Vector4& clipped)
620 return SelectionIntersection(clipped[2] / clipped[3], static_cast<float>(vector3_length_squared(Vector3(clipped[0] / clipped[3], clipped[1] / clipped[3], 0))));
623 void BestPoint(std::size_t count, Vector4 clipped[9], SelectionIntersection& best, clipcull_t cull)
625 Vector3 normalised[9];
628 for(std::size_t i=0; i<count; ++i)
630 normalised[i][0] = clipped[i][0] / clipped[i][3];
631 normalised[i][1] = clipped[i][1] / clipped[i][3];
632 normalised[i][2] = clipped[i][2] / clipped[i][3];
636 if(cull != eClipCullNone && count > 2)
638 double signed_area = triangle_signed_area_XY(normalised[0], normalised[1], normalised[2]);
640 if((cull == eClipCullCW && signed_area > 0)
641 || (cull == eClipCullCCW && signed_area < 0))
647 Segment3D segment(normalised[0], normalised[1]);
648 Point3D point = segment_closest_point_to_point(segment, Vector3(0, 0, 0));
649 assign_if_closer(best, SelectionIntersection(point.z(), 0));
651 else if(count > 2 && !point_test_polygon_2d(Vector3(0, 0, 0), normalised, normalised + count))
653 point_iterator_t end = normalised + count;
654 for(point_iterator_t previous = end-1, current = normalised; current != end; previous = current, ++current)
656 Segment3D segment(*previous, *current);
657 Point3D point = segment_closest_point_to_point(segment, Vector3(0, 0, 0));
658 float depth = point.z();
660 float distance = static_cast<float>(vector3_length_squared(point));
662 assign_if_closer(best, SelectionIntersection(depth, distance));
669 SelectionIntersection(
670 static_cast<float>(ray_distance_to_plane(
671 Ray(Vector3(0, 0, 0), Vector3(0, 0, 1)),
672 plane3_for_points(normalised[0], normalised[1], normalised[2])
679 #if defined(DEBUG_SELECTION)
681 g_render_clipped.insert(clipped, count);
685 void LineStrip_BestPoint(const Matrix4& local2view, const PointVertex* vertices, const std::size_t size, SelectionIntersection& best)
688 for(std::size_t i = 0; (i + 1) < size; ++i)
690 const std::size_t count = matrix4_clip_line(local2view, vertex3f_to_vector3(vertices[i].vertex), vertex3f_to_vector3(vertices[i + 1].vertex), clipped);
691 BestPoint(count, clipped, best, eClipCullNone);
695 void LineLoop_BestPoint(const Matrix4& local2view, const PointVertex* vertices, const std::size_t size, SelectionIntersection& best)
698 for(std::size_t i = 0; i < size; ++i)
700 const std::size_t count = matrix4_clip_line(local2view, vertex3f_to_vector3(vertices[i].vertex), vertex3f_to_vector3(vertices[(i+1)%size].vertex), clipped);
701 BestPoint(count, clipped, best, eClipCullNone);
705 void Line_BestPoint(const Matrix4& local2view, const PointVertex vertices[2], SelectionIntersection& best)
708 const std::size_t count = matrix4_clip_line(local2view, vertex3f_to_vector3(vertices[0].vertex), vertex3f_to_vector3(vertices[1].vertex), clipped);
709 BestPoint(count, clipped, best, eClipCullNone);
712 void Circle_BestPoint(const Matrix4& local2view, clipcull_t cull, const PointVertex* vertices, const std::size_t size, SelectionIntersection& best)
715 for(std::size_t i=0; i<size; ++i)
717 const std::size_t count = matrix4_clip_triangle(local2view, g_vector3_identity, vertex3f_to_vector3(vertices[i].vertex), vertex3f_to_vector3(vertices[(i+1)%size].vertex), clipped);
718 BestPoint(count, clipped, best, cull);
722 void Quad_BestPoint(const Matrix4& local2view, clipcull_t cull, const PointVertex* vertices, SelectionIntersection& best)
726 const std::size_t count = matrix4_clip_triangle(local2view, vertex3f_to_vector3(vertices[0].vertex), vertex3f_to_vector3(vertices[1].vertex), vertex3f_to_vector3(vertices[3].vertex), clipped);
727 BestPoint(count, clipped, best, cull);
730 const std::size_t count = matrix4_clip_triangle(local2view, vertex3f_to_vector3(vertices[1].vertex), vertex3f_to_vector3(vertices[2].vertex), vertex3f_to_vector3(vertices[3].vertex), clipped);
731 BestPoint(count, clipped, best, cull);
735 struct FlatShadedVertex
747 typedef FlatShadedVertex* FlatShadedVertexIterator;
748 void Triangles_BestPoint(const Matrix4& local2view, clipcull_t cull, FlatShadedVertexIterator first, FlatShadedVertexIterator last, SelectionIntersection& best)
750 for(FlatShadedVertexIterator x(first), y(first+1), z(first+2); x != last; x += 3, y += 3, z +=3)
754 matrix4_clip_triangle(
756 reinterpret_cast<const Vector3&>((*x).vertex),
757 reinterpret_cast<const Vector3&>((*y).vertex),
758 reinterpret_cast<const Vector3&>((*z).vertex),
769 typedef std::multimap<SelectionIntersection, Selectable*> SelectableSortedSet;
771 class SelectionPool : public Selector
773 SelectableSortedSet m_pool;
774 SelectionIntersection m_intersection;
775 Selectable* m_selectable;
778 void pushSelectable(Selectable& selectable)
780 m_intersection = SelectionIntersection();
781 m_selectable = &selectable;
785 addSelectable(m_intersection, m_selectable);
786 m_intersection = SelectionIntersection();
788 void addIntersection(const SelectionIntersection& intersection)
790 assign_if_closer(m_intersection, intersection);
792 void addSelectable(const SelectionIntersection& intersection, Selectable* selectable)
794 if(intersection.valid())
796 m_pool.insert(SelectableSortedSet::value_type(intersection, selectable));
800 typedef SelectableSortedSet::iterator iterator;
804 return m_pool.begin();
813 return m_pool.empty();
818 const Colour4b g_colour_sphere(0, 0, 0, 255);
819 const Colour4b g_colour_screen(0, 255, 255, 255);
820 const Colour4b g_colour_selected(255, 255, 0, 255);
822 inline const Colour4b& colourSelected(const Colour4b& colour, bool selected)
824 return (selected) ? g_colour_selected : colour;
827 template<typename remap_policy>
828 inline void draw_semicircle(const std::size_t segments, const float radius, PointVertex* vertices, remap_policy remap)
830 const double increment = c_pi / double(segments << 2);
832 std::size_t count = 0;
835 remap_policy::set(vertices[segments << 2].vertex, -radius, 0, 0);
836 while(count < segments)
838 PointVertex* i = vertices + count;
839 PointVertex* j = vertices + ((segments << 1) - (count + 1));
841 PointVertex* k = i + (segments << 1);
842 PointVertex* l = j + (segments << 1);
845 PointVertex* m = i + (segments << 2);
846 PointVertex* n = j + (segments << 2);
847 PointVertex* o = k + (segments << 2);
848 PointVertex* p = l + (segments << 2);
851 remap_policy::set(i->vertex, x,-y, 0);
852 remap_policy::set(k->vertex,-y,-x, 0);
854 remap_policy::set(m->vertex,-x, y, 0);
855 remap_policy::set(o->vertex, y, x, 0);
861 const double theta = increment * count;
862 x = static_cast<float>(radius * cos(theta));
863 y = static_cast<float>(radius * sin(theta));
866 remap_policy::set(j->vertex, y,-x, 0);
867 remap_policy::set(l->vertex,-x,-y, 0);
869 remap_policy::set(n->vertex,-y, x, 0);
870 remap_policy::set(p->vertex, x, y, 0);
878 virtual Manipulatable* GetManipulatable() = 0;
879 virtual void testSelect(const View& view, const Matrix4& pivot2world)
882 virtual void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world)
885 virtual void setSelected(bool select) = 0;
886 virtual bool isSelected() const = 0;
890 inline Vector3 normalised_safe(const Vector3& self)
892 if(vector3_equal(self, g_vector3_identity))
894 return g_vector3_identity;
896 return vector3_normalised(self);
900 class RotateManipulator : public Manipulator
902 struct RenderableCircle : public OpenGLRenderable
904 Array<PointVertex> m_vertices;
906 RenderableCircle(std::size_t size) : m_vertices(size)
909 void render(RenderStateFlags state) const
911 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_vertices.data()->colour);
912 glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_vertices.data()->vertex);
913 glDrawArrays(GL_LINE_LOOP, 0, GLsizei(m_vertices.size()));
915 void setColour(const Colour4b& colour)
917 for(Array<PointVertex>::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
919 (*i).colour = colour;
924 struct RenderableSemiCircle : public OpenGLRenderable
926 Array<PointVertex> m_vertices;
928 RenderableSemiCircle(std::size_t size) : m_vertices(size)
931 void render(RenderStateFlags state) const
933 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_vertices.data()->colour);
934 glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_vertices.data()->vertex);
935 glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_vertices.size()));
937 void setColour(const Colour4b& colour)
939 for(Array<PointVertex>::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
941 (*i).colour = colour;
948 Vector3 m_axis_screen;
949 RenderableSemiCircle m_circle_x;
950 RenderableSemiCircle m_circle_y;
951 RenderableSemiCircle m_circle_z;
952 RenderableCircle m_circle_screen;
953 RenderableCircle m_circle_sphere;
954 SelectableBool m_selectable_x;
955 SelectableBool m_selectable_y;
956 SelectableBool m_selectable_z;
957 SelectableBool m_selectable_screen;
958 SelectableBool m_selectable_sphere;
960 Matrix4 m_local2world_x;
961 Matrix4 m_local2world_y;
962 Matrix4 m_local2world_z;
963 bool m_circle_x_visible;
964 bool m_circle_y_visible;
965 bool m_circle_z_visible;
967 static Shader* m_state_outer;
969 RotateManipulator(Rotatable& rotatable, std::size_t segments, float radius) :
972 m_circle_x((segments << 2) + 1),
973 m_circle_y((segments << 2) + 1),
974 m_circle_z((segments << 2) + 1),
975 m_circle_screen(segments<<3),
976 m_circle_sphere(segments<<3)
978 draw_semicircle(segments, radius, m_circle_x.m_vertices.data(), RemapYZX());
979 draw_semicircle(segments, radius, m_circle_y.m_vertices.data(), RemapZXY());
980 draw_semicircle(segments, radius, m_circle_z.m_vertices.data(), RemapXYZ());
982 draw_circle(segments, radius * 1.15f, m_circle_screen.m_vertices.data(), RemapXYZ());
983 draw_circle(segments, radius, m_circle_sphere.m_vertices.data(), RemapXYZ());
989 m_circle_x.setColour(colourSelected(g_colour_x, m_selectable_x.isSelected()));
990 m_circle_y.setColour(colourSelected(g_colour_y, m_selectable_y.isSelected()));
991 m_circle_z.setColour(colourSelected(g_colour_z, m_selectable_z.isSelected()));
992 m_circle_screen.setColour(colourSelected(g_colour_screen, m_selectable_screen.isSelected()));
993 m_circle_sphere.setColour(colourSelected(g_colour_sphere, false));
996 void updateCircleTransforms()
998 Vector3 localViewpoint(matrix4_transformed_direction(matrix4_transposed(m_pivot.m_worldSpace), vector4_to_vector3(m_pivot.m_viewpointSpace.z())));
1000 m_circle_x_visible = !vector3_equal_epsilon(g_vector3_axis_x, localViewpoint, 1e-6f);
1001 if(m_circle_x_visible)
1003 m_local2world_x = g_matrix4_identity;
1004 vector4_to_vector3(m_local2world_x.y()) = normalised_safe(
1005 vector3_cross(g_vector3_axis_x, localViewpoint)
1007 vector4_to_vector3(m_local2world_x.z()) = normalised_safe(
1008 vector3_cross(vector4_to_vector3(m_local2world_x.x()), vector4_to_vector3(m_local2world_x.y()))
1010 matrix4_premultiply_by_matrix4(m_local2world_x, m_pivot.m_worldSpace);
1013 m_circle_y_visible = !vector3_equal_epsilon(g_vector3_axis_y, localViewpoint, 1e-6f);
1014 if(m_circle_y_visible)
1016 m_local2world_y = g_matrix4_identity;
1017 vector4_to_vector3(m_local2world_y.z()) = normalised_safe(
1018 vector3_cross(g_vector3_axis_y, localViewpoint)
1020 vector4_to_vector3(m_local2world_y.x()) = normalised_safe(
1021 vector3_cross(vector4_to_vector3(m_local2world_y.y()), vector4_to_vector3(m_local2world_y.z()))
1023 matrix4_premultiply_by_matrix4(m_local2world_y, m_pivot.m_worldSpace);
1026 m_circle_z_visible = !vector3_equal_epsilon(g_vector3_axis_z, localViewpoint, 1e-6f);
1027 if(m_circle_z_visible)
1029 m_local2world_z = g_matrix4_identity;
1030 vector4_to_vector3(m_local2world_z.x()) = normalised_safe(
1031 vector3_cross(g_vector3_axis_z, localViewpoint)
1033 vector4_to_vector3(m_local2world_z.y()) = normalised_safe(
1034 vector3_cross(vector4_to_vector3(m_local2world_z.z()), vector4_to_vector3(m_local2world_z.x()))
1036 matrix4_premultiply_by_matrix4(m_local2world_z, m_pivot.m_worldSpace);
1040 void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world)
1042 m_pivot.update(pivot2world, volume.GetModelview(), volume.GetProjection(), volume.GetViewport());
1043 updateCircleTransforms();
1048 renderer.SetState(m_state_outer, Renderer::eWireframeOnly);
1049 renderer.SetState(m_state_outer, Renderer::eFullMaterials);
1051 renderer.addRenderable(m_circle_screen, m_pivot.m_viewpointSpace);
1052 renderer.addRenderable(m_circle_sphere, m_pivot.m_viewpointSpace);
1054 if(m_circle_x_visible)
1056 renderer.addRenderable(m_circle_x, m_local2world_x);
1058 if(m_circle_y_visible)
1060 renderer.addRenderable(m_circle_y, m_local2world_y);
1062 if(m_circle_z_visible)
1064 renderer.addRenderable(m_circle_z, m_local2world_z);
1067 void testSelect(const View& view, const Matrix4& pivot2world)
1069 m_pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport());
1070 updateCircleTransforms();
1072 SelectionPool selector;
1076 Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_local2world_x));
1078 #if defined(DEBUG_SELECTION)
1079 g_render_clipped.construct(view.GetViewMatrix());
1082 SelectionIntersection best;
1083 LineStrip_BestPoint(local2view, m_circle_x.m_vertices.data(), m_circle_x.m_vertices.size(), best);
1084 selector.addSelectable(best, &m_selectable_x);
1088 Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_local2world_y));
1090 #if defined(DEBUG_SELECTION)
1091 g_render_clipped.construct(view.GetViewMatrix());
1094 SelectionIntersection best;
1095 LineStrip_BestPoint(local2view, m_circle_y.m_vertices.data(), m_circle_y.m_vertices.size(), best);
1096 selector.addSelectable(best, &m_selectable_y);
1100 Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_local2world_z));
1102 #if defined(DEBUG_SELECTION)
1103 g_render_clipped.construct(view.GetViewMatrix());
1106 SelectionIntersection best;
1107 LineStrip_BestPoint(local2view, m_circle_z.m_vertices.data(), m_circle_z.m_vertices.size(), best);
1108 selector.addSelectable(best, &m_selectable_z);
1113 Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_viewpointSpace));
1116 SelectionIntersection best;
1117 LineLoop_BestPoint(local2view, m_circle_screen.m_vertices.data(), m_circle_screen.m_vertices.size(), best);
1118 selector.addSelectable(best, &m_selectable_screen);
1122 SelectionIntersection best;
1123 Circle_BestPoint(local2view, eClipCullCW, m_circle_sphere.m_vertices.data(), m_circle_sphere.m_vertices.size(), best);
1124 selector.addSelectable(best, &m_selectable_sphere);
1128 m_axis_screen = m_pivot.m_axis_screen;
1130 if(!selector.failed())
1132 (*selector.begin()).second->setSelected(true);
1136 Manipulatable* GetManipulatable()
1138 if(m_selectable_x.isSelected())
1140 m_axis.SetAxis(g_vector3_axis_x);
1143 else if(m_selectable_y.isSelected())
1145 m_axis.SetAxis(g_vector3_axis_y);
1148 else if(m_selectable_z.isSelected())
1150 m_axis.SetAxis(g_vector3_axis_z);
1153 else if(m_selectable_screen.isSelected())
1155 m_axis.SetAxis(m_axis_screen);
1162 void setSelected(bool select)
1164 m_selectable_x.setSelected(select);
1165 m_selectable_y.setSelected(select);
1166 m_selectable_z.setSelected(select);
1167 m_selectable_screen.setSelected(select);
1169 bool isSelected() const
1171 return m_selectable_x.isSelected()
1172 | m_selectable_y.isSelected()
1173 | m_selectable_z.isSelected()
1174 | m_selectable_screen.isSelected()
1175 | m_selectable_sphere.isSelected();
1179 Shader* RotateManipulator::m_state_outer;
1182 const float arrowhead_length = 16;
1183 const float arrowhead_radius = 4;
1185 inline void draw_arrowline(const float length, PointVertex* line, const std::size_t axis)
1187 (*line++).vertex = vertex3f_identity;
1188 (*line).vertex = vertex3f_identity;
1189 vertex3f_to_array((*line).vertex)[axis] = length - arrowhead_length;
1192 template<typename VertexRemap, typename NormalRemap>
1193 inline void draw_arrowhead(const std::size_t segments, const float length, FlatShadedVertex* vertices, VertexRemap, NormalRemap)
1195 std::size_t head_tris = (segments << 3);
1196 const double head_segment = c_2pi / head_tris;
1197 for(std::size_t i = 0; i < head_tris; ++i)
1200 FlatShadedVertex& point = vertices[i*6+0];
1201 VertexRemap::x(point.vertex) = length - arrowhead_length;
1202 VertexRemap::y(point.vertex) = arrowhead_radius * static_cast<float>(cos(i * head_segment));
1203 VertexRemap::z(point.vertex) = arrowhead_radius * static_cast<float>(sin(i * head_segment));
1204 NormalRemap::x(point.normal) = arrowhead_radius / arrowhead_length;
1205 NormalRemap::y(point.normal) = static_cast<float>(cos(i * head_segment));
1206 NormalRemap::z(point.normal) = static_cast<float>(sin(i * head_segment));
1209 FlatShadedVertex& point = vertices[i*6+1];
1210 VertexRemap::x(point.vertex) = length;
1211 VertexRemap::y(point.vertex) = 0;
1212 VertexRemap::z(point.vertex) = 0;
1213 NormalRemap::x(point.normal) = arrowhead_radius / arrowhead_length;
1214 NormalRemap::y(point.normal) = static_cast<float>(cos((i + 0.5) * head_segment));
1215 NormalRemap::z(point.normal) = static_cast<float>(sin((i + 0.5) * head_segment));
1218 FlatShadedVertex& point = vertices[i*6+2];
1219 VertexRemap::x(point.vertex) = length - arrowhead_length;
1220 VertexRemap::y(point.vertex) = arrowhead_radius * static_cast<float>(cos((i+1) * head_segment));
1221 VertexRemap::z(point.vertex) = arrowhead_radius * static_cast<float>(sin((i+1) * head_segment));
1222 NormalRemap::x(point.normal) = arrowhead_radius / arrowhead_length;
1223 NormalRemap::y(point.normal) = static_cast<float>(cos((i+1) * head_segment));
1224 NormalRemap::z(point.normal) = static_cast<float>(sin((i+1) * head_segment));
1228 FlatShadedVertex& point = vertices[i*6+3];
1229 VertexRemap::x(point.vertex) = length - arrowhead_length;
1230 VertexRemap::y(point.vertex) = 0;
1231 VertexRemap::z(point.vertex) = 0;
1232 NormalRemap::x(point.normal) = -1;
1233 NormalRemap::y(point.normal) = 0;
1234 NormalRemap::z(point.normal) = 0;
1237 FlatShadedVertex& point = vertices[i*6+4];
1238 VertexRemap::x(point.vertex) = length - arrowhead_length;
1239 VertexRemap::y(point.vertex) = arrowhead_radius * static_cast<float>(cos(i * head_segment));
1240 VertexRemap::z(point.vertex) = arrowhead_radius * static_cast<float>(sin(i * head_segment));
1241 NormalRemap::x(point.normal) = -1;
1242 NormalRemap::y(point.normal) = 0;
1243 NormalRemap::z(point.normal) = 0;
1246 FlatShadedVertex& point = vertices[i*6+5];
1247 VertexRemap::x(point.vertex) = length - arrowhead_length;
1248 VertexRemap::y(point.vertex) = arrowhead_radius * static_cast<float>(cos((i+1) * head_segment));
1249 VertexRemap::z(point.vertex) = arrowhead_radius * static_cast<float>(sin((i+1) * head_segment));
1250 NormalRemap::x(point.normal) = -1;
1251 NormalRemap::y(point.normal) = 0;
1252 NormalRemap::z(point.normal) = 0;
1257 template<typename Triple>
1258 class TripleRemapXYZ
1261 static float& x(Triple& triple)
1265 static float& y(Triple& triple)
1269 static float& z(Triple& triple)
1275 template<typename Triple>
1276 class TripleRemapYZX
1279 static float& x(Triple& triple)
1283 static float& y(Triple& triple)
1287 static float& z(Triple& triple)
1293 template<typename Triple>
1294 class TripleRemapZXY
1297 static float& x(Triple& triple)
1301 static float& y(Triple& triple)
1305 static float& z(Triple& triple)
1311 void vector3_print(const Vector3& v)
1313 globalOutputStream() << "( " << v.x() << " " << v.y() << " " << v.z() << " )";
1316 class TranslateManipulator : public Manipulator
1318 struct RenderableArrowLine : public OpenGLRenderable
1320 PointVertex m_line[2];
1322 RenderableArrowLine()
1325 void render(RenderStateFlags state) const
1327 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_line[0].colour);
1328 glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_line[0].vertex);
1329 glDrawArrays(GL_LINES, 0, 2);
1331 void setColour(const Colour4b& colour)
1333 m_line[0].colour = colour;
1334 m_line[1].colour = colour;
1337 struct RenderableArrowHead : public OpenGLRenderable
1339 Array<FlatShadedVertex> m_vertices;
1341 RenderableArrowHead(std::size_t size)
1345 void render(RenderStateFlags state) const
1347 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(FlatShadedVertex), &m_vertices.data()->colour);
1348 glVertexPointer(3, GL_FLOAT, sizeof(FlatShadedVertex), &m_vertices.data()->vertex);
1349 glNormalPointer(GL_FLOAT, sizeof(FlatShadedVertex), &m_vertices.data()->normal);
1350 glDrawArrays(GL_TRIANGLES, 0, GLsizei(m_vertices.size()));
1352 void setColour(const Colour4b& colour)
1354 for(Array<FlatShadedVertex>::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
1356 (*i).colour = colour;
1360 struct RenderableQuad : public OpenGLRenderable
1362 PointVertex m_quad[4];
1363 void render(RenderStateFlags state) const
1365 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_quad[0].colour);
1366 glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_quad[0].vertex);
1367 glDrawArrays(GL_LINE_LOOP, 0, 4);
1369 void setColour(const Colour4b& colour)
1371 m_quad[0].colour = colour;
1372 m_quad[1].colour = colour;
1373 m_quad[2].colour = colour;
1374 m_quad[3].colour = colour;
1378 TranslateFree m_free;
1379 TranslateAxis m_axis;
1380 RenderableArrowLine m_arrow_x;
1381 RenderableArrowLine m_arrow_y;
1382 RenderableArrowLine m_arrow_z;
1383 RenderableArrowHead m_arrow_head_x;
1384 RenderableArrowHead m_arrow_head_y;
1385 RenderableArrowHead m_arrow_head_z;
1386 RenderableQuad m_quad_screen;
1387 SelectableBool m_selectable_x;
1388 SelectableBool m_selectable_y;
1389 SelectableBool m_selectable_z;
1390 SelectableBool m_selectable_screen;
1391 Pivot2World m_pivot;
1393 static Shader* m_state_wire;
1394 static Shader* m_state_fill;
1396 TranslateManipulator(Translatable& translatable, std::size_t segments, float length) :
1397 m_free(translatable),
1398 m_axis(translatable),
1399 m_arrow_head_x(3 * 2 * (segments << 3)),
1400 m_arrow_head_y(3 * 2 * (segments << 3)),
1401 m_arrow_head_z(3 * 2 * (segments << 3))
1403 draw_arrowline(length, m_arrow_x.m_line, 0);
1404 draw_arrowhead(segments, length, m_arrow_head_x.m_vertices.data(), TripleRemapXYZ<Vertex3f>(), TripleRemapXYZ<Normal3f>());
1405 draw_arrowline(length, m_arrow_y.m_line, 1);
1406 draw_arrowhead(segments, length, m_arrow_head_y.m_vertices.data(), TripleRemapYZX<Vertex3f>(), TripleRemapYZX<Normal3f>());
1407 draw_arrowline(length, m_arrow_z.m_line, 2);
1408 draw_arrowhead(segments, length, m_arrow_head_z.m_vertices.data(), TripleRemapZXY<Vertex3f>(), TripleRemapZXY<Normal3f>());
1410 draw_quad(16, m_quad_screen.m_quad);
1413 void UpdateColours()
1415 m_arrow_x.setColour(colourSelected(g_colour_x, m_selectable_x.isSelected()));
1416 m_arrow_head_x.setColour(colourSelected(g_colour_x, m_selectable_x.isSelected()));
1417 m_arrow_y.setColour(colourSelected(g_colour_y, m_selectable_y.isSelected()));
1418 m_arrow_head_y.setColour(colourSelected(g_colour_y, m_selectable_y.isSelected()));
1419 m_arrow_z.setColour(colourSelected(g_colour_z, m_selectable_z.isSelected()));
1420 m_arrow_head_z.setColour(colourSelected(g_colour_z, m_selectable_z.isSelected()));
1421 m_quad_screen.setColour(colourSelected(g_colour_screen, m_selectable_screen.isSelected()));
1424 bool manipulator_show_axis(const Pivot2World& pivot, const Vector3& axis)
1426 return fabs(vector3_dot(pivot.m_axis_screen, axis)) < 0.95;
1429 void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world)
1431 m_pivot.update(pivot2world, volume.GetModelview(), volume.GetProjection(), volume.GetViewport());
1436 Vector3 x = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.x()));
1437 bool show_x = manipulator_show_axis(m_pivot, x);
1439 Vector3 y = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.y()));
1440 bool show_y = manipulator_show_axis(m_pivot, y);
1442 Vector3 z = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.z()));
1443 bool show_z = manipulator_show_axis(m_pivot, z);
1445 renderer.SetState(m_state_wire, Renderer::eWireframeOnly);
1446 renderer.SetState(m_state_wire, Renderer::eFullMaterials);
1450 renderer.addRenderable(m_arrow_x, m_pivot.m_worldSpace);
1454 renderer.addRenderable(m_arrow_y, m_pivot.m_worldSpace);
1458 renderer.addRenderable(m_arrow_z, m_pivot.m_worldSpace);
1461 renderer.addRenderable(m_quad_screen, m_pivot.m_viewplaneSpace);
1463 renderer.SetState(m_state_fill, Renderer::eWireframeOnly);
1464 renderer.SetState(m_state_fill, Renderer::eFullMaterials);
1468 renderer.addRenderable(m_arrow_head_x, m_pivot.m_worldSpace);
1472 renderer.addRenderable(m_arrow_head_y, m_pivot.m_worldSpace);
1476 renderer.addRenderable(m_arrow_head_z, m_pivot.m_worldSpace);
1479 void testSelect(const View& view, const Matrix4& pivot2world)
1481 m_pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport());
1483 SelectionPool selector;
1485 Vector3 x = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.x()));
1486 bool show_x = manipulator_show_axis(m_pivot, x);
1488 Vector3 y = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.y()));
1489 bool show_y = manipulator_show_axis(m_pivot, y);
1491 Vector3 z = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.z()));
1492 bool show_z = manipulator_show_axis(m_pivot, z);
1495 Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_viewpointSpace));
1498 SelectionIntersection best;
1499 Quad_BestPoint(local2view, eClipCullCW, m_quad_screen.m_quad, best);
1502 best = SelectionIntersection(0, 0);
1503 selector.addSelectable(best, &m_selectable_screen);
1509 Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_worldSpace));
1511 #if defined(DEBUG_SELECTION)
1512 g_render_clipped.construct(view.GetViewMatrix());
1517 SelectionIntersection best;
1518 Line_BestPoint(local2view, m_arrow_x.m_line, best);
1519 Triangles_BestPoint(local2view, eClipCullCW, m_arrow_head_x.m_vertices.begin(), m_arrow_head_x.m_vertices.end(), best);
1520 selector.addSelectable(best, &m_selectable_x);
1525 SelectionIntersection best;
1526 Line_BestPoint(local2view, m_arrow_y.m_line, best);
1527 Triangles_BestPoint(local2view, eClipCullCW, m_arrow_head_y.m_vertices.begin(), m_arrow_head_y.m_vertices.end(), best);
1528 selector.addSelectable(best, &m_selectable_y);
1533 SelectionIntersection best;
1534 Line_BestPoint(local2view, m_arrow_z.m_line, best);
1535 Triangles_BestPoint(local2view, eClipCullCW, m_arrow_head_z.m_vertices.begin(), m_arrow_head_z.m_vertices.end(), best);
1536 selector.addSelectable(best, &m_selectable_z);
1540 if(!selector.failed())
1542 (*selector.begin()).second->setSelected(true);
1546 Manipulatable* GetManipulatable()
1548 if(m_selectable_x.isSelected())
1550 m_axis.SetAxis(g_vector3_axis_x);
1553 else if(m_selectable_y.isSelected())
1555 m_axis.SetAxis(g_vector3_axis_y);
1558 else if(m_selectable_z.isSelected())
1560 m_axis.SetAxis(g_vector3_axis_z);
1569 void setSelected(bool select)
1571 m_selectable_x.setSelected(select);
1572 m_selectable_y.setSelected(select);
1573 m_selectable_z.setSelected(select);
1574 m_selectable_screen.setSelected(select);
1576 bool isSelected() const
1578 return m_selectable_x.isSelected()
1579 | m_selectable_y.isSelected()
1580 | m_selectable_z.isSelected()
1581 | m_selectable_screen.isSelected();
1585 Shader* TranslateManipulator::m_state_wire;
1586 Shader* TranslateManipulator::m_state_fill;
1588 class ScaleManipulator : public Manipulator
1590 struct RenderableArrow : public OpenGLRenderable
1592 PointVertex m_line[2];
1594 void render(RenderStateFlags state) const
1596 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_line[0].colour);
1597 glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_line[0].vertex);
1598 glDrawArrays(GL_LINES, 0, 2);
1600 void setColour(const Colour4b& colour)
1602 m_line[0].colour = colour;
1603 m_line[1].colour = colour;
1606 struct RenderableQuad : public OpenGLRenderable
1608 PointVertex m_quad[4];
1609 void render(RenderStateFlags state) const
1611 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_quad[0].colour);
1612 glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_quad[0].vertex);
1613 glDrawArrays(GL_QUADS, 0, 4);
1615 void setColour(const Colour4b& colour)
1617 m_quad[0].colour = colour;
1618 m_quad[1].colour = colour;
1619 m_quad[2].colour = colour;
1620 m_quad[3].colour = colour;
1626 RenderableArrow m_arrow_x;
1627 RenderableArrow m_arrow_y;
1628 RenderableArrow m_arrow_z;
1629 RenderableQuad m_quad_screen;
1630 SelectableBool m_selectable_x;
1631 SelectableBool m_selectable_y;
1632 SelectableBool m_selectable_z;
1633 SelectableBool m_selectable_screen;
1634 Pivot2World m_pivot;
1636 ScaleManipulator(Scalable& scalable, std::size_t segments, float length) :
1640 draw_arrowline(length, m_arrow_x.m_line, 0);
1641 draw_arrowline(length, m_arrow_y.m_line, 1);
1642 draw_arrowline(length, m_arrow_z.m_line, 2);
1644 draw_quad(16, m_quad_screen.m_quad);
1647 Pivot2World& getPivot()
1652 void UpdateColours()
1654 m_arrow_x.setColour(colourSelected(g_colour_x, m_selectable_x.isSelected()));
1655 m_arrow_y.setColour(colourSelected(g_colour_y, m_selectable_y.isSelected()));
1656 m_arrow_z.setColour(colourSelected(g_colour_z, m_selectable_z.isSelected()));
1657 m_quad_screen.setColour(colourSelected(g_colour_screen, m_selectable_screen.isSelected()));
1660 void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world)
1662 m_pivot.update(pivot2world, volume.GetModelview(), volume.GetProjection(), volume.GetViewport());
1667 renderer.addRenderable(m_arrow_x, m_pivot.m_worldSpace);
1668 renderer.addRenderable(m_arrow_y, m_pivot.m_worldSpace);
1669 renderer.addRenderable(m_arrow_z, m_pivot.m_worldSpace);
1671 renderer.addRenderable(m_quad_screen, m_pivot.m_viewpointSpace);
1673 void testSelect(const View& view, const Matrix4& pivot2world)
1675 m_pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport());
1677 SelectionPool selector;
1680 Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_worldSpace));
1682 #if defined(DEBUG_SELECTION)
1683 g_render_clipped.construct(view.GetViewMatrix());
1687 SelectionIntersection best;
1688 Line_BestPoint(local2view, m_arrow_x.m_line, best);
1689 selector.addSelectable(best, &m_selectable_x);
1693 SelectionIntersection best;
1694 Line_BestPoint(local2view, m_arrow_y.m_line, best);
1695 selector.addSelectable(best, &m_selectable_y);
1699 SelectionIntersection best;
1700 Line_BestPoint(local2view, m_arrow_z.m_line, best);
1701 selector.addSelectable(best, &m_selectable_z);
1706 Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_viewpointSpace));
1709 SelectionIntersection best;
1710 Quad_BestPoint(local2view, eClipCullCW, m_quad_screen.m_quad, best);
1711 selector.addSelectable(best, &m_selectable_screen);
1715 if(!selector.failed())
1717 (*selector.begin()).second->setSelected(true);
1721 Manipulatable* GetManipulatable()
1723 if(m_selectable_x.isSelected())
1725 m_axis.SetAxis(g_vector3_axis_x);
1728 else if(m_selectable_y.isSelected())
1730 m_axis.SetAxis(g_vector3_axis_y);
1733 else if(m_selectable_z.isSelected())
1735 m_axis.SetAxis(g_vector3_axis_z);
1742 void setSelected(bool select)
1744 m_selectable_x.setSelected(select);
1745 m_selectable_y.setSelected(select);
1746 m_selectable_z.setSelected(select);
1747 m_selectable_screen.setSelected(select);
1749 bool isSelected() const
1751 return m_selectable_x.isSelected()
1752 | m_selectable_y.isSelected()
1753 | m_selectable_z.isSelected()
1754 | m_selectable_screen.isSelected();
1759 inline PlaneSelectable* Instance_getPlaneSelectable(scene::Instance& instance)
1761 return InstanceTypeCast<PlaneSelectable>::cast(instance);
1764 class PlaneSelectableSelectPlanes : public scene::Graph::Walker
1766 Selector& m_selector;
1767 SelectionTest& m_test;
1768 PlaneCallback m_selectedPlaneCallback;
1770 PlaneSelectableSelectPlanes(Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
1771 : m_selector(selector), m_test(test), m_selectedPlaneCallback(selectedPlaneCallback)
1774 bool pre(const scene::Path& path, scene::Instance& instance) const
1776 if(path.top().get().visible())
1778 Selectable* selectable = Instance_getSelectable(instance);
1779 if(selectable != 0 && selectable->isSelected())
1781 PlaneSelectable* planeSelectable = Instance_getPlaneSelectable(instance);
1782 if(planeSelectable != 0)
1784 planeSelectable->selectPlanes(m_selector, m_test, m_selectedPlaneCallback);
1792 class PlaneSelectableSelectReversedPlanes : public scene::Graph::Walker
1794 Selector& m_selector;
1795 const SelectedPlanes& m_selectedPlanes;
1797 PlaneSelectableSelectReversedPlanes(Selector& selector, const SelectedPlanes& selectedPlanes)
1798 : m_selector(selector), m_selectedPlanes(selectedPlanes)
1801 bool pre(const scene::Path& path, scene::Instance& instance) const
1803 if(path.top().get().visible())
1805 Selectable* selectable = Instance_getSelectable(instance);
1806 if(selectable != 0 && selectable->isSelected())
1808 PlaneSelectable* planeSelectable = Instance_getPlaneSelectable(instance);
1809 if(planeSelectable != 0)
1811 planeSelectable->selectReversedPlanes(m_selector, m_selectedPlanes);
1819 void Scene_forEachPlaneSelectable_selectPlanes(scene::Graph& graph, Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
1821 graph.traverse(PlaneSelectableSelectPlanes(selector, test, selectedPlaneCallback));
1824 void Scene_forEachPlaneSelectable_selectReversedPlanes(scene::Graph& graph, Selector& selector, const SelectedPlanes& selectedPlanes)
1826 graph.traverse(PlaneSelectableSelectReversedPlanes(selector, selectedPlanes));
1833 bool operator()(const Plane3& plane, const Plane3& other) const
1835 if(plane.a < other.a)
1839 if(other.a < plane.a)
1844 if(plane.b < other.b)
1848 if(other.b < plane.b)
1853 if(plane.c < other.c)
1857 if(other.c < plane.c)
1862 if(plane.d < other.d)
1866 if(other.d < plane.d)
1875 typedef std::set<Plane3, PlaneLess> PlaneSet;
1877 inline void PlaneSet_insert(PlaneSet& self, const Plane3& plane)
1882 inline bool PlaneSet_contains(const PlaneSet& self, const Plane3& plane)
1884 return self.find(plane) != self.end();
1888 class SelectedPlaneSet : public SelectedPlanes
1890 PlaneSet m_selectedPlanes;
1894 return m_selectedPlanes.empty();
1897 void insert(const Plane3& plane)
1899 PlaneSet_insert(m_selectedPlanes, plane);
1901 bool contains(const Plane3& plane) const
1903 return PlaneSet_contains(m_selectedPlanes, plane);
1905 typedef MemberCaller1<SelectedPlaneSet, const Plane3&, &SelectedPlaneSet::insert> InsertCaller;
1909 bool Scene_forEachPlaneSelectable_selectPlanes(scene::Graph& graph, Selector& selector, SelectionTest& test)
1911 SelectedPlaneSet selectedPlanes;
1913 Scene_forEachPlaneSelectable_selectPlanes(graph, selector, test, SelectedPlaneSet::InsertCaller(selectedPlanes));
1914 Scene_forEachPlaneSelectable_selectReversedPlanes(graph, selector, selectedPlanes);
1916 return !selectedPlanes.empty();
1919 void Scene_Translate_Component_Selected(scene::Graph& graph, const Vector3& translation);
1920 void Scene_Translate_Selected(scene::Graph& graph, const Vector3& translation);
1921 void Scene_TestSelect_Primitive(Selector& selector, SelectionTest& test, const VolumeTest& volume);
1922 void Scene_TestSelect_Component(Selector& selector, SelectionTest& test, const VolumeTest& volume, SelectionSystem::EComponentMode componentMode);
1923 void Scene_TestSelect_Component_Selected(Selector& selector, SelectionTest& test, const VolumeTest& volume, SelectionSystem::EComponentMode componentMode);
1924 void Scene_SelectAll_Component(bool select, SelectionSystem::EComponentMode componentMode);
1926 class ResizeTranslatable : public Translatable
1928 void translate(const Vector3& translation)
1930 Scene_Translate_Component_Selected(GlobalSceneGraph(), translation);
1934 class DragTranslatable : public Translatable
1936 void translate(const Vector3& translation)
1938 if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent)
1940 Scene_Translate_Component_Selected(GlobalSceneGraph(), translation);
1944 Scene_Translate_Selected(GlobalSceneGraph(), translation);
1949 class SelectionVolume : public SelectionTest
1951 Matrix4 m_local2view;
1957 SelectionVolume(const View& view)
1962 const VolumeTest& getVolume() const
1967 const Vector3& getNear() const
1971 const Vector3& getFar() const
1976 void BeginMesh(const Matrix4& localToWorld, bool twoSided)
1978 m_local2view = matrix4_multiplied_by_matrix4(m_view.GetViewMatrix(), localToWorld);
1980 // Cull back-facing polygons based on winding being clockwise or counter-clockwise.
1981 // Don't cull if the view is wireframe and the polygons are two-sided.
1982 m_cull = twoSided && !m_view.fill() ? eClipCullNone : (matrix4_handedness(localToWorld) == MATRIX4_RIGHTHANDED) ? eClipCullCW : eClipCullCCW;
1985 Matrix4 screen2world(matrix4_full_inverse(m_local2view));
1987 m_near = vector4_projected(
1988 matrix4_transformed_vector4(
1990 Vector4(0, 0, -1, 1)
1994 m_far = vector4_projected(
1995 matrix4_transformed_vector4(
2002 #if defined(DEBUG_SELECTION)
2003 g_render_clipped.construct(m_view.GetViewMatrix());
2006 void TestPoint(const Vector3& point, SelectionIntersection& best)
2009 if(matrix4_clip_point(m_local2view, point, clipped) == c_CLIP_PASS)
2011 best = select_point_from_clipped(clipped);
2014 void TestPolygon(const VertexPointer& vertices, std::size_t count, SelectionIntersection& best)
2017 for(std::size_t i=0; i+2<count; ++i)
2020 matrix4_clip_triangle(
2022 reinterpret_cast<const Vector3&>(vertices[0]),
2023 reinterpret_cast<const Vector3&>(vertices[i+1]),
2024 reinterpret_cast<const Vector3&>(vertices[i+2]),
2033 void TestLineLoop(const VertexPointer& vertices, std::size_t count, SelectionIntersection& best)
2038 for(VertexPointer::iterator i = vertices.begin(), end = i + count, prev = i + (count-1); i != end; prev = i, ++i)
2043 reinterpret_cast<const Vector3&>((*prev)),
2044 reinterpret_cast<const Vector3&>((*i)),
2053 void TestLineStrip(const VertexPointer& vertices, std::size_t count, SelectionIntersection& best)
2058 for(VertexPointer::iterator i = vertices.begin(), end = i + count, next = i + 1; next != end; i = next, ++next)
2063 reinterpret_cast<const Vector3&>((*i)),
2064 reinterpret_cast<const Vector3&>((*next)),
2073 void TestLines(const VertexPointer& vertices, std::size_t count, SelectionIntersection& best)
2078 for(VertexPointer::iterator i = vertices.begin(), end = i + count; i != end; i += 2)
2083 reinterpret_cast<const Vector3&>((*i)),
2084 reinterpret_cast<const Vector3&>((*(i+1))),
2093 void TestTriangles(const VertexPointer& vertices, const IndexPointer& indices, SelectionIntersection& best)
2096 for(IndexPointer::iterator i(indices.begin()); i != indices.end(); i += 3)
2099 matrix4_clip_triangle(
2101 reinterpret_cast<const Vector3&>(vertices[*i]),
2102 reinterpret_cast<const Vector3&>(vertices[*(i+1)]),
2103 reinterpret_cast<const Vector3&>(vertices[*(i+2)]),
2112 void TestQuads(const VertexPointer& vertices, const IndexPointer& indices, SelectionIntersection& best)
2115 for(IndexPointer::iterator i(indices.begin()); i != indices.end(); i += 4)
2118 matrix4_clip_triangle(
2120 reinterpret_cast<const Vector3&>(vertices[*i]),
2121 reinterpret_cast<const Vector3&>(vertices[*(i+1)]),
2122 reinterpret_cast<const Vector3&>(vertices[*(i+3)]),
2130 matrix4_clip_triangle(
2132 reinterpret_cast<const Vector3&>(vertices[*(i+1)]),
2133 reinterpret_cast<const Vector3&>(vertices[*(i+2)]),
2134 reinterpret_cast<const Vector3&>(vertices[*(i+3)]),
2143 void TestQuadStrip(const VertexPointer& vertices, const IndexPointer& indices, SelectionIntersection& best)
2146 for(IndexPointer::iterator i(indices.begin()); i+2 != indices.end(); i += 2)
2149 matrix4_clip_triangle(
2151 reinterpret_cast<const Vector3&>(vertices[*i]),
2152 reinterpret_cast<const Vector3&>(vertices[*(i+1)]),
2153 reinterpret_cast<const Vector3&>(vertices[*(i+2)]),
2161 matrix4_clip_triangle(
2163 reinterpret_cast<const Vector3&>(vertices[*(i+2)]),
2164 reinterpret_cast<const Vector3&>(vertices[*(i+1)]),
2165 reinterpret_cast<const Vector3&>(vertices[*(i+3)]),
2176 class SelectionCounter
2179 typedef const Selectable& first_argument_type;
2181 SelectionCounter(const SelectionChangeCallback& onchanged)
2182 : m_count(0), m_onchanged(onchanged)
2185 void operator()(const Selectable& selectable)
2187 if(selectable.isSelected())
2193 ASSERT_MESSAGE(m_count != 0, "selection counter underflow");
2197 m_onchanged(selectable);
2201 return m_count == 0;
2203 std::size_t size() const
2208 std::size_t m_count;
2209 SelectionChangeCallback m_onchanged;
2212 inline void ConstructSelectionTest(View& view, const rect_t selection_box)
2214 view.EnableScissor(selection_box.min[0], selection_box.max[0], selection_box.min[1], selection_box.max[1]);
2217 inline const rect_t SelectionBoxForPoint(const float device_point[2], const float device_epsilon[2])
2219 rect_t selection_box;
2220 selection_box.min[0] = device_point[0] - device_epsilon[0];
2221 selection_box.min[1] = device_point[1] - device_epsilon[1];
2222 selection_box.max[0] = device_point[0] + device_epsilon[0];
2223 selection_box.max[1] = device_point[1] + device_epsilon[1];
2224 return selection_box;
2227 inline const rect_t SelectionBoxForArea(const float device_point[2], const float device_delta[2])
2229 rect_t selection_box;
2230 selection_box.min[0] = (device_delta[0] < 0) ? (device_point[0] + device_delta[0]) : (device_point[0]);
2231 selection_box.min[1] = (device_delta[1] < 0) ? (device_point[1] + device_delta[1]) : (device_point[1]);
2232 selection_box.max[0] = (device_delta[0] > 0) ? (device_point[0] + device_delta[0]) : (device_point[0]);
2233 selection_box.max[1] = (device_delta[1] > 0) ? (device_point[1] + device_delta[1]) : (device_point[1]);
2234 return selection_box;
2237 Quaternion construct_local_rotation(const Quaternion& world, const Quaternion& localToWorld)
2239 return quaternion_normalised(quaternion_multiplied_by_quaternion(
2240 quaternion_normalised(quaternion_multiplied_by_quaternion(
2241 quaternion_inverse(localToWorld),
2248 inline void matrix4_assign_rotation(Matrix4& matrix, const Matrix4& other)
2250 matrix[0] = other[0];
2251 matrix[1] = other[1];
2252 matrix[2] = other[2];
2253 matrix[4] = other[4];
2254 matrix[5] = other[5];
2255 matrix[6] = other[6];
2256 matrix[8] = other[8];
2257 matrix[9] = other[9];
2258 matrix[10] = other[10];
2261 void matrix4_assign_rotation_for_pivot(Matrix4& matrix, scene::Instance& instance)
2263 Editable* editable = Node_getEditable(instance.path().top());
2266 matrix4_assign_rotation(matrix, matrix4_multiplied_by_matrix4(instance.localToWorld(), editable->getLocalPivot()));
2270 matrix4_assign_rotation(matrix, instance.localToWorld());
2274 inline bool Instance_isSelectedComponents(scene::Instance& instance)
2276 ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
2277 return componentSelectionTestable != 0
2278 && componentSelectionTestable->isSelectedComponents();
2281 class TranslateSelected : public SelectionSystem::Visitor
2283 const Vector3& m_translate;
2285 TranslateSelected(const Vector3& translate)
2286 : m_translate(translate)
2289 void visit(scene::Instance& instance) const
2291 Transformable* transform = Instance_getTransformable(instance);
2294 transform->setType(TRANSFORM_PRIMITIVE);
2295 transform->setTranslation(m_translate);
2300 void Scene_Translate_Selected(scene::Graph& graph, const Vector3& translation)
2302 if(GlobalSelectionSystem().countSelected() != 0)
2304 GlobalSelectionSystem().foreachSelected(TranslateSelected(translation));
2308 Vector3 get_local_pivot(const Vector3& world_pivot, const Matrix4& localToWorld)
2311 matrix4_transformed_point(
2312 matrix4_full_inverse(localToWorld),
2318 void translation_for_pivoted_matrix_transform(Vector3& parent_translation, const Matrix4& local_transform, const Vector3& world_pivot, const Matrix4& localToWorld, const Matrix4& localToParent)
2320 // we need a translation inside the parent system to move the origin of this object to the right place
2322 // mathematically, it must fulfill:
2324 // local_translation local_transform local_pivot = local_pivot
2325 // local_translation = local_pivot - local_transform local_pivot
2328 // local_transform local_translation local_pivot = local_pivot
2329 // local_translation local_pivot = local_transform^-1 local_pivot
2330 // local_translation + local_pivot = local_transform^-1 local_pivot
2331 // local_translation = local_transform^-1 local_pivot - local_pivot
2333 Vector3 local_pivot(get_local_pivot(world_pivot, localToWorld));
2335 Vector3 local_translation(
2338 matrix4_transformed_point(
2343 matrix4_transformed_point(
2344 matrix4_full_inverse(local_transform),
2352 translation_local2object(parent_translation, local_translation, localToParent);
2356 globalOutputStream() << "World pivot is at " << world_pivot << "\n";
2357 globalOutputStream() << "Local pivot is at " << local_pivot << "\n";
2358 globalOutputStream() << "Transformation " << local_transform << " moves it to: " << matrix4_transformed_point(local_transform, local_pivot) << "\n";
2359 globalOutputStream() << "Must move by " << local_translation << " in the local system" << "\n";
2360 globalOutputStream() << "Must move by " << parent_translation << " in the parent system" << "\n";
2364 void translation_for_pivoted_rotation(Vector3& parent_translation, const Quaternion& local_rotation, const Vector3& world_pivot, const Matrix4& localToWorld, const Matrix4& localToParent)
2366 translation_for_pivoted_matrix_transform(parent_translation, matrix4_rotation_for_quaternion_quantised(local_rotation), world_pivot, localToWorld, localToParent);
2369 void translation_for_pivoted_scale(Vector3& parent_translation, const Vector3& world_scale, const Vector3& world_pivot, const Matrix4& localToWorld, const Matrix4& localToParent)
2371 Matrix4 local_transform(
2372 matrix4_multiplied_by_matrix4(
2373 matrix4_full_inverse(localToWorld),
2374 matrix4_multiplied_by_matrix4(
2375 matrix4_scale_for_vec3(world_scale),
2380 local_transform.tx() = local_transform.ty() = local_transform.tz() = 0; // cancel translation parts
2381 translation_for_pivoted_matrix_transform(parent_translation, local_transform, world_pivot, localToWorld, localToParent);
2384 class rotate_selected : public SelectionSystem::Visitor
2386 const Quaternion& m_rotate;
2387 const Vector3& m_world_pivot;
2389 rotate_selected(const Quaternion& rotation, const Vector3& world_pivot)
2390 : m_rotate(rotation), m_world_pivot(world_pivot)
2393 void visit(scene::Instance& instance) const
2395 TransformNode* transformNode = Node_getTransformNode(instance.path().top());
2396 if(transformNode != 0)
2398 Transformable* transform = Instance_getTransformable(instance);
2401 transform->setType(TRANSFORM_PRIMITIVE);
2402 transform->setScale(c_scale_identity);
2403 transform->setTranslation(c_translation_identity);
2405 transform->setType(TRANSFORM_PRIMITIVE);
2406 transform->setRotation(m_rotate);
2409 Editable* editable = Node_getEditable(instance.path().top());
2410 const Matrix4& localPivot = editable != 0 ? editable->getLocalPivot() : g_matrix4_identity;
2412 Vector3 parent_translation;
2413 translation_for_pivoted_rotation(
2417 matrix4_multiplied_by_matrix4(instance.localToWorld(), localPivot),
2418 matrix4_multiplied_by_matrix4(transformNode->localToParent(), localPivot)
2421 transform->setTranslation(parent_translation);
2428 void Scene_Rotate_Selected(scene::Graph& graph, const Quaternion& rotation, const Vector3& world_pivot)
2430 if(GlobalSelectionSystem().countSelected() != 0)
2432 GlobalSelectionSystem().foreachSelected(rotate_selected(rotation, world_pivot));
2436 class scale_selected : public SelectionSystem::Visitor
2438 const Vector3& m_scale;
2439 const Vector3& m_world_pivot;
2441 scale_selected(const Vector3& scaling, const Vector3& world_pivot)
2442 : m_scale(scaling), m_world_pivot(world_pivot)
2445 void visit(scene::Instance& instance) const
2447 TransformNode* transformNode = Node_getTransformNode(instance.path().top());
2448 if(transformNode != 0)
2450 Transformable* transform = Instance_getTransformable(instance);
2453 transform->setType(TRANSFORM_PRIMITIVE);
2454 transform->setScale(c_scale_identity);
2455 transform->setTranslation(c_translation_identity);
2457 transform->setType(TRANSFORM_PRIMITIVE);
2458 transform->setScale(m_scale);
2460 Editable* editable = Node_getEditable(instance.path().top());
2461 const Matrix4& localPivot = editable != 0 ? editable->getLocalPivot() : g_matrix4_identity;
2463 Vector3 parent_translation;
2464 translation_for_pivoted_scale(
2468 matrix4_multiplied_by_matrix4(instance.localToWorld(), localPivot),
2469 matrix4_multiplied_by_matrix4(transformNode->localToParent(), localPivot)
2472 transform->setTranslation(parent_translation);
2479 void Scene_Scale_Selected(scene::Graph& graph, const Vector3& scaling, const Vector3& world_pivot)
2481 if(GlobalSelectionSystem().countSelected() != 0)
2483 GlobalSelectionSystem().foreachSelected(scale_selected(scaling, world_pivot));
2488 class translate_component_selected : public SelectionSystem::Visitor
2490 const Vector3& m_translate;
2492 translate_component_selected(const Vector3& translate)
2493 : m_translate(translate)
2496 void visit(scene::Instance& instance) const
2498 Transformable* transform = Instance_getTransformable(instance);
2501 transform->setType(TRANSFORM_COMPONENT);
2502 transform->setTranslation(m_translate);
2507 void Scene_Translate_Component_Selected(scene::Graph& graph, const Vector3& translation)
2509 if(GlobalSelectionSystem().countSelected() != 0)
2511 GlobalSelectionSystem().foreachSelectedComponent(translate_component_selected(translation));
2515 class rotate_component_selected : public SelectionSystem::Visitor
2517 const Quaternion& m_rotate;
2518 const Vector3& m_world_pivot;
2520 rotate_component_selected(const Quaternion& rotation, const Vector3& world_pivot)
2521 : m_rotate(rotation), m_world_pivot(world_pivot)
2524 void visit(scene::Instance& instance) const
2526 Transformable* transform = Instance_getTransformable(instance);
2529 Vector3 parent_translation;
2530 translation_for_pivoted_rotation(parent_translation, m_rotate, m_world_pivot, instance.localToWorld(), Node_getTransformNode(instance.path().top())->localToParent());
2532 transform->setType(TRANSFORM_COMPONENT);
2533 transform->setRotation(m_rotate);
2534 transform->setTranslation(parent_translation);
2539 void Scene_Rotate_Component_Selected(scene::Graph& graph, const Quaternion& rotation, const Vector3& world_pivot)
2541 if(GlobalSelectionSystem().countSelectedComponents() != 0)
2543 GlobalSelectionSystem().foreachSelectedComponent(rotate_component_selected(rotation, world_pivot));
2547 class scale_component_selected : public SelectionSystem::Visitor
2549 const Vector3& m_scale;
2550 const Vector3& m_world_pivot;
2552 scale_component_selected(const Vector3& scaling, const Vector3& world_pivot)
2553 : m_scale(scaling), m_world_pivot(world_pivot)
2556 void visit(scene::Instance& instance) const
2558 Transformable* transform = Instance_getTransformable(instance);
2561 Vector3 parent_translation;
2562 translation_for_pivoted_scale(parent_translation, m_scale, m_world_pivot, instance.localToWorld(), Node_getTransformNode(instance.path().top())->localToParent());
2564 transform->setType(TRANSFORM_COMPONENT);
2565 transform->setScale(m_scale);
2566 transform->setTranslation(parent_translation);
2571 void Scene_Scale_Component_Selected(scene::Graph& graph, const Vector3& scaling, const Vector3& world_pivot)
2573 if(GlobalSelectionSystem().countSelectedComponents() != 0)
2575 GlobalSelectionSystem().foreachSelectedComponent(scale_component_selected(scaling, world_pivot));
2580 class BooleanSelector : public Selector
2583 SelectionIntersection m_intersection;
2584 Selectable* m_selectable;
2586 BooleanSelector() : m_selected(false)
2590 void pushSelectable(Selectable& selectable)
2592 m_intersection = SelectionIntersection();
2593 m_selectable = &selectable;
2595 void popSelectable()
2597 if(m_intersection.valid())
2601 m_intersection = SelectionIntersection();
2603 void addIntersection(const SelectionIntersection& intersection)
2605 if(m_selectable->isSelected())
2607 assign_if_closer(m_intersection, intersection);
2617 class BestSelector : public Selector
2619 SelectionIntersection m_intersection;
2620 Selectable* m_selectable;
2621 SelectionIntersection m_bestIntersection;
2622 std::list<Selectable*> m_bestSelectable;
2624 BestSelector() : m_bestIntersection(SelectionIntersection()), m_bestSelectable(0)
2628 void pushSelectable(Selectable& selectable)
2630 m_intersection = SelectionIntersection();
2631 m_selectable = &selectable;
2633 void popSelectable()
2635 if(m_intersection.equalEpsilon(m_bestIntersection, 0.25f, 0.001f))
2637 m_bestSelectable.push_back(m_selectable);
2638 m_bestIntersection = m_intersection;
2640 else if(m_intersection < m_bestIntersection)
2642 m_bestSelectable.clear();
2643 m_bestSelectable.push_back(m_selectable);
2644 m_bestIntersection = m_intersection;
2646 m_intersection = SelectionIntersection();
2648 void addIntersection(const SelectionIntersection& intersection)
2650 assign_if_closer(m_intersection, intersection);
2653 std::list<Selectable*>& best()
2655 return m_bestSelectable;
2659 class DragManipulator : public Manipulator
2661 TranslateFree m_freeResize;
2662 TranslateFree m_freeDrag;
2663 ResizeTranslatable m_resize;
2664 DragTranslatable m_drag;
2665 SelectableBool m_dragSelectable;
2670 DragManipulator() : m_freeResize(m_resize), m_freeDrag(m_drag), m_selected(false)
2674 Manipulatable* GetManipulatable()
2676 return m_dragSelectable.isSelected() ? &m_freeDrag : &m_freeResize;
2679 void testSelect(const View& view, const Matrix4& pivot2world)
2681 SelectionPool selector;
2683 SelectionVolume test(view);
2685 if(GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
2687 BooleanSelector booleanSelector;
2689 Scene_TestSelect_Primitive(booleanSelector, test, view);
2691 if(booleanSelector.isSelected())
2693 selector.addSelectable(SelectionIntersection(0, 0), &m_dragSelectable);
2698 m_selected = Scene_forEachPlaneSelectable_selectPlanes(GlobalSceneGraph(), selector, test);
2703 BestSelector bestSelector;
2704 Scene_TestSelect_Component_Selected(bestSelector, test, view, GlobalSelectionSystem().ComponentMode());
2705 for(std::list<Selectable*>::iterator i = bestSelector.best().begin(); i != bestSelector.best().end(); ++i)
2707 if(!(*i)->isSelected())
2709 GlobalSelectionSystem().setSelectedAllComponents(false);
2712 selector.addSelectable(SelectionIntersection(0, 0), (*i));
2713 m_dragSelectable.setSelected(true);
2717 for(SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i)
2719 (*i).second->setSelected(true);
2723 void setSelected(bool select)
2725 m_selected = select;
2726 m_dragSelectable.setSelected(select);
2728 bool isSelected() const
2730 return m_selected || m_dragSelectable.isSelected();
2734 class ClipManipulator : public Manipulator
2738 Manipulatable* GetManipulatable()
2740 ERROR_MESSAGE("clipper is not manipulatable");
2744 void setSelected(bool select)
2747 bool isSelected() const
2753 class select_all : public scene::Graph::Walker
2757 select_all(bool select)
2761 bool pre(const scene::Path& path, scene::Instance& instance) const
2763 Selectable* selectable = Instance_getSelectable(instance);
2766 selectable->setSelected(m_select);
2772 class select_all_component : public scene::Graph::Walker
2775 SelectionSystem::EComponentMode m_mode;
2777 select_all_component(bool select, SelectionSystem::EComponentMode mode)
2778 : m_select(select), m_mode(mode)
2781 bool pre(const scene::Path& path, scene::Instance& instance) const
2783 ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
2784 if(componentSelectionTestable)
2786 componentSelectionTestable->setSelectedComponents(m_select, m_mode);
2792 void Scene_SelectAll_Component(bool select, SelectionSystem::EComponentMode componentMode)
2794 GlobalSceneGraph().traverse(select_all_component(select, componentMode));
2798 // RadiantSelectionSystem
2799 class RadiantSelectionSystem :
2800 public SelectionSystem,
2801 public Translatable,
2806 mutable Matrix4 m_pivot2world;
2807 Matrix4 m_pivot2world_start;
2808 Matrix4 m_manip2pivot_start;
2809 Translation m_translation;
2810 Rotation m_rotation;
2813 static Shader* m_state;
2815 EManipulatorMode m_manipulator_mode;
2816 Manipulator* m_manipulator;
2821 EComponentMode m_componentmode;
2823 SelectionCounter m_count_primitive;
2824 SelectionCounter m_count_component;
2826 TranslateManipulator m_translate_manipulator;
2827 RotateManipulator m_rotate_manipulator;
2828 ScaleManipulator m_scale_manipulator;
2829 DragManipulator m_drag_manipulator;
2830 ClipManipulator m_clip_manipulator;
2832 typedef SelectionList<scene::Instance> selection_t;
2833 selection_t m_selection;
2834 selection_t m_component_selection;
2836 Signal1<const Selectable&> m_selectionChanged_callbacks;
2838 void ConstructPivot() const;
2839 mutable bool m_pivotChanged;
2840 bool m_pivot_moving;
2842 void Scene_TestSelect(Selector& selector, SelectionTest& test, const View& view, SelectionSystem::EMode mode, SelectionSystem::EComponentMode componentMode);
2844 bool nothingSelected() const
2846 return (Mode() == eComponent && m_count_component.empty())
2847 || (Mode() == ePrimitive && m_count_primitive.empty());
2860 RadiantSelectionSystem() :
2861 m_undo_begun(false),
2863 m_componentmode(eDefault),
2864 m_count_primitive(SelectionChangedCaller(*this)),
2865 m_count_component(SelectionChangedCaller(*this)),
2866 m_translate_manipulator(*this, 2, 64),
2867 m_rotate_manipulator(*this, 8, 64),
2868 m_scale_manipulator(*this, 0, 64),
2869 m_pivotChanged(false),
2870 m_pivot_moving(false)
2872 SetManipulatorMode(eTranslate);
2874 addSelectionChangeCallback(PivotChangedSelectionCaller(*this));
2875 AddGridChangeCallback(PivotChangedCaller(*this));
2877 void pivotChanged() const
2879 m_pivotChanged = true;
2880 SceneChangeNotify();
2882 typedef ConstMemberCaller<RadiantSelectionSystem, &RadiantSelectionSystem::pivotChanged> PivotChangedCaller;
2883 void pivotChangedSelection(const Selectable& selectable)
2887 typedef MemberCaller1<RadiantSelectionSystem, const Selectable&, &RadiantSelectionSystem::pivotChangedSelection> PivotChangedSelectionCaller;
2889 void SetMode(EMode mode)
2901 void SetComponentMode(EComponentMode mode)
2903 m_componentmode = mode;
2905 EComponentMode ComponentMode() const
2907 return m_componentmode;
2909 void SetManipulatorMode(EManipulatorMode mode)
2911 m_manipulator_mode = mode;
2912 switch(m_manipulator_mode)
2914 case eTranslate: m_manipulator = &m_translate_manipulator; break;
2915 case eRotate: m_manipulator = &m_rotate_manipulator; break;
2916 case eScale: m_manipulator = &m_scale_manipulator; break;
2917 case eDrag: m_manipulator = &m_drag_manipulator; break;
2918 case eClip: m_manipulator = &m_clip_manipulator; break;
2922 EManipulatorMode ManipulatorMode() const
2924 return m_manipulator_mode;
2927 SelectionChangeCallback getObserver(EMode mode)
2929 if(mode == ePrimitive)
2931 return makeCallback1(m_count_primitive);
2935 return makeCallback1(m_count_component);
2938 std::size_t countSelected() const
2940 return m_count_primitive.size();
2942 std::size_t countSelectedComponents() const
2944 return m_count_component.size();
2946 void onSelectedChanged(scene::Instance& instance, const Selectable& selectable)
2948 if(selectable.isSelected())
2950 m_selection.append(instance);
2954 m_selection.erase(instance);
2957 ASSERT_MESSAGE(m_selection.size() == m_count_primitive.size(), "selection-tracking error");
2959 void onComponentSelection(scene::Instance& instance, const Selectable& selectable)
2961 if(selectable.isSelected())
2963 m_component_selection.append(instance);
2967 m_component_selection.erase(instance);
2970 ASSERT_MESSAGE(m_component_selection.size() == m_count_component.size(), "selection-tracking error");
2972 scene::Instance& ultimateSelected() const
2974 ASSERT_MESSAGE(m_selection.size() > 0, "no instance selected");
2975 return m_selection.back();
2977 scene::Instance& penultimateSelected() const
2979 ASSERT_MESSAGE(m_selection.size() > 1, "only one instance selected");
2980 return *(*(--(--m_selection.end())));
2982 void setSelectedAll(bool selected)
2984 GlobalSceneGraph().traverse(select_all(selected));
2986 m_manipulator->setSelected(selected);
2988 void setSelectedAllComponents(bool selected)
2990 Scene_SelectAll_Component(selected, SelectionSystem::eVertex);
2991 Scene_SelectAll_Component(selected, SelectionSystem::eEdge);
2992 Scene_SelectAll_Component(selected, SelectionSystem::eFace);
2994 m_manipulator->setSelected(selected);
2997 void foreachSelected(const Visitor& visitor) const
2999 selection_t::const_iterator i = m_selection.begin();
3000 while(i != m_selection.end())
3002 visitor.visit(*(*(i++)));
3005 void foreachSelectedComponent(const Visitor& visitor) const
3007 selection_t::const_iterator i = m_component_selection.begin();
3008 while(i != m_component_selection.end())
3010 visitor.visit(*(*(i++)));
3014 void addSelectionChangeCallback(const SelectionChangeHandler& handler)
3016 m_selectionChanged_callbacks.connectLast(handler);
3018 void selectionChanged(const Selectable& selectable)
3020 m_selectionChanged_callbacks(selectable);
3022 typedef MemberCaller1<RadiantSelectionSystem, const Selectable&, &RadiantSelectionSystem::selectionChanged> SelectionChangedCaller;
3027 m_pivot2world_start = GetPivot2World();
3030 bool SelectManipulator(const View& view, const float device_point[2], const float device_epsilon[2])
3032 if(!nothingSelected() || (ManipulatorMode() == eDrag && Mode() == eComponent))
3034 #if defined (DEBUG_SELECTION)
3035 g_render_clipped.destroy();
3038 m_manipulator->setSelected(false);
3040 if(!nothingSelected() || (ManipulatorMode() == eDrag && Mode() == eComponent))
3042 View scissored(view);
3043 ConstructSelectionTest(scissored, SelectionBoxForPoint(device_point, device_epsilon));
3044 m_manipulator->testSelect(scissored, GetPivot2World());
3049 m_pivot_moving = m_manipulator->isSelected();
3054 pivot.update(GetPivot2World(), view.GetModelview(), view.GetProjection(), view.GetViewport());
3056 m_manip2pivot_start = matrix4_multiplied_by_matrix4(matrix4_full_inverse(m_pivot2world_start), pivot.m_worldSpace);
3058 Matrix4 device2manip;
3059 ConstructDevice2Manip(device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport());
3060 m_manipulator->GetManipulatable()->Construct(device2manip, device_point[0], device_point[1]);
3062 m_undo_begun = false;
3065 SceneChangeNotify();
3068 return m_pivot_moving;
3073 if(Mode() == eComponent)
3075 setSelectedAllComponents(false);
3079 setSelectedAll(false);
3083 void SelectPoint(const View& view, const float device_point[2], const float device_epsilon[2], RadiantSelectionSystem::EModifier modifier, bool face)
3085 ASSERT_MESSAGE(fabs(device_point[0]) <= 1.0f && fabs(device_point[1]) <= 1.0f, "point-selection error");
3086 if(modifier == eReplace)
3090 setSelectedAllComponents(false);
3098 #if defined (DEBUG_SELECTION)
3099 g_render_clipped.destroy();
3103 View scissored(view);
3104 ConstructSelectionTest(scissored, SelectionBoxForPoint(device_point, device_epsilon));
3106 SelectionVolume volume(scissored);
3107 SelectionPool selector;
3110 Scene_TestSelect_Component(selector, volume, scissored, eFace);
3114 Scene_TestSelect(selector, volume, scissored, Mode(), ComponentMode());
3117 if(!selector.failed())
3121 case RadiantSelectionSystem::eToggle:
3123 SelectableSortedSet::iterator best = selector.begin();
3124 // toggle selection of the object with least depth
3125 if((*best).second->isSelected())
3126 (*best).second->setSelected(false);
3128 (*best).second->setSelected(true);
3131 // if cycle mode not enabled, enable it
3132 case RadiantSelectionSystem::eReplace:
3135 (*selector.begin()).second->setSelected(true);
3138 // select the next object in the list from the one already selected
3139 case RadiantSelectionSystem::eCycle:
3141 SelectionPool::iterator i = selector.begin();
3142 while(i != selector.end())
3144 if((*i).second->isSelected())
3146 (*i).second->setSelected(false);
3148 if(i != selector.end())
3150 i->second->setSelected(true);
3154 selector.begin()->second->setSelected(true);
3169 void SelectArea(const View& view, const float device_point[2], const float device_delta[2], RadiantSelectionSystem::EModifier modifier, bool face)
3171 if(modifier == eReplace)
3175 setSelectedAllComponents(false);
3183 #if defined (DEBUG_SELECTION)
3184 g_render_clipped.destroy();
3188 View scissored(view);
3189 ConstructSelectionTest(scissored, SelectionBoxForArea(device_point, device_delta));
3191 SelectionVolume volume(scissored);
3195 Scene_TestSelect_Component(pool, volume, scissored, eFace);
3199 Scene_TestSelect(pool, volume, scissored, Mode(), ComponentMode());
3202 for(SelectionPool::iterator i = pool.begin(); i != pool.end(); ++i)
3204 (*i).second->setSelected(!(modifier == RadiantSelectionSystem::eToggle && (*i).second->isSelected()));
3210 void translate(const Vector3& translation)
3212 if(!nothingSelected())
3214 //ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
3216 m_translation = translation;
3218 m_pivot2world = m_pivot2world_start;
3219 matrix4_translate_by_vec3(m_pivot2world, translation);
3221 if(Mode() == eComponent)
3223 Scene_Translate_Component_Selected(GlobalSceneGraph(), m_translation);
3227 Scene_Translate_Selected(GlobalSceneGraph(), m_translation);
3230 SceneChangeNotify();
3233 void outputTranslation(TextOutputStream& ostream)
3235 ostream << " -xyz " << m_translation.x() << " " << m_translation.y() << " " << m_translation.z();
3237 void rotate(const Quaternion& rotation)
3239 if(!nothingSelected())
3241 //ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
3243 m_rotation = rotation;
3245 if(Mode() == eComponent)
3247 Scene_Rotate_Component_Selected(GlobalSceneGraph(), m_rotation, vector4_to_vector3(m_pivot2world.t()));
3249 matrix4_assign_rotation_for_pivot(m_pivot2world, m_component_selection.back());
3253 Scene_Rotate_Selected(GlobalSceneGraph(), m_rotation, vector4_to_vector3(m_pivot2world.t()));
3255 matrix4_assign_rotation_for_pivot(m_pivot2world, m_selection.back());
3258 SceneChangeNotify();
3261 void outputRotation(TextOutputStream& ostream)
3263 ostream << " -eulerXYZ " << m_rotation.x() << " " << m_rotation.y() << " " << m_rotation.z();
3265 void scale(const Vector3& scaling)
3267 if(!nothingSelected())
3271 if(Mode() == eComponent)
3273 Scene_Scale_Component_Selected(GlobalSceneGraph(), m_scale, vector4_to_vector3(m_pivot2world.t()));
3277 Scene_Scale_Selected(GlobalSceneGraph(), m_scale, vector4_to_vector3(m_pivot2world.t()));
3280 SceneChangeNotify();
3283 void outputScale(TextOutputStream& ostream)
3285 ostream << " -scale " << m_scale.x() << " " << m_scale.y() << " " << m_scale.z();
3288 void rotateSelected(const Quaternion& rotation)
3294 void translateSelected(const Vector3& translation)
3297 translate(translation);
3300 void scaleSelected(const Vector3& scaling)
3307 void MoveSelected(const View& view, const float device_point[2])
3309 if(m_manipulator->isSelected())
3313 m_undo_begun = true;
3314 GlobalUndoSystem().start();
3317 Matrix4 device2manip;
3318 ConstructDevice2Manip(device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport());
3319 m_manipulator->GetManipulatable()->Transform(m_manip2pivot_start, device2manip, device_point[0], device_point[1]);
3323 /// \todo Support view-dependent nudge.
3324 void NudgeManipulator(const Vector3& nudge, const Vector3& view)
3326 if(ManipulatorMode() == eTranslate || ManipulatorMode() == eDrag)
3328 translateSelected(nudge);
3333 void freezeTransforms();
3335 void renderSolid(Renderer& renderer, const VolumeTest& volume) const;
3336 void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
3338 renderSolid(renderer, volume);
3341 const Matrix4& GetPivot2World() const
3344 return m_pivot2world;
3347 static void constructStatic()
3349 m_state = GlobalShaderCache().capture("$POINT");
3350 #if defined(DEBUG_SELECTION)
3351 g_state_clipped = GlobalShaderCache().capture("$DEBUG_CLIPPED");
3353 TranslateManipulator::m_state_wire = GlobalShaderCache().capture("$WIRE_OVERLAY");
3354 TranslateManipulator::m_state_fill = GlobalShaderCache().capture("$FLATSHADE_OVERLAY");
3355 RotateManipulator::m_state_outer = GlobalShaderCache().capture("$WIRE_OVERLAY");
3358 static void destroyStatic()
3360 #if defined(DEBUG_SELECTION)
3361 GlobalShaderCache().release("$DEBUG_CLIPPED");
3363 GlobalShaderCache().release("$WIRE_OVERLAY");
3364 GlobalShaderCache().release("$FLATSHADE_OVERLAY");
3365 GlobalShaderCache().release("$WIRE_OVERLAY");
3366 GlobalShaderCache().release("$POINT");
3370 Shader* RadiantSelectionSystem::m_state = 0;
3375 RadiantSelectionSystem* g_RadiantSelectionSystem;
3377 inline RadiantSelectionSystem& getSelectionSystem()
3379 return *g_RadiantSelectionSystem;
3385 class testselect_entity_visible : public scene::Graph::Walker
3387 Selector& m_selector;
3388 SelectionTest& m_test;
3390 testselect_entity_visible(Selector& selector, SelectionTest& test)
3391 : m_selector(selector), m_test(test)
3394 bool pre(const scene::Path& path, scene::Instance& instance) const
3396 Selectable* selectable = Instance_getSelectable(instance);
3398 && Node_isEntity(path.top()))
3400 m_selector.pushSelectable(*selectable);
3403 SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
3404 if(selectionTestable)
3406 selectionTestable->testSelect(m_selector, m_test);
3411 void post(const scene::Path& path, scene::Instance& instance) const
3413 Selectable* selectable = Instance_getSelectable(instance);
3415 && Node_isEntity(path.top()))
3417 m_selector.popSelectable();
3422 class testselect_primitive_visible : public scene::Graph::Walker
3424 Selector& m_selector;
3425 SelectionTest& m_test;
3427 testselect_primitive_visible(Selector& selector, SelectionTest& test)
3428 : m_selector(selector), m_test(test)
3431 bool pre(const scene::Path& path, scene::Instance& instance) const
3433 Selectable* selectable = Instance_getSelectable(instance);
3436 m_selector.pushSelectable(*selectable);
3439 SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
3440 if(selectionTestable)
3442 selectionTestable->testSelect(m_selector, m_test);
3447 void post(const scene::Path& path, scene::Instance& instance) const
3449 Selectable* selectable = Instance_getSelectable(instance);
3452 m_selector.popSelectable();
3457 class testselect_component_visible : public scene::Graph::Walker
3459 Selector& m_selector;
3460 SelectionTest& m_test;
3461 SelectionSystem::EComponentMode m_mode;
3463 testselect_component_visible(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
3464 : m_selector(selector), m_test(test), m_mode(mode)
3467 bool pre(const scene::Path& path, scene::Instance& instance) const
3469 ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
3470 if(componentSelectionTestable)
3472 componentSelectionTestable->testSelectComponents(m_selector, m_test, m_mode);
3480 class testselect_component_visible_selected : public scene::Graph::Walker
3482 Selector& m_selector;
3483 SelectionTest& m_test;
3484 SelectionSystem::EComponentMode m_mode;
3486 testselect_component_visible_selected(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
3487 : m_selector(selector), m_test(test), m_mode(mode)
3490 bool pre(const scene::Path& path, scene::Instance& instance) const
3492 Selectable* selectable = Instance_getSelectable(instance);
3493 if(selectable != 0 && selectable->isSelected())
3495 ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
3496 if(componentSelectionTestable)
3498 componentSelectionTestable->testSelectComponents(m_selector, m_test, m_mode);
3506 void Scene_TestSelect_Primitive(Selector& selector, SelectionTest& test, const VolumeTest& volume)
3508 Scene_forEachVisible(GlobalSceneGraph(), volume, testselect_primitive_visible(selector, test));
3511 void Scene_TestSelect_Component_Selected(Selector& selector, SelectionTest& test, const VolumeTest& volume, SelectionSystem::EComponentMode componentMode)
3513 Scene_forEachVisible(GlobalSceneGraph(), volume, testselect_component_visible_selected(selector, test, componentMode));
3516 void Scene_TestSelect_Component(Selector& selector, SelectionTest& test, const VolumeTest& volume, SelectionSystem::EComponentMode componentMode)
3518 Scene_forEachVisible(GlobalSceneGraph(), volume, testselect_component_visible(selector, test, componentMode));
3521 void RadiantSelectionSystem::Scene_TestSelect(Selector& selector, SelectionTest& test, const View& view, SelectionSystem::EMode mode, SelectionSystem::EComponentMode componentMode)
3527 Scene_forEachVisible(GlobalSceneGraph(), view, testselect_entity_visible(selector, test));
3531 Scene_TestSelect_Primitive(selector, test, view);
3534 Scene_TestSelect_Component_Selected(selector, test, view, componentMode);
3539 class FreezeTransforms : public scene::Graph::Walker
3542 bool pre(const scene::Path& path, scene::Instance& instance) const
3544 TransformNode* transformNode = Node_getTransformNode(path.top());
3545 if(transformNode != 0)
3547 Transformable* transform = Instance_getTransformable(instance);
3550 transform->freezeTransform();
3557 void RadiantSelectionSystem::freezeTransforms()
3559 GlobalSceneGraph().traverse(FreezeTransforms());
3563 void RadiantSelectionSystem::endMove()
3567 if(Mode() == ePrimitive)
3569 if(ManipulatorMode() == eDrag)
3571 Scene_SelectAll_Component(false, SelectionSystem::eFace);
3575 m_pivot_moving = false;
3578 SceneChangeNotify();
3582 StringOutputStream command;
3584 if(ManipulatorMode() == eTranslate)
3586 command << "translateTool";
3587 outputTranslation(command);
3589 else if(ManipulatorMode() == eRotate)
3591 command << "rotateTool";
3592 outputRotation(command);
3594 else if(ManipulatorMode() == eScale)
3596 command << "scaleTool";
3597 outputScale(command);
3599 else if(ManipulatorMode() == eDrag)
3601 command << "dragTool";
3604 GlobalUndoSystem().finish(command.c_str());
3609 inline AABB Instance_getPivotBounds(scene::Instance& instance)
3611 Entity* entity = Node_getEntity(instance.path().top());
3613 && (entity->getEntityClass().fixedsize
3614 || !node_is_group(instance.path().top())))
3616 Editable* editable = Node_getEditable(instance.path().top());
3619 return AABB(vector4_to_vector3(matrix4_multiplied_by_matrix4(instance.localToWorld(), editable->getLocalPivot()).t()), Vector3(0, 0, 0));
3623 return AABB(vector4_to_vector3(instance.localToWorld().t()), Vector3(0, 0, 0));
3627 return instance.worldAABB();
3630 class bounds_selected : public scene::Graph::Walker
3634 bounds_selected(AABB& bounds)
3639 bool pre(const scene::Path& path, scene::Instance& instance) const
3641 Selectable* selectable = Instance_getSelectable(instance);
3643 && selectable->isSelected())
3645 aabb_extend_by_aabb_safe(m_bounds, Instance_getPivotBounds(instance));
3651 class bounds_selected_component : public scene::Graph::Walker
3655 bounds_selected_component(AABB& bounds)
3660 bool pre(const scene::Path& path, scene::Instance& instance) const
3662 Selectable* selectable = Instance_getSelectable(instance);
3664 && selectable->isSelected())
3666 ComponentEditable* componentEditable = Instance_getComponentEditable(instance);
3667 if(componentEditable)
3669 aabb_extend_by_aabb_safe(m_bounds, aabb_for_oriented_aabb_safe(componentEditable->getSelectedComponentsBounds(), instance.localToWorld()));
3676 void Scene_BoundsSelected(scene::Graph& graph, AABB& bounds)
3678 graph.traverse(bounds_selected(bounds));
3681 void Scene_BoundsSelectedComponent(scene::Graph& graph, AABB& bounds)
3683 graph.traverse(bounds_selected_component(bounds));
3687 inline void pivot_for_node(Matrix4& pivot, scene::Node& node, scene::Instance& instance)
3689 ComponentEditable* componentEditable = Instance_getComponentEditable(instance);
3690 if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
3691 && componentEditable != 0)
3693 pivot = matrix4_translation_for_vec3(componentEditable->getSelectedComponentsBounds().origin);
3697 Bounded* bounded = Instance_getBounded(instance);
3700 pivot = matrix4_translation_for_vec3(bounded->localAABB().origin);
3704 pivot = g_matrix4_identity;
3710 void RadiantSelectionSystem::ConstructPivot() const
3712 if(!m_pivotChanged || m_pivot_moving)
3714 m_pivotChanged = false;
3716 Vector3 m_object_pivot;
3718 if(!nothingSelected())
3722 if(Mode() == eComponent)
3724 Scene_BoundsSelectedComponent(GlobalSceneGraph(), bounds);
3728 Scene_BoundsSelected(GlobalSceneGraph(), bounds);
3730 m_object_pivot = bounds.origin;
3733 vector3_snap(m_object_pivot, GetGridSize());
3734 m_pivot2world = matrix4_translation_for_vec3(m_object_pivot);
3736 switch(m_manipulator_mode)
3741 if(Mode() == eComponent)
3743 matrix4_assign_rotation_for_pivot(m_pivot2world, m_component_selection.back());
3747 matrix4_assign_rotation_for_pivot(m_pivot2world, m_selection.back());
3751 if(Mode() == eComponent)
3753 matrix4_assign_rotation_for_pivot(m_pivot2world, m_component_selection.back());
3757 matrix4_assign_rotation_for_pivot(m_pivot2world, m_selection.back());
3766 void RadiantSelectionSystem::renderSolid(Renderer& renderer, const VolumeTest& volume) const
3768 //if(view->TestPoint(m_object_pivot))
3769 if(!nothingSelected())
3771 renderer.Highlight(Renderer::ePrimitive, false);
3772 renderer.Highlight(Renderer::eFace, false);
3774 renderer.SetState(m_state, Renderer::eWireframeOnly);
3775 renderer.SetState(m_state, Renderer::eFullMaterials);
3777 m_manipulator->render(renderer, volume, GetPivot2World());
3780 #if defined(DEBUG_SELECTION)
3781 renderer.SetState(g_state_clipped, Renderer::eWireframeOnly);
3782 renderer.SetState(g_state_clipped, Renderer::eFullMaterials);
3783 renderer.addRenderable(g_render_clipped, g_render_clipped.m_world);
3788 void SelectionSystem_OnBoundsChanged()
3790 getSelectionSystem().pivotChanged();
3794 SignalHandlerId SelectionSystem_boundsChanged;
3796 void SelectionSystem_Construct()
3798 RadiantSelectionSystem::constructStatic();
3800 g_RadiantSelectionSystem = new RadiantSelectionSystem;
3802 SelectionSystem_boundsChanged = GlobalSceneGraph().addBoundsChangedCallback(FreeCaller<SelectionSystem_OnBoundsChanged>());
3804 GlobalShaderCache().attachRenderable(getSelectionSystem());
3807 void SelectionSystem_Destroy()
3809 GlobalShaderCache().detachRenderable(getSelectionSystem());
3811 GlobalSceneGraph().removeBoundsChangedCallback(SelectionSystem_boundsChanged);
3813 delete g_RadiantSelectionSystem;
3815 RadiantSelectionSystem::destroyStatic();
3821 inline float screen_normalised(float pos, std::size_t size)
3823 return ((2.0f * pos) / size) - 1.0f;
3826 typedef Vector2 DeviceVector;
3828 inline DeviceVector window_to_normalised_device(WindowVector window, std::size_t width, std::size_t height)
3830 return DeviceVector(screen_normalised(window.x(), width), screen_normalised(height - 1 - window.y(), height));
3833 inline float device_constrained(float pos)
3835 return std::min(1.0f, std::max(-1.0f, pos));
3838 inline DeviceVector device_constrained(DeviceVector device)
3840 return DeviceVector(device_constrained(device.x()), device_constrained(device.y()));
3843 inline float window_constrained(float pos, std::size_t origin, std::size_t size)
3845 return std::min(static_cast<float>(origin + size), std::max(static_cast<float>(origin), pos));
3848 inline WindowVector window_constrained(WindowVector window, std::size_t x, std::size_t y, std::size_t width, std::size_t height)
3850 return WindowVector(window_constrained(window.x(), x, width), window_constrained(window.y(), y, height));
3853 typedef Callback1<DeviceVector> MouseEventCallback;
3855 Single<MouseEventCallback> g_mouseMovedCallback;
3856 Single<MouseEventCallback> g_mouseUpCallback;
3859 const ButtonIdentifier c_button_select = c_buttonLeft;
3860 const ModifierFlags c_modifier_manipulator = c_modifierNone;
3861 const ModifierFlags c_modifier_toggle = c_modifierShift;
3862 const ModifierFlags c_modifier_replace = c_modifierShift | c_modifierAlt;
3863 const ModifierFlags c_modifier_face = c_modifierControl;
3865 const ButtonIdentifier c_button_select = c_buttonLeft;
3866 const ModifierFlags c_modifier_manipulator = c_modifierNone;
3867 const ModifierFlags c_modifier_toggle = c_modifierControl;
3868 const ModifierFlags c_modifier_replace = c_modifierNone;
3869 const ModifierFlags c_modifier_face = c_modifierShift;
3871 const ModifierFlags c_modifier_toggle_face = c_modifier_toggle | c_modifier_face;
3872 const ModifierFlags c_modifier_replace_face = c_modifier_replace | c_modifier_face;
3874 const ButtonIdentifier c_button_texture = c_buttonMiddle;
3875 const ModifierFlags c_modifier_apply_texture = c_modifierControl | c_modifierShift;
3876 const ModifierFlags c_modifier_copy_texture = c_modifierNone;
3880 RadiantSelectionSystem::EModifier modifier_for_state(ModifierFlags state)
3882 if(state == c_modifier_toggle || state == c_modifier_toggle_face)
3884 return RadiantSelectionSystem::eToggle;
3886 if(state == c_modifier_replace || state == c_modifier_replace_face)
3888 return RadiantSelectionSystem::eReplace;
3890 return RadiantSelectionSystem::eManipulator;
3893 rect_t getDeviceArea() const
3895 DeviceVector delta(m_current - m_start);
3896 if(selecting() && fabs(delta.x()) > m_epsilon.x() && fabs(delta.y()) > m_epsilon.y())
3898 return SelectionBoxForArea(&m_start[0], &delta[0]);
3902 rect_t default_area = { { 0, 0, }, { 0, 0, }, };
3903 return default_area;
3908 DeviceVector m_start;
3909 DeviceVector m_current;
3910 DeviceVector m_epsilon;
3911 std::size_t m_unmoved_replaces;
3912 ModifierFlags m_state;
3914 RectangleCallback m_window_update;
3916 Selector_() : m_start(0.0f, 0.0f), m_current(0.0f, 0.0f), m_unmoved_replaces(0), m_state(c_modifierNone)
3922 m_window_update(getDeviceArea());
3925 void testSelect(DeviceVector position)
3927 RadiantSelectionSystem::EModifier modifier = modifier_for_state(m_state);
3928 if(modifier != RadiantSelectionSystem::eManipulator)
3930 DeviceVector delta(position - m_start);
3931 if(fabs(delta.x()) > m_epsilon.x() && fabs(delta.y()) > m_epsilon.y())
3933 DeviceVector delta(position - m_start);
3934 getSelectionSystem().SelectArea(*m_view, &m_start[0], &delta[0], modifier, (m_state & c_modifier_face) != c_modifierNone);
3938 if(modifier == RadiantSelectionSystem::eReplace && m_unmoved_replaces++ > 0)
3940 modifier = RadiantSelectionSystem::eCycle;
3942 getSelectionSystem().SelectPoint(*m_view, &position[0], &m_epsilon[0], modifier, (m_state & c_modifier_face) != c_modifierNone);
3946 m_start = m_current = DeviceVector(0.0f, 0.0f);
3950 bool selecting() const
3952 return m_state != c_modifier_manipulator;
3955 void setState(ModifierFlags state)
3957 bool was_selecting = selecting();
3959 if(was_selecting ^ selecting())
3965 ModifierFlags getState() const
3970 void modifierEnable(ModifierFlags type)
3972 setState(bitfield_enable(getState(), type));
3974 void modifierDisable(ModifierFlags type)
3976 setState(bitfield_disable(getState(), type));
3979 void mouseDown(DeviceVector position)
3981 m_start = m_current = device_constrained(position);
3984 void mouseMoved(DeviceVector position)
3986 m_current = device_constrained(position);
3989 typedef MemberCaller1<Selector_, DeviceVector, &Selector_::mouseMoved> MouseMovedCaller;
3991 void mouseUp(DeviceVector position)
3993 testSelect(device_constrained(position));
3995 g_mouseMovedCallback.clear();
3996 g_mouseUpCallback.clear();
3998 typedef MemberCaller1<Selector_, DeviceVector, &Selector_::mouseUp> MouseUpCaller;
4005 DeviceVector m_epsilon;
4008 bool mouseDown(DeviceVector position)
4010 return getSelectionSystem().SelectManipulator(*m_view, &position[0], &m_epsilon[0]);
4013 void mouseMoved(DeviceVector position)
4015 getSelectionSystem().MoveSelected(*m_view, &position[0]);
4017 typedef MemberCaller1<Manipulator_, DeviceVector, &Manipulator_::mouseMoved> MouseMovedCaller;
4019 void mouseUp(DeviceVector position)
4021 getSelectionSystem().endMove();
4022 g_mouseMovedCallback.clear();
4023 g_mouseUpCallback.clear();
4025 typedef MemberCaller1<Manipulator_, DeviceVector, &Manipulator_::mouseUp> MouseUpCaller;
4028 void Scene_copyClosestTexture(SelectionTest& test);
4029 void Scene_applyClosestTexture(SelectionTest& test);
4031 class RadiantWindowObserver : public SelectionSystemWindowObserver
4044 Selector_ m_selector;
4045 Manipulator_ m_manipulator;
4047 RadiantWindowObserver() : m_mouse_down(false)
4054 void setView(const View& view)
4056 m_selector.m_view = &view;
4057 m_manipulator.m_view = &view;
4059 void setRectangleDrawCallback(const RectangleCallback& callback)
4061 m_selector.m_window_update = callback;
4063 void onSizeChanged(int width, int height)
4067 DeviceVector epsilon(SELECT_EPSILON / static_cast<float>(m_width), SELECT_EPSILON / static_cast<float>(m_height));
4068 m_selector.m_epsilon = m_manipulator.m_epsilon = epsilon;
4070 void onMouseDown(const WindowVector& position, ButtonIdentifier button, ModifierFlags modifiers)
4072 if(button == c_button_select)
4074 m_mouse_down = true;
4076 DeviceVector devicePosition(window_to_normalised_device(position, m_width, m_height));
4077 if(modifiers == c_modifier_manipulator && m_manipulator.mouseDown(devicePosition))
4079 g_mouseMovedCallback.insert(MouseEventCallback(Manipulator_::MouseMovedCaller(m_manipulator)));
4080 g_mouseUpCallback.insert(MouseEventCallback(Manipulator_::MouseUpCaller(m_manipulator)));
4084 m_selector.mouseDown(devicePosition);
4085 g_mouseMovedCallback.insert(MouseEventCallback(Selector_::MouseMovedCaller(m_selector)));
4086 g_mouseUpCallback.insert(MouseEventCallback(Selector_::MouseUpCaller(m_selector)));
4089 else if(button == c_button_texture)
4091 DeviceVector devicePosition(device_constrained(window_to_normalised_device(position, m_width, m_height)));
4093 View scissored(*m_selector.m_view);
4094 ConstructSelectionTest(scissored, SelectionBoxForPoint(&devicePosition[0], &m_selector.m_epsilon[0]));
4095 SelectionVolume volume(scissored);
4097 if(modifiers == c_modifier_apply_texture)
4099 Scene_applyClosestTexture(volume);
4101 else if(modifiers == c_modifier_copy_texture)
4103 Scene_copyClosestTexture(volume);
4107 void onMouseMotion(const WindowVector& position, ModifierFlags modifiers)
4109 m_selector.m_unmoved_replaces = 0;
4111 if(m_mouse_down && !g_mouseMovedCallback.empty())
4113 g_mouseMovedCallback.get()(window_to_normalised_device(position, m_width, m_height));
4116 void onMouseUp(const WindowVector& position, ButtonIdentifier button, ModifierFlags modifiers)
4118 if(button == c_button_select && !g_mouseUpCallback.empty())
4120 m_mouse_down = false;
4122 g_mouseUpCallback.get()(window_to_normalised_device(position, m_width, m_height));
4125 void onModifierDown(ModifierFlags type)
4127 m_selector.modifierEnable(type);
4129 void onModifierUp(ModifierFlags type)
4131 m_selector.modifierDisable(type);
4137 SelectionSystemWindowObserver* NewWindowObserver()
4139 return new RadiantWindowObserver;
4144 #include "modulesystem/singletonmodule.h"
4145 #include "modulesystem/moduleregistry.h"
4147 class SelectionDependencies :
4148 public GlobalSceneGraphModuleRef,
4149 public GlobalShaderCacheModuleRef,
4150 public GlobalOpenGLModuleRef
4154 class SelectionAPI : public TypeSystemRef
4156 SelectionSystem* m_selection;
4158 typedef SelectionSystem Type;
4159 STRING_CONSTANT(Name, "*");
4163 SelectionSystem_Construct();
4165 m_selection = &getSelectionSystem();
4169 SelectionSystem_Destroy();
4171 SelectionSystem* getTable()
4177 typedef SingletonModule<SelectionAPI, SelectionDependencies> SelectionModule;
4178 typedef Static<SelectionModule> StaticSelectionModule;
4179 StaticRegisterModule staticRegisterSelection(StaticSelectionModule::instance());