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