mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-16 17:01:53 +00:00
[qfvis] Use simd vector code
While whether it's any faster is debatable (it's slightly slower, but many more portals are being tested due to different rounding in the base vis stage), it's certainly easier to read.
This commit is contained in:
parent
b6ab832ed4
commit
ff4cd84891
4 changed files with 236 additions and 145 deletions
|
@ -74,6 +74,7 @@ extern pthread_rwlock_t *portal_locks;
|
|||
|
||||
#include "QF/cmem.h"
|
||||
#include "QF/set.h"
|
||||
#include "QF/simd/vec4f.h"
|
||||
|
||||
#define MAX_PORTALS 32768
|
||||
#define PORTALFILE "PRT1"
|
||||
|
@ -87,7 +88,9 @@ typedef struct winding_s {
|
|||
struct winding_s *next;
|
||||
qboolean original; // don't free, it's part of the portal
|
||||
unsigned numpoints;
|
||||
vec3_t points[MAX_PORTALS_ON_CLUSTER]; // variable sized
|
||||
int id;
|
||||
int thread;
|
||||
vec4f_t points[MAX_PORTALS_ON_CLUSTER]; // variable sized
|
||||
} winding_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -98,9 +101,9 @@ typedef enum {
|
|||
} vstatus_t;
|
||||
|
||||
typedef struct {
|
||||
plane_t plane; // normal pointing into neighbor
|
||||
vec4f_t plane; // normal pointing into neighbor
|
||||
vspheref_t sphere; // bounding sphere
|
||||
int cluster; // neighbor
|
||||
sphere_t sphere; // bounding sphere
|
||||
winding_t *winding;
|
||||
vstatus_t status;
|
||||
set_t *visbits;
|
||||
|
@ -110,8 +113,8 @@ typedef struct {
|
|||
} portal_t;
|
||||
|
||||
typedef struct seperating_plane_s {
|
||||
vec4f_t plane; // from portal is on positive side
|
||||
struct seperating_plane_s *next;
|
||||
plane_t plane; // from portal is on positive side
|
||||
} sep_t;
|
||||
|
||||
typedef struct passage_s {
|
||||
|
@ -122,9 +125,9 @@ typedef struct passage_s {
|
|||
|
||||
typedef struct cluster_s {
|
||||
int numportals;
|
||||
int visofs;
|
||||
passage_t *passages;
|
||||
portal_t *portals[MAX_PORTALS_ON_CLUSTER];
|
||||
int visofs;
|
||||
} cluster_t;
|
||||
|
||||
typedef struct pstack_s {
|
||||
|
@ -132,8 +135,8 @@ typedef struct pstack_s {
|
|||
cluster_t *cluster; ///< the cluster being sub-vised
|
||||
winding_t *source_winding; ///< clipped source portal winding
|
||||
portal_t *pass_portal; ///< the portal exiting from the cluster
|
||||
vec4f_t pass_plane; ///< plane of the pass portal
|
||||
winding_t *pass_winding; ///< clipped pass portal winding
|
||||
plane_t pass_plane; ///< plane of the pass portal
|
||||
set_t *mightsee;
|
||||
sep_t *separators[2];
|
||||
} pstack_t;
|
||||
|
@ -173,6 +176,7 @@ typedef struct threaddata_s {
|
|||
memsuper_t *memsuper; ///< per-thread memory pool
|
||||
set_pool_t set_pool;
|
||||
int id;
|
||||
int winding_id;
|
||||
} threaddata_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -198,7 +202,8 @@ extern byte *uncompressed;
|
|||
|
||||
void FreeWinding (threaddata_t *thread, winding_t *w);
|
||||
winding_t *NewWinding (threaddata_t *thread, int points);
|
||||
winding_t *ClipWinding (threaddata_t *thread, winding_t *in, const plane_t *split, qboolean keepon);
|
||||
winding_t *ClipWinding (threaddata_t *thread, winding_t *in, vec4f_t split,
|
||||
qboolean keepon);
|
||||
winding_t *CopyWinding (threaddata_t *thread, const winding_t *w);
|
||||
|
||||
void ClusterFlow (int clusternum);
|
||||
|
|
|
@ -84,24 +84,25 @@ SimpleFlood (basethread_t *thread, portal_t *srcportal, int clusternum)
|
|||
}
|
||||
|
||||
static inline int
|
||||
test_sphere (sphere_t *sphere, plane_t *plane)
|
||||
test_sphere (const vspheref_t *sphere, vec4f_t plane)
|
||||
{
|
||||
float d;
|
||||
int front, back;
|
||||
const vec4f_t zero = {};
|
||||
float r = sphere->radius;
|
||||
vec4f_t eps = { r, r, r, r };
|
||||
vec4f_t d = _mm_addsub_ps (zero, dotf (sphere->center, plane));
|
||||
vec4i_t c = (d - eps) >= 0;
|
||||
|
||||
d = DotProduct (sphere->center, plane->normal) - plane->dist;
|
||||
front = (d >= sphere->radius);
|
||||
back = (d <= -sphere->radius);
|
||||
return front - back;
|
||||
c = (vec4i_t) _mm_hsub_epi32 ((__m128i) c, (__m128i) c);
|
||||
return c[0];
|
||||
}
|
||||
|
||||
void
|
||||
PortalBase (basethread_t *thread, portal_t *portal)
|
||||
{
|
||||
unsigned i, j, k;
|
||||
float d;
|
||||
portal_t *tp;
|
||||
winding_t *winding;
|
||||
unsigned i, j, k;
|
||||
vec4f_t d;
|
||||
portal_t *tp;
|
||||
winding_t *winding;
|
||||
int tp_side, portal_side;
|
||||
|
||||
i = portal - portals;
|
||||
|
@ -118,14 +119,14 @@ PortalBase (basethread_t *thread, portal_t *portal)
|
|||
// visibility.
|
||||
|
||||
// First check using the bounding spheres of the two portals.
|
||||
tp_side = test_sphere (&tp->sphere, &portal->plane);
|
||||
tp_side = test_sphere (&tp->sphere, portal->plane);
|
||||
if (tp_side < 0) {
|
||||
// The test portal definitely is entirely behind the portal's
|
||||
// plane.
|
||||
thread->spherecull++;
|
||||
continue; // entirely behind
|
||||
}
|
||||
portal_side = test_sphere (&portal->sphere, &tp->plane);
|
||||
portal_side = test_sphere (&portal->sphere, tp->plane);
|
||||
if (portal_side > 0) {
|
||||
// The portal definitely is entirely in front of the test
|
||||
// portal's plane.
|
||||
|
@ -138,9 +139,8 @@ PortalBase (basethread_t *thread, portal_t *portal)
|
|||
// do a more refined check.
|
||||
winding = tp->winding;
|
||||
for (k = 0; k < winding->numpoints; k++) {
|
||||
d = DotProduct (winding->points[k],
|
||||
portal->plane.normal) - portal->plane.dist;
|
||||
if (d > ON_EPSILON)
|
||||
d = dotf (winding->points[k], portal->plane);
|
||||
if (d[0] > ON_EPSILON)
|
||||
break;
|
||||
}
|
||||
if (k == winding->numpoints) {
|
||||
|
@ -154,9 +154,8 @@ PortalBase (basethread_t *thread, portal_t *portal)
|
|||
// do a more refined check.
|
||||
winding = portal->winding;
|
||||
for (k = 0; k < winding->numpoints; k++) {
|
||||
d = DotProduct (winding->points[k],
|
||||
tp->plane.normal) - tp->plane.dist;
|
||||
if (d < -ON_EPSILON)
|
||||
d = dotf (winding->points[k], tp->plane);
|
||||
if (d[0] < -ON_EPSILON)
|
||||
break;
|
||||
}
|
||||
if (k == winding->numpoints) {
|
||||
|
|
|
@ -133,48 +133,47 @@ test_zero (float d)
|
|||
}
|
||||
|
||||
static int
|
||||
calc_plane (const vec3_t v1, const vec3_t v2, int flip, const vec3_t p,
|
||||
plane_t *plane)
|
||||
calc_plane (vec4f_t v1, vec4f_t v2, int flip, vec4f_t p, vec4f_t *plane)
|
||||
{
|
||||
vec_t length;
|
||||
vec4f_t length;
|
||||
|
||||
if (flip < 0) {
|
||||
//CrossProduct (v2, v1, plane.normal);
|
||||
plane->normal[0] = v2[1] * v1[2] - v2[2] * v1[1];
|
||||
plane->normal[1] = v2[2] * v1[0] - v2[0] * v1[2];
|
||||
plane->normal[2] = v2[0] * v1[1] - v2[1] * v1[0];
|
||||
(*plane)[0] = v2[1] * v1[2] - v2[2] * v1[1];
|
||||
(*plane)[1] = v2[2] * v1[0] - v2[0] * v1[2];
|
||||
(*plane)[2] = v2[0] * v1[1] - v2[1] * v1[0];
|
||||
} else {
|
||||
//CrossProduct (v1, v2, plane.normal);
|
||||
plane->normal[0] = v1[1] * v2[2] - v1[2] * v2[1];
|
||||
plane->normal[1] = v1[2] * v2[0] - v1[0] * v2[2];
|
||||
plane->normal[2] = v1[0] * v2[1] - v1[1] * v2[0];
|
||||
(*plane)[0] = v1[1] * v2[2] - v1[2] * v2[1];
|
||||
(*plane)[1] = v1[2] * v2[0] - v1[0] * v2[2];
|
||||
(*plane)[2] = v1[0] * v2[1] - v1[1] * v2[0];
|
||||
}
|
||||
(*plane)[3] = 0;
|
||||
|
||||
length = DotProduct (plane->normal, plane->normal);
|
||||
length = dotf (*plane, *plane);
|
||||
|
||||
// if points don't make a valid plane, skip it
|
||||
if (length < ON_EPSILON)
|
||||
if (length[0] < ON_EPSILON)
|
||||
return 0;
|
||||
|
||||
length = 1 / sqrt (length);
|
||||
VectorScale (plane->normal, length, plane->normal);
|
||||
plane->dist = DotProduct (p, plane->normal);
|
||||
*plane /= vsqrtf (length);
|
||||
(*plane)[3] = -dotf (p, *plane)[0];
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
test_plane (const plane_t *plane, const winding_t *pass, int index)
|
||||
test_plane (vec4f_t plane, const winding_t *pass, int index)
|
||||
{
|
||||
int s1, s2;
|
||||
int k;
|
||||
vec_t d;
|
||||
vec4f_t d;
|
||||
|
||||
k = (index + 1) % pass->numpoints;
|
||||
d = DotProduct (pass->points[k], plane->normal) - plane->dist;
|
||||
s1 = test_zero (d);
|
||||
d = dotf (pass->points[k], plane);
|
||||
s1 = test_zero (d[0]);
|
||||
k = (index + pass->numpoints - 1) % pass->numpoints;
|
||||
d = DotProduct (pass->points[k], plane->normal) - plane->dist;
|
||||
s2 = test_zero (d);
|
||||
d = dotf (pass->points[k], plane);
|
||||
s2 = test_zero (d[0]);
|
||||
if (s1 == 0 && s2 == 0)
|
||||
return 0;
|
||||
if (s1 < 0 || s2 < 0)
|
||||
|
@ -183,32 +182,30 @@ test_plane (const plane_t *plane, const winding_t *pass, int index)
|
|||
}
|
||||
|
||||
static inline sep_t *
|
||||
create_separator (threaddata_t *thread, const plane_t *src_pl,
|
||||
const vec3_t p1, const vec3_t v1,
|
||||
create_separator (threaddata_t *thread, vec4f_t src_pl, vec4f_t p1, vec4f_t v1,
|
||||
const winding_t *pass, int index, int flip)
|
||||
{
|
||||
int fliptest;
|
||||
vec_t d;
|
||||
vec3_t v2;
|
||||
plane_t plane;
|
||||
vec4f_t d;
|
||||
vec4f_t v2;
|
||||
vec4f_t plane;
|
||||
sep_t *sep;
|
||||
|
||||
d = DotProduct (pass->points[index], src_pl->normal) - src_pl->dist;
|
||||
if ((fliptest = test_zero (d)) == 0)
|
||||
d = dotf (pass->points[index], src_pl);
|
||||
if ((fliptest = test_zero (d[0])) == 0)
|
||||
return 0; // The point lies in the source plane
|
||||
|
||||
VectorSubtract (pass->points[index], p1, v2);
|
||||
v2 = pass->points[index] - p1;
|
||||
if (!calc_plane (v1, v2, fliptest, pass->points[index], &plane))
|
||||
return 0; // point does not form a valid plane
|
||||
|
||||
if (!test_plane (&plane, pass, index))
|
||||
if (!test_plane (plane, pass, index))
|
||||
return 0; // not the right point
|
||||
|
||||
sep = new_separator (thread);
|
||||
// flip the normal if we want the back side
|
||||
if (flip) {
|
||||
VectorNegate (plane.normal, sep->plane.normal);
|
||||
sep->plane.dist = -plane.dist;
|
||||
sep->plane = -plane;
|
||||
} else {
|
||||
sep->plane = plane;
|
||||
}
|
||||
|
@ -233,20 +230,20 @@ create_separator (threaddata_t *thread, const plane_t *src_pl,
|
|||
*/
|
||||
static sep_t *
|
||||
FindSeparators (threaddata_t *thread,
|
||||
const winding_t *source, const plane_t src_pl,
|
||||
const winding_t *source, vec4f_t src_pl,
|
||||
const winding_t *pass, int flip)
|
||||
{
|
||||
unsigned i, j, l;
|
||||
vec3_t v1;
|
||||
vec4f_t v1;
|
||||
|
||||
sep_t *separators = 0, *sep;
|
||||
|
||||
for (i = 0; i < source->numpoints; i++) {
|
||||
l = (i + 1) % source->numpoints;
|
||||
VectorSubtract (source->points[l], source->points[i], v1);
|
||||
v1 = source->points[l] - source->points[i];
|
||||
|
||||
for (j = 0; j < pass->numpoints; j++) {
|
||||
sep = create_separator (thread, &src_pl, source->points[i], v1,
|
||||
sep = create_separator (thread, src_pl, source->points[i], v1,
|
||||
pass, j, flip);
|
||||
if (sep) {
|
||||
sep->next = separators;
|
||||
|
@ -259,12 +256,13 @@ FindSeparators (threaddata_t *thread,
|
|||
}
|
||||
|
||||
static winding_t *
|
||||
ClipToSeparators (threaddata_t *thread, const sep_t *separators, winding_t *target)
|
||||
ClipToSeparators (threaddata_t *thread, const sep_t *separators,
|
||||
winding_t *target)
|
||||
{
|
||||
const sep_t *sep;
|
||||
|
||||
for (sep = separators; target && sep; sep = sep->next) {
|
||||
target = ClipWinding (thread, target, &sep->plane, false);
|
||||
target = ClipWinding (thread, target, sep->plane, false);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
@ -304,7 +302,6 @@ mightsee_more (set_t *might, const set_t *prev_might, const set_t *test,
|
|||
RecursiveClusterFlow
|
||||
|
||||
Flood fill through the clusters
|
||||
If src_portal is NULL, this is the originating cluster
|
||||
*/
|
||||
static void
|
||||
RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
||||
|
@ -315,8 +312,8 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
cluster_t *cluster;
|
||||
pstack_t *stack;
|
||||
portal_t *target_portal;
|
||||
plane_t backplane;
|
||||
const plane_t *source_plane, *pass_plane;
|
||||
vec4f_t backplane;
|
||||
vec4f_t source_plane, pass_plane;
|
||||
const winding_t *pass_winding;
|
||||
winding_t *source_winding, *target_winding;
|
||||
|
||||
|
@ -344,9 +341,9 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
might = stack->mightsee;
|
||||
vis = thread->clustervis;
|
||||
|
||||
source_plane = &thread->pstack_head.pass_plane;
|
||||
source_plane = thread->pstack_head.pass_plane;
|
||||
pass_winding = prevstack->pass_winding;
|
||||
pass_plane = &prevstack->pass_plane;
|
||||
pass_plane = prevstack->pass_plane;
|
||||
|
||||
// check all portals for flowing into other clusters
|
||||
for (i = 0; i < cluster->numportals; i++) {
|
||||
|
@ -363,11 +360,13 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
}
|
||||
|
||||
// get plane of target_portal, point normal into the neighbor cluster
|
||||
VectorNegate (target_portal->plane.normal, backplane.normal);
|
||||
backplane.dist = -target_portal->plane.dist;
|
||||
backplane = -target_portal->plane;
|
||||
|
||||
if (_VectorCompare (pass_plane->normal, backplane.normal))
|
||||
vec4f_t diff = vabsf (pass_plane - backplane);
|
||||
vec4i_t cmp = diff > (vec4f_t) {0.001, 0.001, 0.001, 0.001};
|
||||
if (!(cmp[0] || cmp[1] || cmp[2])) { // dist isn't interesting
|
||||
continue; // can't go out a coplanar face
|
||||
}
|
||||
|
||||
thread->stats.portalcheck++;
|
||||
|
||||
|
@ -398,7 +397,7 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
// if it gets clipped away, earlier stack levels will get corrupted
|
||||
source_winding = CopyWinding (thread, prevstack->source_winding);
|
||||
|
||||
source_winding = ClipWinding (thread, source_winding, &backplane, false);
|
||||
source_winding = ClipWinding (thread, source_winding, backplane, false);
|
||||
if (!source_winding) {
|
||||
FreeWinding (thread, target_winding);
|
||||
continue;
|
||||
|
@ -412,7 +411,7 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
if (!stack->separators[0])
|
||||
stack->separators[0] = FindSeparators (thread,
|
||||
source_winding,
|
||||
*source_plane,
|
||||
source_plane,
|
||||
pass_winding, 0);
|
||||
target_winding = ClipToSeparators (thread,
|
||||
stack->separators[0],
|
||||
|
@ -431,7 +430,7 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
if (!stack->separators[1])
|
||||
stack->separators[1] = FindSeparators (thread,
|
||||
pass_winding,
|
||||
*pass_plane,
|
||||
pass_plane,
|
||||
source_winding, 1);
|
||||
target_winding = ClipToSeparators (thread,
|
||||
stack->separators[1],
|
||||
|
@ -466,7 +465,7 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
if (options.level > 3) {
|
||||
winding_t *old = source_winding;
|
||||
sep_t *sep;
|
||||
sep = FindSeparators (thread, pass_winding, *pass_plane,
|
||||
sep = FindSeparators (thread, pass_winding, pass_plane,
|
||||
target_winding, 1);
|
||||
source_winding = ClipToSeparators (thread, sep, source_winding);
|
||||
free_separators (thread, sep);
|
||||
|
|
|
@ -134,17 +134,19 @@ EndThreads (void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
PlaneFromWinding (winding_t *winding, plane_t *plane)
|
||||
static vec4f_t
|
||||
PlaneFromWinding (winding_t *winding)
|
||||
{
|
||||
vec3_t v1, v2;
|
||||
vec4f_t plane;
|
||||
vec4f_t v1, v2;
|
||||
|
||||
// calc plane using CW winding
|
||||
VectorSubtract (winding->points[2], winding->points[1], v1);
|
||||
VectorSubtract (winding->points[0], winding->points[1], v2);
|
||||
CrossProduct (v2, v1, plane->normal);
|
||||
_VectorNormalize (plane->normal);
|
||||
plane->dist = DotProduct (winding->points[0], plane->normal);
|
||||
v1 = winding->points[2] - winding->points[1];
|
||||
v2 = winding->points[0] - winding->points[1];
|
||||
plane = normalf (crossf (v2, v1));
|
||||
// negative so dot(point, plane) includes -dist (point[3] = 1)
|
||||
plane[3] = -dotf (winding->points[0], plane)[0];
|
||||
return plane;
|
||||
}
|
||||
|
||||
winding_t *
|
||||
|
@ -160,6 +162,8 @@ NewWinding (threaddata_t *thread, int points)
|
|||
winding = CMEMALLOC (13, winding_t, thread->winding, thread->memsuper);
|
||||
memset (winding, 0, size);
|
||||
thread->stats.winding_alloc++;
|
||||
winding->id = thread->winding_id++;
|
||||
winding->thread = thread->id;
|
||||
|
||||
return winding;
|
||||
}
|
||||
|
@ -188,6 +192,8 @@ CopyWinding (threaddata_t *thread, const winding_t *w)
|
|||
memcpy (copy, w, size);
|
||||
copy->original = false;
|
||||
thread->stats.winding_alloc++;
|
||||
copy->id = thread->winding_id++;
|
||||
copy->thread = thread->id;
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
@ -198,12 +204,111 @@ NewFlippedWinding (threaddata_t *thread, const winding_t *w)
|
|||
unsigned i;
|
||||
|
||||
flipped = NewWinding (thread, w->numpoints);
|
||||
for (i = 0; i < w->numpoints; i++)
|
||||
VectorCopy (w->points[i], flipped->points[w->numpoints - 1 - i]);
|
||||
for (i = 0; i < w->numpoints; i++) {
|
||||
flipped->points[w->numpoints - 1 - i] = w->points[i];
|
||||
}
|
||||
flipped->numpoints = w->numpoints;
|
||||
return flipped;
|
||||
}
|
||||
|
||||
static vec4i_t
|
||||
signeps (vec4f_t dist)
|
||||
{
|
||||
const vec4f_t zero = {};
|
||||
const vec4f_t eps = { ON_EPSILON, ON_EPSILON, ON_EPSILON, ON_EPSILON };
|
||||
vec4f_t d = _mm_addsub_ps (zero, dist);
|
||||
vec4i_t c = (d - eps) > 0;
|
||||
c = (vec4i_t) _mm_hsub_epi32 ((__m128i) c, (__m128i) c);
|
||||
return c;
|
||||
}
|
||||
|
||||
static vec4f_t
|
||||
split_edge (const vec4f_t *points, const vec4f_t *dists,
|
||||
int ind1, int ind2, vec4f_t split)
|
||||
{
|
||||
vec4f_t p1 = points[ind1];
|
||||
vec4f_t p2 = points[ind2];
|
||||
vec4f_t d1 = dists[ind1];
|
||||
vec4f_t d2 = dists[ind2];
|
||||
// avoid nan/inf in w: d1's w is never 0 (would not be here if it was)
|
||||
// so the multiply ensures d1.w - d2.w cannot be 0 and thus d1.w/diff
|
||||
// will not result in division by 0
|
||||
static const vec4f_t one = { 1, 1, 1, 0 };
|
||||
vec4f_t d = d1 / (d1 - d2 * one);
|
||||
vec4f_t mid = p1 + d * (p2 - p1);
|
||||
|
||||
// avoid roundoff error when possible by forcing the appropriate
|
||||
// component to the split-plane's distance when the split-plane's
|
||||
// normal is signed-canonical.
|
||||
// "nan" because 0x7fffffff is nan when viewed as a float
|
||||
static const vec4f_t onenan = { 1, 1, 1, ~0u >> 1 };
|
||||
static const vec4i_t nan = { ~0u >> 1, ~0u >> 1, ~0u >> 1, ~0u >> 1};
|
||||
vec4i_t x = _mm_and_ps (split, (__m128) nan) == onenan;
|
||||
// plane vector has -dist in w
|
||||
vec4f_t y = _mm_and_ps (split, (__m128) x) * -split[3];
|
||||
mid = _mm_blendv_ps (mid, y, (__m128) x);
|
||||
if (isnan (mid[0])) *(int *) 0 = 0;
|
||||
return mid;
|
||||
}
|
||||
|
||||
static inline int __attribute__((const))
|
||||
is_not_on (int x)
|
||||
{
|
||||
return x & 1;
|
||||
}
|
||||
|
||||
static inline int __attribute__((const))
|
||||
is_back (int x)
|
||||
{
|
||||
return x & 2;
|
||||
}
|
||||
|
||||
static inline int __attribute__((const))
|
||||
is_not_back (unsigned x)
|
||||
{
|
||||
return ~x & 2;
|
||||
}
|
||||
|
||||
static inline int __attribute__((const))
|
||||
is_front (unsigned x)
|
||||
{
|
||||
return is_not_on (x) & (is_not_back (x) >> 1);
|
||||
}
|
||||
|
||||
static inline int __attribute__((const))
|
||||
is_back_front (unsigned x, unsigned y)
|
||||
{
|
||||
return (is_back (x) >> 1) & is_front (y);
|
||||
}
|
||||
|
||||
static inline int __attribute__((const))
|
||||
is_front_back (unsigned x, unsigned y)
|
||||
{
|
||||
return is_front (x) & (is_back (y) >> 1);
|
||||
}
|
||||
|
||||
static inline int __attribute__((const))
|
||||
is_transition (unsigned x, unsigned y)
|
||||
{
|
||||
return is_back_front (x, y) | is_front_back (x, y);
|
||||
}
|
||||
|
||||
static inline void
|
||||
test_point (vec4f_t split, const vec4f_t *points, int index, vec4f_t *dists,
|
||||
int *sides, unsigned *counts)
|
||||
{
|
||||
dists[index] = dotf (points[index], split);
|
||||
sides[index] = signeps (dists[index])[0];
|
||||
counts[sides[index]]++;
|
||||
}
|
||||
|
||||
#undef SIDE_FRONT
|
||||
#undef SIDE_BACK
|
||||
#undef SIDE_ON
|
||||
#define SIDE_FRONT 1
|
||||
#define SIDE_BACK -1
|
||||
#define SIDE_ON 0
|
||||
|
||||
/*
|
||||
ClipWinding
|
||||
|
||||
|
@ -216,86 +321,68 @@ NewFlippedWinding (threaddata_t *thread, const winding_t *w)
|
|||
it will be clipped away.
|
||||
*/
|
||||
winding_t *
|
||||
ClipWinding (threaddata_t *thread, winding_t *in, const plane_t *split, qboolean keepon)
|
||||
ClipWinding (threaddata_t *thread, winding_t *in, vec4f_t split,
|
||||
qboolean keepon)
|
||||
{
|
||||
unsigned maxpts, i, j;
|
||||
int counts[3], sides[MAX_POINTS_ON_WINDING];
|
||||
vec_t dot;
|
||||
vec_t dists[MAX_POINTS_ON_WINDING];
|
||||
vec_t *p1, *p2;
|
||||
vec3_t mid;
|
||||
unsigned maxpts = 0;
|
||||
unsigned i;
|
||||
unsigned _counts[3];
|
||||
unsigned *const counts = _counts + 1;
|
||||
int *const sides = alloca ((in->numpoints + 1) * sizeof (int));
|
||||
vec4f_t *const dists = alloca ((in->numpoints + 1) * sizeof (vec4f_t));
|
||||
winding_t *neww;
|
||||
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
counts[SIDE_FRONT] = counts[SIDE_ON] = counts[SIDE_BACK] = 0;
|
||||
|
||||
// determine sides for each point
|
||||
for (i = 0; i < in->numpoints; i++) {
|
||||
dot = DotProduct (in->points[i], split->normal);
|
||||
dot -= split->dist;
|
||||
dists[i] = dot;
|
||||
if (dot > ON_EPSILON)
|
||||
sides[i] = SIDE_FRONT;
|
||||
else if (dot < -ON_EPSILON)
|
||||
sides[i] = SIDE_BACK;
|
||||
else {
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
test_point (split, in->points, 0, dists, sides, counts);
|
||||
for (i = 1; i < in->numpoints; i++) {
|
||||
test_point (split, in->points, i, dists, sides, counts);
|
||||
maxpts += is_transition (sides[i - 1], sides[i]);
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
maxpts += is_transition (sides[i - 1], sides[i]);
|
||||
|
||||
if (keepon && !counts[0] && !counts[1])
|
||||
if (keepon && counts[SIDE_ON] == in->numpoints) {
|
||||
return in;
|
||||
|
||||
if (!counts[0]) {
|
||||
}
|
||||
if (!counts[SIDE_FRONT]) {
|
||||
FreeWinding (thread, in);
|
||||
return NULL;
|
||||
}
|
||||
if (!counts[1])
|
||||
if (!counts[SIDE_BACK]) {
|
||||
return in;
|
||||
}
|
||||
|
||||
maxpts = in->numpoints + 4; // can't use counts[0] + 2 because
|
||||
// of fp grouping errors
|
||||
maxpts += in->numpoints - counts[SIDE_BACK];
|
||||
neww = NewWinding (thread, maxpts);
|
||||
|
||||
for (i = 0; i < in->numpoints; i++) {
|
||||
p1 = in->points[i];
|
||||
|
||||
if (sides[i] == SIDE_ON) {
|
||||
VectorCopy (p1, neww->points[neww->numpoints]);
|
||||
neww->numpoints++;
|
||||
neww->points[neww->numpoints++] = in->points[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sides[i] == SIDE_FRONT) {
|
||||
VectorCopy (p1, neww->points[neww->numpoints]);
|
||||
neww->numpoints++;
|
||||
neww->points[neww->numpoints++] = in->points[i];
|
||||
}
|
||||
|
||||
if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
|
||||
if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i]) {
|
||||
continue;
|
||||
|
||||
// generate a split point
|
||||
p2 = in->points[(i + 1) % in->numpoints];
|
||||
|
||||
dot = dists[i] / (dists[i] - dists[i + 1]);
|
||||
for (j = 0; j < 3; j++) {
|
||||
// avoid round off error when possible
|
||||
if (split->normal[j] == 1)
|
||||
mid[j] = split->dist;
|
||||
else if (split->normal[j] == -1)
|
||||
mid[j] = -split->dist;
|
||||
else
|
||||
mid[j] = p1[j] + dot * (p2[j] - p1[j]);
|
||||
}
|
||||
|
||||
VectorCopy (mid, neww->points[neww->numpoints]);
|
||||
neww->numpoints++;
|
||||
vec4f_t mid = split_edge (in->points, dists, i,
|
||||
(i + 1) % in->numpoints, split);
|
||||
neww->points[neww->numpoints++] = mid;
|
||||
}
|
||||
|
||||
if (neww->numpoints > maxpts)
|
||||
Sys_Error ("ClipWinding: points exceeded estimate");
|
||||
if (neww->numpoints < maxpts) {
|
||||
Sys_Error ("ClipWinding: not all points copied: n:%u m:%u i:%u %u %u %u",
|
||||
neww->numpoints, maxpts, in->numpoints,
|
||||
counts[SIDE_BACK], counts[SIDE_ON], counts[SIDE_FRONT]);
|
||||
}
|
||||
if (neww->numpoints > maxpts) {
|
||||
Sys_Error ("ClipWinding: points exceeded estimate: n:%u m:%u",
|
||||
neww->numpoints, maxpts);
|
||||
}
|
||||
// free the original winding
|
||||
FreeWinding (thread, in);
|
||||
|
||||
|
@ -1033,10 +1120,10 @@ LoadPortals (char *name)
|
|||
int read_leafs = 0;
|
||||
int clusternums[2];
|
||||
cluster_t *cluster;
|
||||
plane_t plane;
|
||||
vec4f_t plane;
|
||||
portal_t *portal;
|
||||
winding_t *winding;
|
||||
sphere_t sphere;
|
||||
vspheref_t sphere;
|
||||
QFile *f;
|
||||
|
||||
if (!strcmp (name, "-"))
|
||||
|
@ -1158,6 +1245,7 @@ LoadPortals (char *name)
|
|||
Sys_Error ("LoadPortals: reading portal %u", i);
|
||||
line = err;
|
||||
}
|
||||
winding->points[j][3] = 1;
|
||||
|
||||
while (isspace ((byte) *line))
|
||||
line++;
|
||||
|
@ -1165,10 +1253,11 @@ LoadPortals (char *name)
|
|||
Sys_Error ("LoadPortals: reading portal %u", i);
|
||||
}
|
||||
|
||||
sphere = SmallestEnclosingBall_vf(winding->points, winding->numpoints);
|
||||
//printf (VEC4F_FMT" %.9g\n", VEC4_EXP (sphere.center), sphere.radius);
|
||||
|
||||
// calc plane
|
||||
PlaneFromWinding (winding, &plane);
|
||||
sphere = SmallestEnclosingBall((const vec_t(*)[3])winding->points,
|
||||
winding->numpoints);
|
||||
plane = PlaneFromWinding (winding);
|
||||
|
||||
// create forward portal
|
||||
cluster = &clusters[clusternums[0]];
|
||||
|
@ -1178,8 +1267,7 @@ LoadPortals (char *name)
|
|||
cluster->numportals++;
|
||||
|
||||
portal->winding = winding;
|
||||
VectorNegate (plane.normal, portal->plane.normal);
|
||||
portal->plane.dist = -plane.dist; // plane is for CW, portal is CCW
|
||||
portal->plane = -plane; // plane is for CW, portal is CCW
|
||||
portal->cluster = clusternums[1];
|
||||
portal->sphere = sphere;
|
||||
portal++;
|
||||
|
|
Loading…
Reference in a new issue