Quake II RTX doxygen  1.0 dev
bsp_mesh.c File Reference
#include "vkpt.h"
#include "shader/global_textures.h"
#include "material.h"
#include <assert.h>
#include <float.h>
#include <tinyobj_loader_c.h>

Go to the source code of this file.

Classes

struct  point2_t
 
struct  poly_t
 

Macros

#define TINYOBJ_LOADER_C_IMPLEMENTATION
 
#define DUMP_WORLD_MESH_TO_OBJ   0
 
#define CP_V(idx, src)
 
#define CP_T(idx, src)
 
#define CP_M(idx)
 
#define FOREACH_BIT_BEGIN(SET, ROWSIZE, VAR)
 
#define FOREACH_BIT_END   } } } }
 
#define MAX_POLY_VERTS   32
 
#define MAX_LIGHTS_PER_CLUSTER   1024
 

Functions

static void remove_collinear_edges (float *positions, float *tex_coords, int *num_vertices)
 
static int create_poly (const mface_t *surf, uint32_t material_id, float *positions_out, float *tex_coord_out, uint32_t *material_out)
 
static int belongs_to_model (bsp_t *bsp, mface_t *surf)
 
static int filter_static_opaque (int flags)
 
static int filter_static_transparent (int flags)
 
static int filter_static_sky (int flags)
 
static int filter_all (int flags)
 
qboolean get_triangle_off_center (const float *positions, float *center, float *anti_center)
 
static int get_surf_light_style (const mface_t *surf)
 
static qboolean get_surf_plane_equation (mface_t *surf, float *plane)
 
static qboolean is_sky_or_lava_cluster (bsp_mesh_t *wm, mface_t *surf, int cluster, int material_id)
 
static void merge_pvs_rows (bsp_t *bsp, char *src, char *dst)
 
static void connect_pvs (bsp_t *bsp, int cluster_a, char *pvs_a, int cluster_b, char *pvs_b)
 
static void make_pvs_symmetric (bsp_t *bsp)
 
static void build_pvs2 (bsp_t *bsp)
 
static void collect_surfaces (int *idx_ctr, bsp_mesh_t *wm, bsp_t *bsp, int model_idx, int(*filter)(int))
 
static float dot2 (point2_t *a, point2_t *b)
 
static float cross2 (point2_t *a, point2_t *b)
 
static point2_t vsub (point2_t *a, point2_t *b)
 
static int left_of (point2_t *a, point2_t *b, point2_t *c)
 
static int line_sect (point2_t *x0, point2_t *x1, point2_t *y0, point2_t *y1, point2_t *res)
 
static void poly_append (poly_t *p, point2_t *v)
 
static int poly_winding (poly_t *p)
 
static void poly_edge_clip (poly_t *sub, point2_t *x0, point2_t *x1, int left, poly_t *res)
 
static void clip_polygon (poly_t *input, poly_t *clipper, poly_t *output)
 
static light_poly_tappend_light_poly (int *num_lights, int *allocated, light_poly_t **lights)
 
static qboolean is_light_material (uint32_t material)
 
static void collect_ligth_polys (bsp_mesh_t *wm, bsp_t *bsp, int model_idx, int *num_lights, int *allocated_lights, light_poly_t **lights)
 
static void collect_sky_and_lava_ligth_polys (bsp_mesh_t *wm, bsp_t *bsp)
 
static qboolean is_model_transparent (bsp_mesh_t *wm, bsp_model_t *model)
 
uint32_t floatBitsToUint (float f)
 
uint32_t encode_normal (vec3_t normal)
 
void compute_aabb (const float *positions, int numvert, float *aabb_min, float *aabb_max)
 
void compute_world_tangents (bsp_mesh_t *wm)
 
static void load_sky_and_lava_clusters (bsp_mesh_t *wm, const char *map_name)
 
static void load_cameras (bsp_mesh_t *wm, const char *map_name)
 
static void compute_sky_visibility (bsp_mesh_t *wm, bsp_t *bsp)
 
static void compute_cluster_aabbs (bsp_mesh_t *wm)
 
static void get_aabb_corner (aabb_t *aabb, int corner_idx, vec3_t corner)
 
static qboolean light_affects_cluster (light_poly_t *light, aabb_t *aabb)
 
static void collect_cluster_lights (bsp_mesh_t *wm, bsp_t *bsp)
 
static qboolean bsp_mesh_load_custom_sky (int *idx_ctr, bsp_mesh_t *wm, bsp_t *bsp, const char *map_name)
 
void bsp_mesh_create_from_bsp (bsp_mesh_t *wm, bsp_t *bsp, const char *map_name)
 
void bsp_mesh_destroy (bsp_mesh_t *wm)
 
void bsp_mesh_register_textures (bsp_t *bsp)
 

Variables

cvar_t * cvar_pt_enable_nodraw
 

Macro Definition Documentation

◆ CP_M

#define CP_M (   idx)
Value:
do { \
if(material_out) { \
material_out[k] = material_id; \
} \
} while(0)

◆ CP_T

#define CP_T (   idx,
  src 
)
Value:
do { \
if(tex_coord_out) { \
memcpy(tex_coord_out + (idx) * 2, src, sizeof(float) * 2); \
} \
} while(0)

◆ CP_V

#define CP_V (   idx,
  src 
)
Value:
do { \
if(positions_out) { \
memcpy(positions_out + (idx) * 3, src, sizeof(float) * 3); \
} \
} while(0)

◆ DUMP_WORLD_MESH_TO_OBJ

#define DUMP_WORLD_MESH_TO_OBJ   0

Definition at line 89 of file bsp_mesh.c.

◆ FOREACH_BIT_BEGIN

#define FOREACH_BIT_BEGIN (   SET,
  ROWSIZE,
  VAR 
)
Value:
for (int _byte_idx = 0; _byte_idx < ROWSIZE; _byte_idx++) { \
if (SET[_byte_idx]) { \
for (int _bit_idx = 0; _bit_idx < 8; _bit_idx++) { \
if (SET[_byte_idx] & (1 << _bit_idx)) { \
int VAR = (_byte_idx << 3) | _bit_idx;

Definition at line 391 of file bsp_mesh.c.

◆ FOREACH_BIT_END

#define FOREACH_BIT_END   } } } }

Definition at line 398 of file bsp_mesh.c.

◆ MAX_LIGHTS_PER_CLUSTER

#define MAX_LIGHTS_PER_CLUSTER   1024

◆ MAX_POLY_VERTS

#define MAX_POLY_VERTS   32

Definition at line 587 of file bsp_mesh.c.

◆ TINYOBJ_LOADER_C_IMPLEMENTATION

#define TINYOBJ_LOADER_C_IMPLEMENTATION

Definition at line 27 of file bsp_mesh.c.

Function Documentation

◆ append_light_poly()

static light_poly_t* append_light_poly ( int num_lights,
int allocated,
light_poly_t **  lights 
)
static

Definition at line 712 of file bsp_mesh.c.

713 {
714  if (*num_lights == *allocated)
715  {
716  *allocated = max(*allocated * 2, 128);
717  *lights = Z_Realloc(*lights, *allocated * sizeof(light_poly_t));
718  }
719  return *lights + (*num_lights)++;
720 }

Referenced by bsp_mesh_load_custom_sky(), collect_ligth_polys(), and collect_sky_and_lava_ligth_polys().

◆ belongs_to_model()

static int belongs_to_model ( bsp_t *  bsp,
mface_t *  surf 
)
static

Definition at line 235 of file bsp_mesh.c.

236 {
237  for (int i = 0; i < bsp->nummodels; i++) {
238  if (surf >= bsp->models[i].firstface
239  && surf < bsp->models[i].firstface + bsp->models[i].numfaces)
240  return 1;
241  }
242  return 0;
243 }

Referenced by collect_ligth_polys(), collect_sky_and_lava_ligth_polys(), and collect_surfaces().

◆ bsp_mesh_create_from_bsp()

void bsp_mesh_create_from_bsp ( bsp_mesh_t wm,
bsp_t *  bsp,
const char *  map_name 
)

Definition at line 1623 of file bsp_mesh.c.

1624 {
1625  const char* full_game_map_name = map_name;
1626  if (strcmp(map_name, "demo1") == 0)
1627  full_game_map_name = "base1";
1628  else if (strcmp(map_name, "demo2") == 0)
1629  full_game_map_name = "base2";
1630  else if (strcmp(map_name, "demo3") == 0)
1631  full_game_map_name = "base3";
1632 
1633  load_sky_and_lava_clusters(wm, full_game_map_name);
1634  load_cameras(wm, full_game_map_name);
1635 
1636  wm->models = Z_Malloc(bsp->nummodels * sizeof(bsp_model_t));
1637  memset(wm->models, 0, bsp->nummodels * sizeof(bsp_model_t));
1638 
1639  wm->num_models = bsp->nummodels;
1640  wm->num_clusters = bsp->vis->numclusters;
1641 
1642  if (wm->num_clusters + 1 >= MAX_LIGHT_LISTS)
1643  {
1644  Com_Error(ERR_FATAL, "The BSP model has too many clusters (%d)", wm->num_clusters);
1645  }
1646 
1647  wm->num_vertices = 0;
1648  wm->num_indices = 0;
1649  wm->positions = Z_Malloc(MAX_VERT_BSP * 3 * sizeof(*wm->positions));
1650  wm->tex_coords = Z_Malloc(MAX_VERT_BSP * 2 * sizeof(*wm->tex_coords));
1651  wm->materials = Z_Malloc(MAX_VERT_BSP / 3 * sizeof(*wm->materials));
1652  wm->clusters = Z_Malloc(MAX_VERT_BSP / 3 * sizeof(*wm->clusters));
1653 
1654  // clear these here because `bsp_mesh_load_custom_sky` creates lights before `collect_ligth_polys`
1655  wm->num_light_polys = 0;
1656  wm->allocated_light_polys = 0;
1657  wm->light_polys = NULL;
1658 
1659  int idx_ctr = 0;
1660 
1661 #if DUMP_WORLD_MESH_TO_OBJ
1662  {
1663  char filename[MAX_QPATH];
1664  Q_snprintf(filename, sizeof(filename), "C:\\temp\\%s.obj", map_name);
1665  obj_dump_file = fopen(filename, "w");
1666  obj_vertex_num = 1;
1667  }
1668 #endif
1669 
1670  collect_surfaces(&idx_ctr, wm, bsp, -1, filter_static_opaque);
1671  wm->world_idx_count = idx_ctr;
1672 
1673  wm->world_transparent_offset = idx_ctr;
1674  collect_surfaces(&idx_ctr, wm, bsp, -1, filter_static_transparent);
1676 
1677  wm->world_sky_offset = idx_ctr;
1678  collect_surfaces(&idx_ctr, wm, bsp, -1, filter_static_sky);
1679  wm->world_sky_count = idx_ctr - wm->world_sky_offset;
1680 
1681  wm->world_custom_sky_offset = idx_ctr;
1682  bsp_mesh_load_custom_sky(&idx_ctr, wm, bsp, full_game_map_name);
1683  wm->world_custom_sky_count = idx_ctr - wm->world_custom_sky_offset;
1684 
1685  for (int k = 0; k < bsp->nummodels; k++) {
1686  bsp_model_t* model = wm->models + k;
1687  model->idx_offset = idx_ctr;
1688  collect_surfaces(&idx_ctr, wm, bsp, k, filter_all);
1689  model->idx_count = idx_ctr - model->idx_offset;
1690  }
1691 
1692 #if DUMP_WORLD_MESH_TO_OBJ
1693  fclose(obj_dump_file);
1694  obj_dump_file = NULL;
1695 #endif
1696 
1697  if (!bsp->pvs_patched)
1698  {
1699  build_pvs2(bsp);
1700 
1701  if (!BSP_SavePatchedPVS(bsp))
1702  {
1703  Com_EPrintf("Couldn't save patched PVS for %s.\n", bsp->name);
1704  }
1705  }
1706 
1707  wm->num_indices = idx_ctr;
1708  wm->num_vertices = idx_ctr;
1709 
1710  wm->indices = Z_Malloc(idx_ctr * sizeof(int));
1711  for (int i = 0; i < wm->num_vertices; i++)
1712  wm->indices[i] = i;
1713 
1715 
1716  if (wm->num_vertices >= MAX_VERT_BSP) {
1717  Com_Error(ERR_FATAL, "The BSP model has too many vertices (%d)", wm->num_vertices);
1718  }
1719 
1720  for(int i = 0; i < wm->num_models; i++)
1721  {
1722  bsp_model_t* model = wm->models + i;
1723 
1724  compute_aabb(wm->positions + model->idx_offset * 3, model->idx_count, model->aabb_min, model->aabb_max);
1725 
1726  VectorAdd(model->aabb_min, model->aabb_max, model->center);
1727  VectorScale(model->center, 0.5f, model->center);
1728  }
1729 
1731 
1732  vec3_t margin = { 1.f, 1.f, 1.f };
1733  VectorSubtract(wm->world_aabb.mins, margin, wm->world_aabb.mins);
1734  VectorAdd(wm->world_aabb.maxs, margin, wm->world_aabb.maxs);
1735 
1737 
1740 
1741  for (int k = 0; k < bsp->nummodels; k++)
1742  {
1743  bsp_model_t* model = wm->models + k;
1744 
1745  model->num_light_polys = 0;
1746  model->allocated_light_polys = 0;
1747  model->light_polys = NULL;
1748 
1749  collect_ligth_polys(wm, bsp, k, &model->num_light_polys, &model->allocated_light_polys, &model->light_polys);
1750 
1751  model->transparent = is_model_transparent(wm, model);
1752  }
1753 
1754  collect_cluster_lights(wm, bsp);
1755 
1756  compute_sky_visibility(wm, bsp);
1757 }

Referenced by R_BeginRegistration_RTX().

◆ bsp_mesh_destroy()

void bsp_mesh_destroy ( bsp_mesh_t wm)

Definition at line 1760 of file bsp_mesh.c.

1761 {
1762  Z_Free(wm->models);
1763 
1764  Z_Free(wm->positions);
1765  Z_Free(wm->tex_coords);
1766  Z_Free(wm->tangents);
1767  Z_Free(wm->indices);
1768  Z_Free(wm->clusters);
1769  Z_Free(wm->materials);
1770  Z_Free(wm->texel_density);
1771 
1772  Z_Free(wm->light_polys);
1773  Z_Free(wm->cluster_lights);
1775  Z_Free(wm->cluster_aabbs);
1776 
1777  memset(wm, 0, sizeof(*wm));
1778 }

Referenced by R_BeginRegistration_RTX().

◆ bsp_mesh_load_custom_sky()

static qboolean bsp_mesh_load_custom_sky ( int idx_ctr,
bsp_mesh_t wm,
bsp_t *  bsp,
const char *  map_name 
)
static

Definition at line 1538 of file bsp_mesh.c.

1539 {
1540  char filename[MAX_QPATH];
1541  Q_snprintf(filename, sizeof(filename), "maps/sky/%s.obj", map_name);
1542 
1543  void* file_buffer = NULL;
1544  ssize_t file_size = FS_LoadFile(filename, &file_buffer);
1545  if (!file_buffer)
1546  return qfalse;
1547 
1548  tinyobj_attrib_t attrib;
1549  tinyobj_shape_t* shapes = NULL;
1550  size_t num_shapes;
1551  tinyobj_material_t* materials = NULL;
1552  size_t num_materials;
1553 
1554  unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
1555  int ret = tinyobj_parse_obj(&attrib, &shapes, &num_shapes, &materials,
1556  &num_materials, (const char*)file_buffer, file_size, flags);
1557 
1558  FS_FreeFile(file_buffer);
1559 
1560  if (ret != TINYOBJ_SUCCESS) {
1561  Com_WPrintf("Couldn't parse sky polygon definition file %s.\n", filename);
1562  return qfalse;
1563  }
1564 
1565  int face_offset = 0;
1566  for (int nprim = 0; nprim < attrib.num_face_num_verts; nprim++)
1567  {
1568  int face_num_verts = attrib.face_num_verts[nprim];
1569  int i0 = attrib.faces[face_offset + 0].v_idx;
1570  int i1 = attrib.faces[face_offset + 1].v_idx;
1571  int i2 = attrib.faces[face_offset + 2].v_idx;
1572 
1573  vec3_t v0, v1, v2;
1574  VectorCopy(attrib.vertices + i0 * 3, v0);
1575  VectorCopy(attrib.vertices + i1 * 3, v1);
1576  VectorCopy(attrib.vertices + i2 * 3, v2);
1577 
1578  int wm_index = *idx_ctr;
1579  int wm_prim = wm_index / 3;
1580 
1581  VectorCopy(v0, wm->positions + wm_index * 3 + 0);
1582  VectorCopy(v1, wm->positions + wm_index * 3 + 3);
1583  VectorCopy(v2, wm->positions + wm_index * 3 + 6);
1584 
1585  wm->tex_coords[wm_index * 2 + 0] = 0.f;
1586  wm->tex_coords[wm_index * 2 + 1] = 0.f;
1587  wm->tex_coords[wm_index * 2 + 2] = 0.f;
1588  wm->tex_coords[wm_index * 2 + 3] = 0.f;
1589  wm->tex_coords[wm_index * 2 + 4] = 0.f;
1590  wm->tex_coords[wm_index * 2 + 5] = 0.f;
1591 
1592  vec3_t center;
1593  get_triangle_off_center(wm->positions + wm_index * 3, center, NULL);
1594 
1595  int cluster = BSP_PointLeaf(bsp->nodes, center)->cluster;
1596  wm->clusters[wm_prim] = cluster;
1598 
1600 
1601  VectorCopy(v0, light->positions + 0);
1602  VectorCopy(v1, light->positions + 3);
1603  VectorCopy(v2, light->positions + 6);
1604  VectorSet(light->color, -1.f, -1.f, -1.f); // special value for the sky
1605  VectorCopy(center, light->off_center);
1606  light->material = 0;
1607  light->style = 0;
1608  light->cluster = cluster;
1609 
1610  *idx_ctr += 3;
1611 
1612  face_offset += face_num_verts;
1613  }
1614 
1615  tinyobj_attrib_free(&attrib);
1616  tinyobj_shapes_free(shapes, num_shapes);
1617  tinyobj_materials_free(materials, num_materials);
1618 
1619  return qtrue;
1620 }

Referenced by bsp_mesh_create_from_bsp().

◆ bsp_mesh_register_textures()

void bsp_mesh_register_textures ( bsp_t *  bsp)

Definition at line 1781 of file bsp_mesh.c.

1782 {
1783  for (int i = 0; i < bsp->numtexinfo; i++) {
1784  mtexinfo_t *info = bsp->texinfo + i;
1785  imageflags_t flags;
1786  if (info->c.flags & SURF_WARP)
1787  flags = IF_TURBULENT;
1788  else
1789  flags = IF_NONE;
1790 
1791  char buffer[MAX_QPATH];
1792  Q_concat(buffer, sizeof(buffer), "textures/", info->name, ".wal", NULL);
1793  FS_NormalizePath(buffer, buffer);
1794 
1795  pbr_material_t * mat = MAT_FindPBRMaterial(buffer);
1796  if (!mat)
1797  Com_EPrintf("error finding material '%s'\n", buffer);
1798 
1799  image_t* image_diffuse = IMG_Find(buffer, IT_WALL, flags | IF_SRGB);
1800  image_t* image_normals = NULL;
1801  image_t* image_emissive = NULL;
1802 
1803  if (image_diffuse != R_NOTEXTURE)
1804  {
1805  // attempt loading the second texture
1806  Q_concat(buffer, sizeof(buffer), "textures/", info->name, "_n.tga", NULL);
1807  FS_NormalizePath(buffer, buffer);
1808  image_normals = IMG_Find(buffer, IT_WALL, flags);
1809  if (image_normals == R_NOTEXTURE) image_normals = NULL;
1810 
1811  if (image_normals && !image_normals->processing_complete)
1812  {
1813  vkpt_normalize_normal_map(image_normals);
1814  }
1815 
1816  // attempt loading the emissive texture
1817  Q_concat(buffer, sizeof(buffer), "textures/", info->name, "_light.tga", NULL);
1818  FS_NormalizePath(buffer, buffer);
1819  image_emissive = IMG_Find(buffer, IT_WALL, flags | IF_SRGB);
1820  if (image_emissive == R_NOTEXTURE) image_emissive = NULL;
1821 
1822  if (image_emissive && !image_emissive->processing_complete && (mat->emissive_scale > 0.f) && ((mat->flags & MATERIAL_FLAG_LIGHT) != 0 || MAT_IsKind(mat->flags, MATERIAL_KIND_LAVA)))
1823  {
1824  vkpt_extract_emissive_texture_info(image_emissive);
1825  }
1826  }
1827 
1828  // finish registration
1829  MAT_RegisterPBRMaterial(mat, image_diffuse, image_normals, image_emissive);
1830 
1831  info->material = mat;
1832  }
1833 
1834  // link the animation sequences
1835  for (int i = 0; i < bsp->numtexinfo; i++)
1836  {
1837  mtexinfo_t *texinfo = bsp->texinfo + i;
1838  pbr_material_t* material = texinfo->material;
1839 
1840  if (texinfo->numframes > 1)
1841  {
1842  assert(texinfo->next);
1843  assert(texinfo->next->material);
1844 
1845  material->num_frames = texinfo->numframes;
1846  material->next_frame = texinfo->next->material->flags & MATERIAL_INDEX_MASK;
1847  }
1848  }
1849 }

Referenced by R_BeginRegistration_RTX().

◆ build_pvs2()

static void build_pvs2 ( bsp_t *  bsp)
static

Definition at line 436 of file bsp_mesh.c.

437 {
438  size_t matrix_size = bsp->visrowsize * bsp->vis->numclusters;
439 
440  bsp->pvs2_matrix = Z_Mallocz(matrix_size);
441 
442  for (int cluster = 0; cluster < bsp->vis->numclusters; cluster++)
443  {
444  char* pvs = BSP_GetPvs(bsp, cluster);
445  char* dest_pvs = BSP_GetPvs2(bsp, cluster);
446  memcpy(dest_pvs, pvs, bsp->visrowsize);
447 
448  FOREACH_BIT_BEGIN(pvs, bsp->visrowsize, vis_cluster)
449  char* pvs2 = BSP_GetPvs(bsp, vis_cluster);
450  merge_pvs_rows(bsp, pvs2, dest_pvs);
452  }
453 
454 }

Referenced by bsp_mesh_create_from_bsp().

◆ clip_polygon()

static void clip_polygon ( poly_t input,
poly_t clipper,
poly_t output 
)
static

Definition at line 687 of file bsp_mesh.c.

688 {
689  int i;
690  poly_t p1_m, p2_m;
691  poly_t* p1 = &p1_m;
692  poly_t* p2 = &p2_m;
693  poly_t* tmp;
694 
695  int dir = poly_winding(clipper);
696  poly_edge_clip(input, clipper->v + clipper->len - 1, clipper->v, dir, p2);
697  for (i = 0; i < clipper->len - 1; i++) {
698  tmp = p2; p2 = p1; p1 = tmp;
699  if (p1->len == 0) {
700  p2->len = 0;
701  break;
702  }
703  poly_edge_clip(p1, clipper->v + i, clipper->v + i + 1, dir, p2);
704  }
705 
706  output->len = p2->len;
707  if (output->len)
708  memcpy(output->v, p2->v, p2->len * sizeof(point2_t));
709 }

Referenced by collect_ligth_polys().

◆ collect_cluster_lights()

static void collect_cluster_lights ( bsp_mesh_t wm,
bsp_t *  bsp 
)
static

Definition at line 1471 of file bsp_mesh.c.

1472 {
1473 #define MAX_LIGHTS_PER_CLUSTER 1024
1474  int* cluster_lights = Z_Malloc(MAX_LIGHTS_PER_CLUSTER * wm->num_clusters * sizeof(int));
1475  int* cluster_light_counts = Z_Mallocz(wm->num_clusters * sizeof(int));
1476 
1477  // Construct an array of visible lights for each cluster.
1478  // The array is in `cluster_lights`, with MAX_LIGHTS_PER_CLUSTER stride.
1479 
1480  for (int nlight = 0; nlight < wm->num_light_polys; nlight++)
1481  {
1482  light_poly_t* light = wm->light_polys + nlight;
1483 
1484  if(light->cluster < 0)
1485  continue;
1486 
1487  const byte* pvs = BSP_GetPvs(bsp, light->cluster);
1488 
1489  FOREACH_BIT_BEGIN(pvs, bsp->visrowsize, other_cluster)
1490  aabb_t* cluster_aabb = wm->cluster_aabbs + other_cluster;
1491  if (light_affects_cluster(light, cluster_aabb))
1492  {
1493  int* num_cluster_lights = cluster_light_counts + other_cluster;
1494  if (*num_cluster_lights < MAX_LIGHTS_PER_CLUSTER)
1495  {
1496  cluster_lights[other_cluster * MAX_LIGHTS_PER_CLUSTER + *num_cluster_lights] = nlight;
1497  (*num_cluster_lights)++;
1498  }
1499  }
1501  }
1502 
1503  // Count the total number of cluster <-> light relations to allocate memory
1504 
1505  wm->num_cluster_lights = 0;
1506  for (int cluster = 0; cluster < wm->num_clusters; cluster++)
1507  {
1508  wm->num_cluster_lights += cluster_light_counts[cluster];
1509  }
1510 
1511  wm->cluster_lights = Z_Mallocz(wm->num_cluster_lights * sizeof(int));
1512  wm->cluster_light_offsets = Z_Mallocz((wm->num_clusters + 1) * sizeof(int));
1513 
1514  // Com_Printf("Total interactions: %d, culled bbox: %d, culled proj: %d\n", wm->num_cluster_lights, lights_culled_bbox, lights_culled_proj);
1515 
1516  // Compact the previously constructed array into wm->cluster_lights
1517 
1518  int list_offset = 0;
1519  for (int cluster = 0; cluster < wm->num_clusters; cluster++)
1520  {
1521  assert(list_offset >= 0);
1522  wm->cluster_light_offsets[cluster] = list_offset;
1523  int count = cluster_light_counts[cluster];
1524  memcpy(
1525  wm->cluster_lights + list_offset,
1526  cluster_lights + MAX_LIGHTS_PER_CLUSTER * cluster,
1527  count * sizeof(int));
1528  list_offset += count;
1529  }
1530  wm->cluster_light_offsets[wm->num_clusters] = list_offset;
1531 
1532  Z_Free(cluster_lights);
1534 #undef MAX_LIGHTS_PER_CLUSTER
1535 }

Referenced by bsp_mesh_create_from_bsp().

◆ collect_ligth_polys()

static void collect_ligth_polys ( bsp_mesh_t wm,
bsp_t *  bsp,
int  model_idx,
int num_lights,
int allocated_lights,
light_poly_t **  lights 
)
static

Definition at line 729 of file bsp_mesh.c.

730 {
731  mface_t *surfaces = model_idx < 0 ? bsp->faces : bsp->models[model_idx].firstface;
732  int num_faces = model_idx < 0 ? bsp->numfaces : bsp->models[model_idx].numfaces;
733 
734  for (int i = 0; i < num_faces; i++)
735  {
736  mface_t *surf = surfaces + i;
737 
738  if (model_idx < 0 && belongs_to_model(bsp, surf))
739  continue;
740 
741  mtexinfo_t *texinfo = surf->texinfo;
742 
743  if(!texinfo->material)
744  continue;
745 
746  uint32_t material_id = texinfo->material->flags;
747 
748  if(!is_light_material(material_id))
749  continue;
750 
751  const image_t *image = texinfo->material->image_emissive;
752  if (!image)
753  {
754  // This algorithm relies on information from the emissive texture,
755  // specifically the extents of the emissive pixels in that texture.
756  // Ignore surfaces that don't have an emissive texture attached.
757  continue;
758  }
759 
760  int light_style = (texinfo->material->enable_light_styles) ? get_surf_light_style(surf) : 0;
761 
762  if (image->entire_texture_emissive)
763  {
764  // In some cases, the texture is uniform - example is "lsrlt1" used in the "mine" maps.
765  // Such textures are tiled over the models, and the more complex lighting system below
766  // breaks up the models into many small triangles, although there is no need to do that.
767  // In these cases, we just triangulate the surface polygon.
768 
769  float positions[3 * /*max_vertices*/ 32];
770 
771  for (int i = 0; i < surf->numsurfedges; i++)
772  {
773  msurfedge_t *src_surfedge = surf->firstsurfedge + i;
774  medge_t *src_edge = src_surfedge->edge;
775  mvertex_t *src_vert = src_edge->v[src_surfedge->vert];
776 
777  float *p = positions + i * 3;
778 
779  VectorCopy(src_vert->point, p);
780  }
781 
782  int num_vertices = surf->numsurfedges;
783  remove_collinear_edges(positions, NULL, &num_vertices);
784 
785  const int num_triangles = surf->numsurfedges - 2;
786 
787  for (int i = 0; i < num_triangles; i++)
788  {
789  const int e = surf->numsurfedges;
790 
791  int i1 = (i + 2) % e;
792  int i2 = (i + 1) % e;
793 
794  light_poly_t light;
795  VectorCopy(positions, light.positions + 0);
796  VectorCopy(positions + i1 * 3, light.positions + 3);
797  VectorCopy(positions + i2 * 3, light.positions + 6);
798  VectorCopy(image->light_color, light.color);
799 
800  light.material = texinfo->material;
801  light.style = light_style;
802 
803  if(!get_triangle_off_center(light.positions, light.off_center, NULL))
804  continue;
805 
806  light.cluster = BSP_PointLeaf(bsp->nodes, light.off_center)->cluster;
807 
808  if(light.cluster >= 0)
809  {
811  memcpy(list_light, &light, sizeof(light_poly_t));
812  }
813  }
814 
815  continue;
816  }
817 
818  vec4_t plane;
819  if (!get_surf_plane_equation(surf, plane))
820  {
821  // It's possible that some polygons in the game are degenerate, ignore these.
822  continue;
823  }
824 
825  image_t* image_diffuse = texinfo->material->image_diffuse;
826  float tex_scale[2] = { 1.0f / image_diffuse->width, 1.0f / image_diffuse->height };
827 
828  // Scale the texture axes according to the original resolution of the game's .wal textures
829  vec4_t tex_axis0, tex_axis1;
830  VectorScale(texinfo->axis[0], tex_scale[0], tex_axis0);
831  VectorScale(texinfo->axis[1], tex_scale[1], tex_axis1);
832  tex_axis0[3] = texinfo->offset[0] * tex_scale[0];
833  tex_axis1[3] = texinfo->offset[1] * tex_scale[1];
834 
835  // The texture basis is not normalized, so we need the lengths of the axes to convert
836  // texture coordinates back into world space
837  float tex_axis0_inv_square_length = 1.0f / DotProduct(tex_axis0, tex_axis0);
838  float tex_axis1_inv_square_length = 1.0f / DotProduct(tex_axis1, tex_axis1);
839 
840  // Find the normal of the texture plane
841  vec3_t tex_normal;
842  CrossProduct(tex_axis0, tex_axis1, tex_normal);
843  VectorNormalize(tex_normal);
844 
845  float surf_normal_dot_tex_normal = DotProduct(tex_normal, plane);
846 
847  if (surf_normal_dot_tex_normal == 0.f)
848  {
849  // Surface is perpendicular to texture plane, which means we can't un-project
850  // texture coordinates back onto the surface. This shouldn't happen though,
851  // so it should be safe to skip such lights.
852  continue;
853  }
854 
855  // Construct the surface polygon in texture space, and find its texture extents
856 
857  poly_t tex_poly;
858  tex_poly.len = surf->numsurfedges;
859 
860  point2_t tex_min = { FLT_MAX, FLT_MAX };
861  point2_t tex_max = { -FLT_MAX, -FLT_MAX };
862 
863  for (int i = 0; i < surf->numsurfedges; i++)
864  {
865  msurfedge_t *src_surfedge = surf->firstsurfedge + i;
866  medge_t *src_edge = src_surfedge->edge;
867  mvertex_t *src_vert = src_edge->v[src_surfedge->vert];
868 
869  point2_t t;
870  t.x = DotProduct(src_vert->point, tex_axis0) + tex_axis0[3];
871  t.y = DotProduct(src_vert->point, tex_axis1) + tex_axis1[3];
872 
873  tex_poly.v[i] = t;
874 
875  tex_min.x = min(tex_min.x, t.x);
876  tex_min.y = min(tex_min.y, t.y);
877  tex_max.x = max(tex_max.x, t.x);
878  tex_max.y = max(tex_max.y, t.y);
879  }
880 
881  // Instantiate a square polygon for every repetition of the texture in this surface,
882  // then clip the original surface against that square polygon.
883 
884  for (float y_tile = floorf(tex_min.y); y_tile <= ceilf(tex_max.y); y_tile++)
885  {
886  for (float x_tile = floorf(tex_min.x); x_tile <= ceilf(tex_max.x); x_tile++)
887  {
888  float x_min = x_tile + image->min_light_texcoord[0];
889  float x_max = x_tile + image->max_light_texcoord[0];
890  float y_min = y_tile + image->min_light_texcoord[1];
891  float y_max = y_tile + image->max_light_texcoord[1];
892 
893  // The square polygon, for this repetition, according to the extents of emissive pixels
894 
895  poly_t clipper;
896  clipper.len = 4;
897  clipper.v[0].x = x_min; clipper.v[0].y = y_min;
898  clipper.v[1].x = x_max; clipper.v[1].y = y_min;
899  clipper.v[2].x = x_max; clipper.v[2].y = y_max;
900  clipper.v[3].x = x_min; clipper.v[3].y = y_max;
901 
902  // Clip it
903 
904  poly_t instance;
905  clip_polygon(&tex_poly, &clipper, &instance);
906 
907  if (instance.len < 3)
908  {
909  // The square polygon was outside of the original surface
910  continue;
911  }
912 
913  // Map the clipped polygon back onto the surface plane
914 
915  vec3_t instance_positions[MAX_POLY_VERTS];
916  for (int vert = 0; vert < instance.len; vert++)
917  {
918  // Find a world space point on the texture projection plane
919 
920  vec3_t p0, p1, point_on_texture_plane;
921  VectorScale(tex_axis0, (instance.v[vert].x - tex_axis0[3]) * tex_axis0_inv_square_length, p0);
922  VectorScale(tex_axis1, (instance.v[vert].y - tex_axis1[3]) * tex_axis1_inv_square_length, p1);
923  VectorAdd(p0, p1, point_on_texture_plane);
924 
925  // Shoot a ray from that point in the texture normal direction,
926  // and intersect it with the surface plane.
927 
928  // plane: P.N + d = 0
929  // ray: P = At + B
930  // (At + B).N + d = 0
931  // (A.N)t + B.N + d = 0
932  // t = -(B.N + d) / (A.N)
933 
934  float bn = DotProduct(point_on_texture_plane, plane);
935 
936  float ray_t = -(bn + plane[3]) / surf_normal_dot_tex_normal;
937 
938  vec3_t p2;
939  VectorScale(tex_normal, ray_t, p2);
940  VectorAdd(p2, point_on_texture_plane, instance_positions[vert]);
941  }
942 
943  // Create triangles for the polygon, using a triangle fan topology
944 
945  const int num_triangles = instance.len - 2;
946 
947  for (int i = 0; i < num_triangles; i++)
948  {
949  const int e = instance.len;
950 
951  int i1 = (i + 2) % e;
952  int i2 = (i + 1) % e;
953 
954  light_poly_t* light = append_light_poly(num_lights, allocated_lights, lights);
955  light->material = texinfo->material;
956  light->style = light_style;
957  VectorCopy(instance_positions[0], light->positions + 0);
958  VectorCopy(instance_positions[i1], light->positions + 3);
959  VectorCopy(instance_positions[i2], light->positions + 6);
960  VectorCopy(image->light_color, light->color);
961 
962  get_triangle_off_center(light->positions, light->off_center, NULL);
963 
964  if (model_idx < 0)
965  {
966  // Find the cluster for this triangle
967  light->cluster = BSP_PointLeaf(bsp->nodes, light->off_center)->cluster;
968 
969  if (light->cluster < 0)
970  {
971  // Cluster not found - which happens sometimes.
972  // The lighting system can't work with lights that have no cluster, so remove the triangle.
973  (*num_lights)--;
974  }
975  }
976  else
977  {
978  // It's a model: cluster will be determined after model instantiation.
979  light->cluster = -1;
980  }
981  }
982  }
983  }
984  }
985 }

Referenced by bsp_mesh_create_from_bsp().

◆ collect_sky_and_lava_ligth_polys()

static void collect_sky_and_lava_ligth_polys ( bsp_mesh_t wm,
bsp_t *  bsp 
)
static

Definition at line 988 of file bsp_mesh.c.

989 {
990  for (int i = 0; i < bsp->numfaces; i++)
991  {
992  mface_t *surf = bsp->faces + i;
993 
994  if (belongs_to_model(bsp, surf))
995  continue;
996 
997  int flags = surf->drawflags;
998  if (surf->texinfo) flags |= surf->texinfo->c.flags;
999 
1000  qboolean is_sky = !!(flags & SURF_SKY);
1001  qboolean is_lava = surf->texinfo->material ? MAT_IsKind(surf->texinfo->material->flags, MATERIAL_KIND_LAVA) : qfalse;
1002 
1003  if (!is_sky && !is_lava)
1004  continue;
1005 
1006  float positions[3 * /*max_vertices*/ 32];
1007 
1008  for (int i = 0; i < surf->numsurfedges; i++)
1009  {
1010  msurfedge_t *src_surfedge = surf->firstsurfedge + i;
1011  medge_t *src_edge = src_surfedge->edge;
1012  mvertex_t *src_vert = src_edge->v[src_surfedge->vert];
1013 
1014  float *p = positions + i * 3;
1015 
1016  VectorCopy(src_vert->point, p);
1017  }
1018 
1019  int num_vertices = surf->numsurfedges;
1020  remove_collinear_edges(positions, NULL, &num_vertices);
1021 
1022  const int num_triangles = num_vertices - 2;
1023 
1024  for (int i = 0; i < num_triangles; i++)
1025  {
1026  int i1 = (i + 2) % num_vertices;
1027  int i2 = (i + 1) % num_vertices;
1028 
1029  light_poly_t light;
1030  VectorCopy(positions, light.positions + 0);
1031  VectorCopy(positions + i1 * 3, light.positions + 3);
1032  VectorCopy(positions + i2 * 3, light.positions + 6);
1033 
1034  if (is_sky)
1035  {
1036  VectorSet(light.color, -1.f, -1.f, -1.f); // special value for the sky
1037  light.material = 0;
1038  }
1039  else
1040  {
1041  VectorCopy(surf->texinfo->material->image_emissive->light_color, light.color);
1042  light.material = surf->texinfo->material;
1043  }
1044 
1045  light.style = 0;
1046 
1047  if (!get_triangle_off_center(light.positions, light.off_center, NULL))
1048  continue;
1049 
1050  light.cluster = BSP_PointLeaf(bsp->nodes, light.off_center)->cluster;
1051 
1052  if (is_sky_or_lava_cluster(wm, surf, light.cluster, surf->texinfo->material->flags))
1053  {
1055  memcpy(list_light, &light, sizeof(light_poly_t));
1056  }
1057  }
1058  }
1059 }

Referenced by bsp_mesh_create_from_bsp().

◆ collect_surfaces()

static void collect_surfaces ( int idx_ctr,
bsp_mesh_t wm,
bsp_t *  bsp,
int  model_idx,
int(*)(int filter 
)
static

Definition at line 457 of file bsp_mesh.c.

458 {
459  mface_t *surfaces = model_idx < 0 ? bsp->faces : bsp->models[model_idx].firstface;
460  int num_faces = model_idx < 0 ? bsp->numfaces : bsp->models[model_idx].numfaces;
461  qboolean any_pvs_patches = qfalse;
462 
463  for (int i = 0; i < num_faces; i++) {
464  mface_t *surf = surfaces + i;
465 
466  if (model_idx < 0 && belongs_to_model(bsp, surf)) {
467  continue;
468  }
469 
470  uint32_t material_id = surf->texinfo->material ? surf->texinfo->material->flags : 0;
471  uint32_t surf_flags = surf->drawflags | surf->texinfo->c.flags;
472 
473  // ugly hacks for situations when the same texture is used with different effects
474 
475  if ((MAT_IsKind(material_id, MATERIAL_KIND_WATER) || MAT_IsKind(material_id, MATERIAL_KIND_SLIME)) && !(surf_flags & SURF_WARP))
476  material_id = MAT_SetKind(material_id, MATERIAL_KIND_REGULAR);
477 
478  if (MAT_IsKind(material_id, MATERIAL_KIND_GLASS) && !(surf_flags & SURF_TRANS_MASK))
479  material_id = MAT_SetKind(material_id, MATERIAL_KIND_REGULAR);
480 
481  if ((surf_flags & SURF_NODRAW) && cvar_pt_enable_nodraw->integer)
482  continue;
483 
484  // custom transparent surfaces
485  if (surf_flags & SURF_SKY)
486  material_id = MAT_SetKind(material_id, MATERIAL_KIND_SKY);
487 
488  if (MAT_IsKind(material_id, MATERIAL_KIND_REGULAR) && (surf_flags & SURF_TRANS_MASK) && !(material_id & MATERIAL_FLAG_LIGHT))
489  material_id = MAT_SetKind(material_id, MATERIAL_KIND_TRANSPARENT);
490 
491  if (MAT_IsKind(material_id, MATERIAL_KIND_SCREEN) && (surf_flags & SURF_TRANS_MASK))
492  material_id = MAT_SetKind(material_id, MATERIAL_KIND_GLASS);
493 
494  if (surf_flags & SURF_WARP)
495  material_id |= MATERIAL_FLAG_WARP;
496 
497  if (surf_flags & SURF_FLOWING)
498  material_id |= MATERIAL_FLAG_FLOWING;
499 
500  if (!filter(material_id))
501  continue;
502 
503  if ((material_id & MATERIAL_FLAG_LIGHT) && surf->texinfo->material->enable_light_styles)
504  {
505  int light_style = get_surf_light_style(surf);
506  material_id |= (light_style << MATERIAL_LIGHT_STYLE_SHIFT) & MATERIAL_LIGHT_STYLE_MASK;
507  }
508 
509  if (MAT_IsKind(material_id, MATERIAL_KIND_CAMERA) && wm->num_cameras > 0)
510  {
511  // Assign a random camera for this face
512  int camera_id = rand() % (wm->num_cameras * 4);
513  material_id = (material_id & ~MATERIAL_LIGHT_STYLE_MASK) | ((camera_id << MATERIAL_LIGHT_STYLE_SHIFT) & MATERIAL_LIGHT_STYLE_MASK);
514  }
515 
516  if (*idx_ctr + create_poly(surf, material_id, NULL, NULL, NULL) >= MAX_VERT_BSP) {
517  Com_Error(ERR_FATAL, "error: exceeding max vertex limit\n");
518  }
519 
520  int cnt = create_poly(surf, material_id,
521  &wm->positions[*idx_ctr * 3],
522  &wm->tex_coords[*idx_ctr * 2],
523  &wm->materials[*idx_ctr / 3]);
524 
525  for (int it = *idx_ctr / 3, k = 0; k < cnt; k += 3, ++it)
526  {
527  if (model_idx < 0)
528  {
529  // Compute the BSP node for this specific triangle based on its center.
530  // The face lists in the BSP are slightly incorrect, or the original code
531  // in q2vkpt that was extracting them was incorrect.
532 
533  vec3_t center, anti_center;
534  get_triangle_off_center(wm->positions + it * 9, center, anti_center);
535 
536  int cluster = BSP_PointLeaf(bsp->nodes, center)->cluster;
537  wm->clusters[it] = cluster;
538 
539  if (cluster >= 0 && (MAT_IsKind(material_id, MATERIAL_KIND_SKY) || MAT_IsKind(material_id, MATERIAL_KIND_LAVA)))
540  {
541  if(is_sky_or_lava_cluster(wm, surf, cluster, material_id))
542  {
543  wm->materials[it] |= MATERIAL_FLAG_LIGHT;
544  }
545  }
546 
547  if (!bsp->pvs_patched)
548  {
549  if (MAT_IsKind(material_id, MATERIAL_KIND_SLIME) || MAT_IsKind(material_id, MATERIAL_KIND_WATER) || MAT_IsKind(material_id, MATERIAL_KIND_GLASS) || MAT_IsKind(material_id, MATERIAL_KIND_TRANSPARENT))
550  {
551  int anti_cluster = BSP_PointLeaf(bsp->nodes, anti_center)->cluster;
552 
553  if (cluster >= 0 && anti_cluster >= 0 && cluster != anti_cluster)
554  {
555  char* pvs_cluster = BSP_GetPvs(bsp, cluster);
556  char* pvs_anti_cluster = BSP_GetPvs(bsp, anti_cluster);
557 
558  if (!Q_IsBitSet(pvs_cluster, anti_cluster) || !Q_IsBitSet(pvs_anti_cluster, cluster))
559  {
560  connect_pvs(bsp, cluster, pvs_cluster, anti_cluster, pvs_anti_cluster);
561  any_pvs_patches = qtrue;
562  }
563  }
564  }
565  }
566  }
567  else
568  wm->clusters[it] = -1;
569  }
570 
571  *idx_ctr += cnt;
572  }
573 
574  if (any_pvs_patches)
575  make_pvs_symmetric(bsp);
576 }

Referenced by bsp_mesh_create_from_bsp().

◆ compute_aabb()

void compute_aabb ( const float *  positions,
int  numvert,
float *  aabb_min,
float *  aabb_max 
)

Definition at line 1111 of file bsp_mesh.c.

1112 {
1113  VectorSet(aabb_min, FLT_MAX, FLT_MAX, FLT_MAX);
1114  VectorSet(aabb_max, -FLT_MAX, -FLT_MAX, -FLT_MAX);
1115 
1116  for (int i = 0; i < numvert; i++)
1117  {
1118  float const* position = positions + i * 3;
1119 
1120  aabb_min[0] = min(aabb_min[0], position[0]);
1121  aabb_min[1] = min(aabb_min[1], position[1]);
1122  aabb_min[2] = min(aabb_min[2], position[2]);
1123 
1124  aabb_max[0] = max(aabb_max[0], position[0]);
1125  aabb_max[1] = max(aabb_max[1], position[1]);
1126  aabb_max[2] = max(aabb_max[2], position[2]);
1127  }
1128 }

Referenced by bsp_mesh_create_from_bsp().

◆ compute_cluster_aabbs()

static void compute_cluster_aabbs ( bsp_mesh_t wm)
static

Definition at line 1388 of file bsp_mesh.c.

1389 {
1390  wm->cluster_aabbs = Z_Malloc(wm->num_clusters * sizeof(aabb_t));
1391  for (int c = 0; c < wm->num_clusters; c++)
1392  {
1393  VectorSet(wm->cluster_aabbs[c].mins, FLT_MAX, FLT_MAX, FLT_MAX);
1394  VectorSet(wm->cluster_aabbs[c].maxs, -FLT_MAX, -FLT_MAX, -FLT_MAX);
1395  }
1396 
1397  for (int tri = 0; tri < wm->world_idx_count / 3; tri++)
1398  {
1399  int c = wm->clusters[tri];
1400 
1401  if(c < 0 || c >= wm->num_clusters)
1402  continue;
1403 
1404  aabb_t* aabb = wm->cluster_aabbs + c;
1405 
1406  for (int i = 0; i < 3; i++)
1407  {
1408  float const* position = wm->positions + tri * 9 + i * 3;
1409 
1410  aabb->mins[0] = min(aabb->mins[0], position[0]);
1411  aabb->mins[1] = min(aabb->mins[1], position[1]);
1412  aabb->mins[2] = min(aabb->mins[2], position[2]);
1413 
1414  aabb->maxs[0] = max(aabb->maxs[0], position[0]);
1415  aabb->maxs[1] = max(aabb->maxs[1], position[1]);
1416  aabb->maxs[2] = max(aabb->maxs[2], position[2]);
1417  }
1418  }
1419 }

Referenced by bsp_mesh_create_from_bsp().

◆ compute_sky_visibility()

static void compute_sky_visibility ( bsp_mesh_t wm,
bsp_t *  bsp 
)
static

Definition at line 1354 of file bsp_mesh.c.

1355 {
1356  memset(wm->sky_visibility, 0, VIS_MAX_BYTES);
1357 
1358  if (wm->world_sky_count == 0 && wm->world_custom_sky_count == 0)
1359  return;
1360 
1361  int numclusters = bsp->vis->numclusters;
1362 
1363  char clusters_with_sky[VIS_MAX_BYTES];
1364 
1365  memset(clusters_with_sky, 0, VIS_MAX_BYTES);
1366 
1367  for (int i = 0; i < (wm->world_sky_count + wm->world_custom_sky_count) / 3; i++)
1368  {
1369  int prim = wm->world_sky_offset / 3 + i;
1370 
1371  int cluster = wm->clusters[prim];
1372  clusters_with_sky[cluster >> 3] |= (1 << (cluster & 7));
1373  }
1374 
1375  for (int cluster = 0; cluster < numclusters; cluster++)
1376  {
1377  if (clusters_with_sky[cluster >> 3] & (1 << (cluster & 7)))
1378  {
1379  char* mask = BSP_GetPvs(bsp, cluster);
1380 
1381  for (int i = 0; i < bsp->visrowsize; i++)
1382  wm->sky_visibility[i] |= mask[i];
1383  }
1384  }
1385 }

Referenced by bsp_mesh_create_from_bsp().

◆ compute_world_tangents()

void compute_world_tangents ( bsp_mesh_t wm)

Definition at line 1131 of file bsp_mesh.c.

1132 {
1133  // compute tangent space
1134  uint32_t ntriangles = wm->num_indices / 3;
1135 
1136  // tangent space is co-planar to triangle : only need to compute
1137  // 1 vertex because all 3 verts share the same tangent space
1138  wm->tangents = Z_Malloc(MAX_VERT_BSP * sizeof(*wm->tangents));
1139  wm->texel_density = Z_Malloc(MAX_VERT_BSP * sizeof(float) / 3);
1140 
1141  for (int idx_tri = 0; idx_tri < ntriangles; ++idx_tri)
1142  {
1143  uint32_t iA = wm->indices[idx_tri * 3 + 0]; // no vertex indexing
1144  uint32_t iB = wm->indices[idx_tri * 3 + 1];
1145  uint32_t iC = wm->indices[idx_tri * 3 + 2];
1146 
1147  float const * pA = wm->positions + (iA * 3);
1148  float const * pB = wm->positions + (iB * 3);
1149  float const * pC = wm->positions + (iC * 3);
1150 
1151  float const * tA = wm->tex_coords + (iA * 2);
1152  float const * tB = wm->tex_coords + (iB * 2);
1153  float const * tC = wm->tex_coords + (iC * 2);
1154 
1155  vec3_t dP0, dP1;
1156  VectorSubtract(pB, pA, dP0);
1157  VectorSubtract(pC, pA, dP1);
1158 
1159  vec2_t dt0, dt1;
1160  Vector2Subtract(tB, tA, dt0);
1161  Vector2Subtract(tC, tA, dt1);
1162 
1163  float r = 1.f / (dt0[0] * dt1[1] - dt1[0] * dt0[1]);
1164 
1165  vec3_t sdir = {
1166  (dt1[1] * dP0[0] - dt0[1] * dP1[0]) * r,
1167  (dt1[1] * dP0[1] - dt0[1] * dP1[1]) * r,
1168  (dt1[1] * dP0[2] - dt0[1] * dP1[2]) * r };
1169 
1170  vec3_t tdir = {
1171  (dt0[0] * dP1[0] - dt1[0] * dP0[0]) * r,
1172  (dt0[0] * dP1[1] - dt1[0] * dP0[1]) * r,
1173  (dt0[0] * dP1[2] - dt1[0] * dP0[2]) * r };
1174 
1175  vec3_t normal;
1176  CrossProduct(dP0, dP1, normal);
1177  VectorNormalize(normal);
1178 
1179  vec3_t tangent;
1180 
1181  vec3_t t;
1182  VectorScale(normal, DotProduct(normal, sdir), t);
1183  VectorSubtract(sdir, t, t);
1184  VectorNormalize2(t, tangent); // Graham-Schmidt : t = normalize(t - n * (n.t))
1185 
1186  VectorSet(&wm->tangents[idx_tri * 3], tangent[0], tangent[1], tangent[2]);
1187 
1188  vec3_t cross;
1189  CrossProduct(normal, t, cross);
1190  float dot = DotProduct(cross, tdir);
1191 
1192  if (dot < 0.0f)
1193  {
1194  wm->materials[idx_tri] |= MATERIAL_FLAG_HANDEDNESS;
1195  }
1196 
1197  float texel_density = 0.f;
1198  int material_idx = wm->materials[idx_tri] & MATERIAL_INDEX_MASK;
1199  pbr_material_t* mat = MAT_GetPBRMaterial(material_idx);
1200  if (mat && mat->image_diffuse)
1201  {
1202  dt0[0] *= mat->image_diffuse->width;
1203  dt0[1] *= mat->image_diffuse->height;
1204  dt1[0] *= mat->image_diffuse->width;
1205  dt1[1] *= mat->image_diffuse->height;
1206 
1207  float WL0 = VectorLength(dP0);
1208  float WL1 = VectorLength(dP1);
1209  float TL0 = sqrt(dt0[0] * dt0[0] + dt0[1] * dt0[1]);
1210  float TL1 = sqrt(dt1[0] * dt1[0] + dt1[1] * dt1[1]);
1211  float L0 = (WL0 > 0) ? (TL0 / WL0) : 0.f;
1212  float L1 = (WL1 > 0) ? (TL1 / WL1) : 0.f;
1213 
1214  texel_density = max(L0, L1);
1215  }
1216 
1217  wm->texel_density[idx_tri] = texel_density;
1218  }
1219 }

Referenced by bsp_mesh_create_from_bsp().

◆ connect_pvs()

static void connect_pvs ( bsp_t *  bsp,
int  cluster_a,
char *  pvs_a,
int  cluster_b,
char *  pvs_b 
)
static

Definition at line 400 of file bsp_mesh.c.

401 {
402  FOREACH_BIT_BEGIN(pvs_a, bsp->visrowsize, vis_cluster_a)
403  if (vis_cluster_a != cluster_a && vis_cluster_a != cluster_b)
404  {
405  merge_pvs_rows(bsp, pvs_b, BSP_GetPvs(bsp, vis_cluster_a));
406  }
408 
409  FOREACH_BIT_BEGIN(pvs_b, bsp->visrowsize, vis_cluster_b)
410  if (vis_cluster_b != cluster_a && vis_cluster_b != cluster_b)
411  {
412  merge_pvs_rows(bsp, pvs_a, BSP_GetPvs(bsp, vis_cluster_b));
413  }
415 
416  merge_pvs_rows(bsp, pvs_a, pvs_b);
417  merge_pvs_rows(bsp, pvs_b, pvs_a);
418 }

Referenced by collect_surfaces().

◆ create_poly()

static int create_poly ( const mface_t *  surf,
uint32_t  material_id,
float *  positions_out,
float *  tex_coord_out,
uint32_t *  material_out 
)
static

Definition at line 96 of file bsp_mesh.c.

102 {
103  static const int max_vertices = 32;
104  float positions [3 * /*max_vertices*/ 32];
105  float tex_coords[2 * /*max_vertices*/ 32];
106  mtexinfo_t *texinfo = surf->texinfo;
107  assert(surf->numsurfedges < max_vertices);
108 
109  float sc[2] = { 1.f, 1.f };
110  if (texinfo->material)
111  {
112  image_t* image_diffuse = texinfo->material->image_diffuse;
113  sc[0] = 1.0f / image_diffuse->width;
114  sc[1] = 1.0f / image_diffuse->height;
115  }
116 
117  float pos_center[3] = { 0 };
118  float tc_center[2];
119 
120  for (int i = 0; i < surf->numsurfedges; i++) {
121  msurfedge_t *src_surfedge = surf->firstsurfedge + i;
122  medge_t *src_edge = src_surfedge->edge;
123  mvertex_t *src_vert = src_edge->v[src_surfedge->vert];
124 
125  float *p = positions + i * 3;
126  float *t = tex_coords + i * 2;
127 
128  VectorCopy(src_vert->point, p);
129 
130  pos_center[0] += src_vert->point[0];
131  pos_center[1] += src_vert->point[1];
132  pos_center[2] += src_vert->point[2];
133 
134  t[0] = (DotProduct(p, texinfo->axis[0]) + texinfo->offset[0]) * sc[0];
135  t[1] = (DotProduct(p, texinfo->axis[1]) + texinfo->offset[1]) * sc[1];
136 
137 #if DUMP_WORLD_MESH_TO_OBJ
138  if (obj_dump_file)
139  {
140  fprintf(obj_dump_file, "v %.3f %.3f %.3f\n", src_vert->point[0], src_vert->point[1], src_vert->point[2]);
141  }
142 #endif
143  }
144 
145 #if DUMP_WORLD_MESH_TO_OBJ
146  if (obj_dump_file)
147  {
148  fprintf(obj_dump_file, "f ");
149  for (int i = 0; i < surf->numsurfedges; i++) {
150  fprintf(obj_dump_file, "%d ", obj_vertex_num);
151  obj_vertex_num++;
152  }
153  fprintf(obj_dump_file, "\n");
154  }
155 #endif
156 
157  pos_center[0] /= (float)surf->numsurfedges;
158  pos_center[1] /= (float)surf->numsurfedges;
159  pos_center[2] /= (float)surf->numsurfedges;
160 
161  tc_center[0] = (DotProduct(pos_center, texinfo->axis[0]) + texinfo->offset[0]) * sc[0];
162  tc_center[1] = (DotProduct(pos_center, texinfo->axis[1]) + texinfo->offset[1]) * sc[1];
163 
164  int num_vertices = surf->numsurfedges;
165 
166  qboolean is_sky = MAT_IsKind(material_id, MATERIAL_KIND_SKY);
167  if (is_sky)
168  {
169  // process skybox geometry in the same way as we process it for analytic light generation
170  // to avoid mismatches between lights and geometry
171  remove_collinear_edges(positions, tex_coords, &num_vertices);
172  }
173 
174 #define CP_V(idx, src) \
175  do { \
176  if(positions_out) { \
177  memcpy(positions_out + (idx) * 3, src, sizeof(float) * 3); \
178  } \
179  } while(0)
180 
181 #define CP_T(idx, src) \
182  do { \
183  if(tex_coord_out) { \
184  memcpy(tex_coord_out + (idx) * 2, src, sizeof(float) * 2); \
185  } \
186  } while(0)
187 
188 #define CP_M(idx) \
189  do { \
190  if(material_out) { \
191  material_out[k] = material_id; \
192  } \
193  } while(0)
194 
195  int k = 0;
196  /* switch between triangle fan around center or first vertex */
197  //int tess_center = 0;
198  int tess_center = num_vertices > 4 && !is_sky;
199 
200  const int num_triangles = tess_center
201  ? num_vertices
202  : num_vertices - 2;
203 
204  for (int i = 0; i < num_triangles; i++)
205  {
206  int i1 = (i + 2 - tess_center) % num_vertices;
207  int i2 = (i + 1 - tess_center) % num_vertices;
208 
209  CP_V(k, tess_center ? pos_center : positions);
210  CP_T(k, tess_center ? tc_center : tex_coords);
211  CP_M(k);
212  k++;
213 
214  CP_V(k, positions + i1 * 3);
215  CP_T(k, tex_coords + i1 * 2);
216  CP_M(k);
217  k++;
218 
219  CP_V(k, positions + i2 * 3);
220  CP_T(k, tex_coords + i2 * 2);
221  CP_M(k);
222  k++;
223 
224  }
225 
226 #undef CP_V
227 #undef CP_T
228 #undef CP_M
229 
230  assert(k % 3 == 0);
231  return k;
232 }

Referenced by collect_surfaces().

◆ cross2()

static float cross2 ( point2_t a,
point2_t b 
)
inlinestatic

Definition at line 600 of file bsp_mesh.c.

601 {
602  return a->x * b->y - a->y * b->x;
603 }

Referenced by left_of(), and line_sect().

◆ dot2()

static float dot2 ( point2_t a,
point2_t b 
)
inlinestatic

Definition at line 594 of file bsp_mesh.c.

595 {
596  return a->x * b->x + a->y * b->y;
597 }

◆ encode_normal()

uint32_t encode_normal ( vec3_t  normal)

Definition at line 1083 of file bsp_mesh.c.

1084 {
1085  uint32_t projected0, projected1;
1086  float invL1Norm = 1.0f / (fabs(normal[0]) + fabs(normal[1]) + fabs(normal[2]));
1087 
1088  // first find floating point values of octahedral map in [-1,1]:
1089  float enc0, enc1;
1090  if (normal[2] < 0.0f) {
1091  enc0 = (1.0f - abs(normal[1] * invL1Norm)) * ((normal[0] < 0.0f) ? -1.0f : 1.0f);
1092  enc1 = (1.0f - abs(normal[0] * invL1Norm)) * ((normal[1] < 0.0f) ? -1.0f : 1.0f);
1093  }
1094  else {
1095  enc0 = normal[0] * invL1Norm;
1096  enc1 = normal[1] * invL1Norm;
1097  }
1098  // then encode:
1099  uint32_t enci0 = floatBitsToUint((abs(enc0) + 2.0f) / 2.0f);
1100  uint32_t enci1 = floatBitsToUint((abs(enc1) + 2.0f) / 2.0f);
1101  // copy over sign bit and truncated mantissa. could use rounding for increased precision here.
1102  projected0 = ((floatBitsToUint(enc0) & 0x80000000u) >> 16) | ((enci0 & 0x7fffffu) >> 8);
1103  projected1 = ((floatBitsToUint(enc1) & 0x80000000u) >> 16) | ((enci1 & 0x7fffffu) >> 8);
1104  // avoid -0 cases:
1105  if ((projected0 & 0x7fffu) == 0) projected0 = 0;
1106  if ((projected1 & 0x7fffu) == 0) projected1 = 0;
1107  return (projected1 << 16) | projected0;
1108 }

◆ filter_all()

static int filter_all ( int  flags)
static

Definition at line 271 of file bsp_mesh.c.

272 {
273  if (MAT_IsKind(flags, MATERIAL_KIND_SKY))
274  return 0;
275 
276  return 1;
277 }

Referenced by bsp_mesh_create_from_bsp().

◆ filter_static_opaque()

static int filter_static_opaque ( int  flags)
static

Definition at line 245 of file bsp_mesh.c.

246 {
247  flags &= MATERIAL_KIND_MASK;
248  if (flags == MATERIAL_KIND_SKY || flags == MATERIAL_KIND_WATER || flags == MATERIAL_KIND_SLIME || flags == MATERIAL_KIND_GLASS || flags == MATERIAL_KIND_TRANSPARENT)
249  return 0;
250 
251  return 1;
252 }

Referenced by bsp_mesh_create_from_bsp().

◆ filter_static_sky()

static int filter_static_sky ( int  flags)
static

Definition at line 263 of file bsp_mesh.c.

264 {
265  if (MAT_IsKind(flags, MATERIAL_KIND_SKY))
266  return 1;
267 
268  return 0;
269 }

Referenced by bsp_mesh_create_from_bsp().

◆ filter_static_transparent()

static int filter_static_transparent ( int  flags)
static

Definition at line 254 of file bsp_mesh.c.

255 {
256  flags &= MATERIAL_KIND_MASK;
257  if (flags == MATERIAL_KIND_WATER || flags == MATERIAL_KIND_SLIME || flags == MATERIAL_KIND_GLASS || flags == MATERIAL_KIND_TRANSPARENT)
258  return 1;
259 
260  return 0;
261 }

Referenced by bsp_mesh_create_from_bsp().

◆ floatBitsToUint()

uint32_t floatBitsToUint ( float  f)

Definition at line 1080 of file bsp_mesh.c.

1080 { return *((uint32_t*)&f); }

Referenced by encode_normal().

◆ get_aabb_corner()

static void get_aabb_corner ( aabb_t aabb,
int  corner_idx,
vec3_t  corner 
)
static

Definition at line 1422 of file bsp_mesh.c.

1423 {
1424  corner[0] = (corner_idx & 1) ? aabb->maxs[0] : aabb->mins[0];
1425  corner[1] = (corner_idx & 2) ? aabb->maxs[1] : aabb->mins[1];
1426  corner[2] = (corner_idx & 4) ? aabb->maxs[2] : aabb->mins[2];
1427 }

Referenced by light_affects_cluster().

◆ get_surf_light_style()

static int get_surf_light_style ( const mface_t *  surf)
static

Definition at line 317 of file bsp_mesh.c.

318 {
319  for (int nstyle = 0; nstyle < 4; nstyle++)
320  {
321  if (surf->styles[nstyle] != 0 && surf->styles[nstyle] != 255)
322  {
323  return surf->styles[nstyle];
324  }
325  }
326 
327  return 0;
328 }

Referenced by collect_ligth_polys(), and collect_surfaces().

◆ get_surf_plane_equation()

static qboolean get_surf_plane_equation ( mface_t *  surf,
float *  plane 
)
static

Definition at line 331 of file bsp_mesh.c.

332 {
333  for (int i = 0; i < surf->numsurfedges - 2; i++)
334  {
335  float* v0 = surf->firstsurfedge[i + 0].edge->v[surf->firstsurfedge[i + 0].vert]->point;
336  float* v1 = surf->firstsurfedge[i + 1].edge->v[surf->firstsurfedge[i + 1].vert]->point;
337  float* v2 = surf->firstsurfedge[(i + 2) % surf->numsurfedges].edge->v[surf->firstsurfedge[(i + 2) % surf->numsurfedges].vert]->point;
338  vec3_t e0, e1;
339  VectorSubtract(v1, v0, e0);
340  VectorSubtract(v2, v1, e1);
341  CrossProduct(e0, e1, plane);
342  float len = VectorLength(plane);
343  if (len > 0)
344  {
345  VectorScale(plane, 1.0f / len, plane);
346  plane[3] = -DotProduct(plane, v0);
347  return qtrue;
348  }
349  }
350 
351  return qfalse;
352 }

Referenced by collect_ligth_polys(), and is_sky_or_lava_cluster().

◆ get_triangle_off_center()

qboolean get_triangle_off_center ( const float *  positions,
float *  center,
float *  anti_center 
)

Definition at line 282 of file bsp_mesh.c.

283 {
284  const float* v0 = positions + 0;
285  const float* v1 = positions + 3;
286  const float* v2 = positions + 6;
287 
288  // Compute the triangle center
289 
290  VectorCopy(v0, center);
291  VectorAdd(center, v1, center);
292  VectorAdd(center, v2, center);
293  VectorScale(center, 1.f / 3.f, center);
294 
295  // Compute the normal
296 
297  vec3_t e1, e2, normal;
298  VectorSubtract(v1, v0, e1);
299  VectorSubtract(v2, v0, e2);
300  CrossProduct(e1, e2, normal);
301  float length = VectorNormalize(normal);
302 
303  // Offset the center by one normal to make sure that the point is
304  // inside a BSP leaf and not on a boundary plane.
305 
306  VectorAdd(center, normal, center);
307 
308  if (anti_center)
309  {
310  VectorMA(center, -2.f, normal, anti_center);
311  }
312 
313  return (length > 0.f);
314 }

Referenced by bsp_mesh_load_custom_sky(), collect_ligth_polys(), collect_sky_and_lava_ligth_polys(), collect_surfaces(), and vkpt_build_cylinder_light().

◆ is_light_material()

static qboolean is_light_material ( uint32_t  material)
inlinestatic

Definition at line 723 of file bsp_mesh.c.

724 {
725  return (material & MATERIAL_FLAG_LIGHT) != 0;
726 }

Referenced by collect_ligth_polys().

◆ is_model_transparent()

static qboolean is_model_transparent ( bsp_mesh_t wm,
bsp_model_t model 
)
static

Definition at line 1062 of file bsp_mesh.c.

1063 {
1064  if (model->idx_count == 0)
1065  return qfalse;
1066 
1067  for (int i = 0; i < model->idx_count / 3; i++)
1068  {
1069  int prim = model->idx_offset / 3 + i;
1070  int material = wm->materials[prim];
1071 
1073  return qfalse;
1074  }
1075 
1076  return qtrue;
1077 }

Referenced by bsp_mesh_create_from_bsp().

◆ is_sky_or_lava_cluster()

static qboolean is_sky_or_lava_cluster ( bsp_mesh_t wm,
mface_t *  surf,
int  cluster,
int  material_id 
)
static

Definition at line 355 of file bsp_mesh.c.

356 {
357  if (cluster < 0)
358  return qfalse;
359 
360  if (MAT_IsKind(material_id, MATERIAL_KIND_LAVA) && wm->all_lava_emissive)
361  {
362  vec4_t plane;
363  if (get_surf_plane_equation(surf, plane))
364  {
365  if (plane[2] < 0.f)
366  return qtrue;
367  }
368  }
369  else
370  {
371  for (int i = 0; i < wm->num_sky_clusters; i++)
372  {
373  if (wm->sky_clusters[i] == cluster)
374  {
375  return qtrue;
376  }
377  }
378  }
379 
380  return qfalse;
381 }

Referenced by collect_sky_and_lava_ligth_polys(), and collect_surfaces().

◆ left_of()

static int left_of ( point2_t a,
point2_t b,
point2_t c 
)
static

Definition at line 618 of file bsp_mesh.c.

619 {
620  float x;
621  point2_t tmp1 = vsub(b, a);
622  point2_t tmp2 = vsub(c, b);
623  x = cross2(&tmp1, &tmp2);
624  return x < 0 ? -1 : x > 0;
625 }

Referenced by poly_edge_clip(), and poly_winding().

◆ light_affects_cluster()

static qboolean light_affects_cluster ( light_poly_t light,
aabb_t aabb 
)
static

Definition at line 1430 of file bsp_mesh.c.

1431 {
1432  // Empty cluster, nothing is visible
1433  if (aabb->mins[0] > aabb->maxs[0])
1434  return qfalse;
1435 
1436  const float* v0 = light->positions + 0;
1437  const float* v1 = light->positions + 3;
1438  const float* v2 = light->positions + 6;
1439 
1440  // Get the light plane equation
1441  vec3_t e1, e2, normal;
1442  VectorSubtract(v1, v0, e1);
1443  VectorSubtract(v2, v0, e2);
1444  CrossProduct(e1, e2, normal);
1445  VectorNormalize(normal);
1446 
1447  float plane_distance = -DotProduct(normal, v0);
1448 
1449  qboolean all_culled = qtrue;
1450 
1451  // If all 8 corners of the cluster's AABB are behind the light, it's definitely invisible
1452  for (int corner_idx = 0; corner_idx < 8; corner_idx++)
1453  {
1454  vec3_t corner;
1455  get_aabb_corner(aabb, corner_idx, corner);
1456 
1457  float side = DotProduct(normal, corner) + plane_distance;
1458  if (side > 0)
1459  all_culled = qfalse;
1460  }
1461 
1462  if (all_culled)
1463  {
1464  return qfalse;
1465  }
1466 
1467  return qtrue;
1468 }

Referenced by collect_cluster_lights().

◆ line_sect()

static int line_sect ( point2_t x0,
point2_t x1,
point2_t y0,
point2_t y1,
point2_t res 
)
static

Definition at line 628 of file bsp_mesh.c.

629 {
630  point2_t dx, dy, d;
631  dx = vsub(x1, x0);
632  dy = vsub(y1, y0);
633  d = vsub(x0, y0);
634  /* x0 + a dx = y0 + b dy ->
635  x0 X dx = y0 X dx + b dy X dx ->
636  b = (x0 - y0) X dx / (dy X dx) */
637  float dyx = cross2(&dy, &dx);
638  if (!dyx) return 0;
639  dyx = cross2(&d, &dx) / dyx;
640  if (dyx <= 0 || dyx >= 1) return 0;
641 
642  res->x = y0->x + dyx * dy.x;
643  res->y = y0->y + dyx * dy.y;
644  return 1;
645 }

Referenced by poly_edge_clip().

◆ load_cameras()

static void load_cameras ( bsp_mesh_t wm,
const char *  map_name 
)
static

Definition at line 1300 of file bsp_mesh.c.

1301 {
1302  wm->num_cameras = 0;
1303 
1304  char* filebuf = NULL;
1305  FS_LoadFile("cameras.txt", &filebuf);
1306  if (!filebuf)
1307  {
1308  Com_WPrintf("Couldn't read cameras.txt\n");
1309  return;
1310  }
1311 
1312  char const * ptr = (char const *)filebuf;
1313  char linebuf[1024];
1314  qboolean found_map = qfalse;
1315 
1316  while (sgets(linebuf, sizeof(linebuf), &ptr))
1317  {
1318  { char* t = strchr(linebuf, '#'); if (t) *t = 0; } // remove comments
1319  { char* t = strchr(linebuf, '\n'); if (t) *t = 0; } // remove newline
1320 
1321 
1322  vec3_t pos, dir;
1323  if (linebuf[0] >= 'a' && linebuf[0] <= 'z' || linebuf[0] >= 'A' && linebuf[0] <= 'Z')
1324  {
1325  const char* delimiters = " \t\r\n";
1326  const char* word = strtok(linebuf, delimiters);
1327  qboolean matches = strcmp(word, map_name) == 0;
1328 
1329  if (!found_map && matches)
1330  {
1331  found_map = qtrue;
1332  }
1333  else if (found_map && !matches)
1334  {
1335  Z_Free(filebuf);
1336  return;
1337  }
1338  }
1339  else if (found_map && sscanf(linebuf, "(%f, %f, %f) (%f, %f, %f)", &pos[0], &pos[1], &pos[2], &dir[0], &dir[1], &dir[2]) == 6)
1340  {
1341  if (wm->num_cameras < MAX_CAMERAS)
1342  {
1343  VectorCopy(pos, wm->cameras[wm->num_cameras].pos);
1344  VectorCopy(dir, wm->cameras[wm->num_cameras].dir);
1345  wm->num_cameras++;
1346  }
1347  }
1348  }
1349 
1350  Z_Free(filebuf);
1351 }

Referenced by bsp_mesh_create_from_bsp().

◆ load_sky_and_lava_clusters()

static void load_sky_and_lava_clusters ( bsp_mesh_t wm,
const char *  map_name 
)
static

Definition at line 1222 of file bsp_mesh.c.

1223 {
1224  wm->num_sky_clusters = 0;
1225  wm->all_lava_emissive = qfalse;
1226 
1227  // try a map-specific file first
1228  char filename[MAX_QPATH];
1229  Q_snprintf(filename, sizeof(filename), "maps/sky/%s.txt", map_name);
1230 
1231  qboolean found_map = qfalse;
1232 
1233  char* filebuf = NULL;
1234  FS_LoadFile(filename, &filebuf);
1235 
1236  if (filebuf)
1237  {
1238  // we have a map-specific file - no need to look for map name
1239  found_map = qtrue;
1240  }
1241  else
1242  {
1243  // try to load the global file
1244  FS_LoadFile("sky_clusters.txt", &filebuf);
1245  if (!filebuf)
1246  {
1247  Com_WPrintf("Couldn't read sky_clusters.txt\n");
1248  return;
1249  }
1250  }
1251 
1252  char const * ptr = (char const *)filebuf;
1253  char linebuf[1024];
1254 
1255  while (sgets(linebuf, sizeof(linebuf), &ptr))
1256  {
1257  { char* t = strchr(linebuf, '#'); if (t) *t = 0; } // remove comments
1258  { char* t = strchr(linebuf, '\n'); if (t) *t = 0; } // remove newline
1259 
1260  const char* delimiters = " \t\r\n";
1261 
1262  const char* word = strtok(linebuf, delimiters);
1263  while (word)
1264  {
1265  if (word[0] >= 'a' && word[0] <= 'z' || word[0] >= 'A' && word[0] <= 'Z')
1266  {
1267  qboolean matches = strcmp(word, map_name) == 0;
1268 
1269  if (!found_map && matches)
1270  {
1271  found_map = qtrue;
1272  }
1273  else if (found_map && !matches)
1274  {
1275  Z_Free(filebuf);
1276  return;
1277  }
1278  }
1279  else if (found_map)
1280  {
1281  assert(wm->num_sky_clusters < MAX_SKY_CLUSTERS);
1282 
1283  if (!strcmp(word, "!all_lava"))
1284  wm->all_lava_emissive = qtrue;
1285  else
1286  {
1287  int cluster = atoi(word);
1288  wm->sky_clusters[wm->num_sky_clusters++] = cluster;
1289  }
1290  }
1291 
1292  word = strtok(NULL, delimiters);
1293  }
1294  }
1295 
1296  Z_Free(filebuf);
1297 }

Referenced by bsp_mesh_create_from_bsp().

◆ make_pvs_symmetric()

static void make_pvs_symmetric ( bsp_t *  bsp)
static

Definition at line 420 of file bsp_mesh.c.

421 {
422  for (int cluster = 0; cluster < bsp->vis->numclusters; cluster++)
423  {
424  char* pvs = BSP_GetPvs(bsp, cluster);
425 
426  FOREACH_BIT_BEGIN(pvs, bsp->visrowsize, vis_cluster)
427  if (vis_cluster != cluster)
428  {
429  char* vis_pvs = BSP_GetPvs(bsp, vis_cluster);
430  Q_SetBit(vis_pvs, cluster);
431  }
433  }
434 }

Referenced by collect_surfaces().

◆ merge_pvs_rows()

static void merge_pvs_rows ( bsp_t *  bsp,
char *  src,
char *  dst 
)
static

Definition at line 383 of file bsp_mesh.c.

384 {
385  for (int i = 0; i < bsp->visrowsize; i++)
386  {
387  dst[i] |= src[i];
388  }
389 }

Referenced by build_pvs2(), and connect_pvs().

◆ poly_append()

static void poly_append ( poly_t p,
point2_t v 
)
static

Definition at line 648 of file bsp_mesh.c.

649 {
650  assert(p->len < MAX_POLY_VERTS - 1);
651  p->v[p->len++] = *v;
652 }

Referenced by poly_edge_clip().

◆ poly_edge_clip()

static void poly_edge_clip ( poly_t sub,
point2_t x0,
point2_t x1,
int  left,
poly_t res 
)
static

Definition at line 661 of file bsp_mesh.c.

662 {
663  int i, side0, side1;
664  point2_t tmp;
665  point2_t* v0 = sub->v + sub->len - 1;
666  point2_t* v1;
667  res->len = 0;
668 
669  side0 = left_of(x0, x1, v0);
670  if (side0 != -left) poly_append(res, v0);
671 
672  for (i = 0; i < sub->len; i++) {
673  v1 = sub->v + i;
674  side1 = left_of(x0, x1, v1);
675  if (side0 + side1 == 0 && side0)
676  /* last point and current straddle the edge */
677  if (line_sect(x0, x1, v0, v1, &tmp))
678  poly_append(res, &tmp);
679  if (i == sub->len - 1) break;
680  if (side1 != -left) poly_append(res, v1);
681  v0 = v1;
682  side0 = side1;
683  }
684 }

Referenced by clip_polygon().

◆ poly_winding()

static int poly_winding ( poly_t p)
static

Definition at line 655 of file bsp_mesh.c.

656 {
657  return left_of(p->v, p->v + 1, p->v + 2);
658 }

Referenced by clip_polygon().

◆ remove_collinear_edges()

static void remove_collinear_edges ( float *  positions,
float *  tex_coords,
int num_vertices 
)
static

Definition at line 33 of file bsp_mesh.c.

34 {
35  int num_vertices_local = *num_vertices;
36 
37  for (int i = 1; i < num_vertices_local;)
38  {
39  float* p0 = positions + (i - 1) * 3;
40  float* p1 = positions + (i % num_vertices_local) * 3;
41  float* p2 = positions + ((i + 1) % num_vertices_local) * 3;
42 
43  vec3_t e1, e2;
44  VectorSubtract(p1, p0, e1);
45  VectorSubtract(p2, p1, e2);
46  float l1 = VectorLength(e1);
47  float l2 = VectorLength(e2);
48 
49  qboolean remove = qfalse;
50  if (l1 == 0)
51  {
52  remove = qtrue;
53  }
54  else if (l2 > 0)
55  {
56  VectorScale(e1, 1.f / l1, e1);
57  VectorScale(e2, 1.f / l2, e2);
58 
59  float dot = DotProduct(e1, e2);
60  if (dot > 0.999f)
61  remove = qtrue;
62  }
63 
64  if (remove)
65  {
66  if (num_vertices_local - i >= 1)
67  {
68  memcpy(p1, p2, (num_vertices_local - i - 1) * 3 * sizeof(float));
69 
70  if (tex_coords)
71  {
72  float* t1 = tex_coords + (i % num_vertices_local) * 2;
73  float* t2 = tex_coords + ((i + 1) % num_vertices_local) * 2;
74  memcpy(t1, t2, (num_vertices_local - i - 1) * 2 * sizeof(float));
75  }
76  }
77 
78  num_vertices_local--;
79  }
80  else
81  {
82  i++;
83  }
84  }
85 
86  *num_vertices = num_vertices_local;
87 }

Referenced by collect_ligth_polys(), collect_sky_and_lava_ligth_polys(), and create_poly().

◆ vsub()

static point2_t vsub ( point2_t a,
point2_t b 
)
inlinestatic

Definition at line 606 of file bsp_mesh.c.

607 {
608  point2_t res;
609  res.x = a->x - b->x;
610  res.y = a->y - b->y;
611  return res;
612 }

Referenced by left_of(), and line_sect().

Variable Documentation

◆ cvar_pt_enable_nodraw

cvar_t* cvar_pt_enable_nodraw

Definition at line 53 of file main.c.

Referenced by collect_surfaces(), and R_Init_RTX().

MATERIAL_KIND_TRANSPARENT
#define MATERIAL_KIND_TRANSPARENT
Definition: constants.h:68
bsp_mesh_s::num_clusters
int num_clusters
Definition: vkpt.h:366
light_poly_s
Definition: vkpt.h:315
filter_static_sky
static int filter_static_sky(int flags)
Definition: bsp_mesh.c:263
get_surf_light_style
static int get_surf_light_style(const mface_t *surf)
Definition: bsp_mesh.c:317
MATERIAL_LIGHT_STYLE_SHIFT
#define MATERIAL_LIGHT_STYLE_SHIFT
Definition: constants.h:85
BSP_GetPvs2
char * BSP_GetPvs2(bsp_t *bsp, int cluster)
Definition: bsp.c:985
MATERIAL_KIND_LAVA
#define MATERIAL_KIND_LAVA
Definition: constants.h:62
bsp_mesh_s::sky_visibility
char sky_visibility[VIS_MAX_BYTES]
Definition: vkpt.h:384
Q_snprintf
size_t Q_snprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:846
bsp_mesh_s::cluster_aabbs
aabb_t * cluster_aabbs
Definition: vkpt.h:386
pbr_material_s::next_frame
int next_frame
Definition: material.h:45
image_t
struct image_s image_t
Definition: material.h:27
bsp_mesh_s::clusters
int * clusters
Definition: vkpt.h:367
append_light_poly
static light_poly_t * append_light_poly(int *num_lights, int *allocated, light_poly_t **lights)
Definition: bsp_mesh.c:712
is_light_material
static qboolean is_light_material(uint32_t material)
Definition: bsp_mesh.c:723
compute_cluster_aabbs
static void compute_cluster_aabbs(bsp_mesh_t *wm)
Definition: bsp_mesh.c:1388
input
static in_state_t input
Definition: input.c:71
bsp_mesh_s::texel_density
float * texel_density
Definition: vkpt.h:362
point2_t::x
float x
Definition: bsp_mesh.c:584
MAX_SKY_CLUSTERS
#define MAX_SKY_CLUSTERS
Definition: vkpt.h:313
bsp_model_s::light_polys
light_poly_t * light_polys
Definition: vkpt.h:333
bsp_mesh_s::all_lava_emissive
qboolean all_lava_emissive
Definition: vkpt.h:379
MATERIAL_FLAG_WARP
#define MATERIAL_FLAG_WARP
Definition: constants.h:77
surf_s::flags
int flags
Definition: sw.h:252
collect_ligth_polys
static void collect_ligth_polys(bsp_mesh_t *wm, bsp_t *bsp, int model_idx, int *num_lights, int *allocated_lights, light_poly_t **lights)
Definition: bsp_mesh.c:729
clip_polygon
static void clip_polygon(poly_t *input, poly_t *clipper, poly_t *output)
Definition: bsp_mesh.c:687
MATERIAL_FLAG_FLOWING
#define MATERIAL_FLAG_FLOWING
Definition: constants.h:78
light_poly_s::color
vec3_t color
Definition: vkpt.h:318
pbr_material_s::flags
uint32_t flags
Definition: material.h:42
collect_surfaces
static void collect_surfaces(int *idx_ctr, bsp_mesh_t *wm, bsp_t *bsp, int model_idx, int(*filter)(int))
Definition: bsp_mesh.c:457
light_poly_s::material
struct pbr_material_s * material
Definition: vkpt.h:319
MATERIAL_FLAG_HANDEDNESS
#define MATERIAL_FLAG_HANDEDNESS
Definition: constants.h:75
compute_sky_visibility
static void compute_sky_visibility(bsp_mesh_t *wm, bsp_t *bsp)
Definition: bsp_mesh.c:1354
bsp_mesh_s::tex_coords
float * tex_coords
Definition: vkpt.h:359
bsp_mesh_load_custom_sky
static qboolean bsp_mesh_load_custom_sky(int *idx_ctr, bsp_mesh_t *wm, bsp_t *bsp, const char *map_name)
Definition: bsp_mesh.c:1538
MAT_GetPBRMaterial
pbr_material_t * MAT_GetPBRMaterial(int index)
Definition: material.c:457
light_affects_cluster
static qboolean light_affects_cluster(light_poly_t *light, aabb_t *aabb)
Definition: bsp_mesh.c:1430
point2_t
Definition: bsp_mesh.c:583
MATERIAL_KIND_SKY
#define MATERIAL_KIND_SKY
Definition: constants.h:65
bsp_mesh_s::num_models
int num_models
Definition: vkpt.h:346
filter_all
static int filter_all(int flags)
Definition: bsp_mesh.c:271
bsp_mesh_s::num_cluster_lights
int num_cluster_lights
Definition: vkpt.h:369
MATERIAL_FLAG_LIGHT
#define MATERIAL_FLAG_LIGHT
Definition: constants.h:73
load_sky_and_lava_clusters
static void load_sky_and_lava_clusters(bsp_mesh_t *wm, const char *map_name)
Definition: bsp_mesh.c:1222
bsp_mesh_s::pos
vec3_t pos
Definition: vkpt.h:381
bsp_mesh_s::allocated_light_polys
int allocated_light_polys
Definition: vkpt.h:374
bsp_mesh_s::dir
vec3_t dir
Definition: vkpt.h:381
BSP_SavePatchedPVS
qboolean BSP_SavePatchedPVS(bsp_t *bsp)
Definition: bsp.c:1051
bsp_mesh_s::tangents
float * tangents
Definition: vkpt.h:359
poly_t::len
int len
Definition: bsp_mesh.c:590
connect_pvs
static void connect_pvs(bsp_t *bsp, int cluster_a, char *pvs_a, int cluster_b, char *pvs_b)
Definition: bsp_mesh.c:400
make_pvs_symmetric
static void make_pvs_symmetric(bsp_t *bsp)
Definition: bsp_mesh.c:420
aabb_s::mins
vec3_t mins
Definition: vkpt.h:339
bsp_mesh_s::num_indices
int num_indices
Definition: vkpt.h:363
build_pvs2
static void build_pvs2(bsp_t *bsp)
Definition: bsp_mesh.c:436
bsp_model_s::center
vec3_t center
Definition: vkpt.h:327
BSP_PointLeaf
mleaf_t * BSP_PointLeaf(mnode_t *node, vec3_t p)
Definition: bsp.c:1439
MAT_RegisterPBRMaterial
qerror_t MAT_RegisterPBRMaterial(pbr_material_t *mat, image_t *image_diffuse, image_t *image_normals, image_t *image_emissive)
Definition: material.c:397
bsp_mesh_s::num_vertices
int num_vertices
Definition: vkpt.h:364
bsp_model_s::aabb_min
vec3_t aabb_min
Definition: vkpt.h:328
floatBitsToUint
uint32_t floatBitsToUint(float f)
Definition: bsp_mesh.c:1080
compute_world_tangents
void compute_world_tangents(bsp_mesh_t *wm)
Definition: bsp_mesh.c:1131
belongs_to_model
static int belongs_to_model(bsp_t *bsp, mface_t *surf)
Definition: bsp_mesh.c:235
cluster_light_counts
static int cluster_light_counts[MAX_MAP_LEAFS]
Definition: vertex_buffer.c:126
vkpt_normalize_normal_map
void vkpt_normalize_normal_map(image_t *image)
Definition: textures.c:592
left_of
static int left_of(point2_t *a, point2_t *b, point2_t *c)
Definition: bsp_mesh.c:618
bsp_model_s::idx_count
uint32_t idx_count
Definition: vkpt.h:326
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
bsp_mesh_s::sky_clusters
uint32_t sky_clusters[MAX_SKY_CLUSTERS]
Definition: vkpt.h:377
collect_cluster_lights
static void collect_cluster_lights(bsp_mesh_t *wm, bsp_t *bsp)
Definition: bsp_mesh.c:1471
bsp_mesh_s::cluster_lights
int * cluster_lights
Definition: vkpt.h:371
pbr_material_s::emissive_scale
float emissive_scale
Definition: material.h:41
bsp_mesh_s::cluster_light_offsets
int * cluster_light_offsets
Definition: vkpt.h:370
point2_t::y
float y
Definition: bsp_mesh.c:584
CP_M
#define CP_M(idx)
pbr_material_s::num_frames
int num_frames
Definition: material.h:44
get_aabb_corner
static void get_aabb_corner(aabb_t *aabb, int corner_idx, vec3_t corner)
Definition: bsp_mesh.c:1422
pbr_material_s
Definition: material.h:33
vsub
static point2_t vsub(point2_t *a, point2_t *b)
Definition: bsp_mesh.c:606
get_triangle_off_center
qboolean get_triangle_off_center(const float *positions, float *center, float *anti_center)
Definition: bsp_mesh.c:282
filter_static_opaque
static int filter_static_opaque(int flags)
Definition: bsp_mesh.c:245
MAX_VERT_BSP
#define MAX_VERT_BSP
Definition: vertex_buffer.h:23
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
MATERIAL_KIND_REGULAR
#define MATERIAL_KIND_REGULAR
Definition: constants.h:59
create_poly
static int create_poly(const mface_t *surf, uint32_t material_id, float *positions_out, float *tex_coord_out, uint32_t *material_out)
Definition: bsp_mesh.c:96
bsp_model_s::allocated_light_polys
int allocated_light_polys
Definition: vkpt.h:332
vkpt_extract_emissive_texture_info
void vkpt_extract_emissive_texture_info(image_t *image)
Definition: textures.c:532
bsp_mesh_s::materials
uint32_t * materials
Definition: vkpt.h:361
bsp_mesh_s::models
bsp_model_t * models
Definition: vkpt.h:345
MATERIAL_KIND_MASK
#define MATERIAL_KIND_MASK
Definition: constants.h:57
poly_t
Definition: bsp_mesh.c:588
MAX_LIGHT_LISTS
#define MAX_LIGHT_LISTS
Definition: vertex_buffer.h:32
MAX_POLY_VERTS
#define MAX_POLY_VERTS
Definition: bsp_mesh.c:587
light_poly_s::style
int style
Definition: vkpt.h:321
bsp_model_s
Definition: vkpt.h:324
pbr_material_s::image_diffuse
image_t * image_diffuse
Definition: material.h:35
MAT_IsKind
qboolean MAT_IsKind(uint32_t material, uint32_t kind)
Definition: material.c:665
bsp_mesh_s::world_sky_count
uint32_t world_sky_count
Definition: vkpt.h:354
MAX_CAMERAS
#define MAX_CAMERAS
Definition: constants.h:48
VectorNormalize2
vec_t VectorNormalize2(vec3_t v, vec3_t out)
Definition: shared.c:73
FOREACH_BIT_BEGIN
#define FOREACH_BIT_BEGIN(SET, ROWSIZE, VAR)
Definition: bsp_mesh.c:391
FOREACH_BIT_END
#define FOREACH_BIT_END
Definition: bsp_mesh.c:398
MATERIAL_LIGHT_STYLE_MASK
#define MATERIAL_LIGHT_STYLE_MASK
Definition: constants.h:84
light_poly_s::off_center
vec3_t off_center
Definition: vkpt.h:317
IMG_Find
image_t * IMG_Find(const char *name, imagetype_t type, imageflags_t flags)
Definition: images.c:1122
cvar_pt_enable_nodraw
cvar_t * cvar_pt_enable_nodraw
Definition: main.c:53
filter_static_transparent
static int filter_static_transparent(int flags)
Definition: bsp_mesh.c:254
is_sky
bool is_sky(RayPayload rp)
Definition: path_tracer_rgen.h:140
bsp_mesh_s::world_transparent_count
uint32_t world_transparent_count
Definition: vkpt.h:351
bsp_model_s::aabb_max
vec3_t aabb_max
Definition: vkpt.h:329
bsp_mesh_s::indices
int * indices
Definition: vkpt.h:360
c
statCounters_t c
Definition: main.c:30
MATERIAL_KIND_CAMERA
#define MATERIAL_KIND_CAMERA
Definition: constants.h:70
CP_T
#define CP_T(idx, src)
is_sky_or_lava_cluster
static qboolean is_sky_or_lava_cluster(bsp_mesh_t *wm, mface_t *surf, int cluster, int material_id)
Definition: bsp_mesh.c:355
surfaces
surf_t * surfaces
Definition: edge.c:35
bsp_mesh_s::num_sky_clusters
int num_sky_clusters
Definition: vkpt.h:378
MATERIAL_KIND_SLIME
#define MATERIAL_KIND_SLIME
Definition: constants.h:63
bsp_mesh_s::light_polys
light_poly_t * light_polys
Definition: vkpt.h:375
sgets
char * sgets(char *str, int num, char const **input)
Definition: vk_util.c:26
bsp_model_s::num_light_polys
int num_light_polys
Definition: vkpt.h:331
poly_winding
static int poly_winding(poly_t *p)
Definition: bsp_mesh.c:655
merge_pvs_rows
static void merge_pvs_rows(bsp_t *bsp, char *src, char *dst)
Definition: bsp_mesh.c:383
compute_aabb
void compute_aabb(const float *positions, int numvert, float *aabb_min, float *aabb_max)
Definition: bsp_mesh.c:1111
poly_t::v
point2_t v[MAX_POLY_VERTS]
Definition: bsp_mesh.c:589
bsp_mesh_s::world_custom_sky_offset
uint32_t world_custom_sky_offset
Definition: vkpt.h:356
bsp_mesh_s::num_light_polys
int num_light_polys
Definition: vkpt.h:373
get_surf_plane_equation
static qboolean get_surf_plane_equation(mface_t *surf, float *plane)
Definition: bsp_mesh.c:331
bsp_mesh_s::positions
float * positions
Definition: vkpt.h:359
cross2
static float cross2(point2_t *a, point2_t *b)
Definition: bsp_mesh.c:600
CP_V
#define CP_V(idx, src)
line_sect
static int line_sect(point2_t *x0, point2_t *x1, point2_t *y0, point2_t *y1, point2_t *res)
Definition: bsp_mesh.c:628
poly_append
static void poly_append(poly_t *p, point2_t *v)
Definition: bsp_mesh.c:648
remove_collinear_edges
static void remove_collinear_edges(float *positions, float *tex_coords, int *num_vertices)
Definition: bsp_mesh.c:33
aabb_s
Definition: vkpt.h:338
MATERIAL_KIND_SCREEN
#define MATERIAL_KIND_SCREEN
Definition: constants.h:69
bsp_mesh_s::world_idx_count
uint32_t world_idx_count
Definition: vkpt.h:344
collect_sky_and_lava_ligth_polys
static void collect_sky_and_lava_ligth_polys(bsp_mesh_t *wm, bsp_t *bsp)
Definition: bsp_mesh.c:988
bsp_mesh_s::world_sky_offset
uint32_t world_sky_offset
Definition: vkpt.h:353
bsp_mesh_s::world_aabb
aabb_t world_aabb
Definition: vkpt.h:348
Q_concat
size_t Q_concat(char *dest, size_t size,...)
Definition: shared.c:758
bsp_mesh_s::world_transparent_offset
uint32_t world_transparent_offset
Definition: vkpt.h:350
poly_edge_clip
static void poly_edge_clip(poly_t *sub, point2_t *x0, point2_t *x1, int left, poly_t *res)
Definition: bsp_mesh.c:661
aabb_s::maxs
vec3_t maxs
Definition: vkpt.h:340
BSP_GetPvs
char * BSP_GetPvs(bsp_t *bsp, int cluster)
Definition: bsp.c:974
MATERIAL_INDEX_MASK
#define MATERIAL_INDEX_MASK
Definition: constants.h:86
MATERIAL_KIND_WATER
#define MATERIAL_KIND_WATER
Definition: constants.h:61
load_cameras
static void load_cameras(bsp_mesh_t *wm, const char *map_name)
Definition: bsp_mesh.c:1300
MAX_LIGHTS_PER_CLUSTER
#define MAX_LIGHTS_PER_CLUSTER
Z_Realloc
void * Z_Realloc(void *ptr, size_t size)
Definition: zone.c:178
bsp_model_s::idx_offset
uint32_t idx_offset
Definition: vkpt.h:325
light_poly_s::cluster
int cluster
Definition: vkpt.h:320
VectorNormalize
vec_t VectorNormalize(vec3_t v)
Definition: shared.c:55
MAT_SetKind
uint32_t MAT_SetKind(uint32_t material, uint32_t kind)
Definition: material.c:660
is_lava
bool is_lava(uint material)
Definition: path_tracer_rgen.h:200
FS_NormalizePath
size_t FS_NormalizePath(char *out, const char *in)
Definition: files.c:331
MAT_FindPBRMaterial
pbr_material_t * MAT_FindPBRMaterial(char const *name)
Definition: material.c:465
MATERIAL_KIND_GLASS
#define MATERIAL_KIND_GLASS
Definition: constants.h:64
bsp_mesh_s::world_custom_sky_count
uint32_t world_custom_sky_count
Definition: vkpt.h:357
light_poly_s::positions
float positions[9]
Definition: vkpt.h:316
bsp_mesh_s::cameras
struct bsp_mesh_s::@19 cameras[MAX_CAMERAS]
is_model_transparent
static qboolean is_model_transparent(bsp_mesh_t *wm, bsp_model_t *model)
Definition: bsp_mesh.c:1062
bsp_model_s::transparent
qboolean transparent
Definition: vkpt.h:335
bsp_mesh_s::num_cameras
int num_cameras
Definition: vkpt.h:382