From 80b3b82332e66257ffd48e2bc303d63d94bcd58d Mon Sep 17 00:00:00 2001 From: falsycat Date: Fri, 9 Oct 2020 00:00:00 +0000 Subject: [PATCH] [RELEASE] u22-v04 This version is submitted for U22 final presentation. (squashed 158 commits) --- .gitignore | 2 + .gitmodules | 5 +- CMakeLists.txt | 28 +- LICENSE | 361 ++++++++ README.md | 39 + app/CMakeLists.txt | 2 + app/sdl/CMakeLists.txt | 2 +- app/sdl/args.c | 3 - app/sdl/event.c | 6 +- app/sdl/main.c | 13 +- cmake/anysrc.cmake | 7 +- cmake/benum.cmake | 29 + cmake/crial.cmake | 19 + cmake/sos.cmake | 16 +- core/CMakeLists.txt | 6 +- core/lobullet/CMakeLists.txt | 8 +- core/lobullet/base.c | 186 ++--- core/lobullet/base.crial | 44 + core/lobullet/base.h | 71 +- core/lobullet/bomb.c | 205 ----- core/lobullet/bomb.h | 82 -- core/lobullet/linear.c | 217 ++--- core/lobullet/linear.h | 96 +-- core/lobullet/misc.c | 37 - core/lobullet/misc.h | 31 - core/lobullet/pool.c | 81 +- core/lobullet/pool.h | 14 +- core/lobullet/type.h | 11 + core/lochara/CMakeLists.txt | 37 + core/lochara/base.c | 333 ++++++++ core/lochara/base.crial | 60 ++ core/lochara/base.h | 116 +++ core/lochara/big_warder.c | 728 ++++++++++++++++ core/lochara/big_warder.h | 18 + core/lochara/cavia.c | 305 +++++++ core/lochara/cavia.h | 19 + core/lochara/combat.c | 79 ++ core/lochara/combat.h | 51 ++ core/lochara/encephalon.c | 85 ++ core/lochara/encephalon.h | 18 + core/lochara/player.c | 492 +++++++++++ core/lochara/player.h | 15 + core/lochara/pool.c | 58 ++ core/lochara/pool.h | 46 + core/lochara/state.c | 179 ++++ core/lochara/state.h | 233 ++++++ core/lochara/strategy.c | 184 ++++ core/lochara/strategy.h | 131 +++ core/lochara/theists_child.c | 718 ++++++++++++++++ core/lochara/theists_child.h | 18 + core/lochara/type.h | 18 + core/lochara/warder.c | 370 ++++++++ core/lochara/warder.h | 19 + core/locharacter/CMakeLists.txt | 27 - core/locharacter/base.c | 434 ---------- core/locharacter/base.h | 100 --- core/locharacter/big_warder.c | 787 ----------------- core/locharacter/big_warder.h | 37 - core/locharacter/big_warder.private.h | 157 ---- core/locharacter/cavia.c | 265 ------ core/locharacter/cavia.h | 36 - core/locharacter/encephalon.c | 138 --- core/locharacter/encephalon.h | 34 - core/locharacter/greedy_scientist.c | 607 -------------- core/locharacter/greedy_scientist.h | 37 - core/locharacter/greedy_scientist.private.h | 228 ----- core/locharacter/misc.c | 68 -- core/locharacter/misc.h | 76 -- core/locharacter/pool.c | 122 --- core/locharacter/pool.h | 48 -- core/locharacter/scientist.c | 305 ------- core/locharacter/scientist.h | 34 - core/locharacter/theists_child.c | 763 ----------------- core/locharacter/theists_child.h | 37 - core/locharacter/theists_child.private.h | 150 ---- core/locharacter/util.c | 139 ---- core/locharacter/util.h | 54 -- core/locharacter/warder.c | 299 ------- core/locharacter/warder.h | 33 - core/locommon/CMakeLists.txt | 4 + core/locommon/counter.c | 6 + core/locommon/counter.h | 5 + core/locommon/input.h | 19 +- core/locommon/msgpack.h | 98 ++- core/locommon/screen.c | 94 +++ core/locommon/screen.h | 57 ++ core/locommon/ticker.c | 6 +- core/locommon/ticker.h | 1 + core/loeffect/CMakeLists.txt | 4 +- core/loeffect/effect.c | 7 - core/loeffect/effect.h | 69 +- core/loeffect/generic.c | 6 +- core/loeffect/generic.h | 2 +- core/loeffect/recipient.c | 155 ++-- core/loeffect/recipient.crial | 31 + core/loeffect/recipient.h | 58 +- core/loeffect/stance.c | 143 ---- core/loeffect/stance.h | 84 -- core/loentity/CMakeLists.txt | 1 + core/loentity/character.h | 2 + core/loentity/entity.h | 1 + core/loentity/pool.h | 64 ++ core/loentity/store.c | 2 + core/loground/CMakeLists.txt | 7 +- core/loground/base.c | 166 +--- core/loground/base.crial | 31 + core/loground/base.h | 14 +- core/loground/island.c | 6 +- core/loground/island.h | 10 - core/loground/misc.h | 25 - core/loground/pool.c | 54 +- core/loground/type.h | 10 + core/loparticle/CMakeLists.txt | 19 + core/loparticle/aura.c | 66 ++ core/loparticle/aura.crial | 13 + core/loparticle/aura.h | 51 ++ core/loparticle/base.c | 165 ++++ core/loparticle/base.crial | 31 + core/loparticle/base.h | 59 ++ core/{loground => loparticle}/misc.c | 18 +- core/loparticle/misc.h | 25 + core/loparticle/pool.c | 45 + core/loparticle/pool.h | 40 + core/loplayer/CMakeLists.txt | 20 +- core/loplayer/action.c | 880 -------------------- core/loplayer/action.h | 64 -- core/loplayer/camera.c | 266 +----- core/loplayer/camera.h | 81 +- core/loplayer/combat.c | 572 +++---------- core/loplayer/combat.h | 134 +-- core/loplayer/controller.c | 98 ++- core/loplayer/controller.h | 51 +- core/loplayer/entity.c | 311 ------- core/loplayer/entity.h | 93 --- core/loplayer/event.c | 225 ++--- core/loplayer/event.crial | 15 + core/loplayer/event.h | 163 +++- core/loplayer/hud.c | 409 --------- core/loplayer/hud.h | 53 -- core/loplayer/menu.c | 565 ------------- core/loplayer/menu.h | 86 -- core/loplayer/player.c | 246 +----- core/loplayer/player.crial | 14 + core/loplayer/player.h | 89 +- core/loplayer/popup.c | 53 ++ core/loplayer/popup.h | 48 ++ core/loplayer/stance.c | 103 +++ core/loplayer/stance.h | 81 ++ core/loplayer/status.c | 193 ----- core/loplayer/status.h | 87 -- core/loresource/CMakeLists.txt | 5 +- core/loresource/font.c | 4 +- core/loresource/music.c | 118 ++- core/loresource/music.h | 50 +- core/loresource/set.c | 12 +- core/loresource/set.h | 6 +- core/loresource/sound.c | 275 +++--- core/loresource/sound.h | 72 +- core/loresource/text/jp.h | 27 +- core/loscene/CMakeLists.txt | 2 + core/loscene/context.c | 52 +- core/loscene/context.h | 33 +- core/loscene/game.c | 307 ++++--- core/loscene/game.h | 13 +- core/loscene/param.h | 5 - core/loscene/title.c | 166 ++-- core/loscene/title.h | 11 +- core/loshader/CMakeLists.txt | 9 + core/loshader/backwall.c | 97 +-- core/loshader/backwall.h | 32 +- core/loshader/bullet.c | 168 +--- core/loshader/bullet.h | 38 +- core/loshader/character.c | 188 ++--- core/loshader/character.h | 48 +- core/loshader/character.vshader | 4 + core/loshader/cinescope.c | 96 +-- core/loshader/cinescope.h | 33 +- core/loshader/combat_ring.c | 167 +--- core/loshader/combat_ring.h | 42 +- core/loshader/event_line.c | 87 +- core/loshader/event_line.h | 62 +- core/loshader/fog.c | 99 +-- core/loshader/fog.fshader | 2 +- core/loshader/fog.h | 31 +- core/loshader/ground.c | 160 +--- core/loshader/ground.h | 39 +- core/loshader/hud_bar.c | 172 +--- core/loshader/hud_bar.h | 40 +- core/loshader/hud_text.c | 87 +- core/loshader/hud_text.h | 58 +- core/loshader/instanced.c | 92 ++ core/loshader/instanced.h | 55 ++ core/loshader/menu_background.c | 85 +- core/loshader/menu_background.h | 39 +- core/loshader/menu_stance.c | 168 +--- core/loshader/menu_stance.h | 44 +- core/loshader/menu_stance.vshader | 4 +- core/loshader/menu_text.c | 87 +- core/loshader/menu_text.h | 56 +- core/loshader/particle.c | 99 +++ core/loshader/particle.fshader | 9 + core/loshader/particle.h | 52 ++ core/loshader/particle.vshader | 17 + core/loshader/pixsort.c | 90 +- core/loshader/pixsort.fshader | 2 +- core/loshader/pixsort.h | 42 +- core/loshader/popup_text.c | 44 + core/loshader/popup_text.fshader | 35 + core/loshader/popup_text.h | 36 + core/loshader/popup_text.vshader | 43 + core/loshader/posteffect.c | 141 ++-- core/loshader/posteffect.fshader | 112 +-- core/loshader/posteffect.h | 53 +- core/loshader/set.c | 211 ++--- core/loshader/set.h | 68 +- core/loshader/single.c | 91 ++ core/loshader/single.h | 48 ++ core/loshader/text.c | 55 ++ core/loshader/text.h | 44 + core/loshader/uniblock.c | 63 +- core/loshader/uniblock.h | 27 +- core/loui/CMakeLists.txt | 19 + core/loui/combat.c | 127 +++ core/loui/combat.h | 41 + core/loui/event.c | 117 +++ core/loui/event.h | 50 ++ core/loui/hud.c | 319 +++++++ core/loui/hud.h | 96 +++ core/loui/menu.c | 366 ++++++++ core/loui/menu.h | 86 ++ core/loui/popup.c | 137 +++ core/loui/popup.h | 61 ++ core/loui/ui.c | 130 +++ core/loui/ui.h | 63 ++ core/loworld/CMakeLists.txt | 8 +- core/loworld/chunk.c | 30 - core/loworld/chunk.h | 25 +- core/loworld/environment.c | 129 +-- core/loworld/environment.h | 8 +- core/loworld/poolset.c | 85 +- core/loworld/poolset.h | 35 +- core/loworld/store.c | 9 +- core/loworld/store.h | 3 + core/loworld/template.c | 178 ++-- core/loworld/test.h | 146 ---- thirdparty/CMakeLists.txt | 5 + thirdparty/miniaudio/CMakeLists.txt | 21 +- thirdparty/miniaudio/miniaudio.c | 2 - thirdparty/miniaudio/miniaudio.h | 10 - thirdparty/tinycthread | 1 + tool/benum.sh | 141 ++++ tool/bin2c.sh | 15 +- tool/crial.sh | 89 ++ tool/leak-check.sh | 24 +- util/CMakeLists.txt | 4 + util/flasy/CMakeLists.txt | 18 + util/flasy/README.md | 4 + util/flasy/flasy.c | 146 ++++ util/flasy/flasy.h | 34 + util/flasy/test.c | 46 + util/gleasy/atlas.c | 5 +- util/glyphas/CMakeLists.txt | 2 +- util/glyphas/drawer.c | 102 +-- util/glyphas/drawer.h | 28 +- util/glyphas/face.c | 18 +- util/glyphas/test.c | 16 +- util/jukebox/composite.c | 2 +- util/jukebox/decoder.c | 2 +- util/jukebox/delay.c | 2 +- util/jukebox/mixer.c | 2 +- util/jukebox/sound.c | 2 +- util/math/algorithm.h | 3 +- util/statman/CMakeLists.txt | 9 + util/statman/README.md | 4 + util/statman/statman.c | 89 ++ util/statman/statman.h | 47 ++ util/statman/test.c | 160 ++++ 277 files changed, 12154 insertions(+), 13836 deletions(-) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 cmake/benum.cmake create mode 100644 cmake/crial.cmake create mode 100644 core/lobullet/base.crial delete mode 100644 core/lobullet/bomb.c delete mode 100644 core/lobullet/bomb.h delete mode 100644 core/lobullet/misc.c delete mode 100644 core/lobullet/misc.h create mode 100644 core/lobullet/type.h create mode 100644 core/lochara/CMakeLists.txt create mode 100644 core/lochara/base.c create mode 100644 core/lochara/base.crial create mode 100644 core/lochara/base.h create mode 100644 core/lochara/big_warder.c create mode 100644 core/lochara/big_warder.h create mode 100644 core/lochara/cavia.c create mode 100644 core/lochara/cavia.h create mode 100644 core/lochara/combat.c create mode 100644 core/lochara/combat.h create mode 100644 core/lochara/encephalon.c create mode 100644 core/lochara/encephalon.h create mode 100644 core/lochara/player.c create mode 100644 core/lochara/player.h create mode 100644 core/lochara/pool.c create mode 100644 core/lochara/pool.h create mode 100644 core/lochara/state.c create mode 100644 core/lochara/state.h create mode 100644 core/lochara/strategy.c create mode 100644 core/lochara/strategy.h create mode 100644 core/lochara/theists_child.c create mode 100644 core/lochara/theists_child.h create mode 100644 core/lochara/type.h create mode 100644 core/lochara/warder.c create mode 100644 core/lochara/warder.h delete mode 100644 core/locharacter/CMakeLists.txt delete mode 100644 core/locharacter/base.c delete mode 100644 core/locharacter/base.h delete mode 100644 core/locharacter/big_warder.c delete mode 100644 core/locharacter/big_warder.h delete mode 100644 core/locharacter/big_warder.private.h delete mode 100644 core/locharacter/cavia.c delete mode 100644 core/locharacter/cavia.h delete mode 100644 core/locharacter/encephalon.c delete mode 100644 core/locharacter/encephalon.h delete mode 100644 core/locharacter/greedy_scientist.c delete mode 100644 core/locharacter/greedy_scientist.h delete mode 100644 core/locharacter/greedy_scientist.private.h delete mode 100644 core/locharacter/misc.c delete mode 100644 core/locharacter/misc.h delete mode 100644 core/locharacter/pool.c delete mode 100644 core/locharacter/pool.h delete mode 100644 core/locharacter/scientist.c delete mode 100644 core/locharacter/scientist.h delete mode 100644 core/locharacter/theists_child.c delete mode 100644 core/locharacter/theists_child.h delete mode 100644 core/locharacter/theists_child.private.h delete mode 100644 core/locharacter/util.c delete mode 100644 core/locharacter/util.h delete mode 100644 core/locharacter/warder.c delete mode 100644 core/locharacter/warder.h create mode 100644 core/locommon/screen.c create mode 100644 core/locommon/screen.h create mode 100644 core/loeffect/recipient.crial delete mode 100644 core/loeffect/stance.c delete mode 100644 core/loeffect/stance.h create mode 100644 core/loentity/pool.h create mode 100644 core/loground/base.crial delete mode 100644 core/loground/misc.h create mode 100644 core/loground/type.h create mode 100644 core/loparticle/CMakeLists.txt create mode 100644 core/loparticle/aura.c create mode 100644 core/loparticle/aura.crial create mode 100644 core/loparticle/aura.h create mode 100644 core/loparticle/base.c create mode 100644 core/loparticle/base.crial create mode 100644 core/loparticle/base.h rename core/{loground => loparticle}/misc.c (57%) create mode 100644 core/loparticle/misc.h create mode 100644 core/loparticle/pool.c create mode 100644 core/loparticle/pool.h delete mode 100644 core/loplayer/action.c delete mode 100644 core/loplayer/action.h delete mode 100644 core/loplayer/entity.c delete mode 100644 core/loplayer/entity.h create mode 100644 core/loplayer/event.crial delete mode 100644 core/loplayer/hud.c delete mode 100644 core/loplayer/hud.h delete mode 100644 core/loplayer/menu.c delete mode 100644 core/loplayer/menu.h create mode 100644 core/loplayer/player.crial create mode 100644 core/loplayer/popup.c create mode 100644 core/loplayer/popup.h create mode 100644 core/loplayer/stance.c create mode 100644 core/loplayer/stance.h delete mode 100644 core/loplayer/status.c delete mode 100644 core/loplayer/status.h create mode 100644 core/loshader/instanced.c create mode 100644 core/loshader/instanced.h create mode 100644 core/loshader/particle.c create mode 100644 core/loshader/particle.fshader create mode 100644 core/loshader/particle.h create mode 100644 core/loshader/particle.vshader create mode 100644 core/loshader/popup_text.c create mode 100644 core/loshader/popup_text.fshader create mode 100644 core/loshader/popup_text.h create mode 100644 core/loshader/popup_text.vshader create mode 100644 core/loshader/single.c create mode 100644 core/loshader/single.h create mode 100644 core/loshader/text.c create mode 100644 core/loshader/text.h create mode 100644 core/loui/CMakeLists.txt create mode 100644 core/loui/combat.c create mode 100644 core/loui/combat.h create mode 100644 core/loui/event.c create mode 100644 core/loui/event.h create mode 100644 core/loui/hud.c create mode 100644 core/loui/hud.h create mode 100644 core/loui/menu.c create mode 100644 core/loui/menu.h create mode 100644 core/loui/popup.c create mode 100644 core/loui/popup.h create mode 100644 core/loui/ui.c create mode 100644 core/loui/ui.h delete mode 100644 core/loworld/test.h delete mode 100644 thirdparty/miniaudio/miniaudio.c delete mode 100644 thirdparty/miniaudio/miniaudio.h create mode 160000 thirdparty/tinycthread create mode 100755 tool/benum.sh create mode 100755 tool/crial.sh create mode 100644 util/flasy/CMakeLists.txt create mode 100644 util/flasy/README.md create mode 100644 util/flasy/flasy.c create mode 100644 util/flasy/flasy.h create mode 100644 util/flasy/test.c create mode 100644 util/statman/CMakeLists.txt create mode 100644 util/statman/README.md create mode 100644 util/statman/statman.c create mode 100644 util/statman/statman.h create mode 100644 util/statman/test.c diff --git a/.gitignore b/.gitignore index 6ec76ed..f158e8f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /.build +/.rbuild +*.swp diff --git a/.gitmodules b/.gitmodules index 29a5cfe..b7b16a3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "thirdparty/miniaudio"] path = thirdparty/miniaudio/repo - url = https://github.com/dr-soft/miniaudio + url = https://github.com/mackron/miniaudio +[submodule "thirdparty/tinycthread"] + path = thirdparty/tinycthread + url = https://github.com/tinycthread/tinycthread diff --git a/CMakeLists.txt b/CMakeLists.txt index a0f467a..516fd2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,35 +2,37 @@ cmake_minimum_required(VERSION 3.16) project(leftone C) -if (BUILD_TESTING) - enable_testing() -endif() +include(CTest) +set(LEFTONE_C_FLAGS + -Werror -Wall -Wextra -Wno-missing-field-initializers + $<$:-Wno-unused-parameter> + $<$:-mconsole> +) set(LEFTONE_TOOL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tool") -set(CMAKE_C_FLAGS - "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-missing-field-initializers") -set(CMAKE_C_FLAGS_RELEASE - "${CMAKE_C_FLAGS_RELEASE} -Wno-unused-parameter") - -if (WIN32) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mconsole") -endif() - find_package(Freetype REQUIRED) find_package(GLEW REQUIRED) find_package(OpenGL REQUIRED) find_package(SDL2 REQUIRED) find_package(msgpack REQUIRED) +set(SDL2_TARGET SDL2::SDL2) +if (NOT TARGET SDL2::SDL2) + set(SDL2_TARGET ${SDL2_LIBRARIES}) +endif() + include_directories(SYSTEM ${FREETYPE_INCLUDE_DIRS} ${GLEW_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} + ${SDL2_INCLUDE_DIRS} ) -include_directories(.) +include_directories(. ${CMAKE_CURRENT_BINARY_DIR}) include(cmake/anysrc.cmake) +include(cmake/benum.cmake) +include(cmake/crial.cmake) include(cmake/sos.cmake) add_subdirectory(app) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..46c8191 --- /dev/null +++ b/LICENSE @@ -0,0 +1,361 @@ +Creative Commons Legal Code + +Attribution-NonCommercial-ShareAlike 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(g) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "License Elements" means the following high-level license attributes + as selected by Licensor and indicated in the title of this License: + Attribution, Noncommercial, ShareAlike. + e. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + f. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + g. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + h. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + i. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + j. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved, including but not limited to the +rights described in Section 4(e). + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(d), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(d), as requested. + b. You may Distribute or Publicly Perform an Adaptation only under: (i) + the terms of this License; (ii) a later version of this License with + the same License Elements as this License; (iii) a Creative Commons + jurisdiction license (either this or a later license version) that + contains the same License Elements as this License (e.g., + Attribution-NonCommercial-ShareAlike 3.0 US) ("Applicable License"). + You must include a copy of, or the URI, for Applicable License with + every copy of each Adaptation You Distribute or Publicly Perform. You + may not offer or impose any terms on the Adaptation that restrict the + terms of the Applicable License or the ability of the recipient of the + Adaptation to exercise the rights granted to that recipient under the + terms of the Applicable License. You must keep intact all notices that + refer to the Applicable License and to the disclaimer of warranties + with every copy of the Work as included in the Adaptation You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Adaptation, You may not impose any effective technological + measures on the Adaptation that restrict the ability of a recipient of + the Adaptation from You to exercise the rights granted to that + recipient under the terms of the Applicable License. This Section 4(b) + applies to the Adaptation as incorporated in a Collection, but this + does not require the Collection apart from the Adaptation itself to be + made subject to the terms of the Applicable License. + c. You may not exercise any of the rights granted to You in Section 3 + above in any manner that is primarily intended for or directed toward + commercial advantage or private monetary compensation. The exchange of + the Work for other copyrighted works by means of digital file-sharing + or otherwise shall not be considered to be intended for or directed + toward commercial advantage or private monetary compensation, provided + there is no payment of any monetary compensation in con-nection with + the exchange of copyrighted works. + d. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and, (iv) consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4(d) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor reserves + the exclusive right to collect such royalties for any exercise by + You of the rights granted under this License if Your exercise of + such rights is for a purpose or use which is otherwise than + noncommercial as permitted under Section 4(c) and otherwise waives + the right to collect royalties through any statutory or compulsory + licensing scheme; and, + iii. Voluntary License Schemes. The Licensor reserves the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License that is for a + purpose or use which is otherwise than noncommercial as permitted + under Section 4(c). + f. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING AND TO THE +FULLEST EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK AS-IS +AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE +WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT +LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, +ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT +DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED +WARRANTIES, SO THIS EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. + + Creative Commons may be contacted at https://creativecommons.org/. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..ee86da1 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# LEFTONE + +LEFTONE is 2d action game got a prize on [2020 U22 Programming Contest](https://u22procon.com) + +I'm noob at composing so don't expect the BGM quality. :( + +## AUTHOR + +falsycat +[portfolio](https://falsy.cat/) | [twitter](https://twitter.com/falsycat) + +## LICENSE + +***CC-BY-NC-SA-3.0*** + +### Libraries + +- [freetype2](https://www.freetype.org/index.html) - FreeType License +- [glew](http://glew.sourceforge.net) - Modified BSD License +- [miniaudio](https://github.com/mackron/miniaudio) - public domain +- [msgpack-c](https://github.com/msgpack/msgpack-c) - Boost Software License +- [SDL2](https://www.libsdl.org/index.php) - zlib License +- [tinycthread](https://github.com/tinycthread/tinycthread) - zlib License + +### Resources + +- [Otologic](https://otologic.jp) - CC-BY-4.0 +- [99sounds](https://99sounds.org) - [license](https://99sounds.org/license/) + - They replied me it's no problem to put their works on GitHub. +- [minimized Noto Font](https://github.com/hirofumii/Noto-Sans-CJK-JP.min) - SIL OPEN FONT LICENSE + +### Why CC? + +Because some of my shaders are inspired by the followings on ShaderToy, whose default license is CC-BY-NC-SA-3.0. +***YOU HAD BETTER NOT OPEN THESE LINKS BY POOR MACHINES.*** + +- [fractal cage - gaz](https://www.shadertoy.com/view/3l2yDd) +- [Ray Marching: Part 2 - jlfwong](https://www.shadertoy.com/view/lt33z7) +- [Raymarching - Primitives - iq](https://www.shadertoy.com/view/Xds3zN) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 0340b1a..7b876ea 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1 +1,3 @@ +add_compile_options(${LEFTONE_C_FLAGS}) + add_subdirectory(sdl) diff --git a/app/sdl/CMakeLists.txt b/app/sdl/CMakeLists.txt index a3a7805..5d21d9a 100644 --- a/app/sdl/CMakeLists.txt +++ b/app/sdl/CMakeLists.txt @@ -5,7 +5,7 @@ add_executable(app-sdl ) target_link_libraries(app-sdl GLEW::GLEW - SDL2::SDL2 + ${SDL2_TARGET} conv parsarg diff --git a/app/sdl/args.c b/app/sdl/args.c index 86de299..4ef65c3 100644 --- a/app/sdl/args.c +++ b/app/sdl/args.c @@ -75,9 +75,6 @@ void app_args_parse(app_args_t* args, int argc, char** argv) { bool_("skip-title", args->scene.skip_title); - bool_("test-poolset-packing", args->scene.test.loworld_poolset_packing); - bool_("test-player-packing", args->scene.test.loplayer_packing); - /* ---- app parameters ---- */ int_("max-fps", args->max_fps, 1, INT32_MAX); diff --git a/app/sdl/event.c b/app/sdl/event.c index 05be8bd..522d4aa 100644 --- a/app/sdl/event.c +++ b/app/sdl/event.c @@ -10,15 +10,13 @@ #define APP_EVENT_GET_BUTTON_BIT_FROM_KEY(k) ( \ (k) == SDLK_a? LOCOMMON_INPUT_BUTTON_LEFT: \ (k) == SDLK_d? LOCOMMON_INPUT_BUTTON_RIGHT: \ - (k) == SDLK_w? LOCOMMON_INPUT_BUTTON_UP: \ - (k) == SDLK_s? LOCOMMON_INPUT_BUTTON_DOWN: \ (k) == SDLK_SPACE? LOCOMMON_INPUT_BUTTON_JUMP: \ - (k) == SDLK_LSHIFT? LOCOMMON_INPUT_BUTTON_DASH: \ + (k) == SDLK_LSHIFT? LOCOMMON_INPUT_BUTTON_DODGE: \ (k) == SDLK_ESCAPE? LOCOMMON_INPUT_BUTTON_MENU: \ 0) #define APP_EVENT_GET_BUTTON_BIT_FROM_MOUSE(m) ( \ - (m) == SDL_BUTTON_LEFT? LOCOMMON_INPUT_BUTTON_ATTACK: \ + (m) == SDL_BUTTON_LEFT? LOCOMMON_INPUT_BUTTON_SHOOT: \ (m) == SDL_BUTTON_RIGHT? LOCOMMON_INPUT_BUTTON_GUARD: \ 0) diff --git a/app/sdl/main.c b/app/sdl/main.c index f0f92ae..c7d5e2c 100644 --- a/app/sdl/main.c +++ b/app/sdl/main.c @@ -3,7 +3,9 @@ #include #include +#include #include +#include #include #include @@ -128,7 +130,8 @@ int main(int argc, char** argv) { app_get_dpi_(&libs, &args); - loscene_context_t* ctx = loscene_context_new(&args.scene); + loscene_context_t ctx; + loscene_context_initialize(&ctx, &args.scene); locommon_input_t input = { .resolution = vec2(args.scene.width, args.scene.height), @@ -147,10 +150,10 @@ int main(int argc, char** argv) { if (!app_event_handle(&input, &e)) goto EXIT; } - if (!loscene_context_update(ctx, &input, base_time)) goto EXIT; + if (!loscene_context_update(&ctx, &input, base_time)) goto EXIT; glClear(GL_COLOR_BUFFER_BIT); - loscene_context_draw(ctx); + loscene_context_draw(&ctx); SDL_GL_SwapWindow(libs.win); # ifndef NDEBUG @@ -166,7 +169,7 @@ int main(int argc, char** argv) { } EXIT: - loscene_context_delete(ctx); + loscene_context_deinitialize(&ctx); app_deinitialize_libraries_(&libs); - return 0; + return EXIT_SUCCESS; } diff --git a/cmake/anysrc.cmake b/cmake/anysrc.cmake index 517d757..71df7db 100644 --- a/cmake/anysrc.cmake +++ b/cmake/anysrc.cmake @@ -1,8 +1,6 @@ function(target_any_sources target) set(bin2c ${LEFTONE_TOOL_DIR}/bin2c.sh) - target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - foreach (path ${ARGN}) get_filename_component(dirname ${path} DIRECTORY) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/anysrc/${dirname}) @@ -12,9 +10,10 @@ function(target_any_sources target) set(out ${CMAKE_CURRENT_BINARY_DIR}/anysrc/${path}) add_custom_command( OUTPUT ${out}.c ${out}.h - COMMAND cat ${in} | ${bin2c} ${name} ${out} + COMMAND cat ${in} | bash ${bin2c} ${name} ${out} DEPENDS ${path} ${bin2c} - COMMENT "converting ${path} to C header") + COMMENT "converting ${path} to C header" + VERBATIM) target_sources(${target} PRIVATE ${out}.c ${out}.h) endforeach() endfunction() diff --git a/cmake/benum.cmake b/cmake/benum.cmake new file mode 100644 index 0000000..4b6431a --- /dev/null +++ b/cmake/benum.cmake @@ -0,0 +1,29 @@ +add_custom_target(benum-generated) + +function(target_benum_sources target) + set(benum ${LEFTONE_TOOL_DIR}/benum.sh) + + set(output_files "") + foreach (path ${ARGN}) + get_filename_component(dirname ${path} DIRECTORY) + get_filename_component(basename ${path} NAME_WE) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/benum/${dirname}) + + set(in ${CMAKE_CURRENT_SOURCE_DIR}/${path}) + set(out ${CMAKE_CURRENT_BINARY_DIR}/benum/${dirname}/${basename}) + add_custom_command( + OUTPUT ${out}.c ${out}.h + COMMAND bash ${benum} ${out} ${in} < ${in} + DEPENDS ${path} ${benum} + COMMENT "generating benum utilities for ${path}" + VERBATIM) + target_sources(${target} PRIVATE ${out}.c) + + list(APPEND output_files ${out}.c ${out}.h) + endforeach() + + add_custom_target(${target}-benum-generated DEPENDS ${output_files}) + add_dependencies(${target} ${target}-benum-generated) + add_dependencies(benum-generated ${target}-benum-generated) + +endfunction() diff --git a/cmake/crial.cmake b/cmake/crial.cmake new file mode 100644 index 0000000..f942e75 --- /dev/null +++ b/cmake/crial.cmake @@ -0,0 +1,19 @@ +function(target_crial_sources target) + set(crial ${LEFTONE_TOOL_DIR}/crial.sh) + + foreach (path ${ARGN}) + get_filename_component(dirname ${path} DIRECTORY) + get_filename_component(basename ${path} NAME_WE) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/crial/${dirname}) + + set(in ${CMAKE_CURRENT_SOURCE_DIR}/${path}) + set(out ${CMAKE_CURRENT_BINARY_DIR}/crial/${dirname}/${basename}.h) + add_custom_command( + OUTPUT ${out} + COMMAND bash ${crial} < ${in} > ${out} + DEPENDS ${path} ${crial} + COMMENT "generating serializer from ${path}" + VERBATIM) + target_sources(${target} PRIVATE ${out}) + endforeach() +endfunction() diff --git a/cmake/sos.cmake b/cmake/sos.cmake index 08974e2..939244e 100644 --- a/cmake/sos.cmake +++ b/cmake/sos.cmake @@ -1,20 +1,22 @@ function(target_source_of_source target) target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sos) - foreach (file ${ARGN}) - get_filename_component(name ${file} NAME_WE) + foreach (path ${ARGN}) + get_filename_component(dirname ${path} DIRECTORY) + get_filename_component(basename ${path} NAME_WE) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sos/${dirname}) - set(sos_target sos-${target}-${name}) - set(in ${CMAKE_CURRENT_SOURCE_DIR}/${file}) - set(out ${CMAKE_CURRENT_BINARY_DIR}/sos/${file}) + set(sos_target ${target}-${basename}-sos-generator) + set(in ${CMAKE_CURRENT_SOURCE_DIR}/${path}) + set(out ${CMAKE_CURRENT_BINARY_DIR}/sos/${path}) add_executable(${sos_target} ${in}) add_custom_command( OUTPUT ${out} COMMAND ${sos_target} > ${out} DEPENDS ${sos_target} - COMMENT "generating ${file}") + COMMENT "generating ${path}" + VERBATIM) target_sources(${target} PRIVATE ${out}) endforeach() endfunction() diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 0bba832..5ff2769 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,13 +1,15 @@ -include_directories(.) +add_compile_options(${LEFTONE_C_FLAGS}) add_subdirectory(lobullet) -add_subdirectory(locharacter) +add_subdirectory(lochara) add_subdirectory(locommon) add_subdirectory(loeffect) add_subdirectory(loentity) add_subdirectory(loground) +add_subdirectory(loparticle) add_subdirectory(loplayer) add_subdirectory(loresource) add_subdirectory(loscene) add_subdirectory(loshader) +add_subdirectory(loui) add_subdirectory(loworld) diff --git a/core/lobullet/CMakeLists.txt b/core/lobullet/CMakeLists.txt index 7c773d8..9c67314 100644 --- a/core/lobullet/CMakeLists.txt +++ b/core/lobullet/CMakeLists.txt @@ -1,10 +1,14 @@ add_library(lobullet base.c - bomb.c linear.c - misc.c pool.c ) +target_benum_sources(lobullet + type.h +) +target_crial_sources(lobullet + base.crial +) target_link_libraries(lobullet msgpackc diff --git a/core/lobullet/base.c b/core/lobullet/base.c index b01e28d..2448413 100644 --- a/core/lobullet/base.c +++ b/core/lobullet/base.c @@ -12,6 +12,7 @@ #include "util/mpkutil/get.h" #include "util/mpkutil/pack.h" +#include "core/locommon/msgpack.h" #include "core/locommon/position.h" #include "core/locommon/ticker.h" #include "core/loentity/bullet.h" @@ -20,10 +21,20 @@ #include "core/loentity/store.h" #include "core/loresource/set.h" #include "core/loshader/bullet.h" +#include "core/loshader/set.h" -#include "./bomb.h" #include "./linear.h" -#include "./misc.h" +#include "./type.h" + +/* generated serializer */ +#include "core/lobullet/crial/base.h" + +static bool +(*const update_function_vtable_[LOBULLET_TYPE_COUNT])(lobullet_base_t* base) = { + [LOBULLET_TYPE_LINEAR_CIRCLE] = lobullet_linear_circle_update, + [LOBULLET_TYPE_LINEAR_TRIANGLE] = lobullet_linear_triangle_update, + [LOBULLET_TYPE_LINEAR_SQUARE] = lobullet_linear_square_update, +}; static void lobullet_base_delete_(loentity_t* entity) { assert(entity != NULL); @@ -32,18 +43,6 @@ static void lobullet_base_delete_(loentity_t* entity) { if (!base->used) return; base->used = false; - -# define each_(NAME, name) do { \ - if (base->type == LOBULLET_TYPE_##NAME) { \ - lobullet_##name##_tear_down(base); \ - return; \ - } \ - } while (0) - - LOBULLET_TYPE_EACH_(each_); - assert(false); - -# undef each_ } static void lobullet_base_die_(loentity_t* entity) { @@ -55,18 +54,22 @@ static bool lobullet_base_update_(loentity_t* entity) { assert(entity != NULL); lobullet_base_t* base = (typeof(base)) entity; + base->cache = (typeof(base->cache)) {0}; + base->super.owner = base->param.owner; + base->super.velocity = vec2(0, 0); -# define each_(NAME, name) do { \ - if (base->type == LOBULLET_TYPE_##NAME) { \ - return lobullet_##name##_update(base); \ - } \ - } while (0) + const locommon_position_t oldpos = base->super.super.pos; - LOBULLET_TYPE_EACH_(each_); - return false; - -# undef each_ + assert(update_function_vtable_[base->param.type] != NULL); + if (!update_function_vtable_[base->param.type](base)) { + return false; + } + if (base->cache.velocity_calc) { + locommon_position_sub( + &base->super.velocity, &base->super.super.pos, &oldpos); + } + return true; } static void lobullet_base_draw_( @@ -80,7 +83,8 @@ static void lobullet_base_draw_( locommon_position_sub(&p, &base->super.super.pos, basepos); vec2_addeq(&base->cache.instance.pos, &p); - loshader_bullet_drawer_add_instance(base->drawer, &base->cache.instance); + loshader_bullet_drawer_add_instance( + &base->shaders->drawer.bullet, &base->cache.instance); } static void lobullet_base_pack_( @@ -90,29 +94,8 @@ static void lobullet_base_pack_( const lobullet_base_t* base = (typeof(base)) entity; - msgpack_pack_map(packer, 4); - - mpkutil_pack_str(packer, "subclass"); - mpkutil_pack_str(packer, "bullet"); - - mpkutil_pack_str(packer, "type"); - mpkutil_pack_str(packer, lobullet_type_stringify(base->type)); - - mpkutil_pack_str(packer, "id"); - msgpack_pack_uint64(packer, base->super.super.id); - - mpkutil_pack_str(packer, "data"); -# define each_(NAME, name) do { \ - if (base->type == LOBULLET_TYPE_##NAME) { \ - lobullet_##name##_pack_data(base, packer); \ - return; \ - } \ - } while (0) - - LOBULLET_TYPE_EACH_(each_); - assert(false); - -# undef each_ + msgpack_pack_map(packer, CRIAL_PROPERTY_COUNT_); + CRIAL_SERIALIZER_; } static bool lobullet_base_affect_( @@ -122,57 +105,31 @@ static bool lobullet_base_affect_( lobullet_base_t* base = (typeof(base)) bullet; vec2_t v = vec2(0, 0); - switch (base->cache.knockback.algorithm) { - case LOBULLET_BASE_KNOCKBACK_ALGORITHM_VELOCITY: - v = base->super.velocity; - break; - case LOBULLET_BASE_KNOCKBACK_ALGORITHM_POSITION: - locommon_position_sub(&v, &chara->super.pos, &base->super.super.pos); - break; - } - const float plen = vec2_pow_length(&v); - if (plen != 0) { - vec2_diveq(&v, sqrtf(plen)); - vec2_muleq(&v, base->cache.knockback.acceleration); - loentity_character_knockback(chara, &v); - } + locommon_position_sub(&v, &chara->super.pos, &base->super.super.pos); + vec2_muleq(&v, base->cache.knockback); + loentity_character_knockback(chara, &v); if (base->cache.toxic) { - loentity_character_apply_effect(chara, &base->cache.effect); + loentity_character_apply_effect(chara, &base->param.effect); } return base->cache.toxic; } void lobullet_base_initialize( - lobullet_base_t* base, - loresource_set_t* res, - loshader_bullet_drawer_t* drawer, - const locommon_ticker_t* ticker, - loentity_store_t* entities) { + lobullet_base_t* base, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_ticker_t* ticker, + loentity_store_t* entities) { assert(base != NULL); assert(res != NULL); - assert(drawer != NULL); + assert(shaders != NULL); assert(ticker != NULL); assert(entities != NULL); *base = (typeof(*base)) { - .super = { - .super = { - .vtable = { - .delete = lobullet_base_delete_, - .die = lobullet_base_die_, - .update = lobullet_base_update_, - .draw = lobullet_base_draw_, - .pack = lobullet_base_pack_, - }, - .subclass = LOENTITY_SUBCLASS_BULLET, - }, - .vtable = { - .affect = lobullet_base_affect_, - }, - }, .res = res, - .drawer = drawer, + .shaders = shaders, .ticker = ticker, .entities = entities, }; @@ -180,12 +137,31 @@ void lobullet_base_initialize( void lobullet_base_reinitialize(lobullet_base_t* base, loentity_id_t id) { assert(base != NULL); + assert(!base->used); - base->super.super.id = id; + base->super = (typeof(base->super)) { + .super = { + .vtable = { + .delete = lobullet_base_delete_, + .die = lobullet_base_die_, + .update = lobullet_base_update_, + .draw = lobullet_base_draw_, + .pack = lobullet_base_pack_, + }, + .id = id, + .subclass = LOENTITY_SUBCLASS_BULLET, + }, + .vtable = { + .affect = lobullet_base_affect_, + }, + }; + + base->param = (typeof(base->param)) {0}; } void lobullet_base_deinitialize(lobullet_base_t* base) { assert(base != NULL); + assert(!base->used); lobullet_base_delete_(&base->super.super); } @@ -195,41 +171,13 @@ bool lobullet_base_unpack(lobullet_base_t* base, const msgpack_object* obj) { lobullet_base_reinitialize(base, 0); - const char* v; - size_t vlen; - const msgpack_object_map* root = mpkutil_get_map(obj); + if (root == NULL) goto FAIL; -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define streq_(v1, len, v2) \ - (strncmp(v1, v2, len) == 0 && v2[len] == 0) - if (!mpkutil_get_str(item_("subclass"), &v, &vlen) || - !streq_(v, vlen, "bullet")) { - return false; - } -# undef streq_ - - if (!mpkutil_get_str(item_("type"), &v, &vlen) || - !lobullet_type_unstringify(&base->type, v, vlen)) { - return false; - } - - if (!mpkutil_get_uint64(item_("id"), &base->super.super.id)) { - return false; - } - - const msgpack_object* data = item_("data"); -# define each_(NAME, name) do { \ - if (base->type == LOBULLET_TYPE_##NAME) { \ - if (!lobullet_##name##_unpack_data(base, data)) return false; \ - } \ - } while (0) - - LOBULLET_TYPE_EACH_(each_); - -# undef each_ - -# undef item_ + CRIAL_DESERIALIZER_; return true; + +FAIL: + lobullet_base_delete_(&base->super.super); + return false; } diff --git a/core/lobullet/base.crial b/core/lobullet/base.crial new file mode 100644 index 0000000..2a983c4 --- /dev/null +++ b/core/lobullet/base.crial @@ -0,0 +1,44 @@ +/* CRIAL + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + mpkutil_pack_str(packer, $code); + END + DESERIALIZER_BEGIN + const char* v; + size_t vlen; + if (!mpkutil_get_str( + mpkutil_get_map_item_by_str(root, "$name"), &v, &vlen) || + strncmp(v, $code, vlen) != 0 || $code[vlen] != 0) { + goto FAIL; + } + END + PROPERTY subclass = "bullet" + + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + LOCOMMON_MSGPACK_PACK_ANY(packer, &base->$code); + END + DESERIALIZER_BEGIN + if (!LOCOMMON_MSGPACK_UNPACK_ANY( + mpkutil_get_map_item_by_str(root, "$name"), &base->$code)) { + goto FAIL; + } + END + PROPERTY id = super.super.id + PROPERTY pos = super.super.pos + PROPERTY owner = param.owner + PROPERTY type = param.type + PROPERTY target = param.target + PROPERTY basepos = param.basepos + PROPERTY size = param.size + PROPERTY color = param.color + PROPERTY velocity = param.velocity + PROPERTY acceleration = param.acceleration + PROPERTY angle = param.angle + PROPERTY angular_velocity = param.angular_velocity + PROPERTY quiet = param.quiet + PROPERTY knockback = param.knockback + PROPERTY effect = param.effect + PROPERTY since = param.since + PROPERTY duration = param.duration +*/ diff --git a/core/lobullet/base.h b/core/lobullet/base.h index 5656b47..317618f 100644 --- a/core/lobullet/base.h +++ b/core/lobullet/base.h @@ -13,54 +13,61 @@ #include "core/loentity/store.h" #include "core/loresource/set.h" #include "core/loshader/bullet.h" +#include "core/loshader/set.h" -#include "./misc.h" +#include "./type.h" -typedef enum { - LOBULLET_BASE_KNOCKBACK_ALGORITHM_VELOCITY, - LOBULLET_BASE_KNOCKBACK_ALGORITHM_POSITION, -} lobullet_base_knockback_algorithm_t; +typedef struct { + lobullet_type_t type; + loentity_id_t owner; + loentity_id_t target; + + locommon_position_t basepos; + vec2_t size; + vec4_t color; + + vec2_t velocity; + vec2_t acceleration; + + float angle; + float angular_velocity; + + bool quiet; + float knockback; + + loeffect_t effect; + + uint64_t since; + uint64_t duration; +} lobullet_base_param_t; typedef struct { loentity_bullet_t super; bool used; - /* injected deps */ - loresource_set_t* res; - loshader_bullet_drawer_t* drawer; - const locommon_ticker_t* ticker; - loentity_store_t* entities; + loresource_set_t* res; + loshader_set_t* shaders; + const locommon_ticker_t* ticker; + loentity_store_t* entities; + + lobullet_base_param_t param; - /* params not to be packed */ struct { - bool toxic; - loeffect_t effect; - /* When toxic is true, apply this effect to characters hit. */ - - struct { - float acceleration; - lobullet_base_knockback_algorithm_t algorithm; - } knockback; + bool toxic; + float knockback; + bool velocity_calc; loshader_bullet_drawer_instance_t instance; - /* instance pos is added to draw pos */ } cache; - - /* params to be packed (includes id) */ - lobullet_type_t type; - -# define LOBULLET_BASE_DATA_MAX_SIZE 256 - uint8_t data[LOBULLET_BASE_DATA_MAX_SIZE]; - /* pack function for the type is used */ } lobullet_base_t; void lobullet_base_initialize( - lobullet_base_t* base, - loresource_set_t* res, - loshader_bullet_drawer_t* drawer, - const locommon_ticker_t* ticker, - loentity_store_t* entities + lobullet_base_t* base, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_ticker_t* ticker, + loentity_store_t* entities ); void diff --git a/core/lobullet/bomb.c b/core/lobullet/bomb.c deleted file mode 100644 index 5451f44..0000000 --- a/core/lobullet/bomb.c +++ /dev/null @@ -1,205 +0,0 @@ -#include "./bomb.h" - -#include -#include -#include -#include -#include - -#include "util/coly2d/shape.h" -#include "util/math/algorithm.h" -#include "util/math/constant.h" -#include "util/math/vector.h" -#include "util/mpkutil/pack.h" - -#include "core/locommon/msgpack.h" -#include "core/locommon/position.h" -#include "core/locommon/ticker.h" -#include "core/loentity/entity.h" -#include "core/loresource/sound.h" -#include "core/loshader/bullet.h" - -#include "./base.h" -#include "./misc.h" - -#define LOBULLET_BOMB_PARAM_TO_PACK_EACH_(PROC) do { \ - PROC("owner", owner); \ - PROC("pos", pos); \ - PROC("size", size); \ - PROC("angle", angle); \ - PROC("color", color); \ - PROC("silent", silent); \ - PROC("beat", beat); \ - PROC("step", step); \ - PROC("knockback", knockback); \ - PROC("effect", effect); \ - PROC("since", since); \ -} while (0) -#define LOBULLET_BOMB_PARAM_TO_PACK_COUNT 11 - -_Static_assert(sizeof(lobullet_bomb_param_t) <= LOBULLET_BASE_DATA_MAX_SIZE); - -static bool lobullet_bomb_update_(lobullet_base_t* base) { - assert(base != NULL); - - const lobullet_bomb_param_t* p = (typeof(p)) base->data; - - base->super.super.pos = p->pos; - base->super.owner = p->owner; - base->super.velocity = vec2(0, 0); - base->super.shape.size = p->size; - base->super.shape.angle = p->angle; - - const uint64_t st = (p->step-1) * p->beat; - const uint64_t ed = st + 100; - - const uint64_t t = base->ticker->time - p->since; - const uint64_t pt = - (int64_t) t >= base->ticker->delta? t - base->ticker->delta: 0; - - if (!p->silent && pt < st && t >= st) { - loresource_sound_play(base->res->sound, "bomb"); - } - - base->cache.toxic = st <= t && t < ed; - base->cache.effect = p->effect; - return t < p->step*p->beat; -} - -bool lobullet_bomb_param_valid(const lobullet_bomb_param_t* param) { - return - param != NULL && - locommon_position_valid(¶m->pos) && - vec2_valid(¶m->size) && - MATH_FLOAT_VALID(param->angle) && - vec4_valid(¶m->color) && - MATH_FLOAT_VALID(param->beat) && - param->step > 0 && - MATH_FLOAT_VALID(param->knockback); -} -void lobullet_bomb_param_pack( - const lobullet_bomb_param_t* p, msgpack_packer* packer) { - assert(lobullet_bomb_param_valid(p)); - assert(packer != NULL); - - msgpack_pack_map(packer, LOBULLET_BOMB_PARAM_TO_PACK_COUNT); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &p->var); \ - } while (0) - - LOBULLET_BOMB_PARAM_TO_PACK_EACH_(pack_); - -# undef pack_ -} -bool lobullet_bomb_param_unpack( - lobullet_bomb_param_t* p, const msgpack_object* obj) { - assert(p != NULL); - - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &p->var)) { \ - return false; \ - } \ - } while (0) - - LOBULLET_BOMB_PARAM_TO_PACK_EACH_(unpack_); - return lobullet_bomb_param_valid(p); - -# undef unpack_ - -# undef item_ -} - -void lobullet_bomb_build( - lobullet_base_t* base, - lobullet_type_t type, - const lobullet_bomb_param_t* param) { - assert(base != NULL); - assert(lobullet_bomb_param_valid(param)); - - base->type = type; - - lobullet_bomb_param_t* p = (typeof(p)) base->data; - *p = *param; - p->since = base->ticker->time; -} - -bool lobullet_bomb_square_update(lobullet_base_t* base) { - assert(base != NULL); - - if (!lobullet_bomb_update_(base)) return false; - - const lobullet_bomb_param_t* p = (typeof(p)) base->data; - - /* ---- calculate motion ---- */ - const float beats = (base->ticker->time - p->since) / p->beat; - - float time = 0; - float angle = p->angle; - float alpha = 1; - if (beats < p->step-1) { - time = beats - (int64_t) beats; - alpha = 1-time; - time = time*time; - time = (1-time)*.05f; - } else { - time = 1 - powf(1-(beats - (int64_t) beats), 2); - angle += time * MATH_PI/4; - time = 1-time; - } - - /* ---- apply motion ---- */ - base->super.shape.type = COLY2D_SHAPE_TYPE_RECT; - base->super.shape.angle = angle; - - base->cache.instance = (loshader_bullet_drawer_instance_t) { - .bullet_id = LOSHADER_BULLET_ID_SQUARE, - .size = p->size, - .theta = angle, - .color = p->color, - .time = time, - }; - base->cache.instance.color.w *= alpha; - return true; -} - -bool lobullet_bomb_triangle_update(lobullet_base_t* base) { - assert(base != NULL); - - if (!lobullet_bomb_update_(base)) return false; - - const lobullet_bomb_param_t* p = (typeof(p)) base->data; - - /* ---- calculate motion ---- */ - const float beats = (base->ticker->time - p->since) / p->beat; - - float time = 0; - float alpha = 1; - if (beats < p->step-1) { - time = beats - (int64_t) beats; - alpha = 1-time; - time = time*time; - time = (1-time)*.05f; - } else { - time = 1 - powf(1-(beats - (int64_t) beats), 2); - time = 1-time; - } - - /* ---- apply motion ---- */ - base->super.shape.type = COLY2D_SHAPE_TYPE_TRIANGLE; - - base->cache.instance = (loshader_bullet_drawer_instance_t) { - .bullet_id = LOSHADER_BULLET_ID_TRIANGLE, - .size = p->size, - .theta = base->super.shape.angle, - .color = p->color, - .time = time, - }; - base->cache.instance.color.w *= alpha; - return true; -} diff --git a/core/lobullet/bomb.h b/core/lobullet/bomb.h deleted file mode 100644 index ad2b979..0000000 --- a/core/lobullet/bomb.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "util/math/vector.h" - -#include "core/locommon/position.h" -#include "core/loeffect/effect.h" -#include "core/loentity/entity.h" - -#include "./base.h" -#include "./misc.h" - -typedef struct { - loentity_id_t owner; - locommon_position_t pos; - vec2_t size; - float angle; - vec4_t color; - bool silent; - - float beat; - int32_t step; - float knockback; - - loeffect_t effect; - - uint64_t since; /* set by build function */ -} lobullet_bomb_param_t; - -bool -lobullet_bomb_param_valid( - const lobullet_bomb_param_t* param /* NULLABLE */ -); -void -lobullet_bomb_param_pack( - const lobullet_bomb_param_t* param, - msgpack_packer* packer -); -bool -lobullet_bomb_param_unpack( - lobullet_bomb_param_t* param, - const msgpack_object* obj /* NULLABLE */ -); - -void -lobullet_bomb_build( - lobullet_base_t* base, - lobullet_type_t type, - const lobullet_bomb_param_t* param -); - -bool -lobullet_bomb_square_update( - lobullet_base_t* base -); -#define lobullet_bomb_square_build(base, param) \ - lobullet_bomb_build(base, LOBULLET_TYPE_BOMB_SQUARE, param) -#define lobullet_bomb_square_tear_down(base) -#define lobullet_bomb_square_pack_data(base, packer) \ - lobullet_bomb_param_pack( \ - (const lobullet_bomb_param_t*) base->data, packer) -#define lobullet_bomb_square_unpack_data(base, obj) \ - lobullet_bomb_param_unpack( \ - (lobullet_bomb_param_t*) base->data, obj) - -bool -lobullet_bomb_triangle_update( - lobullet_base_t* base -); -#define lobullet_bomb_triangle_build(base, param) \ - lobullet_bomb_build(base, LOBULLET_TYPE_BOMB_TRIANGLE, param) -#define lobullet_bomb_triangle_tear_down(base) -#define lobullet_bomb_triangle_pack_data(base, packer) \ - lobullet_bomb_param_pack( \ - (const lobullet_bomb_param_t*) base->data, packer) -#define lobullet_bomb_triangle_unpack_data(base, obj) \ - lobullet_bomb_param_unpack( \ - (lobullet_bomb_param_t*) base->data, obj) diff --git a/core/lobullet/linear.c b/core/lobullet/linear.c index 67a4b63..f57e1d4 100644 --- a/core/lobullet/linear.c +++ b/core/lobullet/linear.c @@ -1,197 +1,100 @@ #include "./linear.h" -#include -#include #include -#include - -#include #include "util/coly2d/shape.h" -#include "util/math/constant.h" +#include "util/math/algorithm.h" #include "util/math/vector.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" -#include "core/locommon/msgpack.h" #include "core/locommon/position.h" -#include "core/loeffect/effect.h" -#include "core/loentity/entity.h" +#include "core/loshader/bullet.h" #include "./base.h" -#include "./misc.h" -#define LOBULLET_LINEAR_PARAM_TO_PACK_EACH_(PROC) do { \ - PROC("owner", owner); \ - PROC("pos", pos); \ - PROC("size", size); \ - PROC("velocity", velocity); \ - PROC("acceleration", acceleration); \ - PROC("color", color); \ - PROC("duration", duration); \ - PROC("knockback", knockback); \ - PROC("effect", effect); \ - PROC("since", since); \ -} while (0) -#define LOBULLET_LINEAR_PARAM_TO_PACK_COUNT 10 - -_Static_assert(sizeof(lobullet_linear_param_t) <= LOBULLET_BASE_DATA_MAX_SIZE); +#define FADE_DURATION_ 200 static bool lobullet_linear_update_(lobullet_base_t* base) { assert(base != NULL); - const lobullet_linear_param_t* p = (typeof(p)) base->data; + const uint64_t t = base->ticker->time - base->param.since; + const float tf = t/1000.f; - const float t = (base->ticker->time - p->since)/1000.f; - - base->super.owner = p->owner; + if (t >= base->param.duration) { + return false; + } + const uint64_t rt = base->param.duration - t; + const float alpha = rt < FADE_DURATION_? rt*1.f/FADE_DURATION_: 1; /* ---- movement ---- */ vec2_t v1; - vec2_mul(&v1, &p->velocity, t); - + vec2_mul(&v1, &base->param.velocity, tf); vec2_t v2; - vec2_mul(&v2, &p->acceleration, t*t/2); + vec2_mul(&v2, &base->param.acceleration, tf*tf/2); - base->super.super.pos = p->pos; + base->super.super.pos = base->param.basepos; vec2_addeq(&base->super.super.pos.fract, &v1); vec2_addeq(&base->super.super.pos.fract, &v2); locommon_position_reduce(&base->super.super.pos); /* ---- velocity ---- */ - vec2_mul(&base->super.velocity, &p->acceleration, t); - vec2_addeq(&base->super.velocity, &p->velocity); + vec2_mul(&base->super.velocity, &base->param.acceleration, tf); + vec2_addeq(&base->super.velocity, &base->param.velocity); - /* ---- angle ---- */ - const float theta = vec2_pow_length(&base->super.velocity) != 0? - atan2f(base->super.velocity.y, base->super.velocity.x): 0; - base->super.shape.size = p->size; - base->super.shape.angle = theta; + /* ---- parameters ---- */ + const float angle = base->param.angle + base->param.angular_velocity*tf; + base->cache = (typeof(base->cache)) { + .toxic = true, + .knockback = base->param.knockback, - /* ---- parameter update ---- */ - base->cache.toxic = true; - base->cache.effect = p->effect; - - base->cache.knockback = (typeof(base->cache.knockback)) { - .acceleration = p->knockback, - .algorithm = LOBULLET_BASE_KNOCKBACK_ALGORITHM_VELOCITY, + .instance = { + .size = base->param.size, + .theta = angle, + .color = base->param.color, + .time = alpha, + }, }; - - return p->since + p->duration > base->ticker->time; -} - -bool lobullet_linear_param_valid(const lobullet_linear_param_t* param) { - return - param != NULL && - locommon_position_valid(¶m->pos) && - vec2_valid(¶m->size) && - vec2_valid(¶m->velocity) && - vec2_valid(¶m->acceleration) && - param->duration > 0; -} -void lobullet_linear_param_pack( - const lobullet_linear_param_t* p, msgpack_packer* packer) { - assert(lobullet_linear_param_valid(p)); - assert(packer != NULL); - - msgpack_pack_map(packer, LOBULLET_LINEAR_PARAM_TO_PACK_COUNT); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &p->var); \ - } while (0) - - LOBULLET_LINEAR_PARAM_TO_PACK_EACH_(pack_); - -# undef pack_ -} -bool lobullet_linear_param_unpack( - lobullet_linear_param_t* p, const msgpack_object* obj) { - assert(p != NULL); - - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &p->var)) { \ - return false; \ - } \ - } while (0) - - LOBULLET_LINEAR_PARAM_TO_PACK_EACH_(unpack_); - return lobullet_linear_param_valid(p); - -# undef unpack_ - -# undef item_ -} - -void lobullet_linear_build( - lobullet_base_t* base, - lobullet_type_t type, - const lobullet_linear_param_t* param) { - assert(base != NULL); - assert(lobullet_linear_param_valid(param)); - - base->type = type; - - lobullet_linear_param_t* p = (typeof(p)) base->data; - *p = *param; - p->since = base->ticker->time; -} - -bool lobullet_linear_light_update(lobullet_base_t* base) { - assert(base != NULL); - - static const uint64_t fadedur = 500; - - if (!lobullet_linear_update_(base)) return false; - - const lobullet_linear_param_t* p = (typeof(p)) base->data; - - /* ---- calculation ---- */ - vec2_t size = p->size; - vec2_muleq(&size, 1.2f); - - float alpha = 1; - const uint64_t remain = p->duration - (base->ticker->time - p->since); - if (remain <= fadedur) alpha = remain*1.f / fadedur; - - /* ---- apply result ---- */ - base->super.shape.type = COLY2D_SHAPE_TYPE_ELLIPSE; - - base->cache.instance = (loshader_bullet_drawer_instance_t) { - .bullet_id = LOSHADER_BULLET_ID_LIGHT, - .size = size, - .theta = base->super.shape.angle, - .color = p->color, + base->super.shape = (coly2d_shape_t) { + .size = base->param.size, + .angle = angle, }; - base->cache.instance.color.w = alpha; return true; } +bool lobullet_linear_circle_update(lobullet_base_t* base) { + assert(base != NULL); + + if (!lobullet_linear_update_(base)) return false; + base->cache.instance.bullet_id = LOSHADER_BULLET_ID_LIGHT; + base->super.shape.type = COLY2D_SHAPE_TYPE_ELLIPSE; + + return true; +} bool lobullet_linear_triangle_update(lobullet_base_t* base) { assert(base != NULL); if (!lobullet_linear_update_(base)) return false; + base->cache.instance.bullet_id = LOSHADER_BULLET_ID_TRIANGLE; + base->super.shape.type = COLY2D_SHAPE_TYPE_TRIANGLE; - const lobullet_linear_param_t* p = (typeof(p)) base->data; - - /* ---- calculation ---- */ - vec2_t size = p->size; - size.x *= 1-(1-cos(MATH_PI/3))/2; - size.y *= 1-(1-sin(MATH_PI/3))/2; - - /* ---- apply result ---- */ - base->super.shape.type = COLY2D_SHAPE_TYPE_TRIANGLE; - - base->cache.instance = (loshader_bullet_drawer_instance_t) { - .bullet_id = LOSHADER_BULLET_ID_TRIANGLE, - .size = size, - .theta = base->super.shape.angle, - .color = p->color, - .time = 1, - }; return true; } +bool lobullet_linear_square_update(lobullet_base_t* base) { + assert(base != NULL); + + if (!lobullet_linear_update_(base)) return false; + base->cache.instance.bullet_id = LOSHADER_BULLET_ID_SQUARE; + base->super.shape.type = COLY2D_SHAPE_TYPE_RECT; + + return true; +} + +void lobullet_linear_build_( + lobullet_base_t* base, + const lobullet_base_param_t* param) { + assert(base != NULL); + assert(param != NULL); + + base->super.super.pos = param->basepos; + base->param = *param; + base->param.since = base->ticker->time; +} diff --git a/core/lobullet/linear.h b/core/lobullet/linear.h index 90dc51d..0748fbc 100644 --- a/core/lobullet/linear.h +++ b/core/lobullet/linear.h @@ -1,81 +1,51 @@ #pragma once #include -#include - -#include #include "util/math/vector.h" #include "core/locommon/position.h" -#include "core/loeffect/effect.h" -#include "core/loentity/entity.h" #include "./base.h" -typedef struct { - loentity_id_t owner; - - locommon_position_t pos; - vec2_t size; - vec2_t velocity; - vec2_t acceleration; - vec4_t color; - - uint64_t duration; - float knockback; - - loeffect_t effect; - - uint64_t since; /* set by build function */ -} lobullet_linear_param_t; - bool -lobullet_linear_param_valid( - const lobullet_linear_param_t* param -); -void -lobullet_linear_param_pack( - const lobullet_linear_param_t* param, - msgpack_packer* packer -); -bool -lobullet_linear_param_unpack( - lobullet_linear_param_t* param, - const msgpack_object* obj /* NULLABLE */ -); - -void -lobullet_linear_build( - lobullet_base_t* base, - lobullet_type_t type, - const lobullet_linear_param_t* param -); - -bool -lobullet_linear_light_update( +lobullet_linear_circle_update( lobullet_base_t* base ); -#define lobullet_linear_light_build(base, param) \ - lobullet_linear_build(base, LOBULLET_TYPE_LINEAR_LIGHT, param) -#define lobullet_linear_light_tear_down(base) -#define lobullet_linear_light_pack_data(base, packer) \ - lobullet_linear_param_pack( \ - (const lobullet_linear_param_t*) base->data, packer) -#define lobullet_linear_light_unpack_data(base, obj) \ - lobullet_linear_param_unpack( \ - (lobullet_linear_param_t*) base->data, obj) bool lobullet_linear_triangle_update( lobullet_base_t* base ); -#define lobullet_linear_triangle_build(base, param) \ - lobullet_linear_build(base, LOBULLET_TYPE_LINEAR_TRIANGLE, param) -#define lobullet_linear_triangle_tear_down(base) -#define lobullet_linear_triangle_pack_data(base, packer) \ - lobullet_linear_param_pack( \ - (const lobullet_linear_param_t*) base->data, packer) -#define lobullet_linear_triangle_unpack_data(base, obj) \ - lobullet_linear_param_unpack( \ - (lobullet_linear_param_t*) base->data, obj) + +bool +lobullet_linear_square_update( + lobullet_base_t* base +); + +void +lobullet_linear_build_( + lobullet_base_t* base, + const lobullet_base_param_t* param +); +#define lobullet_linear_circle_build(base, ...) \ + lobullet_linear_build_( \ + base, \ + &(lobullet_base_param_t) { \ + .type = LOBULLET_TYPE_LINEAR_CIRCLE, \ + __VA_ARGS__ \ + }) +#define lobullet_linear_triangle_build(base, ...) \ + lobullet_linear_build_( \ + base, \ + &(lobullet_base_param_t) { \ + .type = LOBULLET_TYPE_LINEAR_TRIANGLE, \ + __VA_ARGS__ \ + }) +#define lobullet_linear_square_build(base, ...) \ + lobullet_linear_build_( \ + base, \ + &(lobullet_base_param_t) { \ + .type = LOBULLET_TYPE_LINEAR_SQUARE, \ + __VA_ARGS__ \ + }) diff --git a/core/lobullet/misc.c b/core/lobullet/misc.c deleted file mode 100644 index 766f0a9..0000000 --- a/core/lobullet/misc.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "./misc.h" - -#include -#include -#include -#include - -const char* lobullet_type_stringify(lobullet_type_t type) { -# define each_(NAME, name) do { \ - if (type == LOBULLET_TYPE_##NAME) return #name; \ - } while (0) - - LOBULLET_TYPE_EACH_(each_); - - assert(false); - return NULL; - -# undef each_ -} - -bool lobullet_type_unstringify( - lobullet_type_t* type, const char* v, size_t len) { - assert(type != NULL); - assert(v != NULL || len == 0); - -# define each_(NAME, name) do { \ - if (strncmp(v, #name, len) == 0 && #name[len] == 0) { \ - *type = LOBULLET_TYPE_##NAME; \ - return true; \ - } \ - } while (0) - - LOBULLET_TYPE_EACH_(each_); - return false; - -# undef each_ -} diff --git a/core/lobullet/misc.h b/core/lobullet/misc.h deleted file mode 100644 index 7d56b6b..0000000 --- a/core/lobullet/misc.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include - -/* dont forget to update EACH macro */ -typedef enum { - LOBULLET_TYPE_LINEAR_LIGHT, - LOBULLET_TYPE_LINEAR_TRIANGLE, - LOBULLET_TYPE_BOMB_SQUARE, - LOBULLET_TYPE_BOMB_TRIANGLE, -} lobullet_type_t; - -#define LOBULLET_TYPE_EACH_(PROC) do { \ - PROC(LINEAR_LIGHT, linear_light); \ - PROC(LINEAR_TRIANGLE, linear_triangle); \ - PROC(BOMB_SQUARE, bomb_square); \ - PROC(BOMB_TRIANGLE, bomb_triangle); \ -} while (0) - -const char* -lobullet_type_stringify( - lobullet_type_t type -); - -bool -lobullet_type_unstringify( - lobullet_type_t* type, - const char* v, - size_t len -); diff --git a/core/lobullet/pool.c b/core/lobullet/pool.c index a30eb23..419cdde 100644 --- a/core/lobullet/pool.c +++ b/core/lobullet/pool.c @@ -8,43 +8,24 @@ #include "core/locommon/counter.h" #include "core/locommon/ticker.h" +#include "core/loentity/pool.h" #include "core/loentity/store.h" #include "core/loresource/set.h" -#include "core/loshader/bullet.h" +#include "core/loshader/set.h" #include "./base.h" -struct lobullet_pool_t { - loresource_set_t* res; - loshader_bullet_drawer_t* drawer; - locommon_counter_t* idgen; - const locommon_ticker_t* ticker; - loentity_store_t* entities; - - size_t length; - lobullet_base_t items[1]; -}; - -static size_t lobullet_pool_find_unused_item_index_( - const lobullet_pool_t* pool) { - assert(pool != NULL); - - for (size_t i = 0; i < pool->length; ++i) { - if (!pool->items[i].used) return i; - } - fprintf(stderr, "bullet pool overflow\n"); - abort(); -} +LOENTITY_POOL_SOURCE_TEMPLATE(lobullet) lobullet_pool_t* lobullet_pool_new( - loresource_set_t* res, - loshader_bullet_drawer_t* drawer, - locommon_counter_t* idgen, - const locommon_ticker_t* ticker, - loentity_store_t* entities, - size_t length) { + loresource_set_t* res, + loshader_set_t* shaders, + locommon_counter_t* idgen, + const locommon_ticker_t* ticker, + loentity_store_t* entities, + size_t length) { assert(res != NULL); - assert(drawer != NULL); + assert(shaders != NULL); assert(idgen != NULL); assert(ticker != NULL); assert(entities != NULL); @@ -53,52 +34,16 @@ lobullet_pool_t* lobullet_pool_new( lobullet_pool_t* pool = memory_new(sizeof(*pool) + (length-1)*sizeof(pool->items[0])); *pool = (typeof(*pool)) { - .res = res, - .drawer = drawer, - .idgen = idgen, - .ticker = ticker, - .entities = entities, - .length = length, + .idgen = idgen, + .length = length, }; for (size_t i = 0; i < pool->length; ++i) { lobullet_base_initialize( &pool->items[i], res, - drawer, + shaders, ticker, entities); } return pool; } - -void lobullet_pool_delete(lobullet_pool_t* pool) { - if (pool == NULL) return; - - for (size_t i = 0; i < pool->length; ++i) { - lobullet_base_deinitialize(&pool->items[i]); - } - memory_delete(pool); -} - -lobullet_base_t* lobullet_pool_create(lobullet_pool_t* pool) { - assert(pool != NULL); - - const size_t i = lobullet_pool_find_unused_item_index_(pool); - - pool->items[i].used = true; - lobullet_base_reinitialize( - &pool->items[i], locommon_counter_count(pool->idgen)); - return &pool->items[i]; -} - -lobullet_base_t* lobullet_pool_unpack_item( - lobullet_pool_t* pool, const msgpack_object* obj) { - assert(pool != NULL); - - const size_t i = lobullet_pool_find_unused_item_index_(pool); - - if (!lobullet_base_unpack(&pool->items[i], obj)) return NULL; - - pool->items[i].used = true; - return &pool->items[i]; -} diff --git a/core/lobullet/pool.h b/core/lobullet/pool.h index 66d9557..6308bb0 100644 --- a/core/lobullet/pool.h +++ b/core/lobullet/pool.h @@ -8,7 +8,7 @@ #include "core/locommon/ticker.h" #include "core/loentity/store.h" #include "core/loresource/set.h" -#include "core/loshader/bullet.h" +#include "core/loshader/set.h" #include "./base.h" @@ -17,12 +17,12 @@ typedef struct lobullet_pool_t lobullet_pool_t; lobullet_pool_t* /* OWNERSHIP */ lobullet_pool_new( - loresource_set_t* res, - loshader_bullet_drawer_t* drawer, - locommon_counter_t* idgen, - const locommon_ticker_t* ticker, - loentity_store_t* entities, - size_t length + loresource_set_t* res, + loshader_set_t* shaders, + locommon_counter_t* idgen, + const locommon_ticker_t* ticker, + loentity_store_t* entities, + size_t length ); void diff --git a/core/lobullet/type.h b/core/lobullet/type.h new file mode 100644 index 0000000..7b79101 --- /dev/null +++ b/core/lobullet/type.h @@ -0,0 +1,11 @@ +#pragma once + +typedef enum { + /* BENUM BEGIN lobullet_type */ + LOBULLET_TYPE_LINEAR_CIRCLE, + LOBULLET_TYPE_LINEAR_TRIANGLE, + LOBULLET_TYPE_LINEAR_SQUARE, + /* BENUM END */ +} lobullet_type_t; + +#include "core/lobullet/benum/type.h" diff --git a/core/lochara/CMakeLists.txt b/core/lochara/CMakeLists.txt new file mode 100644 index 0000000..8be0ca2 --- /dev/null +++ b/core/lochara/CMakeLists.txt @@ -0,0 +1,37 @@ +add_library(lochara + base.c + big_warder.c + cavia.c + combat.c + encephalon.c + player.c + pool.c + state.c + strategy.c + theists_child.c + warder.c +) +target_benum_sources(lochara + state.h + strategy.h + type.h +) +target_crial_sources(lochara + base.crial +) + +target_link_libraries(lochara + msgpackc + + chaos + math + statman + + lobullet + locommon + loeffect + loentity + loplayer + loresource + loshader +) diff --git a/core/lochara/base.c b/core/lochara/base.c new file mode 100644 index 0000000..fdae598 --- /dev/null +++ b/core/lochara/base.c @@ -0,0 +1,333 @@ +#include "./base.h" + +#include +#include +#include +#include + +#include + +#include "util/math/algorithm.h" +#include "util/math/vector.h" +#include "util/mpkutil/get.h" +#include "util/mpkutil/pack.h" +#include "util/statman/statman.h" + +#include "core/lobullet/pool.h" +#include "core/locommon/easing.h" +#include "core/locommon/msgpack.h" +#include "core/locommon/physics.h" +#include "core/locommon/ticker.h" +#include "core/loeffect/recipient.h" +#include "core/loentity/character.h" +#include "core/loentity/ground.h" +#include "core/loentity/store.h" +#include "core/loplayer/player.h" +#include "core/loresource/sound.h" +#include "core/loshader/character.h" + +#include "./big_warder.h" +#include "./cavia.h" +#include "./encephalon.h" +#include "./player.h" +#include "./state.h" +#include "./theists_child.h" +#include "./type.h" +#include "./warder.h" + +/* generated serializer */ +#include "core/lochara/crial/base.h" + +#define GRAVITY_ACCELERATION_ 2.2f +#define KNOCKBACK_RECOVERY_ACCELERATION_ 4.4f + +#define BULLET_INVINCIBLE_DURATION_ 500 + +static bool +(*const update_function_vtable_[LOCHARA_TYPE_COUNT])(lochara_base_t* base) = { + [LOCHARA_TYPE_PLAYER] = lochara_player_update, + + [LOCHARA_TYPE_ENCEPHALON] = lochara_encephalon_update, + + [LOCHARA_TYPE_CAVIA] = lochara_cavia_update, + [LOCHARA_TYPE_WARDER] = lochara_warder_update, + + [LOCHARA_TYPE_BIG_WARDER] = lochara_big_warder_update, + [LOCHARA_TYPE_THEISTS_CHILD] = lochara_theists_child_update, +}; + +static loentity_ground_t* lochara_base_find_ground_( + lochara_base_t* base, loentity_id_t id, vec2_t* pos) { + assert(base != NULL); + assert(pos != NULL); + + loentity_store_iterator_t itr; + if (!loentity_store_find_item_by_id(base->entities, &itr, id) || + itr.ground == NULL) { + return NULL; + } + locommon_position_sub(pos, &base->super.super.pos, &itr.ground->super.pos); + pos->x /= itr.ground->size.x; + pos->y -= itr.ground->size.y; + return itr.ground; +} + +static void lochara_base_delete_(loentity_t* entity) { + assert(entity != NULL); + + lochara_base_t* base = (typeof(base)) entity; + + loeffect_recipient_deinitialize(&base->param.recipient); + + base->used = false; +} + +static void lochara_base_die_(loentity_t* entity) { + assert(entity != NULL); + +} + +static bool lochara_base_update_(loentity_t* entity) { + assert(entity != NULL); + + lochara_base_t* base = (typeof(base)) entity; + + base->cache = (typeof(base->cache)) {0}; + base->super.velocity = vec2(0, 0); + + base->cache.ground = lochara_base_find_ground_( + base, base->param.ground, &base->cache.ground_pos); + + assert(update_function_vtable_[base->param.type] != NULL); + return update_function_vtable_[base->param.type](base); +} + +static void lochara_base_draw_( + loentity_t* entity, const locommon_position_t* basepos) { + assert(entity != NULL); + assert(locommon_position_valid(basepos)); + + lochara_base_t* base = (typeof(base)) entity; + + vec2_t pos; + locommon_position_sub(&pos, &base->super.super.pos, basepos); + vec2_addeq(&base->cache.instance.pos, &pos); + + loshader_character_drawer_add_instance( + &base->shaders->drawer.character, &base->cache.instance); +} + +static void lochara_base_pack_( + const loentity_t* entity, msgpack_packer* packer) { + assert(entity != NULL); + assert(packer != NULL); + + lochara_base_t* base = (typeof(base)) entity; + + msgpack_pack_map(packer, CRIAL_PROPERTY_COUNT_); + CRIAL_SERIALIZER_; +} + +static void lochara_base_apply_effect_( + loentity_character_t* chara, const loeffect_t* effect) { + assert(chara != NULL); + assert(effect != NULL); + + lochara_base_t* base = (typeof(base)) chara; + + const bool player = base->param.type == LOCHARA_TYPE_PLAYER; + + loeffect_recipient_apply_effect(&base->param.recipient, effect); + + switch (effect->id) { + case LOEFFECT_ID_DAMAGE: + if (player) { + loresource_sound_set_play(&base->res->sound, LORESOURCE_SOUND_ID_DAMAGE); + } + break; + default: + break; + } +} + +static void lochara_base_knockback_( + loentity_character_t* chara, const vec2_t* v) { + assert(chara != NULL); + assert(vec2_valid(v)); + + lochara_base_t* base = (typeof(base)) chara; + + base->param.gravity += v->y; + base->param.knockback += v->x; + + if (vec2_pow_length(v) > 0) { + base->param.last_knockback = base->ticker->time; + } +} + +void lochara_base_initialize( + lochara_base_t* base, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_ticker_t* ticker, + loentity_store_t* entities, + loplayer_t* player, + lobullet_pool_t* bullet) { + assert(base != NULL); + assert(res != NULL); + assert(shaders != NULL); + assert(ticker != NULL); + assert(entities != NULL); + assert(player != NULL); + assert(bullet != NULL); + + *base = (typeof(*base)) { + .res = res, + .shaders = shaders, + .ticker = ticker, + .entities = entities, + .player = player, + .bullet = bullet, + }; +} + +void lochara_base_reinitialize(lochara_base_t* base, loentity_id_t id) { + assert(base != NULL); + assert(!base->used); + + base->super = (typeof(base->super)) { + .super = { + .vtable = { + .delete = lochara_base_delete_, + .die = lochara_base_die_, + .update = lochara_base_update_, + .draw = lochara_base_draw_, + .pack = lochara_base_pack_, + }, + .id = id, + .subclass = LOENTITY_SUBCLASS_CHARACTER, + }, + .vtable = { + .apply_effect = lochara_base_apply_effect_, + .knockback = lochara_base_knockback_, + }, + }; + + base->param = (typeof(base->param)) {0}; +} + +void lochara_base_deinitialize(lochara_base_t* base) { + assert(base != NULL); + assert(!base->used); + +} + +void lochara_base_calculate_physics( + lochara_base_t* base, const vec2_t* size, const vec2_t* offset) { + assert(base != NULL); + assert(vec2_valid(size)); + assert(vec2_valid(offset)); + + const float dt = base->ticker->delta_f; + + vec2_t velocity = base->param.movement; + velocity.y += base->param.gravity; + velocity.x += base->param.knockback; + + base->param.gravity -= GRAVITY_ACCELERATION_*dt; + locommon_easing_linear_float( + &base->param.knockback, 0, KNOCKBACK_RECOVERY_ACCELERATION_*dt); + + vec2_t disp; + vec2_mul(&disp, &velocity, base->ticker->delta_f); + + vec2_addeq(&base->super.super.pos.fract, &disp); + vec2_subeq(&base->super.super.pos.fract, offset); + locommon_position_reduce(&base->super.super.pos); + + locommon_physics_entity_t e = { + .size = *size, + .pos = base->super.super.pos, + .velocity = velocity, + }; + + loentity_store_solve_collision_between_ground( + base->entities, &e, base->ticker->delta_f); + + base->super.super.pos = e.pos; + vec2_addeq(&base->super.super.pos.fract, offset); + locommon_position_reduce(&base->super.super.pos); + + base->param.on_ground = false; + if (e.velocity.y == 0) { + if (velocity.y <= 0) { + base->param.on_ground = true; + } + if (base->param.gravity*velocity.y > 0) { + base->param.gravity = 0; + } + } + if (e.velocity.x == 0 && velocity.x != 0) { + if (base->param.knockback*velocity.x >= 0) { + base->param.knockback = 0; + } + } + base->super.velocity = velocity = e.velocity; +} + +void lochara_base_bind_on_ground(lochara_base_t* base, const vec2_t* offset) { + assert(base != NULL); + assert(vec2_valid(offset)); + + if (base->cache.ground == NULL) return; + + vec2_t p; + locommon_position_sub( + &p, &base->super.super.pos, &base->cache.ground->super.pos); + + const vec2_t sz = base->cache.ground->size; + p.x = MATH_CLAMP(p.x, -sz.x+offset->x, sz.x-offset->x); + p.y = MATH_CLAMP(p.y, sz.y+offset->y, 1); + + base->super.super.pos = base->cache.ground->super.pos; + vec2_addeq(&base->super.super.pos.fract, &p); + locommon_position_reduce(&base->super.super.pos); +} + +bool lochara_base_affect_bullets(lochara_base_t* base) { + assert(base != NULL); + + const uint64_t t = base->ticker->time; + if (base->param.last_bullet_hit + BULLET_INVINCIBLE_DURATION_ > t) { + return false; + } + + const bool hit = loentity_store_affect_bullets_shot_by_others( + base->entities, + &base->super, + &base->super.velocity, + base->ticker->delta_f); + if (hit) { + base->param.last_bullet_hit = base->ticker->time; + } + return true; +} + +bool lochara_base_unpack(lochara_base_t* base, const msgpack_object* obj) { + assert(base != NULL); + assert(obj != NULL); + assert(!base->used); + + lochara_base_reinitialize(base, 0); /* id will be overwritten */ + + loeffect_recipient_initialize(&base->param.recipient, base->ticker, NULL); + + const msgpack_object_map* root = mpkutil_get_map(obj); + if (root == NULL) goto FAIL; + CRIAL_DESERIALIZER_; + return true; + +FAIL: + lochara_base_delete_(&base->super.super); + return false; +} diff --git a/core/lochara/base.crial b/core/lochara/base.crial new file mode 100644 index 0000000..99e2616 --- /dev/null +++ b/core/lochara/base.crial @@ -0,0 +1,60 @@ +/* CRIAL + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + mpkutil_pack_str(packer, $code); + END + DESERIALIZER_BEGIN + const char* v; + size_t vlen; + if (!mpkutil_get_str( + mpkutil_get_map_item_by_str(root, "$name"), &v, &vlen) || + strncmp(v, $code, vlen) != 0 || $code[vlen] != 0) { + goto FAIL; + } + END + PROPERTY subclass = "character" + + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + LOCOMMON_MSGPACK_PACK_ANY(packer, &base->$code); + END + DESERIALIZER_BEGIN + if (!LOCOMMON_MSGPACK_UNPACK_ANY( + mpkutil_get_map_item_by_str(root, "$name"), &base->$code)) { + goto FAIL; + } + END + PROPERTY id = super.super.id + PROPERTY pos = super.super.pos + PROPERTY velocity = super.velocity + PROPERTY type = param.type + PROPERTY recipient = param.recipient + PROPERTY last_state_changed = param.last_state_changed + PROPERTY last_strategy_changed = param.last_strategy_changed + PROPERTY ground = param.ground + PROPERTY on_ground = param.on_ground + PROPERTY direction = param.direction + PROPERTY movement = param.movement + PROPERTY gravity = param.gravity + PROPERTY knockback = param.knockback + PROPERTY last_knockback = param.last_knockback + PROPERTY last_bullet_hit = param.last_bullet_hit + PROPERTY anchor_pos = param.anchor.pos + PROPERTY anchor_vec = param.anchor.vec + + SERIALIZER_BEGIN + const $code v = base->param.$name; + mpkutil_pack_str(packer, "$name"); + LOCOMMON_MSGPACK_PACK_ANY(packer, &v); + END + DESERIALIZER_BEGIN + $code v; + if (!LOCOMMON_MSGPACK_UNPACK_ANY( + mpkutil_get_map_item_by_str(root, "$name"), &v)) { + goto FAIL; + } + base->param.$name = v; + END + PROPERTY state = lochara_state_t + PROPERTY strategy = lochara_strategy_t +*/ diff --git a/core/lochara/base.h b/core/lochara/base.h new file mode 100644 index 0000000..29ffa68 --- /dev/null +++ b/core/lochara/base.h @@ -0,0 +1,116 @@ +#pragma once + +#include +#include + +#include + +#include "util/math/vector.h" +#include "util/statman/statman.h" + +#include "core/lobullet/pool.h" +#include "core/locommon/ticker.h" +#include "core/loeffect/recipient.h" +#include "core/loentity/character.h" +#include "core/loentity/entity.h" +#include "core/loentity/ground.h" +#include "core/loentity/store.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" + +#include "./state.h" +#include "./strategy.h" +#include "./type.h" + +typedef struct lochara_base_t { + loentity_character_t super; + bool used; + + loresource_set_t* res; + loshader_set_t* shaders; + const locommon_ticker_t* ticker; + loentity_store_t* entities; + loplayer_t* player; + lobullet_pool_t* bullet; + + struct { + lochara_type_t type; + + loeffect_recipient_t recipient; + + statman_state_t state; /* actual type is lochara_state_t */ + uint64_t last_state_changed; + + statman_state_t strategy; /* actual type is lochara_strategy_t */ + uint64_t last_strategy_changed; + + loentity_id_t ground; + bool on_ground; + + vec2_t direction; + vec2_t movement; + float gravity; + float knockback; + uint64_t last_knockback; + uint64_t last_bullet_hit; + + /* some character uses these params for some strategy */ + struct { + locommon_position_t pos; + vec2_t vec; + } anchor; + } param; + + struct { + loentity_ground_t* ground; + vec2_t ground_pos; + loshader_character_drawer_instance_t instance; + } cache; +} lochara_base_t; + +void +lochara_base_initialize( + lochara_base_t* base, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_ticker_t* ticker, + loentity_store_t* entities, + loplayer_t* player, + lobullet_pool_t* bullet +); + +void +lochara_base_reinitialize( + lochara_base_t* base, + loentity_id_t id +); + +void +lochara_base_deinitialize( + lochara_base_t* base +); + +void +lochara_base_calculate_physics( + lochara_base_t* base, + const vec2_t* size, + const vec2_t* offset +); + +void +lochara_base_bind_on_ground( + lochara_base_t* base, + const vec2_t* offset +); + +bool +lochara_base_affect_bullets( + lochara_base_t* base +); + +bool +lochara_base_unpack( + lochara_base_t* base, + const msgpack_object* obj +); diff --git a/core/lochara/big_warder.c b/core/lochara/big_warder.c new file mode 100644 index 0000000..71f0556 --- /dev/null +++ b/core/lochara/big_warder.c @@ -0,0 +1,728 @@ +#include "./big_warder.h" + +#include +#include + +#include "util/chaos/xorshift.h" +#include "util/math/algorithm.h" +#include "util/math/vector.h" +#include "util/statman/statman.h" + +#include "core/lobullet/linear.h" +#include "core/lobullet/pool.h" +#include "core/locommon/position.h" +#include "core/loentity/ground.h" +#include "core/loplayer/event.h" +#include "core/loplayer/stance.h" +#include "core/loresource/music.h" +#include "core/loshader/character.h" + +#include "./base.h" +#include "./state.h" +#include "./strategy.h" +#include "./type.h" + +#define WIDTH_ .025f +#define HEIGHT_ .06f +#define MARKER_ .03f +#define COLOR_ vec4(0, 0, 0, 1) + +#define BPM_ 80 +#define BEAT_ (60.f/BPM_) +#define BEAT_MS_ (BEAT_*1000) +#define MUSIC_DURATION_ (BEAT_MS_*144) + +#define WAKE_UP_RANGE_ (WIDTH_*8) + +#define REWARD_STANCE_ LOPLAYER_STANCE_UNFINISHER + +static const loeffect_recipient_status_t base_status_ = { + .attack = .2f, + .defence = .92f, + .speed = .31f, + .jump = 1.1f, +}; + +static void lochara_big_warder_initialize_shoot_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + lochara_state_initialize_any_(meta, instance, state); + + lochara_base_t* base = instance; + + vec2_t dir; + locommon_position_sub( + &dir, &base->player->entity->super.super.pos, &base->super.super.pos); + + if (dir.x == 0 && dir.y == 0) dir = vec2(1, 0); + vec2_diveq(&dir, vec2_length(&dir)); + + const vec2_t invdir = vec2(dir.y, -dir.x); + + base->param.direction = vec2(MATH_SIGN_NOZERO(dir.x), 0); + for (int32_t i = -4; i <= 4; ++i) { + vec2_t a; + vec2_mul(&a, &dir, 1.5f-MATH_ABS(i)/4.f*.5f); + + vec2_t v; + vec2_mul(&v, &dir, .5f); + + vec2_t p; + vec2_mul(&p, &invdir, i*.02f); + + locommon_position_t pos = base->super.super.pos; + vec2_addeq(&pos.fract, &p); + locommon_position_reduce(&pos); + + lobullet_base_t* b = lobullet_pool_create(base->bullet); + lobullet_linear_circle_build(b, + .owner = base->super.super.id, + .basepos = pos, + .size = vec2(.02f, .02f), + .color = vec4(1, 1, 1, 1), + .acceleration = a, + .velocity = v, + .knockback = 1, + .effect = loeffect_damage( + base->param.recipient.status.attack*.6f), + .duration = 2000, + ); + loentity_store_add(base->entities, &b->super.super); + } +} + +static void lochara_big_warder_update_thrust_in_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + static const uint64_t dur = BEAT_MS_/4; + + lochara_base_t* base = instance; + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + + const float tf = t*1.f / dur; + base->cache.instance.motion.time = powf(tf, 2); + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; +} + +static void lochara_big_warder_update_thrust_out_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + static const uint64_t dur = BEAT_MS_/4; + + lochara_base_t* base = instance; + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + + const float tf = t*1.f / dur; + base->cache.instance.motion.time = 1-powf(1-tf, 2); + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; +} + +static void lochara_big_warder_update_down_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + const bool fast = + meta->state == LOCHARA_STATE_DOWN || + meta->state == LOCHARA_STATE_REVIVE; + const bool reverse = + meta->state == LOCHARA_STATE_REVIVE || + meta->state == LOCHARA_STATE_RESUSCITATE; + + const uint64_t dur = fast? reverse? BEAT_MS_*3: BEAT_MS_: BEAT_MS_*4; + + lochara_base_t* base = instance; + base->param.movement = vec2(0, 0); + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + if (reverse) t = dur - t; + + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_STAND1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_DOWN; + base->cache.instance.motion.time = powf(t*1.f/dur, 6); +} + +static const statman_meta_t state_table_[] = { + lochara_state_stand( + .period = BEAT_MS_*2, + .acceleration = {{5, 5}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_ATTACK1, + ), + lochara_state_walk( + .period = BEAT_MS_, + .acceleration = {{5, 5}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_WALK, + ), + lochara_state_dodge( + .duration = BEAT_MS_/2, + .speed = 1, + .acceleration = {{3, 3}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_WALK, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + ), + + lochara_state_teleport( + .duration = BEAT_MS_, + .offset = {{WIDTH_*2, 0}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_ATTACK2, + ), + + { + .state = LOCHARA_STATE_THRUST_IN, + .name = "THRUST_IN", + .initialize = lochara_state_initialize_any_, + .update = lochara_big_warder_update_thrust_in_state_, + }, + { + .state = LOCHARA_STATE_THRUST_OUT, + .name = "THRUST_OUT", + .initialize = lochara_state_initialize_any_, + .update = lochara_big_warder_update_thrust_out_state_, + }, + { + .state = LOCHARA_STATE_SHOOT, + .name = "SHOOT", + .initialize = lochara_big_warder_initialize_shoot_state_, + .update = lochara_big_warder_update_thrust_in_state_, + }, + { + .state = LOCHARA_STATE_DOWN, + .name = "DOWN", + .initialize = lochara_state_initialize_any_, + .update = lochara_big_warder_update_down_state_, + }, + { + .state = LOCHARA_STATE_REVIVE, + .name = "REVIVE", + .initialize = lochara_state_initialize_any_, + .update = lochara_big_warder_update_down_state_, + }, + { + .state = LOCHARA_STATE_DEAD, + .name = "DEAD", + .initialize = lochara_state_initialize_any_, + .update = lochara_big_warder_update_down_state_, + }, + { + .state = LOCHARA_STATE_RESUSCITATE, + .name = "RESUSCITATE", + .initialize = lochara_state_initialize_any_, + .update = lochara_big_warder_update_down_state_, + }, + {0}, +}; + +static void lochara_big_warder_update_wait_strategy_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + static const float range2 = WAKE_UP_RANGE_*WAKE_UP_RANGE_; + + lochara_base_t* base = instance; + + vec2_t disp; + locommon_position_sub( + &disp, &base->player->entity->super.super.pos, &base->super.super.pos); + + if (fabsf(disp.y) < HEIGHT_/2 && vec2_pow_length(&disp) < range2) { + loeffect_recipient_apply_effect( + &base->param.recipient, &loeffect_resuscitate()); + if (loplayer_stance_set_has(&base->player->stances, REWARD_STANCE_)) { + *next = LOCHARA_STRATEGY_WAKE_UP; + } else { + *next = LOCHARA_STRATEGY_WAKE_UP_EVENT; + } + return; + } + statman_transition_to( + state_table_, instance, &base->param.state, LOCHARA_STATE_DEAD); +} + +static void lochara_big_warder_initialize_wake_up_strategy_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + lochara_strategy_initialize_any_(meta, instance, next); + if (meta->state != LOCHARA_STRATEGY_WAKE_UP_EVENT) return; + + lochara_base_t* base = instance; + loentity_character_apply_effect( + &base->super, &loeffect_fanatic(MUSIC_DURATION_)); + loentity_character_apply_effect( + &base->player->entity->super, &loeffect_curse(MUSIC_DURATION_)); +} + +static void lochara_big_warder_update_wake_up_strategy_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + const bool ev = meta->state == LOCHARA_STRATEGY_WAKE_UP_EVENT; + const uint64_t dur = (ev? BEAT_MS_*16: BEAT_MS_*4); + + lochara_base_t* base = instance; + + const uint64_t t = base->ticker->time - base->param.last_strategy_changed; + if (t >= dur) { + *next = LOCHARA_STRATEGY_APPROACH; + return; + } + statman_transition_to( + state_table_, instance, &base->param.state, LOCHARA_STATE_RESUSCITATE); +} + +static void lochara_big_warder_update_approach_strategy_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + lochara_base_t* base = instance; + if (!loeffect_recipient_is_alive(&base->param.recipient)) { + *next = LOCHARA_STRATEGY_DEAD; + return; + } + + const uint64_t since = base->param.last_strategy_changed; + + uint64_t until = since + BEAT_MS_; + if (base->player->event.executor == base->super.super.id) { + const uint64_t msince = base->player->event.ctx.music.since; + if (msince < since) { + const uint64_t beats = (since - msince)/BEAT_MS_ + 1; + until = msince + beats*BEAT_MS_; + } + } + + /* ---- strategy transition ---- */ + const locommon_position_t* player = &base->player->entity->super.super.pos; + + vec2_t disp; + locommon_position_sub(&disp, player, &base->super.super.pos); + + if (player->chunk.x != base->super.super.pos.chunk.x || + player->chunk.y != base->super.super.pos.chunk.y || + disp.y < -HEIGHT_) { + *next = LOCHARA_STRATEGY_WAIT; + return; + } + + const float dist = MATH_ABS(disp.x); + if (base->ticker->time >= until) { + if (MATH_ABS(disp.y) > HEIGHT_) { + *next = LOCHARA_STRATEGY_SHOOT1; + } else if (dist < WIDTH_*5) { + *next = LOCHARA_STRATEGY_COMBO1; + if (chaos_xorshift(base->ticker->time)%3 == 0) { + *next = LOCHARA_STRATEGY_COMBO2; + } + } else if (dist < WIDTH_*10) { + *next = LOCHARA_STRATEGY_COMBO2; + } else { + *next = LOCHARA_STRATEGY_SHOOT1; + } + return; + } + + if (dist > WIDTH_*6) { + base->param.direction = vec2(MATH_SIGN_NOZERO(disp.x), 0); + } +} + +static const lochara_combat_action_t combo1_[] = { + lochara_combat_action_rest( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_IN, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1.2f, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_DODGE_LEFT, + ), + {0}, +}; + +static const lochara_combat_action_t combo2_[] = { + lochara_combat_action_rest( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_TELEPORT_FRONT, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_IN, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_DODGE_RIGHT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_TELEPORT_BEHIND, + ), + {0}, +}; + +static const lochara_combat_action_t combo3_[] = { + lochara_combat_action_rest( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_THRUST_IN, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_DODGE_RIGHT, + ), + {0}, +}; + +static const lochara_combat_action_t shoot1_[] = { + lochara_combat_action_rest( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_SHOOT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_DODGE_RIGHT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_SHOOT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_DODGE_LEFT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/2*3, + .state = LOCHARA_STATE_STAND, + ), + {0}, +}; + +static const lochara_combat_action_t down_[] = { + lochara_combat_action_rest( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_DOWN, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_*3, + .state = LOCHARA_STATE_REVIVE, + ), + {0}, +}; + +static const lochara_combat_action_t kill_[] = { + lochara_combat_action_rest( + .duration = BEAT_MS_*4, + .state = LOCHARA_STATE_DEAD, + ), + {0}, +}; + +static const lochara_combat_action_t dead_[] = { + lochara_combat_action_rest( + .duration = 30000, + .state = LOCHARA_STATE_DEAD, + ), + {0}, +}; + +static const statman_meta_t strategy_table_[] = { + { + .state = LOCHARA_STRATEGY_WAIT, + .name = "WAIT", + .initialize = lochara_strategy_initialize_any_, + .update = lochara_big_warder_update_wait_strategy_, + }, + { + .state = LOCHARA_STRATEGY_WAKE_UP, + .name = "WAKE_UP", + .initialize = lochara_strategy_initialize_any_, + .update = lochara_big_warder_update_wake_up_strategy_, + }, + { + .state = LOCHARA_STRATEGY_WAKE_UP_EVENT, + .name = "WAKE_UP_EVENT", + .initialize = lochara_big_warder_initialize_wake_up_strategy_, + .update = lochara_big_warder_update_wake_up_strategy_, + }, + { + .state = LOCHARA_STRATEGY_APPROACH, + .name = "APPROACH", + .initialize = lochara_strategy_initialize_any_, + .update = lochara_big_warder_update_approach_strategy_, + }, + + lochara_strategy_combat(COMBO1, + .state_table = state_table_, + .actions = combo1_, + .parry_window = 100, + .parried_next = LOCHARA_STRATEGY_COMBO3, + .next = LOCHARA_STRATEGY_APPROACH, + ), + lochara_strategy_combat(COMBO2, + .state_table = state_table_, + .actions = combo2_, + .parry_window = 100, + .parried_next = LOCHARA_STRATEGY_DOWN, + .next = LOCHARA_STRATEGY_COMBO3, + ), + lochara_strategy_combat(COMBO3, + .state_table = state_table_, + .actions = combo3_, + .parried_next = LOCHARA_STRATEGY_DOWN, + .next = LOCHARA_STRATEGY_APPROACH, + ), + lochara_strategy_combat(SHOOT1, + .state_table = state_table_, + .actions = shoot1_, + .parry_window = 200, + .parried_next = LOCHARA_STRATEGY_DOWN, + .gravity = true, + .next = LOCHARA_STRATEGY_APPROACH, + ), + + lochara_strategy_combat(DOWN, + .state_table = state_table_, + .actions = down_, + .gravity = true, + .next = LOCHARA_STRATEGY_APPROACH, + ), + lochara_strategy_combat(KILL, + .state_table = state_table_, + .actions = kill_, + .gravity = true, + .next = LOCHARA_STRATEGY_WAIT, + ), + lochara_strategy_combat(DEAD, + .state_table = state_table_, + .actions = dead_, + .gravity = true, + .next = LOCHARA_STRATEGY_WAIT, + ), + {0}, +}; + +static void lochara_big_warder_update_event_(lochara_base_t* base) { + assert(base != NULL); + + static const loplayer_event_command_t wake_up[] = { + loplayer_event_command_play_music(LORESOURCE_MUSIC_ID_BOSS_BIG_WARDER), + loplayer_event_command_set_area(.49f, .45f), + loplayer_event_command_set_cinescope(1), + loplayer_event_command_wait(BEAT_MS_*4), + + loplayer_event_command_set_line("boss_big_warder_line0"), + loplayer_event_command_wait(BEAT_MS_*8), + loplayer_event_command_set_line("boss_big_warder_line1"), + loplayer_event_command_wait(BEAT_MS_*4), + + loplayer_event_command_set_line(NULL), + loplayer_event_command_set_cinescope(0), + {0}, + }; + static const loplayer_event_command_t kill[] = { + loplayer_event_command_set_area(0, 0), + loplayer_event_command_set_cinescope(1), + loplayer_event_command_wait(BEAT_MS_), + loplayer_event_command_stop_music(), + + loplayer_event_command_set_line("boss_big_warder_kill_line"), + loplayer_event_command_wait(BEAT_MS_*4), + + loplayer_event_command_finalize(), + {0}, + }; + static const loplayer_event_command_t dead[] = { + loplayer_event_command_set_area(0, 0), + loplayer_event_command_wait(BEAT_MS_), + loplayer_event_command_stop_music(), + loplayer_event_command_finalize(), + {0}, + }; + + const uint64_t t = base->ticker->time; + + loplayer_event_t* event = &base->player->event; + const loentity_id_t id = base->super.super.id; + + locommon_position_t basepos = base->super.super.pos; + basepos.fract = vec2(.5f, .5f); + + if (base->param.strategy == LOCHARA_STRATEGY_WAKE_UP_EVENT) { + loplayer_event_execute_commands(event, id, &basepos, wake_up); + return; + } + if (event->executor != id) return; + + if (base->player->entity->param.state == LOCHARA_STATE_DEAD) { + statman_transition_to( + strategy_table_, base, &base->param.strategy, LOCHARA_STRATEGY_KILL); + loplayer_event_execute_commands(event, id, &basepos, kill); + return; + } + if (base->param.strategy == LOCHARA_STRATEGY_DEAD) { + loplayer_event_execute_commands(event, id, &basepos, dead); + if (!loplayer_stance_set_has(&base->player->stances, REWARD_STANCE_)) { + loplayer_stance_set_add(&base->player->stances, REWARD_STANCE_); + loplayer_popup_queue_new_stance(&base->player->popup, REWARD_STANCE_); + } + return; + } + if (base->player->event.basetime+MUSIC_DURATION_ <= t && + loeffect_recipient_is_alive(&base->param.recipient)) { + loentity_character_apply_effect( + &base->player->entity->super, &loeffect_curse_trigger()); + return; + } + loplayer_event_execute_commands(event, id, &basepos, wake_up); +} + +bool lochara_big_warder_update(lochara_base_t* base) { + assert(base != NULL); + + loeffect_recipient_update(&base->param.recipient, &base_status_); + + statman_update(strategy_table_, base, &base->param.strategy); + lochara_big_warder_update_event_(base); + + const float dir = MATH_SIGN_NOZERO(base->param.direction.x); + base->cache.instance = (loshader_character_drawer_instance_t) { + .character_id = LOSHADER_CHARACTER_ID_WARDER, + .pos = vec2(0, -MARKER_), + .size = vec2(dir*HEIGHT_, HEIGHT_), + .color = COLOR_, + .marker_offset = vec2(0, MARKER_), + }; + statman_update(state_table_, base, &base->param.state); + + if (base->param.strategy != LOCHARA_STRATEGY_WAIT && + base->param.strategy != LOCHARA_STRATEGY_WAKE_UP && + base->param.strategy != LOCHARA_STRATEGY_WAKE_UP_EVENT && + base->param.strategy != LOCHARA_STRATEGY_DEAD) { + base->cache.instance.marker = lochara_base_affect_bullets(base); + } + + lochara_base_calculate_physics( + base, &vec2(WIDTH_, HEIGHT_), &vec2(0, MARKER_)); + lochara_base_bind_on_ground(base, &vec2(WIDTH_, HEIGHT_+MARKER_)); + return true; +} + +void lochara_big_warder_build( + lochara_base_t* base, loentity_ground_t* gnd) { + assert(base != NULL); + assert(gnd != NULL); + + base->super.super.pos = gnd->super.pos; + vec2_addeq(&base->super.super.pos.fract, &vec2(0, gnd->size.y)); + locommon_position_reduce(&base->super.super.pos); + + base->param = (typeof(base->param)) { + .type = LOCHARA_TYPE_BIG_WARDER, + .state = LOCHARA_STATE_DEAD, + .last_state_changed = base->ticker->time, + .strategy = LOCHARA_STRATEGY_WAIT, + .last_strategy_changed = base->ticker->time, + + .ground = gnd->super.id, + }; + loeffect_recipient_initialize( + &base->param.recipient, base->ticker, &base_status_); +} diff --git a/core/lochara/big_warder.h b/core/lochara/big_warder.h new file mode 100644 index 0000000..3219469 --- /dev/null +++ b/core/lochara/big_warder.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "core/loentity/ground.h" + +#include "./base.h" + +bool +lochara_big_warder_update( + lochara_base_t* base +); + +void +lochara_big_warder_build( + lochara_base_t* base, + loentity_ground_t* gnd +); diff --git a/core/lochara/cavia.c b/core/lochara/cavia.c new file mode 100644 index 0000000..039505a --- /dev/null +++ b/core/lochara/cavia.c @@ -0,0 +1,305 @@ +#include "./cavia.h" + +#include +#include +#include + +#include "util/math/algorithm.h" +#include "util/math/vector.h" +#include "util/statman/statman.h" + +#include "core/lobullet/base.h" +#include "core/lobullet/linear.h" +#include "core/loeffect/effect.h" +#include "core/loeffect/recipient.h" +#include "core/loentity/ground.h" +#include "core/loresource/sound.h" +#include "core/loshader/character.h" + +#include "./base.h" +#include "./combat.h" + +#define WIDTH_ .02f +#define HEIGHT_ .05f +#define MARKER_ .02f +#define COLOR_ vec4(0, 0, 0, 1) + +static const loeffect_recipient_status_t base_status_ = { + .attack = .1f, + .defence = .3f, + .speed = .05f, + .jump = 1.f, +}; + +static void lochara_cavia_update_thrust_in_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + static const uint64_t dur = 100; + + lochara_base_t* base = instance; + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + + const float tf = t*1.f / dur; + base->cache.instance.motion.time = powf(tf, 2); + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; +} + +static void lochara_cavia_update_thrust_out_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + static const uint64_t dur = 100; + + lochara_base_t* base = instance; + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + + const float tf = t*1.f / dur; + base->cache.instance.motion.time = powf(tf, 2); + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; +} + +static void lochara_cavia_initialize_dead_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + lochara_state_initialize_any_(meta, instance, state); + + lochara_base_t* base = instance; + for (size_t i = 0; i < 12; ++i) { + const float t = MATH_PI/6*i; + + vec2_t v, a, p; + p = vec2(cos(t), sin(t)); + vec2_mul(&v, &p, .7f); + vec2_mul(&a, &p, -1.4f); + vec2_muleq(&p, .1f); + + locommon_position_t pos = base->super.super.pos; + vec2_addeq(&pos.fract, &p); + locommon_position_reduce(&pos); + + lobullet_base_t* b = lobullet_pool_create(base->bullet); + lobullet_linear_triangle_build(b, + .owner = b->super.super.id, + .basepos = pos, + .velocity = v, + .acceleration = a, + .size = vec2(.01f, .045f), + .color = vec4(0, 0, 0, .8f), + .angle = t-MATH_PI, + .knockback = 1, + .effect = loeffect_damage(.1f), + .duration = 1200, + ); + loentity_store_add(base->entities, &b->super.super); + } + loresource_sound_set_play(&base->res->sound, LORESOURCE_SOUND_ID_ENEMY_TRIGGER); +} + +static void lochara_cavia_update_dead_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + lochara_base_t* base = instance; + base->param.movement = vec2(0, 0); + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > 2000) { + t = 2000; + } + if (meta->state == LOCHARA_STATE_RESUSCITATE) { + if (t == 0) { + loeffect_recipient_apply_effect( + &base->param.recipient, &loeffect_resuscitate()); + } + t = 2000 - t; + } + + if (t < 1000) { + const float tf = t/1000.f; + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_STAND1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_SIT; + base->cache.instance.motion.time = powf(tf, 6); + } else { + const float tf = (t-1000)/1000.f; + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_SIT; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_DOWN; + base->cache.instance.motion.time = powf(tf, 4); + } +} + +static const statman_meta_t state_table_[] = { + lochara_state_stand( + .period = 4000, + .acceleration = {{5, 5}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_STAND2, + ), + lochara_state_walk( + .period = 1000, + .acceleration = {{5, 5}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_WALK, + ), + { + .state = LOCHARA_STATE_THRUST_IN, + .name = "THRUST_IN", + .initialize = lochara_state_initialize_any_, + .update = lochara_cavia_update_thrust_in_, + }, + { + .state = LOCHARA_STATE_THRUST_OUT, + .name = "THRUST_OUT", + .initialize = lochara_state_initialize_any_, + .update = lochara_cavia_update_thrust_out_, + }, + { + .state = LOCHARA_STATE_DEAD, + .name = "DEAD", + .initialize = lochara_cavia_initialize_dead_, + .update = lochara_cavia_update_dead_, + }, + { + .state = LOCHARA_STATE_RESUSCITATE, + .name = "RESUSCITATE", + .initialize = lochara_state_initialize_any_, + .update = lochara_cavia_update_dead_, + }, + {0}, +}; + +static const lochara_combat_action_t combo1_[] = { + lochara_combat_action_rest( + .duration = 300, + .state = LOCHARA_STATE_STAND, + ), + lochara_combat_action_attack( + .duration = 300, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1.2f, + ), + lochara_combat_action_rest( + .duration = 100, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = 150, + .state = LOCHARA_STATE_THRUST_IN, + .damage = .8f, + ), + lochara_combat_action_rest( + .duration = 150, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = 150, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = 1000, + .state = LOCHARA_STATE_THRUST_OUT, + ), + {0}, +}; + +static const lochara_combat_action_t dead_[] = { + lochara_combat_action_rest( + .duration = 30000, + .state = LOCHARA_STATE_DEAD, + ), + lochara_combat_action_rest( + .duration = 2000, + .state = LOCHARA_STATE_RESUSCITATE, + ), + {0}, +}; + +static const statman_meta_t strategy_table_[] = { + lochara_strategy_scouting( + .state_table = state_table_, + .period = 2000, + .stagger = .5f, + .range_close = WIDTH_*2, + .found_close = LOCHARA_STRATEGY_COMBO1, + .range_back = 1, + ), + lochara_strategy_combat(COMBO1, + .state_table = state_table_, + .actions = combo1_, + .next = LOCHARA_STRATEGY_SCOUTING, + ), + lochara_strategy_combat(DEAD, + .state_table = state_table_, + .actions = dead_, + .next = LOCHARA_STRATEGY_SCOUTING, + ), + {0}, +}; + +bool lochara_cavia_update(lochara_base_t* base) { + assert(base != NULL); + + loeffect_recipient_update(&base->param.recipient, &base_status_); + + statman_update(strategy_table_, base, &base->param.strategy); + + const float dir = MATH_SIGN_NOZERO(base->param.direction.x); + base->cache.instance = (loshader_character_drawer_instance_t) { + .character_id = LOSHADER_CHARACTER_ID_CAVIA, + .pos = vec2(0, -MARKER_), + .size = vec2(dir*HEIGHT_, HEIGHT_), + .color = COLOR_, + .marker_offset = vec2(0, MARKER_), + }; + statman_update(state_table_, base, &base->param.state); + + if (base->param.state != LOCHARA_STATE_DEAD) { + base->cache.instance.marker = lochara_base_affect_bullets(base); + } + + lochara_base_calculate_physics( + base, &vec2(WIDTH_, HEIGHT_), &vec2(0, MARKER_)); + lochara_base_bind_on_ground(base, &vec2(WIDTH_, HEIGHT_+MARKER_)); + return true; +} + +void lochara_cavia_build( + lochara_base_t* base, const loentity_ground_t* gnd, float pos) { + assert(base != NULL); + assert(gnd != NULL); + assert(MATH_FLOAT_VALID(pos)); + + base->super.super.pos = gnd->super.pos; + vec2_addeq( + &base->super.super.pos.fract, + &vec2(gnd->size.x*pos, gnd->size.y)); + locommon_position_reduce(&base->super.super.pos); + + base->param = (typeof(base->param)) { + .type = LOCHARA_TYPE_CAVIA, + .state = LOCHARA_STATE_STAND, + .last_state_changed = base->ticker->time, + .strategy = LOCHARA_STRATEGY_SCOUTING, + .last_strategy_changed = base->ticker->time, + + .ground = gnd->super.id, + }; + loeffect_recipient_initialize( + &base->param.recipient, base->ticker, &base_status_); +} diff --git a/core/lochara/cavia.h b/core/lochara/cavia.h new file mode 100644 index 0000000..6df2937 --- /dev/null +++ b/core/lochara/cavia.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "core/loentity/ground.h" + +#include "./base.h" + +bool +lochara_cavia_update( + lochara_base_t* base +); + +void +lochara_cavia_build( + lochara_base_t* base, + const loentity_ground_t* gnd, + float pos +); diff --git a/core/lochara/combat.c b/core/lochara/combat.c new file mode 100644 index 0000000..6bca766 --- /dev/null +++ b/core/lochara/combat.c @@ -0,0 +1,79 @@ +#include "./combat.h" + +#include +#include +#include + +#include "util/math/algorithm.h" + +#include "core/loeffect/effect.h" +#include "core/loentity/character.h" +#include "core/loplayer/combat.h" + +#include "./base.h" +#include "./state.h" + +static void lochara_combat_action_handle_attack_( + const loplayer_combat_attack_t* attack, + loplayer_combat_attack_result_t result) { + assert(attack != NULL); + + lochara_base_t* attacker = attack->data1; + /* TODO(catfoot): store the result in the attacker */ + if (result != LOPLAYER_COMBAT_ATTACK_RESULT_EXECUTED) return; + + const float v = attacker->param.recipient.status.attack* + MATH_SIGN_NOZERO(attacker->param.direction.x); + loentity_character_knockback(&attacker->player->entity->super, &vec2(v, 0)); + + const lochara_combat_action_t* action = attack->data2; + + switch (action->type) { + case LOCHARA_COMBAT_ACTION_TYPE_REST: + break; + case LOCHARA_COMBAT_ACTION_TYPE_ATTACK: + loentity_character_apply_effect( + &attacker->player->entity->super, + &loeffect_damage( + action->damage*attacker->param.recipient.status.attack)); + break; + case LOCHARA_COMBAT_ACTION_TYPE_ATTACK_EFFECT: + loentity_character_apply_effect( + &attacker->player->entity->super, &action->effect); + break; + } +} + +void lochara_combat_action_execute_all_attacks( + const lochara_combat_action_t* actions, lochara_base_t* attacker) { + assert(actions != NULL); + assert(attacker != NULL); + + loplayer_combat_t* combat = &attacker->player->combat; + + uint64_t t = attacker->ticker->time; + for (; actions->duration != 0; t += actions->duration, ++actions) { + if (actions->type == LOCHARA_COMBAT_ACTION_TYPE_REST) continue; + loplayer_combat_add_attack( + combat, + &(loplayer_combat_attack_t) { + .attacker = attacker->super.super.id, + .start = t, + .duration = actions->duration, + .data1 = attacker, + .data2 = (void*) actions, + .handle = lochara_combat_action_handle_attack_, + }); + } +} + +const lochara_combat_action_t* lochara_combat_action_find_by_time( + const lochara_combat_action_t* actions, uint64_t time) { + assert(actions != NULL); + + while (actions->duration != 0 && actions->duration <= time) { + time -= actions->duration; + ++actions; + } + return actions->duration > 0? actions: NULL; +} diff --git a/core/lochara/combat.h b/core/lochara/combat.h new file mode 100644 index 0000000..4acc8ed --- /dev/null +++ b/core/lochara/combat.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include "core/loeffect/effect.h" + +#include "./state.h" + +typedef struct lochara_base_t lochara_base_t; + +typedef enum { + LOCHARA_COMBAT_ACTION_TYPE_REST, + LOCHARA_COMBAT_ACTION_TYPE_ATTACK, + LOCHARA_COMBAT_ACTION_TYPE_ATTACK_EFFECT, +} lochara_combat_action_type_t; + +typedef struct { + lochara_combat_action_type_t type; + lochara_state_t state; + uint64_t duration; + + union { + float damage; + loeffect_t effect; + }; +} lochara_combat_action_t; + +#define lochara_combat_action_rest(...) { \ + .type = LOCHARA_COMBAT_ACTION_TYPE_REST, \ + __VA_ARGS__ \ +} +#define lochara_combat_action_attack(...) { \ + .type = LOCHARA_COMBAT_ACTION_TYPE_ATTACK, \ + __VA_ARGS__ \ +} +#define lochara_combat_action_attack_effect(...) { \ + .type = LOCHARA_COMBAT_ACTION_TYPE_ATTACK_EFFECT, \ + __VA_ARGS__ \ +} + +void +lochara_combat_action_execute_all_attacks( + const lochara_combat_action_t* actions, + lochara_base_t* attacker +); + +const lochara_combat_action_t* /* NULLABLE */ +lochara_combat_action_find_by_time( + const lochara_combat_action_t* actions, + uint64_t t +); diff --git a/core/lochara/encephalon.c b/core/lochara/encephalon.c new file mode 100644 index 0000000..dcab0f0 --- /dev/null +++ b/core/lochara/encephalon.c @@ -0,0 +1,85 @@ +#include "./encephalon.h" + +#include +#include +#include +#include + +#include "util/chaos/xorshift.h" +#include "util/math/vector.h" + +#include "core/locommon/position.h" +#include "core/loeffect/effect.h" +#include "core/loeffect/recipient.h" +#include "core/loentity/ground.h" +#include "core/loshader/character.h" + +#include "./base.h" + +#define WIDTH_ .1f +#define HEIGHT_ .1f +#define RANGE_ .15f +#define COLOR_ vec4(0, 0, 0, .8f) + +bool lochara_encephalon_update(lochara_base_t* base) { + assert(base != NULL); + + base->cache.instance = (loshader_character_drawer_instance_t) { + .character_id = LOSHADER_CHARACTER_ID_ENCEPHALON, + .size = vec2(WIDTH_, HEIGHT_), + .color = COLOR_, + }; + + vec2_t disp; + locommon_position_sub( + &disp, &base->player->entity->super.super.pos, &base->super.super.pos); + + const bool active = fabsf(disp.x) < RANGE_ && fabsf(disp.y) < HEIGHT_; + if (active) { + if (base->param.state != LOCHARA_STATE_SPELL) { + loresource_sound_set_play( + &base->res->sound, LORESOURCE_SOUND_ID_TOUCH_GATE); + base->param.last_state_changed = base->ticker->time; + } + base->param.state = LOCHARA_STATE_SPELL; + + loentity_character_apply_effect( + &base->player->entity->super, &loeffect_resuscitate()); + base->player->entity->param.anchor.pos = + base->player->entity->super.super.pos; + + if (base->param.last_state_changed+500 > base->ticker->time) { + base->cache.instance.color.w = chaos_xorshift(base->ticker->time)%3 >= 1; + } + } else { + base->param.state = LOCHARA_STATE_STAND; + } + + if (base->cache.ground == NULL) return false; + base->super.super.pos = base->cache.ground->super.pos; + base->super.super.pos.fract.y += base->cache.ground->size.y + HEIGHT_; + locommon_position_reduce(&base->super.super.pos); + + return true; +} + +void lochara_encephalon_build( + lochara_base_t* base, const loentity_ground_t* gnd) { + assert(base != NULL); + assert(gnd != NULL); + + base->super.super.pos = gnd->super.pos; + base->super.super.pos.fract.y += gnd->size.y + HEIGHT_; + locommon_position_reduce(&base->super.super.pos); + + base->param = (typeof(base->param)) { + .type = LOCHARA_TYPE_ENCEPHALON, + .state = LOCHARA_STATE_STAND, + .last_state_changed = base->ticker->time, + .ground = gnd->super.id, + }; + loeffect_recipient_initialize( + &base->param.recipient, + base->ticker, + &(loeffect_recipient_status_t) {0}); +} diff --git a/core/lochara/encephalon.h b/core/lochara/encephalon.h new file mode 100644 index 0000000..1805db2 --- /dev/null +++ b/core/lochara/encephalon.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "core/loentity/ground.h" + +#include "./base.h" + +bool +lochara_encephalon_update( + lochara_base_t* base +); + +void +lochara_encephalon_build( + lochara_base_t* base, + const loentity_ground_t* gnd +); diff --git a/core/lochara/player.c b/core/lochara/player.c new file mode 100644 index 0000000..98f4cc5 --- /dev/null +++ b/core/lochara/player.c @@ -0,0 +1,492 @@ +#include "./player.h" + +#include +#include +#include +#include + +#include "util/math/algorithm.h" +#include "util/math/vector.h" +#include "util/statman/statman.h" + +#include "core/lobullet/linear.h" +#include "core/lobullet/pool.h" +#include "core/locommon/easing.h" +#include "core/locommon/position.h" +#include "core/loeffect/effect.h" +#include "core/loeffect/recipient.h" +#include "core/loentity/store.h" +#include "core/loplayer/stance.h" +#include "core/loshader/character.h" + +#include "./base.h" +#include "./state.h" +#include "./type.h" + +#define INITIAL_POS_ locommon_position(0, 0, vec2(.5f, .8f)) + +#define WIDTH_ .02f +#define HEIGHT_ .05f +#define MARKER_ .03f +#define COLOR_ vec4(0, 0, 0, 1) + +#define RESPAWN_DURATION_ 4000 + +#define BULLET_SIZE_ vec2(.02f, .02f) +#define BULLET_COLOR_ vec4(1, .9f, .9f, 1) +#define BULLET_KNOCKBACK_ 4 +#define BULLET_DAMAGE_ .2f +#define BULLET_DURATION_ 1000 +#define BULLET_COST_ .06f + +#define CAMERA_SPEED_ 10 +#define CAMERA_SHIFT_Y_ .1f + +#define CAMERA_FADE_RADIAL_ .6f + +#define CAMERA_DEAD_FADE_ 2 +#define CAMERA_DEAD_SPEED_ .3f +#define CAMERA_DEAD_RECOVERY_SPEED_ 10 + +#define CAMERA_COMBAT_SPEED_ 10 +#define CAMERA_COMBAT_RECOVERY_SPEED_ 5 + +#define CAMERA_ENEMY_ATTACK_INTENSITY_ .2f +#define CAMERA_ENEMY_ATTACK_SPEED_ 4 + +#define CAMERA_DAMAGE_INTENSITY_ .5f +#define CAMERA_DAMAGE_DURATION_ 1000 + +#define CAMERA_ABERRATION_ 1 + +#define CAMERA_CORRUPTION_THRESH_ .2f +#define CAMERA_CORRUPTION_PERIOD_ 4000 + +#define DIRECTION_X_EPSILON_ .005f + +#define GUARD_THRESHOLD_ .8f +#define BACKGUARD_THRESHOLD_ .95f + +static const loeffect_recipient_status_t base_status_ = { + .attack = .2f, + .defence = .2f, + .speed = .3f, + .jump = 1.f, +}; + +static void lochara_player_update_dead_state_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + lochara_base_t* base = instance; + base->param.movement = vec2(0, 0); + + const uint64_t t = base->ticker->time - base->param.last_state_changed; + + if (t >= RESPAWN_DURATION_ && base->player->event.executor == 0) { + loeffect_recipient_apply_effect( + &base->param.recipient, &loeffect_resuscitate()); + base->super.super.pos = base->param.anchor.pos; + + *next = LOCHARA_STATE_STAND; + return; + } + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_STAND1; + base->cache.instance.motion.time = 0; +} + +static void lochara_player_update_shoot_state_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + static const uint64_t dur = 200; + + lochara_base_t* base = instance; + + const uint64_t t = base->ticker->time - base->param.last_state_changed; + const float dt = base->ticker->delta_f; + + locommon_easing_linear_float(&base->param.movement.x, 0, dt); + locommon_easing_linear_float(&base->param.movement.y, 0, dt); + + const bool has_stance = loplayer_stance_set_has( + &base->player->stances, LOPLAYER_STANCE_REVOLUTIONER); + + if (has_stance && t >= dur && base->param.recipient.faith > 0) { + locommon_position_t pos = base->super.super.pos; + pos.fract.x += WIDTH_*MATH_SIGN_NOZERO(base->param.direction.x); + locommon_position_reduce(&pos); + + lobullet_base_t* b = lobullet_pool_create(base->bullet); + lobullet_linear_circle_build(b, + .owner = base->super.super.id, + .basepos = pos, + .size = BULLET_SIZE_, + .color = BULLET_COLOR_, + .velocity = base->param.direction, + .knockback = BULLET_KNOCKBACK_, + .effect = loeffect_damage( + base->param.recipient.status.attack*BULLET_DAMAGE_), + .duration = BULLET_DURATION_,); + loentity_store_add(base->entities, &b->super.super); + + loentity_character_apply_effect( + &base->super, &loeffect_lost(BULLET_COST_)); + base->param.last_state_changed = base->ticker->time; + } + + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_STAND1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_STAND2; + base->cache.instance.motion.time = t > dur? 1: t*1.f / dur; +} + +static const statman_meta_t state_table_[] = { + lochara_state_stand( + .period = 2000, + .acceleration = {{5, 5}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_STAND2, + ), + lochara_state_walk( + .period = 350, + .acceleration = {{5, 5}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_WALK, + ), + lochara_state_sprint( + .period = 300, + .acceleration = {{5, 5}}, + .speed = 1.4f, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_WALK, + ), + lochara_state_dodge( + .duration = 100, + .acceleration = {{3, 3}}, + .speed = 1, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_WALK, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + ), + lochara_state_jump(), + + { + .state = LOCHARA_STATE_GUARD, + .name = "GUARD", + .data = &(lochara_state_move_param_t) { + .speed = 0, + .period = 1000, + .acceleration = {{10, 10}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + }, + .initialize = lochara_state_initialize_any_, + .update = lochara_state_update_move_, + }, + { + .state = LOCHARA_STATE_SHOOT, + .name = "SHOOT", + .initialize = lochara_state_initialize_any_, + .update = lochara_player_update_shoot_state_, + }, + { + .state = LOCHARA_STATE_DEAD, + .name = "DEAD", + .initialize = lochara_state_initialize_any_, + .update = lochara_player_update_dead_state_, + .finalize = lochara_state_cancel_transition_, + }, + {0}, +}; + +static void lochara_player_handle_controller_(lochara_base_t* base) { + assert(base != NULL); + + lochara_state_t next = base->param.state; + switch (base->player->controller.state) { + case LOPLAYER_CONTROLLER_STATE_NONE: + next = LOCHARA_STATE_STAND; + break; + case LOPLAYER_CONTROLLER_STATE_WALK_LEFT: + next = LOCHARA_STATE_WALK_LEFT; + break; + case LOPLAYER_CONTROLLER_STATE_WALK_RIGHT: + next = LOCHARA_STATE_WALK_RIGHT; + break; + case LOPLAYER_CONTROLLER_STATE_SPRINT_LEFT: + next = LOCHARA_STATE_SPRINT_LEFT; + break; + case LOPLAYER_CONTROLLER_STATE_SPRINT_RIGHT: + next = LOCHARA_STATE_SPRINT_RIGHT; + break; + case LOPLAYER_CONTROLLER_STATE_DODGE_FORWARD: + next = + base->param.direction.x < 0? + LOCHARA_STATE_DODGE_LEFT: + LOCHARA_STATE_DODGE_RIGHT; + break; + case LOPLAYER_CONTROLLER_STATE_DODGE_LEFT: + next = LOCHARA_STATE_DODGE_LEFT; + break; + case LOPLAYER_CONTROLLER_STATE_DODGE_RIGHT: + next = LOCHARA_STATE_DODGE_RIGHT; + break; + case LOPLAYER_CONTROLLER_STATE_JUMP: + if (base->param.on_ground) next = LOCHARA_STATE_JUMP; + break; + case LOPLAYER_CONTROLLER_STATE_GUARD: + next = LOCHARA_STATE_GUARD; + break; + case LOPLAYER_CONTROLLER_STATE_SHOOT: + next = LOCHARA_STATE_SHOOT; + break; + } + + if (loplayer_combat_is_attack_pending(&base->player->combat)) { + if (next != LOCHARA_STATE_STAND && + next != LOCHARA_STATE_DODGE_LEFT && + next != LOCHARA_STATE_DODGE_RIGHT && + next != LOCHARA_STATE_GUARD) { + next = LOCHARA_STATE_STAND; + } + } else { + vec2_t dir; + locommon_position_sub( + &dir, &base->player->controller.cursor, &base->super.super.pos); + if (fabsf(dir.x) > DIRECTION_X_EPSILON_) { + vec2_div(&base->param.direction, &dir, vec2_length(&dir)); + } + } + statman_transition_to(state_table_, base, &base->param.state, next); +} + +static void lochara_player_update_combat_(lochara_base_t* base) { + assert(base != NULL); + + const lochara_state_t state = base->param.state; + + if (state == LOCHARA_STATE_DEAD) { + loplayer_combat_set_accepting( + &base->player->combat, + false, + LOPLAYER_COMBAT_ATTACK_RESULT_ABORTED); + } else { + loplayer_combat_set_accepting( + &base->player->combat, + state != LOCHARA_STATE_DODGE_LEFT && + state != LOCHARA_STATE_DODGE_RIGHT, + LOPLAYER_COMBAT_ATTACK_RESULT_DODGED); + } + + loplayer_combat_set_guarding( + &base->player->combat, + state == LOCHARA_STATE_GUARD); + + if (loplayer_combat_is_attack_pending(&base->player->combat)) { + base->param.movement = vec2(0, 0); + base->param.gravity = 0; + } + + float r; + loplayer_combat_attack_t a; + if (!loplayer_combat_pop_attack(&base->player->combat, &a, &r)) return; + + loentity_store_iterator_t itr; + if (!loentity_store_find_item_by_id(base->entities, &itr, a.attacker) || + itr.character == NULL) { + return; + } + vec2_t disp; + locommon_position_sub( + &disp, &itr.character->super.pos, &base->super.super.pos); + + const float dir = disp.x * base->param.direction.x; + const bool reflected = + r > (dir < 0? BACKGUARD_THRESHOLD_: GUARD_THRESHOLD_); + + loplayer_combat_attack_handle( + &a, + reflected? + LOPLAYER_COMBAT_ATTACK_RESULT_REFLECTED: + LOPLAYER_COMBAT_ATTACK_RESULT_EXECUTED); + if (!reflected) return; + + loresource_sound_set_play(&base->res->sound, LORESOURCE_SOUND_ID_REFLECTION); + + loentity_character_apply_effect( + itr.character, + &loeffect_damage(base->param.recipient.status.attack)); + + loentity_character_knockback( + itr.character, + &vec2(MATH_SIGN(disp.x)*base->param.recipient.status.attack, 0)); +} + +static void lochara_player_update_camera_(lochara_base_t* base) { + assert(base != NULL); + + const loeffect_recipient_t* r = &base->param.recipient; + const uint64_t t = base->ticker->time; + const uint64_t pt = base->ticker->prev_time; + const float dt = base->ticker->delta_f; + + const bool combat = loplayer_combat_is_attack_pending(&base->player->combat); + + loplayer_camera_t* camera = &base->player->camera; + + vec2_t sz = base->player->camera.chunk_winsz; + vec2_diveq(&sz, + base->player->camera.scale* + (camera->posteffect.distortion_radial+1)); + + locommon_position_t pos = base->super.super.pos; + if (!combat) { + pos.fract.y += CAMERA_SHIFT_Y_; + locommon_position_reduce(&pos); + } + + loplayer_event_bind_rect_in_area(&base->player->event, &pos, &sz); + + vec2_t disp; + locommon_position_sub(&disp, &pos, &camera->pos); + if (vec2_pow_length(&disp) < 1) { + locommon_easing_smooth_position(&camera->pos, &pos, dt*CAMERA_SPEED_); + } else { + camera->pos = pos; + } + locommon_easing_smooth_float(&camera->scale, 1, dt); + + /* ---- dead ---- */ + if (base->param.state == LOCHARA_STATE_DEAD) { + locommon_easing_smooth_float( + &camera->posteffect.fade_radial, + CAMERA_DEAD_FADE_, + dt*CAMERA_DEAD_SPEED_); + } else { + locommon_easing_smooth_float( + &camera->posteffect.fade_radial, + CAMERA_FADE_RADIAL_, + dt*CAMERA_DEAD_RECOVERY_SPEED_); + } + + /* ---- combat ---- */ + if (combat) { + locommon_easing_smooth_float( + &camera->posteffect.distortion_radial, + 1, + dt*CAMERA_COMBAT_SPEED_); + } else { + locommon_easing_smooth_float( + &camera->posteffect.distortion_radial, + 0, + dt*CAMERA_COMBAT_RECOVERY_SPEED_); + } + + /* ---- enemy attack ---- */ + const loplayer_combat_attack_t* attack = base->player->combat.first_attack; + if (attack != NULL && pt < attack->start && attack->start <= t) { + camera->posteffect.distortion_urgent = CAMERA_ENEMY_ATTACK_INTENSITY_; + } else { + locommon_easing_smooth_float( + &camera->posteffect.distortion_urgent, + 0, + dt*CAMERA_ENEMY_ATTACK_SPEED_); + } + + /* ---- damage ----- */ + if (0 < r->last_damage && + r->last_damage < t && t < r->last_damage+CAMERA_DAMAGE_DURATION_) { + camera->posteffect.raster_whole = + (1 - (t - r->last_damage)*1.f/CAMERA_DAMAGE_DURATION_)* + CAMERA_DAMAGE_INTENSITY_; + } else { + camera->posteffect.raster_whole = 0; + } + + /* ---- amnesia ---- */ + locommon_easing_smooth_float( + &camera->posteffect.distortion_amnesia, + !!(r->effects.amnesia.start < t && + t < r->effects.amnesia.start+r->effects.amnesia.duration), + dt); + + /* ---- corruption ---- */ + if (r->madness <= CAMERA_CORRUPTION_THRESH_) { + if (camera->corruption_since == 0) camera->corruption_since = t; + const uint64_t p = + (t - camera->corruption_since)%CAMERA_CORRUPTION_PERIOD_; + camera->pixsort = 1-powf(p*1.f/CAMERA_CORRUPTION_PERIOD_, 2); + } else { + camera->corruption_since = 0; + locommon_easing_smooth_float(&camera->pixsort, 0, dt); + } + + /* ---- passive ---- */ + locommon_easing_smooth_float( + &camera->posteffect.aberration_radial, CAMERA_ABERRATION_, dt); +} + +bool lochara_player_update(lochara_base_t* base) { + assert(base != NULL); + + loeffect_recipient_update(&base->param.recipient, &base_status_); + if (!loeffect_recipient_is_alive(&base->param.recipient)) { + statman_transition_to( + state_table_, base, &base->param.state, LOCHARA_STATE_DEAD); + } + if (loplayer_stance_set_has( + &base->player->stances, LOPLAYER_STANCE_UNFINISHER)) { + if (base->param.recipient.faith > .5f) { + loeffect_recipient_apply_effect( + &base->param.recipient, &loeffect_heal(base->ticker->delta_f*.01f)); + } + } + + lochara_player_handle_controller_(base); + + const float dir = MATH_SIGN_NOZERO(base->param.direction.x); + base->cache.instance = (loshader_character_drawer_instance_t) { + .character_id = LOSHADER_CHARACTER_ID_PLAYER, + .pos = vec2(0, -MARKER_), + .size = vec2(dir*HEIGHT_, HEIGHT_), + .color = COLOR_, + .marker_offset = vec2(0, MARKER_), + }; + + statman_update(state_table_, base, &base->param.state); + + lochara_player_update_combat_(base); + + if (base->param.state != LOCHARA_STATE_DODGE_LEFT && + base->param.state != LOCHARA_STATE_DODGE_RIGHT && + base->param.state != LOCHARA_STATE_DEAD) { + base->cache.instance.marker = lochara_base_affect_bullets(base); + } + + lochara_base_calculate_physics( + base, &vec2(WIDTH_, HEIGHT_), &vec2(0, MARKER_)); + loplayer_event_bind_rect_in_area( + &base->player->event, + &base->super.super.pos, + &vec2(WIDTH_*.8f, HEIGHT_)); + + lochara_player_update_camera_(base); + return true; +} + +void lochara_player_build(lochara_base_t* base) { + assert(base != NULL); + + base->super.super.pos = base->param.anchor.pos = INITIAL_POS_; + + base->param = (typeof(base->param)) { + .type = LOCHARA_TYPE_PLAYER, + .state = LOCHARA_STATE_STAND, + .last_state_changed = base->ticker->time, + }; + loeffect_recipient_initialize( + &base->param.recipient, base->ticker, &base_status_); +} diff --git a/core/lochara/player.h b/core/lochara/player.h new file mode 100644 index 0000000..85a62b9 --- /dev/null +++ b/core/lochara/player.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "./base.h" + +bool +lochara_player_update( + lochara_base_t* base +); + +void +lochara_player_build( + lochara_base_t* base +); diff --git a/core/lochara/pool.c b/core/lochara/pool.c new file mode 100644 index 0000000..b4f8506 --- /dev/null +++ b/core/lochara/pool.c @@ -0,0 +1,58 @@ +#include "./pool.h" + +#include +#include + +#include + +#include "util/memory/memory.h" + +#include "core/lobullet/pool.h" +#include "core/locommon/counter.h" +#include "core/locommon/ticker.h" +#include "core/loentity/pool.h" +#include "core/loentity/entity.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" + +#include "./base.h" + +LOENTITY_POOL_SOURCE_TEMPLATE(lochara) + +lochara_pool_t* lochara_pool_new( + loresource_set_t* res, + loshader_set_t* shaders, + locommon_counter_t* idgen, + const locommon_ticker_t* ticker, + loentity_store_t* entities, + loplayer_t* player, + lobullet_pool_t* bullet, + size_t length) { + assert(res != NULL); + assert(shaders != NULL); + assert(idgen != NULL); + assert(ticker != NULL); + assert(entities != NULL); + assert(player != NULL); + assert(bullet != NULL); + assert(length > 0); + + lochara_pool_t* pool = + memory_new(sizeof(*pool) + (length-1)*sizeof(pool->items[0])); + *pool = (typeof(*pool)) { + .idgen = idgen, + .length = length, + }; + for (size_t i = 0; i < pool->length; ++i) { + lochara_base_initialize( + &pool->items[i], + res, + shaders, + ticker, + entities, + player, + bullet); + } + return pool; +} diff --git a/core/lochara/pool.h b/core/lochara/pool.h new file mode 100644 index 0000000..d1057ef --- /dev/null +++ b/core/lochara/pool.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +#include + +#include "core/lobullet/pool.h" +#include "core/locommon/counter.h" +#include "core/locommon/ticker.h" +#include "core/loentity/entity.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" + +#include "./base.h" + +struct lochara_pool_t; +typedef struct lochara_pool_t lochara_pool_t; + +lochara_pool_t* /* OWNERSHIP */ +lochara_pool_new( + loresource_set_t* res, + loshader_set_t* shaders, + locommon_counter_t* idgen, + const locommon_ticker_t* ticker, + loentity_store_t* entities, + loplayer_t* player, + lobullet_pool_t* bullet, + size_t length +); + +void +lochara_pool_delete( + lochara_pool_t* pool /* OWNERSHIP */ +); + +lochara_base_t* +lochara_pool_create( + lochara_pool_t* pool +); + +lochara_base_t* +lochara_pool_unpack_item( + lochara_pool_t* pool, + const msgpack_object* obj +); diff --git a/core/lochara/state.c b/core/lochara/state.c new file mode 100644 index 0000000..98bab5b --- /dev/null +++ b/core/lochara/state.c @@ -0,0 +1,179 @@ +#include "./state.h" + +#include +#include +#include +#include + +#include "util/math/algorithm.h" +#include "util/math/vector.h" +#include "util/statman/statman.h" + +#include "core/locommon/easing.h" +#include "core/loresource/sound.h" +#include "core/loshader/character.h" + +#include "./base.h" + +#define MIDAIR_SPEED_ .8f +#define BACKWALK_SPEED_ .6f + +void lochara_state_initialize_any_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + lochara_base_t* base = instance; + base->param.last_state_changed = base->ticker->time; +} +void lochara_state_cancel_transition_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + *state = meta->state; +} + +void lochara_state_update_move_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + const lochara_state_move_param_t* p = meta->data; + lochara_base_t* base = instance; + + const uint64_t t = base->ticker->time - base->param.last_state_changed; + const float dt = base->ticker->delta_f; + + assert(vec2_valid(&p->acceleration)); + assert(MATH_FLOAT_VALID(p->speed)); + assert(vec2_valid(&p->velocity)); + assert(p->period > 0); + + /* ---- acceleration ---- */ + float speed = p->speed*base->param.recipient.status.speed; + if (!base->param.on_ground) { + speed *= MIDAIR_SPEED_; + } + if (vec2_dot(&p->velocity, &base->param.direction) < 0) { + speed *= BACKWALK_SPEED_; + } + + vec2_t velocity = p->velocity; + vec2_muleq(&velocity, speed); + + locommon_easing_linear_float( + &base->param.movement.x, velocity.x, p->acceleration.x*dt); + locommon_easing_linear_float( + &base->param.movement.y, velocity.y, p->acceleration.y*dt); + + /* ---- periodic motion ---- */ + base->cache.instance.motion.time = + (!!base->param.on_ground)*(1-fabs(t%p->period*1.f/p->period*2 - 1)); + base->cache.instance.motion.from = p->motion1; + base->cache.instance.motion.to = p->motion2; +} + +void lochara_state_initialize_dodge_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + lochara_state_initialize_any_(meta, instance, state); + + lochara_base_t* base = instance; + loresource_sound_set_play(&base->res->sound, LORESOURCE_SOUND_ID_DODGE); +} + +void lochara_state_update_dodge_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + const lochara_state_dodge_param_t* p = meta->data; + lochara_base_t* base = instance; + + const uint64_t t = base->ticker->time - base->param.last_state_changed; + + assert(p->duration > 0); + assert(vec2_valid(&p->acceleration)); + assert(vec2_valid(&p->velocity)); + + if (t > p->duration) { + *state = LOCHARA_STATE_STAND; + return; + } + + /* ---- acceleration ---- */ + base->param.movement = p->acceleration; + + vec2_muleq(&base->param.movement, t/1000.f); + base->param.movement.x *= -MATH_SIGN(p->velocity.x); + base->param.movement.y *= -MATH_SIGN(p->velocity.y); + + vec2_addeq(&base->param.movement, &p->velocity); + + /* ---- motion ---- */ + base->cache.instance.motion.time = powf(t*1.f/p->duration, 1.2f); + base->cache.instance.motion.from = p->motion1; + base->cache.instance.motion.to = p->motion2; + + const float a = powf(t*2.f/p->duration-1, 2); + base->cache.instance.size.x *= (1-a)*.8f+1; + base->cache.instance.color.w *= MATH_MIN(a+.2f, 1); +} + +void lochara_state_initialize_jump_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + lochara_state_initialize_any_(meta, instance, next); + + lochara_base_t* base = instance; + base->param.gravity += base->param.recipient.status.jump; + *next = LOCHARA_STATE_STAND; +} + +void lochara_state_update_teleport_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + const lochara_state_teleport_param_t* p = meta->data; + lochara_base_t* base = instance; + + base->param.movement = vec2(0, 0); + + const uint64_t t = base->ticker->time - base->param.last_state_changed; + const uint64_t pt = + t == 0? 0: base->ticker->prev_time - base->param.last_state_changed; + + if (pt < p->duration/2 && p->duration/2 <= t) { + const lochara_base_t* player = base->player->entity; + + const float pdir = + MATH_SIGN_NOZERO(player->param.direction.x)*p->direction; + base->param.direction = vec2(-pdir, 0); + + vec2_t offset = p->offset; + offset.x *= pdir; + + base->super.super.pos = player->super.super.pos; + vec2_addeq(&base->super.super.pos.fract, &offset); + locommon_position_reduce(&base->super.super.pos); + } + + const float tf = fabsf(t*1.f/p->duration*2 - 1); + base->cache.instance.motion.from = p->motion2; + base->cache.instance.motion.to = p->motion1; + base->cache.instance.motion.time = tf; + base->cache.instance.color.w = tf; +} diff --git a/core/lochara/state.h b/core/lochara/state.h new file mode 100644 index 0000000..317a80c --- /dev/null +++ b/core/lochara/state.h @@ -0,0 +1,233 @@ +#pragma once + +#include + +#include "util/math/vector.h" +#include "util/statman/statman.h" + +#include "core/loshader/character.h" + +typedef enum { + /* BENUM BEGIN lochara_state */ + LOCHARA_STATE_STAND, + + LOCHARA_STATE_WALK_LEFT, + LOCHARA_STATE_WALK_RIGHT, + + LOCHARA_STATE_SPRINT_LEFT, + LOCHARA_STATE_SPRINT_RIGHT, + + LOCHARA_STATE_DODGE_LEFT, + LOCHARA_STATE_DODGE_RIGHT, + + LOCHARA_STATE_JUMP, + + LOCHARA_STATE_TELEPORT_BEHIND, + LOCHARA_STATE_TELEPORT_FRONT, + + LOCHARA_STATE_THRUST_IN, + LOCHARA_STATE_THRUST_OUT, + LOCHARA_STATE_SLASH, + LOCHARA_STATE_SPELL, + LOCHARA_STATE_SHOOT, + + LOCHARA_STATE_DOWN, + LOCHARA_STATE_DEAD, + LOCHARA_STATE_REVIVE, + LOCHARA_STATE_RESUSCITATE, + + LOCHARA_STATE_GUARD, + /* BENUM END */ +} lochara_state_t; + +/* generated benum utils */ +#include "core/lochara/benum/state.h" + + +/* ---- default state handlers ---- */ + +void +lochara_state_initialize_any_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); +void +lochara_state_cancel_transition_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + +void +lochara_state_update_move_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + +void +lochara_state_initialize_dodge_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + +void +lochara_state_update_dodge_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + +void +lochara_state_initialize_jump_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + +void +lochara_state_update_teleport_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + + +/* ---- state meta constructor ---- */ + +typedef struct { + vec2_t acceleration; + float speed; + vec2_t velocity; + + uint64_t period; + loshader_character_motion_id_t motion1; + loshader_character_motion_id_t motion2; +} lochara_state_move_param_t; +#define lochara_state_stand(...) \ + (statman_meta_t) { \ + .state = LOCHARA_STATE_STAND, \ + .name = "STAND", \ + .data = &(lochara_state_move_param_t) { \ + .speed = 0, \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_state_initialize_any_, \ + .update = lochara_state_update_move_, \ + } +#define lochara_state_walk(...) \ + (statman_meta_t) { \ + .state = LOCHARA_STATE_WALK_LEFT, \ + .name = "WALK_LEFT", \ + .data = &(lochara_state_move_param_t) { \ + .speed = 1, \ + .velocity = {{-1, 0}}, \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_state_initialize_any_, \ + .update = lochara_state_update_move_, \ + }, \ + (statman_meta_t) { \ + .state = LOCHARA_STATE_WALK_RIGHT, \ + .name = "WALK_RIGHT", \ + .data = &(lochara_state_move_param_t) { \ + .speed = 1, \ + .velocity = {{1, 0}}, \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_state_initialize_any_, \ + .update = lochara_state_update_move_, \ + } +#define lochara_state_sprint(...) \ + (statman_meta_t) { \ + .state = LOCHARA_STATE_SPRINT_LEFT, \ + .name = "SPRINT_LEFT", \ + .data = &(lochara_state_move_param_t) { \ + .velocity = {{-1, 0}}, \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_state_initialize_any_, \ + .update = lochara_state_update_move_, \ + }, \ + (statman_meta_t) { \ + .state = LOCHARA_STATE_SPRINT_RIGHT, \ + .name = "SPRINT_RIGHT", \ + .data = &(lochara_state_move_param_t) { \ + .velocity = {{1, 0}}, \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_state_initialize_any_, \ + .update = lochara_state_update_move_, \ + } + +typedef struct { + uint64_t duration; + float speed; + vec2_t acceleration; + vec2_t velocity; + + loshader_character_motion_id_t motion1; + loshader_character_motion_id_t motion2; +} lochara_state_dodge_param_t; +#define lochara_state_dodge(...) \ + (statman_meta_t) { \ + .state = LOCHARA_STATE_DODGE_LEFT, \ + .name = "DODGE_LEFT", \ + .data = &(lochara_state_dodge_param_t) { \ + .velocity = {{-1, 0}}, \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_state_initialize_dodge_, \ + .update = lochara_state_update_dodge_, \ + .finalize = lochara_state_cancel_transition_, \ + }, \ + (statman_meta_t) { \ + .state = LOCHARA_STATE_DODGE_RIGHT, \ + .name = "DODGE_RIGHT", \ + .data = &(lochara_state_dodge_param_t) { \ + .velocity = {{1, 0}}, \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_state_initialize_dodge_, \ + .update = lochara_state_update_dodge_, \ + .finalize = lochara_state_cancel_transition_, \ + } + +#define lochara_state_jump() \ + (statman_meta_t) { \ + .state = LOCHARA_STATE_JUMP, \ + .name = "JUMP", \ + .initialize = lochara_state_initialize_jump_, \ + } + +typedef struct { + uint64_t duration; + float direction; + vec2_t offset; + + loshader_character_motion_id_t motion1; + loshader_character_motion_id_t motion2; +} lochara_state_teleport_param_t; +#define lochara_state_teleport(...) \ + (statman_meta_t) { \ + .state = LOCHARA_STATE_TELEPORT_FRONT, \ + .name = "TELEPORT_FRONT", \ + .data = &(lochara_state_teleport_param_t) { \ + .direction = 1, \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_state_initialize_any_, \ + .update = lochara_state_update_teleport_, \ + }, \ + (statman_meta_t) { \ + .state = LOCHARA_STATE_TELEPORT_BEHIND, \ + .name = "TELEPORT_BEHIND", \ + .data = &(lochara_state_teleport_param_t) { \ + .direction = -1, \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_state_initialize_any_, \ + .update = lochara_state_update_teleport_, \ + } diff --git a/core/lochara/strategy.c b/core/lochara/strategy.c new file mode 100644 index 0000000..1c767a5 --- /dev/null +++ b/core/lochara/strategy.c @@ -0,0 +1,184 @@ +#include "./strategy.h" + +#include +#include +#include +#include + +#include "util/chaos/xorshift.h" +#include "util/math/algorithm.h" +#include "util/math/vector.h" +#include "util/statman/statman.h" + +#include "core/loeffect/effect.h" +#include "core/loeffect/recipient.h" + +#include "./base.h" +#include "./combat.h" +#include "./state.h" + +#define SEED_ 3467 + +#define PARRY_DAMAGE_ 1 + +void lochara_strategy_initialize_any_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + lochara_base_t* base = instance; + base->param.last_strategy_changed = base->ticker->time; +} + +void lochara_strategy_cancel_transition_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + *next = meta->state; +} + +void lochara_strategy_initialize_scouting_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + lochara_strategy_initialize_any_(meta, instance, next); + + const lochara_strategy_scouting_param_t* p = meta->data; + + lochara_base_t* base = instance; + statman_transition_to( + p->state_table, base, &base->param.state, LOCHARA_STATE_STAND); +} + +void lochara_strategy_update_scouting_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + const lochara_strategy_scouting_param_t* p = meta->data; + assert(p->state_table != NULL); + assert(p->period > 0); + + lochara_base_t* base = instance; + + const uint64_t t = base->ticker->time; + + const bool knockback = base->param.last_knockback+500 > t; + + const bool event = base->player->event.executor != 0; + + /* ---- die ---- */ + if (!loeffect_recipient_is_alive(&base->param.recipient)) { + *next = LOCHARA_STRATEGY_DEAD; + return; + } + + /* ---- strategy transition ---- */ + vec2_t disp; + locommon_position_sub( + &disp, &base->player->entity->super.super.pos, &base->super.super.pos); + + if (!knockback && MATH_ABS(disp.y) < .1f && !event) { + disp.x *= MATH_SIGN_NOZERO(base->param.direction.x); + + const float b = p->range_back; + if (-p->range_close*b < disp.x && disp.x < p->range_close) { + *next = p->found_close; + } else if (-p->range_mid*b < disp.x && disp.x < p->range_mid) { + *next = p->found_mid; + } else if (-p->range_long*b < disp.x && disp.x < p->range_long) { + *next = p->found_long; + } + if (*next != LOCHARA_STRATEGY_SCOUTING) return; + } + + /* ---- state transition ---- */ + const uint64_t since = base->param.last_state_changed; + + uint64_t seed = 1+since*SEED_; +# define rand_() (seed = chaos_xorshift(seed)) + + const uint64_t dur = rand_()%p->period + p->period/2; + + lochara_state_t state = base->param.state; + if (knockback) { + state = LOCHARA_STATE_STAND; + + } else if (since+dur < t) { + seed = 1+t*SEED_; + if (state == LOCHARA_STATE_STAND && rand_()%100/100.f < p->stagger) { + const float r = .5f + base->cache.ground_pos.x*.5f; + if (rand_()%100/100.f < r) { + base->param.direction = vec2(-1, 0); + state = LOCHARA_STATE_WALK_LEFT; + } else { + base->param.direction = vec2(1, 0); + state = LOCHARA_STATE_WALK_RIGHT; + } + } else { + state = LOCHARA_STATE_STAND; + } + } + statman_transition_to(p->state_table, base, &base->param.state, state); + +# undef rand_ +} + +void lochara_strategy_initialize_combat_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + lochara_base_t* base = instance; + + const lochara_strategy_combat_param_t* p = meta->data; + assert(p->actions != NULL); + + if (base->param.last_knockback+p->parry_window > base->ticker->time) { + loentity_character_apply_effect( + &base->super, &loeffect_damage(PARRY_DAMAGE_)); + *next = p->parried_next; + return; + } + + lochara_strategy_initialize_any_(meta, instance, next); + + lochara_combat_action_execute_all_attacks(p->actions, base); + + vec2_t disp; + locommon_position_sub( + &disp, &base->player->entity->super.super.pos, &base->super.super.pos); + base->param.direction = vec2(MATH_SIGN_NOZERO(disp.x), 0); +} + +void lochara_strategy_update_combat_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + const lochara_strategy_combat_param_t* p = meta->data; + assert(p->actions != NULL); + assert(p->next != meta->state); + + lochara_base_t* base = instance; + if (!p->gravity) base->param.gravity = 0; + + const uint64_t t = base->ticker->time - base->param.last_strategy_changed; + + const lochara_combat_action_t* action = + lochara_combat_action_find_by_time(p->actions, t); + if (action == NULL) { + *next = p->next; + return; + } + statman_transition_to( + p->state_table, base, &base->param.state, action->state); +} diff --git a/core/lochara/strategy.h b/core/lochara/strategy.h new file mode 100644 index 0000000..065682a --- /dev/null +++ b/core/lochara/strategy.h @@ -0,0 +1,131 @@ +#pragma once + +#include "util/statman/statman.h" + +#include "./combat.h" + +typedef enum { + /* BENUM BEGIN lochara_strategy */ + LOCHARA_STRATEGY_WAIT, + LOCHARA_STRATEGY_WAKE_UP, + LOCHARA_STRATEGY_WAKE_UP_EVENT, + + LOCHARA_STRATEGY_SCOUTING, + LOCHARA_STRATEGY_APPROACH, + + LOCHARA_STRATEGY_COMBO1, + LOCHARA_STRATEGY_COMBO2, + LOCHARA_STRATEGY_COMBO3, + + LOCHARA_STRATEGY_SHOOT1, + LOCHARA_STRATEGY_SHOOT2, + LOCHARA_STRATEGY_SHOOT3, + + LOCHARA_STRATEGY_SPELL1, + LOCHARA_STRATEGY_SPELL2, + LOCHARA_STRATEGY_SPELL3, + + LOCHARA_STRATEGY_DOWN, + LOCHARA_STRATEGY_DEAD, + LOCHARA_STRATEGY_KILL, + /* BENUM END */ +} lochara_strategy_t; + +/* generated benum header */ +#include "core/lochara/benum/strategy.h" + + +/* ---- default strategy handlers ---- */ + +void +lochara_strategy_initialize_any_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + +void +lochara_strategy_cancel_transition_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + +void +lochara_strategy_initialize_scouting_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + +void +lochara_strategy_update_scouting_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + +void +lochara_strategy_initialize_combat_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + +void +lochara_strategy_update_combat_( + const statman_meta_t* meta, + void* instance, + statman_state_t* next +); + + +/* ---- default strategy constructors ---- */ + +typedef struct { + const statman_meta_t* state_table; + + uint64_t period; + float stagger; /* 0~1 */ + float range_back; + float range_close; + float range_mid; + float range_long; + + lochara_strategy_t found_close; + lochara_strategy_t found_mid; + lochara_strategy_t found_long; +} lochara_strategy_scouting_param_t; +#define lochara_strategy_scouting(...) \ + (statman_meta_t) { \ + .state = LOCHARA_STRATEGY_SCOUTING, \ + .name = "SCOUTING", \ + .data = &(lochara_strategy_scouting_param_t) { \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_strategy_initialize_scouting_, \ + .update = lochara_strategy_update_scouting_, \ + } + +typedef struct { + const statman_meta_t* state_table; + const lochara_combat_action_t* actions; + + uint64_t parry_window; + lochara_strategy_t parried_next; + + bool gravity; + + lochara_strategy_t next; +} lochara_strategy_combat_param_t; +#define lochara_strategy_combat(NAME, ...) \ + (statman_meta_t) { \ + .state = LOCHARA_STRATEGY_##NAME, \ + .name = #NAME, \ + .data = &(lochara_strategy_combat_param_t) { \ + __VA_ARGS__ \ + }, \ + .initialize = lochara_strategy_initialize_combat_, \ + .update = lochara_strategy_update_combat_, \ + .finalize = lochara_strategy_cancel_transition_, \ + } diff --git a/core/lochara/theists_child.c b/core/lochara/theists_child.c new file mode 100644 index 0000000..fbef388 --- /dev/null +++ b/core/lochara/theists_child.c @@ -0,0 +1,718 @@ +#include "./theists_child.h" + +#include +#include + +#include "util/math/algorithm.h" +#include "util/math/vector.h" +#include "util/statman/statman.h" + +#include "core/lobullet/linear.h" +#include "core/lobullet/pool.h" +#include "core/locommon/position.h" +#include "core/loentity/ground.h" +#include "core/loplayer/event.h" +#include "core/loplayer/stance.h" +#include "core/loresource/music.h" +#include "core/loshader/character.h" + +#include "./base.h" +#include "./state.h" +#include "./strategy.h" +#include "./type.h" + +#define WIDTH_ .025f +#define HEIGHT_ .06f +#define MARKER_ .03f +#define COLOR_ vec4(0, 0, 0, 1) + +#define BPM_ 140 +#define BEAT_ (60.f/BPM_) +#define BEAT_MS_ (BEAT_*1000) +#define MUSIC_DURATION_ (BEAT_MS_*232) + +#define WAKE_UP_RANGE_ (WIDTH_*6) + +#define REWARD_STANCE_ LOPLAYER_STANCE_REVOLUTIONER + +static const loeffect_recipient_status_t base_status_ = { + .attack = .3f, + .defence = .92f, + .speed = .31f, + .jump = 1.1f, +}; + +static void lochara_theists_child_initialize_shoot_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + lochara_state_initialize_any_(meta, instance, state); + + lochara_base_t* base = instance; + + vec2_t dir; + locommon_position_sub( + &dir, &base->player->entity->super.super.pos, &base->super.super.pos); + + if (dir.x == 0 && dir.y == 0) dir = vec2(1, 0); + vec2_diveq(&dir, vec2_length(&dir)); + + const vec2_t invdir = vec2(dir.y, -dir.x); + + base->param.direction = vec2(MATH_SIGN_NOZERO(dir.x), 0); + for (int32_t i = -4; i <= 4; ++i) { + vec2_t v; + vec2_mul(&v, &dir, 1); + + vec2_t p; + vec2_mul(&p, &invdir, i*.02f); + + locommon_position_t pos = base->super.super.pos; + vec2_addeq(&pos.fract, &p); + locommon_position_reduce(&pos); + + lobullet_base_t* b = lobullet_pool_create(base->bullet); + lobullet_linear_circle_build(b, + .owner = base->super.super.id, + .basepos = pos, + .size = vec2(.02f, .02f), + .color = vec4(1, 1, 1, 1), + .velocity = v, + .knockback = 1, + .effect = loeffect_damage( + base->param.recipient.status.attack*.6f), + .duration = 1000, + ); + loentity_store_add(base->entities, &b->super.super); + } +} + +static void lochara_theists_child_update_thrust_in_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + static const uint64_t dur = BEAT_MS_/4; + + lochara_base_t* base = instance; + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + + const float tf = t*1.f / dur; + base->cache.instance.motion.time = powf(tf, 2); + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; +} + +static void lochara_theists_child_update_thrust_out_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + static const uint64_t dur = BEAT_MS_/4; + + lochara_base_t* base = instance; + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + + const float tf = t*1.f / dur; + base->cache.instance.motion.time = powf(tf, 2); + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; +} + +static void lochara_theists_child_update_down_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + const bool fast = + meta->state == LOCHARA_STATE_DOWN || + meta->state == LOCHARA_STATE_REVIVE; + const bool reverse = + meta->state == LOCHARA_STATE_REVIVE || + meta->state == LOCHARA_STATE_RESUSCITATE; + + const uint64_t dur = fast? reverse? BEAT_MS_*3: BEAT_MS_: BEAT_MS_*16; + const uint64_t key = fast? dur: dur/2; + + lochara_base_t* base = instance; + base->param.movement = vec2(0, 0); + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + if (reverse) t = dur - t; + + if (t < key) { + const float tf = t*1.f/key; + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_STAND1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_SIT; + base->cache.instance.motion.time = powf(tf, 6); + } else { + const float tf = (t-key)*1.f/(dur-key); + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_SIT; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_DOWN; + base->cache.instance.motion.time = powf(tf, 4); + } +} + +static const statman_meta_t state_table_[] = { + lochara_state_stand( + .period = BEAT_MS_*2, + .acceleration = {{5, 5}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_ATTACK1, + ), + lochara_state_walk( + .period = BEAT_MS_, + .acceleration = {{5, 5}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_WALK, + ), + lochara_state_dodge( + .duration = BEAT_MS_/2, + .speed = 1, + .acceleration = {{3, 3}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_WALK, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + ), + lochara_state_jump(), + + lochara_state_teleport( + .duration = BEAT_MS_*2, + .offset = {{WIDTH_*2, 0}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_ATTACK2, + ), + { + .state = LOCHARA_STATE_THRUST_IN, + .name = "THRUST_IN", + .initialize = lochara_state_initialize_any_, + .update = lochara_theists_child_update_thrust_in_state_, + }, + { + .state = LOCHARA_STATE_THRUST_OUT, + .name = "THRUST_OUT", + .initialize = lochara_state_initialize_any_, + .update = lochara_theists_child_update_thrust_out_state_, + }, + { + .state = LOCHARA_STATE_SHOOT, + .name = "SHOOT", + .initialize = lochara_theists_child_initialize_shoot_state_, + .update = lochara_theists_child_update_thrust_in_state_, + }, + { + .state = LOCHARA_STATE_DOWN, + .name = "DOWN", + .initialize = lochara_state_initialize_any_, + .update = lochara_theists_child_update_down_state_, + }, + { + .state = LOCHARA_STATE_REVIVE, + .name = "REVIVE", + .initialize = lochara_state_initialize_any_, + .update = lochara_theists_child_update_down_state_, + }, + { + .state = LOCHARA_STATE_DEAD, + .name = "DEAD", + .initialize = lochara_state_initialize_any_, + .update = lochara_theists_child_update_down_state_, + }, + { + .state = LOCHARA_STATE_RESUSCITATE, + .name = "RESUSCITATE", + .initialize = lochara_state_initialize_any_, + .update = lochara_theists_child_update_down_state_, + }, + {0}, +}; + +static void lochara_theists_child_update_wait_strategy_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + static const float range2 = WAKE_UP_RANGE_*WAKE_UP_RANGE_; + + lochara_base_t* base = instance; + + vec2_t disp; + locommon_position_sub( + &disp, &base->player->entity->super.super.pos, &base->super.super.pos); + + if (fabsf(disp.y) < HEIGHT_/2 && vec2_pow_length(&disp) < range2) { + loeffect_recipient_apply_effect( + &base->param.recipient, &loeffect_resuscitate()); + if (loplayer_stance_set_has(&base->player->stances, REWARD_STANCE_)) { + *next = LOCHARA_STRATEGY_WAKE_UP; + } else { + *next = LOCHARA_STRATEGY_WAKE_UP_EVENT; + } + return; + } + statman_transition_to( + state_table_, instance, &base->param.state, LOCHARA_STATE_DEAD); +} + +static void lochara_theists_child_initialize_wake_up_strategy_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + lochara_strategy_initialize_any_(meta, instance, next); + if (meta->state != LOCHARA_STRATEGY_WAKE_UP_EVENT) return; + + lochara_base_t* base = instance; + loentity_character_apply_effect( + &base->super, &loeffect_fanatic(MUSIC_DURATION_)); + loentity_character_apply_effect( + &base->player->entity->super, &loeffect_curse(MUSIC_DURATION_)); +} + +static void lochara_theists_child_update_wake_up_strategy_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + const bool ev = meta->state == LOCHARA_STRATEGY_WAKE_UP_EVENT; + const uint64_t dur = (ev? BEAT_MS_*64: BEAT_MS_*16); + + lochara_base_t* base = instance; + + const uint64_t t = base->ticker->time - base->param.last_strategy_changed; + if (t >= dur) { + *next = LOCHARA_STRATEGY_APPROACH; + return; + } + statman_transition_to( + state_table_, instance, &base->param.state, LOCHARA_STATE_RESUSCITATE); +} + +static void lochara_theists_child_update_approach_strategy_( + const statman_meta_t* meta, void* instance, statman_state_t* next) { + assert(meta != NULL); + assert(instance != NULL); + assert(next != NULL); + + lochara_base_t* base = instance; + if (!loeffect_recipient_is_alive(&base->param.recipient)) { + *next = LOCHARA_STRATEGY_DEAD; + return; + } + + const uint64_t since = base->param.last_strategy_changed; + + uint64_t until = since + BEAT_MS_; + if (base->player->event.executor == base->super.super.id) { + const uint64_t msince = base->player->event.ctx.music.since; + if (msince < since) { + const uint64_t beats = (since - msince)/BEAT_MS_ + 1; + until = msince + beats*BEAT_MS_; + } + } + + /* ---- strategy transition ---- */ + const locommon_position_t* player = &base->player->entity->super.super.pos; + + vec2_t disp; + locommon_position_sub(&disp, player, &base->super.super.pos); + + if (player->chunk.x != base->super.super.pos.chunk.x || + player->chunk.y != base->super.super.pos.chunk.y || + disp.y < -HEIGHT_) { + *next = LOCHARA_STRATEGY_WAIT; + return; + } + + const float dist = MATH_ABS(disp.x); + if (base->ticker->time >= until) { + if (MATH_ABS(disp.y) > HEIGHT_) { + *next = LOCHARA_STRATEGY_SHOOT1; + } else if (dist < WIDTH_*4) { + *next = LOCHARA_STRATEGY_COMBO1; + } else if (dist < WIDTH_*8) { + *next = LOCHARA_STRATEGY_SHOOT1; + } else { + *next = LOCHARA_STRATEGY_COMBO2; + } + return; + } + + /* ---- approaching ---- */ + if (dist > WIDTH_*6) { + base->param.direction = vec2(MATH_SIGN_NOZERO(disp.x), 0); + + const lochara_state_t state = + disp.x < 0? LOCHARA_STATE_WALK_LEFT: LOCHARA_STATE_WALK_RIGHT; + statman_transition_to(state_table_, base, &base->param.state, state); + } +} + +static const lochara_combat_action_t combo1_[] = { + lochara_combat_action_rest( + .duration = BEAT_MS_/4*3, + .state = LOCHARA_STATE_STAND, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1.2f, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_IN, + .damage = .8f, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/4*3, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_DODGE_LEFT, + ), + {0}, +}; + +static const lochara_combat_action_t combo2_[] = { + lochara_combat_action_rest( + .duration = BEAT_MS_*2, + .state = LOCHARA_STATE_TELEPORT_FRONT, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1.2f, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_IN, + .damage = .8f, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = BEAT_MS_/4, + .state = LOCHARA_STATE_THRUST_IN, + .damage = .6f, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_/2, + .state = LOCHARA_STATE_DODGE_RIGHT, + ), + {0}, +}; + +static const lochara_combat_action_t shoot1_[] = { + lochara_combat_action_rest( + .duration = 1, + .state = LOCHARA_STATE_JUMP, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_-1, + .state = LOCHARA_STATE_STAND, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_SHOOT, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_*2, + .state = LOCHARA_STATE_TELEPORT_BEHIND, + ), + {0}, +}; + +static const lochara_combat_action_t down_[] = { + lochara_combat_action_rest( + .duration = BEAT_MS_, + .state = LOCHARA_STATE_DOWN, + ), + lochara_combat_action_rest( + .duration = BEAT_MS_*3, + .state = LOCHARA_STATE_REVIVE, + ), + {0}, +}; + +static const lochara_combat_action_t kill_[] = { + lochara_combat_action_rest( + .duration = BEAT_MS_*12, + .state = LOCHARA_STATE_DEAD, + ), + {0}, +}; + +static const lochara_combat_action_t dead_[] = { + lochara_combat_action_rest( + .duration = 30000, + .state = LOCHARA_STATE_DEAD, + ), + {0}, +}; + +static const statman_meta_t strategy_table_[] = { + { + .state = LOCHARA_STRATEGY_WAIT, + .name = "WAIT", + .initialize = lochara_strategy_initialize_any_, + .update = lochara_theists_child_update_wait_strategy_, + }, + { + .state = LOCHARA_STRATEGY_WAKE_UP, + .name = "WAKE_UP", + .initialize = lochara_strategy_initialize_any_, + .update = lochara_theists_child_update_wake_up_strategy_, + }, + { + .state = LOCHARA_STRATEGY_WAKE_UP_EVENT, + .name = "WAKE_UP_EVENT", + .initialize = lochara_theists_child_initialize_wake_up_strategy_, + .update = lochara_theists_child_update_wake_up_strategy_, + }, + { + .state = LOCHARA_STRATEGY_APPROACH, + .name = "APPROACH", + .initialize = lochara_strategy_initialize_any_, + .update = lochara_theists_child_update_approach_strategy_, + }, + + lochara_strategy_combat(COMBO1, + .state_table = state_table_, + .actions = combo1_, + .parry_window = 100, + .parried_next = LOCHARA_STRATEGY_DOWN, + .next = LOCHARA_STRATEGY_APPROACH, + ), + lochara_strategy_combat(COMBO2, + .state_table = state_table_, + .actions = combo2_, + .parry_window = 100, + .parried_next = LOCHARA_STRATEGY_DOWN, + .next = LOCHARA_STRATEGY_APPROACH, + ), + lochara_strategy_combat(SHOOT1, + .state_table = state_table_, + .actions = shoot1_, + .parry_window = 200, + .parried_next = LOCHARA_STRATEGY_DOWN, + .gravity = true, + .next = LOCHARA_STRATEGY_APPROACH, + ), + + lochara_strategy_combat(DOWN, + .state_table = state_table_, + .actions = down_, + .gravity = true, + .next = LOCHARA_STRATEGY_APPROACH, + ), + lochara_strategy_combat(KILL, + .state_table = state_table_, + .actions = kill_, + .gravity = true, + .next = LOCHARA_STRATEGY_WAIT, + ), + lochara_strategy_combat(DEAD, + .state_table = state_table_, + .actions = dead_, + .gravity = true, + .next = LOCHARA_STRATEGY_WAIT, + ), + {0}, +}; + +static void lochara_theists_child_update_event_(lochara_base_t* base) { + assert(base != NULL); + + static const loplayer_event_command_t wake_up[] = { + loplayer_event_command_play_music(LORESOURCE_MUSIC_ID_BOSS_THEISTS_CHILD), + loplayer_event_command_set_area(.49f, .45f), + loplayer_event_command_set_cinescope(1), + loplayer_event_command_wait(BEAT_MS_*16), + + loplayer_event_command_set_line("boss_theists_child_line0"), + loplayer_event_command_wait(BEAT_MS_*16), + loplayer_event_command_set_line("boss_theists_child_line1"), + loplayer_event_command_wait(BEAT_MS_*16), + loplayer_event_command_set_line("boss_theists_child_line2"), + loplayer_event_command_wait(BEAT_MS_*15), + + loplayer_event_command_set_line(NULL), + loplayer_event_command_set_cinescope(0), + {0}, + }; + static const loplayer_event_command_t kill[] = { + loplayer_event_command_set_area(0, 0), + loplayer_event_command_set_cinescope(1), + loplayer_event_command_wait(BEAT_MS_), + loplayer_event_command_stop_music(), + + loplayer_event_command_set_line("boss_theists_child_kill_line0"), + loplayer_event_command_wait(BEAT_MS_*4), + loplayer_event_command_set_line("boss_theists_child_kill_line1"), + loplayer_event_command_wait(BEAT_MS_*4), + + loplayer_event_command_finalize(), + {0}, + }; + static const loplayer_event_command_t dead[] = { + loplayer_event_command_set_area(0, 0), + loplayer_event_command_wait(BEAT_MS_), + loplayer_event_command_stop_music(), + + loplayer_event_command_set_line("boss_theists_child_dead_line"), + loplayer_event_command_wait(BEAT_MS_*8), + + loplayer_event_command_finalize(), + {0}, + }; + + const uint64_t t = base->ticker->time; + + loplayer_event_t* event = &base->player->event; + const loentity_id_t id = base->super.super.id; + + locommon_position_t basepos = base->super.super.pos; + basepos.fract = vec2(.5f, .5f); + + if (base->param.strategy == LOCHARA_STRATEGY_WAKE_UP_EVENT) { + loplayer_event_execute_commands(event, id, &basepos, wake_up); + return; + } + if (event->executor != id) return; + + if (base->player->entity->param.state == LOCHARA_STATE_DEAD) { + statman_transition_to( + strategy_table_, base, &base->param.strategy, LOCHARA_STRATEGY_KILL); + loplayer_event_execute_commands(event, id, &basepos, kill); + return; + } + if (base->param.strategy == LOCHARA_STRATEGY_DEAD) { + loplayer_event_execute_commands(event, id, &basepos, dead); + if (!loplayer_stance_set_has(&base->player->stances, REWARD_STANCE_)) { + loplayer_stance_set_add(&base->player->stances, REWARD_STANCE_); + loplayer_popup_queue_new_stance(&base->player->popup, REWARD_STANCE_); + } + return; + } + if (base->player->event.basetime+MUSIC_DURATION_ <= t && + loeffect_recipient_is_alive(&base->param.recipient)) { + loentity_character_apply_effect( + &base->player->entity->super, &loeffect_curse_trigger()); + return; + } + loplayer_event_execute_commands(event, id, &basepos, wake_up); +} + +bool lochara_theists_child_update(lochara_base_t* base) { + assert(base != NULL); + + loeffect_recipient_update(&base->param.recipient, &base_status_); + + statman_update(strategy_table_, base, &base->param.strategy); + lochara_theists_child_update_event_(base); + + const float dir = MATH_SIGN_NOZERO(base->param.direction.x); + base->cache.instance = (loshader_character_drawer_instance_t) { + .character_id = LOSHADER_CHARACTER_ID_CAVIA, + .pos = vec2(0, -MARKER_), + .size = vec2(dir*HEIGHT_, HEIGHT_), + .color = COLOR_, + .marker_offset = vec2(0, MARKER_), + }; + statman_update(state_table_, base, &base->param.state); + + if (base->param.strategy != LOCHARA_STRATEGY_WAIT && + base->param.strategy != LOCHARA_STRATEGY_WAKE_UP && + base->param.strategy != LOCHARA_STRATEGY_WAKE_UP_EVENT && + base->param.strategy != LOCHARA_STRATEGY_DEAD) { + base->cache.instance.marker = lochara_base_affect_bullets(base); + } + + lochara_base_calculate_physics( + base, &vec2(WIDTH_, HEIGHT_), &vec2(0, MARKER_)); + lochara_base_bind_on_ground(base, &vec2(WIDTH_, HEIGHT_+MARKER_)); + return true; +} + +void lochara_theists_child_build( + lochara_base_t* base, loentity_ground_t* gnd) { + assert(base != NULL); + assert(gnd != NULL); + + base->super.super.pos = gnd->super.pos; + vec2_addeq(&base->super.super.pos.fract, &vec2(0, gnd->size.y)); + locommon_position_reduce(&base->super.super.pos); + + base->param = (typeof(base->param)) { + .type = LOCHARA_TYPE_THEISTS_CHILD, + .state = LOCHARA_STATE_DEAD, + .last_state_changed = base->ticker->time, + .strategy = LOCHARA_STRATEGY_WAIT, + .last_strategy_changed = base->ticker->time, + + .ground = gnd->super.id, + }; + loeffect_recipient_initialize( + &base->param.recipient, base->ticker, &base_status_); +} diff --git a/core/lochara/theists_child.h b/core/lochara/theists_child.h new file mode 100644 index 0000000..78a14ac --- /dev/null +++ b/core/lochara/theists_child.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "core/loentity/ground.h" + +#include "./base.h" + +bool +lochara_theists_child_update( + lochara_base_t* base +); + +void +lochara_theists_child_build( + lochara_base_t* base, + loentity_ground_t* gnd +); diff --git a/core/lochara/type.h b/core/lochara/type.h new file mode 100644 index 0000000..45efc3c --- /dev/null +++ b/core/lochara/type.h @@ -0,0 +1,18 @@ +#pragma once + +typedef enum { + /* BENUM BEGIN lochara_type */ + LOCHARA_TYPE_PLAYER, + + LOCHARA_TYPE_ENCEPHALON, + + LOCHARA_TYPE_CAVIA, + LOCHARA_TYPE_WARDER, + + LOCHARA_TYPE_BIG_WARDER, + LOCHARA_TYPE_THEISTS_CHILD, + /* BENUM END*/ +} lochara_type_t; + +/* generated benum utils */ +#include "core/lochara/benum/type.h" diff --git a/core/lochara/warder.c b/core/lochara/warder.c new file mode 100644 index 0000000..803fec8 --- /dev/null +++ b/core/lochara/warder.c @@ -0,0 +1,370 @@ +#include "./warder.h" + +#include +#include +#include +#include + +#include "util/math/algorithm.h" +#include "util/math/vector.h" +#include "util/statman/statman.h" + +#include "core/lobullet/base.h" +#include "core/lobullet/linear.h" +#include "core/loeffect/effect.h" +#include "core/loeffect/recipient.h" +#include "core/loentity/ground.h" +#include "core/loresource/sound.h" +#include "core/loshader/character.h" + +#include "./base.h" +#include "./combat.h" + +#define WIDTH_ .02f +#define HEIGHT_ .055f +#define MARKER_ .022f +#define COLOR_ vec4(0, 0, 0, 1) + +#define BULLET_DAMAGE_ .9f +#define BULLET_KNOCKBACK_ 6 +#define BULLET_DURATION_ 2000 +#define BULLET_SPEED_ .6f +#define BULLET_COLOR_ vec4(0, 0, 0, 1) +#define BULLET_SIZE_ vec2(.03f, .03f) + +#define SHOOT_DURATION_ 2000 + +static const loeffect_recipient_status_t base_status_ = { + .attack = .2f, + .defence = .05f, + .speed = .05f, + .jump = 1.f, +}; + +static void lochara_warder_update_thrust_in_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + static const uint64_t dur = 100; + + lochara_base_t* base = instance; + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + + const float tf = t*1.f / dur; + base->cache.instance.motion.time = powf(tf, 2); + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; +} + +static void lochara_warder_update_thrust_out_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + static const uint64_t dur = 100; + + lochara_base_t* base = instance; + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + + const float tf = t*1.f / dur; + base->cache.instance.motion.time = powf(tf, 2); + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; +} + +static void lochara_warder_update_shoot_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + lochara_base_t* base = instance; + const uint64_t since = base->param.last_state_changed; + + uint64_t t = base->ticker->time - since; + if (t > SHOOT_DURATION_) t = SHOOT_DURATION_; + + const uint64_t pt = t == 0? 0: base->ticker->prev_time - since; + if (pt < SHOOT_DURATION_/2 && SHOOT_DURATION_/2 <= t) { + vec2_t v = base->param.direction; + vec2_muleq(&v, BULLET_SPEED_); + + lobullet_base_t* b = lobullet_pool_create(base->bullet); + lobullet_linear_circle_build(b, + .owner = base->super.super.id, + .basepos = base->super.super.pos, + .size = BULLET_SIZE_, + .color = BULLET_COLOR_, + .velocity = v, + .knockback = BULLET_KNOCKBACK_, + .effect = loeffect_damage( + base->param.recipient.status.attack*BULLET_DAMAGE_), + .duration = BULLET_DURATION_,); + loentity_store_add(base->entities, &b->super.super); + loresource_sound_set_play( + &base->res->sound, LORESOURCE_SOUND_ID_ENEMY_SHOOT); + } + + float tf = t*1.f/SHOOT_DURATION_*2; + if (tf < 1) { + tf *= 2; + if (tf < 1) { + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_STAND1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; + } else { + tf -= 1; + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; + } + base->cache.instance.motion.time = powf(tf, 4); + } else { + tf -= 1; + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_STAND1; + base->cache.instance.motion.time = tf; + } +} + +static void lochara_warder_initialize_resuscitate_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + lochara_state_initialize_any_(meta, instance, state); + + lochara_base_t* base = instance; + loeffect_recipient_apply_effect( + &base->param.recipient, &loeffect_resuscitate()); +} + +static void lochara_warder_update_dead_state_( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(instance != NULL); + assert(state != NULL); + + static uint64_t dur = 1000; + + lochara_base_t* base = instance; + base->param.movement = vec2(0, 0); + + uint64_t t = base->ticker->time - base->param.last_state_changed; + if (t > dur) t = dur; + + if (base->param.state == LOCHARA_STATE_RESUSCITATE) t = dur - t; + + base->cache.instance.motion.from = LOSHADER_CHARACTER_MOTION_ID_STAND1; + base->cache.instance.motion.to = LOSHADER_CHARACTER_MOTION_ID_DOWN; + base->cache.instance.motion.time = powf(t*1.f/dur, 6); +} + +static const statman_meta_t state_table_[] = { + lochara_state_stand( + .period = 4000, + .acceleration = {{5, 5}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + ), + lochara_state_walk( + .period = 1000, + .acceleration = {{5, 5}}, + .motion1 = LOSHADER_CHARACTER_MOTION_ID_STAND1, + .motion2 = LOSHADER_CHARACTER_MOTION_ID_WALK, + ), + { + .state = LOCHARA_STATE_THRUST_IN, + .name = "THRUST_IN", + .initialize = lochara_state_initialize_any_, + .update = lochara_warder_update_thrust_in_state_, + }, + { + .state = LOCHARA_STATE_THRUST_OUT, + .name = "THRUST_OUT", + .initialize = lochara_state_initialize_any_, + .update = lochara_warder_update_thrust_out_state_, + }, + { + .state = LOCHARA_STATE_SHOOT, + .name = "SHOOT", + .initialize = lochara_state_initialize_any_, + .update = lochara_warder_update_shoot_state_, + }, + { + .state = LOCHARA_STATE_DEAD, + .name = "DEAD", + .initialize = lochara_state_initialize_any_, + .update = lochara_warder_update_dead_state_, + }, + { + .state = LOCHARA_STATE_RESUSCITATE, + .name = "RESUSCITATE", + .initialize = lochara_warder_initialize_resuscitate_state_, + .update = lochara_warder_update_dead_state_, + }, + {0}, +}; + +static const lochara_combat_action_t combo1_[] = { + lochara_combat_action_rest( + .duration = 400, + .state = LOCHARA_STATE_STAND, + ), + lochara_combat_action_attack( + .duration = 200, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = 200, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = 300, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1, + ), + lochara_combat_action_rest( + .duration = 200, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = 300, + .state = LOCHARA_STATE_THRUST_IN, + .damage = 1.2f, + ), + lochara_combat_action_rest( + .duration = 200, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_attack( + .duration = 300, + .state = LOCHARA_STATE_THRUST_IN, + .damage = .8f, + ), + lochara_combat_action_rest( + .duration = 400, + .state = LOCHARA_STATE_THRUST_OUT, + ), + lochara_combat_action_rest( + .duration = 600, + .state = LOCHARA_STATE_STAND, + ), + {0}, +}; + +static const lochara_combat_action_t shoot1_[] = { + lochara_combat_action_rest( + .duration = 100, + .state = LOCHARA_STATE_STAND, + ), + lochara_combat_action_rest( + .duration = SHOOT_DURATION_, + .state = LOCHARA_STATE_SHOOT, + ), + lochara_combat_action_rest( + .duration = 500, + .state = LOCHARA_STATE_STAND, + ), + {0}, +}; + +static const lochara_combat_action_t dead_[] = { + lochara_combat_action_rest( + .duration = 30000, + .state = LOCHARA_STATE_DEAD, + ), + lochara_combat_action_rest( + .duration = 2000, + .state = LOCHARA_STATE_RESUSCITATE, + ), + {0}, +}; + +static const statman_meta_t strategy_table_[] = { + lochara_strategy_scouting( + .state_table = state_table_, + .period = 2000, + .stagger = .8f, + .range_back = .5f, + .range_close = WIDTH_*4, + .found_close = LOCHARA_STRATEGY_COMBO1, + .range_mid = .4f, + .found_mid = LOCHARA_STRATEGY_SHOOT1, + ), + lochara_strategy_combat(COMBO1, + .state_table = state_table_, + .actions = combo1_, + .next = LOCHARA_STRATEGY_SCOUTING, + ), + lochara_strategy_combat(SHOOT1, + .state_table = state_table_, + .actions = shoot1_, + .next = LOCHARA_STRATEGY_SCOUTING, + ), + lochara_strategy_combat(DEAD, + .state_table = state_table_, + .actions = dead_, + .next = LOCHARA_STRATEGY_SCOUTING, + ), + {0}, +}; + +bool lochara_warder_update(lochara_base_t* base) { + assert(base != NULL); + + loeffect_recipient_update(&base->param.recipient, &base_status_); + + statman_update(strategy_table_, base, &base->param.strategy); + + const float dir = MATH_SIGN_NOZERO(base->param.direction.x); + base->cache.instance = (loshader_character_drawer_instance_t) { + .character_id = LOSHADER_CHARACTER_ID_WARDER, + .pos = vec2(0, -MARKER_), + .size = vec2(dir*HEIGHT_, HEIGHT_), + .color = COLOR_, + .marker_offset = vec2(0, MARKER_), + }; + statman_update(state_table_, base, &base->param.state); + + if (base->param.state != LOCHARA_STATE_DEAD) { + base->cache.instance.marker = lochara_base_affect_bullets(base); + } + + lochara_base_calculate_physics( + base, &vec2(WIDTH_, HEIGHT_), &vec2(0, MARKER_)); + lochara_base_bind_on_ground(base, &vec2(WIDTH_, HEIGHT_+MARKER_)); + return true; +} + +void lochara_warder_build( + lochara_base_t* base, const loentity_ground_t* gnd, float pos) { + assert(base != NULL); + assert(gnd != NULL); + assert(MATH_FLOAT_VALID(pos)); + + base->super.super.pos = gnd->super.pos; + vec2_addeq( + &base->super.super.pos.fract, + &vec2(gnd->size.x*pos, gnd->size.y)); + locommon_position_reduce(&base->super.super.pos); + + base->param = (typeof(base->param)) { + .type = LOCHARA_TYPE_WARDER, + .state = LOCHARA_STATE_STAND, + .last_state_changed = base->ticker->time, + .strategy = LOCHARA_STRATEGY_SCOUTING, + .last_strategy_changed = base->ticker->time, + + .ground = gnd->super.id, + }; + loeffect_recipient_initialize( + &base->param.recipient, base->ticker, &base_status_); +} diff --git a/core/lochara/warder.h b/core/lochara/warder.h new file mode 100644 index 0000000..23b9b31 --- /dev/null +++ b/core/lochara/warder.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "core/loentity/ground.h" + +#include "./base.h" + +bool +lochara_warder_update( + lochara_base_t* base +); + +void +lochara_warder_build( + lochara_base_t* base, + const loentity_ground_t* gnd, + float pos +); diff --git a/core/locharacter/CMakeLists.txt b/core/locharacter/CMakeLists.txt deleted file mode 100644 index 67c4fad..0000000 --- a/core/locharacter/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -add_library(locharacter - base.c - big_warder.c - cavia.c - encephalon.c - greedy_scientist.c - misc.c - pool.c - scientist.c - theists_child.c - util.c - warder.c -) -target_link_libraries(locharacter - msgpackc - - math - memory - mpkutil - - lobullet - locommon - loeffect - loentity - loplayer - loshader -) diff --git a/core/locharacter/base.c b/core/locharacter/base.c deleted file mode 100644 index bf84cf2..0000000 --- a/core/locharacter/base.c +++ /dev/null @@ -1,434 +0,0 @@ -#include "./base.h" - -#include -#include -#include -#include - -#include "util/math/algorithm.h" -#include "util/math/vector.h" - -#include "core/lobullet/pool.h" -#include "core/locommon/easing.h" -#include "core/locommon/msgpack.h" -#include "core/locommon/position.h" -#include "core/locommon/ticker.h" -#include "core/loeffect/recipient.h" -#include "core/loentity/character.h" -#include "core/loentity/store.h" -#include "core/loplayer/player.h" -#include "core/loresource/set.h" -#include "core/loshader/character.h" - -#include "./big_warder.h" -#include "./cavia.h" -#include "./encephalon.h" -#include "./greedy_scientist.h" -#include "./scientist.h" -#include "./theists_child.h" -#include "./misc.h" -#include "./warder.h" - -#define LOCHARACTER_BASE_PARAM_TO_PACK_EACH_( \ - PROC, PROC_type, PROC_state, PROC_str) do { \ - PROC_str ("subclass", "character"); \ - PROC_type ("type", type); \ - PROC ("id", super.super.id); \ - PROC ("ground", ground); \ - PROC ("pos", pos); \ - PROC ("direction", direction); \ - PROC ("knockback", knockback); \ - PROC ("gravity", gravity); \ - PROC ("madness", recipient.madness); \ - PROC ("effects", recipient.effects); \ - PROC_state("state", state); \ - PROC ("since", since); \ - PROC ("last-update-time", last_update_time); \ - PROC ("last-knockback-time", last_knockback_time); \ - PROC ("last-hit-time", last_hit_time); \ -} while (0) -#define LOCHARACTER_BASE_PARAM_TO_PACK_COUNT 15 - -static void locharacter_base_convert_to_world_pos_( - const loentity_ground_t* g, locommon_position_t* wpos, const vec2_t* pos) { - assert(g != NULL); - assert(wpos != NULL); - assert(vec2_valid(pos)); - - vec2_t p = *pos; - p.x *= g->size.x; - p.y += g->size.y; - - *wpos = g->super.pos; - vec2_addeq(&wpos->fract, &p); - locommon_position_reduce(wpos); -} - -static void locharacter_base_convert_from_world_pos_( - const loentity_ground_t* g, vec2_t* pos, const locommon_position_t* wpos) { - assert(g != NULL); - assert(pos != NULL); - assert(locommon_position_valid(wpos)); - - locommon_position_sub(pos, wpos, &g->super.pos); - pos->x /= g->size.x; - pos->y -= g->size.y; -} - -static loentity_ground_t* locharacter_base_get_ground_(locharacter_base_t* base) { - assert(base != NULL); - - loentity_store_iterator_t itr; - if (loentity_store_find_item_by_id(base->entities, &itr, base->ground)) { - return itr.ground; - } - return NULL; -} - -static void locharacter_base_handle_knockback_(locharacter_base_t* base) { - assert(base != NULL); - - vec2_t v = base->knockback; - v.x /= base->cache.ground->size.x; - vec2_muleq(&v, base->ticker->delta_f); - vec2_addeq(&base->pos, &v); - - locommon_easing_linear_float(&base->knockback.x, 0, base->ticker->delta_f/2); - locommon_easing_linear_float(&base->knockback.y, 0, base->ticker->delta_f/2); -} - -static void locharacter_base_calculate_world_position_( - locharacter_base_t* base) { - assert(base != NULL); - - base->pos.x = MATH_CLAMP(base->pos.x, -1, 1); - base->pos.y = MATH_CLAMP(base->pos.y, 0, 1); - - if (base->pos.y < base->cache.height) { - if (base->cache.gravity) base->gravity = 0; - base->pos.y = base->cache.height; - } - locharacter_base_convert_to_world_pos_( - base->cache.ground, &base->super.super.pos, &base->pos); -} - -static void locharacter_base_calculate_velocity_( - locharacter_base_t* base, vec2_t* v, const locommon_position_t* oldpos) { - assert(base != NULL); - assert(v != NULL); - assert(locommon_position_valid(oldpos)); - - locommon_position_sub(v, &base->super.super.pos, oldpos); - vec2_diveq(v, base->ticker->delta_f); -} - -static void locharacter_base_execute_bullet_hittest_( - locharacter_base_t* base, const vec2_t* velocity) { - assert(base != NULL); - assert(vec2_valid(velocity)); - - if (base->last_hit_time + 200 > base->ticker->time) return; - - if (loentity_store_affect_bullets_shot_by_one( - base->entities, - &base->super, - base->player->entity.super.super.id, - velocity, - base->ticker->delta_f)) { - base->last_hit_time = base->ticker->time; - } -} - -static void locharacter_base_delete_(loentity_t* entity) { - assert(entity != NULL); - - locharacter_base_t* base = (typeof(base)) entity; - if (!base->used) return; - - base->used = false; - -# define each_(NAME, name) do { \ - if (base->type == LOCHARACTER_TYPE_##NAME) { \ - locharacter_##name##_tear_down(base); \ - return; \ - } \ - } while (0) - - LOCHARACTER_TYPE_EACH_(each_); - assert(false); - -# undef each_ -} - -static void locharacter_base_die_(loentity_t* entity) { - assert(entity != NULL); - -} - -static bool locharacter_base_update_(loentity_t* entity) { - assert(entity != NULL); - - static const float gravity_acceleration = 2.f; - - locharacter_base_t* base = (typeof(base)) entity; - - base->cache = (typeof(base->cache)) { - .time = base->ticker->time, - }; - - base->cache.ground = locharacter_base_get_ground_(base); - if (base->cache.ground == NULL) return false; - - locharacter_base_convert_from_world_pos_( - base->cache.ground, - &base->cache.player_pos, - &base->player->entity.super.super.pos); - - locharacter_base_handle_knockback_(base); - - locommon_position_t oldpos = base->super.super.pos; - - base->pos.y += base->gravity * base->ticker->delta_f; - -# define each_(NAME, name) do { \ - if (base->type == LOCHARACTER_TYPE_##NAME) { \ - if (!locharacter_##name##_update(base)) return false; \ - } \ - } while (0) - - LOCHARACTER_TYPE_EACH_(each_); - -# undef each_ - - locharacter_base_calculate_world_position_(base); - - if (base->cache.gravity) { - base->gravity -= base->ticker->delta_f * gravity_acceleration; - } else { - base->gravity = 0; - } - if (base->cache.bullet_hittest) { - vec2_t velocity; - locharacter_base_calculate_velocity_(base, &velocity, &oldpos); - locharacter_base_execute_bullet_hittest_(base, &velocity); - } - - base->cache.ground = NULL; - base->last_update_time = base->cache.time; - return true; -} - -static void locharacter_base_draw_( - loentity_t* entity, const locommon_position_t* basepos) { - assert(entity != NULL); - assert(locommon_position_valid(basepos)); - - locharacter_base_t* base = (typeof(base)) entity; - - vec2_t v; - locommon_position_sub(&v, &base->super.super.pos, basepos); - vec2_addeq(&base->cache.instance.pos, &v); - - loshader_character_drawer_add_instance(base->drawer, &base->cache.instance); -} - -static void locharacter_base_apply_effect_( - loentity_character_t* entity, const loeffect_t* effect) { - assert(entity != NULL); - assert(effect != NULL); - - locharacter_base_t* base = (typeof(base)) entity; - loeffect_recipient_apply_effect(&base->recipient, effect); -} - -static void locharacter_base_knockback_( - loentity_character_t* chara, const vec2_t* knockback) { - assert(chara != NULL); - assert(vec2_valid(knockback)); - - locharacter_base_t* base = (typeof(base)) chara; - - static const float r = .05f; - if (vec2_pow_length(knockback) > r*r) { - base->last_knockback_time = base->ticker->time; - } - vec2_addeq(&base->knockback, knockback); -} - -static void locharacter_base_pack_( - const loentity_t* chara, msgpack_packer* packer) { - assert(chara != NULL); - assert(packer != NULL); - - const locharacter_base_t* base = (typeof(base)) chara; - - msgpack_pack_map(packer, LOCHARACTER_BASE_PARAM_TO_PACK_COUNT+1); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &base->var); \ - } while (0) -# define pack_type_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - mpkutil_pack_str(packer, locharacter_type_stringify(base->var)); \ - } while (0) -# define pack_state_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - mpkutil_pack_str(packer, locharacter_state_stringify(base->var)); \ - } while (0) -# define pack_str_(name, str) do { \ - mpkutil_pack_str(packer, name); \ - mpkutil_pack_str(packer, str); \ - } while (0) - - LOCHARACTER_BASE_PARAM_TO_PACK_EACH_(pack_, pack_type_, pack_state_, pack_str_); - -# undef pack_str_ -# undef pack_state_ -# undef pack_type_ -# undef pack_ - -# define each_(NAME, name) do { \ - if (base->type == LOCHARACTER_TYPE_##NAME) { \ - locharacter_##name##_pack_data(base, packer); \ - return; \ - } \ - } while (0) - - mpkutil_pack_str(packer, "data"); - LOCHARACTER_TYPE_EACH_(each_); - assert(false); - -# undef each_ -} - -void locharacter_base_initialize( - locharacter_base_t* base, - loresource_set_t* res, - loshader_character_drawer_t* drawer, - const locommon_ticker_t* ticker, - lobullet_pool_t* bullets, - loentity_store_t* entities, - loplayer_t* player) { - assert(base != NULL); - assert(res != NULL); - assert(drawer != NULL); - assert(ticker != NULL); - assert(bullets != NULL); - assert(entities != NULL); - assert(player != NULL); - - *base = (typeof(*base)) { - .super = { - .super = { - .vtable = { - .delete = locharacter_base_delete_, - .die = locharacter_base_die_, - .update = locharacter_base_update_, - .draw = locharacter_base_draw_, - .pack = locharacter_base_pack_, - }, - .subclass = LOENTITY_SUBCLASS_CHARACTER, - }, - .vtable = { - .apply_effect = locharacter_base_apply_effect_, - .knockback = locharacter_base_knockback_, - }, - }, - .res = res, - .drawer = drawer, - .ticker = ticker, - .bullets = bullets, - .entities = entities, - .player = player, - }; - loeffect_recipient_initialize(&base->recipient, ticker); -} - -void locharacter_base_reinitialize(locharacter_base_t* base, loentity_id_t id) { - assert(base != NULL); - -# define reset_(name, var) do { \ - base->var = (typeof(base->var)) {0}; \ - } while (0) -# define reset_str_(name, str) - - LOCHARACTER_BASE_PARAM_TO_PACK_EACH_( - reset_, reset_, reset_, reset_str_); - -# undef reset_str_ -# undef reset_ - - loeffect_recipient_reset(&base->recipient); - base->super.super.id = id; -} - -void locharacter_base_deinitialize(locharacter_base_t* base) { - assert(base != NULL); - - if (base->used) locharacter_base_delete_(&base->super.super); - loeffect_recipient_deinitialize(&base->recipient); -} - -bool locharacter_base_unpack( - locharacter_base_t* base, const msgpack_object* obj) { - assert(base != NULL); - assert(obj != NULL); - - locharacter_base_reinitialize(base, 0); - /* id will be overwritten below */ - - const char* v; - size_t vlen; - - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &base->var)) { \ - return NULL; \ - } \ - } while (0) -# define unpack_type_(name, var) do { \ - if (!mpkutil_get_str(item_(name), &v, &vlen) || \ - !locharacter_type_unstringify(&base->var, v, vlen)) { \ - return NULL; \ - } \ - } while (0) -# define unpack_state_(name, var) do { \ - if (!mpkutil_get_str(item_(name), &v, &vlen) || \ - !locharacter_state_unstringify(&base->var, v, vlen)) { \ - return NULL; \ - } \ - } while (0) -# define unpack_str_(name, str) do { \ - if (!mpkutil_get_str(item_(name), &v, &vlen) || \ - !(strncmp(v, str, vlen) == 0 && str[vlen] == 0)) { \ - return NULL; \ - } \ - } while (0) - - LOCHARACTER_BASE_PARAM_TO_PACK_EACH_( - unpack_, unpack_type_, unpack_state_, unpack_str_); - -# undef unpack_str_ -# undef unpack_state_ -# undef unpack_type_ -# undef unpack_ - - const msgpack_object* data = item_("data"); - -# define each_(NAME, name) do { \ - if (base->type == LOCHARACTER_TYPE_##NAME) { \ - return locharacter_##name##_unpack_data(base, data); \ - } \ - } while (0) - - LOCHARACTER_TYPE_EACH_(each_); - return false; - -# undef each_ - -# undef item_ -} diff --git a/core/locharacter/base.h b/core/locharacter/base.h deleted file mode 100644 index 7e0e0c5..0000000 --- a/core/locharacter/base.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "util/math/vector.h" - -#include "core/lobullet/pool.h" -#include "core/locommon/position.h" -#include "core/locommon/ticker.h" -#include "core/loeffect/recipient.h" -#include "core/loentity/character.h" -#include "core/loentity/store.h" -#include "core/loplayer/player.h" -#include "core/loresource/set.h" -#include "core/loshader/character.h" - -#include "./misc.h" - -typedef struct { - loentity_character_t super; - bool used; - - /* injected deps */ - loresource_set_t* res; - loshader_character_drawer_t* drawer; - const locommon_ticker_t* ticker; - lobullet_pool_t* bullets; - loentity_store_t* entities; - loplayer_t* player; - - /* temporary params for update */ - struct { - /* set before calling update function */ - loentity_ground_t* ground; - vec2_t player_pos; - - uint64_t time; - /* Defaultly equals to ticker->time. - But characters who have an event with music - overwrites this value for synchronization */ - - /* set by update function */ - float height; - bool bullet_hittest; - bool gravity; - - loshader_character_drawer_instance_t instance; - } cache; - - /* params to be packed (includes id) */ - locharacter_type_t type; - - loentity_id_t ground; - vec2_t pos; - float direction; - vec2_t knockback; - float gravity; - - loeffect_recipient_t recipient; - - locharacter_state_t state; - uint64_t since; - - uint64_t last_update_time; - uint64_t last_knockback_time; - uint64_t last_hit_time; - -# define LOCHARACTER_BASE_DATA_MAX_SIZE 256 - uint8_t data[LOCHARACTER_BASE_DATA_MAX_SIZE]; -} locharacter_base_t; - -void -locharacter_base_initialize( - locharacter_base_t* base, - loresource_set_t* res, - loshader_character_drawer_t* drawer, - const locommon_ticker_t* ticker, - lobullet_pool_t* bullets, - loentity_store_t* entities, - loplayer_t* player -); - -void -locharacter_base_reinitialize( - locharacter_base_t* base, - loentity_id_t id -); - -void -locharacter_base_deinitialize( - locharacter_base_t* base -); - -bool -locharacter_base_unpack( - locharacter_base_t* base, - const msgpack_object* obj -); diff --git a/core/locharacter/big_warder.c b/core/locharacter/big_warder.c deleted file mode 100644 index 3b86a0d..0000000 --- a/core/locharacter/big_warder.c +++ /dev/null @@ -1,787 +0,0 @@ -#include "./big_warder.h" - -#include -#include -#include - -#include "util/math/algorithm.h" -#include "util/math/vector.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" - -#include "core/lobullet/base.h" -#include "core/lobullet/bomb.h" -#include "core/lobullet/linear.h" -#include "core/lobullet/pool.h" -#include "core/locommon/easing.h" -#include "core/locommon/msgpack.h" -#include "core/loentity/entity.h" -#include "core/loplayer/combat.h" -#include "core/loplayer/event.h" -#include "core/loplayer/player.h" -#include "core/loresource/music.h" -#include "core/loresource/text.h" -#include "core/loshader/character.h" - -#include "./base.h" -#include "./misc.h" -#include "./util.h" - -typedef struct { - locharacter_event_holder_t event; - - int32_t phase; - vec2_t from; - vec2_t to; -} locharacter_big_warder_param_t; - -_Static_assert( - sizeof(locharacter_big_warder_param_t) <= LOCHARACTER_BASE_DATA_MAX_SIZE); - -#define LOCHARACTER_BIG_WARDER_PARAM_TO_PACK_EACH_(PROC) do { \ - PROC("event-start-time", event.start_time); \ - PROC("phase", phase); \ - PROC("from", from); \ - PROC("to", to); \ -} while (0) -#define LOCHARACTER_BIG_WARDER_PARAM_TO_PACK_COUNT 4 - -static const vec2_t locharacter_big_warder_size_ = vec2(.04f, .07f); - -static const loeffect_recipient_status_t -locharacter_big_warder_base_status_ = { - .attack = .1f, - .defence = .85f, - .speed = .1f, - .jump = .1f, -}; - -#define LOCHARACTER_BIG_WARDER_BEAT (60000/80.f) /* 80 BPM */ -#define LOCHARACTER_BIG_WARDER_MUSIC_DURATION \ - ((uint64_t) LOCHARACTER_BIG_WARDER_BEAT*144) - -#define LOCHARACTER_BIG_WARDER_MELODY_B_BEAT 80 - -#include "./big_warder.private.h" - -static void -locharacter_big_warder_start_wait_state_( - locharacter_base_t* c -); -static void -locharacter_big_warder_start_walk_state_( - locharacter_base_t* c -); -static void -locharacter_big_warder_start_shoot_state_( - locharacter_base_t* c -); -static void -locharacter_big_warder_start_combo_state_( - locharacter_base_t* c -); -static void -locharacter_big_warder_start_thrust_state_( - locharacter_base_t* c -); -static void -locharacter_big_warder_start_cooldown_state_( - locharacter_base_t* c -); -static void -locharacter_big_warder_start_stunned_state_( - locharacter_base_t* c -); -static void -locharacter_big_warder_start_dead_state_( - locharacter_base_t* c -); - -static void locharacter_big_warder_finalize_event_(locharacter_base_t* c) { - assert(c != NULL); - /* This function must start next state. */ - - locharacter_big_warder_param_t* p = (typeof(p)) c->data; - assert(p != NULL); - - locharacter_event_holder_release_control(&p->event); - - if (c->recipient.madness > 0) { - loentity_character_apply_effect( - &c->player->entity.super, &loeffect_curse_trigger()); - locharacter_big_warder_start_wait_state_(c); - } else { - loplayer_gain_stance(c->player, LOEFFECT_STANCE_ID_UNFINISHER); - locharacter_big_warder_start_dead_state_(c); - } -} - -static bool locharacter_big_warder_reset_if_player_left_( - locharacter_base_t* c) { - assert(c != NULL); - - if (MATH_ABS(c->cache.player_pos.x) < 1 && - 0 < c->cache.player_pos.y && c->cache.player_pos.y < 1) { - return false; - } - - locharacter_big_warder_param_t* p = (typeof(p)) c->data; - locharacter_event_holder_release_control(&p->event); - - locharacter_big_warder_start_wait_state_(c); - return true; -} - -static void locharacter_big_warder_update_wait_state_(locharacter_base_t* c) { - assert(c != NULL); - - static const uint64_t period = 1000; - - c->cache.gravity = true; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)%period*1.f/period; - t = (t*2) - 1; - t = MATH_ABS(t); - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = t*t*(3-2*t); - - /* ---- state transition ---- */ - if (MATH_ABS(c->cache.player_pos.x) < 1 && - 0 < c->cache.player_pos.y && c->cache.player_pos.y < 1) { - vec2_t diff; - vec2_sub(&diff, &c->cache.player_pos, &c->pos); - if (vec2_pow_length(&diff) < .5f*.5f) { - locharacter_big_warder_start_walk_state_(c); - return; - } - } -} -static void locharacter_big_warder_start_wait_state_(locharacter_base_t* c) { - assert(c != NULL); - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_WAIT; -} - -static void locharacter_big_warder_update_walk_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_BIG_WARDER_BEAT; - static const float linedur = beat*4; - static const uint64_t period = 800; - - locharacter_big_warder_param_t* p = (typeof(p)) c->data; - - const bool event = locharacter_event_holder_has_control(&p->event); - - const uint64_t min_duration = event? LOCHARACTER_BIG_WARDER_BEAT*16: 0; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &c->cache.instance; - if (c->pos.x != 0) { - float t = (c->cache.time - c->since)%period*1.f/period; - t = (t*2) - 1; - t = MATH_ABS(t); - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_WALK; - instance->motion_time = t; - } else { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - } - - /* ---- position ---- */ - if (c->pos.x != 0) c->direction = -MATH_SIGN(c->pos.x); - - c->pos.y = 0; - locommon_easing_linear_float(&c->pos.x, 0, c->ticker->delta_f/5); - - /* ---- event ---- */ - if (event) { - p->event.param->cinescope = true; - p->event.param->hide_hud = true; - - if (c->since+(p->phase+1)*linedur < c->cache.time) { - static const char* text[] = { - "boss_big_warder_line0", - "boss_big_warder_line1", - }; - if (p->phase < (int32_t) (sizeof(text)/sizeof(text[0]))) { - const char* v = loresource_text_get( - c->res->lang, text[(size_t) p->phase]); - loplayer_event_param_set_line(p->event.param, v, strlen(v)); - } else { - loplayer_event_param_set_line(p->event.param, "", 0); - } - ++p->phase; - } - } - - /* ---- state transition ---- */ - if (locharacter_big_warder_reset_if_player_left_(c)) return; - - if (c->pos.x == 0 && c->since + min_duration <= c->cache.time) { - if (event) { - p->event.param->hide_hud = false; - p->event.param->cinescope = false; - loplayer_event_param_set_line(p->event.param, "", 0); - } - locharacter_big_warder_start_shoot_state_(c); - return; - } -} -static void locharacter_big_warder_start_walk_state_( - locharacter_base_t* c) { - assert(c != NULL); - - locharacter_big_warder_param_t* p = (typeof(p)) c->data; - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_WALK; - - p->phase = 0; - - loeffect_recipient_reset(&c->recipient); - - if (!loeffect_stance_set_has( - &c->player->status.stances, LOEFFECT_STANCE_ID_UNFINISHER)) { - locharacter_event_holder_take_control(&p->event); - } -} - -static void locharacter_big_warder_update_shoot_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_BIG_WARDER_BEAT; - static const uint64_t duration = beat*3; - - const uint64_t t = c->cache.time - c->since; - - c->cache.bullet_hittest = true; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = t; - - /* ---- shooting ---- */ - locharacter_big_warder_param_t* p = (typeof(p)) c->data; - if (p->phase < 4 && p->phase*beat/2 <= c->cache.time - c->since) { - ++p->phase; - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_linear_light_build(b, (&(lobullet_linear_param_t) { - .owner = c->super.super.id, - .pos = c->super.super.pos, - .size = vec2(.04f, .04f), - .velocity = vec2(c->direction*.5f, 0), - .color = vec4(.6f, .6f, .6f, .8f), - .acceleration = vec2(0, 0), - .duration = 2000, - .knockback = .4f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/2), - })); - loentity_store_add(c->entities, &b->super.super); - } - - /* ---- state transition ---- */ - if (locharacter_big_warder_reset_if_player_left_(c)) return; - - if (c->since + duration <= c->cache.time) { - locharacter_big_warder_start_combo_state_(c); - return; - } -} -static void locharacter_big_warder_start_shoot_state_(locharacter_base_t* c) { - assert(c != NULL); - - locharacter_big_warder_param_t* p = (typeof(p)) c->data; - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_SHOOT; - - c->direction = c->cache.player_pos.x - c->pos.x; - c->direction = c->direction > 0? 1: -1; - - p->phase = 0; -} - -static void locharacter_big_warder_update_combo_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_BIG_WARDER_BEAT; - static const uint64_t step_dur = beat; - static const uint64_t attack_dur = beat*2; - - const locharacter_big_warder_param_t* p = (typeof(p)) c->data; - - c->cache.bullet_hittest = true; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - if (c->since + step_dur > c->cache.time) { - const float t = (c->cache.time - c->since)*1.f/step_dur; - - /* ---- position ---- */ - vec2_t dist; - vec2_sub(&dist, &p->to, &p->from); - vec2_muleq(&dist, t*t*(3-2*t)); - c->pos = p->from; - vec2_addeq(&c->pos, &dist); - - /* ---- motion ---- */ - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_WALK; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->motion_time = 1-powf(2*t-1, 4); - } else { - float t = (c->cache.time - c->since - step_dur)*1.f/attack_dur; - t *= 4; - t -= (uint64_t) t; - - /* ---- motion ---- */ - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->motion_time = t*t; - } - - /* ---- state transition ---- */ - if (locharacter_big_warder_reset_if_player_left_(c)) return; - - if (c->since + step_dur + attack_dur <= c->cache.time) { - locharacter_big_warder_start_thrust_state_(c); - return; - } -} -static void locharacter_big_warder_start_combo_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_BIG_WARDER_BEAT; - static const uint64_t parry = 400; - - locharacter_big_warder_param_t* p = (typeof(p)) c->data; - - if (c->last_knockback_time+parry > c->cache.time) { - locharacter_big_warder_start_stunned_state_(c); - return; - } - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_COMBO; - - c->direction = c->cache.player_pos.x - c->pos.x; - c->direction = c->direction > 0? 1: -1; - - c->gravity = 0; - - p->from = c->pos; - p->to = c->cache.player_pos; - p->to.x -= c->direction * locharacter_big_warder_size_.x; - p->to.y -= locharacter_big_warder_size_.y*.2f; - - for (size_t i = 0; i < 4; ++i) { - loplayer_attack(c->player, &(loplayer_combat_attack_t) { - .attacker = c->super.super.id, - .start = c->ticker->time + (uint64_t) (beat*(i/2.f+1)), - .duration = beat/4, - .knockback = vec2(c->direction*.1f, 0), - .effect = loeffect_immediate_damage(c->recipient.status.attack), - }); - } -} - -static void locharacter_big_warder_update_thrust_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_BIG_WARDER_BEAT; - static const uint64_t duration = beat; - - locharacter_big_warder_param_t* p = (typeof(p)) c->data; - - c->cache.bullet_hittest = true; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - - const uint64_t ti = c->cache.time - c->since; - if (p->phase <= 0) { - /* ---- disappear ---- */ - instance->color.w *= 1 - ti/beat/4; - if (ti > beat/4) { - c->pos = p->to; - if (p->phase < 0) { /* backattack */ - c->direction *= -1; - p->phase = 0; - } - ++p->phase; - } - - } else if (p->phase == 1) { - /* ---- appear ---- */ - float t = (ti/beat/2 - .5f)*2; - if (t > 1) t = 1; - - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->motion_time = t; - instance->color.w *= t; - - if (ti > beat/2) ++p->phase; - - } else { - /* ---- attack ---- */ - float t = (ti/beat - .5f)*2; - if (t > 1) t = 1; - - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->motion_time = t; - } - - /* ---- state transition ---- */ - if (locharacter_big_warder_reset_if_player_left_(c)) return; - - if (c->since + duration < c->cache.time) { - locharacter_big_warder_start_cooldown_state_(c); - return; - } -} -static void locharacter_big_warder_start_thrust_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_BIG_WARDER_BEAT; - static const float bmelo = LOCHARACTER_BIG_WARDER_MELODY_B_BEAT; - - locharacter_big_warder_param_t* p = (typeof(p)) c->data; - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_THRUST; - - c->direction = c->cache.player_pos.x - c->pos.x; - c->direction = c->direction > 0? 1: -1; - - c->gravity = 0; - - const bool backattack = - locharacter_event_holder_has_control(&p->event) && - (c->cache.time - p->event.start_time >= beat*bmelo); - const float backattack_f = backattack? 1: -1; - - p->to = c->cache.player_pos; - p->to.x += c->direction*locharacter_big_warder_size_.x*backattack_f; - p->to.y -= locharacter_big_warder_size_.y*.2f; - - p->phase = backattack? -1: 0; - - loplayer_attack(c->player, &(loplayer_combat_attack_t) { - .attacker = c->super.super.id, - .start = c->ticker->time + (uint64_t) (beat/2), - .duration = beat/2, - .knockback = vec2(-backattack_f*c->direction*.1f, 0), - .effect = loeffect_immediate_damage(c->recipient.status.attack), - }); -} - -static void locharacter_big_warder_update_cooldown_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_BIG_WARDER_BEAT; - static const uint64_t duration = beat*4; - - const uint64_t ti = c->cache.time - c->since; - - const locharacter_big_warder_param_t* p = (typeof(p)) c->data; - - c->cache.bullet_hittest = true; - c->cache.gravity = true; - - /* ---- motion ---- */ - float t = ti*1.f/duration; - if (t > 1) t = 1; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = t; - - /* ---- position ---- */ - if (ti < beat*2) { - t = ti/beat/2; - vec2_sub(&c->pos, &p->to, &p->from); - vec2_muleq(&c->pos, t*t*(3-2*t)); - vec2_addeq(&c->pos, &p->from); - - t = t*2-1; - t = 1-powf(MATH_ABS(t), 2); - c->pos.y += t*c->recipient.status.jump/2; - } else { - c->pos = vec2(0, 0); - } - - /* ---- state transition ---- */ - if (locharacter_big_warder_reset_if_player_left_(c)) return; - - if (c->since + duration <= c->cache.time) { - locharacter_big_warder_start_shoot_state_(c); - return; - } -} -static void locharacter_big_warder_start_cooldown_state_( - locharacter_base_t* c) { - assert(c != NULL); - - locharacter_big_warder_param_t* p = (typeof(p)) c->data; - - if (locharacter_event_holder_has_control(&p->event)) { - static const uint64_t dur = LOCHARACTER_BIG_WARDER_MUSIC_DURATION; - if (p->event.start_time+dur < c->cache.time) { - locharacter_big_warder_finalize_event_(c); - return; - } - } else { - if (c->recipient.madness <= 0) { - locharacter_big_warder_start_dead_state_(c); - return; - } - } - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_COOLDOWN; - - p->from = c->pos; - p->to = vec2(0, 0); -} - -static void locharacter_big_warder_update_stunned_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_BIG_WARDER_BEAT; - static const uint64_t duration = beat*4; - - c->cache.gravity = true; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)*1.f/duration; - t *= 6; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - if (t < 1) { - t = 1-powf(1-t, 6); - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->motion_time = t; - } else { - t = (t-1)/5; - if (t > 1) t = 1; - t = t*t*(3-2*t); - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = t; - } - - /* ---- state transition ---- */ - if (c->since + duration <= c->cache.time) { - locharacter_big_warder_start_cooldown_state_(c); - return; - } -} -static void locharacter_big_warder_start_stunned_state_( - locharacter_base_t* c) { - assert(c != NULL); - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_STUNNED; - - loeffect_recipient_apply_effect( - &c->recipient, &loeffect_immediate_damage(1.f)); -} - -static void locharacter_big_warder_update_dead_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const uint64_t anime_duration = 4000; - static const uint64_t duration = 30000; - - c->cache.gravity = true; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)*1.f/anime_duration; - if (t > 1) t = 1; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->motion_time = t*t; - instance->color.w *= 1-t; - - /* ---- state transition ---- */ - if (c->since+duration < c->cache.time) { - locharacter_big_warder_start_wait_state_(c); - return; - } -} -static void locharacter_big_warder_start_dead_state_( - locharacter_base_t* c) { - assert(c != NULL); - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_DEAD; - - loplayer_gain_faith(c->player, .8f); -} - -bool locharacter_big_warder_update(locharacter_base_t* base) { - assert(base != NULL); - - static const vec2_t size = locharacter_big_warder_size_; - static const float height = size.y * 1.4f; - static const float drawsz = MATH_MAX(size.x, size.y); - - locharacter_big_warder_param_t* p = (typeof(p)) base->data; - - loeffect_recipient_update( - &base->recipient, &locharacter_big_warder_base_status_); - - if (!locharacter_event_holder_update(&p->event)) { - locharacter_big_warder_start_wait_state_(base); - } - - base->cache.instance = (loshader_character_drawer_instance_t) { - .character_id = LOSHADER_CHARACTER_ID_WARDER, - .marker_offset = vec2(0, height - drawsz), - .pos = vec2(0, drawsz - height), - .size = vec2(drawsz, drawsz), - .color = vec4(.2f, 0, 0, 1), - }; - - switch (base->state) { - case LOCHARACTER_STATE_WAIT: - locharacter_big_warder_update_wait_state_(base); - break; - case LOCHARACTER_STATE_WALK: - locharacter_big_warder_update_walk_state_(base); - break; - case LOCHARACTER_STATE_SHOOT: - locharacter_big_warder_update_shoot_state_(base); - break; - case LOCHARACTER_STATE_COMBO: - locharacter_big_warder_update_combo_state_(base); - break; - case LOCHARACTER_STATE_THRUST: - locharacter_big_warder_update_thrust_state_(base); - break; - case LOCHARACTER_STATE_COOLDOWN: - locharacter_big_warder_update_cooldown_state_(base); - break; - case LOCHARACTER_STATE_STUNNED: - locharacter_big_warder_update_stunned_state_(base); - break; - case LOCHARACTER_STATE_DEAD: - locharacter_big_warder_update_dead_state_(base); - break; - default: - locharacter_big_warder_start_wait_state_(base); - } - locharacter_big_warder_update_passive_action_(base); - - base->cache.height = height; - - base->cache.instance.marker = !!base->cache.bullet_hittest; - base->cache.instance.size.x *= base->direction; - return true; -} - -void locharacter_big_warder_build( - locharacter_base_t* base, loentity_id_t ground) { - assert(base != NULL); - - base->type = LOCHARACTER_TYPE_BIG_WARDER; - - base->ground = ground; - - base->pos = vec2(.7f, 0); - base->direction = 1; - - base->state = LOCHARACTER_STATE_WAIT; - base->since = base->cache.time; - - locharacter_big_warder_param_t* p = (typeof(p)) base->data; - *p = (typeof(*p)) {0}; - - locharacter_event_holder_initialize( - &p->event, - &base->res->music.boss_big_warder, - base, - LOCHARACTER_BIG_WARDER_MUSIC_DURATION, - 0); -} - -void locharacter_big_warder_tear_down(locharacter_base_t* base) { - assert(base != NULL); - - locharacter_big_warder_param_t* p = (typeof(p)) base->data; - locharacter_event_holder_deinitialize(&p->event); -} - -void locharacter_big_warder_pack_data( - const locharacter_base_t* base, msgpack_packer* packer) { - assert(base != NULL); - assert(packer != NULL); - - const locharacter_big_warder_param_t* p = (typeof(p)) base->data; - - msgpack_pack_map(packer, LOCHARACTER_BIG_WARDER_PARAM_TO_PACK_COUNT); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &p->var); \ - } while (0) - - LOCHARACTER_BIG_WARDER_PARAM_TO_PACK_EACH_(pack_); - -# undef pack_ -} - -bool locharacter_big_warder_unpack_data( - locharacter_base_t* base, const msgpack_object* obj) { - assert(base != NULL); - - locharacter_big_warder_param_t* p = (typeof(p)) base->data; - - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &p->var)) { \ - return false; \ - } \ - } while (0) - - LOCHARACTER_BIG_WARDER_PARAM_TO_PACK_EACH_(unpack_); - -# undef unpack_ - -# undef item_ - - locharacter_event_holder_initialize( - &p->event, - &base->res->music.boss_big_warder, - base, - LOCHARACTER_BIG_WARDER_MUSIC_DURATION, - p->event.start_time); - return true; -} diff --git a/core/locharacter/big_warder.h b/core/locharacter/big_warder.h deleted file mode 100644 index 5e7a02a..0000000 --- a/core/locharacter/big_warder.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -#include - -#include "core/loentity/entity.h" - -#include "./base.h" - -bool -locharacter_big_warder_update( - locharacter_base_t* base -); - -void -locharacter_big_warder_build( - locharacter_base_t* base, - loentity_id_t ground -); - -void -locharacter_big_warder_tear_down( - locharacter_base_t* base -); - -void -locharacter_big_warder_pack_data( - const locharacter_base_t* base, - msgpack_packer* packer -); - -bool -locharacter_big_warder_unpack_data( - locharacter_base_t* base, - const msgpack_object* obj -); diff --git a/core/locharacter/big_warder.private.h b/core/locharacter/big_warder.private.h deleted file mode 100644 index 39d8bb3..0000000 --- a/core/locharacter/big_warder.private.h +++ /dev/null @@ -1,157 +0,0 @@ -static void locharacter_big_warder_update_passive_action_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_BIG_WARDER_BEAT; - - const locharacter_big_warder_param_t* p = (typeof(p)) c->data; - if (!locharacter_event_holder_has_control(&p->event)) return; - - const uint64_t dt = c->cache.time - c->last_update_time; - const uint64_t t = c->cache.time - p->event.start_time; - - const float beats = t/beat; - const float last_beats = t > dt? (t-dt)/beat: 0; - -# define name_pos_(name, x, y) \ - locommon_position_t name = c->cache.ground->super.pos; \ - vec2_addeq(&name.fract, &vec2(x, y)); \ - locommon_position_reduce(&name); - - name_pos_(top, 0, .8f); - name_pos_(center, 0, .25f); - name_pos_(left, -.3f, .2f); - name_pos_(right, .3f, .2f); - name_pos_(leftbottom, -.4f, .1f); - name_pos_(rightbottom, .4f, .1f); - name_pos_(leftbottom_off, -.6f, .1f); - name_pos_(rightbottom_off, .6f, .1f); - -# undef name_pos_ - -# define trigger_on_(x) (last_beats < (x) && beats >= (x)) - - /* ---- intro -> A melody ---- */ - if (trigger_on_(12)) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_square_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = center, - .size = vec2(.4f, .4f), - .angle = MATH_PI/4, - .color = vec4(1, 1, 1, .4f), - .silent = true, - .beat = beat, - .step = 4, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/4), - })); - loentity_store_add(c->entities, &b->super.super); - } - - /* ---- A melody ---- */ - for (size_t i = 48; i < 80; i+=8) { - for (size_t j = 0; j < 2; ++j) { - if (trigger_on_(i-4 + j*4)) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_triangle_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = j? leftbottom: rightbottom, - .size = vec2(.05f, .15f), - .angle = j? 0: MATH_PI, - .color = vec4(1, 1, 1, .6f), - .silent = true, - .beat = beat, - .step = 4, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/2), - })); - loentity_store_add(c->entities, &b->super.super); - } - if (trigger_on_(i + j*4)) { - static const float speed = 1.4f; - static const float accel = .7f / (beat*2); - - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_linear_triangle_build(b, (&(lobullet_linear_param_t) { - .owner = c->super.super.id, - .pos = j? leftbottom_off: rightbottom_off, - .size = vec2(.05f, .15f), - .velocity = vec2(j? speed: -speed, 0), - .acceleration = vec2(j? -accel: accel, 0), - .color = vec4(1, 1, 1, .8f), - .duration = beat*2, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/2), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - } - - /* ---- B melody ---- */ - static const int32_t bmelo_trigger_beats[] = {92, 108}; - static const size_t bmelo_trigger_counts = - sizeof(bmelo_trigger_beats)/sizeof(bmelo_trigger_beats[0]); - for (size_t i = 0; i < bmelo_trigger_counts; ++i) { - const int32_t st = bmelo_trigger_beats[i]; - for (int32_t j = 0; j < 4; ++j) { - if (trigger_on_(st + j/2.f)) { - for (int32_t x = -2; x <= 2; ++x) { - locommon_position_t pos = center; - vec2_addeq(&pos.fract, &vec2(x/2.f*.45f, (j-1)/4.f*.3f)); - locommon_position_reduce(&pos); - - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_square_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = pos, - .size = vec2(.1f, .1f), - .angle = MATH_PI/4, - .color = vec4(1, 1, 1, .6f), - .silent = true, - .beat = beat*2, - .step = 2, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/2), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - } - } - - /* ---- C melody ---- */ - for (int32_t i = 0; i < 8; ++i) { - for (int32_t x = -10; x <= 10; ++x) { - if (trigger_on_(112 + i*4 + (x+10)/100.f)) { - locommon_position_t pos = center; - pos.fract.x += x/10.f*.47f; - pos.fract.y -= .13f; - locommon_position_reduce(&pos); - - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_square_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = pos, - .size = vec2(.06f, .06f), - .angle = MATH_PI/4, - .color = vec4(1, 1, 1, .4f), - .silent = true, - .beat = beat, - .step = 4, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/2), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - } - -# undef trigger_on_ -} diff --git a/core/locharacter/cavia.c b/core/locharacter/cavia.c deleted file mode 100644 index 6a8b412..0000000 --- a/core/locharacter/cavia.c +++ /dev/null @@ -1,265 +0,0 @@ -#include "./cavia.h" - -#include -#include -#include - -#include "util/math/algorithm.h" -#include "util/math/vector.h" - -#include "core/loeffect/recipient.h" -#include "core/loentity/entity.h" -#include "core/loplayer/event.h" -#include "core/loplayer/player.h" -#include "core/loshader/character.h" - -#include "./base.h" -#include "./misc.h" - -static const vec2_t locharacter_cavia_size_ = vec2(.02f, .05f); - -static const loeffect_recipient_status_t locharacter_cavia_base_status_ = { - .attack = .2f, - .defence = .1f, - .speed = .05f, -}; - -static void -locharacter_cavia_start_walk_state_( - locharacter_base_t* base -); -static bool -locharacter_cavia_start_thrust_state_( - locharacter_base_t* base -); -static void -locharacter_cavia_start_cooldown_state_( - locharacter_base_t* base -); -static void -locharacter_cavia_start_dead_state_( - locharacter_base_t* base -); - -static void locharacter_cavia_update_walk_state_(locharacter_base_t* base) { - assert(base != NULL); - - /* ---- movement ---- */ - const vec2_t* gsize = &base->cache.ground->size; - const float s = base->recipient.status.speed; - base->pos.x += base->ticker->delta_f * base->direction * s / gsize->x; - - if (MATH_ABS(base->pos.x) > 1) base->direction *= -1; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &base->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_WALK; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - - const int32_t p = 70/s; - const float t = (base->ticker->time - base->since)%p*2.0f/p - 1; - instance->motion_time = MATH_ABS(t); - - /* ---- dead ---- */ - if (base->recipient.madness <= 0) { - locharacter_cavia_start_dead_state_(base); - return; - } - - /* ---- trigger thrust ---- */ - if (loplayer_event_get_param(base->player->event) == NULL) { - vec2_t dist; - locommon_position_sub( - &dist, &base->player->entity.super.super.pos, &base->super.super.pos); - const float sdist_x = dist.x * base->direction; - if (MATH_ABS(dist.y) < locharacter_cavia_size_.y && - sdist_x >= locharacter_cavia_size_.x && - sdist_x <= locharacter_cavia_size_.x*2) { - if (locharacter_cavia_start_thrust_state_(base)) return; - } - } -} -static void locharacter_cavia_start_walk_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_WALK; -} - -static void locharacter_cavia_update_thrust_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t premotion = 1200; - static const uint64_t duration = 1500; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &base->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - - float t = (base->ticker->time - base->since)*1.0f/premotion; - if (t > 1) t = 1; - instance->motion_time = t*t*t*t; - - /* ---- cooldown ---- */ - if (base->since+duration <= base->ticker->time) { - /* TODO(catfoot): go to cooldown */ - locharacter_cavia_start_cooldown_state_(base); - return; - } -} -static bool locharacter_cavia_start_thrust_state_(locharacter_base_t* base) { - assert(base != NULL); - - const loplayer_combat_attack_t attack = { - .attacker = base->super.super.id, - .start = base->ticker->time + 1000, - .duration = 500, - .knockback = vec2(base->direction*.1f, 0), - .effect = loeffect_immediate_damage(base->recipient.status.attack), - }; - if (!loplayer_attack(base->player, &attack)) return false; - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_THRUST; - return true; -} - -static void locharacter_cavia_update_cooldown_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t duration = 500; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &base->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - - float t = (base->ticker->time - base->since)*1.0f/duration; - if (t > 1) t = 1; - instance->motion_time = t*t*(3-2*t); - - /* ---- cooldown ---- */ - if (base->since+duration <= base->ticker->time) { - if (base->recipient.madness <= 0) { - locharacter_cavia_start_dead_state_(base); - return; - } else { - locharacter_cavia_start_walk_state_(base); - return; - } - } -} -static void locharacter_cavia_start_cooldown_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_COOLDOWN; -} - -static void locharacter_cavia_update_dead_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t anime = 500; - static const uint64_t duration = 30000; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &base->cache.instance; - if (base->since+anime > base->ticker->time) { - const float t = (base->ticker->time - base->since)*1.0f/anime; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->motion_time = t*t; - - } else if (base->since+anime*2 > base->ticker->time) { - const float t = (base->ticker->time - anime - base->since)*1.0f/anime; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->motion_time = t*t; - - } else if (base->ticker->time+anime > base->since+duration) { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = - 1 - (base->since + duration - base->ticker->time)*1.0f/anime; - - } else { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - } - - /* ---- revive ---- */ - if (base->since+duration <= base->ticker->time) { - loeffect_recipient_reset(&base->recipient); - locharacter_cavia_start_walk_state_(base); - return; - } -} -static void locharacter_cavia_start_dead_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_DEAD; - - loplayer_gain_faith(base->player, .1f); -} - -bool locharacter_cavia_update(locharacter_base_t* base) { - assert(base != NULL); - - static const vec2_t size = locharacter_cavia_size_; - static const vec4_t color = vec4(.1f, .1f, .1f, 1); - static const float height = size.y*1.4f; - static const float drawsz = MATH_MAX(size.x, size.y); - - loeffect_recipient_update(&base->recipient, &locharacter_cavia_base_status_); - - base->cache.instance = (loshader_character_drawer_instance_t) { - .character_id = LOSHADER_CHARACTER_ID_CAVIA, - .marker_offset = vec2(0, height - drawsz), - .pos = vec2(0, drawsz - height), - .size = vec2(drawsz, drawsz), - .color = color, - }; - - switch (base->state) { - case LOCHARACTER_STATE_WALK: - locharacter_cavia_update_walk_state_(base); - break; - case LOCHARACTER_STATE_THRUST: - locharacter_cavia_update_thrust_state_(base); - break; - case LOCHARACTER_STATE_COOLDOWN: - locharacter_cavia_update_cooldown_state_(base); - break; - case LOCHARACTER_STATE_DEAD: - locharacter_cavia_update_dead_state_(base); - break; - default: - locharacter_cavia_start_walk_state_(base); - } - - base->cache.bullet_hittest = base->state != LOCHARACTER_STATE_DEAD; - - base->cache.height = height; - - base->cache.instance.size.x *= base->direction; - base->cache.instance.marker = !!base->cache.bullet_hittest; - return true; -} - -void locharacter_cavia_build( - locharacter_base_t* base, const locharacter_cavia_param_t* param) { - assert(base != NULL); - assert(param != NULL); - - base->type = LOCHARACTER_TYPE_CAVIA; - - base->ground = param->ground; - - base->pos = vec2(param->pos, 0); - base->direction = param->direction == 1? 1: -1; - - base->state = LOCHARACTER_STATE_WALK; - base->since = base->ticker->time; -} diff --git a/core/locharacter/cavia.h b/core/locharacter/cavia.h deleted file mode 100644 index 0d65292..0000000 --- a/core/locharacter/cavia.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include - -#include - -#include "util/math/vector.h" - -#include "core/loentity/entity.h" - -#include "./base.h" - -typedef struct { - loentity_id_t ground; - float pos; - float direction; -} locharacter_cavia_param_t; - -bool -locharacter_cavia_update( - locharacter_base_t* base -); - -void -locharacter_cavia_build( - locharacter_base_t* base, - const locharacter_cavia_param_t* param -); - -#define locharacter_cavia_tear_down(base) - -#define locharacter_cavia_pack_data(base, packer) \ - msgpack_pack_nil(packer) - -#define locharacter_cavia_unpack_data(base, obj) \ - (obj != NULL) diff --git a/core/locharacter/encephalon.c b/core/locharacter/encephalon.c deleted file mode 100644 index cfe9ad4..0000000 --- a/core/locharacter/encephalon.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "./encephalon.h" - -#include -#include -#include - -#include - -#include "util/chaos/xorshift.h" -#include "util/math/algorithm.h" -#include "util/math/vector.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" - -#include "core/locommon/msgpack.h" -#include "core/loentity/entity.h" -#include "core/loplayer/player.h" -#include "core/loresource/sound.h" -#include "core/loshader/character.h" - -#include "./base.h" -#include "./misc.h" - -typedef struct { - float progress; -} locharacter_encephalon_param_t; - -_Static_assert( - sizeof(locharacter_encephalon_param_t) <= LOCHARACTER_BASE_DATA_MAX_SIZE); - -static const vec2_t locharacter_encephalon_size_ = vec2(.1f, .1f); - -#define LOCHARACTER_ENCEPHALON_PARAM_TO_PACK_EACH_(PROC) do { \ - PROC("progress", progress); \ -} while (0) -#define LOCHARACTER_ENCEPHALON_PARAM_TO_PACK_COUNT 1 - -static void locharacter_encephalon_update_progress_(locharacter_base_t* base) { - assert(base != NULL); - - locharacter_encephalon_param_t* p = (typeof(p)) base->data; - - const vec2_t* player = &base->cache.player_pos; - const bool near = - MATH_ABS(player->x) < 1 && - 0 <= player->y && player->y < locharacter_encephalon_size_.y; - - if (near && base->state == LOCHARACTER_STATE_WAIT) { - p->progress += base->ticker->delta_f; - if (p->progress >= 1) { - loplayer_touch_encephalon(base->player); - base->state = LOCHARACTER_STATE_COOLDOWN; - loresource_sound_play(base->res->sound, "touch_gate"); - } - } else { - p->progress -= base->ticker->delta_f * 2; - if (!near) base->state = LOCHARACTER_STATE_WAIT; - } - p->progress = MATH_CLAMP(p->progress, 0, 1); -} - -bool locharacter_encephalon_update(locharacter_base_t* base) { - assert(base != NULL); - - locharacter_encephalon_update_progress_(base); - - const locharacter_encephalon_param_t* p = (typeof(p)) base->data; - - base->pos = vec2(0, locharacter_encephalon_size_.y); - - base->cache.instance = (loshader_character_drawer_instance_t) { - .character_id = LOSHADER_CHARACTER_ID_ENCEPHALON, - .from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1, - .to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1, - .color = vec4(p->progress*.5f, 0, 0, .95f), - .size = locharacter_encephalon_size_, - }; - if (base->state == LOCHARACTER_STATE_COOLDOWN && p->progress > 0) { - base->cache.instance.color.w *= - chaos_xorshift(base->ticker->time)%100/100.f; - } - return true; -} - -void locharacter_encephalon_build( - locharacter_base_t* base, loentity_id_t ground) { - assert(base != NULL); - - base->type = LOCHARACTER_TYPE_ENCEPHALON; - - base->ground = ground; - base->pos = vec2(0, 0); - - base->state = LOCHARACTER_STATE_WAIT; -} - -void locharacter_encephalon_pack_data( - const locharacter_base_t* base, msgpack_packer* packer) { - assert(base != NULL); - assert(packer != NULL); - - const locharacter_encephalon_param_t* p = (typeof(p)) base->data; - - msgpack_pack_map(packer, LOCHARACTER_ENCEPHALON_PARAM_TO_PACK_COUNT); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &p->var); \ - } while (0) - - LOCHARACTER_ENCEPHALON_PARAM_TO_PACK_EACH_(pack_); - -# undef pack_ -} - -bool locharacter_encephalon_unpack_data( - locharacter_base_t* base, const msgpack_object* obj) { - assert(base != NULL); - - locharacter_encephalon_param_t* p = (typeof(p)) base->data; - - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &p->var)) { \ - return false; \ - } \ - } while (0) - - LOCHARACTER_ENCEPHALON_PARAM_TO_PACK_EACH_(unpack_); - return true; - -# undef unpack_ - -# undef item_ -} diff --git a/core/locharacter/encephalon.h b/core/locharacter/encephalon.h deleted file mode 100644 index d8657a8..0000000 --- a/core/locharacter/encephalon.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include - -#include - -#include "core/loentity/entity.h" - -#include "./base.h" - -bool -locharacter_encephalon_update( - locharacter_base_t* base -); - -void -locharacter_encephalon_build( - locharacter_base_t* base, - loentity_id_t ground -); - -#define locharacter_encephalon_tear_down(base) - -void -locharacter_encephalon_pack_data( - const locharacter_base_t* base, - msgpack_packer* packer -); - -bool -locharacter_encephalon_unpack_data( - locharacter_base_t* base, - const msgpack_object* obj -); diff --git a/core/locharacter/greedy_scientist.c b/core/locharacter/greedy_scientist.c deleted file mode 100644 index 838cf1c..0000000 --- a/core/locharacter/greedy_scientist.c +++ /dev/null @@ -1,607 +0,0 @@ -#include "./greedy_scientist.h" - -#include -#include -#include -#include - -#include "util/chaos/xorshift.h" -#include "util/math/algorithm.h" -#include "util/math/constant.h" -#include "util/math/vector.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" - -#include "core/lobullet/base.h" -#include "core/lobullet/bomb.h" -#include "core/lobullet/linear.h" -#include "core/lobullet/pool.h" -#include "core/locommon/easing.h" -#include "core/locommon/msgpack.h" -#include "core/loentity/entity.h" -#include "core/loplayer/combat.h" -#include "core/loplayer/event.h" -#include "core/loplayer/player.h" -#include "core/loresource/music.h" -#include "core/loresource/text.h" -#include "core/loshader/character.h" - -#include "./base.h" -#include "./misc.h" -#include "./util.h" - -typedef struct { - locharacter_event_holder_t event; - - int32_t phase; - vec2_t from; - vec2_t to; -} locharacter_greedy_scientist_param_t; - -_Static_assert( - sizeof(locharacter_greedy_scientist_param_t) <= LOCHARACTER_BASE_DATA_MAX_SIZE); - -#define LOCHARACTER_GREEDY_SCIENTIST_PARAM_TO_PACK_EACH_(PROC) do { \ - PROC("event-start-time", event.start_time); \ - PROC("phase", phase); \ - PROC("from", from); \ - PROC("to", to); \ -} while (0) -#define LOCHARACTER_GREEDY_SCIENTIST_PARAM_TO_PACK_COUNT 4 - -static const vec2_t locharacter_greedy_scientist_size_ = vec2(.03f, .07f); - -static const loeffect_recipient_status_t -locharacter_greedy_scientist_base_status_ = { - .attack = .2f, - .defence = .85f, - .speed = .1f, - .jump = .1f, -}; - -#define LOCHARACTER_GREEDY_SCIENTIST_BEAT (60000/140.f) /* 140 BPM */ -#define LOCHARACTER_GREEDY_SCIENTIST_MUSIC_DURATION \ - ((uint64_t) LOCHARACTER_GREEDY_SCIENTIST_BEAT*128) - -#define LOCHARACTER_GREEDY_SCIENTIST_MELODY_B_BEAT 52 - -#include "./greedy_scientist.private.h" - -static void -locharacter_greedy_scientist_start_wait_state_( - locharacter_base_t* c -); -static void -locharacter_greedy_scientist_start_standup_state_( - locharacter_base_t* c -); -static void -locharacter_greedy_scientist_start_combo_state_( - locharacter_base_t* c -); -static void -locharacter_greedy_scientist_start_cooldown_state_( - locharacter_base_t* c -); -static void -locharacter_greedy_scientist_start_stunned_state_( - locharacter_base_t* c -); -static void -locharacter_greedy_scientist_start_dead_state_( - locharacter_base_t* c -); - -static void locharacter_greedy_scientist_finalize_event_(locharacter_base_t* c) { - assert(c != NULL); - /* This function must start next state. */ - - locharacter_greedy_scientist_param_t* p = (typeof(p)) c->data; - assert(p != NULL); - - locharacter_event_holder_release_control(&p->event); - - if (c->recipient.madness > 0) { - loentity_character_apply_effect( - &c->player->entity.super, &loeffect_curse_trigger()); - locharacter_greedy_scientist_start_wait_state_(c); - } else { - loplayer_gain_stance(c->player, LOEFFECT_STANCE_ID_PHILOSOPHER); - locharacter_greedy_scientist_start_dead_state_(c); - } -} - -static bool locharacter_greedy_scientist_reset_if_player_left_( - locharacter_base_t* c) { - assert(c != NULL); - - if (MATH_ABS(c->cache.player_pos.x) < 1 && - 0 < c->cache.player_pos.y && c->cache.player_pos.y < 1) { - return false; - } - - locharacter_greedy_scientist_param_t* p = (typeof(p)) c->data; - locharacter_event_holder_release_control(&p->event); - - locharacter_greedy_scientist_start_wait_state_(c); - return true; -} - -static void locharacter_greedy_scientist_update_wait_state_(locharacter_base_t* c) { - assert(c != NULL); - - static const uint64_t min_duration = LOCHARACTER_GREEDY_SCIENTIST_BEAT*4; - - c->cache.gravity = true; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = 0; - - /* ---- state transition ---- */ - if (c->since + min_duration <= c->cache.time) { - if (MATH_ABS(c->cache.player_pos.x) < 1 && - 0 < c->cache.player_pos.y && c->cache.player_pos.y < 1) { - vec2_t diff; - vec2_sub(&diff, &c->cache.player_pos, &c->pos); - if (vec2_pow_length(&diff) < .5f*.5f) { - locharacter_greedy_scientist_start_standup_state_(c); - return; - } - } - } -} -static void locharacter_greedy_scientist_start_wait_state_(locharacter_base_t* c) { - assert(c != NULL); - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_WAIT; -} - -static void locharacter_greedy_scientist_update_standup_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_GREEDY_SCIENTIST_BEAT; - static const uint64_t period = beat*4; - - locharacter_greedy_scientist_param_t* p = (typeof(p)) c->data; - - const bool event = locharacter_event_holder_has_control(&p->event); - const uint64_t duration = event? beat*20: beat*8; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)%period*1.f/period; - t = t*2-1; - t = MATH_ABS(t); - t = t*t*(3-2*t); - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND2; - instance->motion_time = t; - - /* ---- event ---- */ - if (event) { - p->event.param->cinescope = true; - p->event.param->hide_hud = true; - - if (c->since+(p->phase*8+4)*beat < c->cache.time) { - static const char* text[] = { - "boss_greedy_scientist_line0", - "boss_greedy_scientist_line1", - }; - if (p->phase < (int32_t) (sizeof(text)/sizeof(text[0]))) { - const char* v = loresource_text_get( - c->res->lang, text[(size_t) p->phase]); - loplayer_event_param_set_line(p->event.param, v, strlen(v)); - } else { - loplayer_event_param_set_line(p->event.param, "", 0); - } - ++p->phase; - } - } - - /* ---- state transition ---- */ - if (locharacter_greedy_scientist_reset_if_player_left_(c)) return; - - if (c->since + duration <= c->cache.time) { - if (event) { - p->event.param->cinescope = false; - p->event.param->hide_hud = false; - loplayer_event_param_set_line(p->event.param, "", 0); - } - locharacter_greedy_scientist_start_combo_state_(c); - return; - } -} -static void locharacter_greedy_scientist_start_standup_state_( - locharacter_base_t* c) { - assert(c != NULL); - - locharacter_greedy_scientist_param_t* p = (typeof(p)) c->data; - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_STANDUP; - - loeffect_recipient_reset(&c->recipient); - - if (!loeffect_stance_set_has( - &c->player->status.stances, LOEFFECT_STANCE_ID_PHILOSOPHER)) { - locharacter_event_holder_take_control(&p->event); - } - p->phase = 0; -} - -static void locharacter_greedy_scientist_update_combo_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float offset_y = locharacter_greedy_scientist_size_.y*1.5f; - - static const float beat = LOCHARACTER_GREEDY_SCIENTIST_BEAT; - static const uint64_t step_dur = beat; - static const uint64_t attack_dur = beat*3; - - const locharacter_greedy_scientist_param_t* p = (typeof(p)) c->data; - - c->cache.bullet_hittest = true; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND2; - if (c->since + step_dur > c->cache.time) { - const float t = (c->cache.time - c->since)*1.f/step_dur; - - vec2_t to = p->to; - to.y += offset_y; - - /* ---- position ---- */ - vec2_t dist; - vec2_sub(&dist, &to, &p->from); - vec2_muleq(&dist, t*t*(3-2*t)); - c->pos = p->from; - vec2_addeq(&c->pos, &dist); - - /* ---- motion ---- */ - instance->motion_time = 1-powf(2*t-1, 4); - } else { - float t = (c->cache.time - c->since - step_dur)*1.f/attack_dur; - t *= 3; - t -= (uint64_t) t; - t = t*t; - - /* ---- position ---- */ - c->pos.y -= c->ticker->delta_f*t/3 * offset_y; - - /* ---- motion ---- */ - instance->motion_time = t; - } - - /* ---- state transition ---- */ - if (locharacter_greedy_scientist_reset_if_player_left_(c)) return; - - if (c->since + step_dur + attack_dur <= c->cache.time) { - locharacter_greedy_scientist_start_cooldown_state_(c); - return; - } -} -static void locharacter_greedy_scientist_start_combo_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_GREEDY_SCIENTIST_BEAT; - static const uint64_t parry = 100; - - locharacter_greedy_scientist_param_t* p = (typeof(p)) c->data; - - if (c->last_knockback_time+parry > c->cache.time) { - locharacter_greedy_scientist_start_stunned_state_(c); - return; - } - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_COMBO; - - c->direction = c->cache.player_pos.x - c->pos.x; - c->direction = c->direction > 0? 1: -1; - - c->gravity = 0; - - p->from = c->pos; - p->to = c->cache.player_pos; - - const size_t delay_index = chaos_xorshift(c->cache.time)&1? 2: 3; - for (size_t i = 1; i < 4; ++i) { - const uint64_t delay = i >= delay_index? beat/2: 0; - loplayer_attack(c->player, &(loplayer_combat_attack_t) { - .attacker = c->super.super.id, - .start = c->ticker->time + (uint64_t) (beat*i) + delay, - .duration = beat/2, - .effect = loeffect_immediate_damage(c->recipient.status.attack), - }); - } -} - -static void locharacter_greedy_scientist_update_cooldown_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_GREEDY_SCIENTIST_BEAT; - static const uint64_t duration = beat*4; - - const uint64_t ti = c->cache.time - c->since; - - const locharacter_greedy_scientist_param_t* p = (typeof(p)) c->data; - - c->cache.bullet_hittest = true; - c->cache.gravity = true; - - /* ---- motion ---- */ - float t = ti*1.f/duration; - if (t > 1) t = 1; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND2; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = t; - - /* ---- state transition ---- */ - if (locharacter_greedy_scientist_reset_if_player_left_(c)) return; - - if (c->since + duration <= c->cache.time) { - locharacter_greedy_scientist_start_combo_state_(c); - return; - } -} -static void locharacter_greedy_scientist_start_cooldown_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_GREEDY_SCIENTIST_BEAT; - static const uint64_t bmelo = LOCHARACTER_GREEDY_SCIENTIST_MELODY_B_BEAT*beat; - - locharacter_greedy_scientist_param_t* p = (typeof(p)) c->data; - - if (locharacter_event_holder_has_control(&p->event)) { - static const uint64_t dur = LOCHARACTER_GREEDY_SCIENTIST_MUSIC_DURATION; - if (p->event.start_time+dur < c->cache.time) { - locharacter_greedy_scientist_finalize_event_(c); - return; - } - } else { - if (c->recipient.madness <= 0) { - locharacter_greedy_scientist_start_dead_state_(c); - return; - } - } - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_COOLDOWN; - - if (locharacter_event_holder_has_control(&p->event)) { - locharacter_greedy_scientist_trigger_chained_mines_(c); - if (c->cache.time - p->event.start_time > bmelo) { - locharacter_greedy_scientist_shoot_amnesia_bullet_(c); - } - } -} - -static void locharacter_greedy_scientist_update_stunned_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_GREEDY_SCIENTIST_BEAT; - static const uint64_t duration = beat*4; - - c->cache.gravity = true; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)*1.f/duration; - t *= 6; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - if (t < 1) { - t = 1-powf(1-t, 6); - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->motion_time = t; - } else { - t = (t-1)/5; - if (t > 1) t = 1; - t = t*t*(3-2*t); - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = t; - } - - /* ---- state transition ---- */ - if (c->since + duration <= c->cache.time) { - locharacter_greedy_scientist_start_cooldown_state_(c); - return; - } -} -static void locharacter_greedy_scientist_start_stunned_state_( - locharacter_base_t* c) { - assert(c != NULL); - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_STUNNED; - - loeffect_recipient_apply_effect( - &c->recipient, &loeffect_immediate_damage(1.f)); -} - -static void locharacter_greedy_scientist_update_dead_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const uint64_t anime_duration = 4000; - static const uint64_t duration = 30000; - - c->cache.gravity = true; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)*1.f/anime_duration; - if (t > 1) t = 1; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->motion_time = t*t; - instance->color.w *= 1-t; - - /* ---- state transition ---- */ - if (c->since+duration < c->cache.time) { - locharacter_greedy_scientist_start_wait_state_(c); - return; - } -} -static void locharacter_greedy_scientist_start_dead_state_( - locharacter_base_t* c) { - assert(c != NULL); - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_DEAD; - - loplayer_gain_faith(c->player, .8f); -} - -bool locharacter_greedy_scientist_update(locharacter_base_t* base) { - assert(base != NULL); - - static const vec2_t size = locharacter_greedy_scientist_size_; - static const float height = size.y * 1.4f; - static const float drawsz = MATH_MAX(size.x, size.y); - - locharacter_greedy_scientist_param_t* p = (typeof(p)) base->data; - - loeffect_recipient_update( - &base->recipient, &locharacter_greedy_scientist_base_status_); - - if (!locharacter_event_holder_update(&p->event)) { - locharacter_greedy_scientist_start_wait_state_(base); - } - - base->cache.instance = (loshader_character_drawer_instance_t) { - .character_id = LOSHADER_CHARACTER_ID_SCIENTIST, - .marker_offset = vec2(0, height - drawsz), - .pos = vec2(0, drawsz - height), - .size = vec2(drawsz, drawsz), - .color = vec4(.2f, 0, 0, 1), - }; - - switch (base->state) { - case LOCHARACTER_STATE_WAIT: - locharacter_greedy_scientist_update_wait_state_(base); - break; - case LOCHARACTER_STATE_STANDUP: - locharacter_greedy_scientist_update_standup_state_(base); - break; - case LOCHARACTER_STATE_COMBO: - locharacter_greedy_scientist_update_combo_state_(base); - break; - case LOCHARACTER_STATE_COOLDOWN: - locharacter_greedy_scientist_update_cooldown_state_(base); - break; - case LOCHARACTER_STATE_STUNNED: - locharacter_greedy_scientist_update_stunned_state_(base); - break; - case LOCHARACTER_STATE_DEAD: - locharacter_greedy_scientist_update_dead_state_(base); - break; - default: - locharacter_greedy_scientist_start_wait_state_(base); - } - locharacter_greedy_scientist_update_passive_action_(base); - - base->cache.height = height; - - base->cache.instance.marker = !!base->cache.bullet_hittest; - base->cache.instance.size.x *= base->direction; - return true; -} - -void locharacter_greedy_scientist_build( - locharacter_base_t* base, loentity_id_t ground) { - assert(base != NULL); - - base->type = LOCHARACTER_TYPE_GREEDY_SCIENTIST; - - base->ground = ground; - - base->pos = vec2(.7f, 0); - base->direction = 1; - - base->state = LOCHARACTER_STATE_WAIT; - base->since = base->cache.time; - - locharacter_greedy_scientist_param_t* p = (typeof(p)) base->data; - *p = (typeof(*p)) {0}; - - locharacter_event_holder_initialize( - &p->event, - &base->res->music.boss_greedy_scientist, - base, - LOCHARACTER_GREEDY_SCIENTIST_MUSIC_DURATION, - 0); -} - -void locharacter_greedy_scientist_tear_down(locharacter_base_t* base) { - assert(base != NULL); - - locharacter_greedy_scientist_param_t* p = (typeof(p)) base->data; - locharacter_event_holder_deinitialize(&p->event); -} - -void locharacter_greedy_scientist_pack_data( - const locharacter_base_t* base, msgpack_packer* packer) { - assert(base != NULL); - assert(packer != NULL); - - const locharacter_greedy_scientist_param_t* p = (typeof(p)) base->data; - - msgpack_pack_map(packer, LOCHARACTER_GREEDY_SCIENTIST_PARAM_TO_PACK_COUNT); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &p->var); \ - } while (0) - - LOCHARACTER_GREEDY_SCIENTIST_PARAM_TO_PACK_EACH_(pack_); - -# undef pack_ -} - -bool locharacter_greedy_scientist_unpack_data( - locharacter_base_t* base, const msgpack_object* obj) { - assert(base != NULL); - - locharacter_greedy_scientist_param_t* p = (typeof(p)) base->data; - - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &p->var)) { \ - return false; \ - } \ - } while (0) - - LOCHARACTER_GREEDY_SCIENTIST_PARAM_TO_PACK_EACH_(unpack_); - -# undef unpack_ - -# undef item_ - - locharacter_event_holder_initialize( - &p->event, - &base->res->music.boss_greedy_scientist, - base, - LOCHARACTER_GREEDY_SCIENTIST_MUSIC_DURATION, - p->event.start_time); - return true; -} diff --git a/core/locharacter/greedy_scientist.h b/core/locharacter/greedy_scientist.h deleted file mode 100644 index 85aaded..0000000 --- a/core/locharacter/greedy_scientist.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -#include - -#include "core/loentity/entity.h" - -#include "./base.h" - -bool -locharacter_greedy_scientist_update( - locharacter_base_t* base -); - -void -locharacter_greedy_scientist_build( - locharacter_base_t* base, - loentity_id_t ground -); - -void -locharacter_greedy_scientist_tear_down( - locharacter_base_t* base -); - -void -locharacter_greedy_scientist_pack_data( - const locharacter_base_t* base, - msgpack_packer* packer -); - -bool -locharacter_greedy_scientist_unpack_data( - locharacter_base_t* base, - const msgpack_object* obj -); diff --git a/core/locharacter/greedy_scientist.private.h b/core/locharacter/greedy_scientist.private.h deleted file mode 100644 index 527e65a..0000000 --- a/core/locharacter/greedy_scientist.private.h +++ /dev/null @@ -1,228 +0,0 @@ -static void locharacter_greedy_scientist_trigger_chained_mines_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_GREEDY_SCIENTIST_BEAT; - - locommon_position_t center = c->cache.ground->super.pos; - center.fract.y += .1f; - locommon_position_reduce(¢er); - - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_square_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = center, - .size = vec2(.07f, .07f), - .angle = 0, - .color = vec4(1, .9f, .9f, .8f), - .beat = beat, - .step = 2, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/2), - })); - loentity_store_add(c->entities, &b->super.super); - - for (int32_t i = -6; i <= 6; ++i) { - locommon_position_t pos = center; - pos.fract.x += i/6.f*.5f; - locommon_position_reduce(&pos); - - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_square_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = pos, - .size = vec2(.05f, .05f), - .angle = 0, - .color = vec4(1, 1, 1, .4f), - .silent = true, - .beat = beat*1.5f, - .step = 2, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/2), - })); - loentity_store_add(c->entities, &b->super.super); - } -} - -static void locharacter_greedy_scientist_shoot_amnesia_bullet_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_GREEDY_SCIENTIST_BEAT; - - locommon_position_t pos = c->super.super.pos; - pos.fract.y += locharacter_greedy_scientist_size_.y*1.5f; - locommon_position_reduce(&pos); - - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_linear_light_build(b, (&(lobullet_linear_param_t) { - .owner = c->super.super.id, - .pos = pos, - .size = vec2(.06f, .06f), - .velocity = vec2(0, .1f), - .color = vec4(.8f, .8f, .6f, .8f), - .acceleration = vec2(0, -2), - .duration = 1000, - .effect = loeffect_amnesia(c->ticker->time, beat*8), - })); - loentity_store_add(c->entities, &b->super.super); -} - -static void locharacter_greedy_scientist_update_passive_action_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_GREEDY_SCIENTIST_BEAT; - - const locharacter_greedy_scientist_param_t* p = (typeof(p)) c->data; - if (!locharacter_event_holder_has_control(&p->event)) return; - - const uint64_t dt = c->cache.time - c->last_update_time; - const uint64_t t = c->cache.time - p->event.start_time; - - const float beats = t/beat; - const float last_beats = t > dt? (t-dt)/beat: 0; - -# define name_pos_(name, x, y) \ - locommon_position_t name = c->cache.ground->super.pos; \ - vec2_addeq(&name.fract, &vec2(x, y)); \ - locommon_position_reduce(&name); - - name_pos_(top, 0, .8f); - name_pos_(lefttop, -.3f, .8f); - name_pos_(righttop, .3f, .8f); - name_pos_(center, 0, .4f); - name_pos_(left, -.3f, .2f); - name_pos_(right, .3f, .2f); - -# undef name_pos_ - -# define trigger_on_(x) (last_beats < (x) && beats >= (x)) - - /* ---- intro -> A melody ---- */ - for (size_t i = 0; i < 2; ++i) { - if (trigger_on_(16)) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_triangle_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = i? left: right, - .size = vec2(.1f*cos(MATH_PI/6), .1f), - .angle = -MATH_PI/2, - .color = vec4(1, 1, 1, .4f), - .silent = true, - .beat = beat*2, - .step = 1, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/4), - })); - loentity_store_add(c->entities, &b->super.super); - } - if (trigger_on_(16.5f)) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_triangle_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = i? left: right, - .size = vec2(.1f*cos(MATH_PI/6), .1f), - .angle = MATH_PI/2, - .color = vec4(1, 1, 1, .4f), - .silent = true, - .beat = beat*2, - .step = 1, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/4), - })); - loentity_store_add(c->entities, &b->super.super); - } - if (trigger_on_(17)) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_square_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = i? left: right, - .size = vec2(.12f, .12f), - .angle = MATH_PI/4, - .color = vec4(1, 1, 1, .4f), - .silent = true, - .beat = beat*2, - .step = 1, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/4), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - - for (size_t i = 0; i < 4; ++i) { - if (trigger_on_(18 + i*.5f)) { - locommon_position_t pos = center; - pos.fract.y -= .1f * i; - locommon_position_reduce(&pos); - - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_triangle_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = pos, - .size = vec2(.05f, .2f), - .angle = -MATH_PI/2, - .color = vec4(1, 1, 1, .4f), - .silent = true, - .beat = beat, - .step = 1, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/2), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - - /* ---- B melody ---- */ - for (size_t i = 52, cnt = 0; i < 84; i+=4, ++cnt) { - if (trigger_on_(i)) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_linear_triangle_build(b, (&(lobullet_linear_param_t) { - .owner = c->super.super.id, - .pos = cnt%2? lefttop: righttop, - .size = vec2(.1f, .3f), - .velocity = vec2(0, -1/(beat*4)*1000), - .color = vec4(1, 1, 1, .8f), - .duration = beat*4, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - - /* ---- C melody ---- */ - for (size_t i = 84, cnt = 0; i < 156; i+=8, ++cnt) { - if (trigger_on_(i)) { - for (int32_t x = -1-cnt%2; x <= 2; x+=2) { - locommon_position_t pos = top; - pos.fract.x += .18f*x; - locommon_position_reduce(&pos); - - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_linear_triangle_build(b, (&(lobullet_linear_param_t) { - .owner = c->super.super.id, - .pos = pos, - .size = vec2(.05f, .1f), - .velocity = vec2(0, -1/(beat*4)*1000), - .color = vec4(1, 1, 1, .8f), - .duration = beat*4, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - } - -# undef trigger_on_ -} diff --git a/core/locharacter/misc.c b/core/locharacter/misc.c deleted file mode 100644 index 7caeaed..0000000 --- a/core/locharacter/misc.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "./misc.h" - -#include -#include -#include -#include - -const char* locharacter_type_stringify(locharacter_type_t type) { -# define each_(NAME, name) do { \ - if (type == LOCHARACTER_TYPE_##NAME) return #name; \ - } while(0) - - LOCHARACTER_TYPE_EACH_(each_); - - assert(false); - return NULL; - -# undef each_ -} - -bool locharacter_type_unstringify( - locharacter_type_t* type, const char* v, size_t len) { - assert(type != NULL); - assert(v != NULL || len == 0); - -# define each_(NAME, name) do { \ - if (strncmp(v, #name, len) == 0 && #name[len] == 0) { \ - *type = LOCHARACTER_TYPE_##NAME; \ - return true; \ - } \ - } while(0) - - LOCHARACTER_TYPE_EACH_(each_); - return false; - -# undef each_ -} - -const char* locharacter_state_stringify(locharacter_state_t state) { -# define each_(NAME, name) do { \ - if (state == LOCHARACTER_STATE_##NAME) return #name; \ - } while(0) - - LOCHARACTER_STATE_EACH_(each_); - - assert(false); - return NULL; - -# undef each_ -} - -bool locharacter_state_unstringify( - locharacter_state_t* state, const char* v, size_t len) { - assert(state != NULL); - assert(v != NULL || len == 0); - -# define each_(NAME, name) do { \ - if (strncmp(v, #name, len) == 0 && #name[len] == 0) { \ - *state = LOCHARACTER_STATE_##NAME; \ - return true; \ - } \ - } while(0) - - LOCHARACTER_STATE_EACH_(each_); - return false; - -# undef each_ -} diff --git a/core/locharacter/misc.h b/core/locharacter/misc.h deleted file mode 100644 index 7668492..0000000 --- a/core/locharacter/misc.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include -#include - -/* dont forget to update EACH macro */ -typedef enum { - LOCHARACTER_TYPE_ENCEPHALON, - LOCHARACTER_TYPE_CAVIA, - LOCHARACTER_TYPE_SCIENTIST, - LOCHARACTER_TYPE_WARDER, - LOCHARACTER_TYPE_THEISTS_CHILD, - LOCHARACTER_TYPE_BIG_WARDER, - LOCHARACTER_TYPE_GREEDY_SCIENTIST, -} locharacter_type_t; - -#define LOCHARACTER_TYPE_EACH_(PROC) do { \ - PROC(ENCEPHALON, encephalon); \ - PROC(CAVIA, cavia); \ - PROC(SCIENTIST, scientist); \ - PROC(WARDER, warder); \ - PROC(THEISTS_CHILD, theists_child); \ - PROC(BIG_WARDER, big_warder); \ - PROC(GREEDY_SCIENTIST, greedy_scientist); \ -} while (0) - -/* dont forget to update EACH macro */ -typedef enum { - LOCHARACTER_STATE_WAIT, - LOCHARACTER_STATE_STANDUP, - LOCHARACTER_STATE_WALK, - LOCHARACTER_STATE_SHOOT, - LOCHARACTER_STATE_RUSH, - LOCHARACTER_STATE_THRUST, - LOCHARACTER_STATE_COMBO, - LOCHARACTER_STATE_COOLDOWN, - LOCHARACTER_STATE_STUNNED, - LOCHARACTER_STATE_DEAD, -} locharacter_state_t; - -#define LOCHARACTER_STATE_EACH_(PROC) do { \ - PROC(WAIT, wait); \ - PROC(STANDUP, standup); \ - PROC(WALK, walk); \ - PROC(SHOOT, shoot); \ - PROC(RUSH, rush); \ - PROC(THRUST, thrust); \ - PROC(COMBO, combo); \ - PROC(COOLDOWN, cooldown); \ - PROC(STUNNED, stunned); \ - PROC(DEAD, dead); \ -} while (0) - -const char* -locharacter_type_stringify( - locharacter_type_t type -); - -bool -locharacter_type_unstringify( - locharacter_type_t* type, - const char* v, - size_t len -); - -const char* -locharacter_state_stringify( - locharacter_state_t state -); - -bool -locharacter_state_unstringify( - locharacter_state_t* state, - const char* v, - size_t len -); diff --git a/core/locharacter/pool.c b/core/locharacter/pool.c deleted file mode 100644 index 4b38e7d..0000000 --- a/core/locharacter/pool.c +++ /dev/null @@ -1,122 +0,0 @@ -#include "./pool.h" - -#include -#include -#include -#include - -#include - -#include "util/math/vector.h" -#include "util/memory/memory.h" - -#include "core/lobullet/pool.h" -#include "core/locommon/counter.h" -#include "core/locommon/ticker.h" -#include "core/loentity/store.h" -#include "core/loplayer/player.h" -#include "core/loresource/set.h" -#include "core/loshader/character.h" - -#include "./base.h" - -struct locharacter_pool_t { - loresource_set_t* res; - loshader_character_drawer_t* drawer; - locommon_counter_t* idgen; - const locommon_ticker_t* ticker; - lobullet_pool_t* bullets; - loentity_store_t* entities; - loplayer_t* player; - - size_t length; - locharacter_base_t items[1]; -}; - -static size_t locharacter_pool_find_unused_item_index_( - const locharacter_pool_t* pool) { - assert(pool != NULL); - - for (size_t i = 0; i < pool->length; ++i) { - if (!pool->items[i].used) return i; - } - fprintf(stderr, "character pool overflow\n"); - abort(); -} - -locharacter_pool_t* locharacter_pool_new( - loresource_set_t* res, - loshader_character_drawer_t* drawer, - locommon_counter_t* idgen, - const locommon_ticker_t* ticker, - lobullet_pool_t* bullets, - loentity_store_t* entities, - loplayer_t* player, - size_t length) { - assert(res != NULL); - assert(drawer != NULL); - assert(idgen != NULL); - assert(ticker != NULL); - assert(bullets != NULL); - assert(entities != NULL); - assert(player != NULL); - assert(length > 0); - - locharacter_pool_t* pool = memory_new( - sizeof(*pool) + (length-1)*sizeof(pool->items[0])); - *pool = (typeof(*pool)) { - .res = res, - .drawer = drawer, - .idgen = idgen, - .ticker = ticker, - .bullets = bullets, - .entities = entities, - .player = player, - .length = length, - }; - - for (size_t i = 0; i < pool->length; ++i) { - locharacter_base_initialize( - &pool->items[i], - res, - drawer, - ticker, - bullets, - entities, - player); - } - return pool; -} - -void locharacter_pool_delete(locharacter_pool_t* pool) { - assert(pool != NULL); - - for (size_t i = 0; i < pool->length; ++i) { - locharacter_base_deinitialize(&pool->items[i]); - } - memory_delete(pool); -} - -locharacter_base_t* locharacter_pool_create(locharacter_pool_t* pool) { - assert(pool != NULL); - - const size_t i = locharacter_pool_find_unused_item_index_(pool); - - locharacter_base_reinitialize( - &pool->items[i], locommon_counter_count(pool->idgen)); - - pool->items[i].used = true; - return &pool->items[i]; -} - -locharacter_base_t* locharacter_pool_unpack_item( - locharacter_pool_t* pool, const msgpack_object* obj) { - assert(pool != NULL); - - const size_t i = locharacter_pool_find_unused_item_index_(pool); - - if (!locharacter_base_unpack(&pool->items[i], obj)) return NULL; - - pool->items[i].used = true; - return &pool->items[i]; -} diff --git a/core/locharacter/pool.h b/core/locharacter/pool.h deleted file mode 100644 index b573f47..0000000 --- a/core/locharacter/pool.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include - -#include - -#include "util/math/vector.h" - -#include "core/lobullet/pool.h" -#include "core/locommon/counter.h" -#include "core/locommon/ticker.h" -#include "core/loentity/store.h" -#include "core/loplayer/player.h" -#include "core/loresource/set.h" -#include "core/loshader/character.h" - -#include "./base.h" - -struct locharacter_pool_t; -typedef struct locharacter_pool_t locharacter_pool_t; - -locharacter_pool_t* /* OWNERSHIP */ -locharacter_pool_new( - loresource_set_t* res, - loshader_character_drawer_t* drawer, - locommon_counter_t* idgen, - const locommon_ticker_t* ticker, - lobullet_pool_t* bullets, - loentity_store_t* entities, - loplayer_t* player, - size_t length -); - -void -locharacter_pool_delete( - locharacter_pool_t* pool /* OWNERSHIP */ -); - -locharacter_base_t* -locharacter_pool_create( - locharacter_pool_t* pool -); - -locharacter_base_t* -locharacter_pool_unpack_item( - locharacter_pool_t* pool, - const msgpack_object* obj -); diff --git a/core/locharacter/scientist.c b/core/locharacter/scientist.c deleted file mode 100644 index 35aeda3..0000000 --- a/core/locharacter/scientist.c +++ /dev/null @@ -1,305 +0,0 @@ -#include "./scientist.h" - -#include -#include -#include - -#include "util/math/algorithm.h" -#include "util/math/vector.h" - -#include "core/lobullet/base.h" -#include "core/lobullet/bomb.h" -#include "core/loeffect/recipient.h" -#include "core/loentity/entity.h" -#include "core/loentity/store.h" -#include "core/loplayer/event.h" -#include "core/loplayer/player.h" -#include "core/loresource/sound.h" -#include "core/loshader/character.h" - -#include "./base.h" -#include "./misc.h" - -static const vec2_t locharacter_scientist_size_ = vec2(.02f, .05f); - -static const loeffect_recipient_status_t locharacter_scientist_base_status_ = { - .attack = .2f, - .defence = .1f, -}; - -static void locharacter_scientist_trigger_bomb_(locharacter_base_t* c) { - assert(c != NULL); - - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_square_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = c->player->entity.super.super.pos, - .size = vec2(.15f, .15f), - .angle = 0, - .color = vec4(1, 1, 1, .6f), - .beat = 500, - .step = 2, - .knockback = .1f, - .effect = loeffect_immediate_damage(c->recipient.status.attack), - })); - loentity_store_add(c->entities, &b->super.super); - - loresource_sound_play(c->res->sound, "enemy_trigger"); -} - -static void -locharacter_scientist_start_wait_state_( - locharacter_base_t* base -); -static void -locharacter_scientist_start_shoot_state_( - locharacter_base_t* base -); -static void -locharacter_scientist_start_combo_state_( - locharacter_base_t* base -); -static void -locharacter_scientist_start_dead_state_( - locharacter_base_t* base -); - -static void locharacter_scientist_update_wait_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t duration = 1000; - static const uint64_t period = 1000; - - const uint64_t elapsed = base->ticker->time - base->since; - - /* ---- motion ---- */ - float t = elapsed%period*1.f/period; - t = t*2 - 1; - t = MATH_ABS(t); - t = t*t*(3-2*t); - - loshader_character_drawer_instance_t* instance = &base->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND2; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = t; - - /* ---- state transition ---- */ - if (elapsed >= duration) { - if (base->recipient.madness <= 0) { - locharacter_scientist_start_dead_state_(base); - return; - } - - if (loplayer_event_get_param(base->player->event) == NULL) { - vec2_t disp; - vec2_sub(&disp, &base->cache.player_pos, &base->pos); - disp.x *= base->cache.ground->size.x; - - const float pdist = vec2_pow_length(&disp); - if (MATH_ABS(disp.y) < locharacter_scientist_size_.y && - pdist < .2f*.2f) { - static const float r = locharacter_scientist_size_.x*3; - if (pdist < r*r) { - locharacter_scientist_start_combo_state_(base); - } else if (disp.x*base->direction > 0) { - locharacter_scientist_start_shoot_state_(base); - } - } - return; - } - } -} -static void locharacter_scientist_start_wait_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_WAIT; -} - -static void locharacter_scientist_update_shoot_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t duration = 500; - - const uint64_t elapsed = base->ticker->time - base->since; - - /* ---- motion ---- */ - float t = elapsed*1.f / duration; - if (t > 1) t = 1; - t = t*t; - - loshader_character_drawer_instance_t* instance = &base->cache.instance; - if (t < .5f) { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->motion_time = t*2; - } else { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = (t-.5f)*2; - } - - /* ---- state transition ---- */ - if (elapsed >= duration) { - locharacter_scientist_trigger_bomb_(base); - locharacter_scientist_start_wait_state_(base); - return; - } -} -static void locharacter_scientist_start_shoot_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_SHOOT; -} - -static void locharacter_scientist_update_combo_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t duration = 1000; - - const uint64_t elapsed = base->ticker->time - base->since; - - base->cache.gravity = false; - - /* ---- motion ---- */ - float t = elapsed*1.f/duration; - if (t > 1) t = 1; - t = t*t; - - loshader_character_drawer_instance_t* instance = &base->cache.instance; - if (t < .5f) { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->motion_time = t*2; - } else { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = (t-.5f)*2; - } - - /* ---- state transition ---- */ - if (elapsed >= duration) { - locharacter_scientist_start_wait_state_(base); - return; - } -} -static void locharacter_scientist_start_combo_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_COMBO; - - const float diff = base->cache.player_pos.x - base->pos.x; - base->direction = MATH_SIGN(diff); - - const loplayer_combat_attack_t attack = { - .attacker = base->super.super.id, - .start = base->ticker->time + 600, - .duration = 400, - .knockback = vec2(base->direction*.1f, 0), - .effect = loeffect_immediate_damage(base->recipient.status.attack), - }; - loplayer_attack(base->player, &attack); -} - -static void locharacter_scientist_update_dead_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t anime_duration = 500; - static const uint64_t duration = 30000; - - const uint64_t elapsed = base->ticker->time - base->since; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &base->cache.instance; - if (elapsed > duration - anime_duration) { /* wake up */ - float t = 1-(duration - elapsed)*1.f/anime_duration; - if (t < 0) t = 0; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = 1-powf(1-t, 2); - } else { /* down */ - float t = elapsed*1.f/anime_duration; - if (t > 1) t = 1; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->motion_time = powf(t, 2.); - } - - /* ---- state transition ---- */ - if (elapsed >= duration) { - loeffect_recipient_reset(&base->recipient); - locharacter_scientist_start_wait_state_(base); - return; - } -} -static void locharacter_scientist_start_dead_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_DEAD; - - loplayer_gain_faith(base->player, .3f); -} - -bool locharacter_scientist_update(locharacter_base_t* base) { - assert(base != NULL); - - static const vec2_t size = locharacter_scientist_size_; - static const vec4_t color = vec4(.1f, .1f, .1f, 1); - static const float height = size.y*1.4f; - static const float drawsz = MATH_MAX(size.x, size.y); - - loeffect_recipient_update(&base->recipient, &locharacter_scientist_base_status_); - - base->cache.instance = (loshader_character_drawer_instance_t) { - .character_id = LOSHADER_CHARACTER_ID_SCIENTIST, - .marker_offset = vec2(0, height - drawsz), - .pos = vec2(0, drawsz - height), - .size = vec2(drawsz, drawsz), - .color = color, - }; - - base->cache.gravity = true; - - switch (base->state) { - case LOCHARACTER_STATE_WAIT: - locharacter_scientist_update_wait_state_(base); - break; - case LOCHARACTER_STATE_SHOOT: - locharacter_scientist_update_shoot_state_(base); - break; - case LOCHARACTER_STATE_COMBO: - locharacter_scientist_update_combo_state_(base); - break; - case LOCHARACTER_STATE_DEAD: - locharacter_scientist_update_dead_state_(base); - break; - default: - locharacter_scientist_start_wait_state_(base); - } - - base->cache.bullet_hittest = base->state != LOCHARACTER_STATE_DEAD; - - base->cache.height = height; - - base->cache.instance.size.x *= base->direction; - base->cache.instance.marker = !!base->cache.bullet_hittest; - return true; -} - -void locharacter_scientist_build( - locharacter_base_t* base, const locharacter_scientist_param_t* param) { - assert(base != NULL); - assert(param != NULL); - - base->type = LOCHARACTER_TYPE_SCIENTIST; - - base->ground = param->ground; - - base->pos = vec2(param->pos, 0); - base->direction = param->direction == 1? 1: -1; - - locharacter_scientist_start_wait_state_(base); -} diff --git a/core/locharacter/scientist.h b/core/locharacter/scientist.h deleted file mode 100644 index 5ae2c40..0000000 --- a/core/locharacter/scientist.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include - -#include - -#include "core/loentity/entity.h" - -#include "./base.h" - -typedef struct { - loentity_id_t ground; - float pos; - float direction; -} locharacter_scientist_param_t; - -bool -locharacter_scientist_update( - locharacter_base_t* base -); - -void -locharacter_scientist_build( - locharacter_base_t* base, - const locharacter_scientist_param_t* param -); - -#define locharacter_scientist_tear_down(base) - -#define locharacter_scientist_pack_data(base, packer) \ - msgpack_pack_nil(packer) - -#define locharacter_scientist_unpack_data(base, obj) \ - (obj != NULL) diff --git a/core/locharacter/theists_child.c b/core/locharacter/theists_child.c deleted file mode 100644 index c233027..0000000 --- a/core/locharacter/theists_child.c +++ /dev/null @@ -1,763 +0,0 @@ -#include "./theists_child.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include "util/chaos/xorshift.h" -#include "util/math/algorithm.h" -#include "util/math/constant.h" -#include "util/math/rational.h" -#include "util/math/vector.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" - -#include "core/lobullet/base.h" -#include "core/lobullet/bomb.h" -#include "core/lobullet/linear.h" -#include "core/lobullet/pool.h" -#include "core/locommon/msgpack.h" -#include "core/locommon/ticker.h" -#include "core/loeffect/recipient.h" -#include "core/loeffect/stance.h" -#include "core/loentity/bullet.h" -#include "core/loentity/store.h" -#include "core/loplayer/event.h" -#include "core/loplayer/player.h" -#include "core/loresource/music.h" -#include "core/loresource/set.h" -#include "core/loresource/text.h" -#include "core/loshader/character.h" - -#include "./base.h" -#include "./misc.h" -#include "./util.h" - -typedef struct { - locharacter_event_holder_t event; - - uint64_t phase; - vec2_t from; - vec2_t to; -} locharacter_theists_child_param_t; - -#define LOCHARACTER_THEISTS_CHILD_PARAM_TO_PACK_EACH_(PROC) do { \ - PROC("event-start-time", event.start_time); \ - PROC("phase", phase); \ - PROC("from", from); \ - PROC("to", to); \ -} while (0) -#define LOCHARACTER_THEISTS_CHILD_PARAM_TO_PACK_COUNT 4 - -static const vec2_t locharacter_theists_child_size_ = vec2(.02f, .06f); - -static const loeffect_recipient_status_t -locharacter_theists_child_base_status_ = { - .attack = .1f, - .defence = .9f, - .speed = .1f, - .jump = .2f, -}; - -#define LOCHARACTER_THEISTS_CHILD_BEAT (60000/140.f) /* 140 BPM */ -#define LOCHARACTER_THEISTS_CHILD_MUSIC_DURATION \ - ((uint64_t) LOCHARACTER_THEISTS_CHILD_BEAT*236) - -#define LOCHARACTER_THEISTS_CHILD_MELODY_B_START_BEAT 128 -#define LOCHARACTER_THEISTS_CHILD_MELODY_B_END_BEAT 192 - -#include "./theists_child.private.h" - -static void -locharacter_theists_child_start_wait_state_( - locharacter_base_t* c -); -static void -locharacter_theists_child_start_standup_state_( - locharacter_base_t* c -); -static void -locharacter_theists_child_start_rush_state_( - locharacter_base_t* c -); -static void -locharacter_theists_child_start_combo_state_( - locharacter_base_t* c -); -static void -locharacter_theists_child_start_cooldown_state_( - locharacter_base_t* c -); -static void -locharacter_theists_child_start_stunned_state_( - locharacter_base_t* c -); -static void -locharacter_theists_child_start_dead_state_( - locharacter_base_t* c -); - -static void locharacter_theists_child_finalize_event_(locharacter_base_t* c) { - assert(c != NULL); - /* This function must start next state. */ - - locharacter_theists_child_param_t* p = (typeof(p)) c->data; - assert(p != NULL); - - locharacter_event_holder_release_control(&p->event); - - if (c->recipient.madness > 0) { - loentity_character_apply_effect( - &c->player->entity.super, &loeffect_curse_trigger()); - locharacter_theists_child_start_wait_state_(c); - } else { - loplayer_gain_stance(c->player, LOEFFECT_STANCE_ID_REVOLUTIONER); - locharacter_theists_child_start_dead_state_(c); - } -} - -static bool locharacter_theists_child_reset_if_player_left_( - locharacter_base_t* c) { - assert(c != NULL); - - locharacter_theists_child_param_t* p = (typeof(p)) c->data; - - if (MATH_ABS(c->cache.player_pos.x) < 1 && - 0 < c->cache.player_pos.y && c->cache.player_pos.y < 1) { - return false; - } - locharacter_event_holder_release_control(&p->event); - locharacter_theists_child_start_wait_state_(c); - return true; -} - -static void locharacter_theists_child_fire_bullets_(locharacter_base_t* c) { - assert(c != NULL); - - static const float len = .3f; - static const float accel = .6f; - static const uint64_t dur = 1000; - - for (size_t i = 0; i < 30; ++i) { - const float t = MATH_PI/15*i; - - const vec2_t v = vec2(cos(t), sin(t)); - - locommon_position_t pos = c->super.super.pos; - pos.fract.x += v.x*len; - pos.fract.y += v.y*len; - locommon_position_reduce(&pos); - - lobullet_base_t* bullet = lobullet_pool_create(c->bullets); - lobullet_linear_light_build(bullet, (&(lobullet_linear_param_t) { - .owner = c->super.super.id, - .pos = pos, - .size = vec2(.015f, .015f), - .acceleration = vec2(-v.x*accel, -v.y*accel), - .color = vec4(1, 1, 1, .8f), - .duration = dur, - .knockback = .1f, - .effect = loeffect_immediate_damage(c->recipient.status.attack), - })); - loentity_store_add(c->entities, &bullet->super.super); - } -} - -static void locharacter_theists_child_update_wait_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float standup_range = .5f; - static const int32_t sit_duration = 4000; - - c->cache.gravity = true; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)*1.f/sit_duration; - if (t > 1) t = 1; - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->motion_time = t; - - /* ---- state transition ---- */ - if (c->since+sit_duration <= c->cache.time) { - if (MATH_ABS(c->cache.player_pos.x) < 1 && - 0 < c->cache.player_pos.y && c->cache.player_pos.y < 1) { - vec2_t diff; - vec2_sub(&diff, &c->cache.player_pos, &c->pos); - if (vec2_pow_length(&diff) < standup_range*standup_range) { - locharacter_theists_child_start_standup_state_(c); - return; - } - } - } -} -static void locharacter_theists_child_start_wait_state_(locharacter_base_t* c) { - assert(c != NULL); - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_WAIT; -} - -static void locharacter_theists_child_update_standup_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_THEISTS_CHILD_BEAT; - static const uint64_t line_duration = beat*10; - - locharacter_theists_child_param_t* p = (typeof(p)) c->data; - - const bool event = locharacter_event_holder_has_control(&p->event); - const uint64_t standup_duration = event? beat*64: 1000; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)*1.0f/standup_duration; - if (t > 1) t = 1; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - if (t < .5f) { - t *= 2; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->motion_time = t*t*(3-2*t); - } else { - t = (t-.5f)*2; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = t*t*(3-2*t); - } - - /* ---- event ---- */ - if (event) { - p->event.param->cinescope = true; - p->event.param->hide_hud = true; - - if (c->since+(p->phase+2)*line_duration < c->cache.time) { - static const char* text[] = { - "boss_theists_child_line0", - "boss_theists_child_line1", - "boss_theists_child_line2", - }; - if (p->phase < sizeof(text)/sizeof(text[0])) { - const char* v = loresource_text_get( - c->res->lang, text[(size_t) p->phase]); - loplayer_event_param_set_line(p->event.param, v, strlen(v)); - } else { - loplayer_event_param_set_line(p->event.param, "", 0); - } - ++p->phase; - } - } - - /* ---- state transition ---- */ - if (locharacter_theists_child_reset_if_player_left_(c)) return; - - if (c->since+standup_duration < c->cache.time) { - if (event) { - p->event.param->hide_hud = false; - p->event.param->cinescope = false; - loplayer_event_param_set_line(p->event.param, "", 0); - } - locharacter_theists_child_start_rush_state_(c); - return; - } -} -static void locharacter_theists_child_start_standup_state_( - locharacter_base_t* c) { - assert(c != NULL); - - locharacter_theists_child_param_t* p = (typeof(p)) c->data; - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_STANDUP; - - p->phase = 0; - loeffect_recipient_reset(&c->recipient); - - if (!loeffect_stance_set_has( - &c->player->status.stances, LOEFFECT_STANCE_ID_REVOLUTIONER)) { - locharacter_event_holder_take_control(&p->event); - } -} - -static void locharacter_theists_child_update_rush_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_THEISTS_CHILD_BEAT; - - static const uint64_t premotion_duration = beat*2; - static const uint64_t whole_duration = beat*4; - - const locharacter_theists_child_param_t* p = (typeof(p)) c->data; - - const uint64_t elapsed = c->cache.time - c->since; - - /* ---- motion ---- */ - float t = elapsed*1.f/premotion_duration; - if (t > 1) t = 1; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - if (t < .1f) { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_WALK; - instance->motion_time = 1-powf(1-t*10, 2); - } else if (t < .5f) { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_WALK; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->motion_time = 1-powf(1-(t-.1f)/4*10, 2); - } else { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->motion_time = powf((t-.5f)*2, 4); - } - - /* ---- position ---- */ - vec2_sub(&c->pos, &p->to, &p->from); - c->direction = MATH_SIGN(c->pos.x); - vec2_muleq(&c->pos, powf(t, 2)); - c->pos.y += (1-MATH_ABS(t*2-1))*c->recipient.status.jump*.1f; - vec2_addeq(&c->pos, &p->from); - - /* ---- state transition ---- */ - if (locharacter_theists_child_reset_if_player_left_(c)) return; - - if (c->since+whole_duration < c->cache.time) { - locharacter_theists_child_start_cooldown_state_(c); - return; - } -} -static void locharacter_theists_child_start_rush_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_THEISTS_CHILD_BEAT; - - static const uint64_t parry = 300; - - locharacter_theists_child_param_t* p = (typeof(p)) c->data; - - if (c->last_knockback_time + parry > c->cache.time) { - locharacter_theists_child_start_stunned_state_(c); - return; - } - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_RUSH; - - const vec2_t* player = &c->cache.player_pos; - - const float diffx = player->x - c->pos.x; - p->from = c->pos; - p->to = vec2( - player->x - MATH_SIGN(diffx)*locharacter_theists_child_size_.x*2, - player->y - .02f); - - const loplayer_combat_attack_t attack = { - .attacker = c->super.super.id, - .start = c->ticker->time + (uint64_t) beat, - .duration = beat*3, - .knockback = vec2(MATH_SIGN(player->x)*.2f, 0), - .effect = loeffect_immediate_damage(c->recipient.status.attack*2), - }; - loplayer_attack(c->player, &attack); -} - -static void locharacter_theists_child_update_combo_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_THEISTS_CHILD_BEAT; - static const uint64_t premotion_duration = beat; - static const uint64_t attack_duration = beat; - static const uint64_t whole_duration = beat*4; - - const locharacter_theists_child_param_t* p = (typeof(p)) c->data; - - const uint64_t elapsed = c->cache.time - c->since; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &c->cache.instance; - if (elapsed < premotion_duration) { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->motion_time = elapsed*1.f / premotion_duration; - } else { - const uint64_t attack_elapsed = elapsed - premotion_duration; - - float t = 1; - if (attack_elapsed < attack_duration*p->phase) { - t = attack_elapsed%attack_duration*1.f / attack_duration; - } - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->motion_time = 1-powf(1-t, 4); - } - - /* ---- position ---- */ - if (elapsed < premotion_duration) { - const float t = elapsed*1.f/premotion_duration; - vec2_sub(&c->pos, &p->to, &p->from); - vec2_muleq(&c->pos, t*t); - vec2_addeq(&c->pos, &p->from); - } - - /* ---- state transition ---- */ - if (locharacter_theists_child_reset_if_player_left_(c)) return; - - if (elapsed >= whole_duration) { - locharacter_theists_child_start_cooldown_state_(c); - return; - } -} -static void locharacter_theists_child_start_combo_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_THEISTS_CHILD_BEAT; - static const uint64_t parry = 200; - - locharacter_theists_child_param_t* p = (typeof(p)) c->data; - - if (c->last_knockback_time + parry > c->cache.time) { - locharacter_theists_child_start_stunned_state_(c); - return; - } - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_COMBO; - - const float diffx = c->cache.player_pos.x - c->pos.x; - c->direction = MATH_SIGN(diffx); - - p->phase = 2 + chaos_xorshift(c->since)%2; - p->from = c->pos; - p->to = c->cache.player_pos; - p->to.x -= c->direction*locharacter_theists_child_size_.x*2; - p->to.y -= .02f; - - const loplayer_combat_attack_t attack1 = { - .attacker = c->super.super.id, - .start = c->ticker->time + (uint64_t) beat, - .duration = beat/2, - .knockback = vec2(c->direction*.1f, 0), - .effect = loeffect_immediate_damage(c->recipient.status.attack*.8f), - }; - loplayer_attack(c->player, &attack1); - - const loplayer_combat_attack_t attack2 = { - .attacker = c->super.super.id, - .start = c->ticker->time + (uint64_t) (beat*2), - .duration = p->phase == 2? beat*1.5: beat/2, - .knockback = vec2(c->direction*.1f, 0), - .effect = loeffect_immediate_damage(c->recipient.status.attack*1.1f), - }; - loplayer_attack(c->player, &attack2); - - if (p->phase >= 3) { - const loplayer_combat_attack_t attack3 = { - .attacker = c->super.super.id, - .start = c->ticker->time + (uint64_t) (beat*3), - .duration = beat/2, - .knockback = vec2(c->direction*.1f, 0), - .effect = loeffect_immediate_damage(c->recipient.status.attack*1.3f), - }; - loplayer_attack(c->player, &attack3); - } -} - -static void locharacter_theists_child_update_cooldown_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_THEISTS_CHILD_BEAT; - - static const uint64_t duration = beat*4; - - const locharacter_theists_child_param_t* p = (typeof(p)) c->data; - - c->cache.bullet_hittest = true; - c->cache.gravity = true; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)*1.0f/duration; - if (t > 1) t = 1; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = t; - - /* ---- state transition ---- */ - if (locharacter_theists_child_reset_if_player_left_(c)) return; - - if (c->since+duration < c->cache.time) { - if (locharacter_event_holder_has_control(&p->event)) { - static const uint64_t dur = LOCHARACTER_THEISTS_CHILD_MUSIC_DURATION; - if (p->event.start_time+dur < c->cache.time) { - locharacter_theists_child_finalize_event_(c); - return; - } - } else { - if (c->recipient.madness <= 0) { - locharacter_theists_child_start_dead_state_(c); - return; - } - } - - vec2_t diff; - vec2_sub(&diff, &c->cache.player_pos, &c->pos); - if (vec2_pow_length(&diff) < .5f*.5f) { - locharacter_theists_child_start_combo_state_(c); - return; - } - - locharacter_theists_child_start_rush_state_(c); - return; - } -} -static void locharacter_theists_child_start_cooldown_state_( - locharacter_base_t* c) { - assert(c != NULL); - - const locharacter_theists_child_param_t* p = (typeof(p)) c->data; - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_COOLDOWN; - - bool skip_firing = false; - if (locharacter_event_holder_has_control(&p->event)) { - const float beat = - (c->cache.time - p->event.start_time)/LOCHARACTER_THEISTS_CHILD_BEAT; - skip_firing = - LOCHARACTER_THEISTS_CHILD_MELODY_B_START_BEAT <= beat && - beat < LOCHARACTER_THEISTS_CHILD_MELODY_B_END_BEAT; - } - if (!skip_firing) locharacter_theists_child_fire_bullets_(c); -} - -static void locharacter_theists_child_update_stunned_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_THEISTS_CHILD_BEAT; - static const uint64_t duration = beat*4; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)*1.f/duration; - t *= 6; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - if (t < 1) { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->motion_time = 1-powf(1-t, 6); - } else { - t = (t-1)/5; - if (t > 1) t = 1; - t = t*t*(3-2*t); - - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_SIT; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->motion_time = t; - } - - /* ---- state transition ---- */ - if (c->since+duration < c->cache.time) { - locharacter_theists_child_start_cooldown_state_(c); - return; - } -} -static void locharacter_theists_child_start_stunned_state_( - locharacter_base_t* c) { - assert(c != NULL); - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_STUNNED; - - loeffect_recipient_apply_effect( - &c->recipient, &loeffect_immediate_damage(1.f)); -} - -static void locharacter_theists_child_update_dead_state_( - locharacter_base_t* c) { - assert(c != NULL); - - static const uint64_t anime_duration = 4000; - static const uint64_t duration = 30000; - - c->cache.gravity = true; - - /* ---- motion ---- */ - float t = (c->cache.time - c->since)*1.f/anime_duration; - if (t > 1) t = 1; - - loshader_character_drawer_instance_t* instance = &c->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->motion_time = t*t; - instance->color.w = 1-t; - - /* ---- state transition ---- */ - if (c->since+duration < c->cache.time) { - c->pos = vec2(0, 0); - locharacter_theists_child_start_wait_state_(c); - return; - } -} -static void locharacter_theists_child_start_dead_state_( - locharacter_base_t* c) { - assert(c != NULL); - - c->since = c->cache.time; - c->state = LOCHARACTER_STATE_DEAD; - - loplayer_gain_faith(c->player, .5f); -} - -bool locharacter_theists_child_update(locharacter_base_t* base) { - assert(base != NULL); - - static const vec2_t size = locharacter_theists_child_size_; - static const vec4_t color = vec4(.05f, 0, 0, 1); - static const float height = size.y * 1.4f; - static const float drawsz = MATH_MAX(size.x, size.y); - - locharacter_theists_child_param_t* p = (typeof(p)) base->data; - - loeffect_recipient_update( - &base->recipient, &locharacter_theists_child_base_status_); - - if (!locharacter_event_holder_update(&p->event)) { - locharacter_theists_child_start_wait_state_(base); - } - - base->cache.instance = (loshader_character_drawer_instance_t) { - .character_id = LOSHADER_CHARACTER_ID_CAVIA, - .marker_offset = vec2(0, height - drawsz), - .pos = vec2(0, drawsz - height), - .size = vec2(drawsz, drawsz), - .color = color, - }; - - switch (base->state) { - case LOCHARACTER_STATE_WAIT: - locharacter_theists_child_update_wait_state_(base); - break; - case LOCHARACTER_STATE_STANDUP: - locharacter_theists_child_update_standup_state_(base); - break; - case LOCHARACTER_STATE_RUSH: - locharacter_theists_child_update_rush_state_(base); - break; - case LOCHARACTER_STATE_COMBO: - locharacter_theists_child_update_combo_state_(base); - break; - case LOCHARACTER_STATE_COOLDOWN: - locharacter_theists_child_update_cooldown_state_(base); - break; - case LOCHARACTER_STATE_STUNNED: - locharacter_theists_child_update_stunned_state_(base); - break; - case LOCHARACTER_STATE_DEAD: - locharacter_theists_child_update_dead_state_(base); - break; - default: - locharacter_theists_child_start_wait_state_(base); - } - locharacter_theists_child_update_passive_action_(base); - - base->cache.height = height; - - base->cache.instance.marker = !!base->cache.bullet_hittest; - base->cache.instance.size.x *= base->direction; - return true; -} - -void locharacter_theists_child_build(locharacter_base_t* base, loentity_id_t ground) { - assert(base != NULL); - - base->type = LOCHARACTER_TYPE_THEISTS_CHILD; - - base->ground = ground; - - base->pos = vec2(0, 0); - base->direction = 1; - - base->state = LOCHARACTER_STATE_WAIT; - base->since = base->cache.time; - - locharacter_theists_child_param_t* p = (typeof(p)) base->data; - *p = (typeof(*p)) {0}; - - locharacter_event_holder_initialize( - &p->event, - &base->res->music.boss_theists_child, - base, - LOCHARACTER_THEISTS_CHILD_MUSIC_DURATION, - 0); -} - -void locharacter_theists_child_tear_down(locharacter_base_t* base) { - assert(base != NULL); - - locharacter_theists_child_param_t* p = (typeof(p)) base->data; - locharacter_event_holder_deinitialize(&p->event); -} - -void locharacter_theists_child_pack_data( - const locharacter_base_t* base, msgpack_packer* packer) { - assert(base != NULL); - assert(packer != NULL); - - const locharacter_theists_child_param_t* p = (typeof(p)) base->data; - - msgpack_pack_map(packer, LOCHARACTER_THEISTS_CHILD_PARAM_TO_PACK_COUNT); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &p->var); \ - } while (0) - - LOCHARACTER_THEISTS_CHILD_PARAM_TO_PACK_EACH_(pack_); - -# undef pack_ -} - -bool locharacter_theists_child_unpack_data( - locharacter_base_t* base, const msgpack_object* obj) { - assert(base != NULL); - - locharacter_theists_child_param_t* p = (typeof(p)) base->data; - - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &p->var)) { \ - return false; \ - } \ - } while (0) - - LOCHARACTER_THEISTS_CHILD_PARAM_TO_PACK_EACH_(unpack_); - -# undef unpack_ - -# undef item_ - - locharacter_event_holder_initialize( - &p->event, - &base->res->music.boss_theists_child, - base, - LOCHARACTER_THEISTS_CHILD_MUSIC_DURATION, - p->event.start_time); - return true; -} diff --git a/core/locharacter/theists_child.h b/core/locharacter/theists_child.h deleted file mode 100644 index 3b796b2..0000000 --- a/core/locharacter/theists_child.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -#include - -#include "core/loentity/entity.h" - -#include "./base.h" - -bool -locharacter_theists_child_update( - locharacter_base_t* base -); - -void -locharacter_theists_child_build( - locharacter_base_t* base, - loentity_id_t ground -); - -void -locharacter_theists_child_tear_down( - locharacter_base_t* base -); - -void -locharacter_theists_child_pack_data( - const locharacter_base_t* base, - msgpack_packer* packer -); - -bool -locharacter_theists_child_unpack_data( - locharacter_base_t* base, - const msgpack_object* obj -); diff --git a/core/locharacter/theists_child.private.h b/core/locharacter/theists_child.private.h deleted file mode 100644 index 5ca34c2..0000000 --- a/core/locharacter/theists_child.private.h +++ /dev/null @@ -1,150 +0,0 @@ -static void locharacter_theists_child_update_passive_action_( - locharacter_base_t* c) { - assert(c != NULL); - - static const float beat = LOCHARACTER_THEISTS_CHILD_BEAT; - - const locharacter_theists_child_param_t* p = (typeof(p)) c->data; - if (!locharacter_event_holder_has_control(&p->event)) return; - - const uint64_t dt = c->cache.time - c->last_update_time; - const uint64_t t = c->cache.time - p->event.start_time; - - const float beats = t/beat; - const float last_beats = t > dt? (t-dt)/beat: 0; - -# define name_pos_(name, x, y) \ - locommon_position_t name = c->cache.ground->super.pos; \ - vec2_addeq(&name.fract, &vec2(x, y)); \ - locommon_position_reduce(&name); - - name_pos_(top, 0, .8f); - name_pos_(lefttop, -.25f, .8f); - name_pos_(righttop, .25f, .8f); - name_pos_(center, 0, .25f); - name_pos_(left, -.3f, .2f); - name_pos_(right, .3f, .2f); - -# undef name_pos_ - -# define trigger_on_(x) (last_beats < (x) && beats >= (x)) - - /* ---- intro -> A melody ---- */ - if (trigger_on_(56)) { - for (size_t i = 0; i < 2; ++i) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_triangle_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = i? left: right, - .size = vec2(.05f, .15f), - .angle = -MATH_PI/2, - .color = vec4(1, 1, 1, .8f), - .silent = true, - .beat = beat, - .step = 8, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/2), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - if (trigger_on_(64)) { - for (size_t i = 0; i < 2; ++i) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_linear_triangle_build(b, (&(lobullet_linear_param_t) { - .owner = c->super.super.id, - .pos = i? lefttop: righttop, - .size = vec2(.05f, .15f), - .velocity = vec2(0, -1.4f/(beat/1000*2)), - .acceleration = vec2(0, 1/(beat/1000*2)), - .color = vec4(1, 1, 1, .8f), - .duration = beat*2, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - - /* ---- B melody ---- */ - for (size_t i = 128, cnt = 0; i < 192; i+=4, ++cnt) { - if (trigger_on_(i)) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_square_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = cnt%2 == 0? left: right, - .size = vec2(.13f, .13f), - .angle = MATH_PI/4, - .color = vec4(1, 1, 1, .8f), - .silent = true, - .beat = LOCHARACTER_THEISTS_CHILD_BEAT, - .step = 4, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack/2), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - for (size_t i = 128; i < 192; i+=4) { - if (trigger_on_(i)) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_linear_triangle_build(b, (&(lobullet_linear_param_t) { - .owner = c->super.super.id, - .pos = top, - .size = vec2(.05f, .2f), - .velocity = vec2(0, -1.4f/(beat/1000*2)), - .acceleration = vec2(0, 1/(beat/1000*2)), - .color = vec4(1, 1, 1, .8f), - .duration = beat*2, - .knockback = .1f, - .effect = loeffect_immediate_damage( - c->recipient.status.attack), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - - /* ---- fill-in ---- */ - if (trigger_on_(192)) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_square_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .pos = center, - .size = vec2(.2f, .2f), - .angle = MATH_PI/4, - .color = vec4(1, 1, .4f, .8f), - .silent = true, - .beat = LOCHARACTER_THEISTS_CHILD_BEAT, - .step = 8, - .knockback = .1f, - .effect = loeffect_amnesia( - c->ticker->time + (uint64_t) (8*beat), beat*4), - })); - loentity_store_add(c->entities, &b->super.super); - } - - /* ---- C melody ---- */ - for (size_t i = 200, cnt = 0; i < 232; i+=2, ++cnt) { - if (trigger_on_(i)) { - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_bomb_square_build(b, (&(lobullet_bomb_param_t) { - .owner = c->super.super.id, - .size = vec2(.16f, .16f), - .pos = cnt%2 == 0? left: right, - .angle = MATH_PI/4, - .color = vec4(1, 1, 1, .8f), - .silent = true, - .beat = LOCHARACTER_THEISTS_CHILD_BEAT, - .step = 2, - .knockback = .1f, - .effect = loeffect_immediate_damage(c->recipient.status.attack), - })); - loentity_store_add(c->entities, &b->super.super); - } - } - -# undef trigger_on_ -} diff --git a/core/locharacter/util.c b/core/locharacter/util.c deleted file mode 100644 index d69acac..0000000 --- a/core/locharacter/util.c +++ /dev/null @@ -1,139 +0,0 @@ -#include "./util.h" - -#include -#include -#include -#include - -#include "util/math/rational.h" -#include "util/math/vector.h" - -#include "core/locommon/position.h" -#include "core/loresource/music.h" -#include "core/loplayer/event.h" - -#include "./base.h" - -static void locharacter_event_holder_handle_control_lost_( - locharacter_event_holder_t* holder) { - assert(holder != NULL); - - if (holder->music != NULL) { - jukebox_amp_change_volume(&holder->music->amp, 0, &rational(1, 1)); - jukebox_decoder_stop_after(holder->music->decoder, &rational(1, 1)); - } - - holder->param = NULL; - holder->start_time = 0; -} - -void locharacter_event_holder_initialize( - locharacter_event_holder_t* holder, - loresource_music_player_t* music, - locharacter_base_t* owner, - uint64_t duration, - uint64_t start_time) { - assert(holder != NULL); - assert(music != NULL); - assert(owner != NULL); - assert(duration > 0); - - *holder = (typeof(*holder)) { - .music = music, - .owner = owner, - .duration = duration, - .start_time = start_time, - }; -} - -void locharacter_event_holder_deinitialize( - locharacter_event_holder_t* holder) { - assert(holder != NULL); - - locharacter_event_holder_release_control(holder); -} - -bool locharacter_event_holder_take_control( - locharacter_event_holder_t* holder) { - assert(holder != NULL); - assert(holder->owner != NULL); - assert(holder->owner->cache.ground != NULL); - - const locharacter_base_t* owner = holder->owner; - - const bool recover = holder->start_time > 0; - - const uint64_t t = recover? owner->cache.time - holder->start_time: 0; - if (recover && t >= holder->duration) return false; - - holder->param = loplayer_event_take_control( - owner->player->event, owner->super.super.id); - if (holder->param == NULL) return false; - - loplayer_event_param_t* p = holder->param; - - p->area_pos = owner->cache.ground->super.pos; - p->area_pos.fract.y += .4f; - locommon_position_reduce(&p->area_pos); - - p->area_size = vec2(.45f, .45f); - p->music = holder->music; - - if (!recover) { - loentity_character_apply_effect( - &owner->player->entity.super, - &loeffect_curse(owner->ticker->time, holder->duration)); - holder->start_time = owner->cache.time; - } - if (holder->music != NULL) { - jukebox_decoder_play(holder->music->decoder, &rational(t, 1000), false); - jukebox_amp_change_volume(&holder->music->amp, .8f, &rational(1, 1)); - } - return true; -} - -void locharacter_event_holder_release_control( - locharacter_event_holder_t* holder) { - assert(holder != NULL); - - if (holder->param == NULL) return; - - loplayer_event_param_release_control(holder->param); - locharacter_event_holder_handle_control_lost_(holder); -} - -bool locharacter_event_holder_update(locharacter_event_holder_t* holder) { - assert(holder != NULL); - - if (holder->start_time > holder->owner->ticker->time) { - holder->start_time = 0; - } - - loplayer_event_param_t* p = holder->param; - if (p == NULL) { - if (holder->start_time > 0) { - return locharacter_event_holder_take_control(holder); - } - return true; - } - - if (!p->controlled || p->controlled_by != holder->owner->super.super.id) { - locharacter_event_holder_handle_control_lost_(holder); - return false; - } - - if (holder->music != NULL) { - rational_t r; - jukebox_decoder_get_seek_position(holder->music->decoder, &r); - rational_normalize(&r, 1000); - holder->owner->cache.time = r.num + holder->start_time; - } - return true; -} - -bool locharacter_event_holder_has_control( - const locharacter_event_holder_t* holder) { - assert(holder != NULL); - - return holder->param != NULL; -} diff --git a/core/locharacter/util.h b/core/locharacter/util.h deleted file mode 100644 index 464ab2a..0000000 --- a/core/locharacter/util.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include -#include - -#include "core/loentity/entity.h" -#include "core/loresource/music.h" -#include "core/loplayer/event.h" - -#include "./base.h" - -typedef struct { - loresource_music_player_t* music; - locharacter_base_t* owner; - - uint64_t duration; - - loplayer_event_param_t* param; - uint64_t start_time; -} locharacter_event_holder_t; - -void -locharacter_event_holder_initialize( - locharacter_event_holder_t* holder, - loresource_music_player_t* music, - locharacter_base_t* owner, - uint64_t duration, - uint64_t start_time -); - -void -locharacter_event_holder_deinitialize( - locharacter_event_holder_t* holder -); - -bool -locharacter_event_holder_take_control( - locharacter_event_holder_t* holder -); - -void -locharacter_event_holder_release_control( - locharacter_event_holder_t* holder -); - -bool /* false: event was aborted by others */ -locharacter_event_holder_update( - locharacter_event_holder_t* holder -); - -bool -locharacter_event_holder_has_control( - const locharacter_event_holder_t* holder -); diff --git a/core/locharacter/warder.c b/core/locharacter/warder.c deleted file mode 100644 index 784c17a..0000000 --- a/core/locharacter/warder.c +++ /dev/null @@ -1,299 +0,0 @@ -#include "./warder.h" - -#include -#include -#include - -#include "util/math/algorithm.h" -#include "util/math/vector.h" - -#include "core/lobullet/base.h" -#include "core/lobullet/linear.h" -#include "core/loeffect/recipient.h" -#include "core/loentity/entity.h" -#include "core/loentity/store.h" -#include "core/loplayer/event.h" -#include "core/loplayer/player.h" -#include "core/loresource/sound.h" -#include "core/loshader/character.h" - -#include "./base.h" -#include "./misc.h" - -static const vec2_t locharacter_warder_size_ = vec2(.02f, .05f); - -static const loeffect_recipient_status_t locharacter_warder_base_status_ = { - .attack = .1f, - .defence = -.8f, -}; - -static void locharacter_warder_shoot_(locharacter_base_t* c) { - assert(c != NULL); - - lobullet_base_t* b = lobullet_pool_create(c->bullets); - lobullet_linear_light_build(b, (&(lobullet_linear_param_t) { - .owner = c->super.super.id, - .pos = c->super.super.pos, - .size = vec2(.04f, .04f), - .velocity = vec2(c->direction*.5f, 0), - .color = vec4(.6f, .6f, .6f, .8f), - .acceleration = vec2(0, 0), - .duration = 2000, - .knockback = .4f, - .effect = loeffect_immediate_damage(c->recipient.status.attack), - })); - loentity_store_add(c->entities, &b->super.super); - - loresource_sound_play(c->res->sound, "enemy_shoot"); -} - -static void -locharacter_warder_start_wait_state_( - locharacter_base_t* base -); -static void -locharacter_warder_start_shoot_state_( - locharacter_base_t* base -); -static void -locharacter_warder_start_combo_state_( - locharacter_base_t* base -); -static void -locharacter_warder_start_dead_state_( - locharacter_base_t* base -); - -static void locharacter_warder_update_wait_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t duration = 1000; - - const uint64_t elapsed = base->ticker->time - base->since; - - /* ---- motion ---- */ - float t = elapsed*1.f / duration; - if (t > 1) t = 1; - - loshader_character_drawer_instance_t* instance = &base->cache.instance; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = t*t*(3-2*t); - - /* ---- state transition ---- */ - if (elapsed >= duration) { - if (base->recipient.madness <= 0) { - locharacter_warder_start_dead_state_(base); - return; - } - - if (loplayer_event_get_param(base->player->event) == NULL) { - vec2_t disp; - vec2_sub(&disp, &base->cache.player_pos, &base->pos); - disp.x *= base->cache.ground->size.x; - - const float pdist = vec2_pow_length(&disp); - if (MATH_ABS(disp.y) < locharacter_warder_size_.y && pdist < .4f*.4f) { - static const float r = locharacter_warder_size_.x*3; - if (pdist < r*r) { - locharacter_warder_start_combo_state_(base); - } else if (disp.x*base->direction > 0) { - locharacter_warder_start_shoot_state_(base); - } - } - return; - } - } -} -static void locharacter_warder_start_wait_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_WAIT; -} - -static void locharacter_warder_update_shoot_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t duration = 500; - - const uint64_t elapsed = base->ticker->time - base->since; - - /* ---- motion ---- */ - float t = elapsed*1.f / duration; - if (t > 1) t = 1; - t = t*t; - - loshader_character_drawer_instance_t* instance = &base->cache.instance; - if (t < .5f) { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->motion_time = t*2; - } else { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->motion_time = (t-.5f)*2; - } - - /* ---- state transition ---- */ - if (elapsed >= duration) { - locharacter_warder_shoot_(base); - locharacter_warder_start_wait_state_(base); - return; - } -} -static void locharacter_warder_start_shoot_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_SHOOT; -} - -static void locharacter_warder_update_combo_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t duration = 1000; - - const uint64_t elapsed = base->ticker->time - base->since; - - /* ---- motion ---- */ - float t = elapsed*1.f/duration; - if (t > 1) t = 1; - t = t*t; - - loshader_character_drawer_instance_t* instance = &base->cache.instance; - if (t < .5f) { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->motion_time = t*2; - } else { - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->motion_time = (t-.5f)*2; - } - - /* ---- state transition ---- */ - if (elapsed >= duration) { - locharacter_warder_start_wait_state_(base); - return; - } -} -static void locharacter_warder_start_combo_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_COMBO; - - const float diff = base->cache.player_pos.x - base->pos.x; - base->direction = MATH_SIGN(diff); - - const loplayer_combat_attack_t attack = { - .attacker = base->super.super.id, - .start = base->ticker->time + 500, - .duration = 500, - .knockback = vec2(base->direction*.1f, 0), - .effect = loeffect_immediate_damage(base->recipient.status.attack), - }; - loplayer_attack(base->player, &attack); -} - -static void locharacter_warder_update_dead_state_(locharacter_base_t* base) { - assert(base != NULL); - - static const uint64_t anime_duration = 500; - static const uint64_t duration = 30000; - - const uint64_t elapsed = base->ticker->time - base->since; - - /* ---- motion ---- */ - loshader_character_drawer_instance_t* instance = &base->cache.instance; - if (elapsed > duration - anime_duration) { /* wake up */ - float t = 1-(duration - elapsed)*1.f/anime_duration; - if (t < 0) t = 0; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1; - instance->motion_time = 1-powf(1-t, 2); - } else { /* down */ - float t = elapsed*1.f/anime_duration; - if (t > 1) t = 1; - instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2; - instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN; - instance->motion_time = t; - } - - /* ---- state transition ---- */ - if (elapsed >= duration) { - loeffect_recipient_reset(&base->recipient); - locharacter_warder_start_wait_state_(base); - return; - } -} -static void locharacter_warder_start_dead_state_(locharacter_base_t* base) { - assert(base != NULL); - - base->since = base->ticker->time; - base->state = LOCHARACTER_STATE_DEAD; - - loplayer_gain_faith(base->player, .1f); -} - -bool locharacter_warder_update(locharacter_base_t* base) { - assert(base != NULL); - - static const vec2_t size = locharacter_warder_size_; - static const vec4_t color = vec4(.1f, .1f, .1f, 1); - static const float height = size.y*1.4f; - static const float drawsz = MATH_MAX(size.x, size.y); - - loeffect_recipient_update(&base->recipient, &locharacter_warder_base_status_); - - base->cache.instance = (loshader_character_drawer_instance_t) { - .character_id = LOSHADER_CHARACTER_ID_WARDER, - .marker_offset = vec2(0, height - drawsz), - .pos = vec2(0, drawsz - height), - .size = vec2(drawsz, drawsz), - .color = color, - }; - - switch (base->state) { - case LOCHARACTER_STATE_WAIT: - locharacter_warder_update_wait_state_(base); - break; - case LOCHARACTER_STATE_SHOOT: - locharacter_warder_update_shoot_state_(base); - break; - case LOCHARACTER_STATE_COMBO: - locharacter_warder_update_combo_state_(base); - break; - case LOCHARACTER_STATE_DEAD: - locharacter_warder_update_dead_state_(base); - break; - default: - locharacter_warder_start_wait_state_(base); - } - - base->cache.bullet_hittest = base->state != LOCHARACTER_STATE_DEAD; - base->cache.gravity = true; - - base->cache.height = height; - - base->cache.instance.size.x *= base->direction; - base->cache.instance.marker = !!base->cache.bullet_hittest; - return true; -} - -void locharacter_warder_build( - locharacter_base_t* base, const locharacter_warder_param_t* param) { - assert(base != NULL); - assert(param != NULL); - - base->type = LOCHARACTER_TYPE_WARDER; - - base->ground = param->ground; - - base->pos = vec2(param->pos, 0); - base->direction = -MATH_SIGN(param->pos); - if (base->direction == 0) base->direction = 1; - - locharacter_warder_start_wait_state_(base); -} diff --git a/core/locharacter/warder.h b/core/locharacter/warder.h deleted file mode 100644 index b73c498..0000000 --- a/core/locharacter/warder.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -#include - -#include "core/loentity/entity.h" - -#include "./base.h" - -typedef struct { - loentity_id_t ground; - float pos; -} locharacter_warder_param_t; - -bool -locharacter_warder_update( - locharacter_base_t* base -); - -void -locharacter_warder_build( - locharacter_base_t* base, - const locharacter_warder_param_t* param -); - -#define locharacter_warder_tear_down(base) - -#define locharacter_warder_pack_data(base, packer) \ - msgpack_pack_nil(packer) - -#define locharacter_warder_unpack_data(base, obj) \ - (obj != NULL) diff --git a/core/locommon/CMakeLists.txt b/core/locommon/CMakeLists.txt index 7b282aa..405b983 100644 --- a/core/locommon/CMakeLists.txt +++ b/core/locommon/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(locommon null.c physics.c position.c + screen.c ticker.c ) target_link_libraries(locommon @@ -13,3 +14,6 @@ target_link_libraries(locommon math mpkutil ) +add_dependencies(locommon + benum-generated +) diff --git a/core/locommon/counter.c b/core/locommon/counter.c index aaaa571..0c6a031 100644 --- a/core/locommon/counter.c +++ b/core/locommon/counter.c @@ -26,6 +26,12 @@ size_t locommon_counter_count(locommon_counter_t* counter) { return counter->next++; } +void locommon_counter_reset(locommon_counter_t* counter) { + assert(counter != NULL); + + counter->next = 0; +} + void locommon_counter_pack( const locommon_counter_t* counter, msgpack_packer* packer) { assert(counter != NULL); diff --git a/core/locommon/counter.h b/core/locommon/counter.h index 38ee923..23ed6b8 100644 --- a/core/locommon/counter.h +++ b/core/locommon/counter.h @@ -25,6 +25,11 @@ locommon_counter_count( locommon_counter_t* counter ); +void +locommon_counter_reset( + locommon_counter_t* counter +); + void locommon_counter_pack( const locommon_counter_t* counter, diff --git a/core/locommon/input.h b/core/locommon/input.h index 09edc5a..92eaf70 100644 --- a/core/locommon/input.h +++ b/core/locommon/input.h @@ -5,15 +5,16 @@ #include "util/math/vector.h" typedef enum { - LOCOMMON_INPUT_BUTTON_LEFT = 1 << 0, - LOCOMMON_INPUT_BUTTON_RIGHT = 1 << 1, - LOCOMMON_INPUT_BUTTON_UP = 1 << 2, - LOCOMMON_INPUT_BUTTON_DOWN = 1 << 3, - LOCOMMON_INPUT_BUTTON_DASH = 1 << 4, - LOCOMMON_INPUT_BUTTON_JUMP = 1 << 5, - LOCOMMON_INPUT_BUTTON_ATTACK = 1 << 6, - LOCOMMON_INPUT_BUTTON_GUARD = 1 << 7, - LOCOMMON_INPUT_BUTTON_MENU = 1 << 8, + LOCOMMON_INPUT_BUTTON_LEFT = 1 << 0, + LOCOMMON_INPUT_BUTTON_RIGHT = 1 << 1, + LOCOMMON_INPUT_BUTTON_DODGE = 1 << 2, + LOCOMMON_INPUT_BUTTON_JUMP = 1 << 3, + LOCOMMON_INPUT_BUTTON_GUARD = 1 << 4, + LOCOMMON_INPUT_BUTTON_SHOOT = 1 << 5, + LOCOMMON_INPUT_BUTTON_MENU = 1 << 6, + + LOCOMMON_INPUT_BUTTON_OK = LOCOMMON_INPUT_BUTTON_SHOOT, + LOCOMMON_INPUT_BUTTON_CANCEL = LOCOMMON_INPUT_BUTTON_MENU, } locommon_input_button_t; typedef uint16_t locommon_input_buttons_t; diff --git a/core/locommon/msgpack.h b/core/locommon/msgpack.h index cd380df..a4145a4 100644 --- a/core/locommon/msgpack.h +++ b/core/locommon/msgpack.h @@ -13,11 +13,17 @@ #include "core/locommon/null.h" /* THE FOLLOWING INCLUDES DESTROY DEPENDENCY STRUCTURE BETWEEN MODULES. :( */ +#include "core/lobullet/type.h" +#include "core/lochara/state.h" +#include "core/lochara/strategy.h" +#include "core/lochara/type.h" #include "core/loeffect/effect.h" #include "core/loeffect/generic.h" #include "core/loeffect/recipient.h" -#include "core/loeffect/stance.h" -#include "core/loentity/entity.h" +#include "core/loground/type.h" +#include "core/loparticle/misc.h" +#include "core/loresource/music.h" +#include "core/loresource/sound.h" #define LOCOMMON_MSGPACK_PACK_ANY_(packer, v) _Generic((v), \ const int32_t*: locommon_msgpack_pack_int32_, \ @@ -27,17 +33,30 @@ const char*: locommon_msgpack_pack_str_, \ const vec2_t*: locommon_msgpack_pack_vec2_, \ const vec4_t*: locommon_msgpack_pack_vec4_, \ + \ + const lobullet_type_t*: locommon_msgpack_lobullet_type_pack_, \ + \ + const lochara_type_t*: locommon_msgpack_lochara_type_pack_, \ + const lochara_state_t*: locommon_msgpack_lochara_state_pack_, \ + const lochara_strategy_t*: locommon_msgpack_lochara_strategy_pack_, \ \ const locommon_counter_t*: locommon_counter_pack, \ const locommon_null_t*: locommon_null_pack, \ const locommon_position_t*: locommon_position_pack, \ const locommon_ticker_t*: locommon_ticker_pack, \ \ - const loeffect_t*: loeffect_pack, \ + const loeffect_id_t*: locommon_msgpack_loeffect_id_pack_, \ + const loeffect_t*: loeffect_pack, \ const loeffect_generic_immediate_param_t*: loeffect_generic_immediate_param_pack, \ - const loeffect_generic_lasting_param_t*: loeffect_generic_lasting_param_pack, \ - const loeffect_recipient_effect_param_t*: loeffect_recipient_effect_param_pack, \ - const loeffect_stance_set_t*: loeffect_stance_set_pack \ + const loeffect_generic_lasting_param_t*: loeffect_generic_lasting_param_pack, \ + const loeffect_recipient_t*: loeffect_recipient_pack, \ + \ + const loground_type_t*: locommon_msgpack_loground_type_pack_, \ + \ + const loparticle_type_t*: locommon_msgpack_loparticle_type_pack_, \ + \ + const loresource_music_id_t*: locommon_msgpack_loresource_music_id_pack_, \ + const loresource_sound_id_t*: locommon_msgpack_loresource_sound_id_pack_ \ )(v, packer) #define LOCOMMON_MSGPACK_PACK_ANY(packer, v) \ @@ -50,17 +69,30 @@ bool*: locommon_msgpack_unpack_bool_, \ vec2_t*: locommon_msgpack_unpack_vec2_, \ vec4_t*: locommon_msgpack_unpack_vec4_, \ + \ + lobullet_type_t*: locommon_msgpack_lobullet_type_unpack_, \ + \ + lochara_type_t*: locommon_msgpack_lochara_type_unpack_, \ + lochara_state_t*: locommon_msgpack_lochara_state_unpack_, \ + lochara_strategy_t*: locommon_msgpack_lochara_strategy_unpack_, \ \ locommon_counter_t*: locommon_counter_unpack, \ locommon_null_t*: locommon_null_unpack, \ locommon_position_t*: locommon_position_unpack, \ locommon_ticker_t*: locommon_ticker_unpack, \ \ - loeffect_t*: loeffect_unpack, \ + loeffect_id_t*: locommon_msgpack_loeffect_id_unpack_, \ + loeffect_t*: loeffect_unpack, \ loeffect_generic_immediate_param_t*: loeffect_generic_immediate_param_unpack, \ - loeffect_generic_lasting_param_t*: loeffect_generic_lasting_param_unpack, \ - loeffect_recipient_effect_param_t*: loeffect_recipient_effect_param_unpack, \ - loeffect_stance_set_t*: loeffect_stance_set_unpack \ + loeffect_generic_lasting_param_t*: loeffect_generic_lasting_param_unpack, \ + loeffect_recipient_t*: loeffect_recipient_unpack, \ + \ + loground_type_t*: locommon_msgpack_loground_type_unpack_, \ + \ + loparticle_type_t*: locommon_msgpack_loparticle_type_unpack_, \ + \ + loresource_music_id_t*: locommon_msgpack_loresource_music_id_unpack_, \ + loresource_sound_id_t*: locommon_msgpack_loresource_sound_id_unpack_ \ )(v, obj) static inline void locommon_msgpack_pack_int32_( @@ -116,3 +148,49 @@ static inline bool locommon_msgpack_unpack_vec4_( vec4_t* v, const msgpack_object* obj) { return mpkutil_get_vec4(obj, v); } + +#define enum_packer_(name) \ + static inline void locommon_msgpack_##name##_pack_( \ + const name##_t* v, msgpack_packer* packer) { \ + mpkutil_pack_str(packer, name##_stringify(*v)); \ + } + +#define enum_unpacker_(name) \ + static inline bool locommon_msgpack_##name##_unpack_( \ + name##_t* v, const msgpack_object* obj) { \ + const char* str; \ + size_t len; \ + return \ + mpkutil_get_str(obj, &str, &len) && \ + name##_unstringify(v, str, len); \ + } + +enum_packer_(lobullet_type); +enum_unpacker_(lobullet_type); + +enum_packer_(lochara_state); +enum_unpacker_(lochara_state); + +enum_packer_(lochara_strategy); +enum_unpacker_(lochara_strategy); + +enum_packer_(lochara_type); +enum_unpacker_(lochara_type); + +enum_packer_(loeffect_id); +enum_unpacker_(loeffect_id); + +enum_packer_(loground_type); +enum_unpacker_(loground_type); + +enum_packer_(loparticle_type); +enum_unpacker_(loparticle_type); + +enum_packer_(loresource_music_id); +enum_unpacker_(loresource_music_id); + +enum_packer_(loresource_sound_id); +enum_unpacker_(loresource_sound_id); + +#undef enum_packer_ +#undef enum_unpacker_ diff --git a/core/locommon/screen.c b/core/locommon/screen.c new file mode 100644 index 0000000..b67f63b --- /dev/null +++ b/core/locommon/screen.c @@ -0,0 +1,94 @@ +#include "./screen.h" + +#include +#include +#include + +#include "util/math/matrix.h" +#include "util/math/vector.h" + +#define CM_PER_INCH_ 2.54f + +#define CHUNK_INCH_ 16 +#define MAX_SCALE_ (1/.5f) + +bool locommon_screen_valid(const locommon_screen_t* screen) { + return + screen != NULL && + vec2_valid(&screen->resolution) && + vec2_valid(&screen->dpi) && + screen->resolution.x > 0 && + screen->resolution.y > 0 && + screen->dpi.x > 0 && + screen->dpi.y > 0; +} + +void locommon_screen_calc_pixels_from_cm( + const locommon_screen_t* screen, vec2_t* pixels, const vec2_t* cm) { + assert(locommon_screen_valid(screen)); + assert(pixels != NULL); + assert(vec2_valid(cm)); + + locommon_screen_calc_pixels_from_inch( + screen, pixels, &vec2(cm->x/CM_PER_INCH_, cm->y/CM_PER_INCH_)); +} + +void locommon_screen_calc_pixels_from_inch( + const locommon_screen_t* screen, vec2_t* pixels, const vec2_t* inch) { + assert(locommon_screen_valid(screen)); + assert(pixels != NULL); + assert(vec2_valid(inch)); + + *pixels = *inch; + + pixels->x *= screen->dpi.x; + pixels->y *= screen->dpi.y; +} + +void locommon_screen_calc_winpos_from_cm( + const locommon_screen_t* screen, vec2_t* winpos, const vec2_t* cm) { + assert(locommon_screen_valid(screen)); + assert(winpos != NULL); + assert(vec2_valid(cm)); + + locommon_screen_calc_winpos_from_inch( + screen, winpos, &vec2(cm->x/CM_PER_INCH_, cm->y/CM_PER_INCH_)); +} + +void locommon_screen_calc_winpos_from_inch( + const locommon_screen_t* screen, vec2_t* winpos, const vec2_t* inch) { + assert(locommon_screen_valid(screen)); + assert(winpos != NULL); + assert(vec2_valid(inch)); + + locommon_screen_calc_pixels_from_inch(screen, winpos, inch); + winpos->x /= screen->resolution.x / 2; + winpos->y /= screen->resolution.y / 2; +} + +void locommon_screen_calc_winpos_from_pixels( + const locommon_screen_t* screen, vec2_t* winpos, const vec2_t* pixels) { + assert(locommon_screen_valid(screen)); + assert(winpos != NULL); + assert(vec2_valid(pixels)); + + *winpos = *pixels; + winpos->x /= screen->resolution.x / 2; + winpos->y /= screen->resolution.y / 2; +} + +void locommon_screen_build_projection_matrix( + const locommon_screen_t* screen, mat4_t* proj) { + assert(screen != NULL); + assert(proj != NULL); + + vec2_t scale; + locommon_screen_calc_winpos_from_inch( + screen, &scale, &vec2(CHUNK_INCH_, CHUNK_INCH_)); + + if (scale.x > MAX_SCALE_) { + scale.y *= MAX_SCALE_/scale.x; + scale.x = MAX_SCALE_; + } + *proj = mat4_scale(scale.x, scale.y, 1); +} diff --git a/core/locommon/screen.h b/core/locommon/screen.h new file mode 100644 index 0000000..be630fc --- /dev/null +++ b/core/locommon/screen.h @@ -0,0 +1,57 @@ +#pragma once + +#include + +#include "util/math/matrix.h" +#include "util/math/vector.h" + +typedef struct { + vec2_t resolution; + vec2_t dpi; +} locommon_screen_t; + +bool +locommon_screen_valid( + const locommon_screen_t* screen +); + +void +locommon_screen_calc_pixels_from_cm( + const locommon_screen_t* screen, + vec2_t* pixels, + const vec2_t* cm +); + +void +locommon_screen_calc_pixels_from_inch( + const locommon_screen_t* screen, + vec2_t* pixels, + const vec2_t* inch +); + +void +locommon_screen_calc_winpos_from_cm( + const locommon_screen_t* screen, + vec2_t* winpos, + const vec2_t* cm +); + +void +locommon_screen_calc_winpos_from_inch( + const locommon_screen_t* screen, + vec2_t* winpos, + const vec2_t* inch +); + +void +locommon_screen_calc_winpos_from_pixels( + const locommon_screen_t* screen, + vec2_t* winpos, + const vec2_t* pixels +); + +void +locommon_screen_build_projection_matrix( + const locommon_screen_t* screen, + mat4_t* proj +); diff --git a/core/locommon/ticker.c b/core/locommon/ticker.c index 92957c8..0c3b7c5 100644 --- a/core/locommon/ticker.c +++ b/core/locommon/ticker.c @@ -22,9 +22,11 @@ void locommon_ticker_tick(locommon_ticker_t* ticker, uint64_t time) { assert(ticker != NULL); assert(ticker->time <= time); - ticker->delta = time - ticker->time; + ticker->delta = time - ticker->time; ticker->delta_f = ticker->delta*1.f / LOCOMMON_TICKER_UNIT; - ticker->time = time; + + ticker->prev_time = ticker->time; + ticker->time = time; } void locommon_ticker_pack( diff --git a/core/locommon/ticker.h b/core/locommon/ticker.h index 7c79e1a..1cf8904 100644 --- a/core/locommon/ticker.h +++ b/core/locommon/ticker.h @@ -9,6 +9,7 @@ typedef struct { uint64_t time; + uint64_t prev_time; int64_t delta; float delta_f; diff --git a/core/loeffect/CMakeLists.txt b/core/loeffect/CMakeLists.txt index 66f415e..6a6f87d 100644 --- a/core/loeffect/CMakeLists.txt +++ b/core/loeffect/CMakeLists.txt @@ -2,7 +2,9 @@ add_library(loeffect effect.c generic.c recipient.c - stance.c +) +target_crial_sources(loeffect + recipient.crial ) target_link_libraries(loeffect msgpackc diff --git a/core/loeffect/effect.c b/core/loeffect/effect.c index ea6557d..65f1e8e 100644 --- a/core/loeffect/effect.c +++ b/core/loeffect/effect.c @@ -11,13 +11,6 @@ #include "./generic.h" -#define LOEFFECT_ID_EACH_(PROC) do { \ - PROC(IMMEDIATE_DAMAGE, "imm-damage", imm); \ - PROC(CURSE, "curse", lasting); \ - PROC(CURSE_TRIGGER, "curse-trigger", null); \ - PROC(AMNESIA, "amnesia", lasting); \ -} while (0) - const char* loeffect_id_stringify(loeffect_id_t id) { # define each_(NAME, s, d) do { \ if (LOEFFECT_ID_##NAME == id) return s; \ diff --git a/core/loeffect/effect.h b/core/loeffect/effect.h index e4c2256..6b5bede 100644 --- a/core/loeffect/effect.h +++ b/core/loeffect/effect.h @@ -11,17 +11,38 @@ #include "./generic.h" typedef enum { - LOEFFECT_ID_IMMEDIATE_DAMAGE, + /* system effect */ + LOEFFECT_ID_NONE, + LOEFFECT_ID_RESUSCITATE, + LOEFFECT_ID_LOST_DAMAGE, + LOEFFECT_ID_CURSE_TRIGGER, + LOEFFECT_ID_DAMAGE, + LOEFFECT_ID_HEAL, + LOEFFECT_ID_LOST, + LOEFFECT_ID_RETRIEVAL, + + LOEFFECT_ID_FANATIC, LOEFFECT_ID_CURSE, /* The curse effect actually does nothing and is just for HUD. * To kill player immediately, use curse trigger effect.*/ - LOEFFECT_ID_CURSE_TRIGGER, - LOEFFECT_ID_AMNESIA, - LOEFFECT_ID_LOST, } loeffect_id_t; +#define LOEFFECT_ID_EACH_(PROC) do { \ + PROC(NONE, "none", null); \ + PROC(RESUSCITATE, "resuscitate", null); \ + PROC(LOST_DAMAGE, "lost-damage", null); \ + PROC(CURSE_TRIGGER, "curse-trigger", null); \ + PROC(DAMAGE, "damage", imm); \ + PROC(HEAL, "heal", imm); \ + PROC(LOST, "lost", imm); \ + PROC(RETRIEVAL, "retrieval", imm); \ + PROC(FANATIC, "fanatic", lasting); \ + PROC(CURSE, "curse", lasting); \ + PROC(AMNESIA, "amnesia", lasting); \ +} while (0) + typedef struct { loeffect_id_t id; union { @@ -31,36 +52,38 @@ typedef struct { } data; } loeffect_t; -#define loeffect_immediate_damage(a) \ +#define loeffect_with_null_data_(ID) \ ((loeffect_t) { \ - .id = LOEFFECT_ID_IMMEDIATE_DAMAGE, \ + .id = LOEFFECT_ID_##ID, \ + } ) +#define loeffect_with_imm_data_(ID, a) \ + ((loeffect_t) { \ + .id = LOEFFECT_ID_##ID, \ .data = { .imm = { \ .amount = a, \ }, }, \ } ) - -#define loeffect_curse(b, dur) \ +#define loeffect_with_lasting_data_(ID, d) \ ((loeffect_t) { \ - .id = LOEFFECT_ID_CURSE, \ + .id = LOEFFECT_ID_##ID, \ .data = { .lasting = { \ - .begin = b, \ - .duration = dur, \ + .duration = d, \ }, }, \ } ) -#define loeffect_curse_trigger() \ - ((loeffect_t) { \ - .id = LOEFFECT_ID_CURSE_TRIGGER, \ - } ) +#define loeffect_none() loeffect_with_null_data_(NONE) +#define loeffect_resuscitate() loeffect_with_null_data_(RESUSCITATE) +#define loeffect_lost_damage() loeffect_with_null_data_(LOST_DAMAGE) +#define loeffect_curse_trigger() loeffect_with_null_data_(CURSE_TRIGGER) -#define loeffect_amnesia(b, dur) \ - ((loeffect_t) { \ - .id = LOEFFECT_ID_AMNESIA, \ - .data = { .lasting = { \ - .begin = b, \ - .duration = dur, \ - }, }, \ - } ) +#define loeffect_damage(a) loeffect_with_imm_data_(DAMAGE, a) +#define loeffect_heal(a) loeffect_with_imm_data_(HEAL, a) +#define loeffect_lost(a) loeffect_with_imm_data_(LOST, a) +#define loeffect_retrieval(a) loeffect_with_imm_data_(RETRIEVAL, a) + +#define loeffect_curse(d) loeffect_with_lasting_data_(CURSE, d) +#define loeffect_fanatic(d) loeffect_with_lasting_data_(FANATIC, d) +#define loeffect_amnesia(d) loeffect_with_lasting_data_(AMNESIA, d) const char* loeffect_id_stringify( diff --git a/core/loeffect/generic.c b/core/loeffect/generic.c index 4aaeb99..e15b7c1 100644 --- a/core/loeffect/generic.c +++ b/core/loeffect/generic.c @@ -45,8 +45,8 @@ void loeffect_generic_lasting_param_pack( msgpack_pack_map(packer, 3); - mpkutil_pack_str(packer, "begin"); - msgpack_pack_uint64(packer, param->begin); + mpkutil_pack_str(packer, "start"); + msgpack_pack_uint64(packer, param->start); mpkutil_pack_str(packer, "duration"); msgpack_pack_uint64(packer, param->duration); @@ -66,7 +66,7 @@ bool loeffect_generic_lasting_param_unpack( # define item_(v) mpkutil_get_map_item_by_str(root, v) - if (!mpkutil_get_uint64(item_("begin"), ¶m->begin)) { + if (!mpkutil_get_uint64(item_("start"), ¶m->start)) { return false; } if (!mpkutil_get_uint64(item_("duration"), ¶m->duration)) { diff --git a/core/loeffect/generic.h b/core/loeffect/generic.h index a66f0da..d6b72e0 100644 --- a/core/loeffect/generic.h +++ b/core/loeffect/generic.h @@ -10,7 +10,7 @@ typedef struct { } loeffect_generic_immediate_param_t; typedef struct { - uint64_t begin; + uint64_t start; uint64_t duration; float amount; } loeffect_generic_lasting_param_t; diff --git a/core/loeffect/recipient.c b/core/loeffect/recipient.c index 5b7bccd..c15c978 100644 --- a/core/loeffect/recipient.c +++ b/core/loeffect/recipient.c @@ -16,20 +16,25 @@ #include "./generic.h" -#define LOEFFECT_RECIPIENT_EFFECT_PARAM_EACH_(PROC) do { \ - PROC(curse); \ -} while (0) -#define LOEFFECT_RECIPIENT_EFFECT_PARAM_COUNT 1 +/* generated serializer */ +#include "core/loeffect/crial/recipient.h" + +#define LOST_DAMAGE_AMOUNT_ .03f +#define LOST_DAMAGE_PERIOD_ 1000 void loeffect_recipient_initialize( - loeffect_recipient_t* recipient, const locommon_ticker_t* ticker) { + loeffect_recipient_t* recipient, + const locommon_ticker_t* ticker, + const loeffect_recipient_status_t* status) { assert(recipient != NULL); assert(ticker != NULL); *recipient = (typeof(*recipient)) { .ticker = ticker, + .madness = 1, + .faith = 1, }; - loeffect_recipient_reset(recipient); + if (status != NULL) recipient->status = *status; } void loeffect_recipient_deinitialize(loeffect_recipient_t* recipient) { @@ -37,41 +42,72 @@ void loeffect_recipient_deinitialize(loeffect_recipient_t* recipient) { } -void loeffect_recipient_reset(loeffect_recipient_t* recipient) { - assert(recipient != NULL); - - recipient->madness = 1; - recipient->faith = 1; - - recipient->effects = (typeof(recipient->effects)) {0}; -} - void loeffect_recipient_apply_effect( loeffect_recipient_t* recipient, const loeffect_t* effect) { assert(recipient != NULL); assert(effect != NULL); - if (recipient->madness <= 0) return; + if (effect->id == LOEFFECT_ID_RESUSCITATE) { + recipient->madness = 1; + recipient->faith = 1; + recipient->effects = (typeof(recipient->effects)) {0}; + recipient->last_resuscitate = recipient->ticker->time; + } + if (!loeffect_recipient_is_alive(recipient)) return; + + const float faith_backup = recipient->faith; switch (effect->id) { - case LOEFFECT_ID_IMMEDIATE_DAMAGE: - recipient->madness -= - effect->data.imm.amount * (1-recipient->status.defence); - recipient->last_damage = LOEFFECT_ID_IMMEDIATE_DAMAGE; + case LOEFFECT_ID_NONE: + case LOEFFECT_ID_RESUSCITATE: break; - case LOEFFECT_ID_CURSE: - recipient->effects.curse = effect->data.lasting; + case LOEFFECT_ID_LOST_DAMAGE: + recipient->madness -= LOST_DAMAGE_AMOUNT_; break; case LOEFFECT_ID_CURSE_TRIGGER: recipient->madness = 0; - recipient->last_damage = LOEFFECT_ID_CURSE; + break; + case LOEFFECT_ID_DAMAGE: + recipient->madness -= + effect->data.imm.amount * (1-recipient->status.defence); + recipient->last_damage = recipient->ticker->time; + break; + case LOEFFECT_ID_HEAL: + recipient->madness += effect->data.imm.amount; + recipient->last_heal = recipient->ticker->time; + break; + case LOEFFECT_ID_LOST: + recipient->faith -= effect->data.imm.amount; + recipient->last_lost = recipient->ticker->time; + break; + case LOEFFECT_ID_RETRIEVAL: + recipient->faith += effect->data.imm.amount; + recipient->last_retrieval = recipient->ticker->time; + break; + case LOEFFECT_ID_FANATIC: + recipient->effects.fanatic = effect->data.lasting; + recipient->effects.fanatic.start = recipient->ticker->time; + break; + case LOEFFECT_ID_CURSE: + recipient->effects.curse = effect->data.lasting; + recipient->effects.curse.start = recipient->ticker->time; break; case LOEFFECT_ID_AMNESIA: - recipient->effects.amnesia = effect->data.lasting; + recipient->effects.amnesia = effect->data.lasting; + recipient->effects.amnesia.start = recipient->ticker->time; break; - default: - ; } + + if (!loeffect_recipient_is_alive(recipient)) { + recipient->last_die = recipient->ticker->time; + recipient->last_die_reason = effect->id; + } + if (faith_backup > 0 && recipient->faith <= 0) { + recipient->lost_damage_since = recipient->ticker->time; + } + + recipient->madness = MATH_CLAMP(recipient->madness, 0, 1); + recipient->faith = MATH_CLAMP(recipient->faith, 0, 1); } void loeffect_recipient_update( @@ -79,54 +115,57 @@ void loeffect_recipient_update( assert(recipient != NULL); assert(base != NULL); + const uint64_t t = recipient->ticker->time; + const uint64_t pt = recipient->ticker->prev_time; + recipient->status = *base; if (recipient->madness > 0 && recipient->faith <= 0) { - recipient->madness -= recipient->ticker->delta_f / 30; - recipient->last_damage = LOEFFECT_ID_LOST; + const uint64_t since = recipient->lost_damage_since; + if (pt < since || + (pt-since)/LOST_DAMAGE_PERIOD_ != (t-since)/LOST_DAMAGE_PERIOD_) { + loeffect_recipient_apply_effect(recipient, &loeffect_lost_damage()); + } } - recipient->madness = MATH_CLAMP(recipient->madness, 0, 1); - recipient->faith = MATH_CLAMP(recipient->faith, 0, 1); + const uint64_t fanatic_st = recipient->effects.fanatic.start; + const uint64_t fanatic_ed = fanatic_st + recipient->effects.fanatic.duration; + if (pt < fanatic_ed && fanatic_ed <= t && recipient->madness <= 0) { + recipient->last_die = recipient->ticker->time; + recipient->last_die_reason = LOEFFECT_ID_FANATIC; + } } -void loeffect_recipient_effect_param_pack( - const loeffect_recipient_effect_param_t* param, - msgpack_packer* packer) { - assert(param != NULL); - assert(packer != NULL); +bool loeffect_recipient_is_alive(const loeffect_recipient_t* recipient) { + assert(recipient != NULL); - msgpack_pack_map(packer, LOEFFECT_RECIPIENT_EFFECT_PARAM_COUNT); + if (recipient->madness > 0) return true; -# define each_(name) do { \ - mpkutil_pack_str(packer, #name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, ¶m->name); \ - } while (0) + const uint64_t t = recipient->ticker->time; - LOEFFECT_RECIPIENT_EFFECT_PARAM_EACH_(each_); + const uint64_t fanatic_st = recipient->effects.fanatic.start; + const uint64_t fanatic_ed = fanatic_st + recipient->effects.fanatic.duration; + if (fanatic_st <= t && t < fanatic_ed) return true; -# undef each_ + return false; } -bool loeffect_recipient_effect_param_unpack( - loeffect_recipient_effect_param_t* param, const msgpack_object* obj) { - assert(param != NULL); +void loeffect_recipient_pack( + const loeffect_recipient_t* recipient, msgpack_packer* packer) { + assert(recipient != NULL); + assert(packer != NULL); - if (obj == NULL) return false; + msgpack_pack_map(packer, CRIAL_PROPERTY_COUNT_); + CRIAL_SERIALIZER_; +} + +bool loeffect_recipient_unpack( + loeffect_recipient_t* recipient, const msgpack_object* obj) { + assert(recipient != NULL); const msgpack_object_map* root = mpkutil_get_map(obj); + if (root == NULL) return false; -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define each_(name) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(#name), ¶m->name)) { \ - param->name = (typeof(param->name)) {0}; \ - } \ - } while (0) - - LOEFFECT_RECIPIENT_EFFECT_PARAM_EACH_(each_); - -# undef each_ -# undef item_ + CRIAL_DESERIALIZER_; return true; } diff --git a/core/loeffect/recipient.crial b/core/loeffect/recipient.crial new file mode 100644 index 0000000..b3f52c8 --- /dev/null +++ b/core/loeffect/recipient.crial @@ -0,0 +1,31 @@ +/* CRIAL + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + LOCOMMON_MSGPACK_PACK_ANY(packer, &recipient->$code); + END + DESERIALIZER_BEGIN + if (!LOCOMMON_MSGPACK_UNPACK_ANY( + mpkutil_get_map_item_by_str(root, "$name"), &recipient->$code)) { + return false; + } + END + PROPERTY attack = status.attack + PROPERTY defence = status.defence + PROPERTY speed = status.speed + PROPERTY jump = status.jump + + PROPERTY faith + PROPERTY madness + + PROPERTY last_die + PROPERTY last_die_reason + PROPERTY last_resuscitate + PROPERTY last_damage + PROPERTY last_heal + PROPERTY last_lost + PROPERTY last_retrieval + + PROPERTY fanatic = effects.fanatic + PROPERTY curse = effects.curse + PROPERTY amnesia = effects.amnesia +*/ diff --git a/core/loeffect/recipient.h b/core/loeffect/recipient.h index 57f0397..9c6d880 100644 --- a/core/loeffect/recipient.h +++ b/core/loeffect/recipient.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -17,28 +18,37 @@ typedef struct { float jump; /* [chunks/sec^2] */ } loeffect_recipient_status_t; -typedef struct { - loeffect_generic_lasting_param_t curse; - loeffect_generic_lasting_param_t amnesia; -} loeffect_recipient_effect_param_t; - typedef struct { const locommon_ticker_t* ticker; - float madness; - float faith; - loeffect_id_t last_damage; - - loeffect_recipient_effect_param_t effects; - loeffect_recipient_status_t status; + float madness; + float faith; + + uint64_t last_die; + loeffect_id_t last_die_reason; + + uint64_t lost_damage_since; + + uint64_t last_resuscitate; + uint64_t last_damage; + uint64_t last_heal; + uint64_t last_lost; + uint64_t last_retrieval; + + struct { + loeffect_generic_lasting_param_t fanatic; + loeffect_generic_lasting_param_t curse; + loeffect_generic_lasting_param_t amnesia; + } effects; } loeffect_recipient_t; void loeffect_recipient_initialize( - loeffect_recipient_t* recipient, - const locommon_ticker_t* ticker + loeffect_recipient_t* recipient, + const locommon_ticker_t* ticker, + const loeffect_recipient_status_t* status /* NULLABLE */ ); void @@ -46,11 +56,6 @@ loeffect_recipient_deinitialize( loeffect_recipient_t* recipient ); -void -loeffect_recipient_reset( - loeffect_recipient_t* recipient -); - void loeffect_recipient_apply_effect( loeffect_recipient_t* recipient, @@ -63,14 +68,19 @@ loeffect_recipient_update( const loeffect_recipient_status_t* base ); +bool +loeffect_recipient_is_alive( + const loeffect_recipient_t* recipient +); + void -loeffect_recipient_effect_param_pack( - const loeffect_recipient_effect_param_t* recipient, - msgpack_packer* packer +loeffect_recipient_pack( + const loeffect_recipient_t* recipient, + msgpack_packer* packer ); bool -loeffect_recipient_effect_param_unpack( - loeffect_recipient_effect_param_t* recipient, - const msgpack_object* obj /* NULLABLE */ +loeffect_recipient_unpack( + loeffect_recipient_t* recipient, + const msgpack_object* obj ); diff --git a/core/loeffect/stance.c b/core/loeffect/stance.c deleted file mode 100644 index 3d7a340..0000000 --- a/core/loeffect/stance.c +++ /dev/null @@ -1,143 +0,0 @@ -#include "./stance.h" - -#include -#include -#include -#include -#include - -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" - -#include "core/loshader/menu_stance.h" - -#include "./recipient.h" - -const char* loeffect_stance_stringify(loeffect_stance_id_t id) { -# define each_(NAME, name) \ - if (id == LOEFFECT_STANCE_ID_##NAME) return #name; - - LOEFFECT_STANCE_EACH(each_); - - assert(false); - return NULL; - -# undef each_ -} - -bool loeffect_stance_unstringify( - loeffect_stance_id_t* id, const char* str, size_t len) { - assert(id != NULL); - assert(str != NULL || len == 0); - -# define each_(NAME, name) do {\ - if (strncmp(str, #name, len) == 0 && #name[len] == 0) { \ - *id = LOEFFECT_STANCE_ID_##NAME; \ - return true; \ - } \ - } while (0) - - LOEFFECT_STANCE_EACH(each_); - return false; - -# undef each_ -} - -loshader_menu_stance_id_t loeffect_stance_get_id_for_menu_shader( - loeffect_stance_id_t id) { -# define each_(NAME, name) do {\ - if (id == LOEFFECT_STANCE_ID_##NAME) { \ - return LOSHADER_MENU_STANCE_ID_##NAME; \ - } \ - } while (0) - - LOEFFECT_STANCE_EACH(each_); - - assert(false); - return LOSHADER_MENU_STANCE_ID_EMPTY; - -# undef each_ -} - -void loeffect_stance_set_initialize(loeffect_stance_set_t* set) { - assert(set != NULL); - - *set = 1 << LOEFFECT_STANCE_ID_MISSIONARY; -} - -void loeffect_stance_set_deinitialize(loeffect_stance_set_t* set) { - assert(set != NULL); - -} - -void loeffect_stance_set_add( - loeffect_stance_set_t* set, loeffect_stance_id_t id) { - assert(set != NULL); - - *set |= 1 << id; -} - -void loeffect_stance_set_remove( - loeffect_stance_set_t* set, loeffect_stance_id_t id) { - assert(set != NULL); - - *set &= ~(1 << id); -} - -bool loeffect_stance_set_has( - const loeffect_stance_set_t* set, loeffect_stance_id_t id) { - assert(set != NULL); - - return *set & (1 << id); -} - -void loeffect_stance_set_affect_base_status( - const loeffect_stance_set_t* set, - loeffect_recipient_status_t* status) { - assert(set != NULL); - assert(status != NULL); - -} - -void loeffect_stance_set_pack( - const loeffect_stance_set_t* set, msgpack_packer* packer) { - assert(set != NULL); - assert(packer != NULL); - - loeffect_stance_id_t mask = 1; - size_t len = 0; - while (mask <= *set) { - len += !!(*set & mask); - mask <<= 1; - } - msgpack_pack_array(packer, len); - - mask = 1; - size_t i = 0; - while (*set >= mask) { - if (*set & mask) { - mpkutil_pack_str(packer, loeffect_stance_stringify(i)); - } - ++i; - mask <<= 1; - } -} - -bool loeffect_stance_set_unpack( - loeffect_stance_set_t* set, const msgpack_object* obj) { - assert(set != NULL); - - const msgpack_object_array* array = mpkutil_get_array(obj); - if (array == NULL) return false; - - for (size_t i = 0; i < array->size; ++i) { - size_t len; - const char* name; - if (!mpkutil_get_str(&array->ptr[i], &name, &len)) continue; - - loeffect_stance_id_t stance; - if (!loeffect_stance_unstringify(&stance, name, len)) continue; - *set |= 1 << stance; - } - return true; -} diff --git a/core/loeffect/stance.h b/core/loeffect/stance.h deleted file mode 100644 index d9bd933..0000000 --- a/core/loeffect/stance.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include "core/loshader/menu_stance.h" - -typedef enum { - LOEFFECT_STANCE_ID_MISSIONARY, - LOEFFECT_STANCE_ID_REVOLUTIONER, - LOEFFECT_STANCE_ID_UNFINISHER, - LOEFFECT_STANCE_ID_PHILOSOPHER, - LOEFFECT_STANCE_ID_LENGTH_, -} loeffect_stance_id_t; -_Static_assert(LOEFFECT_STANCE_ID_LENGTH_ < 16); - -typedef uint16_t loeffect_stance_set_t; - -#define LOEFFECT_STANCE_EACH(PROC) do { \ - PROC(MISSIONARY, missionary); \ - PROC(REVOLUTIONER, revolutioner); \ - PROC(UNFINISHER, unfinisher); \ - PROC(PHILOSOPHER, philosopher); \ -} while (0) - -const char* -loeffect_stance_stringify( - loeffect_stance_id_t id -); - -bool -loeffect_stance_unstringify( - loeffect_stance_id_t* id, - const char* str, - size_t len -); - -loshader_menu_stance_id_t -loeffect_stance_get_id_for_menu_shader( - loeffect_stance_id_t id -); - -void -loeffect_stance_set_initialize( - loeffect_stance_set_t* set -); - -void -loeffect_stance_set_deinitialize( - loeffect_stance_set_t* set -); - -void -loeffect_stance_set_add( - loeffect_stance_set_t* set, - loeffect_stance_id_t id -); - -void -loeffect_stance_set_remove( - loeffect_stance_set_t* set, - loeffect_stance_id_t id -); - -bool -loeffect_stance_set_has( - const loeffect_stance_set_t* set, - loeffect_stance_id_t id -); - -void -loeffect_stance_set_pack( - const loeffect_stance_set_t* set, - msgpack_packer* packer -); - -bool -loeffect_stance_set_unpack( - loeffect_stance_set_t* set, - const msgpack_object* obj -); diff --git a/core/loentity/CMakeLists.txt b/core/loentity/CMakeLists.txt index 1e7272a..dfba3d8 100644 --- a/core/loentity/CMakeLists.txt +++ b/core/loentity/CMakeLists.txt @@ -13,4 +13,5 @@ target_link_libraries(loentity memory locommon + loeffect ) diff --git a/core/loentity/character.h b/core/loentity/character.h index 650e063..83c5a64 100644 --- a/core/loentity/character.h +++ b/core/loentity/character.h @@ -25,6 +25,8 @@ struct loentity_character_t { loentity_t super; loentity_character_vtable_t vtable; + + vec2_t velocity; }; void diff --git a/core/loentity/entity.h b/core/loentity/entity.h index c6d280e..acc89d4 100644 --- a/core/loentity/entity.h +++ b/core/loentity/entity.h @@ -43,6 +43,7 @@ typedef struct { typedef enum { LOENTITY_SUBCLASS_NONE, LOENTITY_SUBCLASS_GROUND, + LOENTITY_SUBCLASS_PARTICLE, LOENTITY_SUBCLASS_BULLET, LOENTITY_SUBCLASS_CHARACTER, } loentity_subclass_t; diff --git a/core/loentity/pool.h b/core/loentity/pool.h new file mode 100644 index 0000000..41db339 --- /dev/null +++ b/core/loentity/pool.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include "util/memory/memory.h" + +/* You must define prefix##_pool_new function yourself. */ + +#define LOENTITY_POOL_SOURCE_TEMPLATE(prefix) \ + struct prefix##_pool_t { \ + locommon_counter_t* idgen; \ + size_t length; \ + prefix##_base_t items[1]; \ + }; \ + \ + static size_t prefix##_pool_find_unused_item_index_( \ + const prefix##_pool_t* pool) { \ + assert(pool != NULL); \ + \ + for (size_t i = 0; i < pool->length; ++i) { \ + if (!pool->items[i].used) return i; \ + } \ + fprintf(stderr, #prefix " pool overflow\n"); \ + abort(); \ + } \ + \ + void prefix##_pool_delete(prefix##_pool_t* pool) { \ + assert(pool != NULL); \ + \ + for (size_t i = 0; i < pool->length; ++i) { \ + prefix##_base_deinitialize(&pool->items[i]); \ + } \ + memory_delete(pool); \ + } \ + \ + prefix##_base_t* prefix##_pool_create(prefix##_pool_t* pool) { \ + assert(pool != NULL); \ + \ + const size_t i = prefix##_pool_find_unused_item_index_(pool); \ + \ + prefix##_base_reinitialize( \ + &pool->items[i], locommon_counter_count(pool->idgen)); \ + \ + pool->items[i].used = true; \ + return &pool->items[i]; \ + } \ + \ + prefix##_base_t* prefix##_pool_unpack_item( \ + prefix##_pool_t* pool, const msgpack_object* obj) { \ + assert(pool != NULL); \ + \ + const size_t i = prefix##_pool_find_unused_item_index_(pool); \ + \ + if (!prefix##_base_unpack(&pool->items[i], obj)) return NULL; \ + \ + pool->items[i].used = true; \ + return &pool->items[i]; \ + } diff --git a/core/loentity/store.c b/core/loentity/store.c index 2716816..cd36a71 100644 --- a/core/loentity/store.c +++ b/core/loentity/store.c @@ -37,6 +37,8 @@ static void loentity_store_iterator_assign_by_index_( case LOENTITY_SUBCLASS_GROUND: itr->ground = (loentity_ground_t*) itr->entity; break; + case LOENTITY_SUBCLASS_PARTICLE: + break; case LOENTITY_SUBCLASS_BULLET: itr->bullet = (loentity_bullet_t*) itr->entity; break; diff --git a/core/loground/CMakeLists.txt b/core/loground/CMakeLists.txt index e0f0c4f..ea38dce 100644 --- a/core/loground/CMakeLists.txt +++ b/core/loground/CMakeLists.txt @@ -1,9 +1,14 @@ add_library(loground base.c island.c - misc.c pool.c ) +target_benum_sources(loground + type.h +) +target_crial_sources(loground + base.crial +) target_link_libraries(loground msgpackc diff --git a/core/loground/base.c b/core/loground/base.c index b2a84ea..7071a86 100644 --- a/core/loground/base.c +++ b/core/loground/base.c @@ -18,16 +18,15 @@ #include "core/loshader/ground.h" #include "./island.h" -#include "./misc.h" +#include "./type.h" -#define LOGROUND_BASE_PARAM_TO_PACK_EACH_(PROC, PROC_str, PROC_type) do { \ - PROC_str ("subclass", "ground"); \ - PROC_type ("type", type); \ - PROC ("id", super.super.id); \ - PROC ("pos", super.super.pos); \ - PROC ("size", super.size); \ -} while (0) -#define LOGROUND_BASE_PARAM_TO_PACK_COUNT 5 +/* generated serializer */ +#include "core/loground/crial/base.h" + +static bool +(*const update_function_vtable_[LOGROUND_TYPE_COUNT])(loground_base_t* base) = { + [LOGROUND_TYPE_ISLAND] = loground_island_update, +}; static void loground_base_delete_(loentity_t* entity) { assert(entity != NULL); @@ -36,18 +35,6 @@ static void loground_base_delete_(loentity_t* entity) { if (!base->used) return; base->used = false; - -# define each_(NAME, name) do { \ - if (base->type == LOGROUND_TYPE_##NAME) { \ - loground_##name##_tear_down(base); \ - return; \ - } \ - } while (0) - - LOGROUND_TYPE_EACH_(each_); - assert(false); - -# undef each_ } static void loground_base_die_(loentity_t* entity) { @@ -61,16 +48,8 @@ static bool loground_base_update_(loentity_t* entity) { loground_base_t* base = (typeof(base)) entity; base->cache = (typeof(base->cache)) {0}; -# define each_(NAME, name) do { \ - if (base->type == LOGROUND_TYPE_##NAME) { \ - return loground_##name##_update(base); \ - } \ - } while (0) - - LOGROUND_TYPE_EACH_(each_); - return false; - -# undef each_ + assert(update_function_vtable_[base->param.type] != NULL); + return update_function_vtable_[base->param.type](base); } static void loground_base_draw_( @@ -94,40 +73,8 @@ static void loground_base_pack_( const loground_base_t* base = (typeof(base)) entity; - msgpack_pack_map(packer, LOGROUND_BASE_PARAM_TO_PACK_COUNT+1); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &base->var); \ - } while (0) -# define pack_str_(name, str) do { \ - mpkutil_pack_str(packer, name); \ - mpkutil_pack_str(packer, str); \ - } while (0) -# define pack_type_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - mpkutil_pack_str(packer, loground_type_stringify(base->var)); \ - } while (0) - - - LOGROUND_BASE_PARAM_TO_PACK_EACH_(pack_, pack_str_, pack_type_); - -# undef pack_type_ -# undef pack_str_ -# undef pack_ - -# define each_(NAME, name) do { \ - if (base->type == LOGROUND_TYPE_##NAME) { \ - loground_##name##_pack_data(base, packer); \ - return; \ - } \ - } while (0) - - mpkutil_pack_str(packer, "data"); - LOGROUND_TYPE_EACH_(each_); - assert(false); - -# undef each_ + msgpack_pack_map(packer, CRIAL_PROPERTY_COUNT_); + CRIAL_SERIALIZER_; } void loground_base_initialize( @@ -136,93 +83,48 @@ void loground_base_initialize( assert(drawer != NULL); *base = (typeof(*base)) { - .super = { - .super = { - .vtable = { - .delete = loground_base_delete_, - .die = loground_base_die_, - .update = loground_base_update_, - .draw = loground_base_draw_, - .pack = loground_base_pack_, - }, - .subclass = LOENTITY_SUBCLASS_GROUND, - }, - }, .drawer = drawer, }; } void loground_base_reinitialize(loground_base_t* base, loentity_id_t id) { assert(base != NULL); + assert(!base->used); -# define reset_(name, var) do { \ - base->var = (typeof(base->var)) {0}; \ - } while (0) -# define reset_str_(name, str) - - LOGROUND_BASE_PARAM_TO_PACK_EACH_(reset_, reset_str_, reset_); - -# undef reset_str_ -# undef reset_ - - base->super.super.id = id; + base->super = (typeof(base->super)) { + .super = { + .vtable = { + .delete = loground_base_delete_, + .die = loground_base_die_, + .update = loground_base_update_, + .draw = loground_base_draw_, + .pack = loground_base_pack_, + }, + .id = id, + .subclass = LOENTITY_SUBCLASS_GROUND, + }, + }; + base->param = (typeof(base->param)) {0}; } void loground_base_deinitialize(loground_base_t* base) { assert(base != NULL); + assert(!base->used); - loground_base_delete_(&base->super.super); } bool loground_base_unpack(loground_base_t* base, const msgpack_object *obj) { assert(base != NULL); assert(obj != NULL); - loground_base_reinitialize(base, 0); - /* id will be overwritten below */ - - const char* v; - size_t vlen; + loground_base_reinitialize(base, 0); /* id will be overwritten */ const msgpack_object_map* root = mpkutil_get_map(obj); + if (root == NULL) goto FAIL; + CRIAL_DESERIALIZER_; + return true; -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &base->var)) { \ - return NULL; \ - } \ - } while (0) -# define unpack_type_(name, var) do { \ - if (!mpkutil_get_str(item_(name), &v, &vlen) || \ - !loground_type_unstringify(&base->var, v, vlen)) { \ - return NULL; \ - } \ - } while (0) -# define unpack_str_(name, str) do { \ - if (!mpkutil_get_str(item_(name), &v, &vlen) || \ - !(strncmp(v, str, vlen) == 0 && str[vlen] == 0)) { \ - return NULL; \ - } \ - } while (0) - - LOGROUND_BASE_PARAM_TO_PACK_EACH_(unpack_, unpack_str_, unpack_type_); - -# undef unpack_str_ -# undef unpack_type_ -# undef unpack_ - - const msgpack_object* data = item_("data"); -# define each_(NAME, name) do { \ - if (base->type == LOGROUND_TYPE_##NAME) { \ - return loground_##name##_unpack_data(base, data); \ - } \ - } while (0) - - LOGROUND_TYPE_EACH_(each_); +FAIL: + loground_base_delete_(&base->super.super); return false; - -# undef each_ - -# undef item_ } diff --git a/core/loground/base.crial b/core/loground/base.crial new file mode 100644 index 0000000..a40b3ed --- /dev/null +++ b/core/loground/base.crial @@ -0,0 +1,31 @@ +/* CRIAL + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + mpkutil_pack_str(packer, $code); + END + DESERIALIZER_BEGIN + const char* v; + size_t vlen; + if (!mpkutil_get_str( + mpkutil_get_map_item_by_str(root, "$name"), &v, &vlen) || + strncmp(v, $code, vlen) != 0 || $code[vlen] != 0) { + goto FAIL; + } + END + PROPERTY subclass = "ground" + + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + LOCOMMON_MSGPACK_PACK_ANY(packer, &base->$code); + END + DESERIALIZER_BEGIN + if (!LOCOMMON_MSGPACK_UNPACK_ANY( + mpkutil_get_map_item_by_str(root, "$name"), &base->$code)) { + goto FAIL; + } + END + PROPERTY id = super.super.id + PROPERTY pos = super.super.pos + PROPERTY size = super.size + PROPERTY type = param.type +*/ diff --git a/core/loground/base.h b/core/loground/base.h index 8353174..964dce3 100644 --- a/core/loground/base.h +++ b/core/loground/base.h @@ -9,25 +9,21 @@ #include "core/loentity/ground.h" #include "core/loshader/ground.h" -#include "./misc.h" +#include "./type.h" typedef struct { loentity_ground_t super; bool used; - /* injected deps */ loshader_ground_drawer_t* drawer; - /* params not to be packed */ + struct { + loground_type_t type; + } param; + struct { loshader_ground_drawer_instance_t instance; } cache; - - /* params to be packed (includes id, pos, and size) */ - loground_type_t type; - -# define LOGROUND_BASE_DATA_MAX_SIZE 256 - uint8_t data[LOGROUND_BASE_DATA_MAX_SIZE]; } loground_base_t; void diff --git a/core/loground/island.c b/core/loground/island.c index f814afe..a41f09b 100644 --- a/core/loground/island.c +++ b/core/loground/island.c @@ -7,7 +7,7 @@ #include "core/locommon/position.h" #include "./base.h" -#include "./misc.h" +#include "./type.h" bool loground_island_update(loground_base_t* base) { assert(base != NULL); @@ -28,7 +28,9 @@ void loground_island_build( assert(vec2_valid(size)); assert(size->x >= 0 && size->y >= 0); - base->type = LOGROUND_TYPE_ISLAND; + base->param = (typeof(base->param)) { + .type = LOGROUND_TYPE_ISLAND, + }; base->super.super.pos = *pos; base->super.size = *size; diff --git a/core/loground/island.h b/core/loground/island.h index 43cce41..0568c31 100644 --- a/core/loground/island.h +++ b/core/loground/island.h @@ -2,8 +2,6 @@ #include -#include - #include "util/math/vector.h" #include "core/locommon/position.h" @@ -21,11 +19,3 @@ loground_island_build( const locommon_position_t* pos, const vec2_t* size ); - -#define loground_island_tear_down(base) - -#define loground_island_pack_data(base, packer) \ - msgpack_pack_nil(packer) - -#define loground_island_unpack_data(base, obj) \ - (obj != NULL) diff --git a/core/loground/misc.h b/core/loground/misc.h deleted file mode 100644 index d839899..0000000 --- a/core/loground/misc.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include - -/* dont forget to update EACH macro */ -typedef enum { - LOGROUND_TYPE_ISLAND, -} loground_type_t; - -#define LOGROUND_TYPE_EACH_(PROC) do { \ - PROC(ISLAND, island); \ -} while (0) - -const char* -loground_type_stringify( - loground_type_t type -); - -bool -loground_type_unstringify( - loground_type_t* type, - const char* v, - size_t len -); diff --git a/core/loground/pool.c b/core/loground/pool.c index e704444..a755872 100644 --- a/core/loground/pool.c +++ b/core/loground/pool.c @@ -10,28 +10,12 @@ #include "util/memory/memory.h" #include "core/locommon/counter.h" +#include "core/loentity/pool.h" #include "core/loshader/ground.h" #include "./base.h" -struct loground_pool_t { - loshader_ground_drawer_t* drawer; - locommon_counter_t* idgen; - - size_t length; - loground_base_t items[1]; -}; - -static size_t loground_pool_find_unused_item_index_( - const loground_pool_t* pool) { - assert(pool != NULL); - - for (size_t i = 0; i < pool->length; ++i) { - if (!pool->items[i].used) return i; - } - fprintf(stderr, "ground pool overflow\n"); - abort(); -} +LOENTITY_POOL_SOURCE_TEMPLATE(loground) loground_pool_t* loground_pool_new( loshader_ground_drawer_t* drawer, @@ -44,7 +28,6 @@ loground_pool_t* loground_pool_new( loground_pool_t* pool = memory_new( sizeof(*pool) + (length-1)*sizeof(pool->items[0])); *pool = (typeof(*pool)) { - .drawer = drawer, .idgen = idgen, .length = length, }; @@ -54,36 +37,3 @@ loground_pool_t* loground_pool_new( } return pool; } - -void loground_pool_delete(loground_pool_t* pool) { - assert(pool != NULL); - - for (size_t i = 0; i < pool->length; ++i) { - loground_base_deinitialize(&pool->items[i]); - } - memory_delete(pool); -} - -loground_base_t* loground_pool_create(loground_pool_t* pool) { - assert(pool != NULL); - - const size_t i = loground_pool_find_unused_item_index_(pool); - - loground_base_reinitialize( - &pool->items[i], locommon_counter_count(pool->idgen)); - - pool->items[i].used = true; - return &pool->items[i]; -} - -loground_base_t* loground_pool_unpack_item( - loground_pool_t* pool, const msgpack_object* obj) { - assert(pool != NULL); - - const size_t i = loground_pool_find_unused_item_index_(pool); - - if (!loground_base_unpack(&pool->items[i], obj)) return NULL; - - pool->items[i].used = true; - return &pool->items[i]; -} diff --git a/core/loground/type.h b/core/loground/type.h new file mode 100644 index 0000000..ad7b4e5 --- /dev/null +++ b/core/loground/type.h @@ -0,0 +1,10 @@ +#pragma once + +typedef enum { + /* BENUM BEGIN loground_type */ + LOGROUND_TYPE_ISLAND, + /* BENUM END */ +} loground_type_t; + +/* generated benum header */ +#include "core/loground/benum/type.h" diff --git a/core/loparticle/CMakeLists.txt b/core/loparticle/CMakeLists.txt new file mode 100644 index 0000000..765d374 --- /dev/null +++ b/core/loparticle/CMakeLists.txt @@ -0,0 +1,19 @@ +add_library(loparticle + aura.c + base.c + misc.c + pool.c +) +target_crial_sources(loparticle + aura.crial + base.crial +) +target_link_libraries(loparticle + msgpackc + + mpkutil + + locommon + loentity + loshader +) diff --git a/core/loparticle/aura.c b/core/loparticle/aura.c new file mode 100644 index 0000000..352391d --- /dev/null +++ b/core/loparticle/aura.c @@ -0,0 +1,66 @@ +#include "./aura.h" + +#include +#include + +#include + +#include "util/mpkutil/get.h" +#include "util/mpkutil/pack.h" + +#include "core/locommon/msgpack.h" +#include "core/loentity/entity.h" + +#include "./base.h" + +/* generated serializer */ +#include "core/loparticle/crial/aura.h" + +_Static_assert( + sizeof(loparticle_aura_param_t) <= LOPARTICLE_BASE_DATA_MAX_SIZE, + "data size overflow"); + +bool loparticle_aura_param_valid(const loparticle_aura_param_t* param) { + return param != NULL; +} + +void loparticle_aura_param_pack( + const loparticle_aura_param_t* param, msgpack_packer* packer) { + assert(param != NULL); + assert(packer != NULL); + + msgpack_pack_map(packer, CRIAL_PROPERTY_COUNT_); + + CRIAL_SERIALIZER_; +} + +bool loparticle_aura_param_unpack( + loparticle_aura_param_t* param, const msgpack_object* obj) { + assert(param != NULL); + + const msgpack_object_map* root = mpkutil_get_map(obj); + if (root == NULL) return false; + + CRIAL_DESERIALIZER_; + + return loparticle_aura_param_valid(param); +} + +void loparticle_aura_build( + loparticle_base_t* base, + loparticle_type_t type, + const loparticle_aura_param_t* param) { + assert(base != NULL); + assert(param != NULL); + + base->type = type; + *((loparticle_aura_param_t*) base->data) = *param; +} + +bool loparticle_aura_guard_update(loparticle_base_t* base) { + assert(base != NULL); + + /* TODO(catfoot): */ + + return true; +} diff --git a/core/loparticle/aura.crial b/core/loparticle/aura.crial new file mode 100644 index 0000000..e3e540e --- /dev/null +++ b/core/loparticle/aura.crial @@ -0,0 +1,13 @@ +/* CRIAL + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + LOCOMMON_MSGPACK_PACK_ANY(packer, ¶m->$code); + END + DESERIALIZER_BEGIN + if (!LOCOMMON_MSGPACK_UNPACK_ANY( + mpkutil_get_map_item_by_str(root, "$name"), ¶m->$code)) { + return false; + } + END + PROPERTY target +*/ diff --git a/core/loparticle/aura.h b/core/loparticle/aura.h new file mode 100644 index 0000000..1224e78 --- /dev/null +++ b/core/loparticle/aura.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include + +#include "core/loentity/entity.h" + +#include "./base.h" + +typedef struct { + loentity_id_t target; +} loparticle_aura_param_t; + +bool +loparticle_aura_valid( + const loparticle_aura_param_t* param +); + +void +loparticle_aura_param_pack( + const loparticle_aura_param_t* param, + msgpack_packer* packer +); + +bool +loparticle_aura_param_unpack( + loparticle_aura_param_t* param, + const msgpack_object* obj +); + +void +loparticle_aura_build( + loparticle_base_t* base, + loparticle_type_t type, + const loparticle_aura_param_t* param +); + +bool +loparticle_aura_guard_update( + loparticle_base_t* base +); +#define loparticle_aura_guard_build(base, param) \ + loparticle_aura_build(base, LOPARTICLE_TYPE_AURA_GUARD, param) +#define loparticle_aura_guard_tear_down(base) +#define loparticle_aura_guard_pack_data(base, packer) \ + loparticle_aura_param_pack( \ + (const loparticle_aura_param_t*) base->data, packer) +#define loparticle_aura_guard_unpack_data(base, obj) \ + loparticle_aura_param_unpack( \ + (loparticle_aura_param_t*) base->data, obj) diff --git a/core/loparticle/base.c b/core/loparticle/base.c new file mode 100644 index 0000000..976faba --- /dev/null +++ b/core/loparticle/base.c @@ -0,0 +1,165 @@ +#include "./base.h" + +#include +#include + +#include + +#include "util/mpkutil/get.h" +#include "util/mpkutil/pack.h" + +#include "core/locommon/msgpack.h" +#include "core/locommon/ticker.h" +#include "core/loentity/entity.h" +#include "core/loentity/store.h" +#include "core/loshader/particle.h" + +#include "./aura.h" +#include "./misc.h" + +/* generated serializer */ +#include "core/loparticle/crial/base.h" + +static void loparticle_base_delete_(loentity_t* entity) { + assert(entity != NULL); + + loparticle_base_t* base = (typeof(base)) entity; + if (!base->used) return; + + base->used = false; + +# define each_(NAME, name) do { \ + if (base->type == LOPARTICLE_TYPE_##NAME) { \ + loparticle_##name##_tear_down(base); \ + return; \ + } \ + } while (0) + + LOPARTICLE_TYPE_EACH_(each_); + assert(false); + +# undef each_ +} + +static void loparticle_base_die_(loentity_t* entity) { + assert(entity != NULL); +} + +static bool loparticle_base_update_(loentity_t* entity) { + assert(entity != NULL); + + loparticle_base_t* base = (typeof(base)) entity; + base->cache = (typeof(base->cache)) {0}; + +# define each_(NAME, name) do { \ + if (base->type == LOPARTICLE_TYPE_##NAME) { \ + return loparticle_##name##_update(base); \ + } \ + } while (0) + + LOPARTICLE_TYPE_EACH_(each_); + return false; + +# undef each_ +} + +static void loparticle_base_draw_( + loentity_t* entity, const locommon_position_t* basepos) { + assert(entity != NULL); + assert(basepos != NULL); + + loparticle_base_t* base = (typeof(base)) entity; + + vec2_t p; + locommon_position_sub(&p, &base->super.pos, basepos); + vec2_addeq(&base->cache.instance.pos, &p); + + loshader_particle_drawer_add_instance(base->drawer, &base->cache.instance); +} + +static void loparticle_base_pack_( + const loentity_t* entity, msgpack_packer* packer) { + assert(entity != NULL); + assert(packer != NULL); + + const loparticle_base_t* base = (typeof(base)) entity; + + msgpack_pack_map(packer, CRIAL_PROPERTY_COUNT_+1); + + CRIAL_SERIALIZER_; + + mpkutil_pack_str(packer, "data"); +# define each_(NAME, name) do { \ + if (base->type == LOPARTICLE_TYPE_##NAME) { \ + loparticle_##name##_pack_data(base, packer); \ + return; \ + } \ + } while (0) + + LOPARTICLE_TYPE_EACH_(each_); + assert(false); + +# undef each_ +} + +void loparticle_base_initialize( + loparticle_base_t* base, + loshader_particle_drawer_t* drawer, + const locommon_ticker_t* ticker, + loentity_store_t* entities) { + assert(base != NULL); + assert(drawer != NULL); + assert(ticker != NULL); + assert(entities != NULL); + + *base = (typeof(*base)) { + .super = { + .vtable = { + .delete = loparticle_base_delete_, + .die = loparticle_base_die_, + .update = loparticle_base_update_, + .draw = loparticle_base_draw_, + .pack = loparticle_base_pack_, + }, + .subclass = LOENTITY_SUBCLASS_PARTICLE, + }, + .drawer = drawer, + .ticker = ticker, + .entities = entities, + }; +} + +void loparticle_base_reinitialize(loparticle_base_t* base, loentity_id_t id) { + assert(base != NULL); + + base->super.id = id; +} + +void loparticle_base_deinitialize(loparticle_base_t* base) { + assert(base != NULL); + + loparticle_base_delete_(&base->super); +} + +bool loparticle_base_unpack( + loparticle_base_t* base, const msgpack_object* obj) { + assert(base != NULL); + + loparticle_base_reinitialize(base, 0); + + const msgpack_object_map* root = mpkutil_get_map(obj); + + CRIAL_DESERIALIZER_; + + const msgpack_object* data = mpkutil_get_map_item_by_str(root, "data"); +# define each_(NAME, name) do { \ + if (base->type == LOPARTICLE_TYPE_##NAME) { \ + if (!loparticle_##name##_unpack_data(base, data)) return false; \ + } \ + } while (0) + + LOPARTICLE_TYPE_EACH_(each_); + return true; + +# undef each_ +} diff --git a/core/loparticle/base.crial b/core/loparticle/base.crial new file mode 100644 index 0000000..93bf168 --- /dev/null +++ b/core/loparticle/base.crial @@ -0,0 +1,31 @@ +/* CRIAL + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + mpkutil_pack_str(packer, $code); + END + DESERIALIZER_BEGIN + const char* v; + size_t vlen; + if (!mpkutil_get_str( + mpkutil_get_map_item_by_str(root, "$name"), &v, &vlen) || + strncmp(v, $code, vlen) != 0 || $code[vlen] != 0) { + return false; + } + END + PROPERTY subclass = "particle" + + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + LOCOMMON_MSGPACK_PACK_ANY(packer, &base->$code); + END + DESERIALIZER_BEGIN + if (!LOCOMMON_MSGPACK_UNPACK_ANY( + mpkutil_get_map_item_by_str(root, "$name"), &base->$code)) { + return false; + } + END + PROPERTY type + PROPERTY id = super.id + + # data property is serialized manually (plz see pack/unpack function) +*/ diff --git a/core/loparticle/base.h b/core/loparticle/base.h new file mode 100644 index 0000000..d64c70f --- /dev/null +++ b/core/loparticle/base.h @@ -0,0 +1,59 @@ +#pragma once + +#include + +#include + +#include "core/locommon/ticker.h" +#include "core/loentity/entity.h" +#include "core/loentity/store.h" +#include "core/loshader/particle.h" + +#include "./misc.h" + +typedef struct { + loentity_t super; + bool used; + + /* injected deps */ + loshader_particle_drawer_t* drawer; + const locommon_ticker_t* ticker; + loentity_store_t* entities; + + /* params not to be packed */ + struct { + loshader_particle_drawer_instance_t instance; + } cache; + + /* params to be packed */ + loparticle_type_t type; + +# define LOPARTICLE_BASE_DATA_MAX_SIZE 256 + uint8_t data[LOPARTICLE_BASE_DATA_MAX_SIZE]; + /* pack function for the type is used */ +} loparticle_base_t; + +void +loparticle_base_initialize( + loparticle_base_t* base, + loshader_particle_drawer_t* drawer, + const locommon_ticker_t* ticker, + loentity_store_t* entities +); + +void +loparticle_base_reinitialize( + loparticle_base_t* base, + loentity_id_t id +); + +void +loparticle_base_deinitialize( + loparticle_base_t* base +); + +bool +loparticle_base_unpack( + loparticle_base_t* base, + const msgpack_object* obj +); diff --git a/core/loground/misc.c b/core/loparticle/misc.c similarity index 57% rename from core/loground/misc.c rename to core/loparticle/misc.c index 1d990bd..550933b 100644 --- a/core/loground/misc.c +++ b/core/loparticle/misc.c @@ -5,32 +5,32 @@ #include #include -const char* loground_type_stringify(loground_type_t type) { +const char* loparticle_type_stringify(loparticle_type_t type) { # define each_(NAME, name) do { \ - if (type == LOGROUND_TYPE_##NAME) return #name; \ + if (type == LOPARTICLE_TYPE_##NAME) return #name; \ } while (0) - LOGROUND_TYPE_EACH_(each_); + LOPARTICLE_TYPE_EACH_(each_); + +# undef each_ assert(false); return NULL; - -# undef each_ } -bool loground_type_unstringify( - loground_type_t* type, const char* v, size_t len) { +bool loparticle_type_unstringify( + loparticle_type_t* type, const char* v, size_t len) { assert(type != NULL); assert(v != NULL || len == 0); # define each_(NAME, name) do { \ if (strncmp(v, #name, len) == 0 && #name[len] == 0) { \ - *type = LOGROUND_TYPE_##NAME; \ + *type = LOPARTICLE_TYPE_##NAME; \ return true; \ } \ } while (0) - LOGROUND_TYPE_EACH_(each_); + LOPARTICLE_TYPE_EACH_(each_); return false; # undef each_ diff --git a/core/loparticle/misc.h b/core/loparticle/misc.h new file mode 100644 index 0000000..c60846e --- /dev/null +++ b/core/loparticle/misc.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +/* don't forget to update EACH macro */ +typedef enum { + LOPARTICLE_TYPE_AURA_GUARD, +} loparticle_type_t; + +#define LOPARTICLE_TYPE_EACH_(PROC) do { \ + PROC(AURA_GUARD, aura_guard); \ +} while (0) + +const char* +loparticle_type_stringify( + loparticle_type_t type +); + +bool +loparticle_type_unstringify( + loparticle_type_t* type, + const char* v, + size_t len +); diff --git a/core/loparticle/pool.c b/core/loparticle/pool.c new file mode 100644 index 0000000..ac690b9 --- /dev/null +++ b/core/loparticle/pool.c @@ -0,0 +1,45 @@ +#include "./pool.h" + +#include + +#include + +#include "util/memory/memory.h" + +#include "core/locommon/counter.h" +#include "core/locommon/ticker.h" +#include "core/loentity/pool.h" +#include "core/loentity/store.h" +#include "core/loshader/particle.h" + +#include "./base.h" + +LOENTITY_POOL_SOURCE_TEMPLATE(loparticle) + +loparticle_pool_t* loparticle_pool_new( + loshader_particle_drawer_t* drawer, + locommon_counter_t* idgen, + const locommon_ticker_t* ticker, + loentity_store_t* entities, + size_t length) { + assert(drawer != NULL); + assert(idgen != NULL); + assert(ticker != NULL); + assert(entities != NULL); + assert(length > 0); + + loparticle_pool_t* pool = + memory_new(sizeof(*pool) + (length-1)*sizeof(pool->items[0])); + *pool = (typeof(*pool)) { + .idgen = idgen, + .length = length, + }; + for (size_t i = 0; i < pool->length; ++i) { + loparticle_base_initialize( + &pool->items[i], + drawer, + ticker, + entities); + } + return pool; +} diff --git a/core/loparticle/pool.h b/core/loparticle/pool.h new file mode 100644 index 0000000..ce20fba --- /dev/null +++ b/core/loparticle/pool.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include + +#include "core/locommon/counter.h" +#include "core/locommon/ticker.h" +#include "core/loentity/store.h" +#include "core/loshader/particle.h" + +#include "./base.h" + +struct loparticle_pool_t; +typedef struct loparticle_pool_t loparticle_pool_t; + +loparticle_pool_t* /* OWNERSHIP */ +loparticle_pool_new( + loshader_particle_drawer_t* drawer, + locommon_counter_t* idgen, + const locommon_ticker_t* ticker, + loentity_store_t* entities, + size_t length +); + +void +loparticle_pool_delete( + loparticle_pool_t* pool /* OWNERSHIP */ +); + +loparticle_base_t* +loparticle_pool_create( + loparticle_pool_t* pool +); + +loparticle_base_t* +loparticle_pool_unpack_item( + loparticle_pool_t* pool, + const msgpack_object* obj +); diff --git a/core/loplayer/CMakeLists.txt b/core/loplayer/CMakeLists.txt index 0a5b3f6..3f7b7a3 100644 --- a/core/loplayer/CMakeLists.txt +++ b/core/loplayer/CMakeLists.txt @@ -1,28 +1,26 @@ add_library(loplayer - action.c camera.c combat.c controller.c - entity.c event.c - hud.c - menu.c player.c - status.c + popup.c + stance.c +) +target_benum_sources(loplayer + stance.h +) +target_crial_sources(loplayer + event.crial + player.crial ) target_link_libraries(loplayer msgpackc - conv - glyphas math - memory mpkutil - lobullet locommon - loeffect loentity - loresource loshader ) diff --git a/core/loplayer/action.c b/core/loplayer/action.c deleted file mode 100644 index 1f1baea..0000000 --- a/core/loplayer/action.c +++ /dev/null @@ -1,880 +0,0 @@ -#include "./action.h" - -#include -#include -#include -#include -#include - -#include - -#include "util/math/algorithm.h" -#include "util/memory/memory.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" - -#include "core/lobullet/base.h" -#include "core/lobullet/linear.h" -#include "core/lobullet/pool.h" -#include "core/locommon/easing.h" -#include "core/locommon/ticker.h" -#include "core/loeffect/effect.h" -#include "core/loeffect/stance.h" -#include "core/loentity/store.h" -#include "core/loresource/set.h" -#include "core/loresource/sound.h" -#include "core/loresource/text.h" - -#include "./camera.h" -#include "./combat.h" -#include "./controller.h" -#include "./entity.h" -#include "./event.h" -#include "./hud.h" -#include "./menu.h" -#include "./status.h" - -struct loplayer_action_t { - loresource_set_t* res; - const locommon_ticker_t* ticker; - lobullet_pool_t* bullets; - loentity_store_t* entities; - - loplayer_event_t* event; - loplayer_status_t* status; - loplayer_entity_t* entity; - const loplayer_controller_t* controller; - loplayer_combat_t* combat; - loplayer_camera_t* camera; - loplayer_hud_t* hud; - loplayer_menu_t* menu; - - union { - struct { - } stand; - struct { - float direction; - } moving; - struct { - float direction; - } dodge; - struct { - } combat; - struct { - } shoot; - struct { - } dead; - struct { - bool invincible; - } menu; - } state; - uint64_t since; - - void - (*execute)( - loplayer_action_t* action - ); - void - (*pack)( - const loplayer_action_t* action, - msgpack_packer* packer - ); -}; - -#define LOPLAYER_ACTION_STATE_EACH_(PROC) do { \ - PROC(stand); \ - PROC(moving); \ - PROC(dodge); \ - PROC(combat); \ - PROC(shoot); \ - PROC(dead); \ - PROC(menu); \ -} while (0) - -static void -loplayer_action_start_stand_state_( - loplayer_action_t* action -); -static void -loplayer_action_start_moving_state_( - loplayer_action_t* action, - float direction -); -static void -loplayer_action_start_dodge_state_( - loplayer_action_t* action, - float direction -); -static void -loplayer_action_start_combat_state_( - loplayer_action_t* action -); -static bool -loplayer_action_start_shoot_state_( - loplayer_action_t* action -); -static void -loplayer_action_start_dead_state_( - loplayer_action_t* action -); -static void -loplayer_action_start_menu_state_( - loplayer_action_t* action, - bool invincible -); - -static void loplayer_action_affect_bullet_(loplayer_action_t* action) { - assert(action != NULL); - - if (action->status->bullet_immune_until > action->ticker->time) { - return; - } - if (loplayer_entity_affect_bullet(action->entity)) { - action->status->bullet_immune_until = action->ticker->time + 200; - } -} -static bool loplayer_action_shoot_bullet_(loplayer_action_t* action) { - assert(action != NULL); - - static const float consume = .05f; - - float* f = &action->status->recipient.faith; - if (*f <= 0) return false; - - vec2_t v; - locommon_position_sub( - &v, &action->controller->looking, &action->entity->super.super.pos); - const float vlen = vec2_length(&v); - if (vlen == 0) { - v = vec2(action->entity->direction, 0); - } else { - vec2_diveq(&v, vec2_length(&v)); - } - - /* TODO(catfoot): diffusion */ - vec2_muleq(&v, 1.f); - vec2_addeq(&v, &action->entity->last_velocity); - - lobullet_base_t* b = lobullet_pool_create(action->bullets); - lobullet_linear_light_build(b, (&(lobullet_linear_param_t) { - .owner = action->entity->super.super.id, - .pos = action->entity->super.super.pos, - .size = vec2(.015f, .015f), - .velocity = v, - .acceleration = vec2(0, -.1f), - .color = vec4(.8f, .8f, .8f, .8f), - .duration = 2000, - .knockback = .1f, - .effect = loeffect_immediate_damage( - action->status->recipient.status.attack/2), - })); - loentity_store_add(action->entities, &b->super.super); - - *f -= consume; - if (*f < 0) *f = 0; - return true; -} - -static void loplayer_action_show_tutorial_after_death_(loplayer_action_t* action) { - assert(action != NULL); - -# define text_(name) loresource_text_get(action->res->lang, name) -# define popup_(name) \ - loplayer_menu_popup( \ - action->menu, \ - text_("tutorial_title_"name), \ - text_("tutorial_text_" name)) - - switch (action->status->recipient.last_damage) { - case LOEFFECT_ID_IMMEDIATE_DAMAGE: - popup_("dead_by_combat"); - break; - case LOEFFECT_ID_CURSE: - popup_("dead_by_curse"); - break; - case LOEFFECT_ID_LOST: - popup_("dead_by_lost"); - break; - default: - return; - } - -# undef popup_ -# undef text_ - - loplayer_action_start_menu_popup_state(action); -} - -static void loplayer_action_execute_stand_state_(loplayer_action_t* action) { - assert(action != NULL); - - const float max_acceleration_ = action->entity->on_ground? 2.0f: 0.5f; - - loplayer_entity_aim(action->entity, &action->controller->looking); - - if (action->status->recipient.madness <= 0) { - loplayer_action_start_dead_state_(action); - return; - } - - loplayer_action_affect_bullet_(action); - if (loplayer_combat_accept_all_attacks(action->combat)) { - loplayer_action_start_combat_state_(action); - return; - } - - switch (action->controller->action) { - case LOPLAYER_CONTROLLER_ACTION_NONE: - break; - case LOPLAYER_CONTROLLER_ACTION_ATTACK: - if (loplayer_action_start_shoot_state_(action)) return; - break; - case LOPLAYER_CONTROLLER_ACTION_DODGE: - loplayer_action_start_dodge_state_(action, action->entity->direction); - return; - case LOPLAYER_CONTROLLER_ACTION_GUARD: - break; - case LOPLAYER_CONTROLLER_ACTION_UNGUARD: - break; - case LOPLAYER_CONTROLLER_ACTION_MENU: - if (action->entity->movement.x == 0) { - loplayer_menu_show_status(action->menu); - loplayer_action_start_menu_state_(action, false /* INVINCIBLE */); - return; - } - break; - } - - switch (action->controller->movement) { - case LOPLAYER_CONTROLLER_MOVEMENT_NONE: - break; - case LOPLAYER_CONTROLLER_MOVEMENT_JUMP: - if (action->entity->on_ground) { - action->entity->gravity += action->status->recipient.status.jump; - } - break; - case LOPLAYER_CONTROLLER_MOVEMENT_WALK_LEFT: - case LOPLAYER_CONTROLLER_MOVEMENT_DASH_LEFT: - loplayer_action_start_moving_state_(action, -1); - return; - case LOPLAYER_CONTROLLER_MOVEMENT_WALK_RIGHT: - case LOPLAYER_CONTROLLER_MOVEMENT_DASH_RIGHT: - loplayer_action_start_moving_state_(action, 1); - return; - } - - const float t = (action->ticker->time - action->since)%2000/1000.0f - 1; - action->entity->motion.time = t*t*(3-2*MATH_ABS(t)); - action->entity->motion.from = LOSHADER_CHARACTER_MOTION_ID_STAND1; - action->entity->motion.to = LOSHADER_CHARACTER_MOTION_ID_STAND2; - - locommon_easing_linear_float( - &action->entity->movement.x, - 0, - max_acceleration_ * action->ticker->delta_f); -} -static void loplayer_action_pack_stand_state_( - const loplayer_action_t* action, msgpack_packer* packer) { - assert(action != NULL); - - msgpack_pack_map(packer, 1); - - mpkutil_pack_str(packer, "name"); - mpkutil_pack_str(packer, "stand"); -} -static bool loplayer_action_unpack_stand_state_( - loplayer_action_t* action, const msgpack_object_map* root) { - assert(action != NULL); - - return root != NULL; -} -static void loplayer_action_start_stand_state_(loplayer_action_t* action) { - assert(action != NULL); - - action->since = action->ticker->time; - action->execute = loplayer_action_execute_stand_state_; - action->pack = loplayer_action_pack_stand_state_; - - action->camera->state = LOPLAYER_CAMERA_STATE_DEFAULT; - loplayer_hud_show(action->hud); -} - -static void loplayer_action_execute_moving_state_(loplayer_action_t* action) { - assert(action != NULL); - - static const float backwalk_attenuation_ = 0.8f; - static const float dash_speed_ = 1.4f; - - const float max_acceleration_ = action->entity->on_ground? 2.4f: 0.8f; - - const float dir = action->state.moving.direction; - - loplayer_entity_aim(action->entity, &action->controller->looking); - - if (action->status->recipient.madness <= 0) { - loplayer_action_start_dead_state_(action); - return; - } - - loplayer_action_affect_bullet_(action); - if (loplayer_combat_accept_all_attacks(action->combat)) { - loplayer_action_start_combat_state_(action); - return; - } - - switch (action->controller->action) { - case LOPLAYER_CONTROLLER_ACTION_NONE: - break; - case LOPLAYER_CONTROLLER_ACTION_ATTACK: - if (loplayer_action_start_shoot_state_(action)) return; - break; - case LOPLAYER_CONTROLLER_ACTION_DODGE: - loplayer_action_start_dodge_state_(action, dir); - return; - case LOPLAYER_CONTROLLER_ACTION_GUARD: - break; - case LOPLAYER_CONTROLLER_ACTION_UNGUARD: - break; - case LOPLAYER_CONTROLLER_ACTION_MENU: - break; - } - - float max_speed = action->status->recipient.status.speed; - float control_dir = dir; - - switch (action->controller->movement) { - case LOPLAYER_CONTROLLER_MOVEMENT_NONE: - loplayer_action_start_stand_state_(action); - return; - case LOPLAYER_CONTROLLER_MOVEMENT_JUMP: - if (action->entity->on_ground) { - action->entity->gravity += action->status->recipient.status.jump; - } - return; - case LOPLAYER_CONTROLLER_MOVEMENT_WALK_LEFT: - control_dir = -1; - break; - case LOPLAYER_CONTROLLER_MOVEMENT_WALK_RIGHT: - control_dir = 1; - break; - case LOPLAYER_CONTROLLER_MOVEMENT_DASH_LEFT: - max_speed *= dash_speed_; - control_dir = -1; - break; - case LOPLAYER_CONTROLLER_MOVEMENT_DASH_RIGHT: - max_speed *= dash_speed_; - control_dir = 1; - break; - } - if (control_dir * dir < 0) { - loplayer_action_start_stand_state_(action); - return; - } - - if (dir * action->entity->direction < 0) { - max_speed *= backwalk_attenuation_; - } - - if (action->entity->on_ground) { - const int32_t p = 70/max_speed; - const float t = (action->ticker->time - action->since)%p*2.0f/p - 1; - action->entity->motion.time = MATH_ABS(t); - action->entity->motion.from = LOSHADER_CHARACTER_MOTION_ID_STAND1; - action->entity->motion.to = LOSHADER_CHARACTER_MOTION_ID_WALK; - } - - locommon_easing_linear_float( - &action->entity->movement.x, - max_speed*dir, - max_acceleration_ * action->ticker->delta_f); -} -static void loplayer_action_pack_moving_state_( - const loplayer_action_t* action, msgpack_packer* packer) { - assert(action != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, 2); - - mpkutil_pack_str(packer, "name"); - mpkutil_pack_str(packer, "moving"); - - mpkutil_pack_str(packer, "direction"); - msgpack_pack_double(packer, action->state.moving.direction); -} -static bool loplayer_action_unpack_moving_state_( - loplayer_action_t* action, const msgpack_object_map* root) { - assert(action != NULL); - - const msgpack_object* direction = - mpkutil_get_map_item_by_str(root, "direction"); - if (!mpkutil_get_float(direction, &action->state.moving.direction)) { - return false; - } - return true; -} -static void loplayer_action_start_moving_state_( - loplayer_action_t* action, float dir) { - assert(action != NULL); - assert(MATH_FLOAT_VALID(dir)); - - action->since = action->ticker->time; - action->execute = loplayer_action_execute_moving_state_; - action->pack = loplayer_action_pack_moving_state_; - - action->state = (typeof(action->state)) { - .moving = { - .direction = dir, - }, - }; - action->camera->state = LOPLAYER_CAMERA_STATE_DEFAULT; - loplayer_hud_show(action->hud); -} - -static void loplayer_action_execute_dodge_state_(loplayer_action_t* action) { - assert(action != NULL); - - static const uint64_t duration_ = 200; - static const float start_speed_ = 0.6f; - static const float end_speed_ = 0.1f; - - if (action->since + duration_ <= action->ticker->time) { - loplayer_combat_drop_all_attacks(action->combat); - loplayer_action_start_stand_state_(action); - return; - } - - const float dir = action->state.dodge.direction; - - vec2_t* v = &action->entity->movement; - - const float t = (action->ticker->time - action->since)*1.0f/duration_; - const float r = 1 - powf(1-t, 1.5); - v->x = (r * (start_speed_-end_speed_) + end_speed_) * dir; - v->y = 0; - - action->entity->motion.time = 1-powf(1-t, 2); - action->entity->motion.from = LOSHADER_CHARACTER_MOTION_ID_WALK; - action->entity->motion.to = LOSHADER_CHARACTER_MOTION_ID_STAND1; -} -static void loplayer_action_pack_dodge_state_( - const loplayer_action_t* action, msgpack_packer* packer) { - assert(action != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, 2); - - mpkutil_pack_str(packer, "name"); - mpkutil_pack_str(packer, "dodge"); - - mpkutil_pack_str(packer, "direction"); - msgpack_pack_double(packer, action->state.dodge.direction); -} -static bool loplayer_action_unpack_dodge_state_( - loplayer_action_t* action, const msgpack_object_map* root) { - assert(action != NULL); - - const msgpack_object* direction = - mpkutil_get_map_item_by_str(root, "direction"); - if (!mpkutil_get_float(direction, &action->state.moving.direction)) { - return false; - } - return true; -} -static void loplayer_action_start_dodge_state_( - loplayer_action_t* action, float dir) { - assert(action != NULL); - assert(MATH_FLOAT_VALID(dir)); - - action->since = action->ticker->time; - action->state = (typeof(action->state)) { - .moving = { - .direction = dir, - }, - }; - action->execute = loplayer_action_execute_dodge_state_; - action->pack = loplayer_action_pack_dodge_state_; - - action->camera->state = LOPLAYER_CAMERA_STATE_DEFAULT; - loplayer_hud_show(action->hud); - loplayer_combat_drop_all_attacks(action->combat); - - loresource_sound_play(action->res->sound, "dodge"); -} - -static void loplayer_action_execute_combat_state_(loplayer_action_t* action) { - assert(action != NULL); - - if (action->status->recipient.madness <= 0) { - loplayer_action_start_dead_state_(action); - return; - } - - loplayer_action_affect_bullet_(action); - if (!loplayer_combat_accept_all_attacks(action->combat)) { - loplayer_action_start_stand_state_(action); - return; - } - - switch (action->controller->action) { - case LOPLAYER_CONTROLLER_ACTION_NONE: - break; - case LOPLAYER_CONTROLLER_ACTION_ATTACK: - break; - case LOPLAYER_CONTROLLER_ACTION_DODGE: - loplayer_action_start_dodge_state_(action, action->entity->direction); - return; - case LOPLAYER_CONTROLLER_ACTION_GUARD: - loplayer_combat_guard(action->combat); - break; - case LOPLAYER_CONTROLLER_ACTION_UNGUARD: - loplayer_combat_unguard(action->combat); - break; - case LOPLAYER_CONTROLLER_ACTION_MENU: - break; - } - - action->entity->gravity = 0; - - const float klen = vec2_length(&action->entity->knockback); - if (klen > .1f) vec2_muleq(&action->entity->knockback, .1f/klen); -} -static void loplayer_action_pack_combat_state_( - const loplayer_action_t* action, msgpack_packer* packer) { - assert(action != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, 1); - - mpkutil_pack_str(packer, "name"); - mpkutil_pack_str(packer, "combat"); -} -static bool loplayer_action_unpack_combat_state_( - loplayer_action_t* action, const msgpack_object_map* root) { - assert(action != NULL); - - return root != NULL; -} -static void loplayer_action_start_combat_state_(loplayer_action_t* action) { - assert(action != NULL); - - action->since = action->ticker->time; - action->execute = loplayer_action_execute_combat_state_; - action->pack = loplayer_action_pack_combat_state_; - - action->entity->movement = vec2(0, 0); - - action->camera->state = LOPLAYER_CAMERA_STATE_COMBAT; - loplayer_hud_show(action->hud); -} - -static void loplayer_action_execute_shoot_state_(loplayer_action_t* action) { - assert(action != NULL); - - static const uint64_t duration = 300; - static const float max_acceleration = 1.f; - - loplayer_entity_aim(action->entity, &action->controller->looking); - - if (action->status->recipient.madness <= 0) { - loplayer_action_start_dead_state_(action); - return; - } - - loplayer_action_affect_bullet_(action); - if (loplayer_combat_accept_all_attacks(action->combat)) { - loplayer_action_start_combat_state_(action); - return; - } - - if (action->since+duration <= action->ticker->time) { - if (loplayer_action_shoot_bullet_(action)) { - loresource_sound_play(action->res->sound, "player_shoot"); - } - loplayer_action_start_stand_state_(action); - return; - } - - const float a = max_acceleration * action->ticker->delta_f; - locommon_easing_linear_float(&action->entity->movement.x, 0, a); - locommon_easing_linear_float(&action->entity->movement.y, 0, a); -} -static void loplayer_action_pack_shoot_state_( - const loplayer_action_t* action, msgpack_packer* packer) { - assert(action != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, 1); - - mpkutil_pack_str(packer, "name"); - mpkutil_pack_str(packer, "shoot"); -} -static bool loplayer_action_unpack_shoot_state_( - loplayer_action_t* action, const msgpack_object_map* root) { - assert(action != NULL); - - return root != NULL; -} -static bool loplayer_action_start_shoot_state_(loplayer_action_t* action) { - assert(action != NULL); - - if (!loeffect_stance_set_has( - &action->status->stances, LOEFFECT_STANCE_ID_REVOLUTIONER)) { - return false; - } - - action->since = action->ticker->time; - action->execute = loplayer_action_execute_shoot_state_; - action->pack = loplayer_action_pack_shoot_state_; - - action->camera->state = LOPLAYER_CAMERA_STATE_DEFAULT; - loplayer_hud_show(action->hud); - - loresource_sound_play(action->res->sound, "player_trigger"); - return true; -} - -static void loplayer_action_execute_dead_state_(loplayer_action_t* action) { - assert(action != NULL); - - static const uint64_t duration_ = 3000; - - if (action->since + duration_ <= action->ticker->time) { - loplayer_entity_move(action->entity, &action->status->respawn_pos); - loplayer_status_reset(action->status); - loplayer_combat_drop_all_attacks(action->combat); - - loplayer_action_start_stand_state_(action); - loplayer_action_show_tutorial_after_death_(action); - loplayer_event_abort(action->event); - return; - } -} -static void loplayer_action_pack_dead_state_( - const loplayer_action_t* action, msgpack_packer* packer) { - assert(action != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, 1); - - mpkutil_pack_str(packer, "name"); - mpkutil_pack_str(packer, "dead"); -} -static bool loplayer_action_unpack_dead_state_( - loplayer_action_t* action, const msgpack_object_map* root) { - assert(action != NULL); - - return root != NULL; -} -static void loplayer_action_start_dead_state_(loplayer_action_t* action) { - assert(action != NULL); - - action->since = action->ticker->time; - action->execute = loplayer_action_execute_dead_state_; - action->pack = loplayer_action_pack_dead_state_; - - action->entity->movement = vec2(0, 0); - - action->camera->state = LOPLAYER_CAMERA_STATE_DEAD; - loplayer_hud_hide(action->hud); - loplayer_combat_drop_all_attacks(action->combat); - - /* Deny all event requests. */ - loplayer_event_abort(action->event); - loplayer_event_take_control(action->event, action->entity->super.super.id); -} - -static void loplayer_action_execute_menu_state_(loplayer_action_t* action) { - assert(action != NULL); - - if (action->status->recipient.madness <= 0) { - loplayer_menu_hide(action->menu); - loplayer_action_start_dead_state_(action); - return; - } - - loplayer_action_affect_bullet_(action); - if (!action->state.menu.invincible && - loplayer_combat_accept_all_attacks(action->combat)) { - loplayer_menu_hide(action->menu); - loplayer_action_start_combat_state_(action); - return; - } - - switch (action->controller->action) { - case LOPLAYER_CONTROLLER_ACTION_NONE: - break; - case LOPLAYER_CONTROLLER_ACTION_ATTACK: - break; - case LOPLAYER_CONTROLLER_ACTION_DODGE: - break; - case LOPLAYER_CONTROLLER_ACTION_GUARD: - break; - case LOPLAYER_CONTROLLER_ACTION_UNGUARD: - break; - case LOPLAYER_CONTROLLER_ACTION_MENU: - loplayer_menu_hide(action->menu); - loplayer_action_start_stand_state_(action); - return; - } -} -static void loplayer_action_pack_menu_state_( - const loplayer_action_t* action, msgpack_packer* packer) { - assert(action != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, 2); - - mpkutil_pack_str(packer, "name"); - mpkutil_pack_str(packer, "menu"); - - mpkutil_pack_str(packer, "invincible"); - mpkutil_pack_bool(packer, action->state.menu.invincible); -} -static bool loplayer_action_unpack_menu_state_( - loplayer_action_t* action, const msgpack_object_map* root) { - assert(action != NULL); - - const msgpack_object* invincible = - mpkutil_get_map_item_by_str(root, "invincible"); - if (!mpkutil_get_bool(invincible, &action->state.menu.invincible)) { - return false; - } - return true; -} -static void loplayer_action_start_menu_state_( - loplayer_action_t* action, bool invincible) { - assert(action != NULL); - - action->since = action->ticker->time; - action->execute = loplayer_action_execute_menu_state_; - action->pack = loplayer_action_pack_menu_state_; - - action->entity->movement = vec2(0, 0); - - action->state.menu = (typeof(action->state.menu)) { - .invincible = invincible, - }; - - action->camera->state = LOPLAYER_CAMERA_STATE_MENU; -} - -loplayer_action_t* loplayer_action_new( - loresource_set_t* res, - const locommon_ticker_t* ticker, - lobullet_pool_t* bullets, - loentity_store_t* entities, - loplayer_event_t* event, - loplayer_status_t* status, - loplayer_entity_t* entity, - loplayer_combat_t* combat, - const loplayer_controller_t* controller, - loplayer_camera_t* camera, - loplayer_hud_t* hud, - loplayer_menu_t* menu) { - assert(res != NULL); - assert(ticker != NULL); - assert(bullets != NULL); - assert(entities != NULL); - assert(event != NULL); - assert(status != NULL); - assert(entity != NULL); - assert(combat != NULL); - assert(controller != NULL); - assert(camera != NULL); - assert(hud != NULL); - assert(menu != NULL); - - loplayer_action_t* action = memory_new(sizeof(*action)); - *action = (typeof(*action)) { - .res = res, - .ticker = ticker, - .bullets = bullets, - .entities = entities, - .event = event, - .status = status, - .entity = entity, - .combat = combat, - .controller = controller, - .camera = camera, - .hud = hud, - .menu = menu, - }; - loplayer_action_start_stand_state_(action); - return action; -} - -void loplayer_action_delete(loplayer_action_t* action) { - if (action == NULL) return; - - memory_delete(action); -} - -void loplayer_action_start_menu_popup_state(loplayer_action_t* action) { - assert(action != NULL); - - loplayer_action_start_menu_state_(action, true /* invincible */); -} - -void loplayer_action_execute(loplayer_action_t* action) { - assert(action != NULL); - - assert(action->execute != NULL); - action->execute(action); -} - -void loplayer_action_pack(const loplayer_action_t* action, msgpack_packer* packer) { - assert(action != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, 2); - - mpkutil_pack_str(packer, "since"); - msgpack_pack_uint64(packer, action->since); - - assert(action->pack != NULL); - - mpkutil_pack_str(packer, "state"); - action->pack(action, packer); -} - -bool loplayer_action_unpack( - loplayer_action_t* action, const msgpack_object* obj) { - assert(action != NULL); - - if (obj == NULL) return false; - - const msgpack_object_map* root = mpkutil_get_map(obj); - - const msgpack_object* since = mpkutil_get_map_item_by_str(root, "since"); - if (!mpkutil_get_uint64(since, &action->since)) return false; - - const msgpack_object_map* state = mpkutil_get_map( - mpkutil_get_map_item_by_str(root, "state")); - - bool state_loaded = false; - - const msgpack_object* name = mpkutil_get_map_item_by_str(state, "name"); - const char* v; - size_t len; - if (!mpkutil_get_str(name, &v, &len)) { - loplayer_action_start_stand_state_(action); - state_loaded = true; - } - -# define unpack_state_(name_) do { \ - if (!state_loaded && strncmp(v, #name_, len) == 0 && #name_[len] == 0) { \ - action->execute = loplayer_action_execute_##name_##_state_; \ - action->pack = loplayer_action_pack_##name_##_state_; \ - if (!loplayer_action_unpack_##name_##_state_(action, state)) { \ - loplayer_action_start_stand_state_(action); \ - } \ - state_loaded = true; \ - } \ - } while (0) - - LOPLAYER_ACTION_STATE_EACH_(unpack_state_); - -# undef unpack_state_ - - return true; -} diff --git a/core/loplayer/action.h b/core/loplayer/action.h deleted file mode 100644 index 1eb4817..0000000 --- a/core/loplayer/action.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include - -#include - -#include "core/lobullet/pool.h" -#include "core/locommon/ticker.h" -#include "core/loresource/set.h" - -#include "./camera.h" -#include "./combat.h" -#include "./controller.h" -#include "./entity.h" -#include "./event.h" -#include "./hud.h" -#include "./menu.h" -#include "./status.h" - -struct loplayer_action_t; -typedef struct loplayer_action_t loplayer_action_t; - -loplayer_action_t* /* OWNERSHIP */ -loplayer_action_new( - loresource_set_t* res, - const locommon_ticker_t* ticker, - lobullet_pool_t* bullets, - loentity_store_t* entities, - loplayer_event_t* event, - loplayer_status_t* status, - loplayer_entity_t* entity, - loplayer_combat_t* combat, - const loplayer_controller_t* controller, - loplayer_camera_t* camera, - loplayer_hud_t* hud, - loplayer_menu_t* menu -); - -void -loplayer_action_delete( - loplayer_action_t* action /* OWNERSHIP */ -); - -void -loplayer_action_start_menu_popup_state( - loplayer_action_t* action -); - -void -loplayer_action_execute( - loplayer_action_t* action -); - -void -loplayer_action_pack( - const loplayer_action_t* action, - msgpack_packer* packer -); - -bool -loplayer_action_unpack( - loplayer_action_t* action, - const msgpack_object* obj /* NULLABLE */ -); diff --git a/core/loplayer/camera.c b/core/loplayer/camera.c index f442bff..0419783 100644 --- a/core/loplayer/camera.c +++ b/core/loplayer/camera.c @@ -4,135 +4,43 @@ #include #include -#include "util/math/algorithm.h" #include "util/math/matrix.h" #include "util/math/vector.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" -#include "core/locommon/easing.h" #include "core/locommon/position.h" +#include "core/locommon/screen.h" #include "core/locommon/ticker.h" - -#include "./entity.h" -#include "./event.h" -#include "./status.h" - -#define LOPLAYER_CAMERA_STATE_EACH_(PROC) do { \ - PROC(DEFAULT, default); \ - PROC(COMBAT, combat); \ - PROC(DEAD, dead); \ - PROC(MENU, menu); \ -} while (0) - -static void loplayer_camera_bind_position_in_area_( - const loplayer_camera_t* camera, - locommon_position_t* pos, - const locommon_position_t* areapos, - const vec2_t* areasize) { - assert(camera != NULL); - assert(locommon_position_valid(pos)); - assert(locommon_position_valid(areapos)); - assert(vec2_valid(areasize)); - - vec2_t szoffset = camera->display_chunksz; - vec2_diveq(&szoffset, camera->scale); - - vec2_t sz; - vec2_sub(&sz, areasize, &szoffset); - - vec2_t v; - locommon_position_sub(&v, pos, areapos); - -# define fix_coordinate_(axis) do { \ - if (sz.axis > 0) { \ - if (MATH_ABS(v.axis) > sz.axis) v.axis = MATH_SIGN(v.axis)*sz.axis; \ - } else { \ - v.axis = 0; \ - } \ - } while (0) - - fix_coordinate_(x); - fix_coordinate_(y); - -# undef fix_coordinate_ - - *pos = *areapos; - vec2_addeq(&pos->fract, &v); - locommon_position_reduce(pos); -} - -const char* loplayer_camera_state_stringify(loplayer_camera_state_t state) { -# define each_(NAME, name) do { \ - if (state == LOPLAYER_CAMERA_STATE_##NAME) return #name; \ - } while (0) - - LOPLAYER_CAMERA_STATE_EACH_(each_); - - assert(false); - return NULL; - -# undef each_ -} - -bool loplayer_camera_state_unstringify( - loplayer_camera_state_t* state, const char* str, size_t len) { - assert(state != NULL); - -# define each_(NAME, name) do { \ - if (strncmp(str, #name, len) == 0 && #name[len] == 0) { \ - *state = LOPLAYER_CAMERA_STATE_##NAME; \ - return true; \ - } \ - } while (0) - - LOPLAYER_CAMERA_STATE_EACH_(each_); - return false; - -# undef each_ -} +#include "core/loentity/entity.h" +#include "core/loshader/posteffect.h" void loplayer_camera_initialize( loplayer_camera_t* camera, - loshader_set_t* shaders, - const locommon_ticker_t* ticker, - const loplayer_event_t* event, - const loplayer_status_t* status, - const loplayer_entity_t* entity, - const mat4_t* proj) { - assert(camera != NULL); - assert(shaders != NULL); - assert(ticker != NULL); - assert(event != NULL); - assert(status != NULL); - assert(entity != NULL); - assert(mat4_valid(proj)); + const locommon_screen_t* screen, + const locommon_ticker_t* ticker) { + assert(camera != NULL); + assert(screen != NULL); + assert(ticker != NULL); - mat4_t inv_proj; - mat4_inv(&inv_proj, proj); + mat4_t proj; + locommon_screen_build_projection_matrix(screen, &proj); - static const vec4_t chunk = vec4(1, 1, 0, 0); - vec4_t chunksz; - mat4_mul_vec4(&chunksz, &inv_proj, &chunk); + mat4_t iproj; + mat4_inv(&iproj, &proj); + + vec4_t v; + mat4_mul_vec4(&v, &iproj, &vec4(1, 1, 0, 0)); *camera = (typeof(*camera)) { - .shaders = shaders, - .ticker = ticker, - .event = event, - .status = status, - .entity = entity, + .ticker = ticker, - .display_chunksz = chunksz.xy, + .base_brightness = 1, + .chunk_winsz = v.xy, - .matrix = mat4_scale(1, 1, 1), - .scale = 1.0f, - - .cinesco = { - .color = vec4(0, 0, 0, 1), + .pos = locommon_position(0, 0, vec2(.5f, .5f)), + .scale = 1, + .posteffect = { + .brightness_whole = 1, }, - - .state = LOPLAYER_CAMERA_STATE_DEFAULT, - .brightness = 1, }; } @@ -141,133 +49,9 @@ void loplayer_camera_deinitialize(loplayer_camera_t* camera) { } -void loplayer_camera_update(loplayer_camera_t* camera) { +void loplayer_camera_build_matrix(const loplayer_camera_t* camera, mat4_t* m) { assert(camera != NULL); + assert(m != NULL); - const float d = camera->ticker->delta_f; - const loplayer_status_t* stat = camera->status; - - locommon_position_t target = camera->entity->super.super.pos; - - /* ---- movement ---- */ - const loplayer_event_param_t* e = loplayer_event_get_param(camera->event); - if (e != NULL && e->area_size.x > 0 && e->area_size.y > 0) { - loplayer_camera_bind_position_in_area_( - camera, &target, &e->area_pos, &e->area_size); - } - - vec2_t dist; - locommon_position_sub(&dist, &target, &camera->pos); - if (vec2_pow_length(&dist) > 2) camera->pos = target; - - locommon_easing_smooth_position(&camera->pos, &target, d*10); - -# define ease_float_(name, ed, speed) \ - locommon_easing_smooth_float(&camera->name, ed, d*(speed)) - - /* ---- cinema scope ---- */ - ease_float_(cinesco.size, !!(e != NULL && e->cinescope)*.3f, 2); - - /* ---- damage effect ---- */ - const bool damaged = - stat->last_damage_time > 0 && - stat->last_damage_time+500 > camera->ticker->time; - ease_float_(pe.raster, !!damaged*.5f, damaged? 5: 3); - - /* ---- amnesia effect ---- */ - const uint64_t amnesia_st = stat->recipient.effects.amnesia.begin; - const uint64_t amnesia_dur = stat->recipient.effects.amnesia.duration; - ease_float_( - pe.amnesia_displacement, - !!(amnesia_st+amnesia_dur > camera->ticker->time), 5); - - /* ---- dying effect ---- */ - const float dying = stat->dying_effect; - camera->pixsort = dying < .1f? dying/.1f: powf(1-(dying-.1f), 1.5f); - if (camera->pixsort < 0) camera->pixsort = 0; - - /* ---- switch by current state ---- */ - switch (camera->state) { - case LOPLAYER_CAMERA_STATE_DEFAULT: - ease_float_(scale, 1.0f, 10); - ease_float_(pe.whole_blur, 0.0f, 1); - ease_float_(pe.radial_displacement, 0.0f, 5); - ease_float_(pe.radial_fade, 0.5f, 3); - break; - case LOPLAYER_CAMERA_STATE_COMBAT: - ease_float_(scale, 1.5f, 8); - ease_float_(pe.whole_blur, 0.0f, 1); - ease_float_(pe.radial_displacement, 0.6f, 3); - ease_float_(pe.radial_fade, 0.8f, 1); - break; - case LOPLAYER_CAMERA_STATE_DEAD: - ease_float_(scale, 2.0f, 1); - ease_float_(pe.whole_blur, 1.0f, 1); - ease_float_(pe.radial_displacement, 0.3f, .7f); - ease_float_(pe.radial_fade, 1.5f, .7f); - break; - case LOPLAYER_CAMERA_STATE_MENU: - ease_float_(scale, 1.0f, 10); - ease_float_(pe.whole_blur, 0.9f, 1); - ease_float_(pe.radial_displacement, 0.0f, 10); - ease_float_(pe.radial_fade, 0.6f, 1); - break; - } - -# undef ease_float_ - - /* ---- fixed params ---- */ - camera->pe.brightness = camera->brightness; - - /* ---- matrix ---- */ - camera->matrix = mat4_scale(camera->scale, camera->scale, 1); -} - -void loplayer_camera_draw(const loplayer_camera_t* camera) { - assert(camera != NULL); - - loshader_pixsort_drawer_set_intensity( - camera->shaders->drawer.pixsort, camera->pixsort); - - loshader_posteffect_drawer_set_param( - camera->shaders->drawer.posteffect, &camera->pe); - - loshader_cinescope_drawer_set_param( - camera->shaders->drawer.cinescope, &camera->cinesco); -} - -void loplayer_camera_pack( - const loplayer_camera_t* camera, msgpack_packer* packer) { - assert(camera != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, 2); - - mpkutil_pack_str(packer, "state"); - mpkutil_pack_str(packer, loplayer_camera_state_stringify(camera->state)); - - mpkutil_pack_str(packer, "pos"); - locommon_position_pack(&camera->pos, packer); -} - -bool loplayer_camera_unpack( - loplayer_camera_t* camera, const msgpack_object* obj) { - assert(camera != NULL); - - if (obj == NULL) return false; - - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - const char* v; - size_t len; - if (!mpkutil_get_str(item_("state"), &v, &len) || - !loplayer_camera_state_unstringify(&camera->state, v, len)) { - return false; - } - if (!locommon_position_unpack(&camera->pos, item_("pos"))) { - return false; - } -# undef item_ - return true; + *m = mat4_scale(camera->scale, camera->scale, 1); } diff --git a/core/loplayer/camera.h b/core/loplayer/camera.h index b5c58a2..1f1fc26 100644 --- a/core/loplayer/camera.h +++ b/core/loplayer/camera.h @@ -2,75 +2,34 @@ #include -#include - -#include "util/math/matrix.h" #include "util/math/vector.h" #include "core/locommon/position.h" +#include "core/locommon/screen.h" #include "core/locommon/ticker.h" -#include "core/loshader/cinescope.h" +#include "core/loentity/entity.h" #include "core/loshader/posteffect.h" -#include "core/loshader/set.h" - -#include "./entity.h" -#include "./event.h" -#include "./status.h" - -typedef enum { - LOPLAYER_CAMERA_STATE_DEFAULT, - LOPLAYER_CAMERA_STATE_COMBAT, - LOPLAYER_CAMERA_STATE_DEAD, - LOPLAYER_CAMERA_STATE_MENU, -} loplayer_camera_state_t; typedef struct { - /* injected deps */ - loshader_set_t* shaders; const locommon_ticker_t* ticker; - const loplayer_event_t* event; - const loplayer_status_t* status; - const loplayer_entity_t* entity; - /* immutable params */ - vec2_t display_chunksz; + float base_brightness; + vec2_t chunk_winsz; + + uint64_t corruption_since; - /* read-only mutable params */ locommon_position_t pos; - mat4_t matrix; + float scale; - float scale; float pixsort; - loshader_posteffect_drawer_param_t pe; - loshader_cinescope_drawer_param_t cinesco; - - /* public params */ - loplayer_camera_state_t state; - float brightness; - + loshader_posteffect_drawer_param_t posteffect; } loplayer_camera_t; -const char* -loplayer_camera_state_stringify( - loplayer_camera_state_t state -); - -bool -loplayer_camera_state_unstringify( - loplayer_camera_state_t* state, - const char* str, - size_t len -); - void loplayer_camera_initialize( loplayer_camera_t* camera, - loshader_set_t* shaders, - const locommon_ticker_t* ticker, - const loplayer_event_t* event, - const loplayer_status_t* status, - const loplayer_entity_t* entity, - const mat4_t* proj + const locommon_screen_t* screen, + const locommon_ticker_t* ticker ); void @@ -79,23 +38,7 @@ loplayer_camera_deinitialize( ); void -loplayer_camera_update( - loplayer_camera_t* camera -); - -void -loplayer_camera_draw( - const loplayer_camera_t* camera -); - -void -loplayer_camera_pack( +loplayer_camera_build_matrix( const loplayer_camera_t* camera, - msgpack_packer* packer -); - -bool -loplayer_camera_unpack( - loplayer_camera_t* camera, - const msgpack_object* packer + mat4_t* m ); diff --git a/core/loplayer/combat.c b/core/loplayer/combat.c index d1dece5..b1b612a 100644 --- a/core/loplayer/combat.c +++ b/core/loplayer/combat.c @@ -3,287 +3,72 @@ #include #include #include -#include #include "util/math/algorithm.h" -#include "util/memory/memory.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" -#include "core/locommon/easing.h" -#include "core/locommon/msgpack.h" #include "core/locommon/ticker.h" -#include "core/loeffect/effect.h" -#include "core/loentity/character.h" +#include "core/loentity/entity.h" #include "core/loentity/store.h" -#include "core/loresource/sound.h" -#include "core/loshader/combat_ring.h" -#include "./entity.h" -#include "./status.h" - -struct loplayer_combat_t { - /* injected deps */ - loresource_sound_t* sound; - const locommon_ticker_t* ticker; - loshader_combat_ring_drawer_t* drawer; - loentity_store_t* entities; - - loplayer_status_t* status; - loplayer_entity_t* entity; - - /* temporary cache for drawing */ - uint64_t ring_start; - uint64_t ring_end; - - uint64_t guard_start; - uint64_t guard_end; - - uint64_t attack_end; - float alpha; - - /* params */ - bool accepted; - - size_t length; - loplayer_combat_attack_t attacks[1]; -}; - -#define LOPLAYER_COMBAT_GUARD_ERROR_THRESHOLD 0.55f - -#define LOPLAYER_COMBAT_ATTACK_PARAM_TO_PACK_EACH_(PROC) do { \ - PROC("attacker", attacker); \ - PROC("start", start); \ - PROC("duration", duration); \ - PROC("knockback", knockback); \ - PROC("effect", effect); \ -} while (0) -#define LOPLAYER_COMBAT_ATTACK_PARAM_TO_PACK_COUNT 5 - -static bool loplayer_combat_find_attack_index_in_period_( - loplayer_combat_t* combat, size_t* index, uint64_t st, uint64_t ed) { - assert(combat != NULL); - assert(st <= ed); - - static size_t dummy_; - if (index == NULL) index = &dummy_; - - for (size_t i = 0; i < combat->length; ++i) { - const uint64_t ist = combat->attacks[i].start; - const uint64_t ied = combat->attacks[i].duration + ist; - - if (ist < ed && ied > st) { - *index = i; - return true; - } - } - return false; -} - -static bool loplayer_combat_find_unused_attack_index_( - loplayer_combat_t* combat, size_t *index) { - assert(combat != NULL); - - for (size_t i = 0; i < combat->length; ++i) { - const uint64_t ed = combat->attacks[i].start + combat->attacks[i].duration; - if (ed <= combat->ticker->time) { - *index = i; - return true; - } - } - return false; -} - -static void loplayer_combat_execute_reflective_attack_( - loplayer_combat_t* combat, - loplayer_combat_attack_t* attack, - loentity_character_t* chara) { +static float loplayer_combat_calc_guard_ratio_( + const loplayer_combat_t* combat, const loplayer_combat_attack_t* attack) { assert(combat != NULL); assert(attack != NULL); - if (chara == NULL) return; + if (combat->last_guard_start >= combat->last_guard_end) { + return 0; + } + const uint64_t st = attack->start; + const uint64_t ed = st + attack->duration; - const loeffect_t dmg = - loeffect_immediate_damage(combat->status->recipient.status.attack); - loentity_character_apply_effect(chara, &dmg); - - vec2_t knockback = attack->knockback; - vec2_muleq(&knockback, -1); - loentity_character_knockback(chara, &knockback); - - loresource_sound_play(combat->sound, "reflection"); + float r = 0; + r += MATH_DIFF(combat->last_guard_start, st)/1000.f; + r += MATH_DIFF(combat->last_guard_end, ed)/1000.f; + return 1.f-MATH_CLAMP(r, 0.f, 1.f); } -static void loplayer_combat_execute_enemy_attack_( - loplayer_combat_t* combat, - loplayer_combat_attack_t* attack, - loentity_character_t* chara) { +static loplayer_combat_attack_t* loplayer_combat_find_first_attack_( + loplayer_combat_t* combat) { assert(combat != NULL); - assert(attack != NULL); - /* chara can be NULL */ - (void) chara; - - loplayer_status_apply_effect(combat->status, &attack->effect); - loentity_character_knockback(&combat->entity->super, &attack->knockback); -} - -static void loplayer_combat_handle_attack_( - loplayer_combat_t* combat, - loplayer_combat_attack_t* attack, - loentity_character_t* chara) { - assert(combat != NULL); - assert(attack != NULL); - - if (combat->guard_start < combat->guard_end) { - const uint64_t atked = attack->start + attack->duration; - - const uint64_t stdiff = - MATH_MAX(attack->start, combat->guard_start) - - MATH_MIN(attack->start, combat->guard_start); - const uint64_t eddiff = - MATH_MAX(atked, combat->guard_end) - - MATH_MIN(atked, combat->guard_end); - - const float guard_error = (stdiff + eddiff)*1.0f / attack->duration; - - const bool back_attack = - attack->knockback.x * combat->entity->direction > 0; - - float guard_error_thresh = LOPLAYER_COMBAT_GUARD_ERROR_THRESHOLD; - if (back_attack) guard_error_thresh /= 10; - - if (guard_error < guard_error_thresh) { - loplayer_combat_execute_reflective_attack_(combat, attack, chara); - return; + loplayer_combat_attack_t* first = NULL; + for (size_t i = 0; i < LOPLAYER_COMBAT_RESERVE; ++i) { + loplayer_combat_attack_t* a = &combat->attacks[i]; + if (a->duration > 0) { + if (first == NULL || first->start > a->start) first = a; } } - loplayer_combat_execute_enemy_attack_(combat, attack, chara); + return first; } -static void loplayer_combat_draw_ring_base_( - const loplayer_combat_t* combat) { +static loplayer_combat_attack_t* loplayer_combat_find_unused_attack_( + loplayer_combat_t* combat) { assert(combat != NULL); - loshader_combat_ring_drawer_add_instance( - combat->drawer, &(loshader_combat_ring_drawer_instance_t) { - .range = -1, /* = draw ring base */ - .color = vec4(0, 0, 0, .8f*combat->alpha), - }); -} - -static void loplayer_combat_draw_attacks_(const loplayer_combat_t* combat) { - assert(combat != NULL); - - const uint64_t ring_st = combat->ring_start; - const uint64_t ring_ed = combat->ring_end; - assert(ring_st <= ring_ed); - - const uint64_t ring_dur = ring_ed - ring_st; - - for (size_t i = 0; i < combat->length; ++i) { - const uint64_t st = combat->attacks[i].start; - const uint64_t ed = combat->attacks[i].duration + st; - - if (st < ring_ed && ring_st < ed) { - const uint64_t rst = st - MATH_MIN(ring_st, st); - const uint64_t red = ed - ring_st; - assert(rst <= red); - - loshader_combat_ring_drawer_add_instance( - combat->drawer, &(loshader_combat_ring_drawer_instance_t) { - .range = .8f, - .start = rst*1.f/ring_dur, - .end = MATH_MIN(red, ring_dur)*1.f/ring_dur, - .color = vec4(.7f, .1f, .1f, combat->alpha), - }); - } + for (size_t i = 0; i < LOPLAYER_COMBAT_RESERVE; ++i) { + if (combat->attacks[i].duration == 0) return &combat->attacks[i]; } + return NULL; } -static void loplayer_combat_draw_guard_(const loplayer_combat_t* combat) { - assert(combat != NULL); - - const bool now_guarding = (combat->guard_start > combat->guard_end); - if (!now_guarding && combat->guard_end <= combat->ring_start) { - return; - } - - const float ring_dur = combat->ring_end - combat->ring_start; - assert(ring_dur > 0); - - const uint64_t st = combat->guard_start - - MATH_MIN(combat->ring_start, combat->guard_start); - const uint64_t ed = - (now_guarding? combat->ticker->time: combat->guard_end) - - combat->ring_start; - - loshader_combat_ring_drawer_add_instance( - combat->drawer, &(loshader_combat_ring_drawer_instance_t) { - .range = .7f, - .start = st/ring_dur, - .end = ed/ring_dur, - .color = vec4(.1f, .1f, .7f, combat->alpha), - }); -} - -static void loplayer_combat_draw_clockhand_( - const loplayer_combat_t* combat) { - assert(combat != NULL); - - const uint64_t ring_dur = combat->ring_end - combat->ring_start; - assert(ring_dur > 0); - - assert(combat->ticker->time >= combat->ring_start); - const uint64_t cur = combat->ticker->time - combat->ring_start; - const float curf = cur*1.f/ring_dur; - - loshader_combat_ring_drawer_add_instance( - combat->drawer, &(loshader_combat_ring_drawer_instance_t) { - .range = 0, /* = draw clockhand */ - .start = curf, - .color = vec4(1, 1, 1, combat->alpha), - }); -} - -loplayer_combat_t* loplayer_combat_new( - loresource_sound_t* sound, - loshader_combat_ring_drawer_t* drawer, - const locommon_ticker_t* ticker, - loentity_store_t* entities, - loplayer_status_t* status, - loplayer_entity_t* entity, - size_t length) { - assert(sound != NULL); - assert(drawer != NULL); +void loplayer_combat_initialize( + loplayer_combat_t* combat, + const locommon_ticker_t* ticker, + loentity_store_t* entities) { + assert(combat != NULL); assert(ticker != NULL); assert(entities != NULL); - assert(status != NULL); - assert(entity != NULL); - assert(length > 0); - loplayer_combat_t* combat = memory_new( - sizeof(*combat) + (length-1)*sizeof(combat->attacks[0])); *combat = (typeof(*combat)) { - .sound = sound, - .drawer = drawer, .ticker = ticker, .entities = entities, - .status = status, - .entity = entity, - .length = length, }; - - for (size_t i = 0; i < combat->length; ++i) { - combat->attacks[i] = (typeof(combat->attacks[0])) {0}; - } - return combat; } -void loplayer_combat_delete(loplayer_combat_t* combat) { - if (combat == NULL) return; +void loplayer_combat_deinitialize(loplayer_combat_t* combat) { + assert(combat != NULL); - memory_delete(combat); + loplayer_combat_drop_all_attack(combat, true /* = by system */); } bool loplayer_combat_add_attack( @@ -291,213 +76,132 @@ bool loplayer_combat_add_attack( assert(combat != NULL); assert(attack != NULL); - if (loplayer_combat_find_attack_index_in_period_( - combat, NULL, attack->start, attack->start + attack->duration)) { - return false; + if (!combat->accepting) return false; + + const uint64_t st = attack->start; + const uint64_t ed = st + attack->duration; + if (ed <= combat->ticker->time || attack->duration == 0) return false; + + for (size_t i = 0; i < LOPLAYER_COMBAT_RESERVE; ++i) { + const loplayer_combat_attack_t* a = &combat->attacks[i]; + if (a->duration == 0) continue; + + const uint64_t ist = a->start; + const uint64_t ied = ist + a->duration; + if (st < ied && ist < ed) return false; } - size_t index; - if (!loplayer_combat_find_unused_attack_index_(combat, &index)) { - return false; - } + loplayer_combat_attack_t* a = loplayer_combat_find_unused_attack_(combat); + if (a == NULL) return false; - combat->attacks[index] = *attack; + *a = *attack; + if (combat->first_attack == NULL || + combat->first_attack->start > a->start) { + combat->first_attack = a; + } + if (combat->last_attack == NULL || + combat->last_attack->start < a->start) { + combat->last_attack = a; + } return true; } -bool loplayer_combat_accept_all_attacks(loplayer_combat_t* combat) { +void loplayer_combat_drop_dead_attack(loplayer_combat_t* combat) { assert(combat != NULL); - if (combat->accepted) return true; + for (size_t i = 0; i < LOPLAYER_COMBAT_RESERVE; ++i) { + loplayer_combat_attack_t* a = &combat->attacks[i]; + if (a->duration == 0) continue; - if (!loplayer_combat_find_attack_index_in_period_( - combat, NULL, combat->ticker->time, SIZE_MAX)) { - return false; - } - - combat->accepted = true; - return true; -} - -void loplayer_combat_drop_all_attacks(loplayer_combat_t* combat) { - assert(combat != NULL); - - for (size_t i = 0; i < combat->length; ++i) { - combat->attacks[i] = (typeof(combat->attacks[0])) {0}; - } - combat->accepted = false; - combat->ring_start = 0; - combat->ring_end = 0; - combat->guard_start = 0; - combat->guard_end = 0; - combat->attack_end = 0; -} - -void loplayer_combat_guard(loplayer_combat_t* combat) { - assert(combat != NULL); - - if (combat->ring_end <= combat->ticker->time || - combat->guard_start > combat->guard_end) { - return; - } - combat->guard_start = combat->ticker->time; - - loresource_sound_play(combat->sound, "guard"); -} - -void loplayer_combat_unguard(loplayer_combat_t* combat) { - assert(combat != NULL); - - if (combat->guard_start <= combat->guard_end) return; - - combat->guard_end = combat->ticker->time; -} - -void loplayer_combat_update(loplayer_combat_t* combat) { - assert(combat != NULL); - - if (!combat->accepted) return; - - const uint64_t cur = combat->ticker->time; - const uint64_t pre = cur - combat->ticker->delta; - - combat->ring_end = 0; - for (size_t i = 0; i < combat->length; ++i) { - loentity_store_iterator_t itr = (typeof(itr)) {0}; - - if (!loentity_store_find_item_by_id( - combat->entities, &itr, combat->attacks[i].attacker)) { - combat->attacks[i].start = 0; - combat->attacks[i].duration = 0; + loentity_store_iterator_t itr = {0}; + if (loentity_store_find_item_by_id( + combat->entities, &itr, a->attacker)) { continue; } - const uint64_t st = combat->attacks[i].start; - const uint64_t ed = combat->attacks[i].duration + st; - - const bool pre_active = st <= pre && pre < ed; - const bool cur_active = st <= cur && cur < ed; - if (!pre_active && cur_active) { - combat->attack_end = ed; - } else if (pre_active && !cur_active) { - loplayer_combat_handle_attack_( - combat, &combat->attacks[i], itr.character); - } - combat->ring_end = MATH_MAX(combat->ring_end, ed); - } - if (combat->ring_end > cur) { - if (combat->ring_start == 0) { - combat->ring_start = cur; - } - locommon_easing_smooth_float( - &combat->alpha, 1, combat->ticker->delta_f*10); - } else { - combat->alpha = 0; - loplayer_combat_drop_all_attacks(combat); + if (combat->first_attack == a) combat->first_attack = NULL; + if (combat->last_attack == a) combat->last_attack = NULL; + *a = (typeof(*a)) {0}; } } -void loplayer_combat_draw_ui(const loplayer_combat_t* combat) { +void loplayer_combat_drop_all_attack( + loplayer_combat_t* combat, loplayer_combat_attack_result_t reason) { assert(combat != NULL); - if (!combat->accepted || combat->ring_end <= combat->ticker->time) { - return; + for (size_t i = 0; i < LOPLAYER_COMBAT_RESERVE; ++i) { + loplayer_combat_attack_t* a = &combat->attacks[i]; + if (a->duration != 0) loplayer_combat_attack_handle(a, reason); + *a = (typeof(*a)) {0}; } - loplayer_combat_draw_ring_base_(combat); - loplayer_combat_draw_attacks_(combat); - loplayer_combat_draw_guard_(combat); - loplayer_combat_draw_clockhand_(combat); + combat->first_attack = NULL; + combat->last_attack = NULL; } -void loplayer_combat_pack( - const loplayer_combat_t* combat, msgpack_packer* packer) { - assert(combat != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, 1); - - mpkutil_pack_str(packer, "attacks"); - - size_t len = 0; - for (size_t i = 0; i < combat->length; ++i) { - const uint64_t st = combat->attacks[i].start; - const uint64_t ed = combat->attacks[i].duration + st; - const uint64_t cur = combat->ticker->time; - - if (st <= cur && cur < ed) ++len; - } - msgpack_pack_array(packer, len); - - for (size_t i = 0; i < combat->length; ++i) { - const uint64_t st = combat->attacks[i].start; - const uint64_t ed = combat->attacks[i].duration + st; - const uint64_t cur = combat->ticker->time; - - if (st <= cur && cur < ed) { - loplayer_combat_attack_pack(&combat->attacks[i], packer); - } - } -} - -bool loplayer_combat_unpack( - loplayer_combat_t* combat, const msgpack_object* obj) { - assert(combat != NULL); - - loplayer_combat_drop_all_attacks(combat); - - if (obj == NULL) return false; - - const msgpack_object_map* root = mpkutil_get_map(obj); - - const msgpack_object_array* array = - mpkutil_get_array(mpkutil_get_map_item_by_str(root, "attacks")); - - size_t src = 0, dst = 0; - while (src < array->size && dst < combat->length) { - if (loplayer_combat_attack_unpack( - &combat->attacks[dst], &array->ptr[src++])) { - ++dst; - } - } - return true; -} - -void loplayer_combat_attack_pack( - const loplayer_combat_attack_t* attack, - msgpack_packer* packer) { - assert(attack != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, LOPLAYER_COMBAT_ATTACK_PARAM_TO_PACK_COUNT); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &attack->var); \ - } while (0) - - LOPLAYER_COMBAT_ATTACK_PARAM_TO_PACK_EACH_(pack_); - -# undef pack_ -} - -bool loplayer_combat_attack_unpack( +bool loplayer_combat_pop_attack( + loplayer_combat_t* combat, loplayer_combat_attack_t* attack, - const msgpack_object* obj) { + float* guard_ratio) { + assert(combat != NULL); + assert(attack != NULL); + assert(guard_ratio != NULL); + + const uint64_t t = combat->ticker->time; + const uint64_t pt = combat->ticker->prev_time; + + loplayer_combat_attack_t* first = combat->first_attack; + if (first == NULL) return false; + + const uint64_t ed = first->start + first->duration; + if (pt >= ed || ed > t) return false; + + *attack = *first; + *guard_ratio = loplayer_combat_calc_guard_ratio_(combat, first); + *first = (typeof(*first)) {0}; + + combat->first_attack = loplayer_combat_find_first_attack_(combat); + if (combat->first_attack == NULL) combat->last_attack = NULL; + return true; +} + +void loplayer_combat_set_accepting( + loplayer_combat_t* combat, + bool accepting, + loplayer_combat_attack_result_t reason) { + assert(combat != NULL); + + if (combat->accepting == accepting) return; + + combat->accepting = accepting; + if (!accepting) loplayer_combat_drop_all_attack(combat, reason); +} + +void loplayer_combat_set_guarding(loplayer_combat_t* combat, bool guarding) { + assert(combat != NULL); + + if (combat->last_guard_start <= combat->last_guard_end) { + if (guarding) combat->last_guard_start = combat->ticker->time; + } else { + if (!guarding) combat->last_guard_end = combat->ticker->time; + } +} + +bool loplayer_combat_is_attack_pending(const loplayer_combat_t* combat) { + assert(combat != NULL); + + if (combat->last_attack == NULL) return false; + + const uint64_t st = combat->last_attack->start; + const uint64_t ed = st + combat->last_attack->duration; + + return ed > combat->ticker->time; +} + +void loplayer_combat_attack_handle( + const loplayer_combat_attack_t* attack, + loplayer_combat_attack_result_t result) { assert(attack != NULL); - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &attack->var)) { \ - return false; \ - } \ - } while (0) - - LOPLAYER_COMBAT_ATTACK_PARAM_TO_PACK_EACH_(unpack_); - return true; - -# undef unpack_ -# undef item_ + assert(attack->handle != NULL); + attack->handle(attack, result); } diff --git a/core/loplayer/combat.h b/core/loplayer/combat.h index 5d83f35..798b1a0 100644 --- a/core/loplayer/combat.h +++ b/core/loplayer/combat.h @@ -1,107 +1,109 @@ #pragma once #include -#include - -#include - -#include "util/math/vector.h" #include "core/locommon/ticker.h" -#include "core/loeffect/effect.h" +#include "core/loentity/entity.h" #include "core/loentity/store.h" -#include "core/loresource/sound.h" -#include "core/loshader/combat_ring.h" -#include "./entity.h" -#include "./status.h" +typedef enum { + LOPLAYER_COMBAT_ATTACK_RESULT_EXECUTED, + LOPLAYER_COMBAT_ATTACK_RESULT_REFLECTED, + LOPLAYER_COMBAT_ATTACK_RESULT_DODGED, + LOPLAYER_COMBAT_ATTACK_RESULT_ABORTED, +} loplayer_combat_attack_result_t; -struct loplayer_combat_t; -typedef struct loplayer_combat_t loplayer_combat_t; - -typedef struct { +typedef struct loplayer_combat_attack_t loplayer_combat_attack_t; +struct loplayer_combat_attack_t { loentity_id_t attacker; uint64_t start; uint64_t duration; - vec2_t knockback; + void* data1; + void* data2; - loeffect_t effect; -} loplayer_combat_attack_t; + void + (*handle)( + const loplayer_combat_attack_t* attack, + loplayer_combat_attack_result_t result + ); +}; -loplayer_combat_t* /* OWNERSHIP */ -loplayer_combat_new( - loresource_sound_t* sound, - loshader_combat_ring_drawer_t* drawer, - const locommon_ticker_t* ticker, - loentity_store_t* entities, - loplayer_status_t* status, - loplayer_entity_t* entity, - size_t length +typedef struct { + const locommon_ticker_t* ticker; + loentity_store_t* entities; + +# define LOPLAYER_COMBAT_RESERVE 32 + loplayer_combat_attack_t attacks[LOPLAYER_COMBAT_RESERVE]; + + loplayer_combat_attack_t* first_attack; + loplayer_combat_attack_t* last_attack; + + bool accepting; + + uint64_t last_guard_start; + uint64_t last_guard_end; +} loplayer_combat_t; + +void +loplayer_combat_initialize( + loplayer_combat_t* combat, + const locommon_ticker_t* ticker, + loentity_store_t* entities ); void -loplayer_combat_delete( - loplayer_combat_t* combat /* OWNERSHIP */ +loplayer_combat_deinitialize( + loplayer_combat_t* combat ); +/* All added attacks must finish with being called handle function + while the attacker is alive. */ bool loplayer_combat_add_attack( loplayer_combat_t* combat, const loplayer_combat_attack_t* attack ); +void +loplayer_combat_drop_dead_attack( + loplayer_combat_t* combat +); + +void +loplayer_combat_drop_all_attack( + loplayer_combat_t* combat, + loplayer_combat_attack_result_t reason +); + bool -loplayer_combat_accept_all_attacks( - loplayer_combat_t* combat +loplayer_combat_pop_attack( + loplayer_combat_t* combat, + loplayer_combat_attack_t* attack, + float* guard_ratio ); void -loplayer_combat_drop_all_attacks( - loplayer_combat_t* combat +loplayer_combat_set_accepting( + loplayer_combat_t* combat, + bool accepting, + loplayer_combat_attack_result_t reason ); void -loplayer_combat_guard( - loplayer_combat_t* combat +loplayer_combat_set_guarding( + loplayer_combat_t* combat, + bool guarding ); -void -loplayer_combat_unguard( - loplayer_combat_t* combat -); - -void -loplayer_combat_update( - loplayer_combat_t* combat -); - -void -loplayer_combat_draw_ui( +bool +loplayer_combat_is_attack_pending( const loplayer_combat_t* combat ); void -loplayer_combat_pack( - const loplayer_combat_t* combat, - msgpack_packer* packer -); - -bool -loplayer_combat_unpack( - loplayer_combat_t* combat, - const msgpack_object* obj /* NULLABLE */ -); - -void -loplayer_combat_attack_pack( +loplayer_combat_attack_handle( const loplayer_combat_attack_t* attack, - msgpack_packer* packer -); - -bool -loplayer_combat_attack_unpack( - loplayer_combat_attack_t* attack, - const msgpack_object* obj /* NULLABLE */ + loplayer_combat_attack_result_t result ); diff --git a/core/loplayer/controller.c b/core/loplayer/controller.c index b065143..95cfed9 100644 --- a/core/loplayer/controller.c +++ b/core/loplayer/controller.c @@ -1,16 +1,22 @@ #include "./controller.h" #include -#include #include #include "core/locommon/input.h" #include "core/locommon/position.h" +#include "core/locommon/ticker.h" -void loplayer_controller_initialize(loplayer_controller_t* controller) { +#define DODGE_PRESS_MAX_DURATION_ 300 + +void loplayer_controller_initialize( + loplayer_controller_t* controller, const locommon_ticker_t* ticker) { assert(controller != NULL); + assert(ticker != NULL); - *controller = (typeof(*controller)) {0}; + *controller = (typeof(*controller)) { + .ticker = ticker, + }; } void loplayer_controller_deinitialize(loplayer_controller_t* controller) { @@ -18,62 +24,68 @@ void loplayer_controller_deinitialize(loplayer_controller_t* controller) { } -void loplayer_controller_update( +void loplayer_controller_handle_input( loplayer_controller_t* controller, const locommon_input_t* input, const locommon_position_t* cursor) { assert(controller != NULL); - assert(input != NULL); - assert(locommon_position_valid(cursor)); - controller->looking = *cursor; - controller->cursor = input->cursor; + if (locommon_position_valid(cursor)) { + controller->cursor = *cursor; + } - controller->movement = LOPLAYER_CONTROLLER_MOVEMENT_NONE; - controller->action = LOPLAYER_CONTROLLER_ACTION_NONE; + controller->state = LOPLAYER_CONTROLLER_STATE_NONE; + if (input == NULL) return; - const bool prev_jump = - controller->prev.buttons & LOCOMMON_INPUT_BUTTON_JUMP; - const bool prev_guarding = - controller->prev.buttons & LOCOMMON_INPUT_BUTTON_GUARD; - const bool prev_dash = - controller->prev.buttons & LOCOMMON_INPUT_BUTTON_DASH; - const bool prev_menu = - controller->prev.buttons & LOCOMMON_INPUT_BUTTON_MENU; + if (input->buttons & LOCOMMON_INPUT_BUTTON_LEFT) { + controller->state = LOPLAYER_CONTROLLER_STATE_WALK_LEFT; + } + if (input->buttons & LOCOMMON_INPUT_BUTTON_RIGHT) { + controller->state = LOPLAYER_CONTROLLER_STATE_WALK_RIGHT; + } - if (input->buttons & LOCOMMON_INPUT_BUTTON_JUMP && !prev_jump) { - controller->movement = LOPLAYER_CONTROLLER_MOVEMENT_JUMP; - - } else if (input->buttons & LOCOMMON_INPUT_BUTTON_LEFT) { - controller->movement = LOPLAYER_CONTROLLER_MOVEMENT_WALK_LEFT; - if (input->buttons & LOCOMMON_INPUT_BUTTON_DASH) { - controller->movement = LOPLAYER_CONTROLLER_MOVEMENT_DASH_LEFT; + if (input->buttons & LOCOMMON_INPUT_BUTTON_DODGE) { + if (!controller->sprint) { + controller->sprint = true; + controller->last_sprint_start = controller->ticker->time; } + if (input->buttons & LOCOMMON_INPUT_BUTTON_LEFT) { + controller->state = LOPLAYER_CONTROLLER_STATE_SPRINT_LEFT; + } else if (input->buttons & LOCOMMON_INPUT_BUTTON_RIGHT) { + controller->state = LOPLAYER_CONTROLLER_STATE_SPRINT_RIGHT; + } + } else { + if (controller->sprint) { + controller->sprint = false; - } else if (input->buttons & LOCOMMON_INPUT_BUTTON_RIGHT) { - controller->movement = LOPLAYER_CONTROLLER_MOVEMENT_WALK_RIGHT; - if (input->buttons & LOCOMMON_INPUT_BUTTON_DASH) { - controller->movement = LOPLAYER_CONTROLLER_MOVEMENT_DASH_RIGHT; + assert(controller->ticker->time >= controller->last_sprint_start); + const size_t t = + controller->ticker->time - controller->last_sprint_start; + if (t < DODGE_PRESS_MAX_DURATION_) { + if (input->buttons & LOCOMMON_INPUT_BUTTON_LEFT) { + controller->state = LOPLAYER_CONTROLLER_STATE_DODGE_LEFT; + } else if (input->buttons & LOCOMMON_INPUT_BUTTON_RIGHT) { + controller->state = LOPLAYER_CONTROLLER_STATE_DODGE_RIGHT; + } else { + controller->state = LOPLAYER_CONTROLLER_STATE_DODGE_FORWARD; + } + } } } - if (input->buttons & LOCOMMON_INPUT_BUTTON_ATTACK) { - controller->action = LOPLAYER_CONTROLLER_ACTION_ATTACK; + if (input->buttons & LOCOMMON_INPUT_BUTTON_JUMP) { + if (!controller->jump) { + controller->jump = true; + controller->state = LOPLAYER_CONTROLLER_STATE_JUMP; + } + } else { + controller->jump = false; } if (input->buttons & LOCOMMON_INPUT_BUTTON_GUARD) { - if (!prev_guarding) controller->action = LOPLAYER_CONTROLLER_ACTION_GUARD; - } else { - if (prev_guarding) controller->action = LOPLAYER_CONTROLLER_ACTION_UNGUARD; + controller->state = LOPLAYER_CONTROLLER_STATE_GUARD; } - - if (input->buttons & LOCOMMON_INPUT_BUTTON_DASH && !prev_dash) { - controller->action = LOPLAYER_CONTROLLER_ACTION_DODGE; + if (input->buttons & LOCOMMON_INPUT_BUTTON_SHOOT) { + controller->state = LOPLAYER_CONTROLLER_STATE_SHOOT; } - - if (input->buttons & LOCOMMON_INPUT_BUTTON_MENU && !prev_menu) { - controller->action = LOPLAYER_CONTROLLER_ACTION_MENU; - } - - controller->prev = *input; } diff --git a/core/loplayer/controller.h b/core/loplayer/controller.h index 7ff7bc8..06c89b6 100644 --- a/core/loplayer/controller.h +++ b/core/loplayer/controller.h @@ -1,41 +1,38 @@ #pragma once -#include - #include "core/locommon/input.h" #include "core/locommon/position.h" +#include "core/locommon/ticker.h" typedef enum { - LOPLAYER_CONTROLLER_MOVEMENT_NONE, - LOPLAYER_CONTROLLER_MOVEMENT_JUMP, - LOPLAYER_CONTROLLER_MOVEMENT_WALK_LEFT, - LOPLAYER_CONTROLLER_MOVEMENT_WALK_RIGHT, - LOPLAYER_CONTROLLER_MOVEMENT_DASH_LEFT, - LOPLAYER_CONTROLLER_MOVEMENT_DASH_RIGHT, -} loplayer_controller_movement_t; - -typedef enum { - LOPLAYER_CONTROLLER_ACTION_NONE, - LOPLAYER_CONTROLLER_ACTION_ATTACK, - LOPLAYER_CONTROLLER_ACTION_GUARD, - LOPLAYER_CONTROLLER_ACTION_UNGUARD, - LOPLAYER_CONTROLLER_ACTION_DODGE, - LOPLAYER_CONTROLLER_ACTION_MENU, -} loplayer_controller_action_t; + LOPLAYER_CONTROLLER_STATE_NONE, + LOPLAYER_CONTROLLER_STATE_WALK_LEFT, + LOPLAYER_CONTROLLER_STATE_WALK_RIGHT, + LOPLAYER_CONTROLLER_STATE_SPRINT_LEFT, + LOPLAYER_CONTROLLER_STATE_SPRINT_RIGHT, + LOPLAYER_CONTROLLER_STATE_DODGE_FORWARD, + LOPLAYER_CONTROLLER_STATE_DODGE_LEFT, + LOPLAYER_CONTROLLER_STATE_DODGE_RIGHT, + LOPLAYER_CONTROLLER_STATE_JUMP, + LOPLAYER_CONTROLLER_STATE_GUARD, + LOPLAYER_CONTROLLER_STATE_SHOOT, +} loplayer_controller_state_t; typedef struct { - locommon_position_t looking; - vec2_t cursor; /* display coordinate (-1~1) */ + const locommon_ticker_t* ticker; - loplayer_controller_movement_t movement; - loplayer_controller_action_t action; + loplayer_controller_state_t state; + locommon_position_t cursor; - locommon_input_t prev; + bool jump; + bool sprint; + uint64_t last_sprint_start; } loplayer_controller_t; void loplayer_controller_initialize( - loplayer_controller_t* controller + loplayer_controller_t* controller, + const locommon_ticker_t* ticker ); void @@ -44,8 +41,8 @@ loplayer_controller_deinitialize( ); void -loplayer_controller_update( +loplayer_controller_handle_input( loplayer_controller_t* controller, - const locommon_input_t* input, - const locommon_position_t* cursor + const locommon_input_t* input, /* NULLABLE */ + const locommon_position_t* cursor /* NULLABLE */ ); diff --git a/core/loplayer/entity.c b/core/loplayer/entity.c deleted file mode 100644 index f01e00e..0000000 --- a/core/loplayer/entity.c +++ /dev/null @@ -1,311 +0,0 @@ -#include "./entity.h" - -#include -#include -#include -#include - -#include - -#include "util/math/algorithm.h" -#include "util/math/vector.h" -#include "util/memory/memory.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" - -#include "core/locommon/easing.h" -#include "core/locommon/msgpack.h" -#include "core/locommon/physics.h" -#include "core/locommon/ticker.h" -#include "core/loentity/character.h" -#include "core/loentity/entity.h" -#include "core/loentity/store.h" -#include "core/loresource/sound.h" -#include "core/loshader/character.h" - -#include "./event.h" -#include "./status.h" - -#define LOPLAYER_ENTITY_WIDTH .02f -#define LOPLAYER_ENTITY_HEIGHT .05f -#define LOPLAYER_ENTITY_DRAW_SIZE LOPLAYER_ENTITY_HEIGHT -#define LOPLAYER_ENTITY_SHIFT_Y .03f - -#define LOPLAYER_ENTITY_GRAVITY_ACCELARATION 2.2f -#define LOPLAYER_ENTITY_RECOVERY_ACCELARATION 1.f - -#define LOPLAYER_ENTITY_MAX_GRAVITY 2.f - -#define LOPLAYER_ENTITY_DIRECTION_EPSILON .05f - -#define LOPLAYER_ENTITY_PARAM_TO_PACK_EACH_(PROC) do { \ - PROC("pos", super.super.pos); \ - PROC("movement", movement); \ - PROC("knockback", knockback); \ - PROC("gravity", gravity); \ -} while (0) -#define LOPLAYER_ENTITY_PARAM_TO_PACK_COUNT 4 - -static void loplayer_entity_update_position_( - loplayer_entity_t* p, vec2_t* velocity) { - assert(p != NULL); - assert(vec2_valid(velocity)); - - vec2_t disp = *velocity; - vec2_muleq(&disp, p->ticker->delta_f); - - vec2_addeq(&p->super.super.pos.fract, &disp); - p->super.super.pos.fract.y -= LOPLAYER_ENTITY_SHIFT_Y; - locommon_position_reduce(&p->super.super.pos); - - locommon_physics_entity_t e = { - .size = vec2(LOPLAYER_ENTITY_WIDTH, LOPLAYER_ENTITY_HEIGHT), - .pos = p->super.super.pos, - .velocity = *velocity, - }; - - loentity_store_solve_collision_between_ground( - p->entities, &e, p->ticker->delta_f); - - p->super.super.pos = e.pos; - - p->super.super.pos.fract.y += LOPLAYER_ENTITY_SHIFT_Y; - locommon_position_reduce(&p->super.super.pos); - - p->on_ground = false; - if (e.velocity.y == 0) { - if (velocity->y <= 0) { - p->on_ground = true; - } - if (p->gravity*velocity->y >= 0) p->gravity = 0; - if (p->knockback.y*velocity->y >= 0) p->knockback.y = 0; - } - if (e.velocity.x == 0 && velocity->x != 0) { - if (p->knockback.x*velocity->x >= 0) p->knockback.x = 0; - } - p->last_velocity = *velocity = e.velocity; -} - -static void loplayer_entity_bind_in_event_area_(loplayer_entity_t* p) { - assert(p != NULL); - - const loplayer_event_param_t* e = loplayer_event_get_param(p->event); - if (e == NULL || e->area_size.x <= 0 || e->area_size.y <= 0) return; - - vec2_t v; - locommon_position_sub(&v, &p->super.super.pos, &e->area_pos); - - if (MATH_ABS(v.x) > e->area_size.x) { - v.x = MATH_SIGN(v.x) * e->area_size.x; - } - if (MATH_ABS(v.y) > e->area_size.y) { - v.y = MATH_SIGN(v.y) * e->area_size.y; - } - - p->super.super.pos = e->area_pos; - vec2_addeq(&p->super.super.pos.fract, &v); - locommon_position_reduce(&p->super.super.pos); -} - -static void loplayer_entity_delete_(loentity_t* entity) { - assert(entity != NULL); - - /* does not anything */ -} - -static bool loplayer_entity_update_(loentity_t* entity) { - assert(entity != NULL); - - loplayer_entity_t* p = (typeof(p)) entity; - - /* ---- position ---- */ - vec2_t velocity = p->movement; - vec2_addeq(&velocity, &p->knockback); - velocity.y += p->gravity; - loplayer_entity_update_position_(p, &velocity); - loplayer_entity_bind_in_event_area_(p); - - /* ---- gravity ---- */ - const float dt = p->ticker->delta_f; - p->gravity -= LOPLAYER_ENTITY_GRAVITY_ACCELARATION*dt; - p->gravity = MATH_MAX(p->gravity, -LOPLAYER_ENTITY_MAX_GRAVITY); - - /* ---- recovery from knockback ---- */ - locommon_easing_linear_float( - &p->knockback.x, 0, LOPLAYER_ENTITY_RECOVERY_ACCELARATION*dt); - locommon_easing_linear_float( - &p->knockback.y, 0, LOPLAYER_ENTITY_RECOVERY_ACCELARATION*dt); - return true; -} - -static void loplayer_entity_draw_( - loentity_t* entity, const locommon_position_t* basepos) { - assert(entity != NULL); - assert(basepos != NULL); - - loplayer_entity_t* p = (typeof(p)) entity; - - locommon_position_t center = p->super.super.pos; - center.fract.y -= LOPLAYER_ENTITY_SHIFT_Y; - locommon_position_reduce(¢er); - - loshader_character_drawer_instance_t instance = { - .character_id = LOSHADER_CHARACTER_ID_PLAYER, - .from_motion_id = p->motion.from, - .to_motion_id = p->motion.to, - .motion_time = p->motion.time, - .marker = p->status->bullet_immune_until < p->ticker->time, - .marker_offset = vec2(0, LOPLAYER_ENTITY_SHIFT_Y), - - .size = vec2( - LOPLAYER_ENTITY_DRAW_SIZE*p->direction, LOPLAYER_ENTITY_DRAW_SIZE), - .color = vec4(0, 0, 0, 1), - }; - locommon_position_sub(&instance.pos, ¢er, basepos); - - loshader_character_drawer_add_instance(p->drawer, &instance); -} - -static void loplayer_entity_apply_effect_( - loentity_character_t* chara, const loeffect_t* effect) { - assert(chara != NULL); - assert(effect != NULL); - - loplayer_entity_t* p = (typeof(p)) chara; - loplayer_status_apply_effect(p->status, effect); -} - -static void loplayer_entity_knockback_( - loentity_character_t* chara, const vec2_t* v) { - assert(chara != NULL); - assert(vec2_valid(v)); - - loplayer_entity_t* p = (typeof(p)) chara; - vec2_addeq(&p->knockback, v); -} - -void loplayer_entity_initialize( - loplayer_entity_t* player, - loentity_id_t id, - loresource_sound_t* sound, - loshader_character_drawer_t* drawer, - const locommon_ticker_t* ticker, - loentity_store_t* entities, - const loplayer_event_t* event, - loplayer_status_t* status) { - assert(player != NULL); - assert(sound != NULL); - assert(drawer != NULL); - assert(ticker != NULL); - assert(entities != NULL); - assert(event != NULL); - assert(status != NULL); - - *player = (typeof(*player)) { - .super = { - .super = { - .vtable = { - .delete = loplayer_entity_delete_, - .update = loplayer_entity_update_, - .draw = loplayer_entity_draw_, - }, - .subclass = LOENTITY_SUBCLASS_CHARACTER, - .id = id, - .pos = locommon_position(0, 0, vec2(0.5, 0.5)), - .dont_save = true, - }, - .vtable = { - .apply_effect = loplayer_entity_apply_effect_, - .knockback = loplayer_entity_knockback_, - }, - }, - .sound = sound, - .drawer = drawer, - .ticker = ticker, - .entities = entities, - .event = event, - .status = status, - - .direction = 1, - }; -} - -void loplayer_entity_deinitialize(loplayer_entity_t* player) { - assert(player != NULL); - -} - -void loplayer_entity_move( - loplayer_entity_t* player, const locommon_position_t* pos) { - assert(player != NULL); - assert(locommon_position_valid(pos)); - - player->super.super.pos = *pos; - player->on_ground = false; - player->movement = vec2(0, 0); - player->knockback = vec2(0, 0); - player->gravity = 0; -} - -void loplayer_entity_aim( - loplayer_entity_t* player, const locommon_position_t* pos) { - assert(player != NULL); - assert(locommon_position_valid(pos)); - - vec2_t dir; - locommon_position_sub(&dir, pos, &player->super.super.pos); - - if (MATH_ABS(dir.x) > LOPLAYER_ENTITY_DIRECTION_EPSILON) { - player->direction = MATH_SIGN(dir.x); - } -} - -bool loplayer_entity_affect_bullet(loplayer_entity_t* player) { - assert(player != NULL); - - return loentity_store_affect_bullets_shot_by_others( - player->entities, - &player->super, - &player->last_velocity, - player->ticker->delta_f); -} - -void loplayer_entity_pack( - const loplayer_entity_t* player, msgpack_packer* packer) { - assert(player != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, LOPLAYER_ENTITY_PARAM_TO_PACK_COUNT); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &player->var); \ - } while (0) - - LOPLAYER_ENTITY_PARAM_TO_PACK_EACH_(pack_); - -# undef pack_ -} - -bool loplayer_entity_unpack( - loplayer_entity_t* player, const msgpack_object* obj) { - assert(player != NULL); - - if (obj == NULL) return false; - - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &player->var)) { \ - return false; \ - } \ - } while (0) - - LOPLAYER_ENTITY_PARAM_TO_PACK_EACH_(unpack_); - return true; - -# undef unpack_ -# undef item_ -} diff --git a/core/loplayer/entity.h b/core/loplayer/entity.h deleted file mode 100644 index 37c1d6a..0000000 --- a/core/loplayer/entity.h +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include - -#include - -#include "util/math/vector.h" - -#include "core/locommon/ticker.h" -#include "core/loentity/character.h" -#include "core/loentity/store.h" -#include "core/loresource/sound.h" -#include "core/loshader/character.h" - -#include "./event.h" -#include "./status.h" - -typedef struct { - loentity_character_t super; - - /* injected deps */ - const locommon_ticker_t* ticker; - loresource_sound_t* sound; - loshader_character_drawer_t* drawer; - loentity_store_t* entities; - const loplayer_event_t* event; - loplayer_status_t* status; - - /* read-only mutable params */ - float direction; - - /* public params */ - vec2_t movement; - vec2_t knockback; - float gravity; - - /* temporary cache for update */ - bool on_ground; - vec2_t last_velocity; - - /* temporary cache for draw */ - struct { - loshader_character_motion_id_t from; - loshader_character_motion_id_t to; - float time; - } motion; -} loplayer_entity_t; - -void -loplayer_entity_initialize( - loplayer_entity_t* player, - loentity_id_t id, - loresource_sound_t* sound, - loshader_character_drawer_t* drawer, - const locommon_ticker_t* ticker, - loentity_store_t* entities, - const loplayer_event_t* event, - loplayer_status_t* status -); - -void -loplayer_entity_deinitialize( - loplayer_entity_t* player -); - -void -loplayer_entity_move( - loplayer_entity_t* player, - const locommon_position_t* pos -); - -void -loplayer_entity_aim( - loplayer_entity_t* player, - const locommon_position_t* pos -); - -bool -loplayer_entity_affect_bullet( - loplayer_entity_t* player -); - -void -loplayer_entity_pack( - const loplayer_entity_t* player, - msgpack_packer* packer -); - -bool -loplayer_entity_unpack( - loplayer_entity_t* player, - const msgpack_object* obj -); diff --git a/core/loplayer/event.c b/core/loplayer/event.c index 2039473..88ec16e 100644 --- a/core/loplayer/event.c +++ b/core/loplayer/event.c @@ -3,144 +3,159 @@ #include #include #include +#include -#include "util/glyphas/block.h" -#include "util/glyphas/cache.h" +#include + +#include "util/math/algorithm.h" #include "util/math/vector.h" -#include "util/memory/memory.h" +#include "util/mpkutil/get.h" +#include "util/mpkutil/pack.h" +#include "core/locommon/msgpack.h" #include "core/locommon/position.h" -#include "core/loresource/set.h" -#include "core/loshader/set.h" +#include "core/locommon/ticker.h" +#include "core/loentity/entity.h" -struct loplayer_event_t { - loplayer_event_param_t param; - /* convertible between loplayer_event_t* and loplayer_event_param_t* */ +/* generated serializer */ +#include "core/loplayer/crial/event.h" - /* injected deps */ - loresource_set_t* res; - loshader_set_t* shaders; +static bool loplayer_event_execute_command_( + loplayer_event_t* ev, const loplayer_event_command_t* command) { + assert(ev != NULL); - /* owned objects */ - glyphas_cache_t* font; - glyphas_block_t* text; + if (ev->exectime > ev->ticker->time) return false; - /* immutable params */ - struct { - vec2_t fontsz; - } geometry; -}; - -static void loplayer_event_calculate_geometry_(loplayer_event_t* event) { - assert(event != NULL); - - typeof(event->geometry)* geo = &event->geometry; - - geo->fontsz = event->shaders->dpi; - vec2_muleq(&geo->fontsz, .15f); + switch (command->type) { + case LOPLAYER_EVENT_COMMAND_TYPE_NONE: + return false; + case LOPLAYER_EVENT_COMMAND_TYPE_FINALIZE: + ev->basetime = 0; + ev->executor = 0; + ev->commands = NULL; + ev->ctx = (typeof(ev->ctx)) { + .line = { .last_update = ev->ticker->time, }, + }; + return true; + case LOPLAYER_EVENT_COMMAND_TYPE_PLAY_MUSIC: + ev->ctx.music = (typeof(ev->ctx.music)) { + .enable = true, + .id = command->music, + .since = ev->exectime, + }; + return true; + case LOPLAYER_EVENT_COMMAND_TYPE_STOP_MUSIC: + ev->ctx.music = (typeof(ev->ctx.music)) { + .enable = false, + }; + return true; + case LOPLAYER_EVENT_COMMAND_TYPE_SET_AREA: + ev->ctx.area.size = command->area; + return true; + case LOPLAYER_EVENT_COMMAND_TYPE_SET_CINESCOPE: + ev->ctx.cinescope = command->cinescope; + return true; + case LOPLAYER_EVENT_COMMAND_TYPE_SET_LINE: + if (ev->ctx.line.text_id != command->line) { + ev->ctx.line.text_id = command->line; + ev->ctx.line.last_update = ev->ticker->time; + } + return true; + case LOPLAYER_EVENT_COMMAND_TYPE_WAIT: + ev->exectime += command->wait; + return true; + } + __builtin_unreachable(); } -loplayer_event_t* loplayer_event_new( - loresource_set_t* res, loshader_set_t* shaders) { - assert(res != NULL); - assert(shaders != NULL); +void loplayer_event_initialize( + loplayer_event_t* ev, const locommon_ticker_t* ticker) { + assert(ev != NULL); + assert(ticker != NULL); - loplayer_event_t* event = memory_new(sizeof(*event)); - *event = (typeof(*event)) { - .res = res, - .shaders = shaders, + *ev = (typeof(*ev)) { + .ticker = ticker, }; - loplayer_event_calculate_geometry_(event); - - event->font = glyphas_cache_new( - shaders->tex.event_line, - &res->font.serif, - event->geometry.fontsz.x, - event->geometry.fontsz.y); - - event->text = glyphas_block_new( - GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, - -event->geometry.fontsz.y, - INT32_MAX, - 256); - - return event; } -void loplayer_event_delete(loplayer_event_t* event) { - if (event == NULL) return; +void loplayer_event_deinitialize(loplayer_event_t* ev) { + assert(ev != NULL); - glyphas_cache_delete(event->font); - glyphas_block_delete(event->text); - - memory_delete(event); } -loplayer_event_param_t* loplayer_event_take_control( - loplayer_event_t* event, loentity_id_t id) { - assert(event != NULL); +bool loplayer_event_execute_commands( + loplayer_event_t* ev, + loentity_id_t executor, + const locommon_position_t* pos, + const loplayer_event_command_t* commands) { + assert(ev != NULL); + assert(commands != NULL); + assert(locommon_position_valid(pos)); - if (event->param.controlled) return NULL; + const bool first = ev->basetime == 0; - event->param = (typeof(event->param)) { - .controlled = true, - .controlled_by = id, - }; - return &event->param; + if (first) ev->executor = executor; + if (ev->executor != executor) return false; + + if (ev->commands != commands) { + if (ev->commands != NULL || first) { + ev->basetime = ev->ticker->time; + } + ev->commands = commands; + ev->itr = commands; + ev->exectime = ev->basetime; + } + ev->ctx.area.pos = *pos; + + while (loplayer_event_execute_command_(ev, ev->itr)) ++ev->itr; + return true; } -void loplayer_event_abort(loplayer_event_t* event) { - assert(event != NULL); +void loplayer_event_pack(const loplayer_event_t* ev, msgpack_packer* packer) { + assert(ev != NULL); + assert(packer != NULL); - if (!event->param.controlled) return; - - loplayer_event_param_release_control(&event->param); + msgpack_pack_map(packer, CRIAL_PROPERTY_COUNT_); + CRIAL_SERIALIZER_; } -void loplayer_event_draw(const loplayer_event_t* event) { - assert(event != NULL); +bool loplayer_event_unpack(loplayer_event_t* ev, const msgpack_object* obj) { + assert(ev != NULL); + assert(obj != NULL); - if (!event->param.controlled) return; - - loshader_event_line_drawer_add_block( - &event->shaders->drawer.event_line, event->text); + const msgpack_object_map* root = mpkutil_get_map(obj); + CRIAL_DESERIALIZER_; + return true; } -const loplayer_event_param_t* loplayer_event_get_param( - const loplayer_event_t* event) { - assert(event != NULL); +void loplayer_event_bind_position_in_area( + const loplayer_event_t* ev, locommon_position_t* pos) { + assert(ev != NULL); + assert(locommon_position_valid(pos)); - if (!event->param.controlled) return NULL; - - return &event->param; + loplayer_event_bind_rect_in_area(ev, pos, &vec2(0, 0)); } -void loplayer_event_param_set_line( - loplayer_event_param_t* param, const char* str, size_t len) { - assert(param != NULL); +void loplayer_event_bind_rect_in_area( + const loplayer_event_t* ev, locommon_position_t* pos, const vec2_t* size) { + assert(ev != NULL); + assert(locommon_position_valid(pos)); + assert(vec2_valid(size)); - loplayer_event_t* event = (typeof(event)) param; + if (ev->ctx.area.size.x <= 0 || ev->ctx.area.size.y <= 0) return; - glyphas_block_clear(event->text); + vec2_t sz; + vec2_sub(&sz, &ev->ctx.area.size, size); + if (sz.x < 0) sz.x = 0; + if (sz.y < 0) sz.y = 0; - static const vec4_t white = vec4(1, 1, 1, 1); - glyphas_block_add_characters(event->text, event->font, &white, str, len); + vec2_t v; + locommon_position_sub(&v, pos, &ev->ctx.area.pos); - static const vec2_t center = vec2(.5f, -.5f); - glyphas_block_set_origin(event->text, ¢er); + if (fabs(v.x) > sz.x) v.x = MATH_SIGN(v.x)*sz.x; + if (fabs(v.y) > sz.y) v.y = MATH_SIGN(v.y)*sz.y; - const vec2_t scale = vec2( - 2/event->shaders->resolution.x, 2/event->shaders->resolution.y); - glyphas_block_scale(event->text, &scale); - - static const vec2_t trans = vec2(0, -.85f); - glyphas_block_translate(event->text, &trans); -} - -void loplayer_event_param_release_control(loplayer_event_param_t* param) { - assert(param != NULL); - assert(param->controlled); - - loplayer_event_param_set_line(param, "", 0); - param->controlled = false; + *pos = ev->ctx.area.pos; + vec2_addeq(&pos->fract, &v); + locommon_position_reduce(pos); } diff --git a/core/loplayer/event.crial b/core/loplayer/event.crial new file mode 100644 index 0000000..7eac32d --- /dev/null +++ b/core/loplayer/event.crial @@ -0,0 +1,15 @@ +/* CRIAL + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + LOCOMMON_MSGPACK_PACK_ANY(packer, &ev->$code); + END + DESERIALIZER_BEGIN + if (!LOCOMMON_MSGPACK_UNPACK_ANY( + mpkutil_get_map_item_by_str(root, "$name"), &ev->$code)) { + return false; + } + END + PROPERTY executor = executor + PROPERTY basetime = basetime +*/ + diff --git a/core/loplayer/event.h b/core/loplayer/event.h index 01057f4..ffadefa 100644 --- a/core/loplayer/event.h +++ b/core/loplayer/event.h @@ -1,74 +1,153 @@ #pragma once #include -#include +#include + +#include #include "util/math/vector.h" #include "core/locommon/position.h" +#include "core/locommon/ticker.h" #include "core/loentity/entity.h" #include "core/loresource/music.h" -#include "core/loresource/set.h" -#include "core/loshader/set.h" -struct loplayer_event_t; -typedef struct loplayer_event_t loplayer_event_t; +typedef enum { + LOPLAYER_EVENT_COMMAND_TYPE_NONE, + LOPLAYER_EVENT_COMMAND_TYPE_FINALIZE, + + LOPLAYER_EVENT_COMMAND_TYPE_PLAY_MUSIC, + LOPLAYER_EVENT_COMMAND_TYPE_STOP_MUSIC, + + LOPLAYER_EVENT_COMMAND_TYPE_SET_AREA, + LOPLAYER_EVENT_COMMAND_TYPE_SET_CINESCOPE, + LOPLAYER_EVENT_COMMAND_TYPE_SET_LINE, + + LOPLAYER_EVENT_COMMAND_TYPE_WAIT, +} loplayer_event_command_type_t; typedef struct { - bool controlled; - /* You can return the control by assigning false. */ + loplayer_event_command_type_t type; + union { + loresource_music_id_t music; - loentity_id_t controlled_by; + vec2_t area; - locommon_position_t area_pos; - vec2_t area_size; + float cinescope; - bool cinescope; - bool hide_hud; + const char* line; - loresource_music_player_t* music; -} loplayer_event_param_t; + uint64_t wait; + }; +} loplayer_event_command_t; -loplayer_event_t* /* OWNERSHIP */ -loplayer_event_new( - loresource_set_t* res, - loshader_set_t* shaders +#define loplayer_event_command_finalize() \ + (loplayer_event_command_t) { \ + .type = LOPLAYER_EVENT_COMMAND_TYPE_FINALIZE, \ + } +#define loplayer_event_command_play_music(id) \ + (loplayer_event_command_t) { \ + .type = LOPLAYER_EVENT_COMMAND_TYPE_PLAY_MUSIC, \ + .music = id, \ + } +#define loplayer_event_command_stop_music() \ + (loplayer_event_command_t) { \ + .type = LOPLAYER_EVENT_COMMAND_TYPE_STOP_MUSIC, \ + } +#define loplayer_event_command_set_area(w, h) \ + (loplayer_event_command_t) { \ + .type = LOPLAYER_EVENT_COMMAND_TYPE_SET_AREA, \ + .area = {{w, h}}, \ + } +#define loplayer_event_command_set_cinescope(v) \ + (loplayer_event_command_t) { \ + .type = LOPLAYER_EVENT_COMMAND_TYPE_SET_CINESCOPE, \ + .cinescope = v, \ + } +#define loplayer_event_command_set_line(text_id) \ + (loplayer_event_command_t) { \ + .type = LOPLAYER_EVENT_COMMAND_TYPE_SET_LINE, \ + .line = text_id, \ + } +#define loplayer_event_command_wait(dur) \ + (loplayer_event_command_t) { \ + .type = LOPLAYER_EVENT_COMMAND_TYPE_WAIT, \ + .wait = dur, \ + } + +typedef struct { + struct { + locommon_position_t pos; + vec2_t size; + } area; + + float cinescope; + + struct { + const char* text_id; + uint64_t last_update; + } line; + + struct { + bool enable; + loresource_music_id_t id; + uint64_t since; + } music; +} loplayer_event_context_t; + +typedef struct { + const locommon_ticker_t* ticker; + + loentity_id_t executor; + uint64_t basetime; + + const loplayer_event_command_t* commands; + const loplayer_event_command_t* itr; + uint64_t exectime; + + loplayer_event_context_t ctx; +} loplayer_event_t; + +void +loplayer_event_initialize( + loplayer_event_t* ev, + const locommon_ticker_t* ticker ); void -loplayer_event_delete( - loplayer_event_t* event /* OWNERSHIP*/ +loplayer_event_deinitialize( + loplayer_event_t* ev ); -loplayer_event_param_t* /* NULLABLE */ -loplayer_event_take_control( - loplayer_event_t* event, - loentity_id_t id +bool +loplayer_event_execute_commands( + loplayer_event_t* ev, + loentity_id_t executor, + const locommon_position_t* pos, + const loplayer_event_command_t* commands /* ends with NONE */ ); void -loplayer_event_abort( - loplayer_event_t* event +loplayer_event_pack( + const loplayer_event_t* ev, + msgpack_packer* packer +); + +bool +loplayer_event_unpack( + loplayer_event_t* ev, + const msgpack_object* obj ); void -loplayer_event_draw( - const loplayer_event_t* event -); - -const loplayer_event_param_t* /* NULLABLE */ -loplayer_event_get_param( - const loplayer_event_t* event +loplayer_event_bind_position_in_area( + const loplayer_event_t* ev, + locommon_position_t* pos ); void -loplayer_event_param_set_line( - loplayer_event_param_t* param, - const char* str, - size_t len -); - -void -loplayer_event_param_release_control( - loplayer_event_param_t* param +loplayer_event_bind_rect_in_area( + const loplayer_event_t* ev, + locommon_position_t* pos, + const vec2_t* size ); diff --git a/core/loplayer/hud.c b/core/loplayer/hud.c deleted file mode 100644 index 7ccaff7..0000000 --- a/core/loplayer/hud.c +++ /dev/null @@ -1,409 +0,0 @@ -#include "./hud.h" - -#include -#include -#include -#include - -#include "util/conv/charcode.h" -#include "util/glyphas/block.h" -#include "util/glyphas/cache.h" -#include "util/math/algorithm.h" -#include "util/memory/memory.h" - -#include "core/locommon/easing.h" -#include "core/locommon/position.h" -#include "core/locommon/ticker.h" -#include "core/loresource/set.h" -#include "core/loresource/text.h" -#include "core/loshader/hud_bar.h" -#include "core/loshader/set.h" - -#include "./entity.h" -#include "./event.h" -#include "./status.h" - -typedef struct { - float alpha; - float remain; - - glyphas_block_t* text; -} loplayer_hud_effect_t; - -struct loplayer_hud_t { - /* injected deps */ - loshader_set_t* shaders; - const locommon_ticker_t* ticker; - const loplayer_event_t* event; - const loplayer_status_t* status; - const loplayer_entity_t* entity; - - /* owned objects */ - struct { - glyphas_cache_t* sans; - glyphas_cache_t* serif; - } font; - - /* immutable params */ - struct { - vec2_t fontsz_normal_px; - vec2_t fontsz_normal; - vec2_t fontsz_small_px; - vec2_t fontsz_small; - - vec2_t padding; - - vec2_t madness_bar_pos; - vec2_t madness_bar_size; - - vec2_t faith_bar_pos; - vec2_t faith_bar_size; - - vec2_t effect_bar_pos; - vec2_t effect_bar_size; - } geometry; - - /* mutable params */ - float alpha; - - float prev_madness; - float prev_faith; - - bool shown; - - glyphas_block_t* biome_text; - - union { - struct { - loplayer_hud_effect_t curse; - loplayer_hud_effect_t amnesia; - loplayer_hud_effect_t lost; - }; - loplayer_hud_effect_t array[3]; - } effects; -}; - -static void loplayer_hud_calculate_geometry_(loplayer_hud_t* hud) { - assert(hud != NULL); - - const vec2_t* dpi = &hud->shaders->dpi; - const vec2_t* reso = &hud->shaders->resolution; - - typeof(hud->geometry)* geo = &hud->geometry; - -# define px_to_disp_(v) vec2((v).x/reso->x*2, (v).y/reso->y*2) - - geo->fontsz_normal_px = *dpi; - vec2_muleq(&geo->fontsz_normal_px, .4f); - - geo->fontsz_normal = px_to_disp_(geo->fontsz_normal_px); - - geo->fontsz_small_px = *dpi; - vec2_muleq(&geo->fontsz_small_px, .3f); - - geo->fontsz_small = px_to_disp_(geo->fontsz_small_px); - - geo->padding = *dpi; - vec2_muleq(&geo->padding, .4f); - geo->padding = px_to_disp_(geo->padding); - - geo->madness_bar_size = vec2(.5f, .1f*dpi->y); - geo->madness_bar_size.y /= reso->y/2; - - geo->madness_bar_pos = vec2( - -1 + geo->padding.x + geo->madness_bar_size.x, - 1 - geo->padding.y - geo->madness_bar_size.y); - - geo->faith_bar_size = vec2(.4f, .05f*dpi->y); - geo->faith_bar_size.y /= reso->y/2; - - geo->faith_bar_pos = vec2( - -1 + geo->padding.x + geo->faith_bar_size.x, - 1 - geo->padding.y - geo->madness_bar_size.y*2 - geo->faith_bar_size.y); - - geo->effect_bar_size = vec2(3*dpi->x/reso->x, 4/reso->y); - - geo->effect_bar_pos = vec2(1-geo->padding.x, -1+geo->padding.y); - vec2_subeq(&geo->effect_bar_pos, &geo->effect_bar_size); - -# undef px_to_disp_ -} - -static glyphas_block_t* loplayer_hud_create_effect_text_block_( - const loplayer_hud_t* hud, const char* text) { - assert(hud != NULL); - - glyphas_block_t* block = glyphas_block_new( - GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, - -hud->geometry.fontsz_normal_px.y, - INT32_MAX, - 32); - - static const vec4_t white = vec4(1, 1, 1, 1); - glyphas_block_add_characters( - block, hud->font.sans, &white, text, strlen(text)); - - const vec2_t scale = vec2( - 2/hud->shaders->resolution.x, 2/hud->shaders->resolution.y); - glyphas_block_scale(block, &scale); - - return block; -} - -static void loplayer_hud_initialize_effect_text_( - loplayer_hud_t* hud, loresource_set_t* res) { - assert(hud != NULL); - -# define init_effect_text_(name) \ - hud->effects.name.text = loplayer_hud_create_effect_text_block_( \ - hud, loresource_text_get(res->lang, "effect_"#name)) - - init_effect_text_(curse); - init_effect_text_(amnesia); - init_effect_text_(lost); - -# undef init_effect_ -} - -static void loplayer_hud_update_bars_(loplayer_hud_t* hud) { - assert(hud != NULL); - - const float d = hud->ticker->delta_f; - - locommon_easing_smooth_float( - &hud->prev_madness, hud->status->recipient.madness, d*2); - locommon_easing_smooth_float( - &hud->prev_faith, hud->status->recipient.faith, d*2); -} - -static void loplayer_hud_update_lasting_effect_( - loplayer_hud_t* hud, - loplayer_hud_effect_t* e, - const loeffect_generic_lasting_param_t* p) { - assert(hud != NULL); - assert(e != NULL); - assert(p != NULL); - - const uint64_t end = p->begin + p->duration; - const uint64_t t = hud->ticker->time; - if (p->duration == 0 || end <= t || p->begin > t) { - e->remain = 0; - return; - } - e->remain = 1 - (t - p->begin)*1.f/p->duration; -} - -static void loplayer_hud_update_effects_(loplayer_hud_t* hud) { - assert(hud != NULL); - - const float d = hud->ticker->delta_f; - - loplayer_hud_update_lasting_effect_( - hud, &hud->effects.curse, &hud->status->recipient.effects.curse); - loplayer_hud_update_lasting_effect_( - hud, &hud->effects.amnesia, &hud->status->recipient.effects.amnesia); - hud->effects.lost.remain = - hud->status->recipient.faith > 0? 0: (1-hud->status->recipient.madness); - - static const size_t len = - sizeof(hud->effects.array)/sizeof(hud->effects.array[0]); - for (size_t i = 0; i < len; ++i) { - loplayer_hud_effect_t* e = &hud->effects.array[i]; - locommon_easing_linear_float(&e->alpha, !!(e->remain > 0), d*2); - } -} - -static void loplayer_hud_draw_bars_(const loplayer_hud_t* hud) { - assert(hud != NULL); - - const typeof(hud->geometry)* geo = &hud->geometry; - - const loshader_hud_bar_drawer_instance_t madness = { - .pos = geo->madness_bar_pos, - .size = geo->madness_bar_size, - .bgcolor = vec4(0, 0, 0, 1*hud->alpha), - .fgcolor = vec4(1, 1, 1, .9f*hud->alpha), - .value = MATH_CLAMP(hud->status->recipient.madness, 0, 1), - .prev_value = MATH_CLAMP(hud->prev_madness, 0, 1), - }; - loshader_hud_bar_drawer_add_instance(hud->shaders->drawer.hud_bar, &madness); - - const loshader_hud_bar_drawer_instance_t faith = { - .pos = geo->faith_bar_pos, - .size = geo->faith_bar_size, - .bgcolor = vec4(0, 0, 0, 1*hud->alpha), - .fgcolor = vec4(.9f, .9f, .9f, .9f*hud->alpha), - .value = MATH_CLAMP(hud->status->recipient.faith, 0, 1), - .prev_value = MATH_CLAMP(hud->prev_faith, 0, 1), - }; - loshader_hud_bar_drawer_add_instance(hud->shaders->drawer.hud_bar, &faith); -} - -static void loplayer_hud_draw_effects_(const loplayer_hud_t* hud) { - assert(hud != NULL); - - const typeof(hud->geometry)* geo = &hud->geometry; - - const float lineheight = hud->geometry.fontsz_normal.y; - float h = 0; - - static const size_t len = - sizeof(hud->effects.array)/sizeof(hud->effects.array[0]); - for (size_t i = 0; i < len; ++i) { - const loplayer_hud_effect_t* e = &hud->effects.array[i]; - if (e->alpha == 0) continue; - - const float y = h*lineheight + geo->effect_bar_pos.y; - - static const vec2_t origin = vec2(1, -1); - glyphas_block_set_origin(e->text, &origin); - - const vec2_t trans = vec2(1-geo->padding.x, y); - glyphas_block_translate(e->text, &trans); - glyphas_block_set_alpha(e->text, e->alpha); - - loshader_hud_text_drawer_add_block( - &hud->shaders->drawer.hud_text, e->text); - - const loshader_hud_bar_drawer_instance_t instance = { - .pos = vec2(geo->effect_bar_pos.x, y), - .size = vec2(-geo->effect_bar_size.x, geo->effect_bar_size.y), - .bgcolor = vec4(1, 1, 1, .2f*hud->alpha), - .fgcolor = vec4(1, 1, 1, .8f*hud->alpha), - .value = MATH_CLAMP(e->remain, 0, 1), - .prev_value = MATH_CLAMP(e->remain, 0, 1), - }; - loshader_hud_bar_drawer_add_instance( - hud->shaders->drawer.hud_bar, &instance); - - h += e->alpha * e->alpha * (3-2*e->alpha); - } -} - -loplayer_hud_t* loplayer_hud_new( - loresource_set_t* res, - loshader_set_t* shaders, - const locommon_ticker_t* ticker, - const loplayer_event_t* event, - const loplayer_status_t* status, - const loplayer_entity_t* entity) { - assert(res != NULL); - assert(shaders != NULL); - assert(ticker != NULL); - assert(event != NULL); - assert(status != NULL); - assert(entity != NULL); - - loplayer_hud_t* hud = memory_new(sizeof(*hud)); - *hud = (typeof(*hud)) { - .shaders = shaders, - .ticker = ticker, - .event = event, - .status = status, - .entity = entity, - }; - loplayer_hud_calculate_geometry_(hud); - - hud->font = (typeof(hud->font)) { - .sans = glyphas_cache_new( - shaders->tex.hud_text, - &res->font.sans, - hud->geometry.fontsz_normal_px.x, - hud->geometry.fontsz_normal_px.y), - .serif = glyphas_cache_new( - shaders->tex.hud_text, - &res->font.serif, - hud->geometry.fontsz_small_px.x, - hud->geometry.fontsz_small_px.y), - }; - - hud->biome_text = glyphas_block_new( - GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, - -hud->geometry.fontsz_normal_px.y, - INT32_MAX, - 32); - - loplayer_hud_initialize_effect_text_(hud, res); - - return hud; -} - -void loplayer_hud_delete(loplayer_hud_t* hud) { - if (hud == NULL) return; - - static const size_t len = - sizeof(hud->effects.array) / sizeof(hud->effects.array[0]); - for (size_t i = 0; i < len; ++i) { - glyphas_block_delete(hud->effects.array[i].text); - } - - glyphas_block_delete(hud->biome_text); - - glyphas_cache_delete(hud->font.sans); - glyphas_cache_delete(hud->font.serif); - - memory_delete(hud); -} - -void loplayer_hud_show(loplayer_hud_t* hud) { - assert(hud != NULL); - - hud->shown = true; -} - -void loplayer_hud_hide(loplayer_hud_t* hud) { - assert(hud != NULL); - - hud->shown = false; -} - -void loplayer_hud_set_biome_text(loplayer_hud_t* hud, const char* text) { - assert(hud != NULL); - - glyphas_block_clear(hud->biome_text); - - static const vec4_t white = vec4(1, 1, 1, 1); - glyphas_block_add_characters( - hud->biome_text, hud->font.serif, &white, text, strlen(text)); - - glyphas_block_set_origin(hud->biome_text, &vec2(0, -1)); - - const vec2_t scale = vec2( - 2/hud->shaders->resolution.x, 2/hud->shaders->resolution.y); - glyphas_block_scale(hud->biome_text, &scale); - - const typeof(hud->geometry)* geo = &hud->geometry; - glyphas_block_translate( - hud->biome_text, &vec2(-1+geo->padding.x, -1+geo->padding.y)); - - glyphas_block_make_glitched(hud->biome_text, hud->ticker->time); -} - -void loplayer_hud_update(loplayer_hud_t* hud) { - assert(hud != NULL); - - bool shown = hud->shown; - - const loplayer_event_param_t* e = loplayer_event_get_param(hud->event); - if (e != NULL) { - shown = shown && !e->hide_hud; - } - - const float dt = hud->ticker->delta_f; - locommon_easing_smooth_float(&hud->alpha, !!shown, dt*2); - - loplayer_hud_update_bars_(hud); - loplayer_hud_update_effects_(hud); -} - -void loplayer_hud_draw_ui(const loplayer_hud_t* hud) { - assert(hud != NULL); - - hud->shaders->drawer.hud_text.alpha = hud->alpha; - - loplayer_hud_draw_bars_(hud); - loplayer_hud_draw_effects_(hud); - - loshader_hud_text_drawer_add_block( - &hud->shaders->drawer.hud_text, hud->biome_text); -} diff --git a/core/loplayer/hud.h b/core/loplayer/hud.h deleted file mode 100644 index 1c788d3..0000000 --- a/core/loplayer/hud.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "core/locommon/ticker.h" -#include "core/loresource/set.h" -#include "core/loshader/set.h" - -#include "./entity.h" -#include "./event.h" -#include "./status.h" - -struct loplayer_hud_t; -typedef struct loplayer_hud_t loplayer_hud_t; - -loplayer_hud_t* -loplayer_hud_new( - loresource_set_t* resource, - loshader_set_t* shaders, - const locommon_ticker_t* ticker, - const loplayer_event_t* event, - const loplayer_status_t* status, - const loplayer_entity_t* entity -); - -void -loplayer_hud_delete( - loplayer_hud_t* hud -); - -void -loplayer_hud_show( - loplayer_hud_t* hud -); - -void -loplayer_hud_hide( - loplayer_hud_t* hud -); - -void -loplayer_hud_set_biome_text( - loplayer_hud_t* hud, - const char* text -); - -void -loplayer_hud_update( - loplayer_hud_t* hud -); - -void -loplayer_hud_draw_ui( - const loplayer_hud_t* hud -); diff --git a/core/loplayer/menu.c b/core/loplayer/menu.c deleted file mode 100644 index 3e58593..0000000 --- a/core/loplayer/menu.c +++ /dev/null @@ -1,565 +0,0 @@ -#include "./menu.h" - -#include -#include -#include -#include -#include - -#include "util/glyphas/block.h" -#include "util/glyphas/cache.h" -#include "util/math/algorithm.h" -#include "util/math/constant.h" -#include "util/memory/memory.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" - -#include "core/locommon/easing.h" -#include "core/locommon/ticker.h" -#include "core/loeffect/stance.h" -#include "core/loresource/set.h" -#include "core/loresource/text.h" -#include "core/loshader/set.h" - -#include "./controller.h" -#include "./entity.h" -#include "./status.h" - -typedef struct { - glyphas_block_t* name; - glyphas_block_t* desc; - glyphas_block_t* note; -} loplayer_menu_stance_text_set_t; - -typedef enum { - LOPLAYER_MENU_STATE_HIDDEN, - LOPLAYER_MENU_STATE_STATUS, - LOPLAYER_MENU_STATE_POPUP, -} loplayer_menu_state_t; - -struct loplayer_menu_t { - /* injected deps */ - loresource_set_t* res; - loshader_set_t* shaders; - - const locommon_ticker_t* ticker; - const loplayer_status_t* status; - const loplayer_controller_t* controller; - - /* owned objects */ - struct { - glyphas_cache_t* large; - glyphas_cache_t* normal; - glyphas_cache_t* small; - } font; - - struct { - loplayer_menu_stance_text_set_t stance[LOEFFECT_STANCE_ID_LENGTH_+1]; - /* [0] is for unknown stance */ - - glyphas_block_t* popup_title; - glyphas_block_t* popup_body; - - glyphas_block_t* exit; - } text; - - /* immutable params */ - struct { - vec2_t fontsz_large; - vec2_t fontsz_normal; - vec2_t fontsz_small; - - vec2_t fontsz_large_px; - vec2_t fontsz_normal_px; - vec2_t fontsz_small_px; - - vec2_t range; - vec2_t icon; - vec2_t padding; - } geometry; - - /* mutable params */ - loplayer_menu_state_t state; - float alpha; - - bool stance_hovering; - size_t display_stance_text_index; - - float stance_highlight; - size_t highlighted_stance; - - bool request_exit; -}; - -static void loplayer_menu_calculate_geometry_(loplayer_menu_t* menu) { - assert(menu != NULL); - - const vec2_t* dpi = &menu->shaders->dpi; - const vec2_t* reso = &menu->shaders->resolution; - - typeof(menu->geometry)* geo = &menu->geometry; - - geo->fontsz_large_px = *dpi; - vec2_muleq(&geo->fontsz_large_px, .2f); - - geo->fontsz_normal_px = *dpi; - vec2_muleq(&geo->fontsz_normal_px, .15f); - - geo->fontsz_small_px = *dpi; - vec2_muleq(&geo->fontsz_small_px, .12f); - -# define px_to_disp_(v) vec2((v).x/reso->x*2, (v).y/reso->y*2) - - geo->fontsz_large = px_to_disp_(geo->fontsz_large_px); - geo->fontsz_normal = px_to_disp_(geo->fontsz_normal_px); - geo->fontsz_small = px_to_disp_(geo->fontsz_small_px); - - geo->range = *dpi; - vec2_muleq(&geo->range, 2); - geo->range = px_to_disp_(geo->range); - vec2_diveq(&geo->range, MATH_MAX(geo->range.x, 1)); - vec2_diveq(&geo->range, MATH_MAX(geo->range.y, 1)); - - geo->icon = *dpi; - vec2_muleq(&geo->icon, .4f); - geo->icon = px_to_disp_(geo->icon); - - geo->padding = *dpi; - vec2_muleq(&geo->padding, .2f); - geo->padding = px_to_disp_(geo->padding); - -# undef px_to_disp_ -} - -static void loplayer_menu_initialize_stance_text_set_( - const loplayer_menu_t* menu, - loplayer_menu_stance_text_set_t* set, - const char* name, - const char* desc, - const char* note) { - assert(menu != NULL); - assert(set != NULL); - - const typeof(menu->geometry)* geo = &menu->geometry; - - *set = (typeof(*set)) { - .name = glyphas_block_new( - GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, - -geo->fontsz_large_px.y, - INT32_MAX, - 32), - .desc = glyphas_block_new( - GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, - -geo->fontsz_normal_px.y*1.3f, - geo->fontsz_normal_px.x*18, - 512), - .note = glyphas_block_new( - GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, - -geo->fontsz_small_px.y*1.1f, - geo->fontsz_normal_px.x*18, - 512), - }; - - static const vec4_t white = vec4(1, 1, 1, 1); - static const vec4_t yellow = vec4(1, .7f, 0, 1); - - glyphas_block_add_characters( - set->name, menu->font.large, &white, name, strlen(name)); - glyphas_block_add_characters( - set->desc, menu->font.normal, &white, desc, strlen(desc)); - glyphas_block_add_characters( - set->note, menu->font.small, &yellow, note, strlen(note)); - - glyphas_block_set_origin(set->name, &vec2(.5f, -1)); - glyphas_block_set_origin(set->desc, &vec2(.5f, -.5f)); - glyphas_block_set_origin(set->note, &vec2(.5f, 0)); - - const vec2_t scale = - vec2(2/menu->shaders->resolution.x, 2/menu->shaders->resolution.y); - glyphas_block_scale(set->name, &scale); - glyphas_block_scale(set->desc, &scale); - glyphas_block_scale(set->note, &scale); - - vec2_t offset, size; - glyphas_block_calculate_geometry(set->desc, &offset, &size); - - glyphas_block_translate(set->name, &vec2(0, size.y/2 * 1.1f)); - glyphas_block_translate(set->note, &vec2(0, -size.y/2 * 1.2f)); -} - -static void loplayer_menu_deinitialize_stance_text_set_( - loplayer_menu_stance_text_set_t* set) { - assert(set != NULL); - - glyphas_block_delete(set->name); - glyphas_block_delete(set->desc); - glyphas_block_delete(set->note); -} - -static void loplayer_menu_create_stance_text_(loplayer_menu_t* menu) { - assert(menu != NULL); - -# define text_(name) loresource_text_get(menu->res->lang, name) - - loplayer_menu_initialize_stance_text_set_( - menu, &menu->text.stance[0], "???", "???", ""); - -# define init_stance_set_(NAME, name) \ - loplayer_menu_initialize_stance_text_set_( \ - menu, \ - &menu->text.stance[LOEFFECT_STANCE_ID_##NAME+1], \ - text_("stance_"#name"_name"), \ - text_("stance_"#name"_desc"), \ - text_("stance_"#name"_note")) - - LOEFFECT_STANCE_EACH(init_stance_set_); - -# undef init_stance_set_ -# undef text_ -} - -static void loplayer_menu_create_exit_text_(loplayer_menu_t* menu) { - assert(menu != NULL); - - menu->text.exit = glyphas_block_new( - GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, - -menu->geometry.fontsz_normal_px.y, - INT32_MAX, - 32); - - const char* text = loresource_text_get(menu->res->lang, "menu_exit"); - - static const vec4_t white = vec4(1, 1, 1, 1); - glyphas_block_add_characters( - menu->text.exit, menu->font.normal, &white, text, strlen(text)); - - glyphas_block_set_origin(menu->text.exit, &vec2(.5f, -1)); - - const vec2_t scale = - vec2(2/menu->shaders->resolution.x, 2/menu->shaders->resolution.y); - glyphas_block_scale(menu->text.exit, &scale); - - glyphas_block_translate(menu->text.exit, &vec2(0, -1+menu->geometry.padding.y)); -} - -static void loplayer_menu_build_popup_text_( - loplayer_menu_t* menu, const char* title, const char* text) { - assert(menu != NULL); - - glyphas_block_clear(menu->text.popup_title); - glyphas_block_clear(menu->text.popup_body); - - static const vec4_t white = vec4(1, 1, 1, 1); - glyphas_block_add_characters( - menu->text.popup_title, menu->font.large, &white, title, strlen(title)); - glyphas_block_add_characters( - menu->text.popup_body, menu->font.normal, &white, text, strlen(text)); - - static const vec2_t bottom = vec2(.5f, -1); - static const vec2_t center = vec2(.5f, -.5f); - glyphas_block_set_origin(menu->text.popup_title, &bottom); - glyphas_block_set_origin(menu->text.popup_body, ¢er); - - const vec2_t scale = - vec2(2/menu->shaders->resolution.x, 2/menu->shaders->resolution.y); - glyphas_block_scale(menu->text.popup_title, &scale); - glyphas_block_scale(menu->text.popup_body, &scale); - - vec2_t offset, size; - glyphas_block_calculate_geometry(menu->text.popup_body, &offset, &size); - - const vec2_t upper = vec2(0, size.y/2*1.1f); - glyphas_block_translate(menu->text.popup_title, &upper); -} - -static bool loplayer_menu_find_stance_icon_at_( - const loplayer_menu_t* menu, size_t* index, const vec2_t* pos) { - assert(menu != NULL); - assert(index != NULL); - assert(vec2_valid(pos)); - - const typeof(menu->geometry)* geo = &menu->geometry; - - for (size_t i = 0; i < 5; ++i) { - const float theta = MATH_PI*2/5 * i + MATH_PI/2; - const vec2_t p = - vec2(geo->range.x*cos(theta), geo->range.y*sin(theta)); - - vec2_t diff = *pos; - vec2_subeq(&diff, &p); - - diff.x /= geo->icon.x; - diff.y /= geo->icon.y; - - const float manhattan = MATH_ABS(diff.x) + MATH_ABS(diff.y); - if (manhattan < 1) { - *index = i; - return true; - } - } - return false; -} - -static void loplayer_menu_update_status_(loplayer_menu_t* menu) { - assert(menu != NULL); - - if (menu->alpha != 1) return; - - locommon_easing_linear_float( - &menu->stance_highlight, 0, menu->ticker->delta_f); - - size_t hovered; - menu->stance_hovering = loplayer_menu_find_stance_icon_at_( - menu, &hovered, &menu->controller->cursor); - if (menu->stance_hovering) { - const bool taken = - loeffect_stance_set_has(&menu->status->stances, hovered); - menu->display_stance_text_index = taken? hovered+1: 0; - } - - const typeof(menu->geometry)* geo = &menu->geometry; - if (menu->controller->cursor.y < -1+geo->fontsz_normal.y+geo->padding.y) { - if (menu->controller->prev.buttons & LOCOMMON_INPUT_BUTTON_ATTACK) { - menu->request_exit = true; - } - } -} - -static void loplayer_menu_update_popup_(loplayer_menu_t* menu) { - assert(menu != NULL); - -} - -static void loplayer_menu_draw_stance_icons_(const loplayer_menu_t* menu) { - assert(menu != NULL); - - const typeof(menu->geometry)* geo = &menu->geometry; - - for (size_t i = 0; i < 5; ++i) { - const bool taken = - loeffect_stance_set_has(&menu->status->stances, i); - - const float theta = MATH_PI*2/5 * i + MATH_PI/2; - - const loshader_menu_stance_drawer_instance_t instance = { - .id = taken? - loeffect_stance_get_id_for_menu_shader(i): - LOSHADER_MENU_STANCE_ID_EMPTY, - .pos = vec2(geo->range.x*cos(theta), geo->range.y*sin(theta)), - .size = geo->icon, - .alpha = menu->alpha, - .highlight = menu->stance_highlight * !!(menu->highlighted_stance == i), - }; - loshader_menu_stance_drawer_add_instance( - menu->shaders->drawer.menu_stance, &instance); - } -} - -static void loplayer_menu_draw_status_(const loplayer_menu_t* menu) { - assert(menu != NULL); - - loplayer_menu_draw_stance_icons_(menu); - - if (menu->stance_hovering) { - const loplayer_menu_stance_text_set_t* set = - &menu->text.stance[menu->display_stance_text_index]; - loshader_menu_text_drawer_add_block( - &menu->shaders->drawer.menu_text, set->name); - loshader_menu_text_drawer_add_block( - &menu->shaders->drawer.menu_text, set->desc); - loshader_menu_text_drawer_add_block( - &menu->shaders->drawer.menu_text, set->note); - } - loshader_menu_text_drawer_add_block( - &menu->shaders->drawer.menu_text, menu->text.exit); -} - -static void loplayer_menu_draw_popup_(const loplayer_menu_t* menu) { - assert(menu != NULL); - - loshader_menu_text_drawer_add_block( - &menu->shaders->drawer.menu_text, menu->text.popup_title); - loshader_menu_text_drawer_add_block( - &menu->shaders->drawer.menu_text, menu->text.popup_body); -} - -loplayer_menu_t* loplayer_menu_new( - loresource_set_t* res, - loshader_set_t* shaders, - const locommon_ticker_t* ticker, - const loplayer_status_t* status, - const loplayer_controller_t* controller) { - assert(res != NULL); - assert(shaders != NULL); - assert(ticker != NULL); - assert(status != NULL); - assert(controller != NULL); - - loplayer_menu_t* menu = memory_new(sizeof(*menu)); - *menu = (typeof(*menu)) { - .res = res, - .shaders = shaders, - .ticker = ticker, - .status = status, - .controller = controller, - }; - - loplayer_menu_calculate_geometry_(menu); - - menu->font = (typeof(menu->font)) { - .large = glyphas_cache_new( - shaders->tex.menu_text, - &res->font.sans, - menu->geometry.fontsz_large_px.x, - menu->geometry.fontsz_large_px.y), - .normal = glyphas_cache_new( - shaders->tex.menu_text, - &res->font.sans, - menu->geometry.fontsz_normal_px.x, - menu->geometry.fontsz_normal_px.y), - .small = glyphas_cache_new( - shaders->tex.menu_text, - &res->font.serif, - menu->geometry.fontsz_small_px.x, - menu->geometry.fontsz_small_px.y), - }; - - menu->text = (typeof(menu->text)) { - .popup_title = glyphas_block_new( - GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, - -menu->geometry.fontsz_large_px.y, - INT32_MAX, - 32), - .popup_body = glyphas_block_new( - GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, - -menu->geometry.fontsz_normal_px.y*1.3f, - menu->geometry.fontsz_normal_px.x*18, - 512), - }; - loplayer_menu_create_stance_text_(menu); - loplayer_menu_create_exit_text_(menu); - - return menu; -} - -void loplayer_menu_delete(loplayer_menu_t* menu) { - if (menu == NULL) return; - - static const size_t len = - sizeof(menu->text.stance)/sizeof(menu->text.stance[0]); - for (size_t i = 0; i < len; ++i) { - loplayer_menu_deinitialize_stance_text_set_(&menu->text.stance[i]); - } - - glyphas_block_delete(menu->text.popup_title); - glyphas_block_delete(menu->text.popup_body); - glyphas_block_delete(menu->text.exit); - - glyphas_cache_delete(menu->font.large); - glyphas_cache_delete(menu->font.normal); - glyphas_cache_delete(menu->font.small); - - memory_delete(menu); -} - -void loplayer_menu_show_status(loplayer_menu_t* menu) { - assert(menu != NULL); - - menu->state = LOPLAYER_MENU_STATE_STATUS; - menu->stance_hovering = false; - menu->stance_highlight = 0; -} - -void loplayer_menu_show_status_with_stance_highlighted( - loplayer_menu_t* menu, loeffect_stance_id_t id) { - assert(menu != NULL); - - loplayer_menu_show_status(menu); - menu->stance_highlight = 1; - menu->highlighted_stance = id; -} - -void loplayer_menu_popup( - loplayer_menu_t* menu, const char* title, const char* text) { - assert(menu != NULL); - - menu->state = LOPLAYER_MENU_STATE_POPUP; - loplayer_menu_build_popup_text_(menu, title, text); -} - -void loplayer_menu_hide(loplayer_menu_t* menu) { - assert(menu != NULL); - - menu->state = LOPLAYER_MENU_STATE_HIDDEN; -} - -void loplayer_menu_update(loplayer_menu_t* menu) { - assert(menu != NULL); - - if (menu->state == LOPLAYER_MENU_STATE_HIDDEN) { - locommon_easing_linear_float(&menu->alpha, 0, menu->ticker->delta_f*2); - return; - } - locommon_easing_linear_float(&menu->alpha, 1, menu->ticker->delta_f*2); - - switch (menu->state) { - case LOPLAYER_MENU_STATE_STATUS: - loplayer_menu_update_status_(menu); - return; - case LOPLAYER_MENU_STATE_POPUP: - loplayer_menu_update_popup_(menu); - return; - default: - assert(false); - } -} - -void loplayer_menu_draw_ui(const loplayer_menu_t* menu) { - assert(menu != NULL); - - loshader_menu_background_drawer_set_alpha( - menu->shaders->drawer.menu_background, menu->alpha); - menu->shaders->drawer.menu_text.alpha = menu->alpha; - - switch (menu->state) { - case LOPLAYER_MENU_STATE_HIDDEN: - return; - case LOPLAYER_MENU_STATE_STATUS: - loplayer_menu_draw_status_(menu); - return; - case LOPLAYER_MENU_STATE_POPUP: - loplayer_menu_draw_popup_(menu); - return; - default: - assert(false); - } -} - -bool loplayer_menu_is_shown(const loplayer_menu_t* menu) { - assert(menu != NULL); - - return menu->state != LOPLAYER_MENU_STATE_HIDDEN; -} - -bool loplayer_menu_is_exit_requested(const loplayer_menu_t* menu) { - assert(menu != NULL); - - return menu->request_exit; -} - -void loplayer_menu_pack(const loplayer_menu_t* menu, msgpack_packer* packer) { - assert(menu != NULL); - assert(packer != NULL); - - mpkutil_pack_bool(packer, menu->state != LOPLAYER_MENU_STATE_HIDDEN); -} - -bool loplayer_menu_unpack(loplayer_menu_t* menu, const msgpack_object* obj) { - assert(menu != NULL); - - bool shown = false; - if (!mpkutil_get_bool(obj, &shown)) return false; - - if (shown) loplayer_menu_show_status(menu); - return true; -} diff --git a/core/loplayer/menu.h b/core/loplayer/menu.h deleted file mode 100644 index 5312551..0000000 --- a/core/loplayer/menu.h +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#include - -#include - -#include "core/locommon/ticker.h" -#include "core/loeffect/stance.h" -#include "core/loresource/set.h" -#include "core/loshader/set.h" - -#include "./controller.h" -#include "./entity.h" -#include "./status.h" - -struct loplayer_menu_t; -typedef struct loplayer_menu_t loplayer_menu_t; - -loplayer_menu_t* /* OWNERSHIP */ -loplayer_menu_new( - loresource_set_t* res, - loshader_set_t* shaders, - const locommon_ticker_t* ticker, - const loplayer_status_t* status, - const loplayer_controller_t* controller -); - -void -loplayer_menu_delete( - loplayer_menu_t* menu /* OWNERSHIP */ -); - -void -loplayer_menu_show_status( - loplayer_menu_t* menu -); - -void -loplayer_menu_show_status_with_stance_highlighted( - loplayer_menu_t* menu, - loeffect_stance_id_t id -); - -void -loplayer_menu_popup( - loplayer_menu_t* menu, - const char* title, - const char* text -); - -void -loplayer_menu_hide( - loplayer_menu_t* menu -); - -void -loplayer_menu_update( - loplayer_menu_t* menu -); - -void -loplayer_menu_draw_ui( - const loplayer_menu_t* menu -); - -bool -loplayer_menu_is_shown( - const loplayer_menu_t* menu -); - -bool -loplayer_menu_is_exit_requested( - const loplayer_menu_t* menu -); - -void -loplayer_menu_pack( - const loplayer_menu_t* menu, - msgpack_packer* packer -); - -bool -loplayer_menu_unpack( - loplayer_menu_t* menu, - const msgpack_object* obj /* NULLABLE */ -); diff --git a/core/loplayer/player.c b/core/loplayer/player.c index 83d2199..3e18749 100644 --- a/core/loplayer/player.c +++ b/core/loplayer/player.c @@ -1,183 +1,60 @@ #include "./player.h" #include -#include #include #include -#include -#include -#include #include -#include -#include "util/math/matrix.h" #include "util/mpkutil/get.h" #include "util/mpkutil/pack.h" -#include "core/lobullet/pool.h" #include "core/locommon/input.h" #include "core/locommon/position.h" +#include "core/locommon/screen.h" #include "core/locommon/ticker.h" #include "core/loentity/entity.h" #include "core/loentity/store.h" -#include "core/loshader/hud_bar.h" -#include "core/loshader/posteffect.h" -#include "core/loshader/set.h" -#include "./action.h" #include "./camera.h" #include "./combat.h" #include "./controller.h" -#include "./entity.h" #include "./event.h" -#include "./hud.h" -#include "./menu.h" -#include "./status.h" -#define LOPLAYER_COMBAT_ATTACK_RESERVE 32 +/* generated serializer */ +#include "core/loplayer/crial/player.h" void loplayer_initialize( loplayer_t* player, - loentity_id_t id, - loresource_set_t* res, - loshader_set_t* shaders, + const locommon_screen_t* screen, const locommon_ticker_t* ticker, - lobullet_pool_t* bullets, - loentity_store_t* entities, - const mat4_t* proj) { + loentity_store_t* entities) { assert(player != NULL); - assert(res != NULL); - assert(shaders != NULL); assert(ticker != NULL); - assert(bullets != NULL); assert(entities != NULL); - assert(mat4_valid(proj)); - *player = (typeof(*player)) { - .shaders = shaders, - }; + *player = (typeof(*player)) {0}; - player->event = loplayer_event_new( - res, - shaders); + loplayer_stance_set_initialize(&player->stances); + loplayer_stance_set_add(&player->stances, LOPLAYER_STANCE_MISSIONARY); - loplayer_status_initialize(&player->status, res, ticker); - - loplayer_entity_initialize( - &player->entity, - id, - res->sound, - shaders->drawer.character, - ticker, - entities, - player->event, - &player->status); - loentity_store_add(entities, &player->entity.super.super); - - player->combat = loplayer_combat_new( - res->sound, - shaders->drawer.combat_ring, - ticker, - entities, - &player->status, - &player->entity, - LOPLAYER_COMBAT_ATTACK_RESERVE); - - loplayer_controller_initialize(&player->controller); - - loplayer_camera_initialize( - &player->camera, - shaders, - ticker, - player->event, - &player->status, - &player->entity, - proj); - player->hud = loplayer_hud_new( - res, - shaders, - ticker, - player->event, - &player->status, - &player->entity); - player->menu = loplayer_menu_new( - res, - shaders, - ticker, - &player->status, - &player->controller); - - player->action = loplayer_action_new( - res, - ticker, - bullets, - entities, - player->event, - &player->status, - &player->entity, - player->combat, - &player->controller, - &player->camera, - player->hud, - player->menu); + loplayer_combat_initialize(&player->combat, ticker, entities); + loplayer_controller_initialize(&player->controller, ticker); + loplayer_camera_initialize(&player->camera, screen, ticker); + loplayer_event_initialize(&player->event, ticker); + loplayer_popup_initialize(&player->popup); } void loplayer_deinitialize(loplayer_t* player) { assert(player != NULL); - loplayer_action_delete(player->action); - - loplayer_menu_delete(player->menu); - loplayer_hud_delete(player->hud); + loplayer_popup_deinitialize(&player->popup); + loplayer_event_deinitialize(&player->event); loplayer_camera_deinitialize(&player->camera); - loplayer_controller_deinitialize(&player->controller); + loplayer_combat_deinitialize(&player->combat); - loplayer_combat_delete(player->combat); - - loplayer_entity_deinitialize(&player->entity); - loplayer_status_deinitialize(&player->status); - - loplayer_event_delete(player->event); -} - -void loplayer_popup(loplayer_t* player, const char* title, const char* text) { - assert(player != NULL); - - loplayer_action_start_menu_popup_state(player->action); - loplayer_menu_popup(player->menu, title, text); -} - -bool loplayer_attack( - loplayer_t* player, const loplayer_combat_attack_t* attack) { - assert(player != NULL); - assert(attack != NULL); - - return loplayer_combat_add_attack(player->combat, attack); -} - -void loplayer_touch_encephalon(loplayer_t* player) { - assert(player != NULL); - - loplayer_status_set_respawn_position( - &player->status, &player->entity.super.super.pos); - loplayer_status_reset(&player->status); -} - -void loplayer_gain_stance(loplayer_t* player, loeffect_stance_id_t id) { - assert(player != NULL); - - if (!loplayer_status_add_stance(&player->status, id)) return; - - loplayer_action_start_menu_popup_state(player->action); - loplayer_menu_show_status_with_stance_highlighted(player->menu, id); -} - -void loplayer_gain_faith(loplayer_t* player, float amount) { - assert(player != NULL); - - player->status.recipient.faith += amount; + loplayer_stance_set_deinitialize(&player->stances); } void loplayer_update( @@ -185,104 +62,29 @@ void loplayer_update( const locommon_input_t* input, const locommon_position_t* cursor) { assert(player != NULL); - assert(input != NULL); - assert(locommon_position_valid(cursor)); - loplayer_status_update(&player->status); - /* entity is updated through entity store. */ + loplayer_controller_handle_input(&player->controller, input, cursor); - loplayer_combat_update(player->combat); - - loplayer_camera_update(&player->camera); - loplayer_hud_update(player->hud); - loplayer_menu_update(player->menu); - - loplayer_controller_update(&player->controller, input, cursor); - loplayer_action_execute(player->action); -} - -void loplayer_draw(const loplayer_t* player) { - assert(player != NULL); - - loplayer_camera_draw(&player->camera); - loplayer_event_draw(player->event); - - loplayer_combat_draw_ui(player->combat); - loplayer_hud_draw_ui(player->hud); - loplayer_menu_draw_ui(player->menu); + loplayer_combat_drop_dead_attack(&player->combat); } void loplayer_pack(const loplayer_t* player, msgpack_packer* packer) { assert(player != NULL); assert(packer != NULL); - msgpack_pack_map(packer, 6); - - mpkutil_pack_str(packer, "status"); - loplayer_status_pack(&player->status, packer); + msgpack_pack_map(packer, CRIAL_PROPERTY_COUNT_+1); + CRIAL_SERIALIZER_; mpkutil_pack_str(packer, "entity"); - loplayer_entity_pack(&player->entity, packer); - - mpkutil_pack_str(packer, "combat"); - loplayer_combat_pack(player->combat, packer); - - mpkutil_pack_str(packer, "camera"); - loplayer_camera_pack(&player->camera, packer); - - mpkutil_pack_str(packer, "menu"); - loplayer_menu_pack(player->menu, packer); - - mpkutil_pack_str(packer, "action"); - loplayer_action_pack(player->action, packer); + loentity_pack((const loentity_t*) player->entity, packer); } bool loplayer_unpack(loplayer_t* player, const msgpack_object* obj) { assert(player != NULL); - if (obj == NULL) return false; - const msgpack_object_map* root = mpkutil_get_map(obj); + if (root == NULL) return false; -# define item_(v) mpkutil_get_map_item_by_str(root, v) - if (!loplayer_status_unpack(&player->status, item_("status")) || - !loplayer_entity_unpack(&player->entity, item_("entity")) || - !loplayer_combat_unpack( player->combat, item_("combat")) || - !loplayer_camera_unpack(&player->camera, item_("camera")) || - !loplayer_menu_unpack ( player->menu, item_("menu" )) || - !loplayer_action_unpack( player->action, item_("action"))) { - return false; - } -# undef item_ + CRIAL_DESERIALIZER_; return true; } - -void loplayer_test_packing(const loplayer_t* player) { - assert(player != NULL); - - msgpack_sbuffer buf; - msgpack_sbuffer_init(&buf); - - msgpack_packer pk; - msgpack_packer_init(&pk, &buf, msgpack_sbuffer_write); - - loplayer_pack(player, &pk); - - msgpack_unpacked upk; - msgpack_unpacked_init(&upk); - - size_t off = 0; - const msgpack_unpack_return r = - msgpack_unpack_next(&upk, buf.data, buf.size, &off); - if (r != MSGPACK_UNPACK_SUCCESS) { - fprintf(stderr, "player: invalid msgpack format\n"); - abort(); - } - if (!loplayer_unpack((loplayer_t*) player, &upk.data)) { - fprintf(stderr, "player: failed to unpack\n"); - abort(); - } - printf("player: packing test passed\n"); - msgpack_unpacked_destroy(&upk); - msgpack_sbuffer_destroy(&buf); -} diff --git a/core/loplayer/player.crial b/core/loplayer/player.crial new file mode 100644 index 0000000..652d823 --- /dev/null +++ b/core/loplayer/player.crial @@ -0,0 +1,14 @@ +/* CRIAL + SERIALIZER_BEGIN + mpkutil_pack_str(packer, "$name"); + $code_pack(&player->$name, packer); + END + DESERIALIZER_BEGIN + if (!$code_unpack( + &player->$name, mpkutil_get_map_item_by_str(root, "$name"))) { + return false; + } + END + PROPERTY stances = loplayer_stance_set + PROPERTY event = loplayer_event +*/ diff --git a/core/loplayer/player.h b/core/loplayer/player.h index 499b3f2..87741b3 100644 --- a/core/loplayer/player.h +++ b/core/loplayer/player.h @@ -4,57 +4,39 @@ #include -#include "util/math/matrix.h" - -#include "core/lobullet/pool.h" #include "core/locommon/input.h" #include "core/locommon/position.h" +#include "core/locommon/screen.h" #include "core/locommon/ticker.h" -#include "core/loeffect/stance.h" -#include "core/loentity/entity.h" #include "core/loentity/store.h" -#include "core/loresource/set.h" -#include "core/loshader/set.h" -#include "./action.h" #include "./camera.h" #include "./combat.h" #include "./controller.h" -#include "./entity.h" #include "./event.h" -#include "./hud.h" -#include "./menu.h" -#include "./status.h" +#include "./popup.h" +#include "./stance.h" + +typedef struct lochara_base_t lochara_base_t; typedef struct { - loshader_set_t* shaders; - - loplayer_event_t* event; - - loplayer_status_t status; - loplayer_entity_t entity; - - loplayer_combat_t* combat; + loplayer_stance_set_t stances; + loplayer_combat_t combat; loplayer_controller_t controller; + loplayer_camera_t camera; + loplayer_event_t event; + loplayer_popup_t popup; - loplayer_camera_t camera; - loplayer_hud_t* hud; - loplayer_menu_t* menu; - - loplayer_action_t* action; + lochara_base_t* entity; } loplayer_t; void loplayer_initialize( loplayer_t* player, - loentity_id_t id, - loresource_set_t* res, - loshader_set_t* shaders, + const locommon_screen_t* screen, const locommon_ticker_t* ticker, - lobullet_pool_t* bullets, - loentity_store_t* entities, - const mat4_t* proj + loentity_store_t* entities ); void @@ -62,46 +44,11 @@ loplayer_deinitialize( loplayer_t* player ); -void -loplayer_popup( - loplayer_t* player, - const char* title, - const char* text -); - -bool -loplayer_attack( - loplayer_t* player, - const loplayer_combat_attack_t* attack -); - -void -loplayer_touch_encephalon( - loplayer_t* player -); - -void -loplayer_gain_stance( - loplayer_t* player, - loeffect_stance_id_t id -); - -void -loplayer_gain_faith( - loplayer_t* player, - float amount -); - void loplayer_update( loplayer_t* player, - const locommon_input_t* input, - const locommon_position_t* cursor -); - -void -loplayer_draw( - const loplayer_t* player + const locommon_input_t* input, /* NULLABLE */ + const locommon_position_t* cursor /* NULLABLE */ ); void @@ -110,13 +57,9 @@ loplayer_pack( msgpack_packer* packer ); +/* WARNING: the entity must be unpacked manually */ bool loplayer_unpack( loplayer_t* player, const msgpack_object* obj /* NULLABLE */ ); - -void -loplayer_test_packing( - const loplayer_t* player -); diff --git a/core/loplayer/popup.c b/core/loplayer/popup.c new file mode 100644 index 0000000..e10038c --- /dev/null +++ b/core/loplayer/popup.c @@ -0,0 +1,53 @@ +#include "./popup.h" + +#include +#include +#include + +#include "./stance.h" + +static loplayer_popup_item_t* loplayer_popup_queue_empty_( + loplayer_popup_t* popup) { + assert(popup != NULL); + + const size_t next_tail = (popup->queue_tail+1)%LOPLAYER_POPUP_QUEUE_LENGTH; + if (next_tail == popup->queue_head) return NULL; + + const size_t i = popup->queue_tail; + popup->queue_tail = next_tail; + return &popup->queue[i]; +} + +void loplayer_popup_initialize(loplayer_popup_t* popup) { + assert(popup != NULL); + + *popup = (typeof(*popup)) {0}; +} + +void loplayer_popup_deinitialize(loplayer_popup_t* popup) { + assert(popup != NULL); + +} + +void loplayer_popup_queue_new_stance( + loplayer_popup_t* popup, loplayer_stance_t stance) { + assert(popup != NULL); + + loplayer_popup_item_t* item = loplayer_popup_queue_empty_(popup); + if (item == NULL) return; + + *item = (typeof(*item)) { + .type = LOPLAYER_POPUP_ITEM_TYPE_NEW_STANCE, + .stance = stance, + }; +} + +const loplayer_popup_item_t* loplayer_popup_enqueue(loplayer_popup_t* popup) { + assert(popup != NULL); + + if (popup->queue_tail == popup->queue_head) return NULL; + + const size_t i = popup->queue_head; + popup->queue_head = (popup->queue_head+1)%LOPLAYER_POPUP_QUEUE_LENGTH; + return &popup->queue[i]; +} diff --git a/core/loplayer/popup.h b/core/loplayer/popup.h new file mode 100644 index 0000000..3f41108 --- /dev/null +++ b/core/loplayer/popup.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +#include "./stance.h" + +typedef enum { + LOPLAYER_POPUP_ITEM_TYPE_NEW_STANCE, +} loplayer_popup_item_type_t; + +typedef struct { + loplayer_popup_item_type_t type; + union { + loplayer_stance_t stance; + }; +} loplayer_popup_item_t; + +typedef struct { +# define LOPLAYER_POPUP_QUEUE_LENGTH 32 + loplayer_popup_item_t queue[LOPLAYER_POPUP_QUEUE_LENGTH]; + + size_t queue_tail; + size_t queue_head; + + uint64_t last_enqueue; +} loplayer_popup_t; + +void +loplayer_popup_initialize( + loplayer_popup_t* popup +); + +void +loplayer_popup_deinitialize( + loplayer_popup_t* popup +); + +void +loplayer_popup_queue_new_stance( + loplayer_popup_t* popup, + loplayer_stance_t stance +); + +const loplayer_popup_item_t* +loplayer_popup_enqueue( + loplayer_popup_t* popup +); diff --git a/core/loplayer/stance.c b/core/loplayer/stance.c new file mode 100644 index 0000000..cd02e2f --- /dev/null +++ b/core/loplayer/stance.c @@ -0,0 +1,103 @@ +#include "./stance.h" + +#include +#include +#include +#include +#include + +#include "util/mpkutil/get.h" +#include "util/mpkutil/pack.h" + +#include "core/loshader/menu_stance.h" + +loshader_menu_stance_id_t loplayer_stance_get_menu_shader_id( + loplayer_stance_t stance) { +# define each_(NAME, name) do {\ + if (stance == LOPLAYER_STANCE_##NAME) { \ + return LOSHADER_MENU_STANCE_ID_##NAME; \ + } \ + } while (0) + + LOPLAYER_STANCE_EACH(each_); + + assert(false); + return LOSHADER_MENU_STANCE_ID_EMPTY; + +# undef each_ +} + +void loplayer_stance_set_initialize(loplayer_stance_set_t* set) { + assert(set != NULL); + + *set = 0; +} + +void loplayer_stance_set_deinitialize(loplayer_stance_set_t* set) { + assert(set != NULL); + +} + +void loplayer_stance_set_add( + loplayer_stance_set_t* set, loplayer_stance_t stance) { + assert(set != NULL); + + *set |= 1 << stance; +} + +void loplayer_stance_set_remove( + loplayer_stance_set_t* set, loplayer_stance_t stance) { + assert(set != NULL); + + *set &= ~(1 << stance); +} + +bool loplayer_stance_set_has( + const loplayer_stance_set_t* set, loplayer_stance_t stance) { + assert(set != NULL); + + return *set & (1 << stance); +} + +void loplayer_stance_set_pack( + const loplayer_stance_set_t* set, msgpack_packer* packer) { + assert(set != NULL); + assert(packer != NULL); + + loplayer_stance_t mask = 1; + size_t len = 0; + while (mask <= *set) { + len += !!(*set & mask); + mask <<= 1; + } + msgpack_pack_array(packer, len); + + mask = 1; + size_t i = 0; + while (*set >= mask) { + if (*set & mask) { + mpkutil_pack_str(packer, loplayer_stance_stringify(i)); + } + ++i; + mask <<= 1; + } +} + +bool loplayer_stance_set_unpack( + loplayer_stance_set_t* set, const msgpack_object* obj) { + assert(set != NULL); + + const msgpack_object_array* array = mpkutil_get_array(obj); + if (array == NULL) return false; + + for (size_t i = 0; i < array->size; ++i) { + size_t len; + const char* name; + if (!mpkutil_get_str(&array->ptr[i], &name, &len)) continue; + + loplayer_stance_t stance; + if (!loplayer_stance_unstringify(&stance, name, len)) continue; + *set |= 1 << stance; + } + return true; +} diff --git a/core/loplayer/stance.h b/core/loplayer/stance.h new file mode 100644 index 0000000..632ca2a --- /dev/null +++ b/core/loplayer/stance.h @@ -0,0 +1,81 @@ +#pragma once + +#include +#include +#include + +#include + +#include "core/loshader/menu_stance.h" + +typedef enum { + /* BENUM BEGIN loplayer_stance */ + LOPLAYER_STANCE_MISSIONARY, + LOPLAYER_STANCE_REVOLUTIONER, + LOPLAYER_STANCE_UNFINISHER, + LOPLAYER_STANCE_PHILOSOPHER, + LOPLAYER_STANCE_BETRAYER, + /* BENUM END */ +} loplayer_stance_t; + +#include "core/loplayer/benum/stance.h" +_Static_assert(LOPLAYER_STANCE_COUNT < 16, "too many stances"); + +typedef uint16_t loplayer_stance_set_t; + +const char* +loplayer_stance_stringify( + loplayer_stance_t stance +); + +bool +loplayer_stance_unstringify( + loplayer_stance_t* stance, + const char* str, + size_t len +); + +loshader_menu_stance_id_t +loplayer_stance_get_menu_shader_id( + loplayer_stance_t stance +); + +void +loplayer_stance_set_initialize( + loplayer_stance_set_t* set +); + +void +loplayer_stance_set_deinitialize( + loplayer_stance_set_t* set +); + +void +loplayer_stance_set_add( + loplayer_stance_set_t* set, + loplayer_stance_t stance +); + +void +loplayer_stance_set_remove( + loplayer_stance_set_t* set, + loplayer_stance_t stance +); + +bool +loplayer_stance_set_has( + const loplayer_stance_set_t* set, + loplayer_stance_t stance +); + +void +loplayer_stance_set_pack( + const loplayer_stance_set_t* set, + msgpack_packer* packer +); + +bool +loplayer_stance_set_unpack( + loplayer_stance_set_t* set, + const msgpack_object* obj +); diff --git a/core/loplayer/status.c b/core/loplayer/status.c deleted file mode 100644 index 34e1376..0000000 --- a/core/loplayer/status.c +++ /dev/null @@ -1,193 +0,0 @@ -#include "./status.h" - -#include -#include -#include -#include - -#include - -#include "util/math/algorithm.h" -#include "util/math/vector.h" -#include "util/mpkutil/get.h" -#include "util/mpkutil/pack.h" - -#include "core/locommon/easing.h" -#include "core/locommon/msgpack.h" -#include "core/locommon/position.h" -#include "core/locommon/ticker.h" -#include "core/loeffect/recipient.h" -#include "core/loeffect/stance.h" -#include "core/loresource/set.h" -#include "core/loresource/sound.h" - -static const loeffect_recipient_status_t loplayer_status_base_ = { - .attack = .3f, - .defence = .2f, - .speed = .3f, - .jump = 1.f, -}; - -#define LOPLAYER_STATUS_PARAM_TO_PACK_EACH_(PROC) do { \ - PROC("stances", stances); \ - PROC("madness", recipient.madness); \ - PROC("faith", recipient.faith); \ - PROC("effects", recipient.effects); \ - PROC("respawn-pos", respawn_pos); \ - PROC("last-damage-time", last_damage_time); \ - PROC("bullet-immune-until", bullet_immune_until); \ -} while (0) -#define LOPLAYER_STATUS_PARAM_TO_PACK_COUNT 7 - -#define LOPLAYER_STATUS_MADNESS_DYING_THRESHOLD .3f - -void loplayer_status_initialize( - loplayer_status_t* status, - loresource_set_t* res, - const locommon_ticker_t* ticker) { - assert(status != NULL); - assert(ticker != NULL); - - *status = (typeof(*status)) { - .res = res, - .ticker = ticker, - - .respawn_pos = locommon_position(0, 0, vec2(.5f, .5f)), - }; - - loeffect_stance_set_initialize(&status->stances); - - loeffect_recipient_initialize(&status->recipient, ticker); -} - -void loplayer_status_deinitialize(loplayer_status_t* status) { - assert(status != NULL); - - loeffect_stance_set_deinitialize(&status->stances); - loeffect_recipient_deinitialize(&status->recipient); -} - -void loplayer_status_reset(loplayer_status_t* status) { - assert(status != NULL); - - loeffect_recipient_reset(&status->recipient); -} - -bool loplayer_status_add_stance( - loplayer_status_t* status, loeffect_stance_id_t id) { - assert(status != NULL); - - if (loeffect_stance_set_has(&status->stances, id)) return false; - loeffect_stance_set_add(&status->stances, id); - return true; -} - -void loplayer_status_remove_stance( - loplayer_status_t* status, loeffect_stance_id_t id) { - assert(status != NULL); - - loeffect_stance_set_remove(&status->stances, id); -} - -void loplayer_status_apply_effect( - loplayer_status_t* status, const loeffect_t* effect) { - assert(status != NULL); - assert(effect != NULL); - - if (effect->id == LOEFFECT_ID_IMMEDIATE_DAMAGE) { - status->last_damage_time = status->ticker->time; - loresource_sound_play(status->res->sound, "damage"); - } - - loeffect_recipient_apply_effect(&status->recipient, effect); -} - -void loplayer_status_update(loplayer_status_t* status) { - assert(status != NULL); - - static const uint64_t dying_sound_period = 4000; - - loeffect_recipient_status_t base = loplayer_status_base_; - if (loeffect_stance_set_has(&status->stances, LOEFFECT_STANCE_ID_PHILOSOPHER)) { - base.defence += .3f; - } - - loeffect_recipient_update(&status->recipient, &base); - - /* Makes decreasing madness faster if the player has a stance, UNFINISHER. */ - if (loeffect_stance_set_has( - &status->stances, LOEFFECT_STANCE_ID_UNFINISHER)) { - if (status->recipient.madness > 0) { - if (status->recipient.faith <= 0) { - status->recipient.madness -= status->ticker->delta_f/30; - status->recipient.last_damage = LOEFFECT_ID_LOST; - } else if (status->recipient.faith >= .5f) { - status->recipient.madness += status->ticker->delta_f/120; - } - } - } - - if (status->recipient.madness > 0 && - status->recipient.madness <= LOPLAYER_STATUS_MADNESS_DYING_THRESHOLD) { - uint64_t t = status->ticker->time; - uint64_t pt = t - status->ticker->delta; - - status->dying_effect = t%dying_sound_period*1.f / dying_sound_period; - - t /= dying_sound_period; - pt /= dying_sound_period; - - if (t != pt) loresource_sound_play(status->res->sound, "dying"); - } else { - locommon_easing_linear_float( - &status->dying_effect, 0, status->ticker->delta_f*5); - } -} - -void loplayer_status_set_respawn_position( - loplayer_status_t* status, const locommon_position_t* pos) { - assert(status != NULL); - assert(locommon_position_valid(pos)); - - status->respawn_pos = *pos; -} - -void loplayer_status_pack( - const loplayer_status_t* status, msgpack_packer* packer) { - assert(status != NULL); - assert(packer != NULL); - - msgpack_pack_map(packer, LOPLAYER_STATUS_PARAM_TO_PACK_COUNT); - -# define pack_(name, var) do { \ - mpkutil_pack_str(packer, name); \ - LOCOMMON_MSGPACK_PACK_ANY(packer, &status->var); \ - } while (0) - - LOPLAYER_STATUS_PARAM_TO_PACK_EACH_(pack_); - -# undef pack_ -} - -bool loplayer_status_unpack( - loplayer_status_t* status, const msgpack_object* obj) { - assert(status != NULL); - - if (obj == NULL) return false; - - const msgpack_object_map* root = mpkutil_get_map(obj); - -# define item_(v) mpkutil_get_map_item_by_str(root, v) - -# define unpack_(name, var) do { \ - if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &status->var)) { \ - return false; \ - } \ - } while (0) - - LOPLAYER_STATUS_PARAM_TO_PACK_EACH_(unpack_); - return true; - -# undef unpack_ -# undef item_ -} diff --git a/core/loplayer/status.h b/core/loplayer/status.h deleted file mode 100644 index 8c5d261..0000000 --- a/core/loplayer/status.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "util/math/vector.h" - -#include "core/locommon/position.h" -#include "core/locommon/ticker.h" -#include "core/loeffect/recipient.h" -#include "core/loeffect/stance.h" -#include "core/loresource/set.h" - -typedef struct { - loresource_set_t* res; - const locommon_ticker_t* ticker; - - loeffect_stance_set_t stances; - loeffect_recipient_t recipient; - - locommon_position_t respawn_pos; - - uint64_t last_damage_time; - uint64_t bullet_immune_until; - - float dying_effect; /* 0~1 */ -} loplayer_status_t; - -void -loplayer_status_initialize( - loplayer_status_t* status, - loresource_set_t* res, - const locommon_ticker_t* ticker -); - -void -loplayer_status_deinitialize( - loplayer_status_t* status -); - -void -loplayer_status_reset( - loplayer_status_t* status -); - -bool -loplayer_status_add_stance( - loplayer_status_t* status, - loeffect_stance_id_t id -); - -void -loplayer_status_remove_stance( - loplayer_status_t* status, - loeffect_stance_id_t id -); - -void -loplayer_status_apply_effect( - loplayer_status_t* status, - const loeffect_t* effect -); - -void -loplayer_status_update( - loplayer_status_t* status -); - -void -loplayer_status_set_respawn_position( - loplayer_status_t* status, - const locommon_position_t* pos -); - -void -loplayer_status_pack( - const loplayer_status_t* status, - msgpack_packer* packer -); - -bool -loplayer_status_unpack( - loplayer_status_t* status, - const msgpack_object* obj -); diff --git a/core/loresource/CMakeLists.txt b/core/loresource/CMakeLists.txt index 5bcd7b8..9e558e0 100644 --- a/core/loresource/CMakeLists.txt +++ b/core/loresource/CMakeLists.txt @@ -6,6 +6,10 @@ add_library(loresource sound.c text.c ) +target_benum_sources(loresource + music.h + sound.h +) target_any_sources(loresource font/sans.woff font/serif.woff @@ -36,5 +40,4 @@ target_link_libraries(loresource glyphas jukebox math - memory ) diff --git a/core/loresource/font.c b/core/loresource/font.c index 81fe60d..a985fe7 100644 --- a/core/loresource/font.c +++ b/core/loresource/font.c @@ -7,8 +7,8 @@ #include "util/glyphas/face.h" /* resources */ -#include "anysrc/font/sans.woff.h" -#include "anysrc/font/serif.woff.h" +#include "core/loresource/anysrc/font/sans.woff.h" +#include "core/loresource/anysrc/font/serif.woff.h" void loresource_font_initialize(loresource_font_t* font) { assert(font != NULL); diff --git a/core/loresource/music.c b/core/loresource/music.c index 3da6f09..7495f09 100644 --- a/core/loresource/music.c +++ b/core/loresource/music.c @@ -2,100 +2,90 @@ #include #include -#include -#include -#include #include "util/jukebox/amp.h" #include "util/jukebox/composite.h" #include "util/jukebox/decoder.h" #include "util/jukebox/format.h" #include "util/jukebox/mixer.h" -#include "util/math/rational.h" /* resources */ -#include "anysrc/music/biome_boss.mp3.h" -#include "anysrc/music/biome_cavias_camp.mp3.h" -#include "anysrc/music/biome_laboratory.mp3.h" -#include "anysrc/music/biome_metaphysical_gate.mp3.h" -#include "anysrc/music/boss_big_warder.mp3.h" -#include "anysrc/music/boss_greedy_scientist.mp3.h" -#include "anysrc/music/boss_theists_child.mp3.h" -#include "anysrc/music/boss_theists_child.mp3.h" -#include "anysrc/music/title.mp3.h" +#include "core/loresource/anysrc/music/biome_boss.mp3.h" +#include "core/loresource/anysrc/music/biome_cavias_camp.mp3.h" +#include "core/loresource/anysrc/music/biome_laboratory.mp3.h" +#include "core/loresource/anysrc/music/biome_metaphysical_gate.mp3.h" +#include "core/loresource/anysrc/music/boss_big_warder.mp3.h" +#include "core/loresource/anysrc/music/boss_greedy_scientist.mp3.h" +#include "core/loresource/anysrc/music/boss_theists_child.mp3.h" +#include "core/loresource/anysrc/music/boss_theists_child.mp3.h" +#include "core/loresource/anysrc/music/title.mp3.h" -#define LORESOURCE_MUSIC_EACH_(PROC) do { \ - PROC(biome_boss); \ - PROC(biome_cavias_camp); \ - PROC(biome_laboratory); \ - PROC(biome_metaphysical_gate); \ - PROC(boss_big_warder); \ - PROC(boss_greedy_scientist); \ - PROC(boss_theists_child); \ - PROC(title); \ -} while (0) - -static void loresource_music_player_initialize_( - loresource_music_player_t* p, - const jukebox_format_t* format, - const void* buf, - size_t len) { - assert(p != NULL); +static void loresource_music_initialize_( + loresource_music_t* m, + const jukebox_format_t* format, + const void* buf, + size_t len) { + assert(m != NULL); assert(jukebox_format_valid(format)); assert(buf != NULL || len == 0); - *p = (typeof(*p)) { + *m = (typeof(*m)) { .decoder = jukebox_decoder_new_from_memory_mp3(format, buf, len), .compo = jukebox_composite_new(format, 2), }; - jukebox_amp_initialize(&p->amp, format); + jukebox_amp_initialize(&m->amp, format); - jukebox_composite_add_effect(p->compo, (jukebox_effect_t*) p->decoder); - jukebox_composite_add_effect(p->compo, (jukebox_effect_t*) &p->amp); - jukebox_composite_play(p->compo); + jukebox_composite_add_effect(m->compo, (jukebox_effect_t*) m->decoder); + jukebox_composite_add_effect(m->compo, (jukebox_effect_t*) &m->amp); + jukebox_composite_play(m->compo); +} +static void loresource_music_deinitialize_(loresource_music_t* m) { + assert(m != NULL); + + jukebox_composite_delete(m->compo); + jukebox_amp_deinitialize(&m->amp); + jukebox_decoder_delete(m->decoder); } -static void loresource_music_player_deinitialize_( - loresource_music_player_t* p) { - assert(p != NULL); - - jukebox_composite_delete(p->compo); - jukebox_amp_deinitialize(&p->amp); - jukebox_decoder_delete(p->decoder); -} - -void loresource_music_initialize( - loresource_music_t* music, +void loresource_music_set_initialize( + loresource_music_set_t* set, jukebox_mixer_t* mixer, const jukebox_format_t* format) { - assert(music != NULL); + assert(set != NULL); assert(mixer != NULL); assert(jukebox_format_valid(format)); - *music = (typeof(*music)) {0}; + *set = (typeof(*set)) {0}; -# define each_(n) do { \ - loresource_music_player_initialize_( \ - &music->n, \ +# define each_(N, n) do { \ + loresource_music_t* p = \ + &set->items[LORESOURCE_MUSIC_ID_##N]; \ + *p = (typeof(*p)) { \ + .id = LORESOURCE_MUSIC_ID_##N, \ + .name = #N, \ + }; \ + loresource_music_initialize_( \ + p, \ format, \ loresource_music_##n##_mp3_, \ sizeof(loresource_music_##n##_mp3_)); \ - jukebox_mixer_add_effect(mixer, (jukebox_effect_t*) music->n.compo); \ + jukebox_mixer_add_effect(mixer, (jukebox_effect_t*) p->compo); \ } while (0) - - LORESOURCE_MUSIC_EACH_(each_); - + LORESOURCE_MUSIC_ID_EACH(each_); # undef each_ } -void loresource_music_deinitialize(loresource_music_t* music) { - assert(music != NULL); +void loresource_music_set_deinitialize(loresource_music_set_t* set) { + assert(set != NULL); -# define each_(n) do { \ - loresource_music_player_deinitialize_(&music->n); \ - } while (0) - - LORESOURCE_MUSIC_EACH_(each_); - -# undef each_ + for (size_t i = 0; i < LORESOURCE_MUSIC_ID_COUNT; ++i) { + loresource_music_deinitialize_(&set->items[i]); + } +} + +loresource_music_t* loresource_music_set_get( + loresource_music_set_t* set, loresource_music_id_t id) { + assert(set != NULL); + + return &set->items[id]; } diff --git a/core/loresource/music.h b/core/loresource/music.h index 9952dae..fbb132f 100644 --- a/core/loresource/music.h +++ b/core/loresource/music.h @@ -4,35 +4,49 @@ #include "util/jukebox/composite.h" #include "util/jukebox/decoder.h" #include "util/jukebox/mixer.h" -#include "util/math/rational.h" + +typedef enum { + /* BENUM BEGIN loresource_music_id */ + LORESOURCE_MUSIC_ID_BIOME_BOSS, + LORESOURCE_MUSIC_ID_BIOME_CAVIAS_CAMP, + LORESOURCE_MUSIC_ID_BIOME_METAPHYSICAL_GATE, + LORESOURCE_MUSIC_ID_BIOME_LABORATORY, + LORESOURCE_MUSIC_ID_BOSS_BIG_WARDER, + LORESOURCE_MUSIC_ID_BOSS_GREEDY_SCIENTIST, + LORESOURCE_MUSIC_ID_BOSS_THEISTS_CHILD, + LORESOURCE_MUSIC_ID_TITLE, + /* BENUM END */ +} loresource_music_id_t; + +#include "core/loresource/benum/music.h" typedef struct { + loresource_music_id_t id; + const char* name; + jukebox_decoder_t* decoder; jukebox_amp_t amp; jukebox_composite_t* compo; -} loresource_music_player_t; - -struct loresource_music_t; -typedef struct { - loresource_music_player_t - biome_boss, - biome_cavias_camp, - biome_metaphysical_gate, - biome_laboratory, - boss_big_warder, - boss_greedy_scientist, - boss_theists_child, - title; } loresource_music_t; +typedef struct { + loresource_music_t items[LORESOURCE_MUSIC_ID_COUNT]; +} loresource_music_set_t; + void -loresource_music_initialize( - loresource_music_t* music, +loresource_music_set_initialize( + loresource_music_set_t* set, jukebox_mixer_t* mixer, const jukebox_format_t* format ); void -loresource_music_deinitialize( - loresource_music_t* music +loresource_music_set_deinitialize( + loresource_music_set_t* set +); + +loresource_music_t* +loresource_music_set_get( + loresource_music_set_t* set, + loresource_music_id_t id ); diff --git a/core/loresource/set.c b/core/loresource/set.c index 8f513de..1404309 100644 --- a/core/loresource/set.c +++ b/core/loresource/set.c @@ -21,10 +21,10 @@ void loresource_set_initialize( assert(mixer != NULL); assert(jukebox_format_valid(format)); - *res = (typeof(*res)) { - .sound = loresource_sound_new(mixer, format), - }; - loresource_music_initialize(&res->music, mixer, format); + *res = (typeof(*res)) {0}; + + loresource_sound_set_initialize(&res->sound, mixer, format); + loresource_music_set_initialize(&res->music, mixer, format); loresource_font_initialize(&res->font); loresource_set_change_language(res, lang); } @@ -33,8 +33,8 @@ void loresource_set_deinitialize(loresource_set_t* res) { assert(res != NULL); loresource_font_deinitialize(&res->font); - loresource_sound_delete(res->sound); - loresource_music_deinitialize(&res->music); + loresource_music_set_deinitialize(&res->music); + loresource_sound_set_deinitialize(&res->sound); } void loresource_set_change_language( diff --git a/core/loresource/set.h b/core/loresource/set.h index 0198f24..ab05a7e 100644 --- a/core/loresource/set.h +++ b/core/loresource/set.h @@ -9,9 +9,9 @@ #include "./sound.h" typedef struct { - loresource_sound_t* sound; - loresource_music_t music; - loresource_font_t font; + loresource_sound_set_t sound; + loresource_music_set_t music; + loresource_font_t font; loresource_language_t lang; } loresource_set_t; diff --git a/core/loresource/sound.c b/core/loresource/sound.c index 46c05b7..5db6068 100644 --- a/core/loresource/sound.c +++ b/core/loresource/sound.c @@ -12,252 +12,201 @@ #include "util/jukebox/sound.h" #include "util/math/algorithm.h" #include "util/math/rational.h" -#include "util/memory/memory.h" /* resources */ -#include "anysrc/sound/bomb.mp3.h" -#include "anysrc/sound/enemy_shoot.mp3.h" -#include "anysrc/sound/enemy_trigger.mp3.h" -#include "anysrc/sound/damage.mp3.h" -#include "anysrc/sound/dodge.mp3.h" -#include "anysrc/sound/dying.mp3.h" -#include "anysrc/sound/guard.mp3.h" -#include "anysrc/sound/player_shoot.mp3.h" -#include "anysrc/sound/player_trigger.mp3.h" -#include "anysrc/sound/reflection.mp3.h" -#include "anysrc/sound/touch_gate.mp3.h" +#include "core/loresource/anysrc/sound/bomb.mp3.h" +#include "core/loresource/anysrc/sound/enemy_shoot.mp3.h" +#include "core/loresource/anysrc/sound/enemy_trigger.mp3.h" +#include "core/loresource/anysrc/sound/damage.mp3.h" +#include "core/loresource/anysrc/sound/dodge.mp3.h" +#include "core/loresource/anysrc/sound/dying.mp3.h" +#include "core/loresource/anysrc/sound/guard.mp3.h" +#include "core/loresource/anysrc/sound/player_shoot.mp3.h" +#include "core/loresource/anysrc/sound/player_trigger.mp3.h" +#include "core/loresource/anysrc/sound/reflection.mp3.h" +#include "core/loresource/anysrc/sound/touch_gate.mp3.h" -#define LORESOURCE_SOUND_DECL_(PROC) \ - PROC(bomb); \ - PROC(enemy_shoot); \ - PROC(enemy_trigger); \ - PROC(damage); \ - PROC(dodge); \ - PROC(dying); \ - PROC(guard); \ - PROC(player_shoot); \ - PROC(player_trigger); \ - PROC(reflection); \ - PROC(touch_gate); +#define MAX_CONCURRENT_PLAYS_ 32 -#define LORESOURCE_SOUND_EACH_(PROC) do { \ - LORESOURCE_SOUND_DECL_(PROC) \ -} while (0) - -struct loresource_sound_t { - struct { -# define each_(n) \ - jukebox_sound_buffer_t* n - - LORESOURCE_SOUND_DECL_(each_); - -# undef each_ - } buffers; - - struct { -# define each_(n) \ - jukebox_sound_t* n - - LORESOURCE_SOUND_DECL_(each_); - -# undef each_ - } sounds; - - struct { - jukebox_delay_t* delay; - jukebox_composite_t* compo; - } combat; - struct { - jukebox_delay_t* delay; - jukebox_composite_t* compo; - } env; - struct { - jukebox_composite_t* compo; - } direction; - - struct { - jukebox_amp_t amp; - jukebox_composite_t* compo; - } root; -}; - -#define LORESOURCE_SOUND_MAX_CONCURRENT_PLAY 32 - -static void loresource_sound_initialize_combat_( - loresource_sound_t* sound, +static void loresource_sound_set_initialize_combat_( + loresource_sound_set_t* set, jukebox_mixer_t* mixer, const jukebox_format_t* format) { - assert(sound != NULL); + assert(set != NULL); assert(mixer != NULL); assert(jukebox_format_valid(format)); - typeof(sound->sounds)* s = &sound->sounds; - typeof(sound->combat)* c = &sound->combat; + typeof(set->combat)* c = &set->combat; c->delay = jukebox_delay_new(format, &rational(5, 100), .1f, .4f); c->compo = jukebox_composite_new(format, 7); - jukebox_composite_add_effect(c->compo, (jukebox_effect_t*) s->damage); - jukebox_composite_add_effect(c->compo, (jukebox_effect_t*) s->dodge); - jukebox_composite_add_effect(c->compo, (jukebox_effect_t*) s->guard); - jukebox_composite_add_effect(c->compo, (jukebox_effect_t*) s->player_shoot); - jukebox_composite_add_effect(c->compo, (jukebox_effect_t*) s->player_trigger); - jukebox_composite_add_effect(c->compo, (jukebox_effect_t*) s->reflection); - jukebox_composite_add_effect(c->compo, (jukebox_effect_t*) c->delay); +# define add_(NAME) \ + jukebox_composite_add_effect( \ + c->compo, \ + (jukebox_effect_t*) set->items[LORESOURCE_SOUND_ID_##NAME].sound) + add_(DAMAGE); + add_(DODGE); + add_(GUARD); + add_(PLAYER_SHOOT); + add_(PLAYER_TRIGGER); + add_(REFLECTION); +# undef add_ + jukebox_composite_add_effect(c->compo, (jukebox_effect_t*) c->delay); jukebox_composite_play(c->compo); } -static void loresource_sound_deinitialize_combat_(loresource_sound_t* sound) { - assert(sound != NULL); +static void loresource_sound_set_deinitialize_combat_( + loresource_sound_set_t* set) { + assert(set != NULL); - typeof(sound->combat)* c = &sound->combat; + typeof(set->combat)* c = &set->combat; jukebox_composite_delete(c->compo); jukebox_delay_delete(c->delay); } -static void loresource_sound_initialize_env_( - loresource_sound_t* sound, +static void loresource_sound_set_initialize_env_( + loresource_sound_set_t* set, jukebox_mixer_t* mixer, const jukebox_format_t* format) { - assert(sound != NULL); + assert(set != NULL); assert(mixer != NULL); assert(jukebox_format_valid(format)); - typeof(sound->sounds)* s = &sound->sounds; - typeof(sound->env)* e = &sound->env; + typeof(set->env)* e = &set->env; e->delay = jukebox_delay_new(format, &rational(1, 10), .3f, .4f); e->compo = jukebox_composite_new(format, 5); - jukebox_composite_add_effect(e->compo, (jukebox_effect_t*) s->bomb); - jukebox_composite_add_effect(e->compo, (jukebox_effect_t*) s->enemy_shoot); - jukebox_composite_add_effect(e->compo, (jukebox_effect_t*) s->enemy_trigger); - jukebox_composite_add_effect(e->compo, (jukebox_effect_t*) s->touch_gate); - jukebox_composite_add_effect(e->compo, (jukebox_effect_t*) e->delay); +# define add_(NAME) \ + jukebox_composite_add_effect( \ + e->compo, \ + (jukebox_effect_t*) set->items[LORESOURCE_SOUND_ID_##NAME].sound) + add_(BOMB); + add_(ENEMY_SHOOT); + add_(ENEMY_TRIGGER); + add_(TOUCH_GATE); +# undef add_ + jukebox_composite_add_effect(e->compo, (jukebox_effect_t*) e->delay); jukebox_composite_play(e->compo); } -static void loresource_sound_deinitialize_env_(loresource_sound_t* sound) { - assert(sound != NULL); +static void loresource_sound_set_deinitialize_env_( + loresource_sound_set_t* set) { + assert(set != NULL); - typeof(sound->env)* e = &sound->env; + typeof(set->env)* e = &set->env; jukebox_composite_delete(e->compo); jukebox_delay_delete(e->delay); } -static void loresource_sound_initialize_direction_( - loresource_sound_t* sound, +static void loresource_sound_set_initialize_direction_( + loresource_sound_set_t* set, jukebox_mixer_t* mixer, const jukebox_format_t* format) { - assert(sound != NULL); + assert(set != NULL); assert(mixer != NULL); assert(jukebox_format_valid(format)); - typeof(sound->sounds)* s = &sound->sounds; - typeof(sound->direction)* d = &sound->direction; + typeof(set->direction)* d = &set->direction; d->compo = jukebox_composite_new(format, 1); - jukebox_composite_add_effect(d->compo, (jukebox_effect_t*) s->dying); + +# define add_(NAME) \ + jukebox_composite_add_effect( \ + d->compo, \ + (jukebox_effect_t*) set->items[LORESOURCE_SOUND_ID_##NAME].sound) + add_(DYING); +# undef add_ jukebox_composite_play(d->compo); } -static void loresource_sound_deinitialize_direction_(loresource_sound_t* sound) { - assert(sound != NULL); +static void loresource_sound_set_deinitialize_direction_( + loresource_sound_set_t* set) { + assert(set != NULL); - typeof(sound->direction)* d = &sound->direction; + typeof(set->direction)* d = &set->direction; jukebox_composite_delete(d->compo); } -loresource_sound_t* loresource_sound_new( - jukebox_mixer_t* mixer, const jukebox_format_t* format) { +void loresource_sound_set_initialize( + loresource_sound_set_t* set, + jukebox_mixer_t* mixer, + const jukebox_format_t* format) { + assert(set != NULL); assert(mixer != NULL); assert(jukebox_format_valid(format)); - loresource_sound_t* sound = memory_new(sizeof(*sound)); - *sound = (typeof(*sound)) {0}; + *set = (typeof(*set)) {0}; -# define each_(n) do { \ - sound->buffers.n = jukebox_sound_buffer_new_from_memory_mp3( \ +# define each_(NAME, name) do { \ + jukebox_sound_buffer_t* buf = jukebox_sound_buffer_new_from_memory_mp3( \ format, \ - loresource_sound_##n##_mp3_, \ - sizeof(loresource_sound_##n##_mp3_)); \ - sound->sounds.n = jukebox_sound_new( \ - sound->buffers.n, LORESOURCE_SOUND_MAX_CONCURRENT_PLAY); \ + loresource_sound_##name##_mp3_, \ + sizeof(loresource_sound_##name##_mp3_)); \ + jukebox_sound_t* snd = jukebox_sound_new(buf, MAX_CONCURRENT_PLAYS_); \ + set->items[LORESOURCE_SOUND_ID_##NAME] = (loresource_sound_t) { \ + .buffer = buf, \ + .sound = snd, \ + }; \ } while (0) - - LORESOURCE_SOUND_EACH_(each_); - + LORESOURCE_SOUND_ID_EACH(each_); # undef each_ - sound->root.compo = jukebox_composite_new(format, 4); + set->root.compo = jukebox_composite_new(format, 4); - loresource_sound_initialize_combat_(sound, mixer, format); + loresource_sound_set_initialize_combat_(set, mixer, format); jukebox_composite_add_effect( - sound->root.compo, (jukebox_effect_t*) sound->combat.compo); + set->root.compo, (jukebox_effect_t*) set->combat.compo); - loresource_sound_initialize_env_(sound, mixer, format); + loresource_sound_set_initialize_env_(set, mixer, format); jukebox_composite_add_effect( - sound->root.compo, (jukebox_effect_t*) sound->env.compo); + set->root.compo, (jukebox_effect_t*) set->env.compo); - loresource_sound_initialize_direction_(sound, mixer, format); + loresource_sound_set_initialize_direction_(set, mixer, format); jukebox_composite_add_effect( - sound->root.compo, (jukebox_effect_t*) sound->direction.compo); + set->root.compo, (jukebox_effect_t*) set->direction.compo); - jukebox_amp_initialize(&sound->root.amp, format); - jukebox_composite_add_effect(sound->root.compo, &sound->root.amp.super); + jukebox_amp_initialize(&set->root.amp, format); + jukebox_composite_add_effect(set->root.compo, &set->root.amp.super); - jukebox_amp_change_volume(&sound->root.amp, 1, &rational(1, 1)); - jukebox_composite_play(sound->root.compo); + jukebox_amp_change_volume(&set->root.amp, 1, &rational(1, 1)); + jukebox_composite_play(set->root.compo); - jukebox_mixer_add_effect(mixer, (jukebox_effect_t*) sound->root.compo); - return sound; + jukebox_mixer_add_effect(mixer, (jukebox_effect_t*) set->root.compo); } -void loresource_sound_delete(loresource_sound_t* sound) { - if (sound == NULL) return; +void loresource_sound_set_deinitialize(loresource_sound_set_t* set) { + assert(set != NULL); - jukebox_composite_delete(sound->root.compo); - jukebox_amp_deinitialize(&sound->root.amp); + jukebox_composite_delete(set->root.compo); + jukebox_amp_deinitialize(&set->root.amp); - loresource_sound_deinitialize_combat_(sound); - loresource_sound_deinitialize_env_(sound); - loresource_sound_deinitialize_direction_(sound); + loresource_sound_set_deinitialize_combat_(set); + loresource_sound_set_deinitialize_env_(set); + loresource_sound_set_deinitialize_direction_(set); -# define each_(n) do { \ - jukebox_sound_delete(sound->sounds.n); \ - jukebox_sound_buffer_delete(sound->buffers.n); \ - } while (0) - - LORESOURCE_SOUND_EACH_(each_); - -# undef each_ - - memory_delete(sound); + for (size_t i = 0; i < LORESOURCE_SOUND_ID_COUNT; ++i) { + jukebox_sound_delete(set->items[i].sound); + jukebox_sound_buffer_delete(set->items[i].buffer); + } } -void loresource_sound_play(loresource_sound_t* sound, const char* name) { - assert(sound != NULL); +void loresource_sound_set_play( + loresource_sound_set_t* set, loresource_sound_id_t id) { + assert(set != NULL); -# define each_(n) do { \ - if (strcmp(name, #n) == 0) { \ - jukebox_sound_play(sound->sounds.n); \ - return; \ - } \ - } while (0) - - LORESOURCE_SOUND_EACH_(each_); - -# undef each_ + jukebox_sound_play(set->items[id].sound); } -void loresource_sound_change_master_volume( - loresource_sound_t* sound, float v, const rational_t* duration) { - assert(sound != NULL); +void loresource_sound_set_change_master_volume( + loresource_sound_set_t* set, float v, const rational_t* duration) { + assert(set != NULL); assert(MATH_FLOAT_VALID(v)); assert(rational_valid(duration)); - jukebox_amp_change_volume(&sound->root.amp, v, duration); + jukebox_amp_change_volume(&set->root.amp, v, duration); } diff --git a/core/loresource/sound.h b/core/loresource/sound.h index 9054547..7d73433 100644 --- a/core/loresource/sound.h +++ b/core/loresource/sound.h @@ -2,33 +2,79 @@ #include +#include "util/jukebox/amp.h" +#include "util/jukebox/composite.h" +#include "util/jukebox/delay.h" #include "util/jukebox/format.h" #include "util/jukebox/mixer.h" +#include "util/jukebox/sound.h" #include "util/math/rational.h" -struct loresource_sound_t; -typedef struct loresource_sound_t loresource_sound_t; +typedef enum { + /* BENUM BEGIN loresource_sound_id */ + LORESOURCE_SOUND_ID_BOMB, + LORESOURCE_SOUND_ID_DAMAGE, + LORESOURCE_SOUND_ID_DODGE, + LORESOURCE_SOUND_ID_DYING, + LORESOURCE_SOUND_ID_ENEMY_SHOOT, + LORESOURCE_SOUND_ID_ENEMY_TRIGGER, + LORESOURCE_SOUND_ID_GUARD, + LORESOURCE_SOUND_ID_PLAYER_SHOOT, + LORESOURCE_SOUND_ID_PLAYER_TRIGGER, + LORESOURCE_SOUND_ID_REFLECTION, + LORESOURCE_SOUND_ID_TOUCH_GATE, + /* BENUM END */ +} loresource_sound_id_t; -loresource_sound_t* /* OWNERSHIP */ -loresource_sound_new( +#include "core/loresource/benum/sound.h" + +typedef struct { + jukebox_sound_buffer_t* buffer; + jukebox_sound_t* sound; +} loresource_sound_t; + +typedef struct { + loresource_sound_t items[LORESOURCE_SOUND_ID_COUNT]; + + struct { + jukebox_delay_t* delay; + jukebox_composite_t* compo; + } combat; + struct { + jukebox_delay_t* delay; + jukebox_composite_t* compo; + } env; + struct { + jukebox_composite_t* compo; + } direction; + + struct { + jukebox_amp_t amp; + jukebox_composite_t* compo; + } root; +} loresource_sound_set_t; + +void +loresource_sound_set_initialize( + loresource_sound_set_t* set, jukebox_mixer_t* mixer, const jukebox_format_t* format ); void -loresource_sound_delete( - loresource_sound_t* sound /* OWNERSHIP */ +loresource_sound_set_deinitialize( + loresource_sound_set_t* set ); void -loresource_sound_play( - loresource_sound_t* sound, - const char* name +loresource_sound_set_play( + loresource_sound_set_t* set, + loresource_sound_id_t id ); void -loresource_sound_change_master_volume( - loresource_sound_t* sound, - float v, - const rational_t* duration +loresource_sound_set_change_master_volume( + loresource_sound_set_t* set, + float v, + const rational_t* duration ); diff --git a/core/loresource/text/jp.h b/core/loresource/text/jp.h index 044d673..57e24ac 100644 --- a/core/loresource/text/jp.h +++ b/core/loresource/text/jp.h @@ -15,20 +15,30 @@ static dictres_item_t loresource_text_jp_[] = { {"biome_boss_big_warder", u8"巨頭の看守"}, {"biome_boss_greedy_scientist", u8"貪欲な科学者"}, - {"boss_big_warder_line0", u8"知能すら持たぬ家畜に踏み殺された仲間たちへの哀れみは"}, - {"boss_big_warder_line1", u8"いまや羨望へとその形を変えた"}, + {"boss_big_warder_line0", u8"知能すら持たぬ家畜に踏み殺された仲間たちへの哀れみは"}, + {"boss_big_warder_line1", u8"いまや羨望へとその形を変えた"}, + {"boss_big_warder_kill_line", u8"私はまだ待たなければならいのか"}, {"boss_greedy_scientist_line0", u8"その選択はお前自身のものか?"}, {"boss_greedy_scientist_line1", u8"胸を張ってそうだと,私達の前で言えるのか?"}, - {"boss_theists_child_line0", u8"全ては計画通りだった"}, - {"boss_theists_child_line1", u8"しかし空論は未だ宙に浮いたまま"}, - {"boss_theists_child_line2", u8"それが\"創造主\"の意志だというのか"}, + {"boss_theists_child_line0", u8"全ては計画通りだった"}, + {"boss_theists_child_line1", u8"しかし空論は未だ宙に浮いたまま"}, + {"boss_theists_child_line2", u8"それが\"創造主\"の意志だというのか"}, + {"boss_theists_child_dead_line", u8"またか,また,私は失敗したのか"}, + {"boss_theists_child_kill_line0", u8"私の邪魔をしないでくれ"}, + {"boss_theists_child_kill_line1", u8"承けた使命を果たさなきゃならない"}, {"effect_curse", u8"呪縛"}, {"effect_amnesia", u8"忘却"}, {"effect_lost", u8"喪失"}, + {"popup_new_stance_head", u8"NEW STANCE FOUND"}, + + {"stance_unknown_name", u8"???"}, + {"stance_unknown_desc", u8"???"}, + {"stance_unknown_note", u8"???"}, + {"stance_missionary_name", u8"宣教師"}, {"stance_missionary_desc", u8" あなたは自らの使命を果たすために歩き続ける.\n\n" @@ -57,12 +67,15 @@ static dictres_item_t loresource_text_jp_[] = { {"stance_unfinisher_name", u8"未完走者"}, {"stance_unfinisher_desc", u8" 幾度締め上げようと再生する細胞は永遠への敬遠と共に能力をもたらす.\n\n" - u8" - 信仰が50%以上残っている場合にあなたの狂気は徐々に回復する.\n" - u8" - 信仰をすべて失ったとき,狂気の減少速度が増加する."}, + u8" - 信仰が50%以上残っている場合にあなたの狂気は徐々に回復する."}, {"stance_unfinisher_note", u8"「忌々しい奴らに殺された仲間たちを,昔は気の毒だと思っていたよ." u8"今は妬みしか感じない.」"}, + {"stance_betrayer_name", u8"背信者"}, + {"stance_betrayer_desc", u8"NOT IMPLEMENTED"}, + {"stance_betrayer_note", u8"NOT IMPLEMENTED"}, + {"menu_exit", "EXIT"}, {"title_authors", u8"catfoot"}, diff --git a/core/loscene/CMakeLists.txt b/core/loscene/CMakeLists.txt index 94b424b..53f4569 100644 --- a/core/loscene/CMakeLists.txt +++ b/core/loscene/CMakeLists.txt @@ -16,8 +16,10 @@ target_link_libraries(loscene locommon loentity loground + loparticle loplayer loresource loshader + loui loworld ) diff --git a/core/loscene/context.c b/core/loscene/context.c index c6dfc14..3db6489 100644 --- a/core/loscene/context.c +++ b/core/loscene/context.c @@ -5,13 +5,14 @@ #include #include +#include "util/flasy/flasy.h" #include "util/glyphas/context.h" #include "util/jukebox/mixer.h" #include "util/math/algorithm.h" #include "util/math/vector.h" -#include "util/memory/memory.h" #include "core/locommon/input.h" +#include "core/locommon/screen.h" #include "core/locommon/ticker.h" #include "core/loresource/set.h" #include "core/loshader/set.h" @@ -21,21 +22,10 @@ #include "./scene.h" #include "./title.h" -struct loscene_context_t { - glyphas_context_t glyphas; - jukebox_mixer_t* mixer; +#define MIXER_RESERVE_ 256 - locommon_ticker_t ticker; - - loresource_set_t resources; - loshader_set_t shaders; - - loscene_t* scene; - - loscene_param_t param; -}; - -#define loscene_context_mixer_reserve_ 256 +#define FLASY_BUFSIZE_ (1024*4) /* = 4 KB */ +#define FLASY_HANDLERS_ 256 static const jukebox_format_t loscene_context_mixer_format_ = { .sample_rate = 48000, @@ -45,29 +35,32 @@ static const jukebox_format_t loscene_context_mixer_format_ = { static loscene_t* loscene_context_create_start_scene_(loscene_context_t* ctx) { assert(ctx != NULL); - /* Unless the context is deleted, scenes can hold a pointer to ctx->param. */ - if (ctx->param.skip_title) { - return loscene_game_new( - &ctx->param, &ctx->resources, &ctx->shaders, &ctx->ticker, true); + return loscene_game_new(ctx, true /* = load */); } - return loscene_title_new( - &ctx->param, &ctx->resources, &ctx->shaders, &ctx->ticker); + return loscene_title_new(ctx); } -loscene_context_t* loscene_context_new(const loscene_param_t* param) { +void loscene_context_initialize( + loscene_context_t* ctx, const loscene_param_t* param) { + assert(ctx != NULL); assert(param != NULL); - loscene_context_t* ctx = memory_new(sizeof(*ctx)); *ctx = (typeof(*ctx)) { .param = *param, }; + ctx->flasy = flasy_new(FLASY_BUFSIZE_, FLASY_HANDLERS_); + glyphas_context_initialize(&ctx->glyphas); ctx->mixer = jukebox_mixer_new( - &loscene_context_mixer_format_, loscene_context_mixer_reserve_); + &loscene_context_mixer_format_, MIXER_RESERVE_); + ctx->screen = (typeof(ctx->screen)) { + .resolution = vec2(param->width, param->height), + .dpi = param->dpi, + }; locommon_ticker_initialize(&ctx->ticker, 0); loresource_set_initialize( @@ -78,17 +71,14 @@ loscene_context_t* loscene_context_new(const loscene_param_t* param) { loshader_set_initialize( &ctx->shaders, - param->width, - param->height, - ¶m->dpi, + &ctx->screen, param->max_msaa); ctx->scene = loscene_context_create_start_scene_(ctx); - return ctx; } -void loscene_context_delete(loscene_context_t* ctx) { - if (ctx == NULL) return; +void loscene_context_deinitialize(loscene_context_t* ctx) { + assert(ctx != NULL); /* Firstly delete the mixer working in other thread. */ jukebox_mixer_delete(ctx->mixer); @@ -102,7 +92,7 @@ void loscene_context_delete(loscene_context_t* ctx) { glyphas_context_deinitialize(&ctx->glyphas); - memory_delete(ctx); + flasy_delete(ctx->flasy); } bool loscene_context_update( diff --git a/core/loscene/context.h b/core/loscene/context.h index 80da79f..452f6b8 100644 --- a/core/loscene/context.h +++ b/core/loscene/context.h @@ -3,23 +3,44 @@ #include #include +#include "util/flasy/flasy.h" +#include "util/glyphas/context.h" +#include "util/jukebox/mixer.h" #include "util/math/vector.h" #include "core/locommon/input.h" +#include "core/locommon/ticker.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" #include "./param.h" +#include "./scene.h" -struct loscene_context_t; -typedef struct loscene_context_t loscene_context_t; +typedef struct { + flasy_t* flasy; + glyphas_context_t glyphas; + jukebox_mixer_t* mixer; -loscene_context_t* /* OWNERSHIP */ -loscene_context_new( + locommon_screen_t screen; + locommon_ticker_t ticker; + + loresource_set_t resources; + loshader_set_t shaders; + + loscene_t* scene; + + loscene_param_t param; +} loscene_context_t; + +void +loscene_context_initialize( + loscene_context_t* ctx, const loscene_param_t* param ); void -loscene_context_delete( - loscene_context_t* ctx /* OWNERSHIP */ +loscene_context_deinitialize( + loscene_context_t* ctx ); bool diff --git a/core/loscene/game.c b/core/loscene/game.c index d65c845..c0e6a2f 100644 --- a/core/loscene/game.c +++ b/core/loscene/game.c @@ -18,23 +18,21 @@ #include "util/mpkutil/get.h" #include "util/mpkutil/pack.h" -#include "core/lobullet/pool.h" -#include "core/locharacter/pool.h" +#include "core/lochara/pool.h" +#include "core/lochara/player.h" #include "core/locommon/counter.h" +#include "core/locommon/screen.h" #include "core/locommon/ticker.h" #include "core/loentity/store.h" -#include "core/loground/pool.h" -#include "core/loplayer/camera.h" #include "core/loplayer/player.h" -#include "core/loresource/set.h" -#include "core/loshader/set.h" +#include "core/loui/ui.h" #include "core/loworld/environment.h" #include "core/loworld/generator.h" #include "core/loworld/poolset.h" #include "core/loworld/store.h" -#include "core/loworld/template.h" #include "core/loworld/view.h" +#include "./context.h" #include "./param.h" #include "./scene.h" #include "./title.h" @@ -42,10 +40,7 @@ typedef struct { loscene_t header; - const loscene_param_t* param; - const locommon_ticker_t* app_ticker; - loresource_set_t* res; - loshader_set_t* shaders; + loscene_context_t* ctx; uint64_t app_begin_time; uint64_t begin_time; @@ -54,7 +49,6 @@ typedef struct { locommon_ticker_t ticker; loentity_store_t* entities; - loplayer_t player; loworld_poolset_t pools; @@ -63,42 +57,21 @@ typedef struct { loworld_view_t* view; loworld_environment_t environment; - /* temporary parameters */ + loui_t ui; + bool updated; mat4_t proj; + mat4_t camera; } loscene_game_t; -#define LOSCENE_GAME_MAX_DELTA_TIME 500 +#define MAX_DELTA_TIME_ 500 -#define LOSCENE_GAME_SCALE 4.0f +#define ENTITY_STORE_RESERVE_ 256 +#define WORLD_STORE_CHUNK_RESERVE_ 64 -#define LOSCENE_GAME_ENTITY_STORE_RESERVE 256 -#define LOSCENE_GAME_WORLD_STORE_CHUNK_RESERVE 64 -#define LOSCENE_GAME_BULLETS_PER_CHUNK 64 - -#define LOSCENE_GAME_DATA_BASEPATH "./data/" - -#define LOSCENE_GAME_DATA_FILE_PATH \ - (LOSCENE_GAME_DATA_BASEPATH"game.msgpack") -#define LOSCENE_GAME_WORLD_STORE_BASEPATH \ - (LOSCENE_GAME_DATA_BASEPATH"world/") - -static void loscene_game_build_projection_matrix_(loscene_game_t* s) { - assert(s != NULL); - - static const float chunk_inch = 16; - static const float max_scale = 1/.5f; - - float yscale = s->shaders->dpi.y*chunk_inch/s->shaders->resolution.y*2; - float xscale = s->shaders->dpi.x*chunk_inch/s->shaders->resolution.x*2; - - if (xscale > max_scale) { - yscale *= max_scale/xscale; - xscale = max_scale; - } - - s->proj = mat4_scale(xscale, yscale, 1); -} +#define DATA_BASEPATH_ "./data/" +#define DATA_FILE_PATH_ DATA_BASEPATH_"game.msgpack" +#define WORLD_STORE_BASEPATH_ DATA_BASEPATH_"world/" static void loscene_game_convert_viewport_pos_to_chunk_pos_( loscene_game_t* s, locommon_position_t* pos, const vec2_t* vpos) { @@ -106,7 +79,7 @@ static void loscene_game_convert_viewport_pos_to_chunk_pos_( assert(locommon_position_valid(pos)); mat4_t m, inv; - mat4_mul(&m, &s->proj, &s->player.camera.matrix); + mat4_mul(&m, &s->proj, &mat4_identity()); mat4_inv(&inv, &m); vec4_t disp4; @@ -117,9 +90,8 @@ static void loscene_game_convert_viewport_pos_to_chunk_pos_( locommon_position_reduce(pos); } -static bool loscene_game_load_(loscene_game_t* scene) { - assert(scene != NULL); - /* ! Please note that world and view objects may be invalid now. ! */ +static bool loscene_game_load_(loscene_game_t* s) { + assert(s != NULL); bool ret = false; @@ -129,7 +101,7 @@ static bool loscene_game_load_(loscene_game_t* scene) { msgpack_unpacked unpacked; msgpack_unpacked_init(&unpacked); - FILE* fp = fopen(LOSCENE_GAME_DATA_FILE_PATH, "rb"); + FILE* fp = fopen(DATA_FILE_PATH_, "rb"); if (fp == NULL) goto FINALIZE; const bool loaded = @@ -141,10 +113,22 @@ static bool loscene_game_load_(loscene_game_t* scene) { # define item_(v) mpkutil_get_map_item_by_str(root, v) - if (!loplayer_unpack(&scene->player, item_("player")) || - !loworld_generator_unpack(scene->generator, item_("generator")) || - !locommon_ticker_unpack(&scene->ticker, item_("ticker")) || - !locommon_counter_unpack(&scene->idgen, item_("idgen"))) { + const msgpack_object* player = item_("player"); + s->player.entity = lochara_pool_unpack_item( + s->pools.chara, + mpkutil_get_map_item_by_str(mpkutil_get_map(player), "entity")); + if (s->player.entity == NULL) goto FINALIZE; + + if (s->player.entity->param.type != LOCHARA_TYPE_PLAYER) { + loentity_delete(&s->player.entity->super.super); + s->player.entity = NULL; + goto FINALIZE; + } + + if (!loplayer_unpack(&s->player, player) || + !loworld_generator_unpack(s->generator, item_("generator")) || + !locommon_ticker_unpack(&s->ticker, item_("ticker")) || + !locommon_counter_unpack(&s->idgen, item_("idgen"))) { goto FINALIZE; } @@ -155,7 +139,7 @@ FINALIZE: msgpack_unpacked_destroy(&unpacked); msgpack_unpacker_destroy(&unpacker); - scene->begin_time = scene->ticker.time; + s->begin_time = s->ticker.time; return ret; } @@ -167,7 +151,7 @@ static bool loscene_game_save_(loscene_game_t* scene) { loworld_view_flush_store(scene->view); if (loworld_store_is_error_happened(scene->world)) ret = false; - FILE* fp = fopen(LOSCENE_GAME_DATA_FILE_PATH, "wb"); + FILE* fp = fopen(DATA_FILE_PATH_, "wb"); if (fp == NULL) return false; msgpack_packer pk; @@ -199,19 +183,16 @@ static void loscene_game_delete_(loscene_t* scene) { fprintf(stderr, "failed to save game data\n"); } + loui_deinitialize(&s->ui); + loworld_environment_deinitialize(&s->environment); loworld_view_delete(s->view); loworld_store_delete(s->world); loworld_generator_delete(s->generator); loentity_store_clear(s->entities); - - locharacter_pool_delete(s->pools.character); + loworld_poolset_deinitialize(&s->pools); loplayer_deinitialize(&s->player); - - lobullet_pool_delete(s->pools.bullet); - loground_pool_delete(s->pools.ground); - loentity_store_delete(s->entities); locommon_ticker_deinitialize(&s->ticker); @@ -228,26 +209,34 @@ static loscene_t* loscene_game_update_( loscene_game_t* s = (typeof(s)) scene; s->updated = false; - const uint64_t t = s->app_ticker->time - s->app_begin_time + s->begin_time; + const uint64_t t = + s->ctx->ticker.time - s->app_begin_time + s->begin_time; locommon_ticker_tick(&s->ticker, t); - if (s->ticker.delta > LOSCENE_GAME_MAX_DELTA_TIME) { + if (s->ticker.delta > MAX_DELTA_TIME_) { fprintf(stderr, "1 tick took too long (%"PRId64" ms)\n", s->ticker.delta); return scene; } + s->player.camera.base_brightness = s->ctx->param.brightness; + loplayer_camera_build_matrix(&s->player.camera, &s->camera); + locommon_position_t cursor = s->player.camera.pos; loscene_game_convert_viewport_pos_to_chunk_pos_(s, &cursor, &input->cursor); - loplayer_update(&s->player, input, &cursor); - if (loplayer_menu_is_exit_requested(s->player.menu)) { - return loscene_title_new(s->param, s->res, s->shaders, s->app_ticker); - } + const bool grabbed = loui_is_grabbing_input(&s->ui); + loplayer_update( + &s->player, + grabbed? NULL: input, + grabbed? NULL: &cursor); loworld_view_look(s->view, &s->player.camera.pos); loworld_view_update(s->view); loworld_environment_update(&s->environment); + loui_update(&s->ui, input); + if (s->ui.menu.request_exit) return loscene_title_new(s->ctx); + s->updated = true; return scene; } @@ -258,51 +247,42 @@ static void loscene_game_draw_(loscene_t* scene) { loscene_game_t* s = (typeof(s)) scene; if (!s->updated) return; - const loshader_uniblock_param_t p = { - .proj = s->proj, - .cam = s->player.camera.matrix, - .pos = s->player.camera.pos, - .time = s->ticker.time%60000/1000.0f, - }; - loshader_uniblock_update_param(s->shaders->uniblock, &p); + loshader_posteffect_drawer_set_param( + &s->ctx->shaders.drawer.posteffect, + &(loshader_posteffect_drawer_param_t) { .brightness_whole = 1, }); - loshader_set_clear_all(s->shaders); + loshader_uniblock_update_param( + &s->ctx->shaders.uniblock, + &(loshader_uniblock_param_t) { + .proj = s->proj, + .cam = s->camera, + .pos = s->player.camera.pos, + .time = s->ticker.time%60000/1000.f, + }); + + loshader_set_clear_all(&s->ctx->shaders); + + s->ctx->shaders.drawer.pixsort.intensity = s->player.camera.pixsort; + loshader_posteffect_drawer_set_param( + &s->ctx->shaders.drawer.posteffect, &s->player.camera.posteffect); loworld_environment_draw(&s->environment); loworld_view_draw(s->view); - loplayer_draw(&s->player); - loshader_set_draw_all(s->shaders); -} + loui_draw(&s->ui); -static void loscene_game_execute_tests_( - const loscene_game_t* scene, const loscene_param_t* param) { - assert(scene != NULL); - assert(param != NULL); - - if (param->test.loworld_poolset_packing) { - loworld_poolset_test_packing(&scene->pools); - } - if (param->test.loplayer_packing) { - loplayer_test_packing(&scene->player); - } + loshader_set_draw_all(&s->ctx->shaders); } loscene_t* loscene_game_new( - const loscene_param_t* param, - loresource_set_t* res, - loshader_set_t* shaders, - const locommon_ticker_t* ticker, - bool load) { - assert(param != NULL); - assert(shaders != NULL); - assert(res != NULL); - assert(ticker != NULL); + loscene_context_t* ctx, + bool load) { + assert(ctx != NULL); - loshader_set_drop_cache(shaders); + loshader_set_drop_cache(&ctx->shaders); - loscene_game_t* scene = memory_new(sizeof(*scene)); - *scene = (typeof(*scene)) { + loscene_game_t* s = memory_new(sizeof(*s)); + *s = (typeof(*s)) { .header = { .vtable = { .delete = loscene_game_delete_, @@ -310,89 +290,80 @@ loscene_t* loscene_game_new( .draw = loscene_game_draw_, }, }, - .param = param, - .app_ticker = ticker, - .res = res, - .shaders = shaders, - .app_begin_time = ticker->time, + .ctx = ctx, + .app_begin_time = ctx->ticker.time, }; - loscene_game_build_projection_matrix_(scene); + locommon_screen_build_projection_matrix(&s->ctx->screen, &s->proj); - locommon_counter_initialize(&scene->idgen, 0); - locommon_ticker_initialize(&scene->ticker, 0); + locommon_counter_initialize(&s->idgen, 0); + locommon_ticker_initialize(&s->ticker, 0); - scene->entities = loentity_store_new( - LOSCENE_GAME_ENTITY_STORE_RESERVE); - - scene->pools.ground = loground_pool_new( - scene->shaders->drawer.ground, - &scene->idgen, - LOSCENE_GAME_WORLD_STORE_CHUNK_RESERVE* - LOWORLD_TEMPLATE_MAX_CHARACTERS_PER_CHUNK); - - scene->pools.bullet = lobullet_pool_new( - res, - scene->shaders->drawer.bullet, - &scene->idgen, - &scene->ticker, - scene->entities, - LOSCENE_GAME_WORLD_STORE_CHUNK_RESERVE* - LOSCENE_GAME_BULLETS_PER_CHUNK); + s->entities = loentity_store_new(ENTITY_STORE_RESERVE_); loplayer_initialize( - &scene->player, - locommon_counter_count(&scene->idgen), /* = Absolutely 0 */ - res, - scene->shaders, - &scene->ticker, - scene->pools.bullet, - scene->entities, - &scene->proj); - scene->player.camera.brightness = param->brightness/1000.f; + &s->player, + &s->ctx->screen, + &s->ticker, + s->entities); - scene->pools.character = locharacter_pool_new( - res, - scene->shaders->drawer.character, - &scene->idgen, - &scene->ticker, - scene->pools.bullet, - scene->entities, - &scene->player, - LOSCENE_GAME_WORLD_STORE_CHUNK_RESERVE* - LOWORLD_TEMPLATE_MAX_CHARACTERS_PER_CHUNK); + loworld_poolset_initialize( + &s->pools, + &s->ctx->resources, + &s->ctx->shaders, + &s->idgen, + &s->ticker, + s->entities, + &s->player, + WORLD_STORE_CHUNK_RESERVE_); - scene->generator = loworld_generator_new( - &scene->pools, - scene->app_ticker->time*98641 /* = prime number */); + /* id is always 0 */ + + s->generator = loworld_generator_new( + &s->pools, + s->ctx->ticker.time*98641 /* = prime number */); if (load) { - if (!loscene_game_load_(scene)) { - fprintf(stderr, "failed to load game data\n"); - } + load = loscene_game_load_(s); + if (!load) fprintf(stderr, "failed to load game data\n"); } + if (!load) { + locommon_counter_reset(&s->idgen); + s->player.entity = lochara_pool_create(s->pools.chara); + lochara_player_build(s->player.entity); + } + s->player.entity->super.super.dont_save = true; + loentity_store_add(s->entities, &s->player.entity->super.super); - scene->world = loworld_store_new( - &scene->pools, - scene->generator, - LOSCENE_GAME_WORLD_STORE_CHUNK_RESERVE, - LOSCENE_GAME_WORLD_STORE_BASEPATH, - strlen(LOSCENE_GAME_WORLD_STORE_BASEPATH)); + s->world = loworld_store_new( + s->ctx->flasy, + &s->pools, + s->generator, + WORLD_STORE_CHUNK_RESERVE_, + WORLD_STORE_BASEPATH_, + strlen(WORLD_STORE_BASEPATH_)); - scene->view = loworld_view_new( - scene->world, - scene->entities, - &scene->player.camera.pos); + s->view = loworld_view_new( + s->world, + s->entities, + &locommon_position(0, 0, vec2(.5f, .5f))); loworld_environment_initialize( - &scene->environment, - res, - scene->shaders, - &scene->ticker, - scene->view, - &scene->player, - ¶m->environment); + &s->environment, + &s->ctx->resources, + &s->ctx->shaders, + &s->ticker, + &s->player, + s->view, + &s->ctx->param.environment); - loscene_game_execute_tests_(scene, param); + loui_initialize( + &s->ui, + &s->ctx->resources, + &s->ctx->shaders, + &s->ctx->screen, + &s->ticker, + &s->player, + s->view); - return &scene->header; + return &s->header; } diff --git a/core/loscene/game.h b/core/loscene/game.h index e6c907f..4cabc0b 100644 --- a/core/loscene/game.h +++ b/core/loscene/game.h @@ -1,17 +1,12 @@ #pragma once -#include "core/locommon/ticker.h" -#include "core/loresource/set.h" -#include "core/loshader/set.h" +#include -#include "./param.h" +#include "./context.h" #include "./scene.h" loscene_t* /* OWNERSHIP */ loscene_game_new( - const loscene_param_t* param, - loresource_set_t* res, - loshader_set_t* shaders, - const locommon_ticker_t* ticker, - bool load + loscene_context_t* ctx, + bool load ); diff --git a/core/loscene/param.h b/core/loscene/param.h index 7510b2f..0fdcfd0 100644 --- a/core/loscene/param.h +++ b/core/loscene/param.h @@ -18,9 +18,4 @@ typedef struct { loworld_environment_config_t environment; bool skip_title; - - struct { - bool loworld_poolset_packing; - bool loplayer_packing; - } test; } loscene_param_t; diff --git a/core/loscene/title.c b/core/loscene/title.c index 10f387b..5a0e626 100644 --- a/core/loscene/title.c +++ b/core/loscene/title.c @@ -9,7 +9,6 @@ #include #include -#include "util/chaos/xorshift.h" #include "util/glyphas/block.h" #include "util/glyphas/cache.h" #include "util/jukebox/amp.h" @@ -22,13 +21,12 @@ #include "core/locommon/input.h" #include "core/locommon/position.h" #include "core/loresource/music.h" -#include "core/loresource/set.h" #include "core/loresource/text.h" #include "core/loshader/backwall.h" #include "core/loshader/fog.h" #include "core/loshader/menu_text.h" -#include "core/loshader/set.h" +#include "./context.h" #include "./game.h" #include "./param.h" #include "./scene.h" @@ -44,10 +42,7 @@ typedef enum { typedef struct { loscene_t header; - const loscene_param_t* param; - loresource_set_t* res; - loshader_set_t* shaders; - const locommon_ticker_t* ticker; + loscene_context_t* ctx; struct { vec2_t fontsz_large; @@ -68,7 +63,7 @@ typedef struct { glyphas_block_t* buttons; } text; - loresource_music_player_t* music; + loresource_music_t* music; loscene_title_state_t state; uint64_t since; @@ -80,29 +75,25 @@ typedef struct { static void loscene_title_calculate_geometry_(loscene_title_t* s) { assert(s != NULL); - const vec2_t* dpi = &s->shaders->dpi; - const vec2_t* reso = &s->shaders->resolution; - - s->geo.fontpx_large = *dpi; - vec2_muleq(&s->geo.fontpx_large, .8f); - - s->geo.fontpx_small = *dpi; - vec2_muleq(&s->geo.fontpx_small, .14f); - -# define px_to_disp_(v) vec2((v).x/reso->x*2, (v).y/reso->y*2) - - s->geo.fontsz_large = px_to_disp_(s->geo.fontpx_large); - s->geo.fontsz_small = px_to_disp_(s->geo.fontpx_small); - -# undef px_to_disp_ + locommon_screen_calc_pixels_from_inch( + &s->ctx->screen, &s->geo.fontpx_large, &vec2(.8f, .8f)); + locommon_screen_calc_pixels_from_inch( + &s->ctx->screen, &s->geo.fontpx_small, &vec2(.14f, .14f)); + locommon_screen_calc_winpos_from_pixels( + &s->ctx->screen, &s->geo.fontsz_large, &s->geo.fontpx_large); + locommon_screen_calc_winpos_from_pixels( + &s->ctx->screen, &s->geo.fontsz_small, &s->geo.fontpx_small); } static void loscene_title_create_text_block_(loscene_title_t* s) { assert(s != NULL); - const char* title = loresource_text_get(s->res->lang, "app_name"); - const char* author = loresource_text_get(s->res->lang, "title_authors"); - const char* buttons = loresource_text_get(s->res->lang, "title_buttons"); + const char* title = + loresource_text_get(s->ctx->resources.lang, "app_name"); + const char* author = + loresource_text_get(s->ctx->resources.lang, "title_authors"); + const char* buttons = + loresource_text_get(s->ctx->resources.lang, "title_buttons"); static const vec4_t color = vec4(1, 1, 1, 1); @@ -132,7 +123,7 @@ static void loscene_title_create_text_block_(loscene_title_t* s) { s->text.buttons, s->font.small, &color, buttons, strlen(buttons)); const vec2_t scale = vec2( - 2/s->shaders->resolution.x, 2/s->shaders->resolution.y); + 2/s->ctx->screen.resolution.x, 2/s->ctx->screen.resolution.y); glyphas_block_scale(s->text.title, &scale); glyphas_block_scale(s->text.author, &scale); glyphas_block_scale(s->text.buttons, &scale); @@ -152,16 +143,17 @@ static void loscene_title_update_uniblock_(loscene_title_t* s) { static const uint64_t camspeed = 5000; - const uint64_t chunk = s->ticker->time/camspeed; - const float fract = s->ticker->time%camspeed*1.f/camspeed; + const uint64_t chunk = s->ctx->ticker.time/camspeed; + const float fract = s->ctx->ticker.time%camspeed*1.f/camspeed; - const loshader_uniblock_param_t p = { - .proj = mat4_identity(), - .cam = mat4_identity(), - .pos = locommon_position(chunk, 0, vec2(fract, 0)), - .time = s->ticker->time%60000/1000.0f, - }; - loshader_uniblock_update_param(s->shaders->uniblock, &p); + loshader_uniblock_update_param( + &s->ctx->shaders.uniblock, + &(loshader_uniblock_param_t) { + .proj = mat4_identity(), + .cam = mat4_identity(), + .pos = locommon_position(chunk, 0, vec2(fract, 0)), + .time = s->ctx->ticker.time%60000/1000.0f, + }); } static void loscene_title_delete_(loscene_t* scene) { @@ -189,47 +181,47 @@ static loscene_t* loscene_title_update_( loscene_title_t* s = (typeof(s)) scene; if (s->music == NULL) { - s->music = &s->res->music.title; + s->music = loresource_music_set_get( + &s->ctx->resources.music, LORESOURCE_MUSIC_ID_TITLE); jukebox_decoder_play(s->music->decoder, &rational(0, 1), true); jukebox_amp_change_volume(&s->music->amp, 1, &rational(1, 1)); } switch (s->state) { case LOSCENE_TITLE_STATE_EXPECT_BUTTON_RELEASE: - s->fade = 1 - (s->ticker->time - s->since)*1.f / fadedur; + s->fade = 1 - (s->ctx->ticker.time - s->since)*1.f / fadedur; if (s->fade < 0) s->fade = 0; if (input->buttons == 0 && s->fade <= 0) { s->state = LOSCENE_TITLE_STATE_EXPECT_BUTTON_PRESS; } break; case LOSCENE_TITLE_STATE_EXPECT_BUTTON_PRESS: - if (input->buttons & LOCOMMON_INPUT_BUTTON_ATTACK) { + if (input->buttons & LOCOMMON_INPUT_BUTTON_OK) { jukebox_amp_change_volume(&s->music->amp, 0, &rational(fadedur, 1000)); jukebox_decoder_stop_after(s->music->decoder, &rational(fadedur, 1000)); s->state = LOSCENE_TITLE_STATE_FADING_TO_GAME; - s->since = s->ticker->time; + s->since = s->ctx->ticker.time; } else if (input->buttons & LOCOMMON_INPUT_BUTTON_MENU) { jukebox_amp_change_volume(&s->music->amp, 0, &rational(fadedur, 1000)); jukebox_decoder_stop_after(s->music->decoder, &rational(fadedur, 1000)); s->state = LOSCENE_TITLE_STATE_FADING_TO_EXIT; - s->since = s->ticker->time; + s->since = s->ctx->ticker.time; } break; case LOSCENE_TITLE_STATE_FADING_TO_GAME: - if (s->since + fadedur < s->ticker->time) { - return loscene_game_new( - s->param, s->res, s->shaders, s->ticker, true /* = load data */); + if (s->since + fadedur < s->ctx->ticker.time) { + return loscene_game_new(s->ctx, true /* = load data */); } else { - s->fade = (s->ticker->time - s->since)*1.f/fadedur; + s->fade = (s->ctx->ticker.time - s->since)*1.f/fadedur; } break; case LOSCENE_TITLE_STATE_FADING_TO_EXIT: - if (s->since + fadedur < s->ticker->time) { + if (s->since + fadedur < s->ctx->ticker.time) { return NULL; } else { - s->fade = (s->ticker->time - s->since)*1.f/fadedur; + s->fade = (s->ctx->ticker.time - s->since)*1.f/fadedur; } break; } @@ -242,63 +234,56 @@ static void loscene_title_draw_(loscene_t* scene) { loscene_title_t* s = (typeof(s)) scene; loscene_title_update_uniblock_(s); - loshader_set_clear_all(s->shaders); + loshader_set_clear_all(&s->ctx->shaders); loshader_backwall_drawer_set_param( - s->shaders->drawer.backwall, + &s->ctx->shaders.drawer.backwall, &(loshader_backwall_drawer_param_t) { .type = LOSHADER_BACKWALL_TYPE_JAIL, .transition = 1, }); loshader_fog_drawer_set_param( - s->shaders->drawer.fog, + &s->ctx->shaders.drawer.fog, &(loshader_fog_drawer_param_t) { .type = LOSHADER_FOG_TYPE_WHITE_CLOUD, .transition = 1, }); - loshader_pixsort_drawer_set_intensity(s->shaders->drawer.pixsort, 0); + s->ctx->shaders.drawer.pixsort.intensity = 0; loshader_posteffect_drawer_set_param( - s->shaders->drawer.posteffect, + &s->ctx->shaders.drawer.posteffect, &(loshader_posteffect_drawer_param_t) { - .whole_blur = 1, - .radial_displacement = .05f, - .amnesia_displacement = .1f, - .radial_fade = .5f + s->fade*.3f, - .brightness = s->param->brightness/1000.f, + .blur_whole = 1, + .distortion_radial = .05f, + .distortion_amnesia = .1f, + .fade_radial = .5f + s->fade*.3f, + .brightness_whole = s->ctx->param.brightness/1000.f, }); - s->shaders->drawer.menu_text.alpha = 1; + s->ctx->shaders.drawer.menu_text.alpha = 1; loshader_menu_text_drawer_add_block( - &s->shaders->drawer.menu_text, s->text.title); + &s->ctx->shaders.drawer.menu_text, s->text.title); loshader_menu_text_drawer_add_block( - &s->shaders->drawer.menu_text, s->text.author); + &s->ctx->shaders.drawer.menu_text, s->text.author); loshader_menu_text_drawer_add_block( - &s->shaders->drawer.menu_text, s->text.buttons); + &s->ctx->shaders.drawer.menu_text, s->text.buttons); loshader_cinescope_drawer_set_param( - s->shaders->drawer.cinescope, + &s->ctx->shaders.drawer.cinescope, &(loshader_cinescope_drawer_param_t) {0}); - loshader_set_draw_all(s->shaders); + loshader_set_draw_all(&s->ctx->shaders); } -loscene_t* loscene_title_new( - const loscene_param_t* param, - loresource_set_t* res, - loshader_set_t* shaders, - const locommon_ticker_t* ticker) { - assert(param != NULL); - assert(res != NULL); - assert(shaders != NULL); - assert(ticker != NULL); +loscene_t* loscene_title_new(loscene_context_t* ctx) { + assert(ctx != NULL); - loshader_set_drop_cache(shaders); + loshader_set_drop_cache(&ctx->shaders); - loscene_title_t* scene = memory_new(sizeof(*scene)); - *scene = (typeof(*scene)) { + loscene_title_t* s = memory_new(sizeof(*s)); + *s = (typeof(*s)) { .header = { .vtable = { .delete = loscene_title_delete_, @@ -306,28 +291,25 @@ loscene_t* loscene_title_new( .draw = loscene_title_draw_, }, }, - .param = param, - .res = res, - .shaders = shaders, - .ticker = ticker, + .ctx = ctx, .state = LOSCENE_TITLE_STATE_EXPECT_BUTTON_RELEASE, - .since = ticker->time, + .since = ctx->ticker.time, }; - loscene_title_calculate_geometry_(scene); + loscene_title_calculate_geometry_(s); - scene->font = (typeof(scene->font)) { + s->font = (typeof(s->font)) { .large = glyphas_cache_new( - shaders->tex.menu_text, - &res->font.sans, - scene->geo.fontpx_large.x, - scene->geo.fontpx_large.y), + s->ctx->shaders.tex.menu_text, + &s->ctx->resources.font.sans, + s->geo.fontpx_large.x, + s->geo.fontpx_large.y), .small = glyphas_cache_new( - shaders->tex.menu_text, - &res->font.sans, - scene->geo.fontpx_small.x, - scene->geo.fontpx_small.y), + s->ctx->shaders.tex.menu_text, + &s->ctx->resources.font.sans, + s->geo.fontpx_small.x, + s->geo.fontpx_small.y), }; - loscene_title_create_text_block_(scene); - return &scene->header; + loscene_title_create_text_block_(s); + return &s->header; } diff --git a/core/loscene/title.h b/core/loscene/title.h index 9795a05..f42f90b 100644 --- a/core/loscene/title.h +++ b/core/loscene/title.h @@ -1,16 +1,9 @@ #pragma once -#include "core/locommon/ticker.h" -#include "core/loresource/set.h" -#include "core/loshader/set.h" - -#include "./param.h" +#include "./context.h" #include "./scene.h" loscene_t* /* OWNERSHIP */ loscene_title_new( - const loscene_param_t* param, - loresource_set_t* res, - loshader_set_t* shaders, - const locommon_ticker_t* ticker + loscene_context_t* ctx ); diff --git a/core/loshader/CMakeLists.txt b/core/loshader/CMakeLists.txt index c045519..5659d38 100644 --- a/core/loshader/CMakeLists.txt +++ b/core/loshader/CMakeLists.txt @@ -9,12 +9,17 @@ add_library(loshader ground.c hud_bar.c hud_text.c + instanced.c menu_background.c menu_stance.c menu_text.c + particle.c pixsort.c + popup_text.c posteffect.c set.c + single.c + text.c uniblock.c ) target_any_sources(loshader @@ -45,6 +50,10 @@ target_any_sources(loshader menu_stance.fshader menu_text.vshader menu_text.fshader + particle.vshader + particle.fshader + popup_text.vshader + popup_text.fshader pixsort.vshader pixsort.fshader posteffect.vshader diff --git a/core/loshader/backwall.c b/core/loshader/backwall.c index 62e96f5..6c8355d 100644 --- a/core/loshader/backwall.c +++ b/core/loshader/backwall.c @@ -2,26 +2,16 @@ #include #include -#include - -#include "util/gleasy/buffer.h" -#include "util/gleasy/program.h" -#include "util/math/vector.h" -#include "util/memory/memory.h" +#include "./single.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/backwall.vshader.h" -#include "anysrc/backwall.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/backwall.vshader.h" +#include "core/loshader/anysrc/backwall.fshader.h" -struct loshader_backwall_drawer_t { - const loshader_backwall_program_t* prog; - const loshader_uniblock_t* uniblock; - - gleasy_buffer_uniform_t param; -}; +#define PRIMITIVE_COUNT_ 6 #pragma pack(push, 1) typedef struct { @@ -29,65 +19,29 @@ typedef struct { float prev_type; float transition; } loshader_backwall_drawer_internal_param_t; -_Static_assert( - sizeof(float)*3 == - sizeof(loshader_backwall_drawer_internal_param_t)); #pragma pack(pop) -#define LOSHADER_BACKWALL_UNIBLOCK_INDEX 0 -#define LOSHADER_BACKWALL_PARAM_INDEX 1 +_Static_assert( + sizeof(float)*3 == + sizeof(loshader_backwall_drawer_internal_param_t), + "recheck the type has no padding"); -#define LOSHADER_BACKWALL_PRIMITIVE_COUNT 6 +void loshader_backwall_drawer_initialize( + loshader_backwall_drawer_t* drawer, + const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); + assert(uniblock != NULL); -void loshader_backwall_program_initialize(loshader_backwall_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_backwall_vshader_, sizeof(loshader_backwall_vshader_), loshader_backwall_fshader_, sizeof(loshader_backwall_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, uniblock, LOSHADER_BACKWALL_UNIBLOCK_INDEX); - - const GLuint param = glGetUniformBlockIndex(*prog, "param"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, param, LOSHADER_BACKWALL_PARAM_INDEX); -} - -void loshader_backwall_program_deinitialize(loshader_backwall_program_t* prog) { - assert(prog != NULL); - - glDeleteProgram(*prog); -} - -loshader_backwall_drawer_t* loshader_backwall_drawer_new( - const loshader_backwall_program_t* prog, - const loshader_uniblock_t* uniblock) { - assert(prog != NULL); - assert(uniblock != NULL); - - loshader_backwall_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - }; - - glGenBuffers(1, &drawer->param); - glBindBuffer(GL_UNIFORM_BUFFER, drawer->param); - glBufferData(GL_UNIFORM_BUFFER, - sizeof(loshader_backwall_drawer_internal_param_t), NULL, GL_DYNAMIC_DRAW); - - return drawer; -} - -void loshader_backwall_drawer_delete(loshader_backwall_drawer_t* drawer) { - if (drawer == NULL) return; - - glDeleteBuffers(1, &drawer->param); - - memory_delete(drawer); + loshader_single_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_backwall_drawer_internal_param_t)); } void loshader_backwall_drawer_set_param( @@ -101,18 +55,11 @@ void loshader_backwall_drawer_set_param( .prev_type = param->prev_type, .transition = param->transition, }; - glBindBuffer(GL_UNIFORM_BUFFER, drawer->param); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(p), &p); + loshader_single_drawer_set_param(&drawer->super, &p); } void loshader_backwall_drawer_draw(const loshader_backwall_drawer_t* drawer) { assert(drawer != NULL); - glUseProgram(*drawer->prog); - - loshader_uniblock_bind(drawer->uniblock, LOSHADER_BACKWALL_UNIBLOCK_INDEX); - glBindBufferBase(GL_UNIFORM_BUFFER, - LOSHADER_BACKWALL_PARAM_INDEX, drawer->param); - - glDrawArrays(GL_TRIANGLES, 0, LOSHADER_BACKWALL_PRIMITIVE_COUNT); + loshader_single_drawer_draw(&drawer->super, PRIMITIVE_COUNT_); } diff --git a/core/loshader/backwall.h b/core/loshader/backwall.h index 8e30ebf..81d270a 100644 --- a/core/loshader/backwall.h +++ b/core/loshader/backwall.h @@ -2,14 +2,12 @@ #include -#include "util/gleasy/program.h" - +#include "./single.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_backwall_program_t; - -struct loshader_backwall_drawer_t; -typedef struct loshader_backwall_drawer_t loshader_backwall_drawer_t; +typedef struct { + loshader_single_drawer_t super; +} loshader_backwall_drawer_t; typedef enum { LOSHADER_BACKWALL_TYPE_WHITE = 0, @@ -28,25 +26,13 @@ typedef struct { } loshader_backwall_drawer_param_t; void -loshader_backwall_program_initialize( - loshader_backwall_program_t* prog +loshader_backwall_drawer_initialize( + loshader_backwall_drawer_t* drawer, + const loshader_uniblock_t* uniblock ); -void -loshader_backwall_program_deinitialize( - loshader_backwall_program_t* prog -); - -loshader_backwall_drawer_t* -loshader_backwall_drawer_new( - const loshader_backwall_program_t* prog, - const loshader_uniblock_t* uniblock -); - -void -loshader_backwall_drawer_delete( - loshader_backwall_drawer_t* drawer -); +#define loshader_backwall_drawer_deinitialize(drawer) \ + loshader_single_drawer_deinitialize(&(drawer)->super) void loshader_backwall_drawer_set_param( diff --git a/core/loshader/bullet.c b/core/loshader/bullet.c index 306af9d..049f8e0 100644 --- a/core/loshader/bullet.c +++ b/core/loshader/bullet.c @@ -11,32 +11,22 @@ #include "util/gleasy/buffer.h" #include "util/gleasy/program.h" #include "util/math/vector.h" -#include "util/memory/memory.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/bullet.vshader.h" -#include "anysrc/bullet.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/bullet.vshader.h" +#include "core/loshader/anysrc/bullet.fshader.h" -#define LOSHADER_BULLET_VSHADER_IN_BULLET_ID 0 -#define LOSHADER_BULLET_VSHADER_IN_POS 1 -#define LOSHADER_BULLET_VSHADER_IN_SIZE 2 -#define LOSHADER_BULLET_VSHADER_IN_THETA 3 -#define LOSHADER_BULLET_VSHADER_IN_TIME 4 -#define LOSHADER_BULLET_VSHADER_IN_COLOR 5 +#define VSHADER_IN_BULLET_ID_ 0 +#define VSHADER_IN_POS_ 1 +#define VSHADER_IN_SIZE_ 2 +#define VSHADER_IN_THETA_ 3 +#define VSHADER_IN_TIME_ 4 +#define VSHADER_IN_COLOR_ 5 -struct loshader_bullet_drawer_t { - const loshader_bullet_program_t* prog; - const loshader_uniblock_t* uniblock; - - GLuint vao; - - gleasy_buffer_array_t instances; - size_t instances_reserved; - size_t instances_length; -}; +#define PRIMITIVE_COUNT_ 6 #pragma pack(push, 1) typedef struct { @@ -51,102 +41,45 @@ typedef struct { } loshader_bullet_drawer_internal_instance_t; #pragma pack(pop) -#define LOSHADER_BULLET_UNIBLOCK_INDEX 0 +void loshader_bullet_drawer_initialize( + loshader_bullet_drawer_t* drawer, + const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); + assert(uniblock != NULL); -#define LOSHADER_BULLET_PRIMITIVE_COUNT 6 - -static void loshader_bullet_program_setup_vao_( - gleasy_buffer_array_t instances) { - assert(instances != 0); - - glBindBuffer(GL_ARRAY_BUFFER, instances); - -# define enable_attrib_(NAME, name, dim, type) do { \ - glEnableVertexAttribArray(LOSHADER_BULLET_VSHADER_IN_##NAME); \ - glVertexAttribPointer( \ - LOSHADER_BULLET_VSHADER_IN_##NAME, dim, type, GL_FALSE, \ - sizeof(loshader_bullet_drawer_internal_instance_t), \ - NULL + offsetof(loshader_bullet_drawer_internal_instance_t, name)); \ - glVertexAttribDivisor(LOSHADER_BULLET_VSHADER_IN_##NAME, 1); \ - } while (0) - - enable_attrib_(BULLET_ID, bullet_id, 1, GL_UNSIGNED_SHORT); - - enable_attrib_(POS, pos, 2, GL_FLOAT); - enable_attrib_(SIZE, size, 2, GL_FLOAT); - enable_attrib_(THETA, theta, 1, GL_FLOAT); - enable_attrib_(TIME, time, 1, GL_FLOAT); - - enable_attrib_(COLOR, color, 4, GL_FLOAT); - -# undef enable_attrib_ -} - -void loshader_bullet_program_initialize(loshader_bullet_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_bullet_vshader_, sizeof(loshader_bullet_vshader_), loshader_bullet_fshader_, sizeof(loshader_bullet_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); + loshader_instanced_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_bullet_drawer_internal_instance_t)); - glUniformBlockBinding(*prog, uniblock, LOSHADER_BULLET_UNIBLOCK_INDEX); -} + glBindVertexArray(drawer->super.vao); + glBindBuffer(GL_ARRAY_BUFFER, drawer->super.instances); -void loshader_bullet_program_deinitialize(loshader_bullet_program_t* prog) { - assert(prog != NULL); +# define enable_(index, var, dim, type) do { \ + glEnableVertexAttribArray(index); \ + glVertexAttribPointer( \ + index, dim, type, GL_FALSE, \ + sizeof(loshader_bullet_drawer_internal_instance_t), \ + NULL + offsetof(loshader_bullet_drawer_internal_instance_t, var)); \ + glVertexAttribDivisor(index, 1); \ + } while (0) - glDeleteProgram(*prog); -} + enable_(VSHADER_IN_BULLET_ID_, bullet_id, 1, GL_UNSIGNED_SHORT); -loshader_bullet_drawer_t* loshader_bullet_drawer_new( - const loshader_bullet_program_t* prog, - const loshader_uniblock_t* uniblock) { - assert(prog != NULL); - assert(uniblock != NULL); + enable_(VSHADER_IN_POS_, pos, 2, GL_FLOAT); + enable_(VSHADER_IN_SIZE_, size, 2, GL_FLOAT); + enable_(VSHADER_IN_THETA_, theta, 1, GL_FLOAT); + enable_(VSHADER_IN_TIME_, time, 1, GL_FLOAT); - loshader_bullet_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - }; + enable_(VSHADER_IN_COLOR_, color, 4, GL_FLOAT); - glCreateVertexArrays(1, &drawer->vao); - glBindVertexArray(drawer->vao); - - glGenBuffers(1, &drawer->instances); - loshader_bullet_program_setup_vao_(drawer->instances); - - return drawer; -} - -void loshader_bullet_drawer_delete(loshader_bullet_drawer_t* drawer) { - assert(drawer != NULL); - - glDeleteBuffers(1, &drawer->instances); - - glDeleteVertexArrays(1, &drawer->vao); - - memory_delete(drawer); -} - -void loshader_bullet_drawer_clear( - loshader_bullet_drawer_t* drawer, size_t reserve) { - assert(drawer != NULL); - assert(reserve > 0); - - drawer->instances_length = 0; - - if (drawer->instances_reserved < reserve) { - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferData(GL_ARRAY_BUFFER, - reserve * sizeof(loshader_bullet_drawer_internal_instance_t), - NULL, GL_DYNAMIC_DRAW); - drawer->instances_reserved = reserve; - } +# undef enable_ } void loshader_bullet_drawer_add_instance( @@ -155,11 +88,6 @@ void loshader_bullet_drawer_add_instance( assert(drawer != NULL); assert(instance != NULL); - if (drawer->instances_length >= drawer->instances_reserved) { - fprintf(stderr, "bullet drawer instance overflow\n"); - abort(); - } - const loshader_bullet_drawer_internal_instance_t insta = { .bullet_id = instance->bullet_id, .pos = instance->pos, @@ -168,24 +96,14 @@ void loshader_bullet_drawer_add_instance( .time = instance->time, .color = instance->color, }; - - const size_t offset = drawer->instances_length * sizeof(insta); - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(insta), &insta); - - ++drawer->instances_length; + if (!loshader_instanced_drawer_add_instance(&drawer->super, &insta)) { + fprintf(stderr, "bullet drawer overflow\n"); + abort(); + } } void loshader_bullet_drawer_draw(const loshader_bullet_drawer_t* drawer) { assert(drawer != NULL); - if (drawer->instances_length == 0) return; - - glUseProgram(*drawer->prog); - glBindVertexArray(drawer->vao); - - loshader_uniblock_bind(drawer->uniblock, LOSHADER_BULLET_UNIBLOCK_INDEX); - - glDrawArraysInstanced(GL_TRIANGLES, - 0, LOSHADER_BULLET_PRIMITIVE_COUNT, drawer->instances_length); + loshader_instanced_drawer_draw(&drawer->super, PRIMITIVE_COUNT_); } diff --git a/core/loshader/bullet.h b/core/loshader/bullet.h index fddd566..76d2faa 100644 --- a/core/loshader/bullet.h +++ b/core/loshader/bullet.h @@ -2,15 +2,14 @@ #include -#include "util/gleasy/program.h" #include "util/math/vector.h" +#include "./instanced.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_bullet_program_t; - -struct loshader_bullet_drawer_t; -typedef struct loshader_bullet_drawer_t loshader_bullet_drawer_t; +typedef struct { + loshader_instanced_drawer_t super; +} loshader_bullet_drawer_t; typedef enum { LOSHADER_BULLET_ID_LIGHT = 0, @@ -30,31 +29,16 @@ typedef struct { } loshader_bullet_drawer_instance_t; void -loshader_bullet_program_initialize( - loshader_bullet_program_t* prog +loshader_bullet_drawer_initialize( + loshader_bullet_drawer_t* drawer, + const loshader_uniblock_t* uniblock ); -void -loshader_bullet_program_deinitialize( - loshader_bullet_program_t* prog -); +#define loshader_bullet_drawer_deinitialize(drawer) \ + loshader_instanced_drawer_deinitialize(&(drawer)->super) -loshader_bullet_drawer_t* -loshader_bullet_drawer_new( - const loshader_bullet_program_t* prog, - const loshader_uniblock_t* uniblock -); - -void -loshader_bullet_drawer_delete( - loshader_bullet_drawer_t* drawer -); - -void -loshader_bullet_drawer_clear( - loshader_bullet_drawer_t* drawer, - size_t reserve -); +#define loshader_bullet_drawer_clear(drawer, reserve) \ + loshader_instanced_drawer_clear(&(drawer)->super, reserve) void loshader_bullet_drawer_add_instance( diff --git a/core/loshader/character.c b/core/loshader/character.c index f39e935..5ea970a 100644 --- a/core/loshader/character.c +++ b/core/loshader/character.c @@ -11,36 +11,26 @@ #include "util/gleasy/buffer.h" #include "util/gleasy/program.h" #include "util/math/vector.h" -#include "util/memory/memory.h" +#include "./instanced.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/character.vshader.h" -#include "anysrc/character.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/character.vshader.h" +#include "core/loshader/anysrc/character.fshader.h" -#define LOSHADER_CHARACTER_VSHADER_IN_CHARACTER_ID 0 -#define LOSHADER_CHARACTER_VSHADER_IN_FROM_MOTION_ID 1 -#define LOSHADER_CHARACTER_VSHADER_IN_TO_MOTION_ID 2 -#define LOSHADER_CHARACTER_VSHADER_IN_MOTION_TIME 3 -#define LOSHADER_CHARACTER_VSHADER_IN_MARKER 4 -#define LOSHADER_CHARACTER_VSHADER_IN_MARKER_OFFSET 5 -#define LOSHADER_CHARACTER_VSHADER_IN_POS 6 -#define LOSHADER_CHARACTER_VSHADER_IN_SIZE 7 -#define LOSHADER_CHARACTER_VSHADER_IN_COLOR 8 +#define VSHADER_IN_CHARACTER_ID_ 0 +#define VSHADER_IN_FROM_MOTION_ID_ 1 +#define VSHADER_IN_TO_MOTION_ID_ 2 +#define VSHADER_IN_MOTION_TIME_ 3 +#define VSHADER_IN_MARKER_ 4 +#define VSHADER_IN_MARKER_OFFSET_ 5 +#define VSHADER_IN_POS_ 6 +#define VSHADER_IN_SIZE_ 7 +#define VSHADER_IN_COLOR_ 8 -struct loshader_character_drawer_t { - const loshader_character_program_t* prog; - - const loshader_uniblock_t* uniblock; - - GLuint vao; - - gleasy_buffer_array_t instances; - size_t instances_reserved; - size_t instances_length; -}; +#define PRIMITIVE_COUNT_ 54 #pragma pack(push, 1) typedef struct { @@ -59,105 +49,46 @@ typedef struct { } loshader_character_drawer_internal_instance_t; #pragma pack(pop) -#define LOSHADER_CHARACTER_UNIBLOCK_INDEX 0 +void loshader_character_drawer_initialize( + loshader_character_drawer_t* drawer, const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); + assert(uniblock != NULL); -#define LOSHADER_CHARACTER_PRIMITIVE_COUNT 54 - -static void loshader_character_program_setup_vao_( - const loshader_character_program_t* prog, gleasy_buffer_array_t instances) { - assert(prog != NULL); - assert(instances != 0); - - glBindBuffer(GL_ARRAY_BUFFER, instances); - -# define enable_attrib_(NAME, name, dim, type) do { \ - glEnableVertexAttribArray(LOSHADER_CHARACTER_VSHADER_IN_##NAME); \ - glVertexAttribPointer( \ - LOSHADER_CHARACTER_VSHADER_IN_##NAME, dim, type, GL_FALSE, \ - sizeof(loshader_character_drawer_internal_instance_t), \ - NULL + offsetof(loshader_character_drawer_internal_instance_t, name)); \ - glVertexAttribDivisor(LOSHADER_CHARACTER_VSHADER_IN_##NAME, 1); \ - } while (0) - - enable_attrib_(CHARACTER_ID, character_id, 1, GL_UNSIGNED_SHORT); - enable_attrib_(FROM_MOTION_ID, from_motion_id, 1, GL_UNSIGNED_SHORT); - enable_attrib_(TO_MOTION_ID, to_motion_id, 1, GL_UNSIGNED_SHORT); - enable_attrib_(MOTION_TIME, motion_time, 1, GL_FLOAT); - enable_attrib_(MARKER, marker, 1, GL_FLOAT); - enable_attrib_(MARKER_OFFSET, marker_offset, 2, GL_FLOAT); - - enable_attrib_(POS, pos, 2, GL_FLOAT); - enable_attrib_(SIZE, size, 2, GL_FLOAT); - enable_attrib_(COLOR, color, 4, GL_FLOAT); - -# undef enable_attrib_ -} - -void loshader_character_program_initialize(loshader_character_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( + gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_character_vshader_, sizeof(loshader_character_vshader_), loshader_character_fshader_, sizeof(loshader_character_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); + loshader_instanced_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_character_drawer_internal_instance_t)); - glUniformBlockBinding(*prog, uniblock, LOSHADER_CHARACTER_UNIBLOCK_INDEX); -} + glBindVertexArray(drawer->super.vao); + glBindBuffer(GL_ARRAY_BUFFER, drawer->super.instances); -void loshader_character_program_deinitialize( - loshader_character_program_t* prog) { - assert(prog != NULL); +# define enable_(index, var, dim, type) do { \ + glEnableVertexAttribArray(index); \ + glVertexAttribPointer( \ + index, dim, type, GL_FALSE, \ + sizeof(loshader_character_drawer_internal_instance_t), \ + NULL + offsetof(loshader_character_drawer_internal_instance_t, var)); \ + glVertexAttribDivisor(index, 1); \ + } while (0) - glDeleteProgram(*prog); -} + enable_(VSHADER_IN_CHARACTER_ID_, character_id, 1, GL_UNSIGNED_SHORT); + enable_(VSHADER_IN_FROM_MOTION_ID_, from_motion_id, 1, GL_UNSIGNED_SHORT); + enable_(VSHADER_IN_TO_MOTION_ID_, to_motion_id, 1, GL_UNSIGNED_SHORT); + enable_(VSHADER_IN_MOTION_TIME_, motion_time, 1, GL_FLOAT); + enable_(VSHADER_IN_MARKER_, marker, 1, GL_FLOAT); + enable_(VSHADER_IN_MARKER_OFFSET_, marker_offset, 2, GL_FLOAT); -loshader_character_drawer_t* loshader_character_drawer_new( - const loshader_character_program_t* prog, - const loshader_uniblock_t* uniblock) { - assert(prog != NULL); - assert(uniblock != NULL); + enable_(VSHADER_IN_POS_, pos, 2, GL_FLOAT); + enable_(VSHADER_IN_SIZE_, size, 2, GL_FLOAT); + enable_(VSHADER_IN_COLOR_, color, 4, GL_FLOAT); - loshader_character_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - }; - - glGenBuffers(1, &drawer->instances); - glCreateVertexArrays(1, &drawer->vao); - glBindVertexArray(drawer->vao); - loshader_character_program_setup_vao_(drawer->prog, drawer->instances); - - return drawer; -} - -void loshader_character_drawer_delete(loshader_character_drawer_t* drawer) { - if (drawer == NULL) return; - - glDeleteBuffers(1, &drawer->instances); - - glDeleteVertexArrays(1, &drawer->vao); - - memory_delete(drawer); -} - -void loshader_character_drawer_clear( - loshader_character_drawer_t* drawer, size_t reserve) { - assert(drawer != NULL); - assert(reserve > 0); - - drawer->instances_length = 0; - - if (drawer->instances_reserved < reserve) { - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferData(GL_ARRAY_BUFFER, - reserve * sizeof(loshader_character_drawer_internal_instance_t), - NULL, GL_DYNAMIC_DRAW); - drawer->instances_reserved = reserve; - } +# undef enable_ } void loshader_character_drawer_add_instance( @@ -166,40 +97,25 @@ void loshader_character_drawer_add_instance( assert(drawer != NULL); assert(instance != NULL); - if (drawer->instances_length >= drawer->instances_reserved) { - fprintf(stderr, "character drawer instance overflow\n"); - abort(); - } - const loshader_character_drawer_internal_instance_t insta = { .character_id = instance->character_id, - .from_motion_id = instance->from_motion_id, - .to_motion_id = instance->to_motion_id, - .motion_time = instance->motion_time, + .from_motion_id = instance->motion.from, + .to_motion_id = instance->motion.to, + .motion_time = instance->motion.time, .marker = instance->marker, .marker_offset = instance->marker_offset, .pos = instance->pos, .size = instance->size, .color = instance->color, }; - - const size_t offset = drawer->instances_length * sizeof(insta); - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(insta), &insta); - - ++drawer->instances_length; + if (!loshader_instanced_drawer_add_instance(&drawer->super, &insta)) { + fprintf(stderr, "character drawer overflow\n"); + abort(); + } } void loshader_character_drawer_draw(const loshader_character_drawer_t* drawer) { assert(drawer != NULL); - if (drawer->instances_length == 0) return; - - glUseProgram(*drawer->prog); - glBindVertexArray(drawer->vao); - - loshader_uniblock_bind(drawer->uniblock, LOSHADER_CHARACTER_UNIBLOCK_INDEX); - - glDrawArraysInstanced(GL_TRIANGLES, - 0, LOSHADER_CHARACTER_PRIMITIVE_COUNT, drawer->instances_length); + loshader_instanced_drawer_draw(&drawer->super, PRIMITIVE_COUNT_); } diff --git a/core/loshader/character.h b/core/loshader/character.h index c891ae7..15295a2 100644 --- a/core/loshader/character.h +++ b/core/loshader/character.h @@ -3,15 +3,14 @@ #include #include -#include "util/gleasy/program.h" #include "util/math/vector.h" +#include "./instanced.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_character_program_t; - -struct loshader_character_drawer_t; -typedef struct loshader_character_drawer_t loshader_character_drawer_t; +typedef struct { + loshader_instanced_drawer_t super; +} loshader_character_drawer_t; typedef enum { LOSHADER_CHARACTER_ID_PLAYER = 0, @@ -34,9 +33,11 @@ typedef enum { typedef struct { loshader_character_id_t character_id; - uint32_t from_motion_id; - uint32_t to_motion_id; - float motion_time; + struct { + loshader_character_motion_id_t from; + loshader_character_motion_id_t to; + float time; + } motion; float marker; vec2_t marker_offset; @@ -47,32 +48,17 @@ typedef struct { } loshader_character_drawer_instance_t; void -loshader_character_program_initialize( - loshader_character_program_t* prog -); - -void -loshader_character_program_deinitialize( - loshader_character_program_t* prog -); - -loshader_character_drawer_t* /* OWNERSHIP */ -loshader_character_drawer_new( - const loshader_character_program_t* prog, - const loshader_uniblock_t* uniblock -); - -void -loshader_character_drawer_delete( - loshader_character_drawer_t* drawer /* OWNERSHIP */ -); - -void -loshader_character_drawer_clear( +loshader_character_drawer_initialize( loshader_character_drawer_t* drawer, - size_t reserve + const loshader_uniblock_t* uniblock ); +#define loshader_character_drawer_deinitialize(drawer) \ + loshader_instanced_drawer_deinitialize(&(drawer)->super) + +#define loshader_character_drawer_clear(drawer, reserve) \ + loshader_instanced_drawer_clear(&(drawer)->super, reserve) + void loshader_character_drawer_add_instance( loshader_character_drawer_t* drawer, diff --git a/core/loshader/character.vshader b/core/loshader/character.vshader index ed387d8..c4dae52 100644 --- a/core/loshader/character.vshader +++ b/core/loshader/character.vshader @@ -105,6 +105,9 @@ vec2 cavia_stand1(void) { ); return gl_VertexID < verts.length()? verts[gl_VertexID]: vec2(0.); } +vec2 cavia_stand2(void) { + return cavia_stand1()*vec2(1., .95) + vec2(0., -.05); +} vec2 cavia_walk(void) { const vec2[] verts = vec2[]( vec2( 0.06, 1.00), vec2(-0.16, 0.72), vec2( 0.36, 0.58), @@ -176,6 +179,7 @@ vec2 cavia_down(void) { vec2 cavia(in float motion_id) { return (motion_id == 0.)? cavia_stand1(): + (motion_id == 1.)? cavia_stand2(): (motion_id == 2.)? cavia_walk(): (motion_id == 3.)? cavia_attack1(): (motion_id == 4.)? cavia_attack2(): diff --git a/core/loshader/cinescope.c b/core/loshader/cinescope.c index 7950be2..cc5a0e3 100644 --- a/core/loshader/cinescope.c +++ b/core/loshader/cinescope.c @@ -4,89 +4,46 @@ #include #include -#include "util/gleasy/buffer.h" -#include "util/gleasy/program.h" #include "util/math/vector.h" -#include "util/memory/memory.h" +#include "./single.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/cinescope.vshader.h" -#include "anysrc/cinescope.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/cinescope.vshader.h" +#include "core/loshader/anysrc/cinescope.fshader.h" -struct loshader_cinescope_drawer_t { - const loshader_cinescope_program_t* prog; - const loshader_uniblock_t* uniblock; - - gleasy_buffer_uniform_t param; -}; +#define PRIMITIVE_COUNT_ 12 #pragma pack(push, 1) typedef struct { vec4_t color; float size; } loshader_cinescope_drawer_internal_param_t; -_Static_assert( - sizeof(float)*5 == - sizeof(loshader_cinescope_drawer_internal_param_t)); #pragma pack(pop) -#define LOSHADER_CINESCOPE_UNIBLOCK_INDEX 0 -#define LOSHADER_CINESCOPE_PARAM_INDEX 1 +_Static_assert( + sizeof(float)*5 == + sizeof(loshader_cinescope_drawer_internal_param_t), + "recheck the type has no padding"); -#define LOSHADER_CINESCOPE_PRIMITIVE_COUNT 12 +void loshader_cinescope_drawer_initialize( + loshader_cinescope_drawer_t* drawer, + const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); + assert(uniblock != NULL); -void loshader_cinescope_program_initialize(loshader_cinescope_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( - loshader_header_shader_, sizeof(loshader_header_shader_), + const gleasy_program_t prog = gleasy_program_new( + loshader_header_shader_, sizeof(loshader_header_shader_), loshader_cinescope_vshader_, sizeof(loshader_cinescope_vshader_), loshader_cinescope_fshader_, sizeof(loshader_cinescope_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, uniblock, LOSHADER_CINESCOPE_UNIBLOCK_INDEX); - - const GLuint param = glGetUniformBlockIndex(*prog, "param"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, param, LOSHADER_CINESCOPE_PARAM_INDEX); -} - -void loshader_cinescope_program_deinitialize(loshader_cinescope_program_t* prog) { - assert(prog != NULL); - - glDeleteProgram(*prog); -} - -loshader_cinescope_drawer_t* loshader_cinescope_drawer_new( - const loshader_cinescope_program_t* prog, - const loshader_uniblock_t* uniblock) { - assert(prog != NULL); - assert(uniblock != NULL); - - loshader_cinescope_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - }; - - glGenBuffers(1, &drawer->param); - glBindBuffer(GL_UNIFORM_BUFFER, drawer->param); - glBufferData(GL_UNIFORM_BUFFER, - sizeof(loshader_cinescope_drawer_internal_param_t), NULL, GL_DYNAMIC_DRAW); - - return drawer; -} - -void loshader_cinescope_drawer_delete(loshader_cinescope_drawer_t* drawer) { - if (drawer == NULL) return; - - glDeleteBuffers(1, &drawer->param); - - memory_delete(drawer); + loshader_single_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_cinescope_drawer_internal_param_t)); } void loshader_cinescope_drawer_set_param( @@ -99,18 +56,11 @@ void loshader_cinescope_drawer_set_param( .size = param->size, .color = param->color, }; - glBindBuffer(GL_UNIFORM_BUFFER, drawer->param); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(p), &p); + loshader_single_drawer_set_param(&drawer->super, &p); } void loshader_cinescope_drawer_draw(const loshader_cinescope_drawer_t* drawer) { assert(drawer != NULL); - glUseProgram(*drawer->prog); - - loshader_uniblock_bind(drawer->uniblock, LOSHADER_CINESCOPE_UNIBLOCK_INDEX); - glBindBufferBase(GL_UNIFORM_BUFFER, - LOSHADER_CINESCOPE_PARAM_INDEX, drawer->param); - - glDrawArrays(GL_TRIANGLES, 0, LOSHADER_CINESCOPE_PRIMITIVE_COUNT); + loshader_single_drawer_draw(&drawer->super, PRIMITIVE_COUNT_); } diff --git a/core/loshader/cinescope.h b/core/loshader/cinescope.h index 8cbee4a..6c93aff 100644 --- a/core/loshader/cinescope.h +++ b/core/loshader/cinescope.h @@ -1,14 +1,15 @@ #pragma once -#include "util/gleasy/program.h" +#include + #include "util/math/vector.h" +#include "./single.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_cinescope_program_t; - -struct loshader_cinescope_drawer_t; -typedef struct loshader_cinescope_drawer_t loshader_cinescope_drawer_t; +typedef struct { + loshader_single_drawer_t super; +} loshader_cinescope_drawer_t; typedef struct { float size; @@ -16,25 +17,13 @@ typedef struct { } loshader_cinescope_drawer_param_t; void -loshader_cinescope_program_initialize( - loshader_cinescope_program_t* prog +loshader_cinescope_drawer_initialize( + loshader_cinescope_drawer_t* drawer, + const loshader_uniblock_t* uniblock ); -void -loshader_cinescope_program_deinitialize( - loshader_cinescope_program_t* prog -); - -loshader_cinescope_drawer_t* -loshader_cinescope_drawer_new( - const loshader_cinescope_program_t* prog, - const loshader_uniblock_t* uniblock -); - -void -loshader_cinescope_drawer_delete( - loshader_cinescope_drawer_t* drawer -); +#define loshader_cinescope_drawer_deinitialize(drawer) \ + loshader_single_drawer_deinitialize(&(drawer)->super) void loshader_cinescope_drawer_set_param( diff --git a/core/loshader/combat_ring.c b/core/loshader/combat_ring.c index 996cfbf..64a359d 100644 --- a/core/loshader/combat_ring.c +++ b/core/loshader/combat_ring.c @@ -7,34 +7,24 @@ #include -#include "util/gleasy/buffer.h" #include "util/gleasy/program.h" #include "util/math/algorithm.h" #include "util/math/constant.h" #include "util/math/vector.h" -#include "util/memory/memory.h" +#include "./instanced.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/combat_ring.vshader.h" -#include "anysrc/combat_ring.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/combat_ring.vshader.h" +#include "core/loshader/anysrc/combat_ring.fshader.h" -#define LOSHADER_COMBAT_RING_VSHADER_IN_RANGE 0 -#define LOSHADER_COMBAT_RING_VSHADER_IN_PERIOD 1 -#define LOSHADER_COMBAT_RING_VSHADER_IN_COLOR 2 +#define VSHADER_IN_RANGE_ 0 +#define VSHADER_IN_PERIOD_ 1 +#define VSHADER_IN_COLOR_ 2 -struct loshader_combat_ring_drawer_t { - const loshader_combat_ring_program_t* prog; - const loshader_uniblock_t* uniblock; - - GLuint vao; - - gleasy_buffer_array_t instances; - size_t instances_reserved; - size_t instances_length; -}; +#define PRIMITIVE_COUNT_ 6 #pragma pack(push, 1) typedef struct { @@ -44,102 +34,41 @@ typedef struct { } loshader_combat_ring_drawer_internal_instance_t; #pragma pack(pop) -#define LOSHADER_COMBAT_RING_UNIBLOCK_INDEX 0 +void loshader_combat_ring_drawer_initialize( + loshader_combat_ring_drawer_t* drawer, + const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); + assert(uniblock != NULL); -#define LOSHADER_COMBAT_RING_PRIMITIVE_COUNT 6 - -static void loshader_combat_ring_program_setup_vao_( - gleasy_buffer_array_t instances) { - assert(instances != 0); - - glBindBuffer(GL_ARRAY_BUFFER, instances); - - glEnableVertexAttribArray(LOSHADER_COMBAT_RING_VSHADER_IN_RANGE); - glVertexAttribPointer( - LOSHADER_COMBAT_RING_VSHADER_IN_RANGE, 1, GL_FLOAT, GL_FALSE, - sizeof(loshader_combat_ring_drawer_internal_instance_t), - NULL + offsetof(loshader_combat_ring_drawer_internal_instance_t, range)); - glVertexAttribDivisor(LOSHADER_COMBAT_RING_VSHADER_IN_RANGE, 1); - - glEnableVertexAttribArray(LOSHADER_COMBAT_RING_VSHADER_IN_PERIOD); - glVertexAttribPointer( - LOSHADER_COMBAT_RING_VSHADER_IN_PERIOD, 2, GL_FLOAT, GL_FALSE, - sizeof(loshader_combat_ring_drawer_internal_instance_t), - NULL + offsetof(loshader_combat_ring_drawer_internal_instance_t, period)); - glVertexAttribDivisor(LOSHADER_COMBAT_RING_VSHADER_IN_PERIOD, 1); - - glEnableVertexAttribArray(LOSHADER_COMBAT_RING_VSHADER_IN_COLOR); - glVertexAttribPointer( - LOSHADER_COMBAT_RING_VSHADER_IN_COLOR, 4, GL_FLOAT, GL_FALSE, - sizeof(loshader_combat_ring_drawer_internal_instance_t), - NULL + offsetof(loshader_combat_ring_drawer_internal_instance_t, color)); - glVertexAttribDivisor(LOSHADER_COMBAT_RING_VSHADER_IN_COLOR, 1); -} - -void loshader_combat_ring_program_initialize( - loshader_combat_ring_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_combat_ring_vshader_, sizeof(loshader_combat_ring_vshader_), loshader_combat_ring_fshader_, sizeof(loshader_combat_ring_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); + loshader_instanced_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_combat_ring_drawer_internal_instance_t)); - glUniformBlockBinding(*prog, uniblock, LOSHADER_COMBAT_RING_UNIBLOCK_INDEX); -} + glBindVertexArray(drawer->super.vao); + glBindBuffer(GL_ARRAY_BUFFER, drawer->super.instances); -void loshader_combat_ring_program_deinitialize( - loshader_combat_ring_program_t* prog) { - assert(prog != NULL); +# define enable_(index, var, dim, type) do { \ + glEnableVertexAttribArray(index); \ + glVertexAttribPointer( \ + index, dim, type, GL_FALSE, \ + sizeof(loshader_combat_ring_drawer_internal_instance_t), \ + NULL + \ + offsetof(loshader_combat_ring_drawer_internal_instance_t, var)); \ + glVertexAttribDivisor(index, 1); \ + } while (0) - glDeleteProgram(*prog); -} + enable_(VSHADER_IN_RANGE_, range, 1, GL_FLOAT); + enable_(VSHADER_IN_PERIOD_, period, 2, GL_FLOAT); + enable_(VSHADER_IN_COLOR_, color, 4, GL_FLOAT); -loshader_combat_ring_drawer_t* loshader_combat_ring_drawer_new( - const loshader_combat_ring_program_t* prog, - const loshader_uniblock_t* uniblock) { - assert(prog != NULL); - assert(uniblock != NULL); - - loshader_combat_ring_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - }; - - glCreateVertexArrays(1, &drawer->vao); - glBindVertexArray(drawer->vao); - - glGenBuffers(1, &drawer->instances); - loshader_combat_ring_program_setup_vao_(drawer->instances); - - return drawer; -} - -void loshader_combat_ring_drawer_delete(loshader_combat_ring_drawer_t* drawer) { - if (drawer == NULL) return; - - glDeleteBuffers(1, &drawer->instances); - glDeleteVertexArrays(1, &drawer->vao); - memory_delete(drawer); -} - -void loshader_combat_ring_drawer_clear( - loshader_combat_ring_drawer_t* drawer, size_t reserve) { - assert(drawer != NULL); - - drawer->instances_length = 0; - - if (drawer->instances_reserved < reserve) { - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferData(GL_ARRAY_BUFFER, - reserve * sizeof(loshader_combat_ring_drawer_internal_instance_t), - NULL, GL_DYNAMIC_DRAW); - drawer->instances_reserved = reserve; - } +# undef enable_ } void loshader_combat_ring_drawer_add_instance( @@ -148,36 +77,20 @@ void loshader_combat_ring_drawer_add_instance( assert(drawer != NULL); assert(instance != NULL); - if (drawer->instances_length >= drawer->instances_reserved) { - fprintf(stderr, "combat ring drawer instance overflow\n"); - abort(); - } - - const size_t offset = drawer->instances_length * - sizeof(loshader_combat_ring_drawer_internal_instance_t); - - const loshader_combat_ring_drawer_internal_instance_t i = { + const loshader_combat_ring_drawer_internal_instance_t insta = { .range = instance->range, .period = vec2(instance->start, instance->end), .color = instance->color, }; - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(i), &i); - - ++drawer->instances_length; + if (!loshader_instanced_drawer_add_instance(&drawer->super, &insta)) { + fprintf(stderr, "combat ring drawer overflow\n"); + abort(); + } } void loshader_combat_ring_drawer_draw( const loshader_combat_ring_drawer_t* drawer) { assert(drawer != NULL); - if (drawer->instances_length == 0) return; - - glUseProgram(*drawer->prog); - glBindVertexArray(drawer->vao); - - loshader_uniblock_bind(drawer->uniblock, LOSHADER_COMBAT_RING_UNIBLOCK_INDEX); - - glDrawArraysInstanced(GL_TRIANGLES, - 0, LOSHADER_COMBAT_RING_PRIMITIVE_COUNT, drawer->instances_length); + loshader_instanced_drawer_draw(&drawer->super, PRIMITIVE_COUNT_); } diff --git a/core/loshader/combat_ring.h b/core/loshader/combat_ring.h index 8d5270b..406c3bd 100644 --- a/core/loshader/combat_ring.h +++ b/core/loshader/combat_ring.h @@ -1,16 +1,13 @@ #pragma once -#include - -#include "util/gleasy/program.h" #include "util/math/vector.h" +#include "./instanced.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_combat_ring_program_t; - -struct loshader_combat_ring_drawer_t; -typedef struct loshader_combat_ring_drawer_t loshader_combat_ring_drawer_t; +typedef struct { + loshader_instanced_drawer_t super; +} loshader_combat_ring_drawer_t; typedef struct { float range; @@ -20,32 +17,17 @@ typedef struct { } loshader_combat_ring_drawer_instance_t; void -loshader_combat_ring_program_initialize( - loshader_combat_ring_program_t* prog -); - -void -loshader_combat_ring_program_deinitialize( - loshader_combat_ring_program_t* prog -); - -loshader_combat_ring_drawer_t* /* OWNERSHIP */ -loshader_combat_ring_drawer_new( - const loshader_combat_ring_program_t* prog, - const loshader_uniblock_t* uniblock -); - -void -loshader_combat_ring_drawer_delete( - loshader_combat_ring_drawer_t* drawer /* OWNERSHIP */ -); - -void -loshader_combat_ring_drawer_clear( +loshader_combat_ring_drawer_initialize( loshader_combat_ring_drawer_t* drawer, - size_t reserve + const loshader_uniblock_t* uniblock ); +#define loshader_combat_ring_drawer_deinitialize(drawer) \ + loshader_instanced_drawer_deinitialize(&(drawer)->super) + +#define loshader_combat_ring_drawer_clear(drawer, reserve) \ + loshader_instanced_drawer_clear(&(drawer)->super, reserve) + void loshader_combat_ring_drawer_add_instance( loshader_combat_ring_drawer_t* drawer, diff --git a/core/loshader/event_line.c b/core/loshader/event_line.c index f555bce..6ac4adf 100644 --- a/core/loshader/event_line.c +++ b/core/loshader/event_line.c @@ -1,91 +1,32 @@ #include "./event_line.h" #include -#include #include "util/gleasy/program.h" #include "util/gleasy/texture.h" -#include "util/glyphas/block.h" -#include "util/glyphas/drawer.h" +#include "./text.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/event_line.vshader.h" -#include "anysrc/event_line.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/event_line.vshader.h" +#include "core/loshader/anysrc/event_line.fshader.h" -#define LOSHADER_EVENT_LINE_UNIBLOCK_INDEX 0 +#define UNIBLOCK_INDEX_ 0 -void loshader_event_line_program_initialize( - loshader_event_line_program_t* prog) { - assert(prog != NULL); +void loshader_event_line_drawer_initialize( + loshader_event_line_drawer_t* drawer, + const loshader_uniblock_t* uniblock, + gleasy_texture_2d_t tex) { + assert(drawer != NULL); + assert(uniblock != NULL); + assert(tex != 0); - *prog = gleasy_program_new( + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_event_line_vshader_, sizeof(loshader_event_line_vshader_), loshader_event_line_fshader_, sizeof(loshader_event_line_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, uniblock, LOSHADER_EVENT_LINE_UNIBLOCK_INDEX); -} - -void loshader_event_line_program_deinitialize( - loshader_event_line_program_t* prog) { - assert(prog != NULL); - - glDeleteProgram(*prog); -} - -void loshader_event_line_drawer_initialize( - loshader_event_line_drawer_t* drawer, - const loshader_event_line_program_t* prog, - const loshader_uniblock_t* uniblock, - gleasy_texture_2d_t tex) { - assert(drawer != NULL); - assert(prog != NULL); - assert(uniblock != NULL); - assert(tex != 0); - - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - .tex = tex, - - .glyphas = glyphas_drawer_new(), - }; -} - -void loshader_event_line_drawer_deinitialize( - loshader_event_line_drawer_t* drawer) { - assert(drawer != NULL); - - glyphas_drawer_delete(drawer->glyphas); -} - -void loshader_event_line_drawer_clear( - loshader_event_line_drawer_t* drawer, size_t reserve) { - assert(drawer != NULL); - assert(reserve > 0); - - glyphas_drawer_clear(drawer->glyphas, drawer->tex, reserve); -} - -void loshader_event_line_drawer_add_block( - loshader_event_line_drawer_t* drawer, const glyphas_block_t* block) { - assert(drawer != NULL); - assert(block != NULL); - - glyphas_drawer_add_block(drawer->glyphas, block); -} - -void loshader_event_line_drawer_draw(const loshader_event_line_drawer_t* drawer) { - assert(drawer != NULL); - - glUseProgram(*drawer->prog); - - loshader_uniblock_bind(drawer->uniblock, LOSHADER_EVENT_LINE_UNIBLOCK_INDEX); - - glyphas_drawer_draw(drawer->glyphas); + loshader_text_drawer_initialize(&drawer->super, prog, uniblock, tex); } diff --git a/core/loshader/event_line.h b/core/loshader/event_line.h index 14bdc2c..3c821e0 100644 --- a/core/loshader/event_line.h +++ b/core/loshader/event_line.h @@ -1,63 +1,29 @@ #pragma once -#include - -#include "util/gleasy/program.h" #include "util/gleasy/texture.h" -#include "util/glyphas/block.h" -#include "util/glyphas/drawer.h" +#include "./text.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_event_line_program_t; - typedef struct { - /* injected deps */ - const loshader_event_line_program_t* prog; - const loshader_uniblock_t* uniblock; - - gleasy_texture_2d_t tex; - - /* owned objects */ - glyphas_drawer_t* glyphas; + loshader_text_drawer_t super; } loshader_event_line_drawer_t; -void -loshader_event_line_program_initialize( - loshader_event_line_program_t* prog -); - -void -loshader_event_line_program_deinitialize( - loshader_event_line_program_t* prog -); - void loshader_event_line_drawer_initialize( - loshader_event_line_drawer_t* drawer, - const loshader_event_line_program_t* prog, - const loshader_uniblock_t* uniblock, - gleasy_texture_2d_t tex -); - -void -loshader_event_line_drawer_deinitialize( - loshader_event_line_drawer_t* drawer -); - -void -loshader_event_line_drawer_clear( loshader_event_line_drawer_t* drawer, - size_t reserve + const loshader_uniblock_t* uniblock, + gleasy_texture_2d_t tex ); -void -loshader_event_line_drawer_add_block( - loshader_event_line_drawer_t* drawer, - const glyphas_block_t* block -); +#define loshader_event_line_drawer_deinitialize(drawer) \ + loshader_text_drawer_deinitialize(&(drawer)->super) -void -loshader_event_line_drawer_draw( - const loshader_event_line_drawer_t* drawer -); +#define loshader_event_line_drawer_clear(drawer, reserve) \ + loshader_text_drawer_clear(&(drawer)->super, reserve) + +#define loshader_event_line_drawer_add_block(drawer, block) \ + loshader_text_drawer_add_block(&(drawer)->super, block) + +#define loshader_event_line_drawer_draw(drawer) \ + loshader_text_drawer_draw(&(drawer)->super) diff --git a/core/loshader/fog.c b/core/loshader/fog.c index d5d7026..fee7173 100644 --- a/core/loshader/fog.c +++ b/core/loshader/fog.c @@ -1,29 +1,21 @@ #include "./fog.h" #include -#include -#include -#include "util/gleasy/buffer.h" #include "util/gleasy/program.h" #include "util/math/vector.h" -#include "util/memory/memory.h" #include "core/locommon/position.h" +#include "./single.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/fog.vshader.h" -#include "anysrc/fog.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/fog.vshader.h" +#include "core/loshader/anysrc/fog.fshader.h" -struct loshader_fog_drawer_t { - const loshader_fog_program_t* prog; - const loshader_uniblock_t* uniblock; - - gleasy_buffer_uniform_t param; -}; +#define PRIMITIVE_COUNT_ 6 #pragma pack(push, 1) typedef struct { @@ -35,65 +27,29 @@ typedef struct { vec4_t bounds_pos; vec2_t bounds_size; } loshader_fog_drawer_internal_param_t; -_Static_assert( - sizeof(float)*10 == - sizeof(loshader_fog_drawer_internal_param_t)); #pragma pack(pop) -#define LOSHADER_FOG_UNIBLOCK_INDEX 0 -#define LOSHADER_FOG_PARAM_INDEX 1 +_Static_assert( + sizeof(float)*10 == + sizeof(loshader_fog_drawer_internal_param_t), + "recheck the type has no padding"); -#define LOSHADER_FOG_PRIMITIVE_COUNT 6 - -void loshader_fog_program_initialize(loshader_fog_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( - loshader_header_shader_, sizeof(loshader_header_shader_), - loshader_fog_vshader_, sizeof(loshader_fog_vshader_), - loshader_fog_fshader_, sizeof(loshader_fog_fshader_)); - - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, uniblock, LOSHADER_FOG_UNIBLOCK_INDEX); - - const GLuint param = glGetUniformBlockIndex(*prog, "param"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, param, LOSHADER_FOG_PARAM_INDEX); -} - -void loshader_fog_program_deinitialize(loshader_fog_program_t* prog) { - assert(prog != NULL); - - glDeleteProgram(*prog); -} - -loshader_fog_drawer_t* loshader_fog_drawer_new( - const loshader_fog_program_t* prog, - const loshader_uniblock_t* uniblock) { - assert(prog != NULL); +void loshader_fog_drawer_initialize( + loshader_fog_drawer_t* drawer, + const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); assert(uniblock != NULL); - loshader_fog_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - }; + const gleasy_program_t prog = gleasy_program_new( + loshader_header_shader_, sizeof(loshader_header_shader_), + loshader_fog_vshader_, sizeof(loshader_fog_vshader_), + loshader_fog_fshader_, sizeof(loshader_fog_fshader_)); - glGenBuffers(1, &drawer->param); - glBindBuffer(GL_UNIFORM_BUFFER, drawer->param); - glBufferData(GL_UNIFORM_BUFFER, - sizeof(loshader_fog_drawer_internal_param_t), NULL, GL_DYNAMIC_DRAW); - - return drawer; -} - -void loshader_fog_drawer_delete(loshader_fog_drawer_t* drawer) { - if (drawer == NULL) return; - - glDeleteBuffers(1, &drawer->param); - - memory_delete(drawer); + loshader_single_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_fog_drawer_internal_param_t)); } void loshader_fog_drawer_set_param( @@ -114,18 +70,11 @@ void loshader_fog_drawer_set_param( param->bounds_pos.fract.y), .bounds_size = param->bounds_size, }; - glBindBuffer(GL_UNIFORM_BUFFER, drawer->param); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(p), &p); + loshader_single_drawer_set_param(&drawer->super, &p); } void loshader_fog_drawer_draw(const loshader_fog_drawer_t* drawer) { assert(drawer != NULL); - glUseProgram(*drawer->prog); - - loshader_uniblock_bind(drawer->uniblock, LOSHADER_FOG_UNIBLOCK_INDEX); - glBindBufferBase(GL_UNIFORM_BUFFER, - LOSHADER_FOG_PARAM_INDEX, drawer->param); - - glDrawArrays(GL_TRIANGLES, 0, LOSHADER_FOG_PRIMITIVE_COUNT); + loshader_single_drawer_draw(&drawer->super, PRIMITIVE_COUNT_); } diff --git a/core/loshader/fog.fshader b/core/loshader/fog.fshader index b39c66d..9e78717 100644 --- a/core/loshader/fog.fshader +++ b/core/loshader/fog.fshader @@ -73,7 +73,7 @@ vec4 bounds_fog(void) { vec2 pos; pos.x = (p.bounds_pos.x - uni.pos.x) + (p.bounds_pos.z - uni.pos.z); - pos.y = (p.bounds_pos.y - uni.pos.y) + (p.bounds_pos.y - uni.pos.y); + pos.y = (p.bounds_pos.y - uni.pos.y) + (p.bounds_pos.w - uni.pos.w); pos = (uni.proj * uni.cam * vec4(pos, 0., 1.)).xy; vec2 size = (uni.proj * uni.cam * vec4(p.bounds_size, 0., 0.)).xy; diff --git a/core/loshader/fog.h b/core/loshader/fog.h index 47db16c..8c6ba5f 100644 --- a/core/loshader/fog.h +++ b/core/loshader/fog.h @@ -1,14 +1,15 @@ #pragma once -#include "util/gleasy/program.h" +#include "util/math/vector.h" #include "core/locommon/position.h" +#include "./single.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_fog_program_t; - -typedef struct loshader_fog_drawer_t loshader_fog_drawer_t; +typedef struct { + loshader_single_drawer_t super; +} loshader_fog_drawer_t; typedef enum { LOSHADER_FOG_TYPE_NONE = 0, @@ -27,25 +28,13 @@ typedef struct { } loshader_fog_drawer_param_t; void -loshader_fog_program_initialize( - loshader_fog_program_t* prog +loshader_fog_drawer_initialize( + loshader_fog_drawer_t* drawer, + const loshader_uniblock_t* uniblock ); -void -loshader_fog_program_deinitialize( - loshader_fog_program_t* prog -); - -loshader_fog_drawer_t* -loshader_fog_drawer_new( - const loshader_fog_program_t* prog, - const loshader_uniblock_t* uniblock -); - -void -loshader_fog_drawer_delete( - loshader_fog_drawer_t* drawer -); +#define loshader_fog_drawer_deinitialize(drawer) \ + loshader_single_drawer_deinitialize(&(drawer)->super) void loshader_fog_drawer_set_param( diff --git a/core/loshader/ground.c b/core/loshader/ground.c index aca1a08..752c07d 100644 --- a/core/loshader/ground.c +++ b/core/loshader/ground.c @@ -1,42 +1,25 @@ #include "./ground.h" #include -#include -#include #include #include -#include - -#include "util/math/algorithm.h" -#include "util/math/matrix.h" #include "util/math/vector.h" -#include "util/memory/memory.h" -#include "util/gleasy/buffer.h" #include "util/gleasy/program.h" +#include "./instanced.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/ground.vshader.h" -#include "anysrc/ground.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/ground.vshader.h" +#include "core/loshader/anysrc/ground.fshader.h" -#define LOSHADER_GROUND_VSHADER_IN_GROUND_ID 0 -#define LOSHADER_GROUND_VSHADER_IN_POS 1 -#define LOSHADER_GROUND_VSHADER_IN_SIZE 2 +#define VSHADER_IN_GROUND_ID_ 0 +#define VSHADER_IN_POS_ 1 +#define VSHADER_IN_SIZE_ 2 -struct loshader_ground_drawer_t { - const loshader_ground_program_t* prog; - - const loshader_uniblock_t* uniblock; - - GLuint vao; - - gleasy_buffer_array_t instances; - size_t instances_reserved; - size_t instances_length; -}; +#define PRIMITIVE_COUNT_ 6 #pragma pack(push, 1) typedef struct { @@ -47,90 +30,40 @@ typedef struct { } loshader_ground_drawer_internal_instance_t; #pragma pack(pop) -#define LOSHADER_GROUND_UNIBLOCK_INDEX 0 +void loshader_ground_drawer_initialize( + loshader_ground_drawer_t* drawer, + const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); + assert(uniblock != NULL); -#define LOSHADER_GROUND_PRIMITIVE_COUNT 6 - -static void loshader_ground_program_setup_vao_( - gleasy_buffer_array_t instances) { - assert(instances != 0); - - glBindBuffer(GL_ARRAY_BUFFER, instances); - -# define enable_attrib_(NAME, name, dim, type) do { \ - glEnableVertexAttribArray(LOSHADER_GROUND_VSHADER_IN_##NAME); \ - glVertexAttribPointer( \ - LOSHADER_GROUND_VSHADER_IN_##NAME, \ - dim, type, GL_FALSE, sizeof(loshader_ground_drawer_internal_instance_t), \ - NULL + offsetof(loshader_ground_drawer_internal_instance_t, name)); \ - glVertexAttribDivisor(LOSHADER_GROUND_VSHADER_IN_##NAME, 1); \ - } while (0) - enable_attrib_(GROUND_ID, ground_id, 1, GL_UNSIGNED_SHORT); - enable_attrib_(POS, pos, 2, GL_FLOAT); - enable_attrib_(SIZE, size, 2, GL_FLOAT); -# undef enable_attrib_ -} - -void loshader_ground_program_initialize(loshader_ground_program_t* prog) { - *prog = gleasy_program_new( + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_ground_vshader_, sizeof(loshader_ground_vshader_), loshader_ground_fshader_, sizeof(loshader_ground_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); + loshader_instanced_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_ground_drawer_internal_instance_t)); - glUniformBlockBinding(*prog, uniblock, LOSHADER_GROUND_UNIBLOCK_INDEX); -} -void loshader_ground_program_deinitialize(loshader_ground_program_t* prog) { - assert(prog != NULL); + glBindVertexArray(drawer->super.vao); + glBindBuffer(GL_ARRAY_BUFFER, drawer->super.instances); - glDeleteProgram(*prog); -} +# define enable_(index, var, dim, type) do { \ + glEnableVertexAttribArray(index); \ + glVertexAttribPointer( \ + index, dim, type, GL_FALSE, \ + sizeof(loshader_ground_drawer_internal_instance_t), \ + NULL + offsetof(loshader_ground_drawer_internal_instance_t, var)); \ + glVertexAttribDivisor(index, 1); \ + } while (0) -loshader_ground_drawer_t* loshader_ground_drawer_new( - const loshader_ground_program_t* prog, - const loshader_uniblock_t* uniblock) { - assert(prog != NULL); - assert(uniblock != NULL); + enable_(VSHADER_IN_GROUND_ID_, ground_id, 1, GL_UNSIGNED_SHORT); + enable_(VSHADER_IN_POS_, pos, 2, GL_FLOAT); + enable_(VSHADER_IN_SIZE_, size, 2, GL_FLOAT); - loshader_ground_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - }; - - glCreateVertexArrays(1, &drawer->vao); - glBindVertexArray(drawer->vao); - - glGenBuffers(1, &drawer->instances); - loshader_ground_program_setup_vao_(drawer->instances); - return drawer; -} - -void loshader_ground_drawer_delete(loshader_ground_drawer_t* drawer) { - if (drawer == NULL) return; - - glDeleteBuffers(1, &drawer->instances); - - glDeleteVertexArrays(1, &drawer->vao); - - memory_delete(drawer); -} - -void loshader_ground_drawer_clear( - loshader_ground_drawer_t* drawer, size_t reserve) { - assert(drawer != NULL); - - drawer->instances_length = 0; - - if (drawer->instances_reserved < reserve) { - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferData(GL_ARRAY_BUFFER, - reserve * sizeof(loshader_ground_drawer_instance_t), - NULL, GL_DYNAMIC_DRAW); - drawer->instances_reserved = reserve; - } +# undef enable_ } void loshader_ground_drawer_add_instance( @@ -139,36 +72,19 @@ void loshader_ground_drawer_add_instance( assert(drawer != NULL); assert(instance != NULL); - if (drawer->instances_length >= drawer->instances_reserved) { - fprintf(stderr, "ground drawer instance overflow\n"); - abort(); - } - const loshader_ground_drawer_internal_instance_t inst = { .ground_id = instance->ground_id, .pos = instance->pos, .size = instance->size, }; - - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferSubData(GL_ARRAY_BUFFER, - drawer->instances_length*sizeof(inst), sizeof(inst), &inst); - - ++drawer->instances_length; + if (!loshader_instanced_drawer_add_instance(&drawer->super, &inst)) { + fprintf(stderr, "ground drawer instance overflow\n"); + abort(); + } } void loshader_ground_drawer_draw(const loshader_ground_drawer_t* drawer) { assert(drawer != NULL); - if (drawer->instances_length == 0) return; - - glUseProgram(*drawer->prog); - glBindVertexArray(drawer->vao); - - loshader_uniblock_bind( - drawer->uniblock, LOSHADER_GROUND_UNIBLOCK_INDEX); - - glDrawArraysInstanced(GL_TRIANGLES, - 0, LOSHADER_GROUND_PRIMITIVE_COUNT, drawer->instances_length); + loshader_instanced_drawer_draw(&drawer->super, PRIMITIVE_COUNT_); } - diff --git a/core/loshader/ground.h b/core/loshader/ground.h index 1864811..62f4d3c 100644 --- a/core/loshader/ground.h +++ b/core/loshader/ground.h @@ -1,16 +1,14 @@ #pragma once -#include - #include "util/gleasy/program.h" #include "util/math/vector.h" +#include "./instanced.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_ground_program_t; - -struct loshader_ground_drawer_t; -typedef struct loshader_ground_drawer_t loshader_ground_drawer_t; +typedef struct { + loshader_instanced_drawer_t super; +} loshader_ground_drawer_t; typedef enum { LOSHADER_GROUND_ID_ISLAND = 0, @@ -24,31 +22,16 @@ typedef struct { } loshader_ground_drawer_instance_t; void -loshader_ground_program_initialize( - loshader_ground_program_t* prog +loshader_ground_drawer_initialize( + loshader_ground_drawer_t* drawer, + const loshader_uniblock_t* uniblock ); -void -loshader_ground_program_deinitialize( - loshader_ground_program_t* prog -); +#define loshader_ground_drawer_deinitialize(drawer) \ + loshader_instanced_drawer_deinitialize(&(drawer)->super) -loshader_ground_drawer_t* -loshader_ground_drawer_new( - const loshader_ground_program_t* prog, - const loshader_uniblock_t* uniblock -); - -void -loshader_ground_drawer_delete( - loshader_ground_drawer_t* drawer -); - -void -loshader_ground_drawer_clear( - loshader_ground_drawer_t* drawer, - size_t reserve -); +#define loshader_ground_drawer_clear(drawer, reserve) \ + loshader_instanced_drawer_clear(&(drawer)->super, reserve) void loshader_ground_drawer_add_instance( diff --git a/core/loshader/hud_bar.c b/core/loshader/hud_bar.c index 1c354ad..6bf079e 100644 --- a/core/loshader/hud_bar.c +++ b/core/loshader/hud_bar.c @@ -1,41 +1,28 @@ #include "./hud_bar.h" #include -#include #include #include -#include - -#include "util/gleasy/buffer.h" #include "util/gleasy/program.h" #include "util/math/vector.h" -#include "util/memory/memory.h" +#include "./instanced.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/hud_bar.vshader.h" -#include "anysrc/hud_bar.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/hud_bar.vshader.h" +#include "core/loshader/anysrc/hud_bar.fshader.h" -#define LOSHADER_HUD_BAR_VSHADER_IN_POS 0 -#define LOSHADER_HUD_BAR_VSHADER_IN_SIZE 1 -#define LOSHADER_HUD_BAR_VSHADER_IN_BGCOLOR 2 -#define LOSHADER_HUD_BAR_VSHADER_IN_FGCOLOR 3 -#define LOSHADER_HUD_BAR_VSHADER_IN_VALUE 4 -#define LOSHADER_HUD_BAR_VSHADER_IN_PREV_VALUE 5 +#define VSHADER_IN_POS_ 0 +#define VSHADER_IN_SIZE_ 1 +#define VSHADER_IN_BGCOLOR_ 2 +#define VSHADER_IN_FGCOLOR_ 3 +#define VSHADER_IN_VALUE_ 4 +#define VSHADER_IN_PREV_VALUE_ 5 -struct loshader_hud_bar_drawer_t { - const loshader_hud_bar_program_t* prog; - const loshader_uniblock_t* uniblock; - - GLuint vao; - - gleasy_buffer_array_t instances; - size_t instances_reserved; - size_t instances_length; -}; +#define PRIMITIVE_COUNT_ 18 #pragma pack(push, 1) typedef struct { @@ -50,99 +37,43 @@ typedef struct { } loshader_hud_bar_drawer_internal_instance_t; #pragma pack(pop) -#define LOSHADER_HUD_BAR_UNIBLOCK_INDEX 0 +void loshader_hud_bar_drawer_initialize( + loshader_hud_bar_drawer_t* drawer, + const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); + assert(uniblock != NULL); -#define LOSHADER_HUD_BAR_PRIMITIVE_COUNT 18 - -static void loshader_hud_bar_program_setup_vao_( - gleasy_buffer_array_t instances) { - assert(instances != 0); - - glBindBuffer(GL_ARRAY_BUFFER, instances); - -# define enable_attrib_(NAME, name, dim, type) do { \ - glEnableVertexAttribArray(LOSHADER_HUD_BAR_VSHADER_IN_##NAME); \ - glVertexAttribPointer( \ - LOSHADER_HUD_BAR_VSHADER_IN_##NAME, dim, type, GL_FALSE, \ - sizeof(loshader_hud_bar_drawer_internal_instance_t), \ - NULL + offsetof(loshader_hud_bar_drawer_internal_instance_t, name)); \ - glVertexAttribDivisor(LOSHADER_HUD_BAR_VSHADER_IN_##NAME, 1); \ - } while (0) - - enable_attrib_(POS, pos, 2, GL_FLOAT); - enable_attrib_(SIZE, size, 2, GL_FLOAT); - enable_attrib_(BGCOLOR, bgcolor, 4, GL_FLOAT); - enable_attrib_(FGCOLOR, fgcolor, 4, GL_FLOAT); - enable_attrib_(VALUE, value, 1, GL_FLOAT); - enable_attrib_(PREV_VALUE, prev_value, 1, GL_FLOAT); - -# undef enable_attrib_ -} - -void loshader_hud_bar_program_initialize(loshader_hud_bar_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_hud_bar_vshader_, sizeof(loshader_hud_bar_vshader_), loshader_hud_bar_fshader_, sizeof(loshader_hud_bar_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, uniblock, LOSHADER_HUD_BAR_UNIBLOCK_INDEX); -} + loshader_instanced_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_hud_bar_drawer_internal_instance_t)); -void loshader_hud_bar_program_deinitialize(loshader_hud_bar_program_t* prog) { - assert(prog != NULL); + glBindVertexArray(drawer->super.vao); + glBindBuffer(GL_ARRAY_BUFFER, drawer->super.instances); - glDeleteProgram(*prog); -} +# define enable_(index, var, dim, type) do { \ + glEnableVertexAttribArray(index); \ + glVertexAttribPointer( \ + index, dim, type, GL_FALSE, \ + sizeof(loshader_hud_bar_drawer_internal_instance_t), \ + NULL + offsetof(loshader_hud_bar_drawer_internal_instance_t, var)); \ + glVertexAttribDivisor(index, 1); \ + } while (0) -loshader_hud_bar_drawer_t* loshader_hud_bar_drawer_new( - const loshader_hud_bar_program_t* prog, - const loshader_uniblock_t* uniblock) { - assert(prog != NULL); - assert(uniblock != NULL); + enable_(VSHADER_IN_POS_, pos, 2, GL_FLOAT); + enable_(VSHADER_IN_SIZE_, size, 2, GL_FLOAT); + enable_(VSHADER_IN_BGCOLOR_, bgcolor, 4, GL_FLOAT); + enable_(VSHADER_IN_FGCOLOR_, fgcolor, 4, GL_FLOAT); + enable_(VSHADER_IN_VALUE_, value, 1, GL_FLOAT); + enable_(VSHADER_IN_PREV_VALUE_, prev_value, 1, GL_FLOAT); - loshader_hud_bar_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - }; - - glCreateVertexArrays(1, &drawer->vao); - glBindVertexArray(drawer->vao); - - glGenBuffers(1, &drawer->instances); - loshader_hud_bar_program_setup_vao_(drawer->instances); - - return drawer; -} - -void loshader_hud_bar_drawer_delete(loshader_hud_bar_drawer_t* drawer) { - if (drawer == NULL) return; - - glDeleteBuffers(1, &drawer->instances); - - glDeleteVertexArrays(1, &drawer->vao); - - memory_delete(drawer); -} - -void loshader_hud_bar_drawer_clear( - loshader_hud_bar_drawer_t* drawer, size_t reserve) { - assert(drawer != NULL); - assert(reserve > 0); - - drawer->instances_length = 0; - - if (drawer->instances_reserved < reserve) { - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferData(GL_ARRAY_BUFFER, - sizeof(loshader_hud_bar_drawer_internal_instance_t) * reserve, - NULL, GL_DYNAMIC_DRAW); - drawer->instances_reserved = reserve; - } +# undef enable_ } void loshader_hud_bar_drawer_add_instance( @@ -151,11 +82,6 @@ void loshader_hud_bar_drawer_add_instance( assert(drawer != NULL); assert(instance != NULL); - if (drawer->instances_length >= drawer->instances_reserved) { - fprintf(stderr, "hud bar drawer instance overflow\n"); - abort(); - } - const loshader_hud_bar_drawer_internal_instance_t insta = { .pos = instance->pos, .size = instance->size, @@ -164,24 +90,14 @@ void loshader_hud_bar_drawer_add_instance( .value = instance->value, .prev_value = instance->prev_value, }; - - const size_t offset = drawer->instances_length * sizeof(insta); - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(insta), &insta); - - ++drawer->instances_length; + if (!loshader_instanced_drawer_add_instance(&drawer->super, &insta)) { + fprintf(stderr, "hud bar drawer instance overflow\n"); + abort(); + } } void loshader_hud_bar_drawer_draw(const loshader_hud_bar_drawer_t* drawer) { assert(drawer != NULL); - if (drawer->instances_length == 0) return; - - glUseProgram(*drawer->prog); - glBindVertexArray(drawer->vao); - - loshader_uniblock_bind(drawer->uniblock, LOSHADER_HUD_BAR_UNIBLOCK_INDEX); - - glDrawArraysInstanced(GL_TRIANGLES, - 0, LOSHADER_HUD_BAR_PRIMITIVE_COUNT, drawer->instances_length); + loshader_instanced_drawer_draw(&drawer->super, PRIMITIVE_COUNT_); } diff --git a/core/loshader/hud_bar.h b/core/loshader/hud_bar.h index 7beb0ba..b088d5c 100644 --- a/core/loshader/hud_bar.h +++ b/core/loshader/hud_bar.h @@ -1,14 +1,13 @@ #pragma once -#include "util/gleasy/program.h" #include "util/math/vector.h" +#include "./instanced.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_hud_bar_program_t; - -struct loshader_hud_bar_drawer_t; -typedef struct loshader_hud_bar_drawer_t loshader_hud_bar_drawer_t; +typedef struct { + loshader_instanced_drawer_t super; +} loshader_hud_bar_drawer_t; typedef struct { vec2_t pos; @@ -22,32 +21,17 @@ typedef struct { } loshader_hud_bar_drawer_instance_t; void -loshader_hud_bar_program_initialize( - loshader_hud_bar_program_t* prog -); - -void -loshader_hud_bar_program_deinitialize( - loshader_hud_bar_program_t* prog -); - -loshader_hud_bar_drawer_t* /* OWNERSHIP */ -loshader_hud_bar_drawer_new( - const loshader_hud_bar_program_t* prog, - const loshader_uniblock_t* uniblock -); - -void -loshader_hud_bar_drawer_delete( - loshader_hud_bar_drawer_t* drawer /* OWNERSHIP */ -); - -void -loshader_hud_bar_drawer_clear( +loshader_hud_bar_drawer_initialize( loshader_hud_bar_drawer_t* drawer, - size_t reserve + const loshader_uniblock_t* uniblock ); +#define loshader_hud_bar_drawer_deinitialize(drawer) \ + loshader_instanced_drawer_deinitialize(&(drawer)->super) + +#define loshader_hud_bar_drawer_clear(drawer, reserve) \ + loshader_instanced_drawer_clear(&(drawer)->super, reserve) + void loshader_hud_bar_drawer_add_instance( loshader_hud_bar_drawer_t* drawer, diff --git a/core/loshader/hud_text.c b/core/loshader/hud_text.c index 4d68fc7..1ebb263 100644 --- a/core/loshader/hud_text.c +++ b/core/loshader/hud_text.c @@ -1,95 +1,42 @@ #include "./hud_text.h" #include -#include #include "util/gleasy/program.h" #include "util/gleasy/texture.h" -#include "util/glyphas/block.h" #include "util/glyphas/drawer.h" +#include "./text.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/hud_text.vshader.h" -#include "anysrc/hud_text.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/hud_text.vshader.h" +#include "core/loshader/anysrc/hud_text.fshader.h" -#define LOSHADER_HUD_TEXT_UNIFORM_ALPHA 1 +#define UNIFORM_ALPHA_ 1 /* 0 is used by the super class */ -#define LOSHADER_HUD_TEXT_UNIBLOCK_INDEX 0 +void loshader_hud_text_drawer_initialize( + loshader_hud_text_drawer_t* drawer, + const loshader_uniblock_t* uniblock, + gleasy_texture_2d_t tex) { + assert(drawer != NULL); + assert(uniblock != NULL); + assert(tex != 0); -void loshader_hud_text_program_initialize(loshader_hud_text_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_hud_text_vshader_, sizeof(loshader_hud_text_vshader_), loshader_hud_text_fshader_, sizeof(loshader_hud_text_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, uniblock, LOSHADER_HUD_TEXT_UNIBLOCK_INDEX); -} - -void loshader_hud_text_program_deinitialize(loshader_hud_text_program_t* prog) { - assert(prog != NULL); - - glDeleteProgram(*prog); -} - -void loshader_hud_text_drawer_initialize( - loshader_hud_text_drawer_t* drawer, - const loshader_hud_text_program_t* prog, - const loshader_uniblock_t* uniblock, - gleasy_texture_2d_t tex) { - assert(drawer != NULL); - assert(prog != NULL); - assert(uniblock != NULL); - assert(tex != 0); - - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - .tex = tex, - - .glyphas = glyphas_drawer_new(), - - .alpha = 1, - }; -} - -void loshader_hud_text_drawer_deinitialize( - loshader_hud_text_drawer_t* drawer) { - assert(drawer != NULL); - - glyphas_drawer_delete(drawer->glyphas); -} - -void loshader_hud_text_drawer_clear( - loshader_hud_text_drawer_t* drawer, size_t reserve) { - assert(drawer != NULL); - assert(reserve > 0); - - glyphas_drawer_clear(drawer->glyphas, drawer->tex, reserve); -} - -void loshader_hud_text_drawer_add_block( - loshader_hud_text_drawer_t* drawer, const glyphas_block_t* block) { - assert(drawer != NULL); - assert(block != NULL); - - glyphas_drawer_add_block(drawer->glyphas, block); + loshader_text_drawer_initialize(&drawer->super, prog, uniblock, tex); } void loshader_hud_text_drawer_draw(const loshader_hud_text_drawer_t* drawer) { assert(drawer != NULL); - glUseProgram(*drawer->prog); + glUseProgram(drawer->super.prog); + glUniform1f(UNIFORM_ALPHA_, drawer->alpha); - loshader_uniblock_bind(drawer->uniblock, LOSHADER_HUD_TEXT_UNIBLOCK_INDEX); - - glUniform1f(LOSHADER_HUD_TEXT_UNIFORM_ALPHA, drawer->alpha); - - glyphas_drawer_draw(drawer->glyphas); + loshader_text_drawer_draw_without_use_program(&drawer->super); } diff --git a/core/loshader/hud_text.h b/core/loshader/hud_text.h index d381f2c..5867852 100644 --- a/core/loshader/hud_text.h +++ b/core/loshader/hud_text.h @@ -1,64 +1,32 @@ #pragma once -#include - -#include "util/gleasy/program.h" #include "util/gleasy/texture.h" -#include "util/glyphas/block.h" -#include "util/glyphas/drawer.h" +#include "./text.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_hud_text_program_t; - typedef struct { - /* injected deps */ - const loshader_hud_text_program_t* prog; - const loshader_uniblock_t* uniblock; + loshader_text_drawer_t super; - gleasy_texture_2d_t tex; - - /* owned objects */ - glyphas_drawer_t* glyphas; - - /* public params */ + /* public mutable params */ float alpha; } loshader_hud_text_drawer_t; -void -loshader_hud_text_program_initialize( - loshader_hud_text_program_t* prog -); - -void -loshader_hud_text_program_deinitialize( - loshader_hud_text_program_t* prog -); - void loshader_hud_text_drawer_initialize( - loshader_hud_text_drawer_t* drawer, - const loshader_hud_text_program_t* prog, - const loshader_uniblock_t* uniblock, - gleasy_texture_2d_t tex -); - -void -loshader_hud_text_drawer_deinitialize( - loshader_hud_text_drawer_t* drawer -); - -void -loshader_hud_text_drawer_clear( loshader_hud_text_drawer_t* drawer, - size_t reserve + const loshader_uniblock_t* uniblock, + gleasy_texture_2d_t tex ); -void -loshader_hud_text_drawer_add_block( - loshader_hud_text_drawer_t* drawer, - const glyphas_block_t* block -); +#define loshader_hud_text_drawer_deinitialize(drawer) \ + loshader_text_drawer_deinitialize(&(drawer)->super) + +#define loshader_hud_text_drawer_clear(drawer, reserve) \ + loshader_text_drawer_clear(&(drawer)->super, reserve) + +#define loshader_hud_text_drawer_add_block(drawer, block) \ + loshader_text_drawer_add_block(&(drawer)->super, block) void loshader_hud_text_drawer_draw( diff --git a/core/loshader/instanced.c b/core/loshader/instanced.c new file mode 100644 index 0000000..8685fd1 --- /dev/null +++ b/core/loshader/instanced.c @@ -0,0 +1,92 @@ +#include "./instanced.h" + +#include +#include +#include + +#include + +#include "util/gleasy/buffer.h" +#include "util/gleasy/program.h" + +#include "./uniblock.h" + +#define UNIBLOCK_INDEX_ 0 + +void loshader_instanced_drawer_initialize( + loshader_instanced_drawer_t* drawer, + gleasy_program_t prog, + const loshader_uniblock_t* uniblock, + size_t instance_size) { + assert(drawer != NULL); + assert(uniblock != NULL); + assert(instance_size > 0); + + const GLuint uniblock_index = glGetUniformBlockIndex(prog, "uniblock"); + assert(glGetError() == GL_NO_ERROR); + glUniformBlockBinding(prog, uniblock_index, UNIBLOCK_INDEX_); + + *drawer = (typeof(*drawer)) { + .prog = prog, + .uniblock = uniblock, + .instance_size = instance_size, + }; + + glCreateVertexArrays(1, &drawer->vao); + glGenBuffers(1, &drawer->instances); +} + +void loshader_instanced_drawer_deinitialize( + loshader_instanced_drawer_t* drawer) { + assert(drawer != NULL); + + glDeleteVertexArrays(1, &drawer->vao); + glDeleteBuffers(1, &drawer->instances); + glDeleteProgram(drawer->prog); +} + +void loshader_instanced_drawer_clear( + loshader_instanced_drawer_t* drawer, size_t reserve) { + assert(drawer != NULL); + assert(reserve > 0); + + drawer->instances_length = 0; + + if (drawer->instances_reserved < reserve) { + glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); + glBufferData(GL_ARRAY_BUFFER, + reserve*drawer->instance_size, NULL, GL_DYNAMIC_DRAW); + drawer->instances_reserved = reserve; + } +} + +bool loshader_instanced_drawer_add_instance( + loshader_instanced_drawer_t* drawer, const void* instance) { + assert(drawer != NULL); + assert(instance != NULL); + + if (drawer->instances_length >= drawer->instances_reserved) { + return false; + } + + const size_t offset = drawer->instances_length*drawer->instance_size; + glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); + glBufferSubData(GL_ARRAY_BUFFER, offset, drawer->instance_size, instance); + + ++drawer->instances_length; + return true; +} + +void loshader_instanced_drawer_draw( + const loshader_instanced_drawer_t* drawer, size_t primitives) { + assert(drawer != NULL); + + if (primitives == 0 || drawer->instances_length == 0) return; + + glUseProgram(drawer->prog); + glBindVertexArray(drawer->vao); + + loshader_uniblock_bind(drawer->uniblock, UNIBLOCK_INDEX_); + + glDrawArraysInstanced(GL_TRIANGLES, 0, primitives, drawer->instances_length); +} diff --git a/core/loshader/instanced.h b/core/loshader/instanced.h new file mode 100644 index 0000000..a606f2f --- /dev/null +++ b/core/loshader/instanced.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#include + +#include "util/gleasy/buffer.h" +#include "util/gleasy/program.h" + +#include "./uniblock.h" + +typedef struct { + gleasy_program_t prog; + const loshader_uniblock_t* uniblock; + + GLuint vao; + + size_t instance_size; + + gleasy_buffer_array_t instances; + size_t instances_reserved; + size_t instances_length; +} loshader_instanced_drawer_t; + +void +loshader_instanced_drawer_initialize( + loshader_instanced_drawer_t* drawer, + gleasy_program_t prog, /* OWNERSHIP */ + const loshader_uniblock_t* uniblock, + size_t instance_size +); + +void +loshader_instanced_drawer_deinitialize( + loshader_instanced_drawer_t* drawer +); + +void +loshader_instanced_drawer_clear( + loshader_instanced_drawer_t* drawer, + size_t reserve +); + +bool +loshader_instanced_drawer_add_instance( + loshader_instanced_drawer_t* drawer, + const void* instance +); + +void +loshader_instanced_drawer_draw( + const loshader_instanced_drawer_t* drawer, + size_t primitives +); diff --git a/core/loshader/menu_background.c b/core/loshader/menu_background.c index 9dbb994..8ce0f99 100644 --- a/core/loshader/menu_background.c +++ b/core/loshader/menu_background.c @@ -1,36 +1,30 @@ #include "./menu_background.h" #include - -#include +#include #include "util/gleasy/program.h" #include "util/math/algorithm.h" -#include "util/memory/memory.h" +#include "./single.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/menu_background.vshader.h" -#include "anysrc/menu_background.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/menu_background.vshader.h" +#include "core/loshader/anysrc/menu_background.fshader.h" -#define LOSHADER_MENU_BACKGROUND_UNIFORM_ALPHA 0 +#define UNIFORM_ALPHA_ 0 -struct loshader_menu_background_drawer_t { - const loshader_menu_background_program_t* prog; - const loshader_uniblock_t* uniblock; +#define PRIMITIVE_COUNT_ 6 - float alpha; -}; +void loshader_menu_background_drawer_initialize( + loshader_menu_background_drawer_t* drawer, + const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); + assert(uniblock != NULL); -#define LOSHADER_MENU_BACKGROUND_UNIBLOCK_INDEX 0 - -void loshader_menu_background_program_initialize( - loshader_menu_background_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_menu_background_vshader_, @@ -38,60 +32,19 @@ void loshader_menu_background_program_initialize( loshader_menu_background_fshader_, sizeof(loshader_menu_background_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding( - *prog, uniblock, LOSHADER_MENU_BACKGROUND_UNIBLOCK_INDEX); -} - -void loshader_menu_background_program_deinitialize( - loshader_menu_background_program_t* prog) { - assert(prog != NULL); - - glDeleteProgram(*prog); -} - -loshader_menu_background_drawer_t* loshader_menu_background_drawer_new( - const loshader_menu_background_program_t* prog, - const loshader_uniblock_t* uniblock) { - assert(prog != NULL); - assert(uniblock != NULL); - - loshader_menu_background_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - }; - return drawer; -} - -void loshader_menu_background_drawer_delete( - loshader_menu_background_drawer_t* drawer) { - if (drawer == NULL) return; - - memory_delete(drawer); -} - -void loshader_menu_background_drawer_set_alpha( - loshader_menu_background_drawer_t* drawer, float alpha) { - assert(drawer != NULL); - assert(MATH_FLOAT_VALID(alpha)); - - drawer->alpha = alpha; + loshader_single_drawer_initialize(&drawer->super, prog, uniblock, 0); } void loshader_menu_background_drawer_draw( const loshader_menu_background_drawer_t* drawer) { assert(drawer != NULL); + assert(MATH_FLOAT_VALID(drawer->alpha)); if (drawer->alpha == 0) return; - glUseProgram(*drawer->prog); + glUseProgram(drawer->super.prog); + glUniform1f(UNIFORM_ALPHA_, drawer->alpha); - loshader_uniblock_bind( - drawer->uniblock, LOSHADER_MENU_BACKGROUND_UNIBLOCK_INDEX); - - glUniform1f(LOSHADER_MENU_BACKGROUND_UNIFORM_ALPHA, drawer->alpha); - - glDrawArrays(GL_TRIANGLES, 0, 6); + loshader_single_drawer_draw_without_use_program( + &drawer->super, PRIMITIVE_COUNT_); } diff --git a/core/loshader/menu_background.h b/core/loshader/menu_background.h index b4ec9ce..100d6b9 100644 --- a/core/loshader/menu_background.h +++ b/core/loshader/menu_background.h @@ -2,42 +2,25 @@ #include "util/gleasy/program.h" +#include "./single.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_menu_background_program_t; +typedef struct { + loshader_single_drawer_t super; -struct loshader_menu_background_drawer_t; -typedef - struct loshader_menu_background_drawer_t - loshader_menu_background_drawer_t; + /* public mutable params */ + float alpha; +} loshader_menu_background_drawer_t; void -loshader_menu_background_program_initialize( - loshader_menu_background_program_t* prog -); - -void -loshader_menu_background_program_deinitialize( - loshader_menu_background_program_t* prog -); - -loshader_menu_background_drawer_t* -loshader_menu_background_drawer_new( - const loshader_menu_background_program_t* prog, - const loshader_uniblock_t* uniblock -); - -void -loshader_menu_background_drawer_delete( - loshader_menu_background_drawer_t* drawer -); - -void -loshader_menu_background_drawer_set_alpha( +loshader_menu_background_drawer_initialize( loshader_menu_background_drawer_t* drawer, - float alpha + const loshader_uniblock_t* uniblock ); +#define loshader_menu_background_drawer_deinitialize(drawer) \ + loshader_single_drawer_deinitialize(&(drawer)->super) + void loshader_menu_background_drawer_draw( const loshader_menu_background_drawer_t* drawer diff --git a/core/loshader/menu_stance.c b/core/loshader/menu_stance.c index c31486f..1a9fcdb 100644 --- a/core/loshader/menu_stance.c +++ b/core/loshader/menu_stance.c @@ -7,34 +7,23 @@ #include -#include "util/gleasy/buffer.h" #include "util/gleasy/program.h" #include "util/math/vector.h" -#include "util/memory/memory.h" +#include "./instanced.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/menu_stance.vshader.h" -#include "anysrc/menu_stance.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/menu_stance.vshader.h" +#include "core/loshader/anysrc/menu_stance.fshader.h" -#define LOSHADER_MENU_STANCE_VSHADER_IN_ID 0 -#define LOSHADER_MENU_STANCE_VSHADER_IN_POS 1 -#define LOSHADER_MENU_STANCE_VSHADER_IN_SIZE 2 -#define LOSHADER_MENU_STANCE_VSHADER_IN_ALPHA 3 -#define LOSHADER_MENU_STANCE_VSHADER_IN_HIGHLIGHT 4 +#define VSHADER_IN_ID_ 0 +#define VSHADER_IN_POS_ 1 +#define VSHADER_IN_SIZE_ 2 +#define VSHADER_IN_ALPHA_ 3 -struct loshader_menu_stance_drawer_t { - const loshader_menu_stance_program_t* prog; - const loshader_uniblock_t* uniblock; - - GLuint vao; - - gleasy_buffer_array_t instances; - size_t instances_length; - size_t instances_reserved; -}; +#define PRIMITIVE_COUNT_ 60 #pragma pack(push, 1) typedef struct { @@ -42,104 +31,44 @@ typedef struct { vec2_t pos; vec2_t size; float alpha; - float highlight; } loshader_menu_stance_drawer_internal_instance_t; #pragma pack(pop) -#define LOSHADER_MENU_STANCE_UNIBLOCK_INDEX 0 -#define LOSHADER_MENU_STANCE_PRIMITIVE_COUNT 60 +void loshader_menu_stance_drawer_initialize( + loshader_menu_stance_drawer_t* drawer, + const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); + assert(uniblock != NULL); -static void loshader_menu_stance_program_setup_vao_( - gleasy_buffer_array_t instances) { - assert(instances != 0); - - glBindBuffer(GL_ARRAY_BUFFER, instances); - -# define enable_attrib_(NAME, name, dim, type) do { \ - glEnableVertexAttribArray(LOSHADER_MENU_STANCE_VSHADER_IN_##NAME); \ - glVertexAttribPointer( \ - LOSHADER_MENU_STANCE_VSHADER_IN_##NAME, dim, type, GL_FALSE, \ - sizeof(loshader_menu_stance_drawer_internal_instance_t), \ - NULL + offsetof(loshader_menu_stance_drawer_internal_instance_t, name)); \ - glVertexAttribDivisor(LOSHADER_MENU_STANCE_VSHADER_IN_##NAME, 1); \ - } while (0) - - enable_attrib_(ID, id, 1, GL_UNSIGNED_BYTE); - enable_attrib_(POS, pos, 2, GL_FLOAT); - enable_attrib_(SIZE, size, 2, GL_FLOAT); - enable_attrib_(ALPHA, alpha, 1, GL_FLOAT); - enable_attrib_(HIGHLIGHT, highlight, 1, GL_FLOAT); - -# undef enable_attrib_ -} - -void loshader_menu_stance_program_initialize( - loshader_menu_stance_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_menu_stance_vshader_, sizeof(loshader_menu_stance_vshader_), loshader_menu_stance_fshader_, sizeof(loshader_menu_stance_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, uniblock, LOSHADER_MENU_STANCE_UNIBLOCK_INDEX); -} + loshader_instanced_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_menu_stance_drawer_internal_instance_t)); -void loshader_menu_stance_program_deinitialize( - loshader_menu_stance_program_t* prog) { - assert(prog != NULL); + glBindVertexArray(drawer->super.vao); + glBindBuffer(GL_ARRAY_BUFFER, drawer->super.instances); - glDeleteProgram(*prog); -} +# define enable_(index, var, dim, type) do { \ + glEnableVertexAttribArray(index); \ + glVertexAttribPointer( \ + index, dim, type, GL_FALSE, \ + sizeof(loshader_menu_stance_drawer_internal_instance_t), \ + NULL + offsetof(loshader_menu_stance_drawer_internal_instance_t, var)); \ + glVertexAttribDivisor(index, 1); \ + } while (0) -loshader_menu_stance_drawer_t* loshader_menu_stance_drawer_new( - const loshader_menu_stance_program_t* prog, - const loshader_uniblock_t* uniblock) { - assert(prog != NULL); - assert(uniblock != NULL); + enable_(VSHADER_IN_ID_, id, 1, GL_UNSIGNED_BYTE); + enable_(VSHADER_IN_POS_, pos, 2, GL_FLOAT); + enable_(VSHADER_IN_SIZE_, size, 2, GL_FLOAT); + enable_(VSHADER_IN_ALPHA_, alpha, 1, GL_FLOAT); - loshader_menu_stance_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - }; - - glCreateVertexArrays(1, &drawer->vao); - glBindVertexArray(drawer->vao); - - glGenBuffers(1, &drawer->instances); - loshader_menu_stance_program_setup_vao_(drawer->instances); - - return drawer; -} - -void loshader_menu_stance_drawer_delete( - loshader_menu_stance_drawer_t* drawer) { - assert(drawer != NULL); - - glDeleteBuffers(1, &drawer->instances); - - glDeleteVertexArrays(1, &drawer->vao); - - memory_delete(drawer); -} - -void loshader_menu_stance_drawer_clear( - loshader_menu_stance_drawer_t* drawer, size_t reserve) { - assert(drawer != NULL); - assert(reserve > 0); - - drawer->instances_length = 0; - - if (drawer->instances_reserved < reserve) { - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferData(GL_ARRAY_BUFFER, - reserve * sizeof(loshader_menu_stance_drawer_internal_instance_t), - NULL, GL_DYNAMIC_DRAW); - drawer->instances_reserved = reserve; - } +# undef enable_ } void loshader_menu_stance_drawer_add_instance( @@ -148,38 +77,21 @@ void loshader_menu_stance_drawer_add_instance( assert(drawer != NULL); assert(instance != NULL); - if (drawer->instances_length >= drawer->instances_reserved) { - fprintf(stderr, "menu stance drawer instance overflow\n"); - abort(); - } - const loshader_menu_stance_drawer_internal_instance_t insta = { .id = instance->id, .pos = instance->pos, .size = instance->size, .alpha = instance->alpha, - .highlight = instance->highlight, }; - - const size_t offset = drawer->instances_length * sizeof(insta); - glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); - glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(insta), &insta); - - ++drawer->instances_length; + if (!loshader_instanced_drawer_add_instance(&drawer->super, &insta)) { + fprintf(stderr, "menu stance drawer overflow\n"); + abort(); + } } void loshader_menu_stance_drawer_draw( const loshader_menu_stance_drawer_t* drawer) { assert(drawer != NULL); - if (drawer->instances_length == 0) return; - - glUseProgram(*drawer->prog); - glBindVertexArray(drawer->vao); - - loshader_uniblock_bind( - drawer->uniblock, LOSHADER_MENU_STANCE_UNIBLOCK_INDEX); - - glDrawArraysInstanced(GL_TRIANGLES, - 0, LOSHADER_MENU_STANCE_PRIMITIVE_COUNT, drawer->instances_length); + loshader_instanced_drawer_draw(&drawer->super, PRIMITIVE_COUNT_); } diff --git a/core/loshader/menu_stance.h b/core/loshader/menu_stance.h index 93d41f2..ec6dc3f 100644 --- a/core/loshader/menu_stance.h +++ b/core/loshader/menu_stance.h @@ -1,16 +1,13 @@ #pragma once -#include - -#include "util/gleasy/program.h" #include "util/math/vector.h" +#include "./instanced.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_menu_stance_program_t; - -struct loshader_menu_stance_drawer_t; -typedef struct loshader_menu_stance_drawer_t loshader_menu_stance_drawer_t; +typedef struct { + loshader_instanced_drawer_t super; +} loshader_menu_stance_drawer_t; typedef enum { LOSHADER_MENU_STANCE_ID_EMPTY = 0, @@ -18,6 +15,7 @@ typedef enum { LOSHADER_MENU_STANCE_ID_REVOLUTIONER = 2, LOSHADER_MENU_STANCE_ID_UNFINISHER = 3, LOSHADER_MENU_STANCE_ID_PHILOSOPHER = 4, + LOSHADER_MENU_STANCE_ID_BETRAYER = 0, /* NOT IMPELEMENTED */ } loshader_menu_stance_id_t; typedef struct { @@ -26,36 +24,20 @@ typedef struct { vec2_t pos; vec2_t size; float alpha; - float highlight; } loshader_menu_stance_drawer_instance_t; void -loshader_menu_stance_program_initialize( - loshader_menu_stance_program_t* prog -); - -void -loshader_menu_stance_program_deinitialize( - loshader_menu_stance_program_t* prog -); - -loshader_menu_stance_drawer_t* -loshader_menu_stance_drawer_new( - const loshader_menu_stance_program_t* prog, - const loshader_uniblock_t* uniblock -); - -void -loshader_menu_stance_drawer_delete( - loshader_menu_stance_drawer_t* drawer -); - -void -loshader_menu_stance_drawer_clear( +loshader_menu_stance_drawer_initialize( loshader_menu_stance_drawer_t* drawer, - size_t reserve + const loshader_uniblock_t* uniblock ); +#define loshader_menu_stance_drawer_deinitialize(drawer) \ + loshader_instanced_drawer_deinitialize(&(drawer)->super) + +#define loshader_menu_stance_drawer_clear(drawer, reserve) \ + loshader_instanced_drawer_clear(&(drawer)->super, reserve) + void loshader_menu_stance_drawer_add_instance( loshader_menu_stance_drawer_t* drawer, diff --git a/core/loshader/menu_stance.vshader b/core/loshader/menu_stance.vshader index 10bc297..cd31df2 100644 --- a/core/loshader/menu_stance.vshader +++ b/core/loshader/menu_stance.vshader @@ -2,7 +2,6 @@ layout (location = 0) in float i_id; layout (location = 1) in vec2 i_pos; layout (location = 2) in vec2 i_size; layout (location = 3) in float i_alpha; -layout (location = 4) in float i_highlight; out float v_id; out vec2 v_uv; @@ -88,6 +87,5 @@ void main(void) { v_id = i_id; v_alpha = i_alpha; - float s = i_highlight*.2 + 1.; - gl_Position = vec4(v_uv*i_size*s + i_pos, 0., 1.); + gl_Position = vec4(v_uv*i_size + i_pos, 0., 1.); } diff --git a/core/loshader/menu_text.c b/core/loshader/menu_text.c index ee6e339..7f9d082 100644 --- a/core/loshader/menu_text.c +++ b/core/loshader/menu_text.c @@ -1,97 +1,42 @@ #include "./menu_text.h" #include -#include #include "util/gleasy/program.h" #include "util/gleasy/texture.h" -#include "util/glyphas/block.h" #include "util/glyphas/drawer.h" +#include "./text.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/menu_text.vshader.h" -#include "anysrc/menu_text.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/menu_text.vshader.h" +#include "core/loshader/anysrc/menu_text.fshader.h" -#define LOSHADER_MENU_TEXT_UNIFORM_ALPHA 1 - -#define LOSHADER_MENU_TEXT_UNIBLOCK_INDEX 0 - -void loshader_menu_text_program_initialize( - loshader_menu_text_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( - loshader_header_shader_, sizeof(loshader_header_shader_), - loshader_menu_text_vshader_, sizeof(loshader_menu_text_vshader_), - loshader_menu_text_fshader_, sizeof(loshader_menu_text_fshader_)); - - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, uniblock, LOSHADER_MENU_TEXT_UNIBLOCK_INDEX); -} - -void loshader_menu_text_program_deinitialize( - loshader_menu_text_program_t* prog) { - assert(prog != NULL); - - glDeleteProgram(*prog); -} +#define UNIFORM_ALPHA_ 1 /* 0 is used by the super class */ void loshader_menu_text_drawer_initialize( - loshader_menu_text_drawer_t* drawer, - const loshader_menu_text_program_t* prog, - const loshader_uniblock_t* uniblock, - gleasy_texture_2d_t tex) { + loshader_menu_text_drawer_t* drawer, + const loshader_uniblock_t* uniblock, + gleasy_texture_2d_t tex) { assert(drawer != NULL); - assert(prog != NULL); assert(uniblock != NULL); assert(tex != 0); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - .tex = tex, + const gleasy_program_t prog = gleasy_program_new( + loshader_header_shader_, sizeof(loshader_header_shader_), + loshader_menu_text_vshader_, sizeof(loshader_menu_text_vshader_), + loshader_menu_text_fshader_, sizeof(loshader_menu_text_fshader_)); - .glyphas = glyphas_drawer_new(), - - .alpha = 1, - }; -} - -void loshader_menu_text_drawer_deinitialize( - loshader_menu_text_drawer_t* drawer) { - assert(drawer != NULL); - - glyphas_drawer_delete(drawer->glyphas); -} - -void loshader_menu_text_drawer_clear( - loshader_menu_text_drawer_t* drawer, size_t reserve) { - assert(drawer != NULL); - assert(reserve > 0); - - glyphas_drawer_clear(drawer->glyphas, drawer->tex, reserve); -} - -void loshader_menu_text_drawer_add_block( - loshader_menu_text_drawer_t* drawer, const glyphas_block_t* block) { - assert(drawer != NULL); - assert(block != NULL); - - glyphas_drawer_add_block(drawer->glyphas, block); + loshader_text_drawer_initialize(&drawer->super, prog, uniblock, tex); } void loshader_menu_text_drawer_draw(const loshader_menu_text_drawer_t* drawer) { assert(drawer != NULL); - glUseProgram(*drawer->prog); + glUseProgram(drawer->super.prog); + glUniform1f(UNIFORM_ALPHA_, drawer->alpha); - loshader_uniblock_bind(drawer->uniblock, LOSHADER_MENU_TEXT_UNIBLOCK_INDEX); - - glUniform1f(LOSHADER_MENU_TEXT_UNIFORM_ALPHA, drawer->alpha); - - glyphas_drawer_draw(drawer->glyphas); + loshader_text_drawer_draw_without_use_program(&drawer->super); } diff --git a/core/loshader/menu_text.h b/core/loshader/menu_text.h index 64f5261..81eeab9 100644 --- a/core/loshader/menu_text.h +++ b/core/loshader/menu_text.h @@ -1,64 +1,34 @@ #pragma once -#include - -#include "util/gleasy/program.h" #include "util/gleasy/texture.h" -#include "util/glyphas/block.h" -#include "util/glyphas/drawer.h" +#include "./text.h" #include "./uniblock.h" typedef gleasy_program_t loshader_menu_text_program_t; typedef struct { - /* injected deps */ - const loshader_menu_text_program_t* prog; - const loshader_uniblock_t* uniblock; + loshader_text_drawer_t super; - gleasy_texture_2d_t tex; - - /* owned objects */ - glyphas_drawer_t* glyphas; - - /* public params */ + /* public mutable params */ float alpha; } loshader_menu_text_drawer_t; -void -loshader_menu_text_program_initialize( - loshader_menu_text_program_t* prog -); - -void -loshader_menu_text_program_deinitialize( - loshader_menu_text_program_t* prog -); - void loshader_menu_text_drawer_initialize( - loshader_menu_text_drawer_t* drawer, - const loshader_menu_text_program_t* prog, - const loshader_uniblock_t* uniblock, - gleasy_texture_2d_t tex -); - -void -loshader_menu_text_drawer_deinitialize( - loshader_menu_text_drawer_t* drawer -); - -void -loshader_menu_text_drawer_clear( loshader_menu_text_drawer_t* drawer, - size_t reserve + const loshader_uniblock_t* uniblock, + gleasy_texture_2d_t tex ); -void -loshader_menu_text_drawer_add_block( - loshader_menu_text_drawer_t* drawer, - const glyphas_block_t* block -); +#define loshader_menu_text_drawer_deinitialize(drawer) \ + loshader_text_drawer_deinitialize(&(drawer)->super) + +#define loshader_menu_text_drawer_clear(drawer, reserve) \ + loshader_text_drawer_clear(&(drawer)->super, reserve) + +#define loshader_menu_text_drawer_add_block(drawer, block) \ + loshader_text_drawer_add_block(&(drawer)->super, block) void loshader_menu_text_drawer_draw( diff --git a/core/loshader/particle.c b/core/loshader/particle.c new file mode 100644 index 0000000..7fd8955 --- /dev/null +++ b/core/loshader/particle.c @@ -0,0 +1,99 @@ +#include "./particle.h" + +#include +#include +#include +#include +#include + +#include + +#include "util/gleasy/program.h" +#include "util/math/vector.h" + +#include "./instanced.h" +#include "./uniblock.h" + +/* resources */ +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/particle.vshader.h" +#include "core/loshader/anysrc/particle.fshader.h" + +#define VSHADER_IN_PARTICLE_ID_ 0 +#define VSHADER_IN_POS_ 1 +#define VSHADER_IN_SIZE_ 2 +#define VSHADER_IN_COLOR_ 3 +#define VSHADER_IN_TIME_ 4 + +#define PRIMITIVE_COUNT_ 6 + +#pragma pack(push, 1) +typedef struct { + uint16_t particle_id; + vec2_t pos; + vec2_t size; + vec4_t color; + float time; +} loshader_particle_drawer_internal_instance_t; +#pragma pack(pop) + +void loshader_particle_drawer_initialize( + loshader_particle_drawer_t* drawer, + const loshader_uniblock_t* uniblock) { + assert(drawer != NULL); + assert(uniblock != NULL); + + const gleasy_program_t prog = gleasy_program_new( + loshader_header_shader_, sizeof(loshader_header_shader_), + loshader_particle_vshader_, sizeof(loshader_particle_vshader_), + loshader_particle_fshader_, sizeof(loshader_particle_fshader_)); + + loshader_instanced_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_particle_drawer_internal_instance_t)); + + glBindVertexArray(drawer->super.vao); + glBindBuffer(GL_ARRAY_BUFFER, drawer->super.instances); + +# define enable_(index, var, dim, type) do { \ + glEnableVertexAttribArray(index); \ + glVertexAttribPointer( \ + index, dim, type, GL_FALSE, \ + sizeof(loshader_particle_drawer_internal_instance_t), \ + NULL + offsetof(loshader_particle_drawer_internal_instance_t, var)); \ + glVertexAttribDivisor(index, 1); \ + } while (0) + + enable_(VSHADER_IN_PARTICLE_ID_, particle_id, 1, GL_UNSIGNED_SHORT); + enable_(VSHADER_IN_POS_, pos, 2, GL_FLOAT); + enable_(VSHADER_IN_SIZE_, size, 2, GL_FLOAT); + enable_(VSHADER_IN_COLOR_, color, 4, GL_FLOAT); + enable_(VSHADER_IN_TIME_, time, 1, GL_FLOAT); + +# undef enable_ +} + +void loshader_particle_drawer_add_instance( + loshader_particle_drawer_t* drawer, + const loshader_particle_drawer_instance_t* instance) { + assert(drawer != NULL); + assert(instance != NULL); + + const loshader_particle_drawer_internal_instance_t inst = { + .particle_id = instance->particle_id, + .pos = instance->pos, + .size = instance->size, + }; + if (!loshader_instanced_drawer_add_instance(&drawer->super, &inst)) { + fprintf(stderr, "particle drawer instance overflow\n"); + abort(); + } +} + +void loshader_particle_drawer_draw(const loshader_particle_drawer_t* drawer) { + assert(drawer != NULL); + + loshader_instanced_drawer_draw(&drawer->super, PRIMITIVE_COUNT_); +} diff --git a/core/loshader/particle.fshader b/core/loshader/particle.fshader new file mode 100644 index 0000000..e9bedec --- /dev/null +++ b/core/loshader/particle.fshader @@ -0,0 +1,9 @@ +in vec2 v_uv; +in vec4 v_color; +in float v_time; + +out vec4 o_color; + +void main(void) { + o_color = vec4(0., 0., 0., 1.); +} diff --git a/core/loshader/particle.h b/core/loshader/particle.h new file mode 100644 index 0000000..612d222 --- /dev/null +++ b/core/loshader/particle.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +#include "util/math/vector.h" + +#include "./instanced.h" +#include "./uniblock.h" + +typedef struct { + loshader_instanced_drawer_t super; +} loshader_particle_drawer_t; + +typedef enum { + LOSHADER_PARTICLE_ID_PLAYER = 0, + LOSHADER_PARTICLE_ID_ENCEPHALON = 1, + LOSHADER_PARTICLE_ID_CAVIA = 2, + LOSHADER_PARTICLE_ID_SCIENTIST = 3, + LOSHADER_PARTICLE_ID_WARDER = 4, +} loshader_particle_id_t; + +typedef struct { + loshader_particle_id_t particle_id; + vec2_t pos; + vec2_t size; + vec4_t color; + float time; +} loshader_particle_drawer_instance_t; + +void +loshader_particle_drawer_initialize( + loshader_particle_drawer_t* drawer, + const loshader_uniblock_t* uniblock +); + +#define loshader_particle_drawer_deinitialize(drawer) \ + loshader_instanced_drawer_deinitialize(&(drawer)->super) + +#define loshader_particle_drawer_clear(drawer, reserve) \ + loshader_instanced_drawer_clear(&(drawer)->super, reserve) + +void +loshader_particle_drawer_add_instance( + loshader_particle_drawer_t* drawer, + const loshader_particle_drawer_instance_t* instance +); + +void +loshader_particle_drawer_draw( + const loshader_particle_drawer_t* drawer +); diff --git a/core/loshader/particle.vshader b/core/loshader/particle.vshader new file mode 100644 index 0000000..8d1c88f --- /dev/null +++ b/core/loshader/particle.vshader @@ -0,0 +1,17 @@ +layout (location = 0) in float i_particle_id; +layout (location = 1) in vec2 i_pos; +layout (location = 2) in vec2 i_size; +layout (location = 3) in vec4 i_color; +layout (location = 4) in float i_time; + +out vec2 v_uv; +out vec4 v_color; +out float v_time; + +void main(void) { + v_uv = vec2(0.); + v_color = i_color; + v_time = i_time; + + gl_Position = vec4(0.); +} diff --git a/core/loshader/pixsort.c b/core/loshader/pixsort.c index c4d9426..9b8966c 100644 --- a/core/loshader/pixsort.c +++ b/core/loshader/pixsort.c @@ -9,96 +9,54 @@ #include "util/gleasy/framebuffer.h" #include "util/gleasy/program.h" -#include "util/math/algorithm.h" -#include "util/memory/memory.h" +#include "./single.h" #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/pixsort.vshader.h" -#include "anysrc/pixsort.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/pixsort.vshader.h" +#include "core/loshader/anysrc/pixsort.fshader.h" -#define LOSHADER_PIXSORT_UNIFORM_SRC 0 -#define LOSHADER_PIXSORT_UNIFORM_INTENSITY 1 +#define UNIFORM_SRC_ 0 +#define UNIFORM_INTENSITY_ 1 -#define LOSHADER_PIXSORT_UNIBLOCK_INDEX 0 +#define PRIMITIVE_COUNT_ 6 -struct loshader_pixsort_drawer_t { - const loshader_pixsort_program_t* prog; - const loshader_uniblock_t* uniblock; +void loshader_pixsort_drawer_initialize( + loshader_pixsort_drawer_t* drawer, + const loshader_uniblock_t* uniblock, + const gleasy_framebuffer_t* fb) { + assert(drawer != NULL); + assert(uniblock != NULL); + assert(fb != NULL); - const gleasy_framebuffer_t* fb; + *drawer = (typeof(*drawer)) { + .fb = fb, + }; - float intensity; -}; - -void loshader_pixsort_program_initialize( - loshader_pixsort_program_t* prog) { - assert(prog != NULL); - - *prog = gleasy_program_new( + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_pixsort_vshader_, sizeof(loshader_pixsort_vshader_), loshader_pixsort_fshader_, sizeof(loshader_pixsort_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, uniblock, LOSHADER_PIXSORT_UNIBLOCK_INDEX); -} - -void loshader_pixsort_program_deinitialize( - loshader_pixsort_program_t* prog) { - assert(prog != NULL); - - glDeleteProgram(*prog); -} - -loshader_pixsort_drawer_t* loshader_pixsort_drawer_new( - const loshader_pixsort_program_t* prog, - const loshader_uniblock_t* uniblock, - const gleasy_framebuffer_t* fb) { - assert(prog != NULL); - assert(uniblock != NULL); - assert(fb != NULL); - - loshader_pixsort_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - .fb = fb, - }; - return drawer; -} - -void loshader_pixsort_drawer_delete(loshader_pixsort_drawer_t* drawer) { - if (drawer == NULL) return; - - memory_delete(drawer); -} - -void loshader_pixsort_drawer_set_intensity( - loshader_pixsort_drawer_t* drawer, - float intensity) { - assert(drawer != NULL); - assert(MATH_FLOAT_VALID(intensity)); - - drawer->intensity = intensity; + loshader_single_drawer_initialize(&drawer->super, prog, uniblock, 0); } void loshader_pixsort_drawer_draw( const loshader_pixsort_drawer_t* drawer) { assert(drawer != NULL); - glUseProgram(*drawer->prog); + glUseProgram(drawer->super.prog); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, drawer->fb->colorbuf); - glUniform1i(LOSHADER_PIXSORT_UNIFORM_SRC, 0); - glUniform1f(LOSHADER_PIXSORT_UNIFORM_INTENSITY, drawer->intensity); + glUniform1i(UNIFORM_SRC_, 0); + glUniform1f(UNIFORM_INTENSITY_, drawer->intensity); - glDrawArrays(GL_TRIANGLES, 0, 6); + loshader_single_drawer_draw_without_use_program( + &drawer->super, PRIMITIVE_COUNT_); } bool loshader_pixsort_drawer_is_skippable( diff --git a/core/loshader/pixsort.fshader b/core/loshader/pixsort.fshader index 5585826..759b0c9 100644 --- a/core/loshader/pixsort.fshader +++ b/core/loshader/pixsort.fshader @@ -5,7 +5,7 @@ in vec2 v_uv; out vec4 o_color; -const int N = 2; +const int N = 4; const int S = 20; float luminance(in vec4 col) { diff --git a/core/loshader/pixsort.h b/core/loshader/pixsort.h index 6fa8739..766e7ef 100644 --- a/core/loshader/pixsort.h +++ b/core/loshader/pixsort.h @@ -1,44 +1,28 @@ #pragma once -#include - #include "util/gleasy/framebuffer.h" #include "util/gleasy/program.h" +#include "./single.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_pixsort_program_t; +typedef struct { + loshader_single_drawer_t super; + const gleasy_framebuffer_t* fb; -struct loshader_pixsort_drawer_t; -typedef struct loshader_pixsort_drawer_t loshader_pixsort_drawer_t; + /* public mutable params */ + float intensity; +} loshader_pixsort_drawer_t; void -loshader_pixsort_program_initialize( - loshader_pixsort_program_t* prog +loshader_pixsort_drawer_initialize( + loshader_pixsort_drawer_t* drawer, + const loshader_uniblock_t* uniblock, + const gleasy_framebuffer_t* fb ); -void -loshader_pixsort_program_deinitialize( - loshader_pixsort_program_t* prog -); - -loshader_pixsort_drawer_t* /* OWNERSHIP */ -loshader_pixsort_drawer_new( - const loshader_pixsort_program_t* prog, - const loshader_uniblock_t* uniblock, - const gleasy_framebuffer_t* fb -); - -void -loshader_pixsort_drawer_delete( - loshader_pixsort_drawer_t* drawer /* OWNERSHIP */ -); - -void -loshader_pixsort_drawer_set_intensity( - loshader_pixsort_drawer_t* drawer, - float intensity -); +#define loshader_pixsort_drawer_deinitialize(drawer) \ + loshader_single_drawer_deinitialize(&(drawer)->super) void loshader_pixsort_drawer_draw( diff --git a/core/loshader/popup_text.c b/core/loshader/popup_text.c new file mode 100644 index 0000000..68030d9 --- /dev/null +++ b/core/loshader/popup_text.c @@ -0,0 +1,44 @@ +#include "./popup_text.h" + +#include +#include + +#include "util/gleasy/program.h" +#include "util/gleasy/texture.h" +#include "util/glyphas/drawer.h" + +#include "./text.h" +#include "./uniblock.h" + +/* resources */ +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/popup_text.vshader.h" +#include "core/loshader/anysrc/popup_text.fshader.h" + +#define UNIFORM_ALPHA_ 1 /* 0 is used by the super class */ + +void loshader_popup_text_drawer_initialize( + loshader_popup_text_drawer_t* drawer, + const loshader_uniblock_t* uniblock, + gleasy_texture_2d_t tex) { + assert(drawer != NULL); + assert(uniblock != NULL); + assert(tex != 0); + + const gleasy_program_t prog = gleasy_program_new( + loshader_header_shader_, sizeof(loshader_header_shader_), + loshader_popup_text_vshader_, sizeof(loshader_popup_text_vshader_), + loshader_popup_text_fshader_, sizeof(loshader_popup_text_fshader_)); + + loshader_text_drawer_initialize(&drawer->super, prog, uniblock, tex); +} + +void loshader_popup_text_drawer_draw( + const loshader_popup_text_drawer_t* drawer) { + assert(drawer != NULL); + + glUseProgram(drawer->super.prog); + glUniform1f(UNIFORM_ALPHA_, drawer->alpha); + + loshader_text_drawer_draw_without_use_program(&drawer->super); +} diff --git a/core/loshader/popup_text.fshader b/core/loshader/popup_text.fshader new file mode 100644 index 0000000..ee91820 --- /dev/null +++ b/core/loshader/popup_text.fshader @@ -0,0 +1,35 @@ +layout (location = 0) uniform sampler2D u_tex; +layout (location = 1) uniform float u_alpha; + +in vec2 v_dp; +in vec2 v_uv; +in vec4 v_color; + +out vec4 o_color; + +float rand(in vec2 p) { + /* https://qiita.com/shimacpyon/items/d15dee44a0b8b3883f76 */ + return fract(sin(dot(p ,vec2(12.9898,78.233))) * 43758.5453); +} +float noise(vec2 x) { + /* https://www.shadertoy.com/view/4dS3Wd */ + vec2 i = floor(x); + vec2 f = fract(x); + + float a = rand(i); + float b = rand(i + vec2(1.0, 0.0)); + float c = rand(i + vec2(0.0, 1.0)); + float d = rand(i + vec2(1.0, 1.0)); + + vec2 u = f * f * (3.0 - 2.0 * f); + return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y; +} + +void main(void) { + float t = 1.-pow(1.-u_alpha, 4.); + + float a = texture(u_tex, v_uv).r; + a *= step(noise(v_dp*10.), t); + + o_color = vec4(v_color.rgb, v_color.a*a*t); +} diff --git a/core/loshader/popup_text.h b/core/loshader/popup_text.h new file mode 100644 index 0000000..ea24818 --- /dev/null +++ b/core/loshader/popup_text.h @@ -0,0 +1,36 @@ +#pragma once + +#include "util/gleasy/texture.h" + +#include "./text.h" +#include "./uniblock.h" + +typedef gleasy_program_t loshader_popup_text_program_t; + +typedef struct { + loshader_text_drawer_t super; + + /* public mutable params */ + float alpha; +} loshader_popup_text_drawer_t; + +void +loshader_popup_text_drawer_initialize( + loshader_popup_text_drawer_t* drawer, + const loshader_uniblock_t* uniblock, + gleasy_texture_2d_t tex +); + +#define loshader_popup_text_drawer_deinitialize(drawer) \ + loshader_text_drawer_deinitialize(&(drawer)->super) + +#define loshader_popup_text_drawer_clear(drawer, reserve) \ + loshader_text_drawer_clear(&(drawer)->super, reserve) + +#define loshader_popup_text_drawer_add_block(drawer, block) \ + loshader_text_drawer_add_block(&(drawer)->super, block) + +void +loshader_popup_text_drawer_draw( + const loshader_popup_text_drawer_t* drawer +); diff --git a/core/loshader/popup_text.vshader b/core/loshader/popup_text.vshader new file mode 100644 index 0000000..f08f8a0 --- /dev/null +++ b/core/loshader/popup_text.vshader @@ -0,0 +1,43 @@ +layout (location = 1) uniform float u_alpha; + +layout (location = 0) in vec2 i_pos; +layout (location = 1) in vec2 i_size; +layout (location = 2) in vec2 i_uv_pos; +layout (location = 3) in vec2 i_uv_size; +layout (location = 4) in vec4 i_color; + +out vec2 v_dp; +out vec2 v_uv; +out vec4 v_color; + +const float RANDOM_POS = .1; + +float rand(in vec2 p) { + /* https://qiita.com/shimacpyon/items/d15dee44a0b8b3883f76 */ + return fract(sin(dot(p ,vec2(12.9898,78.233))) * 43758.5453); +} + +void main(void) { + const vec2[] verts = vec2[]( + vec2( 0., 0.), vec2( 0., -1.), vec2( 1., -1.), + vec2( 0., 0.), vec2( 1., -1.), vec2( 1., 0.) + ); + + vec2 seed = i_pos + float(gl_InstanceID); + + vec2 rpos = 1.-vec2(rand(seed.xy), rand(seed.yx))*2.; + rpos.x /= 8.; + rpos.y = -abs(rpos.y); + + float t = pow(1.-u_alpha, 4.); + + rpos *= t*RANDOM_POS; + + vec2 p = gl_VertexID < verts.length()? verts[gl_VertexID]: vec2(0.); + vec2 dp = p*i_size + i_pos+rpos; + + gl_Position = vec4(dp, 0, 1); + v_dp = dp; + v_uv = p*i_uv_size + i_uv_pos; + v_color = i_color; +} diff --git a/core/loshader/posteffect.c b/core/loshader/posteffect.c index fbff4cd..39991ae 100644 --- a/core/loshader/posteffect.c +++ b/core/loshader/posteffect.c @@ -16,96 +16,55 @@ #include "./uniblock.h" /* resources */ -#include "anysrc/header.shader.h" -#include "anysrc/posteffect.vshader.h" -#include "anysrc/posteffect.fshader.h" +#include "core/loshader/anysrc/header.shader.h" +#include "core/loshader/anysrc/posteffect.vshader.h" +#include "core/loshader/anysrc/posteffect.fshader.h" -#define LOSHADER_POSTEFFECT_UNIFORM_SRC 0 +#define UNIFORM_SRC_ 0 -struct loshader_posteffect_drawer_t { - const loshader_posteffect_program_t* prog; - const loshader_uniblock_t* uniblock; - - const gleasy_framebuffer_t* fb; - - gleasy_buffer_uniform_t param; -}; +#define PRIMITIVE_COUNT_ 6 #pragma pack(push, 1) typedef struct { - float whole_blur; - float raster; + float distortion_amnesia; + float distortion_radial; + float distortion_urgent; + float raster_whole; - float radial_displacement; - float amnesia_displacement; - float radial_fade; - - float brightness; -} loshader_posteffect_drawer_param_internal_t; -_Static_assert( - sizeof(float)*6 == - sizeof(loshader_posteffect_drawer_param_internal_t)); + float aberration_radial; + float blur_whole; + float brightness_whole; + float fade_radial; +} loshader_posteffect_drawer_internal_param_t; #pragma pack(pop) -#define LOSHADER_POSTEFFECT_UNIBLOCK_INDEX 0 -#define LOSHADER_POSTEFFECT_PARAM_INDEX 1 +_Static_assert( + sizeof(float)*8 == + sizeof(loshader_posteffect_drawer_internal_param_t), + "recheck the type has no padding"); -void loshader_posteffect_program_initialize( - loshader_posteffect_program_t* prog) { - assert(prog != NULL); +void loshader_posteffect_drawer_initialize( + loshader_posteffect_drawer_t* drawer, + const loshader_uniblock_t* uniblock, + const gleasy_framebuffer_t* fb) { + assert(drawer != NULL); + assert(uniblock != NULL); + assert(fb != NULL); - *prog = gleasy_program_new( + *drawer = (typeof(*drawer)) { + .fb = fb, + }; + + const gleasy_program_t prog = gleasy_program_new( loshader_header_shader_, sizeof(loshader_header_shader_), loshader_posteffect_vshader_, sizeof(loshader_posteffect_vshader_), loshader_posteffect_fshader_, sizeof(loshader_posteffect_fshader_)); - const GLuint uniblock = glGetUniformBlockIndex(*prog, "uniblock"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, uniblock, LOSHADER_POSTEFFECT_UNIBLOCK_INDEX); - - const GLuint param = glGetUniformBlockIndex(*prog, "param"); - assert(glGetError() == GL_NO_ERROR); - glUniformBlockBinding(*prog, param, LOSHADER_POSTEFFECT_PARAM_INDEX); -} - -void loshader_posteffect_program_deinitialize( - loshader_posteffect_program_t* prog) { - assert(prog != NULL); - - glDeleteProgram(*prog); -} - -loshader_posteffect_drawer_t* loshader_posteffect_drawer_new( - const loshader_posteffect_program_t* prog, - const loshader_uniblock_t* uniblock, - const gleasy_framebuffer_t* fb) { - assert(prog != NULL); - assert(uniblock != NULL); - assert(fb != NULL); - - loshader_posteffect_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) { - .prog = prog, - .uniblock = uniblock, - .fb = fb, - }; - - glGenBuffers(1, &drawer->param); - glBindBuffer(GL_UNIFORM_BUFFER, drawer->param); - glBufferData(GL_UNIFORM_BUFFER, - sizeof(loshader_posteffect_drawer_param_internal_t), - NULL, - GL_DYNAMIC_DRAW); - - return drawer; -} - -void loshader_posteffect_drawer_delete(loshader_posteffect_drawer_t* drawer) { - if (drawer == NULL) return; - - glDeleteBuffers(1, &drawer->param); - - memory_delete(drawer); + loshader_single_drawer_initialize( + &drawer->super, + prog, + uniblock, + sizeof(loshader_posteffect_drawer_internal_param_t)); } void loshader_posteffect_drawer_set_param( @@ -114,31 +73,29 @@ void loshader_posteffect_drawer_set_param( assert(drawer != NULL); assert(param != NULL); - const loshader_posteffect_drawer_param_internal_t p = { - .whole_blur = param->whole_blur, - .raster = param->raster, - .radial_displacement = param->radial_displacement, - .amnesia_displacement = param->amnesia_displacement, - .radial_fade = param->radial_fade, - .brightness = param->brightness, + const loshader_posteffect_drawer_internal_param_t p = { + .distortion_amnesia = param->distortion_amnesia, + .distortion_radial = param->distortion_radial, + .distortion_urgent = param->distortion_urgent, + .raster_whole = param->raster_whole, + .aberration_radial = param->aberration_radial, + .blur_whole = param->blur_whole, + .brightness_whole = param->brightness_whole, + .fade_radial = param->fade_radial, }; - glBindBuffer(GL_UNIFORM_BUFFER, drawer->param); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(p), &p); + loshader_single_drawer_set_param(&drawer->super, &p); } void loshader_posteffect_drawer_draw( const loshader_posteffect_drawer_t* drawer) { assert(drawer != NULL); - glUseProgram(*drawer->prog); - - loshader_uniblock_bind(drawer->uniblock, LOSHADER_POSTEFFECT_UNIBLOCK_INDEX); - glBindBufferBase(GL_UNIFORM_BUFFER, - LOSHADER_POSTEFFECT_PARAM_INDEX, drawer->param); + glUseProgram(drawer->super.prog); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, drawer->fb->colorbuf); - glUniform1i(LOSHADER_POSTEFFECT_UNIFORM_SRC, 0); + glUniform1i(UNIFORM_SRC_, 0); - glDrawArrays(GL_TRIANGLES, 0, 6); + loshader_single_drawer_draw_without_use_program( + &drawer->super, PRIMITIVE_COUNT_); } diff --git a/core/loshader/posteffect.fshader b/core/loshader/posteffect.fshader index d5f7d64..8c08cd4 100644 --- a/core/loshader/posteffect.fshader +++ b/core/loshader/posteffect.fshader @@ -1,21 +1,22 @@ layout (location = 0) uniform sampler2D u_src; layout(std140) uniform param { - float whole_blur; - float raster; + float distortion_amnesia; + float distortion_radial; + float distortion_urgent; + float raster_whole; - float radial_displacement; - float amnesia_displacement; - - float radial_fade; - - float brightness; + float aberration_radial; + float blur_whole; + float brightness_whole; + float fade_radial; } p; in vec2 v_uv; out vec4 o_color; +/* ---- utilities ---- */ float atan2(in vec2 p){ return p.x == 0. ? sign(p.y)*PI/2. : atan(p.y, p.x); } @@ -29,7 +30,7 @@ float rand(in vec2 p) { /* https://thebookofshaders.com/13/?lan=jp */ return fract(sin(dot(p.xy, vec2(12.9898, 78.233)))*43758.5453123); } -float noise (in vec2 _st) { +float noise(in vec2 _st) { /* https://thebookofshaders.com/13/?lan=jp*/ vec2 i = floor(_st); vec2 f = fract(_st); @@ -46,7 +47,7 @@ float noise (in vec2 _st) { (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; } -float fbm (in vec2 _st) { +float fbm(in vec2 _st) { /* https://thebookofshaders.com/13/?lan=jp*/ const float octaves = 5; @@ -63,42 +64,46 @@ float fbm (in vec2 _st) { return v; } -vec2 radial_displacement(in vec2 polar) { - float intensity = p.radial_displacement + 1.; - float r = polar.x; +/* ---- distortion effects ---- */ +void distortion_amnesia(inout vec2 uv) { + vec2 a = abs(uv); + + float i = p.distortion_amnesia*(1.-pow(max(a.x, a.y), 2.)); + uv += (fbm(uv)-.5)*i; +} +void distortion_radial(inout vec2 polar) { + float i = p.distortion_radial + 1.; const float sqrt2 = sqrt(2.); - r = (1. - pow(abs(1. - r/sqrt2), intensity))*sqrt2 / intensity; - - return vec2(r, polar.y); + polar.x = (1. - pow(abs(1. - polar.x/sqrt2), i))*sqrt2 / i; } -vec2 amnesia_displacement(in vec2 uv) { - vec2 auv = abs(uv); - float intensity = p.amnesia_displacement*(1.-pow(max(auv.x, auv.y), 2.)); - return uv + fbm(uv)*intensity - intensity/2.; +void distortion_urgent(inout vec2 polar) { + float i = p.distortion_urgent; + polar.x += pow(polar.x, 2.)*sin(polar.y*20.)*.2*i; + polar.x /= i+1.; +} +void raster_whole(inout vec2 uv) { + uv.x += sin(v_uv.y*PI*2./uni.aa*5.)*.05*p.raster_whole; } -float radial_fade(in float len) { - float intensity = p.radial_fade; - return clamp(1. - intensity * max(len - (1.-intensity), 0.), 0., 1.); -} - -vec4 chromatic_aberration(in vec2 uv) { +/* ---- color effects ---- */ +void aberration_radial(inout vec4 color, in vec2 uv) { float a = length(v_uv)/sqrt(2.); - vec2 e = 1./uni.resolution*a; + vec2 e = 4./uni.resolution*pow(a, 4.)*p.aberration_radial; - return vec4( + color = vec4( texture(u_src, uv+e).r, - texture(u_src, uv).g, + color.g, texture(u_src, uv-e).b, 1.); } +void blur_whole(inout vec4 color, in vec2 uv) { + if (p.blur_whole <= 0.) return; -vec4 blur(in vec2 uv) { vec2 e1 = vec2(1./uni.resolution.x, 0.); vec2 e2 = vec2(0., 1./uni.resolution.y); - vec4 color = + vec4 neighbors = texture(u_src, uv+e1+.0) + texture(u_src, uv+e1+e2) + texture(u_src, uv+.0+e2) + @@ -107,33 +112,44 @@ vec4 blur(in vec2 uv) { texture(u_src, uv-e1-e2) + texture(u_src, uv+.0-e2) + texture(u_src, uv+e1-e2); - return color/8.; + color = mix(color, neighbors/8., p.blur_whole); +} +void contrast_whole(inout vec4 color) { + color = pow(color, vec4(1.4)); +} +void monochromize_whole(inout vec4 color) { + color = min(color, vec4(max(color.r, max(color.g, color.b)))*.95); +} +void brightness_whole(inout vec4 color) { + color *= p.brightness_whole; +} +void fade_radial(inout vec4 color, in vec2 polar) { + float i = p.fade_radial; + color.rgb *= clamp(1.-i*max(polar.x-(1.-i), 0.), 0., 1.); } void main(void) { vec2 uv = v_uv; - /* transformation */ + /* distortion effect */ + distortion_amnesia(uv); + vec2 polar = to_polar(uv); - polar = radial_displacement(polar); - + distortion_radial(polar); + distortion_urgent(polar); uv = to_rectangular(polar); - uv = amnesia_displacement(uv); - uv.x += sin(v_uv.y*PI*2./uni.aa*5.)*.05*p.raster; + raster_whole(uv); - /* pixel manipulation */ + /* color effect */ uv = (uv+1.)/2.; - vec4 color = chromatic_aberration(uv); + o_color = texture(u_src, uv); - if (p.whole_blur > 0.) color = mix(color, blur(uv), p.whole_blur); + aberration_radial(o_color, uv); + blur_whole(o_color, uv); - /* blending */ - float a = radial_fade(polar.x); - o_color = mix(vec4(0., 0., 0., 1), color, a); - - /* color manip */ - o_color = pow(o_color, vec4(1.4)); - o_color = min(o_color, vec4(max(o_color.r, max(o_color.g, o_color.b)))*.95); - o_color *= p.brightness; + contrast_whole(o_color); + monochromize_whole(o_color); + brightness_whole(o_color); + fade_radial(o_color, polar); } diff --git a/core/loshader/posteffect.h b/core/loshader/posteffect.h index 91bf564..b43482d 100644 --- a/core/loshader/posteffect.h +++ b/core/loshader/posteffect.h @@ -1,49 +1,38 @@ #pragma once -#include - #include "util/gleasy/framebuffer.h" -#include "util/gleasy/program.h" +#include "./single.h" #include "./uniblock.h" -typedef gleasy_program_t loshader_posteffect_program_t; - -struct loshader_posteffect_drawer_t; -typedef struct loshader_posteffect_drawer_t loshader_posteffect_drawer_t; +typedef struct { + loshader_single_drawer_t super; + const gleasy_framebuffer_t* fb; +} loshader_posteffect_drawer_t; typedef struct { - float whole_blur; - float raster; + /* distortion effect */ + float distortion_amnesia; + float distortion_radial; + float distortion_urgent; + float raster_whole; - float radial_displacement; - float amnesia_displacement; - float radial_fade; - - float brightness; + /* color effect */ + float aberration_radial; + float blur_whole; + float brightness_whole; + float fade_radial; } loshader_posteffect_drawer_param_t; void -loshader_posteffect_program_initialize( - loshader_posteffect_program_t* prog +loshader_posteffect_drawer_initialize( + loshader_posteffect_drawer_t* drawer, + const loshader_uniblock_t* uniblock, + const gleasy_framebuffer_t* fb ); -void -loshader_posteffect_program_deinitialize( - loshader_posteffect_program_t* prog -); - -loshader_posteffect_drawer_t* /* OWNERSHIP */ -loshader_posteffect_drawer_new( - const loshader_posteffect_program_t* prog, - const loshader_uniblock_t* uniblock, - const gleasy_framebuffer_t* fb -); - -void -loshader_posteffect_drawer_delete( - loshader_posteffect_drawer_t* drawer /* OWNERSHIP */ -); +#define loshader_posteffect_drawer_deinitialize(drawer) \ + loshader_single_drawer_deinitialize(&(drawer)->super) void loshader_posteffect_drawer_set_param( diff --git a/core/loshader/set.c b/core/loshader/set.c index 505a180..c679427 100644 --- a/core/loshader/set.c +++ b/core/loshader/set.c @@ -3,8 +3,6 @@ #include #include #include -#include -#include #include @@ -13,6 +11,8 @@ #include "util/math/algorithm.h" #include "util/math/vector.h" +#include "core/locommon/screen.h" + #include "./backwall.h" #include "./bullet.h" #include "./character.h" @@ -26,170 +26,128 @@ #include "./menu_background.h" #include "./menu_stance.h" #include "./menu_text.h" +#include "./particle.h" +#include "./pixsort.h" +#include "./popup_text.h" #include "./posteffect.h" #include "./uniblock.h" void loshader_set_initialize( - loshader_set_t* set, - int32_t width, - int32_t height, - const vec2_t* dpi, - int32_t max_msaa) { + loshader_set_t* set, + const locommon_screen_t* screen, + int32_t max_msaa) { assert(set != NULL); - assert(width > 0); - assert(height > 0); - assert(vec2_valid(dpi)); + assert(locommon_screen_valid(screen)); assert(max_msaa > 0); - *set = (typeof(*set)) { - .resolution = vec2(width, height), - .dpi = *dpi, - }; + *set = (typeof(*set)) {0}; - set->uniblock = loshader_uniblock_new(); - loshader_uniblock_update_display_param(set->uniblock, &set->resolution, dpi); + loshader_uniblock_initialize(&set->uniblock, screen); int max_samples; glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &max_samples); gleasy_framebuffer_initialize( - &set->framebuffer, width, height, MATH_MIN(max_samples, max_msaa)); + &set->framebuffer, + screen->resolution.x, + screen->resolution.y, + MATH_MIN(max_samples, max_msaa)); /* TODO(catfoot): atlas size should depend on DPI. */ set->tex = (typeof(set->tex)) { .hud_text = gleasy_atlas_new(GL_RED, 1024, 1024, true), + .popup_text = gleasy_atlas_new(GL_RED, 1024, 1024, true), .menu_text = gleasy_atlas_new(GL_RED, 1024, 1024, true), .event_line = gleasy_atlas_new(GL_RED, 1024, 1024, true), }; - loshader_backwall_program_initialize(&set->program.backwall); - loshader_ground_program_initialize(&set->program.ground); - loshader_character_program_initialize(&set->program.character); - loshader_bullet_program_initialize(&set->program.bullet); - loshader_fog_program_initialize(&set->program.fog); - loshader_pixsort_program_initialize(&set->program.pixsort); - loshader_posteffect_program_initialize(&set->program.posteffect); - loshader_hud_bar_program_initialize(&set->program.hud_bar); - loshader_hud_text_program_initialize(&set->program.hud_text); - loshader_menu_background_program_initialize(&set->program.menu_background); - loshader_menu_text_program_initialize(&set->program.menu_text); - loshader_menu_stance_program_initialize(&set->program.menu_stance); - loshader_combat_ring_program_initialize(&set->program.combat_ring); - loshader_cinescope_program_initialize(&set->program.cinescope); - loshader_event_line_program_initialize(&set->program.event_line); - - set->drawer = (typeof(set->drawer)) { - .backwall = loshader_backwall_drawer_new( - &set->program.backwall, set->uniblock), - - .ground = loshader_ground_drawer_new( - &set->program.ground, set->uniblock), - - .character = loshader_character_drawer_new( - &set->program.character, set->uniblock), - - .bullet = loshader_bullet_drawer_new( - &set->program.bullet, set->uniblock), - - .fog = loshader_fog_drawer_new( - &set->program.fog, set->uniblock), - - .pixsort = loshader_pixsort_drawer_new( - &set->program.pixsort, set->uniblock, &set->framebuffer), - - .posteffect = loshader_posteffect_drawer_new( - &set->program.posteffect, set->uniblock, &set->framebuffer), - - .hud_bar = loshader_hud_bar_drawer_new( - &set->program.hud_bar, set->uniblock), - - .menu_background = loshader_menu_background_drawer_new( - &set->program.menu_background, set->uniblock), - - .menu_stance = loshader_menu_stance_drawer_new( - &set->program.menu_stance, set->uniblock), - - .combat_ring = loshader_combat_ring_drawer_new( - &set->program.combat_ring, set->uniblock), - - .cinescope = loshader_cinescope_drawer_new( - &set->program.cinescope, set->uniblock), - }; + loshader_backwall_drawer_initialize(&set->drawer.backwall, &set->uniblock); + loshader_ground_drawer_initialize(&set->drawer.ground, &set->uniblock); + loshader_character_drawer_initialize(&set->drawer.character, &set->uniblock); + loshader_bullet_drawer_initialize(&set->drawer.bullet, &set->uniblock); + loshader_particle_drawer_initialize(&set->drawer.particle, &set->uniblock); + loshader_fog_drawer_initialize(&set->drawer.fog, &set->uniblock); + loshader_pixsort_drawer_initialize( + &set->drawer.pixsort, &set->uniblock, &set->framebuffer); + loshader_posteffect_drawer_initialize( + &set->drawer.posteffect, &set->uniblock, &set->framebuffer); + loshader_hud_bar_drawer_initialize(&set->drawer.hud_bar, &set->uniblock); + loshader_menu_background_drawer_initialize( + &set->drawer.menu_background, &set->uniblock); + loshader_menu_stance_drawer_initialize( + &set->drawer.menu_stance, &set->uniblock); + loshader_combat_ring_drawer_initialize( + &set->drawer.combat_ring, &set->uniblock); + loshader_cinescope_drawer_initialize(&set->drawer.cinescope, &set->uniblock); loshader_hud_text_drawer_initialize( &set->drawer.hud_text, - &set->program.hud_text, - set->uniblock, + &set->uniblock, gleasy_atlas_get_texture(set->tex.hud_text)); + loshader_popup_text_drawer_initialize( + &set->drawer.popup_text, + &set->uniblock, + gleasy_atlas_get_texture(set->tex.popup_text)); + loshader_menu_text_drawer_initialize( &set->drawer.menu_text, - &set->program.menu_text, - set->uniblock, + &set->uniblock, gleasy_atlas_get_texture(set->tex.menu_text)); loshader_event_line_drawer_initialize( &set->drawer.event_line, - &set->program.event_line, - set->uniblock, + &set->uniblock, gleasy_atlas_get_texture(set->tex.event_line)); } void loshader_set_deinitialize(loshader_set_t* set) { assert(set != NULL); - loshader_backwall_drawer_delete(set->drawer.backwall); - loshader_ground_drawer_delete(set->drawer.ground); - loshader_character_drawer_delete(set->drawer.character); - loshader_bullet_drawer_delete(set->drawer.bullet); - loshader_fog_drawer_delete(set->drawer.fog); - loshader_pixsort_drawer_delete(set->drawer.pixsort); - loshader_posteffect_drawer_delete(set->drawer.posteffect); - loshader_hud_bar_drawer_delete(set->drawer.hud_bar); + loshader_backwall_drawer_deinitialize(&set->drawer.backwall); + loshader_ground_drawer_deinitialize(&set->drawer.ground); + loshader_character_drawer_deinitialize(&set->drawer.character); + loshader_bullet_drawer_deinitialize(&set->drawer.bullet); + loshader_particle_drawer_deinitialize(&set->drawer.particle); + loshader_fog_drawer_deinitialize(&set->drawer.fog); + loshader_pixsort_drawer_deinitialize(&set->drawer.pixsort); + loshader_posteffect_drawer_deinitialize(&set->drawer.posteffect); + loshader_hud_bar_drawer_deinitialize(&set->drawer.hud_bar); loshader_hud_text_drawer_deinitialize(&set->drawer.hud_text); - loshader_menu_background_drawer_delete(set->drawer.menu_background); + loshader_popup_text_drawer_deinitialize(&set->drawer.popup_text); + loshader_menu_background_drawer_deinitialize(&set->drawer.menu_background); loshader_menu_text_drawer_deinitialize(&set->drawer.menu_text); - loshader_menu_stance_drawer_delete(set->drawer.menu_stance); - loshader_combat_ring_drawer_delete(set->drawer.combat_ring); - loshader_cinescope_drawer_delete(set->drawer.cinescope); + loshader_menu_stance_drawer_deinitialize(&set->drawer.menu_stance); + loshader_combat_ring_drawer_deinitialize(&set->drawer.combat_ring); + loshader_cinescope_drawer_deinitialize(&set->drawer.cinescope); loshader_event_line_drawer_deinitialize(&set->drawer.event_line); - loshader_backwall_program_deinitialize(&set->program.backwall); - loshader_ground_program_deinitialize(&set->program.ground); - loshader_character_program_deinitialize(&set->program.character); - loshader_bullet_program_deinitialize(&set->program.bullet); - loshader_fog_program_deinitialize(&set->program.fog); - loshader_pixsort_program_deinitialize(&set->program.pixsort); - loshader_posteffect_program_deinitialize(&set->program.posteffect); - loshader_hud_bar_program_deinitialize(&set->program.hud_bar); - loshader_hud_text_program_deinitialize(&set->program.hud_text); - loshader_menu_background_program_deinitialize(&set->program.menu_background); - loshader_menu_text_program_deinitialize(&set->program.menu_text); - loshader_menu_stance_program_deinitialize(&set->program.menu_stance); - loshader_combat_ring_program_deinitialize(&set->program.combat_ring); - loshader_cinescope_program_deinitialize(&set->program.cinescope); - loshader_event_line_program_deinitialize(&set->program.event_line); - gleasy_atlas_delete(set->tex.hud_text); + gleasy_atlas_delete(set->tex.popup_text); gleasy_atlas_delete(set->tex.menu_text); gleasy_atlas_delete(set->tex.event_line); - loshader_uniblock_delete(set->uniblock); + loshader_uniblock_deinitialize(&set->uniblock); gleasy_framebuffer_deinitialize(&set->framebuffer); } void loshader_set_clear_all(loshader_set_t* set) { assert(set != NULL); - loshader_ground_drawer_clear(set->drawer.ground, 256); - loshader_character_drawer_clear(set->drawer.character, 256); - loshader_bullet_drawer_clear(set->drawer.bullet, 256); + set->drawer.hud_text.alpha = 0; + set->drawer.menu_background.alpha = 0; + set->drawer.menu_text.alpha = 0; - loshader_hud_bar_drawer_clear(set->drawer.hud_bar, 16); + loshader_ground_drawer_clear(&set->drawer.ground, 256); + loshader_character_drawer_clear(&set->drawer.character, 256); + loshader_bullet_drawer_clear(&set->drawer.bullet, 256); + loshader_particle_drawer_clear(&set->drawer.particle, 256); + + loshader_hud_bar_drawer_clear(&set->drawer.hud_bar, 16); loshader_hud_text_drawer_clear(&set->drawer.hud_text, 256); - loshader_menu_background_drawer_set_alpha(set->drawer.menu_background, 0); + loshader_popup_text_drawer_clear(&set->drawer.popup_text, 256); loshader_menu_text_drawer_clear(&set->drawer.menu_text, 512); - loshader_menu_stance_drawer_clear(set->drawer.menu_stance, 16); - loshader_combat_ring_drawer_clear(set->drawer.combat_ring, 8); + loshader_menu_stance_drawer_clear(&set->drawer.menu_stance, 16); + loshader_combat_ring_drawer_clear(&set->drawer.combat_ring, 8); loshader_event_line_drawer_clear(&set->drawer.event_line, 256); } @@ -203,18 +161,19 @@ void loshader_set_draw_all(const loshader_set_t* set) { glEnable(GL_MULTISAMPLE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - loshader_backwall_drawer_draw(set->drawer.backwall); - loshader_ground_drawer_draw(set->drawer.ground); - loshader_character_drawer_draw(set->drawer.character); - loshader_bullet_drawer_draw(set->drawer.bullet); - loshader_fog_drawer_draw(set->drawer.fog); + loshader_backwall_drawer_draw(&set->drawer.backwall); + loshader_ground_drawer_draw(&set->drawer.ground); + loshader_character_drawer_draw(&set->drawer.character); + loshader_bullet_drawer_draw(&set->drawer.bullet); + loshader_particle_drawer_draw(&set->drawer.particle); + loshader_fog_drawer_draw(&set->drawer.fog); gleasy_framebuffer_flush(&set->framebuffer); /* ---- path 2: pixsort ---- */ - if (!loshader_pixsort_drawer_is_skippable(set->drawer.pixsort)) { + if (!loshader_pixsort_drawer_is_skippable(&set->drawer.pixsort)) { gleasy_framebuffer_bind(&set->framebuffer); - loshader_pixsort_drawer_draw(set->drawer.pixsort); + loshader_pixsort_drawer_draw(&set->drawer.pixsort); gleasy_framebuffer_flush(&set->framebuffer); } @@ -224,18 +183,19 @@ void loshader_set_draw_all(const loshader_set_t* set) { glDisable(GL_BLEND); glDisable(GL_MULTISAMPLE); - loshader_posteffect_drawer_draw(set->drawer.posteffect); + loshader_posteffect_drawer_draw(&set->drawer.posteffect); glEnable(GL_BLEND); glEnable(GL_MULTISAMPLE); - loshader_hud_bar_drawer_draw(set->drawer.hud_bar); + loshader_hud_bar_drawer_draw(&set->drawer.hud_bar); loshader_hud_text_drawer_draw(&set->drawer.hud_text); - loshader_menu_background_drawer_draw(set->drawer.menu_background); + loshader_popup_text_drawer_draw(&set->drawer.popup_text); + loshader_menu_background_drawer_draw(&set->drawer.menu_background); loshader_menu_text_drawer_draw(&set->drawer.menu_text); - loshader_menu_stance_drawer_draw(set->drawer.menu_stance); - loshader_combat_ring_drawer_draw(set->drawer.combat_ring); - loshader_cinescope_drawer_draw(set->drawer.cinescope); + loshader_menu_stance_drawer_draw(&set->drawer.menu_stance); + loshader_combat_ring_drawer_draw(&set->drawer.combat_ring); + loshader_cinescope_drawer_draw(&set->drawer.cinescope); loshader_event_line_drawer_draw(&set->drawer.event_line); gleasy_framebuffer_flush_to_other(&set->framebuffer, 0); @@ -245,6 +205,7 @@ void loshader_set_drop_cache(loshader_set_t* set) { assert(set != NULL); gleasy_atlas_clear(set->tex.hud_text); + gleasy_atlas_clear(set->tex.popup_text); gleasy_atlas_clear(set->tex.menu_text); gleasy_atlas_clear(set->tex.event_line); } diff --git a/core/loshader/set.h b/core/loshader/set.h index bf81d26..db9dfd1 100644 --- a/core/loshader/set.h +++ b/core/loshader/set.h @@ -6,6 +6,8 @@ #include "util/gleasy/framebuffer.h" #include "util/math/vector.h" +#include "core/locommon/screen.h" + #include "./backwall.h" #include "./bullet.h" #include "./character.h" @@ -19,67 +21,49 @@ #include "./menu_background.h" #include "./menu_stance.h" #include "./menu_text.h" +#include "./particle.h" #include "./pixsort.h" +#include "./popup_text.h" #include "./posteffect.h" #include "./uniblock.h" typedef struct { gleasy_framebuffer_t framebuffer; - loshader_uniblock_t* uniblock; + loshader_uniblock_t uniblock; struct { gleasy_atlas_t* hud_text; + gleasy_atlas_t* popup_text; gleasy_atlas_t* menu_text; gleasy_atlas_t* event_line; } tex; struct { - loshader_backwall_program_t backwall; - loshader_ground_program_t ground; - loshader_character_program_t character; - loshader_bullet_program_t bullet; - loshader_fog_program_t fog; - loshader_pixsort_program_t pixsort; - loshader_posteffect_program_t posteffect; - loshader_hud_bar_program_t hud_bar; - loshader_hud_text_program_t hud_text; - loshader_menu_background_program_t menu_background; - loshader_menu_text_program_t menu_text; - loshader_menu_stance_program_t menu_stance; - loshader_combat_ring_program_t combat_ring; - loshader_cinescope_program_t cinescope; - loshader_event_line_program_t event_line; - } program; - - struct { - loshader_backwall_drawer_t* backwall; - loshader_ground_drawer_t* ground; - loshader_character_drawer_t* character; - loshader_bullet_drawer_t* bullet; - loshader_fog_drawer_t* fog; - loshader_pixsort_drawer_t* pixsort; - loshader_posteffect_drawer_t* posteffect; - loshader_hud_bar_drawer_t* hud_bar; - loshader_hud_text_drawer_t hud_text; - loshader_menu_background_drawer_t* menu_background; - loshader_menu_text_drawer_t menu_text; - loshader_menu_stance_drawer_t* menu_stance; - loshader_combat_ring_drawer_t* combat_ring; - loshader_cinescope_drawer_t* cinescope; - loshader_event_line_drawer_t event_line; + loshader_backwall_drawer_t backwall; + loshader_ground_drawer_t ground; + loshader_character_drawer_t character; + loshader_bullet_drawer_t bullet; + loshader_particle_drawer_t particle; + loshader_fog_drawer_t fog; + loshader_pixsort_drawer_t pixsort; + loshader_posteffect_drawer_t posteffect; + loshader_hud_bar_drawer_t hud_bar; + loshader_hud_text_drawer_t hud_text; + loshader_popup_text_drawer_t popup_text; + loshader_menu_background_drawer_t menu_background; + loshader_menu_text_drawer_t menu_text; + loshader_menu_stance_drawer_t menu_stance; + loshader_combat_ring_drawer_t combat_ring; + loshader_cinescope_drawer_t cinescope; + loshader_event_line_drawer_t event_line; } drawer; - - vec2_t resolution; - vec2_t dpi; } loshader_set_t; void loshader_set_initialize( - loshader_set_t* set, - int32_t width, - int32_t height, - const vec2_t* dpi, - int32_t max_msaa + loshader_set_t* set, + const locommon_screen_t* screen, + int32_t max_msaa ); void diff --git a/core/loshader/single.c b/core/loshader/single.c new file mode 100644 index 0000000..1e9d9aa --- /dev/null +++ b/core/loshader/single.c @@ -0,0 +1,91 @@ +#include "./single.h" + +#include +#include +#include + +#include + +#include "util/gleasy/buffer.h" +#include "util/gleasy/program.h" + +#include "./uniblock.h" + +#define UNIBLOCK_INDEX_ 0 +#define PARAM_INDEX_ 1 + +void loshader_single_drawer_initialize( + loshader_single_drawer_t* drawer, + gleasy_program_t prog, + const loshader_uniblock_t* uniblock, + size_t param_size) { + assert(drawer != NULL); + assert(uniblock != NULL); + + const GLuint uniblock_index = glGetUniformBlockIndex(prog, "uniblock"); + assert(glGetError() == GL_NO_ERROR); + glUniformBlockBinding(prog, uniblock_index, UNIBLOCK_INDEX_); + + if (param_size > 0) { + const GLuint param_index = glGetUniformBlockIndex(prog, "param"); + assert(glGetError() == GL_NO_ERROR); + glUniformBlockBinding(prog, param_index, PARAM_INDEX_); + } + + *drawer = (typeof(*drawer)) { + .prog = prog, + .uniblock = uniblock, + .param_size = param_size, + }; + + if (param_size > 0) { + glGenBuffers(1, &drawer->param); + glBindBuffer(GL_UNIFORM_BUFFER, drawer->param); + glBufferData(GL_UNIFORM_BUFFER, param_size, NULL, GL_DYNAMIC_DRAW); + } +} + +void loshader_single_drawer_deinitialize(loshader_single_drawer_t* drawer) { + assert(drawer != NULL); + + if (drawer->param_size > 0) { + glDeleteBuffers(1, &drawer->param); + } + glDeleteProgram(drawer->prog); +} + +void loshader_single_drawer_set_param( + loshader_single_drawer_t* drawer, const void* ptr) { + assert(drawer != NULL); + assert(drawer->param_size > 0); + + assert(ptr != NULL); + + glBindBuffer(GL_UNIFORM_BUFFER, drawer->param); + glBufferSubData(GL_UNIFORM_BUFFER, 0, drawer->param_size, ptr); +} + +void loshader_single_drawer_draw( + const loshader_single_drawer_t* drawer, size_t primitives) { + assert(drawer != NULL); + + if (primitives == 0) return; + + glUseProgram(drawer->prog); + loshader_single_drawer_draw_without_use_program(drawer, primitives); +} + +void loshader_single_drawer_draw_without_use_program( + const loshader_single_drawer_t* drawer, size_t primitives) { + assert(drawer != NULL); + + if (primitives == 0) return; + + loshader_uniblock_bind(drawer->uniblock, UNIBLOCK_INDEX_); + + if (drawer->param_size > 0) { + glBindBufferBase(GL_UNIFORM_BUFFER, PARAM_INDEX_, drawer->param); + } + + glDrawArrays(GL_TRIANGLES, 0, primitives); +} diff --git a/core/loshader/single.h b/core/loshader/single.h new file mode 100644 index 0000000..725ce32 --- /dev/null +++ b/core/loshader/single.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +#include "util/gleasy/buffer.h" +#include "util/gleasy/program.h" + +#include "./uniblock.h" + +typedef struct { + gleasy_program_t prog; + const loshader_uniblock_t* uniblock; + + gleasy_buffer_uniform_t param; + size_t param_size; +} loshader_single_drawer_t; + +void +loshader_single_drawer_initialize( + loshader_single_drawer_t* drawer, + gleasy_program_t prog, /* OWNERSHIP */ + const loshader_uniblock_t* uniblock, + size_t param_size +); + +void +loshader_single_drawer_deinitialize( + loshader_single_drawer_t* drawer +); + +void +loshader_single_drawer_set_param( + loshader_single_drawer_t* drawer, + const void* ptr +); + +void +loshader_single_drawer_draw( + const loshader_single_drawer_t* drawer, + size_t primitives +); + +void +loshader_single_drawer_draw_without_use_program( + const loshader_single_drawer_t* drawer, + size_t primitives +); diff --git a/core/loshader/text.c b/core/loshader/text.c new file mode 100644 index 0000000..2d0bb3e --- /dev/null +++ b/core/loshader/text.c @@ -0,0 +1,55 @@ +#include "./text.h" + +#include + +#include "util/gleasy/program.h" +#include "util/gleasy/texture.h" +#include "util/glyphas/drawer.h" + +#include "./uniblock.h" + +#define UNIBLOCK_INDEX_ 0 + +void loshader_text_drawer_initialize( + loshader_text_drawer_t* drawer, + gleasy_program_t prog, + const loshader_uniblock_t* uniblock, + gleasy_texture_2d_t tex) { + assert(drawer != NULL); + assert(prog != 0); + assert(uniblock != NULL); + assert(tex != 0); + + const GLuint uniblock_index = glGetUniformBlockIndex(prog, "uniblock"); + assert(glGetError() == GL_NO_ERROR); + glUniformBlockBinding(prog, uniblock_index, UNIBLOCK_INDEX_); + + *drawer = (typeof(*drawer)) { + .prog = prog, + .uniblock = uniblock, + }; + glyphas_drawer_initialize(&drawer->super, tex); +} + +void loshader_text_drawer_deinitialize( + loshader_text_drawer_t* drawer) { + assert(drawer != NULL); + + glyphas_drawer_deinitialize(&drawer->super); + glDeleteProgram(drawer->prog); +} + +void loshader_text_drawer_draw(const loshader_text_drawer_t* drawer) { + assert(drawer != NULL); + + glUseProgram(drawer->prog); + loshader_text_drawer_draw_without_use_program(drawer); +} + +void loshader_text_drawer_draw_without_use_program( + const loshader_text_drawer_t* drawer) { + assert(drawer != NULL); + + loshader_uniblock_bind(drawer->uniblock, UNIBLOCK_INDEX_); + glyphas_drawer_draw(&drawer->super); +} diff --git a/core/loshader/text.h b/core/loshader/text.h new file mode 100644 index 0000000..6d62783 --- /dev/null +++ b/core/loshader/text.h @@ -0,0 +1,44 @@ +#pragma once + +#include "util/gleasy/program.h" +#include "util/gleasy/texture.h" +#include "util/glyphas/drawer.h" + +#include "./uniblock.h" + +typedef struct { + glyphas_drawer_t super; + gleasy_program_t prog; + const loshader_uniblock_t* uniblock; + + float alpha; +} loshader_text_drawer_t; + +void +loshader_text_drawer_initialize( + loshader_text_drawer_t* drawer, + gleasy_program_t prog, /* OWNERSHIP */ + const loshader_uniblock_t* uniblock, + gleasy_texture_2d_t tex +); + +void +loshader_text_drawer_deinitialize( + loshader_text_drawer_t* drawer +); + +#define loshader_text_drawer_clear(drawer, reserve) \ + glyphas_drawer_clear(&(drawer)->super, reserve) + +#define loshader_text_drawer_add_block(drawer, block) \ + glyphas_drawer_add_block(&(drawer)->super, block) + +void +loshader_text_drawer_draw( + const loshader_text_drawer_t* drawer +); + +void +loshader_text_drawer_draw_without_use_program( + const loshader_text_drawer_t* drawer +); diff --git a/core/loshader/uniblock.c b/core/loshader/uniblock.c index 2bc146f..d3e192e 100644 --- a/core/loshader/uniblock.c +++ b/core/loshader/uniblock.c @@ -11,13 +11,11 @@ #include "util/math/algorithm.h" #include "util/math/vector.h" #include "util/math/matrix.h" -#include "util/memory/memory.h" #include "core/locommon/position.h" +#include "core/locommon/screen.h" -struct loshader_uniblock_t { - gleasy_buffer_uniform_t buf; -}; +#define AA_ .00001f #pragma pack(push, 1) typedef struct { @@ -34,7 +32,8 @@ typedef struct { } loshader_uniblock_internal_t; _Static_assert( sizeof(float)*5 + 12 + sizeof(float)*37 == - sizeof(loshader_uniblock_internal_t)); + sizeof(loshader_uniblock_internal_t), + "recheck the type has no padding"); #pragma pack(pop) bool loshader_uniblock_param_valid(const loshader_uniblock_param_t* param) { @@ -46,42 +45,25 @@ bool loshader_uniblock_param_valid(const loshader_uniblock_param_t* param) { MATH_FLOAT_VALID(param->time); } -loshader_uniblock_t* loshader_uniblock_new(void) { - loshader_uniblock_t* uni = memory_new(sizeof(*uni)); - *uni = (typeof(*uni)) {0}; +void loshader_uniblock_initialize( + loshader_uniblock_t* uni, const locommon_screen_t* screen) { + assert(uni != NULL); + assert(locommon_screen_valid(screen)); + + *uni = (typeof(*uni)) { + .screen = screen, + }; glGenBuffers(1, &uni->buf); glBindBuffer(GL_UNIFORM_BUFFER, uni->buf); glBufferData(GL_UNIFORM_BUFFER, sizeof(loshader_uniblock_internal_t), NULL, GL_DYNAMIC_DRAW); - - return uni; } -void loshader_uniblock_delete(loshader_uniblock_t* uni) { - if (uni == NULL) return; +void loshader_uniblock_deinitialize(loshader_uniblock_t* uni) { + assert(uni != NULL); glDeleteBuffers(1, &uni->buf); - memory_delete(uni); -} - -void loshader_uniblock_update_display_param( - loshader_uniblock_t* uni, const vec2_t* resolution, const vec2_t* dpi) { - assert(uni != NULL); - assert(vec2_valid(resolution)); - assert(vec2_valid(dpi)); - - const loshader_uniblock_internal_t internal = { - .resolution = *resolution, - .dpi = *dpi, - .aa = MATH_MAX(dpi->x, dpi->y) / 100000, - }; - - static const size_t size = - offsetof(loshader_uniblock_internal_t, aa) + sizeof(internal.aa); - - glBindBuffer(GL_UNIFORM_BUFFER, uni->buf); - glBufferSubData(GL_UNIFORM_BUFFER, 0, size, &internal); } void loshader_uniblock_update_param( @@ -97,17 +79,16 @@ void loshader_uniblock_update_param( param->pos.fract.y); const loshader_uniblock_internal_t internal = { - .proj = param->proj, - .camera = param->cam, - .pos = pos, - .time = param->time, + .resolution = uni->screen->resolution, + .dpi = uni->screen->dpi, + .aa = MATH_MAX(uni->screen->dpi.x, uni->screen->dpi.y) * AA_, + .proj = param->proj, + .camera = param->cam, + .pos = pos, + .time = param->time, }; - - static const size_t offset = offsetof(loshader_uniblock_internal_t, proj); - glBindBuffer(GL_UNIFORM_BUFFER, uni->buf); - glBufferSubData(GL_UNIFORM_BUFFER, - offset, sizeof(internal)-offset, &internal.proj); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(internal), &internal); } void loshader_uniblock_bind(const loshader_uniblock_t* uni, GLuint index) { diff --git a/core/loshader/uniblock.h b/core/loshader/uniblock.h index f05bb3d..a71ac0b 100644 --- a/core/loshader/uniblock.h +++ b/core/loshader/uniblock.h @@ -4,13 +4,18 @@ #include +#include "util/gleasy/buffer.h" #include "util/math/vector.h" #include "util/math/matrix.h" #include "core/locommon/position.h" +#include "core/locommon/screen.h" -struct loshader_uniblock_t; -typedef struct loshader_uniblock_t loshader_uniblock_t; +typedef struct { + const locommon_screen_t* screen; + + gleasy_buffer_uniform_t buf; +} loshader_uniblock_t; typedef struct { mat4_t proj; @@ -26,21 +31,15 @@ loshader_uniblock_param_valid( const loshader_uniblock_param_t* param ); -loshader_uniblock_t* /* OWNERSHIP */ -loshader_uniblock_new( - void +void +loshader_uniblock_initialize( + loshader_uniblock_t* uni, + const locommon_screen_t* screen ); void -loshader_uniblock_delete( - loshader_uniblock_t* uni /* OWNERSHIP */ -); - -void -loshader_uniblock_update_display_param( - loshader_uniblock_t* uni, - const vec2_t* resolution, - const vec2_t* dpi +loshader_uniblock_deinitialize( + loshader_uniblock_t* uni ); void diff --git a/core/loui/CMakeLists.txt b/core/loui/CMakeLists.txt new file mode 100644 index 0000000..5ff70b9 --- /dev/null +++ b/core/loui/CMakeLists.txt @@ -0,0 +1,19 @@ +add_library(loui + combat.c + event.c + hud.c + menu.c + popup.c + ui.c +) +target_link_libraries(loui + glyphas + math + + lochara + locommon + loplayer + loresource + loshader + loworld +) diff --git a/core/loui/combat.c b/core/loui/combat.c new file mode 100644 index 0000000..700463a --- /dev/null +++ b/core/loui/combat.c @@ -0,0 +1,127 @@ +#include "./combat.h" + +#include +#include +#include + +#include "util/math/algorithm.h" +#include "util/math/vector.h" + +#include "core/locommon/easing.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loshader/set.h" + +#define FADE_SPEED_ 50 + +#define RING_ATTACK_RANGE_ .6f +#define RING_GUARD_RANGE_ .8f + +#define RING_BASE_COLOR_(a) vec4(0, 0, 0, (a)*.6f) +#define RING_CLOCKHAND_COLOR_(a) vec4(1, 1, 1, (a)) +#define RING_ATTACK_COLOR_(a) vec4(1, 0, 0, (a)) +#define RING_GUARD_COLOR_(a) vec4(0, 0, 1, (a)) + +#define RING_TAIL_PADDING_ 500 + +void loui_combat_initialize( + loui_combat_t* combat, + loshader_set_t* shaders, + const locommon_ticker_t* ticker, + const loplayer_t* player) { + assert(combat != NULL); + assert(shaders != NULL); + assert(ticker != NULL); + assert(player != NULL); + + *combat = (typeof(*combat)) { + .shaders = shaders, + .ticker = ticker, + .player = player, + }; +} + +void loui_combat_deinitialize(loui_combat_t* combat) { + assert(combat != NULL); + +} + +void loui_combat_update(loui_combat_t* combat) { + assert(combat != NULL); + + const float dt = combat->ticker->delta_f; + + const loplayer_combat_attack_t* la = combat->player->combat.last_attack; + locommon_easing_smooth_float(&combat->alpha, !!(la != NULL), dt*FADE_SPEED_); + if (la == NULL) { + if (combat->ring_end <= combat->ticker->time) { + combat->ring_end = 0; + } + return; + } + + if (combat->ring_end <= combat->ring_start) { + combat->ring_start = combat->ticker->time; + } + combat->ring_end = la->start + la->duration + RING_TAIL_PADDING_; +} + +void loui_combat_draw(const loui_combat_t* combat) { + assert(combat != NULL); + + if (combat->alpha <= 0) return; + + loshader_combat_ring_drawer_add_instance( + &combat->shaders->drawer.combat_ring, + &(loshader_combat_ring_drawer_instance_t) { + .range = -1, /* = base */ + .color = RING_BASE_COLOR_(combat->alpha), + }); + + const uint64_t ring_st = combat->ring_start; + const uint64_t ring_ed = combat->ring_end; + if (ring_ed < ring_st) return; + + const uint64_t t = combat->ticker->time; + const uint64_t dur = ring_ed - ring_st; + loshader_combat_ring_drawer_add_instance( + &combat->shaders->drawer.combat_ring, + &(loshader_combat_ring_drawer_instance_t) { + .range = 0, /* = clockhand */ + .start = (t - ring_st)*1.f/dur, + .color = RING_CLOCKHAND_COLOR_(combat->alpha), + }); + + const loplayer_combat_t* pcombat = &combat->player->combat; + for (size_t i = 0; i < LOPLAYER_COMBAT_RESERVE; ++i) { + const loplayer_combat_attack_t* a = &pcombat->attacks[i]; + if (a->duration == 0) continue; + + const uint64_t st = MATH_MAX(ring_st, a->start); + const uint64_t ed = a->start+a->duration; + + loshader_combat_ring_drawer_add_instance( + &combat->shaders->drawer.combat_ring, + &(loshader_combat_ring_drawer_instance_t) { + .range = RING_ATTACK_RANGE_, + .start = (st - ring_st)*1.f/dur, + .end = (ed - ring_st)*1.f/dur, + .color = RING_ATTACK_COLOR_(combat->alpha), + }); + } + + const uint64_t gst = MATH_MAX(ring_st, pcombat->last_guard_start); + const uint64_t ged = + pcombat->last_guard_start <= pcombat->last_guard_end? + pcombat->last_guard_end: t; + if (ring_st <= gst && gst < ged && ged < ring_ed) { + loshader_combat_ring_drawer_add_instance( + &combat->shaders->drawer.combat_ring, + &(loshader_combat_ring_drawer_instance_t) { + .range = RING_GUARD_RANGE_, + .start = (gst - ring_st)*1.f/dur, + .end = (ged - ring_st)*1.f/dur, + .color = RING_GUARD_COLOR_(combat->alpha), + }); + } +} diff --git a/core/loui/combat.h b/core/loui/combat.h new file mode 100644 index 0000000..cf94b8e --- /dev/null +++ b/core/loui/combat.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loshader/set.h" + +typedef struct { + loshader_set_t* shaders; + const locommon_ticker_t* ticker; + const loplayer_t* player; + + uint64_t ring_start; + uint64_t ring_end; + float clockhand; + float alpha; +} loui_combat_t; + +void +loui_combat_initialize( + loui_combat_t* combat, + loshader_set_t* shaders, + const locommon_ticker_t* ticker, + const loplayer_t* player +); + +void +loui_combat_deinitialize( + loui_combat_t* combat +); + +void +loui_combat_update( + loui_combat_t* combat +); + +void +loui_combat_draw( + const loui_combat_t* combat +); diff --git a/core/loui/event.c b/core/loui/event.c new file mode 100644 index 0000000..3326c81 --- /dev/null +++ b/core/loui/event.c @@ -0,0 +1,117 @@ +#include "./event.h" + +#include +#include + +#include "util/math/vector.h" +#include "util/glyphas/block.h" +#include "util/glyphas/cache.h" + +#include "core/locommon/easing.h" +#include "core/locommon/screen.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/event.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loresource/text.h" +#include "core/loshader/set.h" + +#define LINE_MAX_CHARS_ 256 + +#define CINESCOPE_SIZE_ .23f +#define LINE_COLOR_ vec4(1, 1, 1, 1) + +static void loui_event_update_line_(loui_event_t* ev) { + assert(ev != NULL); + + if (ev->player->event.ctx.line.last_update <= ev->last_line_update) { + return; + } + ev->last_line_update = ev->player->event.ctx.line.last_update; + + const char* id = ev->player->event.ctx.line.text_id; + const char* s = id == NULL? "": loresource_text_get(ev->res->lang, id); + + glyphas_block_clear(ev->line); + glyphas_block_add_characters( + ev->line, ev->font, &LINE_COLOR_, s, strlen(s)); + + glyphas_block_scale( + ev->line, + &vec2(2/ev->screen->resolution.x, 2/ev->screen->resolution.y)); + glyphas_block_set_origin(ev->line, &vec2(.5f, -.5f)); + + vec2_t sz, offset; + glyphas_block_calculate_geometry(ev->line, &sz, &offset); + + const float y = -1 + CINESCOPE_SIZE_/2 + sz.y/2; + glyphas_block_translate(ev->line, &vec2(0, y)); +} + +void loui_event_initialize( + loui_event_t* ev, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_screen_t* screen, + const locommon_ticker_t* ticker, + loplayer_t* player) { + assert(ev != NULL); + assert(res != NULL); + assert(shaders != NULL); + assert(screen != NULL); + assert(ticker != NULL); + assert(player != NULL); + + vec2_t fontpx; + locommon_screen_calc_pixels_from_inch(screen, &fontpx, &vec2(.15f, .15f)); + + *ev = (typeof(*ev)) { + .res = res, + .shaders = shaders, + .screen = screen, + .ticker = ticker, + .player = player, + + .font = glyphas_cache_new( + shaders->tex.event_line, + &res->font.serif, + fontpx.x, + fontpx.y), + .line = glyphas_block_new( + GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, + -fontpx.y, + INT32_MAX, + LINE_MAX_CHARS_), + }; +} + +void loui_event_deinitialize(loui_event_t* ev) { + assert(ev != NULL); + + glyphas_block_delete(ev->line); + glyphas_cache_delete(ev->font); +} + +void loui_event_update(loui_event_t* ev) { + assert(ev != NULL); + + loui_event_update_line_(ev); + + const float dt = ev->ticker->delta_f; + locommon_easing_smooth_float( + &ev->cinescope, ev->player->event.ctx.cinescope*CINESCOPE_SIZE_, dt); +} + +void loui_event_draw(const loui_event_t* ev) { + assert(ev != NULL); + + loshader_event_line_drawer_add_block( + &ev->shaders->drawer.event_line, ev->line); + + loshader_cinescope_drawer_set_param( + &ev->shaders->drawer.cinescope, + &(loshader_cinescope_drawer_param_t) { + .size = ev->cinescope, + .color = vec4(0, 0, 0, 1), + }); +} diff --git a/core/loui/event.h b/core/loui/event.h new file mode 100644 index 0000000..9b482d2 --- /dev/null +++ b/core/loui/event.h @@ -0,0 +1,50 @@ +#pragma once + +#include "util/glyphas/block.h" +#include "util/glyphas/cache.h" + +#include "core/locommon/screen.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" + +typedef struct { + loresource_set_t* res; + loshader_set_t* shaders; + const locommon_screen_t* screen; + const locommon_ticker_t* ticker; + loplayer_t* player; + + glyphas_cache_t* font; + + float cinescope; + + glyphas_block_t* line; + uint64_t last_line_update; +} loui_event_t; + +void +loui_event_initialize( + loui_event_t* ev, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_screen_t* screen, + const locommon_ticker_t* ticker, + loplayer_t* player +); + +void +loui_event_deinitialize( + loui_event_t* ev +); + +void +loui_event_update( + loui_event_t* ev +); + +void +loui_event_draw( + const loui_event_t* ev +); diff --git a/core/loui/hud.c b/core/loui/hud.c new file mode 100644 index 0000000..77b0e32 --- /dev/null +++ b/core/loui/hud.c @@ -0,0 +1,319 @@ +#include "./hud.h" + +#include +#include +#include +#include +#include +#include + +#include "util/glyphas/block.h" +#include "util/glyphas/cache.h" +#include "util/math/vector.h" + +#include "core/lochara/base.h" +#include "core/locommon/easing.h" +#include "core/locommon/screen.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loresource/text.h" +#include "core/loshader/set.h" + +#define BAR_SPEED_ 5 + +#define STATUS_MAX_WIDTH_ .6f +#define STATUS_FAITH_SIZE_ .8f + +#define EFFECT_TEXT_COLOR_ vec4(1, 1, 1, 1) +#define EFFECT_FADE_SPEED_ 2 +#define EFFECT_LINE_HEIGHT_ 1.2f + +#define BIOME_TEXT_COLOR_ vec4(1, 1, 1, 1) +#define BIOME_TEXT_SEED_ 29 /* = prime number */ + +static void loui_hud_calculate_geometry_( + loui_hud_t* hud, const locommon_screen_t* screen) { + assert(hud != NULL); + assert(locommon_screen_valid(screen)); + + typeof(hud->geo)* g = &hud->geo; + +# define inch2winpos_(winpos, inch) \ + locommon_screen_calc_winpos_from_inch(screen, winpos, inch) + + inch2winpos_(&g->padding, &vec2(.3f, .3f)); + + inch2winpos_(&g->madness_sz, &vec2(3.f, .12f)); + if (g->madness_sz.x > STATUS_MAX_WIDTH_) { + vec2_muleq(&g->madness_sz, STATUS_MAX_WIDTH_/g->madness_sz.x); + } + vec2_mul(&g->faith_sz, &g->madness_sz, .5f); + +# undef inch2winpos_ + + g->madness_pos = vec2(-1, 1); + g->madness_pos.x += g->madness_sz.x + g->padding.x; + g->madness_pos.y -= g->madness_sz.y + g->padding.y; + + g->faith_pos = vec2(-1, 1); + g->faith_pos.x += g->padding.x + g->faith_sz.x; + g->faith_pos.y -= g->padding.y + g->madness_sz.y*2 + g->faith_sz.y; + + locommon_screen_calc_pixels_from_inch( + screen, &g->effect_fontpx, &vec2(.4f, .4f)); + locommon_screen_calc_winpos_from_pixels( + screen, &g->effect_fontsz, &g->effect_fontpx); + + g->effect_sz.x = 3*screen->dpi.x/screen->resolution.x; + g->effect_sz.y = 4/screen->resolution.y; + + g->effect_pos = vec2(1-g->padding.x, -1+g->padding.y); + vec2_subeq(&g->effect_pos, &g->effect_sz); + + locommon_screen_calc_pixels_from_inch( + screen, &g->biome_fontpx, &vec2(.3f, .3f)); + locommon_screen_calc_winpos_from_pixels( + screen, &g->biome_fontsz, &g->biome_fontpx); + + vec2_add(&g->biome_pos, &vec2(-1, -1), &g->padding); +} + +static void loui_hud_draw_status_bars_(const loui_hud_t* hud) { + assert(hud != NULL); + + loshader_hud_bar_drawer_add_instance( + &hud->shaders->drawer.hud_bar, + &(loshader_hud_bar_drawer_instance_t) { + .pos = hud->geo.madness_pos, + .size = hud->geo.madness_sz, + .bgcolor = vec4(0, 0, 0, hud->alpha), + .fgcolor = vec4(1, 1, 1, .9f*hud->alpha), + + .value = hud->player->entity->param.recipient.madness, + .prev_value = hud->prev_madness, + }); + loshader_hud_bar_drawer_add_instance( + &hud->shaders->drawer.hud_bar, + &(loshader_hud_bar_drawer_instance_t) { + .pos = hud->geo.faith_pos, + .size = hud->geo.faith_sz, + .bgcolor = vec4(0, 0, 0, hud->alpha), + .fgcolor = vec4(.9f, .9f, .9f, .9f*hud->alpha), + + .value = hud->player->entity->param.recipient.faith, + .prev_value = hud->prev_faith, + }); +} + +static void loui_hud_initialize_effect_( + loui_hud_t* hud, + loui_hud_effect_t* effect, + const locommon_screen_t* screen, + const char* name) { + assert(hud != NULL); + assert(effect != NULL); + assert(name != NULL); + assert(locommon_screen_valid(screen)); + + *effect = (typeof(*effect)) { + .text = glyphas_block_new( + GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, + -hud->geo.effect_fontpx.y, + INT32_MAX, + 32), + }; + glyphas_block_add_characters( + effect->text, hud->font.effect, &EFFECT_TEXT_COLOR_, name, strlen(name)); + + const vec2_t reso = screen->resolution; + glyphas_block_scale(effect->text, &vec2(2/reso.x, 2/reso.y)); +} + +static void loui_hud_deinitialize_effect_(loui_hud_effect_t* effect) { + assert(effect != NULL); + + glyphas_block_delete(effect->text); +} + +static void loui_hud_update_effect_bars_(loui_hud_t* hud) { + assert(hud != NULL); + + const loeffect_recipient_t* r = &hud->player->entity->param.recipient; + loui_hud_effect_set_t* e = &hud->effects.set; + + const uint64_t t = hud->ticker->time; + const float dt = hud->ticker->delta_f; + +# define lasting_effect_(n) do { \ + const bool active = \ + r->effects.n.start <= t && \ + t < r->effects.n.start + r->effects.n.duration; \ + locommon_easing_smooth_float( \ + &e->n.alpha, !!active, dt*EFFECT_FADE_SPEED_); \ + if (active) { \ + e->n.value = (t - r->effects.n.start)*1.f / r->effects.n.duration; \ + } \ + } while (0) + + lasting_effect_(amnesia); + lasting_effect_(curse); + +# undef lasting_effect_ +} + +static void loui_hud_draw_effect_bars_(const loui_hud_t* hud) { + assert(hud != NULL); + + const typeof(hud->geo)* g = &hud->geo; + + float h = 0; + for (size_t i = 0; i < LOUI_HUD_EFFECT_COUNT; ++i) { + const loui_hud_effect_t* e = &hud->effects.arr[i]; + if (e->alpha == 0) continue; + + const float a = e->alpha * hud->alpha; + const float y = h*g->effect_fontsz.y + g->effect_pos.y; + + glyphas_block_set_origin(e->text, &vec2(1, -1)); + glyphas_block_translate(e->text, &vec2(1-g->padding.x, y)); + glyphas_block_set_alpha(e->text, powf(a, 2)); + + loshader_hud_text_drawer_add_block( + &hud->shaders->drawer.hud_text, e->text); + + loshader_hud_bar_drawer_add_instance( + &hud->shaders->drawer.hud_bar, + &(loshader_hud_bar_drawer_instance_t) { + .pos = vec2(g->effect_pos.x, y), + .size = vec2(-g->effect_sz.x, g->effect_sz.y), + .bgcolor = vec4(1, 1, 1, .2f*a), + .fgcolor = vec4(1, 1, 1, .8f*a), + .value = e->value, + .prev_value = e->value, + }); + h += a*a*(3-2*a)*EFFECT_LINE_HEIGHT_; + } +} + +static glyphas_block_t* loui_hud_create_biome_text_( + loui_hud_t* hud, const locommon_screen_t* screen, const char* text) { + assert(hud != NULL); + assert(text != NULL); + assert(locommon_screen_valid(screen)); + + glyphas_block_t* b = glyphas_block_new( + GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, + -hud->geo.biome_fontpx.y, + INT32_MAX, + 32); + glyphas_block_add_characters( + b, hud->font.biome, &BIOME_TEXT_COLOR_, text, strlen(text)); + + const vec2_t reso = screen->resolution; + glyphas_block_scale(b, &vec2(2/reso.x, 2/reso.y)); + + glyphas_block_set_origin(b, &vec2(0, -1)); + glyphas_block_translate(b, &hud->geo.biome_pos); + + glyphas_block_make_glitched(b, text[0]*BIOME_TEXT_SEED_); + return b; +} + +static void loui_hud_draw_biome_text_(const loui_hud_t* hud) { + assert(hud != NULL); + + loshader_hud_text_drawer_add_block( + &hud->shaders->drawer.hud_text, hud->biomes[hud->current_biome]); +} + +void loui_hud_initialize( + loui_hud_t* hud, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_screen_t* screen, + const locommon_ticker_t* ticker, + loplayer_t* player) { + assert(hud != NULL); + assert(res != NULL); + assert(shaders != NULL); + assert(ticker != NULL); + assert(player != NULL); + assert(locommon_screen_valid(screen)); + + *hud = (typeof(*hud)) { + .shaders = shaders, + .ticker = ticker, + .player = player, + }; + loui_hud_calculate_geometry_(hud, screen); + + hud->font = (typeof(hud->font)) { + .effect = glyphas_cache_new( + shaders->tex.hud_text, + &res->font.sans, + hud->geo.effect_fontpx.x, + hud->geo.effect_fontpx.y), + .biome = glyphas_cache_new( + shaders->tex.hud_text, + &res->font.serif, + hud->geo.biome_fontpx.x, + hud->geo.biome_fontpx.y), + }; + +# define text_(name) loresource_text_get(res->lang, name) + + loui_hud_effect_set_t* e = &hud->effects.set; + loui_hud_initialize_effect_( + hud, &e->amnesia, screen, text_("effect_amnesia")); + loui_hud_initialize_effect_( + hud, &e->curse, screen, text_("effect_curse")); + +# define each_(NAME, name) do { \ + hud->biomes[LOWORLD_CHUNK_BIOME_##NAME] = \ + loui_hud_create_biome_text_(hud, screen, text_("biome_"#name)); \ + } while (0) + LOWORLD_CHUNK_BIOME_EACH(each_); +# undef each_ + +# undef text_ +} + +void loui_hud_deinitialize(loui_hud_t* hud) { + assert(hud != NULL); + + for (size_t i = 0; i < LOUI_HUD_EFFECT_COUNT; ++i) { + loui_hud_deinitialize_effect_(&hud->effects.arr[i]); + } + for (size_t i = 0; i < LOWORLD_CHUNK_BIOME_COUNT; ++i) { + glyphas_block_delete(hud->biomes[i]); + } + glyphas_cache_delete(hud->font.effect); + glyphas_cache_delete(hud->font.biome); +} + +void loui_hud_update(loui_hud_t* hud) { + assert(hud != NULL); + + const float dt = hud->ticker->delta_f; + + locommon_easing_smooth_float( + &hud->prev_madness, + hud->player->entity->param.recipient.madness, + dt*BAR_SPEED_); + locommon_easing_smooth_float( + &hud->prev_faith, hud->player->entity->param.recipient.faith, + dt*BAR_SPEED_); + + loui_hud_update_effect_bars_(hud); +} + +void loui_hud_draw(const loui_hud_t* hud) { + assert(hud != NULL); + + hud->shaders->drawer.hud_text.alpha = hud->alpha; + + loui_hud_draw_status_bars_(hud); + loui_hud_draw_effect_bars_(hud); + loui_hud_draw_biome_text_(hud); +} diff --git a/core/loui/hud.h b/core/loui/hud.h new file mode 100644 index 0000000..9adb212 --- /dev/null +++ b/core/loui/hud.h @@ -0,0 +1,96 @@ +#pragma once + +#include + +#include "util/glyphas/block.h" +#include "util/glyphas/cache.h" +#include "util/math/vector.h" + +#include "core/locommon/screen.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" +#include "core/loworld/chunk.h" + +typedef struct { + glyphas_block_t* text; + + float alpha; + float value; +} loui_hud_effect_t; + +typedef struct { + loui_hud_effect_t amnesia; + loui_hud_effect_t curse; +} loui_hud_effect_set_t; + +#define LOUI_HUD_EFFECT_COUNT \ + (sizeof(loui_hud_effect_set_t)/sizeof(loui_hud_effect_t)) + +typedef struct { + loshader_set_t* shaders; + const locommon_ticker_t* ticker; + loplayer_t* player; + + struct { + glyphas_cache_t* effect; + glyphas_cache_t* biome; + } font; + + struct { + vec2_t padding; + + vec2_t madness_pos; + vec2_t madness_sz; + vec2_t faith_pos; + vec2_t faith_sz; + + vec2_t effect_fontpx; + vec2_t effect_fontsz; + vec2_t effect_pos; + vec2_t effect_sz; + + vec2_t biome_fontpx; + vec2_t biome_fontsz; + vec2_t biome_pos; + } geo; + + union { + loui_hud_effect_set_t set; + loui_hud_effect_t arr[LOUI_HUD_EFFECT_COUNT]; + } effects; + + glyphas_block_t* biomes[LOWORLD_CHUNK_BIOME_COUNT]; + loworld_chunk_biome_t current_biome; + + float prev_madness; + float prev_faith; + + float alpha; +} loui_hud_t; + +void +loui_hud_initialize( + loui_hud_t* hud, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_screen_t* screen, + const locommon_ticker_t* ticker, + loplayer_t* player +); + +void +loui_hud_deinitialize( + loui_hud_t* hud +); + +void +loui_hud_update( + loui_hud_t* hud +); + +void +loui_hud_draw( + const loui_hud_t* hud +); diff --git a/core/loui/menu.c b/core/loui/menu.c new file mode 100644 index 0000000..4b5d6e5 --- /dev/null +++ b/core/loui/menu.c @@ -0,0 +1,366 @@ +#include "./menu.h" + +#include +#include + +#include "util/glyphas/block.h" +#include "util/glyphas/cache.h" +#include "util/math/constant.h" +#include "util/math/vector.h" + +#include "core/locommon/easing.h" +#include "core/locommon/input.h" +#include "core/locommon/screen.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loplayer/stance.h" +#include "core/loresource/set.h" +#include "core/loresource/text.h" +#include "core/loshader/set.h" + +#define FADE_SPEED_ 2 + +#define STANCE_TEXT_LINEHEIGHT_ 1.5f +#define STANCE_TEXT_MAX_WIDTH_ 3.5f /* inch */ + +#define STANCE_NAME_RESERVE_ 32 +#define STANCE_DESC_RESERVE_ 256 +#define STANCE_NOTE_RESERVE_ 256 + +#define STANCE_NAME_COLOR_ vec4(1, 1, 1, 1) +#define STANCE_DESC_COLOR_ vec4(1, 1, 1, 1) +#define STANCE_NOTE_COLOR_ vec4(.8f, .8f, 0, 1) + +#define STANCE_ICON_HIGHLIGHT_SPEED_ 5 +#define STANCE_ICON_HIGHLIGHT_SIZE_ .2f + +static void loui_menu_calc_geometry_( + loui_menu_t* menu, const locommon_screen_t* screen) { + assert(menu != NULL); + assert(locommon_screen_valid(screen)); + + typeof(menu->geo)* g = &menu->geo; + +# define calc_font_geo_(name, sz) do { \ + locommon_screen_calc_pixels_from_inch( \ + screen, &g->name##_fontpx, sz); \ + locommon_screen_calc_winpos_from_pixels( \ + screen, &g->name##_fontsz, &g->big_fontpx); \ + } while (0) + + calc_font_geo_(big, &vec2(.20f, .20f)); + calc_font_geo_(normal, &vec2(.16f, .16f)); + calc_font_geo_(small, &vec2(.12f, .12f)); + +# undef calc_font_geo_ + + locommon_screen_calc_winpos_from_inch( + screen, &g->stance_icon_interval, &vec2(2, 2)); + locommon_screen_calc_winpos_from_inch( + screen, &g->stance_iconsz, &vec2(.3f, .3f)); +} + +static void loui_menu_initialize_stance_( + loui_menu_t* menu, + loui_menu_stance_t* stance, + const locommon_screen_t* screen, + const char* name, + const char* desc, + const char* note) { + assert(menu != NULL); + assert(stance != NULL); + assert(name != NULL); + assert(desc != NULL); + assert(note != NULL); + assert(locommon_screen_valid(screen)); + + *stance = (typeof(*stance)) {0}; + + const float theta = + (stance - menu->stances)*1.f/LOPLAYER_STANCE_COUNT*2*MATH_PI + + MATH_PI/2; + stance->pos.x = cos(theta) * menu->geo.stance_icon_interval.x; + stance->pos.y = sin(theta) * menu->geo.stance_icon_interval.y; + + const float width = screen->dpi.x*STANCE_TEXT_MAX_WIDTH_; + const vec2_t invreso = vec2(2/screen->resolution.x, 2/screen->resolution.y); + + stance->name = glyphas_block_new( + GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, + -menu->geo.big_fontpx.y*STANCE_TEXT_LINEHEIGHT_, + INT32_MAX, + STANCE_NAME_RESERVE_); + glyphas_block_add_characters( + stance->name, + menu->font.sans.big, + &STANCE_NAME_COLOR_, + name, + strlen(name)); + glyphas_block_scale(stance->name, &invreso); + + stance->desc = glyphas_block_new( + GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, + -menu->geo.normal_fontpx.y*STANCE_TEXT_LINEHEIGHT_, + width, + STANCE_DESC_RESERVE_); + glyphas_block_add_characters( + stance->desc, + menu->font.sans.normal, + &STANCE_DESC_COLOR_, + desc, + strlen(desc)); + glyphas_block_scale(stance->desc, &invreso); + + stance->note = glyphas_block_new( + GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, + -menu->geo.small_fontpx.y, + width, + STANCE_NOTE_RESERVE_); + glyphas_block_add_characters( + stance->note, + menu->font.serif.small, + &STANCE_NOTE_COLOR_, + note, + strlen(note)); + glyphas_block_scale(stance->note, &invreso); + + glyphas_block_set_origin(stance->name, &vec2(.5f, 0)); + glyphas_block_set_origin(stance->desc, &vec2(.5f, 0)); + glyphas_block_set_origin(stance->note, &vec2(.5f, 0)); + + vec2_t dummy; + + vec2_t namesz; + glyphas_block_calculate_geometry(stance->name, &dummy, &namesz); + vec2_t descsz; + glyphas_block_calculate_geometry(stance->desc, &dummy, &descsz); + vec2_t notesz; + glyphas_block_calculate_geometry(stance->note, &dummy, ¬esz); + + const float note_padding = menu->geo.small_fontsz.y; + + float y = (namesz.y + descsz.y + note_padding + notesz.y)/2; + glyphas_block_translate(stance->name, &vec2(0, y)); + + y -= namesz.y; + glyphas_block_translate(stance->desc, &vec2(0, y)); + + y -= descsz.y + note_padding; + glyphas_block_translate(stance->note, &vec2(0, y)); +} + +static void loui_menu_deinitialize_stance_(loui_menu_stance_t* stance) { + assert(stance != NULL); + + glyphas_block_delete(stance->name); + glyphas_block_delete(stance->desc); + glyphas_block_delete(stance->note); +} + +static glyphas_block_t* loui_menu_create_exit_text_( + loui_menu_t* menu, const locommon_screen_t* screen, const char* text) { + assert(menu != NULL); + assert(screen != NULL); + assert(text != NULL); + + glyphas_block_t* b = glyphas_block_new( + GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, + -menu->geo.normal_fontpx.y, + INT32_MAX, + 32); + glyphas_block_add_characters( + b, menu->font.sans.normal, &vec4(1, 1, 1, 1), text, strlen(text)); + + glyphas_block_scale( + b, &vec2(2.f/screen->resolution.x, 2.f/screen->resolution.y)); + glyphas_block_set_origin(b, &vec2(.5f, -1)); + glyphas_block_translate(b, &vec2(0, -1)); + return b; +} + +static loui_menu_stance_t* loui_menu_find_stance_icon_at_( + loui_menu_t* menu, const vec2_t* pos) { + assert(menu != NULL); + assert(vec2_valid(pos)); + + for (size_t i = 0; i < LOPLAYER_STANCE_COUNT; ++i) { + vec2_t p; + vec2_sub(&p, pos, &menu->stances[i].pos); + p.x /= menu->geo.stance_iconsz.x; + p.y /= menu->geo.stance_iconsz.y; + if (fabsf(p.x) + fabsf(p.y) < 1) { + return &menu->stances[i]; + } + } + return NULL; +} + +static void loui_menu_update_stances_( + loui_menu_t* menu, const locommon_input_t* input) { + assert(menu != NULL); + + const float dt = menu->ticker->delta_f; + + menu->hovered_stance = + input == NULL? NULL: + loui_menu_find_stance_icon_at_(menu, &input->cursor); + + for (size_t i = 0; i < LOPLAYER_STANCE_COUNT; ++i) { + loui_menu_stance_t* s = &menu->stances[i]; + locommon_easing_linear_float( + &s->highlight, + s == menu->hovered_stance, + dt*STANCE_ICON_HIGHLIGHT_SPEED_); + } +} + +static void loui_menu_draw_stance_icons_(const loui_menu_t* menu) { + assert(menu != NULL); + + for (size_t i = 0; i < LOPLAYER_STANCE_COUNT; ++i) { + const loui_menu_stance_t* s = &menu->stances[i]; + + const loshader_menu_stance_id_t id = + loplayer_stance_set_has(&menu->player->stances, i)? + loplayer_stance_get_menu_shader_id(i): + LOSHADER_MENU_STANCE_ID_EMPTY; + + vec2_t sz = menu->geo.stance_iconsz; + vec2_muleq(&sz, 1+powf(s->highlight, 2.f)*STANCE_ICON_HIGHLIGHT_SIZE_); + + loshader_menu_stance_drawer_add_instance( + &menu->shaders->drawer.menu_stance, + &(loshader_menu_stance_drawer_instance_t) { + .id = id, + .pos = s->pos, + .size = sz, + .alpha = menu->alpha, + }); + } +} + +static void loui_menu_draw_stance_text_(const loui_menu_t* menu) { + assert(menu != NULL); + + if (menu->hovered_stance == NULL) return; + + const size_t index = menu->hovered_stance - menu->stances; + + const loui_menu_stance_t* s = menu->hovered_stance; + if (!loplayer_stance_set_has(&menu->player->stances, index)) { + s = &menu->stances[LOPLAYER_STANCE_COUNT]; + } + + loshader_menu_text_drawer_add_block( + &menu->shaders->drawer.menu_text, s->name); + loshader_menu_text_drawer_add_block( + &menu->shaders->drawer.menu_text, s->desc); + loshader_menu_text_drawer_add_block( + &menu->shaders->drawer.menu_text, s->note); +} + +void loui_menu_initialize( + loui_menu_t* menu, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_screen_t* screen, + const locommon_ticker_t* ticker, + loplayer_t* player) { + assert(menu != NULL); + assert(res != NULL); + assert(shaders != NULL); + assert(ticker != NULL); + assert(player != NULL); + assert(locommon_screen_valid(screen)); + + *menu = (typeof(*menu)) { + .shaders = shaders, + .ticker = ticker, + .player = player, + }; + loui_menu_calc_geometry_(menu, screen); + + menu->font = (typeof(menu->font)) { + .sans = { + .big = glyphas_cache_new( + shaders->tex.menu_text, + &res->font.sans, + menu->geo.big_fontpx.x, + menu->geo.big_fontpx.y), + .normal = glyphas_cache_new( + shaders->tex.menu_text, + &res->font.sans, + menu->geo.normal_fontpx.x, + menu->geo.normal_fontpx.y), + }, + .serif = { + .small = glyphas_cache_new( + shaders->tex.menu_text, + &res->font.serif, + menu->geo.small_fontpx.x, + menu->geo.small_fontpx.y), + }, + }; + +# define text_(v) loresource_text_get(res->lang, v) + +# define each_(NAME, name) \ + loui_menu_initialize_stance_( \ + menu, \ + &menu->stances[LOPLAYER_STANCE_##NAME], \ + screen, \ + text_("stance_"#name"_name"), \ + text_("stance_"#name"_desc"), \ + text_("stance_"#name"_note")) + LOPLAYER_STANCE_EACH(each_); +# undef each_ + + loui_menu_initialize_stance_( + menu, &menu->stances[LOPLAYER_STANCE_COUNT], + screen, + text_("stance_unknown_name"), + text_("stance_unknown_desc"), + text_("stance_unknown_note")); + menu->exit_text = loui_menu_create_exit_text_( + menu, screen, text_("menu_exit")); + +# undef text_ +} + +void loui_menu_deinitialize(loui_menu_t* menu) { + assert(menu != NULL); + + for (size_t i = 0; i < LOPLAYER_STANCE_COUNT+1; ++i) { + loui_menu_deinitialize_stance_(&menu->stances[i]); + } + glyphas_block_delete(menu->exit_text); + glyphas_cache_delete(menu->font.sans.big); + glyphas_cache_delete(menu->font.sans.normal); + glyphas_cache_delete(menu->font.serif.small); +} + +void loui_menu_update(loui_menu_t* menu, const locommon_input_t* input) { + assert(menu != NULL); + + loui_menu_update_stances_(menu, input); + + menu->request_exit = + input != NULL && + input->buttons & LOCOMMON_INPUT_BUTTON_OK && + input->cursor.y < -1+menu->geo.normal_fontsz.y; +} + +void loui_menu_draw(const loui_menu_t* menu) { + assert(menu != NULL); + + if (menu->alpha <= 0) return; + + menu->shaders->drawer.menu_text.alpha = menu->alpha; + menu->shaders->drawer.menu_background.alpha = menu->alpha; + + loui_menu_draw_stance_icons_(menu); + loui_menu_draw_stance_text_(menu); + + loshader_menu_text_drawer_add_block( + &menu->shaders->drawer.menu_text, menu->exit_text); +} diff --git a/core/loui/menu.h b/core/loui/menu.h new file mode 100644 index 0000000..05f0d73 --- /dev/null +++ b/core/loui/menu.h @@ -0,0 +1,86 @@ +#pragma once + +#include "util/glyphas/block.h" +#include "util/glyphas/cache.h" +#include "util/math/vector.h" + +#include "core/locommon/input.h" +#include "core/locommon/screen.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loplayer/stance.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" + +typedef struct { + glyphas_block_t* name; + glyphas_block_t* desc; + glyphas_block_t* note; + + vec2_t pos; + float highlight; +} loui_menu_stance_t; + +typedef struct { + loshader_set_t* shaders; + const locommon_ticker_t* ticker; + loplayer_t* player; + + struct { + struct { + glyphas_cache_t* big; + glyphas_cache_t* normal; + } sans; + struct { + glyphas_cache_t* small; + } serif; + } font; + + struct { + vec2_t big_fontpx; + vec2_t big_fontsz; + + vec2_t normal_fontpx; + vec2_t normal_fontsz; + + vec2_t small_fontpx; + vec2_t small_fontsz; + + vec2_t stance_icon_interval; + vec2_t stance_iconsz; + } geo; + + loui_menu_stance_t stances[LOPLAYER_STANCE_COUNT+1]; + loui_menu_stance_t* hovered_stance; + + glyphas_block_t* exit_text; + bool request_exit; + + float alpha; +} loui_menu_t; + +void +loui_menu_initialize( + loui_menu_t* menu, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_screen_t* screen, + const locommon_ticker_t* ticker, + loplayer_t* player +); + +void +loui_menu_deinitialize( + loui_menu_t* menu +); + +void +loui_menu_update( + loui_menu_t* menu, + const locommon_input_t* input /* NULLABLE */ +); + +void +loui_menu_draw( + const loui_menu_t* menu +); diff --git a/core/loui/popup.c b/core/loui/popup.c new file mode 100644 index 0000000..bdbc9bd --- /dev/null +++ b/core/loui/popup.c @@ -0,0 +1,137 @@ +#include "./popup.h" + +#include +#include +#include + +#include "util/glyphas/block.h" +#include "util/glyphas/cache.h" +#include "util/math/vector.h" + +#include "core/locommon/easing.h" +#include "core/locommon/screen.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loplayer/popup.h" +#include "core/loresource/set.h" +#include "core/loresource/text.h" +#include "core/loshader/set.h" + +#define DURATION_ 4 /* [sec] */ + +#define HEAD_COLOR_ vec4(1, 1, 1, 1) + +static void loui_popup_calculate_geometry_( + loui_popup_t* popup, const locommon_screen_t* screen) { + assert(popup != NULL); + assert(screen != NULL); + + typeof(popup->geo)* g = &popup->geo; + + locommon_screen_calc_pixels_from_inch( + screen, &g->big_fontpx, &vec2(.6f, .6f)); + locommon_screen_calc_winpos_from_pixels( + screen, &g->big_fontsz, &g->big_fontpx); +} + +static glyphas_block_t* loui_popup_create_head_text_( + loui_popup_t* popup, const locommon_screen_t* screen, const char* str) { + assert(popup != NULL); + assert(screen != NULL); + assert(str != NULL); + + glyphas_block_t* b = glyphas_block_new( + GLYPHAS_ALIGNER_DIRECTION_HORIZONTAL, + -popup->geo.big_fontpx.y, + INT32_MAX, + 32); + glyphas_block_add_characters( + b, + popup->font.serif.big, + &HEAD_COLOR_, + str, + strlen(str)); + glyphas_block_scale( + b, &vec2(2/screen->resolution.x, 2/screen->resolution.y)); + + glyphas_block_set_origin(b, &vec2(.5f, -1)); + return b; +} + +void loui_popup_initialize( + loui_popup_t* popup, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_screen_t* screen, + const locommon_ticker_t* ticker, + loplayer_t* player) { + assert(popup != NULL); + assert(res != NULL); + assert(shaders != NULL); + assert(screen != NULL); + assert(ticker != NULL); + assert(player != NULL); + + *popup = (typeof(*popup)) { + .shaders = shaders, + .ticker = ticker, + .player = player, + }; + loui_popup_calculate_geometry_(popup, screen); + + popup->font = (typeof(popup->font)) { + .serif = { + .big = glyphas_cache_new( + shaders->tex.popup_text, + &res->font.serif, + popup->geo.big_fontpx.x, + popup->geo.big_fontpx.y), + }, + }; + +# define text_(v) loresource_text_get(res->lang, v) + + popup->head = (typeof(popup->head)) { + .new_stance = loui_popup_create_head_text_( + popup, screen, text_("popup_new_stance_head")), + }; + +# undef text_ +} + +void loui_popup_deinitialize(loui_popup_t* popup) { + assert(popup != NULL); + + glyphas_block_delete(popup->head.new_stance); + glyphas_cache_delete(popup->font.serif.big); +} + +void loui_popup_update(loui_popup_t* popup) { + assert(popup != NULL); + + const float dt = popup->ticker->delta_f; + locommon_easing_linear_float(&popup->alpha, 0, dt/DURATION_); + if (popup->alpha > 0) return; + + const loplayer_popup_item_t* item = + loplayer_popup_enqueue(&popup->player->popup); + if (item == NULL) return; + + popup->item = *item; + popup->alpha = 1; +} + +void loui_popup_draw(const loui_popup_t* popup) { + assert(popup != NULL); + + if (popup->alpha <= 0) return; + + popup->shaders->drawer.popup_text.alpha = popup->alpha; + + switch (popup->item.type) { + case LOPLAYER_POPUP_ITEM_TYPE_NEW_STANCE: + loshader_popup_text_drawer_add_block( + &popup->shaders->drawer.popup_text, popup->head.new_stance); + break; + } +} diff --git a/core/loui/popup.h b/core/loui/popup.h new file mode 100644 index 0000000..db57246 --- /dev/null +++ b/core/loui/popup.h @@ -0,0 +1,61 @@ +#pragma once + +#include "util/glyphas/block.h" +#include "util/glyphas/cache.h" +#include "util/math/vector.h" + +#include "core/locommon/screen.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loplayer/popup.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" + +typedef struct { + loshader_set_t* shaders; + const locommon_ticker_t* ticker; + loplayer_t* player; + + struct { + struct { + glyphas_cache_t* big; + } serif; + } font; + + struct { + vec2_t big_fontpx; + vec2_t big_fontsz; + } geo; + + float alpha; + loplayer_popup_item_t item; + + struct { + glyphas_block_t* new_stance; + } head; +} loui_popup_t; + +void +loui_popup_initialize( + loui_popup_t* popup, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_screen_t* screen, + const locommon_ticker_t* ticker, + loplayer_t* player +); + +void +loui_popup_deinitialize( + loui_popup_t* popup +); + +void +loui_popup_update( + loui_popup_t* popup +); + +void +loui_popup_draw( + const loui_popup_t* popup +); diff --git a/core/loui/ui.c b/core/loui/ui.c new file mode 100644 index 0000000..c6cda78 --- /dev/null +++ b/core/loui/ui.c @@ -0,0 +1,130 @@ +#include "./ui.h" + +#include +#include +#include + +#include "core/locommon/easing.h" +#include "core/locommon/input.h" +#include "core/locommon/screen.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" +#include "core/loworld/chunk.h" +#include "core/loworld/view.h" + +#include "./combat.h" +#include "./event.h" +#include "./hud.h" +#include "./menu.h" + +#define FADE_SPEED_ 4 + +void loui_initialize( + loui_t* ui, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_screen_t* screen, + const locommon_ticker_t* ticker, + loplayer_t* player, + const loworld_view_t* view) { + assert(ui != NULL); + assert(res != NULL); + assert(shaders != NULL); + assert(ticker != NULL); + assert(player != NULL); + assert(view != NULL); + assert(locommon_screen_valid(screen)); + + *ui = (typeof(*ui)) { + .ticker = ticker, + .view = view, + }; + + loui_combat_initialize( + &ui->combat, + shaders, + ticker, + player); + loui_hud_initialize( + &ui->hud, + res, + shaders, + screen, + ticker, + player); + loui_popup_initialize( + &ui->popup, + res, + shaders, + screen, + ticker, + player); + loui_menu_initialize( + &ui->menu, + res, + shaders, + screen, + ticker, + player); + loui_event_initialize( + &ui->event, + res, + shaders, + screen, + ticker, + player); +} + +void loui_deinitialize(loui_t* ui) { + assert(ui != NULL); + + loui_event_deinitialize(&ui->event); + loui_menu_deinitialize(&ui->menu); + loui_popup_deinitialize(&ui->popup); + loui_hud_deinitialize(&ui->hud); + loui_combat_deinitialize(&ui->combat); +} + +void loui_update(loui_t* ui, const locommon_input_t* input) { + assert(ui != NULL); + assert(input != NULL); + + const bool pressed = input->buttons & LOCOMMON_INPUT_BUTTON_MENU; + const float dt = ui->ticker->delta_f; + + if (pressed && !ui->pressed) ui->menu_shown = !ui->menu_shown; + ui->pressed = pressed; + locommon_easing_smooth_float( + &ui->menu.alpha, !!ui->menu_shown, dt*FADE_SPEED_); + + const bool hud = !ui->menu_shown; + locommon_easing_smooth_float( + &ui->hud.alpha, !!hud, dt*FADE_SPEED_); + + const loworld_chunk_t* chunk = loworld_view_get_looking_chunk(ui->view); + ui->hud.current_biome = chunk->biome; + + loui_combat_update(&ui->combat); + loui_hud_update(&ui->hud); + loui_popup_update(&ui->popup); + loui_menu_update(&ui->menu, ui->menu_shown? input: NULL); + loui_event_update(&ui->event); +} + +void loui_draw(const loui_t* ui) { + assert(ui != NULL); + + loui_combat_draw(&ui->combat); + loui_hud_draw(&ui->hud); + loui_popup_draw(&ui->popup); + loui_menu_draw(&ui->menu); + loui_event_draw(&ui->event); +} + +bool loui_is_grabbing_input(const loui_t* ui) { + assert(ui != NULL); + + return ui->menu_shown; +} diff --git a/core/loui/ui.h b/core/loui/ui.h new file mode 100644 index 0000000..22fc8f3 --- /dev/null +++ b/core/loui/ui.h @@ -0,0 +1,63 @@ +#pragma once + +#include + +#include "core/locommon/input.h" +#include "core/locommon/screen.h" +#include "core/locommon/ticker.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" +#include "core/loworld/view.h" + +#include "./combat.h" +#include "./event.h" +#include "./hud.h" +#include "./menu.h" +#include "./popup.h" + +typedef struct { + const locommon_ticker_t* ticker; + const loworld_view_t* view; + + loui_combat_t combat; + loui_hud_t hud; + loui_popup_t popup; + loui_menu_t menu; + loui_event_t event; + + bool pressed; + bool menu_shown; +} loui_t; + +void +loui_initialize( + loui_t* ui, + loresource_set_t* res, + loshader_set_t* shaders, + const locommon_screen_t* screen, + const locommon_ticker_t* ticker, + loplayer_t* player, + const loworld_view_t* view +); + +void +loui_deinitialize( + loui_t* ui +); + +void +loui_update( + loui_t* ui, + const locommon_input_t* input +); + +void +loui_draw( + const loui_t* ui +); + +bool +loui_is_grabbing_input( + const loui_t* ui +); diff --git a/core/loworld/CMakeLists.txt b/core/loworld/CMakeLists.txt index 65f2a8a..af8fd50 100644 --- a/core/loworld/CMakeLists.txt +++ b/core/loworld/CMakeLists.txt @@ -7,21 +7,27 @@ add_library(loworld template.c view.c ) +target_benum_sources(loworld + chunk.h +) target_link_libraries(loworld msgpackc chaos container + flasy jukebox math memory mpkutil lobullet - locharacter + lochara locommon loentity loground + loparticle + loplayer loresource loshader ) diff --git a/core/loworld/chunk.c b/core/loworld/chunk.c index 83b9331..7935b3c 100644 --- a/core/loworld/chunk.c +++ b/core/loworld/chunk.c @@ -29,36 +29,6 @@ static void loworld_chunk_pack_entities_( } } -const char* loworld_chunk_biome_stringify(loworld_chunk_biome_t biome) { -# define each_(NAME, name) \ - if (biome == LOWORLD_CHUNK_BIOME_##NAME) return #name; - - LOWORLD_CHUNK_BIOME_EACH_(each_); - - assert(false); - return NULL; - -# undef each_ -} - -bool loworld_chunk_biome_unstringify( - loworld_chunk_biome_t* biome, const char* str, size_t len) { - assert(biome != NULL); - assert(str != NULL || len == 0); - -# define each_(NAME, name) do { \ - if (strncmp(str, #name, len) == 0 && #name[len] == 0) { \ - *biome = LOWORLD_CHUNK_BIOME_##NAME; \ - return true; \ - } \ - } while (0) - - LOWORLD_CHUNK_BIOME_EACH_(each_); - return false; - -# undef each_ -} - void loworld_chunk_initialize(loworld_chunk_t* chunk) { assert(chunk != NULL); diff --git a/core/loworld/chunk.h b/core/loworld/chunk.h index f46fb8a..2395cf8 100644 --- a/core/loworld/chunk.h +++ b/core/loworld/chunk.h @@ -14,24 +14,19 @@ #define LOWORLD_CHUNK_FILENAME_MAX 64 -/* dont forget to change EACH macro */ typedef enum { + /* BENUM BEGIN loworld_chunk_biome */ LOWORLD_CHUNK_BIOME_METAPHYSICAL_GATE, LOWORLD_CHUNK_BIOME_CAVIAS_CAMP, LOWORLD_CHUNK_BIOME_LABORATORY, LOWORLD_CHUNK_BIOME_BOSS_THEISTS_CHILD, LOWORLD_CHUNK_BIOME_BOSS_BIG_WARDER, LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST, + /* BENUM END */ } loworld_chunk_biome_t; -#define LOWORLD_CHUNK_BIOME_EACH_(PROC) do { \ - PROC(METAPHYSICAL_GATE, metaphysical-gate); \ - PROC(CAVIAS_CAMP, cavias-camp); \ - PROC(LABORATORY, laboratory); \ - PROC(BOSS_THEISTS_CHILD, boss-theists-child); \ - PROC(BOSS_BIG_WARDER, boss-big-warder); \ - PROC(BOSS_GREEDY_SCIENTIST, boss-greedy-scientist); \ -} while (0) +/* generated enum utility */ +#include "core/loworld/benum/chunk.h" typedef struct { struct { @@ -44,18 +39,6 @@ typedef struct { CONTAINER_ARRAY loentity_t** entities; } loworld_chunk_t; -const char* -loworld_chunk_biome_stringify( - loworld_chunk_biome_t biome -); - -bool -loworld_chunk_biome_unstringify( - loworld_chunk_biome_t* biome, - const char* str, - size_t len -); - void loworld_chunk_initialize( loworld_chunk_t* chunk diff --git a/core/loworld/environment.c b/core/loworld/environment.c index 2068483..c6880aa 100644 --- a/core/loworld/environment.c +++ b/core/loworld/environment.c @@ -10,7 +10,6 @@ #include "core/locommon/easing.h" #include "core/locommon/ticker.h" -#include "core/loplayer/event.h" #include "core/loplayer/player.h" #include "core/loresource/music.h" #include "core/loresource/set.h" @@ -21,25 +20,8 @@ #include "./view.h" -static const char* loworld_environment_get_chunk_name_( - loresource_language_t lang, loworld_chunk_biome_t b) { - switch (b) { - case LOWORLD_CHUNK_BIOME_METAPHYSICAL_GATE: - return loresource_text_get(lang, "biome_metaphysical_gate"); - case LOWORLD_CHUNK_BIOME_CAVIAS_CAMP: - return loresource_text_get(lang, "biome_cavias_camp"); - case LOWORLD_CHUNK_BIOME_LABORATORY: - return loresource_text_get(lang, "biome_laboratory"); - case LOWORLD_CHUNK_BIOME_BOSS_THEISTS_CHILD: - return loresource_text_get(lang, "biome_boss_theists_child"); - case LOWORLD_CHUNK_BIOME_BOSS_BIG_WARDER: - return loresource_text_get(lang, "biome_boss_big_warder"); - case LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST: - return loresource_text_get(lang, "biome_boss_greedy_scientist"); - } - assert(false); - return "unknown biome"; -} +#define MUSIC_FADE_DURATION_ rational(1, 1) +#define MUSIC_EVENT_FADE_DURATION_ rational(1, 2) static loshader_backwall_type_t loworld_environment_get_backwall_type_( loworld_chunk_biome_t b) { @@ -57,8 +39,7 @@ static loshader_backwall_type_t loworld_environment_get_backwall_type_( case LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST: return LOSHADER_BACKWALL_TYPE_INFINITE_BOXES; } - assert(false); - return LOSHADER_BACKWALL_TYPE_WHITE; + __builtin_unreachable(); } static loshader_fog_type_t loworld_environment_get_fog_type_( @@ -72,47 +53,37 @@ static loshader_fog_type_t loworld_environment_get_fog_type_( case LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST: return LOSHADER_FOG_TYPE_WHITE_CLOUD; } - assert(false); - return LOSHADER_FOG_TYPE_NONE; + __builtin_unreachable(); } -static loresource_music_player_t* loworld_environment_get_music_( - loworld_chunk_biome_t b, loresource_music_t* m) { +static loresource_music_id_t loworld_environment_get_music_id_( + loworld_chunk_biome_t b) { switch (b) { case LOWORLD_CHUNK_BIOME_METAPHYSICAL_GATE: - return &m->biome_metaphysical_gate; + return LORESOURCE_MUSIC_ID_BIOME_METAPHYSICAL_GATE; case LOWORLD_CHUNK_BIOME_CAVIAS_CAMP: - return &m->biome_cavias_camp; + return LORESOURCE_MUSIC_ID_BIOME_CAVIAS_CAMP; case LOWORLD_CHUNK_BIOME_LABORATORY: - return &m->biome_laboratory; + return LORESOURCE_MUSIC_ID_BIOME_LABORATORY; case LOWORLD_CHUNK_BIOME_BOSS_THEISTS_CHILD: case LOWORLD_CHUNK_BIOME_BOSS_BIG_WARDER: case LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST: - return &m->biome_boss; + return LORESOURCE_MUSIC_ID_BIOME_BOSS; } - assert(false); - return NULL; + __builtin_unreachable(); } -static void loworld_environment_stop_music_(loworld_environment_t* env) { +static void loworld_environment_stop_music_( + loworld_environment_t* env, const rational_t* after) { assert(env != NULL); - if (env->music != NULL && env->music_control) { - jukebox_amp_change_volume(&env->music->amp, 0, &rational(1, 1)); - jukebox_decoder_stop_after(env->music->decoder, &rational(1, 1)); + + if (env->music != NULL) { + jukebox_amp_change_volume(&env->music->amp, 0, after); + jukebox_decoder_stop_after(env->music->decoder, after); } env->music = NULL; } -static void loworld_environment_update_hud_(loworld_environment_t* env) { - assert(env != NULL); - - if (env->transition > 0) return; - - loplayer_hud_set_biome_text( - env->player->hud, - loworld_environment_get_chunk_name_(env->res->lang, env->biome)); -} - static void loworld_environment_update_backwall_(loworld_environment_t* env) { assert(env != NULL); @@ -142,12 +113,11 @@ static void loworld_environment_update_fog_(loworld_environment_t* env) { env->fog.transition = env->transition; /* ---- bounds fog ---- */ - const loplayer_event_param_t* e = - loplayer_event_get_param(env->player->event); - if (e != NULL && vec2_pow_length(&e->area_size) > 0) { - env->fog.bounds_pos = e->area_pos; - env->fog.bounds_size = e->area_size; - + const locommon_position_t* pos = &env->player->event.ctx.area.pos; + const vec2_t* size = &env->player->event.ctx.area.size; + if (size->x > 0 && size->y > 0) { + env->fog.bounds_pos = *pos; + env->fog.bounds_size = *size; locommon_easing_smooth_float( &env->fog.bounds_fog, 1, env->ticker->delta_f); } else { @@ -159,39 +129,29 @@ static void loworld_environment_update_fog_(loworld_environment_t* env) { static void loworld_environment_update_music_(loworld_environment_t* env) { assert(env != NULL); - bool control = true; - loresource_music_player_t* music = - loworld_environment_get_music_(env->biome, &env->res->music); + const loplayer_event_context_t* ev = &env->player->event.ctx; - const loplayer_event_param_t* e = - loplayer_event_get_param(env->player->event); - if (e != NULL) { - music = e->music; - control = false; + loresource_music_t* music = env->music; + if (ev->music.enable) { + music = loresource_music_set_get(&env->res->music, ev->music.id); + if (music != env->music) { + loworld_environment_stop_music_(env, &MUSIC_EVENT_FADE_DURATION_); + jukebox_amp_change_volume(&music->amp, .9f, &MUSIC_EVENT_FADE_DURATION_); - if (!env->sound_attenuation) { - loresource_sound_change_master_volume( - env->res->sound, .2f, &rational(1, 1)); - env->sound_attenuation = true; + const uint64_t t = env->ticker->time - ev->music.since; + jukebox_decoder_play(music->decoder, &rational(t, 1000), true); } - } else { - if (env->sound_attenuation) { - loresource_sound_change_master_volume( - env->res->sound, 1, &rational(1, 1)); - env->sound_attenuation = false; - } - } + music = loresource_music_set_get( + &env->res->music, loworld_environment_get_music_id_(env->biome)); + if (music != env->music) { + loworld_environment_stop_music_(env, &MUSIC_FADE_DURATION_); + jukebox_amp_change_volume(&music->amp, .6f, &MUSIC_FADE_DURATION_); - if (music != env->music) { - loworld_environment_stop_music_(env); - env->music = music; - env->music_control = control; - if (env->music != NULL && env->music_control) { - jukebox_amp_change_volume(&env->music->amp, .6f, &rational(1, 1)); - jukebox_decoder_resume(env->music->decoder, true); + jukebox_decoder_resume(music->decoder, true); } } + env->music = music; } void loworld_environment_initialize( @@ -199,23 +159,23 @@ void loworld_environment_initialize( loresource_set_t* res, loshader_set_t* shaders, const locommon_ticker_t* ticker, + const loplayer_t* player, const loworld_view_t* view, - loplayer_t* player, const loworld_environment_config_t* config) { assert(env != NULL); assert(res != NULL); assert(shaders != NULL); assert(ticker != NULL); - assert(view != NULL); assert(player != NULL); + assert(view != NULL); assert(config != NULL); *env = (typeof(*env)) { .res = res, .shaders = shaders, .ticker = ticker, - .view = view, .player = player, + .view = view, .config = *config, }; @@ -224,7 +184,7 @@ void loworld_environment_initialize( void loworld_environment_deinitialize(loworld_environment_t* env) { assert(env != NULL); - loworld_environment_stop_music_(env); + loworld_environment_stop_music_(env, &rational(1, 10)); } void loworld_environment_update(loworld_environment_t* env) { @@ -236,7 +196,6 @@ void loworld_environment_update(loworld_environment_t* env) { env->biome = chunk->biome; env->transition = 0; } - loworld_environment_update_hud_(env); loworld_environment_update_backwall_(env); loworld_environment_update_fog_(env); loworld_environment_update_music_(env); @@ -248,7 +207,7 @@ void loworld_environment_draw(const loworld_environment_t* env) { assert(env != NULL); loshader_backwall_drawer_set_param( - env->shaders->drawer.backwall, &env->backwall); + &env->shaders->drawer.backwall, &env->backwall); loshader_fog_drawer_set_param( - env->shaders->drawer.fog, &env->fog); + &env->shaders->drawer.fog, &env->fog); } diff --git a/core/loworld/environment.h b/core/loworld/environment.h index 809aec9..4fb537d 100644 --- a/core/loworld/environment.h +++ b/core/loworld/environment.h @@ -21,8 +21,8 @@ typedef struct { loresource_set_t* res; loshader_set_t* shaders; const locommon_ticker_t* ticker; + const loplayer_t* player; const loworld_view_t* view; - loplayer_t* player; /* immutable params */ loworld_environment_config_t config; @@ -31,9 +31,7 @@ typedef struct { float transition; loworld_chunk_biome_t biome; - loresource_music_player_t* music; - bool music_control; - bool sound_attenuation; + loresource_music_t* music; loshader_backwall_drawer_param_t backwall; loshader_fog_drawer_param_t fog; @@ -45,8 +43,8 @@ loworld_environment_initialize( loresource_set_t* res, loshader_set_t* shaders, const locommon_ticker_t* ticker, + const loplayer_t* player, const loworld_view_t* view, - loplayer_t* player, const loworld_environment_config_t* config ); diff --git a/core/loworld/poolset.c b/core/loworld/poolset.c index eb26abb..6b15841 100644 --- a/core/loworld/poolset.c +++ b/core/loworld/poolset.c @@ -7,10 +7,80 @@ #include #include "core/lobullet/pool.h" -#include "core/locharacter/pool.h" +#include "core/lochara/pool.h" +#include "core/locommon/counter.h" +#include "core/locommon/ticker.h" +#include "core/loentity/store.h" #include "core/loground/pool.h" +#include "core/loparticle/pool.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" -#include "./test.h" +#define GROUNDS_PER_CHUNK_ 16 +#define PARTICLES_PER_CHUNK_ 16 +#define BULLETS_PER_CHUNK_ 64 +#define CHARACTERS_PER_CHUNK_ 16 + +void loworld_poolset_initialize( + loworld_poolset_t* pools, + loresource_set_t* res, + loshader_set_t* shaders, + locommon_counter_t* idgen, + const locommon_ticker_t* ticker, + loentity_store_t* entities, + loplayer_t* player, + size_t max_chunks) { + assert(pools != NULL); + assert(res != NULL); + assert(shaders != NULL); + assert(idgen != NULL); + assert(ticker != NULL); + assert(entities != NULL); + assert(player != NULL); + assert(max_chunks > 0); + + *pools = (typeof(*pools)) {0}; + + pools->ground = loground_pool_new( + &shaders->drawer.ground, + idgen, + max_chunks*GROUNDS_PER_CHUNK_); + + pools->particle = loparticle_pool_new( + &shaders->drawer.particle, + idgen, + ticker, + entities, + max_chunks*PARTICLES_PER_CHUNK_); + + pools->bullet = lobullet_pool_new( + res, + shaders, + idgen, + ticker, + entities, + max_chunks*BULLETS_PER_CHUNK_); + + pools->chara = lochara_pool_new( + res, + shaders, + idgen, + ticker, + entities, + player, + pools->bullet, + max_chunks*CHARACTERS_PER_CHUNK_); +} + +void loworld_poolset_deinitialize(loworld_poolset_t* pools) { + assert(pools != NULL); + + lochara_pool_delete(pools->chara); + lobullet_pool_delete(pools->bullet); + loparticle_pool_delete(pools->particle); + loground_pool_delete(pools->ground); +} loentity_t* loworld_poolset_unpack_entity( const loworld_poolset_t* pools, const msgpack_object* obj) { @@ -22,17 +92,14 @@ loentity_t* loworld_poolset_unpack_entity( e = (typeof(e)) loground_pool_unpack_item(pools->ground, obj); if (e != NULL) return e; + e = (typeof(e)) loparticle_pool_unpack_item(pools->particle, obj); + if (e != NULL) return e; + e = (typeof(e)) lobullet_pool_unpack_item(pools->bullet, obj); if (e != NULL) return e; - e = (typeof(e)) locharacter_pool_unpack_item(pools->character, obj); + e = (typeof(e)) lochara_pool_unpack_item(pools->chara, obj); if (e != NULL) return e; return NULL; } - -void loworld_poolset_test_packing(const loworld_poolset_t* pools) { - assert(pools != NULL); - - loworld_test_packing(pools); -} diff --git a/core/loworld/poolset.h b/core/loworld/poolset.h index 515ec01..fac1764 100644 --- a/core/loworld/poolset.h +++ b/core/loworld/poolset.h @@ -5,25 +5,42 @@ #include #include "core/lobullet/pool.h" -#include "core/locharacter/pool.h" +#include "core/lochara/pool.h" +#include "core/locommon/counter.h" +#include "core/locommon/ticker.h" +#include "core/loentity/store.h" #include "core/loground/pool.h" +#include "core/loparticle/pool.h" +#include "core/loplayer/player.h" +#include "core/loresource/set.h" +#include "core/loshader/set.h" typedef struct { loground_pool_t* ground; + loparticle_pool_t* particle; lobullet_pool_t* bullet; - locharacter_pool_t* character; + lochara_pool_t* chara; } loworld_poolset_t; -/* Initialize and Deinitialize each member manually - * because of a dependency issue. */ +void +loworld_poolset_initialize( + loworld_poolset_t* pools, + loresource_set_t* res, + loshader_set_t* shaders, + locommon_counter_t* idgen, + const locommon_ticker_t* ticker, + loentity_store_t* entities, + loplayer_t* player, + size_t max_chunks +); + +void +loworld_poolset_deinitialize( + loworld_poolset_t* pools +); loentity_t* /* NULLABLE/OWNERSHIP */ loworld_poolset_unpack_entity( const loworld_poolset_t* pools, const msgpack_object* obj ); - -void -loworld_poolset_test_packing( - const loworld_poolset_t* pools -); diff --git a/core/loworld/store.c b/core/loworld/store.c index 4c13d33..551c88c 100644 --- a/core/loworld/store.c +++ b/core/loworld/store.c @@ -12,6 +12,7 @@ #include #include +#include "util/flasy/flasy.h" #include "util/memory/memory.h" #include "util/mpkutil/file.h" @@ -35,6 +36,7 @@ struct loworld_store_t { char path[LOWORLD_STORE_PATH_MAX_LENGTH+LOWORLD_CHUNK_FILENAME_MAX]; size_t basepath_length; + flasy_t* flasy; const loworld_poolset_t* pools; const loworld_generator_t* generator; @@ -135,7 +137,7 @@ static bool loworld_store_save_chunk_to_file_( loworld_store_build_chunk_filename_(store, chunk); - FILE* fp = fopen(store->path, "wb"); + FILE* fp = flasy_open_file(store->flasy, store->path, true); if (fp == NULL) return false; msgpack_packer packer; @@ -144,16 +146,18 @@ static bool loworld_store_save_chunk_to_file_( loworld_chunk_pack(chunk, &packer); const bool success = (ferror(fp) == 0); - fclose(fp); + flasy_close_file(store->flasy, fp); return success; } loworld_store_t* loworld_store_new( + flasy_t* flasy, const loworld_poolset_t* pools, const loworld_generator_t* generator, size_t chunks_length, const char* basepath, size_t basepath_length) { + assert(flasy != NULL); assert(pools != NULL); assert(generator != NULL); assert(chunks_length > 0); @@ -167,6 +171,7 @@ loworld_store_t* loworld_store_new( sizeof(*store) + (chunks_length-1)*sizeof(store->chunks[0])); *store = (typeof(*store)) { .basepath_length = basepath_length, + .flasy = flasy, .pools = pools, .generator = generator, .chunks_length = chunks_length, diff --git a/core/loworld/store.h b/core/loworld/store.h index 0b5cbd0..2c9619b 100644 --- a/core/loworld/store.h +++ b/core/loworld/store.h @@ -4,6 +4,8 @@ #include #include +#include "util/flasy/flasy.h" + #include "./chunk.h" #include "./generator.h" #include "./poolset.h" @@ -14,6 +16,7 @@ typedef struct loworld_store_t loworld_store_t; /* TODO(catfoot): make it possible to specify a path to chunk dir */ loworld_store_t* /* OWNERSHIP */ loworld_store_new( + flasy_t* flasy, const loworld_poolset_t* pools, const loworld_generator_t* gen, size_t chunks_length, diff --git a/core/loworld/template.c b/core/loworld/template.c index f85a4fd..7d73a36 100644 --- a/core/loworld/template.c +++ b/core/loworld/template.c @@ -8,23 +8,22 @@ #include "util/math/algorithm.h" #include "util/math/vector.h" -#include "core/locharacter/base.h" -#include "core/locharacter/big_warder.h" -#include "core/locharacter/cavia.h" -#include "core/locharacter/encephalon.h" -#include "core/locharacter/scientist.h" -#include "core/locharacter/greedy_scientist.h" -#include "core/locharacter/theists_child.h" -#include "core/locharacter/warder.h" +#include "core/lochara/base.h" +#include "core/lochara/big_warder.h" +#include "core/lochara/cavia.h" +#include "core/lochara/encephalon.h" +#include "core/lochara/theists_child.h" +#include "core/lochara/warder.h" #include "core/locommon/position.h" #include "core/loentity/entity.h" +#include "core/loentity/ground.h" #include "core/loground/base.h" #include "core/loground/island.h" #include "./chunk.h" #include "./poolset.h" -static loentity_id_t loworld_template_add_ground_island_( +static loentity_ground_t* loworld_template_add_ground_island_( const loworld_template_building_param_t* param, const vec2_t* pos, const vec2_t* sz) { @@ -39,46 +38,30 @@ static loentity_id_t loworld_template_add_ground_island_( loground_base_t* island = loground_pool_create(param->pools->ground); loground_island_build(island, &p, sz); loworld_chunk_add_entity(param->target, &island->super.super); - return island->super.super.id; + return &island->super; } -static loentity_id_t loworld_template_add_character_random_enemy_( +static void loworld_template_add_random_enemy_( const loworld_template_building_param_t* param, uint64_t seed, - loentity_id_t ground, + const loentity_ground_t* gnd, float pos) { - assert(param != NULL); + assert(loworld_template_building_param_valid(param)); + assert(gnd != NULL); + assert(MATH_FLOAT_VALID(pos)); - locharacter_base_t* base = locharacter_pool_create(param->pools->character); + static void (*const builders[])( + lochara_base_t*, const loentity_ground_t*, float) = { + lochara_cavia_build, + lochara_warder_build, + }; + + lochara_base_t* base = lochara_pool_create(param->pools->chara); + + const size_t i = chaos_xorshift(seed)%(sizeof(builders)/sizeof(builders[0])); + builders[i](base, gnd, pos); - bool built = false; - const uint64_t type = (seed = chaos_xorshift(seed))%3; - switch (type) { - case 1: - locharacter_warder_build(base, &(locharacter_warder_param_t) { - .ground = ground, - .pos = pos, - }); - built = true; - break; - case 2: - locharacter_scientist_build(base, &(locharacter_scientist_param_t) { - .ground = ground, - .pos = pos, - .direction = (seed = chaos_xorshift(seed))%2? 1: -1, - }); - built = true; - break; - } - if (!built) { - locharacter_cavia_build(base, &(locharacter_cavia_param_t) { - .ground = ground, - .pos = pos, - .direction = (seed = chaos_xorshift(seed))%2? 1: -1, - }); - } loworld_chunk_add_entity(param->target, &base->super.super); - return base->super.super.id; } bool loworld_template_building_param_valid( @@ -93,15 +76,13 @@ void loworld_template_metaphysical_gate_build_chunk( const loworld_template_building_param_t* param) { assert(loworld_template_building_param_valid(param)); - loworld_template_add_ground_island_( - param, &vec2(.5f, .2f), &vec2(.5f, .1f)); + loworld_template_add_ground_island_(param, &vec2(.5f, .2f), &vec2(.5f, .1f)); - const loentity_id_t ground = loworld_template_add_ground_island_( + const loentity_ground_t* platform = loworld_template_add_ground_island_( param, &vec2(.5f, .45f), &vec2(.2f, .02f)); - locharacter_base_t* encephalon = - locharacter_pool_create(param->pools->character); - locharacter_encephalon_build(encephalon, ground); + lochara_base_t* encephalon = lochara_pool_create(param->pools->chara); + lochara_encephalon_build(encephalon, platform); loworld_chunk_add_entity(param->target, &encephalon->super.super); } @@ -113,12 +94,12 @@ void loworld_template_open_space_build_chunk( const size_t enemy_count = (s = chaos_xorshift(s))%3+1; - const loentity_id_t ground = loworld_template_add_ground_island_( + const loentity_ground_t* gnd = loworld_template_add_ground_island_( param, &vec2(.5f, .2f), &vec2(.47f, .01f)); for (size_t i = 0; i < enemy_count; ++i) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), ground, (2.0f/enemy_count*i - 1)*.75f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), gnd, .1f+.8f/enemy_count*i); } } @@ -128,18 +109,18 @@ void loworld_template_broken_open_space_build_chunk( uint64_t s = param->seed; - const loentity_id_t floor1 = loworld_template_add_ground_island_( + const loentity_ground_t* floor1 = loworld_template_add_ground_island_( param, &vec2(.2f, .2f), &vec2(.18f, .01f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), floor1, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), floor1, .5f); } - const loentity_id_t floor2 = loworld_template_add_ground_island_( + const loentity_ground_t* floor2 = loworld_template_add_ground_island_( param, &vec2(.8f, .2f), &vec2(.18f, .01f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), floor2, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), floor2, .5f); } loworld_template_add_ground_island_( @@ -152,18 +133,18 @@ void loworld_template_passage_build_chunk( uint64_t s = param->seed; - const loentity_id_t floor = loworld_template_add_ground_island_( + const loentity_ground_t* floor = loworld_template_add_ground_island_( param, &vec2(.5f, .25f), &vec2(.5f, .01f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), floor, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), floor, .5f); } - const loentity_id_t ceiling = loworld_template_add_ground_island_( + const loentity_ground_t* ceiling = loworld_template_add_ground_island_( param, &vec2(.55f, .4f), &vec2(.3f, .007f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), ceiling, .2f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), ceiling, .5f); } } @@ -173,42 +154,42 @@ void loworld_template_broken_passage_build_chunk( uint64_t s = param->seed; - const loentity_id_t floor1 = loworld_template_add_ground_island_( + const loentity_ground_t* floor1 = loworld_template_add_ground_island_( param, &vec2(.15f, .25f), &vec2(.15f, .01f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), floor1, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), floor1, .5f); } - const loentity_id_t floor2 = loworld_template_add_ground_island_( + const loentity_ground_t* floor2 = loworld_template_add_ground_island_( param, &vec2(.45f, .25f), &vec2(.1f, .01f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), floor2, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), floor2, .5f); } - const loentity_id_t floor3 = loworld_template_add_ground_island_( + const loentity_ground_t* floor3 = loworld_template_add_ground_island_( param, &vec2(.85f, .25f), &vec2(.15f, .01f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), floor3, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), floor3, .5f); } const uint64_t layout = (s = chaos_xorshift(s))%3; if (layout == 0 || layout == 1) { - const loentity_id_t ceiling = loworld_template_add_ground_island_( + const loentity_ground_t* ceiling = loworld_template_add_ground_island_( param, &vec2(.2f, .4f), &vec2(.15f, .007f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), ceiling, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), ceiling, .5f); } } if (layout == 0 || layout == 2) { - const loentity_id_t ceiling = loworld_template_add_ground_island_( + const loentity_ground_t* ceiling = loworld_template_add_ground_island_( param, &vec2(.7f, .38f), &vec2(.12f, .007f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), ceiling, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), ceiling, .5f); } } } @@ -219,34 +200,34 @@ void loworld_template_stairs_build_chunk( uint64_t s = param->seed; - const loentity_id_t floor1 = loworld_template_add_ground_island_( + const loentity_ground_t* floor1 = loworld_template_add_ground_island_( param, &vec2(.5f, .3f), &vec2(.5f, .015f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), floor1, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), floor1, .5f); } bool layout = (s = chaos_xorshift(s))%2; - const loentity_id_t floor2 = loworld_template_add_ground_island_( + const loentity_ground_t* floor2 = loworld_template_add_ground_island_( param, &vec2(layout? .3f: .6f, .5f), &vec2(.2f, .015f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), floor2, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), floor2, .5f); } layout = !layout; - const loentity_id_t floor3 = loworld_template_add_ground_island_( + const loentity_ground_t* floor3 = loworld_template_add_ground_island_( param, &vec2(layout? .2f: .8f, .7f), &vec2(.18f, .007f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), floor3, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), floor3, .5f); } - const loentity_id_t floor4 = loworld_template_add_ground_island_( + const loentity_ground_t* floor4 = loworld_template_add_ground_island_( param, &vec2(.5f, .9f), &vec2(.32f, .007f)); if ((s = chaos_xorshift(s))%2) { - loworld_template_add_character_random_enemy_( - param, (s = chaos_xorshift(s)), floor4, .5f); + loworld_template_add_random_enemy_( + param, s = chaos_xorshift(s), floor4, .5f); } } @@ -254,11 +235,11 @@ void loworld_template_boss_theists_child_build_chunk( const loworld_template_building_param_t* param) { assert(loworld_template_building_param_valid(param)); - const loentity_id_t ground = loworld_template_add_ground_island_( + loentity_ground_t* gnd = loworld_template_add_ground_island_( param, &vec2(.5f, .1f), &vec2(.5f, .05f)); - locharacter_base_t* boss = locharacter_pool_create(param->pools->character); - locharacter_theists_child_build(boss, ground); + lochara_base_t* boss = lochara_pool_create(param->pools->chara); + lochara_theists_child_build(boss, gnd); loworld_chunk_add_entity(param->target, &boss->super.super); } @@ -266,11 +247,11 @@ void loworld_template_boss_big_warder_build_chunk( const loworld_template_building_param_t* param) { assert(loworld_template_building_param_valid(param)); - const loentity_id_t ground = loworld_template_add_ground_island_( + loentity_ground_t* gnd = loworld_template_add_ground_island_( param, &vec2(.5f, .1f), &vec2(.5f, .05f)); - locharacter_base_t* boss = locharacter_pool_create(param->pools->character); - locharacter_big_warder_build(boss, ground); + lochara_base_t* boss = lochara_pool_create(param->pools->chara); + lochara_big_warder_build(boss, gnd); loworld_chunk_add_entity(param->target, &boss->super.super); } @@ -278,10 +259,7 @@ void loworld_template_boss_greedy_scientist_build_chunk( const loworld_template_building_param_t* param) { assert(loworld_template_building_param_valid(param)); - const loentity_id_t ground = loworld_template_add_ground_island_( + const loentity_ground_t* ground = loworld_template_add_ground_island_( param, &vec2(.5f, .1f), &vec2(.5f, .05f)); - - locharacter_base_t* boss = locharacter_pool_create(param->pools->character); - locharacter_greedy_scientist_build(boss, ground); - loworld_chunk_add_entity(param->target, &boss->super.super); + (void) ground; } diff --git a/core/loworld/test.h b/core/loworld/test.h deleted file mode 100644 index b88be43..0000000 --- a/core/loworld/test.h +++ /dev/null @@ -1,146 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -#include "core/lobullet/base.h" -#include "core/lobullet/bomb.h" -#include "core/lobullet/linear.h" -#include "core/locharacter/base.h" -#include "core/locharacter/big_warder.h" -#include "core/locharacter/cavia.h" -#include "core/locharacter/encephalon.h" -#include "core/locharacter/greedy_scientist.h" -#include "core/locharacter/theists_child.h" -#include "core/locharacter/scientist.h" -#include "core/locharacter/warder.h" -#include "core/locharacter/pool.h" -#include "core/loentity/entity.h" -#include "core/loground/base.h" -#include "core/loground/island.h" -#include "core/loground/pool.h" - -#include "./poolset.h" - -# define pack_and_unpack_(type, name) do { \ - msgpack_sbuffer_clear(buf); \ - loentity_pack(&base->super.super, &packer); \ - loentity_delete(&base->super.super); \ - \ - size_t offset = 0; \ - const msgpack_unpack_return r = \ - msgpack_unpack_next(upk, buf->data, buf->size, &offset); \ - if (r != MSGPACK_UNPACK_SUCCESS) { \ - fprintf(stderr, #type"_"#name": invalid msgpack format\n"); \ - abort(); \ - } \ - if (!type##_base_unpack(base, &upk->data)) { \ - fprintf(stderr, #type"_"#name": failed to unpack\n"); \ - abort(); \ - } \ - loentity_delete(&base->super.super); \ - printf(#type"_"#name": pack test passed\n"); \ - } while (0) - -static inline void loworld_test_packing_grounds( - loground_base_t* base, msgpack_sbuffer* buf, msgpack_unpacked* upk) { - assert(base != NULL); - assert(buf != NULL); - assert(upk != NULL); - - msgpack_packer packer; - msgpack_packer_init(&packer, buf, msgpack_sbuffer_write); - - loground_island_build( - base, &locommon_position(0, 0, vec2(0, 0)), &vec2(1, 1)); - pack_and_unpack_(loground, island); -} - -static inline void loworld_test_packing_bullets( - lobullet_base_t* base, msgpack_sbuffer* buf, msgpack_unpacked* upk) { - assert(base != NULL); - assert(buf != NULL); - assert(upk != NULL); - - msgpack_packer packer; - msgpack_packer_init(&packer, buf, msgpack_sbuffer_write); - - lobullet_bomb_square_build( - base, &((lobullet_bomb_param_t) { .step = 1, })); - pack_and_unpack_(lobullet, bomb); - - lobullet_bomb_triangle_build( - base, &((lobullet_bomb_param_t) { .step = 1, })); - pack_and_unpack_(lobullet, bomb); - - lobullet_linear_light_build( - base, &((lobullet_linear_param_t) { .duration = 1, })); - pack_and_unpack_(lobullet, linear); - - lobullet_linear_triangle_build( - base, &((lobullet_linear_param_t) { .duration = 1, })); - pack_and_unpack_(lobullet, linear); -} - -static inline void loworld_test_packing_characters( - locharacter_base_t* base, msgpack_sbuffer* buf, msgpack_unpacked* upk) { - assert(base != NULL); - assert(buf != NULL); - assert(upk != NULL); - - msgpack_packer packer; - msgpack_packer_init(&packer, buf, msgpack_sbuffer_write); - - locharacter_big_warder_build(base, 0); - pack_and_unpack_(locharacter, big_warder); - - locharacter_cavia_build( - base, &((locharacter_cavia_param_t) { .direction = 1, })); - pack_and_unpack_(locharacter, cavia); - - locharacter_encephalon_build(base, 0); - pack_and_unpack_(locharacter, encephalon); - - locharacter_theists_child_build(base, 0); - pack_and_unpack_(locharacter, theists_child); - - locharacter_greedy_scientist_build(base, 0); - pack_and_unpack_(locharacter, greedy_scientist); - - locharacter_scientist_build(base, &((locharacter_scientist_param_t) {0})); - pack_and_unpack_(locharacter, scientist); - - locharacter_warder_build(base, &((locharacter_warder_param_t) {0})); - pack_and_unpack_(locharacter, warder); -} - -# undef pack_and_unpack_ - -static inline void loworld_test_packing(const loworld_poolset_t* pools) { - assert(pools != NULL); - - msgpack_sbuffer buf; - msgpack_sbuffer_init(&buf); - - msgpack_unpacked upk; - msgpack_unpacked_init(&upk); - - loground_base_t* ground = loground_pool_create(pools->ground); - loworld_test_packing_grounds(ground, &buf, &upk); - loentity_delete(&ground->super.super); - - lobullet_base_t* bullet = lobullet_pool_create(pools->bullet); - loworld_test_packing_bullets(bullet, &buf, &upk); - loentity_delete(&bullet->super.super); - - locharacter_base_t* chara = locharacter_pool_create(pools->character); - loworld_test_packing_characters(chara, &buf, &upk); - loentity_delete(&chara->super.super); - - msgpack_unpacked_destroy(&upk); - msgpack_sbuffer_destroy(&buf); -} diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 8ffbfdd..71deff1 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,2 +1,7 @@ +set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + set(BUILD_TESTING OFF) +set(TINYCTHREAD_DISABLE_TESTS ON) + add_subdirectory(miniaudio) +add_subdirectory(tinycthread) diff --git a/thirdparty/miniaudio/CMakeLists.txt b/thirdparty/miniaudio/CMakeLists.txt index a3fa401..026d387 100644 --- a/thirdparty/miniaudio/CMakeLists.txt +++ b/thirdparty/miniaudio/CMakeLists.txt @@ -1,5 +1,24 @@ +project(miniaudio C) + +set_source_files_properties(repo/miniaudio.h + DIRECTORY . + PROPERTIES + LANGUAGE C + COMPILE_FLAGS "-x c" +) add_library(miniaudio - miniaudio.c + repo/miniaudio.h +) +target_compile_definitions(miniaudio + PRIVATE + MINIAUDIO_IMPLEMENTATION + PUBLIC + MA_NO_ENCODING + MA_NO_FLAC + $<$:MA_DEBUG_OUTPUT> +) +target_include_directories(miniaudio + SYSTEM INTERFACE repo ) target_link_libraries(miniaudio $<$:dl> diff --git a/thirdparty/miniaudio/miniaudio.c b/thirdparty/miniaudio/miniaudio.c deleted file mode 100644 index a765e3a..0000000 --- a/thirdparty/miniaudio/miniaudio.c +++ /dev/null @@ -1,2 +0,0 @@ -#define MINIAUDIO_IMPLEMENTATION -#include "./miniaudio.h" diff --git a/thirdparty/miniaudio/miniaudio.h b/thirdparty/miniaudio/miniaudio.h deleted file mode 100644 index e3ac273..0000000 --- a/thirdparty/miniaudio/miniaudio.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#define MA_NO_ENCODING -#define MA_NO_FLAC - -#ifndef NDEBUG -# define MA_DEBUG_OUTPUT -#endif /* NDEBUG */ - -#include "./repo/miniaudio.h" diff --git a/thirdparty/tinycthread b/thirdparty/tinycthread new file mode 160000 index 0000000..6957fc8 --- /dev/null +++ b/thirdparty/tinycthread @@ -0,0 +1 @@ +Subproject commit 6957fc8383d6c7db25b60b8c849b29caab1caaee diff --git a/tool/benum.sh b/tool/benum.sh new file mode 100755 index 0000000..e0e325c --- /dev/null +++ b/tool/benum.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +set -eu + +if [[ -z ${1+x} || -z ${2+x} ]]; then + echo "usage: cat | ./benum.sh
" + exit 1 +fi + +DSTPATH="$1" +DSTDIR=$(dirname "$DSTPATH") + +HEADERPATH="$2" + +if [[ $DSTPATH =~ /$ ]]; then + echo "destination path must be a filename without extension" >&2 + exit 1 +fi +if [[ ! -d $DSTDIR ]]; then + echo "no such directory: $DSTDIR" >&2 + exit 1 +fi + +preprocess=$(cat << EOS + +s|^\s*|| +s|\s*$|| + +/^\/\* *BENUM *BEGIN.*\*\/$/,/^\/\* *BENUM *END *\*\/$/ ! d +/^\/\* *BENUM *BEGIN.*\*\/$/ { + s|^\/\* *BENUM *BEGIN *([^ ]*) *\*\/$|^\1| + p + s|.||g + x + b +} +/^\/\* *BENUM *END *\*\/$/ { + x + s|\s||g + s|,|\\n|g + s|\\n\\n*|\\n|g + s|^\\n|| + s|\\n$|| + p; b +} + +H + +EOS +) + +header=$(cat << EOS +#include +#include +EOS +) +src=$(cat << EOS +#include "$HEADERPATH" + +#include +#include +#include +#include +EOS +) + +name= +NAME= + +list=() + +output_header() { + if [[ -z $name ]]; then return; fi + + cat << EOS + +#define ${NAME}_EACH(PROC) do { \\ + $(for item in ${list[@]}; do + echo "PROC($item, ${item,,}); \\" + done) +} while (0) + +#define ${NAME}_COUNT ${#list[@]} + +const char* ${name}_stringify(${name}_t v); +bool ${name}_unstringify(${name}_t* v, const char* str, size_t len); + +EOS +} +output_source() { + if [[ -z $name ]]; then return; fi + + cat << EOS + +const char* ${name}_stringify(${name}_t v) { + switch (v) { + $(for item in ${list[@]}; do + echo "case ${NAME}_$item: return \"$item\";" + done) + } + assert(false); + return NULL; +} +bool ${name}_unstringify(${name}_t* v, const char* str, size_t len) { + assert(v != NULL); + assert(str != NULL || len == 0); + $(for item in ${list[@]}; do + echo "if (len == ${#item} && strncmp(str, \"$item\", len) == 0) {" + echo " *v = ${NAME}_$item;" + echo " return true;" + echo "}" + done) + return false; +} + +EOS +} +output() { + header+=$(output_header) + src+=$(output_source) +} + +while read line; do + if [[ $line =~ ^\^(.*)$ ]]; then + output + name="${BASH_REMATCH[1]}" + name="${name,,}" + NAME="${name^^}" + list=() + else + if [[ ! $line =~ ^${NAME}_(.*)$ ]]; then + echo invalid naming rule: "$line" >&2 + exit 1 + fi + list+=(${BASH_REMATCH[1]}) + fi +done < <(cat | sed -r -n "$preprocess") +output + +echo "$header" > "$DSTPATH.h" +echo "$src" > "$DSTPATH.c" diff --git a/tool/bin2c.sh b/tool/bin2c.sh index 83a1d28..c82b183 100755 --- a/tool/bin2c.sh +++ b/tool/bin2c.sh @@ -1,14 +1,19 @@ -#!/bin/sh +#!/bin/bash -set -e +set -eu -name=`echo "$1" | sed -e 's/[^A-z0-9_]/_/g'` +if [[ -z ${1+x} || -z ${2+x} ]]; then + echo "usage: cat | ./bin2c.sh " + exit 1 +fi + +name=$(sed -e 's/[^A-z0-9_]/_/g' <<< "$1") hpath="$2.h" cpath="$2.c" -data=`cat $in | xxd -i` -size=`echo $data | wc -w` +data=$(cat - | xxd -i) +size=$(wc -w <<< "$data") echo "const char $name[$size] = {$data};" > $cpath echo "extern const char $name[$size];" > $hpath diff --git a/tool/crial.sh b/tool/crial.sh new file mode 100755 index 0000000..a1f2153 --- /dev/null +++ b/tool/crial.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +set -eu + +DEFAULT_SERIALIZER="${DEFAULT_SERIALIZER:-}" +DEFAULT_DESERIALIZER="${DEFAULT_DESERIALIZER:-}" + +preproc=$(cat << EOS + +s|^\s*(.*)\s*$|\1| + +/^\/\*\s*CRIAL\s*$/, /^\*\/$/ ! d + +/^\/\*\s*CRIAL\s*$/ d +/^\*\/$/ d + +EOS +) + +seq= +part_serializer="$DEFAULT_SERIALIZER" +part_deserializer="$DEFAULT_DESERIALIZER" + +serializer= +deserializer= + +last_name= +count=0 + +add_property() { + name=$(awk -F ' ' '{print $1}' <<< "$1") + code=$(awk -F ' ' '{print $1}' <<< "$2") + + local s="$part_serializer" + local d="$part_deserializer" + + s=${s//\$name/$name} + d=${d//\$name/$name} + s=${s//\$code/$code} + d=${d//\$code/$code} + + serializer+="do { $s } while (0);" + deserializer+="do { $d } while (0);" + + (( ++count )) +} + +while IFS=$'\n' read line; do + if [[ ! $line ]]; then continue; fi + + case $seq in + serializer) + if [[ $line == "END" ]]; then + seq= + else + part_serializer+="$line" + fi + ;; + deserializer) + if [[ $line == "END" ]]; then + seq= + else + part_deserializer+="$line" + fi + ;; + *) + if [[ $line =~ ^# ]]; then + : + elif [[ $line =~ ^SERIALIZER_BEGIN$ ]]; then + seq="serializer" + part_serializer= + elif [[ $line =~ ^DESERIALIZER_BEGIN$ ]]; then + seq="deserializer" + part_deserializer= + elif [[ $line =~ ^PROPERTY[[:blank:]](.*)=(.*)$ ]]; then + add_property "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" + elif [[ $line =~ ^PROPERTY[[:blank:]](.*)$ ]]; then + add_property "${BASH_REMATCH[1]}" "${BASH_REMATCH[1]}" + else + echo crial syntax error + exit 1 + fi + ;; + esac +done < <(cat - | sed -r "$preproc") + +echo "#define CRIAL_PROPERTY_COUNT_ $count" +echo "#define CRIAL_SERIALIZER_ do { $serializer } while (0)" +echo "#define CRIAL_DESERIALIZER_ do { $deserializer } while (0)" diff --git a/tool/leak-check.sh b/tool/leak-check.sh index c73c62e..3b197c2 100755 --- a/tool/leak-check.sh +++ b/tool/leak-check.sh @@ -1,35 +1,31 @@ -#!/bin/sh +#!/bin/bash -# This script works only with memory-trace file generated in Linux. +set -eu file="memory-trace" -if [ ! -f $file ]; then +if [[ ! -f $file ]]; then echo no memory trace file found exit 1 fi declare -A addrs -while read line; do - IFS=" " read -r type addr1 trash1 addr2 trash2 <<< $line - +while IFS=$' \n' read -r type addr1 dummy1_ addr2 dummy2_; do case "$type" in "new") - addrs[$addr1]="allocated" + addrs[$addr1]=1 ;; "resize") - addrs[$addr1]="freed" - addrs[$addr2]="allocated" + unset addrs[$addr1] ;; "delete") - addrs[$addr1]="freed" + unset addrs[$addr1] + ;; + *) ;; - *) ;; esac done < $file for addr in "${!addrs[@]}"; do - if [ "${addrs[$addr]}" == "allocated" ]; then - echo $addr - fi + echo $addr done diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 7e72637..5deace1 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -1,8 +1,11 @@ +add_compile_options(${LEFTONE_C_FLAGS}) + add_subdirectory(chaos) add_subdirectory(coly2d) add_subdirectory(container) add_subdirectory(conv) add_subdirectory(dictres) +add_subdirectory(flasy) add_subdirectory(gleasy) add_subdirectory(glyphas) add_subdirectory(jukebox) @@ -10,3 +13,4 @@ add_subdirectory(math) add_subdirectory(memory) add_subdirectory(mpkutil) add_subdirectory(parsarg) +add_subdirectory(statman) diff --git a/util/flasy/CMakeLists.txt b/util/flasy/CMakeLists.txt new file mode 100644 index 0000000..c996695 --- /dev/null +++ b/util/flasy/CMakeLists.txt @@ -0,0 +1,18 @@ +add_library(flasy + flasy.c +) +target_link_libraries(flasy + memory + tinycthread +) +if (BUILD_TESTING) + add_executable(flasy-test test.c) + target_link_libraries(flasy-test flasy) + + set(workdir "${CMAKE_CURRENT_BINARY_DIR}/test") + file(MAKE_DIRECTORY ${workdir}) + add_test( + NAME flasy-test + COMMAND bash -c "../flasy-test $(seq 9)" + WORKING_DIRECTORY ${workdir}) +endif() diff --git a/util/flasy/README.md b/util/flasy/README.md new file mode 100644 index 0000000..3bfb620 --- /dev/null +++ b/util/flasy/README.md @@ -0,0 +1,4 @@ +filasy +==== + +ASYnc file FLusher diff --git a/util/flasy/flasy.c b/util/flasy/flasy.c new file mode 100644 index 0000000..fb43963 --- /dev/null +++ b/util/flasy/flasy.c @@ -0,0 +1,146 @@ +#include "./flasy.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "util/memory/memory.h" + +typedef struct { + atomic_uintptr_t fp; + atomic_bool request_flush; + uint8_t buf[1]; +} flasy_handler_t; + +struct flasy_t { + mtx_t mtx; + thrd_t thread; + + size_t bufsz; + + atomic_bool alive; + + size_t length; + uint8_t handlers[1]; +}; + +static int flasy_main_(void* srv_) { + assert(srv_ != NULL); + flasy_t* srv = srv_; + + const size_t hsize = srv->bufsz + offsetof(flasy_handler_t, buf); + uint8_t* end = srv->handlers + hsize*srv->length; + + for (;;) { + const bool alive = atomic_load(&srv->alive); + + for (uint8_t* itr = srv->handlers; itr < end; itr += hsize) { + flasy_handler_t* handler = (typeof(handler)) itr; + + FILE* fp = (typeof(fp)) atomic_load(&handler->fp); + if (fp != NULL && atomic_load(&handler->request_flush)) { + /* while request_flush is true and fp isn't NULL, + no other thread modifies the handler */ + fclose(fp); + atomic_store(&handler->fp, 0); + } + } + thrd_sleep(&(struct timespec) { + .tv_sec = 0, + .tv_nsec = 10000000, /* = 10 ms */ + }, NULL); + + if (!alive) break; + } + return EXIT_SUCCESS; +} + +flasy_t* flasy_new(size_t bufsz, size_t hlen) { + assert(bufsz > 0); + assert(hlen > 0); + + const size_t hsize = bufsz + offsetof(flasy_handler_t, buf); + + flasy_t* srv = memory_new(sizeof(*srv) + hlen*hsize - 1); + *srv = (typeof(*srv)) { + .bufsz = bufsz, + .length = hlen, + }; + + atomic_store(&srv->alive, true); + + uint8_t* itr = srv->handlers; + for (size_t i = 0; i < srv->length; ++i) { + atomic_init(&((flasy_handler_t*) itr)->fp, 0); + itr += hsize; + } + + if (mtx_init(&srv->mtx, mtx_plain) != thrd_success) { + fprintf(stderr, "flasy: failed to create mutex\n"); + abort(); + } + if (thrd_create(&srv->thread, &flasy_main_, srv) != thrd_success) { + fprintf(stderr, "flasy: failed to create thread\n"); + abort(); + } + return srv; +} + +void flasy_delete(flasy_t* srv) { + if (srv == NULL) return; + + atomic_store(&srv->alive, false); + thrd_join(srv->thread, NULL); + + mtx_destroy(&srv->mtx); + + memory_delete(srv); +} + +FILE* flasy_open_file(flasy_t* srv, const char* path, bool binary) { + assert(srv != NULL); + assert(path != NULL); + + const size_t hsize = srv->bufsz + offsetof(flasy_handler_t, buf); + + uint8_t* itr = srv->handlers; + uint8_t* end = srv->handlers + hsize*srv->length; + for (; itr < end; itr += hsize) { + if (atomic_load(&((flasy_handler_t*) itr)->fp) == 0) break; + } + if (itr >= end) return NULL; + + FILE* fp = fopen(path, binary? "wb": "w"); + if (fp == NULL) return NULL; + + flasy_handler_t* handler = (typeof(handler)) itr; + /* while handler->fp is NULL, no other threads modifies the handler */ + + setvbuf(fp, (char*) handler->buf, _IOFBF, srv->bufsz); + atomic_store(&handler->request_flush, false); + atomic_store(&handler->fp, (uintptr_t) fp); + + return fp; +} + +void flasy_close_file(flasy_t* srv, FILE* fp) { + assert(srv != NULL); + assert(fp != NULL); + + const size_t hsize = srv->bufsz + offsetof(flasy_handler_t, buf); + + uint8_t* itr = srv->handlers; + uint8_t* end = srv->handlers + hsize*srv->length; + for (; itr < end; itr += hsize) { + if (atomic_load(&((flasy_handler_t*) itr)->fp) == (uintptr_t) fp) break; + } + assert(itr < end); + + flasy_handler_t* handler = (typeof(handler)) itr; + atomic_store(&handler->request_flush, true); +} diff --git a/util/flasy/flasy.h b/util/flasy/flasy.h new file mode 100644 index 0000000..9ba17f5 --- /dev/null +++ b/util/flasy/flasy.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +/* plz note that all functions are not thread-safe */ + +struct flasy_t; +typedef struct flasy_t flasy_t; + +flasy_t* /* OWNERSHIP */ +flasy_new( + size_t bufsz, + size_t hlen +); + +void +flasy_delete( + flasy_t* srv /* OWNERSHIP */ +); + +FILE* /* OWNERSHIP/NULLABLE */ +flasy_open_file( + flasy_t* srv, + const char* path, + bool binary +); + +void +flasy_close_file( + flasy_t* srv, + FILE* fp /* OWNERSHIP */ +); diff --git a/util/flasy/test.c b/util/flasy/test.c new file mode 100644 index 0000000..25f6e19 --- /dev/null +++ b/util/flasy/test.c @@ -0,0 +1,46 @@ +#undef NDEBUG + +#include +#include +#include +#include +#include +#include + +#include "./flasy.h" + +#define MAX_ 16 +#define COUNT_ (512*1024) + +int main(int argc, char** argv) { + assert(2 <= argc && argc <= MAX_); + + flasy_t* srv = flasy_new(COUNT_*sizeof(uint32_t), MAX_); + + for (size_t i = 0; i < (size_t) argc-1; ++i) { + FILE* fp = flasy_open_file(srv, argv[1+i], true); + assert(fp != NULL); + for (uint32_t i = 0; i < COUNT_; ++i) { + assert(fwrite(&i, sizeof(i), 1, fp) == 1); + } + flasy_close_file(srv, fp); + } + + flasy_delete(srv); /* join */ + + for (size_t i = 0; i < (size_t) argc-1; ++i) { + FILE* fp = fopen(argv[1+i], "rb"); + assert(fp != NULL); + for (uint32_t i = 0; i < COUNT_; ++i) { + uint32_t a; + assert(fread(&a, sizeof(a), 1, fp) == 1); + if (a != i) printf("%d %d\n", i, a); + assert(a == i); + } + uint8_t dummy_; + assert(fread(&dummy_, 1, 1, fp) == 0 && feof(fp) != 0); + fclose(fp); + } + + return EXIT_SUCCESS; +} diff --git a/util/gleasy/atlas.c b/util/gleasy/atlas.c index 501ab1f..cd4df01 100644 --- a/util/gleasy/atlas.c +++ b/util/gleasy/atlas.c @@ -50,7 +50,8 @@ static void gleasy_atlas_resize_bitmap_( const size_t pixel = type*fmt; assert(pixel > 0); - container_array_resize(atlas->resize_buffer, out->width*out->height*pixel); + container_array_resize( + atlas->resize_buffer, (size_t) out->width*out->height*pixel); out->buffer = atlas->resize_buffer; const int32_t ymax = out->height * pixel; @@ -128,7 +129,7 @@ gleasy_atlas_t* gleasy_atlas_new( assert(glGetError() == GL_NO_ERROR); - container_array_reserve(atlas->resize_buffer, width*height*4); + container_array_reserve(atlas->resize_buffer, (size_t) width*height*4); return atlas; } diff --git a/util/glyphas/CMakeLists.txt b/util/glyphas/CMakeLists.txt index 2cc583c..86b14ce 100644 --- a/util/glyphas/CMakeLists.txt +++ b/util/glyphas/CMakeLists.txt @@ -27,7 +27,7 @@ target_link_libraries(glyphas if (BUILD_TESTING) add_executable(glyphas-test test.c) target_link_libraries(glyphas-test - SDL2::SDL2 + ${SDL2_TARGET} glyphas) endif() diff --git a/util/glyphas/drawer.c b/util/glyphas/drawer.c index 29a9b85..efe02f7 100644 --- a/util/glyphas/drawer.c +++ b/util/glyphas/drawer.c @@ -9,31 +9,20 @@ #include "util/gleasy/texture.h" #include "util/gleasy/program.h" #include "util/math/vector.h" -#include "util/memory/memory.h" #include "./block.h" /* resources */ -#include "anysrc/drawer.vshader.h" -#include "anysrc/drawer.fshader.h" +#include "util/glyphas/anysrc/drawer.vshader.h" +#include "util/glyphas/anysrc/drawer.fshader.h" -#define GLYPHAS_DRAWER_UNIFORM_TEX 0 +#define UNIFORM_TEX_ 0 -#define GLYPHAS_DRAWER_VSHADER_IN_POS 0 -#define GLYPHAS_DRAWER_VSHADER_IN_SIZE 1 -#define GLYPHAS_DRAWER_VSHADER_IN_UV_POS 2 -#define GLYPHAS_DRAWER_VSHADER_IN_UV_SIZE 3 -#define GLYPHAS_DRAWER_VSHADER_IN_COLOR 4 - -struct glyphas_drawer_t { - gleasy_texture_2d_t tex; - - GLuint vao; - - gleasy_buffer_array_t instances; - size_t instances_reserved; - size_t instances_length; -}; +#define VSHADER_IN_POS_ 0 +#define VSHADER_IN_SIZE_ 1 +#define VSHADER_IN_UV_POS_ 2 +#define VSHADER_IN_UV_SIZE_ 3 +#define VSHADER_IN_COLOR_ 4 #pragma pack(push, 1) typedef struct { @@ -45,73 +34,60 @@ typedef struct { } glyphas_drawer_instance_t; #pragma pack(pop) -static void glyphas_drawer_setup_vao_( - gleasy_buffer_array_t instances) { - assert(instances != 0); - - glBindBuffer(GL_ARRAY_BUFFER, instances); - -# define enable_attrib_(NAME, name, dim, type) do { \ - glEnableVertexAttribArray(GLYPHAS_DRAWER_VSHADER_IN_##NAME); \ - glVertexAttribPointer( \ - GLYPHAS_DRAWER_VSHADER_IN_##NAME, dim, type, GL_FALSE, \ - sizeof(glyphas_drawer_instance_t), \ - NULL + offsetof(glyphas_drawer_instance_t, name)); \ - glVertexAttribDivisor(GLYPHAS_DRAWER_VSHADER_IN_##NAME, 1); \ - } while (0) - - enable_attrib_(POS, pos, 2, GL_FLOAT); - enable_attrib_(SIZE, size, 2, GL_FLOAT); - enable_attrib_(UV_POS, uv_pos, 2, GL_FLOAT); - enable_attrib_(UV_SIZE, uv_size, 2, GL_FLOAT); - enable_attrib_(COLOR, color, 4, GL_FLOAT); - -# undef enable_attrib_ -} - gleasy_program_t glyphas_drawer_create_default_program(void) { return gleasy_program_new("", 0, glyphas_drawer_vshader_, sizeof(glyphas_drawer_vshader_), glyphas_drawer_fshader_, sizeof(glyphas_drawer_fshader_)); } -glyphas_drawer_t* glyphas_drawer_new(void) { - glyphas_drawer_t* drawer = memory_new(sizeof(*drawer)); - *drawer = (typeof(*drawer)) {0}; +void glyphas_drawer_initialize( + glyphas_drawer_t* drawer, gleasy_texture_2d_t tex) { + assert(drawer != NULL); + + *drawer = (typeof(*drawer)) { + .tex = tex, + }; glCreateVertexArrays(1, &drawer->vao); - glBindVertexArray(drawer->vao); - glGenBuffers(1, &drawer->instances); - glyphas_drawer_setup_vao_(drawer->instances); - return drawer; + glBindVertexArray(drawer->vao); + glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); + +# define enable_(index, var, dim, type) do { \ + glEnableVertexAttribArray(index); \ + glVertexAttribPointer( \ + index, dim, type, GL_FALSE, \ + sizeof(glyphas_drawer_instance_t), \ + NULL + offsetof(glyphas_drawer_instance_t, var)); \ + glVertexAttribDivisor(index, 1); \ + } while (0) + + enable_(VSHADER_IN_POS_, pos, 2, GL_FLOAT); + enable_(VSHADER_IN_SIZE_, size, 2, GL_FLOAT); + enable_(VSHADER_IN_UV_POS_, uv_pos, 2, GL_FLOAT); + enable_(VSHADER_IN_UV_SIZE_, uv_size, 2, GL_FLOAT); + enable_(VSHADER_IN_COLOR_, color, 4, GL_FLOAT); + +# undef enable_attrib_ } -void glyphas_drawer_delete(glyphas_drawer_t* drawer) { - if (drawer == NULL) return; +void glyphas_drawer_deinitialize(glyphas_drawer_t* drawer) { + assert(drawer != NULL); glDeleteBuffers(1, &drawer->instances); - glDeleteVertexArrays(1, &drawer->vao); - - memory_delete(drawer); } -void glyphas_drawer_clear( - glyphas_drawer_t* drawer, gleasy_texture_2d_t tex, size_t reserve) { +void glyphas_drawer_clear(glyphas_drawer_t* drawer, size_t reserve) { assert(drawer != NULL); - assert(tex != 0); assert(reserve > 0); - drawer->tex = tex; - drawer->instances_length = 0; if (drawer->instances_reserved < reserve) { glBindBuffer(GL_ARRAY_BUFFER, drawer->instances); glBufferData(GL_ARRAY_BUFFER, - reserve * sizeof(glyphas_drawer_instance_t), - NULL, GL_DYNAMIC_DRAW); + reserve*sizeof(glyphas_drawer_instance_t), NULL, GL_DYNAMIC_DRAW); drawer->instances_reserved = reserve; } } @@ -158,7 +134,7 @@ void glyphas_drawer_draw(const glyphas_drawer_t* drawer) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, drawer->tex); - glUniform1i(GLYPHAS_DRAWER_UNIFORM_TEX, 0); + glUniform1i(UNIFORM_TEX_, 0); glDrawArraysInstanced(GL_TRIANGLES, 0, 6, drawer->instances_length); } diff --git a/util/glyphas/drawer.h b/util/glyphas/drawer.h index 20d4057..a349c68 100644 --- a/util/glyphas/drawer.h +++ b/util/glyphas/drawer.h @@ -1,33 +1,41 @@ #pragma once +#include "util/gleasy/buffer.h" #include "util/gleasy/texture.h" #include "util/gleasy/program.h" #include "./block.h" -struct glyphas_drawer_t; -typedef struct glyphas_drawer_t glyphas_drawer_t; +typedef struct { + gleasy_texture_2d_t tex; + + GLuint vao; + + gleasy_buffer_array_t instances; + size_t instances_reserved; + size_t instances_length; +} glyphas_drawer_t; gleasy_program_t glyphas_drawer_create_default_program( void ); -glyphas_drawer_t* -glyphas_drawer_new( - void +void +glyphas_drawer_initialize( + glyphas_drawer_t* drawer, + gleasy_texture_2d_t tex ); void -glyphas_drawer_delete( +glyphas_drawer_deinitialize( glyphas_drawer_t* drawer ); void glyphas_drawer_clear( - glyphas_drawer_t* drawer, - gleasy_texture_2d_t tex, - size_t reserve + glyphas_drawer_t* drawer, + size_t reserve ); void @@ -44,7 +52,7 @@ glyphas_drawer_add_block_item( /* The drawer doesn't hold the reference. */ ); -/* bind the program before drawing */ +/* call glUseProgram before calling */ void glyphas_drawer_draw( const glyphas_drawer_t* drawer diff --git a/util/glyphas/face.c b/util/glyphas/face.c index 0f0d583..c70bada 100644 --- a/util/glyphas/face.c +++ b/util/glyphas/face.c @@ -11,6 +11,16 @@ #include "./context.h" +static const char* glyphas_face_get_ft_error_str_(FT_Error err) { + /* what a fucking trick lol. + * https://stackoverflow.com/questions/61641364/gcc-cant-find-ft-error-string-when-trying-to-compile */ +# undef FTERRORS_H_ +# define FT_ERRORDEF(code, val, str) case code: return str; +# define FT_ERROR_START_LIST switch(err) { +# define FT_ERROR_END_LIST default: return "unknown"; } +# include FT_ERRORS_H +} + void glyphas_face_initialize_from_file( glyphas_face_t* face, const glyphas_context_t* ctx, @@ -23,8 +33,8 @@ void glyphas_face_initialize_from_file( const FT_Error err = FT_New_Face(ctx->ft, path, index, &face->ft); if (err != FT_Err_Ok) { - fprintf(stderr, - "failed to load font file '%s': %s\n", path, FT_Error_String(err)); + fprintf(stderr, "failed to load font file '%s': %s\n", + path, glyphas_face_get_ft_error_str_(err)); abort(); } } @@ -43,8 +53,8 @@ void glyphas_face_initialize_from_buffer( const FT_Error err = FT_New_Memory_Face(ctx->ft, data, length, index, &face->ft); if (err != FT_Err_Ok) { - fprintf(stderr, - "failed to load font on memory: %s\n", FT_Error_String(err)); + fprintf(stderr, "failed to load font on memory: %s\n", + glyphas_face_get_ft_error_str_(err)); abort(); } } diff --git a/util/glyphas/test.c b/util/glyphas/test.c index a286842..de533ff 100644 --- a/util/glyphas/test.c +++ b/util/glyphas/test.c @@ -28,8 +28,8 @@ typedef struct { gleasy_atlas_t* atlas; glyphas_cache_t* cache; - gleasy_program_t prog; - glyphas_drawer_t* drawer; + gleasy_program_t prog; + glyphas_drawer_t drawer; } context_t; #define SCALE 0.01f @@ -56,8 +56,8 @@ static void align_text_(context_t* ctx, const char* str) { static const vec2_t origin = vec2(.5f, -.5f); glyphas_block_set_origin(block, &origin); - glyphas_drawer_clear(ctx->drawer, gleasy_atlas_get_texture(ctx->atlas), len); - glyphas_drawer_add_block(ctx->drawer, block); + glyphas_drawer_clear(&ctx->drawer, len); + glyphas_drawer_add_block(&ctx->drawer, block); glyphas_block_delete(block); } @@ -72,8 +72,8 @@ static void initialize_(context_t* ctx, const char* path, const char* str) { ctx->atlas = gleasy_atlas_new(GL_RED, 256, 256, false /* anti-alias */); ctx->cache = glyphas_cache_new(ctx->atlas, &ctx->face, 16, 16); - ctx->prog = glyphas_drawer_create_default_program(); - ctx->drawer = glyphas_drawer_new(); + ctx->prog = glyphas_drawer_create_default_program(); + glyphas_drawer_initialize(&ctx->drawer, gleasy_atlas_get_texture(ctx->atlas)); assert(glGetError() == GL_NO_ERROR); align_text_(ctx, str); @@ -87,13 +87,13 @@ static void draw_(const context_t* ctx) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glUseProgram(ctx->prog); - glyphas_drawer_draw(ctx->drawer); + glyphas_drawer_draw(&ctx->drawer); } static void deinitialize_(context_t* ctx) { assert(ctx != NULL); - glyphas_drawer_delete(ctx->drawer); + glyphas_drawer_deinitialize(&ctx->drawer); glDeleteProgram(ctx->prog); glyphas_cache_delete(ctx->cache); diff --git a/util/jukebox/composite.c b/util/jukebox/composite.c index e4c9593..3689716 100644 --- a/util/jukebox/composite.c +++ b/util/jukebox/composite.c @@ -49,7 +49,7 @@ static void jukebox_composite_affect_( jukebox_effect_affect(c->effects[i], &chunk_pcm); } - const size_t len = chunk_pcm.frames * channels; + const size_t len = (size_t) chunk_pcm.frames*channels; const float* src = chunk; float* dst = pcm->ptr + read * channels; for (uint64_t i = 0; i < len; ++i) { diff --git a/util/jukebox/decoder.c b/util/jukebox/decoder.c index b573b78..fad3eb0 100644 --- a/util/jukebox/decoder.c +++ b/util/jukebox/decoder.c @@ -8,7 +8,7 @@ #include #include -#include "thirdparty/miniaudio/miniaudio.h" +#include #include "util/math/algorithm.h" #include "util/math/rational.h" diff --git a/util/jukebox/delay.c b/util/jukebox/delay.c index 09fe3a0..279dea8 100644 --- a/util/jukebox/delay.c +++ b/util/jukebox/delay.c @@ -32,7 +32,7 @@ static void jukebox_delay_affect_( jukebox_delay_t* d = (typeof(d)) effect; const int32_t ch = d->format.channels; - const size_t pcmlen = pcm->frames*ch; + const size_t pcmlen = (size_t) pcm->frames*ch; for (size_t i = 0; i < pcmlen; ++i) { float* bufoff = &d->buffer[d->offset]; diff --git a/util/jukebox/mixer.c b/util/jukebox/mixer.c index a44c06c..eb95891 100644 --- a/util/jukebox/mixer.c +++ b/util/jukebox/mixer.c @@ -5,7 +5,7 @@ #include #include -#include "thirdparty/miniaudio/miniaudio.h" +#include #include "util/container/array.h" #include "util/memory/memory.h" diff --git a/util/jukebox/sound.c b/util/jukebox/sound.c index 7c138fc..4fc0cd7 100644 --- a/util/jukebox/sound.c +++ b/util/jukebox/sound.c @@ -6,7 +6,7 @@ #include #include -#include "thirdparty/miniaudio/miniaudio.h" +#include #include "util/math/rational.h" #include "util/memory/memory.h" diff --git a/util/math/algorithm.h b/util/math/algorithm.h index 6afca10..f846fe6 100644 --- a/util/math/algorithm.h +++ b/util/math/algorithm.h @@ -14,7 +14,8 @@ #define MATH_CLAMP(x, min, max) ((x) < (min)? (min): (x) > (max)? (max): (x)) -#define MATH_SIGN(a) (a < 0? -1: a > 0? 1: 0) +#define MATH_SIGN(a) (a < 0? -1: a > 0? 1: 0) +#define MATH_SIGN_NOZERO(a) (a < 0? -1: 1) #define MATH_FLOAT_EQUAL(a, b) (MATH_ABS((a) - (b)) < MATH_EPSILON) #define MATH_FLOAT_VALID(a) (!isnan(a) && !isinf(a)) diff --git a/util/statman/CMakeLists.txt b/util/statman/CMakeLists.txt new file mode 100644 index 0000000..5834210 --- /dev/null +++ b/util/statman/CMakeLists.txt @@ -0,0 +1,9 @@ +add_library(statman + statman.c +) + +if (BUILD_TESTING) + add_executable(statman-test test.c) + target_link_libraries(statman-test statman) + add_test(statman-test statman-test) +endif() diff --git a/util/statman/README.md b/util/statman/README.md new file mode 100644 index 0000000..49d24c8 --- /dev/null +++ b/util/statman/README.md @@ -0,0 +1,4 @@ +statman +==== + +the simplest STATe MANagement system diff --git a/util/statman/statman.c b/util/statman/statman.c new file mode 100644 index 0000000..8a81f8d --- /dev/null +++ b/util/statman/statman.c @@ -0,0 +1,89 @@ +#include "./statman.h" + +#include +#include +#include +#include +#include + +#define REDIRECT_MAX_ 100 + +static const statman_meta_t* statman_get_meta_by_state_( + const statman_meta_t* meta, statman_state_t state) { + assert(meta != NULL); + + for (size_t i = 0; meta[i].name != NULL; ++i) { + if (meta[i].state == state) return &meta[i]; + } + fprintf(stderr, "statman: unknown state %"PRIu16"\n", state); + abort(); +} + +static void statman_initialize_state_( + const statman_meta_t* meta, + void* instance, + statman_state_t* state, + size_t depth) { + assert(meta != NULL); + assert(state != NULL); + assert(depth < REDIRECT_MAX_); + + const statman_meta_t* m = statman_get_meta_by_state_(meta, *state); + if (m->initialize == NULL) return; + + const statman_state_t backup = *state; + m->initialize(m, instance, state); + + if (backup != *state) { + statman_initialize_state_(meta, instance, state, depth+1); + } +} + +static void statman_update_state_( + const statman_meta_t* meta, + void* instance, + statman_state_t* state, + size_t depth) { + assert(meta != NULL); + assert(state != NULL); + assert(depth < REDIRECT_MAX_); + + const statman_meta_t* m = statman_get_meta_by_state_(meta, *state); + if (m->update == NULL) return; + + const statman_state_t backup = *state; + m->update(m, instance, state); + + if (backup != *state) { + statman_initialize_state_(meta, instance, state, depth+1); + statman_update_state_(meta, instance, state, depth+1); + } +} + +void statman_update( + const statman_meta_t* meta, void* instance, statman_state_t* state) { + assert(meta != NULL); + assert(state != NULL); + + statman_update_state_(meta, instance, state, 0); +} + +void statman_transition_to( + const statman_meta_t* meta, + void* instance, + statman_state_t* state, + statman_state_t next) { + assert(meta != NULL); + assert(state != NULL); + + if (*state == next) return; + + const statman_meta_t* m = statman_get_meta_by_state_(meta, *state); + if (m->finalize != NULL) { + m->finalize(m, instance, &next); + } + if (*state == next) return; + + *state = next; + statman_initialize_state_(meta, instance, state, 0); +} diff --git a/util/statman/statman.h b/util/statman/statman.h new file mode 100644 index 0000000..1541171 --- /dev/null +++ b/util/statman/statman.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +typedef uint16_t statman_state_t; + +typedef struct statman_meta_t statman_meta_t; +struct statman_meta_t { + statman_state_t state; + const char* name; + const void* data; + + void + (*initialize)( + const statman_meta_t* meta, + void* instance, + statman_state_t* next + ); + void + (*update)( + const statman_meta_t* meta, + void* instance, + statman_state_t* next + ); + void + (*finalize)( + const statman_meta_t* meta, + void* instance, + statman_state_t* next + ); +}; + +void +statman_update( + const statman_meta_t* meta, + void* instance, + statman_state_t* state +); + +/* don't call in callback functions */ +void +statman_transition_to( + const statman_meta_t* meta, + void* instance, + statman_state_t* state, + statman_state_t next +); diff --git a/util/statman/test.c b/util/statman/test.c new file mode 100644 index 0000000..d9d91ab --- /dev/null +++ b/util/statman/test.c @@ -0,0 +1,160 @@ +#undef NDEBUG + +#include +#include +#include + +#include "./statman.h" + +typedef enum { + CHECK_POINT_NONE, + + CHECK_POINT_STATE0_INITIALIZE, + CHECK_POINT_STATE1_INITIALIZE, + CHECK_POINT_STATE2_INITIALIZE, + CHECK_POINT_STATE3_INITIALIZE, + + CHECK_POINT_STATE0_UPDATE, + CHECK_POINT_STATE1_UPDATE, + CHECK_POINT_STATE2_UPDATE, + + CHECK_POINT_STATE0_FINALIZE, + CHECK_POINT_STATE1_FINALIZE, + CHECK_POINT_STATE2_FINALIZE, + CHECK_POINT_STATE3_FINALIZE, +} check_point_t; + +static check_point_t actual_[256] = {0}; +static size_t actual_length_ = 0; + +static inline void check_point_(check_point_t cp) { + assert(actual_length_ < sizeof(actual_)/sizeof(actual_[0])); + actual_[actual_length_++] = cp; +} + +static void state_initialize_( + const statman_meta_t* meta, void* time, statman_state_t* next) { + assert(meta != NULL); + assert(time != NULL); + assert(next != NULL); + + check_point_(CHECK_POINT_STATE0_INITIALIZE+meta->state); +} + +static void state3_initialize_( + const statman_meta_t* meta, void* time, statman_state_t* next) { + assert(meta != NULL); + assert(time != NULL); + assert(next != NULL); + + check_point_(CHECK_POINT_STATE3_INITIALIZE); + *next = 0; +} + +static void state_update_( + const statman_meta_t* meta, void* time, statman_state_t* next) { + assert(meta != NULL); + assert(time != NULL); + assert(next != NULL); + + check_point_(CHECK_POINT_STATE0_UPDATE+meta->state); + + size_t *t = (typeof(t)) time; + if ((*t)++%2 == 0) *next = meta->state+1; +} + +static void state_finalize_( + const statman_meta_t* meta, void* time, statman_state_t* next) { + assert(meta != NULL); + assert(time != NULL); + assert(next != NULL); + + check_point_(CHECK_POINT_STATE0_FINALIZE+meta->state); + *next = 0; +} + +static const statman_meta_t table_[] = { + { + .state = 0, + .name = "0", + .initialize = state_initialize_, + .update = state_update_, + .finalize = state_finalize_, + }, + { + .state = 1, + .name = "1", + .initialize = state_initialize_, + .update = state_update_, + .finalize = state_finalize_, + }, + { + .state = 2, + .name = "2", + .initialize = state_initialize_, + .update = state_update_, + .finalize = state_finalize_, + }, + { + .state = 3, + .name = "3", + .initialize = state3_initialize_, + }, +}; + +int main(void) { + statman_state_t state = 0; + size_t time = 0; + + /* state0 -> state1 */ + statman_update(table_, &time, &state); + assert(state == 1); + assert(time == 2); + + /* state1 -> state2 */ + statman_update(table_, &time, &state); + assert(state == 2); + assert(time == 4); + + /* state2 -> state0 */ + statman_update(table_, &time, &state); + assert(state == 0); + assert(time == 6); + + /* state0 -> state1 */ + statman_update(table_, &time, &state); + assert(state == 1); + assert(time == 8); + + /* stat1's finalizer forces to move to 0 */ + statman_transition_to(table_, &time, &state, 2); + assert(state == 0); + assert(time == 8); + + static const check_point_t expects[] = { + CHECK_POINT_STATE0_UPDATE, + CHECK_POINT_STATE1_INITIALIZE, + CHECK_POINT_STATE1_UPDATE, + + CHECK_POINT_STATE1_UPDATE, + CHECK_POINT_STATE2_INITIALIZE, + CHECK_POINT_STATE2_UPDATE, + + CHECK_POINT_STATE2_UPDATE, + CHECK_POINT_STATE3_INITIALIZE, + CHECK_POINT_STATE0_INITIALIZE, + CHECK_POINT_STATE0_UPDATE, + + CHECK_POINT_STATE0_UPDATE, + CHECK_POINT_STATE1_INITIALIZE, + CHECK_POINT_STATE1_UPDATE, + + CHECK_POINT_STATE1_FINALIZE, + CHECK_POINT_STATE0_INITIALIZE, + }; + + assert(actual_length_ == sizeof(expects)/sizeof(expects[0])); + for (size_t i = 0; i < actual_length_; ++i) { + assert(expects[i] == actual_[i]); + } +}