]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/brushmanip.cpp
b701ca4fb78d0d2b82e843ffea4e8cfe5fc819b1
[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 template<class Visitor>
409 class FaceVisitSelected : public BrushInstanceVisitor
410 {
411   const Visitor& m_visitor;
412 public:
413   FaceVisitSelected(const Visitor& visitor)
414     : m_visitor(visitor)
415   {
416   }
417   void visit(FaceInstance& face) const
418   {
419     if(face.isSelected(SelectionSystem::eFace))
420     {
421       m_visitor.visit(face.getFace());
422     }
423   }
424 };
425
426 template<typename Functor>
427 inline void Scene_forEachBrush(scene::Graph& graph, const Functor& functor)
428 {
429   graph.traverse(InstanceWalker< InstanceApply<BrushInstance, Functor> >(functor));
430 }
431
432 template<typename Type, typename Functor>
433 class InstanceIfVisible : public Functor
434 {
435 public:
436   InstanceIfVisible(const Functor& functor) : Functor(functor)
437   {
438   }
439   void operator()(scene::Instance& instance)
440   {
441     if(instance.path().top().get().visible())
442     {
443       Functor::operator()(instance);
444     }
445   }
446 };
447
448 template<typename Functor>
449 class BrushVisibleWalker : public scene::Graph::Walker
450 {
451   const Functor& m_functor;
452 public:
453   BrushVisibleWalker(const Functor& functor) : m_functor(functor)
454   {
455   }
456   bool pre(const scene::Path& path, scene::Instance& instance) const
457   {
458     if(path.top().get().visible())
459     {
460       BrushInstance* brush = Instance_getBrush(instance);
461       if(brush != 0)
462       {
463         m_functor(*brush);
464       }
465     }
466     return true;
467   }
468 };
469
470 template<typename Functor>
471 inline void Scene_forEachVisibleBrush(scene::Graph& graph, const Functor& functor)
472 {
473   graph.traverse(BrushVisibleWalker<Functor>(functor));
474 }
475
476 template<typename Visitor>
477 inline void Scene_ForEachBrush_ForEachFace(scene::Graph& graph, const Visitor& visitor)
478 {
479   Scene_forEachBrush(graph, BrushForEachFace(FaceVisitAll<Visitor>(visitor)));
480 }
481
482 template<typename Visitor>
483 inline void Scene_ForEachSelectedBrush_ForEachFace(scene::Graph& graph, const Visitor& visitor)
484 {
485   Scene_forEachSelectedBrush(BrushForEachFace(FaceVisitAll<Visitor>(visitor)));
486 }
487
488 template<typename Visitor>
489 inline void Scene_ForEachSelectedBrush_ForEachFaceInstance(scene::Graph& graph, const Visitor& visitor)
490 {
491   Scene_forEachSelectedBrush(BrushForEachFace(FaceInstanceVisitAll<Visitor>(visitor)));
492 }
493
494 template<typename Visitor>
495 class FaceVisitorWrapper
496 {
497   Visitor& m_visitor;
498 public:
499   FaceVisitorWrapper(Visitor& visitor) : m_visitor(visitor)
500   {
501   }
502
503   void operator()(FaceInstance& faceInstance)
504   {
505     m_visitor.visit(faceInstance.getFace());
506   }
507 };
508
509 template<typename Visitor>
510 inline void Scene_ForEachSelectedBrushFace(scene::Graph& graph, Visitor& faceVisitor)
511 {
512   g_SelectedFaceInstances.foreach(FaceVisitorWrapper<Visitor>(faceVisitor));
513 }
514
515
516
517 class FaceSetTexdefVisitor
518 {
519   const TextureProjection& m_projection;
520 public:
521   FaceSetTexdefVisitor(const TextureProjection& projection) : m_projection(projection)
522   {
523   }
524   void visit(Face& face) const
525   {
526     face.SetTexdef(m_projection);
527   }
528 };
529
530 void Scene_BrushSetTexdef_Selected(scene::Graph& graph, const TextureProjection& projection)
531 {
532   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceSetTexdefVisitor(projection));
533   SceneChangeNotify();
534 }
535
536 void Scene_BrushSetTexdef_Component_Selected(scene::Graph& graph, const TextureProjection& projection)
537 {
538   FaceSetTexdefVisitor visitor(projection);
539   Scene_ForEachSelectedBrushFace(graph, visitor);
540   SceneChangeNotify();
541 }
542
543
544 class FaceSetFlagsVisitor
545 {
546   const ContentsFlagsValue& m_projection;
547 public:
548   FaceSetFlagsVisitor(const ContentsFlagsValue& flags) : m_projection(flags)
549   {
550   }
551   void visit(Face& face) const
552   {
553     face.SetFlags(m_projection);
554   }
555 };
556
557 void Scene_BrushSetFlags_Selected(scene::Graph& graph, const ContentsFlagsValue& flags)
558 {
559   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceSetFlagsVisitor(flags));
560   SceneChangeNotify();
561 }
562
563 void Scene_BrushSetFlags_Component_Selected(scene::Graph& graph, const ContentsFlagsValue& flags)
564 {
565   FaceSetFlagsVisitor visitor(flags);
566   Scene_ForEachSelectedBrushFace(graph, visitor);
567   SceneChangeNotify();
568 }
569
570 class FaceShiftTexdefVisitor
571 {
572   float m_s, m_t;
573 public:
574   FaceShiftTexdefVisitor(float s, float t) : m_s(s), m_t(t)
575   {
576   }
577   void visit(Face& face) const
578   {
579     face.ShiftTexdef(m_s, m_t);
580   }
581 };
582
583 void Scene_BrushShiftTexdef_Selected(scene::Graph& graph, float s, float t)
584 {
585   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceShiftTexdefVisitor(s, t));
586   SceneChangeNotify();
587 }
588
589 void Scene_BrushShiftTexdef_Component_Selected(scene::Graph& graph, float s, float t)
590 {
591   FaceShiftTexdefVisitor visitor(s, t);
592   Scene_ForEachSelectedBrushFace(graph, visitor);
593   SceneChangeNotify();
594 }
595
596 class FaceScaleTexdefVisitor
597 {
598   float m_s, m_t;
599 public:
600   FaceScaleTexdefVisitor(float s, float t) : m_s(s), m_t(t)
601   {
602   }
603   void visit(Face& face) const
604   {
605     face.ScaleTexdef(m_s, m_t);
606   }
607 };
608
609 void Scene_BrushScaleTexdef_Selected(scene::Graph& graph, float s, float t)
610 {
611   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceScaleTexdefVisitor(s, t));
612   SceneChangeNotify();
613 }
614
615 void Scene_BrushScaleTexdef_Component_Selected(scene::Graph& graph, float s, float t)
616 {
617   FaceScaleTexdefVisitor visitor(s, t);
618   Scene_ForEachSelectedBrushFace(graph, visitor);
619   SceneChangeNotify();
620 }
621
622 class FaceRotateTexdefVisitor
623 {
624   float m_angle;
625 public:
626   FaceRotateTexdefVisitor(float angle) : m_angle(angle)
627   {
628   }
629   void visit(Face& face) const
630   {
631     face.RotateTexdef(m_angle);
632   }
633 };
634
635 void Scene_BrushRotateTexdef_Selected(scene::Graph& graph, float angle)
636 {
637   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceRotateTexdefVisitor(angle));
638   SceneChangeNotify();
639 }
640
641 void Scene_BrushRotateTexdef_Component_Selected(scene::Graph& graph, float angle)
642 {
643   FaceRotateTexdefVisitor visitor(angle);
644   Scene_ForEachSelectedBrushFace(graph, visitor);
645   SceneChangeNotify();
646 }
647
648
649 class FaceSetShaderVisitor
650 {
651   const char* m_name;
652 public:
653   FaceSetShaderVisitor(const char* name) : m_name(name) {}
654   void visit(Face& face) const
655   {
656     face.SetShader(m_name);
657   }
658 };
659
660 void Scene_BrushSetShader_Selected(scene::Graph& graph, const char* name)
661 {
662   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceSetShaderVisitor(name));
663   SceneChangeNotify();
664 }
665
666 void Scene_BrushSetShader_Component_Selected(scene::Graph& graph, const char* name)
667 {
668   FaceSetShaderVisitor visitor(name);
669   Scene_ForEachSelectedBrushFace(graph, visitor);
670   SceneChangeNotify();
671 }
672
673 class FaceSetDetailVisitor
674 {
675   bool m_detail;
676 public:
677   FaceSetDetailVisitor(bool detail) : m_detail(detail)
678   {
679   }
680   void visit(Face& face) const
681   {
682     face.setDetail(m_detail);
683   }
684 };
685
686 void Scene_BrushSetDetail_Selected(scene::Graph& graph, bool detail)
687 {
688   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceSetDetailVisitor(detail));
689   SceneChangeNotify();
690 }
691
692 bool Face_FindReplaceShader(Face& face, const char* find, const char* replace)
693 {
694   if(shader_equal(face.GetShader(), find))
695   {
696     face.SetShader(replace);
697     return true;
698   }
699   return false;
700 }
701
702 class FaceFindReplaceShaderVisitor
703 {
704   const char* m_find;
705   const char* m_replace;
706 public:
707   FaceFindReplaceShaderVisitor(const char* find, const char* replace) : m_find(find), m_replace(replace)
708   {
709   }
710   void visit(Face& face) const
711   {
712     Face_FindReplaceShader(face, m_find, m_replace);
713   }
714 };
715
716 void Scene_BrushFindReplaceShader(scene::Graph& graph, const char* find, const char* replace)
717 {
718   Scene_ForEachBrush_ForEachFace(graph, FaceFindReplaceShaderVisitor(find, replace));
719 }
720
721 void Scene_BrushFindReplaceShader_Selected(scene::Graph& graph, const char* find, const char* replace)
722 {
723   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceFindReplaceShaderVisitor(find, replace));
724 }
725
726 void Scene_BrushFindReplaceShader_Component_Selected(scene::Graph& graph, const char* find, const char* replace)
727 {
728   FaceFindReplaceShaderVisitor visitor(find, replace);
729   Scene_ForEachSelectedBrushFace(graph, visitor);
730 }
731
732
733 class FaceFitTextureVisitor
734 {
735   float m_s_repeat, m_t_repeat;
736 public:
737   FaceFitTextureVisitor(float s_repeat, float t_repeat) : m_s_repeat(s_repeat), m_t_repeat(t_repeat)
738   {
739   }
740   void visit(Face& face) const
741   {
742     face.FitTexture(m_s_repeat, m_t_repeat);
743   }
744 };
745
746 void Scene_BrushFitTexture_Selected(scene::Graph& graph, float s_repeat, float t_repeat)
747 {
748   Scene_ForEachSelectedBrush_ForEachFace(graph, FaceFitTextureVisitor(s_repeat, t_repeat));
749   SceneChangeNotify();
750 }
751
752 void Scene_BrushFitTexture_Component_Selected(scene::Graph& graph, float s_repeat, float t_repeat)
753 {
754   FaceFitTextureVisitor visitor(s_repeat, t_repeat);
755   Scene_ForEachSelectedBrushFace(graph, visitor);
756   SceneChangeNotify();
757 }
758
759
760 void Scene_BrushConstructPrefab(scene::Graph& graph, EBrushPrefab type, std::size_t sides, const char* shader)
761 {
762   if(GlobalSelectionSystem().countSelected() != 0)
763   {
764     const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
765
766     Brush* brush = Node_getBrush(path.top());
767     if(brush != 0)
768     {
769       AABB bounds = brush->localAABB();
770       TextureProjection projection;
771       TexDef_Construct_Default(projection);
772       Brush_ConstructPrefab(*brush, type, bounds, sides, shader, projection);
773       SceneChangeNotify();
774     }
775   }
776 }
777
778 void Scene_BrushResize_Selected(scene::Graph& graph, const AABB& bounds, const char* shader)
779 {
780   if(GlobalSelectionSystem().countSelected() != 0)
781   {
782     const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
783
784     Brush* brush = Node_getBrush(path.top());
785     if(brush != 0)
786     {
787       TextureProjection projection;
788       TexDef_Construct_Default(projection);
789       Brush_ConstructCuboid(*brush, bounds, shader, projection);
790       SceneChangeNotify();
791     }
792   }
793 }
794
795 bool Brush_hasShader(const Brush& brush, const char* name)
796 {
797   for(Brush::const_iterator i = brush.begin(); i != brush.end(); ++i)
798   {
799     if(shader_equal((*i)->GetShader(), name))
800     {
801       return true;
802     }
803   }
804   return false;
805 }
806
807 class BrushSelectByShaderWalker : public scene::Graph::Walker
808 {
809   const char* m_name;
810 public:
811   BrushSelectByShaderWalker(const char* name)
812     : m_name(name)
813   {
814   }
815   bool pre(const scene::Path& path, scene::Instance& instance) const
816   {
817     if(path.top().get().visible())
818     {
819       Brush* brush = Node_getBrush(path.top());
820       if(brush != 0 && Brush_hasShader(*brush, m_name))
821       {
822         Instance_getSelectable(instance)->setSelected(true);
823       }
824     }
825     return true;
826   }
827 };
828
829 void Scene_BrushSelectByShader(scene::Graph& graph, const char* name)
830 {
831   graph.traverse(BrushSelectByShaderWalker(name));
832 }
833
834 class FaceSelectByShaderVisitor : public BrushInstanceVisitor
835 {
836   const char* m_name;
837 public:
838   FaceSelectByShaderVisitor(const char* name)
839     : m_name(name)
840   {
841   }
842   void visit(FaceInstance& face) const
843   {
844     if(shader_equal(face.getFace().GetShader(), m_name))
845     {
846       face.setSelected(SelectionSystem::eFace, true);
847     }
848   }
849 };
850
851 void Scene_BrushSelectByShader_Component(scene::Graph& graph, const char* name)
852 {
853   Scene_ForEachSelectedBrush_ForEachFaceInstance(graph, FaceSelectByShaderVisitor(name));
854 }
855
856 class FaceGetTexdefVisitor
857 {
858   TextureProjection& m_projection;
859   mutable bool m_done;
860 public:
861   FaceGetTexdefVisitor(TextureProjection& projection)
862     : m_projection(projection), m_done(false)
863   {
864   }
865   void visit(Face& face) const
866   {
867     if(!m_done)
868     {
869       m_done = true;
870       FaceTexdef_getTexdef(face.getTexdef(), m_projection);
871     }
872   }
873 };
874
875
876 void Scene_BrushGetTexdef_Selected(scene::Graph& graph, TextureProjection& projection)
877 {
878   FaceGetTexdefVisitor visitor(projection);
879   Scene_ForEachSelectedBrush_ForEachFace(graph, visitor);
880 }
881
882 void Scene_BrushGetTexdef_Component_Selected(scene::Graph& graph, TextureProjection& projection)
883 {
884 #if 1
885   if(!g_SelectedFaceInstances.empty())
886   {
887     FaceInstance& faceInstance = g_SelectedFaceInstances.last();
888     FaceTexdef_getTexdef(faceInstance.getFace().getTexdef(), projection);
889   }
890 #else
891   FaceGetTexdefVisitor visitor(projection);
892   Scene_ForEachSelectedBrushFace(graph, visitor);
893 #endif
894 }
895
896
897 class FaceGetFlagsVisitor
898 {
899   ContentsFlagsValue& m_flags;
900   mutable bool m_done;
901 public:
902   FaceGetFlagsVisitor(ContentsFlagsValue& flags)
903     : m_flags(flags), m_done(false)
904   {
905   }
906   void visit(Face& face) const
907   {
908     if(!m_done)
909     {
910       m_done = true;
911       FaceShader_getFlags(face.getShader(), m_flags);
912     }
913   }
914 };
915
916
917 void Scene_BrushGetFlags_Selected(scene::Graph& graph, ContentsFlagsValue& flags)
918 {
919   FaceGetFlagsVisitor visitor(flags);
920   Scene_ForEachSelectedBrush_ForEachFace(graph, visitor);
921 }
922
923 void Scene_BrushGetFlags_Component_Selected(scene::Graph& graph, ContentsFlagsValue& flags)
924 {
925 #if 1
926   if(!g_SelectedFaceInstances.empty())
927   {
928     FaceInstance& faceInstance = g_SelectedFaceInstances.last();
929     FaceShader_getFlags(faceInstance.getFace().getShader(), flags);
930   }
931 #else
932   FaceGetFlagsVisitor visitor(flags);
933   Scene_ForEachSelectedBrushFace(graph, visitor);
934 #endif
935 }
936
937
938 class FaceGetShaderVisitor
939 {
940   CopiedString& m_shader;
941   mutable bool m_done;
942 public:
943   FaceGetShaderVisitor(CopiedString& shader)
944     : m_shader(shader), m_done(false)
945   {
946   }
947   void visit(Face& face) const
948   {
949     if(!m_done)
950     {
951       m_done = true;
952       m_shader = face.getShader().getShader();
953     }
954   }
955 };
956
957 void Scene_BrushGetShader_Selected(scene::Graph& graph, CopiedString& shader)
958 {
959   FaceGetShaderVisitor visitor(shader);
960   Scene_ForEachSelectedBrush_ForEachFace(graph, visitor);
961 }
962
963 void Scene_BrushGetShader_Component_Selected(scene::Graph& graph, CopiedString& shader)
964 {
965 #if 1
966   if(!g_SelectedFaceInstances.empty())
967   {
968     FaceInstance& faceInstance = g_SelectedFaceInstances.last();
969     shader = faceInstance.getFace().getShader().getShader();
970   }
971 #else
972   FaceGetShaderVisitor visitor(shader);
973   Scene_ForEachSelectedBrushFace(graph, visitor);
974 #endif
975 }
976
977
978 class filter_face_shader : public FaceFilter
979 {
980   const char* m_shader;
981 public:
982   filter_face_shader(const char* shader) : m_shader(shader)
983   {
984   }
985   bool filter(const Face& face) const
986   {
987     return shader_equal(face.GetShader(), m_shader);
988   }
989 };
990
991 class filter_face_shader_substring : public FaceFilter
992 {
993   const char* m_shader;
994 public:
995   filter_face_shader_substring(const char* shader) : m_shader(shader)
996   {
997   }
998   bool filter(const Face& face) const
999   {
1000     return shader_equal_n(face.GetShader(), m_shader, strlen(m_shader));
1001   }
1002 };
1003
1004 class filter_face_flags : public FaceFilter
1005 {
1006   int m_flags;
1007 public:
1008   filter_face_flags(int flags) : m_flags(flags)
1009   {
1010   }
1011   bool filter(const Face& face) const
1012   {
1013     return (face.getShader().shaderFlags() & m_flags) != 0;
1014   }
1015 };
1016
1017 class filter_face_contents : public FaceFilter
1018 {
1019   int m_contents;
1020 public:
1021   filter_face_contents(int contents) : m_contents(contents)
1022   {
1023   }
1024   bool filter(const Face& face) const
1025   {
1026     return (face.getShader().m_flags.m_contentFlags & m_contents) != 0;
1027   }
1028 };
1029
1030
1031
1032 class FaceFilterAnyVisitor : public BrushVisitor
1033 {
1034   FaceFilter* m_filter;
1035   bool& m_filtered;
1036 public:
1037   FaceFilterAnyVisitor(FaceFilter* filter, bool& filtered) : m_filter(filter), m_filtered(filtered)
1038   {
1039     m_filtered = false;
1040   }
1041   void visit(Face& face) const
1042   {
1043     if(m_filter->filter(face))
1044     {
1045       m_filtered = true;
1046     }
1047   }
1048 };
1049
1050 class filter_brush_any_face : public BrushFilter
1051 {
1052   FaceFilter* m_filter;
1053 public:
1054   filter_brush_any_face(FaceFilter* filter) : m_filter(filter)
1055   {
1056   }
1057   bool filter(const Brush& brush) const
1058   {
1059     bool filtered;
1060     brush.forEachFace(FaceFilterAnyVisitor(m_filter, filtered));
1061     return filtered;
1062   }   
1063 };
1064
1065 class FaceFilterAllVisitor : public BrushVisitor
1066 {
1067   FaceFilter* m_filter;
1068   bool& m_filtered;
1069 public:
1070   FaceFilterAllVisitor(FaceFilter* filter, bool& filtered) : m_filter(filter), m_filtered(filtered)
1071   {
1072     m_filtered = true;
1073   }
1074   void visit(Face& face) const
1075   {
1076     if(!m_filter->filter(face))
1077     {
1078       m_filtered = false;
1079     }
1080   }
1081 };
1082
1083 class filter_brush_all_faces : public BrushFilter
1084 {
1085   FaceFilter* m_filter;
1086 public:
1087   filter_brush_all_faces(FaceFilter* filter) : m_filter(filter)
1088   {
1089   }
1090   bool filter(const Brush& brush) const
1091   {
1092     bool filtered;
1093     brush.forEachFace(FaceFilterAllVisitor(m_filter, filtered));
1094     return filtered;
1095   }   
1096 };
1097
1098
1099 filter_face_flags g_filter_face_clip(QER_CLIP);
1100 filter_brush_all_faces g_filter_brush_clip(&g_filter_face_clip);
1101
1102 filter_face_shader g_filter_face_clip_q2("textures/clip");
1103 filter_brush_all_faces g_filter_brush_clip_q2(&g_filter_face_clip_q2);
1104
1105 filter_face_shader g_filter_face_weapclip("textures/common/weapclip");
1106 filter_brush_all_faces g_filter_brush_weapclip(&g_filter_face_weapclip);
1107
1108 filter_face_shader g_filter_face_botclip("textures/common/botclip");
1109 filter_brush_all_faces g_filter_brush_botclip(&g_filter_face_botclip);
1110
1111 filter_face_shader g_filter_face_caulk("textures/common/caulk");
1112 filter_brush_all_faces g_filter_brush_caulk(&g_filter_face_caulk);
1113
1114 filter_face_shader g_filter_face_caulk_ja("textures/system/caulk");
1115 filter_brush_all_faces g_filter_brush_caulk_ja(&g_filter_face_caulk_ja);
1116
1117 filter_face_shader_substring g_filter_face_liquids("textures/liquids/");
1118 filter_brush_any_face g_filter_brush_liquids(&g_filter_face_liquids);
1119
1120 filter_face_shader g_filter_face_hint("textures/common/hint");
1121 filter_brush_any_face g_filter_brush_hint(&g_filter_face_hint);
1122
1123 filter_face_shader g_filter_face_hint_q2("textures/hint");
1124 filter_brush_any_face g_filter_brush_hint_q2(&g_filter_face_hint_q2);
1125
1126 filter_face_shader g_filter_face_hint_ja("textures/system/hint");
1127 filter_brush_any_face g_filter_brush_hint_ja(&g_filter_face_hint_ja);
1128
1129 filter_face_shader g_filter_face_areaportal("textures/common/areaportal");
1130 filter_brush_all_faces g_filter_brush_areaportal(&g_filter_face_areaportal);
1131
1132 filter_face_shader g_filter_face_visportal("textures/editor/visportal");
1133 filter_brush_any_face g_filter_brush_visportal(&g_filter_face_visportal);
1134
1135 filter_face_shader g_filter_face_clusterportal("textures/common/clusterportal");
1136 filter_brush_all_faces g_filter_brush_clusterportal(&g_filter_face_clusterportal);
1137
1138 filter_face_shader g_filter_face_lightgrid("textures/common/lightgrid");
1139 filter_brush_all_faces g_filter_brush_lightgrid(&g_filter_face_lightgrid);
1140
1141 filter_face_flags g_filter_face_translucent(QER_TRANS);
1142 filter_brush_all_faces g_filter_brush_translucent(&g_filter_face_translucent);
1143
1144 filter_face_contents g_filter_face_detail(CONTENTS_DETAIL);
1145 filter_brush_all_faces g_filter_brush_detail(&g_filter_face_detail);
1146
1147
1148 void BrushFilters_construct()
1149 {
1150   add_brush_filter(g_filter_brush_clip, EXCLUDE_CLIP);
1151   add_brush_filter(g_filter_brush_clip_q2, EXCLUDE_CLIP);
1152   add_brush_filter(g_filter_brush_weapclip, EXCLUDE_CLIP);
1153   add_brush_filter(g_filter_brush_botclip, EXCLUDE_BOTCLIP);
1154   add_brush_filter(g_filter_brush_caulk, EXCLUDE_CAULK);
1155   add_brush_filter(g_filter_brush_caulk_ja, EXCLUDE_CAULK);
1156   add_brush_filter(g_filter_brush_liquids, EXCLUDE_LIQUIDS);
1157   add_brush_filter(g_filter_brush_hint, EXCLUDE_HINTSSKIPS);
1158   add_brush_filter(g_filter_brush_hint_q2, EXCLUDE_HINTSSKIPS);
1159   add_brush_filter(g_filter_brush_hint_ja, EXCLUDE_HINTSSKIPS);
1160   add_brush_filter(g_filter_brush_clusterportal, EXCLUDE_CLUSTERPORTALS);
1161   add_brush_filter(g_filter_brush_visportal, EXCLUDE_VISPORTALS);
1162   add_brush_filter(g_filter_brush_areaportal, EXCLUDE_AREAPORTALS);
1163   add_brush_filter(g_filter_brush_translucent, EXCLUDE_TRANSLUCENT);
1164   add_brush_filter(g_filter_brush_detail, EXCLUDE_DETAILS);
1165   add_brush_filter(g_filter_brush_detail, EXCLUDE_STRUCTURAL, true);
1166   add_brush_filter(g_filter_brush_lightgrid, EXCLUDE_LIGHTGRID);
1167 }
1168
1169 #if 0
1170
1171 void normalquantisation_draw()
1172 {
1173   glPointSize(1);
1174   glBegin(GL_POINTS);
1175   for(std::size_t i = 0; i <= c_quantise_normal; ++i)
1176   {
1177     for(std::size_t j = 0; j <= c_quantise_normal; ++j)
1178     {
1179       Normal3f vertex(normal3f_normalised(Normal3f(
1180         static_cast<float>(c_quantise_normal - j - i),
1181         static_cast<float>(i),
1182         static_cast<float>(j)
1183         )));
1184       VectorScale(normal3f_to_array(vertex), 64.f, normal3f_to_array(vertex));
1185       glVertex3fv(normal3f_to_array(vertex));
1186       vertex.x = -vertex.x;
1187       glVertex3fv(normal3f_to_array(vertex));
1188     }
1189   }
1190   glEnd();
1191 }
1192
1193 class RenderableNormalQuantisation : public OpenGLRenderable
1194 {
1195 public:
1196   void render(RenderStateFlags state) const
1197   {
1198     normalquantisation_draw();
1199   }
1200 };
1201
1202 const float g_test_quantise_normal = 1.f / static_cast<float>(1 << 3);
1203
1204 class TestNormalQuantisation
1205 {
1206   void check_normal(const Normal3f& normal, const Normal3f& other)
1207   {
1208     spherical_t spherical = spherical_from_normal3f(normal);
1209     double longditude = RAD2DEG(spherical.longditude);
1210     double latitude = RAD2DEG(spherical.latitude);
1211     double x = cos(spherical.longditude) * sin(spherical.latitude);
1212     double y = sin(spherical.longditude) * sin(spherical.latitude);
1213     double z = cos(spherical.latitude);
1214
1215     ASSERT_MESSAGE(normal3f_dot(normal, other) > 0.99, "bleh");
1216   }
1217
1218   void test_normal(const Normal3f& normal)
1219   {
1220     Normal3f test = normal3f_from_spherical(spherical_from_normal3f(normal));
1221     check_normal(normal, test);
1222
1223     EOctant octant = normal3f_classify_octant(normal);
1224     Normal3f folded = normal3f_fold_octant(normal, octant);
1225     ESextant sextant = normal3f_classify_sextant(folded);
1226     folded = normal3f_fold_sextant(folded, sextant);
1227
1228     double scale = static_cast<float>(c_quantise_normal) / (folded.x + folded.y + folded.z);
1229
1230     double zbits = folded.z * scale;
1231     double ybits = folded.y * scale;
1232
1233     std::size_t zbits_q = static_cast<std::size_t>(zbits);
1234     std::size_t ybits_q = static_cast<std::size_t>(ybits);
1235
1236     ASSERT_MESSAGE(zbits_q <= (c_quantise_normal / 8) * 3, "bleh");
1237     ASSERT_MESSAGE(ybits_q <= (c_quantise_normal / 2), "bleh");
1238     ASSERT_MESSAGE(zbits_q + ((c_quantise_normal / 2) - ybits_q) <= (c_quantise_normal / 2), "bleh");
1239
1240     std::size_t y_t = (zbits_q < (c_quantise_normal / 4)) ? ybits_q : (c_quantise_normal / 2) - ybits_q;
1241     std::size_t z_t = (zbits_q < (c_quantise_normal / 4)) ? zbits_q : (c_quantise_normal / 2) - zbits_q;
1242     std::size_t index = (c_quantise_normal / 4) * y_t + z_t;
1243     ASSERT_MESSAGE(index <= (c_quantise_normal / 4)*(c_quantise_normal / 2), "bleh");
1244
1245     Normal3f tmp(c_quantise_normal - zbits_q - ybits_q, ybits_q, zbits_q);
1246     tmp = normal3f_normalised(tmp);
1247
1248     Normal3f unfolded = normal3f_unfold_octant(normal3f_unfold_sextant(tmp, sextant), octant);
1249
1250     check_normal(normal, unfolded);
1251
1252     double dot = normal3f_dot(normal, unfolded);
1253     float length = VectorLength(normal3f_to_array(unfolded));
1254     float inv_length = 1 / length;
1255
1256     Normal3f quantised = normal3f_quantised(normal);
1257     check_normal(normal, quantised);
1258   }
1259   void test2(const Normal3f& normal, const Normal3f& other)
1260   {
1261     if(normal3f_quantised(normal) != normal3f_quantised(other))
1262     {
1263       int bleh = 0;
1264     }
1265   }
1266
1267   static Normal3f normalise(float x, float y, float z)
1268   {
1269     return normal3f_normalised(Normal3f(x, y, z));
1270   }
1271
1272   float vec_rand()
1273   {
1274     return static_cast<float>(rand() - (RAND_MAX/2));
1275   }
1276
1277   Normal3f normal3f_rand()
1278   {
1279     return normalise(vec_rand(), vec_rand(), vec_rand());
1280   }
1281
1282 public:
1283   TestNormalQuantisation()
1284   {
1285     for(int i = 4096; i > 0; --i)
1286       test_normal(normal3f_rand());
1287
1288     test_normal(normalise(1, 0, 0));
1289     test_normal(normalise(0, 1, 0));
1290     test_normal(normalise(0, 0, 1));
1291     test_normal(normalise(1, 1, 0));
1292     test_normal(normalise(1, 0, 1));
1293     test_normal(normalise(0, 1, 1));
1294     
1295     test_normal(normalise(10000, 10000, 10000));
1296     test_normal(normalise(10000, 10000, 10001));
1297     test_normal(normalise(10000, 10000, 10002));
1298     test_normal(normalise(10000, 10000, 10010));
1299     test_normal(normalise(10000, 10000, 10020));
1300     test_normal(normalise(10000, 10000, 10030));
1301     test_normal(normalise(10000, 10000, 10100));
1302     test_normal(normalise(10000, 10000, 10101));
1303     test_normal(normalise(10000, 10000, 10102));
1304     test_normal(normalise(10000, 10000, 10200));
1305     test_normal(normalise(10000, 10000, 10201));
1306     test_normal(normalise(10000, 10000, 10202));
1307     test_normal(normalise(10000, 10000, 10203));
1308     test_normal(normalise(10000, 10000, 10300));
1309
1310
1311     test2(normalise(10000, 10000, 10000), normalise(10000, 10000, 10001));
1312     test2(normalise(10000, 10000, 10001), normalise(10000, 10001, 10000));
1313   }
1314 };
1315
1316 TestNormalQuantisation g_testNormalQuantisation;
1317
1318
1319 #endif
1320
1321 #if 0
1322 class TestSelectableObserver : public observer_template<const Selectable&>
1323 {
1324 public:
1325   void notify(const Selectable& arguments)
1326   {
1327     bool bleh = arguments.isSelected();
1328   }
1329 };
1330
1331 inline void test_bleh()
1332 {
1333   TestSelectableObserver test;
1334   ObservableSelectableInstance< SingleObservable< SelectionChangeCallback > > bleh;
1335   bleh.attach(test);
1336   bleh.setSelected(true);
1337   bleh.detach(test);
1338 }
1339
1340 class TestBleh
1341 {
1342 public:
1343   TestBleh()
1344   {
1345     test_bleh();
1346   }
1347 };
1348
1349 const TestBleh testbleh;
1350 #endif
1351
1352
1353 #if 0
1354 class TestRefcountedString
1355 {
1356 public:
1357   TestRefcountedString()
1358   {
1359     {
1360       // copy construct
1361       SmartString string1("string1");
1362       SmartString string2(string1);
1363       SmartString string3(string2);
1364     }
1365     {
1366       // refcounted assignment
1367       SmartString string1("string1");
1368       SmartString string2("string2");
1369       string1 = string2;
1370     }
1371     {
1372       // copy assignment
1373       SmartString string1("string1");
1374       SmartString string2("string2");
1375       string1 = string2.c_str();
1376     }
1377     {
1378       // self-assignment
1379       SmartString string1("string1");
1380       string1 = string1;
1381     }
1382     {
1383       // self-assignment via another reference
1384       SmartString string1("string1");
1385       SmartString string2(string1);
1386       string1 = string2;
1387     }
1388   }
1389 };
1390
1391 const TestRefcountedString g_testRefcountedString;
1392
1393 #endif
1394
1395 void Select_MakeDetail()
1396 {
1397   UndoableCommand undo("brushSetDetail");
1398   Scene_BrushSetDetail_Selected(GlobalSceneGraph(), true);
1399 }
1400
1401 void Select_MakeStructural()
1402 {
1403   UndoableCommand undo("brushClearDetail");
1404   Scene_BrushSetDetail_Selected(GlobalSceneGraph(), false);
1405 }
1406
1407 class BrushMakeSided
1408 {
1409   std::size_t m_count;
1410 public:
1411   BrushMakeSided(std::size_t count)
1412     : m_count(count)
1413   {
1414   }
1415   void set()
1416   {
1417     Scene_BrushConstructPrefab(GlobalSceneGraph(), eBrushPrism, m_count, TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
1418   }
1419   typedef MemberCaller<BrushMakeSided, &BrushMakeSided::set> SetCaller;
1420 };
1421
1422
1423 BrushMakeSided g_brushmakesided3(3);
1424 BrushMakeSided g_brushmakesided4(4);
1425 BrushMakeSided g_brushmakesided5(5);
1426 BrushMakeSided g_brushmakesided6(6);
1427 BrushMakeSided g_brushmakesided7(7);
1428 BrushMakeSided g_brushmakesided8(8);
1429 BrushMakeSided g_brushmakesided9(9);
1430
1431 inline int axis_for_viewtype(int viewtype)
1432 {
1433   switch(viewtype)
1434   {
1435     case XY:
1436       return 2;
1437     case XZ:
1438       return 1;
1439     case YZ:
1440       return 0;
1441   }
1442   return 2;
1443 }
1444
1445 class BrushPrefab
1446 {
1447   EBrushPrefab m_type;
1448 public:
1449   BrushPrefab(EBrushPrefab type)
1450     : m_type(type)
1451   {
1452   }
1453   void set()
1454   {
1455     DoSides(m_type, axis_for_viewtype(GetViewAxis()));
1456   }
1457   typedef MemberCaller<BrushPrefab, &BrushPrefab::set> SetCaller;
1458 };
1459
1460 BrushPrefab g_brushprism(eBrushPrism);
1461 BrushPrefab g_brushcone(eBrushCone);
1462 BrushPrefab g_brushsphere(eBrushSphere);
1463
1464
1465 void FlipClip();
1466 void SplitClip();
1467 void Clip();
1468 void OnClipMode(bool enable);
1469 bool ClipMode();
1470
1471
1472 void ClipSelected()
1473 {
1474   if(ClipMode())
1475   {
1476     UndoableCommand undo("clipperClip");
1477     Clip();
1478   }
1479 }
1480
1481 void SplitSelected()
1482 {
1483   if(ClipMode())
1484   {
1485     UndoableCommand undo("clipperSplit");
1486     SplitClip();
1487   }
1488 }
1489
1490 void FlipClipper()
1491 {
1492   FlipClip();
1493 }
1494
1495
1496 Callback g_texture_lock_status_changed;
1497 BoolExportCaller g_texdef_movelock_caller(g_brush_texturelock_enabled);
1498 ToggleItem g_texdef_movelock_item(g_texdef_movelock_caller);
1499
1500 void Texdef_ToggleMoveLock()
1501 {
1502   g_brush_texturelock_enabled = !g_brush_texturelock_enabled;
1503   g_texdef_movelock_item.update();
1504   g_texture_lock_status_changed();
1505 }
1506
1507
1508
1509
1510 void Face_getClosest(Face& face, SelectionTest& test, SelectionIntersection& bestIntersection, Face*& closestFace)
1511 {
1512   SelectionIntersection intersection;
1513   face.testSelect(test, intersection);
1514   if(intersection.valid()
1515     && SelectionIntersection_closer(intersection, bestIntersection))
1516   {
1517     bestIntersection = intersection;
1518     closestFace = &face;
1519   }
1520 }
1521
1522
1523 class OccludeSelector : public Selector
1524 {
1525   SelectionIntersection& m_bestIntersection;
1526   bool& m_occluded;
1527 public:
1528   OccludeSelector(SelectionIntersection& bestIntersection, bool& occluded) : m_bestIntersection(bestIntersection), m_occluded(occluded)
1529   {
1530     m_occluded = false;
1531   }
1532   void pushSelectable(Selectable& selectable)
1533   {
1534   }
1535   void popSelectable()
1536   {
1537   }
1538   void addIntersection(const SelectionIntersection& intersection)
1539   {
1540     if(SelectionIntersection_closer(intersection, m_bestIntersection))
1541     {
1542       m_bestIntersection = intersection;
1543       m_occluded = true;
1544     }
1545   }
1546 };
1547
1548 class BrushGetClosestFaceVisibleWalker : public scene::Graph::Walker
1549 {
1550   SelectionTest& m_test;
1551   Face*& m_closestFace;
1552   mutable SelectionIntersection m_bestIntersection;
1553 public:
1554   BrushGetClosestFaceVisibleWalker(SelectionTest& test, Face*& closestFace) : m_test(test), m_closestFace(closestFace)
1555   {
1556   }
1557   bool pre(const scene::Path& path, scene::Instance& instance) const
1558   {
1559     if(path.top().get().visible())
1560     {
1561       BrushInstance* brush = Instance_getBrush(instance);
1562       if(brush != 0)
1563       {
1564         m_test.BeginMesh(brush->localToWorld());
1565
1566         for(Brush::const_iterator i = brush->getBrush().begin(); i != brush->getBrush().end(); ++i)
1567         {
1568           Face_getClosest(*(*i), m_test, m_bestIntersection, m_closestFace);
1569         }
1570       }
1571       else
1572       {
1573         SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
1574         if(selectionTestable)
1575         {
1576           bool occluded;
1577           OccludeSelector selector(m_bestIntersection, occluded);
1578           selectionTestable->testSelect(selector, m_test);
1579           if(occluded)
1580           {
1581             m_closestFace = 0;
1582           }
1583         }
1584       }
1585     }
1586     return true;
1587   }
1588 };
1589
1590 Face* Scene_BrushGetClosestFace(scene::Graph& graph, SelectionTest& test)
1591 {
1592   Face* closestFace = 0;
1593   graph.traverse(BrushGetClosestFaceVisibleWalker(test, closestFace));
1594   return closestFace;
1595 }
1596
1597 bool Scene_BrushGetClosestFaceTexture(scene::Graph& graph, SelectionTest& test, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags)
1598 {
1599   Face* face = Scene_BrushGetClosestFace(graph, test);
1600   if(face != 0)
1601   {
1602     shader = face->GetShader();
1603     FaceTexdef_getTexdef(face->getTexdef(), projection);
1604     flags = face->getShader().m_flags;
1605     return true;
1606   }
1607   return false;
1608 }
1609
1610 void Scene_BrushSetClosestFaceTexture(scene::Graph& graph, SelectionTest& test, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags)
1611 {
1612   Face* face = Scene_BrushGetClosestFace(graph, test);
1613   if(face != 0)
1614   {
1615     face->SetShader(shader);
1616     face->SetTexdef(projection);
1617     face->SetFlags(flags);
1618   }
1619 }
1620
1621
1622 class FaceTexture
1623 {
1624 public:
1625   TextureProjection m_projection;
1626   ContentsFlagsValue m_flags;
1627 };
1628
1629 FaceTexture g_faceTextureClipboard;
1630
1631 void FaceTextureClipboard_setDefault()
1632 {
1633   g_faceTextureClipboard.m_flags = ContentsFlagsValue(0, 0, 0, false);
1634   TexDef_Construct_Default(g_faceTextureClipboard.m_projection);
1635 }
1636
1637 void TextureClipboard_textureSelected(const char* shader)
1638 {
1639   FaceTextureClipboard_setDefault();
1640 }
1641
1642 class TextureBrowser;
1643 extern TextureBrowser g_TextureBrowser;
1644 void TextureBrowser_SetSelectedShader(TextureBrowser& textureBrowser, const char* shader);
1645 const char* TextureBrowser_GetSelectedShader(TextureBrowser& textureBrowser);
1646
1647 void Scene_copyClosestFaceTexture(SelectionTest& test)
1648 {
1649   CopiedString shader;
1650   if(Scene_BrushGetClosestFaceTexture(GlobalSceneGraph(), test, shader, g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags))
1651   {
1652     TextureBrowser_SetSelectedShader(g_TextureBrowser, shader.c_str());
1653   }
1654 }
1655
1656 void Scene_applyClosestFaceTexture(SelectionTest& test)
1657 {
1658   UndoableCommand command("facePaintTexture");
1659
1660   Scene_BrushSetClosestFaceTexture(GlobalSceneGraph(), test, TextureBrowser_GetSelectedShader(g_TextureBrowser), g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags);
1661
1662   SceneChangeNotify();
1663 }
1664
1665
1666
1667 void SelectedFaces_copyTexture()
1668 {
1669   if(!g_SelectedFaceInstances.empty())
1670   {
1671     Face& face = g_SelectedFaceInstances.last().getFace();
1672     FaceTexdef_getTexdef(face.getTexdef(), g_faceTextureClipboard.m_projection);
1673     g_faceTextureClipboard.m_flags = face.getShader().m_flags;
1674
1675     TextureBrowser_SetSelectedShader(g_TextureBrowser, face.getShader().getShader());
1676   }
1677 }
1678
1679 void FaceInstance_pasteTexture(FaceInstance& faceInstance)
1680 {
1681   faceInstance.getFace().SetTexdef(g_faceTextureClipboard.m_projection);
1682   faceInstance.getFace().SetShader(TextureBrowser_GetSelectedShader(g_TextureBrowser));
1683   faceInstance.getFace().SetFlags(g_faceTextureClipboard.m_flags);
1684   SceneChangeNotify();
1685 }
1686
1687 void SelectedFaces_pasteTexture()
1688 {
1689   UndoableCommand command("facePasteTexture");
1690   g_SelectedFaceInstances.foreach(FaceInstance_pasteTexture);
1691 }
1692
1693 void Brush_registerCommands()
1694 {
1695   GlobalToggles_insert("TogTexLock", FreeCaller<Texdef_ToggleMoveLock>(), ToggleItem::AddCallbackCaller(g_texdef_movelock_item), Accelerator('T', (GdkModifierType)GDK_SHIFT_MASK));
1696
1697   GlobalCommands_insert("BrushPrism", BrushPrefab::SetCaller(g_brushprism));
1698   GlobalCommands_insert("BrushCone", BrushPrefab::SetCaller(g_brushcone));
1699   GlobalCommands_insert("BrushSphere", BrushPrefab::SetCaller(g_brushsphere));
1700
1701   GlobalCommands_insert("Brush3Sided", BrushMakeSided::SetCaller(g_brushmakesided3), Accelerator('3', (GdkModifierType)GDK_CONTROL_MASK));
1702   GlobalCommands_insert("Brush4Sided", BrushMakeSided::SetCaller(g_brushmakesided4), Accelerator('4', (GdkModifierType)GDK_CONTROL_MASK));
1703   GlobalCommands_insert("Brush5Sided", BrushMakeSided::SetCaller(g_brushmakesided5), Accelerator('5', (GdkModifierType)GDK_CONTROL_MASK));
1704   GlobalCommands_insert("Brush6Sided", BrushMakeSided::SetCaller(g_brushmakesided6), Accelerator('6', (GdkModifierType)GDK_CONTROL_MASK));
1705   GlobalCommands_insert("Brush7Sided", BrushMakeSided::SetCaller(g_brushmakesided7), Accelerator('7', (GdkModifierType)GDK_CONTROL_MASK));
1706   GlobalCommands_insert("Brush8Sided", BrushMakeSided::SetCaller(g_brushmakesided8), Accelerator('8', (GdkModifierType)GDK_CONTROL_MASK));
1707   GlobalCommands_insert("Brush9Sided", BrushMakeSided::SetCaller(g_brushmakesided9), Accelerator('9', (GdkModifierType)GDK_CONTROL_MASK));
1708
1709   GlobalCommands_insert("ClipSelected", FreeCaller<ClipSelected>(), Accelerator(GDK_Return));
1710   GlobalCommands_insert("SplitSelected", FreeCaller<SplitSelected>(), Accelerator(GDK_Return, (GdkModifierType)GDK_SHIFT_MASK));
1711   GlobalCommands_insert("FlipClip", FreeCaller<FlipClipper>(), Accelerator(GDK_Return, (GdkModifierType)GDK_CONTROL_MASK));
1712
1713   GlobalCommands_insert("FaceCopyTexture", FreeCaller<SelectedFaces_copyTexture>());
1714   GlobalCommands_insert("FacePasteTexture", FreeCaller<SelectedFaces_pasteTexture>());
1715
1716   GlobalCommands_insert("MakeDetail", FreeCaller<Select_MakeDetail>(), Accelerator('M', (GdkModifierType)GDK_CONTROL_MASK));
1717   GlobalCommands_insert("MakeStructural", FreeCaller<Select_MakeStructural>(), Accelerator('S', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
1718 }
1719
1720 void Brush_constructMenu(GtkMenu* menu)
1721 {
1722   create_menu_item_with_mnemonic(menu, "Prism...", "BrushPrism");
1723   create_menu_item_with_mnemonic(menu, "Cone...", "BrushCone");
1724   create_menu_item_with_mnemonic(menu, "Sphere...", "BrushSphere");
1725   menu_separator (menu);
1726   {
1727     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "CSG");
1728     create_menu_item_with_mnemonic(menu_in_menu, "Make _Hollow", "CSGHollow");
1729     create_menu_item_with_mnemonic(menu_in_menu, "CSG _Subtract", "CSGSubtract");
1730     create_menu_item_with_mnemonic(menu_in_menu, "CSG _Merge", "CSGMerge");
1731   }
1732   menu_separator(menu);
1733   {
1734     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "Clipper");
1735
1736     create_menu_item_with_mnemonic(menu_in_menu, "Clip selection", "ClipSelected");
1737     create_menu_item_with_mnemonic(menu_in_menu, "Split selection", "SplitSelected");
1738     create_menu_item_with_mnemonic(menu_in_menu, "Flip Clip orientation", "FlipClip");
1739   }
1740   menu_separator(menu);
1741   create_menu_item_with_mnemonic(menu, "Make detail", "MakeDetail");
1742   create_menu_item_with_mnemonic(menu, "Make structural", "MakeStructural");
1743
1744   create_check_menu_item_with_mnemonic(menu, "Texture Lock", "TogTexLock");
1745   menu_separator(menu);
1746   create_menu_item_with_mnemonic(menu, "Copy Face Texture", "FaceCopyTexture");
1747   create_menu_item_with_mnemonic(menu, "Paste Face Texture", "FacePasteTexture");
1748
1749   command_connect_accelerator("Brush3Sided");
1750   command_connect_accelerator("Brush4Sided");
1751   command_connect_accelerator("Brush5Sided");
1752   command_connect_accelerator("Brush6Sided");
1753   command_connect_accelerator("Brush7Sided");
1754   command_connect_accelerator("Brush8Sided");
1755   command_connect_accelerator("Brush9Sided");
1756 }