214 lines
7.0 KiB
C++
214 lines
7.0 KiB
C++
/* Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
See file, 'COPYING', for details.
|
|
*/
|
|
|
|
#include <cfloat>
|
|
|
|
#include <vis/vis.hh>
|
|
#include <common/bsputils.hh>
|
|
|
|
/*
|
|
|
|
Some textures (sky, water, slime, lava) are considered ambien sound emiters.
|
|
Find an aproximate distance to the nearest emiter of each class for each leaf.
|
|
|
|
*/
|
|
|
|
/*
|
|
====================
|
|
SurfaceBBox
|
|
====================
|
|
*/
|
|
static aabb3d SurfaceBBox(const mbsp_t *bsp, const mface_t *surf)
|
|
{
|
|
aabb3d bounds;
|
|
|
|
for (int32_t i = 0; i < surf->numedges; i++) {
|
|
int32_t edgenum = bsp->dsurfedges[surf->firstedge + i], vertnum;
|
|
|
|
if (edgenum >= 0)
|
|
vertnum = bsp->dedges[edgenum][0];
|
|
else
|
|
vertnum = bsp->dedges[-edgenum][1];
|
|
|
|
bounds += bsp->dvertexes[vertnum];
|
|
}
|
|
|
|
return bounds;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CalcAmbientSounds
|
|
====================
|
|
*/
|
|
void CalcAmbientSounds(mbsp_t *bsp)
|
|
{
|
|
const mface_t *surf;
|
|
const mtexinfo_t *info;
|
|
int i, j, k, l;
|
|
mleaf_t *leaf, *hit;
|
|
uint8_t *vis;
|
|
float d, maxd;
|
|
ambient_type_t ambient_type;
|
|
float dists[NUM_AMBIENTS];
|
|
float vol;
|
|
|
|
for (i = 0; i < portalleafs_real; i++) {
|
|
leaf = &bsp->dleafs[i + 1];
|
|
|
|
//
|
|
// clear ambients
|
|
//
|
|
for (j = 0; j < NUM_AMBIENTS; j++)
|
|
dists[j] = 1020;
|
|
|
|
if (portalleafs != portalleafs_real) {
|
|
vis = &uncompressed[leaf->cluster * leafbytes_real];
|
|
} else {
|
|
vis = &uncompressed[i * leafbytes_real];
|
|
}
|
|
|
|
for (j = 0; j < portalleafs_real; j++) {
|
|
if (!(vis[j >> 3] & nth_bit(j & 7)))
|
|
continue;
|
|
|
|
//
|
|
// check this leaf for sound textures
|
|
//
|
|
hit = &bsp->dleafs[j + 1];
|
|
|
|
for (k = 0; k < hit->nummarksurfaces; k++) {
|
|
surf = BSP_GetFace(bsp, bsp->dleaffaces[hit->firstmarksurface + k]);
|
|
info = &bsp->texinfo[surf->texinfo];
|
|
const auto &miptex = bsp->dtex.textures[info->miptex];
|
|
|
|
if (!Q_strncasecmp(miptex.name.data(), "sky", 3) && !vis_options.noambientsky.value())
|
|
ambient_type = AMBIENT_SKY;
|
|
else if (!Q_strncasecmp(miptex.name.data(), "*water", 6) && !vis_options.noambientwater.value())
|
|
ambient_type = AMBIENT_WATER;
|
|
else if (!Q_strncasecmp(miptex.name.data(), "*04water", 8) && !vis_options.noambientwater.value())
|
|
ambient_type = AMBIENT_WATER;
|
|
else if (!Q_strncasecmp(miptex.name.data(), "*slime", 6) && !vis_options.noambientslime.value())
|
|
ambient_type = AMBIENT_WATER; // AMBIENT_SLIME;
|
|
else if (!Q_strncasecmp(miptex.name.data(), "*lava", 5) && !vis_options.noambientlava.value())
|
|
ambient_type = AMBIENT_LAVA;
|
|
else
|
|
continue;
|
|
|
|
// find distance from source leaf to polygon
|
|
aabb3d bounds = SurfaceBBox(bsp, surf);
|
|
maxd = 0;
|
|
for (l = 0; l < 3; l++) {
|
|
if (bounds.mins()[l] > leaf->maxs[l])
|
|
d = bounds.mins()[l] - leaf->maxs[l];
|
|
else if (bounds.maxs()[l] < leaf->mins[l])
|
|
d = leaf->mins[l] - bounds.mins()[l];
|
|
else
|
|
d = 0;
|
|
if (d > maxd)
|
|
maxd = d;
|
|
}
|
|
|
|
maxd = 0.25;
|
|
if (maxd < dists[ambient_type])
|
|
dists[ambient_type] = maxd;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < NUM_AMBIENTS; j++) {
|
|
if (dists[j] < 100)
|
|
vol = 1.0;
|
|
else {
|
|
vol = (vec_t)(1.0 - dists[2] * 0.002);
|
|
if (vol < 0)
|
|
vol = 0;
|
|
}
|
|
leaf->ambient_level[j] = (uint8_t)(vol * 255);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
CalcPHS
|
|
|
|
Calculate the PHS (Potentially Hearable Set)
|
|
by ORing together all the PVS visible from a leaf
|
|
================
|
|
*/
|
|
void CalcPHS(mbsp_t *bsp)
|
|
{
|
|
const int32_t leafbytes = (portalleafs + 7) >> 3;
|
|
const int32_t leaflongs = leafbytes / sizeof(long);
|
|
|
|
// increase the bits size with approximately how much space we'll need
|
|
bsp->dvis.bits.reserve(bsp->dvis.bits.size() * 2);
|
|
|
|
std::vector<uint8_t> uncompressed(leafbytes);
|
|
std::vector<uint8_t> uncompressed_2(leafbytes);
|
|
std::vector<uint8_t> compressed(leafbytes * 2);
|
|
std::vector<uint8_t> uncompressed_orig(leafbytes);
|
|
|
|
int32_t count = 0;
|
|
for (int32_t i = 0; i < portalleafs; i++) {
|
|
const uint8_t *scan = bsp->dvis.bits.data() + bsp->dvis.get_bit_offset(VIS_PVS, i);
|
|
|
|
DecompressRow(scan, leafbytes, uncompressed.data());
|
|
std::copy(uncompressed.begin(), uncompressed.end(), uncompressed_orig.begin());
|
|
|
|
scan = uncompressed_orig.data();
|
|
|
|
for (int32_t j = 0; j < leafbytes; j++) {
|
|
uint8_t bitbyte = scan[j];
|
|
if (!bitbyte)
|
|
continue;
|
|
for (int32_t k = 0; k < 8; k++) {
|
|
if (!(bitbyte & nth_bit(k)))
|
|
continue;
|
|
// OR this pvs row into the phs
|
|
int32_t index = ((j << 3) + k);
|
|
if (index >= portalleafs)
|
|
FError("Bad bit in PVS"); // pad bits should be 0
|
|
const uint8_t *src_compressed = bsp->dvis.bits.data() + bsp->dvis.get_bit_offset(VIS_PVS, index);
|
|
DecompressRow(src_compressed, leafbytes, uncompressed_2.data());
|
|
const long *src = reinterpret_cast<long *>(uncompressed_2.data());
|
|
long *dest = reinterpret_cast<long *>(uncompressed.data());
|
|
for (int32_t l = 0; l < leaflongs; l++)
|
|
dest[l] |= src[l];
|
|
}
|
|
}
|
|
for (int32_t j = 0; j < portalleafs; j++)
|
|
if (uncompressed[j >> 3] & nth_bit(j & 7))
|
|
count++;
|
|
|
|
//
|
|
// compress the bit string
|
|
//
|
|
compressed.clear();
|
|
CompressRow(uncompressed.data(), leafbytes, std::back_inserter(compressed));
|
|
|
|
bsp->dvis.set_bit_offset(VIS_PHS, i, bsp->dvis.bits.size());
|
|
|
|
std::copy(compressed.begin(), compressed.end(), std::back_inserter(bsp->dvis.bits));
|
|
}
|
|
|
|
fmt::print("Average clusters hearable: {}\n", count / portalleafs);
|
|
|
|
bsp->dvis.bits.shrink_to_fit();
|
|
} |