]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/bobtoolz/shapes.cpp
Merge remote-tracking branch 'ttimo/master'
[xonotic/netradiant.git] / contrib / bobtoolz / shapes.cpp
1 /*
2    BobToolz plugin for GtkRadiant
3    Copyright (C) 2001 Gordon Biggans
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20
21 #include "shapes.h"
22
23 #include <list>
24
25 #include "DPoint.h"
26 #include "DPlane.h"
27
28 #include "str.h"
29 #include "misc.h"
30 #include "funchandlers.h"
31
32 #include "iundo.h"
33 #include "ishaders.h"
34 #include "ientity.h"
35 #include "ieclass.h"
36 #include "ipatch.h"
37 #include "qerplugin.h"
38
39 #include <vector>
40 #include <list>
41 #include <map>
42 #include <algorithm>
43 #include <time.h>
44
45 #include "scenelib.h"
46 #include "texturelib.h"
47
48 //#include "dialogs-gtk.h"
49
50 /************************
51     Cube Diagram
52 ************************/
53
54 /*
55
56         7 ----- 5
57         /|    /|
58        / |   / |
59       /  |  /  |
60     4 ----- 6  |
61  |  2|_|___|8
62  |  /  |   /
63  | /   |  /       ----> WEST, definitely
64  ||/    | /
65     1|_____|/3
66
67  */
68
69 /************************
70     Global Variables
71 ************************/
72
73 vec3_t g_Origin = {0.0f, 0.0f, 0.0f};
74
75 extern bool bFacesAll[];
76
77 /************************
78     Helper Functions
79 ************************/
80
81 float Deg2Rad( float angle ){
82         return (float)( angle * Q_PI / 180 );
83 }
84
85 void AddFaceWithTexture( scene::Node& brush, vec3_t va, vec3_t vb, vec3_t vc, const char* texture, bool detail ){
86         _QERFaceData faceData;
87         FillDefaultTexture( &faceData, va, vb, vc, texture );
88         if ( detail ) {
89                 faceData.contents |= FACE_DETAIL;
90         }
91         GlobalBrushCreator().Brush_addFace( brush, faceData );
92 }
93
94 void AddFaceWithTextureScaled( scene::Node& brush, vec3_t va, vec3_t vb, vec3_t vc,
95                                                            const char* texture, bool bVertScale, bool bHorScale,
96                                                            float minX, float minY, float maxX, float maxY ){
97         qtexture_t* pqtTexInfo;
98
99         // TTimo: there used to be a call to pfnHasShader here
100         //   this was not necessary. In Radiant everything is shader.
101         //   If a texture doesn't have a shader script, a default shader object is used.
102         // The IShader object was leaking also
103         // collect texture info: sizes, etc
104         IShader* i = GlobalShaderSystem().getShaderForName( texture );
105         pqtTexInfo = i->getTexture(); // shader width/height doesn't come out properly
106
107         if ( pqtTexInfo ) {
108                 float scale[2] = {0.5f, 0.5f};
109                 float shift[2] = {0, 0};
110
111                 if ( bHorScale ) {
112                         float width = maxX - minX;
113
114                         scale[0] = width / pqtTexInfo->width;
115                         shift[0] = -(float)( (int)maxX % (int)width ) / scale[0];
116                 }
117
118                 if ( bVertScale ) {
119                         float height = maxY - minY;
120
121                         scale[1] = height / pqtTexInfo->height;
122                         shift[1] = (float)( (int)minY % (int)height ) / scale[1];
123                 }
124
125                 _QERFaceData addFace;
126                 FillDefaultTexture( &addFace, va, vb, vc, texture );
127                 addFace.m_texdef.scale[0] = scale[0];
128                 addFace.m_texdef.scale[1] = scale[1];
129                 addFace.m_texdef.shift[0] = shift[0];
130                 addFace.m_texdef.shift[1] = shift[1];
131
132                 GlobalBrushCreator().Brush_addFace( brush, addFace );
133         }
134         else
135         {
136                 // shouldn't even get here, as default missing texture should be returned if
137                 // texture doesn't exist, but just in case
138                 AddFaceWithTexture( brush, va, vb, vc, texture, false );
139                 globalErrorStream() << "BobToolz::Invalid Texture Name-> " << texture;
140         }
141         // the IShader is not kept referenced, DecRef it
142         i->DecRef();
143 }
144
145 /************************
146     --Main Functions--
147 ************************/
148
149 void Build_Wedge( int dir, vec3_t min, vec3_t max, bool bUp ){
150         NodeSmartReference newBrush( GlobalBrushCreator().createBrush() );
151
152         vec3_t v1, v2, v3, v5, v6, v7, v8;
153         VectorCopy( min, v1 );
154         VectorCopy( min, v2 );
155         VectorCopy( min, v3 );
156         VectorCopy( max, v5 );
157         VectorCopy( max, v6 );
158         VectorCopy( max, v7 );
159         VectorCopy( max, v8 );
160
161         v2[0] = max[0];
162         v3[1] = max[1];
163
164         v6[0] = min[0];
165         v7[1] = min[1];
166         v8[2] = min[2];
167
168         if ( bUp ) {
169
170                 if ( dir != MOVE_EAST ) {
171                         AddFaceWithTexture( newBrush, v1, v3, v6, "textures/common/caulk", false );
172                 }
173
174                 if ( dir != MOVE_WEST ) {
175                         AddFaceWithTexture( newBrush, v7, v5, v8, "textures/common/caulk", false );
176                 }
177
178                 if ( dir != MOVE_NORTH ) {
179                         AddFaceWithTexture( newBrush, v1, v7, v2, "textures/common/caulk", false );
180                 }
181
182                 if ( dir != MOVE_SOUTH ) {
183                         AddFaceWithTexture( newBrush, v3, v8, v6, "textures/common/caulk", false );
184                 }
185
186                 AddFaceWithTexture( newBrush, v1, v2, v3, "textures/common/caulk", false );
187
188                 if ( dir == MOVE_EAST ) {
189                         AddFaceWithTexture( newBrush, v1, v3, v5, "textures/common/caulk", false );
190                 }
191
192                 if ( dir == MOVE_WEST ) {
193                         AddFaceWithTexture( newBrush, v2, v6, v8, "textures/common/caulk", false );
194                 }
195
196                 if ( dir == MOVE_NORTH ) {
197                         AddFaceWithTexture( newBrush, v1, v6, v5, "textures/common/caulk", false );
198                 }
199
200                 if ( dir == MOVE_SOUTH ) {
201                         AddFaceWithTexture( newBrush, v7, v3, v8, "textures/common/caulk", false );
202                 }
203         }
204         else
205         {
206                 if ( dir != MOVE_WEST ) {
207                         AddFaceWithTexture( newBrush, v7, v5, v8, "textures/common/caulk", false );
208                 }
209
210                 if ( dir != MOVE_EAST ) {
211                         AddFaceWithTexture( newBrush, v1, v3, v6, "textures/common/caulk", false );
212                 }
213
214                 if ( dir != MOVE_NORTH ) {
215                         AddFaceWithTexture( newBrush, v3, v8, v6, "textures/common/caulk", false );
216                 }
217
218                 if ( dir != MOVE_SOUTH ) {
219                         AddFaceWithTexture( newBrush, v1, v7, v2, "textures/common/caulk", false );
220                 }
221
222
223                 AddFaceWithTexture( newBrush, v6, v5, v7, "textures/common/caulk", false );
224
225                 if ( dir == MOVE_WEST ) {
226                         AddFaceWithTexture( newBrush, v1, v5, v3, "textures/common/caulk", false );
227                 }
228
229                 if ( dir == MOVE_EAST ) {
230                         AddFaceWithTexture( newBrush, v2, v8, v6, "textures/common/caulk", false );
231                 }
232
233                 if ( dir == MOVE_NORTH ) {
234                         AddFaceWithTexture( newBrush, v1, v5, v6, "textures/common/caulk", false );
235                 }
236
237                 if ( dir == MOVE_SOUTH ) {
238                         AddFaceWithTexture( newBrush, v7, v8, v3, "textures/common/caulk", false );
239                 }
240         }
241
242         Node_getTraversable( GlobalRadiant().getMapWorldEntity() )->insert( newBrush );
243 }
244
245 //-----------------------------------------------------------------------------------
246 //-----------------------------------------------------------------------------------
247
248 void Build_StairStep_Wedge( int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail ){
249         NodeSmartReference newBrush( GlobalBrushCreator().createBrush() );
250
251         //----- Build Outer Bounds ---------
252
253         vec3_t v1, v2, v3, v5, v6, v7, v8;
254         VectorCopy( min, v1 );
255         VectorCopy( min, v2 );
256         VectorCopy( min, v3 );
257         VectorCopy( max, v5 );
258         VectorCopy( max, v6 );
259         VectorCopy( max, v7 );
260         VectorCopy( max, v8 );
261
262         v2[0] = max[0];
263         v3[1] = max[1];
264
265         v6[0] = min[0];
266         v7[1] = min[1];
267
268         v8[2] = min[2];
269         //v8 needed this time, becoz of sloping faces (2-4-6-8)
270
271         //----------------------------------
272
273         AddFaceWithTexture( newBrush, v6, v5, v7, mainTexture, detail );
274
275         if ( dir != MOVE_EAST ) {
276                 if ( dir == MOVE_WEST ) {
277                         AddFaceWithTexture( newBrush, v5, v2, v7, riserTexture, detail );
278                 }
279                 else{
280                         AddFaceWithTexture( newBrush, v5, v2, v7, "textures/common/caulk", detail );
281                 }
282         }
283
284         if ( dir != MOVE_WEST ) {
285                 if ( dir == MOVE_EAST ) {
286                         AddFaceWithTexture( newBrush, v1, v3, v6, riserTexture, detail );
287                 }
288                 else{
289                         AddFaceWithTexture( newBrush, v1, v3, v6, "textures/common/caulk", detail );
290                 }
291         }
292
293         if ( dir != MOVE_NORTH ) {
294                 if ( dir == MOVE_SOUTH ) {
295                         AddFaceWithTexture( newBrush, v3, v5, v6, riserTexture, detail );
296                 }
297                 else{
298                         AddFaceWithTexture( newBrush, v3, v5, v6, "textures/common/caulk", detail );
299                 }
300         }
301
302         if ( dir != MOVE_SOUTH ) {
303                 if ( dir == MOVE_NORTH ) {
304                         AddFaceWithTexture( newBrush, v1, v7, v2, riserTexture, detail );
305                 }
306                 else{
307                         AddFaceWithTexture( newBrush, v1, v7, v2, "textures/common/caulk", detail );
308                 }
309         }
310
311
312         if ( dir == MOVE_EAST ) {
313                 AddFaceWithTexture( newBrush, v1, v5, v3, "textures/common/caulk", detail );
314         }
315
316         if ( dir == MOVE_WEST ) {
317                 AddFaceWithTexture( newBrush, v2, v8, v6, "textures/common/caulk", detail );
318         }
319
320         if ( dir == MOVE_NORTH ) {
321                 AddFaceWithTexture( newBrush, v1, v5, v6, "textures/common/caulk", detail );
322         }
323
324         if ( dir == MOVE_SOUTH ) {
325                 AddFaceWithTexture( newBrush, v7, v8, v3, "textures/common/caulk", detail );
326         }
327
328         Node_getTraversable( GlobalRadiant().getMapWorldEntity() )->insert( newBrush );
329 }
330
331 //-----------------------------------------------------------------------------------
332 //-----------------------------------------------------------------------------------
333
334 // internal use only, to get a box without finishing construction
335 scene::Node& Build_Get_BoundingCube_Selective( vec3_t min, vec3_t max, char* texture, bool* useFaces ){
336         NodeSmartReference newBrush( GlobalBrushCreator().createBrush() );
337
338         //----- Build Outer Bounds ---------
339
340         vec3_t v1, v2, v3, v5, v6, v7;
341         VectorCopy( min, v1 );
342         VectorCopy( min, v2 );
343         VectorCopy( min, v3 );
344         VectorCopy( max, v5 );
345         VectorCopy( max, v6 );
346         VectorCopy( max, v7 );
347
348         v2[0] = max[0];
349         v3[1] = max[1];
350
351         v6[0] = min[0];
352         v7[1] = min[1];
353
354         //----------------------------------
355
356         //----- Add Six Cube Faces ---------
357
358         if ( useFaces[0] ) {
359                 AddFaceWithTexture( newBrush, v1, v2, v3, texture, false );
360         }
361         if ( useFaces[1] ) {
362                 AddFaceWithTexture( newBrush, v1, v3, v6, texture, false );
363         }
364         if ( useFaces[2] ) {
365                 AddFaceWithTexture( newBrush, v1, v7, v2, texture, false );
366         }
367
368         if ( useFaces[3] ) {
369                 AddFaceWithTexture( newBrush, v5, v6, v3, texture, false );
370         }
371         if ( useFaces[4] ) {
372                 AddFaceWithTexture( newBrush, v5, v2, v7, texture, false );
373         }
374         if ( useFaces[5] ) {
375                 AddFaceWithTexture( newBrush, v5, v7, v6, texture, false );
376         }
377
378         //----------------------------------
379
380         return newBrush;
381 }
382
383 scene::Node& Build_Get_BoundingCube( vec3_t min, vec3_t max, char* texture ){
384         return Build_Get_BoundingCube_Selective( min, max, texture, bFacesAll );
385 }
386
387 //-----------------------------------------------------------------------------------
388 //-----------------------------------------------------------------------------------
389
390 void Build_StairStep( vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction ){
391         NodeSmartReference newBrush( GlobalBrushCreator().createBrush() );
392
393         //----- Build Outer Bounds ---------
394
395         vec3_t v1, v2, v3, v5, v6, v7;
396         VectorCopy( min, v1 );
397         VectorCopy( min, v2 );
398         VectorCopy( min, v3 );
399         VectorCopy( max, v5 );
400         VectorCopy( max, v6 );
401         VectorCopy( max, v7 );
402
403         v2[0] = max[0];
404         v3[1] = max[1];
405
406         v6[0] = min[0];
407         v7[1] = min[1];
408
409         //----------------------------------
410
411         AddFaceWithTexture( newBrush, v6, v5, v7, mainTexture, false );
412         // top gets current texture
413
414
415         if ( direction == MOVE_EAST ) {
416                 AddFaceWithTexture( newBrush, v1, v3, v6, riserTexture, false );
417         }
418         else{
419                 AddFaceWithTexture( newBrush, v1, v3, v6, "textures/common/caulk", false );
420         }
421         // west facing side, etc...
422
423
424         if ( direction == MOVE_NORTH ) {
425                 AddFaceWithTexture( newBrush, v1, v7, v2, riserTexture, false );
426         }
427         else{
428                 AddFaceWithTexture( newBrush, v1, v7, v2, "textures/common/caulk", false );
429         }
430
431         if ( direction == MOVE_SOUTH ) {
432                 AddFaceWithTexture( newBrush, v3, v5, v6, riserTexture, false );
433         }
434         else{
435                 AddFaceWithTexture( newBrush, v3, v5, v6, "textures/common/caulk", false );
436         }
437
438         if ( direction == MOVE_WEST ) {
439                 AddFaceWithTexture( newBrush, v7, v5, v2, riserTexture, false );
440         }
441         else{
442                 AddFaceWithTexture( newBrush, v7, v5, v2, "textures/common/caulk", false );
443         }
444
445
446         AddFaceWithTexture( newBrush, v1, v2, v3, "textures/common/caulk", false );
447         // base is caulked
448
449         Node_getTraversable( GlobalRadiant().getMapWorldEntity() )->insert( newBrush );
450         // finish brush
451 }
452
453 //-----------------------------------------------------------------------------------
454 //-----------------------------------------------------------------------------------
455
456 void BuildDoorsX2( vec3_t min, vec3_t max,
457                                    bool bSclMainHor, bool bSclMainVert,
458                                    bool bSclTrimHor, bool bSclTrimVert,
459                                    const char* mainTexture, const char* trimTexture,
460                                    int direction ){
461         int xy;
462         if ( direction == 0 ) {
463                 xy = 0;
464         }
465         else{
466                 xy = 1;
467         }
468
469         //----- Build Outer Bounds ---------
470
471         vec3_t v1, v2, v3, v5, v6, v7, ve_1, ve_2, ve_3;
472         VectorCopy( min, v1 );
473         VectorCopy( min, v2 );
474         VectorCopy( min, v3 );
475         VectorCopy( max, v5 );
476         VectorCopy( max, v6 );
477         VectorCopy( max, v7 );
478
479         v2[0] = max[0];
480         v3[1] = max[1];
481
482         v6[0] = min[0];
483         v7[1] = min[1];
484
485         float width = ( max[xy] - min[xy] ) / 2;
486
487         if ( direction == 0 ) {
488                 VectorCopy( v1, ve_1 );
489                 VectorCopy( v3, ve_2 );
490                 VectorCopy( v6, ve_3 );
491         }
492         else
493         {
494                 VectorCopy( v7, ve_1 );
495                 VectorCopy( v1, ve_2 );
496                 VectorCopy( v2, ve_3 );
497         }
498
499         ve_1[xy] += width;
500         ve_2[xy] += width;
501         ve_3[xy] += width;
502
503         //----------------------------------
504
505         NodeSmartReference newBrush1( GlobalBrushCreator().createBrush() );
506         NodeSmartReference newBrush2( GlobalBrushCreator().createBrush() );
507
508         AddFaceWithTexture( newBrush1, v1, v2, v3, "textures/common/caulk", false );
509         AddFaceWithTexture( newBrush1, v5, v7, v6, "textures/common/caulk", false );
510
511         AddFaceWithTexture( newBrush2, v1, v2, v3, "textures/common/caulk", false );
512         AddFaceWithTexture( newBrush2, v5, v7, v6, "textures/common/caulk", false );
513
514         if ( direction == 0 ) {
515                 AddFaceWithTexture( newBrush1, v1, v3, v6, "textures/common/caulk", false );
516                 AddFaceWithTexture( newBrush2, v5, v2, v7, "textures/common/caulk", false );
517         }
518         else
519         {
520                 AddFaceWithTexture( newBrush1, v1, v7, v2, "textures/common/caulk", false );
521                 AddFaceWithTexture( newBrush2, v5, v6, v3, "textures/common/caulk", false );
522         }
523
524         if ( direction == 0 ) {
525                 AddFaceWithTextureScaled( newBrush1, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor,
526                                                                   min[0], min[2], max[0], max[2] );
527                 AddFaceWithTextureScaled( newBrush1, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor,
528                                                                   max[0], min[2], min[0], max[2] );
529
530
531                 AddFaceWithTextureScaled( newBrush2, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor,
532                                                                   min[0], min[2], max[0], max[2] );
533                 AddFaceWithTextureScaled( newBrush2, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor,
534                                                                   max[0], min[2], min[0], max[2] ); // flip max/min to reverse tex dir
535
536
537
538                 AddFaceWithTextureScaled( newBrush1, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor,
539                                                                   min[1], min[2], max[1], max[2] );
540
541                 AddFaceWithTextureScaled( newBrush2, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor,
542                                                                   max[1], min[2], min[1], max[2] );
543         }
544         else
545         {
546                 AddFaceWithTextureScaled( newBrush1, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor,
547                                                                   min[1], min[2], max[1], max[2] );
548                 AddFaceWithTextureScaled( newBrush1, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor,
549                                                                   max[1], min[2], min[1], max[2] );
550
551
552                 AddFaceWithTextureScaled( newBrush2, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor,
553                                                                   min[1], min[2], max[1], max[2] );
554                 AddFaceWithTextureScaled( newBrush2, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor,
555                                                                   max[1], min[2], min[1], max[2] ); // flip max/min to reverse tex dir
556
557
558                 AddFaceWithTextureScaled( newBrush1, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor,
559                                                                   min[0], min[2], max[0], max[2] );
560
561                 AddFaceWithTextureScaled( newBrush2, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor,
562                                                                   max[0], min[2], min[0], max[2] );
563         }
564
565         //----------------------------------
566
567
568         EntityClass* doorClass = GlobalEntityClassManager().findOrInsert( "func_door", true );
569         NodeSmartReference pEDoor1( GlobalEntityCreator().createEntity( doorClass ) );
570         NodeSmartReference pEDoor2( GlobalEntityCreator().createEntity( doorClass ) );
571
572         if ( direction == 0 ) {
573                 Node_getEntity( pEDoor1 )->setKeyValue( "angle", "180" );
574                 Node_getEntity( pEDoor2 )->setKeyValue( "angle", "360" );
575         }
576         else
577         {
578                 Node_getEntity( pEDoor1 )->setKeyValue( "angle", "270" );
579                 Node_getEntity( pEDoor2 )->setKeyValue( "angle", "90" );
580         }
581
582         srand( (unsigned)time( NULL ) );
583
584         char teamname[256];
585         sprintf( teamname, "t%i", rand() );
586         Node_getEntity( pEDoor1 )->setKeyValue( "team", teamname );
587         Node_getEntity( pEDoor2 )->setKeyValue( "team", teamname );
588
589         Node_getTraversable( pEDoor1 )->insert( newBrush1 );
590         Node_getTraversable( pEDoor2 )->insert( newBrush2 );
591
592         Node_getTraversable( GlobalSceneGraph().root() )->insert( pEDoor1 );
593         Node_getTraversable( GlobalSceneGraph().root() )->insert( pEDoor2 );
594
595 //      ResetCurrentTexture();
596 }
597
598 //-----------------------------------------------------------------------------------
599 //-----------------------------------------------------------------------------------
600
601 void MakeBevel( vec3_t vMin, vec3_t vMax ){
602         NodeSmartReference patch( GlobalPatchCreator().createPatch() );
603         GlobalPatchCreator().Patch_resize( patch, 3, 3 );
604         GlobalPatchCreator().Patch_setShader( patch, "textures/common/caulk" );
605         PatchControlMatrix matrix = GlobalPatchCreator().Patch_getControlPoints( patch );
606         vec3_t x_3, y_3, z_3;
607         x_3[0] = vMin[0];   x_3[1] = vMin[0];               x_3[2] = vMax[0];
608         y_3[0] = vMin[1];   y_3[1] = vMax[1];               y_3[2] = vMax[1];
609         z_3[0] = vMin[2];   z_3[1] = ( vMax[2] + vMin[2] ) / 2; z_3[2] = vMax[2];
610         /*
611            x_3[0] = 0;          x_3[1] = 0;             x_3[2] = 64;
612            y_3[0] = 0;          y_3[1] = 64;    y_3[2] = 64;
613            z_3[0] = 0;          z_3[1] = 32;    z_3[2] = 64;*/
614         for ( int i = 0; i < 3; i++ )
615         {
616                 for ( int j = 0; j < 3; j++ )
617                 {
618                         PatchControl& p = matrix( i, j );
619                         p.m_vertex[0] = x_3[i];
620                         p.m_vertex[1] = y_3[i];
621                         p.m_vertex[2] = z_3[j];
622                 }
623         }
624         //does invert the matrix, else the patch face is on wrong side.
625         for ( int i = 0 ; i < 3 ; i++ )
626         {
627                 for ( int j = 0; j < 1; j++ )
628                 {
629                         PatchControl& p = matrix( i,2 - j );
630                         PatchControl& q = matrix( i, j );
631                         std::swap( p.m_vertex, q.m_vertex );
632                         //std::swap(p.m_texcoord, q.m_texcoord);
633                 }
634         }
635         GlobalPatchCreator().Patch_controlPointsChanged( patch );
636         //TODO - the patch has textures weird, patchmanip.h has all function it needs.. lots of duplicate code..
637         //NaturalTexture(patch);
638         Node_getTraversable( GlobalRadiant().getMapWorldEntity() )->insert( patch );
639 }
640
641 void BuildCornerStairs( vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex ){
642         vec3_t* topPoints = new vec3_t[nSteps + 1];
643         vec3_t* botPoints = new vec3_t[nSteps + 1];
644
645         //bool bFacesUse[6] = {true, true, false, true, false, false};
646
647         vec3_t centre;
648         VectorCopy( vMin, centre );
649         centre[0] = vMax[0];
650
651         int height = (int)( vMax[2] - vMin[2] ) / nSteps;
652
653         vec3_t vTop, vBot;
654         VectorCopy( vMax, vTop );
655         VectorCopy( vMin, vBot );
656         vTop[2] = vMin[2] + height;
657
658         int i;
659         for ( i = 0; i <= nSteps; i++ )
660         {
661                 VectorCopy( centre, topPoints[i] );
662                 VectorCopy( centre, botPoints[i] );
663
664                 topPoints[i][2] = vMax[2];
665                 botPoints[i][2] = vMin[2];
666
667                 topPoints[i][0] -= 10 * sinf( Q_PI * i / ( 2 * nSteps ) );
668                 topPoints[i][1] += 10 * cosf( Q_PI * i / ( 2 * nSteps ) );
669
670                 botPoints[i][0] = topPoints[i][0];
671                 botPoints[i][1] = topPoints[i][1];
672         }
673
674         vec3_t tp[3];
675         for ( int j = 0; j < 3; j++ )
676                 VectorCopy( topPoints[j], tp[j] );
677
678         for ( i = 0; i < nSteps; i++ )
679         {
680                 NodeSmartReference brush( GlobalBrushCreator().createBrush() );
681                 vec3_t v1, v2, v3, v5, v6, v7;
682                 VectorCopy( vBot, v1 );
683                 VectorCopy( vBot, v2 );
684                 VectorCopy( vBot, v3 );
685                 VectorCopy( vTop, v5 );
686                 VectorCopy( vTop, v6 );
687                 VectorCopy( vTop, v7 );
688
689                 v2[0] = vTop[0];
690                 v3[1] = vTop[1];
691
692                 v6[0] = vBot[0];
693                 v7[1] = vBot[1];
694
695                 AddFaceWithTexture( brush, v1, v2, v3, "textures/common/caulk", false );
696                 AddFaceWithTexture( brush, v1, v3, v6, "textures/common/caulk", false );
697                 AddFaceWithTexture( brush, v5, v6, v3, "textures/common/caulk", false );
698
699                 for ( int j = 0; j < 3; j++ )
700                         tp[j][2] = vTop[2];
701
702                 AddFaceWithTexture( brush, tp[2], tp[1], tp[0], mainTexture, false );
703
704                 AddFaceWithTexture( brush, centre, botPoints[i + 1], topPoints[i + 1], "textures/common/caulk", false );
705                 AddFaceWithTexture( brush, centre, topPoints[i], botPoints[i], riserTex, false );
706
707                 Node_getTraversable( GlobalRadiant().getMapWorldEntity() )->insert( brush );
708
709                 vTop[2] += height;
710                 vBot[2] += height;
711         }
712
713         delete[] topPoints;
714         delete[] botPoints;
715
716         vMin[2] += height;
717         vMax[2] += height;
718         MakeBevel( vMin, vMax );
719 }