mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-14 17:01:22 +00:00
057a5cc624
I had forgotten to skip the refined tests when the sphere was entirely on the relevant side of the plane. Now BasePortalVis for gmsp3v2 takes 11s on my machine (it was 13 with the previous optimization and 15.9 before that). Also, write some comments describing how BasePortalVis works.
184 lines
4.5 KiB
C
184 lines
4.5 KiB
C
/*
|
|
base-vis.c
|
|
|
|
PVS PHS generator tool
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
Copyright (C) 2002 Colin Thompson
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <getopt.h>
|
|
#include <stdlib.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
# include <unistd.h>
|
|
#endif
|
|
#ifdef HAVE_IO_H
|
|
# include <io.h>
|
|
#endif
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif
|
|
#include <getopt.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "QF/bspfile.h"
|
|
#include "QF/cmd.h"
|
|
#include "QF/mathlib.h"
|
|
#include "QF/quakefs.h"
|
|
#include "QF/sys.h"
|
|
|
|
#include "vis.h"
|
|
#include "options.h"
|
|
|
|
static int clustersee;
|
|
static set_t *portalsee;
|
|
|
|
/*
|
|
This is a rough first-order aproximation that is used to trivially reject
|
|
some of the final calculations.
|
|
*/
|
|
static void
|
|
SimpleFlood (portal_t *srcportal, int clusternum)
|
|
{
|
|
int i;
|
|
cluster_t *cluster;
|
|
portal_t *portal;
|
|
|
|
if (set_is_member (srcportal->mightsee, clusternum))
|
|
return;
|
|
set_add (srcportal->mightsee, clusternum);
|
|
clustersee++;
|
|
|
|
cluster = &clusters[clusternum];
|
|
|
|
for (i = 0; i < cluster->numportals; i++) {
|
|
portal = cluster->portals[i];
|
|
if (!set_is_member (portalsee, portal - portals))
|
|
continue;
|
|
SimpleFlood (srcportal, portal->cluster);
|
|
}
|
|
}
|
|
|
|
static inline int
|
|
test_sphere (sphere_t *sphere, plane_t *plane)
|
|
{
|
|
float d;
|
|
int front, back;
|
|
|
|
d = DotProduct (sphere->center, plane->normal) - plane->dist;
|
|
front = (d >= sphere->radius);
|
|
back = (d <= -sphere->radius);
|
|
return front - back;
|
|
}
|
|
|
|
void
|
|
BasePortalVis (void)
|
|
{
|
|
int i, j, k;
|
|
float d;
|
|
portal_t *tp, *portal;
|
|
winding_t *winding;
|
|
int base_mightsee = 0;
|
|
int tp_side, portal_side;
|
|
double start, end;
|
|
|
|
start = Sys_DoubleTime ();
|
|
portalsee = set_new_size (numportals * 2);
|
|
for (i = 0, portal = portals; i < numportals * 2; i++, portal++) {
|
|
portal->mightsee = set_new_size (portalclusters);
|
|
|
|
set_empty (portalsee);
|
|
|
|
for (j = 0, tp = portals; j < numportals * 2; j++, tp++) {
|
|
if (j == i)
|
|
continue;
|
|
|
|
// If the target portal is behind the portals's plane, then it
|
|
// can't possibly be seen by the portal.
|
|
//
|
|
// If the portal is in front of the target's plane, then the target
|
|
// is of no interest as it is facing counter to the flow of
|
|
// visibility.
|
|
|
|
// First check using the bounding spheres of the two portals.
|
|
tp_side = test_sphere (&tp->sphere, &portal->plane);
|
|
if (tp_side < 0) {
|
|
// The test portal definitely is entirely behind the portal's
|
|
// plane.
|
|
continue; // entirely behind
|
|
}
|
|
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.
|
|
continue; // entirely in front
|
|
}
|
|
|
|
if (tp_side == 0) {
|
|
// The test portal's sphere touches the portal's plane, so
|
|
// 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)
|
|
break;
|
|
}
|
|
if (k == winding->numpoints)
|
|
continue; // no points on front
|
|
}
|
|
|
|
if (portal_side == 0) {
|
|
// The portal's sphere touches the test portal's plane, so
|
|
// 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)
|
|
break;
|
|
}
|
|
if (k == winding->numpoints)
|
|
continue; // no points on front
|
|
}
|
|
|
|
set_add (portalsee, j);
|
|
}
|
|
|
|
clustersee = 0;
|
|
SimpleFlood (portal, portal->cluster);
|
|
portal->nummightsee = clustersee;
|
|
base_mightsee += clustersee;
|
|
}
|
|
set_delete (portalsee);
|
|
end = Sys_DoubleTime ();
|
|
if (options.verbosity > 0)
|
|
printf ("base_mightsee: %d %gs\n", base_mightsee, end - start);
|
|
}
|