Latest compatible version of Classicube from the original GitHub repository (https://github.com/ClassiCube/ClassiCube) that can be compiled on Classicube for PowerMac PPC running Mac OS X 10.4.
This commit is contained in:
275
src/HeldBlockRenderer.c
Normal file
275
src/HeldBlockRenderer.c
Normal file
@@ -0,0 +1,275 @@
|
||||
#include "HeldBlockRenderer.h"
|
||||
#include "Block.h"
|
||||
#include "Game.h"
|
||||
#include "Inventory.h"
|
||||
#include "Graphics.h"
|
||||
#include "Camera.h"
|
||||
#include "ExtMath.h"
|
||||
#include "Event.h"
|
||||
#include "Entity.h"
|
||||
#include "Model.h"
|
||||
#include "Options.h"
|
||||
|
||||
cc_bool HeldBlockRenderer_Show;
|
||||
#ifndef CC_DISABLE_HELDBLOCK
|
||||
static BlockID held_block;
|
||||
static struct Entity held_entity;
|
||||
static struct Matrix held_blockProj;
|
||||
|
||||
static cc_bool held_animating, held_breaking, held_swinging;
|
||||
static float held_swingY;
|
||||
static float held_time, held_period = 0.25f;
|
||||
static BlockID held_lastBlock;
|
||||
|
||||
/* Since not using Entity_SetModel, which normally automatically does this */
|
||||
static void SetHeldModel(struct Model* model) {
|
||||
#ifdef CC_BUILD_CONSOLE
|
||||
static int maxVertices;
|
||||
if (model->maxVertices <= maxVertices) return;
|
||||
|
||||
maxVertices = model->maxVertices;
|
||||
Gfx_DeleteDynamicVb(&held_entity.ModelVB);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void HeldBlockRenderer_RenderModel(void) {
|
||||
struct Model* model;
|
||||
|
||||
Gfx_SetFaceCulling(true);
|
||||
Gfx_SetDepthTest(false);
|
||||
/* Gfx_SetDepthWrite(false); */
|
||||
/* TODO: Need to properly reallocate per model VB here */
|
||||
|
||||
if (Blocks.Draw[held_block] == DRAW_GAS) {
|
||||
model = Entities.CurPlayer->Base.Model;
|
||||
SetHeldModel(model);
|
||||
Vec3_Set(held_entity.ModelScale, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
Model_RenderArm(model, &held_entity);
|
||||
Gfx_SetAlphaTest(false);
|
||||
}
|
||||
else {
|
||||
model = Models.Block;
|
||||
SetHeldModel(model);
|
||||
Vec3_Set(held_entity.ModelScale, 0.4f, 0.4f, 0.4f);
|
||||
|
||||
Gfx_SetupAlphaState(Blocks.Draw[held_block]);
|
||||
Model_Render(model, &held_entity);
|
||||
Gfx_RestoreAlphaState(Blocks.Draw[held_block]);
|
||||
}
|
||||
|
||||
Gfx_SetDepthTest(true);
|
||||
/* Gfx_SetDepthWrite(true); */
|
||||
Gfx_SetFaceCulling(false);
|
||||
}
|
||||
|
||||
static void SetMatrix(void) {
|
||||
struct Entity* p = &Entities.CurPlayer->Base;
|
||||
struct Matrix lookAt;
|
||||
Vec3 eye = { 0,0,0 }; eye.y = Entity_GetEyeHeight(p);
|
||||
|
||||
Matrix_Translate(&lookAt, -eye.x, -eye.y, -eye.z);
|
||||
Matrix_Mul(&Gfx.View, &lookAt, &Camera.TiltM);
|
||||
}
|
||||
|
||||
static void ResetHeldState(void) {
|
||||
/* Based off details from http://pastebin.com/KFV0HkmD (Thanks goodlyay!) */
|
||||
struct Entity* p = &Entities.CurPlayer->Base;
|
||||
Vec3 eye = { 0,0,0 }; eye.y = Entity_GetEyeHeight(p);
|
||||
held_entity.Position = eye;
|
||||
|
||||
held_entity.Position.x -= Camera.BobbingHor;
|
||||
held_entity.Position.y -= Camera.BobbingVer;
|
||||
held_entity.Position.z -= Camera.BobbingHor;
|
||||
|
||||
held_entity.Yaw = -45.0f; held_entity.RotY = -45.0f;
|
||||
held_entity.Pitch = 0.0f; held_entity.RotX = 0.0f;
|
||||
held_entity.ModelBlock = held_block;
|
||||
|
||||
held_entity.SkinType = p->SkinType;
|
||||
held_entity.TextureId = p->TextureId;
|
||||
held_entity.MobTextureId = p->MobTextureId;
|
||||
held_entity.uScale = p->uScale;
|
||||
held_entity.vScale = p->vScale;
|
||||
}
|
||||
|
||||
static void SetBaseOffset(void) {
|
||||
cc_bool sprite = Blocks.Draw[held_block] == DRAW_SPRITE;
|
||||
Vec3 normalOffset = { 0.56f, -0.72f, -0.72f };
|
||||
Vec3 spriteOffset = { 0.46f, -0.52f, -0.72f };
|
||||
Vec3 offset = sprite ? spriteOffset : normalOffset;
|
||||
|
||||
Vec3_AddBy(&held_entity.Position, &offset);
|
||||
if (!sprite && Blocks.Draw[held_block] != DRAW_GAS) {
|
||||
float height = Blocks.MaxBB[held_block].y - Blocks.MinBB[held_block].y;
|
||||
held_entity.Position.y += 0.2f * (1.0f - height);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnProjectionChanged(void* obj) {
|
||||
float fov = 70.0f * MATH_DEG2RAD;
|
||||
float aspectRatio = (float)Game.Width / (float)Game.Height;
|
||||
Gfx_CalcPerspectiveMatrix(&held_blockProj, fov, aspectRatio, (float)Game_ViewDistance);
|
||||
}
|
||||
|
||||
/* Based off incredible gifs from (Thanks goodlyay!)
|
||||
https://dl.dropboxusercontent.com/s/iuazpmpnr89zdgb/slowBreakTranslate.gif
|
||||
https://dl.dropboxusercontent.com/s/z7z8bset914s0ij/slowBreakRotate1.gif
|
||||
https://dl.dropboxusercontent.com/s/pdq79gkzntquld1/slowBreakRotate2.gif
|
||||
https://dl.dropboxusercontent.com/s/w1ego7cy7e5nrk1/slowBreakFull.gif
|
||||
|
||||
https://github.com/ClassiCube/ClassicalSharp/wiki/Dig-animation-details
|
||||
*/
|
||||
static void HeldBlockRenderer_DigAnimation(void) {
|
||||
float sinHalfCircle, sinHalfCircleWeird;
|
||||
float t, sqrtLerpPI;
|
||||
|
||||
t = held_time / held_period;
|
||||
sinHalfCircle = Math_SinF(t * MATH_PI);
|
||||
sqrtLerpPI = Math_SqrtF(t) * MATH_PI;
|
||||
|
||||
held_entity.Position.x -= Math_SinF(sqrtLerpPI) * 0.4f;
|
||||
held_entity.Position.y += Math_SinF(sqrtLerpPI * 2) * 0.2f;
|
||||
held_entity.Position.z -= sinHalfCircle * 0.2f;
|
||||
|
||||
sinHalfCircleWeird = Math_SinF(t * t * MATH_PI);
|
||||
held_entity.RotY -= Math_SinF(sqrtLerpPI) * 80.0f;
|
||||
held_entity.Yaw -= Math_SinF(sqrtLerpPI) * 80.0f;
|
||||
held_entity.RotX += sinHalfCircleWeird * 20.0f;
|
||||
}
|
||||
|
||||
static void HeldBlockRenderer_ResetAnim(cc_bool setLastHeld, float period) {
|
||||
held_time = 0.0f; held_swingY = 0.0f;
|
||||
held_animating = false; held_swinging = false;
|
||||
held_period = period;
|
||||
if (setLastHeld) { held_lastBlock = Inventory_SelectedBlock; }
|
||||
}
|
||||
|
||||
static PackedCol HeldBlockRenderer_GetCol(struct Entity* entity) {
|
||||
struct Entity* player;
|
||||
PackedCol col;
|
||||
float adjPitch, t, scale;
|
||||
|
||||
player = &Entities.CurPlayer->Base;
|
||||
col = player->VTABLE->GetCol(player);
|
||||
|
||||
/* Adjust pitch so angle when looking straight down is 0. */
|
||||
adjPitch = player->Pitch - 90.0f;
|
||||
if (adjPitch < 0.0f) adjPitch += 360.0f;
|
||||
|
||||
/* Adjust color so held block is brighter when looking straight up */
|
||||
t = Math_AbsF(adjPitch - 180.0f) / 180.0f;
|
||||
scale = Math_Lerp(0.9f, 0.7f, t);
|
||||
return PackedCol_Scale(col, scale);
|
||||
}
|
||||
|
||||
void HeldBlockRenderer_ClickAnim(cc_bool digging) {
|
||||
/* TODO: timing still not quite right, rotate2 still not quite right */
|
||||
HeldBlockRenderer_ResetAnim(true, digging ? 0.35 : 0.25);
|
||||
held_swinging = false;
|
||||
held_breaking = digging;
|
||||
held_animating = true;
|
||||
/* Start place animation at bottom of cycle */
|
||||
if (!digging) held_time = held_period / 2;
|
||||
}
|
||||
|
||||
static void DoSwitchBlockAnim(void* obj) {
|
||||
if (held_swinging) {
|
||||
/* Like graph -sin(x) : x=0.5 and x=2.5 have same y values,
|
||||
but increasing x causes y to change in opposite directions */
|
||||
if (held_time > held_period * 0.5f) {
|
||||
held_time = held_period - held_time;
|
||||
}
|
||||
} else {
|
||||
if (held_block == Inventory_SelectedBlock) return;
|
||||
HeldBlockRenderer_ResetAnim(false, 0.25);
|
||||
held_animating = true;
|
||||
held_swinging = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnBlockChanged(void* obj, IVec3 coords, BlockID old, BlockID now) {
|
||||
if (now == BLOCK_AIR) return;
|
||||
HeldBlockRenderer_ClickAnim(false);
|
||||
}
|
||||
|
||||
static void DoAnimation(float delta, float lastSwingY) {
|
||||
float t;
|
||||
if (!held_animating) return;
|
||||
|
||||
if (held_swinging || !held_breaking) {
|
||||
t = held_time / held_period;
|
||||
held_swingY = -0.4f * Math_SinF(t * MATH_PI);
|
||||
held_entity.Position.y += held_swingY;
|
||||
|
||||
if (held_swinging) {
|
||||
/* i.e. the block has gone to bottom of screen and is now returning back up.
|
||||
At this point we switch over to the new held block. */
|
||||
if (held_swingY > lastSwingY) held_lastBlock = held_block;
|
||||
held_block = held_lastBlock;
|
||||
held_entity.ModelBlock = held_block;
|
||||
}
|
||||
} else {
|
||||
HeldBlockRenderer_DigAnimation();
|
||||
}
|
||||
|
||||
held_time += delta;
|
||||
if (held_time > held_period) {
|
||||
HeldBlockRenderer_ResetAnim(true, 0.25f);
|
||||
}
|
||||
}
|
||||
|
||||
void HeldBlockRenderer_Render(float delta) {
|
||||
float lastSwingY;
|
||||
struct Matrix view;
|
||||
if (!HeldBlockRenderer_Show) return;
|
||||
|
||||
lastSwingY = held_swingY;
|
||||
held_swingY = 0.0f;
|
||||
held_block = Inventory_SelectedBlock;
|
||||
view = Gfx.View;
|
||||
|
||||
Gfx_LoadMatrix(MATRIX_PROJ, &held_blockProj);
|
||||
SetMatrix();
|
||||
|
||||
ResetHeldState();
|
||||
DoAnimation(delta, lastSwingY);
|
||||
SetBaseOffset();
|
||||
if (!Camera.Active->isThirdPerson) HeldBlockRenderer_RenderModel();
|
||||
|
||||
Gfx.View = view;
|
||||
Gfx_LoadMatrix(MATRIX_PROJ, &Gfx.Projection);
|
||||
}
|
||||
|
||||
|
||||
static void OnContextLost(void* obj) {
|
||||
Gfx_DeleteDynamicVb(&held_entity.ModelVB);
|
||||
}
|
||||
|
||||
static const struct EntityVTABLE heldEntity_VTABLE = {
|
||||
NULL, NULL, NULL, HeldBlockRenderer_GetCol,
|
||||
NULL, NULL
|
||||
};
|
||||
static void OnInit(void) {
|
||||
Entity_Init(&held_entity);
|
||||
held_entity.VTABLE = &heldEntity_VTABLE;
|
||||
held_entity.NoShade = true;
|
||||
|
||||
HeldBlockRenderer_Show = Options_GetBool(OPT_SHOW_BLOCK_IN_HAND, true);
|
||||
held_lastBlock = Inventory_SelectedBlock;
|
||||
|
||||
Event_Register_(&GfxEvents.ProjectionChanged, NULL, OnProjectionChanged);
|
||||
Event_Register_(&UserEvents.HeldBlockChanged, NULL, DoSwitchBlockAnim);
|
||||
Event_Register_(&UserEvents.BlockChanged, NULL, OnBlockChanged);
|
||||
Event_Register_(&GfxEvents.ContextLost, NULL, OnContextLost);
|
||||
}
|
||||
#else
|
||||
void HeldBlockRenderer_ClickAnim(cc_bool digging) { }
|
||||
void HeldBlockRenderer_Render(float delta) { }
|
||||
|
||||
static void OnInit(void) { }
|
||||
#endif
|
||||
|
||||
struct IGameComponent HeldBlockRenderer_Component = {
|
||||
OnInit /* Init */
|
||||
};
|
||||
Reference in New Issue
Block a user