radiant/layouts: add a single-window layout
[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 LatchedValue<bool> g_useAlternativeTextureProjection( false, "Use alternative texture-projection (\"brush primitives\")" );
38 bool g_showAlternativeTextureProjectionOption = false;
39 bool g_brush_always_caulk;
40
41 bool getTextureLockEnabled(){
42         return g_brush_texturelock_enabled;
43 }
44
45 struct Face_SnapPlanes {
46         static void Export(const QuantiseFunc &self, const Callback<void(bool)> &returnz) {
47                 returnz(self == quantiseInteger);
48         }
49
50         static void Import(QuantiseFunc &self, bool value) {
51                 self = value ? quantiseInteger : quantiseFloating;
52         }
53 };
54
55 void Brush_constructPreferences( PreferencesPage& page ){
56         page.appendCheckBox(
57                 "", "Snap planes to integer grid",
58                 make_property<Face_SnapPlanes>(Face::m_quantise)
59                 );
60         page.appendEntry(
61                 "Default texture scale",
62                 g_texdef_default_scale
63                 );
64         if ( g_showAlternativeTextureProjectionOption ) {
65                 page.appendCheckBox(
66                         "", "Use alternative texture-projection (\"brush primitives\")",
67                         make_property(g_useAlternativeTextureProjection)
68                         );
69         }
70         // d1223m
71         page.appendCheckBox( "",
72                                                  "Always use caulk for new brushes",
73                                                  g_brush_always_caulk
74                                                  );
75 }
76 void Brush_constructPage( PreferenceGroup& group ){
77         PreferencesPage page( group.createPage( "Brush", "Brush Settings" ) );
78         Brush_constructPreferences( page );
79 }
80 void Brush_registerPreferencesPage(){
81         PreferencesDialog_addSettingsPage( makeCallbackF(Brush_constructPage) );
82 }
83
84 void Brush_unlatchPreferences(){
85         Brush_toggleFormat( 0 );
86 }
87
88 void Brush_toggleFormat( int i ){
89         if ( g_showAlternativeTextureProjectionOption ) {
90                 g_useAlternativeTextureProjection.m_value = g_useAlternativeTextureProjection.m_latched ^ i;
91                 Brush::destroyStatic();
92                 Brush::constructStatic( g_useAlternativeTextureProjection.m_value ? eBrushTypeQuake3BP : eBrushTypeQuake3 );
93         }
94 }
95
96 int Brush_toggleFormatCount(){
97         if ( g_showAlternativeTextureProjectionOption ) {
98                 return 2;
99         }
100         return 1;
101 }
102
103 void Brush_switchFormat( bool switch_format ){
104         if ( switch_format )
105         {
106                 g_useAlternativeTextureProjection.m_latched = g_useAlternativeTextureProjection.m_value;
107                 g_useAlternativeTextureProjection.m_value = !g_useAlternativeTextureProjection.m_value;
108                 PreferencesDialog_restartRequired( g_useAlternativeTextureProjection.m_description );
109                 PreferencesDialog_restartIfRequired();
110         }
111 }
112
113 void Brush_Construct( EBrushType type ){
114         if ( type == eBrushTypeQuake3 ) {
115                 g_showAlternativeTextureProjectionOption = true;
116
117                 const char *value = g_pGameDescription->getKeyValue( "brush_primit" );
118                 if ( !string_empty( value ) ) {
119                         g_useAlternativeTextureProjection.m_latched = atoi( value );
120                 }
121
122                 GlobalPreferenceSystem().registerPreference(
123                         "AlternativeTextureProjection",
124                         make_property_string( g_useAlternativeTextureProjection.m_latched )
125                         );
126
127                 g_useAlternativeTextureProjection.useLatched();
128
129                 if ( g_useAlternativeTextureProjection.m_value ) {
130                         type = eBrushTypeQuake3BP;
131                 }
132
133                 // d1223m
134                 GlobalPreferenceSystem().registerPreference(
135                         "BrushAlwaysCaulk",
136             make_property_string( g_brush_always_caulk )
137         );
138         }
139
140         Brush_registerCommands();
141         Brush_registerPreferencesPage();
142
143         BrushFilters_construct();
144
145         BrushClipPlane::constructStatic();
146         BrushInstance::constructStatic();
147         Brush::constructStatic( type );
148
149         Brush::m_maxWorldCoord = g_MaxWorldCoord;
150         BrushInstance::m_counter = &g_brushCount;
151
152         g_texdef_default_scale = 0.5f;
153         const char* value = g_pGameDescription->getKeyValue( "default_scale" );
154         if ( !string_empty( value ) ) {
155                 float scale = static_cast<float>( atof( value ) );
156                 if ( scale != 0 ) {
157                         g_texdef_default_scale = scale;
158                 }
159                 else
160                 {
161                         globalErrorStream() << "error parsing \"default_scale\" attribute\n";
162                 }
163         }
164
165         GlobalPreferenceSystem().registerPreference( "TextureLock", make_property_string( g_brush_texturelock_enabled ) );
166         GlobalPreferenceSystem().registerPreference("BrushSnapPlanes", make_property_string<Face_SnapPlanes>(Face::m_quantise));
167         GlobalPreferenceSystem().registerPreference( "TexdefDefaultScale", make_property_string( g_texdef_default_scale ) );
168
169         GridStatus_getTextureLockEnabled = getTextureLockEnabled;
170         g_texture_lock_status_changed = makeCallbackF(GridStatus_onTextureLockEnabledChanged);
171 }
172
173 void Brush_Destroy(){
174         Brush::m_maxWorldCoord = 0;
175         BrushInstance::m_counter = 0;
176
177         Brush::destroyStatic();
178         BrushInstance::destroyStatic();
179         BrushClipPlane::destroyStatic();
180 }
181
182 void Brush_clipperColourChanged(){
183         BrushClipPlane::destroyStatic();
184         BrushClipPlane::constructStatic();
185 }
186
187 void BrushFaceData_fromFace( const BrushFaceDataCallback& callback, Face& face ){
188         _QERFaceData faceData;
189         faceData.m_p0 = face.getPlane().planePoints()[0];
190         faceData.m_p1 = face.getPlane().planePoints()[1];
191         faceData.m_p2 = face.getPlane().planePoints()[2];
192         faceData.m_shader = face.GetShader();
193         faceData.m_texdef = face.getTexdef().m_projection.m_texdef;
194         faceData.contents = face.getShader().m_flags.m_contentFlags;
195         faceData.flags = face.getShader().m_flags.m_surfaceFlags;
196         faceData.value = face.getShader().m_flags.m_value;
197         callback( faceData );
198 }
199 typedef ConstReferenceCaller<BrushFaceDataCallback, void(Face&), BrushFaceData_fromFace> BrushFaceDataFromFaceCaller;
200 typedef Callback<void(Face&)> FaceCallback;
201
202 class Quake3BrushCreator : public BrushCreator
203 {
204 public:
205 scene::Node& createBrush(){
206         return ( new BrushNode )->node();
207 }
208 bool useAlternativeTextureProjection() const {
209         return g_useAlternativeTextureProjection.m_value;
210 }
211 void Brush_forEachFace( scene::Node& brush, const BrushFaceDataCallback& callback ){
212         ::Brush_forEachFace( *Node_getBrush( brush ), FaceCallback( BrushFaceDataFromFaceCaller( callback ) ) );
213 }
214 bool Brush_addFace( scene::Node& brush, const _QERFaceData& faceData ){
215         Node_getBrush( brush )->undoSave();
216         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;
217 }
218 };
219
220 Quake3BrushCreator g_Quake3BrushCreator;
221
222 BrushCreator& GetBrushCreator(){
223         return g_Quake3BrushCreator;
224 }
225
226 #include "modulesystem/singletonmodule.h"
227 #include "modulesystem/moduleregistry.h"
228
229
230 class BrushDependencies :
231         public GlobalRadiantModuleRef,
232         public GlobalSceneGraphModuleRef,
233         public GlobalShaderCacheModuleRef,
234         public GlobalSelectionModuleRef,
235         public GlobalOpenGLModuleRef,
236         public GlobalUndoModuleRef,
237         public GlobalFilterModuleRef
238 {
239 };
240
241 class BrushDoom3API : public TypeSystemRef
242 {
243 BrushCreator* m_brushdoom3;
244 public:
245 typedef BrushCreator Type;
246 STRING_CONSTANT( Name, "doom3" );
247
248 BrushDoom3API(){
249         Brush_Construct( eBrushTypeDoom3 );
250
251         m_brushdoom3 = &GetBrushCreator();
252 }
253 ~BrushDoom3API(){
254         Brush_Destroy();
255 }
256 BrushCreator* getTable(){
257         return m_brushdoom3;
258 }
259 };
260
261 typedef SingletonModule<BrushDoom3API, BrushDependencies> BrushDoom3Module;
262 typedef Static<BrushDoom3Module> StaticBrushDoom3Module;
263 StaticRegisterModule staticRegisterBrushDoom3( StaticBrushDoom3Module::instance() );
264
265
266 class BrushQuake4API : public TypeSystemRef
267 {
268 BrushCreator* m_brushquake4;
269 public:
270 typedef BrushCreator Type;
271 STRING_CONSTANT( Name, "quake4" );
272
273 BrushQuake4API(){
274         Brush_Construct( eBrushTypeQuake4 );
275
276         m_brushquake4 = &GetBrushCreator();
277 }
278 ~BrushQuake4API(){
279         Brush_Destroy();
280 }
281 BrushCreator* getTable(){
282         return m_brushquake4;
283 }
284 };
285
286 typedef SingletonModule<BrushQuake4API, BrushDependencies> BrushQuake4Module;
287 typedef Static<BrushQuake4Module> StaticBrushQuake4Module;
288 StaticRegisterModule staticRegisterBrushQuake4( StaticBrushQuake4Module::instance() );
289
290
291 class BrushQuake3API : public TypeSystemRef
292 {
293 BrushCreator* m_brushquake3;
294 public:
295 typedef BrushCreator Type;
296 STRING_CONSTANT( Name, "quake3" );
297
298 BrushQuake3API(){
299         Brush_Construct( eBrushTypeQuake3 );
300
301         m_brushquake3 = &GetBrushCreator();
302 }
303 ~BrushQuake3API(){
304         Brush_Destroy();
305 }
306 BrushCreator* getTable(){
307         return m_brushquake3;
308 }
309 };
310
311 typedef SingletonModule<BrushQuake3API, BrushDependencies> BrushQuake3Module;
312 typedef Static<BrushQuake3Module> StaticBrushQuake3Module;
313 StaticRegisterModule staticRegisterBrushQuake3( StaticBrushQuake3Module::instance() );
314
315
316 class BrushQuake2API : public TypeSystemRef
317 {
318 BrushCreator* m_brushquake2;
319 public:
320 typedef BrushCreator Type;
321 STRING_CONSTANT( Name, "quake2" );
322
323 BrushQuake2API(){
324         Brush_Construct( eBrushTypeQuake2 );
325
326         m_brushquake2 = &GetBrushCreator();
327 }
328 ~BrushQuake2API(){
329         Brush_Destroy();
330 }
331 BrushCreator* getTable(){
332         return m_brushquake2;
333 }
334 };
335
336 typedef SingletonModule<BrushQuake2API, BrushDependencies> BrushQuake2Module;
337 typedef Static<BrushQuake2Module> StaticBrushQuake2Module;
338 StaticRegisterModule staticRegisterBrushQuake2( StaticBrushQuake2Module::instance() );
339
340
341 class BrushQuake1API : public TypeSystemRef
342 {
343 BrushCreator* m_brushquake1;
344 public:
345 typedef BrushCreator Type;
346 STRING_CONSTANT( Name, "quake" );
347
348 BrushQuake1API(){
349         Brush_Construct( eBrushTypeQuake );
350
351         m_brushquake1 = &GetBrushCreator();
352 }
353 ~BrushQuake1API(){
354         Brush_Destroy();
355 }
356 BrushCreator* getTable(){
357         return m_brushquake1;
358 }
359 };
360
361 typedef SingletonModule<BrushQuake1API, BrushDependencies> BrushQuake1Module;
362 typedef Static<BrushQuake1Module> StaticBrushQuake1Module;
363 StaticRegisterModule staticRegisterBrushQuake1( StaticBrushQuake1Module::instance() );
364
365
366 class BrushHalfLifeAPI : public TypeSystemRef
367 {
368 BrushCreator* m_brushhalflife;
369 public:
370 typedef BrushCreator Type;
371 STRING_CONSTANT( Name, "halflife" );
372
373 BrushHalfLifeAPI(){
374         Brush_Construct( eBrushTypeHalfLife );
375
376         m_brushhalflife = &GetBrushCreator();
377 }
378 ~BrushHalfLifeAPI(){
379         Brush_Destroy();
380 }
381 BrushCreator* getTable(){
382         return m_brushhalflife;
383 }
384 };
385
386 typedef SingletonModule<BrushHalfLifeAPI, BrushDependencies> BrushHalfLifeModule;
387 typedef Static<BrushHalfLifeModule> StaticBrushHalfLifeModule;
388 StaticRegisterModule staticRegisterBrushHalfLife( StaticBrushHalfLifeModule::instance() );