mirror of
https://github.com/OpenDriver2/REDRIVER2.git
synced 2024-11-22 18:32:42 +01:00
694 lines
14 KiB
C
694 lines
14 KiB
C
#include "driver2.h"
|
|
#include "map.h"
|
|
#include "system.h"
|
|
#include "spool.h"
|
|
#include "convert.h"
|
|
#include "texture.h"
|
|
#include "mission.h"
|
|
#include "draw.h"
|
|
#include "camera.h"
|
|
#include "glaunch.h"
|
|
#include "players.h"
|
|
#include "main.h"
|
|
|
|
char *map_lump = NULL;
|
|
int initarea = 0;
|
|
int LoadedArea;
|
|
|
|
int current_region = 0;
|
|
int old_region = 0;
|
|
|
|
int current_cell_x = 0;
|
|
int current_cell_z = 0;
|
|
|
|
int num_regions;
|
|
int view_dist;
|
|
int pvs_square;
|
|
int pvs_square_sq;
|
|
|
|
int units_across_halved;
|
|
int units_down_halved;
|
|
|
|
int regions_across;
|
|
int regions_down;
|
|
|
|
PACKED_CELL_OBJECT** pcoplist;
|
|
CELL_OBJECT** coplist;
|
|
|
|
OUT_CELL_FILE_HEADER cell_header;
|
|
|
|
int cells_across = 1000;
|
|
int cells_down = 1000;
|
|
|
|
unsigned short* cell_ptrs;
|
|
PACKED_CELL_OBJECT* cell_objects;
|
|
int sizeof_cell_object_computed_values;
|
|
CELL_DATA* cells;
|
|
int num_straddlers; // objects between regions
|
|
|
|
#define MAX_REGIONS 1024
|
|
|
|
// [D] [T]
|
|
void InitCellData(void)
|
|
{
|
|
int loop;
|
|
|
|
D_MALLOC_BEGIN();
|
|
|
|
cell_ptrs = (ushort*)D_MALLOC(4096 * sizeof(short));
|
|
|
|
// init cell pointers
|
|
for (loop = 0; loop < 4096; loop++)
|
|
cell_ptrs[loop] = 0xFF;
|
|
|
|
// (mallocptr + 8192);
|
|
cell_objects = (PACKED_CELL_OBJECT*)D_MALLOC((num_straddlers + cell_objects_add[4]) * sizeof(PACKED_CELL_OBJECT));
|
|
cells = (CELL_DATA*)D_MALLOC(cell_slots_add[4] * sizeof(CELL_DATA));
|
|
|
|
D_MALLOC_END();
|
|
|
|
sizeof_cell_object_computed_values = (num_straddlers + cell_objects_add[4] + 7) / sizeof(PACKED_CELL_OBJECT);
|
|
}
|
|
|
|
// [D] [T]
|
|
void ProcessMapLump(char* lump_ptr, int lump_size)
|
|
{
|
|
memcpy((u_char*)&cell_header, (u_char*)lump_ptr, sizeof(OUT_CELL_FILE_HEADER));
|
|
|
|
cells_across = cell_header.cells_across;
|
|
cells_down = cell_header.cells_down;
|
|
num_regions = cell_header.num_regions;
|
|
|
|
#ifdef PSX
|
|
if(num_regions > MAX_REGIONS)
|
|
{
|
|
printError("MAX_REGIONS is too small , allocate at least %d !", num_regions);
|
|
trap(0x400);
|
|
}
|
|
|
|
if(cell_header.cell_size != MAP_CELL_SIZE)
|
|
{
|
|
printError("Error LevEdit cellsize %d whilst PSX cellsize %d\n", cell_header.cell_size, MAP_CELL_SIZE);
|
|
trap(0x400);
|
|
}
|
|
|
|
if (cell_header.region_size != MAP_REGION_SIZE)
|
|
{
|
|
printError("Error LevEdit regionsize %d whilst PSX regionsize %d\n", cell_header.region_size, MAP_REGION_SIZE);
|
|
trap(0x400);
|
|
}
|
|
#endif
|
|
|
|
view_dist = 10;
|
|
pvs_square = 21;
|
|
pvs_square_sq = 21 * 21;
|
|
|
|
units_across_halved = cells_across / 2 * MAP_CELL_SIZE;
|
|
units_down_halved = cells_down / 2 * MAP_CELL_SIZE;
|
|
|
|
regions_across = cells_across / MAP_REGION_SIZE;
|
|
regions_down = cells_down / MAP_REGION_SIZE;
|
|
|
|
lump_ptr += sizeof(OUT_CELL_FILE_HEADER);
|
|
|
|
num_straddlers = *(int*)lump_ptr;
|
|
|
|
InitCellData();
|
|
memcpy((u_char*)cell_objects, (u_char*)lump_ptr + 4, num_straddlers * sizeof(PACKED_CELL_OBJECT));
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void NewProcessRoadMapLump(ROAD_MAP_LUMP_DATA *pRoadMapLumpData, char *pLumpFile)
|
|
{
|
|
Getlong((char*)&pRoadMapLumpData->width, pLumpFile);
|
|
Getlong((char*)&pRoadMapLumpData->height, pLumpFile + 4);
|
|
|
|
pRoadMapLumpData->unitXMid = (pRoadMapLumpData->width + 1) * 512;
|
|
pRoadMapLumpData->unitZMid = pRoadMapLumpData->height * 512;
|
|
}
|
|
|
|
// [D] [T]
|
|
void ProcessJunctionsLump(char *lump_file, int lump_size)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void ProcessRoadsLump(char *lump_file, int lump_size)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// [D] [T]
|
|
void ProcessRoadBoundsLump(char *lump_file, int lump_size)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// [D] [T]
|
|
void ProcessJuncBoundsLump(char *lump_file, int lump_size)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// [D] [T]
|
|
int newPositionVisible(VECTOR *pos, char *pvs, int ccx, int ccz)
|
|
{
|
|
int dx; // $a2
|
|
int dz; // $a0
|
|
int cellx; // $v1
|
|
int cellz; // $v0
|
|
|
|
dx = pos->vx + units_across_halved;
|
|
dz = pos->vz + units_down_halved;
|
|
|
|
cellx = (dx / MAP_CELL_SIZE) - ccx;
|
|
cellz = (dz / MAP_CELL_SIZE) - ccz;
|
|
|
|
if (ABS(cellx) <= view_dist && ABS(cellz) <= view_dist)
|
|
{
|
|
return pvs[cellx + 10 + (cellz + 10) * pvs_square] != 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// [D] [T]
|
|
int PositionVisible(VECTOR *pos)
|
|
{
|
|
int dx; // $a1
|
|
int dz; // $a0
|
|
int cellx; // $v1
|
|
int cellz; // $v0
|
|
|
|
int ab;
|
|
|
|
dx = pos->vx + units_across_halved;
|
|
dz = pos->vz + units_down_halved;
|
|
|
|
cellx = (dx / MAP_CELL_SIZE) - current_cell_x;
|
|
cellz = (dz / MAP_CELL_SIZE) - current_cell_z;
|
|
|
|
if (cellx < 0)
|
|
ab = -cellx;
|
|
else
|
|
ab = cellx;
|
|
|
|
if (ab <= view_dist)
|
|
{
|
|
if (cellz < 0)
|
|
ab = -cellz;
|
|
else
|
|
ab = cellz;
|
|
|
|
if (ab <= view_dist)
|
|
return CurrentPVS[cellx + 10 + (cellz + 10) * pvs_square] != 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// FIXME: move it somewhere else
|
|
extern int saved_leadcar_pos;
|
|
|
|
int region_x = 0;
|
|
int region_z = 0;
|
|
|
|
int current_barrel_region_xcell = 0;
|
|
int current_barrel_region_zcell = 0;
|
|
|
|
// [D] [T]
|
|
int CheckUnpackNewRegions(void)
|
|
{
|
|
ushort sort;
|
|
ushort *destsort;
|
|
ushort *srcsort;
|
|
|
|
int x, z;
|
|
int i, j;
|
|
int sortcount;
|
|
int leftright_unpack, topbottom_unpack;
|
|
int target_region, region_to_unpack;
|
|
int num_regions_to_unpack;
|
|
int force_load_boundary;
|
|
AREA_LOAD_INFO regions_to_unpack[3];
|
|
SVECTOR sortregions[4];
|
|
ushort sortorder[4];
|
|
|
|
leftright_unpack = 0;
|
|
topbottom_unpack = 0;
|
|
num_regions_to_unpack = 0;
|
|
|
|
if (saved_leadcar_pos != 0)
|
|
return 0;
|
|
|
|
force_load_boundary = 13;
|
|
|
|
if (lead_car == 0)
|
|
force_load_boundary = 18;
|
|
|
|
if (current_barrel_region_xcell < force_load_boundary)
|
|
{
|
|
if (region_x != 0)
|
|
{
|
|
leftright_unpack = 1;
|
|
num_regions_to_unpack = 1;
|
|
regions_to_unpack[0].xoffset = -1;
|
|
regions_to_unpack[0].zoffset = 0;
|
|
}
|
|
}
|
|
else if (32 - force_load_boundary < current_barrel_region_xcell)
|
|
{
|
|
if (region_x < regions_across)
|
|
{
|
|
leftright_unpack = 2;
|
|
num_regions_to_unpack = 1;
|
|
regions_to_unpack[0].xoffset = 1;
|
|
regions_to_unpack[0].zoffset = 0;
|
|
}
|
|
}
|
|
|
|
if (current_barrel_region_zcell < force_load_boundary)
|
|
{
|
|
if (region_z != 0)
|
|
{
|
|
topbottom_unpack = 1;
|
|
regions_to_unpack[num_regions_to_unpack].xoffset = 0;
|
|
regions_to_unpack[num_regions_to_unpack].zoffset = -1;
|
|
num_regions_to_unpack++;
|
|
}
|
|
}
|
|
else if (32 - force_load_boundary < current_barrel_region_zcell && region_z != 0)
|
|
{
|
|
topbottom_unpack = 2;
|
|
regions_to_unpack[num_regions_to_unpack].xoffset = 0;
|
|
regions_to_unpack[num_regions_to_unpack].zoffset = 1;
|
|
num_regions_to_unpack++;
|
|
}
|
|
|
|
if (num_regions_to_unpack == 2)
|
|
{
|
|
if (topbottom_unpack == 1)
|
|
{
|
|
if (leftright_unpack == 1)
|
|
{
|
|
regions_to_unpack[2].xoffset = -1;
|
|
regions_to_unpack[2].zoffset = -1;
|
|
}
|
|
else
|
|
{
|
|
regions_to_unpack[2].xoffset = 1;
|
|
regions_to_unpack[2].zoffset = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (leftright_unpack == 1)
|
|
regions_to_unpack[2].xoffset = -1;
|
|
else
|
|
regions_to_unpack[2].xoffset = 1;
|
|
|
|
regions_to_unpack[2].zoffset = 1;
|
|
}
|
|
num_regions_to_unpack = 3;
|
|
}
|
|
|
|
// get next region a space
|
|
for (i = 0, sortcount = 0; i < num_regions_to_unpack; i++)
|
|
{
|
|
x = regions_to_unpack[i].xoffset;
|
|
z = regions_to_unpack[i].zoffset;
|
|
|
|
target_region = (region_x + x & 1U) + (region_z + z & 1U) * 2;
|
|
region_to_unpack = current_region + x + z * (cells_across / 32);
|
|
|
|
if (region_to_unpack != regions_unpacked[target_region] && loading_region[target_region] == -1)
|
|
{
|
|
ClearRegion(target_region);
|
|
|
|
if (spoolinfo_offsets[region_to_unpack] == 0xffff)
|
|
{
|
|
regions_unpacked[target_region] = region_to_unpack;
|
|
}
|
|
else
|
|
{
|
|
Spool *spoolptr = (Spool*)(RegionSpoolInfo + spoolinfo_offsets[region_to_unpack]);
|
|
|
|
if (old_region == -1 && spoolptr->super_region != 0xFF)
|
|
initarea = spoolptr->super_region;
|
|
|
|
sortregions[sortcount].vx = region_to_unpack;
|
|
sortregions[sortcount].vy = target_region;
|
|
sortregions[sortcount].vz = spoolptr->offset;
|
|
|
|
sortorder[sortcount] = sortcount;
|
|
sortcount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < sortcount; i++)
|
|
{
|
|
if (sortcount > (i + 1))
|
|
{
|
|
srcsort = sortorder + i;
|
|
destsort = sortorder + (i + 1);
|
|
|
|
j = sortcount - (i + 1);
|
|
|
|
do {
|
|
sort = *srcsort;
|
|
if (sortregions[*destsort].vz < sortregions[*srcsort].vz)
|
|
{
|
|
*srcsort = *destsort;
|
|
*destsort = sort;
|
|
}
|
|
|
|
j--;
|
|
destsort++;
|
|
} while (j > 0);
|
|
}
|
|
|
|
UnpackRegion(sortregions[sortorder[i]].vx, sortregions[sortorder[i]].vy);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// [D] [T]
|
|
void ControlMap(void)
|
|
{
|
|
int region_to_unpack;
|
|
|
|
current_cell_x = (player[0].spoolXZ->vx + units_across_halved) / MAP_CELL_SIZE;
|
|
current_cell_z = (player[0].spoolXZ->vz + units_down_halved) / MAP_CELL_SIZE;
|
|
|
|
region_x = current_cell_x / MAP_REGION_SIZE;
|
|
region_z = current_cell_z / MAP_REGION_SIZE;
|
|
|
|
old_region = current_region;
|
|
|
|
current_barrel_region_xcell = current_cell_x - region_x * MAP_REGION_SIZE;
|
|
current_barrel_region_zcell = current_cell_z - region_z * MAP_REGION_SIZE;
|
|
|
|
region_to_unpack = region_x + region_z * regions_across;
|
|
|
|
if (current_region == -1)
|
|
UnpackRegion(region_to_unpack, region_x & 1U | (region_z & 1U) * 2);
|
|
|
|
current_region = region_to_unpack;
|
|
|
|
CheckLoadAreaData(current_barrel_region_xcell, current_barrel_region_zcell);
|
|
|
|
CheckUnpackNewRegions();
|
|
|
|
current_cell_x = (camera_position.vx + units_across_halved) / MAP_CELL_SIZE;
|
|
current_cell_z = (camera_position.vz + units_down_halved) / MAP_CELL_SIZE;
|
|
|
|
StartSpooling();
|
|
}
|
|
|
|
// [D] [T]
|
|
void InitMap(void)
|
|
{
|
|
int region_to_unpack;
|
|
int barrel_region;
|
|
int i;
|
|
|
|
initarea = -1;
|
|
LoadedArea = -1;
|
|
current_region = -1;
|
|
|
|
i = slotsused;
|
|
|
|
while (i < 19)
|
|
{
|
|
int tpage = tpageslots[i];
|
|
|
|
if (tpage != 0xff)
|
|
tpageloaded[tpage] = 0;
|
|
|
|
tpageslots[i] = 0xff;
|
|
i++;
|
|
}
|
|
|
|
// load regions synchronously
|
|
if (doSpooling)
|
|
{
|
|
regions_unpacked[0] = -1;
|
|
regions_unpacked[1] = -1;
|
|
regions_unpacked[2] = -1;
|
|
regions_unpacked[3] = -1;
|
|
|
|
ControlMap();
|
|
}
|
|
else
|
|
{
|
|
old_region = -1;
|
|
|
|
if (multiplayerregions[1] == -1)
|
|
{
|
|
multiplayerregions[1] = multiplayerregions[0] + 1;
|
|
multiplayerregions[2] = multiplayerregions[0] - (cells_across >> 5);
|
|
multiplayerregions[3] = multiplayerregions[2] + 1;
|
|
}
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
region_to_unpack = multiplayerregions[i];
|
|
|
|
if (spoolinfo_offsets[region_to_unpack] != 0xffff)
|
|
{
|
|
Spool* spoolptr = (Spool*)(RegionSpoolInfo + spoolinfo_offsets[region_to_unpack]);
|
|
|
|
if (spoolptr->super_region != 0xff)
|
|
initarea = spoolptr->super_region;
|
|
|
|
barrel_region = (region_to_unpack % regions_across & 1U) +
|
|
(region_to_unpack / regions_across & 1U) * 2;
|
|
|
|
UnpackRegion(region_to_unpack, barrel_region);
|
|
}
|
|
}
|
|
|
|
LoadInAreaTSets(initarea);
|
|
LoadInAreaModels(initarea);
|
|
|
|
current_cell_x = (camera_position.vx + units_across_halved) / MAP_CELL_SIZE;
|
|
current_cell_z = (camera_position.vz + units_down_halved) / MAP_CELL_SIZE;
|
|
|
|
StartSpooling();
|
|
}
|
|
}
|
|
|
|
// [D] [T] [A]
|
|
void GetVisSetAtPosition(VECTOR *pos, char *tgt, int *ccx, int *ccz)
|
|
{
|
|
int cx, cz;
|
|
int rx, rz;
|
|
|
|
cx = (pos->vx + units_across_halved) / MAP_CELL_SIZE;
|
|
cz = (pos->vz + units_down_halved) / MAP_CELL_SIZE;
|
|
|
|
*ccx = cx;
|
|
*ccz = cz;
|
|
|
|
rx = cx / MAP_REGION_SIZE;
|
|
rz = cz / MAP_REGION_SIZE;
|
|
|
|
int barrel_region_x = (rx & 1);
|
|
int barrel_region_z = (rz & 1);
|
|
|
|
GetPVSRegionCell2(
|
|
barrel_region_x + barrel_region_z * 2,
|
|
rx + rz * regions_across,
|
|
(cz - rz * MAP_REGION_SIZE) * MAP_REGION_SIZE + cx - rx * MAP_REGION_SIZE,
|
|
tgt);
|
|
}
|
|
|
|
char* PVS_Buffers[4] = { 0 };
|
|
int pvsSize[4] = { 0, 0, 0, 0 };
|
|
unsigned char *PVSEncodeTable = NULL;
|
|
|
|
// [D] [T]
|
|
void PVSDecode(char *output, char *celldata, ushort sz, int havanaCorruptCellBodge)
|
|
{
|
|
u_char* nybblearray;
|
|
int pixelIndex;
|
|
u_char* decodebuf;
|
|
u_char* op;
|
|
int i, j;
|
|
int symIndex;
|
|
int size;
|
|
|
|
decodebuf = (u_char*)getScratchAddr(0);
|
|
nybblearray = (u_char*)getScratchAddr(0) + pvs_square_sq;
|
|
|
|
ClearMem((char*)decodebuf,pvs_square_sq);
|
|
|
|
// decode byte-swapped array
|
|
for (i = 0; i < sz; i++)
|
|
((ushort*)nybblearray)[i] = M_SHRT_2((unsigned char)celldata[i], (unsigned char)celldata[i] >> 4) & 0xf0f;
|
|
|
|
pixelIndex = 0;
|
|
symIndex = 0;
|
|
i = 0;
|
|
|
|
// decompress image
|
|
while (i < sz * 2)
|
|
{
|
|
int ni;
|
|
int sym;
|
|
|
|
ni = nybblearray[i];
|
|
i++;
|
|
|
|
if (ni < 12)
|
|
{
|
|
symIndex = ni * 2;
|
|
spod:
|
|
sym = M_SHRT_2(PVSEncodeTable[symIndex], PVSEncodeTable[symIndex + 1]);
|
|
}
|
|
else
|
|
{
|
|
if (i == sz*2)
|
|
break;
|
|
|
|
sym = (ni & 3) * 16 + nybblearray[i];
|
|
i++;
|
|
|
|
if (sym < 60)
|
|
{
|
|
symIndex = sym * 2 + 24;
|
|
goto spod;
|
|
}
|
|
|
|
sym = ((sym & 3) * 16 + nybblearray[i]) * 16 + nybblearray[i+1];
|
|
i += 2;
|
|
}
|
|
|
|
pixelIndex += (sym >> 1);
|
|
decodebuf[pixelIndex] = 1;
|
|
pixelIndex++;
|
|
|
|
if ((sym & 1) != 0)
|
|
{
|
|
decodebuf[pixelIndex] = 1;
|
|
pixelIndex++;
|
|
}
|
|
}
|
|
|
|
if (havanaCorruptCellBodge == 0)
|
|
decodebuf[pvs_square_sq-1] ^= 1;
|
|
|
|
size = pvs_square - 2;
|
|
|
|
op = (decodebuf - 1) + (size * pvs_square + pvs_square);
|
|
i = size;
|
|
while (i >= 0)
|
|
{
|
|
i--;
|
|
j = pvs_square;
|
|
while (j > 0)
|
|
{
|
|
*op = *op ^ op[pvs_square];
|
|
j--;
|
|
op--;
|
|
}
|
|
}
|
|
|
|
size = pvs_square - 1;
|
|
op = (decodebuf - 2) + (size * pvs_square + pvs_square);
|
|
|
|
i = size;
|
|
while (i >= 0)
|
|
{
|
|
j = pvs_square-2;
|
|
while (j >= 0)
|
|
{
|
|
*op = *op ^ op[1];
|
|
j--;
|
|
op--;
|
|
}
|
|
i--;
|
|
op--;
|
|
}
|
|
|
|
#if 0
|
|
printf("=========================\n");
|
|
for (i = 0; i < pvs_square; i++)
|
|
{
|
|
char line[64];
|
|
memcpy(line, (char*)decodebuf + i * pvs_square, pvs_square);
|
|
for (j = 0; j < pvs_square; j++)
|
|
{
|
|
if (line[j] == 0)
|
|
line[j] = '.';
|
|
else
|
|
line[j] = 'O';
|
|
}
|
|
line[j] = 0;
|
|
printf("%s\n", line);
|
|
}
|
|
printf("=========================\n");
|
|
#endif
|
|
memcpy((u_char*)output, decodebuf, pvs_square_sq-1); // 110*4
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void GetPVSRegionCell2(int source_region, int region, int cell, char *output)
|
|
{
|
|
int k;
|
|
u_int havanaCorruptCellBodge;
|
|
char *tbp;
|
|
char *bp;
|
|
ushort length;
|
|
|
|
#ifndef PSX
|
|
if (gDemoLevel)
|
|
{
|
|
// don't draw non-loaded regions
|
|
for (k = 0; k < pvs_square_sq; k++)
|
|
output[k] = 1;
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (regions_unpacked[source_region] == region && loading_region[source_region] == -1)
|
|
{
|
|
bp = PVS_Buffers[source_region];
|
|
PVSEncodeTable = (u_char *)(bp + 0x802);
|
|
tbp = bp + cell * 2;
|
|
|
|
length = M_SHRT_2((u_char)tbp[2], (u_char)tbp[3]) - M_SHRT_2((u_char)tbp[0], (u_char)tbp[1]) & 0xffff;
|
|
|
|
if (length != 0)
|
|
{
|
|
havanaCorruptCellBodge = (regions_unpacked[source_region] == 158 && cell == 168);
|
|
|
|
PVSDecode(output, bp + M_SHRT_2((u_char)tbp[0], (u_char)tbp[1]), length, havanaCorruptCellBodge);
|
|
}
|
|
else
|
|
{
|
|
for (k = 0; k < pvs_square_sq; k++)
|
|
output[k] = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// don't draw non-loaded regions
|
|
for (k = 0; k < pvs_square_sq; k++)
|
|
output[k] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|