]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/selection.cpp
revert the last commit, instead fix the underlying bug
[xonotic/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         // verify it!
2355         globalOutputStream() << "World pivot is at " << world_pivot << "\n";
2356         globalOutputStream() << "Local pivot is at " << local_pivot << "\n";
2357         globalOutputStream() << "Transformation " << local_transform << " moves it to: " << matrix4_transformed_point(local_transform, local_pivot) << "\n";
2358         globalOutputStream() << "Must move by " << local_translation << " in the local system" << "\n";
2359         globalOutputStream() << "Must move by " << parent_translation << " in the parent system" << "\n";
2360 }
2361
2362 void translation_for_pivoted_rotation(Vector3& parent_translation, const Quaternion& local_rotation, const Vector3& world_pivot, const Matrix4& localToWorld, const Matrix4& localToParent)
2363 {
2364   translation_for_pivoted_matrix_transform(parent_translation, matrix4_rotation_for_quaternion_quantised(local_rotation), world_pivot, localToWorld, localToParent);
2365 }
2366
2367 void translation_for_pivoted_scale(Vector3& parent_translation, const Vector3& world_scale, const Vector3& world_pivot, const Matrix4& localToWorld, const Matrix4& localToParent)
2368 {
2369   Matrix4 local_transform(
2370         matrix4_multiplied_by_matrix4(
2371                 matrix4_full_inverse(localToWorld),
2372                 matrix4_multiplied_by_matrix4(
2373                         matrix4_scale_for_vec3(world_scale),
2374                         localToWorld
2375                 )
2376         )
2377   );
2378   local_transform.tx() = local_transform.ty() = local_transform.tz() = 0; // cancel translation parts
2379   translation_for_pivoted_matrix_transform(parent_translation, local_transform, world_pivot, localToWorld, localToParent);
2380 }
2381
2382 class rotate_selected : public SelectionSystem::Visitor
2383 {
2384   const Quaternion& m_rotate;
2385   const Vector3& m_world_pivot;
2386 public:
2387   rotate_selected(const Quaternion& rotation, const Vector3& world_pivot)
2388     : m_rotate(rotation), m_world_pivot(world_pivot)
2389   {
2390   }
2391   void visit(scene::Instance& instance) const
2392   {
2393     TransformNode* transformNode = Node_getTransformNode(instance.path().top());
2394     if(transformNode != 0)
2395     {
2396       Transformable* transform = Instance_getTransformable(instance);
2397       if(transform != 0)
2398       {
2399         transform->setType(TRANSFORM_PRIMITIVE);
2400         transform->setScale(c_scale_identity);
2401         transform->setTranslation(c_translation_identity);
2402
2403         transform->setType(TRANSFORM_PRIMITIVE);
2404         transform->setRotation(m_rotate);
2405
2406         {
2407           Editable* editable = Node_getEditable(instance.path().top());
2408           const Matrix4& localPivot = editable != 0 ? editable->getLocalPivot() : g_matrix4_identity;
2409
2410           Vector3 parent_translation;
2411           translation_for_pivoted_rotation(
2412             parent_translation,
2413             m_rotate,
2414             m_world_pivot,
2415             matrix4_multiplied_by_matrix4(instance.localToWorld(), localPivot),
2416             matrix4_multiplied_by_matrix4(transformNode->localToParent(), localPivot)
2417           );
2418
2419           transform->setTranslation(parent_translation);
2420         }
2421       } 
2422     }
2423   }
2424 };
2425
2426 void Scene_Rotate_Selected(scene::Graph& graph, const Quaternion& rotation, const Vector3& world_pivot)
2427 {
2428   if(GlobalSelectionSystem().countSelected() != 0)
2429   {
2430     GlobalSelectionSystem().foreachSelected(rotate_selected(rotation, world_pivot));
2431   }
2432 }
2433
2434 class scale_selected : public SelectionSystem::Visitor
2435 {
2436   const Vector3& m_scale;
2437   const Vector3& m_world_pivot;
2438 public:
2439   scale_selected(const Vector3& scaling, const Vector3& world_pivot)
2440     : m_scale(scaling), m_world_pivot(world_pivot)
2441   {
2442   }
2443   void visit(scene::Instance& instance) const
2444   {
2445     TransformNode* transformNode = Node_getTransformNode(instance.path().top());
2446     if(transformNode != 0)
2447     {
2448       Transformable* transform = Instance_getTransformable(instance);
2449       if(transform != 0)
2450       {
2451         transform->setType(TRANSFORM_PRIMITIVE);
2452         transform->setScale(c_scale_identity);
2453         transform->setTranslation(c_translation_identity);
2454
2455         transform->setType(TRANSFORM_PRIMITIVE);
2456         transform->setScale(m_scale);
2457         {
2458           Editable* editable = Node_getEditable(instance.path().top());
2459           const Matrix4& localPivot = editable != 0 ? editable->getLocalPivot() : g_matrix4_identity;
2460     
2461           Vector3 parent_translation;
2462           translation_for_pivoted_scale(
2463             parent_translation,
2464             m_scale,
2465             m_world_pivot,
2466             matrix4_multiplied_by_matrix4(instance.localToWorld(), localPivot),
2467             matrix4_multiplied_by_matrix4(transformNode->localToParent(), localPivot)
2468           );
2469
2470           transform->setTranslation(parent_translation);
2471         }
2472       }
2473     }
2474   }
2475 };
2476
2477 void Scene_Scale_Selected(scene::Graph& graph, const Vector3& scaling, const Vector3& world_pivot)
2478 {
2479   if(GlobalSelectionSystem().countSelected() != 0)
2480   {
2481     GlobalSelectionSystem().foreachSelected(scale_selected(scaling, world_pivot));
2482   }
2483 }
2484
2485
2486 class translate_component_selected : public SelectionSystem::Visitor
2487 {
2488   const Vector3& m_translate;
2489 public:
2490   translate_component_selected(const Vector3& translate)
2491     : m_translate(translate)
2492   {
2493   }
2494   void visit(scene::Instance& instance) const
2495   {
2496     Transformable* transform = Instance_getTransformable(instance);
2497     if(transform != 0)
2498     {
2499       transform->setType(TRANSFORM_COMPONENT);
2500       transform->setTranslation(m_translate);
2501     }
2502   }
2503 };
2504
2505 void Scene_Translate_Component_Selected(scene::Graph& graph, const Vector3& translation)
2506 {
2507   if(GlobalSelectionSystem().countSelected() != 0)
2508   {
2509     GlobalSelectionSystem().foreachSelectedComponent(translate_component_selected(translation));
2510   }
2511 }
2512
2513 class rotate_component_selected : public SelectionSystem::Visitor
2514 {
2515   const Quaternion& m_rotate;
2516   const Vector3& m_world_pivot;
2517 public:
2518   rotate_component_selected(const Quaternion& rotation, const Vector3& world_pivot)
2519     : m_rotate(rotation), m_world_pivot(world_pivot)
2520   {
2521   }
2522   void visit(scene::Instance& instance) const
2523   {
2524     Transformable* transform = Instance_getTransformable(instance);
2525     if(transform != 0)
2526     {
2527       Vector3 parent_translation;
2528       translation_for_pivoted_rotation(parent_translation, m_rotate, m_world_pivot, instance.localToWorld(), Node_getTransformNode(instance.path().top())->localToParent());
2529
2530       transform->setType(TRANSFORM_COMPONENT);
2531       transform->setRotation(m_rotate);
2532       transform->setTranslation(parent_translation);
2533     }
2534   }
2535 };
2536
2537 void Scene_Rotate_Component_Selected(scene::Graph& graph, const Quaternion& rotation, const Vector3& world_pivot)
2538 {
2539   if(GlobalSelectionSystem().countSelectedComponents() != 0)
2540   {
2541     GlobalSelectionSystem().foreachSelectedComponent(rotate_component_selected(rotation, world_pivot));
2542   }
2543 }
2544
2545 class scale_component_selected : public SelectionSystem::Visitor
2546 {
2547   const Vector3& m_scale;
2548   const Vector3& m_world_pivot;
2549 public:
2550   scale_component_selected(const Vector3& scaling, const Vector3& world_pivot)
2551     : m_scale(scaling), m_world_pivot(world_pivot)
2552   {
2553   }
2554   void visit(scene::Instance& instance) const
2555   {
2556     Transformable* transform = Instance_getTransformable(instance);
2557     if(transform != 0)
2558     {
2559       Vector3 parent_translation;
2560       translation_for_pivoted_scale(parent_translation, m_scale, m_world_pivot, instance.localToWorld(), Node_getTransformNode(instance.path().top())->localToParent());
2561
2562       transform->setType(TRANSFORM_COMPONENT);
2563       transform->setScale(m_scale);
2564       transform->setTranslation(parent_translation);
2565     }
2566   }
2567 };
2568
2569 void Scene_Scale_Component_Selected(scene::Graph& graph, const Vector3& scaling, const Vector3& world_pivot)
2570 {
2571   if(GlobalSelectionSystem().countSelectedComponents() != 0)
2572   {
2573     GlobalSelectionSystem().foreachSelectedComponent(scale_component_selected(scaling, world_pivot));
2574   }
2575 }
2576
2577
2578 class BooleanSelector : public Selector
2579 {
2580   bool m_selected;
2581   SelectionIntersection m_intersection;
2582   Selectable* m_selectable;
2583 public:
2584   BooleanSelector() : m_selected(false)
2585   {
2586   }
2587
2588   void pushSelectable(Selectable& selectable)
2589   {
2590     m_intersection = SelectionIntersection();
2591     m_selectable = &selectable;
2592   }
2593   void popSelectable()
2594   {
2595     if(m_intersection.valid())
2596     {
2597       m_selected = true;
2598     }
2599     m_intersection = SelectionIntersection();
2600   }
2601   void addIntersection(const SelectionIntersection& intersection)
2602   {
2603     if(m_selectable->isSelected())
2604     {
2605       assign_if_closer(m_intersection, intersection);
2606     }
2607   }
2608
2609   bool isSelected()
2610   {
2611     return m_selected;
2612   }
2613 };
2614
2615 class BestSelector : public Selector
2616 {
2617   SelectionIntersection m_intersection;
2618   Selectable* m_selectable;
2619   SelectionIntersection m_bestIntersection;
2620   std::list<Selectable*> m_bestSelectable;
2621 public:
2622   BestSelector() : m_bestIntersection(SelectionIntersection()), m_bestSelectable(0)
2623   {
2624   }
2625
2626   void pushSelectable(Selectable& selectable)
2627   {
2628     m_intersection = SelectionIntersection();
2629     m_selectable = &selectable;
2630   }
2631   void popSelectable()
2632   {
2633     if(m_intersection.equalEpsilon(m_bestIntersection, 0.25f, 0.001f))
2634     {
2635       m_bestSelectable.push_back(m_selectable);
2636       m_bestIntersection = m_intersection;
2637     }
2638     else if(m_intersection < m_bestIntersection)
2639     {
2640       m_bestSelectable.clear();
2641       m_bestSelectable.push_back(m_selectable);
2642       m_bestIntersection = m_intersection;
2643     }
2644     m_intersection = SelectionIntersection();
2645   }
2646   void addIntersection(const SelectionIntersection& intersection)
2647   {
2648     assign_if_closer(m_intersection, intersection);
2649   }
2650
2651   std::list<Selectable*>& best()
2652   {
2653     return m_bestSelectable;
2654   }
2655 };
2656
2657 class DragManipulator : public Manipulator
2658 {
2659   TranslateFree m_freeResize;
2660   TranslateFree m_freeDrag;
2661   ResizeTranslatable m_resize;
2662   DragTranslatable m_drag;
2663   SelectableBool m_dragSelectable;
2664 public:
2665
2666   bool m_selected;
2667
2668   DragManipulator() : m_freeResize(m_resize), m_freeDrag(m_drag), m_selected(false)
2669   {
2670   }
2671
2672   Manipulatable* GetManipulatable()
2673   {
2674     return m_dragSelectable.isSelected() ? &m_freeDrag : &m_freeResize;
2675   }
2676
2677   void testSelect(const View& view, const Matrix4& pivot2world)
2678   {
2679     SelectionPool selector;
2680
2681     SelectionVolume test(view);
2682
2683     if(GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
2684     {
2685       BooleanSelector booleanSelector;
2686
2687       Scene_TestSelect_Primitive(booleanSelector, test, view);
2688
2689       if(booleanSelector.isSelected())
2690       {
2691         selector.addSelectable(SelectionIntersection(0, 0), &m_dragSelectable);
2692         m_selected = false;
2693       }
2694       else
2695       {
2696         m_selected = Scene_forEachPlaneSelectable_selectPlanes(GlobalSceneGraph(), selector, test);
2697       }
2698     }
2699     else
2700     {
2701       BestSelector bestSelector;
2702       Scene_TestSelect_Component_Selected(bestSelector, test, view, GlobalSelectionSystem().ComponentMode());
2703       for(std::list<Selectable*>::iterator i = bestSelector.best().begin(); i != bestSelector.best().end(); ++i)
2704       {
2705         if(!(*i)->isSelected())
2706         {
2707           GlobalSelectionSystem().setSelectedAllComponents(false);
2708         }
2709         m_selected = false;
2710         selector.addSelectable(SelectionIntersection(0, 0), (*i));
2711         m_dragSelectable.setSelected(true);
2712       }
2713     }
2714
2715     for(SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i)
2716     {
2717       (*i).second->setSelected(true);
2718     }
2719   }
2720   
2721   void setSelected(bool select)
2722   {
2723     m_selected = select;
2724     m_dragSelectable.setSelected(select);
2725   }
2726   bool isSelected() const
2727   {
2728     return m_selected || m_dragSelectable.isSelected();
2729   }
2730 };
2731
2732 class ClipManipulator : public Manipulator
2733 {
2734 public:
2735
2736   Manipulatable* GetManipulatable()
2737   {
2738     ERROR_MESSAGE("clipper is not manipulatable");
2739     return 0;
2740   }
2741
2742   void setSelected(bool select)
2743   {
2744   }
2745   bool isSelected() const
2746   {
2747     return false;
2748   }
2749 };
2750
2751 class select_all : public scene::Graph::Walker
2752 {
2753   bool m_select;
2754 public:
2755   select_all(bool select)
2756     : m_select(select)
2757   {
2758   }
2759   bool pre(const scene::Path& path, scene::Instance& instance) const
2760   {
2761     Selectable* selectable = Instance_getSelectable(instance);
2762     if(selectable != 0)
2763     {
2764       selectable->setSelected(m_select);
2765     }
2766     return true;
2767   }
2768 };
2769
2770 class select_all_component : public scene::Graph::Walker
2771 {
2772   bool m_select;
2773   SelectionSystem::EComponentMode m_mode;
2774 public:
2775   select_all_component(bool select, SelectionSystem::EComponentMode mode)
2776     : m_select(select), m_mode(mode)
2777   {
2778   }
2779   bool pre(const scene::Path& path, scene::Instance& instance) const
2780   {
2781     ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
2782     if(componentSelectionTestable)
2783     {
2784       componentSelectionTestable->setSelectedComponents(m_select, m_mode);
2785     }
2786     return true;
2787   }
2788 };
2789
2790 void Scene_SelectAll_Component(bool select, SelectionSystem::EComponentMode componentMode)
2791 {
2792   GlobalSceneGraph().traverse(select_all_component(select, componentMode));
2793 }
2794
2795
2796 // RadiantSelectionSystem
2797 class RadiantSelectionSystem :
2798   public SelectionSystem,
2799   public Translatable,
2800   public Rotatable,
2801   public Scalable,
2802   public Renderable
2803 {
2804   mutable Matrix4 m_pivot2world;
2805   Matrix4 m_pivot2world_start;
2806   Matrix4 m_manip2pivot_start;
2807   Translation m_translation;
2808   Rotation m_rotation;
2809   Scale m_scale;
2810 public:
2811   static Shader* m_state;
2812 private:
2813   EManipulatorMode m_manipulator_mode;
2814   Manipulator* m_manipulator;
2815
2816   // state
2817   bool m_undo_begun;
2818   EMode m_mode;
2819   EComponentMode m_componentmode;
2820
2821   SelectionCounter m_count_primitive;
2822   SelectionCounter m_count_component;
2823
2824   TranslateManipulator m_translate_manipulator;
2825   RotateManipulator m_rotate_manipulator;
2826   ScaleManipulator m_scale_manipulator;
2827   DragManipulator m_drag_manipulator;
2828   ClipManipulator m_clip_manipulator;
2829
2830   typedef SelectionList<scene::Instance> selection_t;
2831   selection_t m_selection;
2832   selection_t m_component_selection;
2833
2834   Signal1<const Selectable&> m_selectionChanged_callbacks;
2835
2836   void ConstructPivot() const;
2837   mutable bool m_pivotChanged;
2838   bool m_pivot_moving;
2839
2840   void Scene_TestSelect(Selector& selector, SelectionTest& test, const View& view, SelectionSystem::EMode mode, SelectionSystem::EComponentMode componentMode);
2841
2842   bool nothingSelected() const
2843   {
2844     return (Mode() == eComponent && m_count_component.empty())
2845       || (Mode() == ePrimitive && m_count_primitive.empty());
2846   }
2847
2848
2849 public:
2850   enum EModifier
2851   {
2852     eManipulator,
2853     eToggle,
2854     eReplace,
2855     eCycle,
2856   };
2857
2858   RadiantSelectionSystem() :
2859     m_undo_begun(false),
2860     m_mode(ePrimitive),
2861     m_componentmode(eDefault),
2862     m_count_primitive(SelectionChangedCaller(*this)),
2863     m_count_component(SelectionChangedCaller(*this)),
2864     m_translate_manipulator(*this, 2, 64),
2865     m_rotate_manipulator(*this, 8, 64),
2866     m_scale_manipulator(*this, 0, 64),
2867     m_pivotChanged(false),
2868     m_pivot_moving(false)
2869   {
2870     SetManipulatorMode(eTranslate);
2871     pivotChanged();
2872     addSelectionChangeCallback(PivotChangedSelectionCaller(*this));
2873     AddGridChangeCallback(PivotChangedCaller(*this));
2874   }
2875   void pivotChanged() const
2876   {
2877     m_pivotChanged = true;
2878     SceneChangeNotify();
2879   }
2880   typedef ConstMemberCaller<RadiantSelectionSystem, &RadiantSelectionSystem::pivotChanged> PivotChangedCaller;
2881   void pivotChangedSelection(const Selectable& selectable)
2882   {
2883     pivotChanged();
2884   }
2885   typedef MemberCaller1<RadiantSelectionSystem, const Selectable&, &RadiantSelectionSystem::pivotChangedSelection> PivotChangedSelectionCaller;
2886
2887   void SetMode(EMode mode)
2888   {
2889     if(m_mode != mode)
2890     {
2891       m_mode = mode;
2892       pivotChanged();
2893     }
2894   }
2895   EMode Mode() const
2896   {
2897     return m_mode;
2898   }
2899   void SetComponentMode(EComponentMode mode)
2900   {
2901     m_componentmode = mode;
2902   }
2903   EComponentMode ComponentMode() const
2904   {
2905     return m_componentmode;
2906   }
2907   void SetManipulatorMode(EManipulatorMode mode)
2908   {
2909     m_manipulator_mode = mode;
2910     switch(m_manipulator_mode)
2911     {
2912     case eTranslate: m_manipulator = &m_translate_manipulator; break;
2913     case eRotate: m_manipulator = &m_rotate_manipulator; break;
2914     case eScale: m_manipulator = &m_scale_manipulator; break;
2915     case eDrag: m_manipulator = &m_drag_manipulator; break;
2916     case eClip: m_manipulator = &m_clip_manipulator; break;
2917     }
2918     pivotChanged();
2919   }
2920   EManipulatorMode ManipulatorMode() const
2921   {
2922     return m_manipulator_mode;
2923   }
2924
2925   SelectionChangeCallback getObserver(EMode mode)
2926   {
2927     if(mode == ePrimitive)
2928     {
2929       return makeCallback1(m_count_primitive);
2930     }
2931     else
2932     {
2933       return makeCallback1(m_count_component);
2934     }
2935   }
2936   std::size_t countSelected() const
2937   {
2938     return m_count_primitive.size();
2939   }
2940   std::size_t countSelectedComponents() const
2941   {
2942     return m_count_component.size();
2943   }
2944   void onSelectedChanged(scene::Instance& instance, const Selectable& selectable)
2945   {
2946     if(selectable.isSelected())
2947     {
2948       m_selection.append(instance);
2949     }
2950     else
2951     {
2952       m_selection.erase(instance);
2953     }
2954
2955     ASSERT_MESSAGE(m_selection.size() == m_count_primitive.size(), "selection-tracking error");
2956   }
2957   void onComponentSelection(scene::Instance& instance, const Selectable& selectable)
2958   {
2959     if(selectable.isSelected())
2960     {
2961       m_component_selection.append(instance);
2962     }
2963     else
2964     {
2965       m_component_selection.erase(instance);
2966     }
2967
2968     ASSERT_MESSAGE(m_component_selection.size() == m_count_component.size(), "selection-tracking error");
2969   }
2970   scene::Instance& ultimateSelected() const
2971   {
2972     ASSERT_MESSAGE(m_selection.size() > 0, "no instance selected");
2973     return m_selection.back();
2974   }
2975   scene::Instance& penultimateSelected() const
2976   {
2977     ASSERT_MESSAGE(m_selection.size() > 1, "only one instance selected");
2978     return *(*(--(--m_selection.end())));
2979   }
2980   void setSelectedAll(bool selected)
2981   {
2982     GlobalSceneGraph().traverse(select_all(selected));
2983
2984     m_manipulator->setSelected(selected);
2985   }
2986   void setSelectedAllComponents(bool selected)
2987   {
2988     Scene_SelectAll_Component(selected, SelectionSystem::eVertex);
2989     Scene_SelectAll_Component(selected, SelectionSystem::eEdge);
2990     Scene_SelectAll_Component(selected, SelectionSystem::eFace);
2991
2992     m_manipulator->setSelected(selected);
2993   }
2994
2995   void foreachSelected(const Visitor& visitor) const
2996   {
2997     selection_t::const_iterator i = m_selection.begin();
2998     while(i != m_selection.end())
2999     {
3000       visitor.visit(*(*(i++)));
3001     }
3002   }
3003   void foreachSelectedComponent(const Visitor& visitor) const
3004   {
3005     selection_t::const_iterator i = m_component_selection.begin();
3006     while(i != m_component_selection.end())
3007     {
3008       visitor.visit(*(*(i++)));
3009     }
3010   }
3011
3012   void addSelectionChangeCallback(const SelectionChangeHandler& handler)
3013   {
3014     m_selectionChanged_callbacks.connectLast(handler);
3015   }
3016   void selectionChanged(const Selectable& selectable)
3017   {
3018     m_selectionChanged_callbacks(selectable);
3019   }
3020   typedef MemberCaller1<RadiantSelectionSystem, const Selectable&, &RadiantSelectionSystem::selectionChanged> SelectionChangedCaller;
3021
3022
3023   void startMove()
3024   {
3025     m_pivot2world_start = GetPivot2World();
3026   }
3027
3028   bool SelectManipulator(const View& view, const float device_point[2], const float device_epsilon[2])
3029   {
3030     if(!nothingSelected() || (ManipulatorMode() == eDrag && Mode() == eComponent))
3031     {
3032 #if defined (DEBUG_SELECTION)
3033       g_render_clipped.destroy();
3034 #endif
3035
3036       m_manipulator->setSelected(false);
3037
3038       if(!nothingSelected() || (ManipulatorMode() == eDrag && Mode() == eComponent))
3039       {
3040         View scissored(view);
3041         ConstructSelectionTest(scissored, SelectionBoxForPoint(device_point, device_epsilon));
3042         m_manipulator->testSelect(scissored, GetPivot2World());
3043       }
3044
3045       startMove();
3046
3047       m_pivot_moving = m_manipulator->isSelected();
3048
3049       if(m_pivot_moving)
3050       {
3051         Pivot2World pivot;
3052         pivot.update(GetPivot2World(), view.GetModelview(), view.GetProjection(), view.GetViewport());
3053
3054         m_manip2pivot_start = matrix4_multiplied_by_matrix4(matrix4_full_inverse(m_pivot2world_start), pivot.m_worldSpace);
3055
3056         Matrix4 device2manip;
3057         ConstructDevice2Manip(device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport());
3058         m_manipulator->GetManipulatable()->Construct(device2manip, device_point[0], device_point[1]);
3059
3060         m_undo_begun = false;
3061       }
3062
3063       SceneChangeNotify();
3064     }
3065
3066     return m_pivot_moving;
3067   }
3068
3069   void deselectAll()
3070   {
3071     if(Mode() == eComponent)
3072     {
3073       setSelectedAllComponents(false);
3074     }
3075     else
3076     {
3077       setSelectedAll(false);
3078     }
3079   }
3080
3081   void SelectPoint(const View& view, const float device_point[2], const float device_epsilon[2], RadiantSelectionSystem::EModifier modifier, bool face)
3082   {
3083     ASSERT_MESSAGE(fabs(device_point[0]) <= 1.0f && fabs(device_point[1]) <= 1.0f, "point-selection error");
3084     if(modifier == eReplace)
3085     {
3086       if(face)
3087       {
3088         setSelectedAllComponents(false);
3089       }
3090       else
3091       {
3092         deselectAll();
3093       }
3094     }
3095
3096   #if defined (DEBUG_SELECTION)
3097     g_render_clipped.destroy();
3098   #endif
3099
3100     {
3101       View scissored(view);
3102       ConstructSelectionTest(scissored, SelectionBoxForPoint(device_point, device_epsilon));
3103
3104       SelectionVolume volume(scissored);
3105       SelectionPool selector;
3106       if(face)
3107       {
3108         Scene_TestSelect_Component(selector, volume, scissored, eFace);
3109       }
3110       else
3111       {
3112         Scene_TestSelect(selector, volume, scissored, Mode(), ComponentMode());
3113       }
3114
3115       if(!selector.failed())
3116       {
3117         switch(modifier)
3118         {
3119         case RadiantSelectionSystem::eToggle:
3120           {
3121             SelectableSortedSet::iterator best = selector.begin();
3122             // toggle selection of the object with least depth
3123             if((*best).second->isSelected())
3124               (*best).second->setSelected(false);
3125             else
3126               (*best).second->setSelected(true);
3127           }
3128           break;
3129           // if cycle mode not enabled, enable it
3130         case RadiantSelectionSystem::eReplace:
3131           {
3132             // select closest
3133             (*selector.begin()).second->setSelected(true);
3134           }
3135           break;
3136           // select the next object in the list from the one already selected
3137         case RadiantSelectionSystem::eCycle:
3138           {
3139             SelectionPool::iterator i = selector.begin();
3140             while(i != selector.end())
3141             {
3142               if((*i).second->isSelected())
3143               {
3144                 (*i).second->setSelected(false);
3145                 ++i;
3146                 if(i != selector.end())
3147                 {
3148                   i->second->setSelected(true);
3149                 }
3150                 else
3151                 {
3152                   selector.begin()->second->setSelected(true);
3153                 }
3154                 break;
3155               }
3156               ++i;
3157             }
3158           }
3159           break;
3160         default:
3161           break;
3162         }
3163       }
3164     }
3165   } 
3166
3167   void SelectArea(const View& view, const float device_point[2], const float device_delta[2], RadiantSelectionSystem::EModifier modifier, bool face)
3168   {
3169     if(modifier == eReplace)
3170     {
3171       if(face)
3172       {
3173         setSelectedAllComponents(false);
3174       }
3175       else
3176       {
3177         deselectAll();
3178       }
3179     }
3180
3181   #if defined (DEBUG_SELECTION)
3182       g_render_clipped.destroy();
3183   #endif
3184
3185     {
3186       View scissored(view);
3187       ConstructSelectionTest(scissored, SelectionBoxForArea(device_point, device_delta));
3188
3189       SelectionVolume volume(scissored);
3190       SelectionPool pool;
3191       if(face)
3192       {
3193         Scene_TestSelect_Component(pool, volume, scissored, eFace);
3194       }
3195       else
3196       {
3197         Scene_TestSelect(pool, volume, scissored, Mode(), ComponentMode());
3198       }
3199
3200       for(SelectionPool::iterator i = pool.begin(); i != pool.end(); ++i)
3201       {
3202         (*i).second->setSelected(!(modifier == RadiantSelectionSystem::eToggle && (*i).second->isSelected()));
3203       }
3204     }
3205   }
3206
3207
3208   void translate(const Vector3& translation)
3209   {
3210     if(!nothingSelected())
3211     {
3212       //ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
3213
3214       m_translation = translation;
3215
3216       m_pivot2world = m_pivot2world_start;
3217       matrix4_translate_by_vec3(m_pivot2world, translation);
3218
3219       if(Mode() == eComponent)
3220       {
3221         Scene_Translate_Component_Selected(GlobalSceneGraph(), m_translation);
3222       }
3223       else
3224       {
3225         Scene_Translate_Selected(GlobalSceneGraph(), m_translation);
3226       }
3227
3228       SceneChangeNotify();
3229     }
3230   }
3231   void outputTranslation(TextOutputStream& ostream)
3232   {
3233     ostream << " -xyz " << m_translation.x() << " " << m_translation.y() << " " << m_translation.z();
3234   }
3235   void rotate(const Quaternion& rotation)
3236   {
3237     if(!nothingSelected())
3238     {
3239       //ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
3240       
3241       m_rotation = rotation;
3242
3243       if(Mode() == eComponent)
3244       {
3245         Scene_Rotate_Component_Selected(GlobalSceneGraph(), m_rotation, vector4_to_vector3(m_pivot2world.t()));
3246
3247         matrix4_assign_rotation_for_pivot(m_pivot2world, m_component_selection.back());
3248       }
3249       else
3250       {
3251         Scene_Rotate_Selected(GlobalSceneGraph(), m_rotation, vector4_to_vector3(m_pivot2world.t()));
3252
3253         matrix4_assign_rotation_for_pivot(m_pivot2world, m_selection.back());
3254       }
3255
3256       SceneChangeNotify();
3257     }
3258   }
3259   void outputRotation(TextOutputStream& ostream)
3260   {
3261     ostream << " -eulerXYZ " << m_rotation.x() << " " << m_rotation.y() << " " << m_rotation.z();
3262   }
3263   void scale(const Vector3& scaling)
3264   {
3265     if(!nothingSelected())
3266     {
3267       m_scale = scaling;
3268
3269       if(Mode() == eComponent)
3270       {
3271         Scene_Scale_Component_Selected(GlobalSceneGraph(), m_scale, vector4_to_vector3(m_pivot2world.t()));
3272       }
3273       else
3274       {
3275         Scene_Scale_Selected(GlobalSceneGraph(), m_scale, vector4_to_vector3(m_pivot2world.t()));
3276       }
3277
3278       SceneChangeNotify();
3279     }
3280   }
3281   void outputScale(TextOutputStream& ostream)
3282   {
3283     ostream << " -scale " << m_scale.x() << " " << m_scale.y() << " " << m_scale.z();
3284   }
3285
3286   void rotateSelected(const Quaternion& rotation)
3287   {
3288     startMove();
3289     rotate(rotation);
3290     freezeTransforms();
3291   }
3292   void translateSelected(const Vector3& translation)
3293   {
3294     startMove();
3295     translate(translation);
3296     freezeTransforms();
3297   }
3298   void scaleSelected(const Vector3& scaling)
3299   {
3300     startMove();
3301     scale(scaling);
3302     freezeTransforms();
3303   }
3304
3305   void MoveSelected(const View& view, const float device_point[2])
3306   {
3307     if(m_manipulator->isSelected())
3308     {
3309       if(!m_undo_begun)
3310       {
3311         m_undo_begun = true;
3312         GlobalUndoSystem().start();
3313       }
3314
3315       Matrix4 device2manip;
3316       ConstructDevice2Manip(device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport());
3317       m_manipulator->GetManipulatable()->Transform(m_manip2pivot_start, device2manip, device_point[0], device_point[1]);
3318     }
3319   }
3320
3321   /// \todo Support view-dependent nudge.
3322   void NudgeManipulator(const Vector3& nudge, const Vector3& view)
3323   {
3324     if(ManipulatorMode() == eTranslate || ManipulatorMode() == eDrag)
3325     {
3326       translateSelected(nudge);
3327     }
3328   }
3329
3330   void endMove();
3331   void freezeTransforms();
3332
3333   void renderSolid(Renderer& renderer, const VolumeTest& volume) const;
3334   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
3335   {
3336     renderSolid(renderer, volume);
3337   }
3338
3339   const Matrix4& GetPivot2World() const
3340   {
3341     ConstructPivot();
3342     return m_pivot2world;
3343   }
3344
3345   static void constructStatic()
3346   {
3347     m_state = GlobalShaderCache().capture("$POINT");
3348   #if defined(DEBUG_SELECTION)
3349     g_state_clipped = GlobalShaderCache().capture("$DEBUG_CLIPPED");
3350   #endif
3351     TranslateManipulator::m_state_wire = GlobalShaderCache().capture("$WIRE_OVERLAY");
3352     TranslateManipulator::m_state_fill = GlobalShaderCache().capture("$FLATSHADE_OVERLAY");
3353     RotateManipulator::m_state_outer = GlobalShaderCache().capture("$WIRE_OVERLAY");
3354   }
3355
3356   static void destroyStatic()
3357   {
3358   #if defined(DEBUG_SELECTION)
3359     GlobalShaderCache().release("$DEBUG_CLIPPED");
3360   #endif
3361     GlobalShaderCache().release("$WIRE_OVERLAY");
3362     GlobalShaderCache().release("$FLATSHADE_OVERLAY");
3363     GlobalShaderCache().release("$WIRE_OVERLAY");
3364     GlobalShaderCache().release("$POINT");
3365   }
3366 };
3367
3368 Shader* RadiantSelectionSystem::m_state = 0;
3369
3370
3371 namespace
3372 {
3373   RadiantSelectionSystem* g_RadiantSelectionSystem;
3374
3375   inline RadiantSelectionSystem& getSelectionSystem()
3376   {
3377     return *g_RadiantSelectionSystem;
3378   }
3379 }
3380
3381
3382
3383 class testselect_entity_visible : public scene::Graph::Walker
3384 {
3385   Selector& m_selector;
3386   SelectionTest& m_test;
3387 public:
3388   testselect_entity_visible(Selector& selector, SelectionTest& test)
3389     : m_selector(selector), m_test(test)
3390   {
3391   }
3392   bool pre(const scene::Path& path, scene::Instance& instance) const
3393   {
3394     Selectable* selectable = Instance_getSelectable(instance);
3395     if(selectable != 0
3396       && Node_isEntity(path.top()))
3397     {
3398       m_selector.pushSelectable(*selectable);
3399     }
3400
3401     SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
3402     if(selectionTestable)
3403     {
3404       selectionTestable->testSelect(m_selector, m_test);
3405     }
3406
3407     return true;
3408   }
3409   void post(const scene::Path& path, scene::Instance& instance) const
3410   {
3411     Selectable* selectable = Instance_getSelectable(instance);
3412     if(selectable != 0
3413       && Node_isEntity(path.top()))
3414     {
3415       m_selector.popSelectable();
3416     }
3417   }
3418 };
3419
3420 class testselect_primitive_visible : public scene::Graph::Walker
3421 {
3422   Selector& m_selector;
3423   SelectionTest& m_test;
3424 public:
3425   testselect_primitive_visible(Selector& selector, SelectionTest& test)
3426     : m_selector(selector), m_test(test)
3427   {
3428   }
3429   bool pre(const scene::Path& path, scene::Instance& instance) const
3430   {
3431     Selectable* selectable = Instance_getSelectable(instance);
3432     if(selectable != 0)
3433     {
3434       m_selector.pushSelectable(*selectable);
3435     }
3436
3437     SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
3438     if(selectionTestable)
3439     {
3440       selectionTestable->testSelect(m_selector, m_test);
3441     }
3442
3443     return true;
3444   }
3445   void post(const scene::Path& path, scene::Instance& instance) const
3446   {
3447     Selectable* selectable = Instance_getSelectable(instance);
3448     if(selectable != 0)
3449     {
3450       m_selector.popSelectable();
3451     }
3452   }
3453 };
3454
3455 class testselect_component_visible : public scene::Graph::Walker
3456 {
3457   Selector& m_selector;
3458   SelectionTest& m_test;
3459   SelectionSystem::EComponentMode m_mode;
3460 public:
3461   testselect_component_visible(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
3462     : m_selector(selector), m_test(test), m_mode(mode)
3463   {
3464   }
3465   bool pre(const scene::Path& path, scene::Instance& instance) const
3466   {
3467     ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
3468     if(componentSelectionTestable)
3469     {
3470       componentSelectionTestable->testSelectComponents(m_selector, m_test, m_mode);
3471     }
3472
3473     return true;
3474   }
3475 };
3476
3477
3478 class testselect_component_visible_selected : public scene::Graph::Walker
3479 {
3480   Selector& m_selector;
3481   SelectionTest& m_test;
3482   SelectionSystem::EComponentMode m_mode;
3483 public:
3484   testselect_component_visible_selected(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
3485     : m_selector(selector), m_test(test), m_mode(mode)
3486   {
3487   }
3488   bool pre(const scene::Path& path, scene::Instance& instance) const
3489   {
3490     Selectable* selectable = Instance_getSelectable(instance);
3491     if(selectable != 0 && selectable->isSelected())
3492     {
3493       ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable(instance);
3494       if(componentSelectionTestable)
3495       {
3496         componentSelectionTestable->testSelectComponents(m_selector, m_test, m_mode);
3497       }
3498     }
3499
3500     return true;
3501   }
3502 };
3503
3504 void Scene_TestSelect_Primitive(Selector& selector, SelectionTest& test, const VolumeTest& volume)
3505 {
3506   Scene_forEachVisible(GlobalSceneGraph(), volume, testselect_primitive_visible(selector, test));
3507 }
3508
3509 void Scene_TestSelect_Component_Selected(Selector& selector, SelectionTest& test, const VolumeTest& volume, SelectionSystem::EComponentMode componentMode)
3510 {
3511   Scene_forEachVisible(GlobalSceneGraph(), volume, testselect_component_visible_selected(selector, test, componentMode));
3512 }
3513
3514 void Scene_TestSelect_Component(Selector& selector, SelectionTest& test, const VolumeTest& volume, SelectionSystem::EComponentMode componentMode)
3515 {
3516   Scene_forEachVisible(GlobalSceneGraph(), volume, testselect_component_visible(selector, test, componentMode));
3517 }
3518
3519 void RadiantSelectionSystem::Scene_TestSelect(Selector& selector, SelectionTest& test, const View& view, SelectionSystem::EMode mode, SelectionSystem::EComponentMode componentMode)
3520 {
3521   switch(mode)
3522   {
3523   case eEntity:
3524     {
3525       Scene_forEachVisible(GlobalSceneGraph(), view, testselect_entity_visible(selector, test));
3526     }
3527     break;
3528   case ePrimitive:
3529     Scene_TestSelect_Primitive(selector, test, view);
3530     break;
3531   case eComponent:
3532     Scene_TestSelect_Component_Selected(selector, test, view, componentMode);
3533     break;
3534   }
3535 }
3536
3537 class FreezeTransforms : public scene::Graph::Walker
3538 {
3539 public:
3540   bool pre(const scene::Path& path, scene::Instance& instance) const
3541   {
3542     TransformNode* transformNode = Node_getTransformNode(path.top());
3543     if(transformNode != 0)
3544     {
3545       Transformable* transform = Instance_getTransformable(instance);
3546       if(transform != 0)
3547       {
3548         transform->freezeTransform(); 
3549       }
3550     }
3551     return true;
3552   }
3553 };
3554
3555 void RadiantSelectionSystem::freezeTransforms()
3556 {
3557   GlobalSceneGraph().traverse(FreezeTransforms());
3558 }
3559
3560
3561 void RadiantSelectionSystem::endMove()
3562 {
3563   freezeTransforms();
3564
3565   if(Mode() == ePrimitive)
3566   {
3567     if(ManipulatorMode() == eDrag)
3568     {
3569       Scene_SelectAll_Component(false, SelectionSystem::eFace);
3570     }
3571   }
3572
3573   m_pivot_moving = false;
3574   pivotChanged();
3575
3576   SceneChangeNotify();
3577
3578   if(m_undo_begun)
3579   {
3580     StringOutputStream command;
3581
3582     if(ManipulatorMode() == eTranslate)
3583     {
3584       command << "translateTool";
3585       outputTranslation(command);
3586     }
3587     else if(ManipulatorMode() == eRotate)
3588     {
3589       command << "rotateTool";
3590       outputRotation(command);
3591     }
3592     else if(ManipulatorMode() == eScale)
3593     {
3594       command << "scaleTool";
3595       outputScale(command);
3596     }
3597     else if(ManipulatorMode() == eDrag)
3598     {
3599       command << "dragTool";
3600     }
3601
3602     GlobalUndoSystem().finish(command.c_str());
3603   }
3604
3605 }
3606
3607 inline AABB Instance_getPivotBounds(scene::Instance& instance)
3608 {
3609   Entity* entity = Node_getEntity(instance.path().top());
3610   if(entity != 0
3611     && (entity->getEntityClass().fixedsize
3612     || !node_is_group(instance.path().top())))
3613   {
3614     Editable* editable = Node_getEditable(instance.path().top());
3615     if(editable != 0)
3616     {
3617       return AABB(vector4_to_vector3(matrix4_multiplied_by_matrix4(instance.localToWorld(), editable->getLocalPivot()).t()), Vector3(0, 0, 0));
3618     }
3619     else
3620     {
3621       return AABB(vector4_to_vector3(instance.localToWorld().t()), Vector3(0, 0, 0));
3622     }
3623   }
3624
3625   return instance.worldAABB();
3626 }
3627
3628 class bounds_selected : public scene::Graph::Walker
3629 {
3630   AABB& m_bounds;
3631 public:
3632   bounds_selected(AABB& bounds)
3633     : m_bounds(bounds)
3634   {
3635     m_bounds = AABB();
3636   }
3637   bool pre(const scene::Path& path, scene::Instance& instance) const
3638   {
3639     Selectable* selectable = Instance_getSelectable(instance);
3640     if(selectable != 0
3641       && selectable->isSelected())
3642     {
3643       aabb_extend_by_aabb_safe(m_bounds, Instance_getPivotBounds(instance));
3644     }
3645     return true;
3646   }
3647 };
3648
3649 class bounds_selected_component : public scene::Graph::Walker
3650 {
3651   AABB& m_bounds;
3652 public:
3653   bounds_selected_component(AABB& bounds)
3654     : m_bounds(bounds)
3655   {
3656     m_bounds = AABB();
3657   }
3658   bool pre(const scene::Path& path, scene::Instance& instance) const
3659   {
3660     Selectable* selectable = Instance_getSelectable(instance);
3661     if(selectable != 0
3662       && selectable->isSelected())
3663     {
3664       ComponentEditable* componentEditable = Instance_getComponentEditable(instance);
3665       if(componentEditable)
3666       {
3667         aabb_extend_by_aabb_safe(m_bounds, aabb_for_oriented_aabb_safe(componentEditable->getSelectedComponentsBounds(), instance.localToWorld()));
3668       }
3669     }
3670     return true;
3671   }
3672 };
3673
3674 void Scene_BoundsSelected(scene::Graph& graph, AABB& bounds)
3675 {
3676   graph.traverse(bounds_selected(bounds));
3677 }
3678
3679 void Scene_BoundsSelectedComponent(scene::Graph& graph, AABB& bounds)
3680 {
3681   graph.traverse(bounds_selected_component(bounds));
3682 }
3683
3684 #if 0
3685 inline void pivot_for_node(Matrix4& pivot, scene::Node& node, scene::Instance& instance)
3686 {
3687   ComponentEditable* componentEditable = Instance_getComponentEditable(instance);
3688   if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
3689     && componentEditable != 0)
3690   {
3691     pivot = matrix4_translation_for_vec3(componentEditable->getSelectedComponentsBounds().origin);
3692   }
3693   else
3694   {
3695     Bounded* bounded = Instance_getBounded(instance);
3696     if(bounded != 0)
3697     {
3698       pivot = matrix4_translation_for_vec3(bounded->localAABB().origin);
3699     }
3700     else
3701     {
3702       pivot = g_matrix4_identity;
3703     }
3704   }
3705 }
3706 #endif
3707
3708 void RadiantSelectionSystem::ConstructPivot() const
3709 {
3710   if(!m_pivotChanged || m_pivot_moving)
3711     return;
3712   m_pivotChanged = false;
3713
3714   Vector3 m_object_pivot;
3715
3716   if(!nothingSelected())
3717   {
3718     {
3719       AABB bounds;
3720       if(Mode() == eComponent)
3721       {
3722         Scene_BoundsSelectedComponent(GlobalSceneGraph(), bounds);
3723       }
3724       else
3725       {
3726         Scene_BoundsSelected(GlobalSceneGraph(), bounds);
3727       }
3728       m_object_pivot = bounds.origin;
3729     }
3730
3731     vector3_snap(m_object_pivot, GetGridSize());
3732     m_pivot2world = matrix4_translation_for_vec3(m_object_pivot);
3733
3734     switch(m_manipulator_mode)
3735     {
3736     case eTranslate:
3737       break;
3738     case eRotate:
3739       if(Mode() == eComponent)
3740       {
3741         matrix4_assign_rotation_for_pivot(m_pivot2world, m_component_selection.back());
3742       }
3743       else
3744       {
3745         matrix4_assign_rotation_for_pivot(m_pivot2world, m_selection.back());
3746       }
3747       break;
3748     case eScale:
3749       if(Mode() == eComponent)
3750       {
3751         matrix4_assign_rotation_for_pivot(m_pivot2world, m_component_selection.back());
3752       }
3753       else
3754       {
3755         matrix4_assign_rotation_for_pivot(m_pivot2world, m_selection.back());
3756       }
3757       break;
3758     default:
3759       break;
3760     }
3761   }
3762 }
3763
3764 void RadiantSelectionSystem::renderSolid(Renderer& renderer, const VolumeTest& volume) const
3765 {
3766   //if(view->TestPoint(m_object_pivot))
3767   if(!nothingSelected())
3768   {
3769     renderer.Highlight(Renderer::ePrimitive, false);
3770     renderer.Highlight(Renderer::eFace, false);
3771
3772     renderer.SetState(m_state, Renderer::eWireframeOnly);
3773     renderer.SetState(m_state, Renderer::eFullMaterials);
3774
3775     m_manipulator->render(renderer, volume, GetPivot2World());
3776   }
3777
3778 #if defined(DEBUG_SELECTION)
3779   renderer.SetState(g_state_clipped, Renderer::eWireframeOnly);
3780   renderer.SetState(g_state_clipped, Renderer::eFullMaterials);
3781   renderer.addRenderable(g_render_clipped, g_render_clipped.m_world);
3782 #endif
3783 }
3784
3785
3786 void SelectionSystem_OnBoundsChanged()
3787 {
3788   getSelectionSystem().pivotChanged();
3789 }
3790
3791
3792 SignalHandlerId SelectionSystem_boundsChanged;
3793
3794 void SelectionSystem_Construct()
3795 {
3796   RadiantSelectionSystem::constructStatic();
3797
3798   g_RadiantSelectionSystem = new RadiantSelectionSystem;
3799
3800   SelectionSystem_boundsChanged = GlobalSceneGraph().addBoundsChangedCallback(FreeCaller<SelectionSystem_OnBoundsChanged>());
3801
3802   GlobalShaderCache().attachRenderable(getSelectionSystem());
3803 }
3804
3805 void SelectionSystem_Destroy()
3806 {
3807   GlobalShaderCache().detachRenderable(getSelectionSystem());
3808
3809   GlobalSceneGraph().removeBoundsChangedCallback(SelectionSystem_boundsChanged);
3810
3811   delete g_RadiantSelectionSystem;
3812
3813   RadiantSelectionSystem::destroyStatic();
3814 }
3815
3816
3817
3818
3819 inline float screen_normalised(float pos, std::size_t size)
3820 {
3821   return ((2.0f * pos) / size) - 1.0f;
3822 }
3823
3824 typedef Vector2 DeviceVector;
3825
3826 inline DeviceVector window_to_normalised_device(WindowVector window, std::size_t width, std::size_t height)
3827 {
3828   return DeviceVector(screen_normalised(window.x(), width), screen_normalised(height - 1 - window.y(), height));
3829 }
3830
3831 inline float device_constrained(float pos)
3832 {
3833   return std::min(1.0f, std::max(-1.0f, pos));
3834 }
3835
3836 inline DeviceVector device_constrained(DeviceVector device)
3837 {
3838   return DeviceVector(device_constrained(device.x()), device_constrained(device.y()));
3839 }
3840
3841 inline float window_constrained(float pos, std::size_t origin, std::size_t size)
3842 {
3843   return std::min(static_cast<float>(origin + size), std::max(static_cast<float>(origin), pos));
3844 }
3845
3846 inline WindowVector window_constrained(WindowVector window, std::size_t x, std::size_t y, std::size_t width, std::size_t height)
3847 {
3848   return WindowVector(window_constrained(window.x(), x, width), window_constrained(window.y(), y, height));
3849 }
3850
3851 typedef Callback1<DeviceVector> MouseEventCallback;
3852
3853 Single<MouseEventCallback> g_mouseMovedCallback;
3854 Single<MouseEventCallback> g_mouseUpCallback;
3855
3856 #if 1
3857 const ButtonIdentifier c_button_select = c_buttonLeft;
3858 const ModifierFlags c_modifier_manipulator = c_modifierNone;
3859 const ModifierFlags c_modifier_toggle = c_modifierShift;
3860 const ModifierFlags c_modifier_replace = c_modifierShift | c_modifierAlt;
3861 const ModifierFlags c_modifier_face = c_modifierControl;
3862 #else
3863 const ButtonIdentifier c_button_select = c_buttonLeft;
3864 const ModifierFlags c_modifier_manipulator = c_modifierNone;
3865 const ModifierFlags c_modifier_toggle = c_modifierControl;
3866 const ModifierFlags c_modifier_replace = c_modifierNone;
3867 const ModifierFlags c_modifier_face = c_modifierShift;
3868 #endif
3869 const ModifierFlags c_modifier_toggle_face = c_modifier_toggle | c_modifier_face;
3870 const ModifierFlags c_modifier_replace_face = c_modifier_replace | c_modifier_face;
3871
3872 const ButtonIdentifier c_button_texture = c_buttonMiddle;
3873 const ModifierFlags c_modifier_apply_texture = c_modifierControl | c_modifierShift;
3874 const ModifierFlags c_modifier_copy_texture = c_modifierNone;
3875
3876 class Selector_
3877 {
3878   RadiantSelectionSystem::EModifier modifier_for_state(ModifierFlags state)
3879   {
3880     if(state == c_modifier_toggle || state == c_modifier_toggle_face)
3881     {
3882       return RadiantSelectionSystem::eToggle;
3883     }
3884     if(state == c_modifier_replace || state == c_modifier_replace_face)
3885     {
3886       return RadiantSelectionSystem::eReplace;
3887     }
3888     return RadiantSelectionSystem::eManipulator;
3889   }
3890
3891   rect_t getDeviceArea() const
3892   {
3893     DeviceVector delta(m_current - m_start);
3894     if(selecting() && fabs(delta.x()) > m_epsilon.x() && fabs(delta.y()) > m_epsilon.y())
3895     {
3896       return SelectionBoxForArea(&m_start[0], &delta[0]);
3897     }
3898     else
3899     {
3900       rect_t default_area = { { 0, 0, }, { 0, 0, }, };
3901       return default_area;
3902     }
3903   }
3904
3905 public:
3906   DeviceVector m_start;
3907   DeviceVector m_current;
3908   DeviceVector m_epsilon;
3909   std::size_t m_unmoved_replaces;
3910   ModifierFlags m_state;
3911   const View* m_view;
3912   RectangleCallback m_window_update;
3913
3914   Selector_() : m_start(0.0f, 0.0f), m_current(0.0f, 0.0f), m_unmoved_replaces(0), m_state(c_modifierNone)
3915   {
3916   }
3917
3918   void draw_area()
3919   {
3920     m_window_update(getDeviceArea());
3921   }
3922
3923   void testSelect(DeviceVector position)
3924   {
3925     RadiantSelectionSystem::EModifier modifier = modifier_for_state(m_state);
3926     if(modifier != RadiantSelectionSystem::eManipulator)
3927     {
3928       DeviceVector delta(position - m_start);
3929       if(fabs(delta.x()) > m_epsilon.x() && fabs(delta.y()) > m_epsilon.y())
3930       {
3931         DeviceVector delta(position - m_start);
3932         getSelectionSystem().SelectArea(*m_view, &m_start[0], &delta[0], modifier, (m_state & c_modifier_face) != c_modifierNone);
3933       }
3934       else
3935       {
3936         if(modifier == RadiantSelectionSystem::eReplace && m_unmoved_replaces++ > 0)
3937         {
3938           modifier = RadiantSelectionSystem::eCycle;
3939         }
3940         getSelectionSystem().SelectPoint(*m_view, &position[0], &m_epsilon[0], modifier, (m_state & c_modifier_face) != c_modifierNone);
3941       }
3942     }
3943
3944     m_start = m_current = DeviceVector(0.0f, 0.0f);
3945     draw_area();
3946   }
3947
3948   bool selecting() const
3949   {
3950     return m_state != c_modifier_manipulator;
3951   }
3952
3953   void setState(ModifierFlags state)
3954   {
3955     bool was_selecting = selecting();
3956     m_state = state;
3957     if(was_selecting ^ selecting())
3958     {
3959       draw_area();
3960     }
3961   }
3962
3963   ModifierFlags getState() const
3964   {
3965     return m_state;
3966   }
3967
3968   void modifierEnable(ModifierFlags type)
3969   {
3970     setState(bitfield_enable(getState(), type));
3971   }
3972   void modifierDisable(ModifierFlags type)
3973   {
3974     setState(bitfield_disable(getState(), type));
3975   }
3976
3977   void mouseDown(DeviceVector position)
3978   {
3979     m_start = m_current = device_constrained(position);
3980   }
3981
3982   void mouseMoved(DeviceVector position)
3983   {
3984     m_current = device_constrained(position);
3985     draw_area();
3986   }
3987   typedef MemberCaller1<Selector_, DeviceVector, &Selector_::mouseMoved> MouseMovedCaller;
3988
3989   void mouseUp(DeviceVector position)
3990   {
3991     testSelect(device_constrained(position));
3992
3993     g_mouseMovedCallback.clear();
3994     g_mouseUpCallback.clear();
3995   }
3996   typedef MemberCaller1<Selector_, DeviceVector, &Selector_::mouseUp> MouseUpCaller;
3997 };
3998
3999
4000 class Manipulator_
4001 {
4002 public:
4003   DeviceVector m_epsilon;
4004   const View* m_view;
4005
4006   bool mouseDown(DeviceVector position)
4007   {
4008     return getSelectionSystem().SelectManipulator(*m_view, &position[0], &m_epsilon[0]);
4009   }
4010
4011   void mouseMoved(DeviceVector position)
4012   {
4013     getSelectionSystem().MoveSelected(*m_view, &position[0]);
4014   }
4015   typedef MemberCaller1<Manipulator_, DeviceVector, &Manipulator_::mouseMoved> MouseMovedCaller;
4016
4017   void mouseUp(DeviceVector position)
4018   {
4019     getSelectionSystem().endMove();
4020     g_mouseMovedCallback.clear();
4021     g_mouseUpCallback.clear();
4022   }
4023   typedef MemberCaller1<Manipulator_, DeviceVector, &Manipulator_::mouseUp> MouseUpCaller;
4024 };
4025
4026 void Scene_copyClosestTexture(SelectionTest& test);
4027 void Scene_applyClosestTexture(SelectionTest& test);
4028
4029 class RadiantWindowObserver : public SelectionSystemWindowObserver
4030 {
4031   enum
4032   {
4033     SELECT_EPSILON = 8,
4034   };
4035
4036   int m_width;
4037   int m_height;
4038
4039   bool m_mouse_down;
4040
4041 public:
4042   Selector_ m_selector;
4043   Manipulator_ m_manipulator;
4044
4045   RadiantWindowObserver() : m_mouse_down(false)
4046   {
4047   }
4048   void release()
4049   {
4050     delete this;
4051   }
4052   void setView(const View& view)
4053   {
4054     m_selector.m_view = &view;
4055     m_manipulator.m_view = &view;
4056   }
4057   void setRectangleDrawCallback(const RectangleCallback& callback)
4058   {
4059     m_selector.m_window_update = callback;
4060   }
4061   void onSizeChanged(int width, int height)
4062   {
4063     m_width = width;
4064     m_height = height;
4065     DeviceVector epsilon(SELECT_EPSILON / static_cast<float>(m_width), SELECT_EPSILON / static_cast<float>(m_height));
4066     m_selector.m_epsilon = m_manipulator.m_epsilon = epsilon;
4067   }
4068   void onMouseDown(const WindowVector& position, ButtonIdentifier button, ModifierFlags modifiers)
4069   {
4070     if(button == c_button_select)
4071     {
4072       m_mouse_down = true;
4073
4074       DeviceVector devicePosition(window_to_normalised_device(position, m_width, m_height));
4075       if(modifiers == c_modifier_manipulator && m_manipulator.mouseDown(devicePosition))
4076       {
4077         g_mouseMovedCallback.insert(MouseEventCallback(Manipulator_::MouseMovedCaller(m_manipulator)));
4078         g_mouseUpCallback.insert(MouseEventCallback(Manipulator_::MouseUpCaller(m_manipulator)));
4079       }
4080       else
4081       {
4082         m_selector.mouseDown(devicePosition);
4083         g_mouseMovedCallback.insert(MouseEventCallback(Selector_::MouseMovedCaller(m_selector)));
4084         g_mouseUpCallback.insert(MouseEventCallback(Selector_::MouseUpCaller(m_selector)));
4085       }
4086     }
4087     else if(button == c_button_texture)
4088     {
4089       DeviceVector devicePosition(device_constrained(window_to_normalised_device(position, m_width, m_height)));
4090
4091       View scissored(*m_selector.m_view);
4092       ConstructSelectionTest(scissored, SelectionBoxForPoint(&devicePosition[0], &m_selector.m_epsilon[0]));
4093       SelectionVolume volume(scissored);
4094
4095       if(modifiers == c_modifier_apply_texture)
4096       {
4097         Scene_applyClosestTexture(volume);
4098       }
4099       else if(modifiers == c_modifier_copy_texture)
4100       {
4101         Scene_copyClosestTexture(volume);
4102       }
4103     }
4104   }
4105   void onMouseMotion(const WindowVector& position, ModifierFlags modifiers)
4106   {
4107     m_selector.m_unmoved_replaces = 0;
4108
4109     if(m_mouse_down && !g_mouseMovedCallback.empty())
4110     {
4111       g_mouseMovedCallback.get()(window_to_normalised_device(position, m_width, m_height));
4112     }
4113   }
4114   void onMouseUp(const WindowVector& position, ButtonIdentifier button, ModifierFlags modifiers)
4115   {
4116     if(button == c_button_select && !g_mouseUpCallback.empty())
4117     {
4118       m_mouse_down = false;
4119
4120       g_mouseUpCallback.get()(window_to_normalised_device(position, m_width, m_height));
4121     }
4122   }
4123   void onModifierDown(ModifierFlags type)
4124   {
4125     m_selector.modifierEnable(type);
4126   }
4127   void onModifierUp(ModifierFlags type)
4128   {
4129     m_selector.modifierDisable(type);
4130   }
4131 };
4132
4133
4134
4135 SelectionSystemWindowObserver* NewWindowObserver()
4136 {
4137   return new RadiantWindowObserver;
4138 }
4139
4140
4141
4142 #include "modulesystem/singletonmodule.h"
4143 #include "modulesystem/moduleregistry.h"
4144
4145 class SelectionDependencies :
4146   public GlobalSceneGraphModuleRef,
4147   public GlobalShaderCacheModuleRef,
4148   public GlobalOpenGLModuleRef
4149 {
4150 };
4151
4152 class SelectionAPI : public TypeSystemRef
4153 {
4154   SelectionSystem* m_selection;
4155 public:
4156   typedef SelectionSystem Type;
4157   STRING_CONSTANT(Name, "*");
4158
4159   SelectionAPI()
4160   {
4161     SelectionSystem_Construct();
4162
4163     m_selection = &getSelectionSystem();
4164   }
4165   ~SelectionAPI()
4166   {
4167     SelectionSystem_Destroy();
4168   }
4169   SelectionSystem* getTable()
4170   {
4171     return m_selection;
4172   }
4173 };
4174
4175 typedef SingletonModule<SelectionAPI, SelectionDependencies> SelectionModule;
4176 typedef Static<SelectionModule> StaticSelectionModule;
4177 StaticRegisterModule staticRegisterSelection(StaticSelectionModule::instance());