]> icculus.org git repositories - divverent/netradiant.git/blob - radiant/selection.cpp
allow specifying executable type
[divverent/netradiant.git] / radiant / selection.cpp
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
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.
11
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.
16
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
20 */
21
22 #include "selection.h"
23
24 #include "debugging/debugging.h"
25
26 #include <map>
27 #include <list>
28 #include <set>
29
30 #include "windowobserver.h"
31 #include "iundo.h"
32 #include "ientity.h"
33 #include "cullable.h"
34 #include "renderable.h"
35 #include "selectable.h"
36 #include "editable.h"
37
38 #include "math/frustum.h"
39 #include "signal/signal.h"
40 #include "generic/object.h"
41 #include "selectionlib.h"
42 #include "render.h"
43 #include "view.h"
44 #include "renderer.h"
45 #include "stream/stringstream.h"
46 #include "eclasslib.h"
47 #include "generic/bitfield.h"
48 #include "generic/static.h"
49 #include "pivot.h"
50 #include "stringio.h"
51 #include "container/container.h"
52
53 #include "grid.h"
54
55 TextOutputStream& ostream_write(TextOutputStream& t, const Vector4& v)
56 {
57         return t << "[ " << v.x() << " " << v.y() << " " << v.z() << " " << v.w() << " ]";
58 }
59
60 TextOutputStream& ostream_write(TextOutputStream& t, const Matrix4& m)
61 {
62         return t << "[ " << m.x() << " " << m.y() << " " << m.z() << " " << m.t() << " ]";
63 }
64
65 struct Pivot2World
66 {
67   Matrix4 m_worldSpace;
68   Matrix4 m_viewpointSpace;
69   Matrix4 m_viewplaneSpace;
70   Vector3 m_axis_screen;
71
72   void update(const Matrix4& pivot2world, const Matrix4& modelview, const Matrix4& projection, const Matrix4& viewport)
73   {
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);
77   }
78 };
79
80
81 void point_for_device_point(Vector3& point, const Matrix4& device2object, const float x, const float y, const float z)
82 {
83   // transform from normalised device coords to object coords
84   point = vector4_projected(matrix4_transformed_vector4(device2object, Vector4(x, y, z, 1)));
85 }
86
87 void ray_for_device_point(Ray& ray, const Matrix4& device2object, const float x, const float y)
88 {
89     // point at x, y, zNear
90   point_for_device_point(ray.origin, device2object, x, y, -1);
91
92   // point at x, y, zFar
93   point_for_device_point(ray.direction, device2object, x, y, 1);
94
95   // construct ray
96   vector3_subtract(ray.direction, ray.origin);
97   vector3_normalise(ray.direction);
98 }
99
100 bool sphere_intersect_ray(const Vector3& origin, float radius, const Ray& ray, Vector3& intersection)
101 {
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);
105
106   if(d > 0)
107   {
108     intersection = vector3_added(ray.origin, vector3_scaled(ray.direction, a - sqrt(d)));
109     return true;
110   }
111   else
112   {
113     intersection = vector3_added( ray.origin, vector3_scaled(ray.direction, a));
114     return false;
115   }
116 }
117
118 void ray_intersect_ray(const Ray& ray, const Ray& other, Vector3& intersection)
119 {
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
127
128   if (D < 0.000001)
129   {
130     // the lines are almost parallel
131     intersection = vector3_added(other.origin, vector3_scaled(other.direction, e));
132   }
133   else
134   {
135     intersection = vector3_added(other.origin, vector3_scaled(other.direction, (e - dot*d) / D));
136   }    
137 }
138
139 const Vector3 g_origin(0, 0, 0);
140 const float g_radius = 64;
141
142 void point_on_sphere(Vector3& point, const Matrix4& device2object, const float x, const float y)
143 {
144   Ray ray;
145   ray_for_device_point(ray, device2object, x, y);
146   sphere_intersect_ray(g_origin, g_radius, ray, point);
147 }
148
149 void point_on_axis(Vector3& point, const Vector3& axis, const Matrix4& device2object, const float x, const float y)
150 {
151   Ray ray;
152   ray_for_device_point(ray, device2object, x, y);
153   ray_intersect_ray(ray, Ray(Vector3(0, 0, 0), axis), point);
154 }
155
156 void point_on_plane(Vector3& point, const Matrix4& device2object, const float x, const float y)
157 {
158   Matrix4 object2device(matrix4_full_inverse(device2object));
159   point = vector4_projected(matrix4_transformed_vector4(device2object, Vector4(x, y, object2device[14] / object2device[15], 1)));
160 }
161
162 //! a and b are unit vectors .. returns angle in radians
163 inline float angle_between(const Vector3& a, const Vector3& b)
164 {
165   return static_cast<float>(2.0 * atan2(
166     vector3_length(vector3_subtracted(a, b)),
167     vector3_length(vector3_added(a, b))
168   ));
169 }
170
171
172 #if defined(_DEBUG)
173 class test_quat
174 {
175 public:
176   test_quat(const Vector3& from, const Vector3& to)
177   {
178     Vector4 quaternion(quaternion_for_unit_vectors(from, to));
179     Matrix4 matrix(matrix4_rotation_for_quaternion(quaternion_multiplied_by_quaternion(quaternion, c_quaternion_identity)));
180   }
181 private:
182 };
183
184 static test_quat bleh(g_vector3_axis_x, g_vector3_axis_y);
185 #endif
186
187 //! axis is a unit vector
188 inline void constrain_to_axis(Vector3& vec, const Vector3& axis)
189 {
190   vec = vector3_normalised(vector3_added(vec, vector3_scaled(axis, -vector3_dot(vec, axis))));
191 }
192
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)
195 {
196   if(vector3_dot(axis, vector3_cross(a, b)) > 0.0)
197     return angle_between(a, b);
198   else
199     return -angle_between(a, b);
200 }
201
202 float distance_for_axis(const Vector3& a, const Vector3& b, const Vector3& axis)
203 {
204   return static_cast<float>(vector3_dot(b, axis) - vector3_dot(a, axis));
205 }
206
207 class Manipulatable
208 {
209 public:
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;
212 };
213
214 void transform_local2object(Matrix4& object, const Matrix4& local, const Matrix4& local2object)
215 {
216   object = matrix4_multiplied_by_matrix4(
217     matrix4_multiplied_by_matrix4(local2object, local),
218     matrix4_full_inverse(local2object)
219   );
220 }
221
222 class Rotatable
223 {
224 public:
225   virtual void rotate(const Quaternion& rotation) = 0;
226 };
227
228 class RotateFree : public Manipulatable
229 {
230   Vector3 m_start;
231   Rotatable& m_rotatable;
232 public:
233   RotateFree(Rotatable& rotatable)
234     : m_rotatable(rotatable)
235   {
236   }
237   void Construct(const Matrix4& device2manip, const float x, const float y)
238   {
239     point_on_sphere(m_start, device2manip, x, y);
240     vector3_normalise(m_start);
241   }
242   void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
243   {
244     Vector3 current;
245
246     point_on_sphere(current, device2manip, x, y);
247     vector3_normalise(current);
248
249     m_rotatable.rotate(quaternion_for_unit_vectors(m_start, current));
250   }
251 };
252
253 class RotateAxis : public Manipulatable
254 {
255   Vector3 m_axis;
256   Vector3 m_start;
257   Rotatable& m_rotatable;
258 public:
259   RotateAxis(Rotatable& rotatable)
260     : m_rotatable(rotatable)
261   {
262   }
263   void Construct(const Matrix4& device2manip, const float x, const float y)
264   {
265     point_on_sphere(m_start, device2manip, x, y);
266     constrain_to_axis(m_start, m_axis);
267   }
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)
270   {
271     Vector3 current;
272     point_on_sphere(current, device2manip, x, y);
273     constrain_to_axis(current, m_axis);
274
275     m_rotatable.rotate(quaternion_for_axisangle(m_axis, angle_for_axis(m_start, current, m_axis)));
276   }
277
278   void SetAxis(const Vector3& axis)
279   {
280     m_axis = axis;
281   }
282 };
283
284 void translation_local2object(Vector3& object, const Vector3& local, const Matrix4& local2object)
285 {
286   object = matrix4_get_translation_vec3(
287     matrix4_multiplied_by_matrix4(
288       matrix4_translated_by_vec3(local2object, local),
289       matrix4_full_inverse(local2object)
290     )
291   );
292 }
293
294 class Translatable
295 {
296 public:
297   virtual void translate(const Vector3& translation) = 0;
298 };
299
300 class TranslateAxis : public Manipulatable
301 {
302   Vector3 m_start;
303   Vector3 m_axis;
304   Translatable& m_translatable;
305 public:
306   TranslateAxis(Translatable& translatable)
307     : m_translatable(translatable)
308   {
309   }
310   void Construct(const Matrix4& device2manip, const float x, const float y)
311   {
312     point_on_axis(m_start, m_axis, device2manip, x, y);
313   }
314   void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
315   {
316     Vector3 current;
317     point_on_axis(current, m_axis, device2manip, x, y);
318     current = vector3_scaled(m_axis, distance_for_axis(m_start, current, m_axis));
319
320     translation_local2object(current, current, manip2object);
321     vector3_snap(current, GetGridSize());
322
323     m_translatable.translate(current);
324   }
325
326   void SetAxis(const Vector3& axis)
327   {
328     m_axis = axis;
329   }
330 };
331
332 class TranslateFree : public Manipulatable
333 {
334 private:
335   Vector3 m_start;
336   Translatable& m_translatable;
337 public:
338   TranslateFree(Translatable& translatable)
339     : m_translatable(translatable)
340   {
341   }
342   void Construct(const Matrix4& device2manip, const float x, const float y)
343   {
344     point_on_plane(m_start, device2manip, x, y);
345   }
346   void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
347   {
348     Vector3 current;
349     point_on_plane(current, device2manip, x, y);
350     current = vector3_subtracted(current, m_start);
351
352     translation_local2object(current, current, manip2object);
353     vector3_snap(current, GetGridSize());
354     
355     m_translatable.translate(current);
356   }
357 };
358
359
360 class Scalable
361 {
362 public:
363   virtual void scale(const Vector3& scaling) = 0;
364 };
365
366
367 class ScaleAxis : public Manipulatable
368 {
369 private:
370   Vector3 m_start;
371   Vector3 m_axis;
372   Scalable& m_scalable;
373 public:
374   ScaleAxis(Scalable& scalable)
375     : m_scalable(scalable)
376   {
377   }
378   void Construct(const Matrix4& device2manip, const float x, const float y)
379   {
380     point_on_axis(m_start, m_axis, device2manip, x, y);
381   }
382   void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
383   {
384     Vector3 current;
385     point_on_axis(current, m_axis, device2manip, x, y);
386     Vector3 delta = vector3_subtracted(current, m_start);
387
388     translation_local2object(delta, delta, manip2object);
389     vector3_snap(delta, GetGridSize());
390     
391     Vector3 start(vector3_snapped(m_start, GetGridSize()));
392     Vector3 scale(
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]
396     );
397     m_scalable.scale(scale);
398   }
399
400   void SetAxis(const Vector3& axis)
401   {
402     m_axis = axis;
403   }
404 };
405
406 class ScaleFree : public Manipulatable
407 {
408 private:
409   Vector3 m_start;
410   Scalable& m_scalable;
411 public:
412   ScaleFree(Scalable& scalable)
413     : m_scalable(scalable)
414   {
415   }
416   void Construct(const Matrix4& device2manip, const float x, const float y)
417   {
418     point_on_plane(m_start, device2manip, x, y);
419   }
420   void Transform(const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y)
421   {
422     Vector3 current;
423     point_on_plane(current, device2manip, x, y);
424     Vector3 delta = vector3_subtracted(current, m_start);
425
426     translation_local2object(delta, delta, manip2object);
427     vector3_snap(delta, GetGridSize());
428     
429     Vector3 start(vector3_snapped(m_start, GetGridSize()));
430     Vector3 scale(
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]
434     );
435     m_scalable.scale(scale);
436   }
437 };
438
439
440
441
442
443
444
445
446
447
448 class RenderableClippedPrimitive : public OpenGLRenderable
449 {
450   struct primitive_t
451   {
452     PointVertex m_points[9];
453     std::size_t m_count;
454   };
455   Matrix4 m_inverse;
456   std::vector<primitive_t> m_primitives;
457 public:
458   Matrix4 m_world;
459
460   void render(RenderStateFlags state) const
461   {
462     for(std::size_t i=0; i<m_primitives.size(); ++i)
463     {
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)
467       {
468       case 1: break;
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;
471       }
472     }
473   }
474
475   void construct(const Matrix4& world2device)
476   {
477     m_inverse = matrix4_full_inverse(world2device);
478     m_world = g_matrix4_identity;
479   }
480
481   void insert(const Vector4 clipped[9], std::size_t count)
482   {
483     add_one();
484
485     m_primitives.back().m_count = count;
486     for(std::size_t i=0; i<count; ++i)
487     {
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);
490     }
491   }
492
493   void destroy()
494   {
495     m_primitives.clear();
496   }
497 private:
498   void add_one()
499   {
500     m_primitives.push_back(primitive_t());
501
502     const Colour4b colour_clipped(255, 127, 0, 255);
503
504     for(std::size_t i=0; i<9; ++i)
505       m_primitives.back().m_points[i].colour = colour_clipped;
506   }
507 };
508
509 #if defined(_DEBUG)
510 #define DEBUG_SELECTION
511 #endif
512
513 #if defined(DEBUG_SELECTION)
514 Shader* g_state_clipped;
515 RenderableClippedPrimitive g_render_clipped;
516 #endif
517
518
519 #if 0
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
523 float
524 dist_Point_to_Line( Point P, Line L)
525 {
526     Vector v = L.P1 - L.P0;
527     Vector w = P - L.P0;
528
529     double c1 = dot(w,v);
530     double c2 = dot(v,v);
531     double b = c1 / c2;
532
533     Point Pb = L.P0 + b * v;
534     return d(P, Pb);
535 }
536 #endif
537
538 class Segment3D
539 {
540   typedef Vector3 point_type;
541 public:
542   Segment3D(const point_type& _p0, const point_type& _p1)
543     : p0(_p0), p1(_p1)
544   {
545   }
546
547   point_type p0, p1;
548 };
549
550 typedef Vector3 Point3D;
551
552 inline double vector3_distance_squared(const Point3D& a, const Point3D& b)
553 {
554   return vector3_length_squared(b - a);
555 }
556
557 // get the distance of a point to a segment.
558 Point3D segment_closest_point_to_point(const Segment3D& segment, const Point3D& point)
559 {
560   Vector3 v = segment.p1 - segment.p0;
561   Vector3 w = point - segment.p0;
562
563   double c1 = vector3_dot(w,v);
564   if ( c1 <= 0 )
565     return segment.p0;
566
567   double c2 = vector3_dot(v,v);
568   if ( c2 <= c1 )
569     return segment.p1;
570
571   return Point3D(segment.p0 + v * (c1 / c2));
572 }
573
574 double segment_dist_to_point_3d(const Segment3D& segment, const Point3D& point)
575 {
576   return vector3_distance_squared(point, segment_closest_point_to_point(segment, point));
577 }
578
579 typedef Vector3 point_t;
580 typedef const Vector3* point_iterator_t;
581
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 )
585 {
586   std::size_t crossings = 0;
587
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
597       {
598         ++crossings;   // a valid crossing of y=P[1] right of P[0]
599       }
600     }
601   }
602   return (crossings & 0x1) != 0;    // 0 if even (out), and 1 if odd (in)
603 }
604
605 inline double triangle_signed_area_XY(const Vector3& p0, const Vector3& p1, const Vector3& p2)
606 {
607   return ((p1[0] - p0[0]) * (p2[1] - p0[1])) - ((p2[0] - p0[0]) * (p1[1] - p0[1]));
608 }
609
610 enum clipcull_t
611 {
612   eClipCullNone,
613   eClipCullCW,
614   eClipCullCCW,
615 };
616
617
618 inline SelectionIntersection select_point_from_clipped(Vector4& clipped)
619 {
620   return SelectionIntersection(clipped[2] / clipped[3], static_cast<float>(vector3_length_squared(Vector3(clipped[0] / clipped[3], clipped[1] / clipped[3], 0))));
621 }
622
623 void BestPoint(std::size_t count, Vector4 clipped[9], SelectionIntersection& best, clipcull_t cull)
624 {
625   Vector3 normalised[9];
626
627   {
628     for(std::size_t i=0; i<count; ++i)
629     {
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];
633     }
634   }
635
636   if(cull != eClipCullNone && count > 2)
637   {      
638     double signed_area = triangle_signed_area_XY(normalised[0], normalised[1], normalised[2]);
639
640     if((cull == eClipCullCW && signed_area > 0)
641       || (cull == eClipCullCCW && signed_area < 0))
642       return;
643   }
644
645   if(count == 2)
646   {
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));
650   }
651   else if(count > 2 && !point_test_polygon_2d(Vector3(0, 0, 0), normalised, normalised + count))
652   {
653     point_iterator_t end = normalised + count;
654     for(point_iterator_t previous = end-1, current = normalised; current != end; previous = current, ++current)
655     {
656       Segment3D segment(*previous, *current);
657       Point3D point = segment_closest_point_to_point(segment, Vector3(0, 0, 0));
658       float depth = point.z();
659       point.z() = 0;
660       float distance = static_cast<float>(vector3_length_squared(point));
661
662       assign_if_closer(best, SelectionIntersection(depth, distance));
663     }
664   }
665   else if(count > 2)
666   {
667     assign_if_closer(
668       best,
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])
673         )), 
674         0
675       )
676     );
677   }
678
679 #if defined(DEBUG_SELECTION)
680     if(count >= 2)
681       g_render_clipped.insert(clipped, count);
682 #endif
683 }
684
685 void LineStrip_BestPoint(const Matrix4& local2view, const PointVertex* vertices, const std::size_t size, SelectionIntersection& best)
686 {
687   Vector4 clipped[2];
688   for(std::size_t i = 0; (i + 1) < size; ++i)
689   {
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);
692   }
693 }
694
695 void LineLoop_BestPoint(const Matrix4& local2view, const PointVertex* vertices, const std::size_t size, SelectionIntersection& best)
696 {
697   Vector4 clipped[2];
698   for(std::size_t i = 0; i < size; ++i)
699   {
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);
702   }
703 }
704
705 void Line_BestPoint(const Matrix4& local2view, const PointVertex vertices[2], SelectionIntersection& best)
706 {
707   Vector4 clipped[2];
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);
710 }
711
712 void Circle_BestPoint(const Matrix4& local2view, clipcull_t cull, const PointVertex* vertices, const std::size_t size, SelectionIntersection& best)
713 {
714   Vector4 clipped[9];
715   for(std::size_t i=0; i<size; ++i)
716   {
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);
719   }
720 }
721
722 void Quad_BestPoint(const Matrix4& local2view, clipcull_t cull, const PointVertex* vertices, SelectionIntersection& best)
723 {
724   Vector4 clipped[9];
725   {
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);
728   }
729   {
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);
732   }
733 }
734
735 struct FlatShadedVertex
736 {
737   Vertex3f vertex;
738   Colour4b colour;
739   Normal3f normal;
740
741   FlatShadedVertex()
742   {
743   }
744 };
745
746
747 typedef FlatShadedVertex* FlatShadedVertexIterator;
748 void Triangles_BestPoint(const Matrix4& local2view, clipcull_t cull, FlatShadedVertexIterator first, FlatShadedVertexIterator last, SelectionIntersection& best)
749 {
750   for(FlatShadedVertexIterator x(first), y(first+1), z(first+2); x != last; x += 3, y += 3, z +=3)
751   {
752     Vector4 clipped[9];
753     BestPoint(
754       matrix4_clip_triangle(
755         local2view,
756         reinterpret_cast<const Vector3&>((*x).vertex),
757         reinterpret_cast<const Vector3&>((*y).vertex),
758         reinterpret_cast<const Vector3&>((*z).vertex),
759         clipped
760       ),
761       clipped,
762       best,
763       cull
764     );
765   }
766 }
767
768
769 typedef std::multimap<SelectionIntersection, Selectable*> SelectableSortedSet;
770
771 class SelectionPool : public Selector
772 {
773   SelectableSortedSet m_pool;
774   SelectionIntersection m_intersection;
775   Selectable* m_selectable;
776
777 public:
778   void pushSelectable(Selectable& selectable)
779   {
780     m_intersection = SelectionIntersection();
781     m_selectable = &selectable;
782   }
783   void popSelectable()
784   {
785     addSelectable(m_intersection, m_selectable);
786     m_intersection = SelectionIntersection();
787   }
788   void addIntersection(const SelectionIntersection& intersection)
789   {
790     assign_if_closer(m_intersection, intersection);
791   }
792   void addSelectable(const SelectionIntersection& intersection, Selectable* selectable)
793   {
794     if(intersection.valid())
795     {
796       m_pool.insert(SelectableSortedSet::value_type(intersection, selectable));
797     }
798   }
799
800   typedef SelectableSortedSet::iterator iterator;
801
802   iterator begin()
803   {
804     return m_pool.begin();
805   }
806   iterator end()
807   {
808     return m_pool.end();
809   }
810
811   bool failed()
812   {
813     return m_pool.empty();
814   }
815 };
816
817
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);
821
822 inline const Colour4b& colourSelected(const Colour4b& colour, bool selected)
823 {
824   return (selected) ? g_colour_selected : colour;
825 }
826
827 template<typename remap_policy>
828 inline void draw_semicircle(const std::size_t segments, const float radius, PointVertex* vertices, remap_policy remap)
829 {
830   const double increment = c_pi / double(segments << 2);
831
832   std::size_t count = 0;
833   float x = radius;
834   float y = 0;
835   remap_policy::set(vertices[segments << 2].vertex, -radius, 0, 0);
836   while(count < segments)
837   {
838     PointVertex* i = vertices + count;
839     PointVertex* j = vertices + ((segments << 1) - (count + 1));
840
841     PointVertex* k = i + (segments << 1);
842     PointVertex* l = j + (segments << 1);
843
844 #if 0
845     PointVertex* m = i + (segments << 2);
846     PointVertex* n = j + (segments << 2);
847     PointVertex* o = k + (segments << 2);
848     PointVertex* p = l + (segments << 2);
849 #endif
850
851     remap_policy::set(i->vertex, x,-y, 0);
852     remap_policy::set(k->vertex,-y,-x, 0);
853 #if 0
854     remap_policy::set(m->vertex,-x, y, 0);
855     remap_policy::set(o->vertex, y, x, 0);
856 #endif
857
858     ++count;
859
860     {
861       const double theta = increment * count;
862       x = static_cast<float>(radius * cos(theta));
863       y = static_cast<float>(radius * sin(theta));
864     }
865
866     remap_policy::set(j->vertex, y,-x, 0);
867     remap_policy::set(l->vertex,-x,-y, 0);
868 #if 0
869     remap_policy::set(n->vertex,-y, x, 0);
870     remap_policy::set(p->vertex, x, y, 0);
871 #endif
872   }
873 }
874
875 class Manipulator
876 {
877 public:
878   virtual Manipulatable* GetManipulatable() = 0;
879   virtual void testSelect(const View& view, const Matrix4& pivot2world)
880   {
881   }
882   virtual void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world)
883   {
884   }
885   virtual void setSelected(bool select) = 0;
886   virtual bool isSelected() const = 0;
887 };
888
889
890 inline Vector3 normalised_safe(const Vector3& self)
891 {
892   if(vector3_equal(self, g_vector3_identity))
893   {
894     return g_vector3_identity;
895   }
896   return vector3_normalised(self);
897 }
898
899
900 class RotateManipulator : public Manipulator
901 {
902   struct RenderableCircle : public OpenGLRenderable
903   {
904     Array<PointVertex> m_vertices;
905
906     RenderableCircle(std::size_t size) : m_vertices(size)
907     {
908     }
909     void render(RenderStateFlags state) const
910     {
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()));
914     }
915     void setColour(const Colour4b& colour)
916     {
917       for(Array<PointVertex>::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
918       {
919         (*i).colour = colour;
920       }
921     }
922   };
923
924   struct RenderableSemiCircle : public OpenGLRenderable
925   {
926     Array<PointVertex> m_vertices;
927
928     RenderableSemiCircle(std::size_t size) : m_vertices(size)
929     {
930     }
931     void render(RenderStateFlags state) const
932     {
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()));
936     }
937     void setColour(const Colour4b& colour)
938     {
939       for(Array<PointVertex>::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
940       {
941         (*i).colour = colour;
942       }
943     }
944   };
945
946   RotateFree m_free;
947   RotateAxis m_axis;
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;
959   Pivot2World m_pivot;
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;
966 public:
967   static Shader* m_state_outer;
968
969   RotateManipulator(Rotatable& rotatable, std::size_t segments, float radius) :
970     m_free(rotatable),
971     m_axis(rotatable),
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)
977   {
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());
981
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());
984   }
985
986
987   void UpdateColours()
988   {
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));
994   }
995   
996   void updateCircleTransforms()
997   {
998     Vector3 localViewpoint(matrix4_transformed_direction(matrix4_transposed(m_pivot.m_worldSpace), vector4_to_vector3(m_pivot.m_viewpointSpace.z())));
999
1000     m_circle_x_visible = !vector3_equal_epsilon(g_vector3_axis_x, localViewpoint, 1e-6f);
1001     if(m_circle_x_visible)
1002     {
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)
1006       );
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()))
1009       );
1010       matrix4_premultiply_by_matrix4(m_local2world_x, m_pivot.m_worldSpace);
1011     }
1012
1013     m_circle_y_visible = !vector3_equal_epsilon(g_vector3_axis_y, localViewpoint, 1e-6f);
1014     if(m_circle_y_visible)
1015     {
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)
1019       );
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()))
1022       );
1023       matrix4_premultiply_by_matrix4(m_local2world_y, m_pivot.m_worldSpace);
1024     }
1025
1026     m_circle_z_visible = !vector3_equal_epsilon(g_vector3_axis_z, localViewpoint, 1e-6f);
1027     if(m_circle_z_visible)
1028     {
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)
1032       );
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()))
1035       );
1036       matrix4_premultiply_by_matrix4(m_local2world_z, m_pivot.m_worldSpace);
1037     }
1038   }
1039
1040   void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world)
1041   {
1042     m_pivot.update(pivot2world, volume.GetModelview(), volume.GetProjection(), volume.GetViewport());
1043     updateCircleTransforms();
1044
1045     // temp hack
1046     UpdateColours();
1047
1048     renderer.SetState(m_state_outer, Renderer::eWireframeOnly);
1049     renderer.SetState(m_state_outer, Renderer::eFullMaterials);
1050
1051     renderer.addRenderable(m_circle_screen, m_pivot.m_viewpointSpace);
1052     renderer.addRenderable(m_circle_sphere, m_pivot.m_viewpointSpace);
1053
1054     if(m_circle_x_visible)
1055     {
1056       renderer.addRenderable(m_circle_x, m_local2world_x);
1057     }
1058     if(m_circle_y_visible)
1059     {
1060       renderer.addRenderable(m_circle_y, m_local2world_y);
1061     }
1062     if(m_circle_z_visible)
1063     {
1064       renderer.addRenderable(m_circle_z, m_local2world_z);
1065     }
1066   }
1067   void testSelect(const View& view, const Matrix4& pivot2world)
1068   {
1069     m_pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport());
1070     updateCircleTransforms();
1071
1072     SelectionPool selector;
1073
1074     {
1075       {
1076         Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_local2world_x));
1077
1078 #if defined(DEBUG_SELECTION)
1079         g_render_clipped.construct(view.GetViewMatrix());
1080 #endif
1081
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);
1085       }
1086
1087       {
1088         Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_local2world_y));
1089
1090 #if defined(DEBUG_SELECTION)
1091         g_render_clipped.construct(view.GetViewMatrix());
1092 #endif
1093
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);
1097       }
1098
1099       {
1100         Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_local2world_z));
1101
1102 #if defined(DEBUG_SELECTION)
1103         g_render_clipped.construct(view.GetViewMatrix());
1104 #endif
1105
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);
1109       }
1110     }
1111
1112     {
1113       Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_viewpointSpace));
1114
1115       {
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); 
1119       }
1120
1121       {
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); 
1125       }
1126     }
1127
1128     m_axis_screen = m_pivot.m_axis_screen;
1129
1130     if(!selector.failed())
1131     {
1132       (*selector.begin()).second->setSelected(true);
1133     }
1134   }
1135
1136   Manipulatable* GetManipulatable()
1137   {
1138     if(m_selectable_x.isSelected())
1139     {
1140       m_axis.SetAxis(g_vector3_axis_x);
1141       return &m_axis;
1142     }
1143     else if(m_selectable_y.isSelected())
1144     {
1145       m_axis.SetAxis(g_vector3_axis_y);
1146       return &m_axis;
1147     }
1148     else if(m_selectable_z.isSelected())
1149     {
1150       m_axis.SetAxis(g_vector3_axis_z);
1151       return &m_axis;
1152     }
1153     else if(m_selectable_screen.isSelected())
1154     {
1155       m_axis.SetAxis(m_axis_screen);
1156       return &m_axis;
1157     }
1158     else
1159       return &m_free;
1160   }
1161
1162   void setSelected(bool select)
1163   {
1164     m_selectable_x.setSelected(select);
1165     m_selectable_y.setSelected(select);
1166     m_selectable_z.setSelected(select);
1167     m_selectable_screen.setSelected(select);
1168   }
1169   bool isSelected() const
1170   {
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();
1176   }
1177 };
1178
1179 Shader* RotateManipulator::m_state_outer;
1180
1181
1182 const float arrowhead_length = 16;
1183 const float arrowhead_radius = 4;
1184
1185 inline void draw_arrowline(const float length, PointVertex* line, const std::size_t axis)
1186 {
1187   (*line++).vertex = vertex3f_identity;
1188   (*line).vertex = vertex3f_identity;
1189   vertex3f_to_array((*line).vertex)[axis] = length - arrowhead_length;
1190 }
1191
1192 template<typename VertexRemap, typename NormalRemap>
1193 inline void draw_arrowhead(const std::size_t segments, const float length, FlatShadedVertex* vertices, VertexRemap, NormalRemap)
1194 {
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)
1198   {
1199     {
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));
1207     }
1208     {
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));
1216     }
1217     {
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));
1225     }
1226
1227     {
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;
1235     }
1236     {
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;
1244     }
1245     {
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;
1253     }
1254   }
1255 }
1256
1257 template<typename Triple>
1258 class TripleRemapXYZ
1259 {
1260 public:
1261   static float& x(Triple& triple)
1262   {
1263     return triple.x();
1264   }
1265   static float& y(Triple& triple)
1266   {
1267     return triple.y();
1268   }
1269   static float& z(Triple& triple)
1270   {
1271     return triple.z();
1272   }
1273 };
1274
1275 template<typename Triple>
1276 class TripleRemapYZX
1277 {
1278 public:
1279   static float& x(Triple& triple)
1280   {
1281     return triple.y();
1282   }
1283   static float& y(Triple& triple)
1284   {
1285     return triple.z();
1286   }
1287   static float& z(Triple& triple)
1288   {
1289     return triple.x();
1290   }
1291 };
1292
1293 template<typename Triple>
1294 class TripleRemapZXY
1295 {
1296 public:
1297   static float& x(Triple& triple)
1298   {
1299     return triple.z();
1300   }
1301   static float& y(Triple& triple)
1302   {
1303     return triple.x();
1304   }
1305   static float& z(Triple& triple)
1306   {
1307     return triple.y();
1308   }
1309 };
1310
1311 void vector3_print(const Vector3& v)
1312 {
1313   globalOutputStream() << "( " << v.x() << " " << v.y() << " " << v.z() << " )";
1314 }
1315
1316 class TranslateManipulator : public Manipulator
1317 {
1318   struct RenderableArrowLine : public OpenGLRenderable
1319   {
1320     PointVertex m_line[2];
1321
1322     RenderableArrowLine()
1323     {
1324     }
1325     void render(RenderStateFlags state) const
1326     {
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);
1330     }
1331     void setColour(const Colour4b& colour)
1332     {
1333       m_line[0].colour = colour;
1334       m_line[1].colour = colour;
1335     }
1336   };
1337   struct RenderableArrowHead : public OpenGLRenderable
1338   {
1339     Array<FlatShadedVertex> m_vertices;
1340
1341     RenderableArrowHead(std::size_t size)
1342       : m_vertices(size)
1343     {
1344     }
1345     void render(RenderStateFlags state) const
1346     {
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()));
1351     }
1352     void setColour(const Colour4b& colour)
1353     {
1354       for(Array<FlatShadedVertex>::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
1355       {
1356         (*i).colour = colour;
1357       }
1358     }
1359   };
1360   struct RenderableQuad : public OpenGLRenderable
1361   {
1362     PointVertex m_quad[4];
1363     void render(RenderStateFlags state) const
1364     {
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);
1368     }
1369     void setColour(const Colour4b& colour)
1370     {
1371       m_quad[0].colour = colour;
1372       m_quad[1].colour = colour;
1373       m_quad[2].colour = colour;
1374       m_quad[3].colour = colour;
1375     }
1376   };
1377
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;
1392 public:
1393   static Shader* m_state_wire;
1394   static Shader* m_state_fill;
1395
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))
1402   {
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>());
1409
1410     draw_quad(16, m_quad_screen.m_quad);
1411   }
1412
1413   void UpdateColours()
1414   {
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()));
1422   }
1423
1424   bool manipulator_show_axis(const Pivot2World& pivot, const Vector3& axis)
1425   {
1426     return fabs(vector3_dot(pivot.m_axis_screen, axis)) < 0.95;
1427   }
1428
1429   void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world)
1430   {
1431     m_pivot.update(pivot2world, volume.GetModelview(), volume.GetProjection(), volume.GetViewport());
1432
1433     // temp hack
1434     UpdateColours();
1435
1436     Vector3 x = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.x()));
1437     bool show_x = manipulator_show_axis(m_pivot, x);
1438
1439     Vector3 y = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.y()));
1440     bool show_y = manipulator_show_axis(m_pivot, y);
1441
1442     Vector3 z = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.z()));
1443     bool show_z = manipulator_show_axis(m_pivot, z);
1444
1445     renderer.SetState(m_state_wire, Renderer::eWireframeOnly);
1446     renderer.SetState(m_state_wire, Renderer::eFullMaterials);
1447
1448     if(show_x)
1449     {
1450       renderer.addRenderable(m_arrow_x, m_pivot.m_worldSpace);
1451     }
1452     if(show_y)
1453     {
1454       renderer.addRenderable(m_arrow_y, m_pivot.m_worldSpace);
1455     }
1456     if(show_z)
1457     {
1458       renderer.addRenderable(m_arrow_z, m_pivot.m_worldSpace);
1459     }
1460
1461     renderer.addRenderable(m_quad_screen, m_pivot.m_viewplaneSpace);
1462
1463     renderer.SetState(m_state_fill, Renderer::eWireframeOnly);
1464     renderer.SetState(m_state_fill, Renderer::eFullMaterials);
1465
1466     if(show_x)
1467     {
1468       renderer.addRenderable(m_arrow_head_x, m_pivot.m_worldSpace);
1469     }
1470     if(show_y)
1471     {
1472       renderer.addRenderable(m_arrow_head_y, m_pivot.m_worldSpace);
1473     }
1474     if(show_z)
1475     {
1476       renderer.addRenderable(m_arrow_head_z, m_pivot.m_worldSpace);
1477     }
1478   }
1479   void testSelect(const View& view, const Matrix4& pivot2world)
1480   {
1481     m_pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport());
1482
1483     SelectionPool selector;
1484
1485     Vector3 x = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.x()));
1486     bool show_x = manipulator_show_axis(m_pivot, x);
1487
1488     Vector3 y = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.y()));
1489     bool show_y = manipulator_show_axis(m_pivot, y);
1490
1491     Vector3 z = vector3_normalised(vector4_to_vector3(m_pivot.m_worldSpace.z()));
1492     bool show_z = manipulator_show_axis(m_pivot, z);
1493
1494     {
1495       Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_viewpointSpace));
1496
1497       {
1498         SelectionIntersection best;
1499         Quad_BestPoint(local2view, eClipCullCW, m_quad_screen.m_quad, best);
1500         if(best.valid())
1501         {
1502           best = SelectionIntersection(0, 0);
1503           selector.addSelectable(best, &m_selectable_screen);
1504         }
1505       }
1506     }
1507
1508     {
1509       Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_worldSpace));
1510
1511 #if defined(DEBUG_SELECTION)
1512       g_render_clipped.construct(view.GetViewMatrix());
1513 #endif
1514
1515       if(show_x)
1516       {
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);
1521       }
1522
1523       if(show_y)
1524       {
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);
1529       }
1530
1531       if(show_z)
1532       {
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);
1537       }
1538     }
1539
1540     if(!selector.failed())
1541     {
1542       (*selector.begin()).second->setSelected(true);
1543     }
1544   }
1545
1546   Manipulatable* GetManipulatable()
1547   {
1548     if(m_selectable_x.isSelected())
1549     {
1550       m_axis.SetAxis(g_vector3_axis_x);
1551       return &m_axis;
1552     }
1553     else if(m_selectable_y.isSelected())
1554     {
1555       m_axis.SetAxis(g_vector3_axis_y);
1556       return &m_axis;
1557     }
1558     else if(m_selectable_z.isSelected())
1559     {
1560       m_axis.SetAxis(g_vector3_axis_z);
1561       return &m_axis;
1562     }
1563     else
1564     {
1565       return &m_free;
1566     }
1567   }
1568
1569   void setSelected(bool select)
1570   {
1571     m_selectable_x.setSelected(select);
1572     m_selectable_y.setSelected(select);
1573     m_selectable_z.setSelected(select);
1574     m_selectable_screen.setSelected(select);
1575   }
1576   bool isSelected() const
1577   {
1578     return m_selectable_x.isSelected()
1579       | m_selectable_y.isSelected()
1580       | m_selectable_z.isSelected()
1581       | m_selectable_screen.isSelected();
1582   }
1583 };
1584
1585 Shader* TranslateManipulator::m_state_wire;
1586 Shader* TranslateManipulator::m_state_fill;
1587
1588 class ScaleManipulator : public Manipulator
1589 {
1590   struct RenderableArrow : public OpenGLRenderable
1591   {
1592     PointVertex m_line[2];
1593
1594     void render(RenderStateFlags state) const
1595     {
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);
1599     }
1600     void setColour(const Colour4b& colour)
1601     {
1602       m_line[0].colour = colour;
1603       m_line[1].colour = colour;
1604     }
1605   };
1606   struct RenderableQuad : public OpenGLRenderable
1607   {
1608     PointVertex m_quad[4];
1609     void render(RenderStateFlags state) const
1610     {
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);
1614     }
1615     void setColour(const Colour4b& colour)
1616     {
1617       m_quad[0].colour = colour;
1618       m_quad[1].colour = colour;
1619       m_quad[2].colour = colour;
1620       m_quad[3].colour = colour;
1621     }
1622   };
1623
1624   ScaleFree m_free;
1625   ScaleAxis m_axis;
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;
1635 public:
1636   ScaleManipulator(Scalable& scalable, std::size_t segments, float length) :
1637     m_free(scalable),
1638     m_axis(scalable)
1639   {
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);
1643
1644     draw_quad(16, m_quad_screen.m_quad);
1645   }
1646
1647   Pivot2World& getPivot()
1648   {
1649     return m_pivot;
1650   }
1651
1652   void UpdateColours()
1653   {
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()));
1658   }
1659
1660   void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world)
1661   {
1662     m_pivot.update(pivot2world, volume.GetModelview(), volume.GetProjection(), volume.GetViewport());
1663
1664     // temp hack
1665     UpdateColours();
1666
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);
1670
1671     renderer.addRenderable(m_quad_screen, m_pivot.m_viewpointSpace);
1672   }
1673   void testSelect(const View& view, const Matrix4& pivot2world)
1674   {
1675     m_pivot.update(pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport());
1676
1677     SelectionPool selector;
1678
1679     {
1680       Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_worldSpace));
1681
1682 #if defined(DEBUG_SELECTION)
1683       g_render_clipped.construct(view.GetViewMatrix());
1684 #endif
1685
1686     {
1687         SelectionIntersection best;
1688         Line_BestPoint(local2view, m_arrow_x.m_line, best);
1689         selector.addSelectable(best, &m_selectable_x);
1690       }
1691
1692       {
1693         SelectionIntersection best;
1694         Line_BestPoint(local2view, m_arrow_y.m_line, best);
1695         selector.addSelectable(best, &m_selectable_y);
1696       }
1697
1698       {
1699         SelectionIntersection best;
1700         Line_BestPoint(local2view, m_arrow_z.m_line, best);
1701         selector.addSelectable(best, &m_selectable_z);
1702       }
1703     }
1704
1705     {
1706       Matrix4 local2view(matrix4_multiplied_by_matrix4(view.GetViewMatrix(), m_pivot.m_viewpointSpace));
1707
1708       {
1709         SelectionIntersection best;
1710         Quad_BestPoint(local2view, eClipCullCW, m_quad_screen.m_quad, best);
1711         selector.addSelectable(best, &m_selectable_screen);
1712       }
1713     }
1714
1715     if(!selector.failed())
1716     {
1717       (*selector.begin()).second->setSelected(true);
1718     }
1719   }
1720
1721   Manipulatable* GetManipulatable()
1722   {
1723     if(m_selectable_x.isSelected())
1724     {
1725       m_axis.SetAxis(g_vector3_axis_x);
1726       return &m_axis;
1727     }
1728     else if(m_selectable_y.isSelected())
1729     {
1730       m_axis.SetAxis(g_vector3_axis_y);
1731       return &m_axis;
1732     }
1733     else if(m_selectable_z.isSelected())
1734     {
1735       m_axis.SetAxis(g_vector3_axis_z);
1736       return &m_axis;
1737     }
1738     else
1739       return &m_free;
1740   }
1741
1742   void setSelected(bool select)
1743   {
1744     m_selectable_x.setSelected(select);
1745     m_selectable_y.setSelected(select);
1746     m_selectable_z.setSelected(select);
1747     m_selectable_screen.setSelected(select);
1748   }
1749   bool isSelected() const
1750   {
1751     return m_selectable_x.isSelected()
1752       | m_selectable_y.isSelected()
1753       | m_selectable_z.isSelected()
1754       | m_selectable_screen.isSelected();
1755   }
1756 };
1757
1758
1759 inline PlaneSelectable* Instance_getPlaneSelectable(scene::Instance& instance)
1760 {
1761   return InstanceTypeCast<PlaneSelectable>::cast(instance);
1762 }
1763
1764 class PlaneSelectableSelectPlanes : public scene::Graph::Walker
1765 {
1766   Selector& m_selector;
1767   SelectionTest& m_test;
1768   PlaneCallback m_selectedPlaneCallback;
1769 public:
1770   PlaneSelectableSelectPlanes(Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
1771     : m_selector(selector), m_test(test), m_selectedPlaneCallback(selectedPlaneCallback)
1772   {
1773   }
1774   bool pre(const scene::Path& path, scene::Instance& instance) const
1775   {
1776     if(path.top().get().visible())
1777     {
1778       Selectable* selectable = Instance_getSelectable(instance);
1779       if(selectable != 0 && selectable->isSelected())
1780       {
1781         PlaneSelectable* planeSelectable = Instance_getPlaneSelectable(instance);
1782         if(planeSelectable != 0)
1783         {
1784           planeSelectable->selectPlanes(m_selector, m_test, m_selectedPlaneCallback);
1785         }
1786       }
1787     }
1788     return true; 
1789   }
1790 };
1791
1792 class PlaneSelectableSelectReversedPlanes : public scene::Graph::Walker
1793 {
1794   Selector& m_selector;
1795   const SelectedPlanes& m_selectedPlanes;
1796 public:
1797   PlaneSelectableSelectReversedPlanes(Selector& selector, const SelectedPlanes& selectedPlanes)
1798     : m_selector(selector), m_selectedPlanes(selectedPlanes)
1799   {
1800   }
1801   bool pre(const scene::Path& path, scene::Instance& instance) const
1802   {
1803     if(path.top().get().visible())
1804     {
1805       Selectable* selectable = Instance_getSelectable(instance);
1806       if(selectable != 0 && selectable->isSelected())
1807       {
1808         PlaneSelectable* planeSelectable = Instance_getPlaneSelectable(instance);
1809         if(planeSelectable != 0)
1810         {
1811           planeSelectable->selectReversedPlanes(m_selector, m_selectedPlanes);
1812         }
1813       }
1814     }
1815     return true; 
1816   }
1817 };
1818
1819 void Scene_forEachPlaneSelectable_selectPlanes(scene::Graph& graph, Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
1820 {
1821   graph.traverse(PlaneSelectableSelectPlanes(selector, test, selectedPlaneCallback));
1822 }
1823
1824 void Scene_forEachPlaneSelectable_selectReversedPlanes(scene::Graph& graph, Selector& selector, const SelectedPlanes& selectedPlanes)
1825 {
1826   graph.traverse(PlaneSelectableSelectReversedPlanes(selector, selectedPlanes));
1827 }
1828
1829
1830 class PlaneLess
1831 {
1832 public:
1833   bool operator()(const Plane3& plane, const Plane3& other) const
1834   {
1835     if(plane.a < other.a)
1836     {
1837       return true;
1838     }
1839     if(other.a < plane.a)
1840     {
1841       return false;
1842     }
1843
1844     if(plane.b < other.b)
1845     {
1846       return true;
1847     }
1848     if(other.b < plane.b)
1849     {
1850       return false;
1851     }
1852
1853     if(plane.c < other.c)
1854     {
1855       return true;
1856     }
1857     if(other.c < plane.c)
1858     {
1859       return false;
1860     }
1861
1862     if(plane.d < other.d)
1863     {
1864       return true;
1865     }
1866     if(other.d < plane.d)
1867     {
1868       return false;
1869     }
1870
1871     return false;
1872   }
1873 };
1874
1875 typedef std::set<Plane3, PlaneLess> PlaneSet;
1876
1877 inline void PlaneSet_insert(PlaneSet& self, const Plane3& plane)
1878 {
1879   self.insert(plane);
1880 }
1881
1882 inline bool PlaneSet_contains(const PlaneSet& self, const Plane3& plane)
1883 {
1884   return self.find(plane) != self.end();
1885 }
1886
1887
1888 class SelectedPlaneSet : public SelectedPlanes
1889 {
1890   PlaneSet m_selectedPlanes;
1891 public:
1892   bool empty() const
1893   {
1894     return m_selectedPlanes.empty();
1895   }
1896
1897   void insert(const Plane3& plane)
1898   {
1899     PlaneSet_insert(m_selectedPlanes, plane);
1900   }
1901   bool contains(const Plane3& plane) const
1902   {
1903     return PlaneSet_contains(m_selectedPlanes, plane);
1904   }
1905   typedef MemberCaller1<SelectedPlaneSet, const Plane3&, &SelectedPlaneSet::insert> InsertCaller;
1906 };
1907
1908
1909 bool Scene_forEachPlaneSelectable_selectPlanes(scene::Graph& graph, Selector& selector, SelectionTest& test)
1910 {
1911   SelectedPlaneSet selectedPlanes;
1912
1913   Scene_forEachPlaneSelectable_selectPlanes(graph, selector, test, SelectedPlaneSet::InsertCaller(selectedPlanes));
1914   Scene_forEachPlaneSelectable_selectReversedPlanes(graph, selector, selectedPlanes);
1915
1916   return !selectedPlanes.empty();
1917 }
1918
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);
1925
1926 class ResizeTranslatable : public Translatable
1927 {
1928   void translate(const Vector3& translation)
1929   {
1930     Scene_Translate_Component_Selected(GlobalSceneGraph(), translation);
1931   }
1932 };
1933
1934 class DragTranslatable : public Translatable
1935 {
1936   void translate(const Vector3& translation)
1937   {
1938     if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent)
1939     {
1940       Scene_Translate_Component_Selected(GlobalSceneGraph(), translation);
1941     }
1942     else
1943     {
1944       Scene_Translate_Selected(GlobalSceneGraph(), translation);
1945     }
1946   }
1947 };
1948
1949 class SelectionVolume : public SelectionTest
1950 {
1951   Matrix4 m_local2view;
1952   const View& m_view;
1953   clipcull_t m_cull;
1954   Vector3 m_near;
1955   Vector3 m_far;
1956 public:
1957   SelectionVolume(const View& view)
1958     : m_view(view)
1959   {
1960   }
1961
1962   const VolumeTest& getVolume() const
1963   {
1964     return m_view;
1965   }
1966
1967   const Vector3& getNear() const
1968   {
1969     return m_near;
1970   }
1971   const Vector3& getFar() const
1972   {
1973     return m_far;
1974   }
1975
1976   void BeginMesh(const Matrix4& localToWorld, bool twoSided)
1977   {
1978     m_local2view = matrix4_multiplied_by_matrix4(m_view.GetViewMatrix(), localToWorld);
1979
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;
1983
1984     {
1985       Matrix4 screen2world(matrix4_full_inverse(m_local2view));
1986
1987       m_near = vector4_projected(
1988         matrix4_transformed_vector4(
1989           screen2world,
1990           Vector4(0, 0, -1, 1)
1991         )
1992       );
1993
1994       m_far = vector4_projected(
1995         matrix4_transformed_vector4(
1996           screen2world,
1997           Vector4(0, 0, 1, 1)
1998         )
1999       );
2000     }
2001
2002 #if defined(DEBUG_SELECTION)
2003     g_render_clipped.construct(m_view.GetViewMatrix());
2004 #endif
2005   }
2006   void TestPoint(const Vector3& point, SelectionIntersection& best)
2007   {
2008     Vector4 clipped;
2009     if(matrix4_clip_point(m_local2view, point, clipped) == c_CLIP_PASS)
2010     {
2011       best = select_point_from_clipped(clipped);
2012     }
2013   }
2014   void TestPolygon(const VertexPointer& vertices, std::size_t count, SelectionIntersection& best)
2015   {
2016     Vector4 clipped[9];
2017     for(std::size_t i=0; i+2<count; ++i)
2018     {
2019       BestPoint(
2020         matrix4_clip_triangle(
2021           m_local2view,
2022           reinterpret_cast<const Vector3&>(vertices[0]),
2023           reinterpret_cast<const Vector3&>(vertices[i+1]),
2024           reinterpret_cast<const Vector3&>(vertices[i+2]),
2025           clipped
2026         ),
2027         clipped,
2028         best,
2029         m_cull
2030       );
2031     }
2032   }
2033   void TestLineLoop(const VertexPointer& vertices, std::size_t count, SelectionIntersection& best)
2034   {
2035     if(count == 0)
2036       return;
2037     Vector4 clipped[9];
2038     for(VertexPointer::iterator i = vertices.begin(), end = i + count, prev = i + (count-1); i != end; prev = i, ++i)
2039     {
2040       BestPoint(
2041         matrix4_clip_line(
2042           m_local2view,
2043           reinterpret_cast<const Vector3&>((*prev)),
2044           reinterpret_cast<const Vector3&>((*i)),
2045           clipped
2046         ),
2047         clipped,
2048         best,
2049         m_cull
2050       );
2051     }
2052   }
2053   void TestLineStrip(const VertexPointer& vertices, std::size_t count, SelectionIntersection& best)
2054   {
2055     if(count == 0)
2056       return;
2057     Vector4 clipped[9];
2058     for(VertexPointer::iterator i = vertices.begin(), end = i + count, next = i + 1; next != end; i = next, ++next)
2059     {
2060       BestPoint(
2061         matrix4_clip_line(
2062           m_local2view,
2063           reinterpret_cast<const Vector3&>((*i)),
2064           reinterpret_cast<const Vector3&>((*next)),
2065           clipped
2066         ),
2067         clipped,
2068         best,
2069         m_cull
2070       );
2071     }
2072   }
2073   void TestLines(const VertexPointer& vertices, std::size_t count, SelectionIntersection& best)
2074   {
2075     if(count == 0)
2076       return;
2077     Vector4 clipped[9];
2078     for(VertexPointer::iterator i = vertices.begin(), end = i + count; i != end; i += 2)
2079     {
2080       BestPoint(
2081         matrix4_clip_line(
2082           m_local2view,
2083           reinterpret_cast<const Vector3&>((*i)),
2084           reinterpret_cast<const Vector3&>((*(i+1))),
2085           clipped
2086         ),
2087         clipped,
2088         best,
2089         m_cull
2090       );
2091     }
2092   }
2093   void TestTriangles(const VertexPointer& vertices, const IndexPointer& indices, SelectionIntersection& best)
2094   {
2095     Vector4 clipped[9];
2096     for(IndexPointer::iterator i(indices.begin()); i != indices.end(); i += 3)
2097     {
2098       BestPoint(
2099         matrix4_clip_triangle(
2100           m_local2view,
2101           reinterpret_cast<const Vector3&>(vertices[*i]),
2102           reinterpret_cast<const Vector3&>(vertices[*(i+1)]),
2103           reinterpret_cast<const Vector3&>(vertices[*(i+2)]),
2104           clipped
2105         ),
2106         clipped,
2107         best,
2108         m_cull
2109       );
2110     }
2111   }
2112   void TestQuads(const VertexPointer& vertices, const IndexPointer& indices, SelectionIntersection& best)
2113   {
2114     Vector4 clipped[9];
2115     for(IndexPointer::iterator i(indices.begin()); i != indices.end(); i += 4)
2116     {
2117       BestPoint(
2118         matrix4_clip_triangle(
2119           m_local2view,
2120           reinterpret_cast<const Vector3&>(vertices[*i]),
2121           reinterpret_cast<const Vector3&>(vertices[*(i+1)]),
2122           reinterpret_cast<const Vector3&>(vertices[*(i+3)]),
2123           clipped
2124         ),
2125         clipped,
2126         best,
2127         m_cull
2128       );
2129             BestPoint(
2130         matrix4_clip_triangle(
2131           m_local2view,
2132           reinterpret_cast<const Vector3&>(vertices[*(i+1)]),
2133           reinterpret_cast<const Vector3&>(vertices[*(i+2)]),
2134           reinterpret_cast<const Vector3&>(vertices[*(i+3)]),
2135           clipped
2136         ),
2137         clipped,
2138         best,
2139         m_cull
2140       );
2141     }
2142   }
2143   void TestQuadStrip(const VertexPointer& vertices, const IndexPointer& indices, SelectionIntersection& best)
2144   {
2145     Vector4 clipped[9];
2146     for(IndexPointer::iterator i(indices.begin()); i+2 != indices.end(); i += 2)
2147     {
2148       BestPoint(
2149         matrix4_clip_triangle(
2150           m_local2view,
2151           reinterpret_cast<const Vector3&>(vertices[*i]),
2152           reinterpret_cast<const Vector3&>(vertices[*(i+1)]),
2153           reinterpret_cast<const Vector3&>(vertices[*(i+2)]),
2154           clipped
2155         ),
2156         clipped,
2157         best,
2158         m_cull
2159       );
2160       BestPoint(
2161         matrix4_clip_triangle(
2162           m_local2view,
2163           reinterpret_cast<const Vector3&>(vertices[*(i+2)]),
2164           reinterpret_cast<const Vector3&>(vertices[*(i+1)]),
2165           reinterpret_cast<const Vector3&>(vertices[*(i+3)]),
2166           clipped
2167         ),
2168         clipped,
2169         best,
2170         m_cull
2171       );
2172     }
2173   }
2174 };
2175
2176 class SelectionCounter
2177 {
2178 public:
2179   typedef const Selectable& first_argument_type;
2180
2181   SelectionCounter(const SelectionChangeCallback& onchanged)
2182     : m_count(0), m_onchanged(onchanged)
2183   {
2184   }
2185   void operator()(const Selectable& selectable)
2186   {
2187     if(selectable.isSelected())
2188     {
2189       ++m_count;
2190     }
2191     else
2192     {
2193       ASSERT_MESSAGE(m_count != 0, "selection counter underflow");
2194       --m_count;
2195     }
2196
2197     m_onchanged(selectable);
2198   }
2199   bool empty() const
2200   {
2201     return m_count == 0;
2202   }
2203   std::size_t size() const
2204   {
2205     return m_count;
2206   }
2207 private:
2208   std::size_t m_count;
2209   SelectionChangeCallback m_onchanged;
2210 };
2211
2212 inline void ConstructSelectionTest(View& view, const rect_t selection_box)
2213 {
2214   view.EnableScissor(selection_box.min[0], selection_box.max[0], selection_box.min[1], selection_box.max[1]);
2215 }
2216
2217 inline const rect_t SelectionBoxForPoint(const float device_point[2], const float device_epsilon[2])
2218 {
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;
2225 }
2226
2227 inline const rect_t SelectionBoxForArea(const float device_point[2], const float device_delta[2])
2228 {
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;
2235 }
2236
2237 Quaternion construct_local_rotation(const Quaternion& world, const Quaternion& localToWorld)
2238 {
2239   return quaternion_normalised(quaternion_multiplied_by_quaternion(
2240     quaternion_normalised(quaternion_multiplied_by_quaternion(
2241       quaternion_inverse(localToWorld),
2242       world
2243     )),
2244     localToWorld
2245   ));
2246 }
2247
2248 inline void matrix4_assign_rotation(Matrix4& matrix, const Matrix4& other)
2249 {
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];
2259 }
2260
2261 void matrix4_assign_rotation_for_pivot(Matrix4& matrix, scene::Instance& instance)
2262 {
2263   Editable* editable = Node_getEditable(instance.path().top());
2264   if(editable != 0)
2265   {
2266     matrix4_assign_rotation(matrix, matrix4_multiplied_by_matrix4(instance.localToWorld(), editable->getLocalPivot()));
2267   }
2268   else
2269   {
2270     matrix4_assign_rotation(matrix, instance.localToWorld());
2271   }
2272 }
2273
2274 inline bool Instance_isSelectedComponents(scene::Instance& instance)
2275 {
2276   ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
2277   return componentSelectionTestable != 0
2278     && componentSelectionTestable->isSelectedComponents();
2279 }
2280
2281 class TranslateSelected : public SelectionSystem::Visitor
2282 {
2283   const Vector3& m_translate;
2284 public:
2285   TranslateSelected(const Vector3& translate)
2286     : m_translate(translate)
2287   {
2288   }
2289   void visit(scene::Instance& instance) const
2290   {
2291     Transformable* transform = Instance_getTransformable(instance);
2292     if(transform != 0)
2293     {
2294       transform->setType(TRANSFORM_PRIMITIVE);
2295       transform->setTranslation(m_translate);
2296     }
2297   }
2298 };
2299
2300 void Scene_Translate_Selected(scene::Graph& graph, const Vector3& translation)
2301 {
2302   if(GlobalSelectionSystem().countSelected() != 0)
2303   {
2304     GlobalSelectionSystem().foreachSelected(TranslateSelected(translation));
2305   }
2306 }
2307
2308 Vector3 get_local_pivot(const Vector3& world_pivot, const Matrix4& localToWorld)
2309 {
2310   return Vector3(
2311     matrix4_transformed_point(
2312       matrix4_full_inverse(localToWorld),
2313       world_pivot
2314     )
2315   );
2316 }
2317
2318 void translation_for_pivoted_matrix_transform(Vector3& parent_translation, const Matrix4& local_transform, const Vector3& world_pivot, const Matrix4& localToWorld, const Matrix4& localToParent)
2319 {
2320         // we need a translation inside the parent system to move the origin of this object to the right place
2321         
2322         // mathematically, it must fulfill:
2323         //
2324         //   local_translation local_transform local_pivot = local_pivot
2325         //   local_translation = local_pivot - local_transform local_pivot
2326         //
2327         //   or maybe?
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
2332         
2333         Vector3 local_pivot(get_local_pivot(world_pivot, localToWorld));
2334
2335         Vector3 local_translation(
2336                 vector3_subtracted(
2337                         local_pivot,
2338                         matrix4_transformed_point(
2339                                 local_transform,
2340                                 local_pivot
2341                         )
2342                 /*
2343                         matrix4_transformed_point(
2344                                 matrix4_full_inverse(local_transform),
2345                                 local_pivot
2346                         ),
2347                         local_pivot
2348                 */
2349                 )
2350         );
2351         
2352         translation_local2object(parent_translation, local_translation, localToParent);
2353
2354         /*
2355         // verify it!
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";
2361         */
2362 }
2363
2364 void translation_for_pivoted_rotation(Vector3& parent_translation, const Quaternion& local_rotation, const Vector3& world_pivot, const Matrix4& localToWorld, const Matrix4& localToParent)
2365 {
2366   translation_for_pivoted_matrix_transform(parent_translation, matrix4_rotation_for_quaternion_quantised(local_rotation), world_pivot, localToWorld, localToParent);
2367 }
2368
2369 void translation_for_pivoted_scale(Vector3& parent_translation, const Vector3& world_scale, const Vector3& world_pivot, const Matrix4& localToWorld, const Matrix4& localToParent)
2370 {
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),
2376                         localToWorld
2377                 )
2378         )
2379   );
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);
2382 }
2383
2384 class rotate_selected : public SelectionSystem::Visitor
2385 {
2386   const Quaternion& m_rotate;
2387   const Vector3& m_world_pivot;
2388 public:
2389   rotate_selected(const Quaternion& rotation, const Vector3& world_pivot)
2390     : m_rotate(rotation), m_world_pivot(world_pivot)
2391   {
2392   }
2393   void visit(scene::Instance& instance) const
2394   {
2395     TransformNode* transformNode = Node_getTransformNode(instance.path().top());
2396     if(transformNode != 0)
2397     {
2398       Transformable* transform = Instance_getTransformable(instance);
2399       if(transform != 0)
2400       {
2401         transform->setType(TRANSFORM_PRIMITIVE);
2402         transform->setScale(c_scale_identity);
2403         transform->setTranslation(c_translation_identity);
2404
2405         transform->setType(TRANSFORM_PRIMITIVE);
2406         transform->setRotation(m_rotate);
2407
2408         {
2409           Editable* editable = Node_getEditable(instance.path().top());
2410           const Matrix4& localPivot = editable != 0 ? editable->getLocalPivot() : g_matrix4_identity;
2411
2412           Vector3 parent_translation;
2413           translation_for_pivoted_rotation(
2414             parent_translation,
2415             m_rotate,
2416             m_world_pivot,
2417             matrix4_multiplied_by_matrix4(instance.localToWorld(), localPivot),
2418             matrix4_multiplied_by_matrix4(transformNode->localToParent(), localPivot)
2419           );
2420
2421           transform->setTranslation(parent_translation);
2422         }
2423       } 
2424     }
2425   }
2426 };
2427
2428 void Scene_Rotate_Selected(scene::Graph& graph, const Quaternion& rotation, const Vector3& world_pivot)
2429 {
2430   if(GlobalSelectionSystem().countSelected() != 0)
2431   {
2432     GlobalSelectionSystem().foreachSelected(rotate_selected(rotation, world_pivot));
2433   }
2434 }
2435
2436 class scale_selected : public SelectionSystem::Visitor
2437 {
2438   const Vector3& m_scale;
2439   const Vector3& m_world_pivot;
2440 public:
2441   scale_selected(const Vector3& scaling, const Vector3& world_pivot)
2442     : m_scale(scaling), m_world_pivot(world_pivot)
2443   {
2444   }
2445   void visit(scene::Instance& instance) const
2446   {
2447     TransformNode* transformNode = Node_getTransformNode(instance.path().top());
2448     if(transformNode != 0)
2449     {
2450       Transformable* transform = Instance_getTransformable(instance);
2451       if(transform != 0)
2452       {
2453         transform->setType(TRANSFORM_PRIMITIVE);
2454         transform->setScale(c_scale_identity);
2455         transform->setTranslation(c_translation_identity);
2456
2457         transform->setType(TRANSFORM_PRIMITIVE);
2458         transform->setScale(m_scale);
2459         {
2460           Editable* editable = Node_getEditable(instance.path().top());
2461           const Matrix4& localPivot = editable != 0 ? editable->getLocalPivot() : g_matrix4_identity;
2462     
2463           Vector3 parent_translation;
2464           translation_for_pivoted_scale(
2465             parent_translation,
2466             m_scale,
2467             m_world_pivot,
2468             matrix4_multiplied_by_matrix4(instance.localToWorld(), localPivot),
2469             matrix4_multiplied_by_matrix4(transformNode->localToParent(), localPivot)
2470           );
2471
2472           transform->setTranslation(parent_translation);
2473         }
2474       }
2475     }
2476   }
2477 };
2478
2479 void Scene_Scale_Selected(scene::Graph& graph, const Vector3& scaling, const Vector3& world_pivot)
2480 {
2481   if(GlobalSelectionSystem().countSelected() != 0)
2482   {
2483     GlobalSelectionSystem().foreachSelected(scale_selected(scaling, world_pivot));
2484   }
2485 }
2486
2487
2488 class translate_component_selected : public SelectionSystem::Visitor
2489 {
2490   const Vector3& m_translate;
2491 public:
2492   translate_component_selected(const Vector3& translate)
2493     : m_translate(translate)
2494   {
2495   }
2496   void visit(scene::Instance& instance) const
2497   {
2498     Transformable* transform = Instance_getTransformable(instance);
2499     if(transform != 0)
2500     {
2501       transform->setType(TRANSFORM_COMPONENT);
2502       transform->setTranslation(m_translate);
2503     }
2504   }
2505 };
2506
2507 void Scene_Translate_Component_Selected(scene::Graph& graph, const Vector3& translation)
2508 {
2509   if(GlobalSelectionSystem().countSelected() != 0)
2510   {
2511     GlobalSelectionSystem().foreachSelectedComponent(translate_component_selected(translation));
2512   }
2513 }
2514
2515 class rotate_component_selected : public SelectionSystem::Visitor
2516 {
2517   const Quaternion& m_rotate;
2518   const Vector3& m_world_pivot;
2519 public:
2520   rotate_component_selected(const Quaternion& rotation, const Vector3& world_pivot)
2521     : m_rotate(rotation), m_world_pivot(world_pivot)
2522   {
2523   }
2524   void visit(scene::Instance& instance) const
2525   {
2526     Transformable* transform = Instance_getTransformable(instance);
2527     if(transform != 0)
2528     {
2529       Vector3 parent_translation;
2530       translation_for_pivoted_rotation(parent_translation, m_rotate, m_world_pivot, instance.localToWorld(), Node_getTransformNode(instance.path().top())->localToParent());
2531
2532       transform->setType(TRANSFORM_COMPONENT);
2533       transform->setRotation(m_rotate);
2534       transform->setTranslation(parent_translation);
2535     }
2536   }
2537 };
2538
2539 void Scene_Rotate_Component_Selected(scene::Graph& graph, const Quaternion& rotation, const Vector3& world_pivot)
2540 {
2541   if(GlobalSelectionSystem().countSelectedComponents() != 0)
2542   {
2543     GlobalSelectionSystem().foreachSelectedComponent(rotate_component_selected(rotation, world_pivot));
2544   }
2545 }
2546
2547 class scale_component_selected : public SelectionSystem::Visitor
2548 {
2549   const Vector3& m_scale;
2550   const Vector3& m_world_pivot;
2551 public:
2552   scale_component_selected(const Vector3& scaling, const Vector3& world_pivot)
2553     : m_scale(scaling), m_world_pivot(world_pivot)
2554   {
2555   }
2556   void visit(scene::Instance& instance) const
2557   {
2558     Transformable* transform = Instance_getTransformable(instance);
2559     if(transform != 0)
2560     {
2561       Vector3 parent_translation;
2562       translation_for_pivoted_scale(parent_translation, m_scale, m_world_pivot, instance.localToWorld(), Node_getTransformNode(instance.path().top())->localToParent());
2563
2564       transform->setType(TRANSFORM_COMPONENT);
2565       transform->setScale(m_scale);
2566       transform->setTranslation(parent_translation);
2567     }
2568   }
2569 };
2570
2571 void Scene_Scale_Component_Selected(scene::Graph& graph, const Vector3& scaling, const Vector3& world_pivot)
2572 {
2573   if(GlobalSelectionSystem().countSelectedComponents() != 0)
2574   {
2575     GlobalSelectionSystem().foreachSelectedComponent(scale_component_selected(scaling, world_pivot));
2576   }
2577 }
2578
2579
2580 class BooleanSelector : public Selector
2581 {
2582   bool m_selected;
2583   SelectionIntersection m_intersection;
2584   Selectable* m_selectable;
2585 public:
2586   BooleanSelector() : m_selected(false)
2587   {
2588   }
2589
2590   void pushSelectable(Selectable& selectable)
2591   {
2592     m_intersection = SelectionIntersection();
2593     m_selectable = &selectable;
2594   }
2595   void popSelectable()
2596   {
2597     if(m_intersection.valid())
2598     {
2599       m_selected = true;
2600     }
2601     m_intersection = SelectionIntersection();
2602   }
2603   void addIntersection(const SelectionIntersection& intersection)
2604   {
2605     if(m_selectable->isSelected())
2606     {
2607       assign_if_closer(m_intersection, intersection);
2608     }
2609   }
2610
2611   bool isSelected()
2612   {
2613     return m_selected;
2614   }
2615 };
2616
2617 class BestSelector : public Selector
2618 {
2619   SelectionIntersection m_intersection;
2620   Selectable* m_selectable;
2621   SelectionIntersection m_bestIntersection;
2622   std::list<Selectable*> m_bestSelectable;
2623 public:
2624   BestSelector() : m_bestIntersection(SelectionIntersection()), m_bestSelectable(0)
2625   {
2626   }
2627
2628   void pushSelectable(Selectable& selectable)
2629   {
2630     m_intersection = SelectionIntersection();
2631     m_selectable = &selectable;
2632   }
2633   void popSelectable()
2634   {
2635     if(m_intersection.equalEpsilon(m_bestIntersection, 0.25f, 0.001f))
2636     {
2637       m_bestSelectable.push_back(m_selectable);
2638       m_bestIntersection = m_intersection;
2639     }
2640     else if(m_intersection < m_bestIntersection)
2641     {
2642       m_bestSelectable.clear();
2643       m_bestSelectable.push_back(m_selectable);
2644       m_bestIntersection = m_intersection;
2645     }
2646     m_intersection = SelectionIntersection();
2647   }
2648   void addIntersection(const SelectionIntersection& intersection)
2649   {
2650     assign_if_closer(m_intersection, intersection);
2651   }
2652
2653   std::list<Selectable*>& best()
2654   {
2655     return m_bestSelectable;
2656   }
2657 };
2658
2659 class DragManipulator : public Manipulator
2660 {
2661   TranslateFree m_freeResize;
2662   TranslateFree m_freeDrag;
2663   ResizeTranslatable m_resize;
2664   DragTranslatable m_drag;
2665   SelectableBool m_dragSelectable;
2666 public:
2667
2668   bool m_selected;
2669
2670   DragManipulator() : m_freeResize(m_resize), m_freeDrag(m_drag), m_selected(false)
2671   {
2672   }
2673
2674   Manipulatable* GetManipulatable()
2675   {
2676     return m_dragSelectable.isSelected() ? &m_freeDrag : &m_freeResize;
2677   }
2678
2679   void testSelect(const View& view, const Matrix4& pivot2world)
2680   {
2681     SelectionPool selector;
2682
2683     SelectionVolume test(view);
2684
2685     if(GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
2686     {
2687       BooleanSelector booleanSelector;
2688
2689       Scene_TestSelect_Primitive(booleanSelector, test, view);
2690
2691       if(booleanSelector.isSelected())
2692       {
2693         selector.addSelectable(SelectionIntersection(0, 0), &m_dragSelectable);
2694         m_selected = false;
2695       }
2696       else
2697       {
2698         m_selected = Scene_forEachPlaneSelectable_selectPlanes(GlobalSceneGraph(), selector, test);
2699       }
2700     }
2701     else
2702     {
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)
2706       {
2707         if(!(*i)->isSelected())
2708         {
2709           GlobalSelectionSystem().setSelectedAllComponents(false);
2710         }
2711         m_selected = false;
2712         selector.addSelectable(SelectionIntersection(0, 0), (*i));
2713         m_dragSelectable.setSelected(true);
2714       }
2715     }
2716
2717     for(SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i)
2718     {
2719       (*i).second->setSelected(true);
2720     }
2721   }
2722   
2723   void setSelected(bool select)
2724   {
2725     m_selected = select;
2726     m_dragSelectable.setSelected(select);
2727   }
2728   bool isSelected() const
2729   {
2730     return m_selected || m_dragSelectable.isSelected();
2731   }
2732 };
2733
2734 class ClipManipulator : public Manipulator
2735 {
2736 public:
2737
2738   Manipulatable* GetManipulatable()
2739   {
2740     ERROR_MESSAGE("clipper is not manipulatable");
2741     return 0;
2742   }
2743
2744   void setSelected(bool select)
2745   {
2746   }
2747   bool isSelected() const
2748   {
2749     return false;
2750   }
2751 };
2752
2753 class select_all : public scene::Graph::Walker
2754 {
2755   bool m_select;
2756 public:
2757   select_all(bool select)
2758     : m_select(select)
2759   {
2760   }
2761   bool pre(const scene::Path& path, scene::Instance& instance) const
2762   {
2763     Selectable* selectable = Instance_getSelectable(instance);
2764     if(selectable != 0)
2765     {
2766       selectable->setSelected(m_select);
2767     }
2768     return true;
2769   }
2770 };
2771
2772 class select_all_component : public scene::Graph::Walker
2773 {
2774   bool m_select;
2775   SelectionSystem::EComponentMode m_mode;
2776 public:
2777   select_all_component(bool select, SelectionSystem::EComponentMode mode)
2778     : m_select(select), m_mode(mode)
2779   {
2780   }
2781   bool pre(const scene::Path& path, scene::Instance& instance) const
2782   {
2783     ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
2784     if(componentSelectionTestable)
2785     {
2786       componentSelectionTestable->setSelectedComponents(m_select, m_mode);
2787     }
2788     return true;
2789   }
2790 };
2791
2792 void Scene_SelectAll_Component(bool select, SelectionSystem::EComponentMode componentMode)
2793 {
2794   GlobalSceneGraph().traverse(select_all_component(select, componentMode));
2795 }
2796
2797
2798 // RadiantSelectionSystem
2799 class RadiantSelectionSystem :
2800   public SelectionSystem,
2801   public Translatable,
2802   public Rotatable,
2803   public Scalable,
2804   public Renderable
2805 {
2806   mutable Matrix4 m_pivot2world;
2807   Matrix4 m_pivot2world_start;
2808   Matrix4 m_manip2pivot_start;
2809   Translation m_translation;
2810   Rotation m_rotation;
2811   Scale m_scale;
2812 public:
2813   static Shader* m_state;
2814 private:
2815   EManipulatorMode m_manipulator_mode;
2816   Manipulator* m_manipulator;
2817
2818   // state
2819   bool m_undo_begun;
2820   EMode m_mode;
2821   EComponentMode m_componentmode;
2822
2823   SelectionCounter m_count_primitive;
2824   SelectionCounter m_count_component;
2825
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;
2831
2832   typedef SelectionList<scene::Instance> selection_t;
2833   selection_t m_selection;
2834   selection_t m_component_selection;
2835
2836   Signal1<const Selectable&> m_selectionChanged_callbacks;
2837
2838   void ConstructPivot() const;
2839   mutable bool m_pivotChanged;
2840   bool m_pivot_moving;
2841
2842   void Scene_TestSelect(Selector& selector, SelectionTest& test, const View& view, SelectionSystem::EMode mode, SelectionSystem::EComponentMode componentMode);
2843
2844   bool nothingSelected() const
2845   {
2846     return (Mode() == eComponent && m_count_component.empty())
2847       || (Mode() == ePrimitive && m_count_primitive.empty());
2848   }
2849
2850
2851 public:
2852   enum EModifier
2853   {
2854     eManipulator,
2855     eToggle,
2856     eReplace,
2857     eCycle,
2858   };
2859
2860   RadiantSelectionSystem() :
2861     m_undo_begun(false),
2862     m_mode(ePrimitive),
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)
2871   {
2872     SetManipulatorMode(eTranslate);
2873     pivotChanged();
2874     addSelectionChangeCallback(PivotChangedSelectionCaller(*this));
2875     AddGridChangeCallback(PivotChangedCaller(*this));
2876   }
2877   void pivotChanged() const
2878   {
2879     m_pivotChanged = true;
2880     SceneChangeNotify();
2881   }
2882   typedef ConstMemberCaller<RadiantSelectionSystem, &RadiantSelectionSystem::pivotChanged> PivotChangedCaller;
2883   void pivotChangedSelection(const Selectable& selectable)
2884   {
2885     pivotChanged();
2886   }
2887   typedef MemberCaller1<RadiantSelectionSystem, const Selectable&, &RadiantSelectionSystem::pivotChangedSelection> PivotChangedSelectionCaller;
2888
2889   void SetMode(EMode mode)
2890   {
2891     if(m_mode != mode)
2892     {
2893       m_mode = mode;
2894       pivotChanged();
2895     }
2896   }
2897   EMode Mode() const
2898   {
2899     return m_mode;
2900   }
2901   void SetComponentMode(EComponentMode mode)
2902   {
2903     m_componentmode = mode;
2904   }
2905   EComponentMode ComponentMode() const
2906   {
2907     return m_componentmode;
2908   }
2909   void SetManipulatorMode(EManipulatorMode mode)
2910   {
2911     m_manipulator_mode = mode;
2912     switch(m_manipulator_mode)
2913     {
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;
2919     }
2920     pivotChanged();
2921   }
2922   EManipulatorMode ManipulatorMode() const
2923   {
2924     return m_manipulator_mode;
2925   }
2926
2927   SelectionChangeCallback getObserver(EMode mode)
2928   {
2929     if(mode == ePrimitive)
2930     {
2931       return makeCallback1(m_count_primitive);
2932     }
2933     else
2934     {
2935       return makeCallback1(m_count_component);
2936     }
2937   }
2938   std::size_t countSelected() const
2939   {
2940     return m_count_primitive.size();
2941   }
2942   std::size_t countSelectedComponents() const
2943   {
2944     return m_count_component.size();
2945   }
2946   void onSelectedChanged(scene::Instance& instance, const Selectable& selectable)
2947   {
2948     if(selectable.isSelected())
2949     {
2950       m_selection.append(instance);
2951     }
2952     else
2953     {
2954       m_selection.erase(instance);
2955     }
2956
2957     ASSERT_MESSAGE(m_selection.size() == m_count_primitive.size(), "selection-tracking error");
2958   }
2959   void onComponentSelection(scene::Instance& instance, const Selectable& selectable)
2960   {
2961     if(selectable.isSelected())
2962     {
2963       m_component_selection.append(instance);
2964     }
2965     else
2966     {
2967       m_component_selection.erase(instance);
2968     }
2969
2970     ASSERT_MESSAGE(m_component_selection.size() == m_count_component.size(), "selection-tracking error");
2971   }
2972   scene::Instance& ultimateSelected() const
2973   {
2974     ASSERT_MESSAGE(m_selection.size() > 0, "no instance selected");
2975     return m_selection.back();
2976   }
2977   scene::Instance& penultimateSelected() const
2978   {
2979     ASSERT_MESSAGE(m_selection.size() > 1, "only one instance selected");
2980     return *(*(--(--m_selection.end())));
2981   }
2982   void setSelectedAll(bool selected)
2983   {
2984     GlobalSceneGraph().traverse(select_all(selected));
2985
2986     m_manipulator->setSelected(selected);
2987   }
2988   void setSelectedAllComponents(bool selected)
2989   {
2990     Scene_SelectAll_Component(selected, SelectionSystem::eVertex);
2991     Scene_SelectAll_Component(selected, SelectionSystem::eEdge);
2992     Scene_SelectAll_Component(selected, SelectionSystem::eFace);
2993
2994     m_manipulator->setSelected(selected);
2995   }
2996
2997   void foreachSelected(const Visitor& visitor) const
2998   {
2999     selection_t::const_iterator i = m_selection.begin();
3000     while(i != m_selection.end())
3001     {
3002       visitor.visit(*(*(i++)));
3003     }
3004   }
3005   void foreachSelectedComponent(const Visitor& visitor) const
3006   {
3007     selection_t::const_iterator i = m_component_selection.begin();
3008     while(i != m_component_selection.end())
3009     {
3010       visitor.visit(*(*(i++)));
3011     }
3012   }
3013
3014   void addSelectionChangeCallback(const SelectionChangeHandler& handler)
3015   {
3016     m_selectionChanged_callbacks.connectLast(handler);
3017   }
3018   void selectionChanged(const Selectable& selectable)
3019   {
3020     m_selectionChanged_callbacks(selectable);
3021   }
3022   typedef MemberCaller1<RadiantSelectionSystem, const Selectable&, &RadiantSelectionSystem::selectionChanged> SelectionChangedCaller;
3023
3024
3025   void startMove()
3026   {
3027     m_pivot2world_start = GetPivot2World();
3028   }
3029
3030   bool SelectManipulator(const View& view, const float device_point[2], const float device_epsilon[2])
3031   {
3032     if(!nothingSelected() || (ManipulatorMode() == eDrag && Mode() == eComponent))
3033     {
3034 #if defined (DEBUG_SELECTION)
3035       g_render_clipped.destroy();
3036 #endif
3037
3038       m_manipulator->setSelected(false);
3039
3040       if(!nothingSelected() || (ManipulatorMode() == eDrag && Mode() == eComponent))
3041       {
3042         View scissored(view);
3043         ConstructSelectionTest(scissored, SelectionBoxForPoint(device_point, device_epsilon));
3044         m_manipulator->testSelect(scissored, GetPivot2World());
3045       }
3046
3047       startMove();
3048
3049       m_pivot_moving = m_manipulator->isSelected();
3050
3051       if(m_pivot_moving)
3052       {
3053         Pivot2World pivot;
3054         pivot.update(GetPivot2World(), view.GetModelview(), view.GetProjection(), view.GetViewport());
3055
3056         m_manip2pivot_start = matrix4_multiplied_by_matrix4(matrix4_full_inverse(m_pivot2world_start), pivot.m_worldSpace);
3057
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]);
3061
3062         m_undo_begun = false;
3063       }
3064
3065       SceneChangeNotify();
3066     }
3067
3068     return m_pivot_moving;
3069   }
3070
3071   void deselectAll()
3072   {
3073     if(Mode() == eComponent)
3074     {
3075       setSelectedAllComponents(false);
3076     }
3077     else
3078     {
3079       setSelectedAll(false);
3080     }
3081   }
3082
3083   void SelectPoint(const View& view, const float device_point[2], const float device_epsilon[2], RadiantSelectionSystem::EModifier modifier, bool face)
3084   {
3085     ASSERT_MESSAGE(fabs(device_point[0]) <= 1.0f && fabs(device_point[1]) <= 1.0f, "point-selection error");
3086     if(modifier == eReplace)
3087     {
3088       if(face)
3089       {
3090         setSelectedAllComponents(false);
3091       }
3092       else
3093       {
3094         deselectAll();
3095       }
3096     }
3097
3098   #if defined (DEBUG_SELECTION)
3099     g_render_clipped.destroy();
3100   #endif
3101
3102     {
3103       View scissored(view);
3104       ConstructSelectionTest(scissored, SelectionBoxForPoint(device_point, device_epsilon));
3105
3106       SelectionVolume volume(scissored);
3107       SelectionPool selector;
3108       if(face)
3109       {
3110         Scene_TestSelect_Component(selector, volume, scissored, eFace);
3111       }
3112       else
3113       {
3114         Scene_TestSelect(selector, volume, scissored, Mode(), ComponentMode());
3115       }
3116
3117       if(!selector.failed())
3118       {
3119         switch(modifier)
3120         {
3121         case RadiantSelectionSystem::eToggle:
3122           {
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);
3127             else
3128               (*best).second->setSelected(true);
3129           }
3130           break;
3131           // if cycle mode not enabled, enable it
3132         case RadiantSelectionSystem::eReplace:
3133           {
3134             // select closest
3135             (*selector.begin()).second->setSelected(true);
3136           }
3137           break;
3138           // select the next object in the list from the one already selected
3139         case RadiantSelectionSystem::eCycle:
3140           {
3141             SelectionPool::iterator i = selector.begin();
3142             while(i != selector.end())
3143             {
3144               if((*i).second->isSelected())
3145               {
3146                 (*i).second->setSelected(false);
3147                 ++i;
3148                 if(i != selector.end())
3149                 {
3150                   i->second->setSelected(true);
3151                 }
3152                 else
3153                 {
3154                   selector.begin()->second->setSelected(true);
3155                 }
3156                 break;
3157               }
3158               ++i;
3159             }
3160           }
3161           break;
3162         default:
3163           break;
3164         }
3165       }
3166     }
3167   } 
3168
3169   void SelectArea(const View& view, const float device_point[2], const float device_delta[2], RadiantSelectionSystem::EModifier modifier, bool face)
3170   {
3171     if(modifier == eReplace)
3172     {
3173       if(face)
3174       {
3175         setSelectedAllComponents(false);
3176       }
3177       else
3178       {
3179         deselectAll();
3180       }
3181     }
3182
3183   #if defined (DEBUG_SELECTION)
3184       g_render_clipped.destroy();
3185   #endif
3186
3187     {
3188       View scissored(view);
3189       ConstructSelectionTest(scissored, SelectionBoxForArea(device_point, device_delta));
3190
3191       SelectionVolume volume(scissored);
3192       SelectionPool pool;
3193       if(face)
3194       {
3195         Scene_TestSelect_Component(pool, volume, scissored, eFace);
3196       }
3197       else
3198       {
3199         Scene_TestSelect(pool, volume, scissored, Mode(), ComponentMode());
3200       }
3201
3202       for(SelectionPool::iterator i = pool.begin(); i != pool.end(); ++i)
3203       {
3204         (*i).second->setSelected(!(modifier == RadiantSelectionSystem::eToggle && (*i).second->isSelected()));
3205       }
3206     }
3207   }
3208
3209
3210   void translate(const Vector3& translation)
3211   {
3212     if(!nothingSelected())
3213     {
3214       //ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
3215
3216       m_translation = translation;
3217
3218       m_pivot2world = m_pivot2world_start;
3219       matrix4_translate_by_vec3(m_pivot2world, translation);
3220
3221       if(Mode() == eComponent)
3222       {
3223         Scene_Translate_Component_Selected(GlobalSceneGraph(), m_translation);
3224       }
3225       else
3226       {
3227         Scene_Translate_Selected(GlobalSceneGraph(), m_translation);
3228       }
3229
3230       SceneChangeNotify();
3231     }
3232   }
3233   void outputTranslation(TextOutputStream& ostream)
3234   {
3235     ostream << " -xyz " << m_translation.x() << " " << m_translation.y() << " " << m_translation.z();
3236   }
3237   void rotate(const Quaternion& rotation)
3238   {
3239     if(!nothingSelected())
3240     {
3241       //ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
3242       
3243       m_rotation = rotation;
3244
3245       if(Mode() == eComponent)
3246       {
3247         Scene_Rotate_Component_Selected(GlobalSceneGraph(), m_rotation, vector4_to_vector3(m_pivot2world.t()));
3248
3249         matrix4_assign_rotation_for_pivot(m_pivot2world, m_component_selection.back());
3250       }
3251       else
3252       {
3253         Scene_Rotate_Selected(GlobalSceneGraph(), m_rotation, vector4_to_vector3(m_pivot2world.t()));
3254
3255         matrix4_assign_rotation_for_pivot(m_pivot2world, m_selection.back());
3256       }
3257
3258       SceneChangeNotify();
3259     }
3260   }
3261   void outputRotation(TextOutputStream& ostream)
3262   {
3263     ostream << " -eulerXYZ " << m_rotation.x() << " " << m_rotation.y() << " " << m_rotation.z();
3264   }
3265   void scale(const Vector3& scaling)
3266   {
3267     if(!nothingSelected())
3268     {
3269       m_scale = scaling;
3270
3271       if(Mode() == eComponent)
3272       {
3273         Scene_Scale_Component_Selected(GlobalSceneGraph(), m_scale, vector4_to_vector3(m_pivot2world.t()));
3274       }
3275       else
3276       {
3277         Scene_Scale_Selected(GlobalSceneGraph(), m_scale, vector4_to_vector3(m_pivot2world.t()));
3278       }
3279
3280       SceneChangeNotify();
3281     }
3282   }
3283   void outputScale(TextOutputStream& ostream)
3284   {
3285     ostream << " -scale " << m_scale.x() << " " << m_scale.y() << " " << m_scale.z();
3286   }
3287
3288   void rotateSelected(const Quaternion& rotation)
3289   {
3290     startMove();
3291     rotate(rotation);
3292     freezeTransforms();
3293   }
3294   void translateSelected(const Vector3& translation)
3295   {
3296     startMove();
3297     translate(translation);
3298     freezeTransforms();
3299   }
3300   void scaleSelected(const Vector3& scaling)
3301   {
3302     startMove();
3303     scale(scaling);
3304     freezeTransforms();
3305   }
3306
3307   void MoveSelected(const View& view, const float device_point[2])
3308   {
3309     if(m_manipulator->isSelected())
3310     {
3311       if(!m_undo_begun)
3312       {
3313         m_undo_begun = true;
3314         GlobalUndoSystem().start();
3315       }
3316
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]);
3320     }
3321   }
3322
3323   /// \todo Support view-dependent nudge.
3324   void NudgeManipulator(const Vector3& nudge, const Vector3& view)
3325   {
3326     if(ManipulatorMode() == eTranslate || ManipulatorMode() == eDrag)
3327     {
3328       translateSelected(nudge);
3329     }
3330   }
3331
3332   void endMove();
3333   void freezeTransforms();
3334
3335   void renderSolid(Renderer& renderer, const VolumeTest& volume) const;
3336   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
3337   {
3338     renderSolid(renderer, volume);
3339   }
3340
3341   const Matrix4& GetPivot2World() const
3342   {
3343     ConstructPivot();
3344     return m_pivot2world;
3345   }
3346
3347   static void constructStatic()
3348   {
3349     m_state = GlobalShaderCache().capture("$POINT");
3350   #if defined(DEBUG_SELECTION)
3351     g_state_clipped = GlobalShaderCache().capture("$DEBUG_CLIPPED");
3352   #endif
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");
3356   }
3357
3358   static void destroyStatic()
3359   {
3360   #if defined(DEBUG_SELECTION)
3361     GlobalShaderCache().release("$DEBUG_CLIPPED");
3362   #endif
3363     GlobalShaderCache().release("$WIRE_OVERLAY");
3364     GlobalShaderCache().release("$FLATSHADE_OVERLAY");
3365     GlobalShaderCache().release("$WIRE_OVERLAY");
3366     GlobalShaderCache().release("$POINT");
3367   }
3368 };
3369
3370 Shader* RadiantSelectionSystem::m_state = 0;
3371
3372
3373 namespace
3374 {
3375   RadiantSelectionSystem* g_RadiantSelectionSystem;
3376
3377   inline RadiantSelectionSystem& getSelectionSystem()
3378   {
3379     return *g_RadiantSelectionSystem;
3380   }
3381 }
3382
3383
3384
3385 class testselect_entity_visible : public scene::Graph::Walker
3386 {
3387   Selector& m_selector;
3388   SelectionTest& m_test;
3389 public:
3390   testselect_entity_visible(Selector& selector, SelectionTest& test)
3391     : m_selector(selector), m_test(test)
3392   {
3393   }
3394   bool pre(const scene::Path& path, scene::Instance& instance) const
3395   {
3396     Selectable* selectable = Instance_getSelectable(instance);
3397     if(selectable != 0
3398       && Node_isEntity(path.top()))
3399     {
3400       m_selector.pushSelectable(*selectable);
3401     }
3402
3403     SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
3404     if(selectionTestable)
3405     {
3406       selectionTestable->testSelect(m_selector, m_test);
3407     }
3408
3409     return true;
3410   }
3411   void post(const scene::Path& path, scene::Instance& instance) const
3412   {
3413     Selectable* selectable = Instance_getSelectable(instance);
3414     if(selectable != 0
3415       && Node_isEntity(path.top()))
3416     {
3417       m_selector.popSelectable();
3418     }
3419   }
3420 };
3421
3422 class testselect_primitive_visible : public scene::Graph::Walker
3423 {
3424   Selector& m_selector;
3425   SelectionTest& m_test;
3426 public:
3427   testselect_primitive_visible(Selector& selector, SelectionTest& test)
3428     : m_selector(selector), m_test(test)
3429   {
3430   }
3431   bool pre(const scene::Path& path, scene::Instance& instance) const
3432   {
3433     Selectable* selectable = Instance_getSelectable(instance);
3434     if(selectable != 0)
3435     {
3436       m_selector.pushSelectable(*selectable);
3437     }
3438
3439     SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
3440     if(selectionTestable)
3441     {
3442       selectionTestable->testSelect(m_selector, m_test);
3443     }
3444
3445     return true;
3446   }
3447   void post(const scene::Path& path, scene::Instance& instance) const
3448   {
3449     Selectable* selectable = Instance_getSelectable(instance);
3450     if(selectable != 0)
3451     {
3452       m_selector.popSelectable();
3453     }
3454   }
3455 };
3456
3457 class testselect_component_visible : public scene::Graph::Walker
3458 {
3459   Selector& m_selector;
3460   SelectionTest& m_test;
3461   SelectionSystem::EComponentMode m_mode;
3462 public:
3463   testselect_component_visible(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
3464     : m_selector(selector), m_test(test), m_mode(mode)
3465   {
3466   }
3467   bool pre(const scene::Path& path, scene::Instance& instance) const
3468   {
3469     ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
3470     if(componentSelectionTestable)
3471     {
3472       componentSelectionTestable->testSelectComponents(m_selector, m_test, m_mode);
3473     }
3474
3475     return true;
3476   }
3477 };
3478
3479
3480 class testselect_component_visible_selected : public scene::Graph::Walker
3481 {
3482   Selector& m_selector;
3483   SelectionTest& m_test;
3484   SelectionSystem::EComponentMode m_mode;
3485 public:
3486   testselect_component_visible_selected(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
3487     : m_selector(selector), m_test(test), m_mode(mode)
3488   {
3489   }
3490   bool pre(const scene::Path& path, scene::Instance& instance) const
3491   {
3492     Selectable* selectable = Instance_getSelectable(instance);
3493     if(selectable != 0 && selectable->isSelected())
3494     {
3495       ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
3496       if(componentSelectionTestable)
3497       {
3498         componentSelectionTestable->testSelectComponents(m_selector, m_test, m_mode);
3499       }
3500     }
3501
3502     return true;
3503   }
3504 };
3505
3506 void Scene_TestSelect_Primitive(Selector& selector, SelectionTest& test, const VolumeTest& volume)
3507 {
3508   Scene_forEachVisible(GlobalSceneGraph(), volume, testselect_primitive_visible(selector, test));
3509 }
3510
3511 void Scene_TestSelect_Component_Selected(Selector& selector, SelectionTest& test, const VolumeTest& volume, SelectionSystem::EComponentMode componentMode)
3512 {
3513   Scene_forEachVisible(GlobalSceneGraph(), volume, testselect_component_visible_selected(selector, test, componentMode));
3514 }
3515
3516 void Scene_TestSelect_Component(Selector& selector, SelectionTest& test, const VolumeTest& volume, SelectionSystem::EComponentMode componentMode)
3517 {
3518   Scene_forEachVisible(GlobalSceneGraph(), volume, testselect_component_visible(selector, test, componentMode));
3519 }
3520
3521 void RadiantSelectionSystem::Scene_TestSelect(Selector& selector, SelectionTest& test, const View& view, SelectionSystem::EMode mode, SelectionSystem::EComponentMode componentMode)
3522 {
3523   switch(mode)
3524   {
3525   case eEntity:
3526     {
3527       Scene_forEachVisible(GlobalSceneGraph(), view, testselect_entity_visible(selector, test));
3528     }
3529     break;
3530   case ePrimitive:
3531     Scene_TestSelect_Primitive(selector, test, view);
3532     break;
3533   case eComponent:
3534     Scene_TestSelect_Component_Selected(selector, test, view, componentMode);
3535     break;
3536   }
3537 }
3538
3539 class FreezeTransforms : public scene::Graph::Walker
3540 {
3541 public:
3542   bool pre(const scene::Path& path, scene::Instance& instance) const
3543   {
3544     TransformNode* transformNode = Node_getTransformNode(path.top());
3545     if(transformNode != 0)
3546     {
3547       Transformable* transform = Instance_getTransformable(instance);
3548       if(transform != 0)
3549       {
3550         transform->freezeTransform(); 
3551       }
3552     }
3553     return true;
3554   }
3555 };
3556
3557 void RadiantSelectionSystem::freezeTransforms()
3558 {
3559   GlobalSceneGraph().traverse(FreezeTransforms());
3560 }
3561
3562
3563 void RadiantSelectionSystem::endMove()
3564 {
3565   freezeTransforms();
3566
3567   if(Mode() == ePrimitive)
3568   {
3569     if(ManipulatorMode() == eDrag)
3570     {
3571       Scene_SelectAll_Component(false, SelectionSystem::eFace);
3572     }
3573   }
3574
3575   m_pivot_moving = false;
3576   pivotChanged();
3577
3578   SceneChangeNotify();
3579
3580   if(m_undo_begun)
3581   {
3582     StringOutputStream command;
3583
3584     if(ManipulatorMode() == eTranslate)
3585     {
3586       command << "translateTool";
3587       outputTranslation(command);
3588     }
3589     else if(ManipulatorMode() == eRotate)
3590     {
3591       command << "rotateTool";
3592       outputRotation(command);
3593     }
3594     else if(ManipulatorMode() == eScale)
3595     {
3596       command << "scaleTool";
3597       outputScale(command);
3598     }
3599     else if(ManipulatorMode() == eDrag)
3600     {
3601       command << "dragTool";
3602     }
3603
3604     GlobalUndoSystem().finish(command.c_str());
3605   }
3606
3607 }
3608
3609 inline AABB Instance_getPivotBounds(scene::Instance& instance)
3610 {
3611   Entity* entity = Node_getEntity(instance.path().top());
3612   if(entity != 0
3613     && (entity->getEntityClass().fixedsize
3614     || !node_is_group(instance.path().top())))
3615   {
3616     Editable* editable = Node_getEditable(instance.path().top());
3617     if(editable != 0)
3618     {
3619       return AABB(vector4_to_vector3(matrix4_multiplied_by_matrix4(instance.localToWorld(), editable->getLocalPivot()).t()), Vector3(0, 0, 0));
3620     }
3621     else
3622     {
3623       return AABB(vector4_to_vector3(instance.localToWorld().t()), Vector3(0, 0, 0));
3624     }
3625   }
3626
3627   return instance.worldAABB();
3628 }
3629
3630 class bounds_selected : public scene::Graph::Walker
3631 {
3632   AABB& m_bounds;
3633 public:
3634   bounds_selected(AABB& bounds)
3635     : m_bounds(bounds)
3636   {
3637     m_bounds = AABB();
3638   }
3639   bool pre(const scene::Path& path, scene::Instance& instance) const
3640   {
3641     Selectable* selectable = Instance_getSelectable(instance);
3642     if(selectable != 0
3643       && selectable->isSelected())
3644     {
3645       aabb_extend_by_aabb_safe(m_bounds, Instance_getPivotBounds(instance));
3646     }
3647     return true;
3648   }
3649 };
3650
3651 class bounds_selected_component : public scene::Graph::Walker
3652 {
3653   AABB& m_bounds;
3654 public:
3655   bounds_selected_component(AABB& bounds)
3656     : m_bounds(bounds)
3657   {
3658     m_bounds = AABB();
3659   }
3660   bool pre(const scene::Path& path, scene::Instance& instance) const
3661   {
3662     Selectable* selectable = Instance_getSelectable(instance);
3663     if(selectable != 0
3664       && selectable->isSelected())
3665     {
3666       ComponentEditable* componentEditable = Instance_getComponentEditable(instance);
3667       if(componentEditable)
3668       {
3669         aabb_extend_by_aabb_safe(m_bounds, aabb_for_oriented_aabb_safe(componentEditable->getSelectedComponentsBounds(), instance.localToWorld()));
3670       }
3671     }
3672     return true;
3673   }
3674 };
3675
3676 void Scene_BoundsSelected(scene::Graph& graph, AABB& bounds)
3677 {
3678   graph.traverse(bounds_selected(bounds));
3679 }
3680
3681 void Scene_BoundsSelectedComponent(scene::Graph& graph, AABB& bounds)
3682 {
3683   graph.traverse(bounds_selected_component(bounds));
3684 }
3685
3686 #if 0
3687 inline void pivot_for_node(Matrix4& pivot, scene::Node& node, scene::Instance& instance)
3688 {
3689   ComponentEditable* componentEditable = Instance_getComponentEditable(instance);
3690   if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
3691     && componentEditable != 0)
3692   {
3693     pivot = matrix4_translation_for_vec3(componentEditable->getSelectedComponentsBounds().origin);
3694   }
3695   else
3696   {
3697     Bounded* bounded = Instance_getBounded(instance);
3698     if(bounded != 0)
3699     {
3700       pivot = matrix4_translation_for_vec3(bounded->localAABB().origin);
3701     }
3702     else
3703     {
3704       pivot = g_matrix4_identity;
3705     }
3706   }
3707 }
3708 #endif
3709
3710 void RadiantSelectionSystem::ConstructPivot() const
3711 {
3712   if(!m_pivotChanged || m_pivot_moving)
3713     return;
3714   m_pivotChanged = false;
3715
3716   Vector3 m_object_pivot;
3717
3718   if(!nothingSelected())
3719   {
3720     {
3721       AABB bounds;
3722       if(Mode() == eComponent)
3723       {
3724         Scene_BoundsSelectedComponent(GlobalSceneGraph(), bounds);
3725       }
3726       else
3727       {
3728         Scene_BoundsSelected(GlobalSceneGraph(), bounds);
3729       }
3730       m_object_pivot = bounds.origin;
3731     }
3732
3733     vector3_snap(m_object_pivot, GetGridSize());
3734     m_pivot2world = matrix4_translation_for_vec3(m_object_pivot);
3735
3736     switch(m_manipulator_mode)
3737     {
3738     case eTranslate:
3739       break;
3740     case eRotate:
3741       if(Mode() == eComponent)
3742       {
3743         matrix4_assign_rotation_for_pivot(m_pivot2world, m_component_selection.back());
3744       }
3745       else
3746       {
3747         matrix4_assign_rotation_for_pivot(m_pivot2world, m_selection.back());
3748       }
3749       break;
3750     case eScale:
3751       if(Mode() == eComponent)
3752       {
3753         matrix4_assign_rotation_for_pivot(m_pivot2world, m_component_selection.back());
3754       }
3755       else
3756       {
3757         matrix4_assign_rotation_for_pivot(m_pivot2world, m_selection.back());
3758       }
3759       break;
3760     default:
3761       break;
3762     }
3763   }
3764 }
3765
3766 void RadiantSelectionSystem::renderSolid(Renderer& renderer, const VolumeTest& volume) const
3767 {
3768   //if(view->TestPoint(m_object_pivot))
3769   if(!nothingSelected())
3770   {
3771     renderer.Highlight(Renderer::ePrimitive, false);
3772     renderer.Highlight(Renderer::eFace, false);
3773
3774     renderer.SetState(m_state, Renderer::eWireframeOnly);
3775     renderer.SetState(m_state, Renderer::eFullMaterials);
3776
3777     m_manipulator->render(renderer, volume, GetPivot2World());
3778   }
3779
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);
3784 #endif
3785 }
3786
3787
3788 void SelectionSystem_OnBoundsChanged()
3789 {
3790   getSelectionSystem().pivotChanged();
3791 }
3792
3793
3794 SignalHandlerId SelectionSystem_boundsChanged;
3795
3796 void SelectionSystem_Construct()
3797 {
3798   RadiantSelectionSystem::constructStatic();
3799
3800   g_RadiantSelectionSystem = new RadiantSelectionSystem;
3801
3802   SelectionSystem_boundsChanged = GlobalSceneGraph().addBoundsChangedCallback(FreeCaller<SelectionSystem_OnBoundsChanged>());
3803
3804   GlobalShaderCache().attachRenderable(getSelectionSystem());
3805 }
3806
3807 void SelectionSystem_Destroy()
3808 {
3809   GlobalShaderCache().detachRenderable(getSelectionSystem());
3810
3811   GlobalSceneGraph().removeBoundsChangedCallback(SelectionSystem_boundsChanged);
3812
3813   delete g_RadiantSelectionSystem;
3814
3815   RadiantSelectionSystem::destroyStatic();
3816 }
3817
3818
3819
3820
3821 inline float screen_normalised(float pos, std::size_t size)
3822 {
3823   return ((2.0f * pos) / size) - 1.0f;
3824 }
3825
3826 typedef Vector2 DeviceVector;
3827
3828 inline DeviceVector window_to_normalised_device(WindowVector window, std::size_t width, std::size_t height)
3829 {
3830   return DeviceVector(screen_normalised(window.x(), width), screen_normalised(height - 1 - window.y(), height));
3831 }
3832
3833 inline float device_constrained(float pos)
3834 {
3835   return std::min(1.0f, std::max(-1.0f, pos));
3836 }
3837
3838 inline DeviceVector device_constrained(DeviceVector device)
3839 {
3840   return DeviceVector(device_constrained(device.x()), device_constrained(device.y()));
3841 }
3842
3843 inline float window_constrained(float pos, std::size_t origin, std::size_t size)
3844 {
3845   return std::min(static_cast<float>(origin + size), std::max(static_cast<float>(origin), pos));
3846 }
3847
3848 inline WindowVector window_constrained(WindowVector window, std::size_t x, std::size_t y, std::size_t width, std::size_t height)
3849 {
3850   return WindowVector(window_constrained(window.x(), x, width), window_constrained(window.y(), y, height));
3851 }
3852
3853 typedef Callback1<DeviceVector> MouseEventCallback;
3854
3855 Single<MouseEventCallback> g_mouseMovedCallback;
3856 Single<MouseEventCallback> g_mouseUpCallback;
3857
3858 #if 1
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;
3864 #else
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;
3870 #endif
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;
3873
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;
3877
3878 class Selector_
3879 {
3880   RadiantSelectionSystem::EModifier modifier_for_state(ModifierFlags state)
3881   {
3882     if(state == c_modifier_toggle || state == c_modifier_toggle_face)
3883     {
3884       return RadiantSelectionSystem::eToggle;
3885     }
3886     if(state == c_modifier_replace || state == c_modifier_replace_face)
3887     {
3888       return RadiantSelectionSystem::eReplace;
3889     }
3890     return RadiantSelectionSystem::eManipulator;
3891   }
3892
3893   rect_t getDeviceArea() const
3894   {
3895     DeviceVector delta(m_current - m_start);
3896     if(selecting() && fabs(delta.x()) > m_epsilon.x() && fabs(delta.y()) > m_epsilon.y())
3897     {
3898       return SelectionBoxForArea(&m_start[0], &delta[0]);
3899     }
3900     else
3901     {
3902       rect_t default_area = { { 0, 0, }, { 0, 0, }, };
3903       return default_area;
3904     }
3905   }
3906
3907 public:
3908   DeviceVector m_start;
3909   DeviceVector m_current;
3910   DeviceVector m_epsilon;
3911   std::size_t m_unmoved_replaces;
3912   ModifierFlags m_state;
3913   const View* m_view;
3914   RectangleCallback m_window_update;
3915
3916   Selector_() : m_start(0.0f, 0.0f), m_current(0.0f, 0.0f), m_unmoved_replaces(0), m_state(c_modifierNone)
3917   {
3918   }
3919
3920   void draw_area()
3921   {
3922     m_window_update(getDeviceArea());
3923   }
3924
3925   void testSelect(DeviceVector position)
3926   {
3927     RadiantSelectionSystem::EModifier modifier = modifier_for_state(m_state);
3928     if(modifier != RadiantSelectionSystem::eManipulator)
3929     {
3930       DeviceVector delta(position - m_start);
3931       if(fabs(delta.x()) > m_epsilon.x() && fabs(delta.y()) > m_epsilon.y())
3932       {
3933         DeviceVector delta(position - m_start);
3934         getSelectionSystem().SelectArea(*m_view, &m_start[0], &delta[0], modifier, (m_state & c_modifier_face) != c_modifierNone);
3935       }
3936       else
3937       {
3938         if(modifier == RadiantSelectionSystem::eReplace && m_unmoved_replaces++ > 0)
3939         {
3940           modifier = RadiantSelectionSystem::eCycle;
3941         }
3942         getSelectionSystem().SelectPoint(*m_view, &position[0], &m_epsilon[0], modifier, (m_state & c_modifier_face) != c_modifierNone);
3943       }
3944     }
3945
3946     m_start = m_current = DeviceVector(0.0f, 0.0f);
3947     draw_area();
3948   }
3949
3950   bool selecting() const
3951   {
3952     return m_state != c_modifier_manipulator;
3953   }
3954
3955   void setState(ModifierFlags state)
3956   {
3957     bool was_selecting = selecting();
3958     m_state = state;
3959     if(was_selecting ^ selecting())
3960     {
3961       draw_area();
3962     }
3963   }
3964
3965   ModifierFlags getState() const
3966   {
3967     return m_state;
3968   }
3969
3970   void modifierEnable(ModifierFlags type)
3971   {
3972     setState(bitfield_enable(getState(), type));
3973   }
3974   void modifierDisable(ModifierFlags type)
3975   {
3976     setState(bitfield_disable(getState(), type));
3977   }
3978
3979   void mouseDown(DeviceVector position)
3980   {
3981     m_start = m_current = device_constrained(position);
3982   }
3983
3984   void mouseMoved(DeviceVector position)
3985   {
3986     m_current = device_constrained(position);
3987     draw_area();
3988   }
3989   typedef MemberCaller1<Selector_, DeviceVector, &Selector_::mouseMoved> MouseMovedCaller;
3990
3991   void mouseUp(DeviceVector position)
3992   {
3993     testSelect(device_constrained(position));
3994
3995     g_mouseMovedCallback.clear();
3996     g_mouseUpCallback.clear();
3997   }
3998   typedef MemberCaller1<Selector_, DeviceVector, &Selector_::mouseUp> MouseUpCaller;
3999 };
4000
4001
4002 class Manipulator_
4003 {
4004 public:
4005   DeviceVector m_epsilon;
4006   const View* m_view;
4007
4008   bool mouseDown(DeviceVector position)
4009   {
4010     return getSelectionSystem().SelectManipulator(*m_view, &position[0], &m_epsilon[0]);
4011   }
4012
4013   void mouseMoved(DeviceVector position)
4014   {
4015     getSelectionSystem().MoveSelected(*m_view, &position[0]);
4016   }
4017   typedef MemberCaller1<Manipulator_, DeviceVector, &Manipulator_::mouseMoved> MouseMovedCaller;
4018
4019   void mouseUp(DeviceVector position)
4020   {
4021     getSelectionSystem().endMove();
4022     g_mouseMovedCallback.clear();
4023     g_mouseUpCallback.clear();
4024   }
4025   typedef MemberCaller1<Manipulator_, DeviceVector, &Manipulator_::mouseUp> MouseUpCaller;
4026 };
4027
4028 void Scene_copyClosestTexture(SelectionTest& test);
4029 void Scene_applyClosestTexture(SelectionTest& test);
4030
4031 class RadiantWindowObserver : public SelectionSystemWindowObserver
4032 {
4033   enum
4034   {
4035     SELECT_EPSILON = 8,
4036   };
4037
4038   int m_width;
4039   int m_height;
4040
4041   bool m_mouse_down;
4042
4043 public:
4044   Selector_ m_selector;
4045   Manipulator_ m_manipulator;
4046
4047   RadiantWindowObserver() : m_mouse_down(false)
4048   {
4049   }
4050   void release()
4051   {
4052     delete this;
4053   }
4054   void setView(const View& view)
4055   {
4056     m_selector.m_view = &view;
4057     m_manipulator.m_view = &view;
4058   }
4059   void setRectangleDrawCallback(const RectangleCallback& callback)
4060   {
4061     m_selector.m_window_update = callback;
4062   }
4063   void onSizeChanged(int width, int height)
4064   {
4065     m_width = width;
4066     m_height = 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;
4069   }
4070   void onMouseDown(const WindowVector& position, ButtonIdentifier button, ModifierFlags modifiers)
4071   {
4072     if(button == c_button_select)
4073     {
4074       m_mouse_down = true;
4075
4076       DeviceVector devicePosition(window_to_normalised_device(position, m_width, m_height));
4077       if(modifiers == c_modifier_manipulator && m_manipulator.mouseDown(devicePosition))
4078       {
4079         g_mouseMovedCallback.insert(MouseEventCallback(Manipulator_::MouseMovedCaller(m_manipulator)));
4080         g_mouseUpCallback.insert(MouseEventCallback(Manipulator_::MouseUpCaller(m_manipulator)));
4081       }
4082       else
4083       {
4084         m_selector.mouseDown(devicePosition);
4085         g_mouseMovedCallback.insert(MouseEventCallback(Selector_::MouseMovedCaller(m_selector)));
4086         g_mouseUpCallback.insert(MouseEventCallback(Selector_::MouseUpCaller(m_selector)));
4087       }
4088     }
4089     else if(button == c_button_texture)
4090     {
4091       DeviceVector devicePosition(device_constrained(window_to_normalised_device(position, m_width, m_height)));
4092
4093       View scissored(*m_selector.m_view);
4094       ConstructSelectionTest(scissored, SelectionBoxForPoint(&devicePosition[0], &m_selector.m_epsilon[0]));
4095       SelectionVolume volume(scissored);
4096
4097       if(modifiers == c_modifier_apply_texture)
4098       {
4099         Scene_applyClosestTexture(volume);
4100       }
4101       else if(modifiers == c_modifier_copy_texture)
4102       {
4103         Scene_copyClosestTexture(volume);
4104       }
4105     }
4106   }
4107   void onMouseMotion(const WindowVector& position, ModifierFlags modifiers)
4108   {
4109     m_selector.m_unmoved_replaces = 0;
4110
4111     if(m_mouse_down && !g_mouseMovedCallback.empty())
4112     {
4113       g_mouseMovedCallback.get()(window_to_normalised_device(position, m_width, m_height));
4114     }
4115   }
4116   void onMouseUp(const WindowVector& position, ButtonIdentifier button, ModifierFlags modifiers)
4117   {
4118     if(button == c_button_select && !g_mouseUpCallback.empty())
4119     {
4120       m_mouse_down = false;
4121
4122       g_mouseUpCallback.get()(window_to_normalised_device(position, m_width, m_height));
4123     }
4124   }
4125   void onModifierDown(ModifierFlags type)
4126   {
4127     m_selector.modifierEnable(type);
4128   }
4129   void onModifierUp(ModifierFlags type)
4130   {
4131     m_selector.modifierDisable(type);
4132   }
4133 };
4134
4135
4136
4137 SelectionSystemWindowObserver* NewWindowObserver()
4138 {
4139   return new RadiantWindowObserver;
4140 }
4141
4142
4143
4144 #include "modulesystem/singletonmodule.h"
4145 #include "modulesystem/moduleregistry.h"
4146
4147 class SelectionDependencies :
4148   public GlobalSceneGraphModuleRef,
4149   public GlobalShaderCacheModuleRef,
4150   public GlobalOpenGLModuleRef
4151 {
4152 };
4153
4154 class SelectionAPI : public TypeSystemRef
4155 {
4156   SelectionSystem* m_selection;
4157 public:
4158   typedef SelectionSystem Type;
4159   STRING_CONSTANT(Name, "*");
4160
4161   SelectionAPI()
4162   {
4163     SelectionSystem_Construct();
4164
4165     m_selection = &getSelectionSystem();
4166   }
4167   ~SelectionAPI()
4168   {
4169     SelectionSystem_Destroy();
4170   }
4171   SelectionSystem* getTable()
4172   {
4173     return m_selection;
4174   }
4175 };
4176
4177 typedef SingletonModule<SelectionAPI, SelectionDependencies> SelectionModule;
4178 typedef Static<SelectionModule> StaticSelectionModule;
4179 StaticRegisterModule staticRegisterSelection(StaticSelectionModule::instance());