allow undo “make detail/structural”, <3 @SpiKe, thanks @Garux, fix #76
[xonotic/netradiant.git] / radiant / brush.h
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
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 #if !defined( INCLUDED_BRUSH_H )
23 #define INCLUDED_BRUSH_H
24
25 /// \file
26 /// \brief The brush primitive.
27 ///
28 /// A collection of planes that define a convex polyhedron.
29 /// The Boundary-Representation of this primitive is a manifold polygonal mesh.
30 /// Each face polygon is represented by a list of vertices in a \c Winding.
31 /// Each vertex is associated with another face that is adjacent to the edge
32 /// formed by itself and the next vertex in the winding. This information can
33 /// be used to find edge-pairs and vertex-rings.
34
35
36 #include "debugging/debugging.h"
37
38 #include "itexdef.h"
39 #include "iundo.h"
40 #include "iselection.h"
41 #include "irender.h"
42 #include "imap.h"
43 #include "ibrush.h"
44 #include "igl.h"
45 #include "ifilter.h"
46 #include "nameable.h"
47 #include "moduleobserver.h"
48
49 #include <set>
50
51 #include "cullable.h"
52 #include "renderable.h"
53 #include "selectable.h"
54 #include "editable.h"
55 #include "mapfile.h"
56
57 #include "math/frustum.h"
58 #include "selectionlib.h"
59 #include "render.h"
60 #include "texturelib.h"
61 #include "container/container.h"
62 #include "generic/bitfield.h"
63 #include "signal/signalfwd.h"
64
65 #include "winding.h"
66 #include "brush_primit.h"
67
68 const unsigned int BRUSH_DETAIL_FLAG = 27;
69 const unsigned int BRUSH_DETAIL_MASK = (1 << BRUSH_DETAIL_FLAG);
70
71 enum EBrushType {
72     eBrushTypeQuake,
73     eBrushTypeQuake2,
74     eBrushTypeQuake3,
75     eBrushTypeQuake3BP,
76     eBrushTypeDoom3,
77     eBrushTypeQuake4,
78     eBrushTypeHalfLife,
79 };
80
81
82 #define BRUSH_CONNECTIVITY_DEBUG 0
83 #define BRUSH_DEGENERATE_DEBUG 0
84
85 template<typename TextOuputStreamType>
86 inline TextOuputStreamType &ostream_write(TextOuputStreamType &ostream, const Matrix4 &m)
87 {
88     return ostream << "(" << m[0] << " " << m[1] << " " << m[2] << " " << m[3] << ", "
89                    << m[4] << " " << m[5] << " " << m[6] << " " << m[7] << ", "
90                    << m[8] << " " << m[9] << " " << m[10] << " " << m[11] << ", "
91                    << m[12] << " " << m[13] << " " << m[14] << " " << m[15] << ")";
92 }
93
94 inline void print_vector3(const Vector3 &v)
95 {
96     globalOutputStream() << "( " << v.x() << " " << v.y() << " " << v.z() << " )\n";
97 }
98
99 inline void print_3x3(const Matrix4 &m)
100 {
101     globalOutputStream() << "( " << m.xx() << " " << m.xy() << " " << m.xz() << " ) "
102                          << "( " << m.yx() << " " << m.yy() << " " << m.yz() << " ) "
103                          << "( " << m.zx() << " " << m.zy() << " " << m.zz() << " )\n";
104 }
105
106
107 inline bool texdef_sane(const texdef_t &texdef)
108 {
109     return fabs(texdef.shift[0]) < (1 << 16)
110            && fabs(texdef.shift[1]) < (1 << 16);
111 }
112
113 inline void Winding_DrawWireframe(const Winding &winding)
114 {
115     glVertexPointer(3, GL_FLOAT, sizeof(WindingVertex), &winding.points.data()->vertex);
116     glDrawArrays(GL_LINE_LOOP, 0, GLsizei(winding.numpoints));
117 }
118
119 inline void Winding_Draw(const Winding &winding, const Vector3 &normal, RenderStateFlags state)
120 {
121     glVertexPointer(3, GL_FLOAT, sizeof(WindingVertex), &winding.points.data()->vertex);
122
123     if ((state & RENDER_BUMP) != 0) {
124         Vector3 normals[c_brush_maxFaces];
125         typedef Vector3 *Vector3Iter;
126         for (Vector3Iter i = normals, end = normals + winding.numpoints; i != end; ++i) {
127             *i = normal;
128         }
129         if (GlobalShaderCache().useShaderLanguage()) {
130             glNormalPointer(GL_FLOAT, sizeof(Vector3), normals);
131             glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(WindingVertex),
132                                      &winding.points.data()->texcoord);
133             glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(WindingVertex),
134                                      &winding.points.data()->tangent);
135             glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(WindingVertex),
136                                      &winding.points.data()->bitangent);
137         } else {
138             glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(Vector3), normals);
139             glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(WindingVertex), &winding.points.data()->texcoord);
140             glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(WindingVertex), &winding.points.data()->tangent);
141             glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(WindingVertex), &winding.points.data()->bitangent);
142         }
143     } else {
144         if (state & RENDER_LIGHTING) {
145             Vector3 normals[c_brush_maxFaces];
146             typedef Vector3 *Vector3Iter;
147             for (Vector3Iter i = normals, last = normals + winding.numpoints; i != last; ++i) {
148                 *i = normal;
149             }
150             glNormalPointer(GL_FLOAT, sizeof(Vector3), normals);
151         }
152
153         if (state & RENDER_TEXTURE) {
154             glTexCoordPointer(2, GL_FLOAT, sizeof(WindingVertex), &winding.points.data()->texcoord);
155         }
156     }
157 #if 0
158                                                                                                                             if ( state & RENDER_FILL ) {
159                 glDrawArrays( GL_TRIANGLE_FAN, 0, GLsizei( winding.numpoints ) );
160         }
161         else
162         {
163                 glDrawArrays( GL_LINE_LOOP, 0, GLsizei( winding.numpoints ) );
164         }
165 #else
166     glDrawArrays(GL_POLYGON, 0, GLsizei(winding.numpoints));
167 #endif
168
169 #if 0
170                                                                                                                             const Winding& winding = winding;
171
172         if ( state & RENDER_FILL ) {
173                 glBegin( GL_POLYGON );
174         }
175         else
176         {
177                 glBegin( GL_LINE_LOOP );
178         }
179
180         if ( state & RENDER_LIGHTING ) {
181                 glNormal3fv( normal );
182         }
183
184         for ( int i = 0; i < winding.numpoints; ++i )
185         {
186                 if ( state & RENDER_TEXTURE ) {
187                         glTexCoord2fv( &winding.points[i][3] );
188                 }
189                 glVertex3fv( winding.points[i] );
190         }
191         glEnd();
192 #endif
193 }
194
195
196 #include "shaderlib.h"
197
198 typedef DoubleVector3 PlanePoints[3];
199
200 inline bool planepts_equal(const PlanePoints planepts, const PlanePoints other)
201 {
202     return planepts[0] == other[0] && planepts[1] == other[1] && planepts[2] == other[2];
203 }
204
205 inline void planepts_assign(PlanePoints planepts, const PlanePoints other)
206 {
207     planepts[0] = other[0];
208     planepts[1] = other[1];
209     planepts[2] = other[2];
210 }
211
212 inline void planepts_quantise(PlanePoints planepts, double snap)
213 {
214     vector3_snap(planepts[0], snap);
215     vector3_snap(planepts[1], snap);
216     vector3_snap(planepts[2], snap);
217 }
218
219 inline float vector3_max_component(const Vector3 &vec3)
220 {
221     return std::max(fabsf(vec3[0]), std::max(fabsf(vec3[1]), fabsf(vec3[2])));
222 }
223
224 inline void edge_snap(Vector3 &edge, double snap)
225 {
226     float scale = static_cast<float>( ceil(fabs(snap / vector3_max_component(edge))));
227     if (scale > 0.0f) {
228         vector3_scale(edge, scale);
229     }
230     vector3_snap(edge, snap);
231 }
232
233 inline void planepts_snap(PlanePoints planepts, double snap)
234 {
235     Vector3 edge01(vector3_subtracted(planepts[1], planepts[0]));
236     Vector3 edge12(vector3_subtracted(planepts[2], planepts[1]));
237     Vector3 edge20(vector3_subtracted(planepts[0], planepts[2]));
238
239     double length_squared_01 = vector3_dot(edge01, edge01);
240     double length_squared_12 = vector3_dot(edge12, edge12);
241     double length_squared_20 = vector3_dot(edge20, edge20);
242
243     vector3_snap(planepts[0], snap);
244
245     if (length_squared_01 < length_squared_12) {
246         if (length_squared_12 < length_squared_20) {
247             edge_snap(edge01, snap);
248             edge_snap(edge12, snap);
249             planepts[1] = vector3_added(planepts[0], edge01);
250             planepts[2] = vector3_added(planepts[1], edge12);
251         } else {
252             edge_snap(edge20, snap);
253             edge_snap(edge01, snap);
254             planepts[1] = vector3_added(planepts[0], edge20);
255             planepts[2] = vector3_added(planepts[1], edge01);
256         }
257     } else {
258         if (length_squared_01 < length_squared_20) {
259             edge_snap(edge01, snap);
260             edge_snap(edge12, snap);
261             planepts[1] = vector3_added(planepts[0], edge01);
262             planepts[2] = vector3_added(planepts[1], edge12);
263         } else {
264             edge_snap(edge12, snap);
265             edge_snap(edge20, snap);
266             planepts[1] = vector3_added(planepts[0], edge12);
267             planepts[2] = vector3_added(planepts[1], edge20);
268         }
269     }
270 }
271
272 inline PointVertex pointvertex_for_planept(const DoubleVector3 &point, const Colour4b &colour)
273 {
274     return PointVertex(
275             Vertex3f(
276                     static_cast<float>( point.x()),
277                     static_cast<float>( point.y()),
278                     static_cast<float>( point.z())
279             ),
280             colour
281     );
282 }
283
284 inline PointVertex pointvertex_for_windingpoint(const Vector3 &point, const Colour4b &colour)
285 {
286     return PointVertex(
287             vertex3f_for_vector3(point),
288             colour
289     );
290 }
291
292 inline bool check_plane_is_integer(const PlanePoints &planePoints)
293 {
294     return !float_is_integer(planePoints[0][0])
295            || !float_is_integer(planePoints[0][1])
296            || !float_is_integer(planePoints[0][2])
297            || !float_is_integer(planePoints[1][0])
298            || !float_is_integer(planePoints[1][1])
299            || !float_is_integer(planePoints[1][2])
300            || !float_is_integer(planePoints[2][0])
301            || !float_is_integer(planePoints[2][1])
302            || !float_is_integer(planePoints[2][2]);
303 }
304
305 inline void brush_check_shader(const char *name)
306 {
307     if (!shader_valid(name)) {
308         globalErrorStream() << "brush face has invalid texture name: '" << name << "'\n";
309     }
310 }
311
312 class FaceShaderObserver {
313 public:
314     virtual void realiseShader() = 0;
315
316     virtual void unrealiseShader() = 0;
317 };
318
319 typedef ReferencePair<FaceShaderObserver> FaceShaderObserverPair;
320
321
322 class ContentsFlagsValue {
323 public:
324     ContentsFlagsValue()
325     {
326     }
327
328     ContentsFlagsValue(int surfaceFlags, int contentFlags, int value, bool specified) :
329             m_surfaceFlags(surfaceFlags),
330             m_contentFlags(contentFlags),
331             m_value(value),
332             m_specified(specified)
333     {
334     }
335
336     int m_surfaceFlags;
337     int m_contentFlags;
338     int m_value;
339     bool m_specified;
340 };
341
342 inline void ContentsFlagsValue_assignMasked(ContentsFlagsValue &flags, const ContentsFlagsValue &other)
343 {
344     bool detail = bitfield_enabled(flags.m_contentFlags, BRUSH_DETAIL_MASK);
345     flags = other;
346     if (detail) {
347         flags.m_contentFlags = bitfield_enable(flags.m_contentFlags, BRUSH_DETAIL_MASK);
348     } else {
349         flags.m_contentFlags = bitfield_disable(flags.m_contentFlags, BRUSH_DETAIL_MASK);
350     }
351 }
352
353
354 class FaceShader : public ModuleObserver {
355 public:
356     class SavedState {
357     public:
358         CopiedString m_shader;
359         ContentsFlagsValue m_flags;
360
361         SavedState(const FaceShader &faceShader)
362         {
363             m_shader = faceShader.getShader();
364             m_flags = faceShader.m_flags;
365         }
366
367         void exportState(FaceShader &faceShader) const
368         {
369             faceShader.setShader(m_shader.c_str());
370             faceShader.m_flags = m_flags;
371         }
372     };
373
374     CopiedString m_shader;
375     Shader *m_state;
376     ContentsFlagsValue m_flags;
377     FaceShaderObserverPair m_observers;
378     bool m_instanced;
379     bool m_realised;
380
381     FaceShader(const char *shader, const ContentsFlagsValue &flags = ContentsFlagsValue(0, 0, 0, false)) :
382             m_shader(shader),
383             m_state(0),
384             m_flags(flags),
385             m_instanced(false),
386             m_realised(false)
387     {
388         captureShader();
389     }
390
391     ~FaceShader()
392     {
393         releaseShader();
394     }
395
396 // copy-construction not supported
397     FaceShader(const FaceShader &other);
398
399     void instanceAttach()
400     {
401         m_instanced = true;
402         m_state->incrementUsed();
403     }
404
405     void instanceDetach()
406     {
407         m_state->decrementUsed();
408         m_instanced = false;
409     }
410
411     void captureShader()
412     {
413         ASSERT_MESSAGE(m_state == 0, "shader cannot be captured");
414         brush_check_shader(m_shader.c_str());
415         m_state = GlobalShaderCache().capture(m_shader.c_str());
416         m_state->attach(*this);
417     }
418
419     void releaseShader()
420     {
421         ASSERT_MESSAGE(m_state != 0, "shader cannot be released");
422         m_state->detach(*this);
423         GlobalShaderCache().release(m_shader.c_str());
424         m_state = 0;
425     }
426
427     void realise()
428     {
429         ASSERT_MESSAGE(!m_realised, "FaceTexdef::realise: already realised");
430         m_realised = true;
431         m_observers.forEach([](FaceShaderObserver &observer) {
432             observer.realiseShader();
433         });
434     }
435
436     void unrealise()
437     {
438         ASSERT_MESSAGE(m_realised, "FaceTexdef::unrealise: already unrealised");
439         m_observers.forEach([](FaceShaderObserver &observer) {
440             observer.unrealiseShader();
441         });
442         m_realised = false;
443     }
444
445     void attach(FaceShaderObserver &observer)
446     {
447         m_observers.attach(observer);
448         if (m_realised) {
449             observer.realiseShader();
450         }
451     }
452
453     void detach(FaceShaderObserver &observer)
454     {
455         if (m_realised) {
456             observer.unrealiseShader();
457         }
458         m_observers.detach(observer);
459     }
460
461     const char *getShader() const
462     {
463         return m_shader.c_str();
464     }
465
466     void setShader(const char *name)
467     {
468         if (m_instanced) {
469             m_state->decrementUsed();
470         }
471         releaseShader();
472         m_shader = name;
473         captureShader();
474         if (m_instanced) {
475             m_state->incrementUsed();
476         }
477     }
478
479     ContentsFlagsValue getFlags() const
480     {
481         ASSERT_MESSAGE(m_realised, "FaceShader::getFlags: flags not valid when unrealised");
482         if (!m_flags.m_specified) {
483             return ContentsFlagsValue(
484                     m_state->getTexture().surfaceFlags,
485                     m_state->getTexture().contentFlags,
486                     m_state->getTexture().value,
487                     true
488             );
489         }
490         return m_flags;
491     }
492
493     void setFlags(const ContentsFlagsValue &flags)
494     {
495         ASSERT_MESSAGE(m_realised, "FaceShader::setFlags: flags not valid when unrealised");
496         ContentsFlagsValue_assignMasked(m_flags, flags);
497     }
498
499     Shader *state() const
500     {
501         return m_state;
502     }
503
504     std::size_t width() const
505     {
506         if (m_realised) {
507             return m_state->getTexture().width;
508         }
509         return 1;
510     }
511
512     std::size_t height() const
513     {
514         if (m_realised) {
515             return m_state->getTexture().height;
516         }
517         return 1;
518     }
519
520     unsigned int shaderFlags() const
521     {
522         if (m_realised) {
523             return m_state->getFlags();
524         }
525         return 0;
526     }
527 };
528
529
530 class FaceTexdef : public FaceShaderObserver {
531 // not copyable
532     FaceTexdef(const FaceTexdef &other);
533
534 // not assignable
535     FaceTexdef &operator=(const FaceTexdef &other);
536
537 public:
538     class SavedState {
539     public:
540         TextureProjection m_projection;
541
542         SavedState(const FaceTexdef &faceTexdef)
543         {
544             m_projection = faceTexdef.m_projection;
545         }
546
547         void exportState(FaceTexdef &faceTexdef) const
548         {
549             Texdef_Assign(faceTexdef.m_projection, m_projection);
550         }
551     };
552
553     FaceShader &m_shader;
554     TextureProjection m_projection;
555     bool m_projectionInitialised;
556     bool m_scaleApplied;
557
558     FaceTexdef(
559             FaceShader &shader,
560             const TextureProjection &projection,
561             bool projectionInitialised = true
562     ) :
563             m_shader(shader),
564             m_projection(projection),
565             m_projectionInitialised(projectionInitialised),
566             m_scaleApplied(false)
567     {
568         m_shader.attach(*this);
569     }
570
571     ~FaceTexdef()
572     {
573         m_shader.detach(*this);
574     }
575
576     void addScale()
577     {
578         ASSERT_MESSAGE(!m_scaleApplied, "texture scale aready added");
579         m_scaleApplied = true;
580         m_projection.m_brushprimit_texdef.addScale(m_shader.width(), m_shader.height());
581     }
582
583     void removeScale()
584     {
585         ASSERT_MESSAGE(m_scaleApplied, "texture scale aready removed");
586         m_scaleApplied = false;
587         m_projection.m_brushprimit_texdef.removeScale(m_shader.width(), m_shader.height());
588     }
589
590     void realiseShader()
591     {
592         if (m_projectionInitialised && !m_scaleApplied) {
593             addScale();
594         }
595     }
596
597     void unrealiseShader()
598     {
599         if (m_projectionInitialised && m_scaleApplied) {
600             removeScale();
601         }
602     }
603
604     void setTexdef(const TextureProjection &projection)
605     {
606         removeScale();
607         Texdef_Assign(m_projection, projection);
608         addScale();
609     }
610
611     void shift(float s, float t)
612     {
613         ASSERT_MESSAGE(texdef_sane(m_projection.m_texdef), "FaceTexdef::shift: bad texdef");
614         removeScale();
615         Texdef_Shift(m_projection, s, t);
616         addScale();
617     }
618
619     void scale(float s, float t)
620     {
621         removeScale();
622         Texdef_Scale(m_projection, s, t);
623         addScale();
624     }
625
626     void rotate(float angle)
627     {
628         removeScale();
629         Texdef_Rotate(m_projection, angle);
630         addScale();
631     }
632
633     void fit(const Vector3 &normal, const Winding &winding, float s_repeat, float t_repeat)
634     {
635         Texdef_FitTexture(m_projection, m_shader.width(), m_shader.height(), normal, winding, s_repeat, t_repeat);
636     }
637
638     void emitTextureCoordinates(Winding &winding, const Vector3 &normal, const Matrix4 &localToWorld)
639     {
640         Texdef_EmitTextureCoordinates(m_projection, m_shader.width(), m_shader.height(), winding, normal, localToWorld);
641     }
642
643     void transform(const Plane3 &plane, const Matrix4 &matrix)
644     {
645         removeScale();
646         Texdef_transformLocked(m_projection, m_shader.width(), m_shader.height(), plane, matrix);
647         addScale();
648     }
649
650     TextureProjection normalised() const
651     {
652         brushprimit_texdef_t tmp(m_projection.m_brushprimit_texdef);
653         tmp.removeScale(m_shader.width(), m_shader.height());
654         return TextureProjection(m_projection.m_texdef, tmp, m_projection.m_basis_s, m_projection.m_basis_t);
655     }
656
657     void setBasis(const Vector3 &normal)
658     {
659         Matrix4 basis;
660         Normal_GetTransform(normal, basis);
661         m_projection.m_basis_s = Vector3(basis.xx(), basis.yx(), basis.zx());
662         m_projection.m_basis_t = Vector3(-basis.xy(), -basis.yy(), -basis.zy());
663     }
664 };
665
666 inline void planepts_print(const PlanePoints &planePoints, TextOutputStream &ostream)
667 {
668     ostream << "( " << planePoints[0][0] << " " << planePoints[0][1] << " " << planePoints[0][2] << " ) "
669             << "( " << planePoints[1][0] << " " << planePoints[1][1] << " " << planePoints[1][2] << " ) "
670             << "( " << planePoints[2][0] << " " << planePoints[2][1] << " " << planePoints[2][2] << " )";
671 }
672
673
674 inline Plane3 Plane3_applyTranslation(const Plane3 &plane, const Vector3 &translation)
675 {
676     Plane3 tmp(plane3_translated(Plane3(plane.normal(), -plane.dist()), translation));
677     return Plane3(tmp.normal(), -tmp.dist());
678 }
679
680 inline Plane3 Plane3_applyTransform(const Plane3 &plane, const Matrix4 &matrix)
681 {
682     Plane3 tmp(plane3_transformed(Plane3(plane.normal(), -plane.dist()), matrix));
683     return Plane3(tmp.normal(), -tmp.dist());
684 }
685
686 class FacePlane {
687     PlanePoints m_planepts;
688     Plane3 m_planeCached;
689     Plane3 m_plane;
690 public:
691     Vector3 m_funcStaticOrigin;
692
693     static EBrushType m_type;
694
695     static bool isDoom3Plane()
696     {
697         return FacePlane::m_type == eBrushTypeDoom3 || FacePlane::m_type == eBrushTypeQuake4;
698     }
699
700     class SavedState {
701     public:
702         PlanePoints m_planepts;
703         Plane3 m_plane;
704
705         SavedState(const FacePlane &facePlane)
706         {
707             if (facePlane.isDoom3Plane()) {
708                 m_plane = facePlane.m_plane;
709             } else {
710                 planepts_assign(m_planepts, facePlane.planePoints());
711             }
712         }
713
714         void exportState(FacePlane &facePlane) const
715         {
716             if (facePlane.isDoom3Plane()) {
717                 facePlane.m_plane = m_plane;
718                 facePlane.updateTranslated();
719             } else {
720                 planepts_assign(facePlane.planePoints(), m_planepts);
721                 facePlane.MakePlane();
722             }
723         }
724     };
725
726     FacePlane() : m_funcStaticOrigin(0, 0, 0)
727     {
728     }
729
730     FacePlane(const FacePlane &other) : m_funcStaticOrigin(0, 0, 0)
731     {
732         if (!isDoom3Plane()) {
733             planepts_assign(m_planepts, other.m_planepts);
734             MakePlane();
735         } else {
736             m_plane = other.m_plane;
737             updateTranslated();
738         }
739     }
740
741     void MakePlane()
742     {
743         if (!isDoom3Plane()) {
744 #if 0
745                                                                                                                                     if ( check_plane_is_integer( m_planepts ) ) {
746                         globalErrorStream() << "non-integer planepts: ";
747                         planepts_print( m_planepts, globalErrorStream() );
748                         globalErrorStream() << "\n";
749                 }
750 #endif
751             m_planeCached = plane3_for_points(m_planepts);
752         }
753     }
754
755     void reverse()
756     {
757         if (!isDoom3Plane()) {
758             vector3_swap(m_planepts[0], m_planepts[2]);
759             MakePlane();
760         } else {
761             m_planeCached = plane3_flipped(m_plane);
762             updateSource();
763         }
764     }
765
766     void transform(const Matrix4 &matrix, bool mirror)
767     {
768         if (!isDoom3Plane()) {
769
770 #if 0
771             bool off = check_plane_is_integer( planePoints() );
772 #endif
773
774             matrix4_transform_point(matrix, m_planepts[0]);
775             matrix4_transform_point(matrix, m_planepts[1]);
776             matrix4_transform_point(matrix, m_planepts[2]);
777
778             if (mirror) {
779                 reverse();
780             }
781
782 #if 0
783                                                                                                                                     if ( check_plane_is_integer( planePoints() ) ) {
784                         if ( !off ) {
785                                 globalErrorStream() << "caused by transform\n";
786                         }
787                 }
788 #endif
789             MakePlane();
790         } else {
791             m_planeCached = Plane3_applyTransform(m_planeCached, matrix);
792             updateSource();
793         }
794     }
795
796     void offset(float offset)
797     {
798         if (!isDoom3Plane()) {
799             Vector3 move(vector3_scaled(m_planeCached.normal(), -offset));
800
801             vector3_subtract(m_planepts[0], move);
802             vector3_subtract(m_planepts[1], move);
803             vector3_subtract(m_planepts[2], move);
804
805             MakePlane();
806         } else {
807             m_planeCached.d += offset;
808             updateSource();
809         }
810     }
811
812     void updateTranslated()
813     {
814         m_planeCached = Plane3_applyTranslation(m_plane, m_funcStaticOrigin);
815     }
816
817     void updateSource()
818     {
819         m_plane = Plane3_applyTranslation(m_planeCached, vector3_negated(m_funcStaticOrigin));
820     }
821
822
823     PlanePoints &planePoints()
824     {
825         return m_planepts;
826     }
827
828     const PlanePoints &planePoints() const
829     {
830         return m_planepts;
831     }
832
833     const Plane3 &plane3() const
834     {
835         return m_planeCached;
836     }
837
838     void setDoom3Plane(const Plane3 &plane)
839     {
840         m_plane = plane;
841         updateTranslated();
842     }
843
844     const Plane3 &getDoom3Plane() const
845     {
846         return m_plane;
847     }
848
849     void copy(const FacePlane &other)
850     {
851         if (!isDoom3Plane()) {
852             planepts_assign(m_planepts, other.m_planepts);
853             MakePlane();
854         } else {
855             m_planeCached = other.m_plane;
856             updateSource();
857         }
858     }
859
860     void copy(const Vector3 &p0, const Vector3 &p1, const Vector3 &p2)
861     {
862         if (!isDoom3Plane()) {
863             m_planepts[0] = p0;
864             m_planepts[1] = p1;
865             m_planepts[2] = p2;
866             MakePlane();
867         } else {
868             m_planeCached = plane3_for_points(p2, p1, p0);
869             updateSource();
870         }
871     }
872 };
873
874 inline void Winding_testSelect(Winding &winding, SelectionTest &test, SelectionIntersection &best)
875 {
876     test.TestPolygon(VertexPointer(reinterpret_cast<VertexPointer::pointer>( &winding.points.data()->vertex ),
877                                    sizeof(WindingVertex)), winding.numpoints, best);
878 }
879
880 const double GRID_MIN = 0.125;
881
882 inline double quantiseInteger(double f)
883 {
884     return float_to_integer(f);
885 }
886
887 inline double quantiseFloating(double f)
888 {
889     return float_snapped(f, 1.f / (1 << 16));
890 }
891
892 typedef double ( *QuantiseFunc )(double f);
893
894 class Face;
895
896 class FaceFilter {
897 public:
898     virtual bool filter(const Face &face) const = 0;
899 };
900
901 bool face_filtered(Face &face);
902
903 void add_face_filter(FaceFilter &filter, int mask, bool invert = false);
904
905 void Brush_addTextureChangedCallback(const SignalHandler &callback);
906
907 void Brush_textureChanged();
908
909
910 extern bool g_brush_texturelock_enabled;
911
912 class FaceObserver {
913 public:
914     virtual void planeChanged() = 0;
915
916     virtual void connectivityChanged() = 0;
917
918     virtual void shaderChanged() = 0;
919
920     virtual void evaluateTransform() = 0;
921 };
922
923 class Face :
924         public OpenGLRenderable,
925         public Filterable,
926         public Undoable,
927         public FaceShaderObserver {
928     std::size_t m_refcount;
929
930     class SavedState : public UndoMemento {
931     public:
932         FacePlane::SavedState m_planeState;
933         FaceTexdef::SavedState m_texdefState;
934         FaceShader::SavedState m_shaderState;
935
936         SavedState(const Face &face) : m_planeState(face.getPlane()), m_texdefState(face.getTexdef()),
937                                        m_shaderState(face.getShader())
938         {
939         }
940
941         void exportState(Face &face) const
942         {
943             m_planeState.exportState(face.getPlane());
944             m_shaderState.exportState(face.getShader());
945             m_texdefState.exportState(face.getTexdef());
946         }
947
948         void release()
949         {
950             delete this;
951         }
952     };
953
954 public:
955     static QuantiseFunc m_quantise;
956     static EBrushType m_type;
957
958     PlanePoints m_move_planepts;
959     PlanePoints m_move_planeptsTransformed;
960 private:
961     FacePlane m_plane;
962     FacePlane m_planeTransformed;
963     FaceShader m_shader;
964     FaceTexdef m_texdef;
965     TextureProjection m_texdefTransformed;
966
967     Winding m_winding;
968     Vector3 m_centroid;
969     bool m_filtered;
970
971     FaceObserver *m_observer;
972     UndoObserver *m_undoable_observer;
973     MapFile *m_map;
974
975 // assignment not supported
976     Face &operator=(const Face &other);
977
978 // copy-construction not supported
979     Face(const Face &other);
980
981 public:
982
983     Face(FaceObserver *observer) :
984             m_refcount(0),
985             m_shader(texdef_name_default()),
986             m_texdef(m_shader, TextureProjection(), false),
987             m_filtered(false),
988             m_observer(observer),
989             m_undoable_observer(0),
990             m_map(0)
991     {
992         m_shader.attach(*this);
993         m_plane.copy(Vector3(0, 0, 0), Vector3(64, 0, 0), Vector3(0, 64, 0));
994         m_texdef.setBasis(m_plane.plane3().normal());
995         planeChanged();
996     }
997
998     Face(
999             const Vector3 &p0,
1000             const Vector3 &p1,
1001             const Vector3 &p2,
1002             const char *shader,
1003             const TextureProjection &projection,
1004             FaceObserver *observer
1005     ) :
1006             m_refcount(0),
1007             m_shader(shader),
1008             m_texdef(m_shader, projection),
1009             m_observer(observer),
1010             m_undoable_observer(0),
1011             m_map(0)
1012     {
1013         m_shader.attach(*this);
1014         m_plane.copy(p0, p1, p2);
1015         m_texdef.setBasis(m_plane.plane3().normal());
1016         planeChanged();
1017         updateFiltered();
1018     }
1019
1020     Face(const Face &other, FaceObserver *observer) :
1021             m_refcount(0),
1022             m_shader(other.m_shader.getShader(), other.m_shader.m_flags),
1023             m_texdef(m_shader, other.getTexdef().normalised()),
1024             m_observer(observer),
1025             m_undoable_observer(0),
1026             m_map(0)
1027     {
1028         m_shader.attach(*this);
1029         m_plane.copy(other.m_plane);
1030         planepts_assign(m_move_planepts, other.m_move_planepts);
1031         m_texdef.setBasis(m_plane.plane3().normal());
1032         planeChanged();
1033         updateFiltered();
1034     }
1035
1036     ~Face()
1037     {
1038         m_shader.detach(*this);
1039     }
1040
1041     void planeChanged()
1042     {
1043         revertTransform();
1044         m_observer->planeChanged();
1045     }
1046
1047     void realiseShader()
1048     {
1049         m_observer->shaderChanged();
1050     }
1051
1052     void unrealiseShader()
1053     {
1054     }
1055
1056     void instanceAttach(MapFile *map)
1057     {
1058         m_shader.instanceAttach();
1059         m_map = map;
1060         m_undoable_observer = GlobalUndoSystem().observer(this);
1061         GlobalFilterSystem().registerFilterable(*this);
1062     }
1063
1064     void instanceDetach(MapFile *map)
1065     {
1066         GlobalFilterSystem().unregisterFilterable(*this);
1067         m_undoable_observer = 0;
1068         GlobalUndoSystem().release(this);
1069         m_map = 0;
1070         m_shader.instanceDetach();
1071     }
1072
1073     void render(RenderStateFlags state) const
1074     {
1075         Winding_Draw(m_winding, m_planeTransformed.plane3().normal(), state);
1076     }
1077
1078     void updateFiltered()
1079     {
1080         m_filtered = face_filtered(*this);
1081     }
1082
1083     bool isFiltered() const
1084     {
1085         return m_filtered;
1086     }
1087
1088     void undoSave()
1089     {
1090         if (m_map != 0) {
1091             m_map->changed();
1092         }
1093         if (m_undoable_observer != 0) {
1094             m_undoable_observer->save(this);
1095         }
1096     }
1097
1098 // undoable
1099     UndoMemento *exportState() const
1100     {
1101         return new SavedState(*this);
1102     }
1103
1104     void importState(const UndoMemento *data)
1105     {
1106         undoSave();
1107
1108         static_cast<const SavedState *>( data )->exportState(*this);
1109
1110         planeChanged();
1111         m_observer->connectivityChanged();
1112         texdefChanged();
1113         m_observer->shaderChanged();
1114         updateFiltered();
1115     }
1116
1117     void IncRef()
1118     {
1119         ++m_refcount;
1120     }
1121
1122     void DecRef()
1123     {
1124         if (--m_refcount == 0) {
1125             delete this;
1126         }
1127     }
1128
1129     void flipWinding()
1130     {
1131         m_plane.reverse();
1132         planeChanged();
1133     }
1134
1135     bool intersectVolume(const VolumeTest &volume, const Matrix4 &localToWorld) const
1136     {
1137         return volume.TestPlane(Plane3(plane3().normal(), -plane3().dist()), localToWorld);
1138     }
1139
1140     void render(Renderer &renderer, const Matrix4 &localToWorld) const
1141     {
1142         renderer.SetState(m_shader.state(), Renderer::eFullMaterials);
1143         renderer.addRenderable(*this, localToWorld);
1144     }
1145
1146     void transform(const Matrix4 &matrix, bool mirror)
1147     {
1148         if (g_brush_texturelock_enabled) {
1149             Texdef_transformLocked(m_texdefTransformed, m_shader.width(), m_shader.height(), m_plane.plane3(), matrix);
1150         }
1151
1152         m_planeTransformed.transform(matrix, mirror);
1153
1154 #if 0
1155         ASSERT_MESSAGE( projectionaxis_for_normal( normal ) == projectionaxis_for_normal( plane3().normal() ), "bleh" );
1156 #endif
1157         m_observer->planeChanged();
1158
1159         if (g_brush_texturelock_enabled) {
1160             Brush_textureChanged();
1161         }
1162     }
1163
1164     void assign_planepts(const PlanePoints planepts)
1165     {
1166         m_planeTransformed.copy(planepts[0], planepts[1], planepts[2]);
1167         m_observer->planeChanged();
1168     }
1169
1170 /// \brief Reverts the transformable state of the brush to identity.
1171     void revertTransform()
1172     {
1173         m_planeTransformed = m_plane;
1174         planepts_assign(m_move_planeptsTransformed, m_move_planepts);
1175         m_texdefTransformed = m_texdef.m_projection;
1176     }
1177
1178     void freezeTransform()
1179     {
1180         undoSave();
1181         m_plane = m_planeTransformed;
1182         planepts_assign(m_move_planepts, m_move_planeptsTransformed);
1183         m_texdef.m_projection = m_texdefTransformed;
1184     }
1185
1186     void update_move_planepts_vertex(std::size_t index, PlanePoints planePoints)
1187     {
1188         std::size_t numpoints = getWinding().numpoints;
1189         ASSERT_MESSAGE(index < numpoints, "update_move_planepts_vertex: invalid index");
1190
1191         std::size_t opposite = Winding_Opposite(getWinding(), index);
1192         std::size_t adjacent = Winding_wrap(getWinding(), opposite + numpoints - 1);
1193         planePoints[0] = getWinding()[opposite].vertex;
1194         planePoints[1] = getWinding()[index].vertex;
1195         planePoints[2] = getWinding()[adjacent].vertex;
1196         // winding points are very inaccurate, so they must be quantised before using them to generate the face-plane
1197         planepts_quantise(planePoints, GRID_MIN);
1198     }
1199
1200     void snapto(float snap)
1201     {
1202         if (contributes()) {
1203 #if 0
1204                                                                                                                                     ASSERT_MESSAGE( plane3_valid( m_plane.plane3() ), "invalid plane before snap to grid" );
1205                 planepts_snap( m_plane.planePoints(), snap );
1206                 ASSERT_MESSAGE( plane3_valid( m_plane.plane3() ), "invalid plane after snap to grid" );
1207 #else
1208             PlanePoints planePoints;
1209             update_move_planepts_vertex(0, planePoints);
1210             vector3_snap(planePoints[0], snap);
1211             vector3_snap(planePoints[1], snap);
1212             vector3_snap(planePoints[2], snap);
1213             assign_planepts(planePoints);
1214             freezeTransform();
1215 #endif
1216             SceneChangeNotify();
1217             if (!plane3_valid(m_plane.plane3())) {
1218                 globalErrorStream() << "WARNING: invalid plane after snap to grid\n";
1219             }
1220         }
1221     }
1222
1223     void testSelect(SelectionTest &test, SelectionIntersection &best)
1224     {
1225         Winding_testSelect(m_winding, test, best);
1226     }
1227
1228     void testSelect_centroid(SelectionTest &test, SelectionIntersection &best)
1229     {
1230         test.TestPoint(m_centroid, best);
1231     }
1232
1233     void shaderChanged()
1234     {
1235         EmitTextureCoordinates();
1236         Brush_textureChanged();
1237         m_observer->shaderChanged();
1238         updateFiltered();
1239         planeChanged();
1240         SceneChangeNotify();
1241     }
1242
1243     const char *GetShader() const
1244     {
1245         return m_shader.getShader();
1246     }
1247
1248     void SetShader(const char *name)
1249     {
1250         undoSave();
1251         m_shader.setShader(name);
1252         shaderChanged();
1253     }
1254
1255     void revertTexdef()
1256     {
1257         m_texdefTransformed = m_texdef.m_projection;
1258     }
1259
1260     void texdefChanged()
1261     {
1262         revertTexdef();
1263         EmitTextureCoordinates();
1264         Brush_textureChanged();
1265     }
1266
1267     void GetTexdef(TextureProjection &projection) const
1268     {
1269         projection = m_texdef.normalised();
1270     }
1271
1272     void SetTexdef(const TextureProjection &projection)
1273     {
1274         undoSave();
1275         m_texdef.setTexdef(projection);
1276         texdefChanged();
1277     }
1278
1279     void GetFlags(ContentsFlagsValue &flags) const
1280     {
1281         flags = m_shader.getFlags();
1282     }
1283
1284     void SetFlags(const ContentsFlagsValue &flags)
1285     {
1286         undoSave();
1287         m_shader.setFlags(flags);
1288         m_observer->shaderChanged();
1289         updateFiltered();
1290     }
1291
1292     void ShiftTexdef(float s, float t)
1293     {
1294         undoSave();
1295         m_texdef.shift(s, t);
1296         texdefChanged();
1297     }
1298
1299     void ScaleTexdef(float s, float t)
1300     {
1301         undoSave();
1302         m_texdef.scale(s, t);
1303         texdefChanged();
1304     }
1305
1306     void RotateTexdef(float angle)
1307     {
1308         undoSave();
1309         m_texdef.rotate(angle);
1310         texdefChanged();
1311     }
1312
1313     void FitTexture(float s_repeat, float t_repeat)
1314     {
1315         undoSave();
1316         m_texdef.fit(m_plane.plane3().normal(), m_winding, s_repeat, t_repeat);
1317         texdefChanged();
1318     }
1319
1320     void EmitTextureCoordinates()
1321     {
1322         Texdef_EmitTextureCoordinates(m_texdefTransformed, m_shader.width(), m_shader.height(), m_winding,
1323                                       plane3().normal(), g_matrix4_identity);
1324     }
1325
1326
1327     const Vector3 &centroid() const
1328     {
1329         return m_centroid;
1330     }
1331
1332     void construct_centroid()
1333     {
1334         Winding_Centroid(m_winding, plane3(), m_centroid);
1335     }
1336
1337     const Winding &getWinding() const
1338     {
1339         return m_winding;
1340     }
1341
1342     Winding &getWinding()
1343     {
1344         return m_winding;
1345     }
1346
1347     const Plane3 &plane3() const
1348     {
1349         m_observer->evaluateTransform();
1350         return m_planeTransformed.plane3();
1351     }
1352
1353     FacePlane &getPlane()
1354     {
1355         return m_plane;
1356     }
1357
1358     const FacePlane &getPlane() const
1359     {
1360         return m_plane;
1361     }
1362
1363     FaceTexdef &getTexdef()
1364     {
1365         return m_texdef;
1366     }
1367
1368     const FaceTexdef &getTexdef() const
1369     {
1370         return m_texdef;
1371     }
1372
1373     FaceShader &getShader()
1374     {
1375         return m_shader;
1376     }
1377
1378     const FaceShader &getShader() const
1379     {
1380         return m_shader;
1381     }
1382
1383     bool isDetail() const
1384     {
1385         return (m_shader.m_flags.m_contentFlags & BRUSH_DETAIL_MASK) != 0;
1386     }
1387
1388     void setDetail(bool detail)
1389     {
1390         undoSave();
1391         if (detail && !isDetail()) {
1392             m_shader.m_flags.m_contentFlags |= BRUSH_DETAIL_MASK;
1393         } else if (!detail && isDetail()) {
1394             m_shader.m_flags.m_contentFlags &= ~BRUSH_DETAIL_MASK;
1395         }
1396         m_observer->shaderChanged();
1397     }
1398
1399     bool contributes() const
1400     {
1401         return m_winding.numpoints > 2;
1402     }
1403
1404     bool is_bounded() const
1405     {
1406         for (Winding::const_iterator i = m_winding.begin(); i != m_winding.end(); ++i) {
1407             if ((*i).adjacent == c_brush_maxFaces) {
1408                 return false;
1409             }
1410         }
1411         return true;
1412     }
1413 };
1414
1415
1416 class FaceVertexId {
1417     std::size_t m_face;
1418     std::size_t m_vertex;
1419
1420 public:
1421     FaceVertexId(std::size_t face, std::size_t vertex)
1422             : m_face(face), m_vertex(vertex)
1423     {
1424     }
1425
1426     std::size_t getFace() const
1427     {
1428         return m_face;
1429     }
1430
1431     std::size_t getVertex() const
1432     {
1433         return m_vertex;
1434     }
1435 };
1436
1437 typedef std::size_t faceIndex_t;
1438
1439 struct EdgeRenderIndices {
1440     RenderIndex first;
1441     RenderIndex second;
1442
1443     EdgeRenderIndices()
1444             : first(0), second(0)
1445     {
1446     }
1447
1448     EdgeRenderIndices(const RenderIndex _first, const RenderIndex _second)
1449             : first(_first), second(_second)
1450     {
1451     }
1452 };
1453
1454 struct EdgeFaces {
1455     faceIndex_t first;
1456     faceIndex_t second;
1457
1458     EdgeFaces()
1459             : first(c_brush_maxFaces), second(c_brush_maxFaces)
1460     {
1461     }
1462
1463     EdgeFaces(const faceIndex_t _first, const faceIndex_t _second)
1464             : first(_first), second(_second)
1465     {
1466     }
1467 };
1468
1469 class RenderableWireframe : public OpenGLRenderable {
1470 public:
1471     void render(RenderStateFlags state) const
1472     {
1473 #if 1
1474         glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_vertices->colour);
1475         glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_vertices->vertex);
1476         glDrawElements(GL_LINES, GLsizei(m_size << 1), RenderIndexTypeID, m_faceVertex.data());
1477 #else
1478                                                                                                                                 glBegin( GL_LINES );
1479         for ( std::size_t i = 0; i < m_size; ++i )
1480         {
1481                 glVertex3fv( &m_vertices[m_faceVertex[i].first].vertex.x );
1482                 glVertex3fv( &m_vertices[m_faceVertex[i].second].vertex.x );
1483         }
1484         glEnd();
1485 #endif
1486     }
1487
1488     Array<EdgeRenderIndices> m_faceVertex;
1489     std::size_t m_size;
1490     const PointVertex *m_vertices;
1491 };
1492
1493 class Brush;
1494
1495 typedef std::vector<Brush *> brush_vector_t;
1496
1497 class BrushFilter {
1498 public:
1499     virtual bool filter(const Brush &brush) const = 0;
1500 };
1501
1502 bool brush_filtered(Brush &brush);
1503
1504 void add_brush_filter(BrushFilter &filter, int mask, bool invert = false);
1505
1506
1507 /// \brief Returns true if 'self' takes priority when building brush b-rep.
1508 inline bool plane3_inside(const Plane3 &self, const Plane3 &other, bool selfIsLater)
1509 {
1510     if (vector3_equal_epsilon(self.normal(), other.normal(), 0.001)) {
1511         // same plane? prefer the one with smaller index
1512         if (self.dist() == other.dist()) {
1513             return selfIsLater;
1514         }
1515         return self.dist() < other.dist();
1516     }
1517     return true;
1518 }
1519
1520 typedef SmartPointer<Face> FaceSmartPointer;
1521 typedef std::vector<FaceSmartPointer> Faces;
1522
1523 /// \brief Returns the unique-id of the edge adjacent to \p faceVertex in the edge-pair for the set of \p faces.
1524 inline FaceVertexId next_edge(const Faces &faces, FaceVertexId faceVertex)
1525 {
1526     std::size_t adjacent_face = faces[faceVertex.getFace()]->getWinding()[faceVertex.getVertex()].adjacent;
1527     std::size_t adjacent_vertex = Winding_FindAdjacent(faces[adjacent_face]->getWinding(), faceVertex.getFace());
1528
1529     ASSERT_MESSAGE(adjacent_vertex != c_brush_maxFaces, "connectivity data invalid");
1530     if (adjacent_vertex == c_brush_maxFaces) {
1531         return faceVertex;
1532     }
1533
1534     return FaceVertexId(adjacent_face, adjacent_vertex);
1535 }
1536
1537 /// \brief Returns the unique-id of the vertex adjacent to \p faceVertex in the vertex-ring for the set of \p faces.
1538 inline FaceVertexId next_vertex(const Faces &faces, FaceVertexId faceVertex)
1539 {
1540     FaceVertexId nextEdge = next_edge(faces, faceVertex);
1541     return FaceVertexId(nextEdge.getFace(),
1542                         Winding_next(faces[nextEdge.getFace()]->getWinding(), nextEdge.getVertex()));
1543 }
1544
1545 class SelectableEdge {
1546     Vector3 getEdge() const
1547     {
1548         const Winding &winding = getFace().getWinding();
1549         return vector3_mid(winding[m_faceVertex.getVertex()].vertex,
1550                            winding[Winding_next(winding, m_faceVertex.getVertex())].vertex);
1551     }
1552
1553 public:
1554     Faces &m_faces;
1555     FaceVertexId m_faceVertex;
1556
1557     SelectableEdge(Faces &faces, FaceVertexId faceVertex)
1558             : m_faces(faces), m_faceVertex(faceVertex)
1559     {
1560     }
1561
1562     SelectableEdge &operator=(const SelectableEdge &other)
1563     {
1564         m_faceVertex = other.m_faceVertex;
1565         return *this;
1566     }
1567
1568     Face &getFace() const
1569     {
1570         return *m_faces[m_faceVertex.getFace()];
1571     }
1572
1573     void testSelect(SelectionTest &test, SelectionIntersection &best)
1574     {
1575         test.TestPoint(getEdge(), best);
1576     }
1577 };
1578
1579 class SelectableVertex {
1580     Vector3 getVertex() const
1581     {
1582         return getFace().getWinding()[m_faceVertex.getVertex()].vertex;
1583     }
1584
1585 public:
1586     Faces &m_faces;
1587     FaceVertexId m_faceVertex;
1588
1589     SelectableVertex(Faces &faces, FaceVertexId faceVertex)
1590             : m_faces(faces), m_faceVertex(faceVertex)
1591     {
1592     }
1593
1594     SelectableVertex &operator=(const SelectableVertex &other)
1595     {
1596         m_faceVertex = other.m_faceVertex;
1597         return *this;
1598     }
1599
1600     Face &getFace() const
1601     {
1602         return *m_faces[m_faceVertex.getFace()];
1603     }
1604
1605     void testSelect(SelectionTest &test, SelectionIntersection &best)
1606     {
1607         test.TestPoint(getVertex(), best);
1608     }
1609 };
1610
1611 class BrushObserver {
1612 public:
1613     virtual void reserve(std::size_t size) = 0;
1614
1615     virtual void clear() = 0;
1616
1617     virtual void push_back(Face &face) = 0;
1618
1619     virtual void pop_back() = 0;
1620
1621     virtual void erase(std::size_t index) = 0;
1622
1623     virtual void connectivityChanged() = 0;
1624
1625     virtual void edge_clear() = 0;
1626
1627     virtual void edge_push_back(SelectableEdge &edge) = 0;
1628
1629     virtual void vertex_clear() = 0;
1630
1631     virtual void vertex_push_back(SelectableVertex &vertex) = 0;
1632
1633     virtual void DEBUG_verify() const = 0;
1634 };
1635
1636 class BrushVisitor {
1637 public:
1638     virtual void visit(Face &face) const = 0;
1639 };
1640
1641 class Brush :
1642         public TransformNode,
1643         public Bounded,
1644         public Cullable,
1645         public Snappable,
1646         public Undoable,
1647         public FaceObserver,
1648         public Filterable,
1649         public Nameable,
1650         public BrushDoom3 {
1651 private:
1652     scene::Node *m_node;
1653     typedef UniqueSet<BrushObserver *> Observers;
1654     Observers m_observers;
1655     UndoObserver *m_undoable_observer;
1656     MapFile *m_map;
1657
1658 // state
1659     Faces m_faces;
1660 // ----
1661
1662 // cached data compiled from state
1663     Array<PointVertex> m_faceCentroidPoints;
1664     RenderablePointArray m_render_faces;
1665
1666     Array<PointVertex> m_uniqueVertexPoints;
1667     typedef std::vector<SelectableVertex> SelectableVertices;
1668     SelectableVertices m_select_vertices;
1669     RenderablePointArray m_render_vertices;
1670
1671     Array<PointVertex> m_uniqueEdgePoints;
1672     typedef std::vector<SelectableEdge> SelectableEdges;
1673     SelectableEdges m_select_edges;
1674     RenderablePointArray m_render_edges;
1675
1676     Array<EdgeRenderIndices> m_edge_indices;
1677     Array<EdgeFaces> m_edge_faces;
1678
1679     AABB m_aabb_local;
1680 // ----
1681
1682     Callback<void()> m_evaluateTransform;
1683     Callback<void()> m_boundsChanged;
1684
1685     mutable bool m_planeChanged;   // b-rep evaluation required
1686     mutable bool m_transformChanged;   // transform evaluation required
1687 // ----
1688
1689 public:
1690     STRING_CONSTANT(Name, "Brush");
1691
1692     Callback<void()> m_lightsChanged;
1693
1694 // static data
1695     static Shader *m_state_point;
1696 // ----
1697
1698     static EBrushType m_type;
1699     static double m_maxWorldCoord;
1700
1701     Brush(scene::Node &node, const Callback<void()> &evaluateTransform, const Callback<void()> &boundsChanged) :
1702             m_node(&node),
1703             m_undoable_observer(0),
1704             m_map(0),
1705             m_render_faces(m_faceCentroidPoints, GL_POINTS),
1706             m_render_vertices(m_uniqueVertexPoints, GL_POINTS),
1707             m_render_edges(m_uniqueEdgePoints, GL_POINTS),
1708             m_evaluateTransform(evaluateTransform),
1709             m_boundsChanged(boundsChanged),
1710             m_planeChanged(false),
1711             m_transformChanged(false)
1712     {
1713         planeChanged();
1714     }
1715
1716     Brush(const Brush &other, scene::Node &node, const Callback<void()> &evaluateTransform,
1717           const Callback<void()> &boundsChanged) :
1718             m_node(&node),
1719             m_undoable_observer(0),
1720             m_map(0),
1721             m_render_faces(m_faceCentroidPoints, GL_POINTS),
1722             m_render_vertices(m_uniqueVertexPoints, GL_POINTS),
1723             m_render_edges(m_uniqueEdgePoints, GL_POINTS),
1724             m_evaluateTransform(evaluateTransform),
1725             m_boundsChanged(boundsChanged),
1726             m_planeChanged(false),
1727             m_transformChanged(false)
1728     {
1729         copy(other);
1730     }
1731
1732     Brush(const Brush &other) :
1733             TransformNode(other),
1734             Bounded(other),
1735             Cullable(other),
1736             Snappable(),
1737             Undoable(other),
1738             FaceObserver(other),
1739             Filterable(other),
1740             Nameable(other),
1741             BrushDoom3(other),
1742             m_node(0),
1743             m_undoable_observer(0),
1744             m_map(0),
1745             m_render_faces(m_faceCentroidPoints, GL_POINTS),
1746             m_render_vertices(m_uniqueVertexPoints, GL_POINTS),
1747             m_render_edges(m_uniqueEdgePoints, GL_POINTS),
1748             m_planeChanged(false),
1749             m_transformChanged(false)
1750     {
1751         copy(other);
1752     }
1753
1754     ~Brush()
1755     {
1756         ASSERT_MESSAGE(m_observers.empty(), "Brush::~Brush: observers still attached");
1757     }
1758
1759 // assignment not supported
1760     Brush &operator=(const Brush &other);
1761
1762     void setDoom3GroupOrigin(const Vector3 &origin)
1763     {
1764         //globalOutputStream() << "func_static origin before: " << m_funcStaticOrigin << " after: " << origin << "\n";
1765         for (Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) {
1766             (*i)->getPlane().m_funcStaticOrigin = origin;
1767             (*i)->getPlane().updateTranslated();
1768             (*i)->planeChanged();
1769         }
1770         planeChanged();
1771     }
1772
1773     void attach(BrushObserver &observer)
1774     {
1775         for (Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) {
1776             observer.push_back(*(*i));
1777         }
1778
1779         for (SelectableEdges::iterator i = m_select_edges.begin(); i != m_select_edges.end(); ++i) {
1780             observer.edge_push_back(*i);
1781         }
1782
1783         for (SelectableVertices::iterator i = m_select_vertices.begin(); i != m_select_vertices.end(); ++i) {
1784             observer.vertex_push_back(*i);
1785         }
1786
1787         m_observers.insert(&observer);
1788     }
1789
1790     void detach(BrushObserver &observer)
1791     {
1792         m_observers.erase(&observer);
1793     }
1794
1795     void forEachFace(const BrushVisitor &visitor) const
1796     {
1797         for (Faces::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i) {
1798             visitor.visit(*(*i));
1799         }
1800     }
1801
1802     void forEachFace_instanceAttach(MapFile *map) const
1803     {
1804         for (Faces::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i) {
1805             (*i)->instanceAttach(map);
1806         }
1807     }
1808
1809     void forEachFace_instanceDetach(MapFile *map) const
1810     {
1811         for (Faces::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i) {
1812             (*i)->instanceDetach(map);
1813         }
1814     }
1815
1816     InstanceCounter m_instanceCounter;
1817
1818     void instanceAttach(const scene::Path &path)
1819     {
1820         if (++m_instanceCounter.m_count == 1) {
1821             m_map = path_find_mapfile(path.begin(), path.end());
1822             m_undoable_observer = GlobalUndoSystem().observer(this);
1823             GlobalFilterSystem().registerFilterable(*this);
1824             forEachFace_instanceAttach(m_map);
1825         } else {
1826             ASSERT_MESSAGE(path_find_mapfile(path.begin(), path.end()) == m_map,
1827                            "node is instanced across more than one file");
1828         }
1829     }
1830
1831     void instanceDetach(const scene::Path &path)
1832     {
1833         if (--m_instanceCounter.m_count == 0) {
1834             forEachFace_instanceDetach(m_map);
1835             GlobalFilterSystem().unregisterFilterable(*this);
1836             m_map = 0;
1837             m_undoable_observer = 0;
1838             GlobalUndoSystem().release(this);
1839         }
1840     }
1841
1842 // nameable
1843     const char *name() const
1844     {
1845         return "brush";
1846     }
1847
1848     void attach(const NameCallback &callback)
1849     {
1850     }
1851
1852     void detach(const NameCallback &callback)
1853     {
1854     }
1855
1856 // filterable
1857     void updateFiltered()
1858     {
1859         if (m_node != 0) {
1860             if (brush_filtered(*this)) {
1861                 m_node->enable(scene::Node::eFiltered);
1862             } else {
1863                 m_node->disable(scene::Node::eFiltered);
1864             }
1865         }
1866     }
1867
1868 // observer
1869     void planeChanged()
1870     {
1871         m_planeChanged = true;
1872         aabbChanged();
1873         m_lightsChanged();
1874     }
1875
1876     void shaderChanged()
1877     {
1878         updateFiltered();
1879         planeChanged();
1880     }
1881
1882     void evaluateBRep() const
1883     {
1884         if (m_planeChanged) {
1885             m_planeChanged = false;
1886             const_cast<Brush *>( this )->buildBRep();
1887         }
1888     }
1889
1890     void transformChanged()
1891     {
1892         m_transformChanged = true;
1893         planeChanged();
1894     }
1895
1896     typedef MemberCaller<Brush, void(), &Brush::transformChanged> TransformChangedCaller;
1897
1898     void evaluateTransform()
1899     {
1900         if (m_transformChanged) {
1901             m_transformChanged = false;
1902             revertTransform();
1903             m_evaluateTransform();
1904         }
1905     }
1906
1907     const Matrix4 &localToParent() const
1908     {
1909         return g_matrix4_identity;
1910     }
1911
1912     void aabbChanged()
1913     {
1914         m_boundsChanged();
1915     }
1916
1917     const AABB &localAABB() const
1918     {
1919         evaluateBRep();
1920         return m_aabb_local;
1921     }
1922
1923     VolumeIntersectionValue intersectVolume(const VolumeTest &test, const Matrix4 &localToWorld) const
1924     {
1925         return test.TestAABB(m_aabb_local, localToWorld);
1926     }
1927
1928     void renderComponents(SelectionSystem::EComponentMode mode, Renderer &renderer, const VolumeTest &volume,
1929                           const Matrix4 &localToWorld) const
1930     {
1931         switch (mode) {
1932             case SelectionSystem::eVertex:
1933                 renderer.addRenderable(m_render_vertices, localToWorld);
1934                 break;
1935             case SelectionSystem::eEdge:
1936                 renderer.addRenderable(m_render_edges, localToWorld);
1937                 break;
1938             case SelectionSystem::eFace:
1939                 renderer.addRenderable(m_render_faces, localToWorld);
1940                 break;
1941             default:
1942                 break;
1943         }
1944     }
1945
1946     void transform(const Matrix4 &matrix)
1947     {
1948         bool mirror = matrix4_handedness(matrix) == MATRIX4_LEFTHANDED;
1949
1950         for (Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) {
1951             (*i)->transform(matrix, mirror);
1952         }
1953     }
1954
1955     void snapto(float snap)
1956     {
1957         for (Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) {
1958             (*i)->snapto(snap);
1959         }
1960     }
1961
1962     void revertTransform()
1963     {
1964         for (Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) {
1965             (*i)->revertTransform();
1966         }
1967     }
1968
1969     void freezeTransform()
1970     {
1971         for (Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) {
1972             (*i)->freezeTransform();
1973         }
1974     }
1975
1976 /// \brief Returns the absolute index of the \p faceVertex.
1977     std::size_t absoluteIndex(FaceVertexId faceVertex)
1978     {
1979         std::size_t index = 0;
1980         for (std::size_t i = 0; i < faceVertex.getFace(); ++i) {
1981             index += m_faces[i]->getWinding().numpoints;
1982         }
1983         return index + faceVertex.getVertex();
1984     }
1985
1986     void appendFaces(const Faces &other)
1987     {
1988         clear();
1989         for (Faces::const_iterator i = other.begin(); i != other.end(); ++i) {
1990             push_back(*i);
1991         }
1992     }
1993
1994 /// \brief The undo memento for a brush stores only the list of face references - the faces are not copied.
1995     class BrushUndoMemento : public UndoMemento {
1996     public:
1997         BrushUndoMemento(const Faces &faces) : m_faces(faces)
1998         {
1999         }
2000
2001         void release()
2002         {
2003             delete this;
2004         }
2005
2006         Faces m_faces;
2007     };
2008
2009     void undoSave()
2010     {
2011         if (m_map != 0) {
2012             m_map->changed();
2013         }
2014         if (m_undoable_observer != 0) {
2015             m_undoable_observer->save(this);
2016         }
2017     }
2018
2019     UndoMemento *exportState() const
2020     {
2021         return new BrushUndoMemento(m_faces);
2022     }
2023
2024     void importState(const UndoMemento *state)
2025     {
2026         undoSave();
2027         appendFaces(static_cast<const BrushUndoMemento *>( state )->m_faces);
2028         planeChanged();
2029
2030         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2031             (*i)->DEBUG_verify();
2032         }
2033     }
2034
2035     bool isDetail()
2036     {
2037         return !m_faces.empty() && m_faces.front()->isDetail();
2038     }
2039
2040 /// \brief Appends a copy of \p face to the end of the face list.
2041     Face *addFace(const Face &face)
2042     {
2043         if (m_faces.size() == c_brush_maxFaces) {
2044             return 0;
2045         }
2046         undoSave();
2047         push_back(FaceSmartPointer(new Face(face, this)));
2048         m_faces.back()->setDetail(isDetail());
2049         planeChanged();
2050         return m_faces.back();
2051     }
2052
2053 /// \brief Appends a new face constructed from the parameters to the end of the face list.
2054     Face *addPlane(const Vector3 &p0, const Vector3 &p1, const Vector3 &p2, const char *shader,
2055                    const TextureProjection &projection)
2056     {
2057         if (m_faces.size() == c_brush_maxFaces) {
2058             return 0;
2059         }
2060         undoSave();
2061         push_back(FaceSmartPointer(new Face(p0, p1, p2, shader, projection, this)));
2062         m_faces.back()->setDetail(isDetail());
2063         planeChanged();
2064         return m_faces.back();
2065     }
2066
2067     static void constructStatic(EBrushType type)
2068     {
2069         m_type = type;
2070         Face::m_type = type;
2071         FacePlane::m_type = type;
2072
2073         g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_QUAKE;
2074         if (m_type == eBrushTypeQuake3BP || m_type == eBrushTypeDoom3 || m_type == eBrushTypeQuake4) {
2075             g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_BRUSHPRIMITIVES;
2076             // g_brush_texturelock_enabled = true; // bad idea, this overrides user setting
2077         } else if (m_type == eBrushTypeHalfLife) {
2078             g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_HALFLIFE;
2079             // g_brush_texturelock_enabled = true; // bad idea, this overrides user setting
2080         }
2081
2082         Face::m_quantise = (m_type == eBrushTypeQuake) ? quantiseInteger : quantiseFloating;
2083
2084         m_state_point = GlobalShaderCache().capture("$POINT");
2085     }
2086
2087     static void destroyStatic()
2088     {
2089         GlobalShaderCache().release("$POINT");
2090     }
2091
2092     std::size_t DEBUG_size()
2093     {
2094         return m_faces.size();
2095     }
2096
2097     typedef Faces::const_iterator const_iterator;
2098
2099     const_iterator begin() const
2100     {
2101         return m_faces.begin();
2102     }
2103
2104     const_iterator end() const
2105     {
2106         return m_faces.end();
2107     }
2108
2109     Face *back()
2110     {
2111         return m_faces.back();
2112     }
2113
2114     const Face *back() const
2115     {
2116         return m_faces.back();
2117     }
2118
2119     void reserve(std::size_t count)
2120     {
2121         m_faces.reserve(count);
2122         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2123             (*i)->reserve(count);
2124         }
2125     }
2126
2127     void push_back(Faces::value_type face)
2128     {
2129         m_faces.push_back(face);
2130         if (m_instanceCounter.m_count != 0) {
2131             m_faces.back()->instanceAttach(m_map);
2132         }
2133         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2134             (*i)->push_back(*face);
2135             (*i)->DEBUG_verify();
2136         }
2137     }
2138
2139     void pop_back()
2140     {
2141         if (m_instanceCounter.m_count != 0) {
2142             m_faces.back()->instanceDetach(m_map);
2143         }
2144         m_faces.pop_back();
2145         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2146             (*i)->pop_back();
2147             (*i)->DEBUG_verify();
2148         }
2149     }
2150
2151     void erase(std::size_t index)
2152     {
2153         if (m_instanceCounter.m_count != 0) {
2154             m_faces[index]->instanceDetach(m_map);
2155         }
2156         m_faces.erase(m_faces.begin() + index);
2157         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2158             (*i)->erase(index);
2159             (*i)->DEBUG_verify();
2160         }
2161     }
2162
2163     void connectivityChanged()
2164     {
2165         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2166             (*i)->connectivityChanged();
2167         }
2168     }
2169
2170
2171     void clear()
2172     {
2173         undoSave();
2174         if (m_instanceCounter.m_count != 0) {
2175             forEachFace_instanceDetach(m_map);
2176         }
2177         m_faces.clear();
2178         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2179             (*i)->clear();
2180             (*i)->DEBUG_verify();
2181         }
2182     }
2183
2184     std::size_t size() const
2185     {
2186         return m_faces.size();
2187     }
2188
2189     bool empty() const
2190     {
2191         return m_faces.empty();
2192     }
2193
2194 /// \brief Returns true if any face of the brush contributes to the final B-Rep.
2195     bool hasContributingFaces() const
2196     {
2197         for (const_iterator i = begin(); i != end(); ++i) {
2198             if ((*i)->contributes()) {
2199                 return true;
2200             }
2201         }
2202         return false;
2203     }
2204
2205 /// \brief Removes faces that do not contribute to the brush. This is useful for cleaning up after CSG operations on the brush.
2206 /// Note: removal of empty faces is not performed during direct brush manipulations, because it would make a manipulation irreversible if it created an empty face.
2207     void removeEmptyFaces()
2208     {
2209         evaluateBRep();
2210
2211         {
2212             std::size_t i = 0;
2213             while (i < m_faces.size()) {
2214                 if (!m_faces[i]->contributes()) {
2215                     erase(i);
2216                     planeChanged();
2217                 } else {
2218                     ++i;
2219                 }
2220             }
2221         }
2222     }
2223
2224 /// \brief Constructs \p winding from the intersection of \p plane with the other planes of the brush.
2225     void windingForClipPlane(Winding &winding, const Plane3 &plane) const
2226     {
2227         FixedWinding buffer[2];
2228         bool swap = false;
2229
2230         // get a poly that covers an effectively infinite area
2231         Winding_createInfinite(buffer[swap], plane, m_maxWorldCoord + 1);
2232
2233         // chop the poly by all of the other faces
2234         {
2235             for (std::size_t i = 0; i < m_faces.size(); ++i) {
2236                 const Face &clip = *m_faces[i];
2237
2238                 if (plane3_equal(clip.plane3(), plane)
2239                     || !plane3_valid(clip.plane3()) || !plane_unique(i)
2240                     || plane3_opposing(plane, clip.plane3())) {
2241                     continue;
2242                 }
2243
2244                 buffer[!swap].clear();
2245
2246 #if BRUSH_CONNECTIVITY_DEBUG
2247                 globalOutputStream() << "clip vs face: " << i << "\n";
2248 #endif
2249
2250                 {
2251                     // flip the plane, because we want to keep the back side
2252                     Plane3 clipPlane(vector3_negated(clip.plane3().normal()), -clip.plane3().dist());
2253                     Winding_Clip(buffer[swap], plane, clipPlane, i, buffer[!swap]);
2254                 }
2255
2256 #if BRUSH_CONNECTIVITY_DEBUG
2257                                                                                                                                         for ( FixedWinding::Points::iterator k = buffer[!swap].points.begin(), j = buffer[!swap].points.end() - 1; k != buffer[!swap].points.end(); j = k, ++k )
2258                         {
2259                                 if ( vector3_length_squared( vector3_subtracted( ( *k ).vertex, ( *j ).vertex ) ) < 1 ) {
2260                                         globalOutputStream() << "v: " << std::distance( buffer[!swap].points.begin(), j ) << " tiny edge adjacent to face " << ( *j ).adjacent << "\n";
2261                                 }
2262                         }
2263 #endif
2264
2265                 //ASSERT_MESSAGE(buffer[!swap].numpoints != 1, "created single-point winding");
2266
2267                 swap = !swap;
2268             }
2269         }
2270
2271         Winding_forFixedWinding(winding, buffer[swap]);
2272
2273 #if BRUSH_CONNECTIVITY_DEBUG
2274                                                                                                                                 Winding_printConnectivity( winding );
2275
2276         for ( Winding::iterator i = winding.begin(), j = winding.end() - 1; i != winding.end(); j = i, ++i )
2277         {
2278                 if ( vector3_length_squared( vector3_subtracted( ( *i ).vertex, ( *j ).vertex ) ) < 1 ) {
2279                         globalOutputStream() << "v: " << std::distance( winding.begin(), j ) << " tiny edge adjacent to face " << ( *j ).adjacent << "\n";
2280                 }
2281         }
2282 #endif
2283     }
2284
2285     void update_wireframe(RenderableWireframe &wire, const bool *faces_visible) const
2286     {
2287         wire.m_faceVertex.resize(m_edge_indices.size());
2288         wire.m_vertices = m_uniqueVertexPoints.data();
2289         wire.m_size = 0;
2290         for (std::size_t i = 0; i < m_edge_faces.size(); ++i) {
2291             if (faces_visible[m_edge_faces[i].first]
2292                 || faces_visible[m_edge_faces[i].second]) {
2293                 wire.m_faceVertex[wire.m_size++] = m_edge_indices[i];
2294             }
2295         }
2296     }
2297
2298
2299     void update_faces_wireframe(Array<PointVertex> &wire, const bool *faces_visible) const
2300     {
2301         std::size_t count = 0;
2302         for (std::size_t i = 0; i < m_faceCentroidPoints.size(); ++i) {
2303             if (faces_visible[i]) {
2304                 ++count;
2305             }
2306         }
2307
2308         wire.resize(count);
2309         Array<PointVertex>::iterator p = wire.begin();
2310         for (std::size_t i = 0; i < m_faceCentroidPoints.size(); ++i) {
2311             if (faces_visible[i]) {
2312                 *p++ = m_faceCentroidPoints[i];
2313             }
2314         }
2315     }
2316
2317 /// \brief Makes this brush a deep-copy of the \p other.
2318     void copy(const Brush &other)
2319     {
2320         for (Faces::const_iterator i = other.m_faces.begin(); i != other.m_faces.end(); ++i) {
2321             addFace(*(*i));
2322         }
2323         planeChanged();
2324     }
2325
2326 private:
2327     void edge_push_back(FaceVertexId faceVertex)
2328     {
2329         m_select_edges.push_back(SelectableEdge(m_faces, faceVertex));
2330         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2331             (*i)->edge_push_back(m_select_edges.back());
2332         }
2333     }
2334
2335     void edge_clear()
2336     {
2337         m_select_edges.clear();
2338         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2339             (*i)->edge_clear();
2340         }
2341     }
2342
2343     void vertex_push_back(FaceVertexId faceVertex)
2344     {
2345         m_select_vertices.push_back(SelectableVertex(m_faces, faceVertex));
2346         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2347             (*i)->vertex_push_back(m_select_vertices.back());
2348         }
2349     }
2350
2351     void vertex_clear()
2352     {
2353         m_select_vertices.clear();
2354         for (Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) {
2355             (*i)->vertex_clear();
2356         }
2357     }
2358
2359 /// \brief Returns true if the face identified by \p index is preceded by another plane that takes priority over it.
2360     bool plane_unique(std::size_t index) const
2361     {
2362         // duplicate plane
2363         for (std::size_t i = 0; i < m_faces.size(); ++i) {
2364             if (index != i && !plane3_inside(m_faces[index]->plane3(), m_faces[i]->plane3(), index < i)) {
2365                 return false;
2366             }
2367         }
2368         return true;
2369     }
2370
2371 /// \brief Removes edges that are smaller than the tolerance used when generating brush windings.
2372     void removeDegenerateEdges()
2373     {
2374         for (std::size_t i = 0; i < m_faces.size(); ++i) {
2375             Winding &winding = m_faces[i]->getWinding();
2376             for (Winding::iterator j = winding.begin(); j != winding.end();) {
2377                 std::size_t index = std::distance(winding.begin(), j);
2378                 std::size_t next = Winding_next(winding, index);
2379                 if (Edge_isDegenerate(winding[index].vertex, winding[next].vertex)) {
2380 #if BRUSH_DEGENERATE_DEBUG
2381                     globalOutputStream() << "Brush::buildWindings: face " << i << ": degenerate edge adjacent to " << winding[index].adjacent << "\n";
2382 #endif
2383                     Winding &other = m_faces[winding[index].adjacent]->getWinding();
2384                     std::size_t adjacent = Winding_FindAdjacent(other, i);
2385                     if (adjacent != c_brush_maxFaces) {
2386                         other.erase(other.begin() + adjacent);
2387                     }
2388                     winding.erase(j);
2389                 } else {
2390                     ++j;
2391                 }
2392             }
2393         }
2394     }
2395
2396 /// \brief Invalidates faces that have only two vertices in their winding, while preserving edge-connectivity information.
2397     void removeDegenerateFaces()
2398     {
2399         // save adjacency info for degenerate faces
2400         for (std::size_t i = 0; i < m_faces.size(); ++i) {
2401             Winding &degen = m_faces[i]->getWinding();
2402
2403             if (degen.numpoints == 2) {
2404 #if BRUSH_DEGENERATE_DEBUG
2405                 globalOutputStream() << "Brush::buildWindings: face " << i << ": degenerate winding adjacent to " << degen[0].adjacent << ", " << degen[1].adjacent << "\n";
2406 #endif
2407                 // this is an "edge" face, where the plane touches the edge of the brush
2408                 {
2409                     Winding &winding = m_faces[degen[0].adjacent]->getWinding();
2410                     std::size_t index = Winding_FindAdjacent(winding, i);
2411                     if (index != c_brush_maxFaces) {
2412 #if BRUSH_DEGENERATE_DEBUG
2413                         globalOutputStream() << "Brush::buildWindings: face " << degen[0].adjacent << ": remapping adjacent " << winding[index].adjacent << " to " << degen[1].adjacent << "\n";
2414 #endif
2415                         winding[index].adjacent = degen[1].adjacent;
2416                     }
2417                 }
2418
2419                 {
2420                     Winding &winding = m_faces[degen[1].adjacent]->getWinding();
2421                     std::size_t index = Winding_FindAdjacent(winding, i);
2422                     if (index != c_brush_maxFaces) {
2423 #if BRUSH_DEGENERATE_DEBUG
2424                         globalOutputStream() << "Brush::buildWindings: face " << degen[1].adjacent << ": remapping adjacent " << winding[index].adjacent << " to " << degen[0].adjacent << "\n";
2425 #endif
2426                         winding[index].adjacent = degen[0].adjacent;
2427                     }
2428                 }
2429
2430                 degen.resize(0);
2431             }
2432         }
2433     }
2434
2435 /// \brief Removes edges that have the same adjacent-face as their immediate neighbour.
2436     void removeDuplicateEdges()
2437     {
2438         // verify face connectivity graph
2439         for (std::size_t i = 0; i < m_faces.size(); ++i) {
2440             //if(m_faces[i]->contributes())
2441             {
2442                 Winding &winding = m_faces[i]->getWinding();
2443                 for (std::size_t j = 0; j != winding.numpoints;) {
2444                     std::size_t next = Winding_next(winding, j);
2445                     if (winding[j].adjacent == winding[next].adjacent) {
2446 #if BRUSH_DEGENERATE_DEBUG
2447                         globalOutputStream() << "Brush::buildWindings: face " << i << ": removed duplicate edge adjacent to face " << winding[j].adjacent << "\n";
2448 #endif
2449                         winding.erase(winding.begin() + next);
2450                     } else {
2451                         ++j;
2452                     }
2453                 }
2454             }
2455         }
2456     }
2457
2458 /// \brief Removes edges that do not have a matching pair in their adjacent-face.
2459     void verifyConnectivityGraph()
2460     {
2461         // verify face connectivity graph
2462         for (std::size_t i = 0; i < m_faces.size(); ++i) {
2463             //if(m_faces[i]->contributes())
2464             {
2465                 Winding &winding = m_faces[i]->getWinding();
2466                 for (Winding::iterator j = winding.begin(); j != winding.end();) {
2467 #if BRUSH_CONNECTIVITY_DEBUG
2468                     globalOutputStream() << "Brush::buildWindings: face " << i << ": adjacent to face " << ( *j ).adjacent << "\n";
2469 #endif
2470                     // remove unidirectional graph edges
2471                     if ((*j).adjacent == c_brush_maxFaces
2472                         || Winding_FindAdjacent(m_faces[(*j).adjacent]->getWinding(), i) == c_brush_maxFaces) {
2473 #if BRUSH_CONNECTIVITY_DEBUG
2474                         globalOutputStream() << "Brush::buildWindings: face " << i << ": removing unidirectional connectivity graph edge adjacent to face " << ( *j ).adjacent << "\n";
2475 #endif
2476                         winding.erase(j);
2477                     } else {
2478                         ++j;
2479                     }
2480                 }
2481             }
2482         }
2483     }
2484
2485 /// \brief Returns true if the brush is a finite volume. A brush without a finite volume extends past the maximum world bounds and is not valid.
2486     bool isBounded()
2487     {
2488         for (const_iterator i = begin(); i != end(); ++i) {
2489             if (!(*i)->is_bounded()) {
2490                 return false;
2491             }
2492         }
2493         return true;
2494     }
2495
2496 /// \brief Constructs the polygon windings for each face of the brush. Also updates the brush bounding-box and face texture-coordinates.
2497     bool buildWindings()
2498     {
2499
2500         {
2501             m_aabb_local = AABB();
2502
2503             for (std::size_t i = 0; i < m_faces.size(); ++i) {
2504                 Face &f = *m_faces[i];
2505
2506                 if (!plane3_valid(f.plane3()) || !plane_unique(i)) {
2507                     f.getWinding().resize(0);
2508                 } else {
2509 #if BRUSH_CONNECTIVITY_DEBUG
2510                     globalOutputStream() << "face: " << i << "\n";
2511 #endif
2512                     windingForClipPlane(f.getWinding(), f.plane3());
2513
2514                     // update brush bounds
2515                     const Winding &winding = f.getWinding();
2516                     for (Winding::const_iterator i = winding.begin(); i != winding.end(); ++i) {
2517                         aabb_extend_by_point_safe(m_aabb_local, (*i).vertex);
2518                     }
2519
2520                     // update texture coordinates
2521                     f.EmitTextureCoordinates();
2522                 }
2523             }
2524         }
2525
2526         bool degenerate = !isBounded();
2527
2528         if (!degenerate) {
2529             // clean up connectivity information.
2530             // these cleanups must be applied in a specific order.
2531             removeDegenerateEdges();
2532             removeDegenerateFaces();
2533             removeDuplicateEdges();
2534             verifyConnectivityGraph();
2535         }
2536
2537         return degenerate;
2538     }
2539
2540 /// \brief Constructs the face windings and updates anything that depends on them.
2541     void buildBRep();
2542 };
2543
2544
2545 class FaceInstance;
2546
2547 class FaceInstanceSet {
2548     typedef SelectionList<FaceInstance> FaceInstances;
2549     FaceInstances m_faceInstances;
2550 public:
2551     void insert(FaceInstance &faceInstance)
2552     {
2553         m_faceInstances.append(faceInstance);
2554     }
2555
2556     void erase(FaceInstance &faceInstance)
2557     {
2558         m_faceInstances.erase(faceInstance);
2559     }
2560
2561     template<typename Functor>
2562     void foreach(Functor functor)
2563     {
2564         for (FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) {
2565             functor(*(*i));
2566         }
2567     }
2568
2569     bool empty() const
2570     {
2571         return m_faceInstances.empty();
2572     }
2573
2574     FaceInstance &last() const
2575     {
2576         return m_faceInstances.back();
2577     }
2578 };
2579
2580 extern FaceInstanceSet g_SelectedFaceInstances;
2581
2582 typedef std::list<std::size_t> VertexSelection;
2583
2584 inline VertexSelection::iterator VertexSelection_find(VertexSelection &self, std::size_t value)
2585 {
2586     return std::find(self.begin(), self.end(), value);
2587 }
2588
2589 inline VertexSelection::const_iterator VertexSelection_find(const VertexSelection &self, std::size_t value)
2590 {
2591     return std::find(self.begin(), self.end(), value);
2592 }
2593
2594 inline VertexSelection::iterator VertexSelection_insert(VertexSelection &self, std::size_t value)
2595 {
2596     VertexSelection::iterator i = VertexSelection_find(self, value);
2597     if (i == self.end()) {
2598         self.push_back(value);
2599         return --self.end();
2600     }
2601     return i;
2602 }
2603
2604 inline void VertexSelection_erase(VertexSelection &self, std::size_t value)
2605 {
2606     VertexSelection::iterator i = VertexSelection_find(self, value);
2607     if (i != self.end()) {
2608         self.erase(i);
2609     }
2610 }
2611
2612 inline bool triangle_reversed(std::size_t x, std::size_t y, std::size_t z)
2613 {
2614     return !((x < y && y < z) || (z < x && x < y) || (y < z && z < x));
2615 }
2616
2617 template<typename Element>
2618 inline Vector3
2619 triangle_cross(const BasicVector3<Element> &x, const BasicVector3<Element> y, const BasicVector3<Element> &z)
2620 {
2621     return vector3_cross(y - x, z - x);
2622 }
2623
2624 template<typename Element>
2625 inline bool
2626 triangles_same_winding(const BasicVector3<Element> &x1, const BasicVector3<Element> y1, const BasicVector3<Element> &z1,
2627                        const BasicVector3<Element> &x2, const BasicVector3<Element> y2, const BasicVector3<Element> &z2)
2628 {
2629     return vector3_dot(triangle_cross(x1, y1, z1), triangle_cross(x2, y2, z2)) > 0;
2630 }
2631
2632
2633 typedef const Plane3 *PlanePointer;
2634 typedef PlanePointer *PlanesIterator;
2635
2636 class VectorLightList : public LightList {
2637     typedef std::vector<const RendererLight *> Lights;
2638     Lights m_lights;
2639 public:
2640     void addLight(const RendererLight &light)
2641     {
2642         m_lights.push_back(&light);
2643     }
2644
2645     void clear()
2646     {
2647         m_lights.clear();
2648     }
2649
2650     void evaluateLights() const
2651     {
2652     }
2653
2654     void lightsChanged() const
2655     {
2656     }
2657
2658     void forEachLight(const RendererLightCallback &callback) const
2659     {
2660         for (Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i) {
2661             callback(*(*i));
2662         }
2663     }
2664 };
2665
2666 class FaceInstance {
2667     Face *m_face;
2668     ObservedSelectable m_selectable;
2669     ObservedSelectable m_selectableVertices;
2670     ObservedSelectable m_selectableEdges;
2671     SelectionChangeCallback m_selectionChanged;
2672
2673     VertexSelection m_vertexSelection;
2674     VertexSelection m_edgeSelection;
2675
2676 public:
2677     mutable VectorLightList m_lights;
2678
2679     FaceInstance(Face &face, const SelectionChangeCallback &observer) :
2680             m_face(&face),
2681             m_selectable(SelectedChangedCaller(*this)),
2682             m_selectableVertices(observer),
2683             m_selectableEdges(observer),
2684             m_selectionChanged(observer)
2685     {
2686     }
2687
2688     FaceInstance(const FaceInstance &other) :
2689             m_face(other.m_face),
2690             m_selectable(SelectedChangedCaller(*this)),
2691             m_selectableVertices(other.m_selectableVertices),
2692             m_selectableEdges(other.m_selectableEdges),
2693             m_selectionChanged(other.m_selectionChanged)
2694     {
2695     }
2696
2697     FaceInstance &operator=(const FaceInstance &other)
2698     {
2699         m_face = other.m_face;
2700         return *this;
2701     }
2702
2703     Face &getFace()
2704     {
2705         return *m_face;
2706     }
2707
2708     const Face &getFace() const
2709     {
2710         return *m_face;
2711     }
2712
2713     void selectedChanged(const Selectable &selectable)
2714     {
2715         if (selectable.isSelected()) {
2716             g_SelectedFaceInstances.insert(*this);
2717         } else {
2718             g_SelectedFaceInstances.erase(*this);
2719         }
2720         m_selectionChanged(selectable);
2721     }
2722
2723     typedef MemberCaller<FaceInstance, void(const Selectable &), &FaceInstance::selectedChanged> SelectedChangedCaller;
2724
2725     bool selectedVertices() const
2726     {
2727         return !m_vertexSelection.empty();
2728     }
2729
2730     bool selectedEdges() const
2731     {
2732         return !m_edgeSelection.empty();
2733     }
2734
2735     bool isSelected() const
2736     {
2737         return m_selectable.isSelected();
2738     }
2739
2740     bool selectedComponents() const
2741     {
2742         return selectedVertices() || selectedEdges() || isSelected();
2743     }
2744
2745     bool selectedComponents(SelectionSystem::EComponentMode mode) const
2746     {
2747         switch (mode) {
2748             case SelectionSystem::eVertex:
2749                 return selectedVertices();
2750             case SelectionSystem::eEdge:
2751                 return selectedEdges();
2752             case SelectionSystem::eFace:
2753                 return isSelected();
2754             default:
2755                 return false;
2756         }
2757     }
2758
2759     void setSelected(SelectionSystem::EComponentMode mode, bool select)
2760     {
2761         switch (mode) {
2762             case SelectionSystem::eFace:
2763                 m_selectable.setSelected(select);
2764                 break;
2765             case SelectionSystem::eVertex:
2766                 ASSERT_MESSAGE(!select, "select-all not supported");
2767
2768                 m_vertexSelection.clear();
2769                 m_selectableVertices.setSelected(false);
2770                 break;
2771             case SelectionSystem::eEdge:
2772                 ASSERT_MESSAGE(!select, "select-all not supported");
2773
2774                 m_edgeSelection.clear();
2775                 m_selectableEdges.setSelected(false);
2776                 break;
2777             default:
2778                 break;
2779         }
2780     }
2781
2782     template<typename Functor>
2783     void SelectedVertices_foreach(Functor functor) const
2784     {
2785         for (VertexSelection::const_iterator i = m_vertexSelection.begin(); i != m_vertexSelection.end(); ++i) {
2786             std::size_t index = Winding_FindAdjacent(getFace().getWinding(), *i);
2787             if (index != c_brush_maxFaces) {
2788                 functor(getFace().getWinding()[index].vertex);
2789             }
2790         }
2791     }
2792
2793     template<typename Functor>
2794     void SelectedEdges_foreach(Functor functor) const
2795     {
2796         for (VertexSelection::const_iterator i = m_edgeSelection.begin(); i != m_edgeSelection.end(); ++i) {
2797             std::size_t index = Winding_FindAdjacent(getFace().getWinding(), *i);
2798             if (index != c_brush_maxFaces) {
2799                 const Winding &winding = getFace().getWinding();
2800                 std::size_t adjacent = Winding_next(winding, index);
2801                 functor(vector3_mid(winding[index].vertex, winding[adjacent].vertex));
2802             }
2803         }
2804     }
2805
2806     template<typename Functor>
2807     void SelectedFaces_foreach(Functor functor) const
2808     {
2809         if (isSelected()) {
2810             functor(centroid());
2811         }
2812     }
2813
2814     template<typename Functor>
2815     void SelectedComponents_foreach(Functor functor) const
2816     {
2817         SelectedVertices_foreach(functor);
2818         SelectedEdges_foreach(functor);
2819         SelectedFaces_foreach(functor);
2820     }
2821
2822     void iterate_selected(AABB &aabb) const
2823     {
2824         SelectedComponents_foreach([&](const Vector3 &point) {
2825             aabb_extend_by_point_safe(aabb, point);
2826         });
2827     }
2828
2829     void iterate_selected(RenderablePointVector &points) const
2830     {
2831         SelectedComponents_foreach([&](const Vector3 &point) {
2832             const Colour4b colour_selected(0, 0, 255, 255);
2833             points.push_back(pointvertex_for_windingpoint(point, colour_selected));
2834         });
2835     }
2836
2837     bool intersectVolume(const VolumeTest &volume, const Matrix4 &localToWorld) const
2838     {
2839         return m_face->intersectVolume(volume, localToWorld);
2840     }
2841
2842     void render(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
2843     {
2844         if (!m_face->isFiltered() && m_face->contributes() && intersectVolume(volume, localToWorld)) {
2845             renderer.PushState();
2846             if (selectedComponents()) {
2847                 renderer.Highlight(Renderer::eFace);
2848             }
2849             m_face->render(renderer, localToWorld);
2850             renderer.PopState();
2851         }
2852     }
2853
2854     void testSelect(SelectionTest &test, SelectionIntersection &best)
2855     {
2856         if (!m_face->isFiltered()) {
2857             m_face->testSelect(test, best);
2858         }
2859     }
2860
2861     void testSelect(Selector &selector, SelectionTest &test)
2862     {
2863         SelectionIntersection best;
2864         testSelect(test, best);
2865         if (best.valid()) {
2866             Selector_add(selector, m_selectable, best);
2867         }
2868     }
2869
2870     void testSelect_centroid(Selector &selector, SelectionTest &test)
2871     {
2872         if (m_face->contributes() && !m_face->isFiltered()) {
2873             SelectionIntersection best;
2874             m_face->testSelect_centroid(test, best);
2875             if (best.valid()) {
2876                 Selector_add(selector, m_selectable, best);
2877             }
2878         }
2879     }
2880
2881     void selectPlane(Selector &selector, const Line &line, PlanesIterator first, PlanesIterator last,
2882                      const PlaneCallback &selectedPlaneCallback)
2883     {
2884         for (Winding::const_iterator i = getFace().getWinding().begin(); i != getFace().getWinding().end(); ++i) {
2885             Vector3 v(vector3_subtracted(line_closest_point(line, (*i).vertex), (*i).vertex));
2886             double dot = vector3_dot(getFace().plane3().normal(), v);
2887             if (dot <= 0) {
2888                 return;
2889             }
2890         }
2891
2892         Selector_add(selector, m_selectable);
2893
2894         selectedPlaneCallback(getFace().plane3());
2895     }
2896
2897     void selectReversedPlane(Selector &selector, const SelectedPlanes &selectedPlanes)
2898     {
2899         if (selectedPlanes.contains(plane3_flipped(getFace().plane3()))) {
2900             Selector_add(selector, m_selectable);
2901         }
2902     }
2903
2904     void transformComponents(const Matrix4 &matrix)
2905     {
2906         if (isSelected()) {
2907             m_face->transform(matrix, false);
2908         }
2909         if (selectedVertices()) {
2910             if (m_vertexSelection.size() == 1) {
2911                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[1]);
2912                 m_face->assign_planepts(m_face->m_move_planeptsTransformed);
2913             } else if (m_vertexSelection.size() == 2) {
2914                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[1]);
2915                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[2]);
2916                 m_face->assign_planepts(m_face->m_move_planeptsTransformed);
2917             } else if (m_vertexSelection.size() >= 3) {
2918                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[0]);
2919                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[1]);
2920                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[2]);
2921                 m_face->assign_planepts(m_face->m_move_planeptsTransformed);
2922             }
2923         }
2924         if (selectedEdges()) {
2925             if (m_edgeSelection.size() == 1) {
2926                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[0]);
2927                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[1]);
2928                 m_face->assign_planepts(m_face->m_move_planeptsTransformed);
2929             } else if (m_edgeSelection.size() >= 2) {
2930                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[0]);
2931                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[1]);
2932                 matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[2]);
2933                 m_face->assign_planepts(m_face->m_move_planeptsTransformed);
2934             }
2935         }
2936     }
2937
2938     void snapto(float snap)
2939     {
2940         m_face->snapto(snap);
2941     }
2942
2943     void snapComponents(float snap)
2944     {
2945         if (isSelected()) {
2946             snapto(snap);
2947         }
2948         if (selectedVertices()) {
2949             vector3_snap(m_face->m_move_planepts[0], snap);
2950             vector3_snap(m_face->m_move_planepts[1], snap);
2951             vector3_snap(m_face->m_move_planepts[2], snap);
2952             m_face->assign_planepts(m_face->m_move_planepts);
2953             planepts_assign(m_face->m_move_planeptsTransformed, m_face->m_move_planepts);
2954             m_face->freezeTransform();
2955         }
2956         if (selectedEdges()) {
2957             vector3_snap(m_face->m_move_planepts[0], snap);
2958             vector3_snap(m_face->m_move_planepts[1], snap);
2959             vector3_snap(m_face->m_move_planepts[2], snap);
2960             m_face->assign_planepts(m_face->m_move_planepts);
2961             planepts_assign(m_face->m_move_planeptsTransformed, m_face->m_move_planepts);
2962             m_face->freezeTransform();
2963         }
2964     }
2965
2966     void update_move_planepts_vertex(std::size_t index)
2967     {
2968         m_face->update_move_planepts_vertex(index, m_face->m_move_planepts);
2969     }
2970
2971     void update_move_planepts_vertex2(std::size_t index, std::size_t other)
2972     {
2973         const std::size_t numpoints = m_face->getWinding().numpoints;
2974         ASSERT_MESSAGE(index < numpoints, "select_vertex: invalid index");
2975
2976         const std::size_t opposite = Winding_Opposite(m_face->getWinding(), index, other);
2977
2978         if (triangle_reversed(index, other, opposite)) {
2979             std::swap(index, other);
2980         }
2981
2982         ASSERT_MESSAGE(
2983                 triangles_same_winding(
2984                         m_face->getWinding()[opposite].vertex,
2985                         m_face->getWinding()[index].vertex,
2986                         m_face->getWinding()[other].vertex,
2987                         m_face->getWinding()[0].vertex,
2988                         m_face->getWinding()[1].vertex,
2989                         m_face->getWinding()[2].vertex
2990                 ),
2991                 "update_move_planepts_vertex2: error"
2992         );
2993
2994         m_face->m_move_planepts[0] = m_face->getWinding()[opposite].vertex;
2995         m_face->m_move_planepts[1] = m_face->getWinding()[index].vertex;
2996         m_face->m_move_planepts[2] = m_face->getWinding()[other].vertex;
2997         planepts_quantise(m_face->m_move_planepts, GRID_MIN); // winding points are very inaccurate
2998     }
2999
3000     void update_selection_vertex()
3001     {
3002         if (m_vertexSelection.size() == 0) {
3003             m_selectableVertices.setSelected(false);
3004         } else {
3005             m_selectableVertices.setSelected(true);
3006
3007             if (m_vertexSelection.size() == 1) {
3008                 std::size_t index = Winding_FindAdjacent(getFace().getWinding(), *m_vertexSelection.begin());
3009
3010                 if (index != c_brush_maxFaces) {
3011                     update_move_planepts_vertex(index);
3012                 }
3013             } else if (m_vertexSelection.size() == 2) {
3014                 std::size_t index = Winding_FindAdjacent(getFace().getWinding(), *m_vertexSelection.begin());
3015                 std::size_t other = Winding_FindAdjacent(getFace().getWinding(), *(++m_vertexSelection.begin()));
3016
3017                 if (index != c_brush_maxFaces
3018                     && other != c_brush_maxFaces) {
3019                     update_move_planepts_vertex2(index, other);
3020                 }
3021             }
3022         }
3023     }
3024
3025     void select_vertex(std::size_t index, bool select)
3026     {
3027         if (select) {
3028             VertexSelection_insert(m_vertexSelection, getFace().getWinding()[index].adjacent);
3029         } else {
3030             VertexSelection_erase(m_vertexSelection, getFace().getWinding()[index].adjacent);
3031         }
3032
3033         SceneChangeNotify();
3034         update_selection_vertex();
3035     }
3036
3037     bool selected_vertex(std::size_t index) const
3038     {
3039         return VertexSelection_find(m_vertexSelection, getFace().getWinding()[index].adjacent) !=
3040                m_vertexSelection.end();
3041     }
3042
3043     void update_move_planepts_edge(std::size_t index)
3044     {
3045         std::size_t numpoints = m_face->getWinding().numpoints;
3046         ASSERT_MESSAGE(index < numpoints, "select_edge: invalid index");
3047
3048         std::size_t adjacent = Winding_next(m_face->getWinding(), index);
3049         std::size_t opposite = Winding_Opposite(m_face->getWinding(), index);
3050         m_face->m_move_planepts[0] = m_face->getWinding()[index].vertex;
3051         m_face->m_move_planepts[1] = m_face->getWinding()[adjacent].vertex;
3052         m_face->m_move_planepts[2] = m_face->getWinding()[opposite].vertex;
3053         planepts_quantise(m_face->m_move_planepts, GRID_MIN); // winding points are very inaccurate
3054     }
3055
3056     void update_selection_edge()
3057     {
3058         if (m_edgeSelection.size() == 0) {
3059             m_selectableEdges.setSelected(false);
3060         } else {
3061             m_selectableEdges.setSelected(true);
3062
3063             if (m_edgeSelection.size() == 1) {
3064                 std::size_t index = Winding_FindAdjacent(getFace().getWinding(), *m_edgeSelection.begin());
3065
3066                 if (index != c_brush_maxFaces) {
3067                     update_move_planepts_edge(index);
3068                 }
3069             }
3070         }
3071     }
3072
3073     void select_edge(std::size_t index, bool select)
3074     {
3075         if (select) {
3076             VertexSelection_insert(m_edgeSelection, getFace().getWinding()[index].adjacent);
3077         } else {
3078             VertexSelection_erase(m_edgeSelection, getFace().getWinding()[index].adjacent);
3079         }
3080
3081         SceneChangeNotify();
3082         update_selection_edge();
3083     }
3084
3085     bool selected_edge(std::size_t index) const
3086     {
3087         return VertexSelection_find(m_edgeSelection, getFace().getWinding()[index].adjacent) != m_edgeSelection.end();
3088     }
3089
3090     const Vector3 &centroid() const
3091     {
3092         return m_face->centroid();
3093     }
3094
3095     void connectivityChanged()
3096     {
3097         // This occurs when a face is added or removed.
3098         // The current vertex and edge selections no longer valid and must be cleared.
3099         m_vertexSelection.clear();
3100         m_selectableVertices.setSelected(false);
3101         m_edgeSelection.clear();
3102         m_selectableEdges.setSelected(false);
3103     }
3104 };
3105
3106 class BrushClipPlane : public OpenGLRenderable {
3107     Plane3 m_plane;
3108     Winding m_winding;
3109     static Shader *m_state;
3110 public:
3111     static void constructStatic()
3112     {
3113         m_state = GlobalShaderCache().capture("$CLIPPER_OVERLAY");
3114     }
3115
3116     static void destroyStatic()
3117     {
3118         GlobalShaderCache().release("$CLIPPER_OVERLAY");
3119     }
3120
3121     void setPlane(const Brush &brush, const Plane3 &plane)
3122     {
3123         m_plane = plane;
3124         if (plane3_valid(m_plane)) {
3125             brush.windingForClipPlane(m_winding, m_plane);
3126         } else {
3127             m_winding.resize(0);
3128         }
3129     }
3130
3131     void render(RenderStateFlags state) const
3132     {
3133         if ((state & RENDER_FILL) != 0) {
3134             Winding_Draw(m_winding, m_plane.normal(), state);
3135         } else {
3136             Winding_DrawWireframe(m_winding);
3137
3138             // also draw a line indicating the direction of the cut
3139             Vector3 lineverts[2];
3140             Winding_Centroid(m_winding, m_plane, lineverts[0]);
3141             lineverts[1] = vector3_added(lineverts[0], vector3_scaled(m_plane.normal(), Brush::m_maxWorldCoord * 4));
3142
3143             glVertexPointer(3, GL_FLOAT, sizeof(Vector3), &lineverts[0]);
3144             glDrawArrays(GL_LINES, 0, GLsizei(2));
3145         }
3146     }
3147
3148     void render(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
3149     {
3150         renderer.SetState(m_state, Renderer::eWireframeOnly);
3151         renderer.SetState(m_state, Renderer::eFullMaterials);
3152         renderer.addRenderable(*this, localToWorld);
3153     }
3154 };
3155
3156 inline void Face_addLight(const FaceInstance &face, const Matrix4 &localToWorld, const RendererLight &light)
3157 {
3158     const Plane3 &facePlane = face.getFace().plane3();
3159     const Vector3 &origin = light.aabb().origin;
3160     Plane3 tmp(plane3_transformed(Plane3(facePlane.normal(), -facePlane.dist()), localToWorld));
3161     if (!plane3_test_point(tmp, origin)
3162         || !plane3_test_point(tmp, vector3_added(origin, light.offset()))) {
3163         face.m_lights.addLight(light);
3164     }
3165 }
3166
3167
3168 typedef std::vector<FaceInstance> FaceInstances;
3169
3170 class EdgeInstance : public Selectable {
3171     FaceInstances &m_faceInstances;
3172     SelectableEdge *m_edge;
3173
3174     void select_edge(bool select)
3175     {
3176         FaceVertexId faceVertex = m_edge->m_faceVertex;
3177         m_faceInstances[faceVertex.getFace()].select_edge(faceVertex.getVertex(), select);
3178         faceVertex = next_edge(m_edge->m_faces, faceVertex);
3179         m_faceInstances[faceVertex.getFace()].select_edge(faceVertex.getVertex(), select);
3180     }
3181
3182     bool selected_edge() const
3183     {
3184         FaceVertexId faceVertex = m_edge->m_faceVertex;
3185         if (!m_faceInstances[faceVertex.getFace()].selected_edge(faceVertex.getVertex())) {
3186             return false;
3187         }
3188         faceVertex = next_edge(m_edge->m_faces, faceVertex);
3189         if (!m_faceInstances[faceVertex.getFace()].selected_edge(faceVertex.getVertex())) {
3190             return false;
3191         }
3192
3193         return true;
3194     }
3195
3196 public:
3197     EdgeInstance(FaceInstances &faceInstances, SelectableEdge &edge)
3198             : m_faceInstances(faceInstances), m_edge(&edge)
3199     {
3200     }
3201
3202     EdgeInstance &operator=(const EdgeInstance &other)
3203     {
3204         m_edge = other.m_edge;
3205         return *this;
3206     }
3207
3208     void setSelected(bool select)
3209     {
3210         select_edge(select);
3211     }
3212
3213     bool isSelected() const
3214     {
3215         return selected_edge();
3216     }
3217
3218
3219     void testSelect(Selector &selector, SelectionTest &test)
3220     {
3221         SelectionIntersection best;
3222         m_edge->testSelect(test, best);
3223         if (best.valid()) {
3224             Selector_add(selector, *this, best);
3225         }
3226     }
3227 };
3228
3229 class VertexInstance : public Selectable {
3230     FaceInstances &m_faceInstances;
3231     SelectableVertex *m_vertex;
3232
3233     void select_vertex(bool select)
3234     {
3235         FaceVertexId faceVertex = m_vertex->m_faceVertex;
3236         do {
3237             m_faceInstances[faceVertex.getFace()].select_vertex(faceVertex.getVertex(), select);
3238             faceVertex = next_vertex(m_vertex->m_faces, faceVertex);
3239         } while (faceVertex.getFace() != m_vertex->m_faceVertex.getFace());
3240     }
3241
3242     bool selected_vertex() const
3243     {
3244         FaceVertexId faceVertex = m_vertex->m_faceVertex;
3245         do {
3246             if (!m_faceInstances[faceVertex.getFace()].selected_vertex(faceVertex.getVertex())) {
3247                 return false;
3248             }
3249             faceVertex = next_vertex(m_vertex->m_faces, faceVertex);
3250         } while (faceVertex.getFace() != m_vertex->m_faceVertex.getFace());
3251         return true;
3252     }
3253
3254 public:
3255     VertexInstance(FaceInstances &faceInstances, SelectableVertex &vertex)
3256             : m_faceInstances(faceInstances), m_vertex(&vertex)
3257     {
3258     }
3259
3260     VertexInstance &operator=(const VertexInstance &other)
3261     {
3262         m_vertex = other.m_vertex;
3263         return *this;
3264     }
3265
3266     void setSelected(bool select)
3267     {
3268         select_vertex(select);
3269     }
3270
3271     bool isSelected() const
3272     {
3273         return selected_vertex();
3274     }
3275
3276     void testSelect(Selector &selector, SelectionTest &test)
3277     {
3278         SelectionIntersection best;
3279         m_vertex->testSelect(test, best);
3280         if (best.valid()) {
3281             Selector_add(selector, *this, best);
3282         }
3283     }
3284 };
3285
3286 class BrushInstanceVisitor {
3287 public:
3288     virtual void visit(FaceInstance &face) const = 0;
3289 };
3290
3291 class BrushInstance :
3292         public BrushObserver,
3293         public scene::Instance,
3294         public Selectable,
3295         public Renderable,
3296         public SelectionTestable,
3297         public ComponentSelectionTestable,
3298         public ComponentEditable,
3299         public ComponentSnappable,
3300         public PlaneSelectable,
3301         public LightCullable {
3302     class TypeCasts {
3303         InstanceTypeCastTable m_casts;
3304     public:
3305         TypeCasts()
3306         {
3307             InstanceStaticCast<BrushInstance, Selectable>::install(m_casts);
3308             InstanceContainedCast<BrushInstance, Bounded>::install(m_casts);
3309             InstanceContainedCast<BrushInstance, Cullable>::install(m_casts);
3310             InstanceStaticCast<BrushInstance, Renderable>::install(m_casts);
3311             InstanceStaticCast<BrushInstance, SelectionTestable>::install(m_casts);
3312             InstanceStaticCast<BrushInstance, ComponentSelectionTestable>::install(m_casts);
3313             InstanceStaticCast<BrushInstance, ComponentEditable>::install(m_casts);
3314             InstanceStaticCast<BrushInstance, ComponentSnappable>::install(m_casts);
3315             InstanceStaticCast<BrushInstance, PlaneSelectable>::install(m_casts);
3316             InstanceIdentityCast<BrushInstance>::install(m_casts);
3317             InstanceContainedCast<BrushInstance, Transformable>::install(m_casts);
3318         }
3319
3320         InstanceTypeCastTable &get()
3321         {
3322             return m_casts;
3323         }
3324     };
3325
3326
3327     Brush &m_brush;
3328
3329     FaceInstances m_faceInstances;
3330
3331     typedef std::vector<EdgeInstance> EdgeInstances;
3332     EdgeInstances m_edgeInstances;
3333     typedef std::vector<VertexInstance> VertexInstances;
3334     VertexInstances m_vertexInstances;
3335
3336     ObservedSelectable m_selectable;
3337
3338     mutable RenderableWireframe m_render_wireframe;
3339     mutable RenderablePointVector m_render_selected;
3340     mutable AABB m_aabb_component;
3341     mutable Array<PointVertex> m_faceCentroidPointsCulled;
3342     RenderablePointArray m_render_faces_wireframe;
3343     mutable bool m_viewChanged;   // requires re-evaluation of view-dependent cached data
3344
3345     BrushClipPlane m_clipPlane;
3346
3347     static Shader *m_state_selpoint;
3348
3349     const LightList *m_lightList;
3350
3351     TransformModifier m_transform;
3352
3353     BrushInstance(const BrushInstance &other); // NOT COPYABLE
3354     BrushInstance &operator=(const BrushInstance &other); // NOT ASSIGNABLE
3355 public:
3356     static Counter *m_counter;
3357
3358     typedef LazyStatic<TypeCasts> StaticTypeCasts;
3359
3360     void lightsChanged()
3361     {
3362         m_lightList->lightsChanged();
3363     }
3364
3365     typedef MemberCaller<BrushInstance, void(), &BrushInstance::lightsChanged> LightsChangedCaller;
3366
3367     STRING_CONSTANT(Name, "BrushInstance");
3368
3369     BrushInstance(const scene::Path &path, scene::Instance *parent, Brush &brush) :
3370             Instance(path, parent, this, StaticTypeCasts::instance().get()),
3371             m_brush(brush),
3372             m_selectable(SelectedChangedCaller(*this)),
3373             m_render_selected(GL_POINTS),
3374             m_render_faces_wireframe(m_faceCentroidPointsCulled, GL_POINTS),
3375             m_viewChanged(false),
3376             m_transform(Brush::TransformChangedCaller(m_brush), ApplyTransformCaller(*this))
3377     {
3378         m_brush.instanceAttach(Instance::path());
3379         m_brush.attach(*this);
3380         m_counter->increment();
3381
3382         m_lightList = &GlobalShaderCache().attach(*this);
3383         m_brush.m_lightsChanged = LightsChangedCaller(*this); ///\todo Make this work with instancing.
3384
3385         Instance::setTransformChangedCallback(LightsChangedCaller(*this));
3386     }
3387
3388     ~BrushInstance()
3389     {
3390         Instance::setTransformChangedCallback(Callback<void()>());
3391
3392         m_brush.m_lightsChanged = Callback<void()>();
3393         GlobalShaderCache().detach(*this);
3394
3395         m_counter->decrement();
3396         m_brush.detach(*this);
3397         m_brush.instanceDetach(Instance::path());
3398     }
3399
3400     Brush &getBrush()
3401     {
3402         return m_brush;
3403     }
3404
3405     const Brush &getBrush() const
3406     {
3407         return m_brush;
3408     }
3409
3410     Bounded &get(NullType<Bounded>)
3411     {
3412         return m_brush;
3413     }
3414
3415     Cullable &get(NullType<Cullable>)
3416     {
3417         return m_brush;
3418     }
3419
3420     Transformable &get(NullType<Transformable>)
3421     {
3422         return m_transform;
3423     }
3424
3425     void selectedChanged(const Selectable &selectable)
3426     {
3427         GlobalSelectionSystem().getObserver(SelectionSystem::ePrimitive)(selectable);
3428         GlobalSelectionSystem().onSelectedChanged(*this, selectable);
3429
3430         Instance::selectedChanged();
3431     }
3432
3433     typedef MemberCaller<BrushInstance, void(
3434             const Selectable &), &BrushInstance::selectedChanged> SelectedChangedCaller;
3435
3436     void selectedChangedComponent(const Selectable &selectable)
3437     {
3438         GlobalSelectionSystem().getObserver(SelectionSystem::eComponent)(selectable);
3439         GlobalSelectionSystem().onComponentSelection(*this, selectable);
3440     }
3441
3442     typedef MemberCaller<BrushInstance, void(
3443             const Selectable &), &BrushInstance::selectedChangedComponent> SelectedChangedComponentCaller;
3444
3445     const BrushInstanceVisitor &forEachFaceInstance(const BrushInstanceVisitor &visitor)
3446     {
3447         for (FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) {
3448             visitor.visit(*i);
3449         }
3450         return visitor;
3451     }
3452
3453     static void constructStatic()
3454     {
3455         m_state_selpoint = GlobalShaderCache().capture("$SELPOINT");
3456     }
3457
3458     static void destroyStatic()
3459     {
3460         GlobalShaderCache().release("$SELPOINT");
3461     }
3462
3463     void clear()
3464     {
3465         m_faceInstances.clear();
3466     }
3467
3468     void reserve(std::size_t size)
3469     {
3470         m_faceInstances.reserve(size);
3471     }
3472
3473     void push_back(Face &face)
3474     {
3475         m_faceInstances.push_back(FaceInstance(face, SelectedChangedComponentCaller(*this)));
3476     }
3477
3478     void pop_back()
3479     {
3480         ASSERT_MESSAGE(!m_faceInstances.empty(), "erasing invalid element");
3481         m_faceInstances.pop_back();
3482     }
3483
3484     void erase(std::size_t index)
3485     {
3486         ASSERT_MESSAGE(index < m_faceInstances.size(), "erasing invalid element");
3487         m_faceInstances.erase(m_faceInstances.begin() + index);
3488     }
3489
3490     void connectivityChanged()
3491     {
3492         for (FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) {
3493             (*i).connectivityChanged();
3494         }
3495     }
3496
3497     void edge_clear()
3498     {
3499         m_edgeInstances.clear();
3500     }
3501
3502     void edge_push_back(SelectableEdge &edge)
3503     {
3504         m_edgeInstances.push_back(EdgeInstance(m_faceInstances, edge));
3505     }
3506
3507     void vertex_clear()
3508     {
3509         m_vertexInstances.clear();
3510     }
3511
3512     void vertex_push_back(SelectableVertex &vertex)
3513     {
3514         m_vertexInstances.push_back(VertexInstance(m_faceInstances, vertex));
3515     }
3516
3517     void DEBUG_verify() const
3518     {
3519         ASSERT_MESSAGE(m_faceInstances.size() == m_brush.DEBUG_size(), "FATAL: mismatch");
3520     }
3521
3522     bool isSelected() const
3523     {
3524         return m_selectable.isSelected();
3525     }
3526
3527     void setSelected(bool select)
3528     {
3529         m_selectable.setSelected(select);
3530     }
3531
3532     void update_selected() const
3533     {
3534         m_render_selected.clear();
3535         for (FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) {
3536             if ((*i).getFace().contributes()) {
3537                 (*i).iterate_selected(m_render_selected);
3538             }
3539         }
3540     }
3541
3542     void evaluateViewDependent(const VolumeTest &volume, const Matrix4 &localToWorld) const
3543     {
3544         if (m_viewChanged) {
3545             m_viewChanged = false;
3546
3547             bool faces_visible[c_brush_maxFaces];
3548             {
3549                 bool *j = faces_visible;
3550                 for (FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i, ++j) {
3551                     *j = (*i).intersectVolume(volume, localToWorld);
3552                 }
3553             }
3554
3555             m_brush.update_wireframe(m_render_wireframe, faces_visible);
3556             m_brush.update_faces_wireframe(m_faceCentroidPointsCulled, faces_visible);
3557         }
3558     }
3559
3560     void renderComponentsSelected(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
3561     {
3562         m_brush.evaluateBRep();
3563
3564         update_selected();
3565         if (!m_render_selected.empty()) {
3566             renderer.Highlight(Renderer::ePrimitive, false);
3567             renderer.SetState(m_state_selpoint, Renderer::eWireframeOnly);
3568             renderer.SetState(m_state_selpoint, Renderer::eFullMaterials);
3569             renderer.addRenderable(m_render_selected, localToWorld);
3570         }
3571     }
3572
3573     void renderComponents(Renderer &renderer, const VolumeTest &volume) const
3574     {
3575         m_brush.evaluateBRep();
3576
3577         const Matrix4 &localToWorld = Instance::localToWorld();
3578
3579         renderer.SetState(m_brush.m_state_point, Renderer::eWireframeOnly);
3580         renderer.SetState(m_brush.m_state_point, Renderer::eFullMaterials);
3581
3582         if (volume.fill() && GlobalSelectionSystem().ComponentMode() == SelectionSystem::eFace) {
3583             evaluateViewDependent(volume, localToWorld);
3584             renderer.addRenderable(m_render_faces_wireframe, localToWorld);
3585         } else {
3586             m_brush.renderComponents(GlobalSelectionSystem().ComponentMode(), renderer, volume, localToWorld);
3587         }
3588     }
3589
3590     void renderClipPlane(Renderer &renderer, const VolumeTest &volume) const
3591     {
3592         if (GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eClip && isSelected()) {
3593             m_clipPlane.render(renderer, volume, localToWorld());
3594         }
3595     }
3596
3597     void renderCommon(Renderer &renderer, const VolumeTest &volume) const
3598     {
3599         bool componentMode = GlobalSelectionSystem().Mode() == SelectionSystem::eComponent;
3600
3601         if (componentMode && isSelected()) {
3602             renderComponents(renderer, volume);
3603         }
3604
3605         if (parentSelected()) {
3606             if (!componentMode) {
3607                 renderer.Highlight(Renderer::eFace);
3608             }
3609             renderer.Highlight(Renderer::ePrimitive);
3610         }
3611     }
3612
3613     void renderSolid(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
3614     {
3615         //renderCommon(renderer, volume);
3616
3617         m_lightList->evaluateLights();
3618
3619         for (FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) {
3620             renderer.setLights((*i).m_lights);
3621             (*i).render(renderer, volume, localToWorld);
3622         }
3623
3624         renderComponentsSelected(renderer, volume, localToWorld);
3625     }
3626
3627     void renderWireframe(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
3628     {
3629         //renderCommon(renderer, volume);
3630
3631         evaluateViewDependent(volume, localToWorld);
3632
3633         if (m_render_wireframe.m_size != 0) {
3634             renderer.addRenderable(m_render_wireframe, localToWorld);
3635         }
3636
3637         renderComponentsSelected(renderer, volume, localToWorld);
3638     }
3639
3640     void renderSolid(Renderer &renderer, const VolumeTest &volume) const
3641     {
3642         m_brush.evaluateBRep();
3643
3644         renderClipPlane(renderer, volume);
3645
3646         renderSolid(renderer, volume, localToWorld());
3647     }
3648
3649     void renderWireframe(Renderer &renderer, const VolumeTest &volume) const
3650     {
3651         m_brush.evaluateBRep();
3652
3653         renderClipPlane(renderer, volume);
3654
3655         renderWireframe(renderer, volume, localToWorld());
3656     }
3657
3658     void viewChanged() const
3659     {
3660         m_viewChanged = true;
3661     }
3662
3663     void testSelect(Selector &selector, SelectionTest &test)
3664     {
3665         test.BeginMesh(localToWorld());
3666
3667         SelectionIntersection best;
3668         for (FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) {
3669             (*i).testSelect(test, best);
3670         }
3671         if (best.valid()) {
3672             selector.addIntersection(best);
3673         }
3674     }
3675
3676     bool isSelectedComponents() const
3677     {
3678         for (FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) {
3679             if ((*i).selectedComponents()) {
3680                 return true;
3681             }
3682         }
3683         return false;
3684     }
3685
3686     void setSelectedComponents(bool select, SelectionSystem::EComponentMode mode)
3687     {
3688         for (FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) {
3689             (*i).setSelected(mode, select);
3690         }
3691     }
3692
3693     void testSelectComponents(Selector &selector, SelectionTest &test, SelectionSystem::EComponentMode mode)
3694     {
3695         test.BeginMesh(localToWorld());
3696
3697         switch (mode) {
3698             case SelectionSystem::eVertex: {
3699                 for (VertexInstances::iterator i = m_vertexInstances.begin(); i != m_vertexInstances.end(); ++i) {
3700                     (*i).testSelect(selector, test);
3701                 }
3702             }
3703                 break;
3704             case SelectionSystem::eEdge: {
3705                 for (EdgeInstances::iterator i = m_edgeInstances.begin(); i != m_edgeInstances.end(); ++i) {
3706                     (*i).testSelect(selector, test);
3707                 }
3708             }
3709                 break;
3710             case SelectionSystem::eFace: {
3711