]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/brushmanip.cpp
940c6f649035bc939d770a3d8e34db5644633f3f
[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_substring g_filter_face_liquids("textures/liquids/");
1115 filter_brush_any_face g_filter_brush_liquids(&g_filter_face_liquids);
1116
1117 filter_face_shader g_filter_face_hint("textures/common/hint");
1118 filter_brush_any_face g_filter_brush_hint(&g_filter_face_hint);
1119
1120 filter_face_shader g_filter_face_hint_q2("textures/hint");
1121 filter_brush_any_face g_filter_brush_hint_q2(&g_filter_face_hint_q2);
1122
1123 filter_face_shader g_filter_face_areaportal("textures/common/areaportal");
1124 filter_brush_all_faces g_filter_brush_areaportal(&g_filter_face_areaportal);
1125
1126 filter_face_shader g_filter_face_visportal("textures/editor/visportal");
1127 filter_brush_any_face g_filter_brush_visportal(&g_filter_face_visportal);
1128
1129 filter_face_shader g_filter_face_clusterportal("textures/common/clusterportal");
1130 filter_brush_all_faces g_filter_brush_clusterportal(&g_filter_face_clusterportal);
1131
1132 filter_face_shader g_filter_face_lightgrid("textures/common/lightgrid");
1133 filter_brush_all_faces g_filter_brush_lightgrid(&g_filter_face_lightgrid);
1134
1135 filter_face_flags g_filter_face_translucent(QER_TRANS);
1136 filter_brush_all_faces g_filter_brush_translucent(&g_filter_face_translucent);
1137
1138 filter_face_contents g_filter_face_detail(CONTENTS_DETAIL);
1139 filter_brush_all_faces g_filter_brush_detail(&g_filter_face_detail);
1140
1141
1142 void BrushFilters_construct()
1143 {
1144   add_brush_filter(g_filter_brush_clip, EXCLUDE_CLIP);
1145   add_brush_filter(g_filter_brush_clip_q2, EXCLUDE_CLIP);
1146   add_brush_filter(g_filter_brush_weapclip, EXCLUDE_CLIP);
1147   add_brush_filter(g_filter_brush_botclip, EXCLUDE_BOTCLIP);
1148   add_brush_filter(g_filter_brush_caulk, EXCLUDE_CAULK);
1149   add_brush_filter(g_filter_brush_liquids, EXCLUDE_LIQUIDS);
1150   add_brush_filter(g_filter_brush_hint, EXCLUDE_HINTSSKIPS);
1151   add_brush_filter(g_filter_brush_hint_q2, EXCLUDE_HINTSSKIPS);
1152   add_brush_filter(g_filter_brush_clusterportal, EXCLUDE_CLUSTERPORTALS);
1153   add_brush_filter(g_filter_brush_visportal, EXCLUDE_VISPORTALS);
1154   add_brush_filter(g_filter_brush_areaportal, EXCLUDE_AREAPORTALS);
1155   add_brush_filter(g_filter_brush_translucent, EXCLUDE_TRANSLUCENT);
1156   add_brush_filter(g_filter_brush_detail, EXCLUDE_DETAILS);
1157   add_brush_filter(g_filter_brush_detail, EXCLUDE_STRUCTURAL, true);
1158   add_brush_filter(g_filter_brush_lightgrid, EXCLUDE_LIGHTGRID);
1159 }
1160
1161 #if 0
1162
1163 void normalquantisation_draw()
1164 {
1165   glPointSize(1);
1166   glBegin(GL_POINTS);
1167   for(std::size_t i = 0; i <= c_quantise_normal; ++i)
1168   {
1169     for(std::size_t j = 0; j <= c_quantise_normal; ++j)
1170     {
1171       Normal3f vertex(normal3f_normalised(Normal3f(
1172         static_cast<float>(c_quantise_normal - j - i),
1173         static_cast<float>(i),
1174         static_cast<float>(j)
1175         )));
1176       VectorScale(normal3f_to_array(vertex), 64.f, normal3f_to_array(vertex));
1177       glVertex3fv(normal3f_to_array(vertex));
1178       vertex.x = -vertex.x;
1179       glVertex3fv(normal3f_to_array(vertex));
1180     }
1181   }
1182   glEnd();
1183 }
1184
1185 class RenderableNormalQuantisation : public OpenGLRenderable
1186 {
1187 public:
1188   void render(RenderStateFlags state) const
1189   {
1190     normalquantisation_draw();
1191   }
1192 };
1193
1194 const float g_test_quantise_normal = 1.f / static_cast<float>(1 << 3);
1195
1196 class TestNormalQuantisation
1197 {
1198   void check_normal(const Normal3f& normal, const Normal3f& other)
1199   {
1200     spherical_t spherical = spherical_from_normal3f(normal);
1201     double longditude = RAD2DEG(spherical.longditude);
1202     double latitude = RAD2DEG(spherical.latitude);
1203     double x = cos(spherical.longditude) * sin(spherical.latitude);
1204     double y = sin(spherical.longditude) * sin(spherical.latitude);
1205     double z = cos(spherical.latitude);
1206
1207     ASSERT_MESSAGE(normal3f_dot(normal, other) > 0.99, "bleh");
1208   }
1209
1210   void test_normal(const Normal3f& normal)
1211   {
1212     Normal3f test = normal3f_from_spherical(spherical_from_normal3f(normal));
1213     check_normal(normal, test);
1214
1215     EOctant octant = normal3f_classify_octant(normal);
1216     Normal3f folded = normal3f_fold_octant(normal, octant);
1217     ESextant sextant = normal3f_classify_sextant(folded);
1218     folded = normal3f_fold_sextant(folded, sextant);
1219
1220     double scale = static_cast<float>(c_quantise_normal) / (folded.x + folded.y + folded.z);
1221
1222     double zbits = folded.z * scale;
1223     double ybits = folded.y * scale;
1224
1225     std::size_t zbits_q = static_cast<std::size_t>(zbits);
1226     std::size_t ybits_q = static_cast<std::size_t>(ybits);
1227
1228     ASSERT_MESSAGE(zbits_q <= (c_quantise_normal / 8) * 3, "bleh");
1229     ASSERT_MESSAGE(ybits_q <= (c_quantise_normal / 2), "bleh");
1230     ASSERT_MESSAGE(zbits_q + ((c_quantise_normal / 2) - ybits_q) <= (c_quantise_normal / 2), "bleh");
1231
1232     std::size_t y_t = (zbits_q < (c_quantise_normal / 4)) ? ybits_q : (c_quantise_normal / 2) - ybits_q;
1233     std::size_t z_t = (zbits_q < (c_quantise_normal / 4)) ? zbits_q : (c_quantise_normal / 2) - zbits_q;
1234     std::size_t index = (c_quantise_normal / 4) * y_t + z_t;
1235     ASSERT_MESSAGE(index <= (c_quantise_normal / 4)*(c_quantise_normal / 2), "bleh");
1236
1237     Normal3f tmp(c_quantise_normal - zbits_q - ybits_q, ybits_q, zbits_q);
1238     tmp = normal3f_normalised(tmp);
1239
1240     Normal3f unfolded = normal3f_unfold_octant(normal3f_unfold_sextant(tmp, sextant), octant);
1241
1242     check_normal(normal, unfolded);
1243
1244     double dot = normal3f_dot(normal, unfolded);
1245     float length = VectorLength(normal3f_to_array(unfolded));
1246     float inv_length = 1 / length;
1247
1248     Normal3f quantised = normal3f_quantised(normal);
1249     check_normal(normal, quantised);
1250   }
1251   void test2(const Normal3f& normal, const Normal3f& other)
1252   {
1253     if(normal3f_quantised(normal) != normal3f_quantised(other))
1254     {
1255       int bleh = 0;
1256     }
1257   }
1258
1259   static Normal3f normalise(float x, float y, float z)
1260   {
1261     return normal3f_normalised(Normal3f(x, y, z));
1262   }
1263
1264   float vec_rand()
1265   {
1266     return static_cast<float>(rand() - (RAND_MAX/2));
1267   }
1268
1269   Normal3f normal3f_rand()
1270   {
1271     return normalise(vec_rand(), vec_rand(), vec_rand());
1272   }
1273
1274 public:
1275   TestNormalQuantisation()
1276   {
1277     for(int i = 4096; i > 0; --i)
1278       test_normal(normal3f_rand());
1279
1280     test_normal(normalise(1, 0, 0));
1281     test_normal(normalise(0, 1, 0));
1282     test_normal(normalise(0, 0, 1));
1283     test_normal(normalise(1, 1, 0));
1284     test_normal(normalise(1, 0, 1));
1285     test_normal(normalise(0, 1, 1));
1286     
1287     test_normal(normalise(10000, 10000, 10000));
1288     test_normal(normalise(10000, 10000, 10001));
1289     test_normal(normalise(10000, 10000, 10002));
1290     test_normal(normalise(10000, 10000, 10010));
1291     test_normal(normalise(10000, 10000, 10020));
1292     test_normal(normalise(10000, 10000, 10030));
1293     test_normal(normalise(10000, 10000, 10100));
1294     test_normal(normalise(10000, 10000, 10101));
1295     test_normal(normalise(10000, 10000, 10102));
1296     test_normal(normalise(10000, 10000, 10200));
1297     test_normal(normalise(10000, 10000, 10201));
1298     test_normal(normalise(10000, 10000, 10202));
1299     test_normal(normalise(10000, 10000, 10203));
1300     test_normal(normalise(10000, 10000, 10300));
1301
1302
1303     test2(normalise(10000, 10000, 10000), normalise(10000, 10000, 10001));
1304     test2(normalise(10000, 10000, 10001), normalise(10000, 10001, 10000));
1305   }
1306 };
1307
1308 TestNormalQuantisation g_testNormalQuantisation;
1309
1310
1311 #endif
1312
1313 #if 0
1314 class TestSelectableObserver : public observer_template<const Selectable&>
1315 {
1316 public:
1317   void notify(const Selectable& arguments)
1318   {
1319     bool bleh = arguments.isSelected();
1320   }
1321 };
1322
1323 inline void test_bleh()
1324 {
1325   TestSelectableObserver test;
1326   ObservableSelectableInstance< SingleObservable< SelectionChangeCallback > > bleh;
1327   bleh.attach(test);
1328   bleh.setSelected(true);
1329   bleh.detach(test);
1330 }
1331
1332 class TestBleh
1333 {
1334 public:
1335   TestBleh()
1336   {
1337     test_bleh();
1338   }
1339 };
1340
1341 const TestBleh testbleh;
1342 #endif
1343
1344
1345 #if 0
1346 class TestRefcountedString
1347 {
1348 public:
1349   TestRefcountedString()
1350   {
1351     {
1352       // copy construct
1353       SmartString string1("string1");
1354       SmartString string2(string1);
1355       SmartString string3(string2);
1356     }
1357     {
1358       // refcounted assignment
1359       SmartString string1("string1");
1360       SmartString string2("string2");
1361       string1 = string2;
1362     }
1363     {
1364       // copy assignment
1365       SmartString string1("string1");
1366       SmartString string2("string2");
1367       string1 = string2.c_str();
1368     }
1369     {
1370       // self-assignment
1371       SmartString string1("string1");
1372       string1 = string1;
1373     }
1374     {
1375       // self-assignment via another reference
1376       SmartString string1("string1");
1377       SmartString string2(string1);
1378       string1 = string2;
1379     }
1380   }
1381 };
1382
1383 const TestRefcountedString g_testRefcountedString;
1384
1385 #endif
1386
1387 void Select_MakeDetail()
1388 {
1389   UndoableCommand undo("brushSetDetail");
1390   Scene_BrushSetDetail_Selected(GlobalSceneGraph(), true);
1391 }
1392
1393 void Select_MakeStructural()
1394 {
1395   UndoableCommand undo("brushClearDetail");
1396   Scene_BrushSetDetail_Selected(GlobalSceneGraph(), false);
1397 }
1398
1399 class BrushMakeSided
1400 {
1401   std::size_t m_count;
1402 public:
1403   BrushMakeSided(std::size_t count)
1404     : m_count(count)
1405   {
1406   }
1407   void set()
1408   {
1409     Scene_BrushConstructPrefab(GlobalSceneGraph(), eBrushPrism, m_count, TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
1410   }
1411   typedef MemberCaller<BrushMakeSided, &BrushMakeSided::set> SetCaller;
1412 };
1413
1414
1415 BrushMakeSided g_brushmakesided3(3);
1416 BrushMakeSided g_brushmakesided4(4);
1417 BrushMakeSided g_brushmakesided5(5);
1418 BrushMakeSided g_brushmakesided6(6);
1419 BrushMakeSided g_brushmakesided7(7);
1420 BrushMakeSided g_brushmakesided8(8);
1421 BrushMakeSided g_brushmakesided9(9);
1422
1423 inline int axis_for_viewtype(int viewtype)
1424 {
1425   switch(viewtype)
1426   {
1427     case XY:
1428       return 2;
1429     case XZ:
1430       return 1;
1431     case YZ:
1432       return 0;
1433   }
1434   return 2;
1435 }
1436
1437 class BrushPrefab
1438 {
1439   EBrushPrefab m_type;
1440 public:
1441   BrushPrefab(EBrushPrefab type)
1442     : m_type(type)
1443   {
1444   }
1445   void set()
1446   {
1447     DoSides(m_type, axis_for_viewtype(GetViewAxis()));
1448   }
1449   typedef MemberCaller<BrushPrefab, &BrushPrefab::set> SetCaller;
1450 };
1451
1452 BrushPrefab g_brushprism(eBrushPrism);
1453 BrushPrefab g_brushcone(eBrushCone);
1454 BrushPrefab g_brushsphere(eBrushSphere);
1455
1456
1457 void FlipClip();
1458 void SplitClip();
1459 void Clip();
1460 void OnClipMode(bool enable);
1461 bool ClipMode();
1462
1463
1464 void ClipSelected()
1465 {
1466   if(ClipMode())
1467   {
1468     UndoableCommand undo("clipperClip");
1469     Clip();
1470   }
1471 }
1472
1473 void SplitSelected()
1474 {
1475   if(ClipMode())
1476   {
1477     UndoableCommand undo("clipperSplit");
1478     SplitClip();
1479   }
1480 }
1481
1482 void FlipClipper()
1483 {
1484   FlipClip();
1485 }
1486
1487
1488 Callback g_texture_lock_status_changed;
1489 BoolExportCaller g_texdef_movelock_caller(g_brush_texturelock_enabled);
1490 ToggleItem g_texdef_movelock_item(g_texdef_movelock_caller);
1491
1492 void Texdef_ToggleMoveLock()
1493 {
1494   g_brush_texturelock_enabled = !g_brush_texturelock_enabled;
1495   g_texdef_movelock_item.update();
1496   g_texture_lock_status_changed();
1497 }
1498
1499
1500
1501
1502 void Face_getClosest(Face& face, SelectionTest& test, SelectionIntersection& bestIntersection, Face*& closestFace)
1503 {
1504   SelectionIntersection intersection;
1505   face.testSelect(test, intersection);
1506   if(intersection.valid()
1507     && SelectionIntersection_closer(intersection, bestIntersection))
1508   {
1509     bestIntersection = intersection;
1510     closestFace = &face;
1511   }
1512 }
1513
1514
1515 class OccludeSelector : public Selector
1516 {
1517   SelectionIntersection& m_bestIntersection;
1518   bool& m_occluded;
1519 public:
1520   OccludeSelector(SelectionIntersection& bestIntersection, bool& occluded) : m_bestIntersection(bestIntersection), m_occluded(occluded)
1521   {
1522     m_occluded = false;
1523   }
1524   void pushSelectable(Selectable& selectable)
1525   {
1526   }
1527   void popSelectable()
1528   {
1529   }
1530   void addIntersection(const SelectionIntersection& intersection)
1531   {
1532     if(SelectionIntersection_closer(intersection, m_bestIntersection))
1533     {
1534       m_bestIntersection = intersection;
1535       m_occluded = true;
1536     }
1537   }
1538 };
1539
1540 class BrushGetClosestFaceVisibleWalker : public scene::Graph::Walker
1541 {
1542   SelectionTest& m_test;
1543   Face*& m_closestFace;
1544   mutable SelectionIntersection m_bestIntersection;
1545 public:
1546   BrushGetClosestFaceVisibleWalker(SelectionTest& test, Face*& closestFace) : m_test(test), m_closestFace(closestFace)
1547   {
1548   }
1549   bool pre(const scene::Path& path, scene::Instance& instance) const
1550   {
1551     if(path.top().get().visible())
1552     {
1553       BrushInstance* brush = Instance_getBrush(instance);
1554       if(brush != 0)
1555       {
1556         m_test.BeginMesh(brush->localToWorld());
1557
1558         for(Brush::const_iterator i = brush->getBrush().begin(); i != brush->getBrush().end(); ++i)
1559         {
1560           Face_getClosest(*(*i), m_test, m_bestIntersection, m_closestFace);
1561         }
1562       }
1563       else
1564       {
1565         SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
1566         if(selectionTestable)
1567         {
1568           bool occluded;
1569           OccludeSelector selector(m_bestIntersection, occluded);
1570           selectionTestable->testSelect(selector, m_test);
1571           if(occluded)
1572           {
1573             m_closestFace = 0;
1574           }
1575         }
1576       }
1577     }
1578     return true;
1579   }
1580 };
1581
1582 Face* Scene_BrushGetClosestFace(scene::Graph& graph, SelectionTest& test)
1583 {
1584   Face* closestFace = 0;
1585   graph.traverse(BrushGetClosestFaceVisibleWalker(test, closestFace));
1586   return closestFace;
1587 }
1588
1589 bool Scene_BrushGetClosestFaceTexture(scene::Graph& graph, SelectionTest& test, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags)
1590 {
1591   Face* face = Scene_BrushGetClosestFace(graph, test);
1592   if(face != 0)
1593   {
1594     shader = face->GetShader();
1595     FaceTexdef_getTexdef(face->getTexdef(), projection);
1596     flags = face->getShader().m_flags;
1597     return true;
1598   }
1599   return false;
1600 }
1601
1602 void Scene_BrushSetClosestFaceTexture(scene::Graph& graph, SelectionTest& test, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags)
1603 {
1604   Face* face = Scene_BrushGetClosestFace(graph, test);
1605   if(face != 0)
1606   {
1607     face->SetShader(shader);
1608     face->SetTexdef(projection);
1609     face->SetFlags(flags);
1610   }
1611 }
1612
1613
1614 class FaceTexture
1615 {
1616 public:
1617   TextureProjection m_projection;
1618   ContentsFlagsValue m_flags;
1619 };
1620
1621 FaceTexture g_faceTextureClipboard;
1622
1623 void FaceTextureClipboard_setDefault()
1624 {
1625   g_faceTextureClipboard.m_flags = ContentsFlagsValue(0, 0, 0, false);
1626   TexDef_Construct_Default(g_faceTextureClipboard.m_projection);
1627 }
1628
1629 void TextureClipboard_textureSelected(const char* shader)
1630 {
1631   FaceTextureClipboard_setDefault();
1632 }
1633
1634 class TextureBrowser;
1635 extern TextureBrowser g_TextureBrowser;
1636 void TextureBrowser_SetSelectedShader(TextureBrowser& textureBrowser, const char* shader);
1637 const char* TextureBrowser_GetSelectedShader(TextureBrowser& textureBrowser);
1638
1639 void Scene_copyClosestFaceTexture(SelectionTest& test)
1640 {
1641   CopiedString shader;
1642   if(Scene_BrushGetClosestFaceTexture(GlobalSceneGraph(), test, shader, g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags))
1643   {
1644     TextureBrowser_SetSelectedShader(g_TextureBrowser, shader.c_str());
1645   }
1646 }
1647
1648 void Scene_applyClosestFaceTexture(SelectionTest& test)
1649 {
1650   UndoableCommand command("facePaintTexture");
1651
1652   Scene_BrushSetClosestFaceTexture(GlobalSceneGraph(), test, TextureBrowser_GetSelectedShader(g_TextureBrowser), g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags);
1653
1654   SceneChangeNotify();
1655 }
1656
1657
1658
1659 void SelectedFaces_copyTexture()
1660 {
1661   if(!g_SelectedFaceInstances.empty())
1662   {
1663     Face& face = g_SelectedFaceInstances.last().getFace();
1664     FaceTexdef_getTexdef(face.getTexdef(), g_faceTextureClipboard.m_projection);
1665     g_faceTextureClipboard.m_flags = face.getShader().m_flags;
1666
1667     TextureBrowser_SetSelectedShader(g_TextureBrowser, face.getShader().getShader());
1668   }
1669 }
1670
1671 void FaceInstance_pasteTexture(FaceInstance& faceInstance)
1672 {
1673   faceInstance.getFace().SetTexdef(g_faceTextureClipboard.m_projection);
1674   faceInstance.getFace().SetShader(TextureBrowser_GetSelectedShader(g_TextureBrowser));
1675   faceInstance.getFace().SetFlags(g_faceTextureClipboard.m_flags);
1676   SceneChangeNotify();
1677 }
1678
1679 void SelectedFaces_pasteTexture()
1680 {
1681   UndoableCommand command("facePasteTexture");
1682   g_SelectedFaceInstances.foreach(FaceInstance_pasteTexture);
1683 }
1684
1685 void Brush_registerCommands()
1686 {
1687   GlobalToggles_insert("TogTexLock", FreeCaller<Texdef_ToggleMoveLock>(), ToggleItem::AddCallbackCaller(g_texdef_movelock_item), Accelerator('T', (GdkModifierType)GDK_SHIFT_MASK));
1688
1689   GlobalCommands_insert("BrushPrism", BrushPrefab::SetCaller(g_brushprism));
1690   GlobalCommands_insert("BrushCone", BrushPrefab::SetCaller(g_brushcone));
1691   GlobalCommands_insert("BrushSphere", BrushPrefab::SetCaller(g_brushsphere));
1692
1693   GlobalCommands_insert("Brush3Sided", BrushMakeSided::SetCaller(g_brushmakesided3), Accelerator('3', (GdkModifierType)GDK_CONTROL_MASK));
1694   GlobalCommands_insert("Brush4Sided", BrushMakeSided::SetCaller(g_brushmakesided4), Accelerator('4', (GdkModifierType)GDK_CONTROL_MASK));
1695   GlobalCommands_insert("Brush5Sided", BrushMakeSided::SetCaller(g_brushmakesided5), Accelerator('5', (GdkModifierType)GDK_CONTROL_MASK));
1696   GlobalCommands_insert("Brush6Sided", BrushMakeSided::SetCaller(g_brushmakesided6), Accelerator('6', (GdkModifierType)GDK_CONTROL_MASK));
1697   GlobalCommands_insert("Brush7Sided", BrushMakeSided::SetCaller(g_brushmakesided7), Accelerator('7', (GdkModifierType)GDK_CONTROL_MASK));
1698   GlobalCommands_insert("Brush8Sided", BrushMakeSided::SetCaller(g_brushmakesided8), Accelerator('8', (GdkModifierType)GDK_CONTROL_MASK));
1699   GlobalCommands_insert("Brush9Sided", BrushMakeSided::SetCaller(g_brushmakesided9), Accelerator('9', (GdkModifierType)GDK_CONTROL_MASK));
1700
1701   GlobalCommands_insert("ClipSelected", FreeCaller<ClipSelected>(), Accelerator(GDK_Return));
1702   GlobalCommands_insert("SplitSelected", FreeCaller<SplitSelected>(), Accelerator(GDK_Return, (GdkModifierType)GDK_SHIFT_MASK));
1703   GlobalCommands_insert("FlipClip", FreeCaller<FlipClipper>(), Accelerator(GDK_Return, (GdkModifierType)GDK_CONTROL_MASK));
1704
1705   GlobalCommands_insert("FaceCopyTexture", FreeCaller<SelectedFaces_copyTexture>());
1706   GlobalCommands_insert("FacePasteTexture", FreeCaller<SelectedFaces_pasteTexture>());
1707
1708   GlobalCommands_insert("MakeDetail", FreeCaller<Select_MakeDetail>(), Accelerator('M', (GdkModifierType)GDK_CONTROL_MASK));
1709   GlobalCommands_insert("MakeStructural", FreeCaller<Select_MakeStructural>(), Accelerator('S', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
1710 }
1711
1712 void Brush_constructMenu(GtkMenu* menu)
1713 {
1714   create_menu_item_with_mnemonic(menu, "Prism...", "BrushPrism");
1715   create_menu_item_with_mnemonic(menu, "Cone...", "BrushCone");
1716   create_menu_item_with_mnemonic(menu, "Sphere...", "BrushSphere");
1717   menu_separator (menu);
1718   {
1719     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "CSG");
1720     create_menu_item_with_mnemonic(menu_in_menu, "Make _Hollow", "CSGHollow");
1721     create_menu_item_with_mnemonic(menu_in_menu, "CSG _Subtract", "CSGSubtract");
1722     create_menu_item_with_mnemonic(menu_in_menu, "CSG _Merge", "CSGMerge");
1723   }
1724   menu_separator(menu);
1725   {
1726     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "Clipper");
1727
1728     create_menu_item_with_mnemonic(menu_in_menu, "Clip selection", "ClipSelected");
1729     create_menu_item_with_mnemonic(menu_in_menu, "Split selection", "SplitSelected");
1730     create_menu_item_with_mnemonic(menu_in_menu, "Flip Clip orientation", "FlipClip");
1731   }
1732   menu_separator(menu);
1733   create_menu_item_with_mnemonic(menu, "Make detail", "MakeDetail");
1734   create_menu_item_with_mnemonic(menu, "Make structural", "MakeStructural");
1735
1736   create_check_menu_item_with_mnemonic(menu, "Texture Lock", "TogTexLock");
1737   menu_separator(menu);
1738   create_menu_item_with_mnemonic(menu, "Copy Face Texture", "FaceCopyTexture");
1739   create_menu_item_with_mnemonic(menu, "Paste Face Texture", "FacePasteTexture");
1740
1741   command_connect_accelerator("Brush3Sided");
1742   command_connect_accelerator("Brush4Sided");
1743   command_connect_accelerator("Brush5Sided");
1744   command_connect_accelerator("Brush6Sided");
1745   command_connect_accelerator("Brush7Sided");
1746   command_connect_accelerator("Brush8Sided");
1747   command_connect_accelerator("Brush9Sided");
1748 }