vhlt/hlrad/qrad.cpp

5920 lines
171 KiB
C++
Raw Normal View History

2016-09-20 21:07:53 +00:00
/*
R A D I O S I T Y -aka- R A D
Code based on original code from Valve Software,
Modified by Sean "Zoner" Cavanaugh (seanc@gearboxsoftware.com) with permission.
Modified by Tony "Merl" Moore (merlinis@bigpond.net.au) [AJM]
*/
#ifdef SYSTEM_WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <vector>
#include <string>
#include "qrad.h"
/*
* NOTES
* -----
* every surface must be divided into at least two g_patches each axis
*/
#ifdef ZHLT_XASH
int g_dlitdatasize = 0;
int g_max_map_dlitdata = 0;
byte *g_ddlitdata = NULL;
char g_dlitfile[_MAX_PATH] = "";
bool g_drawdirection = false;
vec_t g_directionscale = 0.0;
#endif
#ifdef HLRAD_FASTMODE
bool g_fastmode = DEFAULT_FASTMODE;
#endif
typedef enum
{
eMethodVismatrix,
eMethodSparseVismatrix,
eMethodNoVismatrix
}
eVisMethods;
#ifdef HLRAD_ARG_MISC
eVisMethods g_method = DEFAULT_METHOD;
#else
eVisMethods g_method = eMethodVismatrix;
#endif
vec_t g_fade = DEFAULT_FADE;
#ifndef HLRAD_ARG_MISC
int g_falloff = DEFAULT_FALLOFF;
#endif
patch_t* g_face_patches[MAX_MAP_FACES];
entity_t* g_face_entity[MAX_MAP_FACES];
eModelLightmodes g_face_lightmode[MAX_MAP_FACES];
#ifdef HLRAD_MORE_PATCHES
patch_t* g_patches;
#else
patch_t g_patches[MAX_PATCHES];
#endif
#ifdef HLRAD_CUSTOMTEXLIGHT
entity_t* g_face_texlights[MAX_MAP_FACES];
#endif
unsigned g_num_patches;
#ifdef ZHLT_TEXLIGHT
#ifdef HLRAD_MORE_PATCHES
static vec3_t (*emitlight)[MAXLIGHTMAPS]; //LRC
static vec3_t (*addlight)[MAXLIGHTMAPS]; //LRC
#else
static vec3_t emitlight[MAX_PATCHES][MAXLIGHTMAPS]; //LRC
static vec3_t addlight[MAX_PATCHES][MAXLIGHTMAPS]; //LRC
#endif
#ifdef ZHLT_XASH
#ifdef HLRAD_MORE_PATCHES
static vec3_t (*emitlight_direction)[MAXLIGHTMAPS];
static vec3_t (*addlight_direction)[MAXLIGHTMAPS];
#else
static vec3_t emitlight_direction[MAX_PATCHES][MAXLIGHTMAPS];
static vec3_t addlight_direction[MAX_PATCHES][MAXLIGHTMAPS];
#endif
#endif
#ifdef HLRAD_AUTOCORING
#ifdef HLRAD_MORE_PATCHES
static unsigned char (*newstyles)[MAXLIGHTMAPS];
#else
static unsigned char newstyles[MAX_PATCHES][MAXLIGHTMAPS];
#endif
#endif
#else
#ifdef HLRAD_MORE_PATCHES
static vec3_t (*emitlight);
static vec3_t (*addlight);
#else
static vec3_t emitlight[MAX_PATCHES];
static vec3_t addlight[MAX_PATCHES];
#endif
#endif
vec3_t g_face_offset[MAX_MAP_FACES]; // for rotating bmodels
vec_t g_direct_scale = DEFAULT_DLIGHT_SCALE;
unsigned g_numbounce = DEFAULT_BOUNCE; // 3; /* Originally this was 8 */
static bool g_dumppatches = DEFAULT_DUMPPATCHES;
vec3_t g_ambient = { DEFAULT_AMBIENT_RED, DEFAULT_AMBIENT_GREEN, DEFAULT_AMBIENT_BLUE };
#ifndef HLRAD_FinalLightFace_VL
float g_maxlight = DEFAULT_MAXLIGHT; // 196 /* Originally this was 196 */
#endif
#ifdef HLRAD_PRESERVELIGHTMAPCOLOR
vec_t g_limitthreshold = DEFAULT_LIMITTHRESHOLD;
bool g_drawoverload = false;
#endif
float g_lightscale = DEFAULT_LIGHTSCALE;
float g_dlight_threshold = DEFAULT_DLIGHT_THRESHOLD; // was DIRECT_LIGHT constant
char g_source[_MAX_PATH] = "";
char g_vismatfile[_MAX_PATH] = "";
bool g_incremental = DEFAULT_INCREMENTAL;
#ifndef HLRAD_WHOME
float g_qgamma = DEFAULT_GAMMA;
#endif
float g_indirect_sun = DEFAULT_INDIRECT_SUN;
bool g_extra = DEFAULT_EXTRA;
bool g_texscale = DEFAULT_TEXSCALE;
float g_smoothing_threshold;
float g_smoothing_value = DEFAULT_SMOOTHING_VALUE;
#ifdef HLRAD_CUSTOMSMOOTH
float g_smoothing_threshold_2;
float g_smoothing_value_2 = DEFAULT_SMOOTHING2_VALUE;
#endif
bool g_circus = DEFAULT_CIRCUS;
bool g_allow_opaques = DEFAULT_ALLOW_OPAQUES;
#ifdef HLRAD_SUNSPREAD
bool g_allow_spread = DEFAULT_ALLOW_SPREAD;
#endif
// --------------------------------------------------------------------------
// Changes by Adam Foster - afoster@compsoc.man.ac.uk
#ifdef HLRAD_WHOME
vec3_t g_colour_qgamma = { DEFAULT_COLOUR_GAMMA_RED, DEFAULT_COLOUR_GAMMA_GREEN, DEFAULT_COLOUR_GAMMA_BLUE };
vec3_t g_colour_lightscale = { DEFAULT_COLOUR_LIGHTSCALE_RED, DEFAULT_COLOUR_LIGHTSCALE_GREEN, DEFAULT_COLOUR_LIGHTSCALE_BLUE };
vec3_t g_colour_jitter_hack = { DEFAULT_COLOUR_JITTER_HACK_RED, DEFAULT_COLOUR_JITTER_HACK_GREEN, DEFAULT_COLOUR_JITTER_HACK_BLUE };
vec3_t g_jitter_hack = { DEFAULT_JITTER_HACK_RED, DEFAULT_JITTER_HACK_GREEN, DEFAULT_JITTER_HACK_BLUE };
#ifndef HLRAD_ARG_MISC
bool g_diffuse_hack = DEFAULT_DIFFUSE_HACK;
bool g_spotlight_hack = DEFAULT_SPOTLIGHT_HACK;
#endif
#ifndef HLRAD_CUSTOMTEXLIGHT // no softlight hack
vec3_t g_softlight_hack = { DEFAULT_SOFTLIGHT_HACK_RED, DEFAULT_SOFTLIGHT_HACK_GREEN, DEFAULT_SOFTLIGHT_HACK_BLUE };
float g_softlight_hack_distance = DEFAULT_SOFTLIGHT_HACK_DISTANCE;
#endif
#endif
// --------------------------------------------------------------------------
#ifdef HLRAD_HULLU
bool g_customshadow_with_bouncelight = DEFAULT_CUSTOMSHADOW_WITH_BOUNCELIGHT;
bool g_rgb_transfers = DEFAULT_RGB_TRANSFERS;
#endif
#ifdef HLRAD_TRANSTOTAL_HACK
float g_transtotal_hack = DEFAULT_TRANSTOTAL_HACK;
#endif
#ifdef HLRAD_MINLIGHT
unsigned char g_minlight = DEFAULT_MINLIGHT;
#endif
#ifdef HLRAD_TRANSFERDATA_COMPRESS
float_type g_transfer_compress_type = DEFAULT_TRANSFER_COMPRESS_TYPE;
vector_type g_rgbtransfer_compress_type = DEFAULT_RGBTRANSFER_COMPRESS_TYPE;
#endif
#ifdef HLRAD_SOFTSKY
bool g_softsky = DEFAULT_SOFTSKY;
#endif
#ifdef HLRAD_OPAQUE_BLOCK
int g_blockopaque = DEFAULT_BLOCKOPAQUE;
#endif
#ifdef HLRAD_TEXTURE
bool g_notextures = DEFAULT_NOTEXTURES;
#endif
#ifdef HLRAD_REFLECTIVITY
vec_t g_texreflectgamma = DEFAULT_TEXREFLECTGAMMA;
vec_t g_texreflectscale = DEFAULT_TEXREFLECTSCALE;
#endif
#ifdef HLRAD_AVOIDWALLBLEED
bool g_bleedfix = DEFAULT_BLEEDFIX;
#endif
#ifdef HLRAD_DEBUG_DRAWPOINTS
bool g_drawpatch = false;
bool g_drawsample = false;
vec3_t g_drawsample_origin = {0,0,0};
vec_t g_drawsample_radius = 0;
bool g_drawedge = false;
bool g_drawlerp = false;
#endif
#ifdef HLRAD_AVOIDWALLBLEED
bool g_drawnudge = false;
#endif
// Cosine of smoothing angle(in radians)
float g_coring = DEFAULT_CORING; // Light threshold to force to blackness(minimizes lightmaps)
bool g_chart = DEFAULT_CHART;
bool g_estimate = DEFAULT_ESTIMATE;
bool g_info = DEFAULT_INFO;
#ifdef ZHLT_PROGRESSFILE // AJM
char* g_progressfile = DEFAULT_PROGRESSFILE; // "-progressfile path"
#endif
// Patch creation and subdivision criteria
bool g_subdivide = DEFAULT_SUBDIVIDE;
vec_t g_chop = DEFAULT_CHOP;
vec_t g_texchop = DEFAULT_TEXCHOP;
// Opaque faces
opaqueList_t* g_opaque_face_list = NULL;
unsigned g_opaque_face_count = 0;
unsigned g_max_opaque_face_count = 0; // Current array maximum (used for reallocs)
#ifndef HLRAD_OPAQUE_NODE
#ifdef HLRAD_OPAQUE_GROUP
opaqueGroup_t g_opaque_group_list[MAX_OPAQUE_GROUP_COUNT];
unsigned g_opaque_group_count = 0;
#endif
#endif
#ifdef HLRAD_STYLE_CORING
vec_t g_corings[ALLSTYLES];
#endif
#ifdef HLRAD_TRANSLUCENT
vec3_t* g_translucenttextures = NULL;
vec_t g_translucentdepth = DEFAULT_TRANSLUCENTDEPTH;
#endif
#ifdef HLRAD_BLUR
vec_t g_blur = DEFAULT_BLUR;
#endif
#ifdef HLRAD_ACCURATEBOUNCE
bool g_noemitterrange = DEFAULT_NOEMITTERRANGE;
#endif
#ifdef HLRAD_TEXLIGHTGAP
vec_t g_texlightgap = DEFAULT_TEXLIGHTGAP;
#endif
// Misc
int leafparents[MAX_MAP_LEAFS];
int nodeparents[MAX_MAP_NODES];
#ifdef HLRAD_READABLE_EXCEEDSTYLEWARNING
int stylewarningcount = 0;
int stylewarningnext = 1;
#endif
#ifdef HLRAD_AUTOCORING
vec_t g_maxdiscardedlight = 0;
vec3_t g_maxdiscardedpos = {0, 0, 0};
#endif
#ifdef ZHLT_INFO_COMPILE_PARAMETERS
// =====================================================================================
// GetParamsFromEnt
// this function is called from parseentity when it encounters the
// info_compile_parameters entity. each tool should have its own version of this
// to handle its own specific settings.
// =====================================================================================
void GetParamsFromEnt(entity_t* mapent)
{
int iTmp;
float flTmp;
char szTmp[256]; //lightdata
const char* pszTmp;
Log("\nCompile Settings detected from info_compile_parameters entity\n");
// lightdata(string) : "Lighting Data Memory" : "8192"
iTmp = IntForKey(mapent, "lightdata") * 1024; //lightdata
if (iTmp > g_max_map_lightdata) //--vluzacn
{
g_max_map_lightdata = iTmp;
sprintf_s(szTmp, "%i", g_max_map_lightdata);
Log("%30s [ %-9s ]\n", "Lighting Data Memory", szTmp);
}
// verbose(choices) : "Verbose compile messages" : 0 = [ 0 : "Off" 1 : "On" ]
iTmp = IntForKey(mapent, "verbose");
if (iTmp == 1)
{
g_verbose = true;
}
else if (iTmp == 0)
{
g_verbose = false;
}
Log("%30s [ %-9s ]\n", "Compile Option", "setting");
Log("%30s [ %-9s ]\n", "Verbose Compile Messages", g_verbose ? "on" : "off");
// estimate(choices) :"Estimate Compile Times?" : 0 = [ 0: "Yes" 1: "No" ]
if (IntForKey(mapent, "estimate"))
{
g_estimate = true;
}
else
{
g_estimate = false;
}
Log("%30s [ %-9s ]\n", "Estimate Compile Times", g_estimate ? "on" : "off");
// priority(choices) : "Priority Level" : 0 = [ 0 : "Normal" 1 : "High" -1 : "Low" ]
if (!strcmp(ValueForKey(mapent, "priority"), "1"))
{
g_threadpriority = eThreadPriorityHigh;
Log("%30s [ %-9s ]\n", "Thread Priority", "high");
}
else if (!strcmp(ValueForKey(mapent, "priority"), "-1"))
{
g_threadpriority = eThreadPriorityLow;
Log("%30s [ %-9s ]\n", "Thread Priority", "low");
}
// bounce(integer) : "Number of radiosity bounces" : 0
iTmp = IntForKey(mapent, "bounce");
if (iTmp)
{
g_numbounce = abs(iTmp);
Log("%30s [ %-9s ]\n", "Number of radiosity bounces", ValueForKey(mapent, "bounce"));
}
#ifdef HLRAD_HULLU
iTmp = IntForKey(mapent, "customshadowwithbounce");
if (iTmp)
{
g_customshadow_with_bouncelight = true;
Log("%30s [ %-9s ]\n", "Custom Shadow with Bounce Light", ValueForKey(mapent, "customshadowwithbounce"));
}
iTmp = IntForKey(mapent, "rgbtransfers");
if (iTmp)
{
g_rgb_transfers = true;
Log("%30s [ %-9s ]\n", "RGB Transfers", ValueForKey(mapent, "rgbtransfers"));
}
#endif
// ambient(string) : "Ambient world light (0.0 to 1.0, R G B)" : "0 0 0"
//vec3_t g_ambient = { DEFAULT_AMBIENT_RED, DEFAULT_AMBIENT_GREEN, DEFAULT_AMBIENT_BLUE };
pszTmp = ValueForKey(mapent, "ambient");
if (pszTmp)
{
float red = 0, green = 0, blue = 0;
if (sscanf(pszTmp, "%f %f %f", &red, &green, &blue))
{
if (red < 0 || red > 1 || green < 0 || green > 1 || blue < 0 || blue > 1)
{
Error("info_compile_parameters: Ambient World Light (ambient) all 3 values must be within the range of 0.0 to 1.0\n"
"Parsed values:\n"
" red [ %1.3f ] %s\n"
" green [ %1.3f ] %s\n"
" blue [ %1.3f ] %s\n"
, red, (red < 0 || red > 1) ? "OUT OF RANGE" : ""
, green, (green < 0 || green > 1) ? "OUT OF RANGE" : ""
, blue, (blue < 0 || blue > 1) ? "OUT OF RANGE" : "" );
}
if (red == 0 && green == 0 && blue == 0)
{} // dont bother setting null values
else
{
g_ambient[0] = red * 128;
g_ambient[1] = green * 128;
g_ambient[2] = blue * 128;
Log("%30s [ %1.3f %1.3f %1.3f ]\n", "Ambient world light (R G B)", red, green, blue);
}
}
else
{
Error("info_compile_parameters: Ambient World Light (ambient) has unrecognised value\n"
"This keyvalue accepts 3 numeric values from 0.000 to 1.000, use \"0 0 0\" if in doubt");
}
}
// smooth(integer) : "Smoothing threshold (in degrees)" : 0
flTmp = FloatForKey(mapent, "smooth");
if (flTmp)
{
/*g_smoothing_threshold = flTmp;*/
g_smoothing_threshold = cos(g_smoothing_value * (Q_PI / 180.0)); // --vluzacn
Log("%30s [ %-9s ]\n", "Smoothing threshold", ValueForKey(mapent, "smooth"));
}
// dscale(integer) : "Direct Lighting Scale" : 1
flTmp = FloatForKey(mapent, "dscale");
if (flTmp)
{
g_direct_scale = flTmp;
Log("%30s [ %-9s ]\n", "Direct Lighting Scale", ValueForKey(mapent, "dscale"));
}
// chop(integer) : "Chop Size" : 64
iTmp = IntForKey(mapent, "chop");
if (iTmp)
{
g_chop = iTmp;
Log("%30s [ %-9s ]\n", "Chop Size", ValueForKey(mapent, "chop"));
}
// texchop(integer) : "Texture Light Chop Size" : 32
flTmp = FloatForKey(mapent, "texchop");
if (flTmp)
{
g_texchop = flTmp;
Log("%30s [ %-9s ]\n", "Texture Light Chop Size", ValueForKey(mapent, "texchop"));
}
/*
hlrad(choices) : "HLRAD" : 0 =
[
0 : "Off"
1 : "Normal"
2 : "Extra"
]
*/
iTmp = IntForKey(mapent, "hlrad");
if (iTmp == 0)
{
Fatal(assume_TOOL_CANCEL,
"%s flag was not checked in info_compile_parameters entity, execution of %s cancelled", g_Program, g_Program);
CheckFatal();
}
else if (iTmp == 1)
{
g_extra = false;
}
else if (iTmp == 2)
{
g_extra = true;
}
Log("%30s [ %-9s ]\n", "Extra RAD", g_extra ? "on" : "off");
/*
sparse(choices) : "Vismatrix Method" : 2 =
[
0 : "No Vismatrix"
1 : "Sparse Vismatrix"
2 : "Normal"
]
*/
iTmp = IntForKey(mapent, "sparse");
if (iTmp == 1)
{
g_method = eMethodSparseVismatrix;
}
else if (iTmp == 0)
{
g_method = eMethodNoVismatrix;
}
else if (iTmp == 2)
{
g_method = eMethodVismatrix;
}
Log("%30s [ %-9s ]\n", "Sparse Vismatrix", g_method == eMethodSparseVismatrix ? "on" : "off");
Log("%30s [ %-9s ]\n", "NoVismatrix", g_method == eMethodNoVismatrix ? "on" : "off");
/*
circus(choices) : "Circus RAD lighting" : 0 =
[
0 : "Off"
1 : "On"
]
*/
iTmp = IntForKey(mapent, "circus");
if (iTmp == 0)
{
g_circus = false;
}
else if (iTmp == 1)
{
g_circus = true;
}
Log("%30s [ %-9s ]\n", "Circus Lighting Mode", g_circus ? "on" : "off");
////////////////////
Log("\n");
}
#endif
// =====================================================================================
// MakeParents
// blah
// =====================================================================================
static void MakeParents(const int nodenum, const int parent)
{
int i;
int j;
dnode_t* node;
nodeparents[nodenum] = parent;
node = g_dnodes + nodenum;
for (i = 0; i < 2; i++)
{
j = node->children[i];
if (j < 0)
{
leafparents[-j - 1] = nodenum;
}
else
{
MakeParents(j, nodenum);
}
}
}
// =====================================================================================
//
// TEXTURE LIGHT VALUES
//
// =====================================================================================
// misc
typedef struct
{
std::string name;
vec3_t value;
const char* filename;
}
texlight_t;
static std::vector< texlight_t > s_texlights;
typedef std::vector< texlight_t >::iterator texlight_i;
// =====================================================================================
// ReadLightFile
// =====================================================================================
static void ReadLightFile(const char* const filename)
{
FILE* f;
char scan[MAXTOKEN];
short argCnt;
unsigned int file_texlights = 0;
f = fopen(filename, "r");
if (!f)
{
Warning("Could not open texlight file %s", filename);
return;
}
else
{
#ifdef HLRAD_CUSTOMTEXLIGHT
Log("Reading texlights from '%s'\n", filename);
#else
Log("[Reading texlights from '%s']\n", filename);
#endif
}
while (fgets(scan, sizeof(scan), f))
{
char* comment;
char szTexlight[_MAX_PATH];
vec_t r, g, b, i = 1;
comment = strstr(scan, "//");
if (comment)
{
// Newline and Null terminate the string early if there is a c++ style single line comment
comment[0] = '\n';
comment[1] = 0;
}
argCnt = sscanf(scan, "%s %f %f %f %f", szTexlight, &r, &g, &b, &i);
if (argCnt == 2)
{
// With 1+1 args, the R,G,B values are all equal to the first value
g = b = r;
}
else if (argCnt == 5)
{
// With 1+4 args, the R,G,B values are "scaled" by the fourth numeric value i;
r *= i / 255.0;
g *= i / 255.0;
b *= i / 255.0;
}
else if (argCnt != 4)
{
if (strlen(scan) > 4)
{
Warning("ignoring bad texlight '%s' in %s", scan, filename);
}
continue;
}
texlight_i it;
for (it = s_texlights.begin(); it != s_texlights.end(); it++)
{
if (strcmp(it->name.c_str(), szTexlight) == 0)
{
if (strcmp(it->filename, filename) == 0)
{
Warning("Duplication of texlight '%s' in file '%s'!", it->name.c_str(), it->filename);
}
else if (it->value[0] != r || it->value[1] != g || it->value[2] != b)
{
Warning("Overriding '%s' from '%s' with '%s'!", it->name.c_str(), it->filename, filename);
}
else
{
Warning("Redundant '%s' def in '%s' AND '%s'!", it->name.c_str(), it->filename, filename);
}
s_texlights.erase(it);
break;
}
}
texlight_t texlight;
texlight.name = szTexlight;
texlight.value[0] = r;
texlight.value[1] = g;
texlight.value[2] = b;
texlight.filename = filename;
file_texlights++;
s_texlights.push_back(texlight);
}
fclose (f); //--vluzacn
#ifndef HLRAD_CUSTOMTEXLIGHT
Log("[%u texlights parsed from '%s']\n\n", file_texlights, filename);
#endif
}
// =====================================================================================
// LightForTexture
// =====================================================================================
static void LightForTexture(const char* const name, vec3_t result)
{
texlight_i it;
for (it = s_texlights.begin(); it != s_texlights.end(); it++)
{
if (!strcasecmp(name, it->name.c_str()))
{
VectorCopy(it->value, result);
return;
}
}
VectorClear(result);
}
// =====================================================================================
//
// MAKE FACES
//
// =====================================================================================
// =====================================================================================
// BaseLightForFace
// =====================================================================================
static void BaseLightForFace(const dface_t* const f, vec3_t light)
{
#ifdef HLRAD_CUSTOMTEXLIGHT
int fn = f - g_dfaces;
if (g_face_texlights[fn])
{
double r, g, b, scaler;
switch (sscanf (ValueForKey (g_face_texlights[fn], "_light"), "%lf %lf %lf %lf", &r, &g, &b, &scaler))
{
case -1:
case 0:
r = 0.0;
case 1:
g = b = r;
case 3:
break;
case 4:
r *= scaler / 255.0;
g *= scaler / 255.0;
b *= scaler / 255.0;
break;
default:
vec3_t origin;
GetVectorForKey (g_face_texlights[fn], "origin", origin);
Log("light at (%f,%f,%f) has bad or missing '_light' value : '%s'\n",
origin[0], origin[1], origin[2], ValueForKey (g_face_texlights[fn], "_light"));
r = g = b = 0;
break;
}
light[0] = r > 0? r: 0;
light[1] = g > 0? g: 0;
light[2] = b > 0? b: 0;
return;
}
#endif
texinfo_t* tx;
miptex_t* mt;
int ofs;
//
// check for light emited by texture
//
tx = &g_texinfo[f->texinfo];
ofs = ((dmiptexlump_t*)g_dtexdata)->dataofs[tx->miptex];
mt = (miptex_t*)((byte*) g_dtexdata + ofs);
LightForTexture(mt->name, light);
}
// =====================================================================================
// IsSpecial
// =====================================================================================
static bool IsSpecial(const dface_t* const f)
{
return g_texinfo[f->texinfo].flags & TEX_SPECIAL;
}
// =====================================================================================
// PlacePatchInside
// =====================================================================================
static bool PlacePatchInside(patch_t* patch)
{
const dplane_t* plane;
const vec_t* face_offset = g_face_offset[patch->faceNumber];
plane = getPlaneFromFaceNumber(patch->faceNumber);
#ifdef HLRAD_PATCHBLACK_FIX
#ifdef HLRAD_ACCURATEBOUNCE_REDUCEAREA
vec_t pointsfound;
vec_t pointstested;
pointsfound = pointstested = 0;
#endif
vec3_t center;
bool found;
vec3_t bestpoint;
vec_t bestdist = -1.0;
vec3_t point;
vec_t dist;
vec3_t v;
patch->winding->getCenter (center);
found = false;
VectorMA (center, PATCH_HUNT_OFFSET, plane->normal, point);
#ifdef HLRAD_ACCURATEBOUNCE_REDUCEAREA
pointstested++;
#endif
if (HuntForWorld (point, face_offset, plane, 4, 0.2, PATCH_HUNT_OFFSET) ||
HuntForWorld (point, face_offset, plane, 4, 0.8, PATCH_HUNT_OFFSET))
{
#ifdef HLRAD_ACCURATEBOUNCE_REDUCEAREA
pointsfound++;
#endif
VectorSubtract (point, center, v);
dist = VectorLength (v);
if (!found || dist < bestdist)
{
found = true;
VectorCopy (point, bestpoint);
bestdist = dist;
}
}
#ifndef HLRAD_ACCURATEBOUNCE_REDUCEAREA
if (!found)
#endif
{
for (int i = 0; i < patch->winding->m_NumPoints; i++)
{
const vec_t *p1;
const vec_t *p2;
p1 = patch->winding->m_Points[i];
p2 = patch->winding->m_Points[(i+1)%patch->winding->m_NumPoints];
VectorAdd (p1, p2, point);
VectorAdd (point, center, point);
VectorScale (point, 1.0/3.0, point);
VectorMA (point, PATCH_HUNT_OFFSET, plane->normal, point);
#ifdef HLRAD_ACCURATEBOUNCE_REDUCEAREA
pointstested++;
#endif
if (HuntForWorld (point, face_offset, plane, 4, 0.2, PATCH_HUNT_OFFSET) ||
HuntForWorld (point, face_offset, plane, 4, 0.8, PATCH_HUNT_OFFSET))
{
#ifdef HLRAD_ACCURATEBOUNCE_REDUCEAREA
pointsfound++;
#endif
VectorSubtract (point, center, v);
dist = VectorLength (v);
if (!found || dist < bestdist)
{
found = true;
VectorCopy (point, bestpoint);
bestdist = dist;
}
}
}
}
#ifdef HLRAD_ACCURATEBOUNCE_REDUCEAREA
patch->exposure = pointsfound / pointstested;
#endif
if (found)
{
VectorCopy (bestpoint, patch->origin);
patch->flags = ePatchFlagNull;
return true;
}
else
{
VectorMA (center, PATCH_HUNT_OFFSET, plane->normal, patch->origin);
patch->flags = ePatchFlagOutside;
Developer(DEVELOPER_LEVEL_FLUFF, "Patch @ (%4.3f %4.3f %4.3f) outside world\n",
patch->origin[0], patch->origin[1], patch->origin[2]);
return false;
}
#else // obviously who wrote these code misunderstood the function of HuntForWorld
if (!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.01) &&
!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.1) &&
!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.5) &&
!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, -0.01) &&
!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, -0.1))
{
// Try offsetting it by the plane normal (1 unit away) and try again
VectorAdd(plane->normal, patch->origin, patch->origin); // Original offset-into-world method
if (PointInLeaf(patch->origin) == g_dleafs)
{
if (!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.01) &&
!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.1) &&
!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, 0.5) &&
!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, -0.01) &&
!HuntForWorld(patch->origin, face_offset, plane, 11, 0.1, -0.1))
{
patch->flags = (ePatchFlags)(patch->flags | ePatchFlagOutside);
Developer(DEVELOPER_LEVEL_MESSAGE, "Patch @ (%4.3f %4.3f %4.3f) outside world\n",
patch->origin[0], patch->origin[1], patch->origin[2]);
return false;
}
}
}
return true;
#endif
}
#ifdef HLRAD_ACCURATEBOUNCE
static void UpdateEmitterInfo (patch_t *patch)
{
#if ACCURATEBOUNCE_DEFAULT_SKYLEVEL + 3 > SKYLEVELMAX
#error "please raise SKYLEVELMAX"
#endif
const vec_t *origin = patch->origin;
const Winding *winding = patch->winding;
vec_t radius = ON_EPSILON;
for (int x = 0; x < winding->m_NumPoints; x++)
{
vec3_t delta;
vec_t dist;
VectorSubtract (winding->m_Points[x], origin, delta);
dist = VectorLength (delta);
if (dist > radius)
{
radius = dist;
}
}
int skylevel = ACCURATEBOUNCE_DEFAULT_SKYLEVEL;
vec_t area = winding->getArea ();
vec_t size = 0.8f;
if (area < size * radius * radius) // the shape is too thin
{
skylevel++;
size *= 0.25f;
if (area < size * radius * radius)
{
skylevel++;
size *= 0.25f;
if (area < size * radius * radius)
{
// stop here
radius = sqrt (area / size);
// just decrease the range to limit the use of the new method. because when the area is small, the new method becomes randomized and unstable.
}
}
}
patch->emitter_range = ACCURATEBOUNCE_THRESHOLD * radius;
if (g_noemitterrange)
{
patch->emitter_range = 0.0;
}
patch->emitter_skylevel = skylevel;
}
#endif
// =====================================================================================
//
// SUBDIVIDE PATCHES
//
// =====================================================================================
// misc
#define MAX_SUBDIVIDE 16384
static Winding* windingArray[MAX_SUBDIVIDE];
static unsigned g_numwindings = 0;
#ifdef HLRAD_SUBDIVIDEPATCH_NEW
// =====================================================================================
// cutWindingWithGrid
// Caller must free this returned value at some point
// =====================================================================================
static void cutWindingWithGrid (patch_t *patch, const dplane_t *plA, const dplane_t *plB)
// This function has been rewritten because the original one is not totally correct and may fail to do what it claims.
{
// patch->winding->m_NumPoints must > 0
// plA->dist and plB->dist will not be used
Winding *winding = NULL;
vec_t chop;
vec_t epsilon;
const int max_gridsize = 64;
vec_t gridstartA;
vec_t gridstartB;
int gridsizeA;
int gridsizeB;
vec_t gridchopA;
vec_t gridchopB;
int numstrips;
winding = new Winding (*patch->winding); // perform all the operations on the copy
chop = patch->chop;
chop = qmax (1.0, chop);
epsilon = 0.6;
// optimize the grid
{
vec_t minA;
vec_t maxA;
vec_t minB;
vec_t maxB;
minA = minB = BOGUS_RANGE;
maxA = maxB = -BOGUS_RANGE;
for (int x = 0; x < winding->m_NumPoints; x++)
{
vec_t *point;
vec_t dotA;
vec_t dotB;
point = winding->m_Points[x];
dotA = DotProduct (point, plA->normal);
minA = qmin (minA, dotA);
maxA = qmax (maxA, dotA);
dotB = DotProduct (point, plB->normal);
minB = qmin (minB, dotB);
maxB = qmax (maxB, dotB);
}
gridchopA = chop;
gridsizeA = (int)ceil ((maxA - minA - 2 * epsilon) / gridchopA);
gridsizeA = qmax (1, gridsizeA);
if (gridsizeA > max_gridsize)
{
gridsizeA = max_gridsize;
gridchopA = (maxA - minA) / (vec_t)gridsizeA;
}
gridstartA = (minA + maxA) / 2.0 - (gridsizeA / 2.0) * gridchopA;
gridchopB = chop;
gridsizeB = (int)ceil ((maxB - minB - 2 * epsilon) / gridchopB);
gridsizeB = qmax (1, gridsizeB);
if (gridsizeB > max_gridsize)
{
gridsizeB = max_gridsize;
gridchopB = (maxB - minB) / (vec_t)gridsizeB;
}
gridstartB = (minB + maxB) / 2.0 - (gridsizeB / 2.0) * gridchopB;
}
// cut the winding by the direction of plane A and save into windingArray
{
g_numwindings = 0;
for (int i = 1; i < gridsizeA; i++)
{
vec_t dist;
Winding *front = NULL;
Winding *back = NULL;
dist = gridstartA + i * gridchopA;
winding->Clip (plA->normal, dist, &front, &back);
if (!front || front->WindingOnPlaneSide (plA->normal, dist, epsilon) == SIDE_ON) // ended
{
if (front)
{
delete front;
front = NULL;
}
if (back)
{
delete back;
back = NULL;
}
break;
}
if (!back || back->WindingOnPlaneSide (plA->normal, dist, epsilon) == SIDE_ON) // didn't begin
{
if (front)
{
delete front;
front = NULL;
}
if (back)
{
delete back;
back = NULL;
}
continue;
}
delete winding;
winding = NULL;
windingArray[g_numwindings] = back;
g_numwindings++;
back = NULL;
winding = front;
front = NULL;
}
windingArray[g_numwindings] = winding;
g_numwindings++;
winding = NULL;
}
// cut by the direction of plane B
{
numstrips = g_numwindings;
for (int i = 0; i < numstrips; i++)
{
Winding *strip = windingArray[i];
windingArray[i] = NULL;
for (int j = 1; j < gridsizeB; j++)
{
vec_t dist;
Winding *front = NULL;
Winding *back = NULL;
dist = gridstartB + j * gridchopB;
strip->Clip (plB->normal, dist, &front, &back);
if (!front || front->WindingOnPlaneSide (plB->normal, dist, epsilon) == SIDE_ON) // ended
{
if (front)
{
delete front;
front = NULL;
}
if (back)
{
delete back;
back = NULL;
}
break;
}
if (!back || back->WindingOnPlaneSide (plB->normal, dist, epsilon) == SIDE_ON) // didn't begin
{
if (front)
{
delete front;
front = NULL;
}
if (back)
{
delete back;
back = NULL;
}
continue;
}
delete strip;
strip = NULL;
windingArray[g_numwindings] = back;
g_numwindings++;
back = NULL;
strip = front;
front = NULL;
}
windingArray[g_numwindings] = strip;
g_numwindings++;
strip = NULL;
}
}
delete patch->winding;
patch->winding = NULL;
}
#else
// =====================================================================================
// AddWindingToArray
// =====================================================================================
static void AddWindingToArray(Winding* winding)
{
unsigned x;
Winding** wA = windingArray;
for (x = 0; x < g_numwindings; x++, wA++)
{
if (*wA == winding)
{
return;
}
}
windingArray[g_numwindings++] = winding;
}
static void CreateStrips_r(Winding* winding, const vec3_t plane_normal, const vec_t plane_dist, vec_t step)
{
Winding* A;
Winding* B;
vec_t areaA;
vec_t areaB;
winding->Clip(plane_normal, plane_dist + step, &A, &B);
if (A && B)
{
areaA = A->getArea();
areaB = B->getArea();
if ((areaA > 1.0) && (areaB > 1.0))
{
delete winding;
CreateStrips_r(A, plane_normal, plane_dist + step, step);
CreateStrips_r(B, plane_normal, plane_dist + step, step);
return;
}
}
else
{ // Try the other direction
if (A)
{
delete A;
}
if (B)
{
delete B;
}
winding->Clip(plane_normal, plane_dist - step, &A, &B);
if (A && B)
{
areaA = A->getArea();
areaB = B->getArea();
if ((areaA > 1.0) && (areaB > 1.0))
{
delete winding;
CreateStrips_r(A, plane_normal, plane_dist - step, step);
CreateStrips_r(B, plane_normal, plane_dist - step, step);
return;
}
}
}
// Last recursion, save it into the list
if (A)
{
delete A;
}
if (B)
{
delete B;
}
AddWindingToArray(winding);
hlassume(g_numwindings < MAX_SUBDIVIDE, assume_GENERIC);
}
// =====================================================================================
// CreateStrips
// =====================================================================================
static bool CreateStrips(Winding* winding, const dplane_t* plane, vec_t step)
{
Winding* A;
Winding* B;
vec_t areaA;
vec_t areaB;
winding->Clip(plane->normal, plane->dist, &A, &B);
if (A && B)
{
areaA = A->getArea();
areaB = B->getArea();
if ((areaA > 1.0) && (areaB > 1.0))
{
CreateStrips_r(A, (vec_t*)plane->normal, plane->dist, step);
CreateStrips_r(B, (vec_t*)plane->normal, plane->dist, step);
return true;
}
}
if (A)
{
delete A;
}
if (B)
{
delete B;
}
AddWindingToArray(winding);
hlassume(g_numwindings < MAX_SUBDIVIDE, assume_GENERIC);
return false;
}
// =====================================================================================
// cutWindingWithGrid
// Caller must free this returned value at some point
// =====================================================================================
static void cutWindingWithGrid(patch_t* patch, const dplane_t* const plA, const dplane_t* const plB)
{
Winding** winding;
unsigned int count;
unsigned int x;
#ifdef HLRAD_SubdividePatch_NOTMIDDLE
dplane_t plA_adjusted = *plA;
dplane_t plB_adjusted = *plB;
vec_t Amin, Amax, Bmin, Bmax;
vec_t Ashift, Ashiftmin, Ashiftmax;
vec_t Bshift, Bshiftmin, Bshiftmax;
Amin = Bmin = BOGUS_RANGE;
Amax = Bmax = -BOGUS_RANGE;
for (x = 0; x < patch->winding->m_NumPoints; x++)
{
vec_t A, B;
const vec3_t &p = patch->winding->m_Points[x];
A = DotProduct (plA->normal, p) - plA->dist;
B = DotProduct (plB->normal, p) - plB->dist;
if (A < Amin) Amin = A;
if (A > Amax) Amax = A;
if (B < Bmin) Bmin = B;
if (B > Bmax) Bmax = B;
}
Amin /= patch->chop;
Amax /= patch->chop;
Ashiftmin = Amax - floor (Amax - NORMAL_EPSILON);
Ashiftmax = Amin - floor (Amin + NORMAL_EPSILON);
Ashift = Ashiftmin <= Ashiftmax + NORMAL_EPSILON? (Ashiftmin + Ashiftmax) / 2: 0;
if (Ashift > 0.5) Ashift -= 1;
plA_adjusted.dist += Ashift * patch->chop;
Bmin /= patch->chop;
Bmax /= patch->chop;
Bshiftmin = Bmax - floor (Bmax - NORMAL_EPSILON);
Bshiftmax = Bmin - floor (Bmin + NORMAL_EPSILON);
Bshift = Bshiftmin <= Bshiftmax + NORMAL_EPSILON? (Bshiftmin + Bshiftmax) / 2: 0;
if (Bshift > 0.5) Bshift -= 1;
plB_adjusted.dist += Bshift * patch->chop;
#endif
g_numwindings = 0;
#ifdef HLRAD_SubdividePatch_NOTMIDDLE
if (CreateStrips(patch->winding, &plA_adjusted, patch->chop))
#else
if (CreateStrips(patch->winding, plA, patch->chop))
#endif
{
delete patch->winding;
patch->winding = NULL; // Invalidated by CreateStrips routine
}
count = g_numwindings;
for (x = 0, winding = windingArray; x < count; x++, winding++)
{
#ifdef HLRAD_SubdividePatch_NOTMIDDLE
if (CreateStrips(*winding, &plB_adjusted, patch->chop))
#else
if (CreateStrips(*winding, plB, patch->chop))
#endif
{
delete *winding;
*winding = NULL;
}
}
}
#endif
// =====================================================================================
// getGridPlanes
// From patch, determine perpindicular grid planes to subdivide with (returned in planeA and planeB)
// assume S and T is perpindicular (they SHOULD be in worldcraft 3.3 but aren't always . . .)
// =====================================================================================
static void getGridPlanes(const patch_t* const p, dplane_t* const pl)
{
const patch_t* patch = p;
dplane_t* planes = pl;
const dface_t* f = g_dfaces + patch->faceNumber;
texinfo_t* tx = &g_texinfo[f->texinfo];
dplane_t* plane = planes;
const dplane_t* faceplane = getPlaneFromFaceNumber(patch->faceNumber);
int x;
for (x = 0; x < 2; x++, plane++)
{
#ifdef ZHLT_FREETEXTUREAXIS
// cut the patch along texel grid planes
vec_t val;
val = DotProduct (faceplane->normal, tx->vecs[!x]);
VectorMA (tx->vecs[!x], -val, faceplane->normal, plane->normal);
#else
vec3_t a, b, c;
vec3_t delta1, delta2;
VectorCopy(patch->origin, a);
VectorAdd(patch->origin, faceplane->normal, b);
VectorAdd(patch->origin, tx->vecs[x], c);
VectorSubtract(b, a, delta1);
VectorSubtract(c, a, delta2);
CrossProduct(delta1, delta2, plane->normal);
#endif
VectorNormalize(plane->normal);
plane->dist = DotProduct(plane->normal, patch->origin);
}
}
// =====================================================================================
// SubdividePatch
// =====================================================================================
static void SubdividePatch(patch_t* patch)
{
dplane_t planes[2];
dplane_t* plA = &planes[0];
dplane_t* plB = &planes[1];
Winding** winding;
unsigned x;
patch_t* new_patch;
memset(windingArray, 0, sizeof(windingArray));
g_numwindings = 0;
getGridPlanes(patch, planes);
cutWindingWithGrid(patch, plA, plB);
x = 0;
patch->next = NULL;
winding = windingArray;
while (*winding == NULL)
{
winding++;
x++;
}
patch->winding = *winding;
winding++;
x++;
patch->area = patch->winding->getArea();
patch->winding->getCenter(patch->origin);
PlacePatchInside(patch);
#ifdef HLRAD_ACCURATEBOUNCE
UpdateEmitterInfo (patch);
#endif
new_patch = g_patches + g_num_patches;
for (; x < g_numwindings; x++, winding++)
{
if (*winding)
{
memcpy(new_patch, patch, sizeof(patch_t));
new_patch->winding = *winding;
new_patch->area = new_patch->winding->getArea();
new_patch->winding->getCenter(new_patch->origin);
PlacePatchInside(new_patch);
#ifdef HLRAD_ACCURATEBOUNCE
UpdateEmitterInfo (new_patch);
#endif
new_patch++;
g_num_patches++;
hlassume(g_num_patches < MAX_PATCHES, assume_MAX_PATCHES);
}
}
// ATTENTION: We let SortPatches relink all the ->next correctly! instead of doing it here too which is somewhat complicated
}
// =====================================================================================
// MakePatchForFace
static float totalarea = 0;
// =====================================================================================
#ifdef HLRAD_CUSTOMCHOP
vec_t *chopscales; //[nummiptex]
void ReadCustomChopValue()
{
int num;
int i, k;
entity_t *mapent;
epair_t *ep;
num = ((dmiptexlump_t *)g_dtexdata)->nummiptex;
chopscales = (vec_t *)malloc (num * sizeof(vec_t));
for (i = 0; i < num; i++)
{
chopscales[i] = 1.0;
}
for (k = 0; k < g_numentities; k++)
{
mapent = &g_entities[k];
if (strcmp(ValueForKey(mapent, "classname"), "info_chopscale"))
continue;
Developer (DEVELOPER_LEVEL_MESSAGE, "info_chopscale entity detected.\n");
for (i = 0; i < num; i++)
{
const char *texname = ((miptex_t*)(g_dtexdata+((dmiptexlump_t*)g_dtexdata)->dataofs[i]))->name;
for (ep = mapent->epairs; ep; ep = ep->next)
{
if (strcasecmp (ep->key, texname))
continue;
if (!strcasecmp (ep->key, "origin"))
continue;
if (atof (ep->value) <= 0)
continue;
chopscales[i] = atof (ep->value);
Developer (DEVELOPER_LEVEL_MESSAGE, "info_chopscale: %s = %f\n", texname, chopscales[i]);
}
}
}
}
vec_t ChopScaleForTexture (int facenum)
{
return chopscales[g_texinfo[g_dfaces[facenum].texinfo].miptex];
}
#endif
#ifdef HLRAD_CUSTOMSMOOTH
vec_t *g_smoothvalues; //[nummiptex]
void ReadCustomSmoothValue()
{
int num;
int i, k;
entity_t *mapent;
epair_t *ep;
num = ((dmiptexlump_t *)g_dtexdata)->nummiptex;
g_smoothvalues = (vec_t *)malloc (num * sizeof(vec_t));
for (i = 0; i < num; i++)
{
g_smoothvalues[i] = g_smoothing_threshold;
}
for (k = 0; k < g_numentities; k++)
{
mapent = &g_entities[k];
if (strcmp(ValueForKey(mapent, "classname"), "info_smoothvalue"))
continue;
Developer (DEVELOPER_LEVEL_MESSAGE, "info_smoothvalue entity detected.\n");
for (i = 0; i < num; i++)
{
const char *texname = ((miptex_t*)(g_dtexdata+((dmiptexlump_t*)g_dtexdata)->dataofs[i]))->name;
for (ep = mapent->epairs; ep; ep = ep->next)
{
if (strcasecmp (ep->key, texname))
continue;
if (!strcasecmp (ep->key, "origin"))
continue;
g_smoothvalues[i] = cos(atof (ep->value) * (Q_PI / 180.0));
Developer (DEVELOPER_LEVEL_MESSAGE, "info_smoothvalue: %s = %f\n", texname, atof (ep->value));
}
}
}
}
#endif
#ifdef HLRAD_TRANSLUCENT
void ReadTranslucentTextures()
{
int num;
int i, k;
entity_t *mapent;
epair_t *ep;
num = ((dmiptexlump_t *)g_dtexdata)->nummiptex;
g_translucenttextures = (vec3_t *)malloc (num * sizeof(vec3_t));
for (i = 0; i < num; i++)
{
VectorClear (g_translucenttextures[i]);
}
for (k = 0; k < g_numentities; k++)
{
mapent = &g_entities[k];
if (strcmp(ValueForKey(mapent, "classname"), "info_translucent"))
continue;
Developer (DEVELOPER_LEVEL_MESSAGE, "info_translucent entity detected.\n");
for (i = 0; i < num; i++)
{
const char *texname = ((miptex_t*)(g_dtexdata+((dmiptexlump_t*)g_dtexdata)->dataofs[i]))->name;
for (ep = mapent->epairs; ep; ep = ep->next)
{
if (strcasecmp (ep->key, texname))
continue;
if (!strcasecmp (ep->key, "origin"))
continue;
double r, g, b;
int count;
count = sscanf (ep->value, "%lf %lf %lf", &r, &g, &b);
if (count == 1)
{
g = b = r;
}
else if (count != 3)
{
Warning ("ignore bad translucent value '%s'", ep->value);
continue;
}
if (r < 0.0 || r > 1.0 || g < 0.0 || g > 1.0 || b < 0.0 || b > 1.0)
{
Warning ("translucent value should be 0.0-1.0");
continue;
}
g_translucenttextures[i][0] = r;
g_translucenttextures[i][1] = g;
g_translucenttextures[i][2] = b;
Developer (DEVELOPER_LEVEL_MESSAGE, "info_translucent: %s = %f %f %f\n", texname, r, g, b);
}
}
}
}
#endif
#ifdef HLRAD_DIVERSE_LIGHTING
vec3_t *g_lightingconeinfo;//[nummiptex]
static vec_t DefaultScaleForPower (vec_t power)
{
vec_t scale;
// scale = Pi / Integrate [2 Pi * Sin [x] * Cos[x] ^ power, {x, 0, Pi / 2}]
scale = (1 + power) / 2.0;
return scale;
}
void ReadLightingCone ()
{
int num;
int i, k;
entity_t *mapent;
epair_t *ep;
num = ((dmiptexlump_t *)g_dtexdata)->nummiptex;
g_lightingconeinfo = (vec3_t *)malloc (num * sizeof(vec3_t));
for (i = 0; i < num; i++)
{
g_lightingconeinfo[i][0] = 1.0; // default power
g_lightingconeinfo[i][1] = 1.0; // default scale
}
for (k = 0; k < g_numentities; k++)
{
mapent = &g_entities[k];
if (strcmp(ValueForKey(mapent, "classname"), "info_angularfade"))
continue;
Developer (DEVELOPER_LEVEL_MESSAGE, "info_angularfade entity detected.\n");
for (i = 0; i < num; i++)
{
const char *texname = ((miptex_t*)(g_dtexdata+((dmiptexlump_t*)g_dtexdata)->dataofs[i]))->name;
for (ep = mapent->epairs; ep; ep = ep->next)
{
if (strcasecmp (ep->key, texname))
continue;
if (!strcasecmp (ep->key, "origin"))
continue;
double power, scale;
int count;
count = sscanf (ep->value, "%lf %lf", &power, &scale);
if (count == 1)
{
scale = 1.0;
}
else if (count != 2)
{
Warning ("ignore bad angular fade value '%s'", ep->value);
continue;
}
if (power < 0.0 || scale < 0.0)
{
Warning ("ignore disallowed angular fade value '%s'", ep->value);
continue;
}
scale *= DefaultScaleForPower (power);
g_lightingconeinfo[i][0] = power;
g_lightingconeinfo[i][1] = scale;
Developer (DEVELOPER_LEVEL_MESSAGE, "info_angularfade: %s = %f %f\n", texname, power, scale);
}
}
}
}
#endif
static vec_t getScale(const patch_t* const patch)
{
dface_t* f = g_dfaces + patch->faceNumber;
texinfo_t* tx = &g_texinfo[f->texinfo];
if (g_texscale)
{
#ifdef ZHLT_FREETEXTUREAXIS
const dplane_t* faceplane = getPlaneFromFace (f);
vec3_t vecs_perpendicular[2];
vec_t scale[2];
vec_t dot;
// snap texture "vecs" to faceplane without affecting texture alignment
for (int x = 0; x < 2; x++)
{
dot = DotProduct (faceplane->normal, tx->vecs[x]);
VectorMA (tx->vecs[x], -dot, faceplane->normal, vecs_perpendicular[x]);
}
scale[0] = 1 / qmax (NORMAL_EPSILON, VectorLength (vecs_perpendicular[0]));
scale[1] = 1 / qmax (NORMAL_EPSILON, VectorLength (vecs_perpendicular[1]));
// don't care about the angle between vecs[0] and vecs[1] (given the length of "vecs", smaller angle = larger texel area), because gridplanes will have the same angle (also smaller angle = larger patch area)
return sqrt (scale[0] * scale[1]);
#else
vec_t scale[2];
scale[0] = 0.0;
scale[1] = 0.0;
scale[0] += tx->vecs[0][0] * tx->vecs[0][0];
scale[0] += tx->vecs[0][1] * tx->vecs[0][1];
scale[0] += tx->vecs[0][2] * tx->vecs[0][2];
scale[1] += tx->vecs[1][0] * tx->vecs[1][0];
scale[1] += tx->vecs[1][1] * tx->vecs[1][1];
scale[1] += tx->vecs[1][2] * tx->vecs[1][2];
scale[0] = sqrt(scale[0]);
scale[1] = sqrt(scale[1]);
return 2.0 / ((scale[0] + scale[1]));
#endif
}
else
{
return 1.0;
}
}
// =====================================================================================
// getChop
// =====================================================================================
#ifdef HLRAD_TEXLIGHTTHRESHOLD_FIX
static bool getEmitMode (const patch_t *patch)
{
bool emitmode = false;
vec_t value =
#ifdef HLRAD_REFLECTIVITY
DotProduct (patch->baselight, patch->texturereflectivity) / 3
#else
VectorAvg (patch->baselight)
#endif
;
#ifdef HLRAD_CUSTOMTEXLIGHT
if (g_face_texlights[patch->faceNumber])
{
if (*ValueForKey (g_face_texlights[patch->faceNumber], "_scale"))
{
value *= FloatForKey (g_face_texlights[patch->faceNumber], "_scale");
}
}
#endif
if (value > 0.0)
{
emitmode = true;
}
if (value < g_dlight_threshold)
{
emitmode = false;
}
#ifdef HLRAD_CUSTOMTEXLIGHT
if (g_face_texlights[patch->faceNumber])
{
switch (IntForKey (g_face_texlights[patch->faceNumber], "_fast"))
{
case 1:
emitmode = false;
break;
case 2:
emitmode = true;
break;
}
}
#endif
return emitmode;
}
#endif
static vec_t getChop(const patch_t* const patch)
{
vec_t rval;
#ifdef HLRAD_CUSTOMTEXLIGHT
if (g_face_texlights[patch->faceNumber])
{
if (*ValueForKey (g_face_texlights[patch->faceNumber], "_chop"))
{
rval = FloatForKey (g_face_texlights[patch->faceNumber], "_chop");
if (rval < 1.0)
{
rval = 1.0;
}
return rval;
}
}
#endif
#ifdef HLRAD_TEXLIGHTTHRESHOLD_FIX
if (!patch->emitmode)
#else
if (VectorCompare(patch->baselight, vec3_origin))
#endif
{
rval = g_chop * getScale(patch);
}
else
{
rval = g_texchop * getScale(patch);
#ifdef HLRAD_ACCURATEBOUNCE_TEXLIGHT
// we needn't do this now, so let's save our compile time.
#else
if (g_extra)
{
rval *= 0.5;
}
#endif
}
#ifdef HLRAD_CUSTOMCHOP
rval *= ChopScaleForTexture (patch->faceNumber);
#endif
return rval;
}
// =====================================================================================
// MakePatchForFace
// =====================================================================================
#ifdef ZHLT_TEXLIGHT
static void MakePatchForFace(const int fn, Winding* w, int style
#ifdef HLRAD_BOUNCE_STYLE
, int bouncestyle
#endif
) //LRC
#else
static void MakePatchForFace(const int fn, Winding* w
#ifdef HLRAD_BOUNCE_STYLE
, int bouncestyle
#endif
)
#endif
{
const dface_t* f = g_dfaces + fn;
// No g_patches at all for the sky!
if (!IsSpecial(f))
{
#ifdef HLRAD_CUSTOMTEXLIGHT
#ifdef ZHLT_TEXLIGHT
if (g_face_texlights[fn])
{
style = IntForKey (g_face_texlights[fn], "style");
#ifdef ZHLT_TEXLIGHT
if (style < 0)
style = -style;
#endif
#ifdef HLRAD_STYLE_CORING
style = (unsigned char)style;
if (style >= ALLSTYLES)
{
Error ("invalid light style: style (%d) >= ALLSTYLES (%d)", style, ALLSTYLES);
}
#endif
}
#endif
#endif
patch_t* patch;
vec3_t light;
vec3_t centroid = { 0, 0, 0 };
int numpoints = w->m_NumPoints;
if (numpoints < 3) // WTF! (Actually happens in real-world maps too)
{
Developer(DEVELOPER_LEVEL_WARNING, "Face %d only has %d points on winding\n", fn, numpoints);
return;
}
if (numpoints > MAX_POINTS_ON_WINDING)
{
Error("numpoints %d > MAX_POINTS_ON_WINDING", numpoints);
return;
}
patch = &g_patches[g_num_patches];
hlassume(g_num_patches < MAX_PATCHES, assume_MAX_PATCHES);
memset(patch, 0, sizeof(patch_t));
patch->winding = w;
patch->area = patch->winding->getArea();
patch->winding->getCenter(patch->origin);
patch->faceNumber = fn;
totalarea += patch->area;
#ifndef HLRAD_PATCHBLACK_FIX
PlacePatchInside(patch);
#ifdef HLRAD_ACCURATEBOUNCE
UpdateEmitterInfo (patch);
#endif
#endif
BaseLightForFace(f, light);
#ifdef ZHLT_TEXLIGHT
//LRC VectorCopy(light, patch->totallight);
#else
VectorCopy(light, patch->totallight);
#endif
VectorCopy(light, patch->baselight);
#ifdef ZHLT_TEXLIGHT
#ifdef HLRAD_AUTOCORING
patch->emitstyle = style;
#else
//LRC
int i;
patch->totalstyle[0] = 0;
for (i = 1; i < MAXLIGHTMAPS; i++)
{
patch->totalstyle[i] = 255;
}
if (style)
{
patch->emitstyle = patch->totalstyle[1] = style;
}
//LRC (ends)
#endif
#endif
#ifdef HLRAD_REFLECTIVITY
VectorCopy (g_textures[g_texinfo[f->texinfo].miptex].reflectivity, patch->texturereflectivity);
#ifdef HLRAD_CUSTOMTEXLIGHT_COLOR
if (g_face_texlights[fn] && *ValueForKey (g_face_texlights[fn], "_texcolor"))
{
vec3_t texturecolor;
vec3_t texturereflectivity;
GetVectorForKey (g_face_texlights[fn], "_texcolor", texturecolor);
for (int k = 0; k < 3; k++)
{
texturecolor[k] = floor (texturecolor[k] + 0.001);
}
if (VectorMinimum (texturecolor) < -0.001 || VectorMaximum (texturecolor) > 255.001)
{
vec3_t origin;
GetVectorForKey (g_face_texlights[fn], "origin", origin);
Error ("light_surface entity at (%g,%g,%g): texture color (%g,%g,%g) must be numbers between 0 and 255.", origin[0], origin[1], origin[2], texturecolor[0], texturecolor[1], texturecolor[2]);
}
VectorScale (texturecolor, 1.0 / 255.0, texturereflectivity);
for (int k = 0; k < 3; k++)
{
texturereflectivity[k] = pow (texturereflectivity[k], g_texreflectgamma);
}
VectorScale (texturereflectivity, g_texreflectscale, texturereflectivity);
if (VectorMaximum (texturereflectivity) > 1.0 + NORMAL_EPSILON)
{
Warning ("Texture '%s': reflectivity (%f,%f,%f) greater than 1.0.", g_textures[g_texinfo[f->texinfo].miptex].name, texturereflectivity[0], texturereflectivity[1], texturereflectivity[2]);
}
VectorCopy (texturereflectivity, patch->texturereflectivity);
}
#endif
{
vec_t opacity = 0.0;
if (g_face_entity[fn] - g_entities == 0)
{
opacity = 1.0;
}
else
{
int x;
for (x = 0; x < g_opaque_face_count; x++)
{
opaqueList_t *op = &g_opaque_face_list[x];
#ifdef HLRAD_OPAQUE_NODE
if (op->entitynum == g_face_entity[fn] - g_entities)
#else
if (op->facenum == fn)
#endif
{
opacity = 1.0;
#ifdef HLRAD_HULLU
if (op->transparency)
{
opacity = 1.0 - VectorAvg (op->transparency_scale);
opacity = opacity > 1.0? 1.0: opacity < 0.0? 0.0: opacity;
}
#endif
#ifdef HLRAD_BOUNCE_STYLE
if (op->style != -1)
{ // toggleable opaque entity
if (bouncestyle == -1)
{ // by default
opacity = 0.0; // doesn't reflect light
}
}
#endif
break;
}
}
#ifdef HLRAD_BOUNCE_STYLE
if (x == g_opaque_face_count)
{ // not opaque
if (bouncestyle != -1)
{ // with light_bounce
opacity = 1.0; // reflects light
}
}
#endif
}
#ifdef ZHLT_HIDDENSOUNDTEXTURE
// if the face is a world face and it's not referenced by any leaf, it must be a hidden face, and shouldn't reflect light
if (g_dmodels[0].firstface <= fn && fn < g_dmodels[0].firstface + g_dmodels[0].numfaces)
{
bool found = false;
for (int x = 0; x < g_nummarksurfaces; x++)
{
if (g_dmarksurfaces[x] == fn)
{
found = true;
break;
}
}
if (!found)
{
opacity = 0.0;
}
}
#endif
VectorScale (patch->texturereflectivity, opacity, patch->bouncereflectivity);
}
#ifdef HLRAD_BOUNCE_STYLE
patch->bouncestyle = bouncestyle;
if (bouncestyle == 0)
{ // there is an unnamed light_bounce
patch->bouncestyle = -1; // reflects light normally
}
#endif
#endif
#ifdef HLRAD_TEXLIGHTTHRESHOLD_FIX
patch->emitmode = getEmitMode (patch);
#endif
patch->scale = getScale(patch);
patch->chop = getChop(patch);
#ifdef HLRAD_TRANSLUCENT
VectorCopy (g_translucenttextures[g_texinfo[f->texinfo].miptex], patch->translucent_v);
patch->translucent_b = !VectorCompare (patch->translucent_v, vec3_origin);
#endif
#ifdef HLRAD_PATCHBLACK_FIX
PlacePatchInside(patch);
#ifdef HLRAD_ACCURATEBOUNCE
UpdateEmitterInfo (patch);
#endif
#endif
g_face_patches[fn] = patch;
g_num_patches++;
// Per-face data
{
int j;
// Centroid of face for nudging samples in direct lighting pass
for (j = 0; j < f->numedges; j++)
{
int edge = g_dsurfedges[f->firstedge + j];
if (edge > 0)
{
VectorAdd(g_dvertexes[g_dedges[edge].v[0]].point, centroid, centroid);
VectorAdd(g_dvertexes[g_dedges[edge].v[1]].point, centroid, centroid);
}
else
{
VectorAdd(g_dvertexes[g_dedges[-edge].v[1]].point, centroid, centroid);
VectorAdd(g_dvertexes[g_dedges[-edge].v[0]].point, centroid, centroid);
}
}
// Fixup centroid for anything with an altered origin (rotating models/turrets mostly)
// Save them for moving direct lighting points towards the face center
VectorScale(centroid, 1.0 / (f->numedges * 2), centroid);
VectorAdd(centroid, g_face_offset[fn], g_face_centroids[fn]);
}
{
vec3_t mins;
vec3_t maxs;
patch->winding->getBounds(mins, maxs);
if (g_subdivide)
{
vec_t amt;
vec_t length;
vec3_t delta;
VectorSubtract(maxs, mins, delta);
length = VectorLength(delta);
#ifdef HLRAD_CHOP_FIX
amt = patch->chop;
#else // loss patches on faces where texture scale < 1 and range < g_chop
if (VectorCompare(patch->baselight, vec3_origin))
{
amt = g_chop;
}
else
{
amt = g_texchop;
}
#endif
if (length > amt)
{
if (patch->area < 1.0)
{
Developer(DEVELOPER_LEVEL_WARNING,
"Patch at (%4.3f %4.3f %4.3f) (face %d) tiny area (%4.3f) not subdividing \n",
patch->origin[0], patch->origin[1], patch->origin[2], patch->faceNumber, patch->area);
}
else
{
SubdividePatch(patch);
}
}
}
}
}
}
// =====================================================================================
// AddFaceToOpaqueList
// =====================================================================================
static void AddFaceToOpaqueList(
#ifdef HLRAD_OPAQUE_NODE
int entitynum, int modelnum, const vec3_t origin
#else
const unsigned facenum, const Winding* const winding
#endif
#ifdef HLRAD_HULLU
, const vec3_t &transparency_scale, const bool transparency
#endif
#ifndef HLRAD_OPAQUE_NODE
#ifdef HLRAD_OPAQUE_GROUP
, const dmodel_t* mod
#endif
#endif
#ifdef HLRAD_OPAQUE_STYLE
, int style
#endif
#ifdef HLRAD_OPAQUE_BLOCK
, bool block
#endif
)
{
if (g_opaque_face_count == g_max_opaque_face_count)
{
g_max_opaque_face_count += OPAQUE_ARRAY_GROWTH_SIZE;
g_opaque_face_list = (opaqueList_t*)realloc(g_opaque_face_list, sizeof(opaqueList_t) * g_max_opaque_face_count);
#ifdef HLRAD_HLASSUMENOMEMORY
hlassume (g_opaque_face_list != NULL, assume_NoMemory);
#endif
}
{
opaqueList_t* opaque = &g_opaque_face_list[g_opaque_face_count];
g_opaque_face_count++;
#ifdef HLRAD_OPAQUE_STYLE
if (transparency && style != -1)
{
Warning ("Dynamic shadow is not allowed in entity with custom shadow.\n");
style = -1;
}
#endif
#ifdef HLRAD_HULLU
VectorCopy(transparency_scale, opaque->transparency_scale);
opaque->transparency = transparency;
#endif
#ifdef HLRAD_OPAQUE_NODE
opaque->entitynum = entitynum;
opaque->modelnum = modelnum;
VectorCopy (origin, opaque->origin);
#else
opaque->facenum = facenum;
getAdjustedPlaneFromFaceNumber(facenum, &opaque->plane);
opaque->winding = new Winding(*winding);
#endif
#ifndef HLRAD_OPAQUE_NODE
#ifdef HLRAD_OPAQUE_GROUP
{
int ig;
for (ig=0; ig<g_opaque_group_count; ++ig)
if (mod==g_opaque_group_list[ig].mod)
break;
if (ig==g_opaque_group_count) //new opaque group
{
if (g_opaque_group_count>=MAX_OPAQUE_GROUP_COUNT)
Error ("too many opaque models");
g_opaque_group_list[ig].mod=mod;
#ifdef HLRAD_OPAQUE_RANGE
for (int i=0; i<3; ++i)
{
g_opaque_group_list[ig].mins[i]=mod->mins[i]+g_face_offset[facenum][i]-1;
g_opaque_group_list[ig].maxs[i]=mod->maxs[i]+g_face_offset[facenum][i]+1;
}
#endif
g_opaque_group_count++;
}
opaque->groupnum=ig;
}
#endif
#endif
#ifdef HLRAD_OPAQUE_STYLE
opaque->style = style;
#endif
#ifdef HLRAD_OPAQUE_BLOCK
opaque->block = block;
#endif
}
}
// =====================================================================================
// FreeOpaqueFaceList
// =====================================================================================
static void FreeOpaqueFaceList()
{
unsigned x;
opaqueList_t* opaque = g_opaque_face_list;
for (x = 0; x < g_opaque_face_count; x++, opaque++)
{
#ifndef HLRAD_OPAQUE_NODE
delete opaque->winding;
opaque->winding = NULL;
#endif
}
free(g_opaque_face_list);
g_opaque_face_list = NULL;
g_opaque_face_count = 0;
g_max_opaque_face_count = 0;
}
#ifdef HLRAD_OPAQUE_NODE
static void LoadOpaqueEntities()
{
int modelnum, entnum;
for (modelnum = 0; modelnum < g_nummodels; modelnum++)
{
dmodel_t *model = &g_dmodels[modelnum];
char stringmodel[16];
sprintf (stringmodel, "*%i", modelnum);
for (entnum = 0; entnum < g_numentities; entnum++)
{
entity_t *ent = &g_entities[entnum];
if (strcmp (ValueForKey (ent, "model"), stringmodel))
continue;
vec3_t origin;
{
GetVectorForKey (ent, "origin", origin);
if (*ValueForKey (ent, "light_origin") && *ValueForKey (ent, "model_center"))
{
entity_t *ent2 = FindTargetEntity (ValueForKey (ent, "light_origin"));
if (ent2)
{
vec3_t light_origin, model_center;
GetVectorForKey (ent2, "origin", light_origin);
GetVectorForKey (ent, "model_center", model_center);
VectorSubtract (light_origin, model_center, origin);
}
}
}
bool opaque = false;
{
if (g_allow_opaques && (IntForKey (ent, "zhlt_lightflags") & eModelLightmodeOpaque))
opaque = true;
}
#ifdef HLRAD_HULLU
vec3_t d_transparency;
VectorFill (d_transparency, 0.0);
bool b_transparency = false;
{
const char *s;
if (*(s = ValueForKey(ent, "zhlt_customshadow")))
{
double r1 = 1.0, g1 = 1.0, b1 = 1.0, tmp = 1.0;
if (sscanf(s, "%lf %lf %lf", &r1, &g1, &b1) == 3) //RGB version
{
if(r1<0.0) r1 = 0.0;
if(g1<0.0) g1 = 0.0;
if(b1<0.0) b1 = 0.0;
d_transparency[0] = r1;
d_transparency[1] = g1;
d_transparency[2] = b1;
}
else if (sscanf(s, "%lf", &tmp) == 1) //Greyscale version
{
if(tmp<0.0) tmp = 0.0;
VectorFill(d_transparency, tmp);
}
}
if (!VectorCompare (d_transparency, vec3_origin))
b_transparency = true;
}
#endif
#ifdef HLRAD_OPAQUE_STYLE
int opaquestyle = -1;
{
int j;
for (j = 0; j < g_numentities; j++)
{
entity_t *lightent = &g_entities[j];
if (!strcmp (ValueForKey (lightent, "classname"), "light_shadow")
&& *ValueForKey (lightent, "target")
&& !strcmp (ValueForKey (lightent, "target"), ValueForKey (ent, "targetname")))
{
opaquestyle = IntForKey (lightent, "style");
#ifdef ZHLT_TEXLIGHT
if (opaquestyle < 0)
opaquestyle = -opaquestyle;
#endif
#ifdef HLRAD_STYLE_CORING
opaquestyle = (unsigned char)opaquestyle;
if (opaquestyle >= ALLSTYLES)
{
Error ("invalid light style: style (%d) >= ALLSTYLES (%d)", opaquestyle, ALLSTYLES);
}
#endif
break;
}
}
}
#endif
#ifdef HLRAD_OPAQUE_BLOCK
bool block = false;
{
if (g_blockopaque)
{
block = true;
if (IntForKey (ent, "zhlt_lightflags") & eModelLightmodeNonsolid)
block = false;
if (b_transparency)
block = false;
#ifdef HLRAD_OPAQUE_STYLE
if (opaquestyle != -1)
block = false;
#endif
}
}
#endif
if (opaque)
{
AddFaceToOpaqueList (entnum, modelnum, origin
#ifdef HLRAD_HULLU
, d_transparency, b_transparency
#endif
#ifdef HLRAD_OPAQUE_STYLE
, opaquestyle
#endif
#ifdef HLRAD_OPAQUE_BLOCK
, block
#endif
);
}
}
}
{
Log("%i opaque models\n", g_opaque_face_count);
int i, facecount;
for (facecount = 0, i = 0; i < g_opaque_face_count; i++)
{
facecount += CountOpaqueFaces (g_opaque_face_list[i].modelnum);
}
Log("%i opaque faces\n", facecount);
}
}
#endif
// =====================================================================================
// MakePatches
// =====================================================================================
#ifdef HLRAD_CUSTOMTEXLIGHT
static entity_t *FindTexlightEntity (int facenum)
{
dface_t *face = &g_dfaces[facenum];
const dplane_t *dplane = getPlaneFromFace (face);
const char *texname = GetTextureByNumber (face->texinfo);
entity_t *faceent = g_face_entity[facenum];
vec3_t centroid;
Winding *w = new Winding (*face);
w->getCenter (centroid);
delete w;
VectorAdd (centroid, g_face_offset[facenum], centroid);
entity_t *found = NULL;
vec_t bestdist = -1;
for (int i = 0; i < g_numentities; i++)
{
entity_t *ent = &g_entities[i];
if (strcmp (ValueForKey (ent, "classname"), "light_surface"))
continue;
if (strcasecmp (ValueForKey (ent, "_tex"), texname))
continue;
vec3_t delta;
GetVectorForKey (ent, "origin", delta);
VectorSubtract (delta, centroid, delta);
vec_t dist = VectorLength (delta);
if (*ValueForKey (ent, "_frange"))
{
if (dist > FloatForKey (ent, "_frange"))
continue;
}
if (*ValueForKey (ent, "_fdist"))
{
if (fabs (DotProduct (delta, dplane->normal)) > FloatForKey (ent, "_fdist"))
continue;
}
if (*ValueForKey (ent, "_fclass"))
{
if (strcmp (ValueForKey (faceent, "classname"), ValueForKey (ent, "_fclass")))
continue;
}
if (*ValueForKey (ent, "_fname"))
{
if (strcmp (ValueForKey (faceent, "targetname"), ValueForKey (ent, "_fname")))
continue;
}
if (bestdist >= 0 && dist > bestdist)
continue;
found = ent;
bestdist = dist;
}
return found;
}
#endif
static void MakePatches()
{
int i;
int j;
unsigned int k;
dface_t* f;
int fn;
Winding* w;
dmodel_t* mod;
vec3_t origin;
entity_t* ent;
const char* s;
vec3_t light_origin;
vec3_t model_center;
bool b_light_origin;
bool b_model_center;
eModelLightmodes lightmode;
#ifdef ZHLT_TEXLIGHT
int style; //LRC
#endif
#ifndef HLRAD_OPAQUE_NODE
#ifdef HLRAD_HULLU
vec3_t d_transparency;
bool b_transparency;
#endif
#endif
Log("%i faces\n", g_numfaces);
Log("Create Patches : ");
#ifdef HLRAD_MORE_PATCHES
g_patches = (patch_t *)AllocBlock (MAX_PATCHES * sizeof (patch_t));
#endif
for (i = 0; i < g_nummodels; i++)
{
b_light_origin = false;
b_model_center = false;
lightmode = eModelLightmodeNull;
#ifndef HLRAD_OPAQUE_NODE
#ifdef HLRAD_OPACITY // AJM
float l_opacity = 0.0f; // decimal percentage
#endif
#endif
mod = g_dmodels + i;
ent = EntityForModel(i);
VectorCopy(vec3_origin, origin);
if (*(s = ValueForKey(ent, "zhlt_lightflags")))
{
lightmode = (eModelLightmodes)atoi(s);
}
// models with origin brushes need to be offset into their in-use position
if (*(s = ValueForKey(ent, "origin")))
{
double v1, v2, v3;
if (sscanf(s, "%lf %lf %lf", &v1, &v2, &v3) == 3)
{
origin[0] = v1;
origin[1] = v2;
origin[2] = v3;
}
}
// Allow models to be lit in an alternate location (pt1)
if (*(s = ValueForKey(ent, "light_origin")))
{
entity_t* e = FindTargetEntity(s);
if (e)
{
if (*(s = ValueForKey(e, "origin")))
{
double v1, v2, v3;
if (sscanf(s, "%lf %lf %lf", &v1, &v2, &v3) == 3)
{
light_origin[0] = v1;
light_origin[1] = v2;
light_origin[2] = v3;
b_light_origin = true;
}
}
}
}
// Allow models to be lit in an alternate location (pt2)
if (*(s = ValueForKey(ent, "model_center")))
{
double v1, v2, v3;
if (sscanf(s, "%lf %lf %lf", &v1, &v2, &v3) == 3)
{
model_center[0] = v1;
model_center[1] = v2;
model_center[2] = v3;
b_model_center = true;
}
}
#ifndef HLRAD_OPAQUE_NODE
#ifdef HLRAD_HULLU
// Check for colored transparency/custom shadows
VectorFill(d_transparency, 1.0);
b_transparency = false;
if (*(s = ValueForKey(ent, "zhlt_customshadow")))
{
double r1 = 1.0, g1 = 1.0, b1 = 1.0, tmp = 1.0;
if (sscanf(s, "%lf %lf %lf", &r1, &g1, &b1) == 3) //RGB version
{
if(r1<0.0) r1 = 0.0;
if(g1<0.0) g1 = 0.0;
if(b1<0.0) b1 = 0.0;
d_transparency[0] = r1;
d_transparency[1] = g1;
d_transparency[2] = b1;
b_transparency = true;
}
else if (sscanf(s, "%lf", &tmp) == 1) //Greyscale version
{
if(tmp<0.0) tmp = 0.0;
VectorFill(d_transparency, tmp);
b_transparency = true;
}
}
#endif
#endif
// Allow models to be lit in an alternate location (pt3)
if (b_light_origin && b_model_center)
{
VectorSubtract(light_origin, model_center, origin);
}
#ifdef ZHLT_TEXLIGHT
//LRC:
if (*(s = ValueForKey(ent, "style")))
{
style = atoi(s);
if (style < 0)
style = -style;
}
else
{
style = 0;
}
//LRC (ends)
#ifdef HLRAD_STYLE_CORING
style = (unsigned char)style;
if (style >= ALLSTYLES)
{
Error ("invalid light style: style (%d) >= ALLSTYLES (%d)", style, ALLSTYLES);
}
#endif
#endif
#ifndef HLRAD_OPAQUE_NODE
#ifdef HLRAD_OPAQUE_STYLE
int opaquestyle = -1;
for (j = 0; j < g_numentities; j++)
{
entity_t *lightent = &g_entities[j];
if (!strcmp (ValueForKey (lightent, "classname"), "light_shadow")
&& *ValueForKey (lightent, "target")
&& !strcmp (ValueForKey (lightent, "target"), ValueForKey (ent, "targetname")))
{
opaquestyle = IntForKey (lightent, "style");
#ifdef ZHLT_TEXLIGHT
if (opaquestyle < 0)
opaquestyle = -opaquestyle;
#endif
#ifdef HLRAD_STYLE_CORING
opaquestyle = (unsigned char)opaquestyle;
if (opaquestyle >= ALLSTYLES)
{
Error ("invalid light style: style (%d) >= ALLSTYLES (%d)", opaquestyle, ALLSTYLES);
}
#endif
break;
}
}
#endif
#endif
#ifdef HLRAD_BOUNCE_STYLE
int bouncestyle = -1;
{
int j;
for (j = 0; j < g_numentities; j++)
{
entity_t *lightent = &g_entities[j];
if (!strcmp (ValueForKey (lightent, "classname"), "light_bounce")
&& *ValueForKey (lightent, "target")
&& !strcmp (ValueForKey (lightent, "target"), ValueForKey (ent, "targetname")))
{
bouncestyle = IntForKey (lightent, "style");
#ifdef ZHLT_TEXLIGHT
if (bouncestyle < 0)
bouncestyle = -bouncestyle;
#endif
#ifdef HLRAD_STYLE_CORING
bouncestyle = (unsigned char)bouncestyle;
if (bouncestyle >= ALLSTYLES)
{
Error ("invalid light style: style (%d) >= ALLSTYLES (%d)", bouncestyle, ALLSTYLES);
}
#endif
break;
}
}
}
#endif
for (j = 0; j < mod->numfaces; j++)
{
fn = mod->firstface + j;
g_face_entity[fn] = ent;
VectorCopy(origin, g_face_offset[fn]);
#ifdef HLRAD_CUSTOMTEXLIGHT
g_face_texlights[fn] = FindTexlightEntity (fn);
#endif
g_face_lightmode[fn] = lightmode;
f = g_dfaces + fn;
w = new Winding(*f);
for (k = 0; k < w->m_NumPoints; k++)
{
VectorAdd(w->m_Points[k], origin, w->m_Points[k]);
}
#ifndef HLRAD_OPAQUE_NODE
if (g_allow_opaques)
{
if (lightmode & eModelLightmodeOpaque)
{
AddFaceToOpaqueList(fn, w
#ifdef HLRAD_HULLU
, d_transparency, b_transparency
#endif
#ifdef HLRAD_OPAQUE_GROUP
, mod
#endif
#ifdef HLRAD_OPAQUE_STYLE
, opaquestyle
#endif
);
}
}
#endif
#ifdef ZHLT_TEXLIGHT
MakePatchForFace(fn, w, style
#ifdef HLRAD_BOUNCE_STYLE
, bouncestyle
#endif
); //LRC
#else
MakePatchForFace(fn, w
#ifdef HLRAD_BOUNCE_STYLE
, bouncestyle
#endif
);
#endif
}
}
Log("%i base patches\n", g_num_patches);
#ifndef HLRAD_OPAQUE_NODE
#ifdef HLRAD_OPAQUE_GROUP
Log("%i opaque models\n", g_opaque_group_count);
#endif
Log("%i opaque faces\n", g_opaque_face_count);
#endif
Log("%i square feet [%.2f square inches]\n", (int)(totalarea / 144), totalarea);
}
// =====================================================================================
// patch_sorter
// =====================================================================================
static int CDECL patch_sorter(const void* p1, const void* p2)
{
patch_t* patch1 = (patch_t*)p1;
patch_t* patch2 = (patch_t*)p2;
if (patch1->faceNumber < patch2->faceNumber)
{
return -1;
}
else if (patch1->faceNumber > patch2->faceNumber)
{
return 1;
}
else
{
return 0;
}
}
// =====================================================================================
// patch_sorter
// This sorts the patches by facenumber, which makes their runs compress even better
// =====================================================================================
static void SortPatches()
{
#ifdef HLRAD_MORE_PATCHES
// SortPatches is the ideal place to do this, because the address of the patches are going to be invalidated.
patch_t *old_patches = g_patches;
g_patches = (patch_t *)AllocBlock ((g_num_patches + 1) * sizeof (patch_t)); // allocate one extra slot considering how terribly the code were written
memcpy (g_patches, old_patches, g_num_patches * sizeof (patch_t));
FreeBlock (old_patches);
#endif
qsort((void*)g_patches, (size_t) g_num_patches, sizeof(patch_t), patch_sorter);
// Fixup g_face_patches & Fixup patch->next
memset(g_face_patches, 0, sizeof(g_face_patches));
{
unsigned x;
patch_t* patch = g_patches + 1;
patch_t* prev = g_patches;
#ifdef HLRAD_SortPatches_FIX
g_face_patches[prev->faceNumber] = prev;
#else
g_face_patches[0] = g_patches;
#endif
for (x = 1; x < g_num_patches; x++, patch++)
{
if (patch->faceNumber != prev->faceNumber)
{
prev->next = NULL;
g_face_patches[patch->faceNumber] = patch;
}
else
{
prev->next = patch;
}
prev = patch;
}
}
#ifdef HLRAD_ENTITYBOUNCE_FIX
for (unsigned x = 0; x < g_num_patches; x++)
{
patch_t *patch = &g_patches[x];
patch->leafnum = PointInLeaf (patch->origin) - g_dleafs;
}
#endif
}
// =====================================================================================
// FreePatches
// =====================================================================================
static void FreePatches()
{
unsigned x;
patch_t* patch = g_patches;
// AJM EX
//Log("patches: %i of %i (%2.2lf percent)\n", g_num_patches, MAX_PATCHES, (double)((double)g_num_patches / (double)MAX_PATCHES));
for (x = 0; x < g_num_patches; x++, patch++)
{
delete patch->winding;
}
memset(g_patches, 0, sizeof(patch_t) * g_num_patches);
#ifdef HLRAD_MORE_PATCHES
FreeBlock (g_patches);
g_patches = NULL;
#endif
}
//=====================================================================
// =====================================================================================
// WriteWorld
// =====================================================================================
static void WriteWorld(const char* const name)
{
unsigned i;
unsigned j;
FILE* out;
patch_t* patch;
Winding* w;
out = fopen(name, "w");
if (!out)
Error("Couldn't open %s", name);
for (j = 0, patch = g_patches; j < g_num_patches; j++, patch++)
{
w = patch->winding;
Log("%i\n", w->m_NumPoints);
for (i = 0; i < w->m_NumPoints; i++)
{
#ifdef ZHLT_TEXLIGHT
Log("%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
w->m_Points[i][0],
w->m_Points[i][1],
w->m_Points[i][2], patch->totallight[0][0] / 256, patch->totallight[0][1] / 256, patch->totallight[0][2] / 256); //LRC
#else
Log("%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
w->m_Points[i][0],
w->m_Points[i][1],
w->m_Points[i][2], patch->totallight[0] / 256, patch->totallight[1] / 256, patch->totallight[2] / 256);
#endif
}
Log("\n");
}
fclose(out);
}
// =====================================================================================
// CollectLight
// =====================================================================================
static void CollectLight()
{
#ifdef ZHLT_TEXLIGHT
unsigned j; //LRC
#endif
unsigned i;
patch_t* patch;
for (i = 0, patch = g_patches; i < g_num_patches; i++, patch++)
{
#ifdef HLRAD_AUTOCORING
vec3_t newtotallight[MAXLIGHTMAPS];
#ifdef ZHLT_XASH
vec3_t newtotallight_direction[MAXLIGHTMAPS];
#endif
for (j = 0; j < MAXLIGHTMAPS && newstyles[i][j] != 255; j++)
{
VectorClear (newtotallight[j]);
#ifdef ZHLT_XASH
VectorClear (newtotallight_direction[j]);
#endif
int k;
for (k = 0; k < MAXLIGHTMAPS && patch->totalstyle[k] != 255; k++)
{
if (patch->totalstyle[k] == newstyles[i][j])
{
VectorCopy (patch->totallight[k], newtotallight[j]);
#ifdef ZHLT_XASH
VectorCopy (patch->totallight_direction[k], newtotallight_direction[k]);
#endif
break;
}
}
}
for (j = 0; j < MAXLIGHTMAPS; j++)
{
if (newstyles[i][j] != 255)
{
patch->totalstyle[j] = newstyles[i][j];
VectorCopy (newtotallight[j], patch->totallight[j]);
VectorCopy (addlight[i][j], emitlight[i][j]);
#ifdef ZHLT_XASH
VectorCopy (newtotallight_direction[j], patch->totallight_direction[j]);
VectorCopy (addlight_direction[i][j], emitlight_direction[i][j]);
#endif
}
else
{
patch->totalstyle[j] = 255;
}
}
#else
#ifdef ZHLT_TEXLIGHT
//LRC
for (j = 0; j < MAXLIGHTMAPS && patch->totalstyle[j] != 255; j++)
{
VectorAdd(patch->totallight[j], addlight[i][j], patch->totallight[j]);
#ifdef HLRAD_TRANSFERDATA_COMPRESS
VectorCopy(addlight[i][j], emitlight[i][j]);
#else
VectorScale(addlight[i][j], TRANSFER_SCALE, emitlight[i][j]);
#endif
VectorClear(addlight[i][j]);
}
#else
VectorAdd(patch->totallight, addlight[i], patch->totallight);
#ifdef HLRAD_TRANSFERDATA_COMPRESS
VectorCopy(addlight[i], emitlight[i]);
#else
VectorScale(addlight[i], TRANSFER_SCALE, emitlight[i]);
#endif
VectorClear(addlight[i]);
#endif
#endif
}
}
// =====================================================================================
// GatherLight
// Get light from other g_patches
// Run multi-threaded
// =====================================================================================
#ifdef SYSTEM_WIN32
#pragma warning(push)
#pragma warning(disable: 4100) // unreferenced formal parameter
#endif
static void GatherLight(int threadnum)
{
int j;
patch_t* patch;
#ifdef ZHLT_TEXLIGHT
unsigned k,m; //LRC
//LRC vec3_t sum;
#else
unsigned k;
vec3_t sum;
#endif
unsigned iIndex;
transfer_data_t* tData;
transfer_index_t* tIndex;
#ifdef HLRAD_TRANSFERDATA_COMPRESS
float f;
#endif
#ifdef HLRAD_STYLE_CORING
#ifdef ZHLT_TEXLIGHT
#ifndef HLRAD_AUTOCORING
int style_index;
#endif
vec3_t adds[ALLSTYLES];
#ifdef ZHLT_XASH
vec3_t adds_direction[ALLSTYLES];
#endif
int style;
#endif
#endif
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
unsigned int fastfind_index = 0;
#endif
while (1)
{
j = GetThreadWork();
if (j == -1)
{
break;
}
#ifdef HLRAD_STYLE_CORING
#ifdef ZHLT_TEXLIGHT
memset (adds, 0, ALLSTYLES * sizeof(vec3_t));
#ifdef ZHLT_XASH
memset (adds_direction, 0, ALLSTYLES * sizeof (vec3_t));
#endif
#endif
#endif
patch = &g_patches[j];
tData = patch->tData;
tIndex = patch->tIndex;
iIndex = patch->iIndex;
#ifdef ZHLT_TEXLIGHT
#ifndef HLRAD_AUTOCORING
//LRC
for (m = 0; m < MAXLIGHTMAPS && patch->totalstyle[m] != 255; m++)
{
VectorClear(addlight[j][m]);
}
#endif
#else
VectorClear(sum);
#endif
#ifdef HLRAD_AUTOCORING
for (m = 0; m < MAXLIGHTMAPS && patch->totalstyle[m] != 255; m++)
{
VectorAdd (adds[patch->totalstyle[m]], patch->totallight[m], adds[patch->totalstyle[m]]);
#ifdef ZHLT_XASH
VectorAdd (adds_direction[patch->totalstyle[m]], patch->totallight_direction[m], adds_direction[patch->totalstyle[m]]);
#endif
}
#endif
#ifdef ZHLT_XASH
#ifdef HLRAD_TRANSLUCENT
const vec3_t &patchnormal = getPlaneFromFaceNumber (patch->faceNumber)->normal;
#endif
#endif
for (k = 0; k < iIndex; k++, tIndex++)
{
unsigned l;
unsigned size = (tIndex->size + 1);
unsigned patchnum = tIndex->index;
#ifdef HLRAD_TRANSFERDATA_COMPRESS
for (l = 0; l < size; l++, tData+=float_size[g_transfer_compress_type], patchnum++)
#else
for (l = 0; l < size; l++, tData++, patchnum++)
#endif
{
vec3_t v;
#ifdef ZHLT_TEXLIGHT
//LRC:
patch_t* emitpatch = &g_patches[patchnum];
unsigned emitstyle;
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
int opaquestyle = -1;
GetStyle (j, patchnum, opaquestyle, fastfind_index);
#endif
#ifdef HLRAD_TRANSFERDATA_COMPRESS
float_decompress (g_transfer_compress_type, tData, &f);
#endif
#ifdef ZHLT_XASH
vec3_t direction;
VectorSubtract (patch->origin, emitpatch->origin, direction);
VectorNormalize (direction);
#ifdef HLRAD_TRANSLUCENT
vec_t dot = DotProduct (direction, patchnormal);
if (dot > 0)
{
// reflect the direction back
VectorMA (direction, -dot * 2, patchnormal, direction);
}
#endif
#endif
// for each style on the emitting patch
#ifdef HLRAD_AUTOCORING
for (emitstyle = 0; emitstyle < MAXLIGHTMAPS && emitpatch->directstyle[emitstyle] != 255; emitstyle++)
{
#ifdef HLRAD_TRANSFERDATA_COMPRESS
VectorScale(emitpatch->directlight[emitstyle], f, v);
#else
VectorScale(emitpatch->directlight[emitstyle], (*tData) * TRANSFER_SCALE, v);
#endif
#ifdef HLRAD_REFLECTIVITY
VectorMultiply(v, emitpatch->bouncereflectivity, v);
#endif
if (isPointFinite (v))
{
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
int addstyle = emitpatch->directstyle[emitstyle];
#ifdef HLRAD_BOUNCE_STYLE
if (emitpatch->bouncestyle != -1)
{
if (addstyle == 0 || addstyle == emitpatch->bouncestyle)
addstyle = emitpatch->bouncestyle;
else
continue;
}
#endif
if (opaquestyle != -1)
{
if (addstyle == 0 || addstyle == opaquestyle)
addstyle = opaquestyle;
else
continue;
}
VectorAdd(adds[addstyle], v, adds[addstyle]);
#ifdef ZHLT_XASH
vec_t brightness = VectorAvg (v);
VectorMA (adds_direction[addstyle], brightness, direction, adds_direction[addstyle]);
#endif
#else
VectorAdd(adds[emitpatch->directstyle[emitstyle]], v, adds[emitpatch->directstyle[emitstyle]]);
#ifdef ZHLT_XASH
vec_t brightness = VectorAvg (v);
VectorMA (adds_direction[emitpatch->directstyle[emitstyle]], brightness, direction, adds_direction[emitpatch->directstyle[emitstyle]]);
#endif
#endif
}
}
#endif
for (emitstyle = 0; emitstyle < MAXLIGHTMAPS && emitpatch->totalstyle[emitstyle] != 255; emitstyle++)
{
#ifdef HLRAD_STYLE_CORING
#ifdef HLRAD_TRANSFERDATA_COMPRESS
VectorScale(emitlight[patchnum][emitstyle], f, v);
#else
#ifdef HLRAD_AUTOCORING
VectorScale(emitlight[patchnum][emitstyle], (*tData) * TRANSFER_SCALE, v);
#else
VectorScale(emitlight[patchnum][emitstyle], (*tData), v);
#endif
#endif
#ifdef HLRAD_REFLECTIVITY
VectorMultiply(v, emitpatch->bouncereflectivity, v);
#endif
if (isPointFinite(v))
{
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
int addstyle = emitpatch->totalstyle[emitstyle];
#ifdef HLRAD_BOUNCE_STYLE
if (emitpatch->bouncestyle != -1)
{
if (addstyle == 0 || addstyle == emitpatch->bouncestyle)
addstyle = emitpatch->bouncestyle;
else
continue;
}
#endif
if (opaquestyle != -1)
{
if (addstyle == 0 || addstyle == opaquestyle)
addstyle = opaquestyle;
else
continue;
}
VectorAdd(adds[addstyle], v, adds[addstyle]);
#ifdef ZHLT_XASH
vec_t brightness = VectorAvg (v);
VectorMA (adds_direction[addstyle], brightness, direction, adds_direction[addstyle]);
#endif
#else
VectorAdd(adds[emitpatch->totalstyle[emitstyle]], v, adds[emitpatch->totalstyle[emitstyle]]);
#ifdef ZHLT_XASH
vec_t brightness = VectorAvg (v);
VectorMA (adds_direction[emitpatch->totalstyle[emitstyle]], brightness, direction, adds_direction[emitpatch->totalstyle[emitstyle]]);
#endif
#endif
}
else
{
Verbose("GatherLight, v (%4.3f %4.3f %4.3f)@(%4.3f %4.3f %4.3f)\n",
v[0], v[1], v[2], patch->origin[0], patch->origin[1], patch->origin[2]);
}
#else
// find the matching style on this (destination) patch
for (m = 0; m < MAXLIGHTMAPS && patch->totalstyle[m] != 255; m++)
{
if (patch->totalstyle[m] == emitpatch->totalstyle[emitstyle])
{
break;
}
}
if (m == MAXLIGHTMAPS)
{
#ifdef HLRAD_READABLE_EXCEEDSTYLEWARNING
if (++stylewarningcount >= stylewarningnext)
{
stylewarningnext = stylewarningcount * 2;
Warning("Too many direct light styles on a face(?,?,?)");
Warning(" total %d warnings for too many styles", stylewarningcount);
}
#else
Warning("Too many direct light styles on a face(?,?,?)");
#endif
}
else
{
if (patch->totalstyle[m] == 255)
{
patch->totalstyle[m] = emitpatch->totalstyle[emitstyle];
// Log("Granting new style %d to patch at idx %d\n", patch->totalstyle[m], m);
}
#ifdef HLRAD_TRANSFERDATA_COMPRESS
float_decompress (g_transfer_compress_type, tData, &f);
VectorScale(emitlight[patchnum][emitstyle], f, v);
#else
VectorScale(emitlight[patchnum][emitstyle], (*tData), v);
#endif
#ifdef HLRAD_REFLECTIVITY
VectorMultiply(v, emitpatch->bouncereflectivity, v);
#endif
if (isPointFinite(v))
{
VectorAdd(addlight[j][m], v, addlight[j][m]);
}
else
{
Verbose("GatherLight, v (%4.3f %4.3f %4.3f)@(%4.3f %4.3f %4.3f)\n",
v[0], v[1], v[2], patch->origin[0], patch->origin[1], patch->origin[2]);
}
}
#endif
}
//LRC (ends)
#else
#ifdef HLRAD_TRANSFERDATA_COMPRESS
float_decompress (g_transfer_compress_type, tData, &f);
VectorScale(emitlight[patchnum], f, v);
#else
VectorScale(emitlight[patchnum], (*tData), v);
#endif
#ifdef HLRAD_REFLECTIVITY
VectorMultiply(v, emitpatch->bouncereflectivity, v);
#endif
if (isPointFinite(v))
{
VectorAdd(sum, v, sum);
}
else
{
Verbose("GatherLight, v (%4.3f %4.3f %4.3f)@(%4.3f %4.3f %4.3f)\n",
v[0], v[1], v[2], patch->origin[0], patch->origin[1], patch->origin[2]);
}
#endif
}
}
#ifdef HLRAD_AUTOCORING
vec_t maxlights[ALLSTYLES];
for (style = 0; style < ALLSTYLES; style++)
{
maxlights[style] = VectorMaximum (adds[style]);
}
for (m = 0; m < MAXLIGHTMAPS; m++)
{
unsigned char beststyle = 255;
if (m == 0)
{
beststyle = 0;
}
else
{
vec_t bestmaxlight = 0;
for (style = 1; style < ALLSTYLES; style++)
{
if (maxlights[style] > bestmaxlight + NORMAL_EPSILON)
{
bestmaxlight = maxlights[style];
beststyle = style;
}
}
}
if (beststyle != 255)
{
maxlights[beststyle] = 0;
newstyles[j][m] = beststyle;
VectorCopy (adds[beststyle], addlight[j][m]);
#ifdef ZHLT_XASH
VectorCopy (adds_direction[beststyle], addlight_direction[j][m]);
#endif
}
else
{
newstyles[j][m] = 255;
}
}
for (style = 1; style < ALLSTYLES; style++)
{
if (maxlights[style] > g_maxdiscardedlight + NORMAL_EPSILON)
{
ThreadLock ();
if (maxlights[style] > g_maxdiscardedlight + NORMAL_EPSILON)
{
g_maxdiscardedlight = maxlights[style];
VectorCopy (patch->origin, g_maxdiscardedpos);
}
ThreadUnlock ();
}
}
#else
#ifdef ZHLT_TEXLIGHT
//LRC VectorCopy(sum, addlight[j]);
#ifdef HLRAD_STYLE_CORING
for (style = 0; style < ALLSTYLES; ++style)
{
if (VectorMaximum(adds[style]) > g_corings[style] * BOUNCE_CORING_SCALE)
{
for (style_index = 0; style_index < MAXLIGHTMAPS; style_index++)
{
if (patch->totalstyle[style_index] == style || patch->totalstyle[style_index] == 255)
{
break;
}
}
if (style_index == MAXLIGHTMAPS)
{
#ifdef HLRAD_READABLE_EXCEEDSTYLEWARNING
if (++stylewarningcount >= stylewarningnext)
{
stylewarningnext = stylewarningcount * 2;
Warning("Too many indirect light styles on a face(%f,%f,%f)", patch->origin[0], patch->origin[1], patch->origin[2]);
Warning(" total %d warnings for too many styles", stylewarningcount);
}
#else
Warning("Too many indirect light styles on a face(%f,%f,%f)", patch->origin[0], patch->origin[1], patch->origin[2]);
#endif
}
else
{
if (patch->totalstyle[style_index] == 255)
{
patch->totalstyle[style_index] = style;
}
VectorAdd(addlight[j][style_index], adds[style], addlight[j][style_index]);
}
}
}
#endif
#else
VectorCopy(sum, addlight[j]);
#endif
#endif
}
}
// RGB Transfer version
#ifdef HLRAD_HULLU
static void GatherRGBLight(int threadnum)
{
int j;
patch_t* patch;
#ifdef ZHLT_TEXLIGHT
unsigned k,m; //LRC
//LRC vec3_t sum;
#else
unsigned k;
vec3_t sum;
#endif
unsigned iIndex;
rgb_transfer_data_t* tRGBData;
transfer_index_t* tIndex;
#ifdef HLRAD_TRANSFERDATA_COMPRESS
float f[3];
#endif
#ifdef HLRAD_STYLE_CORING
#ifdef ZHLT_TEXLIGHT
#ifndef HLRAD_AUTOCORING
int style_index;
#endif
vec3_t adds[ALLSTYLES];
#ifdef ZHLT_XASH
vec3_t adds_direction[ALLSTYLES];
#endif
int style;
#endif
#endif
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
unsigned int fastfind_index = 0;
#endif
while (1)
{
j = GetThreadWork();
if (j == -1)
{
break;
}
#ifdef HLRAD_STYLE_CORING
#ifdef ZHLT_TEXLIGHT
memset (adds, 0, ALLSTYLES * sizeof(vec3_t));
#ifdef ZHLT_XASH
memset (adds_direction, 0, ALLSTYLES * sizeof (vec3_t));
#endif
#endif
#endif
patch = &g_patches[j];
tRGBData = patch->tRGBData;
tIndex = patch->tIndex;
iIndex = patch->iIndex;
#ifdef ZHLT_TEXLIGHT
#ifndef HLRAD_AUTOCORING
//LRC
for (m = 0; m < MAXLIGHTMAPS && patch->totalstyle[m] != 255; m++)
{
VectorClear(addlight[j][m]);
}
#endif
#else
VectorClear(sum);
#endif
#ifdef HLRAD_AUTOCORING
for (m = 0; m < MAXLIGHTMAPS && patch->totalstyle[m] != 255; m++)
{
VectorAdd (adds[patch->totalstyle[m]], patch->totallight[m], adds[patch->totalstyle[m]]);
#ifdef ZHLT_XASH
VectorAdd (adds_direction[patch->totalstyle[m]], patch->totallight_direction[m], adds_direction[patch->totalstyle[m]]);
#endif
}
#endif
#ifdef ZHLT_XASH
#ifdef HLRAD_TRANSLUCENT
const vec3_t &patchnormal = getPlaneFromFaceNumber (patch->faceNumber)->normal;
#endif
#endif
for (k = 0; k < iIndex; k++, tIndex++)
{
unsigned l;
unsigned size = (tIndex->size + 1);
unsigned patchnum = tIndex->index;
#ifdef HLRAD_TRANSFERDATA_COMPRESS
for (l = 0; l < size; l++, tRGBData+=vector_size[g_rgbtransfer_compress_type], patchnum++)
#else
for (l = 0; l < size; l++, tRGBData++, patchnum++)
#endif
{
vec3_t v;
#ifdef ZHLT_TEXLIGHT
//LRC:
patch_t* emitpatch = &g_patches[patchnum];
unsigned emitstyle;
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
int opaquestyle = -1;
GetStyle (j, patchnum, opaquestyle, fastfind_index);
#endif
#ifdef HLRAD_TRANSFERDATA_COMPRESS
vector_decompress (g_rgbtransfer_compress_type, tRGBData, &f[0], &f[1], &f[2]);
#endif
#ifdef ZHLT_XASH
vec3_t direction;
VectorSubtract (patch->origin, emitpatch->origin, direction);
VectorNormalize (direction);
#ifdef HLRAD_TRANSLUCENT
vec_t dot = DotProduct (direction, patchnormal);
if (dot > 0)
{
// reflect the direction back
VectorMA (direction, -dot * 2, patchnormal, direction);
}
#endif
#endif
// for each style on the emitting patch
#ifdef HLRAD_AUTOCORING
for (emitstyle = 0; emitstyle < MAXLIGHTMAPS && emitpatch->directstyle[emitstyle] != 255; emitstyle++)
{
#ifdef HLRAD_TRANSFERDATA_COMPRESS
VectorMultiply(emitpatch->directlight[emitstyle], f, v);
#else
VectorMultiply(emitpatch->directlight[emitstyle], (*tRGBData), v);
VectorScale(v, TRANSFER_SCALE, v);
#endif
#ifdef HLRAD_REFLECTIVITY
VectorMultiply(v, emitpatch->bouncereflectivity, v);
#endif
if (isPointFinite (v))
{
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
int addstyle = emitpatch->directstyle[emitstyle];
#ifdef HLRAD_BOUNCE_STYLE
if (emitpatch->bouncestyle != -1)
{
if (addstyle == 0 || addstyle == emitpatch->bouncestyle)
addstyle = emitpatch->bouncestyle;
else
continue;
}
#endif
if (opaquestyle != -1)
{
if (addstyle == 0 || addstyle == opaquestyle)
addstyle = opaquestyle;
else
continue;
}
VectorAdd(adds[addstyle], v, adds[addstyle]);
#ifdef ZHLT_XASH
vec_t brightness = VectorAvg (v);
VectorMA (adds_direction[addstyle], brightness, direction, adds_direction[addstyle]);
#endif
#else
VectorAdd(adds[emitpatch->directstyle[emitstyle]], v, adds[emitpatch->directstyle[emitstyle]]);
#ifdef ZHLT_XASH
vec_t brightness = VectorAvg (v);
VectorMA (adds_direction[emitpatch->directstyle[emitstyle]], brightness, direction, adds_direction[emitpatch->directstyle[emitstyle]]);
#endif
#endif
}
}
#endif
for (emitstyle = 0; emitstyle < MAXLIGHTMAPS && emitpatch->totalstyle[emitstyle] != 255; emitstyle++)
{
#ifdef HLRAD_STYLE_CORING
#ifdef HLRAD_TRANSFERDATA_COMPRESS
VectorMultiply(emitlight[patchnum][emitstyle], f, v);
#else
#ifdef HLRAD_AUTOCORING
VectorMultiply(emitlight[patchnum][emitstyle], (*tRGBData), v);
VectorScale(v, TRANSFER_SCALE, v);
#else
VectorMultiply(emitlight[patchnum][emitstyle], (*tRGBData), v);
#endif
#endif
#ifdef HLRAD_REFLECTIVITY
VectorMultiply(v, emitpatch->bouncereflectivity, v);
#endif
if (isPointFinite(v))
{
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
int addstyle = emitpatch->totalstyle[emitstyle];
#ifdef HLRAD_BOUNCE_STYLE
if (emitpatch->bouncestyle != -1)
{
if (addstyle == 0 || addstyle == emitpatch->bouncestyle)
addstyle = emitpatch->bouncestyle;
else
continue;
}
#endif
if (opaquestyle != -1)
{
if (addstyle == 0 || addstyle == opaquestyle)
addstyle = opaquestyle;
else
continue;
}
VectorAdd(adds[addstyle], v, adds[addstyle]);
#ifdef ZHLT_XASH
vec_t brightness = VectorAvg (v);
VectorMA (adds_direction[addstyle], brightness, direction, adds_direction[addstyle]);
#endif
#else
VectorAdd(adds[emitpatch->totalstyle[emitstyle]], v, adds[emitpatch->totalstyle[emitstyle]]);
#ifdef ZHLT_XASH
vec_t brightness = VectorAvg (v);
VectorMA (adds_direction[emitpatch->totalstyle[emitstyle]], brightness, direction, adds_direction[emitpatch->totalstyle[emitstyle]]);
#endif
#endif
}
else
{
Verbose("GatherLight, v (%4.3f %4.3f %4.3f)@(%4.3f %4.3f %4.3f)\n",
v[0], v[1], v[2], patch->origin[0], patch->origin[1], patch->origin[2]);
}
#else
// find the matching style on this (destination) patch
for (m = 0; m < MAXLIGHTMAPS && patch->totalstyle[m] != 255; m++)
{
if (patch->totalstyle[m] == emitpatch->totalstyle[emitstyle])
{
break;
}
}
if (m == MAXLIGHTMAPS)
{
#ifdef HLRAD_READABLE_EXCEEDSTYLEWARNING
if (++stylewarningcount >= stylewarningnext)
{
stylewarningnext = stylewarningcount * 2;
Warning("Too many direct light styles on a face(?,?,?)");
Warning(" total %d warnings for too many styles", stylewarningcount);
}
#else
Warning("Too many direct light styles on a face(?,?,?)");
#endif
}
else
{
if (patch->totalstyle[m] == 255)
{
patch->totalstyle[m] = emitpatch->totalstyle[emitstyle];
// Log("Granting new style %d to patch at idx %d\n", patch->totalstyle[m], m);
}
#ifdef HLRAD_TRANSFERDATA_COMPRESS
vector_decompress (g_rgbtransfer_compress_type, tRGBData, &f[0], &f[1], &f[2]);
VectorMultiply(emitlight[patchnum][emitstyle], f, v);
#else
VectorMultiply(emitlight[patchnum][emitstyle], (*tRGBData), v);
#endif
#ifdef HLRAD_REFLECTIVITY
VectorMultiply(v, emitpatch->bouncereflectivity, v);
#endif
if (isPointFinite(v))
{
VectorAdd(addlight[j][m], v, addlight[j][m]);
}
else
{
Verbose("GatherLight, v (%4.3f %4.3f %4.3f)@(%4.3f %4.3f %4.3f)\n",
v[0], v[1], v[2], patch->origin[0], patch->origin[1], patch->origin[2]);
}
}
#endif
}
//LRC (ends)
#else
#ifdef HLRAD_TRANSFERDATA_COMPRESS
vector_decompress (g_rgbtransfer_compress_type, tRGBData, &f[0], &f[1], &f[2]);
VectorMultiply(emitlight[patchnum], (*tRGBData), v);
#else
VectorMultiply(emitlight[patchnum], (*tRGBData), v);
#endif
#ifdef HLRAD_REFLECTIVITY
VectorMultiply(v, emitpatch->bouncereflectivity, v);
#endif
if (isPointFinite(v))
{
VectorAdd(sum, v, sum);
}
else
{
Verbose("GatherLight, v (%4.3f %4.3f %4.3f)@(%4.3f %4.3f %4.3f)\n",
v[0], v[1], v[2], patch->origin[0], patch->origin[1], patch->origin[2]);
}
#endif
}
}
#ifdef HLRAD_AUTOCORING
vec_t maxlights[ALLSTYLES];
for (style = 0; style < ALLSTYLES; style++)
{
maxlights[style] = VectorMaximum (adds[style]);
}
for (m = 0; m < MAXLIGHTMAPS; m++)
{
unsigned char beststyle = 255;
if (m == 0)
{
beststyle = 0;
}
else
{
vec_t bestmaxlight = 0;
for (style = 1; style < ALLSTYLES; style++)
{
if (maxlights[style] > bestmaxlight + NORMAL_EPSILON)
{
bestmaxlight = maxlights[style];
beststyle = style;
}
}
}
if (beststyle != 255)
{
maxlights[beststyle] = 0;
newstyles[j][m] = beststyle;
VectorCopy (adds[beststyle], addlight[j][m]);
#ifdef ZHLT_XASH
VectorCopy (adds_direction[beststyle], addlight_direction[j][m]);
#endif
}
else
{
newstyles[j][m] = 255;
}
}
for (style = 1; style < ALLSTYLES; style++)
{
if (maxlights[style] > g_maxdiscardedlight + NORMAL_EPSILON)
{
ThreadLock ();
if (maxlights[style] > g_maxdiscardedlight + NORMAL_EPSILON)
{
g_maxdiscardedlight = maxlights[style];
VectorCopy (patch->origin, g_maxdiscardedpos);
}
ThreadUnlock ();
}
}
#else
#ifdef ZHLT_TEXLIGHT
//LRC VectorCopy(sum, addlight[j]);
#ifdef HLRAD_STYLE_CORING
for (style = 0; style < ALLSTYLES; ++style)
{
if (VectorMaximum(adds[style]) > g_corings[style] * BOUNCE_CORING_SCALE)
{
for (style_index = 0; style_index < MAXLIGHTMAPS; style_index++)
{
if (patch->totalstyle[style_index] == style || patch->totalstyle[style_index] == 255)
{
break;
}
}
if (style_index == MAXLIGHTMAPS)
{
#ifdef HLRAD_READABLE_EXCEEDSTYLEWARNING
if (++stylewarningcount >= stylewarningnext)
{
stylewarningnext = stylewarningcount * 2;
Warning("Too many indirect light styles on a face(%f,%f,%f)", patch->origin[0], patch->origin[1], patch->origin[2]);
Warning(" total %d warnings for too many styles", stylewarningcount);
}
#else
Warning("Too many indirect light styles on a face(%f,%f,%f)", patch->origin[0], patch->origin[1], patch->origin[2]);
#endif
}
else
{
if (patch->totalstyle[style_index] == 255)
{
patch->totalstyle[style_index] = style;
}
VectorAdd(addlight[j][style_index], adds[style], addlight[j][style_index]);
}
}
}
#endif
#else
VectorCopy(sum, addlight[j]);
#endif
#endif
}
}
#endif
#ifdef SYSTEM_WIN32
#pragma warning(pop)
#endif
// =====================================================================================
// BounceLight
// =====================================================================================
static void BounceLight()
{
unsigned i;
char name[64];
#ifdef ZHLT_TEXLIGHT
unsigned j; //LRC
#endif
for (i = 0; i < g_num_patches; i++)
{
#ifdef HLRAD_AUTOCORING
patch_t *patch = &g_patches[i];
for (j = 0; j < MAXLIGHTMAPS && patch->totalstyle[j] != 255; j++)
{
VectorCopy (patch->totallight[j], emitlight[i][j]);
#ifdef ZHLT_XASH
VectorCopy (patch->totallight_direction[j], emitlight_direction[i][j]);
#endif
}
#else
#ifdef ZHLT_TEXLIGHT
//LRC
for (j = 0; j < MAXLIGHTMAPS && g_patches[i].totalstyle[j] != 255; j++)
{
#ifdef HLRAD_TRANSFERDATA_COMPRESS
VectorCopy(g_patches[i].totallight[j], emitlight[i][j]);
#else
VectorScale(g_patches[i].totallight[j], TRANSFER_SCALE, emitlight[i][j]);
#endif
}
#else
#ifdef HLRAD_TRANSFERDATA_COMPRESS
VectorCopy(g_patches[i].totallight, emitlight[i]);
#else
VectorScale(g_patches[i].totallight, TRANSFER_SCALE, emitlight[i]);
#endif
#endif
#endif
}
for (i = 0; i < g_numbounce; i++)
{
#ifdef ZHLT_CONSOLE
Log("Bounce %u ", i + 1);
#else
printf("Bounce %u ", i + 1);
#endif
#ifdef HLRAD_HULLU
if(g_rgb_transfers)
{NamedRunThreadsOn(g_num_patches, g_estimate, GatherRGBLight);}
else
{NamedRunThreadsOn(g_num_patches, g_estimate, GatherLight);}
#else
NamedRunThreadsOn(g_num_patches, g_estimate, GatherLight);
#endif
CollectLight();
if (g_dumppatches)
{
sprintf(name, "bounce%u.txt", i);
WriteWorld(name);
}
}
#ifdef HLRAD_AUTOCORING
for (i = 0; i < g_num_patches; i++)
{
patch_t *patch = &g_patches[i];
for (j = 0; j < MAXLIGHTMAPS && patch->totalstyle[j] != 255; j++)
{
VectorCopy (emitlight[i][j], patch->totallight[j]);
#ifdef ZHLT_XASH
VectorCopy (emitlight_direction[i][j], patch->totallight_direction[j]);
#endif
}
}
#endif
}
// =====================================================================================
// CheckMaxPatches
// =====================================================================================
static void CheckMaxPatches()
{
switch (g_method)
{
case eMethodVismatrix:
hlassume(g_num_patches < MAX_VISMATRIX_PATCHES, assume_MAX_PATCHES); // should use "<=" instead. --vluzacn
break;
case eMethodSparseVismatrix:
hlassume(g_num_patches < MAX_SPARSE_VISMATRIX_PATCHES, assume_MAX_PATCHES);
break;
case eMethodNoVismatrix:
hlassume(g_num_patches < MAX_PATCHES, assume_MAX_PATCHES);
break;
}
}
// =====================================================================================
// MakeScalesStub
// =====================================================================================
static void MakeScalesStub()
{
switch (g_method)
{
case eMethodVismatrix:
MakeScalesVismatrix();
break;
case eMethodSparseVismatrix:
MakeScalesSparseVismatrix();
break;
case eMethodNoVismatrix:
MakeScalesNoVismatrix();
break;
}
}
// =====================================================================================
// FreeTransfers
// =====================================================================================
static void FreeTransfers()
{
unsigned x;
patch_t* patch = g_patches;
for (x = 0; x < g_num_patches; x++, patch++)
{
if (patch->tData)
{
FreeBlock(patch->tData);
patch->tData = NULL;
}
#ifdef HLRAD_HULLU
if (patch->tRGBData)
{
FreeBlock(patch->tRGBData);
patch->tRGBData = NULL;
}
#endif
if (patch->tIndex)
{
FreeBlock(patch->tIndex);
patch->tIndex = NULL;
}
}
}
#ifdef ZHLT_XASH
vec_t FindDirectionScale (vec_t gamma)
// gamma 0.55(default) 0.6 0.7 0.8 0.9 1.0 0.5 0.4 0.3 0.2 0.1
// returned value 0.266 0.313 0.424 0.565 0.751 1.000 0.225 0.155 0.099 0.055 0.023
{
if (gamma >= 1.0 - NORMAL_EPSILON)
{
return 1.0;
}
if (gamma < NORMAL_EPSILON)
{
return 0.0;
}
int numsteps = 200;
vec_t testmax = 2.0;
vec3_t staticlight;
vec3_t dynamiclight;
vec_t maxlength = 1;
int maxlength_i = -1;
int maxlength_j = -1;
int i, j;
for (i = 0; i < numsteps; i++)
{
for (j = 0; j < numsteps; j++)
{
vec_t directionlength;
staticlight[0] = 1.0;
staticlight[2] = staticlight[1] = testmax * (vec_t)i / (vec_t)numsteps;
dynamiclight[0] = testmax * (vec_t)j / (vec_t)numsteps;
dynamiclight[2] = dynamiclight[1] = 0.0;
{
vec3_t finalstaticlight, finaldynamiclight;
directionlength = (VectorAvg (staticlight) * 1.0 + VectorAvg (dynamiclight) * (-1.0)) / (VectorAvg (staticlight) + VectorAvg (dynamiclight));
for (int k = 0; k < 3; k++)
{
finalstaticlight[k] = pow (staticlight[k], gamma);
finaldynamiclight[k] = pow (staticlight[k] + dynamiclight[k], gamma) - finalstaticlight[k];
}
if (VectorAvg (finaldynamiclight) < NORMAL_EPSILON)
{
continue;
}
directionlength = (VectorAvg (finalstaticlight) + VectorAvg (finaldynamiclight)) * directionlength;
directionlength = fabs ((directionlength - VectorAvg (finalstaticlight) * 1.0) / VectorAvg (finaldynamiclight));
}
if (directionlength > maxlength)
{
maxlength = directionlength;
maxlength_i = i;
maxlength_j = j;
}
}
}
Developer (DEVELOPER_LEVEL_MESSAGE, "maxlength = %f i = %d j = %d\n", maxlength, maxlength_i, maxlength_j);
return 1 / maxlength;
}
#endif
#ifdef ZHLT_EMBEDLIGHTMAP
static void ExtendLightmapBuffer ()
{
int maxsize;
int i;
int j;
int ofs;
dface_t *f;
maxsize = 0;
for (i = 0; i < g_numfaces; i++)
{
f = &g_dfaces[i];
if (f->lightofs >= 0)
{
ofs = f->lightofs;
for (j = 0; j < MAXLIGHTMAPS && f->styles[j] != 255; j++)
{
ofs += (MAX_SURFACE_EXTENT + 1) * (MAX_SURFACE_EXTENT + 1) * 3;
}
if (ofs > maxsize)
{
maxsize = ofs;
}
}
}
if (maxsize >= g_lightdatasize)
{
hlassume (maxsize <= g_max_map_lightdata, assume_MAX_MAP_LIGHTING);
memset (&g_dlightdata[g_lightdatasize], 0, maxsize - g_lightdatasize);
g_lightdatasize = maxsize;
#ifdef ZHLT_XASH
hlassume (maxsize < g_max_map_dlitdata, assume_MAX_MAP_LIGHTING);
memset (&g_ddlitdata[g_dlitdatasize], 0, maxsize - g_dlitdatasize);
g_dlitdatasize = maxsize;
#endif
}
}
#endif
// =====================================================================================
// RadWorld
// =====================================================================================
static void RadWorld()
{
unsigned i;
#ifdef ZHLT_TEXLIGHT
unsigned j;
#endif
MakeBackplanes();
MakeParents(0, -1);
MakeTnodes(&g_dmodels[0]);
#ifdef HLRAD_OPAQUE_NODE
CreateOpaqueNodes();
LoadOpaqueEntities();
#endif
// turn each face into a single patch
MakePatches();
#ifdef HLRAD_DEBUG_DRAWPOINTS
if (g_drawpatch)
{
char name[_MAX_PATH+20];
sprintf (name, "%s_patch.pts", g_Mapname);
Log ("Writing '%s' ...\n", name);
FILE *f;
f = fopen(name, "w");
if (f)
{
const int pos_count = 15;
const vec3_t pos[pos_count] = {{0,0,0},{1,0,0},{0,1,0},{-1,0,0},{0,-1,0},{1,0,0},{0,0,1},{-1,0,0},{0,0,-1},{0,-1,0},{0,0,1},{0,1,0},{0,0,-1},{1,0,0},{0,0,0}};
int j, k;
patch_t *patch;
vec3_t v;
for (j = 0, patch = g_patches; j < g_num_patches; j++, patch++)
{
if (patch->flags == ePatchFlagOutside)
continue;
VectorCopy (patch->origin, v);
for (k = 0; k < pos_count; ++k)
fprintf (f, "%g %g %g\n", v[0]+pos[k][0], v[1]+pos[k][1], v[2]+pos[k][2]);
}
fclose(f);
Log ("OK.\n");
}
else
Log ("Error.\n");
}
#endif
CheckMaxPatches(); // Check here for exceeding max patches, to prevent a lot of work from occuring before an error occurs
SortPatches(); // Makes the runs in the Transfer Compression really good
PairEdges();
#ifdef HLRAD_DEBUG_DRAWPOINTS
if (g_drawedge)
{
char name[_MAX_PATH+20];
sprintf (name, "%s_edge.pts", g_Mapname);
Log ("Writing '%s' ...\n", name);
FILE *f;
f = fopen(name, "w");
if (f)
{
const int pos_count = 15;
const vec3_t pos[pos_count] = {{0,0,0},{1,0,0},{0,1,0},{-1,0,0},{0,-1,0},{1,0,0},{0,0,1},{-1,0,0},{0,0,-1},{0,-1,0},{0,0,1},{0,1,0},{0,0,-1},{1,0,0},{0,0,0}};
int j, k;
edgeshare_t *es;
vec3_t v;
for (j = 0, es = g_edgeshare; j < MAX_MAP_EDGES; j++, es++)
{
#ifdef HLRAD_GetPhongNormal_VL
if (es->smooth)
#else
if (es->coplanar || !VectorCompare (es->interface_normal, vec3_origin))
#endif
{
int v0 = g_dedges[j].v[0], v1 = g_dedges[j].v[1];
VectorAdd (g_dvertexes[v0].point, g_dvertexes[v1].point, v);
VectorScale (v, 0.5, v);
VectorAdd (v, es->interface_normal, v);
VectorAdd (v, g_face_offset[es->faces[0] - g_dfaces], v);
for (k = 0; k < pos_count; ++k)
fprintf (f, "%g %g %g\n", v[0]+pos[k][0], v[1]+pos[k][1], v[2]+pos[k][2]);
}
}
fclose(f);
Log ("OK.\n");
}
else
Log ("Error.\n");
}
#endif
#ifdef HLRAD_SOFTSKY
BuildDiffuseNormals ();
#endif
// create directlights out of g_patches and lights
CreateDirectLights();
Log("\n");
#ifdef HLRAD_GROWSAMPLE
// generate a position map for each face
NamedRunThreadsOnIndividual(g_numfaces, g_estimate, FindFacePositions);
#endif
// build initial facelights
NamedRunThreadsOnIndividual(g_numfaces, g_estimate, BuildFacelights);
#ifdef HLRAD_GROWSAMPLE
FreePositionMaps ();
#endif
// free up the direct lights now that we have facelights
DeleteDirectLights();
if (g_numbounce > 0)
{
// build transfer lists
MakeScalesStub();
#ifdef HLRAD_MORE_PATCHES
// these arrays are only used in CollectLight, GatherLight and BounceLight
#ifdef ZHLT_TEXLIGHT
emitlight = (vec3_t (*)[MAXLIGHTMAPS])AllocBlock ((g_num_patches + 1) * sizeof (vec3_t [MAXLIGHTMAPS]));
addlight = (vec3_t (*)[MAXLIGHTMAPS])AllocBlock ((g_num_patches + 1) * sizeof (vec3_t [MAXLIGHTMAPS]));
#ifdef ZHLT_XASH
emitlight_direction = (vec3_t (*)[MAXLIGHTMAPS])AllocBlock ((g_num_patches + 1) * sizeof (vec3_t [MAXLIGHTMAPS]));
addlight_direction = (vec3_t (*)[MAXLIGHTMAPS])AllocBlock ((g_num_patches + 1) * sizeof (vec3_t [MAXLIGHTMAPS]));
#endif
#ifdef HLRAD_AUTOCORING
newstyles = (unsigned char (*)[MAXLIGHTMAPS])AllocBlock ((g_num_patches + 1) * sizeof (unsigned char [MAXLIGHTMAPS]));
#endif
#else
emitlight = (vec3_t *)AllocBlock ((g_num_patches + 1) * sizeof (vec3_t));
addlight = (vec3_t *)AllocBlock ((g_num_patches + 1) * sizeof (vec3_t));
#endif
#endif
// spread light around
BounceLight();
#ifndef HLRAD_AUTOCORING
for (i = 0; i < g_num_patches; i++)
{
#ifdef ZHLT_TEXLIGHT// AJM
for (j = 0; j < MAXLIGHTMAPS && g_patches[i].totalstyle[j] != 255; j++)
{
VectorSubtract(g_patches[i].totallight[j], g_patches[i].directlight[j], g_patches[i].totallight[j]);
}
#else
VectorSubtract(g_patches[i].totallight, g_patches[i].directlight, g_patches[i].totallight);
#endif
}
#endif
#ifdef HLRAD_MORE_PATCHES
#ifdef ZHLT_TEXLIGHT
FreeBlock (emitlight);
emitlight = NULL;
FreeBlock (addlight);
addlight = NULL;
#ifdef ZHLT_XASH
FreeBlock (emitlight_direction);
emitlight_direction = NULL;
FreeBlock (addlight_direction);
addlight_direction = NULL;
#endif
#ifdef HLRAD_AUTOCORING
FreeBlock (newstyles);
newstyles = NULL;
#endif
#else
FreeBlock (emitlight);
emitlight = NULL;
FreeBlock (addlight);
addlight = NULL;
#endif
#endif
}
#ifndef HLRAD_AUTOCORING
#ifdef HLRAD_GatherPatchLight
if (g_numbounce <= 0)
{
for (i = 0; i < g_num_patches; i++)
{
#ifdef ZHLT_TEXLIGHT// AJM
for (j = 0; j < MAXLIGHTMAPS && g_patches[i].totalstyle[j] != 255; j++)
{
VectorSubtract(g_patches[i].totallight[j], g_patches[i].directlight[j], g_patches[i].totallight[j]);
}
#else
VectorSubtract(g_patches[i].totallight, g_patches[i].directlight, g_patches[i].totallight);
#endif
}
}
#endif
#endif
FreeTransfers();
#ifdef HLRAD_OPAQUE_STYLE_BOUNCE
FreeStyleArrays ();
#endif
#ifdef HLRAD_LOCALTRIANGULATION
NamedRunThreadsOnIndividual (g_numfaces, g_estimate, CreateTriangulations);
#endif
// blend bounced light into direct light and save
PrecompLightmapOffsets();
#ifdef ZHLT_XASH
#ifdef HLRAD_WHOME
g_directionscale = FindDirectionScale (VectorAvg (g_colour_qgamma));
#else
g_directionscale = FindDirectionScale (g_qgamma);
#endif
#endif
#ifdef HLRAD_GROWSAMPLE
ScaleDirectLights ();
#ifndef HLRAD_GatherPatchLight
if (g_numbounce)
#endif
{
CreateFacelightDependencyList ();
NamedRunThreadsOnIndividual (g_numfaces, g_estimate, AddPatchLights);
FreeFacelightDependencyList ();
}
#endif
#ifdef HLRAD_LOCALTRIANGULATION
FreeTriangulations ();
#endif
NamedRunThreadsOnIndividual(g_numfaces, g_estimate, FinalLightFace);
#ifdef HLRAD_AUTOCORING
if (g_maxdiscardedlight > 0.01)
{
Verbose ("Maximum brightness loss (too many light styles on a face) = %f @(%f, %f, %f)\n", g_maxdiscardedlight, g_maxdiscardedpos[0], g_maxdiscardedpos[1], g_maxdiscardedpos[2]);
}
#endif
#ifdef HLRAD_MDL_LIGHT_HACK
MdlLightHack ();
#endif
#ifdef HLRAD_REDUCELIGHTMAP
ReduceLightmap();
if (g_lightdatasize == 0)
{
g_lightdatasize = 1;
g_dlightdata[0] = 0;
#ifdef ZHLT_XASH
g_dlitdatasize = 1;
g_ddlitdata[0] = 0;
#endif
}
#endif
#ifdef ZHLT_EMBEDLIGHTMAP
ExtendLightmapBuffer (); // expand the size of lightdata array (for a few KB) to ensure that game engine reads within its valid range
#endif
}
// =====================================================================================
// Usage
// =====================================================================================
static void Usage()
{
Banner();
Log("\n-= %s Options =-\n\n", g_Program);
#ifdef ZHLT_CONSOLE
Log(" -console # : Set to 0 to turn off the pop-up console (default is 1)\n");
#endif
#ifdef ZHLT_LANGFILE
Log(" -lang file : localization file\n");
#endif
#ifdef HLRAD_TEXTURE
Log(" -waddir folder : Search this folder for wad files.\n");
#endif
#ifdef HLRAD_FASTMODE
Log(" -fast : Fast rad\n");
#endif
#ifdef HLRAD_ARG_MISC
Log(" -vismatrix value: Set vismatrix method to normal, sparse or off .\n");
#else
Log(" -sparse : Enable low memory vismatrix algorithm\n");
Log(" -nomatrix : Disable usage of vismatrix entirely\n\n");
#endif
Log(" -extra : Improve lighting quality by doing 9 point oversampling\n");
Log(" -bounce # : Set number of radiosity bounces\n");
Log(" -ambient r g b : Set ambient world light (0.0 to 1.0, r g b)\n");
#ifndef HLRAD_FinalLightFace_VL
Log(" -maxlight # : Set maximum light intensity value\n");
#endif
#ifdef HLRAD_PRESERVELIGHTMAPCOLOR
Log(" -limiter # : Set light clipping threshold (-1=None)\n");
#endif
Log(" -circus : Enable 'circus' mode for locating unlit lightmaps\n");
#ifdef HLRAD_SUNSPREAD
Log(" -nospread : Disable sunlight spread angles for this compile\n");
#endif
Log(" -nopaque : Disable the opaque zhlt_lightflags for this compile\n\n");
Log(" -smooth # : Set smoothing threshold for blending (in degrees)\n");
#ifdef HLRAD_CUSTOMSMOOTH
Log(" -smooth2 # : Set smoothing threshold between different textures\n");
#endif
Log(" -chop # : Set radiosity patch size for normal textures\n");
Log(" -texchop # : Set radiosity patch size for texture light faces\n\n");
Log(" -notexscale : Do not scale radiosity patches with texture scale\n");
Log(" -coring # : Set lighting threshold before blackness\n");
Log(" -dlight # : Set direct lighting threshold\n");
Log(" -nolerp : Disable radiosity interpolation, nearest point instead\n\n");
Log(" -fade # : Set global fade (larger values = shorter lights)\n");
#ifndef HLRAD_ARG_MISC
Log(" -falloff # : Set global falloff mode (1 = inv linear, 2 = inv square)\n");
#endif
#ifdef HLRAD_TEXLIGHTGAP
Log(" -texlightgap # : Set global gap distance for texlights\n");
#endif
Log(" -scale # : Set global light scaling value\n");
Log(" -gamma # : Set global gamma value\n\n");
Log(" -sky # : Set ambient sunlight contribution in the shade outside\n");
Log(" -lights file : Manually specify a lights.rad file to use\n");
Log(" -noskyfix : Disable light_environment being global\n");
Log(" -incremental : Use or create an incremental transfer list file\n\n");
Log(" -dump : Dumps light patches to a file for hlrad debugging info\n\n");
Log(" -texdata # : Alter maximum texture memory limit (in kb)\n");
Log(" -lightdata # : Alter maximum lighting memory limit (in kb)\n"); //lightdata
Log(" -chart : display bsp statitics\n");
Log(" -low | -high : run program an altered priority level\n");
Log(" -nolog : Do not generate the compile logfiles\n");
Log(" -threads # : manually specify the number of threads to run\n");
#ifdef SYSTEM_WIN32
Log(" -estimate : display estimated time during compile\n");
#endif
#ifdef ZHLT_PROGRESSFILE // AJM
Log(" -progressfile path : specify the path to a file for progress estimate output\n");
#endif
#ifdef SYSTEM_POSIX
Log(" -noestimate : Do not display continuous compile time estimates\n");
#endif
Log(" -verbose : compile with verbose messages\n");
Log(" -noinfo : Do not show tool configuration information\n");
Log(" -dev # : compile with developer message\n\n");
// ------------------------------------------------------------------------
// Changes by Adam Foster - afoster@compsoc.man.ac.uk
#ifdef HLRAD_WHOME
// AJM: we dont need this extra crap
//Log("-= Unofficial features added by Adam Foster (afoster@compsoc.man.ac.uk) =-\n\n");
Log(" -colourgamma r g b : Sets different gamma values for r, g, b\n" );
Log(" -colourscale r g b : Sets different lightscale values for r, g ,b\n" );
Log(" -colourjitter r g b : Adds noise, independent colours, for dithering\n");
Log(" -jitter r g b : Adds noise, monochromatic, for dithering\n");
#ifndef HLRAD_ARG_MISC
Log(" -nodiffuse : Disables light_environment diffuse hack\n");
Log(" -nospotpoints : Disables light_spot spherical point sources\n");
#endif
#ifndef HLRAD_CUSTOMTEXLIGHT // no softlight hack
Log(" -softlight r g b d : Scaling values for backwards-light hack\n\n");
#endif
//Log("-= End of unofficial features! =-\n\n" );
#endif
// ------------------------------------------------------------------------
#ifdef HLRAD_HULLU
Log(" -customshadowwithbounce : Enables custom shadows with bounce light\n");
Log(" -rgbtransfers : Enables RGB Transfers (for custom shadows)\n\n");
#endif
#ifdef HLRAD_TRANSTOTAL_HACK
#ifndef HLRAD_REFLECTIVITY
Log(" -bscale : Scaling light on every bounce\n\n");
#endif
#endif
#ifdef HLRAD_MINLIGHT
Log(" -minlight # : Minimum final light (integer from 0 to 255)\n");
#endif
#ifdef HLRAD_TRANSFERDATA_COMPRESS
{
int i;
Log(" -compress # : compress tranfer (");
for (i=0; i<float_type_count; i++)
Log (" %d=%s", i, float_type_string[i]);
Log(" )\n");
Log(" -rgbcompress # : compress rgbtranfer (");
for (i=0; i<vector_type_count; i++)
Log (" %d=%s", i, vector_type_string[i]);
Log(" )\n");
}
#endif
#ifdef HLRAD_SOFTSKY
Log(" -softsky # : Smooth skylight.(0=off 1=on)\n");
#endif
#ifdef HLRAD_TRANSLUCENT
Log(" -depth # : Thickness of translucent objects.\n");
#endif
#ifdef HLRAD_OPAQUE_BLOCK
Log(" -blockopaque # : Remove the black areas around opaque entities.(0=off 1=on)\n");
#endif
#ifdef HLRAD_TEXTURE
Log(" -notextures : Don't load textures.\n");
#endif
#ifdef HLRAD_REFLECTIVITY
Log(" -texreflectgamma # : Gamma that relates reflectivity to texture color bits.\n");
Log(" -texreflectscale # : Reflectivity for 255-white texture.\n");
#endif
#ifdef HLRAD_BLUR
Log(" -blur # : Enlarge lightmap sample to blur the lightmap.\n");
#endif
#ifdef HLRAD_ACCURATEBOUNCE
Log(" -noemitterrange: Don't fix pointy texlights.\n");
#endif
#ifdef HLRAD_AVOIDWALLBLEED
Log(" -nobleedfix : Don't fix wall bleeding problem for large blur value.\n");
#endif
#ifdef HLRAD_DEBUG_DRAWPOINTS
Log(" -drawpatch : Export light patch positions to file 'mapname_patch.pts'.\n");
Log(" -drawsample x y z r : Export light sample positions in an area to file 'mapname_sample.pts'.\n");
Log(" -drawedge : Export smooth edge positions to file 'mapname_edge.pts'.\n");
Log(" -drawlerp : Show bounce light triangulation status.\n");
#endif
#ifdef HLRAD_AVOIDWALLBLEED
Log(" -drawnudge : Show nudged samples.\n");
#endif
#ifdef HLRAD_PRESERVELIGHTMAPCOLOR
Log(" -drawoverload : Highlight fullbright spots\n");
#endif
Log(" mapfile : The mapfile to compile\n\n");
exit(1);
}
// =====================================================================================
// Settings
// =====================================================================================
static void Settings()
{
char* tmp;
char buf1[1024];
char buf2[1024];
if (!g_info)
{
return;
}
Log("\n-= Current %s Settings =-\n", g_Program);
Log("Name | Setting | Default\n"
"--------------------|---------------------|-------------------------\n");
// ZHLT Common Settings
if (DEFAULT_NUMTHREADS == -1)
{
Log("threads [ %17d ] [ Varies ]\n", g_numthreads);
}
else
{
Log("threads [ %17d ] [ %17d ]\n", g_numthreads, DEFAULT_NUMTHREADS);
}
Log("verbose [ %17s ] [ %17s ]\n", g_verbose ? "on" : "off", DEFAULT_VERBOSE ? "on" : "off");
Log("log [ %17s ] [ %17s ]\n", g_log ? "on" : "off", DEFAULT_LOG ? "on" : "off");
Log("developer [ %17d ] [ %17d ]\n", g_developer, DEFAULT_DEVELOPER);
Log("chart [ %17s ] [ %17s ]\n", g_chart ? "on" : "off", DEFAULT_CHART ? "on" : "off");
Log("estimate [ %17s ] [ %17s ]\n", g_estimate ? "on" : "off", DEFAULT_ESTIMATE ? "on" : "off");
Log("max texture memory [ %17d ] [ %17d ]\n", g_max_map_miptex, DEFAULT_MAX_MAP_MIPTEX);
Log("max lighting memory [ %17d ] [ %17d ]\n", g_max_map_lightdata, DEFAULT_MAX_MAP_LIGHTDATA); //lightdata
switch (g_threadpriority)
{
case eThreadPriorityNormal:
default:
tmp = "Normal";
break;
case eThreadPriorityLow:
tmp = "Low";
break;
case eThreadPriorityHigh:
tmp = "High";
break;
}
Log("priority [ %17s ] [ %17s ]\n", tmp, "Normal");
Log("\n");
#ifdef HLRAD_FASTMODE
Log("fast rad [ %17s ] [ %17s ]\n", g_fastmode? "on": "off", DEFAULT_FASTMODE? "on": "off");
#endif
#ifdef HLRAD_ARG_MISC
Log("vismatrix algorithm [ %17s ] [ %17s ]\n",
g_method == eMethodVismatrix? "Original": g_method == eMethodSparseVismatrix? "Sparse": g_method == eMethodNoVismatrix? "NoMatrix": "Unknown",
DEFAULT_METHOD == eMethodVismatrix? "Original": DEFAULT_METHOD == eMethodSparseVismatrix? "Sparse": DEFAULT_METHOD == eMethodNoVismatrix? "NoMatrix": "Unknown"
);
#else
// HLRAD Specific Settings
switch (g_method)
{
default:
tmp = "Unknown";
break;
case eMethodVismatrix:
tmp = "Original";
break;
case eMethodSparseVismatrix:
tmp = "Sparse";
break;
case eMethodNoVismatrix:
tmp = "NoMatrix";
break;
}
Log("vismatrix algorithm [ %17s ] [ %17s ]\n", tmp, "Original");
#endif
Log("oversampling (-extra)[ %17s ] [ %17s ]\n", g_extra ? "on" : "off", DEFAULT_EXTRA ? "on" : "off");
Log("bounces [ %17d ] [ %17d ]\n", g_numbounce, DEFAULT_BOUNCE);
safe_snprintf(buf1, sizeof(buf1), "%1.3f %1.3f %1.3f", g_ambient[0], g_ambient[1], g_ambient[2]);
safe_snprintf(buf2, sizeof(buf2), "%1.3f %1.3f %1.3f", DEFAULT_AMBIENT_RED, DEFAULT_AMBIENT_GREEN, DEFAULT_AMBIENT_BLUE);
Log("ambient light [ %17s ] [ %17s ]\n", buf1, buf2);
#ifndef HLRAD_FinalLightFace_VL
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_maxlight);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_MAXLIGHT);
Log("maximum light [ %17s ] [ %17s ]\n", buf1, buf2);
#endif
#ifdef HLRAD_PRESERVELIGHTMAPCOLOR
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_limitthreshold);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_LIMITTHRESHOLD);
Log("light limit threshold[ %17s ] [ %17s ]\n", g_limitthreshold >= 0 ? buf1 : "None", buf2);
#endif
Log("circus mode [ %17s ] [ %17s ]\n", g_circus ? "on" : "off", DEFAULT_CIRCUS ? "on" : "off");
Log("\n");
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_smoothing_value);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_SMOOTHING_VALUE);
Log("smoothing threshold [ %17s ] [ %17s ]\n", buf1, buf2);
#ifdef HLRAD_CUSTOMSMOOTH
safe_snprintf(buf1, sizeof(buf1), g_smoothing_value_2<0? "no change": "%3.3f", g_smoothing_value_2);
safe_snprintf(buf2, sizeof(buf2), DEFAULT_SMOOTHING2_VALUE<0? "no change": "%3.3f", DEFAULT_SMOOTHING2_VALUE);
Log("smoothing threshold 2[ %17s ] [ %17s ]\n", buf1, buf2);
#endif
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_dlight_threshold);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_DLIGHT_THRESHOLD);
Log("direct threshold [ %17s ] [ %17s ]\n", buf1, buf2);
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_direct_scale);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_DLIGHT_SCALE);
Log("direct light scale [ %17s ] [ %17s ]\n", buf1, buf2);
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_coring);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_CORING);
Log("coring threshold [ %17s ] [ %17s ]\n", buf1, buf2);
Log("patch interpolation [ %17s ] [ %17s ]\n", g_lerp_enabled ? "on" : "off", DEFAULT_LERP_ENABLED ? "on" : "off");
Log("\n");
Log("texscale [ %17s ] [ %17s ]\n", g_texscale ? "on" : "off", DEFAULT_TEXSCALE ? "on" : "off");
Log("patch subdividing [ %17s ] [ %17s ]\n", g_subdivide ? "on" : "off", DEFAULT_SUBDIVIDE ? "on" : "off");
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_chop);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_CHOP);
Log("chop value [ %17s ] [ %17s ]\n", buf1, buf2);
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_texchop);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_TEXCHOP);
Log("texchop value [ %17s ] [ %17s ]\n", buf1, buf2);
Log("\n");
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_fade);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_FADE);
Log("global fade [ %17s ] [ %17s ]\n", buf1, buf2);
#ifndef HLRAD_ARG_MISC
Log("global falloff [ %17d ] [ %17d ]\n", g_falloff, DEFAULT_FALLOFF);
#endif
#ifdef HLRAD_TEXLIGHTGAP
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_texlightgap);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_TEXLIGHTGAP);
Log("global texlight gap [ %17s ] [ %17s ]\n", buf1, buf2);
#endif
// ------------------------------------------------------------------------
// Changes by Adam Foster - afoster@compsoc.man.ac.uk
// replaces the old stuff for displaying current values for gamma and lightscale
#ifdef HLRAD_WHOME
safe_snprintf(buf1, sizeof(buf1), "%1.3f %1.3f %1.3f", g_colour_lightscale[0], g_colour_lightscale[1], g_colour_lightscale[2]);
safe_snprintf(buf2, sizeof(buf2), "%1.3f %1.3f %1.3f", DEFAULT_COLOUR_LIGHTSCALE_RED, DEFAULT_COLOUR_LIGHTSCALE_GREEN, DEFAULT_COLOUR_LIGHTSCALE_BLUE);
Log("global light scale [ %17s ] [ %17s ]\n", buf1, buf2);
safe_snprintf(buf1, sizeof(buf1), "%1.3f %1.3f %1.3f", g_colour_qgamma[0], g_colour_qgamma[1], g_colour_qgamma[2]);
safe_snprintf(buf2, sizeof(buf2), "%1.3f %1.3f %1.3f", DEFAULT_COLOUR_GAMMA_RED, DEFAULT_COLOUR_GAMMA_GREEN, DEFAULT_COLOUR_GAMMA_BLUE);
Log("global gamma [ %17s ] [ %17s ]\n", buf1, buf2);
#endif
// ------------------------------------------------------------------------
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_lightscale);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_LIGHTSCALE);
Log("global light scale [ %17s ] [ %17s ]\n", buf1, buf2);
#ifndef HLRAD_WHOME
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_qgamma);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_GAMMA);
Log("global gamma amount [ %17s ] [ %17s ]\n", buf1, buf2);
#endif
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_indirect_sun);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_INDIRECT_SUN);
Log("global sky diffusion [ %17s ] [ %17s ]\n", buf1, buf2);
Log("\n");
#ifdef HLRAD_SUNSPREAD
Log("spread angles [ %17s ] [ %17s ]\n", g_allow_spread ? "on" : "off", DEFAULT_ALLOW_SPREAD ? "on" : "off");
#endif
Log("opaque entities [ %17s ] [ %17s ]\n", g_allow_opaques ? "on" : "off", DEFAULT_ALLOW_OPAQUES ? "on" : "off");
Log("sky lighting fix [ %17s ] [ %17s ]\n", g_sky_lighting_fix ? "on" : "off", DEFAULT_SKY_LIGHTING_FIX ? "on" : "off");
Log("incremental [ %17s ] [ %17s ]\n", g_incremental ? "on" : "off", DEFAULT_INCREMENTAL ? "on" : "off");
Log("dump [ %17s ] [ %17s ]\n", g_dumppatches ? "on" : "off", DEFAULT_DUMPPATCHES ? "on" : "off");
// ------------------------------------------------------------------------
// Changes by Adam Foster - afoster@compsoc.man.ac.uk
// displays information on all the brand-new features :)
#ifdef HLRAD_WHOME
Log("\n");
safe_snprintf(buf1, sizeof(buf1), "%3.1f %3.1f %3.1f", g_colour_jitter_hack[0], g_colour_jitter_hack[1], g_colour_jitter_hack[2]);
safe_snprintf(buf2, sizeof(buf2), "%3.1f %3.1f %3.1f", DEFAULT_COLOUR_JITTER_HACK_RED, DEFAULT_COLOUR_JITTER_HACK_GREEN, DEFAULT_COLOUR_JITTER_HACK_BLUE);
Log("colour jitter [ %17s ] [ %17s ]\n", buf1, buf2);
safe_snprintf(buf1, sizeof(buf1), "%3.1f %3.1f %3.1f", g_jitter_hack[0], g_jitter_hack[1], g_jitter_hack[2]);
safe_snprintf(buf2, sizeof(buf2), "%3.1f %3.1f %3.1f", DEFAULT_JITTER_HACK_RED, DEFAULT_JITTER_HACK_GREEN, DEFAULT_JITTER_HACK_BLUE);
Log("monochromatic jitter [ %17s ] [ %17s ]\n", buf1, buf2);
#ifndef HLRAD_CUSTOMTEXLIGHT // no softlight hack
safe_snprintf(buf1, sizeof(buf1), "%2.1f %2.1f %2.1f %2.1f", g_softlight_hack[0], g_softlight_hack[1], g_softlight_hack[2], g_softlight_hack_distance);
safe_snprintf(buf2, sizeof(buf2), "%2.1f %2.1f %2.1f %2.1f", DEFAULT_SOFTLIGHT_HACK_RED, DEFAULT_SOFTLIGHT_HACK_GREEN, DEFAULT_SOFTLIGHT_HACK_BLUE, DEFAULT_SOFTLIGHT_HACK_DISTANCE);
Log("softlight hack [ %17s ] [ %17s ]\n", buf1, buf2);
#endif
#ifndef HLRAD_ARG_MISC
Log("diffuse hack [ %17s ] [ %17s ]\n", g_diffuse_hack ? "on" : "off", DEFAULT_DIFFUSE_HACK ? "on" : "off");
Log("spotlight points [ %17s ] [ %17s ]\n", g_spotlight_hack ? "on" : "off", DEFAULT_SPOTLIGHT_HACK ? "on" : "off");
#endif
#endif
// ------------------------------------------------------------------------
#ifdef HLRAD_HULLU
Log("\n");
Log("custom shadows with bounce light\n"
" [ %17s ] [ %17s ]\n", g_customshadow_with_bouncelight ? "on" : "off", DEFAULT_CUSTOMSHADOW_WITH_BOUNCELIGHT ? "on" : "off");
Log("rgb transfers [ %17s ] [ %17s ]\n", g_rgb_transfers ? "on" : "off", DEFAULT_RGB_TRANSFERS ? "on" : "off");
#endif
#ifdef HLRAD_TRANSTOTAL_HACK
#ifndef HLRAD_REFLECTIVITY
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_transtotal_hack);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_TRANSTOTAL_HACK);
Log("bounce scale [ %17s ] [ %17s ]\n", buf1, buf2);
#endif
#endif
#ifdef HLRAD_MINLIGHT
Log("minimum final light [ %17d ] [ %17d ]\n", (int)g_minlight, (int)DEFAULT_MINLIGHT);
#endif
#ifdef HLRAD_TRANSFERDATA_COMPRESS
sprintf (buf1, "%d (%s)", g_transfer_compress_type, float_type_string[g_transfer_compress_type]);
sprintf (buf2, "%d (%s)", DEFAULT_TRANSFER_COMPRESS_TYPE, float_type_string[DEFAULT_TRANSFER_COMPRESS_TYPE]);
Log("size of transfer [ %17s ] [ %17s ]\n", buf1, buf2);
sprintf (buf1, "%d (%s)", g_rgbtransfer_compress_type, vector_type_string[g_rgbtransfer_compress_type]);
sprintf (buf2, "%d (%s)", DEFAULT_RGBTRANSFER_COMPRESS_TYPE, vector_type_string[DEFAULT_RGBTRANSFER_COMPRESS_TYPE]);
Log("size of rgbtransfer [ %17s ] [ %17s ]\n", buf1, buf2);
#endif
#ifdef HLRAD_SOFTSKY
Log("soft sky [ %17s ] [ %17s ]\n", g_softsky ? "on" : "off", DEFAULT_SOFTSKY ? "on" : "off");
#endif
#ifdef HLRAD_TRANSLUCENT
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_translucentdepth);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_TRANSLUCENTDEPTH);
Log("translucent depth [ %17s ] [ %17s ]\n", buf1, buf2);
#endif
#ifdef HLRAD_OPAQUE_BLOCK
Log("block opaque [ %17s ] [ %17s ]\n", g_blockopaque ? "on" : "off", DEFAULT_BLOCKOPAQUE ? "on" : "off");
#endif
#ifdef HLRAD_TEXTURE
Log("ignore textures [ %17s ] [ %17s ]\n", g_notextures ? "on" : "off", DEFAULT_NOTEXTURES ? "on" : "off");
#endif
#ifdef HLRAD_REFLECTIVITY
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_texreflectgamma);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_TEXREFLECTGAMMA);
Log("reflectivity gamma [ %17s ] [ %17s ]\n", buf1, buf2);
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_texreflectscale);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_TEXREFLECTSCALE);
Log("reflectivity scale [ %17s ] [ %17s ]\n", buf1, buf2);
#endif
#ifdef HLRAD_BLUR
safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_blur);
safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_BLUR);
Log("blur size [ %17s ] [ %17s ]\n", buf1, buf2);
#endif
#ifdef HLRAD_ACCURATEBOUNCE
Log("no emitter range [ %17s ] [ %17s ]\n", g_noemitterrange ? "on" : "off", DEFAULT_NOEMITTERRANGE ? "on" : "off");
#endif
#ifdef HLRAD_AVOIDWALLBLEED
Log("wall bleeding fix [ %17s ] [ %17s ]\n", g_bleedfix ? "on" : "off", DEFAULT_BLEEDFIX ? "on" : "off");
#endif
Log("\n\n");
}
#ifdef HLRAD_INFO_TEXLIGHTS
// AJM: added in
// =====================================================================================
// ReadInfoTexlights
// try and parse texlight info from the info_texlights entity
// =====================================================================================
void ReadInfoTexlights()
{
int k;
int values;
int numtexlights = 0;
float r, g, b, i;
entity_t* mapent;
epair_t* ep;
texlight_t texlight;
for (k = 0; k < g_numentities; k++)
{
mapent = &g_entities[k];
if (strcmp(ValueForKey(mapent, "classname"), "info_texlights"))
continue;
#ifdef HLRAD_CUSTOMTEXLIGHT
Log("Reading texlights from info_texlights map entity\n");
#else
Log("[Reading texlights from info_texlights map entity]\n");
#endif
for (ep = mapent->epairs; ep; ep = ep->next)
{
if ( !strcmp(ep->key, "classname")
|| !strcmp(ep->key, "origin")
)
continue; // we dont care about these keyvalues
values = sscanf(ep->value, "%f %f %f %f", &r, &g, &b, &i);
if (values == 1)
{
g = b = r;
}
else if (values == 4) // use brightness value.
{
r *= i / 255.0;
g *= i / 255.0;
b *= i / 255.0;
}
else if (values != 3)
{
Warning("ignoring bad texlight '%s' in info_texlights entity", ep->key);
continue;
}
texlight.name = ep->key;
texlight.value[0] = r;
texlight.value[1] = g;
texlight.value[2] = b;
texlight.filename = "info_texlights";
s_texlights.push_back(texlight);
numtexlights++;
}
#ifndef HLRAD_CUSTOMTEXLIGHT
Log("[%i texlights parsed from info_texlights map entity]\n\n", numtexlights);
#endif
}
}
#endif
const char* lights_rad = "lights.rad";
const char* ext_rad = ".rad";
// =====================================================================================
// LoadRadFiles
// =====================================================================================
void LoadRadFiles(const char* const mapname, const char* const user_rad, const char* argv0)
{
char global_lights[_MAX_PATH];
char mapname_lights[_MAX_PATH];
char mapfile[_MAX_PATH];
char mapdir[_MAX_PATH];
char appdir[_MAX_PATH];
// Get application directory (only an approximation on posix systems)
// try looking in the directory we were run from
{
char tmp[_MAX_PATH];
memset(tmp, 0, sizeof(tmp));
#ifdef SYSTEM_WIN32
GetModuleFileName(NULL, tmp, _MAX_PATH);
#else
safe_strncpy(tmp, argv0, _MAX_PATH);
#endif
ExtractFilePath(tmp, appdir);
}
// Get map directory
ExtractFilePath(mapname, mapdir);
#ifdef ZHLT_DEFAULTEXTENSION_FIX
ExtractFile(mapname, mapfile);
#else
ExtractFileBase(mapname, mapfile);
#endif
// Look for lights.rad in mapdir
safe_strncpy(global_lights, mapdir, _MAX_PATH);
safe_strncat(global_lights, lights_rad, _MAX_PATH);
if (q_exists(global_lights))
{
ReadLightFile(global_lights);
}
else
{
// Look for lights.rad in appdir
safe_strncpy(global_lights, appdir, _MAX_PATH);
safe_strncat(global_lights, lights_rad, _MAX_PATH);
if (q_exists(global_lights))
{
ReadLightFile(global_lights);
}
else
{
// Look for lights.rad in current working directory
safe_strncpy(global_lights, lights_rad, _MAX_PATH);
if (q_exists(global_lights))
{
ReadLightFile(global_lights);
}
}
}
// Look for mapname.rad in mapdir
safe_strncpy(mapname_lights, mapdir, _MAX_PATH);
safe_strncat(mapname_lights, mapfile, _MAX_PATH);
#ifdef ZHLT_DEFAULTEXTENSION_FIX
safe_strncat(mapname_lights, ext_rad, _MAX_PATH);
#else
DefaultExtension(mapname_lights, ext_rad);
#endif
if (q_exists(mapname_lights))
{
ReadLightFile(mapname_lights);
}
if (user_rad)
{
char user_lights[_MAX_PATH];
char userfile[_MAX_PATH];
ExtractFile(user_rad, userfile);
// Look for user.rad from command line (raw)
safe_strncpy(user_lights, user_rad, _MAX_PATH);
if (q_exists(user_lights))
{
ReadLightFile(user_lights);
}
else
{
// Try again with .rad enforced as extension
DefaultExtension(user_lights, ext_rad);
if (q_exists(user_lights))
{
ReadLightFile(user_lights);
}
else
{
// Look for user.rad in mapdir
safe_strncpy(user_lights, mapdir, _MAX_PATH);
safe_strncat(user_lights, userfile, _MAX_PATH);
DefaultExtension(user_lights, ext_rad);
if (q_exists(user_lights))
{
ReadLightFile(user_lights);
}
else
{
// Look for user.rad in appdir
safe_strncpy(user_lights, appdir, _MAX_PATH);
safe_strncat(user_lights, userfile, _MAX_PATH);
DefaultExtension(user_lights, ext_rad);
if (q_exists(user_lights))
{
ReadLightFile(user_lights);
}
else
{
// Look for user.rad in current working directory
safe_strncpy(user_lights, userfile, _MAX_PATH);
DefaultExtension(user_lights, ext_rad);
if (q_exists(user_lights))
{
ReadLightFile(user_lights);
}
}
}
}
}
}
#ifdef HLRAD_INFO_TEXLIGHTS
ReadInfoTexlights(); // AJM
#endif
}
#ifdef ZHLT_XASH
void WriteDlitData (const char *filename)
{
FILE *f;
if (g_drawdirection)
{
if (g_dlitdatasize != g_lightdatasize)
{
Error ("g_dlitdatasize != g_lightdatasize");
}
memcpy (g_dlightdata, g_ddlitdata, g_lightdatasize);
}
f = SafeOpenWrite (filename);
fputc ('Q', f);
fputc ('L', f);
fputc ('I', f);
fputc ('T', f);
fputc (1, f);
fputc (0, f);
fputc (0, f);
fputc (0, f);
SafeWrite (f, g_ddlitdata, g_dlitdatasize);
fclose (f);
}
#endif
// =====================================================================================
// main
// =====================================================================================
int main(const int argc, char** argv)
{
int i;
double start, end;
const char* mapname_from_arg = NULL;
const char* user_lights = NULL;
g_Program = "hlrad";
#ifdef ZHLT_PARAMFILE
int argcold = argc;
char ** argvold = argv;
{
int argc;
char ** argv;
ParseParamFile (argcold, argvold, argc, argv);
{
#endif
#ifdef ZHLT_CONSOLE
if (InitConsole (argc, argv) < 0)
Usage();
#endif
if (argc == 1)
Usage();
for (i = 1; i < argc; i++)
{
if (!strcasecmp(argv[i], "-dump"))
{
g_dumppatches = true;
}
#ifdef ZHLT_CONSOLE
else if (!strcasecmp(argv[i], "-console"))
{
#ifndef SYSTEM_WIN32
Warning("The option '-console #' is only valid for Windows.");
#endif
if (i + 1 < argc)
++i;
else
Usage();
}
#endif
else if (!strcasecmp(argv[i], "-bounce"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_numbounce = atoi(argv[++i]);
if (g_numbounce > 1000)
{
Log("Unexpectedly large value (>1000) for '-bounce'\n");
Usage();
}
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-dev"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_developer = (developer_level_t)atoi(argv[++i]);
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-verbose"))
{
g_verbose = true;
}
else if (!strcasecmp(argv[i], "-noinfo"))
{
g_info = false;
}
else if (!strcasecmp(argv[i], "-threads"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_numthreads = atoi(argv[++i]);
if (g_numthreads < 1)
{
Log("Expected value of at least 1 for '-threads'\n");
Usage();
}
}
else
{
Usage();
}
}
#ifdef SYSTEM_WIN32
else if (!strcasecmp(argv[i], "-estimate"))
{
g_estimate = true;
}
#endif
#ifdef SYSTEM_POSIX
else if (!strcasecmp(argv[i], "-noestimate"))
{
g_estimate = false;
}
#endif
#ifdef ZHLT_NETVIS
else if (!strcasecmp(argv[i], "-client"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_clientid = atoi(argv[++i]);
}
else
{
Usage();
}
}
#endif
#ifdef HLRAD_FASTMODE
else if (!strcasecmp (argv[i], "-fast"))
{
g_fastmode = true;
}
#endif
else if (!strcasecmp(argv[i], "-nolerp"))
{
g_lerp_enabled = false;
}
else if (!strcasecmp(argv[i], "-chop"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_chop = atof(argv[++i]);
if (g_chop < 1)
{
Log("expected value greater than 1 for '-chop'\n");
Usage();
}
if (g_chop < 32)
{
Log("Warning: Chop values below 32 are not recommended.");
}
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-texchop"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_texchop = atof(argv[++i]);
if (g_texchop < 1)
{
Log("expected value greater than 1 for '-texchop'\n");
Usage();
}
if (g_texchop < 32)
{
Log("Warning: texchop values below 16 are not recommended.");
}
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-notexscale"))
{
g_texscale = false;
}
else if (!strcasecmp(argv[i], "-nosubdivide"))
{
if (i < argc)
{
g_subdivide = false;
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-scale"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
// ------------------------------------------------------------------------
// Changes by Adam Foster - afoster@compsoc.man.ac.uk
// Munge monochrome lightscale into colour one
#ifdef HLRAD_WHOME
i++;
g_colour_lightscale[0] = (float)atof(argv[i]);
g_colour_lightscale[1] = (float)atof(argv[i]);
g_colour_lightscale[2] = (float)atof(argv[i]);
#else
g_lightscale = (float)atof(argv[++i]);
#endif
// ------------------------------------------------------------------------
}
else
{
Usage();
}
}
#ifndef HLRAD_ARG_MISC
else if (!strcasecmp(argv[i], "-falloff"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_falloff = (float)atoi(argv[++i]);
if ((g_falloff != 1) && (g_falloff != 2))
{
Log("-falloff must be 1 or 2\n");
Usage();
}
}
else
{
Usage();
}
}
#endif
else if (!strcasecmp(argv[i], "-fade"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_fade = (float)atof(argv[++i]);
if (g_fade < 0.0)
{
Log("-fade must be a positive number\n");
Usage();
}
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-ambient"))
{
if (i + 3 < argc)
{
g_ambient[0] = (float)atof(argv[++i]) * 128;
g_ambient[1] = (float)atof(argv[++i]) * 128;
g_ambient[2] = (float)atof(argv[++i]) * 128;
}
else
{
Error("expected three color values after '-ambient'\n");
}
}
#ifndef HLRAD_FinalLightFace_VL
else if (!strcasecmp(argv[i], "-maxlight"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_maxlight = (float)atof(argv[++i]) * 128;
if (g_maxlight <= 0)
{
Log("expected positive value after '-maxlight'\n");
Usage();
}
}
else
{
Usage();
}
}
#endif
#ifdef HLRAD_PRESERVELIGHTMAPCOLOR
else if (!strcasecmp(argv[i], "-limiter"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_limitthreshold = atof(argv[++i]);
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-drawoverload"))
{
g_drawoverload = true;
}
#endif
else if (!strcasecmp(argv[i], "-lights"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
user_lights = argv[++i];
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-circus"))
{
g_circus = true;
}
else if (!strcasecmp(argv[i], "-noskyfix"))
{
g_sky_lighting_fix = false;
}
else if (!strcasecmp(argv[i], "-incremental"))
{
g_incremental = true;
}
else if (!strcasecmp(argv[i], "-chart"))
{
g_chart = true;
}
else if (!strcasecmp(argv[i], "-low"))
{
g_threadpriority = eThreadPriorityLow;
}
else if (!strcasecmp(argv[i], "-high"))
{
g_threadpriority = eThreadPriorityHigh;
}
else if (!strcasecmp(argv[i], "-nolog"))
{
g_log = false;
}
else if (!strcasecmp(argv[i], "-gamma"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
// ------------------------------------------------------------------------
// Changes by Adam Foster - afoster@compsoc.man.ac.uk
// Munge values from original, monochrome gamma into colour gamma
#ifdef HLRAD_WHOME
i++;
g_colour_qgamma[0] = (float)atof(argv[i]);
g_colour_qgamma[1] = (float)atof(argv[i]);
g_colour_qgamma[2] = (float)atof(argv[i]);
#else
g_qgamma = (float)atof(argv[++i]);
#endif
// ------------------------------------------------------------------------
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-dlight"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_dlight_threshold = (float)atof(argv[++i]);
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-extra"))
{
g_extra = true;
}
else if (!strcasecmp(argv[i], "-sky"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_indirect_sun = (float)atof(argv[++i]);
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-smooth"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_smoothing_value = atof(argv[++i]);
}
else
{
Usage();
}
}
#ifdef HLRAD_CUSTOMSMOOTH
else if (!strcasecmp(argv[i], "-smooth2"))
{
if (i + 1 < argc)
{
g_smoothing_value_2 = atof(argv[++i]);
}
else
{
Usage();
}
}
#endif
else if (!strcasecmp(argv[i], "-coring"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_coring = (float)atof(argv[++i]);
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-texdata"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
int x = atoi(argv[++i]) * 1024;
//if (x > g_max_map_miptex) //--vluzacn
{
g_max_map_miptex = x;
}
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-lightdata")) //lightdata
{
if (i + 1 < argc) //--vluzacn
{
int x = atoi(argv[++i]) * 1024;
//if (x > g_max_map_lightdata) //--vluzacn
{
g_max_map_lightdata = x;
}
}
else
{
Usage();
}
}
#ifdef HLRAD_ARG_MISC
else if (!strcasecmp (argv[i], "-vismatrix"))
{
if (i + 1 < argc)
{
const char *value = argv[++i];
if (!strcasecmp (value, "normal"))
{
g_method = eMethodVismatrix;
}
else if (!strcasecmp (value, "sparse"))
{
g_method = eMethodSparseVismatrix;
}
else if (!strcasecmp (value, "off"))
{
g_method = eMethodNoVismatrix;
}
else
{
Error ("Unknown vismatrix type: '%s'", value);
}
}
else
{
Usage ();
}
}
#else
else if (!strcasecmp(argv[i], "-sparse"))
{
g_method = eMethodSparseVismatrix;
}
else if (!strcasecmp(argv[i], "-nomatrix"))
{
g_method = eMethodNoVismatrix;
}
#endif
#ifdef HLRAD_SUNSPREAD
else if (!strcasecmp (argv[i], "-nospread"))
{
g_allow_spread = false;
}
#endif
else if (!strcasecmp(argv[i], "-nopaque")
|| !strcasecmp(argv[i], "-noopaque")) //--vluzacn
{
g_allow_opaques = false;
}
else if (!strcasecmp(argv[i], "-dscale"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_direct_scale = (float)atof(argv[++i]);
}
else
{
Usage();
}
}
// ------------------------------------------------------------------------
// Changes by Adam Foster - afoster@compsoc.man.ac.uk
#ifdef HLRAD_WHOME
else if (!strcasecmp(argv[i], "-colourgamma"))
{
if (i + 3 < argc)
{
g_colour_qgamma[0] = (float)atof(argv[++i]);
g_colour_qgamma[1] = (float)atof(argv[++i]);
g_colour_qgamma[2] = (float)atof(argv[++i]);
}
else
{
Error("expected three color values after '-colourgamma'\n");
}
}
else if (!strcasecmp(argv[i], "-colourscale"))
{
if (i + 3 < argc)
{
g_colour_lightscale[0] = (float)atof(argv[++i]);
g_colour_lightscale[1] = (float)atof(argv[++i]);
g_colour_lightscale[2] = (float)atof(argv[++i]);
}
else
{
Error("expected three color values after '-colourscale'\n");
}
}
else if (!strcasecmp(argv[i], "-colourjitter"))
{
if (i + 3 < argc)
{
g_colour_jitter_hack[0] = (float)atof(argv[++i]);
g_colour_jitter_hack[1] = (float)atof(argv[++i]);
g_colour_jitter_hack[2] = (float)atof(argv[++i]);
}
else
{
Error("expected three color values after '-colourjitter'\n");
}
}
else if (!strcasecmp(argv[i], "-jitter"))
{
if (i + 3 < argc)
{
g_jitter_hack[0] = (float)atof(argv[++i]);
g_jitter_hack[1] = (float)atof(argv[++i]);
g_jitter_hack[2] = (float)atof(argv[++i]);
}
else
{
Error("expected three color values after '-jitter'\n");
}
}
#ifndef HLRAD_ARG_MISC
else if (!strcasecmp(argv[i], "-nodiffuse"))
{
g_diffuse_hack = false;
}
else if (!strcasecmp(argv[i], "-nospotpoints"))
{
g_spotlight_hack = false;
}
#endif
#ifndef HLRAD_CUSTOMTEXLIGHT // no softlight hack
else if (!strcasecmp(argv[i], "-softlight"))
{
if (i + 4 < argc)
{
g_softlight_hack[0] = (float)atof(argv[++i]);
g_softlight_hack[1] = (float)atof(argv[++i]);
g_softlight_hack[2] = (float)atof(argv[++i]);
g_softlight_hack_distance = (float)atof(argv[++i]);
}
else
{
Error("expected three color scalers and a distance after '-softlight'\n");
}
}
#endif
#endif
// ------------------------------------------------------------------------
#ifdef HLRAD_HULLU
else if (!strcasecmp(argv[i], "-customshadowwithbounce"))
{
g_customshadow_with_bouncelight = true;
}
else if (!strcasecmp(argv[i], "-rgbtransfers"))
{
g_rgb_transfers = true;
}
#endif
#ifdef ZHLT_PROGRESSFILE // AJM
else if (!strcasecmp(argv[i], "-progressfile"))
{
if (i + 1 < argc) //added "1" .--vluzacn
{
g_progressfile = argv[++i];
}
else
{
Log("Error: -progressfile: expected path to progress file following parameter\n");
Usage();
}
}
#endif
#ifdef HLRAD_TRANSTOTAL_HACK
else if (!strcasecmp(argv[i], "-bscale"))
{
#ifdef HLRAD_REFLECTIVITY
Error ("'-bscale' is obsolete.");
#endif
if (i + 1 < argc)
{
g_transtotal_hack = (float)atof(argv[++i]);
}
else
{
Usage();
}
}
#endif
#ifdef HLRAD_MINLIGHT
else if (!strcasecmp(argv[i], "-minlight"))
{
if (i + 1 < argc)
{
int v = atoi(argv[++i]);
v = qmax (0, qmin (v, 255));
g_minlight = (unsigned char)v;
}
else
{
Usage();
}
}
#endif
#ifdef HLRAD_SOFTSKY
else if (!strcasecmp(argv[i], "-softsky"))
{
if (i + 1 < argc)
{
g_softsky = (bool)atoi(argv[++i]);
}
else
{
Usage();
}
}
#endif
#ifdef HLRAD_DEBUG_DRAWPOINTS
else if (!strcasecmp(argv[i], "-drawpatch"))
{
g_drawpatch = true;
}
else if (!strcasecmp(argv[i], "-drawsample"))
{
g_drawsample = true;
if (i + 4 < argc)
{
g_drawsample_origin[0] = atof(argv[++i]);
g_drawsample_origin[1] = atof(argv[++i]);
g_drawsample_origin[2] = atof(argv[++i]);
g_drawsample_radius = atof(argv[++i]);
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-drawedge"))
{
g_drawedge = true;
}
else if (!strcasecmp(argv[i], "-drawlerp"))
{
g_drawlerp = true;
}
#endif
#ifdef HLRAD_AVOIDWALLBLEED
else if (!strcasecmp(argv[i], "-drawnudge"))
{
g_drawnudge = true;
}
#endif
#ifdef ZHLT_XASH
else if (!strcasecmp (argv[i], "-drawdirection"))
{
g_drawdirection = true;
}
#endif
#ifdef HLRAD_TRANSFERDATA_COMPRESS
else if (!strcasecmp(argv[i], "-compress"))
{
if (i + 1 < argc)
{
g_transfer_compress_type = (float_type)atoi(argv[++i]);
if (g_transfer_compress_type < 0 || g_transfer_compress_type >= float_type_count)
Usage();
}
else
{
Usage();
}
}
else if (!strcasecmp(argv[i], "-rgbcompress"))
{
if (i + 1 < argc)
{
g_rgbtransfer_compress_type = (vector_type)atoi(argv[++i]);
if (g_rgbtransfer_compress_type < 0 || g_rgbtransfer_compress_type >= vector_type_count)
Usage();
}
else
{
Usage();
}
}
#endif
#ifdef HLRAD_TRANSLUCENT
else if (!strcasecmp (argv[i], "-depth"))
{
if (i + 1 < argc)
{
g_translucentdepth = atof(argv[++i]);
}
else
{
Usage ();
}
}
#endif
#ifdef HLRAD_OPAQUE_BLOCK
else if (!strcasecmp (argv[i], "-blockopaque"))
{
if (i + 1 < argc)
{
g_blockopaque = atoi(argv[++i]);
}
else
{
Usage ();
}
}
#endif
#ifdef HLRAD_TEXTURE
else if (!strcasecmp (argv[i], "-waddir"))
{
if (i + 1 < argc)
{
AddWadFolder (argv[++i]);
}
else
{
Usage ();
}
}
else if (!strcasecmp (argv[i], "-notextures"))
{
g_notextures = true;
}
#endif
#ifdef HLRAD_REFLECTIVITY
else if (!strcasecmp (argv[i], "-texreflectgamma"))
{
if (i + 1 < argc)
{
g_texreflectgamma = atof (argv[++i]);
}
else
{
Usage ();
}
}
else if (!strcasecmp (argv[i], "-texreflectscale"))
{
if (i + 1 < argc)
{
g_texreflectscale = atof (argv[++i]);
}
else
{
Usage ();
}
}
#endif
#ifdef HLRAD_BLUR
else if (!strcasecmp (argv[i], "-blur"))
{
if (i + 1 < argc)
{
g_blur = atof (argv[++i]);
}
else
{
Usage ();
}
}
#endif
#ifdef HLRAD_ACCURATEBOUNCE
else if (!strcasecmp (argv[i], "-noemitterrange"))
{
g_noemitterrange = true;
}
#endif
#ifdef HLRAD_AVOIDWALLBLEED
else if (!strcasecmp (argv[i], "-nobleedfix"))
{
g_bleedfix = false;
}
#endif
#ifdef HLRAD_TEXLIGHTGAP
else if (!strcasecmp (argv[i], "-texlightgap"))
{
if (i + 1 < argc)
{
g_texlightgap = atof (argv[++i]);
}
else
{
Usage ();
}
}
#endif
#ifdef ZHLT_LANGFILE
else if (!strcasecmp (argv[i], "-lang"))
{
if (i + 1 < argc)
{
char tmp[_MAX_PATH];
#ifdef SYSTEM_WIN32
GetModuleFileName (NULL, tmp, _MAX_PATH);
#else
safe_strncpy (tmp, argv[0], _MAX_PATH);
#endif
LoadLangFile (argv[++i], tmp);
}
else
{
Usage();
}
}
#endif
else if (argv[i][0] == '-')
{
Log("Unknown option \"%s\"\n", argv[i]);
Usage();
}
else if (!mapname_from_arg)
{
mapname_from_arg = argv[i];
}
else
{
Log("Unknown option \"%s\"\n", argv[i]);
Usage();
}
}
if (!mapname_from_arg)
{
Log("No mapname specified\n");
Usage();
}
g_smoothing_threshold = (float)cos(g_smoothing_value * (Q_PI / 180.0));
safe_strncpy(g_Mapname, mapname_from_arg, _MAX_PATH);
FlipSlashes(g_Mapname);
StripExtension(g_Mapname);
OpenLog(g_clientid);
atexit(CloseLog);
ThreadSetDefault();
ThreadSetPriority(g_threadpriority);
#ifdef ZHLT_PARAMFILE
LogStart(argcold, argvold);
{
int i;
Log("Arguments: ");
for (i = 1; i < argc; i++)
{
if (strchr(argv[i], ' '))
{
Log("\"%s\" ", argv[i]);
}
else
{
Log("%s ", argv[i]);
}
}
Log("\n");
}
#else
LogStart(argc, argv);
#endif
CheckForErrorLog();
#ifdef HLRAD_TRANSFERDATA_COMPRESS
compress_compatability_test ();
#endif
#ifdef ZHLT_64BIT_FIX
#ifdef PLATFORM_CAN_CALC_EXTENT
hlassume (CalcFaceExtents_test (), assume_first);
#endif
#endif
dtexdata_init();
atexit(dtexdata_free);
#ifdef ZHLT_XASH
g_max_map_dlitdata = g_max_map_lightdata;
g_ddlitdata = (byte *)malloc (g_max_map_dlitdata);
hlassume (g_ddlitdata != NULL, assume_NoMemory);
safe_snprintf (g_dlitfile, _MAX_PATH, "%s.dlit", g_Mapname);
#endif
// END INIT
// BEGIN RAD
start = I_FloatTime();
// normalise maxlight
#ifndef HLRAD_FinalLightFace_VL
if (g_maxlight > 255)
g_maxlight = 255;
#endif
#ifdef ZHLT_DEFAULTEXTENSION_FIX
safe_snprintf(g_source, _MAX_PATH, "%s.bsp", g_Mapname);
#else
strcpy(g_source, mapname_from_arg);
StripExtension(g_source);
DefaultExtension(g_source, ".bsp");
#endif
LoadBSPFile(g_source);
#ifdef ZHLT_64BIT_FIX
#ifndef PLATFORM_CAN_CALC_EXTENT
char extentfilename[_MAX_PATH];
safe_snprintf (extentfilename, _MAX_PATH, "%s.ext", g_Mapname);
Log ("Loading extent file '%s'\n", extentfilename);
if (!q_exists (extentfilename))
{
hlassume (false, assume_NO_EXTENT_FILE);
}
LoadExtentFile (extentfilename);
#endif
#endif
ParseEntities();
#ifdef HLRAD_FASTMODE
if (g_fastmode)
{
g_numbounce = 0;
#ifdef HLRAD_SOFTSKY
g_softsky = false;
#endif
}
#endif
Settings();
#ifdef ZHLT_EMBEDLIGHTMAP
DeleteEmbeddedLightmaps ();
#endif
#ifdef HLRAD_TEXTURE
LoadTextures ();
#endif
LoadRadFiles(g_Mapname, user_lights, argv[0]);
#ifdef HLRAD_CUSTOMCHOP
ReadCustomChopValue ();
#endif
#ifdef HLRAD_CUSTOMSMOOTH
ReadCustomSmoothValue ();
#endif
#ifdef HLRAD_TRANSLUCENT
ReadTranslucentTextures ();
#endif
#ifdef HLRAD_DIVERSE_LIGHTING
ReadLightingCone ();
#endif
#ifdef HLRAD_CUSTOMSMOOTH
g_smoothing_threshold_2 = g_smoothing_value_2 < 0 ? g_smoothing_threshold : (float)cos(g_smoothing_value_2 * (Q_PI / 180.0));
#endif
#ifdef HLRAD_STYLE_CORING
{
int style;
for (style = 0; style < ALLSTYLES; ++style)
{
g_corings[style] = style? g_coring: 0;
}
}
#endif
#ifdef HLRAD_ARG_MISC
if (g_direct_scale != 1.0)
{
Warning ("dscale value should be 1.0 for final compile.\nIf you need to adjust the bounced light, use the '-texreflectscale' and '-texreflectgamma' options instead.");
}
#ifdef HLRAD_WHOME
if (g_colour_lightscale[0] != 2.0 || g_colour_lightscale[1] != 2.0 || g_colour_lightscale[2] != 2.0)
#else
if (g_lightscale != 2.0)
#endif
{
Warning ("light scale value should be 2.0 for final compile.\nValues other than 2.0 will result in incorrect interpretation of light_environment's brightness when the engine loads the map.");
}
#endif
#ifdef HLRAD_DEBUG_DRAWPOINTS
if (g_drawlerp)
{
g_direct_scale = 0.0;
}
#endif
if (!g_visdatasize)
{
#ifdef HLRAD_WITHOUTVIS
Warning("No vis information.");
#else
Warning("No vis information, direct lighting only.");
g_numbounce = 0;
g_ambient[0] = g_ambient[1] = g_ambient[2] = 0.1f;
#endif
}
#ifdef HLRAD_BLUR
if (g_blur < 1.0)
{
g_blur = 1.0;
}
#endif
RadWorld();
FreeOpaqueFaceList();
FreePatches();
#ifdef HLRAD_OPAQUE_NODE
DeleteOpaqueNodes ();
#endif
#ifdef ZHLT_EMBEDLIGHTMAP
#ifdef HLRAD_TEXTURE
EmbedLightmapInTextures ();
#endif
#endif
if (g_chart)
PrintBSPFileSizes();
#ifdef ZHLT_XASH
WriteDlitData (g_dlitfile);
free (g_ddlitdata);
g_ddlitdata = NULL;
#endif
WriteBSPFile(g_source);
end = I_FloatTime();
LogTimeElapsed(end - start);
// END RAD
#ifdef ZHLT_PARAMFILE
}
}
#endif
return 0;
}