vhlt/hlrad/vismatrix.cpp
2016-09-21 00:07:53 +03:00

664 lines
19 KiB
C++

#include "qrad.h"
////////////////////////////
// begin old vismat.c
//
#define HALFBIT
// =====================================================================================
//
// VISIBILITY MATRIX
// Determine which patches can see each other
// Use the PVS to accelerate if available
//
// =====================================================================================
static byte* s_vismatrix;
#ifndef HLRAD_TRANSPARENCY_CPP
#ifdef HLRAD_HULLU
// =====================================================================================
// OPACITY ARRAY
// =====================================================================================
typedef struct {
unsigned bitpos;
vec3_t transparency;
} transparency_t;
static transparency_t *s_transparency_list = NULL;
static unsigned long s_transparency_count = 0;
static unsigned long s_max_transparency_count=0;
static void FindOpacity(const unsigned bitpos, vec3_t &out)
{
for(unsigned long i = 0; i < s_transparency_count; i++)
{
if( s_transparency_list[i].bitpos == bitpos )
{
VectorCopy(s_transparency_list[i].transparency, out);
return;
}
}
VectorFill(out, 1.0);
}
#endif /*HLRAD_HULLU*/
#endif
// =====================================================================================
// TestPatchToFace
// Sets vis bits for all patches in the face
// =====================================================================================
static void TestPatchToFace(const unsigned patchnum, const int facenum, const int head, const unsigned int bitpos
#ifdef HLRAD_ENTITYBOUNCE_FIX
, byte *pvs
#endif
)
{
patch_t* patch = &g_patches[patchnum];
patch_t* patch2 = g_face_patches[facenum];
// if emitter is behind that face plane, skip all patches
if (patch2)
{
const dplane_t* plane2 = getPlaneFromFaceNumber(facenum);
#ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN
if (DotProduct (patch->origin, plane2->normal) > PatchPlaneDist (patch2) + ON_EPSILON - patch->emitter_range)
#else
if (DotProduct(patch->origin, plane2->normal) > (PatchPlaneDist(patch2) + MINIMUM_PATCH_DISTANCE))
#endif
{
// we need to do a real test
const dplane_t* plane = getPlaneFromFaceNumber(patch->faceNumber);
for (; patch2; patch2 = patch2->next)
{
unsigned m = patch2 - g_patches;
#ifdef HLRAD_HULLU
vec3_t transparency = {1.0, 1.0, 1.0};
#endif
#ifdef HLRAD_OPAQUE_STYLE
int opaquestyle = -1;
#endif
// check vis between patch and patch2
// if bit has not already been set
// && v2 is not behind light plane
// && v2 is visible from v1
if (m > patchnum)
{
#ifdef HLRAD_ENTITYBOUNCE_FIX
if (patch2->leafnum == 0 || !(pvs[(patch2->leafnum - 1) >> 3] & (1 << ((patch2->leafnum - 1) & 7))))
{
continue;
}
#endif
#ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN
vec3_t origin1, origin2;
vec3_t delta;
vec_t dist;
VectorSubtract (patch->origin, patch2->origin, delta);
dist = VectorLength (delta);
if (dist < patch2->emitter_range - ON_EPSILON)
{
GetAlternateOrigin (patch->origin, plane->normal, patch2, origin2);
}
else
{
VectorCopy (patch2->origin, origin2);
}
if (DotProduct (origin2, plane->normal) <= PatchPlaneDist (patch) + MINIMUM_PATCH_DISTANCE)
{
continue;
}
if (dist < patch->emitter_range - ON_EPSILON)
{
GetAlternateOrigin (patch2->origin, plane2->normal, patch, origin1);
}
else
{
VectorCopy (patch->origin, origin1);
}
if (DotProduct (origin1, plane2->normal) <= PatchPlaneDist (patch2) + MINIMUM_PATCH_DISTANCE)
{
continue;
}
#else
if (DotProduct(patch2->origin, plane->normal) <= (PatchPlaneDist(patch) + MINIMUM_PATCH_DISTANCE))
{
continue;
}
#endif
#ifdef HLRAD_WATERBLOCKLIGHT
if (TestLine(
#ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN
origin1, origin2
#else
patch->origin, patch2->origin
#endif
) != CONTENTS_EMPTY)
#else
if (TestLine_r(head,
#ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN
origin1, origin2
#else
patch->origin, patch2->origin
#endif
) != CONTENTS_EMPTY)
#endif
{
continue;
}
if (TestSegmentAgainstOpaqueList(
#ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN
origin1, origin2
#else
patch->origin, patch2->origin
#endif
#ifdef HLRAD_HULLU
, transparency
#endif
#ifdef HLRAD_OPAQUE_STYLE
, opaquestyle
#endif
))
{
continue;
}
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
if (opaquestyle != -1)
{
AddStyleToStyleArray (m, patchnum, opaquestyle);
AddStyleToStyleArray (patchnum, m, opaquestyle);
}
#endif
//Log("SDF::3\n");
// patchnum can see patch m
unsigned bitset = bitpos + m;
#ifdef HLRAD_HULLU
#ifdef HLRAD_TRANSPARENCY_CPP
if(g_customshadow_with_bouncelight && !VectorCompare(transparency, vec3_one))
// zhlt3.4: if(g_customshadow_with_bouncelight && VectorCompare(transparency, vec3_one)) . --vluzacn
{
AddTransparencyToRawArray(patchnum, m, transparency);
}
#else
// transparency face fix table
// TODO: this method makes MakeScale extreamly slow.. find new one
if(g_customshadow_with_bouncelight && fabs(VectorAvg(transparency) - 1.0) < 0.001)
//wrong? (and in sparse) --vluzacn
{
while(s_transparency_count >= s_max_transparency_count)
{
//new size
unsigned long old_max = s_max_transparency_count;
s_max_transparency_count += 128;
//realloc
s_transparency_list = (transparency_t*)realloc(s_transparency_list, s_max_transparency_count * sizeof(transparency_t));
// clean new memory
memset(&s_transparency_list[old_max], 0, sizeof(transparency_t) * 128);
}
//add to array
VectorCopy(transparency, s_transparency_list[s_transparency_count].transparency);
s_transparency_list[s_transparency_count].bitpos = bitset;
s_transparency_count++;
}
#endif
#endif /*HLRAD_HULLU*/
ThreadLock (); //--vluzacn
s_vismatrix[bitset >> 3] |= 1 << (bitset & 7);
ThreadUnlock (); //--vluzacn
}
}
}
}
}
#ifndef HLRAD_VISMATRIX_NOMARKSURFACES
// =====================================================================================
// BuildVisRow
// Calc vis bits from a single patch
// =====================================================================================
static void BuildVisRow(const int patchnum, byte* pvs, const int head, const unsigned int bitpos)
{
int j, k, l;
byte face_tested[MAX_MAP_FACES];
dleaf_t* leaf;
memset(face_tested, 0, g_numfaces);
// leaf 0 is the solid leaf (skipped)
#ifdef HLRAD_VIS_FIX
for (j = 1, leaf = g_dleafs + 1; j < 1 + g_dmodels[0].visleafs; j++, leaf++)
#else
for (j = 1, leaf = g_dleafs + 1; j < g_numleafs; j++, leaf++)
#endif
{
if (!(pvs[(j - 1) >> 3] & (1 << ((j - 1) & 7))))
continue; // not in pvs
for (k = 0; k < leaf->nummarksurfaces; k++)
{
l = g_dmarksurfaces[leaf->firstmarksurface + k];
// faces can be marksurfed by multiple leaves, but
// don't bother testing again
if (face_tested[l])
continue;
face_tested[l] = 1;
TestPatchToFace(patchnum, l, head, bitpos
#ifdef HLRAD_ENTITYBOUNCE_FIX
, pvs
#endif
);
}
}
}
#endif
// =====================================================================================
// BuildVisLeafs
// This is run by multiple threads
// =====================================================================================
#ifdef SYSTEM_WIN32
#pragma warning(push)
#pragma warning(disable: 4100) // unreferenced formal parameter
#endif
static void BuildVisLeafs(int threadnum)
{
int i;
int lface, facenum, facenum2;
byte pvs[(MAX_MAP_LEAFS + 7) / 8];
dleaf_t* srcleaf;
dleaf_t* leaf;
patch_t* patch;
int head;
unsigned bitpos;
unsigned patchnum;
while (1)
{
//
// build a minimal BSP tree that only
// covers areas relevent to the PVS
//
i = GetThreadWork();
if (i == -1)
break;
i++; // skip leaf 0
srcleaf = &g_dleafs[i];
#ifdef HLRAD_WITHOUTVIS
if (!g_visdatasize)
{
#ifdef ZHLT_DecompressVis_FIX
memset (pvs, 255, (g_dmodels[0].visleafs + 7) / 8);
#else
memset(pvs, 255, (g_numleafs + 7) / 8);
#endif
}
else
{
#endif
#ifdef HLRAD_VIS_FIX
if (srcleaf->visofs == -1)
{
Developer (DEVELOPER_LEVEL_ERROR, "Error: No visdata for leaf %d\n", i);
continue;
}
#endif
DecompressVis(&g_dvisdata[srcleaf->visofs], pvs, sizeof(pvs));
#ifdef HLRAD_WITHOUTVIS
}
#endif
head = 0;
//
// go through all the faces inside the
// leaf, and process the patches that
// actually have origins inside
//
#ifdef HLRAD_VISMATRIX_NOMARKSURFACES
for (facenum = 0; facenum < g_numfaces; facenum++)
{
for (patch = g_face_patches[facenum]; patch; patch = patch->next)
{
if (patch->leafnum != i)
continue;
patchnum = patch - g_patches;
#ifdef HALFBIT
bitpos = patchnum * g_num_patches - (patchnum * (patchnum + 1)) / 2;
#else
bitpos = patchnum * g_num_patches;
#endif
for (facenum2 = facenum + 1; facenum2 < g_numfaces; facenum2++)
TestPatchToFace (patchnum, facenum2, head, bitpos, pvs);
}
}
#else
for (lface = 0; lface < srcleaf->nummarksurfaces; lface++)
{
facenum = g_dmarksurfaces[srcleaf->firstmarksurface + lface];
for (patch = g_face_patches[facenum]; patch; patch = patch->next)
{
#ifdef HLRAD_ENTITYBOUNCE_FIX
if (patch->leafnum != i)
continue;
#else
leaf = PointInLeaf(patch->origin);
if (leaf != srcleaf)
continue;
#endif
patchnum = patch - g_patches;
#ifdef HALFBIT
bitpos = patchnum * g_num_patches - (patchnum * (patchnum + 1)) / 2;
#else
bitpos = patchnum * g_num_patches;
#endif
// build to all other world leafs
BuildVisRow(patchnum, pvs, head, bitpos);
// build to bmodel faces
if (g_nummodels < 2)
continue;
for (facenum2 = g_dmodels[1].firstface; facenum2 < g_numfaces; facenum2++)
TestPatchToFace(patchnum, facenum2, head, bitpos
#ifdef HLRAD_ENTITYBOUNCE_FIX
, pvs
#endif
);
}
}
#ifdef HLRAD_ENTITYBOUNCE_FIX
if (g_nummodels >= 2)
{
for (facenum = g_dmodels[1].firstface; facenum < g_numfaces; facenum++)
{
for (patch = g_face_patches[facenum]; patch; patch = patch->next)
{
if (patch->leafnum != i)
continue;
patchnum = patch - g_patches;
#ifdef HALFBIT
bitpos = patchnum * g_num_patches - (patchnum * (patchnum + 1)) / 2;
#else
bitpos = patchnum * g_num_patches;
#endif
// skip BuildVisRow here because entity patchnums are always bigger than world patchnums.
for (facenum2 = g_dmodels[1].firstface; facenum2 < g_numfaces; facenum2++)
TestPatchToFace (patchnum, facenum2, head, bitpos, pvs);
}
}
}
#endif
#endif
}
}
#ifdef SYSTEM_WIN32
#pragma warning(pop)
#endif
// =====================================================================================
// BuildVisMatrix
// =====================================================================================
static void BuildVisMatrix()
{
int c;
#ifdef HALFBIT
c = ((g_num_patches + 1) * (g_num_patches + 1)) / 16;
c += 1; //--vluzacn
#else
c = g_num_patches * ((g_num_patches + 7) / 8);
#endif
Log("%-20s: %5.1f megs\n", "visibility matrix", c / (1024 * 1024.0));
s_vismatrix = (byte*)AllocBlock(c);
if (!s_vismatrix)
{
Log("Failed to allocate s_vismatrix");
hlassume(s_vismatrix != NULL, assume_NoMemory);
}
#ifdef HLRAD_VIS_FIX
NamedRunThreadsOn(g_dmodels[0].visleafs, g_estimate, BuildVisLeafs);
#else
NamedRunThreadsOn(g_numleafs - 1, g_estimate, BuildVisLeafs);
#endif
}
static void FreeVisMatrix()
{
if (s_vismatrix)
{
if (FreeBlock(s_vismatrix))
{
s_vismatrix = NULL;
}
else
{
Warning("Unable to free s_vismatrix");
}
}
#ifndef HLRAD_TRANSPARENCY_CPP
#ifdef HLRAD_HULLU
if(s_transparency_list)
{
free(s_transparency_list);
s_transparency_list = NULL;
}
s_transparency_count = s_max_transparency_count = 0;
#endif
#endif
}
// =====================================================================================
// CheckVisBit
// =====================================================================================
#ifdef HLRAD_TRANSPARENCY_CPP
static bool CheckVisBitVismatrix(unsigned p1, unsigned p2
#ifdef HLRAD_HULLU
, vec3_t &transparency_out
, unsigned int &next_index
#endif
)
{
unsigned bitpos;
#ifdef HLRAD_HULLU
const unsigned a = p1;
const unsigned b = p2;
VectorFill(transparency_out, 1.0);
#endif
if (p1 > p2)
{
#ifndef HLRAD_HULLU
const unsigned a = p1;
const unsigned b = p2;
#endif
p1 = b;
p2 = a;
}
if (p1 > g_num_patches)
{
Warning("in CheckVisBit(), p1 > num_patches");
}
if (p2 > g_num_patches)
{
Warning("in CheckVisBit(), p2 > num_patches");
}
#ifdef HALFBIT
bitpos = p1 * g_num_patches - (p1 * (p1 + 1)) / 2 + p2;
#else
bitpos = p1 * g_num_patches + p2;
#endif
if (s_vismatrix[bitpos >> 3] & (1 << (bitpos & 7)))
{
#ifdef HLRAD_HULLU
if(g_customshadow_with_bouncelight)
{
GetTransparency( a, b, transparency_out, next_index );
}
#endif
return true;
}
return false;
}
#else /*HLRAD_TRANSPARENCY_CPP*/
static bool CheckVisBitVismatrix(unsigned p1, unsigned p2
#ifdef HLRAD_HULLU
, vec3_t &transparency_out
#endif
)
{
unsigned bitpos;
if (p1 > p2)
{
const unsigned a = p1;
const unsigned b = p2;
p1 = b;
p2 = a;
}
if (p1 > g_num_patches)
{
Warning("in CheckVisBit(), p1 > num_patches");
}
if (p2 > g_num_patches)
{
Warning("in CheckVisBit(), p2 > num_patches");
}
#ifdef HALFBIT
bitpos = p1 * g_num_patches - (p1 * (p1 + 1)) / 2 + p2;
#else
bitpos = p1 * g_num_patches + p2;
#endif
if (s_vismatrix[bitpos >> 3] & (1 << (bitpos & 7)))
{
#ifdef HLRAD_HULLU
if(g_customshadow_with_bouncelight)
{
vec3_t getvalue = {1.0, 1.0, 1.0};
FindOpacity(bitpos, getvalue);
VectorCopy(getvalue, transparency_out);
}
else
{
VectorFill(transparency_out, 1.0);
}
#endif
return true;
}
#ifdef HLRAD_HULLU
VectorFill(transparency_out, 0.0);
#endif
return false;
}
#endif /*HLRAD_TRANSPARENCY_CPP*/
//
// end old vismat.c
////////////////////////////
// =====================================================================================
// MakeScalesVismatrix
// =====================================================================================
void MakeScalesVismatrix()
{
char transferfile[_MAX_PATH];
hlassume(g_num_patches < MAX_VISMATRIX_PATCHES, assume_MAX_PATCHES);
#ifdef ZHLT_DEFAULTEXTENSION_FIX
safe_snprintf(transferfile, _MAX_PATH, "%s.inc", g_Mapname);
#else
safe_strncpy(transferfile, g_source, _MAX_PATH);
StripExtension(transferfile);
DefaultExtension(transferfile, ".inc");
#endif
if (!g_incremental || !readtransfers(transferfile, g_num_patches))
{
// determine visibility between g_patches
BuildVisMatrix();
g_CheckVisBit = CheckVisBitVismatrix;
#ifdef HLRAD_HULLU
#ifdef HLRAD_TRANSPARENCY_CPP
CreateFinalTransparencyArrays("custom shadow array");
#else
if((s_max_transparency_count*sizeof(transparency_t))>=(1024 * 1024))
Log("%-20s: %5.1f megs\n", "custom shadow array", (s_max_transparency_count*sizeof(transparency_t)) / (1024 * 1024.0));
else if(s_transparency_count)
Log("%-20s: %5.1f kilos\n", "custom shadow array", (s_max_transparency_count*sizeof(transparency_t)) / 1024.0);
#endif
#endif
#ifndef HLRAD_HULLU
NamedRunThreadsOn(g_num_patches, g_estimate, MakeScales);
#else
if(g_rgb_transfers)
{NamedRunThreadsOn(g_num_patches, g_estimate, MakeRGBScales);}
else
{NamedRunThreadsOn(g_num_patches, g_estimate, MakeScales);}
#endif
FreeVisMatrix();
#ifdef HLRAD_HULLU
#ifdef HLRAD_TRANSPARENCY_CPP
FreeTransparencyArrays();
#endif
#endif
#ifndef HLRAD_NOSWAP
// invert the transfers for gather vs scatter
#ifndef HLRAD_HULLU
NamedRunThreadsOnIndividual(g_num_patches, g_estimate, SwapTransfers);
#else
if(g_rgb_transfers)
{NamedRunThreadsOnIndividual(g_num_patches, g_estimate, SwapRGBTransfers);}
else
{NamedRunThreadsOnIndividual(g_num_patches, g_estimate, SwapTransfers);}
#endif
#endif /*HLRAD_NOSWAP*/
if (g_incremental)
writetransfers(transferfile, g_num_patches);
else
_unlink(transferfile);
DumpTransfersMemoryUsage();
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
CreateFinalStyleArrays ("dynamic shadow array");
#endif
}
}