From 419b2b1f7f9399401a56bf7317c115acbfe989ff Mon Sep 17 00:00:00 2001
From: Spoike <acceptthis@users.sourceforge.net>
Date: Mon, 26 Jun 2017 09:31:02 +0000
Subject: [PATCH] fix brush editor giving up with too many polys. fix race
 condition that was causing prespawning to skip the call to CSQC_WorldLoaded.
 misc other irrelevant tweaks.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5120 fc73d0e0-1445-4013-8a0c-d673dee63da5
---
 engine/client/cl_parse.c             |   4 +-
 engine/client/cl_screen.c            |   6 +-
 engine/client/console.c              |   2 +-
 engine/client/image.c                | 243 +++++++++++++--------------
 engine/gl/gl_heightmap.c             | 126 +++++++-------
 engine/server/pr_cmds.c              |   2 +-
 engine/server/sv_mvd.c               |  14 +-
 engine/server/sv_send.c              |   3 +-
 quakec/csaddon/src/editor_brushes.qc |  13 +-
 9 files changed, 204 insertions(+), 209 deletions(-)

diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c
index 8b5782155..354dff406 100644
--- a/engine/client/cl_parse.c
+++ b/engine/client/cl_parse.c
@@ -1175,8 +1175,8 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload)
 
 	float giveuptime = Sys_DoubleTime()+1;	//small things get padded into a single frame
 
-#define atstage() ((cl.contentstage == stage++ && !dontactuallyload)?++cl.contentstage:false)
-#define endstage() if (!cls.timedemo && giveuptime<Sys_DoubleTime()) return -1;
+#define atstage() ((cl.contentstage == stage++ && !dontactuallyload)?true:false)
+#define endstage() ++cl.contentstage;if (!cls.timedemo && giveuptime<Sys_DoubleTime()) return -1;
 
 	pmove.numphysent = 0;
 	pmove.physents[0].model = NULL;
diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c
index 099bc7ccf..4da92cd37 100644
--- a/engine/client/cl_screen.c
+++ b/engine/client/cl_screen.c
@@ -2289,11 +2289,11 @@ qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer,
 	}
 	else
 #endif
-	/*	if (!Q_strcasecmp(ext, "bmp"))
+		if (!Q_strcasecmp(ext, "bmp"))
 	{
-		return WriteBMPFile(pcxname, buffer[0], width, height);
+		return WriteBMPFile(filename, fsroot, buffer[0], bytestride, width, height, fmt);
 	}
-	else*/
+	else
 		if (!Q_strcasecmp(ext, "pcx"))
 	{
 		int y, x, s;
diff --git a/engine/client/console.c b/engine/client/console.c
index c1dedbd54..b2ca74d44 100644
--- a/engine/client/console.c
+++ b/engine/client/console.c
@@ -772,7 +772,7 @@ conline_t *Con_ResizeLineBuffer(console_t *con, conline_t *old, unsigned int len
 {
 	conline_t *l;
 
-	old->maxlength = length;
+	old->maxlength = length & 0xffff;
 	if (old->maxlength < old->length)
 		return NULL;	//overflow.
 	l = BZ_Realloc(old, sizeof(*l)+(old->maxlength)*sizeof(conchar_t));
diff --git a/engine/client/image.c b/engine/client/image.c
index a8ab49c9d..778fcec2d 100644
--- a/engine/client/image.c
+++ b/engine/client/image.c
@@ -2051,22 +2051,31 @@ qbyte *ReadPCXPalette(qbyte *buf, int len, qbyte *out)
 typedef struct bmpheader_s
 {
 /*	unsigned short	Type;*/
-	unsigned long	Size;
+	unsigned int	Size;
 	unsigned short	Reserved1;
 	unsigned short	Reserved2;
-	unsigned long	OffsetofBMPBits;
-	unsigned long	SizeofBITMAPINFOHEADER;
-	signed long		Width;
-	signed long		Height;
+	unsigned int	OffsetofBMPBits;
+	unsigned int	SizeofBITMAPINFOHEADER;
+	signed int		Width;
+	signed int		Height;
 	unsigned short	Planes;
 	unsigned short	BitCount;
-	unsigned long	Compression;
-	unsigned long	ImageSize;
-	signed long		TargetDeviceXRes;
-	signed long		TargetDeviceYRes;
-	unsigned long	NumofColorIndices;
-	unsigned long	NumofImportantColorIndices;
+	unsigned int	Compression;
+	unsigned int	ImageSize;
+	signed int		TargetDeviceXRes;
+	signed int		TargetDeviceYRes;
+	unsigned int	NumofColorIndices;
+	unsigned int	NumofImportantColorIndices;
 } bmpheader_t;
+typedef struct bmpheaderv4_s
+{
+	unsigned int	RedMask;
+	unsigned int	GreenMask;
+	unsigned int	BlueMask;
+	unsigned int	AlphaMask;
+	qbyte			ColourSpace[4];	//"Win " or "sRGB"
+	qbyte			ColourSpaceCrap[24+4*3];
+} bmpheaderv4_t;
 
 qbyte *ReadBMPFile(qbyte *buf, int length, int *width, int *height)
 {
@@ -2094,7 +2103,7 @@ qbyte *ReadBMPFile(qbyte *buf, int length, int *width, int *height)
 	h.NumofColorIndices = LittleLong(h.NumofColorIndices);
 	h.NumofImportantColorIndices = LittleLong(h.NumofImportantColorIndices);
 
-	if (h.Compression)	//probably RLE?
+	if (h.Compression)	//RLE? BITFIELDS (gah)?
 		return NULL;
 
 	*width = h.Width;
@@ -2195,134 +2204,108 @@ qbyte *ReadBMPFile(qbyte *buf, int length, int *width, int *height)
 	return NULL;
 }
 
-/*void WriteBMPFile(char *filename, qbyte *in, int width, int height)
+void WriteBMPFile(char *filename, enum fs_relative fsroot, qbyte *in, int instride, int width, int height, uploadfmt_t fmt)
 {
-	unsigned int i;
-	bmpheader_t *h;
+	int y;
+	bmpheader_t h;
+	bmpheaderv4_t h4;
 	qbyte *data;
 	qbyte *out;
+	int outstride;
+	int bits = 32;
+	int extraheadersize = sizeof(h4);
 
-	out = BZ_Malloc(sizeof(bmpheader_t)+width*3*height);
-
-
-
-	*(short*)((qbyte *)h-2) = *(short*)"BM";
-	h->Size = LittleLong(in->Size);
-	h->Reserved1 = LittleShort(in->Reserved1);
-	h->Reserved2 = LittleShort(in->Reserved2);
-	h->OffsetofBMPBits = LittleLong(in->OffsetofBMPBits);
-	h->SizeofBITMAPINFOHEADER = LittleLong(in->SizeofBITMAPINFOHEADER);
-	h->Width = LittleLong(in->Width);
-	h->Height = LittleLong(in->Height);
-	h->Planes = LittleShort(in->Planes);
-	h->BitCount = LittleShort(in->BitCount);
-	h->Compression = LittleLong(in->Compression);
-	h->ImageSize = LittleLong(in->ImageSize);
-	h->TargetDeviceXRes = LittleLong(in->TargetDeviceXRes);
-	h->TargetDeviceYRes = LittleLong(in->TargetDeviceYRes);
-	h->NumofColorIndices = LittleLong(in->NumofColorIndices);
-	h->NumofImportantColorIndices = LittleLong(in->NumofImportantColorIndices);
-
-	if (h.Compression)	//probably RLE?
-		return NULL;
-
-	*width = h.Width;
-	*height = h.Height;
-
-	if (h.NumofColorIndices != 0 || h.BitCount == 8)	//8 bit
+	memset(&h4, 0, sizeof(h4));
+	h4.ColourSpace[0] = 'W';
+	h4.ColourSpace[1] = 'i';
+	h4.ColourSpace[2] = 'n';
+	h4.ColourSpace[3] = ' ';
+	switch(fmt)
 	{
-		int x, y;
-		unsigned int *data32;
-		unsigned int	pal[256];
-		if (!h.NumofColorIndices)
-			h.NumofColorIndices = (int)pow(2, h.BitCount);
-		if (h.NumofColorIndices>256)
-			return NULL;
+	case TF_RGBA32:
+		h4.RedMask		= 0x000000ff;
+		h4.GreenMask	= 0x0000ff00;
+		h4.BlueMask		= 0x00ff0000;
+		h4.AlphaMask	= 0xff000000;
+		break;
+	case TF_BGRA32:
+		h4.RedMask		= 0x00ff0000;
+		h4.GreenMask	= 0x0000ff00;
+		h4.BlueMask		= 0x000000ff;
+		h4.AlphaMask	= 0xff000000;
+		break;
+	case TF_RGBX32:
+		h4.RedMask		= 0x000000ff;
+		h4.GreenMask	= 0x0000ff00;
+		h4.BlueMask		= 0x00ff0000;
+		h4.AlphaMask	= 0x00000000;
+		break;
+	case TF_BGRX32:
+		h4.RedMask		= 0x00ff0000;
+		h4.GreenMask	= 0x0000ff00;
+		h4.BlueMask		= 0x000000ff;
+		h4.AlphaMask	= 0x00000000;
+		break;
+	case TF_RGB24:
+		h4.RedMask		= 0x000000ff;
+		h4.GreenMask	= 0x0000ff00;
+		h4.BlueMask		= 0x00ff0000;
+		h4.AlphaMask	= 0x00000000;
+		bits = 3;
+		break;
+	case TF_BGR24:
+		h4.RedMask		= 0x00ff0000;
+		h4.GreenMask	= 0x0000ff00;
+		h4.BlueMask		= 0x000000ff;
+		h4.AlphaMask	= 0x00000000;
+		bits = 3;
+		extraheadersize = 0;
+		break;
 
-		data = buf+2;
-		data += sizeof(h);
-
-		for (i = 0; i < h.NumofColorIndices; i++)
-		{
-			pal[i] = data[i*4+0] + (data[i*4+1]<<8) + (data[i*4+2]<<16) + (255/<<16);
-		}
-
-		buf += h.OffsetofBMPBits;
-		data32 = BZ_Malloc(h.Width * h.Height*4);
-		for (y = 0; y < h.Height; y++)
-		{
-			i = (h.Height-1-y) * (h.Width);
-			for (x = 0; x < h.Width; x++)
-			{
-				data32[i] = pal[buf[x]];
-				i++;
-			}
-			buf += h.Width;
-		}
-
-		return (qbyte *)data32;
+	default:
+		return;
 	}
-	else if (h.BitCount == 4)	//4 bit
+
+
+	outstride = width * (bits/8);
+	outstride = (outstride+3)&~3;	//bmp pads rows to a multiple of 4 bytes.
+
+	data = BZ_Malloc(2+sizeof(h)+extraheadersize+width*outstride);
+	out = data+2+sizeof(h)+extraheadersize;
+
+
+	data[0] = 'B';
+	data[1] = 'M';
+	h.Size = 2+sizeof(h)+extraheadersize + outstride*height;
+	h.Reserved1 = 0;
+	h.Reserved2 = 0;
+	h.OffsetofBMPBits = 2+sizeof(h)+extraheadersize;
+	h.SizeofBITMAPINFOHEADER = sizeof(h)+extraheadersize;
+	h.Width = width;
+	h.Height = height;
+	h.Planes = 1;
+	h.BitCount = bits;
+	h.Compression = extraheadersize?3/*BI_BITFIELDS*/:0/*BI_RGB aka BGR...*/;
+	h.ImageSize = outstride*height;
+	h.TargetDeviceXRes = 2835;//72DPI
+	h.TargetDeviceYRes = 2835;
+	h.NumofColorIndices = 0;
+	h.NumofImportantColorIndices = 0;
+	memcpy(data+2, &h, sizeof(h));
+	if (extraheadersize)
+		memcpy(data+2+sizeof(h), &h4, sizeof(h4));
+
+	for (y = 0; y < height; y++)
 	{
-		int x, y;
-		unsigned int *data32;
-		unsigned int	pal[16];
-		if (!h.NumofColorIndices)
-			h.NumofColorIndices = (int)pow(2, h.BitCount);
-		if (h.NumofColorIndices>16)
-			return NULL;
-		if (h.Width&1)
-			return NULL;
-
-		data = buf+2;
-		data += sizeof(h);
-
-		for (i = 0; i < h.NumofColorIndices; i++)
-		{
-			pal[i] = data[i*4+0] + (data[i*4+1]<<8) + (data[i*4+2]<<16) + (255<<16);
-		}
-
-		buf += h.OffsetofBMPBits;
-		data32 = BZ_Malloc(h.Width * h.Height*4);
-		for (y = 0; y < h.Height; y++)
-		{
-			i = (h.Height-1-y) * (h.Width);
-			for (x = 0; x < h.Width/2; x++)
-			{
-				data32[i++] = pal[buf[x]>>4];
-				data32[i++] = pal[buf[x]&15];
-			}
-			buf += h.Width>>1;
-		}
-
-		return (qbyte *)data32;
+		memcpy(out, in, width * (bits/8));
+		memset(out+width*(bits/8), 0, outstride-width*(bits/8));
+		out += outstride;
+		in += instride;
 	}
-	else if (h.BitCount == 24)	//24 bit... no 16?
-	{
-		int x, y;
-		buf += h.OffsetofBMPBits;
-		data = BZ_Malloc(h.Width * h.Height*4);
-		for (y = 0; y < h.Height; y++)
-		{
-			i = (h.Height-1-y) * (h.Width);
-			for (x = 0; x < h.Width; x++)
-			{
-				data[i*4+0] = buf[x*3+2];
-				data[i*4+1] = buf[x*3+1];
-				data[i*4+2] = buf[x*3+0];
-				data[i*4+3] = 255;
-				i++;
-			}
-			buf += h.Width*3;
-		}
 
-		return data;
-	}
-	else
-		return NULL;
-
-	return NULL;
-}*/
+	COM_WriteFile(filename, fsroot, data, h.Size);
+	BZ_Free(data);
+}
 
 
 #ifndef NPFTE
diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c
index b80094faf..4086b0a57 100644
--- a/engine/gl/gl_heightmap.c
+++ b/engine/gl/gl_heightmap.c
@@ -5736,78 +5736,84 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
 			{
 				i = 0;
 				br = hm->wbrushes;
-				for (numverts = 0, numindicies = 0; i < hm->numbrushes; i++, br++)
+				for (;i < hm->numbrushes;)
 				{
-					//if a single batch has too many verts, cut it off before it overflows our maximum batch size, and hope we don't get a really really complex brush.
-					if (numverts > 0xf000 || numindicies > 0xf000)
-						break;
-
-					for (j = 0; j < br->numplanes; j++)
+					for (numverts = 0, numindicies = 0; i < hm->numbrushes; i++, br++)
 					{
-						if (br->faces[j].tex == bt && !br->selected && br->faces[j].lightmap == lmnum)
+						//if a single batch has too many verts, cut it off before it overflows our maximum batch size, and hope we don't get a really really complex brush.
+						if (numverts > 0xf000 || numindicies > 0xf000)
+							break;
+
+						for (j = 0; j < br->numplanes; j++)
 						{
-							size_t k, o;
-							float s,t;
-
-							for (k = 0, o = numverts; k < br->faces[j].numpoints; k++, o++)
+							if (br->faces[j].tex == bt && !br->selected && br->faces[j].lightmap == lmnum)
 							{
-								VectorCopy(br->faces[j].points[k], arrays->coord[o]);
-								VectorCopy(br->planes[j], arrays->normal[o]);
-								VectorCopy(br->faces[j].stdir[0], arrays->svector[o]);
-								VectorCopy(br->faces[j].stdir[1], arrays->tvector[o]);
+								size_t k, o;
+								float s,t;
 
-								//compute the texcoord planes
-								s = (DotProduct(arrays->svector[o], arrays->coord[o]) + br->faces[j].stdir[0][3]);
-								t = (DotProduct(arrays->tvector[o], arrays->coord[o]) + br->faces[j].stdir[1][3]);
-								arrays->texcoord[o][0] = s * scale[0];
-								arrays->texcoord[o][1] = t * scale[1];
+								for (k = 0, o = numverts; k < br->faces[j].numpoints; k++, o++)
+								{
+									VectorCopy(br->faces[j].points[k], arrays->coord[o]);
+									VectorCopy(br->planes[j], arrays->normal[o]);
+									VectorCopy(br->faces[j].stdir[0], arrays->svector[o]);
+									VectorCopy(br->faces[j].stdir[1], arrays->tvector[o]);
 
-								//maths, maths, and more maths.
-								arrays->lmcoord[o][0] = (br->faces[j].lmbase[0]+0.5 + s/br->faces[j].lmscale-br->faces[j].lmbias[0]) * hm->brushlmscale;
-								arrays->lmcoord[o][1] = (br->faces[j].lmbase[1]+0.5 + t/br->faces[j].lmscale-br->faces[j].lmbias[1]) * hm->brushlmscale;
+									//compute the texcoord planes
+									s = (DotProduct(arrays->svector[o], arrays->coord[o]) + br->faces[j].stdir[0][3]);
+									t = (DotProduct(arrays->tvector[o], arrays->coord[o]) + br->faces[j].stdir[1][3]);
+									arrays->texcoord[o][0] = s * scale[0];
+									arrays->texcoord[o][1] = t * scale[1];
+
+									//maths, maths, and more maths.
+									arrays->lmcoord[o][0] = (br->faces[j].lmbase[0]+0.5 + s/br->faces[j].lmscale-br->faces[j].lmbias[0]) * hm->brushlmscale;
+									arrays->lmcoord[o][1] = (br->faces[j].lmbase[1]+0.5 + t/br->faces[j].lmscale-br->faces[j].lmbias[1]) * hm->brushlmscale;
+								}
+								for (k = 2; k < br->faces[j].numpoints; k++)
+								{	//triangle fans
+									arrays->index[numindicies++] = numverts + 0;
+									arrays->index[numindicies++] = numverts + k-1;
+									arrays->index[numindicies++] = numverts + k-0;
+								}
+								numverts += br->faces[j].numpoints;
 							}
-							for (k = 2; k < br->faces[j].numpoints; k++)
-							{	//triangle fans
-								arrays->index[numindicies++] = numverts + 0;
-								arrays->index[numindicies++] = numverts + k-1;
-								arrays->index[numindicies++] = numverts + k-0;
-							}
-							numverts += br->faces[j].numpoints;
 						}
 					}
-				}
 
-				if (numverts || numindicies)
-				{
-					bb = Z_Malloc(sizeof(*bb) + (sizeof(bb->mesh.xyz_array[0])+sizeof(arrays->texcoord[0])+sizeof(arrays->lmcoord[0])+sizeof(arrays->normal[0])+sizeof(arrays->svector[0])+sizeof(arrays->tvector[0])) * numverts);
-					bb->next = bt->batches;
-					bt->batches = bb;
-					bb->lightmap = lmnum;
-					BE_VBO_Begin(&ctx, (sizeof(arrays->coord[0])+sizeof(arrays->texcoord[0])+sizeof(arrays->lmcoord[0])+sizeof(arrays->normal[0])+sizeof(arrays->svector[0])+sizeof(arrays->tvector[0])) * numverts);
-					BE_VBO_Data(&ctx, arrays->coord,	sizeof(arrays->coord	[0])*numverts,		&bb->vbo.coord);
-					BE_VBO_Data(&ctx, arrays->texcoord, sizeof(arrays->texcoord	[0])*numverts,		&bb->vbo.texcoord);
-					BE_VBO_Data(&ctx, arrays->lmcoord,	sizeof(arrays->lmcoord	[0])*numverts,		&bb->vbo.lmcoord[0]);
-					BE_VBO_Data(&ctx, arrays->normal,	sizeof(arrays->normal	[0])*numverts,		&bb->vbo.normals);
-					BE_VBO_Data(&ctx, arrays->svector,	sizeof(arrays->svector	[0])*numverts,		&bb->vbo.svector);
-					BE_VBO_Data(&ctx, arrays->tvector,	sizeof(arrays->tvector	[0])*numverts,		&bb->vbo.tvector);
-					BE_VBO_Finish(&ctx, arrays->index,	sizeof(arrays->index	[0])*numindicies,	&bb->vbo.indicies, &bb->vbo.vbomem, &bb->vbo.ebomem);
+					if (numverts || numindicies)
+					{
+						bb = Z_Malloc(sizeof(*bb) + (sizeof(bb->mesh.xyz_array[0])+sizeof(arrays->texcoord[0])+sizeof(arrays->lmcoord[0])+sizeof(arrays->normal[0])+sizeof(arrays->svector[0])+sizeof(arrays->tvector[0])) * numverts);
+						bb->next = bt->batches;
+						bt->batches = bb;
+						bb->lightmap = lmnum;
+						BE_VBO_Begin(&ctx, (sizeof(arrays->coord[0])+sizeof(arrays->texcoord[0])+sizeof(arrays->lmcoord[0])+sizeof(arrays->normal[0])+sizeof(arrays->svector[0])+sizeof(arrays->tvector[0])) * numverts);
+						BE_VBO_Data(&ctx, arrays->coord,	sizeof(arrays->coord	[0])*numverts,		&bb->vbo.coord);
+						BE_VBO_Data(&ctx, arrays->texcoord, sizeof(arrays->texcoord	[0])*numverts,		&bb->vbo.texcoord);
+						BE_VBO_Data(&ctx, arrays->lmcoord,	sizeof(arrays->lmcoord	[0])*numverts,		&bb->vbo.lmcoord[0]);
+						BE_VBO_Data(&ctx, arrays->normal,	sizeof(arrays->normal	[0])*numverts,		&bb->vbo.normals);
+						BE_VBO_Data(&ctx, arrays->svector,	sizeof(arrays->svector	[0])*numverts,		&bb->vbo.svector);
+						BE_VBO_Data(&ctx, arrays->tvector,	sizeof(arrays->tvector	[0])*numverts,		&bb->vbo.tvector);
+						BE_VBO_Finish(&ctx, arrays->index,	sizeof(arrays->index	[0])*numindicies,	&bb->vbo.indicies, &bb->vbo.vbomem, &bb->vbo.ebomem);
 
-					bb->mesh.xyz_array = (vecV_t*)(bb+1);
-					memcpy(bb->mesh.xyz_array, arrays->coord, sizeof(*bb->mesh.xyz_array) * numverts);
-					bb->mesh.st_array = (vec2_t*)(bb->mesh.xyz_array+numverts);
-					memcpy(bb->mesh.st_array, arrays->texcoord, sizeof(*bb->mesh.st_array) * numverts);
-					bb->mesh.lmst_array[0] = (vec2_t*)(bb->mesh.st_array+numverts);
-					memcpy(bb->mesh.lmst_array[0], arrays->lmcoord, sizeof(*bb->mesh.lmst_array) * numverts);
-					bb->mesh.normals_array = (vec3_t*)(bb->mesh.lmst_array[0]+numverts);
-					memcpy(bb->mesh.normals_array, arrays->normal, sizeof(*bb->mesh.normals_array) * numverts);
-					bb->mesh.snormals_array = (vec3_t*)(bb->mesh.normals_array+numverts);
-					memcpy(bb->mesh.snormals_array, arrays->svector, sizeof(*bb->mesh.snormals_array) * numverts);
-					bb->mesh.tnormals_array = (vec3_t*)(bb->mesh.snormals_array+numverts);
-					memcpy(bb->mesh.tnormals_array, arrays->tvector, sizeof(*bb->mesh.tnormals_array) * numverts);
+						bb->mesh.xyz_array = (vecV_t*)(bb+1);
+						memcpy(bb->mesh.xyz_array, arrays->coord, sizeof(*bb->mesh.xyz_array) * numverts);
+						bb->mesh.st_array = (vec2_t*)(bb->mesh.xyz_array+numverts);
+						memcpy(bb->mesh.st_array, arrays->texcoord, sizeof(*bb->mesh.st_array) * numverts);
+						bb->mesh.lmst_array[0] = (vec2_t*)(bb->mesh.st_array+numverts);
+						memcpy(bb->mesh.lmst_array[0], arrays->lmcoord, sizeof(*bb->mesh.lmst_array) * numverts);
+						bb->mesh.normals_array = (vec3_t*)(bb->mesh.lmst_array[0]+numverts);
+						memcpy(bb->mesh.normals_array, arrays->normal, sizeof(*bb->mesh.normals_array) * numverts);
+						bb->mesh.snormals_array = (vec3_t*)(bb->mesh.normals_array+numverts);
+						memcpy(bb->mesh.snormals_array, arrays->svector, sizeof(*bb->mesh.snormals_array) * numverts);
+						bb->mesh.tnormals_array = (vec3_t*)(bb->mesh.snormals_array+numverts);
+						memcpy(bb->mesh.tnormals_array, arrays->tvector, sizeof(*bb->mesh.tnormals_array) * numverts);
 
-					bb->pmesh = &bb->mesh;
-					bb->mesh.numindexes = numindicies;
-					bb->mesh.numvertexes = numverts;
+						bb->pmesh = &bb->mesh;
+						bb->mesh.numindexes = numindicies;
+						bb->mesh.numvertexes = numverts;
+
+						numverts = 0;
+						numindicies = 0;
+					}
 				}
 			}
 		}
diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c
index eae747d20..ddf12b083 100644
--- a/engine/server/pr_cmds.c
+++ b/engine/server/pr_cmds.c
@@ -10432,7 +10432,7 @@ BuiltinList_t BuiltinList[] = {				//nq	qw		h2		ebfs
 	{"drawrotsubpic",	PF_Fixme,	0,		0,		0,		0,		D("void(vector pivot, vector mins, vector maxs, string pic, vector txmin, vector txsize, vector rgb, vector alphaandangles)", "Overcomplicated draw function for over complicated people. Positions follow drawrotpic, while texture coords follow drawsubpic. Due to argument count limitations in builtins, the alpha value and angles are combined into separate fields of a vector (tip: use fteqcc's [alpha, angle] feature.")},
 
 //330
-	{"getstati",		PF_Fixme,	0,		0,		0,		330,	D("#define getstati_punf(stnum) (float)(__variant)getstati(stnum)\nint(float stnum)", "Retrieves the numerical value of the given EV_INTEGER or EV_ENTITY stat (converted to a float).")},// (EXT_CSQC)
+	{"getstati",		PF_Fixme,	0,		0,		0,		330,	D("#define getstati_punf(stnum) (float)(__variant)getstati(stnum)\nint(float stnum)", "Retrieves the numerical value of the given EV_INTEGER or EV_ENTITY stat. Use getstati_punf if you wish to type-pun a float stat as an int to avoid truncation issues in DP.")},// (EXT_CSQC)
 	{"getstatf",		PF_Fixme,	0,		0,		0,		331,	D("#define getstatbits getstatf\nfloat(float stnum, optional float firstbit, optional float bitcount)", "Retrieves the numerical value of the given EV_FLOAT stat. If firstbit and bitcount are specified, retrieves the upper bits of the STAT_ITEMS stat (converted into a float, so there are no VM dependancies).")},// (EXT_CSQC)
 	{"getstats",		PF_Fixme,	0,		0,		0,		332,	D("string(float stnum)", "Retrieves the value of the given EV_STRING stat, as a tempstring.\nOlder engines may use 4 consecutive integer stats, with a limit of 15 chars (yes, really. 15.), but "FULLENGINENAME" uses a separate namespace for string stats and has a much higher length limit.")},
 	{"getplayerstat",	PF_Fixme,	0,		0,		0,		0,		D("__variant(float playernum, float statnum, float stattype)", "Retrieves a specific player's stat, matching the type specified on the server. This builtin is primarily intended for mvd playback where ALL players are known. For EV_ENTITY, world will be returned if the entity is not in the pvs, use type-punning with EV_INTEGER to get the entity number if you just want to see if its set. STAT_ITEMS should be queried as an EV_INTEGER on account of runes and items2 being packed into the upper bits.")},
diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c
index 92c222a0e..5ed440107 100644
--- a/engine/server/sv_mvd.c
+++ b/engine/server/sv_mvd.c
@@ -940,11 +940,17 @@ void SV_MVD_WriteReliables(qboolean writebroadcasts)
 	if (writebroadcasts)
 	{
 		//chuck in the broadcast reliables
-		ClientReliableCheckBlock(&demo.recorder, sv.reliable_datagram.cursize);
-		ClientReliableWrite_SZ(&demo.recorder, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
+		if (sv.reliable_datagram.cursize)
+		{
+			ClientReliableCheckBlock(&demo.recorder, sv.reliable_datagram.cursize);
+			ClientReliableWrite_SZ(&demo.recorder, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
+		}
 		//and the broadcast unreliables. everything is reliables when it comes to mvds
-		ClientReliableCheckBlock(&demo.recorder, sv.datagram.cursize);
-		ClientReliableWrite_SZ(&demo.recorder, sv.datagram.data, sv.datagram.cursize);
+		if (sv.datagram.cursize)
+		{
+			ClientReliableCheckBlock(&demo.recorder, sv.datagram.cursize);
+			ClientReliableWrite_SZ(&demo.recorder, sv.datagram.data, sv.datagram.cursize);
+		}
 	}
 
 	if (demo.recorder.netchan.message.cursize)
diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c
index 1c3b7aa5f..9c68a5df4 100644
--- a/engine/server/sv_send.c
+++ b/engine/server/sv_send.c
@@ -2769,7 +2769,8 @@ void SV_FlushBroadcasts (void)
 		}
 	}
 
-	SV_MVD_WriteReliables(true);
+	if (sv.mvdrecording)
+		SV_MVD_WriteReliables(true);
 
 	SZ_Clear (&sv.reliable_datagram);
 	SZ_Clear (&sv.datagram);
diff --git a/quakec/csaddon/src/editor_brushes.qc b/quakec/csaddon/src/editor_brushes.qc
index 86fe6f89f..3cea8a138 100644
--- a/quakec/csaddon/src/editor_brushes.qc
+++ b/quakec/csaddon/src/editor_brushes.qc
@@ -64,7 +64,7 @@ void() brush_deselectall =
 {
 	for (int i = 0; i < selectedbrushcount; i++)
 		brush_selected(selectedbrushes[i].model, selectedbrushes[i].id, -1, FALSE);
-
+
 	selectedbrushcount = 0;
 };
 void(int modelidx, int brushid) brush_select =
@@ -204,8 +204,7 @@ int(int mod, int id, brushface_t *faces, int numfaces, int contents) brush_histo
 {
 	int wasselected = brush_isselected(mod, id);
 	if (wasselected)
-		selectedbrushes[wasselected-1].id = -id;	//hack so that brush_history_delete won't remove this entry.
-	
+		selectedbrushes[wasselected-1].id = -id;	//hack so that brush_history_delete won't remove this entry.
 	brush_history_delete(mod, id);
 	id = brush_history_create(mod, faces, numfaces, contents, FALSE);
 	if (wasselected)
@@ -914,7 +913,7 @@ p3p1edge:
 	}
 	else
 	{
-		brush_history_edit(soup->model, soup->brush, faces, numfaces, 1i); 
+		brush_history_edit(soup->model, soup->brush, faces, numfaces, 1i); 
 		
 		soup->numidx = 0;
 		soup->numverts = 0;
@@ -1136,7 +1135,7 @@ static void(vector sizes) drawwireframeview =
 static void() editor_brushes_drawselected =
 {
 	float intensity = (sin(gettime(5)*4)+1)*0.05;
-	int facenum, point, points;
+	int facenum, point, points;
 	vector col;
 	
 	//draw all selected brush faces.
@@ -1183,7 +1182,7 @@ void(vector mousepos) editor_brushes_addentities =
 	int points, point;
 	int facenum;
 	float intensity = (sin(gettime(5)*4)+1)*0.05;
-	vector displace, tmp;
+	vector displace, tmp;
 	vector mid;
 	
 	autocvar_ca_brush_view = fabs(autocvar_ca_brush_view) % 4f;
@@ -1873,7 +1872,7 @@ void(entity e) editor_brush_set_entity
 
 float(float key, float unic, vector mousepos) editor_brushes_key =
 {
-	brushface_t *fa;
+	brushface_t *fa;
 	vector t = mousefar;
 	vector o = mousenear;
 	int i;