Quake II RTX doxygen  1.0 dev
bsp.c File Reference
#include "shared/shared.h"
#include "shared/list.h"
#include "common/cvar.h"
#include "common/cmd.h"
#include "common/common.h"
#include "common/files.h"
#include "common/bsp.h"
#include "common/math.h"
#include "common/utils.h"
#include "common/mdfour.h"
#include "system/hunk.h"

Go to the source code of this file.

Classes

struct  lump_info_t
 

Macros

#define ALLOC(size)   Hunk_Alloc(&bsp->hunk, size)
 
#define LOAD(func)   static qerror_t BSP_Load##func(bsp_t *bsp, void *base, size_t count)
 
#define DEBUG(msg)   Com_DPrintf("%s: %s\n", __func__, msg)
 
#define L(func, lump, disk_t, mem_t)   { BSP_Load##func, LUMP_##lump, sizeof(disk_t), sizeof(mem_t), MAX_MAP_##lump }
 

Functions

 LOAD (Visibility)
 
 LOAD (Texinfo)
 
 LOAD (Planes)
 
 LOAD (BrushSides)
 
 LOAD (Brushes)
 
 LOAD (LeafBrushes)
 
 LOAD (Leafs)
 
 LOAD (Nodes)
 
 LOAD (Submodels)
 
 LOAD (AreaPortals)
 
 LOAD (Areas)
 
 LOAD (EntString)
 
static void BSP_List_f (void)
 
static bsp_t * BSP_Find (const char *name)
 
static qerror_t BSP_SetParent (mnode_t *node, int key)
 
static qerror_t BSP_ValidateTree (bsp_t *bsp)
 
static qerror_t BSP_ValidateAreaPortals (bsp_t *bsp)
 
void BSP_Free (bsp_t *bsp)
 
static void BSP_BuildPvsMatrix (bsp_t *bsp)
 
char * BSP_GetPvs (bsp_t *bsp, int cluster)
 
char * BSP_GetPvs2 (bsp_t *bsp, int cluster)
 
static qboolean BSP_GetPatchedPVSFileName (const char *map_path, char pvs_path[MAX_QPATH])
 
static qboolean BSP_LoadPatchedPVS (bsp_t *bsp)
 
qboolean BSP_SavePatchedPVS (bsp_t *bsp)
 
qerror_t BSP_Load (const char *name, bsp_t **bsp_p)
 
byte * BSP_ClusterVis (bsp_t *bsp, byte *mask, int cluster, int vis)
 
mleaf_t * BSP_PointLeaf (mnode_t *node, vec3_t p)
 
mmodel_t * BSP_InlineModel (bsp_t *bsp, const char *name)
 
void BSP_Init (void)
 

Variables

mtexinfo_t nulltexinfo
 
static cvar_t * map_visibility_patch
 
static const lump_info_t bsp_lumps []
 
static list_t bsp_cache
 

Macro Definition Documentation

◆ ALLOC

#define ALLOC (   size)    Hunk_Alloc(&bsp->hunk, size)

Definition at line 47 of file bsp.c.

◆ DEBUG

#define DEBUG (   msg)    Com_DPrintf("%s: %s\n", __func__, msg)

Definition at line 53 of file bsp.c.

◆ L

#define L (   func,
  lump,
  disk_t,
  mem_t 
)    { BSP_Load##func, LUMP_##lump, sizeof(disk_t), sizeof(mem_t), MAX_MAP_##lump }

Definition at line 764 of file bsp.c.

◆ LOAD

#define LOAD (   func)    static qerror_t BSP_Load##func(bsp_t *bsp, void *base, size_t count)

Definition at line 50 of file bsp.c.

Function Documentation

◆ BSP_BuildPvsMatrix()

static void BSP_BuildPvsMatrix ( bsp_t *  bsp)
static

Definition at line 954 of file bsp.c.

955 {
956  if (!bsp->vis)
957  return;
958 
959  // a typical map with 2K clusters will take half a megabyte of memory for the matrix
960  size_t matrix_size = bsp->visrowsize * bsp->vis->numclusters;
961 
962  // allocate the matrix but don't set it in the BSP structure yet:
963  // we want BSP_CluterVis to use the old PVS data here, and not the new empty matrix
964  char* pvs_matrix = Z_Mallocz(matrix_size);
965 
966  for (int cluster = 0; cluster < bsp->vis->numclusters; cluster++)
967  {
968  BSP_ClusterVis(bsp, pvs_matrix + bsp->visrowsize * cluster, cluster, DVIS_PVS);
969  }
970 
971  bsp->pvs_matrix = pvs_matrix;
972 }

Referenced by BSP_Load().

◆ BSP_ClusterVis()

byte* BSP_ClusterVis ( bsp_t *  bsp,
byte *  mask,
int  cluster,
int  vis 
)

Definition at line 1339 of file bsp.c.

1340 {
1341  byte *in, *out, *in_end, *out_end;
1342  int c;
1343 
1344  if (!bsp || !bsp->vis) {
1345  return memset(mask, 0xff, VIS_MAX_BYTES);
1346  }
1347  if (cluster == -1) {
1348  return memset(mask, 0, bsp->visrowsize);
1349  }
1350  if (cluster < 0 || cluster >= bsp->vis->numclusters) {
1351  Com_Error(ERR_DROP, "%s: bad cluster", __func__);
1352  }
1353 
1354  if (vis == DVIS_PVS2)
1355  {
1356  if (bsp->pvs2_matrix)
1357  {
1358  char* row = BSP_GetPvs2(bsp, cluster);
1359  memcpy(mask, row, bsp->visrowsize);
1360  return mask;
1361  }
1362 
1363  // fallback
1364  vis = DVIS_PVS;
1365  }
1366 
1367  if (vis == DVIS_PVS && bsp->pvs_matrix)
1368  {
1369  char* row = BSP_GetPvs(bsp, cluster);
1370  memcpy(mask, row, bsp->visrowsize);
1371  return mask;
1372  }
1373 
1374  // decompress vis
1375  in_end = (byte *)bsp->vis + bsp->numvisibility;
1376  in = (byte *)bsp->vis + bsp->vis->bitofs[cluster][vis];
1377  out_end = mask + bsp->visrowsize;
1378  out = mask;
1379  do {
1380  if (in >= in_end) {
1381  goto overrun;
1382  }
1383  if (*in) {
1384  *out++ = *in++;
1385  continue;
1386  }
1387 
1388  if (in + 1 >= in_end) {
1389  goto overrun;
1390  }
1391  c = in[1];
1392  in += 2;
1393  if (out + c > out_end) {
1394 overrun:
1395  c = out_end - out;
1396  }
1397  while (c--) {
1398  *out++ = 0;
1399  }
1400  } while (out < out_end);
1401 
1402  // apply our ugly PVS patches
1403  if (map_visibility_patch->integer) {
1404  if (bsp->checksum == 0x1e5b50c5) {
1405  // q2dm3, pent bridge
1406  if (cluster == 345 || cluster == 384) {
1407  Q_SetBit(mask, 466);
1408  Q_SetBit(mask, 484);
1409  Q_SetBit(mask, 692);
1410  }
1411  } else if (bsp->checksum == 0x04cfa792) {
1412  // q2dm1, above lower RL
1413  if (cluster == 395) {
1414  Q_SetBit(mask, 176);
1415  Q_SetBit(mask, 183);
1416  }
1417  } else if (bsp->checksum == 0x2c3ab9b0) {
1418  // q2dm8, CG/RG area
1419  if (cluster == 629 || cluster == 631 ||
1420  cluster == 633 || cluster == 639) {
1421  Q_SetBit(mask, 908);
1422  Q_SetBit(mask, 909);
1423  Q_SetBit(mask, 910);
1424  Q_SetBit(mask, 915);
1425  Q_SetBit(mask, 923);
1426  Q_SetBit(mask, 924);
1427  Q_SetBit(mask, 927);
1428  Q_SetBit(mask, 930);
1429  Q_SetBit(mask, 938);
1430  Q_SetBit(mask, 939);
1431  Q_SetBit(mask, 947);
1432  }
1433  }
1434  }
1435 
1436  return mask;
1437 }

Referenced by BSP_BuildPvsMatrix(), CM_FatPVS(), GL_MarkLeaves(), MVD_ParseMulticast(), MVD_ParseSound(), PF_inVIS(), PF_StartSound(), R_MarkLeaves(), SV_BuildClientFrame(), SV_Multicast(), and vkpt_show_pvs().

◆ BSP_Find()

static bsp_t* BSP_Find ( const char *  name)
static

Definition at line 816 of file bsp.c.

817 {
818  bsp_t *bsp;
819 
820  LIST_FOR_EACH(bsp_t, bsp, &bsp_cache, entry) {
821  if (!FS_pathcmp(bsp->name, name)) {
822  return bsp;
823  }
824  }
825 
826  return NULL;
827 }

Referenced by BSP_Load().

◆ BSP_Free()

void BSP_Free ( bsp_t *  bsp)

Definition at line 932 of file bsp.c.

933 {
934  if (!bsp) {
935  return;
936  }
937  if (bsp->refcount <= 0) {
938  Com_Error(ERR_FATAL, "%s: negative refcount", __func__);
939  }
940  if (--bsp->refcount == 0) {
941  if (bsp->pvs2_matrix)
942  {
943  // free the PVS2 matrix separately - it's not part of the hunk
944  Z_Free(bsp->pvs2_matrix);
945  bsp->pvs2_matrix = NULL;
946  }
947 
948  Hunk_Free(&bsp->hunk);
949  List_Remove(&bsp->entry);
950  Z_Free(bsp);
951  }
952 }

Referenced by BSP_Test_f(), CL_ClearState(), CM_FreeMap(), GL_FreeWorld(), MVD_GameInit(), R_BeginRegistration(), R_BeginRegistration_RTX(), and R_Shutdown().

◆ BSP_GetPatchedPVSFileName()

static qboolean BSP_GetPatchedPVSFileName ( const char *  map_path,
char  pvs_path[MAX_QPATH] 
)
static

Definition at line 997 of file bsp.c.

998 {
999  int path_len = strlen(map_path);
1000  if (path_len < 5 || strcmp(map_path + path_len - 4, ".bsp") != 0)
1001  return qfalse;
1002 
1003  const char* map_file = strrchr(map_path, '/');
1004  if (map_file)
1005  map_file += 1;
1006  else
1007  map_file = map_path;
1008 
1009  memset(pvs_path, 0, MAX_QPATH);
1010  strncpy(pvs_path, map_path, map_file - map_path);
1011  strcat(pvs_path, "pvs/");
1012  strncat(pvs_path, map_file, strlen(map_file) - 4);
1013  strcat(pvs_path, ".bin");
1014 
1015  return qtrue;
1016 }

Referenced by BSP_LoadPatchedPVS(), and BSP_SavePatchedPVS().

◆ BSP_GetPvs()

char* BSP_GetPvs ( bsp_t *  bsp,
int  cluster 
)

Definition at line 974 of file bsp.c.

975 {
976  if (!bsp->vis || !bsp->pvs_matrix)
977  return NULL;
978 
979  if (cluster < 0 || cluster >= bsp->vis->numclusters)
980  return NULL;
981 
982  return bsp->pvs_matrix + bsp->visrowsize * cluster;
983 }

Referenced by BSP_ClusterVis(), build_pvs2(), collect_cluster_lights(), collect_surfaces(), compute_sky_visibility(), connect_pvs(), inject_model_lights(), and make_pvs_symmetric().

◆ BSP_GetPvs2()

char* BSP_GetPvs2 ( bsp_t *  bsp,
int  cluster 
)

Definition at line 985 of file bsp.c.

986 {
987  if (!bsp->vis || !bsp->pvs2_matrix)
988  return NULL;
989 
990  if (cluster < 0 || cluster >= bsp->vis->numclusters)
991  return NULL;
992 
993  return bsp->pvs2_matrix + bsp->visrowsize * cluster;
994 }

Referenced by BSP_ClusterVis(), and build_pvs2().

◆ BSP_Init()

void BSP_Init ( void  )

Definition at line 1477 of file bsp.c.

1478 {
1479  map_visibility_patch = Cvar_Get("map_visibility_patch", "1", 0);
1480 
1481  Cmd_AddCommand("bsplist", BSP_List_f);
1482 
1483  List_Init(&bsp_cache);
1484 }

Referenced by Qcommon_Init().

◆ BSP_InlineModel()

mmodel_t* BSP_InlineModel ( bsp_t *  bsp,
const char *  name 
)

Definition at line 1459 of file bsp.c.

1460 {
1461  int num;
1462 
1463  if (!bsp || !name) {
1464  Com_Error(ERR_DROP, "%s: NULL", __func__);
1465  }
1466  if (name[0] != '*') {
1467  Com_Error(ERR_DROP, "%s: bad name: %s", __func__, name);
1468  }
1469  num = atoi(name + 1);
1470  if (num < 1 || num >= bsp->nummodels) {
1471  Com_Error(ERR_DROP, "%s: bad number: %d", __func__, num);
1472  }
1473 
1474  return &bsp->models[num];
1475 }

Referenced by CL_RegisterBspModels(), and CL_UpdateConfigstring().

◆ BSP_List_f()

static void BSP_List_f ( void  )
static

Definition at line 795 of file bsp.c.

796 {
797  bsp_t *bsp;
798  size_t bytes;
799 
800  if (LIST_EMPTY(&bsp_cache)) {
801  Com_Printf("BSP cache is empty\n");
802  return;
803  }
804 
805  Com_Printf("------------------\n");
806  bytes = 0;
807 
808  LIST_FOR_EACH(bsp_t, bsp, &bsp_cache, entry) {
809  Com_Printf("%8"PRIz" : %s (%d refs)\n",
810  bsp->hunk.mapped, bsp->name, bsp->refcount);
811  bytes += bsp->hunk.mapped;
812  }
813  Com_Printf("Total resident: %"PRIz"\n", bytes);
814 }

Referenced by BSP_Init().

◆ BSP_Load()

qerror_t BSP_Load ( const char *  name,
bsp_t **  bsp_p 
)

Definition at line 1087 of file bsp.c.

1088 {
1089  bsp_t *bsp;
1090  byte *buf;
1091  dheader_t *header;
1092  const lump_info_t *info;
1093  size_t filelen, ofs, len, end, count;
1094  qerror_t ret;
1095  byte *lumpdata[HEADER_LUMPS];
1096  size_t lumpcount[HEADER_LUMPS];
1097  size_t memsize;
1098 
1099  if (!name || !bsp_p)
1100  Com_Error(ERR_FATAL, "%s: NULL", __func__);
1101 
1102  *bsp_p = NULL;
1103 
1104  if (!*name)
1105  return Q_ERR_NOENT;
1106 
1107  if ((bsp = BSP_Find(name)) != NULL) {
1108  Com_PageInMemory(bsp->hunk.base, bsp->hunk.cursize);
1109  bsp->refcount++;
1110  *bsp_p = bsp;
1111  return Q_ERR_SUCCESS;
1112  }
1113 
1114  //
1115  // load the file
1116  //
1117  filelen = FS_LoadFile(name, (void **)&buf);
1118  if (!buf) {
1119  return filelen;
1120  }
1121 
1122  // byte swap and validate the header
1123  header = (dheader_t *)buf;
1124  if (LittleLong(header->ident) != IDBSPHEADER) {
1125  ret = Q_ERR_UNKNOWN_FORMAT;
1126  goto fail2;
1127  }
1128  if (LittleLong(header->version) != BSPVERSION) {
1129  ret = Q_ERR_UNKNOWN_FORMAT;
1130  goto fail2;
1131  }
1132 
1133  // byte swap and validate all lumps
1134  memsize = 0;
1135  for (info = bsp_lumps; info->load; info++) {
1136  ofs = LittleLong(header->lumps[info->lump].fileofs);
1137  len = LittleLong(header->lumps[info->lump].filelen);
1138  end = ofs + len;
1139  if (end < ofs || end > filelen) {
1140  ret = Q_ERR_BAD_EXTENT;
1141  goto fail2;
1142  }
1143  if (len % info->disksize) {
1144  ret = Q_ERR_ODD_SIZE;
1145  goto fail2;
1146  }
1147  count = len / info->disksize;
1148  if (count > info->maxcount) {
1149  ret = Q_ERR_TOO_MANY;
1150  goto fail2;
1151  }
1152 
1153  lumpdata[info->lump] = buf + ofs;
1154  lumpcount[info->lump] = count;
1155 
1156  memsize += count * info->memsize;
1157  }
1158 
1159  // load into hunk
1160  len = strlen(name);
1161  bsp = Z_Mallocz(sizeof(*bsp) + len);
1162  memcpy(bsp->name, name, len + 1);
1163  bsp->refcount = 1;
1164 
1165  // add an extra page for cacheline alignment overhead
1166  Hunk_Begin(&bsp->hunk, memsize + 4096);
1167 
1168  // calculate the checksum
1169  bsp->checksum = LittleLong(Com_BlockChecksum(buf, filelen));
1170 
1171  // load all lumps
1172  for (info = bsp_lumps; info->load; info++) {
1173  ret = info->load(bsp, lumpdata[info->lump], lumpcount[info->lump]);
1174  if (ret) {
1175  goto fail1;
1176  }
1177  }
1178 
1179  ret = BSP_ValidateAreaPortals(bsp);
1180  if (ret) {
1181  goto fail1;
1182  }
1183 
1184  ret = BSP_ValidateTree(bsp);
1185  if (ret) {
1186  goto fail1;
1187  }
1188 
1189  if (!BSP_LoadPatchedPVS(bsp))
1190  {
1191  if (dedicated->integer)
1192  Com_WPrintf("WARNING: Pathced PVS file for %s unavailable. Some entities may disappear.\n"
1193  "Load the map with the RTX renderer once to generate the patched PVS file.\n", bsp->name);
1194  else
1195  BSP_BuildPvsMatrix(bsp);
1196  }
1197  else
1198  {
1199  bsp->pvs_patched = qtrue;
1200  }
1201 
1202  Hunk_End(&bsp->hunk);
1203 
1204  List_Append(&bsp_cache, &bsp->entry);
1205 
1206  FS_FreeFile(buf);
1207 
1208  *bsp_p = bsp;
1209  return Q_ERR_SUCCESS;
1210 
1211 fail1:
1212  Hunk_Free(&bsp->hunk);
1213  Z_Free(bsp);
1214 fail2:
1215  FS_FreeFile(buf);
1216  return ret;
1217 }

Referenced by BSP_Test_f(), CL_RegisterBspModels(), CM_LoadMap(), GL_LoadWorld(), MVD_GameInit(), R_BeginRegistration(), and R_BeginRegistration_RTX().

◆ BSP_LoadPatchedPVS()

static qboolean BSP_LoadPatchedPVS ( bsp_t *  bsp)
static

Definition at line 1019 of file bsp.c.

1020 {
1021  char pvs_path[MAX_QPATH];
1022 
1023  if (!BSP_GetPatchedPVSFileName(bsp->name, pvs_path))
1024  return qfalse;
1025 
1026  unsigned char* filebuf = 0;
1027  ssize_t filelen = 0;
1028  filelen = FS_LoadFile(pvs_path, &filebuf);
1029 
1030  if (filebuf == 0)
1031  return qfalse;
1032 
1033  size_t matrix_size = bsp->visrowsize * bsp->vis->numclusters;
1034  if (filelen != matrix_size * 2)
1035  {
1036  FS_FreeFile(filebuf);
1037  return qfalse;
1038  }
1039 
1040  bsp->pvs_matrix = Z_Malloc(matrix_size);
1041  memcpy(bsp->pvs_matrix, filebuf, matrix_size);
1042 
1043  bsp->pvs2_matrix = Z_Malloc(matrix_size);
1044  memcpy(bsp->pvs2_matrix, filebuf + matrix_size, matrix_size);
1045 
1046  FS_FreeFile(filebuf);
1047  return qtrue;
1048 }

Referenced by BSP_Load().

◆ BSP_PointLeaf()

mleaf_t* BSP_PointLeaf ( mnode_t *  node,
vec3_t  p 
)

Definition at line 1439 of file bsp.c.

1440 {
1441  float d;
1442 
1443  while (node->plane) {
1444  d = PlaneDiffFast(p, node->plane);
1445  if (d < 0)
1446  node = node->children[1];
1447  else
1448  node = node->children[0];
1449  }
1450 
1451  return (mleaf_t *)node;
1452 }

Referenced by bsp_mesh_load_custom_sky(), CM_PointContents(), CM_PointLeaf(), CM_TransformedPointContents(), collect_ligth_polys(), collect_sky_and_lava_ligth_polys(), collect_surfaces(), GL_MarkLeaves(), PF_inVIS(), process_bsp_entity(), process_regular_entity(), R_RenderFrame_RTX(), R_SetupFrame(), and vkpt_build_cylinder_light().

◆ BSP_SavePatchedPVS()

qboolean BSP_SavePatchedPVS ( bsp_t *  bsp)

Definition at line 1051 of file bsp.c.

1052 {
1053  char pvs_path[MAX_QPATH];
1054 
1055  if (!BSP_GetPatchedPVSFileName(bsp->name, pvs_path))
1056  return qfalse;
1057 
1058  if (!bsp->pvs_matrix)
1059  return qfalse;
1060 
1061  if (!bsp->pvs2_matrix)
1062  return qfalse;
1063 
1064  size_t matrix_size = bsp->visrowsize * bsp->vis->numclusters;
1065  unsigned char* filebuf = Z_Malloc(matrix_size * 2);
1066 
1067  memcpy(filebuf, bsp->pvs_matrix, matrix_size);
1068  memcpy(filebuf + matrix_size, bsp->pvs2_matrix, matrix_size);
1069 
1070  qerror_t err = FS_WriteFile(pvs_path, filebuf, matrix_size * 2);
1071 
1072  Z_Free(filebuf);
1073 
1074  if (err >= 0)
1075  return qtrue;
1076  else
1077  return qfalse;
1078 }

Referenced by bsp_mesh_create_from_bsp().

◆ BSP_SetParent()

static qerror_t BSP_SetParent ( mnode_t *  node,
int  key 
)
static

Definition at line 829 of file bsp.c.

830 {
831  mnode_t *child;
832 #if USE_REF
833  mface_t *face;
834  int i;
835 #endif
836 
837  while (node->plane) {
838 #if USE_REF
839  // a face may never belong to more than one node
840  for (i = 0, face = node->firstface; i < node->numfaces; i++, face++) {
841  if (face->drawframe) {
842  DEBUG("duplicate face");
843  return Q_ERR_INFINITE_LOOP;
844  }
845  face->drawframe = key;
846  }
847 #endif
848 
849  child = node->children[0];
850  if (child->parent) {
851  DEBUG("cycle encountered");
852  return Q_ERR_INFINITE_LOOP;
853  }
854  child->parent = node;
855  if (BSP_SetParent(child, key)) {
856  return Q_ERR_INFINITE_LOOP;
857  }
858 
859  child = node->children[1];
860  if (child->parent) {
861  DEBUG("cycle encountered");
862  return Q_ERR_INFINITE_LOOP;
863  }
864  child->parent = node;
865  node = child;
866  }
867 
868  return Q_ERR_SUCCESS;
869 }

Referenced by BSP_ValidateTree().

◆ BSP_ValidateAreaPortals()

static qerror_t BSP_ValidateAreaPortals ( bsp_t *  bsp)
static

Definition at line 909 of file bsp.c.

910 {
911  mareaportal_t *p;
912  int i;
913 
914  bsp->lastareaportal = 0;
915  for (i = 0, p = bsp->areaportals; i < bsp->numareaportals; i++, p++) {
916  if (p->portalnum >= MAX_MAP_AREAPORTALS) {
917  DEBUG("bad portalnum");
918  return Q_ERR_TOO_MANY;
919  }
920  if (p->portalnum > bsp->lastareaportal) {
921  bsp->lastareaportal = p->portalnum;
922  }
923  if (p->otherarea >= bsp->numareas) {
924  DEBUG("bad otherarea");
925  return Q_ERR_BAD_INDEX;
926  }
927  }
928 
929  return Q_ERR_SUCCESS;
930 }

Referenced by BSP_Load().

◆ BSP_ValidateTree()

static qerror_t BSP_ValidateTree ( bsp_t *  bsp)
static

Definition at line 871 of file bsp.c.

872 {
873  mmodel_t *mod;
874  qerror_t ret;
875  int i;
876 #if USE_REF
877  mface_t *face;
878  int j;
879 #endif
880 
881  for (i = 0, mod = bsp->models; i < bsp->nummodels; i++, mod++) {
882  if (i == 0 && mod->headnode != bsp->nodes) {
883  DEBUG("map model 0 headnode is not the first node");
884  return Q_ERR_INVALID_FORMAT;
885  }
886 
887  ret = BSP_SetParent(mod->headnode, ~i);
888  if (ret) {
889  return ret;
890  }
891 
892 #if USE_REF
893  // a face may never belong to more than one model
894  for (j = 0, face = mod->firstface; j < mod->numfaces; j++, face++) {
895  if (face->drawframe && face->drawframe != ~i) {
896  DEBUG("duplicate face");
897  return Q_ERR_INFINITE_LOOP;
898  }
899  face->drawframe = ~i;
900  }
901 #endif
902  }
903 
904  return Q_ERR_SUCCESS;
905 }

Referenced by BSP_Load().

◆ LOAD() [1/12]

LOAD ( AreaPortals  )

Definition at line 691 of file bsp.c.

692 {
693  dareaportal_t *in;
694  mareaportal_t *out;
695  int i;
696 
697  bsp->numareaportals = count;
698  bsp->areaportals = ALLOC(sizeof(*out) * count);
699 
700  in = base;
701  out = bsp->areaportals;
702  for (i = 0; i < count; i++, in++, out++) {
703  out->portalnum = LittleLong(in->portalnum);
704  out->otherarea = LittleLong(in->otherarea);
705  }
706 
707  return Q_ERR_SUCCESS;
708 }

◆ LOAD() [2/12]

LOAD ( Areas  )

Definition at line 710 of file bsp.c.

711 {
712  darea_t *in;
713  marea_t *out;
714  int i;
715  uint32_t numareaportals, firstareaportal, lastareaportal;
716 
717  bsp->numareas = count;
718  bsp->areas = ALLOC(sizeof(*out) * count);
719 
720  in = base;
721  out = bsp->areas;
722  for (i = 0; i < count; i++, in++, out++) {
723  numareaportals = LittleLong(in->numareaportals);
724  firstareaportal = LittleLong(in->firstareaportal);
725  lastareaportal = firstareaportal + numareaportals;
726  if (lastareaportal < firstareaportal || lastareaportal > bsp->numareaportals) {
727  DEBUG("bad areaportals");
728  return Q_ERR_BAD_INDEX;
729  }
730  out->numareaportals = numareaportals;
731  out->firstareaportal = bsp->areaportals + firstareaportal;
732  out->floodvalid = 0;
733  }
734 
735  return Q_ERR_SUCCESS;
736 }

◆ LOAD() [3/12]

LOAD ( Brushes  )

Definition at line 223 of file bsp.c.

224 {
225  dbrush_t *in;
226  mbrush_t *out;
227  int i;
228  uint32_t firstside, numsides, lastside;
229 
230  bsp->numbrushes = count;
231  bsp->brushes = ALLOC(sizeof(*out) * count);
232 
233  in = base;
234  out = bsp->brushes;
235  for (i = 0; i < count; i++, out++, in++) {
236  firstside = LittleLong(in->firstside);
237  numsides = LittleLong(in->numsides);
238  lastside = firstside + numsides;
239  if (lastside < firstside || lastside > bsp->numbrushsides) {
240  DEBUG("bad brushsides");
241  return Q_ERR_BAD_INDEX;
242  }
243  out->firstbrushside = bsp->brushsides + firstside;
244  out->numsides = numsides;
245  out->contents = LittleLong(in->contents);
246  out->checkcount = 0;
247  }
248 
249  return Q_ERR_SUCCESS;
250 }

◆ LOAD() [4/12]

LOAD ( BrushSides  )

Definition at line 189 of file bsp.c.

190 {
191  dbrushside_t *in;
192  mbrushside_t *out;
193  int i;
194  uint16_t planenum, texinfo;
195 
196  bsp->numbrushsides = count;
197  bsp->brushsides = ALLOC(sizeof(*out) * count);
198 
199  in = base;
200  out = bsp->brushsides;
201  for (i = 0; i < count; i++, in++, out++) {
202  planenum = LittleShort(in->planenum);
203  if (planenum >= bsp->numplanes) {
204  DEBUG("bad planenum");
205  return Q_ERR_BAD_INDEX;
206  }
207  out->plane = bsp->planes + planenum;
208  texinfo = LittleShort(in->texinfo);
209  if (texinfo == (uint16_t)-1) {
210  out->texinfo = &nulltexinfo;
211  } else {
212  if (texinfo >= bsp->numtexinfo) {
213  DEBUG("bad texinfo");
214  return Q_ERR_BAD_INDEX;
215  }
216  out->texinfo = bsp->texinfo + texinfo;
217  }
218  }
219 
220  return Q_ERR_SUCCESS;
221 }

◆ LOAD() [5/12]

LOAD ( EntString  )

Definition at line 738 of file bsp.c.

739 {
740  bsp->numentitychars = count;
741  bsp->entitystring = ALLOC(count + 1);
742  memcpy(bsp->entitystring, base, count);
743  bsp->entitystring[count] = 0;
744 
745  return Q_ERR_SUCCESS;
746 }

◆ LOAD() [6/12]

LOAD ( LeafBrushes  )

Definition at line 252 of file bsp.c.

253 {
254  uint16_t *in;
255  mbrush_t **out;
256  int i;
257  uint16_t brushnum;
258 
259  bsp->numleafbrushes = count;
260  bsp->leafbrushes = ALLOC(sizeof(*out) * count);
261 
262  in = base;
263  out = bsp->leafbrushes;
264  for (i = 0; i < count; i++, in++, out++) {
265  brushnum = LittleShort(*in);
266  if (brushnum >= bsp->numbrushes) {
267  DEBUG("bad brushnum");
268  return Q_ERR_BAD_INDEX;
269  }
270  *out = bsp->brushes + brushnum;
271  }
272 
273  return Q_ERR_SUCCESS;
274 }

◆ LOAD() [7/12]

LOAD ( Leafs  )

Definition at line 469 of file bsp.c.

470 {
471  dleaf_t *in;
472  mleaf_t *out;
473  int i;
474  uint16_t cluster, area;
475  uint16_t firstleafbrush, numleafbrushes, lastleafbrush;
476 #if USE_REF
477  int j;
478  uint16_t firstleafface, numleaffaces, lastleafface;
479 #endif
480 
481  if (!count) {
482  DEBUG("map with no leafs");
483  return Q_ERR_TOO_FEW;
484  }
485 
486  bsp->numleafs = count;
487  bsp->leafs = ALLOC(sizeof(*out) * count);
488 
489  in = base;
490  out = bsp->leafs;
491  for (i = 0; i < count; i++, in++, out++) {
492  out->plane = NULL;
493  out->contents = LittleLong(in->contents);
494  cluster = LittleShort(in->cluster);
495  if (cluster == (uint16_t)-1) {
496  // solid leafs use special -1 cluster
497  out->cluster = -1;
498  } else if (bsp->vis == NULL) {
499  // map has no vis, use 0 as a default cluster
500  out->cluster = 0;
501  } else {
502  // validate cluster
503  if (cluster >= bsp->vis->numclusters) {
504  DEBUG("bad cluster");
505  return Q_ERR_BAD_INDEX;
506  }
507  out->cluster = cluster;
508  }
509 
510  area = LittleShort(in->area);
511  if (area >= bsp->numareas) {
512  DEBUG("bad area");
513  return Q_ERR_BAD_INDEX;
514  }
515  out->area = area;
516 
517  firstleafbrush = LittleShort(in->firstleafbrush);
518  numleafbrushes = LittleShort(in->numleafbrushes);
519  lastleafbrush = firstleafbrush + numleafbrushes;
520  if (lastleafbrush < firstleafbrush || lastleafbrush > bsp->numleafbrushes) {
521  DEBUG("bad leafbrushes");
522  return Q_ERR_BAD_INDEX;
523  }
524  out->firstleafbrush = bsp->leafbrushes + firstleafbrush;
525  out->numleafbrushes = numleafbrushes;
526 
527 #if USE_REF
528  firstleafface = LittleShort(in->firstleafface);
529  numleaffaces = LittleShort(in->numleaffaces);
530  lastleafface = firstleafface + numleaffaces;
531  if (lastleafface < firstleafface || lastleafface > bsp->numleaffaces) {
532  DEBUG("bad leaffaces");
533  return Q_ERR_BAD_INDEX;
534  }
535  out->firstleafface = bsp->leaffaces + firstleafface;
536  out->numleaffaces = numleaffaces;
537 
538  for (j = 0; j < 3; j++) {
539  out->mins[j] = (int16_t)LittleShort(in->mins[j]);
540  out->maxs[j] = (int16_t)LittleShort(in->maxs[j]);
541  }
542 
543  out->parent = NULL;
544  out->visframe = -1;
545 #endif
546  }
547 
548  if (bsp->leafs[0].contents != CONTENTS_SOLID) {
549  DEBUG("map leaf 0 is not CONTENTS_SOLID");
550  return Q_ERR_INVALID_FORMAT;
551  }
552 
553  return Q_ERR_SUCCESS;
554 }

◆ LOAD() [8/12]

LOAD ( Nodes  )

Definition at line 556 of file bsp.c.

557 {
558  dnode_t *in;
559  mnode_t *out;
560  int i, j;
561  uint32_t planenum, child;
562 #if USE_REF
563  uint16_t firstface, numfaces, lastface;
564 #endif
565 
566  if (!count) {
567  DEBUG("map with no nodes");
568  return Q_ERR_TOO_FEW;
569  }
570 
571  bsp->numnodes = count;
572  bsp->nodes = ALLOC(sizeof(*out) * count);
573 
574  in = base;
575  out = bsp->nodes;
576  for (i = 0; i < count; i++, out++, in++) {
577  planenum = LittleLong(in->planenum);
578  if (planenum >= bsp->numplanes) {
579  DEBUG("bad planenum");
580  return Q_ERR_BAD_INDEX;
581  }
582  out->plane = bsp->planes + planenum;
583 
584  for (j = 0; j < 2; j++) {
585  child = LittleLong(in->children[j]);
586  if (child & 0x80000000) {
587  child = ~child;
588  if (child >= bsp->numleafs) {
589  DEBUG("bad leafnum");
590  return Q_ERR_BAD_INDEX;
591  }
592  out->children[j] = (mnode_t *)(bsp->leafs + child);
593  } else {
594  if (child >= count) {
595  DEBUG("bad nodenum");
596  return Q_ERR_BAD_INDEX;
597  }
598  out->children[j] = bsp->nodes + child;
599  }
600  }
601 
602 #if USE_REF
603  firstface = LittleShort(in->firstface);
604  numfaces = LittleShort(in->numfaces);
605  lastface = firstface + numfaces;
606  if (lastface < firstface || lastface > bsp->numfaces) {
607  DEBUG("bad faces");
608  return Q_ERR_BAD_INDEX;
609  }
610  out->firstface = bsp->faces + firstface;
611  out->numfaces = numfaces;
612 
613  for (j = 0; j < 3; j++) {
614  out->mins[j] = (int16_t)LittleShort(in->mins[j]);
615  out->maxs[j] = (int16_t)LittleShort(in->maxs[j]);
616  }
617 
618  out->parent = NULL;
619  out->visframe = -1;
620 #endif
621  }
622 
623  return Q_ERR_SUCCESS;
624 }

◆ LOAD() [9/12]

LOAD ( Planes  )

Definition at line 166 of file bsp.c.

167 {
168  dplane_t *in;
169  cplane_t *out;
170  int i, j;
171 
172  bsp->numplanes = count;
173  bsp->planes = ALLOC(sizeof(*out) * count);
174 
175  in = base;
176  out = bsp->planes;
177  for (i = 0; i < count; i++, in++, out++) {
178  for (j = 0; j < 3; j++) {
179  out->normal[j] = LittleFloat(in->normal[j]);
180  }
181  out->dist = LittleFloat(in->dist);
182  SetPlaneType(out);
183  SetPlaneSignbits(out);
184  }
185 
186  return Q_ERR_SUCCESS;
187 }

◆ LOAD() [10/12]

LOAD ( Submodels  )

Definition at line 626 of file bsp.c.

627 {
628  dmodel_t *in;
629  mmodel_t *out;
630  int i, j;
631  uint32_t headnode;
632 #if USE_REF
633  uint32_t firstface, numfaces, lastface;
634 #endif
635 
636  if (!count) {
637  DEBUG("map with no models");
638  return Q_ERR_TOO_FEW;
639  }
640 
641  bsp->models = ALLOC(sizeof(*out) * count);
642  bsp->nummodels = count;
643 
644  in = base;
645  out = bsp->models;
646  for (i = 0; i < count; i++, in++, out++) {
647  for (j = 0; j < 3; j++) {
648  // spread the mins / maxs by a pixel
649  out->mins[j] = LittleFloat(in->mins[j]) - 1;
650  out->maxs[j] = LittleFloat(in->maxs[j]) + 1;
651  out->origin[j] = LittleFloat(in->origin[j]);
652  }
653  headnode = LittleLong(in->headnode);
654  if (headnode & 0x80000000) {
655  // be careful, some models have no nodes, just a leaf
656  headnode = ~headnode;
657  if (headnode >= bsp->numleafs) {
658  DEBUG("bad headleaf");
659  return Q_ERR_BAD_INDEX;
660  }
661  out->headnode = (mnode_t *)(bsp->leafs + headnode);
662  } else {
663  if (headnode >= bsp->numnodes) {
664  DEBUG("bad headnode");
665  return Q_ERR_BAD_INDEX;
666  }
667  out->headnode = bsp->nodes + headnode;
668  }
669 #if USE_REF
670  if (i == 0) {
671  continue;
672  }
673  firstface = LittleLong(in->firstface);
674  numfaces = LittleLong(in->numfaces);
675  lastface = firstface + numfaces;
676  if (lastface < firstface || lastface > bsp->numfaces) {
677  DEBUG("bad faces");
678  return Q_ERR_BAD_INDEX;
679  }
680  out->firstface = bsp->faces + firstface;
681  out->numfaces = numfaces;
682 
683  out->radius = RadiusFromBounds(out->mins, out->maxs);
684 #endif
685  }
686 
687  return Q_ERR_SUCCESS;
688 }

◆ LOAD() [11/12]

LOAD ( Texinfo  )

Definition at line 102 of file bsp.c.

103 {
104  dtexinfo_t *in;
105  mtexinfo_t *out;
106  int i;
107 #if USE_REF
108  int j, k;
109  int32_t next;
110  mtexinfo_t *step;
111 #endif
112 
113  bsp->numtexinfo = count;
114  bsp->texinfo = ALLOC(sizeof(*out) * count);
115 
116  in = base;
117  out = bsp->texinfo;
118  for (i = 0; i < count; i++, in++, out++) {
119  memcpy(out->c.name, in->texture, sizeof(out->c.name));
120  out->c.name[sizeof(out->c.name) - 1] = 0;
121  memcpy(out->name, in->texture, sizeof(out->name));
122  out->name[sizeof(out->name) - 1] = 0;
123  out->c.flags = LittleLong(in->flags);
124  out->c.value = LittleLong(in->value);
125 
126 #if USE_REF
127  out->radiance = in->value;
128  for (j = 0; j < 2; j++) {
129  for (k = 0; k < 3; k++) {
130  out->axis[j][k] = LittleFloat(in->vecs[j][k]);
131  }
132  out->offset[j] = LittleFloat(in->vecs[j][k]);
133  }
134 
135  next = (int32_t)LittleLong(in->nexttexinfo);
136  if (next > 0) {
137  if (next >= count) {
138  DEBUG("bad anim chain");
139  return Q_ERR_BAD_INDEX;
140  }
141  out->next = bsp->texinfo + next;
142  } else {
143  out->next = NULL;
144  }
145 #endif
146  }
147 
148 #if USE_REF
149  // count animation frames
150  out = bsp->texinfo;
151  for (i = 0; i < count; i++, out++) {
152  out->numframes = 1;
153  for (step = out->next; step && step != out; step = step->next) {
154  if (out->numframes == count) {
155  DEBUG("infinite anim chain");
156  return Q_ERR_INFINITE_LOOP;
157  }
158  out->numframes++;
159  }
160  }
161 #endif
162 
163  return Q_ERR_SUCCESS;
164 }

◆ LOAD() [12/12]

LOAD ( Visibility  )

Definition at line 56 of file bsp.c.

57 {
58  uint32_t numclusters, bitofs;
59  int i, j;
60 
61  if (!count) {
62  return Q_ERR_SUCCESS;
63  }
64 
65  if (count < 4) {
66  DEBUG("too small header");
67  return Q_ERR_TOO_FEW;
68  }
69 
70  bsp->numvisibility = count;
71  bsp->vis = ALLOC(count);
72  memcpy(bsp->vis, base, count);
73 
74  numclusters = LittleLong(bsp->vis->numclusters);
75  if (numclusters > MAX_MAP_LEAFS) {
76  DEBUG("bad numclusters");
77  return Q_ERR_TOO_MANY;
78  }
79 
80  if (numclusters > (count - 4) / 8) {
81  DEBUG("too small header");
82  return Q_ERR_TOO_FEW;
83  }
84 
85  bsp->vis->numclusters = numclusters;
86  bsp->visrowsize = (numclusters + 7) >> 3;
87 
88  for (i = 0; i < numclusters; i++) {
89  for (j = 0; j < 2; j++) {
90  bitofs = LittleLong(bsp->vis->bitofs[i][j]);
91  if (bitofs >= count) {
92  DEBUG("bad bitofs");
93  return Q_ERR_BAD_INDEX;
94  }
95  bsp->vis->bitofs[i][j] = bitofs;
96  }
97  }
98 
99  return Q_ERR_SUCCESS;
100 }

Variable Documentation

◆ bsp_cache

list_t bsp_cache
static

Definition at line 793 of file bsp.c.

Referenced by BSP_Find(), BSP_Init(), BSP_List_f(), and BSP_Load().

◆ bsp_lumps

const lump_info_t bsp_lumps[]
static
Initial value:
= {
L(Visibility, VISIBILITY, byte, byte),
L(Texinfo, TEXINFO, dtexinfo_t, mtexinfo_t),
L(Planes, PLANES, dplane_t, cplane_t),
L(BrushSides, BRUSHSIDES, dbrushside_t, mbrushside_t),
L(Brushes, BRUSHES, dbrush_t, mbrush_t),
L(LeafBrushes, LEAFBRUSHES, uint16_t, mbrush_t *),
L(AreaPortals, AREAPORTALS, dareaportal_t, mareaportal_t),
L(Areas, AREAS, darea_t, marea_t),
L(Leafs, LEAFS, dleaf_t, mleaf_t),
L(Nodes, NODES, dnode_t, mnode_t),
L(Submodels, MODELS, dmodel_t, mmodel_t),
L(EntString, ENTSTRING, char, char),
{ NULL }
}

Definition at line 767 of file bsp.c.

Referenced by BSP_Load().

◆ map_visibility_patch

cvar_t* map_visibility_patch
static

Definition at line 37 of file bsp.c.

Referenced by BSP_ClusterVis(), and BSP_Init().

◆ nulltexinfo

mtexinfo_t nulltexinfo

Definition at line 30 of file cmodel.c.

Referenced by CM_BoxTrace(), CM_InitBoxHull(), and LOAD().

RadiusFromBounds
vec_t RadiusFromBounds(const vec3_t mins, const vec3_t maxs)
Definition: shared.c:127
BSP_LoadPatchedPVS
static qboolean BSP_LoadPatchedPVS(bsp_t *bsp)
Definition: bsp.c:1019
BSP_GetPvs2
char * BSP_GetPvs2(bsp_t *bsp, int cluster)
Definition: bsp.c:985
Com_BlockChecksum
uint32_t Com_BlockChecksum(void *buffer, size_t len)
Definition: mdfour.c:187
Hunk_Begin
void Hunk_Begin(memhunk_t *hunk, size_t maxsize)
Definition: hunk.c:23
Cmd_AddCommand
void Cmd_AddCommand(const char *name, xcommand_t function)
Definition: cmd.c:1562
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
BSP_ClusterVis
byte * BSP_ClusterVis(bsp_t *bsp, byte *mask, int cluster, int vis)
Definition: bsp.c:1339
bsp_cache
static list_t bsp_cache
Definition: bsp.c:793
lump_info_t
Definition: bsp.c:756
FS_WriteFile
qerror_t FS_WriteFile(const char *path, const void *data, size_t len)
Definition: files.c:1932
BSP_GetPatchedPVSFileName
static qboolean BSP_GetPatchedPVSFileName(const char *map_path, char pvs_path[MAX_QPATH])
Definition: bsp.c:997
lump_info_t::lump
unsigned lump
Definition: bsp.c:758
Hunk_Free
void Hunk_Free(memhunk_t *hunk)
Definition: hunk.c:75
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
dedicated
cvar_t * dedicated
Definition: g_main.c:46
BSP_SetParent
static qerror_t BSP_SetParent(mnode_t *node, int key)
Definition: bsp.c:829
BSP_List_f
static void BSP_List_f(void)
Definition: bsp.c:795
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
nulltexinfo
mtexinfo_t nulltexinfo
Definition: cmodel.c:30
lump_info_t::load
qerror_t(* load)(bsp_t *, void *, size_t)
Definition: bsp.c:757
Hunk_End
void Hunk_End(memhunk_t *hunk)
Definition: hunk.c:66
BSP_ValidateAreaPortals
static qerror_t BSP_ValidateAreaPortals(bsp_t *bsp)
Definition: bsp.c:909
lump_info_t::disksize
size_t disksize
Definition: bsp.c:759
SetPlaneSignbits
void SetPlaneSignbits(cplane_t *plane)
Definition: math.c:298
bsp_lumps
static const lump_info_t bsp_lumps[]
Definition: bsp.c:767
lump_info_t::memsize
size_t memsize
Definition: bsp.c:760
lump_info_t::maxcount
size_t maxcount
Definition: bsp.c:761
c
statCounters_t c
Definition: main.c:30
map_visibility_patch
static cvar_t * map_visibility_patch
Definition: bsp.c:37
BSP_Find
static bsp_t * BSP_Find(const char *name)
Definition: bsp.c:816
BSP_BuildPvsMatrix
static void BSP_BuildPvsMatrix(bsp_t *bsp)
Definition: bsp.c:954
err
int err
Definition: win.h:24
SetPlaneType
void SetPlaneType(cplane_t *plane)
Definition: math.c:278
DEBUG
#define DEBUG(msg)
Definition: bsp.c:53
Com_PageInMemory
void Com_PageInMemory(void *buffer, size_t size)
Definition: utils.c:383
BSP_GetPvs
char * BSP_GetPvs(bsp_t *bsp, int cluster)
Definition: bsp.c:974
ALLOC
#define ALLOC(size)
Definition: bsp.c:47
BSP_ValidateTree
static qerror_t BSP_ValidateTree(bsp_t *bsp)
Definition: bsp.c:871
L
#define L(func, lump, disk_t, mem_t)
Definition: bsp.c:764