e8b605ca7d4a8da202ff4b350610644035951b12
[xonotic/netradiant.git] / radiant / brushmodule.cpp
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #include "brushmodule.h"
23
24 #include "qerplugin.h"
25
26 #include "brushnode.h"
27 #include "brushmanip.h"
28
29 #include "preferencesystem.h"
30 #include "stringio.h"
31
32 #include "map.h"
33 #include "qe3.h"
34 #include "mainframe.h"
35 #include "preferences.h"
36
37 LatchedBool g_useAlternativeTextureProjection(false, "Use alternative texture-projection");
38 bool g_showAlternativeTextureProjectionOption = false;
39 bool g_brush_always_caulk;
40
41 bool getTextureLockEnabled()
42 {
43   return g_brush_texturelock_enabled;
44 }
45
46 void Face_importSnapPlanes(bool value)
47 {
48   Face::m_quantise = value ? quantiseInteger : quantiseFloating;
49 }
50 typedef FreeCaller1<bool, Face_importSnapPlanes> FaceImportSnapPlanesCaller;
51
52 void Face_exportSnapPlanes(const BoolImportCallback& importer)
53 {
54   importer(Face::m_quantise == quantiseInteger);
55 }
56 typedef FreeCaller1<const BoolImportCallback&, Face_exportSnapPlanes> FaceExportSnapPlanesCaller;
57
58 void Brush_constructPreferences(PreferencesPage& page)
59 {
60   page.appendCheckBox(
61     "", "Snap planes to integer grid",
62     FaceImportSnapPlanesCaller(),
63     FaceExportSnapPlanesCaller()
64   );
65   page.appendEntry(
66     "Default texture scale",
67     g_texdef_default_scale
68   );
69   if(g_showAlternativeTextureProjectionOption)
70   {
71     page.appendCheckBox(
72       "", "Use alternative texture-projection",
73       LatchedBoolImportCaller(g_useAlternativeTextureProjection),
74       BoolExportCaller(g_useAlternativeTextureProjection.m_latched)
75     );
76   }
77   // d1223m
78   page.appendCheckBox("", 
79     "Always use caulk for new brushes",
80     g_brush_always_caulk
81   );
82 }
83 void Brush_constructPage(PreferenceGroup& group)
84 {
85   PreferencesPage page(group.createPage("Brush", "Brush Settings"));
86   Brush_constructPreferences(page);
87 }
88 void Brush_registerPreferencesPage()
89 {
90   PreferencesDialog_addSettingsPage(FreeCaller1<PreferenceGroup&, Brush_constructPage>());
91 }
92
93 void Brush_unlatchPreferences()
94 {
95         if(g_showAlternativeTextureProjectionOption)
96         {
97                 g_useAlternativeTextureProjection.useLatched();
98                 globalErrorStream() << "Unlatched g_useAlternativeTextureProjection (" << g_useAlternativeTextureProjection.m_value << ")\n";
99                 Brush::destroyStatic();
100                 Brush::constructStatic(g_useAlternativeTextureProjection.m_value ? eBrushTypeQuake3BP : eBrushTypeQuake3);
101         }
102 }
103
104 void Brush_Construct(EBrushType type)
105 {
106   if(type == eBrushTypeQuake3)
107   {
108     g_showAlternativeTextureProjectionOption = true;
109
110     GlobalPreferenceSystem().registerPreference(
111       "AlternativeTextureProjection",
112       BoolImportStringCaller(g_useAlternativeTextureProjection.m_latched),
113       BoolExportStringCaller(g_useAlternativeTextureProjection.m_latched)
114     );
115     g_useAlternativeTextureProjection.useLatched();
116
117     if(g_useAlternativeTextureProjection.m_value)
118     {
119       type = eBrushTypeQuake3BP;
120     }
121     
122     // d1223m
123     GlobalPreferenceSystem().registerPreference(
124       "BrushAlwaysCaulk", 
125       BoolImportStringCaller(g_brush_always_caulk), 
126       BoolExportStringCaller(g_brush_always_caulk));
127   }
128
129   Brush_registerCommands();
130   Brush_registerPreferencesPage();
131
132   BrushFilters_construct();
133
134   BrushClipPlane::constructStatic();
135   BrushInstance::constructStatic();
136   Brush::constructStatic(type);
137
138   Brush::m_maxWorldCoord = g_MaxWorldCoord;
139   BrushInstance::m_counter = &g_brushCount;
140
141   g_texdef_default_scale = 0.5f;
142   const char* value = g_pGameDescription->getKeyValue("default_scale");
143   if(!string_empty(value))
144   {
145     float scale = static_cast<float>(atof(value));
146     if(scale != 0)
147     {
148       g_texdef_default_scale = scale;
149     }
150     else
151     {
152       globalErrorStream() << "error parsing \"default_scale\" attribute\n";
153     }
154   }
155
156   GlobalPreferenceSystem().registerPreference("TextureLock", BoolImportStringCaller(g_brush_texturelock_enabled), BoolExportStringCaller(g_brush_texturelock_enabled));
157   GlobalPreferenceSystem().registerPreference("BrushSnapPlanes", makeBoolStringImportCallback(FaceImportSnapPlanesCaller()), makeBoolStringExportCallback(FaceExportSnapPlanesCaller()));
158   GlobalPreferenceSystem().registerPreference("TexdefDefaultScale", FloatImportStringCaller(g_texdef_default_scale), FloatExportStringCaller(g_texdef_default_scale));
159
160   GridStatus_getTextureLockEnabled = getTextureLockEnabled;
161   g_texture_lock_status_changed = FreeCaller<GridStatus_onTextureLockEnabledChanged>();
162 }
163
164 void Brush_Destroy()
165 {
166   Brush::m_maxWorldCoord = 0;
167   BrushInstance::m_counter = 0;
168
169   Brush::destroyStatic();
170   BrushInstance::destroyStatic();
171   BrushClipPlane::destroyStatic();
172 }
173
174 void Brush_clipperColourChanged()
175 {
176   BrushClipPlane::destroyStatic();
177   BrushClipPlane::constructStatic();
178 }
179
180 void BrushFaceData_fromFace(const BrushFaceDataCallback& callback, Face& face)
181 {
182   _QERFaceData faceData;
183   faceData.m_p0 = face.getPlane().planePoints()[0];
184   faceData.m_p1 = face.getPlane().planePoints()[1];
185   faceData.m_p2 = face.getPlane().planePoints()[2];
186   faceData.m_shader = face.GetShader();
187   faceData.m_texdef = face.getTexdef().m_projection.m_texdef;
188   faceData.contents = face.getShader().m_flags.m_contentFlags;
189   faceData.flags = face.getShader().m_flags.m_surfaceFlags;
190   faceData.value = face.getShader().m_flags.m_value;
191   callback(faceData);
192 }
193 typedef ConstReferenceCaller1<BrushFaceDataCallback, Face&, BrushFaceData_fromFace> BrushFaceDataFromFaceCaller;
194 typedef Callback1<Face&> FaceCallback;
195
196 class Quake3BrushCreator : public BrushCreator
197 {
198 public:
199   scene::Node& createBrush()
200   {
201     return (new BrushNode)->node();
202   }
203   bool useAlternativeTextureProjection() const
204   {
205     return g_useAlternativeTextureProjection.m_value;
206   }
207   void Brush_forEachFace(scene::Node& brush, const BrushFaceDataCallback& callback)
208   {
209     ::Brush_forEachFace(*Node_getBrush(brush), FaceCallback(BrushFaceDataFromFaceCaller(callback)));
210   }
211   bool Brush_addFace(scene::Node& brush, const _QERFaceData& faceData)
212   {
213     Node_getBrush(brush)->undoSave();
214     return Node_getBrush(brush)->addPlane(faceData.m_p0, faceData.m_p1, faceData.m_p2, faceData.m_shader, TextureProjection(faceData.m_texdef, brushprimit_texdef_t(), Vector3(0, 0, 0), Vector3(0, 0, 0))) != 0;
215   }
216 };
217
218 Quake3BrushCreator g_Quake3BrushCreator;
219
220 BrushCreator& GetBrushCreator()
221 {
222   return g_Quake3BrushCreator;
223 }
224
225 #include "modulesystem/singletonmodule.h"
226 #include "modulesystem/moduleregistry.h"
227
228
229 class BrushDependencies :
230   public GlobalRadiantModuleRef,
231   public GlobalSceneGraphModuleRef,
232   public GlobalShaderCacheModuleRef,
233   public GlobalSelectionModuleRef,
234   public GlobalOpenGLModuleRef,
235   public GlobalUndoModuleRef,
236   public GlobalFilterModuleRef
237 {
238 };
239
240 class BrushDoom3API : public TypeSystemRef
241 {
242   BrushCreator* m_brushdoom3;
243 public:
244   typedef BrushCreator Type;
245   STRING_CONSTANT(Name, "doom3");
246
247   BrushDoom3API()
248   {
249     Brush_Construct(eBrushTypeDoom3);
250
251      m_brushdoom3 = &GetBrushCreator();
252   }
253   ~BrushDoom3API()
254   {
255     Brush_Destroy();
256   }
257   BrushCreator* getTable()
258   {
259     return m_brushdoom3;
260   }
261 };
262
263 typedef SingletonModule<BrushDoom3API, BrushDependencies> BrushDoom3Module;
264 typedef Static<BrushDoom3Module> StaticBrushDoom3Module;
265 StaticRegisterModule staticRegisterBrushDoom3(StaticBrushDoom3Module::instance());
266
267
268 class BrushQuake4API : public TypeSystemRef
269 {
270   BrushCreator* m_brushquake4;
271 public:
272   typedef BrushCreator Type;
273   STRING_CONSTANT(Name, "quake4");
274
275   BrushQuake4API()
276   {
277     Brush_Construct(eBrushTypeQuake4);
278
279      m_brushquake4 = &GetBrushCreator();
280   }
281   ~BrushQuake4API()
282   {
283     Brush_Destroy();
284   }
285   BrushCreator* getTable()
286   {
287     return m_brushquake4;
288   }
289 };
290
291 typedef SingletonModule<BrushQuake4API, BrushDependencies> BrushQuake4Module;
292 typedef Static<BrushQuake4Module> StaticBrushQuake4Module;
293 StaticRegisterModule staticRegisterBrushQuake4(StaticBrushQuake4Module::instance());
294
295
296 class BrushQuake3API : public TypeSystemRef
297 {
298   BrushCreator* m_brushquake3;
299 public:
300   typedef BrushCreator Type;
301   STRING_CONSTANT(Name, "quake3");
302
303   BrushQuake3API()
304   {
305     Brush_Construct(eBrushTypeQuake3);
306
307     m_brushquake3 = &GetBrushCreator();
308   }
309   ~BrushQuake3API()
310   {
311     Brush_Destroy();
312   }
313   BrushCreator* getTable()
314   {
315     return m_brushquake3;
316   }
317 };
318
319 typedef SingletonModule<BrushQuake3API, BrushDependencies> BrushQuake3Module;
320 typedef Static<BrushQuake3Module> StaticBrushQuake3Module;
321 StaticRegisterModule staticRegisterBrushQuake3(StaticBrushQuake3Module::instance());
322
323
324 class BrushQuake2API : public TypeSystemRef
325 {
326   BrushCreator* m_brushquake2;
327 public:
328   typedef BrushCreator Type;
329   STRING_CONSTANT(Name, "quake2");
330
331   BrushQuake2API()
332   {
333     Brush_Construct(eBrushTypeQuake2);
334
335     m_brushquake2 = &GetBrushCreator();
336   }
337   ~BrushQuake2API()
338   {
339     Brush_Destroy();
340   }
341   BrushCreator* getTable()
342   {
343     return m_brushquake2;
344   }
345 };
346
347 typedef SingletonModule<BrushQuake2API, BrushDependencies> BrushQuake2Module;
348 typedef Static<BrushQuake2Module> StaticBrushQuake2Module;
349 StaticRegisterModule staticRegisterBrushQuake2(StaticBrushQuake2Module::instance());
350
351
352 class BrushQuake1API : public TypeSystemRef
353 {
354   BrushCreator* m_brushquake1;
355 public:
356   typedef BrushCreator Type;
357   STRING_CONSTANT(Name, "quake");
358
359   BrushQuake1API()
360   {
361     Brush_Construct(eBrushTypeQuake);
362
363     m_brushquake1 = &GetBrushCreator();
364   }
365   ~BrushQuake1API()
366   {
367     Brush_Destroy();
368   }
369   BrushCreator* getTable()
370   {
371     return m_brushquake1;
372   }
373 };
374
375 typedef SingletonModule<BrushQuake1API, BrushDependencies> BrushQuake1Module;
376 typedef Static<BrushQuake1Module> StaticBrushQuake1Module;
377 StaticRegisterModule staticRegisterBrushQuake1(StaticBrushQuake1Module::instance());
378
379
380 class BrushHalfLifeAPI : public TypeSystemRef
381 {
382   BrushCreator* m_brushhalflife;
383 public:
384   typedef BrushCreator Type;
385   STRING_CONSTANT(Name, "halflife");
386
387   BrushHalfLifeAPI()
388   {
389     Brush_Construct(eBrushTypeHalfLife);
390
391     m_brushhalflife = &GetBrushCreator();
392   }
393   ~BrushHalfLifeAPI()
394   {
395     Brush_Destroy();
396   }
397   BrushCreator* getTable()
398   {
399     return m_brushhalflife;
400   }
401 };
402
403 typedef SingletonModule<BrushHalfLifeAPI, BrushDependencies> BrushHalfLifeModule;
404 typedef Static<BrushHalfLifeModule> StaticBrushHalfLifeModule;
405 StaticRegisterModule staticRegisterBrushHalfLife(StaticBrushHalfLifeModule::instance());