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