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