3c5e37340352e9399c8a5660d203683ceb750d25
[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
34 #include "refcounted_ptr.h"
35
36 #include <vector>
37 #include <list>
38 #include <map>
39 #include <algorithm>
40
41 #include "scenelib.h"
42
43 //#include "dialogs-gtk.h"
44
45 /************************
46         Cube Diagram
47 ************************/
48
49 /*
50
51                 7 ----- 5
52             /|    /|
53            / |   / |
54           /  |  /  |
55         4 ----- 6  |
56          |  2|_|___|8
57          |  /  |   /
58          | /   |  /       ----> WEST, definitely
59          |/    | /
60         1|_____|/3
61
62 */
63
64 /************************
65         Global Variables
66 ************************/
67
68 vec3_t  g_Origin = {0.0f, 0.0f, 0.0f};
69
70 extern bool bFacesAll[];
71
72 /************************
73         Helper Functions
74 ************************/
75
76 float Deg2Rad(float angle)
77 {
78         return (float)(angle*Q_PI/180);
79 }
80
81 void AddFaceWithTexture(scene::Node& brush, vec3_t va, vec3_t vb, vec3_t vc, const char* texture, bool detail)
82 {
83         _QERFaceData faceData;
84         FillDefaultTexture(&faceData, va, vb, vc, texture);
85         if(detail)
86                 faceData.m_texdef.contents |= FACE_DETAIL;
87   GlobalBrushCreator().addBrushFace(brush, faceData);
88 }
89
90 void AddFaceWithTextureScaled(scene::Node& brush, vec3_t va, vec3_t vb, vec3_t vc, 
91                                                           const char* texture, bool bVertScale, bool bHorScale, 
92                                                           float minX, float minY, float maxX, float maxY)
93 {
94         qtexture_t* pqtTexInfo;
95
96   // TTimo: there used to be a call to pfnHasShader here
97   //   this was not necessary. In Radiant everything is shader.
98   //   If a texture doesn't have a shader script, a default shader object is used.
99   // The IShader object was leaking also
100         // collect texture info: sizes, etc
101         IShader* i = QERApp_Shader_ForName(texture);
102   pqtTexInfo = i->getTexture(); // shader width/height doesn't come out properly
103
104         if(pqtTexInfo)
105         {
106                 float scale[2] = {0.5f, 0.5f};
107                 float shift[2] = {0, 0};
108
109                 if(bHorScale)
110                 {
111                         int texWidth = pqtTexInfo->width;
112                         float width = maxX - minX;
113
114                         scale[0] = width/texWidth;
115                         shift[0] = -(float)((int)maxX%(int)width)/scale[0];
116                 }
117
118                 if(bVertScale)
119                 {
120                         int texHeight = pqtTexInfo->height;
121                         float height = maxY - minY;
122
123                         scale[1] = height/texHeight;
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().addBrushFace(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                 Sys_ERROR("BobToolz::Invalid Texture Name-> %s", 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 {
153   NodeSmartReference newBrush(GlobalBrushCreator().createBrush());
154
155         vec3_t v1, v2, v3, v5, v6, v7, v8;
156         VectorCopy(min, v1);
157         VectorCopy(min, v2);
158         VectorCopy(min, v3);
159         VectorCopy(max, v5);
160         VectorCopy(max, v6);
161         VectorCopy(max, v7);
162         VectorCopy(max, v8);
163
164         v2[0] = max[0];
165         v3[1] = max[1];
166
167         v6[0] = min[0];
168         v7[1] = min[1];
169         v8[2] = min[2];
170
171         if(bUp)
172         {
173
174                 if(dir != MOVE_EAST)
175                         AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE);
176
177                 if(dir != MOVE_WEST)
178                         AddFaceWithTexture(newBrush, v7, v5, v8, "textures/common/caulk", FALSE);
179
180                 if(dir != MOVE_NORTH)
181                         AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE);
182
183                 if(dir != MOVE_SOUTH)
184                         AddFaceWithTexture(newBrush, v3, v8, v6, "textures/common/caulk", FALSE);
185
186                 AddFaceWithTexture(newBrush, v1, v2, v3, "textures/common/caulk", FALSE);
187
188                 if(dir == MOVE_EAST)
189                         AddFaceWithTexture(newBrush, v1, v3, v5, "textures/common/caulk", FALSE);
190
191                 if(dir == MOVE_WEST)
192                         AddFaceWithTexture(newBrush, v2, v6, v8, "textures/common/caulk", FALSE);
193
194                 if(dir == MOVE_NORTH)
195                         AddFaceWithTexture(newBrush, v1, v6, v5, "textures/common/caulk", FALSE);
196
197                 if(dir == MOVE_SOUTH)
198                         AddFaceWithTexture(newBrush, v7, v3, v8, "textures/common/caulk", FALSE);
199         }
200         else
201         {
202                 if(dir != MOVE_WEST)
203                         AddFaceWithTexture(newBrush, v7, v5, v8, "textures/common/caulk", FALSE);
204
205                 if(dir != MOVE_EAST)
206                         AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE);
207
208                 if(dir != MOVE_NORTH)
209                         AddFaceWithTexture(newBrush, v3, v8, v6, "textures/common/caulk", FALSE);
210
211                 if(dir != MOVE_SOUTH)
212                         AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE);
213
214                 
215                 AddFaceWithTexture(newBrush, v6, v5, v7, "textures/common/caulk", FALSE);
216
217                 if(dir == MOVE_WEST)
218                         AddFaceWithTexture(newBrush, v1, v5, v3, "textures/common/caulk", FALSE);
219
220                 if(dir == MOVE_EAST)
221                         AddFaceWithTexture(newBrush, v2, v8, v6, "textures/common/caulk", FALSE);
222
223                 if(dir == MOVE_NORTH)
224                         AddFaceWithTexture(newBrush, v1, v5, v6, "textures/common/caulk", FALSE);
225
226                 if(dir == MOVE_SOUTH)
227                         AddFaceWithTexture(newBrush, v7, v8, v3, "textures/common/caulk", FALSE);
228         }
229
230         Node_getTraversable(GetWorldspawn())->insert(newBrush);
231 }
232
233 //-----------------------------------------------------------------------------------
234 //-----------------------------------------------------------------------------------
235
236 void Build_StairStep_Wedge(int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail)
237 {
238   NodeSmartReference newBrush(GlobalBrushCreator().createBrush());
239
240         //----- Build Outer Bounds ---------
241
242         vec3_t v1, v2, v3, v5, v6, v7, v8;
243         VectorCopy(min, v1);
244         VectorCopy(min, v2);
245         VectorCopy(min, v3);
246         VectorCopy(max, v5);
247         VectorCopy(max, v6);
248         VectorCopy(max, v7);
249         VectorCopy(max, v8);
250
251         v2[0] = max[0];
252         v3[1] = max[1];
253
254         v6[0] = min[0];
255         v7[1] = min[1];
256
257         v8[2] = min[2];
258         //v8 needed this time, becoz of sloping faces (2-4-6-8)
259
260         //----------------------------------
261
262         AddFaceWithTexture(newBrush, v6, v5, v7, mainTexture, detail);
263
264         if(dir != MOVE_EAST)
265         {
266                 if(dir == MOVE_WEST)
267                         AddFaceWithTexture(newBrush, v5, v2, v7, riserTexture, detail);
268                 else
269                         AddFaceWithTexture(newBrush, v5, v2, v7, "textures/common/caulk", detail);
270         }
271
272         if(dir != MOVE_WEST)
273         {
274                 if(dir == MOVE_EAST)
275                         AddFaceWithTexture(newBrush, v1, v3, v6, riserTexture, detail);
276                 else
277                         AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", detail);
278         }
279
280         if(dir != MOVE_NORTH)
281         {
282                 if(dir == MOVE_SOUTH)
283                         AddFaceWithTexture(newBrush, v3, v5, v6, riserTexture, detail);
284                 else
285                         AddFaceWithTexture(newBrush, v3, v5, v6, "textures/common/caulk", detail);
286         }
287
288         if(dir != MOVE_SOUTH)
289         {
290                 if(dir == MOVE_NORTH)
291                         AddFaceWithTexture(newBrush, v1, v7, v2, riserTexture, detail);
292                 else
293                         AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", detail);
294         }
295
296                 
297         if(dir == MOVE_EAST)
298                 AddFaceWithTexture(newBrush, v1, v5, v3, "textures/common/caulk", detail);
299
300         if(dir == MOVE_WEST)
301                 AddFaceWithTexture(newBrush, v2, v8, v6, "textures/common/caulk", detail);
302
303         if(dir == MOVE_NORTH)
304                 AddFaceWithTexture(newBrush, v1, v5, v6, "textures/common/caulk", detail);
305
306         if(dir == MOVE_SOUTH)
307                 AddFaceWithTexture(newBrush, v7, v8, v3, "textures/common/caulk", detail);
308
309   Node_getTraversable(GetWorldspawn())->insert(newBrush);
310 }
311
312 //-----------------------------------------------------------------------------------
313 //-----------------------------------------------------------------------------------
314
315 // internal use only, to get a box without finishing construction
316 scene::Node& Build_Get_BoundingCube_Selective(vec3_t min, vec3_t max, char* texture, bool* useFaces)
317 {
318   scene::Node& newBrush(GlobalBrushCreator().createBrush());
319
320         //----- Build Outer Bounds ---------
321
322         vec3_t v1, v2, v3, v5, v6, v7;
323         VectorCopy(min, v1);
324         VectorCopy(min, v2);
325         VectorCopy(min, v3);
326         VectorCopy(max, v5);
327         VectorCopy(max, v6);
328         VectorCopy(max, v7);
329
330         v2[0] = max[0];
331         v3[1] = max[1];
332
333         v6[0] = min[0];
334         v7[1] = min[1];
335
336         //----------------------------------
337
338         //----- Add Six Cube Faces ---------
339
340         if(useFaces[0])
341                 AddFaceWithTexture(newBrush, v1, v2, v3, texture, FALSE);
342         if(useFaces[1])
343                 AddFaceWithTexture(newBrush, v1, v3, v6, texture, FALSE);
344         if(useFaces[2])
345                 AddFaceWithTexture(newBrush, v1, v7, v2, texture, FALSE);
346
347         if(useFaces[3])
348                 AddFaceWithTexture(newBrush, v5, v6, v3, texture, FALSE);
349         if(useFaces[4])
350                 AddFaceWithTexture(newBrush, v5, v2, v7, texture, FALSE);
351         if(useFaces[5])
352                 AddFaceWithTexture(newBrush, v5, v7, v6, texture, FALSE);
353
354         //----------------------------------
355
356         return newBrush;
357 }
358
359 scene::Node& Build_Get_BoundingCube(vec3_t min, vec3_t max, char* texture)
360 {
361         return Build_Get_BoundingCube_Selective(min, max, texture, bFacesAll);
362 }
363
364 //-----------------------------------------------------------------------------------
365 //-----------------------------------------------------------------------------------
366
367 void Build_StairStep(vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction)
368 {
369   scene::Node& newBrush(GlobalBrushCreator().createBrush());
370
371         //----- Build Outer Bounds ---------
372
373         vec3_t v1, v2, v3, v5, v6, v7;
374         VectorCopy(min, v1);
375         VectorCopy(min, v2);
376         VectorCopy(min, v3);
377         VectorCopy(max, v5);
378         VectorCopy(max, v6);
379         VectorCopy(max, v7);
380
381         v2[0] = max[0];
382         v3[1] = max[1];
383
384         v6[0] = min[0];
385         v7[1] = min[1];
386
387         //----------------------------------
388
389         AddFaceWithTexture(newBrush, v6, v5, v7, mainTexture, FALSE);
390         // top gets current texture
391
392
393         if(direction == MOVE_EAST)
394                 AddFaceWithTexture(newBrush, v1, v3, v6, riserTexture, FALSE);
395         else
396                 AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE);
397         // west facing side, etc...
398
399         
400         if(direction == MOVE_NORTH)
401                 AddFaceWithTexture(newBrush, v1, v7, v2, riserTexture, FALSE);
402         else
403                 AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE);
404
405         if(direction == MOVE_SOUTH)
406                 AddFaceWithTexture(newBrush, v3, v5, v6, riserTexture, FALSE);
407         else
408                 AddFaceWithTexture(newBrush, v3, v5, v6, "textures/common/caulk", FALSE);
409         
410         if(direction == MOVE_WEST)
411                 AddFaceWithTexture(newBrush, v7, v5, v2, riserTexture, FALSE);
412         else
413                 AddFaceWithTexture(newBrush, v7, v5, v2, "textures/common/caulk", FALSE);
414
415
416         AddFaceWithTexture(newBrush, v1, v2, v3, "textures/common/caulk", FALSE);
417         // base is caulked
418
419         Node_getTraversable(GetWorldspawn())->insert(newBrush);
420         // finish brush
421 }
422
423 //-----------------------------------------------------------------------------------
424 //-----------------------------------------------------------------------------------
425
426 void BuildDoorsX2(vec3_t min, vec3_t max, 
427                                   bool bSclMainHor, bool bSclMainVert, 
428                                   bool bSclTrimHor, bool bSclTrimVert,
429                                   const char* mainTexture, const char* trimTexture,
430                                   int direction)
431 {
432         int xy;
433         if(direction == 0)
434                 xy = 0;
435         else
436                 xy = 1;
437
438         //----- Build Outer Bounds ---------
439
440         vec3_t v1, v2, v3, v5, v6, v7, ve_1, ve_2, ve_3;
441         VectorCopy(min, v1);
442         VectorCopy(min, v2);
443         VectorCopy(min, v3);
444         VectorCopy(max, v5);
445         VectorCopy(max, v6);
446         VectorCopy(max, v7);
447
448         v2[0] = max[0];
449         v3[1] = max[1];
450
451         v6[0] = min[0];
452         v7[1] = min[1];
453
454         float width = (max[xy] - min[xy])/2;
455         
456         if(direction == 0)
457         {
458                 VectorCopy(v1, ve_1);
459                 VectorCopy(v3, ve_2);
460                 VectorCopy(v6, ve_3);
461         }
462         else
463         {
464                 VectorCopy(v7, ve_1);
465                 VectorCopy(v1, ve_2);
466                 VectorCopy(v2, ve_3);
467         }
468
469         ve_1[xy] += width;
470         ve_2[xy] += width;
471         ve_3[xy] += width;
472
473         //----------------------------------
474
475   NodeSmartReference newBrush1(GlobalBrushCreator().createBrush());
476         NodeSmartReference newBrush2(GlobalBrushCreator().createBrush());
477
478         AddFaceWithTexture(newBrush1, v1, v2, v3, "textures/common/caulk", FALSE);
479         AddFaceWithTexture(newBrush1, v5, v7, v6, "textures/common/caulk", FALSE);
480
481         AddFaceWithTexture(newBrush2, v1, v2, v3, "textures/common/caulk", FALSE);
482         AddFaceWithTexture(newBrush2, v5, v7, v6, "textures/common/caulk", FALSE);
483
484         if(direction == 0)
485         {
486                 AddFaceWithTexture(newBrush1, v1, v3, v6, "textures/common/caulk", FALSE);
487                 AddFaceWithTexture(newBrush2, v5, v2, v7, "textures/common/caulk", FALSE);
488         }
489         else
490         {
491                 AddFaceWithTexture(newBrush1, v1, v7, v2, "textures/common/caulk", FALSE);
492                 AddFaceWithTexture(newBrush2, v5, v6, v3, "textures/common/caulk", FALSE);
493         }
494
495         if(direction == 0)
496         {
497                 AddFaceWithTextureScaled(newBrush1, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor,
498                         min[0], min[2], max[0], max[2]);
499                 AddFaceWithTextureScaled(newBrush1, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor,
500                         max[0], min[2], min[0], max[2]);
501
502                 
503                 AddFaceWithTextureScaled(newBrush2, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor,
504                         min[0], min[2], max[0], max[2]);
505                 AddFaceWithTextureScaled(newBrush2, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor,
506                         max[0], min[2], min[0], max[2]);        // flip max/min to reverse tex dir
507
508
509         
510                 AddFaceWithTextureScaled(newBrush1, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor,
511                         min[1], min[2], max[1], max[2]);
512
513                 AddFaceWithTextureScaled(newBrush2, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor,
514                         max[1], min[2], min[1], max[2]);
515         }
516         else
517         {
518                 AddFaceWithTextureScaled(newBrush1, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor,
519                         min[1], min[2], max[1], max[2]);
520                 AddFaceWithTextureScaled(newBrush1, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor,
521                         max[1], min[2], min[1], max[2]);
522
523                 
524                 AddFaceWithTextureScaled(newBrush2, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor,
525                         min[1], min[2], max[1], max[2]);
526                 AddFaceWithTextureScaled(newBrush2, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor,
527                         max[1], min[2], min[1], max[2]);        // flip max/min to reverse tex dir
528
529
530                 AddFaceWithTextureScaled(newBrush1, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor,
531                         min[0], min[2], max[0], max[2]);
532
533                 AddFaceWithTextureScaled(newBrush2, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor,
534                         max[0], min[2], min[0], max[2]);
535         }
536
537         //----------------------------------
538         
539
540   NodeSmartReference pEDoor1 = GlobalEntityCreator().createEntity("func_door");
541         NodeSmartReference pEDoor2 = GlobalEntityCreator().createEntity("func_door");
542
543         if(direction == 0)
544         {
545     pEDoor1->m_entity->setkeyvalue("angle", "180");
546     pEDoor2->m_entity->setkeyvalue("angle", "360");
547         }
548         else
549         {
550     pEDoor1->m_entity->setkeyvalue("angle", "270");
551     pEDoor2->m_entity->setkeyvalue("angle", "90");
552         }
553
554         srand((unsigned)time(NULL));
555
556         char teamname[256];
557         sprintf(teamname, "t%i", rand());
558   pEDoor1->m_entity->setkeyvalue("team", teamname);
559   pEDoor2->m_entity->setkeyvalue("team", teamname);
560
561         Node_getTraversable(pEDoor1)->insert(newBrush1);
562         Node_getTraversable(pEDoor2)->insert(newBrush2);
563
564   Node_getTraversable(GlobalSceneGraph().root())->insert(pEDoor1);
565   Node_getTraversable(GlobalSceneGraph().root())->insert(pEDoor2);
566
567 //      ResetCurrentTexture();
568 }
569
570 //-----------------------------------------------------------------------------------
571 //-----------------------------------------------------------------------------------
572
573 void MakeBevel(vec3_t vMin, vec3_t vMax)
574 {
575   NodeSmartReference patch(GlobalPatchCreator().createPatch());
576   aabb_t aabb;
577   aabb_construct_for_vec3(&aabb, vMin, vMax);
578 #if 0
579   patch->m_patch->ConstructPrefab(&aabb, eBevel, 2); // 2 == XY view
580 #endif
581
582   Node_getTraversable(GetWorldspawn())->insert(patch);
583 }
584
585 void BuildCornerStairs(vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex)
586 {
587         vec3_t* topPoints = new vec3_t[nSteps+1];
588         vec3_t* botPoints = new vec3_t[nSteps+1];
589
590         bool bFacesUse[6] = {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE};
591
592         vec3_t centre;
593         VectorCopy(vMin, centre);
594         centre[0] = vMax[0];
595
596         int height = (int)(vMax[2] - vMin[2]) / nSteps;
597
598         vec3_t vTop, vBot;
599         VectorCopy(vMax, vTop);
600         VectorCopy(vMin, vBot);
601         vTop[2] = vMin[2] + height;
602
603   int i;
604         for(i = 0; i <= nSteps; i++)
605         {
606                 VectorCopy(centre, topPoints[i]);
607                 VectorCopy(centre, botPoints[i]);
608                 
609                 topPoints[i][2] = vMax[2];
610                 botPoints[i][2] = vMin[2];
611
612                 topPoints[i][0] -= 10 * sinf( Q_PI * i / ( 2 * nSteps ) );
613                 topPoints[i][1] += 10 * cosf( Q_PI * i / ( 2 * nSteps ) );
614
615                 botPoints[i][0] = topPoints[i][0];
616                 botPoints[i][1] = topPoints[i][1];
617         }
618
619         vec3_t tp[3];
620         for(int j = 0; j < 3; j++)
621                 VectorCopy(topPoints[j], tp[j]);
622
623         for(i = 0; i < nSteps; i++)
624         {
625     scene::Node& brush = Build_Get_BoundingCube_Selective(vBot, vTop, "textures/common/caulk", bFacesUse);
626
627                 for(int j = 0; j < 3; j++)
628                         tp[j][2] = vTop[2];
629
630                 AddFaceWithTexture(brush, tp[2], tp[1], tp[0], mainTexture, FALSE);
631
632                 AddFaceWithTexture(brush, centre, botPoints[i+1], topPoints[i+1], "textures/common/caulk", FALSE);
633                 AddFaceWithTexture(brush, centre, topPoints[i], botPoints[i], riserTex, FALSE);
634
635                 Node_getTraversable(GetWorldspawn())->insert(brush);
636
637                 vTop[2] += height;
638                 vBot[2] += height;
639         }
640
641         delete[] topPoints;
642         delete[] botPoints;
643
644         vMin[2] += height;
645         vMax[2] += height;
646         MakeBevel(vMin, vMax);
647 }