Annotation of quake2/qcommon/cmodel.c, revision 1.1

1.1     ! root        1: // cmodel.c -- model loading
        !             2: #include "qcommon.h"
        !             3: typedef struct
        !             4: {
        !             5:        cplane_t        *plane;
        !             6:        int                     children[2];            // negative numbers are leafs
        !             7: } cnode_t;
        !             8: typedef struct
        !             9: {
        !            10:        cplane_t        *plane;
        !            11:        csurface_t      *surface;
        !            12: } cbrushside_t;
        !            13: typedef struct
        !            14: {
        !            15:        int                     contents;
        !            16:        int                     cluster;
        !            17:        int                     area;
        !            18:        unsigned short  firstleafbrush;
        !            19:        unsigned short  numleafbrushes;
        !            20: } cleaf_t;
        !            21: typedef struct
        !            22: {
        !            23:        int                     contents;
        !            24:        int                     numsides;
        !            25:        int                     firstbrushside;
        !            26:        int                     checkcount;             // to avoid repeated testings
        !            27: } cbrush_t;
        !            28: typedef struct
        !            29: {
        !            30:        int             numareaportals;
        !            31:        int             firstareaportal;
        !            32:        int             floodnum;                       // if two areas have equal floodnums, they are connected
        !            33:        int             floodvalid;
        !            34: } carea_t;
        !            35: int                    checkcount;
        !            36: char           map_name[MAX_QPATH];
        !            37: int                    numbrushsides;
        !            38: cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES];
        !            39: int                    numtexinfo;
        !            40: csurface_t     map_surfaces[MAX_MAP_TEXINFO];
        !            41: int                    numplanes;
        !            42: cplane_t       map_planes[MAX_MAP_PLANES+6];           // extra for box hull
        !            43: int                    numnodes;
        !            44: cnode_t                map_nodes[MAX_MAP_NODES+6];             // extra for box hull
        !            45: int                    numleafs = 1;   // allow leaf funcs to be called without a map
        !            46: cleaf_t                map_leafs[MAX_MAP_LEAFS];
        !            47: int                    emptyleaf, solidleaf;
        !            48: int                    numleafbrushes;
        !            49: unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES];
        !            50: int                    numcmodels;
        !            51: cmodel_t       map_cmodels[MAX_MAP_MODELS];
        !            52: int                    numbrushes;
        !            53: cbrush_t       map_brushes[MAX_MAP_BRUSHES];
        !            54: int                    numvisibility;
        !            55: byte           map_visibility[MAX_MAP_VISIBILITY];
        !            56: dvis_t         *map_vis = (dvis_t *)map_visibility;
        !            57: int                    numentitychars;
        !            58: char           map_entitystring[MAX_MAP_ENTSTRING];
        !            59: int                    numareas = 1;
        !            60: carea_t                map_areas[MAX_MAP_AREAS];
        !            61: int                    numareaportals;
        !            62: dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS];
        !            63: int                    numclusters = 1;
        !            64: csurface_t     nullsurface;
        !            65: int                    floodvalid;
        !            66: qboolean       portalopen[MAX_MAP_AREAPORTALS];
        !            67: cvar_t         *map_noareas;
        !            68: void   CM_InitBoxHull (void);
        !            69: void   FloodAreaConnections (void);
        !            70: int            c_pointcontents;
        !            71: int            c_traces, c_brush_traces;
        !            72: /*
        !            73: ===============================================================================
        !            74:                                        MAP LOADING
        !            75: ===============================================================================
        !            76: */
        !            77: byte   *cmod_base;
        !            78: /*
        !            79: =================
        !            80: CMod_LoadSubmodels
        !            81: =================
        !            82: */
        !            83: void CMod_LoadSubmodels (lump_t *l)
        !            84: {
        !            85:        dmodel_t        *in;
        !            86:        cmodel_t        *out;
        !            87:        int                     i, j, count;
        !            88:        in = (void *)(cmod_base + l->fileofs);
        !            89:        if (l->filelen % sizeof(*in))
        !            90:                Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
        !            91:        count = l->filelen / sizeof(*in);
        !            92:        if (count < 1)
        !            93:                Com_Error (ERR_DROP, "Map with no models");
        !            94:        if (count > MAX_MAP_MODELS)
        !            95:                Com_Error (ERR_DROP, "Map has too many models");
        !            96:        numcmodels = count;
        !            97:        for ( i=0 ; i<count ; i++, in++, out++)
        !            98:        {
        !            99:                out = &map_cmodels[i];
        !           100:                for (j=0 ; j<3 ; j++)
        !           101:                {       // spread the mins / maxs by a pixel
        !           102:                        out->mins[j] = LittleFloat (in->mins[j]) - 1;
        !           103:                        out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
        !           104:                        out->origin[j] = LittleFloat (in->origin[j]);
        !           105:                }
        !           106:                out->headnode = LittleLong (in->headnode);
        !           107:        }
        !           108: }
        !           109: /*
        !           110: =================
        !           111: CMod_LoadSurfaces
        !           112: =================
        !           113: */
        !           114: void CMod_LoadSurfaces (lump_t *l)
        !           115: {
        !           116:        texinfo_t       *in;
        !           117:        csurface_t      *out;
        !           118:        int                     i, count;
        !           119:        in = (void *)(cmod_base + l->fileofs);
        !           120:        if (l->filelen % sizeof(*in))
        !           121:                Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
        !           122:        count = l->filelen / sizeof(*in);
        !           123:        if (count < 1)
        !           124:                Com_Error (ERR_DROP, "Map with no surfaces");
        !           125:        if (count > MAX_MAP_TEXINFO)
        !           126:                Com_Error (ERR_DROP, "Map has too many surfaces");
        !           127:        numtexinfo = count;
        !           128:        out = map_surfaces;
        !           129:        for ( i=0 ; i<count ; i++, in++, out++)
        !           130:        {
        !           131:                strncpy (out->name, in->texture, sizeof(out->name)-1);
        !           132:                out->flags = LittleLong (in->flags);
        !           133:                out->value = LittleLong (in->value);
        !           134:        }
        !           135: }
        !           136: /*
        !           137: =================
        !           138: CMod_LoadNodes
        !           139: =================
        !           140: */
        !           141: void CMod_LoadNodes (lump_t *l)
        !           142: {
        !           143:        dnode_t         *in;
        !           144:        int                     child;
        !           145:        cnode_t         *out;
        !           146:        int                     i, j, count;
        !           147:        
        !           148:        in = (void *)(cmod_base + l->fileofs);
        !           149:        if (l->filelen % sizeof(*in))
        !           150:                Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
        !           151:        count = l->filelen / sizeof(*in);
        !           152:        if (count < 1)
        !           153:                Com_Error (ERR_DROP, "Map has no nodes");
        !           154:        if (count > MAX_MAP_NODES)
        !           155:                Com_Error (ERR_DROP, "Map has too many nodes");
        !           156:        out = map_nodes;
        !           157:        numnodes = count;
        !           158:        for (i=0 ; i<count ; i++, out++, in++)
        !           159:        {
        !           160:                out->plane = map_planes + LittleLong(in->planenum);
        !           161:                for (j=0 ; j<2 ; j++)
        !           162:                {
        !           163:                        child = LittleLong (in->children[j]);
        !           164:                        out->children[j] = child;
        !           165:                }
        !           166:        }
        !           167: }
        !           168: /*
        !           169: =================
        !           170: CMod_LoadBrushes
        !           171: =================
        !           172: */
        !           173: void CMod_LoadBrushes (lump_t *l)
        !           174: {
        !           175:        dbrush_t        *in;
        !           176:        cbrush_t        *out;
        !           177:        int                     i, count;
        !           178:        
        !           179:        in = (void *)(cmod_base + l->fileofs);
        !           180:        if (l->filelen % sizeof(*in))
        !           181:                Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
        !           182:        count = l->filelen / sizeof(*in);
        !           183:        if (count > MAX_MAP_BRUSHES)
        !           184:                Com_Error (ERR_DROP, "Map has too many brushes");
        !           185:        out = map_brushes;
        !           186:        numbrushes = count;
        !           187:        for (i=0 ; i<count ; i++, out++, in++)
        !           188:        {
        !           189:                out->firstbrushside = LittleLong(in->firstside);
        !           190:                out->numsides = LittleLong(in->numsides);
        !           191:                out->contents = LittleLong(in->contents);
        !           192:        }
        !           193: }
        !           194: /*
        !           195: =================
        !           196: CMod_LoadLeafs
        !           197: =================
        !           198: */
        !           199: void CMod_LoadLeafs (lump_t *l)
        !           200: {
        !           201:        int                     i;
        !           202:        cleaf_t         *out;
        !           203:        dleaf_t         *in;
        !           204:        int                     count;
        !           205:        
        !           206:        in = (void *)(cmod_base + l->fileofs);
        !           207:        if (l->filelen % sizeof(*in))
        !           208:                Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
        !           209:        count = l->filelen / sizeof(*in);
        !           210:        if (count < 1)
        !           211:                Com_Error (ERR_DROP, "Map with no leafs");
        !           212:        // need to save space for box planes
        !           213:        if (count > MAX_MAP_PLANES)
        !           214:                Com_Error (ERR_DROP, "Map has too many planes");
        !           215:        out = map_leafs;        
        !           216:        numleafs = count;
        !           217:        numclusters = 0;
        !           218:        for ( i=0 ; i<count ; i++, in++, out++)
        !           219:        {
        !           220:                out->contents = LittleLong (in->contents);
        !           221:                out->cluster = LittleShort (in->cluster);
        !           222:                out->area = LittleShort (in->area);
        !           223:                out->firstleafbrush = LittleShort (in->firstleafbrush);
        !           224:                out->numleafbrushes = LittleShort (in->numleafbrushes);
        !           225:                if (out->cluster >= numclusters)
        !           226:                        numclusters = out->cluster + 1;
        !           227:        }
        !           228:        if (map_leafs[0].contents != CONTENTS_SOLID)
        !           229:                Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
        !           230:        solidleaf = 0;
        !           231:        emptyleaf = -1;
        !           232:        for (i=1 ; i<numleafs ; i++)
        !           233:        {
        !           234:                if (!map_leafs[i].contents)
        !           235:                {
        !           236:                        emptyleaf = i;
        !           237:                        break;
        !           238:                }
        !           239:        }
        !           240:        if (emptyleaf == -1)
        !           241:                Com_Error (ERR_DROP, "Map does not have an empty leaf");
        !           242: }
        !           243: /*
        !           244: =================
        !           245: CMod_LoadPlanes
        !           246: =================
        !           247: */
        !           248: void CMod_LoadPlanes (lump_t *l)
        !           249: {
        !           250:        int                     i, j;
        !           251:        cplane_t        *out;
        !           252:        dplane_t        *in;
        !           253:        int                     count;
        !           254:        int                     bits;
        !           255:        
        !           256:        in = (void *)(cmod_base + l->fileofs);
        !           257:        if (l->filelen % sizeof(*in))
        !           258:                Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
        !           259:        count = l->filelen / sizeof(*in);
        !           260:        if (count < 1)
        !           261:                Com_Error (ERR_DROP, "Map with no planes");
        !           262:        // need to save space for box planes
        !           263:        if (count > MAX_MAP_PLANES)
        !           264:                Com_Error (ERR_DROP, "Map has too many planes");
        !           265:        out = map_planes;       
        !           266:        numplanes = count;
        !           267:        for ( i=0 ; i<count ; i++, in++, out++)
        !           268:        {
        !           269:                bits = 0;
        !           270:                for (j=0 ; j<3 ; j++)
        !           271:                {
        !           272:                        out->normal[j] = LittleFloat (in->normal[j]);
        !           273:                        if (out->normal[j] < 0)
        !           274:                                bits |= 1<<j;
        !           275:                }
        !           276:                out->dist = LittleFloat (in->dist);
        !           277:                out->type = LittleLong (in->type);
        !           278:                out->signbits = bits;
        !           279:        }
        !           280: }
        !           281: /*
        !           282: =================
        !           283: CMod_LoadLeafBrushes
        !           284: =================
        !           285: */
        !           286: void CMod_LoadLeafBrushes (lump_t *l)
        !           287: {
        !           288:        int                     i;
        !           289:        unsigned short  *out;
        !           290:        unsigned short  *in;
        !           291:        int                     count;
        !           292:        
        !           293:        in = (void *)(cmod_base + l->fileofs);
        !           294:        if (l->filelen % sizeof(*in))
        !           295:                Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
        !           296:        count = l->filelen / sizeof(*in);
        !           297:        if (count < 1)
        !           298:                Com_Error (ERR_DROP, "Map with no planes");
        !           299:        // need to save space for box planes
        !           300:        if (count > MAX_MAP_LEAFBRUSHES)
        !           301:                Com_Error (ERR_DROP, "Map has too many leafbrushes");
        !           302:        out = map_leafbrushes;
        !           303:        numleafbrushes = count;
        !           304:        for ( i=0 ; i<count ; i++, in++, out++)
        !           305:                *out = LittleShort (*in);
        !           306: }
        !           307: /*
        !           308: =================
        !           309: CMod_LoadBrushSides
        !           310: =================
        !           311: */
        !           312: void CMod_LoadBrushSides (lump_t *l)
        !           313: {
        !           314:        int                     i, j;
        !           315:        cbrushside_t    *out;
        !           316:        dbrushside_t    *in;
        !           317:        int                     count;
        !           318:        int                     num;
        !           319:        in = (void *)(cmod_base + l->fileofs);
        !           320:        if (l->filelen % sizeof(*in))
        !           321:                Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
        !           322:        count = l->filelen / sizeof(*in);
        !           323:        // need to save space for box planes
        !           324:        if (count > MAX_MAP_BRUSHSIDES)
        !           325:                Com_Error (ERR_DROP, "Map has too many planes");
        !           326:        out = map_brushsides;   
        !           327:        numbrushsides = count;
        !           328:        for ( i=0 ; i<count ; i++, in++, out++)
        !           329:        {
        !           330:                num = LittleShort (in->planenum);
        !           331:                out->plane = &map_planes[num];
        !           332:                j = LittleShort (in->texinfo);
        !           333:                if (j >= numtexinfo)
        !           334:                        Com_Error (ERR_DROP, "Bad brushside texinfo");
        !           335:                out->surface = &map_surfaces[j];
        !           336:        }
        !           337: }
        !           338: /*
        !           339: =================
        !           340: CMod_LoadAreas
        !           341: =================
        !           342: */
        !           343: void CMod_LoadAreas (lump_t *l)
        !           344: {
        !           345:        int                     i;
        !           346:        carea_t         *out;
        !           347:        darea_t         *in;
        !           348:        int                     count;
        !           349:        in = (void *)(cmod_base + l->fileofs);
        !           350:        if (l->filelen % sizeof(*in))
        !           351:                Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
        !           352:        count = l->filelen / sizeof(*in);
        !           353:        if (count > MAX_MAP_AREAS)
        !           354:                Com_Error (ERR_DROP, "Map has too many areas");
        !           355:        out = map_areas;
        !           356:        numareas = count;
        !           357:        for ( i=0 ; i<count ; i++, in++, out++)
        !           358:        {
        !           359:                out->numareaportals = LittleLong (in->numareaportals);
        !           360:                out->firstareaportal = LittleLong (in->firstareaportal);
        !           361:                out->floodvalid = 0;
        !           362:                out->floodnum = 0;
        !           363:        }
        !           364: }
        !           365: /*
        !           366: =================
        !           367: CMod_LoadAreaPortals
        !           368: =================
        !           369: */
        !           370: void CMod_LoadAreaPortals (lump_t *l)
        !           371: {
        !           372:        int                     i;
        !           373:        dareaportal_t           *out;
        !           374:        dareaportal_t   *in;
        !           375:        int                     count;
        !           376:        in = (void *)(cmod_base + l->fileofs);
        !           377:        if (l->filelen % sizeof(*in))
        !           378:                Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
        !           379:        count = l->filelen / sizeof(*in);
        !           380:        if (count > MAX_MAP_AREAS)
        !           381:                Com_Error (ERR_DROP, "Map has too many areas");
        !           382:        out = map_areaportals;
        !           383:        numareaportals = count;
        !           384:        for ( i=0 ; i<count ; i++, in++, out++)
        !           385:        {
        !           386:                out->portalnum = LittleLong (in->portalnum);
        !           387:                out->otherarea = LittleLong (in->otherarea);
        !           388:        }
        !           389: }
        !           390: /*
        !           391: =================
        !           392: CMod_LoadVisibility
        !           393: =================
        !           394: */
        !           395: void CMod_LoadVisibility (lump_t *l)
        !           396: {
        !           397:        int             i;
        !           398:        numvisibility = l->filelen;
        !           399:        if (l->filelen > MAX_MAP_VISIBILITY)
        !           400:                Com_Error (ERR_DROP, "Map has too large visibility lump");
        !           401:        memcpy (map_visibility, cmod_base + l->fileofs, l->filelen);
        !           402:        map_vis->numclusters = LittleLong (map_vis->numclusters);
        !           403:        for (i=0 ; i<map_vis->numclusters ; i++)
        !           404:        {
        !           405:                map_vis->bitofs[i][0] = LittleLong (map_vis->bitofs[i][0]);
        !           406:                map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]);
        !           407:        }
        !           408: }
        !           409: /*
        !           410: =================
        !           411: CMod_LoadEntityString
        !           412: =================
        !           413: */
        !           414: void CMod_LoadEntityString (lump_t *l)
        !           415: {
        !           416:        numentitychars = l->filelen;
        !           417:        if (l->filelen > MAX_MAP_ENTSTRING)
        !           418:                Com_Error (ERR_DROP, "Map has too large entity lump");
        !           419:        memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen);
        !           420: }
        !           421: /*
        !           422: ==================
        !           423: CM_LoadMap
        !           424: Loads in the map and all submodels
        !           425: ==================
        !           426: */
        !           427: cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum)
        !           428: {
        !           429:        unsigned                *buf;
        !           430:        int                             i;
        !           431:        dheader_t               header;
        !           432:        int                             length;
        !           433:        static unsigned last_checksum;
        !           434:        map_noareas = Cvar_Get ("map_noareas", "0", 0);
        !           435:        if (  !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) )
        !           436:        {
        !           437:                *checksum = last_checksum;
        !           438:                if (!clientload)
        !           439:                {
        !           440:                        memset (portalopen, 0, sizeof(portalopen));
        !           441:                        FloodAreaConnections ();
        !           442:                }
        !           443:                return &map_cmodels[0];         // still have the right version
        !           444:        }
        !           445:        // free old stuff
        !           446:        numplanes = 0;
        !           447:        numnodes = 0;
        !           448:        numleafs = 0;
        !           449:        numcmodels = 0;
        !           450:        numvisibility = 0;
        !           451:        numentitychars = 0;
        !           452:        map_entitystring[0] = 0;
        !           453:        map_name[0] = 0;
        !           454:        if (!name || !name[0])
        !           455:        {
        !           456:                numleafs = 1;
        !           457:                numclusters = 1;
        !           458:                numareas = 1;
        !           459:                *checksum = 0;
        !           460:                return &map_cmodels[0];                 // cinematic servers won't have anything at all
        !           461:        }
        !           462:        //
        !           463:        // load the file
        !           464:        //
        !           465:        length = FS_LoadFile (name, (void **)&buf);
        !           466:        if (!buf)
        !           467:                Com_Error (ERR_DROP, "Couldn't load %s", name);
        !           468: 
        !           469:        last_checksum = LittleLong (Com_BlockChecksum (buf, length));
        !           470:        *checksum = last_checksum;
        !           471:        header = *(dheader_t *)buf;
        !           472:        for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
        !           473:                ((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
        !           474:        if (header.version != BSPVERSION)
        !           475:                Com_Error (ERR_DROP, "CMod_LoadBrushModel: %s has wrong version number (%i should be %i)"
        !           476:                , name, header.version, BSPVERSION);
        !           477:        cmod_base = (byte *)buf;
        !           478:        // load into heap
        !           479:        CMod_LoadSurfaces (&header.lumps[LUMP_TEXINFO]);
        !           480:        CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
        !           481:        CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
        !           482:        CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
        !           483:        CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
        !           484:        CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
        !           485:        CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
        !           486:        CMod_LoadNodes (&header.lumps[LUMP_NODES]);
        !           487:        CMod_LoadAreas (&header.lumps[LUMP_AREAS]);
        !           488:        CMod_LoadAreaPortals (&header.lumps[LUMP_AREAPORTALS]);
        !           489:        CMod_LoadVisibility (&header.lumps[LUMP_VISIBILITY]);
        !           490:        CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
        !           491:        FS_FreeFile (buf);
        !           492:        CM_InitBoxHull ();
        !           493:        memset (portalopen, 0, sizeof(portalopen));
        !           494:        FloodAreaConnections ();
        !           495:        strcpy (map_name, name);
        !           496:        return &map_cmodels[0];
        !           497: }
        !           498: /*
        !           499: ==================
        !           500: CM_InlineModel
        !           501: ==================
        !           502: */
        !           503: cmodel_t       *CM_InlineModel (char *name)
        !           504: {
        !           505:        int             num;
        !           506:        if (!name || name[0] != '*')
        !           507:                Com_Error (ERR_DROP, "CM_InlineModel: bad name");
        !           508:        num = atoi (name+1);
        !           509:        if (num < 1 || num >= numcmodels)
        !           510:                Com_Error (ERR_DROP, "CM_InlineModel: bad number");
        !           511:        return &map_cmodels[num];
        !           512: }
        !           513: int            CM_NumClusters (void)
        !           514: {
        !           515:        return numclusters;
        !           516: }
        !           517: int            CM_NumInlineModels (void)
        !           518: {
        !           519:        return numcmodels;
        !           520: }
        !           521: char   *CM_EntityString (void)
        !           522: {
        !           523:        return map_entitystring;
        !           524: }
        !           525: int            CM_LeafContents (int leafnum)
        !           526: {
        !           527:        if (leafnum < 0 || leafnum >= numleafs)
        !           528:                Com_Error (ERR_DROP, "CM_LeafContents: bad number");
        !           529:        return map_leafs[leafnum].contents;
        !           530: }
        !           531: int            CM_LeafCluster (int leafnum)
        !           532: {
        !           533:        if (leafnum < 0 || leafnum >= numleafs)
        !           534:                Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
        !           535:        return map_leafs[leafnum].cluster;
        !           536: }
        !           537: int            CM_LeafArea (int leafnum)
        !           538: {
        !           539:        if (leafnum < 0 || leafnum >= numleafs)
        !           540:                Com_Error (ERR_DROP, "CM_LeafArea: bad number");
        !           541:        return map_leafs[leafnum].area;
        !           542: }
        !           543: //=======================================================================
        !           544: cplane_t       *box_planes;
        !           545: int                    box_headnode;
        !           546: cbrush_t       *box_brush;
        !           547: cleaf_t                *box_leaf;
        !           548: /*
        !           549: ===================
        !           550: CM_InitBoxHull
        !           551: Set up the planes and nodes so that the six floats of a bounding box
        !           552: can just be stored out and get a proper clipping hull structure.
        !           553: ===================
        !           554: */
        !           555: void CM_InitBoxHull (void)
        !           556: {
        !           557:        int                     i;
        !           558:        int                     side;
        !           559:        cnode_t         *c;
        !           560:        cplane_t        *p;
        !           561:        cbrushside_t    *s;
        !           562:        box_headnode = numnodes;
        !           563:        box_planes = &map_planes[numplanes];
        !           564:        if (numnodes+6 > MAX_MAP_NODES
        !           565:                || numbrushes+1 > MAX_MAP_BRUSHES
        !           566:                || numleafbrushes+1 > MAX_MAP_LEAFBRUSHES
        !           567:                || numbrushsides+6 > MAX_MAP_BRUSHSIDES
        !           568:                || numplanes+12 > MAX_MAP_PLANES)
        !           569:                Com_Error (ERR_DROP, "Not enough room for box tree");
        !           570:        box_brush = &map_brushes[numbrushes];
        !           571:        box_brush->numsides = 6;
        !           572:        box_brush->firstbrushside = numbrushsides;
        !           573:        box_brush->contents = CONTENTS_MONSTER;
        !           574:        box_leaf = &map_leafs[numleafs];
        !           575:        box_leaf->contents = CONTENTS_MONSTER;
        !           576:        box_leaf->firstleafbrush = numleafbrushes;
        !           577:        box_leaf->numleafbrushes = 1;
        !           578:        map_leafbrushes[numleafbrushes] = numbrushes;
        !           579:        for (i=0 ; i<6 ; i++)
        !           580:        {
        !           581:                side = i&1;
        !           582:                // brush sides
        !           583:                s = &map_brushsides[numbrushsides+i];
        !           584:                s->plane =      map_planes + (numplanes+i*2+side);
        !           585:                s->surface = &nullsurface;
        !           586:                // nodes
        !           587:                c = &map_nodes[box_headnode+i];
        !           588:                c->plane = map_planes + (numplanes+i*2);
        !           589:                c->children[side] = -1 - emptyleaf;
        !           590:                if (i != 5)
        !           591:                        c->children[side^1] = box_headnode+i + 1;
        !           592:                else
        !           593:                        c->children[side^1] = -1 - numleafs;
        !           594:                // planes
        !           595:                p = &box_planes[i*2];
        !           596:                p->type = i>>1;
        !           597:                p->signbits = 0;
        !           598:                VectorClear (p->normal);
        !           599:                p->normal[i>>1] = 1;
        !           600:                p = &box_planes[i*2+1];
        !           601:                p->type = 3 + (i>>1);
        !           602:                p->signbits = 0;
        !           603:                VectorClear (p->normal);
        !           604:                p->normal[i>>1] = -1;
        !           605:        }       
        !           606: }
        !           607: /*
        !           608: ===================
        !           609: CM_HeadnodeForBox
        !           610: To keep everything totally uniform, bounding boxes are turned into small
        !           611: BSP trees instead of being compared directly.
        !           612: ===================
        !           613: */
        !           614: int    CM_HeadnodeForBox (vec3_t mins, vec3_t maxs)
        !           615: {
        !           616:        box_planes[0].dist = maxs[0];
        !           617:        box_planes[1].dist = -maxs[0];
        !           618:        box_planes[2].dist = mins[0];
        !           619:        box_planes[3].dist = -mins[0];
        !           620:        box_planes[4].dist = maxs[1];
        !           621:        box_planes[5].dist = -maxs[1];
        !           622:        box_planes[6].dist = mins[1];
        !           623:        box_planes[7].dist = -mins[1];
        !           624:        box_planes[8].dist = maxs[2];
        !           625:        box_planes[9].dist = -maxs[2];
        !           626:        box_planes[10].dist = mins[2];
        !           627:        box_planes[11].dist = -mins[2];
        !           628:        return box_headnode;
        !           629: }
        !           630: /*
        !           631: ==================
        !           632: CM_PointLeafnum_r
        !           633: ==================
        !           634: */
        !           635: int CM_PointLeafnum_r (vec3_t p, int num)
        !           636: {
        !           637:        float           d;
        !           638:        cnode_t         *node;
        !           639:        cplane_t        *plane;
        !           640:        while (num >= 0)
        !           641:        {
        !           642:                node = map_nodes + num;
        !           643:                plane = node->plane;
        !           644:                
        !           645:                if (plane->type < 3)
        !           646:                        d = p[plane->type] - plane->dist;
        !           647:                else
        !           648:                        d = DotProduct (plane->normal, p) - plane->dist;
        !           649:                if (d < 0)
        !           650:                        num = node->children[1];
        !           651:                else
        !           652:                        num = node->children[0];
        !           653:        }
        !           654:        c_pointcontents++;              // optimize counter
        !           655:        return -1 - num;
        !           656: }
        !           657: int CM_PointLeafnum (vec3_t p)
        !           658: {
        !           659:        if (!numplanes)
        !           660:                return 0;               // sound may call this without map loaded
        !           661:        return CM_PointLeafnum_r (p, 0);
        !           662: }
        !           663: /*
        !           664: =============
        !           665: CM_BoxLeafnums
        !           666: Fills in a list of all the leafs touched
        !           667: =============
        !           668: */
        !           669: int            leaf_count, leaf_maxcount;
        !           670: int            *leaf_list;
        !           671: float  *leaf_mins, *leaf_maxs;
        !           672: int            leaf_topnode;
        !           673: void CM_BoxLeafnums_r (int nodenum)
        !           674: {
        !           675:        cplane_t        *plane;
        !           676:        cnode_t         *node;
        !           677:        int             s;
        !           678:        while (1)
        !           679:        {
        !           680:                if (nodenum < 0)
        !           681:                {
        !           682:                        if (leaf_count >= leaf_maxcount)
        !           683:                        {
        !           684: //                             Com_Printf ("CM_BoxLeafnums_r: overflow\n");
        !           685:                                return;
        !           686:                        }
        !           687:                        leaf_list[leaf_count++] = -1 - nodenum;
        !           688:                        return;
        !           689:                }
        !           690:        
        !           691:                node = &map_nodes[nodenum];
        !           692:                plane = node->plane;
        !           693: //             s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane);
        !           694:                s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane);
        !           695:                if (s == 1)
        !           696:                        nodenum = node->children[0];
        !           697:                else if (s == 2)
        !           698:                        nodenum = node->children[1];
        !           699:                else
        !           700:                {       // go down both
        !           701:                        if (leaf_topnode == -1)
        !           702:                                leaf_topnode = nodenum;
        !           703:                        CM_BoxLeafnums_r (node->children[0]);
        !           704:                        nodenum = node->children[1];
        !           705:                }
        !           706:        }
        !           707: }
        !           708: int    CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode)
        !           709: {
        !           710:        leaf_list = list;
        !           711:        leaf_count = 0;
        !           712:        leaf_maxcount = listsize;
        !           713:        leaf_mins = mins;
        !           714:        leaf_maxs = maxs;
        !           715:        leaf_topnode = -1;
        !           716:        CM_BoxLeafnums_r (headnode);
        !           717:        if (topnode)
        !           718:                *topnode = leaf_topnode;
        !           719:        return leaf_count;
        !           720: }
        !           721: int    CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode)
        !           722: {
        !           723:        return CM_BoxLeafnums_headnode (mins, maxs, list,
        !           724:                listsize, map_cmodels[0].headnode, topnode);
        !           725: }
        !           726: /*
        !           727: ==================
        !           728: CM_PointContents
        !           729: ==================
        !           730: */
        !           731: int CM_PointContents (vec3_t p, int headnode)
        !           732: {
        !           733:        int             l;
        !           734:        if (!numnodes)  // map not loaded
        !           735:                return 0;
        !           736: 
        !           737:        l = CM_PointLeafnum_r (p, headnode);
        !           738:        return map_leafs[l].contents;
        !           739: }
        !           740: /*
        !           741: ==================
        !           742: CM_TransformedPointContents
        !           743: Handles offseting and rotation of the end points for moving and
        !           744: rotating entities
        !           745: ==================
        !           746: */
        !           747: int    CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles)
        !           748: {
        !           749:        vec3_t          p_l;
        !           750:        vec3_t          temp;
        !           751:        vec3_t          forward, right, up;
        !           752:        int                     l;
        !           753:        // subtract origin offset
        !           754:        VectorSubtract (p, origin, p_l);
        !           755:        // rotate start and end into the models frame of reference
        !           756:        if (headnode != box_headnode && 
        !           757:        (angles[0] || angles[1] || angles[2]) )
        !           758:        {
        !           759:                AngleVectors (angles, forward, right, up);
        !           760:                VectorCopy (p_l, temp);
        !           761:                p_l[0] = DotProduct (temp, forward);
        !           762:                p_l[1] = -DotProduct (temp, right);
        !           763:                p_l[2] = DotProduct (temp, up);
        !           764:        }
        !           765:        l = CM_PointLeafnum_r (p_l, headnode);
        !           766:        return map_leafs[l].contents;
        !           767: }
        !           768: /*
        !           769: ===============================================================================
        !           770: BOX TRACING
        !           771: ===============================================================================
        !           772: */
        !           773: // 1/32 epsilon to keep floating point happy
        !           774: #define        DIST_EPSILON    (0.03125)
        !           775: vec3_t trace_start, trace_end;
        !           776: vec3_t trace_mins, trace_maxs;
        !           777: vec3_t trace_extents;
        !           778: trace_t        trace_trace;
        !           779: int            trace_contents;
        !           780: qboolean       trace_ispoint;          // optimized case
        !           781: /*
        !           782: ================
        !           783: CM_ClipBoxToBrush
        !           784: ================
        !           785: */
        !           786: void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
        !           787:                                          trace_t *trace, cbrush_t *brush)
        !           788: {
        !           789:        int                     i, j;
        !           790:        cplane_t        *plane, *clipplane;
        !           791:        float           dist;
        !           792:        float           enterfrac, leavefrac;
        !           793:        vec3_t          ofs;
        !           794:        float           d1, d2;
        !           795:        qboolean        getout, startout;
        !           796:        float           f;
        !           797:        cbrushside_t    *side, *leadside;
        !           798: 
        !           799:        enterfrac = -1;
        !           800:        leavefrac = 1;
        !           801:        clipplane = NULL;
        !           802: 
        !           803:        if (!brush->numsides)
        !           804:                return;
        !           805: 
        !           806:        c_brush_traces++;
        !           807: 
        !           808:        getout = false;
        !           809:        startout = false;
        !           810:        leadside = NULL;
        !           811: 
        !           812:        for (i=0 ; i<brush->numsides ; i++)
        !           813:        {
        !           814:                side = &map_brushsides[brush->firstbrushside+i];
        !           815:                plane = side->plane;
        !           816: 
        !           817:                // FIXME: special case for axial
        !           818: 
        !           819:                if (!trace_ispoint)
        !           820:                {       // general box case
        !           821: 
        !           822:                        // push the plane out apropriately for mins/maxs
        !           823: 
        !           824:                        // FIXME: use signbits into 8 way lookup for each mins/maxs
        !           825:                        for (j=0 ; j<3 ; j++)
        !           826:                        {
        !           827:                                if (plane->normal[j] < 0)
        !           828:                                        ofs[j] = maxs[j];
        !           829:                                else
        !           830:                                        ofs[j] = mins[j];
        !           831:                        }
        !           832:                        dist = DotProduct (ofs, plane->normal);
        !           833:                        dist = plane->dist - dist;
        !           834:                }
        !           835:                else
        !           836:                {       // special point case
        !           837:                        dist = plane->dist;
        !           838:                }
        !           839: 
        !           840:                d1 = DotProduct (p1, plane->normal) - dist;
        !           841:                d2 = DotProduct (p2, plane->normal) - dist;
        !           842: 
        !           843:                if (d2 > 0)
        !           844:                        getout = true;  // endpoint is not in solid
        !           845:                if (d1 > 0)
        !           846:                        startout = true;
        !           847: 
        !           848:                // if completely in front of face, no intersection
        !           849:                if (d1 > 0 && d2 >= d1)
        !           850:                        return;
        !           851: 
        !           852:                if (d1 <= 0 && d2 <= 0)
        !           853:                        continue;
        !           854: 
        !           855:                // crosses face
        !           856:                if (d1 > d2)
        !           857:                {       // enter
        !           858:                        f = (d1-DIST_EPSILON) / (d1-d2);
        !           859:                        if (f > enterfrac)
        !           860:                        {
        !           861:                                enterfrac = f;
        !           862:                                clipplane = plane;
        !           863:                                leadside = side;
        !           864:                        }
        !           865:                }
        !           866:                else
        !           867:                {       // leave
        !           868:                        f = (d1+DIST_EPSILON) / (d1-d2);
        !           869:                        if (f < leavefrac)
        !           870:                                leavefrac = f;
        !           871:                }
        !           872:        }
        !           873: 
        !           874:        if (!startout)
        !           875:        {       // original point was inside brush
        !           876:                trace->startsolid = true;
        !           877:                if (!getout)
        !           878:                        trace->allsolid = true;
        !           879:                return;
        !           880:        }
        !           881:        if (enterfrac < leavefrac)
        !           882:        {
        !           883:                if (enterfrac > -1 && enterfrac < trace->fraction)
        !           884:                {
        !           885:                        if (enterfrac < 0)
        !           886:                                enterfrac = 0;
        !           887:                        trace->fraction = enterfrac;
        !           888:                        trace->plane = *clipplane;
        !           889:                        trace->surface = leadside->surface;
        !           890:                        trace->contents = brush->contents;
        !           891:                }
        !           892:        }
        !           893: }
        !           894: 
        !           895: /*
        !           896: ================
        !           897: CM_TestBoxInBrush
        !           898: ================
        !           899: */
        !           900: void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1,
        !           901:                                          trace_t *trace, cbrush_t *brush)
        !           902: {
        !           903:        int                     i, j;
        !           904:        cplane_t        *plane;
        !           905:        float           dist;
        !           906:        vec3_t          ofs;
        !           907:        float           d1;
        !           908:        cbrushside_t    *side;
        !           909: 
        !           910:        if (!brush->numsides)
        !           911:                return;
        !           912: 
        !           913:        for (i=0 ; i<brush->numsides ; i++)
        !           914:        {
        !           915:                side = &map_brushsides[brush->firstbrushside+i];
        !           916:                plane = side->plane;
        !           917: 
        !           918:                // FIXME: special case for axial
        !           919: 
        !           920:                // general box case
        !           921: 
        !           922:                // push the plane out apropriately for mins/maxs
        !           923: 
        !           924:                // FIXME: use signbits into 8 way lookup for each mins/maxs
        !           925:                for (j=0 ; j<3 ; j++)
        !           926:                {
        !           927:                        if (plane->normal[j] < 0)
        !           928:                                ofs[j] = maxs[j];
        !           929:                        else
        !           930:                                ofs[j] = mins[j];
        !           931:                }
        !           932:                dist = DotProduct (ofs, plane->normal);
        !           933:                dist = plane->dist - dist;
        !           934: 
        !           935:                d1 = DotProduct (p1, plane->normal) - dist;
        !           936: 
        !           937:                // if completely in front of face, no intersection
        !           938:                if (d1 > 0)
        !           939:                        return;
        !           940: 
        !           941:        }
        !           942: 
        !           943:        // inside this brush
        !           944:        trace->startsolid = trace->allsolid = true;
        !           945:        trace->fraction = 0;
        !           946:        trace->contents = brush->contents;
        !           947: }
        !           948: 
        !           949: /*
        !           950: ================
        !           951: CM_TraceToLeaf
        !           952: ================
        !           953: */
        !           954: void CM_TraceToLeaf (int leafnum)
        !           955: {
        !           956:        int                     k;
        !           957:        int                     brushnum;
        !           958:        cleaf_t         *leaf;
        !           959:        cbrush_t        *b;
        !           960: 
        !           961:        leaf = &map_leafs[leafnum];
        !           962:        if ( !(leaf->contents & trace_contents))
        !           963:                return;
        !           964:        // trace line against all brushes in the leaf
        !           965:        for (k=0 ; k<leaf->numleafbrushes ; k++)
        !           966:        {
        !           967:                brushnum = map_leafbrushes[leaf->firstleafbrush+k];
        !           968:                b = &map_brushes[brushnum];
        !           969:                if (b->checkcount == checkcount)
        !           970:                        continue;       // already checked this brush in another leaf
        !           971:                b->checkcount = checkcount;
        !           972: 
        !           973:                if ( !(b->contents & trace_contents))
        !           974:                        continue;
        !           975:                CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b);
        !           976:                if (!trace_trace.fraction)
        !           977:                        return;
        !           978:        }
        !           979: 
        !           980: }
        !           981: 
        !           982: 
        !           983: /*
        !           984: ================
        !           985: CM_TestInLeaf
        !           986: ================
        !           987: */
        !           988: void CM_TestInLeaf (int leafnum)
        !           989: {
        !           990:        int                     k;
        !           991:        int                     brushnum;
        !           992:        cleaf_t         *leaf;
        !           993:        cbrush_t        *b;
        !           994: 
        !           995:        leaf = &map_leafs[leafnum];
        !           996:        if ( !(leaf->contents & trace_contents))
        !           997:                return;
        !           998:        // trace line against all brushes in the leaf
        !           999:        for (k=0 ; k<leaf->numleafbrushes ; k++)
        !          1000:        {
        !          1001:                brushnum = map_leafbrushes[leaf->firstleafbrush+k];
        !          1002:                b = &map_brushes[brushnum];
        !          1003:                if (b->checkcount == checkcount)
        !          1004:                        continue;       // already checked this brush in another leaf
        !          1005:                b->checkcount = checkcount;
        !          1006: 
        !          1007:                if ( !(b->contents & trace_contents))
        !          1008:                        continue;
        !          1009:                CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b);
        !          1010:                if (!trace_trace.fraction)
        !          1011:                        return;
        !          1012:        }
        !          1013: 
        !          1014: }
        !          1015: 
        !          1016: 
        !          1017: /*
        !          1018: ==================
        !          1019: CM_RecursiveHullCheck
        !          1020: ==================
        !          1021: */
        !          1022: void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2)
        !          1023: {
        !          1024:        cnode_t         *node;
        !          1025:        cplane_t        *plane;
        !          1026:        float           t1, t2, offset;
        !          1027:        float           frac, frac2;
        !          1028:        float           idist;
        !          1029:        int                     i;
        !          1030:        vec3_t          mid;
        !          1031:        int                     side;
        !          1032:        float           midf;
        !          1033:        if (trace_trace.fraction <= p1f)
        !          1034:                return;         // already hit something nearer
        !          1035:        // if < 0, we are in a leaf node
        !          1036:        if (num < 0)
        !          1037:        {
        !          1038:                CM_TraceToLeaf (-1-num);
        !          1039:                return;
        !          1040:        }
        !          1041:        //
        !          1042:        // find the point distances to the seperating plane
        !          1043:        // and the offset for the size of the box
        !          1044:        //
        !          1045:        node = map_nodes + num;
        !          1046:        plane = node->plane;
        !          1047:        if (plane->type < 3)
        !          1048:        {
        !          1049:                t1 = p1[plane->type] - plane->dist;
        !          1050:                t2 = p2[plane->type] - plane->dist;
        !          1051:                offset = trace_extents[plane->type];
        !          1052:        }
        !          1053:        else
        !          1054:        {
        !          1055:                t1 = DotProduct (plane->normal, p1) - plane->dist;
        !          1056:                t2 = DotProduct (plane->normal, p2) - plane->dist;
        !          1057:                if (trace_ispoint)
        !          1058:                        offset = 0;
        !          1059:                else
        !          1060:                        offset = fabs(trace_extents[0]*plane->normal[0]) +
        !          1061:                                fabs(trace_extents[1]*plane->normal[1]) +
        !          1062:                                fabs(trace_extents[2]*plane->normal[2]);
        !          1063:        }
        !          1064: #if 0
        !          1065: CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
        !          1066: CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
        !          1067: return;
        !          1068: #endif
        !          1069:        // see which sides we need to consider
        !          1070:        if (t1 >= offset && t2 >= offset)
        !          1071:        {
        !          1072:                CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
        !          1073:                return;
        !          1074:        }
        !          1075:        if (t1 < -offset && t2 < -offset)
        !          1076:        {
        !          1077:                CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
        !          1078:                return;
        !          1079:        }
        !          1080:        // put the crosspoint DIST_EPSILON pixels on the near side
        !          1081:        if (t1 < t2)
        !          1082:        {
        !          1083:                idist = 1.0/(t1-t2);
        !          1084:                side = 1;
        !          1085:                frac2 = (t1 + offset + DIST_EPSILON)*idist;
        !          1086:                frac = (t1 - offset + DIST_EPSILON)*idist;
        !          1087:        }
        !          1088:        else if (t1 > t2)
        !          1089:        {
        !          1090:                idist = 1.0/(t1-t2);
        !          1091:                side = 0;
        !          1092:                frac2 = (t1 - offset - DIST_EPSILON)*idist;
        !          1093:                frac = (t1 + offset + DIST_EPSILON)*idist;
        !          1094:        }
        !          1095:        else
        !          1096:        {
        !          1097:                side = 0;
        !          1098:                frac = 1;
        !          1099:                frac2 = 0;
        !          1100:        }
        !          1101:        // move up to the node
        !          1102:        if (frac < 0)
        !          1103:                frac = 0;
        !          1104:        if (frac > 1)
        !          1105:                frac = 1;
        !          1106:                
        !          1107:        midf = p1f + (p2f - p1f)*frac;
        !          1108:        for (i=0 ; i<3 ; i++)
        !          1109:                mid[i] = p1[i] + frac*(p2[i] - p1[i]);
        !          1110:        CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid);
        !          1111:        // go past the node
        !          1112:        if (frac2 < 0)
        !          1113:                frac2 = 0;
        !          1114:        if (frac2 > 1)
        !          1115:                frac2 = 1;
        !          1116:                
        !          1117:        midf = p1f + (p2f - p1f)*frac2;
        !          1118:        for (i=0 ; i<3 ; i++)
        !          1119:                mid[i] = p1[i] + frac2*(p2[i] - p1[i]);
        !          1120:        CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2);
        !          1121: }
        !          1122: //======================================================================
        !          1123: /*
        !          1124: ==================
        !          1125: CM_BoxTrace
        !          1126: ==================
        !          1127: */
        !          1128: trace_t                CM_BoxTrace (vec3_t start, vec3_t end,
        !          1129:                                                  vec3_t mins, vec3_t maxs,
        !          1130:                                                  int headnode, int brushmask)
        !          1131: {
        !          1132:        int             i;
        !          1133:        checkcount++;           // for multi-check avoidance
        !          1134:        c_traces++;                     // for statistics, may be zeroed
        !          1135:        // fill in a default trace
        !          1136:        memset (&trace_trace, 0, sizeof(trace_trace));
        !          1137:        trace_trace.fraction = 1;
        !          1138:        trace_trace.surface = &nullsurface;
        !          1139: 
        !          1140:        if (!numnodes)  // map not loaded
        !          1141:                return trace_trace;
        !          1142:        trace_contents = brushmask;
        !          1143:        VectorCopy (start, trace_start);
        !          1144:        VectorCopy (end, trace_end);
        !          1145:        VectorCopy (mins, trace_mins);
        !          1146:        VectorCopy (maxs, trace_maxs);
        !          1147: 
        !          1148:        //
        !          1149:        // check for position test special case
        !          1150:        //
        !          1151:        if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2])
        !          1152:        {
        !          1153:                int             leafs[1024];
        !          1154:                int             i, numleafs;
        !          1155:                vec3_t  c1, c2;
        !          1156:                int             topnode;
        !          1157: 
        !          1158:                VectorAdd (start, mins, c1);
        !          1159:                VectorAdd (start, maxs, c2);
        !          1160:                for (i=0 ; i<3 ; i++)
        !          1161:                {
        !          1162:                        c1[i] -= 1;
        !          1163:                        c2[i] += 1;
        !          1164:                }
        !          1165: 
        !          1166:                numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode);
        !          1167:                for (i=0 ; i<numleafs ; i++)
        !          1168:                {
        !          1169:                        CM_TestInLeaf (leafs[i]);
        !          1170:                        if (trace_trace.allsolid)
        !          1171:                                break;
        !          1172:                }
        !          1173:                VectorCopy (start, trace_trace.endpos);
        !          1174:                return trace_trace;
        !          1175:        }
        !          1176: 
        !          1177:        //
        !          1178:        // check for point special case
        !          1179:        //
        !          1180:        if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0
        !          1181:                && maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0)
        !          1182:        {
        !          1183:                trace_ispoint = true;
        !          1184:                VectorClear (trace_extents);
        !          1185:        }
        !          1186:        else
        !          1187:        {
        !          1188:                trace_ispoint = false;
        !          1189:                trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0];
        !          1190:                trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1];
        !          1191:                trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2];
        !          1192:        }
        !          1193: 
        !          1194:        //
        !          1195:        // general sweeping through world
        !          1196:        //
        !          1197:        CM_RecursiveHullCheck (headnode, 0, 1, start, end);
        !          1198:        if (trace_trace.fraction == 1)
        !          1199:        {
        !          1200:                VectorCopy (end, trace_trace.endpos);
        !          1201:        }
        !          1202:        else
        !          1203:        {
        !          1204:                for (i=0 ; i<3 ; i++)
        !          1205:                        trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]);
        !          1206:        }
        !          1207:        return trace_trace;
        !          1208: }
        !          1209: /*
        !          1210: ==================
        !          1211: CM_TransformedBoxTrace
        !          1212: Handles offseting and rotation of the end points for moving and
        !          1213: rotating entities
        !          1214: ==================
        !          1215: */
        !          1216: #ifdef _WIN32
        !          1217: #pragma optimize( "", off )
        !          1218: #endif
        !          1219: 
        !          1220: 
        !          1221: trace_t                CM_TransformedBoxTrace (vec3_t start, vec3_t end,
        !          1222:                                                  vec3_t mins, vec3_t maxs,
        !          1223:                                                  int headnode, int brushmask,
        !          1224:                                                  vec3_t origin, vec3_t angles)
        !          1225: {
        !          1226:        trace_t         trace;
        !          1227:        vec3_t          start_l, end_l;
        !          1228:        vec3_t          a;
        !          1229:        vec3_t          forward, right, up;
        !          1230:        vec3_t          temp;
        !          1231:        qboolean        rotated;
        !          1232:        // subtract origin offset
        !          1233:        VectorSubtract (start, origin, start_l);
        !          1234:        VectorSubtract (end, origin, end_l);
        !          1235:        // rotate start and end into the models frame of reference
        !          1236:        if (headnode != box_headnode && 
        !          1237:        (angles[0] || angles[1] || angles[2]) )
        !          1238:                rotated = true;
        !          1239:        else
        !          1240:                rotated = false;
        !          1241:        if (rotated)
        !          1242:        {
        !          1243:                AngleVectors (angles, forward, right, up);
        !          1244:                VectorCopy (start_l, temp);
        !          1245:                start_l[0] = DotProduct (temp, forward);
        !          1246:                start_l[1] = -DotProduct (temp, right);
        !          1247:                start_l[2] = DotProduct (temp, up);
        !          1248:                VectorCopy (end_l, temp);
        !          1249:                end_l[0] = DotProduct (temp, forward);
        !          1250:                end_l[1] = -DotProduct (temp, right);
        !          1251:                end_l[2] = DotProduct (temp, up);
        !          1252:        }
        !          1253:        // sweep the box through the model
        !          1254:        trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask);
        !          1255:        if (rotated && trace.fraction != 1.0)
        !          1256:        {
        !          1257:                // FIXME: figure out how to do this with existing angles
        !          1258:                VectorNegate (angles, a);
        !          1259:                AngleVectors (a, forward, right, up);
        !          1260:                VectorCopy (trace.plane.normal, temp);
        !          1261:                trace.plane.normal[0] = DotProduct (temp, forward);
        !          1262:                trace.plane.normal[1] = -DotProduct (temp, right);
        !          1263:                trace.plane.normal[2] = DotProduct (temp, up);
        !          1264:        }
        !          1265:        trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
        !          1266:        trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
        !          1267:        trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
        !          1268:        return trace;
        !          1269: }
        !          1270: #ifdef _WIN32
        !          1271: #pragma optimize( "", on )
        !          1272: #endif
        !          1273: 
        !          1274: 
        !          1275: /*
        !          1276: ===============================================================================
        !          1277: PVS / PHS
        !          1278: ===============================================================================
        !          1279: */
        !          1280: /*
        !          1281: ===================
        !          1282: CM_DecompressVis
        !          1283: ===================
        !          1284: */
        !          1285: void CM_DecompressVis (byte *in, byte *out)
        !          1286: {
        !          1287:        int             c;
        !          1288:        byte    *out_p;
        !          1289:        int             row;
        !          1290:        row = (numclusters+7)>>3;       
        !          1291:        out_p = out;
        !          1292: 
        !          1293:        if (!in || !numvisibility)
        !          1294:        {       // no vis info, so make all visible
        !          1295:                while (row)
        !          1296:                {
        !          1297:                        *out_p++ = 0xff;
        !          1298:                        row--;
        !          1299:                }
        !          1300:                return;         
        !          1301:        }
        !          1302:        do
        !          1303:        {
        !          1304:                if (*in)
        !          1305:                {
        !          1306:                        *out_p++ = *in++;
        !          1307:                        continue;
        !          1308:                }
        !          1309:        
        !          1310:                c = in[1];
        !          1311:                in += 2;
        !          1312:                if ((out_p - out) + c > row)
        !          1313:                {
        !          1314:                        c = row - (out_p - out);
        !          1315:                        Com_DPrintf ("warning: Vis decompression overrun\n");
        !          1316:                }
        !          1317:                while (c)
        !          1318:                {
        !          1319:                        *out_p++ = 0;
        !          1320:                        c--;
        !          1321:                }
        !          1322:        } while (out_p - out < row);
        !          1323: }
        !          1324: byte   pvsrow[MAX_MAP_LEAFS/8];
        !          1325: byte   phsrow[MAX_MAP_LEAFS/8];
        !          1326: byte   *CM_ClusterPVS (int cluster)
        !          1327: {
        !          1328:        if (cluster == -1)
        !          1329:                memset (pvsrow, 0, (numclusters+7)>>3);
        !          1330:        else
        !          1331:                CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow);
        !          1332:        return pvsrow;
        !          1333: }
        !          1334: byte   *CM_ClusterPHS (int cluster)
        !          1335: {
        !          1336:        if (cluster == -1)
        !          1337:                memset (phsrow, 0, (numclusters+7)>>3);
        !          1338:        else
        !          1339:                CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow);
        !          1340:        return phsrow;
        !          1341: }
        !          1342: /*
        !          1343: ===============================================================================
        !          1344: AREAPORTALS
        !          1345: ===============================================================================
        !          1346: */
        !          1347: void FloodArea_r (carea_t *area, int floodnum)
        !          1348: {
        !          1349:        int             i;
        !          1350:        dareaportal_t   *p;
        !          1351:        if (area->floodvalid == floodvalid)
        !          1352:        {
        !          1353:                if (area->floodnum == floodnum)
        !          1354:                        return;
        !          1355:                Com_Error (ERR_DROP, "FloodArea_r: reflooded");
        !          1356:        }
        !          1357:        area->floodnum = floodnum;
        !          1358:        area->floodvalid = floodvalid;
        !          1359:        p = &map_areaportals[area->firstareaportal];
        !          1360:        for (i=0 ; i<area->numareaportals ; i++, p++)
        !          1361:        {
        !          1362:                if (portalopen[p->portalnum])
        !          1363:                        FloodArea_r (&map_areas[p->otherarea], floodnum);
        !          1364:        }
        !          1365: }
        !          1366: /*
        !          1367: ====================
        !          1368: FloodAreaConnections
        !          1369: ====================
        !          1370: */
        !          1371: void   FloodAreaConnections (void)
        !          1372: {
        !          1373:        int             i;
        !          1374:        carea_t *area;
        !          1375:        int             floodnum;
        !          1376:        // all current floods are now invalid
        !          1377:        floodvalid++;
        !          1378:        floodnum = 0;
        !          1379:        // area 0 is not used
        !          1380:        for (i=1 ; i<numareas ; i++)
        !          1381:        {
        !          1382:                area = &map_areas[i];
        !          1383:                if (area->floodvalid == floodvalid)
        !          1384:                        continue;               // already flooded into
        !          1385:                floodnum++;
        !          1386:                FloodArea_r (area, floodnum);
        !          1387:        }
        !          1388: }
        !          1389: void   CM_SetAreaPortalState (int portalnum, qboolean open)
        !          1390: {
        !          1391:        if (portalnum > numareaportals)
        !          1392:                Com_Error (ERR_DROP, "areaportal > numareaportals");
        !          1393:        portalopen[portalnum] = open;
        !          1394:        FloodAreaConnections ();
        !          1395: }
        !          1396: qboolean       CM_AreasConnected (int area1, int area2)
        !          1397: {
        !          1398:        if (map_noareas->value)
        !          1399:                return true;
        !          1400:        if (area1 > numareas || area2 > numareas)
        !          1401:                Com_Error (ERR_DROP, "area > numareas");
        !          1402:        if (map_areas[area1].floodnum == map_areas[area2].floodnum)
        !          1403:                return true;
        !          1404:        return false;
        !          1405: }
        !          1406: /*
        !          1407: =================
        !          1408: CM_WriteAreaBits
        !          1409: Writes a length byte followed by a bit vector of all the areas
        !          1410: that area in the same flood as the area parameter
        !          1411: This is used by the client refreshes to cull visibility
        !          1412: =================
        !          1413: */
        !          1414: int CM_WriteAreaBits (byte *buffer, int area)
        !          1415: {
        !          1416:        int             i;
        !          1417:        int             floodnum;
        !          1418:        int             bytes;
        !          1419:        bytes = (numareas+7)>>3;
        !          1420:        if (map_noareas->value)
        !          1421:        {       // for debugging, send everything
        !          1422:                memset (buffer, 255, bytes);
        !          1423:        }
        !          1424:        else
        !          1425:        {
        !          1426:                memset (buffer, 0, bytes);
        !          1427:                floodnum = map_areas[area].floodnum;
        !          1428:                for (i=0 ; i<numareas ; i++)
        !          1429:                {
        !          1430:                        if (map_areas[i].floodnum == floodnum || !area)
        !          1431:                                buffer[i>>3] |= 1<<(i&7);
        !          1432:                }
        !          1433:        }
        !          1434:        return bytes;
        !          1435: }
        !          1436: /*
        !          1437: ===================
        !          1438: CM_WritePortalState
        !          1439: Writes the portal state to a savegame file
        !          1440: ===================
        !          1441: */
        !          1442: void   CM_WritePortalState (FILE *f)
        !          1443: {
        !          1444:        fwrite (portalopen, sizeof(portalopen), 1, f);
        !          1445: }
        !          1446: /*
        !          1447: ===================
        !          1448: CM_ReadPortalState
        !          1449: Reads the portal state from a savegame file
        !          1450: and recalculates the area connections
        !          1451: ===================
        !          1452: */
        !          1453: void   CM_ReadPortalState (FILE *f)
        !          1454: {
        !          1455:        FS_Read (portalopen, sizeof(portalopen), f);
        !          1456:        FloodAreaConnections ();
        !          1457: }
        !          1458: /*
        !          1459: =============
        !          1460: CM_HeadnodeVisible
        !          1461: Returns true if any leaf under headnode has a cluster that
        !          1462: is potentially visible
        !          1463: =============
        !          1464: */
        !          1465: qboolean CM_HeadnodeVisible (int nodenum, byte *visbits)
        !          1466: {
        !          1467:        int             leafnum;
        !          1468:        int             cluster;
        !          1469:        cnode_t *node;
        !          1470:        if (nodenum < 0)
        !          1471:        {
        !          1472:                leafnum = -1-nodenum;
        !          1473:                cluster = map_leafs[leafnum].cluster;
        !          1474:                if (cluster == -1)
        !          1475:                        return false;
        !          1476:                if (visbits[cluster>>3] & (1<<(cluster&7)))
        !          1477:                        return true;
        !          1478:                return false;
        !          1479:        }
        !          1480:        node = &map_nodes[nodenum];
        !          1481:        if (CM_HeadnodeVisible(node->children[0], visbits))
        !          1482:                return true;
        !          1483:        return CM_HeadnodeVisible(node->children[1], visbits);
        !          1484: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.