#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 */ };