[qfvis] Remove the cluster portals limit

This removes the last of the arbitrary limits from qfvis. The goal is
not so much supporting crazy maps, but more about better data usage
(cluster_t is now 24 (or 16) bytes instead of 1048 (or 528). And
passages isn't used (yet?)...
This commit is contained in:
Bill Currie 2021-07-29 21:03:07 +09:00
parent fe98a513bc
commit 9461779ba7
4 changed files with 98 additions and 72 deletions

View file

@ -79,13 +79,10 @@ extern pthread_rwlock_t *stats_lock;
#include "QF/zone.h" #include "QF/zone.h"
#include "QF/simd/vec4f.h" #include "QF/simd/vec4f.h"
#define MAX_PORTALS 32768
#define PORTALFILE "PRT1" #define PORTALFILE "PRT1"
#define PORTALFILE_AM "PRT1-AM" #define PORTALFILE_AM "PRT1-AM"
#define PORTALFILE2 "PRT2" #define PORTALFILE2 "PRT2"
#define ON_EPSILON 0.1 #define ON_EPSILON 0.1
#define MAX_POINTS_ON_WINDING 64
#define MAX_PORTALS_ON_CLUSTER 128
typedef struct winding_s { typedef struct winding_s {
struct winding_s *next; struct winding_s *next;
@ -130,7 +127,7 @@ typedef struct cluster_s {
int numportals; int numportals;
int visofs; int visofs;
passage_t *passages; passage_t *passages;
portal_t *portals[MAX_PORTALS_ON_CLUSTER]; portal_t *portals;
} cluster_t; } cluster_t;
typedef struct pstack_s { typedef struct pstack_s {

View file

@ -76,7 +76,7 @@ SimpleFlood (basethread_t *thread, portal_t *srcportal, int clusternum)
cluster = &clusters[clusternum]; cluster = &clusters[clusternum];
for (i = 0; i < cluster->numportals; i++) { for (i = 0; i < cluster->numportals; i++) {
portal = cluster->portals[i]; portal = &cluster->portals[i];
if (!set_is_member (thread->portalsee, portal - portals)) if (!set_is_member (thread->portalsee, portal - portals))
continue; continue;
SimpleFlood (thread, srcportal, portal->cluster); SimpleFlood (thread, srcportal, portal->cluster);

View file

@ -349,7 +349,7 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
// check all portals for flowing into other clusters // check all portals for flowing into other clusters
for (i = 0; i < cluster->numportals; i++) { for (i = 0; i < cluster->numportals; i++) {
target_portal = cluster->portals[i]; target_portal = &cluster->portals[i];
if (!set_is_member (prevstack->mightsee, target_portal->cluster)) if (!set_is_member (prevstack->mightsee, target_portal->cluster))
continue; // can't possibly see it continue; // can't possibly see it

View file

@ -408,7 +408,7 @@ UpdateMightsee (threaddata_t *thread, cluster_t *source, cluster_t *dest)
clusternum = dest - clusters; clusternum = dest - clusters;
for (i = 0; i < source->numportals; i++) { for (i = 0; i < source->numportals; i++) {
portal = source->portals[i]; portal = &source->portals[i];
WRLOCK_PORTAL (portal); WRLOCK_PORTAL (portal);
if (portal->status == stat_none) { if (portal->status == stat_none) {
if (set_is_member (portal->mightsee, clusternum)) { if (set_is_member (portal->mightsee, clusternum)) {
@ -462,7 +462,7 @@ PortalCompleted (threaddata_t *thread, portal_t *completed)
changed = set_new_size_r (&thread->set_pool, portalclusters); changed = set_new_size_r (&thread->set_pool, portalclusters);
cluster = &clusters[completed->cluster]; cluster = &clusters[completed->cluster];
for (i = 0; i < cluster->numportals; i++) { for (i = 0; i < cluster->numportals; i++) {
portal = cluster->portals[i]; portal = &cluster->portals[i];
if (portal->status != stat_done) if (portal->status != stat_done)
continue; continue;
set_assign (changed, portal->mightsee); set_assign (changed, portal->mightsee);
@ -480,10 +480,10 @@ PortalCompleted (threaddata_t *thread, portal_t *completed)
for (j = 0; j < cluster->numportals; j++) { for (j = 0; j < cluster->numportals; j++) {
if (j == i) if (j == i)
continue; continue;
if (cluster->portals[j]->status == stat_done) if (cluster->portals[j].status == stat_done)
set_difference (changed, cluster->portals[j]->visbits); set_difference (changed, cluster->portals[j].visbits);
else else
set_difference (changed, cluster->portals[j]->mightsee); set_difference (changed, cluster->portals[j].mightsee);
} }
for (ci = set_first_r (&thread->set_pool, changed); ci; for (ci = set_first_r (&thread->set_pool, changed); ci;
ci = set_next_r (&thread->set_pool, ci)) { ci = set_next_r (&thread->set_pool, ci)) {
@ -845,7 +845,7 @@ ClusterFlow (int clusternum)
memset (compressed.data, 0, compressed.maxsize); memset (compressed.data, 0, compressed.maxsize);
visclusters = set_new (); visclusters = set_new ();
for (i = 0; i < cluster->numportals; i++) { for (i = 0; i < cluster->numportals; i++) {
portal = cluster->portals[i]; portal = &cluster->portals[i];
if (portal->status != stat_done) if (portal->status != stat_done)
Sys_Error ("portal not done"); Sys_Error ("portal not done");
set_union (visclusters, portal->visbits); set_union (visclusters, portal->visbits);
@ -1153,20 +1153,58 @@ CalcPassages (void)
} }
} }
#endif #endif
static winding_t *
parse_winding (const char *line, int numpoints)
{
winding_t *winding = NewWinding (&main_thread, numpoints);
winding->original = true;
winding->numpoints = numpoints;
for (int i = 0; i < numpoints; i++) {
// (%ld %ld %ld)
while (isspace ((byte) *line))
line++;
if (*line++ != '(') {
return 0;
}
for (int j = 0; j < 3; j++) {
char *err;
winding->points[i][j] = strtod (line, &err);
if (err == line) {
return 0;
}
line = err;
}
winding->points[i][3] = 1;
while (isspace ((byte) *line))
line++;
if (*line++ != ')') {
return 0;
}
}
return winding;
}
static void static void
LoadPortals (char *name) LoadPortals (char *name)
{ {
typedef struct {
unsigned clusters[2];
} clusterpair_t;
const char *line; const char *line;
char *err; char *err;
unsigned numpoints, i, j, k; unsigned numpoints;
int read_leafs = 0; int read_leafs = 0;
int clusternums[2];
cluster_t *cluster;
vec4f_t plane; vec4f_t plane;
portal_t *portal;
winding_t *winding;
vspheref_t sphere; vspheref_t sphere;
QFile *f; QFile *f;
clusterpair_t *clusternums;
if (!strcmp (name, "-")) if (!strcmp (name, "-"))
f = Qdopen (0, "rt"); // create a QFile of stdin f = Qdopen (0, "rt"); // create a QFile of stdin
@ -1233,22 +1271,24 @@ LoadPortals (char *name)
// direction // direction
portals = calloc (2 * numportals, sizeof (portal_t)); portals = calloc (2 * numportals, sizeof (portal_t));
portal_queue = malloc (2 * numportals * sizeof (portal_t *)); portal_queue = malloc (2 * numportals * sizeof (portal_t *));
for (i = 0; i < 2 * numportals; i++) { for (unsigned i = 0; i < 2 * numportals; i++) {
portal_queue[i] = &portals[i]; portal_queue[i] = &portals[i];
} }
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
portal_locks = calloc (2 * numportals, sizeof (pthread_rwlock_t)); portal_locks = calloc (2 * numportals, sizeof (pthread_rwlock_t));
for (i = 0; i < 2 * numportals; i++) { for (unsigned i = 0; i < 2 * numportals; i++) {
if (pthread_rwlock_init (&portal_locks[i], 0)) if (pthread_rwlock_init (&portal_locks[i], 0))
Sys_Error ("pthread_rwlock_init failed"); Sys_Error ("pthread_rwlock_init failed");
} }
#endif #endif
clusters = calloc (portalclusters, sizeof (cluster_t));
clusters = calloc (portalclusters, sizeof (cluster_t));
originalvismapsize = numrealleafs * ((numrealleafs + 7) / 8); originalvismapsize = numrealleafs * ((numrealleafs + 7) / 8);
for (i = 0, portal = portals; i < numportals; i++) { clusternums = calloc (numportals, sizeof (clusterpair_t));
winding_t **windings = malloc (numportals * sizeof (winding_t *));
for (unsigned i = 0; i < numportals; i++) {
line = Qgetline (f); line = Qgetline (f);
if (!line) if (!line)
Sys_Error ("LoadPortals: reading portal %u", i); Sys_Error ("LoadPortals: reading portal %u", i);
@ -1257,41 +1297,36 @@ LoadPortals (char *name)
if (err == line) if (err == line)
Sys_Error ("LoadPortals: reading portal %u", i); Sys_Error ("LoadPortals: reading portal %u", i);
line = err; line = err;
for (j = 0; j < 2; j++) {
clusternums[j] = strtol (line, &err, 10); for (int j = 0; j < 2; j++) {
clusternums[i].clusters[j] = strtoul (line, &err, 10);
if (err == line) if (err == line)
Sys_Error ("LoadPortals: reading portal %u", i); Sys_Error ("LoadPortals: reading portal %u", i);
line = err; line = err;
}
if ((unsigned) clusternums[0] > (unsigned) portalclusters if (clusternums[i].clusters[j] > portalclusters)
|| (unsigned) clusternums[1] > (unsigned) portalclusters)
Sys_Error ("LoadPortals: reading portal %u", i);
winding = portal->winding = NewWinding (&main_thread, numpoints);
winding->original = true;
winding->numpoints = numpoints;
for (j = 0; j < numpoints; j++) {
// (%ld %ld %ld)
while (isspace ((byte) *line))
line++;
if (*line++ != '(')
Sys_Error ("LoadPortals: reading portal %u", i);
for (k = 0; k < 3; k++) {
winding->points[j][k] = strtod (line, &err);
if (err == line)
Sys_Error ("LoadPortals: reading portal %u", i);
line = err;
}
winding->points[j][3] = 1;
while (isspace ((byte) *line))
line++;
if (*line++ != ')')
Sys_Error ("LoadPortals: reading portal %u", i); Sys_Error ("LoadPortals: reading portal %u", i);
} }
clusters[clusternums[i].clusters[0]].numportals++;
clusters[clusternums[i].clusters[1]].numportals++;
if (!(windings[i] = parse_winding (line, numpoints))) {
Sys_Error ("LoadPortals: reading portal %u", i);
}
}
clusters[0].portals = portals;
for (unsigned i = 1; i < portalclusters; i++) {
portal_t *portal = clusters[i - 1].portals;
clusters[i].portals = portal + clusters[i - 1].numportals;
clusters[i - 1].numportals = 0;
}
clusters[portalclusters - 1].numportals = 0;
for (unsigned i = 0; i < numportals; i++) {
winding_t *winding = windings[i];
cluster_t *cluster;
portal_t *portal;
sphere = SmallestEnclosingBall_vf(winding->points, winding->numpoints); sphere = SmallestEnclosingBall_vf(winding->points, winding->numpoints);
//printf (VEC4F_FMT" %.9g\n", VEC4_EXP (sphere.center), sphere.radius); //printf (VEC4F_FMT" %.9g\n", VEC4_EXP (sphere.center), sphere.radius);
@ -1300,45 +1335,39 @@ LoadPortals (char *name)
plane = PlaneFromWinding (winding); plane = PlaneFromWinding (winding);
// create forward portal // create forward portal
cluster = &clusters[clusternums[0]]; cluster = &clusters[clusternums[i].clusters[0]];
if (cluster->numportals == MAX_PORTALS_ON_CLUSTER) portal = &cluster->portals[cluster->numportals++];
Sys_Error ("Cluster with too many portals");
cluster->portals[cluster->numportals] = portal;
cluster->numportals++;
portal->winding = winding;
portal->plane = -plane; // 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->sphere = sphere;
portal++; portal->cluster = clusternums[i].clusters[1];
portal->winding = winding;
// create backwards portal
cluster = &clusters[clusternums[1]];
if (cluster->numportals == MAX_PORTALS_ON_CLUSTER)
Sys_Error ("Cluster with too many portals");
cluster->portals[cluster->numportals] = portal;
cluster->numportals++;
// Use a flipped winding for the reverse portal so the winding // Use a flipped winding for the reverse portal so the winding
// direction and plane normal match. // direction and plane normal match.
portal->winding = NewFlippedWinding (&main_thread, winding); winding = NewFlippedWinding (&main_thread, winding); // **
portal->winding->original = true; winding->original = true;
// create backwards portal
cluster = &clusters[clusternums[i].clusters[1]];
portal = &cluster->portals[cluster->numportals++];
portal->plane = plane; portal->plane = plane;
portal->cluster = clusternums[0];
portal->sphere = sphere; portal->sphere = sphere;
portal++; portal->cluster = clusternums[i].clusters[0];
portal->winding = winding;
} }
free (clusternums);
free (windings);
leafcluster = calloc (numrealleafs, sizeof (int)); leafcluster = calloc (numrealleafs, sizeof (int));
if (read_leafs) { if (read_leafs) {
for (i = 0; i < numrealleafs; i++) { for (unsigned i = 0; i < numrealleafs; i++) {
line = Qgetline (f); line = Qgetline (f);
if (sscanf (line, "%i\n", &leafcluster[i]) != 1) if (sscanf (line, "%i\n", &leafcluster[i]) != 1)
Sys_Error ("LoadPortals: parse error in leaf->cluster " Sys_Error ("LoadPortals: parse error in leaf->cluster "
"mappings"); "mappings");
} }
} else { } else {
for (i = 0; i < numrealleafs; i++) for (unsigned i = 0; i < numrealleafs; i++)
leafcluster[i] = i; leafcluster[i] = i;
} }
Qclose (f); Qclose (f);