shithub: qk1

Download patch

ref: 41f0fca28c4087f9c3520c92f79d6e03334a7195
parent: d3fd0ce3fd223f7acfdba6ea650cba84f3d2db57
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Mon Oct 9 20:57:02 EDT 2023

normal quake: completely rewrite memory management; increase default limits

"Zone" is no longer. Use malloc/free instead, with double-linked lists.
This makes -m cmdline argument obsolete - memory is allocated dynamically and
the engine no longer falls over on Arcane Dimensions entry map.

--- a/bspfile.h
+++ b/bspfile.h
@@ -10,7 +10,7 @@
 #define	MAX_MAP_PLANES		32767
 #define	MAX_MAP_NODES		32767		// because negative shorts are contents
 #define	MAX_MAP_CLIPNODES	32767		//
-#define	MAX_MAP_LEAFS		8192
+#define	MAX_MAP_LEAFS		65535
 #define	MAX_MAP_VERTS		65535
 #define	MAX_MAP_FACES		65535
 #define	MAX_MAP_MARKSURFACES 65535
--- a/cl_main.c
+++ b/cl_main.c
@@ -183,7 +183,6 @@
 	case 3:	
 		MSG_WriteByte (&cls.message, clc_stringcmd);
 		MSG_WriteString (&cls.message, "begin");
-		Cache_Report ();		// print remaining memory
 		break;
 		
 	case 4:
--- a/cl_parse.c
+++ b/cl_parse.c
@@ -213,7 +213,7 @@
 		Con_Printf("Bad maxclients (%d) from server\n", cl.maxclients);
 		return;
 	}
-	cl.scores = Hunk_AllocName(cl.maxclients * sizeof *cl.scores, "scores");
+	cl.scores = Hunk_Alloc(cl.maxclients * sizeof *cl.scores);
 
 // parse gametype
 	cl.gametype = MSG_ReadByte ();
@@ -291,8 +291,6 @@
 	
 	R_NewMap ();
 
-	Hunk_Check ();		// make sure nothing is hurt
-	
 	noclip_anglehack = false;		// noclip is turned off at start	
 }
 
--- a/client.h
+++ b/client.h
@@ -65,7 +65,7 @@
 	vec3_t	start, end;
 } beam_t;
 
-#define	MAX_EFRAGS		640
+#define	MAX_EFRAGS		4096
 
 #define	MAX_MAPSTRING	2048
 #define	MAX_DEMOS		8
@@ -267,7 +267,7 @@
 void CL_Disconnect_f (void);
 void CL_NextDemo (void);
 
-#define			MAX_VISEDICTS	256
+#define			MAX_VISEDICTS	4096
 extern	int				cl_numvisedicts;
 extern	entity_t		*cl_visedicts[MAX_VISEDICTS];
 
--- a/cmd.c
+++ b/cmd.c
@@ -264,7 +264,7 @@
 void Cmd_Exec_f (void)
 {
 	char	*f;
-	int		mark;
+	void	*mark;
 
 	if (Cmd_Argc () != 2)
 	{
@@ -272,7 +272,7 @@
 		return;
 	}
 
-	mark = Hunk_LowMark ();
+	mark = Hunk_Mark ();
 	f = loadhunklmp(Cmd_Argv(1), nil);
 	if(f == nil){
 		Con_Printf(va("exec: %r\n"));
@@ -281,7 +281,7 @@
 	Con_Printf ("execing %s\n",Cmd_Argv(1));
 	
 	Cbuf_InsertText (f);
-	Hunk_FreeToLowMark (mark);
+	Hunk_FreeToMark (mark);
 }
 
 
--- a/common.c
+++ b/common.c
@@ -310,7 +310,7 @@
 {
 	if(startsize < 256)
 		startsize = 256;
-	buf->data = Hunk_AllocName(startsize, "sizebuf");
+	buf->data = Hunk_Alloc(startsize);
 	buf->maxsize = startsize;
 	buf->cursize = 0;
 }
--- a/console.c
+++ b/console.c
@@ -175,7 +175,7 @@
 */
 void Con_Init (void)
 {
-	con_text = Hunk_AllocName (CON_TEXTSIZE, "context");
+	con_text = Hunk_Alloc(CON_TEXTSIZE);
 	memset(con_text, ' ', CON_TEXTSIZE);
 	con_linewidth = -1;
 	Con_CheckResize ();
--- a/dat.h
+++ b/dat.h
@@ -1,8 +1,6 @@
 typedef struct Sfx Sfx;
 
 extern char *game;
-extern uchar *membase;
-extern int memsize;
 
 enum{
 	Npath = 64,
--- a/draw.c
+++ b/draw.c
@@ -24,7 +24,7 @@
 typedef struct cachepic_s
 {
 	char		name[Npath];
-	cache_user_t	cache;
+	mem_user_t	cache;
 } cachepic_t;
 
 #define	MAX_CACHED_PICS		128
--- a/fns.h
+++ b/fns.h
@@ -34,7 +34,7 @@
 char*	ext(char*, char*);
 void	radix(char*, char*);
 void*	loadhunklmp(char *, int *);
-void*	loadcachelmp(char *, cache_user_t *);
+void*	loadcachelmp(char *, mem_user_t *);
 void*	loadstklmp(char *, void *, int, int *);
 void	loadpoints(void);
 void	dumpcfg(void);
--- a/fs.c
+++ b/fs.c
@@ -104,7 +104,7 @@
 static int notid1;
 static int loadsize;
 static uchar *loadbuf;
-static cache_user_t *loadcache;
+static mem_user_t *loadcache;
 static Biobuf *demobf;
 static vlong demoofs;
 
@@ -376,8 +376,8 @@
 	radix(f, r);
 	buf = nil;
 	switch(mth){
-	case Fhunk: buf = Hunk_AllocName(m + 1, r); break;
-	case Fcache: buf = Cache_Alloc(loadcache, m + 1, r); break;
+	case Fhunk: buf = Hunk_Alloc(m + 1); break;
+	case Fcache: buf = Cache_Alloc(loadcache, m + 1); break;
 	case Fstack: buf = m + 1 <= loadsize ? loadbuf : Hunk_TempAlloc(m + 1); break;
 	}
 	if(buf == nil)
@@ -397,7 +397,7 @@
 }
 
 void *
-loadcachelmp(char *f, cache_user_t *c)
+loadcachelmp(char *f, mem_user_t *c)
 {
 	loadcache = c;
 	loadlmp(f, Fcache, nil);
@@ -828,7 +828,7 @@
 		fatal("pak %s: invalid lump number %d", f, nlmp);
 	if(nlmp != Npak0lmp)
 		notid1 = 1;
-	l = Hunk_AllocName(nlmp * sizeof *l, "pak");
+	l = Hunk_Alloc(nlmp * sizeof *l);
 	p = Hunk_Alloc(sizeof *p);
 	strncpy(p->f, f, sizeof(p->f)-1);
 	p->bf = bf;
--- a/host.c
+++ b/host.c
@@ -24,7 +24,7 @@
 double		oldrealtime;			// last frame run
 int			host_framecount;
 
-int			host_hunklevel;
+void		*host_hunklevel;
 
 client_t	*host_client;			// current client
 
@@ -140,7 +140,7 @@
 	svs.maxclientslimit = svs.maxclients;
 	if (svs.maxclientslimit < 4)
 		svs.maxclientslimit = 4;
-	svs.clients = Hunk_AllocName(svs.maxclientslimit * sizeof *svs.clients, "clients");
+	svs.clients = Hunk_Alloc(svs.maxclientslimit * sizeof *svs.clients);
 
 	if (svs.maxclients > 1)
 		setcvarv ("deathmatch", 1.0);
@@ -395,7 +395,7 @@
 	D_FlushCaches ();
 	Mod_ClearAll ();
 	if (host_hunklevel)
-		Hunk_FreeToLowMark (host_hunklevel);
+		Hunk_FreeToMark (host_hunklevel);
 
 	cls.signon = 0;
 	memset(&sv, 0, sizeof sv);
@@ -597,7 +597,6 @@
 	Mod_Init ();
 	NET_Init ();
 	SV_Init ();
-	dprint("%4.1f megabyte heap\n", memsize / (1024 * 1024.0));
 	R_InitTextures ();		// needed even for dedicated servers
  
 	if (cls.state != ca_dedicated)
@@ -626,8 +625,7 @@
 	Cbuf_InsertText ("+mlook\n");
 	Cbuf_InsertText ("exec quake.rc\n");
 
-	Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
-	host_hunklevel = Hunk_LowMark ();
+	host_hunklevel = Hunk_Mark ();
 
 	host_initialized = true;	
 }
--- a/model.c
+++ b/model.c
@@ -14,7 +14,7 @@
 
 byte	mod_novis[MAX_MAP_LEAFS/8];
 
-#define	MAX_MOD_KNOWN	256
+#define	MAX_MOD_KNOWN	4096
 model_t	mod_known[MAX_MOD_KNOWN];
 int		mod_numknown;
 
@@ -339,7 +339,7 @@
 	m->nummiptex = LittleLong (m->nummiptex);
 	
 	loadmodel->numtextures = m->nummiptex;
-	loadmodel->textures = Hunk_AllocName(m->nummiptex * sizeof *loadmodel->textures, loadname);
+	loadmodel->textures = Hunk_Alloc(m->nummiptex * sizeof *loadmodel->textures);
 
 	for (i=0 ; i<m->nummiptex ; i++)
 	{
@@ -355,7 +355,7 @@
 		if ( (mt->width & 15) || (mt->height & 15) )
 			fatal ("Texture %s is not 16 aligned", mt->name);
 		pixels = mt->width*mt->height/64*85;
-		tx = Hunk_AllocName(pixels + sizeof *tx, loadname);
+		tx = Hunk_Alloc(pixels + sizeof *tx);
 		loadmodel->textures[i] = tx;
 
 		memcpy(tx->name, mt->name, sizeof tx->name);
@@ -476,7 +476,7 @@
 		loadmodel->lightdata = nil;
 		return;
 	}
-	loadmodel->lightdata = Hunk_AllocName(l->filelen, loadname);
+	loadmodel->lightdata = Hunk_Alloc(l->filelen);
 	memcpy(loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
 }
 
@@ -493,7 +493,7 @@
 		loadmodel->visdata = nil;
 		return;
 	}
-	loadmodel->visdata = Hunk_AllocName(l->filelen, loadname);
+	loadmodel->visdata = Hunk_Alloc(l->filelen);
 	memcpy(loadmodel->visdata, mod_base + l->fileofs, l->filelen);
 }
 
@@ -510,7 +510,7 @@
 		loadmodel->entities = nil;
 		return;
 	}
-	loadmodel->entities = Hunk_AllocName(l->filelen, loadname);
+	loadmodel->entities = Hunk_Alloc(l->filelen);
 	memcpy(loadmodel->entities, mod_base + l->fileofs, l->filelen);
 }
 
@@ -530,7 +530,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadVertexes: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName(count * sizeof *out, loadname);
+	out = Hunk_Alloc(count * sizeof *out);
 
 	loadmodel->vertexes = out;
 	loadmodel->numvertexes = count;
@@ -558,7 +558,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadSubmodels: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName(count * sizeof *out, loadname);
+	out = Hunk_Alloc(count * sizeof *out);
 
 	loadmodel->submodels = out;
 	loadmodel->numsubmodels = count;
@@ -594,7 +594,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadEdges: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName((count+1) * sizeof *out, loadname);
+	out = Hunk_Alloc((count+1) * sizeof *out);
 
 	loadmodel->edges = out;
 	loadmodel->numedges = count;
@@ -623,7 +623,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadTexInfo: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName(count * sizeof *out, loadname);
+	out = Hunk_Alloc(count * sizeof *out);
 
 	loadmodel->texinfo = out;
 	loadmodel->numtexinfo = count;
@@ -688,7 +688,7 @@
 	int		bmins[2], bmaxs[2];
 
 	mins[0] = mins[1] = 999999;
-	maxs[0] = maxs[1] = -99999;
+	maxs[0] = maxs[1] = -999999;
 
 	tex = s->texinfo;
 	
@@ -742,7 +742,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadFaces: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName(count * sizeof *out, loadname);
+	out = Hunk_Alloc(count * sizeof *out);
 
 	loadmodel->surfaces = out;
 	loadmodel->numsurfaces = count;
@@ -825,7 +825,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadNodes: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName(count * sizeof *out, loadname);
+	out = Hunk_Alloc(count * sizeof *out);
 
 	loadmodel->nodes = out;
 	loadmodel->numnodes = count;
@@ -872,7 +872,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadLeafs: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName(count * sizeof *out, loadname);
+	out = Hunk_Alloc(count * sizeof *out);
 
 	loadmodel->leafs = out;
 	loadmodel->numleafs = count;
@@ -919,7 +919,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadClipnodes: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName(count * sizeof *out, loadname);
+	out = Hunk_Alloc(count * sizeof *out);
 
 	loadmodel->clipnodes = out;
 	loadmodel->numclipnodes = count;
@@ -974,7 +974,7 @@
 	
 	in = loadmodel->nodes;
 	count = loadmodel->numnodes;
-	out = Hunk_AllocName(count * sizeof *out, loadname);
+	out = Hunk_Alloc(count * sizeof *out);
 
 	hull->clipnodes = out;
 	hull->firstclipnode = 0;
@@ -1010,7 +1010,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadMarksurfaces: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName(count * sizeof *out, loadname);
+	out = Hunk_Alloc(count * sizeof *out);
 
 	loadmodel->marksurfaces = out;
 	loadmodel->nummarksurfaces = count;
@@ -1038,7 +1038,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadSurfedges: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName(count * sizeof *out, loadname);
+	out = Hunk_Alloc(count * sizeof *out);
 
 	loadmodel->surfedges = out;
 	loadmodel->numsurfedges = count;
@@ -1064,7 +1064,7 @@
 	if (l->filelen % sizeof(*in))
 		fatal("Mod_LoadPlanes: funny lump size in %s", loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName(count * 2 * sizeof *out, loadname);
+	out = Hunk_Alloc(count * 2 * sizeof *out);
 
 	loadmodel->planes = out;
 	loadmodel->numplanes = count;
@@ -1176,7 +1176,7 @@
 
 		if (i < mod->numsubmodels-1)
 		{	// duplicate the basic information
-			char	name[10];
+			char	name[32];
 
 			sprint (name, "*%d", i+1);
 			loadmodel = Mod_FindName (name);
@@ -1220,10 +1220,9 @@
 	}
 
 	pinframe = (trivertx_t *)(pdaliasframe + 1);
-	pframe = Hunk_AllocName(numv * sizeof *pframe, loadname);
+	*pframeindex = Hunk_From(pheader);
+	pframe = Hunk_Alloc(numv * sizeof *pframe);
 
-	*pframeindex = (byte *)pframe - (byte *)pheader;
-
 	for (j=0 ; j<numv ; j++)
 	{
 		int		k;
@@ -1262,8 +1261,9 @@
 
 	numframes = LittleLong (pingroup->numframes);
 
-	paliasgroup = Hunk_AllocName(sizeof(*paliasgroup) +
-			(numframes - 1) * sizeof paliasgroup->frames[0], loadname);
+	*pframeindex = Hunk_From(pheader);
+	paliasgroup = Hunk_Alloc(sizeof(*paliasgroup) +
+			(numframes - 1) * sizeof paliasgroup->frames[0]);
 
 	paliasgroup->numframes = numframes;
 
@@ -1274,14 +1274,11 @@
 		pbboxmax->v[i] = pingroup->bboxmax.v[i];
 	}
 
-	*pframeindex = (byte *)paliasgroup - (byte *)pheader;
-
 	pin_intervals = (daliasinterval_t *)(pingroup + 1);
 
-	poutintervals = Hunk_AllocName(numframes * sizeof *poutintervals, loadname);
+	paliasgroup->intervals = Hunk_From(pheader);
+	poutintervals = Hunk_Alloc(numframes * sizeof *poutintervals);
 
-	paliasgroup->intervals = (byte *)poutintervals - (byte *)pheader;
-
 	for (i=0 ; i<numframes ; i++)
 	{
 		*poutintervals = LittleFloat (pin_intervals->interval);
@@ -1312,9 +1309,9 @@
 {
 	uchar *pskin, *pinskin;
 
-	pskin = Hunk_AllocName(skinsize, loadname);
+	*pskinindex = Hunk_From(pheader);
+	pskin = Hunk_Alloc(skinsize);
 	pinskin = (uchar *)pin;
-	*pskinindex = (uchar *)pskin - (uchar *)pheader;
 	memcpy(pskin, pinskin, skinsize);
 	pinskin += skinsize;
 	return (void *)pinskin;
@@ -1340,20 +1337,17 @@
 
 	numskins = LittleLong (pinskingroup->numskins);
 
-	paliasskingroup = Hunk_AllocName(sizeof(*paliasskingroup) +
-		(numskins - 1) * sizeof paliasskingroup->skindescs[0], loadname);
+	*pskinindex = Hunk_From(pheader);
+	paliasskingroup = Hunk_Alloc(sizeof(*paliasskingroup) +
+		(numskins - 1) * sizeof paliasskingroup->skindescs[0]);
 
 	paliasskingroup->numskins = numskins;
 
-	*pskinindex = (byte *)paliasskingroup - (byte *)pheader;
-
 	pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
 
-	poutskinintervals = Hunk_AllocName(numskins * sizeof *poutskinintervals,
-		loadname);
+	paliasskingroup->intervals = Hunk_From(pheader);
+	poutskinintervals = Hunk_Alloc(numskins * sizeof *poutskinintervals);
 
-	paliasskingroup->intervals = (byte *)poutskinintervals - (byte *)pheader;
-
 	for (i=0 ; i<numskins ; i++)
 	{
 		*poutskinintervals = LittleFloat (pinskinintervals->interval);
@@ -1395,9 +1389,6 @@
 	daliasskintype_t	*pskintype;
 	maliasskindesc_t	*pskindesc;
 	int					skinsize;
-	int					start, end, total;
-	
-	start = Hunk_LowMark ();
 
 	pinmodel = (mdl_t *)buffer;
 
@@ -1416,11 +1407,12 @@
 			LittleLong (pinmodel->numverts) * sizeof (stvert_t) +
 			LittleLong (pinmodel->numtris) * sizeof (mtriangle_t);
 
-	pheader = Hunk_AllocName(size, loadname);
+	pheader = Hunk_Alloc(size);
 	pmodel = (mdl_t *) ((byte *)&pheader[1] +
 			(LittleLong (pinmodel->numframes) - 1) *
 			 sizeof (pheader->frames[0]));
-	
+	pheader->model = (byte *)pmodel - (byte *)pheader;
+
 //	mod->cache.data = pheader;
 	mod->flags = LittleLong (pinmodel->flags);
 
@@ -1467,8 +1459,6 @@
 	if (pmodel->skinwidth & 0x03)
 		fatal ("Mod_LoadAliasModel: skinwidth not multiple of 4");
 
-	pheader->model = (byte *)pmodel - (byte *)pheader;
-
 //
 // load the skins
 //
@@ -1479,10 +1469,9 @@
 
 	pskintype = (daliasskintype_t *)&pinmodel[1];
 
-	pskindesc = Hunk_AllocName(numskins * sizeof *pskindesc, loadname);
+	pheader->skindesc = Hunk_From(pheader);
+	pskindesc = Hunk_Alloc(numskins * sizeof *pskindesc);
 
-	pheader->skindesc = (byte *)pskindesc - (byte *)pheader;
-
 	for (i=0 ; i<numskins ; i++)
 	{
 		aliasskintype_t	skintype;
@@ -1589,15 +1578,8 @@
 //
 // move the complete, relocatable alias model to the cache
 //	
-	end = Hunk_LowMark ();
-	total = end - start;
-	
-	Cache_Alloc (&mod->cache, total, loadname);
-	if (!mod->cache.data)
-		return;
-	memcpy(mod->cache.data, pheader, total);
 
-	Hunk_FreeToLowMark (start);
+	Hunk_CacheFrom(&mod->cache, pheader);
 }
 
 void *
@@ -1613,7 +1595,7 @@
 	height = LittleLong(pinframe->height);
 	size = width * height;
 
-	pspriteframe = Hunk_AllocName(size + sizeof *pspriteframe, loadname);
+	pspriteframe = Hunk_Alloc(size + sizeof *pspriteframe);
 
 	memset(pspriteframe, 0, size + sizeof *pspriteframe);
 	*ppframe = pspriteframe;
@@ -1651,8 +1633,8 @@
 
 	numframes = LittleLong (pingroup->numframes);
 
-	pspritegroup = Hunk_AllocName(sizeof(*pspritegroup) +
-		(numframes - 1) * sizeof pspritegroup->frames[0], loadname);
+	pspritegroup = Hunk_Alloc(sizeof(*pspritegroup) +
+		(numframes - 1) * sizeof pspritegroup->frames[0]);
 
 	pspritegroup->numframes = numframes;
 
@@ -1660,7 +1642,7 @@
 
 	pin_intervals = (dspriteinterval_t *)(pingroup + 1);
 
-	poutintervals = Hunk_AllocName(numframes * sizeof *poutintervals, loadname);
+	poutintervals = Hunk_Alloc(numframes * sizeof *poutintervals);
 
 	pspritegroup->intervals = poutintervals;
 
@@ -1711,7 +1693,7 @@
 
 	size = sizeof (msprite_t) +	(numframes - 1) * sizeof (psprite->frames);
 
-	psprite = Hunk_AllocName(size, loadname);
+	psprite = Hunk_Alloc(size);
 
 	mod->cache.data = psprite;
 
--- a/model.h
+++ b/model.h
@@ -343,7 +343,7 @@
 //
 // additional model data
 //
-	cache_user_t	cache;		// only access through Mod_Extradata
+	mem_user_t	cache;		// only access through Mod_Extradata
 
 } model_t;
 
--- a/net_main.c
+++ b/net_main.c
@@ -524,7 +524,7 @@
 
 	for (i = 0; i < net_numsockets; i++)
 	{
-		s = Hunk_AllocName(sizeof *s, "qsocket");
+		s = Hunk_Alloc(sizeof *s);
 		s->next = net_freeSockets;
 		net_freeSockets = s;
 		s->disconnected = true;
--- a/qk1.c
+++ b/qk1.c
@@ -5,18 +5,11 @@
 #include "quakedef.h"
 #include "fns.h"
 
-mainstacksize = 512*1024;
+mainstacksize = 4*1024*1024;
 char *netmtpt = "/net";
-uchar *membase;
-int memsize;
 char *game;
 int debug;
 
-enum{
-	KB = 1024*1024,
-	Nmem = 64 * KB
-};
-
 void
 dprint(char *fmt, ...)
 {
@@ -119,7 +112,6 @@
 {
 	double t, t´, Δt;
 
-	memsize = Nmem;
 	ARGBEGIN{
 	case 'D':
 		debug = 1;
@@ -130,17 +122,11 @@
 	case 'g':
 		game = EARGF(usage());
 		break;
-	case 'm':
-		memsize = strtol(EARGF(usage()), nil, 0) * KB;
-		if(memsize <= 0)
-			sysfatal("invalid memsize");
-		break;
 	case 'x':
 		netmtpt = EARGF(usage());
 		break;
 	default: usage();
 	}ARGEND
-	membase = emalloc(memsize);
 	srand(getpid());
 	/* ignore fp exceptions: rendering shit assumes they are */
 	setfcr(getfcr() & ~(FPOVFL|FPUNFL|FPINVAL|FPZDIV));
--- a/quakedef.h
+++ b/quakedef.h
@@ -31,10 +31,10 @@
 //
 // per-level limits
 //
-#define	MAX_EDICTS		600			// FIXME: ouch! ouch! ouch!
+#define	MAX_EDICTS		32000			// FIXME: ouch! ouch! ouch!
 #define	Nlights	64
-#define	MAX_MODELS		256			// these are sent over the net as bytes
-#define	MAX_SOUNDS		256			// so they cannot be blindly increased
+#define	MAX_MODELS		4096			// these are sent over the net as bytes
+#define	MAX_SOUNDS		2048			// so they cannot be blindly increased
 
 #define	MAX_STYLESTRING	64
 
@@ -41,7 +41,7 @@
 //
 // stats are integers communicated to the client by the server
 //
-#define	MAX_CL_STATS		32
+#define	MAX_CL_STATS		256
 #define	STAT_HEALTH			0
 #define	STAT_FRAGS			1
 #define	STAT_WEAPON			2
@@ -161,7 +161,7 @@
 
 struct Sfx{
 	char s[Npath];
-	cache_user_t cu;
+	mem_user_t cu;
 };
 
 extern cvar_t bgmvolume;
--- a/r_bsp.c
+++ b/r_bsp.c
@@ -23,8 +23,8 @@
 
 typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
 
-#define MAX_BMODEL_VERTS	500			// 6K
-#define MAX_BMODEL_EDGES	1000		// 12K
+#define MAX_BMODEL_VERTS	1000		// 6K
+#define MAX_BMODEL_EDGES	3000		// 12K
 
 static mvertex_t	*pbverts;
 static bedge_t		*pbedges;
--- a/r_edge.c
+++ b/r_edge.c
@@ -14,8 +14,6 @@
 have a sentinal at both ends?
 */
 
-
-edge_t	*auxedges;
 edge_t	*r_edges, *edge_p, *edge_max;
 
 surf_t	*surfaces, *surface_p, *surf_max;
@@ -628,12 +626,11 @@
 void R_ScanEdges (void)
 {
 	int		iv, bottom;
-	byte	basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
 	espan_t	*basespan_p;
 	surf_t	*s;
 
 	basespan_p = (espan_t *)
-			((uintptr)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+			((uintptr)(r_basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
 	max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
 
 	span_p = basespan_p;
--- a/r_main.c
+++ b/r_main.c
@@ -11,6 +11,8 @@
 alight_t	r_viewlighting = {128, 192, viewlightvec};
 float		r_time1;
 int			r_numallocatededges;
+int			r_numallocatedbasespans;
+byte		*r_basespans;
 qboolean	r_drawpolys;
 qboolean	r_drawculledpolys;
 qboolean	r_worldpolysbacktofront;
@@ -108,10 +110,8 @@
 cvar_t	r_drawflat = {"r_drawflat", "0"};
 cvar_t	r_ambient = {"r_ambient", "0"};
 cvar_t	r_reportsurfout = {"r_reportsurfout", "0"};
-cvar_t	r_maxsurfs = {"r_maxsurfs", "0"};
 cvar_t	r_numsurfs = {"r_numsurfs", "0"};
 cvar_t	r_reportedgeout = {"r_reportedgeout", "0"};
-cvar_t	r_maxedges = {"r_maxedges", "0"};
 cvar_t	r_numedges = {"r_numedges", "0"};
 cvar_t	r_aliastransbase = {"r_aliastransbase", "200"};
 cvar_t	r_aliastransadj = {"r_aliastransadj", "100"};
@@ -132,7 +132,7 @@
 	byte	*dest;
 	
 // create a simple checkerboard texture for the default
-	r_notexture_mip = Hunk_AllocName(16*16+8*8+4*4+2*2 + sizeof *r_notexture_mip, "notexture");
+	r_notexture_mip = Hunk_Alloc(16*16+8*8+4*4+2*2 + sizeof *r_notexture_mip);
 	
 	r_notexture_mip->width = r_notexture_mip->height = 16;
 	r_notexture_mip->offsets[0] = sizeof *r_notexture_mip;
@@ -184,17 +184,12 @@
 	Cvar_RegisterVariable (&r_aliasstats);
 	Cvar_RegisterVariable (&r_dspeeds);
 	Cvar_RegisterVariable (&r_reportsurfout);
-	Cvar_RegisterVariable (&r_maxsurfs);
 	Cvar_RegisterVariable (&r_numsurfs);
 	Cvar_RegisterVariable (&r_reportedgeout);
-	Cvar_RegisterVariable (&r_maxedges);
 	Cvar_RegisterVariable (&r_numedges);
 	Cvar_RegisterVariable (&r_aliastransbase);
 	Cvar_RegisterVariable (&r_aliastransadj);
 
-	setcvarv ("r_maxedges", (float)NUMSTACKEDGES);
-	setcvarv ("r_maxsurfs", (float)NUMSTACKSURFACES);
-
 	view_clipplanes[0].leftedge = true;
 	view_clipplanes[1].rightedge = true;
 	view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
@@ -223,47 +218,26 @@
 // FIXME: is this one short?
 	for (i=0 ; i<cl.worldmodel->numleafs ; i++)
 		cl.worldmodel->leafs[i].efrags = nil;
-		 	
+
+	r_numallocatedbasespans = MAXSPANS;
+	r_basespans = Hunk_Alloc(r_numallocatedbasespans * sizeof(espan_t) + CACHE_SIZE);
 	r_viewleaf = nil;
 	R_ClearParticles ();
 
-	r_cnumsurfs = r_maxsurfs.value;
-
-	if (r_cnumsurfs <= MINSURFACES)
-		r_cnumsurfs = MINSURFACES;
-
-	if (r_cnumsurfs > NUMSTACKSURFACES)
-	{
-		surfaces = Hunk_AllocName(r_cnumsurfs * sizeof *surfaces, "surfaces");
-		surface_p = surfaces;
-		surf_max = &surfaces[r_cnumsurfs];
-		r_surfsonstack = false;
+	r_cnumsurfs = MAXSURFACES;
+	surfaces = Hunk_Alloc(r_cnumsurfs * sizeof *surfaces);
+	surface_p = surfaces;
+	surf_max = &surfaces[r_cnumsurfs];
 	// surface 0 doesn't really exist; it's just a dummy because index 0
 	// is used to indicate no edge attached to surface
-		surfaces--;
-	}
-	else
-	{
-		r_surfsonstack = true;
-	}
+	surfaces--;
 
 	r_maxedgesseen = 0;
 	r_maxsurfsseen = 0;
 
-	r_numallocatededges = r_maxedges.value;
+	r_numallocatededges = MAXEDGES;
+	r_edges = Hunk_Alloc(r_numallocatededges * sizeof *r_edges);
 
-	if (r_numallocatededges < MINEDGES)
-		r_numallocatededges = MINEDGES;
-
-	if (r_numallocatededges <= NUMSTACKEDGES)
-	{
-		auxedges = nil;
-	}
-	else
-	{
-		auxedges = Hunk_AllocName(r_numallocatededges * sizeof *auxedges, "edges");
-	}
-
 	r_dowarpold = false;
 	r_viewchanged = false;
 #ifdef PASSAGES
@@ -814,31 +788,6 @@
 */
 void R_EdgeDrawing (void)
 {
-	edge_t	ledges[NUMSTACKEDGES +
-				((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
-	surf_t	lsurfs[NUMSTACKSURFACES +
-				((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
-
-	if (auxedges)
-	{
-		r_edges = auxedges;
-	}
-	else
-	{
-		r_edges =  (edge_t *)
-				(((uintptr)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
-	}
-
-	if (r_surfsonstack)
-	{
-		surfaces =  (surf_t *)
-				(((uintptr)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
-		surf_max = &surfaces[r_cnumsurfs];
-	// surface 0 doesn't really exist; it's just a dummy because index 0
-	// is used to indicate no edge attached to surface
-		surfaces--;
-	}
-
 	R_BeginEdgeFrame ();
 
 	if (r_dspeeds.value)
@@ -877,9 +826,9 @@
 r_refdef must be set before the first call
 ================
 */
-void R_RenderView_ (void)
+void R_RenderView (void)
 {
-	byte	warpbuffer[WARP_WIDTH * WARP_HEIGHT];
+	static byte	warpbuffer[WARP_WIDTH * WARP_HEIGHT];
 
 	r_warpbuffer = warpbuffer;
 
@@ -958,27 +907,6 @@
 
 // back to high floating-point precision
 	fppdbl ();
-}
-
-void R_RenderView (void)
-{
-	int		dummy;
-	int		delta;
-	
-	delta = (byte *)&dummy - r_stack_start;
-	if (delta < -10000 || delta > 10000)
-		fatal ("R_RenderView: called without enough stack");
-
-	if ( Hunk_LowMark() & 3 )
-		fatal ("Hunk is missaligned");
-
-	if ( (uintptr)(&dummy) & 3 )
-		fatal ("Stack is missaligned");
-
-	if ( (uintptr)(&r_warpbuffer) & 3 )
-		fatal ("Globals are missaligned");
-
-	R_RenderView_ ();
 }
 
 /*
--- a/r_part.c
+++ b/r_part.c
@@ -4,7 +4,7 @@
 #include "quakedef.h"
 #include "fns.h"
 
-#define MAX_PARTICLES			2048	// default max # of particles at one
+#define MAX_PARTICLES			4096	// default max # of particles at one
 										//  time
 #define ABSOLUTE_MIN_PARTICLES	512		// no fewer than this no matter what's
 										//  on the command line
@@ -25,7 +25,7 @@
 R_InitParticles(void)
 {
 	r_numparticles = MAX_PARTICLES;
-	particles = Hunk_AllocName(r_numparticles * sizeof *particles, "particles");
+	particles = Hunk_Alloc(r_numparticles * sizeof *particles);
 }
 
 /*
--- a/r_shared.h
+++ b/r_shared.h
@@ -7,16 +7,12 @@
 #define MAXWORKINGVERTS	(MAXVERTS+4)	// max points in an intermediate
 										//  polygon (while processing)
 // !!! if this is changed, it must be changed in d_ifacea.h too !!!
-#define	MAXHEIGHT		2048
-#define	MAXWIDTH		2048
+#define	MAXHEIGHT		3840
+#define	MAXWIDTH		2160
 #define MAXDIMENSION	((MAXHEIGHT > MAXWIDTH) ? MAXHEIGHT : MAXWIDTH)
 
 #define SIN_BUFFER_SIZE	(MAXDIMENSION+CYCLE)
 
-#define INFINITE_DISTANCE	0x10000		// distance that's always guaranteed to
-										//  be farther away than anything in
-										//  the scene
-
 //===================================================================
 
 extern void	R_DrawLine (polyvert_t *polyvert0, polyvert_t *polyvert1);
@@ -39,11 +35,10 @@
 extern	vec3_t	vright, base_vright;
 extern	entity_t		*currententity;
 
-#define NUMSTACKEDGES		2400
-#define	MINEDGES			NUMSTACKEDGES
-#define NUMSTACKSURFACES	800
-#define MINSURFACES			NUMSTACKSURFACES
-#define	MAXSPANS			3000
+// NOTE: these are only initial values. limits are supposed to scale up dynamically
+#define	MAXEDGES			8192
+#define MAXSURFACES			8192
+#define	MAXSPANS			8192
 
 // !!! if this is changed, it must be changed in asm_draw.h too !!!
 typedef struct espan_s
@@ -74,6 +69,9 @@
 
 	int			pad[2];				// to 64 bytes
 } surf_t;
+
+extern int r_numallocatedbasespans;
+extern byte *r_basespans;
 
 extern	surf_t	*surfaces, *surface_p, *surf_max;
 
--- a/snd.c
+++ b/snd.c
@@ -311,7 +311,7 @@
 	stepscale = (float)info.rate / Srate;	
 	len = info.samples / stepscale;
 	len *= info.width * info.channels;
-	if(sc = Cache_Alloc(&sfx->cu, len + sizeof *sc, sfx->s), sc == nil)
+	if(sc = Cache_Alloc(&sfx->cu, len + sizeof *sc), sc == nil)
 		return nil;
 	sc->length = info.samples;
 	sc->loop = info.loopofs;
@@ -851,11 +851,7 @@
 	Cvar_RegisterVariable(&ambient_level);
 	Cvar_RegisterVariable(&ambient_fade);
 
-	if(memsize < 0x800000){
-		setcvar("loadas8bit", "1");
-		fprint(2, "initsnd: forcing 8bit width\n");
-	}
-	known_sfx = Hunk_AllocName(MAX_SFX * sizeof *known_sfx, "Sfx");
+	known_sfx = Hunk_Alloc(MAX_SFX * sizeof *known_sfx);
 	num_sfx = 0;
 	ambsfx[Ambwater] = precachesfx("ambience/water1.wav");
 	ambsfx[Ambsky] = precachesfx("ambience/wind2.wav");
--- a/sv_main.c
+++ b/sv_main.c
@@ -1049,7 +1049,7 @@
 // allocate server memory
 	sv.max_edicts = MAX_EDICTS;
 	
-	sv.edicts = Hunk_AllocName (sv.max_edicts*pr_edict_size, "edicts");
+	sv.edicts = Hunk_Alloc(sv.max_edicts*pr_edict_size);
 
 	sv.datagram.maxsize = sizeof sv.datagram_buf;
 	sv.datagram.cursize = 0;
--- a/vid.c
+++ b/vid.c
@@ -40,16 +40,15 @@
 		vid.height = 160;
 	if(d_pzbuffer != nil){
 		D_FlushCaches();
-		Hunk_FreeToHighMark(highhunk);
+		free(d_pzbuffer);
 		d_pzbuffer = nil;
 	}
 
-	highhunk = Hunk_HighMark();
 	// alloc an extra line in case we want to wrap, and allocate the z-buffer
 	hunkvbuf = vid.width * vid.height * sizeof *d_pzbuffer;
 	scachesz = D_SurfaceCacheForRes(vid.width, vid.height);
 	hunkvbuf += scachesz;
-	if((d_pzbuffer = Hunk_HighAllocName(hunkvbuf, "video")) == nil)
+	if((d_pzbuffer = malloc(hunkvbuf)) == nil)
 		sysfatal("Not enough memory for video mode\n");
 	surfcache = (byte *)d_pzbuffer + vid.width * vid.height * sizeof *d_pzbuffer;
 	D_InitCaches(surfcache, scachesz);
--- a/zone.c
+++ b/zone.c
@@ -4,856 +4,175 @@
 #include "quakedef.h"
 #include "fns.h"
 
-#define	DYNAMIC_SIZE	0xc000
+typedef struct mem_t mem_t;
 
-#define	ZONEID	0x1d4a11
-#define MINFRAGMENT	64
-
-typedef struct memblock_s
+struct mem_t
 {
-	int		size;           // including the header and possibly tiny fragments
-	int     tag;            // a tag of 0 is a free block
-	int     id;        		// should be ZONEID
-	struct memblock_s       *next, *prev;
-	int		pad;			// pad to 64 bit boundary
-} memblock_t;
+	mem_t *prev, *next;
+	mem_user_t *user;
+	int size; // NOT including this header
+};
 
-typedef struct
-{
-	int		size;		// total bytes malloced, including header
-	memblock_t	blocklist;		// start / end cap for linked list
-	memblock_t	*rover;
-} memzone_t;
+static mem_t *hunk_head;
+static mem_t *cache_head;
 
-void Cache_FreeLow (int new_low_hunk);
-void Cache_FreeHigh (int new_high_hunk);
-
-
-/*
-==============================================================================
-
-						ZONE MEMORY ALLOCATION
-
-There is never any space between memblocks, and there will never be two
-contiguous free memblocks.
-
-The rover can be left pointing at a non-empty block
-
-The zone calls are pretty much only used for small strings and structures,
-all big things are allocated on the hunk.
-==============================================================================
-*/
-
-memzone_t	*mainzone;
-
-void Z_ClearZone (memzone_t *zone, int size);
-
-
-/*
-========================
-Z_ClearZone
-========================
-*/
-void Z_ClearZone (memzone_t *zone, int size)
+int
+Hunk_From(void *p)
 {
-	memblock_t	*block;
-	
-// set the entire zone to one free block
+	mem_t *m;
+	int off;
 
-	zone->blocklist.next = zone->blocklist.prev = block =
-		(memblock_t *)((byte *)zone + sizeof(memzone_t));
-	zone->blocklist.tag = 1;	// in use block
-	zone->blocklist.id = 0;
-	zone->blocklist.size = 0;
-	zone->rover = block;
-	
-	block->prev = block->next = &zone->blocklist;
-	block->tag = 0;			// free block
-	block->id = ZONEID;
-	block->size = size - sizeof(memzone_t);
-}
-
-
-/*
-========================
-Z_Free
-========================
-*/
-void Z_Free (void *ptr)
-{
-	memblock_t	*block, *other;
-	
-	if (!ptr)
-		fatal ("Z_Free: NULL pointer");
-
-	block = (memblock_t *)((uchar *)ptr - sizeof(memblock_t));
-	if (block->id != ZONEID)
-		fatal ("Z_Free: freed a pointer without ZONEID");
-	if (block->tag == 0)
-		fatal ("Z_Free: freed a freed pointer");
-
-	block->tag = 0;		// mark as free
-	
-	other = block->prev;
-	if (!other->tag)
-	{	// merge with previous free block
-		other->size += block->size;
-		other->next = block->next;
-		other->next->prev = other;
-		if (block == mainzone->rover)
-			mainzone->rover = other;
-		block = other;
+	for(off = 0, m = hunk_head; m != nil; m = m->next){
+		off += m->size;
+		if((void*)(m+1) == p)
+			break;
 	}
-	
-	other = block->next;
-	if (!other->tag)
-	{	// merge the next free block onto the end
-		block->size += other->size;
-		block->next = other->next;
-		block->next->prev = block;
-		if (other == mainzone->rover)
-			mainzone->rover = block;
-	}
+	assert(m != nil || p == nil);
+	return off;
 }
 
-void *
-Z_Malloc(int size)
+void
+Hunk_CacheFrom(mem_user_t *c, void *p)
 {
-	void *buf;
+	int size;
+	mem_t *n, *prev;
+	byte *data;
 
-	Z_CheckHeap();	// DEBUG
-	if((buf = Z_TagMalloc(size, 1)) == nil)
-		fatal("Z_Malloc: failed on allocation of %d bytes", size);
-	memset(buf, 0, size);
-
-	return buf;
-}
-
-void *Z_TagMalloc (int size, int tag)
-{
-	int		extra;
-	memblock_t	*start, *rover, *new, *base;
-
-	if (!tag)
-		fatal ("Z_TagMalloc: tried to use a 0 tag");
-
-//
-// scan through the block list looking for the first free block
-// of sufficient size
-//
-	size += sizeof(memblock_t);	// account for size of block header
-	size += 4;					// space for memory trash tester
-	size = (size + 7) & ~7;		// align to 8-byte boundary
-	
-	base = rover = mainzone->rover;
-	start = base->prev;
-	
-	do
-	{
-		if (rover == start)	// scaned all the way around the list
-			return nil;
-		if (rover->tag)
-			base = rover = rover->next;
-		else
-			rover = rover->next;
-	} while (base->tag || base->size < size);
-	
-//
-// found a block big enough
-//
-	extra = base->size - size;
-	if (extra >  MINFRAGMENT)
-	{	// there will be a free fragment after the allocated block
-		new = (memblock_t *) ((byte *)base + size );
-		new->size = extra;
-		new->tag = 0;			// free block
-		new->prev = base;
-		new->id = ZONEID;
-		new->next = base->next;
-		new->next->prev = new;
-		base->next = new;
-		base->size = size;
+	for(size = 0, n = hunk_head; n != nil; n = n->next){
+		size += n->size;
+		if((void*)(n+1) == p)
+			break;
 	}
-	
-	base->tag = tag;				// no longer a free block
-	
-	mainzone->rover = base->next;	// next allocation will start looking here
-	
-	base->id = ZONEID;
+	assert((void*)(n+1) == p);
+	data = Cache_Alloc(c, size);
 
-// marker for memory trash testing
-	*(int *)((byte *)base + base->size - 4) = ZONEID;
-
-	return (void *) ((byte *)base + sizeof(memblock_t));
-}
-
-
-/*
-========================
-Z_Print
-========================
-*/
-void Z_Print (memzone_t *zone)
-{
-	memblock_t	*block;
-	
-	Con_Printf ("zone size: %d  location: %p\n",mainzone->size,mainzone);
-	
-	for (block = zone->blocklist.next ; ; block = block->next)
-	{
-		Con_Printf ("block:%p    size:%7d    tag:%3d\n",
-			block, block->size, block->tag);
-		
-		if (block->next == &zone->blocklist)
-			break;			// all blocks have been hit	
-		if ( (byte *)block + block->size != (byte *)block->next)
-			Con_Printf ("ERROR: block size does not touch the next block\n");
-		if ( block->next->prev != block)
-			Con_Printf ("ERROR: next block doesn't have proper back link\n");
-		if (!block->tag && !block->next->tag)
-			Con_Printf ("ERROR: two consecutive free blocks\n");
+	hunk_head = n->next;
+	if(hunk_head != nil)
+		hunk_head->prev = nil;
+	for(size = 0; n != nil; n = prev){
+		memmove(data+size, n+1, n->size);
+		size += n->size;
+		prev = n->prev;
+		free(n);
 	}
 }
 
-
-/*
-========================
-Z_CheckHeap
-========================
-*/
-void Z_CheckHeap (void)
+void *
+Hunk_Alloc(int size)
 {
-	memblock_t	*block;
-	
-	for (block = mainzone->blocklist.next ; ; block = block->next)
-	{
-		if (block->next == &mainzone->blocklist)
-			break;			// all blocks have been hit	
-		if ( (byte *)block + block->size != (byte *)block->next)
-			fatal ("Z_CheckHeap: block size does not touch the next block\n");
-		if ( block->next->prev != block)
-			fatal ("Z_CheckHeap: next block doesn't have proper back link\n");
-		if (!block->tag && !block->next->tag)
-			fatal ("Z_CheckHeap: two consecutive free blocks\n");
-	}
-}
+	mem_t *m;
 
-//============================================================================
+	size = (size+15)&~15;
+	m = mallocz(sizeof(*m) + size, 1);
+	if(m == nil)
+		sysfatal("Hunk_Alloc: %r");
+	m->size = size;
+	m->next = hunk_head;
+	if(hunk_head != nil)
+		hunk_head->prev = m;
+	hunk_head = m;
 
-#define	HUNK_SENTINAL	0x1df001ed
-
-typedef struct
-{
-	int		sentinal;
-	int		size;		// including sizeof(hunk_t), -1 = not allocated
-	char	name[8];
-} hunk_t;
-
-int		hunk_low_used;
-int		hunk_high_used;
-
-qboolean	hunk_tempactive;
-int		hunk_tempmark;
-
-void R_FreeTextures (void);
-
-/*
-==============
-Hunk_Check
-
-Run consistancy and sentinal trahing checks
-==============
-*/
-void Hunk_Check (void)
-{
-	hunk_t	*h;
-	
-	for (h = (hunk_t *)membase ; (byte *)h != membase + hunk_low_used ; )
-	{
-		if (h->sentinal != HUNK_SENTINAL)
-			fatal ("Hunk_Check: trahsed sentinal");
-		if (h->size < 16 || h->size + (byte *)h - membase > memsize)
-			fatal ("Hunk_Check: bad size");
-		h = (hunk_t *)((byte *)h+h->size);
-	}
+	return m+1;
 }
 
-/*
-==============
-Hunk_Print
-
-If "all" is specified, every single allocation is printed.
-Otherwise, allocations with the same name will be totaled up before printing.
-==============
-*/
-void Hunk_Print (qboolean all)
+void *
+Hunk_Mark(void)
 {
-	hunk_t	*h, *next, *endlow, *starthigh, *endhigh;
-	int		count, sum;
-	int		totalblocks;
-	char	name[9];
-
-	name[8] = 0;
-	count = 0;
-	sum = 0;
-	totalblocks = 0;
-	
-	h = (hunk_t *)membase;
-	endlow = (hunk_t *)(membase + hunk_low_used);
-	starthigh = (hunk_t *)(membase + memsize - hunk_high_used);
-	endhigh = (hunk_t *)(membase + memsize);
-
-	Con_Printf ("          :%8d total hunk size\n", memsize);
-	Con_Printf ("-------------------------\n");
-
-	while (1)
-	{
-	//
-	// skip to the high hunk if done with low hunk
-	//
-		if ( h == endlow )
-		{
-			Con_Printf ("-------------------------\n");
-			Con_Printf ("          :%8d REMAINING\n", memsize - hunk_low_used - hunk_high_used);
-			Con_Printf ("-------------------------\n");
-			h = starthigh;
-		}
-		
-	//
-	// if totally done, break
-	//
-		if ( h == endhigh )
-			break;
-
-	//
-	// run consistancy checks
-	//
-		if (h->sentinal != HUNK_SENTINAL)
-			fatal ("Hunk_Check: trahsed sentinal");
-		if (h->size < 16 || h->size + (byte *)h - membase > memsize)
-			fatal ("Hunk_Check: bad size");
-			
-		next = (hunk_t *)((byte *)h+h->size);
-		count++;
-		totalblocks++;
-		sum += h->size;
-
-	//
-	// print the single block
-	//
-		memcpy(name, h->name, 8);
-		if (all)
-			Con_Printf ("%8p :%8d %8s\n",h, h->size, name);
-			
-	//
-	// print the total
-	//
-		if (next == endlow || next == endhigh || 
-		strncmp (h->name, next->name, 8) )
-		{
-			if (!all)
-				Con_Printf ("          :%8d %8s (TOTAL)\n",sum, name);
-			count = 0;
-			sum = 0;
-		}
-
-		h = next;
-	}
-
-	Con_Printf ("-------------------------\n");
-	Con_Printf ("%8d total blocks\n", totalblocks);
-	
+	return hunk_head;
 }
 
-/*
-===================
-Hunk_AllocName
-===================
-*/
-void *Hunk_AllocName (int size, char *name)
+void
+Hunk_FreeToMark(void *mark)
 {
-	hunk_t	*h;
-	
-#ifdef PARANOID
-	Hunk_Check ();
-#endif
+	mem_t *m;
 
-	if (size < 0)
-		fatal ("Hunk_Alloc: bad size: %d", size);
-		
-	size = sizeof(hunk_t) + ((size+15)&~15);
-	
-	if (memsize - hunk_low_used - hunk_high_used < size)
-		fatal ("Hunk_Alloc: failed on %d bytes",size);
-	
-	h = (hunk_t *)(membase + hunk_low_used);
-	hunk_low_used += size;
-
-	Cache_FreeLow (hunk_low_used);
-
-	memset(h, 0, size);
-	
-	h->size = size;
-	h->sentinal = HUNK_SENTINAL;
-	strncpy(h->name, name, 8);
-	
-	return (void *)(h+1);
-}
-
-/*
-===================
-Hunk_Alloc
-===================
-*/
-void *Hunk_Alloc (int size)
-{
-	return Hunk_AllocName (size, "unknown");
-}
-
-int	Hunk_LowMark (void)
-{
-	return hunk_low_used;
-}
-
-void Hunk_FreeToLowMark (int mark)
-{
-	if (mark < 0 || mark > hunk_low_used)
-		fatal ("Hunk_FreeToLowMark: bad mark %d", mark);
-	memset(membase + mark, 0, hunk_low_used - mark);
-	hunk_low_used = mark;
-}
-
-int	Hunk_HighMark (void)
-{
-	if (hunk_tempactive)
-	{
-		hunk_tempactive = false;
-		Hunk_FreeToHighMark (hunk_tempmark);
+	while(hunk_head != mark){
+		m = hunk_head->next;
+		free(hunk_head);
+		hunk_head = m;
 	}
-
-	return hunk_high_used;
 }
 
-void Hunk_FreeToHighMark (int mark)
+void *
+Hunk_TempAlloc(int size)
 {
-	if (hunk_tempactive)
-	{
-		hunk_tempactive = false;
-		Hunk_FreeToHighMark (hunk_tempmark);
-	}
-	if (mark < 0 || mark > hunk_high_used)
-		fatal ("Hunk_FreeToHighMark: bad mark %d", mark);
-	memset(membase + memsize - hunk_high_used, 0, hunk_high_used - mark);
-	hunk_high_used = mark;
-}
+	static void	*buf;
+	static int bufsz;
 
+	if(bufsz > size)
+		return buf;
+	buf = realloc(buf, size);
+	if(buf == nil)
+		sysfatal("Hunk_TempAlloc: %r");
+	bufsz = size;
 
-/*
-===================
-Hunk_HighAllocName
-===================
-*/
-void *Hunk_HighAllocName (int size, char *name)
-{
-	hunk_t	*h;
-
-	if (size < 0)
-		fatal ("Hunk_HighAllocName: bad size: %d", size);
-
-	if (hunk_tempactive)
-	{
-		Hunk_FreeToHighMark (hunk_tempmark);
-		hunk_tempactive = false;
-	}
-
-#ifdef PARANOID
-	Hunk_Check ();
-#endif
-
-	size = sizeof(hunk_t) + ((size+15)&~15);
-
-	if (memsize - hunk_low_used - hunk_high_used < size)
-	{
-		Con_Printf ("Hunk_HighAlloc: failed on %d bytes\n",size);
-		return nil;
-	}
-
-	hunk_high_used += size;
-	Cache_FreeHigh (hunk_high_used);
-
-	h = (hunk_t *)(membase + memsize - hunk_high_used);
-
-	memset(h, 0, size);
-	h->size = size;
-	h->sentinal = HUNK_SENTINAL;
-	strncpy(h->name, name, 8);
-
-	return (void *)(h+1);
-}
-
-
-/*
-=================
-Hunk_TempAlloc
-
-Return space from the top of the hunk
-=================
-*/
-void *Hunk_TempAlloc (int size)
-{
-	void	*buf;
-
-	size = (size+15)&~15;
-	
-	if (hunk_tempactive)
-	{
-		Hunk_FreeToHighMark (hunk_tempmark);
-		hunk_tempactive = false;
-	}
-	
-	hunk_tempmark = Hunk_HighMark ();
-
-	buf = Hunk_HighAllocName (size, "temp");
-
-	hunk_tempactive = true;
-
 	return buf;
 }
 
-/*
-===============================================================================
-
-CACHE MEMORY
-
-===============================================================================
-*/
-
-typedef struct cache_system_s
+void *
+Cache_Check(mem_user_t *c)
 {
-	int						size;		// including this header
-	cache_user_t			*user;
-	char					name[16];
-	struct cache_system_s	*prev, *next;
-	struct cache_system_s	*lru_prev, *lru_next;	// for LRU flushing	
-} cache_system_t;
-
-cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);
-
-cache_system_t	cache_head;
-
-/*
-===========
-Cache_Move
-===========
-*/
-void Cache_Move ( cache_system_t *c)
-{
-	cache_system_t		*new;
-
-// we are clearing up space at the bottom, so only allocate it late
-	new = Cache_TryAlloc (c->size, true);
-	if (new)
-	{
-//		Con_Printf ("cache_move ok\n");
-
-		memcpy(new+1, c+1, c->size - sizeof *new);
-		new->user = c->user;
-		memcpy(new->name, c->name, sizeof new->name);
-		Cache_Free (c->user);
-		new->user->data = (void *)(new+1);
-	}
-	else
-	{
-//		Con_Printf ("cache_move failed\n");
-
-		Cache_Free (c->user);		// tough luck...
-	}
+	return c->data;
 }
 
-/*
-============
-Cache_FreeLow
-
-Throw things out until the hunk can be expanded to the given point
-============
-*/
-void Cache_FreeLow (int new_low_hunk)
+static void
+Cache_Flush(void)
 {
-	cache_system_t	*c;
-	
-	while (1)
-	{
-		c = cache_head.next;
-		if (c == &cache_head)
-			return;		// nothing in cache at all
-		if ((byte *)c >= membase + new_low_hunk)
-			return;		// there is space to grow the hunk
-		Cache_Move ( c );	// reclaim the space
-	}
-}
-
-/*
-============
-Cache_FreeHigh
-
-Throw things out until the hunk can be expanded to the given point
-============
-*/
-void Cache_FreeHigh (int new_high_hunk)
-{
-	cache_system_t	*c, *prev;
-	
-	prev = nil;
-	while (1)
-	{
-		c = cache_head.prev;
-		if (c == &cache_head)
-			return;		// nothing in cache at all
-		if ( (byte *)c + c->size <= membase + memsize - new_high_hunk)
-			return;		// there is space to grow the hunk
-		if (c == prev)
-			Cache_Free (c->user);	// didn't move out of the way
-		else
-		{
-			Cache_Move (c);	// try to move it
-			prev = c;
-		}
-	}
-}
-
-void Cache_UnlinkLRU (cache_system_t *cs)
-{
-	if (!cs->lru_next || !cs->lru_prev)
-		fatal ("Cache_UnlinkLRU: NULL link");
-
-	cs->lru_next->lru_prev = cs->lru_prev;
-	cs->lru_prev->lru_next = cs->lru_next;
-	
-	cs->lru_prev = cs->lru_next = nil;
-}
-
-void Cache_MakeLRU (cache_system_t *cs)
-{
-	if (cs->lru_next || cs->lru_prev)
-		fatal ("Cache_MakeLRU: active link");
-
-	cache_head.lru_next->lru_prev = cs;
-	cs->lru_next = cache_head.lru_next;
-	cs->lru_prev = &cache_head;
-	cache_head.lru_next = cs;
-}
-
-/*
-============
-Cache_TryAlloc
-
-Looks for a free block of memory between the high and low hunk marks
-Size should already include the header and padding
-============
-*/
-cache_system_t *Cache_TryAlloc (int size, qboolean nobottom)
-{
-	cache_system_t	*cs, *new;
-	
-// is the cache completely empty?
-
-	if (!nobottom && cache_head.prev == &cache_head)
-	{
-		if (memsize - hunk_high_used - hunk_low_used < size)
-			fatal ("Cache_TryAlloc: %d is greater then free hunk", size);
-
-		new = (cache_system_t *) (membase + hunk_low_used);
-		memset(new, 0, sizeof *new);
-		new->size = size;
-
-		cache_head.prev = cache_head.next = new;
-		new->prev = new->next = &cache_head;
+	mem_t *s;
 		
-		Cache_MakeLRU (new);
-		return new;
+	while(cache_head != nil){
+		s = cache_head->next;
+		cache_head->user->data = nil;
+		free(cache_head);
+		cache_head = s;
 	}
-	
-// search from the bottom up for space
-
-	new = (cache_system_t *) (membase + hunk_low_used);
-	cs = cache_head.next;
-	
-	do
-	{
-		if (!nobottom || cs != cache_head.next)
-		{
-			if ( (byte *)cs - (byte *)new >= size)
-			{	// found space
-				memset(new, 0, sizeof *new);
-				new->size = size;
-				
-				new->next = cs;
-				new->prev = cs->prev;
-				cs->prev->next = new;
-				cs->prev = new;
-				
-				Cache_MakeLRU (new);
-	
-				return new;
-			}
-		}
-
-	// continue looking		
-		new = (cache_system_t *)((byte *)cs + cs->size);
-		cs = cs->next;
-
-	} while (cs != &cache_head);
-	
-// try to allocate one at the very end
-	if ( membase + memsize - hunk_high_used - (byte *)new >= size)
-	{
-		memset(new, 0, sizeof *new);
-		new->size = size;
-		
-		new->next = &cache_head;
-		new->prev = cache_head.prev;
-		cache_head.prev->next = new;
-		cache_head.prev = new;
-		
-		Cache_MakeLRU (new);
-
-		return new;
-	}
-	
-	return nil;		// couldn't allocate
 }
 
-/*
-============
-Cache_Flush
-
-Throw everything out, so new data will be demand cached
-============
-*/
-void Cache_Flush (void)
-{
-	while (cache_head.next != &cache_head)
-		Cache_Free ( cache_head.next->user );	// reclaim the space
-}
-
 void
-Cache_Report(void)
+Cache_Free(mem_user_t *c)
 {
-	dprint("%4.1f megabyte data cache\n",
-		(memsize - hunk_high_used - hunk_low_used)
-		/ (float)(1024*1024));
-}
+	mem_t *cs;
 
-/*
-============
-Cache_Init
+	if(!c->data)
+		fatal("Cache_Free: not allocated");
 
-============
-*/
-void Cache_Init (void)
-{
-	cache_head.next = cache_head.prev = &cache_head;
-	cache_head.lru_next = cache_head.lru_prev = &cache_head;
-
-	Cmd_AddCommand ("flush", Cache_Flush);
-}
-
-/*
-==============
-Cache_Free
-
-Frees the memory and removes it from the LRU list
-==============
-*/
-void Cache_Free (cache_user_t *c)
-{
-	cache_system_t	*cs;
-
-	if (!c->data)
-		fatal ("Cache_Free: not allocated");
-
-	cs = ((cache_system_t *)c->data) - 1;
-
+	cs = ((mem_t *)c->data) - 1;
+	if(cs == cache_head)
+		cache_head = cs->next;
 	cs->prev->next = cs->next;
 	cs->next->prev = cs->prev;
 	cs->next = cs->prev = nil;
 
 	c->data = nil;
-
-	Cache_UnlinkLRU (cs);
+	free(cs);
 }
 
-
-
-/*
-==============
-Cache_Check
-==============
-*/
-void *Cache_Check (cache_user_t *c)
+void *
+Cache_Alloc(mem_user_t *c, int size)
 {
-	cache_system_t	*cs;
+	mem_t *cs;
 
-	if (!c->data)
-		return nil;
+	if(c->data)
+		fatal("Cache_Alloc: allready allocated");
+	if(size <= 0)
+		fatal("Cache_Alloc: size %d", size);
 
-	cs = ((cache_system_t *)c->data) - 1;
-
-// move to head of LRU
-	Cache_UnlinkLRU (cs);
-	Cache_MakeLRU (cs);
+	cs = mallocz(sizeof(*cs) + size, 1);
+	if(cs == nil)
+		sysfatal("Cache_Alloc: %r");
+	cs->size = size;
+	cs->next = cache_head;
+	if(cache_head != nil)
+		cache_head->prev = cs;
+	cache_head = cs;
+	c->data = cs+1;
+	cs->user = c;
 	
 	return c->data;
 }
 
-
-/*
-==============
-Cache_Alloc
-==============
-*/
-void *Cache_Alloc (cache_user_t *c, int size, char *name)
+void
+Memory_Init(void)
 {
-	cache_system_t	*cs;
-
-	if (c->data)
-		fatal ("Cache_Alloc: allready allocated");
-	
-	if (size <= 0)
-		fatal ("Cache_Alloc: size %d", size);
-
-	size = (size + sizeof(*cs) + 15) & ~15;
-
-// find memory for it	
-	while (1)
-	{
-		cs = Cache_TryAlloc (size, false);
-		if (cs)
-		{
-			strncpy (cs->name, name, sizeof(cs->name)-1);
-			c->data = (void *)(cs+1);
-			cs->user = c;
-			break;
-		}
-	
-	// free the least recently used cahedat
-		if (cache_head.lru_prev == &cache_head)
-			fatal ("Cache_Alloc: out of memory");
-													// not enough memory at all
-		Cache_Free ( cache_head.lru_prev->user );
-	} 
-	
-	return Cache_Check (c);
-}
-
-void Memory_Init (void)
-{
-	int zonesize = DYNAMIC_SIZE;
-
-	hunk_low_used = 0;
-	hunk_high_used = 0;
-	
-	Cache_Init ();
-	mainzone = Hunk_AllocName (zonesize, "zone" );
-	Z_ClearZone (mainzone, zonesize);
+	Cmd_AddCommand("flush", Cache_Flush);
 }
--- a/zone.h
+++ b/zone.h
@@ -1,112 +1,20 @@
-/*
- memory allocation
-
-
-H_??? The hunk manages the entire memory block given to quake.  It must be
-contiguous.  Memory can be allocated from either the low or high end in a
-stack fashion.  The only way memory is released is by resetting one of the
-pointers.
-
-Hunk allocations should be given a name, so the Hunk_Print () function
-can display usage.
-
-Hunk allocations are guaranteed to be 16 byte aligned.
-
-The video buffers are allocated high to avoid leaving a hole underneath
-server allocations when changing to a higher video mode.
-
-
-Z_??? Zone memory functions used for small, dynamic allocations like text
-strings from command input.  There is only about 48K for it, allocated at
-the very bottom of the hunk.
-
-Cache_??? Cache memory is for objects that can be dynamically loaded and
-can usefully stay persistant between levels.  The size of the cache
-fluctuates from level to level.
-
-To allocate a cachable object
-
-
-Temp_??? Temp memory is used for file loading and surface caching.  The size
-of the cache memory is adjusted so that there is a minimum of 512k remaining
-for temp memory.
-
-
------- Top of Memory -------
-
-high hunk allocations
-
-<--- high hunk reset point held by vid
-
-video buffer
-
-z buffer
-
-surface cache
-
-<--- high hunk used
-
-cachable memory
-
-<--- low hunk used
-
-client and server low hunk allocations
-
-<-- low hunk reset point held by host
-
-startup hunk allocations
-
-Zone block
-
------ Bottom of Memory -----
-
-
-
-*/
-
-void Memory_Init (void);
-
-void Z_Free (void *ptr);
-void *Z_Malloc (int size);			// returns 0 filled memory
-void *Z_TagMalloc (int size, int tag);
-
-void Z_DumpHeap (void);
-void Z_CheckHeap (void);
-int Z_FreeMemory (void);
-
-void *Hunk_Alloc (int size);		// returns 0 filled memory
-void *Hunk_AllocName (int size, char *name);
-
-void *Hunk_HighAllocName (int size, char *name);
-
-int	Hunk_LowMark (void);
-void Hunk_FreeToLowMark (int mark);
-
-int	Hunk_HighMark (void);
-void Hunk_FreeToHighMark (int mark);
-
-void *Hunk_TempAlloc (int size);
-
-void Hunk_Check (void);
-
-typedef struct cache_user_s
+typedef struct
 {
-	void	*data;
-} cache_user_t;
+	void *data;
+}mem_user_t;
 
-void Cache_Flush (void);
+#define Z_Free(p) free(p)
+#define Z_Malloc(sz) mallocz((sz), 1)
 
-void *Cache_Check (cache_user_t *c);
-// returns the cached data, and moves to the head of the LRU list
-// if present, otherwise returns NULL
+int Hunk_From(void *p);
+void Hunk_CacheFrom(mem_user_t *c, void *p);
+void *Hunk_Alloc(int size);
+void *Hunk_Mark(void);
+void Hunk_FreeToMark(void *mark);
+void *Hunk_TempAlloc(int size);
 
-void Cache_Free (cache_user_t *c);
+void *Cache_Alloc(mem_user_t *c, int size);
+void *Cache_Check(mem_user_t *c);
+void Cache_Free(mem_user_t *c);
 
-void *Cache_Alloc (cache_user_t *c, int size, char *name);
-// Returns NULL if all purgable data was tossed and there still
-// wasn't enough room.
-
-void Cache_Report (void);
-
-
-
+void Memory_Init(void);