Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation2/src/libraries/tools/bsp/Q3Map.cpp @ 7790

Last change on this file since 7790 was 7163, checked in by dafrick, 14 years ago

Merged presentation3 branch into trunk.

  • Property svn:eol-style set to native
File size: 144.9 KB
Line 
1/*
2===========================================================================
3Copyright (C) 2008 Daniel Örstadius
4Copyright (C) 2009 Jared Prince
5
6This file is part of bsp-renderer source code.
7
8bsp-renderer is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
12
13bsp-renderer is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with bsp-renderer.  If not, see <http://www.gnu.org/licenses/>.
20
21*/
22
23// Q3Map.cpp -- handles the map data
24
25#include <string>
26#include <math.h>
27
28#include "Q3Map.h"
29#include "Q3Map_misc.h"
30
31
32//temp
33//#include <io.h>
34//#include <fcntl.h>      /* Needed only for _O_RDWR definition */
35//#include <sys/stat.h>
36
37Q3Map::Q3Map()
38{
39        m_nDebugA=0 ;
40
41        m_nNewCount=0 ;
42       
43  m_pTexturesOrig=NULL ;
44  m_pFaces=NULL ;
45  m_pVertices=NULL ;
46  m_pMeshVerts=NULL ;
47  m_pLeafs=NULL ;
48  m_pLeafFaces=NULL ;
49  m_pPlanes=NULL ;
50  m_pNodes=NULL ;
51
52        //m_VisData->vecs=NULL ; // can't NULL this because m_VisData doesn't exist yet!
53        m_VisData=NULL ;
54   
55  m_pBrushes=NULL ;
56  m_pLeafBrushes=NULL ;
57  m_pBrushSides=NULL ;
58  m_pLightMaps=NULL ;
59  m_pEntities=NULL ;
60
61        m_pSubZones=NULL ;
62        m_pPortals=NULL ;
63        //////////////////////////////////////////////////////
64
65        // initiallize our triangle memory management
66        m_nTriangleSize=0 ;
67        m_pTriangleMem=NULL ;
68        m_pTriangle=NULL ;
69        m_nTriangleMax=0 ;
70        m_nTriangleLimit=0 ;
71
72        m_nVertexSize=0 ;
73        m_pVertexMem=NULL ;
74        m_pVertex=NULL ;
75        m_nVertexMax=0 ;
76        m_nVertexLimit=0 ;
77
78        m_nLightSize=0 ;
79        m_pLightMem=NULL ;
80        m_pLight=NULL ;
81        m_nLightMax=0 ;
82        m_nLightLimit=0 ;
83        m_nMaxMultiZoneLight=0 ;
84
85        m_nLampSize=0 ;
86        m_pLampMem=NULL ;
87        m_pLamp=NULL ;
88        m_nLampMax=0 ;
89        m_nLampLimit=0 ;
90
91        m_nTextureSize=0 ;
92        m_pTextureMem=NULL ;
93        m_pTexture=NULL ;
94        m_nTextureMax=0 ;
95        m_nTextureLimit=0 ;
96
97        m_nTexLampSize=0 ;
98        m_pTexLampMem=NULL ;
99        m_pTexLamp=NULL ;
100        m_nTexLampMax=0 ;
101        m_nTexLampLimit=0 ;
102
103        m_BspFaces=NULL;
104
105        m_pTransTexture=NULL ;
106
107
108//      Q3Bug.LogInit() ;
109
110}
111
112Q3Map::~Q3Map()
113{
114//      Q3Bug.LogSave("Q3Bug.log") ;
115
116        DELETE_ARRAY(m_pTransTexture) ;
117        //DELETE_ARRAY(m_pSubZones) ;
118        DELETE_ARRAY(mVisibleFaces) ;
119
120        FreeLightMemory() ;
121        FreeLampMemory() ;
122        FreeVertexMemory() ;
123        FreeTriangleMemory() ;
124        FreeTextureMemory() ;
125        FreeTexLampMemory() ;
126        DestroyBspFacesMemory() ;       // free up face and patch data.  Normally already done if we're just loading a new level or quitting, but we might also be here due to a loading fail or something.
127
128        // no need to delete any of the pointers to the lumps since their memory belongs to m_pRawBspFile over in OgreFramework.
129
130       
131}
132
133void Q3Map::DestroyBspFacesMemory(void)
134{
135        if(m_BspFaces) 
136        {
137                // clean up any memory declared for patches
138                for (int i=0; i < m_NumBspFaces; i++)
139      if ((m_BspFaces[i].type == PATCH) && (m_BspFaces[i].patch != NULL))
140                        {
141                                DELETE_ARRAY( m_BspFaces[i].patch->bezier ) ;
142                                DELETE_POINTER( m_BspFaces[i].patch ) ;
143                        }
144
145                // delete the faces memory
146                DELETE_ARRAY( m_BspFaces ) ;
147        }
148}
149
150
151
152int Q3Map::parseMap(const char* pMem, size_t Size)
153{       
154        // we check all lump info to make sure it isn't trying to go out of bounds,
155        // in case some mangled bsp is trying to do something devious or is just corrupted
156       
157       
158       
159
160
161        m_BspHeader=*((Q3BspHeader_t*)pMem) ; // pointer to the header
162
163        // run a check that the total size of all the iLengths plus the header isn't too large
164        size_t TotalLength=sizeof(Q3BspHeader_t) ; // initialize to the size of the header
165        int nLump=0 ;
166        int nOther=0 ;
167        int nLumpMin=0 ;
168        int nLumpMax=0 ;
169        int nOtherMin=0 ;
170        int nOtherMax=0 ;
171        for(nLump=0 ; nLump<MAX_LUMP ; nLump++)
172        {
173                if(m_BspHeader.Lumps[nLump].iLength<0) return -1 ; // lumps shouldn't have a negative size. FAIL!
174                if(m_BspHeader.Lumps[nLump].iLength>MAX_LUMP_SIZE) return -2 ; // no lump has a right to be this big... FAIL!
175               
176               
177                if( (m_BspHeader.Lumps[nLump].iLength>0) && (m_BspHeader.Lumps[nLump].iOffset<sizeof(Q3BspHeader_t)) )
178                        return -3 ; // lump overlaps header, FAIL!
179
180                if((m_BspHeader.Lumps[nLump].iLength==0) && (m_BspHeader.Lumps[nLump].iOffset!=0))
181                        return -4 ; // lump size is zero and yet offset is not zero???  FAIL!
182
183
184                TotalLength+=m_BspHeader.Lumps[nLump].iLength ;
185                if(TotalLength>Size) return -5 ;// this file is messed up, the lumps add up to more than the file size.  FAIL!
186
187                // make sure this lump doesn't overlap any other lumps
188                nLumpMin=m_BspHeader.Lumps[nLump].iOffset ;
189                nLumpMax=nLumpMin+m_BspHeader.Lumps[nLump].iLength-1 ;
190
191                for(nOther=nLump+1 ; nOther<MAX_LUMP ; nOther++)
192                        if((m_BspHeader.Lumps[nLump].iLength>0) && (m_BspHeader.Lumps[nOther].iLength>0)) // don't check zero sized lumps
193                        {
194                                nOtherMin=m_BspHeader.Lumps[nOther].iOffset ;
195                                nOtherMax=nOtherMin+m_BspHeader.Lumps[nOther].iLength-1 ;
196
197                                if((nLumpMax>=nOtherMin) && (nLumpMin<=nOtherMax)) 
198                                return -6 ; // lump overlaps another lump, FAIL!
199                        }
200        }
201
202       
203
204
205        // setup pointers to the lumps
206
207        if((m_BspHeader.Lumps[0].iOffset<0) || (m_BspHeader.Lumps[0].iOffset>=Size)) return -7 ; // fail if out of memory bounds
208        m_pEntities=(char*)(pMem+m_BspHeader.Lumps[0].iOffset) ;
209
210        if((m_BspHeader.Lumps[Faces].iOffset<0) || (m_BspHeader.Lumps[Faces].iOffset>=Size)) return -8 ; // out of bounds
211        if(m_BspHeader.Lumps[Faces].iOffset+m_BspHeader.Lumps[Faces].iLength>Size) return -9 ; // out of bounds
212  m_iNumFaces = m_BspHeader.Lumps[Faces].iLength / sizeof(Q3BspFace_t);
213        m_pFaces=(Q3BspFace_t*)(pMem+m_BspHeader.Lumps[Faces].iOffset) ;
214
215        if((m_BspHeader.Lumps[Vertices].iOffset<0) || (m_BspHeader.Lumps[Vertices].iOffset>=Size)) return -10 ; // out of bounds
216        if(m_BspHeader.Lumps[Vertices].iOffset+m_BspHeader.Lumps[Vertices].iLength>Size) return -11 ; // out of bounds
217  m_iNumVertices = m_BspHeader.Lumps[Vertices].iLength / sizeof(Q3BspVertex);
218        m_pVertices=(Q3BspVertex*)(pMem+m_BspHeader.Lumps[Vertices].iOffset) ;
219
220        if((m_BspHeader.Lumps[MeshVerts].iOffset<0) || (m_BspHeader.Lumps[MeshVerts].iOffset>=Size)) return -12 ; // out of bounds
221        if(m_BspHeader.Lumps[MeshVerts].iOffset+m_BspHeader.Lumps[MeshVerts].iLength>Size) return -13 ; // out of bounds
222  m_iNumMeshVerts = m_BspHeader.Lumps[MeshVerts].iLength / sizeof(int);
223        m_pMeshVerts=(int*)(pMem+m_BspHeader.Lumps[MeshVerts].iOffset) ;
224
225        if((m_BspHeader.Lumps[Leafs].iOffset<0) || (m_BspHeader.Lumps[Leafs].iOffset>=Size)) return -14 ; // out of bounds
226        if(m_BspHeader.Lumps[Leafs].iOffset+m_BspHeader.Lumps[Leafs].iLength>Size) return -15 ; // out of bounds
227  m_iNumLeafs = m_BspHeader.Lumps[Leafs].iLength / sizeof(Q3BspLeaf);
228        m_pLeafs=(Q3BspLeaf*)(pMem+m_BspHeader.Lumps[Leafs].iOffset) ;
229
230        if((m_BspHeader.Lumps[LeafFaces].iOffset<0) || (m_BspHeader.Lumps[LeafFaces].iOffset>=Size)) return -16 ; // out of bounds
231        if(m_BspHeader.Lumps[LeafFaces].iOffset+m_BspHeader.Lumps[LeafFaces].iLength>Size) return -17 ; // out of bounds
232  m_iNumLeafFaces = m_BspHeader.Lumps[LeafFaces].iLength / sizeof(int);
233        m_pLeafFaces=(int*)(pMem+m_BspHeader.Lumps[LeafFaces].iOffset) ;
234
235        if((m_BspHeader.Lumps[LeafBrushes].iOffset<0) || (m_BspHeader.Lumps[LeafBrushes].iOffset>=Size)) return -18 ; // out of bounds
236        if(m_BspHeader.Lumps[LeafBrushes].iOffset+m_BspHeader.Lumps[LeafBrushes].iLength>Size) return -19 ; // out of bounds
237  m_iNumLeafBrushes = m_BspHeader.Lumps[LeafBrushes].iLength / sizeof(int);
238        m_pLeafBrushes=(int*)(pMem+m_BspHeader.Lumps[LeafBrushes].iOffset) ;
239
240        if((m_BspHeader.Lumps[Textures].iOffset<0) || (m_BspHeader.Lumps[Textures].iOffset>=Size)) return -20 ; // out of bounds
241        if(m_BspHeader.Lumps[Textures].iOffset+m_BspHeader.Lumps[Textures].iLength>Size) return -21 ; // out of bounds
242  m_iNumTexs = m_BspHeader.Lumps[Textures].iLength / sizeof(Q3BspTexture);
243        m_pTexturesOrig=(Q3BspTexture*)(pMem+m_BspHeader.Lumps[Textures].iOffset) ;
244
245        if((m_BspHeader.Lumps[Planes].iOffset<0) || (m_BspHeader.Lumps[Planes].iOffset>=Size)) return -22 ; // out of bounds
246        if(m_BspHeader.Lumps[Planes].iOffset+m_BspHeader.Lumps[Planes].iLength>Size) return -23 ; // out of bounds
247  m_iNumPlanes = m_BspHeader.Lumps[Planes].iLength / sizeof(Q3BspPlane);
248        m_pPlanes=(Q3BspPlane*)(pMem+m_BspHeader.Lumps[Planes].iOffset) ;
249
250        if((m_BspHeader.Lumps[Nodes].iOffset<0) || (m_BspHeader.Lumps[Nodes].iOffset>=Size)) return -24 ; // out of bounds
251        if(m_BspHeader.Lumps[Nodes].iOffset+m_BspHeader.Lumps[Nodes].iLength>Size) return -25 ; // out of bounds
252  m_iNumNodes = m_BspHeader.Lumps[Nodes].iLength / sizeof(Q3BspNode);
253        m_pNodes=(Q3BspNode*)(pMem+m_BspHeader.Lumps[Nodes].iOffset) ;
254
255  //m_iNumModels = m_BspHeader.Lumps[Models].iLength / sizeof(Q3BspModel);
256  //m_pModels = new Q3BspModel[m_iNumModels];
257
258        // bzn doesn't use lightmaps
259  //m_iNumLightMaps = m_BspHeader.Lumps[LightMaps].iLength / sizeof(Q3BspLightMap);
260        //m_pLightMaps=(Q3BspLightMap*)(pMem+m_BspHeader.Lumps[LightMaps].iOffset) ;
261
262        if((m_BspHeader.Lumps[Brushes].iOffset<0) || (m_BspHeader.Lumps[Brushes].iOffset>=Size)) return -26 ; // out of bounds
263        if(m_BspHeader.Lumps[Brushes].iOffset+m_BspHeader.Lumps[Brushes].iLength>Size) return -27 ; // out of bounds
264  m_iNumBrushes = m_BspHeader.Lumps[Brushes].iLength / sizeof(Q3BspBrush);
265        m_pBrushes=(Q3BspBrush*)(pMem+m_BspHeader.Lumps[Brushes].iOffset) ;
266
267
268        if((m_BspHeader.Lumps[BrushSides].iOffset<0) || (m_BspHeader.Lumps[BrushSides].iOffset>=Size)) return -28 ; // out of bounds
269        if(m_BspHeader.Lumps[BrushSides].iOffset+m_BspHeader.Lumps[BrushSides].iLength>Size) return -29 ; // out of bounds
270  m_iNumBrushSides = m_BspHeader.Lumps[BrushSides].iLength / sizeof(Q3BspBrushSide);
271        m_pBrushSides=(Q3BspBrushSide*)(pMem+m_BspHeader.Lumps[BrushSides].iOffset) ;
272
273  //m_iNumEffects = m_BspHeader.Lumps[Effects].iLength / sizeof(Q3BspEffect);
274  //m_pEffects = new Q3BspEffect[m_iNumEffects];
275  //
276  //m_pImages = new BDTexture[m_iNumTexs];
277
278        // bzn doesn't use visdata
279        //m_VisData=(Q3BspVisData*)(pMem+m_BspHeader.Lumps[VisData].iOffset) ;
280        //m_VisData->vecs=(unsigned char*)(pMem+m_BspHeader.Lumps[VisData].iOffset + 2*sizeof(int)) ;
281
282        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
283
284        // bzn specific data
285        if((m_BspHeader.Lumps[SubZoneData].iOffset<0) || (m_BspHeader.Lumps[SubZoneData].iOffset>=Size)) return -30 ; // out of bounds
286        if(m_BspHeader.Lumps[SubZoneData].iOffset+m_BspHeader.Lumps[SubZoneData].iLength>Size) return -31 ; // out of bounds
287        m_iNumSubZones = m_BspHeader.Lumps[SubZoneData].iLength / sizeof(BZN_SubZone_t);
288  m_pSubZones=(BZN_SubZone_t*)(pMem+m_BspHeader.Lumps[SubZoneData].iOffset) ;
289
290        if((m_BspHeader.Lumps[PortalData].iOffset<0) || (m_BspHeader.Lumps[PortalData].iOffset>=Size)) return -32 ; // out of bounds
291        if(m_BspHeader.Lumps[PortalData].iOffset+m_BspHeader.Lumps[PortalData].iLength>Size) return -33 ; // out of bounds
292        m_iNumPortals = m_BspHeader.Lumps[PortalData].iLength / sizeof(BZN_Portal_t);
293        m_pPortals=(BZN_Portal_t*)(pMem+m_BspHeader.Lumps[PortalData].iOffset) ;
294
295       
296
297
298
299
300        // fix coords and setup face memory
301        swizzleCoords();
302  mVisibleFaces = new int[m_iNumFaces];
303
304
305        // we need a new version of the textures, because when we parse the lights they will have textures to add to it,
306        // and we can't expand the texture lump because it's in the middle of a block of memory containing all the lumps.
307
308        // copy the texture lump
309        int nTexture=0 ;
310        for(nTexture=0 ; nTexture<m_iNumTexs ; nTexture++)
311        {
312                if(!AddTexture(m_pTexturesOrig[nTexture])) return -34 ; // failed to add texture, probably out of memory
313        }
314       
315        return 0 ;
316
317}
318
319
320void Q3Map::swizzleCoords(void)
321{
322  //DEBUG_OUTPUT("swizziling data...");
323  // vertices
324  for (int i=0; i < m_iNumVertices; i++)
325  {
326    swizzleFloat3(m_pVertices[i].position);
327    swizzleFloat3(m_pVertices[i].normal);
328    //m_pVertices[i].texcoord[0][0] = 1.0f - m_pVertices[i].texcoord[0][0];             
329  }
330
331  // leafs
332  for (int i=0; i < m_iNumLeafs; i++)
333  {
334    swizzleInt3(m_pLeafs[i].maxs);
335    swizzleInt3(m_pLeafs[i].mins);
336  }
337
338  // faces, do lightmaps later...
339  for (int i=0; i < m_iNumFaces; i++)
340  {
341    swizzleFloat3(m_pFaces[i].normal);
342  }
343
344  // planes
345  for (int i=0; i < m_iNumPlanes; i++)
346  {
347    swizzleFloat3(m_pPlanes[i].normal);         
348  }
349
350  // nodes
351  for (int i=0; i < m_iNumNodes; i++)
352  {
353    swizzleInt3(m_pNodes[i].maxs);
354    swizzleInt3(m_pNodes[i].mins);
355  }
356
357       
358        // subzones
359        float flTemp=0.0f ;
360        for (int i=0; i < m_iNumSubZones; i++)
361  {
362                swizzleFloat3(m_pSubZones[i].Max);             
363                swizzleFloat3(m_pSubZones[i].Min);
364
365                // swizzling will mix up z max and min due to the sign change, so swap them
366                flTemp=m_pSubZones[i].Max[2] ;
367                m_pSubZones[i].Max[2]=m_pSubZones[i].Min[2] ;
368                m_pSubZones[i].Min[2]=flTemp ;
369
370  }
371
372        // portals
373        for (int i=0; i < m_iNumPortals; i++)
374  {
375                swizzleFloat3(m_pPortals[i].Max);               
376                swizzleFloat3(m_pPortals[i].Min);
377
378                // swizzling will mix up z max and min due to the sign change, so swap them
379                flTemp=m_pPortals[i].Max[2] ;
380                m_pPortals[i].Max[2]=m_pPortals[i].Min[2] ;
381                m_pPortals[i].Min[2]=flTemp ;
382
383  }
384
385       
386       
387
388}
389
390void Q3Map::swizzleFloat3(float t[3])
391{       
392  float temp;
393  temp = t[1];
394  t[1] = t[2];
395  t[2] = -temp;
396}
397
398void Q3Map::swizzleInt3(int t[3])
399{       
400  int temp;
401  temp = t[1];
402  t[1] = t[2];
403  t[2] = -temp;
404}
405
406
407
408Q3BspPatch *Q3Map::handlePatch(int faceIndex)
409{
410  Q3BspPatch *q3patch;
411  q3patch = new Q3BspPatch;
412
413  int patch_size_x = (m_pFaces[faceIndex].size[0] - 1) / 2;
414  int patch_size_y = (m_pFaces[faceIndex].size[1] - 1) / 2;
415  int num_bezier_patches = patch_size_y * patch_size_x;
416
417  q3patch->size = num_bezier_patches;
418  q3patch->bezier = new Bezier[q3patch->size];
419
420  int patchIndex =  0;
421  int ii, n, j, nn;
422  for (ii = 0, n = 0; n < patch_size_x; n++, ii = 2*n)
423  {                             
424    for (j=0, nn=0; nn < patch_size_y; nn++, j = 2*nn)
425    {
426      int index = 0;
427      for (int ctr = 0; ctr < 3; ctr++)
428      { 
429        int pos = ctr * m_pFaces[faceIndex].size[0];
430
431        q3patch->bezier[patchIndex].mControls[index++] = 
432          BspVertex(
433          // position
434          m_pVertices[m_pFaces[faceIndex].vertex + 
435          ii + 
436          m_pFaces[faceIndex].size[0] * j + 
437          pos].position,
438          // texture coordinates
439          m_pVertices[m_pFaces[faceIndex].vertex + 
440          ii + 
441          m_pFaces[faceIndex].size[0] * j +
442          pos].texcoord,
443          // normal
444          m_pVertices[m_pFaces[faceIndex].vertex +
445          ii +
446          m_pFaces[faceIndex].size[0] * j +
447          pos].normal);
448
449        q3patch->bezier[patchIndex].mControls[index++] = 
450                BspVertex(
451                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 1].position,
452                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 1].texcoord,
453                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 1].normal);
454
455        q3patch->bezier[patchIndex].mControls[index++] = 
456                BspVertex(
457                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 2].position,
458                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 2].texcoord,
459                  m_pVertices[m_pFaces[faceIndex].vertex + ii + m_pFaces[faceIndex].size[0] * j + pos + 2].normal);                                             
460      }     
461      q3patch->bezier[patchIndex].tessellate(5);
462      patchIndex++;
463    }
464  }
465
466  return q3patch;
467}
468
469
470int Q3Map::findVisibleFaces(const QVECTOR *camPos, int *facesToRender)
471{
472  int leaf;
473  int visCluster;       
474
475  leaf = findLeaf(camPos);     
476
477  visCluster = m_pLeafs[leaf].cluster;
478
479  memset(mVisibleFaces, 0, sizeof(int) * m_iNumFaces); 
480
481  int faceindex;
482  int renderindex=0;
483  m_ClusterCount=0 ;
484 
485  for (int i=0; i < m_iNumLeafs; i++)
486  {
487    if (isClusterVisible(visCluster, m_pLeafs[i].cluster))
488    {                           
489                        m_ClusterCount++ ;
490      bool vis=true ;//bool vis = mViewFrustum->checkIfBoxInside(m_pLeafs[i].mins, m_pLeafs[i].maxs);                                           
491     
492          if (vis)
493      {
494        for (int k=0; k < m_pLeafs[i].n_leaffaces; k++)
495        {                                       
496          faceindex =   m_pLeafFaces[m_pLeafs[i].leafface + k];                         
497          if (mVisibleFaces[faceindex] == 0)
498          {
499            mVisibleFaces[faceindex] = 1;                                               
500            facesToRender[renderindex++] = faceindex;
501          }
502        }
503      }                 
504    }
505  }
506 
507
508  facesToRender[renderindex] = -1;     
509
510  return renderindex;
511}
512
513
514int Q3Map::findLeaf(const QVECTOR *camPos) const
515{
516  int index = 0;
517
518  while (index >= 0)
519  {
520    const Q3BspNode *node = &m_pNodes[index];
521    const Q3BspPlane *plane = &m_pPlanes[node->plane];
522
523    // distance from point to plane
524    //QVECTOR normal = QVECTOR(plane->normal);           
525    QVECTOR normal ;
526        normal[0]=plane->normal[0] ;
527        normal[1]=plane->normal[1] ;
528        normal[2]=plane->normal[2] ;
529       
530       
531        //const float distance = D3DXVec3Dot(&normal,camPos) - plane->dist;
532
533        const float distance=(normal[0]* *camPos[0] + normal[1]* *camPos[1] + normal[2]* *camPos[2]) - plane->dist ;
534
535    if(distance >= 0)
536      index = node->children[0];
537    else
538      index = node->children[1];
539  }
540
541  return -index - 1;
542}
543
544bool Q3Map::isClusterVisible(int visCluster, int testCluster) const
545{
546  if (m_VisData == NULL)
547    return true;
548
549  if ((m_VisData->vecs == NULL) || (visCluster < 0))   
550    return true;   
551
552  int i = (visCluster * m_VisData->sz_vecs) + (testCluster >> 3);
553  unsigned char visSet = m_VisData->vecs[i];
554
555  return (visSet & (1 << (testCluster & 7))) != 0;
556}
557
558Q3BspFace_t *Q3Map::getFaces(void)
559{
560  return m_pFaces;
561}
562
563
564
565
566
567 /***********************************************************************************************************\
568                                               
569                                   New Parsing and Triangulation Functions
570                                               
571 \***********************************************************************************************************/
572
573
574
575
576// This routine is basically an overview of the entire process that converts the BSP
577// into something our Ogre code can use to construct the map's mesh and level data.
578// In essence, it converts the map geometry into a list of triangles sorted by zone and material,
579// as well as extracting other map info like zone and portal bounding boxes, lights, entities etc.
580
581int Q3Map::ParseAndTriangulateMap(const char* pData, size_t Size)
582{
583       
584//      char chMessage[1024] ;
585        int nError=0 ;
586
587                // setup pointers to the various lumps and get their quantities
588                nError=parseMap( pData, Size ) ;
589                if(nError<0)
590                {
591                        //sprintf(chMessage, "Parse Map Error: %i", nError) ;
592                        //Q3Bug.LogAddCR(chMessage) ;
593                        return ERROR_ParseMap ;
594                }
595
596                // extract entities such as lights, monsters, etc
597                if(!ParseEntities())                                                                            return ERROR_ParseEntities ;
598
599                // initial memory allocation for triangles
600                m_nVertexMax=0 ;
601                if(!AllocateVertexMemory(m_iNumVertices))       return ERROR_AllocateVertex ;
602                if(!AllocateTriangleMemory())                                           return ERROR_AllocateTriangle ;
603                if(!initFaces())                                                                                                return ERROR_InitializeFaces ;
604
605                // no new map textures should be added after here, or else SetupTransTextures won't work
606                if(!SetupTransTextures())                                                               return ERROR_SetupTransTextures ;
607
608                // work out the zones
609                SetupZones() ;
610
611                // convert faces to triangles
612                if(!ConvertFacesToTriangles())                                  return ERROR_ConvertFaces ;
613
614                if(!ConvertPatchesToTriangles())                                return ERROR_ConvertPatches ;
615
616                if(!ConvertLampsToTriangles())                                  return ERROR_ConvertLamps ;
617
618                if(!ConvertLampsToGlowTriangles())                      return ERROR_ConvertLampGlow ;
619
620                if(!ConvertLightsToGlowTriangles())                     return ERROR_ConvertLightGlow ;
621
622                GetTexLampTextureNumbers() ; // find out which textures, if any, are textures/common/bzn_lightnode0 to textures/common/bzn_lightnode3
623
624                // assign triangles to zones, splitting them where necessary
625                if(!AssignTrianglesToZones())                                           return ERROR_AssignTriangles ;
626
627                if(!ConvertTexLampsToLampTriangles())           return ERROR_ConvertTexLamp ;
628
629                // sort by group and re-range the group numbers
630                if(!SortTrianglesIntoGroups())                                  return ERROR_SortGroups ;
631
632                // sort the triangles in order of zone and texture.  This will also get rid of any unsubzoned triangles.
633                if(!SortTrianglesIntoBatches())                                 return ERROR_SortTriangles ;
634
635               
636
637
638                // Setup the portals, lights and various bits of map connectivity
639                AssignPortalsToZones() ;                // what portals each zone touches
640                AssignLightsToZones() ;                 // what lights each zone touches
641                AssignLightsToPortals() ;               // what lights each portal touches
642                AssignZonesToZones() ;                  // what zones each zone touches
643
644
645                return NOERROR ;
646}
647
648void Q3Map::FreeParseMem(void)
649{
650        FreeVertexMemory() ;
651        FreeTriangleMemory() ;
652        DestroyBspFacesMemory() ;
653}
654
655
656
657
658
659
660
661
662
663
664
665
666///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
667// memory management
668
669int Q3Map::AllocateTriangleMemory(void)
670{
671        // memory for the Triangle
672        m_nTriangleSize=MEMADD ; // starting memory size
673        m_pTriangleMem=malloc(m_nTriangleSize) ; // allocate starting memory space
674        m_pTriangle=(triangle_t*)m_pTriangleMem ; // a pointer to the memory cast as a triangle_t
675        m_nTriangleMax=0 ;
676        m_nTriangleLimit=m_nTriangleSize/sizeof(triangle_t) ; // if pos reaches this memory must expand
677
678        if(m_pTriangleMem==NULL)
679                return 0 ;
680
681        return 1 ;
682}
683
684void Q3Map::FreeTriangleMemory(void)
685{
686        if(m_pTriangleMem) free(m_pTriangleMem) ;
687        m_pTriangleMem=NULL ;
688        m_pTriangle=NULL ;
689        m_nTriangleMax=0 ;
690        m_nTriangleLimit=0 ;
691}
692
693// increase size of Triangle memory, return 0 if failed
694int Q3Map::ExpandTriangleMemory(void)
695{
696        m_nTriangleSize+=MEMADD ; // increase size
697        m_pTriangleMem=realloc(m_pTriangleMem, m_nTriangleSize) ; // reallocate the memory
698        if(m_pTriangleMem==NULL) return 0 ; // failed to allocate memory, get out and return false
699
700        // if here then memory allocation succeeded
701        m_pTriangle=(triangle_t*)m_pTriangleMem ; // pointer to the memory cast as a triangle_t
702        m_nTriangleLimit=m_nTriangleSize/sizeof(triangle_t) ; // if pos reaches this memory must expand
703        return 1 ; // ok
704}
705
706int Q3Map::AddTriangle(triangle_t Triangle)
707{
708        if(m_nTriangleMax>=m_nTriangleLimit)
709                if( !ExpandTriangleMemory() )
710                        return 0 ;
711
712        m_pTriangle[m_nTriangleMax++]=Triangle ;
713
714        return 1 ;
715}
716
717int Q3Map::AllocateVertexMemory(int nVertNum)
718{
719        // memory for the Vertex
720        m_nVertexSize=nVertNum*sizeof(Q3BspVertex)+MEMADD ; // starting memory size
721        m_pVertexMem=malloc(m_nVertexSize) ; // allocate starting memory space
722        m_pVertex=(Q3BspVertex*)m_pVertexMem ; // a pointer to the memory cast as a triangle_t
723        m_nVertexLimit=m_nVertexSize/sizeof(Q3BspVertex) ; // if pos reaches this memory must expand
724
725        if(m_pVertexMem==NULL)
726                return 0 ;
727
728        return 1 ;
729}
730
731void Q3Map::FreeVertexMemory(void)
732{
733        if(m_pVertexMem) free(m_pVertexMem) ;
734        m_pVertexMem=NULL ;
735        m_pVertex=NULL ;
736        m_nVertexMax=0 ;
737        m_nVertexLimit=0 ;
738}
739
740// increase size of Vertex memory, return 0 if failed
741int Q3Map::ExpandVertexMemory(void)
742{
743        m_nVertexSize+=MEMADD ; // increase size
744        m_pVertexMem=realloc(m_pVertexMem, m_nVertexSize) ; // reallocate the memory
745        if(m_pVertexMem==NULL) return 0 ; // failed to allocate memory, get out and return false
746
747        // if here then memory allocation succeeded
748        m_pVertex=(Q3BspVertex*)m_pVertexMem ; // pointer to the memory cast as a triangle_t
749        m_nVertexLimit=m_nVertexSize/sizeof(Q3BspVertex) ; // if pos reaches this memory must expand
750        return 1 ; // ok
751}
752
753int Q3Map::AddVertex(Q3BspVertex Vertex)
754{
755
756        if(m_nVertexMax>=m_nVertexLimit)
757                if( !ExpandVertexMemory() )
758                        return 0 ;
759
760        m_pVertex[m_nVertexMax++]=Vertex ;
761
762        return 1 ;
763}
764
765int Q3Map::AllocateLightMemory(void)
766{
767        // memory for the Light
768        m_nLightSize=MEMADD ; // starting memory size
769        m_pLightMem=malloc(m_nLightSize) ; // allocate starting memory space
770        m_pLight=(light_t*)m_pLightMem ; // a pointer to the memory cast as a light_t
771        m_nLightMax=0 ;
772        m_nLightLimit=m_nLightSize/sizeof(light_t) ; // if pos reaches this memory must expand
773
774        if(m_pLightMem==NULL)
775                return 0 ;
776
777        return 1 ;
778}
779
780void Q3Map::FreeLightMemory(void)
781{
782        if(m_pLightMem) free(m_pLightMem) ;
783        m_pLightMem=NULL ;
784        m_pLight=NULL ;
785        m_nLightMax=0 ;
786        m_nLightLimit=0 ;
787}
788
789// increase size of Light memory, return 0 if failed
790int Q3Map::ExpandLightMemory(void)
791{
792        m_nLightSize+=MEMADD ; // increase size
793        m_pLightMem=realloc(m_pLightMem, m_nLightSize) ; // reallocate the memory
794        if(m_pLightMem==NULL) return 0 ; // failed to allocate memory, get out and return false
795
796        // if here then memory allocation succeeded
797        m_pLight=(light_t*)m_pLightMem ; // pointer to the memory cast as a light_t
798        m_nLightLimit=m_nLightSize/sizeof(light_t) ; // if pos reaches this memory must expand
799        return 1 ; // ok
800}
801
802int Q3Map::AddLight(light_t Light)
803{
804        if(m_nLightLimit==0) // light memory hasn't been allocated yet
805        {
806                if( !AllocateLightMemory() )
807                        return 0 ;
808        }
809        else
810                if(m_nLightMax>=m_nLightLimit)
811                        if( !ExpandLightMemory() )
812                                return 0 ;
813
814        m_pLight[m_nLightMax++]=Light ;
815
816        return 1 ;
817}
818
819// lamps are deferred shading, non-shadowing point lights
820int Q3Map::AllocateLampMemory(void)
821{
822        // memory for the Lamp
823        m_nLampSize=MEMADD ; // starting memory size
824        m_pLampMem=malloc(m_nLampSize) ; // allocate starting memory space
825        m_pLamp=(lamp_t*)m_pLampMem ; // a pointer to the memory cast as a lamp_t
826        m_nLampMax=0 ;
827        m_nLampLimit=m_nLampSize/sizeof(lamp_t) ; // if pos reaches this memory must expand
828
829        if(m_pLampMem==NULL)
830                return 0 ;
831
832        return 1 ;
833}
834
835void Q3Map::FreeLampMemory(void)
836{
837        if(m_pLampMem) free(m_pLampMem) ;
838        m_pLampMem=NULL ;
839        m_pLamp=NULL ;
840        m_nLampMax=0 ;
841        m_nLampLimit=0 ;
842}
843
844// increase size of Lamp memory, return 0 if failed
845int Q3Map::ExpandLampMemory(void)
846{
847        m_nLampSize+=MEMADD ; // increase size
848        m_pLampMem=realloc(m_pLampMem, m_nLampSize) ; // reallocate the memory
849        if(m_pLampMem==NULL) return 0 ; // failed to allocate memory, get out and return false
850
851        // if here then memory allocation succeeded
852        m_pLamp=(lamp_t*)m_pLampMem ; // pointer to the memory cast as a lamp_t
853        m_nLampLimit=m_nLampSize/sizeof(lamp_t) ; // if pos reaches this memory must expand
854        return 1 ; // ok
855}
856
857int Q3Map::AddLamp(lamp_t Lamp)
858{
859        if(m_nLampLimit==0) // Lamp memory hasn't been allocated yet
860        {
861                if( !AllocateLampMemory() )
862                        return 0 ;
863        }
864        else
865                if(m_nLampMax>=m_nLampLimit)
866                        if( !ExpandLampMemory() )
867                                return 0 ;
868
869        m_pLamp[m_nLampMax++]=Lamp ;
870
871        return 1 ;
872}
873
874//////////////
875// Q3BspTexture textures.  We duplicate the loaded texture mem and then add lighting textures to it.
876
877int Q3Map::AllocateTextureMemory(void)
878{
879        // memory for the Texture
880        m_nTextureSize=MEMADD ; // starting memory size
881        m_pTextureMem=malloc(m_nTextureSize) ; // allocate starting memory space
882        m_pTexture=(Q3BspTexture*)m_pTextureMem ; // a pointer to the memory cast as a Q3BspTexture
883        m_nTextureMax=0 ;
884        m_nTextureLimit=m_nTextureSize/sizeof(Q3BspTexture) ; // if pos reaches this memory must expand
885
886        if(m_pTextureMem==NULL)
887                return 0 ;
888
889        return 1 ;
890}
891
892void Q3Map::FreeTextureMemory(void)
893{
894        if(m_pTextureMem) free(m_pTextureMem) ;
895        m_pTextureMem=NULL ;
896        m_pTexture=NULL ;
897        m_nTextureMax=0 ;
898        m_nTextureLimit=0 ;
899}
900
901// increase size of Texture memory, return 0 if failed
902int Q3Map::ExpandTextureMemory(void)
903{
904        m_nTextureSize+=MEMADD ; // increase size
905        m_pTextureMem=realloc(m_pTextureMem, m_nTextureSize) ; // reallocate the memory
906        if(m_pTextureMem==NULL) return 0 ; // failed to allocate memory, get out and return false
907
908        // if here then memory allocation succeeded
909        m_pTexture=(Q3BspTexture*)m_pTextureMem ; // pointer to the memory cast as a Q3BspTexture
910        m_nTextureLimit=m_nTextureSize/sizeof(Q3BspTexture) ; // if pos reaches this memory must expand
911        return 1 ; // ok
912}
913
914int Q3Map::AddTexture(Q3BspTexture Texture)
915{
916        if(m_nTextureLimit==0) // Texture memory hasn't been allocated yet
917        {
918                if( !AllocateTextureMemory() )
919                        return 0 ;
920        }
921        else
922                if(m_nTextureMax>=m_nTextureLimit)
923                        if( !ExpandTextureMemory() )
924                                return 0 ;
925
926        m_pTexture[m_nTextureMax++]=Texture ;
927
928        return 1 ;
929}
930
931// special version of the Add function, will not add if the texture name already exist. 
932// Will succeed even if the texture is already on the list, but fails if it can't add a new texture
933// returns texture index, or -1 on fail
934// Q3 texture names can be tricky, I think I've had cases where they ended in spaces instead of nulls,
935// and they might go all the way to the end without either.
936
937int Q3Map::AddTextureUnique(Q3BspTexture Texture)
938{
939        if(m_nTextureLimit==0) // Texture memory hasn't been allocated yet
940                if( !AllocateTextureMemory() )
941                        return ADDTEXTUREUNIQUE_FAIL ; // fail
942
943
944        // scan through all the newly added textures so far and see if this one already exists.
945        int nTexture=0 ;
946        int nPos=0 ;
947
948        bool bMatch=false ;
949
950        for(nTexture=0 ; nTexture<m_nTextureMax ; nTexture++)
951        {
952                bMatch=true ;
953                // scan through the characters of the texture names, comparing them.  We start after the original textures
954                //for(nPos=m_iNumTexs ; nPos<Q3NAMESIZE ; nPos++)
955                for(nPos=0 ; nPos<Q3NAMESIZE ; nPos++)
956                {
957                        // is it the end of the texture name? 
958                        if(
959                                                ((Texture.name[nPos]                                                    ==0)    || (Texture.name[nPos]                                                  ==' ')) // Texture    name end
960                                        &&((m_pTexture[nTexture].name[nPos] ==0)        || (m_pTexture[nTexture].name[nPos]     ==' ')) // m_pTexture name end
961                                )
962                                break ;
963
964                        // do the two textures have a difference in the name at this position?
965                        if(Texture.name[nPos]!=m_pTexture[nTexture].name[nPos])
966                        {
967                                bMatch=false ;
968                                break ;
969                        }
970               
971                }// end scanning name
972
973                if(bMatch) // found a match, so return ok but don't add a texture
974                {
975                        return nTexture ;  // we don't add any new texture, return this texture's index
976                }
977        }
978
979        // if we got this far, we must have a unique texture
980
981        // add the texture, it is unique
982        if(m_nTextureMax>=m_nTextureLimit)
983                if( !ExpandTextureMemory() )
984                        return ADDTEXTUREUNIQUE_FAIL ; // fail
985
986        m_pTexture[m_nTextureMax++]=Texture ;
987
988        return m_nTextureMax-1 ; // return this new texture's index
989
990}
991
992
993////////////////////////////////////////
994
995int Q3Map::AllocateTexLampMemory(void)
996{
997        // memory for the TexLamp
998        m_nTexLampSize=MEMADD ; // starting memory size
999        m_pTexLampMem=malloc(m_nTexLampSize) ; // allocate starting memory space
1000        m_pTexLamp=(int*)m_pTexLampMem ; // a pointer to the memory cast as an int
1001        m_nTexLampMax=0 ;
1002        m_nTexLampLimit=m_nTexLampSize/sizeof(int) ; // if pos reaches this memory must expand
1003
1004        if(m_pTexLampMem==NULL)
1005                return 0 ;
1006
1007        return 1 ;
1008}
1009
1010void Q3Map::FreeTexLampMemory(void)
1011{
1012        if(m_pTexLampMem) free(m_pTexLampMem) ;
1013        m_pTexLampMem=NULL ;
1014        m_pTexLamp=NULL ;
1015        m_nTexLampMax=0 ;
1016        m_nTexLampLimit=0 ;
1017}
1018
1019// increase size of TexLamp memory, return 0 if failed
1020int Q3Map::ExpandTexLampMemory(void)
1021{
1022        m_nTexLampSize+=MEMADD ; // increase size
1023        m_pTexLampMem=realloc(m_pTexLampMem, m_nTexLampSize) ; // reallocate the memory
1024        if(m_pTexLampMem==NULL) return 0 ; // failed to allocate memory, get out and return false
1025
1026        // if here then memory allocation succeeded
1027        m_pTexLamp=(int*)m_pTexLampMem ; // pointer to the memory cast as an int
1028        m_nTexLampLimit=m_nTexLampSize/sizeof(int) ; // if pos reaches this memory must expand
1029        return 1 ; // ok
1030}
1031
1032int Q3Map::AddTexLamp(int TexLamp)
1033{
1034        if(m_nTexLampMax>=m_nTexLampLimit)
1035                if( !ExpandTexLampMemory() )
1036                        return 0 ;
1037
1038        m_pTexLamp[m_nTexLampMax++]=TexLamp ;
1039
1040        return 1 ;
1041}
1042
1043/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1044//
1045// extract entities from bsp entities lump
1046int Q3Map::ParseEntities(void)
1047{
1048//      char chKey[MAX_TOKENSIZE+1] ;   // +1 to leave room for null terminator
1049//      char chValue[MAX_TOKENSIZE+1] ; // +1 to leave room for null terminator
1050        int nPos=0 ;
1051        int nMaxPos=m_BspHeader.Lumps[0].iLength ;
1052        int nEntityType=0 ;
1053
1054
1055        // reset the spotlight textures
1056        m_nMaxSpotlightTexture=0 ;
1057        for(nPos=0 ; nPos<MAX_PROJECTORTEX ; nPos++)
1058                m_chSpotlightTexture[nPos][0]='\0' ;
1059
1060        strcpy(m_chSpotlightTexture[m_nMaxSpotlightTexture], "spotlight.dds") ; // the default spotlight texture
1061        m_nMaxSpotlightTexture++ ;
1062
1063        ////////////////////////////////////////////////////////////////////////////
1064        // before adding all the entities we need to add some default textures
1065        Q3BspTexture Texture ;
1066        Texture.contents=0 ;
1067        Texture.flags=0 ;
1068
1069        // default lamp texture
1070        strcpy(Texture.name, "lights/lamp_default") ;
1071        m_nDefaultTextureIndexLamp=AddTextureUnique(Texture) ;
1072        if(m_nDefaultTextureIndexLamp==ADDTEXTUREUNIQUE_FAIL) return 0 ;
1073
1074        // default lamp2Pass texture
1075        strcpy(Texture.name, "lights/lamp2pass_default") ;
1076        m_nDefaultTextureIndexLamp2Pass=AddTextureUnique(Texture) ;
1077        if(m_nDefaultTextureIndexLamp2Pass==ADDTEXTUREUNIQUE_FAIL) return 0 ;
1078
1079        // default glow texture
1080        strcpy(Texture.name, "GLOW_lamp") ;
1081        m_nDefaultTextureIndexGlowLamp=AddTextureUnique(Texture) ;
1082        if(m_nDefaultTextureIndexGlowLamp==ADDTEXTUREUNIQUE_FAIL) return 0 ;
1083
1084        // default glow texture
1085        strcpy(Texture.name, "GLOW_light") ;
1086        m_nDefaultTextureIndexGlowLight=AddTextureUnique(Texture) ;
1087        if(m_nDefaultTextureIndexGlowLight==ADDTEXTUREUNIQUE_FAIL) return 0 ;
1088
1089
1090        // default spotlight texture
1091        //strcpy(Texture.name, "lights/light_default") ;
1092        //m_nDefaultTextureIndexSpotlight=AddTextureUnique(Texture) ;
1093        //if(m_nDefaultTextureIndexSpotlight==ADDTEXTUREUNIQUE_FAIL) return 0 ;
1094
1095        //
1096        ///////////////////////////////////////////////////////////////////////////
1097
1098
1099        nPos=-1 ;
1100        while(NextEntity(&nPos, nMaxPos))
1101        {
1102               
1103                nEntityType=GetEntityType(nPos, nMaxPos) ; // what type of entity is it?
1104
1105
1106                switch(nEntityType)
1107                {
1108                        case ENTITY_ERROR: return 0 ; // something is wrong with the entity data
1109
1110                        case ENTITY_LIGHT: 
1111                                if(!ParseAndAddLight(&nPos, nMaxPos)) 
1112                                        return 0 ; // something went wrong with parsing the light
1113                                break ;
1114                }// end switch entity type
1115
1116
1117        }// end get next entity
1118
1119
1120
1121        // everything is ok.
1122        return 1 ;
1123}
1124
1125// move to the beginning of the next entity.
1126// fail if there are no more.
1127int Q3Map::NextEntity(int* pPos, int nMaxPos)
1128{
1129        while((++*pPos<nMaxPos) && (m_pEntities[*pPos]!='{')) ;
1130
1131        if(*pPos==nMaxPos) 
1132                return 0 ;
1133
1134        return 1 ;
1135}
1136
1137// find out what type of entity this is.
1138// Since the classname might not be at the beginning we have to scan through the whole entity
1139// This function also doesn't update the position like the others do,
1140// since scanning of further key/values will have to start at the beginning of the entity again.
1141int Q3Map::GetEntityType(int nPos, int nMaxPos)
1142{
1143        char chKey[MAX_TOKENSIZE+1] ;   // +1 to leave room for null terminator
1144        char chValue[MAX_TOKENSIZE+1] ; // +1 to leave room for null terminator
1145
1146        while(nPos<nMaxPos)
1147        {
1148                if(GetEntityKeyAndValue(&nPos, nMaxPos, chKey, chValue)!=KEY_OK) return ENTITY_ERROR ; // something went wrong, couldn't find any good keys
1149               
1150                if(strcmp(chKey, "classname")==0) // found the classname key
1151                {
1152                        if(strcmp(chValue, "worldspawn")==0)                    return ENTITY_WORLDSPAWN ;
1153                        if(strcmp(chValue, "light")==0)                                         return ENTITY_LIGHT ;
1154
1155                        // wasn't any entity we recognize
1156                        return ENTITY_UNKNOWN ;
1157
1158                }// end if got entity classname
1159
1160        }// end while nPos
1161
1162        // didn't find any classname
1163        return ENTITY_ERROR ;
1164}
1165
1166// get next entity key and value
1167int Q3Map::GetEntityKeyAndValue(int* pPos, int nMaxPos, char* pKey, char* pValue)
1168{
1169
1170        char* pEntText=m_pEntities ;
1171        int nEntPos=*pPos ;
1172        int nKeyPos=-1 ;
1173        int nValuePos=-1 ;
1174
1175        // clear key and value strings
1176        pKey[0]='\0' ;
1177        pValue[0]='\0' ;
1178
1179        /////////////////////////////////////////////////////////////////////////////////////////
1180        // Key
1181
1182        // find the next "
1183        while((++nEntPos<nMaxPos) && (pEntText[nEntPos]!='}') && (pEntText[nEntPos]!='"')) ;
1184
1185        // didn't find key, get out
1186        if((nEntPos==nMaxPos) || (pEntText[nEntPos]=='}'))
1187                return KEY_NONE ;
1188
1189
1190        // copy key
1191        while((++nEntPos<nMaxPos) && (nKeyPos<MAX_TOKENSIZE) && (pEntText[nEntPos]!='}') && (pEntText[nEntPos]!='"')) 
1192                pKey[++nKeyPos]=pEntText[nEntPos] ;
1193
1194        if((nEntPos==nMaxPos) || (nKeyPos==MAX_TOKENSIZE) || (pEntText[nEntPos]=='}'))
1195                return KEY_ERROR ; // entity was incomplete or too big
1196
1197        pKey[++nKeyPos]='\0' ;
1198
1199        /////////////////////////////////////////////////////////////////////////////////////////
1200        // value
1201
1202        // find the next "
1203        while((++nEntPos<nMaxPos) && (pEntText[nEntPos]!='}') && (pEntText[nEntPos]!='"')) ;
1204
1205        // didn't find value, get out
1206        if((nEntPos==nMaxPos) || (pEntText[nEntPos]=='}'))
1207                return KEY_ERROR ; 
1208
1209        // copy value
1210        while((++nEntPos<nMaxPos) && (nValuePos<MAX_TOKENSIZE) && (pEntText[nEntPos]!='}') && (pEntText[nEntPos]!='"')) 
1211                pValue[++nValuePos]=pEntText[nEntPos] ;
1212
1213        if((nEntPos==nMaxPos) || (nValuePos==MAX_TOKENSIZE) || (pEntText[nEntPos]=='}'))
1214                return KEY_ERROR ; // entity was incomplete or too big
1215
1216        pValue[++nValuePos]='\0' ;
1217
1218        /////////////////////////////////////////////////////////////////////////////////////////
1219
1220        *pPos=nEntPos+1 ;
1221
1222        return KEY_OK ;
1223}
1224
1225
1226// fills array pNumber with the values extracted from pValue, returns how many numbers it got.
1227// float version
1228int Q3Map::GetNumbersFromValue(char* pValue, float *pNumber, int nNumberSize)
1229{
1230        int nLength=strlen(pValue) ;
1231        if(nLength<1) return 0 ;
1232
1233        int nPos=-1 ;
1234        int nCount=0 ;
1235        char chTemp[MAX_TOKENSIZE+1] ;
1236        int nTempPos=0 ;
1237
1238        do
1239        {
1240
1241                nPos++ ;
1242               
1243                if(
1244                                ((pValue[nPos]>='0') && (pValue[nPos]<='9')) // found another digit
1245                                ||
1246                                (pValue[nPos]=='.')
1247                                ||
1248                                (pValue[nPos]=='-')
1249                        )
1250                {
1251                        chTemp[nTempPos++]=pValue[nPos] ;
1252                        if(nTempPos==MAX_TOKENSIZE) return 0 ; // number too big
1253                }
1254                else // anything else means the end of the number
1255                {
1256                       
1257                        chTemp[nTempPos]='\0' ;
1258                        pNumber[nCount++]=atof(chTemp) ;
1259                        nTempPos=0 ;
1260                }
1261               
1262
1263        }while((nPos<nLength) && (nCount<nNumberSize) && (pValue[nPos]!='\0')) ;
1264
1265
1266        return nCount ;
1267}
1268
1269// integer version
1270int Q3Map::GetNumbersFromValue(char* pValue, int *pNumber, int nNumberSize)
1271{
1272        int nLength=strlen(pValue) ;
1273        if(nLength<1) return 0 ;
1274
1275        int nPos=-1 ;
1276        int nCount=0 ;
1277        char chTemp[MAX_TOKENSIZE+1] ;
1278        int nTempPos=0 ;
1279
1280        do
1281        {
1282
1283                nPos++ ;
1284               
1285                if(
1286                                ((pValue[nPos]>='0') && (pValue[nPos]<='9')) // found another digit
1287                                ||
1288                                (pValue[nPos]=='.')
1289                                ||
1290                                (pValue[nPos]=='-')
1291                        )
1292                {
1293                        chTemp[nTempPos++]=pValue[nPos] ;
1294                        if(nTempPos==MAX_TOKENSIZE) return 0 ; // number too big
1295                }
1296                else // anything else means the end of the number
1297                {
1298                       
1299                        chTemp[nTempPos]='\0' ;
1300                        pNumber[nCount++]=atoi(chTemp) ;
1301                        nTempPos=0 ;
1302                }
1303               
1304
1305        }while((nPos<nLength) && (nCount<nNumberSize) && (pValue[nPos]!='\0')) ;
1306
1307
1308        return nCount ;
1309}
1310
1311//''
1312// extracts data for either forward rendered shadow casting spotlights or deferred shading non-shadowing point lights
1313// the point lights ("lamps") will later be changed into map triangles.
1314int Q3Map::ParseAndAddLight(int* pPos, int nMaxPos)
1315{
1316//      char chMessage[1024] ;
1317
1318
1319        char chKey[MAX_TOKENSIZE+1] ;   // +1 to leave room for null terminator
1320        char chValue[MAX_TOKENSIZE+1] ; // +1 to leave room for null terminator
1321        float flOrigin[3]={0.0f, 0.0f, 0.0f} ;
1322        float flColour[3]={1.0f, 1.0f, 1.0f} ;
1323        float flCentre[3]={0.0f, 0.0f, 0.0f} ;
1324        float flAimvec[3]={0.0f, 0.0f, 0.0f} ;
1325        float flRadius[3]={0.0f, 0.0f, 0.0f} ;
1326       
1327        float flTemp[3]={0.0f, 0.0f, 0.0f} ;
1328        int nTemp[3] ;
1329
1330        float flAngle=0.0f ;
1331        float flCutoff=0.0f ;
1332        float flLength=0.0f ;
1333        float flBrightness=0.0f ;
1334        int nLightNode=-1 ;
1335
1336        bool bSpotLight=false ;
1337
1338        Q3BspTexture Q3Texture ;
1339        Q3Texture.flags=0 ;
1340        Q3Texture.contents=0 ;
1341        Q3Texture.name[0]=0 ;
1342
1343
1344        light_t NewLight ; // forward rendered shadow casting spotlight
1345        ZeroMemory((void*)&NewLight, sizeof(light_t)) ;
1346
1347        lamp_t NewLamp ; // deferred shading non-shadowing point light
1348        ZeroMemory((void*)&NewLamp, sizeof(lamp_t)) ;
1349
1350        int nKeyReturn=KEY_NONE ; 
1351
1352        do
1353        {
1354                nKeyReturn=GetEntityKeyAndValue(pPos, nMaxPos, chKey, chValue) ;
1355       
1356                if(nKeyReturn==KEY_OK) // found a key
1357                {
1358
1359                        if(strcmp(chKey, "origin")==0)
1360                        {
1361                                if(GetNumbersFromValue(chValue, flOrigin, 3)!=3) return 0 ; // extract the numbers
1362                                swizzleFloat3(flOrigin) ; // fix coordinates
1363                        }
1364                        else
1365                        if(strcmp(chKey, "_color")==0)
1366                        {
1367                                if(GetNumbersFromValue(chValue, flColour, 3)!=3) return 0 ; // extract the numbers
1368                        }
1369                        else
1370                        if(strcmp(chKey, "light_center")==0)
1371                        {
1372                                if(GetNumbersFromValue(chValue, flCentre, 3)!=3) return 0 ; // extract the numbers             
1373                                swizzleFloat3(flCentre) ; // fix coordinates
1374                        }
1375                        else
1376                        if(strcmp(chKey, "light_target")==0)
1377                        {
1378                                if(GetNumbersFromValue(chValue, flAimvec, 3)!=3) return 0 ; // extract the numbers             
1379                                swizzleFloat3(flAimvec) ; // fix coordinates
1380                                bSpotLight=true ; // if there's a target key, then this must be a spotlight
1381                        }
1382                        else
1383                        if(strcmp(chKey, "light_radius")==0)
1384                        {
1385                                if(GetNumbersFromValue(chValue, flRadius, 3)!=3) return 0 ; // extract the numbers
1386                                swizzleFloat3(flRadius) ; // fix coordinates
1387                                // make sure all values are positive
1388                                flRadius[0]=fabs(flRadius[0]) ;
1389                                flRadius[1]=fabs(flRadius[1]) ;
1390                                flRadius[2]=fabs(flRadius[2]) ;
1391                        }
1392                        else
1393                        if(strcmp(chKey, "light_abc")==0)
1394                        {
1395                                if(GetNumbersFromValue(chValue, flTemp, 3)!=3) return 0 ; // extract the numbers
1396                                flAngle                         = flTemp[0] ;
1397                                flBrightness    = flTemp[1] ;
1398                                flCutoff                        = flTemp[2] ;
1399                        }
1400                        else
1401                        if(strcmp(chKey, "texture")==0)
1402                        {
1403                                strcpy(Q3Texture.name, chValue) ;
1404                        }
1405                        if(strcmp(chKey, "light_node")==0)
1406                        {
1407                                if(GetNumbersFromValue(chValue, nTemp, 1)!=1) return 0 ; // extract the number
1408                                nLightNode                              = nTemp[0] ;   
1409                                if((nLightNode<0) || (nLightNode>3)) return 0 ; // something dodgy about the lightnode number
1410                        }
1411
1412                }// end if key ok
1413
1414               
1415
1416        }while(nKeyReturn==KEY_OK) ;  // end do looping through keys
1417
1418
1419        // return a fail if there was a problem with the keys
1420        if(nKeyReturn==KEY_ERROR) return 0 ; 
1421
1422
1423        if(bSpotLight)// found a light_target so this must be a spotlight
1424        {
1425                // light settings.
1426                NewLight.Position[0]=flOrigin[0]+flCentre[0] ;
1427                NewLight.Position[1]=flOrigin[1]+flCentre[1] ;
1428                NewLight.Position[2]=flOrigin[2]+flCentre[2] ;
1429
1430                NewLight.Min[0]=flOrigin[0]-flRadius[0] ;
1431                NewLight.Min[1]=flOrigin[1]-flRadius[1] ;
1432                NewLight.Min[2]=flOrigin[2]-flRadius[2] ;
1433
1434                NewLight.Max[0]=flOrigin[0]+flRadius[0] ;
1435                NewLight.Max[1]=flOrigin[1]+flRadius[1] ;
1436                NewLight.Max[2]=flOrigin[2]+flRadius[2] ;
1437
1438                NewLight.Colour[0]=flColour[0] ;
1439                NewLight.Colour[1]=flColour[1] ;
1440                NewLight.Colour[2]=flColour[2] ;
1441
1442                NewLight.Angle=flAngle ;
1443                NewLight.Cutoff=flCutoff ;
1444                NewLight.Brightness=flBrightness * BRIGHTNESSTWEAK ;
1445
1446
1447                // direction light points, as a normal
1448                flLength=sqrt( flAimvec[0]*flAimvec[0] + flAimvec[1]*flAimvec[1] + flAimvec[2]*flAimvec[2] ) ;
1449                if(flLength>0.0f)
1450                {
1451                        NewLight.Direction[0]=flAimvec[0]/flLength ;
1452                        NewLight.Direction[1]=flAimvec[1]/flLength ;
1453                        NewLight.Direction[2]=flAimvec[2]/flLength ;
1454                }
1455                else
1456                { // default to pointing down
1457                        NewLight.Direction[0]=0.0f ;
1458                        NewLight.Direction[1]=1.0f ;
1459                        NewLight.Direction[2]=0.0f ;
1460                }
1461
1462                NewLight.ZoneCount=0 ;
1463                NewLight.CentreZone=0 ;
1464       
1465               
1466                if(Q3Texture.name[0]==0)       
1467                        strcpy(Q3Texture.name, "spotlight.dds") ;
1468               
1469                NewLight.Texture=AddSpolightTexture(Q3Texture.name) ;
1470
1471
1472                if(NewLight.Texture==ADDSPOTLIGHTTEXTURE_FAIL)
1473                        return 0 ; // failure   
1474       
1475                //AddTextureUnique(Q3Texture) ;
1476                /*
1477                // add the light's texture index
1478                if(Q3Texture.name[0]==0)
1479                        NewLight.Texture=m_nDefaultTextureIndexSpotlight ;
1480                else
1481                {
1482                        NewLight.Texture=AddTextureUnique(Q3Texture) ; // this will add the texture name to the list if it is unique, as well as setting the index
1483                        if(NewLight.Texture==ADDTEXTUREUNIQUE_FAIL)
1484                                return 0 ;
1485                }
1486                */
1487
1488                return AddLight(NewLight) ;
1489        }
1490        else // add a non-shadowing deferred shading point light
1491        {
1492                // light settings.
1493                NewLamp.Position[0]=flOrigin[0]+flCentre[0] ;
1494                NewLamp.Position[1]=flOrigin[1]+flCentre[1] ;
1495                NewLamp.Position[2]=flOrigin[2]+flCentre[2] ;
1496
1497                NewLamp.Min[0]=flOrigin[0]-flRadius[0] ;
1498                NewLamp.Min[1]=flOrigin[1]-flRadius[1] ;
1499                NewLamp.Min[2]=flOrigin[2]-flRadius[2] ;
1500
1501                NewLamp.Max[0]=flOrigin[0]+flRadius[0] ;
1502                NewLamp.Max[1]=flOrigin[1]+flRadius[1] ;
1503                NewLamp.Max[2]=flOrigin[2]+flRadius[2] ;
1504
1505                NewLamp.Colour[0]=flColour[0] ;
1506                NewLamp.Colour[1]=flColour[1] ;
1507                NewLamp.Colour[2]=flColour[2] ;
1508
1509                NewLamp.Brightness=flBrightness * BRIGHTNESSTWEAK ;
1510
1511                NewLamp.LightNode=nLightNode ; // typically -1, but may be 0 to 3 if this lamp is the node for some TexLamp freeform deferred shading geometry.
1512
1513
1514                // Note that m_pLamp.Zone will be set after we first convert lamps into triangles and then
1515                // assign those triangles to zones.  At that point, if the assigned triangle is also flagged as
1516                // coming from a lamp, then the lamp's list of zones will be updated.
1517
1518                                // add the light's texture index
1519                if(Q3Texture.name[0]==0)
1520                {
1521                        if(nLightNode==-1)
1522                                NewLamp.Texture=m_nDefaultTextureIndexLamp ; // normal 1 pass deferred shading
1523                        else
1524                                NewLamp.Texture=m_nDefaultTextureIndexLamp2Pass ; // special 2 pass deferred shading to texlamps
1525                }
1526                else
1527                {
1528                        NewLamp.Texture=AddTextureUnique(Q3Texture) ; // this will add the texture name to the list if it is unique, as well as setting the index
1529                        if(NewLamp.Texture==ADDTEXTUREUNIQUE_FAIL) 
1530                                return 0 ;
1531                }       
1532
1533                return AddLamp(NewLamp) ;
1534        }
1535
1536}
1537
1538// adds a spotlight texture name if it is unique, returns the index to that texture name either way.
1539// returns ADDSPOTLIGHTTEXTURE_FAIL on a fail
1540
1541int Q3Map::AddSpolightTexture(char TEXNAME[])
1542{
1543        if((strlen(TEXNAME)>Q3NAMESIZE) || (m_nMaxSpotlightTexture>=MAX_PROJECTORTEX))
1544                return ADDSPOTLIGHTTEXTURE_FAIL ;
1545
1546
1547        // scan through all the newly added textures so far and see if this one already exists.
1548        int nTexture=0 ;
1549        int nPos=0 ;
1550
1551        bool bMatch ;
1552
1553        for(nTexture=0 ; nTexture<m_nMaxSpotlightTexture ; nTexture++)
1554        {
1555                bMatch=true ;
1556                // scan through the characters of the texture names, comparing them.
1557                for(nPos=0 ; nPos<Q3NAMESIZE ; nPos++)
1558                {
1559                        // do the two textures have a difference in the name at this position?
1560                        if(m_chSpotlightTexture[nTexture][nPos]!=TEXNAME[nPos])
1561                        {
1562                                bMatch=false ;
1563                                break ;
1564                        }
1565
1566                        // is it the end of the texture name? 
1567                        if(TEXNAME[nPos]=='\0') // end of texture
1568                                break ;
1569               
1570                }// end scanning name
1571
1572                if(bMatch) // found a match, so return ok but don't add a texture
1573                        return nTexture ;  // we don't add any new texture, return this texture's index
1574        }
1575
1576        // if we got this far, we must have a unique texture
1577        strcpy(m_chSpotlightTexture[m_nMaxSpotlightTexture], TEXNAME) ;
1578        m_nMaxSpotlightTexture++ ;
1579
1580        return m_nMaxSpotlightTexture-1 ; // return this new texture's index
1581
1582}
1583
1584
1585/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1586
1587
1588int Q3Map::initFaces(void)
1589{
1590
1591        m_nGroup=0 ; // reset the group counter, used to work out transparent groupings for triangles.
1592       
1593  Q3BspFace_t *faces = getFaces();
1594
1595  m_BspFaces = new Q3BspFaceRenderer[m_iNumFaces];
1596        if(m_BspFaces==NULL) return 0 ; // fail, out of memory.
1597  m_NumBspFaces = m_iNumFaces;
1598
1599       
1600  for (int i=0; i < m_NumBspFaces; i++)
1601  {                                     
1602    m_BspFaces[i].lm_index = faces[i].lm_index;
1603    m_BspFaces[i].meshvert = faces[i].meshvert;
1604    m_BspFaces[i].n_meshverts = faces[i].n_meshverts;
1605    m_BspFaces[i].n_vertexes = faces[i].n_vertexes;
1606    for (int j=0; j<3; j++)
1607      m_BspFaces[i].normal[j] = faces[i].normal[j];
1608    m_BspFaces[i].texture = faces[i].texture;
1609    m_BspFaces[i].type = faces[i].type;
1610    m_BspFaces[i].vertex = faces[i].vertex;
1611
1612    m_BspFaces[i].n_triangles = m_BspFaces[i].n_meshverts / 3;
1613
1614    if (m_BspFaces[i].type == PATCH)
1615    {
1616      m_BspFaces[i].patch = handlePatch(i);
1617    }
1618    else
1619    {
1620      m_BspFaces[i].patch = NULL;
1621    }
1622
1623
1624  }
1625
1626
1627        // check patches aren't degenerate
1628        int numIndex = 0;
1629  int numVertex = 0;
1630
1631
1632    for (int i=0; i < m_NumBspFaces; i++)
1633    {           
1634
1635                        numIndex = 0;
1636                        numVertex = 0;
1637
1638      if ((m_BspFaces[i].type == PATCH) && (m_BspFaces[i].patch != NULL))
1639                        {
1640          for (int j=0; j < m_BspFaces[i].patch->size; j++)
1641          {
1642            numIndex += m_BspFaces[i].patch->bezier[j].mNumIndex;
1643            numVertex += m_BspFaces[i].patch->bezier[j].mNumVertex;
1644          }
1645
1646                                        if((numIndex==0) || (numVertex==0))
1647                                        {
1648                                                DELETE_ARRAY( m_BspFaces[i].patch->bezier ) ;
1649                                                DELETE_POINTER( m_BspFaces[i].patch ) ;
1650                                        }
1651
1652      }// end if patch
1653
1654
1655    }// end for
1656
1657
1658
1659        // copy the vertices over. 
1660        // We need to work on a copy because we need to create new verts when splitting triangles that cross subzones, and for patches
1661        for(int i=0 ; i<m_iNumVertices ; i++)
1662        {
1663                m_pVertex[i]=m_pVertices[i] ;
1664                m_nVertexMax++ ; // need to update this manually since we aren't adding new verts, but filling in the original mem.
1665        }
1666
1667
1668        return 1 ;
1669
1670}
1671
1672
1673/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1674//
1675// stuff for assigning triangles to subzones, splitting them where necessary.
1676//
1677/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1678
1679void Q3Map::SetupZones(void)
1680{
1681        int nSubZone=0 ;
1682        int nZone=0 ;
1683        int nPos=0 ;
1684
1685//      float flMinX=0.0f ;
1686//      float flMinY=0.0f ;
1687//      float flMinZ=0.0f ;
1688//      float flMaxX=0.0f ;
1689//      float flMaxY=0.0f ;
1690//      float flMaxZ=0.0f ;
1691
1692        m_nMaxZone=0 ;
1693       
1694        for(nZone=0 ; nZone<MAX_ZONE ; nZone++)
1695        {
1696                m_nZone[nZone][INDEX_SUBZONECOUNT]=0 ;
1697                m_ZoneBoundary[nZone].Min[0]=MINMAXLIMIT ;
1698                m_ZoneBoundary[nZone].Min[1]=MINMAXLIMIT ;
1699                m_ZoneBoundary[nZone].Min[2]=MINMAXLIMIT ;
1700                m_ZoneBoundary[nZone].Max[0]=-MINMAXLIMIT ;
1701                m_ZoneBoundary[nZone].Max[1]=-MINMAXLIMIT ;
1702                m_ZoneBoundary[nZone].Max[2]=-MINMAXLIMIT ;
1703        }
1704
1705
1706        // find the highest used zone number, then +1 to get our limit.
1707        for(nSubZone=0 ; nSubZone<m_iNumSubZones ; nSubZone++)
1708                if(m_pSubZones[nSubZone].Zone>m_nMaxZone)
1709                        m_nMaxZone=m_pSubZones[nSubZone].Zone ;
1710
1711        m_nMaxZone++ ; // our limit
1712
1713       
1714        //char chMessage[1024] ;
1715
1716
1717        // fill in what subzones are in each zone
1718        for(nSubZone=0 ; nSubZone<m_iNumSubZones ; nSubZone++)
1719        {
1720               
1721
1722                nZone=m_pSubZones[nSubZone].Zone ;
1723
1724                // find next empty slot in this zone
1725                nPos=0 ;
1726                while((nPos<MAX_SUBZONEPERZONE) && (nPos<m_nZone[nZone][INDEX_SUBZONECOUNT]))
1727                        nPos++ ;
1728
1729                // if there's room, add the subzone to this zone
1730                if(nPos<MAX_SUBZONEPERZONE) 
1731                {
1732                        m_nZone[nZone][nPos]=nSubZone ;
1733
1734                        // limits used for cutting up lights (not useful for other boundary stuff, check subzones instead)
1735                        if(m_pSubZones[nSubZone].Min[0]<m_ZoneBoundary[nZone].Min[0]) 
1736                                m_ZoneBoundary[nZone].Min[0]= m_pSubZones[nSubZone].Min[0] ;
1737                        if(m_pSubZones[nSubZone].Min[1]<m_ZoneBoundary[nZone].Min[1]) 
1738                                m_ZoneBoundary[nZone].Min[1]= m_pSubZones[nSubZone].Min[1] ;
1739                        if(m_pSubZones[nSubZone].Min[2]<m_ZoneBoundary[nZone].Min[2]) 
1740                                m_ZoneBoundary[nZone].Min[2]= m_pSubZones[nSubZone].Min[2] ;
1741
1742                        if(m_pSubZones[nSubZone].Max[0]>m_ZoneBoundary[nZone].Max[0]) 
1743                                m_ZoneBoundary[nZone].Max[0]= m_pSubZones[nSubZone].Max[0] ;
1744                        if(m_pSubZones[nSubZone].Max[1]>m_ZoneBoundary[nZone].Max[1]) 
1745                                m_ZoneBoundary[nZone].Max[1]= m_pSubZones[nSubZone].Max[1] ;
1746                        if(m_pSubZones[nSubZone].Max[2]>m_ZoneBoundary[nZone].Max[2]) 
1747                                m_ZoneBoundary[nZone].Max[2]= m_pSubZones[nSubZone].Max[2] ;
1748
1749                        m_nZone[nZone][INDEX_SUBZONECOUNT]++ ;
1750                }
1751
1752
1753        }
1754
1755
1756}
1757
1758
1759// work out what zone each triangle is in.
1760// if it is in more than one, cut it up into smaller triangles that are only in one zone each.
1761int Q3Map::AssignTrianglesToZones(void)
1762{
1763        int nCurrentTriangle=0 ;
1764//      int nZone=0 ;
1765
1766
1767        /*
1768        char chMessage[1024] ;
1769        float flPos[3] ;
1770        int nTri=0 ;
1771        float flVert[3][3] ;
1772       
1773
1774        for(nTri=0 ; nTri<m_nTriangleMax ; nTri++)
1775        {
1776                flVert[0][0]=m_pVertex[  m_pTriangle[nTri].VIndex[0]  ].position[0] ;
1777                flVert[0][1]=m_pVertex[  m_pTriangle[nTri].VIndex[0]  ].position[1] ;
1778                flVert[0][2]=m_pVertex[  m_pTriangle[nTri].VIndex[0]  ].position[2] ;
1779
1780                flVert[1][0]=m_pVertex[  m_pTriangle[nTri].VIndex[1]  ].position[0] ;
1781                flVert[1][1]=m_pVertex[  m_pTriangle[nTri].VIndex[1]  ].position[1] ;
1782                flVert[1][2]=m_pVertex[  m_pTriangle[nTri].VIndex[1]  ].position[2] ;
1783
1784                flVert[2][0]=m_pVertex[  m_pTriangle[nTri].VIndex[2]  ].position[0] ;
1785                flVert[2][1]=m_pVertex[  m_pTriangle[nTri].VIndex[2]  ].position[1] ;
1786                flVert[2][2]=m_pVertex[  m_pTriangle[nTri].VIndex[2]  ].position[2] ;
1787
1788
1789                flPos[0]=(flVert[0][0]+flVert[1][0]+flVert[2][0])/3.0f ;
1790                flPos[1]=(flVert[0][1]+flVert[1][1]+flVert[2][1])/3.0f ;
1791                flPos[2]=(flVert[0][2]+flVert[1][2]+flVert[2][2])/3.0f ;
1792
1793                nZone=0 ;
1794                while((nZone<m_iNumSubZones) && !PointInZone(flPos, nZone))
1795                        nZone++ ;
1796
1797
1798
1799
1800        }
1801        */
1802
1803
1804
1805        for(nCurrentTriangle=0 ; nCurrentTriangle<m_nTriangleMax ; nCurrentTriangle++)
1806        {
1807                if(!SetupTriangleZone(nCurrentTriangle)) return 0 ; // what zone completely contains this triangle, if any
1808
1809        }// end for current triangle
1810
1811        return 1 ;
1812}
1813
1814// return the zone this triangle is in, or -1 if it is not entirely contained by any zone
1815// this is also a convienient spot for us to update Lamp zones when we discover what zones its triangles are in,
1816// and also a handy place to note if the triangle is a TexLamp or not
1817// (TexLamp is free form geometry that is bound to a lamp and gets converted to deferred shading lights, allowing us to do fake shadowing)
1818
1819int Q3Map::FindTriangleZone(int nTriangle)
1820{
1821        int nZone=0 ;
1822//      int nSubZone=0 ;
1823        int nPos=0 ;
1824        bool bVertInSubZone=false ;
1825        int nVert=0 ;
1826        bool bTriangleInZone=false ;
1827//      int nMaxSubZone=m_iNumSubZones ;
1828        float flVert[6][3] ; // verts 0, 1, 2 are the original triangle corners, verts 3, 4, 5 are interpolated edge points.
1829        // we need the edge points, since it's possible for all the
1830        // triangle verts to be in one L shaped zone but the triangle they form not be in that zone.
1831        // (such as if there's a vert at the corner and two ends of the "L")
1832
1833
1834        flVert[0][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[0] ;
1835        flVert[0][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[1] ;
1836        flVert[0][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[2] ;
1837
1838        flVert[1][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[0] ;
1839        flVert[1][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[1] ;
1840        flVert[1][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[2] ;
1841
1842        flVert[2][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[0] ;
1843        flVert[2][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[1] ;
1844        flVert[2][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[2] ;
1845
1846        flVert[3][0]=(flVert[0][0]+flVert[1][0])/2.0f ;
1847        flVert[3][1]=(flVert[0][1]+flVert[1][1])/2.0f ;
1848        flVert[3][2]=(flVert[0][2]+flVert[1][2])/2.0f ;
1849
1850        flVert[4][0]=(flVert[1][0]+flVert[2][0])/2.0f ;
1851        flVert[4][1]=(flVert[1][1]+flVert[2][1])/2.0f ;
1852        flVert[4][2]=(flVert[1][2]+flVert[2][2])/2.0f ;
1853
1854        flVert[5][0]=(flVert[2][0]+flVert[0][0])/2.0f ;
1855        flVert[5][1]=(flVert[2][1]+flVert[0][1])/2.0f ;
1856        flVert[5][2]=(flVert[2][2]+flVert[0][2])/2.0f ;
1857
1858
1859        // scan through the zones until:
1860        // a) we find a zone that completely contains the six vertices
1861        // b) we run out of zones.
1862
1863
1864        do
1865        {
1866                nVert=0 ;
1867                bTriangleInZone=false ;
1868
1869                // scan through the verts until:
1870                // a) we find a vert that isn't in this zone
1871                // b) we run out of verts
1872
1873                do
1874                {
1875
1876                        // scan through the zone's subzones until:
1877                        // a) we find one that contains this vert,
1878                        // b) we hit the subzoneperzone limit,
1879                        // c) this zone runs out of subzones
1880
1881                        nPos=0 ;
1882                        do
1883                        {
1884                                bVertInSubZone=PointInSubZone(flVert[nVert], m_nZone[nZone][nPos]) ;
1885                        }while( !bVertInSubZone && (++nPos<MAX_SUBZONEPERZONE) && (nPos<m_nZone[nZone][INDEX_SUBZONECOUNT])) ;
1886
1887                        // if bVertInSubZone is false, we found a vert that isn't in this zone.
1888
1889                }while(bVertInSubZone && (++nVert<6)) ;
1890
1891                if(bVertInSubZone) bTriangleInZone=true ;
1892
1893        }while(!bTriangleInZone && (++nZone<m_nMaxZone)) ;
1894
1895
1896       
1897
1898
1899        if(!bTriangleInZone)
1900                return -1 ;
1901        else
1902        {
1903
1904                // if this triangle came from a lamp entity, we note in that lamp entity that it touches this zone
1905                int nLamp=m_pTriangle[nTriangle].Lamp ;
1906                if(nLamp>-1) // if we have a lamp
1907                {
1908
1909
1910                        int nSlot=m_pLamp[nLamp].Zone[MAX_ZONEPERLIGHT] ;
1911
1912                        if(nSlot<MAX_ZONEPERLIGHT) // if the lamp isn't maxed out on zones
1913                        {
1914                                // check if we already have this zone recorded
1915                                int nCheckSlot=0 ;
1916                                int nFoundDuplicate=0 ;
1917                                for(nCheckSlot=0 ; nCheckSlot<nSlot ; nCheckSlot++)
1918                                        if(m_pLamp[nLamp].Zone[nCheckSlot]==nZone)
1919                                        {
1920                                                nFoundDuplicate=1 ;
1921                                                break ;
1922                                        }
1923
1924                                if(!nFoundDuplicate)
1925                                {
1926                                        m_pLamp[nLamp].Zone[nSlot]=nZone ;  // write the zone into this slot
1927                                        m_pLamp[nLamp].Zone[MAX_ZONEPERLIGHT]++ ; // note that we have one more zone
1928                                }
1929
1930                        }
1931                }
1932
1933
1934                // if this triangle is a TexLamp triangle (free form deferred lighting shapes)
1935                // then we remember this, in order to make assigning it to a lamp faster
1936                int nTexture=m_pTriangle[nTriangle].Texture ;
1937                if((nTexture==m_nBZN_LightNode0) || (nTexture==m_nBZN_LightNode1) || (nTexture==m_nBZN_LightNode2) || (nTexture==m_nBZN_LightNode3))
1938                        if(!AddTexLamp(nTriangle)) 
1939                                return ADDTEXLAMP_FAIL ; //if we failed to note the texlamp (probably out of memory), the whole level load will fail.
1940
1941
1942                // finally, return the zone the triangle is in.
1943                return nZone ;
1944        }
1945}
1946
1947
1948
1949// work out what zone a triangle is in, cut it up if it's in more than one.
1950int Q3Map::SetupTriangleZone(int nTriangle)
1951{
1952
1953
1954        int nZone=0 ;
1955
1956        nZone=FindTriangleZone(nTriangle) ;
1957
1958        if(nZone==ADDTEXLAMP_FAIL)
1959                return 0 ; 
1960
1961
1962        if(nZone!=-1) // triangle was completely in a zone
1963                m_pTriangle[nTriangle].Zone=nZone ;
1964        else
1965        {
1966                // This triangle is in more than one zone.  (Or no subzone at all)
1967                // we chop it up along the edges of every subzone it is in (regardless of whether they are a common zone or not)
1968                // so that the resulting triangles will all be in just one subzone, and therefore in only one zone.
1969                // this might produce a few extra triangles more than we strictly need, since some will both be in the same zone,
1970                // but it is simple and the extra triangles are trivial in number.
1971
1972                // As we go to each new cut plane, it must be applied progressively to all newly created triangles too.
1973
1974                int nInitialTrianglePos=m_nTriangleMax ; // where we start adding new triangles
1975
1976                int nTriLoop=0 ;
1977                int nTriangleToCut=0 ;
1978                int nMaxTriangle=0 ;
1979                int nSide=0 ;
1980                int nAxis=0 ;
1981                float flCutPos=0.0f ;
1982                int nSubZone=0 ;
1983                int nMaxSubZone=m_iNumSubZones ;
1984                int nVert=0 ;
1985                float flVert[6][3] ; // verts 0, 1, 2 are the original triangle corners, verts 3, 4, 5 are interpolated edge points.
1986                // we need the edge points, since it's possible for all the
1987                // triangle verts to be in one L shaped zone but the triangle they form not be in that zone.
1988                // (such as if there's a vert at the corner and two ends of the "L")
1989
1990
1991                flVert[0][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[0] ;
1992                flVert[0][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[1] ;
1993                flVert[0][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[2] ;
1994
1995                flVert[1][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[0] ;
1996                flVert[1][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[1] ;
1997                flVert[1][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[2] ;
1998
1999                flVert[2][0]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[0] ;
2000                flVert[2][1]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[1] ;
2001                flVert[2][2]=m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[2] ;
2002
2003                flVert[3][0]=(flVert[0][0]+flVert[1][0])/2.0f ;
2004                flVert[3][1]=(flVert[0][1]+flVert[1][1])/2.0f ;
2005                flVert[3][2]=(flVert[0][2]+flVert[1][2])/2.0f ;
2006
2007                flVert[4][0]=(flVert[1][0]+flVert[2][0])/2.0f ;
2008                flVert[4][1]=(flVert[1][1]+flVert[2][1])/2.0f ;
2009                flVert[4][2]=(flVert[1][2]+flVert[2][2])/2.0f ;
2010
2011                flVert[5][0]=(flVert[2][0]+flVert[0][0])/2.0f ;
2012                flVert[5][1]=(flVert[2][1]+flVert[0][1])/2.0f ;
2013                flVert[5][2]=(flVert[2][2]+flVert[0][2])/2.0f ;
2014       
2015
2016
2017
2018                for(nSubZone=0 ; nSubZone<nMaxSubZone ; nSubZone++)
2019                {
2020                        // are any of our original verts in this subzone?
2021
2022                        nVert=0 ;
2023                        while( !PointInSubZone(flVert[nVert], nSubZone) && (++nVert<6)) ;
2024
2025                        if(nVert<6) // one of the verts must have been in this subzone.
2026                        {
2027                                // cutup all triangles by the sides of this subzone.
2028                                // we'll need to cut more and more triangles as this progresses. (or at least test if they need to be cut)
2029                                for(nSide=0 ; nSide<6 ; nSide++)
2030                                {
2031                                        switch(nSide)
2032                                        {
2033                                                case 0: nAxis=AXIS_X ; flCutPos=m_pSubZones[nSubZone].Min[0] ; break ;
2034                                                case 1: nAxis=AXIS_X ; flCutPos=m_pSubZones[nSubZone].Max[0] ; break ;
2035                                                case 2: nAxis=AXIS_Y ; flCutPos=m_pSubZones[nSubZone].Min[1] ; break ;
2036                                                case 3: nAxis=AXIS_Y ; flCutPos=m_pSubZones[nSubZone].Max[1] ; break ;
2037                                                case 4: nAxis=AXIS_Z ; flCutPos=m_pSubZones[nSubZone].Min[2] ; break ;
2038                                                case 5: nAxis=AXIS_Z ; flCutPos=m_pSubZones[nSubZone].Max[2] ; break ;
2039                                        }
2040
2041
2042                                        nMaxTriangle=m_nTriangleMax-nInitialTrianglePos ;  // how may new triangles have been created since we first started cutting the original.
2043
2044                                        for(nTriLoop=-1 ; nTriLoop<nMaxTriangle ; nTriLoop++)
2045                                        {
2046                                                // work out if we are cutting up the original triangle or one of the newly created ones.
2047                                                if(nTriLoop==-1)
2048                                                        nTriangleToCut=nTriangle ; // the original triangle, perhaps heavily cutup by now.
2049                                                else
2050                                                        nTriangleToCut=nInitialTrianglePos+nTriLoop ;  // one of the newly created triangles.
2051
2052                                                if(!SplitTriangle(nTriangleToCut, nAxis, flCutPos)) return 0 ; // cut up the triangle, fail if we're out of memory or whatever.
2053
2054
2055                                        }// end for nTriLoop
2056
2057                                }// end cutting by each side of the subzone
2058
2059                        }// end if one of the verts was in this subzone
2060
2061                }// end going through all subzones
2062
2063
2064                // now that the triangle is well and truly chopped up, assign it a zone.
2065                // Even though it should be entirely in a subzone by now, there's still the chance that
2066                // it might not be inside any subzone at all.  If so, it will be assigned -1 zone and
2067                // exluded from the manualobjects
2068               
2069                m_pTriangle[nTriangle].Zone=FindTriangleZone(nTriangle) ;
2070
2071                // we don't have to worry about assigning zones to the newly created triangles,
2072                // they'll get theirs when the AssignTrianglesToZones loop reaches them at the end.
2073
2074        }// end if triangle was in more than one subzone (or no subzone at all)
2075
2076        return 1 ;
2077}
2078
2079
2080// cut a triangle along some axial plane, turning into 2 or 3 triangles.
2081// If the plane doesn't go through the triangle then nothing will happen.
2082int Q3Map::SplitTriangle(int nTriangle, int nAxis, float flCutPos)
2083{
2084
2085        triangle_t NewTri ;
2086
2087        // these will stay -1 if no vert is created, else will be index of the new vert
2088        int nABNum=-1 ;
2089        int nBCNum=-1 ;
2090        int nCANum=-1 ;
2091
2092        Q3BspVertex     VertA = m_pVertex[  m_pTriangle[ nTriangle ].VIndex[0]  ] ;
2093        Q3BspVertex     VertB = m_pVertex[  m_pTriangle[ nTriangle ].VIndex[1]  ] ;
2094        Q3BspVertex     VertC = m_pVertex[  m_pTriangle[ nTriangle ].VIndex[2]  ] ;
2095        Q3BspVertex     VertexAB ;
2096        Q3BspVertex     VertexBC ;
2097        Q3BspVertex     VertexCA ;
2098
2099        float flSpan=0.0f ;
2100        float flCutSpan=0.0f ;
2101        float flPercent=0.0f ;
2102
2103        switch(nAxis)
2104        {
2105
2106                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2107                case AXIS_X:
2108
2109                        ////////////////////////////////////////////////////////////////////////////////////////////////
2110                        // if VertA is on one side of the cut and VertB is on the other, create VertexAB on the cutline.
2111                        if( 
2112                                        ((VertA.position[0]<flCutPos-SUBZONE_EPSILON) && (VertB.position[0]>flCutPos+SUBZONE_EPSILON))
2113                                        ||
2114                                        ((VertA.position[0]>flCutPos+SUBZONE_EPSILON) && (VertB.position[0]<flCutPos-SUBZONE_EPSILON))
2115                                )
2116                        {
2117                                // work out the span and percentage
2118                                if(VertA.position[0]<flCutPos)
2119                                {
2120                                        flSpan=VertB.position[0]-VertA.position[0] ;
2121                                        flCutSpan=flCutPos-VertA.position[0] ;
2122                                        flPercent=1.0f-flCutSpan/flSpan ;
2123                                }
2124                                else
2125                                {
2126                                        flSpan=VertA.position[0]-VertB.position[0] ;
2127                                        flCutSpan=flCutPos-VertB.position[0] ;
2128                                        flPercent=flCutSpan/flSpan ;
2129                                }
2130
2131                                CreateTweenVert(&VertA, &VertB, flPercent, &VertexAB) ;
2132                                nABNum=m_nVertexMax ;
2133                                if(!AddVertex(VertexAB)) 
2134                                        return 0 ;
2135                        }// end if need create VertexAB
2136
2137                        ////////////////////////////////////////////////////////////////////////////////////////////////
2138                        // if VertB is on one side of the cut and VertC is on the other, create VertexBC on the cutline.
2139                        if( 
2140                                        ((VertB.position[0]<flCutPos-SUBZONE_EPSILON) && (VertC.position[0]>flCutPos+SUBZONE_EPSILON))
2141                                        ||
2142                                        ((VertB.position[0]>flCutPos+SUBZONE_EPSILON) && (VertC.position[0]<flCutPos-SUBZONE_EPSILON))
2143                                )
2144                        {
2145                                // work out the span and percentage
2146                                if(VertB.position[0]<flCutPos)
2147                                {
2148                                        flSpan=VertC.position[0]-VertB.position[0] ;
2149                                        flCutSpan=flCutPos-VertB.position[0] ;
2150                                        flPercent=1.0f-flCutSpan/flSpan ;
2151                                }
2152                                else
2153                                {
2154                                        flSpan=VertB.position[0]-VertC.position[0] ;
2155                                        flCutSpan=flCutPos-VertC.position[0] ;
2156                                        flPercent=flCutSpan/flSpan ;
2157                                }
2158
2159                                CreateTweenVert(&VertB, &VertC, flPercent, &VertexBC) ;
2160                                nBCNum=m_nVertexMax ;
2161                                if(!AddVertex(VertexBC)) 
2162                                        return 0 ;
2163
2164                        }// end if need create VertexBC
2165
2166                        ////////////////////////////////////////////////////////////////////////////////////////////////
2167                        // if VertC is on one side of the cut and VertA is on the other, create VertexCA on the cutline.
2168                        if( 
2169                                        ((VertC.position[0]<flCutPos) && (VertA.position[0]>flCutPos))
2170                                        ||
2171                                        ((VertC.position[0]>flCutPos) && (VertA.position[0]<flCutPos))
2172                                )
2173                        {
2174                                // work out the span and percentage
2175                                if(VertC.position[0]<flCutPos)
2176                                {
2177                                        flSpan=VertA.position[0]-VertC.position[0] ;
2178                                        flCutSpan=flCutPos-VertC.position[0] ;
2179                                        flPercent=1.0f-flCutSpan/flSpan ;
2180                                }
2181                                else
2182                                {
2183                                        flSpan=VertC.position[0]-VertA.position[0] ;
2184                                        flCutSpan=flCutPos-VertA.position[0] ;
2185                                        flPercent=flCutSpan/flSpan ;
2186                                }
2187
2188                                CreateTweenVert(&VertC, &VertA, flPercent, &VertexCA) ;
2189                                nCANum=m_nVertexMax ;
2190                                if(!AddVertex(VertexCA)) 
2191                                        return 0 ;
2192
2193                        }// end if need create VertexCA
2194                        break ;
2195
2196               
2197                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2198                case AXIS_Y:
2199
2200                        ////////////////////////////////////////////////////////////////////////////////////////////////
2201                        // if VertA is on one side of the cut and VertB is on the other, create VertexAB on the cutline.
2202                        if( 
2203                                        ((VertA.position[1]<flCutPos-SUBZONE_EPSILON) && (VertB.position[1]>flCutPos+SUBZONE_EPSILON))
2204                                        ||
2205                                        ((VertA.position[1]>flCutPos+SUBZONE_EPSILON) && (VertB.position[1]<flCutPos-SUBZONE_EPSILON))
2206                                )
2207                        {
2208                                // work out the span and percentage
2209                                if(VertA.position[1]<flCutPos)
2210                                {
2211                                        flSpan=VertB.position[1]-VertA.position[1] ;
2212                                        flCutSpan=flCutPos-VertA.position[1] ;
2213                                        flPercent=1.0f-flCutSpan/flSpan ;
2214                                }
2215                                else
2216                                {
2217                                        flSpan=VertA.position[1]-VertB.position[1] ;
2218                                        flCutSpan=flCutPos-VertB.position[1] ;
2219                                        flPercent=flCutSpan/flSpan ;
2220                                }
2221
2222                                CreateTweenVert(&VertA, &VertB, flPercent, &VertexAB) ;
2223                                nABNum=m_nVertexMax ;
2224                                if(!AddVertex(VertexAB)) 
2225                                        return 0 ;
2226                        }// end if need create VertexAB
2227
2228                        ////////////////////////////////////////////////////////////////////////////////////////////////
2229                        // if VertB is on one side of the cut and VertC is on the other, create VertexBC on the cutline.
2230                        if( 
2231                                        ((VertB.position[1]<flCutPos-SUBZONE_EPSILON) && (VertC.position[1]>flCutPos+SUBZONE_EPSILON))
2232                                        ||
2233                                        ((VertB.position[1]>flCutPos+SUBZONE_EPSILON) && (VertC.position[1]<flCutPos-SUBZONE_EPSILON))
2234                                )
2235                        {
2236                                // work out the span and percentage
2237                                if(VertB.position[1]<flCutPos)
2238                                {
2239                                        flSpan=VertC.position[1]-VertB.position[1] ;
2240                                        flCutSpan=flCutPos-VertB.position[1] ;
2241                                        flPercent=1.0f-flCutSpan/flSpan ;
2242                                }
2243                                else
2244                                {
2245                                        flSpan=VertB.position[1]-VertC.position[1] ;
2246                                        flCutSpan=flCutPos-VertC.position[1] ;
2247                                        flPercent=flCutSpan/flSpan ;
2248                                }
2249
2250                                CreateTweenVert(&VertB, &VertC, flPercent, &VertexBC) ;
2251                                nBCNum=m_nVertexMax ;
2252                                if(!AddVertex(VertexBC)) 
2253                                        return 0 ;
2254
2255                        }// end if need create VertexBC
2256
2257                        ////////////////////////////////////////////////////////////////////////////////////////////////
2258                        // if VertC is on one side of the cut and VertA is on the other, create VertexCA on the cutline.
2259                        if( 
2260                                        ((VertC.position[1]<flCutPos) && (VertA.position[1]>flCutPos))
2261                                        ||
2262                                        ((VertC.position[1]>flCutPos) && (VertA.position[1]<flCutPos))
2263                                )
2264                        {
2265                                // work out the span and percentage
2266                                if(VertC.position[1]<flCutPos)
2267                                {
2268                                        flSpan=VertA.position[1]-VertC.position[1] ;
2269                                        flCutSpan=flCutPos-VertC.position[1] ;
2270                                        flPercent=1.0f-flCutSpan/flSpan ;
2271                                }
2272                                else
2273                                {
2274                                        flSpan=VertC.position[1]-VertA.position[1] ;
2275                                        flCutSpan=flCutPos-VertA.position[1] ;
2276                                        flPercent=flCutSpan/flSpan ;
2277                                }
2278
2279                                CreateTweenVert(&VertC, &VertA, flPercent, &VertexCA) ;
2280                                nCANum=m_nVertexMax ;
2281                                if(!AddVertex(VertexCA)) 
2282                                        return 0 ;
2283
2284                        }// end if need create VertexCA
2285                        break ;
2286
2287                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2288                case AXIS_Z:
2289
2290                        ////////////////////////////////////////////////////////////////////////////////////////////////
2291                        // if VertA is on one side of the cut and VertB is on the other, create VertexAB on the cutline.
2292                        if( 
2293                                        ((VertA.position[2]<flCutPos-SUBZONE_EPSILON) && (VertB.position[2]>flCutPos+SUBZONE_EPSILON))
2294                                        ||
2295                                        ((VertA.position[2]>flCutPos+SUBZONE_EPSILON) && (VertB.position[2]<flCutPos-SUBZONE_EPSILON))
2296                                )
2297                        {
2298                                // work out the span and percentage
2299                                if(VertA.position[2]<flCutPos)
2300                                {
2301                                        flSpan=VertB.position[2]-VertA.position[2] ;
2302                                        flCutSpan=flCutPos-VertA.position[2] ;
2303                                        flPercent=1.0f-flCutSpan/flSpan ;
2304                                }
2305                                else
2306                                {
2307                                        flSpan=VertA.position[2]-VertB.position[2] ;
2308                                        flCutSpan=flCutPos-VertB.position[2] ;
2309                                        flPercent=flCutSpan/flSpan ;
2310                                }
2311
2312                                CreateTweenVert(&VertA, &VertB, flPercent, &VertexAB) ;
2313                                nABNum=m_nVertexMax ;
2314                                if(!AddVertex(VertexAB)) 
2315                                        return 0 ;
2316                        }// end if need create VertexAB
2317
2318                        ////////////////////////////////////////////////////////////////////////////////////////////////
2319                        // if VertB is on one side of the cut and VertC is on the other, create VertexBC on the cutline.
2320                        if( 
2321                                        ((VertB.position[2]<flCutPos-SUBZONE_EPSILON) && (VertC.position[2]>flCutPos+SUBZONE_EPSILON))
2322                                        ||
2323                                        ((VertB.position[2]>flCutPos+SUBZONE_EPSILON) && (VertC.position[2]<flCutPos-SUBZONE_EPSILON))
2324                                )
2325                        {
2326                                // work out the span and percentage
2327                                if(VertB.position[2]<flCutPos)
2328                                {
2329                                        flSpan=VertC.position[2]-VertB.position[2] ;
2330                                        flCutSpan=flCutPos-VertB.position[2] ;
2331                                        flPercent=1.0f-flCutSpan/flSpan ;
2332                                }
2333                                else
2334                                {
2335                                        flSpan=VertB.position[2]-VertC.position[2] ;
2336                                        flCutSpan=flCutPos-VertC.position[2] ;
2337                                        flPercent=flCutSpan/flSpan ;
2338                                }
2339
2340                                CreateTweenVert(&VertB, &VertC, flPercent, &VertexBC) ;
2341                                nBCNum=m_nVertexMax ;
2342                                if(!AddVertex(VertexBC)) 
2343                                        return 0 ;
2344
2345                        }// end if need create VertexBC
2346
2347                        ////////////////////////////////////////////////////////////////////////////////////////////////
2348                        // if VertC is on one side of the cut and VertA is on the other, create VertexCA on the cutline.
2349                        if( 
2350                                        ((VertC.position[2]<flCutPos) && (VertA.position[2]>flCutPos))
2351                                        ||
2352                                        ((VertC.position[2]>flCutPos) && (VertA.position[2]<flCutPos))
2353                                )
2354                        {
2355                                // work out the span and percentage
2356                                if(VertC.position[2]<flCutPos)
2357                                {
2358                                        flSpan=VertA.position[2]-VertC.position[2] ;
2359                                        flCutSpan=flCutPos-VertC.position[2] ;
2360                                        flPercent=1.0f-flCutSpan/flSpan ;
2361                                }
2362                                else
2363                                {
2364                                        flSpan=VertC.position[2]-VertA.position[2] ;
2365                                        flCutSpan=flCutPos-VertA.position[2] ;
2366                                        flPercent=flCutSpan/flSpan ;
2367                                }
2368
2369                                CreateTweenVert(&VertC, &VertA, flPercent, &VertexCA) ;
2370                                nCANum=m_nVertexMax ;
2371                                if(!AddVertex(VertexCA)) 
2372                                        return 0 ;
2373
2374                        }// end if need create VertexCA
2375                        break ;
2376
2377
2378        }
2379
2380//      int nInitialTrianglePos=m_nTriangleMax ; // debugging
2381
2382        // default parameters for all new triangles
2383        NewTri.Texture  =       m_pTriangle[ nTriangle ].Texture ;
2384        //NewTri.Lightmap       =       m_pTriangle[ nTriangle ].Lightmap ; // bzn doesn't use lightmaps
2385        NewTri.Lamp                     = m_pTriangle[ nTriangle ].Lamp ; 
2386        NewTri.Group = m_pTriangle[ nTriangle ].Group ;
2387
2388        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2389        // now we create new triangles depending on the verts we created.
2390        if((nABNum!=-1) && (nCANum!=-1))
2391        {
2392                // add (AB, B, C)
2393                NewTri.VIndex[0]=nABNum ;
2394                NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[1] ;
2395                NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[2] ;
2396                if(!AddTriangle(NewTri)) return 0 ;
2397
2398                // add (C, CA, AB)
2399                NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[2] ;
2400                NewTri.VIndex[1]=nCANum ;
2401                NewTri.VIndex[2]=nABNum ;
2402                if(!AddTriangle(NewTri)) return 0 ;
2403
2404                // overwrite the original triangle with (A, AB, CA)
2405                NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[0] ;
2406                NewTri.VIndex[1]=nABNum ;
2407                NewTri.VIndex[2]=nCANum ;
2408                m_pTriangle[ nTriangle ]=NewTri ;
2409        }
2410        else
2411        if((nABNum!=-1) && (nBCNum!=-1))
2412        {
2413                // add (BC, C, A)
2414                NewTri.VIndex[0]=nBCNum ;
2415                NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[2] ;
2416                NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[0] ;
2417                if(!AddTriangle(NewTri)) return 0 ;
2418
2419                // add (A, AB, BC)
2420                NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[0] ;
2421                NewTri.VIndex[1]=nABNum ;
2422                NewTri.VIndex[2]=nBCNum ;
2423                if(!AddTriangle(NewTri)) return 0 ;
2424
2425                // overwrite the original triangle with (B, BC, AB)
2426                NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[1] ;
2427                NewTri.VIndex[1]=nBCNum ;
2428                NewTri.VIndex[2]=nABNum ;
2429                m_pTriangle[ nTriangle ]=NewTri ;
2430        }
2431        else
2432        if((nBCNum!=-1) && (nCANum!=-1))
2433        {
2434                // add (CA, A, B)
2435                NewTri.VIndex[0]=nCANum ;
2436                NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[0] ;
2437                NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[1] ;
2438                if(!AddTriangle(NewTri)) return 0 ;
2439
2440                // add (B, BC, CA)
2441                NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[1] ;
2442                NewTri.VIndex[1]=nBCNum ;
2443                NewTri.VIndex[2]=nCANum ;
2444                if(!AddTriangle(NewTri)) return 0 ;
2445
2446                // overwrite the original triangle with (C, CA, BC)
2447                NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[2] ;
2448                NewTri.VIndex[1]=nCANum ;
2449                NewTri.VIndex[2]=nBCNum ;
2450                m_pTriangle[ nTriangle ]=NewTri ;
2451        }
2452        else
2453        if(nABNum!=-1)
2454        {
2455                // add (AB, B, C)
2456                NewTri.VIndex[0]=nABNum ;
2457                NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[1] ;
2458                NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[2] ;
2459                if(!AddTriangle(NewTri)) return 0 ;
2460
2461                // overwrite the original triangle with (A, AB, C)
2462                NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[0] ;
2463                NewTri.VIndex[1]=nABNum ;
2464                NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[2] ;
2465                m_pTriangle[ nTriangle ]=NewTri ;
2466        }
2467        else
2468        if(nBCNum!=-1)
2469        {
2470                // add (BC, C, A)
2471                NewTri.VIndex[0]=nBCNum ;
2472                NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[2] ;
2473                NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[0] ;
2474                if(!AddTriangle(NewTri)) return 0 ;
2475
2476                // overwrite the original triangle with (B, BC, A)
2477                NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[1] ;
2478                NewTri.VIndex[1]=nBCNum ;
2479                NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[0] ;
2480                m_pTriangle[ nTriangle ]=NewTri ;
2481        }
2482        else
2483        if(nCANum!=-1)
2484        {
2485                // add (CA, A, B)
2486                NewTri.VIndex[0]=nCANum ;
2487                NewTri.VIndex[1]=m_pTriangle[ nTriangle ].VIndex[0] ;
2488                NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[1] ;
2489                if(!AddTriangle(NewTri)) return 0 ;
2490
2491                // overwrite the original triangle with (C, CA, B)
2492                NewTri.VIndex[0]=m_pTriangle[ nTriangle ].VIndex[2] ;
2493                NewTri.VIndex[1]=nCANum ;
2494                NewTri.VIndex[2]=m_pTriangle[ nTriangle ].VIndex[1] ;
2495                m_pTriangle[ nTriangle ]=NewTri ;
2496        }
2497
2498        return 1 ;
2499}
2500
2501void Q3Map::CreateTweenVert(Q3BspVertex* pVertA, Q3BspVertex* pVertB, float flPercent0, Q3BspVertex* pVertexAB)
2502{
2503        float flPercent1=1.0f-flPercent0 ;
2504
2505        pVertexAB->color[0]=(unsigned char)(flPercent0*pVertA->color[0] + flPercent1*pVertB->color[0]) ;
2506        pVertexAB->color[1]=(unsigned char)(flPercent0*pVertA->color[1] + flPercent1*pVertB->color[1]) ;
2507        pVertexAB->color[2]=(unsigned char)(flPercent0*pVertA->color[2] + flPercent1*pVertB->color[2]) ;
2508        pVertexAB->color[3]=(unsigned char)(flPercent0*pVertA->color[3] + flPercent1*pVertB->color[3]) ;
2509
2510        pVertexAB->position[0]=flPercent0*pVertA->position[0] + flPercent1*pVertB->position[0] ;
2511        pVertexAB->position[1]=flPercent0*pVertA->position[1] + flPercent1*pVertB->position[1] ;
2512        pVertexAB->position[2]=flPercent0*pVertA->position[2] + flPercent1*pVertB->position[2] ;
2513                               
2514        pVertexAB->texcoord[0][0]=flPercent0*pVertA->texcoord[0][0] + flPercent1*pVertB->texcoord[0][0] ;
2515        pVertexAB->texcoord[0][1]=flPercent0*pVertA->texcoord[0][1] + flPercent1*pVertB->texcoord[0][1] ;
2516        pVertexAB->texcoord[1][0]=flPercent0*pVertA->texcoord[1][0] + flPercent1*pVertB->texcoord[1][0] ;
2517        pVertexAB->texcoord[1][1]=flPercent0*pVertA->texcoord[1][1] + flPercent1*pVertB->texcoord[1][1] ;
2518
2519        pVertexAB->normal[0]=flPercent0*pVertA->normal[0] + flPercent1*pVertB->normal[0] ;
2520        pVertexAB->normal[1]=flPercent0*pVertA->normal[1] + flPercent1*pVertB->normal[1] ;
2521        pVertexAB->normal[2]=flPercent0*pVertA->normal[2] + flPercent1*pVertB->normal[2] ;
2522        // normalize
2523        float flLen=sqrt(pVertexAB->normal[0]*pVertexAB->normal[0] + pVertexAB->normal[1]*pVertexAB->normal[1] + pVertexAB->normal[2]*pVertexAB->normal[2]) ;
2524        if(flLen!=0.0f) // don't divide by zero... but normal is messed up.
2525        {
2526                pVertexAB->normal[0]/=flLen ;
2527                pVertexAB->normal[1]/=flLen ;
2528                pVertexAB->normal[2]/=flLen ;
2529        }
2530        else
2531        {
2532                // default a messed up normal to point upward
2533                pVertexAB->normal[0]=0.0f ;
2534                pVertexAB->normal[1]=1.0f ;
2535                pVertexAB->normal[2]=0.0f ;
2536        }
2537}
2538
2539// returns the next subzone a point is in after the start subzone, or -1 if there are no more subzones
2540int Q3Map::GetNextSubZone(float *flPoint, int nStart, int nMax)
2541{
2542        while(++nStart<nMax)
2543                if(PointInSubZone(flPoint, nStart))
2544                        break ;
2545
2546        if(nStart==nMax)
2547                return -1 ;
2548        else
2549                return nStart ;
2550}
2551
2552// returns true if a point is in a subzone.
2553bool Q3Map::PointInSubZone(float *flPoint, int nSubZone)
2554{
2555        if(
2556                                (flPoint[0]>=m_pSubZones[nSubZone].Min[0]-SUBZONE_EPSILON) && (flPoint[0]<=m_pSubZones[nSubZone].Max[0]+SUBZONE_EPSILON)
2557                        &&(flPoint[1]>=m_pSubZones[nSubZone].Min[1]-SUBZONE_EPSILON) && (flPoint[1]<=m_pSubZones[nSubZone].Max[1]+SUBZONE_EPSILON)
2558                        &&(flPoint[2]>=m_pSubZones[nSubZone].Min[2]-SUBZONE_EPSILON) && (flPoint[2]<=m_pSubZones[nSubZone].Max[2]+SUBZONE_EPSILON)
2559                )
2560                return true ;
2561
2562        return false ;
2563}
2564
2565// returns true if a point is in a zone.
2566bool Q3Map::PointInZone(float *flPos, int nZone)
2567{
2568        int nMaxSubZone=m_nZone[nZone][INDEX_SUBZONECOUNT] ;
2569
2570        for(int nSubZoneIndex=0 ; nSubZoneIndex<nMaxSubZone ; nSubZoneIndex++)
2571                if(PointInSubZone(flPos, m_nZone[nZone][nSubZoneIndex]))
2572                        return true ;
2573               
2574        return false ;
2575}
2576
2577// returns true if an axis aligned bounding box touches a subzone.
2578bool Q3Map::AABBTouchesSubZone(float *flPointMin, float *flPointMax, int nSubZone)
2579{
2580        // if test AABB overlaps the subzone AABB
2581        if(
2582                                 (m_pSubZones[nSubZone].Min[0]<flPointMax[0]) && (m_pSubZones[nSubZone].Max[0]>flPointMin[0])
2583                        && (m_pSubZones[nSubZone].Min[1]<flPointMax[1]) && (m_pSubZones[nSubZone].Max[1]>flPointMin[1])
2584                        && (m_pSubZones[nSubZone].Min[2]<flPointMax[2]) && (m_pSubZones[nSubZone].Max[2]>flPointMin[2])
2585                )
2586                return true ;
2587
2588        return false ;
2589}
2590
2591// returns true if an axis aligned bounding box touches a zone.
2592bool Q3Map::AABBTouchesZone(float *flPosMin, float *flPosMax, int nZone)
2593{
2594        int nMaxSubZone=m_nZone[nZone][INDEX_SUBZONECOUNT] ;
2595
2596        for(int nSubZoneIndex=0 ; nSubZoneIndex<nMaxSubZone ; nSubZoneIndex++)
2597                if(AABBTouchesSubZone(flPosMin, flPosMax, m_nZone[nZone][nSubZoneIndex]))
2598                        return true ;
2599               
2600        return false ;
2601}
2602
2603// take the faces from the BSP and add them to our list of triangles.
2604int Q3Map::ConvertFacesToTriangles(void)
2605{
2606        int nFaceIndex = 0 ;
2607       
2608//      int nVertex=0 ;
2609//      int nVertexMax=0 ;
2610        int nTriangle=0 ;
2611        int nTriangleMax=0 ;
2612
2613//      float flPosX=0.0f ;
2614//      float flPosY=0.0f ;
2615//      float flPosZ=0.0f ;
2616//      float   flNormX=0.0f ;
2617//      float   flNormY=0.0f ;
2618//      float   flNormZ=0.0f ;
2619//      float flTexU=0.0f ;
2620//      float flTexV=0.0f ;
2621        int nMeshVert=0 ;
2622//      int nMeshVertA=0 ;
2623//      int nMeshVertB=0 ;
2624//      int nMeshVertC=0 ;
2625
2626//      Q3BspVertex *vertices = m_pVertices ;
2627        int *meshverts = m_pMeshVerts ;
2628       
2629        QVECTOR junk ;
2630        junk[0]=0.0f ;
2631        junk[1]=0.0f ;
2632        junk[2]=0.0f ;
2633
2634
2635        nFaceIndex = 0 ;       
2636        while(nFaceIndex<m_iNumFaces)
2637        {
2638
2639                switch (m_BspFaces[nFaceIndex].type)
2640                {
2641                        case MESH:   
2642                        case POLYGON:   
2643
2644                                nTriangleMax=m_BspFaces[nFaceIndex].n_triangles ;
2645                                nMeshVert=m_BspFaces[nFaceIndex].meshvert ;
2646                               
2647                                for(nTriangle=0 ; nTriangle<nTriangleMax ; nTriangle++)
2648                                {
2649
2650                                        // if we are out of memory, grow it.  If we can't grow it, fail
2651                                        if(m_nTriangleMax>=m_nTriangleLimit)
2652                                                if(!ExpandTriangleMemory())
2653                                                        return 0 ;
2654
2655                                       
2656
2657                                        m_pTriangle[ m_nTriangleMax ].Texture=          m_BspFaces[nFaceIndex].texture ;
2658                                        //m_pTriangle[ m_nTriangleMax ].Lightmap=               m_BspFaces[nFaceIndex].lm_index ; // bzn doesn't use lightmaps
2659                                        m_pTriangle[ m_nTriangleMax ].VIndex[0]=        meshverts[ nMeshVert++ ]+m_BspFaces[nFaceIndex].vertex ;
2660                                        m_pTriangle[ m_nTriangleMax ].VIndex[1]=        meshverts[ nMeshVert++ ]+m_BspFaces[nFaceIndex].vertex ;
2661                                        m_pTriangle[ m_nTriangleMax ].VIndex[2]=        meshverts[ nMeshVert++ ]+m_BspFaces[nFaceIndex].vertex ;
2662
2663                                        m_pTriangle[ m_nTriangleMax ].Lamp=-1 ; // assume it didn't come from a lamp, this will be updated later
2664                                       
2665                                        m_pTriangle[ m_nTriangleMax ].Group=m_nGroup ; // increment group number. 
2666
2667                                        m_nTriangleMax++ ;
2668                                }// end for nTriangle
2669                                m_nGroup++ ; // increment group.  Every face is a new group.
2670                               
2671                        break ;
2672
2673                }// end switch
2674               
2675                nFaceIndex++;
2676        } // end while 
2677
2678        return 1 ;
2679
2680}
2681
2682
2683// convert the patch info from the BSP into bezier curved triangle meshes and add to our triangle list.
2684int Q3Map::ConvertPatchesToTriangles(void)
2685{
2686
2687//      float flPosX=0.0f ;
2688//      float flPosY=0.0f ;
2689//      float flPosZ=0.0f ;
2690//      float   flNormX=0.0f ;
2691//      float   flNormY=0.0f ;
2692//      float   flNormZ=0.0f ;
2693//      float flTexU=0.0f ;
2694//      float flTexV=0.0f ;
2695//      int nMeshVert=0 ;
2696        int nMeshVertA=0 ;
2697        int nMeshVertB=0 ;
2698        int nMeshVertC=0 ;
2699
2700
2701        int nTriPerRow=0 ;
2702        int nRow=0 ;
2703
2704        int nFirstVertex=m_nVertexMax ;
2705       
2706        int nVertCount=nFirstVertex ;
2707//      int nPatchCount=0 ;
2708
2709        int* pIndexBuffer=NULL ;
2710
2711        Q3BspVertex NewVert ;
2712               
2713
2714
2715
2716        int nCount=0 ;
2717        int nCountB=0 ;
2718
2719
2720
2721               
2722    int indexBufferindex = 0;
2723       
2724    int vertexBufferindex = 0;
2725
2726    for (int faceIndex=0; faceIndex < m_iNumFaces; faceIndex++)
2727    {           
2728
2729                        nCount++ ;
2730                        if(nCount==1)
2731                        {
2732                                nCountB+=nCount ;
2733                                nCount=0 ;
2734                        }
2735
2736
2737      if (m_BspFaces[faceIndex].type == PATCH)
2738      {
2739        Q3BspPatch *patch = m_BspFaces[faceIndex].patch;
2740
2741        if (patch != NULL)
2742        {
2743                                       
2744          for (int bezierIndex=0; bezierIndex < patch->size; bezierIndex++)
2745          {
2746                                                indexBufferindex = 0;
2747                                                pIndexBuffer = new int[patch->bezier[bezierIndex].mNumIndex] ;
2748                                                if(pIndexBuffer==NULL) return 0 ; // ran out of memory
2749
2750
2751            for (int index=0; index < patch->bezier[bezierIndex].mNumIndex; index++)
2752            {   
2753              pIndexBuffer[indexBufferindex] = patch->bezier[bezierIndex].mIndex[index];
2754              indexBufferindex++;
2755            }
2756
2757            for (int vertex=0; vertex < patch->bezier[bezierIndex].mNumVertex; vertex++)
2758            {
2759
2760              BspVertex *bspVertex = &patch->bezier[bezierIndex].mVertex[vertex];
2761
2762                                                        NewVert.position[0]=bspVertex->mPosition[0] ;
2763                                                        NewVert.position[1]=bspVertex->mPosition[1] ;
2764                                                        NewVert.position[2]=bspVertex->mPosition[2] ;
2765                                                        NewVert.normal[0]=bspVertex->mNormal[0] ;
2766                                                        NewVert.normal[1]=bspVertex->mNormal[1] ;
2767                                                        NewVert.normal[2]=bspVertex->mNormal[2] ;
2768                                                        NewVert.texcoord[0][0]=bspVertex->mTexcoord[0][0] ;
2769                                                        NewVert.texcoord[0][1]=bspVertex->mTexcoord[0][1] ;
2770
2771                                                       
2772
2773                                                        // if we are out of memory, grow it.  If we can't grow it, fail
2774                                                        if(m_nVertexMax>=m_nVertexLimit)
2775                                                                if(!ExpandVertexMemory())
2776                                                                {
2777                                                                        if(pIndexBuffer) DELETE_ARRAY( pIndexBuffer ) ;
2778                                                                        return 0 ;
2779                                                                }
2780
2781
2782                                                        if(!AddVertex(NewVert)) 
2783                                                        {
2784                                                                if(pIndexBuffer) DELETE_ARRAY( pIndexBuffer ) ;
2785                                                                return 0 ;
2786                                                        }
2787
2788                                                        nVertCount++ ;
2789              vertexBufferindex++;
2790
2791            }// end for vertex
2792
2793
2794                                                for (int j=0; j < 5; j++)
2795                                                {
2796                                                        nRow=m_BspFaces[faceIndex].patch->bezier[bezierIndex].mRowIndex[j] ;
2797                                                        nTriPerRow=m_BspFaces[faceIndex].patch->bezier[bezierIndex].mTrianglesPerRow[j] ;
2798
2799                                                        nMeshVertA=pIndexBuffer[nRow+0]+nFirstVertex ;
2800                                                        nMeshVertB=pIndexBuffer[nRow+1]+nFirstVertex ;
2801                                                       
2802                                                        for(int nVert=2 ; nVert<nTriPerRow ; nVert++)
2803                                                        {
2804                                                                // if we are out of memory, grow it.  If we can't grow it, fail
2805                                                                if(m_nTriangleMax>=m_nTriangleLimit)
2806                                                                        if(!ExpandTriangleMemory())
2807                                                                        {
2808                                                                                if(pIndexBuffer) DELETE_ARRAY( pIndexBuffer ) ;
2809                                                                                return 0 ;
2810                                                                        }
2811
2812                                                                m_pTriangle[ m_nTriangleMax ].Texture=          m_BspFaces[faceIndex].texture ;
2813                                                                //m_pTriangle[ m_nTriangleMax ].Lightmap=               m_BspFaces[faceIndex].lm_index ; // bzn doesn't use lightmaps
2814
2815                                                               
2816                                                               
2817                                                                nMeshVertC=pIndexBuffer[nRow+nVert]+nFirstVertex ;
2818
2819
2820                                                                if(nVert&1)
2821                                                                {
2822                                                                        m_pTriangle[ m_nTriangleMax ].VIndex[0]=        nMeshVertB ;
2823                                                                        m_pTriangle[ m_nTriangleMax ].VIndex[1]=        nMeshVertA ;
2824                                                                        m_pTriangle[ m_nTriangleMax ].VIndex[2]=        nMeshVertC ;
2825                                                                }
2826                                                                else
2827                                                                {
2828                                                                        m_pTriangle[ m_nTriangleMax ].VIndex[0]=        nMeshVertA ;
2829                                                                        m_pTriangle[ m_nTriangleMax ].VIndex[1]=        nMeshVertB ;
2830                                                                        m_pTriangle[ m_nTriangleMax ].VIndex[2]=        nMeshVertC ;
2831                                                                }
2832
2833                                                                m_pTriangle[ m_nTriangleMax ].Lamp=-1 ; // assume it didn't come from a lamp, this will be updated later
2834
2835
2836                                                                m_pTriangle[ m_nTriangleMax ].Group=m_nGroup ;
2837
2838
2839                                                                m_nTriangleMax++ ;
2840
2841                                                                nMeshVertA=nMeshVertB ;
2842                                                                nMeshVertB=nMeshVertC ;
2843                                                        }
2844                               
2845
2846                                                }
2847                                               
2848
2849                                                // finished with the index buffer
2850                                                if(pIndexBuffer) 
2851                                                        DELETE_ARRAY( pIndexBuffer ) ; 
2852
2853                                                nFirstVertex=nVertCount ;
2854          }// end for bezier index
2855
2856
2857                                        m_nGroup++ ; // increment the group number.  Each patch is treated as a single group.
2858
2859        }// end if patch not null
2860      }// end if patch
2861    }// end for faceIndex
2862
2863        return 1 ;
2864
2865}
2866
2867//''
2868// some triangles might be designed to be deferred shading shapes inside of Lamp entities.
2869// If so, change their material to the deferred shading configuration for that lamp entity.
2870int Q3Map::ConvertTexLampsToLampTriangles(void)
2871{
2872
2873        float flCentreX=0.0f ;
2874        float flCentreY=0.0f ;
2875        float flCentreZ=0.0f ;
2876
2877//      float flMinX=0.0f ;
2878//      float flMinY=0.0f ;
2879//      float flMinZ=0.0f ;
2880//      float flMaxX=0.0f ;
2881//      float flMaxY=0.0f ;
2882//      float flMaxZ=0.0f ;
2883
2884//      float   flNormX=0.0f ;
2885//      float   flNormY=0.0f ;
2886//      float   flNormZ=0.0f ;
2887//      float flTexU=0.0f ;
2888//      float flTexV=0.0f ;
2889
2890        float flColR=0.0f ;
2891        float flColG=0.0f ;
2892        float flColB=0.0f ;
2893
2894        float flBrightness=0.0f ;
2895
2896        int nLamp=0 ;
2897        int nTriangle=0 ;
2898        int nTexLampListPos=0 ;
2899        int nLightNode=0 ;
2900        int nTexture=0 ;
2901        int nZone=0 ;
2902//      int nLampZone=0 ;
2903//      int nMaxLampZone=0 ;
2904//      int nZoneMatch=0 ;
2905
2906
2907        for(nTexLampListPos=0 ; nTexLampListPos<m_nTexLampMax ; nTexLampListPos++)
2908        {
2909                nTriangle=m_pTexLamp[nTexLampListPos] ;
2910
2911                nZone=m_pTriangle[nTriangle].Zone ;
2912
2913                nTexture=m_pTriangle[nTriangle].Texture ;
2914
2915                if(nTexture==m_nBZN_LightNode0)
2916                        nLightNode=0 ;
2917                else
2918                if(nTexture==m_nBZN_LightNode1)
2919                        nLightNode=1 ;
2920                else
2921                if(nTexture==m_nBZN_LightNode2)
2922                        nLightNode=2 ;
2923                else
2924                if(nTexture==m_nBZN_LightNode3)
2925                        nLightNode=3 ;
2926                else
2927                        return 0 ; // didn't match any lightnode, something went wrong.
2928
2929
2930                // scan through all the lamps, finding the ones that touch the same zone as this triangle and that have the same lightnode number
2931                for(nLamp=0 ; nLamp<m_nLampMax ; nLamp++)
2932                {
2933                        // skip if the lightnode doesn't match
2934                        if(m_pLamp[nLamp].LightNode!=nLightNode)
2935                                continue ;
2936
2937
2938                        /*
2939                        // lightnode matches, check if lamp touches the same zone (lamps can touch multiple zones so we have to check them all)
2940                        nZoneMatch=0 ;
2941                        nMaxLampZone=m_pLamp[nLamp].Zone[MAX_ZONEPERLIGHT] ;
2942                        for(nLampZone=0 ; nLampZone<nMaxLampZone ; nLampZone++)
2943                        {
2944                                if(m_pLamp[nLamp].Zone[nLampZone]==nZone)
2945                                {
2946                                        nZoneMatch=1 ;
2947                                        break ;
2948                                }
2949                        }
2950                       
2951                       
2952                        // if the zone didn't match, continue
2953                        if(!nZoneMatch) continue ;
2954
2955                        */
2956
2957
2958
2959                        // check if all three vertices of this triangle fall within the bounds of this lamp
2960                        if(
2961                                                // first vert
2962                                                (m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[0]>=m_pLamp[nLamp].Min[0])
2963                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[0]<=m_pLamp[nLamp].Max[0])
2964                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[1]>=m_pLamp[nLamp].Min[1])
2965                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[1]<=m_pLamp[nLamp].Max[1])
2966                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[2]>=m_pLamp[nLamp].Min[2])
2967                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].position[2]<=m_pLamp[nLamp].Max[2]) 
2968                                        &&
2969                                                // second vert
2970                                                (m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[0]>=m_pLamp[nLamp].Min[0])
2971                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[0]<=m_pLamp[nLamp].Max[0])
2972                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[1]>=m_pLamp[nLamp].Min[1])
2973                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[1]<=m_pLamp[nLamp].Max[1])
2974                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[2]>=m_pLamp[nLamp].Min[2])
2975                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].position[2]<=m_pLamp[nLamp].Max[2]) 
2976                                        &&
2977                                                // third vert
2978                                                (m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[0]>=m_pLamp[nLamp].Min[0])
2979                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[0]<=m_pLamp[nLamp].Max[0])
2980                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[1]>=m_pLamp[nLamp].Min[1])
2981                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[1]<=m_pLamp[nLamp].Max[1])
2982                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[2]>=m_pLamp[nLamp].Min[2])
2983                                        &&(m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].position[2]<=m_pLamp[nLamp].Max[2]) 
2984       
2985                                        )
2986                        {
2987
2988
2989                                m_pTriangle[nTriangle].Texture=m_pLamp[nLamp].Texture ;
2990                                m_pTriangle[nTriangle].Lamp=nLamp ;
2991
2992                                flCentreX =             m_pLamp[nLamp].Position[0] ;
2993                                flCentreY =             m_pLamp[nLamp].Position[1] ;
2994                                flCentreZ =             m_pLamp[nLamp].Position[2] ;
2995                                flColR =                        m_pLamp[nLamp].Colour[0]*255.0f ;
2996                                flColG =                        m_pLamp[nLamp].Colour[1]*255.0f ;
2997                                flColB =                        m_pLamp[nLamp].Colour[2]*255.0f ;
2998                                flBrightness=   m_pLamp[nLamp].Brightness ; 
2999
3000                                m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].texcoord[0][0]=flCentreX ;
3001                                m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].texcoord[0][1]=flCentreY ;
3002                                m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].texcoord[1][0]=flCentreZ ;
3003                                m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].texcoord[1][1]=flBrightness ;
3004                                m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].color[0]=(unsigned char)flColR ;
3005                                m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].color[1]=(unsigned char)flColG ;
3006                                m_pVertex[  m_pTriangle[nTriangle].VIndex[0]  ].color[2]=(unsigned char)flColB ;
3007
3008                                m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].texcoord[0][0]=flCentreX ;
3009                                m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].texcoord[0][1]=flCentreY ;
3010                                m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].texcoord[1][0]=flCentreZ ;
3011                                m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].texcoord[1][1]=flBrightness ;
3012                                m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].color[0]=(unsigned char)flColR ;
3013                                m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].color[1]=(unsigned char)flColG ;
3014                                m_pVertex[  m_pTriangle[nTriangle].VIndex[1]  ].color[2]=(unsigned char)flColB ;
3015
3016                                m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].texcoord[0][0]=flCentreX ;
3017                                m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].texcoord[0][1]=flCentreY ;
3018                                m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].texcoord[1][0]=flCentreZ ;
3019                                m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].texcoord[1][1]=flBrightness ;
3020                                m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].color[0]=(unsigned char)flColR ;
3021                                m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].color[1]=(unsigned char)flColG ;
3022                                m_pVertex[  m_pTriangle[nTriangle].VIndex[2]  ].color[2]=(unsigned char)flColB ;
3023
3024                               
3025                                m_pTriangle[ m_nTriangleMax ].Group=m_nGroup ;
3026
3027
3028                        }// end triangle is in bounds of lamp
3029
3030
3031                        m_nGroup++ ; // increment group number.  Every texture lamp is a group.
3032
3033
3034                }// end for nLamp
3035
3036
3037        }
3038
3039
3040
3041        return 1 ;
3042}
3043
3044
3045// convert lamps into boxes.  Lamps are deferred shading non-shadowing lights, and are rendered as triangles
3046// The texture coords are actually the light centre point, the spot the shaders calculate as the source of the lighting,
3047// and also the brightness
3048// The triangles created will remember the lamp they came from, via Triangle.Lamp
3049
3050int Q3Map::ConvertLampsToTriangles(void)
3051{
3052        float flCentreX=0.0f ;
3053        float flCentreY=0.0f ;
3054        float flCentreZ=0.0f ;
3055
3056        float flMinX=0.0f ;
3057        float flMinY=0.0f ;
3058        float flMinZ=0.0f ;
3059        float flMaxX=0.0f ;
3060        float flMaxY=0.0f ;
3061        float flMaxZ=0.0f ;
3062
3063//      float   flNormX=0.0f ;
3064//      float   flNormY=0.0f ;
3065//      float   flNormZ=0.0f ;
3066//      float flTexU=0.0f ;
3067//      float flTexV=0.0f ;
3068
3069        float flColR=0.0f ;
3070        float flColG=0.0f ;
3071        float flColB=0.0f ;
3072
3073        float flBrightness=0.0f ;
3074
3075        int nLamp=0 ;
3076
3077        // lower case = min, upper case = max
3078        Q3BspVertex Vert_xyz ;
3079        Q3BspVertex Vert_Xyz ;
3080        Q3BspVertex Vert_xYz ;
3081        Q3BspVertex Vert_XYz ;
3082        Q3BspVertex Vert_xyZ ;
3083        Q3BspVertex Vert_XyZ ;
3084        Q3BspVertex Vert_xYZ ;
3085        Q3BspVertex Vert_XYZ ;
3086
3087        int n_xyz=0 ;
3088        int n_Xyz=0 ;
3089        int n_xYz=0 ;
3090        int n_XYz=0 ;
3091        int n_xyZ=0 ;
3092        int n_XyZ=0 ;
3093        int n_xYZ=0 ;
3094        int n_XYZ=0 ;
3095
3096        int nFirstVertex=0 ;
3097
3098        triangle_t Triangle ;
3099        ZeroMemory((void*)&Triangle, sizeof(triangle_t)) ;
3100       
3101        for(nLamp=0 ; nLamp<m_nLampMax ; nLamp++)
3102        {
3103                if(m_pLamp[nLamp].LightNode>-1) continue ; // lamps that are lightnodes don't add their own triangles.  They just exist as information for TexLamps.
3104
3105
3106                flCentreX =             m_pLamp[nLamp].Position[0] ;
3107                flCentreY =             m_pLamp[nLamp].Position[1] ;
3108                flCentreZ =             m_pLamp[nLamp].Position[2] ;
3109
3110                flMinX =                        m_pLamp[nLamp].Min[0] ;
3111                flMinY =                        m_pLamp[nLamp].Min[1] ;
3112                flMinZ =                        m_pLamp[nLamp].Min[2] ;
3113
3114                flMaxX =                        m_pLamp[nLamp].Max[0] ;
3115                flMaxY =                        m_pLamp[nLamp].Max[1] ;
3116                flMaxZ =                        m_pLamp[nLamp].Max[2] ;
3117
3118                flColR =                        m_pLamp[nLamp].Colour[0]*255.0f ;
3119                flColG =                        m_pLamp[nLamp].Colour[1]*255.0f ;
3120                flColB =                        m_pLamp[nLamp].Colour[2]*255.0f ;
3121               
3122                flBrightness=   m_pLamp[nLamp].Brightness ; 
3123               
3124                //////////////////////////////////////
3125                // setup our 8 vertices.  Normal isn't that important, I just approximate regardless of actual box shape
3126
3127
3128                nFirstVertex=m_nVertexMax ; // we need to remember which vertex is which for defining the triangles
3129
3130                // vertex numbers
3131                n_xyz=nFirstVertex+0 ;
3132                n_Xyz=nFirstVertex+1 ;
3133                n_xYz=nFirstVertex+2 ;
3134                n_XYz=nFirstVertex+3 ;
3135                n_xyZ=nFirstVertex+4 ;
3136                n_XyZ=nFirstVertex+5 ;
3137                n_xYZ=nFirstVertex+6 ;
3138                n_XYZ=nFirstVertex+7 ;
3139
3140
3141                Vert_xyz.position[0]=flMinX ;
3142                Vert_xyz.position[1]=flMinY ;
3143                Vert_xyz.position[2]=flMinZ ;
3144                Vert_xyz.normal[0]=-0.5773502691896 ;
3145                Vert_xyz.normal[1]=-0.5773502691896 ;
3146                Vert_xyz.normal[2]=-0.5773502691896 ;
3147                Vert_xyz.texcoord[0][0]=flCentreX ;
3148                Vert_xyz.texcoord[0][1]=flCentreY ;
3149                Vert_xyz.texcoord[1][0]=flCentreZ ;
3150                Vert_xyz.texcoord[1][1]=flBrightness ;
3151                Vert_xyz.color[0]=(unsigned char)flColR ;
3152                Vert_xyz.color[1]=(unsigned char)flColG ;
3153                Vert_xyz.color[2]=(unsigned char)flColB ;
3154                if(!AddVertex(Vert_xyz)) return 0 ;
3155                       
3156
3157                Vert_Xyz.position[0]=flMaxX ;
3158                Vert_Xyz.position[1]=flMinY ;
3159                Vert_Xyz.position[2]=flMinZ ;
3160                Vert_Xyz.normal[0]= 0.5773502691896 ;
3161                Vert_Xyz.normal[1]=-0.5773502691896 ;
3162                Vert_Xyz.normal[2]=-0.5773502691896 ;
3163                Vert_Xyz.texcoord[0][0]=flCentreX ;
3164                Vert_Xyz.texcoord[0][1]=flCentreY ;
3165                Vert_Xyz.texcoord[1][0]=flCentreZ ;
3166                Vert_Xyz.texcoord[1][1]=flBrightness ;
3167                Vert_Xyz.color[0]=(unsigned char)flColR ;
3168                Vert_Xyz.color[1]=(unsigned char)flColG ;
3169                Vert_Xyz.color[2]=(unsigned char)flColB ;
3170                if(!AddVertex(Vert_Xyz)) return 0 ;
3171
3172                Vert_xYz.position[0]=flMinX ;
3173                Vert_xYz.position[1]=flMaxY ;
3174                Vert_xYz.position[2]=flMinZ ;
3175                Vert_xYz.normal[0]=-0.5773502691896 ;
3176                Vert_xYz.normal[1]= 0.5773502691896 ;
3177                Vert_xYz.normal[2]=-0.5773502691896 ;
3178                Vert_xYz.texcoord[0][0]=flCentreX ;
3179                Vert_xYz.texcoord[0][1]=flCentreY ;
3180                Vert_xYz.texcoord[1][0]=flCentreZ ;
3181                Vert_xYz.texcoord[1][1]=flBrightness ;
3182                Vert_xYz.color[0]=(unsigned char)flColR ;
3183                Vert_xYz.color[1]=(unsigned char)flColG ;
3184                Vert_xYz.color[2]=(unsigned char)flColB ;
3185                if(!AddVertex(Vert_xYz)) return 0 ;
3186
3187                Vert_XYz.position[0]=flMaxX ;
3188                Vert_XYz.position[1]=flMaxY ;
3189                Vert_XYz.position[2]=flMinZ ;
3190                Vert_XYz.normal[0]= 0.5773502691896 ;
3191                Vert_XYz.normal[1]= 0.5773502691896 ;
3192                Vert_XYz.normal[2]=-0.5773502691896 ;
3193                Vert_XYz.texcoord[0][0]=flCentreX ;
3194                Vert_XYz.texcoord[0][1]=flCentreY ;
3195                Vert_XYz.texcoord[1][0]=flCentreZ ;
3196                Vert_XYz.texcoord[1][1]=flBrightness ;
3197                Vert_XYz.color[0]=(unsigned char)flColR ;
3198                Vert_XYz.color[1]=(unsigned char)flColG ;
3199                Vert_XYz.color[2]=(unsigned char)flColB ;
3200                if(!AddVertex(Vert_XYz)) return 0 ;
3201
3202                //////////////////////////////////////
3203
3204                Vert_xyZ.position[0]=flMinX ;
3205                Vert_xyZ.position[1]=flMinY ;
3206                Vert_xyZ.position[2]=flMaxZ ;
3207                Vert_xyZ.normal[0]=-0.5773502691896 ;
3208                Vert_xyZ.normal[1]=-0.5773502691896 ;
3209                Vert_xyZ.normal[2]= 0.5773502691896 ;
3210                Vert_xyZ.texcoord[0][0]=flCentreX ;
3211                Vert_xyZ.texcoord[0][1]=flCentreY ;
3212                Vert_xyZ.texcoord[1][0]=flCentreZ ;
3213                Vert_xyZ.texcoord[1][1]=flBrightness ;
3214                Vert_xyZ.color[0]=(unsigned char)flColR ;
3215                Vert_xyZ.color[1]=(unsigned char)flColG ;
3216                Vert_xyZ.color[2]=(unsigned char)flColB ;
3217                if(!AddVertex(Vert_xyZ)) return 0 ;
3218
3219                Vert_XyZ.position[0]=flMaxX ;
3220                Vert_XyZ.position[1]=flMinY ;
3221                Vert_XyZ.position[2]=flMaxZ ;
3222                Vert_XyZ.normal[0]= 0.5773502691896 ;
3223                Vert_XyZ.normal[1]=-0.5773502691896 ;
3224                Vert_XyZ.normal[2]= 0.5773502691896 ;
3225                Vert_XyZ.texcoord[0][0]=flCentreX ;
3226                Vert_XyZ.texcoord[0][1]=flCentreY ;
3227                Vert_XyZ.texcoord[1][0]=flCentreZ ;
3228                Vert_XyZ.texcoord[1][1]=flBrightness ;
3229                Vert_XyZ.color[0]=(unsigned char)flColR ;
3230                Vert_XyZ.color[1]=(unsigned char)flColG ;
3231                Vert_XyZ.color[2]=(unsigned char)flColB ;
3232                if(!AddVertex(Vert_XyZ)) return 0 ;
3233
3234                Vert_xYZ.position[0]=flMinX ;
3235                Vert_xYZ.position[1]=flMaxY ;
3236                Vert_xYZ.position[2]=flMaxZ ;
3237                Vert_xYZ.normal[0]=-0.5773502691896 ;
3238                Vert_xYZ.normal[1]= 0.5773502691896 ;
3239                Vert_xYZ.normal[2]= 0.5773502691896 ;
3240                Vert_xYZ.texcoord[0][0]=flCentreX ;
3241                Vert_xYZ.texcoord[0][1]=flCentreY ;
3242                Vert_xYZ.texcoord[1][0]=flCentreZ ;
3243                Vert_xYZ.texcoord[1][1]=flBrightness ;
3244                Vert_xYZ.color[0]=(unsigned char)flColR ;
3245                Vert_xYZ.color[1]=(unsigned char)flColG ;
3246                Vert_xYZ.color[2]=(unsigned char)flColB ;
3247                if(!AddVertex(Vert_xYZ)) return 0 ;
3248
3249                Vert_XYZ.position[0]=flMaxX ;
3250                Vert_XYZ.position[1]=flMaxY ;
3251                Vert_XYZ.position[2]=flMaxZ ;
3252                Vert_XYZ.normal[0]= 0.5773502691896 ;
3253                Vert_XYZ.normal[1]= 0.5773502691896 ;
3254                Vert_XYZ.normal[2]= 0.5773502691896 ;
3255                Vert_XYZ.texcoord[0][0]=flCentreX ;
3256                Vert_XYZ.texcoord[0][1]=flCentreY ;
3257                Vert_XYZ.texcoord[1][0]=flCentreZ ;
3258                Vert_XYZ.texcoord[1][1]=flBrightness ;
3259                Vert_XYZ.color[0]=(unsigned char)flColR ;
3260                Vert_XYZ.color[1]=(unsigned char)flColG ;
3261                Vert_XYZ.color[2]=(unsigned char)flColB ;
3262                if(!AddVertex(Vert_XYZ)) return 0 ;
3263
3264                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3265
3266                Triangle.Texture=m_pLamp[nLamp].Texture ;
3267                Triangle.Lamp=nLamp ;
3268                Triangle.Group=m_nGroup ;
3269
3270                /////////////////////////////////////
3271
3272                Triangle.VIndex[2]=n_xyz ;
3273                Triangle.VIndex[1]=n_xyZ ;
3274                Triangle.VIndex[0]=n_xYZ ;
3275                if(!AddTriangle(Triangle)) return 0 ;
3276
3277                Triangle.VIndex[2]=n_xYZ ;
3278                Triangle.VIndex[1]=n_xYz ;
3279                Triangle.VIndex[0]=n_xyz ;
3280                if(!AddTriangle(Triangle)) return 0 ;
3281       
3282                /////////////////////////////////////
3283
3284                Triangle.VIndex[0]=n_Xyz ;
3285                Triangle.VIndex[1]=n_XyZ ;
3286                Triangle.VIndex[2]=n_XYZ ;
3287                if(!AddTriangle(Triangle)) return 0 ;
3288
3289                Triangle.VIndex[0]=n_XYZ ;
3290                Triangle.VIndex[1]=n_XYz ;
3291                Triangle.VIndex[2]=n_Xyz ;
3292                if(!AddTriangle(Triangle)) return 0 ;
3293
3294                /////////////////////////////////////
3295
3296                Triangle.VIndex[2]=n_xyz ;
3297                Triangle.VIndex[1]=n_xYz ;
3298                Triangle.VIndex[0]=n_XYz ;
3299                if(!AddTriangle(Triangle)) return 0 ;
3300
3301                Triangle.VIndex[2]=n_XYz ;
3302                Triangle.VIndex[1]=n_Xyz ;
3303                Triangle.VIndex[0]=n_xyz ;
3304                if(!AddTriangle(Triangle)) return 0 ;
3305       
3306                /////////////////////////////////////
3307
3308                Triangle.VIndex[0]=n_xyZ ;
3309                Triangle.VIndex[1]=n_xYZ ;
3310                Triangle.VIndex[2]=n_XYZ ;
3311                if(!AddTriangle(Triangle)) return 0 ;
3312
3313                Triangle.VIndex[0]=n_XYZ ;
3314                Triangle.VIndex[1]=n_XyZ ;
3315                Triangle.VIndex[2]=n_xyZ ;
3316                if(!AddTriangle(Triangle)) return 0 ;
3317       
3318                /////////////////////////////////////
3319
3320                Triangle.VIndex[0]=n_xyz ;
3321                Triangle.VIndex[1]=n_xyZ ;
3322                Triangle.VIndex[2]=n_XyZ ;
3323                if(!AddTriangle(Triangle)) return 0 ;
3324
3325                Triangle.VIndex[0]=n_XyZ ;
3326                Triangle.VIndex[1]=n_Xyz ;
3327                Triangle.VIndex[2]=n_xyz ;
3328                if(!AddTriangle(Triangle)) return 0 ;
3329
3330                /////////////////////////////////////
3331
3332                Triangle.VIndex[2]=n_xYz ;
3333                Triangle.VIndex[1]=n_xYZ ;
3334                Triangle.VIndex[0]=n_XYZ ;
3335                if(!AddTriangle(Triangle)) return 0 ;
3336
3337                Triangle.VIndex[2]=n_XYZ ;
3338                Triangle.VIndex[1]=n_XYz ;
3339                Triangle.VIndex[0]=n_xYz ;
3340                if(!AddTriangle(Triangle)) return 0 ;
3341       
3342                m_nGroup++ ; // increment group once for every lamp
3343        }
3344       
3345
3346
3347        return 1 ;
3348}
3349
3350
3351int Q3Map::ConvertLampsToGlowTriangles(void)
3352{
3353        float flCentreX=0.0f ;
3354        float flCentreY=0.0f ;
3355        float flCentreZ=0.0f ;
3356
3357        float flMinX=0.0f ;
3358        float flMinY=0.0f ;
3359        float flMinZ=0.0f ;
3360        float flMaxX=0.0f ;
3361        float flMaxY=0.0f ;
3362        float flMaxZ=0.0f ;
3363
3364//      float   flNormX=0.0f ;
3365//      float   flNormY=0.0f ;
3366//      float   flNormZ=0.0f ;
3367//      float flTexU=0.0f ;
3368//      float flTexV=0.0f ;
3369
3370        float flColR=0.0f ;
3371        float flColG=0.0f ;
3372        float flColB=0.0f ;
3373
3374        float flBrightness=0.0f ;
3375
3376        int nLamp=0 ;
3377
3378
3379        Q3BspVertex Vert_L ;
3380        Q3BspVertex Vert_R ;
3381        Q3BspVertex Vert_F ;
3382        Q3BspVertex Vert_B ;
3383        Q3BspVertex Vert_U ;
3384        Q3BspVertex Vert_D ;
3385
3386
3387        int n_L=0 ;
3388        int n_R=0 ;
3389        int n_F=0 ;
3390        int n_B=0 ;
3391        int n_U=0 ;
3392        int n_D=0 ;
3393       
3394        int nFirstVertex=0 ;
3395
3396        float flBaseGlowSize=0.15f ;//0.2f;//0.001f ;
3397        float flGlowSize=0.0f ;
3398
3399
3400
3401        triangle_t Triangle ;
3402        ZeroMemory((void*)&Triangle, sizeof(triangle_t)) ;
3403       
3404        for(nLamp=0 ; nLamp<m_nLampMax ; nLamp++)
3405        {
3406
3407                flGlowSize=flBaseGlowSize*m_pLamp[nLamp].Brightness ;
3408
3409                flCentreX =             m_pLamp[nLamp].Position[0] ;
3410                flCentreY =             m_pLamp[nLamp].Position[1] ;
3411                flCentreZ =             m_pLamp[nLamp].Position[2] ;
3412
3413                flMinX =                        flCentreX-flGlowSize ;
3414                flMinY =                        flCentreY-flGlowSize ;
3415                flMinZ =                        flCentreZ-flGlowSize ;
3416
3417                flMaxX =                        flCentreX+flGlowSize ;
3418                flMaxY =                        flCentreY+flGlowSize ;
3419                flMaxZ =                        flCentreZ+flGlowSize ;
3420
3421                flColR =                        m_pLamp[nLamp].Colour[0]*255.0f ;
3422                flColG =                        m_pLamp[nLamp].Colour[1]*255.0f ;
3423                flColB =                        m_pLamp[nLamp].Colour[2]*255.0f ;
3424               
3425                flBrightness=   m_pLamp[nLamp].Brightness*4.0f ; 
3426               
3427                //////////////////////////////////////
3428                // setup our 8 vertices.  Normal isn't that important, I just approximate regardless of actual box shape
3429
3430
3431                nFirstVertex=m_nVertexMax ; // we need to remember which vertex is which for defining the triangles
3432
3433                // vertex numbers
3434                n_L=nFirstVertex+0 ;
3435                n_R=nFirstVertex+1 ;
3436                n_F=nFirstVertex+2 ;
3437                n_B=nFirstVertex+3 ;
3438                n_U=nFirstVertex+4 ;
3439                n_D=nFirstVertex+5 ;
3440
3441
3442
3443                Vert_L.position[0]=flMinX ;
3444                Vert_L.position[1]=flCentreY ;
3445                Vert_L.position[2]=flCentreZ ;
3446                Vert_L.normal[0]=-1.0 ;
3447                Vert_L.normal[1]=0.0 ;
3448                Vert_L.normal[2]=0.0 ;
3449                Vert_L.texcoord[0][0]=flCentreX ;
3450                Vert_L.texcoord[0][1]=flCentreY ;
3451                Vert_L.texcoord[1][0]=flCentreZ ;
3452                Vert_L.texcoord[1][1]=flBrightness ;
3453                Vert_L.color[0]=(unsigned char)flColR ;
3454                Vert_L.color[1]=(unsigned char)flColG ;
3455                Vert_L.color[2]=(unsigned char)flColB ;
3456                if(!AddVertex(Vert_L)) return 0 ;
3457
3458                Vert_R.position[0]=flMaxX ;
3459                Vert_R.position[1]=flCentreY ;
3460                Vert_R.position[2]=flCentreZ ;
3461                Vert_R.normal[0]=1.0 ;
3462                Vert_R.normal[1]=0.0 ;
3463                Vert_R.normal[2]=0.0 ;
3464                Vert_R.texcoord[0][0]=flCentreX ;
3465                Vert_R.texcoord[0][1]=flCentreY ;
3466                Vert_R.texcoord[1][0]=flCentreZ ;
3467                Vert_R.texcoord[1][1]=flBrightness ;
3468                Vert_R.color[0]=(unsigned char)flColR ;
3469                Vert_R.color[1]=(unsigned char)flColG ;
3470                Vert_R.color[2]=(unsigned char)flColB ;
3471                if(!AddVertex(Vert_R)) return 0 ;
3472
3473                Vert_F.position[0]=flCentreX ;
3474                Vert_F.position[1]=flCentreY ;
3475                Vert_F.position[2]=flMinZ ;
3476                Vert_F.normal[0]=0.0 ;
3477                Vert_F.normal[1]=0.0 ;
3478                Vert_F.normal[2]=-1.0 ;
3479                Vert_F.texcoord[0][0]=flCentreX ;
3480                Vert_F.texcoord[0][1]=flCentreY ;
3481                Vert_F.texcoord[1][0]=flCentreZ ;
3482                Vert_F.texcoord[1][1]=flBrightness ;
3483                Vert_F.color[0]=(unsigned char)flColR ;
3484                Vert_F.color[1]=(unsigned char)flColG ;
3485                Vert_F.color[2]=(unsigned char)flColB ;
3486                if(!AddVertex(Vert_F)) return 0 ;
3487               
3488                Vert_B.position[0]=flCentreX ;
3489                Vert_B.position[1]=flCentreY ;
3490                Vert_B.position[2]=flMaxZ ;
3491                Vert_B.normal[0]=0.0 ;
3492                Vert_B.normal[1]=0.0 ;
3493                Vert_B.normal[2]=1.0 ;
3494                Vert_B.texcoord[0][0]=flCentreX ;
3495                Vert_B.texcoord[0][1]=flCentreY ;
3496                Vert_B.texcoord[1][0]=flCentreZ ;
3497                Vert_B.texcoord[1][1]=flBrightness ;
3498                Vert_B.color[0]=(unsigned char)flColR ;
3499                Vert_B.color[1]=(unsigned char)flColG ;
3500                Vert_B.color[2]=(unsigned char)flColB ;
3501                if(!AddVertex(Vert_B)) return 0 ;
3502
3503                Vert_U.position[0]=flCentreX ;
3504                Vert_U.position[1]=flMaxY ;
3505                Vert_U.position[2]=flCentreZ ;
3506                Vert_U.normal[0]=0.0 ;
3507                Vert_U.normal[1]=1.0 ;
3508                Vert_U.normal[2]=0.0 ;
3509                Vert_U.texcoord[0][0]=flCentreX ;
3510                Vert_U.texcoord[0][1]=flCentreY ;
3511                Vert_U.texcoord[1][0]=flCentreZ ;
3512                Vert_U.texcoord[1][1]=flBrightness ;
3513                Vert_U.color[0]=(unsigned char)flColR ;
3514                Vert_U.color[1]=(unsigned char)flColG ;
3515                Vert_U.color[2]=(unsigned char)flColB ;
3516                if(!AddVertex(Vert_U)) return 0 ;
3517
3518                Vert_D.position[0]=flCentreX ;
3519                Vert_D.position[1]=flMinY ;
3520                Vert_D.position[2]=flCentreZ ;
3521                Vert_D.normal[0]=0.0 ;
3522                Vert_D.normal[1]=-1.0 ;
3523                Vert_D.normal[2]=0.0 ;
3524                Vert_D.texcoord[0][0]=flCentreX ;
3525                Vert_D.texcoord[0][1]=flCentreY ;
3526                Vert_D.texcoord[1][0]=flCentreZ ;
3527                Vert_D.texcoord[1][1]=flBrightness ;
3528                Vert_D.color[0]=(unsigned char)flColR ;
3529                Vert_D.color[1]=(unsigned char)flColG ;
3530                Vert_D.color[2]=(unsigned char)flColB ;
3531                if(!AddVertex(Vert_D)) return 0 ;
3532
3533                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3534
3535                Triangle.Texture=m_nDefaultTextureIndexGlowLamp ;
3536                Triangle.Lamp=-1 ;
3537                Triangle.Group=m_nGroup ;
3538
3539                /////////////////////////////////////
3540
3541                Triangle.VIndex[0]=n_U ;
3542                Triangle.VIndex[1]=n_L ;
3543                Triangle.VIndex[2]=n_F ;
3544                if(!AddTriangle(Triangle)) return 0 ;
3545
3546                Triangle.VIndex[0]=n_U ;
3547                Triangle.VIndex[1]=n_F ;
3548                Triangle.VIndex[2]=n_R ;
3549                if(!AddTriangle(Triangle)) return 0 ;
3550       
3551                Triangle.VIndex[0]=n_U ;
3552                Triangle.VIndex[1]=n_R ;
3553                Triangle.VIndex[2]=n_B ;
3554                if(!AddTriangle(Triangle)) return 0 ;
3555
3556                Triangle.VIndex[0]=n_U ;
3557                Triangle.VIndex[1]=n_B ;
3558                Triangle.VIndex[2]=n_L ;
3559                if(!AddTriangle(Triangle)) return 0 ;
3560
3561                //////////////////////////////////////
3562
3563                Triangle.VIndex[2]=n_D ;
3564                Triangle.VIndex[1]=n_L ;
3565                Triangle.VIndex[0]=n_F ;
3566                if(!AddTriangle(Triangle)) return 0 ;
3567
3568                Triangle.VIndex[2]=n_D ;
3569                Triangle.VIndex[1]=n_F ;
3570                Triangle.VIndex[0]=n_R ;
3571                if(!AddTriangle(Triangle)) return 0 ;
3572       
3573                Triangle.VIndex[2]=n_D ;
3574                Triangle.VIndex[1]=n_R ;
3575                Triangle.VIndex[0]=n_B ;
3576                if(!AddTriangle(Triangle)) return 0 ;
3577
3578                Triangle.VIndex[2]=n_D ;
3579                Triangle.VIndex[1]=n_B ;
3580                Triangle.VIndex[0]=n_L ;
3581                if(!AddTriangle(Triangle)) return 0 ;
3582
3583                m_nGroup++ ; // increment group once for each glow
3584               
3585        }
3586       
3587
3588
3589        return 1 ;
3590}
3591
3592/////////////////////////////////////////////////////////////////////////////////////////////////////
3593
3594
3595int Q3Map::ConvertLightsToGlowTriangles(void)
3596{
3597        float flCentreX=0.0f ;
3598        float flCentreY=0.0f ;
3599        float flCentreZ=0.0f ;
3600
3601        float flMinX=0.0f ;
3602        float flMinY=0.0f ;
3603        float flMinZ=0.0f ;
3604        float flMaxX=0.0f ;
3605        float flMaxY=0.0f ;
3606        float flMaxZ=0.0f ;
3607
3608//      float   flNormX=0.0f ;
3609//      float   flNormY=0.0f ;
3610//      float   flNormZ=0.0f ;
3611//      float flTexU=0.0f ;
3612//      float flTexV=0.0f ;
3613
3614        float flColR=0.0f ;
3615        float flColG=0.0f ;
3616        float flColB=0.0f ;
3617
3618        float flBrightness=0.0f ;
3619
3620        int nLight=0 ;
3621
3622        Q3BspVertex Vert_Or ;
3623        Q3BspVertex Vert_A0 ;
3624        Q3BspVertex Vert_A1 ;
3625        Q3BspVertex Vert_B0 ;
3626        Q3BspVertex Vert_B1 ;
3627
3628
3629        int n_Or=0 ;
3630        int n_A0=0 ;
3631        int n_A1=0 ;
3632        int n_B0=0 ;
3633        int n_B1=0 ;
3634       
3635        int nFirstVertex=0 ;
3636
3637        float flBaseGlowSize=0.2f ;//0.001f ;
3638        float flGlowSize=0.0f ;
3639
3640//      char chMessage[1024] ;
3641
3642
3643
3644        triangle_t Triangle ;
3645        ZeroMemory((void*)&Triangle, sizeof(triangle_t)) ;
3646       
3647        for(nLight=0 ; nLight<m_nLightMax ; nLight++)
3648        //for(nLight=0 ; nLight<1 ; nLight++)
3649        {
3650                //if(m_pLight[nLight].LightNode>-1) continue ; // Lights that are lightnodes don't add their own triangles.  They just exist as information for TexLights.
3651
3652                flGlowSize=flBaseGlowSize*m_pLight[nLight].Brightness ;
3653
3654                flCentreX =             m_pLight[nLight].Position[0] ;
3655                flCentreY =             m_pLight[nLight].Position[1] ;
3656                flCentreZ =             m_pLight[nLight].Position[2] ;
3657
3658                flMinX =                        flCentreX-flGlowSize ;
3659                flMinY =                        flCentreY-flGlowSize ;
3660                flMinZ =                        flCentreZ-flGlowSize ;
3661
3662                flMaxX =                        flCentreX+flGlowSize ;
3663                flMaxY =                        flCentreY+flGlowSize ;
3664                flMaxZ =                        flCentreZ+flGlowSize ;
3665
3666                flColR =                        m_pLight[nLight].Colour[0]*255.0f ;
3667                flColG =                        m_pLight[nLight].Colour[1]*255.0f ;
3668                flColB =                        m_pLight[nLight].Colour[2]*255.0f ;
3669               
3670                flBrightness=   m_pLight[nLight].Brightness * 0.75 ;//*2.0 ;
3671               
3672                //////////////////////////////////////
3673                // setup our 5 vertices.
3674
3675
3676                nFirstVertex=m_nVertexMax ; // we need to remember which vertex is which for defining the triangles
3677
3678                // vertex numbers
3679                n_Or=nFirstVertex+0 ;
3680                n_A0=nFirstVertex+1 ;
3681                n_A1=nFirstVertex+2 ;
3682                n_B0=nFirstVertex+3 ;
3683                n_B1=nFirstVertex+4 ;
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3701
3702
3703               
3704       
3705        float flHALFPI =        1.5707963 ;
3706        float flTWOPI =         6.2831853 ;
3707        float flPI =                    3.1415926 ;
3708        float flAngle=(m_pLight[nLight].Angle/360.0f*flTWOPI)/2.0 ;
3709        float flCutoff=32.0f ;//m_pLight[nLight].Brightness ;
3710       
3711        Q3BspVertex color ;
3712
3713        Q3BspVertex NormalVert ;
3714        SetVertex(&NormalVert, m_pLight[nLight].Direction[0], m_pLight[nLight].Direction[1], m_pLight[nLight].Direction[2]) ;
3715        NormalVert=GetNormalised(&NormalVert) ;
3716
3717        Q3BspVertex normal ;
3718        SetVertex(&normal, m_pLight[nLight].Direction[0]*flCutoff, m_pLight[nLight].Direction[1]*flCutoff, m_pLight[nLight].Direction[2]*flCutoff) ;
3719
3720        Q3BspVertex adjust=normal ;
3721        VertexScale(&adjust, 0.5) ;
3722
3723        Q3BspVertex start ;             SetVertex(&start, flCentreX, flCentreY, flCentreZ) ;
3724        Q3BspVertex end ;                       SetVertex(&end, flCentreX+normal.position[0], flCentreY+normal.position[1], flCentreZ+normal.position[2]) ;
3725
3726        Q3BspVertex xaxis ; SetVertex(&xaxis, 1,0,0) ;
3727        Q3BspVertex xaxisneg ; SetVertex(&xaxisneg, -1,0,0) ;
3728        Q3BspVertex yaxis ; SetVertex(&yaxis, 0,1,0) ;
3729        Q3BspVertex Origin ; SetVertex(&Origin, 0,0,0) ;
3730        Q3BspVertex tangentA ;
3731        Q3BspVertex tangentB ;
3732        Q3BspVertex tangentStart ;
3733        Q3BspVertex tangentEnd ;
3734        Q3BspVertex tangentEndA0 ;
3735        Q3BspVertex tangentEndA1 ;
3736        Q3BspVertex tangentEndB0 ;
3737        Q3BspVertex tangentEndB1 ;
3738
3739        Q3BspVertex tangentANorm ;
3740        Q3BspVertex tangentBNorm ;
3741
3742        Q3BspVertex raytangent ;
3743
3744        Q3BspVertex ray ;
3745        float theta=0.0f ;
3746        float adjacent=0.0f ;
3747        SetVertex(&color, 0.66, 0.66, 0.66) ;
3748
3749        if(flAngle<0.0001) return 0 ;
3750
3751        if(flAngle>flPI-0.01) // near on 180 degrees
3752                flAngle=flPI-0.01 ;
3753
3754
3755        Q3BspVertex backshift ;
3756        backshift=normal ;
3757        VertexScale(&backshift, 0.95) ;
3758       
3759
3760        if( !VectorsAreEqual(&NormalVert, &xaxis) && !VectorsAreEqual(&NormalVert, &xaxisneg) )
3761                tangentA=NormalizedCrossProduct(Origin, normal, xaxis) ;
3762        else
3763                tangentA=NormalizedCrossProduct(Origin, normal, yaxis) ;
3764       
3765        tangentB=NormalizedCrossProduct(Origin, normal, tangentA) ;
3766
3767        tangentANorm=tangentA ;
3768        tangentBNorm=tangentB ;
3769
3770
3771       
3772        theta=flHALFPI-flAngle ; // angle between adjacent and hypotenuse (the normal is the "opposite" side, and we know there's a right angle)
3773        adjacent=VertexDistance(&Origin, &normal)/tan(theta) ; 
3774
3775        //////////////////////////////////////////////////////////////////////
3776       
3777        Vert_Or.position[0]=end.position[0]-backshift.position[0] ;
3778        Vert_Or.position[1]=end.position[1]-backshift.position[1] ;
3779        Vert_Or.position[2]=end.position[2]-backshift.position[2] ;
3780        Vert_Or.normal[0]= NormalVert.position[0] ;
3781        Vert_Or.normal[1]= NormalVert.position[1] ;
3782        Vert_Or.normal[2]= NormalVert.position[2] ;
3783        Vert_Or.texcoord[0][0]=flCentreX ;
3784        Vert_Or.texcoord[0][1]=flCentreY ;
3785        Vert_Or.texcoord[1][0]=flCentreZ ;
3786        Vert_Or.texcoord[1][1]=flBrightness ;
3787        Vert_Or.color[0]=(unsigned char)flColR ;
3788        Vert_Or.color[1]=(unsigned char)flColG ;
3789        Vert_Or.color[2]=(unsigned char)flColB ;
3790        if(!AddVertex(Vert_Or)) return 0 ;
3791
3792
3793
3794
3795        //////////////////////////////////////////////////////////////////////
3796
3797        flColR=0.0f ;
3798        flColG=0.0f ;
3799        flColB=0.0f ;
3800
3801        tangentA=GetNormalised(&tangentA) ;
3802        VertexScale(&tangentA,  adjacent) ; 
3803
3804        tangentStart=start ;
3805        tangentEnd=VectorSubtract(&end, &tangentA) ;
3806        ray=VectorSubtract(&tangentEnd, &tangentStart) ;
3807        ray=GetNormalised(&ray) ;
3808        VertexScale(&ray, flCutoff) ;
3809        tangentStart=start ;
3810        tangentEndA0=VectorAdd(&start, &ray) ;
3811
3812        raytangent=VectorSubtract(&end, &tangentEndA0) ;
3813        raytangent=VectorAdd(&raytangent, &adjust) ;
3814        raytangent=GetNormalised(&raytangent) ;
3815
3816
3817
3818        tangentEndA0=VectorSubtract(&tangentEndA0, &backshift) ;
3819        Vert_A0.position[0]=tangentEndA0.position[0] ;
3820        Vert_A0.position[1]=tangentEndA0.position[1] ;
3821        Vert_A0.position[2]=tangentEndA0.position[2] ;
3822        Vert_A0.normal[0]= -raytangent.position[0] ;
3823        Vert_A0.normal[1]= -raytangent.position[1] ;
3824        Vert_A0.normal[2]= -raytangent.position[2] ;
3825        Vert_A0.texcoord[0][0]=flCentreX ;
3826        Vert_A0.texcoord[0][1]=flCentreY ;
3827        Vert_A0.texcoord[1][0]=flCentreZ ;
3828        Vert_A0.texcoord[1][1]=flBrightness ;
3829        Vert_A0.color[0]=(unsigned char)flColR ;//abs(Vert_A0.normal[0])*255 ;//0.0f ;
3830        Vert_A0.color[1]=(unsigned char)flColG ;//abs(Vert_A0.normal[1])*255 ;//0.0f ;
3831        Vert_A0.color[2]=(unsigned char)flColB ;//abs(Vert_A0.normal[2])*255 ;//0.0f ;
3832        if(!AddVertex(Vert_A0)) return 0 ;
3833
3834
3835        tangentStart=start ;
3836        tangentEnd=VectorAdd(&end, &tangentA) ;
3837        ray=VectorSubtract(&tangentEnd, &tangentStart) ;
3838        ray=GetNormalised(&ray) ;
3839        VertexScale(&ray, flCutoff) ; //ray.getScaledBy(cutoff) ;
3840        tangentStart=start ;
3841        tangentEndA1=VectorAdd(&start, &ray) ;
3842
3843        raytangent=VectorSubtract(&end, &tangentEndA1) ;
3844        raytangent=VectorAdd(&raytangent, &adjust) ;
3845        raytangent=GetNormalised(&raytangent) ;
3846
3847        tangentEndA1=VectorSubtract(&tangentEndA1, &backshift) ;
3848        Vert_A1.position[0]=tangentEndA1.position[0] ;
3849        Vert_A1.position[1]=tangentEndA1.position[1] ;
3850        Vert_A1.position[2]=tangentEndA1.position[2] ;
3851        Vert_A1.normal[0]= -raytangent.position[0] ;
3852        Vert_A1.normal[1]= -raytangent.position[1] ;
3853        Vert_A1.normal[2]= -raytangent.position[2] ;
3854        Vert_A1.texcoord[0][0]=flCentreX ;
3855        Vert_A1.texcoord[0][1]=flCentreY ;
3856        Vert_A1.texcoord[1][0]=flCentreZ ;
3857        Vert_A1.texcoord[1][1]=flBrightness ;
3858        Vert_A1.color[0]=(unsigned char)flColR ;//abs(Vert_A1.normal[0])*255 ;//0.0f ;
3859        Vert_A1.color[1]=(unsigned char)flColG ;//abs(Vert_A1.normal[1])*255 ;//0.0f ;
3860        Vert_A1.color[2]=(unsigned char)flColB ;//abs(Vert_A1.normal[2])*255 ;//0.0f ;
3861        if(!AddVertex(Vert_A1)) return 0 ;
3862
3863        //////////////////////////////////////////////////////////////////////
3864
3865        tangentB=GetNormalised(&tangentB) ;
3866        VertexScale(&tangentB, adjacent) ; //tangentB.getScaledBy(adjacent) ;
3867
3868        tangentStart=start ;
3869        tangentEnd=VectorSubtract(&end, &tangentB) ;
3870        ray=VectorSubtract(&tangentEnd, &tangentStart) ;
3871        ray=GetNormalised(&ray) ;
3872        VertexScale(&ray, flCutoff) ; //ray.getScaledBy(cutoff) ;
3873        tangentStart=start ;
3874        tangentEndB0=VectorAdd(&start, &ray) ;
3875
3876        raytangent=VectorSubtract(&end, &tangentEndB0) ;
3877        raytangent=VectorAdd(&raytangent, &adjust) ;
3878        raytangent=GetNormalised(&raytangent) ;
3879
3880        tangentEndB0=VectorSubtract(&tangentEndB0, &backshift) ;
3881        Vert_B0.position[0]=tangentEndB0.position[0] ;
3882        Vert_B0.position[1]=tangentEndB0.position[1] ;
3883        Vert_B0.position[2]=tangentEndB0.position[2] ;
3884        Vert_B0.normal[0]= -raytangent.position[0] ;
3885        Vert_B0.normal[1]= -raytangent.position[1] ;
3886        Vert_B0.normal[2]= -raytangent.position[2] ;
3887        Vert_B0.texcoord[0][0]=flCentreX ;
3888        Vert_B0.texcoord[0][1]=flCentreY ;
3889        Vert_B0.texcoord[1][0]=flCentreZ ;
3890        Vert_B0.texcoord[1][1]=flBrightness ;
3891        Vert_B0.color[0]=(unsigned char)flColR ;//abs(Vert_B0.normal[0])*255 ;//0.0f ;
3892        Vert_B0.color[1]=(unsigned char)flColG ;//abs(Vert_B0.normal[1])*255 ;//0.0f ;
3893        Vert_B0.color[2]=(unsigned char)flColB ;//abs(Vert_B0.normal[2])*255 ;//0.0f ;
3894        if(!AddVertex(Vert_B0)) return 0 ;
3895
3896        tangentStart=start ;
3897        tangentEnd=VectorAdd(&end, &tangentB) ;
3898        ray=VectorSubtract(&tangentEnd, &tangentStart) ;
3899        ray=GetNormalised(&ray) ;
3900        VertexScale(&ray, flCutoff) ; //ray.getScaledBy(cutoff) ;
3901        tangentStart=start ;
3902        tangentEndB1=VectorAdd(&start, &ray) ;
3903
3904        raytangent=VectorSubtract(&end, &tangentEndB1) ;
3905        raytangent=VectorAdd(&raytangent, &adjust) ;
3906        raytangent=GetNormalised(&raytangent) ;
3907
3908        tangentEndB1=VectorSubtract(&tangentEndB1, &backshift) ;
3909        Vert_B1.position[0]=tangentEndB1.position[0] ;
3910        Vert_B1.position[1]=tangentEndB1.position[1] ;
3911        Vert_B1.position[2]=tangentEndB1.position[2] ;
3912        Vert_B1.normal[0]= -raytangent.position[0] ;
3913        Vert_B1.normal[1]= -raytangent.position[1] ;
3914        Vert_B1.normal[2]= -raytangent.position[2] ;
3915        Vert_B1.texcoord[0][0]=flCentreX ;
3916        Vert_B1.texcoord[0][1]=flCentreY ;
3917        Vert_B1.texcoord[1][0]=flCentreZ ;
3918        Vert_B1.texcoord[1][1]=flBrightness ;
3919        Vert_B1.color[0]=(unsigned char)flColR ;//abs(Vert_B1.normal[0])*255 ;//0.0f ;
3920        Vert_B1.color[1]=(unsigned char)flColG ;//abs(Vert_B1.normal[1])*255 ;//0.0f ;
3921        Vert_B1.color[2]=(unsigned char)flColB ;//abs(Vert_B1.normal[2])*255 ;//0.0f ;
3922        if(!AddVertex(Vert_B1)) return 0 ;
3923
3924        /////////////////////////////////////////////////////////////////////
3925
3926
3927
3928
3929        // the four verts are position correctly to make the large end of a cone (or rather, pyramid) that would be consistent
3930        // with the angle and their distance from the origin.  However we cheat and move them back on top of the origin
3931        // so that map lights come out looking better.
3932       
3933        /*
3934        SetVertex(&normal, m_pLight[nLight].Direction[0]*flCutoff, m_pLight[nLight].Direction[1]*flCutoff, m_pLight[nLight].Direction[2]*flCutoff) ;
3935
3936        tangentEndA0=VectorSubtract(&tangentEndA0, &normal) ;
3937        Vert_A0.position[0]=tangentEndA0.position[0] ;
3938        Vert_A0.position[1]=tangentEndA0.position[1] ;
3939        Vert_A0.position[2]=tangentEndA0.position[2] ;
3940
3941        tangentEndA1=VectorSubtract(&tangentEndA1, &normal) ;
3942        Vert_A1.position[0]=tangentEndA1.position[0] ;
3943        Vert_A1.position[1]=tangentEndA1.position[1] ;
3944        Vert_A1.position[2]=tangentEndA1.position[2] ;
3945
3946        tangentEndB0=VectorSubtract(&tangentEndB0, &normal) ;
3947        Vert_A0.position[0]=tangentEndB0.position[0] ;
3948        Vert_A0.position[1]=tangentEndB0.position[1] ;
3949        Vert_A0.position[2]=tangentEndB0.position[2] ;
3950
3951        tangentEndB1=VectorSubtract(&tangentEndB1, &normal) ;
3952        Vert_A1.position[0]=tangentEndB1.position[0] ;
3953        Vert_A1.position[1]=tangentEndB1.position[1] ;
3954        Vert_A1.position[2]=tangentEndB1.position[2] ;
3955        */
3956
3957
3958        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3959
3960                Triangle.Texture=m_nDefaultTextureIndexGlowLight ;
3961                Triangle.Lamp=-1 ;
3962                Triangle.Group=m_nGroup ;
3963
3964                /////////////////////////////////////
3965
3966                Triangle.VIndex[0]=n_Or ;
3967                Triangle.VIndex[2]=n_A0 ;
3968                Triangle.VIndex[1]=n_B1 ;
3969                if(!AddTriangle(Triangle)) return 0 ;
3970
3971                Triangle.VIndex[0]=n_Or ;
3972                Triangle.VIndex[2]=n_B1 ;
3973                Triangle.VIndex[1]=n_A1 ;
3974                if(!AddTriangle(Triangle)) return 0 ;
3975
3976                Triangle.VIndex[0]=n_Or ;
3977                Triangle.VIndex[2]=n_A1 ;
3978                Triangle.VIndex[1]=n_B0 ;
3979                if(!AddTriangle(Triangle)) return 0 ;
3980               
3981                Triangle.VIndex[0]=n_Or ;
3982                Triangle.VIndex[2]=n_B0 ;
3983                Triangle.VIndex[1]=n_A0 ;
3984                if(!AddTriangle(Triangle)) return 0 ;
3985
3986                m_nGroup++ ; // increment group once for each glow
3987               
3988        }
3989       
3990        return 1 ;
3991}
3992
3993
3994
3995
3996/////////////////////////////////////////////////////////////////////////////////////////////////////
3997// some vertex manipulation functions used for setting up the light disk.
3998// They only work on the position, so other parts of the struct need to be setup seperately
3999
4000
4001void Q3Map::SetVertex(Q3BspVertex *pVert, float flXPos, float flYPos, float flZPos)
4002{
4003        pVert->position[0]=flXPos ;
4004        pVert->position[1]=flYPos ;
4005        pVert->position[2]=flZPos ;
4006}
4007
4008// this doesn't test exact equivalence, but rather within the range of an epsilon VERYSMALL
4009bool Q3Map::VectorsAreEqual(Q3BspVertex* pVecA, Q3BspVertex* pVecB)
4010{
4011        if( fabs(pVecA->position[0] - pVecB->position[0])>VERYSMALL ) return false ;
4012        if( fabs(pVecA->position[1] - pVecB->position[1])>VERYSMALL ) return false ;
4013        if( fabs(pVecA->position[2] - pVecB->position[2])>VERYSMALL ) return false ;
4014
4015        return true ;
4016}
4017
4018// VertA is the origin of VertB and VertC
4019Q3BspVertex Q3Map::NormalizedCrossProduct(Q3BspVertex VertA, Q3BspVertex VertB, Q3BspVertex VertC)
4020{
4021
4022
4023        Q3BspVertex Cross ;
4024
4025        // edge vectors
4026        float flVecXA_CP = VertA.position[0] - VertB.position[0] ;
4027        float flVecYA_CP = VertA.position[1] - VertB.position[1] ;
4028        float flVecZA_CP = VertA.position[2] - VertB.position[2] ;
4029        float flVecXB_CP = VertA.position[0] - VertC.position[0] ;
4030        float flVecYB_CP = VertA.position[1] - VertC.position[1] ;
4031        float flVecZB_CP = VertA.position[2] - VertC.position[2] ;
4032
4033        // cross product
4034        float flCpx_CP = (flVecZA_CP * flVecYB_CP) - (flVecYA_CP * flVecZB_CP);
4035        float flCpy_CP = (flVecXA_CP * flVecZB_CP) - (flVecZA_CP * flVecXB_CP);
4036        float flCpz_CP = (flVecYA_CP * flVecXB_CP) - (flVecXA_CP * flVecYB_CP);
4037
4038        // Normalize
4039        float flR_CP = sqrt(flCpx_CP * flCpx_CP + flCpy_CP * flCpy_CP + flCpz_CP * flCpz_CP);
4040
4041        Cross.position[0] = flCpx_CP / flR_CP;
4042        Cross.position[1] = flCpy_CP / flR_CP;
4043        Cross.position[2] = flCpz_CP / flR_CP;
4044
4045        return Cross ;
4046}
4047
4048float Q3Map::VertexDistance(Q3BspVertex* VertA, Q3BspVertex* VertB)
4049{
4050        float flXDis=VertA->position[0]-VertB->position[0] ;
4051        float flYDis=VertA->position[1]-VertB->position[1] ;
4052        float flZDis=VertA->position[2]-VertB->position[2] ;
4053
4054        return sqrt(flXDis*flXDis+flYDis*flYDis+flZDis*flZDis) ;
4055}
4056
4057void Q3Map::VertexScale(Q3BspVertex* pVert, float flScale)
4058{
4059        pVert->position[0]*=flScale ;
4060        pVert->position[1]*=flScale ;
4061        pVert->position[2]*=flScale ;
4062}
4063
4064Q3BspVertex Q3Map::GetNormalised(Q3BspVertex* pVector)
4065{
4066        float flLength=sqrt((pVector->position[0]*pVector->position[0])+(pVector->position[1]*pVector->position[1])+(pVector->position[2]*pVector->position[2])) ;
4067
4068        Q3BspVertex Vector=*pVector ;
4069
4070        Vector.position[0]/=flLength ;
4071        Vector.position[1]/=flLength ;
4072        Vector.position[2]/=flLength ;
4073
4074        return Vector ;
4075}
4076
4077Q3BspVertex Q3Map::VectorAdd(Q3BspVertex* pVecA, Q3BspVertex* pVecB)
4078{
4079        Q3BspVertex Vector ;
4080
4081        Vector.position[0]=pVecA->position[0] + pVecB->position[0] ;
4082        Vector.position[1]=pVecA->position[1] + pVecB->position[1] ;
4083        Vector.position[2]=pVecA->position[2] + pVecB->position[2] ;
4084
4085        return Vector ;
4086}
4087
4088Q3BspVertex Q3Map::VectorSubtract(Q3BspVertex* pVecA, Q3BspVertex* pVecB)
4089{
4090        Q3BspVertex Vector ;
4091
4092        Vector.position[0]=pVecA->position[0] - pVecB->position[0] ;
4093        Vector.position[1]=pVecA->position[1] - pVecB->position[1] ;
4094        Vector.position[2]=pVecA->position[2] - pVecB->position[2] ;
4095
4096        return Vector ;
4097}
4098
4099Q3BspVertex Q3Map::VectorMultiply(Q3BspVertex* pVecA, Q3BspVertex* pVecB)
4100{
4101        Q3BspVertex Vector ;
4102
4103        Vector.position[0]=pVecA->position[0] * pVecB->position[0] ;
4104        Vector.position[1]=pVecA->position[1] * pVecB->position[1] ;
4105        Vector.position[2]=pVecA->position[2] * pVecB->position[2] ;
4106
4107        return Vector ;
4108}
4109
4110
4111
4112///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4113
4114
4115
4116
4117void Q3Map::GetTexLampTextureNumbers()
4118{
4119        m_nBZN_LightNode0=-1 ;
4120        m_nBZN_LightNode1=-1 ;
4121        m_nBZN_LightNode2=-1 ;
4122        m_nBZN_LightNode3=-1 ;
4123
4124        int nTex=0;
4125        char chTexName[1024] ;
4126        int nLen=0 ;
4127        int nPos=0 ;
4128
4129        int nMatch=0 ;
4130
4131        strcpy(chTexName, "textures/common/bzn_lightnode") ;
4132        nLen=strlen(chTexName) ;
4133
4134        for(nTex=0 ; nTex<m_nTextureMax ; nTex++)
4135        {
4136                nMatch=1 ;
4137                for(nPos=nLen-1 ; nPos>=0 ; nPos--) // faster to check backwards since lots of textures will start with "textures/common/"
4138                        if(m_pTexture[nTex].name[nPos]!=chTexName[nPos])
4139                        {
4140                                nMatch=0 ;
4141                                break ;
4142                        }
4143
4144                if(nMatch)
4145                {
4146                        // what is the last character?
4147                        if(m_pTexture[nTex].name[nLen]=='0')
4148                                m_nBZN_LightNode0=nTex ;
4149                        else
4150                        if(m_pTexture[nTex].name[nLen]=='1')
4151                                m_nBZN_LightNode1=nTex ;
4152                        else
4153                        if(m_pTexture[nTex].name[nLen]=='2')
4154                                m_nBZN_LightNode2=nTex ;
4155                        else
4156                        if(m_pTexture[nTex].name[nLen]=='3')
4157                                m_nBZN_LightNode3=nTex ;
4158                       
4159                }// end if match
4160
4161
4162        }// end for nTex
4163
4164}
4165
4166int Q3Map::SortTrianglesIntoGroups(void)
4167{
4168
4169
4170        int nNewSize=0 ; // we will drop non-subzoned (-1 zone) triangles here, so new number of triangles may be less than old number.
4171
4172        ULONGLONG *pFaceOrder = new ULONGLONG[m_nTriangleMax] ;
4173        if(pFaceOrder==NULL) return 0 ; // out of memory.
4174
4175        // temporary copy of m_pTriangles to make sorting easier
4176        triangle_t *TempTriangle = new triangle_t[m_nTriangleMax];
4177        if(TempTriangle==NULL) { DELETE_ARRAY( pFaceOrder ) ; return 0 ; } // out of memory
4178        memcpy((void*)TempTriangle, (void*)m_pTriangle, m_nTriangleMax*sizeof(triangle_t)) ;
4179
4180        // create the initial face "value" by setting the most significant bits to it's criteria number
4181        for (int i=0; i < m_nTriangleMax; i++)
4182                if(m_pTriangle[i].Zone!=-1) // drop unsubzoned triangles
4183                        pFaceOrder[nNewSize++] = ( ((ULONGLONG)m_pTriangle[i].Zone)<<GROUPSORT_SUBZONE_SHIFT ) + ( ((ULONGLONG)m_pTriangle[i].Texture)<<GROUPSORT_GROUP_SHIFT ) + i ;
4184
4185        // sort the ULONGLONGs, this will order things according to our criteria
4186        // sorting is based firstly on subzone, secondly on texture. 
4187        // So all triangles in a subzone will be grouped together,
4188        // and within that group all triangles with the same material will be grouped together. 
4189
4190        qsort( (void *)pFaceOrder, nNewSize, sizeof(ULONGLONG), &Q3Map::compareGroups);
4191
4192        // copy the sorted faces back to the original
4193        for (int i=0; i < nNewSize; i++)
4194                m_pTriangle[i]=TempTriangle[ (pFaceOrder[i]&FACESORT_FACE_MASK) ] ;
4195
4196        // update m_nTriangleMax to show that there may now be less triangles
4197        m_nTriangleMax=nNewSize ;
4198
4199        // clean up the memory we used
4200        DELETE_ARRAY( pFaceOrder ) ;
4201        DELETE_ARRAY( TempTriangle ) ;
4202
4203
4204        // now that the triangles are sorting according to zone and group,
4205        // re-assign the group numbers per zone, from 0 to FACESORT_GROUP_LIMIT-1
4206        // All non-trans triangles will be group 0, trans triangles will be 1 to FACESORT_GROUP_LIMIT-1
4207
4208        int nTri=0 ;
4209        int nZone=-1 ;
4210        int nGroup=-1 ;
4211        int nNewGroup=0 ;
4212
4213        //char chMessage[1024] ;
4214
4215        for(nTri=0 ; nTri<m_nTriangleMax ; nTri++)
4216        {
4217                // reset the newgroup if we've got a new zone
4218                if(m_pTriangle[nTri].Zone!=nZone) 
4219                {
4220                        nZone=m_pTriangle[nTri].Zone ;
4221                        nGroup=-1 ;
4222                        nNewGroup=0 ;
4223                }       
4224
4225                // if we have a new group, increment the newgroup number, fail if we have too many
4226                if(m_pTriangle[nTri].Group!=nGroup) 
4227                {
4228                        // if this is a trans triangle, inc the newgroup
4229                        if(m_pTransTexture[ m_pTriangle[nTri].Texture ])
4230                        {
4231                                nNewGroup++ ; // will always be at least 1
4232                                if(nNewGroup>=FACESORT_GROUP_LIMIT) return 0 ; // too many groups in a zone.
4233                        }
4234
4235                        nGroup=m_pTriangle[nTri].Group ;
4236                }
4237
4238                if(m_pTransTexture[ m_pTriangle[nTri].Texture ]==0)
4239                        m_pTriangle[nTri].Group=0 ;
4240                else
4241                        m_pTriangle[nTri].Group=nNewGroup ;
4242
4243
4244
4245        }// end for tri
4246
4247        return 1 ;
4248}
4249
4250
4251// static function for sorting groups, required by qsort
4252int Q3Map::compareGroups( const void *arg1, const void *arg2 )
4253{
4254        ULONGLONG FaceA= *(ULONGLONG*)arg1 ;
4255        ULONGLONG FaceB= *(ULONGLONG*)arg2 ;
4256
4257        if(FaceA < FaceB)
4258                return -1 ;
4259        else
4260                if(FaceA > FaceB)
4261                        return 1 ;
4262               
4263        return 0 ;
4264}
4265
4266
4267
4268// sort faces so that we can batch effectively when constructing our manualobjects
4269// Currently grouped according to zone and texture.
4270// Triangles not in any subzone will be dropped at this stage.
4271int Q3Map::SortTrianglesIntoBatches(void)
4272{
4273
4274
4275        int nNewSize=0 ; // we will drop non-subzoned (-1 zone) triangles here, so new number of triangles may be less than old number.
4276
4277        ULONGLONG *pFaceOrder = new ULONGLONG[m_nTriangleMax] ;
4278        if(pFaceOrder==NULL) return 0 ; // out of memory.
4279
4280        // temporary copy of m_pTriangles to make sorting easier
4281        triangle_t *TempTriangle = new triangle_t[m_nTriangleMax];
4282        if(TempTriangle==NULL) { DELETE_ARRAY( pFaceOrder ) ; return 0 ; } // out of memory
4283        memcpy((void*)TempTriangle, (void*)m_pTriangle, m_nTriangleMax*sizeof(triangle_t)) ;
4284
4285        // create the initial face "value" by setting the most significant bits to it's criteria number
4286        for (int i=0; i < m_nTriangleMax; i++)
4287                if(m_pTriangle[i].Zone!=-1) // drop unsubzoned triangles
4288                        pFaceOrder[nNewSize++] = ( ((ULONGLONG)m_pTriangle[i].Zone)<<FACESORT_SUBZONE_SHIFT ) + ( ((ULONGLONG)m_pTriangle[i].Texture)<<FACESORT_TEXTURE_SHIFT ) + ( ((ULONGLONG)m_pTriangle[i].Group)<<FACESORT_GROUP_SHIFT ) + i ;
4289
4290        // sort the ULONGLONGs, this will order things according to our criteria
4291        // sorting is based firstly on subzone, secondly on texture. 
4292        // So all triangles in a subzone will be grouped together,
4293        // and within that group all triangles with the same material will be grouped together. 
4294
4295        qsort( (void *)pFaceOrder, nNewSize, sizeof(ULONGLONG), &Q3Map::compareTriangles);
4296
4297        // copy the sorted faces back to the original
4298        for (int i=0; i < nNewSize; i++)
4299                m_pTriangle[i]=TempTriangle[ (pFaceOrder[i]&FACESORT_FACE_MASK) ] ;
4300
4301        // update m_nTriangleMax to show that there may now be less triangles
4302        m_nTriangleMax=nNewSize ;
4303
4304        // clean up the memory we used
4305        DELETE_ARRAY( pFaceOrder ) ;
4306        DELETE_ARRAY( TempTriangle ) ;
4307
4308        return 1 ;
4309}
4310
4311// static function for sorting triangles, required by qsort
4312int Q3Map::compareTriangles( const void *arg1, const void *arg2 )
4313{
4314        ULONGLONG FaceA= *(ULONGLONG*)arg1 ;
4315        ULONGLONG FaceB= *(ULONGLONG*)arg2 ;
4316
4317        if(FaceA < FaceB)
4318                return -1 ;
4319        else
4320                if(FaceA > FaceB)
4321                        return 1 ;
4322               
4323        return 0 ;
4324}
4325
4326
4327
4328
4329// note which texture numbers correspond to textures that have transparency.
4330// needed for when we work out transparency groups and related stuff
4331int Q3Map::SetupTransTextures(void)
4332{
4333        int nMaterial=0 ;
4334        int nPos=0 ;
4335        char chMaterial[1024] ;
4336
4337        // create the memory for the transtextures
4338        m_pTransTexture = new int[m_nTextureMax] ;
4339        if(m_pTransTexture==NULL) return 0 ; // out of memory.
4340
4341        for(nMaterial=0 ; nMaterial<m_nTextureMax ; nMaterial++)
4342        {
4343                // copy the material name.
4344                // q3 texture names are a max of 64 characters ( Q3NAMESIZE ) and may not be null terminated.  They have no extension either.
4345                nPos=-1 ;
4346                while((++nPos<Q3NAMESIZE) && (m_pTexture[nMaterial].name[nPos]!=' ') && (m_pTexture[nMaterial].name[nPos]!='\0'))
4347                        chMaterial[nPos]=m_pTexture[nMaterial].name[nPos] ;
4348
4349                // make sure name is null terminated
4350                chMaterial[nPos]='\0' ;
4351
4352
4353                // is the texture a type we need to flag as transparent?
4354                if(strstr(chMaterial, "GEL")!=NULL)
4355                        m_pTransTexture[nMaterial]=1 ;
4356                else
4357                        m_pTransTexture[nMaterial]=0 ;
4358
4359        }// end for nMaterial
4360
4361        return 1 ;
4362
4363}
4364
4365//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4366
4367int Q3Map::AssignPortalsToZones(void)
4368{
4369        int nZone=0 ;
4370        float flMinX=0.0f ;
4371        float flMaxX=0.0f ;
4372        float flMinY=0.0f ;
4373        float flMaxY=0.0f ;
4374        float flMinZ=0.0f ;
4375        float flMaxZ=0.0f ;
4376        int nMaxSubZone=m_iNumSubZones ;
4377        int nSubZone=0 ;
4378        int nMaxPortal=m_iNumPortals ;
4379        int nPortal=0 ;
4380        int nIndex=0 ;
4381        int nPos=0 ;
4382
4383
4384
4385        // clear the portal settings.
4386        for(nZone=0 ; nZone<m_nMaxZone ; nZone++)
4387                m_nZoneTouchesPortal[nZone][INDEX_PORTALCOUNT]=0 ;
4388
4389        for(nPortal=0 ; nPortal<nMaxPortal ; nPortal++)
4390                m_nPortalTouchesZone[nPortal][INDEX_PORTALZONECOUNT]=0 ;
4391
4392
4393
4394        // now test each subzone against each portal to see what zones each portal contains.
4395        for(nSubZone=0 ; nSubZone<nMaxSubZone ; nSubZone++)
4396        {
4397                nZone=m_pSubZones[nSubZone].Zone ;
4398                flMinX=m_pSubZones[nSubZone].Min[0] ;
4399                flMaxX=m_pSubZones[nSubZone].Max[0] ;
4400                flMinY=m_pSubZones[nSubZone].Min[1] ;
4401                flMaxY=m_pSubZones[nSubZone].Max[1] ;
4402                flMinZ=m_pSubZones[nSubZone].Min[2] ;
4403                flMaxZ=m_pSubZones[nSubZone].Max[2] ;
4404
4405                // test all the portals to see if any overlap this subzone
4406                for(nPortal=0 ; nPortal<nMaxPortal ; nPortal++)
4407                {
4408
4409                        // if AABB overlap
4410                        if(
4411                                                 (flMinX<m_pPortals[nPortal].Max[0]) && (flMaxX>m_pPortals[nPortal].Min[0])
4412                                        && (flMinY<m_pPortals[nPortal].Max[1]) && (flMaxY>m_pPortals[nPortal].Min[1])
4413                                        && (flMinZ<m_pPortals[nPortal].Max[2]) && (flMaxZ>m_pPortals[nPortal].Min[2])
4414                                )
4415                        {
4416
4417                                // add this portal to the zone's portal list
4418                                nIndex=m_nZoneTouchesPortal[nZone][INDEX_PORTALCOUNT] ;
4419                                if(nIndex<MAX_PORTALPERZONE) // only add if we aren't already maxed out.
4420                                {
4421                                        // we need to check this portal isn't already on the list.
4422                                        // it might have gotten on by another subzone, since a zone can have multiple subzones.
4423                                        nPos=-1 ;
4424                                        while((++nPos<nIndex) && (m_nZoneTouchesPortal[nZone][nPos]!=nPortal)) ; 
4425
4426                                        if(nPos==nIndex) // this can only be true if we didn't already find nPortal in the list
4427                                        {
4428                                                m_nZoneTouchesPortal[nZone][nIndex]=nPortal ;
4429                                                m_nZoneTouchesPortal[nZone][INDEX_PORTALCOUNT]++ ;
4430                                        }
4431                                }
4432
4433                                // add this zone to the portal's list
4434                                nIndex=m_nPortalTouchesZone[nPortal][INDEX_PORTALZONECOUNT] ;
4435                                if(nIndex<MAX_ZONEPERPORTAL)
4436                                {
4437                                        // we need to check this zone isn't already on the list.
4438                                        // it might have gotten on by another subzone, since a zone can have multiple subzones.
4439                                        nPos=-1 ;
4440                                        while((++nPos<nIndex) && (m_nPortalTouchesZone[nPortal][nPos]!=nZone)) ; 
4441
4442                                        if(nPos==nIndex) // this can only be true if we didn't already find nZone in the list
4443                                        {
4444                                                m_nPortalTouchesZone[nPortal][nIndex]=nZone ;
4445                                                m_nPortalTouchesZone[nPortal][INDEX_PORTALZONECOUNT]++ ;
4446                                        }
4447                                }
4448
4449                        }// end if portal overlaps subzone
4450
4451                }// end for portal
4452
4453        }// end for subzone
4454
4455        return 1 ;
4456}
4457
4458int Q3Map::AssignLightsToZones(void)
4459{
4460        int nZone=0 ;
4461        float flMinX=0.0f ;
4462        float flMaxX=0.0f ;
4463        float flMinY=0.0f ;
4464        float flMaxY=0.0f ;
4465        float flMinZ=0.0f ;
4466        float flMaxZ=0.0f ;
4467        int nMaxSubZone=m_iNumSubZones ;
4468        int nSubZone=0 ;
4469        int nMaxLight=m_nLightMax ;
4470        int nLight=0 ;
4471        int nIndex=0 ;
4472        int nPos=0 ;
4473
4474
4475
4476        // clear the light settings.
4477        for(nZone=0 ; nZone<m_nMaxZone ; nZone++)
4478                m_nZoneContainsLightCentre[nZone][INDEX_LIGHTCOUNT]=m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT]=0 ;
4479
4480        for(nLight=0 ; nLight<nMaxLight ; nLight++)
4481                m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT]=0 ;
4482       
4483
4484
4485
4486        // now test each subzone against each light what contains/touches what
4487        for(nSubZone=0 ; nSubZone<nMaxSubZone ; nSubZone++)
4488        {
4489                nZone=m_pSubZones[nSubZone].Zone ;
4490                flMinX=m_pSubZones[nSubZone].Min[0] ;
4491                flMaxX=m_pSubZones[nSubZone].Max[0] ;
4492                flMinY=m_pSubZones[nSubZone].Min[1] ;
4493                flMaxY=m_pSubZones[nSubZone].Max[1] ;
4494                flMinZ=m_pSubZones[nSubZone].Min[2] ;
4495                flMaxZ=m_pSubZones[nSubZone].Max[2] ;
4496
4497                // test all the lights to see if any have centers inside this subzone
4498                for(nLight=0 ; nLight<nMaxLight ; nLight++)
4499                {
4500
4501                        /////////////////////////////////////////////////////////////////////////////////////
4502
4503                        // if light center is in this subzone
4504                        if(
4505                                                 (m_pLight[nLight].Position[0]>=flMinX) && (m_pLight[nLight].Position[0]<=flMaxX)
4506                                        && (m_pLight[nLight].Position[1]>=flMinY) && (m_pLight[nLight].Position[1]<=flMaxY)
4507                                        && (m_pLight[nLight].Position[2]>=flMinZ) && (m_pLight[nLight].Position[2]<=flMaxZ)
4508                                )
4509                        {
4510
4511                                // add this light to the zone's light list
4512                                nIndex=m_nZoneContainsLightCentre[nZone][INDEX_LIGHTCOUNT] ;
4513                                if(nIndex<MAX_LIGHTPERZONE) // only add if we aren't already maxed out.
4514                                {
4515                                        // we need to check this light isn't already on the list.
4516                                        // it might have gotten on by another subzone, since a zone can have multiple subzones.
4517                                        nPos=-1 ;
4518                                        while((++nPos<nIndex) && (m_nZoneContainsLightCentre[nZone][nPos]!=nLight)) ; 
4519
4520                                        if(nPos==nIndex) // this can only be true if we didn't already find nLight in the list
4521                                        {
4522                                                m_nZoneContainsLightCentre[nZone][nIndex]=nLight ;
4523                                                m_nZoneContainsLightCentre[nZone][INDEX_LIGHTCOUNT]++ ;
4524
4525                                                // assign this zone as the light's centre.  We only allow one zone to be the light's centre zone,
4526                                                // so this will get overwritten if the light is on the border.
4527                                                m_pLight[nLight].CentreZone=nZone ;
4528                                        }
4529                                }
4530
4531                        }// end if light centre contained by subzone
4532
4533                        /////////////////////////////////////////////////////////////////////////////////////
4534
4535                        // if light touches subzone (we store it in ZoneTouchesSubLight for now, will overwrite later)
4536                        // if light AABB overlaps the zone AABB
4537                        if(
4538                                                 (flMinX<m_pLight[nLight].Max[0]) && (flMaxX>m_pLight[nLight].Min[0])
4539                                        && (flMinY<m_pLight[nLight].Max[1]) && (flMaxY>m_pLight[nLight].Min[1])
4540                                        && (flMinZ<m_pLight[nLight].Max[2]) && (flMaxZ>m_pLight[nLight].Min[2])
4541                                )
4542                        {
4543                                // add this light to the zone's light list
4544                                nIndex=m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT] ;
4545                                if(nIndex<MAX_LIGHTPERZONE) // only add if we aren't already maxed out.
4546                                {
4547                                        // we need to check this light isn't already on the list.
4548                                        // it might have gotten on by another subzone, since a zone can have multiple subzones.
4549                                        nPos=-1 ;
4550                                        while((++nPos<nIndex) && (m_nZoneTouchesSubLight[nZone][nPos]!=nLight)) ; 
4551
4552                                        if(nPos==nIndex) // this can only be true if we didn't already find nPortal in the list
4553                                        {
4554                                                m_nZoneTouchesSubLight[nZone][nIndex]=nLight ;
4555                                                m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT]++ ;
4556                                        }
4557                                }
4558
4559                                // add this zone to the light's list
4560                                nIndex=m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT] ;
4561                                if(nIndex<MAX_ZONEPERLIGHT)
4562                                {
4563                                        // we need to check this zone isn't already on the list.
4564                                        // it might have gotten on by another subzone, since a zone can have multiple subzones.
4565                                        nPos=-1 ;
4566                                        while((++nPos<nIndex) && (m_nLightTouchesZone[nLight][nPos]!=nZone)) ; 
4567
4568                                        if(nPos==nIndex) // this can only be true if we didn't already find nZone in the list
4569                                        {
4570                                                m_nLightTouchesZone[nLight][nIndex]=nZone ;
4571                                                m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT]++ ;
4572                                        }
4573                                }
4574
4575                        }// end if light touches contained by subzone
4576
4577                        /////////////////////////////////////////////////////////////////////////////////////
4578
4579
4580
4581
4582                }// end for light
4583
4584        }// end for subzone
4585
4586
4587        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4588        //
4589        // work out the sublights.  These are cut up boxes made from the light boxes, one per zone.
4590        // Most lights will just become a single sublight, but multizone lights will be cut up into
4591        // multiple sublights.  These are used for calculating light visibility.
4592        //
4593
4594        m_nSubLightMax=0 ;
4595        int nMaxZone=0 ;
4596        int nZoneIndex=0 ;
4597        int nSubLightCentre=0 ;
4598        sublight_t TempSubLight ;
4599        for(nLight=0 ; nLight<nMaxLight ; nLight++)
4600        {
4601
4602                m_pLight[nLight].ZoneCount=m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT] ; // in the light, note how many zones it touches
4603
4604                if((m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT]>1) && (m_nMaxMultiZoneLight<MAX_LIGHT))// this is a multizone light
4605                        m_nMultiZoneLight[m_nMaxMultiZoneLight++]=nLight ;
4606
4607
4608                m_pLight[nLight].SubLightStart=m_nSubLightMax ; // where this light's cut up sublights start in m_SubLight
4609
4610
4611                // break the light up into it's different sublights, cut by zones.
4612                nMaxZone=m_nLightTouchesZone[nLight][INDEX_LIGHTZONECOUNT] ;
4613                for(nZoneIndex=0 ; nZoneIndex<nMaxZone ; nZoneIndex++)
4614                {
4615                        nZone=m_nLightTouchesZone[nLight][nZoneIndex] ;
4616
4617                        flMinX= m_pLight[nLight].Min[0]<m_ZoneBoundary[nZone].Min[0] ? m_ZoneBoundary[nZone].Min[0] : m_pLight[nLight].Min[0] ; 
4618                        flMinY= m_pLight[nLight].Min[1]<m_ZoneBoundary[nZone].Min[1] ? m_ZoneBoundary[nZone].Min[1] : m_pLight[nLight].Min[1] ; 
4619                        flMinZ= m_pLight[nLight].Min[2]<m_ZoneBoundary[nZone].Min[2] ? m_ZoneBoundary[nZone].Min[2] : m_pLight[nLight].Min[2] ;
4620
4621                        flMaxX= m_pLight[nLight].Max[0]>m_ZoneBoundary[nZone].Max[0] ? m_ZoneBoundary[nZone].Max[0] : m_pLight[nLight].Max[0] ; 
4622                        flMaxY= m_pLight[nLight].Max[1]>m_ZoneBoundary[nZone].Max[1] ? m_ZoneBoundary[nZone].Max[1] : m_pLight[nLight].Max[1] ; 
4623                        flMaxZ= m_pLight[nLight].Max[2]>m_ZoneBoundary[nZone].Max[2] ? m_ZoneBoundary[nZone].Max[2] : m_pLight[nLight].Max[2] ; 
4624
4625                        // add the cut down light as a sublight
4626                        m_SubLight[m_nSubLightMax].Light=nLight ;
4627                        m_SubLight[m_nSubLightMax].Zone=nZone ;
4628                        m_SubLight[m_nSubLightMax].Min[0]=flMinX ;
4629                        m_SubLight[m_nSubLightMax].Min[1]=flMinY ;
4630                        m_SubLight[m_nSubLightMax].Min[2]=flMinZ ;
4631                        m_SubLight[m_nSubLightMax].Max[0]=flMaxX ;
4632                        m_SubLight[m_nSubLightMax].Max[1]=flMaxY ;
4633                        m_SubLight[m_nSubLightMax].Max[2]=flMaxZ ;
4634
4635                        // remember which sublight is the centre
4636                        if(
4637                                                 (m_pLight[nLight].Position[0]>=flMinX) && (m_pLight[nLight].Position[0]<=flMaxX)
4638                                        && (m_pLight[nLight].Position[1]>=flMinY) && (m_pLight[nLight].Position[1]<=flMaxY)
4639                                        && (m_pLight[nLight].Position[2]>=flMinZ) && (m_pLight[nLight].Position[2]<=flMaxZ)
4640                                )
4641                                nSubLightCentre=m_nSubLightMax ;
4642
4643                                       
4644                        m_nSubLightMax++ ; // we don't have to worry about bound checking this, because we've already checked there aren't too many lights.
4645
4646                }// end for zoneindex                   
4647               
4648                // move the sublight that contains the centre to the beginning of the sublights for this light.
4649                // We always want the first sublight to contain the centre to make the culling algos work better.
4650                TempSubLight=m_SubLight[ m_pLight[nLight].SubLightStart ] ;
4651                m_SubLight[ m_pLight[nLight].SubLightStart ] = m_SubLight[ nSubLightCentre ] ;
4652                m_SubLight[ nSubLightCentre ] = TempSubLight ;
4653
4654
4655               
4656        }// end for light
4657
4658        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4659        //
4660        // recalculate m_nZoneTouchesSubLight using the newly created sublights
4661        // (instead of the complete lights that were originally used)
4662        //
4663
4664        int nSubLight=0 ;
4665
4666
4667        // clear the light settings.
4668        for(nZone=0 ; nZone<m_nMaxZone ; nZone++)
4669                m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT]=0 ;
4670
4671        for(nSubZone=0 ; nSubZone<nMaxSubZone ; nSubZone++)
4672        {
4673                nZone=m_pSubZones[nSubZone].Zone ;
4674                flMinX=m_pSubZones[nSubZone].Min[0] ;
4675                flMaxX=m_pSubZones[nSubZone].Max[0] ;
4676                flMinY=m_pSubZones[nSubZone].Min[1] ;
4677                flMaxY=m_pSubZones[nSubZone].Max[1] ;
4678                flMinZ=m_pSubZones[nSubZone].Min[2] ;
4679                flMaxZ=m_pSubZones[nSubZone].Max[2] ;
4680
4681                // test all the lights to see if any have centers inside this subzone
4682                for(nSubLight=0 ; nSubLight<m_nSubLightMax ; nSubLight++)
4683                {
4684                        // if light touches subzone (we store it in ZoneTouchesSubLight for now, will overwrite later)
4685                        // if light AABB overlaps the zone AABB
4686                        if(
4687                                                 (flMinX<m_SubLight[nSubLight].Max[0]) && (flMaxX>m_SubLight[nSubLight].Min[0])
4688                                        && (flMinY<m_SubLight[nSubLight].Max[1]) && (flMaxY>m_SubLight[nSubLight].Min[1])
4689                                        && (flMinZ<m_SubLight[nSubLight].Max[2]) && (flMaxZ>m_SubLight[nSubLight].Min[2])
4690                                )
4691                        {
4692                                // add this light to the zone's light list
4693                                nIndex=m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT] ;
4694                                if(nIndex<MAX_LIGHTPERZONE) // only add if we aren't already maxed out.
4695                                {
4696                                        // we need to check this light isn't already on the list.
4697                                        // it might have gotten on by another subzone, since a zone can have multiple subzones.
4698                                        nPos=-1 ;
4699                                        while((++nPos<nIndex) && (m_nZoneTouchesSubLight[nZone][nPos]!=nSubLight)) ; 
4700
4701                                        if(nPos==nIndex) // this can only be true if we didn't already find nSubLight in the list
4702                                        {
4703                                                m_nZoneTouchesSubLight[nZone][nIndex]=nSubLight ;
4704                                                m_nZoneTouchesSubLight[nZone][INDEX_LIGHTCOUNT]++ ;
4705                                        }
4706
4707                                }
4708
4709                        }// end if overlap
4710
4711                }// end for nSubLight
4712
4713        }// end for nSubZone
4714
4715
4716
4717
4718
4719        return 1 ;
4720}
4721
4722
4723int Q3Map::AssignLightsToPortals(void)
4724{
4725        float flMinX=0.0f ;
4726        float flMaxX=0.0f ;
4727        float flMinY=0.0f ;
4728        float flMaxY=0.0f ;
4729        float flMinZ=0.0f ;
4730        float flMaxZ=0.0f ;
4731        int nMaxPortal=m_iNumPortals ;
4732        int nPortal=0 ;
4733        int nMaxLight=m_nLightMax ;
4734        int nLight=0 ;
4735        int nIndex=0 ;
4736        int nPos=0 ;
4737
4738
4739
4740        // clear the light settings.
4741        for(nPortal=0 ; nPortal<nMaxPortal ; nPortal++)
4742                m_nPortalTouchesLight[nPortal][INDEX_PORTALLIGHTCOUNT]=0 ;
4743
4744        // now test each portal against each light to see if they touch
4745        for(nPortal=0 ; nPortal<nMaxPortal ; nPortal++)
4746        {
4747                flMinX=m_pPortals[nPortal].Min[0] ;
4748                flMaxX=m_pPortals[nPortal].Max[0] ;
4749                flMinY=m_pPortals[nPortal].Min[1] ;
4750                flMaxY=m_pPortals[nPortal].Max[1] ;
4751                flMinZ=m_pPortals[nPortal].Min[2] ;
4752                flMaxZ=m_pPortals[nPortal].Max[2] ;
4753
4754                // test all the lights to see if any touch this portal
4755                for(nLight=0 ; nLight<nMaxLight ; nLight++)
4756                {
4757
4758                        // if light AABB overlaps the portal AABB
4759                        if(
4760                                                 (flMinX<m_pLight[nLight].Max[0]) && (flMaxX>m_pLight[nLight].Min[0])
4761                                        && (flMinY<m_pLight[nLight].Max[1]) && (flMaxY>m_pLight[nLight].Min[1])
4762                                        && (flMinZ<m_pLight[nLight].Max[2]) && (flMaxZ>m_pLight[nLight].Min[2])
4763                                )
4764                        {
4765
4766                                // add this light to the portal's light list
4767                                nIndex=m_nPortalTouchesLight[nPortal][INDEX_PORTALLIGHTCOUNT] ;
4768                                if(nIndex<MAX_LIGHTPERPORTAL) // only add if we aren't already maxed out.
4769                                {
4770                                        // we need to check this light isn't already on the list.
4771                                        // it might have gotten on by another subzone, since a zone can have multiple subzones.
4772                                        nPos=-1 ;
4773                                        while((++nPos<nIndex) && (m_nPortalTouchesLight[nPortal][nPos]!=nLight)) ; 
4774
4775                                        if(nPos==nIndex) // this can only be true if we didn't already find nLight in the list
4776                                        {
4777                                                m_nPortalTouchesLight[nPortal][nIndex]=nLight ;
4778                                                m_nPortalTouchesLight[nPortal][INDEX_PORTALLIGHTCOUNT]++ ;
4779                                        }
4780                                }
4781
4782                                // we don't keep a list of the portals that a light touches, we don't use such a thing.
4783
4784                        }// end if light touches portal
4785
4786                }// end for light
4787
4788        }// end for portal
4789
4790        return 1 ;
4791}
4792
4793// work out all the other zones each zone touches, via portals
4794int Q3Map::AssignZonesToZones(void)
4795{
4796       
4797
4798        int nCentralZone=0 ;
4799        int nPortalZone=0 ;
4800        int nMaxPortalZone=0 ;
4801        int nPortalZoneIndex=0 ;
4802        int nPortal=0 ;
4803        int nPortalIndex=0 ;
4804        int nMaxPortal=0 ;
4805
4806        int nTouchZoneIndex=0 ;
4807        int nMaxTouchZone=0 ;
4808        int nAddZone=0 ;
4809
4810
4811        // scan through all the zones (consider them "central zones")
4812        for(nCentralZone=0 ; nCentralZone<m_nMaxZone ; nCentralZone++)
4813        {
4814                nMaxTouchZone=0 ;
4815
4816                // scan through all the portals in this centralzone.
4817                nMaxPortal=m_nZoneTouchesPortal[nCentralZone][INDEX_PORTALCOUNT] ;
4818                for(nPortalIndex=0 ; nPortalIndex<nMaxPortal; nPortalIndex++)
4819                {
4820                        nPortal=m_nZoneTouchesPortal[nCentralZone][nPortalIndex] ;
4821
4822                        // scan through all the zones this portal touches and add then to the central zone's list
4823                        nMaxPortalZone=m_nPortalTouchesZone[nPortal][INDEX_PORTALZONECOUNT] ;
4824                        for(nPortalZoneIndex=0 ; nPortalZoneIndex<nMaxPortalZone ; nPortalZoneIndex++)
4825                        {
4826                                nPortalZone=m_nPortalTouchesZone[nPortal][nPortalZoneIndex] ;
4827
4828                                // we've got a portal zone. 
4829                                if(nPortalZone==nCentralZone) continue ; // if it's the central zone, skip it.
4830
4831                                // check we don't already have it listed.
4832                                nAddZone=1 ;
4833                                for(nTouchZoneIndex=0 ; nTouchZoneIndex<nMaxTouchZone ; nTouchZoneIndex++)
4834                                {
4835                                        if(m_nZoneTouchesPortal[nCentralZone][nTouchZoneIndex]==nPortalZone)
4836                                        {
4837                                                nAddZone=0 ;
4838                                                break ;
4839                                        }// end if
4840                                }// end for nTouchZoneIndex
4841       
4842                                if(nAddZone)
4843                                {
4844                                        m_nZoneTouchesZone[nCentralZone][nMaxTouchZone]=nPortalZone ;
4845                                        nMaxTouchZone++ ;
4846                                        if(nMaxTouchZone>=MAX_ZONEPERZONE) 
4847                                                nMaxTouchZone=MAX_ZONEPERZONE-1 ;
4848
4849                                       
4850                                }
4851
4852
4853                        }// end for portal zone index
4854
4855
4856                }// end for portal index
4857               
4858                // set the maximum
4859                m_nZoneTouchesZone[nCentralZone][INDEX_ZONEPERZONECOUNT]=nMaxTouchZone ;
4860
4861                /*
4862                sprintf(m_chBug, "CentralZone %i, TouchedZoneCount %i", nCentralZone, m_nZoneTouchesPortal[nCentralZone][INDEX_ZONEPERZONECOUNT]) ;
4863                Q3Bug.LogAddCR(m_chBug) ;
4864                for(nTouchZoneIndex=0 ; nTouchZoneIndex<m_nZoneTouchesZone[nCentralZone][INDEX_ZONEPERZONECOUNT] ; nTouchZoneIndex++)
4865                {
4866                        sprintf(m_chBug, "     TouchedZone %i", m_nZoneTouchesZone[nCentralZone][nTouchZoneIndex]) ;
4867                        Q3Bug.LogAddCR(m_chBug) ;
4868                }
4869                */
4870
4871
4872        }// end for central zone
4873
4874
4875
4876
4877        return 1 ;
4878}
4879
4880
4881
Note: See TracBrowser for help on using the repository browser.