REDRIVER2/src_rebuild/Game/C/map.c
2022-01-29 13:39:06 +03:00

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;
}
}