diff options
author | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
---|---|---|
committer | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
commit | abef6da56913f1c55528103e60a50451a39628b1 (patch) | |
tree | b3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/HeldBlockRenderer.c |
initial commit
Diffstat (limited to 'src/HeldBlockRenderer.c')
-rw-r--r-- | src/HeldBlockRenderer.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/src/HeldBlockRenderer.c b/src/HeldBlockRenderer.c new file mode 100644 index 0000000..93511c3 --- /dev/null +++ b/src/HeldBlockRenderer.c @@ -0,0 +1,267 @@ +#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; +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/UnknownShadow200/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_PROJECTION, &held_blockProj); + SetMatrix(); + + ResetHeldState(); + DoAnimation(delta, lastSwingY); + SetBaseOffset(); + if (!Camera.Active->isThirdPerson) HeldBlockRenderer_RenderModel(); + + Gfx.View = view; + Gfx_LoadMatrix(MATRIX_PROJECTION, &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); +} + +struct IGameComponent HeldBlockRenderer_Component = { + OnInit /* Init */ +}; |