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