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