#include "quakedef.h"
#include "model_zymotic.h"
//#include "r_textures.h"

zymbonematrix *zymbonepose;
float *aliasvert;
float *aliasvertnorm;
byte *aliasvertcolor;
byte *aliasvertcolor2;
int *aliasvertusage;

extern model_t *loadmodel;
extern char loadname[32];	// for hunk tags

#define MD2MAX_VERTS 2048
#define VectorClear(a) {a[0]=a[1]=a[2]=0;}

void gl_models_start(void)
{
	aliasvert = malloc(sizeof(float[MD2MAX_VERTS][3]));
	aliasvertnorm = malloc(sizeof(float[MD2MAX_VERTS][3]));
	aliasvertcolor = malloc(sizeof(byte[MD2MAX_VERTS][4]));
	aliasvertcolor2 = malloc(sizeof(byte[MD2MAX_VERTS][4])); // used temporarily for tinted coloring
	zymbonepose = malloc(sizeof(zymbonematrix[256]));
	aliasvertusage = malloc(sizeof(int[MD2MAX_VERTS]));
}

void gl_models_shutdown(void)
{
	free(aliasvert);
	free(aliasvertnorm);
	free(aliasvertcolor);
	free(aliasvertcolor2);
	free(zymbonepose);
	free(aliasvertusage);
}

void ZymoticLerpBones(int count, zymbonematrix *bonebase, frameblend_t *blend, zymbone_t *bone, float rootorigin[3], float rootangles[3], float rootscale)
{
	float lerp1, lerp2, lerp3, lerp4;
	zymbonematrix *out, rootmatrix, m, *bone1, *bone2, *bone3, *bone4;
	lerp1 = 1 - lerp2;
	out = zymbonepose;
	AngleVectors(rootangles, rootmatrix.m[0], rootmatrix.m[1], rootmatrix.m[2]);
	VectorScale(rootmatrix.m[0], rootscale, rootmatrix.m[0]);
	VectorScale(rootmatrix.m[1], rootscale, rootmatrix.m[1]);
	VectorScale(rootmatrix.m[2], rootscale, rootmatrix.m[2]);
	rootmatrix.m[0][3] = rootorigin[0];
	rootmatrix.m[1][3] = rootorigin[1];
	rootmatrix.m[2][3] = rootorigin[2];
	bone1 = bonebase + blend[0].frame * count;
	lerp1 = blend[0].lerp;
	if (blend[1].lerp)
	{
		bone2 = bonebase + blend[1].frame * count;
		lerp2 = blend[1].lerp;
		if (blend[2].lerp)
		{
			bone3 = bonebase + blend[2].frame * count;
			lerp3 = blend[2].lerp;
			if (blend[3].lerp)
			{
				// 4 poses
				bone4 = bonebase + blend[3].frame * count;
				lerp4 = blend[3].lerp;
				while(count--)
				{
					// interpolate matrices
					m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2 + bone3->m[0][0] * lerp3 + bone4->m[0][0] * lerp4;
					m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2 + bone3->m[0][1] * lerp3 + bone4->m[0][1] * lerp4;
					m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2 + bone3->m[0][2] * lerp3 + bone4->m[0][2] * lerp4;
					m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2 + bone3->m[0][3] * lerp3 + bone4->m[0][3] * lerp4;
					m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2 + bone3->m[1][0] * lerp3 + bone4->m[1][0] * lerp4;
					m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2 + bone3->m[1][1] * lerp3 + bone4->m[1][1] * lerp4;
					m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2 + bone3->m[1][2] * lerp3 + bone4->m[1][2] * lerp4;
					m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2 + bone3->m[1][3] * lerp3 + bone4->m[1][3] * lerp4;
					m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2 + bone3->m[2][0] * lerp3 + bone4->m[2][0] * lerp4;
					m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2 + bone3->m[2][1] * lerp3 + bone4->m[2][1] * lerp4;
					m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2 + bone3->m[2][2] * lerp3 + bone4->m[2][2] * lerp4;
					m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2 + bone3->m[2][3] * lerp3 + bone4->m[2][3] * lerp4;
					if (bone->parent >= 0)
						R_ConcatTransforms(&zymbonepose[bone->parent].m[0], &m.m[0], &out->m[0]);
					else
						R_ConcatTransforms(&rootmatrix.m[0], &m.m[0], &out->m[0]);
					bone1++;
					bone2++;
					bone3++;
					bone4++;
					bone++;
					out++;
				}
			}
			else
			{
				// 3 poses
				while(count--)
				{
					// interpolate matrices
					m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2 + bone3->m[0][0] * lerp3;
					m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2 + bone3->m[0][1] * lerp3;
					m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2 + bone3->m[0][2] * lerp3;
					m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2 + bone3->m[0][3] * lerp3;
					m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2 + bone3->m[1][0] * lerp3;
					m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2 + bone3->m[1][1] * lerp3;
					m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2 + bone3->m[1][2] * lerp3;
					m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2 + bone3->m[1][3] * lerp3;
					m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2 + bone3->m[2][0] * lerp3;
					m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2 + bone3->m[2][1] * lerp3;
					m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2 + bone3->m[2][2] * lerp3;
					m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2 + bone3->m[2][3] * lerp3;
					if (bone->parent >= 0)
						R_ConcatTransforms(&zymbonepose[bone->parent].m[0], &m.m[0], &out->m[0]);
					else
						R_ConcatTransforms(&rootmatrix.m[0], &m.m[0], &out->m[0]);
					bone1++;
					bone2++;
					bone3++;
					bone++;
					out++;
				}
			}
		}
		else
		{
			// 2 poses
			while(count--)
			{
				// interpolate matrices
				m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2;
				m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2;
				m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2;
				m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2;
				m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2;
				m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2;
				m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2;
				m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2;
				m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2;
				m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2;
				m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2;
				m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2;
				if (bone->parent >= 0)
					R_ConcatTransforms(&zymbonepose[bone->parent].m[0], &m.m[0], &out->m[0]);
				else
					R_ConcatTransforms(&rootmatrix.m[0], &m.m[0], &out->m[0]);
				bone1++;
				bone2++;
				bone++;
				out++;
			}
		}
	}
	else
	{
		// 1 pose
		if (lerp1 != 1)
		{
			// lerp != 1.0
			while(count--)
			{
				// interpolate matrices
				m.m[0][0] = bone1->m[0][0] * lerp1;
				m.m[0][1] = bone1->m[0][1] * lerp1;
				m.m[0][2] = bone1->m[0][2] * lerp1;
				m.m[0][3] = bone1->m[0][3] * lerp1;
				m.m[1][0] = bone1->m[1][0] * lerp1;
				m.m[1][1] = bone1->m[1][1] * lerp1;
				m.m[1][2] = bone1->m[1][2] * lerp1;
				m.m[1][3] = bone1->m[1][3] * lerp1;
				m.m[2][0] = bone1->m[2][0] * lerp1;
				m.m[2][1] = bone1->m[2][1] * lerp1;
				m.m[2][2] = bone1->m[2][2] * lerp1;
				m.m[2][3] = bone1->m[2][3] * lerp1;
				if (bone->parent >= 0)
					R_ConcatTransforms(&zymbonepose[bone->parent].m[0], &m.m[0], &out->m[0]);
				else
					R_ConcatTransforms(&rootmatrix.m[0], &m.m[0], &out->m[0]);
				bone1++;
				bone++;
				out++;
			}
		}
		else
		{
			// lerp == 1.0
			while(count--)
			{
				if (bone->parent >= 0)
					R_ConcatTransforms(&zymbonepose[bone->parent].m[0], &bone1->m[0], &out->m[0]);
				else
					R_ConcatTransforms(&rootmatrix.m[0], &bone1->m[0], &out->m[0]);
				bone1++;
				bone++;
				out++;
			}
		}
	}
}

void ZymoticTransformVerts(int vertcount, int *bonecounts, zymvertex_t *vert)
{
	int c;
	float *out = aliasvert;
	zymbonematrix *matrix;
	while(vertcount--)
	{
		c = *bonecounts++;
		// FIXME: validate bonecounts at load time (must be >= 1)
		if (c == 1)
		{
			matrix = &zymbonepose[vert->bonenum];
			out[0] = vert->origin[0] * matrix->m[0][0] + vert->origin[1] * matrix->m[0][1] + vert->origin[2] * matrix->m[0][2] + matrix->m[0][3];
			out[1] = vert->origin[0] * matrix->m[1][0] + vert->origin[1] * matrix->m[1][1] + vert->origin[2] * matrix->m[1][2] + matrix->m[1][3];
			out[2] = vert->origin[0] * matrix->m[2][0] + vert->origin[1] * matrix->m[2][1] + vert->origin[2] * matrix->m[2][2] + matrix->m[2][3];
			vert++;
		}
		else
		{
			VectorClear(out);
			while(c--)
			{
				matrix = &zymbonepose[vert->bonenum];
				out[0] += vert->origin[0] * matrix->m[0][0] + vert->origin[1] * matrix->m[0][1] + vert->origin[2] * matrix->m[0][2] + matrix->m[0][3];
				out[1] += vert->origin[0] * matrix->m[1][0] + vert->origin[1] * matrix->m[1][1] + vert->origin[2] * matrix->m[1][2] + matrix->m[1][3];
				out[2] += vert->origin[0] * matrix->m[2][0] + vert->origin[1] * matrix->m[2][1] + vert->origin[2] * matrix->m[2][2] + matrix->m[2][3];
				vert++;
			}
		}
		out += 3;
	}
}

float ixtable[4096];

void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist)
{
	int a, b, c, d;
	float *out, v1[3], v2[3], normal[3];
	int *u;
	if (!ixtable[1])
	{
		ixtable[0] = 0;
		for (a = 1;a < 4096;a++)
			ixtable[a] = 1.0f / a;
	}
	// clear normals
	memset(aliasvertnorm, 0, sizeof(float[3]) * vertcount);
	memset(aliasvertusage, 0, sizeof(int) * vertcount);
	// parse render list and accumulate surface normals
	while(shadercount--)
	{
		d = *renderlist++;
		while (d--)
		{
			a = renderlist[0]*3;
			b = renderlist[1]*3;
			c = renderlist[2]*3;
			v1[0] = aliasvert[a+0] - aliasvert[b+0];
			v1[1] = aliasvert[a+1] - aliasvert[b+1];
			v1[2] = aliasvert[a+2] - aliasvert[b+2];
			v2[0] = aliasvert[c+0] - aliasvert[b+0];
			v2[1] = aliasvert[c+1] - aliasvert[b+1];
			v2[2] = aliasvert[c+2] - aliasvert[b+2];
			CrossProduct(v1, v2, normal);
			VectorNormalize(normal);
			// add surface normal to vertices
			aliasvertnorm[a+0] += normal[0];
			aliasvertnorm[a+1] += normal[1];
			aliasvertnorm[a+2] += normal[2];
			aliasvertusage[a]++;
			aliasvertnorm[b+0] += normal[0];
			aliasvertnorm[b+1] += normal[1];
			aliasvertnorm[b+2] += normal[2];
			aliasvertusage[b]++;
			aliasvertnorm[c+0] += normal[0];
			aliasvertnorm[c+1] += normal[1];
			aliasvertnorm[c+2] += normal[2];
			aliasvertusage[c]++;
			renderlist += 3;
		}
	}
	// average surface normals
	out = aliasvertnorm;
	u = aliasvertusage;
	while(vertcount--)
	{
		if (*u > 1)
		{
			a = ixtable[*u];
			out[0] *= a;
			out[1] *= a;
			out[2] *= a;
		}
		u++;
		out += 3;
	}
}

void GL_DrawZymoticModelMesh(byte *colors, zymtype1header_t *m)
{
	int i, c, *renderlist;
	rtexture_t **texture;

	renderlist = (int *)(m->lump_render.start + (int) m);
	texture = (rtexture_t **)(m->lump_shaders.start + (int) m);
	glVertexPointer(3, GL_FLOAT, 0, aliasvert);
	glEnableClientState(GL_VERTEX_ARRAY);

	glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
	glEnableClientState(GL_COLOR_ARRAY);

	glTexCoordPointer(2, GL_FLOAT, 0, (float *)(m->lump_texcoords.start + (int) m));
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	for (i = 0;i < m->numshaders;i++)
	{
		c = (*renderlist++) * 3;
//		glBindTexture(GL_TEXTURE_2D, R_GetTexture(*texture));
		texture++;
		glDrawElements(GL_TRIANGLES, c, GL_UNSIGNED_INT, renderlist);
		renderlist += c;
	}

	glDisableClientState(GL_TEXTURE_COORD_ARRAY);

	glDisableClientState(GL_COLOR_ARRAY);

	glDisableClientState(GL_VERTEX_ARRAY);
}

/*
=================
R_DrawZymoticFrame
=================
*/
void R_DrawZymoticFrame (zymtype1header_t *m, float alpha, vec3_t color, entity_t *ent, int shadow, vec3_t org, vec3_t angles, vec_t scale, frameblend_t *blend, int skinblah, int effects, int flags)
{
	ZymoticLerpBones(m->numbones, (zymbonematrix *)(m->lump_poses.start + (int) m), blend, (zymbone_t *)(m->lump_bones.start + (int) m), org, angles, scale);
	ZymoticTransformVerts(m->numverts, (int *)(m->lump_vertbonecounts.start + (int) m), (zymvertex_t *)(m->lump_verts.start + (int) m));
	ZymoticCalcNormals(m->numverts, m->numshaders, (int *)(m->lump_render.start + (int) m));

//	R_LightModel(ent, m->numverts, org, color);


	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glShadeModel(GL_SMOOTH);
/*	if (effects & EF_ADDITIVE)
	{
		glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive rendering
		glEnable(GL_BLEND);
		glDepthMask(0);
	}
	else if (alpha != 1.0)
	{
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
		glDepthMask(0);
	}
	else
	{
*/		glDisable(GL_BLEND);
		glDepthMask(1);
//	}

	GL_DrawZymoticModelMesh(aliasvertcolor, m);

//	if (fogenabled)
//		GL_DrawZymoticModelMeshFog(org, m);

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable (GL_BLEND);
	glDepthMask(1);
}

void swapintblock(int *m, int size)
{
	size /= 4;
	while(size--)
		*m++ = BigLong(*m);
}

void Mod_LoadZymoticModel (model_t *mod, void *buffer)
{
	int i, pbase, start, end, total, *skinrange;
	rtexture_t **texture, **skin;
	char *shadername;
	zymtype1header_t *pinmodel, *pheader;
	zymscene_t *scene;
	zymbone_t *bone;
	animscene_t *animscenes;

	start = Hunk_LowMark ();

	pinmodel = (void *)buffer;

	if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
		Host_Error ("Mod_LoadZymoticModel: %s is not a zymotic model\n");

	if (BigLong(pinmodel->type) != 1)
		Host_Error ("Mod_LoadZymoticModel: only type 1 (skeletal pose) models are currently supported\n");

	mod->type = mod_alias;
	mod->aliastype = ALIASTYPE_ZYM;

	pheader = Hunk_AllocName (BigLong(pinmodel->filesize), va("%s Zymotic model", loadname));

	pbase = (int) pheader;

	memcpy(pheader, pinmodel, BigLong(pinmodel->filesize));

	// byteswap header
	memcpy(pheader->id, pinmodel->id, 12);
	pheader->type = BigLong(pheader->type);
	pheader->filesize = BigLong(pheader->filesize);
	pheader->mins[0] = BigFloat(pheader->mins[0]);
	pheader->mins[1] = BigFloat(pheader->mins[1]);
	pheader->mins[2] = BigFloat(pheader->mins[2]);
	pheader->maxs[0] = BigFloat(pheader->maxs[0]);
	pheader->maxs[1] = BigFloat(pheader->maxs[1]);
	pheader->maxs[2] = BigFloat(pheader->maxs[2]);
	pheader->radius = BigFloat(pheader->radius);
	pheader->numverts = BigLong(pheader->numverts);
	pheader->numtris = BigLong(pheader->numtris);
	pheader->numshaders = BigLong(pheader->numshaders);
	pheader->numbones = BigLong(pheader->numbones);
	pheader->numscenes = BigLong(pheader->numscenes);


	pheader->lump_scenes.start = BigLong(pheader->lump_scenes.start);pheader->lump_scenes.length = BigLong(pheader->lump_scenes.length);
	pheader->lump_poses.start = BigLong(pheader->lump_poses.start);pheader->lump_poses.length = BigLong(pheader->lump_poses.length);
	pheader->lump_bones.start = BigLong(pheader->lump_bones.start);pheader->lump_bones.length = BigLong(pheader->lump_bones.length);
	pheader->lump_vertbonecounts.start = BigLong(pheader->lump_vertbonecounts.start);pheader->lump_vertbonecounts.length = BigLong(pheader->lump_vertbonecounts.length);
	pheader->lump_verts.start = BigLong(pheader->lump_verts.start);pheader->lump_verts.length = BigLong(pheader->lump_verts.length);
	pheader->lump_texcoords.start = BigLong(pheader->lump_texcoords.start);pheader->lump_texcoords.length = BigLong(pheader->lump_texcoords.length);
	pheader->lump_render.start = BigLong(pheader->lump_render.start);pheader->lump_render.length = BigLong(pheader->lump_render.length);
	pheader->lump_shaders.start = BigLong(pheader->lump_shaders.start);pheader->lump_shaders.length = BigLong(pheader->lump_shaders.length);
	pheader->lump_trizone.start = BigLong(pheader->lump_trizone.start);pheader->lump_trizone.length = BigLong(pheader->lump_trizone.length);

	mod->flags = 0; // there are no flags
	mod->numframes = pheader->numscenes;
	mod->synctype = ST_SYNC;
	mod->numtris = pheader->numtris;

	// FIXME: add skin support and texturing and shaders and...
// load the skins
	skinrange = loadmodel->skinanimrange;
	skin = loadmodel->skinanim;
//	skinrange = Hunk_AllocName (sizeof(int) * (pheader->num_skins * 2), loadname);	
//	skin = skinrange + pheader->num_skins * 2;
//	loadmodel->skinanimrange = (int) skinrange - (int) pheader;
//	loadmodel->skinanim = (int) skin - (int) pheader;
	*skinrange++ = 0;
	*skinrange++ = 1;
	*skin++ = NULL;
	*skin++ = NULL;
	*skin++ = NULL;
	*skin++ = NULL;
	*skin++ = NULL;
	loadmodel->numskins = 1;

	// go through the lumps, swapping things

//	zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
	scene = (void *) (pheader->lump_scenes.start + pbase);
	animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
	for (i = 0;i < pheader->numscenes;i++)
	{
		scene->mins[0] = BigFloat(scene->mins[0]);
		scene->mins[1] = BigFloat(scene->mins[1]);
		scene->mins[2] = BigFloat(scene->mins[2]);
		scene->maxs[0] = BigFloat(scene->maxs[0]);
		scene->maxs[1] = BigFloat(scene->maxs[1]);
		scene->maxs[2] = BigFloat(scene->maxs[2]);
		scene->radius = BigFloat(scene->radius);
		scene->framerate = BigFloat(scene->framerate);
		scene->flags = BigLong(scene->flags);
		scene->start = BigLong(scene->start);
		scene->length = BigLong(scene->length);

		memcpy(animscenes[i].name, scene->name, 32);
		animscenes[i].firstframe = scene->start;
		animscenes[i].framecount = scene->length;
		animscenes[i].framerate = scene->framerate;
		animscenes[i].loop = (scene->flags & ZYMSCENEFLAG_NOLOOP) == 0;

		scene++;
	}
	mod->ofs_scenes = (int) animscenes - pbase;

//	zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
	swapintblock((void *) (pheader->lump_poses.start + pbase), pheader->lump_poses.length);

//	zymlump_t lump_bones; // zymbone_t bone[numbones];
	bone = (void *) (pheader->lump_bones.start + pbase);
	for (i = 0;i < pheader->numbones;i++)
	{
		bone->flags = BigLong(bone->flags);
		bone->parent = BigLong(bone->parent);
		bone++;
	}

//	zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
	swapintblock((void *) (pheader->lump_vertbonecounts.start + pbase), pheader->lump_vertbonecounts.length);

//	zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
	swapintblock((void *) (pheader->lump_verts.start + pbase), pheader->lump_verts.length);

//	zymlump_t lump_texcoords; // float texcoords[numvertices][2];
	swapintblock((void *) (pheader->lump_texcoords.start + pbase), pheader->lump_texcoords.length);

//	zymlump_t lump_render; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices)
	swapintblock((void *) (pheader->lump_render.start + pbase), pheader->lump_render.length);

//	zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
	shadername = (void *) (pheader->lump_shaders.start + pbase);
	texture = (void *) shadername;
	for (i = 0;i < pheader->numshaders;i++)
	{
		rtexture_t *rt;
		rt = loadtextureimage(shadername, 0, 0, true, 1, true);
		shadername += 32;
		*texture++ = rt; // reuse shader name list for texture pointers
	}

//	zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
	swapintblock((void *) (pheader->lump_trizone.start + pbase), pheader->lump_trizone.length);

	// model bbox
	for (i = 0;i < 3;i++)
	{
		mod->mins[i] = pheader->mins[i];
		mod->maxs[i] = pheader->maxs[i];
	}

// move the complete, relocatable alias model to the cache
	end = Hunk_LowMark ();
	mod->cachesize = total = end - start;
	
	Cache_Alloc (&mod->cache, total, loadname);
	if (!mod->cache.data)
		return;
	memcpy (mod->cache.data, pheader, total);

	Hunk_FreeToLowMark (start);
}
