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