summary refs log tree commit diff
path: root/src/Model.c
diff options
context:
space:
mode:
authorWlodekM <[email protected]>2024-06-16 10:35:45 +0300
committerWlodekM <[email protected]>2024-06-16 10:35:45 +0300
commitabef6da56913f1c55528103e60a50451a39628b1 (patch)
treeb3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/Model.c
initial commit
Diffstat (limited to 'src/Model.c')
-rw-r--r--src/Model.c2439
1 files changed, 2439 insertions, 0 deletions
diff --git a/src/Model.c b/src/Model.c
new file mode 100644
index 0000000..ea02890
--- /dev/null
+++ b/src/Model.c
@@ -0,0 +1,2439 @@
+#include "Model.h"
+#include "ExtMath.h"
+#include "Funcs.h"
+#include "Game.h"
+#include "Graphics.h"
+#include "Entity.h"
+#include "Camera.h"
+#include "Event.h"
+#include "ExtMath.h"
+#include "TexturePack.h"
+#include "Drawer.h"
+#include "Block.h"
+#include "Stream.h"
+#include "Options.h"
+
+struct _ModelsData Models;
+/* NOTE: None of the built in models use more than 12 parts at once, but custom models can use up to 64 parts. */
+#define MODELS_MAX_VERTICES (MODEL_BOX_VERTICES * MAX_CUSTOM_MODEL_PARTS)
+
+#define UV_POS_MASK ((cc_uint16)0x7FFF)
+#define UV_MAX ((cc_uint16)0x8000)
+#define UV_MAX_SHIFT 15
+#define AABB_Width(bb)  ((bb)->Max.x - (bb)->Min.x)
+#define AABB_Height(bb) ((bb)->Max.y - (bb)->Min.y)
+#define AABB_Length(bb) ((bb)->Max.z - (bb)->Min.z)
+
+
+/*########################################################################################################################*
+*------------------------------------------------------------Model--------------------------------------------------------*
+*#########################################################################################################################*/
+static void Model_GetTransform(struct Entity* e, Vec3 pos, struct Matrix* m) {
+	Entity_GetTransform(e, pos, e->ModelScale, m);
+}
+static void Model_NullFunc(struct Entity* e) { }
+static void Model_NoParts(void) { }
+
+void Model_Init(struct Model* model) {
+	model->bobbing  = true;
+	model->usesSkin = true;
+	model->calcHumanAnims = false;
+	model->usesHumanSkin  = false;
+	model->pushes = true;
+
+	model->gravity     = 0.08f;
+	Vec3_Set(model->drag,           0.91f, 0.98f, 0.91f);
+	Vec3_Set(model->groundFriction, 0.6f,   1.0f,  0.6f);
+
+	model->maxScale    = 2.0f;
+	model->shadowScale = 1.0f;
+	model->armX = 6; model->armY = 12;
+
+	model->GetTransform = Model_GetTransform;
+	model->DrawArm      = Model_NullFunc;
+}
+
+cc_bool Model_ShouldRender(struct Entity* e) {
+	Vec3 pos = e->Position;
+	struct AABB bb;
+	float bbWidth, bbHeight, bbLength;
+	float maxYZ, maxXYZ;
+
+	Entity_GetPickingBounds(e, &bb);
+	bbWidth  = AABB_Width(&bb);
+	bbHeight = AABB_Height(&bb);
+	bbLength = AABB_Length(&bb);
+
+	maxYZ  = max(bbHeight, bbLength);
+	maxXYZ = max(bbWidth,  maxYZ);
+	pos.y += bbHeight * 0.5f; /* Centre Y coordinate. */
+	return FrustumCulling_SphereInFrustum(pos.x, pos.y, pos.z, maxXYZ);
+}
+
+static float Model_MinDist(float dist, float extent) {
+	/* Compare min coord, centre coord, and max coord */
+	float dMin = Math_AbsF(dist - extent), dMax = Math_AbsF(dist + extent);
+	float dMinMax = min(dMin, dMax);
+	return min(Math_AbsF(dist), dMinMax);
+}
+
+float Model_RenderDistance(struct Entity* e) {
+	Vec3 pos     = e->Position;
+	struct AABB* bb = &e->ModelAABB;
+	Vec3 camPos  = Camera.CurrentPos;
+	float dx, dy, dz;
+
+	/* X and Z are already at centre of model */
+	/* Y is at feet, so needs to be moved up to centre */
+	pos.y += AABB_Height(bb) * 0.5f;
+
+	dx = Model_MinDist(camPos.x - pos.x, AABB_Width(bb)  * 0.5f);
+	dy = Model_MinDist(camPos.y - pos.y, AABB_Height(bb) * 0.5f);
+	dz = Model_MinDist(camPos.z - pos.z, AABB_Length(bb) * 0.5f);
+	return dx * dx + dy * dy + dz * dz;
+}
+
+void Model_Render(struct Model* model, struct Entity* e) {
+	struct Matrix m;
+	Vec3 pos = e->Position;
+	if (model->bobbing) pos.y += e->Anim.BobbingModel;
+	/* Original classic offsets models slightly into ground */
+	if (Game_ClassicMode && (e->Flags & ENTITY_FLAG_CLASSIC_ADJUST))
+		pos.y -= 1.5f / 16.0f;
+
+	Model_SetupState(model, e);
+	Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
+
+	model->GetTransform(e, pos, &e->Transform);
+	Matrix_Mul(&m, &e->Transform, &Gfx.View);
+
+	Gfx_LoadMatrix(MATRIX_VIEW, &m);
+	model->Draw(e);
+	Gfx_LoadMatrix(MATRIX_VIEW, &Gfx.View);
+}
+
+void Model_SetupState(struct Model* model, struct Entity* e) {
+	PackedCol col;
+	float yawDelta;
+
+	model->index = 0;
+	col = e->VTABLE->GetCol(e);
+	Models.Cols[0] = col;
+
+	/* If a model forgets to call Model_ApplyTexture but still tries to draw, */
+	/* then it is not using the model API properly. */
+	/* So set uScale/vScale to ridiculous defaults to make it obvious */
+	/* TODO: Remove setting this eventually */
+	Models.uScale = 100.0f;
+	Models.vScale = 100.0f;
+
+	if (!e->NoShade) {
+		Models.Cols[1] = PackedCol_Scale(col, PACKEDCOL_SHADE_YMIN);
+		Models.Cols[2] = PackedCol_Scale(col, PACKEDCOL_SHADE_Z);
+		Models.Cols[4] = PackedCol_Scale(col, PACKEDCOL_SHADE_X);
+	} else {
+		Models.Cols[1] = col; Models.Cols[2] = col; Models.Cols[4] = col;
+	}
+
+	Models.Cols[3] = Models.Cols[2]; 
+	Models.Cols[5] = Models.Cols[4];
+	yawDelta = e->Yaw - e->RotY;
+
+	Models.cosHead = Math_CosF(yawDelta * MATH_DEG2RAD);
+	Models.sinHead = Math_SinF(yawDelta * MATH_DEG2RAD);
+	Models.Active  = model;
+}
+
+void Model_ApplyTexture(struct Entity* e) {
+	struct Model* model = Models.Active;
+	struct ModelTex* data;
+	GfxResourceID tex;
+	cc_bool _64x64;
+
+	tex = model->usesHumanSkin ? e->TextureId : e->MobTextureId;
+	if (tex) {
+		Models.skinType = e->SkinType;
+	} else {
+		data = model->defaultTex;
+		tex  = data->texID;
+		Models.skinType = data->skinType;
+	}
+
+	Gfx_BindTexture(tex);
+	_64x64 = Models.skinType != SKIN_64x32;
+
+	Models.uScale = e->uScale * 0.015625f;
+	Models.vScale = e->vScale * (_64x64 ? 0.015625f : 0.03125f);
+}
+
+
+void Model_UpdateVB(void) {
+	struct Model* model = Models.Active;
+	if (!Models.Vb)
+		Models.Vb = Gfx_CreateDynamicVb(VERTEX_FORMAT_TEXTURED, Models.MaxVertices);
+	
+	Gfx_SetDynamicVbData(Models.Vb, Models.Vertices, model->index);
+	Gfx_DrawVb_IndexedTris(model->index);
+	model->index = 0;
+}
+
+/* Need to restore vertices array to keep third party plugins such as MoreModels working */
+static struct VertexTextured* real_vertices;
+static GfxResourceID modelVB;
+
+void Model_LockVB(struct Entity* entity, int verticesCount) {
+#ifdef CC_BUILD_CONSOLE
+	if (!entity->ModelVB) {
+		entity->ModelVB = Gfx_CreateDynamicVb(VERTEX_FORMAT_TEXTURED, Models.Active->maxVertices);
+	}
+	modelVB = entity->ModelVB;
+#else
+	if (!Models.Vb) {
+		Models.Vb = Gfx_CreateDynamicVb(VERTEX_FORMAT_TEXTURED, Models.MaxVertices);
+	}
+	modelVB = Models.Vb;
+#endif
+
+	real_vertices   = Models.Vertices;
+	Models.Vertices = Gfx_LockDynamicVb(modelVB, VERTEX_FORMAT_TEXTURED, verticesCount);
+}
+
+void Model_UnlockVB(void) {
+	Gfx_UnlockDynamicVb(modelVB);
+	Models.Vertices = real_vertices;
+}
+
+
+void Model_DrawPart(struct ModelPart* part) {
+	struct Model* model        = Models.Active;
+	struct ModelVertex* src    = &model->vertices[part->offset];
+	struct VertexTextured* dst = &Models.Vertices[model->index];
+
+	struct ModelVertex v;
+	int i, count = part->count;
+
+	for (i = 0; i < count; i++) {
+		v = *src;
+		dst->x = v.x; dst->y = v.y; dst->z = v.z;
+		dst->Col = Models.Cols[i >> 2];
+
+		dst->U = (v.u & UV_POS_MASK) * Models.uScale - (v.u >> UV_MAX_SHIFT) * 0.01f * Models.uScale;
+		dst->V = (v.v & UV_POS_MASK) * Models.vScale - (v.v >> UV_MAX_SHIFT) * 0.01f * Models.vScale;
+		src++; dst++;
+	}
+	model->index += count;
+}
+
+#define Model_RotateX t = cosX * v.y + sinX * v.z; v.z = -sinX * v.y + cosX * v.z; v.y = t;
+#define Model_RotateY t = cosY * v.x - sinY * v.z; v.z =  sinY * v.x + cosY * v.z; v.x = t;
+#define Model_RotateZ t = cosZ * v.x + sinZ * v.y; v.y = -sinZ * v.x + cosZ * v.y; v.x = t;
+
+void Model_DrawRotate(float angleX, float angleY, float angleZ, struct ModelPart* part, cc_bool head) {
+	struct Model* model        = Models.Active;
+	struct ModelVertex* src    = &model->vertices[part->offset];
+	struct VertexTextured* dst = &Models.Vertices[model->index];
+
+	float cosX = Math_CosF(-angleX), sinX = Math_SinF(-angleX);
+	float cosY = Math_CosF(-angleY), sinY = Math_SinF(-angleY);
+	float cosZ = Math_CosF(-angleZ), sinZ = Math_SinF(-angleZ);
+	float t, x = part->rotX, y = part->rotY, z = part->rotZ;
+	
+	struct ModelVertex v;
+	int i, count = part->count;
+
+	for (i = 0; i < count; i++) {
+		v = *src;
+		v.x -= x; v.y -= y; v.z -= z;
+
+		/* Rotate locally */
+		if (Models.Rotation == ROTATE_ORDER_ZYX) {
+			Model_RotateZ
+			Model_RotateY
+			Model_RotateX
+		} else if (Models.Rotation == ROTATE_ORDER_XZY) {
+			Model_RotateX
+			Model_RotateZ
+			Model_RotateY
+		} else if (Models.Rotation == ROTATE_ORDER_YZX) {
+			Model_RotateY
+			Model_RotateZ
+			Model_RotateX
+		} else if (Models.Rotation == ROTATE_ORDER_XYZ) {
+			Model_RotateX
+			Model_RotateY
+			Model_RotateZ
+		}
+
+		/* Rotate globally (inlined RotY) */
+		if (head) {
+			t = Models.cosHead * v.x - Models.sinHead * v.z; v.z = Models.sinHead * v.x + Models.cosHead * v.z; v.x = t;
+		}
+		dst->x = v.x + x; dst->y = v.y + y; dst->z = v.z + z;
+		dst->Col = Models.Cols[i >> 2];
+
+		dst->U = (v.u & UV_POS_MASK) * Models.uScale - (v.u >> UV_MAX_SHIFT) * 0.01f * Models.uScale;
+		dst->V = (v.v & UV_POS_MASK) * Models.vScale - (v.v >> UV_MAX_SHIFT) * 0.01f * Models.vScale;
+		src++; dst++;
+	}
+	model->index += count;
+}
+
+void Model_RenderArm(struct Model* model, struct Entity* e) {
+	struct Matrix m, translate;
+	Vec3 pos = e->Position;
+	if (model->bobbing) pos.y += e->Anim.BobbingModel;
+
+	Model_SetupState(model, e);
+	Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
+	Model_ApplyTexture(e);
+
+	if (Models.ClassicArms) {
+		/* TODO: Position's not quite right. */
+		/* Matrix_Translate(out m, -armX / 16f + 0.2f, -armY / 16f - 0.20f, 0); */
+		/* is better, but that breaks the dig animation */
+		Matrix_Translate(&translate, -model->armX / 16.0f,         -model->armY / 16.0f - 0.10f, 0);
+	} else {
+		Matrix_Translate(&translate, -model->armX / 16.0f + 0.10f, -model->armY / 16.0f - 0.26f, 0);
+	}
+
+	Entity_GetTransform(e, pos, e->ModelScale, &m);
+	Matrix_Mul(&m, &m,         &Gfx.View);
+	Matrix_Mul(&m, &translate, &m);
+
+	Gfx_LoadMatrix(MATRIX_VIEW, &m);
+	Models.Rotation = ROTATE_ORDER_YZX;
+	model->DrawArm(e);
+	Models.Rotation = ROTATE_ORDER_ZYX;
+	Gfx_LoadMatrix(MATRIX_VIEW, &Gfx.View);
+}
+
+void Model_DrawArmPart(struct ModelPart* part) {
+	struct Model* model  = Models.Active;
+	struct ModelPart arm = *part;
+	arm.rotX = model->armX / 16.0f; 
+	arm.rotY = (model->armY + model->armY / 2) / 16.0f;
+
+	if (Models.ClassicArms) {
+		Model_DrawRotate(0, -90 * MATH_DEG2RAD, 120 * MATH_DEG2RAD, &arm, false);
+	} else {
+		Model_DrawRotate(-20 * MATH_DEG2RAD, -70 * MATH_DEG2RAD, 135 * MATH_DEG2RAD, &arm, false);
+	}
+}
+
+
+/*########################################################################################################################*
+*----------------------------------------------------------BoxDesc--------------------------------------------------------*
+*#########################################################################################################################*/
+void BoxDesc_BuildBox(struct ModelPart* part, const struct BoxDesc* desc) {
+	int sidesW = desc->sizeZ, bodyW = desc->sizeX, bodyH = desc->sizeY;
+	float x1 = desc->x1, y1 = desc->y1, z1 = desc->z1;
+	float x2 = desc->x2, y2 = desc->y2, z2 = desc->z2;
+	int x = desc->texX, y = desc->texY;
+	struct Model* m = Models.Active;
+
+	BoxDesc_YQuad2(m, x1, x2, z2, z1, y2, /* top */
+		x + sidesW + bodyW,                  y, 
+		x + sidesW,                          y + sidesW);
+	BoxDesc_YQuad2(m, x2, x1, z2, z1, y1, /* bottom */
+		x + sidesW + bodyW,                  y,
+		x + sidesW + bodyW + bodyW,          y + sidesW);
+	BoxDesc_ZQuad2(m, x1, x2, y1, y2, z1, /* front */
+		x + sidesW + bodyW,                  y + sidesW, 
+		x + sidesW,                          y + sidesW + bodyH); 
+	BoxDesc_ZQuad2(m, x2, x1, y1, y2, z2, /* back */
+		x + sidesW + bodyW + sidesW + bodyW, y + sidesW, 
+		x + sidesW + bodyW + sidesW,         y + sidesW + bodyH);
+	BoxDesc_XQuad2(m, z1, z2, y1, y2, x2,  /* left */
+		x + sidesW,                          y + sidesW, 
+		x,                                   y + sidesW + bodyH);
+	BoxDesc_XQuad2(m, z2, z1, y1, y2, x1, /* right */
+		x + sidesW + bodyW + sidesW,         y + sidesW, 
+		x + sidesW + bodyW,                  y + sidesW + bodyH); 
+
+	ModelPart_Init(part, m->index - MODEL_BOX_VERTICES, MODEL_BOX_VERTICES,
+		desc->rotX, desc->rotY, desc->rotZ);
+}
+
+void BoxDesc_BuildRotatedBox(struct ModelPart* part, const struct BoxDesc* desc) {
+	int sidesW = desc->sizeY, bodyW = desc->sizeX, bodyH = desc->sizeZ;
+	float x1 = desc->x1, y1 = desc->y1, z1 = desc->z1;
+	float x2 = desc->x2, y2 = desc->y2, z2 = desc->z2;
+	int x = desc->texX, y = desc->texY, i;
+	struct Model* m = Models.Active;
+
+	BoxDesc_YQuad2(m, x1, x2, z1, z2, y2, /* top */
+		x + sidesW + bodyW + sidesW,         y + sidesW,
+		x + sidesW + bodyW + sidesW + bodyW, y + sidesW + bodyH);
+	BoxDesc_YQuad2(m, x2, x1, z1, z2, y1, /* bottom */
+		x + sidesW,                          y + sidesW,
+		x + sidesW + bodyW,                  y + sidesW + bodyH);
+	BoxDesc_ZQuad2(m, x2, x1, y1, y2, z1, /* front */
+		x + sidesW,                          y,
+		x + sidesW + bodyW,                  y + sidesW);
+	BoxDesc_ZQuad2(m, x1, x2, y2, y1, z2, /* back */
+		x + sidesW + bodyW,                  y,
+		x + sidesW + bodyW + bodyW,          y + sidesW);
+	BoxDesc_XQuad2(m, y2, y1, z2, z1, x2, /* left */
+		x,                                   y + sidesW,
+		x + sidesW,                          y + sidesW + bodyH);
+	BoxDesc_XQuad2(m, y1, y2, z2, z1, x1, /* right */
+		x + sidesW + bodyW,                  y + sidesW, 
+		x + sidesW + bodyW + sidesW,         y + sidesW + bodyH); 
+
+	/* rotate left and right 90 degrees	*/
+	for (i = m->index - 8; i < m->index; i++) {
+		struct ModelVertex vertex = m->vertices[i];
+		float z = vertex.z; vertex.z = vertex.y; vertex.y = z;
+		m->vertices[i] = vertex;
+	}
+
+	ModelPart_Init(part, m->index - MODEL_BOX_VERTICES, MODEL_BOX_VERTICES,
+		desc->rotX, desc->rotY, desc->rotZ);
+}
+
+
+void BoxDesc_XQuad(struct Model* m, int texX, int texY, int texWidth, int texHeight, float z1, float z2, float y1, float y2, float x, cc_bool swapU) {
+	int u1 = texX, u2 = texX + texWidth, tmp;
+	if (swapU) { tmp = u1; u1 = u2; u2 = tmp; }
+	BoxDesc_XQuad2(m, z1, z2, y1, y2, x, u1, texY, u2, texY + texHeight);
+}
+
+void BoxDesc_YQuad(struct Model* m, int texX, int texY, int texWidth, int texHeight, float x1, float x2, float z1, float z2, float y, cc_bool swapU) {
+	int u1 = texX, u2 = texX + texWidth, tmp;
+	if (swapU) { tmp = u1; u1 = u2; u2 = tmp; }
+	BoxDesc_YQuad2(m, x1, x2, z1, z2, y, u1, texY, u2, texY + texHeight);
+}
+
+void BoxDesc_ZQuad(struct Model* m, int texX, int texY, int texWidth, int texHeight, float x1, float x2, float y1, float y2, float z, cc_bool swapU) {
+	int u1 = texX, u2 = texX + texWidth, tmp;
+	if (swapU) { tmp = u1; u1 = u2; u2 = tmp; }
+	BoxDesc_ZQuad2(m, x1, x2, y1, y2, z, u1, texY, u2, texY + texHeight);
+}
+
+void BoxDesc_XQuad2(struct Model* m, float z1, float z2, float y1, float y2, float x, int u1, int v1, int u2, int v2) {
+	if (u1 <= u2) { u2 |= UV_MAX; } else { u1 |= UV_MAX; }
+	if (v1 <= v2) { v2 |= UV_MAX; } else { v1 |= UV_MAX; }
+
+	ModelVertex_Init(&m->vertices[m->index], x, y1, z1, u1, v2); m->index++;
+	ModelVertex_Init(&m->vertices[m->index], x, y2, z1, u1, v1); m->index++;
+	ModelVertex_Init(&m->vertices[m->index], x, y2, z2, u2, v1); m->index++;
+	ModelVertex_Init(&m->vertices[m->index], x, y1, z2, u2, v2); m->index++;
+}
+
+void BoxDesc_YQuad2(struct Model* m, float x1, float x2, float z1, float z2, float y, int u1, int v1, int u2, int v2) {
+	if (u1 <= u2) { u2 |= UV_MAX; } else { u1 |= UV_MAX; }
+	if (v1 <= v2) { v2 |= UV_MAX; } else { v1 |= UV_MAX; }
+
+	ModelVertex_Init(&m->vertices[m->index], x1, y, z2, u1, v2); m->index++;
+	ModelVertex_Init(&m->vertices[m->index], x1, y, z1, u1, v1); m->index++;
+	ModelVertex_Init(&m->vertices[m->index], x2, y, z1, u2, v1); m->index++;
+	ModelVertex_Init(&m->vertices[m->index], x2, y, z2, u2, v2); m->index++;
+}
+
+void BoxDesc_ZQuad2(struct Model* m, float x1, float x2, float y1, float y2, float z, int u1, int v1, int u2, int v2) {
+	if (u1 <= u2) { u2 |= UV_MAX; } else { u1 |= UV_MAX; }
+	if (v1 <= v2) { v2 |= UV_MAX; } else { v1 |= UV_MAX; }
+
+	ModelVertex_Init(&m->vertices[m->index], x1, y1, z, u1, v2); m->index++;
+	ModelVertex_Init(&m->vertices[m->index], x1, y2, z, u1, v1); m->index++;
+	ModelVertex_Init(&m->vertices[m->index], x2, y2, z, u2, v1); m->index++;
+	ModelVertex_Init(&m->vertices[m->index], x2, y1, z, u2, v2); m->index++;
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------Models common----------------------------------------------------*
+*#########################################################################################################################*/
+static struct Model* models_head;
+static struct Model* models_tail;
+static struct ModelTex* textures_head;
+static struct ModelTex* textures_tail;
+
+#define Model_RetSize(x,y,z) static Vec3 P = { (x)/16.0f,(y)/16.0f,(z)/16.0f }; e->Size = P;
+#define Model_RetAABB(x1,y1,z1, x2,y2,z2) static struct AABB BB = { { (x1)/16.0f,(y1)/16.0f,(z1)/16.0f }, { (x2)/16.0f,(y2)/16.0f,(z2)/16.0f } }; e->ModelAABB = BB;
+
+static void MakeModel(struct Model* model) {
+	struct Model* active = Models.Active;
+	Models.Active = model;
+	model->MakeParts();
+
+	model->flags |= MODEL_FLAG_INITED;
+	model->index  = 0;
+	Models.Active = active;
+}
+
+struct Model* Model_Get(const cc_string* name) {
+	struct Model* model;
+
+	for (model = models_head; model; model = model->next) {
+		if (!String_CaselessEqualsConst(name, model->name)) continue;
+
+		if (!(model->flags & MODEL_FLAG_INITED))
+			MakeModel(model);
+		return model;
+	}
+	return NULL;
+}
+
+void Model_Register(struct Model* model) {
+	LinkedList_Append(model, models_head, models_tail);
+}
+
+void Model_Unregister(struct Model* model) {
+	struct Model* cur;
+	int i;
+	LinkedList_Remove(model, cur, models_head, models_tail); 
+
+	/* unset this model from all entities, replacing with default fallback */
+	for (i = 0; i < ENTITIES_MAX_COUNT; i++) 
+	{
+		struct Entity* e = Entities.List[i];
+		if (e && e->Model == model) {
+			cc_string humanModelName = String_FromReadonly(Models.Human->name);
+			Entity_SetModel(e, &humanModelName);
+		}
+	}
+}
+
+void Model_RegisterTexture(struct ModelTex* tex) {
+	LinkedList_Append(tex, textures_head, textures_tail);
+}
+
+static void Models_TextureChanged(void* obj, struct Stream* stream, const cc_string* name) {
+	struct ModelTex* tex;
+
+	for (tex = textures_head; tex; tex = tex->next) 
+	{
+		if (!String_CaselessEqualsConst(name, tex->name)) continue;
+
+		Game_UpdateTexture(&tex->texID, stream, name, &tex->skinType, NULL);
+		return;
+	}
+}
+
+
+#ifdef CUSTOM_MODELS
+/*########################################################################################################################*
+*------------------------------------------------------Custom Models------------------------------------------------------*
+*#########################################################################################################################*/
+#ifdef CC_BUILD_LOWMEM
+static struct CustomModel* custom_models;
+
+struct CustomModel* CustomModel_Get(int id) {
+	if (id >= MAX_CUSTOM_MODELS) return NULL;
+
+	/* TODO log message if allocation fails? */
+	if (!custom_models)
+		custom_models = Mem_TryAlloc(MAX_CUSTOM_MODELS, sizeof(struct CustomModel));
+
+	if (!custom_models) return NULL;
+	return &custom_models[id];
+}
+#else
+static struct CustomModel custom_models[MAX_CUSTOM_MODELS];
+
+struct CustomModel* CustomModel_Get(int id) {
+	if (id >= MAX_CUSTOM_MODELS) return NULL;
+
+	return &custom_models[id];
+}
+#endif
+
+void CustomModel_BuildPart(struct CustomModel* cm, struct CustomModelPartDef* part) {
+	float x1 = part->min.x, y1 = part->min.y, z1 = part->min.z;
+	float x2 = part->max.x, y2 = part->max.y, z2 = part->max.z;
+	struct CustomModelPart* p  = &cm->parts[cm->curPartIndex];
+
+	cm->model.index   = cm->curPartIndex * MODEL_BOX_VERTICES;
+	p->fullbright     = part->flags & 0x01;
+	p->firstPersonArm = part->flags & 0x02;
+	if (p->firstPersonArm) cm->numArmParts++;
+
+	BoxDesc_YQuad2(&cm->model, x1, x2, z2, z1, y2, /* top */
+		part->u1[0],                         part->v1[0],
+		part->u2[0],                         part->v2[0]);
+	BoxDesc_YQuad2(&cm->model, x2, x1, z2, z1, y1, /* bottom */
+		part->u1[1],                         part->v1[1],
+		part->u2[1],                         part->v2[1]);
+	BoxDesc_ZQuad2(&cm->model, x1, x2, y1, y2, z1, /* front */
+		part->u1[2],                         part->v1[2],
+		part->u2[2],                         part->v2[2]);
+	BoxDesc_ZQuad2(&cm->model, x2, x1, y1, y2, z2, /* back */
+		part->u1[3],                         part->v1[3],
+		part->u2[3],                         part->v2[3]);
+	BoxDesc_XQuad2(&cm->model, z1, z2, y1, y2, x2, /* left */
+		part->u1[4],                         part->v1[4],
+		part->u2[4],                         part->v2[4]);
+	BoxDesc_XQuad2(&cm->model, z2, z1, y1, y2, x1, /* right */
+		part->u1[5],                         part->v1[5], 
+		part->u2[5],                         part->v2[5]);
+
+	ModelPart_Init(&p->modelPart, cm->model.index - MODEL_BOX_VERTICES, MODEL_BOX_VERTICES,
+		part->rotationOrigin.x, part->rotationOrigin.y, part->rotationOrigin.z);
+}
+
+/* fmodf behaves differently on negatives vs positives,
+   but we want the function to be consistent on both so that the user can
+   specify direction using the "a" parameter in "Game.Time * anim->a".
+*/
+static float EuclidianMod(float x, float y) {
+	return x - Math_Floor(x / y) * y;
+}
+
+static struct ModelVertex oldVertices[MODEL_BOX_VERTICES];
+static float CustomModel_GetAnimationValue(
+	struct CustomModelAnim* anim,
+	struct CustomModelPart* part,
+	struct CustomModel* cm,
+	struct Entity* e
+) {
+	switch (anim->type) {
+		case CustomModelAnimType_Head:
+			return -e->Pitch * MATH_DEG2RAD;
+
+		case CustomModelAnimType_LeftLegX:
+			return e->Anim.LeftLegX;
+
+		case CustomModelAnimType_RightLegX:
+			return e->Anim.RightLegX;
+
+		case CustomModelAnimType_LeftArmX:
+			/* TODO: we're using 2 different rotation orders here */
+			Models.Rotation = ROTATE_ORDER_XZY;
+			return e->Anim.LeftArmX;
+
+		case CustomModelAnimType_LeftArmZ:
+			Models.Rotation = ROTATE_ORDER_XZY;
+			return e->Anim.LeftArmZ;
+
+		case CustomModelAnimType_RightArmX:
+			Models.Rotation = ROTATE_ORDER_XZY;
+			return e->Anim.RightArmX;
+
+		case CustomModelAnimType_RightArmZ:
+			Models.Rotation = ROTATE_ORDER_XZY;
+			return e->Anim.RightArmZ;
+
+		/*
+			a: speed
+			b: shift pos
+		*/
+		case CustomModelAnimType_Spin:
+			return (float)Game.Time * anim->a + anim->b;
+
+		case CustomModelAnimType_SpinVelocity:
+			return e->Anim.WalkTime * anim->a + anim->b;
+
+		/*
+			a: speed
+			b: width
+			c: shift cycle
+			d: shift pos
+		*/
+		case CustomModelAnimType_SinRotate:
+		case CustomModelAnimType_SinTranslate:
+		case CustomModelAnimType_SinSize:
+			return ( Math_SinF((float)Game.Time * anim->a + 2 * MATH_PI * anim->c) + anim->d ) * anim->b;
+
+		case CustomModelAnimType_SinRotateVelocity:
+		case CustomModelAnimType_SinTranslateVelocity:
+		case CustomModelAnimType_SinSizeVelocity:
+			return ( Math_SinF(e->Anim.WalkTime * anim->a + 2 * MATH_PI * anim->c) + anim->d ) * anim->b;
+
+		/*
+			a: speed
+			b: width
+			c: shift cycle
+			d: max value
+		*/
+		case CustomModelAnimType_FlipRotate:
+		case CustomModelAnimType_FlipTranslate:
+		case CustomModelAnimType_FlipSize:
+			return EuclidianMod((float)Game.Time * anim->a + anim->c, anim->d) * anim->b;
+
+		case CustomModelAnimType_FlipRotateVelocity:
+		case CustomModelAnimType_FlipTranslateVelocity:
+		case CustomModelAnimType_FlipSizeVelocity:
+			return EuclidianMod(e->Anim.WalkTime * anim->a + anim->c, anim->d) * anim->b;
+	}
+
+	return 0.0f;
+}
+
+static PackedCol oldCols[FACE_COUNT];
+static void CustomModel_DrawPart(
+	struct CustomModelPart* part,
+	struct CustomModel* cm,
+	struct Entity* e
+) {
+	int i, animIndex;
+	float rotX, rotY, rotZ;
+	cc_bool head = false;
+	cc_bool modifiedVertices = false;
+	float value = 0.0f;
+
+	if (part->fullbright) {
+		for (i = 0; i < FACE_COUNT; i++) 
+		{
+			oldCols[i] = Models.Cols[i];
+			Models.Cols[i] = PACKEDCOL_WHITE;
+		}
+	}
+	
+	/* bbmodels use xyz rotation order */
+	Models.Rotation = ROTATE_ORDER_XYZ;
+	
+	rotX = part->rotation.x * MATH_DEG2RAD;
+	rotY = part->rotation.y * MATH_DEG2RAD;
+	rotZ = part->rotation.z * MATH_DEG2RAD;
+
+	for (animIndex = 0; animIndex < MAX_CUSTOM_MODEL_ANIMS; animIndex++) 
+	{
+		struct CustomModelAnim* anim = &part->anims[animIndex];
+		if (anim->type == CustomModelAnimType_None) continue;
+
+		value = CustomModel_GetAnimationValue(anim, part, cm, e);
+	
+		if (
+			!modifiedVertices &&
+			(anim->type == CustomModelAnimType_SinTranslate ||
+				anim->type == CustomModelAnimType_SinTranslateVelocity ||
+				anim->type == CustomModelAnimType_SinSize ||
+				anim->type == CustomModelAnimType_SinSizeVelocity ||
+				anim->type == CustomModelAnimType_FlipTranslate ||
+				anim->type == CustomModelAnimType_FlipTranslateVelocity ||
+				anim->type == CustomModelAnimType_FlipSize ||
+				anim->type == CustomModelAnimType_FlipSizeVelocity)
+		) {
+			modifiedVertices = true;
+			Mem_Copy(
+				oldVertices,
+				&cm->model.vertices[part->modelPart.offset],
+				sizeof(struct ModelVertex) * MODEL_BOX_VERTICES
+			);
+		}
+		
+		if (
+			anim->type == CustomModelAnimType_SinTranslate ||
+			anim->type == CustomModelAnimType_SinTranslateVelocity ||
+			anim->type == CustomModelAnimType_FlipTranslate ||
+			anim->type == CustomModelAnimType_FlipTranslateVelocity
+		) {
+			for (i = 0; i < MODEL_BOX_VERTICES; i++) {
+				struct ModelVertex* vertex = &cm->model.vertices[part->modelPart.offset + i];
+				switch (anim->axis) {
+					case CustomModelAnimAxis_X:
+						vertex->x += value;
+						break;
+
+					case CustomModelAnimAxis_Y:
+						vertex->y += value;
+						break;
+
+					case CustomModelAnimAxis_Z:
+						vertex->z += value;
+						break;
+				}
+			}
+		} else if (
+			anim->type == CustomModelAnimType_SinSize ||
+			anim->type == CustomModelAnimType_SinSizeVelocity ||
+			anim->type == CustomModelAnimType_FlipSize ||
+			anim->type == CustomModelAnimType_FlipSizeVelocity
+		) {
+			for (i = 0; i < MODEL_BOX_VERTICES; i++) {
+				struct ModelVertex* vertex = &cm->model.vertices[part->modelPart.offset + i];
+				switch (anim->axis) {
+					case CustomModelAnimAxis_X:
+						vertex->x = Math_Lerp(part->modelPart.rotX, vertex->x, value);
+						break;
+
+					case CustomModelAnimAxis_Y:
+						vertex->y = Math_Lerp(part->modelPart.rotY, vertex->y, value);
+						break;
+
+					case CustomModelAnimAxis_Z:
+						vertex->z = Math_Lerp(part->modelPart.rotZ, vertex->z, value);
+						break;
+				}
+			}
+		} else {
+			if (anim->type == CustomModelAnimType_Head) {
+				head = true;
+			}
+			
+			switch (anim->axis) {
+				case CustomModelAnimAxis_X:
+					rotX += value;
+					break;
+
+				case CustomModelAnimAxis_Y:
+					rotY += value;
+					break;
+
+				case CustomModelAnimAxis_Z:
+					rotZ += value;
+					break;
+			}
+		}
+	}
+
+	if (rotX || rotY || rotZ || head) {
+		Model_DrawRotate(rotX, rotY, rotZ, &part->modelPart, head);
+	} else {
+		Model_DrawPart(&part->modelPart);
+	}
+
+	if (modifiedVertices) {
+		Mem_Copy(
+			&cm->model.vertices[part->modelPart.offset],
+			oldVertices,
+			sizeof(struct ModelVertex) * MODEL_BOX_VERTICES
+		);
+	}
+
+	if (part->fullbright) {
+		for (i = 0; i < FACE_COUNT; i++) 
+		{
+			Models.Cols[i] = oldCols[i];
+		}
+	}
+}
+
+static void CustomModel_Draw(struct Entity* e) {
+	struct CustomModel* cm = (struct CustomModel*)Models.Active;
+	int i;
+
+	Model_ApplyTexture(e);
+	Models.uScale = e->uScale / cm->uScale;
+	Models.vScale = e->vScale / cm->vScale;
+	Model_LockVB(e, cm->numParts * MODEL_BOX_VERTICES);
+
+	for (i = 0; i < cm->numParts; i++) 
+	{
+		CustomModel_DrawPart(&cm->parts[i], cm, e);
+	}
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(cm->numParts * MODEL_BOX_VERTICES);
+	Models.Rotation = ROTATE_ORDER_ZYX;
+}
+
+static float CustomModel_GetNameY(struct Entity* e) {
+	return ((struct CustomModel*)e->Model)->nameY;
+}
+
+static float CustomModel_GetEyeY(struct Entity* e) {
+	return ((struct CustomModel*)e->Model)->eyeY;
+}
+
+static void CustomModel_GetCollisionSize(struct Entity* e) {
+	e->Size = ((struct CustomModel*)e->Model)->collisionBounds;
+}
+
+static void CustomModel_GetPickingBounds(struct Entity* e) {
+	e->ModelAABB = ((struct CustomModel*)e->Model)->pickingBoundsAABB;
+}
+
+static void CustomModel_DrawArm(struct Entity* e) {
+	struct CustomModel* cm = (struct CustomModel*)Models.Active;
+	int i;
+	if (!cm->numArmParts) return;
+	Gfx_SetAlphaTest(true);
+
+	Models.uScale = 1.0f / cm->uScale;
+	Models.vScale = 1.0f / cm->vScale;
+	Model_LockVB(e, cm->numArmParts * MODEL_BOX_VERTICES);
+
+	for (i = 0; i < cm->numParts; i++) 
+	{
+		struct CustomModelPart* part = &cm->parts[i];
+		if (part->firstPersonArm) {
+			Model_DrawArmPart(&part->modelPart);
+		}
+	}
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(cm->numArmParts * MODEL_BOX_VERTICES);
+}
+
+static void CheckMaxVertices(void) {
+	/* hack to undo plugins setting a smaller vertices buffer */
+	if (Models.MaxVertices < MODELS_MAX_VERTICES) {
+		Platform_LogConst("CheckMaxVertices found smaller buffer, resetting Models.Vb");
+		Models.MaxVertices = MODELS_MAX_VERTICES;
+		Gfx_DeleteDynamicVb(&Models.Vb);
+	}
+}
+
+void CustomModel_Register(struct CustomModel* cm) {
+	static struct ModelTex customDefaultTex;
+
+	CheckMaxVertices();
+	cm->model.name       = cm->name;
+	cm->model.defaultTex = &customDefaultTex;
+
+	cm->model.MakeParts = Model_NoParts;
+	cm->model.Draw      = CustomModel_Draw;
+	cm->model.GetNameY  = CustomModel_GetNameY;
+	cm->model.GetEyeY   = CustomModel_GetEyeY;
+	cm->model.GetCollisionSize = CustomModel_GetCollisionSize;
+	cm->model.GetPickingBounds = CustomModel_GetPickingBounds;
+	cm->model.DrawArm          = CustomModel_DrawArm;
+
+	/* add to front of models linked list to override original models */
+	if (!models_head) {
+		models_head = &cm->model;
+		models_tail = models_head;
+	} else {
+		cm->model.next = models_head;
+		models_head = &cm->model;
+	}
+	cm->registered = true;
+}
+
+void CustomModel_Undefine(struct CustomModel* cm) {
+	if (!cm->defined) return;
+	if (cm->registered) Model_Unregister((struct Model*)cm);
+
+	Mem_Free(cm->model.vertices);
+	Mem_Set(cm, 0, sizeof(struct CustomModel));
+}
+
+static void CustomModel_FreeAll(void) {
+	int i;
+	if (!custom_models) return;
+
+	for (i = 0; i < MAX_CUSTOM_MODELS; i++) 
+	{
+		CustomModel_Undefine(&custom_models[i]);
+	}
+}
+#else
+static void CustomModel_FreeAll(void) { }
+#endif
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------HumanModel------------------------------------------------------*
+*#########################################################################################################################*/
+struct ModelLimbs {
+	struct ModelPart leftLeg, rightLeg, leftArm, rightArm, leftLegLayer, rightLegLayer, leftArmLayer, rightArmLayer;
+};
+struct ModelSet {
+	struct ModelPart head, torso, hat, torsoLayer;
+	struct ModelLimbs limbs[3];
+};
+#define HUMAN_BASE_VERTICES  (6 * MODEL_BOX_VERTICES)
+#define HUMAN_HAT32_VERTICES (1 * MODEL_BOX_VERTICES)
+#define HUMAN_HAT64_VERTICES (6 * MODEL_BOX_VERTICES)
+#define HUMAN_MAX_VERTICES   HUMAN_BASE_VERTICES + HUMAN_HAT64_VERTICES
+
+static void HumanModel_DrawCore(struct Entity* e, struct ModelSet* model, cc_bool opaqueBody) {
+	struct ModelLimbs* set;
+	int type, num;
+	Model_ApplyTexture(e);
+
+	type = Models.skinType;
+	set  = &model->limbs[type & 0x3];
+	num  = HUMAN_BASE_VERTICES + (type == SKIN_64x32 ? HUMAN_HAT32_VERTICES : HUMAN_HAT64_VERTICES);
+	Model_LockVB(e, num);
+
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &model->head, true);
+	Model_DrawPart(&model->torso);
+	Model_DrawRotate(e->Anim.LeftLegX,  0, e->Anim.LeftLegZ,  &set->leftLeg,  false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, e->Anim.RightLegZ, &set->rightLeg, false);
+
+	Models.Rotation = ROTATE_ORDER_XZY;
+	Model_DrawRotate(e->Anim.LeftArmX,  0, e->Anim.LeftArmZ,  &set->leftArm,  false);
+	Model_DrawRotate(e->Anim.RightArmX, 0, e->Anim.RightArmZ, &set->rightArm, false);
+	Models.Rotation = ROTATE_ORDER_ZYX;
+
+	if (type != SKIN_64x32) {
+		Model_DrawPart(&model->torsoLayer);
+		Model_DrawRotate(e->Anim.LeftLegX,  0, e->Anim.LeftLegZ,  &set->leftLegLayer,  false);
+		Model_DrawRotate(e->Anim.RightLegX, 0, e->Anim.RightLegZ, &set->rightLegLayer, false);
+
+		Models.Rotation = ROTATE_ORDER_XZY;
+		Model_DrawRotate(e->Anim.LeftArmX,  0, e->Anim.LeftArmZ,  &set->leftArmLayer,  false);
+		Model_DrawRotate(e->Anim.RightArmX, 0, e->Anim.RightArmZ, &set->rightArmLayer, false);
+		Models.Rotation = ROTATE_ORDER_ZYX;
+	}
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &model->hat, true);
+
+	Model_UnlockVB();
+	if (opaqueBody) {
+		/* human model draws the body opaque so players can't have invisible skins */
+		Gfx_SetAlphaTest(false);
+		Gfx_DrawVb_IndexedTris_Range(HUMAN_BASE_VERTICES, 0);
+		Gfx_SetAlphaTest(true);
+		Gfx_DrawVb_IndexedTris_Range(num - HUMAN_BASE_VERTICES, HUMAN_BASE_VERTICES);
+	} else {
+		Gfx_DrawVb_IndexedTris(num);
+	}
+}
+
+static void HumanModel_DrawArmCore(struct Entity* e, struct ModelSet* model) {
+	struct ModelLimbs* set;
+	int type, num;
+	Gfx_SetAlphaTest(true);
+
+	type = Models.skinType;
+	set  = &model->limbs[type & 0x3];
+	num  = type == SKIN_64x32 ? MODEL_BOX_VERTICES : (2 * MODEL_BOX_VERTICES);
+	Model_LockVB(e, num);
+
+	Model_DrawArmPart(&set->rightArm);
+	if (type != SKIN_64x32) Model_DrawArmPart(&set->rightArmLayer);
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(num);
+}
+
+
+static struct ModelSet human_set;
+static void HumanModel_MakeParts(void) {
+	static const struct BoxDesc head = {
+		BoxDesc_Tex(0,0),
+		BoxDesc_Box(-4,24,-4, 4,32,4),
+		BoxDesc_Rot(0,24,0),
+	}; 
+	static const struct BoxDesc torso = {
+		BoxDesc_Tex(16,16),
+		BoxDesc_Box(-4,12,-2, 4,24,2),
+		BoxDesc_Rot(0,12,0),
+	}; 
+	static const struct BoxDesc hat = {
+		BoxDesc_Tex(32,0),
+		BoxDesc_Dims(-4,24,-4, 4,32,4),
+		BoxDesc_Bounds(-4.5f,23.5f,-4.5f, 4.5f,32.5f,4.5f),
+		BoxDesc_Rot(0,24,0),
+	}; 
+	static const struct BoxDesc torsoL = {
+		BoxDesc_Tex(16,32),
+		BoxDesc_Dims(-4,12,-2, 4,24,2),
+		BoxDesc_Bounds(-4.5f,11.5f,-2.5f, 4.5f,24.5f,2.5f),
+		BoxDesc_Rot(0,12,0),
+	};
+
+	static const struct BoxDesc lArm = {
+		BoxDesc_Tex(40,16),
+		BoxDesc_Box(-4,12,-2, -8,24,2),
+		BoxDesc_Rot(-5,22,0),
+	};
+	static const struct BoxDesc rArm = {
+		BoxDesc_Tex(40,16),
+		BoxDesc_Box(4,12,-2, 8,24,2),
+		BoxDesc_Rot(5,22,0),
+	};
+	static const struct BoxDesc lLeg = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(0,0,-2, -4,12,2),
+		BoxDesc_Rot(0,12,0),
+	};
+	static const struct BoxDesc rLeg = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(0,0,-2, 4,12,2),
+		BoxDesc_Rot(0,12,0),
+	};
+
+	static const struct BoxDesc lArm64 = {
+		BoxDesc_Tex(32,48),
+		BoxDesc_Box(-8,12,-2, -4,24,2),
+		BoxDesc_Rot(-5,22,0),
+	};
+	static const struct BoxDesc lLeg64 = {
+		BoxDesc_Tex(16,48),
+		BoxDesc_Box(-4,0,-2, 0,12,2),
+		BoxDesc_Rot(0,12,0),
+	};
+	static const struct BoxDesc lArmL = {
+		BoxDesc_Tex(48,48),
+		BoxDesc_Dims(-8,12,-2, -4,24,2),
+		BoxDesc_Bounds(-8.5f,11.5f,-2.5f, -3.5f,24.5f,2.5f),
+		BoxDesc_Rot(-5,22,0),
+	};
+	static const struct BoxDesc rArmL = {
+		BoxDesc_Tex(40,32),
+		BoxDesc_Dims(4,12,-2, 8,24,2),
+		BoxDesc_Bounds(3.5f,11.5f,-2.5f, 8.5f,24.5f,2.5f),
+		BoxDesc_Rot(5,22,0),
+	};
+	static const struct BoxDesc lLegL = {
+		BoxDesc_Tex(0,48),
+		BoxDesc_Dims(-4,0,-2, 0,12,2),
+		BoxDesc_Bounds(-4.5f,-0.5f,-2.5f, 0.5f,12.5f,2.5f),
+		BoxDesc_Rot(0,12,0),
+	};
+	static const struct BoxDesc rLegL = {
+		BoxDesc_Tex(0,32),
+		BoxDesc_Dims(0,0,-2, 4,12,2),
+		BoxDesc_Bounds(-0.5f,-0.5f,-2.5f, 4.5f,12.5f,2.5f),
+		BoxDesc_Rot(0,12,0),
+	};
+
+	/* Thin arms - make sure to keep in sync with lArm64/rArm/lArmL/rArmL */
+	static const struct BoxDesc thin_lArm = {
+		BoxDesc_Tex(32,48),
+		BoxDesc_Box(-7,12,-2, -4,24,2),
+		BoxDesc_Rot(-5,22,0),
+	};
+	static const struct BoxDesc thin_rArm = {
+		BoxDesc_Tex(40,16),
+		BoxDesc_Box(4,12,-2, 7,24,2),
+		BoxDesc_Rot(5,22,0),
+	};
+	static const struct BoxDesc thin_lArmL = {
+		BoxDesc_Tex(48,48),
+		BoxDesc_Dims(-7,12,-2, -4,24,2),
+		BoxDesc_Bounds(-7.5f,11.5f,-2.5f, -3.5f,24.5f,2.5f),
+		BoxDesc_Rot(-5,22,0),
+	};
+	static const struct BoxDesc thin_rArmL = {
+		BoxDesc_Tex(40,32),
+		BoxDesc_Dims(4,12,-2, 7,24,2),
+		BoxDesc_Bounds(3.5f,11.5f,-2.5f, 7.5f,24.5f,2.5f),
+		BoxDesc_Rot(5,22,0),
+	};
+
+	struct ModelLimbs* set     = &human_set.limbs[0];
+	struct ModelLimbs* set64   = &human_set.limbs[1];
+	struct ModelLimbs* setSlim = &human_set.limbs[2];
+
+	BoxDesc_BuildBox(&human_set.head,  &head);
+	BoxDesc_BuildBox(&human_set.torso, &torso);
+	BoxDesc_BuildBox(&human_set.hat,   &hat);
+	BoxDesc_BuildBox(&human_set.torsoLayer, &torsoL);
+
+	BoxDesc_BuildBox(&set->leftLeg,  &lLeg);
+	BoxDesc_BuildBox(&set->rightLeg, &rLeg);
+	BoxDesc_BuildBox(&set->leftArm,  &lArm);
+	BoxDesc_BuildBox(&set->rightArm, &rArm);
+
+	/* 64x64 arms and legs */
+	BoxDesc_BuildBox(&set64->leftLeg, &lLeg64);
+	set64->rightLeg = set->rightLeg;
+	BoxDesc_BuildBox(&set64->leftArm, &lArm64);
+	set64->rightArm = set->rightArm;
+
+	/* Thin arms and legs */
+	setSlim->leftLeg  = set64->leftLeg;
+	setSlim->rightLeg = set64->rightLeg;
+	BoxDesc_BuildBox(&setSlim->leftArm,  &thin_lArm);
+	BoxDesc_BuildBox(&setSlim->rightArm, &thin_rArm);
+
+	/* 64x64 arm and leg layers */
+	BoxDesc_BuildBox(&set64->leftLegLayer,  &lLegL);
+	BoxDesc_BuildBox(&set64->rightLegLayer, &rLegL);
+	BoxDesc_BuildBox(&set64->leftArmLayer,  &lArmL);
+	BoxDesc_BuildBox(&set64->rightArmLayer, &rArmL);
+
+	/* Thin arm and leg layers */
+	setSlim->leftLegLayer  = set64->leftLegLayer;
+	setSlim->rightLegLayer = set64->rightLegLayer;
+	BoxDesc_BuildBox(&setSlim->leftArmLayer,  &thin_lArmL);
+	BoxDesc_BuildBox(&setSlim->rightArmLayer, &thin_rArmL);
+}
+
+static void HumanModel_Draw(struct Entity* e) {
+	HumanModel_DrawCore(e, &human_set, true);
+}
+
+static void HumanModel_DrawArm(struct Entity* e) {
+	HumanModel_DrawArmCore(e, &human_set);
+}
+
+static float HumanModel_GetNameY(struct Entity* e) { return 32.5f/16.0f; }
+static float HumanModel_GetEyeY(struct Entity* e)  { return 26.0f/16.0f; }
+static void HumanModel_GetSize(struct Entity* e)   { Model_RetSize(8.6f,28.1f,8.6f); }
+static void HumanModel_GetBounds(struct Entity* e) { Model_RetAABB(-8,0,-4, 8,32,4); }
+
+static struct ModelVertex human_vertices[MODEL_BOX_VERTICES * (7 + 7 + 4)];
+static struct ModelTex human_tex = { "char.png" };
+static struct Model  human_model = { 
+	"humanoid", human_vertices, &human_tex,
+	HumanModel_MakeParts, HumanModel_Draw,
+	HumanModel_GetNameY,  HumanModel_GetEyeY,
+	HumanModel_GetSize,   HumanModel_GetBounds,
+};
+
+static void HumanoidModel_Register(void) {
+	Model_Init(&human_model);
+	human_model.DrawArm  = HumanModel_DrawArm;
+
+	human_model.calcHumanAnims = true;
+	human_model.usesHumanSkin  = true;
+	human_model.flags |= MODEL_FLAG_CLEAR_HAT;
+	human_model.maxVertices    = HUMAN_MAX_VERTICES;
+
+	Model_Register(&human_model);
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------ChibiModel------------------------------------------------------*
+*#########################################################################################################################*/
+static struct ModelSet chibi_set;
+
+CC_NOINLINE static void ChibiModel_ScalePart(struct ModelPart* dst, struct ModelPart* src) {
+	struct Model* chibi = Models.Active;
+	int i;
+
+	*dst = *src;
+	dst->rotX *= 0.5f; dst->rotY *= 0.5f; dst->rotZ *= 0.5f;
+	
+	for (i = src->offset; i < src->offset + src->count; i++) {
+		chibi->vertices[i] = human_model.vertices[i];
+
+		chibi->vertices[i].x *= 0.5f;
+		chibi->vertices[i].y *= 0.5f;
+		chibi->vertices[i].z *= 0.5f;
+	}
+}
+
+CC_NOINLINE static void ChibiModel_ScaleLimbs(struct ModelLimbs* dst, struct ModelLimbs* src) {
+	ChibiModel_ScalePart(&dst->leftLeg,  &src->leftLeg);
+	ChibiModel_ScalePart(&dst->rightLeg, &src->rightLeg);
+	ChibiModel_ScalePart(&dst->leftArm,  &src->leftArm);
+	ChibiModel_ScalePart(&dst->rightArm, &src->rightArm);
+
+	ChibiModel_ScalePart(&dst->leftLegLayer,  &src->leftLegLayer);
+	ChibiModel_ScalePart(&dst->rightLegLayer, &src->rightLegLayer);
+	ChibiModel_ScalePart(&dst->leftArmLayer,  &src->leftArmLayer);
+	ChibiModel_ScalePart(&dst->rightArmLayer, &src->rightArmLayer);
+}
+
+static void ChibiModel_MakeParts(void) {
+	static const struct BoxDesc head = {
+		BoxDesc_Tex(0,0),
+		BoxDesc_Box(-4,12,-4, 4,20,4),
+		BoxDesc_Rot(0,13,0),
+	};
+	static const struct BoxDesc hat = {
+		BoxDesc_Tex(32,0),
+		BoxDesc_Dims(-4,12,-4, 4,20,4),
+		BoxDesc_Bounds(-4.25f,11.75f,-4.25f, 4.25f,20.25f,4.25f),
+		BoxDesc_Rot(0,13,0),
+	}; 
+
+	/* Chibi is mostly just half scale humanoid */
+	ChibiModel_ScalePart(&chibi_set.torso,      &human_set.torso);
+	ChibiModel_ScalePart(&chibi_set.torsoLayer, &human_set.torsoLayer);
+	ChibiModel_ScaleLimbs(&chibi_set.limbs[0], &human_set.limbs[0]);
+	ChibiModel_ScaleLimbs(&chibi_set.limbs[1], &human_set.limbs[1]);
+	ChibiModel_ScaleLimbs(&chibi_set.limbs[2], &human_set.limbs[2]);
+
+	/* But head is at normal size */
+	Models.Active->index = human_set.head.offset;
+	BoxDesc_BuildBox(&chibi_set.head, &head);
+	Models.Active->index = human_set.hat.offset;
+	BoxDesc_BuildBox(&chibi_set.hat,  &hat);
+}
+
+static void ChibiModel_Draw(struct Entity* e) {
+	HumanModel_DrawCore(e, &chibi_set, true);
+}
+
+static void ChibiModel_DrawArm(struct Entity* e) {
+	HumanModel_DrawArmCore(e, &chibi_set);
+}
+
+static float ChibiModel_GetNameY(struct Entity* e) { return 20.2f/16.0f; }
+static float ChibiModel_GetEyeY(struct Entity* e)  { return 14.0f/16.0f; }
+static void ChibiModel_GetSize(struct Entity* e)   { Model_RetSize(4.6f,20.1f,4.6f); }
+static void ChibiModel_GetBounds(struct Entity* e) { Model_RetAABB(-4,0,-4, 4,16,4); }
+
+static struct ModelVertex chibi_vertices[MODEL_BOX_VERTICES * (7 + 7 + 4)];
+static struct Model chibi_model = { "chibi", chibi_vertices, &human_tex,
+	ChibiModel_MakeParts, ChibiModel_Draw,
+	ChibiModel_GetNameY,  ChibiModel_GetEyeY, 
+	ChibiModel_GetSize,   ChibiModel_GetBounds
+};
+
+static void ChibiModel_Register(void) {
+	Model_Init(&chibi_model);
+	chibi_model.DrawArm  = ChibiModel_DrawArm;
+	chibi_model.armX = 3; 
+	chibi_model.armY = 6;
+
+	chibi_model.calcHumanAnims = true;
+	chibi_model.usesHumanSkin  = true;
+	chibi_model.flags |= MODEL_FLAG_CLEAR_HAT;
+	chibi_model.maxVertices    = HUMAN_MAX_VERTICES;
+
+	chibi_model.maxScale    = 3.0f;
+	chibi_model.shadowScale = 0.5f;
+	Model_Register(&chibi_model);
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------SittingModel-----------------------------------------------------*
+*#########################################################################################################################*/
+#define SIT_OFFSET 10.0f
+
+static void SittingModel_GetTransform(struct Entity* e, Vec3 pos, struct Matrix* m) {
+	pos.y -= (SIT_OFFSET / 16.0f) * e->ModelScale.y;
+	Entity_GetTransform(e, pos, e->ModelScale, m);
+}
+
+static void SittingModel_Draw(struct Entity* e) {
+	e->Anim.LeftLegX =  1.5f; e->Anim.RightLegX = 1.5f;
+	e->Anim.LeftLegZ = -0.1f; e->Anim.RightLegZ = 0.1f;
+	HumanModel_Draw(e);
+}
+
+static float SittingModel_GetEyeY(struct Entity* e)  { return (26.0f - SIT_OFFSET) / 16.0f; }
+static void SittingModel_GetSize(struct Entity* e)   { Model_RetSize(8.6f,28.1f - SIT_OFFSET,8.6f); }
+static void SittingModel_GetBounds(struct Entity* e) { Model_RetAABB(-8,0,-4, 8,32 - SIT_OFFSET,4); }
+
+static struct Model sitting_model = { "sit", human_vertices, &human_tex,
+	Model_NoParts,        SittingModel_Draw,
+	HumanModel_GetNameY,  SittingModel_GetEyeY,
+	SittingModel_GetSize, SittingModel_GetBounds
+};
+
+static void SittingModel_Register(void) {
+	Model_Init(&sitting_model);
+	sitting_model.DrawArm  = HumanModel_DrawArm;
+
+	sitting_model.calcHumanAnims = true;
+	sitting_model.usesHumanSkin  = true;
+	sitting_model.flags |= MODEL_FLAG_CLEAR_HAT;
+	sitting_model.maxVertices    = HUMAN_MAX_VERTICES;
+
+	sitting_model.shadowScale  = 0.5f;
+	sitting_model.GetTransform = SittingModel_GetTransform;
+	Model_Register(&sitting_model);
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------CorpseModel------------------------------------------------------*
+*#########################################################################################################################*/
+static void CorpseModel_Draw(struct Entity* e) {
+	e->Anim.LeftLegX = 0.025f; e->Anim.RightLegX = 0.025f;
+	e->Anim.LeftArmX = 0.025f; e->Anim.RightArmX = 0.025f;
+	e->Anim.LeftLegZ = -0.15f; e->Anim.RightLegZ =  0.15f;
+	e->Anim.LeftArmZ = -0.20f; e->Anim.RightArmZ =  0.20f;
+	HumanModel_Draw(e);
+}
+
+static struct Model corpse_model;
+static void CorpseModel_Register(void) {
+	corpse_model      = human_model;
+	corpse_model.name = "corpse";
+
+	corpse_model.MakeParts = Model_NoParts;
+	corpse_model.Draw      = CorpseModel_Draw;
+	Model_Register(&corpse_model);
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------HeadModel-------------------------------------------------------*
+*#########################################################################################################################*/
+#define HEAD_MAX_VERTICES (2 * MODEL_BOX_VERTICES)
+
+static void HeadModel_GetTransform(struct Entity* e, Vec3 pos, struct Matrix* m) {
+	pos.y -= (24.0f/16.0f) * e->ModelScale.y;
+	Entity_GetTransform(e, pos, e->ModelScale, m);
+}
+
+static void HeadModel_Draw(struct Entity* e) {
+	struct ModelPart part;
+	Model_ApplyTexture(e);
+	Model_LockVB(e, HEAD_MAX_VERTICES);
+
+	part = human_set.head; part.rotY += 4.0f/16.0f;
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &part, true);
+	part = human_set.hat;  part.rotY += 4.0f/16.0f;
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &part, true);
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(HEAD_MAX_VERTICES);
+}
+
+static float HeadModel_GetEyeY(struct Entity* e)  { return 6.0f/16.0f; }
+static void HeadModel_GetSize(struct Entity* e)   { Model_RetSize(7.9f,7.9f,7.9f); }
+static void HeadModel_GetBounds(struct Entity* e) { Model_RetAABB(-4,0,-4, 4,8,4); }
+
+static struct Model head_model = { "head", human_vertices, &human_tex,
+	Model_NoParts,       HeadModel_Draw,
+	HumanModel_GetNameY, HeadModel_GetEyeY,
+	HeadModel_GetSize,   HeadModel_GetBounds
+};
+
+static void HeadModel_Register(void) {
+	Model_Init(&head_model);
+	head_model.usesHumanSkin = true;
+	head_model.flags |= MODEL_FLAG_CLEAR_HAT;
+
+	head_model.pushes        = false;
+	head_model.GetTransform  = HeadModel_GetTransform;
+	head_model.maxVertices   = HEAD_MAX_VERTICES;
+	Model_Register(&head_model);
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------ChickenModel-----------------------------------------------------*
+*#########################################################################################################################*/
+static struct ModelPart chicken_head, chicken_wattle, chicken_beak, chicken_torso;
+static struct ModelPart chicken_leftLeg, chicken_rightLeg, chicken_leftWing, Chicken_RightWing;
+#define CHICKEN_MAX_VERTICES (6 * MODEL_BOX_VERTICES + 2 * (MODEL_QUAD_VERTICES * 2))
+
+static void ChickenModel_MakeLeg(struct ModelPart* part, int x1, int x2, int legX1, int legX2) {
+#define ch_y1 ( 1.0f/64.0f)
+#define ch_y2 ( 5.0f/16.0f)
+#define ch_z2 ( 1.0f/16.0f)
+#define ch_z1 (-2.0f/16.0f)
+
+	struct Model* m = Models.Active;
+	BoxDesc_YQuad2(m, x2/16.0f,    x1/16.0f,    ch_z1, ch_z2, ch_y1,
+		32,0, 35,3); /* bottom feet */
+	BoxDesc_ZQuad2(m, legX1/16.0f, legX2/16.0f, ch_y1, ch_y2, ch_z2,
+		36,3, 37,8); /* vertical part of leg */
+
+	ModelPart_Init(part, m->index - MODEL_QUAD_VERTICES * 2, MODEL_QUAD_VERTICES * 2,
+		0.0f/16.0f, 5.0f/16.0f, 1.0f/16.0f);
+}
+
+static void ChickenModel_MakeParts(void) {
+	static const struct BoxDesc head = {
+		BoxDesc_Tex(0,0),
+		BoxDesc_Box(-2,9,-6, 2,15,-3),
+		BoxDesc_Rot(0,9,-4),
+	};
+	static const struct BoxDesc wattle = {
+		BoxDesc_Tex(14,4),
+		BoxDesc_Box(-1,9,-7, 1,11,-5),
+		BoxDesc_Rot(0,9,-4),
+	};
+	static const struct BoxDesc beak = {
+		BoxDesc_Tex(14,0),
+		BoxDesc_Box(-2,11,-8, 2,13,-6),
+		BoxDesc_Rot(0,9,-4),
+	};
+	static const struct BoxDesc torso = {
+		BoxDesc_Tex(0,9),
+		BoxDesc_Box(-3,5,-4, 3,11,3),
+		BoxDesc_Rot(0,5,0),
+	};
+	static const struct BoxDesc lWing = {
+		BoxDesc_Tex(24,13),
+		BoxDesc_Box(-4,7,-3, -3,11,3),
+		BoxDesc_Rot(-3,11,0),
+	}; 
+	static const struct BoxDesc rWing = {
+		BoxDesc_Tex(24,13),
+		BoxDesc_Box(3,7,-3, 4,11,3),
+		BoxDesc_Rot(3,11,0),
+	}; 
+	
+	BoxDesc_BuildBox(&chicken_head,   &head);
+	BoxDesc_BuildBox(&chicken_wattle, &wattle);
+	BoxDesc_BuildBox(&chicken_beak,   &beak);
+	BoxDesc_BuildRotatedBox(&chicken_torso, &torso);
+	BoxDesc_BuildBox(&chicken_leftWing,     &lWing);
+	BoxDesc_BuildBox(&Chicken_RightWing,    &rWing);
+
+	ChickenModel_MakeLeg(&chicken_leftLeg, -3, 0, -2, -1);
+	ChickenModel_MakeLeg(&chicken_rightLeg, 0, 3, 1, 2);
+}
+
+static void ChickenModel_Draw(struct Entity* e) {
+	PackedCol col = Models.Cols[0];
+	int i;
+	Model_ApplyTexture(e);
+	Model_LockVB(e, CHICKEN_MAX_VERTICES);
+
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &chicken_head,   true);
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &chicken_wattle, true);
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &chicken_beak,   true);
+
+	Model_DrawPart(&chicken_torso);
+	Model_DrawRotate(0, 0, -Math_AbsF(e->Anim.LeftArmX), &chicken_leftWing,  false);
+	Model_DrawRotate(0, 0,  Math_AbsF(e->Anim.LeftArmX), &Chicken_RightWing, false);
+
+	for (i = 0; i < FACE_COUNT; i++) 
+	{
+		Models.Cols[i] = PackedCol_Scale(col, 0.7f);
+	}
+
+	Model_DrawRotate(e->Anim.LeftLegX,  0, 0, &chicken_leftLeg,  false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, 0, &chicken_rightLeg, false);
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(CHICKEN_MAX_VERTICES);
+}
+
+static float ChickenModel_GetNameY(struct Entity* e) { return 1.0125f; }
+static float ChickenModel_GetEyeY(struct Entity* e)  { return 14.0f/16.0f; }
+static void ChickenModel_GetSize(struct Entity* e)   { Model_RetSize(8.0f,12.0f,8.0f); }
+static void ChickenModel_GetBounds(struct Entity* e) { Model_RetAABB(-4,0,-8, 4,15,4); }
+
+static struct ModelVertex chicken_vertices[MODEL_BOX_VERTICES * 6 + (MODEL_QUAD_VERTICES * 2) * 2];
+static struct ModelTex chicken_tex = { "chicken.png" };
+static struct Model chicken_model = { "chicken", chicken_vertices, &chicken_tex,
+	ChickenModel_MakeParts, ChickenModel_Draw,
+	ChickenModel_GetNameY,  ChickenModel_GetEyeY,
+	ChickenModel_GetSize,   ChickenModel_GetBounds
+};
+
+static void ChickenModel_Register(void) {
+	Model_Init(&chicken_model);
+	chicken_model.maxVertices = CHICKEN_MAX_VERTICES;
+	Model_Register(&chicken_model);
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------CreeperModel-----------------------------------------------------*
+*#########################################################################################################################*/
+static struct ModelPart creeper_head, creeper_torso, creeper_leftLegFront;
+static struct ModelPart creeper_rightLegFront, creeper_leftLegBack, creeper_rightLegBack;
+#define CREEPER_MAX_VERTICES (6 * MODEL_BOX_VERTICES)
+
+static void CreeperModel_MakeParts(void) {
+	static const struct BoxDesc head = {
+		BoxDesc_Tex(0,0),
+		BoxDesc_Box(-4,18,-4, 4,26,4),
+		BoxDesc_Rot(0,18,0),
+	};
+	static const struct BoxDesc torso = {
+		BoxDesc_Tex(16,16),
+		BoxDesc_Box(-4,6,-2, 4,18,2),
+		BoxDesc_Rot(0,6,0),
+	}; 
+	static const struct BoxDesc lFront = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(-4,0,-6, 0,6,-2),
+		BoxDesc_Rot(0,6,-2),
+	}; 
+	static const struct BoxDesc rFront = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(0,0,-6, 4,6,-2),
+		BoxDesc_Rot(0,6,-2),
+	}; 
+	static const struct BoxDesc lBack = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(-4,0,2, 0,6,6),
+		BoxDesc_Rot(0,6,2),
+	}; 
+	static const struct BoxDesc rBack = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(0,0,2, 4,6,6),
+		BoxDesc_Rot(0,6,2),
+	};
+	
+	BoxDesc_BuildBox(&creeper_head,  &head);
+	BoxDesc_BuildBox(&creeper_torso, &torso);
+	BoxDesc_BuildBox(&creeper_leftLegFront,  &lFront);
+	BoxDesc_BuildBox(&creeper_rightLegFront, &rFront);
+	BoxDesc_BuildBox(&creeper_leftLegBack,   &lBack);
+	BoxDesc_BuildBox(&creeper_rightLegBack,  &rBack);
+}
+
+static void CreeperModel_Draw(struct Entity* e) {
+	Model_ApplyTexture(e);
+	Model_LockVB(e, CREEPER_MAX_VERTICES);
+
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &creeper_head, true);
+	Model_DrawPart(&creeper_torso);
+	Model_DrawRotate(e->Anim.LeftLegX,  0, 0, &creeper_leftLegFront,  false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, 0, &creeper_rightLegFront, false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, 0, &creeper_leftLegBack,   false);
+	Model_DrawRotate(e->Anim.LeftLegX,  0, 0, &creeper_rightLegBack,  false);
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(CREEPER_MAX_VERTICES);
+}
+
+static float CreeperModel_GetNameY(struct Entity* e) { return 1.7f; }
+static float CreeperModel_GetEyeY(struct Entity* e)  { return 22.0f/16.0f; }
+static void CreeperModel_GetSize(struct Entity* e)   { Model_RetSize(8.0f,26.0f,8.0f); }
+static void CreeperModel_GetBounds(struct Entity* e) { Model_RetAABB(-4,0,-6, 4,26,6); }
+
+static struct ModelVertex creeper_vertices[MODEL_BOX_VERTICES * 6];
+static struct ModelTex creeper_tex = { "creeper.png" };
+static struct Model creeper_model  = { 
+	"creeper", creeper_vertices, &creeper_tex,
+	CreeperModel_MakeParts, CreeperModel_Draw,
+	CreeperModel_GetNameY,  CreeperModel_GetEyeY,
+	CreeperModel_GetSize,   CreeperModel_GetBounds
+};
+
+static void CreeperModel_Register(void) {
+	Model_Init(&creeper_model);
+	creeper_model.maxVertices = CREEPER_MAX_VERTICES;
+	Model_Register(&creeper_model);
+}
+
+
+/*########################################################################################################################*
+*----------------------------------------------------------PigModel-------------------------------------------------------*
+*#########################################################################################################################*/
+static struct ModelPart pig_head, pig_torso, pig_leftLegFront, pig_rightLegFront;
+static struct ModelPart pig_leftLegBack, pig_rightLegBack;
+#define PIG_MAX_VERTICES (6 * MODEL_BOX_VERTICES)
+
+static void PigModel_MakeParts(void) {
+	static const struct BoxDesc head = {
+		BoxDesc_Tex(0,0),
+		BoxDesc_Box(-4,8,-14, 4,16,-6),
+		BoxDesc_Rot(0,12,-6),
+	}; 
+	static const struct BoxDesc torso = {
+		BoxDesc_Tex(28,8),
+		BoxDesc_Box(-5,6,-8, 5,14,8),
+		BoxDesc_Rot(0,6,0),
+	}; 
+	static const struct BoxDesc lFront = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(-5,0,-7, -1,6,-3),
+		BoxDesc_Rot(0,6,-5),
+	}; 
+	static const struct BoxDesc rFront = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(1,0,-7, 5,6,-3),
+		BoxDesc_Rot(0,6,-5),
+	}; 
+	static const struct BoxDesc lBack = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(-5,0,5, -1,6,9),
+		BoxDesc_Rot(0,6,7),
+	}; 
+	static const struct BoxDesc rBack = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(1,0,5, 5,6,9),
+		BoxDesc_Rot(0,6,7),
+	}; 
+	
+	BoxDesc_BuildBox(&pig_head,          &head);
+	BoxDesc_BuildRotatedBox(&pig_torso,  &torso);
+	BoxDesc_BuildBox(&pig_leftLegFront,  &lFront);
+	BoxDesc_BuildBox(&pig_rightLegFront, &rFront);
+	BoxDesc_BuildBox(&pig_leftLegBack,   &lBack);
+	BoxDesc_BuildBox(&pig_rightLegBack,  &rBack);
+}
+
+static void PigModel_Draw(struct Entity* e) {
+	Model_ApplyTexture(e);
+	Model_LockVB(e, PIG_MAX_VERTICES);
+
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &pig_head, true);
+	Model_DrawPart(&pig_torso);
+	Model_DrawRotate(e->Anim.LeftLegX,  0, 0, &pig_leftLegFront,  false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, 0, &pig_rightLegFront, false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, 0, &pig_leftLegBack,   false);
+	Model_DrawRotate(e->Anim.LeftLegX,  0, 0, &pig_rightLegBack,  false);
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(PIG_MAX_VERTICES);
+}
+
+static float PigModel_GetNameY(struct Entity* e) { return 1.075f; }
+static float PigModel_GetEyeY(struct Entity* e)  { return 12.0f/16.0f; }
+static void PigModel_GetSize(struct Entity* e)   { Model_RetSize(14.0f,14.0f,14.0f); }
+static void PigModel_GetBounds(struct Entity* e) { Model_RetAABB(-5,0,-14, 5,16,9); }
+
+static struct ModelVertex pig_vertices[MODEL_BOX_VERTICES * 6];
+static struct ModelTex pig_tex = { "pig.png" };
+static struct Model pig_model  = { "pig", pig_vertices, &pig_tex,
+	PigModel_MakeParts, PigModel_Draw,
+	PigModel_GetNameY,  PigModel_GetEyeY,
+	PigModel_GetSize,   PigModel_GetBounds
+};
+
+static void PigModel_Register(void) {
+	Model_Init(&pig_model);
+	pig_model.maxVertices = PIG_MAX_VERTICES;
+	Model_Register(&pig_model);
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------SheepModel------------------------------------------------------*
+*#########################################################################################################################*/
+static struct ModelPart sheep_head, sheep_torso, sheep_leftLegFront;
+static struct ModelPart sheep_rightLegFront, sheep_leftLegBack, sheep_rightLegBack;
+static struct ModelPart fur_head, fur_torso, fur_leftLegFront, fur_rightLegFront;
+static struct ModelPart fur_leftLegBack, fur_rightLegBack;
+static struct ModelTex fur_tex = { "sheep_fur.png" };
+#define SHEEP_BODY_VERTICES (6 * MODEL_BOX_VERTICES)
+#define SHEEP_FUR_VERTICES  (6 * MODEL_BOX_VERTICES)
+
+static void SheepModel_MakeParts(void) {
+	static const struct BoxDesc head = {
+		BoxDesc_Tex(0,0),
+		BoxDesc_Box(-3,16,-14, 3,22,-6),
+		BoxDesc_Rot(0,18,-8),
+	};
+	static const struct BoxDesc torso = {
+		BoxDesc_Tex(28,8),
+		BoxDesc_Box(-4,12,-8, 4,18,8),
+		BoxDesc_Rot(0,12,0),
+	}; 	
+	static const struct BoxDesc lFront = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(-5,0,-7, -1,12,-3),
+		BoxDesc_Rot(0,12,-5),
+	}; 
+	static const struct BoxDesc rFront = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(1,0,-7, 5,12,-3),
+		BoxDesc_Rot(0,12,-5),
+	}; 
+	static const struct BoxDesc lBack = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(-5,0,5, -1,12,9),
+		BoxDesc_Rot(0,12,7),
+	}; 
+	static const struct BoxDesc rBack = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(1,0,5, 5,12,9),
+		BoxDesc_Rot(0,12,7),
+	};
+
+	static const struct BoxDesc fHead = {
+		BoxDesc_Tex(0,0),
+		BoxDesc_Dims(-3,16,-12, 3,22,-6),
+		BoxDesc_Bounds(-3.5f,15.5f,-12.5f, 3.5f,22.5f,-5.5f),
+		BoxDesc_Rot(0,18,-8),
+	}; 
+	static const struct BoxDesc fTorso = {
+		BoxDesc_Tex(28,8),
+		BoxDesc_Dims(-4,12,-8, 4,18,8),
+		BoxDesc_Bounds(-6.0f,10.5f,-10.0f, 6.0f,19.5f,10.0f),
+		BoxDesc_Rot(0,12,0),
+	};
+	static const struct BoxDesc flFront = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Dims(-5,6,-7, -1,12,-3),
+		BoxDesc_Bounds(-5.5f,5.5f,-7.5f, -0.5f,12.5f,-2.5f),
+		BoxDesc_Rot(0,12,-5),
+	};
+	static const struct BoxDesc frFront = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Dims(1,6,-7, 5,12,-3),
+		BoxDesc_Bounds(0.5f,5.5f,-7.5f, 5.5f,12.5f,-2.5f),
+		BoxDesc_Rot(0,12,-5),
+	};
+	static const struct BoxDesc flBack = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Dims(-5,6,5, -1,12,9),
+		BoxDesc_Bounds(-5.5f,5.5f,4.5f, -0.5f,12.5f,9.5f),
+		BoxDesc_Rot(0,12,7),
+	}; 
+	static const struct BoxDesc frBack = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Dims(1,6,5, 5,12,9),
+		BoxDesc_Bounds(0.5f,5.5f,4.5f, 5.5f,12.5f,9.5f),
+		BoxDesc_Rot(0,12,7),
+	}; 
+
+	BoxDesc_BuildBox(&sheep_head,          &head);
+	BoxDesc_BuildRotatedBox(&sheep_torso,  &torso);
+	BoxDesc_BuildBox(&sheep_leftLegFront,  &lFront);
+	BoxDesc_BuildBox(&sheep_rightLegFront, &rFront);
+	BoxDesc_BuildBox(&sheep_leftLegBack,   &lBack);
+	BoxDesc_BuildBox(&sheep_rightLegBack,  &rBack);
+	
+	BoxDesc_BuildBox(&fur_head,          &fHead);
+	BoxDesc_BuildRotatedBox(&fur_torso,  &fTorso);
+	BoxDesc_BuildBox(&fur_leftLegFront,  &flFront);
+	BoxDesc_BuildBox(&fur_rightLegFront, &frFront);
+	BoxDesc_BuildBox(&fur_leftLegBack,   &flBack);
+	BoxDesc_BuildBox(&fur_rightLegBack,  &frBack);
+}
+
+static void SheepModel_DrawBody(struct Entity* e) {
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &sheep_head, true);
+	Model_DrawPart(&sheep_torso);
+	Model_DrawRotate(e->Anim.LeftLegX,  0, 0, &sheep_leftLegFront,  false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, 0, &sheep_rightLegFront, false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, 0, &sheep_leftLegBack,   false);
+	Model_DrawRotate(e->Anim.LeftLegX,  0, 0, &sheep_rightLegBack,  false);
+}
+
+static void FurlessModel_Draw(struct Entity* e) {
+	Model_ApplyTexture(e);
+	Model_LockVB(e, SHEEP_BODY_VERTICES);
+
+	SheepModel_DrawBody(e);
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(SHEEP_BODY_VERTICES);
+}
+
+static void SheepModel_Draw(struct Entity* e) {
+	Model_ApplyTexture(e);
+	Model_LockVB(e, SHEEP_BODY_VERTICES + SHEEP_FUR_VERTICES);
+
+	SheepModel_DrawBody(e);
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &fur_head, true);
+	Model_DrawPart(&fur_torso);
+	Model_DrawRotate(e->Anim.LeftLegX,  0, 0, &fur_leftLegFront,  false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, 0, &fur_rightLegFront, false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, 0, &fur_leftLegBack,   false);
+	Model_DrawRotate(e->Anim.LeftLegX,  0, 0, &fur_rightLegBack,  false);
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(SHEEP_BODY_VERTICES);
+	Gfx_BindTexture(fur_tex.texID);
+	Gfx_DrawVb_IndexedTris_Range(SHEEP_FUR_VERTICES, SHEEP_BODY_VERTICES);
+}
+
+static float SheepModel_GetNameY(struct Entity* e) { return 1.48125f; }
+static float SheepModel_GetEyeY(struct Entity* e)  { return 20.0f/16.0f; }
+static void SheepModel_GetSize(struct Entity* e)   { Model_RetSize(10.0f,20.0f,10.0f); }
+static void SheepModel_GetBounds(struct Entity* e) { Model_RetAABB(-6,0,-13, 6,23,10); }
+
+static struct ModelVertex sheep_vertices[MODEL_BOX_VERTICES * 6 * 2];
+static struct ModelTex sheep_tex = { "sheep.png" };
+static struct Model sheep_model  = { "sheep", sheep_vertices, &sheep_tex,
+	SheepModel_MakeParts, SheepModel_Draw,
+	SheepModel_GetNameY,  SheepModel_GetEyeY,
+	SheepModel_GetSize,   SheepModel_GetBounds
+};
+static struct Model nofur_model  = { "sheep_nofur", sheep_vertices, &sheep_tex,
+	SheepModel_MakeParts, FurlessModel_Draw,
+	SheepModel_GetNameY,  SheepModel_GetEyeY,
+	SheepModel_GetSize,   SheepModel_GetBounds
+};
+
+static void SheepModel_Register(void) {
+	Model_Init(&sheep_model);
+	sheep_model.maxVertices = SHEEP_BODY_VERTICES + SHEEP_FUR_VERTICES;
+	Model_Register(&sheep_model);
+}
+
+static void NoFurModel_Register(void) {
+	Model_Init(&nofur_model);
+	nofur_model.maxVertices = SHEEP_BODY_VERTICES;
+	Model_Register(&nofur_model);
+}
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------SkeletonModel-----------------------------------------------------*
+*#########################################################################################################################*/
+static struct ModelPart skeleton_head, skeleton_torso, skeleton_leftLeg;
+static struct ModelPart skeleton_rightLeg, skeleton_leftArm, skeleton_rightArm;
+#define SKELETON_MAX_VERTICES (6 * MODEL_BOX_VERTICES)
+
+static void SkeletonModel_MakeParts(void) {
+	static const struct BoxDesc head = {
+		BoxDesc_Tex(0,0),
+		BoxDesc_Box(-4,24,-4, 4,32,4),
+		BoxDesc_Rot(0,24,0),
+	};
+	static const struct BoxDesc torso = {
+		BoxDesc_Tex(16,16),
+		BoxDesc_Box(-4,12,-2, 4,24,2),
+		BoxDesc_Rot(0,12,0),
+	}; 
+	static const struct BoxDesc lLeg = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(-1,0,-1, -3,12,1),
+		BoxDesc_Rot(0,12,0),
+	}; 
+	static const struct BoxDesc rLeg = {
+		BoxDesc_Tex(0,16),
+		BoxDesc_Box(1,0,-1, 3,12,1),
+		BoxDesc_Rot(0,12,0),
+	}; 
+	static const struct BoxDesc lArm = {
+		BoxDesc_Tex(40,16),
+		BoxDesc_Box(-4,12,-1, -6,24,1),
+		BoxDesc_Rot(-5,23,0),
+	}; 
+	static const struct BoxDesc rArm = {
+		BoxDesc_Tex(40,16),
+		BoxDesc_Box(4,12,-1, 6,24,1),
+		BoxDesc_Rot(5,23,0),
+	}; 
+
+	BoxDesc_BuildBox(&skeleton_head,  &head);
+	BoxDesc_BuildBox(&skeleton_torso, &torso);
+	BoxDesc_BuildBox(&skeleton_leftLeg,  &lLeg);
+	BoxDesc_BuildBox(&skeleton_rightLeg, &rLeg);
+	BoxDesc_BuildBox(&skeleton_leftArm,  &lArm);
+	BoxDesc_BuildBox(&skeleton_rightArm, &rArm);
+}
+
+static void SkeletonModel_Draw(struct Entity* e) {
+	Model_ApplyTexture(e);
+	Model_LockVB(e, SKELETON_MAX_VERTICES);
+
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &skeleton_head, true);
+	Model_DrawPart(&skeleton_torso);
+	Model_DrawRotate(e->Anim.LeftLegX,  0, 0,                      &skeleton_leftLeg,  false);
+	Model_DrawRotate(e->Anim.RightLegX, 0, 0,                      &skeleton_rightLeg, false);
+	Model_DrawRotate(90.0f * MATH_DEG2RAD,   0, e->Anim.LeftArmZ,  &skeleton_leftArm,  false);
+	Model_DrawRotate(90.0f * MATH_DEG2RAD,   0, e->Anim.RightArmZ, &skeleton_rightArm, false);
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(SKELETON_MAX_VERTICES);
+}
+
+static void SkeletonModel_DrawArm(struct Entity* e) {
+	Gfx_SetAlphaTest(true);
+	Model_LockVB(e, MODEL_BOX_VERTICES);
+
+	Model_DrawArmPart(&skeleton_rightArm);
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(MODEL_BOX_VERTICES);
+}
+
+static void SkeletonModel_GetSize(struct Entity* e)   { Model_RetSize(8.0f,28.1f,8.0f); }
+static void SkeletonModel_GetBounds(struct Entity* e) { Model_RetAABB(-4,0,-4, 4,32,4); }
+
+static struct ModelVertex skeleton_vertices[MODEL_BOX_VERTICES * 6];
+static struct ModelTex skeleton_tex = { "skeleton.png" };
+static struct Model skeleton_model  = { "skeleton", skeleton_vertices, &skeleton_tex,
+	SkeletonModel_MakeParts, SkeletonModel_Draw,
+	HumanModel_GetNameY,     HumanModel_GetEyeY,
+	SkeletonModel_GetSize,   SkeletonModel_GetBounds
+};
+
+static void SkeletonModel_Register(void) {
+	Model_Init(&skeleton_model);
+	skeleton_model.DrawArm     = SkeletonModel_DrawArm;
+	skeleton_model.armX        = 5;
+	skeleton_model.maxVertices = SKELETON_MAX_VERTICES;
+	Model_Register(&skeleton_model);
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------SpiderModel------------------------------------------------------*
+*#########################################################################################################################*/
+static struct ModelPart spider_head, spider_link, spider_end;
+static struct ModelPart spider_leftLeg, spider_rightLeg;
+#define SPIDER_MAX_VERTICES (11 * MODEL_BOX_VERTICES)
+
+static void SpiderModel_MakeParts(void) {
+	static const struct BoxDesc head = {
+		BoxDesc_Tex(32,4),
+		BoxDesc_Box(-4,4,-11, 4,12,-3),
+		BoxDesc_Rot(0,8,-3),
+	};
+	static const struct BoxDesc link = {
+		BoxDesc_Tex(0,0),
+		BoxDesc_Box(-3,5,3, 3,11,-3),
+		BoxDesc_Rot(0,5,0),
+	}; 
+	static const struct BoxDesc end = {
+		BoxDesc_Tex(0,12),
+		BoxDesc_Box(-5,4,3, 5,12,15),
+		BoxDesc_Rot(0,4,9),
+	}; 
+	static const struct BoxDesc lLeg = {
+		BoxDesc_Tex(18,0),
+		BoxDesc_Box(-19,7,-1, -3,9,1),
+		BoxDesc_Rot(-3,8,0),
+	}; 
+	static const struct BoxDesc rLeg = {
+		BoxDesc_Tex(18,0),
+		BoxDesc_Box(3,7,-1, 19,9,1),
+		BoxDesc_Rot(3,8,0),
+	};
+	
+	BoxDesc_BuildBox(&spider_head, &head);
+	BoxDesc_BuildBox(&spider_link, &link);
+	BoxDesc_BuildBox(&spider_end,  &end);
+	BoxDesc_BuildBox(&spider_leftLeg,  &lLeg);
+	BoxDesc_BuildBox(&spider_rightLeg, &rLeg);
+}
+
+#define quarterPi (MATH_PI / 4.0f)
+#define eighthPi  (MATH_PI / 8.0f)
+
+static void SpiderModel_Draw(struct Entity* e) {
+	float rotX, rotY, rotZ;
+	Model_ApplyTexture(e);
+	Model_LockVB(e, SPIDER_MAX_VERTICES);
+
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &spider_head, true);
+	Model_DrawPart(&spider_link);
+	Model_DrawPart(&spider_end);
+
+	rotX = Math_SinF(e->Anim.WalkTime)     * e->Anim.Swing * MATH_PI;
+	rotZ = Math_CosF(e->Anim.WalkTime * 2) * e->Anim.Swing * MATH_PI / 16.0f;
+	rotY = Math_SinF(e->Anim.WalkTime * 2) * e->Anim.Swing * MATH_PI / 32.0f;
+	Models.Rotation = ROTATE_ORDER_XZY;
+
+	Model_DrawRotate(rotX,  quarterPi  + rotY, eighthPi + rotZ, &spider_leftLeg,  false);
+	Model_DrawRotate(-rotX,  eighthPi  + rotY, eighthPi + rotZ, &spider_leftLeg,  false);
+	Model_DrawRotate(rotX,  -eighthPi  - rotY, eighthPi - rotZ, &spider_leftLeg,  false);
+	Model_DrawRotate(-rotX, -quarterPi - rotY, eighthPi - rotZ, &spider_leftLeg,  false);
+
+	Model_DrawRotate(rotX, -quarterPi + rotY, -eighthPi + rotZ, &spider_rightLeg, false);
+	Model_DrawRotate(-rotX, -eighthPi + rotY, -eighthPi + rotZ, &spider_rightLeg, false);
+	Model_DrawRotate(rotX,   eighthPi - rotY, -eighthPi - rotZ, &spider_rightLeg, false);
+	Model_DrawRotate(-rotX, quarterPi - rotY, -eighthPi - rotZ, &spider_rightLeg, false);
+
+	Models.Rotation = ROTATE_ORDER_ZYX;
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(SPIDER_MAX_VERTICES);
+}
+
+static float SpiderModel_GetNameY(struct Entity* e) { return 1.0125f; }
+static float SpiderModel_GetEyeY(struct Entity* e)  { return 8.0f/16.0f; }
+static void SpiderModel_GetSize(struct Entity* e)   { Model_RetSize(15.0f,12.0f,15.0f); }
+static void SpiderModel_GetBounds(struct Entity* e) { Model_RetAABB(-5,0,-11, 5,12,15); }
+
+static struct ModelVertex spider_vertices[MODEL_BOX_VERTICES * 5];
+static struct ModelTex spider_tex = { "spider.png" };
+static struct Model spider_model  = { "spider", spider_vertices, &spider_tex,
+	SpiderModel_MakeParts, SpiderModel_Draw,
+	SpiderModel_GetNameY,  SpiderModel_GetEyeY,
+	SpiderModel_GetSize,   SpiderModel_GetBounds
+};
+
+static void SpiderModel_Register(void) {
+	Model_Init(&spider_model);
+	spider_model.maxVertices = SPIDER_MAX_VERTICES;
+	Model_Register(&spider_model);
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------ZombieModel------------------------------------------------------*
+*#########################################################################################################################*/
+static void ZombieModel_Draw(struct Entity* e) {
+	e->Anim.LeftArmX  = 90.0f * MATH_DEG2RAD;
+	e->Anim.RightArmX = 90.0f * MATH_DEG2RAD;
+	HumanModel_DrawCore(e, &human_set, false);
+}
+static void ZombieModel_DrawArm(struct Entity* e) {
+	HumanModel_DrawArmCore(e, &human_set);
+}
+
+static void ZombieModel_GetBounds(struct Entity* e) { Model_RetAABB(-4,0,-4, 4,32,4); }
+
+static struct ModelTex zombie_tex = { "zombie.png" };
+static struct Model zombie_model  = { "zombie", human_vertices, &zombie_tex,
+	Model_NoParts,       ZombieModel_Draw,
+	HumanModel_GetNameY, HumanModel_GetEyeY, 
+	HumanModel_GetSize,  ZombieModel_GetBounds 
+};
+
+static void ZombieModel_Register(void) {
+	Model_Init(&zombie_model);
+	zombie_model.DrawArm     = ZombieModel_DrawArm;
+	zombie_model.maxVertices = HUMAN_MAX_VERTICES;
+	Model_Register(&zombie_model);
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------BlockModel------------------------------------------------------*
+*#########################################################################################################################*/
+#define BLOCKMODEL_SPRITE_COUNT (8 * 4)
+#define BLOCKMODEL_CUBE_COUNT   (6 * 4)
+#define BLOCKMODEL_MAX_VERTICES BLOCKMODEL_SPRITE_COUNT
+
+static BlockID bModel_block = BLOCK_AIR;
+static int bModel_index, bModel_texIndices[8];
+static struct VertexTextured* bModel_vertices;
+
+static float BlockModel_GetNameY(struct Entity* e) {
+	BlockID block = e->ModelBlock;
+	return Blocks.MaxBB[block].y + 0.075f;
+}
+
+static float BlockModel_GetEyeY(struct Entity* e) {
+	BlockID block = e->ModelBlock;
+	float minY    = Blocks.MinBB[block].y;
+	float maxY    = Blocks.MaxBB[block].y;
+	return (minY + maxY) / 2.0f;
+}
+
+static void BlockModel_GetSize(struct Entity* e) {
+	static Vec3 shrink = { 0.75f/16.0f, 0.75f/16.0f, 0.75f/16.0f };
+	Vec3* size = &e->Size;
+	BlockID block = e->ModelBlock;
+
+	Vec3_Sub(size, &Blocks.MaxBB[block], &Blocks.MinBB[block]);
+	/* to fit slightly inside */
+	Vec3_SubBy(size, &shrink);
+
+	/* fix for 0 size blocks */
+	size->x = max(size->x, 0.125f/16.0f);
+	size->y = max(size->y, 0.125f/16.0f);
+	size->z = max(size->z, 0.125f/16.0f);
+}
+
+static void BlockModel_GetBounds(struct Entity* e) {
+	static Vec3 offset = { -0.5f, 0.0f, -0.5f };
+	BlockID block = e->ModelBlock;
+
+	Vec3_Add(&e->ModelAABB.Min, &Blocks.MinBB[block], &offset);
+	Vec3_Add(&e->ModelAABB.Max, &Blocks.MaxBB[block], &offset);
+}
+
+static TextureLoc BlockModel_GetTex(Face face) {
+	TextureLoc loc = Block_Tex(bModel_block, face);
+	bModel_texIndices[bModel_index++] = Atlas1D_Index(loc);
+	return loc;
+}
+
+static void BlockModel_SpriteZQuad(cc_bool firstPart, cc_bool mirror) {
+	struct VertexTextured* ptr, v;
+	PackedCol col; int tmp;
+	float xz1, xz2;
+	TextureLoc loc = BlockModel_GetTex(FACE_ZMAX);
+	TextureRec rec = Atlas1D_TexRec(loc, 1, &tmp);
+
+	col = Models.Cols[0];
+	Block_Tint(col, bModel_block);
+
+	xz1 = 0.0f; xz2 = 0.0f;
+	if (firstPart) { /* Need to break into two quads for when drawing a sprite model in hand. */
+		if (mirror) { rec.u1 = 0.5f; xz1 = -5.5f/16.0f; }
+		else {        rec.u2 = 0.5f; xz2 = -5.5f/16.0f; }
+	} else {
+		if (mirror) { rec.u2 = 0.5f; xz2 =  5.5f/16.0f; }
+		else {        rec.u1 = 0.5f; xz1 =  5.5f/16.0f; }
+	}
+
+	ptr   = bModel_vertices;
+	v.Col = col;
+
+	v.x = xz1; v.y = 0.0f; v.z = xz1; v.U = rec.u2; v.V = rec.v2; *ptr++ = v;
+	           v.y = 1.0f;                          v.V = rec.v1; *ptr++ = v;
+	v.x = xz2;             v.z = xz2; v.U = rec.u1;               *ptr++ = v;
+	           v.y = 0.0f;                          v.V = rec.v2; *ptr++ = v;
+
+	bModel_vertices = ptr;
+}
+
+static void BlockModel_SpriteXQuad(cc_bool firstPart, cc_bool mirror) {
+	struct VertexTextured* ptr, v;
+	PackedCol col; int tmp;
+	float x1, x2, z1, z2;
+	TextureLoc loc = BlockModel_GetTex(FACE_XMAX);
+	TextureRec rec = Atlas1D_TexRec(loc, 1, &tmp);
+
+	col = Models.Cols[0];
+	Block_Tint(col, bModel_block);
+
+	x1 = 0.0f; x2 = 0.0f; z1 = 0.0f; z2 = 0.0f;
+	if (firstPart) {
+		if (mirror) { rec.u2 = 0.5f; x2 = -5.5f/16.0f; z2 =  5.5f/16.0f; }
+		else {        rec.u1 = 0.5f; x1 = -5.5f/16.0f; z1 =  5.5f/16.0f; }
+	} else {
+		if (mirror) { rec.u1 = 0.5f; x1 =  5.5f/16.0f; z1 = -5.5f/16.0f; }
+		else {        rec.u2 = 0.5f; x2 =  5.5f/16.0f; z2 = -5.5f/16.0f; }
+	}
+
+	ptr   = bModel_vertices;
+	v.Col = col;
+
+	v.x = x1; v.y = 0.0f; v.z = z1; v.U = rec.u2; v.V = rec.v2; *ptr++ = v;
+	          v.y = 1.0f;                         v.V = rec.v1; *ptr++ = v;
+	v.x = x2;             v.z = z2; v.U = rec.u1;               *ptr++ = v;
+	          v.y = 0.0f;                         v.V = rec.v2; *ptr++ = v;
+
+	bModel_vertices = ptr;
+}
+
+static void BlockModel_BuildParts(struct Entity* e, cc_bool sprite) {
+	struct VertexTextured* ptr;
+	Vec3 min, max;
+	TextureLoc loc;
+
+	Model_LockVB(e, sprite ? BLOCKMODEL_SPRITE_COUNT : BLOCKMODEL_CUBE_COUNT);
+	ptr = Models.Vertices;
+
+	if (sprite) {
+		bModel_vertices = ptr;
+
+		BlockModel_SpriteXQuad(false, false);
+		BlockModel_SpriteXQuad(false, true);
+		BlockModel_SpriteZQuad(false, false);
+		BlockModel_SpriteZQuad(false, true);
+
+		BlockModel_SpriteZQuad(true, false);
+		BlockModel_SpriteZQuad(true, true);
+		BlockModel_SpriteXQuad(true, false);
+		BlockModel_SpriteXQuad(true, true);
+	} else {
+		Drawer.MinBB = Blocks.MinBB[bModel_block]; Drawer.MinBB.y = 1.0f - Drawer.MinBB.y;
+		Drawer.MaxBB = Blocks.MaxBB[bModel_block]; Drawer.MaxBB.y = 1.0f - Drawer.MaxBB.y;
+		Drawer.Tinted  = Blocks.Tinted[bModel_block];
+		Drawer.TintCol = Blocks.FogCol[bModel_block];
+
+		min = Blocks.RenderMinBB[bModel_block];
+		max = Blocks.RenderMaxBB[bModel_block];
+
+		Drawer.X1 = min.x - 0.5f; Drawer.Y1 = min.y; Drawer.Z1 = min.z - 0.5f;
+		Drawer.X2 = max.x - 0.5f; Drawer.Y2 = max.y; Drawer.Z2 = max.z - 0.5f;		
+
+		loc = BlockModel_GetTex(FACE_YMIN); Drawer_YMin(1, Models.Cols[1], loc, &ptr);
+		loc = BlockModel_GetTex(FACE_ZMIN); Drawer_ZMin(1, Models.Cols[3], loc, &ptr);
+		loc = BlockModel_GetTex(FACE_XMAX); Drawer_XMax(1, Models.Cols[5], loc, &ptr);
+		loc = BlockModel_GetTex(FACE_ZMAX); Drawer_ZMax(1, Models.Cols[2], loc, &ptr);
+		loc = BlockModel_GetTex(FACE_XMIN); Drawer_XMin(1, Models.Cols[4], loc, &ptr);
+		loc = BlockModel_GetTex(FACE_YMAX); Drawer_YMax(1, Models.Cols[0], loc, &ptr);
+	}
+
+	Model_UnlockVB();
+}
+
+static void BlockModel_DrawParts(void) {
+	int lastTexIndex, i, offset = 0, count = 0;
+
+	lastTexIndex = bModel_texIndices[0];
+	for (i = 0; i < bModel_index; i++, count += 4) {
+		if (bModel_texIndices[i] == lastTexIndex) continue;
+
+		/* Different 1D flush texture, flush current vertices */
+		Gfx_BindTexture(Atlas1D.TexIds[lastTexIndex]);
+		Gfx_DrawVb_IndexedTris_Range(count, offset);
+		lastTexIndex = bModel_texIndices[i];
+			
+		offset += count;
+		count   = 0;
+	}
+
+	/* Leftover vertices */
+	if (!count) return;
+	Gfx_BindTexture(Atlas1D.TexIds[lastTexIndex]); 
+	Gfx_DrawVb_IndexedTris_Range(count, offset);
+}
+
+static void BlockModel_Draw(struct Entity* e) {
+	cc_bool sprite;
+	int i;
+
+	bModel_block = e->ModelBlock;
+	bModel_index = 0;
+	if (Blocks.Draw[bModel_block] == DRAW_GAS) return;
+
+	if (Blocks.Brightness[bModel_block]) {
+		for (i = 0; i < FACE_COUNT; i++)
+		{
+			Models.Cols[i] = PACKEDCOL_WHITE;
+		}
+	}
+
+	sprite = Blocks.Draw[bModel_block] == DRAW_SPRITE;
+	BlockModel_BuildParts(e, sprite);
+
+	if (sprite) Gfx_SetFaceCulling(true);
+	BlockModel_DrawParts();
+	if (sprite) Gfx_SetFaceCulling(false);
+}
+
+static struct Model block_model = { "block", NULL, &human_tex,
+	Model_NoParts,       BlockModel_Draw,
+	BlockModel_GetNameY, BlockModel_GetEyeY,
+	BlockModel_GetSize,  BlockModel_GetBounds,
+};
+
+static void BlockModel_Register(void) {
+	Model_Init(&block_model);
+	block_model.bobbing     = false;
+	block_model.usesSkin    = false;
+	block_model.pushes      = false;
+	block_model.maxVertices = BLOCKMODEL_MAX_VERTICES;
+	Model_Register(&block_model);
+	Models.Block = &block_model;
+}
+
+
+/*########################################################################################################################*
+*----------------------------------------------------------SkinnedCubeModel-----------------------------------------------*
+*#########################################################################################################################*/
+static struct ModelPart skinnedCube_head;
+#define SKINNEDCUBE_MAX_VERTICES (1 * MODEL_BOX_VERTICES)
+
+static void SkinnedCubeModel_MakeParts(void) {
+	static const struct BoxDesc head = {
+		BoxDesc_Tex(0,0),
+		BoxDesc_Box(-8,0,-8, 8,16,8),
+		BoxDesc_Rot(0,8,0),
+	};
+
+	BoxDesc_BuildBox(&skinnedCube_head, &head);
+}
+
+static void SkinnedCubeModel_Draw(struct Entity* e) {
+	Model_ApplyTexture(e);
+	Model_LockVB(e, SKINNEDCUBE_MAX_VERTICES);
+
+	Model_DrawRotate(-e->Pitch * MATH_DEG2RAD, 0, 0, &skinnedCube_head, true);
+
+	Model_UnlockVB();
+	Gfx_DrawVb_IndexedTris(SKINNEDCUBE_MAX_VERTICES);
+}
+
+static float SkinnedCubeModel_GetNameY(struct Entity* e) { return 1.075f; }
+static float SkinnedCubeModel_GetEyeY(struct Entity* e) { return 8.0f / 16.0f; }
+static void SkinnedCubeModel_GetSize(struct Entity* e) { Model_RetSize(15.0f, 15.0f, 15.0f); }
+static void SkinnedCubeModel_GetBounds(struct Entity* e) { Model_RetAABB(-8, 0, -8, 8, 16, 8); }
+
+static struct ModelVertex skinnedCube_vertices[MODEL_BOX_VERTICES];
+static struct ModelTex skinnedCube_tex = { "skinnedcube.png" };
+static struct Model skinnedCube_model = { "skinnedcube", skinnedCube_vertices, &skinnedCube_tex,
+	SkinnedCubeModel_MakeParts, SkinnedCubeModel_Draw,
+	SkinnedCubeModel_GetNameY,  SkinnedCubeModel_GetEyeY,
+	SkinnedCubeModel_GetSize,   SkinnedCubeModel_GetBounds
+};
+
+static void SkinnedCubeModel_Register(void) {
+	Model_Init(&skinnedCube_model);
+	skinnedCube_model.usesHumanSkin = true;
+	skinnedCube_model.pushes        = false;
+	skinnedCube_model.maxVertices   = SKINNEDCUBE_MAX_VERTICES;
+	Model_Register(&skinnedCube_model);
+}
+
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------HoldModel-------------------------------------------------------*
+*#########################################################################################################################*/
+static void RecalcProperties(struct Entity* e) {
+	// Calculate block ID based on the X scale of the model
+	// E.g, hold|1.001 = stone (ID = 1), hold|1.041 = gold (ID = 41) etc.
+	BlockID block = (BlockID)((e->ModelScale.x - 0.9999f) * 1000);
+
+	if (block > 0) {
+		// Change the block that the player is holding
+		if (block < BLOCK_COUNT) e->ModelBlock = block;
+		else e->ModelBlock = BLOCK_AIR;
+
+		Vec3_Set(e->ModelScale, 1, 1, 1);
+		Entity_UpdateModelBounds(e); // Adjust size/modelAABB after changing model scale
+	}
+}
+
+static void DrawBlockTransform(struct Entity* e, float dispX, float dispY, float dispZ, float scale) {
+	static Vec3 pos;
+	static struct Matrix m, temp;
+
+	pos = e->Position;
+	pos.y += e->Anim.BobbingModel;
+
+	Entity_GetTransform(e, pos, e->ModelScale, &m);
+	Matrix_Mul(&m, &m, &Gfx.View);
+	Matrix_Translate(&temp, dispX, dispY, dispZ);
+	Matrix_Mul(&m, &temp, &m);
+	Matrix_Scale(&temp, scale / 1.5f, scale / 1.5f, scale / 1.5f);
+	Matrix_Mul(&m, &temp, &m);
+
+	Model_SetupState(&block_model, e);
+	Gfx_LoadMatrix(MATRIX_VIEW, &m);
+	block_model.Draw(e);
+}
+
+static void HoldModel_Draw(struct Entity* e) {
+	float handBob;
+	float handIdle;
+	RecalcProperties(e);
+
+	handBob  = Math_SinF(e->Anim.WalkTime * 2.0f) * e->Anim.Swing * MATH_PI / 16.0f;
+	handIdle = e->Anim.RightArmX * (1.0f - e->Anim.Swing);
+
+	e->Anim.RightArmX = 0.5f + handBob + handIdle;
+	e->Anim.RightArmZ = 0;
+
+	Model_SetupState(Models.Human, e);
+	HumanModel_Draw(e);
+
+	DrawBlockTransform(e, 0.33F, (MATH_PI / 3 + handBob + handIdle) * 10 / 16 + 0.127f, -7.0f / 16, 0.5f);
+}
+
+static struct Model hold_model;
+
+static float HoldModel_GetEyeY(struct Entity* e) {
+	RecalcProperties(e);
+	return HumanModel_GetEyeY(e);
+}
+
+static void HoldModel_Register(void) {
+	hold_model = human_model;
+	hold_model.name = "hold";
+	hold_model.MakeParts = Model_NoParts;
+	hold_model.Draw      = HoldModel_Draw;
+	hold_model.GetEyeY   = HoldModel_GetEyeY;
+	Model_Register(&hold_model);
+}
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------Models component--------------------------------------------------*
+*#########################################################################################################################*/
+static void RegisterDefaultModels(void) {
+	Model_RegisterTexture(&human_tex);
+	Model_RegisterTexture(&chicken_tex);
+	Model_RegisterTexture(&creeper_tex);
+	Model_RegisterTexture(&pig_tex);
+	Model_RegisterTexture(&sheep_tex);
+	Model_RegisterTexture(&fur_tex);
+	Model_RegisterTexture(&skeleton_tex);
+	Model_RegisterTexture(&spider_tex);
+	Model_RegisterTexture(&zombie_tex);
+	Model_RegisterTexture(&skinnedCube_tex);
+
+	HumanoidModel_Register();
+	MakeModel(&human_model);
+	Models.Human = &human_model;
+	BlockModel_Register();
+
+	ChickenModel_Register();
+	CreeperModel_Register();
+	PigModel_Register();
+	SheepModel_Register();
+	NoFurModel_Register();
+	SkeletonModel_Register();
+	SpiderModel_Register();
+	ZombieModel_Register();
+
+	ChibiModel_Register();
+	HeadModel_Register();
+	SittingModel_Register();
+	CorpseModel_Register();
+	SkinnedCubeModel_Register();
+	HoldModel_Register();
+}
+
+static void OnContextLost(void* obj) {
+	struct ModelTex* tex;
+	Gfx_DeleteDynamicVb(&Models.Vb);
+	if (Gfx.ManagedTextures) return;
+
+	for (tex = textures_head; tex; tex = tex->next) 
+	{
+		Gfx_DeleteTexture(&tex->texID);
+	}
+}
+
+static void OnInit(void) {
+	Models.MaxVertices = MODELS_MAX_VERTICES;
+	RegisterDefaultModels();
+	Models.ClassicArms = Options_GetBool(OPT_CLASSIC_ARM_MODEL, Game_ClassicMode);
+
+	Event_Register_(&TextureEvents.FileChanged, NULL, Models_TextureChanged);
+	Event_Register_(&GfxEvents.ContextLost,     NULL, OnContextLost);
+}
+
+static void OnFree(void) {
+	OnContextLost(NULL);
+	CustomModel_FreeAll();
+}
+
+static void OnReset(void) { CustomModel_FreeAll(); }
+
+struct IGameComponent Models_Component = {
+	OnInit,  /* Init  */
+	OnFree,  /* Free  */
+	OnReset, /* Reset */
+};