vhlt/hlrad/qradutil.cpp

1052 lines
27 KiB
C++

#include "qrad.h"
static dplane_t backplanes[MAX_MAP_PLANES];
#ifdef HLRAD_HuntForWorld_EDGE_FIX
dleaf_t* PointInLeaf_Worst_r(int nodenum, const vec3_t point)
{
vec_t dist;
dnode_t* node;
dplane_t* plane;
while (nodenum >= 0)
{
node = &g_dnodes[nodenum];
plane = &g_dplanes[node->planenum];
dist = DotProduct(point, plane->normal) - plane->dist;
if (dist > HUNT_WALL_EPSILON)
{
nodenum = node->children[0];
}
else if (dist < -HUNT_WALL_EPSILON)
{
nodenum = node->children[1];
}
else
{
dleaf_t* result[2];
result[0] = PointInLeaf_Worst_r(node->children[0], point);
result[1] = PointInLeaf_Worst_r(node->children[1], point);
if (result[0] == g_dleafs || result[0]->contents == CONTENTS_SOLID)
return result[0];
if (result[1] == g_dleafs || result[1]->contents == CONTENTS_SOLID)
return result[1];
if (result[0]->contents == CONTENTS_SKY)
return result[0];
if (result[1]->contents == CONTENTS_SKY)
return result[1];
#ifdef HLRAD_WATERBLOCKLIGHT
if (result[0]->contents == result[1]->contents)
return result[0];
return g_dleafs;
#else
return result[0];
#endif
}
}
return &g_dleafs[-nodenum - 1];
}
dleaf_t* PointInLeaf_Worst(const vec3_t point)
{
return PointInLeaf_Worst_r(0, point);
}
#endif
dleaf_t* PointInLeaf(const vec3_t point)
{
int nodenum;
vec_t dist;
dnode_t* node;
dplane_t* plane;
nodenum = 0;
while (nodenum >= 0)
{
node = &g_dnodes[nodenum];
plane = &g_dplanes[node->planenum];
dist = DotProduct(point, plane->normal) - plane->dist;
if (dist >= 0.0)
{
nodenum = node->children[0];
}
else
{
nodenum = node->children[1];
}
}
return &g_dleafs[-nodenum - 1];
}
/*
* ==============
* PatchPlaneDist
* Fixes up patch planes for brush models with an origin brush
* ==============
*/
vec_t PatchPlaneDist(const patch_t* const patch)
{
const dplane_t* plane = getPlaneFromFaceNumber(patch->faceNumber);
return plane->dist + DotProduct(g_face_offset[patch->faceNumber], plane->normal);
}
void MakeBackplanes()
{
int i;
for (i = 0; i < g_numplanes; i++)
{
backplanes[i].dist = -g_dplanes[i].dist;
VectorSubtract(vec3_origin, g_dplanes[i].normal, backplanes[i].normal);
}
}
const dplane_t* getPlaneFromFace(const dface_t* const face)
{
if (!face)
{
Error("getPlaneFromFace() face was NULL\n");
}
if (face->side)
{
return &backplanes[face->planenum];
}
else
{
return &g_dplanes[face->planenum];
}
}
const dplane_t* getPlaneFromFaceNumber(const unsigned int faceNumber)
{
dface_t* face = &g_dfaces[faceNumber];
if (face->side)
{
return &backplanes[face->planenum];
}
else
{
return &g_dplanes[face->planenum];
}
}
// Returns plane adjusted for face offset (for origin brushes, primarily used in the opaque code)
void getAdjustedPlaneFromFaceNumber(unsigned int faceNumber, dplane_t* plane)
{
dface_t* face = &g_dfaces[faceNumber];
const vec_t* face_offset = g_face_offset[faceNumber];
plane->type = (planetypes)0;
if (face->side)
{
vec_t dist;
VectorCopy(backplanes[face->planenum].normal, plane->normal);
dist = DotProduct(plane->normal, face_offset);
plane->dist = backplanes[face->planenum].dist + dist;
}
else
{
vec_t dist;
VectorCopy(g_dplanes[face->planenum].normal, plane->normal);
dist = DotProduct(plane->normal, face_offset);
plane->dist = g_dplanes[face->planenum].dist + dist;
}
}
// Will modify the plane with the new dist
void TranslatePlane(dplane_t* plane, const vec_t* delta)
{
#ifdef HLRAD_MATH_VL
plane->dist += DotProduct (plane->normal, delta);
#else
vec3_t proj;
vec_t magnitude;
ProjectionPoint(delta, plane->normal, proj);
magnitude = VectorLength(proj);
if (DotProduct(plane->normal, delta) > 0) //if zero, magnitude will be zero.
{
plane->dist += magnitude;
}
else
{
plane->dist -= magnitude;
}
#endif
}
// HuntForWorld will never return CONTENTS_SKY or CONTENTS_SOLID leafs
dleaf_t* HuntForWorld(vec_t* point, const vec_t* plane_offset, const dplane_t* plane, int hunt_size, vec_t hunt_scale, vec_t hunt_offset)
{
dleaf_t* leaf;
int x, y, z;
int a;
vec3_t current_point;
vec3_t original_point;
vec3_t best_point;
dleaf_t* best_leaf = NULL;
vec_t best_dist = 99999999.0;
vec3_t scales;
dplane_t new_plane = *plane;
#ifndef HLRAD_HuntForWorld_FIX
if (hunt_scale < 0.1)
{
hunt_scale = 0.1;
}
#endif
scales[0] = 0.0;
scales[1] = -hunt_scale;
scales[2] = hunt_scale;
VectorCopy(point, best_point);
VectorCopy(point, original_point);
TranslatePlane(&new_plane, plane_offset);
#ifndef HLRAD_HuntForWorld_FIX
if (!hunt_size)
{
hunt_size = DEFAULT_HUNT_SIZE;
}
#endif
#ifdef HLRAD_HuntForWorld_FIX
for (a = 0; a < hunt_size; a++)
#else
for (a = 1; a < hunt_size; a++)
#endif
{
for (x = 0; x < 3; x++)
{
current_point[0] = original_point[0] + (scales[x % 3] * a);
for (y = 0; y < 3; y++)
{
current_point[1] = original_point[1] + (scales[y % 3] * a);
for (z = 0; z < 3; z++)
{
#ifdef HLRAD_HuntForWorld_FIX
if (a == 0)
{
if (x || y || z)
continue;
}
#endif
vec3_t delta;
vec_t dist;
current_point[2] = original_point[2] + (scales[z % 3] * a);
SnapToPlane(&new_plane, current_point, hunt_offset);
VectorSubtract(current_point, original_point, delta);
#ifdef HLRAD_MATH_VL
dist = DotProduct(delta, delta);
#else
dist = VectorLength(delta);
#endif
#ifdef HLRAD_OPAQUE_BLOCK
{
int x;
for (x = 0; x < g_opaque_face_count; x++)
{
if (TestPointOpaque (g_opaque_face_list[x].modelnum, g_opaque_face_list[x].origin, g_opaque_face_list[x].block, current_point))
break;
}
if (x < g_opaque_face_count)
continue;
}
#endif
if (dist < best_dist)
{
#ifdef HLRAD_HuntForWorld_EDGE_FIX
if ((leaf = PointInLeaf_Worst(current_point)) != g_dleafs)
#else
if ((leaf = PointInLeaf(current_point)) != g_dleafs)
#endif
{
if ((leaf->contents != CONTENTS_SKY) && (leaf->contents != CONTENTS_SOLID))
{
if (x || y || z)
{
//dist = best_dist;
#ifdef HLRAD_HuntForWorld_FIX
best_dist = dist;
#endif
best_leaf = leaf;
VectorCopy(current_point, best_point);
continue;
}
else
{
VectorCopy(current_point, point);
return leaf;
}
}
}
}
}
}
}
if (best_leaf)
{
break;
}
}
VectorCopy(best_point, point);
return best_leaf;
}
#ifdef HLRAD_GROWSAMPLE
// ApplyMatrix: (x y z 1)T -> matrix * (x y z 1)T
void ApplyMatrix (const matrix_t &m, const vec3_t in, vec3_t &out)
{
int i;
hlassume (&in[0] != &out[0], assume_first);
VectorCopy (m.v[3], out);
for (i = 0; i < 3; i++)
{
VectorMA (out, in[i], m.v[i], out);
}
}
// ApplyMatrixOnPlane: (x y z -dist) -> (x y z -dist) * matrix
void ApplyMatrixOnPlane (const matrix_t &m_inverse, const vec3_t in_normal, vec_t in_dist, vec3_t &out_normal, vec_t &out_dist)
// out_normal is not normalized
{
int i;
hlassume (&in_normal[0] != &out_normal[0], assume_first);
for (i = 0; i < 3; i++)
{
out_normal[i] = DotProduct (in_normal, m_inverse.v[i]);
}
out_dist = - (DotProduct (in_normal, m_inverse.v[3]) - in_dist);
}
void MultiplyMatrix (const matrix_t &m_left, const matrix_t &m_right, matrix_t &m)
// The following two processes are equivalent:
// 1) ApplyMatrix (m1, v_in, v_temp), ApplyMatrix (m2, v_temp, v_out);
// 2) MultiplyMatrix (m2, m1, m), ApplyMatrix (m, v_in, v_out);
{
int i, j;
const vec_t lastrow[4] = {0, 0, 0, 1};
hlassume (&m != &m_left && &m != &m_right, assume_first);
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
m.v[j][i] = m_left.v[0][i] * m_right.v[j][0]
+ m_left.v[1][i] * m_right.v[j][1]
+ m_left.v[2][i] * m_right.v[j][2]
+ m_left.v[3][i] * lastrow[j];
}
}
}
matrix_t MultiplyMatrix (const matrix_t &m_left, const matrix_t &m_right)
{
matrix_t m;
MultiplyMatrix (m_left, m_right, m);
return m;
}
void MatrixForScale (const vec3_t center, vec_t scale, matrix_t &m)
{
int i;
for (i = 0; i < 3; i++)
{
VectorClear (m.v[i]);
m.v[i][i] = scale;
}
VectorScale (center, 1 - scale, m.v[3]);
}
matrix_t MatrixForScale (const vec3_t center, vec_t scale)
{
matrix_t m;
MatrixForScale (center, scale, m);
return m;
}
vec_t CalcMatrixSign (const matrix_t &m)
{
vec3_t v;
CrossProduct (m.v[0], m.v[1], v);
return DotProduct (v, m.v[2]);
}
void TranslateWorldToTex (int facenum, matrix_t &m)
// without g_face_offset
{
dface_t *f;
texinfo_t *ti;
const dplane_t *fp;
int i;
f = &g_dfaces[facenum];
ti = &g_texinfo[f->texinfo];
fp = getPlaneFromFace (f);
for (i = 0; i < 3; i++)
{
m.v[i][0] = ti->vecs[0][i];
m.v[i][1] = ti->vecs[1][i];
m.v[i][2] = fp->normal[i];
}
m.v[3][0] = ti->vecs[0][3];
m.v[3][1] = ti->vecs[1][i];
m.v[3][2] = -fp->dist;
}
bool InvertMatrix (const matrix_t &m, matrix_t &m_inverse)
{
double texplanes[2][4];
double faceplane[4];
int i;
double texaxis[2][3];
double normalaxis[3];
double det, sqrlen1, sqrlen2, sqrlen3;
double texorg[3];
for (i = 0; i < 4; i++)
{
texplanes[0][i] = m.v[i][0];
texplanes[1][i] = m.v[i][1];
faceplane[i] = m.v[i][2];
}
sqrlen1 = DotProduct (texplanes[0], texplanes[0]);
sqrlen2 = DotProduct (texplanes[1], texplanes[1]);
sqrlen3 = DotProduct (faceplane, faceplane);
if (sqrlen1 <= NORMAL_EPSILON * NORMAL_EPSILON || sqrlen2 <= NORMAL_EPSILON * NORMAL_EPSILON || sqrlen3 <= NORMAL_EPSILON * NORMAL_EPSILON)
// s gradient, t gradient or face normal is too close to 0
{
return false;
}
CrossProduct (texplanes[0], texplanes[1], normalaxis);
det = DotProduct (normalaxis, faceplane);
if (det * det <= sqrlen1 * sqrlen2 * sqrlen3 * NORMAL_EPSILON * NORMAL_EPSILON)
// s gradient, t gradient and face normal are coplanar
{
return false;
}
VectorScale (normalaxis, 1 / det, normalaxis);
CrossProduct (texplanes[1], faceplane, texaxis[0]);
VectorScale (texaxis[0], 1 / det, texaxis[0]);
CrossProduct (faceplane, texplanes[0], texaxis[1]);
VectorScale (texaxis[1], 1 / det, texaxis[1]);
VectorScale (normalaxis, -faceplane[3], texorg);
VectorMA (texorg, -texplanes[0][3], texaxis[0], texorg);
VectorMA (texorg, -texplanes[1][3], texaxis[1], texorg);
VectorCopy (texaxis[0], m_inverse.v[0]);
VectorCopy (texaxis[1], m_inverse.v[1]);
VectorCopy (normalaxis, m_inverse.v[2]);
VectorCopy (texorg, m_inverse.v[3]);
return true;
}
typedef struct
{
bool valid;
#ifdef HLRAD_AVOIDWALLBLEED
bool nudged;
#endif
vec_t best_s; // FindNearestPosition will return this value
vec_t best_t;
vec3_t pos; // with DEFAULT_HUNT_OFFSET
}
position_t;
// Size of potision_t (21) * positions per sample (9) * max number of samples (max AllocBlock (64) * 128 * 128)
// = 200MB of RAM
// But they are freed before BuildVisLeafs, so it's not a problem.
typedef struct
{
bool valid;
int facenum;
vec3_t face_offset;
vec3_t face_centroid;
matrix_t worldtotex;
matrix_t textoworld;
Winding *facewinding;
dplane_t faceplane;
Winding *facewindingwithoffset;
dplane_t faceplanewithoffset;
Winding *texwinding;
dplane_t texplane; // (0, 0, 1, 0) or (0, 0, -1, 0)
vec3_t texcentroid;
vec3_t start; // s_start, t_start, 0
vec3_t step; // s_step, t_step, 0
int w; // number of s
int h; // number of t
position_t *grid; // [h][w]
}
positionmap_t;
static positionmap_t g_face_positions[MAX_MAP_FACES];
static bool IsPositionValid (positionmap_t *map, const vec3_t &pos_st, vec3_t &pos_out, bool usephongnormal = true, bool doedgetest = true, int hunt_size = 2, vec_t hunt_scale = 0.2)
{
vec3_t pos;
vec3_t pos_normal;
vec_t hunt_offset;
ApplyMatrix (map->textoworld, pos_st, pos);
VectorAdd (pos, map->face_offset, pos);
if (usephongnormal)
{
GetPhongNormal (map->facenum, pos, pos_normal);
}
else
{
VectorCopy (map->faceplanewithoffset.normal, pos_normal);
}
VectorMA (pos, DEFAULT_HUNT_OFFSET, pos_normal, pos);
hunt_offset = DotProduct (pos, map->faceplanewithoffset.normal) - map->faceplanewithoffset.dist; // might be smaller than DEFAULT_HUNT_OFFSET
// push the point 0.2 units around to avoid walls
if (!HuntForWorld (pos, vec3_origin, &map->faceplanewithoffset, hunt_size, hunt_scale, hunt_offset))
{
return false;
}
if (doedgetest && !point_in_winding_noedge (*map->facewindingwithoffset, map->faceplanewithoffset, pos, DEFAULT_EDGE_WIDTH))
{
// if the sample has gone beyond face boundaries, be careful that it hasn't passed a wall
vec3_t test;
#ifdef HLRAD_HULLU
vec3_t transparency;
#endif
#ifdef HLRAD_OPAQUE_STYLE
int opaquestyle;
#endif
VectorCopy (pos, test);
snap_to_winding_noedge (*map->facewindingwithoffset, map->faceplanewithoffset, test, DEFAULT_EDGE_WIDTH, 4 * DEFAULT_EDGE_WIDTH);
if (!HuntForWorld (test, vec3_origin, &map->faceplanewithoffset, hunt_size, hunt_scale, hunt_offset))
{
return false;
}
if (TestLine (pos, test) != CONTENTS_EMPTY)
{
return false;
}
if (TestSegmentAgainstOpaqueList (pos, test
#ifdef HLRAD_HULLU
, transparency
#endif
#ifdef HLRAD_OPAQUE_STYLE
, opaquestyle
#endif
) == true
#ifdef HLRAD_OPAQUE_STYLE
|| opaquestyle != -1
#endif
)
{
return false;
}
}
VectorCopy (pos, pos_out);
return true;
}
static void CalcSinglePosition (positionmap_t *map, int is, int it)
{
position_t *p;
vec_t smin, smax, tmin, tmax;
dplane_t clipplanes[4];
const vec3_t v_s = {1, 0, 0};
const vec3_t v_t = {0, 1, 0};
Winding *zone;
p = &map->grid[is + map->w * it];
smin = map->start[0] + is * map->step[0];
smax = map->start[0] + (is + 1) * map->step[0];
tmin = map->start[1] + it * map->step[1];
tmax = map->start[1] + (it + 1) * map->step[1];
VectorScale (v_s, 1, clipplanes[0].normal); clipplanes[0].dist = smin;
VectorScale (v_s, -1, clipplanes[1].normal); clipplanes[1].dist = -smax;
VectorScale (v_t, 1, clipplanes[2].normal); clipplanes[2].dist = tmin;
VectorScale (v_t, -1, clipplanes[3].normal); clipplanes[3].dist = -tmax;
#ifdef HLRAD_AVOIDWALLBLEED
p->nudged = true; // it's nudged unless it can get its position directly from its s,t
#endif
zone = new Winding (*map->texwinding);
for (int x = 0; x < 4 && zone->m_NumPoints > 0; x++)
{
zone->Clip (clipplanes[x], false);
}
if (zone->m_NumPoints == 0)
{
p->valid = false;
}
else
{
vec3_t original_st;
vec3_t test_st;
original_st[0] = map->start[0] + (is + 0.5) * map->step[0];
original_st[1] = map->start[1] + (it + 0.5) * map->step[1];
original_st[2] = 0.0;
p->valid = false;
if (!p->valid)
{
VectorCopy (original_st, test_st);
snap_to_winding (*zone, map->texplane, test_st);
if (IsPositionValid (map, test_st, p->pos))
{
p->valid = true;
#ifdef HLRAD_AVOIDWALLBLEED
p->nudged = false;
#endif
p->best_s = test_st[0];
p->best_t = test_st[1];
}
}
if (!p->valid)
{
zone->getCenter (test_st);
if (IsPositionValid (map, test_st, p->pos))
{
p->valid = true;
p->best_s = test_st[0];
p->best_t = test_st[1];
}
}
if (!p->valid
#ifdef HLRAD_FASTMODE
&& !g_fastmode
#endif
)
{
const int numnudges = 12;
vec3_t nudgelist[numnudges] = {{0.1, 0, 0}, {-0.1, 0, 0}, {0, 0.1, 0}, {0, -0.1, 0},
{0.3, 0, 0}, {-0.3, 0, 0}, {0, 0.3, 0}, {0, -0.3, 0},
{0.3, 0.3, 0}, {-0.3, 0.3, 0}, {-0.3, -0.3, 0}, {0.3, -0.3, 0}};
for (int i = 0; i < numnudges; i++)
{
VectorMultiply (nudgelist[i], map->step, test_st);
VectorAdd (test_st, original_st, test_st);
snap_to_winding (*zone, map->texplane, test_st);
if (IsPositionValid (map, test_st, p->pos))
{
p->valid = true;
p->best_s = test_st[0];
p->best_t = test_st[1];
break;
}
}
}
}
delete zone;
}
void FindFacePositions (int facenum)
// this function must be called after g_face_offset and g_face_centroids and g_edgeshare have been calculated
{
dface_t *f;
positionmap_t *map;
texinfo_t *ti;
vec3_t v;
const vec3_t v_up = {0, 0, 1};
vec_t density;
vec_t texmins[2], texmaxs[2];
int imins[2], imaxs[2];
int is, it;
int x;
int k;
f = &g_dfaces[facenum];
map = &g_face_positions[facenum];
map->valid = true;
map->facenum = facenum;
map->facewinding = NULL;
map->facewindingwithoffset = NULL;
map->texwinding = NULL;
map->grid = NULL;
ti = &g_texinfo[f->texinfo];
if (ti->flags & TEX_SPECIAL)
{
map->valid = false;
return;
}
VectorCopy (g_face_offset[facenum], map->face_offset);
VectorCopy (g_face_centroids[facenum], map->face_centroid);
TranslateWorldToTex (facenum, map->worldtotex);
if (!InvertMatrix (map->worldtotex, map->textoworld))
{
map->valid = false;
return;
}
map->facewinding = new Winding (*f);
map->faceplane = *getPlaneFromFace (f);
map->facewindingwithoffset = new Winding (map->facewinding->m_NumPoints);
for (x = 0; x < map->facewinding->m_NumPoints; x++)
{
VectorAdd (map->facewinding->m_Points[x], map->face_offset, map->facewindingwithoffset->m_Points[x]);
}
map->faceplanewithoffset = map->faceplane;
map->faceplanewithoffset.dist = map->faceplane.dist + DotProduct (map->face_offset, map->faceplane.normal);
map->texwinding = new Winding (map->facewinding->m_NumPoints);
for (x = 0; x < map->facewinding->m_NumPoints; x++)
{
ApplyMatrix (map->worldtotex, map->facewinding->m_Points[x], map->texwinding->m_Points[x]);
map->texwinding->m_Points[x][2] = 0.0;
}
map->texwinding->RemoveColinearPoints ();
VectorCopy (v_up, map->texplane.normal);
if (CalcMatrixSign (map->worldtotex) < 0.0)
{
map->texplane.normal[2] *= -1;
}
map->texplane.dist = 0.0;
if (map->texwinding->m_NumPoints == 0)
{
delete map->facewinding;
map->facewinding = NULL;
delete map->facewindingwithoffset;
map->facewindingwithoffset = NULL;
delete map->texwinding;
map->texwinding = NULL;
map->valid = false;
return;
}
VectorSubtract (map->face_centroid, map->face_offset, v);
ApplyMatrix (map->worldtotex, v, map->texcentroid);
map->texcentroid[2] = 0.0;
for (x = 0; x < map->texwinding->m_NumPoints; x++)
{
for (k = 0; k < 2; k++)
{
if (x == 0 || map->texwinding->m_Points[x][k] < texmins[k])
texmins[k] = map->texwinding->m_Points[x][k];
if (x == 0 || map->texwinding->m_Points[x][k] > texmaxs[k])
texmaxs[k] = map->texwinding->m_Points[x][k];
}
}
density = 3.0;
#ifdef HLRAD_FASTMODE
if (g_fastmode)
{
density = 1.0;
}
#endif
map->step[0] = (vec_t)TEXTURE_STEP / density;
map->step[1] = (vec_t)TEXTURE_STEP / density;
map->step[2] = 1.0;
for (k = 0; k < 2; k++)
{
imins[k] = (int)floor (texmins[k] / map->step[k] + 0.5 - ON_EPSILON);
imaxs[k] = (int)ceil (texmaxs[k] / map->step[k] - 0.5 + ON_EPSILON);
}
map->start[0] = (imins[0] - 0.5) * map->step[0];
map->start[1] = (imins[1] - 0.5) * map->step[1];
map->start[2] = 0.0;
map->w = imaxs[0] - imins[0] + 1;
map->h = imaxs[1] - imins[1] + 1;
if (map->w <= 0 || map->h <= 0 || (double)map->w * (double)map->h > 99999999)
{
delete map->facewinding;
map->facewinding = NULL;
delete map->facewindingwithoffset;
map->facewindingwithoffset = NULL;
delete map->texwinding;
map->texwinding = NULL;
map->valid = false;
return;
}
map->grid = (position_t *)malloc (map->w * map->h * sizeof (position_t));
hlassume (map->grid != NULL, assume_NoMemory);
for (it = 0; it < map->h; it++)
{
for (is = 0; is < map->w; is++)
{
CalcSinglePosition (map, is, it);
}
}
return;
}
void FreePositionMaps ()
{
#ifdef HLRAD_DEBUG_DRAWPOINTS
if (g_drawsample)
{
char name[_MAX_PATH+20];
sprintf (name, "%s_positions.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 i, j, k;
vec3_t v, dist;
for (i = 0; i < g_numfaces; ++i)
{
positionmap_t *map = &g_face_positions[i];
if (!map->valid)
{
continue;
}
for (j = 0; j < map->h * map->w; ++j)
{
if (!map->grid[j].valid)
{
continue;
}
VectorCopy (map->grid[j].pos, v);
VectorSubtract (v, g_drawsample_origin, dist);
if (DotProduct (dist, dist) < g_drawsample_radius * g_drawsample_radius)
{
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
for (int facenum = 0; facenum < g_numfaces; facenum++)
{
positionmap_t *map = &g_face_positions[facenum];
if (map->valid)
{
delete map->facewinding;
map->facewinding = NULL;
delete map->facewindingwithoffset;
map->facewindingwithoffset = NULL;
delete map->texwinding;
map->texwinding = NULL;
free (map->grid);
map->grid = NULL;
map->valid = false;
}
}
}
bool FindNearestPosition (int facenum, const Winding *texwinding, const dplane_t &texplane, vec_t s, vec_t t, vec3_t &pos, vec_t *best_s, vec_t *best_t, vec_t *dist
#ifdef HLRAD_AVOIDWALLBLEED
, bool *nudged
#endif
)
{
positionmap_t *map;
vec3_t original_st;
int x;
int itmin, itmax, ismin, ismax;
const vec3_t v_s = {1, 0, 0};
const vec3_t v_t = {0, 1, 0};
int is;
int it;
vec3_t v;
bool found;
int best_is;
int best_it;
vec_t best_dist;
map = &g_face_positions[facenum];
if (!map->valid)
{
return false;
}
original_st[0] = s;
original_st[1] = t;
original_st[2] = 0.0;
if (point_in_winding (*map->texwinding, map->texplane, original_st, 4 * ON_EPSILON))
{
itmin = (int)ceil ((original_st[1] - map->start[1] - 2 * ON_EPSILON) / map->step[1]) - 1;
itmax = (int)floor ((original_st[1] - map->start[1] + 2 * ON_EPSILON) / map->step[1]);
ismin = (int)ceil ((original_st[0] - map->start[0] - 2 * ON_EPSILON) / map->step[0]) - 1;
ismax = (int)floor ((original_st[0] - map->start[0] + 2 * ON_EPSILON) / map->step[0]);
itmin = qmax (0, itmin);
itmax = qmin (itmax, map->h - 1);
ismin = qmax (0, ismin);
ismax = qmin (ismax, map->w - 1);
found = false;
#ifdef HLRAD_AVOIDWALLBLEED
bool best_nudged = true;
#endif
for (it = itmin; it <= itmax; it++)
{
for (is = ismin; is <= ismax; is++)
{
position_t *p;
vec3_t current_st;
vec_t d;
p = &map->grid[is + map->w * it];
if (!p->valid)
{
continue;
}
current_st[0] = p->best_s;
current_st[1] = p->best_t;
current_st[2] = 0.0;
VectorSubtract (current_st, original_st, v);
d = VectorLength (v);
if (!found ||
#ifdef HLRAD_AVOIDWALLBLEED
!p->nudged && best_nudged ||
p->nudged == best_nudged
&&
#endif
d < best_dist - 2 * ON_EPSILON)
{
found = true;
best_is = is;
best_it = it;
best_dist = d;
#ifdef HLRAD_AVOIDWALLBLEED
best_nudged = p->nudged;
#endif
}
}
}
if (found)
{
position_t *p;
p = &map->grid[best_is + map->w * best_it];
VectorCopy (p->pos, pos);
*best_s = p->best_s;
*best_t = p->best_t;
*dist = 0.0;
#ifdef HLRAD_AVOIDWALLBLEED
*nudged = p->nudged;
#endif
return true;
}
}
#ifdef HLRAD_AVOIDWALLBLEED
*nudged = true;
#endif
itmin = map->h;
itmax = -1;
ismin = map->w;
ismax = -1;
for (x = 0; x < texwinding->m_NumPoints; x++)
{
it = (int)floor ((texwinding->m_Points[x][1] - map->start[1] + 0.5 * ON_EPSILON) / map->step[1]);
itmin = qmin (itmin, it);
it = (int)ceil ((texwinding->m_Points[x][1] - map->start[1] - 0.5 * ON_EPSILON) / map->step[1]) - 1;
itmax = qmax (it, itmax);
is = (int)floor ((texwinding->m_Points[x][0] - map->start[0] + 0.5 * ON_EPSILON) / map->step[0]);
ismin = qmin (ismin, is);
is = (int)ceil ((texwinding->m_Points[x][0] - map->start[0] - 0.5 * ON_EPSILON) / map->step[0]) - 1;
ismax = qmax (is, ismax);
}
itmin = qmax (0, itmin);
itmax = qmin (itmax, map->h - 1);
ismin = qmax (0, ismin);
ismax = qmin (ismax, map->w - 1);
found = false;
for (it = itmin; it <= itmax; it++)
{
for (is = ismin; is <= ismax; is++)
{
position_t *p;
vec3_t current_st;
vec_t d;
p = &map->grid[is + map->w * it];
if (!p->valid)
{
continue;
}
current_st[0] = p->best_s;
current_st[1] = p->best_t;
current_st[2] = 0.0;
VectorSubtract (current_st, original_st, v);
d = VectorLength (v);
if (!found || d < best_dist - ON_EPSILON)
{
found = true;
best_is = is;
best_it = it;
best_dist = d;
}
}
}
if (found)
{
position_t *p;
p = &map->grid[best_is + map->w * best_it];
VectorCopy (p->pos, pos);
*best_s = p->best_s;
*best_t = p->best_t;
*dist = best_dist;
return true;
}
return false;
}
#endif