diff --git a/src/Model.c b/src/Model.c index 4d8a8c4bd..62de9bf49 100644 --- a/src/Model.c +++ b/src/Model.c @@ -551,78 +551,182 @@ static void CustomModel_MakeParts(void) { } } +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: + return ( Math_SinF((float)Game.Time * anim->a + 2 * MATH_PI * anim->c) + anim->d ) * anim->b; + + case CustomModelAnimType_SinRotateVelocity: + case CustomModelAnimType_SinTranslateVelocity: + return ( Math_SinF(e->Anim.WalkTime * anim->a + 2 * MATH_PI * 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 ( + anim->type == CustomModelAnimType_SinTranslate || + anim->type == CustomModelAnimType_SinTranslateVelocity + ) { + if (!modifiedVertices) { + modifiedVertices = true; + Mem_Copy( + oldVertices, + &cm->model.vertices[part->modelPart.offset], + sizeof(struct ModelVertex) * MODEL_BOX_VERTICES + ); + } + + for (i = 0; i < MODEL_BOX_VERTICES; i++) { + switch (anim->axis) { + case CustomModelAnimAxis_X: + cm->model.vertices[part->modelPart.offset + i].X += value; + break; + + case CustomModelAnimAxis_Y: + cm->model.vertices[part->modelPart.offset + i].Y += value; + break; + + case CustomModelAnimAxis_Z: + cm->model.vertices[part->modelPart.offset + i].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) { - int i, j; struct CustomModel* cm = (struct CustomModel*)Models.Active; + int partIndex; Model_ApplyTexture(e); Models.uScale = 1.0f / cm->uScale; Models.vScale = 1.0f / cm->vScale; - for (i = 0; i < cm->numParts; i++) { - float rotX, rotY, rotZ; - cc_bool head; - struct CustomModelPart* part = &cm->parts[i]; - - if (part->fullbright) { - for (j = 0; j < FACE_COUNT; j++) { - oldCols[j] = Models.Cols[j]; - Models.Cols[j] = 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; - head = false; - - if (part->anim == CustomModelAnim_Head) { - head = true; - rotX += -e->Pitch * MATH_DEG2RAD; - } else if (part->anim == CustomModelAnim_LeftLeg) { - rotX += e->Anim.LeftLegX; - rotZ += e->Anim.LeftLegZ; - } else if (part->anim == CustomModelAnim_RightLeg) { - rotX += e->Anim.RightLegX; - rotZ += e->Anim.RightLegZ; - } else if (part->anim == CustomModelAnim_LeftArm) { - /* TODO: we're using 2 different rotation orders here */ - Models.Rotation = ROTATE_ORDER_XZY; - rotX += e->Anim.LeftArmX; - rotZ += e->Anim.LeftArmZ; - } else if (part->anim == CustomModelAnim_RightArm) { - Models.Rotation = ROTATE_ORDER_XZY; - rotX += e->Anim.RightArmX; - rotZ += e->Anim.RightArmZ; - } else if (part->anim == CustomModelAnim_SpinX) { - rotX += (float)(Game.Time * part->animModifier); - } else if (part->anim == CustomModelAnim_SpinY) { - rotY += (float)(Game.Time * part->animModifier); - } else if (part->anim == CustomModelAnim_SpinZ) { - rotZ += (float)(Game.Time * part->animModifier); - } else if (part->anim == CustomModelAnim_SpinXVelocity) { - rotX += e->Anim.WalkTime * part->animModifier; - } else if (part->anim == CustomModelAnim_SpinYVelocity) { - rotY += e->Anim.WalkTime * part->animModifier; - } else if (part->anim == CustomModelAnim_SpinZVelocity) { - rotZ += e->Anim.WalkTime * part->animModifier; - } - - if (rotX || rotY || rotZ || head) { - Model_DrawRotate(rotX, rotY, rotZ, &cm->parts[i].modelPart, head); - } else { - Model_DrawPart(&cm->parts[i].modelPart); - } - - if (part->fullbright) { - for (j = 0; j < FACE_COUNT; j++) { - Models.Cols[j] = oldCols[j]; - } - } + for (partIndex = 0; partIndex < cm->numParts; partIndex++) { + CustomModel_DrawPart(&cm->parts[partIndex], cm, e); } Model_UpdateVB(); diff --git a/src/Model.h b/src/Model.h index 2219c1863..ba87fa6d2 100644 --- a/src/Model.h +++ b/src/Model.h @@ -211,20 +211,35 @@ CC_API void BoxDesc_ZQuad2(struct Model* m, float x1, float x2, float y1, float #define MAX_CUSTOM_MODELS 64 #define MAX_CUSTOM_MODEL_PARTS 64 +#define MAX_CUSTOM_MODEL_ANIMS 4 -enum CustomModelAnim { - CustomModelAnim_None = 0, - CustomModelAnim_Head = 1, - CustomModelAnim_LeftLeg = 2, - CustomModelAnim_RightLeg = 3, - CustomModelAnim_LeftArm = 4, - CustomModelAnim_RightArm = 5, - CustomModelAnim_SpinX = 6, - CustomModelAnim_SpinY = 7, - CustomModelAnim_SpinZ = 8, - CustomModelAnim_SpinXVelocity = 9, - CustomModelAnim_SpinYVelocity = 10, - CustomModelAnim_SpinZVelocity = 11 +enum CustomModelAnimType { + CustomModelAnimType_None = 0, + CustomModelAnimType_Head = 1, + CustomModelAnimType_LeftLegX = 2, + CustomModelAnimType_RightLegX = 3, + CustomModelAnimType_LeftArmX = 4, + CustomModelAnimType_LeftArmZ = 5, + CustomModelAnimType_RightArmX = 6, + CustomModelAnimType_RightArmZ = 7, + CustomModelAnimType_Spin = 8, + CustomModelAnimType_SpinVelocity = 9, + CustomModelAnimType_SinRotate = 10, + CustomModelAnimType_SinRotateVelocity = 11, + CustomModelAnimType_SinTranslate = 12, + CustomModelAnimType_SinTranslateVelocity = 13 +}; + +enum CustomModelAnimAxis { + CustomModelAnimAxis_X = 0, + CustomModelAnimAxis_Y = 1, + CustomModelAnimAxis_Z = 2, +}; + +struct CustomModelAnim { + cc_uint8 type; + cc_uint8 axis; + float a, b, c, d; }; struct CustomModelPart { @@ -245,8 +260,7 @@ struct CustomModelPart { /* rotation angles */ Vec3 rotation; - float animModifier; - cc_uint8 anim; + struct CustomModelAnim anims[MAX_CUSTOM_MODEL_ANIMS]; cc_bool fullbright; cc_bool firstPersonArm; diff --git a/src/Protocol.c b/src/Protocol.c index 39fdf2f38..c32313637 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -60,7 +60,7 @@ static struct MapState map2; /* CPE state */ cc_bool cpe_needD3Fix; static int cpe_serverExtensionsCount, cpe_pingTicks; -static int cpe_envMapVer = 2, cpe_blockDefsExtVer = 2; +static int cpe_envMapVer = 2, cpe_blockDefsExtVer = 2, cpe_customModelsVer = 2; static cc_bool cpe_sendHeldBlock, cpe_useMessageTypes, cpe_extEntityPos, cpe_blockPerms, cpe_fastMap; static cc_bool cpe_twoWayPing, cpe_extTextures, cpe_extBlocks; @@ -851,6 +851,7 @@ static void CPE_SendCpeExtInfoReply(void) { if (String_CaselessEqualsConst(&name, "ExtPlayerList")) ver = 2; if (String_CaselessEqualsConst(&name, "EnvMapAppearance")) ver = cpe_envMapVer; if (String_CaselessEqualsConst(&name, "BlockDefinitionsExt")) ver = cpe_blockDefsExtVer; + if (String_CaselessEqualsConst(&name, "CustomModels")) ver = cpe_customModelsVer; if (!Game_AllowCustomBlocks) { if (String_CaselessEqualsConst(&name, "BlockDefinitionsExt")) continue; @@ -924,6 +925,11 @@ static void CPE_ExtEntry(cc_uint8* data) { } else if (String_CaselessEqualsConst(&ext, "FastMap")) { Net_PacketSizes[OPCODE_LEVEL_BEGIN] += 4; cpe_fastMap = true; + } else if (String_CaselessEqualsConst(&ext, "CustomModels")) { + cpe_customModelsVer = min(2, version); + if (version == 2) { + Net_PacketSizes[OPCODE_DEFINE_MODEL_PART] = 167; + } } #ifdef EXTENDED_TEXTURES else if (String_CaselessEqualsConst(&ext, "ExtendedTextures")) { @@ -1521,12 +1527,26 @@ static void CPE_DefineModelPart(cc_uint8* data) { part->rotation.Z = GetFloat(data); data += 4; - /* read anim */ - part->anim = *data++; + if (cpe_customModelsVer == 1) { + /* ignore animations */ + data++; + data += 4; + } else if (cpe_customModelsVer == 2) { + for (i = 0; i < MAX_CUSTOM_MODEL_ANIMS; i++) { + cc_uint8 tmp = *data++; + part->anims[i].type = tmp & 0x3F; + part->anims[i].axis = tmp >> 6; - /* read animModifier */ - part->animModifier = GetFloat(data); - data += 4; + part->anims[i].a = GetFloat(data); + data += 4; + part->anims[i].b = GetFloat(data); + data += 4; + part->anims[i].c = GetFloat(data); + data += 4; + part->anims[i].d = GetFloat(data); + data += 4; + } + } /* read bool flags */ flags = *data++; @@ -1548,7 +1568,7 @@ static void CPE_UndefineModel(cc_uint8* data) { static void CPE_Reset(void) { cpe_serverExtensionsCount = 0; cpe_pingTicks = 0; cpe_sendHeldBlock = false; cpe_useMessageTypes = false; - cpe_envMapVer = 2; cpe_blockDefsExtVer = 2; + cpe_envMapVer = 2; cpe_blockDefsExtVer = 2; cpe_customModelsVer = 2; cpe_needD3Fix = false; cpe_extEntityPos = false; cpe_twoWayPing = false; cpe_extTextures = false; cpe_fastMap = false; cpe_extBlocks = false; Game_UseCPEBlocks = false;