Limit the number of active sections. This allows stupidly huge maps without running out of memory.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4090 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2012-07-21 08:06:07 +00:00
parent 65fb47c9f6
commit 9baba9adcd
1 changed files with 65 additions and 4 deletions

View File

@ -8,6 +8,7 @@
//#define STRICTEDGES //strict (ugly) grid
#define TERRAINTHICKNESS 16
#define TERRAINACTIVESECTIONS 1000
//heightmaps work thusly:
//there is one raw heightmap file
@ -78,6 +79,9 @@ typedef struct
} dsection_t;
typedef struct
{
link_t recycle;
int sx, sy;
float heights[SECTHEIGHTSIZE*SECTHEIGHTSIZE];
unsigned short holes;
unsigned int flags;
@ -104,7 +108,8 @@ typedef struct
{
hmsection_t *section[MAXSECTIONS*MAXSECTIONS];
} hmcluster_t;
typedef struct heightmap_s {
typedef struct heightmap_s
{
char path[MAX_QPATH];
int firstsegx, firstsegy;
int maxsegx, maxsegy; //tex/cull sections
@ -116,6 +121,9 @@ typedef struct heightmap_s {
mesh_t *askymesh;
unsigned int exteriorcontents;
int activesections;
link_t recycle;
#ifndef SERVERONLY
struct lmsect_s
{
@ -135,6 +143,7 @@ typedef struct heightmap_s {
static void ted_dorelight(heightmap_t *hm);
static void Terr_Collect(heightmap_t *hm);
#ifndef SERVERONLY
@ -256,6 +265,11 @@ static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, in
return NULL;
}
memset(s, 0, sizeof(*s));
InsertLinkBefore(&s->recycle, &hm->recycle);
s->sx = sx;
s->sy = sy;
hm->activesections++;
#ifndef SERVERONLY
s->lightmap = -1;
@ -554,6 +568,8 @@ static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, qboolean dolo
{
if (doload)
{
while (hm->activesections > TERRAINACTIVESECTIONS)
Terr_Collect(hm);
section = cluster->section[sx + sy*MAXSECTIONS] = Terr_LoadSection(hm, section, x, y);
}
}
@ -589,6 +605,7 @@ int HeightMap_Save(heightmap_t *hm)
void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusable)
{
RemoveLink(&s->recycle);
#ifndef SERVERONLY
if (lightmapreusable && s->lightmap >= 0)
{
@ -602,6 +619,9 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
hm->unusedlmsects = lms;
}
if (hm->relight == s)
hm->relight = NULL;
#ifdef GLQUAKE
if (qrenderer == QR_OPENGL)
{
@ -616,6 +636,34 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
#endif
free(s);
hm->activesections--;
}
//garbage collect the oldest section, to make space for another
static void Terr_Collect(heightmap_t *hm)
{
hmcluster_t *c;
hmsection_t *s;
int cx, cy;
int sx, sy;
link_t *ln = &hm->recycle;
for (ln = &hm->recycle; ln->next != &hm->recycle; )
{
s = (hmsection_t*)ln->next;
cx = s->sx/MAXSECTIONS;
cy = s->sy/MAXSECTIONS;
c = hm->cluster[cx + cy*MAXSECTIONS];
sx = s->sx & (MAXSECTIONS-1);
sy = s->sy & (MAXSECTIONS-1);
if (c->section[sx+sy*MAXSECTIONS] != s)
Sys_Error("invalid section collection");
c->section[sx+sy*MAXSECTIONS] = NULL;
Terr_DestroySection(hm, s, true);
return;
}
}
/*purge all sections
@ -1008,7 +1056,6 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
{
if (!hm->relight)
{
s->flags &= ~TSF_RELIGHT;
hm->relight = s;
hm->relightidx = 0;
hm->relightmin[0] = mins[0];
@ -1338,6 +1385,18 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
return;
s = Terr_GetSection(tr->hm, tx/(SECTHEIGHTSIZE-1), ty/(SECTHEIGHTSIZE-1), true);
if (!s)
{
//you're not allowed to walk into sections that have not loaded.
//might as well check the entire section instead of just one tile
Vector4Set(n[0], 1, 0, 0, (tx/(SECTHEIGHTSIZE-1) + 1 - CHUNKBIAS)*tr->hm->sectionsize);
Vector4Set(n[1], -1, 0, 0, -(tx/(SECTHEIGHTSIZE-1) + 0 - CHUNKBIAS)*tr->hm->sectionsize);
Vector4Set(n[2], 0, 1, 0, (ty/(SECTHEIGHTSIZE-1) + 1 - CHUNKBIAS)*tr->hm->sectionsize);
Vector4Set(n[3], 0, -1, 0, -(ty/(SECTHEIGHTSIZE-1) + 0 - CHUNKBIAS)*tr->hm->sectionsize);
Heightmap_Trace_Brush(tr, n, 4);
return;
}
sx = tx - CHUNKBIAS*(SECTHEIGHTSIZE-1);
sy = ty - CHUNKBIAS*(SECTHEIGHTSIZE-1);
@ -1345,7 +1404,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
ty = ty % (SECTHEIGHTSIZE-1);
holebit = 1u<<(tx/(SECTHEIGHTSIZE>>2) + (ty/(SECTHEIGHTSIZE>>2))*4);
if (!s || (s->holes & holebit))
if (s->holes & holebit)
return; //no collision with holes
VectorSet(p[0], tr->htilesize*(sx+0), tr->htilesize*(sy+0), s->heights[(tx+0)+(ty+0)*SECTHEIGHTSIZE]);
@ -1680,7 +1739,7 @@ static void ted_dorelight(heightmap_t *hm)
// float scaletab[EXPAND*2*EXPAND*2];
vec3_t ldir = {0.4, 0.7, 2};
hmsection_t *s = hm->relight;
s->flags &= ~TSF_RELIGHT;
hm->relight = NULL;
for (y = -EXPAND; y < SECTTEXSIZE+EXPAND; y++)
@ -2305,6 +2364,7 @@ qboolean Terr_LoadTerrainModel (model_t *mod, void *buffer)
hm = Hunk_Alloc(sizeof(*hm));
memset(hm, 0, sizeof(*hm));
ClearLink(&hm->recycle);
COM_FileBase(mod->name, hm->path, sizeof(hm->path));
mod->entities = Hunk_AllocName(strlen(buffer)+1, mod->name);
@ -2402,6 +2462,7 @@ void *Mod_LoadTerrainInfo(model_t *mod, char *loadname)
scale = 1024;
hm = Z_Malloc(sizeof(*hm));
ClearLink(&hm->recycle);
Q_strncpyz(hm->path, loadname, sizeof(hm->path));
hm->sectionsize = scale;
hm->firstsegx = bounds[0];