]> git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/bobtoolz/shapes.cpp
multicontext: optional per-viewport texture bind
[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 = QERApp_Shader_ForName( texture );
105
106         pqtTexInfo = i->getTexture(); // shader width/height doesn't come out properly
107
108         if ( pqtTexInfo ) {
109                 float scale[2] = {0.5f, 0.5f};
110                 float shift[2] = {0, 0};
111
112                 if ( bHorScale ) {
113                         float width = maxX - minX;
114
115                         scale[0] = width / pqtTexInfo->width;
116                         shift[0] = -(float)( (int)maxX % (int)width ) / scale[0];
117                 }
118
119                 if ( bVertScale ) {
120                         float height = maxY - minY;
121
122                         scale[1] = height / pqtTexInfo->height;
123                         shift[1] = (float)( (int)minY % (int)height ) / scale[1];
124                 }
125
126                 _QERFaceData addFace;
127                 FillDefaultTexture( &addFace, va, vb, vc, texture );
128                 addFace.m_texdef.scale[0] = scale[0];
129                 addFace.m_texdef.scale[1] = scale[1];
130                 addFace.m_texdef.shift[0] = shift[0];
131                 addFace.m_texdef.shift[1] = shift[1];
132
133                 GlobalBrushCreator().Brush_addFace( brush, addFace );
134         }
135         else
136         {
137                 // shouldn't even get here, as default missing texture should be returned if
138                 // texture doesn't exist, but just in case
139                 AddFaceWithTexture( brush, va, vb, vc, texture, false );
140                 globalErrorStream() << "BobToolz::Invalid Texture Name-> " << texture;
141         }
142         // the IShader is not kept referenced, DecRef it
143         i->DecRef();
144 }
145
146 /************************
147     --Main Functions--
148 ************************/
149
150 void Build_Wedge( int dir, vec3_t min, vec3_t max, bool bUp ){
151         NodeSmartReference newBrush( GlobalBrushCreator().createBrush() );
152
153         vec3_t v1, v2, v3, v5, v6, v7, v8;
154         VectorCopy( min, v1 );
155         VectorCopy( min, v2 );
156         VectorCopy( min, v3 );
157         VectorCopy( max, v5 );
158         VectorCopy( max, v6 );
159         VectorCopy( max, v7 );
160         VectorCopy( max, v8 );
161
162         v2[0] = max[0];
163         v3[1] = max[1];
164
165         v6[0] = min[0];
166         v7[1] = min[1];
167         v8[2] = min[2];
168
169         if ( bUp ) {
170
171                 if ( dir != MOVE_EAST ) {
172                         AddFaceWithTexture( newBrush, v1, v3, v6, "textures/common/caulk", false );
173                 }
174
175                 if ( dir != MOVE_WEST ) {
176                         AddFaceWithTexture( newBrush, v7, v5, v8, "textures/common/caulk", false );
177                 }
178
179                 if ( dir != MOVE_NORTH ) {
180                         AddFaceWithTexture( newBrush, v1, v7, v2, "textures/common/caulk", false );
181                 }
182
183                 if ( dir != MOVE_SOUTH ) {
184                         AddFaceWithTexture( newBrush, v3, v8, v6, "textures/common/caulk", false );
185                 }
186
187                 AddFaceWithTexture( newBrush, v1, v2, v3, "textures/common/caulk", false );
188
189                 if ( dir == MOVE_EAST ) {
190                         AddFaceWithTexture( newBrush, v1, v3, v5, "textures/common/caulk", false );
191                 }
192
193                 if ( dir == MOVE_WEST ) {
194                         AddFaceWithTexture( newBrush, v2, v6, v8, "textures/common/caulk", false );
195                 }
196
197                 if ( dir == MOVE_NORTH ) {
198                         AddFaceWithTexture( newBrush, v1, v6, v5, "textures/common/caulk", false );
199                 }
200
201                 if ( dir == MOVE_SOUTH ) {
202                         AddFaceWithTexture( newBrush, v7, v3, v8, "textures/common/caulk", false );
203                 }
204         }
205         else
206         {
207                 if ( dir != MOVE_WEST ) {
208                         AddFaceWithTexture( newBrush, v7, v5, v8, "textures/common/caulk", false );
209                 }
210
211                 if ( dir != MOVE_EAST ) {
212                         AddFaceWithTexture( newBrush, v1, v3, v6, "textures/common/caulk", false );
213                 }
214
215                 if ( dir != MOVE_NORTH ) {
216                         AddFaceWithTexture( newBrush, v3, v8, v6, "textures/common/caulk", false );
217                 }
218
219                 if ( dir != MOVE_SOUTH ) {
220                         AddFaceWithTexture( newBrush, v1, v7, v2, "textures/common/caulk", false );
221                 }
222
223
224                 AddFaceWithTexture( newBrush, v6, v5, v7, "textures/common/caulk", false );
225
226                 if ( dir == MOVE_WEST ) {
227                         AddFaceWithTexture( newBrush, v1, v5, v3, "textures/common/caulk", false );
228                 }
229
230                 if ( dir == MOVE_EAST ) {
231                         AddFaceWithTexture( newBrush, v2, v8, v6, "textures/common/caulk", false );
232                 }
233
234                 if ( dir == MOVE_NORTH ) {
235                         AddFaceWithTexture( newBrush, v1, v5, v6, "textures/common/caulk", false );
236                 }
237
238                 if ( dir == MOVE_SOUTH ) {
239                         AddFaceWithTexture( newBrush, v7, v8, v3, "textures/common/caulk", false );
240                 }
241         }
242
243         Node_getTraversable( GlobalRadiant().getMapWorldEntity() )->insert( newBrush );
244 }
245
246 //-----------------------------------------------------------------------------------
247 //-----------------------------------------------------------------------------------
248
249 void Build_StairStep_Wedge( int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail ){
250         NodeSmartReference newBrush( GlobalBrushCreator().createBrush() );
251
252         //----- Build Outer Bounds ---------
253
254         vec3_t v1, v2, v3, v5, v6, v7, v8;
255         VectorCopy( min, v1 );
256         VectorCopy( min, v2 );
257         VectorCopy( min, v3 );
258         VectorCopy( max, v5 );
259         VectorCopy( max, v6 );
260         VectorCopy( max, v7 );
261         VectorCopy( max, v8 );
262
263         v2[0] = max[0];
264         v3[1] = max[1];
265
266         v6[0] = min[0];
267         v7[1] = min[1];
268
269         v8[2] = min[2];
270         //v8 needed this time, becoz of sloping faces (2-4-6-8)
271
272         //----------------------------------
273
274         AddFaceWithTexture( newBrush, v6, v5, v7, mainTexture, detail );
275
276         if ( dir != MOVE_EAST ) {
277                 if ( dir == MOVE_WEST ) {
278                         AddFaceWithTexture( newBrush, v5, v2, v7, riserTexture, detail );
279                 }
280                 else{
281                         AddFaceWithTexture( newBrush, v5, v2, v7, "textures/common/caulk", detail );
282                 }
283         }
284
285         if ( dir != MOVE_WEST ) {
286                 if ( dir == MOVE_EAST ) {
287                         AddFaceWithTexture( newBrush, v1, v3, v6, riserTexture, detail );
288                 }
289                 else{
290                         AddFaceWithTexture( newBrush, v1, v3, v6, "textures/common/caulk", detail );
291                 }
292         }
293
294         if ( dir != MOVE_NORTH ) {
295                 if ( dir == MOVE_SOUTH ) {
296                         AddFaceWithTexture( newBrush, v3, v5, v6, riserTexture, detail );
297                 }
298                 else{
299                         AddFaceWithTexture( newBrush, v3, v5, v6, "textures/common/caulk", detail );
300                 }
301         }
302
303         if ( dir != MOVE_SOUTH ) {
304                 if ( dir == MOVE_NORTH ) {
305                         AddFaceWithTexture( newBrush, v1, v7, v2, riserTexture, detail );
306                 }
307                 else{
308                         AddFaceWithTexture( newBrush, v1, v7, v2, "textures/common/caulk", detail );
309                 }
310         }
311
312
313         if ( dir == MOVE_EAST ) {
314                 AddFaceWithTexture( newBrush, v1, v5, v3, "textures/common/caulk", detail );
315         }
316
317         if ( dir == MOVE_WEST ) {
318                 AddFaceWithTexture( newBrush, v2, v8, v6, "textures/common/caulk", detail );
319         }
320
321         if ( dir == MOVE_NORTH ) {
322                 AddFaceWithTexture( newBrush, v1, v5, v6, "textures/common/caulk", detail );
323         }
324
325         if ( dir == MOVE_SOUTH ) {
326                 AddFaceWithTexture( newBrush, v7, v8, v3, "textures/common/caulk", detail );
327         }
328
329         Node_getTraversable( GlobalRadiant().getMapWorldEntity() )->insert( newBrush );
330 }
331
332 //-----------------------------------------------------------------------------------
333 //-----------------------------------------------------------------------------------
334
335 // internal use only, to get a box without finishing construction
336 scene::Node& Build_Get_BoundingCube_Selective( vec3_t min, vec3_t max, char* texture, bool* useFaces ){
337         NodeSmartReference newBrush( GlobalBrushCreator().createBrush() );
338
339         //----- Build Outer Bounds ---------
340
341         vec3_t v1, v2, v3, v5, v6, v7;
342         VectorCopy( min, v1 );
343         VectorCopy( min, v2 );
344         VectorCopy( min, v3 );
345         VectorCopy( max, v5 );
346         VectorCopy( max, v6 );
347         VectorCopy( max, v7 );
348
349         v2[0] = max[0];
350         v3[1] = max[1];
351
352         v6[0] = min[0];
353         v7[1] = min[1];
354
355         //----------------------------------
356
357         //----- Add Six Cube Faces ---------
358
359         if ( useFaces[0] ) {
360                 AddFaceWithTexture( newBrush, v1, v2, v3, texture, false );
361         }
362         if ( useFaces[1] ) {
363                 AddFaceWithTexture( newBrush, v1, v3, v6, texture, false );
364         }
365         if ( useFaces[2] ) {
366                 AddFaceWithTexture( newBrush, v1, v7, v2, texture, false );
367         }
368
369         if ( useFaces[3] ) {
370                 AddFaceWithTexture( newBrush, v5, v6, v3, texture, false );
371         }
372         if ( useFaces[4] ) {
373                 AddFaceWithTexture( newBrush, v5, v2, v7, texture, false );
374         }
375         if ( useFaces[5] ) {
376                 AddFaceWithTexture( newBrush, v5, v7, v6, texture, false );
377         }
378
379         //----------------------------------
380
381         return newBrush;
382 }
383
384 scene::Node& Build_Get_BoundingCube( vec3_t min, vec3_t max, char* texture ){
385         return Build_Get_BoundingCube_Selective( min, max, texture, bFacesAll );
386 }
387
388 //-----------------------------------------------------------------------------------
389 //-----------------------------------------------------------------------------------
390
391 void Build_StairStep( vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction ){
392         NodeSmartReference newBrush( GlobalBrushCreator().createBrush() );
393
394         //----- Build Outer Bounds ---------
395
396         vec3_t v1, v2, v3, v5, v6, v7;
397         VectorCopy( min, v1 );
398         VectorCopy( min, v2 );
399         VectorCopy( min, v3 );
400         VectorCopy( max, v5 );
401         VectorCopy( max, v6 );
402         VectorCopy( max, v7 );
403
404         v2[0] = max[0];
405         v3[1] = max[1];
406
407         v6[0] = min[0];
408         v7[1] = min[1];
409
410         //----------------------------------
411
412         AddFaceWithTexture( newBrush, v6, v5, v7, mainTexture, false );
413         // top gets current texture
414
415
416         if ( direction == MOVE_EAST ) {
417                 AddFaceWithTexture( newBrush, v1, v3, v6, riserTexture, false );
418         }
419         else{
420                 AddFaceWithTexture( newBrush, v1, v3, v6, "textures/common/caulk", false );
421         }
422         // west facing side, etc...
423
424
425         if ( direction == MOVE_NORTH ) {
426                 AddFaceWithTexture( newBrush, v1, v7, v2, riserTexture, false );
427         }
428         else{
429                 AddFaceWithTexture( newBrush, v1, v7, v2, "textures/common/caulk", false );
430         }
431
432         if ( direction == MOVE_SOUTH ) {
433                 AddFaceWithTexture( newBrush, v3, v5, v6, riserTexture, false );
434         }
435         else{
436                 AddFaceWithTexture( newBrush, v3, v5, v6, "textures/common/caulk", false );
437         }
438
439         if ( direction == MOVE_WEST ) {
440                 AddFaceWithTexture( newBrush, v7, v5, v2, riserTexture, false );
441         }
442         else{
443                 AddFaceWithTexture( newBrush, v7, v5, v2, "textures/common/caulk", false );
444         }
445
446
447         AddFaceWithTexture( newBrush, v1, v2, v3, "textures/common/caulk", false );
448         // base is caulked
449
450         Node_getTraversable( GlobalRadiant().getMapWorldEntity() )->insert( newBrush );
451         // finish brush
452 }
453
454 //-----------------------------------------------------------------------------------
455 //-----------------------------------------------------------------------------------
456
457 void BuildDoorsX2( vec3_t min, vec3_t max,
458                                    bool bSclMainHor, bool bSclMainVert,
459                                    bool bSclTrimHor, bool bSclTrimVert,
460                                    const char* mainTexture, const char* trimTexture,
461                                    int direction ){
462         int xy;
463         if ( direction == 0 ) {
464                 xy = 0;
465         }
466         else{
467                 xy = 1;
468         }
469
470         //----- Build Outer Bounds ---------
471
472         vec3_t v1, v2, v3, v5, v6, v7, ve_1, ve_2, ve_3;
473         VectorCopy( min, v1 );
474         VectorCopy( min, v2 );
475         VectorCopy( min, v3 );
476         VectorCopy( max, v5 );
477         VectorCopy( max, v6 );
478         VectorCopy( max, v7 );
479
480         v2[0] = max[0];
481         v3[1] = max[1];
482
483         v6[0] = min[0];
484         v7[1] = min[1];
485
486         float width = ( max[xy] - min[xy] ) / 2;
487
488         if ( direction == 0 ) {
489                 VectorCopy( v1, ve_1 );
490                 VectorCopy( v3, ve_2 );
491                 VectorCopy( v6, ve_3 );
492         }
493         else
494         {
495                 VectorCopy( v7, ve_1 );
496                 VectorCopy( v1, ve_2 );
497                 VectorCopy( v2, ve_3 );
498         }
499
500         ve_1[xy] += width;
501         ve_2[xy] += width;
502         ve_3[xy] += width;
503
504         //----------------------------------
505
506         NodeSmartReference newBrush1( GlobalBrushCreator().createBrush() );
507         NodeSmartReference newBrush2( GlobalBrushCreator().createBrush() );
508
509         AddFaceWithTexture( newBrush1, v1, v2, v3, "textures/common/caulk", false );
510         AddFaceWithTexture( newBrush1, v5, v7, v6, "textures/common/caulk", false );
511
512         AddFaceWithTexture( newBrush2, v1, v2, v3, "textures/common/caulk", false );
513         AddFaceWithTexture( newBrush2, v5, v7, v6, "textures/common/caulk", false );
514
515         if ( direction == 0 ) {
516                 AddFaceWithTexture( newBrush1, v1, v3, v6, "textures/common/caulk", false );
517                 AddFaceWithTexture( newBrush2, v5, v2, v7, "textures/common/caulk", false );
518         }
519         else
520         {
521                 AddFaceWithTexture( newBrush1, v1, v7, v2, "textures/common/caulk", false );
522                 AddFaceWithTexture( newBrush2, v5, v6, v3, "textures/common/caulk", false );
523         }
524
525         if ( direction == 0 ) {
526                 AddFaceWithTextureScaled( newBrush1, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor,
527                                                                   min[0], min[2], max[0], max[2] );
528                 AddFaceWithTextureScaled( newBrush1, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor,
529                                                                   max[0], min[2], min[0], max[2] );
530
531
532                 AddFaceWithTextureScaled( newBrush2, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor,
533                                                                   min[0], min[2], max[0], max[2] );
534                 AddFaceWithTextureScaled( newBrush2, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor,
535                                                                   max[0], min[2], min[0], max[2] ); // flip max/min to reverse tex dir
536
537
538
539                 AddFaceWithTextureScaled( newBrush1, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor,
540                                                                   min[1], min[2], max[1], max[2] );
541
542                 AddFaceWithTextureScaled( newBrush2, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor,
543                                                                   max[1], min[2], min[1], max[2] );
544         }
545         else
546         {
547                 AddFaceWithTextureScaled( newBrush1, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor,
548                                                                   min[1], min[2], max[1], max[2] );
549                 AddFaceWithTextureScaled( newBrush1, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor,
550                                                                   max[1], min[2], min[1], max[2] );
551
552
553                 AddFaceWithTextureScaled( newBrush2, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor,
554                                                                   min[1], min[2], max[1], max[2] );
555                 AddFaceWithTextureScaled( newBrush2, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor,
556                                                                   max[1], min[2], min[1], max[2] ); // flip max/min to reverse tex dir
557
558
559                 AddFaceWithTextureScaled( newBrush1, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor,
560                                                                   min[0], min[2], max[0], max[2] );
561
562                 AddFaceWithTextureScaled( newBrush2, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor,
563                                                                   max[0], min[2], min[0], max[2] );
564         }
565
566         //----------------------------------
567
568
569         EntityClass* doorClass = GlobalEntityClassManager().findOrInsert( "func_door", true );
570         NodeSmartReference pEDoor1( GlobalEntityCreator().createEntity( doorClass ) );
571         NodeSmartReference pEDoor2( GlobalEntityCreator().createEntity( doorClass ) );
572
573         if ( direction == 0 ) {
574                 Node_getEntity( pEDoor1 )->setKeyValue( "angle", "180" );
575                 Node_getEntity( pEDoor2 )->setKeyValue( "angle", "360" );
576         }
577         else
578         {
579                 Node_getEntity( pEDoor1 )->setKeyValue( "angle", "270" );
580                 Node_getEntity( pEDoor2 )->setKeyValue( "angle", "90" );
581         }
582
583         srand( (unsigned)time( NULL ) );
584
585         char teamname[256];
586         sprintf( teamname, "t%i", rand() );
587         Node_getEntity( pEDoor1 )->setKeyValue( "team", teamname );
588         Node_getEntity( pEDoor2 )->setKeyValue( "team", teamname );
589
590         Node_getTraversable( pEDoor1 )->insert( newBrush1 );
591         Node_getTraversable( pEDoor2 )->insert( newBrush2 );
592
593         Node_getTraversable( GlobalSceneGraph().root() )->insert( pEDoor1 );
594         Node_getTraversable( GlobalSceneGraph().root() )->insert( pEDoor2 );
595
596 //      ResetCurrentTexture();
597 }
598
599 //-----------------------------------------------------------------------------------
600 //-----------------------------------------------------------------------------------
601
602 void MakeBevel( vec3_t vMin, vec3_t vMax ){
603         NodeSmartReference patch( GlobalPatchCreator().createPatch() );
604         GlobalPatchCreator().Patch_resize( patch, 3, 3 );
605         GlobalPatchCreator().Patch_setShader( patch, "textures/common/caulk" );
606         PatchControlMatrix matrix = GlobalPatchCreator().Patch_getControlPoints( patch );
607         vec3_t x_3, y_3, z_3;
608         x_3[0] = vMin[0];   x_3[1] = vMin[0];               x_3[2] = vMax[0];
609         y_3[0] = vMin[1];   y_3[1] = vMax[1];               y_3[2] = vMax[1];
610         z_3[0] = vMin[2];   z_3[1] = ( vMax[2] + vMin[2] ) / 2; z_3[2] = vMax[2];
611         /*
612            x_3[0] = 0;          x_3[1] = 0;             x_3[2] = 64;
613            y_3[0] = 0;          y_3[1] = 64;    y_3[2] = 64;
614            z_3[0] = 0;          z_3[1] = 32;    z_3[2] = 64;*/
615         for ( int i = 0; i < 3; i++ )
616         {
617                 for ( int j = 0; j < 3; j++ )
618                 {
619                         PatchControl& p = matrix( i, j );
620                         p.m_vertex[0] = x_3[i];
621                         p.m_vertex[1] = y_3[i];
622                         p.m_vertex[2] = z_3[j];
623                 }
624         }
625         //does invert the matrix, else the patch face is on wrong side.
626         for ( int i = 0 ; i < 3 ; i++ )
627         {
628                 for ( int j = 0; j < 1; j++ )
629                 {
630                         PatchControl& p = matrix( i,2 - j );
631                         PatchControl& q = matrix( i, j );
632                         std::swap( p.m_vertex, q.m_vertex );
633                         //std::swap(p.m_texcoord, q.m_texcoord);
634                 }
635         }
636         GlobalPatchCreator().Patch_controlPointsChanged( patch );
637         //TODO - the patch has textures weird, patchmanip.h has all function it needs.. lots of duplicate code..
638         //NaturalTexture(patch);
639         Node_getTraversable( GlobalRadiant().getMapWorldEntity() )->insert( patch );
640 }
641
642 void BuildCornerStairs( vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex ){
643         vec3_t* topPoints = new vec3_t[nSteps + 1];
644         vec3_t* botPoints = new vec3_t[nSteps + 1];
645
646         //bool bFacesUse[6] = {true, true, false, true, false, false};
647
648         vec3_t centre;
649         VectorCopy( vMin, centre );
650         centre[0] = vMax[0];
651
652         int height = (int)( vMax[2] - vMin[2] ) / nSteps;
653
654         vec3_t vTop, vBot;
655         VectorCopy( vMax, vTop );
656         VectorCopy( vMin, vBot );
657         vTop[2] = vMin[2] + height;
658
659         int i;
660         for ( i = 0; i <= nSteps; i++ )
661         {
662                 VectorCopy( centre, topPoints[i] );
663                 VectorCopy( centre, botPoints[i] );
664
665                 topPoints[i][2] = vMax[2];
666                 botPoints[i][2] = vMin[2];
667
668                 topPoints[i][0] -= 10 * sinf( Q_PI * i / ( 2 * nSteps ) );
669                 topPoints[i][1] += 10 * cosf( Q_PI * i / ( 2 * nSteps ) );
670
671                 botPoints[i][0] = topPoints[i][0];
672                 botPoints[i][1] = topPoints[i][1];
673         }
674
675         vec3_t tp[3];
676         for ( int j = 0; j < 3; j++ )
677                 VectorCopy( topPoints[j], tp[j] );
678
679         for ( i = 0; i < nSteps; i++ )
680         {
681                 NodeSmartReference brush( GlobalBrushCreator().createBrush() );
682                 vec3_t v1, v2, v3, v5, v6, v7;
683                 VectorCopy( vBot, v1 );
684                 VectorCopy( vBot, v2 );
685                 VectorCopy( vBot, v3 );
686                 VectorCopy( vTop, v5 );
687                 VectorCopy( vTop, v6 );
688                 VectorCopy( vTop, v7 );
689
690                 v2[0] = vTop[0];
691                 v3[1] = vTop[1];
692
693                 v6[0] = vBot[0];
694                 v7[1] = vBot[1];
695
696                 AddFaceWithTexture( brush, v1, v2, v3, "textures/common/caulk", false );
697                 AddFaceWithTexture( brush, v1, v3, v6, "textures/common/caulk", false );
698                 AddFaceWithTexture( brush, v5, v6, v3, "textures/common/caulk", false );
699
700                 for ( int j = 0; j < 3; j++ )
701                         tp[j][2] = vTop[2];
702
703                 AddFaceWithTexture( brush, tp[2], tp[1], tp[0], mainTexture, false );
704
705                 AddFaceWithTexture( brush, centre, botPoints[i + 1], topPoints[i + 1], "textures/common/caulk", false );
706                 AddFaceWithTexture( brush, centre, topPoints[i], botPoints[i], riserTex, false );
707
708                 Node_getTraversable( GlobalRadiant().getMapWorldEntity() )->insert( brush );
709
710                 vTop[2] += height;
711                 vBot[2] += height;
712         }
713
714         delete[] topPoints;
715         delete[] botPoints;
716
717         vMin[2] += height;
718         vMax[2] += height;
719         MakeBevel( vMin, vMax );
720 }