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