]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/brushmanip.cpp
copy/paste face textures; fixed gtk assert on linux
[xonotic/netradiant.git] / radiant / brushmanip.cpp
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 #include "brushmanip.h"
23
24
25 #include "gtkutil/widget.h"
26 #include "gtkutil/menu.h"
27 #include "gtkmisc.h"
28 #include "brushnode.h"
29 #include "map.h"
30 #include "texwindow.h"
31 #include "gtkdlgs.h"
32 #include "commands.h"
33 #include "mainframe.h"
34 #include "dialog.h"
35 #include "xywindow.h"
36 #include "preferences.h"
37
38 #include <list>
39
40
41 void Brush_ConstructCuboid(Brush& brush, const AABB& bounds, const char* shader, const TextureProjection& projection)
42 {
43   const unsigned char box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } };
44   Vector3 mins(vector3_subtracted(bounds.origin, bounds.extents));
45   Vector3 maxs(vector3_added(bounds.origin, bounds.extents));
46
47   brush.undoSave();
48   brush.clear();
49   brush.reserve(6);
50
51   {
52     for(int i=0; i < 3; ++i)
53     {
54       Vector3 planepts1(maxs);
55       Vector3 planepts2(maxs);
56       planepts2[box[i][0]] = mins[box[i][0]];
57       planepts1[box[i][1]] = mins[box[i][1]];
58
59       brush.addPlane(maxs, planepts1, planepts2, shader, projection);
60     }
61   }
62   {
63     for(int i=0; i < 3; ++i)
64     {
65       Vector3 planepts1(mins);
66       Vector3 planepts2(mins);
67       planepts1[box[i][0]] = maxs[box[i][0]];
68       planepts2[box[i][1]] = maxs[box[i][1]];
69
70       brush.addPlane(mins, planepts1, planepts2, shader, projection);
71     }
72   }
73 }
74
75 inline float max_extent(const Vector3& extents)
76 {
77   return std::max(std::max(extents[0], extents[1]), extents[2]);
78 }
79
80 inline float max_extent_2d(const Vector3& extents, int axis)
81 {
82   switch(axis)
83   {
84   case 0:
85     return std::max(extents[1], extents[2]);
86   case 1:
87     return std::max(extents[0], extents[2]);
88   default:
89     return std::max(extents[0], extents[1]);
90   }
91 }
92
93 const std::size_t c_brushPrism_minSides = 3;
94 const std::size_t c_brushPrism_maxSides = c_brush_maxFaces - 2;
95 const char* const c_brushPrism_name = "brushPrism";
96
97 void Brush_ConstructPrism(Brush& brush, const AABB& bounds, std::size_t sides, int axis, const char* shader, const TextureProjection& projection)
98 {
99   if(sides < c_brushPrism_minSides)
100   {
101     globalErrorStream() << c_brushPrism_name << ": sides " << Unsigned(sides) << ": too few sides, minimum is " << Unsigned(c_brushPrism_minSides) << "\n";
102     return;
103   }
104   if(sides > c_brushPrism_maxSides)
105   {
106     globalErrorStream() << c_brushPrism_name << ": sides " << Unsigned(sides) << ": too many sides, maximum is " << Unsigned(c_brushPrism_maxSides) << "\n";
107     return;
108   }
109
110   brush.undoSave();
111   brush.clear();
112   brush.reserve(sides+2);
113
114   Vector3 mins(vector3_subtracted(bounds.origin, bounds.extents));
115   Vector3 maxs(vector3_added(bounds.origin, bounds.extents));
116
117   float radius = max_extent_2d(bounds.extents, axis);
118   const Vector3& mid = bounds.origin;
119   Vector3 planepts[3];
120
121   planepts[2][(axis+1)%3] = mins[(axis+1)%3];
122   planepts[2][(axis+2)%3] = mins[(axis+2)%3];
123   planepts[2][axis] = maxs[axis];
124   planepts[1][(axis+1)%3] = maxs[(axis+1)%3];
125   planepts[1][(axis+2)%3] = mins[(axis+2)%3];
126   planepts[1][axis] = maxs[axis];
127   planepts[0][(axis+1)%3] = maxs[(axis+1)%3];
128   planepts[0][(axis+2)%3] = maxs[(axis+2)%3];
129   planepts[0][axis] = maxs[axis];
130
131   brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection);
132
133   planepts[0][(axis+1)%3] = mins[(axis+1)%3];
134   planepts[0][(axis+2)%3] = mins[(axis+2)%3];
135   planepts[0][axis] = mins[axis];
136   planepts[1][(axis+1)%3] = maxs[(axis+1)%3];
137   planepts[1][(axis+2)%3] = mins[(axis+2)%3];
138   planepts[1][axis] = mins[axis];
139   planepts[2][(axis+1)%3] = maxs[(axis+1)%3];
140   planepts[2][(axis+2)%3] = maxs[(axis+2)%3];
141   planepts[2][axis] = mins[axis];
142
143   brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection);
144  
145   for (std::size_t i=0 ; i<sides ; ++i)
146   {
147     double sv = sin (i*3.14159265*2/sides);
148     double cv = cos (i*3.14159265*2/sides);
149
150     planepts[0][(axis+1)%3] = static_cast<float>(floor(mid[(axis+1)%3]+radius*cv+0.5));
151     planepts[0][(axis+2)%3] = static_cast<float>(floor(mid[(axis+2)%3]+radius*sv+0.5));
152     planepts[0][axis] = mins[axis];
153
154     planepts[1][(axis+1)%3] = planepts[0][(axis+1)%3];
155     planepts[1][(axis+2)%3] = planepts[0][(axis+2)%3];
156     planepts[1][axis] = maxs[axis];
157
158     planepts[2][(axis+1)%3] = static_cast<float>(floor(planepts[0][(axis+1)%3] - radius*sv + 0.5));
159     planepts[2][(axis+2)%3] = static_cast<float>(floor(planepts[0][(axis+2)%3] + radius*cv + 0.5));
160     planepts[2][axis] = maxs[axis];
161
162     brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection);
163   }
164 }
165
166 const std::size_t c_brushCone_minSides = 3;
167 const std::size_t c_brushCone_maxSides = 32;
168 const char* const c_brushCone_name = "brushCone";
169
170 void Brush_ConstructCone(Brush& brush, const AABB& bounds, std::size_t sides, const char* shader, const TextureProjection& projection)
171 {
172   if(sides < c_brushCone_minSides)
173   {
174     globalErrorStream() << c_brushCone_name << ": sides " << Unsigned(sides) << ": too few sides, minimum is " << Unsigned(c_brushCone_minSides) << "\n";
175     return;
176   }
177   if(sides > c_brushCone_maxSides)
178   {
179     globalErrorStream() << c_brushCone_name << ": sides " << Unsigned(sides) << ": too many sides, maximum is " << Unsigned(c_brushCone_maxSides) << "\n";
180     return;
181   }
182
183   brush.undoSave();
184   brush.clear();
185   brush.reserve(sides+1);
186
187   Vector3 mins(vector3_subtracted(bounds.origin, bounds.extents));
188   Vector3 maxs(vector3_added(bounds.origin, bounds.extents));
189
190   float radius = max_extent(bounds.extents);
191   const Vector3& mid = bounds.origin;
192   Vector3 planepts[3];
193
194   planepts[0][0] = mins[0];planepts[0][1] = mins[1];planepts[0][2] = mins[2];
195   planepts[1][0] = maxs[0];planepts[1][1] = mins[1];planepts[1][2] = mins[2];
196   planepts[2][0] = maxs[0];planepts[2][1] = maxs[1];planepts[2][2] = mins[2];
197
198   brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection);
199
200   for (std::size_t i=0 ; i<sides ; ++i)
201   {
202     double sv = sin (i*3.14159265*2/sides);
203     double cv = cos (i*3.14159265*2/sides);
204
205     planepts[0][0] = static_cast<float>(floor(mid[0]+radius*cv+0.5));
206     planepts[0][1] = static_cast<float>(floor(mid[1]+radius*sv+0.5));
207     planepts[0][2] = mins[2];
208
209     planepts[1][0] = mid[0];
210     planepts[1][1] = mid[1];
211     planepts[1][2] = maxs[2];
212
213     planepts[2][0] = static_cast<float>(floor(planepts[0][0] - radius * sv + 0.5));
214     planepts[2][1] = static_cast<float>(floor(planepts[0][1] + radius * cv + 0.5));
215     planepts[2][2] = maxs[2];
216
217     brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection);
218   }
219 }
220
221 const std::size_t c_brushSphere_minSides = 3;
222 const std::size_t c_brushSphere_maxSides = 7;
223 const char* const c_brushSphere_name = "brushSphere";
224
225 void Brush_ConstructSphere(Brush& brush, const AABB& bounds, std::size_t sides, const char* shader, const TextureProjection& projection)
226 {
227   if(sides < c_brushSphere_minSides)
228   {
229     globalErrorStream() << c_brushSphere_name << ": sides " << Unsigned(sides) << ": too few sides, minimum is " << Unsigned(c_brushSphere_minSides) << "\n";
230     return;
231   }
232   if(sides > c_brushSphere_maxSides)
233   {
234     globalErrorStream() << c_brushSphere_name << ": sides " << Unsigned(sides) << ": too many sides, maximum is " << Unsigned(c_brushSphere_maxSides) << "\n";
235     return;
236   }
237
238   brush.undoSave();
239   brush.clear();
240   brush.reserve(sides*sides);
241
242   float radius = max_extent(bounds.extents);
243   const Vector3& mid = bounds.origin;
244   Vector3 planepts[3];
245
246   double dt = 2 * c_pi / sides;
247   double dp = c_pi / sides;
248   for(std::size_t i=0; i < sides; i++)
249   {
250     for(std::size_t j=0;j < sides-1; j++)
251     {
252       double t = i * dt;
253       double p = float(j * dp - c_pi / 2);
254
255       planepts[0] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t, p), radius));
256       planepts[1] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t, p + dp), radius));
257       planepts[2] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t + dt, p + dp), radius));
258
259       brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection);
260     }
261   }
262
263   {
264     double p = (sides - 1) * dp - c_pi / 2;
265     for(std::size_t i = 0; i < sides; i++)
266     {
267       double t = i * dt;
268
269       planepts[0] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t, p), radius));
270       planepts[1] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t + dt, p + dp), radius));
271       planepts[2] = vector3_added(mid, vector3_scaled(vector3_for_spherical(t + dt, p), radius));
272
273       brush.addPlane(planepts[0], planepts[1], planepts[2], shader, projection);
274     }
275   }
276 }
277
278 int GetViewAxis()
279 {
280   switch(GlobalXYWnd_getCurrentViewType())
281   {
282     case XY:
283       return 2;
284     case XZ:
285       return 1;
286     case YZ:
287       return 0;
288   }
289   return 2;
290 }
291
292 void Brush_ConstructPrefab(Brush& brush, EBrushPrefab type, const AABB& bounds, std::size_t sides, const char* shader, const TextureProjection& projection)
293 {
294   switch(type)
295   {
296   case eBrushCuboid:
297     {
298       UndoableCommand undo("brushCuboid");
299
300       Brush_ConstructCuboid(brush, bounds, shader, projection);
301     }
302     break;
303   case eBrushPrism:
304     {
305       int axis = GetViewAxis();
306       StringOutputStream command;
307       command << c_brushPrism_name << " -sides " << Unsigned(sides) << " -axis " << axis;
308       UndoableCommand undo(command.c_str());
309
310       Brush_ConstructPrism(brush, bounds, sides, axis, shader, projection);
311     }
312     break;
313   case eBrushCone:
314     {
315       StringOutputStream command;
316       command << c_brushCone_name << " -sides " << Unsigned(sides);
317       UndoableCommand undo(command.c_str());
318
319       Brush_ConstructCone(brush, bounds, sides, shader, projection);
320     }
321     break;
322   case eBrushSphere:
323     {
324       StringOutputStream command;
325       command << c_brushSphere_name << " -sides " << Unsigned(sides);
326       UndoableCommand undo(command.c_str());
327
328       Brush_ConstructSphere(brush, bounds, sides, shader, projection);
329     }
330     break;
331   }
332 }
333
334
335 void ConstructRegionBrushes(scene::Node* brushes[6], const Vector3& region_mins, const Vector3& region_maxs)
336 {
337   {
338     // set mins
339     Vector3 mins(region_mins[0]-32, region_mins[1]-32, region_mins[2]-32);
340
341     // vary maxs
342     for(std::size_t i=0; i<3; i++)
343     {
344       Vector3 maxs(region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32);
345       maxs[i] = region_mins[i];
346       Brush_ConstructCuboid(*Node_getBrush(*brushes[i]), aabb_for_minmax(mins, maxs), texdef_name_default(), TextureProjection());
347     }
348   }
349
350   {
351     // set maxs
352     Vector3 maxs(region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32);
353
354     // vary mins
355     for(std::size_t i=0; i<3; i++)
356     {
357       Vector3 mins(region_mins[0]-32, region_mins[1]-32, region_mins[2]-32);
358       mins[i] = region_maxs[i];
359       Brush_ConstructCuboid(*Node_getBrush(*brushes[i+3]), aabb_for_minmax(mins, maxs), texdef_name_default(), TextureProjection());
360     }
361   }
362 }
363
364
365 class BrushForEachFace
366 {
367   const BrushInstanceVisitor& m_visitor;
368 public:
369   BrushForEachFace(const BrushInstanceVisitor& visitor) : m_visitor(visitor)
370   {
371   }
372   void operator()(BrushInstance& brush) const
373   {
374     brush.forEachFaceInstance(m_visitor);
375   }
376 };
377
378 template<class Visitor>
379 class FaceVisitAll : public BrushInstanceVisitor
380 {
381   const Visitor& m_visitor;
382 public:
383   FaceVisitAll(const Visitor& visitor)
384     : m_visitor(visitor)
385   {
386   }
387   void visit(FaceInstance& face) const
388   {
389     m_visitor.visit(face.getFace());
390   }
391 };
392
393 template<class Visitor>
394 class FaceInstanceVisitAll : public BrushInstanceVisitor
395 {
396   const Visitor& m_visitor;
397 public:
398   FaceInstanceVisitAll(const Visitor& visitor)
399     : m_visitor(visitor)
400   {
401   }
402   void visit(FaceInstance& face) const
403   {
404     m_visitor.visit(face);
405   }
406 };
407
408 #if 0
409 template<class Visitor>
410 class FaceVisitSelected : public BrushInstanceVisitor
411 {
412   const Visitor& m_visitor;
413 public:
414   FaceVisitSelected(const Visitor& visitor)
415     : m_visitor(visitor)
416   {
417   }
418   void visit(FaceInstance& face) const
419   {
420     if(face.isSelected(SelectionSystem::eFace))
421     {
422       m_visitor.visit(face.getFace());
423     }
424   }
425 };
426 #endif
427
428 template<typename Functor>
429 inline void Scene_forEachBrush(scene::Graph& graph, const Functor& functor)
430 {
431   graph.traverse(InstanceWalker< InstanceApply<BrushInstance, Functor> >(functor));
432 }
433
434 template<typename Type, typename Functor>
435 class InstanceIfVisible : public Functor
436 {
437 public:
438   InstanceIfVisible(const Functor& functor) : Functor(functor)
439   {
440   }
441   void operator()(scene::Instance& instance)
442   {
443     if(instance.path().top().get().visible())
444     {
445       Functor::operator()(instance);
446     }
447   }
448 };
449
450 template<typename Functor>
451 class BrushVisibleWalker : public scene::Graph::Walker
452 {
453   const Functor& m_functor;
454 public:
455   BrushVisibleWalker(const Functor& functor) : m_functor(functor)
456   {
457   }
458   bool pre(const scene::Path& path, scene::Instance& instance) const
459   {
460     if(path.top().get().visible())
461     {
462       BrushInstance* brush = Instance_getBrush(instance);
463       if(brush != 0)
464       {
465         m_functor(*brush);
466       }
467     }
468     return true;
469   }
470 };
471
472 template<typename Functor>
473 inline void Scene_forEachVisibleBrush(scene::Graph& graph, const Functor& functor)
474 {
475   graph.traverse(BrushVisibleWalker<Functor>(functor));
476 }
477
478 template<typename Visitor>
479 inline void Scene_ForEachBrush_ForEachFace(scene::Graph& graph, const Visitor& visitor)
480 {
481   Scene_forEachBrush(graph, BrushForEachFace(FaceVisitAll<Visitor>(visitor)));
482 }
483
484 template<typename Visitor>
485 inline void Scene_ForEachSelectedBrush_ForEachFace(scene::Graph& graph, const Visitor& visitor)
486 {
487   Scene_forEachSelectedBrush(BrushForEachFace(FaceVisitAll<Visitor>(visitor)));
488 }
489
490 template<typename Visitor>
491 inline void Scene_ForEachSelectedBrush_ForEachFaceInstance(scene::Graph& graph, const Visitor& visitor)
492 {
493   Scene_forEachSelectedBrush(BrushForEachFace(FaceInstanceVisitAll<Visitor>(visitor)));
494 }
495
496 template<typename Visitor>
497 class FaceVisitorWrapper
498 {
499   Visitor& m_visitor;
500 public:
501   FaceVisitorWrapper(Visitor& visitor) : m_visitor(visitor)
502   {
503   }
504
505   void operator()(FaceInstance& faceInstance)
506   {
507     m_visitor.visit(faceInstance.getFace());
508   }
509 };
510
511 template<typename Visitor>
512 inline void Scene_ForEachSelectedBrushFace(scene::Graph& graph, Visitor& faceVisitor)
513 {
514   g_SelectedFaceInstances.foreach(FaceVisitorWrapper<Visitor>(faceVisitor));
515 }
516
517
518
519 class FaceSetTexdefVisitor
520 {
521   const TextureProjection& m_projection;
522 public:
523   FaceSetTexdefVisitor(const TextureProjection& projection) : m_projection(projection)
524   {
525   }
526   void visit(Face& face) const
527   {
528     face.SetTexdef(m_projection);
529   }
530 };
531
532 void Scene_BrushSetTexdef_Selected(scene::Graph& graph, const TextureProjection& projection)
533 {
534   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceSetTexdefVisitor(projection));
535   SceneChangeNotify();
536 }
537
538 void Scene_BrushSetTexdef_Component_Selected(scene::Graph& graph, const TextureProjection& projection)
539 {
540   FaceSetTexdefVisitor visitor(projection);
541   Scene_ForEachSelectedBrushFace(graph, visitor);
542   SceneChangeNotify();
543 }
544
545
546 class FaceSetFlagsVisitor
547 {
548   const ContentsFlagsValue& m_projection;
549 public:
550   FaceSetFlagsVisitor(const ContentsFlagsValue& flags) : m_projection(flags)
551   {
552   }
553   void visit(Face& face) const
554   {
555     face.SetFlags(m_projection);
556   }
557 };
558
559 void Scene_BrushSetFlags_Selected(scene::Graph& graph, const ContentsFlagsValue& flags)
560 {
561   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceSetFlagsVisitor(flags));
562   SceneChangeNotify();
563 }
564
565 void Scene_BrushSetFlags_Component_Selected(scene::Graph& graph, const ContentsFlagsValue& flags)
566 {
567   FaceSetFlagsVisitor visitor(flags);
568   Scene_ForEachSelectedBrushFace(graph, visitor);
569   SceneChangeNotify();
570 }
571
572 class FaceShiftTexdefVisitor
573 {
574   float m_s, m_t;
575 public:
576   FaceShiftTexdefVisitor(float s, float t) : m_s(s), m_t(t)
577   {
578   }
579   void visit(Face& face) const
580   {
581     face.ShiftTexdef(m_s, m_t);
582   }
583 };
584
585 void Scene_BrushShiftTexdef_Selected(scene::Graph& graph, float s, float t)
586 {
587   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceShiftTexdefVisitor(s, t));
588   SceneChangeNotify();
589 }
590
591 void Scene_BrushShiftTexdef_Component_Selected(scene::Graph& graph, float s, float t)
592 {
593   FaceShiftTexdefVisitor visitor(s, t);
594   Scene_ForEachSelectedBrushFace(graph, visitor);
595   SceneChangeNotify();
596 }
597
598 class FaceScaleTexdefVisitor
599 {
600   float m_s, m_t;
601 public:
602   FaceScaleTexdefVisitor(float s, float t) : m_s(s), m_t(t)
603   {
604   }
605   void visit(Face& face) const
606   {
607     face.ScaleTexdef(m_s, m_t);
608   }
609 };
610
611 void Scene_BrushScaleTexdef_Selected(scene::Graph& graph, float s, float t)
612 {
613   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceScaleTexdefVisitor(s, t));
614   SceneChangeNotify();
615 }
616
617 void Scene_BrushScaleTexdef_Component_Selected(scene::Graph& graph, float s, float t)
618 {
619   FaceScaleTexdefVisitor visitor(s, t);
620   Scene_ForEachSelectedBrushFace(graph, visitor);
621   SceneChangeNotify();
622 }
623
624 class FaceRotateTexdefVisitor
625 {
626   float m_angle;
627 public:
628   FaceRotateTexdefVisitor(float angle) : m_angle(angle)
629   {
630   }
631   void visit(Face& face) const
632   {
633     face.RotateTexdef(m_angle);
634   }
635 };
636
637 void Scene_BrushRotateTexdef_Selected(scene::Graph& graph, float angle)
638 {
639   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceRotateTexdefVisitor(angle));
640   SceneChangeNotify();
641 }
642
643 void Scene_BrushRotateTexdef_Component_Selected(scene::Graph& graph, float angle)
644 {
645   FaceRotateTexdefVisitor visitor(angle);
646   Scene_ForEachSelectedBrushFace(graph, visitor);
647   SceneChangeNotify();
648 }
649
650
651 class FaceSetShaderVisitor
652 {
653   const char* m_name;
654 public:
655   FaceSetShaderVisitor(const char* name) : m_name(name) {}
656   void visit(Face& face) const
657   {
658     face.SetShader(m_name);
659   }
660 };
661
662 void Scene_BrushSetShader_Selected(scene::Graph& graph, const char* name)
663 {
664   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceSetShaderVisitor(name));
665   SceneChangeNotify();
666 }
667
668 void Scene_BrushSetShader_Component_Selected(scene::Graph& graph, const char* name)
669 {
670   FaceSetShaderVisitor visitor(name);
671   Scene_ForEachSelectedBrushFace(graph, visitor);
672   SceneChangeNotify();
673 }
674
675 class FaceSetDetailVisitor
676 {
677   bool m_detail;
678 public:
679   FaceSetDetailVisitor(bool detail) : m_detail(detail)
680   {
681   }
682   void visit(Face& face) const
683   {
684     face.setDetail(m_detail);
685   }
686 };
687
688 void Scene_BrushSetDetail_Selected(scene::Graph& graph, bool detail)
689 {
690   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceSetDetailVisitor(detail));
691   SceneChangeNotify();
692 }
693
694 bool Face_FindReplaceShader(Face& face, const char* find, const char* replace)
695 {
696   if(shader_equal(face.GetShader(), find))
697   {
698     face.SetShader(replace);
699     return true;
700   }
701   return false;
702 }
703
704 class FaceFindReplaceShaderVisitor
705 {
706   const char* m_find;
707   const char* m_replace;
708 public:
709   FaceFindReplaceShaderVisitor(const char* find, const char* replace) : m_find(find), m_replace(replace)
710   {
711   }
712   void visit(Face& face) const
713   {
714     Face_FindReplaceShader(face, m_find, m_replace);
715   }
716 };
717
718 void Scene_BrushFindReplaceShader(scene::Graph& graph, const char* find, const char* replace)
719 {
720   Scene_ForEachBrush_ForEachFace(graph, FaceFindReplaceShaderVisitor(find, replace));
721 }
722
723 void Scene_BrushFindReplaceShader_Selected(scene::Graph& graph, const char* find, const char* replace)
724 {
725   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceFindReplaceShaderVisitor(find, replace));
726 }
727
728 void Scene_BrushFindReplaceShader_Component_Selected(scene::Graph& graph, const char* find, const char* replace)
729 {
730   FaceFindReplaceShaderVisitor visitor(find, replace);
731   Scene_ForEachSelectedBrushFace(graph, visitor);
732 }
733
734
735 class FaceFitTextureVisitor
736 {
737   float m_s_repeat, m_t_repeat;
738 public:
739   FaceFitTextureVisitor(float s_repeat, float t_repeat) : m_s_repeat(s_repeat), m_t_repeat(t_repeat)
740   {
741   }
742   void visit(Face& face) const
743   {
744     face.FitTexture(m_s_repeat, m_t_repeat);
745   }
746 };
747
748 void Scene_BrushFitTexture_Selected(scene::Graph& graph, float s_repeat, float t_repeat)
749 {
750   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceFitTextureVisitor(s_repeat, t_repeat));
751   SceneChangeNotify();
752 }
753
754 void Scene_BrushFitTexture_Component_Selected(scene::Graph& graph, float s_repeat, float t_repeat)
755 {
756   FaceFitTextureVisitor visitor(s_repeat, t_repeat);
757   Scene_ForEachSelectedBrushFace(graph, visitor);
758   SceneChangeNotify();
759 }
760
761
762 void Scene_BrushConstructPrefab(scene::Graph& graph, EBrushPrefab type, std::size_t sides, const char* shader)
763 {
764   if(GlobalSelectionSystem().countSelected() != 0)
765   {
766     const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
767
768     Brush* brush = Node_getBrush(path.top());
769     if(brush != 0)
770     {
771       AABB bounds = brush->localAABB();
772       TextureProjection projection;
773       TexDef_Construct_Default(projection);
774       Brush_ConstructPrefab(*brush, type, bounds, sides, shader, projection);
775       SceneChangeNotify();
776     }
777   }
778 }
779
780 void Scene_BrushResize_Selected(scene::Graph& graph, const AABB& bounds, const char* shader)
781 {
782   if(GlobalSelectionSystem().countSelected() != 0)
783   {
784     const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
785
786     Brush* brush = Node_getBrush(path.top());
787     if(brush != 0)
788     {
789       TextureProjection projection;
790       TexDef_Construct_Default(projection);
791       Brush_ConstructCuboid(*brush, bounds, shader, projection);
792       SceneChangeNotify();
793     }
794   }
795 }
796
797 bool Brush_hasShader(const Brush& brush, const char* name)
798 {
799   for(Brush::const_iterator i = brush.begin(); i != brush.end(); ++i)
800   {
801     if(shader_equal((*i)->GetShader(), name))
802     {
803       return true;
804     }
805   }
806   return false;
807 }
808
809 class BrushSelectByShaderWalker : public scene::Graph::Walker
810 {
811   const char* m_name;
812 public:
813   BrushSelectByShaderWalker(const char* name)
814     : m_name(name)
815   {
816   }
817   bool pre(const scene::Path& path, scene::Instance& instance) const
818   {
819     if(path.top().get().visible())
820     {
821       Brush* brush = Node_getBrush(path.top());
822       if(brush != 0 && Brush_hasShader(*brush, m_name))
823       {
824         Instance_getSelectable(instance)->setSelected(true);
825       }
826     }
827     return true;
828   }
829 };
830
831 void Scene_BrushSelectByShader(scene::Graph& graph, const char* name)
832 {
833   graph.traverse(BrushSelectByShaderWalker(name));
834 }
835
836 class FaceSelectByShaderVisitor : public BrushInstanceVisitor
837 {
838   const char* m_name;
839 public:
840   FaceSelectByShaderVisitor(const char* name)
841     : m_name(name)
842   {
843   }
844   void visit(FaceInstance& face) const
845   {
846     if(shader_equal(face.getFace().GetShader(), m_name))
847     {
848       face.setSelected(SelectionSystem::eFace, true);
849     }
850   }
851 };
852
853 void Scene_BrushSelectByShader_Component(scene::Graph& graph, const char* name)
854 {
855   Scene_ForEachSelectedBrush_ForEachFaceInstance(graph, FaceSelectByShaderVisitor(name));
856 }
857
858 class FaceGetTexdefVisitor
859 {
860   TextureProjection& m_projection;
861   mutable bool m_done;
862 public:
863   FaceGetTexdefVisitor(TextureProjection& projection)
864     : m_projection(projection), m_done(false)
865   {
866   }
867   void visit(Face& face) const
868   {
869     if(!m_done)
870     {
871       m_done = true;
872       FaceTexdef_getTexdef(face.getTexdef(), m_projection);
873     }
874   }
875 };
876
877
878 void Scene_BrushGetTexdef_Selected(scene::Graph& graph, TextureProjection& projection)
879 {
880   FaceGetTexdefVisitor visitor(projection);
881   Scene_ForEachSelectedBrush_ForEachFace(graph, visitor);
882 }
883
884 void Scene_BrushGetTexdef_Component_Selected(scene::Graph& graph, TextureProjection& projection)
885 {
886 #if 1
887   if(!g_SelectedFaceInstances.empty())
888   {
889     FaceInstance& faceInstance = g_SelectedFaceInstances.last();
890     FaceTexdef_getTexdef(faceInstance.getFace().getTexdef(), projection);
891   }
892 #else
893   FaceGetTexdefVisitor visitor(projection);
894   Scene_ForEachSelectedBrushFace(graph, visitor);
895 #endif
896 }
897
898
899 class FaceGetFlagsVisitor
900 {
901   ContentsFlagsValue& m_flags;
902   mutable bool m_done;
903 public:
904   FaceGetFlagsVisitor(ContentsFlagsValue& flags)
905     : m_flags(flags), m_done(false)
906   {
907   }
908   void visit(Face& face) const
909   {
910     if(!m_done)
911     {
912       m_done = true;
913       FaceShader_getFlags(face.getShader(), m_flags);
914     }
915   }
916 };
917
918
919 void Scene_BrushGetFlags_Selected(scene::Graph& graph, ContentsFlagsValue& flags)
920 {
921   FaceGetFlagsVisitor visitor(flags);
922   Scene_ForEachSelectedBrush_ForEachFace(graph, visitor);
923 }
924
925 void Scene_BrushGetFlags_Component_Selected(scene::Graph& graph, ContentsFlagsValue& flags)
926 {
927 #if 1
928   if(!g_SelectedFaceInstances.empty())
929   {
930     FaceInstance& faceInstance = g_SelectedFaceInstances.last();
931     FaceShader_getFlags(faceInstance.getFace().getShader(), flags);
932   }
933 #else
934   FaceGetFlagsVisitor visitor(flags);
935   Scene_ForEachSelectedBrushFace(graph, visitor);
936 #endif
937 }
938
939
940 class FaceGetShaderVisitor
941 {
942   CopiedString& m_shader;
943   mutable bool m_done;
944 public:
945   FaceGetShaderVisitor(CopiedString& shader)
946     : m_shader(shader), m_done(false)
947   {
948   }
949   void visit(Face& face) const
950   {
951     if(!m_done)
952     {
953       m_done = true;
954       m_shader = face.getShader().getShader();
955     }
956   }
957 };
958
959 void Scene_BrushGetShader_Selected(scene::Graph& graph, CopiedString& shader)
960 {
961   FaceGetShaderVisitor visitor(shader);
962   Scene_ForEachSelectedBrush_ForEachFace(graph, visitor);
963 }
964
965 void Scene_BrushGetShader_Component_Selected(scene::Graph& graph, CopiedString& shader)
966 {
967 #if 1
968   if(!g_SelectedFaceInstances.empty())
969   {
970     FaceInstance& faceInstance = g_SelectedFaceInstances.last();
971     shader = faceInstance.getFace().getShader().getShader();
972   }
973 #else
974   FaceGetShaderVisitor visitor(shader);
975   Scene_ForEachSelectedBrushFace(graph, visitor);
976 #endif
977 }
978
979
980 class filter_face_shader : public FaceFilter
981 {
982   const char* m_shader;
983 public:
984   filter_face_shader(const char* shader) : m_shader(shader)
985   {
986   }
987   bool filter(const Face& face) const
988   {
989     return shader_equal(face.GetShader(), m_shader);
990   }
991 };
992
993 class filter_face_shader_substring : public FaceFilter
994 {
995   const char* m_shader;
996 public:
997   filter_face_shader_substring(const char* shader) : m_shader(shader)
998   {
999   }
1000   bool filter(const Face& face) const
1001   {
1002     return shader_equal_n(face.GetShader(), m_shader, strlen(m_shader));
1003   }
1004 };
1005
1006 class filter_face_flags : public FaceFilter
1007 {
1008   int m_flags;
1009 public:
1010   filter_face_flags(int flags) : m_flags(flags)
1011   {
1012   }
1013   bool filter(const Face& face) const
1014   {
1015     return (face.getShader().shaderFlags() & m_flags) != 0;
1016   }
1017 };
1018
1019 class filter_face_contents : public FaceFilter
1020 {
1021   int m_contents;
1022 public:
1023   filter_face_contents(int contents) : m_contents(contents)
1024   {
1025   }
1026   bool filter(const Face& face) const
1027   {
1028     return (face.getShader().m_flags.m_contentFlags & m_contents) != 0;
1029   }
1030 };
1031
1032
1033
1034 class FaceFilterAnyVisitor : public BrushVisitor
1035 {
1036   FaceFilter* m_filter;
1037   bool& m_filtered;
1038 public:
1039   FaceFilterAnyVisitor(FaceFilter* filter, bool& filtered) : m_filter(filter), m_filtered(filtered)
1040   {
1041     m_filtered = false;
1042   }
1043   void visit(Face& face) const
1044   {
1045     if(m_filter->filter(face))
1046     {
1047       m_filtered = true;
1048     }
1049   }
1050 };
1051
1052 class filter_brush_any_face : public BrushFilter
1053 {
1054   FaceFilter* m_filter;
1055 public:
1056   filter_brush_any_face(FaceFilter* filter) : m_filter(filter)
1057   {
1058   }
1059   bool filter(const Brush& brush) const
1060   {
1061     bool filtered;
1062     brush.forEachFace(FaceFilterAnyVisitor(m_filter, filtered));
1063     return filtered;
1064   }   
1065 };
1066
1067 class FaceFilterAllVisitor : public BrushVisitor
1068 {
1069   FaceFilter* m_filter;
1070   bool& m_filtered;
1071 public:
1072   FaceFilterAllVisitor(FaceFilter* filter, bool& filtered) : m_filter(filter), m_filtered(filtered)
1073   {
1074     m_filtered = true;
1075   }
1076   void visit(Face& face) const
1077   {
1078     if(!m_filter->filter(face))
1079     {
1080       m_filtered = false;
1081     }
1082   }
1083 };
1084
1085 class filter_brush_all_faces : public BrushFilter
1086 {
1087   FaceFilter* m_filter;
1088 public:
1089   filter_brush_all_faces(FaceFilter* filter) : m_filter(filter)
1090   {
1091   }
1092   bool filter(const Brush& brush) const
1093   {
1094     bool filtered;
1095     brush.forEachFace(FaceFilterAllVisitor(m_filter, filtered));
1096     return filtered;
1097   }   
1098 };
1099
1100
1101 filter_face_flags g_filter_face_clip(QER_CLIP);
1102 filter_brush_all_faces g_filter_brush_clip(&g_filter_face_clip);
1103
1104 filter_face_shader g_filter_face_clip_q2("textures/clip");
1105 filter_brush_all_faces g_filter_brush_clip_q2(&g_filter_face_clip_q2);
1106
1107 filter_face_shader g_filter_face_weapclip("textures/common/weapclip");
1108 filter_brush_all_faces g_filter_brush_weapclip(&g_filter_face_weapclip);
1109
1110 filter_face_shader g_filter_face_botclip("textures/common/botclip");
1111 filter_brush_all_faces g_filter_brush_botclip(&g_filter_face_botclip);
1112
1113 filter_face_shader g_filter_face_caulk("textures/common/caulk");
1114 filter_brush_all_faces g_filter_brush_caulk(&g_filter_face_caulk);
1115
1116 filter_face_shader g_filter_face_caulk_ja("textures/system/caulk");
1117 filter_brush_all_faces g_filter_brush_caulk_ja(&g_filter_face_caulk_ja);
1118
1119 filter_face_shader_substring g_filter_face_liquids("textures/liquids/");
1120 filter_brush_any_face g_filter_brush_liquids(&g_filter_face_liquids);
1121
1122 filter_face_shader g_filter_face_hint("textures/common/hint");
1123 filter_brush_any_face g_filter_brush_hint(&g_filter_face_hint);
1124
1125 filter_face_shader g_filter_face_hint_q2("textures/hint");
1126 filter_brush_any_face g_filter_brush_hint_q2(&g_filter_face_hint_q2);
1127
1128 filter_face_shader g_filter_face_hint_ja("textures/system/hint");
1129 filter_brush_any_face g_filter_brush_hint_ja(&g_filter_face_hint_ja);
1130
1131 filter_face_shader g_filter_face_areaportal("textures/common/areaportal");
1132 filter_brush_all_faces g_filter_brush_areaportal(&g_filter_face_areaportal);
1133
1134 filter_face_shader g_filter_face_visportal("textures/editor/visportal");
1135 filter_brush_any_face g_filter_brush_visportal(&g_filter_face_visportal);
1136
1137 filter_face_shader g_filter_face_clusterportal("textures/common/clusterportal");
1138 filter_brush_all_faces g_filter_brush_clusterportal(&g_filter_face_clusterportal);
1139
1140 filter_face_shader g_filter_face_lightgrid("textures/common/lightgrid");
1141 filter_brush_all_faces g_filter_brush_lightgrid(&g_filter_face_lightgrid);
1142
1143 filter_face_flags g_filter_face_translucent(QER_TRANS);
1144 filter_brush_all_faces g_filter_brush_translucent(&g_filter_face_translucent);
1145
1146 filter_face_contents g_filter_face_detail(CONTENTS_DETAIL);
1147 filter_brush_all_faces g_filter_brush_detail(&g_filter_face_detail);
1148
1149
1150 void BrushFilters_construct()
1151 {
1152   add_brush_filter(g_filter_brush_clip, EXCLUDE_CLIP);
1153   add_brush_filter(g_filter_brush_clip_q2, EXCLUDE_CLIP);
1154   add_brush_filter(g_filter_brush_weapclip, EXCLUDE_CLIP);
1155   add_brush_filter(g_filter_brush_botclip, EXCLUDE_BOTCLIP);
1156   add_brush_filter(g_filter_brush_caulk, EXCLUDE_CAULK);
1157   add_brush_filter(g_filter_brush_caulk_ja, EXCLUDE_CAULK);
1158   add_brush_filter(g_filter_brush_liquids, EXCLUDE_LIQUIDS);
1159   add_brush_filter(g_filter_brush_hint, EXCLUDE_HINTSSKIPS);
1160   add_brush_filter(g_filter_brush_hint_q2, EXCLUDE_HINTSSKIPS);
1161   add_brush_filter(g_filter_brush_hint_ja, EXCLUDE_HINTSSKIPS);
1162   add_brush_filter(g_filter_brush_clusterportal, EXCLUDE_CLUSTERPORTALS);
1163   add_brush_filter(g_filter_brush_visportal, EXCLUDE_VISPORTALS);
1164   add_brush_filter(g_filter_brush_areaportal, EXCLUDE_AREAPORTALS);
1165   add_brush_filter(g_filter_brush_translucent, EXCLUDE_TRANSLUCENT);
1166   add_brush_filter(g_filter_brush_detail, EXCLUDE_DETAILS);
1167   add_brush_filter(g_filter_brush_detail, EXCLUDE_STRUCTURAL, true);
1168   add_brush_filter(g_filter_brush_lightgrid, EXCLUDE_LIGHTGRID);
1169 }
1170
1171 #if 0
1172
1173 void normalquantisation_draw()
1174 {
1175   glPointSize(1);
1176   glBegin(GL_POINTS);
1177   for(std::size_t i = 0; i <= c_quantise_normal; ++i)
1178   {
1179     for(std::size_t j = 0; j <= c_quantise_normal; ++j)
1180     {
1181       Normal3f vertex(normal3f_normalised(Normal3f(
1182         static_cast<float>(c_quantise_normal - j - i),
1183         static_cast<float>(i),
1184         static_cast<float>(j)
1185         )));
1186       VectorScale(normal3f_to_array(vertex), 64.f, normal3f_to_array(vertex));
1187       glVertex3fv(normal3f_to_array(vertex));
1188       vertex.x = -vertex.x;
1189       glVertex3fv(normal3f_to_array(vertex));
1190     }
1191   }
1192   glEnd();
1193 }
1194
1195 class RenderableNormalQuantisation : public OpenGLRenderable
1196 {
1197 public:
1198   void render(RenderStateFlags state) const
1199   {
1200     normalquantisation_draw();
1201   }
1202 };
1203
1204 const float g_test_quantise_normal = 1.f / static_cast<float>(1 << 3);
1205
1206 class TestNormalQuantisation
1207 {
1208   void check_normal(const Normal3f& normal, const Normal3f& other)
1209   {
1210     spherical_t spherical = spherical_from_normal3f(normal);
1211     double longditude = RAD2DEG(spherical.longditude);
1212     double latitude = RAD2DEG(spherical.latitude);
1213     double x = cos(spherical.longditude) * sin(spherical.latitude);
1214     double y = sin(spherical.longditude) * sin(spherical.latitude);
1215     double z = cos(spherical.latitude);
1216
1217     ASSERT_MESSAGE(normal3f_dot(normal, other) > 0.99, "bleh");
1218   }
1219
1220   void test_normal(const Normal3f& normal)
1221   {
1222     Normal3f test = normal3f_from_spherical(spherical_from_normal3f(normal));
1223     check_normal(normal, test);
1224
1225     EOctant octant = normal3f_classify_octant(normal);
1226     Normal3f folded = normal3f_fold_octant(normal, octant);
1227     ESextant sextant = normal3f_classify_sextant(folded);
1228     folded = normal3f_fold_sextant(folded, sextant);
1229
1230     double scale = static_cast<float>(c_quantise_normal) / (folded.x + folded.y + folded.z);
1231
1232     double zbits = folded.z * scale;
1233     double ybits = folded.y * scale;
1234
1235     std::size_t zbits_q = static_cast<std::size_t>(zbits);
1236     std::size_t ybits_q = static_cast<std::size_t>(ybits);
1237
1238     ASSERT_MESSAGE(zbits_q <= (c_quantise_normal / 8) * 3, "bleh");
1239     ASSERT_MESSAGE(ybits_q <= (c_quantise_normal / 2), "bleh");
1240     ASSERT_MESSAGE(zbits_q + ((c_quantise_normal / 2) - ybits_q) <= (c_quantise_normal / 2), "bleh");
1241
1242     std::size_t y_t = (zbits_q < (c_quantise_normal / 4)) ? ybits_q : (c_quantise_normal / 2) - ybits_q;
1243     std::size_t z_t = (zbits_q < (c_quantise_normal / 4)) ? zbits_q : (c_quantise_normal / 2) - zbits_q;
1244     std::size_t index = (c_quantise_normal / 4) * y_t + z_t;
1245     ASSERT_MESSAGE(index <= (c_quantise_normal / 4)*(c_quantise_normal / 2), "bleh");
1246
1247     Normal3f tmp(c_quantise_normal - zbits_q - ybits_q, ybits_q, zbits_q);
1248     tmp = normal3f_normalised(tmp);
1249
1250     Normal3f unfolded = normal3f_unfold_octant(normal3f_unfold_sextant(tmp, sextant), octant);
1251
1252     check_normal(normal, unfolded);
1253
1254     double dot = normal3f_dot(normal, unfolded);
1255     float length = VectorLength(normal3f_to_array(unfolded));
1256     float inv_length = 1 / length;
1257
1258     Normal3f quantised = normal3f_quantised(normal);
1259     check_normal(normal, quantised);
1260   }
1261   void test2(const Normal3f& normal, const Normal3f& other)
1262   {
1263     if(normal3f_quantised(normal) != normal3f_quantised(other))
1264     {
1265       int bleh = 0;
1266     }
1267   }
1268
1269   static Normal3f normalise(float x, float y, float z)
1270   {
1271     return normal3f_normalised(Normal3f(x, y, z));
1272   }
1273
1274   float vec_rand()
1275   {
1276     return static_cast<float>(rand() - (RAND_MAX/2));
1277   }
1278
1279   Normal3f normal3f_rand()
1280   {
1281     return normalise(vec_rand(), vec_rand(), vec_rand());
1282   }
1283
1284 public:
1285   TestNormalQuantisation()
1286   {
1287     for(int i = 4096; i > 0; --i)
1288       test_normal(normal3f_rand());
1289
1290     test_normal(normalise(1, 0, 0));
1291     test_normal(normalise(0, 1, 0));
1292     test_normal(normalise(0, 0, 1));
1293     test_normal(normalise(1, 1, 0));
1294     test_normal(normalise(1, 0, 1));
1295     test_normal(normalise(0, 1, 1));
1296     
1297     test_normal(normalise(10000, 10000, 10000));
1298     test_normal(normalise(10000, 10000, 10001));
1299     test_normal(normalise(10000, 10000, 10002));
1300     test_normal(normalise(10000, 10000, 10010));
1301     test_normal(normalise(10000, 10000, 10020));
1302     test_normal(normalise(10000, 10000, 10030));
1303     test_normal(normalise(10000, 10000, 10100));
1304     test_normal(normalise(10000, 10000, 10101));
1305     test_normal(normalise(10000, 10000, 10102));
1306     test_normal(normalise(10000, 10000, 10200));
1307     test_normal(normalise(10000, 10000, 10201));
1308     test_normal(normalise(10000, 10000, 10202));
1309     test_normal(normalise(10000, 10000, 10203));
1310     test_normal(normalise(10000, 10000, 10300));
1311
1312
1313     test2(normalise(10000, 10000, 10000), normalise(10000, 10000, 10001));
1314     test2(normalise(10000, 10000, 10001), normalise(10000, 10001, 10000));
1315   }
1316 };
1317
1318 TestNormalQuantisation g_testNormalQuantisation;
1319
1320
1321 #endif
1322
1323 #if 0
1324 class TestSelectableObserver : public observer_template<const Selectable&>
1325 {
1326 public:
1327   void notify(const Selectable& arguments)
1328   {
1329     bool bleh = arguments.isSelected();
1330   }
1331 };
1332
1333 inline void test_bleh()
1334 {
1335   TestSelectableObserver test;
1336   ObservableSelectableInstance< SingleObservable< SelectionChangeCallback > > bleh;
1337   bleh.attach(test);
1338   bleh.setSelected(true);
1339   bleh.detach(test);
1340 }
1341
1342 class TestBleh
1343 {
1344 public:
1345   TestBleh()
1346   {
1347     test_bleh();
1348   }
1349 };
1350
1351 const TestBleh testbleh;
1352 #endif
1353
1354
1355 #if 0
1356 class TestRefcountedString
1357 {
1358 public:
1359   TestRefcountedString()
1360   {
1361     {
1362       // copy construct
1363       SmartString string1("string1");
1364       SmartString string2(string1);
1365       SmartString string3(string2);
1366     }
1367     {
1368       // refcounted assignment
1369       SmartString string1("string1");
1370       SmartString string2("string2");
1371       string1 = string2;
1372     }
1373     {
1374       // copy assignment
1375       SmartString string1("string1");
1376       SmartString string2("string2");
1377       string1 = string2.c_str();
1378     }
1379     {
1380       // self-assignment
1381       SmartString string1("string1");
1382       string1 = string1;
1383     }
1384     {
1385       // self-assignment via another reference
1386       SmartString string1("string1");
1387       SmartString string2(string1);
1388       string1 = string2;
1389     }
1390   }
1391 };
1392
1393 const TestRefcountedString g_testRefcountedString;
1394
1395 #endif
1396
1397 void Select_MakeDetail()
1398 {
1399   UndoableCommand undo("brushSetDetail");
1400   Scene_BrushSetDetail_Selected(GlobalSceneGraph(), true);
1401 }
1402
1403 void Select_MakeStructural()
1404 {
1405   UndoableCommand undo("brushClearDetail");
1406   Scene_BrushSetDetail_Selected(GlobalSceneGraph(), false);
1407 }
1408
1409 class BrushMakeSided
1410 {
1411   std::size_t m_count;
1412 public:
1413   BrushMakeSided(std::size_t count)
1414     : m_count(count)
1415   {
1416   }
1417   void set()
1418   {
1419     Scene_BrushConstructPrefab(GlobalSceneGraph(), eBrushPrism, m_count, TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
1420   }
1421   typedef MemberCaller<BrushMakeSided, &BrushMakeSided::set> SetCaller;
1422 };
1423
1424
1425 BrushMakeSided g_brushmakesided3(3);
1426 BrushMakeSided g_brushmakesided4(4);
1427 BrushMakeSided g_brushmakesided5(5);
1428 BrushMakeSided g_brushmakesided6(6);
1429 BrushMakeSided g_brushmakesided7(7);
1430 BrushMakeSided g_brushmakesided8(8);
1431 BrushMakeSided g_brushmakesided9(9);
1432
1433 inline int axis_for_viewtype(int viewtype)
1434 {
1435   switch(viewtype)
1436   {
1437     case XY:
1438       return 2;
1439     case XZ:
1440       return 1;
1441     case YZ:
1442       return 0;
1443   }
1444   return 2;
1445 }
1446
1447 class BrushPrefab
1448 {
1449   EBrushPrefab m_type;
1450 public:
1451   BrushPrefab(EBrushPrefab type)
1452     : m_type(type)
1453   {
1454   }
1455   void set()
1456   {
1457     DoSides(m_type, axis_for_viewtype(GetViewAxis()));
1458   }
1459   typedef MemberCaller<BrushPrefab, &BrushPrefab::set> SetCaller;
1460 };
1461
1462 BrushPrefab g_brushprism(eBrushPrism);
1463 BrushPrefab g_brushcone(eBrushCone);
1464 BrushPrefab g_brushsphere(eBrushSphere);
1465
1466
1467 void FlipClip();
1468 void SplitClip();
1469 void Clip();
1470 void OnClipMode(bool enable);
1471 bool ClipMode();
1472
1473
1474 void ClipSelected()
1475 {
1476   if(ClipMode())
1477   {
1478     UndoableCommand undo("clipperClip");
1479     Clip();
1480   }
1481 }
1482
1483 void SplitSelected()
1484 {
1485   if(ClipMode())
1486   {
1487     UndoableCommand undo("clipperSplit");
1488     SplitClip();
1489   }
1490 }
1491
1492 void FlipClipper()
1493 {
1494   FlipClip();
1495 }
1496
1497
1498 Callback g_texture_lock_status_changed;
1499 BoolExportCaller g_texdef_movelock_caller(g_brush_texturelock_enabled);
1500 ToggleItem g_texdef_movelock_item(g_texdef_movelock_caller);
1501
1502 void Texdef_ToggleMoveLock()
1503 {
1504   g_brush_texturelock_enabled = !g_brush_texturelock_enabled;
1505   g_texdef_movelock_item.update();
1506   g_texture_lock_status_changed();
1507 }
1508
1509
1510
1511
1512 void Face_getClosest(Face& face, SelectionTest& test, SelectionIntersection& bestIntersection, Face*& closestFace)
1513 {
1514   SelectionIntersection intersection;
1515   face.testSelect(test, intersection);
1516   if(intersection.valid()
1517     && SelectionIntersection_closer(intersection, bestIntersection))
1518   {
1519     bestIntersection = intersection;
1520     closestFace = &face;
1521   }
1522 }
1523
1524
1525 class OccludeSelector : public Selector
1526 {
1527   SelectionIntersection& m_bestIntersection;
1528   bool& m_occluded;
1529 public:
1530   OccludeSelector(SelectionIntersection& bestIntersection, bool& occluded) : m_bestIntersection(bestIntersection), m_occluded(occluded)
1531   {
1532     m_occluded = false;
1533   }
1534   void pushSelectable(Selectable& selectable)
1535   {
1536   }
1537   void popSelectable()
1538   {
1539   }
1540   void addIntersection(const SelectionIntersection& intersection)
1541   {
1542     if(SelectionIntersection_closer(intersection, m_bestIntersection))
1543     {
1544       m_bestIntersection = intersection;
1545       m_occluded = true;
1546     }
1547   }
1548 };
1549
1550 class BrushGetClosestFaceVisibleWalker : public scene::Graph::Walker
1551 {
1552   SelectionTest& m_test;
1553   Face*& m_closestFace;
1554   mutable SelectionIntersection m_bestIntersection;
1555 public:
1556   BrushGetClosestFaceVisibleWalker(SelectionTest& test, Face*& closestFace) : m_test(test), m_closestFace(closestFace)
1557   {
1558   }
1559   bool pre(const scene::Path& path, scene::Instance& instance) const
1560   {
1561     if(path.top().get().visible())
1562     {
1563       BrushInstance* brush = Instance_getBrush(instance);
1564       if(brush != 0)
1565       {
1566         m_test.BeginMesh(brush->localToWorld());
1567
1568         for(Brush::const_iterator i = brush->getBrush().begin(); i != brush->getBrush().end(); ++i)
1569         {
1570           Face_getClosest(*(*i), m_test, m_bestIntersection, m_closestFace);
1571         }
1572       }
1573       else
1574       {
1575         SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
1576         if(selectionTestable)
1577         {
1578           bool occluded;
1579           OccludeSelector selector(m_bestIntersection, occluded);
1580           selectionTestable->testSelect(selector, m_test);
1581           if(occluded)
1582           {
1583             m_closestFace = 0;
1584           }
1585         }
1586       }
1587     }
1588     return true;
1589   }
1590 };
1591
1592 Face* Scene_BrushGetClosestFace(scene::Graph& graph, SelectionTest& test)
1593 {
1594   Face* closestFace = 0;
1595   graph.traverse(BrushGetClosestFaceVisibleWalker(test, closestFace));
1596   return closestFace;
1597 }
1598
1599 bool Scene_BrushGetClosestFaceTexture(scene::Graph& graph, SelectionTest& test, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags)
1600 {
1601   Face* face = Scene_BrushGetClosestFace(graph, test);
1602   if(face != 0)
1603   {
1604     shader = face->GetShader();
1605     FaceTexdef_getTexdef(face->getTexdef(), projection);
1606     flags = face->getShader().m_flags;
1607     return true;
1608   }
1609   return false;
1610 }
1611
1612 void Scene_BrushSetClosestFaceTexture(scene::Graph& graph, SelectionTest& test, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags)
1613 {
1614   Face* face = Scene_BrushGetClosestFace(graph, test);
1615   if(face != 0)
1616   {
1617     face->SetShader(shader);
1618     face->SetTexdef(projection);
1619     face->SetFlags(flags);
1620   }
1621 }
1622
1623
1624 class FaceTexture
1625 {
1626 public:
1627   TextureProjection m_projection;
1628   ContentsFlagsValue m_flags;
1629 };
1630
1631 FaceTexture g_faceTextureClipboard;
1632
1633 void FaceTextureClipboard_setDefault()
1634 {
1635   g_faceTextureClipboard.m_flags = ContentsFlagsValue(0, 0, 0, false);
1636   TexDef_Construct_Default(g_faceTextureClipboard.m_projection);
1637 }
1638
1639 void TextureClipboard_textureSelected(const char* shader)
1640 {
1641   FaceTextureClipboard_setDefault();
1642 }
1643
1644 class TextureBrowser;
1645 extern TextureBrowser g_TextureBrowser;
1646 void TextureBrowser_SetSelectedShader(TextureBrowser& textureBrowser, const char* shader);
1647 const char* TextureBrowser_GetSelectedShader(TextureBrowser& textureBrowser);
1648
1649 void Scene_copyClosestFaceTexture(SelectionTest& test)
1650 {
1651   CopiedString shader;
1652   if(Scene_BrushGetClosestFaceTexture(GlobalSceneGraph(), test, shader, g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags))
1653   {
1654     TextureBrowser_SetSelectedShader(g_TextureBrowser, shader.c_str());
1655   }
1656 }
1657
1658 void Scene_applyClosestFaceTexture(SelectionTest& test)
1659 {
1660   UndoableCommand command("facePaintTexture");
1661
1662   Scene_BrushSetClosestFaceTexture(GlobalSceneGraph(), test, TextureBrowser_GetSelectedShader(g_TextureBrowser), g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags);
1663
1664   SceneChangeNotify();
1665 }
1666
1667
1668
1669 void SelectedFaces_copyTexture()
1670 {
1671   if(!g_SelectedFaceInstances.empty())
1672   {
1673     Face& face = g_SelectedFaceInstances.last().getFace();
1674     FaceTexdef_getTexdef(face.getTexdef(), g_faceTextureClipboard.m_projection);
1675     g_faceTextureClipboard.m_flags = face.getShader().m_flags;
1676
1677     TextureBrowser_SetSelectedShader(g_TextureBrowser, face.getShader().getShader());
1678   }
1679 }
1680
1681 void FaceInstance_pasteTexture(FaceInstance& faceInstance)
1682 {
1683   faceInstance.getFace().SetTexdef(g_faceTextureClipboard.m_projection);
1684   faceInstance.getFace().SetShader(TextureBrowser_GetSelectedShader(g_TextureBrowser));
1685   faceInstance.getFace().SetFlags(g_faceTextureClipboard.m_flags);
1686   SceneChangeNotify();
1687 }
1688
1689 bool SelectedFaces_empty()
1690 {
1691   return g_SelectedFaceInstances.empty();
1692 }
1693
1694 void SelectedFaces_pasteTexture()
1695 {
1696   UndoableCommand command("facePasteTexture");
1697   g_SelectedFaceInstances.foreach(FaceInstance_pasteTexture);
1698 }
1699
1700 void Brush_registerCommands()
1701 {
1702   GlobalToggles_insert("TogTexLock", FreeCaller<Texdef_ToggleMoveLock>(), ToggleItem::AddCallbackCaller(g_texdef_movelock_item), Accelerator('T', (GdkModifierType)GDK_SHIFT_MASK));
1703
1704   GlobalCommands_insert("BrushPrism", BrushPrefab::SetCaller(g_brushprism));
1705   GlobalCommands_insert("BrushCone", BrushPrefab::SetCaller(g_brushcone));
1706   GlobalCommands_insert("BrushSphere", BrushPrefab::SetCaller(g_brushsphere));
1707
1708   GlobalCommands_insert("Brush3Sided", BrushMakeSided::SetCaller(g_brushmakesided3), Accelerator('3', (GdkModifierType)GDK_CONTROL_MASK));
1709   GlobalCommands_insert("Brush4Sided", BrushMakeSided::SetCaller(g_brushmakesided4), Accelerator('4', (GdkModifierType)GDK_CONTROL_MASK));
1710   GlobalCommands_insert("Brush5Sided", BrushMakeSided::SetCaller(g_brushmakesided5), Accelerator('5', (GdkModifierType)GDK_CONTROL_MASK));
1711   GlobalCommands_insert("Brush6Sided", BrushMakeSided::SetCaller(g_brushmakesided6), Accelerator('6', (GdkModifierType)GDK_CONTROL_MASK));
1712   GlobalCommands_insert("Brush7Sided", BrushMakeSided::SetCaller(g_brushmakesided7), Accelerator('7', (GdkModifierType)GDK_CONTROL_MASK));
1713   GlobalCommands_insert("Brush8Sided", BrushMakeSided::SetCaller(g_brushmakesided8), Accelerator('8', (GdkModifierType)GDK_CONTROL_MASK));
1714   GlobalCommands_insert("Brush9Sided", BrushMakeSided::SetCaller(g_brushmakesided9), Accelerator('9', (GdkModifierType)GDK_CONTROL_MASK));
1715
1716   GlobalCommands_insert("ClipSelected", FreeCaller<ClipSelected>(), Accelerator(GDK_Return));
1717   GlobalCommands_insert("SplitSelected", FreeCaller<SplitSelected>(), Accelerator(GDK_Return, (GdkModifierType)GDK_SHIFT_MASK));
1718   GlobalCommands_insert("FlipClip", FreeCaller<FlipClipper>(), Accelerator(GDK_Return, (GdkModifierType)GDK_CONTROL_MASK));
1719
1720   GlobalCommands_insert("FaceCopyTexture", FreeCaller<SelectedFaces_copyTexture>());
1721   GlobalCommands_insert("FacePasteTexture", FreeCaller<SelectedFaces_pasteTexture>());
1722
1723   GlobalCommands_insert("MakeDetail", FreeCaller<Select_MakeDetail>(), Accelerator('M', (GdkModifierType)GDK_CONTROL_MASK));
1724   GlobalCommands_insert("MakeStructural", FreeCaller<Select_MakeStructural>(), Accelerator('S', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
1725 }
1726
1727 void Brush_constructMenu(GtkMenu* menu)
1728 {
1729   create_menu_item_with_mnemonic(menu, "Prism...", "BrushPrism");
1730   create_menu_item_with_mnemonic(menu, "Cone...", "BrushCone");
1731   create_menu_item_with_mnemonic(menu, "Sphere...", "BrushSphere");
1732   menu_separator (menu);
1733   {
1734     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "CSG");
1735     create_menu_item_with_mnemonic(menu_in_menu, "Make _Hollow", "CSGHollow");
1736     create_menu_item_with_mnemonic(menu_in_menu, "CSG _Subtract", "CSGSubtract");
1737     create_menu_item_with_mnemonic(menu_in_menu, "CSG _Merge", "CSGMerge");
1738   }
1739   menu_separator(menu);
1740   {
1741     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "Clipper");
1742
1743     create_menu_item_with_mnemonic(menu_in_menu, "Clip selection", "ClipSelected");
1744     create_menu_item_with_mnemonic(menu_in_menu, "Split selection", "SplitSelected");
1745     create_menu_item_with_mnemonic(menu_in_menu, "Flip Clip orientation", "FlipClip");
1746   }
1747   menu_separator(menu);
1748   create_menu_item_with_mnemonic(menu, "Make detail", "MakeDetail");
1749   create_menu_item_with_mnemonic(menu, "Make structural", "MakeStructural");
1750
1751   create_check_menu_item_with_mnemonic(menu, "Texture Lock", "TogTexLock");
1752   menu_separator(menu);
1753   create_menu_item_with_mnemonic(menu, "Copy Face Texture", "FaceCopyTexture");
1754   create_menu_item_with_mnemonic(menu, "Paste Face Texture", "FacePasteTexture");
1755
1756   command_connect_accelerator("Brush3Sided");
1757   command_connect_accelerator("Brush4Sided");
1758   command_connect_accelerator("Brush5Sided");
1759   command_connect_accelerator("Brush6Sided");
1760   command_connect_accelerator("Brush7Sided");
1761   command_connect_accelerator("Brush8Sided");
1762   command_connect_accelerator("Brush9Sided");
1763 }