This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/physic/cm_portals.c

211 lines
4.8 KiB
C

//=======================================================================
// Copyright XashXT Group 2007 ©
// cm_portals.c - server visibility
//=======================================================================
#include "cm_local.h"
/*
===============================================================================
PVS / PHS
===============================================================================
*/
/*
===================
CM_DecompressVis
===================
*/
void CM_DecompressVis( byte *in, byte *out )
{
byte *out_p;
int c, row;
row = (cm.numclusters + 7)>>3;
out_p = out;
if( !in )
{
// no vis info, so make all visible
while( row )
{
*out_p++ = 0xff;
row--;
}
return;
}
do
{
if(*in)
{
*out_p++ = *in++;
continue;
}
c = in[1];
in += 2;
if((out_p - out) + c > row)
{
c = row - (out_p - out);
MsgDev(D_WARN, "CM_DecompressVis: decompression overrun\n");
}
while( c )
{
*out_p++ = 0;
c--;
}
} while( out_p - out < row );
}
byte *CM_ClusterPVS( int cluster )
{
if( cluster < 0 || cluster >= cm.numclusters || !cm.vis )
Mem_Set( cm.pvsrow, 0xFF, (cm.numclusters + 31) & ~31 );
else CM_DecompressVis( cm.visbase + cm.vis->bitofs[cluster][DVIS_PVS], cm.pvsrow );
return cm.pvsrow;
}
byte *CM_ClusterPHS( int cluster )
{
if( cluster < 0 || cluster >= cm.numclusters || !cm.vis )
Mem_Set( cm.phsrow, 0xFF, (cm.numclusters + 31) & ~31 );
else CM_DecompressVis( cm.visbase + cm.vis->bitofs[cluster][DVIS_PHS], cm.phsrow );
return cm.phsrow;
}
/*
===============================================================================
AREAPORTALS
===============================================================================
*/
void CM_FloodArea_r( int areanum, int floodnum )
{
carea_t *area;
int i, *con;
area = &cm.areas[areanum];
if( area->floodvalid == cm.floodvalid )
{
if( area->floodnum == floodnum ) return;
Host_Error("FloodArea_r: reflooded\n");
}
area->floodnum = floodnum;
area->floodvalid = cm.floodvalid;
con = cm.areaportals + areanum * cm.numareas;
for( i = 0; i < cm.numareas; i++ )
if( con[i] > 0 ) CM_FloodArea_r( i, floodnum );
}
/*
====================
CM_FloodAreaConnections
====================
*/
void CM_FloodAreaConnections( void )
{
carea_t *area;
int i, floodnum = 0;
// all current floods are now invalid
cm.floodvalid++;
// area 0 is not used
for( i = 0, area = cm.areas; i < cm.numareas; i++, area++ )
{
if( area->floodvalid == cm.floodvalid )
continue; // already flooded into
floodnum++;
CM_FloodArea_r( i, floodnum );
}
}
void CM_SetAreaPortals ( byte *portals, size_t size )
{
if( size == cm.areaportals_size )
{
Mem_Copy( cm.areaportals, portals, cm.areaportals_size );
CM_FloodAreaConnections();
return;
}
MsgDev( D_ERROR, "CM_SetAreaPortals: portals mismatch size (%i should be %i)\n", size, cm.areaportals_size );
}
void CM_GetAreaPortals ( byte **portals, size_t *size )
{
byte *prt = *portals;
if( prt ) Mem_Copy( prt, cm.areaportals, cm.areaportals_size );
if( size) *size = cm.areaportals_size;
}
void CM_SetAreaPortalState( int area1, int area2, bool open )
{
if( area1 < 0 || area2 < 0 ) return;
if( area1 >= cm.numareas || area2 >= cm.numareas )
Host_Error( "CM_SetAreaPortalState: bad area numbers %i or %i\n", area1, area2 );
if( open )
{
cm.areaportals[area1*cm.numareas+area2]++;
cm.areaportals[area2*cm.numareas+area1]++;
}
else
{
cm.areaportals[area1*cm.numareas+area2]--;
cm.areaportals[area2*cm.numareas+area1]--;
if(cm.areaportals[area2*cm.numareas+area1] < 0 )
Host_Error( "CM_SetAreaPortalState: negative reference count\n" );
}
CM_FloodAreaConnections();
}
bool CM_AreasConnected( int area, int otherarea )
{
if( cm_noareas->integer ) return true;
if( area > cm.numareas || otherarea > cm.numareas )
Host_Error("CM_AreasConnected: area >= cm.numareas\n" );
if( area < 0 || otherarea < 0 ) return false;
if( area == otherarea ) return true; // quick test
if( cm.areas[area].floodnum == cm.areas[otherarea].floodnum )
return true;
return false;
}
/*
=================
CM_WriteAreaBits
Writes a length byte followed by a bit vector of all the areas
that area in the same flood as the area parameter
This is used by the client refreshes to cull visibility
=================
*/
int CM_WriteAreaBits( byte *buffer, int area )
{
int i, size, floodnum;
size = (cm.numareas + 7)>>3;
if( cm_noareas->integer || area == -1 )
{
Mem_Set( buffer, 0xFF, size );
}
else
{
floodnum = cm.areas[area].floodnum;
for( i = 0; i < cm.numareas; i++ )
{
if( cm.areas[i].floodnum == floodnum || area == -1 )
buffer[i>>3] |= 1 << (i & 7);
}
}
return size;
}