From 2a031c7dde3e3c88ead74afe4deb2fa7cb2ba9ce Mon Sep 17 00:00:00 2001 From: korenkonder Date: Tue, 11 May 2021 21:04:48 +0300 Subject: [PATCH] v0.4.0.0 --- .gitignore | 1 + extern/src/cimgui.h | 3390 +++++++++ extern/src/cimgui_impl.h | 38 + res/MikuShoot.ico | Bin 0 -> 120193 bytes res/MikuShoot.png | Bin 0 -> 70959 bytes res/MikuWow.ico | Bin 0 -> 130576 bytes res/MikuWow.png | Bin 0 -> 73271 bytes src/CLOUD/Classes/background_color.c | 102 - src/CLOUD/Classes/background_color.h | 26 - src/CLOUD/Classes/glitter_editor.c | 6430 +++++++++++++---- src/CLOUD/Classes/glitter_editor.h | 31 +- src/CLOUD/Classes/glitter_test.c | 235 - src/CLOUD/Classes/glitter_test.h | 32 - src/CLOUD/Classes/post_process.c | 257 - src/CLOUD/Classes/post_process.h | 24 - src/CLOUD/classes.c | 133 + src/CLOUD/classes.h | 42 + src/CLOUD/classes/data_test.c | 27 + src/CLOUD/classes/data_test.h | 12 + src/CLOUD/classes/data_test/glitter_test.c | 249 + src/CLOUD/classes/data_test/glitter_test.h | 17 + src/CLOUD/classes/graphics.c | 59 + src/CLOUD/classes/graphics.h | 14 + src/CLOUD/classes/graphics/background_color.c | 97 + src/CLOUD/classes/graphics/background_color.h | 17 + src/CLOUD/classes/graphics/glitter_counter.c | 123 + src/CLOUD/classes/graphics/glitter_counter.h | 16 + src/CLOUD/classes/graphics/post_process.c | 245 + src/CLOUD/classes/graphics/post_process.h | 16 + src/CLOUD/classes/imgui_helper.c | 1094 +++ src/CLOUD/classes/imgui_helper.h | 116 + src/CLOUD/control.c | 180 +- src/CLOUD/input.c | 144 +- src/CLOUD/input.h | 5 - src/CLOUD/main.c | 69 +- src/CLOUD/render.c | 2572 ++++--- src/CLOUD/render.h | 27 - src/CLOUD/shared.c | 81 +- src/CLOUD/shared.h | 41 +- src/CLOUD/sound.c | 7 +- src/CRE/Glitter/animation.c | 99 +- src/CRE/Glitter/animation.h | 8 +- src/CRE/Glitter/counter.c | 16 +- src/CRE/Glitter/counter.h | 3 +- src/CRE/Glitter/curve.c | 1416 ++-- src/CRE/Glitter/curve.h | 17 +- src/CRE/Glitter/curve_get_value.c | 198 + src/CRE/Glitter/diva_effect.c | 14 +- src/CRE/Glitter/diva_effect.h | 4 +- src/CRE/Glitter/diva_list.c | 12 +- src/CRE/Glitter/diva_list.h | 2 +- src/CRE/Glitter/diva_resource.c | 12 +- src/CRE/Glitter/diva_resource.h | 2 +- src/CRE/Glitter/effect.c | 628 +- src/CRE/Glitter/effect.h | 11 +- src/CRE/Glitter/effect_group.c | 40 +- src/CRE/Glitter/effect_group.h | 6 +- src/CRE/Glitter/effect_inst.c | 798 +- src/CRE/Glitter/effect_inst.h | 26 +- src/CRE/Glitter/emitter.c | 617 +- src/CRE/Glitter/emitter.h | 9 +- src/CRE/Glitter/emitter_inst.c | 653 +- src/CRE/Glitter/emitter_inst.h | 32 +- src/CRE/Glitter/file_reader.c | 107 +- src/CRE/Glitter/file_reader.h | 8 +- src/CRE/Glitter/glitter.c | 34 + src/CRE/Glitter/glitter.h | 423 +- src/CRE/Glitter/list.c | 27 +- src/CRE/Glitter/list.h | 2 +- src/CRE/Glitter/locus_history.c | 37 +- src/CRE/Glitter/locus_history.h | 4 +- src/CRE/Glitter/particle.c | 993 ++- src/CRE/Glitter/particle.h | 9 +- src/CRE/Glitter/particle_inst.c | 314 +- src/CRE/Glitter/particle_inst.h | 18 +- src/CRE/Glitter/particle_manager.c | 264 +- src/CRE/Glitter/particle_manager.h | 53 +- src/CRE/Glitter/random.c | 287 +- src/CRE/Glitter/random.h | 24 +- src/CRE/Glitter/render_element.c | 468 ++ src/CRE/Glitter/render_element.h | 23 + src/CRE/Glitter/render_group.c | 2394 +++--- src/CRE/Glitter/render_group.h | 43 +- src/CRE/Glitter/scene.c | 105 +- src/CRE/Glitter/scene.h | 7 +- src/CRE/Glitter/shared.c | 21 +- src/CRE/Glitter/shared.h | 7 +- src/CRE/Glitter/texture.c | 248 +- src/CRE/Glitter/texture.h | 6 +- src/CRE/GlitterX/curve_x.h | 11 + src/CRE/GlitterX/curve_x_get_value.c | 198 + src/CRE/GlitterX/effect_inst_x.c | 56 + src/CRE/GlitterX/effect_inst_x.h | 8 + src/CRE/GlitterX/emitter_inst_x.c | 12 + src/CRE/GlitterX/emitter_inst_x.h | 8 + src/CRE/GlitterX/locus_history_x.c | 64 + src/CRE/GlitterX/locus_history_x.h | 13 + src/CRE/GlitterX/particle_inst_x.c | 8 + src/CRE/GlitterX/particle_inst_x.h | 8 + src/CRE/GlitterX/render_element_x.c | 12 + src/CRE/GlitterX/render_element_x.h | 8 + src/CRE/GlitterX/render_group_x.c | 16 + src/CRE/GlitterX/render_group_x.h | 8 + src/CRE/camera.c | 380 +- src/CRE/camera.h | 41 +- src/CRE/dof.c | 108 + src/CRE/dof.h | 53 + src/CRE/fbo_dof.c | 62 +- src/CRE/fbo_dof.h | 3 +- src/CRE/fbo_hdr.c | 23 +- src/CRE/fbo_helper.c | 19 +- src/CRE/fbo_helper.h | 5 +- src/CRE/fbo_pp.c | 166 +- src/CRE/fbo_render.c | 71 +- src/CRE/fbo_render.h | 7 +- src/CRE/gl_object.c | 342 +- src/CRE/gl_object.h | 42 +- src/CRE/hash.c | 13 +- src/CRE/hash.h | 20 +- src/CRE/light.c | 16 + src/CRE/light.h | 44 + src/CRE/lock.h | 35 + src/CRE/material.c | 16 + src/CRE/material.h | 34 + src/CRE/microui.c | 1250 ---- src/CRE/microui.h | 379 - src/CRE/microui_atlas.inl | 994 --- src/CRE/post_process.c | 2 +- src/CRE/shader.c | 291 +- src/CRE/shader.h | 126 +- src/CRE/shared.c | 16 + src/CRE/shared.h | 38 + src/CRE/static_var.c | 129 + src/CRE/static_var.h | 19 + src/CRE/task.c | 1 + src/CRE/task.h | 64 +- src/CRE/texture.c | 427 +- src/CRE/texture.h | 27 + src/CRE/timer.h | 41 +- src/CRE/vertex.c | 326 +- src/CRE/vertex.h | 52 +- src/KKdLib/a3dai.c | 164 +- src/KKdLib/add_param.c | 170 - src/KKdLib/add_param.h | 36 - src/KKdLib/aes.c | 2 +- src/KKdLib/auth_3d.c | 6 + src/KKdLib/auth_3d.h | 65 +- src/KKdLib/char_buffer.c | 13 +- src/KKdLib/char_buffer.h | 10 +- src/KKdLib/dds.c | 467 ++ src/KKdLib/dds.h | 26 + src/KKdLib/default.c | 10 +- src/KKdLib/default.h | 39 +- src/KKdLib/divafile.c | 6 +- src/KKdLib/dsc.c | 754 +- src/KKdLib/dsc.h | 535 +- src/KKdLib/enbaya.c | 2 +- src/KKdLib/f2_enrs.c | 105 +- src/KKdLib/f2_enrs.h | 19 +- src/KKdLib/f2_header.c | 12 - src/KKdLib/f2_header.h | 7 +- src/KKdLib/f2_pof.c | 60 +- src/KKdLib/f2_pof.h | 7 - src/KKdLib/f2_struct.c | 112 +- src/KKdLib/f2_struct.h | 3 +- src/KKdLib/farc.c | 562 +- src/KKdLib/farc.h | 12 +- src/KKdLib/half_t.h | 3 + src/KKdLib/hash.c | 231 +- src/KKdLib/hash.h | 3 + src/KKdLib/interpolation.c | 268 + src/KKdLib/interpolation.h | 33 + src/KKdLib/io_deflate.c | 131 +- src/KKdLib/io_json.c | 14 +- src/KKdLib/io_path.c | 106 +- src/KKdLib/io_path.h | 10 +- src/KKdLib/io_stream.c | 47 +- src/KKdLib/io_stream.h | 3 +- src/KKdLib/kkc.c | 52 +- src/KKdLib/kkc.h | 24 +- src/KKdLib/kkfs.c | 589 +- src/KKdLib/kkfs.h | 21 +- src/KKdLib/mat.c | 539 +- src/KKdLib/mat.h | 16 + src/KKdLib/math.c | 48 - src/KKdLib/math.h | 19 - src/KKdLib/mot.c | 170 + src/KKdLib/mot.h | 36 + src/KKdLib/{pdi.c => moti.c} | 48 +- src/KKdLib/moti.h | 36 + src/KKdLib/msgpack.c | 185 +- src/KKdLib/msgpack.h | 4 +- src/KKdLib/pdi.h | 36 - src/KKdLib/pv_db.h | 10 - src/KKdLib/qti.c | 8 +- src/KKdLib/quat_trans.c | 4 +- src/KKdLib/sort.c | 6 +- src/KKdLib/sort.h | 2 - src/KKdLib/sound_diva.c | 28 +- src/KKdLib/sound_diva.h | 2 +- src/KKdLib/sound_vag.c | 35 +- src/KKdLib/sound_vag.h | 2 +- src/KKdLib/sound_wav.c | 10 +- src/KKdLib/sound_wav.h | 2 +- src/KKdLib/str_utils.c | 362 + src/KKdLib/str_utils.h | 35 + src/KKdLib/txp.c | 415 +- src/KKdLib/txp.h | 31 +- src/KKdLib/types.h | 12 +- src/KKdLib/utf8.c | 2 +- src/KKdLib/vec.c | 16 +- src/KKdLib/vec.h | 816 ++- src/KKdLib/vector.c | 7 + src/KKdLib/vector.h | 418 +- thirdparty.txt | 76 +- 215 files changed, 26266 insertions(+), 14539 deletions(-) create mode 100644 extern/src/cimgui.h create mode 100644 extern/src/cimgui_impl.h create mode 100644 res/MikuShoot.ico create mode 100644 res/MikuShoot.png create mode 100644 res/MikuWow.ico create mode 100644 res/MikuWow.png delete mode 100644 src/CLOUD/Classes/background_color.c delete mode 100644 src/CLOUD/Classes/background_color.h delete mode 100644 src/CLOUD/Classes/glitter_test.c delete mode 100644 src/CLOUD/Classes/glitter_test.h delete mode 100644 src/CLOUD/Classes/post_process.c delete mode 100644 src/CLOUD/Classes/post_process.h create mode 100644 src/CLOUD/classes.c create mode 100644 src/CLOUD/classes.h create mode 100644 src/CLOUD/classes/data_test.c create mode 100644 src/CLOUD/classes/data_test.h create mode 100644 src/CLOUD/classes/data_test/glitter_test.c create mode 100644 src/CLOUD/classes/data_test/glitter_test.h create mode 100644 src/CLOUD/classes/graphics.c create mode 100644 src/CLOUD/classes/graphics.h create mode 100644 src/CLOUD/classes/graphics/background_color.c create mode 100644 src/CLOUD/classes/graphics/background_color.h create mode 100644 src/CLOUD/classes/graphics/glitter_counter.c create mode 100644 src/CLOUD/classes/graphics/glitter_counter.h create mode 100644 src/CLOUD/classes/graphics/post_process.c create mode 100644 src/CLOUD/classes/graphics/post_process.h create mode 100644 src/CLOUD/classes/imgui_helper.c create mode 100644 src/CLOUD/classes/imgui_helper.h create mode 100644 src/CRE/Glitter/curve_get_value.c create mode 100644 src/CRE/Glitter/render_element.c create mode 100644 src/CRE/Glitter/render_element.h create mode 100644 src/CRE/GlitterX/curve_x.h create mode 100644 src/CRE/GlitterX/curve_x_get_value.c create mode 100644 src/CRE/GlitterX/effect_inst_x.c create mode 100644 src/CRE/GlitterX/effect_inst_x.h create mode 100644 src/CRE/GlitterX/emitter_inst_x.c create mode 100644 src/CRE/GlitterX/emitter_inst_x.h create mode 100644 src/CRE/GlitterX/locus_history_x.c create mode 100644 src/CRE/GlitterX/locus_history_x.h create mode 100644 src/CRE/GlitterX/particle_inst_x.c create mode 100644 src/CRE/GlitterX/particle_inst_x.h create mode 100644 src/CRE/GlitterX/render_element_x.c create mode 100644 src/CRE/GlitterX/render_element_x.h create mode 100644 src/CRE/GlitterX/render_group_x.c create mode 100644 src/CRE/GlitterX/render_group_x.h create mode 100644 src/CRE/dof.c create mode 100644 src/CRE/dof.h create mode 100644 src/CRE/light.c create mode 100644 src/CRE/light.h create mode 100644 src/CRE/lock.h create mode 100644 src/CRE/material.c create mode 100644 src/CRE/material.h delete mode 100644 src/CRE/microui.c delete mode 100644 src/CRE/microui.h delete mode 100644 src/CRE/microui_atlas.inl create mode 100644 src/CRE/shared.c create mode 100644 src/CRE/shared.h delete mode 100644 src/KKdLib/add_param.c delete mode 100644 src/KKdLib/add_param.h create mode 100644 src/KKdLib/auth_3d.c create mode 100644 src/KKdLib/dds.c create mode 100644 src/KKdLib/dds.h create mode 100644 src/KKdLib/interpolation.c create mode 100644 src/KKdLib/interpolation.h delete mode 100644 src/KKdLib/math.c delete mode 100644 src/KKdLib/math.h create mode 100644 src/KKdLib/mot.c create mode 100644 src/KKdLib/mot.h rename src/KKdLib/{pdi.c => moti.c} (65%) create mode 100644 src/KKdLib/moti.h delete mode 100644 src/KKdLib/pdi.h create mode 100644 src/KKdLib/str_utils.c create mode 100644 src/KKdLib/str_utils.h diff --git a/.gitignore b/.gitignore index 6cffc7f2..36ddd4ba 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ lib libdebug obj objdebug +*.aps *.cs *.rc *.sln diff --git a/extern/src/cimgui.h b/extern/src/cimgui.h new file mode 100644 index 00000000..7865352e --- /dev/null +++ b/extern/src/cimgui.h @@ -0,0 +1,3390 @@ +//This file is automatically generated by generator.lua from https://github.com/cimgui/cimgui +//based on imgui.h file version "1.82" from Dear ImGui https://github.com/ocornut/imgui +//with imgui_internal.h api +#ifndef CIMGUI_INCLUDED +#define CIMGUI_INCLUDED +#include +#include +#if defined _WIN32 || defined __CYGWIN__ + #ifdef CIMGUI_NO_EXPORT + #define API + #else + #define API __declspec(dllexport) + #endif +#else + #ifdef __GNUC__ + #define API __attribute__((__visibility__("default"))) + #else + #define API + #endif +#endif + +#if defined __cplusplus + #define EXTERN extern "C" +#else + #include + #include + #define EXTERN extern +#endif + +#define CIMGUI_API EXTERN API +#define CONST const + + +#ifdef _MSC_VER +typedef unsigned __int64 ImU64; +#else +//typedef unsigned long long ImU64; +#endif + + +#ifdef CIMGUI_DEFINE_ENUMS_AND_STRUCTS +typedef struct ImGuiTableColumnSettings ImGuiTableColumnSettings; +typedef struct ImGuiTableCellData ImGuiTableCellData; +typedef struct ImGuiViewportP ImGuiViewportP; +typedef struct ImGuiPtrOrIndex ImGuiPtrOrIndex; +typedef struct ImGuiShrinkWidthItem ImGuiShrinkWidthItem; +typedef struct ImGuiDataTypeTempStorage ImGuiDataTypeTempStorage; +typedef struct ImVec2ih ImVec2ih; +typedef struct ImVec1 ImVec1; +typedef struct StbTexteditRow StbTexteditRow; +typedef struct STB_TexteditState STB_TexteditState; +typedef struct StbUndoState StbUndoState; +typedef struct StbUndoRecord StbUndoRecord; +typedef struct ImGuiWindowSettings ImGuiWindowSettings; +typedef struct ImGuiWindowTempData ImGuiWindowTempData; +typedef struct ImGuiWindow ImGuiWindow; +typedef struct ImGuiTableColumnsSettings ImGuiTableColumnsSettings; +typedef struct ImGuiTableSettings ImGuiTableSettings; +typedef struct ImGuiTableColumn ImGuiTableColumn; +typedef struct ImGuiTable ImGuiTable; +typedef struct ImGuiTabItem ImGuiTabItem; +typedef struct ImGuiTabBar ImGuiTabBar; +typedef struct ImGuiStyleMod ImGuiStyleMod; +typedef struct ImGuiStackSizes ImGuiStackSizes; +typedef struct ImGuiSettingsHandler ImGuiSettingsHandler; +typedef struct ImGuiPopupData ImGuiPopupData; +typedef struct ImGuiOldColumns ImGuiOldColumns; +typedef struct ImGuiOldColumnData ImGuiOldColumnData; +typedef struct ImGuiNextItemData ImGuiNextItemData; +typedef struct ImGuiNextWindowData ImGuiNextWindowData; +typedef struct ImGuiMetricsConfig ImGuiMetricsConfig; +typedef struct ImGuiNavMoveResult ImGuiNavMoveResult; +typedef struct ImGuiMenuColumns ImGuiMenuColumns; +typedef struct ImGuiLastItemDataBackup ImGuiLastItemDataBackup; +typedef struct ImGuiInputTextState ImGuiInputTextState; +typedef struct ImGuiGroupData ImGuiGroupData; +typedef struct ImGuiDataTypeInfo ImGuiDataTypeInfo; +typedef struct ImGuiContextHook ImGuiContextHook; +typedef struct ImGuiColorMod ImGuiColorMod; +typedef struct ImDrawDataBuilder ImDrawDataBuilder; +typedef struct ImRect ImRect; +typedef struct ImBitVector ImBitVector; +typedef struct ImFontAtlasCustomRect ImFontAtlasCustomRect; +typedef struct ImDrawCmdHeader ImDrawCmdHeader; +typedef struct ImGuiStoragePair ImGuiStoragePair; +typedef struct ImGuiTextRange ImGuiTextRange; +typedef struct ImVec4 ImVec4; +typedef struct ImVec2 ImVec2; +typedef struct ImGuiViewport ImGuiViewport; +typedef struct ImGuiTextFilter ImGuiTextFilter; +typedef struct ImGuiTextBuffer ImGuiTextBuffer; +typedef struct ImGuiTableColumnSortSpecs ImGuiTableColumnSortSpecs; +typedef struct ImGuiTableSortSpecs ImGuiTableSortSpecs; +typedef struct ImGuiStyle ImGuiStyle; +typedef struct ImGuiStorage ImGuiStorage; +typedef struct ImGuiSizeCallbackData ImGuiSizeCallbackData; +typedef struct ImGuiPayload ImGuiPayload; +typedef struct ImGuiOnceUponAFrame ImGuiOnceUponAFrame; +typedef struct ImGuiListClipper ImGuiListClipper; +typedef struct ImGuiInputTextCallbackData ImGuiInputTextCallbackData; +typedef struct ImGuiIO ImGuiIO; +typedef struct ImGuiContext ImGuiContext; +typedef struct ImColor ImColor; +typedef struct ImFontGlyphRangesBuilder ImFontGlyphRangesBuilder; +typedef struct ImFontGlyph ImFontGlyph; +typedef struct ImFontConfig ImFontConfig; +typedef struct ImFontBuilderIO ImFontBuilderIO; +typedef struct ImFontAtlas ImFontAtlas; +typedef struct ImFont ImFont; +typedef struct ImDrawVert ImDrawVert; +typedef struct ImDrawListSplitter ImDrawListSplitter; +typedef struct ImDrawListSharedData ImDrawListSharedData; +typedef struct ImDrawList ImDrawList; +typedef struct ImDrawData ImDrawData; +typedef struct ImDrawCmd ImDrawCmd; +typedef struct ImDrawChannel ImDrawChannel; + +struct ImDrawChannel; +struct ImDrawCmd; +struct ImDrawData; +struct ImDrawList; +struct ImDrawListSharedData; +struct ImDrawListSplitter; +struct ImDrawVert; +struct ImFont; +struct ImFontAtlas; +struct ImFontBuilderIO; +struct ImFontConfig; +struct ImFontGlyph; +struct ImFontGlyphRangesBuilder; +struct ImColor; +struct ImGuiContext; +struct ImGuiIO; +struct ImGuiInputTextCallbackData; +struct ImGuiListClipper; +struct ImGuiOnceUponAFrame; +struct ImGuiPayload; +struct ImGuiSizeCallbackData; +struct ImGuiStorage; +struct ImGuiStyle; +struct ImGuiTableSortSpecs; +struct ImGuiTableColumnSortSpecs; +struct ImGuiTextBuffer; +struct ImGuiTextFilter; +struct ImGuiViewport; +typedef int ImGuiCol; +typedef int ImGuiCond; +typedef int ImGuiDataType; +typedef int ImGuiDir; +typedef int ImGuiKey; +typedef int ImGuiNavInput; +typedef int ImGuiMouseButton; +typedef int ImGuiMouseCursor; +typedef int ImGuiSortDirection; +typedef int ImGuiStyleVar; +typedef int ImGuiTableBgTarget; +typedef int ImDrawFlags; +typedef int ImDrawListFlags; +typedef int ImFontAtlasFlags; +typedef int ImGuiBackendFlags; +typedef int ImGuiButtonFlags; +typedef int ImGuiColorEditFlags; +typedef int ImGuiConfigFlags; +typedef int ImGuiComboFlags; +typedef int ImGuiDragDropFlags; +typedef int ImGuiFocusedFlags; +typedef int ImGuiHoveredFlags; +typedef int ImGuiInputTextFlags; +typedef int ImGuiKeyModFlags; +typedef int ImGuiPopupFlags; +typedef int ImGuiSelectableFlags; +typedef int ImGuiSliderFlags; +typedef int ImGuiTabBarFlags; +typedef int ImGuiTabItemFlags; +typedef int ImGuiTableFlags; +typedef int ImGuiTableColumnFlags; +typedef int ImGuiTableRowFlags; +typedef int ImGuiTreeNodeFlags; +typedef int ImGuiViewportFlags; +typedef int ImGuiWindowFlags; +typedef void* ImTextureID; +typedef unsigned int ImGuiID; +typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); +typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); +typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); +typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); +typedef unsigned short ImWchar16; +typedef unsigned int ImWchar32; +typedef ImWchar16 ImWchar; +typedef signed char ImS8; +typedef unsigned char ImU8; +typedef signed short ImS16; +typedef unsigned short ImU16; +typedef signed int ImS32; +typedef unsigned int ImU32; +typedef int64_t ImS64; +typedef uint64_t ImU64; +typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); +typedef unsigned short ImDrawIdx; +struct ImBitVector; +struct ImRect; +struct ImDrawDataBuilder; +struct ImDrawListSharedData; +struct ImGuiColorMod; +struct ImGuiContext; +struct ImGuiContextHook; +struct ImGuiDataTypeInfo; +struct ImGuiGroupData; +struct ImGuiInputTextState; +struct ImGuiLastItemDataBackup; +struct ImGuiMenuColumns; +struct ImGuiNavMoveResult; +struct ImGuiMetricsConfig; +struct ImGuiNextWindowData; +struct ImGuiNextItemData; +struct ImGuiOldColumnData; +struct ImGuiOldColumns; +struct ImGuiPopupData; +struct ImGuiSettingsHandler; +struct ImGuiStackSizes; +struct ImGuiStyleMod; +struct ImGuiTabBar; +struct ImGuiTabItem; +struct ImGuiTable; +struct ImGuiTableColumn; +struct ImGuiTableSettings; +struct ImGuiTableColumnsSettings; +struct ImGuiWindow; +struct ImGuiWindowTempData; +struct ImGuiWindowSettings; +typedef int ImGuiLayoutType; +typedef int ImGuiItemFlags; +typedef int ImGuiItemStatusFlags; +typedef int ImGuiOldColumnFlags; +typedef int ImGuiNavHighlightFlags; +typedef int ImGuiNavDirSourceFlags; +typedef int ImGuiNavMoveFlags; +typedef int ImGuiNextItemDataFlags; +typedef int ImGuiNextWindowDataFlags; +typedef int ImGuiSeparatorFlags; +typedef int ImGuiTextFlags; +typedef int ImGuiTooltipFlags; +typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...); +extern ImGuiContext* GImGui; +typedef FILE* ImFileHandle; +typedef int ImPoolIdx; +typedef void (*ImGuiContextHookCallback)(ImGuiContext* ctx, ImGuiContextHook* hook); +typedef ImS8 ImGuiTableColumnIdx; +typedef ImU8 ImGuiTableDrawChannelIdx; +typedef struct ImVector{int Size;int Capacity;void* Data;} ImVector; +typedef struct ImVector_ImGuiTableSettings {int Size;int Capacity;ImGuiTableSettings* Data;} ImVector_ImGuiTableSettings; +typedef struct ImChunkStream_ImGuiTableSettings {ImVector_ImGuiTableSettings Buf;} ImChunkStream_ImGuiTableSettings; +typedef struct ImVector_ImGuiWindowSettings {int Size;int Capacity;ImGuiWindowSettings* Data;} ImVector_ImGuiWindowSettings; +typedef struct ImChunkStream_ImGuiWindowSettings {ImVector_ImGuiWindowSettings Buf;} ImChunkStream_ImGuiWindowSettings; +typedef struct ImSpan_ImGuiTableCellData {ImGuiTableCellData* Data;ImGuiTableCellData* DataEnd;} ImSpan_ImGuiTableCellData; +typedef struct ImSpan_ImGuiTableColumn {ImGuiTableColumn* Data;ImGuiTableColumn* DataEnd;} ImSpan_ImGuiTableColumn; +typedef struct ImSpan_ImGuiTableColumnIdx {ImGuiTableColumnIdx* Data;ImGuiTableColumnIdx* DataEnd;} ImSpan_ImGuiTableColumnIdx; +typedef struct ImVector_ImDrawChannel {int Size;int Capacity;ImDrawChannel* Data;} ImVector_ImDrawChannel; +typedef struct ImVector_ImDrawCmd {int Size;int Capacity;ImDrawCmd* Data;} ImVector_ImDrawCmd; +typedef struct ImVector_ImDrawIdx {int Size;int Capacity;ImDrawIdx* Data;} ImVector_ImDrawIdx; +typedef struct ImVector_ImDrawListPtr {int Size;int Capacity;ImDrawList** Data;} ImVector_ImDrawListPtr; +typedef struct ImVector_ImDrawVert {int Size;int Capacity;ImDrawVert* Data;} ImVector_ImDrawVert; +typedef struct ImVector_ImFontPtr {int Size;int Capacity;ImFont** Data;} ImVector_ImFontPtr; +typedef struct ImVector_ImFontAtlasCustomRect {int Size;int Capacity;ImFontAtlasCustomRect* Data;} ImVector_ImFontAtlasCustomRect; +typedef struct ImVector_ImFontConfig {int Size;int Capacity;ImFontConfig* Data;} ImVector_ImFontConfig; +typedef struct ImVector_ImFontGlyph {int Size;int Capacity;ImFontGlyph* Data;} ImVector_ImFontGlyph; +typedef struct ImVector_ImGuiColorMod {int Size;int Capacity;ImGuiColorMod* Data;} ImVector_ImGuiColorMod; +typedef struct ImVector_ImGuiContextHook {int Size;int Capacity;ImGuiContextHook* Data;} ImVector_ImGuiContextHook; +typedef struct ImVector_ImGuiGroupData {int Size;int Capacity;ImGuiGroupData* Data;} ImVector_ImGuiGroupData; +typedef struct ImVector_ImGuiID {int Size;int Capacity;ImGuiID* Data;} ImVector_ImGuiID; +typedef struct ImVector_ImGuiItemFlags {int Size;int Capacity;ImGuiItemFlags* Data;} ImVector_ImGuiItemFlags; +typedef struct ImVector_ImGuiOldColumnData {int Size;int Capacity;ImGuiOldColumnData* Data;} ImVector_ImGuiOldColumnData; +typedef struct ImVector_ImGuiOldColumns {int Size;int Capacity;ImGuiOldColumns* Data;} ImVector_ImGuiOldColumns; +typedef struct ImVector_ImGuiPopupData {int Size;int Capacity;ImGuiPopupData* Data;} ImVector_ImGuiPopupData; +typedef struct ImVector_ImGuiPtrOrIndex {int Size;int Capacity;ImGuiPtrOrIndex* Data;} ImVector_ImGuiPtrOrIndex; +typedef struct ImVector_ImGuiSettingsHandler {int Size;int Capacity;ImGuiSettingsHandler* Data;} ImVector_ImGuiSettingsHandler; +typedef struct ImVector_ImGuiShrinkWidthItem {int Size;int Capacity;ImGuiShrinkWidthItem* Data;} ImVector_ImGuiShrinkWidthItem; +typedef struct ImVector_ImGuiStoragePair {int Size;int Capacity;ImGuiStoragePair* Data;} ImVector_ImGuiStoragePair; +typedef struct ImVector_ImGuiStyleMod {int Size;int Capacity;ImGuiStyleMod* Data;} ImVector_ImGuiStyleMod; +typedef struct ImVector_ImGuiTabItem {int Size;int Capacity;ImGuiTabItem* Data;} ImVector_ImGuiTabItem; +typedef struct ImVector_ImGuiTableColumnSortSpecs {int Size;int Capacity;ImGuiTableColumnSortSpecs* Data;} ImVector_ImGuiTableColumnSortSpecs; +typedef struct ImVector_ImGuiTextRange {int Size;int Capacity;ImGuiTextRange* Data;} ImVector_ImGuiTextRange; +typedef struct ImVector_ImGuiViewportPPtr {int Size;int Capacity;ImGuiViewportP** Data;} ImVector_ImGuiViewportPPtr; +typedef struct ImVector_ImGuiWindowPtr {int Size;int Capacity;ImGuiWindow** Data;} ImVector_ImGuiWindowPtr; +typedef struct ImVector_ImTextureID {int Size;int Capacity;ImTextureID* Data;} ImVector_ImTextureID; +typedef struct ImVector_ImU32 {int Size;int Capacity;ImU32* Data;} ImVector_ImU32; +typedef struct ImVector_ImVec2 {int Size;int Capacity;ImVec2* Data;} ImVector_ImVec2; +typedef struct ImVector_ImVec4 {int Size;int Capacity;ImVec4* Data;} ImVector_ImVec4; +typedef struct ImVector_ImWchar {int Size;int Capacity;ImWchar* Data;} ImVector_ImWchar; +typedef struct ImVector_char {int Size;int Capacity;char* Data;} ImVector_char; +typedef struct ImVector_float {int Size;int Capacity;float* Data;} ImVector_float; +typedef struct ImVector_unsigned_char {int Size;int Capacity;unsigned char* Data;} ImVector_unsigned_char; + +struct ImVec2 +{ + float x, y; +}; +struct ImVec4 +{ + float x, y, z, w; +}; +typedef enum { + ImGuiWindowFlags_None = 0, + ImGuiWindowFlags_NoTitleBar = 1 << 0, + ImGuiWindowFlags_NoResize = 1 << 1, + ImGuiWindowFlags_NoMove = 1 << 2, + ImGuiWindowFlags_NoScrollbar = 1 << 3, + ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, + ImGuiWindowFlags_NoCollapse = 1 << 5, + ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, + ImGuiWindowFlags_NoBackground = 1 << 7, + ImGuiWindowFlags_NoSavedSettings = 1 << 8, + ImGuiWindowFlags_NoMouseInputs = 1 << 9, + ImGuiWindowFlags_MenuBar = 1 << 10, + ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, + ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, + ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, + ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, + ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, + ImGuiWindowFlags_NoNavInputs = 1 << 18, + ImGuiWindowFlags_NoNavFocus = 1 << 19, + ImGuiWindowFlags_UnsavedDocument = 1 << 20, + ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, + ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_NavFlattened = 1 << 23, + ImGuiWindowFlags_ChildWindow = 1 << 24, + ImGuiWindowFlags_Tooltip = 1 << 25, + ImGuiWindowFlags_Popup = 1 << 26, + ImGuiWindowFlags_Modal = 1 << 27, + ImGuiWindowFlags_ChildMenu = 1 << 28 +}ImGuiWindowFlags_; +typedef enum { + ImGuiInputTextFlags_None = 0, + ImGuiInputTextFlags_CharsDecimal = 1 << 0, + ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, + ImGuiInputTextFlags_CharsUppercase = 1 << 2, + ImGuiInputTextFlags_CharsNoBlank = 1 << 3, + ImGuiInputTextFlags_AutoSelectAll = 1 << 4, + ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, + ImGuiInputTextFlags_CallbackCompletion = 1 << 6, + ImGuiInputTextFlags_CallbackHistory = 1 << 7, + ImGuiInputTextFlags_CallbackAlways = 1 << 8, + ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, + ImGuiInputTextFlags_AllowTabInput = 1 << 10, + ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, + ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, + ImGuiInputTextFlags_AlwaysOverwrite = 1 << 13, + ImGuiInputTextFlags_ReadOnly = 1 << 14, + ImGuiInputTextFlags_Password = 1 << 15, + ImGuiInputTextFlags_NoUndoRedo = 1 << 16, + ImGuiInputTextFlags_CharsScientific = 1 << 17, + ImGuiInputTextFlags_CallbackResize = 1 << 18, + ImGuiInputTextFlags_CallbackEdit = 1 << 19, + ImGuiInputTextFlags_Multiline = 1 << 20, + ImGuiInputTextFlags_NoMarkEdited = 1 << 21 +}ImGuiInputTextFlags_; +typedef enum { + ImGuiTreeNodeFlags_None = 0, + ImGuiTreeNodeFlags_Selected = 1 << 0, + ImGuiTreeNodeFlags_Framed = 1 << 1, + ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, + ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, + ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, + ImGuiTreeNodeFlags_Leaf = 1 << 8, + ImGuiTreeNodeFlags_Bullet = 1 << 9, + ImGuiTreeNodeFlags_FramePadding = 1 << 10, + ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, + ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, + ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog +}ImGuiTreeNodeFlags_; +typedef enum { + ImGuiPopupFlags_None = 0, + ImGuiPopupFlags_MouseButtonLeft = 0, + ImGuiPopupFlags_MouseButtonRight = 1, + ImGuiPopupFlags_MouseButtonMiddle = 2, + ImGuiPopupFlags_MouseButtonMask_ = 0x1F, + ImGuiPopupFlags_MouseButtonDefault_ = 1, + ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 5, + ImGuiPopupFlags_NoOpenOverItems = 1 << 6, + ImGuiPopupFlags_AnyPopupId = 1 << 7, + ImGuiPopupFlags_AnyPopupLevel = 1 << 8, + ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel +}ImGuiPopupFlags_; +typedef enum { + ImGuiSelectableFlags_None = 0, + ImGuiSelectableFlags_DontClosePopups = 1 << 0, + ImGuiSelectableFlags_SpanAllColumns = 1 << 1, + ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, + ImGuiSelectableFlags_Disabled = 1 << 3, + ImGuiSelectableFlags_AllowItemOverlap = 1 << 4 +}ImGuiSelectableFlags_; +typedef enum { + ImGuiComboFlags_None = 0, + ImGuiComboFlags_PopupAlignLeft = 1 << 0, + ImGuiComboFlags_HeightSmall = 1 << 1, + ImGuiComboFlags_HeightRegular = 1 << 2, + ImGuiComboFlags_HeightLarge = 1 << 3, + ImGuiComboFlags_HeightLargest = 1 << 4, + ImGuiComboFlags_NoArrowButton = 1 << 5, + ImGuiComboFlags_NoPreview = 1 << 6, + ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest +}ImGuiComboFlags_; +typedef enum { + ImGuiTabBarFlags_None = 0, + ImGuiTabBarFlags_Reorderable = 1 << 0, + ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, + ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, + ImGuiTabBarFlags_NoTooltip = 1 << 5, + ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, + ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, + ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, + ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown +}ImGuiTabBarFlags_; +typedef enum { + ImGuiTabItemFlags_None = 0, + ImGuiTabItemFlags_UnsavedDocument = 1 << 0, + ImGuiTabItemFlags_SetSelected = 1 << 1, + ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, + ImGuiTabItemFlags_NoPushId = 1 << 3, + ImGuiTabItemFlags_NoTooltip = 1 << 4, + ImGuiTabItemFlags_NoReorder = 1 << 5, + ImGuiTabItemFlags_Leading = 1 << 6, + ImGuiTabItemFlags_Trailing = 1 << 7 +}ImGuiTabItemFlags_; +typedef enum { + ImGuiTableFlags_None = 0, + ImGuiTableFlags_Resizable = 1 << 0, + ImGuiTableFlags_Reorderable = 1 << 1, + ImGuiTableFlags_Hideable = 1 << 2, + ImGuiTableFlags_Sortable = 1 << 3, + ImGuiTableFlags_NoSavedSettings = 1 << 4, + ImGuiTableFlags_ContextMenuInBody = 1 << 5, + ImGuiTableFlags_RowBg = 1 << 6, + ImGuiTableFlags_BordersInnerH = 1 << 7, + ImGuiTableFlags_BordersOuterH = 1 << 8, + ImGuiTableFlags_BordersInnerV = 1 << 9, + ImGuiTableFlags_BordersOuterV = 1 << 10, + ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, + ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, + ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, + ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, + ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, + ImGuiTableFlags_NoBordersInBody = 1 << 11, + ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, + ImGuiTableFlags_SizingFixedFit = 1 << 13, + ImGuiTableFlags_SizingFixedSame = 2 << 13, + ImGuiTableFlags_SizingStretchProp = 3 << 13, + ImGuiTableFlags_SizingStretchSame = 4 << 13, + ImGuiTableFlags_NoHostExtendX = 1 << 16, + ImGuiTableFlags_NoHostExtendY = 1 << 17, + ImGuiTableFlags_NoKeepColumnsVisible = 1 << 18, + ImGuiTableFlags_PreciseWidths = 1 << 19, + ImGuiTableFlags_NoClip = 1 << 20, + ImGuiTableFlags_PadOuterX = 1 << 21, + ImGuiTableFlags_NoPadOuterX = 1 << 22, + ImGuiTableFlags_NoPadInnerX = 1 << 23, + ImGuiTableFlags_ScrollX = 1 << 24, + ImGuiTableFlags_ScrollY = 1 << 25, + ImGuiTableFlags_SortMulti = 1 << 26, + ImGuiTableFlags_SortTristate = 1 << 27, + ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame +}ImGuiTableFlags_; +typedef enum { + ImGuiTableColumnFlags_None = 0, + ImGuiTableColumnFlags_DefaultHide = 1 << 0, + ImGuiTableColumnFlags_DefaultSort = 1 << 1, + ImGuiTableColumnFlags_WidthStretch = 1 << 2, + ImGuiTableColumnFlags_WidthFixed = 1 << 3, + ImGuiTableColumnFlags_NoResize = 1 << 4, + ImGuiTableColumnFlags_NoReorder = 1 << 5, + ImGuiTableColumnFlags_NoHide = 1 << 6, + ImGuiTableColumnFlags_NoClip = 1 << 7, + ImGuiTableColumnFlags_NoSort = 1 << 8, + ImGuiTableColumnFlags_NoSortAscending = 1 << 9, + ImGuiTableColumnFlags_NoSortDescending = 1 << 10, + ImGuiTableColumnFlags_NoHeaderWidth = 1 << 11, + ImGuiTableColumnFlags_PreferSortAscending = 1 << 12, + ImGuiTableColumnFlags_PreferSortDescending = 1 << 13, + ImGuiTableColumnFlags_IndentEnable = 1 << 14, + ImGuiTableColumnFlags_IndentDisable = 1 << 15, + ImGuiTableColumnFlags_IsEnabled = 1 << 20, + ImGuiTableColumnFlags_IsVisible = 1 << 21, + ImGuiTableColumnFlags_IsSorted = 1 << 22, + ImGuiTableColumnFlags_IsHovered = 1 << 23, + ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed, + ImGuiTableColumnFlags_IndentMask_ = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_IndentDisable, + ImGuiTableColumnFlags_StatusMask_ = ImGuiTableColumnFlags_IsEnabled | ImGuiTableColumnFlags_IsVisible | ImGuiTableColumnFlags_IsSorted | ImGuiTableColumnFlags_IsHovered, + ImGuiTableColumnFlags_NoDirectResize_ = 1 << 30 +}ImGuiTableColumnFlags_; +typedef enum { + ImGuiTableRowFlags_None = 0, + ImGuiTableRowFlags_Headers = 1 << 0 +}ImGuiTableRowFlags_; +typedef enum { + ImGuiTableBgTarget_None = 0, + ImGuiTableBgTarget_RowBg0 = 1, + ImGuiTableBgTarget_RowBg1 = 2, + ImGuiTableBgTarget_CellBg = 3 +}ImGuiTableBgTarget_; +typedef enum { + ImGuiFocusedFlags_None = 0, + ImGuiFocusedFlags_ChildWindows = 1 << 0, + ImGuiFocusedFlags_RootWindow = 1 << 1, + ImGuiFocusedFlags_AnyWindow = 1 << 2, + ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows +}ImGuiFocusedFlags_; +typedef enum { + ImGuiHoveredFlags_None = 0, + ImGuiHoveredFlags_ChildWindows = 1 << 0, + ImGuiHoveredFlags_RootWindow = 1 << 1, + ImGuiHoveredFlags_AnyWindow = 1 << 2, + ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 3, + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5, + ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 6, + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 7, + ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, + ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows +}ImGuiHoveredFlags_; +typedef enum { + ImGuiDragDropFlags_None = 0, + ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, + ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, + ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, + ImGuiDragDropFlags_SourceExtern = 1 << 4, + ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, + ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect +}ImGuiDragDropFlags_; +typedef enum { + ImGuiDataType_S8, + ImGuiDataType_U8, + ImGuiDataType_S16, + ImGuiDataType_U16, + ImGuiDataType_S32, + ImGuiDataType_U32, + ImGuiDataType_S64, + ImGuiDataType_U64, + ImGuiDataType_Float, + ImGuiDataType_Double, + ImGuiDataType_COUNT +}ImGuiDataType_; +typedef enum { + ImGuiDir_None = -1, + ImGuiDir_Left = 0, + ImGuiDir_Right = 1, + ImGuiDir_Up = 2, + ImGuiDir_Down = 3, + ImGuiDir_COUNT +}ImGuiDir_; +typedef enum { + ImGuiSortDirection_None = 0, + ImGuiSortDirection_Ascending = 1, + ImGuiSortDirection_Descending = 2 +}ImGuiSortDirection_; +typedef enum { + ImGuiKey_Tab, + ImGuiKey_LeftArrow, + ImGuiKey_RightArrow, + ImGuiKey_UpArrow, + ImGuiKey_DownArrow, + ImGuiKey_PageUp, + ImGuiKey_PageDown, + ImGuiKey_Home, + ImGuiKey_End, + ImGuiKey_Insert, + ImGuiKey_Delete, + ImGuiKey_Backspace, + ImGuiKey_Space, + ImGuiKey_Enter, + ImGuiKey_Escape, + ImGuiKey_KeyPadEnter, + ImGuiKey_A, + ImGuiKey_C, + ImGuiKey_V, + ImGuiKey_X, + ImGuiKey_Y, + ImGuiKey_Z, + ImGuiKey_COUNT +}ImGuiKey_; +typedef enum { + ImGuiKeyModFlags_None = 0, + ImGuiKeyModFlags_Ctrl = 1 << 0, + ImGuiKeyModFlags_Shift = 1 << 1, + ImGuiKeyModFlags_Alt = 1 << 2, + ImGuiKeyModFlags_Super = 1 << 3 +}ImGuiKeyModFlags_; +typedef enum { + ImGuiNavInput_Activate, + ImGuiNavInput_Cancel, + ImGuiNavInput_Input, + ImGuiNavInput_Menu, + ImGuiNavInput_DpadLeft, + ImGuiNavInput_DpadRight, + ImGuiNavInput_DpadUp, + ImGuiNavInput_DpadDown, + ImGuiNavInput_LStickLeft, + ImGuiNavInput_LStickRight, + ImGuiNavInput_LStickUp, + ImGuiNavInput_LStickDown, + ImGuiNavInput_FocusPrev, + ImGuiNavInput_FocusNext, + ImGuiNavInput_TweakSlow, + ImGuiNavInput_TweakFast, + ImGuiNavInput_KeyMenu_, + ImGuiNavInput_KeyLeft_, + ImGuiNavInput_KeyRight_, + ImGuiNavInput_KeyUp_, + ImGuiNavInput_KeyDown_, + ImGuiNavInput_COUNT, + ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyMenu_ +}ImGuiNavInput_; +typedef enum { + ImGuiConfigFlags_None = 0, + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, + ImGuiConfigFlags_NavEnableGamepad = 1 << 1, + ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, + ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, + ImGuiConfigFlags_NoMouse = 1 << 4, + ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, + ImGuiConfigFlags_IsSRGB = 1 << 20, + ImGuiConfigFlags_IsTouchScreen = 1 << 21 +}ImGuiConfigFlags_; +typedef enum { + ImGuiBackendFlags_None = 0, + ImGuiBackendFlags_HasGamepad = 1 << 0, + ImGuiBackendFlags_HasMouseCursors = 1 << 1, + ImGuiBackendFlags_HasSetMousePos = 1 << 2, + ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 +}ImGuiBackendFlags_; +typedef enum { + ImGuiCol_Text, + ImGuiCol_TextDisabled, + ImGuiCol_WindowBg, + ImGuiCol_ChildBg, + ImGuiCol_PopupBg, + ImGuiCol_Border, + ImGuiCol_BorderShadow, + ImGuiCol_FrameBg, + ImGuiCol_FrameBgHovered, + ImGuiCol_FrameBgActive, + ImGuiCol_TitleBg, + ImGuiCol_TitleBgActive, + ImGuiCol_TitleBgCollapsed, + ImGuiCol_MenuBarBg, + ImGuiCol_ScrollbarBg, + ImGuiCol_ScrollbarGrab, + ImGuiCol_ScrollbarGrabHovered, + ImGuiCol_ScrollbarGrabActive, + ImGuiCol_CheckMark, + ImGuiCol_SliderGrab, + ImGuiCol_SliderGrabActive, + ImGuiCol_Button, + ImGuiCol_ButtonHovered, + ImGuiCol_ButtonActive, + ImGuiCol_Header, + ImGuiCol_HeaderHovered, + ImGuiCol_HeaderActive, + ImGuiCol_Separator, + ImGuiCol_SeparatorHovered, + ImGuiCol_SeparatorActive, + ImGuiCol_ResizeGrip, + ImGuiCol_ResizeGripHovered, + ImGuiCol_ResizeGripActive, + ImGuiCol_Tab, + ImGuiCol_TabHovered, + ImGuiCol_TabActive, + ImGuiCol_TabUnfocused, + ImGuiCol_TabUnfocusedActive, + ImGuiCol_PlotLines, + ImGuiCol_PlotLinesHovered, + ImGuiCol_PlotHistogram, + ImGuiCol_PlotHistogramHovered, + ImGuiCol_TableHeaderBg, + ImGuiCol_TableBorderStrong, + ImGuiCol_TableBorderLight, + ImGuiCol_TableRowBg, + ImGuiCol_TableRowBgAlt, + ImGuiCol_TextSelectedBg, + ImGuiCol_DragDropTarget, + ImGuiCol_NavHighlight, + ImGuiCol_NavWindowingHighlight, + ImGuiCol_NavWindowingDimBg, + ImGuiCol_ModalWindowDimBg, + ImGuiCol_COUNT +}ImGuiCol_; +typedef enum { + ImGuiStyleVar_Alpha, + ImGuiStyleVar_WindowPadding, + ImGuiStyleVar_WindowRounding, + ImGuiStyleVar_WindowBorderSize, + ImGuiStyleVar_WindowMinSize, + ImGuiStyleVar_WindowTitleAlign, + ImGuiStyleVar_ChildRounding, + ImGuiStyleVar_ChildBorderSize, + ImGuiStyleVar_PopupRounding, + ImGuiStyleVar_PopupBorderSize, + ImGuiStyleVar_FramePadding, + ImGuiStyleVar_FrameRounding, + ImGuiStyleVar_FrameBorderSize, + ImGuiStyleVar_ItemSpacing, + ImGuiStyleVar_ItemInnerSpacing, + ImGuiStyleVar_IndentSpacing, + ImGuiStyleVar_CellPadding, + ImGuiStyleVar_ScrollbarSize, + ImGuiStyleVar_ScrollbarRounding, + ImGuiStyleVar_GrabMinSize, + ImGuiStyleVar_GrabRounding, + ImGuiStyleVar_TabRounding, + ImGuiStyleVar_ButtonTextAlign, + ImGuiStyleVar_SelectableTextAlign, + ImGuiStyleVar_COUNT +}ImGuiStyleVar_; +typedef enum { + ImGuiButtonFlags_None = 0, + ImGuiButtonFlags_MouseButtonLeft = 1 << 0, + ImGuiButtonFlags_MouseButtonRight = 1 << 1, + ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, + ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, + ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft +}ImGuiButtonFlags_; +typedef enum { + ImGuiColorEditFlags_None = 0, + ImGuiColorEditFlags_NoAlpha = 1 << 1, + ImGuiColorEditFlags_NoPicker = 1 << 2, + ImGuiColorEditFlags_NoOptions = 1 << 3, + ImGuiColorEditFlags_NoSmallPreview = 1 << 4, + ImGuiColorEditFlags_NoInputs = 1 << 5, + ImGuiColorEditFlags_NoTooltip = 1 << 6, + ImGuiColorEditFlags_NoLabel = 1 << 7, + ImGuiColorEditFlags_NoSidePreview = 1 << 8, + ImGuiColorEditFlags_NoDragDrop = 1 << 9, + ImGuiColorEditFlags_NoBorder = 1 << 10, + ImGuiColorEditFlags_AlphaBar = 1 << 16, + ImGuiColorEditFlags_AlphaPreview = 1 << 17, + ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, + ImGuiColorEditFlags_HDR = 1 << 19, + ImGuiColorEditFlags_DisplayRGB = 1 << 20, + ImGuiColorEditFlags_DisplayHSV = 1 << 21, + ImGuiColorEditFlags_DisplayHex = 1 << 22, + ImGuiColorEditFlags_Uint8 = 1 << 23, + ImGuiColorEditFlags_Float = 1 << 24, + ImGuiColorEditFlags_PickerHueBar = 1 << 25, + ImGuiColorEditFlags_PickerHueWheel = 1 << 26, + ImGuiColorEditFlags_InputRGB = 1 << 27, + ImGuiColorEditFlags_InputHSV = 1 << 28, + ImGuiColorEditFlags__OptionsDefault = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags__DisplayMask = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex, + ImGuiColorEditFlags__DataTypeMask = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, + ImGuiColorEditFlags__PickerMask = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags__InputMask = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV +}ImGuiColorEditFlags_; +typedef enum { + ImGuiSliderFlags_None = 0, + ImGuiSliderFlags_AlwaysClamp = 1 << 4, + ImGuiSliderFlags_Logarithmic = 1 << 5, + ImGuiSliderFlags_NoRoundToFormat = 1 << 6, + ImGuiSliderFlags_NoInput = 1 << 7, + ImGuiSliderFlags_InvalidMask_ = 0x7000000F +}ImGuiSliderFlags_; +typedef enum { + ImGuiMouseButton_Left = 0, + ImGuiMouseButton_Right = 1, + ImGuiMouseButton_Middle = 2, + ImGuiMouseButton_COUNT = 5 +}ImGuiMouseButton_; +typedef enum { + ImGuiMouseCursor_None = -1, + ImGuiMouseCursor_Arrow = 0, + ImGuiMouseCursor_TextInput, + ImGuiMouseCursor_ResizeAll, + ImGuiMouseCursor_ResizeNS, + ImGuiMouseCursor_ResizeEW, + ImGuiMouseCursor_ResizeNESW, + ImGuiMouseCursor_ResizeNWSE, + ImGuiMouseCursor_Hand, + ImGuiMouseCursor_NotAllowed, + ImGuiMouseCursor_COUNT +}ImGuiMouseCursor_; +typedef enum { + ImGuiCond_None = 0, + ImGuiCond_Always = 1 << 0, + ImGuiCond_Once = 1 << 1, + ImGuiCond_FirstUseEver = 1 << 2, + ImGuiCond_Appearing = 1 << 3 +}ImGuiCond_; +struct ImGuiStyle +{ + float Alpha; + ImVec2 WindowPadding; + float WindowRounding; + float WindowBorderSize; + ImVec2 WindowMinSize; + ImVec2 WindowTitleAlign; + ImGuiDir WindowMenuButtonPosition; + float ChildRounding; + float ChildBorderSize; + float PopupRounding; + float PopupBorderSize; + ImVec2 FramePadding; + float FrameRounding; + float FrameBorderSize; + ImVec2 ItemSpacing; + ImVec2 ItemInnerSpacing; + ImVec2 CellPadding; + ImVec2 TouchExtraPadding; + float IndentSpacing; + float ColumnsMinSpacing; + float ScrollbarSize; + float ScrollbarRounding; + float GrabMinSize; + float GrabRounding; + float LogSliderDeadzone; + float TabRounding; + float TabBorderSize; + float TabMinWidthForCloseButton; + ImGuiDir ColorButtonPosition; + ImVec2 ButtonTextAlign; + ImVec2 SelectableTextAlign; + ImVec2 DisplayWindowPadding; + ImVec2 DisplaySafeAreaPadding; + float MouseCursorScale; + bool AntiAliasedLines; + bool AntiAliasedLinesUseTex; + bool AntiAliasedFill; + float CurveTessellationTol; + float CircleTessellationMaxError; + ImVec4 Colors[ImGuiCol_COUNT]; +}; +struct ImGuiIO +{ + ImGuiConfigFlags ConfigFlags; + ImGuiBackendFlags BackendFlags; + ImVec2 DisplaySize; + float DeltaTime; + float IniSavingRate; + const char* IniFilename; + const char* LogFilename; + float MouseDoubleClickTime; + float MouseDoubleClickMaxDist; + float MouseDragThreshold; + int KeyMap[ImGuiKey_COUNT]; + float KeyRepeatDelay; + float KeyRepeatRate; + void* UserData; + ImFontAtlas*Fonts; + float FontGlobalScale; + bool FontAllowUserScaling; + ImFont* FontDefault; + ImVec2 DisplayFramebufferScale; + bool MouseDrawCursor; + bool ConfigMacOSXBehaviors; + bool ConfigInputTextCursorBlink; + bool ConfigDragClickToInputText; + bool ConfigWindowsResizeFromEdges; + bool ConfigWindowsMoveFromTitleBarOnly; + float ConfigMemoryCompactTimer; + const char* BackendPlatformName; + const char* BackendRendererName; + void* BackendPlatformUserData; + void* BackendRendererUserData; + void* BackendLanguageUserData; + const char* (*GetClipboardTextFn)(void* user_data); + void (*SetClipboardTextFn)(void* user_data, const char* text); + void* ClipboardUserData; + void (*ImeSetInputScreenPosFn)(int x, int y); + void* ImeWindowHandle; + ImVec2 MousePos; + bool MouseDown[5]; + float MouseWheel; + float MouseWheelH; + bool KeyCtrl; + bool KeyShift; + bool KeyAlt; + bool KeySuper; + bool KeysDown[512]; + float NavInputs[ImGuiNavInput_COUNT]; + bool WantCaptureMouse; + bool WantCaptureKeyboard; + bool WantTextInput; + bool WantSetMousePos; + bool WantSaveIniSettings; + bool NavActive; + bool NavVisible; + float Framerate; + int MetricsRenderVertices; + int MetricsRenderIndices; + int MetricsRenderWindows; + int MetricsActiveWindows; + int MetricsActiveAllocations; + ImVec2 MouseDelta; + ImGuiKeyModFlags KeyMods; + ImVec2 MousePosPrev; + ImVec2 MouseClickedPos[5]; + double MouseClickedTime[5]; + bool MouseClicked[5]; + bool MouseDoubleClicked[5]; + bool MouseReleased[5]; + bool MouseDownOwned[5]; + bool MouseDownWasDoubleClick[5]; + float MouseDownDuration[5]; + float MouseDownDurationPrev[5]; + ImVec2 MouseDragMaxDistanceAbs[5]; + float MouseDragMaxDistanceSqr[5]; + float KeysDownDuration[512]; + float KeysDownDurationPrev[512]; + float NavInputsDownDuration[ImGuiNavInput_COUNT]; + float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; + float PenPressure; + ImWchar16 InputQueueSurrogate; + ImVector_ImWchar InputQueueCharacters; +}; +struct ImGuiInputTextCallbackData +{ + ImGuiInputTextFlags EventFlag; + ImGuiInputTextFlags Flags; + void* UserData; + ImWchar EventChar; + ImGuiKey EventKey; + char* Buf; + int BufTextLen; + int BufSize; + bool BufDirty; + int CursorPos; + int SelectionStart; + int SelectionEnd; +}; +struct ImGuiSizeCallbackData +{ + void* UserData; + ImVec2 Pos; + ImVec2 CurrentSize; + ImVec2 DesiredSize; +}; +struct ImGuiPayload +{ + void* Data; + int DataSize; + ImGuiID SourceId; + ImGuiID SourceParentId; + int DataFrameCount; + char DataType[32 + 1]; + bool Preview; + bool Delivery; +}; +struct ImGuiTableColumnSortSpecs +{ + ImGuiID ColumnUserID; + ImS16 ColumnIndex; + ImS16 SortOrder; + ImGuiSortDirection SortDirection : 8; +}; +struct ImGuiTableSortSpecs +{ + const ImGuiTableColumnSortSpecs* Specs; + int SpecsCount; + bool SpecsDirty; +}; +struct ImGuiOnceUponAFrame +{ + int RefFrame; +}; +struct ImGuiTextRange +{ + const char* b; + const char* e; +}; +struct ImGuiTextFilter +{ + char InputBuf[256]; + ImVector_ImGuiTextRange Filters; + int CountGrep; +}; +struct ImGuiTextBuffer +{ + ImVector_char Buf; +}; +struct ImGuiStoragePair +{ + ImGuiID key; + union { int val_i; float val_f; void* val_p; }; +}; +struct ImGuiStorage +{ + ImVector_ImGuiStoragePair Data; +}; +typedef struct ImVector_ImGuiTabBar {int Size;int Capacity;ImGuiTabBar* Data;} ImVector_ImGuiTabBar; +typedef struct ImPool_ImGuiTabBar {ImVector_ImGuiTabBar Buf;ImGuiStorage Map;ImPoolIdx FreeIdx;} ImPool_ImGuiTabBar; +typedef struct ImVector_ImGuiTable {int Size;int Capacity;ImGuiTable* Data;} ImVector_ImGuiTable; +typedef struct ImPool_ImGuiTable {ImVector_ImGuiTable Buf;ImGuiStorage Map;ImPoolIdx FreeIdx;} ImPool_ImGuiTable; +struct ImGuiListClipper +{ + int DisplayStart; + int DisplayEnd; + int ItemsCount; + int StepNo; + int ItemsFrozen; + float ItemsHeight; + float StartPosY; +}; +struct ImColor +{ + ImVec4 Value; +}; +struct ImDrawCmd +{ + ImVec4 ClipRect; + ImTextureID TextureId; + unsigned int VtxOffset; + unsigned int IdxOffset; + unsigned int ElemCount; + ImDrawCallback UserCallback; + void* UserCallbackData; +}; +struct ImDrawVert +{ + ImVec2 pos; + ImVec2 uv; + ImU32 col; +}; +struct ImDrawCmdHeader +{ + ImVec4 ClipRect; + ImTextureID TextureId; + unsigned int VtxOffset; +}; +struct ImDrawChannel +{ + ImVector_ImDrawCmd _CmdBuffer; + ImVector_ImDrawIdx _IdxBuffer; +}; +struct ImDrawListSplitter +{ + int _Current; + int _Count; + ImVector_ImDrawChannel _Channels; +}; +typedef enum { + ImDrawFlags_None = 0, + ImDrawFlags_Closed = 1 << 0, + ImDrawFlags_RoundCornersTopLeft = 1 << 4, + ImDrawFlags_RoundCornersTopRight = 1 << 5, + ImDrawFlags_RoundCornersBottomLeft = 1 << 6, + ImDrawFlags_RoundCornersBottomRight = 1 << 7, + ImDrawFlags_RoundCornersNone = 1 << 8, + ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft, + ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, + ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone +}ImDrawFlags_; +typedef enum { + ImDrawListFlags_None = 0, + ImDrawListFlags_AntiAliasedLines = 1 << 0, + ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, + ImDrawListFlags_AntiAliasedFill = 1 << 2, + ImDrawListFlags_AllowVtxOffset = 1 << 3 +}ImDrawListFlags_; +struct ImDrawList +{ + ImVector_ImDrawCmd CmdBuffer; + ImVector_ImDrawIdx IdxBuffer; + ImVector_ImDrawVert VtxBuffer; + ImDrawListFlags Flags; + unsigned int _VtxCurrentIdx; + const ImDrawListSharedData* _Data; + const char* _OwnerName; + ImDrawVert* _VtxWritePtr; + ImDrawIdx* _IdxWritePtr; + ImVector_ImVec4 _ClipRectStack; + ImVector_ImTextureID _TextureIdStack; + ImVector_ImVec2 _Path; + ImDrawCmdHeader _CmdHeader; + ImDrawListSplitter _Splitter; + float _FringeScale; +}; +struct ImDrawData +{ + bool Valid; + int CmdListsCount; + int TotalIdxCount; + int TotalVtxCount; + ImDrawList** CmdLists; + ImVec2 DisplayPos; + ImVec2 DisplaySize; + ImVec2 FramebufferScale; +}; +struct ImFontConfig +{ + void* FontData; + int FontDataSize; + bool FontDataOwnedByAtlas; + int FontNo; + float SizePixels; + int OversampleH; + int OversampleV; + bool PixelSnapH; + ImVec2 GlyphExtraSpacing; + ImVec2 GlyphOffset; + const ImWchar* GlyphRanges; + float GlyphMinAdvanceX; + float GlyphMaxAdvanceX; + bool MergeMode; + unsigned int FontBuilderFlags; + float RasterizerMultiply; + ImWchar EllipsisChar; + char Name[40]; + ImFont* DstFont; +}; +struct ImFontGlyph +{ + unsigned int Colored : 1; + unsigned int Visible : 1; + unsigned int Codepoint : 30; + float AdvanceX; + float X0, Y0, X1, Y1; + float U0, V0, U1, V1; +}; +struct ImFontGlyphRangesBuilder +{ + ImVector_ImU32 UsedChars; +}; +struct ImFontAtlasCustomRect +{ + unsigned short Width, Height; + unsigned short X, Y; + unsigned int GlyphID; + float GlyphAdvanceX; + ImVec2 GlyphOffset; + ImFont* Font; +}; +typedef enum { + ImFontAtlasFlags_None = 0, + ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, + ImFontAtlasFlags_NoMouseCursors = 1 << 1, + ImFontAtlasFlags_NoBakedLines = 1 << 2 +}ImFontAtlasFlags_; +struct ImFontAtlas +{ + ImFontAtlasFlags Flags; + ImTextureID TexID; + int TexDesiredWidth; + int TexGlyphPadding; + bool Locked; + bool TexPixelsUseColors; + unsigned char* TexPixelsAlpha8; + unsigned int* TexPixelsRGBA32; + int TexWidth; + int TexHeight; + ImVec2 TexUvScale; + ImVec2 TexUvWhitePixel; + ImVector_ImFontPtr Fonts; + ImVector_ImFontAtlasCustomRect CustomRects; + ImVector_ImFontConfig ConfigData; + ImVec4 TexUvLines[(63) + 1]; + const ImFontBuilderIO* FontBuilderIO; + unsigned int FontBuilderFlags; + int PackIdMouseCursors; + int PackIdLines; +}; +struct ImFont +{ + ImVector_float IndexAdvanceX; + float FallbackAdvanceX; + float FontSize; + ImVector_ImWchar IndexLookup; + ImVector_ImFontGlyph Glyphs; + const ImFontGlyph* FallbackGlyph; + ImFontAtlas* ContainerAtlas; + const ImFontConfig* ConfigData; + short ConfigDataCount; + ImWchar FallbackChar; + ImWchar EllipsisChar; + bool DirtyLookupTables; + float Scale; + float Ascent, Descent; + int MetricsTotalSurface; + ImU8 Used4kPagesMap[(0xFFFF +1)/4096/8]; +}; +typedef enum { + ImGuiViewportFlags_None = 0, + ImGuiViewportFlags_IsPlatformWindow = 1 << 0, + ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, + ImGuiViewportFlags_OwnedByApp = 1 << 2 +}ImGuiViewportFlags_; +struct ImGuiViewport +{ + ImGuiViewportFlags Flags; + ImVec2 Pos; + ImVec2 Size; + ImVec2 WorkPos; + ImVec2 WorkSize; +}; +struct StbUndoRecord +{ + int where; + int insert_length; + int delete_length; + int char_storage; +}; +struct StbUndoState +{ + StbUndoRecord undo_rec [99]; + ImWchar undo_char[999]; + short undo_point, redo_point; + int undo_char_point, redo_char_point; +}; +struct STB_TexteditState +{ + int cursor; + int select_start; + int select_end; + unsigned char insert_mode; + int row_count_per_page; + unsigned char cursor_at_end_of_line; + unsigned char initialized; + unsigned char has_preferred_x; + unsigned char single_line; + unsigned char padding1, padding2, padding3; + float preferred_x; + StbUndoState undostate; +}; +struct StbTexteditRow +{ + float x0,x1; + float baseline_y_delta; + float ymin,ymax; + int num_chars; +}; +struct ImVec1 +{ + float x; +}; +struct ImVec2ih +{ + short x, y; +}; +struct ImRect +{ + ImVec2 Min; + ImVec2 Max; +}; +struct ImBitVector +{ + ImVector_ImU32 Storage; +}; +struct ImDrawListSharedData +{ + ImVec2 TexUvWhitePixel; + ImFont* Font; + float FontSize; + float CurveTessellationTol; + float CircleSegmentMaxError; + ImVec4 ClipRectFullscreen; + ImDrawListFlags InitialFlags; + ImVec2 ArcFastVtx[48]; + float ArcFastRadiusCutoff; + ImU8 CircleSegmentCounts[64]; + const ImVec4* TexUvLines; +}; +struct ImDrawDataBuilder +{ + ImVector_ImDrawListPtr Layers[2]; +}; +typedef enum { + ImGuiItemFlags_None = 0, + ImGuiItemFlags_NoTabStop = 1 << 0, + ImGuiItemFlags_ButtonRepeat = 1 << 1, + ImGuiItemFlags_Disabled = 1 << 2, + ImGuiItemFlags_NoNav = 1 << 3, + ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, + ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, + ImGuiItemFlags_MixedValue = 1 << 6, + ImGuiItemFlags_ReadOnly = 1 << 7, + ImGuiItemFlags_Default_ = 0 +}ImGuiItemFlags_; +typedef enum { + ImGuiItemStatusFlags_None = 0, + ImGuiItemStatusFlags_HoveredRect = 1 << 0, + ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, + ImGuiItemStatusFlags_Edited = 1 << 2, + ImGuiItemStatusFlags_ToggledSelection = 1 << 3, + ImGuiItemStatusFlags_ToggledOpen = 1 << 4, + ImGuiItemStatusFlags_HasDeactivated = 1 << 5, + ImGuiItemStatusFlags_Deactivated = 1 << 6, + ImGuiItemStatusFlags_HoveredWindow = 1 << 7 +}ImGuiItemStatusFlags_; +typedef enum { + ImGuiButtonFlags_PressedOnClick = 1 << 4, + ImGuiButtonFlags_PressedOnClickRelease = 1 << 5, + ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, + ImGuiButtonFlags_PressedOnRelease = 1 << 7, + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, + ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, + ImGuiButtonFlags_Repeat = 1 << 10, + ImGuiButtonFlags_FlattenChildren = 1 << 11, + ImGuiButtonFlags_AllowItemOverlap = 1 << 12, + ImGuiButtonFlags_DontClosePopups = 1 << 13, + ImGuiButtonFlags_Disabled = 1 << 14, + ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, + ImGuiButtonFlags_NoKeyModifiers = 1 << 16, + ImGuiButtonFlags_NoHoldingActiveId = 1 << 17, + ImGuiButtonFlags_NoNavFocus = 1 << 18, + ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, + ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, + ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease +}ImGuiButtonFlagsPrivate_; +typedef enum { + ImGuiSliderFlags_Vertical = 1 << 20, + ImGuiSliderFlags_ReadOnly = 1 << 21 +}ImGuiSliderFlagsPrivate_; +typedef enum { + ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20, + ImGuiSelectableFlags_SelectOnClick = 1 << 21, + ImGuiSelectableFlags_SelectOnRelease = 1 << 22, + ImGuiSelectableFlags_SpanAvailWidth = 1 << 23, + ImGuiSelectableFlags_DrawHoveredWhenHeld = 1 << 24, + ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25, + ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 26 +}ImGuiSelectableFlagsPrivate_; +typedef enum { + ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20 +}ImGuiTreeNodeFlagsPrivate_; +typedef enum { + ImGuiSeparatorFlags_None = 0, + ImGuiSeparatorFlags_Horizontal = 1 << 0, + ImGuiSeparatorFlags_Vertical = 1 << 1, + ImGuiSeparatorFlags_SpanAllColumns = 1 << 2 +}ImGuiSeparatorFlags_; +typedef enum { + ImGuiTextFlags_None = 0, + ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0 +}ImGuiTextFlags_; +typedef enum { + ImGuiTooltipFlags_None = 0, + ImGuiTooltipFlags_OverridePreviousTooltip = 1 << 0 +}ImGuiTooltipFlags_; +typedef enum { + ImGuiLayoutType_Horizontal = 0, + ImGuiLayoutType_Vertical = 1 +}ImGuiLayoutType_; +typedef enum { + ImGuiLogType_None = 0, + ImGuiLogType_TTY, + ImGuiLogType_File, + ImGuiLogType_Buffer, + ImGuiLogType_Clipboard +}ImGuiLogType; +typedef enum { + ImGuiAxis_None = -1, + ImGuiAxis_X = 0, + ImGuiAxis_Y = 1 +}ImGuiAxis; +typedef enum { + ImGuiPlotType_Lines, + ImGuiPlotType_Histogram +}ImGuiPlotType; +typedef enum { + ImGuiInputSource_None = 0, + ImGuiInputSource_Mouse, + ImGuiInputSource_Keyboard, + ImGuiInputSource_Gamepad, + ImGuiInputSource_Nav, + ImGuiInputSource_COUNT +}ImGuiInputSource; +typedef enum { + ImGuiInputReadMode_Down, + ImGuiInputReadMode_Pressed, + ImGuiInputReadMode_Released, + ImGuiInputReadMode_Repeat, + ImGuiInputReadMode_RepeatSlow, + ImGuiInputReadMode_RepeatFast +}ImGuiInputReadMode; +typedef enum { + ImGuiNavHighlightFlags_None = 0, + ImGuiNavHighlightFlags_TypeDefault = 1 << 0, + ImGuiNavHighlightFlags_TypeThin = 1 << 1, + ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, + ImGuiNavHighlightFlags_NoRounding = 1 << 3 +}ImGuiNavHighlightFlags_; +typedef enum { + ImGuiNavDirSourceFlags_None = 0, + ImGuiNavDirSourceFlags_Keyboard = 1 << 0, + ImGuiNavDirSourceFlags_PadDPad = 1 << 1, + ImGuiNavDirSourceFlags_PadLStick = 1 << 2 +}ImGuiNavDirSourceFlags_; +typedef enum { + ImGuiNavMoveFlags_None = 0, + ImGuiNavMoveFlags_LoopX = 1 << 0, + ImGuiNavMoveFlags_LoopY = 1 << 1, + ImGuiNavMoveFlags_WrapX = 1 << 2, + ImGuiNavMoveFlags_WrapY = 1 << 3, + ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, + ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, + ImGuiNavMoveFlags_ScrollToEdge = 1 << 6 +}ImGuiNavMoveFlags_; +typedef enum { + ImGuiNavForward_None, + ImGuiNavForward_ForwardQueued, + ImGuiNavForward_ForwardActive +}ImGuiNavForward; +typedef enum { + ImGuiNavLayer_Main = 0, + ImGuiNavLayer_Menu = 1, + ImGuiNavLayer_COUNT +}ImGuiNavLayer; +typedef enum { + ImGuiPopupPositionPolicy_Default, + ImGuiPopupPositionPolicy_ComboBox, + ImGuiPopupPositionPolicy_Tooltip +}ImGuiPopupPositionPolicy; +struct ImGuiDataTypeTempStorage +{ + ImU8 Data[8]; +}; +struct ImGuiDataTypeInfo +{ + size_t Size; + const char* Name; + const char* PrintFmt; + const char* ScanFmt; +}; +typedef enum { + ImGuiDataType_String = ImGuiDataType_COUNT + 1, + ImGuiDataType_Pointer, + ImGuiDataType_ID +}ImGuiDataTypePrivate_; +struct ImGuiColorMod +{ + ImGuiCol Col; + ImVec4 BackupValue; +}; +struct ImGuiStyleMod +{ + ImGuiStyleVar VarIdx; + union { int BackupInt[2]; float BackupFloat[2]; }; +}; +struct ImGuiGroupData +{ + ImGuiID WindowID; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec1 BackupIndent; + ImVec1 BackupGroupOffset; + ImVec2 BackupCurrLineSize; + float BackupCurrLineTextBaseOffset; + ImGuiID BackupActiveIdIsAlive; + bool BackupActiveIdPreviousFrameIsAlive; + bool BackupHoveredIdIsAlive; + bool EmitItem; +}; +struct ImGuiMenuColumns +{ + float Spacing; + float Width, NextWidth; + float Pos[3], NextWidths[3]; +}; +struct ImGuiInputTextState +{ + ImGuiID ID; + int CurLenW, CurLenA; + ImVector_ImWchar TextW; + ImVector_char TextA; + ImVector_char InitialTextA; + bool TextAIsValid; + int BufCapacityA; + float ScrollX; + STB_TexteditState Stb; + float CursorAnim; + bool CursorFollow; + bool SelectedAllMouseLock; + bool Edited; + ImGuiInputTextFlags UserFlags; + ImGuiInputTextCallback UserCallback; + void* UserCallbackData; +}; +struct ImGuiPopupData +{ + ImGuiID PopupId; + ImGuiWindow* Window; + ImGuiWindow* SourceWindow; + int OpenFrameCount; + ImGuiID OpenParentId; + ImVec2 OpenPopupPos; + ImVec2 OpenMousePos; +}; +struct ImGuiNavMoveResult +{ + ImGuiWindow* Window; + ImGuiID ID; + ImGuiID FocusScopeId; + float DistBox; + float DistCenter; + float DistAxial; + ImRect RectRel; +}; +typedef enum { + ImGuiNextWindowDataFlags_None = 0, + ImGuiNextWindowDataFlags_HasPos = 1 << 0, + ImGuiNextWindowDataFlags_HasSize = 1 << 1, + ImGuiNextWindowDataFlags_HasContentSize = 1 << 2, + ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3, + ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4, + ImGuiNextWindowDataFlags_HasFocus = 1 << 5, + ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6, + ImGuiNextWindowDataFlags_HasScroll = 1 << 7 +}ImGuiNextWindowDataFlags_; +struct ImGuiNextWindowData +{ + ImGuiNextWindowDataFlags Flags; + ImGuiCond PosCond; + ImGuiCond SizeCond; + ImGuiCond CollapsedCond; + ImVec2 PosVal; + ImVec2 PosPivotVal; + ImVec2 SizeVal; + ImVec2 ContentSizeVal; + ImVec2 ScrollVal; + bool CollapsedVal; + ImRect SizeConstraintRect; + ImGuiSizeCallback SizeCallback; + void* SizeCallbackUserData; + float BgAlphaVal; + ImVec2 MenuBarOffsetMinVal; +}; +typedef enum { + ImGuiNextItemDataFlags_None = 0, + ImGuiNextItemDataFlags_HasWidth = 1 << 0, + ImGuiNextItemDataFlags_HasOpen = 1 << 1 +}ImGuiNextItemDataFlags_; +struct ImGuiNextItemData +{ + ImGuiNextItemDataFlags Flags; + float Width; + ImGuiID FocusScopeId; + ImGuiCond OpenCond; + bool OpenVal; +}; +struct ImGuiShrinkWidthItem +{ + int Index; + float Width; +}; +struct ImGuiPtrOrIndex +{ + void* Ptr; + int Index; +}; +typedef enum { + ImGuiOldColumnFlags_None = 0, + ImGuiOldColumnFlags_NoBorder = 1 << 0, + ImGuiOldColumnFlags_NoResize = 1 << 1, + ImGuiOldColumnFlags_NoPreserveWidths = 1 << 2, + ImGuiOldColumnFlags_NoForceWithinWindow = 1 << 3, + ImGuiOldColumnFlags_GrowParentContentsSize = 1 << 4 +}ImGuiOldColumnFlags_; +struct ImGuiOldColumnData +{ + float OffsetNorm; + float OffsetNormBeforeResize; + ImGuiOldColumnFlags Flags; + ImRect ClipRect; +}; +struct ImGuiOldColumns +{ + ImGuiID ID; + ImGuiOldColumnFlags Flags; + bool IsFirstFrame; + bool IsBeingResized; + int Current; + int Count; + float OffMinX, OffMaxX; + float LineMinY, LineMaxY; + float HostCursorPosY; + float HostCursorMaxPosX; + ImRect HostInitialClipRect; + ImRect HostBackupClipRect; + ImRect HostBackupParentWorkRect; + ImVector_ImGuiOldColumnData Columns; + ImDrawListSplitter Splitter; +}; +struct ImGuiViewportP +{ + ImGuiViewport _ImGuiViewport; + int DrawListsLastFrame[2]; + ImDrawList* DrawLists[2]; + ImDrawData DrawDataP; + ImDrawDataBuilder DrawDataBuilder; + ImVec2 WorkOffsetMin; + ImVec2 WorkOffsetMax; + ImVec2 CurrWorkOffsetMin; + ImVec2 CurrWorkOffsetMax; +}; +struct ImGuiWindowSettings +{ + ImGuiID ID; + ImVec2ih Pos; + ImVec2ih Size; + bool Collapsed; + bool WantApply; +}; +struct ImGuiSettingsHandler +{ + const char* TypeName; + ImGuiID TypeHash; + void (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); + void (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); + void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); + void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); + void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); + void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); + void* UserData; +}; +struct ImGuiMetricsConfig +{ + bool ShowWindowsRects; + bool ShowWindowsBeginOrder; + bool ShowTablesRects; + bool ShowDrawCmdMesh; + bool ShowDrawCmdBoundingBoxes; + int ShowWindowsRectsType; + int ShowTablesRectsType; +}; +struct ImGuiStackSizes +{ + short SizeOfIDStack; + short SizeOfColorStack; + short SizeOfStyleVarStack; + short SizeOfFontStack; + short SizeOfFocusScopeStack; + short SizeOfGroupStack; + short SizeOfBeginPopupStack; +}; +typedef enum { ImGuiContextHookType_NewFramePre, ImGuiContextHookType_NewFramePost, ImGuiContextHookType_EndFramePre, ImGuiContextHookType_EndFramePost, ImGuiContextHookType_RenderPre, ImGuiContextHookType_RenderPost, ImGuiContextHookType_Shutdown, ImGuiContextHookType_PendingRemoval_ }ImGuiContextHookType; +struct ImGuiContextHook +{ + ImGuiID HookId; + ImGuiContextHookType Type; + ImGuiID Owner; + ImGuiContextHookCallback Callback; + void* UserData; +}; +struct ImGuiContext +{ + bool Initialized; + bool FontAtlasOwnedByContext; + ImGuiIO IO; + ImGuiStyle Style; + ImFont* Font; + float FontSize; + float FontBaseSize; + ImDrawListSharedData DrawListSharedData; + double Time; + int FrameCount; + int FrameCountEnded; + int FrameCountRendered; + bool WithinFrameScope; + bool WithinFrameScopeWithImplicitWindow; + bool WithinEndChild; + bool GcCompactAll; + bool TestEngineHookItems; + ImGuiID TestEngineHookIdInfo; + void* TestEngine; + ImVector_ImGuiWindowPtr Windows; + ImVector_ImGuiWindowPtr WindowsFocusOrder; + ImVector_ImGuiWindowPtr WindowsTempSortBuffer; + ImVector_ImGuiWindowPtr CurrentWindowStack; + ImGuiStorage WindowsById; + int WindowsActiveCount; + ImGuiWindow* CurrentWindow; + ImGuiWindow* HoveredWindow; + ImGuiWindow* HoveredWindowUnderMovingWindow; + ImGuiWindow* MovingWindow; + ImGuiWindow* WheelingWindow; + ImVec2 WheelingWindowRefMousePos; + float WheelingWindowTimer; + ImGuiID HoveredId; + ImGuiID HoveredIdPreviousFrame; + bool HoveredIdAllowOverlap; + bool HoveredIdUsingMouseWheel; + bool HoveredIdPreviousFrameUsingMouseWheel; + bool HoveredIdDisabled; + float HoveredIdTimer; + float HoveredIdNotActiveTimer; + ImGuiID ActiveId; + ImGuiID ActiveIdIsAlive; + float ActiveIdTimer; + bool ActiveIdIsJustActivated; + bool ActiveIdAllowOverlap; + bool ActiveIdNoClearOnFocusLoss; + bool ActiveIdHasBeenPressedBefore; + bool ActiveIdHasBeenEditedBefore; + bool ActiveIdHasBeenEditedThisFrame; + bool ActiveIdUsingMouseWheel; + ImU32 ActiveIdUsingNavDirMask; + ImU32 ActiveIdUsingNavInputMask; + ImU64 ActiveIdUsingKeyInputMask; + ImVec2 ActiveIdClickOffset; + ImGuiWindow* ActiveIdWindow; + ImGuiInputSource ActiveIdSource; + int ActiveIdMouseButton; + ImGuiID ActiveIdPreviousFrame; + bool ActiveIdPreviousFrameIsAlive; + bool ActiveIdPreviousFrameHasBeenEditedBefore; + ImGuiWindow* ActiveIdPreviousFrameWindow; + ImGuiID LastActiveId; + float LastActiveIdTimer; + ImGuiNextWindowData NextWindowData; + ImGuiNextItemData NextItemData; + ImVector_ImGuiColorMod ColorStack; + ImVector_ImGuiStyleMod StyleVarStack; + ImVector_ImFontPtr FontStack; + ImVector_ImGuiID FocusScopeStack; + ImVector_ImGuiItemFlags ItemFlagsStack; + ImVector_ImGuiGroupData GroupStack; + ImVector_ImGuiPopupData OpenPopupStack; + ImVector_ImGuiPopupData BeginPopupStack; + ImVector_ImGuiViewportPPtr Viewports; + ImGuiWindow* NavWindow; + ImGuiID NavId; + ImGuiID NavFocusScopeId; + ImGuiID NavActivateId; + ImGuiID NavActivateDownId; + ImGuiID NavActivatePressedId; + ImGuiID NavInputId; + ImGuiID NavJustTabbedId; + ImGuiID NavJustMovedToId; + ImGuiID NavJustMovedToFocusScopeId; + ImGuiKeyModFlags NavJustMovedToKeyMods; + ImGuiID NavNextActivateId; + ImGuiInputSource NavInputSource; + ImRect NavScoringRect; + int NavScoringCount; + ImGuiNavLayer NavLayer; + int NavIdTabCounter; + bool NavIdIsAlive; + bool NavMousePosDirty; + bool NavDisableHighlight; + bool NavDisableMouseHover; + bool NavAnyRequest; + bool NavInitRequest; + bool NavInitRequestFromMove; + ImGuiID NavInitResultId; + ImRect NavInitResultRectRel; + bool NavMoveRequest; + ImGuiNavMoveFlags NavMoveRequestFlags; + ImGuiNavForward NavMoveRequestForward; + ImGuiKeyModFlags NavMoveRequestKeyMods; + ImGuiDir NavMoveDir, NavMoveDirLast; + ImGuiDir NavMoveClipDir; + ImGuiNavMoveResult NavMoveResultLocal; + ImGuiNavMoveResult NavMoveResultLocalVisibleSet; + ImGuiNavMoveResult NavMoveResultOther; + ImGuiWindow* NavWrapRequestWindow; + ImGuiNavMoveFlags NavWrapRequestFlags; + ImGuiWindow* NavWindowingTarget; + ImGuiWindow* NavWindowingTargetAnim; + ImGuiWindow* NavWindowingListWindow; + float NavWindowingTimer; + float NavWindowingHighlightAlpha; + bool NavWindowingToggleLayer; + ImGuiWindow* TabFocusRequestCurrWindow; + ImGuiWindow* TabFocusRequestNextWindow; + int TabFocusRequestCurrCounterRegular; + int TabFocusRequestCurrCounterTabStop; + int TabFocusRequestNextCounterRegular; + int TabFocusRequestNextCounterTabStop; + bool TabFocusPressed; + float DimBgRatio; + ImGuiMouseCursor MouseCursor; + bool DragDropActive; + bool DragDropWithinSource; + bool DragDropWithinTarget; + ImGuiDragDropFlags DragDropSourceFlags; + int DragDropSourceFrameCount; + int DragDropMouseButton; + ImGuiPayload DragDropPayload; + ImRect DragDropTargetRect; + ImGuiID DragDropTargetId; + ImGuiDragDropFlags DragDropAcceptFlags; + float DragDropAcceptIdCurrRectSurface; + ImGuiID DragDropAcceptIdCurr; + ImGuiID DragDropAcceptIdPrev; + int DragDropAcceptFrameCount; + ImGuiID DragDropHoldJustPressedId; + ImVector_unsigned_char DragDropPayloadBufHeap; + unsigned char DragDropPayloadBufLocal[16]; + ImGuiTable* CurrentTable; + ImPool_ImGuiTable Tables; + ImVector_ImGuiPtrOrIndex CurrentTableStack; + ImVector_float TablesLastTimeActive; + ImVector_ImDrawChannel DrawChannelsTempMergeBuffer; + ImGuiTabBar* CurrentTabBar; + ImPool_ImGuiTabBar TabBars; + ImVector_ImGuiPtrOrIndex CurrentTabBarStack; + ImVector_ImGuiShrinkWidthItem ShrinkWidthBuffer; + ImVec2 LastValidMousePos; + ImGuiInputTextState InputTextState; + ImFont InputTextPasswordFont; + ImGuiID TempInputId; + ImGuiColorEditFlags ColorEditOptions; + float ColorEditLastHue; + float ColorEditLastSat; + float ColorEditLastColor[3]; + ImVec4 ColorPickerRef; + float SliderCurrentAccum; + bool SliderCurrentAccumDirty; + bool DragCurrentAccumDirty; + float DragCurrentAccum; + float DragSpeedDefaultRatio; + float ScrollbarClickDeltaToGrabCenter; + int TooltipOverrideCount; + float TooltipSlowDelay; + ImVector_char ClipboardHandlerData; + ImVector_ImGuiID MenusIdSubmittedThisFrame; + ImVec2 PlatformImePos; + ImVec2 PlatformImeLastPos; + char PlatformLocaleDecimalPoint; + bool SettingsLoaded; + float SettingsDirtyTimer; + ImGuiTextBuffer SettingsIniData; + ImVector_ImGuiSettingsHandler SettingsHandlers; + ImChunkStream_ImGuiWindowSettings SettingsWindows; + ImChunkStream_ImGuiTableSettings SettingsTables; + ImVector_ImGuiContextHook Hooks; + ImGuiID HookIdNext; + bool LogEnabled; + ImGuiLogType LogType; + ImFileHandle LogFile; + ImGuiTextBuffer LogBuffer; + const char* LogNextPrefix; + const char* LogNextSuffix; + float LogLinePosY; + bool LogLineFirstItem; + int LogDepthRef; + int LogDepthToExpand; + int LogDepthToExpandDefault; + bool DebugItemPickerActive; + ImGuiID DebugItemPickerBreakId; + ImGuiMetricsConfig DebugMetricsConfig; + float FramerateSecPerFrame[120]; + int FramerateSecPerFrameIdx; + float FramerateSecPerFrameAccum; + int WantCaptureMouseNextFrame; + int WantCaptureKeyboardNextFrame; + int WantTextInputNextFrame; + char TempBuffer[1024 * 3 + 1]; +}; +struct ImGuiWindowTempData +{ + ImVec2 CursorPos; + ImVec2 CursorPosPrevLine; + ImVec2 CursorStartPos; + ImVec2 CursorMaxPos; + ImVec2 IdealMaxPos; + ImVec2 CurrLineSize; + ImVec2 PrevLineSize; + float CurrLineTextBaseOffset; + float PrevLineTextBaseOffset; + ImVec1 Indent; + ImVec1 ColumnsOffset; + ImVec1 GroupOffset; + ImGuiID LastItemId; + ImGuiItemStatusFlags LastItemStatusFlags; + ImRect LastItemRect; + ImRect LastItemDisplayRect; + ImGuiNavLayer NavLayerCurrent; + int NavLayerActiveMask; + int NavLayerActiveMaskNext; + ImGuiID NavFocusScopeIdCurrent; + bool NavHideHighlightOneFrame; + bool NavHasScroll; + bool MenuBarAppending; + ImVec2 MenuBarOffset; + ImGuiMenuColumns MenuColumns; + int TreeDepth; + ImU32 TreeJumpToParentOnPopMask; + ImVector_ImGuiWindowPtr ChildWindows; + ImGuiStorage* StateStorage; + ImGuiOldColumns* CurrentColumns; + int CurrentTableIdx; + ImGuiLayoutType LayoutType; + ImGuiLayoutType ParentLayoutType; + int FocusCounterRegular; + int FocusCounterTabStop; + ImGuiItemFlags ItemFlags; + float ItemWidth; + float TextWrapPos; + ImVector_float ItemWidthStack; + ImVector_float TextWrapPosStack; + ImGuiStackSizes StackSizesOnBegin; +}; +struct ImGuiWindow +{ + char* Name; + ImGuiID ID; + ImGuiWindowFlags Flags; + ImVec2 Pos; + ImVec2 Size; + ImVec2 SizeFull; + ImVec2 ContentSize; + ImVec2 ContentSizeIdeal; + ImVec2 ContentSizeExplicit; + ImVec2 WindowPadding; + float WindowRounding; + float WindowBorderSize; + int NameBufLen; + ImGuiID MoveId; + ImGuiID ChildId; + ImVec2 Scroll; + ImVec2 ScrollMax; + ImVec2 ScrollTarget; + ImVec2 ScrollTargetCenterRatio; + ImVec2 ScrollTargetEdgeSnapDist; + ImVec2 ScrollbarSizes; + bool ScrollbarX, ScrollbarY; + bool Active; + bool WasActive; + bool WriteAccessed; + bool Collapsed; + bool WantCollapseToggle; + bool SkipItems; + bool Appearing; + bool Hidden; + bool IsFallbackWindow; + bool HasCloseButton; + signed char ResizeBorderHeld; + short BeginCount; + short BeginOrderWithinParent; + short BeginOrderWithinContext; + ImGuiID PopupId; + ImS8 AutoFitFramesX, AutoFitFramesY; + ImS8 AutoFitChildAxises; + bool AutoFitOnlyGrows; + ImGuiDir AutoPosLastDirection; + ImS8 HiddenFramesCanSkipItems; + ImS8 HiddenFramesCannotSkipItems; + ImS8 HiddenFramesForRenderOnly; + ImGuiCond SetWindowPosAllowFlags : 8; + ImGuiCond SetWindowSizeAllowFlags : 8; + ImGuiCond SetWindowCollapsedAllowFlags : 8; + ImVec2 SetWindowPosVal; + ImVec2 SetWindowPosPivot; + ImVector_ImGuiID IDStack; + ImGuiWindowTempData DC; + ImRect OuterRectClipped; + ImRect InnerRect; + ImRect InnerClipRect; + ImRect WorkRect; + ImRect ParentWorkRect; + ImRect ClipRect; + ImRect ContentRegionRect; + ImVec2ih HitTestHoleSize; + ImVec2ih HitTestHoleOffset; + int LastFrameActive; + float LastTimeActive; + float ItemWidthDefault; + ImGuiStorage StateStorage; + ImVector_ImGuiOldColumns ColumnsStorage; + float FontWindowScale; + int SettingsOffset; + ImDrawList* DrawList; + ImDrawList DrawListInst; + ImGuiWindow* ParentWindow; + ImGuiWindow* RootWindow; + ImGuiWindow* RootWindowForTitleBarHighlight; + ImGuiWindow* RootWindowForNav; + ImGuiWindow* NavLastChildNavWindow; + ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; + ImRect NavRectRel[ImGuiNavLayer_COUNT]; + int MemoryDrawListIdxCapacity; + int MemoryDrawListVtxCapacity; + bool MemoryCompacted; +}; +struct ImGuiLastItemDataBackup +{ + ImGuiID LastItemId; + ImGuiItemStatusFlags LastItemStatusFlags; + ImRect LastItemRect; + ImRect LastItemDisplayRect; +}; +typedef enum { + ImGuiTabBarFlags_DockNode = 1 << 20, + ImGuiTabBarFlags_IsFocused = 1 << 21, + ImGuiTabBarFlags_SaveSettings = 1 << 22 +}ImGuiTabBarFlagsPrivate_; +typedef enum { + ImGuiTabItemFlags_NoCloseButton = 1 << 20, + ImGuiTabItemFlags_Button = 1 << 21 +}ImGuiTabItemFlagsPrivate_; +struct ImGuiTabItem +{ + ImGuiID ID; + ImGuiTabItemFlags Flags; + int LastFrameVisible; + int LastFrameSelected; + float Offset; + float Width; + float ContentWidth; + ImS16 NameOffset; + ImS16 BeginOrder; + ImS16 IndexDuringLayout; + bool WantClose; +}; +struct ImGuiTabBar +{ + ImVector_ImGuiTabItem Tabs; + ImGuiTabBarFlags Flags; + ImGuiID ID; + ImGuiID SelectedTabId; + ImGuiID NextSelectedTabId; + ImGuiID VisibleTabId; + int CurrFrameVisible; + int PrevFrameVisible; + ImRect BarRect; + float CurrTabsContentsHeight; + float PrevTabsContentsHeight; + float WidthAllTabs; + float WidthAllTabsIdeal; + float ScrollingAnim; + float ScrollingTarget; + float ScrollingTargetDistToVisibility; + float ScrollingSpeed; + float ScrollingRectMinX; + float ScrollingRectMaxX; + ImGuiID ReorderRequestTabId; + ImS8 ReorderRequestDir; + ImS8 BeginCount; + bool WantLayout; + bool VisibleTabWasSubmitted; + bool TabsAddedNew; + ImS16 TabsActiveCount; + ImS16 LastTabItemIdx; + float ItemSpacingY; + ImVec2 FramePadding; + ImVec2 BackupCursorPos; + ImGuiTextBuffer TabsNames; +}; +struct ImGuiTableColumn +{ + ImGuiTableColumnFlags Flags; + float WidthGiven; + float MinX; + float MaxX; + float WidthRequest; + float WidthAuto; + float StretchWeight; + float InitStretchWeightOrWidth; + ImRect ClipRect; + ImGuiID UserID; + float WorkMinX; + float WorkMaxX; + float ItemWidth; + float ContentMaxXFrozen; + float ContentMaxXUnfrozen; + float ContentMaxXHeadersUsed; + float ContentMaxXHeadersIdeal; + ImS16 NameOffset; + ImGuiTableColumnIdx DisplayOrder; + ImGuiTableColumnIdx IndexWithinEnabledSet; + ImGuiTableColumnIdx PrevEnabledColumn; + ImGuiTableColumnIdx NextEnabledColumn; + ImGuiTableColumnIdx SortOrder; + ImGuiTableDrawChannelIdx DrawChannelCurrent; + ImGuiTableDrawChannelIdx DrawChannelFrozen; + ImGuiTableDrawChannelIdx DrawChannelUnfrozen; + bool IsEnabled; + bool IsEnabledNextFrame; + bool IsVisibleX; + bool IsVisibleY; + bool IsRequestOutput; + bool IsSkipItems; + bool IsPreserveWidthAuto; + ImS8 NavLayerCurrent; + ImU8 AutoFitQueue; + ImU8 CannotSkipItemsQueue; + ImU8 SortDirection : 2; + ImU8 SortDirectionsAvailCount : 2; + ImU8 SortDirectionsAvailMask : 4; + ImU8 SortDirectionsAvailList; +}; +struct ImGuiTableCellData +{ + ImU32 BgColor; + ImGuiTableColumnIdx Column; +}; +struct ImGuiTable +{ + ImGuiID ID; + ImGuiTableFlags Flags; + void* RawData; + ImSpan_ImGuiTableColumn Columns; + ImSpan_ImGuiTableColumnIdx DisplayOrderToIndex; + ImSpan_ImGuiTableCellData RowCellData; + ImU64 EnabledMaskByDisplayOrder; + ImU64 EnabledMaskByIndex; + ImU64 VisibleMaskByIndex; + ImU64 RequestOutputMaskByIndex; + ImGuiTableFlags SettingsLoadedFlags; + int SettingsOffset; + int LastFrameActive; + int ColumnsCount; + int CurrentRow; + int CurrentColumn; + ImS16 InstanceCurrent; + ImS16 InstanceInteracted; + float RowPosY1; + float RowPosY2; + float RowMinHeight; + float RowTextBaseline; + float RowIndentOffsetX; + ImGuiTableRowFlags RowFlags : 16; + ImGuiTableRowFlags LastRowFlags : 16; + int RowBgColorCounter; + ImU32 RowBgColor[2]; + ImU32 BorderColorStrong; + ImU32 BorderColorLight; + float BorderX1; + float BorderX2; + float HostIndentX; + float MinColumnWidth; + float OuterPaddingX; + float CellPaddingX; + float CellPaddingY; + float CellSpacingX1; + float CellSpacingX2; + float LastOuterHeight; + float LastFirstRowHeight; + float InnerWidth; + float ColumnsGivenWidth; + float ColumnsAutoFitWidth; + float ResizedColumnNextWidth; + float ResizeLockMinContentsX2; + float RefScale; + ImRect OuterRect; + ImRect InnerRect; + ImRect WorkRect; + ImRect InnerClipRect; + ImRect BgClipRect; + ImRect Bg0ClipRectForDrawCmd; + ImRect Bg2ClipRectForDrawCmd; + ImRect HostClipRect; + ImRect HostBackupWorkRect; + ImRect HostBackupParentWorkRect; + ImRect HostBackupInnerClipRect; + ImVec2 HostBackupPrevLineSize; + ImVec2 HostBackupCurrLineSize; + ImVec2 HostBackupCursorMaxPos; + ImVec2 UserOuterSize; + ImVec1 HostBackupColumnsOffset; + float HostBackupItemWidth; + int HostBackupItemWidthStackSize; + ImGuiWindow* OuterWindow; + ImGuiWindow* InnerWindow; + ImGuiTextBuffer ColumnsNames; + ImDrawListSplitter DrawSplitter; + ImGuiTableColumnSortSpecs SortSpecsSingle; + ImVector_ImGuiTableColumnSortSpecs SortSpecsMulti; + ImGuiTableSortSpecs SortSpecs; + ImGuiTableColumnIdx SortSpecsCount; + ImGuiTableColumnIdx ColumnsEnabledCount; + ImGuiTableColumnIdx ColumnsEnabledFixedCount; + ImGuiTableColumnIdx DeclColumnsCount; + ImGuiTableColumnIdx HoveredColumnBody; + ImGuiTableColumnIdx HoveredColumnBorder; + ImGuiTableColumnIdx AutoFitSingleColumn; + ImGuiTableColumnIdx ResizedColumn; + ImGuiTableColumnIdx LastResizedColumn; + ImGuiTableColumnIdx HeldHeaderColumn; + ImGuiTableColumnIdx ReorderColumn; + ImGuiTableColumnIdx ReorderColumnDir; + ImGuiTableColumnIdx LeftMostEnabledColumn; + ImGuiTableColumnIdx RightMostEnabledColumn; + ImGuiTableColumnIdx LeftMostStretchedColumn; + ImGuiTableColumnIdx RightMostStretchedColumn; + ImGuiTableColumnIdx ContextPopupColumn; + ImGuiTableColumnIdx FreezeRowsRequest; + ImGuiTableColumnIdx FreezeRowsCount; + ImGuiTableColumnIdx FreezeColumnsRequest; + ImGuiTableColumnIdx FreezeColumnsCount; + ImGuiTableColumnIdx RowCellDataCurrent; + ImGuiTableDrawChannelIdx DummyDrawChannel; + ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; + ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen; + bool IsLayoutLocked; + bool IsInsideRow; + bool IsInitializing; + bool IsSortSpecsDirty; + bool IsUsingHeaders; + bool IsContextPopupOpen; + bool IsSettingsRequestLoad; + bool IsSettingsDirty; + bool IsDefaultDisplayOrder; + bool IsResetAllRequest; + bool IsResetDisplayOrderRequest; + bool IsUnfrozenRows; + bool IsDefaultSizingPolicy; + bool MemoryCompacted; + bool HostSkipItems; +}; +struct ImGuiTableColumnSettings +{ + float WidthOrWeight; + ImGuiID UserID; + ImGuiTableColumnIdx Index; + ImGuiTableColumnIdx DisplayOrder; + ImGuiTableColumnIdx SortOrder; + ImU8 SortDirection : 2; + ImU8 IsEnabled : 1; + ImU8 IsStretch : 1; +}; +struct ImGuiTableSettings +{ + ImGuiID ID; + ImGuiTableFlags SaveFlags; + float RefScale; + ImGuiTableColumnIdx ColumnsCount; + ImGuiTableColumnIdx ColumnsCountMax; + bool WantApply; +}; +struct ImFontBuilderIO +{ + bool (*FontBuilder_Build)(ImFontAtlas* atlas); +}; +#else +struct GLFWwindow; +struct SDL_Window; +typedef union SDL_Event SDL_Event; +#endif // CIMGUI_DEFINE_ENUMS_AND_STRUCTS + +#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS +typedef ImGuiStorage::ImGuiStoragePair ImGuiStoragePair; +typedef ImGuiTextFilter::ImGuiTextRange ImGuiTextRange; +typedef ImStb::STB_TexteditState STB_TexteditState; +typedef ImStb::StbTexteditRow StbTexteditRow; +typedef ImStb::StbUndoRecord StbUndoRecord; +typedef ImStb::StbUndoState StbUndoState; +typedef ImChunkStream ImChunkStream_ImGuiTableSettings; +typedef ImChunkStream ImChunkStream_ImGuiWindowSettings; +typedef ImPool ImPool_ImGuiTabBar; +typedef ImPool ImPool_ImGuiTable; +typedef ImSpan ImSpan_ImGuiTableCellData; +typedef ImSpan ImSpan_ImGuiTableColumn; +typedef ImSpan ImSpan_ImGuiTableColumnIdx; +typedef ImVector ImVector_ImDrawChannel; +typedef ImVector ImVector_ImDrawCmd; +typedef ImVector ImVector_ImDrawIdx; +typedef ImVector ImVector_ImDrawListPtr; +typedef ImVector ImVector_ImDrawVert; +typedef ImVector ImVector_ImFontPtr; +typedef ImVector ImVector_ImFontAtlasCustomRect; +typedef ImVector ImVector_ImFontConfig; +typedef ImVector ImVector_ImFontGlyph; +typedef ImVector ImVector_ImGuiColorMod; +typedef ImVector ImVector_ImGuiContextHook; +typedef ImVector ImVector_ImGuiGroupData; +typedef ImVector ImVector_ImGuiID; +typedef ImVector ImVector_ImGuiItemFlags; +typedef ImVector ImVector_ImGuiOldColumnData; +typedef ImVector ImVector_ImGuiOldColumns; +typedef ImVector ImVector_ImGuiPopupData; +typedef ImVector ImVector_ImGuiPtrOrIndex; +typedef ImVector ImVector_ImGuiSettingsHandler; +typedef ImVector ImVector_ImGuiShrinkWidthItem; +typedef ImVector ImVector_ImGuiStoragePair; +typedef ImVector ImVector_ImGuiStyleMod; +typedef ImVector ImVector_ImGuiTabItem; +typedef ImVector ImVector_ImGuiTableColumnSortSpecs; +typedef ImVector ImVector_ImGuiTextRange; +typedef ImVector ImVector_ImGuiViewportPPtr; +typedef ImVector ImVector_ImGuiWindowPtr; +typedef ImVector ImVector_ImTextureID; +typedef ImVector ImVector_ImU32; +typedef ImVector ImVector_ImVec2; +typedef ImVector ImVector_ImVec4; +typedef ImVector ImVector_ImWchar; +typedef ImVector ImVector_char; +typedef ImVector ImVector_float; +typedef ImVector ImVector_unsigned_char; +#endif //CIMGUI_DEFINE_ENUMS_AND_STRUCTS +CIMGUI_API ImVec2* ImVec2_ImVec2_Nil(void); +CIMGUI_API void ImVec2_destroy(ImVec2* self); +CIMGUI_API ImVec2* ImVec2_ImVec2_Float(float _x,float _y); +CIMGUI_API ImVec4* ImVec4_ImVec4_Nil(void); +CIMGUI_API void ImVec4_destroy(ImVec4* self); +CIMGUI_API ImVec4* ImVec4_ImVec4_Float(float _x,float _y,float _z,float _w); +CIMGUI_API ImGuiContext* igCreateContext(ImFontAtlas* shared_font_atlas); +CIMGUI_API void igDestroyContext(ImGuiContext* ctx); +CIMGUI_API ImGuiContext* igGetCurrentContext(void); +CIMGUI_API void igSetCurrentContext(ImGuiContext* ctx); +CIMGUI_API ImGuiIO* igGetIO(void); +CIMGUI_API ImGuiStyle* igGetStyle(void); +CIMGUI_API void igNewFrame(void); +CIMGUI_API void igEndFrame(void); +CIMGUI_API void igRender(void); +CIMGUI_API ImDrawData* igGetDrawData(void); +CIMGUI_API const char* igGetVersion(void); +CIMGUI_API void igStyleColorsDark(ImGuiStyle* dst); +CIMGUI_API void igStyleColorsLight(ImGuiStyle* dst); +CIMGUI_API void igStyleColorsClassic(ImGuiStyle* dst); +CIMGUI_API bool igBegin(const char* name,bool* p_open,ImGuiWindowFlags flags); +CIMGUI_API void igEnd(void); +CIMGUI_API bool igBeginChild_Str(const char* str_id,const ImVec2 size,bool border,ImGuiWindowFlags flags); +CIMGUI_API bool igBeginChild_ID(ImGuiID id,const ImVec2 size,bool border,ImGuiWindowFlags flags); +CIMGUI_API void igEndChild(void); +CIMGUI_API bool igIsWindowAppearing(void); +CIMGUI_API bool igIsWindowCollapsed(void); +CIMGUI_API bool igIsWindowFocused(ImGuiFocusedFlags flags); +CIMGUI_API bool igIsWindowHovered(ImGuiHoveredFlags flags); +CIMGUI_API ImDrawList* igGetWindowDrawList(void); +CIMGUI_API void igGetWindowPos(ImVec2 *pOut); +CIMGUI_API void igGetWindowSize(ImVec2 *pOut); +CIMGUI_API float igGetWindowWidth(void); +CIMGUI_API float igGetWindowHeight(void); +CIMGUI_API void igSetNextWindowPos(const ImVec2 pos,ImGuiCond cond,const ImVec2 pivot); +CIMGUI_API void igSetNextWindowSize(const ImVec2 size,ImGuiCond cond); +CIMGUI_API void igSetNextWindowSizeConstraints(const ImVec2 size_min,const ImVec2 size_max,ImGuiSizeCallback custom_callback,void* custom_callback_data); +CIMGUI_API void igSetNextWindowContentSize(const ImVec2 size); +CIMGUI_API void igSetNextWindowCollapsed(bool collapsed,ImGuiCond cond); +CIMGUI_API void igSetNextWindowFocus(void); +CIMGUI_API void igSetNextWindowBgAlpha(float alpha); +CIMGUI_API void igSetWindowPos_Vec2(const ImVec2 pos,ImGuiCond cond); +CIMGUI_API void igSetWindowSize_Vec2(const ImVec2 size,ImGuiCond cond); +CIMGUI_API void igSetWindowCollapsed_Bool(bool collapsed,ImGuiCond cond); +CIMGUI_API void igSetWindowFocus_Nil(void); +CIMGUI_API void igSetWindowFontScale(float scale); +CIMGUI_API void igSetWindowPos_Str(const char* name,const ImVec2 pos,ImGuiCond cond); +CIMGUI_API void igSetWindowSize_Str(const char* name,const ImVec2 size,ImGuiCond cond); +CIMGUI_API void igSetWindowCollapsed_Str(const char* name,bool collapsed,ImGuiCond cond); +CIMGUI_API void igSetWindowFocus_Str(const char* name); +CIMGUI_API void igGetContentRegionAvail(ImVec2 *pOut); +CIMGUI_API void igGetContentRegionMax(ImVec2 *pOut); +CIMGUI_API void igGetWindowContentRegionMin(ImVec2 *pOut); +CIMGUI_API void igGetWindowContentRegionMax(ImVec2 *pOut); +CIMGUI_API float igGetWindowContentRegionWidth(void); +CIMGUI_API float igGetScrollX(void); +CIMGUI_API float igGetScrollY(void); +CIMGUI_API void igSetScrollX_Float(float scroll_x); +CIMGUI_API void igSetScrollY_Float(float scroll_y); +CIMGUI_API float igGetScrollMaxX(void); +CIMGUI_API float igGetScrollMaxY(void); +CIMGUI_API void igSetScrollHereX(float center_x_ratio); +CIMGUI_API void igSetScrollHereY(float center_y_ratio); +CIMGUI_API void igSetScrollFromPosX_Float(float local_x,float center_x_ratio); +CIMGUI_API void igSetScrollFromPosY_Float(float local_y,float center_y_ratio); +CIMGUI_API void igPushFont(ImFont* font); +CIMGUI_API void igPopFont(void); +CIMGUI_API void igPushStyleColor_U32(ImGuiCol idx,ImU32 col); +CIMGUI_API void igPushStyleColor_Vec4(ImGuiCol idx,const ImVec4 col); +CIMGUI_API void igPopStyleColor(int count); +CIMGUI_API void igPushStyleVar_Float(ImGuiStyleVar idx,float val); +CIMGUI_API void igPushStyleVar_Vec2(ImGuiStyleVar idx,const ImVec2 val); +CIMGUI_API void igPopStyleVar(int count); +CIMGUI_API void igPushAllowKeyboardFocus(bool allow_keyboard_focus); +CIMGUI_API void igPopAllowKeyboardFocus(void); +CIMGUI_API void igPushButtonRepeat(bool repeat); +CIMGUI_API void igPopButtonRepeat(void); +CIMGUI_API void igPushItemWidth(float item_width); +CIMGUI_API void igPopItemWidth(void); +CIMGUI_API void igSetNextItemWidth(float item_width); +CIMGUI_API float igCalcItemWidth(void); +CIMGUI_API void igPushTextWrapPos(float wrap_local_pos_x); +CIMGUI_API void igPopTextWrapPos(void); +CIMGUI_API ImFont* igGetFont(void); +CIMGUI_API float igGetFontSize(void); +CIMGUI_API void igGetFontTexUvWhitePixel(ImVec2 *pOut); +CIMGUI_API ImU32 igGetColorU32_Col(ImGuiCol idx,float alpha_mul); +CIMGUI_API ImU32 igGetColorU32_Vec4(const ImVec4 col); +CIMGUI_API ImU32 igGetColorU32_U32(ImU32 col); +CIMGUI_API const ImVec4* igGetStyleColorVec4(ImGuiCol idx); +CIMGUI_API void igSeparator(void); +CIMGUI_API void igSameLine(float offset_from_start_x,float spacing); +CIMGUI_API void igNewLine(void); +CIMGUI_API void igSpacing(void); +CIMGUI_API void igDummy(const ImVec2 size); +CIMGUI_API void igIndent(float indent_w); +CIMGUI_API void igUnindent(float indent_w); +CIMGUI_API void igBeginGroup(void); +CIMGUI_API void igEndGroup(void); +CIMGUI_API void igGetCursorPos(ImVec2 *pOut); +CIMGUI_API float igGetCursorPosX(void); +CIMGUI_API float igGetCursorPosY(void); +CIMGUI_API void igSetCursorPos(const ImVec2 local_pos); +CIMGUI_API void igSetCursorPosX(float local_x); +CIMGUI_API void igSetCursorPosY(float local_y); +CIMGUI_API void igGetCursorStartPos(ImVec2 *pOut); +CIMGUI_API void igGetCursorScreenPos(ImVec2 *pOut); +CIMGUI_API void igSetCursorScreenPos(const ImVec2 pos); +CIMGUI_API void igAlignTextToFramePadding(void); +CIMGUI_API float igGetTextLineHeight(void); +CIMGUI_API float igGetTextLineHeightWithSpacing(void); +CIMGUI_API float igGetFrameHeight(void); +CIMGUI_API float igGetFrameHeightWithSpacing(void); +CIMGUI_API void igPushID_Str(const char* str_id); +CIMGUI_API void igPushID_StrStr(const char* str_id_begin,const char* str_id_end); +CIMGUI_API void igPushID_Ptr(const void* ptr_id); +CIMGUI_API void igPushID_Int(int int_id); +CIMGUI_API void igPopID(void); +CIMGUI_API ImGuiID igGetID_Str(const char* str_id); +CIMGUI_API ImGuiID igGetID_StrStr(const char* str_id_begin,const char* str_id_end); +CIMGUI_API ImGuiID igGetID_Ptr(const void* ptr_id); +CIMGUI_API void igTextUnformatted(const char* text,const char* text_end); +CIMGUI_API void igText(const char* fmt,...); +CIMGUI_API void igTextV(const char* fmt,va_list args); +CIMGUI_API void igTextColored(const ImVec4 col,const char* fmt,...); +CIMGUI_API void igTextColoredV(const ImVec4 col,const char* fmt,va_list args); +CIMGUI_API void igTextDisabled(const char* fmt,...); +CIMGUI_API void igTextDisabledV(const char* fmt,va_list args); +CIMGUI_API void igTextWrapped(const char* fmt,...); +CIMGUI_API void igTextWrappedV(const char* fmt,va_list args); +CIMGUI_API void igLabelText(const char* label,const char* fmt,...); +CIMGUI_API void igLabelTextV(const char* label,const char* fmt,va_list args); +CIMGUI_API void igBulletText(const char* fmt,...); +CIMGUI_API void igBulletTextV(const char* fmt,va_list args); +CIMGUI_API bool igButton(const char* label,const ImVec2 size); +CIMGUI_API bool igSmallButton(const char* label); +CIMGUI_API bool igInvisibleButton(const char* str_id,const ImVec2 size,ImGuiButtonFlags flags); +CIMGUI_API bool igArrowButton(const char* str_id,ImGuiDir dir); +CIMGUI_API void igImage(ImTextureID user_texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,const ImVec4 tint_col,const ImVec4 border_col); +CIMGUI_API bool igImageButton(ImTextureID user_texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,int frame_padding,const ImVec4 bg_col,const ImVec4 tint_col); +CIMGUI_API bool igCheckbox(const char* label,bool* v); +CIMGUI_API bool igCheckboxFlags_IntPtr(const char* label,int* flags,int flags_value); +CIMGUI_API bool igCheckboxFlags_UintPtr(const char* label,unsigned int* flags,unsigned int flags_value); +CIMGUI_API bool igRadioButton_Bool(const char* label,bool active); +CIMGUI_API bool igRadioButton_IntPtr(const char* label,int* v,int v_button); +CIMGUI_API void igProgressBar(float fraction,const ImVec2 size_arg,const char* overlay); +CIMGUI_API void igBullet(void); +CIMGUI_API bool igBeginCombo(const char* label,const char* preview_value,ImGuiComboFlags flags); +CIMGUI_API void igEndCombo(void); +CIMGUI_API bool igCombo_Str_arr(const char* label,int* current_item,const char* const items[],int items_count,int popup_max_height_in_items); +CIMGUI_API bool igCombo_Str(const char* label,int* current_item,const char* items_separated_by_zeros,int popup_max_height_in_items); +CIMGUI_API bool igCombo_FnBoolPtr(const char* label,int* current_item,bool(*items_getter)(void* data,int idx,const char** out_text),void* data,int items_count,int popup_max_height_in_items); +CIMGUI_API bool igDragFloat(const char* label,float* v,float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragFloat2(const char* label,float v[2],float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragFloat3(const char* label,float v[3],float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragFloat4(const char* label,float v[4],float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragFloatRange2(const char* label,float* v_current_min,float* v_current_max,float v_speed,float v_min,float v_max,const char* format,const char* format_max,ImGuiSliderFlags flags); +CIMGUI_API bool igDragInt(const char* label,int* v,float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragInt2(const char* label,int v[2],float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragInt3(const char* label,int v[3],float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragInt4(const char* label,int v[4],float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragIntRange2(const char* label,int* v_current_min,int* v_current_max,float v_speed,int v_min,int v_max,const char* format,const char* format_max,ImGuiSliderFlags flags); +CIMGUI_API bool igDragScalar(const char* label,ImGuiDataType data_type,void* p_data,float v_speed,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragScalarN(const char* label,ImGuiDataType data_type,void* p_data,int components,float v_speed,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderFloat(const char* label,float* v,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderFloat2(const char* label,float v[2],float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderFloat3(const char* label,float v[3],float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderFloat4(const char* label,float v[4],float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderAngle(const char* label,float* v_rad,float v_degrees_min,float v_degrees_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderInt(const char* label,int* v,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderInt2(const char* label,int v[2],int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderInt3(const char* label,int v[3],int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderInt4(const char* label,int v[4],int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderScalar(const char* label,ImGuiDataType data_type,void* p_data,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderScalarN(const char* label,ImGuiDataType data_type,void* p_data,int components,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igVSliderFloat(const char* label,const ImVec2 size,float* v,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igVSliderInt(const char* label,const ImVec2 size,int* v,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igVSliderScalar(const char* label,const ImVec2 size,ImGuiDataType data_type,void* p_data,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igInputText(const char* label,char* buf,size_t buf_size,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data); +CIMGUI_API bool igInputTextMultiline(const char* label,char* buf,size_t buf_size,const ImVec2 size,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data); +CIMGUI_API bool igInputTextWithHint(const char* label,const char* hint,char* buf,size_t buf_size,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data); +CIMGUI_API bool igInputFloat(const char* label,float* v,float step,float step_fast,const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputFloat2(const char* label,float v[2],const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputFloat3(const char* label,float v[3],const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputFloat4(const char* label,float v[4],const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputInt(const char* label,int* v,int step,int step_fast,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputInt2(const char* label,int v[2],ImGuiInputTextFlags flags); +CIMGUI_API bool igInputInt3(const char* label,int v[3],ImGuiInputTextFlags flags); +CIMGUI_API bool igInputInt4(const char* label,int v[4],ImGuiInputTextFlags flags); +CIMGUI_API bool igInputDouble(const char* label,double* v,double step,double step_fast,const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputScalar(const char* label,ImGuiDataType data_type,void* p_data,const void* p_step,const void* p_step_fast,const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputScalarN(const char* label,ImGuiDataType data_type,void* p_data,int components,const void* p_step,const void* p_step_fast,const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igColorEdit3(const char* label,float col[3],ImGuiColorEditFlags flags); +CIMGUI_API bool igColorEdit4(const char* label,float col[4],ImGuiColorEditFlags flags); +CIMGUI_API bool igColorPicker3(const char* label,float col[3],ImGuiColorEditFlags flags); +CIMGUI_API bool igColorPicker4(const char* label,float col[4],ImGuiColorEditFlags flags,const float* ref_col); +CIMGUI_API bool igColorButton(const char* desc_id,const ImVec4 col,ImGuiColorEditFlags flags,ImVec2 size); +CIMGUI_API void igSetColorEditOptions(ImGuiColorEditFlags flags); +CIMGUI_API bool igTreeNode_Str(const char* label); +CIMGUI_API bool igTreeNode_StrStr(const char* str_id,const char* fmt,...); +CIMGUI_API bool igTreeNode_Ptr(const void* ptr_id,const char* fmt,...); +CIMGUI_API bool igTreeNodeV_Str(const char* str_id,const char* fmt,va_list args); +CIMGUI_API bool igTreeNodeV_Ptr(const void* ptr_id,const char* fmt,va_list args); +CIMGUI_API bool igTreeNodeEx_Str(const char* label,ImGuiTreeNodeFlags flags); +CIMGUI_API bool igTreeNodeEx_StrStr(const char* str_id,ImGuiTreeNodeFlags flags,const char* fmt,...); +CIMGUI_API bool igTreeNodeEx_Ptr(const void* ptr_id,ImGuiTreeNodeFlags flags,const char* fmt,...); +CIMGUI_API bool igTreeNodeExV_Str(const char* str_id,ImGuiTreeNodeFlags flags,const char* fmt,va_list args); +CIMGUI_API bool igTreeNodeExV_Ptr(const void* ptr_id,ImGuiTreeNodeFlags flags,const char* fmt,va_list args); +CIMGUI_API void igTreePush_Str(const char* str_id); +CIMGUI_API void igTreePush_Ptr(const void* ptr_id); +CIMGUI_API void igTreePop(void); +CIMGUI_API float igGetTreeNodeToLabelSpacing(void); +CIMGUI_API bool igCollapsingHeader_TreeNodeFlags(const char* label,ImGuiTreeNodeFlags flags); +CIMGUI_API bool igCollapsingHeader_BoolPtr(const char* label,bool* p_visible,ImGuiTreeNodeFlags flags); +CIMGUI_API void igSetNextItemOpen(bool is_open,ImGuiCond cond); +CIMGUI_API bool igSelectable_Bool(const char* label,bool selected,ImGuiSelectableFlags flags,const ImVec2 size); +CIMGUI_API bool igSelectable_BoolPtr(const char* label,bool* p_selected,ImGuiSelectableFlags flags,const ImVec2 size); +CIMGUI_API bool igBeginListBox(const char* label,const ImVec2 size); +CIMGUI_API void igEndListBox(void); +CIMGUI_API bool igListBox_Str_arr(const char* label,int* current_item,const char* const items[],int items_count,int height_in_items); +CIMGUI_API bool igListBox_FnBoolPtr(const char* label,int* current_item,bool(*items_getter)(void* data,int idx,const char** out_text),void* data,int items_count,int height_in_items); +CIMGUI_API void igPlotLines_FloatPtr(const char* label,const float* values,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size,int stride); +CIMGUI_API void igPlotLines_FnFloatPtr(const char* label,float(*values_getter)(void* data,int idx),void* data,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size); +CIMGUI_API void igPlotHistogram_FloatPtr(const char* label,const float* values,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size,int stride); +CIMGUI_API void igPlotHistogram_FnFloatPtr(const char* label,float(*values_getter)(void* data,int idx),void* data,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size); +CIMGUI_API void igValue_Bool(const char* prefix,bool b); +CIMGUI_API void igValue_Int(const char* prefix,int v); +CIMGUI_API void igValue_Uint(const char* prefix,unsigned int v); +CIMGUI_API void igValue_Float(const char* prefix,float v,const char* float_format); +CIMGUI_API bool igBeginMenuBar(void); +CIMGUI_API void igEndMenuBar(void); +CIMGUI_API bool igBeginMainMenuBar(void); +CIMGUI_API void igEndMainMenuBar(void); +CIMGUI_API bool igBeginMenu(const char* label,bool enabled); +CIMGUI_API void igEndMenu(void); +CIMGUI_API bool igMenuItem_Bool(const char* label,const char* shortcut,bool selected,bool enabled); +CIMGUI_API bool igMenuItem_BoolPtr(const char* label,const char* shortcut,bool* p_selected,bool enabled); +CIMGUI_API void igBeginTooltip(void); +CIMGUI_API void igEndTooltip(void); +CIMGUI_API void igSetTooltip(const char* fmt,...); +CIMGUI_API void igSetTooltipV(const char* fmt,va_list args); +CIMGUI_API bool igBeginPopup(const char* str_id,ImGuiWindowFlags flags); +CIMGUI_API bool igBeginPopupModal(const char* name,bool* p_open,ImGuiWindowFlags flags); +CIMGUI_API void igEndPopup(void); +CIMGUI_API void igOpenPopup(const char* str_id,ImGuiPopupFlags popup_flags); +CIMGUI_API void igOpenPopupOnItemClick(const char* str_id,ImGuiPopupFlags popup_flags); +CIMGUI_API void igCloseCurrentPopup(void); +CIMGUI_API bool igBeginPopupContextItem(const char* str_id,ImGuiPopupFlags popup_flags); +CIMGUI_API bool igBeginPopupContextWindow(const char* str_id,ImGuiPopupFlags popup_flags); +CIMGUI_API bool igBeginPopupContextVoid(const char* str_id,ImGuiPopupFlags popup_flags); +CIMGUI_API bool igIsPopupOpen_Str(const char* str_id,ImGuiPopupFlags flags); +CIMGUI_API bool igBeginTable(const char* str_id,int column,ImGuiTableFlags flags,const ImVec2 outer_size,float inner_width); +CIMGUI_API void igEndTable(void); +CIMGUI_API void igTableNextRow(ImGuiTableRowFlags row_flags,float min_row_height); +CIMGUI_API bool igTableNextColumn(void); +CIMGUI_API bool igTableSetColumnIndex(int column_n); +CIMGUI_API void igTableSetupColumn(const char* label,ImGuiTableColumnFlags flags,float init_width_or_weight,ImGuiID user_id); +CIMGUI_API void igTableSetupScrollFreeze(int cols,int rows); +CIMGUI_API void igTableHeadersRow(void); +CIMGUI_API void igTableHeader(const char* label); +CIMGUI_API ImGuiTableSortSpecs* igTableGetSortSpecs(void); +CIMGUI_API int igTableGetColumnCount(void); +CIMGUI_API int igTableGetColumnIndex(void); +CIMGUI_API int igTableGetRowIndex(void); +CIMGUI_API const char* igTableGetColumnName_Int(int column_n); +CIMGUI_API ImGuiTableColumnFlags igTableGetColumnFlags(int column_n); +CIMGUI_API void igTableSetBgColor(ImGuiTableBgTarget target,ImU32 color,int column_n); +CIMGUI_API void igColumns(int count,const char* id,bool border); +CIMGUI_API void igNextColumn(void); +CIMGUI_API int igGetColumnIndex(void); +CIMGUI_API float igGetColumnWidth(int column_index); +CIMGUI_API void igSetColumnWidth(int column_index,float width); +CIMGUI_API float igGetColumnOffset(int column_index); +CIMGUI_API void igSetColumnOffset(int column_index,float offset_x); +CIMGUI_API int igGetColumnsCount(void); +CIMGUI_API bool igBeginTabBar(const char* str_id,ImGuiTabBarFlags flags); +CIMGUI_API void igEndTabBar(void); +CIMGUI_API bool igBeginTabItem(const char* label,bool* p_open,ImGuiTabItemFlags flags); +CIMGUI_API void igEndTabItem(void); +CIMGUI_API bool igTabItemButton(const char* label,ImGuiTabItemFlags flags); +CIMGUI_API void igSetTabItemClosed(const char* tab_or_docked_window_label); +CIMGUI_API void igLogToTTY(int auto_open_depth); +CIMGUI_API void igLogToFile(int auto_open_depth,const char* filename); +CIMGUI_API void igLogToClipboard(int auto_open_depth); +CIMGUI_API void igLogFinish(void); +CIMGUI_API void igLogButtons(void); +CIMGUI_API void igLogTextV(const char* fmt,va_list args); +CIMGUI_API bool igBeginDragDropSource(ImGuiDragDropFlags flags); +CIMGUI_API bool igSetDragDropPayload(const char* type,const void* data,size_t sz,ImGuiCond cond); +CIMGUI_API void igEndDragDropSource(void); +CIMGUI_API bool igBeginDragDropTarget(void); +CIMGUI_API const ImGuiPayload* igAcceptDragDropPayload(const char* type,ImGuiDragDropFlags flags); +CIMGUI_API void igEndDragDropTarget(void); +CIMGUI_API const ImGuiPayload* igGetDragDropPayload(void); +CIMGUI_API void igPushClipRect(const ImVec2 clip_rect_min,const ImVec2 clip_rect_max,bool intersect_with_current_clip_rect); +CIMGUI_API void igPopClipRect(void); +CIMGUI_API void igSetItemDefaultFocus(void); +CIMGUI_API void igSetKeyboardFocusHere(int offset); +CIMGUI_API bool igIsItemHovered(ImGuiHoveredFlags flags); +CIMGUI_API bool igIsItemActive(void); +CIMGUI_API bool igIsItemFocused(void); +CIMGUI_API bool igIsItemClicked(ImGuiMouseButton mouse_button); +CIMGUI_API bool igIsItemVisible(void); +CIMGUI_API bool igIsItemEdited(void); +CIMGUI_API bool igIsItemActivated(void); +CIMGUI_API bool igIsItemDeactivated(void); +CIMGUI_API bool igIsItemDeactivatedAfterEdit(void); +CIMGUI_API bool igIsItemToggledOpen(void); +CIMGUI_API bool igIsAnyItemHovered(void); +CIMGUI_API bool igIsAnyItemActive(void); +CIMGUI_API bool igIsAnyItemFocused(void); +CIMGUI_API void igGetItemRectMin(ImVec2 *pOut); +CIMGUI_API void igGetItemRectMax(ImVec2 *pOut); +CIMGUI_API void igGetItemRectSize(ImVec2 *pOut); +CIMGUI_API void igSetItemAllowOverlap(void); +CIMGUI_API ImGuiViewport* igGetMainViewport(void); +CIMGUI_API bool igIsRectVisible_Nil(const ImVec2 size); +CIMGUI_API bool igIsRectVisible_Vec2(const ImVec2 rect_min,const ImVec2 rect_max); +CIMGUI_API double igGetTime(void); +CIMGUI_API int igGetFrameCount(void); +CIMGUI_API ImDrawList* igGetBackgroundDrawList_Nil(void); +CIMGUI_API ImDrawList* igGetForegroundDrawList_Nil(void); +CIMGUI_API ImDrawListSharedData* igGetDrawListSharedData(void); +CIMGUI_API const char* igGetStyleColorName(ImGuiCol idx); +CIMGUI_API void igSetStateStorage(ImGuiStorage* storage); +CIMGUI_API ImGuiStorage* igGetStateStorage(void); +CIMGUI_API void igCalcListClipping(int items_count,float items_height,int* out_items_display_start,int* out_items_display_end); +CIMGUI_API bool igBeginChildFrame(ImGuiID id,const ImVec2 size,ImGuiWindowFlags flags); +CIMGUI_API void igEndChildFrame(void); +CIMGUI_API void igCalcTextSize(ImVec2 *pOut,const char* text,const char* text_end,bool hide_text_after_double_hash,float wrap_width); +CIMGUI_API void igColorConvertU32ToFloat4(ImVec4 *pOut,ImU32 in); +CIMGUI_API ImU32 igColorConvertFloat4ToU32(const ImVec4 in); +CIMGUI_API void igColorConvertRGBtoHSV(float r,float g,float b,float* out_h,float* out_s,float* out_v); +CIMGUI_API void igColorConvertHSVtoRGB(float h,float s,float v,float* out_r,float* out_g,float* out_b); +CIMGUI_API int igGetKeyIndex(ImGuiKey imgui_key); +CIMGUI_API bool igIsKeyDown(int user_key_index); +CIMGUI_API bool igIsKeyPressed(int user_key_index,bool repeat); +CIMGUI_API bool igIsKeyReleased(int user_key_index); +CIMGUI_API int igGetKeyPressedAmount(int key_index,float repeat_delay,float rate); +CIMGUI_API void igCaptureKeyboardFromApp(bool want_capture_keyboard_value); +CIMGUI_API bool igIsMouseDown(ImGuiMouseButton button); +CIMGUI_API bool igIsMouseClicked(ImGuiMouseButton button,bool repeat); +CIMGUI_API bool igIsMouseReleased(ImGuiMouseButton button); +CIMGUI_API bool igIsMouseDoubleClicked(ImGuiMouseButton button); +CIMGUI_API bool igIsMouseHoveringRect(const ImVec2 r_min,const ImVec2 r_max,bool clip); +CIMGUI_API bool igIsMousePosValid(const ImVec2* mouse_pos); +CIMGUI_API bool igIsAnyMouseDown(void); +CIMGUI_API void igGetMousePos(ImVec2 *pOut); +CIMGUI_API void igGetMousePosOnOpeningCurrentPopup(ImVec2 *pOut); +CIMGUI_API bool igIsMouseDragging(ImGuiMouseButton button,float lock_threshold); +CIMGUI_API void igGetMouseDragDelta(ImVec2 *pOut,ImGuiMouseButton button,float lock_threshold); +CIMGUI_API void igResetMouseDragDelta(ImGuiMouseButton button); +CIMGUI_API ImGuiMouseCursor igGetMouseCursor(void); +CIMGUI_API void igSetMouseCursor(ImGuiMouseCursor cursor_type); +CIMGUI_API void igCaptureMouseFromApp(bool want_capture_mouse_value); +CIMGUI_API const char* igGetClipboardText(void); +CIMGUI_API void igSetClipboardText(const char* text); +CIMGUI_API void igLoadIniSettingsFromDisk(const char* ini_filename); +CIMGUI_API void igLoadIniSettingsFromMemory(const char* ini_data,size_t ini_size); +CIMGUI_API void igSaveIniSettingsToDisk(const char* ini_filename); +CIMGUI_API const char* igSaveIniSettingsToMemory(size_t* out_ini_size); +CIMGUI_API bool igDebugCheckVersionAndDataLayout(const char* version_str,size_t sz_io,size_t sz_style,size_t sz_vec2,size_t sz_vec4,size_t sz_drawvert,size_t sz_drawidx); +CIMGUI_API void igSetAllocatorFunctions(ImGuiMemAllocFunc alloc_func,ImGuiMemFreeFunc free_func,void* user_data); +CIMGUI_API void igGetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func,ImGuiMemFreeFunc* p_free_func,void** p_user_data); +CIMGUI_API void* igMemAlloc(size_t size); +CIMGUI_API void igMemFree(void* ptr); +CIMGUI_API ImGuiStyle* ImGuiStyle_ImGuiStyle(void); +CIMGUI_API void ImGuiStyle_destroy(ImGuiStyle* self); +CIMGUI_API void ImGuiStyle_ScaleAllSizes(ImGuiStyle* self,float scale_factor); +CIMGUI_API void ImGuiIO_AddInputCharacter(ImGuiIO* self,unsigned int c); +CIMGUI_API void ImGuiIO_AddInputCharacterUTF16(ImGuiIO* self,ImWchar16 c); +CIMGUI_API void ImGuiIO_AddInputCharactersUTF8(ImGuiIO* self,const char* str); +CIMGUI_API void ImGuiIO_ClearInputCharacters(ImGuiIO* self); +CIMGUI_API ImGuiIO* ImGuiIO_ImGuiIO(void); +CIMGUI_API void ImGuiIO_destroy(ImGuiIO* self); +CIMGUI_API ImGuiInputTextCallbackData* ImGuiInputTextCallbackData_ImGuiInputTextCallbackData(void); +CIMGUI_API void ImGuiInputTextCallbackData_destroy(ImGuiInputTextCallbackData* self); +CIMGUI_API void ImGuiInputTextCallbackData_DeleteChars(ImGuiInputTextCallbackData* self,int pos,int bytes_count); +CIMGUI_API void ImGuiInputTextCallbackData_InsertChars(ImGuiInputTextCallbackData* self,int pos,const char* text,const char* text_end); +CIMGUI_API void ImGuiInputTextCallbackData_SelectAll(ImGuiInputTextCallbackData* self); +CIMGUI_API void ImGuiInputTextCallbackData_ClearSelection(ImGuiInputTextCallbackData* self); +CIMGUI_API bool ImGuiInputTextCallbackData_HasSelection(ImGuiInputTextCallbackData* self); +CIMGUI_API ImGuiPayload* ImGuiPayload_ImGuiPayload(void); +CIMGUI_API void ImGuiPayload_destroy(ImGuiPayload* self); +CIMGUI_API void ImGuiPayload_Clear(ImGuiPayload* self); +CIMGUI_API bool ImGuiPayload_IsDataType(ImGuiPayload* self,const char* type); +CIMGUI_API bool ImGuiPayload_IsPreview(ImGuiPayload* self); +CIMGUI_API bool ImGuiPayload_IsDelivery(ImGuiPayload* self); +CIMGUI_API ImGuiTableColumnSortSpecs* ImGuiTableColumnSortSpecs_ImGuiTableColumnSortSpecs(void); +CIMGUI_API void ImGuiTableColumnSortSpecs_destroy(ImGuiTableColumnSortSpecs* self); +CIMGUI_API ImGuiTableSortSpecs* ImGuiTableSortSpecs_ImGuiTableSortSpecs(void); +CIMGUI_API void ImGuiTableSortSpecs_destroy(ImGuiTableSortSpecs* self); +CIMGUI_API ImGuiOnceUponAFrame* ImGuiOnceUponAFrame_ImGuiOnceUponAFrame(void); +CIMGUI_API void ImGuiOnceUponAFrame_destroy(ImGuiOnceUponAFrame* self); +CIMGUI_API ImGuiTextFilter* ImGuiTextFilter_ImGuiTextFilter(const char* default_filter); +CIMGUI_API void ImGuiTextFilter_destroy(ImGuiTextFilter* self); +CIMGUI_API bool ImGuiTextFilter_Draw(ImGuiTextFilter* self,const char* label,float width); +CIMGUI_API bool ImGuiTextFilter_PassFilter(ImGuiTextFilter* self,const char* text,const char* text_end); +CIMGUI_API void ImGuiTextFilter_Build(ImGuiTextFilter* self); +CIMGUI_API void ImGuiTextFilter_Clear(ImGuiTextFilter* self); +CIMGUI_API bool ImGuiTextFilter_IsActive(ImGuiTextFilter* self); +CIMGUI_API ImGuiTextRange* ImGuiTextRange_ImGuiTextRange_Nil(void); +CIMGUI_API void ImGuiTextRange_destroy(ImGuiTextRange* self); +CIMGUI_API ImGuiTextRange* ImGuiTextRange_ImGuiTextRange_Str(const char* _b,const char* _e); +CIMGUI_API bool ImGuiTextRange_empty(ImGuiTextRange* self); +CIMGUI_API void ImGuiTextRange_split(ImGuiTextRange* self,char separator,ImVector_ImGuiTextRange* out); +CIMGUI_API ImGuiTextBuffer* ImGuiTextBuffer_ImGuiTextBuffer(void); +CIMGUI_API void ImGuiTextBuffer_destroy(ImGuiTextBuffer* self); +CIMGUI_API const char* ImGuiTextBuffer_begin(ImGuiTextBuffer* self); +CIMGUI_API const char* ImGuiTextBuffer_end(ImGuiTextBuffer* self); +CIMGUI_API int ImGuiTextBuffer_size(ImGuiTextBuffer* self); +CIMGUI_API bool ImGuiTextBuffer_empty(ImGuiTextBuffer* self); +CIMGUI_API void ImGuiTextBuffer_clear(ImGuiTextBuffer* self); +CIMGUI_API void ImGuiTextBuffer_reserve(ImGuiTextBuffer* self,int capacity); +CIMGUI_API const char* ImGuiTextBuffer_c_str(ImGuiTextBuffer* self); +CIMGUI_API void ImGuiTextBuffer_append(ImGuiTextBuffer* self,const char* str,const char* str_end); +CIMGUI_API void ImGuiTextBuffer_appendfv(ImGuiTextBuffer* self,const char* fmt,va_list args); +CIMGUI_API ImGuiStoragePair* ImGuiStoragePair_ImGuiStoragePair_Int(ImGuiID _key,int _val_i); +CIMGUI_API void ImGuiStoragePair_destroy(ImGuiStoragePair* self); +CIMGUI_API ImGuiStoragePair* ImGuiStoragePair_ImGuiStoragePair_Float(ImGuiID _key,float _val_f); +CIMGUI_API ImGuiStoragePair* ImGuiStoragePair_ImGuiStoragePair_Ptr(ImGuiID _key,void* _val_p); +CIMGUI_API void ImGuiStorage_Clear(ImGuiStorage* self); +CIMGUI_API int ImGuiStorage_GetInt(ImGuiStorage* self,ImGuiID key,int default_val); +CIMGUI_API void ImGuiStorage_SetInt(ImGuiStorage* self,ImGuiID key,int val); +CIMGUI_API bool ImGuiStorage_GetBool(ImGuiStorage* self,ImGuiID key,bool default_val); +CIMGUI_API void ImGuiStorage_SetBool(ImGuiStorage* self,ImGuiID key,bool val); +CIMGUI_API float ImGuiStorage_GetFloat(ImGuiStorage* self,ImGuiID key,float default_val); +CIMGUI_API void ImGuiStorage_SetFloat(ImGuiStorage* self,ImGuiID key,float val); +CIMGUI_API void* ImGuiStorage_GetVoidPtr(ImGuiStorage* self,ImGuiID key); +CIMGUI_API void ImGuiStorage_SetVoidPtr(ImGuiStorage* self,ImGuiID key,void* val); +CIMGUI_API int* ImGuiStorage_GetIntRef(ImGuiStorage* self,ImGuiID key,int default_val); +CIMGUI_API bool* ImGuiStorage_GetBoolRef(ImGuiStorage* self,ImGuiID key,bool default_val); +CIMGUI_API float* ImGuiStorage_GetFloatRef(ImGuiStorage* self,ImGuiID key,float default_val); +CIMGUI_API void** ImGuiStorage_GetVoidPtrRef(ImGuiStorage* self,ImGuiID key,void* default_val); +CIMGUI_API void ImGuiStorage_SetAllInt(ImGuiStorage* self,int val); +CIMGUI_API void ImGuiStorage_BuildSortByKey(ImGuiStorage* self); +CIMGUI_API ImGuiListClipper* ImGuiListClipper_ImGuiListClipper(void); +CIMGUI_API void ImGuiListClipper_destroy(ImGuiListClipper* self); +CIMGUI_API void ImGuiListClipper_Begin(ImGuiListClipper* self,int items_count,float items_height); +CIMGUI_API void ImGuiListClipper_End(ImGuiListClipper* self); +CIMGUI_API bool ImGuiListClipper_Step(ImGuiListClipper* self); +CIMGUI_API ImColor* ImColor_ImColor_Nil(void); +CIMGUI_API void ImColor_destroy(ImColor* self); +CIMGUI_API ImColor* ImColor_ImColor_Int(int r,int g,int b,int a); +CIMGUI_API ImColor* ImColor_ImColor_U32(ImU32 rgba); +CIMGUI_API ImColor* ImColor_ImColor_Float(float r,float g,float b,float a); +CIMGUI_API ImColor* ImColor_ImColor_Vec4(const ImVec4 col); +CIMGUI_API void ImColor_SetHSV(ImColor* self,float h,float s,float v,float a); +CIMGUI_API void ImColor_HSV(ImColor *pOut,float h,float s,float v,float a); +CIMGUI_API ImDrawCmd* ImDrawCmd_ImDrawCmd(void); +CIMGUI_API void ImDrawCmd_destroy(ImDrawCmd* self); +CIMGUI_API ImDrawListSplitter* ImDrawListSplitter_ImDrawListSplitter(void); +CIMGUI_API void ImDrawListSplitter_destroy(ImDrawListSplitter* self); +CIMGUI_API void ImDrawListSplitter_Clear(ImDrawListSplitter* self); +CIMGUI_API void ImDrawListSplitter_ClearFreeMemory(ImDrawListSplitter* self); +CIMGUI_API void ImDrawListSplitter_Split(ImDrawListSplitter* self,ImDrawList* draw_list,int count); +CIMGUI_API void ImDrawListSplitter_Merge(ImDrawListSplitter* self,ImDrawList* draw_list); +CIMGUI_API void ImDrawListSplitter_SetCurrentChannel(ImDrawListSplitter* self,ImDrawList* draw_list,int channel_idx); +CIMGUI_API ImDrawList* ImDrawList_ImDrawList(const ImDrawListSharedData* shared_data); +CIMGUI_API void ImDrawList_destroy(ImDrawList* self); +CIMGUI_API void ImDrawList_PushClipRect(ImDrawList* self,ImVec2 clip_rect_min,ImVec2 clip_rect_max,bool intersect_with_current_clip_rect); +CIMGUI_API void ImDrawList_PushClipRectFullScreen(ImDrawList* self); +CIMGUI_API void ImDrawList_PopClipRect(ImDrawList* self); +CIMGUI_API void ImDrawList_PushTextureID(ImDrawList* self,ImTextureID texture_id); +CIMGUI_API void ImDrawList_PopTextureID(ImDrawList* self); +CIMGUI_API void ImDrawList_GetClipRectMin(ImVec2 *pOut,ImDrawList* self); +CIMGUI_API void ImDrawList_GetClipRectMax(ImVec2 *pOut,ImDrawList* self); +CIMGUI_API void ImDrawList_AddLine(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,ImU32 col,float thickness); +CIMGUI_API void ImDrawList_AddRect(ImDrawList* self,const ImVec2 p_min,const ImVec2 p_max,ImU32 col,float rounding,ImDrawFlags flags,float thickness); +CIMGUI_API void ImDrawList_AddRectFilled(ImDrawList* self,const ImVec2 p_min,const ImVec2 p_max,ImU32 col,float rounding,ImDrawFlags flags); +CIMGUI_API void ImDrawList_AddRectFilledMultiColor(ImDrawList* self,const ImVec2 p_min,const ImVec2 p_max,ImU32 col_upr_left,ImU32 col_upr_right,ImU32 col_bot_right,ImU32 col_bot_left); +CIMGUI_API void ImDrawList_AddQuad(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,ImU32 col,float thickness); +CIMGUI_API void ImDrawList_AddQuadFilled(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,ImU32 col); +CIMGUI_API void ImDrawList_AddTriangle(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,ImU32 col,float thickness); +CIMGUI_API void ImDrawList_AddTriangleFilled(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,ImU32 col); +CIMGUI_API void ImDrawList_AddCircle(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments,float thickness); +CIMGUI_API void ImDrawList_AddCircleFilled(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments); +CIMGUI_API void ImDrawList_AddNgon(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments,float thickness); +CIMGUI_API void ImDrawList_AddNgonFilled(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments); +CIMGUI_API void ImDrawList_AddText_Vec2(ImDrawList* self,const ImVec2 pos,ImU32 col,const char* text_begin,const char* text_end); +CIMGUI_API void ImDrawList_AddText_FontPtr(ImDrawList* self,const ImFont* font,float font_size,const ImVec2 pos,ImU32 col,const char* text_begin,const char* text_end,float wrap_width,const ImVec4* cpu_fine_clip_rect); +CIMGUI_API void ImDrawList_AddPolyline(ImDrawList* self,const ImVec2* points,int num_points,ImU32 col,ImDrawFlags flags,float thickness); +CIMGUI_API void ImDrawList_AddConvexPolyFilled(ImDrawList* self,const ImVec2* points,int num_points,ImU32 col); +CIMGUI_API void ImDrawList_AddBezierCubic(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,ImU32 col,float thickness,int num_segments); +CIMGUI_API void ImDrawList_AddBezierQuadratic(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,ImU32 col,float thickness,int num_segments); +CIMGUI_API void ImDrawList_AddImage(ImDrawList* self,ImTextureID user_texture_id,const ImVec2 p_min,const ImVec2 p_max,const ImVec2 uv_min,const ImVec2 uv_max,ImU32 col); +CIMGUI_API void ImDrawList_AddImageQuad(ImDrawList* self,ImTextureID user_texture_id,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,const ImVec2 uv1,const ImVec2 uv2,const ImVec2 uv3,const ImVec2 uv4,ImU32 col); +CIMGUI_API void ImDrawList_AddImageRounded(ImDrawList* self,ImTextureID user_texture_id,const ImVec2 p_min,const ImVec2 p_max,const ImVec2 uv_min,const ImVec2 uv_max,ImU32 col,float rounding,ImDrawFlags flags); +CIMGUI_API void ImDrawList_PathClear(ImDrawList* self); +CIMGUI_API void ImDrawList_PathLineTo(ImDrawList* self,const ImVec2 pos); +CIMGUI_API void ImDrawList_PathLineToMergeDuplicate(ImDrawList* self,const ImVec2 pos); +CIMGUI_API void ImDrawList_PathFillConvex(ImDrawList* self,ImU32 col); +CIMGUI_API void ImDrawList_PathStroke(ImDrawList* self,ImU32 col,ImDrawFlags flags,float thickness); +CIMGUI_API void ImDrawList_PathArcTo(ImDrawList* self,const ImVec2 center,float radius,float a_min,float a_max,int num_segments); +CIMGUI_API void ImDrawList_PathArcToFast(ImDrawList* self,const ImVec2 center,float radius,int a_min_of_12,int a_max_of_12); +CIMGUI_API void ImDrawList_PathBezierCubicCurveTo(ImDrawList* self,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,int num_segments); +CIMGUI_API void ImDrawList_PathBezierQuadraticCurveTo(ImDrawList* self,const ImVec2 p2,const ImVec2 p3,int num_segments); +CIMGUI_API void ImDrawList_PathRect(ImDrawList* self,const ImVec2 rect_min,const ImVec2 rect_max,float rounding,ImDrawFlags flags); +CIMGUI_API void ImDrawList_AddCallback(ImDrawList* self,ImDrawCallback callback,void* callback_data); +CIMGUI_API void ImDrawList_AddDrawCmd(ImDrawList* self); +CIMGUI_API ImDrawList* ImDrawList_CloneOutput(ImDrawList* self); +CIMGUI_API void ImDrawList_ChannelsSplit(ImDrawList* self,int count); +CIMGUI_API void ImDrawList_ChannelsMerge(ImDrawList* self); +CIMGUI_API void ImDrawList_ChannelsSetCurrent(ImDrawList* self,int n); +CIMGUI_API void ImDrawList_PrimReserve(ImDrawList* self,int idx_count,int vtx_count); +CIMGUI_API void ImDrawList_PrimUnreserve(ImDrawList* self,int idx_count,int vtx_count); +CIMGUI_API void ImDrawList_PrimRect(ImDrawList* self,const ImVec2 a,const ImVec2 b,ImU32 col); +CIMGUI_API void ImDrawList_PrimRectUV(ImDrawList* self,const ImVec2 a,const ImVec2 b,const ImVec2 uv_a,const ImVec2 uv_b,ImU32 col); +CIMGUI_API void ImDrawList_PrimQuadUV(ImDrawList* self,const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 d,const ImVec2 uv_a,const ImVec2 uv_b,const ImVec2 uv_c,const ImVec2 uv_d,ImU32 col); +CIMGUI_API void ImDrawList_PrimWriteVtx(ImDrawList* self,const ImVec2 pos,const ImVec2 uv,ImU32 col); +CIMGUI_API void ImDrawList_PrimWriteIdx(ImDrawList* self,ImDrawIdx idx); +CIMGUI_API void ImDrawList_PrimVtx(ImDrawList* self,const ImVec2 pos,const ImVec2 uv,ImU32 col); +CIMGUI_API void ImDrawList__ResetForNewFrame(ImDrawList* self); +CIMGUI_API void ImDrawList__ClearFreeMemory(ImDrawList* self); +CIMGUI_API void ImDrawList__PopUnusedDrawCmd(ImDrawList* self); +CIMGUI_API void ImDrawList__OnChangedClipRect(ImDrawList* self); +CIMGUI_API void ImDrawList__OnChangedTextureID(ImDrawList* self); +CIMGUI_API void ImDrawList__OnChangedVtxOffset(ImDrawList* self); +CIMGUI_API int ImDrawList__CalcCircleAutoSegmentCount(ImDrawList* self,float radius); +CIMGUI_API void ImDrawList__PathArcToFastEx(ImDrawList* self,const ImVec2 center,float radius,int a_min_sample,int a_max_sample,int a_step); +CIMGUI_API void ImDrawList__PathArcToN(ImDrawList* self,const ImVec2 center,float radius,float a_min,float a_max,int num_segments); +CIMGUI_API ImDrawData* ImDrawData_ImDrawData(void); +CIMGUI_API void ImDrawData_destroy(ImDrawData* self); +CIMGUI_API void ImDrawData_Clear(ImDrawData* self); +CIMGUI_API void ImDrawData_DeIndexAllBuffers(ImDrawData* self); +CIMGUI_API void ImDrawData_ScaleClipRects(ImDrawData* self,const ImVec2 fb_scale); +CIMGUI_API ImFontConfig* ImFontConfig_ImFontConfig(void); +CIMGUI_API void ImFontConfig_destroy(ImFontConfig* self); +CIMGUI_API ImFontGlyphRangesBuilder* ImFontGlyphRangesBuilder_ImFontGlyphRangesBuilder(void); +CIMGUI_API void ImFontGlyphRangesBuilder_destroy(ImFontGlyphRangesBuilder* self); +CIMGUI_API void ImFontGlyphRangesBuilder_Clear(ImFontGlyphRangesBuilder* self); +CIMGUI_API bool ImFontGlyphRangesBuilder_GetBit(ImFontGlyphRangesBuilder* self,size_t n); +CIMGUI_API void ImFontGlyphRangesBuilder_SetBit(ImFontGlyphRangesBuilder* self,size_t n); +CIMGUI_API void ImFontGlyphRangesBuilder_AddChar(ImFontGlyphRangesBuilder* self,ImWchar c); +CIMGUI_API void ImFontGlyphRangesBuilder_AddText(ImFontGlyphRangesBuilder* self,const char* text,const char* text_end); +CIMGUI_API void ImFontGlyphRangesBuilder_AddRanges(ImFontGlyphRangesBuilder* self,const ImWchar* ranges); +CIMGUI_API void ImFontGlyphRangesBuilder_BuildRanges(ImFontGlyphRangesBuilder* self,ImVector_ImWchar* out_ranges); +CIMGUI_API ImFontAtlasCustomRect* ImFontAtlasCustomRect_ImFontAtlasCustomRect(void); +CIMGUI_API void ImFontAtlasCustomRect_destroy(ImFontAtlasCustomRect* self); +CIMGUI_API bool ImFontAtlasCustomRect_IsPacked(ImFontAtlasCustomRect* self); +CIMGUI_API ImFontAtlas* ImFontAtlas_ImFontAtlas(void); +CIMGUI_API void ImFontAtlas_destroy(ImFontAtlas* self); +CIMGUI_API ImFont* ImFontAtlas_AddFont(ImFontAtlas* self,const ImFontConfig* font_cfg); +CIMGUI_API ImFont* ImFontAtlas_AddFontDefault(ImFontAtlas* self,const ImFontConfig* font_cfg); +CIMGUI_API ImFont* ImFontAtlas_AddFontFromFileTTF(ImFontAtlas* self,const char* filename,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges); +CIMGUI_API ImFont* ImFontAtlas_AddFontFromMemoryTTF(ImFontAtlas* self,void* font_data,int font_size,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges); +CIMGUI_API ImFont* ImFontAtlas_AddFontFromMemoryCompressedTTF(ImFontAtlas* self,const void* compressed_font_data,int compressed_font_size,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges); +CIMGUI_API ImFont* ImFontAtlas_AddFontFromMemoryCompressedBase85TTF(ImFontAtlas* self,const char* compressed_font_data_base85,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges); +CIMGUI_API void ImFontAtlas_ClearInputData(ImFontAtlas* self); +CIMGUI_API void ImFontAtlas_ClearTexData(ImFontAtlas* self); +CIMGUI_API void ImFontAtlas_ClearFonts(ImFontAtlas* self); +CIMGUI_API void ImFontAtlas_Clear(ImFontAtlas* self); +CIMGUI_API bool ImFontAtlas_Build(ImFontAtlas* self); +CIMGUI_API void ImFontAtlas_GetTexDataAsAlpha8(ImFontAtlas* self,unsigned char** out_pixels,int* out_width,int* out_height,int* out_bytes_per_pixel); +CIMGUI_API void ImFontAtlas_GetTexDataAsRGBA32(ImFontAtlas* self,unsigned char** out_pixels,int* out_width,int* out_height,int* out_bytes_per_pixel); +CIMGUI_API bool ImFontAtlas_IsBuilt(ImFontAtlas* self); +CIMGUI_API void ImFontAtlas_SetTexID(ImFontAtlas* self,ImTextureID id); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesDefault(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesKorean(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesJapanese(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesChineseFull(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesChineseSimplifiedCommon(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesCyrillic(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesThai(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesVietnamese(ImFontAtlas* self); +CIMGUI_API int ImFontAtlas_AddCustomRectRegular(ImFontAtlas* self,int width,int height); +CIMGUI_API int ImFontAtlas_AddCustomRectFontGlyph(ImFontAtlas* self,ImFont* font,ImWchar id,int width,int height,float advance_x,const ImVec2 offset); +CIMGUI_API ImFontAtlasCustomRect* ImFontAtlas_GetCustomRectByIndex(ImFontAtlas* self,int index); +CIMGUI_API void ImFontAtlas_CalcCustomRectUV(ImFontAtlas* self,const ImFontAtlasCustomRect* rect,ImVec2* out_uv_min,ImVec2* out_uv_max); +CIMGUI_API bool ImFontAtlas_GetMouseCursorTexData(ImFontAtlas* self,ImGuiMouseCursor cursor,ImVec2* out_offset,ImVec2* out_size,ImVec2 out_uv_border[2],ImVec2 out_uv_fill[2]); +CIMGUI_API ImFont* ImFont_ImFont(void); +CIMGUI_API void ImFont_destroy(ImFont* self); +CIMGUI_API const ImFontGlyph* ImFont_FindGlyph(ImFont* self,ImWchar c); +CIMGUI_API const ImFontGlyph* ImFont_FindGlyphNoFallback(ImFont* self,ImWchar c); +CIMGUI_API float ImFont_GetCharAdvance(ImFont* self,ImWchar c); +CIMGUI_API bool ImFont_IsLoaded(ImFont* self); +CIMGUI_API const char* ImFont_GetDebugName(ImFont* self); +CIMGUI_API void ImFont_CalcTextSizeA(ImVec2 *pOut,ImFont* self,float size,float max_width,float wrap_width,const char* text_begin,const char* text_end,const char** remaining); +CIMGUI_API const char* ImFont_CalcWordWrapPositionA(ImFont* self,float scale,const char* text,const char* text_end,float wrap_width); +CIMGUI_API void ImFont_RenderChar(ImFont* self,ImDrawList* draw_list,float size,ImVec2 pos,ImU32 col,ImWchar c); +CIMGUI_API void ImFont_RenderText(ImFont* self,ImDrawList* draw_list,float size,ImVec2 pos,ImU32 col,const ImVec4 clip_rect,const char* text_begin,const char* text_end,float wrap_width,bool cpu_fine_clip); +CIMGUI_API void ImFont_BuildLookupTable(ImFont* self); +CIMGUI_API void ImFont_ClearOutputData(ImFont* self); +CIMGUI_API void ImFont_GrowIndex(ImFont* self,int new_size); +CIMGUI_API void ImFont_AddGlyph(ImFont* self,const ImFontConfig* src_cfg,ImWchar c,float x0,float y0,float x1,float y1,float u0,float v0,float u1,float v1,float advance_x); +CIMGUI_API void ImFont_AddRemapChar(ImFont* self,ImWchar dst,ImWchar src,bool overwrite_dst); +CIMGUI_API void ImFont_SetGlyphVisible(ImFont* self,ImWchar c,bool visible); +CIMGUI_API void ImFont_SetFallbackChar(ImFont* self,ImWchar c); +CIMGUI_API bool ImFont_IsGlyphRangeUnused(ImFont* self,unsigned int c_begin,unsigned int c_last); +CIMGUI_API ImGuiViewport* ImGuiViewport_ImGuiViewport(void); +CIMGUI_API void ImGuiViewport_destroy(ImGuiViewport* self); +CIMGUI_API void ImGuiViewport_GetCenter(ImVec2 *pOut,ImGuiViewport* self); +CIMGUI_API void ImGuiViewport_GetWorkCenter(ImVec2 *pOut,ImGuiViewport* self); +CIMGUI_API ImGuiID igImHashData(const void* data,size_t data_size,ImU32 seed); +CIMGUI_API ImGuiID igImHashStr(const char* data,size_t data_size,ImU32 seed); +CIMGUI_API ImU32 igImAlphaBlendColors(ImU32 col_a,ImU32 col_b); +CIMGUI_API bool igImIsPowerOfTwo_Int(int v); +CIMGUI_API bool igImIsPowerOfTwo_U64(ImU64 v); +CIMGUI_API int igImUpperPowerOfTwo(int v); +CIMGUI_API int igImStricmp(const char* str1,const char* str2); +CIMGUI_API int igImStrnicmp(const char* str1,const char* str2,size_t count); +CIMGUI_API void igImStrncpy(char* dst,const char* src,size_t count); +CIMGUI_API char* igImStrdup(const char* str); +CIMGUI_API char* igImStrdupcpy(char* dst,size_t* p_dst_size,const char* str); +CIMGUI_API const char* igImStrchrRange(const char* str_begin,const char* str_end,char c); +CIMGUI_API int igImStrlenW(const ImWchar* str); +CIMGUI_API const char* igImStreolRange(const char* str,const char* str_end); +CIMGUI_API const ImWchar* igImStrbolW(const ImWchar* buf_mid_line,const ImWchar* buf_begin); +CIMGUI_API const char* igImStristr(const char* haystack,const char* haystack_end,const char* needle,const char* needle_end); +CIMGUI_API void igImStrTrimBlanks(char* str); +CIMGUI_API const char* igImStrSkipBlank(const char* str); +CIMGUI_API int igImFormatString(char* buf,size_t buf_size,const char* fmt,...); +CIMGUI_API int igImFormatStringV(char* buf,size_t buf_size,const char* fmt,va_list args); +CIMGUI_API const char* igImParseFormatFindStart(const char* format); +CIMGUI_API const char* igImParseFormatFindEnd(const char* format); +CIMGUI_API const char* igImParseFormatTrimDecorations(const char* format,char* buf,size_t buf_size); +CIMGUI_API int igImParseFormatPrecision(const char* format,int default_value); +CIMGUI_API bool igImCharIsBlankA(char c); +CIMGUI_API bool igImCharIsBlankW(unsigned int c); +CIMGUI_API int igImTextStrToUtf8(char* buf,int buf_size,const ImWchar* in_text,const ImWchar* in_text_end); +CIMGUI_API int igImTextCharFromUtf8(unsigned int* out_char,const char* in_text,const char* in_text_end); +CIMGUI_API int igImTextStrFromUtf8(ImWchar* buf,int buf_size,const char* in_text,const char* in_text_end,const char** in_remaining); +CIMGUI_API int igImTextCountCharsFromUtf8(const char* in_text,const char* in_text_end); +CIMGUI_API int igImTextCountUtf8BytesFromChar(const char* in_text,const char* in_text_end); +CIMGUI_API int igImTextCountUtf8BytesFromStr(const ImWchar* in_text,const ImWchar* in_text_end); +CIMGUI_API ImFileHandle igImFileOpen(const char* filename,const char* mode); +CIMGUI_API bool igImFileClose(ImFileHandle file); +CIMGUI_API ImU64 igImFileGetSize(ImFileHandle file); +CIMGUI_API ImU64 igImFileRead(void* data,ImU64 size,ImU64 count,ImFileHandle file); +CIMGUI_API ImU64 igImFileWrite(const void* data,ImU64 size,ImU64 count,ImFileHandle file); +CIMGUI_API void* igImFileLoadToMemory(const char* filename,const char* mode,size_t* out_file_size,int padding_bytes); +CIMGUI_API float igImPow_Float(float x,float y); +CIMGUI_API double igImPow_double(double x,double y); +CIMGUI_API float igImLog_Float(float x); +CIMGUI_API double igImLog_double(double x); +CIMGUI_API float igImAbs_Float(float x); +CIMGUI_API double igImAbs_double(double x); +CIMGUI_API float igImSign_Float(float x); +CIMGUI_API double igImSign_double(double x); +CIMGUI_API void igImMin(ImVec2 *pOut,const ImVec2 lhs,const ImVec2 rhs); +CIMGUI_API void igImMax(ImVec2 *pOut,const ImVec2 lhs,const ImVec2 rhs); +CIMGUI_API void igImClamp(ImVec2 *pOut,const ImVec2 v,const ImVec2 mn,ImVec2 mx); +CIMGUI_API void igImLerp_Vec2Float(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,float t); +CIMGUI_API void igImLerp_Vec2Vec2(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,const ImVec2 t); +CIMGUI_API void igImLerp_Vec4(ImVec4 *pOut,const ImVec4 a,const ImVec4 b,float t); +CIMGUI_API float igImSaturate(float f); +CIMGUI_API float igImLengthSqr_Vec2(const ImVec2 lhs); +CIMGUI_API float igImLengthSqr_Vec4(const ImVec4 lhs); +CIMGUI_API float igImInvLength(const ImVec2 lhs,float fail_value); +CIMGUI_API float igImFloor_Float(float f); +CIMGUI_API void igImFloor_Vec2(ImVec2 *pOut,const ImVec2 v); +CIMGUI_API int igImModPositive(int a,int b); +CIMGUI_API float igImDot(const ImVec2 a,const ImVec2 b); +CIMGUI_API void igImRotate(ImVec2 *pOut,const ImVec2 v,float cos_a,float sin_a); +CIMGUI_API float igImLinearSweep(float current,float target,float speed); +CIMGUI_API void igImMul(ImVec2 *pOut,const ImVec2 lhs,const ImVec2 rhs); +CIMGUI_API void igImBezierCubicCalc(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,float t); +CIMGUI_API void igImBezierCubicClosestPoint(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,const ImVec2 p,int num_segments); +CIMGUI_API void igImBezierCubicClosestPointCasteljau(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,const ImVec2 p,float tess_tol); +CIMGUI_API void igImBezierQuadraticCalc(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,float t); +CIMGUI_API void igImLineClosestPoint(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,const ImVec2 p); +CIMGUI_API bool igImTriangleContainsPoint(const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 p); +CIMGUI_API void igImTriangleClosestPoint(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 p); +CIMGUI_API void igImTriangleBarycentricCoords(const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 p,float* out_u,float* out_v,float* out_w); +CIMGUI_API float igImTriangleArea(const ImVec2 a,const ImVec2 b,const ImVec2 c); +CIMGUI_API ImGuiDir igImGetDirQuadrantFromDelta(float dx,float dy); +CIMGUI_API ImVec1* ImVec1_ImVec1_Nil(void); +CIMGUI_API void ImVec1_destroy(ImVec1* self); +CIMGUI_API ImVec1* ImVec1_ImVec1_Float(float _x); +CIMGUI_API ImVec2ih* ImVec2ih_ImVec2ih_Nil(void); +CIMGUI_API void ImVec2ih_destroy(ImVec2ih* self); +CIMGUI_API ImVec2ih* ImVec2ih_ImVec2ih_short(short _x,short _y); +CIMGUI_API ImVec2ih* ImVec2ih_ImVec2ih_Vec2(const ImVec2 rhs); +CIMGUI_API ImRect* ImRect_ImRect_Nil(void); +CIMGUI_API void ImRect_destroy(ImRect* self); +CIMGUI_API ImRect* ImRect_ImRect_Vec2(const ImVec2 min,const ImVec2 max); +CIMGUI_API ImRect* ImRect_ImRect_Vec4(const ImVec4 v); +CIMGUI_API ImRect* ImRect_ImRect_Float(float x1,float y1,float x2,float y2); +CIMGUI_API void ImRect_GetCenter(ImVec2 *pOut,ImRect* self); +CIMGUI_API void ImRect_GetSize(ImVec2 *pOut,ImRect* self); +CIMGUI_API float ImRect_GetWidth(ImRect* self); +CIMGUI_API float ImRect_GetHeight(ImRect* self); +CIMGUI_API float ImRect_GetArea(ImRect* self); +CIMGUI_API void ImRect_GetTL(ImVec2 *pOut,ImRect* self); +CIMGUI_API void ImRect_GetTR(ImVec2 *pOut,ImRect* self); +CIMGUI_API void ImRect_GetBL(ImVec2 *pOut,ImRect* self); +CIMGUI_API void ImRect_GetBR(ImVec2 *pOut,ImRect* self); +CIMGUI_API bool ImRect_Contains_Vec2(ImRect* self,const ImVec2 p); +CIMGUI_API bool ImRect_Contains_Rect(ImRect* self,const ImRect r); +CIMGUI_API bool ImRect_Overlaps(ImRect* self,const ImRect r); +CIMGUI_API void ImRect_Add_Vec2(ImRect* self,const ImVec2 p); +CIMGUI_API void ImRect_Add_Rect(ImRect* self,const ImRect r); +CIMGUI_API void ImRect_Expand_Float(ImRect* self,const float amount); +CIMGUI_API void ImRect_Expand_Vec2(ImRect* self,const ImVec2 amount); +CIMGUI_API void ImRect_Translate(ImRect* self,const ImVec2 d); +CIMGUI_API void ImRect_TranslateX(ImRect* self,float dx); +CIMGUI_API void ImRect_TranslateY(ImRect* self,float dy); +CIMGUI_API void ImRect_ClipWith(ImRect* self,const ImRect r); +CIMGUI_API void ImRect_ClipWithFull(ImRect* self,const ImRect r); +CIMGUI_API void ImRect_Floor(ImRect* self); +CIMGUI_API bool ImRect_IsInverted(ImRect* self); +CIMGUI_API void ImRect_ToVec4(ImVec4 *pOut,ImRect* self); +CIMGUI_API bool igImBitArrayTestBit(const ImU32* arr,int n); +CIMGUI_API void igImBitArrayClearBit(ImU32* arr,int n); +CIMGUI_API void igImBitArraySetBit(ImU32* arr,int n); +CIMGUI_API void igImBitArraySetBitRange(ImU32* arr,int n,int n2); +CIMGUI_API void ImBitVector_Create(ImBitVector* self,int sz); +CIMGUI_API void ImBitVector_Clear(ImBitVector* self); +CIMGUI_API bool ImBitVector_TestBit(ImBitVector* self,int n); +CIMGUI_API void ImBitVector_SetBit(ImBitVector* self,int n); +CIMGUI_API void ImBitVector_ClearBit(ImBitVector* self,int n); +CIMGUI_API ImDrawListSharedData* ImDrawListSharedData_ImDrawListSharedData(void); +CIMGUI_API void ImDrawListSharedData_destroy(ImDrawListSharedData* self); +CIMGUI_API void ImDrawListSharedData_SetCircleTessellationMaxError(ImDrawListSharedData* self,float max_error); +CIMGUI_API void ImDrawDataBuilder_Clear(ImDrawDataBuilder* self); +CIMGUI_API void ImDrawDataBuilder_ClearFreeMemory(ImDrawDataBuilder* self); +CIMGUI_API int ImDrawDataBuilder_GetDrawListCount(ImDrawDataBuilder* self); +CIMGUI_API void ImDrawDataBuilder_FlattenIntoSingleLayer(ImDrawDataBuilder* self); +CIMGUI_API ImGuiStyleMod* ImGuiStyleMod_ImGuiStyleMod_Int(ImGuiStyleVar idx,int v); +CIMGUI_API void ImGuiStyleMod_destroy(ImGuiStyleMod* self); +CIMGUI_API ImGuiStyleMod* ImGuiStyleMod_ImGuiStyleMod_Float(ImGuiStyleVar idx,float v); +CIMGUI_API ImGuiStyleMod* ImGuiStyleMod_ImGuiStyleMod_Vec2(ImGuiStyleVar idx,ImVec2 v); +CIMGUI_API ImGuiMenuColumns* ImGuiMenuColumns_ImGuiMenuColumns(void); +CIMGUI_API void ImGuiMenuColumns_destroy(ImGuiMenuColumns* self); +CIMGUI_API void ImGuiMenuColumns_Update(ImGuiMenuColumns* self,int count,float spacing,bool clear); +CIMGUI_API float ImGuiMenuColumns_DeclColumns(ImGuiMenuColumns* self,float w0,float w1,float w2); +CIMGUI_API float ImGuiMenuColumns_CalcExtraSpace(ImGuiMenuColumns* self,float avail_w); +CIMGUI_API ImGuiInputTextState* ImGuiInputTextState_ImGuiInputTextState(void); +CIMGUI_API void ImGuiInputTextState_destroy(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_ClearText(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_ClearFreeMemory(ImGuiInputTextState* self); +CIMGUI_API int ImGuiInputTextState_GetUndoAvailCount(ImGuiInputTextState* self); +CIMGUI_API int ImGuiInputTextState_GetRedoAvailCount(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_OnKeyPressed(ImGuiInputTextState* self,int key); +CIMGUI_API void ImGuiInputTextState_CursorAnimReset(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_CursorClamp(ImGuiInputTextState* self); +CIMGUI_API bool ImGuiInputTextState_HasSelection(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_ClearSelection(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_SelectAll(ImGuiInputTextState* self); +CIMGUI_API ImGuiPopupData* ImGuiPopupData_ImGuiPopupData(void); +CIMGUI_API void ImGuiPopupData_destroy(ImGuiPopupData* self); +CIMGUI_API ImGuiNavMoveResult* ImGuiNavMoveResult_ImGuiNavMoveResult(void); +CIMGUI_API void ImGuiNavMoveResult_destroy(ImGuiNavMoveResult* self); +CIMGUI_API void ImGuiNavMoveResult_Clear(ImGuiNavMoveResult* self); +CIMGUI_API ImGuiNextWindowData* ImGuiNextWindowData_ImGuiNextWindowData(void); +CIMGUI_API void ImGuiNextWindowData_destroy(ImGuiNextWindowData* self); +CIMGUI_API void ImGuiNextWindowData_ClearFlags(ImGuiNextWindowData* self); +CIMGUI_API ImGuiNextItemData* ImGuiNextItemData_ImGuiNextItemData(void); +CIMGUI_API void ImGuiNextItemData_destroy(ImGuiNextItemData* self); +CIMGUI_API void ImGuiNextItemData_ClearFlags(ImGuiNextItemData* self); +CIMGUI_API ImGuiPtrOrIndex* ImGuiPtrOrIndex_ImGuiPtrOrIndex_Ptr(void* ptr); +CIMGUI_API void ImGuiPtrOrIndex_destroy(ImGuiPtrOrIndex* self); +CIMGUI_API ImGuiPtrOrIndex* ImGuiPtrOrIndex_ImGuiPtrOrIndex_Int(int index); +CIMGUI_API ImGuiOldColumnData* ImGuiOldColumnData_ImGuiOldColumnData(void); +CIMGUI_API void ImGuiOldColumnData_destroy(ImGuiOldColumnData* self); +CIMGUI_API ImGuiOldColumns* ImGuiOldColumns_ImGuiOldColumns(void); +CIMGUI_API void ImGuiOldColumns_destroy(ImGuiOldColumns* self); +CIMGUI_API ImGuiViewportP* ImGuiViewportP_ImGuiViewportP(void); +CIMGUI_API void ImGuiViewportP_destroy(ImGuiViewportP* self); +CIMGUI_API void ImGuiViewportP_GetMainRect(ImRect *pOut,ImGuiViewportP* self); +CIMGUI_API void ImGuiViewportP_GetWorkRect(ImRect *pOut,ImGuiViewportP* self); +CIMGUI_API void ImGuiViewportP_UpdateWorkRect(ImGuiViewportP* self); +CIMGUI_API ImGuiWindowSettings* ImGuiWindowSettings_ImGuiWindowSettings(void); +CIMGUI_API void ImGuiWindowSettings_destroy(ImGuiWindowSettings* self); +CIMGUI_API char* ImGuiWindowSettings_GetName(ImGuiWindowSettings* self); +CIMGUI_API ImGuiSettingsHandler* ImGuiSettingsHandler_ImGuiSettingsHandler(void); +CIMGUI_API void ImGuiSettingsHandler_destroy(ImGuiSettingsHandler* self); +CIMGUI_API ImGuiMetricsConfig* ImGuiMetricsConfig_ImGuiMetricsConfig(void); +CIMGUI_API void ImGuiMetricsConfig_destroy(ImGuiMetricsConfig* self); +CIMGUI_API ImGuiStackSizes* ImGuiStackSizes_ImGuiStackSizes(void); +CIMGUI_API void ImGuiStackSizes_destroy(ImGuiStackSizes* self); +CIMGUI_API void ImGuiStackSizes_SetToCurrentState(ImGuiStackSizes* self); +CIMGUI_API void ImGuiStackSizes_CompareWithCurrentState(ImGuiStackSizes* self); +CIMGUI_API ImGuiContextHook* ImGuiContextHook_ImGuiContextHook(void); +CIMGUI_API void ImGuiContextHook_destroy(ImGuiContextHook* self); +CIMGUI_API ImGuiContext* ImGuiContext_ImGuiContext(ImFontAtlas* shared_font_atlas); +CIMGUI_API void ImGuiContext_destroy(ImGuiContext* self); +CIMGUI_API ImGuiWindow* ImGuiWindow_ImGuiWindow(ImGuiContext* context,const char* name); +CIMGUI_API void ImGuiWindow_destroy(ImGuiWindow* self); +CIMGUI_API ImGuiID ImGuiWindow_GetID_Str(ImGuiWindow* self,const char* str,const char* str_end); +CIMGUI_API ImGuiID ImGuiWindow_GetID_Ptr(ImGuiWindow* self,const void* ptr); +CIMGUI_API ImGuiID ImGuiWindow_GetID_Int(ImGuiWindow* self,int n); +CIMGUI_API ImGuiID ImGuiWindow_GetIDNoKeepAlive_Str(ImGuiWindow* self,const char* str,const char* str_end); +CIMGUI_API ImGuiID ImGuiWindow_GetIDNoKeepAlive_Ptr(ImGuiWindow* self,const void* ptr); +CIMGUI_API ImGuiID ImGuiWindow_GetIDNoKeepAlive_Int(ImGuiWindow* self,int n); +CIMGUI_API ImGuiID ImGuiWindow_GetIDFromRectangle(ImGuiWindow* self,const ImRect r_abs); +CIMGUI_API void ImGuiWindow_Rect(ImRect *pOut,ImGuiWindow* self); +CIMGUI_API float ImGuiWindow_CalcFontSize(ImGuiWindow* self); +CIMGUI_API float ImGuiWindow_TitleBarHeight(ImGuiWindow* self); +CIMGUI_API void ImGuiWindow_TitleBarRect(ImRect *pOut,ImGuiWindow* self); +CIMGUI_API float ImGuiWindow_MenuBarHeight(ImGuiWindow* self); +CIMGUI_API void ImGuiWindow_MenuBarRect(ImRect *pOut,ImGuiWindow* self); +CIMGUI_API ImGuiLastItemDataBackup* ImGuiLastItemDataBackup_ImGuiLastItemDataBackup(void); +CIMGUI_API void ImGuiLastItemDataBackup_destroy(ImGuiLastItemDataBackup* self); +CIMGUI_API void ImGuiLastItemDataBackup_Backup(ImGuiLastItemDataBackup* self); +CIMGUI_API void ImGuiLastItemDataBackup_Restore(ImGuiLastItemDataBackup* self); +CIMGUI_API ImGuiTabItem* ImGuiTabItem_ImGuiTabItem(void); +CIMGUI_API void ImGuiTabItem_destroy(ImGuiTabItem* self); +CIMGUI_API ImGuiTabBar* ImGuiTabBar_ImGuiTabBar(void); +CIMGUI_API void ImGuiTabBar_destroy(ImGuiTabBar* self); +CIMGUI_API int ImGuiTabBar_GetTabOrder(ImGuiTabBar* self,const ImGuiTabItem* tab); +CIMGUI_API const char* ImGuiTabBar_GetTabName(ImGuiTabBar* self,const ImGuiTabItem* tab); +CIMGUI_API ImGuiTableColumn* ImGuiTableColumn_ImGuiTableColumn(void); +CIMGUI_API void ImGuiTableColumn_destroy(ImGuiTableColumn* self); +CIMGUI_API ImGuiTable* ImGuiTable_ImGuiTable(void); +CIMGUI_API void ImGuiTable_destroy(ImGuiTable* self); +CIMGUI_API ImGuiTableColumnSettings* ImGuiTableColumnSettings_ImGuiTableColumnSettings(void); +CIMGUI_API void ImGuiTableColumnSettings_destroy(ImGuiTableColumnSettings* self); +CIMGUI_API ImGuiTableSettings* ImGuiTableSettings_ImGuiTableSettings(void); +CIMGUI_API void ImGuiTableSettings_destroy(ImGuiTableSettings* self); +CIMGUI_API ImGuiTableColumnSettings* ImGuiTableSettings_GetColumnSettings(ImGuiTableSettings* self); +CIMGUI_API ImGuiWindow* igGetCurrentWindowRead(void); +CIMGUI_API ImGuiWindow* igGetCurrentWindow(void); +CIMGUI_API ImGuiWindow* igFindWindowByID(ImGuiID id); +CIMGUI_API ImGuiWindow* igFindWindowByName(const char* name); +CIMGUI_API void igUpdateWindowParentAndRootLinks(ImGuiWindow* window,ImGuiWindowFlags flags,ImGuiWindow* parent_window); +CIMGUI_API void igCalcWindowNextAutoFitSize(ImVec2 *pOut,ImGuiWindow* window); +CIMGUI_API bool igIsWindowChildOf(ImGuiWindow* window,ImGuiWindow* potential_parent); +CIMGUI_API bool igIsWindowAbove(ImGuiWindow* potential_above,ImGuiWindow* potential_below); +CIMGUI_API bool igIsWindowNavFocusable(ImGuiWindow* window); +CIMGUI_API void igGetWindowAllowedExtentRect(ImRect *pOut,ImGuiWindow* window); +CIMGUI_API void igSetWindowPos_WindowPtr(ImGuiWindow* window,const ImVec2 pos,ImGuiCond cond); +CIMGUI_API void igSetWindowSize_WindowPtr(ImGuiWindow* window,const ImVec2 size,ImGuiCond cond); +CIMGUI_API void igSetWindowCollapsed_WindowPtr(ImGuiWindow* window,bool collapsed,ImGuiCond cond); +CIMGUI_API void igSetWindowHitTestHole(ImGuiWindow* window,const ImVec2 pos,const ImVec2 size); +CIMGUI_API void igFocusWindow(ImGuiWindow* window); +CIMGUI_API void igFocusTopMostWindowUnderOne(ImGuiWindow* under_this_window,ImGuiWindow* ignore_window); +CIMGUI_API void igBringWindowToFocusFront(ImGuiWindow* window); +CIMGUI_API void igBringWindowToDisplayFront(ImGuiWindow* window); +CIMGUI_API void igBringWindowToDisplayBack(ImGuiWindow* window); +CIMGUI_API void igSetCurrentFont(ImFont* font); +CIMGUI_API ImFont* igGetDefaultFont(void); +CIMGUI_API ImDrawList* igGetForegroundDrawList_WindowPtr(ImGuiWindow* window); +CIMGUI_API ImDrawList* igGetBackgroundDrawList_ViewportPtr(ImGuiViewport* viewport); +CIMGUI_API ImDrawList* igGetForegroundDrawList_ViewportPtr(ImGuiViewport* viewport); +CIMGUI_API void igInitialize(ImGuiContext* context); +CIMGUI_API void igShutdown(ImGuiContext* context); +CIMGUI_API void igUpdateHoveredWindowAndCaptureFlags(void); +CIMGUI_API void igStartMouseMovingWindow(ImGuiWindow* window); +CIMGUI_API void igUpdateMouseMovingWindowNewFrame(void); +CIMGUI_API void igUpdateMouseMovingWindowEndFrame(void); +CIMGUI_API ImGuiID igAddContextHook(ImGuiContext* context,const ImGuiContextHook* hook); +CIMGUI_API void igRemoveContextHook(ImGuiContext* context,ImGuiID hook_to_remove); +CIMGUI_API void igCallContextHooks(ImGuiContext* context,ImGuiContextHookType type); +CIMGUI_API void igMarkIniSettingsDirty_Nil(void); +CIMGUI_API void igMarkIniSettingsDirty_WindowPtr(ImGuiWindow* window); +CIMGUI_API void igClearIniSettings(void); +CIMGUI_API ImGuiWindowSettings* igCreateNewWindowSettings(const char* name); +CIMGUI_API ImGuiWindowSettings* igFindWindowSettings(ImGuiID id); +CIMGUI_API ImGuiWindowSettings* igFindOrCreateWindowSettings(const char* name); +CIMGUI_API ImGuiSettingsHandler* igFindSettingsHandler(const char* type_name); +CIMGUI_API void igSetNextWindowScroll(const ImVec2 scroll); +CIMGUI_API void igSetScrollX_WindowPtr(ImGuiWindow* window,float scroll_x); +CIMGUI_API void igSetScrollY_WindowPtr(ImGuiWindow* window,float scroll_y); +CIMGUI_API void igSetScrollFromPosX_WindowPtr(ImGuiWindow* window,float local_x,float center_x_ratio); +CIMGUI_API void igSetScrollFromPosY_WindowPtr(ImGuiWindow* window,float local_y,float center_y_ratio); +CIMGUI_API void igScrollToBringRectIntoView(ImVec2 *pOut,ImGuiWindow* window,const ImRect item_rect); +CIMGUI_API ImGuiID igGetItemID(void); +CIMGUI_API ImGuiItemStatusFlags igGetItemStatusFlags(void); +CIMGUI_API ImGuiID igGetActiveID(void); +CIMGUI_API ImGuiID igGetFocusID(void); +CIMGUI_API ImGuiItemFlags igGetItemsFlags(void); +CIMGUI_API void igSetActiveID(ImGuiID id,ImGuiWindow* window); +CIMGUI_API void igSetFocusID(ImGuiID id,ImGuiWindow* window); +CIMGUI_API void igClearActiveID(void); +CIMGUI_API ImGuiID igGetHoveredID(void); +CIMGUI_API void igSetHoveredID(ImGuiID id); +CIMGUI_API void igKeepAliveID(ImGuiID id); +CIMGUI_API void igMarkItemEdited(ImGuiID id); +CIMGUI_API void igPushOverrideID(ImGuiID id); +CIMGUI_API ImGuiID igGetIDWithSeed(const char* str_id_begin,const char* str_id_end,ImGuiID seed); +CIMGUI_API void igItemSize_Vec2(const ImVec2 size,float text_baseline_y); +CIMGUI_API void igItemSize_Rect(const ImRect bb,float text_baseline_y); +CIMGUI_API bool igItemAdd(const ImRect bb,ImGuiID id,const ImRect* nav_bb); +CIMGUI_API bool igItemHoverable(const ImRect bb,ImGuiID id); +CIMGUI_API bool igIsClippedEx(const ImRect bb,ImGuiID id,bool clip_even_when_logged); +CIMGUI_API void igSetLastItemData(ImGuiWindow* window,ImGuiID item_id,ImGuiItemStatusFlags status_flags,const ImRect item_rect); +CIMGUI_API bool igFocusableItemRegister(ImGuiWindow* window,ImGuiID id); +CIMGUI_API void igFocusableItemUnregister(ImGuiWindow* window); +CIMGUI_API void igCalcItemSize(ImVec2 *pOut,ImVec2 size,float default_w,float default_h); +CIMGUI_API float igCalcWrapWidthForPos(const ImVec2 pos,float wrap_pos_x); +CIMGUI_API void igPushMultiItemsWidths(int components,float width_full); +CIMGUI_API void igPushItemFlag(ImGuiItemFlags option,bool enabled); +CIMGUI_API void igPopItemFlag(void); +CIMGUI_API bool igIsItemToggledSelection(void); +CIMGUI_API void igGetContentRegionMaxAbs(ImVec2 *pOut); +CIMGUI_API void igShrinkWidths(ImGuiShrinkWidthItem* items,int count,float width_excess); +CIMGUI_API void igLogBegin(ImGuiLogType type,int auto_open_depth); +CIMGUI_API void igLogToBuffer(int auto_open_depth); +CIMGUI_API void igLogRenderedText(const ImVec2* ref_pos,const char* text,const char* text_end); +CIMGUI_API void igLogSetNextTextDecoration(const char* prefix,const char* suffix); +CIMGUI_API bool igBeginChildEx(const char* name,ImGuiID id,const ImVec2 size_arg,bool border,ImGuiWindowFlags flags); +CIMGUI_API void igOpenPopupEx(ImGuiID id,ImGuiPopupFlags popup_flags); +CIMGUI_API void igClosePopupToLevel(int remaining,bool restore_focus_to_window_under_popup); +CIMGUI_API void igClosePopupsOverWindow(ImGuiWindow* ref_window,bool restore_focus_to_window_under_popup); +CIMGUI_API bool igIsPopupOpen_ID(ImGuiID id,ImGuiPopupFlags popup_flags); +CIMGUI_API bool igBeginPopupEx(ImGuiID id,ImGuiWindowFlags extra_flags); +CIMGUI_API void igBeginTooltipEx(ImGuiWindowFlags extra_flags,ImGuiTooltipFlags tooltip_flags); +CIMGUI_API ImGuiWindow* igGetTopMostPopupModal(void); +CIMGUI_API void igFindBestWindowPosForPopup(ImVec2 *pOut,ImGuiWindow* window); +CIMGUI_API void igFindBestWindowPosForPopupEx(ImVec2 *pOut,const ImVec2 ref_pos,const ImVec2 size,ImGuiDir* last_dir,const ImRect r_outer,const ImRect r_avoid,ImGuiPopupPositionPolicy policy); +CIMGUI_API void igNavInitWindow(ImGuiWindow* window,bool force_reinit); +CIMGUI_API bool igNavMoveRequestButNoResultYet(void); +CIMGUI_API void igNavMoveRequestCancel(void); +CIMGUI_API void igNavMoveRequestForward(ImGuiDir move_dir,ImGuiDir clip_dir,const ImRect bb_rel,ImGuiNavMoveFlags move_flags); +CIMGUI_API void igNavMoveRequestTryWrapping(ImGuiWindow* window,ImGuiNavMoveFlags move_flags); +CIMGUI_API float igGetNavInputAmount(ImGuiNavInput n,ImGuiInputReadMode mode); +CIMGUI_API void igGetNavInputAmount2d(ImVec2 *pOut,ImGuiNavDirSourceFlags dir_sources,ImGuiInputReadMode mode,float slow_factor,float fast_factor); +CIMGUI_API int igCalcTypematicRepeatAmount(float t0,float t1,float repeat_delay,float repeat_rate); +CIMGUI_API void igActivateItem(ImGuiID id); +CIMGUI_API void igSetNavID(ImGuiID id,int nav_layer,ImGuiID focus_scope_id,const ImRect rect_rel); +CIMGUI_API void igPushFocusScope(ImGuiID id); +CIMGUI_API void igPopFocusScope(void); +CIMGUI_API ImGuiID igGetFocusedFocusScope(void); +CIMGUI_API ImGuiID igGetFocusScope(void); +CIMGUI_API void igSetItemUsingMouseWheel(void); +CIMGUI_API bool igIsActiveIdUsingNavDir(ImGuiDir dir); +CIMGUI_API bool igIsActiveIdUsingNavInput(ImGuiNavInput input); +CIMGUI_API bool igIsActiveIdUsingKey(ImGuiKey key); +CIMGUI_API bool igIsMouseDragPastThreshold(ImGuiMouseButton button,float lock_threshold); +CIMGUI_API bool igIsKeyPressedMap(ImGuiKey key,bool repeat); +CIMGUI_API bool igIsNavInputDown(ImGuiNavInput n); +CIMGUI_API bool igIsNavInputTest(ImGuiNavInput n,ImGuiInputReadMode rm); +CIMGUI_API ImGuiKeyModFlags igGetMergedKeyModFlags(void); +CIMGUI_API bool igBeginDragDropTargetCustom(const ImRect bb,ImGuiID id); +CIMGUI_API void igClearDragDrop(void); +CIMGUI_API bool igIsDragDropPayloadBeingAccepted(void); +CIMGUI_API void igSetWindowClipRectBeforeSetChannel(ImGuiWindow* window,const ImRect clip_rect); +CIMGUI_API void igBeginColumns(const char* str_id,int count,ImGuiOldColumnFlags flags); +CIMGUI_API void igEndColumns(void); +CIMGUI_API void igPushColumnClipRect(int column_index); +CIMGUI_API void igPushColumnsBackground(void); +CIMGUI_API void igPopColumnsBackground(void); +CIMGUI_API ImGuiID igGetColumnsID(const char* str_id,int count); +CIMGUI_API ImGuiOldColumns* igFindOrCreateColumns(ImGuiWindow* window,ImGuiID id); +CIMGUI_API float igGetColumnOffsetFromNorm(const ImGuiOldColumns* columns,float offset_norm); +CIMGUI_API float igGetColumnNormFromOffset(const ImGuiOldColumns* columns,float offset); +CIMGUI_API void igTableOpenContextMenu(int column_n); +CIMGUI_API void igTableSetColumnEnabled(int column_n,bool enabled); +CIMGUI_API void igTableSetColumnWidth(int column_n,float width); +CIMGUI_API void igTableSetColumnSortDirection(int column_n,ImGuiSortDirection sort_direction,bool append_to_sort_specs); +CIMGUI_API int igTableGetHoveredColumn(void); +CIMGUI_API float igTableGetHeaderRowHeight(void); +CIMGUI_API void igTablePushBackgroundChannel(void); +CIMGUI_API void igTablePopBackgroundChannel(void); +CIMGUI_API ImGuiTable* igGetCurrentTable(void); +CIMGUI_API ImGuiTable* igTableFindByID(ImGuiID id); +CIMGUI_API bool igBeginTableEx(const char* name,ImGuiID id,int columns_count,ImGuiTableFlags flags,const ImVec2 outer_size,float inner_width); +CIMGUI_API void igTableBeginInitMemory(ImGuiTable* table,int columns_count); +CIMGUI_API void igTableBeginApplyRequests(ImGuiTable* table); +CIMGUI_API void igTableSetupDrawChannels(ImGuiTable* table); +CIMGUI_API void igTableUpdateLayout(ImGuiTable* table); +CIMGUI_API void igTableUpdateBorders(ImGuiTable* table); +CIMGUI_API void igTableUpdateColumnsWeightFromWidth(ImGuiTable* table); +CIMGUI_API void igTableDrawBorders(ImGuiTable* table); +CIMGUI_API void igTableDrawContextMenu(ImGuiTable* table); +CIMGUI_API void igTableMergeDrawChannels(ImGuiTable* table); +CIMGUI_API void igTableSortSpecsSanitize(ImGuiTable* table); +CIMGUI_API void igTableSortSpecsBuild(ImGuiTable* table); +CIMGUI_API ImGuiSortDirection igTableGetColumnNextSortDirection(ImGuiTableColumn* column); +CIMGUI_API void igTableFixColumnSortDirection(ImGuiTable* table,ImGuiTableColumn* column); +CIMGUI_API float igTableGetColumnWidthAuto(ImGuiTable* table,ImGuiTableColumn* column); +CIMGUI_API void igTableBeginRow(ImGuiTable* table); +CIMGUI_API void igTableEndRow(ImGuiTable* table); +CIMGUI_API void igTableBeginCell(ImGuiTable* table,int column_n); +CIMGUI_API void igTableEndCell(ImGuiTable* table); +CIMGUI_API void igTableGetCellBgRect(ImRect *pOut,const ImGuiTable* table,int column_n); +CIMGUI_API const char* igTableGetColumnName_TablePtr(const ImGuiTable* table,int column_n); +CIMGUI_API ImGuiID igTableGetColumnResizeID(const ImGuiTable* table,int column_n,int instance_no); +CIMGUI_API float igTableGetMaxColumnWidth(const ImGuiTable* table,int column_n); +CIMGUI_API void igTableSetColumnWidthAutoSingle(ImGuiTable* table,int column_n); +CIMGUI_API void igTableSetColumnWidthAutoAll(ImGuiTable* table); +CIMGUI_API void igTableRemove(ImGuiTable* table); +CIMGUI_API void igTableGcCompactTransientBuffers(ImGuiTable* table); +CIMGUI_API void igTableGcCompactSettings(void); +CIMGUI_API void igTableLoadSettings(ImGuiTable* table); +CIMGUI_API void igTableSaveSettings(ImGuiTable* table); +CIMGUI_API void igTableResetSettings(ImGuiTable* table); +CIMGUI_API ImGuiTableSettings* igTableGetBoundSettings(ImGuiTable* table); +CIMGUI_API void igTableSettingsInstallHandler(ImGuiContext* context); +CIMGUI_API ImGuiTableSettings* igTableSettingsCreate(ImGuiID id,int columns_count); +CIMGUI_API ImGuiTableSettings* igTableSettingsFindByID(ImGuiID id); +CIMGUI_API bool igBeginTabBarEx(ImGuiTabBar* tab_bar,const ImRect bb,ImGuiTabBarFlags flags); +CIMGUI_API ImGuiTabItem* igTabBarFindTabByID(ImGuiTabBar* tab_bar,ImGuiID tab_id); +CIMGUI_API void igTabBarRemoveTab(ImGuiTabBar* tab_bar,ImGuiID tab_id); +CIMGUI_API void igTabBarCloseTab(ImGuiTabBar* tab_bar,ImGuiTabItem* tab); +CIMGUI_API void igTabBarQueueReorder(ImGuiTabBar* tab_bar,const ImGuiTabItem* tab,int dir); +CIMGUI_API bool igTabBarProcessReorder(ImGuiTabBar* tab_bar); +CIMGUI_API bool igTabItemEx(ImGuiTabBar* tab_bar,const char* label,bool* p_open,ImGuiTabItemFlags flags); +CIMGUI_API void igTabItemCalcSize(ImVec2 *pOut,const char* label,bool has_close_button); +CIMGUI_API void igTabItemBackground(ImDrawList* draw_list,const ImRect bb,ImGuiTabItemFlags flags,ImU32 col); +CIMGUI_API void igTabItemLabelAndCloseButton(ImDrawList* draw_list,const ImRect bb,ImGuiTabItemFlags flags,ImVec2 frame_padding,const char* label,ImGuiID tab_id,ImGuiID close_button_id,bool is_contents_visible,bool* out_just_closed,bool* out_text_clipped); +CIMGUI_API void igRenderText(ImVec2 pos,const char* text,const char* text_end,bool hide_text_after_hash); +CIMGUI_API void igRenderTextWrapped(ImVec2 pos,const char* text,const char* text_end,float wrap_width); +CIMGUI_API void igRenderTextClipped(const ImVec2 pos_min,const ImVec2 pos_max,const char* text,const char* text_end,const ImVec2* text_size_if_known,const ImVec2 align,const ImRect* clip_rect); +CIMGUI_API void igRenderTextClippedEx(ImDrawList* draw_list,const ImVec2 pos_min,const ImVec2 pos_max,const char* text,const char* text_end,const ImVec2* text_size_if_known,const ImVec2 align,const ImRect* clip_rect); +CIMGUI_API void igRenderTextEllipsis(ImDrawList* draw_list,const ImVec2 pos_min,const ImVec2 pos_max,float clip_max_x,float ellipsis_max_x,const char* text,const char* text_end,const ImVec2* text_size_if_known); +CIMGUI_API void igRenderFrame(ImVec2 p_min,ImVec2 p_max,ImU32 fill_col,bool border,float rounding); +CIMGUI_API void igRenderFrameBorder(ImVec2 p_min,ImVec2 p_max,float rounding); +CIMGUI_API void igRenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list,ImVec2 p_min,ImVec2 p_max,ImU32 fill_col,float grid_step,ImVec2 grid_off,float rounding,ImDrawFlags flags); +CIMGUI_API void igRenderNavHighlight(const ImRect bb,ImGuiID id,ImGuiNavHighlightFlags flags); +CIMGUI_API const char* igFindRenderedTextEnd(const char* text,const char* text_end); +CIMGUI_API void igRenderArrow(ImDrawList* draw_list,ImVec2 pos,ImU32 col,ImGuiDir dir,float scale); +CIMGUI_API void igRenderBullet(ImDrawList* draw_list,ImVec2 pos,ImU32 col); +CIMGUI_API void igRenderCheckMark(ImDrawList* draw_list,ImVec2 pos,ImU32 col,float sz); +CIMGUI_API void igRenderMouseCursor(ImDrawList* draw_list,ImVec2 pos,float scale,ImGuiMouseCursor mouse_cursor,ImU32 col_fill,ImU32 col_border,ImU32 col_shadow); +CIMGUI_API void igRenderArrowPointingAt(ImDrawList* draw_list,ImVec2 pos,ImVec2 half_sz,ImGuiDir direction,ImU32 col); +CIMGUI_API void igRenderRectFilledRangeH(ImDrawList* draw_list,const ImRect rect,ImU32 col,float x_start_norm,float x_end_norm,float rounding); +CIMGUI_API void igRenderRectFilledWithHole(ImDrawList* draw_list,ImRect outer,ImRect inner,ImU32 col,float rounding); +CIMGUI_API void igTextEx(const char* text,const char* text_end,ImGuiTextFlags flags); +CIMGUI_API bool igButtonEx(const char* label,const ImVec2 size_arg,ImGuiButtonFlags flags); +CIMGUI_API bool igCloseButton(ImGuiID id,const ImVec2 pos); +CIMGUI_API bool igCollapseButton(ImGuiID id,const ImVec2 pos); +CIMGUI_API bool igArrowButtonEx(const char* str_id,ImGuiDir dir,ImVec2 size_arg,ImGuiButtonFlags flags); +CIMGUI_API void igScrollbar(ImGuiAxis axis); +CIMGUI_API bool igScrollbarEx(const ImRect bb,ImGuiID id,ImGuiAxis axis,float* p_scroll_v,float avail_v,float contents_v,ImDrawFlags flags); +CIMGUI_API bool igImageButtonEx(ImGuiID id,ImTextureID texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,const ImVec2 padding,const ImVec4 bg_col,const ImVec4 tint_col); +CIMGUI_API void igGetWindowScrollbarRect(ImRect *pOut,ImGuiWindow* window,ImGuiAxis axis); +CIMGUI_API ImGuiID igGetWindowScrollbarID(ImGuiWindow* window,ImGuiAxis axis); +CIMGUI_API ImGuiID igGetWindowResizeID(ImGuiWindow* window,int n); +CIMGUI_API void igSeparatorEx(ImGuiSeparatorFlags flags); +CIMGUI_API bool igCheckboxFlags_S64Ptr(const char* label,ImS64* flags,ImS64 flags_value); +CIMGUI_API bool igCheckboxFlags_U64Ptr(const char* label,ImU64* flags,ImU64 flags_value); +CIMGUI_API bool igButtonBehavior(const ImRect bb,ImGuiID id,bool* out_hovered,bool* out_held,ImGuiButtonFlags flags); +CIMGUI_API bool igDragBehavior(ImGuiID id,ImGuiDataType data_type,void* p_v,float v_speed,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderBehavior(const ImRect bb,ImGuiID id,ImGuiDataType data_type,void* p_v,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags,ImRect* out_grab_bb); +CIMGUI_API bool igSplitterBehavior(const ImRect bb,ImGuiID id,ImGuiAxis axis,float* size1,float* size2,float min_size1,float min_size2,float hover_extend,float hover_visibility_delay); +CIMGUI_API bool igTreeNodeBehavior(ImGuiID id,ImGuiTreeNodeFlags flags,const char* label,const char* label_end); +CIMGUI_API bool igTreeNodeBehaviorIsOpen(ImGuiID id,ImGuiTreeNodeFlags flags); +CIMGUI_API void igTreePushOverrideID(ImGuiID id); +CIMGUI_API const ImGuiDataTypeInfo* igDataTypeGetInfo(ImGuiDataType data_type); +CIMGUI_API int igDataTypeFormatString(char* buf,int buf_size,ImGuiDataType data_type,const void* p_data,const char* format); +CIMGUI_API void igDataTypeApplyOp(ImGuiDataType data_type,int op,void* output,const void* arg_1,const void* arg_2); +CIMGUI_API bool igDataTypeApplyOpFromText(const char* buf,const char* initial_value_buf,ImGuiDataType data_type,void* p_data,const char* format); +CIMGUI_API int igDataTypeCompare(ImGuiDataType data_type,const void* arg_1,const void* arg_2); +CIMGUI_API bool igDataTypeClamp(ImGuiDataType data_type,void* p_data,const void* p_min,const void* p_max); +CIMGUI_API bool igInputTextEx(const char* label,const char* hint,char* buf,int buf_size,const ImVec2 size_arg,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data); +CIMGUI_API bool igTempInputText(const ImRect bb,ImGuiID id,const char* label,char* buf,int buf_size,ImGuiInputTextFlags flags); +CIMGUI_API bool igTempInputScalar(const ImRect bb,ImGuiID id,const char* label,ImGuiDataType data_type,void* p_data,const char* format,const void* p_clamp_min,const void* p_clamp_max); +CIMGUI_API bool igTempInputIsActive(ImGuiID id); +CIMGUI_API ImGuiInputTextState* igGetInputTextState(ImGuiID id); +CIMGUI_API void igColorTooltip(const char* text,const float* col,ImGuiColorEditFlags flags); +CIMGUI_API void igColorEditOptionsPopup(const float* col,ImGuiColorEditFlags flags); +CIMGUI_API void igColorPickerOptionsPopup(const float* ref_col,ImGuiColorEditFlags flags); +CIMGUI_API int igPlotEx(ImGuiPlotType plot_type,const char* label,float(*values_getter)(void* data,int idx),void* data,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 frame_size); +CIMGUI_API void igShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list,int vert_start_idx,int vert_end_idx,ImVec2 gradient_p0,ImVec2 gradient_p1,ImU32 col0,ImU32 col1); +CIMGUI_API void igShadeVertsLinearUV(ImDrawList* draw_list,int vert_start_idx,int vert_end_idx,const ImVec2 a,const ImVec2 b,const ImVec2 uv_a,const ImVec2 uv_b,bool clamp); +CIMGUI_API void igGcCompactTransientMiscBuffers(void); +CIMGUI_API void igGcCompactTransientWindowBuffers(ImGuiWindow* window); +CIMGUI_API void igGcAwakeTransientWindowBuffers(ImGuiWindow* window); +CIMGUI_API void igErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback,void* user_data); +CIMGUI_API void igDebugDrawItemRect(ImU32 col); +CIMGUI_API void igDebugStartItemPicker(void); +CIMGUI_API void igDebugNodeColumns(ImGuiOldColumns* columns); +CIMGUI_API void igDebugNodeDrawList(ImGuiWindow* window,const ImDrawList* draw_list,const char* label); +CIMGUI_API void igDebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list,const ImDrawList* draw_list,const ImDrawCmd* draw_cmd,bool show_mesh,bool show_aabb); +CIMGUI_API void igDebugNodeStorage(ImGuiStorage* storage,const char* label); +CIMGUI_API void igDebugNodeTabBar(ImGuiTabBar* tab_bar,const char* label); +CIMGUI_API void igDebugNodeTable(ImGuiTable* table); +CIMGUI_API void igDebugNodeTableSettings(ImGuiTableSettings* settings); +CIMGUI_API void igDebugNodeWindow(ImGuiWindow* window,const char* label); +CIMGUI_API void igDebugNodeWindowSettings(ImGuiWindowSettings* settings); +CIMGUI_API void igDebugNodeWindowsList(ImVector_ImGuiWindowPtr* windows,const char* label); +CIMGUI_API void igDebugNodeViewport(ImGuiViewportP* viewport); +CIMGUI_API void igDebugRenderViewportThumbnail(ImDrawList* draw_list,ImGuiViewportP* viewport,const ImRect bb); +CIMGUI_API const ImFontBuilderIO* igImFontAtlasGetBuilderForStbTruetype(void); +CIMGUI_API void igImFontAtlasBuildInit(ImFontAtlas* atlas); +CIMGUI_API void igImFontAtlasBuildSetupFont(ImFontAtlas* atlas,ImFont* font,ImFontConfig* font_config,float ascent,float descent); +CIMGUI_API void igImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas,void* stbrp_context_opaque); +CIMGUI_API void igImFontAtlasBuildFinish(ImFontAtlas* atlas); +CIMGUI_API void igImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas,int x,int y,int w,int h,const char* in_str,char in_marker_char,unsigned char in_marker_pixel_value); +CIMGUI_API void igImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas,int x,int y,int w,int h,const char* in_str,char in_marker_char,unsigned int in_marker_pixel_value); +CIMGUI_API void igImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256],float in_multiply_factor); +CIMGUI_API void igImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256],unsigned char* pixels,int x,int y,int w,int h,int stride); + + +/////////////////////////hand written functions +//no LogTextV +CIMGUI_API void igLogText(CONST char *fmt, ...); +//no appendfV +CIMGUI_API void ImGuiTextBuffer_appendf(struct ImGuiTextBuffer *buffer, const char *fmt, ...); +//for getting FLT_MAX in bindings +CIMGUI_API float igGET_FLT_MAX(); +//for getting FLT_MIN in bindings +CIMGUI_API float igGET_FLT_MIN(); + + +CIMGUI_API ImVector_ImWchar* ImVector_ImWchar_create(); +CIMGUI_API void ImVector_ImWchar_destroy(ImVector_ImWchar* self); +CIMGUI_API void ImVector_ImWchar_Init(ImVector_ImWchar* p); +CIMGUI_API void ImVector_ImWchar_UnInit(ImVector_ImWchar* p); + + +#endif //CIMGUI_INCLUDED + + + + diff --git a/extern/src/cimgui_impl.h b/extern/src/cimgui_impl.h new file mode 100644 index 00000000..5fe456e2 --- /dev/null +++ b/extern/src/cimgui_impl.h @@ -0,0 +1,38 @@ +typedef struct SDL_Window SDL_Window; +typedef struct GLFWwindow GLFWwindow; + +struct GLFWwindow; + +struct SDL_Window; +typedef union SDL_Event SDL_Event;CIMGUI_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window,bool install_callbacks); +CIMGUI_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window,bool install_callbacks); +CIMGUI_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window,bool install_callbacks); +CIMGUI_API void ImGui_ImplGlfw_Shutdown(); +CIMGUI_API void ImGui_ImplGlfw_NewFrame(); +CIMGUI_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window,int button,int action,int mods); +CIMGUI_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window,double xoffset,double yoffset); +CIMGUI_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window,int key,int scancode,int action,int mods); +CIMGUI_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window,unsigned int c); +CIMGUI_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version); +CIMGUI_API void ImGui_ImplOpenGL3_Shutdown(); +CIMGUI_API void ImGui_ImplOpenGL3_NewFrame(); +CIMGUI_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); +CIMGUI_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); +CIMGUI_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); +CIMGUI_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); +CIMGUI_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); +CIMGUI_API bool ImGui_ImplOpenGL2_Init(); +CIMGUI_API void ImGui_ImplOpenGL2_Shutdown(); +CIMGUI_API void ImGui_ImplOpenGL2_NewFrame(); +CIMGUI_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data); +CIMGUI_API bool ImGui_ImplOpenGL2_CreateFontsTexture(); +CIMGUI_API void ImGui_ImplOpenGL2_DestroyFontsTexture(); +CIMGUI_API bool ImGui_ImplOpenGL2_CreateDeviceObjects(); +CIMGUI_API void ImGui_ImplOpenGL2_DestroyDeviceObjects(); +CIMGUI_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window,void* sdl_gl_context); +CIMGUI_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); +CIMGUI_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window); +CIMGUI_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window); +CIMGUI_API void ImGui_ImplSDL2_Shutdown(); +CIMGUI_API void ImGui_ImplSDL2_NewFrame(SDL_Window* window); +CIMGUI_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); diff --git a/res/MikuShoot.ico b/res/MikuShoot.ico new file mode 100644 index 0000000000000000000000000000000000000000..2a97f52a6796ee27f9d3866689a3cded88c67af2 GIT binary patch literal 120193 zcmeFZbyyYM_cy!wfF3qS!>TI01?mtFE2e(lENG@z&ik- zr~g|QAp+X#u{G0)qdiP63d`M8N;8dmRFh=R^!3L1N;^z`o|tG+!h4j3nT&&k-u`UqW}YWh$ipf`fbFnbR7|}vHh*%DFMd1h=7^- zZ@q;Kz~vdyKkf5^7vdZH2x1RuA29)%2ow56pg5#&{}N*MzbFn7BGtIKzXh^Ib`g$) zuC6Xbuz&D_{e8k7!pI-t5VApI+|dRp7(5=2!LY_9dZIk_Jq-v|JU$2uXcQW4pzm@} z#pAJ%=!temdt#9~fm86I2;LnLr(nV{$PsL!JIXy2(Z&>nV+xSNf$k_zPd0oCD^kZ4 z;!`X<(FPt^JPuP(5FU=;SWswvX9QP(=!b`4@s^&RC=aC0dLUQCV?0Aqgx0MP{qQhF zd??xzg+dw%k_!(f;0bbfLd!uxm~d%4B6ml5$Po^Nm@y#RP&C>zlpKR}CFc>m4I?UNQFeb&_9fi^)H`7PCV90dzv2)0PBzusOp%AY~Ee)`9$Y^26 zF_tKln*k=!U~V?h6OHx=L)1~GVSt*O3uQr}oI_ElSpzH3M`dM&nj)$Q&w60UVz6^_ z7Aa_ytEDFzBN&E4d12=;kb*+#qtR$hZ4_#5cGe3hLQ#lKlpwN2Ap;MPf=23SJrqJ# z7%Sv-rw{2*S&>-?6a+a!DD06V$m|EgRFe9Kk>dXxbs?sw5ne)g2jM-03Gdr1yACI5s8J z(<-H)0E0|CYzn3z9E+STJTkSAiGo57u;S649$^?{qM{8@+EyrJLXbO$p~8+~zImb# zd7|_U5>Y5ibXXwvtAVE_$^$w1Dabf`pzyPR%q#;>6b8tV1E?@oAVvKC|3O`d&NRY= zaUz@~XM_p&F#^R=9Ta~zME|qTK}-xhblf07MFC>WR3LMd5(E#kf*2Dkvd;!80@R>< zj1@STkAVn{Fo-f82L-NUaDq-APOvJ00=GOU3!DHkJ{eFGmIdwOB%pPS2DFaTz!`)M zPacMIO5~s;#sp{OS>T*3BbX^OgPjUes&jxlvacm_91Kn#2QxKM&=pmHQ}PO6qsIXr z##G>IP65F-%s|6MnZ62O97k>g#dM)AA&6SA=vR4#Mlc$ zpydg0H9ZLd&O*p#C;~A-;(&ISf@7?wL5k4;j&Ys?IaVt;Az%pVvIaz1wC`Ut8?9` zy&nV}kG-Jlu^*_)r+}^i9?pmqfsR@pSjv}x;qfxCRlW&lPi27lIUHD9C4jYcA~-sx zgTD4M>K<+*n7@v4BRfC`Aj z+yGnaUT}6808jVl5FRmr@GvBJr9z^AJ|qWSfkgBjNQtV0==j?Z8#fF%91aRHGN2?s z9~qYfsLx1(Ti32Za$-4Tq~8Qw{5`mseFyS#??HM(6C|hCLt0iNWF$X?tkg$vDWeTC zb00!(ejAisYk=$5uR~Qu1>C!L59;sShFdoqp{2PQKGes-^BZ~ay(0zsZ&gD7-8$%M zZG-P!X^@%T2ZdLAAt`wTE?s^D#n+!gQQ0U|+GJnid)=g*$Q$n!yXJ@N`h-@Jx*?>@lz2;rH&577rC&w>dK3*)i;{b6_L z?A^Dk|I+v!!w28LpQe7g4X|a$cj3Z?19&8tC`L9c$d77k$)#@oU+_UWe#hzI>FF)x z=CWz|AAB&2f2dekP!PAN{hR*Lr{;e)LO>AxPOI+X~O-M+%AoZe3YdVS??bxTVd(f~mLp|0gMq(`f*F06*H@g}N!fkE&$b@hSmhf1djP?ovy|J<8Y|udhL$k}^;tBYk z-qC;BSbm^maL@(;-*R1do&aB8K0_6PONb3(RYvgK=N{EN)c3smd0=W|`QaHvrKzd8 zxye{}m;guYYjMUUB*X@CDC2PP!rG?frVYKlt-bTh2hx?dbw(Np={Ws7sBf%|(}pDB z62b#1RpR4uQe;HTJ-ywg{D{)K`4s|WW##AFzTsd04#S#@FfIX?5Ew{_Mf{N=B69ET zVdjvL5@_h{>3u&x@5t!=*YH2vKK_UV#C}j9WdvehiHPKW4~jxgNm$ghr>C{2o{>}7 z`riQ~X#9DuilA|kfxZO$@k&Hwk9%AXNph12Q#JJT)YA$hr=%BgZE<-8xsW$DKIJ7R z;gS;M#KlRm@wj+p#Qqa^Qjz0F#i{Q1+-E?}39oZc?;}r#+Sb?aM(0PbyyXiM~6N`OvE96nFuS(D2p=p)RG;$Qu3uZDJg`6h@M6n!Q)to$Wf0U zBk989$JUe~NRJ{IyBlbggh_ansTyiY6iZ6-uO{JSC=Zd7$RPgUc!`LZ5$xl~?hF)i z2s}}R`N@5%<03~y#A)vfQrKK6$-h>V!pRdT$t@h8m>e%dLrz3%>t<_0K`I>^8EMT>{8AkM;4{d$ za5${EN^*KKj>F7@K#T|8ARXdxH8CUf=dlSVC)q#vY#JUVL_rx5#|sO(xp}ymAB+vs zKm?V$D}^}%wb?ef^*1hqogpmHK9^DICZIIUkLtx$<1aYq(L*kV>k(&Rv{IQCG?g+5fp;7WQUM} zCJc3I*+2HP1(D}ALca$DkedWf35($WHlV_2YeuSc&=wBy=wH0h<^diyrv#)BS7Hh7 z9FP*f83h6-5J4%Y;Op1V-#*8jpZ$x6*;z{tl~@FSAjZW@(IW7FD>xM@h8wpKI%W0o zA3V~DX99>je<8^1JcQi!5Z!~HGL_Kb%9{vjdi@8Fbi#|!-2(_N9(!;S360?*gauwc zJHS_}$NU$5W(Jx02XxS90u=dSg{i!@wTD=RECi3es5{OS7Z7194o3I81bi~7IY z{~m$3e=5`el!VBSK!k}(AVSVgAi_Elf%dx&ivN^^Je3z=O@#lGr~Y^D`(Jq~CkZJW zqoxE2W?GQrq&~<`rP*0PLx2`k1&<)PD?i9{34!V{VWch#y24aoC`$?Fl#$$1lo^bW z+|yE?2`rSEz+R07>=d}cOobC1l#v`%ofTYF*^t~*2+qg}gPE!z=%0{>v$D!ys;U5X zx`)A5mmN?h2QLFAt(44aRSPm4MNR1A;O#kB5k-J8p+qJ^^Sp! z0g|7Z2!fZTAOxR320@Oz5Mh4|yv|Dj+Cv0l14RMtB@HsH`k=^R4(i;YAS)37it;W< z&glzs5@AUG83fv*T1ft^1Ln%7K~u;SOw?@PywZ6v)6#+S+J<0p$`I^~48d3rIj(sQ z9JJ1Zqlr1#>Dz+aIW35?)kX498@S+T1+gA_5aMnHI-34qY2pq}XWikPp*Pr=p^*G4 z3_Q=e9ps^2mRJb0K|`>cJ0zatf)ocHzJO5lJK zkmJUW@agk za&dzsbQoO1NkAq}267Tk!d09cz!|;kV0!iroHJ?yN4t7B zZ`Kah799{_dkZ21D+YNR$y-2$Q;DO|>5s^a>kL0a5 z-&{xvE`dZ0lDEb*04^>Oa#E6@`0{0_EGmMOyz&8|KzDiY7!*>il zHa&Rf-PQrUuejNv_G}l%kGQ)d;tPyEVqPbVtKV(>6>n{Aye_}<6InlJJ&>Oe@euPo zY4d$+Yy03wD8ApH1Q=yURd%Lx$rK{^e-u>hYg1@iL=<1gcz~mcpv>Fkw+ch+|{9~ZI z{rmRzCj(DUzXUI)z?h@&33AH^%`KgX1%ipLww>)wTQ9#0apHU-A=<0kJ3BjfuQdMy zc>K8Q`quWJTe5zkaVLahV@_`(;+=WTN&=u0vC-9By0x?2D(4XwA|ite(tf@82LZgd zyV6KVXb?!rJ>CTdI zND|V$p!gWl!~NEL(h`nOpVpsdsUo;SpqGkBQtig%pB#(Gb$DqRc%Ig9%gZ?qjEsC* zT3-8c5ucnO&qNxOgd?ZwJ4eIMYgnf(pCosq{*Qos@A1Num-F)ru{8c}(&^bTT<5r{xw&L;$;m<7 z_Ep@}+Bz)Qd_-X zVnKldMer^uh?<&O0+*bW{8t`6iaefopUcJI6rvF~lam#=xmjY9l9Q6~IhPBNmoG07 zIqbfaREUm_N90NJ)Dkg>6v^4->>oaSsQ-c>2bemKBFK}Hkh4(xwv=%Eebzw8jw`VQHVRq)p)eqtu01pGJ5IVL}{3h++QM_YQy8 z(>4DqHbH`y|Bxad8(63_fxFrf&=nH{LnNNCR1*Pn6$#KeeiBYgO2b)6bvP@n1ZGOo za86Mki8oZiPKOn&b&xe~M{aO3<_E`9$G}!k40$#m2Wu@wu+>xpM|}2WV?Pz#<%JcMKws^>5d+GT?Vc0X&Tq!TXdFc$ley|2Y-#wowLu2Nl5D zN<$>_jE-}KLi18PN$P1DXeL(_w-pfLCfC2=$Ye0mb8bk%jLTrc<*lJk7 z8L=2}G}1<53>(Bh8*n$&1!rWf+u!;uxSTQv7kzv1JmrA+=?Gp{=fThZ9Jre~K!}Gv zpj`}+wOR`#RziU<5^H#y`GB{TKX_P0!UcB}gn0P?+AkQ;-Z6jb81hRuAAO$Ol#2Dg8>>v$ESZTmVN<$j5?wuMV z5BVV{ArB)BxlyuE5-ooadnAVHBkR7lfDd+qv_KTZg?K@7XawAhjfBj28OTjW7*B{h z5j!(hW zx$7WS2o8CMV22?tCKuu(@&Jb^Mf#WyC3#7Zka!JlUdw~D#2QG(--U}8s~{(*8sbx$ zASvwuWM?!$YE~;`XSP84#fONj9`Xv>p|GeEdG>cg%l!tpl-CO-<;WU!*#MN??uUET zkKyLM7tqe|g}V)-P}_{~!zsA` za2y&RjX`tU1T?gNga;kd(DZl)TAqA^8RUvwV%Ucj>3vu;+lP&yeb~IT55Md8VSD87 zdN$!AKc=rp5_lwrQnQ?awV6Jii!=o8;A^dwF?>(?1~AK2~f&7_rLqzGS$@BfQITQ z;Y}sY=~KGr2wCAlW=Mt<_QAJ337;XH*447Wj(>?h6vg?zaj&`6wYtGIzxU*G5gD1D zpu*QTaY9D9@)m{@?;92yYfl$#+_>Cu`lu&a$_uos=fw*HuAZLW`?DW#B{r|94iD`A zX?FbigszGi=cGZiC+cr4tG$ z^C>^mH+v>+O*qpVxJVJ}S2F15G6*rn%BL+JenrVz<1jr@TI>0lH2pYv~>dLxE4wFE1dQYb*_e2x3_!U+H|D*bLWDz^vu@8)E?`?``Se0(H(mJ zQD5X@d&)vhYfWuy>o$w>+AD?d-+@!#Miv?;0y@=xHFxfc)11lp<6&Y#=NPjdt-3ZW zaJ%Y`d3I!qHGZo=KuTQCutj&DOzVf?j((+91d3jYZBP=Ta#7C{Jbx~x@cXwvS1=zxI#STeyM2Au+wv(*u23O>i~)UpHIn{PLvyoRe-;<^ z+Z9yc{F~!#yBiZvU%apwx>Fvx_XE}WWOb-B^`j#P=x+c1{HIXY{dZA`lU;N()ra|l zsp@CaFT>T|ydS^j&x~oRjE}3(A;T#vTaHYoqS>YF<(R5RdQS$9SR=;6Mj997}t~NTtWXB?XVLQ^LO1GI+|VRk?yjx zexA~JSaDYvKjp=o;45{ybcmhMVb5b%&+}g!oVR_<9{T1@<=#@zT0;Ys|6_JkSIChg zN3uMgfBXEcsJ8pVLm7HDw&_q>c8X`up4Iujmk@J!#O&hYGLOm2d%HD57kj#^jwo6e zegnsd>$LXTd3U#T=yP+nYSvL(%`>aC zwAwo!z6??)%xsx$A?`2;C6P#FsS-N$nN#5#)%cm`BaUWCx@^TK4*whZA4fNuNDZ zHXR*c$z!`^g6k>S;{*`&zt*GB7 z3D-$wy+V;sBor;6<&^$jlv>}kh4qupD|yzd*P76>v)?K`H~AX!tQZT1zXqNNIJ~zP zV_g@>(xK=2c)am>Qb(7AN|6)(?E9&VVy55oWZmND@E|}3B$+NcCJK8N#loQ^&~xZ}(?$tEDZ*?r-m^V1Dh0M(-@9yR&C`xgA-gl9a6Nbc$Yod&fj$SC*LA z@1!a90KRkY_R2+xfV_r5)(;uqe=!&=+3q^1d8yms`*I)N zRtYAK{>f#G>&kxDefc=kQu|^w$9u=f<8AHH&KkO?!7najE23uS>?>7j4#DYw9}#|e zc6KRaXZON5f>b1}SlnXI3jC3cK6BL0Ot4Lg&IF)2>F^H!+2&ta^K zKO#RCE{)xkNpZwrBO_6|y1K_CoH{;iFZc5pV6iO`u2xnGe4jX4X0N3rv735-TeIk? zwWF-%ExPAEbZCyKi$rf)iF3@w;VR21g&-}5b)&gkz0*7l`u5p2YZvA)%A1Gx@E>qr z)~{JIQm;^*5>v##J15VBRyxltB-A%!pz(;Kz@h2f7Oj`UrM9-HdyXM$gWvMzlz=#W zp@Kf1R8T|(v3W?Hl~%ZgfL9v*6$`4$-%xae|Z zH&b05Us#fPJ1NAAQTEA{0@6E&>#teK;S9?)N; zr$H zZJ!NEc7L^sA@9#Bez$;p12uYBQBE*0N$WSwOaHlNQ9`}9BehAf$>XZdbOr$oGW zQ21OMyIUdyUN<$YVjYOO3LJC4hY8eAzrTL-X0oJh!_$R6j)0y9@7IYh0wg<;x72P6 z8?}Ki-(o7R2|0PUEg3jOv$w@3oNuze@XRN-hy@C%O{3~tPr77;yhnjWk@G1e5x zan$UQi_BfGne>3U-@Dr46s1>_ZjZg5cBAATQHlJR{P8p2ZcYo4Jkxz^)7C{P+m-aB zSHm64%2%aaWVxf)SgjkpYU&u7kK}#&!_kqV)}!ZD4aDHeC?ziPrZT0;M`&F6FvaxL z*QVy_)K^h6yw`WXWvTdg=bEVBHMfi{A&M(42>&yIpQ|}cO~uSG3fSMh&BNl6nOCB`H%nzm%vMn&?u9*Z4_8|(RQD6@>IQBT$C)j& zv-No$m0ct|^}}udB5P7QdHqIZa|Ky1PfV6iCao@BuA%OUaHheF_$y1~2&V@o;KX;@dfZFzZDj3yN!8u}nZ*AGD zgs-?iM;`InNz|;`3t!x(M$bRU9Q}AQXS1ed1zoJ3cPnO=i813cM{P2XI95Nn>PNwM zpQDHGpRIGHvbY?V;}1Gyknk(O`}@%&H!{t2kABJ=ec4z?dMF?|BR}m#N^Pd2qtvZq z{3jw$Y71u_f$(L8$js`uKiQ2t-3M=1nu}0~Vt#2E=*j*0S?tqN?>PPHtkv|N1<5Do z`w^729V^!ck0`!*&hefRUNj}Tba{sDD00$^{P629O$$*YhODry0h5?lA4W!&8;6OO zWbV7554HcIrlTu;A1yJ@Jd ze8f(Q1|M!goKw@v>DZ%GXHal{&cr^1=mfC+&;>m@Dg20R%Wg8jtM)%Xdvjc#vH#%B z-T#*2C0Z34gCUl6Vx+9_G%=8U-X7EOKEU@ zeW)^Z2|;aZ_t$P36+cra+K0i|e|9hm%&xGPbQ^EZ>%;_2B+I z5l(#drXxK3%Jk=j%&ZOLN!#Tcje&aZoR&!jk$Z}0o|L=P&VX%Gq!W++6Sh|!;GhRf z-G zKKyyX*5>P4=lyFsbH|#D7pkfq3x!SuTBzpKw2^i&xXdj+cm`$kogwt5pczDM83xFQ zfGCpcVnK0>Z{zw$A>yi?>B@}01&<=XdJ(o?SmN%3R=Yrs@xIpB7d!04q-`%fr};P7 z*?b--@9^nyp%rAyBi_eYEGo@0lO79f;*eBED-m@)!n0xD6dV39T~`+*h1lZ*20FFZ zd~KTjmG*uQO$n&08>{6P6r{BNdQ^pZebZ<{@*TSe&707OU0D$kuiuZt7Kl4H+ZSC1 zilrFE@inde`0k1bKt?dr$JjW;+y-(w`rf9v$q;H}kmaeQ3#=SvU8PUbrXkz89y zd$uhts|Kw^`&IW$b*X$}OXR#c_cq?|Ki>H*^VY4py1Hfkon3W6$8XPxb_n^HG0cQ47jYLZ?Jn8xcx-`s2HO#HbFiC!Hq7D zaULUyJ8wz)=o9f}2ge{PnhXuKKu0&)UDKIpbY+pM!+e-#N z8anY5Kk1~UrQLX9wp{oYQ<9UF=`}DF4GqMxTc0(S$9)&eQ?2EFJ69d16nf%^QyUgg zCfb@7*YVq|p931x9Gv=z*6c1AA3Z9enMz?nq=}~7IHwDhT1K2FhuvwKGDTRsP7C52 z#s7E-JonApSHOoq!OmmGyCUEm~UjWF6fGkt6OAZc4-!`y4 z?4^ulPU4BmqBXvwCoZAN_@EE<_y-T((U$Z4dYIznqJ%&BLX(T5hHT10TtR0kNOKs; z$cbm=I0Fk``fLi*#P|lWr>SopuGSOu-{yxn-8dqJcm^VvFdDVrIq$}Gt@gw_BB*`7 zzx_NQaIw94Y_O52OOHXMZ>UT4HH}d2_g~U(eaFZwYYbDI%F|vnv#GruBdrvrqLk8q+EAp{P9EyI!fTxtUH>M<7U$D6Uym!qrXcYL5_~ zgw8BQZ-ZrP6}Et}%l3Oo-bKGm({~l)%m%W9=P6H9dLOB%x~}};{hPR0E9UtqgRQYW zZCFa+`B1~%S_pCB%Oh)lQnRy%u8uuG8K^FGkytnSJ)L-&IL7jny!px{}Dq zB4xNTwU{m_hZUingY~Jt4Hfa_T#zzrYQ{`Iy_735Ue8moWpi%pT5)_|SeUt8F!a1VK55%KVqfO6s=s3gq66R_`j7(rYO~sd~qmyNWI) zCMJzZ_3NiituxKZ9=TkOea?*}gKhzCYJ2A$oymc0=l4+dbc)6slCDY2R3@r4dLy0~ z0v2C?CyHfaW|p13>RYqix;m(GDKGD<=8oaz;*_7Y`&e3&-31R>#gUcOI4n82K=8Qk zOi%as_QTxA7U(rUNHTPUNOaYBgXU>Q*H?2yey&~NN5}a--0ZwTBe>|Nxo&2g_$J`j zlgn$;Y(oJ4! zrtuI8{G8Z z0ez&q@8+xUj=B7y2ThITK2t%Q;qx?ps#rFY{BLv=(Dp9&_j9LDslwMpQP= zm8k6&USq>&1WJa=zWMaDiib~7n&rFbxAG?%6#aJ}1zm6B;)@YdmW1OhOv>qJg68wG zFGdXT>lz+SSfO<`2~r8Z+j^1xd%8^}@kM$s&7UK$6?ezUG9Jz_CYrp^4LYkqJ2H?& zGs(vBHRb#A9)-+$x%;-d>iYBkHAZd}GdZp>vMj>8QO-9`OZmp|;0y=mO+ zPJcJB<>j;!7(;sBt!>2cN96Er>&qDS<^BteTl~$3eyUk+MRL@Myv^W|Ow+D#l00h6 z%3G|M_(0rJwW*Osh03-!{Behny^=KBR4G?h*)L1g{r=dQ^8S6Tsj(;}toYvAtAzqln`weryx{Tv2#gC@qjx5?RyoiHe~YHD!Hgur-{+H-CG{UUB<%Br;W5f&Fdv7Fwj=s z$><7)c){;?T2M1${1H6%n`fk{=5I_og=ZD=O78gBFxL#`%oG0*^XnI{EhxM5z^Q7f zUz<2>sya*Gll1vY*Msf(Wv5arhEt=zdNY1xv*>>M^>9Xt$zXWQw>LoH{O5tm^+zaI zwXRt4?CzK5I`sih^gjfx(p{Vwzo#OM`}X;3!CvyARnOb~^9u_>1A+y`1s?sPxadEz z3yX`LpH`krZtlOWjqx~TWE6(~;+AB=H=w_GDe8~n&z-LxXuc}h2)|dV zF;=?Ta{};hTnY6 zd|oQ4tC#+f^yR(nAr^y~?U3%?LVvZ1w19TUGhz?bxjjM?>GoPASVD4$d;JG>celmg z&NVa1U1{tr?Mb4KWwKS?UZM!%+8>)LYt2`ve#k?A>VwXvYHN^6$Ntalx+=%gDk)wO z`o*^0!IOeBXqQ>6u z<9@rYDfsEv10Nd-cibv2)5uA1b9txh z?#n{iXJRrEU>zoVG8VMz7{MWaGR5QMRVk%tS$$!ls>Uz&>i7J(Mom6J2&rgUr=WQ*&h#4%1;pq#(3{qM zoUsvxz|O-UXNR6CUsR35h@K6b4ZP__1XV0m{eyB)$K@}?&==d=*C(;_3)AWAn#9A@ z8SUo5ld`0~Ryj4jRc}uFLw;h_?VE>ytS{$|z!UP0ReHt6tY<#V(Jc%{4}Zu1MCH0Z z3oCd~RbY>z&8moNyPX&6Yzy=@@eRCTIQ-<~1*I{)Um*cysk%gh?#i-HL+!^)1qqq|`(St+dFbZZU8h;T7WH)c0; zUS3rz7AULac;Mz1*#E-&*z0V1a$b@y^T_$-)|XF6<7`}RPduWgi<#AGGqA({TXvywaY8PWRE6fbdO7q}j7()D!egSQ1N7IKh%)#Crs>@h zQr@bzbCGE7i7r;)`r2!)r~)b1=(_ITkzsJ9ZE`TIYJX+Q*nc?mHC7sHL7DwHcW&-g zzxz^gkY)MSjaA)v29t@vxUM^4!wJ+849i6c#PojBPo}1<0wE10Y@*UyY?7JLz3$dm zRz4Z31)6hUpNhOEUQZy63n?f4(jXv;2X12{qmtmo_RWaN(AP$^Jww%ZAF%|q{pP#2 z_5AhIA;~u$R!6S*2y`=ay7FoFXLApiSe5+NlC3wzSNp1mu>1}P(6nlQIa?w(Zq_s3 zD{hC6$<(>1!$)}`nfF3FAg_jIi6A-RcMRi$GwS2``Sz4y(OVs^?_!S=X<`HMgFC_} znFm$^4XjvgmB&rbs>GUw9a8=-BO34<+xb@dHsP8*5GbQsu%E0ZP z&DnD+U&b5;KSq0dd%xz1TGD#G{@#f$y|>;XSj&ZSZ+)>~xjUq`vZBJa_Oy^IiplB4 z2lnoQDXEKY1N0P5-fHVcB3Km3QRA<71iSNCiZ7jLfyH4{8`3&u8ighgD*3tjL&4AL zLMY)$yI4x&yI*PX7<{#N!et*95-c2fp z$;k@)#<$8+;b(ZIIHXDMJ~=HZU&yAkz$-Cr=K)vbMlM&CW|tM;O~;jI&-(r($OzSx9ZMH zaV_vIm$lqHM<3%Ib|diVQL6MoWg@b;mfjG3)&8=owgF4Jn640J`swt!(LlcK*43Go zVVF*(Sb9AXlc*rN#`pN%5O!ls{`>wP<8#K1R@+|ex z*CHrO8gtC)Gy>dDvE>^Mu-xpr+DBF_E~;g7K~6c9B(Qmc1@E=@w1;8B4k6ldJXrswrYbW zs^1G}vOG~NAI#!XA+vYeQB(OIlCNX=^``dS$NlR~O4#CNV@cb!%2VI6Bd2lXx?$Xr zpJtOnc6z)&>`x1f)<-vAP1Sc`YY^y>C>Fm_zTu8xBb$&^p89w^%`LFe8ufeX!qAbp zFTU>uq~vTiSS}NFJ!a!&r8etMXivUHuILo;q$XLvIAY!-lmf*&a9-}12-~W#v5rTy zxN+W>%1rBCbyVtknw+Q8vkSs6JoeN(D9Sn`BO-@ijYuday)$l|dX{DX<1xFm_l^=Z z_p3)2B8egYBJU^YCM|FA6`+LJ9HKI}#Jsrd4}0cqj%LSBk{-|G`W3UX8o4~Yi%Fw; z`T;9mke~m^!S_X{$@TaArv{X}`T6;ykTvKXZEfwg?+;Ri#>S2Amz9>5UaDHHdl6u= z^8pzv!MiJdlPiJ|KmB$bziA#{75hmg1I^jpH7pu~bdLYs(JD z|1`%azthltQJ6L-xcYr;r)SVJ}}$3v=AxWEPT2PokM-j&ulPFuu@9I!tIQl<&C5}@!2Og#2)xu}GlN{OE*~udKR8%;YmzVkN=$AHj<~ZkmyI{rE`< zJ2R#s;BCi zJXVd{^Gi}otuM6*uF_vo8ZiDP!I@V|-Cf(b< zauP|;Tw*J^eB$FSv$4_j>-<@%V@4@jm(-gZnp5qGd*7Z{rgt{??QuW48unaG`s6R8*Y$aEG zI7q6hx#c?zh8O(DU)G*IbLJVZ&BxG%>Slgv=@Guu{hFD=woiBHc8*RoMcoiBdx~E; z8|?h!(?g2VlaE*bggkMryir-QP9qYrXNbMt%s;|x=icU+LD%*Qjt;YrIB(98fr#$pcQ`l zQ=6nq(^K;sd~99Z#6DUR%WD2EK&(#g_jJfVY_7ec7Kx@8 z{`$qIwP%mcN3*xkY$*HHVC??xy`_m8&tDI%a7T^>`FI<@^IlWe@at^Y-Yow$dYU(C>P3kgqJ_X~S03vWWic_Iu%dcNymvLDJk;CmFa{jDxRdTS$-60_hkf{ahpNZuBGh zh_HP^W0 zG?1gp=`}KhGW27X4~Teu90EJ07qoSBW+m;KUTm^^AdE zIg8;HSy~nv>i$#)9_&T*9 z5?6!0Jv+%3CHb?Pmh8cfis;>-jklN)d%twv&mZ7UJtdpk33fi57V(?wFPenjd!C#T zE}tPSZuu~{O^d)C@%YaI3yMdhrA%FU4f2f{!-zZ)@?faN#!t_*IfjuWrqPbl! zqxwgNA&HB%j!l>DVng0PsfwfLsRvU=Yt7 zmx)LJ_hGChZc7pC4eQshx88g2y&%@#X%P;V-%sZj;Ga*ufX_B;Ms9Atof(XXn-F~V ztf^>iZNt93hxN)H8rVRRp*e-LWlV-=e*NNy!#T|^+_B(e-Z$&r&*slh?^I2^$SV-e)JE&5S+W1 z*P@~#EARTw6n$KQ=is4Z`1!+sAi_R`4i5?>>c*WNMB<_mzid82&H?eeK2?9Tox^?K z{}j!+g(_#lXGDdDV}8~&IsRSWN~$ZcH|IFoyKH@CKZUq;D`6Qo8gjUw9RL7I@dl-O zu%Zj_TnsR{{itnx4_>q(VL{^E%Ufd6`6q0J=_U|pX>LbjLkn?mJx;H|K|xhJ_MqtF zP3qXNUSwiwhDa4|b98bd0=RlMRWT^lxv|#?u$lEx?kSupEk=)4LCm=Y(^HU2Ai(0{ zfNYZoK)~bfL+g%ZdtYB~8$c3=#38<2on3-c67x&*6i!?Ka{^i}Kxxw>FAN7T7y#HN z1Hf)40Km=P-w!w5bS3`lSN9XQ9}9!kg@0#Rc@;kSWE1}JkLPgoNRCdE?@3dMf5|)% z(KjfsuMyn+MJ+s%`-?x?sEhdHMb4W4r06)Ec~ki{JFjq@J6i>;8a_XGbQ)q;Er++P z_pl#6TW}Cm4#4IUFvuPaaK5jfHzFcJ5M&9k1+i!pSfaQk5q^Dr3mWR1g;?OwIJ?ij z!^nUALs5`I>BEGSbj%n%Uh#F7l$$KN83q!#l*>vw0X8*S?LdIfV@ILAr%xikycE4! z%K#U^ATc2MvX$_S@F4$#8xY`r_z=+t2L~X)>?dSjZEEc9u3ogZv=d0Sp<6DL$^;S} z8%kV2fCCpG03eM3pylEQfG1@Da5Xf6#IgVIzT5G@{oi#203Mk9f@1vs4}Zs7Z+?W< z=4M@}u6Ckbj=e#W`8id0*o7p1Y8>cOws|M2cJ9>#{a6tk7$jU?*`v+bFS&2URpr=! z<|NuWY(4`Vb0D}R0>}p9kQy6Wg~f{JDU3L( zh^P<;*I*?W=wb(er%TS_%cfem)Bc!)%((N;oAdy{b@w)Wx)m?I@CH8pbc;i&ZPsvm z)3kHhqgY~x_cb@7%ZZYSbHOFj~`BwPZH_rA`@a_h|{@VtZceo6UPfnAf-dtRU zEdo1^9Te`Ys(UaO!^lh*q5#JVIAfqxU4YRB0D=oJX~lryWennMH4%}L(#mT9KMm&I zYHOP4)##K9Xv)b${u>{nv%$t8WhRUw4k=3-AH}?Ba?Jr4Tzz1AS51U^>i}~GTybdE ziDM%6Ks%D`C7QH$3Bspk!QiR6SiYY$PX^lQ{6v^9NBP+kzj``X|LyEXZFLix8e0S? zuudg1DioHGKpl5D@&FJhzVj3SJTU`qCjfZ4ybxO&YtTJ_0$6aR3;?`9>gpTt=pUcN z+i!i0lA=4y>ftsoYp*ZDJgM*2?iU}3wLFK1k7XbLUx(pxHRidrWwenZJPitGdbuY<) zPyhR6e8A<8TiTqSXr=``DaeAEL7^xj)@@@$4VrrOiY0H^w?BIJ^nuHBxn47aJjKn# z_VkG27bTx;*7^N&5KH!$i3nDz;JCRrXS~^Y><}vIYxG>e=yb%dTMeU=ekzMi6$2Ci z@G{s~^Ph3=i{)iBXN_$RTuVQ({>2}BjtaH}$c+`F^CnCpkc^WK z$N-=cl9P-%ZfAt81H7pyAfRciZ()ne;j_8u?C#bMB+T(KNV{@10+SM99RvvQnDg$> z03dSvIg|11#;2~P8Fh6{!hgkw0G5Bt3RWeC{z3zQC$RwAANmva5N*CzU5fhNZVc26 zkNxRM>)-$RJj#m89J28$lNmy6;G)n-%(a9er>zAa)K;Ljr&~9M-hqL_!!LSn_TXc^ zM_BGxT317p@cd&XpjP;01=o~}u>Z*EL;Et>zj}z-klu6|@;qxa>Mn-~E zG1#U9FuJ>q+ecwe0R1v2UsurX*8l*(TtEwP0jw+O?C28ny(-P$*B4WX__d|5#d?tY&$j9M=0@QJ#5_O#Xca3+b*!T$H!s^Lzh<=b5P*zeS zWM2E9lzhAirJHO)Tm0PfCQiZV#3bn)82}81fp=loq5%X4Ae4grigmztY8P>o`%a%k zPH~YggqYV<%=9cIu2}-3+3b-U0FQSliASs?^`^1XYG16%|5|+njSsW`)s^+c1$RiP z(iwa#fr69p_xC||O!P&~0aS1K5}ODBYT7&SRCxhPyX=zg1P8+>JQ5v61zK}>tiyQn zP_eu}n+ShiNI2qr{E$lo!E8mDUFKI#^ccHzzLdsSy&at>{d_B`cJ31jC~mx~vEq-5V6sPAQ){d6`{#Ey zNp<)340v7p7Cv(tBInO>n#oAz0_+2XOmYFyVTb{IJtlq*WA!vln*og%cx_dqgNtz8 zt^+6}E}@6^}u^Vvx;&CDm2fdEywF+FEr# z@e8vc?a~#nOc*28Y#5-w%q8*e9U2y_=J?k(1pq|aZ(1WA!~w9SMBxC`>-c&T09deW zbQ-Q3J$eKkfksvYC?f#)_<`S}gEqW>mlrw$Ktv>B)?bO<=4RA?wH=-1WqJVcrO6#1 z7=*RqF^Hud(wm;*YzOW9Rb?pZY}XS%=kS|5UC8}j{zFLecn*|)+SXaufKwvhU7dO? zfY|?uX`>Mu6pS+^g{Y|GtT){Q`pdg(B9LYM8kkd49NbrxUB{Lx%q9*;#V1z3nZ zjZ2Jlo65@GIfrfD6~qPf_UNrVodqSxd+Q@KmsP6AqC>;5aMDzSnuBF4fJxQH4@mG% zKiEA_zf~0n6a?V8V2jJ)yj&bBEO5v#7!VnT^vhQxFe8QJR{{Zdj!E=gpxKY)_%LA- zv1mWGEP2Md;_;t07=pqrxz61p4Kv*+zG;W0-~2J z5V{ciARXx(gDzj7Nn1T=7#P5bEaDO)L`ECWhQ*5J=5~~q)(CMx*V;O8`o*_UcPh_z zec}XHX3r8P!9j5V4n*%RfT&+}7V7BkLS0i6N{Ib0uBjH{fPFqfzP}|Y4pB3wz&APy zrocdW1^5X!ZKIcCuo90m10_55NDfnyLzc3`D}ht&7R)Zw&CP92m89H<6=O4S_q=R0 zc6eR10PyYu|06hn=POE3>H+{ve*VHj)_Up$3?>4A6#qc1Ai^I@yMKV}R8m8e@m@`( zh%44+7-g@%kg=IaT)i0nQ4vGi#m@2W&oY1U#~VehzkaPoSsq!Z&O7qr;((FhK(ok; z$3ZbBvEZ#@avGYOP~BKBl3i-K289aOLdM-qO5*Yy6Y5l)I9Du#P zP746?0KhQGJjS{%B3d~380D4QMvGxfLk&Kwt46!ljgto6oEVEyYnO|}jzdc5c#esm zTVHzza-Mz}t%aonp38*E3q2^njLf7ISj@CYyu1-eY?8Ou?#)_a8cmC?gHAYgY+ffDRM25rRg?lwpH02|Cd;3b$2u2=ey8`ob)CVixA{p zIPZnGP~o{H$Fz? z{v&GgRvwEblcys!Hclck21F;I@5&`tLyPTmZni5CPf<0A3^jD76Ow;^bm3 zy^=O5o9~F>nXzls+xF5^?`v+r+co8AuuBQeG4P42mmrMeh=)S_?pDNrr+5wkyvvn- zx>TXS!i$Ag+SLInxcAolUz~ z*?qX5O@sD}lRmSoy8Y-uopTT?0a+OsGG(Gpw%5i67>za%PyxW`$OR0h*Bllc79K2| zf`rqH=34yZyt{Emr~3M4G;!3Mi?Cp8NhOZG@FrSo>eT0s4GYJLX){FSV8H>H2KEGW zCjxNTZAo<{4(FXgMQx2PAHcb4Jh!YD2u@8BxhR9vlH~GagIil)CjfZ0q6CGVdb7Q^ zB?OVnR>4Dn}MO8GDroZfusLwkpJd~ zXvr^j_}WN3IGeVnjTw(fONjV^L1t}TX{)RR0Fobp9t7GuJ8|Gl4sy%%_X$i%65fHn z5fSPowf^&3E&B<0 z9Y_B0JX*?ara;aLeCh0Yu$avbB7kSIzCqQxv&prvq5_A`oEFN|zG0YO2R}&EKQC{Q zlr}7D486v|KRirIQsbcx=Ia6gYz25rSnt~P30P?^!{;qTU|OcyXT#G30A+*}Z&sJ# zWLqoxH49xh`f$mvdD%m=^=k%yXr~Mw0II&+CoBMcc2RFk5KR2pqbGm-PeBd1IxoIY1~0!zPSHP;vrsxE7DRSidd+&`ALBX3Or)isZ9~}? z+Z-yuMv>ezW9&qP2ib^U3UKju9^$HLszT6i(K7qL`_ysdmKN(|SihKPVHWgdGpR-i zs62~S8EDj06;|AX2i0@?9asrAg0fRf)r>rmvHROQaPr9)(Oguf9y1dFtS1g2++uOm z0cak;;D!_6;GQ!j#n^v32lXw@BQNg{w()#WU$_XZe@qm@i5mzRmm%DZ-L3Nr4FCgK z0TcjWF>4obSlb)xbon|suR`#|$q1b}*Cz6=kDO}#oX|pBOi(DaQbr-^(iI3yh&`vo z@A{O%8^^muhTG3jfBcm0YeD>DCLqERs*}eJCT~@t>HcmStAO3&Evl@*9s+?DP1YbD z=%|Hr5jt&(;0O#(#Q@nQSk4`&0>EJ00*2>E=+OE)I&t>Jw^5gqrz$_$8EDCrslpOq zBCwPejs~a(5CNF$U`5~V6UR~0)aWtsi)5!hKE#0p!k@MG@;veHIZ%rei45CnAp2(c zhK7jz72#7R!Y?e;LC>MIuL}ThX!FUo7JOV&r8DF6S~rgwhwueUZ2(|0#96goej=S$ zTr@_lTLDW($}k6bD5ng5=jSHeT#uc?+1K6|3t4HL`8S(n{*;(_&F<)Y_t#z0!FQcO zpvR&31s4i;}cU-F?-wu`1txcjXQ9)`}4XgtFFe5qlZyhU+2>El7G+P$3cOC zB3DCra438UMA>uGVh$Euh_|eN;(2atZ4p_TxO6!u6B#x~A;f|}gpSJ;if%R?nw&&< zUN`_S$s$0NM@vR_Uz?2IAr!#I|yNb~c%K8fE6X zS>19EBgOi2V~@Y;T?bM0{%1PVU2=4s$ZW$^Zxv5KrG}qDlMZa4t_rtRVK45}i303R zR@>BsZK9fx&Fz?V3&9*NymTRqzP=8+0HuJ4LCXQi9D%`^F5ny!zuXzL6qMrBGq0jY z4hrJu92FIfwKHeKmjFOrI0Nkbyr>$8-QRiaD2YfVPU9{38obL#5@(hWRX99LhVbi(_XlAbRCe z1f`|uL=SF8jrmW}0T}IK1YEh%j(oG-q`jgVC;tANE`}m5JRFzLoew`he@82T{gnh# z0m27uoX0C*w-FaXrjm_Juhqz3?M0cjbCTCvs<0N5N7 zHG8_K*y|nSS(+(ljVGa>O;2_8DF0$R!f6nBAU$&$8QSj8t)r?Ic`v?&Ha202h0ss( zs|iyw#$!yPEneRsso-U2kRd#UQU}jY{%mM%#`a@}QPW^c$1GBZjT?=ahIg@yRJH z#LnYKg6l$*#f(K$7LyEVmVaWfd5D?3++EJ` zJDroD6u}e5>H~u`nS%{VjDW@@s45Oe6a)so zSVwg&a{m1aI_X_$>@%@$)@+2)yHRHbbY`}+qPnpGn+_a6X-%~(_xGzWA8#LICZu3q z)-*)P6`AabS{F*8g#agy&xbgQaOXE-bRc|PNtnd8xbMl zdg69+J!cA0XSxTbn`Q!j76lHSIivG2VC7!eq_OZ02tdujW9V*d(j|x;sIe~$>jPpJ z%)0yqVLm6r$+SllNdVTx5~{L_*LZSE7n6mmpW zcSnzSXCP?YyB{rw44QvB}LdxEU7k7$Ux#1a{-o#fI?QL$}Yp~U^F=;6-%d0R{_BOF8rJ(t;1MnCGr;%S?hWB@D7ZwL?<5+-EYnQ@A z+(+Hvn=rex6gTw2J{>Nm;>N>t0(Y%RseuLrpEyQ z(ysrWl>>Z?gDJiMIf{yI)ZNi5YS8udNQD;rXcw&gViS7n>X35vI#|Y}Ipn_^X#nVM zZpEp8y@+;^%|>E518C3|X3Zq|HAXJ+Was(kmb-RN_zp@r)_3p#YrF)zXe_=wc@%lH z7`2*d-^d8WUAmeUW3-f9Lt`3L0l=UI0UKA~87_~ItYGC@3a3Rf6*WH~y~ZUaV=ajR z+8UDf&(%sqwf)!;9Lvwwx%qN`#w5mL$+X#s4AHaws#V0Oq)D?E0pOI=aOQx-3fMg- zPvDDvd(qmVA#l33B|QZxm#-EaLG7XADBHA?)=i7kWVp^6dkWrk_jmBSU*3ndKL3lB z19(^F02*Wtpvfr*u+HZHGUL&|TL&B6$9BdpCVXP~ImA>d2Q7Wqaxw=EJHI5B%MWAj zx>@ofv}^jE!=Ou|A;fBq#B(+;F4j1w|IYd63+Sw2xm5yy-~eB&nMv}$Um%n%#W0}q z&&6>!Rsu;M&|{M?>76s$><|htTa5+g0@yJqa=~1&nDqJp8%JPtVj6UB4H$V%VM9(X zPCxUi@C#7dxTGXpGHZ@QZarnpnC)gi|IZH|5Ltb+EjBz1Yi7+8br==VOUa04(CRz1 zJ#wNCQ19jx5TwSHoj21nY(H{T=b|kNyDplI_@(p2jjQ$?LdCYPgr&+;5V+~?Tkzu$} z%zxoQW~|7bk3e64o9$mjvnevHbB&VAo!{AUfdCqPfShBFccKG%r$vr?ZM2|wa4@2m zFGdhoN*2mAeYPO&-zL>GsI4V{K|I~iThp0*oc_;i#3tLc>Z219aLMdBl0StV0rCpy zAdzR+iR0LFDn}$ARazL$!_sNlB>QK`1x%%}m%4A;@$Ijv2CF#hts4N~#{L*@Y}rEM zSh0=^^Ij)F={t%LVs5m$^L7E z8O7+##AA@6*Mco(QFMW`*%;+iUF=QA`PsN)D`#ibE+%KQ&1`DH>mLwXcS0sYmj4YH zpPY&*>0?E0JF)Ay3jA>+3OFo27g}hm3<6yALI46JCz#I;>=VB4YLn{<#;#o{G|XB} zzasBzgN0n11<$Q>Kr0c%+1K7fTd6H7kWGQBXUs&L66L5F6YhUST|GYB{S~S-^#ub- zcAh(NJZ6oXBIOg1O`t}*UEk%7Z*TzsnorJ@f=u+MOG@ze_HC$XY}9@4A03I5%T^&| zOuBIDYAGm2#rEBT>#_E_cP+l|#w+mXAAW&O->?g!0~p8*xMRa-c=q03Bg@|`0N|yH z5}^##^*=EQkt^0pS%EwS04Bm7+L1fkxWw zMW?vgYV+C;!uiJ);p_gAqXuOeM##XqWu+tv96`5+3*b^>k@MytY{pbcp=PiVg+ux< zlTl+9G-!(QoLc~3ol5b?n}jk@Y3#ALbjnmr&B$=rtvT3d@9ERnaqO7dR|c<4;u-7KHPxE?|K-EETQP6e!W&%hAO-8e!sYQ zL@Ze)asvzq03u^5v*aB;s=V(igGzT@9cngwD&E<(Gvl z?Ci!63P#RfS69;{l#H$#FV@`W-VjKx{Fn=8uFjq(f`F7oBRv0PZp2eI-}NGOZkyJd z2CZV@Z9jGtMb(wM>jWf^5@tcas7N~zz?L1zsBi%$qs~HbK3oHtD7Z{m@kbjq{WM_7 z`UEkNx2nL@)a#7N=*xWDa{)h=}c*Iv6`06?dI#6=4LcYf=K zSQ8S7C<5$vs>?-8fUfE?ZHgQWXse8gMDwp}QA_Y)o9GXTt=I1$>s1)St#+tH)gfBKBN`}=yEurhlF zvd2yoK|MyJ(TR-jd>-7&|86-k?R9NO*%|50ZQGGwt`8dW3JOH(WvfMsI~EOj4Oj0y zjN(r=$+{%RcA){ll?b2(fSYc-2lLD!7;g^37xguwoS&9-yoe^k=EzAw-~<4aUBA1t zR}@I-WtQLSe#uFuKSIxmDkJ18Askb`AjaysZ7N z`f9)OFf^}LTBOsE9zRMgzr_I_?&AI(mZ9B(Wj5EKsU>OCS{t0pt3r>_tNI6U3h_;c z4~ewb+Bkv0)MUi0UM^%&#T07LL<1T$tiLvAfTRl;J^;A8LiN7GD0pXs&Jr*sJsr!Z zP7&d`{9AT;-g@LHcAd;ocmJg5Xsn+%A4xGWy1*U>GoSW36g3KsTRn}{KH?^dtEz+r zrQb<16GcbD>Dwo!reI8Bq6i&kJ%!QW2=cu&4?E~NH|*Vu7L5ZCZwe7pCy2Zk-e$>N zysN$u`EPxMMpg>i-S_JP04C}$13)8jXFD3}byTGFGe$a0UQ9 zt*t0{YXj-Yd6Mj%YfKWKj7&98tp`ip&e)6?#Hxj17 zt=n+;>{*?Y5~sRj|A06WTZJefyOkHb^9ed?YIXPfx&Q#Db&vP;M`l2v$O@zd09M9? zOq+?&>^ahXvLF4YmFuD@yFR<}>hgmOuuys$8&UH)$>8Nu9yuP!gw>0khK>5u#3Uw1 z3%kE33$vF1ptQIOEzRvt7emvjJi!5U*48V_2%+WxEX{;0kTcbA;!Mso9AU8_mN!12e{s5n$!5ad6}HQ%M}ytDCptbZMz>J(&|?k$lA(ku_MHOY4rSN)>(d zxhOKLv~vLfBk2mP002iw2GP2oU=9{({&fIA7q-yuA2xHI^fBw#|7T^pKHK=kuI~hN z-7TJ${&H={+Kuz1X5yRF)BI+A;eOOG*+@cK;$c|t-*%<`v?qd{SjrX$Bq_O0S*~fOl6WK zK;}%eIRmu50h(uU*M`C;i1g|N089u<&^13@MAG_|YBa1O3N)NNqn_p-0Icw(dHLz$s0+>kFaU6s?;sM98ns@kaYQp>_cN5qZ$MV!FFv$@!FTAw(?6c~W0#S0LUHD0d2r*RIF z2S*JVHc9#bt?6*E^X5^b`8@l^hp1HbD-gT%25M0Zz<(5^t8x7quR_)gC&Aq7Ob-EldLefDbL}pDl^LC;-4+6CA)S830o5`@Kud z9cUqSRaBsE%Qke;B#H}qVI?`)lyxBr)cSd2d^4cpkkqIUIXvXXA)Vmw5&a2qBSR+0@Ab2>dl^zZ+Ux@jBi2U~ZleGu1hu z4J_@Nb+BZniE-^|ZAb1)ZwZ|MKkq;yfDd*3XM^Mb&Xow@uIT_EnE=4$xDT*EnvWev z{kH9Db{w{;rr&ghu5_3d0Ky_Hh>8vsF#rSIi`j23V%bpdJds0NStascdtW31kskE1xsU#IgOh9U^YZww%ASV#6DJ@*N%Tn%kVl~N!WWxK zEUVL%cQcQQL+VwRz?={#=>qm0M)5~qpr@_aR9Sy>G_+Pj?Izd5%6r=NXYw%1BdH=}4LVhaG5 z^%hAUd9l!r)K2Vvab+b=78Zz_bgaxfUzzE-Z(MsYDL$TN1&d72NTU+ac5q5TLoD@Ez)Aax0WtObZ7{qngde4 z049EuoM>ertv`!dn+_krXM6XdrNc>FKKpHihQT;03C8$10R(b@g!UqmZl=B-eFUg| zCB?*&b~$had}z^tr#OdN95ukHk%TZ|>E2Gll;xIKm9nnNYoG@d<{{5)53s&J`B5{|l5qSf2Rslfg zD`2z_8CLufJb4%ok%Ci$=REZ?n(_+OW1Jo6yQ`NYAv|1V^;vJ>d))ldL{HNa|WPr-<+bRo59DvDWu$?zhX9m&wNX8ZbK-`wn0%$kBbIl4QMnuTt zZV-g;%}zLKmStzNFEv&kezteN*m><)e*>}WURhbR>nG^4HdzOHZoVJqWgywUFDD0m zg@q0x0V^=aB_-lp%a#i6MOts1yP+1(eZGlAf^r=g`A0<}<%-oJkw|l10Zu*lI;n^5i_$a*^*^uW{8;*$Kj;G(zaXJZoA!YcfX~tTi&L- zO*w7TkefKM9Vd<{j#(y|Ni11lF|#z1<~!#;nD=Jh%sheH-rvub^x(ex?z`uI51(o$ z00{Dx0N^W2|1uoF#ge=D+&BIM1q*W@JN>YxS@;d~ zbO|d$9kHTK?X5!GV3yKd?K|!_lKPyPnSrdtBwQ*g!i~~W;jN}#L)=vC;suCVG+$O? z!Zl}r#y7xW6_DoID8^wpZLrUV{6FqO)9nKFI|tGGKfiVrvWS~eviSJ;_`z3^|D7M_ zWcFi1`{UtHP}8hm$QCx667l;G@xx6@dIvY){)OxWrUN%`N+94Q3kUl9VcE2)cx?F+ z!O3uA5W1LOKpe>_GT_lQ3v~+ghdT9v?Dl2rk`OGx7BQvo_hlh)r0;%zdYCwzC z;)vN-7aS2fTNi93imYHbSE&6+9Ai_o?B z(>L{(^DelLpXjmm;nOSEvG43TohZg^zaakfbU}Eo6DIZG5yZ6*CBV1cxPifvQWs7j zE+QOHu3CXblP0M5+2}p@U&x_0k#TM9QYK|q9gIY|MUM4H!chRbg&x7 z3Oms|Ao1{BtnoeqfgpYXY-q-rX<`z?l@ORS?+ zUDWJ^#Hq#xO|a>#kl_?yQto;Q0OBLV@bHpVLfg+Sw*^Fm`mD5`n^ZtF8so>LV_L>| zQK5#FTWXkzkuyii&kQ0lsZ| z##j;sRv|e$Mm^4BdyPce+_DPY8sy5sV~O?eYiUEzh0A#5Xa9xuo7drVSvOuj)qsi? zi3^CQ-T$fCQTXiqXquBjA?}?j=^7OP2oJClhY0-eL>+!{wo&}9t|31Qey}+SJEn!> zG>K~evF{klKRto!>~pRGO|oNLB#Fr)7QmATp!3$^2^^G?ezNmVOU@;<-?%Af;DuBS zbN(!(ZCfjnfw-3dJv6h6mB!FfRw)#Kl6gu}047F8lKj5_d9>@_B=&D8JHM2?A|3N5 zPeV$4g2*D|JS5{J6&5#2FFCOZ%^ABBS2on*N`9U&KRQ>*2_;To4v7P-4Zm@>OrK1X zIHj1SixI=gLjnSH5ra~J6NfTT^$$>TEDmK(Jv4T+zWs~W(bMQ)Jz1glm8}~P9xRpc z5&+<<_*+;E0f2*rPSKiq|MXeix3RLz?xIDo5TQA9if)&H;Wduus^@7=`wc*Vxx5$G zt;Wjf(^RK4Ci0E$70vj>G|j>Wx0$MDh%PvGyq@dZRDrQm8+FV5ZV zL=REqg0v9K8xw>Of61vXGB^llO1nn|0Kx*KZRqW*E%@=tdenDH8>J6jG$zUq|FbO_ zvy=UC@OBaY`$#t0t7=gE&U@&pt}Kj#X3dCxwPJ5W7E z8;9S@m9TPpDo>_9rvr93*El;Lv0TouGEh>2t}E9tsF_z*=6;b_dG>1b)l@sGBf$IP zkz=@8a#wHFQ9zZ}eSCZ@)~{cQWy=;IGAcrR`?j_YT+hwNt$sVc{@Ew7X-d|p0YLvi zFN%m0o0Jeo*IRJCst2V_y_lL1gsF)EG)^0i<(J^~bJx())hqNh^_Q-q;>b~*7~oHv zWWtt*X~PazXUP&abA!Ey79E2Cl-TQm0rzGE$F}C^ID!D+%g+l_pyNY~KJjzoC^c39 zawbWsZj92HroN?Ep6hulRTbEL%#{ z80g;KuQ@0zKFpo+21Ep`bq!YhAtlMkB8Z;@V*EI12&b1je*vAvrK;JQubDP>48F2$ zGa@yat9khpRaN5;M?OVybuA1>#QlB$KQ;AA>%8?}%)+(TkWNdts=Rk^PBDeG6P!d&T{hf3d1cH@IZC@kH#(htwVukVOl*l~~i9{CrVHtG%mB$o~E$ zo6a1UPBO9$x6Ad)C{_fxe+AYhY&pVQ^$!6I&0)q`-&Wgc%4S5kBW-U@rn+s{{bd1@zX`pytFGUDe}+$O!!V zGmj%q=pP(oX4Bv?5(VBqe%iD+$v_-P;>6g^Yw+E_``oAkKt*!{zP0-ZB7y=jk+|$g z`pH}i&uc>mag|kdBpx`@=JAHYH69ChzANbgG-5zV#(2c7-QuVVpe+yXu30sUTPU}5 zZ*DZ8~;GZyT zZU+EmdZ;w2=;Z%m={Q0r`J&(UV=wOR^Ag;_Y7u>38QE!3R3Z!-{~%u|W=80EvaR#` zD({vOVZN<=g8|0ZlM)hx5X@Obu!mOE$AZ+5R<{ScO&V7)0uMxy`(p-rnTSEe(W0p$Q>Bn z_j2{NlWlv4-Sq~$3|lh4=$EY)WOMt^eM!)kbCR#&^CS8hdO;%iX`2w2jg659aiUTy zVvl2^9UiOXH1p~NCYQXUX1LVS>h1xjqUR`cev_=ByiFMBwCS=WfFFRj)T`h9kaxKD zpf)adJJQMTfJA9Aq0t`40EA#xvqVMq-&P?GeNZRG#JF@cA+ettP{c;7Q4>+s(c&W$ zdh_o|dY4=8u92G>Z?kOmmKkfdx!00qL{ehYWOo4d7e!+YQP=lcrnsE(E)>;TzTN!V zoY61MhKX7@`87CDqn)@EeujZ|OSMf%wYZ>Ap*yhD3ii_rgaEyXFC>Bve>Gjl-=I!` zM{Q1I(Ub6A$bHTCRSIAdZ#F9{BbvoQpTQMRsJ(_NevSlTGA{L@5e!&}B1?rQT`P$$ z|4W%gXWWi-bt#(2FRB|Yv?;}Ka;ru$r*gg)Ynl%#rOb%PyE>NRz_zKJ6)>IXl;ent ztJI|IWw}F7r?kBtrMg9P&*rlsuKQ(WizK60OFSflzo|o{zRr!_S@qFUyy>rm&XFE& zM+3f}{1xrijCs^(C*u#TpDY{p!XD>|%=+M$j@g&g z1>cq=v7}jSl}tOgIFbOx$9^Bn=6p}ybOgX$Efs4;IN(}!Yq}J>9j?ToZG_n#cmDWC z8i{bUhtI>nFPQGac(b)PA+Kr|LaFt@YrWt{WJlx=jwo*`8zh z^y=#9mSs|Nd|7l@Q4(0x--(m)GYEHitekSC?j#DCm7==jZJN_f5;d<$N7#opN2^WO z@e90Qlo;DZ&TxN1DYw9nxY{=clL0(2IpR2n3cY)L1VI0rE!5j{gfy$yT-LIhd&uVw z7wBO81=KlAa__Rl%golBaI3^U&_~5Ut$MI`?{CL>?#cr_tc}MJdZwnNHAT&RB-y!N z)Qn~DwTT;CJoa?C;J)5I&U1vB3DV}jnJ1>b@BmKv4fu{zd5@MJtIu{ z@*9}-m`Jbs_#TOl5(&%i>S1nmLPaMN{~S#;R&oP80sI>jwW$PlPMUJv$g1e-0_`{~ zi;)m*uS@!7SwI9ag8Dxj4P;4ymQhxa+8bS)$dwZ}!1o$`s5ypkyiSGbwfw{3#4T9mnt{no^4<`G7q4Kh( zt#%#k6;{GAbMf-SPe(}@<~1u>b(ns1{8LK=y}C;yCnPI$sHEF|!&7F_jhrbFm1T*_+S z>ic&j4*%PAAyw`Mf}8`<$|1&g79INTf-#_T1Qjqr0-oTnY#jUnSYU$y9te-r`a-4WF_OZRY3Ou(E8Q$rJe|6IJ}hg@Ri{wfkfI4wdJF z2SEj6cO+#fuZ|co-%5H>98uV8BTuxoqXU8$kPb7;^RJP_7{6JP^X1DGuF+g)xf=QkwRh! zW4G^tLW|NLXNTTTY+Ggew7Em7N1Em5r>ek{uEt8$t_y6fAJ0Qb1`zbLi%QzSbGvIiUq%!VsezhO{%hcB3FE*0WR87r< zl4H-mso2nylCj2tPi+&q_~Hyaw;uErDv|Ahyg^nb1IAsu5ow7(X*<6T_*wd=e*gV| zBHzgjBgZW0<8d#ZnjOwLiG)!m_BcBfM4~nt6kAZBo{lpah4jq|O~V1{6=lGf-fnMJ z+S8rWX420zt`nF;Thhup{?+%~Uqt74y-$*lgE^oT{gGe7b3*I&WmPCsOAGIrkD+u@ z2C%fbz~%f9yln!zY0!`($AS)wKNTdR zt-Ri`y`Yo%?}Ih*S;-IFEwFZGY#JPQm*ptwbB8V2ICtxKRAu?8MyqQ%K zlj4E<{Gs$OGYD1ne7K!6Gb&faAQ8&5yzjD*Nf-iEqwQgN?u(yWdu`8C6$z3s1%=^$ z2F$I8t>tj$R!f}e5sTl;xEzGk$rQed)kv33NDvJm)upNx6T_ZZ=IGbsW*$t;&!Ico zkFM!4eCkmUek8Etu=jWavc3zrogx2XHVEl3XjrX7hxqthNHDZFbs(>CNp1wTefQ%g#oWVzMFioSr- zQ3!Cqv&u892R_uWY)V))F-Kwg6olgB^;T+qGG=Gw`<(u#;xz=y|Y?{e3N#4O{H@;wDv9ui#h z27FQ?Y+&`jlP(Y8@}8y^y~Fbcl+D-a`!{_|SwrR*v$8oT`n z?_L509V^4i)va3s_#!3TbzP{^#=jm)TNKwtHIf<;-OoyZ6Fjg98HGdC3(iLT5AGsM zDD1_Dv-wS|CMqamnSVOz6oT3aMJYrrwU05B5Z zg!jkVizV>56#l^{TeJG+Rf{%+)xOBZOI)iG4G`yWQegFQsjx zGfJPs#nmC!AG@q(>+_HZ>i0@at3f@17lC5{LMr-#D&S;Da|6<;y+smv)zNlQ@QZ+8OXmN-xY71Y+ zXfM~?!o4mE7oF)XIUqyjEVv8(_Ru*k6SmkVB5LDvDs;$96nlFzC%4JM-U^StV`^v7 zMhsDv2Vi(v!RvwbAfGkqREMh>$XQ2Cw?6R19Z2(jz`L)6quJcH%ck~_8Z-CW@1Ok8c+VV{ zV!rUgwI|WdRFD~EjmSTXthedtuxYB(ZqJ+%%KzXEyt^?sIqCjqUGrU|Hct)+OoUAt zOW+NqS@b(k6iTO|_Tq5w!xqEhHvF*UT@M&Kg`i}uL8QddV`!1b<@lDaM2~?-){T~u|<-@_$`nB|KE3$LiT5k4cn z*QliyX5aU2k_L3P6P45aruPbHxI}l&_ySc{4G7rJNWc~q6?W9(j4fGAC7kef@C5w2 zMc^iP`Umd8R{QqkNJ0VxBUH`fInmfd^9>GeB4eHaU9~ zoR9c&xUH7eoUOng0$;|YJh#>BR*J>PtmnCWloetMTwYB*qk7sr2nouOJL=ZMUXmy< zX2y-VSQMvtYQ5nDdALYZY20K*C(;h8wimsaON)rf)cJir)>Q<(weh6pt1-bldka|1sE4#f~&c#wl7L_{S3gyehf}iW7r}iVcJ`x^2$G&wNe5N+7(vvyFb$= zZtTa=@6N7-o!Qv;tzpFF9X*kx4e62V1|%h2tv;cJo61#pQMy*EjRc^SJ2SOxgD~b!*xn(wI*&Uc4X0ZPb8uH=gs`n{#;#7cNFPY@ z>(>J7xREduV;T`-_guTz?7fFc{{~_|I}$$o1SA{yyP@7(+KEc1S{eJrTfK@@yzRmI zC@6oiFFBdRHb;=m$p~v&cW9$5)%}Fq%7sr{7l?xG0YNhUq90H+5@mF;T>zZ{D~nji zn-ot!7F@UEkpZPBdLKHPZ7HQ$-#|MNIpY;fF9Lg&~z4WH1#!RTA3Pc!m%LP^t={ z$y6=VY4?72|5$x!*o?AgF~BQm4%5`givseww6yE4hB9&JwTj#ZyZZ&^_X&K8l&Um_ zvck>#admB@G%(yBeW})6h{dY7;M?pzK#)$IUM9uJ!g>iUY0?8%jjhH*(tV7=St*aEZ;pDst-D zb#hU7^yeGL?)2t{x252pXzBUUO6>SuhG)3P!^kviqLVL+eO?PkD2?BQpQE$NR7pZJ z1D8@*jl=9kRSRjmEq(^@MSRGz`lPHLd3=!&p-(*@?~gnofAtK(EPv_qk($f?sQb%$ zDAuBy_x`&ToWDm_uX#pc?&~R(8i&W7xB0|f84(+ayxaEnQwp!(h+>E|J}o?Lt`rNC z?80>iShnBzDs!*3K)iDuCT*@Vd<}PLMzi?}wdHF+4u{#@fh%xLnN4yDj=rn>2rSZLYP3)$AuHt7VnO+6?I+O=c)$Nhs*G zHG6uU>fn#}d@Ji)u$nfT5Xs!e+4TIQ8B#~@@KeoD!yWyc^EgV9l@3$L3yi%e2^lfg z%9agsu8QYs3Rl_*&3%9Jv21nM5$va^-&k)4%}gs3tK^NcM17Qf`Ai2@V7dOlW}cc8 zGnQqO-x$Z)xuE&GUb+!F^KkRwtELdax9ivGPdKcx?$2erVj+%MA?MW(CFQ;4SB=5N=;yg5$*geYUvIP4OFja;eu|g9x_O_HDtBvNI&AV#__d zRPecH<*)s!twXK17%ycz7MR!ixN|ud_7~CO!x=lg89)GKKV^|kFy0O6{Ci|QAk@wh z)etwH`Y%a*pIA6?AqCp{+I7aKniik}a1Q5q&43vbEAa9fe8L))9f(RR^4W;C3Awf* zZ`W^sS@@y<4s4yFBTZb~cf{{iY;B3h&kC(%EvcSrG@%N`M`@G&1NOnHdtdYjeiT}B z%1E(LP45AKSAoKG=D)<-`HH2zvtc%i?o=k^r_`E3bmQQfPYV_LJp)VP&ttXtSKHig zcr3A8KqE03A8_j;b^8ycnCCiTwD0ov@%K`X1yonR-S@+msa7Dnug~)3mH<9G#h4Ln zs})BL4;aWD?Qd~-*wP8sM(&m#?=0~NyDF?jD@b>_5X}$Ml#!6hKhV>SLkzO_-cvVL zWLlKkREp|0`=bLl3PQ#D{Bt%`y5M+QYNQmUQKl5+6^D8!M98n_r|QcVijA4`y0CVW zh;d@@7b@|LO1uLAzvR4oz2tt19x{XWKn2Uxb4RdjEJ1VzJ4$ubK@ST@Zx_;G893wG zVqEOIn9B9rKrw%S+E_^s|M|f@^FYl|`lTCn#;ihwY*ixtCRG%XI^AD=POorH5UsaA z{=G}1wy(w`>Sb+E_&4OOfWS9Oel~{NwE6=f-X4qv<~sU(t!s3a>YHiwO6*pNSdTyW zROBlD#k4Bwy~|Csp?Y9y3h+vTo+dIy?Cy1hp{s}0bk7sbZG z#3lW#?5DLAE@@b+)>EH(d+}2q)zfr|QlQZ?r{ekR5*fq|w0yBCKq=4pW;E^w0Ej(g66hi0ig^YFbq&U)E*KUJg`?Ho9OPhHag_#dn6D7M>ud-N|{Pd zPS%BmC~}FF15?5hl+PYp+{$=1+stuB7$5;P zVxW^bD`Pk;-~*<>dj>Vy-707Qrm^I6N)!Xfn4t25?N%USV1Ud{xo-;s$@FPtgr(&}GFSI+*xYH7ZKv^KP}O!kB3H6wH2b86nl0|M2f`e{ZM59&*7b`Hm3- zO42zIJwq51H^x1ev)Jepv&D0D9SpARc+RC9%e zK9O!L{>8hB#LpeLa8T0nLNetLHp84e#!}@XT6Q&pW(nL8oEU6h@_wvw69=mICTz^5 z?h8QnDajY1Nmt_KQ!3nm_P6$ef_gCUy+XV_&SUB=mh0BTUCL;s#*52+{fk(1ZV-;X zZXg=Sux=@!$iy!@yO`$%>DZZBT2Op+$vBSk-asdAtr%_Ee%|#7b=iR*R|E_!Vp$%& z!a~$nx0YSet(CqC|{DwDXPt>+o;r zI5DIYy>sTa{^54Bb1##}5&(m!&8aIjgQ|vbei1*bm(u#g?-bS2ci!Le>!$s#(H86% z0^Xk%@u^V*4;TxV znBLukEPb)>{G8>rqP(|^EVLbM`r(iY-7Bv}#;kPbfJIVsf4Ad1uxVAw=SH{}7AIvq znuhLP_W1 zGZtY1$VjNTw|oL#=*HvKWu~AE?5kxH5*bg)-4sl&%1Q>M=M#mIWp%hlAejJ2L4HUpou#;p9 zV{%~`d1SHDZ^OPnDsG7g9x^Wzum^~c-8Q+|RJktWE=BKu9wGb$N-y^B0u&X0apx!K z61BQwy(Fr*x&i6_>6hg-KRR-E-`Hf%J4YA3>$w(zdL$PFsPc!AkPEStLi5tr->>$s!jB3UA=F5o~=Nl_jc5EAk( z1z><8!~@l>?@_eCV}oRaAygS5%Z-DcJZ_QFj3&TkJ_Z9@dd}d5F}?9M|0`k)>W_f< zj&G?T$#O9T*PS%82mD4DV4nBZ!>x0EidjS(=xmI5fW~@rDmn9Us@(4KOdm)&)|y~O z8Y|yBlg&d?K4Alv%BZz;i;%b8p z>Y|5%NXJ5wfYkGUz}-Rx7T|k^;LZ-qF#VYg&~*nx!ni1$j(itzRSIFj#0ca--jo2~ z`x9hX0s}-NuBV@wqHi8Nqi-f+f;e~|BM@=8%fra38`M7vLSwM5K$+Qjvj)xQ2~=+> z!Y(Cy=@ER2nYtO#)9+Gp^#SVi72&yjv~C1Q zF`R;Qa}xx?cFx2Cl3?a6R`h^cBi^9bS3LyUcSYG)*+upA7z{KF2~AgeEPqH@cr9{_ zfX&tzeA-f&M60R^Gb{W;I{S$))n!M5$5(B>n zz&eHC^_lTqCP1cQM^H>7l;0y39H9#!mL{8dA=FO?6`(7DEQwOx0_P(eo5ufsb3CUuC)0yEB$)iLke8*Gfz!#@T~O0c_A z&=y~Ox{3HH5VyqLxzHzF9Mv1K(&77Upk7v9y0_tPrDTZl=M*IUv?)z>3$xF!q}W)| zmxrv0Gcd4KkAr5T64>%@sqny>6BzU!ZYgFiCw^lH8GLNH(MHksfrq;)l6c(CWZ1sE zoMqK*_9xo#cVT%-N}^_2eMSfH+*%ojKU}P{!vcVtU&?j(Z<9 zE6!!{vO3di(dUhjaD`v@D}=rO&u>cebz3pn;gA5!@Lr@rV-apA{)PZ?fV`jSE*lR& z#zCMFPwT&k65I2Wi{Q;k@{oZL3P>Z0UY}Xf-IqkwQgcuz?v+pD#!Z2vP_7;5nP`^1b38ZDhzY+Cc+&l_ zz7#W^!ME1eg>)sQ)uFu`@W7+r(u-8Z1I@27H`4xm=5?uYh+mhH_l2yALbrU3W=+4H zm^1m1SSoZP4y#z_)?5|GkPZjocb%-6a*A|$2gn^Gc>*6M3_fg?NyxKj*$Y_rtM)SG zM3G|$F81~VU!?xieDPR<5tE?4#2uTbwL+&)ew zjJ$sy=;nlJ_Wpqg9E|7F&`G*5!2l6}479-j$c=|z?{o@;vX}b5iWsc6lA7RxaMCn-|IKhc1Ofu=Q?95Av(c8;mzdk z^Bfsbz@p_TT!61ew4QV`)<@EyO5qkb18?Wx5+AmeH$wM-y9^~TkmFQZNfrU4gcu%! z-@*Q%uB;to(E3Dpf6D)(xf$IlyEwki493`8*5yN}gv#3j7~pAb*#H2J2`BqRs(5xF zni65tw~e(@jVdlFkfR~voH8r?$Y!O%_zRQnj_V5Ew*-iul*1YmzOhIqtrum7&fy}P z)b6xG9m8?Nvhg_y=YnG_Uxo6DGlK#Bdn4EDz4*=5;dLnGq`1G=(%r%zlsBjInUz8& zQuJ$#d*~#{<>l&kW}}``xdPLE8nA6DiYe%l!D{q0eXf5sg_S_5dnJuXk^WX2SJovQ zu!Ys8QJl(!z5U?%PG9@}qv$l}`Gd6XlXs|9THn{Vmeyu?Vb50u9_K4OKV|pqp9Pjw zh>rt8jarVG=VW}&{|tO02TVUc+>tHo_4vjZSZV^B`NEY8(;@YVW!kOJ5ayzmhJMbI zjygB0{pgAK*6u9QO)geMOt(k>zZZ~V#8R`U^pv=4ejF@aG!2~~@9J>T_^|}Mg0w>4kj_AST6&ddpgt~v5n|Q3{s9|~r18*W3)%ORRaitstj&Ty zUnXARfn`1G*c^$y2p4Ld%n`WGnA+2G&1OWRrsJp|nrm3?_rx|s3hRwb*y{JZDY6!5 z{-dqwh|<#7Mww6J^}~H$WqoLS07fB`x76&*RSVhXYf_fykGt>w#`-V?l&o(N zl9)owYt`hEAAwW(1x(;YY948^EvPdW4ye13Zjt#okUKNZv3Mbf51C%n+Ko6~glM6&!EWtc=F%merM zEo$F*An_lz;*wcYZvES}u)~_ps;;3a5$1F}HYN@>WUvu&%MnMUmk67bTHw^%+pf{K z2=;=QCnhe|0PhZKH2GUpEMnh+Q0>P66J-R)4b6byB&wA6w&nL2`IWnXsxU(XpVCc0 z3*=k)$ozJ5=aHZ@o|E1xQBG+XeFvD3ty059doA|0p-;j9nj9AlfC#T)+6VEOA7}u) zpO>A$x)4$1x-XfW2eNDtjE1(aDQtVYAIg^`9JllTa+-i6M3%>y2InjIK#?ewaldm& z3Ktf&euzS{tSO!WM(8J`D?1Vr%SK-qyW6P`7reBO;y43QdAYF1ak)%tAVSP_|6q8m z0Q;hu_(u{k7J=gzU)X%fK1oCcey*9T4cm40FGFez+&hc^GCiLQlLk9A1+;E;@t5f%BSt!UP>V}Lt)1eh#esZmAh4X69c zcFvia$$)V*;)zQa$|-nHF!_;TI$(xZnNXSux~1XR8TV z9q?XWeDxyqo?H6dI!&{qWyLq8rXwQXdaP{ZhCZS( zHyWIFw5+V&4GfFWxTbZu$$evQf4*nVYSx$CrVR^^(zfqDV%$kUz&gz;oM8k!w}|U@ zYEAuj2Hd0I0eEQXUdqj9PmBfd+?nlb!$Vp(&ZwK3ToJiHf2&1g+hoA7!``Zwh~uX8 zwL3XH@2^mS%Cwf{{OHT~U$yW%Bde>TITBj*KdgmI@s-+4DQPoX1)8D%fbpH5NT+zS z^6)o*NWT=%i)#_XgAcAN7GvSR41uNOVU+4^fqr62dTJ@>y?V{IaHRg2u`|b98*$1vgSEu9rF#)*n`!^IQm+?@l*{JNlZBAuAyd*PFM2uJ{@5 zd9@HCfah_8ZX@HZmS+KtFwRSq=`kZz&{W|Fp7Gu2ryvx?ni*s-1E*WI$(}|}CTnGr z>h@qgyQP&_Bw>y(V)VDkj+*Rarxw+vOYU`*c1~_E9y!5Ew%;iHXUaM4GV5`(vg0LdyB%F%!`!$FVOS7oxcv^xChpXiNB&d-#7NEz<}1q ziv$0&75fmzEe0P5a{nC+xjCQ#6q{gB`fatssI_O+g%#YE^Y7V`X@SiK2bmPTy?*3B zVw9)L^IUpfwuSu*%(+}2Co1(K9O+ov^XcK1=r#vah+x4BVkGTvpqrzTCZ{UY6Y3n@ zCMgJ(#pjw4-hG6n*#R%udN{!>_}@`_@i+!m-LXj7W=|r^d%>0i4=y-N7Jtw#n0L5z z3l`M)NUdjcyTl)$GmeaRfxEsTJCZ+LAdXq??S~7p{_`x#I)-Vo@-?X?ZgMHr*mebg z^=O4<1sFKhXaD>+4i-=5h8=rcRc zC#TGjt1a4GJOkIcdb8kS(^xEMakFHWPp-#n7pN%of*|6$W$_3}jJhvdxB#27FZM#gWqf0t zFGwUK!JpEO{hQ;cnX{q_onOm(j=t6|u`2XFn?5TB*Oz*a7ODmPDrFgd1VW8?Tw8TC z07Tx*AY!0-1jiD=KTR(9727F-bdD_*FkJr#H#&h|cI)KWgPN}|7Z`x-YwCOb^Ye3F zWrM*Bw6FMAu3e%36)H1YF6lyo_SSA|$d7OcnFhSHm9-uZSjt@{GPd^xDIHb_2dmrbA*59}Z}@3>RH&IU0oEa^K6k*)otll(`K|B($%2vE=9<%7`E6O;!nWn(?sq{`tQ@DzxkD6cupNe zK;FFn0eVL5grSIvHof^c>MuL3C`h0++x|HlTT^_JP!ANpgi|I zNSC26u7Dx{Yd23VZytwf!nako*24`19f)1%l6heTvMiIj@>(kr8WZHV#C9j(c)}l5 zj0+PI2v`Jme-YjWPm5Y?r{2skNN9;y;3wvcZo7Cha4m$2!BbJv>N5IDOWQh;To_2J zTwgXcxNS1~)p}>7GJ^+7eCiur7;;7Okhqw4KLwM){8SOM)+-NRsWWXby6&=>S1r{AY4uQ_}~t-h9qkwyu@k2U0yZ@(C@0 za$fkLh$JZ1^%@Ql1LFfZn=-(ge@LdP2;tR_OSjP%hvh;by!EFL z>af9r@E5Sv$pSL@B{8Gvt#4GRRDs$y^JAAoZ!RhzxaLPtg;orQxBEP2ZeuIbQPyhGYBMccY=Gt4q81ti9c@t+UeVA2wwxpkO5S zn7%V$Jhk1VS!0}!`B4CLP-PnMuh$X;*-1O4S)}zsnx7eFRw}KTau(8^V_mLXGnaq!4RC(FzUOz8XDyeA1+h#J2 zCO0)D(5=?OP}G_dEdJ@!DGGfnb>qyj8a zenEyC-&tSp{h_A`5YQUcfSEcszZ_dKOsG5F6qtxj`y}6W{@^HmuC%@twoD-VO}aIc z(}Hl`Rx?6crAA7ZmD!zL7r4BQ{8NTxpPZbSYDi?8O;TK1(MRUrfWvEcM}Jz~ZJr8= zW>@(wP=y>JgU`FIC_DWA2k4xii8~+He_Di5{zL=gQ`c6B;TDFGU;0Z-a5RFsM&A<~ zE8Rq|;$g8hyJ&!0zbUZhRdQ}tWt9MEueW3BX9E;*oaXUL=|6kjK9Q_aR^*rb*JrX| zixwV(IPkPI!^%v7onW*Tj)?xdJvaola>Uj~?B#kDv4CtgIS+gP>+k8Z;NV1T18um3 z+M`$`p^O|NOlj_KCYbz)b8DsjL;;UD$kHLrYgUqa z9mJ#k6h|h?3Dtf?qRHTTS`vr=D93CIBY**Y=?R*6kRm{BneVZfU3$HMi zJhtU}m-D>(ghh)IeBfhuUXj04A?SmY5~fh>cG&3Dw;JH-h}PfVCso6NQ#SWmV&u=S z)nRL0=JqItzCF=z7ZD_PcOR*{8z=;Y(05d(S$W+Uza%Qd5)_X!m59zVkLE_Y#8uow zS@)tQ(@A>HFu^dPOR?Fml+x`FD7P+VS7;`cNe>^;Vbx-D=sOg5E zQuhh}{;9x1k=gOv=FjGgMu=I|7LlQ1m=iV7Ih@4|5B!BiwZv<)j}I;ub_KG<#gEzM zmE}Dn0LY?s>VF?8097*Ks9^<#C@H?*p;HC_?t^U-Nb#9kwx1$GBA4wK?dl<#|FuS1 zXSJ$8g! zn^uIi%N2K!83zZ)OEL0IaHdKe+)&iHQyyJlV)yu#RR|Hv9_rfGhV@U$uUZgkpwa?| z+w@aE)swk6qdE|94c)EFFlA*Fx{@Z&J6qvu!&jz9JCM!s8nHW6lGu+3$7-x3DHVi} z-S>1*^YRO@1D;-W2HUd3^b3YE*IUxE^lv zs`5czcQKav4rAYq@W1?)q@ktRWM>ih!FyvtDK(^h+B=3Cch``%@|ulKkgXESIX7=~ z;Go}gX43!*%wsLC9o6P`SoCZkd6 zJY?QCY>vn*Y1fdk^~aJY5sv!|hM;3tKSc*+uinY9jJ0^ED&~lFInO+K$ z|Ki1W)l!2@njPEgcxiwmjV3DK6Y8uCI}ugq~|gw^w8@?pr54Qx%XfaBO|PypBdjNK^p|5r<3? zhrbW%NQBq)4t_VO__9we)Ol=b%P~2h5KZo9eT~e)A;tUgn*rbG--*5loV zMKQFr@#OX^DkLN6&0ixcaa|M>c5sDO8u9MFeZ2I3BNAcEh6JY_q`+ao&vz}1$&Dhj z-*trzg>Q#+hl3L;JD@b0j}ME%1&1`d*(wy?G~fwbM4s#eahmeCf*UjA!b;i#)8^~!ZDD(O1R=0hx^ILMT>|*bj5J-Dh(eFEF=A67i94RwVB&? z`i6aA5wn>qwrvSb_cnJF93-8;Qwp?oUXJ?XRf?Va%KNNJtR63!6kV>9txI&AI&Vmt zFdjD)v<44Q@1Ytp8=n3h3m+xK=;?i+bq{db>n3Y2L5~X#vf@F&xx{O|=4KBDNR6?` zC4RPKi$Rnq{m-z(+cA)l#AKCmMI#Qsb^pTE?lHcR(>Fl{)-TL0vZ1Vs)%Khy6}pMS zUx&l2fB(=({UuJuVere}CPgO9 z)D;U7!Pc91&<;f)TZ%qBlxpCMn1Tgb!sP1?7F)e}p9R)m{$0R^(T+bq76_3Oc$IUx zx=UYlyQWqdl1|T8x=dy-S6Zxe+&ho}RXB#|w%GP)`>u3)bv_u9P{HxX29_E&m1BW8rNx$if+dh86Q>Ed0zTjE>S?K z4Ly_PKRERN{7q{P4 zo_((Xz~JKJR36$xm(B;>vDM7pvOF&wc9Lnwk0QeN_j7SC^(NZ=|p9Ld3_cUyH=Wi*#A4T>!v?$Dj@XBvW7yy1V*hZ$Q^?(BIyU+K=|3uc2N&92gUg ztQVg_0Lh8EZ>0pfSoOg#UYiUyrUAgm>alD0ia}Sx50ka{hIk%f2Lh^1bc&{7qPn&!q2_93Cn(_+cEi_*X^rqcakoql(rx z94agpVu3c36mLxFV^i_s7oNfNnNw6zz_e}O>459ymLcu_%6M;Hx{6nS{E7wutZ2<3 z0GPKHowu%_>B?pF%N%$_#yF&J+k%jU1Wg}91psBNyu%X*(AC*1IRhEE0}uA}pl0uG z^wv89bo?X2k@eYU1rTVjRg{2YVTn!Jc@=vOttk8O2x`t;bPE6$VFmDYTUpk4=hu_I zBHweF>Ifowky?v>7k>FBLT}A*Hlxi62oE`093_QiIPqyVF6CSoG4`GaU-G`Q3RB&* zgm{dh9e)h5!JJ^_el}N*#cp_JsBI`diA?nDD{vscP`0P>06o<4N8^%%Q;x&Z(`T1*od0AgeGQkj+mP`Lniyt?Zs z%Y+r+qN;G@W)=Y4vHc1R@pxE?7aYOfdeL$uUZ6pmZ13{#Xov!4uVV#YO-&t6A3u+? zr*lwURjck4?)nVm3dh9S&nHnWH9Q=#A;Chsf4|yjm@iFDkQo_WZX6_*bFT`Y7MBX| zL2ct~Lr*{V2-a*|EqQAWQTF%D;tx&1C~*J;0RR0n5gsg#5dgF)06>3tSCpag)G-l2 z#4UW>IAlKZFao0@M+g8sQN1<+07_J#^9Nu6s3rjDa|VEyo<%@xjP6>6&@6IUY3Z1G z01$ovr!MGBL zp@476IfwSVTViwc3k^lq6ORcX5UjSh!FvLLep^2}TYE%skWuDc&S6&b;RoogapVMG z0LXgb83e|~>19>f{3nS3jx{NW_u z`#Qx-j8+?#5%e#lXy7R;YHY&3+k3+&9_H?4 z3;=*xe+B>%6lAx%^uRgp>yI2nciCMv0}fX+8T-gX2+PcXV)K)TO4)U#8gz=yT({G@ z-||rTi4qIo@apmo0D6|437lPXLxo~593cb%oM+GKu6Dh}{h~H)#T*53KuiJ6FPrra zd~_7q#0jzYp1X)V?w2+9?65PL-JD}$5KeRDYaLx`GwqNxg2xWm=h2K_fZ6{OC3kVA ztU~7`#A{(}MjHO^+h4|*G%4KH6LEVwZ~Tcg3PyMO1v|v9fBwW7yz}boB55qQK_6eV zWX(d|oHZ&Up!`$U^uq7IsuNS#62PWFjtejX z0DHd;&F9bRoPpRiF>dh!B&}Kwizebt0RdG9;LHU$#$h;%RmZbYb?h|youUEt0O0Bh ztfbiD9Y2DIp6&Ni(hWZ~3y|AI=7kd&sXo9=AKV!IIV|@e5r5A4t0L)!yT)#~?5wk3 zOp4I#$2#T68x06B_4a>uj^A7l&U8@Q-hmH^3n*=F(VgSmf}eTuaXheorQisLV!qRz zHuB5Yg%!KMr_(I6zavoIfxr%nicfVh>@GI4Ie$9Cu= zlq`xjpjG7nTmZn`ccdAqIeQV6M^2!>!;yrP^8x&m8vx*bS*sfuN`xO9PHcWCf+K=O zI&F)=j(=Z4z{`c6`e4)Er3=@vZ}&lz7TMXg?KrUO1Drf`RLvSa5EzVxX-m;OVU7*}_@>U1LNs4IgZ{QQL`|NEjP2Xu8yu{T z)p_i?xika-HU)O|p}Sqq*{+OEvl?XjGn5+05PsmT~06OBNP+0yhodTkbuAnE-)&oRjWVp_qn`l8p0AN?(F17^p4`^P<0Rpz>CRFcz9|N6^ zOg+IVNf`g!Gll?Q@g@dnp091qxASm!-y!riIU|90swG1ZxRGJB=^M8GkE{qk5FIRU?}hNJ)yMg&reCltmH&t-m`jm!Qsl& zhWC!|moKID@9Sm| z@)%S{pzr_AMWw+O05%2kPrW;^^hbYlGpYmtbf~9-i3QDk?rBjVQ}-yD*rno?4lckb zh{pMgca&A4WS47J;D6e_9+`=8w95w~A|VFhagjpNr)u@xfQxBQLCpzoOL8>C0WqgU z{KuL2-}z9O`;3U6W&O;UD9lVuz~uNiDLBW>vrRPva2pMRcSGo-BNB}4hWd_9ynf|6 z>N~r1$7j!*L1MtyMB-L$8%|C@*K-#Aai{z0s%r4-AH0m}N=GXE?&w5Ru6~R}fe>R5 z>9?Uh?>1U4pGV|`2}oPF4guj|9+ZJz0AN4_1@#J_0O1m>9Wvc(YiU9C2fH!Q?nu_j z>A^Fec>;dn;jW*->dFPUEhwou+}G5C!Z&xJo#Zv8F#vq$=`EO+nJjGi;YkSyB-z); z&x_}t1?JgykM|9Im-0qX?A&wq)J44e_6MlGSK~tb{8}8LH#0F2i^e1)CL|a>CgO0- z(~H5pjfBM?3DFNrZ{odYBiih?*>JSD6z6E8(OLwiPM?IYfBQ>_iFJ4ej$TG!i|eJD zKWd2ZU-`}t(NyoqgxwvRjEdEdW6(d)P=w$koKUps{Amofw;*l91}RKfQI0$B{+eSN z0B{`T>Oh?w6x7}41OU?gtZ=A1^bvY%Yt_R6B!{MP#?mpVaNcs&fFK0~eB?wNUbf_Z zLgxI}{)G0@a`jYrZ~%Vt#fLF7D+PhX`Ul6x!#But;ZN;};cx-Q=Z7f{I2{m)OmFAo z&ELO^qJmNvnP2$r6PrJWM67v9NeB=0H%-{)uG5-rN7%0+Q#Ulr!Dzyox5iek!p0`N zef6f!J1`?N9bfvp&mm*{Sn;>l-QCT3<8u~|_f=Qi!~g!r_tDzy$ZRbD;DIMF=o?`C z{=$J^5Zx7bg+3sD;X)+LodaK`UZ+O@_}=fFycO+2``^Qs09|@8N8`eV&F9ac{myMQ zF^CVz;t3>s#4lQ?7rIqTfFuSu6oOW-TQXZ2@_xS)ZJOGEVZr|R(ce6XMN>0`{2v${ z2cN(o=Ud(O>FNA%^#LC5b$8w(>04^6>+#lWyKp}Hl4|zRHm-!UWLz5N5{DJ)=Rc$b z97EYL&Gc(lPiJbc_wp^wzR8d-Ga%Bc_71#r{g%ikq%_VU_`(;T!Tg1@rQ1fr`Wv2i zpG&Zc0pQ=iCsKnc%?tqWQLZl3dOe3WS36RdFGEmlw8Ry=k^jYC0sx#Qk4=5OT{aOE zG$3c=(e}ah?K<*v(RlKh8mPnGNKrGVW6ajgGV7sziniFJ%mFB=vpjsX!QNg1fVXu3 z5FFrxZ$7yK4=tOEppXy*M8~>t0Gd~YyAwkO0T>a<2y_C}I8E2yUHh^BgTun~=iJz& zH#apI%hS^k&RKYdP5hqqEkoicJj}sRl!k8YG9$A#nz~cFmO174(V`NZEvryPukeU4 zJn`%!*sx{I$aa3W=Z$4^{x@gqy;YAI1AwxV%m4S*R-^6q6(lZN zjL3{M__!zoomPe+0I(&XTTTyVld}WqI0RY8!)nopCz>XCpqdmHjK2$gYqT(EOPp_Zeabk4z0mfIGS*#4Q zxpxZi^Pjwm+L}6-U4})Z$q8{-lQ|A?K|%VQ3SOF5;l$+b>s=>c@yZo=9rFm2jp)ay zSFl+$zw3W-H0E|MR8(T`oqQDl*l*}-=v z-|Pn5k(`O@CEH{GaP3>G!4aEt!5xIe#UgtAIQWMs+_5p}H~>I9n{>p+K|$?3B2AbJ z08s0xC_~N1`}6=XWirwqd021&+B?+TfQnCm!T~6Y+RX|u0stTD02WP&!}q`VG@_%U zi35m(Ur_LncaC8v?i>YifLnWOJAVDjACYtZickVNw^-tCHe_XB0~2eOA$M58bV_u<$M`t06;UR zoEVfX0Sp9EJq-P2Jr(7sIY0oQ3Dk+0I00!7KLo4DQKkg|IJf}W0-y~L@&o|+f7prE zqEby?1DKK)jGuq=bBK$HmPLS2k3cdUtAK~@MrMGP7-cM-bP@b>_fOP-?@$t^1gOWj3 zH3Rx^T5ipvF!-(v00nQniu0LG^T;5Xm?BI0A60KiQ@qb>?4=e_Jm?(VOu zsK%?md;>SG-F7kg`3PHoG&W7h6ooa0G9Kv~@09NKokx@KEuNKv-hB>+&RwY&+BH9& zde9zf@9V|B+Xc8*<%n?Iwqp~X|J>8ME=P^{orqESwX?kgKmX2;P+nZBu8aPlFqA*= z1o|Rk^>6PIsqZv11R&Ny8-YNCs96DvI{^6Z?+kMmu=!5}1$9f70C7y?65P*r$1^9< zS>h-Y<`))*?`rJy)(VwckX#aUhs?E3_}cJ38nz0NH%C=eSbj2CIT ze5_^{zk$?0RKho-+%v;Pm?8LK>Jz*-M<0f?@22(Bj`>k;0nW(gX7&Jl=&>z$>e)xt zYdjJEkbprw;2OQy(b|Te{pSx*`Tx874!}5yv+d{Zbf?~XFP3dtw&jW|?!AIBwjrhk zNTUP-NeF}^~xk$2l@8$k^XYclQZ_Dk;Hc7rogr(it z+1c5BpLzS6=Q4Y@1cu=1nD3z_C|qYixAk-C2HIQU$B3UC<}5q`j1oW?0DNSZy7`Ld z$;Gg~*5mw>;>_y+sEGVp>)gq(y|P`u7{sJ9JnNVr)Dm)^&{VO&$=% zTQgzDn~6IFtvr2>=Lw)jc>#X(^rOh^+DX~n)9x-gsDI8)2f#S)+~X&);GZ9%yrfiI z+q&2k6b_n(R@&sW22}un>o=h~HKn$<$!lnO0sw9aXl~^I(9+Z@2LNGis6KHFr33)d zXsTg%B6ieBbC6l~gog6(@GNkQ5WKb(ue=ot6} zg{a5B-!vO+{95(vO7eDSYT2W4F~{MFfntR!{4MwuWUT~!jp^>P`b4n-Tggt2J+dHzs<4*i?Czu zM$rO5O24x1gHfI}0PR*^^?}`D1KfWj`m$Or2ng}xH7wo7Z~=hxjAUM|5=Ef9OR$Ln zMosQ1?hMr4>aqkx_V0)IF{2&TN>sQ26C4gfk{khMlPdAq+uKmIb04m6+$Kp1!T`Wh zjaj|3@#K#mL~u+jtid7rc>({eKp^} zd?Xd(_jbNIJHJOAill=o@vB~|t?1R3`%U_N3^ij{I&}cs9RNVVK+nJQQyv*8YkI`( z>Ad2coE;}q@VvkL14s8A5YxR;MWFmU??PQdCeI6~xBJUSmHf?qCHdb!zy@FThK5@ z0Kn{U4_0|L_F_s89uaZ^h!IAk(kJLufQ;-=_V4CztGkIDgt=--Wf;Z{>;gM8T zhrD@tfWFOE_MI0IBA?KkOKg15Fh>NZ#*HW zvr#6X>mz2NJ|;!`=BmL#@?*|KxTFm9@o~$aIqggz%B8Qr7kpz~aYp6}Kw0$SL&z3kLk?998$Q-sf$Jsnf-p1|a1xy;-l;@3Q9 z63j3qby`nP`YklJ%92t1b?@y%k5MtN^YIw7OoYT@L{0yuF<# z2cZ;Us%gU6`BDY|)u)cTZpIcZ_3pb6nw{;qhnqu?;}^488W*501`q&Lp1pueif)pWda1{QhP57c*#@bI4f`1Z2}C@(G*kJZJcqp1IQG>1eOV*f?Oo=FMI zqzv@+CuN{7-*lb*1pv@oUptzcT6umzatS6ta6eBXK=sL^uA8wPEamRI5!PJ^0K(*i zf4L{11#(@0I{+}isbO;2g)hHBbComqfCB&m{V=F+4rV@dFQQY^WVO+>Uo~zy2pIV+ zo12z)9M|Jr6B{25CQyKz9mQ#n(HK05*sa)iF_m+<5I%)EFjmZGv>+JSk?({}L z*~mE3y^JCOzd4bM^QC1-PEEqAZ@+-BaEICLW_Es+d&%Y`0hUz@zs0(5mW!Ey>3ngo z5va)O54**xvHMG&&D|@|jqBruZf!pB53+G_K(ri)0HCq3wDS`H5D*Bl>hhVC?cR>+ zV~4rIjt{{II&soOMD*ß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 literal 0 HcmV?d00001 diff --git a/res/MikuShoot.png b/res/MikuShoot.png new file mode 100644 index 0000000000000000000000000000000000000000..259616a7742ea4e0b23c3045474cd9c08562d805 GIT binary patch literal 70959 zcmV)uK$gFWP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D|D{PpK~#8N?0p4* zAI0_mJNLUJmy5d-AwmRqcXtX@pp;TqDzyF4(o&;9p;T!LEl}Lu-6e#Cxa;MTbHD%l zyqVdZ-S6yv*E-fq4rj?dD?5v_v$H8X2X{7OwU{fWT@(MSA+hLeYo}EYJV_g0dY!1N zOPi*PF8b#`ucvd*Jw@wN$7PpYM%Q0|z1AsIS65TNe*Lu0$B%#fYx>cTeyw#u9JY=BoiyK?|=%Sze z-?!)o-~X!Cr-quE8rpyV{b~OE`J!)aZM7S^hs!Vj8C`W%P#78Zy+P5Q3SZi~9Dfpsm#lwLS=|Evcp_%KyQjf@vERT`^DN zzJsRIwvC&$&PP^mF8AKPrgc6f&$S>!&n-KLdvVg6LoaS83%LK)fZhRDpH&Y$K^tCp zmAbgclP<2g=EwBqFMm$!Qp3IX-b*K)bW)^%`_h-bPuE@dSFH=;(0&8x?196yuKP%( z2UpwPM$d1nrWdwtp{?8lOg)!6xqWWX>LC6n;No!`(;26nathsf=bg$V1XP}a!cmDO z$Qe8Mn8T^x%;{RMZh*>j2s4u2n-Xr^i!(#j9Vy`cSK>PyT|B;<|C^hras5VZk}A6B z#h31D)mhw61rMdWwmbH#N|eD;8;8B3fHlI(w-_MMc!y+zjPlrVZSu_#ZS*!)4^i zk&(g;SifS8Rs}Ke&;yJlON3RjqQpg$+|sD*DFab4^grwx;IbI7=Pa7{s~^&oFMWox z9Szh4RFA5vX*7JqtZvnnty^XGWv3yXsyL*eP^;XC%7)34Cu>Uty&etq)C&s>VE>x z#sFL}rk^@>su;NN{>yJ^RS*@^qutmrl}KbHF6Q1Hq*`Nk5bWr$NI~ zV~;&ntLQ*n{wLrR{(;M>r*b8Wz&~!i%Pow!Ach`ygw})*W@mjj#hH)ZsBvk+M8T#{ zB3$VJ^(yQ@xDNH3K85D|^xITAD%FX8%;OHBuYLUrtxt~nx>~JD4m%&vmoh(J-E)ZY ztAET?(d%!#qg6p1bkIRsMf>6M|GR+OjR~`^BBAcMLq@4ioPYk8wJM0BA%mpnmlQ^_ z>7JY1_>#83Gqr99!vt&7e>-+qnziTI+@Pmib|Fo_{7aPI2P>A6A&Y+dn?F&0!3gT? zOuon>J3B|K;vv!DI&H|r&yX_mg#&?=1-%G=DqX^kiBBH=3iUW6T7PXyaivz_XB zNU?p%3Q22nAH$(1qaBA{4OKkNqQc6)H1qpkrZHz6PuY37VikwB)^^It8A=~~@R2rg zqqHnqXm)bJcxi)RGinD3v<5dN=z0#uuW?1CT9t?wUwBQcA~6z||K9{0Cd)883Gpwl zY4E8Fo__b-a}Tsm%-H*QtqLM5FOPBy3$!jCVezGeny5tYgswz80w$=Q4z6zH8hZDq z*V6oJ{zMCJ{0F`D!>g%v8|H%S5W|!%Tz6f&0!Ct9WG5 z?zl0C4QLa^Ps9=)|D-%TSYIDD9gZ#zC;_ClvYJ(b!Dy{p?y=^7rWJfZm6lau=l!6t<|K8MMmi?TW2ifS9QUIBUE$;17vJe+##2Uk;PtE@WT#o$U;6ve}EBIm^p@+)cc`Vx7J1IMRFs)k`{G6$*EO`$uEwBR!Ion-N_T-9U=L}N|=f7FN zVI?!Zc>WPIhaP$;b#!zPKB7+t=Y8r+S{20Tb52n`KOt?H3bZi8JRIaE8oU_wf{-)O z!W|V4LFBSVzMc@9RH1wbQgY;QICUE~X`Kb6nW??8iQfGFͯ_BZ&XB6)roTbnc9 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 JPDHLkV1oOt2bKT; literal 0 HcmV?d00001 diff --git a/res/MikuWow.ico b/res/MikuWow.ico new file mode 100644 index 0000000000000000000000000000000000000000..d3a727cdfa3d180646ed55388f0ca33c47f48316 GIT binary patch literal 130576 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

N<# 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

dPL3GS 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 literal 0 HcmV?d00001 diff --git a/src/CLOUD/Classes/background_color.c b/src/CLOUD/Classes/background_color.c deleted file mode 100644 index 732a5442..00000000 --- a/src/CLOUD/Classes/background_color.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#include "background_color.h" -#include "../../CRE/microui.h" - -extern mu_Context* muctx; - -extern int32_t width; -extern int32_t height; - -const char* background_color_window_title = "Background Color"; - -background_color_struct background_color; - -void background_color_dispose() { - background_color.enabled = false; - background_color.dispose = false; - background_color.disposed = true; -} - -void background_color_init() { - background_color.enabled = true; -} - -void background_color_control() { - if (!background_color.enabled) - return; -} - -void background_color_input() { - if (!background_color.enabled) - return; -} - -void background_color_mui() { - if (!background_color.enabled) - return; - else if (background_color.disposed) { - mu_Container* cnt = mu_get_container(muctx, background_color_window_title); - muctx->hover_root = muctx->next_hover_root = cnt; - cnt->rect = mu_rect(0, 0, 0, 0); - cnt->open = true; - mu_bring_to_front(muctx, cnt); - background_color.disposed = false; - } - - int32_t w = min(width / 3, 360); - int32_t h = muctx->style->title_height + 104; - - if (!mu_begin_window_ex(muctx, background_color_window_title, - mu_rect(0, 0, w, h), - 0 /*MU_OPT_NOINTERACT | MU_OPT_NOCLOSE*/, false, true, false)) { - background_color.dispose = true; - return; - } - - mu_layout_row(muctx, 2, (int[]) { -78, -1 }, 74); - - mu_layout_begin_column(muctx); - mu_layout_row(muctx, 2, (int[]) { 46, -1 }, 0); - - mu_Color c = mu_color_real(background_color.color.x, background_color.color.y, background_color.color.z, 1.0f); - mu_label(muctx, "Red:"); - mu_slider_uint8_t(muctx, &c.r, 0, 255); - mu_label(muctx, "Green:"); - mu_slider_uint8_t(muctx, &c.g, 0, 255); - mu_label(muctx, "Blue:"); - mu_slider_uint8_t(muctx, &c.b, 0, 255); - background_color.color.x = c.r; - background_color.color.y = c.g; - background_color.color.z = c.b; - vec3_mult_scalar(background_color.color, 1.0f / 255.0f, background_color.color); - - mu_layout_row(muctx, 1, (int[]) { -1 }, 0); - if (mu_button(muctx, "Reset Color")) - background_color.color = (vec3){ 0.74117647f, 0.74117647f, 0.74117647f }; - mu_layout_end_column(muctx); - - mu_Rect r = mu_layout_next(muctx); - mu_draw_rect(muctx, r, c); - char buf[32]; - sprintf_s(buf, 32, "#%02X%02X%02X", c.r, c.g, c.b); - mu_draw_control_text(muctx, buf, r, MU_COLOR_TEXT, MU_OPT_ALIGNCENTER); - mu_end_window(muctx); -} - -void background_color_render() { - if (background_color.dispose) { - background_color_dispose(); - return; - } - else if (!background_color.enabled) - return; -} - -void background_color_sound() { - if (!background_color.enabled) - return; -} diff --git a/src/CLOUD/Classes/background_color.h b/src/CLOUD/Classes/background_color.h deleted file mode 100644 index fdfb4725..00000000 --- a/src/CLOUD/Classes/background_color.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#pragma once - -#include "../../KKdLib/default.h" -#include "../../KKdLib/vec.h" - -typedef struct background_color_struct { - bool enabled; - bool dispose; - bool disposed; - vec3 color; -} background_color_struct; - -extern background_color_struct background_color; - -extern void background_color_dispose(); -extern void background_color_init(); -extern void background_color_control(); -extern void background_color_input(); -extern void background_color_mui(); -extern void background_color_render(); -extern void background_color_sound(); diff --git a/src/CLOUD/Classes/glitter_editor.c b/src/CLOUD/Classes/glitter_editor.c index 44d71e61..d4cab4fb 100644 --- a/src/CLOUD/Classes/glitter_editor.c +++ b/src/CLOUD/Classes/glitter_editor.c @@ -1,38 +1,302 @@ /* by korenkonder GitHub/GitLab: korenkonder + + Curve Editor code based on Animation Timeline code from https://github.com/crash5band/Glitter */ +#ifdef CLOUD_DEV #include "glitter_editor.h" +#include "../../KKdLib/dds.h" +#include "../../KKdLib/interpolation.h" +#include "../../KKdLib/io_path.h" +#include "../../KKdLib/io_stream.h" +#include "../../KKdLib/str_utils.h" +#include "../../KKdLib/txp.h" +#include "../../CRE/Glitter/curve.h" #include "../../CRE/Glitter/diva_effect.h" #include "../../CRE/Glitter/diva_list.h" #include "../../CRE/Glitter/diva_resource.h" +#include "../../CRE/Glitter/effect.h" #include "../../CRE/Glitter/effect_group.h" +#include "../../CRE/Glitter/emitter.h" #include "../../CRE/Glitter/file_reader.h" +#include "../../CRE/Glitter/particle.h" #include "../../CRE/Glitter/particle_manager.h" #include "../../CRE/Glitter/scene.h" -#include "../../CRE/microui.h" +#include "../../CRE/Glitter/texture.h" +#include "../../CRE/shared.h" +#include "../../CRE/task.h" #include "../input.h" #include -#include -#include +#include +#include +#include "imgui_helper.h" -extern mu_Context* muctx; +typedef enum glitter_editor_selected_enum { + GLITTER_EDITOR_SELECTED_NONE = 0, + GLITTER_EDITOR_SELECTED_EFFECT, + GLITTER_EDITOR_SELECTED_EMITTER, + GLITTER_EDITOR_SELECTED_PARTICLE, +} glitter_editor_selected_enum; + +typedef enum glitter_editor_flags { + GLITTER_EDITOR_ADD = 0x01, + GLITTER_EDITOR_DUPLICATE = 0x02, + GLITTER_EDITOR_DELETE = 0x04, + GLITTER_EDITOR_MOVE_UP = 0x08, + GLITTER_EDITOR_MOVE_DOWN = 0x10, + GLITTER_EDITOR_IMPORT = 0x20, + GLITTER_EDITOR_EXPORT = 0x40, +} glitter_editor_flags; + +typedef struct glitter_editor_struct { + bool dispose; + bool disposed; + bool test; + bool imgui_focus; + bool create_popup; + bool load; + bool load_popup; + bool load_error_list_popup; + bool save; + bool save_popup; + bool save_compress; + bool close; + bool input_play; + bool input_stop; + bool input_pause; + bool input_reload; + bool effect_group_add; + glitter_editor_flags resource_flags; + glitter_editor_flags effect_flags; + glitter_editor_flags emitter_flags; + glitter_editor_flags particle_flags; + glitter_type save_glt_type; + float_t frame_counter; + float_t old_frame_counter; + float_t start_frame; + float_t end_frame; + int32_t random; + int32_t counter; + glitter_effect_group* effect_group; + glitter_scene* scene; + wchar_t file[MAX_PATH]; +} glitter_editor_struct; + +typedef struct glitter_curve_editor { + glitter_curve_type type; + vector_ptr_glitter_curve* curves; + glitter_curve* list[GLITTER_CURVE_V_SCROLL_ALPHA_2ND - GLITTER_CURVE_TRANSLATION_X + 1]; + glitter_curve curve; + glitter_curve_key* key; + + int32_t frame_width; + float_t zoom_time; + float_t prev_zoom_time; + float_t zoom_value; + float_t key_radius_in; + float_t key_radius_out; + float_t height_offset; + int32_t frame; + + ImDrawList* draw_list; + ImGuiIO* io; + float_t timeline_pos; + + float_t range; + + bool add_key; + bool del_key; + bool add_curve; + bool del_curve; +} glitter_curve_editor; + +static const char* glitter_direction_name[] = { + [GLITTER_DIRECTION_BILLBOARD] = "Billboard", + [GLITTER_DIRECTION_EMITTER_DIRECTION] = "Emitter Direction", + [GLITTER_DIRECTION_PREV_POSITION] = "Prev Position", + [GLITTER_DIRECTION_POSITION] = "Position", + [GLITTER_DIRECTION_Y_AXIS] = "Y Axis", + [GLITTER_DIRECTION_X_AXIS] = "X Axis", + [GLITTER_DIRECTION_Z_AXIS] = "Z Axis", + [GLITTER_DIRECTION_BILLBOARD_Y_ONLY] = "Billboard Y Only", + [GLITTER_DIRECTION_PREV_POSITION_DUP] = "Prev Position##Dup", + [GLITTER_DIRECTION_EMITTER_ROTATION] = "Emitter Rotation", + [GLITTER_DIRECTION_EFFECT_ROTATION] = "Effect Rotation", + [GLITTER_DIRECTION_PARTICLE_ROTATION] = "Particle Rotation", +}; + +static const char* glitter_effect_type_name[] = { + [0] = "Normal", + [1] = "Local", + [2] = "Chara Parent", + [3] = "Object Parent", +}; + +static const char* glitter_effect_ext_anim_index_name[] = { + [0] = "P1", + [1] = "P2", + [2] = "P3", + [3] = "P4", + [4] = "P5", + [5] = "P6", +}; + +static const char* glitter_effect_ext_anim_node_index_name[] = { + [0] = "Head", + [1] = "Mouth", + [2] = "Belly", + [3] = "Chest", + [4] = "Left Shoulder", + [5] = "Left Elbow", + [6] = "Left Elbow Dup", + [7] = "Left Hand", + [8] = "Right Shoulder", + [9] = "Right Elbow", + [10] = "Right Elbow Dup", + [11] = "Right Hand", + [12] = "Left Thigh", + [13] = "Left Knee", + [14] = "Left Toe", + [15] = "Right Thigh", + [16] = "Right Knee", + [17] = "Right Toe", +}; + +static const char* glitter_emitter_name[] = { + [GLITTER_EMITTER_BOX] = "Box", + [GLITTER_EMITTER_CYLINDER] = "Cylinder", + [GLITTER_EMITTER_SPHERE] = "Sphere", + [GLITTER_EMITTER_MESH] = "Mesh", + [GLITTER_EMITTER_POLYGON] = "Polygon", +}; + +static const char* glitter_emitter_emission_direction_name[] = { + [GLITTER_EMITTER_EMISSION_DIRECTION_NONE] = "None", + [GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD] = "Outward", + [GLITTER_EMITTER_EMISSION_DIRECTION_INWARD] = "Inward", +}; + +static const char* glitter_emitter_timer_name[] = { + [GLITTER_EMITTER_TIMER_BY_TIME] = "By Time", + [GLITTER_EMITTER_TIMER_BY_DISTANCE] = "By Distance", +}; + +static const char* glitter_key_name[] = { + [GLITTER_KEY_CONSTANT] = "Constant", + [GLITTER_KEY_LINEAR] = "Linear", + [GLITTER_KEY_HERMITE] = "Hermite", +}; + +static const char* glitter_particle_blend_name[] = { + [GLITTER_PARTICLE_BLEND_ZERO] = "Zero", + [GLITTER_PARTICLE_BLEND_TYPICAL] = "Typical", + [GLITTER_PARTICLE_BLEND_ADD] = "Add", + [GLITTER_PARTICLE_BLEND_SUBTRACT] = "Subtract", + [GLITTER_PARTICLE_BLEND_MULTIPLY] = "Multiply", + [GLITTER_PARTICLE_BLEND_PUNCH_THROUGH] = "Punch Through", +}; + +static const char* glitter_particle_name[] = { + [GLITTER_PARTICLE_QUAD] = "Quad", + [GLITTER_PARTICLE_LINE] = "Line", + [GLITTER_PARTICLE_LOCUS] = "Locus", + [GLITTER_PARTICLE_MESH] = "Mesh", +}; + +static const char* glitter_pivot_name[] = { + [GLITTER_PIVOT_TOP_LEFT] = "Top Left", + [GLITTER_PIVOT_TOP_CENTER] = "Top Center", + [GLITTER_PIVOT_TOP_RIGHT] = "Top Right", + [GLITTER_PIVOT_MIDDLE_LEFT] = "Middle Left", + [GLITTER_PIVOT_MIDDLE_CENTER] = "Middle Center", + [GLITTER_PIVOT_MIDDLE_RIGHT] = "Middle Right", + [GLITTER_PIVOT_BOTTOM_LEFT] = "Bottom Left", + [GLITTER_PIVOT_BOTTOM_CENTER] = "Bottom Center", + [GLITTER_PIVOT_BOTTOM_RIGHT] = "Bottom Right", +}; + +static const char* glitter_uv_index_type_name[] = { + [GLITTER_UV_INDEX_FIXED] = "Fixed", + [GLITTER_UV_INDEX_INITIAL_RANDOM_FIXED] = "Initial Random / Fixed", + [GLITTER_UV_INDEX_RANDOM] = "Random", + [GLITTER_UV_INDEX_FORWARD] = "Forward", + [GLITTER_UV_INDEX_REVERSE] = "Reverse", + [GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD] = "Initial Random / Forward", + [GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE] = "Initial Random / Reverse", + [GLITTER_UV_INDEX_USER] = "User", +}; + +static const float_t curve_base_values[] = { + [GLITTER_CURVE_TRANSLATION_X] = 0.0f, + [GLITTER_CURVE_TRANSLATION_Y] = 0.0f, + [GLITTER_CURVE_TRANSLATION_Z] = 0.0f, + [GLITTER_CURVE_ROTATION_X] = 0.0f, + [GLITTER_CURVE_ROTATION_Y] = 0.0f, + [GLITTER_CURVE_ROTATION_Z] = 0.0f, + [GLITTER_CURVE_SCALE_X] = 1.0f, + [GLITTER_CURVE_SCALE_Y] = 1.0f, + [GLITTER_CURVE_SCALE_Z] = 1.0f, + [GLITTER_CURVE_SCALE_ALL] = 1.0f, + [GLITTER_CURVE_COLOR_R] = 1.0f, + [GLITTER_CURVE_COLOR_G] = 1.0f, + [GLITTER_CURVE_COLOR_B] = 1.0f, + [GLITTER_CURVE_COLOR_A] = 1.0f, + [GLITTER_CURVE_COLOR_RGB_SCALE] = 1.0f, + [GLITTER_CURVE_COLOR_R_2ND] = 1.0f, + [GLITTER_CURVE_COLOR_G_2ND] = 1.0f, + [GLITTER_CURVE_COLOR_B_2ND] = 1.0f, + [GLITTER_CURVE_COLOR_A_2ND] = 1.0f, + [GLITTER_CURVE_COLOR_RGB_SCALE_2ND] = 1.0f, + [GLITTER_CURVE_EMISSION_INTERVAL] = 0.0f, + [GLITTER_CURVE_PARTICLES_PER_EMISSION] = 0.0f, + [GLITTER_CURVE_U_SCROLL] = 0.0f, + [GLITTER_CURVE_V_SCROLL] = 0.0f, + [GLITTER_CURVE_U_SCROLL_ALPHA] = 0.0f, + [GLITTER_CURVE_V_SCROLL_ALPHA] = 0.0f, + [GLITTER_CURVE_U_SCROLL_2ND] = 0.0f, + [GLITTER_CURVE_V_SCROLL_2ND] = 0.0f, + [GLITTER_CURVE_U_SCROLL_ALPHA_2ND] = 0.0f, + [GLITTER_CURVE_V_SCROLL_ALPHA_2ND] = 0.0f, +}; + +static const float_t curve_editor_timeline_base_pos = 50.0f; +static ImVec4 tint_col = { 1.0f, 1.0f, 1.0f, 1.0f }; +static ImVec4 border_col = { 1.0f, 1.0f, 1.0f, 0.5f }; + +extern vector_task_render tasks_render; +extern vector_task_render_draw3d tasks_render_draw3d; extern int32_t width; extern int32_t height; extern bool input_reset; +extern bool input_locked; extern float_t frame_speed; +extern bool grid_3d; extern glitter_particle_manager* gpm; +extern glitter_type glt_type; extern bool close; +extern bool global_context_menu; const char* glitter_editor_window_title = "Glitter Editor"; -glitter_editor_struct glitter_editor; +bool glitter_editor_enabled; +static glitter_editor_struct glitter_editor; -static void glitter_editor_load(); +static glitter_editor_selected_enum selected_type; +static int32_t selected_resource; +static glitter_effect* selected_effect; +static glitter_emitter* selected_emitter; +static glitter_particle* selected_particle; +static glitter_curve_editor curve_editor; + +static void glitter_editor_windows(); + +static void glitter_editor_reload(); +static void glitter_editor_reset(); static void glitter_editor_save(); static void glitter_editor_open_window(); static void glitter_editor_save_window(); @@ -41,1204 +305,271 @@ static void glitter_editor_load_file(wchar_t* path, wchar_t* file); static void glitter_editor_save_file(wchar_t* path, wchar_t* file); static bool glitter_editor_list_open_window(glitter_effect_group* eg); static bool glitter_editor_list_parse(char* data, size_t length, char*** lines, size_t* count); +static bool glitter_editor_resource_import(); +static bool glitter_editor_resource_export(); -static void glitter_editor_mui_show_animation(vector_ptr_glitter_curve* curve); +static void glitter_editor_test_window(); +static void glitter_editor_top_bar(); +static void glitter_editor_effects(); +static void glitter_editor_effects_context_menu(glitter_effect* effect, + glitter_emitter* emitter, glitter_particle* particle, + ssize_t i_idx, ssize_t j_idx, ssize_t k_idx, + glitter_editor_selected_enum type); +static void glitter_editor_resources(); +static void glitter_editor_resources_context_menu(int32_t resource, + ssize_t i_idx, bool selected_none); +static void glitter_editor_property(); +static void glitter_editor_property_effect(); +static void glitter_editor_property_emitter(); +static void glitter_editor_property_particle(); +static bool glitter_editor_property_particle_texture(char* label, char** items, + glitter_particle* particle, int32_t* tex, uint64_t* tex_hash, int32_t texture, + bool* tex_anim, int32_t* tex_frame, int32_t* tex_index, int32_t* tex_tex); -static glitter_effect* selected_effect; -static glitter_emitter* selected_emitter; -static glitter_particle* selected_particle; -static vector_ptr_glitter_curve* selected_animation; -static glitter_curve* selected_curve; +static void glitter_editor_popups(); +static void glitter_editor_file_create_popup(ImGuiIO* io, + ImGuiStyle* style, ImFont* font, const float_t title_bar_size); +static void glitter_editor_file_load_popup(ImGuiIO* io, + ImGuiStyle* style, ImFont* font, const float_t title_bar_size); +static void glitter_editor_file_load_error_list_popup(ImGuiIO* io, + ImGuiStyle* style, ImFont* font, const float_t title_bar_size); +static void glitter_editor_file_save_popup(ImGuiIO* io, + ImGuiStyle* style, ImFont* font, const float_t title_bar_size); + +static void glitter_editor_curve_editor(); +static void glitter_editor_curve_editor_curve_reset(glitter_curve* curve); +static void glitter_editor_curve_editor_curve_set(glitter_curve* curve, glitter_curve_type type); +static void glitter_editor_curve_editor_curves_reset(); +static glitter_curve_key* glitter_editor_curve_editor_get_selected_key(glitter_curve* curve); +static void glitter_editor_curve_editor_get_scroll_bar(float_t max_pos, float_t canvas_size, + float_t frame_width, ImVec2 scrollbar_size, ImVec2 scrollbar_pos, + ImVec2 bar_offset, ImVec2* bar_size, ImVec2* bar_pos, ImVec2* bar_max); +static void glitter_editor_curve_editor_key_manager(vector_glitter_curve_key* keys, bool* add_key, bool* del_key); +static void glitter_editor_curve_editor_property_window(); +static void glitter_editor_curve_editor_reset_state(glitter_curve_type type); +static void glitter_editor_curve_editor_selector(); + +static bool glitter_editor_hash_input(const char* label, uint64_t* hash); void glitter_editor_dispose() { - vector_ptr_glitter_scene_clear(&gpm->scenes, (void*)glitter_scene_dispose); - vector_ptr_glitter_effect_group_clear(&gpm->effect_groups, (void*)glitter_effect_group_dispose); - glitter_editor.file[0] = 0; + task_render task; + memset(&task, 0, sizeof(task_render)); + task.free.type = TASK_RENDER_FREE_GL_OBJECT; + task.free.hash = hash_char("Glitter Editor Dummy"); + vector_task_render_push_back(&tasks_render, &task); + + memset(&task, 0, sizeof(task_render)); + task.free.type = TASK_RENDER_FREE_LIGHT_DIR; + task.free.hash = hash_char("Glitter Editor Dummy Light Dir"); + vector_task_render_push_back(&tasks_render, &task); + + memset(&task, 0, sizeof(task_render)); + task.free.type = TASK_RENDER_FREE_LIGHT_POINT; + task.free.hash = hash_char("Glitter Editor Dummy Light Point"); + vector_task_render_push_back(&tasks_render, &task); + + vector_ptr_glitter_scene_free(&gpm->scenes, glitter_scene_dispose); + vector_ptr_glitter_effect_group_free(&gpm->effect_groups, glitter_effect_group_dispose); + + glitter_editor_enabled = false; + glitter_editor.test = false; + glitter_editor.imgui_focus = false; + glitter_editor.create_popup = false; glitter_editor.load = false; + glitter_editor.load_popup = false; + glitter_editor.load_error_list_popup = false; glitter_editor.save = false; - glitter_editor.save_big_endian = false; + glitter_editor.save_popup = false; + glitter_editor.save_compress = false; + glitter_editor.close = false; glitter_editor.input_play = false; glitter_editor.input_stop = false; glitter_editor.input_pause = true; glitter_editor.input_reload = false; - glitter_editor.frame_counter = 0.0f; - glitter_editor.old_frame_counter = 0.0f; + glitter_editor.effect_group_add = false; + glitter_editor.resource_flags = 0; + glitter_editor.effect_flags = 0; + glitter_editor.emitter_flags = 0; + glitter_editor.particle_flags = 0; + glitter_editor.frame_counter = 0; + glitter_editor.old_frame_counter = 0; + glitter_editor.start_frame = 0; + glitter_editor.end_frame = 0; + glitter_editor.random = 0; + glitter_editor.counter = 0; glitter_editor.effect_group = 0; glitter_editor.scene = 0; - glitter_editor.enabled = false; + memset(glitter_editor.file, 0, sizeof(glitter_editor.file)); glitter_editor.dispose = false; glitter_editor.disposed = true; } void glitter_editor_init() { + if (glitter_editor_enabled || glitter_editor.dispose) + glitter_editor_dispose(); + LARGE_INTEGER time; QueryPerformanceCounter(&time); - gpm->counter = (uint32_t)time.LowPart; - gpm->random = (uint32_t)(time.LowPart * 0x0CAD3078); - glitter_editor.enabled = true; + gpm->counter = (uint32_t)(time.LowPart * 0x0CAD3078LL); + glitter_editor_enabled = true; + glitter_editor.test = false; gpm->emission = 1.0f; + gpm->draw_all = true; + gpm->draw_all_mesh = true; + glt_type = GLITTER_AFT; + grid_3d = true; + + gl_object_update gl_obj; + memset(&gl_obj, 0, sizeof(gl_object_update)); + gl_obj.cull_face = gl_object_cull_face_default; + + task_render task; + memset(&task, 0, sizeof(task_render)); + task.type = TASK_RENDER_UPDATE; + task.update.type = TASK_RENDER_UPDATE_GL_OBJECT; + task.update.hash = hash_char("Glitter Editor Dummy"); + task.update.gl_obj = gl_obj; + vector_task_render_push_back(&tasks_render, &task); + glitter_editor_reset(); + return; + + wchar_t* path_f2 = L"F2\\"; + wchar_t* path_aft = L"AFT\\"; + vector_ptr_wchar_t files_f2 = { 0, 0, 0 }; + vector_ptr_wchar_t files_aft = { 0, 0, 0 }; + path_wget_files(&files_f2, path_f2); + path_wget_files(&files_aft, path_aft); + for (wchar_t** i = files_f2.begin; i != files_f2.end;) + if (str_utils_wcheck_ends_with(*i, L".farc")) + i++; + else + vector_ptr_wchar_t_erase(&files_f2, i - files_f2.begin, 0); + + for (wchar_t** i = files_aft.begin; i != files_aft.end;) + if (str_utils_wcheck_ends_with(*i, L".farc")) + i++; + else + vector_ptr_wchar_t_erase(&files_aft, i - files_aft.begin, 0); + + stream* s = io_wopen(L"name_F2nd.glitter.txt", L"rb"); + size_t length = s->length; + char* data = force_malloc(length); + io_read(s, data, length); + io_dispose(s); + + char** lines; + size_t count; + if (glitter_editor_list_parse(data, length, &lines, &count)) { + uint64_t* hashes = force_malloc_s(uint64_t, count); + for (size_t i = 0; i < count; i++) + hashes[i] = hash_murmurhash(lines[i], min(strlen(lines[i]), 0x7F), 0, false, false); + + ssize_t c = files_f2.end - files_f2.begin; + glitter_file_reader* fr = 0; + if (files_f2.begin && files_aft.begin) + for (ssize_t i = 0; i < c; i++) { + if (!files_f2.begin[i]) + continue; + + wchar_t* file_f2 = files_f2.begin[i]; + wchar_t* file_aft = files_aft.begin[i]; + file_f2 = str_utils_wget_without_extension(file_f2); + file_aft = str_utils_wget_without_extension(file_aft); + glt_type = GLITTER_F2; + fr = glitter_file_reader_winit(GPM_VAL, path_f2, file_f2, 1.0f); + glitter_file_reader_read(GPM_VAL, fr); + + if (fr && fr->effect_group) { + glitter_effect_group* eg = fr->effect_group; + for (glitter_effect** i = eg->effects.begin; i != eg->effects.end; i++) { + if (!*i) + continue; + + glitter_effect* e = *i; + memset(e->name, 0, 0x80); + if (e->data.name_hash == hash_murmurhash_empty) + continue; + + size_t j; + for (j = 0; j < count; j++) + if (e->data.name_hash == hashes[j]) + break; + + if (j == count) + break; + memcpy(e->name, lines[j], min(strlen(lines[j]), 0x7F)); + } + + glitter_editor.effect_group = fr->effect_group; + glitter_editor.save_glt_type = GLITTER_AFT; + glitter_editor_save_file(path_aft, file_aft); + glitter_effect_group_dispose(fr->effect_group); + } + free(file_f2); + free(file_aft); + } + glitter_file_reader_dispose(fr); + + for (size_t i = 0; i < count; i++) + free(lines[i]); + free(lines); + free(hashes); + } + free(data); + glitter_editor.effect_group = 0; } -void glitter_editor_control() { - if (!glitter_editor.enabled) +void glitter_editor_drop(size_t count, wchar_t** paths) { + if (!glitter_editor_enabled) return; + + if (count < 1 || !paths[0]) + return; + + memcpy(glitter_editor.file, paths[0], + min((wcslen(paths[0]) + 1) * sizeof(wchar_t), sizeof(glitter_editor.file))); + glitter_editor.load_popup = true; +} + +void glitter_editor_imgui() { + if (!glitter_editor_enabled) { + if (!glitter_editor.disposed) + glitter_editor.dispose = true; + return; + } + else if (glitter_editor.disposed) { + glitter_editor_enabled = false; + glitter_editor.disposed = false; + return; + } + + glitter_editor.imgui_focus = false; + if (glitter_editor.test) + glitter_editor_test_window(); + else + glitter_editor_windows(); + glitter_editor_popups(); } void glitter_editor_input() { - if (!glitter_editor.enabled) + if (!glitter_editor_enabled) return; + input_locked |= glitter_editor.imgui_focus; + + ImGuiIO* io = igGetIO(); + if (input_is_down(VK_CONTROL) && input_is_tapped('O')) glitter_editor_open_window(); - else if (input_is_down(VK_CONTROL) && input_is_down(VK_SHIFT) && input_is_tapped('S')) - glitter_editor_save_as_window(); - else if (input_is_down(VK_CONTROL) && input_is_tapped('S')) - glitter_editor_save_window(); -} - -void glitter_editor_mui() { - if (!glitter_editor.enabled) - return; - else if (glitter_editor.disposed) { - mu_Container* cnt = mu_get_container(muctx, glitter_editor_window_title); - muctx->hover_root = muctx->next_hover_root = cnt; - cnt->rect = mu_rect(0, 0, 0, 0); - cnt->open = true; - mu_bring_to_front(muctx, cnt); - glitter_editor.disposed = false; - } - - char buf[0x80]; - - int32_t x; - int32_t y; - int32_t w; - int32_t h; - - sprintf_s(buf, sizeof(buf), "Start Frame: %.0f / End Frame: %.0f", glitter_editor.start_frame, glitter_editor.end_frame); - int32_t top_bar_end_frame_text_width = muctx->text_width(muctx->style->font, buf, strlen(buf)); - - x = min(width / 3, 360); - y = 0; - w = width - min(width / 3, 360) * 2; - h = muctx->style->title_height + muctx->style->spacing + 2; - - if (w < (600 + top_bar_end_frame_text_width + (muctx->style->spacing + 2) * 11)) - h += muctx->style->scrollbar_size; - - if (mu_begin_window_ex(muctx, "Glitter Editor Top Bar", - mu_rect(x, y, w, h), - MU_OPT_NOINTERACT | MU_OPT_NOCLOSE | MU_OPT_NOTITLE, true, true, true)) { - mu_layout_row(muctx, 11, (int[]) { 80, 40, 40, 40, 60, 80, 80, 80, 40, 60, top_bar_end_frame_text_width }, 0); - if (mu_button(muctx, "Reset Camera")) - input_reset = true; - - if (mu_button(muctx, "Play")) - glitter_editor.input_play = true; - - if (mu_button(muctx, "Pause")) - glitter_editor.input_pause = true; - - if (mu_button(muctx, "Stop")) - glitter_editor.input_stop = true; - - mu_label(muctx, "Emission:"); - mu_slider_step(muctx, &gpm->emission, 1.0f, 2.0f, 0.01f); - - mu_label(muctx, "Frame Speed:"); - mu_slider_step(muctx, &frame_speed, 0.0f, 3.0f, 0.01f); - - float_t frame_counter = (float_t)(int32_t)glitter_editor.frame_counter; - mu_label(muctx, "Frame: "); - if (mu_slider_ex(muctx, &frame_counter, glitter_editor.start_frame, - glitter_editor.end_frame, 1.0f, "%.0f", MU_OPT_ALIGNCENTER) & MU_RES_CHANGE) { - glitter_editor.old_frame_counter = glitter_editor.frame_counter; - glitter_editor.frame_counter = (float_t)(int32_t)frame_counter; - } - - mu_text(muctx, buf); - mu_end_window(muctx); - } - - x = 0; - y = 0; - w = min(width / 3, 360); - h = height - y; - - selected_effect = 0; - selected_emitter = 0; - selected_particle = 0; - selected_animation = 0; - selected_curve = 0; - - if (mu_begin_window_ex(muctx, "Glitter Editor Left Window", - mu_rect(x, y, w, h), - MU_OPT_NOINTERACT | MU_OPT_NOCLOSE | MU_OPT_NOTITLE, true, true, false)) { - if (!glitter_editor.effect_group) - goto editor_left_window_end; - - glitter_effect** i; - glitter_emitter** j; - glitter_particle** k; - glitter_effect_group* eg = glitter_editor.effect_group; - size_t i_idx = 1; - for (i = eg->effects.begin; i != eg->effects.end; i++, i_idx++) { - if (!*i) - continue; - - glitter_effect* effect = *i; - mu_push_id(muctx, &i_idx, sizeof(i_idx)); - sprintf_s(buf, sizeof(buf), "Effect %lld", i_idx); - if (mu_begin_treenode(muctx, buf)) { - if (!selected_effect) - selected_effect = effect; - - glitter_editor_mui_show_animation(&effect->curve); - - size_t j_idx = 1; - for (j = effect->emitters.begin; j != effect->emitters.end; j++, j_idx++) { - if (!*j) - continue; - - glitter_emitter* emitter = *j; - mu_push_id(muctx, &j_idx, sizeof(j_idx)); - sprintf_s(buf, sizeof(buf), "Emitter %lld", j_idx); - if (mu_begin_treenode(muctx, buf)) { - if (!selected_emitter) - selected_emitter = emitter; - - glitter_editor_mui_show_animation(&emitter->curve); - - size_t k_idx = 1; - for (k = emitter->particles.begin; k != emitter->particles.end; k++, k_idx++) { - if (!*k) - continue; - - glitter_particle* particle = *k; - mu_push_id(muctx, &k_idx, sizeof(k_idx)); - sprintf_s(buf, sizeof(buf), "Particle %lld", k_idx); - if (mu_begin_treenode(muctx, buf)) { - if (!selected_particle) - selected_particle = particle; - - glitter_editor_mui_show_animation(&particle->curve); - - mu_end_treenode(muctx); - } - mu_pop_id(muctx); - } - mu_end_treenode(muctx); - } - mu_pop_id(muctx); - } - mu_end_treenode(muctx); - } - mu_pop_id(muctx); - } - - editor_left_window_end: - mu_end_window(muctx); - } - - const char* glitter_direction_name[] = { - [GLITTER_DIRECTION_BILLBOARD] = "Billboard", - [GLITTER_DIRECTION_EMITTER_DIRECTION] = "Emitter Direction", - [GLITTER_DIRECTION_TYPE_2_DIR_ANGLE] = "Type 2 Dir Angle", - [GLITTER_DIRECTION_TYPE_3_DIR_ANGLE] = "Type 3 Dir Angle", - [GLITTER_DIRECTION_Y_AXIS] = "Y Axis", - [GLITTER_DIRECTION_X_AXIS] = "X Axis", - [GLITTER_DIRECTION_Z_AXIS] = "Z Axis", - [GLITTER_DIRECTION_BILLBOARD_Y_ONLY] = "Billboard Y Only", - [GLITTER_DIRECTION_TYPE_8_DIR_ANGLE] = "Type 8 Dir Angle", - [GLITTER_DIRECTION_EMITTER_ROTATION] = "Emitter Rotation", - [GLITTER_DIRECTION_EFFECT_ROTATION] = "Effect Rotation", - [GLITTER_DIRECTION_PARTICLE_ROTATION] = "Particle Rotation", - }; - - const char* glitter_emitter_name[] = { - [GLITTER_EMITTER_BOX] = "Box", - [GLITTER_EMITTER_CYLINDER] = "Cylinder", - [GLITTER_EMITTER_SPHERE] = "Sphere", - [GLITTER_EMITTER_MESH] = "Mesh", - [GLITTER_EMITTER_POLYGON] = "Polygon", - }; - - const char* glitter_emitter_emission_direction_name[] = { - [GLITTER_EMITTER_EMISSION_DIRECTION_PARTICLE_VELOCITY] = "Particle Velocity", - [GLITTER_EMITTER_EMISSION_DIRECTION_INWARD] = "Inward", - [GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD] = "Outward", - }; - - const char* glitter_particle_blend_name[] = { - [GLITTER_PARTICLE_BLEND_ZERO] = "Zero", - [GLITTER_PARTICLE_BLEND_TYPICAL] = "Typical", - [GLITTER_PARTICLE_BLEND_ADD] = "Add", - [GLITTER_PARTICLE_BLEND_SUBTRACT] = "Subtract", - [GLITTER_PARTICLE_BLEND_MULTIPLY] = "Multiply", - [GLITTER_PARTICLE_BLEND_PUNCH_THROUGH] = "Punch Through", - }; - - const char* glitter_particle_name[] = { - [GLITTER_PARTICLE_QUAD] = "Quad", - [GLITTER_PARTICLE_LINE] = "Line", - [GLITTER_PARTICLE_LOCUS] = "Locus", - [GLITTER_PARTICLE_MESH] = "Mesh", - }; - - const char* glitter_pivot_name[] = { - [GLITTER_PIVOT_TOP_LEFT] = "Top Left", - [GLITTER_PIVOT_TOP_CENTER] = "Top Center", - [GLITTER_PIVOT_TOP_RIGHT] = "Top Right", - [GLITTER_PIVOT_MIDDLE_LEFT] = "Middle Left", - [GLITTER_PIVOT_MIDDLE_CENTER] = "Middle Center", - [GLITTER_PIVOT_MIDDLE_RIGHT] = "Middle Right", - [GLITTER_PIVOT_BOTTOM_LEFT] = "Bottom Left", - [GLITTER_PIVOT_BOTTOM_CENTER] = "Bottom Center", - [GLITTER_PIVOT_BOTTOM_RIGHT] = "Bottom Right", - }; - - const char* glitter_uv_index_type_name[] = { - [GLITTER_UV_INDEX_FIXED] = "Fixed", - [GLITTER_UV_INDEX_INITIAL_RANDOM_FIXED] = "Initial Random / Fixed", - [GLITTER_UV_INDEX_RANDOM] = "Random", - [GLITTER_UV_INDEX_FORWARD] = "Forward", - [GLITTER_UV_INDEX_REVERSE] = "Reverse", - [GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD] = "Initial Random / Forward", - [GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE] = "Initial Random / Reverse", - [GLITTER_UV_INDEX_USER] = "User", - }; - - x = width - min(width / 3, 360); - y = 0; - w = min(width / 3, 360); - h = height - y; - - if (mu_begin_window_ex(muctx, "Glitter Editor Right Window", - mu_rect(x, y, w, h), - MU_OPT_NOINTERACT | MU_OPT_NOCLOSE | MU_OPT_NOTITLE, true, true, false)) { - if (!glitter_editor.effect_group || !selected_effect) - goto editor_right_window_end; - - mu_Rect body = muctx->layout_stack.items[muctx->layout_stack.idx - 1].body; - mu_push_id(muctx, &selected_effect, sizeof(glitter_effect*)); - if (selected_effect && mu_header_ex(muctx, "Effect", MU_OPT_EXPANDED)) { - int32_t tw0 = mu_misc_get_max_text_width(muctx, (char* []) { - "Name:", "Translation", "Rotation", "Scale", - "Appear Time:", "Life Time:", "Start Time:", "Emission:" - }, 8); - int32_t tw1 = mu_misc_get_max_text_width(muctx, (char* []) { - "X:" - }, 1); - int32_t tw2 = mu_misc_get_max_text_width(muctx, (char* []) { - "Y:" - }, 1); - int32_t tw3 = mu_misc_get_max_text_width(muctx, (char* []) { - "Z:" - }, 1); - int32_t sw = (int)((body.w - (tw0 + 4) - (tw1 + 2) - (tw2 + 2) - (tw3 + 2) - (muctx->style->spacing + 2) * 3) / 3.0f); - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - glitter_effect effect = *selected_effect; - char name[0x80]; - memcpy(name, effect.name, 0x80); - mu_label(muctx, "Name:"); - if (mu_button(muctx, name)) { - effect.data.name_hash = gpm->f2 ? hash_char_murmurhash(name, 0, false) : hash_char_fnv1a64(name); - memcpy(effect.name, name, 0x80); - } - - mu_layout_row(muctx, 7, (int[]) { tw0, tw1, sw, tw2, sw, tw3, sw }, 0); - - vec3 translation = effect.translation; - mu_label(muctx, "Translation"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &translation.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &translation.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &translation.z, 0.0001f, "%g"); - effect.translation = translation; - - vec3 rotation = effect.rotation; - vec3_mult_scalar(rotation, (float_t)(180.0 / M_PI), rotation); - mu_label(muctx, "Rotation"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &rotation.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &rotation.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &rotation.z, 0.0001f, "%g"); - vec3_mult_scalar(rotation, (float_t)(M_PI / 180.0), rotation); - effect.rotation = rotation; - - vec3 scale = effect.scale; - mu_label(muctx, "Scale"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &scale.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &scale.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &scale.z, 0.0001f, "%g"); - effect.scale = scale; - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - float_t appear_time = (float_t)(int32_t)effect.data.appear_time; - mu_label(muctx, "Appear Time:"); - mu_number_fmt(muctx, &appear_time, 1.0f, "%.0f"); - appear_time = clamp(appear_time, 0.0f, 32767.0f); - effect.data.appear_time = (float_t)(int32_t)appear_time; - - float_t life_time = (float_t)(int32_t)effect.data.life_time; - mu_label(muctx, "Life Time:"); - mu_number_fmt(muctx, &life_time, 1.0f, "%.0f"); - life_time = clamp(life_time, 0.0f, 32767.0f - appear_time); - effect.data.life_time = (float_t)(int32_t)life_time; - - float_t start_time = (float_t)(int32_t)effect.data.start_time; - mu_label(muctx, "Start Time:"); - mu_number_fmt(muctx, &start_time, 1.0f, "%.0f"); - start_time = clamp(start_time, 0.0f, 32767.0f - appear_time); - effect.data.start_time = (float_t)(int32_t)start_time; - - mu_layout_row(muctx, 1, (int[]) { -1 }, 0); - - glitter_effect_flag flags = effect.data.flags; - bool loop = flags & GLITTER_EFFECT_FLAG_LOOP ? true : false; - mu_checkbox(muctx, "Loop", &loop); - if (loop) - flags |= GLITTER_EFFECT_FLAG_LOOP; - else - flags &= ~GLITTER_EFFECT_FLAG_LOOP; - - bool local = flags & GLITTER_EFFECT_FLAG_LOCAL ? true : false; - mu_checkbox(muctx, "Local", &local); - if (local) - flags |= GLITTER_EFFECT_FLAG_LOCAL; - else - flags &= ~GLITTER_EFFECT_FLAG_LOCAL; - - bool alpha = flags & GLITTER_EFFECT_FLAG_ALPHA ? true : false; - mu_checkbox(muctx, "Alpha", &alpha); - if (alpha) - flags |= GLITTER_EFFECT_FLAG_ALPHA; - else - flags &= ~GLITTER_EFFECT_FLAG_ALPHA; - - bool fog = flags & GLITTER_EFFECT_FLAG_FOG ? true : false; - mu_checkbox(muctx, "Fog", &fog); - if (fog) { - flags |= GLITTER_EFFECT_FLAG_FOG; - flags &= ~GLITTER_EFFECT_FLAG_FOG_HEIGHT; - } - else - flags &= ~GLITTER_EFFECT_FLAG_FOG; - - bool fog_height = flags & GLITTER_EFFECT_FLAG_FOG_HEIGHT ? true : false; - mu_checkbox(muctx, "Fog Height", &fog_height); - if (fog_height) { - flags |= GLITTER_EFFECT_FLAG_FOG_HEIGHT; - flags &= ~GLITTER_EFFECT_FLAG_FOG; - } - else - flags &= ~GLITTER_EFFECT_FLAG_FOG_HEIGHT; - - bool use_emission = flags & GLITTER_EFFECT_FLAG_EMISSION ? true : false; - mu_checkbox(muctx, "Use Emission", &use_emission); - if (use_emission) - flags |= GLITTER_EFFECT_FLAG_EMISSION; - else - flags &= ~GLITTER_EFFECT_FLAG_EMISSION; - effect.data.flags = flags; - - uint32_t version = effect.version; - bool set_emission = version == 7 ? true : false; - mu_checkbox(muctx, "Set Emission", &set_emission); - effect.version = set_emission ? 7 : 6; - - if (version == 7) { - float_t emission = effect.data.emission; - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - mu_label(muctx, "Emission:"); - mu_number_fmt(muctx, &emission, 0.0001f, "%g"); - effect.data.emission = max(emission, 0.0f); - } - - uint64_t hash1 = hash_fnv1a64((void*)selected_effect, sizeof(glitter_effect)); - uint64_t hash2 = hash_fnv1a64((void*)&effect, sizeof(glitter_effect)); - if (hash1 != hash2) { - for (glitter_emitter** i = selected_effect->emitters.begin; i != selected_effect->emitters.end; i++) { - if (!*i) - continue; - - glitter_emitter* emitter = *i; - for (glitter_particle** j = emitter->particles.begin; j != emitter->particles.end; j++) { - if (!*j) - continue; - - glitter_particle* particle = *j; - if (effect.data.flags & GLITTER_EFFECT_FLAG_LOCAL) - particle->data.data.flags |= GLITTER_PARTICLE_FLAG_LOCAL; - else - particle->data.data.flags &= ~GLITTER_PARTICLE_FLAG_LOCAL; - - if (effect.data.flags & GLITTER_EFFECT_FLAG_EMISSION) - particle->data.data.flags |= GLITTER_PARTICLE_FLAG_EMISSION; - else - particle->data.data.flags &= ~GLITTER_PARTICLE_FLAG_EMISSION; - } - } - glitter_editor.input_reload = true; - } - *selected_effect = effect; - } - mu_pop_id(muctx); - - mu_push_id(muctx, &selected_emitter, sizeof(glitter_emitter*)); - if (selected_emitter && mu_header_ex(muctx, "Emitter", MU_OPT_EXPANDED)) { - int32_t tw0 = mu_misc_get_max_text_width(muctx, (char* []) { - "Translation", "Rotation", "Scale", "Rotation Add", "Start Time:", "Life Time:", - "Loop Start Time:", "Loop End Time:", "Emission Interval:", "Particles Per Emission:", - "Direction:", "Loop:", "Size", "Radius:", "Height:", "Start Angle:", "End Angle:", - "Plain:", "Direction:", "Latitude:", "Longitude:", "Scale:", "Count:" - }, 23); - int32_t tw1 = mu_misc_get_max_text_width(muctx, (char* []) { - "X:" - }, 1); - int32_t tw2 = mu_misc_get_max_text_width(muctx, (char* []) { - "Y:" - }, 1); - int32_t tw3 = mu_misc_get_max_text_width(muctx, (char* []) { - "Z:" - }, 1); - int32_t sw = (int)((body.w - (tw0 + 4) - (tw1 + 2) - (tw2 + 2) - (tw3 + 2) - (muctx->style->spacing + 2) * 3) / 3.0f); - - glitter_emitter emitter = *selected_emitter; - mu_layout_row(muctx, 7, (int[]) { tw0, tw1, sw, tw2, sw, tw3, sw }, 0); - - vec3 translation = emitter.translation; - mu_label(muctx, "Translation"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &translation.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &translation.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &translation.z, 0.0001f, "%g"); - emitter.translation = translation; - - vec3 rotation = emitter.rotation; - vec3_mult_scalar(rotation, (float_t)(180.0 / M_PI), rotation); - mu_label(muctx, "Rotation"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &rotation.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &rotation.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &rotation.z, 0.0001f, "%g"); - vec3_mult_scalar(rotation, (float_t)(M_PI / 180.0), rotation); - emitter.rotation = rotation; - - vec3 scale = emitter.scale; - mu_label(muctx, "Scale"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &scale.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &scale.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &scale.z, 0.0001f, "%g"); - emitter.scale = scale; - - vec3 rotation_add = emitter.data.rotation_add; - vec3_mult_scalar(rotation_add, (float_t)(180.0 / M_PI), rotation_add); - mu_label(muctx, "Rotation Add"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &rotation_add.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &rotation_add.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &rotation_add.z, 0.0001f, "%g"); - vec3_mult_scalar(rotation_add, (float_t)(M_PI / 180.0), rotation_add); - emitter.data.rotation_add = rotation_add; - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - float_t start_time = (float_t)(int32_t)emitter.data.start_time; - mu_label(muctx, "Start Time:"); - mu_number_fmt(muctx, &start_time, 1.0f, "%.0f"); - start_time = clamp(start_time, 0.0f, 32767.0f); - emitter.data.start_time = (float_t)(int32_t)start_time; - - float_t life_time = (float_t)(int32_t)emitter.data.life_time; - mu_label(muctx, "Life Time:"); - mu_number_fmt(muctx, &life_time, 1.0f, "%.0f"); - life_time = clamp(life_time, 0.0f, 32767.0f); - emitter.data.life_time = (float_t)(int32_t)life_time; - - float_t loop_start_time = (float_t)(int32_t)emitter.data.loop_start_time; - mu_label(muctx, "Loop Start Time:"); - mu_number_fmt(muctx, &loop_start_time, 1.0f, "%.0f"); - if (loop_start_time < start_time) - loop_start_time = 0.0f; - else - loop_start_time = clamp(loop_start_time, start_time, start_time + life_time); - emitter.data.loop_start_time = (float_t)(int32_t)loop_start_time; - - float_t loop_end_time = (float_t)(int32_t)emitter.data.loop_end_time; - mu_label(muctx, "Loop End Time:"); - mu_number_fmt(muctx, &loop_end_time, 1.0f, "%.0f"); - if (loop_end_time < 0.0f) - loop_end_time = -1.0f; - else - loop_end_time = clamp(loop_end_time, loop_start_time, start_time + life_time); - emitter.data.loop_end_time = (float_t)(int32_t)loop_end_time; - - float_t emission_interval = emitter.data.emission_interval; - mu_label(muctx, "Emission Interval:"); - mu_number_fmt(muctx, &emission_interval, 1.0f, "%.0f"); - emitter.data.emission_interval = clamp(emission_interval, 0.0f, life_time); - - float_t particles_per_emission = emitter.data.particles_per_emission; - mu_label(muctx, "Particles Per Emission:"); - mu_number_fmt(muctx, &particles_per_emission, 1.0f, "%.0f"); - emitter.data.particles_per_emission = max(particles_per_emission, 0.0f); - - float_t direction = (float_t)emitter.data.direction; - direction = clamp(direction, GLITTER_DIRECTION_BILLBOARD, GLITTER_DIRECTION_PARTICLE_ROTATION); - mu_label(muctx, "Direction:"); - mu_slider_ex(muctx, &direction, GLITTER_DIRECTION_BILLBOARD, GLITTER_DIRECTION_PARTICLE_ROTATION, - 1.0f, glitter_direction_name[emitter.data.direction], MU_OPT_ALIGNCENTER); - direction = clamp(direction, GLITTER_DIRECTION_BILLBOARD, GLITTER_DIRECTION_PARTICLE_ROTATION); - emitter.data.direction = (int32_t)direction; - - mu_layout_row(muctx, 1, (int[]) { -1 }, 0); - - glitter_emitter_flag flags = emitter.data.flags; - bool loop = flags & GLITTER_EMITTER_FLAG_LOOP ? true : false; - mu_checkbox(muctx, "Loop", &loop); - if (loop) - flags |= GLITTER_EMITTER_FLAG_LOOP; - else - flags &= ~GLITTER_EMITTER_FLAG_LOOP; - emitter.data.flags = flags; - - float_t type = (float_t)emitter.data.type; - type = clamp(type, GLITTER_EMITTER_BOX, GLITTER_EMITTER_POLYGON); - mu_label(muctx, "Type:"); - mu_slider_ex(muctx, &type, GLITTER_EMITTER_BOX, GLITTER_EMITTER_POLYGON, - 1.0f, glitter_emitter_name[emitter.data.type], MU_OPT_ALIGNCENTER); - type = clamp(type, GLITTER_EMITTER_BOX, GLITTER_EMITTER_POLYGON); - emitter.data.type = (int32_t)type; - - switch (emitter.data.type) { - case GLITTER_EMITTER_BOX: { - mu_layout_row(muctx, 7, (int[]) { tw0, tw1, sw, tw2, sw, tw3, sw }, 0); - vec3 size = emitter.data.box.size; - mu_label(muctx, "Size"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &size.x, 0.0001f, "%g"); - size.x = max(size.x, 0.0f); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &size.y, 0.0001f, "%g"); - size.y = max(size.y, 0.0f); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &size.z, 0.0001f, "%g"); - size.z = max(size.z, 0.0f); - emitter.data.box.size = size; - } break; - case GLITTER_EMITTER_CYLINDER: { - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - float_t radius = emitter.data.cylinder.radius; - mu_label(muctx, "Radius:"); - mu_number_fmt(muctx, &radius, 0.0001f, "%g"); - emitter.data.cylinder.radius = max(radius, 0.0f); - - float_t height = emitter.data.cylinder.height; - mu_label(muctx, "Height:"); - mu_number_fmt(muctx, &height, 0.0001f, "%g"); - emitter.data.cylinder.height = max(height, 0.0f); - - float_t start_angle = emitter.data.cylinder.start_angle * (float_t)(180.0 / M_PI); - mu_label(muctx, "Start Angle:"); - mu_number_fmt(muctx, &start_angle, 0.0001f, "%g"); - emitter.data.cylinder.start_angle = start_angle * (float_t)(M_PI / 180.0); - - float_t end_angle = emitter.data.cylinder.end_angle * (float_t)(180.0 / M_PI); - mu_label(muctx, "End Angle:"); - mu_number_fmt(muctx, &end_angle, 0.0001f, "%g"); - emitter.data.cylinder.end_angle = end_angle * (float_t)(M_PI / 180.0); - - mu_layout_row(muctx, 1, (int[]) { -1 }, 0); - - bool plain = emitter.data.cylinder.plain; - mu_checkbox(muctx, "Plain", &plain); - emitter.data.cylinder.plain = plain; - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - float_t direction = (float_t)emitter.data.cylinder.direction; - direction = clamp(direction, GLITTER_EMITTER_EMISSION_DIRECTION_PARTICLE_VELOCITY, - GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD); - mu_label(muctx, "Direction:"); - mu_slider_ex(muctx, &direction, GLITTER_EMITTER_EMISSION_DIRECTION_PARTICLE_VELOCITY, - GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD, 1.0f, - glitter_emitter_emission_direction_name[emitter.data.cylinder.direction], MU_OPT_ALIGNCENTER); - direction = clamp(direction, GLITTER_EMITTER_EMISSION_DIRECTION_PARTICLE_VELOCITY, - GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD); - emitter.data.cylinder.direction = (int32_t)direction; - } break; - case GLITTER_EMITTER_SPHERE: { - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - float_t radius = emitter.data.sphere.radius; - mu_label(muctx, "Radius:"); - mu_number_fmt(muctx, &radius, 0.0001f, "%g"); - emitter.data.sphere.radius = max(radius, 0.0f); - - float_t latitude = emitter.data.sphere.latitude * (float_t)(180.0 / M_PI); - mu_label(muctx, "Latitude:"); - mu_number_fmt(muctx, &latitude, 0.0001f, "%g"); - emitter.data.sphere.latitude = latitude * (float_t)(M_PI / 180.0); - - float_t longitude = emitter.data.sphere.longitude * (float_t)(180.0 / M_PI); - mu_label(muctx, "Longitude:"); - mu_number_fmt(muctx, &longitude, 0.0001f, "%g"); - emitter.data.sphere.longitude = longitude * (float_t)(M_PI / 180.0); - - mu_layout_row(muctx, 1, (int[]) { -1 }, 0); - - bool plain = emitter.data.sphere.plain; - mu_checkbox(muctx, "Plain", &plain); - emitter.data.sphere.plain = plain; - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - float_t direction = (float_t)emitter.data.sphere.direction; - direction = clamp(direction, GLITTER_EMITTER_EMISSION_DIRECTION_PARTICLE_VELOCITY, - GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD); - mu_label(muctx, "Direction:"); - mu_slider_ex(muctx, &direction, GLITTER_EMITTER_EMISSION_DIRECTION_PARTICLE_VELOCITY, - GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD, 1.0f, - glitter_emitter_emission_direction_name[emitter.data.cylinder.direction], MU_OPT_ALIGNCENTER); - direction = clamp(direction, GLITTER_EMITTER_EMISSION_DIRECTION_PARTICLE_VELOCITY, - GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD); - emitter.data.sphere.direction = (int32_t)direction; - } break; - case GLITTER_EMITTER_MESH: { - - } break; - case GLITTER_EMITTER_POLYGON: { - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - float_t scale = emitter.data.polygon.scale; - mu_label(muctx, "Scale:"); - mu_number_fmt(muctx, &scale, 0.0001f, "%g"); - emitter.data.polygon.scale = max(scale, 0.0f); - - float_t count = (float_t)emitter.data.polygon.count; - mu_label(muctx, "Count:"); - mu_number_fmt(muctx, &count, 1.0f, "%.0f"); - emitter.data.polygon.count = (int32_t)max(count, 0.0f); - } break; - } - - uint64_t hash1 = hash_fnv1a64((void*)selected_emitter, sizeof(glitter_emitter)); - uint64_t hash2 = hash_fnv1a64((void*)&emitter, sizeof(glitter_emitter)); - if (hash1 != hash2) - glitter_editor.input_reload = true; - *selected_emitter = emitter; - } - mu_pop_id(muctx); - - mu_push_id(muctx, &selected_particle, sizeof(glitter_particle*)); - if (selected_particle && mu_header_ex(muctx, "Particle", MU_OPT_EXPANDED)) { - int32_t tw0 = mu_misc_get_max_text_width(muctx, (char* []) { - "Life Time:", "Type:", "Pivot:", "Draw Type:", "Z Offset:", "Rotation", "Rotation Random", - "Rotation Add", "Rotation Add Random", "Scale", "Scale Random", "Direction:", - "Direction Random", "Speed:", "Speed Random:", "Deceleration:", "Deceleration Random:", - "Gravitational Acceleration", "External Acceleration", "External Acceleration Random", - "Reflection Coeff:", "Reflection Coeff Random:", "Rebound Plane Y:", "Color R:", "Color G:", - "Color B:", "Color A:", "UV Index Type:", "UV Split", "UV Index:", "Frame Step UV:", - "UV Index Start:", "UV Index End:", "UV Scroll Add", "UV Scroll Add Scale:", "Blend Mode 0:", - "Blend Mode 1:", "Count:", "Locus History Size:", "Locus History Size Random:", "Emission:" - }, 41); - int32_t tw1 = mu_misc_get_max_text_width(muctx, (char* []) { - "X:", "U:" - }, 2); - int32_t tw2 = mu_misc_get_max_text_width(muctx, (char* []) { - "Y:", "V:" - }, 2); - int32_t tw3 = mu_misc_get_max_text_width(muctx, (char* []) { - "Z:" - }, 1); - int32_t sw = (int)((body.w - (tw0 + 4) - (tw1 + 2) - (tw2 + 2) - (tw3 + 2) - (muctx->style->spacing + 2) * 3) / 3.0f); - - glitter_particle particle = *selected_particle; - mu_layout_row(muctx, 1, (int[]) { -1 }, 0); - - glitter_particle_flag flags = particle.data.data.flags; - bool loop = flags & GLITTER_PARTICLE_FLAG_LOOP ? true : false; - mu_checkbox(muctx, "Loop", &loop); - if (loop) - flags |= GLITTER_PARTICLE_FLAG_LOOP; - else - flags &= ~GLITTER_PARTICLE_FLAG_LOOP; - - bool use_model_mat = flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT ? true : false; - mu_checkbox(muctx, "Use Model Mat", &use_model_mat); - if (use_model_mat) - flags |= GLITTER_PARTICLE_FLAG_USE_MODEL_MAT; - else - flags &= ~GLITTER_PARTICLE_FLAG_USE_MODEL_MAT; - - bool scale_y_by_x = flags & GLITTER_PARTICLE_FLAG_SCALE_Y_BY_X ? true : false; - mu_checkbox(muctx, "Scale Y by X", &scale_y_by_x); - if (scale_y_by_x) - flags |= GLITTER_PARTICLE_FLAG_SCALE_Y_BY_X; - else - flags &= ~GLITTER_PARTICLE_FLAG_SCALE_Y_BY_X; - - bool rebound_plane = flags & GLITTER_PARTICLE_FLAG_REBOUND_PLANE ? true : false; - mu_checkbox(muctx, "Rebound Plane", &rebound_plane); - if (rebound_plane) - flags |= GLITTER_PARTICLE_FLAG_REBOUND_PLANE; - else - flags &= ~GLITTER_PARTICLE_FLAG_REBOUND_PLANE; - - bool translate_by_emitter = flags & GLITTER_PARTICLE_FLAG_TRANSLATE_BY_EMITTER ? true : false; - mu_checkbox(muctx, "Translate by Emitter", &translate_by_emitter); - if (translate_by_emitter) - flags |= GLITTER_PARTICLE_FLAG_TRANSLATE_BY_EMITTER; - else - flags &= ~GLITTER_PARTICLE_FLAG_TRANSLATE_BY_EMITTER; - - bool use_scale = flags & GLITTER_PARTICLE_FLAG_SCALE ? true : false; - mu_checkbox(muctx, "Use Scale", &use_scale); - if (use_scale) - flags |= GLITTER_PARTICLE_FLAG_SCALE; - else - flags &= ~GLITTER_PARTICLE_FLAG_SCALE; - - bool second_texture = flags & GLITTER_PARTICLE_FLAG_SECOND_TEXTURE ? true : false; - mu_checkbox(muctx, "Second Texture", &second_texture); - if (second_texture) - flags |= GLITTER_PARTICLE_FLAG_SECOND_TEXTURE; - else - flags &= ~GLITTER_PARTICLE_FLAG_SECOND_TEXTURE; - - bool local = flags & GLITTER_PARTICLE_FLAG_LOCAL ? true : false; - mu_checkbox(muctx, "Local", &local); - if (local) - flags |= GLITTER_PARTICLE_FLAG_LOCAL; - else - flags &= ~GLITTER_PARTICLE_FLAG_LOCAL; - - bool use_emission = flags & GLITTER_PARTICLE_FLAG_EMISSION ? true : false; - mu_checkbox(muctx, "Use Emission", &use_emission); - if (use_emission) - flags |= GLITTER_PARTICLE_FLAG_EMISSION; - else - flags &= ~GLITTER_PARTICLE_FLAG_EMISSION; - particle.data.data.flags = flags; - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - float_t life_time = particle.data.data.life_time; - mu_label(muctx, "Life Time:"); - mu_number_fmt(muctx, &life_time, 0.0001f, "%g"); - particle.data.data.life_time = max(life_time, 0.0f); - - float_t type = (float_t)particle.data.data.type; - type = clamp(type, GLITTER_PARTICLE_QUAD, GLITTER_PARTICLE_MESH); - mu_label(muctx, "Type:"); - mu_slider_ex(muctx, &type, GLITTER_PARTICLE_QUAD, GLITTER_PARTICLE_MESH, - 1.0f, glitter_particle_name[particle.data.data.type], MU_OPT_ALIGNCENTER); - type = clamp(type, GLITTER_PARTICLE_QUAD, GLITTER_PARTICLE_MESH); - particle.data.data.type = (int32_t)type; - - float_t pivot = (float_t)particle.data.data.pivot; - pivot = clamp(pivot, GLITTER_PIVOT_TOP_LEFT, GLITTER_PIVOT_BOTTOM_RIGHT); - mu_label(muctx, "Pivot:"); - mu_slider_ex(muctx, &pivot, GLITTER_PIVOT_TOP_LEFT, GLITTER_PIVOT_BOTTOM_RIGHT, - 1.0f, glitter_pivot_name[particle.data.data.pivot], MU_OPT_ALIGNCENTER); - pivot = clamp(pivot, GLITTER_PIVOT_TOP_LEFT, GLITTER_PIVOT_BOTTOM_RIGHT); - particle.data.data.pivot = (int32_t)pivot; - - float_t draw_type = (float_t)particle.data.data.draw_type; - draw_type = clamp(draw_type, GLITTER_DIRECTION_BILLBOARD, GLITTER_DIRECTION_PARTICLE_ROTATION); - mu_label(muctx, "Draw Type:"); - mu_slider_ex(muctx, &draw_type, GLITTER_DIRECTION_BILLBOARD, GLITTER_DIRECTION_PARTICLE_ROTATION, - 1.0f, glitter_direction_name[particle.data.data.draw_type], MU_OPT_ALIGNCENTER); - draw_type = clamp(draw_type, GLITTER_DIRECTION_BILLBOARD, GLITTER_DIRECTION_PARTICLE_ROTATION); - particle.data.data.draw_type = (int32_t)draw_type; - - float_t z_offset = particle.data.data.z_offset; - mu_label(muctx, "Z Offset:"); - mu_number_fmt(muctx, &z_offset, 0.0001f, "%g"); - particle.data.data.z_offset = max(z_offset, 0.0f); - - mu_layout_row(muctx, 7, (int[]) { tw0, tw1, sw, tw2, sw, tw3, sw }, 0); - - vec3 rotation = particle.data.data.rotation; - vec3_mult_scalar(rotation, (float_t)(180.0 / M_PI), rotation); - mu_label(muctx, "Rotation"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &rotation.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &rotation.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &rotation.z, 0.0001f, "%g"); - vec3_mult_scalar(rotation, (float_t)(M_PI / 180.0), rotation); - particle.data.data.rotation = rotation; - - vec3 rotation_random = particle.data.data.rotation_random; - vec3_mult_scalar(rotation_random, (float_t)(180.0 / M_PI), rotation_random); - mu_label(muctx, "Rotation Random"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &rotation_random.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &rotation_random.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &rotation_random.z, 0.0001f, "%g"); - vec3_mult_scalar(rotation_random, (float_t)(M_PI / 180.0), rotation_random); - particle.data.data.rotation_random = rotation_random; - - vec3 rotation_add = particle.data.data.rotation_add; - vec3_mult_scalar(rotation_add, (float_t)(180.0 / M_PI), rotation_add); - mu_label(muctx, "Rotation Add"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &rotation_add.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &rotation_add.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &rotation_add.z, 0.0001f, "%g"); - vec3_mult_scalar(rotation_add, (float_t)(M_PI / 180.0), rotation_add); - particle.data.data.rotation_add = rotation_add; - - vec3 rotation_add_random = particle.data.data.rotation_add_random; - vec3_mult_scalar(rotation_add_random, (float_t)(180.0 / M_PI), rotation_add_random); - mu_label(muctx, "Rotation Add Random"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &rotation_add_random.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &rotation_add_random.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &rotation_add_random.z, 0.0001f, "%g"); - vec3_mult_scalar(rotation_add_random, (float_t)(M_PI / 180.0), rotation_add_random); - particle.data.data.rotation_add_random = rotation_add_random; - - mu_layout_row(muctx, 5, (int[]) { tw0, tw1, sw, tw2, sw }, 0); - - vec3 scale = particle.data.data.scale; - mu_label(muctx, "Scale"); - mu_label(muctx, "X:");; - mu_number_fmt(muctx, &scale.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &scale.y, 0.0001f, "%g"); - particle.data.data.scale = scale; - - vec3 scale_random = particle.data.data.scale_random; - mu_label(muctx, "Scale Random"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &scale_random.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &scale_random.y, 0.0001f, "%g"); - particle.data.data.scale_random = scale_random; - - mu_layout_row(muctx, 7, (int[]) { tw0, tw1, sw, tw2, sw, tw3, sw }, 0); - - vec3 direction = particle.data.data.direction; - mu_label(muctx, "Direction"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &direction.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &direction.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &direction.z, 0.0001f, "%g"); - particle.data.data.direction = direction; - - vec3 direction_random = particle.data.data.direction_random; - mu_label(muctx, "Direction Random"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &direction_random.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &direction_random.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &direction_random.z, 0.0001f, "%g"); - particle.data.data.direction_random = direction_random; - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - float_t speed = particle.data.data.speed; - mu_label(muctx, "Speed:"); - mu_number_fmt(muctx, &speed, 0.0001f, "%g"); - particle.data.data.speed = max(speed, 0.0f); - - float_t speed_random = particle.data.data.speed_random; - mu_label(muctx, "Speed Random:"); - mu_number_fmt(muctx, &speed_random, 0.0001f, "%g"); - particle.data.data.speed_random = max(speed_random, 0.0f); - - float_t deceleration = particle.data.data.deceleration; - mu_label(muctx, "Deceleration:"); - mu_number_fmt(muctx, &deceleration, 0.0001f, "%g"); - particle.data.data.deceleration = max(deceleration, 0.0f); - - float_t deceleration_random = particle.data.data.deceleration_random; - mu_label(muctx, "Deceleration Random:"); - mu_number_fmt(muctx, &deceleration_random, 0.0001f, "%g"); - particle.data.data.deceleration_random = max(deceleration_random, 0.0f); - - mu_layout_row(muctx, 7, (int[]) { tw0, tw1, sw, tw2, sw, tw3, sw }, 0); - - vec3 gravitational_acceleration = particle.data.data.gravitational_acceleration; - mu_label(muctx, "Gravitational Acceleration"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &gravitational_acceleration.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &gravitational_acceleration.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &gravitational_acceleration.z, 0.0001f, "%g"); - particle.data.data.gravitational_acceleration = gravitational_acceleration; - - vec3 external_acceleration = particle.data.data.external_acceleration; - mu_label(muctx, "External Acceleration"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &external_acceleration.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &external_acceleration.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &external_acceleration.z, 0.0001f, "%g"); - particle.data.data.external_acceleration = external_acceleration; - - vec3 external_acceleration_random = particle.data.data.external_acceleration_random; - mu_label(muctx, "External Acceleration Random"); - mu_label(muctx, "X:"); - mu_number_fmt(muctx, &external_acceleration_random.x, 0.0001f, "%g"); - mu_label(muctx, "Y:"); - mu_number_fmt(muctx, &external_acceleration_random.y, 0.0001f, "%g"); - mu_label(muctx, "Z:"); - mu_number_fmt(muctx, &external_acceleration_random.z, 0.0001f, "%g"); - particle.data.data.external_acceleration_random = external_acceleration_random; - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - float_t reflection_coeff = particle.data.data.reflection_coeff; - mu_label(muctx, "Reflection Coeff:"); - mu_number_fmt(muctx, &reflection_coeff, 0.0001f, "%g"); - particle.data.data.reflection_coeff = reflection_coeff; - - float_t reflection_coeff_random = particle.data.data.reflection_coeff_random; - mu_label(muctx, "Reflection Coeff Random:"); - mu_number_fmt(muctx, &reflection_coeff_random, 0.0001f, "%g"); - particle.data.data.reflection_coeff_random = reflection_coeff_random; - - float_t rebound_plane_y = particle.data.data.rebound_plane_y; - mu_label(muctx, "Rebound Plane Y:"); - mu_number_fmt(muctx, &rebound_plane_y, 0.0001f, "%g"); - particle.data.data.rebound_plane_y = rebound_plane_y; - - float_t color_r = particle.data.data.color.x * 255.0f; - mu_label(muctx, "Color R:"); - mu_slider_fmt(muctx, &color_r, 0.0f, 255.0f, 1.0f, "%.0f"); - particle.data.data.color.x = color_r * (float_t)(1.0 / 255.0); - - float_t color_g = particle.data.data.color.y * 255.0f; - mu_label(muctx, "Color G:"); - mu_slider_fmt(muctx, &color_g, 0.0f, 255.0f, 1.0f, "%.0f"); - particle.data.data.color.y = color_g * (float_t)(1.0 / 255.0); - - float_t color_b = particle.data.data.color.z * 255.0f; - mu_label(muctx, "Color B:"); - mu_slider_fmt(muctx, &color_b, 0.0f, 255.0f, 1.0f, "%.0f"); - particle.data.data.color.z = color_b * (float_t)(1.0 / 255.0); - - float_t color_a = particle.data.data.color.w * 255.0f; - mu_label(muctx, "Color A:"); - mu_slider_fmt(muctx, &color_a, 0.0f, 255.0f, 1.0f, "%.0f"); - particle.data.data.color.w = color_a * (float_t)(1.0 / 255.0); - - float_t uv_index_type = (float_t)particle.data.data.uv_index_type; - uv_index_type = clamp(uv_index_type, GLITTER_UV_INDEX_FIXED, GLITTER_UV_INDEX_USER); - mu_label(muctx, "UV Index Type:"); - mu_slider_ex(muctx, &uv_index_type, GLITTER_UV_INDEX_FIXED, GLITTER_UV_INDEX_USER, - 1.0f, glitter_uv_index_type_name[particle.data.data.uv_index_type], MU_OPT_ALIGNCENTER); - uv_index_type = clamp(uv_index_type, GLITTER_UV_INDEX_FIXED, GLITTER_UV_INDEX_USER); - particle.data.data.uv_index_type = (int32_t)uv_index_type; - - mu_layout_row(muctx, 5, (int[]) { tw0, tw1, sw, tw2, sw }, 0); - - float_t split_u = (float_t)particle.data.data.split_u; - mu_label(muctx, "UV Split"); - mu_label(muctx, "U:"); - mu_number_fmt(muctx, &split_u, 1.0f, "%.0f"); - particle.data.data.split_u = (uint8_t)(1 << (int32_t)log2f(clamp(split_u, 1.0f, 128.0f))); - - float_t split_v = (float_t)particle.data.data.split_v; - mu_label(muctx, "V:"); - mu_number_fmt(muctx, &split_v, 1.0f, "%.0f"); - particle.data.data.split_v = (uint8_t)(1 << (int32_t)log2f(clamp(split_v, 1.0f, 128.0f))); - - particle.data.data.split_uv.x = 1.0f / (float_t)particle.data.data.split_u; - particle.data.data.split_uv.y = 1.0f / (float_t)particle.data.data.split_v; - - int32_t uv_max_count = (int32_t)(particle.data.data.split_u * particle.data.data.split_v); - if (uv_max_count) - uv_max_count--; - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - float_t frame_step_uv = (float_t)(int16_t)particle.data.data.frame_step_uv; - mu_label(muctx, "Frame Step UV:"); - mu_number_fmt(muctx, &frame_step_uv, 1.0f, "%.0f"); - particle.data.data.frame_step_uv = (float_t)(int16_t)clamp(frame_step_uv, 0.0f, 32767.0f); - - float_t uv_index_start = (float_t)particle.data.data.uv_index_start; - mu_label(muctx, "UV Index Start:"); - mu_slider_ex(muctx, &uv_index_start, 0.0f, (float_t)uv_max_count, 1.0f, "%.0f", MU_OPT_ALIGNCENTER); - particle.data.data.uv_index_start = (int32_t)uv_index_start; - - float_t uv_index_end = (float_t)particle.data.data.uv_index_end; - mu_label(muctx, "UV Index End:"); - mu_slider_ex(muctx, &uv_index_end, uv_index_start, (float_t)uv_max_count, 1.0f, "%.0f", MU_OPT_ALIGNCENTER); - particle.data.data.uv_index_end = (int32_t)uv_index_end; - - float_t uv_index = (float_t)particle.data.data.uv_index; - mu_label(muctx, "UV Index:"); - mu_slider_ex(muctx, &uv_index, uv_index_start, uv_index_end, 1.0f, "%.0f", MU_OPT_ALIGNCENTER); - particle.data.data.uv_index = (int32_t)uv_index; - - mu_layout_row(muctx, 5, (int[]) { tw0, tw1, sw, tw2, sw }, 0); - - vec2 uv_scroll_add = particle.data.data.uv_scroll_add; - mu_label(muctx, "UV Scroll Add"); - mu_label(muctx, "U:"); - mu_number_fmt(muctx, &uv_scroll_add.x, 0.0001f, "%g"); - mu_label(muctx, "V:"); - mu_number_fmt(muctx, &uv_scroll_add.y, 0.0001f, "%g"); - particle.data.data.uv_scroll_add = uv_scroll_add; - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - float_t uv_scroll_add_scale = particle.data.data.uv_scroll_add_scale; - mu_label(muctx, "UV Scroll Add Scale:"); - mu_number_fmt(muctx, &uv_scroll_add_scale, 0.0001f, "%g"); - particle.data.data.uv_scroll_add_scale = uv_scroll_add_scale; - - float_t blend_mode0 = (float_t)particle.data.data.blend_mode0; - blend_mode0 = clamp(blend_mode0, GLITTER_PARTICLE_BLEND_ZERO, GLITTER_PARTICLE_BLEND_PUNCH_THROUGH); - mu_label(muctx, "Blend Mode 0:"); - mu_slider_ex(muctx, &blend_mode0, GLITTER_PARTICLE_BLEND_ZERO, GLITTER_PARTICLE_BLEND_PUNCH_THROUGH, - 1.0f, glitter_particle_blend_name[particle.data.data.blend_mode0], MU_OPT_ALIGNCENTER); - blend_mode0 = clamp(blend_mode0, GLITTER_PARTICLE_BLEND_ZERO, GLITTER_PARTICLE_BLEND_PUNCH_THROUGH); - particle.data.data.blend_mode0 = (int32_t)blend_mode0; - - if (particle.data.data.flags & GLITTER_PARTICLE_FLAG_SECOND_TEXTURE) { - float_t blend_mode1 = (float_t)particle.data.data.blend_mode1; - blend_mode1 = clamp(blend_mode1, GLITTER_PARTICLE_BLEND_ZERO, GLITTER_PARTICLE_BLEND_PUNCH_THROUGH); - mu_label(muctx, "Blend Mode 1:"); - mu_slider_ex(muctx, &blend_mode1, GLITTER_PARTICLE_BLEND_ZERO, GLITTER_PARTICLE_BLEND_PUNCH_THROUGH, - 1.0f, glitter_particle_blend_name[particle.data.data.blend_mode1], MU_OPT_ALIGNCENTER); - blend_mode1 = clamp(blend_mode1, GLITTER_PARTICLE_BLEND_ZERO, GLITTER_PARTICLE_BLEND_PUNCH_THROUGH); - particle.data.data.blend_mode1 = (int32_t)blend_mode1; - } - - switch (particle.data.data.uv_index_type) { - case GLITTER_UV_INDEX_FIXED: - case GLITTER_UV_INDEX_RANDOM: - case GLITTER_UV_INDEX_FORWARD: - case GLITTER_UV_INDEX_REVERSE: - case GLITTER_UV_INDEX_USER: - particle.data.data.uv_index &= uv_max_count; - break; - case GLITTER_UV_INDEX_INITIAL_RANDOM_FIXED: - case GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD: - case GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE: - if (particle.data.data.uv_index < particle.data.data.uv_index_start) - particle.data.data.uv_index = particle.data.data.uv_index_start; - else if (particle.data.data.uv_index_end >= 0 - && particle.data.data.uv_index > particle.data.data.uv_index_end) - particle.data.data.uv_index = particle.data.data.uv_index_end; - - particle.data.data.uv_index = max(particle.data.data.uv_index, uv_max_count); - break; - } - - if (particle.data.data.uv_index_end >= 0) - particle.data.data.uv_index_count = particle.data.data.uv_index_end - particle.data.data.uv_index_start + 1; - else - particle.data.data.uv_index_count = uv_max_count - particle.data.data.uv_index_start; - - if (particle.data.data.uv_index_count < 0) - particle.data.data.uv_index_count = 0; - - mu_layout_row(muctx, 1, (int[]) { -1 }, 0); - - glitter_particle_flag sub_flags = particle.data.data.sub_flags; - bool use_curve = sub_flags & GLITTER_PARTICLE_SUB_FLAG_USE_CURVE ? true : false; - mu_checkbox(muctx, "Use Curve", &use_curve); - if (use_curve) - sub_flags |= GLITTER_PARTICLE_SUB_FLAG_USE_CURVE; - else - sub_flags &= ~GLITTER_PARTICLE_SUB_FLAG_USE_CURVE; - particle.data.data.sub_flags = sub_flags; - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - float_t count = (float_t)particle.data.data.count; - mu_label(muctx, "Count:"); - mu_number_fmt(muctx, &count, 1.0f, "%.0f"); - particle.data.data.count = (int32_t)max(count, 0.0f); - - float_t locus_history_size = (float_t)particle.data.data.locus_history_size; - mu_label(muctx, "Locus History Size:"); - mu_number_fmt(muctx, &locus_history_size, 1.0f, "%.0f"); - particle.data.data.locus_history_size = (int32_t)max(locus_history_size, 0.0f); - - float_t locus_history_size_random = (float_t)particle.data.data.locus_history_size_random; - mu_label(muctx, "Locus History Size Random:"); - mu_number_fmt(muctx, &locus_history_size_random, 1.0f, "%.0f"); - particle.data.data.locus_history_size_random = (int32_t)max(locus_history_size_random, 0.0f); - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - float_t emission = particle.data.data.emission; - mu_label(muctx, "Emission:"); - mu_number_fmt(muctx, &emission, 0.0001f, "%g"); - particle.data.data.emission = max(emission, 0.0f); - - uint64_t hash1 = hash_fnv1a64((void*)selected_particle, sizeof(glitter_particle)); - uint64_t hash2 = hash_fnv1a64((void*)&particle, sizeof(glitter_particle)); - if (hash1 != hash2) - glitter_editor.input_reload = true; - *selected_particle = particle; - } - mu_pop_id(muctx); - - mu_push_id(muctx, &selected_curve, sizeof(glitter_curve*)); - if (selected_curve && mu_header_ex(muctx, "Curve", MU_OPT_EXPANDED)) { - glitter_curve curve = *selected_curve; - - uint64_t hash1 = hash_fnv1a64((void*)selected_curve, sizeof(glitter_curve)); - uint64_t hash2 = hash_fnv1a64((void*)&curve, sizeof(glitter_curve)); - if (hash1 != hash2) - glitter_editor.input_reload = true; - *selected_curve = curve; - } - mu_pop_id(muctx); - - editor_right_window_end: - mu_end_window(muctx); - } - - x = min(width / 3, 360); - y = height - min(height / 3, 240); - w = width - min(width / 3, 360) * 2; - h = min(height / 3, 240); - - if (mu_begin_window_ex(muctx, "Glitter Editor Bottom Window", - mu_rect(x, y, w, h), - MU_OPT_NOINTERACT | MU_OPT_NOCLOSE | MU_OPT_NOTITLE, true, true, false)) { - if (!glitter_editor.effect_group) - goto editor_bottom_window_end; - - editor_bottom_window_end: - mu_end_window(muctx); + else if (input_is_down(VK_CONTROL) && input_is_tapped(VK_F4)) + glitter_editor.close = true; + else if (input_is_tapped('P')) + glitter_editor.test ^= true; + else if (glitter_editor.imgui_focus) { + if (input_is_down(VK_CONTROL) && input_is_down(VK_SHIFT) && input_is_tapped('S')) + glitter_editor_save_as_window(); + else if (input_is_down(VK_CONTROL) && input_is_tapped('S')) + glitter_editor_save_window(); } } @@ -1247,22 +578,343 @@ void glitter_editor_render() { glitter_editor_dispose(); return; } - else if (!glitter_editor.enabled) + else if (!glitter_editor_enabled) return; + bool has_resource = selected_resource != -1; + bool has_effect = selected_effect != 0; + bool has_emitter = selected_emitter != 0 && has_effect; + bool has_particle = selected_particle != 0 && has_emitter; + + if (glitter_editor.effect_group_add) { + glitter_editor.effect_group = glitter_effect_group_init(GPM_VAL); + vector_ptr_glitter_effect_group_push_back(&gpm->effect_groups, &glitter_editor.effect_group); + } + + bool tex_reload = false; + if (glitter_editor.resource_flags & GLITTER_EDITOR_IMPORT) + if (glitter_editor_resource_import()) + tex_reload = true; + + if (has_resource) { + if (glitter_editor.resource_flags & GLITTER_EDITOR_EXPORT) + glitter_editor_resource_export(); + else if (glitter_editor.resource_flags & GLITTER_EDITOR_DELETE) { + glitter_effect_group* eg = glitter_editor.effect_group; + size_t rc = eg->resources_count; + + ssize_t j = -1; + for (size_t i = 0; i < rc; i++) + if (i == selected_resource) { + j = i; + break; + } + + if (j > -1) { + uint64_t hash = eg->resource_hashes.begin[j]; + txp_free(&eg->resources_tex.begin[j]); + vector_uint64_t_erase(&eg->resource_hashes, j); + vector_txp_erase(&eg->resources_tex, j); + eg->resources_count--; + + uint64_t empty_hash = glt_type != GLITTER_AFT + ? hash_murmurhash_empty : hash_fnv1a64_empty; + for (glitter_effect** i = eg->effects.begin; i != eg->effects.end; i++) + if (*i) { + glitter_effect* effect = *i; + for (glitter_emitter** j = effect->emitters.begin; j != effect->emitters.end; j++) + if (*j) { + glitter_emitter* emitter = *j; + for (glitter_particle** k = emitter->particles.begin; k != emitter->particles.end; k++) + if (*k) { + glitter_particle* particle = *k; + if (particle->data.tex_hash0 == hash) { + particle->data.tex_hash0 = empty_hash; + particle->data.texture0 = 0; + } + + if (particle->data.tex_hash1 == hash) { + particle->data.tex_hash1 = empty_hash; + particle->data.texture1 = 0; + } + } + } + } + } + selected_resource = -1; + tex_reload = true; + } + else if (glitter_editor.resource_flags & GLITTER_EDITOR_MOVE_UP) { + glitter_effect_group* eg = glitter_editor.effect_group; + size_t rc = eg->resources_count; + uint64_t* rh = eg->resource_hashes.begin; + txp* rt = eg->resources_tex.begin; + + ssize_t j = -1; + for (size_t i = 0; i < rc; i++) + if (i == selected_resource) { + j = i; + break; + } + + if (j > 0) { + uint64_t temp_hash = rh[j - 1]; + txp temp_txp = rt[j - 1]; + rh[j - 1] = rh[j]; + rt[j - 1] = rt[j]; + rh[j] = temp_hash; + rt[j] = temp_txp; + glitter_editor.input_reload = true; + } + tex_reload = true; + } + else if (glitter_editor.resource_flags & GLITTER_EDITOR_MOVE_DOWN) { + glitter_effect_group* eg = glitter_editor.effect_group; + size_t rc = eg->resources_count; + uint64_t* rh = eg->resource_hashes.begin; + txp* rt = eg->resources_tex.begin; + + ssize_t j = -1; + for (size_t i = 0; i < rc; i++) + if (i == selected_resource) { + j = i; + break; + } + + if (j > -1 && j < (ssize_t)rc - 1) { + uint64_t temp_hash = rh[j + 1]; + txp temp_txp = rt[j + 1]; + rh[j + 1] = rh[j]; + rt[j + 1] = rt[j]; + rh[j] = temp_hash; + rt[j] = temp_txp; + glitter_editor.input_reload = true; + } + tex_reload = true; + } + } + + if (tex_reload && glitter_editor.effect_group) { + glitter_texture_load(glitter_editor.effect_group); + glitter_editor.input_reload = true; + } + + if (glitter_editor.effect_flags & GLITTER_EDITOR_ADD) { + glitter_effect_group* eg = glitter_editor.effect_group; + ssize_t eff_count = eg->effects.end - eg->effects.begin; + + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + + glitter_effect* e = glitter_effect_init(GPM_VAL); + sprintf_s(e->name, sizeof(e->name), "eff_%016llx", + (eff_count + 1) * time.LowPart * hash_murmurhash_empty); + vector_ptr_glitter_effect_push_back(&eg->effects, &e); + glitter_editor.input_reload = true; + } + + if (has_effect) + if (glitter_editor.effect_flags & GLITTER_EDITOR_DUPLICATE) { + glitter_effect_group* eg = glitter_editor.effect_group; + ssize_t eff_count = eg->effects.end - eg->effects.begin; + + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + + glitter_effect* e = glitter_effect_copy(GPM_VAL, selected_effect); + sprintf_s(e->name, sizeof(e->name), "eff_%016llx", + (eff_count + 1) * time.LowPart * hash_murmurhash_empty); + vector_ptr_glitter_effect_push_back(&eg->effects, &e); + glitter_editor.input_reload = true; + } + else if ((glitter_editor.effect_flags & GLITTER_EDITOR_DELETE)) { + glitter_effect_group* eg = glitter_editor.effect_group; + + ssize_t j = -1; + for (glitter_effect** i = eg->effects.begin; i != eg->effects.end; i++) + if (*i && *i == selected_effect) { + j = i - eg->effects.begin; + break; + } + + if (j > -1) + vector_ptr_glitter_effect_erase(&eg->effects, j, glitter_effect_dispose); + selected_type = GLITTER_EDITOR_SELECTED_NONE; + selected_resource = -1; + selected_effect = 0; + selected_emitter = 0; + selected_particle = 0; + + if (eg->effects.end - eg->effects.begin < 1) + glitter_editor.close = true; + else + glitter_editor.input_reload = true; + } + else if (glitter_editor.effect_flags & GLITTER_EDITOR_MOVE_UP) { + glitter_effect_group* eg = glitter_editor.effect_group; + + ssize_t j = -1; + for (glitter_effect** i = eg->effects.begin; + i != eg->effects.end; i++) + if (*i == selected_effect) { + j = i - eg->effects.begin; + break; + } + + if (j > 0) { + glitter_effect* temp = eg->effects.begin[j - 1]; + eg->effects.begin[j - 1] = eg->effects.begin[j]; + eg->effects.begin[j] = temp; + glitter_editor.input_reload = true; + } + } + else if (glitter_editor.effect_flags & GLITTER_EDITOR_MOVE_DOWN) { + glitter_effect_group* eg = glitter_editor.effect_group; + + ssize_t j = -1; + for (glitter_effect** i = eg->effects.begin; + i != eg->effects.end; i++) + if (*i == selected_effect) { + j = i - eg->effects.begin; + break; + } + + if (j > -1 && j < eg->effects.end - eg->effects.begin - 1) { + glitter_effect* temp = eg->effects.begin[j + 1]; + eg->effects.begin[j + 1] = eg->effects.begin[j]; + eg->effects.begin[j] = temp; + glitter_editor.input_reload = true; + } + } + else if (glitter_editor.emitter_flags & GLITTER_EDITOR_ADD) { + glitter_emitter* e = glitter_emitter_init(GPM_VAL); + vector_ptr_glitter_emitter_push_back(&selected_effect->emitters, &e); + glitter_editor.input_reload = true; + } + + if (has_emitter) + if (glitter_editor.emitter_flags & GLITTER_EDITOR_DUPLICATE) { + glitter_emitter* e = glitter_emitter_copy(GPM_VAL, selected_emitter); + vector_ptr_glitter_emitter_push_back(&selected_effect->emitters, &e); + glitter_editor.input_reload = true; + } + else if (glitter_editor.emitter_flags & GLITTER_EDITOR_DELETE) { + ssize_t j = -1; + for (glitter_emitter** i = selected_effect->emitters.begin; + i != selected_effect->emitters.end; i++) + if (*i && *i == selected_emitter) { + j = i - selected_effect->emitters.begin; + break; + } + + if (j > -1) + vector_ptr_glitter_emitter_erase(&selected_effect->emitters, j, glitter_emitter_dispose); + selected_type = GLITTER_EDITOR_SELECTED_EFFECT; + selected_emitter = 0; + selected_particle = 0; + glitter_editor.input_reload = true; + } + else if (glitter_editor.emitter_flags & GLITTER_EDITOR_MOVE_UP) { + ssize_t j = -1; + for (glitter_emitter** i = selected_effect->emitters.begin; + i != selected_effect->emitters.end; i++) + if (*i == selected_emitter) { + j = i - selected_effect->emitters.begin; + break; + } + + if (j > 0) { + glitter_emitter* temp = selected_effect->emitters.begin[j - 1]; + selected_effect->emitters.begin[j - 1] = selected_effect->emitters.begin[j]; + selected_effect->emitters.begin[j] = temp; + glitter_editor.input_reload = true; + } + } + else if (glitter_editor.emitter_flags & GLITTER_EDITOR_MOVE_DOWN) { + ssize_t j = -1; + for (glitter_emitter** i = selected_effect->emitters.begin; + i != selected_effect->emitters.end; i++) + if (*i == selected_emitter) { + j = i - selected_effect->emitters.begin; + break; + } + + if (j > -1 && j < selected_effect->emitters.end - selected_effect->emitters.begin - 1) { + glitter_emitter* temp = selected_effect->emitters.begin[j + 1]; + selected_effect->emitters.begin[j + 1] = selected_effect->emitters.begin[j]; + selected_effect->emitters.begin[j] = temp; + glitter_editor.input_reload = true; + } + } + else if (glitter_editor.particle_flags & GLITTER_EDITOR_ADD) { + glitter_particle* p = glitter_particle_init(GPM_VAL); + vector_ptr_glitter_particle_push_back(&selected_emitter->particles, &p); + glitter_editor.input_reload = true; + } + + if (has_particle) + if (glitter_editor.particle_flags & GLITTER_EDITOR_DUPLICATE) { + glitter_particle* p = glitter_particle_copy(GPM_VAL, selected_particle); + vector_ptr_glitter_particle_push_back(&selected_emitter->particles, &p); + glitter_editor.input_reload = true; + } + else if (glitter_editor.particle_flags & GLITTER_EDITOR_DELETE) { + ssize_t j = (ssize_t)-1; + for (glitter_particle** i = selected_emitter->particles.begin; + i != selected_emitter->particles.end; i++) + if (*i && *i == selected_particle) { + j = i - selected_emitter->particles.begin; + break; + } + + if (j > -1) + vector_ptr_glitter_particle_erase(&selected_emitter->particles, j, glitter_particle_dispose); + selected_type = GLITTER_EDITOR_SELECTED_EMITTER; + selected_particle = 0; + glitter_editor.input_reload = true; + } + else if (glitter_editor.particle_flags & GLITTER_EDITOR_MOVE_UP) { + ssize_t j = -1; + for (glitter_particle** i = selected_emitter->particles.begin; + i != selected_emitter->particles.end; i++) + if (*i == selected_particle) { + j = i - selected_emitter->particles.begin; + break; + } + + if (j > 0) { + glitter_particle* temp = selected_emitter->particles.begin[j - 1]; + selected_emitter->particles.begin[j - 1] = selected_emitter->particles.begin[j]; + selected_emitter->particles.begin[j] = temp; + glitter_editor.input_reload = true; + } + } + else if (glitter_editor.particle_flags & GLITTER_EDITOR_MOVE_DOWN) { + ssize_t j = -1; + for (glitter_particle** i = selected_emitter->particles.begin; + i != selected_emitter->particles.end; i++) + if (*i == selected_particle) { + j = i - selected_emitter->particles.begin; + break; + } + + if (j > -1 && j < selected_emitter->particles.end - selected_emitter->particles.begin - 1) { + glitter_particle* temp = selected_emitter->particles.begin[j + 1]; + selected_emitter->particles.begin[j + 1] = selected_emitter->particles.begin[j]; + selected_emitter->particles.begin[j] = temp; + glitter_editor.input_reload = true; + } + } + + glitter_editor.effect_group_add = false; + glitter_editor.resource_flags = 0; + glitter_editor.effect_flags = 0; + glitter_editor.emitter_flags = 0; + glitter_editor.particle_flags = 0; + if (glitter_editor.load || glitter_editor.save) { - wchar_t* temp = path_wget_without_extension(glitter_editor.file); - wchar_t* file = wcsrchr(temp, L'\\'); - wchar_t* path; - if (file) { - path = path_wget_without_extension(glitter_editor.file); - wcsrchr(path, L'\\')[1] = 0; - *file++ = 0; - } - else { - path = 0; - file = temp; - } + wchar_t* file = str_utils_wget_without_extension(glitter_editor.file); + wchar_t* path = str_utils_wsplit_right_get_left_include(glitter_editor.file, L'\\'); if (glitter_editor.load) glitter_editor_load_file(path, file); @@ -1271,17 +923,30 @@ void glitter_editor_render() { glitter_editor.load = false; glitter_editor.save = false; - glitter_editor.save_big_endian = false; - file = 0; + glitter_editor.save_compress = false; free(path); - free(temp); + free(file); + return; + } + else if (glitter_editor.close) { + vector_ptr_glitter_scene_clear(&gpm->scenes, glitter_scene_dispose); + vector_ptr_glitter_effect_group_clear(&gpm->effect_groups, glitter_effect_group_dispose); + + glitter_editor.effect_group = 0; + glitter_editor.scene = 0; + memset(glitter_editor.file, 0, sizeof(glitter_editor.file)); + glitter_editor.close = false; return; } - glitter_particle_manager_get_start_end_frame(gpm, &glitter_editor.start_frame, &glitter_editor.end_frame); + glitter_particle_manager_get_start_end_frame(gpm, glt_type, + &glitter_editor.start_frame, &glitter_editor.end_frame); - if (!glitter_editor.effect_group) + if (!glitter_editor.effect_group) { + glitter_editor.input_play = false; + glitter_editor.input_stop = false; return; + } if (!glitter_editor.input_pause && glitter_editor.old_frame_counter == glitter_editor.frame_counter) { glitter_editor.old_frame_counter = glitter_editor.frame_counter; @@ -1289,6 +954,17 @@ void glitter_editor_render() { glitter_editor.frame_counter += get_frame_speed(); } + if (glitter_editor.input_reload) { + vector_ptr_glitter_scene_clear(&gpm->scenes, glitter_scene_dispose); + glitter_editor.scene = glitter_scene_init(glitter_editor.effect_group); + vector_ptr_glitter_scene_push_back(&gpm->scenes, &glitter_editor.scene); + gpm->counter = glitter_editor.counter; + glitter_particle_manager_set_frame(GPM_VAL, glitter_editor.effect_group, &glitter_editor.scene, + glitter_editor.frame_counter, glitter_editor.old_frame_counter, glitter_editor.counter, true); + glitter_editor.old_frame_counter = glitter_editor.frame_counter; + glitter_editor.input_reload = false; + } + if (glitter_editor.old_frame_counter != glitter_editor.frame_counter) { if (glitter_editor.end_frame > 0.0f) while (glitter_editor.frame_counter >= glitter_editor.end_frame) @@ -1297,78 +973,332 @@ void glitter_editor_render() { if (glitter_editor.frame_counter < glitter_editor.start_frame) glitter_editor.frame_counter = glitter_editor.start_frame; - glitter_particle_manager_set_frame(gpm, glitter_editor.effect_group, &glitter_editor.scene, - glitter_editor.frame_counter, glitter_editor.old_frame_counter, - glitter_editor.random, glitter_editor.counter, false); + glitter_particle_manager_set_frame(GPM_VAL, glitter_editor.effect_group, &glitter_editor.scene, + glitter_editor.frame_counter, glitter_editor.old_frame_counter, glitter_editor.counter, false); glitter_editor.old_frame_counter = glitter_editor.frame_counter; } - if (glitter_editor.input_reload) { - vector_ptr_glitter_scene_clear(&gpm->scenes, (void*)glitter_scene_dispose); - glitter_editor.scene = glitter_scene_init(glitter_editor.effect_group); - vector_ptr_glitter_scene_push_back(&gpm->scenes, &glitter_editor.scene); - gpm->random = glitter_editor.random; - gpm->counter = glitter_editor.counter; - glitter_particle_manager_set_frame(gpm, glitter_editor.effect_group, &glitter_editor.scene, - glitter_editor.frame_counter, 0.0f, glitter_editor.random, glitter_editor.counter, true); - glitter_editor.input_reload = false; - } - else if (glitter_editor.input_play) + if (glitter_editor.input_play) glitter_editor.input_pause = false; else if (glitter_editor.input_stop) { - gpm->random = glitter_editor.random; gpm->counter = glitter_editor.counter; - glitter_particle_manager_set_frame(gpm, glitter_editor.effect_group, &glitter_editor.scene, - 0.0f, 0.0f, glitter_editor.random, glitter_editor.counter, true); - glitter_editor.frame_counter = 0.0f; - glitter_editor.old_frame_counter = 0.0f; + glitter_editor.frame_counter = glitter_editor.start_frame; + glitter_particle_manager_set_frame(GPM_VAL, glitter_editor.effect_group, &glitter_editor.scene, + glitter_editor.frame_counter, glitter_editor.old_frame_counter, glitter_editor.counter, true); + glitter_editor.old_frame_counter = glitter_editor.frame_counter; glitter_editor.input_pause = true; } glitter_editor.input_play = false; glitter_editor.input_stop = false; } -void glitter_editor_sound() { - if (!glitter_editor.enabled) - return; +static void glitter_editor_windows() { + ImGuiIO* io = igGetIO(); + ImGuiStyle* style = igGetStyle(); + ImFont* font = igGetFont(); + + const float_t title_bar_size = font->FontSize + style->ItemSpacing.y + style->FramePadding.y * 2.0f; + + ImVec2 main_menu_bar_size = ImVec2_Empty; + + if (igBeginMainMenuBar()) { + if (igBeginMenu("File", true)) { + if (igMenuItem_Bool("Open", "Ctrl+O", false, true)) + glitter_editor_open_window(); + if (igMenuItem_Bool("Save", "Ctrl+S", false, glt_type != GLITTER_X)) + glitter_editor_save_window(); + if (igMenuItem_Bool("Save As..", "Ctrl+Shift+S", false, glt_type != GLITTER_X)) + glitter_editor_save_as_window(); + if (igMenuItem_Bool("Close", "Ctrl+F4", false, true)) + glitter_editor.close = true; + if (igMenuItem_Bool("Quit", 0, false, true)) + close = true; + igEndMenu(); + } + + if (igBeginMenu("Edit", false)) { + igEndMenu(); + } + + if (igBeginMenu("Mode", true)) { + if (glt_type != GLITTER_X) { + if (igMenuItem_Bool("F2nd", 0, false, glt_type != GLITTER_F2)) { + glt_type = GLITTER_F2; + glitter_editor_reload(); + } + + if (igMenuItem_Bool("AFT", 0, false, glt_type != GLITTER_AFT)) { + glt_type = GLITTER_AFT; + glitter_editor_reload(); + } + } + else { + if (igMenuItem_Bool("X", 0, false, glt_type != GLITTER_X)) { + glt_type = GLITTER_X; + glitter_editor_reload(); + } + } + igEndMenu(); + } + glitter_editor.imgui_focus |= igIsWindowFocused(0); + igGetWindowSize(&main_menu_bar_size); + igEndMainMenuBar(); + } + + float_t x; + float_t y; + float_t w; + float_t h; + float_t win_x; + float_t win_y; + + win_x = min((float_t)width / 4.0f, 400.0f); + + x = win_x; + y = main_menu_bar_size.y; + w = (float_t)width - win_x * 2.0f; + h = 0; + + ImGuiWindowFlags window_flags; + bool selected = selected_effect || selected_emitter || selected_particle ? true : false; + + window_flags = 0; + window_flags |= ImGuiWindowFlags_NoTitleBar; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoCollapse; + window_flags |= ImGuiWindowFlags_AlwaysAutoResize; + window_flags |= ImGuiWindowFlags_HorizontalScrollbar; + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + window_flags |= ImGuiWindowFlags_AlwaysHorizontalScrollbar; + + igSetNextWindowPos((ImVec2) { x, y }, ImGuiCond_Always, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Always); + + igPushID_Str("Glitter Editor Top Bar"); + if (igBegin("Top Bar", 0, window_flags)) { + glitter_editor_top_bar(); + glitter_editor.imgui_focus |= igIsWindowFocused(0); + } + igEnd(); + igPopID(); + + x = 0; + y = main_menu_bar_size.y; + w = min((float_t)width / 4.0f, 400.0f); + h = (float_t)height - y - min((float_t)height / 3.0f, 320.0f); + + window_flags = 0; + window_flags |= ImGuiWindowFlags_NoTitleBar; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoCollapse; + window_flags |= ImGuiWindowFlags_NoFocusOnAppearing; + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + + igSetNextWindowPos((ImVec2) { x, y }, ImGuiCond_Always, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Always); + + igPushID_Str("Glitter Editor Effects Window"); + if (igBegin("Effects", 0, window_flags)) { + if (igBeginTabBar("Effects Tab", 0)) { + if (igBeginTabItem("Effects", 0, 0)) { + glitter_editor_effects_context_menu(0, 0, 0, 0, 0, 0, GLITTER_EDITOR_SELECTED_NONE); + if (glitter_editor.effect_group) + glitter_editor_effects(); + igEndTabItem(); + } + + imguiDisableElementPush(glitter_editor.effect_group != 0); + if (igBeginTabItem("Resources", 0, 0)) { + glitter_editor_resources_context_menu(-1, 0, true); + if (glitter_editor.effect_group) + glitter_editor_resources(); + igEndTabItem(); + } + imguiDisableElementPop(glitter_editor.effect_group != 0); + igEndTabBar(); + } + glitter_editor.imgui_focus |= igIsWindowFocused(0); + } + igEnd(); + igPopID(); + + win_x = min((float_t)width / 4.0f, 400.0f); + + x = (float_t)width - win_x; + y = main_menu_bar_size.y; + w = win_x; + h = (float_t)height - y - min((float_t)height / 3.0f, 320.0f); + + window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoCollapse; + window_flags |= ImGuiWindowFlags_NoFocusOnAppearing; + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + + igSetNextWindowPos((ImVec2) { x, y }, ImGuiCond_Always, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Always); + + igPushID_Str("Glitter Editor Property Window"); + if (igBegin("Property", 0, window_flags)) { + if (glitter_editor.effect_group && selected) + glitter_editor_property(); + glitter_editor.imgui_focus |= igIsWindowFocused(0); + } + igEnd(); + igPopID(); + + win_x = min((float_t)width / 4.0f, 400.0f); + win_y = min((float_t)height / 3.0f, 320.0f); + + x = 0; + y = (float_t)height - win_y; + w = win_x; + h = win_y; + + window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoCollapse; + window_flags |= ImGuiWindowFlags_NoFocusOnAppearing; + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + + igSetNextWindowPos((ImVec2) { x, y }, ImGuiCond_Always, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Always); + + igPushID_Str("Glitter Editor Curve Editor Selector Window"); + if (igBegin("Curve Editor Selector", 0, window_flags)) { + if (glitter_editor.effect_group && selected) + glitter_editor_curve_editor_selector(); + glitter_editor.imgui_focus |= igIsWindowFocused(0); + } + igEnd(); + igPopID(); + + win_x = min((float_t)width / 4.0f, 400.0f); + win_y = min((float_t)height / 3.0f, 320.0f); + + x = win_x; + y = (float_t)height - win_y; + w = (float_t)width - win_x * 2.0f; + h = win_y; + + window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoCollapse; + window_flags |= ImGuiWindowFlags_NoFocusOnAppearing; + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + + igSetNextWindowPos((ImVec2) { x, y }, ImGuiCond_Always, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Always); + + igPushID_Str("Glitter Editor Curve Editor Window"); + if (igBegin("Curve Editor", 0, window_flags)) { + if (glitter_editor.effect_group && selected) + glitter_editor_curve_editor(); + glitter_editor.imgui_focus |= igIsWindowFocused(0); + } + igEnd(); + igPopID(); + + win_x = min((float_t)width / 4.0f, 400.0f); + win_y = min((float_t)height / 3.0f, 320.0f); + + x = (float_t)width - win_x; + y = (float_t)height - win_y; + w = win_x; + h = win_y; + + window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoCollapse; + window_flags |= ImGuiWindowFlags_NoFocusOnAppearing; + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + + igSetNextWindowPos((ImVec2) { x, y }, ImGuiCond_Always, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Always); + + igPushID_Str("Glitter Editor Curve Editor Property Window"); + if (igBegin("Curve Editor Property", 0, window_flags)) { + if (glitter_editor.effect_group && selected) + glitter_editor_curve_editor_property_window(); + glitter_editor.imgui_focus |= igIsWindowFocused(0); + } + igEnd(); + igPopID(); } -static void glitter_editor_load() { - int msgboxID = MessageBoxW(0, L"Load as F2nd Glitter file?", L"Glitter Load", MB_YESNO); - gpm->f2 = msgboxID == IDYES ? true : false; - glitter_editor.load = true; +static void glitter_editor_reload() { + if (!glitter_editor.effect_group) + return; + + glitter_editor.input_reload = true; + glitter_effect_group* eg = glitter_editor.effect_group; + for (glitter_effect** i = eg->effects.begin; i != eg->effects.end; i++) { + if (!*i) + continue; + + glitter_effect* effect = *i; + if (glt_type != GLITTER_AFT) + effect->data.name_hash = hash_murmurhash(effect->name, min(strlen(effect->name), 0x7F), 0, false, false); + else + effect->data.name_hash = hash_fnv1a64(effect->name, min(strlen(effect->name), 0x7F)); + } + + if (curve_editor.type >= GLITTER_CURVE_TRANSLATION_X + && curve_editor.type <= GLITTER_CURVE_V_SCROLL_ALPHA_2ND) + switch (selected_type) { + case GLITTER_EDITOR_SELECTED_EFFECT: + case GLITTER_EDITOR_SELECTED_EMITTER: + case GLITTER_EDITOR_SELECTED_PARTICLE: + glitter_curve_recalculate(GPM_VAL, &curve_editor.curve, &curve_editor.curve.keys); + break; + } +} + +static void glitter_editor_reset() { + selected_type = GLITTER_EDITOR_SELECTED_NONE; + selected_resource = -1; + selected_effect = 0; + selected_emitter = 0; + selected_particle = 0; + glitter_editor_curve_editor_reset_state(-1); + glitter_editor_curve_editor_curves_reset(); } static void glitter_editor_save() { - if (gpm->f2) { - int msgboxID = MessageBoxW(0, L"Save as F2nd Glitter file for PS3?", L"Glitter Save", MB_YESNO); - glitter_editor.save_big_endian = msgboxID == IDYES ? true : false; - } - else - glitter_editor.save_big_endian = false; - glitter_editor.save = true; + glitter_editor.save_popup = glt_type == GLITTER_X ? false : true; } static void glitter_editor_open_window() { - if (SUCCEEDED(CoInitializeEx(0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) { - wchar_t file[MAX_PATH]; - OPENFILENAME ofn; - memset(&file, 0, sizeof(file)); - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.lpstrFilter = L"Glitter Farc Files (*.farc)\0*.farc\0\0"; - ofn.lpstrFile = file; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrTitle = L"File to Open"; - if (GetOpenFileNameW(&ofn)) { - memcpy(glitter_editor.file, file, sizeof(file)); - glitter_editor_load(); - } - CoUninitialize(); + if (FAILED(CoInitializeEx(0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) + return; + + wchar_t file[MAX_PATH]; + memset(&file, 0, sizeof(file)); + + OPENFILENAMEW ofn; + memset(&ofn, 0, sizeof(OPENFILENAMEW)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.lpstrFilter = L"Glitter Farc Files (*.farc)\0*.farc\0\0"; + ofn.lpstrFile = file; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrTitle = L"File to Open"; + if (GetOpenFileNameW(&ofn)) { + memcpy(glitter_editor.file, file, sizeof(file)); + glitter_editor.load_popup = true; } + CoUninitialize(); } static void glitter_editor_save_window() { + if (!glitter_editor.effect_group || !glitter_editor.scene) + return; + if (glitter_editor.file[0]) glitter_editor_save(); else @@ -1376,36 +1306,41 @@ static void glitter_editor_save_window() { } static void glitter_editor_save_as_window() { - if (SUCCEEDED(CoInitializeEx(0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) { - wchar_t file[MAX_PATH]; - OPENFILENAME ofn; - memset(&file, 0, sizeof(file)); - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.lpstrFilter = L"Glitter Farc Files (*.farc)\0*.farc\0\0"; - ofn.lpstrFile = file; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrTitle = L"File to Save"; - ofn.Flags = OFN_NONETWORKBUTTON; - if (GetSaveFileNameW(&ofn)) { - memcpy(glitter_editor.file, file, sizeof(file)); - glitter_editor_save(); - } - CoUninitialize(); + if (glt_type == GLITTER_X || FAILED(CoInitializeEx(0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) { + glitter_editor.save_popup = false; + return; } + + wchar_t file[MAX_PATH]; + memset(&file, 0, sizeof(file)); + + OPENFILENAMEW ofn; + memset(&ofn, 0, sizeof(OPENFILENAMEW)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.lpstrFilter = L"Glitter Farc Files (*.farc)\0*.farc\0\0"; + ofn.lpstrFile = file; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrTitle = L"File to Save"; + ofn.Flags = OFN_NONETWORKBUTTON; + if (GetSaveFileNameW(&ofn)) { + memcpy(glitter_editor.file, file, sizeof(file)); + glitter_editor_save(); + } + else + glitter_editor.save_popup = false; + CoUninitialize(); } static void glitter_editor_load_file(wchar_t* path, wchar_t* file) { - vector_ptr_glitter_scene_clear(&gpm->scenes, (void*)glitter_scene_dispose); - vector_ptr_glitter_effect_group_clear(&gpm->effect_groups, (void*)glitter_effect_group_dispose); + vector_ptr_glitter_scene_clear(&gpm->scenes, glitter_scene_dispose); + vector_ptr_glitter_effect_group_clear(&gpm->effect_groups, glitter_effect_group_dispose); glitter_editor.effect_group = 0; glitter_editor.scene = 0; - glitter_file_reader* fr = glitter_file_reader_init(path, file, gpm->f2, -1.0f); - if (glitter_file_reader_read(fr)) { - - if (!gpm->f2) { + glitter_file_reader* fr = glitter_file_reader_winit(GPM_VAL, path, file, -1.0f); + if (glitter_file_reader_read(GPM_VAL, fr)) { + if (glt_type == GLITTER_AFT) { bool lst_valid = true; glitter_effect_group* eg = fr->effect_group; for (glitter_effect** i = eg->effects.begin; i != eg->effects.end; i++) { @@ -1421,20 +1356,17 @@ static void glitter_editor_load_file(wchar_t* path, wchar_t* file) { if (!lst_valid && !glitter_editor_list_open_window(fr->effect_group)) { glitter_effect_group_dispose(fr->effect_group); - MessageBoxW(0, L"There was an error while parsing Glitter file.\n" - L"Invalid Glitter List File", L"Open Error", MB_ICONERROR); + glitter_editor.load_error_list_popup = true; } else goto add_effect_group; } else if (!glitter_editor_list_open_window(fr->effect_group)) { glitter_effect_group_dispose(fr->effect_group); - MessageBoxW(0, L"There was an error while parsing Glitter file.\n" - L"Invalid Glitter List File", L"Open Error", MB_ICONERROR); + glitter_editor.load_error_list_popup = true; } else { add_effect_group: - glitter_editor.random = gpm->random; glitter_editor.counter = gpm->counter; glitter_editor.effect_group = fr->effect_group; glitter_editor.scene = glitter_scene_init(fr->effect_group); @@ -1446,7 +1378,7 @@ static void glitter_editor_load_file(wchar_t* path, wchar_t* file) { if (!*i) continue; - glitter_scene_init_effect(glitter_editor.scene, *i, id, false); + glitter_scene_init_effect(GPM_VAL, glitter_editor.scene, *i, id, false); } vector_ptr_glitter_effect_group_push_back(&gpm->effect_groups, &glitter_editor.effect_group); @@ -1456,55 +1388,42 @@ static void glitter_editor_load_file(wchar_t* path, wchar_t* file) { glitter_editor.input_pause = true; } } - else if (fr->effect_group) { + else if (fr->effect_group) glitter_effect_group_dispose(fr->effect_group); - MessageBoxW(0, L"There was an error while parsing Glitter file.\n" - L"Invalid Glitter FARC", L"Open Error", MB_ICONERROR); - } glitter_file_reader_dispose(fr); + glitter_editor_reset(); } static void glitter_editor_save_file(wchar_t* path, wchar_t* file) { - f2_struct* st; + glitter_type glt_type = glitter_editor.save_glt_type; + + f2_struct st; farc_file ff_drs; farc_file ff_dve; farc_file ff_lst; - bool use_big_endian; - - use_big_endian = gpm->f2 && glitter_editor.save_big_endian; memset(&ff_drs, 0, sizeof(farc_file)); memset(&ff_dve, 0, sizeof(farc_file)); memset(&ff_lst, 0, sizeof(farc_file)); farc* f = farc_init(); - st = f2_struct_init(); - if (glitter_diva_effect_unparse_file(glitter_editor.effect_group, st, use_big_endian)) { - f2_struct_write_memory(st, &ff_dve.data, &ff_dve.size_uncompressed, true, false); - ff_dve.name = path_wadd_extension(file, L".dve"); + if (glitter_diva_effect_unparse_file(GPM_VAL, glitter_editor.effect_group, &st)) { + f2_struct_write_memory(&st, &ff_dve.data, &ff_dve.size, true, false); + ff_dve.name = str_utils_wadd(file, L".dve"); } else goto End; - f2_struct_dispose(st); - st = f2_struct_init(); - if (glitter_diva_resource_unparse_file(glitter_editor.effect_group, st, use_big_endian)) { - f2_struct_write_memory(st, &ff_drs.data, &ff_drs.size_uncompressed, true, false); - ff_drs.name = path_wadd_extension(file, L".drs"); + if (glitter_diva_resource_unparse_file(glitter_editor.effect_group, &st)) { + f2_struct_write_memory(&st, &ff_drs.data, &ff_drs.size, true, false); + ff_drs.name = str_utils_wadd(file, L".drs"); } - else { - free(ff_dve.data); - free(ff_dve.name); - goto End; - } - f2_struct_dispose(st); - if (!gpm->f2) { - st = f2_struct_init(); - if (glitter_diva_list_unparse_file(glitter_editor.effect_group, st, use_big_endian)) { - f2_struct_write_memory(st, &ff_lst.data, &ff_lst.size_uncompressed, true, false); - ff_lst.name = path_wadd_extension(file, L".lst"); + if (glt_type == GLITTER_AFT) { + if (glitter_diva_list_unparse_file(glitter_editor.effect_group, &st)) { + f2_struct_write_memory(&st, &ff_lst.data, &ff_lst.size, true, false); + ff_lst.name = str_utils_wadd(file, L".lst"); } else { free(ff_dve.data); @@ -1513,23 +1432,23 @@ static void glitter_editor_save_file(wchar_t* path, wchar_t* file) { free(ff_drs.name); goto End; } - f2_struct_dispose(st); } - vector_farc_file_push_back(&f->files, &ff_drs); + if (ff_drs.data) + vector_farc_file_push_back(&f->files, &ff_drs); vector_farc_file_push_back(&f->files, &ff_dve); - if (!gpm->f2) + if (glt_type == GLITTER_AFT) vector_farc_file_push_back(&f->files, &ff_lst); farc_compress_mode mode; - if (gpm->f2 && use_big_endian) - mode = FARC_COMPRESS_FARC_GZIP_AES; + if (glitter_editor.save_compress) + mode = glt_type != GLITTER_AFT ? FARC_COMPRESS_FARC_GZIP_AES : FARC_COMPRESS_FArC; else mode = FARC_COMPRESS_FArc; - wchar_t* temp = path_wadd_extension(path, file); - if (gpm->f2) { - wchar_t* list_temp = path_wadd_extension(temp, L".glitter.txt"); + wchar_t* temp = str_utils_wadd(path, file); + if (glt_type != GLITTER_AFT) { + wchar_t* list_temp = str_utils_wadd(temp, L".glitter.txt"); stream* s = io_wopen(list_temp, L"wb"); if (s->io.stream) { glitter_effect_group* eg = glitter_editor.effect_group; @@ -1545,73 +1464,76 @@ static void glitter_editor_save_file(wchar_t* path, wchar_t* file) { farc_wwrite(f, temp, mode, false); free(temp); - farc_dispose(f); - return; End: - f2_struct_dispose(st); farc_dispose(f); } static bool glitter_editor_list_open_window(glitter_effect_group* eg) { bool ret = false; - if (SUCCEEDED(CoInitializeEx(0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) { - wchar_t file[MAX_PATH]; - OPENFILENAME ofn; - memset(&file, 0, sizeof(file)); - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.lpstrFilter = L"Glitter UTF-8 List Files (*.glitter.txt)\0*.glitter.txt\0\0"; - ofn.lpstrFile = file; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrTitle = L"File to Open"; - ofn.Flags = OFN_NONETWORKBUTTON; - if (GetOpenFileNameW(&ofn)) { - stream* s = io_wopen(file, L"rb"); - size_t length = s->length; - char* data = force_malloc(length); - io_read(s, data, length); - io_dispose(s); + if (FAILED(CoInitializeEx(0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) + return ret; - char** lines; - size_t count; - if (glitter_editor_list_parse(data, length, &lines, &count)) { - uint64_t* hashes = force_malloc_s(sizeof(uint64_t), count); - if (gpm->f2) - for (size_t i = 0; i < count; i++) - hashes[i] = hash_murmurhash(lines[i], min(strlen(lines[i]), 0x7F), 0, false, false); - else - for (size_t i = 0; i < count; i++) - hashes[i] = hash_fnv1a64(lines[i], min(strlen(lines[i]), 0x7F)); + wchar_t file[MAX_PATH]; + memset(&file, 0, sizeof(file)); - ret = true; - for (glitter_effect** i = eg->effects.begin; i != eg->effects.end; i++) { - if (!*i) - continue; + OPENFILENAMEW ofn; + memset(&ofn, 0, sizeof(OPENFILENAMEW)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.lpstrFilter = L"Glitter UTF-8 List Files (*.glitter.txt)\0*.glitter.txt\0\0"; + ofn.lpstrFile = file; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrTitle = L"File to Open"; + if (GetOpenFileNameW(&ofn)) { + stream* s = io_wopen(file, L"rb"); + size_t length = s->length; + char* data = force_malloc(length); + io_read(s, data, length); + io_dispose(s); - size_t j; - glitter_effect* e = *i; - for (j = 0; j < count; j++) - if (e->data.name_hash == hashes[j]) - break; + char** lines; + size_t count; + if (glitter_editor_list_parse(data, length, &lines, &count)) { + uint64_t empty_hash = glt_type != GLITTER_AFT + ? hash_murmurhash_empty : hash_fnv1a64_empty; + uint64_t* hashes = force_malloc_s(uint64_t, count); + if (glt_type != GLITTER_AFT) + for (size_t i = 0; i < count; i++) + hashes[i] = hash_murmurhash(lines[i], min(strlen(lines[i]), 0x7F), 0, false, false); + else + for (size_t i = 0; i < count; i++) + hashes[i] = hash_fnv1a64(lines[i], min(strlen(lines[i]), 0x7F)); - if (j == count) { - ret = false; + ret = true; + for (glitter_effect** i = eg->effects.begin; i != eg->effects.end; i++) { + if (!*i) + continue; + + glitter_effect* e = *i; + memset(e->name, 0, 0x80); + if (e->data.name_hash == empty_hash) + continue; + + size_t j; + for (j = 0; j < count; j++) + if (e->data.name_hash == hashes[j]) break; - } - memset(e->name, 0, 0x80); - memcpy(e->name, lines[j], min(strlen(lines[j]), 0x7F)); + if (j == count) { + ret = false; + continue; } - for (size_t i = 0; i < count; i++) - free(lines[i]); - free(lines); - free(hashes); + memcpy(e->name, lines[j], min(strlen(lines[j]), 0x7F)); } - free(data); + + for (size_t i = 0; i < count; i++) + free(lines[i]); + free(lines); + free(hashes); } - CoUninitialize(); + free(data); } + CoUninitialize(); return ret; } @@ -1652,11 +1574,11 @@ static bool glitter_editor_list_parse(char* data, size_t length, char*** lines, } lf = false; - size_t* line_lengths = force_malloc_s(sizeof(size_t), c); - size_t* line_offsets = force_malloc_s(sizeof(size_t), c); + size_t* line_lengths = force_malloc_s(size_t, c); + size_t* line_offsets = force_malloc_s(size_t, c); line_lengths[0] = 0; line_offsets[0] = 0; - for (size_t i = 0, j = 0, l = 0; i < length && j < c; ) { + for (size_t i = 0, j = 0, l = 0; j < c; ) { ch = data[i]; while ((ch == '\r' || ch == '\n') && ++i < length) { ch = data[i]; @@ -1679,12 +1601,16 @@ static bool glitter_editor_list_parse(char* data, size_t length, char*** lines, } } - char** temp_lines = force_malloc_s(sizeof(char*), c); + char** temp_lines = force_malloc_s(char*, c); for (size_t i = 0, l = 0; i < c; i++) { l = line_lengths[i]; char* temp = force_malloc(l + 1); memcpy(temp, data + line_offsets[i], l); temp[l] = 0; + + char* t; + if (t = strstr(temp, "#(?)")) + *t = 0; temp_lines[i] = temp; } *lines = temp_lines; @@ -1695,87 +1621,3739 @@ static bool glitter_editor_list_parse(char* data, size_t length, char*** lines, return true; } -static void glitter_editor_mui_show_animation(vector_ptr_glitter_curve* curve) { - if (!mu_begin_treenode(muctx, "Animation")) +static bool glitter_editor_resource_import() { + if (FAILED(CoInitializeEx(0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) + return false; + + bool ret = false; + + wchar_t file[MAX_PATH]; + memset(&file, 0, sizeof(file)); + + OPENFILENAMEW ofn; + memset(&ofn, 0, sizeof(OPENFILENAMEW)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.lpstrFilter = L"DirectDraw Sufrace Files (*.dds)\0*.dds\0\0"; + ofn.lpstrFile = file; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrTitle = L"File to Open"; + if (GetOpenFileNameW(&ofn)) { + wchar_t* f = str_utils_wget_without_extension(file); + wchar_t* p = str_utils_wsplit_right_get_left(file, L'.'); + dds* d = dds_init(); + + uint64_t hash_aft = hash_wchar_t_fnv1a64(f); + uint64_t hash_f2 = hash_wchar_t_murmurhash(f, 0, false); + + glitter_effect_group* eg = glitter_editor.effect_group; + int32_t rc = eg->resources_count; + uint64_t* rh = eg->resource_hashes.begin; + for (int32_t i = 0; i < rc; i++) + if (rh[i] == hash_aft || rh[i] == hash_f2) + goto DDSEnd; + + dds_wread(d, p); + if (d->width == 0 || d->height == 0 || d->mipmaps_count == 0 || d->data.end - d->data.begin < 1) + goto DDSEnd; + + txp tex; + memset(&tex, 0, sizeof(txp)); + tex.array_size = d->has_cubemap ? 6 : 1; + tex.has_cubemap = d->has_cubemap; + tex.mipmaps_count = d->mipmaps_count; + + vector_txp_mipmap_append(&tex.data, (tex.has_cubemap ? 6LL : 1LL) * tex.mipmaps_count); + uint32_t index = 0; + do + for (uint32_t i = 0; i < tex.mipmaps_count; i++) { + txp_mipmap tex_mip; + memset(&tex_mip, 0, sizeof(txp_mipmap)); + tex_mip.width = max(d->width >> i, 1); + tex_mip.height = max(d->height >> i, 1); + tex_mip.format = d->format; + + uint32_t size = txp_get_size(tex_mip.format, + tex_mip.width, tex_mip.height); + tex_mip.size = size; + tex_mip.data = force_malloc(size); + memcpy(tex_mip.data, d->data.begin[index], size); + vector_txp_mipmap_push_back(&tex.data, &tex_mip); + index++; + } + while (index / tex.mipmaps_count < tex.array_size); + + eg->resources_count++; + if (glt_type == GLITTER_AFT) + vector_uint64_t_push_back(&eg->resource_hashes, &hash_aft); + else + vector_uint64_t_push_back(&eg->resource_hashes, &hash_f2); + vector_txp_push_back(&eg->resources_tex, &tex); + ret = true; + DDSEnd: + dds_dispose(d); + free(f); + free(p); + } + CoUninitialize(); + return ret; +} + +static bool glitter_editor_resource_export() { + if (FAILED(CoInitializeEx(0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) + return false; + + bool ret = false; + + wchar_t file[MAX_PATH]; + memset(&file, 0, sizeof(file)); + + OPENFILENAMEW ofn; + memset(&ofn, 0, sizeof(OPENFILENAMEW)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.lpstrFilter = L"DirectDraw Sufrace Files (*.dds)\0*.dds\0\0"; + ofn.lpstrFile = file; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrTitle = L"File to Save"; + ofn.Flags = OFN_NONETWORKBUTTON; + if (GetSaveFileNameW(&ofn)) { + wchar_t* p = str_utils_wsplit_right_get_left(file, L'.'); + dds* d = dds_init(); + + glitter_effect_group* eg = glitter_editor.effect_group; + txp tex = eg->resources_tex.begin[selected_resource]; + + txp_format format = tex.data.begin[0].format; + uint32_t width = tex.data.begin[0].width; + uint32_t height = tex.data.begin[0].height; + + d->format = format; + d->width = width; + d->height = height; + d->mipmaps_count = tex.mipmaps_count; + d->has_cubemap = tex.has_cubemap; + d->data = (vector_ptr_void){ 0, 0, 0 }; + + vector_ptr_void_append(&d->data, (tex.has_cubemap ? 6LL : 1LL) * tex.mipmaps_count); + uint32_t index = 0; + do + for (uint32_t i = 0; i < tex.mipmaps_count; i++) { + uint32_t size = txp_get_size(format, + max(width >> i, 1), max(height >> i, 1)); + void* data = force_malloc(size); + memcpy(data, tex.data.begin[index].data, size); + vector_ptr_void_push_back(&d->data, &data); + index++; + } + while (index / tex.mipmaps_count < tex.array_size); + dds_wwrite(d, p); + ret = true; + dds_dispose(d); + free(p); + } + CoUninitialize(); + return ret; +} + +static void glitter_editor_test_window() { + float_t w = min((float_t)width / 4.0f, 360.0f); + float_t h = 374.0f; + + igSetNextWindowPos(ImVec2_Empty, ImGuiCond_FirstUseEver, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_FirstUseEver); + + ImGuiWindowFlags window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoCollapse; + + bool test = glitter_editor.test; + if (!igBegin("Glitter Editor Test Window", &test, window_flags)) { + glitter_editor.test = false; + glitter_editor.imgui_focus |= igIsWindowFocused(0); + igEnd(); return; + } - if (!selected_animation) - selected_animation = curve; + if (imguiButton("Reset Camera (R)", ImVec2_Empty)) + input_reset = true; - char buf[0x80]; - size_t i_idx = 1; - for (glitter_curve** i = curve->begin; i != curve->end; i++, i_idx++) { + ImVec2 t; + igGetContentRegionAvail(&t); + if (igBeginTable("buttons", 2, 0, ImVec2_Empty, 0.0f)) { + igTableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, t.x * 0.5f, 0); + + igTableNextColumn(); + igGetContentRegionAvail(&t); + if (imguiButton("Play (F)", (ImVec2) { t.x, 0.0f }) || igIsKeyPressed(GLFW_KEY_F, true)) + glitter_editor.input_play = true; + + igTableNextColumn(); + igGetContentRegionAvail(&t); + if (imguiButton("Stop (V)", (ImVec2) { t.x, 0.0f }) || igIsKeyPressed(GLFW_KEY_V, true)) + glitter_editor.input_stop = true; + + igTableNextColumn(); + igGetContentRegionAvail(&t); + if (imguiButton("Reload (T)", (ImVec2) { t.x, 0.0f }) || igIsKeyPressed(GLFW_KEY_T, true)) + glitter_editor.input_reload = true; + + igTableNextColumn(); + igGetContentRegionAvail(&t); + if (imguiButton("Pause (G)", (ImVec2) { t.x, 0.0f }) || igIsKeyPressed(GLFW_KEY_G, true)) + glitter_editor.input_pause = true; + igEndTable(); + } + + igSeparator(); + + float_t frame_counter = (float_t)(int32_t)glitter_editor.frame_counter; + if (imguiColumnSliderFloat("Frame", &frame_counter, glitter_editor.start_frame, + glitter_editor.end_frame, "%.0f", 0)) { + glitter_editor.old_frame_counter = glitter_editor.frame_counter; + glitter_editor.frame_counter = (float_t)(int32_t)frame_counter; + } + + igText("Start Frame: %.0f / End Frame: %.0f", glitter_editor.start_frame, glitter_editor.end_frame); + + igSeparator(); + + igText("%.0f - %.0f/%.0f", glitter_editor.frame_counter, glitter_editor.start_frame, glitter_editor.end_frame); + + size_t ctrl; + size_t disp; + + ctrl = glitter_particle_manager_get_ctrl_count(GPM_VAL, GLITTER_PARTICLE_QUAD); + disp = glitter_particle_manager_get_disp_count(GPM_VAL, GLITTER_PARTICLE_QUAD); + igText(" Quad: ctrl%lld, disp%lld", ctrl, disp); + + ctrl = glitter_particle_manager_get_ctrl_count(GPM_VAL, GLITTER_PARTICLE_LOCUS); + disp = glitter_particle_manager_get_disp_count(GPM_VAL, GLITTER_PARTICLE_LOCUS); + igText("Locus: ctrl%lld, disp%lld", ctrl, disp); + + ctrl = glitter_particle_manager_get_ctrl_count(GPM_VAL, GLITTER_PARTICLE_LINE); + disp = glitter_particle_manager_get_disp_count(GPM_VAL, GLITTER_PARTICLE_LINE); + igText(" Line: ctrl%lld, disp%lld", ctrl, disp); + + ctrl = glitter_particle_manager_get_ctrl_count(GPM_VAL, GLITTER_PARTICLE_MESH); + disp = glitter_particle_manager_get_disp_count(GPM_VAL, GLITTER_PARTICLE_MESH); + igText(" Mesh: ctrl%lld, disp%lld", ctrl, disp); + + igSeparator(); + + imguiColumnSliderFloat("Emission", &gpm->emission, 1.0f, 2.0f, "%.2f", 0); + imguiColumnSliderFloat("Frame Speed", &frame_speed, 0.0f, 3.0f, "%.2f", 0); + + igSeparator(); + + imguiCheckbox("Grid", &grid_3d); + + imguiCheckbox("Draw All", &gpm->draw_all); + + imguiDisableElementPush(gpm->draw_all); + imguiCheckbox("Draw All Mesh", &gpm->draw_all_mesh); + imguiDisableElementPop(gpm->draw_all); + glitter_editor.imgui_focus |= igIsWindowFocused(0); + igEnd(); +} + +static void glitter_editor_top_bar() { + if (imguiButton("Reset Camera", ImVec2_Empty)) + input_reset = true; + + igSameLine(0.0f, -1.0f); + if (imguiButton("Play", ImVec2_Empty)) + glitter_editor.input_play = true; + + igSameLine(0.0f, -1.0f); + if (imguiButton("Pause", ImVec2_Empty)) + glitter_editor.input_pause = true; + + igSameLine(0.0f, -1.0f); + if (imguiButton("Stop", ImVec2_Empty)) + glitter_editor.input_stop = true; + + igSameLine(0.0f, -1.0f); + igSeparatorEx(ImGuiSeparatorFlags_Vertical); + + igSameLine(0.0f, -1.0f); + igText("Emission:"); + igSameLine(0.0f, -1.0f); + igSetNextItemWidth(80.0f); + igSliderFloat("##Emission:", &gpm->emission, 1.0f, 2.0f, "%.2f", 0); + + igSameLine(0.0f, -1.0f); + igText("Frame Speed:"); + igSameLine(0.0f, -1.0f); + igSetNextItemWidth(80.0f); + igSliderFloat("##Frame Speed:", &frame_speed, 0.0f, 3.0f, "%.2f", 0); + + igSameLine(0.0f, -1.0f); + igSeparatorEx(ImGuiSeparatorFlags_Vertical); + + igSameLine(0.0f, -1.0f); + imguiCheckbox("Grid", &grid_3d); + + igSameLine(0.0f, -1.0f); + imguiCheckbox("Draw All", &gpm->draw_all); + + imguiDisableElementPush(gpm->draw_all); + igSameLine(0.0f, -1.0f); + imguiCheckbox("Draw All Mesh", &gpm->draw_all_mesh); + imguiDisableElementPop(gpm->draw_all); + + igSameLine(0.0f, -1.0f); + igSeparatorEx(ImGuiSeparatorFlags_Vertical); + + igSameLine(0.0f, -1.0f); + igText("Frame"); + float_t frame_counter = (float_t)(int32_t)glitter_editor.frame_counter; + igSameLine(0.0f, -1.0f); + igSetNextItemWidth(80.0f); + if (igSliderFloat("##Frame", &frame_counter, glitter_editor.start_frame, + glitter_editor.end_frame, "%.0f", 0)) { + glitter_editor.old_frame_counter = glitter_editor.frame_counter; + glitter_editor.frame_counter = (float_t)(int32_t)frame_counter; + } + + igSameLine(0.0f, -1.0f); + igText("Start Frame: %.0f / End Frame: %.0f", glitter_editor.start_frame, glitter_editor.end_frame); +} + +static void glitter_editor_effects() { + char buf[0x100]; + + ImGuiTreeNodeFlags tree_node_base_flags = 0; + tree_node_base_flags |= ImGuiTreeNodeFlags_OpenOnDoubleClick; + tree_node_base_flags |= ImGuiTreeNodeFlags_OpenOnArrow; + tree_node_base_flags |= ImGuiTreeNodeFlags_SpanAvailWidth; + + ImGuiTreeNodeFlags tree_node_flags; + + glitter_effect_group* eg = glitter_editor.effect_group; + igPushID_Ptr(eg); + ssize_t i_idx = 1; + for (glitter_effect** i = eg->effects.begin; + i != eg->effects.end; i++, i_idx++) { if (!*i) continue; - glitter_curve* curve = *i; - mu_push_id(muctx, &i_idx, sizeof(i_idx)); - switch (curve->type) { - case GLITTER_CURVE_TRANSLATION_X: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Translation X"); + glitter_effect* effect = *i; + tree_node_flags = tree_node_base_flags; + if (effect == selected_effect && !selected_emitter && !selected_particle) + tree_node_flags |= ImGuiTreeNodeFlags_Selected; + + igPushID_Ptr(effect); + if (igTreeNodeEx_StrStr("effect", tree_node_flags, "%s (%016llX)", + effect->name, (size_t)effect * hash_fnv1a64_empty)) { + glitter_editor_effects_context_menu(effect, 0, 0, + i_idx, 0, 0, GLITTER_EDITOR_SELECTED_EFFECT); + + ssize_t j_idx = 1; + for (glitter_emitter** j = effect->emitters.begin; + j != effect->emitters.end; j++, j_idx++) { + if (!*j) + continue; + + glitter_emitter* emitter = *j; + tree_node_flags = tree_node_base_flags; + if (emitter == selected_emitter && !selected_particle) + tree_node_flags |= ImGuiTreeNodeFlags_Selected; + + igPushID_Ptr(emitter); + if (igTreeNodeEx_StrStr("emitter", tree_node_flags, "Emitter %lld (%016llX)", + j_idx, (size_t)emitter * hash_fnv1a64_empty)) { + glitter_editor_effects_context_menu(effect, emitter, 0, + i_idx, j_idx, 0, GLITTER_EDITOR_SELECTED_EMITTER); + + ssize_t k_idx = 1; + for (glitter_particle** k = emitter->particles.begin; + k != emitter->particles.end; k++, k_idx++) { + if (!*k) + continue; + + glitter_particle* particle = *k; + tree_node_flags = tree_node_base_flags; + + igPushID_Ptr(particle); + sprintf_s(buf, sizeof(buf), "Particle %lld (%016llX)", + k_idx, (size_t)particle * hash_fnv1a64_empty); + igSelectable_Bool(buf, particle == selected_particle, 0, (ImVec2) { 0.0f, 0.0f }); + glitter_editor_effects_context_menu(effect, emitter, particle, + i_idx, j_idx, k_idx, GLITTER_EDITOR_SELECTED_PARTICLE); + igPopID(); + } + igTreePop(); + } + else + glitter_editor_effects_context_menu(effect, emitter, 0, + i_idx, j_idx, 0, GLITTER_EDITOR_SELECTED_EMITTER); + igPopID(); + } + igTreePop(); + } + else + glitter_editor_effects_context_menu(effect, 0, 0, + i_idx, 0, 0, GLITTER_EDITOR_SELECTED_EFFECT); + igPopID(); + } + igPopID(); +} + +static void glitter_editor_effects_context_menu(glitter_effect* effect, + glitter_emitter* emitter, glitter_particle* particle, + ssize_t i_idx, ssize_t j_idx, ssize_t k_idx, + glitter_editor_selected_enum type) { + bool focused = igIsItemFocused(); + + static void* selected; + if (type == GLITTER_EDITOR_SELECTED_NONE) { + if (igIsWindowHovered(0) && igIsMouseReleased(ImGuiMouseButton_Right)) { + igOpenPopup("effects popup", ImGuiPopupFlags_MouseButtonRight); + selected = 0; + } + else if (selected != 0) + goto End; + } + else if (igIsItemHovered(0) && igIsMouseReleased(ImGuiMouseButton_Right)) { + switch (type) { + case GLITTER_EDITOR_SELECTED_EFFECT: + selected = effect; break; - case GLITTER_CURVE_TRANSLATION_Y: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Translation Y"); + case GLITTER_EDITOR_SELECTED_EMITTER: + selected = emitter; break; - case GLITTER_CURVE_TRANSLATION_Z: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Translation Z"); - break; - case GLITTER_CURVE_ROTATION_X: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Rotation X"); - break; - case GLITTER_CURVE_ROTATION_Y: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Rotation Y"); - break; - case GLITTER_CURVE_ROTATION_Z: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Rotation Z"); - break; - case GLITTER_CURVE_SCALE_X: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Scale X"); - break; - case GLITTER_CURVE_SCALE_Y: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Scale Y"); - break; - case GLITTER_CURVE_SCALE_Z: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Scale Z"); - break; - case GLITTER_CURVE_SCALE_ALL: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Scale All"); - break; - case GLITTER_CURVE_COLOR_R: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Color Red"); - break; - case GLITTER_CURVE_COLOR_G: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Color Green"); - break; - case GLITTER_CURVE_COLOR_B: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Color Blue"); - break; - case GLITTER_CURVE_COLOR_A: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Color Alpha"); - break; - case GLITTER_CURVE_EMISSION_INTERVAL: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Emission Interval"); - break; - case GLITTER_CURVE_PARTICLES_PER_EMISSION: - sprintf_s(buf, sizeof(buf), "Curve: %s", "Particles Per Emission"); - break; - case GLITTER_CURVE_U_SCROLL: - sprintf_s(buf, sizeof(buf), "Curve: %s", "U Scroll"); - break; - case GLITTER_CURVE_V_SCROLL: - sprintf_s(buf, sizeof(buf), "Curve: %s", "V Scroll"); + case GLITTER_EDITOR_SELECTED_PARTICLE: + selected = particle; break; default: - sprintf_s(buf, sizeof(buf), "Curve: Unknown ID %d", curve->type); + goto End; + } + igOpenPopup("effects popup", ImGuiPopupFlags_MouseButtonRight); + } + else + switch (type) { + case GLITTER_EDITOR_SELECTED_EFFECT: + if (selected != effect) + goto End; + break; + case GLITTER_EDITOR_SELECTED_EMITTER: + if (selected != emitter) + goto End; + break; + case GLITTER_EDITOR_SELECTED_PARTICLE: + if (selected != particle) + goto End; + break; + default: + goto End; + } + + ImGuiWindowFlags window_flags = 0; + window_flags |= ImGuiWindowFlags_NoTitleBar; + window_flags |= ImGuiWindowFlags_AlwaysAutoResize; + + if (!igBeginPopup("effects popup", window_flags)) + goto End; + + global_context_menu = false; + + bool close = false; + switch (type) { + case GLITTER_EDITOR_SELECTED_NONE: { + if (igMenuItem_Bool("Add Effect", 0, false, true)) { + if (!glitter_editor.effect_group) + glitter_editor.create_popup = true; + else + glitter_editor.effect_flags |= GLITTER_EDITOR_ADD; + close = true; + } + } break; + case GLITTER_EDITOR_SELECTED_EFFECT: { + if (!glitter_editor.effect_group) + break; + + glitter_effect_group* eg = glitter_editor.effect_group; + igText("%s (%016llX)", effect->name, (size_t)effect * hash_fnv1a64_empty); + igSeparator(); + if (igMenuItem_Bool("Duplicate Effect", 0, false, true)) { + glitter_editor.effect_flags |= GLITTER_EDITOR_DUPLICATE; + selected_effect = effect; + close = true; + } + + if (igMenuItem_Bool("Delete Effect", 0, false, true)) { + glitter_editor.effect_flags |= GLITTER_EDITOR_DELETE; + selected_effect = effect; + close = true; + } + + if (igMenuItem_Bool("Move Effect Up", 0, false, i_idx > 1)) { + glitter_editor.effect_flags |= GLITTER_EDITOR_MOVE_UP; + selected_effect = effect; + close = true; + } + + if (igMenuItem_Bool("Move Effect Down", 0, false, + i_idx < eg->effects.end - eg->effects.begin)) { + glitter_editor.effect_flags |= GLITTER_EDITOR_MOVE_DOWN; + selected_effect = effect; + close = true; + } + + igSeparator(); + + if (igMenuItem_Bool("Add Emitter", 0, false, true)) { + glitter_editor.emitter_flags |= GLITTER_EDITOR_ADD; + selected_effect = effect; + close = true; + } + } break; + case GLITTER_EDITOR_SELECTED_EMITTER: { + if (!selected_effect) + break; + + igText("Emitter %lld (%016llX)", j_idx, (size_t)emitter * hash_fnv1a64_empty); + igSeparator(); + if (igMenuItem_Bool("Duplicate Emitter", 0, false, true)) { + glitter_editor.emitter_flags |= GLITTER_EDITOR_DUPLICATE; + selected_emitter = emitter; + close = true; + } + + if (igMenuItem_Bool("Delete Emitter", 0, false, true)) { + glitter_editor.emitter_flags |= GLITTER_EDITOR_DELETE; + selected_emitter = emitter; + close = true; + } + + if (igMenuItem_Bool("Move Emitter Up", 0, false, j_idx > 1)) { + glitter_editor.emitter_flags |= GLITTER_EDITOR_MOVE_UP; + selected_emitter = emitter; + close = true; + } + + if (igMenuItem_Bool("Move Emitter Down", 0, false, + j_idx < selected_effect->emitters.end - selected_effect->emitters.begin)) { + glitter_editor.emitter_flags |= GLITTER_EDITOR_MOVE_DOWN; + selected_emitter = emitter; + close = true; + } + + igSeparator(); + + if (igMenuItem_Bool("Add Particle", 0, false, true)) { + glitter_editor.particle_flags |= GLITTER_EDITOR_ADD; + selected_emitter = emitter; + close = true; + } + } break; + case GLITTER_EDITOR_SELECTED_PARTICLE: { + if (!selected_emitter) + break; + + igText("Particle %lld (%016llX)", k_idx, (size_t)particle * hash_fnv1a64_empty); + igSeparator(); + if (igMenuItem_Bool("Duplicate Particle", 0, false, true)) { + glitter_editor.particle_flags |= GLITTER_EDITOR_DUPLICATE; + selected_particle = particle; + close = true; + } + + if (igMenuItem_Bool("Delete Particle", 0, false, true)) { + glitter_editor.particle_flags |= GLITTER_EDITOR_DELETE; + selected_particle = particle; + close = true; + } + + if (igMenuItem_Bool("Move Particle Up", 0, false, k_idx > 1)) { + glitter_editor.particle_flags |= GLITTER_EDITOR_MOVE_UP; + selected_particle = particle; + close = true; + } + + if (igMenuItem_Bool("Move Particle Down", 0, false, + k_idx < selected_emitter->particles.end - selected_emitter->particles.begin)) { + glitter_editor.particle_flags |= GLITTER_EDITOR_MOVE_DOWN; + selected_particle = particle; + close = true; + } + } break; + } + + if (close) { + igCloseCurrentPopup(); + selected = 0; + } + igEndPopup(); + +End: + if (!focused) + return; + + switch (type) { + case GLITTER_EDITOR_SELECTED_EFFECT: + if (selected_type != type || selected_effect != effect) + glitter_editor_reset(); + selected_effect = effect; + selected_emitter = 0; + selected_particle = 0; + break; + case GLITTER_EDITOR_SELECTED_EMITTER: + if (selected_type != type || selected_emitter != emitter) + glitter_editor_reset(); + selected_effect = effect; + selected_emitter = emitter; + selected_particle = 0; + break; + case GLITTER_EDITOR_SELECTED_PARTICLE: + if (selected_type != type || selected_particle != particle) + glitter_editor_reset(); + selected_effect = effect; + selected_emitter = emitter; + selected_particle = particle; + break; + } + selected_type = type; +} + +static void glitter_editor_resources() { + char buf[0x100]; + + ImGuiTreeNodeFlags tree_node_base_flags = 0; + tree_node_base_flags |= ImGuiTreeNodeFlags_OpenOnDoubleClick; + tree_node_base_flags |= ImGuiTreeNodeFlags_OpenOnArrow; + tree_node_base_flags |= ImGuiTreeNodeFlags_SpanAvailWidth; + + glitter_effect_group* eg = glitter_editor.effect_group; + int32_t* r = eg->resources.begin; + int32_t rc = eg->resources_count; + uint64_t* rh = eg->resource_hashes.begin; + igPushID_Ptr(eg); + ssize_t i_idx = 1; + for (int32_t i = 0; i < rc; i++, i_idx++) { + sprintf_s(buf, sizeof(buf), "Texture %d (%016llX)", i + 1, rh[i]); + igSelectable_Bool(buf, i == selected_resource, 0, (ImVec2) { 0.0f, 0.0f }); + if (igIsItemHovered(0)) { + igBeginTooltip(); + igImage((void*)(size_t)r[i], (ImVec2) { 192.0f, 192.0f }, + ImVec2_Empty, ImVec2_Identity, tint_col, border_col); + igEndTooltip(); + } + glitter_editor_resources_context_menu(i, i_idx, false); + igPopID(); + } + igPopID(); +} + +static void glitter_editor_resources_context_menu(int32_t resource, ssize_t i_idx, bool selected_none) { + bool focused = igIsItemFocused(); + + static size_t selected; + if (selected_none) { + if (igIsWindowHovered(0) && igIsMouseReleased(ImGuiMouseButton_Right)) { + igOpenPopup("resources popup", ImGuiPopupFlags_MouseButtonRight); + selected = -1; + } + else if (selected != -1) + goto End; + } + else if (igIsItemHovered(0) && igIsMouseReleased(ImGuiMouseButton_Right)) { + selected = resource; + igOpenPopup("resources popup", ImGuiPopupFlags_MouseButtonRight); + } + else if (selected != resource) + goto End; + + ImGuiWindowFlags window_flags = 0; + window_flags |= ImGuiWindowFlags_NoTitleBar; + window_flags |= ImGuiWindowFlags_AlwaysAutoResize; + + if (!igBeginPopup("resources popup", window_flags)) + goto End; + + global_context_menu = false; + + bool close = false; + if (selected_none) { + if (igMenuItem_Bool("Import Resource", 0, false, true)) { + glitter_editor.resource_flags |= GLITTER_EDITOR_IMPORT; + close = true; + } + } + else { + size_t i = resource; + glitter_effect_group* eg = glitter_editor.effect_group; + ssize_t rc = eg->resources_count; + uint64_t* rh = eg->resource_hashes.begin; + igText("Texture %lld (%016llX)", i + 1, rh[i]); + igSeparator(); + if (igMenuItem_Bool("Export Resource", 0, false, true)) { + glitter_editor.resource_flags |= GLITTER_EDITOR_EXPORT; + selected_resource = resource; + close = true; + } + + if (igMenuItem_Bool("Delete Resource", 0, false, true)) { + glitter_editor.resource_flags |= GLITTER_EDITOR_DELETE; + selected_resource = resource; + close = true; + } + + if (igMenuItem_Bool("Move Resource Up", 0, false, i_idx > 1)) { + glitter_editor.resource_flags |= GLITTER_EDITOR_MOVE_UP; + selected_resource = resource; + close = true; + } + + if (igMenuItem_Bool("Move Resource Down", 0, false, + i_idx < rc)) { + glitter_editor.resource_flags |= GLITTER_EDITOR_MOVE_DOWN; + selected_resource = resource; + close = true; + } + } + + if (close) { + igCloseCurrentPopup(); + selected = 0; + } + igEndPopup(); + +End: + if (!focused) + return; + + selected_resource = resource; +} + +static void glitter_editor_property() { + switch (selected_type) { + case GLITTER_EDITOR_SELECTED_EFFECT: + glitter_editor_property_effect(); + break; + case GLITTER_EDITOR_SELECTED_EMITTER: + glitter_editor_property_emitter(); + break; + case GLITTER_EDITOR_SELECTED_PARTICLE: + glitter_editor_property_particle(); + break; + } +} + +static void glitter_editor_property_effect() { + imguiSetColumnSpace(2.0f / 5.0f); + + glitter_effect effect = *selected_effect; + bool changed = false; + + glitter_curve_type_flags flags = glitter_effect_curve_flags; + for (glitter_curve_type i = GLITTER_CURVE_TRANSLATION_X; i <= GLITTER_CURVE_V_SCROLL_ALPHA_2ND; i++) + for (glitter_curve** j = effect.curve.begin; j != effect.curve.end; j++) + if (*j && (*j)->type == i) + flags &= ~(1 << i); + + const size_t name_size = sizeof(effect.name); + char name[sizeof(effect.name)]; + memcpy(name, effect.name, name_size); + if (imguiColumnInputText("Name", name, name_size, 0, 0, 0)) { + effect.data.name_hash = glt_type != GLITTER_AFT + ? hash_char_murmurhash(name, 0, false) : hash_char_fnv1a64(name); + memcpy(effect.name, name, name_size - 1); + changed = true; + } + + if (imguiColumnDragInt("Appear Time", + &effect.data.appear_time, 1.0f, 0x0000, 0x7FFF, "%d", 0)) + changed = true; + + if (imguiColumnDragInt("Life Time", + &effect.data.life_time, 1.0f, 0x0000, 0x7FFF - effect.data.appear_time, "%d", 0)) + changed = true; + + if (imguiColumnDragInt("Start Time", + &effect.data.start_time, 1.0f, 0x0000, 0x7FFF - effect.data.appear_time, "%d", 0)) + changed = true; + + igSeparator(); + + if (imguiColumnDragVec3Flag("Translation", + &effect.translation, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + flags & GLITTER_CURVE_TYPE_TRANSLATION_XYZ)) + changed = true; + + vec3 rotation; + vec3_mult_scalar(effect.rotation, RAD_TO_DEG_FLOAT, rotation); + if (imguiColumnDragVec3Flag("Rotation", + &rotation, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_ROTATION_XYZ) >> 3)) { + vec3_mult_scalar(rotation, DEG_TO_RAD_FLOAT, effect.rotation); + changed = true; + } + + if (imguiColumnDragVec3Flag("Scale", + &effect.scale, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_SCALE_XYZ) >> 6)) + changed = true; + + igSeparator(); + + if (imguiCheckboxFlags_UintPtr("Loop", + (uint32_t*)&effect.data.flags, + GLITTER_EFFECT_LOOP)) + changed = true; + + if (imguiCheckboxFlags_UintPtr("Alpha", + (uint32_t*)&effect.data.flags, + GLITTER_EFFECT_ALPHA)) + changed = true; + + if (imguiCheckboxFlags_UintPtr("Fog", + (uint32_t*)&effect.data.flags, + GLITTER_EFFECT_FOG)) + changed = true; + + if (imguiCheckboxFlags_UintPtr("Fog Height", + (uint32_t*)&effect.data.flags, + GLITTER_EFFECT_FOG_HEIGHT)) + changed = true; + + if (imguiCheckboxFlags_UintPtr("Use Emission", + (uint32_t*)&effect.data.flags, + GLITTER_EFFECT_EMISSION)) + changed = true; + + if (glt_type == GLITTER_X) + if (imguiCheckboxFlags_UintPtr("Use Seed", + (uint32_t*)&effect.data.flags, + GLITTER_EFFECT_USE_SEED)) + changed = true; + + if (effect.data.flags & GLITTER_EFFECT_FOG && effect.data.flags & GLITTER_EFFECT_FOG_HEIGHT) { + effect.data.flags &= ~GLITTER_EFFECT_FOG_HEIGHT; + changed = true; + } + + if (effect.data.flags & GLITTER_EFFECT_FOG_HEIGHT && effect.data.flags & GLITTER_EFFECT_FOG) { + effect.data.flags &= ~GLITTER_EFFECT_FOG; + changed = true; + } + + if (glt_type != GLITTER_X) { + bool set_emission = effect.version == 7; + if (imguiCheckbox("Set Emission", + &set_emission)) { + effect.version = set_emission ? 7 : 6; + changed = true; + } + + if (effect.version == 7 && imguiColumnDragFloat("Emission", + &effect.data.emission, 0.0001f, 0.0f, HALF_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + } + else { + if (effect.data.flags & GLITTER_EFFECT_USE_SEED + && imguiColumnInputScalar("Seed", ImGuiDataType_U32, &effect.data.seed, + 0, 0, "%08X", ImGuiInputTextFlags_CharsHexadecimal)) + changed = true; + + if (imguiColumnDragFloat("Emission", + &effect.data.emission, 0.0001f, 0.0f, HALF_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + } + + int32_t type; + if (effect.data.flags & GLITTER_EFFECT_LOCAL) + type = 1; + else if (effect.data.ext_anim) + type = effect.data.ext_anim->flags & GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM ? 2 : 3; + else + type = 0; + + if (imguiColumnComboBox("Type", glitter_effect_type_name, + 4, &type, 0, false, &glitter_editor.imgui_focus)) { + if (type == 1) { + effect.data.flags |= GLITTER_EFFECT_LOCAL; + free(effect.data.ext_anim); + } + else { + effect.data.flags &= ~GLITTER_EFFECT_LOCAL; + if (type == 2 || type == 3) { + if (!effect.data.ext_anim) + effect.data.ext_anim = force_malloc(sizeof(glitter_effect_ext_anim)); + if (type == 2) + effect.data.ext_anim->flags |= GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM; + else + effect.data.ext_anim->flags &= ~GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM; + } + else + free(effect.data.ext_anim); + } + changed = true; + } + + if (~effect.data.flags & GLITTER_EFFECT_LOCAL && effect.data.ext_anim) { + igSeparator(); + + bool ext_anim_changed = false; + glitter_effect_ext_anim ext_anim = *effect.data.ext_anim; + if (glt_type == GLITTER_X) { + if (ext_anim.flags & GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM) { + if (imguiColumnComboBox("Chara Index", glitter_effect_ext_anim_index_name, + 3, &ext_anim.index, 0, false, &glitter_editor.imgui_focus)) + ext_anim_changed = true; + + if (imguiColumnComboBox("Parent Bone", glitter_effect_ext_anim_node_index_name, + 18, &ext_anim.index, 0, false, &glitter_editor.imgui_focus)) + ext_anim_changed = true; + } + else { + uint32_t object_hash = (uint32_t)ext_anim.object_hash; + if (glitter_editor_hash_input("Object Hash", &ext_anim.object_hash)) + ext_anim_changed = true; + + imguiColumnInputScalar("Instance ID", ImGuiDataType_U32, &ext_anim.instance_id, + 0, 0, "%d", ImGuiInputTextFlags_CharsDecimal); + + if (glitter_editor_hash_input("Some Hash", &ext_anim.some_hash)) + ext_anim_changed = true; + + const size_t mesh_name_size = sizeof(ext_anim.mesh_name); + char mesh_name[sizeof(ext_anim.mesh_name)]; + memcpy(mesh_name, ext_anim.mesh_name, mesh_name_size); + if (imguiColumnInputText("Mesh Name", mesh_name, mesh_name_size, 0, 0, 0)) { + memcpy(ext_anim.mesh_name, mesh_name, mesh_name_size); + ext_anim_changed = true; + } + } + + if (imguiCheckboxFlags_UintPtr("Trans Only", + (uint32_t*)&ext_anim.flags, + GLITTER_EFFECT_EXT_ANIM_EXT_ANIM_TRANS_ONLY)) + ext_anim_changed = true; + + if (imguiCheckboxFlags_UintPtr("No Trans X", + (uint32_t*)&ext_anim.flags, + GLITTER_EFFECT_EXT_ANIM_NO_TRANS_X)) + ext_anim_changed = true; + + if (imguiCheckboxFlags_UintPtr("No Trans Y", + (uint32_t*)&ext_anim.flags, + GLITTER_EFFECT_EXT_ANIM_NO_TRANS_Y)) + ext_anim_changed = true; + + if (imguiCheckboxFlags_UintPtr("No Trans Z", + (uint32_t*)&ext_anim.flags, + GLITTER_EFFECT_EXT_ANIM_NO_TRANS_Z)) + ext_anim_changed = true; + + if (imguiCheckboxFlags_UintPtr("Get Then Update", + (uint32_t*)&ext_anim.flags, + GLITTER_EFFECT_EXT_ANIM_GET_THEN_UPDATE)) + ext_anim_changed = true; + } + else { + if (ext_anim.flags & GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM) { + const int32_t max_chara = glt_type == GLITTER_AFT ? 6 : 3; + if (imguiColumnComboBox("Chara Index", glitter_effect_ext_anim_index_name, + max_chara, &ext_anim.index, 0, false, &glitter_editor.imgui_focus)) + ext_anim_changed = true; + + if (imguiColumnComboBox("Parent Bone", glitter_effect_ext_anim_node_index_name, + 18, &ext_anim.index, 0, false, &glitter_editor.imgui_focus)) + ext_anim_changed = true; + } + else { + if (glitter_editor_hash_input("Object Hash", &ext_anim.object_hash)) + ext_anim_changed = true; + + const size_t mesh_name_size = sizeof(ext_anim.mesh_name); + char mesh_name[sizeof(ext_anim.mesh_name)]; + memcpy(mesh_name, ext_anim.mesh_name, mesh_name_size); + if (imguiColumnInputText("Mesh Name", mesh_name, mesh_name_size, 0, 0, 0)) { + memcpy(ext_anim.mesh_name, mesh_name, mesh_name_size); + ext_anim_changed = true; + } + } + + if (imguiCheckboxFlags_UintPtr("Trans Only", + (uint32_t*)&ext_anim.flags, + GLITTER_EFFECT_EXT_ANIM_EXT_ANIM_TRANS_ONLY)) + ext_anim_changed = true; + } + + uint64_t hash1 = hash_fnv1a64((void*)effect.data.ext_anim, sizeof(glitter_effect_ext_anim)); + uint64_t hash2 = hash_fnv1a64((void*)&ext_anim, sizeof(glitter_effect_ext_anim)); + if (hash1 != hash2 && ext_anim_changed) { + *effect.data.ext_anim = ext_anim; + changed = true; + } + } + + uint64_t hash1 = hash_fnv1a64((void*)selected_effect, sizeof(glitter_effect)); + uint64_t hash2 = hash_fnv1a64((void*)&effect, sizeof(glitter_effect)); + if (hash1 != hash2 && changed) { + for (glitter_emitter** i = effect.emitters.begin; i != effect.emitters.end; i++) { + if (!*i) + continue; + + glitter_emitter* emitter = *i; + for (glitter_particle** j = emitter->particles.begin; j != emitter->particles.end; j++) { + if (!*j) + continue; + + glitter_particle* particle = *j; + glitter_particle_flag flags = particle->data.flags; + if (effect.data.flags & GLITTER_EFFECT_LOCAL) + flags |= GLITTER_PARTICLE_LOCAL; + else + flags &= ~GLITTER_PARTICLE_LOCAL; + + if (effect.data.flags & GLITTER_EFFECT_EMISSION) + flags |= GLITTER_PARTICLE_EMISSION; + else + flags &= ~GLITTER_PARTICLE_EMISSION; + particle->data.flags = flags; + } + } + glitter_editor.input_reload = true; + *selected_effect = effect; + } + + imguiSetDefaultColumnSpace(); +} + +static void glitter_editor_property_emitter() { + imguiSetColumnSpace(2.0f / 5.0f); + + glitter_emitter emitter = *selected_emitter; + bool changed = false; + + glitter_curve_type_flags flags = glitter_emitter_curve_flags; + for (glitter_curve_type i = GLITTER_CURVE_TRANSLATION_X; i <= GLITTER_CURVE_V_SCROLL_ALPHA_2ND; i++) + for (glitter_curve** j = emitter.curve.begin; j != emitter.curve.end; j++) + if (*j && (*j)->type == i) + flags &= ~(1 << i); + + igText("Parent Effect:\nAppear Time: %d; Life Time: %d; Start Time: %d", + selected_effect->data.appear_time, selected_effect->data.life_time, selected_effect->data.start_time); + + igSeparator(); + + if (imguiColumnDragInt("Start Time", + &emitter.data.start_time, 1.0f, 0x0000, 0x7FFF, "%d", 0)) + changed = true; + + if (imguiColumnDragInt("Life Time", + &emitter.data.life_time, 1.0f, 0x0000, 0x7FFF, "%d", 0)) + changed = true; + + if (imguiColumnDragInt("Loop Start Time", &emitter.data.loop_start_time, + 1.0f, -0x0001, emitter.data.start_time + emitter.data.life_time, "%d", 0)) { + if (emitter.data.loop_start_time < emitter.data.start_time) + emitter.data.loop_start_time = 0; + changed = emitter.data.loop_start_time != selected_emitter->data.loop_start_time; + } + + if (imguiColumnDragInt("Loop End Time", &emitter.data.loop_end_time, + 1.0f, -0x0001, emitter.data.start_time + emitter.data.life_time, "%d", 0)) { + if (emitter.data.loop_end_time < 0) + emitter.data.loop_end_time = -1; + changed = emitter.data.loop_end_time != selected_emitter->data.loop_end_time; + } + + igSeparator(); + + if (imguiColumnDragVec3Flag("Translation", + &emitter.translation, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + flags & GLITTER_CURVE_TYPE_TRANSLATION_XYZ)) + changed = true; + + vec3 rotation; + vec3_mult_scalar(emitter.rotation, RAD_TO_DEG_FLOAT, rotation); + if (imguiColumnDragVec3Flag("Rotation", + &rotation, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_ROTATION_XYZ) >> 3)) { + vec3_mult_scalar(rotation, DEG_TO_RAD_FLOAT, emitter.rotation); + changed = true; + } + + vec3 rotation_add; + vec3_mult_scalar(emitter.data.rotation_add, RAD_TO_DEG_FLOAT, rotation_add); + if (imguiColumnDragVec3Flag("Rotation Add", + &rotation_add, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_ROTATION_XYZ) >> 3)) { + vec3_mult_scalar(rotation_add, DEG_TO_RAD_FLOAT, emitter.data.rotation_add); + changed = true; + } + + if (imguiColumnDragVec3Flag("Scale", + &emitter.scale, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_SCALE_XYZ) >> 6)) + changed = true; + + igSeparator(); + + if (imguiCheckboxFlags_UintPtr("Loop", + (uint32_t*)&emitter.data.flags, + GLITTER_EMITTER_LOOP)) + changed = true; + + if (imguiCheckboxFlags_UintPtr("Kill On End", + (uint32_t*)&emitter.data.flags, + GLITTER_EMITTER_KILL_ON_END)) + changed = true; + + if (glt_type == GLITTER_X + && imguiCheckboxFlags_UintPtr("Use Seed", + (uint32_t*)&emitter.data.flags, + GLITTER_EMITTER_USE_SEED)) + changed = true; + + igSeparator(); + + if (glt_type == GLITTER_X) { + if (emitter.data.flags & GLITTER_EMITTER_USE_SEED + && imguiColumnInputScalar("Seed", ImGuiDataType_U32, &emitter.data.seed, + 0, 0, "%08X", ImGuiInputTextFlags_CharsHexadecimal)) + changed = true; + + if (imguiColumnComboBox("Timer Type", glitter_emitter_timer_name, + GLITTER_EMITTER_TIMER_BY_DISTANCE, + (int32_t*)&emitter.data.timer, 0, true, &glitter_editor.imgui_focus)) + changed = true; + } + + float_t emission_interval_step = glt_type == GLITTER_X + && emitter.data.timer == GLITTER_EMITTER_TIMER_BY_DISTANCE ? 0.0001f : 1.0f; + if (imguiColumnDragFloatFlag(emitter.data.emission_interval >= 0.000001f ? "Emit Interval" + : (emitter.data.emission_interval <= -0.000001f + ? "Emit Interval (On End)" : "Emit Interval (On Start)"), + &emitter.data.emission_interval, emission_interval_step, -1.0f, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_EMISSION_INTERVAL) >> 20)) + changed = true; + + if (imguiColumnDragFloatFlag("PTC Per Emit", + &emitter.data.particles_per_emission, 1.0f, 0.0f, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_PARTICLES_PER_EMISSION) >> 21)) + changed = true; + + if (imguiColumnComboBox("Direction", glitter_direction_name, + GLITTER_DIRECTION_PARTICLE_ROTATION, + (int32_t*)&emitter.data.direction, 0, true, &glitter_editor.imgui_focus)) + changed = true; + + if (imguiColumnComboBox("Type", glitter_emitter_name, + GLITTER_EMITTER_POLYGON, + (int32_t*)&emitter.data.type, 0, true, &glitter_editor.imgui_focus)) + changed = true; + + igSeparator(); + + switch (emitter.data.type) { + case GLITTER_EMITTER_BOX: { + igPushID_Str("Box"); + if (imguiColumnDragVec3("Size", + &emitter.data.box.size, 0.0001f, 0.0f, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + igPopID(); + } break; + case GLITTER_EMITTER_CYLINDER: { + float_t start_angle, end_angle; + + igPushID_Str("Cylinder"); + if (imguiColumnDragFloat("Radius", + &emitter.data.cylinder.radius, 0.0001f, 0.0f, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + if (imguiColumnDragFloat("Height", + &emitter.data.cylinder.height, 0.0001f, 0.0f, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + start_angle = emitter.data.cylinder.start_angle * RAD_TO_DEG_FLOAT; + if (imguiColumnDragFloat("Start Angle", + &start_angle, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + emitter.data.cylinder.start_angle = start_angle * DEG_TO_RAD_FLOAT; + changed = true; + } + + end_angle = emitter.data.cylinder.end_angle * RAD_TO_DEG_FLOAT; + if (imguiColumnDragFloat("End Angle", + &end_angle, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + emitter.data.cylinder.end_angle = end_angle * DEG_TO_RAD_FLOAT; + changed = true; + } + + if (imguiCheckbox("On Edge", + &emitter.data.cylinder.on_edge)) + changed = true; + + if (imguiColumnComboBox("Direction", + glitter_emitter_emission_direction_name, + GLITTER_EMITTER_EMISSION_DIRECTION_INWARD, + (int32_t*)&emitter.data.cylinder.direction, 0, true, &glitter_editor.imgui_focus)) + changed = true; + igPopID(); + } break; + case GLITTER_EMITTER_SPHERE: { + float_t latitude, longitude; + + igPushID_Str("Sphere"); + if (imguiColumnDragFloat("Radius", + &emitter.data.sphere.radius, 0.0001f, 0.0f, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + latitude = emitter.data.sphere.latitude * RAD_TO_DEG_FLOAT; + if (imguiColumnDragFloat("Latitude", + &latitude, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + emitter.data.sphere.latitude = latitude * DEG_TO_RAD_FLOAT; + changed = true; + } + + longitude = emitter.data.sphere.longitude * RAD_TO_DEG_FLOAT; + if (imguiColumnDragFloat("Longitude", + &longitude, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + emitter.data.sphere.longitude = longitude * DEG_TO_RAD_FLOAT; + changed = true; + } + + if (imguiCheckbox("On Edge", + &emitter.data.sphere.on_edge)) + changed = true; + + if (imguiColumnComboBox("Direction", + glitter_emitter_emission_direction_name, + GLITTER_EMITTER_EMISSION_DIRECTION_INWARD, + (int32_t*)&emitter.data.sphere.direction, 0, true, &glitter_editor.imgui_focus)) + changed = true; + igPopID(); + } break; + case GLITTER_EMITTER_POLYGON: { + igPushID_Str("Polygon"); + if (imguiColumnDragFloat("Scale", + &emitter.data.polygon.size, 0.0001f, 0.0f, FLT_MAX, + "%g", ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + if (imguiColumnDragInt("Count", + &emitter.data.polygon.count, 1.0f, 0, 0x7FFFFF, "%d", 0)) + changed = true; + + if (glt_type == GLITTER_X) + if (imguiColumnComboBox("Direction", + glitter_emitter_emission_direction_name, + GLITTER_EMITTER_EMISSION_DIRECTION_INWARD, + (int32_t*)&emitter.data.cylinder.direction, 0, true, &glitter_editor.imgui_focus)) + changed = true; + igPopID(); + } break; + } + + uint64_t hash1 = hash_fnv1a64((void*)selected_emitter, sizeof(glitter_emitter)); + uint64_t hash2 = hash_fnv1a64((void*)&emitter, sizeof(glitter_emitter)); + if (hash1 != hash2 && changed) { + glitter_editor.input_reload = true; + *selected_emitter = emitter; + } + + imguiSetDefaultColumnSpace(); +} + +static void glitter_editor_property_particle() { + imguiSetColumnSpace(2.0f / 5.0f); + + glitter_particle particle = *selected_particle; + bool changed = false; + + glitter_curve_type_flags flags = 0; + if (glt_type == GLITTER_X) + flags = glitter_particle_x_curve_flags; + else + flags = glitter_particle_curve_flags; + + if (particle.data.type != GLITTER_PARTICLE_MESH) { + flags &= ~GLITTER_CURVE_TYPE_UV_SCROLL_2ND; + if (particle.data.draw_type != GLITTER_DIRECTION_PARTICLE_ROTATION) + flags &= ~(GLITTER_CURVE_TYPE_ROTATION_X | GLITTER_CURVE_TYPE_ROTATION_Y); + } + + if (particle.data.sub_flags & GLITTER_PARTICLE_SUB_USE_CURVE) + for (glitter_curve_type i = GLITTER_CURVE_TRANSLATION_X; i <= GLITTER_CURVE_V_SCROLL_ALPHA_2ND; i++) + for (glitter_curve** j = particle.curve.begin; j != particle.curve.end; j++) + if (*j && (*j)->type == i) + flags &= ~(1 << i); + + igText("Parent Effect:\nAppear Time: %d; Life Time: %d; Start Time: %d", + selected_effect->data.appear_time, selected_effect->data.life_time, selected_effect->data.start_time); + + igText("Parent Emitter:\nStart Time: %d; Life Time: %d\nLoop Start Time: %d; Loop End Time: %d", + selected_emitter->data.start_time, selected_emitter->data.life_time, + selected_emitter->data.loop_start_time, selected_emitter->data.loop_end_time); + + igSeparator(); + + bool flags_changed = false; + if (imguiCheckboxFlags_UintPtr("Loop", + (uint32_t*)&particle.data.flags, + GLITTER_PARTICLE_LOOP)) + flags_changed = true; + + if (imguiCheckboxFlags_UintPtr("Emitter Local", + (uint32_t*)&particle.data.flags, + GLITTER_PARTICLE_EMITTER_LOCAL)) + flags_changed = true; + + if (imguiCheckboxFlags_UintPtr("Scale Y by X", + (uint32_t*)&particle.data.flags, + GLITTER_PARTICLE_SCALE_Y_BY_X)) + flags_changed = true; + + if (imguiCheckboxFlags_UintPtr("Rebound Plane", + (uint32_t*)&particle.data.flags, + GLITTER_PARTICLE_REBOUND_PLANE)) + flags_changed = true; + + if (imguiCheckboxFlags_UintPtr("Rotate by Emitter", + (uint32_t*)&particle.data.flags, + GLITTER_PARTICLE_ROTATE_BY_EMITTER)) + flags_changed = true; + + if (imguiCheckboxFlags_UintPtr("Use Scale", + (uint32_t*)&particle.data.flags, + GLITTER_PARTICLE_SCALE)) + flags_changed = true; + + if (imguiCheckboxFlags_UintPtr("Second Texture", + (uint32_t*)&particle.data.flags, + GLITTER_PARTICLE_SECOND_TEXTURE)) + flags_changed = true; + + if (glt_type == GLITTER_X) { + if (imguiCheckboxFlags_UintPtr("Depth Test", + (uint32_t*)&particle.data.flags, + GLITTER_PARTICLE_DEPTH_TEST)) + flags_changed = true; + + imguiDisableElementPush(particle.data.type == GLITTER_PARTICLE_LOCUS); + if (imguiCheckboxFlags_UintPtr("Rotate Locus", + (uint32_t*)&particle.data.flags, + GLITTER_PARTICLE_ROTATE_LOCUS)) + flags_changed = true; + imguiDisableElementPop(particle.data.type == GLITTER_PARTICLE_LOCUS); + } + + if (flags_changed) + changed = true; + + igSeparator(); + + if (glt_type == GLITTER_X) { + vec2i life_time; + life_time.x = particle.data.life_time; + life_time.y = particle.data.life_time_random; + if (imguiColumnDragVec2I("Life Time [R]", + &life_time, 1.0f, 0x0000, 0x7FFF, "%d", 0)) { + particle.data.life_time = life_time.x; + particle.data.life_time_random = life_time.y; + changed = true; + } + + vec2i fade_in; + fade_in.x = particle.data.fade_in; + fade_in.y = particle.data.fade_in_random; + if (imguiColumnDragVec2I("Fade In [R]", + &fade_in, 1.0f, 0x0000, 0x7FFF, "%d", 0)) { + particle.data.fade_in = fade_in.x; + particle.data.fade_in_random = fade_in.y; + changed = true; + } + + vec2i fade_out; + fade_out.x = particle.data.fade_out; + fade_out.y = particle.data.fade_out_random; + if (imguiColumnDragVec2I("Fade Out [R]", + &fade_out, 1.0f, 0x0000, 0x7FFF, "%d", 0)) { + particle.data.fade_out = fade_out.x; + particle.data.fade_out_random = fade_out.y; + changed = true; + } + + if (imguiColumnComboBox("Type", glitter_particle_name, + GLITTER_PARTICLE_MESH, + (int32_t*)&particle.data.type, 0, true, &glitter_editor.imgui_focus)) + changed = true; + } + else { + if (imguiColumnDragInt("Life Time", + &particle.data.life_time, 1.0f, 0x0000, 0x7FFF, "%d", 0)) + changed = true; + + if (imguiColumnComboBox("Type", glitter_particle_name, + GLITTER_PARTICLE_LOCUS, + (int32_t*)&particle.data.type, 0, true, &glitter_editor.imgui_focus)) + changed = true; + } + + if (particle.data.type != GLITTER_PARTICLE_MESH) + if (imguiColumnComboBox("Pivot", glitter_pivot_name, + GLITTER_PIVOT_BOTTOM_RIGHT, + (int32_t*)&particle.data.pivot, 0, true, &glitter_editor.imgui_focus)) + changed = true; + + if (particle.data.type == GLITTER_PARTICLE_QUAD || particle.data.type == GLITTER_PARTICLE_MESH) + if (imguiColumnComboBox("Draw Type", glitter_direction_name, + GLITTER_DIRECTION_PARTICLE_ROTATION, + (int32_t*)&particle.data.draw_type, 0, true, &glitter_editor.imgui_focus)) + changed = true; + + if (particle.data.type == GLITTER_PARTICLE_QUAD) + if (imguiColumnDragFloat("Z Offset", + &particle.data.z_offset, 0.0001f, -FLT_MAX, FLT_MAX, + "%g", ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + igSeparator(); + + vec3 rotation; + vec3_mult_scalar(particle.data.rotation, RAD_TO_DEG_FLOAT, rotation); + if (imguiColumnDragVec3Flag("Rotation", + &rotation, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_ROTATION_XYZ) >> 3)) { + vec3_mult_scalar(rotation, DEG_TO_RAD_FLOAT, particle.data.rotation); + changed = true; + } + + vec3 rotation_random; + vec3_mult_scalar(particle.data.rotation_random, RAD_TO_DEG_FLOAT, rotation_random); + if (imguiColumnDragVec3Flag("Rotation Random", + &rotation_random, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_ROTATION_XYZ) >> 3)) { + vec3_mult_scalar(rotation_random, DEG_TO_RAD_FLOAT, particle.data.rotation_random); + changed = true; + } + + vec3 rotation_add; + vec3_mult_scalar(particle.data.rotation_add, RAD_TO_DEG_FLOAT, rotation_add); + if (imguiColumnDragVec3Flag("Rotation Add", + &rotation_add, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_ROTATION_XYZ) >> 3)) { + vec3_mult_scalar(rotation_add, DEG_TO_RAD_FLOAT, particle.data.rotation_add); + changed = true; + } + + vec3 rotation_add_random; + vec3_mult_scalar(particle.data.rotation_add_random, RAD_TO_DEG_FLOAT, rotation_add_random); + if (imguiColumnDragVec3Flag("Rotation Add Random", + &rotation_add_random, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + (flags & GLITTER_CURVE_TYPE_ROTATION_XYZ) >> 3)) { + vec3_mult_scalar(rotation_add_random, DEG_TO_RAD_FLOAT, particle.data.rotation_add_random); + changed = true; + } + + imguiDisableElementPush(particle.data.type != GLITTER_PARTICLE_MESH); + if (imguiColumnDragVec2Flag("Scale", + (vec2*)&particle.data.scale, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + particle.data.flags & GLITTER_PARTICLE_SCALE_Y_BY_X ? 0x01 : 0x03)) + changed = true; + + if (imguiColumnDragVec2Flag("Scale Random", + (vec2*)&particle.data.scale_random, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat, + particle.data.flags & GLITTER_PARTICLE_SCALE_Y_BY_X ? 0x01 : 0x03)) + changed = true; + imguiDisableElementPop(particle.data.type != GLITTER_PARTICLE_MESH); + + igSeparator(); + + if (imguiColumnDragVec3("Direction", + &particle.data.direction, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + if (imguiColumnDragVec3("Direction Random", + &particle.data.direction_random, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + vec2 speed; + speed.x = particle.data.speed; + speed.y = particle.data.speed_random; + if (imguiColumnDragVec2("Speed [R]", + &speed, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + particle.data.speed = speed.x; + particle.data.speed_random = speed.y; + changed = true; + } + + vec2 deceleration; + deceleration.x = particle.data.deceleration; + deceleration.y = particle.data.deceleration_random; + if (imguiColumnDragVec2("Deceleration [R]", + &deceleration, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + particle.data.deceleration = deceleration.x; + particle.data.deceleration_random = deceleration.y; + changed = true; + } + + if (imguiColumnDragVec3("Gravity", + &particle.data.gravity, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + if (imguiColumnDragVec3("Acceleration", + &particle.data.acceleration, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + if (imguiColumnDragVec3("Acceleration Random", + &particle.data.acceleration_random, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + vec2 reflection_coeff; + reflection_coeff.x = particle.data.reflection_coeff; + reflection_coeff.y = particle.data.reflection_coeff_random; + if (imguiColumnDragVec2("Refl Coeff [R]", + &reflection_coeff, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + particle.data.reflection_coeff = reflection_coeff.x; + particle.data.reflection_coeff_random = reflection_coeff.y; + changed = true; + } + + if (imguiColumnDragFloat("Rebound Plane Y", + &particle.data.rebound_plane_y, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + igSeparator(); + + vec4 color; + vec4i color_int; + vec4_mult_scalar(particle.data.color, 255.0f, color); + vec4_to_vec4i(color, color_int); + if (imguiColumnDragVec4IFlag("Color", + &color_int, 1.0f, 0x00, 0xFF, "%d", 0, + (flags & GLITTER_CURVE_TYPE_COLOR_RGBA) >> 10)) { + vec4i_to_vec4(color_int, color); + vec4_mult_scalar(color, (float_t)(1.0 / 255.0), particle.data.color); + changed = true; + } + + if (imguiColumnComboBox("UV Index Type", glitter_uv_index_type_name, + GLITTER_UV_INDEX_USER, + (int32_t*)&particle.data.uv_index_type, 0, true, &glitter_editor.imgui_focus)) + changed = true; + + vec2i split; + split.x = particle.data.split_u; + split.y = particle.data.split_v; + if (imguiColumnDragVec2I("UV Split", + &split, 1.0f, 1, 128, "%d", 0)) { + particle.data.split_u = (uint8_t)(1 << (int32_t)log2f((float_t)split.x)); + particle.data.split_v = (uint8_t)(1 << (int32_t)log2f((float_t)split.y)); + + particle.data.split_uv.x = 1.0f / (float_t)particle.data.split_u; + particle.data.split_uv.y = 1.0f / (float_t)particle.data.split_v; + changed = true; + } + + int32_t uv_max_count = (int32_t)(particle.data.split_u * particle.data.split_v); + if (uv_max_count) + uv_max_count--; + + if (imguiColumnDragInt("Frame Step UV", + &particle.data.frame_step_uv, 1.0f, 0x0000, 0x7FFF, "%d", 0)) + changed = true; + + if (imguiColumnDragInt("UV Index Start", + &particle.data.uv_index_start, 1.0f, 0, uv_max_count, "%d", 0)) + changed = true; + + if (imguiColumnDragInt("UV Index End", + &particle.data.uv_index_end, 1.0f, particle.data.uv_index_start, uv_max_count, "%d", 0)) + changed = true; + + if (imguiColumnDragInt("UV Index", + &particle.data.uv_index, 1.0f, particle.data.uv_index_start, + particle.data.uv_index_end, "%d", 0)) + changed = true; + + if (imguiColumnDragVec2("UV Scroll Add", + &particle.data.uv_scroll_add, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + if (imguiColumnDragFloat("UV Scroll Add Scale", + &particle.data.uv_scroll_add_scale, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + if (particle.data.type != GLITTER_PARTICLE_MESH) { + int32_t idx0 = 0; + int32_t idx1 = 0; + glitter_effect_group* eg = glitter_editor.effect_group; + size_t rc = eg->resources_count; + uint64_t* rh = eg->resource_hashes.begin; + for (size_t i = 0; i < rc && (!idx0 || !idx1); i++) { + if (idx0 == 0 && rh[i] == particle.data.tex_hash0) + idx0 = (int32_t)(i + 1); + + if (idx1 == 0 && rh[i] == particle.data.tex_hash1) + idx1 = (int32_t)(i + 1); + } + + char** texture_name_list = force_malloc_s(char*, rc + 1); + char* texture_names = force_malloc_s(char[0x40], rc + 1); + + texture_name_list[0] = texture_names; + snprintf(texture_name_list[0], 0x40, "No Texture"); + for (size_t i = 0; i < rc; i++) + snprintf(texture_name_list[i + 1] = &texture_names[0x40 * (i + 1)], + 0x40, "Texture %lld (%016llX)", i + 1, rh[i]); + + static bool tex0_anim; + static int32_t tex0_frame; + static int32_t tex0_index; + static int32_t tex0_tex; + if (glitter_editor_property_particle_texture("Texture 0", texture_name_list, + &particle, &particle.data.texture0, &particle.data.tex_hash0, + idx0, &tex0_anim, &tex0_frame, &tex0_index, &tex0_tex)) + changed = true; + + if (particle.data.flags & GLITTER_PARTICLE_SECOND_TEXTURE) { + static bool tex11_anim; + static int32_t tex1_frame; + static int32_t tex1_index; + static int32_t tex1_tex; + if (glitter_editor_property_particle_texture("Texture 1", texture_name_list, + &particle, &particle.data.texture1, &particle.data.tex_hash1, + idx0, &tex11_anim, &tex1_frame, &tex1_index, &tex1_tex)) + changed = true; + } + free(texture_names); + free(texture_name_list); + + if (imguiColumnComboBox("Blend Mode 0", glitter_particle_blend_name, + GLITTER_PARTICLE_BLEND_PUNCH_THROUGH, + (int32_t*)&particle.data.blend_mode0, 0, true, &glitter_editor.imgui_focus)) + changed = true; + + if (particle.data.flags & GLITTER_PARTICLE_SECOND_TEXTURE + && imguiColumnComboBox("Blend Mode 1", glitter_particle_blend_name, + GLITTER_PARTICLE_BLEND_PUNCH_THROUGH, + (int32_t*)&particle.data.blend_mode1, 0, true, &glitter_editor.imgui_focus)) + changed = true; + } + + switch (particle.data.uv_index_type) { + case GLITTER_UV_INDEX_FIXED: + case GLITTER_UV_INDEX_RANDOM: + case GLITTER_UV_INDEX_FORWARD: + case GLITTER_UV_INDEX_REVERSE: + case GLITTER_UV_INDEX_USER: + particle.data.uv_index &= uv_max_count; + break; + case GLITTER_UV_INDEX_INITIAL_RANDOM_FIXED: + case GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD: + case GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE: + if (particle.data.uv_index < particle.data.uv_index_start) + particle.data.uv_index = particle.data.uv_index_start; + else if (particle.data.uv_index_end >= 0 && particle.data.uv_index > particle.data.uv_index_end) + particle.data.uv_index = particle.data.uv_index_end; + + particle.data.uv_index = min(particle.data.uv_index, uv_max_count); + break; + } + + if (particle.data.uv_index_end >= 0) + particle.data.uv_index_count = particle.data.uv_index_end - particle.data.uv_index_start + 1; + else + particle.data.uv_index_count = uv_max_count - particle.data.uv_index_start; + + if (particle.data.uv_index_count < 0) + particle.data.uv_index_count = 0; + + if (imguiCheckboxFlags_UintPtr("Use Animation Curve", + (uint32_t*)&particle.data.sub_flags, + GLITTER_PARTICLE_SUB_USE_CURVE)) + changed = true; + + igSeparator(); + + if (glt_type != GLITTER_X || particle.data.type == GLITTER_PARTICLE_QUAD) + if (imguiColumnDragInt("Count", + &particle.data.count, 1.0f, 0x0000, 0x7FFFFF, "%d", 0)) + changed = true; + + if (imguiColumnDragFloat("Emission", + &particle.data.emission, 0.0001f, 0.0f, HALF_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) + changed = true; + + if (particle.data.type == GLITTER_PARTICLE_LOCUS) { + if (imguiColumnDragInt("Locus Hist Size", + &particle.data.locus_history_size, 1.0f, 0x0000, 0x7FFFFF, "%d", 0)) + changed = true; + + if (imguiColumnDragInt("Locus Hist Size Rand", + &particle.data.locus_history_size_random, 1.0f, 0x0000, 0x7FFFFF, "%d", 0)) + changed = true; + } + else if (particle.data.type == GLITTER_PARTICLE_MESH) { + igSeparator(); + + glitter_particle_mesh* mesh = &particle.data.mesh; + if (glitter_editor_hash_input("Object Name Hash", &mesh->object_name_hash)) + changed = true; + + if (glitter_editor_hash_input("Object File Hash", &mesh->object_file_hash)) + changed = true; + + const size_t object_mesh_name_size = sizeof(mesh->object_mesh_name); + char object_mesh_name[sizeof(mesh->object_mesh_name)]; + memcpy(object_mesh_name, mesh->object_mesh_name, object_mesh_name_size); + if (imguiColumnInputText("Object Mesh Name", object_mesh_name, object_mesh_name_size, 0, 0, 0)) { + memcpy(mesh->object_mesh_name, object_mesh_name, object_mesh_name_size); + changed = true; + } + + if (glitter_editor_hash_input("Some Hash", &mesh->some_hash)) + changed = true; + } + + uint64_t hash1 = hash_fnv1a64((void*)selected_particle, sizeof(glitter_particle)); + uint64_t hash2 = hash_fnv1a64((void*)&particle, sizeof(glitter_particle)); + if (hash1 != hash2 && changed) { + glitter_editor.input_reload = true; + *selected_particle = particle; + } + + imguiSetDefaultColumnSpace(); +} + +static bool glitter_editor_property_particle_texture(char* label, char** items, + glitter_particle* particle, int32_t* tex, uint64_t* tex_hash, int32_t texture, + bool* tex_anim, int32_t* tex_frame, int32_t* tex_index, int32_t* tex_tex) { + const uint64_t empty_hash = glt_type != GLITTER_AFT + ? hash_murmurhash_empty : hash_fnv1a64_empty; + + glitter_effect_group* eg = glitter_editor.effect_group; + size_t rc = eg->resources_count; + int32_t* r = eg->resources.begin; + uint64_t* rh = eg->resource_hashes.begin; + txp* rt = eg->resources_tex.begin; + + ImVec2 uv_min; + ImVec2 uv_max; + + const char* temp_label = imguiStartPropertyColumn(label); + int32_t prev_texture = texture; + if (igBeginCombo(temp_label, items[texture], 0)) { + int32_t uv_index = *tex_index; + if (!*tex_anim) { + *tex_anim = true; + *tex_frame = 0; + *tex_tex = texture; + + uv_index = particle->data.uv_index; + int32_t max_uv = particle->data.split_u * particle->data.split_v; + if (max_uv > 1 && particle->data.uv_index_count > 1) { + switch (particle->data.uv_index_type) { + case GLITTER_UV_INDEX_INITIAL_RANDOM_FIXED: + case GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD: + case GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE: { + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + uv_index += time.LowPart % particle->data.uv_index_count; + } break; + } + } + } + else if (particle->data.uv_index_type == GLITTER_UV_INDEX_INITIAL_RANDOM_FIXED) { + if (particle->data.uv_index_count > 0 && *tex_frame % 40 == 0) { + uv_index = particle->data.uv_index; + + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + uv_index += time.LowPart % particle->data.uv_index_count; + } + } + else if (particle->data.frame_step_uv && *tex_frame % particle->data.frame_step_uv == 0) { + int32_t max_uv = particle->data.split_u * particle->data.split_v; + if (max_uv) + max_uv--; + + switch (particle->data.uv_index_type) { + case GLITTER_UV_INDEX_RANDOM: + uv_index = particle->data.uv_index_start; + if (particle->data.uv_index_count > 1) { + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + uv_index += time.LowPart % particle->data.uv_index_count; + } + break; + case GLITTER_UV_INDEX_FORWARD: + case GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD: + uv_index = (uint8_t)(max_uv & (uv_index + 1)); + break; + case GLITTER_UV_INDEX_REVERSE: + case GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE: + uv_index = (uint8_t)(max_uv & (uv_index - 1)); + break; + } + } + *tex_index = uv_index; + + vec2 uv; + uv.x = (float_t)(uv_index % particle->data.split_u) * particle->data.split_uv.x; + uv.y = (float_t)(uv_index / particle->data.split_u) * particle->data.split_uv.y; + uv_min.x = uv.x; + uv_min.y = uv.y; + uv_max.x = uv.x + particle->data.split_uv.x; + uv_max.y = uv.y + particle->data.split_uv.y; + + for (int32_t n = 0; n <= rc; n++) { + igPushID_Int(n); + if (igSelectable_Bool(items[n], texture == n, 0, ImVec2_Empty) + || imguiItemKeyPressed(GLFW_KEY_ENTER, true)) + texture = n; + + if (igIsItemHovered(0) && n) { + if (*tex_tex != n) { + *tex_anim = true; + *tex_frame = 0; + *tex_tex = n; + + uv_index = particle->data.uv_index; + int32_t max_uv = particle->data.split_u * particle->data.split_v; + if (max_uv > 1) { + switch (particle->data.uv_index_type) { + case GLITTER_UV_INDEX_INITIAL_RANDOM_FIXED: + case GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD: + case GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE: { + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + uv_index += time.LowPart % particle->data.uv_index_count; + } break; + } + } + *tex_index = uv_index; + + vec2 uv; + uv.x = (float_t)(uv_index % particle->data.split_u) * particle->data.split_uv.x; + uv.y = (float_t)(uv_index / particle->data.split_u) * particle->data.split_uv.y; + uv_min.x = uv.x; + uv_min.y = uv.y; + uv_max.x = uv.x + particle->data.split_uv.x; + uv_max.y = uv.y + particle->data.split_uv.y; + } + + ImVec2 size1 = (ImVec2){ 128.0f, 128.0f }; + ImVec2 size2 = (ImVec2){ 128.0f, 128.0f }; + + txp_mipmap* rtm = rt[n - 1].data.begin; + float_t aspect1 = (float_t)rtm->width / (float_t)rtm->height; + float_t aspect2 = aspect1; + if (particle->data.split_u * particle->data.split_v > 1) { + float_t uv_aspect = (float_t)particle->data.split_u + / (float_t)particle->data.split_v; + if (uv_aspect > 1.0f) + aspect2 /= uv_aspect; + else if (uv_aspect < 1.0f) + aspect2 *= uv_aspect; + } + + if (aspect1 > 1.0f) + size1.y /= aspect1; + else if (aspect1 < 1.0f) + size1.x *= aspect1; + + if (aspect2 > 1.0f) + size2.y /= aspect2; + else if (aspect2 < 1.0f) + size2.x *= aspect2; + + igBeginTooltip(); + igText("Frame: %d\nUV Index %d", *tex_frame, *tex_index); + igImage((void*)(size_t)r[n - 1], size1, ImVec2_Empty, ImVec2_Identity, tint_col, border_col); + igImage((void*)(size_t)r[n - 1], size2, uv_min, uv_max, tint_col, border_col); + igEndTooltip(); + } + + if (texture == n) + igSetItemDefaultFocus(); + igPopID(); + } + + glitter_editor.imgui_focus |= igIsWindowFocused(0); + igEndCombo(); + (*tex_frame)++; + } + else { + *tex_anim = false; + *tex_frame = 0; + *tex_index = 0; + *tex_tex = 0; + } + bool res = prev_texture != texture; + imguiEndPropertyColumn(temp_label); + + if (res) + if (texture) { + *tex = r[texture - 1]; + *tex_hash = rh[texture - 1]; + } + else { + *tex = 0; + *tex_hash = empty_hash; + } + return res; +} + +static void glitter_editor_popups() { + ImGuiIO* io = igGetIO(); + ImGuiStyle* style = igGetStyle(); + ImFont* font = igGetFont(); + + const float_t title_bar_size = font->FontSize + style->ItemSpacing.y + style->FramePadding.y * 2.0f; + + igPushID_Str("Glitter Editor Glitter File Create Pop-up"); + glitter_editor_file_create_popup(io, style, font, title_bar_size); + igPopID(); + + igPushID_Str("Glitter Editor Glitter File Load Pop-up"); + glitter_editor_file_load_popup(io, style, font, title_bar_size); + igPopID(); + + igPushID_Str("Glitter Editor Glitter File Load Error List Pop-up"); + glitter_editor_file_load_error_list_popup(io, style, font, title_bar_size); + igPopID(); + + igPushID_Str("Glitter Editor Glitter File Save"); + glitter_editor_file_save_popup(io, style, font, title_bar_size); + igPopID(); +} + +static void glitter_editor_file_create_popup(ImGuiIO* io, + ImGuiStyle* style, ImFont* font, const float_t title_bar_size) { + float_t x; + float_t y; + float_t w; + float_t h; + float_t win_x; + float_t win_y; + + ImGuiWindowFlags window_flags; + + if (glitter_editor.create_popup) { + igOpenPopup("Create Glitter File as...", 0); + glitter_editor.create_popup = false; + } + + const float_t button_width = 60.0f; + + win_x = button_width * 3.0f + style->ItemSpacing.x * 2.0f; + win_y = title_bar_size + font->FontSize + style->ItemSpacing.y * 2.0f + style->FramePadding.y * 3.0f; + + x = (float_t)width * 0.5f - win_x * 0.5f; + y = (float_t)height * 0.5f - win_y * 0.5f; + w = win_x; + h = win_y; + + window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoScrollbar; + window_flags |= ImGuiWindowFlags_NoScrollWithMouse; + + igPushStyleVar_Vec2(ImGuiStyleVar_WindowTitleAlign, (ImVec2) { 0.5f, 0.5f }); + igSetNextWindowPos((ImVec2) { x, y }, ImGuiCond_Always, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Always); + if (igBeginPopupModal("Create Glitter File as...", 0, window_flags)) { + ImVec2 t; + igGetContentRegionAvail(&t); + x = win_x * 0.5f - t.x * 0.5f; + y = title_bar_size; + + igSetCursorPos((ImVec2) { x, y }); + igGetContentRegionAvail(&t); + if (igBeginTable("buttons", 2, 0, ImVec2_Empty, 0.0f)) { + bool close = false; + + igTableNextColumn();; + igGetContentRegionAvail(&t); + if (imguiButton("F2nd", t)) { + glt_type = GLITTER_F2; + close = true; + } + + igTableNextColumn();; + igGetContentRegionAvail(&t); + if (imguiButton("AFT", t)) { + glt_type = GLITTER_AFT; + close = true; + } + + /*igTableNextColumn(); + igGetContentRegionAvail(&t); + if (imguiButton("X", t)) { + glt_type = GLITTER_X; + close = true; + }*/ + + if (close) { + glitter_editor.effect_group_add = true; + glitter_editor.effect_flags |= GLITTER_EDITOR_ADD; + igCloseCurrentPopup(); + } + igEndTable(); + } + glitter_editor.imgui_focus |= igIsWindowFocused(0); + igEndPopup(); + } + igEnd(); + igPopStyleVar(1); +} + +static void glitter_editor_file_load_popup(ImGuiIO* io, + ImGuiStyle* style, ImFont* font, const float_t title_bar_size) { + float_t x; + float_t y; + float_t w; + float_t h; + float_t win_x; + float_t win_y; + + ImGuiWindowFlags window_flags; + + if (glitter_editor.load_popup) { + igOpenPopup("Load Glitter File as...", 0); + glitter_editor.load_popup = false; + } + + const float_t button_width = 60.0f; + + win_x = button_width * 3.0f + style->ItemSpacing.x * 2.0f; + win_y = title_bar_size + font->FontSize + style->ItemSpacing.y * 2.0f + style->FramePadding.y * 3.0f; + + x = (float_t)width * 0.5f - win_x * 0.5f; + y = (float_t)height * 0.5f - win_y * 0.5f; + w = win_x; + h = win_y; + + window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoScrollbar; + window_flags |= ImGuiWindowFlags_NoScrollWithMouse; + + igPushStyleVar_Vec2(ImGuiStyleVar_WindowTitleAlign, (ImVec2) { 0.5f, 0.5f }); + igSetNextWindowPos((ImVec2) { x, y }, ImGuiCond_Always, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Always); + if (igBeginPopupModal("Load Glitter File as...", 0, window_flags)) { + ImVec2 t; + igGetContentRegionAvail(&t); + x = win_x * 0.5f - t.x * 0.5f; + y = title_bar_size; + + igSetCursorPos((ImVec2) { x, y }); + igGetContentRegionAvail(&t); + if (igBeginTable("buttons", 2, 0, ImVec2_Empty, 0.0f)) { + bool close = false; + + igTableNextColumn();; + igGetContentRegionAvail(&t); + if (imguiButton("F2nd", t)) { + glt_type = GLITTER_F2; + close = true; + } + + igTableNextColumn();; + igGetContentRegionAvail(&t); + if (imguiButton("AFT", t)) { + glt_type = GLITTER_AFT; + close = true; + } + + /*igTableNextColumn(); + igGetContentRegionAvail(&t); + if (imguiButton("X", t)) { + glt_type = GLITTER_X; + close = true; + }*/ + + if (close) { + glitter_editor.load = true; + igCloseCurrentPopup(); + } + igEndTable(); + } + glitter_editor.imgui_focus |= igIsWindowFocused(0); + igEndPopup(); + } + igEnd(); + igPopStyleVar(1); +} + +static void glitter_editor_file_load_error_list_popup(ImGuiIO* io, + ImGuiStyle* style, ImFont* font, const float_t title_bar_size) { + float_t x; + float_t y; + float_t w; + float_t h; + float_t win_x; + float_t win_y; + + ImGuiWindowFlags window_flags; + + if (glitter_editor.load_error_list_popup) { + igOpenPopup("Glitter File Load Error", 0); + glitter_editor.load_error_list_popup = false; + } + + win_x = 264.0f; + win_y = title_bar_size + font->FontSize * 3.0f + + style->ItemSpacing.y * 3.0f + style->FramePadding.y * 2.0f; + + x = (float_t)width * 0.5f - win_x * 0.5f; + y = (float_t)height * 0.5f - win_y * 0.5f; + w = win_x; + h = win_y; + + window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoScrollbar; + window_flags |= ImGuiWindowFlags_NoScrollWithMouse; + + igPushStyleVar_Vec2(ImGuiStyleVar_WindowTitleAlign, (ImVec2) { 0.5f, 0.5f }); + igSetNextWindowPos((ImVec2) { x, y }, ImGuiCond_Always, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Always); + if (igBeginPopupModal("Glitter File Load Error", 0, window_flags)) { + igSetCursorPosY(title_bar_size); + igText("Can't find name in Glitter List File\n" + "for hash in Glitter Effect File"); + + ImVec2 t; + igGetContentRegionAvail(&t); + igSetCursorPosX(t.x * 0.5f - 20.0f); + + x = 40.0f; + y = font->FontSize + style->FramePadding.y * 2.0f; + if (imguiButton("OK", (ImVec2) { x, y })) + igCloseCurrentPopup(); + glitter_editor.imgui_focus |= igIsWindowFocused(0); + igEndPopup(); + } + igEnd(); + igPopStyleVar(1); +} + +static void glitter_editor_file_save_popup(ImGuiIO* io, + ImGuiStyle* style, ImFont* font, const float_t title_bar_size) { + float_t x; + float_t y; + float_t w; + float_t h; + float_t win_x; + float_t win_y; + + ImGuiWindowFlags window_flags; + + if (glitter_editor.save_popup) { + igOpenPopup("Save Glitter File as...", 0); + glitter_editor.save_popup = false; + } + + const float_t button_width = 60.0f; + + win_x = button_width * 4.0f + style->ItemSpacing.x * 3.0f; + win_y = title_bar_size + font->FontSize + style->ItemSpacing.y * 2.0f + style->FramePadding.y * 3.0f; + + x = (float_t)width * 0.5f - win_x * 0.5f; + y = (float_t)height * 0.5f - win_y * 0.5f; + w = win_x; + h = win_y; + + window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoScrollbar; + window_flags |= ImGuiWindowFlags_NoScrollWithMouse; + + igPushStyleVar_Vec2(ImGuiStyleVar_WindowTitleAlign, (ImVec2) { 0.5f, 0.5f }); + igSetNextWindowPos((ImVec2) { x, y }, ImGuiCond_Always, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Always); + if (igBeginPopupModal("Save Glitter File as...", 0, window_flags)) { + ImVec2 t; + igGetContentRegionAvail(&t); + x = win_x * 0.5f - t.x * 0.5f; + y = title_bar_size; + + igSetCursorPos((ImVec2) { x, y }); + igGetContentRegionAvail(&t); + if (igBeginTable("buttons", 4, 0, ImVec2_Empty, 0.0f)) { + bool close = false; + + igTableNextColumn();; + igGetContentRegionAvail(&t); + if (imguiButton("F2 PSV", t)) { + glitter_editor.save = true; + glitter_editor.save_compress = false; + glitter_editor.save_glt_type = GLITTER_F2; + close = true; + } + + igTableNextColumn();; + igGetContentRegionAvail(&t); + if (imguiButton("F2 PS3", t)) { + glitter_editor.save = true; + glitter_editor.save_compress = true; + glitter_editor.save_glt_type = GLITTER_F2; + close = true; + } + + igTableNextColumn();; + igGetContentRegionAvail(&t); + if (imguiButton("AFT", t)) { + glitter_editor.save = true; + glitter_editor.save_compress = false; + glitter_editor.save_glt_type = GLITTER_AFT; + close = true; + } + + igTableNextColumn(); + igGetContentRegionAvail(&t); + if (imguiButton("None", t)) { + glitter_editor.save = false; + glitter_editor.save_compress = false; + close = true; + } + + if (close) + igCloseCurrentPopup(); + igEndTable(); + } + glitter_editor.imgui_focus |= igIsWindowFocused(0); + igEndPopup(); + } + igEnd(); + igPopStyleVar(1); +} + +static float_t convert_height_to_value(float_t val, float_t pos, float_t size, float_t min, float_t max) { + float_t t = (val - pos - curve_editor.height_offset) / (size - curve_editor.height_offset); + return (1.0f - t) * (max - min) + min; +} +static float_t convert_value_to_height(float_t val, float_t pos, float_t size, float_t min, float_t max) { + float_t t = 1.0f - (val - min) / (max - min); + return pos + t * (size - curve_editor.height_offset) + curve_editor.height_offset; +} + +static void glitter_editor_curve_editor() { + if (curve_editor.type < GLITTER_CURVE_TRANSLATION_X + || curve_editor.type > GLITTER_CURVE_V_SCROLL_ALPHA_2ND) + return; + + switch (selected_type) { + case GLITTER_EDITOR_SELECTED_EFFECT: + case GLITTER_EDITOR_SELECTED_EMITTER: + case GLITTER_EDITOR_SELECTED_PARTICLE: + break; + default: + return; + } + + glitter_curve* curve = &curve_editor.curve; + vector_glitter_curve_key keys = curve->keys_rev; + bool changed = false; + + bool add_key = false; + bool del_key = false; + glitter_editor_curve_editor_key_manager(&keys, &add_key, &del_key); + + if (igIsWindowFocused(0)) { + if (add_key && igIsKeyPressed(GLFW_KEY_INSERT, true)) + curve_editor.add_key = true; + else if (del_key && igIsKeyPressed(GLFW_KEY_DELETE, true)) + curve_editor.del_key = true; + else if (igIsKeyPressed(GLFW_KEY_RIGHT, true)) + curve_editor.frame++; + else if (igIsKeyPressed(GLFW_KEY_LEFT, true)) + curve_editor.frame--; + } + + bool exist = true; + if (curve_editor.add_key && add_key) { + if (!curve_editor.list[curve_editor.type] || keys.end - keys.begin == 0) { + glitter_curve_key key; + memset(&key, 0, sizeof(glitter_curve_key)); + key.frame = curve_editor.curve.start_time; + + if (!curve_editor.list[curve_editor.type]) { + glitter_curve* curve = glitter_curve_init(GPM_VAL); + vector_ptr_glitter_curve_push_back(curve_editor.curves, &curve); + curve_editor.list[curve_editor.type] = curve; + } + + glitter_editor_curve_editor_curve_set(curve, curve_editor.type); + vector_glitter_curve_key_push_back(&keys, &key); + *curve_editor.list[curve_editor.type] = curve_editor.curve; + curve_editor.frame = curve_editor.curve.start_time; + changed = true; + } + else { + glitter_curve_key* i = keys.begin; + bool is_before_start = keys.begin->frame > curve_editor.frame; + bool has_key_after = false; + if (!is_before_start) + for (i++; i != keys.end; i++) + if (curve_editor.frame <= i->frame) { + has_key_after = keys.end - i > 0; + break; + } + + ssize_t pos = i - keys.begin; + if (!is_before_start) + pos--; + + glitter_curve_key key; + memset(&key, 0, sizeof(glitter_curve_key)); + key.frame = curve_editor.frame; + if (!is_before_start && has_key_after) { + glitter_curve_key* c = i - 1; + glitter_curve_key* n = i; + key.type = c->type; + switch (c->type) { + case GLITTER_KEY_CONSTANT: + key.value = c->value; + key.random_range = c->random_range; + break; + case GLITTER_KEY_LINEAR: { + float_t t = (float_t)(key.frame - c->frame) / (float_t)(n->frame - c->frame); + key.value = lerp(c->value, n->value, t); + key.random_range = lerp(c->random_range, n->random_range, t); + } break; + case GLITTER_KEY_HERMITE: { + int32_t df = n->frame - c->frame; + int32_t _df = key.frame - c->frame; + float_t* v_arr = 0; + size_t v_length = 0; + interpolate_chs(c->value, n->value, c->tangent2, n->tangent1, 0, df, &v_arr, &v_length); + key.value = v_arr[_df]; + key.random_range = lerp(c->random_range, n->random_range, (float_t)_df / (float_t)df); + interpolate_chs_reverse(v_arr, v_length, &c->tangent2, &key.tangent1, 0, _df); + interpolate_chs_reverse(v_arr, v_length, &key.tangent2, &n->tangent1, _df, df); + free(v_arr); + } break; + } + vector_glitter_curve_key_insert(&keys, ++pos, &key); + } + else if (is_before_start) { + glitter_curve_key* n = i; + key.type = n->type; + key.value = n->value; + key.random_range = n->random_range; + vector_glitter_curve_key_insert(&keys, pos, &key); + } + else { + glitter_curve_key* c = i - 1; + key.type = c->type; + key.value = c->value; + key.random_range = c->random_range; + vector_glitter_curve_key_insert(&keys, ++pos, &key); + } + *curve_editor.list[curve_editor.type] = curve_editor.curve; + changed = true; + } + } + else if (curve_editor.del_key && del_key) { + for (glitter_curve_key* i = keys.begin; i != keys.end; i++) + if (i == curve_editor.key) { + bool has_key_before = keys.begin->frame < i->frame; + bool has_key_after = keys.end[-1].frame > i->frame; + if (has_key_before && i[-1].type == GLITTER_KEY_HERMITE && has_key_after) { + glitter_curve_key* c = i - 1; + glitter_curve_key* n = i + 1; + int32_t df_c = i->frame - c->frame; + int32_t df_n = n->frame - i->frame; + + float_t* v_arr_c = 0; + size_t v_length_c = 0; + interpolate_chs(c->value, i->value, c->tangent2, + i->tangent1, 0, df_c, &v_arr_c, &v_length_c); + + float_t* v_arr_n = 0; + size_t v_length_n = 0; + if (i->type == GLITTER_KEY_HERMITE) + interpolate_chs(i->value, n->value, i->tangent2, + n->tangent1, 0, df_n, &v_arr_n, &v_length_n); + else + interpolate_linear(i->value, n->value, + 0, df_n, &v_arr_n, &v_length_n); + + size_t v_length = v_length_c + v_length_n - 1; + float_t* v_arr = force_malloc_s(float_t, v_length); + memmove(v_arr, v_arr_c, (v_length_c - 1) * sizeof(float_t)); + memmove(v_arr + (v_length_c - 1), v_arr_n, (v_length_n) * sizeof(float_t)); + free(v_arr_c); + free(v_arr_n); + interpolate_chs_reverse(v_arr, v_length, &c->tangent2, + &n->tangent1, 0, (size_t)n->frame - c->frame); + free(v_arr); + } + vector_glitter_curve_key_erase(&keys, i - keys.begin); + changed = true; + break; + } + + glitter_curve* c = curve_editor.list[curve_editor.type]; + if (c && keys.end - keys.begin == 0) { + vector_ptr_glitter_curve* curves = curve_editor.curves; + for (glitter_curve** i = curves->begin; i != curves->end; i++) + if (*i && *i == c) { + vector_ptr_glitter_curve_erase(curves, i - curves->begin, glitter_curve_dispose); + exist = false; + break; + } + + glitter_editor_curve_editor_curve_reset(&curve_editor.curve); + curve_editor.list[curve_editor.type] = 0; + changed = true; + } + } + else if (curve_editor.add_curve) { + glitter_curve_key key; + memset(&key, 0, sizeof(glitter_curve_key)); + key.frame = curve_editor.curve.start_time; + glitter_curve* c = glitter_curve_init(GPM_VAL); + vector_ptr_glitter_curve_push_back(curve_editor.curves, &c); + curve_editor.list[curve_editor.type] = c; + glitter_editor_curve_editor_curve_set(curve, curve_editor.type); + vector_glitter_curve_key_push_back(&keys, &key); + *curve_editor.list[curve_editor.type] = curve_editor.curve; + curve_editor.frame = curve_editor.curve.start_time; + changed = true; + } + else if (curve_editor.del_curve) { + glitter_curve* c = curve_editor.list[curve_editor.type]; + vector_ptr_glitter_curve* curves = curve_editor.curves; + for (glitter_curve** i = curves->begin; i != curves->end; i++) + if (*i && *i == c) { + vector_ptr_glitter_curve_erase(curves, i - curves->begin, glitter_curve_dispose); + break; + } + + glitter_editor_curve_editor_curve_reset(&curve_editor.curve); + curve_editor.list[curve_editor.type] = 0; + curve_editor.frame = 0; + changed = true; + } + curve_editor.add_key = false; + curve_editor.del_key = false; + curve_editor.add_curve = false; + curve_editor.del_curve = false; + + curve_editor.key = glitter_editor_curve_editor_get_selected_key(curve); + + int32_t start_time = curve->start_time; + int32_t end_time = curve->end_time; + + ImGuiIO* io = igGetIO(); + ImGuiStyle* style = igGetStyle(); + ImFont* font = igGetFont(); + + ImVec2 cont_reg_avail; + igGetContentRegionAvail(&cont_reg_avail); + + ImVec2 canvas_size, canvas_pos, canvas_pos_min, canvas_pos_max; + curve_editor.draw_list = igGetWindowDrawList(); + canvas_size = cont_reg_avail; + igGetCursorScreenPos(&canvas_pos); + canvas_pos_min.x = canvas_pos.x; + canvas_pos_min.y = canvas_pos.y; + canvas_pos_max.x = canvas_pos.x + canvas_size.x; + canvas_pos_max.y = canvas_pos.y + canvas_size.y; + canvas_size.y -= style->ScrollbarSize; + + ImRect boundaries; + boundaries.Min = canvas_pos; + boundaries.Max.x = canvas_pos.x + canvas_size.x; + boundaries.Max.y = canvas_pos.y + canvas_size.y; + + if (curve_editor.zoom_time != curve_editor.prev_zoom_time) { + float_t timeline_pos = curve_editor.timeline_pos + curve_editor_timeline_base_pos; + timeline_pos *= curve_editor.zoom_time / curve_editor.prev_zoom_time; + curve_editor.timeline_pos = timeline_pos - curve_editor_timeline_base_pos; + } + curve_editor.prev_zoom_time = curve_editor.zoom_time; + + float_t frame_width = curve_editor.frame_width * curve_editor.zoom_time; + canvas_pos.x -= curve_editor.timeline_pos; + + igItemSize_Rect(boundaries, -1.0f); + bool hovered = igIsMouseHoveringRect(boundaries.Min, boundaries.Max, true); + igRenderFrame(boundaries.Min, boundaries.Max, igGetColorU32_Col(ImGuiCol_FrameBg, 1.0f), true, 1.0f); + + static bool can_drag; + if (hovered && igIsMouseClicked(ImGuiMouseButton_Left, false)) + can_drag = true; + + if (can_drag && igIsMouseReleased(ImGuiMouseButton_Left)) + can_drag = false; + + float_t timeline_max_offset = (end_time - start_time) * frame_width; + timeline_max_offset = max(timeline_max_offset, 0.0f) - curve_editor_timeline_base_pos; + + ImVec2 scrollbar_size, scrollbar_pos; + scrollbar_size.x = canvas_size.x; + scrollbar_size.y = style->ScrollbarSize; + scrollbar_pos.x = boundaries.Min.x; + scrollbar_pos.y = boundaries.Max.y; + ImRect scroll_boundaries; + scroll_boundaries.Min = scrollbar_pos; + scroll_boundaries.Max.x = scrollbar_pos.x + scrollbar_size.x; + scroll_boundaries.Max.y = scrollbar_pos.y + scrollbar_size.y; + + igRenderFrame(scroll_boundaries.Min, scroll_boundaries.Max, + igGetColorU32_Col(ImGuiCol_ScrollbarBg, 1.0f), false, 0.0f); + + static const ImVec2 bar_offset = { 5.0f, 2.5f }; + ImVec2 bar_size, bar_pos, bar_max; + glitter_editor_curve_editor_get_scroll_bar(timeline_max_offset, + canvas_size.x, frame_width, scrollbar_size, scrollbar_pos, + bar_offset, &bar_size, &bar_pos, &bar_max); + + igSetCursorScreenPos(bar_pos); + igInvisibleButton("scroll_handle", bar_size, 0); + bool scroolbar_move = igIsItemActive(); + + ImDrawList_AddRectFilled(curve_editor.draw_list, bar_pos, bar_max, + igGetColorU32_Col(ImGuiCol_ScrollbarGrab, 1.0f), style->ScrollbarRounding, 0); + + ImDrawList_PushClipRect(curve_editor.draw_list, boundaries.Min, boundaries.Max, true); + + int32_t start = (int32_t)(curve_editor.timeline_pos / frame_width) + start_time; + int32_t end = (int32_t)((curve_editor.timeline_pos + canvas_size.x) / frame_width) + start_time; + + ImU32 line_color_valid_bold = igGetColorU32_Vec4((ImVec4) { 0.5f, 0.5f, 0.5f, 0.75f }); + ImU32 line_color_valid = igGetColorU32_Vec4((ImVec4) { 0.4f, 0.4f, 0.4f, 0.45f }); + ImU32 line_color_not_valid = igGetColorU32_Vec4((ImVec4) { 0.2f, 0.2f, 0.2f, 0.75f }); + for (int32_t frame = start; frame <= end; frame++) { + if (frame < start_time) + continue; + + int32_t f = frame - start_time; + float_t x = canvas_pos.x + f * frame_width; + float_t y = canvas_pos.y + (f % 2 ? 10.0f : 0.0f) + canvas_size.y; + + bool bold_frame = f % 10 == 0 || f == 0 || frame == end_time; + bool valid_frame = f >= 0 && frame <= end_time; + + ImU32 line_color = valid_frame ? (bold_frame ? line_color_valid_bold + : line_color_valid) : line_color_not_valid; + ImDrawList_AddLine(curve_editor.draw_list, + (ImVec2) { x, y - canvas_size.y }, (ImVec2) { x, y }, line_color, 0.80f); + + if (bold_frame) { + char buf[0x20]; + sprintf_s(buf, sizeof(buf), "%d", frame); + ImDrawList_AddText_Vec2(curve_editor.draw_list, + (ImVec2) { x + 3, canvas_pos.y }, line_color, buf, 0); + } + } + + float_t max = curve_editor.range * (1.0f / curve_editor.zoom_value); + float_t min; + if (curve->type == GLITTER_CURVE_EMISSION_INTERVAL) + min = -1.0f; + else if (curve->type == GLITTER_CURVE_PARTICLES_PER_EMISSION) + min = 0.0f; + else + min = -max; + + for (int32_t j = 0; j < 5; j++) { + float_t x_pos = canvas_pos_min.x; + float_t y_pos = canvas_pos.y + j * 0.25f * (canvas_size.y + - curve_editor.height_offset) + curve_editor.height_offset; + + ImU32 line_color = j % 2 == 1 + ? igGetColorU32_Vec4((ImVec4) { 0.35f, 0.35f, 0.35f, 0.45f }) + : igGetColorU32_Vec4((ImVec4) { 0.45f, 0.45f, 0.45f, 0.75f }); + bool last = j == 4; + if (j && !last) + ImDrawList_AddLine(curve_editor.draw_list, (ImVec2) { x_pos, y_pos }, + (ImVec2) { x_pos + canvas_size.x, y_pos }, line_color, 0.80f); + + float_t val = max - j * 0.25f * (max - min); + char buf[0x20]; + sprintf_s(buf, sizeof(buf), "%.2f", val); + ImDrawList_AddText_Vec2(curve_editor.draw_list, (ImVec2) { x_pos + 2, y_pos + (last ? -16 : -2) }, + igGetColorU32_Vec4((ImVec4) { 0.65f, 0.65f, 0.65f, 0.85f }), buf, 0); + } + + if (curve->type >= GLITTER_CURVE_ROTATION_X && curve->type <= GLITTER_CURVE_ROTATION_Z) { + max *= DEG_TO_RAD_FLOAT; + min *= DEG_TO_RAD_FLOAT; + } + else if (curve->type >= GLITTER_CURVE_COLOR_R && curve->type <= GLITTER_CURVE_COLOR_RGB_SCALE_2ND) { + max *= (float_t)(1.0 / 255.0); + min *= (float_t)(1.0 / 255.0); + } + + float_t base_line = convert_value_to_height(0.0f, canvas_pos.y, canvas_size.y, min, max); + + ImVec2 p1, p2, p3; + p1.x = canvas_pos_min.x; + p1.y = canvas_pos.y + curve_editor.height_offset; + p2.x = p1.x + canvas_size.x; + p2.y = canvas_pos.y + curve_editor.height_offset; + p3.x = canvas_pos_min.x; + p3.y = canvas_pos.y; + ImDrawList_AddLine(curve_editor.draw_list, p1, p2, + igGetColorU32_Vec4((ImVec4) { 0.5f, 0.5f, 0.5f, 0.85f }), 2.0f); + + ImU32 random_range_color = igGetColorU32_Vec4((ImVec4) { 0.5f, 0.5f, 0.0f, 0.25f }); + ImU32 key_random_range_color = igGetColorU32_Vec4((ImVec4) { 0.5f, 0.0f, 0.5f, 0.25f }); + ImU32 default_color = igGetColorU32_Vec4((ImVec4) { 1.0f, 1.0f, 1.0f, 0.75f }); + ImU32 selected_color = igGetColorU32_Vec4((ImVec4) { 0.0f, 1.0f, 1.0f, 0.75f }); + + if (curve->flags & GLITTER_CURVE_RANDOM_RANGE + || curve->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) { + float_t random_range = curve->random_range; + bool random_range_mult = curve->flags & GLITTER_CURVE_RANDOM_RANGE_MULT; + bool random_range_negate = curve->flags & GLITTER_CURVE_RANDOM_RANGE_NEGATE; + bool glt_type_x = glt_type == GLITTER_X; + for (glitter_curve_key* i = keys.begin; i != keys.end; i++) { + if (i->frame >= end_time || keys.end - i <= 1) + break; + + glitter_curve_key* c = i; + glitter_curve_key* n = i + 1; + float_t x1 = canvas_pos.x + (float_t)(c->frame - start_time) * frame_width; + float_t x2 = canvas_pos.x + (float_t)(n->frame - start_time) * frame_width; + + if (((x1 < canvas_pos_min.x) && (x2 < canvas_pos_min.x)) || + (x1 > canvas_pos_max.x) && (x2 > canvas_pos_max.x)) + continue; + + x1 = max(x1, canvas_pos_min.x); + x2 = min(x2, canvas_pos_max.x); + + glitter_key_type k_type = c->type; + float_t c_frame = (float_t)c->frame; + float_t n_frame = (float_t)n->frame; + float_t c_value = c->value; + float_t n_value = n->value; + float_t c_random_range = c->random_range; + float_t n_random_range = n->random_range; + if (random_range_mult) + if (glt_type_x) { + c_random_range *= c_value * 0.01f; + n_random_range *= n_value * 0.01f; + } + else { + c_random_range *= c_value; + n_random_range *= n_value; + } + + size_t frame_width_int = (size_t)roundf(frame_width); + if (k_type == GLITTER_KEY_CONSTANT) { + vec3 value = { c_value + c_random_range, c_value, c_value - c_random_range }; + vec3 random = { random_range, random_range, random_range }; + if (random_range_mult) { + vec3_mult(random, value, random); + if (glt_type_x) + vec3_mult_scalar(random, 0.01f, random); + } + + if (value.x != value.y) { + float_t y1 = convert_value_to_height(value.x + random.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(value.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y3 = convert_value_to_height(value.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y4 = convert_value_to_height(value.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + ImDrawList_AddRectFilled(curve_editor.draw_list, + (ImVec2) { x1, y1 }, (ImVec2) { x2, y2 }, + random_range_color, 0.0f, 0); + + y3 = clamp(y3, canvas_pos_min.y, canvas_pos_max.y); + y4 = clamp(y4, canvas_pos_min.y, canvas_pos_max.y); + if (y3 != y4) + ImDrawList_AddRectFilled(curve_editor.draw_list, + (ImVec2) { x1, y3 }, (ImVec2) { x2, y4 }, + key_random_range_color, 0.0f, 0); + } + else { + float_t y1 = convert_value_to_height(value.y + random.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(value.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + ImDrawList_AddRectFilled(curve_editor.draw_list, + (ImVec2) { x1, y1 }, (ImVec2) { x2, y2 }, + random_range_color, 0.0f, 0); + } + + if (random_range_negate) + if (value.y != value.z) { + float_t y1 = convert_value_to_height(value.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(value.z, + canvas_pos.y, canvas_size.y, min, max); + float_t y3 = convert_value_to_height(value.z, + canvas_pos.y, canvas_size.y, min, max); + float_t y4 = convert_value_to_height(value.z - random.z, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + ImDrawList_AddRectFilled(curve_editor.draw_list, + (ImVec2) { x1, y1 }, (ImVec2) { x2, y2 }, + key_random_range_color, 0.0f, 0); + + y3 = clamp(y3, canvas_pos_min.y, canvas_pos_max.y); + y4 = clamp(y4, canvas_pos_min.y, canvas_pos_max.y); + if (y3 != y4) + ImDrawList_AddRectFilled(curve_editor.draw_list, + (ImVec2) { x1, y3 }, (ImVec2) { x2, y4 }, + random_range_color, 0.0f, 0); + } + else { + float_t y1 = convert_value_to_height(value.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(value.y - random.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + ImDrawList_AddRectFilled(curve_editor.draw_list, + (ImVec2) { x1, y1 }, (ImVec2) { x2, y2 }, + random_range_color, 0.0f, 0); + } + } + else { + float_t c_tangent2 = c->tangent2; + float_t n_tangent1 = n->tangent1; + + vec3 c_frame_vec = { c_frame, c_frame, c_frame }; + vec3 n_frame_vec = { n_frame, n_frame, n_frame }; + vec3 c_value_vec = (vec3){ c_value + c_random_range, c_value, c_value - c_random_range }; + vec3 n_value_vec = (vec3){ n_value + n_random_range, n_value, n_value - n_random_range }; + vec3 c_tangent2_vec = { c_tangent2, c_tangent2, c_tangent2 }; + vec3 n_tangent1_vec = { n_tangent1, n_tangent1, n_tangent1 }; + for (size_t i = c->frame; i < n->frame; i++) + for (size_t j = 0; j < frame_width_int; j++) { + float_t frame = (float_t)i + (float_t)j / frame_width; + vec3 frame_vec = { frame, frame, frame }; + + vec3 value; + if (k_type != GLITTER_KEY_HERMITE) + interpolate_linear_value_vec3(&c_value_vec, &n_value_vec, + &c_frame_vec, &n_frame_vec, &frame_vec, &value); + else + interpolate_chs_value_vec3(&c_value_vec, &n_value_vec, + &c_tangent2_vec, &n_tangent1_vec, + &c_frame_vec, &n_frame_vec, &frame_vec, &value); + + if (random_range_mult) { + vec3 random = { random_range, random_range, random_range }; + vec3_mult(random, value, random); + if (glt_type_x) + vec3_mult_scalar(random, 0.01f, random); + } + + float_t x = canvas_pos.x + + (float_t)(i - start_time) * frame_width + (float_t)j; + if (value.x != value.y) { + float_t y1 = convert_value_to_height(value.x + random_range, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(value.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y3 = convert_value_to_height(value.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y4 = convert_value_to_height(value.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + ImDrawList_AddLine(curve_editor.draw_list, + (ImVec2) { x, y1 }, (ImVec2) { x, y2 }, + random_range_color, 0.0f); + + y3 = clamp(y3, canvas_pos_min.y, canvas_pos_max.y); + y4 = clamp(y4, canvas_pos_min.y, canvas_pos_max.y); + if (y3 != y4) + ImDrawList_AddLine(curve_editor.draw_list, + (ImVec2) { x, y3 }, (ImVec2) { x, y4 }, + key_random_range_color, 0.0f); + } + else { + float_t y1 = convert_value_to_height(value.y + random_range, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(value.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + ImDrawList_AddLine(curve_editor.draw_list, + (ImVec2) { x, y1 }, (ImVec2) { x, y2 }, + random_range_color, 0.0f); + } + + if (random_range_negate) + if (value.y != value.z) { + float_t y1 = convert_value_to_height(value.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(value.z, + canvas_pos.y, canvas_size.y, min, max); + float_t y3 = convert_value_to_height(value.z, + canvas_pos.y, canvas_size.y, min, max); + float_t y4 = convert_value_to_height(value.z - random_range, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + ImDrawList_AddLine(curve_editor.draw_list, + (ImVec2) { x, y1 }, (ImVec2) { x, y2 }, + key_random_range_color, 0.0f); + + y3 = clamp(y3, canvas_pos_min.y, canvas_pos_max.y); + y4 = clamp(y4, canvas_pos_min.y, canvas_pos_max.y); + if (y3 != y4) + ImDrawList_AddLine(curve_editor.draw_list, + (ImVec2) { x, y3 }, (ImVec2) { x, y4 }, + random_range_color, 0.0f); + } + else { + float_t y1 = convert_value_to_height(value.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(value.y - random_range, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + ImDrawList_AddLine(curve_editor.draw_list, + (ImVec2) { x, y1 }, (ImVec2) { x, y2 }, + random_range_color, 0.0f); + } + } + } + } + } + + for (glitter_curve_key* i = keys.begin; i != keys.end; i++) { + if (i->frame >= end_time || keys.end - i <= 1) + break; + + glitter_curve_key* c = i; + glitter_curve_key* n = i + 1; + float_t x1 = canvas_pos.x + (float_t)(c->frame - start_time) * frame_width; + float_t x2 = canvas_pos.x + (float_t)(n->frame - start_time) * frame_width; + + if (((x1 < canvas_pos_min.x) && (x2 < canvas_pos_min.x)) || + (x1 > canvas_pos_max.x) && (x2 > canvas_pos_max.x)) + continue; + + float_t c_value = c->value; + float_t n_value = n->value; + + if (i->type != GLITTER_KEY_HERMITE) { + float_t y1 = convert_value_to_height(c_value, canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(n_value, canvas_pos.y, canvas_size.y, min, max); + + if (i->type == GLITTER_KEY_CONSTANT) { + ImVec2 points_temp[4]; + points_temp[0] = (ImVec2){ x1, y1 }; + points_temp[1] = (ImVec2){ x2, y1 }; + points_temp[2] = (ImVec2){ x2, y1 }; + points_temp[3] = (ImVec2){ x2, y2 }; + ImDrawList_AddPolyline(curve_editor.draw_list, points_temp, 4, default_color, 0, 3.0f); + } + else + ImDrawList_AddLine(curve_editor.draw_list, + (ImVec2) { x1, y1 }, (ImVec2) { x2, y2 }, default_color, 3.0f); + } + else { + float_t c_frame = (float_t)c->frame; + float_t n_frame = (float_t)n->frame; + float_t c_tangent2 = (float_t)c->tangent2; + float_t n_tangent1 = (float_t)n->tangent1; + size_t frame_width_int = (size_t)roundf(frame_width); + size_t points_count = ((size_t)n_frame - (size_t)c_frame) * frame_width_int; + ImVec2* points = force_malloc_s(ImVec2, points_count); + for (size_t i = c->frame; i < n->frame; i++) + for (size_t j = 0; j < frame_width_int; j++) { + float_t value = interpolate_chs_value(c_value, n_value, c_tangent2, n_tangent1, + c_frame, n_frame, (float_t)i + (float_t)j / frame_width); + + ImVec2 point; + point.x = canvas_pos.x + + (float_t)(i - start_time) * frame_width + (float_t)j; + point.y = convert_value_to_height(value, + canvas_pos.y, canvas_size.y, min, max); + points[(i - c->frame) * frame_width_int + j] = point; + } + ImDrawList_AddPolyline(curve_editor.draw_list, points, + (int32_t)points_count, default_color, 0, 3.0f); + free(points); + } + } + + const ImU32 key_constant_color = igGetColorU32_Vec4((ImVec4) { 1.0f, 0.0f, 0.0f, 0.75f }); + const ImU32 key_linear_color = igGetColorU32_Vec4((ImVec4) { 0.0f, 1.0f, 0.0f, 0.75f }); + const ImU32 key_hermite_color = igGetColorU32_Vec4((ImVec4) { 0.0f, 0.0f, 1.0f, 0.75f }); + + bool dragged = false; + bool holding_tan = false; + for (glitter_curve_key* i = keys.begin; i != keys.end; i++) { + if (!(i->frame >= start_time || i->frame <= end_time)) + continue; + else if (i - keys.begin > 1) + if (i->frame < start_time && i[1].frame < start_time) + continue; + else if (i->frame > end_time && i[-1].frame > end_time) + continue; + + float_t x = canvas_pos.x + ((size_t)i->frame - start_time) * frame_width; + float_t y = convert_value_to_height(i->value, canvas_pos.y, canvas_size.y, min, max); + + if (!(x >= p3.x - 10.0f && x <= p3.x + canvas_size.x + 10.0f) + || !(y >= p3.y - 10.0f && y <= p3.y + canvas_size.y + 10.0f)) + continue; + + ImU32 value_color; + switch (i->type) { + case GLITTER_KEY_CONSTANT: + value_color = key_constant_color; + break; + case GLITTER_KEY_LINEAR: + default: + value_color = key_linear_color; + break; + case GLITTER_KEY_HERMITE: + value_color = key_hermite_color; break; } - if (mu_begin_treenode(muctx, buf)) { - if (!selected_curve) - selected_curve = curve; - mu_end_treenode(muctx); + igPushID_Ptr(i); + igSetCursorScreenPos((ImVec2) { x - 7.5f, y - 7.5f }); + igInvisibleButton("val", (ImVec2) { 15.0f, 15.0f }, 0); + + if (can_drag && igIsItemActive() && igIsMouseDragging(ImGuiMouseButton_Left, -1.0f)) { + float_t old_y = y; + + static int32_t base_frame; + static float_t base_y; + if ((igIsKeyPressed(GLFW_KEY_LEFT_SHIFT, false) && !igIsKeyDown(GLFW_KEY_RIGHT_SHIFT)) + || (igIsKeyPressed(GLFW_KEY_RIGHT_SHIFT, false) && !igIsKeyDown(GLFW_KEY_LEFT_SHIFT))) { + base_frame = i->frame; + base_y = i->value; + } + + if (i->frame >= start_time && i->frame <= end_time) { + int32_t start = i - keys.begin > 0 ? (i - 1)->frame + 1 : start_time; + int32_t end = keys.end - i > 1 ? (i + 1)->frame - 1 : end_time; + curve_editor.frame = (int32_t)roundf((io->MousePos.x - canvas_pos.x) / frame_width); + curve_editor.frame = clamp(curve_editor.frame + start_time, start, end); + if (i->frame != curve_editor.frame) { + i->frame = curve_editor.frame; + changed = true; + } + } + + static float_t mouse_delta_history; + if ((igIsKeyPressed(GLFW_KEY_LEFT_SHIFT, false) && !igIsKeyDown(GLFW_KEY_RIGHT_SHIFT)) + || (igIsKeyPressed(GLFW_KEY_RIGHT_SHIFT, false) && !igIsKeyDown(GLFW_KEY_LEFT_SHIFT))) + mouse_delta_history = io->MouseDelta.y; + else if ((igIsKeyReleased(GLFW_KEY_LEFT_SHIFT) && !igIsKeyDown(GLFW_KEY_RIGHT_SHIFT)) + || igIsKeyReleased(GLFW_KEY_RIGHT_SHIFT) && !igIsKeyDown(GLFW_KEY_LEFT_SHIFT)) { + y += mouse_delta_history; + y += io->MouseDelta.y; + } + else if (igIsKeyDown(GLFW_KEY_LEFT_SHIFT) || igIsKeyDown(GLFW_KEY_RIGHT_SHIFT)) + mouse_delta_history += io->MouseDelta.y; + else + y += io->MouseDelta.y; + + if (old_y != y) { + float_t value = convert_height_to_value(y, canvas_pos.y, canvas_size.y, min, max); + dragged = true; + + if (i->value != value) { + i->value = value; + changed = true; + } + curve_editor.key = i; + } + } + + if (i - keys.begin > 0 && (i - 1)->type == GLITTER_KEY_HERMITE) { + ImU32 tangent1_color; + float_t tangent1; + ImVec2 circle_pos; + circle_pos.x = x - 25.0f; + circle_pos.y = y - base_line + convert_value_to_height(tangent1 = i->tangent1, + canvas_pos.y, canvas_size.y, min, max); + ImDrawList_AddLine(curve_editor.draw_list, (ImVec2) { x, y }, circle_pos, default_color, 1.5f); + + if ((circle_pos.x >= p3.x - 10.0f && circle_pos.x <= p3.x + canvas_size.x + 10.0f) + && (circle_pos.y >= p3.y - 10.0f && circle_pos.y <= p3.y + canvas_size.y + 10.0f)) { + igSetCursorScreenPos((ImVec2) { circle_pos.x - 7.5f, circle_pos.y - 7.5f }); + igInvisibleButton("tan1", (ImVec2) { 15.0f, 15.0f }, 0); + + if (can_drag && igIsItemActive()) { + if (igIsMouseDragging(ImGuiMouseButton_Left, -1.0f)) { + i->tangent1 = convert_height_to_value(circle_pos.y + io->MouseDelta.y - y + base_line, + canvas_pos.y, canvas_size.y, min, max); + + if (i->tangent1 != tangent1) + changed = true; + } + holding_tan = true; + tangent1_color = selected_color; + } + else + tangent1_color = default_color; + + ImDrawList_AddCircleFilled(curve_editor.draw_list, circle_pos, + curve_editor.key_radius_in, tangent1_color, 12); + } + } + + if (keys.end - i > 1 && i->type == GLITTER_KEY_HERMITE) { + ImU32 tangent2_color; + float_t tangent2; + ImVec2 circle_pos; + circle_pos.x = x + 25.0f; + circle_pos.y = y - base_line + convert_value_to_height(tangent2 = i->tangent2, + canvas_pos.y, canvas_size.y, min, max); + ImDrawList_AddLine(curve_editor.draw_list, (ImVec2) { x, y }, circle_pos, default_color, 1.5f); + + if ((circle_pos.x >= p3.x - 10.0f && circle_pos.x <= p3.x + canvas_size.x + 10.0f) + && (circle_pos.y >= p3.y - 10.0f && circle_pos.y <= p3.y + canvas_size.y + 10.0f)) { + igSetCursorScreenPos((ImVec2) { circle_pos.x - 7.5f, circle_pos.y - 7.5f }); + igInvisibleButton("tan2", (ImVec2) { 15.0f, 15.0f }, 0); + + if (can_drag && igIsItemActive()) { + if (igIsMouseDragging(ImGuiMouseButton_Left, -1.0f)) { + i->tangent2 = convert_height_to_value(circle_pos.y + io->MouseDelta.y - y + base_line, + canvas_pos.y, canvas_size.y, min, max); + + if (i->tangent2 != tangent2) + changed = true; + } + holding_tan = true; + tangent2_color = selected_color; + } + else + tangent2_color = default_color; + + ImDrawList_AddCircleFilled(curve_editor.draw_list, circle_pos, + curve_editor.key_radius_in, tangent2_color, 12); + } + } + + ImDrawList_AddCircleFilled(curve_editor.draw_list, (ImVec2) { x, y }, + curve_editor.key_radius_out, curve_editor.key == i ? selected_color : default_color, 12); + ImDrawList_AddCircleFilled(curve_editor.draw_list, (ImVec2) { x, y }, + curve_editor.key_radius_in, value_color, 12); + igPopID(); + } + + if (can_drag && !scroolbar_move && io->MouseDown[0] && (!holding_tan || dragged)) { + int32_t frame = (int32_t)roundf((io->MousePos.x - canvas_pos.x) / frame_width); + curve_editor.frame = clamp(frame + start_time, start_time, end_time); + curve_editor.key = glitter_editor_curve_editor_get_selected_key(curve); + } + curve_editor.frame = clamp(curve_editor.frame, start_time, end_time); + + int32_t cursor_frame = curve_editor.frame - start_time; + ImVec2 cursor_pos = canvas_pos; + cursor_pos.x += cursor_frame * frame_width; + if (cursor_pos.x >= p1.x - 10.0f && cursor_pos.x <= p1.x + canvas_size.x + 10.0f) { + ImU32 cursor_color = igGetColorU32_Vec4((ImVec4) { 0.8f, 0.8f, 0.8f, 0.75f }); + p1.x = cursor_pos.x; + p1.y = canvas_pos.y + canvas_size.y; + ImDrawList_AddLine(curve_editor.draw_list, cursor_pos, p1, cursor_color, 2.5f); + + p1 = p2 = p3 = cursor_pos; + p1.x -= 10.0f; + p2.y += 10.0f; + p3.x += 10.0f; + ImDrawList_AddTriangleFilled(curve_editor.draw_list, p1, p2, p3, cursor_color); + } + ImDrawList_PopClipRect(curve_editor.draw_list); + + if (hovered) + if (igIsKeyDown(GLFW_KEY_LEFT_SHIFT) || igIsKeyDown(GLFW_KEY_RIGHT_SHIFT)) + curve_editor.timeline_pos -= io->MouseWheel * 25.0f * 4.0f; + else + curve_editor.timeline_pos -= io->MouseWheel * 25.0f; + + if (scroolbar_move && io->MouseDelta.x != 0.0f) + curve_editor.timeline_pos += io->MouseDelta.x * curve_editor.zoom_time; + + curve_editor.timeline_pos = clamp(curve_editor.timeline_pos, -curve_editor_timeline_base_pos, timeline_max_offset); + curve->keys_rev = keys; + + if (curve_editor.list[curve_editor.type]) { + uint64_t hash1 = hash_fnv1a64((void*)curve_editor.list[curve_editor.type], sizeof(glitter_curve)); + uint64_t hash2 = hash_fnv1a64((void*)curve, sizeof(glitter_curve)); + if (hash1 != hash2) + *curve_editor.list[curve_editor.type] = *curve; + + if (changed) { + glitter_curve_recalculate(GPM_VAL, curve, &curve->keys); + glitter_editor.input_reload = true; } - mu_pop_id(muctx); } - mu_end_treenode(muctx); } + +static void glitter_editor_curve_editor_curve_reset(glitter_curve* curve) { + memset(curve, 0, sizeof(glitter_curve)); + glitter_editor_curve_editor_curve_set(curve, -1); +} + +static void glitter_editor_curve_editor_curve_set(glitter_curve* curve, glitter_curve_type type) { + curve->type = type; + if (glt_type == GLITTER_X) { + curve->version = 2; + curve->keys_version = 3; + } + else { + curve->version = 1; + curve->keys_version = 2; + } +} + +static void glitter_editor_curve_editor_curves_reset() { + glitter_editor_curve_editor_curve_reset(&curve_editor.curve); + memset(&curve_editor.list, 0, sizeof(glitter_curve*) + * GLITTER_CURVE_V_SCROLL_ALPHA_2ND - GLITTER_CURVE_TRANSLATION_X + 1); + curve_editor.curves = 0; + curve_editor.key = 0; +} + +static glitter_curve_key* glitter_editor_curve_editor_get_selected_key(glitter_curve* curve) { + vector_glitter_curve_key keys = curve->keys_rev; + for (glitter_curve_key* i = keys.begin; i != keys.end; i++) { + if (i->frame == curve_editor.frame) + return i; + } + return 0; +} + +static void glitter_editor_curve_editor_get_scroll_bar(float_t max_pos, float_t canvas_size, + float_t frame_width, ImVec2 scrollbar_size, ImVec2 scrollbar_pos, + ImVec2 bar_offset, ImVec2* bar_size, ImVec2* bar_pos, ImVec2* bar_max) { + scrollbar_size.x -= bar_offset.x * 2.0f; + scrollbar_size.y -= bar_offset.y * 2.0f; + + float_t cur_pos = curve_editor.timeline_pos + curve_editor_timeline_base_pos; + float_t visible_frames = canvas_size / frame_width; + float_t max_frames = ((max_pos <= 0.0f ? 0.0f : max_pos) + canvas_size) / frame_width; + float_t size_x = scrollbar_size.x * (floorf(visible_frames) / floorf(max_frames)); + float_t size_y = scrollbar_size.y; + + bar_size->x = size_x; + bar_size->y = size_y; + bar_pos->x = scrollbar_pos.x + bar_offset.x + (max_pos <= 0.0f ? 1.0f + : min(cur_pos / max_pos, 1.0f)) * (scrollbar_size.x - size_x); + bar_pos->y = scrollbar_pos.y + bar_offset.y; + bar_max->x = bar_pos->x + bar_size->x; + bar_max->y = bar_pos->y + bar_size->y; +} + +static void glitter_editor_curve_editor_key_manager(vector_glitter_curve_key* keys, bool* add_key, bool* del_key) { + glitter_curve* curve = &curve_editor.curve; + *add_key = true; + *del_key = false; + for (glitter_curve_key* i = keys->begin; i != keys->end; i++) + if (i->frame > curve->end_time) + break; + else if (i->frame == curve_editor.frame) { + *add_key = false; + *del_key = true; + break; + } +} + +static void glitter_editor_curve_editor_property_window() { + if (curve_editor.type < GLITTER_CURVE_TRANSLATION_X + || curve_editor.type > GLITTER_CURVE_V_SCROLL_ALPHA_2ND) + return; + + float_t scale; + float_t inv_scale; + float_t min; + + glitter_curve_type_flags flags = 0; + switch (selected_type) { + case GLITTER_EDITOR_SELECTED_EFFECT: + flags = glitter_effect_curve_flags; + break; + case GLITTER_EDITOR_SELECTED_EMITTER: + flags = glitter_emitter_curve_flags; + break; + case GLITTER_EDITOR_SELECTED_PARTICLE: + if (glt_type == GLITTER_X) + flags = glitter_particle_x_curve_flags; + else + flags = glitter_particle_curve_flags; + + if (selected_particle->data.type != GLITTER_PARTICLE_MESH) { + flags &= ~GLITTER_CURVE_TYPE_UV_SCROLL_2ND; + if (selected_particle->data.draw_type != GLITTER_DIRECTION_PARTICLE_ROTATION) + flags &= ~(GLITTER_CURVE_TYPE_ROTATION_X | GLITTER_CURVE_TYPE_ROTATION_Y); + } + break; + default: + return; + } + + glitter_curve* curve = &curve_editor.curve; + if (curve->type >= GLITTER_CURVE_ROTATION_X && curve->type <= GLITTER_CURVE_ROTATION_Z) { + scale = RAD_TO_DEG_FLOAT; + inv_scale = DEG_TO_RAD_FLOAT; + } + else if (curve->type >= GLITTER_CURVE_COLOR_R && curve->type <= GLITTER_CURVE_COLOR_RGB_SCALE_2ND) { + scale = 255.0f; + inv_scale = (float_t)(1.0 / 255.0); + } + else { + scale = 1.0f; + inv_scale = 1.0f; + } + + if (curve->type == GLITTER_CURVE_EMISSION_INTERVAL) + min = -1.0f; + else if (curve->type == GLITTER_CURVE_PARTICLES_PER_EMISSION) + min = 0.0f; + else + min = -FLT_MAX; + + bool random_range = curve->flags & GLITTER_CURVE_RANDOM_RANGE ? true : false; + bool key_random_range = curve->flags & GLITTER_CURVE_KEY_RANDOM_RANGE ? true : false; + + bool changed = false; + + igText("Frame: %d", curve_editor.frame); + + if (curve_editor.key && igTreeNodeEx_Str("Key", ImGuiTreeNodeFlags_DefaultOpen)) { + glitter_curve_key* c = curve_editor.key; + glitter_curve_key* n = curve->keys_rev.end - c > 1 ? curve_editor.key + 1 : 0; + if (imguiColumnComboBox("Type", glitter_key_name, + GLITTER_KEY_HERMITE, + (int32_t*)&c->type, 0, true, &glitter_editor.imgui_focus)) + changed = true; + + float_t value = c->value * scale; + if (imguiColumnDragFloat("Value", + &value, 0.0001f, min, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + c->value = value * inv_scale; + changed = true; + } + + imguiDisableElementPush(key_random_range); + float_t random = c->random_range * scale; + if (imguiColumnDragFloat("Random Range", + &random, 0.0001f, 0.0f, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + random *= inv_scale; + if (random != c->random_range) { + c->random_range = random; + changed = true; + } + } + imguiDisableElementPop(key_random_range); + + if (n && c->type == GLITTER_KEY_HERMITE) { + float_t tangent2 = c->tangent2 * scale; + if (imguiColumnDragFloat("Tangent 1", + &tangent2, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + c->tangent2 = tangent2 * inv_scale; + changed = true; + } + + float_t tangent1 = n->tangent1 * scale; + if (imguiColumnDragFloat("Tangent 2", + &tangent1, 0.0001f, -FLT_MAX, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + n->tangent1 = tangent1 * inv_scale; + changed = true; + } + } + igTreePop(); + } + + if (igTreeNodeEx_Str("Curve", ImGuiTreeNodeFlags_DefaultOpen)) { + if (imguiCheckbox("Repeat", &curve->repeat)) + changed = true; + + int32_t start_time = curve->start_time; + if (imguiColumnInputInt("Start Time", + &start_time, 1, 1, 0)) { + start_time = clamp(start_time, 0, 0x7FFF); + if (curve->end_time < start_time) { + curve->end_time = start_time; + changed = true; + } + + if (curve->start_time != start_time) { + curve->start_time = start_time; + changed = true; + } + } + + int32_t end_time = curve->end_time; + if (imguiColumnInputInt("End Time", + &end_time, 1, 1, 0)) { + if (curve->start_time > end_time) + end_time = curve->start_time; + + if (curve->end_time != end_time) { + curve->end_time = end_time; + changed = true; + } + } + + imguiDisableElementPush(random_range); + float_t random = curve->random_range * scale; + if (imguiColumnDragFloat("Random Range", + &random, 0.0001f, 0.0f, FLT_MAX, "%g", + ImGuiSliderFlags_NoRoundToFormat)) { + random *= inv_scale; + if (random != curve->random_range) { + curve->random_range = random; + changed = true; + } + } + imguiDisableElementPop(random_range); + + int32_t c_type = curve->version; + igText("C Type:"); + igSameLine(0.0f, -1.0f); + igSetNextItemWidth(60.0f); + if (igInputInt("##C Type:", &c_type, 1, 1, 0)) { + if (glt_type == GLITTER_X) + c_type = clamp(c_type, 1, 2); + else + c_type = clamp(c_type, 0, 1); + + if (c_type != curve->version) + changed = true; + curve->version = c_type; + } + + int32_t k_type = curve->keys_version; + igSameLine(0.0f, -1.0f); + igText("K Type:"); + igSameLine(0.0f, -1.0f); + igSetNextItemWidth(60.0f); + if (igInputInt("##K Type:", &k_type, 1, 1, 0)) { + if (glt_type == GLITTER_X) + k_type = clamp(k_type, 2, 3); + else + k_type = clamp(k_type, 0, 2); + + if (k_type != curve->keys_version) + changed = true; + curve->keys_version = k_type; + } + + igSeparator(); + + igPushID_Str("Flags"); + if (imguiCheckboxFlags_UintPtr("Baked", + (uint32_t*)&curve->flags, + GLITTER_CURVE_BAKED)) + changed = true; + + if (glt_type == GLITTER_X) { + imguiDisableElementPush(curve->flags & GLITTER_CURVE_BAKED ? true : false); + if (imguiCheckboxFlags_UintPtr("Baked Full", + (uint32_t*)&curve->flags, + GLITTER_CURVE_BAKED_FULL)) + changed = true; + imguiDisableElementPop(curve->flags & GLITTER_CURVE_BAKED ? true : false); + } + + igSeparator(); + + if (imguiCheckboxFlags_UintPtr("Random Range", + (uint32_t*)&curve->flags, + GLITTER_CURVE_RANDOM_RANGE)) + changed = true; + + if (imguiCheckboxFlags_UintPtr("Key Random Range", + (uint32_t*)&curve->flags, + GLITTER_CURVE_KEY_RANDOM_RANGE)) + changed = true; + + if (imguiCheckboxFlags_UintPtr("Random Range Negate", + (uint32_t*)&curve->flags, + GLITTER_CURVE_RANDOM_RANGE_NEGATE)) + changed = true; + + if (imguiCheckboxFlags_UintPtr("Step Random", + (uint32_t*)&curve->flags, + GLITTER_CURVE_STEP)) + changed = true; + + if (imguiCheckboxFlags_UintPtr("Random Negate", + (uint32_t*)&curve->flags, + GLITTER_CURVE_NEGATE)) + changed = true; + + if (imguiCheckboxFlags_UintPtr(glt_type == GLITTER_X + ? "Scale Random by Value * 0.01" : "Scale Random by Value", + (uint32_t*)&curve->flags, + GLITTER_CURVE_RANDOM_RANGE_MULT)) + changed = true; + igPopID(); + igTreePop(); + } + + if (curve_editor.list[curve_editor.type]) { + uint64_t hash1 = hash_fnv1a64((void*)curve_editor.list[curve_editor.type], sizeof(glitter_curve)); + uint64_t hash2 = hash_fnv1a64((void*)curve, sizeof(glitter_effect)); + if (hash1 != hash2) + *curve_editor.list[curve_editor.type] = *curve; + + if (changed) { + glitter_curve_recalculate(GPM_VAL, curve, &curve->keys); + glitter_editor.input_reload = true; + } + } +} + +static void glitter_editor_curve_editor_reset_state(glitter_curve_type type) { + if (curve_editor.type != type) + curve_editor.type = type; + + curve_editor.frame_width = 16; + curve_editor.zoom_time = 2.0f; + curve_editor.prev_zoom_time = 2.0f; + curve_editor.zoom_value = 1.0f; + curve_editor.key_radius_in = 6.0f; + curve_editor.key_radius_out = 8.0f; + curve_editor.height_offset = 20.0f; + curve_editor.frame = 0; + curve_editor.key = 0; + + curve_editor.timeline_pos = -curve_editor_timeline_base_pos; + + switch (type) { + case GLITTER_CURVE_TRANSLATION_X: + case GLITTER_CURVE_TRANSLATION_Y: + case GLITTER_CURVE_TRANSLATION_Z: + curve_editor.range = 25.0f; + break; + case GLITTER_CURVE_ROTATION_X: + case GLITTER_CURVE_ROTATION_Y: + case GLITTER_CURVE_ROTATION_Z: + curve_editor.range = 360.0f; + break; + case GLITTER_CURVE_SCALE_X: + case GLITTER_CURVE_SCALE_Y: + case GLITTER_CURVE_SCALE_Z: + case GLITTER_CURVE_SCALE_ALL: + curve_editor.range = 5.0f; + break; + case GLITTER_CURVE_COLOR_R: + case GLITTER_CURVE_COLOR_G: + case GLITTER_CURVE_COLOR_B: + case GLITTER_CURVE_COLOR_A: + case GLITTER_CURVE_COLOR_RGB_SCALE: + case GLITTER_CURVE_COLOR_R_2ND: + case GLITTER_CURVE_COLOR_G_2ND: + case GLITTER_CURVE_COLOR_B_2ND: + case GLITTER_CURVE_COLOR_A_2ND: + case GLITTER_CURVE_COLOR_RGB_SCALE_2ND: + curve_editor.range = 255.0f; + break; + case GLITTER_CURVE_EMISSION_INTERVAL: + curve_editor.range = 20.0f; + break; + case GLITTER_CURVE_PARTICLES_PER_EMISSION: + curve_editor.range = 50.0f; + break; + case GLITTER_CURVE_U_SCROLL: + case GLITTER_CURVE_V_SCROLL: + case GLITTER_CURVE_U_SCROLL_ALPHA: + case GLITTER_CURVE_V_SCROLL_ALPHA: + case GLITTER_CURVE_U_SCROLL_2ND: + case GLITTER_CURVE_V_SCROLL_2ND: + case GLITTER_CURVE_U_SCROLL_ALPHA_2ND: + case GLITTER_CURVE_V_SCROLL_ALPHA_2ND: + curve_editor.range = 1.0f; + break; + default: + curve_editor.range = 1.0f; + break; + } + + curve_editor.add_key = false; + curve_editor.del_key = false; +} + +static void glitter_editor_curve_editor_selector() { + glitter_curve_type_flags flags = 0; + vector_ptr_glitter_curve* curves = 0; + switch (selected_type) { + case GLITTER_EDITOR_SELECTED_EFFECT: + flags = glitter_effect_curve_flags; + curves = &selected_effect->curve; + break; + case GLITTER_EDITOR_SELECTED_EMITTER: + flags = glitter_emitter_curve_flags; + curves = &selected_emitter->curve; + break; + case GLITTER_EDITOR_SELECTED_PARTICLE: + if (glt_type == GLITTER_X) + flags = glitter_particle_x_curve_flags; + else + flags = glitter_particle_curve_flags; + curves = &selected_particle->curve; + + if (selected_particle->data.type != GLITTER_PARTICLE_MESH) { + flags &= ~GLITTER_CURVE_TYPE_UV_SCROLL_2ND; + if (selected_particle->data.draw_type != GLITTER_DIRECTION_PARTICLE_ROTATION) + flags &= ~(GLITTER_CURVE_TYPE_ROTATION_X | GLITTER_CURVE_TYPE_ROTATION_Y); + } + break; + default: + return; + } + curve_editor.curves = curves; + + for (glitter_curve_type i = GLITTER_CURVE_TRANSLATION_X; i <= GLITTER_CURVE_V_SCROLL_ALPHA_2ND; i++) { + bool found = false; + glitter_curve** j; + for (j = curves->begin; j != curves->end; j++) + if (*j && (*j)->type == i) { + found = true; + break; + } + curve_editor.list[i] = found ? *j : 0; + } + + ImVec2 cont_reg_avail; + igGetContentRegionAvail(&cont_reg_avail); + if (igBeginListBox("##Curves", (ImVec2) { cont_reg_avail.x * 0.5f, cont_reg_avail.y })) { + ImGuiTreeNodeFlags tree_node_flags = 0; + tree_node_flags |= ImGuiTreeNodeFlags_DefaultOpen; + tree_node_flags |= ImGuiTreeNodeFlags_OpenOnDoubleClick; + tree_node_flags |= ImGuiTreeNodeFlags_OpenOnArrow; + tree_node_flags |= ImGuiTreeNodeFlags_SpanAvailWidth; + +#define LIST_BOX(label, curve_type) \ +if (flags & GLITTER_CURVE_TYPE_##curve_type){ \ + char* _l = curve_editor.list[GLITTER_CURVE_##curve_type] ? label" [*]" : label; \ + if (igSelectable_Bool(_l, curve_editor.type == GLITTER_CURVE_##curve_type, 0, ImVec2_Empty)) \ + glitter_editor_curve_editor_reset_state(GLITTER_CURVE_##curve_type); \ +\ + if (igIsItemFocused() && curve_editor.type != GLITTER_CURVE_##curve_type) \ + glitter_editor_curve_editor_reset_state(GLITTER_CURVE_##curve_type); \ +} + + if (flags & GLITTER_CURVE_TYPE_TRANSLATION_XYZ + && igTreeNodeEx_Str("Translation", tree_node_flags)) { + igPushID_Str("T"); + LIST_BOX("X", TRANSLATION_X); + LIST_BOX("Y", TRANSLATION_Y); + LIST_BOX("Z", TRANSLATION_Z); + igPopID(); + igTreePop(); + } + + if (flags & GLITTER_CURVE_TYPE_ROTATION_XYZ + && igTreeNodeEx_Str("Rotation", tree_node_flags)) { + igPushID_Str("R"); + LIST_BOX("X", ROTATION_X); + LIST_BOX("Y", ROTATION_Y); + LIST_BOX("Z", ROTATION_Z); + igPopID(); + igTreePop(); + } + + if (flags & (GLITTER_CURVE_TYPE_SCALE_XYZ | GLITTER_CURVE_TYPE_SCALE_ALL) + && igTreeNodeEx_Str("Scale", tree_node_flags)) { + igPushID_Str("S"); + LIST_BOX("X", SCALE_X); + LIST_BOX("Y", SCALE_Y); + LIST_BOX("Z", SCALE_Z); + LIST_BOX("All", SCALE_ALL); + igPopID(); + igTreePop(); + } + + if (flags & (GLITTER_CURVE_TYPE_COLOR_RGBA | GLITTER_CURVE_TYPE_COLOR_RGB_SCALE) + && igTreeNodeEx_Str("Color", tree_node_flags)) { + igPushID_Str("C"); + LIST_BOX("R", COLOR_R); + LIST_BOX("G", COLOR_G); + LIST_BOX("B", COLOR_B); + LIST_BOX("A", COLOR_A); + LIST_BOX("RGB Scale", COLOR_RGB_SCALE); + igPopID(); + igTreePop(); + } + + if (flags & (GLITTER_CURVE_TYPE_COLOR_RGBA_2ND | GLITTER_CURVE_TYPE_COLOR_RGB_SCALE_2ND) + && igTreeNodeEx_Str("Color 2nd", tree_node_flags)) { + igPushID_Str("C2"); + LIST_BOX("R", COLOR_R_2ND); + LIST_BOX("G", COLOR_G_2ND); + LIST_BOX("B", COLOR_B_2ND); + LIST_BOX("A", COLOR_A_2ND); + LIST_BOX("RGB Scale", COLOR_RGB_SCALE_2ND); + igPopID(); + igTreePop(); + } + + LIST_BOX("Emit Interval", EMISSION_INTERVAL); + LIST_BOX("PTC Per Emit", PARTICLES_PER_EMISSION); + + if (flags & (GLITTER_CURVE_TYPE_UV_SCROLL | GLITTER_CURVE_TYPE_UV_SCROLL_ALPHA) + && igTreeNodeEx_Str("UV Scroll", tree_node_flags)) { + igPushID_Str("UV"); + LIST_BOX("U", U_SCROLL); + LIST_BOX("V", V_SCROLL); + LIST_BOX("U Alpha", U_SCROLL_ALPHA); + LIST_BOX("V Alpha", V_SCROLL_ALPHA); + igPopID(); + igTreePop(); + } + + if (flags & (GLITTER_CURVE_TYPE_UV_SCROLL_2ND | GLITTER_CURVE_TYPE_UV_SCROLL_ALPHA_2ND) + && igTreeNodeEx_Str("UV Scroll 2nd", tree_node_flags)) { + igPushID_Str("UV2"); + LIST_BOX("U", U_SCROLL_2ND); + LIST_BOX("V", V_SCROLL_2ND); + LIST_BOX("U Alpha", U_SCROLL_ALPHA_2ND); + LIST_BOX("V Alpha", V_SCROLL_ALPHA_2ND); + igPopID(); + igTreePop(); + } +#undef LIST_BOX + glitter_editor.imgui_focus |= igIsWindowFocused(0); + igEndListBox(); + } + + if (curve_editor.type < GLITTER_CURVE_TRANSLATION_X || curve_editor.type > GLITTER_CURVE_V_SCROLL_ALPHA_2ND) + return; + + if (curve_editor.list[curve_editor.type]) + curve_editor.curve = *curve_editor.list[curve_editor.type]; + else if (curve_editor.curve.type != curve_editor.type) { + memset(&curve_editor.curve, 0, sizeof(glitter_curve)); + glitter_editor_curve_editor_curve_set(&curve_editor.curve, curve_editor.type); + } + glitter_curve* curve = &curve_editor.curve; + + igSameLine(0.0f, -1.0f); + igBeginGroup(); + imguiSetColumnSpace(3.0f / 7.0f); + float_t zoom_time = curve_editor.zoom_time * 100.0f; + imguiColumnSliderFloat("Zoom Time", &zoom_time, 5.0f, 500.0f, "%.1f%%", 0); + curve_editor.zoom_time = zoom_time * 0.01f; + + int32_t zoom_value = (int32_t)roundf(curve_editor.zoom_value * 100.0f); + imguiColumnSliderInt("Zoom Value", &zoom_value, 10, 1000, "%d%%", 0); + curve_editor.zoom_value = (float_t)zoom_value * 0.01f; + + imguiColumnDragFloat("Range", + &curve_editor.range, 0.0001f, 0.0f, FLT_MAX, "%g", 0); + imguiSetDefaultColumnSpace(); + + vector_glitter_curve_key keys = curve->keys_rev; + + bool add_key = false; + bool del_key = false; + glitter_editor_curve_editor_key_manager(&keys, &add_key, &del_key); + + igSeparator(); + ImVec2 t; + igGetContentRegionAvail(&t); + imguiDisableElementPush(add_key); + if (imguiButton("Add Key", (ImVec2) { t.x, 0.0f })) + curve_editor.add_key = true; + imguiDisableElementPop(add_key); + + imguiDisableElementPush(del_key); + if (imguiButton("Delete Key", (ImVec2) { t.x, 0.0f })) + curve_editor.del_key = true; + imguiDisableElementPop(del_key); + + bool has_curve_in_list = curve_editor.list[curve_editor.type] ? true : false; + imguiDisableElementPush(!has_curve_in_list); + if (imguiButton("Add Curve", (ImVec2) { t.x, 0.0f })) + curve_editor.add_curve = true; + imguiDisableElementPop(!has_curve_in_list); + + imguiDisableElementPush(has_curve_in_list); + if (imguiButton("Delete Curve", (ImVec2) { t.x, 0.0f })) + curve_editor.del_curve = true; + imguiDisableElementPop(has_curve_in_list); +} + +static bool glitter_editor_hash_input(const char* label, uint64_t* hash) { + uint64_t h = *hash; + if (imguiColumnInputScalar(label, ImGuiDataType_U64, &h, + 0, 0, "%016llX", ImGuiInputTextFlags_CharsHexadecimal)) { + if (h == 0) + h = hash_fnv1a64_empty; + + if (h != *hash) { + *hash = h; + return true; + } + } + return false; +} +#endif diff --git a/src/CLOUD/Classes/glitter_editor.h b/src/CLOUD/Classes/glitter_editor.h index 3db1cdbb..a1bb5b01 100644 --- a/src/CLOUD/Classes/glitter_editor.h +++ b/src/CLOUD/Classes/glitter_editor.h @@ -5,38 +5,17 @@ #pragma once +#ifdef CLOUD_DEV #include "../../KKdLib/default.h" #include "../../KKdLib/vec.h" #include "../../CRE/Glitter/glitter.h" -typedef struct glitter_editor_struct { - bool enabled; - bool dispose; - bool disposed; - bool load; - bool save; - bool save_big_endian; - bool input_play; - bool input_stop; - bool input_pause; - bool input_reload; - float_t frame_counter; - float_t old_frame_counter; - float_t start_frame; - float_t end_frame; - int32_t random; - int32_t counter; - glitter_effect_group* effect_group; - glitter_scene* scene; - wchar_t file[MAX_PATH]; -} glitter_editor_struct; - -extern glitter_editor_struct glitter_editor; +extern bool glitter_editor_enabled; extern void glitter_editor_dispose(); extern void glitter_editor_init(); -extern void glitter_editor_control(); +extern void glitter_editor_drop(size_t count, wchar_t** paths); +extern void glitter_editor_imgui(); extern void glitter_editor_input(); -extern void glitter_editor_mui(); extern void glitter_editor_render(); -extern void glitter_editor_sound(); +#endif diff --git a/src/CLOUD/Classes/glitter_test.c b/src/CLOUD/Classes/glitter_test.c deleted file mode 100644 index 8fe3125f..00000000 --- a/src/CLOUD/Classes/glitter_test.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#include "glitter_test.h" -#include "../../CRE/Glitter/glitter.h" -#include "../../CRE/Glitter/effect_group.h" -#include "../../CRE/Glitter/file_reader.h" -#include "../../CRE/Glitter/particle_manager.h" -#include "../../CRE/Glitter/scene.h" -#include "../../CRE/microui.h" -#include "../input.h" - -extern mu_Context* muctx; - -extern int32_t width; -extern int32_t height; -extern bool input_reset; -extern float_t frame_speed; - -extern glitter_particle_manager* gpm; - -const char* glitter_test_window_title = "Glitter"; - -glitter_test_struct glitter_test; - -void glitter_test_dispose() { - vector_ptr_glitter_scene_clear(&gpm->scenes, (void*)glitter_scene_dispose); - vector_ptr_glitter_effect_group_clear(&gpm->effect_groups, (void*)glitter_effect_group_dispose); - - vector_ptr_wchar_t_free(&glitter_test.files, 0); - glitter_test.file = 0; - glitter_test.input_play = false; - glitter_test.input_stop = false; - glitter_test.input_auto = false; - glitter_test.input_pause = false; - glitter_test.frame_counter = 0.0f; - glitter_test.enabled = false; - glitter_test.dispose = false; - glitter_test.disposed = true; -} - -void glitter_test_init() { - vector_ptr_wchar_t_free(&glitter_test.files, 0); - path_wget_files(&glitter_test.files, L"rom\\particle"); - for (wchar_t** i = glitter_test.files.begin; i != glitter_test.files.end; i++) { - wchar_t* temp = 0; - if (path_wcheck_ends_with(*i, L".farc")) - temp = path_wget_without_extension(*i); - free(*i); - *i = temp; - } - - size_t glitter_test_files_count = 0; - for (wchar_t** i = glitter_test.files.begin; i != glitter_test.files.end; i++) - if (*i) - glitter_test.files.begin[glitter_test_files_count++] = *i; - glitter_test.files.end = &glitter_test.files.begin[glitter_test_files_count]; - glitter_test.enabled = true; - gpm->emission = 1.0f; -} - -void glitter_test_control() { - if (!glitter_test.enabled) - return; -} - -void glitter_test_input() { - if (!glitter_test.enabled) - return; - - if (input_is_tapped('F')) - glitter_test.input_play = true; - - if (input_is_tapped('V')) - glitter_test.input_stop = true; - - if (input_is_tapped('T')) - glitter_test.input_auto ^= true; - - if (input_is_tapped('G')) - glitter_test.input_pause ^= true; -} - -void glitter_test_mui() { - if (!glitter_test.enabled) - return; - else if (glitter_test.disposed) { - mu_Container* cnt = mu_get_container(muctx, glitter_test_window_title); - muctx->hover_root = muctx->next_hover_root = cnt; - cnt->rect = mu_rect(0, 0, 0, 0); - cnt->open = true; - mu_bring_to_front(muctx, cnt); - glitter_test.disposed = false; - } - - int32_t w = min(width / 3, 360); - int32_t h = 340; - - if (!mu_begin_window_ex(muctx, glitter_test_window_title, - mu_rect(0, 0, w, h), - 0 /*MU_OPT_NOINTERACT | MU_OPT_NOCLOSE*/, false, true, false)) { - glitter_test.dispose = true; - return; - } - - mu_layout_row(muctx, 2, (int[]) { 32, -1 }, 0); - mu_label(muctx, "File:"); - char* glitter_file_temp = wchar_t_string_to_char_string(glitter_test.file); - if (mu_button(muctx, glitter_file_temp ? glitter_file_temp : "...")) - mu_open_popup(muctx, "glitter file"); - free(glitter_file_temp); - - if (mu_begin_window_ex(muctx, "glitter file", - mu_rect(0, 0, 240, 360), - MU_OPT_NOTITLE | MU_OPT_POPUP | MU_OPT_CLOSED, false, true, false)) { - mu_Rect body = muctx->layout_stack.items[muctx->layout_stack.idx - 1].body; - mu_layout_row(muctx, 1, (int[]) { body.w }, 0); - for (wchar_t** i = glitter_test.files.begin; i != glitter_test.files.end; i++) { - mu_push_id(muctx, &i, sizeof(i)); - char* temp = wchar_t_string_to_char_string(*i); - if (glitter_test.file && !wcscmp(*i, glitter_test.file)) - mu_draw_control_text(muctx, temp, mu_layout_next(muctx), MU_COLOR_TEXT, MU_OPT_ALIGNCENTER); - else if (mu_button(muctx, temp)) - glitter_test.file = *i; - free(temp); - mu_pop_id(muctx); - } - mu_end_window(muctx); - } - - mu_layout_row(muctx, 1, (int[]) { -1 }, 0); - if (mu_button(muctx, "Reset Camera (R)")) - input_reset = true; - - if (mu_button(muctx, "Play (F)")) - glitter_test.input_play = true; - - if (mu_button(muctx, "Stop (V)")) - glitter_test.input_stop = true; - - mu_checkbox(muctx, "Auto (T)", &glitter_test.input_auto); - mu_checkbox(muctx, "Pause (G)", &glitter_test.input_pause); - - size_t ctrl; - size_t disp; - float_t frame; - float_t life_time; - char buf[0x40]; - - mu_layout_row(muctx, 1, (int[]) { -1 }, 0); - glitter_particle_manager_get_frame(gpm, &frame, &life_time); - sprintf_s(buf, sizeof(buf), "%.0f - %.0f/%.0f", glitter_test.frame_counter, frame, life_time); - mu_label(muctx, buf); - - mu_layout_row(muctx, 2, (int[]) { 40, -1 }, 0); - ctrl = glitter_particle_manager_get_ctrl_count(gpm, GLITTER_PARTICLE_QUAD); - disp = glitter_particle_manager_get_disp_count(gpm, GLITTER_PARTICLE_QUAD); - mu_label(muctx, "Quad: "); - sprintf_s(buf, sizeof(buf), "ctrl%lld, disp%lld", ctrl, disp); - mu_label(muctx, buf); - - ctrl = glitter_particle_manager_get_ctrl_count(gpm, GLITTER_PARTICLE_LOCUS); - disp = glitter_particle_manager_get_disp_count(gpm, GLITTER_PARTICLE_LOCUS); - mu_label(muctx, "Locus: "); - sprintf_s(buf, sizeof(buf), "ctrl%lld, disp%lld", ctrl, disp); - mu_label(muctx, buf); - - ctrl = glitter_particle_manager_get_ctrl_count(gpm, GLITTER_PARTICLE_LINE); - disp = glitter_particle_manager_get_disp_count(gpm, GLITTER_PARTICLE_LINE); - mu_label(muctx, "Line: "); - sprintf_s(buf, sizeof(buf), "ctrl%lld, disp%lld", ctrl, disp); - mu_label(muctx, buf); - - mu_layout_row(muctx, 2, (int[]) { 80, -1 }, 0); - mu_label(muctx, "Emission: "); - mu_slider_step(muctx, &gpm->emission, 1.0f, 2.0f, 0.01f); - - mu_label(muctx, "Frame Speed: "); - mu_slider_step(muctx, &frame_speed, 0.0f, 3.0f, 0.01f); - mu_end_window(muctx); -} - -void glitter_test_render() { - if (glitter_test.dispose) { - glitter_test_dispose(); - return; - } - else if (!glitter_test.enabled) - return; - - if (!glitter_test.input_pause) { - if (gpm->scenes.end != gpm->scenes.begin) - glitter_test.frame_counter += get_frame_speed(); - - glitter_particle_manager_update_scene(gpm); - } - - if (glitter_test.file) { - uint64_t hash = gpm->f2 - ? hash_wchar_t_murmurhash(glitter_test.file, 0, false) - : hash_wchar_t_fnv1a64(glitter_test.file); - if (glitter_test.input_play || glitter_test.input_stop) { - glitter_particle_manager_free_scene(gpm, hash); - glitter_test.frame_counter = 0.0f; - } - - if (glitter_test.input_auto && !glitter_particle_manager_check_scene(gpm, hash)) { - if (glitter_particle_manager_check_effect_group(gpm, hash)) - goto load; - else - goto reset; - } - else if (glitter_test.input_play && !glitter_particle_manager_test_load_scene(gpm, hash)) { - reset: - vector_ptr_glitter_scene_clear(&gpm->scenes, (void*)glitter_scene_dispose); - vector_ptr_glitter_effect_group_clear(&gpm->effect_groups, (void*)glitter_effect_group_dispose); - - glitter_file_reader* fr = glitter_file_reader_init(0, glitter_test.file, gpm->f2, -1.0f); - vector_ptr_glitter_file_reader_push_back(&gpm->file_readers, &fr); - glitter_particle_manager_update_file_reader(gpm); - load: - glitter_test.frame_counter = 0.0f; - glitter_particle_manager_test_load_scene(gpm, hash); - } - glitter_test.input_play = false; - glitter_test.input_stop = false; - } -} - -void glitter_test_sound() { - if (!glitter_test.enabled) - return; -} diff --git a/src/CLOUD/Classes/glitter_test.h b/src/CLOUD/Classes/glitter_test.h deleted file mode 100644 index f0984ae5..00000000 --- a/src/CLOUD/Classes/glitter_test.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#pragma once - -#include "../../KKdLib/default.h" -#include "../../KKdLib/vector.h" - -typedef struct glitter_test_struct { - bool enabled; - bool dispose; - bool disposed; - bool input_play; - bool input_stop; - bool input_auto; - bool input_pause; - float_t frame_counter; - wchar_t* file; - vector_ptr_wchar_t files; -} glitter_test_struct; - -extern glitter_test_struct glitter_test; - -extern void glitter_test_dispose(); -extern void glitter_test_init(); -extern void glitter_test_control(); -extern void glitter_test_input(); -extern void glitter_test_mui(); -extern void glitter_test_render(); -extern void glitter_test_sound(); diff --git a/src/CLOUD/Classes/post_process.c b/src/CLOUD/Classes/post_process.c deleted file mode 100644 index bc590eb1..00000000 --- a/src/CLOUD/Classes/post_process.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#include "post_process.h" -#include "../../CRE/microui.h" -#include "../../CRE/post_process.h" - -extern mu_Context* muctx; - -extern int32_t width; -extern int32_t height; - -const char* post_process_window_title = "Post Process"; - -extern radius* rad; -extern intensity* inten; -extern tone_map_sat_gamma* tmsg; -extern tone_map_data* tmd; - -post_process_struct post_process; - -extern void post_process_dispose() { - post_process.enabled = false; - post_process.dispose = false; - post_process.disposed = true; -} - -extern void post_process_init() { - post_process.enabled = true; -} - -extern void post_process_control() { - if (!post_process.enabled) - return; -} - -extern void post_process_input() { - if (!post_process.enabled) - return; -} - -extern void post_process_mui() { - if (!post_process.enabled) - return; - else if (post_process.disposed) { - mu_Container* cnt = mu_get_container(muctx, post_process_window_title); - muctx->hover_root = muctx->next_hover_root = cnt; - cnt->rect = mu_rect(0, 0, 0, 0); - cnt->open = true; - mu_bring_to_front(muctx, cnt); - post_process.disposed = false; - } - - int32_t w = min(width / 3, 360); - int32_t h = 540; - - if (!mu_begin_window_ex(muctx, post_process_window_title, - mu_rect(0, 0, w, h), - 0 /*MU_OPT_NOINTERACT | MU_OPT_NOCLOSE*/, false, true, false)) { - post_process.dispose = true; - return; - } - - if (mu_begin_treenode(muctx, "Tone Trans")) { - int32_t tw0 = mu_misc_get_max_text_width(muctx, (char* []) { - "Start", "End" - }, 2); - int32_t tw1 = mu_misc_get_max_text_width(muctx, (char* []) { - "R:" - }, 1); - int32_t tw2 = mu_misc_get_max_text_width(muctx, (char* []) { - "G:" - }, 1); - int32_t tw3 = mu_misc_get_max_text_width(muctx, (char* []) { - "B:" - }, 1); - mu_Rect body = muctx->layout_stack.items[muctx->layout_stack.idx - 1].body; - int32_t sw = (int)((body.w - (tw0 + 4) - (tw1 + 2) - (tw2 + 2) - (tw3 + 2) - (muctx->style->spacing + 2) * 7) / 3.0f); - - mu_layout_row(muctx, 7, (int[]) { tw0, tw1, sw, tw2, sw, tw3, sw }, 0); - - vec3 tone_trans_start = *tone_map_data_get_tone_trans_start(tmd); - mu_label(muctx, "Start"); - mu_label(muctx, "R:"); - mu_slider_step(muctx, &tone_trans_start.x, 0.0f, 1.0f, 0.01f); - mu_label(muctx, "G:"); - mu_slider_step(muctx, &tone_trans_start.y, 0.0f, 1.0f, 0.01f); - mu_label(muctx, "B:"); - mu_slider_step(muctx, &tone_trans_start.z, 0.0f, 1.0f, 0.01f); - tone_map_data_set_tone_trans_start(tmd, &tone_trans_start); - - vec3 tone_trans_end = *tone_map_data_get_tone_trans_end(tmd); - mu_label(muctx, "End"); - mu_label(muctx, "R:"); - mu_slider_step(muctx, &tone_trans_end.x, 0.0f, 1.0f, 0.01f); - mu_label(muctx, "G:"); - mu_slider_step(muctx, &tone_trans_end.y, 0.0f, 1.0f, 0.01f); - mu_label(muctx, "B:"); - mu_slider_step(muctx, &tone_trans_end.z, 0.0f, 1.0f, 0.01f); - tone_map_data_set_tone_trans_end(tmd, &tone_trans_end); - mu_end_treenode(muctx); - } - - if (mu_begin_treenode(muctx, "Scene Fade")) { - int32_t tw0 = mu_misc_get_max_text_width(muctx, (char* []) { - "Alpha:", "Color", "Blend Func:" - }, 3); - int32_t tw1 = mu_misc_get_max_text_width(muctx, (char* []) { - "R:" - }, 1); - int32_t tw2 = mu_misc_get_max_text_width(muctx, (char* []) { - "G:" - }, 1); - int32_t tw3 = mu_misc_get_max_text_width(muctx, (char* []) { - "B:" - }, 1); - mu_Rect body = muctx->layout_stack.items[muctx->layout_stack.idx - 1].body; - int32_t sw = (int)((body.w - (tw0 + 4) - (tw1 + 2) - (tw2 + 2) - (tw3 + 2) - (muctx->style->spacing + 2) * 7) / 3.0f); - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - float_t scene_fade_alpha = tone_map_data_get_scene_fade_alpha(tmd); - mu_label(muctx, "Alpha:"); - mu_slider_step(muctx, &scene_fade_alpha, 0.0f, 1.0f, 0.01f); - tone_map_data_set_scene_fade_alpha(tmd, scene_fade_alpha); - - mu_layout_row(muctx, 7, (int[]) { tw0, tw1, sw, tw2, sw, tw3, sw }, 0); - - vec3 scene_fade_color = *tone_map_data_get_scene_fade_color(tmd); - mu_label(muctx, "Color"); - mu_label(muctx, "R:"); - mu_slider_step(muctx, &scene_fade_color.x, 0.0f, 1.0f, 0.01f); - mu_label(muctx, "G:"); - mu_slider_step(muctx, &scene_fade_color.y, 0.0f, 1.0f, 0.01f); - mu_label(muctx, "B:"); - mu_slider_step(muctx, &scene_fade_color.z, 0.0f, 1.0f, 0.01f); - tone_map_data_set_scene_fade_color(tmd, &scene_fade_color); - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - const char* blend_func_label; - uint8_t scene_fade_blend_func = (uint8_t)tone_map_data_get_scene_fade_blend_func(tmd); - switch (scene_fade_blend_func) { - case 0: - default: - blend_func_label = "0: OVER"; - break; - case 1: - blend_func_label = "1: MULTI"; - break; - case 2: - blend_func_label = "2: PLUS"; - break; - } - mu_label(muctx, "Blend Func:"); - mu_slider_uint8_t_label(muctx, &scene_fade_blend_func, 0, 2, blend_func_label); - tone_map_data_set_scene_fade_blend_func(tmd, scene_fade_blend_func); - mu_end_treenode(muctx); - } - - if (mu_begin_treenode_ex(muctx, "Glow Param", MU_OPT_EXPANDED)) { - int32_t tw0 = mu_misc_get_max_text_width(muctx, (char* []) { - "Tone Map:", "Exposure:", "Gamma:", "Saturate 1:", "Saturate 2:" - }, 5); - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - const char* tone_map_method_label; - uint8_t tone_map_method = (uint8_t)tone_map_data_get_tone_map_method(tmd); - switch (tone_map_method) { - case 0: - default: - tone_map_method_label = "YCC EXPONENT"; - break; - case 1: - tone_map_method_label = "RGB LINEAR"; - break; - case 2: - tone_map_method_label = "RGB LINEAR2"; - break; - } - mu_label(muctx, "Tone Map:"); - mu_slider_uint8_t_label(muctx, &tone_map_method, 0, 2, tone_map_method_label); - tone_map_data_set_tone_map_method(tmd, tone_map_method); - - mu_layout_row(muctx, 1, (int[]) { -1 }, 0); - bool auto_exposure = tone_map_data_get_auto_exposure(tmd); - mu_checkbox(muctx, "Auto Exposure", &auto_exposure); - tone_map_data_set_auto_exposure(tmd, auto_exposure); - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - float_t exposure = tone_map_data_get_exposure(tmd); - mu_label(muctx, "Exposure:"); - mu_slider_step(muctx, &exposure, 0.0f, 4.0f, 0.02f); - tone_map_data_set_exposure(tmd, exposure); - - float_t gamma = tone_map_sat_gamma_get_gamma(tmsg); - mu_label(muctx, "Gamma:"); - mu_slider_step(muctx, &gamma, 0.2f, 2.2f, 0.01f); - tone_map_sat_gamma_set_gamma(tmsg, gamma); - - uint8_t saturate1 = tone_map_sat_gamma_get_saturate1(tmsg); - mu_label(muctx, "Saturate 1:"); - mu_slider_uint8_t(muctx, &saturate1, 1, 6); - tone_map_sat_gamma_set_saturate1(tmsg, saturate1); - - float_t saturate2 = tone_map_sat_gamma_get_saturate2(tmsg); - mu_label(muctx, "Saturate 2:"); - mu_slider_step(muctx, &saturate2, 0.0f, 1.0f, 0.01f); - tone_map_sat_gamma_set_saturate2(tmsg, saturate2); - mu_end_treenode(muctx); - } - - if (mu_begin_treenode_ex(muctx, "Glare", MU_OPT_EXPANDED)) { - int32_t tw0 = mu_misc_get_max_text_width(muctx, (char* []) { - "Radius R:", "Radius G:", "Radius B:", "Inten R:", "Inten G:", "Inten B:" - }, 6); - - mu_layout_row(muctx, 2, (int[]) { tw0, -1 }, 0); - - vec3 radius = *radius_get(rad); - mu_label(muctx, "Radius R:"); - mu_slider_step(muctx, &radius.x, 1.0f, 3.0f, 0.01f); - mu_label(muctx, "Radius G:"); - mu_slider_step(muctx, &radius.y, 1.0f, 3.0f, 0.01f); - mu_label(muctx, "Radius B:"); - mu_slider_step(muctx, &radius.z, 1.0f, 3.0f, 0.01f); - radius_set(rad, &radius); - - vec3 intensity = *intensity_get(inten); - mu_label(muctx, "Inten R:"); - mu_slider_step(muctx, &intensity.x, 0.0f, 2.0f, 0.01f); - mu_label(muctx, "Inten G:"); - mu_slider_step(muctx, &intensity.y, 0.0f, 2.0f, 0.01f); - mu_label(muctx, "Inten B:"); - mu_slider_step(muctx, &intensity.z, 0.0f, 2.0f, 0.01f); - intensity_set(inten, &intensity); - mu_end_treenode(muctx); - } - mu_end_window(muctx); -} - -extern void post_process_render() { - if (post_process.dispose) { - post_process_dispose(); - return; - } - else if (!post_process.enabled) - return; -} - -extern void post_process_sound() { - if (!post_process.enabled) - return; -} diff --git a/src/CLOUD/Classes/post_process.h b/src/CLOUD/Classes/post_process.h deleted file mode 100644 index fa2f9050..00000000 --- a/src/CLOUD/Classes/post_process.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#pragma once - -#include "../../KKdLib/default.h" - -typedef struct post_process_struct { - bool enabled; - bool dispose; - bool disposed; -} post_process_struct; - -extern post_process_struct post_process; - -extern void post_process_dispose(); -extern void post_process_init(); -extern void post_process_control(); -extern void post_process_input(); -extern void post_process_mui(); -extern void post_process_render(); -extern void post_process_sound(); diff --git a/src/CLOUD/classes.c b/src/CLOUD/classes.c new file mode 100644 index 00000000..aab3e0fc --- /dev/null +++ b/src/CLOUD/classes.c @@ -0,0 +1,133 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "classes.h" + +void classes_process_dispose(classes_struct* classes, const size_t classes_count) { + if (!classes || !classes_count) + return; + + for (size_t i = 0; i < classes_count; i++) { + if (classes[i].dispose) { + lock_lock(classes[i].lock); + classes[i].dispose(); + lock_unlock(classes[i].lock); + } + lock_dispose(classes[i].lock); + + if (classes[i].sub_classes && classes[i].sub_classes_count) + classes_process_dispose(classes[i].sub_classes, classes[i].sub_classes_count); + } +} + +void classes_process_init(classes_struct* classes, const size_t classes_count) { + if (!classes || !classes_count) + return; + + for (size_t i = 0; i < classes_count; i++) { + lock_init(classes[i].lock); + if (classes[i].init && classes[i].flags & CLASSES_INIT_AT_STARTUP) { + lock_lock(classes[i].lock); + classes[i].init(); + lock_unlock(classes[i].lock); + } + + if (classes[i].sub_classes && classes[i].sub_classes_count) + classes_process_init(classes[i].sub_classes, classes[i].sub_classes_count); + } +} + +void classes_process_control(classes_struct* classes, const size_t classes_count) { + if (!classes || !classes_count) + return; + + for (size_t i = 0; i < classes_count; i++) { + if (classes[i].lock_init && classes[i].control) { + lock_lock(classes[i].lock); + classes[i].control(); + lock_unlock(classes[i].lock); + } + + if (classes[i].sub_classes && classes[i].sub_classes_count) + classes_process_control(classes[i].sub_classes, classes[i].sub_classes_count); + } +} + +void classes_process_drop(classes_struct* classes, size_t classes_count, size_t count, wchar_t** paths) { + for (size_t i = 0; i < classes_count; i++) { + if (classes[i].lock_init && classes[i].drop) { + lock_lock(classes[i].lock); + classes[i].drop(count, paths); + lock_unlock(classes[i].lock); + } + + if (classes[i].sub_classes && classes[i].sub_classes_count) + classes_process_drop(classes[i].sub_classes, classes[i].sub_classes_count, count, paths); + } +} + +void classes_process_imgui(classes_struct* classes, const size_t classes_count) { + if (!classes || !classes_count) + return; + + for (size_t i = 0; i < classes_count; i++) { + if (classes[i].lock_init && classes[i].imgui) { + lock_lock(classes[i].lock); + classes[i].imgui(); + lock_unlock(classes[i].lock); + } + + if (classes[i].sub_classes && classes[i].sub_classes_count) + classes_process_imgui(classes[i].sub_classes, classes[i].sub_classes_count); + } +} + +void classes_process_input(classes_struct* classes, const size_t classes_count) { + if (!classes || !classes_count) + return; + + for (size_t i = 0; i < classes_count; i++) { + if (classes[i].lock_init && classes[i].input) { + lock_lock(classes[i].lock); + classes[i].input(); + lock_unlock(classes[i].lock); + } + + if (classes[i].sub_classes && classes[i].sub_classes_count) + classes_process_input(classes[i].sub_classes, classes[i].sub_classes_count); + } +} + +void classes_process_render(classes_struct* classes, const size_t classes_count) { + if (!classes || !classes_count) + return; + + for (size_t i = 0; i < classes_count; i++) { + if (classes[i].lock_init && classes[i].render) { + lock_lock(classes[i].lock); + classes[i].render(); + lock_unlock(classes[i].lock); + } + + if (classes[i].sub_classes && classes[i].sub_classes_count) + classes_process_render(classes[i].sub_classes, classes[i].sub_classes_count); + } +} + +void classes_process_sound(classes_struct* classes, const size_t classes_count) { + if (!classes || !classes_count) + return; + + for (size_t i = 0; i < classes_count; i++) { + if (classes[i].lock_init && classes[i].sound) { + lock_lock(classes[i].lock); + classes[i].sound(); + lock_unlock(classes[i].lock); + } + + if (classes[i].sub_classes && classes[i].sub_classes_count) + classes_process_sound(classes[i].sub_classes, classes[i].sub_classes_count); + } +} diff --git a/src/CLOUD/classes.h b/src/CLOUD/classes.h new file mode 100644 index 00000000..81b5f902 --- /dev/null +++ b/src/CLOUD/classes.h @@ -0,0 +1,42 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/default.h" +#include "../CRE/lock.h" + +typedef enum classes_enum { + CLASSES_INIT_AT_STARTUP = 0x01, + CLASSES_IN_CONTEXT_MENU = 0x02, +} classes_enum; + +typedef struct classes_struct classes_struct; + +struct classes_struct { + const char* name; + const classes_enum flags; + bool* enabled; + const void(FASTCALL* dispose)(); + const void(FASTCALL* init)(); + const void(FASTCALL* control)(); + const void(FASTCALL* drop)(size_t count, wchar_t** paths); + const void(FASTCALL* imgui)(); + const void(FASTCALL* input)(); + const void(FASTCALL* render)(); + const void(FASTCALL* sound)(); + lock_val(lock); + classes_struct* sub_classes; + size_t sub_classes_count; +}; + +extern void classes_process_dispose(classes_struct* classes, size_t classes_count); +extern void classes_process_init (classes_struct* classes, size_t classes_count); +extern void classes_process_control(classes_struct* classes, size_t classes_count); +extern void classes_process_drop (classes_struct* classes, size_t classes_count, size_t count, wchar_t** paths); +extern void classes_process_imgui (classes_struct* classes, size_t classes_count); +extern void classes_process_input (classes_struct* classes, size_t classes_count); +extern void classes_process_render (classes_struct* classes, size_t classes_count); +extern void classes_process_sound (classes_struct* classes, size_t classes_count); diff --git a/src/CLOUD/classes/data_test.c b/src/CLOUD/classes/data_test.c new file mode 100644 index 00000000..0a44c2bf --- /dev/null +++ b/src/CLOUD/classes/data_test.c @@ -0,0 +1,27 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "data_test.h" + +bool data_test_enabled = true; + +classes_struct data_test_classes[1] = { + { + .name = "Glitter Test", + .flags = CLASSES_INIT_AT_STARTUP | CLASSES_IN_CONTEXT_MENU, + .enabled = &glitter_test_enabled, + .dispose = (void*)glitter_test_dispose, + .init = (void*)glitter_test_init, + .control = (void*)0, + .drop = (void*)0, + .input = (void*)glitter_test_input, + .imgui = (void*)glitter_test_imgui, + .render = (void*)glitter_test_render, + .sound = (void*)0, + .lock = 0, + .sub_classes = 0, + .sub_classes_count = 0, + }, +}; diff --git a/src/CLOUD/classes/data_test.h b/src/CLOUD/classes/data_test.h new file mode 100644 index 00000000..f2920c46 --- /dev/null +++ b/src/CLOUD/classes/data_test.h @@ -0,0 +1,12 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../classes.h" +#include "data_test/glitter_test.h" + +extern bool data_test_enabled; +extern classes_struct data_test_classes[]; diff --git a/src/CLOUD/classes/data_test/glitter_test.c b/src/CLOUD/classes/data_test/glitter_test.c new file mode 100644 index 00000000..45e47455 --- /dev/null +++ b/src/CLOUD/classes/data_test/glitter_test.c @@ -0,0 +1,249 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "glitter_test.h" +#include "../../../KKdLib/io_path.h" +#include "../../../KKdLib/str_utils.h" +#include "../../../CRE/Glitter/glitter.h" +#include "../../../CRE/Glitter/effect_group.h" +#include "../../../CRE/Glitter/file_reader.h" +#include "../../../CRE/Glitter/particle_manager.h" +#include "../../../CRE/Glitter/scene.h" +#include "../../input.h" +#include "../imgui_helper.h" + +typedef struct glitter_test_struct { + bool dispose; + bool disposed; + bool imgui_focus; + bool input_play; + bool input_stop; + bool input_auto; + bool input_pause; + float_t frame_counter; + char* file; + vector_ptr_char files; +} glitter_test_struct; + +extern int32_t width; +extern int32_t height; +extern bool input_reset; +extern bool input_locked; +extern float_t frame_speed; +extern bool grid_3d; + +extern glitter_particle_manager* gpm; +extern glitter_type glt_type; + +const char* glitter_test_window_title = "Glitter"; + +#ifdef CLOUD_DEV +bool glitter_test_enabled = false; +#else +bool glitter_test_enabled = true; +#endif +static glitter_test_struct glitter_test; + +void glitter_test_dispose() { + vector_ptr_glitter_scene_free(&gpm->scenes, glitter_scene_dispose); + vector_ptr_glitter_effect_group_free(&gpm->effect_groups, glitter_effect_group_dispose); + + vector_ptr_char_free(&glitter_test.files, 0); + glitter_test_enabled = false; + glitter_test.file = 0; + glitter_test.imgui_focus = false; + glitter_test.input_play = false; + glitter_test.input_stop = false; + glitter_test.input_auto = false; + glitter_test.input_pause = false; + glitter_test.frame_counter = 0.0f; + glitter_test.dispose = false; + glitter_test.disposed = true; +} + +void glitter_test_init() { + if (glitter_test_enabled || glitter_test.dispose) + glitter_test_dispose(); + + vector_ptr_char_free(&glitter_test.files, 0); + path_get_files(&glitter_test.files, "rom\\particle"); + for (char** i = glitter_test.files.begin; i != glitter_test.files.end;) + if (str_utils_check_ends_with(*i, ".farc")) { + char* temp = str_utils_get_without_extension(*i); + vector_ptr_char_erase(&glitter_test.files, i - glitter_test.files.begin, 0); + vector_ptr_char_insert(&glitter_test.files, i - glitter_test.files.begin, &temp); + i++; + } + else + vector_ptr_char_erase(&glitter_test.files, i - glitter_test.files.begin, 0); + + glitter_test.file = glitter_test.files.end - glitter_test.files.begin > 0 ? glitter_test.files.begin[0] : 0; + + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + gpm->counter = (uint32_t)(time.LowPart * 0x0CAD3078LL); + glitter_test_enabled = true; + gpm->emission = 1.0f; + gpm->draw_all = false; + gpm->draw_all_mesh = false; + glt_type = GLITTER_AFT; + grid_3d = false; +} + +void glitter_test_imgui() { + if (!glitter_test_enabled) { + if (!glitter_test.disposed) + glitter_test.dispose = true; + return; + } + else if (glitter_test.disposed) + glitter_test.disposed = false; + + float_t w = min((float_t)width / 4.0f, 360.0f); + float_t h = min((float_t)height, 348.0f); + + igSetNextWindowPos(ImVec2_Empty, ImGuiCond_Appearing, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Appearing); + + ImGuiWindowFlags window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoCollapse; + + glitter_test.imgui_focus = false; + if (!igBegin(glitter_test_window_title, &glitter_test_enabled, window_flags)) { + glitter_test.dispose = true; + igEnd(); + return; + } + + int32_t file_index = -1; + if (glitter_test.file) + for (char** i = glitter_test.files.begin; i != glitter_test.files.end; i++) + if (!strcmp(*i, glitter_test.file)) { + file_index = (int32_t)(i - glitter_test.files.begin); + break; + } + + int32_t file_index_old = file_index; + imguiColumnComboBox("File", glitter_test.files.begin, + glitter_test.files.end - glitter_test.files.begin, + &file_index, 0, false, &glitter_test.imgui_focus); + + if (file_index != file_index_old) { + glitter_test.file = glitter_test.files.begin[file_index]; + glitter_test.input_stop = true; + } + + if (imguiButton("Reset Camera (R)", ImVec2_Empty)) + input_reset = true; + + if (imguiButton("Play (F)", ImVec2_Empty) || igIsKeyPressed(GLFW_KEY_F, true)) + glitter_test.input_play = true; + + if (imguiButton("Stop (V)", ImVec2_Empty) || igIsKeyPressed(GLFW_KEY_V, true)) + glitter_test.input_stop = true; + + imguiCheckbox("Auto (T)", &glitter_test.input_auto); + if (igIsKeyPressed(GLFW_KEY_T, true)) + glitter_test.input_auto ^= true; + + imguiCheckbox("Pause (G)", &glitter_test.input_pause); + if (igIsKeyPressed(GLFW_KEY_G, true)) + glitter_test.input_pause ^= true; + + igSeparator(); + + size_t ctrl; + size_t disp; + float_t frame; + float_t life_time; + + frame = 0.0f; + life_time = 0.0f; + glitter_particle_manager_get_frame(GPM_VAL, &frame, &life_time); + igText("%.0f - %.0f/%.0f", glitter_test.frame_counter, frame, life_time); + + ctrl = glitter_particle_manager_get_ctrl_count(GPM_VAL, GLITTER_PARTICLE_QUAD); + disp = glitter_particle_manager_get_disp_count(GPM_VAL, GLITTER_PARTICLE_QUAD); + igText(" Quad: ctrl%lld, disp%lld", ctrl, disp); + + ctrl = glitter_particle_manager_get_ctrl_count(GPM_VAL, GLITTER_PARTICLE_LOCUS); + disp = glitter_particle_manager_get_disp_count(GPM_VAL, GLITTER_PARTICLE_LOCUS); + igText("Locus: ctrl%lld, disp%lld", ctrl, disp); + + ctrl = glitter_particle_manager_get_ctrl_count(GPM_VAL, GLITTER_PARTICLE_LINE); + disp = glitter_particle_manager_get_disp_count(GPM_VAL, GLITTER_PARTICLE_LINE); + igText(" Line: ctrl%lld, disp%lld", ctrl, disp); + + ctrl = glitter_particle_manager_get_ctrl_count(GPM_VAL, GLITTER_PARTICLE_MESH); + disp = glitter_particle_manager_get_disp_count(GPM_VAL, GLITTER_PARTICLE_MESH); + igText(" Mesh: ctrl%lld, disp%lld", ctrl, disp); + + igSeparator(); + + imguiColumnSliderFloat("Emission", &gpm->emission, 1.0f, 2.0f, "%.2f", 0); + imguiColumnSliderFloat("Frame Speed", &frame_speed, 0.0f, 3.0f, "%.2f", 0); + + igSeparator(); + + imguiCheckbox("Grid", &grid_3d); + + glitter_test.imgui_focus |= igIsWindowFocused(0); + igEnd(); +} + +void glitter_test_input() { + if (!glitter_test_enabled) + return; + + input_locked |= glitter_test.imgui_focus; +} + +void glitter_test_render() { + if (glitter_test.dispose) { + glitter_test_dispose(); + return; + } + else if (!glitter_test_enabled) + return; + + if (!glitter_test.input_pause) { + if (gpm->scenes.end != gpm->scenes.begin) + glitter_test.frame_counter += get_frame_speed(); + + glitter_particle_manager_update_scene(GPM_VAL); + } + + if (glitter_test.file) { + if (glitter_test.input_play || glitter_test.input_stop) { + glitter_particle_manager_free_scenes(GPM_VAL); + glitter_test.frame_counter = 0.0f; + } + + uint64_t hash = glt_type != GLITTER_AFT + ? hash_char_murmurhash(glitter_test.file, 0, false) + : hash_char_fnv1a64(glitter_test.file); + if (glitter_test.input_auto && !glitter_particle_manager_check_scene(GPM_VAL, hash)) { + if (glitter_particle_manager_check_effect_group(GPM_VAL, hash)) + goto load; + else + goto reset; + } + else if (glitter_test.input_play && !glitter_particle_manager_test_load_scene(GPM_VAL, hash, true)) { + reset: + glitter_particle_manager_free_scenes(GPM_VAL); + glitter_particle_manager_free_effect_groups(GPM_VAL); + + glitter_file_reader* fr = glitter_file_reader_init(GPM_VAL, 0, glitter_test.file, -1.0f); + vector_ptr_glitter_file_reader_push_back(&gpm->file_readers, &fr); + glitter_particle_manager_update_file_reader(GPM_VAL); + load: + glitter_test.frame_counter = 0.0f; + glitter_particle_manager_test_load_scene(GPM_VAL, hash, true); + } + glitter_test.input_play = false; + glitter_test.input_stop = false; + } +} diff --git a/src/CLOUD/classes/data_test/glitter_test.h b/src/CLOUD/classes/data_test/glitter_test.h new file mode 100644 index 00000000..724cc496 --- /dev/null +++ b/src/CLOUD/classes/data_test/glitter_test.h @@ -0,0 +1,17 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../../../KKdLib/default.h" +#include "../../../KKdLib/vector.h" + +extern bool glitter_test_enabled; + +extern void glitter_test_dispose(); +extern void glitter_test_init(); +extern void glitter_test_imgui(); +extern void glitter_test_input(); +extern void glitter_test_render(); diff --git a/src/CLOUD/classes/graphics.c b/src/CLOUD/classes/graphics.c new file mode 100644 index 00000000..63b8dfaf --- /dev/null +++ b/src/CLOUD/classes/graphics.c @@ -0,0 +1,59 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "graphics.h" + +bool graphics_enabled = true; + +classes_struct graphics_classes[3] = { + { + .name = "Background Color", + .flags = CLASSES_IN_CONTEXT_MENU, + .enabled = &background_color_enabled, + .dispose = (void*)background_color_dispose, + .init = (void*)background_color_init, + .control = (void*)0, + .drop = (void*)0, + .imgui = (void*)background_color_imgui, + .input = (void*)background_color_input, + .render = (void*)background_color_render, + .sound = (void*)0, + .lock = 0, + .sub_classes = 0, + .sub_classes_count = 0, + }, + { + .name = "Post Process", + .flags = CLASSES_IN_CONTEXT_MENU, + .enabled = &post_process_enabled, + .dispose = (void*)post_process_dispose, + .init = (void*)post_process_init, + .control = (void*)0, + .drop = (void*)0, + .imgui = (void*)post_process_imgui, + .input = (void*)post_process_input, + .render = (void*)post_process_render, + .sound = (void*)0, + .lock = 0, + .sub_classes = 0, + .sub_classes_count = 0, + }, + { + .name = "Glitter##Counter", + .flags = CLASSES_IN_CONTEXT_MENU, + .enabled = &glitter_counter_enabled, + .dispose = (void*)glitter_counter_dispose, + .init = (void*)glitter_counter_init, + .control = (void*)0, + .drop = (void*)0, + .imgui = (void*)glitter_counter_imgui, + .input = (void*)glitter_counter_input, + .render = (void*)glitter_counter_render, + .sound = (void*)0, + .lock = 0, + .sub_classes = 0, + .sub_classes_count = 0, + }, +}; diff --git a/src/CLOUD/classes/graphics.h b/src/CLOUD/classes/graphics.h new file mode 100644 index 00000000..7b6dd8d7 --- /dev/null +++ b/src/CLOUD/classes/graphics.h @@ -0,0 +1,14 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../classes.h" +#include "graphics/background_color.h" +#include "graphics/glitter_counter.h" +#include "graphics/post_process.h" + +extern bool graphics_enabled; +extern classes_struct graphics_classes[]; diff --git a/src/CLOUD/classes/graphics/background_color.c b/src/CLOUD/classes/graphics/background_color.c new file mode 100644 index 00000000..5298dd73 --- /dev/null +++ b/src/CLOUD/classes/graphics/background_color.c @@ -0,0 +1,97 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "background_color.h" +#include "../imgui_helper.h" + +typedef struct background_color_struct { + bool dispose; + bool disposed; + bool imgui_focus; +} background_color_struct; + +extern int32_t width; +extern int32_t height; +extern bool input_locked; +extern vec3 back3d_color; + +const char* background_color_window_title = "Background Color"; + +bool background_color_enabled = false; +static background_color_struct background_color; + +void background_color_dispose() { + background_color_enabled = false; + background_color.imgui_focus = false; + background_color.dispose = false; + background_color.disposed = true; +} + +void background_color_init() { + if (background_color_enabled || background_color.dispose) + background_color_dispose(); + + background_color_enabled = true; +} + +void background_color_imgui() { + if (!background_color_enabled) { + if (!background_color.disposed) + background_color.dispose = true; + return; + } + else if (background_color.disposed) + background_color_enabled = true; + + float_t w = min((float_t)width / 4.0f, 360.0f); + float_t h = min((float_t)height, 80.0f); + + igSetNextWindowPos(ImVec2_Empty, ImGuiCond_Appearing, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Appearing); + + ImGuiWindowFlags window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoCollapse; + + background_color.imgui_focus = false; + if (!igBegin(background_color_window_title, &background_color_enabled, window_flags)) { + background_color.dispose = true; + igEnd(); + return; + } + + ImVec2 temp; + igGetContentRegionAvail(&temp); + + ImGuiColorEditFlags color_edit_flags = 0; + color_edit_flags |= ImGuiColorEditFlags_NoLabel; + color_edit_flags |= ImGuiColorEditFlags_NoSidePreview; + color_edit_flags |= ImGuiColorEditFlags_NoDragDrop; + + igSetNextItemWidth(temp.x); + igColorEdit3("##Background Color", (float_t*)&back3d_color, color_edit_flags); + + if (imguiButton("Reset Color", ImVec2_Empty)) + back3d_color = (vec3){ 0.74117647f, 0.74117647f, 0.74117647f }; + + background_color.imgui_focus |= igIsWindowFocused(0); + igEnd(); +} + +void background_color_input() { + if (!background_color_enabled) + return; + + input_locked |= background_color.imgui_focus; +} + +void background_color_render() { + if (background_color.dispose) { + background_color_dispose(); + return; + } + else if (!background_color_enabled) + return; +} diff --git a/src/CLOUD/classes/graphics/background_color.h b/src/CLOUD/classes/graphics/background_color.h new file mode 100644 index 00000000..50053e71 --- /dev/null +++ b/src/CLOUD/classes/graphics/background_color.h @@ -0,0 +1,17 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../../../KKdLib/default.h" +#include "../../../KKdLib/vec.h" + +extern bool background_color_enabled; + +extern void background_color_dispose(); +extern void background_color_init(); +extern void background_color_imgui(); +extern void background_color_input(); +extern void background_color_render(); diff --git a/src/CLOUD/classes/graphics/glitter_counter.c b/src/CLOUD/classes/graphics/glitter_counter.c new file mode 100644 index 00000000..df955880 --- /dev/null +++ b/src/CLOUD/classes/graphics/glitter_counter.c @@ -0,0 +1,123 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "glitter_counter.h" +#include "../../../CRE/Glitter/glitter.h" +#include "../../../CRE/Glitter/particle_manager.h" +#include "../imgui_helper.h" + +typedef struct glitter_counter_struct { + bool dispose; + bool disposed; + bool imgui_focus; +} glitter_counter_struct; + +extern int32_t width; +extern int32_t height; +extern bool input_locked; + +extern glitter_particle_manager* gpm; +glitter_type glt_type; + +const char* glitter_counter_window_title = "Glitter##Counter"; + +bool glitter_counter_enabled = false; +static glitter_counter_struct glitter_counter; + +void glitter_counter_dispose() { + glitter_counter_enabled = false; + glitter_counter.imgui_focus = false; + glitter_counter.dispose = false; + glitter_counter.disposed = true; +} + +void glitter_counter_init() { + if (glitter_counter_enabled || glitter_counter.dispose) + glitter_counter_dispose(); + + glitter_counter_enabled = true; +} + +void glitter_counter_imgui() { + if (!glitter_counter_enabled) { + if (!glitter_counter.disposed) + glitter_counter.dispose = true; + return; + } + else if (glitter_counter.disposed) + glitter_counter_enabled = true; + + float_t w = min((float_t)width / 4.0f, 148.0f); + float_t h = min((float_t)height, 204.0f); + + igSetNextWindowPos(ImVec2_Empty, ImGuiCond_Appearing, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Appearing); + + ImGuiWindowFlags window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoCollapse; + + glitter_counter.imgui_focus = false; + if (!igBegin(glitter_counter_window_title, &glitter_counter_enabled, window_flags)) { + glitter_counter.dispose = true; + igEnd(); + return; + } + + size_t ctrl; + size_t disp; + size_t total_ctrl = 0; + size_t total_disp = 0; + + ctrl = glitter_particle_manager_get_ctrl_count(gpm, glt_type, GLITTER_PARTICLE_QUAD); + disp = glitter_particle_manager_get_disp_count(gpm, glt_type, GLITTER_PARTICLE_QUAD); + igText("QUAD (ctrl):%6lld", ctrl); + igText(" (disp):%6lld", disp); + total_ctrl += ctrl; + total_disp += disp; + + ctrl = glitter_particle_manager_get_ctrl_count(gpm, glt_type, GLITTER_PARTICLE_LOCUS); + disp = glitter_particle_manager_get_disp_count(gpm, glt_type, GLITTER_PARTICLE_LOCUS); + igText("LOCUS (ctrl):%6lld", ctrl); + igText(" (disp):%6lld", disp); + total_ctrl += ctrl; + total_disp += disp; + + ctrl = glitter_particle_manager_get_ctrl_count(gpm, glt_type, GLITTER_PARTICLE_LINE); + disp = glitter_particle_manager_get_disp_count(gpm, glt_type, GLITTER_PARTICLE_LINE); + igText("LINE (ctrl):%6lld", ctrl); + igText(" (disp):%6lld", disp); + total_ctrl += ctrl; + total_disp += disp; + + ctrl = glitter_particle_manager_get_ctrl_count(gpm, glt_type, GLITTER_PARTICLE_MESH); + disp = glitter_particle_manager_get_disp_count(gpm, glt_type, GLITTER_PARTICLE_MESH); + igText("MESH (ctrl):%6lld", ctrl); + igText(" (disp):%6lld", disp); + total_ctrl += ctrl; + total_disp += disp; + + igText("TOTAL (ctrl):%6lld", total_ctrl); + igText(" (disp):%6lld", total_disp); + + glitter_counter.imgui_focus |= igIsWindowFocused(0); + igEnd(); +} + +void glitter_counter_input() { + if (!glitter_counter_enabled) + return; + + input_locked |= glitter_counter.imgui_focus; +} + +void glitter_counter_render() { + if (glitter_counter.dispose) { + glitter_counter_dispose(); + return; + } + else if (!glitter_counter_enabled) + return; +} diff --git a/src/CLOUD/classes/graphics/glitter_counter.h b/src/CLOUD/classes/graphics/glitter_counter.h new file mode 100644 index 00000000..733e65ae --- /dev/null +++ b/src/CLOUD/classes/graphics/glitter_counter.h @@ -0,0 +1,16 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../../../KKdLib/default.h" + +extern bool glitter_counter_enabled; + +extern void glitter_counter_dispose(); +extern void glitter_counter_init(); +extern void glitter_counter_imgui(); +extern void glitter_counter_input(); +extern void glitter_counter_render(); diff --git a/src/CLOUD/classes/graphics/post_process.c b/src/CLOUD/classes/graphics/post_process.c new file mode 100644 index 00000000..b1e176ec --- /dev/null +++ b/src/CLOUD/classes/graphics/post_process.c @@ -0,0 +1,245 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "post_process.h" +#include "../../../CRE/post_process.h" +#include "../../../CRE/dof.h" +#include "../imgui_helper.h" + +typedef struct post_process_struct { + bool dispose; + bool disposed; + bool imgui_focus; +} post_process_struct; + +extern int32_t width; +extern int32_t height; +extern bool input_locked; + +const char* post_process_window_title = "Post Process"; + +extern dof_struct* dof; +extern radius* rad; +extern intensity* inten; +extern tone_map_sat_gamma* tmsg; +extern tone_map_data* tmd; + +bool post_process_enabled = false; +static post_process_struct post_process; + +extern void post_process_dispose() { + post_process_enabled = false; + post_process.imgui_focus = false; + post_process.dispose = false; + post_process.disposed = true; +} + +extern void post_process_init() { + if (post_process_enabled || post_process.dispose) + post_process_dispose(); + + post_process_enabled = true; +} + +extern void post_process_imgui() { + if (!post_process_enabled) { + if (!post_process.disposed) + post_process.dispose = true; + return; + } + else if (post_process.disposed) + post_process_enabled = true; + + ImGuiIO* io = igGetIO(); + ImGuiStyle* style = igGetStyle(); + ImFont* font = igGetFont(); + + float_t w = min((float_t)width / 4.0f, 360.0f); + float_t h = min((float_t)height, 740.0f); + + igSetNextWindowPos(ImVec2_Empty, ImGuiCond_Appearing, ImVec2_Empty); + igSetNextWindowSize((ImVec2) { w, h }, ImGuiCond_Appearing); + + ImGuiWindowFlags window_flags = 0; + window_flags |= ImGuiWindowFlags_NoResize; + window_flags |= ImGuiWindowFlags_NoCollapse; + + post_process.imgui_focus = false; + if (!igBegin(post_process_window_title, &post_process_enabled, window_flags)) { + post_process.dispose = true; + igEnd(); + return; + } + + if (igTreeNode_Str("Tone Trans")) { + vec3 tone_trans_start = *tone_map_data_get_tone_trans_start(tmd); + imguiColumnSliderVec3("Start", &tone_trans_start, 0.0f, 1.0f, "%.2f", 0); + tone_map_data_set_tone_trans_start(tmd, &tone_trans_start); + + vec3 tone_trans_end = *tone_map_data_get_tone_trans_end(tmd); + imguiColumnSliderVec3("End", &tone_trans_end, 0.0f, 1.0f, "%.2f", 0); + tone_map_data_set_tone_trans_end(tmd, &tone_trans_end); + igTreePop(); + } + + if (igTreeNode_Str("Scene Fade")) { + float_t scene_fade_alpha = tone_map_data_get_scene_fade_alpha(tmd); + imguiColumnSliderFloat("Alpha", &scene_fade_alpha, 0.0f, 1.0f, "%.2f", 0); + tone_map_data_set_scene_fade_alpha(tmd, scene_fade_alpha); + + vec3 scene_fade_color = *tone_map_data_get_scene_fade_color(tmd); + imguiColumnSliderVec3("Color", &scene_fade_color, 0.0f, 1.0f, "%.2f", 0); + tone_map_data_set_scene_fade_color(tmd, &scene_fade_color); + + const char* scene_fade_blend_func_labels[] = { + "0: OVER", + "1: MULTI", + "2: PLUS", + }; + + int32_t scene_fade_blend_func = tone_map_data_get_scene_fade_blend_func(tmd); + imguiColumnComboBox("Blend Func", scene_fade_blend_func_labels, 3, + &scene_fade_blend_func, 0, false, &post_process.imgui_focus); + tone_map_data_set_scene_fade_blend_func(tmd, scene_fade_blend_func); + igTreePop(); + } + + if (igTreeNodeEx_Str("Glow Param", ImGuiTreeNodeFlags_DefaultOpen)) { + const char* tone_map_method_labels[] = { + "YCC EXPONENT", + "RGB LINEAR", + "RGB LINEAR2", + }; + + int32_t tone_map_method = tone_map_data_get_tone_map_method(tmd); + imguiColumnComboBox("Tone Map", tone_map_method_labels, 3, + &tone_map_method, 0, false, &post_process.imgui_focus); + tone_map_data_set_tone_map_method(tmd, tone_map_method); + + float_t exposure = tone_map_data_get_exposure(tmd); + imguiColumnSliderFloat("Exposure", &exposure, 0.0f, 4.0f, "%.2f", 0); + exposure = roundf(exposure / 0.02f) * 0.02f; + tone_map_data_set_exposure(tmd, exposure); + + bool auto_exposure = tone_map_data_get_auto_exposure(tmd); + imguiCheckbox("Auto Exposure", &auto_exposure); + tone_map_data_set_auto_exposure(tmd, auto_exposure); + + float_t gamma = tone_map_sat_gamma_get_gamma(tmsg); + imguiColumnSliderFloat("Gamma", &gamma, 0.2f, 2.2f, "%.2f", 0); + tone_map_sat_gamma_set_gamma(tmsg, gamma); + + int32_t saturate1 = tone_map_sat_gamma_get_saturate1(tmsg); + imguiColumnSliderInt("Saturate 1", &saturate1, 1, 6, "%d", 0); + tone_map_sat_gamma_set_saturate1(tmsg, saturate1); + + float_t saturate2 = tone_map_sat_gamma_get_saturate2(tmsg); + imguiColumnSliderFloat("Saturate 2", &saturate2, 0.0f, 1.0f, "%.2f", 0); + tone_map_sat_gamma_set_saturate2(tmsg, saturate2); + igTreePop(); + } + + if (igTreeNodeEx_Str("Glare", ImGuiTreeNodeFlags_DefaultOpen)) { + vec3 radius = *radius_get(rad); + imguiColumnSliderFloat("Radius R", &radius.x, 1.0f, 3.0f, "%.2f", 0); + imguiColumnSliderFloat("Radius G", &radius.y, 1.0f, 3.0f, "%.2f", 0); + imguiColumnSliderFloat("Radius B", &radius.z, 1.0f, 3.0f, "%.2f", 0); + radius_set(rad, &radius); + + vec3 intensity = *intensity_get(inten); + imguiColumnSliderFloat("Inten R", &intensity.x, 0.0f, 2.0f, "%.2f", 0); + imguiColumnSliderFloat("Inten G", &intensity.y, 0.0f, 2.0f, "%.2f", 0); + imguiColumnSliderFloat("Inten B", &intensity.z, 0.0f, 2.0f, "%.2f", 0); + intensity_set(inten, &intensity); + igTreePop(); + } + + if (igTreeNodeEx_Str("DOF", ImGuiTreeNodeFlags_DefaultOpen)) { + bool use_ui_params = dof->debug.flags & DOF_DEBUG_USE_UI_PARAMS; + bool phys = use_ui_params && dof->debug.flags & DOF_DEBUG_ENABLE_PHYS_DOF; + bool f2 = use_ui_params && ~dof->debug.flags & DOF_DEBUG_ENABLE_PHYS_DOF; + + float_t alpha = style->Alpha * imgui_alpha_disabled_scale; + + imguiCheckboxFlags_UintPtr("use UI params", (uint32_t*)&dof->debug.flags, DOF_DEBUG_USE_UI_PARAMS); + + if (!use_ui_params) { + igPushItemFlag(ImGuiItemFlags_Disabled, true); + igPushStyleVar_Float(ImGuiStyleVar_Alpha, alpha); + } + imguiCheckboxFlags_UintPtr("enable DOF", (uint32_t*)&dof->debug.flags, DOF_DEBUG_ENABLE_DOF); + imguiCheckboxFlags_UintPtr("enable physical DOF", (uint32_t*)&dof->debug.flags, DOF_DEBUG_ENABLE_PHYS_DOF); + if (!use_ui_params) { + igPopItemFlag(); + igPopStyleVar(1); + } + + if (!phys) { + igPushItemFlag(ImGuiItemFlags_Disabled, true); + igPushStyleVar_Float(ImGuiStyleVar_Alpha, alpha); + } + imguiCheckboxFlags_UintPtr("auto focus", (uint32_t*)&dof->debug.flags, DOF_DEBUG_AUTO_FOCUS); + if (!phys) { + igPopItemFlag(); + igPopStyleVar(1); + } + + imguiSetColumnSpace(16.0f / 31.0f); + if (!phys) { + igPushItemFlag(ImGuiItemFlags_Disabled, true); + igPushStyleVar_Float(ImGuiStyleVar_Alpha, alpha); + } + imguiColumnSliderFloat("distance to focus[m]", &dof->debug.distance_to_focus, 0.01f, 30.0f, "%.2f", 0); + imguiColumnSliderFloat("focal length[mm]", &dof->debug.focal_length, 0.1f, 100.0f, "%.2f", 0); + imguiColumnSliderFloat("F-Number", &dof->debug.f_number, 0.1f, 40.0f, "%.2f", 0); + if (!phys) { + igPopItemFlag(); + igPopStyleVar(1); + } + + if (!f2) { + igPushItemFlag(ImGuiItemFlags_Disabled, true); + igPushStyleVar_Float(ImGuiStyleVar_Alpha, alpha); + } + imguiColumnSliderFloat("f2 distance to focus[m]", &dof->debug.f2.distance_to_focus, 0.01f, 30.0f, "%.2f", 0); + imguiColumnSliderFloat("f2 focus range[m]", &dof->debug.f2.focus_range, 0.0f, 10.0f, "%.2f", 0); + imguiColumnSliderFloat("f2 fuzzing range[m]", &dof->debug.f2.fuzzing_range, 0.0f, 10.0f, "%.2f", 0); + imguiColumnSliderFloat("f2 ratio", &dof->debug.f2.ratio, 0.0f, 1.0f, "%.2f", 0); + if (!f2) { + igPopItemFlag(); + igPopStyleVar(1); + } + imguiSetDefaultColumnSpace(); + igTreePop(); + } + + if (imguiButton("Reset Post Process", ImVec2_Empty)) { + dof_initialize(dof, 0, 0); + radius_initialize(rad, (vec3[]) { 2.0f, 2.0f, 2.0f }); + intensity_initialize(inten, (vec3[]) { 1.0f, 1.0f, 1.0f }); + tone_map_sat_gamma_initialize(tmsg, 1.0f, 1, 1.0f); + tone_map_data_initialize(tmd, 2.0f, true, (vec3[]) { 0.0f, 0.0f, 0.0f}, 0.0f, 0, + (vec3[]) { 0.0f, 0.0f, 0.0f }, (vec3[]) { 1.0f, 1.0f, 1.0f }, 0); + } + + post_process.imgui_focus |= igIsWindowFocused(0); + igEnd(); +} + +void post_process_input() { + if (!post_process_enabled) + return; + + input_locked |= post_process.imgui_focus; +} + +extern void post_process_render() { + if (post_process.dispose) { + post_process_dispose(); + return; + } + else if (!post_process_enabled) + return; +} diff --git a/src/CLOUD/classes/graphics/post_process.h b/src/CLOUD/classes/graphics/post_process.h new file mode 100644 index 00000000..92fdaba3 --- /dev/null +++ b/src/CLOUD/classes/graphics/post_process.h @@ -0,0 +1,16 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../../../KKdLib/default.h" + +extern bool post_process_enabled; + +extern void post_process_dispose(); +extern void post_process_init(); +extern void post_process_imgui(); +extern void post_process_input(); +extern void post_process_render(); diff --git a/src/CLOUD/classes/imgui_helper.c b/src/CLOUD/classes/imgui_helper.c new file mode 100644 index 00000000..9faef809 --- /dev/null +++ b/src/CLOUD/classes/imgui_helper.c @@ -0,0 +1,1094 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "imgui_helper.h" +#include "../../KKdLib/str_utils.h" + +const ImVec1 ImVec1_Empty = { 0.0f }; +const ImVec2 ImVec2_Empty = { 0.0f, 0.0f }; +const ImVec4 ImVec4_Empty = { 0.0f, 0.0f, 0.0f, 0.0f }; +const ImVec1 ImVec1_Identity = { 1.0f }; +const ImVec2 ImVec2_Identity = { 1.0f, 1.0f }; +const ImVec4 ImVec4_Identity = { 1.0f, 1.0f, 1.0f, 1.0f }; +const float_t imgui_alpha_disabled_scale = 0.5f; + +static float_t column_space = (float_t)(1.0 / 3.0); +static float_t cell_padding; + +inline bool imguiItemKeyDown(int32_t key) { + return igIsItemFocused() && igIsKeyDown(key); +} + +inline bool imguiItemKeyPressed(int32_t key, bool repeat) { + return igIsItemFocused() && igIsKeyPressed(key, repeat); +} + +inline bool imguiItemKeyReleased(int32_t key) { + return igIsItemFocused() && igIsKeyReleased(key); +} + +inline float_t imguiGetColumnSpace() { + return column_space; +} + +inline void imguiSetColumnSpace(float_t val) { + column_space = val; +} + +inline void imguiSetDefaultColumnSpace() { + column_space = (float_t)(1.0 / 3.0); +} + +inline void imguiDisableElementPush(bool enable) { + if (!enable) { + igPushItemFlag(ImGuiItemFlags_Disabled, true); + igPushStyleVar_Float(ImGuiStyleVar_Alpha, igGetStyle()->Alpha * imgui_alpha_disabled_scale); + } +} + +inline void imguiDisableElementPop(bool enable) { + if (!enable) { + igPopItemFlag(); + igPopStyleVar(1); + } +} + +const char* imguiStartPropertyColumn(const char* label) { + igPushID_Str(label); + + ImVec2 t; + igGetContentRegionAvail(&t); + igBeginTable("table", 2, 0, ImVec2_Empty, 0.0f); + igTableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, t.x * column_space, 0); + + char* label_temp = str_utils_add((char*)label, ""); + char* temp; + if (temp = strstr(label_temp, "##")) + *temp = 0; + igTableNextColumn(); + igGetContentRegionAvail(&t); + igSetNextItemWidth(t.x); + igText(label_temp); + free(label_temp); + + igTableNextColumn(); + igGetContentRegionAvail(&t); + igSetNextItemWidth(t.x); + return (const char*)str_utils_add("##", (char*)label); +} + +void imguiEndPropertyColumn(const char* temp) { + igEndTable(); + igPopID(); + free((void*)temp); +} + +bool imguiButton(const char* label, const ImVec2 size) { + return igButton(label, size) || imguiItemKeyPressed(GLFW_KEY_ENTER, true); +} + +bool imguiButtonEx(const char* label, const ImVec2 size, ImGuiButtonFlags flags) { + return igButtonEx(label, size, flags) || imguiItemKeyPressed(GLFW_KEY_ENTER, true); +} + +bool imguiCheckbox(const char* label, bool* v) { + if (igCheckbox(label, v)) + return true; + else if (imguiItemKeyPressed(GLFW_KEY_ENTER, true)) { + *v ^= true; + return true; + } + else + return false; +} + +bool imguiCheckboxFlags_IntPtr(const char* label, int* flags, int flags_value) { + if (igCheckboxFlags_IntPtr(label, flags, flags_value)) + return true; + else if (imguiItemKeyPressed(GLFW_KEY_ENTER, true)) { + *flags ^= flags_value; + return true; + } + else + return false; +} + +bool imguiCheckboxFlags_UintPtr(const char* label, unsigned int* flags, unsigned int flags_value) { + if (igCheckboxFlags_UintPtr(label, flags, flags_value)) + return true; + else if (imguiItemKeyPressed(GLFW_KEY_ENTER, true)) { + *flags ^= flags_value; + return true; + } + else + return false; +} + +static bool igDragFloatDisable(const char* label, float_t* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, bool enable) { + igPushID_Str(label); + imguiDisableElementPush(enable); + bool res = igDragFloat("", val, speed, min, max, enable ? format : "...", flags); + imguiDisableElementPop(enable); + igPopID(); + igPopItemWidth(); + return res; +} + +static bool igDragIntDisable(const char* label, int32_t* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, bool enable) { + igPushID_Str(label); + imguiDisableElementPush(enable); + bool res = igDragInt("", val, speed, min, max, enable ? format : "...", flags); + imguiDisableElementPop(enable); + igPopID(); + igPopItemWidth(); + return res; +} + +static bool igSliderFloatDisable(const char* label, float_t* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, bool enable) { + igPushID_Str(label); + imguiDisableElementPush(enable); + bool res = igSliderFloat(label, val, min, max, enable ? format : "...", flags); + imguiDisableElementPop(enable); + igPopID(); + igPopItemWidth(); + return res; +} + +static bool igSliderIntDisable(const char* label, int32_t* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, bool enable) { + igPushID_Str(label); + imguiDisableElementPush(enable); + bool res = igSliderInt(label, val, min, max, enable ? format : "...", flags); + imguiDisableElementPop(enable); + igPopID(); + igPopItemWidth(); + return res; +} + +static const char* startPropertyColumnDisable(const char* label, bool enable) { + igPushID_Str(label); + + ImVec2 t; + igGetContentRegionAvail(&t); + igBeginTable("table", 2, 0, ImVec2_Empty, 0.0f); + igTableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, t.x * column_space, 0); + + char* label_temp = str_utils_add((char*)label, ""); + char* temp; + if (temp = strstr(label_temp, "##")) + *temp = 0; + igTableNextColumn(); + igGetContentRegionAvail(&t); + igSetNextItemWidth(t.x); + imguiDisableElementPush(enable); + igText(label_temp); + imguiDisableElementPop(enable); + free(label_temp); + + igTableNextColumn(); + igGetContentRegionAvail(&t); + igSetNextItemWidth(t.x); + return (const char*)str_utils_add("##", (char*)label); +} + +bool imguiComboBox(const char* label, const char** items, const size_t size, + int32_t* selected_idx, ImGuiComboFlags flags, bool include_last, bool* focus) { + int32_t prev_selected_idx = *selected_idx; + + if (!include_last && size < 1) { + imguiDisableElementPush(false); + if (igBeginCombo(label, "None", flags)) + igEndCombo(); + imguiDisableElementPop(false); + return false; + } + + if (igBeginCombo(label, items[*selected_idx], flags)) { + if (include_last) + for (size_t n = 0; n <= size; n++) { + igPushID_Int((int32_t)n); + if (igSelectable_Bool(items[n], *selected_idx == n, 0, ImVec2_Empty) + || imguiItemKeyPressed(GLFW_KEY_ENTER, true)) + *selected_idx = (int32_t)n; + igPopID(); + + if (*selected_idx == n) + igSetItemDefaultFocus(); + } + else + for (size_t n = 0; n < size; n++) { + igPushID_Int((int32_t)n); + if (igSelectable_Bool(items[n], *selected_idx == n, 0, ImVec2_Empty) + || imguiItemKeyPressed(GLFW_KEY_ENTER, true)) + *selected_idx = (int32_t)n; + igPopID(); + + if (*selected_idx == n) + igSetItemDefaultFocus(); + } + + if (focus) + *focus |= igIsWindowFocused(0); + igEndCombo(); + } + return prev_selected_idx != *selected_idx; +} + +bool imguiColumnColorEdit3(const char* label, vec3* val, ImGuiColorEditFlags flags) { + float_t v[3]; + *(vec3*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igColorEdit3(temp_label, v, flags); + imguiEndPropertyColumn(temp_label); + if (res) + *val = *(vec3*)v; + return res; +} + +bool imguiColumnColorEdit4(const char* label, vec4* val, ImGuiColorEditFlags flags) { + float_t v[4]; + *(vec4*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igColorEdit4(temp_label, v, flags); + imguiEndPropertyColumn(temp_label); + if (res) + *val = *(vec4*)v; + return res; +} + +bool imguiColumnComboBox(const char* label, const char** items, const size_t size, + int32_t* selected_idx, ImGuiComboFlags flags, bool include_last, bool* focus) { + const char* temp_label = imguiStartPropertyColumn(label); + bool res = imguiComboBox(temp_label, items, size, selected_idx, flags, include_last, focus); + imguiEndPropertyColumn(temp_label); + return res; +} + +bool imguiColumnDragFloat(const char* label, float_t* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags) { + float_t v[1]; + *v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igDragFloat(temp_label, v, speed, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + *v = clamp(*v, min, max); + if (*v == *val) + return false; + + *val = *v; + return true; +} + +bool imguiColumnDragVec2(const char* label, vec2* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags) { + float_t v[2]; + *(vec2*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igDragFloat2(temp_label, v, speed, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + if (v[0] == val->x && v[1] == val->y) + return false; + + *val = *(vec2*)v; + return true; +} + +bool imguiColumnDragVec3(const char* label, vec3* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags) { + float_t v[3]; + *(vec3*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igDragFloat3(temp_label, v, speed, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z) + return false; + + *val = *(vec3*)v; + return true; +} + +bool imguiColumnDragVec4(const char* label, vec4* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags) { + float_t v[4]; + *(vec4*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igDragFloat4(temp_label, v, speed, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + v[3] = clamp(v[3], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) + return false; + + *val = *(vec4*)v; + return true; +} + +bool imguiColumnDragInt(const char* label, int32_t* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags) { + int32_t v[1]; + *v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igDragInt(temp_label, v, speed, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + *v = clamp(*v, min, max); + if (*v == *val) + return false; + + *val = *v; + return true; +} + +bool imguiColumnDragVec2I(const char* label, vec2i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags) { + int32_t v[2]; + *(vec2i*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igDragInt2(temp_label, v, speed, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + if (v[0] == val->x && v[1] == val->y) + return false; + + *val = *(vec2i*)v; + return true; +} + +bool imguiColumnDragVec3I(const char* label, vec3i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags) { + int32_t v[3]; + *(vec3i*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igDragInt3(temp_label, v, speed, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z) + return false; + + *val = *(vec3i*)v; + return true; +} + +bool imguiColumnDragVec4I(const char* label, vec4i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags) { + int32_t v[4]; + *(vec4i*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igDragInt4(temp_label, v, speed, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + v[3] = clamp(v[3], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) + return false; + + *val = *(vec4i*)v; + return true; +} + +bool imguiColumnInputText(const char* label, char* buf, size_t buf_size, + ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) { + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igInputText(temp_label, buf, buf_size, flags, callback, user_data); + imguiEndPropertyColumn(temp_label); + return res; +} + +bool imguiColumnSliderFloat(const char* label, float_t* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags) { + float_t v[1]; + *v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igSliderFloat(temp_label, v, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + *v = clamp(*v, min, max); + if (*v == *val) + return false; + + *val = *v; + return true; +} + +bool imguiColumnSliderVec2(const char* label, vec2* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags) { + float_t v[2]; + *(vec2*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igSliderFloat2(temp_label, v, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + if (v[0] == val->x && v[1] == val->y) + return false; + + *val = *(vec2*)v; + return true; +} + +bool imguiColumnSliderVec3(const char* label, vec3* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags) { + float_t v[3]; + *(vec3*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igSliderFloat3(temp_label, v, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z) + return false; + + *val = *(vec3*)v; + return true; +} + +bool imguiColumnSliderVec4(const char* label, vec4* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags) { + float_t v[4]; + *(vec4*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igSliderFloat4(temp_label, v, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + v[3] = clamp(v[3], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) + return false; + + *val = *(vec4*)v; + return true; +} + +bool imguiColumnSliderInt(const char* label, int32_t* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags) { + int32_t v[1]; + *v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igSliderInt(temp_label, v, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + *v = clamp(*v, min, max); + if (*v == *val) + return false; + + *val = *v; + return true; +} + +bool imguiColumnSliderVec2I(const char* label, vec2i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags) { + int32_t v[2]; + *(vec2i*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igSliderInt2(temp_label, v, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + if (v[0] == val->x && v[1] == val->y) + return false; + + *val = *(vec2i*)v; + return true; +} + +bool imguiColumnSliderVec3I(const char* label, vec3i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags) { + int32_t v[3]; + *(vec3i*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igSliderInt3(temp_label, v, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z) + return false; + + *val = *(vec3i*)v; + return true; +} + +bool imguiColumnSliderVec4I(const char* label, vec4i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags) { + int32_t v[4]; + *(vec4i*)v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igSliderInt4(temp_label, v, min, max, format, flags); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + v[3] = clamp(v[3], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) + return false; + + *val = *(vec4i*)v; + return true; +} + +bool imguiColumnInputFloat(const char* label, float_t* val, + float_t step, float_t step_fast, const char* format, ImGuiInputTextFlags flags) { + float_t v[1]; + *v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igInputFloat(temp_label, v, step, step_fast, format, flags); + imguiEndPropertyColumn(temp_label); + if (res) + *val = *v; + return res; +} + +bool imguiColumnInputInt(const char* label, int32_t* val, + int32_t step, int32_t step_fast, ImGuiInputTextFlags flags) { + int32_t v[1]; + *v = *val; + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igInputInt(temp_label, v, step, step_fast, flags); + imguiEndPropertyColumn(temp_label); + if (res) + *val = *v; + return res; +} + +bool imguiColumnInputScalar(const char* label, ImGuiDataType data_type, void* p_data, + const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags) { + const char* temp_label = imguiStartPropertyColumn(label); + bool res = igInputScalar(temp_label, data_type, p_data, p_step, p_step_fast, format, flags); + imguiEndPropertyColumn(temp_label); + return res; +} + +bool imguiColumnDragFloatFlag(const char* label, float_t* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + float_t v[1]; + *v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x01 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(1, igCalcItemWidth()); + res |= igDragFloatDisable("##X", &v[0], speed, min, max, format, flags, bit_flag & 0x01 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + *v = clamp(*v, min, max); + if (*v == *val) + return false; + + *val = *v; + return true; +} + +bool imguiColumnDragVec2Flag(const char* label, vec2* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + float_t v[2]; + *(vec2*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x03 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(2, igCalcItemWidth()); + res |= igDragFloatDisable("##X", &v[0], speed, min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragFloatDisable("##Y", &v[1], speed, min, max, format, flags, bit_flag & 0x02 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + if (v[0] == val->x && v[1] == val->y) + return false; + + *val = *(vec2*)v; + return true; +} + +bool imguiColumnDragVec3Flag(const char* label, vec3* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + float_t v[3]; + *(vec3*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x07 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(3, igCalcItemWidth()); + res |= igDragFloatDisable("##X", &v[0], speed, min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragFloatDisable("##Y", &v[1], speed, min, max, format, flags, bit_flag & 0x02 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragFloatDisable("##Z", &v[2], speed, min, max, format, flags, bit_flag & 0x04 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z) + return false; + + *val = *(vec3*)v; + return true; +} + +bool imguiColumnDragVec4Flag(const char* label, vec4* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + float_t v[4]; + *(vec4*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x0F ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(4, igCalcItemWidth()); + res |= igDragFloatDisable("##X", &v[0], speed, min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragFloatDisable("##Y", &v[1], speed, min, max, format, flags, bit_flag & 0x02 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragFloatDisable("##Z", &v[2], speed, min, max, format, flags, bit_flag & 0x04 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragFloatDisable("##W", &v[3], speed, min, max, format, flags, bit_flag & 0x08 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + v[3] = clamp(v[3], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) + return false; + + *val = *(vec4*)v; + return true; +} + +bool imguiColumnDragIntFlag(const char* label, int32_t* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + int32_t v[1]; + *v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x01 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(1, igCalcItemWidth()); + res |= igDragIntDisable("##X", &v[0], speed, min, max, format, flags, bit_flag & 0x01 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + *v = clamp(*v, min, max); + if (*v == *val) + return false; + + *val = *v; + return true; +} + +bool imguiColumnDragVec2IFlag(const char* label, vec2i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + int32_t v[2]; + *(vec2i*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x03 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(2, igCalcItemWidth()); + res |= igDragIntDisable("##X", &v[0], speed, min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragIntDisable("##Y", &v[1], speed, min, max, format, flags, bit_flag & 0x02 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + if (v[0] == val->x && v[1] == val->y) + return false; + + *val = *(vec2i*)v; + return true; +} + +bool imguiColumnDragVec3IFlag(const char* label, vec3i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + int32_t v[3]; + *(vec3i*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x07 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(3, igCalcItemWidth()); + res |= igDragIntDisable("##X", &v[0], speed, min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragIntDisable("##Y", &v[1], speed, min, max, format, flags, bit_flag & 0x02 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragIntDisable("##Z", &v[2], speed, min, max, format, flags, bit_flag & 0x04 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z) + return false; + + *val = *(vec3i*)v; + return true; +} + +bool imguiColumnDragVec4IFlag(const char* label, vec4i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + int32_t v[4]; + *(vec4i*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x0F ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(4, igCalcItemWidth()); + res |= igDragIntDisable("##X", &v[0], speed, min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragIntDisable("##Y", &v[1], speed, min, max, format, flags, bit_flag & 0x02 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragIntDisable("##Z", &v[2], speed, min, max, format, flags, bit_flag & 0x04 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igDragIntDisable("##W", &v[3], speed, min, max, format, flags, bit_flag & 0x08 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + v[3] = clamp(v[3], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) + return false; + + *val = *(vec4i*)v; + return true; +} + +bool imguiColumnSliderFloatFlag(const char* label, float_t* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + float_t v[1]; + *v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x01 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(1, igCalcItemWidth()); + res |= igSliderFloatDisable("##X", &v[0], min, max, format, flags, bit_flag & 0x01 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + *v = clamp(*v, min, max); + if (*v == *val) + return false; + + *val = *v; + return true; +} + +bool imguiColumnSliderVec2Flag(const char* label, vec2* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + float_t v[2]; + *(vec2*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x03 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(2, igCalcItemWidth()); + res |= igSliderFloatDisable("##X", &v[0], min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderFloatDisable("##Y", &v[1], min, max, format, flags, bit_flag & 0x02 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + if (v[0] == val->x && v[1] == val->y) + return false; + + *val = *(vec2*)v; + return true; +} + +bool imguiColumnSliderVec3Flag(const char* label, vec3* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + float_t v[3]; + *(vec3*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x07 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(3, igCalcItemWidth()); + res |= igSliderFloatDisable("##X", &v[0], min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderFloatDisable("##Y", &v[1], min, max, format, flags, bit_flag & 0x02 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderFloatDisable("##Z", &v[2], min, max, format, flags, bit_flag & 0x04 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z) + return false; + + *val = *(vec3*)v; + return true; +} + +bool imguiColumnSliderVec4Flag(const char* label, vec4* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + float_t v[4]; + *(vec4*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x0F ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(4, igCalcItemWidth()); + res |= igSliderFloatDisable("##X", &v[0], min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderFloatDisable("##Y", &v[1], min, max, format, flags, bit_flag & 0x02 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderFloatDisable("##Z", &v[2], min, max, format, flags, bit_flag & 0x04 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderFloatDisable("##W", &v[3], min, max, format, flags, bit_flag & 0x08 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + v[3] = clamp(v[3], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) + return false; + + *val = *(vec4*)v; + return true; +} + +bool imguiColumnSliderIntFlag(const char* label, int32_t* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + int32_t v[1]; + *v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x01 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(1, igCalcItemWidth()); + res |= igSliderIntDisable("##X", &v[0], min, max, format, flags, bit_flag & 0x01 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + *v = clamp(*v, min, max); + if (*v == *val) + return false; + + *val = *v; + return true; +} + +bool imguiColumnSliderVec2IFlag(const char* label, vec2i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + int32_t v[2]; + *(vec2i*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x03 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(2, igCalcItemWidth()); + res |= igSliderIntDisable("##X", &v[0], min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderIntDisable("##Y", &v[1], min, max, format, flags, bit_flag & 0x02 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + if (v[0] == val->x && v[1] == val->y) + return false; + + *val = *(vec2i*)v; + return true; +} + +bool imguiColumnSliderVec3IFlag(const char* label, vec3i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + int32_t v[3]; + *(vec3i*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x07 ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(3, igCalcItemWidth()); + res |= igSliderIntDisable("##X", &v[0], min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderIntDisable("##Y", &v[1], min, max, format, flags, bit_flag & 0x02 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderIntDisable("##Z", &v[2], min, max, format, flags, bit_flag & 0x04 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z) + return false; + + *val = *(vec3i*)v; + return true; +} + +bool imguiColumnSliderVec4IFlag(const char* label, vec4i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag) { + int32_t v[4]; + *(vec4i*)v = *val; + const char* temp_label = startPropertyColumnDisable(label, bit_flag & 0x0F ? true : false); + bool res = false; + ImGuiStyle* style = igGetStyle(); + igBeginGroup(); + igPushID_Str(label); + igPushMultiItemsWidths(4, igCalcItemWidth()); + res |= igSliderIntDisable("##X", &v[0], min, max, format, flags, bit_flag & 0x01 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderIntDisable("##Y", &v[1], min, max, format, flags, bit_flag & 0x02 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderIntDisable("##Z", &v[2], min, max, format, flags, bit_flag & 0x04 ? true : false); + igSameLine(0.0f, style->ItemInnerSpacing.x); + res |= igSliderIntDisable("##W", &v[3], min, max, format, flags, bit_flag & 0x08 ? true : false); + igPopID(); + igEndGroup(); + imguiEndPropertyColumn(temp_label); + if (!res) + return false; + + v[0] = clamp(v[0], min, max); + v[1] = clamp(v[1], min, max); + v[2] = clamp(v[2], min, max); + v[3] = clamp(v[3], min, max); + if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) + return false; + + *val = *(vec4i*)v; + return true; +} diff --git a/src/CLOUD/classes/imgui_helper.h b/src/CLOUD/classes/imgui_helper.h new file mode 100644 index 00000000..958abe40 --- /dev/null +++ b/src/CLOUD/classes/imgui_helper.h @@ -0,0 +1,116 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../../KKdLib/default.h" +#include "../../KKdLib/vec.h" +#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS +#include +#include + +extern const ImVec1 ImVec1_Empty; +extern const ImVec2 ImVec2_Empty; +extern const ImVec4 ImVec4_Empty; +extern const ImVec1 ImVec1_Identity; +extern const ImVec2 ImVec2_Identity; +extern const ImVec4 ImVec4_Identity; +extern const float_t imgui_alpha_disabled_scale; + +extern bool imguiItemKeyDown(int32_t key); +extern bool imguiItemKeyPressed(int32_t key, bool repeat); +extern bool imguiItemKeyReleased(int32_t key); +extern float_t imguiGetColumnSpace(); +extern void imguiSetColumnSpace(float_t val); +extern void imguiSetDefaultColumnSpace(); +extern void imguiDisableElementPush(bool enable); +extern void imguiDisableElementPop(bool enable); + +extern const char* imguiStartPropertyColumn(const char* label); +extern void imguiEndPropertyColumn(const char* temp); + +extern bool imguiButton(const char* label, const ImVec2 size); +extern bool imguiButtonEx(const char* label, const ImVec2 size, ImGuiButtonFlags flags); +extern bool imguiCheckbox(const char* label, bool* v); +extern bool imguiCheckboxFlags_IntPtr(const char* label, int* flags, int flags_value); +extern bool imguiCheckboxFlags_UintPtr(const char* label, unsigned int* flags, unsigned int flags_value); +extern bool imguiComboBox(const char* label, const char** items, const size_t size, + int32_t* selected_idx, ImGuiComboFlags flags, bool include_last, bool* focus); +extern bool imguiColumnColorEdit3(const char* label, vec3* val, ImGuiColorEditFlags flags); +extern bool imguiColumnColorEdit4(const char* label, vec4* val, ImGuiColorEditFlags flags); +extern bool imguiColumnComboBox(const char* label, const char** items, const size_t size, + int32_t* selected_idx, ImGuiComboFlags flags, bool include_last, bool* focus); +extern bool imguiColumnDragFloat(const char* label, float_t* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnDragVec2(const char* label, vec2* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnDragVec3(const char* label, vec3* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnDragVec4(const char* label, vec4* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnDragInt(const char* label, int32_t* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnDragVec2I(const char* label, vec2i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnDragVec3I(const char* label, vec3i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnDragVec4I(const char* label, vec4i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnInputText(const char* label, char* buf, size_t buf_size, + ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data); +extern bool imguiColumnSliderFloat(const char* label, float_t* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnSliderVec2(const char* label, vec2* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnSliderVec3(const char* label, vec3* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnSliderVec4(const char* label, vec4* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnSliderInt(const char* label, int32_t* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnSliderVec2I(const char* label, vec2i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnSliderVec3I(const char* label, vec3i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnSliderVec4I(const char* label, vec4i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); +extern bool imguiColumnInputFloat(const char* label, float_t* val, + float_t step, float_t step_fast, const char* format, ImGuiInputTextFlags flags); +extern bool imguiColumnInputInt(const char* label, int32_t* val, + int32_t step, int32_t step_fast, ImGuiInputTextFlags flags); +extern bool imguiColumnInputScalar(const char* label, ImGuiDataType data_type, void* p_data, + const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags); +extern bool imguiColumnDragFloatFlag(const char* label, float_t* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnDragVec2Flag(const char* label, vec2* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnDragVec3Flag(const char* label, vec3* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnDragVec4Flag(const char* label, vec4* val, float_t speed, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnDragIntFlag(const char* label, int32_t* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnDragVec2IFlag(const char* label, vec2i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnDragVec3IFlag(const char* label, vec3i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnDragVec4IFlag(const char* label, vec4i* val, float_t speed, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnSliderFloatFlag(const char* label, float_t* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnSliderVec2Flag(const char* label, vec2* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnSliderVec3Flag(const char* label, vec3* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnSliderVec4Flag(const char* label, vec4* val, + float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnSliderIntFlag(const char* label, int32_t* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnSliderVec2IFlag(const char* label, vec2i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnSliderVec3IFlag(const char* label, vec3i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); +extern bool imguiColumnSliderVec4IFlag(const char* label, vec4i* val, + int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); diff --git a/src/CLOUD/control.c b/src/CLOUD/control.c index c14b8e6b..6a4a1c00 100644 --- a/src/CLOUD/control.c +++ b/src/CLOUD/control.c @@ -6,20 +6,16 @@ #include "control.h" #include "input.h" #include "../KKdLib/io_path.h" +#include "../CRE/lock.h" #include "../CRE/task.h" extern vector_task_render tasks_render; extern vector_task_render_draw2d tasks_render_draw2d; extern vector_task_render_draw3d tasks_render_draw3d; extern bool close; -HANDLE control_lock = 0; -extern HANDLE input_lock; -extern HANDLE render_lock; +HANDLE control_lock; +lock_extern_val(render_lock); extern HWND window_handle; -extern HANDLE mu_lock; -extern HANDLE mu_input_lock; -extern vector_wchar_t mu_input; -extern vector_char mu_input_ansi; extern int32_t width; extern int32_t height; @@ -29,77 +25,49 @@ extern float_t frame_speed; extern double_t render_freq; extern double_t sound_freq; extern double_t input_freq; -extern HANDLE render_freq_lock; -extern HANDLE sound_freq_lock; -extern HANDLE input_freq_lock; +lock_extern_val(render_freq_lock); +lock_extern_val(sound_freq_lock); +lock_extern_val(input_freq_lock); #define FREQ 60 #include "../CRE/timer.h" timer_val(control); -static void mui_process(); - int32_t control_main(void* arg) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); timer_init(control, "Control"); - memset(&tasks_render, 0, sizeof(vector_task_render)); - while (!render_lock) + while (!lock_check_init(render_lock)) msleep(control_timer, 0.0625); while (!close) { timer_calc_pre(control); - if (input_lock) { - WaitForSingleObject(input_lock, INFINITE); - if (window_handle == GetForegroundWindow()) { - if (input_is_down(VK_CONTROL) && input_is_tapped('C')) - break; - } - ReleaseMutex(input_lock); - } + lock_lock(render_lock); + lock_unlock(render_lock); - if (render_lock) { - WaitForSingleObject(render_lock, INFINITE); - vector_task_render_clear(&tasks_render); - if (muctx && mu_lock && input_lock) { - WaitForSingleObject(input_lock, INFINITE); - WaitForSingleObject(mu_lock, INFINITE); - mui_process(); - ReleaseMutex(mu_lock); - ReleaseMutex(input_lock); - } - ReleaseMutex(render_lock); - } + classes_process_control(classes, classes_count); - for (size_t i = 0; i < classes_count; i++) - if (classes[i].control) - classes[i].control(); + if (lock_check_init(control_freq_lock) || lock_check_init(render_freq_lock) + || lock_check_init(sound_freq_lock) || lock_check_init(input_freq_lock)) { + char buf[0x1000]; + int32_t len = 0; + lock_lock(control_freq_lock); + len += snprintf(buf + len, sizeof(buf) - len, "Control: %04d ", (int32_t)round(control_freq)); + lock_unlock(control_freq_lock); - if (control_freq_lock || render_freq_lock || sound_freq_lock || input_freq_lock) { - if (control_freq_lock) { - WaitForSingleObject(control_freq_lock, INFINITE); - printf("Control: %04d ", (int32_t)round(control_freq)); - ReleaseMutex(control_freq_lock); - } + lock_lock(render_freq_lock); + len += snprintf(buf + len, sizeof(buf) - len, "Render: %04d ", (int32_t)round(render_freq)); + lock_unlock(render_freq_lock); - if (render_freq_lock) { - WaitForSingleObject(render_freq_lock, INFINITE); - printf("Render: %04d ", (int32_t)round(render_freq)); - ReleaseMutex(render_freq_lock); - } + lock_lock(render_freq_lock); + len += snprintf(buf + len, sizeof(buf) - len, "Sound: %04d ", (int32_t)round(sound_freq)); + lock_unlock(render_freq_lock); - if (sound_freq_lock) { - WaitForSingleObject(sound_freq_lock, INFINITE); - printf("Sound: %04d ", (int32_t)round(sound_freq)); - ReleaseMutex(sound_freq_lock); - } - - if (input_freq_lock) { - WaitForSingleObject(input_freq_lock, INFINITE); - printf("Input: %04d ", (int32_t)round(input_freq)); - ReleaseMutex(input_freq_lock); - } - printf("\n"); + lock_lock(input_freq_lock); + len += snprintf(buf + len, sizeof(buf) - len, "Input: %04d ", (int32_t)round(input_freq)); + lock_unlock(input_freq_lock); + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + printf(buf); } double_t cycle_time = timer_calc_post(control); @@ -119,95 +87,3 @@ static void write_log(const char* text) { strcat_s(logbuf, 64000, text); logbuf_updated = 1; } - -static void mui_process() { - if (mu_input_lock && window_handle == GetForegroundWindow()) { - POINT position = input_mouse_position(); - double_t scroll_x = input_mouse_scroll_x() * -50.0; - double_t scroll_y = input_mouse_scroll_y() * -50.0; - input_mouse_reset_scroll(); - mu_input_mousemove(muctx, position.x, position.y); - mu_input_scroll(muctx, (int)round(scroll_x), (int)round(scroll_y)); - - if (input_is_tapped(VK_LBUTTON)) - mu_input_mousedown(muctx, MU_MOUSE_LEFT); - else if (input_is_released(VK_LBUTTON)) - mu_input_mouseup(muctx, MU_MOUSE_LEFT); - - if (input_is_tapped(VK_RBUTTON)) - mu_input_mousedown(muctx, MU_MOUSE_RIGHT); - else if (input_is_released(VK_RBUTTON)) - mu_input_mouseup(muctx, MU_MOUSE_RIGHT); - - if (input_is_tapped(VK_MBUTTON)) - mu_input_mousedown(muctx, MU_MOUSE_MIDDLE); - else if (input_is_released(VK_MBUTTON)) - mu_input_mouseup(muctx, MU_MOUSE_MIDDLE); - - if (input_is_tapped(VK_SHIFT) || input_is_tapped(VK_LSHIFT) || input_is_tapped(VK_RSHIFT)) - mu_input_keydown(muctx, MU_KEY_SHIFT); - else if (input_is_released(VK_SHIFT) || input_is_released(VK_SHIFT) || input_is_released(VK_SHIFT)) - mu_input_keyup(muctx, MU_KEY_SHIFT); - - if (input_is_tapped(VK_CONTROL) || input_is_tapped(VK_LCONTROL) || input_is_tapped(VK_RCONTROL)) - mu_input_keydown(muctx, MU_KEY_CTRL); - else if (input_is_released(VK_CONTROL) || input_is_released(VK_CONTROL) || input_is_released(VK_CONTROL)) - mu_input_keyup(muctx, MU_KEY_CTRL); - - if (input_is_tapped(VK_MENU) || input_is_tapped(VK_LMENU) || input_is_tapped(VK_RMENU)) - mu_input_keydown(muctx, MU_KEY_ALT); - else if (input_is_released(VK_MENU) || input_is_released(VK_LMENU) || input_is_released(VK_RMENU)) - mu_input_keyup(muctx, MU_KEY_ALT); - - if (input_is_tapped(VK_RETURN)) - mu_input_keydown(muctx, MU_KEY_RETURN); - else if (input_is_released(VK_RETURN)) - mu_input_keyup(muctx, MU_KEY_RETURN); - - if (input_is_tapped(VK_BACK)) - mu_input_keydown(muctx, MU_KEY_BACKSPACE); - else if (input_is_released(VK_BACK)) - mu_input_keyup(muctx, MU_KEY_BACKSPACE); - - if (input_is_tapped(VK_ESCAPE)) - muctx->focus = 0; - - WaitForSingleObject(mu_input_lock, INFINITE); - mu_input_text(muctx, mu_input_ansi.begin); - vector_wchar_t_clear(&mu_input); - mu_input.end++; - mu_input.end[-1] = 0; - vector_char_clear(&mu_input_ansi); - mu_input_ansi.end++; - mu_input_ansi.end[-1] = 0; - ReleaseMutex(mu_input_lock); - } - - mu_begin(muctx); - for (size_t i = 0; i < classes_count; i++) - if (classes[i].mui) - classes[i].mui(); - - if (input_is_tapped(VK_RBUTTON)) - mu_open_popup(muctx, "context menu"); - - if (mu_begin_window_ex(muctx, "context menu", - mu_rect(0, 0, 180, 120), - MU_OPT_NOTITLE | MU_OPT_POPUP | MU_OPT_CLOSED, false, true, false)) { - mu_Rect body = muctx->layout_stack.items[muctx->layout_stack.idx - 1].body; - mu_layout_row(muctx, 1, (int[]) { body.w }, 0); - for (size_t i = 0; i < classes_count; i++) { - if (!classes[i].enabled || !classes[i].init || !classes[i].name || ~classes[i].flags & CLASSES_IN_CONTEXT_MENU) - continue; - - mu_push_id(muctx, &i, sizeof(i)); - if (*classes[i].enabled) - mu_draw_control_text(muctx, classes[i].name, mu_layout_next(muctx), MU_COLOR_TEXT, 0); - else if (mu_button_ex(muctx, classes[i].name, 0, 0)) - classes[i].init(); - mu_pop_id(muctx); - } - mu_end_window(muctx); - } - mu_end(muctx); -} diff --git a/src/CLOUD/input.c b/src/CLOUD/input.c index 8dce7d01..4488b6bb 100644 --- a/src/CLOUD/input.c +++ b/src/CLOUD/input.c @@ -7,7 +7,8 @@ #include "input.h" #include "../KKdLib/vec.h" -#include "../CRE/microui.h" +#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS +#include #define KEYBOARD_KEYS 0xFF @@ -17,8 +18,6 @@ typedef struct key_state { typedef struct mouse_state { POINT position; - double_t scroll_x; - double_t scroll_y; } mouse_state; key_state input_key_current_state; @@ -27,17 +26,19 @@ key_state input_key_last_state; mouse_state input_mouse_current_state; mouse_state input_mouse_last_state; -float_t input_movement_speed = 1.0f; -float_t input_rotation_sensitivity = 0.5f; -vec2 input_move; -vec2 input_rotate; +double_t input_movement_speed = 0.1; +double_t input_rotation_sensitivity = 0.5; +vec2d input_move; +vec2d input_rotate; +double_t input_roll; bool input_reset; bool input_reset_mouse_position; +bool input_locked; extern bool close; -HANDLE input_lock = 0; +lock_val(input_lock); +extern HANDLE render_lock; extern HANDLE window_handle; -extern HANDLE mu_input_lock; void input_poll(); @@ -47,19 +48,22 @@ timer_val(input); int32_t input_main(void* arg) { timer_init(input, "Input"); - input_lock = CreateMutexW(0, 0, L"Input"); - if (!input_lock) + lock_init(input_lock); + if (!input_lock_init) goto End; + while (state != RENDER_INITIALIZED) + msleep(input_timer, 0.0625); + while (!close) { timer_calc_pre(input); - WaitForSingleObject(input_lock, INFINITE); + lock_lock(input_lock); input_poll(); - ReleaseMutex(input_lock); + lock_unlock(input_lock); double_t cycle_time = timer_calc_post(input); msleep(input_timer, 1000.0 / FREQ - cycle_time); } - CloseHandle(input_lock); + lock_dispose(input_lock); End: timer_dispose(input); @@ -70,6 +74,7 @@ void input_poll() { input_mouse_last_state = input_mouse_current_state; input_key_last_state = input_key_current_state; + ImGuiIO* io = igGetIO(); for (uint8_t i = 0; i < KEYBOARD_KEYS; i++) input_key_current_state.key_states[i] = GetAsyncKeyState(i) < 0; @@ -78,57 +83,69 @@ void input_poll() { ScreenToClient(window_handle, &input_mouse_current_state.position); } - input_rotate.x = 0.0f; - input_rotate.y = 0.0f; - input_move.x = 0.0f; - input_move.y = 0.0f; + input_move.x = 0.0; + input_move.y = 0.0; + input_rotate.x = 0.0; + input_rotate.y = 0.0; + input_roll = 0.0; - if (!window_handle || window_handle != GetForegroundWindow() || (muctx && muctx->text_input)) + if (!window_handle || window_handle != GetForegroundWindow()) return; - float_t temp_input_movement_speed = input_movement_speed / 10.0f; - if (input_is_down(VK_SHIFT)) - temp_input_movement_speed = input_movement_speed; - else if (input_is_down(VK_CONTROL)) - temp_input_movement_speed = input_movement_speed / 100.0f; + input_locked = false; + classes_process_input(classes, classes_count); - if (input_is_down('W')) - input_move.x += temp_input_movement_speed; - if (input_is_down('A')) - input_move.y -= temp_input_movement_speed; - if (input_is_down('S')) - input_move.x -= temp_input_movement_speed; - if (input_is_down('D')) - input_move.y += temp_input_movement_speed; + if (!input_locked) { + double_t speed; + if (input_is_down(VK_SHIFT)) + speed = input_movement_speed * 10.0; + else if (input_is_down(VK_CONTROL)) + speed = input_movement_speed / 10.0; + else + speed = input_movement_speed; - temp_input_movement_speed = input_movement_speed; - if (input_is_down(VK_SHIFT)) - temp_input_movement_speed = input_movement_speed * 10.0f; - else if (input_is_down(VK_CONTROL)) - temp_input_movement_speed = input_movement_speed / 10.0f; + if (input_is_down('W')) + input_move.x += speed; + if (input_is_down('S')) + input_move.x -= speed; - if (input_is_down(VK_UP)) - input_rotate.y += temp_input_movement_speed; - if (input_is_down(VK_LEFT)) - input_rotate.x -= temp_input_movement_speed; - if (input_is_down(VK_DOWN)) - input_rotate.y -= temp_input_movement_speed; - if (input_is_down(VK_RIGHT)) - input_rotate.x += temp_input_movement_speed; + if (input_is_down('A')) + input_move.y -= speed; + if (input_is_down('D')) + input_move.y += speed; - if (input_is_tapped('R')) - input_reset = true; + if (input_is_down(VK_SHIFT)) + speed = input_movement_speed * 100.0; + else if (input_is_down(VK_CONTROL)) + speed = input_movement_speed; + else + speed = input_movement_speed * 10.0; - for (size_t i = 0; i < classes_count; i++) - if (classes[i].input) - classes[i].input(); + if (input_is_down(VK_UP)) + input_rotate.y += speed; + if (input_is_down(VK_DOWN)) + input_rotate.y -= speed; - if (input_is_down(VK_MBUTTON)) { + if (input_is_down(VK_LEFT)) + input_rotate.x -= speed; + if (input_is_down(VK_RIGHT)) + input_rotate.x += speed; + + if (input_is_down('Q')) + input_roll -= speed; + if (input_is_down('E')) + input_roll += speed; + + if (input_is_tapped('R')) + input_reset = true; + } + + if (!io->WantCaptureMouse && input_is_down(VK_MBUTTON)) { if (!input_reset_mouse_position) { POINT last = input_mouse_last_state.position; POINT curr = input_mouse_current_state.position; - input_rotate.y += (float_t)(((double_t)last.y - (double_t)curr.y) * input_rotation_sensitivity); - input_rotate.x += (float_t)(((double_t)curr.x - (double_t)last.x) * input_rotation_sensitivity); + input_rotate.y += ((double_t)last.y - (double_t)curr.y) * input_rotation_sensitivity; + input_rotate.x += ((double_t)curr.x - (double_t)last.x) * input_rotation_sensitivity; } input_reset_mouse_position = false; } @@ -163,24 +180,3 @@ inline bool input_was_up(uint8_t keycode) { inline POINT input_mouse_position() { return input_mouse_current_state.position; } - -inline void input_mouse_reset_scroll() { - input_mouse_current_state.scroll_x = 0.0f; - input_mouse_current_state.scroll_y = 0.0f; -} - -inline double_t input_mouse_scroll_x() { - return input_mouse_current_state.scroll_x; -} - -inline double_t input_mouse_scroll_y() { - return input_mouse_current_state.scroll_y; -} - -inline void input_mouse_add_scroll_x(double_t value) { - input_mouse_current_state.scroll_x += value; -} - -inline void input_mouse_add_scroll_y(double_t value) { - input_mouse_current_state.scroll_y += value; -} diff --git a/src/CLOUD/input.h b/src/CLOUD/input.h index d652e588..41a749aa 100644 --- a/src/CLOUD/input.h +++ b/src/CLOUD/input.h @@ -15,8 +15,3 @@ extern bool input_is_released(uint8_t keycode); extern bool input_was_down(uint8_t keycode); extern bool input_was_up(uint8_t keycode); extern POINT input_mouse_position(); -extern double_t input_mouse_scroll_x(); -extern double_t input_mouse_scroll_y(); -extern void input_mouse_reset_scroll(); -extern void input_mouse_add_scroll_x(double_t value); -extern void input_mouse_add_scroll_y(double_t value); diff --git a/src/CLOUD/main.c b/src/CLOUD/main.c index 0370181e..5ba36d0e 100644 --- a/src/CLOUD/main.c +++ b/src/CLOUD/main.c @@ -4,15 +4,13 @@ */ #include "../KKdLib/kkfs.h" -#include "../KKdLib/f2_struct.h" -#include "../KKdLib/mat.h" -#include "../KKdLib/vec.h" #include "elf.h" #include "main.h" #include "unedat.h" #include +#include -FORCE_INLINE void next_rand_uint8_t_pointer(uint8_t* arr, size_t length, uint32_t* state) { +static inline void next_rand_uint8_t_pointer(uint8_t* arr, size_t length, uint32_t* state) { if (!arr || length < 1) return; @@ -96,68 +94,10 @@ typedef struct thread { } thread; int wmain(int argc, wchar_t** argv) { - /*stream* s; - void* data; - size_t length; - f2_struct* st; - s = io_wopen(L"eff_stgpv832_main!\\eff_stgpv832_main.drs", L"rb"); - length = s->length; - data = force_malloc(length); - io_read(s, data, length); - io_dispose(s); - - st = f2_struct_init(); - f2_struct_read_memory(st, data, length); - free(data); - f2_struct_write_memory(st, &data, &length, true, false); - f2_struct_dispose(st); - - s = io_wopen(L"eff_stgpv832_main\\eff_stgpv832_main.drs", L"wb"); - io_write(s, data, length); - io_dispose(s); - free(data); - - s = io_wopen(L"eff_stgpv832_main!\\eff_stgpv832_main.dve", L"rb"); - length = s->length; - data = force_malloc(length); - io_read(s, data, length); - io_dispose(s); - - st = f2_struct_init(); - f2_struct_read_memory(st, data, length); - free(data); - f2_struct_write_memory(st, &data, &length, true, false); - f2_struct_dispose(st); - - s = io_wopen(L"eff_stgpv832_main\\eff_stgpv832_main.dve", L"wb"); - io_write(s, data, length); - io_dispose(s); - free(data); - - s = io_wopen(L"eff_stgpv832_main!\\eff_stgpv832_main.lst", L"rb"); - length = s->length; - data = force_malloc(length); - io_read(s, data, length); - io_dispose(s); - - st = f2_struct_init(); - f2_struct_read_memory(st, data, length); - free(data); - f2_struct_write_memory(st, &data, &length, true, false); - f2_struct_dispose(st); - - s = io_wopen(L"eff_stgpv832_main\\eff_stgpv832_main.lst", L"wb"); - io_write(s, data, length); - io_dispose(s); - free(data); - - farc* f = farc_init(); - farc_wwrite(f, argv[1], FARC_COMPRESS_FARC_GZIP_AES); - farc_dispose(f); - return;*/ - //ShowWindow(GetConsoleWindow(), SW_HIDE); + timeBeginPeriod(1); QueryPerformanceFrequency(&performance_frequency); + SetProcessDPIAware(); render_init_struct ris; ris.res.x = 0; @@ -184,6 +124,7 @@ int wmain(int argc, wchar_t** argv) { CloseHandle(render.handle); if (sound.handle) CloseHandle(sound.handle); + timeEndPeriod(1); return 0; } diff --git a/src/CLOUD/render.c b/src/CLOUD/render.c index 5e50cada..e5061547 100644 --- a/src/CLOUD/render.c +++ b/src/CLOUD/render.c @@ -7,9 +7,10 @@ #include "render.h" #include "../CRE/camera.h" -#include "../CRE/microui_atlas.inl" +#include "../CRE/dof.h" #include "../CRE/post_process.h" #include "../CRE/random.h" +#include "../CRE/shared.h" #include "../CRE/static_var.h" #include "../KKdLib/farc.h" #define GLEW_STATIC @@ -17,34 +18,38 @@ #include #define GLFW_EXPOSE_NATIVE_WIN32 #include +#include #include "../CRE/fbo_dof.h" #include "../CRE/fbo_hdr.h" #include "../CRE/fbo_pp.h" #include "../CRE/fbo_render.h" +#include "../CRE/lock.h" #include "../CRE/Glitter/particle_manager.h" +vector(gl_object) +vector_func(gl_object) + vector_task_render tasks_render = { 0, 0, 0 }; vector_task_render_draw2d tasks_render_draw2d = { 0, 0, 0 }; vector_task_render_draw3d tasks_render_draw3d = { 0, 0, 0 }; static vector_task_render_draw2d tasks_render_draw2d_int = { 0, 0, 0 }; static vector_task_render_draw3d tasks_render_draw3d_int = { 0, 0, 0 }; -vector_func(hash_ptr_gl_object) -vector_func(hash_shader_model) -vector_func(hash_texture) -vector_func(hash_texture_set) -vector_func(hash_ptr_vertex) +static vector_task_render_draw3d temp_draw3d_tasks = { 0, 0, 0 }; +static vector_gl_object temp_draw3d_objects = { 0, 0, 0 }; static vector_hash_ptr_gl_object vec_gl_obj = { 0, 0, 0 }; +static vector_hash_light_dir vec_light_dir = { 0, 0, 0 }; +static vector_hash_light_point vec_light_point = { 0, 0, 0 }; +static vector_hash_material vec_mat = { 0, 0, 0 }; static vector_hash_shader_model vec_shad = { 0, 0, 0 }; static vector_hash_texture vec_tex = { 0, 0, 0 }; static vector_hash_texture_set vec_tex_set = { 0, 0, 0 }; +static vector_hash_texture_bone_mat vec_tex_bone_mat = { 0, 0, 0 }; static vector_hash_ptr_vertex vec_vert = { 0, 0, 0 }; -static texture dir_lights; -static int32_t dir_lights_count; -static texture point_lights; -static int32_t point_lights_count; +static texture light_dir_tex; +static texture light_point_tex; static fbo_render* rfbo; static fbo_hdr* hfbo; @@ -60,27 +65,50 @@ static shader_fbo hfbs[2]; static shader_fbo tfbs; shader_fbo particle_shader; shader_fbo sprite_shader; -shader_fbo mu_shader; +shader_fbo grid_shader; + +shader_model default_shader; +material default_material; +texture_set default_texture; +texture_bone_mat default_bone_mat; +vertex* default_vertex; + +#define grid_size 50.0f +#define grid_spacing 0.5f +#define grid_vertex_count ((size_t)((grid_size * 2.0f) / grid_spacing) + 1) * 4 static int32_t fb_vao, fb_vbo; +static int32_t grid_vao, grid_vbo; static int32_t common_ubo = 0; static int32_t dof_common_ubo = 0; static int32_t dof_texcoords_ubo = 0; static int32_t tone_map_ubo = 0; static int32_t global_matrices_ubo = 0; -bool micro_ui = true; +bool imgui = true; bool ui = true; bool front_2d = true; bool g_front_3d = true; +bool grid_3d = false; bool c_front_3d = true; bool back_2d = true; -bool back_3d = true; +bool g_back_3d = true; +bool c_back_3d = true; +bool glitter_3d = true; -bool enable_dof = false; -bool enable_dof_f2 = false; bool enable_post_process = true; +static const float_t light_dir_data_default[6] = { + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, +}; + +static const float_t light_point_data_default[12] = { + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, +}; + static const double_t const_scale[] = { 1.0 / 8.0, // 12.5% 2.0 / 8.0, // 25% @@ -110,73 +138,46 @@ vec2i internal_res; int32_t width; int32_t height; -render_state state; - static const double_t aspect = 16.0 / 9.0; camera* cam; +dof_struct* dof; radius* rad; intensity* inten; tone_map_sat_gamma* tmsg; tone_map_data* tmd; glitter_particle_manager* gpm; - -texture mu_font; -HANDLE mu_lock = 0; -HANDLE mu_input_lock = 0; -vector_wchar_t mu_input; -vector_char mu_input_ansi; - -#define MU_BUFFER_SIZE 16384 -static GLfloat* mu_vert_buf; -static GLfloat* mu_uv_buf; -static GLfloat* mu_color_buf; -static GLfloat* mu_depth_buf; -static GLuint* mu_index_buf; -static size_t mu_buf_idx; -static int32_t mu_vao, mu_vert_vbo, mu_uv_vbo, mu_color_vbo, mu_depth_vbo; - -/* -Camera.Struct camStruct = new Camera.Struct(); -Camera.DOF dof = new Camera.DOF();*/ - -static mat4* dir_light_data; -static mat4* point_light_trans; -static mat4* point_light_data; +glitter_type glt_type; +vec3 back3d_color; static void render_load(); static void render_update(); static void render_draw(); static void render_dispose(); -static void render_micro_ui(); -static void render_ui(); -static void render_front_2d(); -static void render_c_front_3d(); -static void render_g_front_3d(); -static void render_back_3d(); -static void render_back_2d(); +static void render_imgui(); +static void render_2d(task_render_draw2d_type type); +static void render_c_3d(task_render_draw3d_type type); +static void render_c_3d_translucent(task_render_draw3d_type type); +static void render_g_3d(task_render_draw3d_type type); +static void render_grid_3d(); +static void render_glitter_3d(int32_t alpha); +static void render_drop_glfw(GLFWwindow* window, int count, char** paths); static void render_resize_fb_glfw(GLFWwindow* window, int32_t w, int32_t h); static void render_resize_fb(bool change_fb); -static void render_input_text_glfw(GLFWwindow* window, uint32_t codepoint); -static void render_input_mouse_scroll_glfw(GLFWwindow* window, double_t xoffset, double_t yoffset); -static void render_dof_get_texcoords(float_t* a1, float_t a2); - -static void render_mui_flush(); -static void render_mui_push_quad(mu_Rect dst, mu_Rect src, mu_Color color); -static inline void render_mui_draw_rect(mu_Rect rect, mu_Color color); -static inline void render_mui_draw_text(const char* text, mu_Vec2 pos, mu_Color color); -static inline void render_mui_draw_icon(int id, mu_Rect rect, mu_Color color); -static inline void render_mui_set_clip_rect(mu_Rect rect); -static inline void render_mui_draw_texture(); -static int render_mui_get_text_width(mu_Font font, const char* text, size_t len); -static int render_mui_get_text_height(mu_Font font); +static void render_dof_get_texcoords(vec2* data, float_t a2); +static void render_imgui_context_menu(classes_struct* classes, const size_t classes_count); +static bool render_glitter_mesh_add_list(glitter_particle_mesh* mesh, vec4* color, mat4* model, mat4* uv_mat); +static void render_update_uniform_c(task_render_uniform* uniform, shader_model* s); +static void render_update_uniform_g(task_render_uniform* uniform, shader_model* s); extern bool close; -HANDLE render_lock = 0; +lock_val(render_lock); HWND window_handle; GLFWwindow* window; +ImGuiContext* ig; +bool global_context_menu; #define FREQ 60 #include "../CRE/timer.h" @@ -186,30 +187,17 @@ int32_t render_main(void* arg) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); timer_init(render, "Render"); - render_lock = CreateMutexW(0, 0, L"Render"); - if (!render_lock) + lock_init(render_lock); + if (!lock_check_init(render_lock)) goto End; - mu_lock = CreateMutexW(0, 0, L"microui"); - if (!mu_lock) - goto End; - - mu_input_lock = CreateMutexW(0, 0, L"microui Input"); - if (!mu_input_lock) - goto End; - - vector_wchar_t_append(&mu_input, 1); - mu_input.end++; - mu_input.end[-1] = 0; - vector_char_append(&mu_input_ansi, 1); - mu_input_ansi.end++; - mu_input_ansi.end[-1] = 0; - render_init_struct* ris = (render_init_struct*)arg; window_handle = 0; state = RENDER_UNINITIALIZED; + +#pragma region GLFW GLEW Init glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -229,7 +217,14 @@ int32_t render_main(void* arg) { glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); glfwWindowHint(GLFW_REFRESH_RATE, FREQ); - window = glfwCreateWindow(width, height, "CLOUD", + const char* glfw_titlelabel; +#ifdef CLOUD_DEV + glfw_titlelabel = "CLOUDDev"; +#else + glfw_titlelabel = "CLOUD"; +#endif + + window = glfwCreateWindow(width, height, glfw_titlelabel, mode->width == width && mode->height == height ? monitor : 0, 0); if (!window) { glfwTerminate(); @@ -239,10 +234,9 @@ int32_t render_main(void* arg) { window_handle = glfwGetWin32Window(window); glfwMakeContextCurrent(window); glfwFocusWindow(window); + glfwSetDropCallback(window, (void*)render_drop_glfw); glfwSetWindowSizeCallback(window, (void*)render_resize_fb_glfw); - glfwSetCharCallback(window, (void*)render_input_text_glfw); - glfwSetScrollCallback(window, (void*)render_input_mouse_scroll_glfw); - glfwSetWindowSizeLimits(window, 640, 360, GLFW_DONT_CARE, GLFW_DONT_CARE); + glfwSetWindowSizeLimits(window, 960, 540, GLFW_DONT_CARE, GLFW_DONT_CARE); RECT window_rect; GetClientRect(window_handle, &window_rect); @@ -264,15 +258,15 @@ int32_t render_main(void* arg) { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &sv_max_texture_size); glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &sv_max_texture_max_anisotropy); glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); +#pragma endregion state = RENDER_INITIALIZING; - WaitForSingleObject(render_lock, INFINITE); - WaitForSingleObject(mu_lock, INFINITE); + lock_lock(render_lock); render_load(); - ReleaseMutex(mu_lock); - ReleaseMutex(render_lock); + lock_unlock(render_lock); state = RENDER_INITIALIZED; +#pragma region GL Init glfwGetFramebufferSize(window, &width, &height); glViewport(0, 0, width, height); glfwSwapInterval(0); @@ -282,34 +276,37 @@ int32_t render_main(void* arg) { glDisable(GL_DEPTH_TEST); glDepthMask(false); glDisable(GL_CULL_FACE); +#pragma endregion while (!close) { timer_calc_pre(render); glfwPollEvents(); - WaitForSingleObject(render_lock, INFINITE); + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + igNewFrame(); + lock_lock(render_lock); render_update(); - ReleaseMutex(render_lock); - WaitForSingleObject(mu_lock, INFINITE); + lock_unlock(render_lock); render_draw(); - ReleaseMutex(mu_lock); glfwSwapBuffers(window); close |= glfwWindowShouldClose(window); double_t cycle_time = timer_calc_post(render); msleep(render_timer, 1000.0 / FREQ - cycle_time); } - CloseHandle(mu_lock); - CloseHandle(mu_input_lock); - mu_lock = 0; - mu_input_lock = 0; - WaitForSingleObject(render_lock, INFINITE); + state = RENDER_DISPOSING; + + lock_lock(render_lock); render_dispose(); - ReleaseMutex(render_lock); + lock_unlock(render_lock); + state = RENDER_DISPOSED; + +#pragma region GLFW Dispose glfwDestroyWindow(window); glfwTerminate(); - CloseHandle(render_lock); - render_lock = 0; +#pragma endregion + lock_dispose(render_lock); End: timer_dispose(render); @@ -317,58 +314,76 @@ End: } static void render_load() { + tasks_render = (vector_task_render){ 0, 0, 0 }; + tasks_render_draw2d = (vector_task_render_draw2d){ 0, 0, 0 }; + tasks_render_draw3d = (vector_task_render_draw3d){ 0, 0, 0 }; + tasks_render_draw2d_int = (vector_task_render_draw2d){ 0, 0, 0 }; + tasks_render_draw3d_int = (vector_task_render_draw3d){ 0, 0, 0 }; + + temp_draw3d_tasks = (vector_task_render_draw3d){ 0, 0, 0 }; + temp_draw3d_objects = (vector_gl_object){ 0, 0, 0 }; + + vec_gl_obj = (vector_hash_ptr_gl_object){ 0, 0, 0 }; + vec_light_dir = (vector_hash_light_dir){ 0, 0, 0 }; + vec_light_point = (vector_hash_light_point){ 0, 0, 0 }; + vec_mat = (vector_hash_material){ 0, 0, 0 }; + vec_shad = (vector_hash_shader_model){ 0, 0, 0 }; + vec_tex = (vector_hash_texture){ 0, 0, 0 }; + vec_tex_set = (vector_hash_texture_set){ 0, 0, 0 }; + vec_tex_bone_mat = (vector_hash_texture_bone_mat){ 0, 0, 0 }; + vec_vert = (vector_hash_ptr_vertex){ 0, 0, 0 }; + cam = camera_init(); + dof = dof_init(); rad = radius_init(); inten = intensity_init(); tmsg = tone_map_sat_gamma_init(); tmd = tone_map_data_init(); gpm = glitter_particle_manager_init(); - muctx = force_malloc(sizeof(mu_Context)); + dof_initialize(dof, 0, 0); radius_initialize(rad, (vec3[]) { 2.0f, 2.0f, 2.0f }); intensity_initialize(inten, (vec3[]) { 1.0f, 1.0f, 1.0f }); tone_map_sat_gamma_initialize(tmsg, 1.0f, 1, 1.0f); tone_map_data_initialize(tmd, 2.0f, true, (vec3[]) { 0.0f, 0.0f, 0.0f}, 0.0f, 0, (vec3[]) { 0.0f, 0.0f, 0.0f }, (vec3[]) { 1.0f, 1.0f, 1.0f }, 0); - mu_init(muctx); - muctx->text_width = render_mui_get_text_width; - muctx->text_height = render_mui_get_text_height; - camera_initialize(cam, aspect, 70.0); camera_reset(cam); - //camera_move_vec3(cam, &(vec3){ 1.35542f, 1.41634f, 1.27852f }); - //camera_rotate_vec2(cam, &(vec2){ -45.0f, -32.5f }); - //camera_move_vec3(cam, &(vec3){ -6.67555f, 4.68882f, -3.67537f }); - //camera_rotate_vec2(cam, &(vec2){ 136.5f, -20.5f }); - camera_move_vec3(cam, &(vec3){ 0.0f, 1.0f, 3.45f }); + //camera_set_position(cam, &(vec3){ 1.35542f, 1.41634f, 1.27852f }); + //camera_rotate(cam, &(vec2d){ -45.0, -32.5 }); + //camera_set_position(cam, &(vec3){ -6.67555f, 4.68882f, -3.67537f }); + //camera_rotate(cam, &(vec2d){ 136.5, -20.5 }); + camera_set_position(cam, &(vec3){ 0.0f, 1.0f, 3.45f }); glGenBuffers(1, &global_matrices_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, global_matrices_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(mat4) * 4, 0, GL_STREAM_DRAW); - glBindBufferRange(GL_UNIFORM_BUFFER, 0, global_matrices_ubo, 0, sizeof(mat4) * 4); - glGenBuffers(1, &dof_common_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, dof_common_ubo); - glBufferData(GL_UNIFORM_BUFFER, 16 * 4, 0, GL_STREAM_DRAW); - glBindBufferRange(GL_UNIFORM_BUFFER, 0, dof_common_ubo, 0, 16 * 4); - glGenBuffers(1, &common_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, common_ubo); - glBufferData(GL_UNIFORM_BUFFER, 4 * 4, 0, GL_STREAM_DRAW); - glBindBufferRange(GL_UNIFORM_BUFFER, 0, common_ubo, 0, 4 * 4); - glGenBuffers(1, &tone_map_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, tone_map_ubo); - glBufferData(GL_UNIFORM_BUFFER, 16 * 4, 0, GL_STREAM_DRAW); - glBindBufferRange(GL_UNIFORM_BUFFER, 0, tone_map_ubo, 0, 16 * 4); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - glGenBuffers(1, &dof_texcoords_ubo); -#pragma region LoadShaders + bind_uniform_buffer(global_matrices_ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(mat4) * 4, 0, GL_STREAM_DRAW); + + bind_uniform_buffer(dof_common_ubo); + glBufferData(GL_UNIFORM_BUFFER, 16 * 4, 0, GL_STREAM_DRAW); + + bind_uniform_buffer(common_ubo); + glBufferData(GL_UNIFORM_BUFFER, 4 * 4, 0, GL_STREAM_DRAW); + + bind_uniform_buffer(tone_map_ubo); + glBufferData(GL_UNIFORM_BUFFER, 16 * 4, 0, GL_STREAM_DRAW); + bind_uniform_buffer(0); + + glBindBufferRange(GL_UNIFORM_BUFFER, 0, global_matrices_ubo, 0, sizeof(mat4) * 4); + glBindBufferRange(GL_UNIFORM_BUFFER, 0, dof_common_ubo, 0, 16 * 4); + glBindBufferRange(GL_UNIFORM_BUFFER, 0, common_ubo, 0, 4 * 4); + glBindBufferRange(GL_UNIFORM_BUFFER, 0, tone_map_ubo, 0, 16 * 4); + glBindBufferRange(GL_UNIFORM_BUFFER, 0, dof_texcoords_ubo, 0, align_val(7 * 7, 2) * sizeof(vec2)); + +#pragma region Load Shaders char temp[0x80]; - memset(temp, 0, 0x80); + memset(temp, 0, sizeof(temp)); hfbo = fbo_hdr_init(); rfbo = fbo_render_init(); @@ -376,31 +391,31 @@ static void render_load() { pfbo = fbo_pp_init(); float_t verts_quad[] = { - -1, -1, -1, 1, 1, -1, 1, 1 + -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }; glGenBuffers(1, &fb_vbo); glGenVertexArrays(1, &fb_vao); - glBindBuffer(GL_ARRAY_BUFFER, fb_vbo); + bind_array_buffer(fb_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(verts_quad), verts_quad, GL_STATIC_DRAW); - glBindVertexArray(fb_vao); + bind_vertex_array(fb_vao); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0); // Pos - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 8, 0); // Pos + bind_vertex_array(0); + bind_array_buffer(0); farc* f = farc_init(); farc_read(f, "rom\\core_shaders.farc", true, false); shader_param param; - for (int32_t i = 0; i < 5; i++) { + for (size_t i = 0; i < 5; i++) { memset(¶m, 0, sizeof(shader_param)); param.name = L"Color FB"; param.vert = L"rfb"; param.frag = L"cfb"; - sprintf_s(temp, 0x80, "SAMPLES%d", 1 << i); + sprintf_s(temp, sizeof(temp), "SAMPLES%d", 1 << i); param.param[0] = temp; shader_fbo_load(&cfbs[i], f, ¶m); @@ -408,7 +423,7 @@ static void render_load() { param.name = L"Color FB"; param.vert = L"rfb"; param.frag = L"cfb"; - sprintf_s(temp, 0x80, "SAMPLES%d", 1 << i); + sprintf_s(temp, sizeof(temp), "SAMPLES%d", 1 << i); param.param[0] = temp; param.param[1] = "DEPTH"; shader_fbo_load(&cfbs[i + 5], f, ¶m); @@ -417,7 +432,7 @@ static void render_load() { param.name = L"G-Buffer FB"; param.vert = L"rfb"; param.frag = L"gfb"; - sprintf_s(temp, 0x80, "SAMPLES%d", 1 << i); + sprintf_s(temp, sizeof(temp), "SAMPLES%d", 1 << i); param.param[0] = temp; shader_fbo_load(&gfbs[i], f, ¶m); } @@ -449,13 +464,13 @@ static void render_load() { L"dof5", }; - for (int32_t i = 0; i < 2; i++) + for (size_t i = 0; i < 2; i++) for (int32_t j = 0; j < 5; j++) { memset(¶m, 0, sizeof(shader_param)); param.name = L"DOF FB"; param.vert = L"rfb"; param.frag = dof_shaders[j]; - sprintf_s(temp, 0x80, "USE_F2_COC (%d)", i); + sprintf_s(temp, sizeof(temp), "USE_F2_COC (%lld)", i); param.param[0] = temp; shader_fbo_load(&dfbs[i * 5 + j], f, ¶m); } @@ -479,14 +494,15 @@ static void render_load() { L"exposure3", }; - for (int32_t i = 0; i < 16; i++) { + for (size_t i = 0; i < 16; i++) { memset(¶m, 0, sizeof(shader_param)); + param.param[0] = temp; param.name = L"Post Process FB"; param.vert = post_process_shaders[i]; param.frag = post_process_shaders[i]; shader_fbo_load(&bfbs[i], f, ¶m); } - + memset(¶m, 0, sizeof(shader_param)); param.name = L"Tone Map FB"; param.vert = L"tone_map"; @@ -506,32 +522,258 @@ static void render_load() { shader_fbo_load(&sprite_shader, f, ¶m); memset(¶m, 0, sizeof(shader_param)); - param.name = L"microui"; - param.vert = L"microui"; - param.frag = L"microui"; - shader_fbo_load(&mu_shader, f, ¶m); + param.name = L"Grid"; + param.vert = L"grid"; + param.frag = L"grid"; + shader_fbo_load(&grid_shader, f, ¶m); + farc_dispose(f); - for (int32_t i = 0; i < 10; i++) { + { + uint8_t tex_dat_diffuse[] = { + 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + }; + + texture_data tex_data_diffuse = { + .type = TEXTURE_2D, + .width = 8, + .height = 8, + .depth = 0, + .data = tex_dat_diffuse, + .pixel_type = GL_UNSIGNED_BYTE, + .pixel_format = GL_RGB, + .pixel_internal_format = GL_RGB8, + .generate_mipmap = false, + .wrap_mode_s = GL_REPEAT, + .wrap_mode_t = GL_REPEAT, + .wrap_mode_r = GL_REPEAT, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST, + }; + + uint8_t tex_dat_other[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + texture_data tex_data_other = { + .type = TEXTURE_2D, + .width = 8, + .height = 8, + .depth = 0, + .data = tex_dat_other, + .pixel_type = GL_UNSIGNED_BYTE, + .pixel_format = GL_RGB, + .pixel_internal_format = GL_RGB8, + .generate_mipmap = false, + .wrap_mode_s = GL_REPEAT, + .wrap_mode_t = GL_REPEAT, + .wrap_mode_r = GL_REPEAT, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST, + }; + + texture_set_data tex_set; + memset(&tex_set, 0, sizeof(texture_set_data)); + tex_set.diffuse = &tex_data_diffuse; + tex_set.specular = &tex_data_other; + tex_set.displacement = &tex_data_other; + tex_set.normal = &tex_data_other; + tex_set.albedo = &tex_data_other; + tex_set.ao = &tex_data_other; + tex_set.metallic = &tex_data_other; + tex_set.roughness = &tex_data_other; + texture_set_load(&default_texture, &tex_set); + + default_material.texture = default_texture; + default_material.blend = material_blend_default; + default_material.translucent = false; + + shader_model_update param_model; + memset(¶m_model, 0, sizeof(shader_model_update)); + + stream* s; + size_t l; + + s = io_wopen(L"rom\\shaders\\0000.vert", L"r"); + l = s->length; + param_model.vert = force_malloc(l + 1); + io_read(s, param_model.vert, l); + param_model.vert[l] = 0; + io_dispose(s); + + s = io_wopen(L"rom\\shaders\\0000_c.frag", L"r"); + l = s->length; + param_model.frag_c = force_malloc(l + 1); + io_read(s, param_model.frag_c, l); + param_model.frag_c[l] = 0; + io_dispose(s); + + s = io_wopen(L"rom\\shaders\\0000_g.frag", L"r"); + l = s->length; + param_model.frag_g = force_malloc(l+ 1); + io_read(s, param_model.frag_g, l); + param_model.frag_g[l] = 0; + io_dispose(s); + + memset(¶m, 0, sizeof(shader_param)); + param.name = L"Default"; + param_model.param = param; + shader_model_load(&default_shader, ¶m_model); + free(param_model.vert); + free(param_model.frag_c); + free(param_model.frag_g); + + float_t verts_cube[] = { + -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, + 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, + -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, + -1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, + + -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, + -1.0f, -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, + -1.0f, -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, + -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, + + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + + -1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, + -1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, + + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, + }; + + vertex_update vert_upd; + memset(&vert_upd, 0, sizeof(vertex_update)); + vert_upd.data = verts_cube; + vert_upd.length = sizeof(verts_cube) / sizeof(float_t); + vert_upd.uv = true; + vert_upd.normal = true; + + default_vertex = vertex_init(); + vertex_load(default_vertex, &vert_upd); + + texture_bone_mat_data tex_bone_mat; + memset(&tex_bone_mat, 0, sizeof(texture_bone_mat_data)); + tex_bone_mat.count = 1; + tex_bone_mat.data = (mat4*)&mat4_identity; + texture_bone_mat_load(&default_bone_mat, &tex_bone_mat); + + texture_data light_dir_tex_data = { + .type = TEXTURE_2D, + .width = 2, + .height = 1, + .depth = 0, + .data = (void*)light_dir_data_default, + .pixel_type = GL_FLOAT, + .pixel_format = GL_RGB, + .pixel_internal_format = GL_RGB32F, + .generate_mipmap = false, + .wrap_mode_s = GL_REPEAT, + .wrap_mode_t = GL_REPEAT, + .wrap_mode_r = GL_REPEAT, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST, + }; + + memset(&light_dir_tex, 0, sizeof(texture)); + texture_load(&light_dir_tex, &light_dir_tex_data); + + texture_data light_point_tex_data = { + .type = TEXTURE_2D, + .width = 3, + .height = 1, + .depth = 0, + .data = (void*)light_point_data_default, + .pixel_type = GL_FLOAT, + .pixel_format = GL_RGBA, + .pixel_internal_format = GL_RGBA32F, + .generate_mipmap = false, + .wrap_mode_s = GL_REPEAT, + .wrap_mode_t = GL_REPEAT, + .wrap_mode_r = GL_REPEAT, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST, + }; + + memset(&light_point_tex, 0, sizeof(texture)); + texture_load(&light_point_tex, &light_point_tex_data); + } + + for (size_t i = 0; i < 10; i++) { shader_fbo_set_int(&cfbs[i], "ColorTexture", 0); if (i >= 5) shader_fbo_set_int(&cfbs[i], "DepthTexture", 1); } - for (int32_t i = 0; i < 5; i++) { + for (size_t i = 0; i < 5; i++) { shader_fbo_set_int(&gfbs[i], "gPos", 0); - shader_fbo_set_int(&gfbs[i], "gNormal", 1); - shader_fbo_set_int(&gfbs[i], "gAlbedo", 2); - shader_fbo_set_int(&gfbs[i], "gSpec", 3); - shader_fbo_set_int(&gfbs[i], "dirLights", 4); - shader_fbo_set_int(&gfbs[i], "pointLights", 5); + shader_fbo_set_int(&gfbs[i], "gAlbedo", 1); + shader_fbo_set_int(&gfbs[i], "gSpec", 2); + shader_fbo_set_int(&gfbs[i], "gNormal", 3); + shader_fbo_set_int(&gfbs[i], "lightDir", 4); + shader_fbo_set_int(&gfbs[i], "lightPoint", 5); } shader_fbo_set_int(&ffbs, "Texture", 0); - for (int32_t i = 0; i < 2; i++) + for (size_t i = 0; i < 2; i++) shader_fbo_set_int(&hfbs[i], "Color", 0); - for (int32_t i = 0; i < 10; i += 5) { + for (size_t i = 0; i < 10; i += 5) { shader_fbo_set_int(&dfbs[i], "Depth", 0); shader_fbo_set_int(&dfbs[i + 1], "Tile", 0); shader_fbo_set_int(&dfbs[i + 2], "Depth", 0); @@ -547,22 +789,24 @@ static void render_load() { shader_fbo_set_int(&dfbs[i + 4], "Depth", 4); shader_fbo_set_uniform_block_binding(&dfbs[i], "DOFCommon", 1); - shader_fbo_set_uniform_block_binding(&dfbs[i + 1], "DOFCommon", 1); + shader_fbo_set_uniform_block_binding(&dfbs[i + 2], "Common", 0); shader_fbo_set_uniform_block_binding(&dfbs[i + 2], "DOFCommon", 1); + shader_fbo_set_uniform_block_binding(&dfbs[i + 3], "Common", 0); shader_fbo_set_uniform_block_binding(&dfbs[i + 3], "DOFCommon", 1); shader_fbo_set_uniform_block_binding(&dfbs[i + 3], "DOFTexcoords", 2); + shader_fbo_set_uniform_block_binding(&dfbs[i + 4], "Common", 0); shader_fbo_set_uniform_block_binding(&dfbs[i + 4], "DOFCommon", 1); } - for (int32_t i = 0; i < 2; i++) + for (size_t i = 0; i < 2; i++) shader_fbo_set_int(&bfbs[i], "Texture", 0); - for (int32_t i = 2; i < 5; i++) { + for (size_t i = 2; i < 5; i++) { shader_fbo_set_int(&bfbs[i], "Texture", 0); shader_fbo_set_int(&bfbs[i], "TexLuma", 1); } - for (int32_t i = 5; i < 13; i++) + for (size_t i = 5; i < 13; i++) shader_fbo_set_int(&bfbs[i], "Texture", 0); shader_fbo_set_int(&bfbs[13], "Texture0", 0); @@ -570,9 +814,9 @@ static void render_load() { shader_fbo_set_int(&bfbs[13], "Texture2", 2); shader_fbo_set_int(&bfbs[13], "Texture3", 3); - for (int32_t i = 14; i < 16; i++) + for (size_t i = 14; i < 16; i++) shader_fbo_set_int(&bfbs[i], "Texture", 0); - + shader_fbo_set_int(&tfbs, "Texture0", 0); shader_fbo_set_int(&tfbs, "Texture1", 1); shader_fbo_set_int(&tfbs, "Texture2", 2); @@ -586,8 +830,7 @@ static void render_load() { shader_fbo_set_int_array(&sprite_shader, "Texture", 3, ((int32_t[]){ 0, 1, 2 })); shader_fbo_set_uniform_block_binding(&sprite_shader, "Common", 0); - shader_fbo_set_int(&mu_shader, "Texture", 0); - shader_fbo_set_uniform_block_binding(&mu_shader, "Common", 0); + shader_fbo_set_uniform_block_binding(&grid_shader, "GlobalMatrices", 0); render_resize_fb(false); @@ -597,103 +840,163 @@ static void render_load() { fbo_pp_initialize(pfbo, &internal_3d_res, fb_vao, bfbs, &tfbs, tone_map_ubo); render_resize_fb(true); - - static const int32_t len = 7 * 7 * 2; - float_t dof_texcoords[7 * 7 * 2]; - render_dof_get_texcoords(dof_texcoords, 3.0f); - glBindBuffer(GL_UNIFORM_BUFFER, dof_texcoords_ubo); - glBufferData(GL_UNIFORM_BUFFER, len * sizeof(float_t), 0, GL_STATIC_DRAW); - glBindBufferRange(GL_UNIFORM_BUFFER, 0, dof_texcoords_ubo, 0, len * sizeof(float_t)); - glBufferSubData(GL_UNIFORM_BUFFER, 0, len * sizeof(float_t), dof_texcoords); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - farc_dispose(f); #pragma endregion - memset(&dir_lights, 0, sizeof(texture)); - dir_lights_count = 0; - memset(&point_lights, 0, sizeof(texture)); - point_lights_count = 0; + const int32_t dof_tex_len = align_val(7 * 7, 2); + vec2 dof_texcoords[align_val(7 * 7, 2)]; + memset(dof_texcoords, 0, dof_tex_len * sizeof(vec2)); + render_dof_get_texcoords(dof_texcoords, 3.0f); + bind_uniform_buffer(dof_texcoords_ubo); + glBufferData(GL_UNIFORM_BUFFER, dof_tex_len * sizeof(vec2), 0, GL_STATIC_DRAW); + glBufferSubData(GL_UNIFORM_BUFFER, 0, dof_tex_len * sizeof(vec2), dof_texcoords); + bind_uniform_buffer(0); - memset(&mu_font, 0, sizeof(texture)); - texture_data muctx_font_data = { - .type = TEXTURE_2D, - .width = ATLAS_WIDTH, - .height = ATLAS_HEIGHT, - .depth = 0, - .data = atlas_texture, - .pixel_format = GL_RED, - .pixel_type = GL_UNSIGNED_BYTE, - .pixel_internal_format = GL_RED, - .generate_mipmap = false, - .wrap_mode_s = GL_CLAMP, - .wrap_mode_t = GL_CLAMP, - .wrap_mode_r = GL_CLAMP, - .min_filter = GL_NEAREST, - .mag_filter = GL_NEAREST, - }; - texture_load(&mu_font, &muctx_font_data); + float_t* grid_verts = force_malloc_s(float_t, grid_vertex_count * 7); - glGenBuffers(1, &mu_vert_vbo); - glGenBuffers(1, &mu_uv_vbo); - glGenBuffers(1, &mu_color_vbo); - glGenBuffers(1, &mu_depth_vbo); - glGenVertexArrays(1, &mu_vao); + size_t v = 0; + for (float_t x = -grid_size; x <= grid_size; x += grid_spacing) { + vec4 x_color; + vec4 z_color; + if (x == 0) { + x_color = (vec4){ 1.0f, 0.0f, 0.0f, 1.0f }; + z_color = (vec4){ 0.0f, 1.0f, 0.0f, 1.0f }; + } + else if (abs((int32_t)(x / grid_spacing)) % 2 == 0) { + x_color = (vec4){ 0.2f, 0.2f, 0.2f, 0.6f }; + z_color = (vec4){ 0.2f, 0.2f, 0.2f, 0.6f }; + } + else { + x_color = (vec4){ 0.5f, 0.5f, 0.5f, 0.6f }; + z_color = (vec4){ 0.5f, 0.5f, 0.5f, 0.6f }; + } - mu_vert_buf = force_malloc_s(sizeof(GLfloat), MU_BUFFER_SIZE * 2 * 4); - mu_uv_buf = force_malloc_s(sizeof(GLfloat), MU_BUFFER_SIZE * 2 * 4); - mu_color_buf = force_malloc_s(sizeof(GLfloat), MU_BUFFER_SIZE * 4 * 4); - mu_depth_buf = force_malloc_s(sizeof(GLfloat), MU_BUFFER_SIZE * 1 * 4); - mu_index_buf = force_malloc_s(sizeof(GLuint), MU_BUFFER_SIZE * 6); + grid_verts[v++] = x; + grid_verts[v++] = 0.0f; + grid_verts[v++] = -grid_size; + grid_verts[v++] = x_color.x; + grid_verts[v++] = x_color.y; + grid_verts[v++] = x_color.z; + grid_verts[v++] = x_color.w; - glBindVertexArray(mu_vao); - glBindBuffer(GL_ARRAY_BUFFER, mu_vert_vbo); - glBufferData(GL_ARRAY_BUFFER, MU_BUFFER_SIZE * 2 * 4 * sizeof(GLfloat), mu_vert_buf, GL_DYNAMIC_DRAW); + grid_verts[v++] = x; + grid_verts[v++] = 0.0f; + grid_verts[v++] = grid_size; + grid_verts[v++] = x_color.x; + grid_verts[v++] = x_color.y; + grid_verts[v++] = x_color.z; + grid_verts[v++] = x_color.w; + + grid_verts[v++] = -grid_size; + grid_verts[v++] = 0.0f; + grid_verts[v++] = x; + grid_verts[v++] = z_color.x; + grid_verts[v++] = z_color.y; + grid_verts[v++] = z_color.z; + grid_verts[v++] = z_color.w; + + grid_verts[v++] = grid_size; + grid_verts[v++] = 0.0f; + grid_verts[v++] = x; + grid_verts[v++] = z_color.x; + grid_verts[v++] = z_color.y; + grid_verts[v++] = z_color.z; + grid_verts[v++] = z_color.w; + } + + glGenBuffers(1, &grid_vbo); + glGenVertexArrays(1, &grid_vao); + bind_array_buffer(grid_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(float_t) * grid_vertex_count * 7, grid_verts, GL_STATIC_DRAW); + + bind_vertex_array(grid_vao); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, false, 8, 0); // Pos - glBindBuffer(GL_ARRAY_BUFFER, mu_uv_vbo); - glBufferData(GL_ARRAY_BUFFER, MU_BUFFER_SIZE * 2 * 4 * sizeof(GLfloat), mu_uv_buf, GL_DYNAMIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float_t) * 7, (void*)0); // Pos glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, false, 8, 0); // UV - glBindBuffer(GL_ARRAY_BUFFER, mu_color_vbo); - glBufferData(GL_ARRAY_BUFFER, MU_BUFFER_SIZE * 4 * 4 * sizeof(GLfloat), mu_color_buf, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 4, GL_FLOAT, false, 16, 0); // Color - glBindBuffer(GL_ARRAY_BUFFER, mu_depth_vbo); - glBufferData(GL_ARRAY_BUFFER, MU_BUFFER_SIZE * 1 * 4 * sizeof(GLfloat), mu_depth_buf, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 1, GL_FLOAT, false, 4, 0); // Depth - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(float_t) * 7, (void*)(sizeof(float_t) * 3)); // Color + bind_vertex_array(0); + bind_array_buffer(0); - background_color.color = (vec3){ 0.74117647f, 0.74117647f, 0.74117647f }; + free(grid_verts); - for (size_t i = 0; i < classes_count; i++) - if (classes[i].init && classes[i].flags & CLASSES_INIT_AT_STARTUP) - classes[i].init(); + ig = igCreateContext(0); + ImGuiIO* io = igGetIO(); + io->IniFilename = 0; + io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + igStyleColorsDark(0); + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init("#version 430"); + + back3d_color = (vec3){ 0.74117647f, 0.74117647f, 0.74117647f }; + + classes_process_init(classes, classes_count); } -extern vec2 input_move; -extern vec2 input_rotate; +extern vec2d input_move; +extern vec2d input_rotate; +extern double_t input_roll; extern bool input_reset; static void render_update() { + global_context_menu = true; + classes_process_imgui(classes, classes_count); + + if (global_context_menu && igIsMouseReleased(ImGuiMouseButton_Right) + && !igIsItemHovered(0) && ig->OpenPopupStack.Size <= 0) + igOpenPopup("Classes init context menu", 0); + + if (igBeginPopupContextItem("Classes init context menu", 0)) { + render_imgui_context_menu(classes, classes_count); + igEndPopup(); + } + + igRender(); + if (window_handle == GetForegroundWindow()) { if (input_reset) { input_reset = false; camera_reset(cam); - //camera_move_vec3(cam, &(vec3){ 1.35542f, 1.41634f, 1.27852f }); - //camera_rotate_vec2(cam, &(vec2){ -45.0f, -32.5f }); - //camera_move_vec3(cam, &(vec3){ -6.67555f, 4.68882f, -3.67537f }); - //camera_rotate_vec2(cam, &(vec2){ 136.5f, -20.5f }); - camera_move_vec3(cam, &(vec3){ 0.0f, 1.0f, 3.45f }); + //camera_set_position(cam, &(vec3){ 1.35542f, 1.41634f, 1.27852f }); + //camera_rotate(cam, &(vec2d){ -45.0, -32.5 }); + //camera_set_position(cam, &(vec3){ -6.67555f, 4.68882f, -3.67537f }); + //camera_rotate(cam, &(vec2d){ 136.5, -20.5 }); + camera_set_position(cam, &(vec3){ 0.0f, 1.0f, 3.45f }); } else { - camera_move_vec2(cam, &input_move); - camera_rotate_vec2(cam, &input_rotate); + camera_rotate(cam, &input_rotate); + camera_move(cam, &input_move); + camera_roll(cam, input_roll); } } + camera_update(cam); - for (task_render* i = tasks_render.begin; i != tasks_render.end; i++) { + shader_model_c_set_int_array(&default_shader, "material", 8, ((int32_t[]){ 0, 1, 2, 3, 4, 5, 6, 7 })); + shader_model_c_set_int_array(&default_shader, "tex_mode", 8, ((int32_t[]){ 0, 0, 0, 0, 0, 0, 0, 0 })); + shader_model_c_set_bool(&default_shader, "use_bones", false); + shader_model_c_set_bool(&default_shader, "write_only_depth", false); + shader_model_c_set_mat4(&default_shader, "model", false, &mat4_identity); + shader_model_c_set_mat4(&default_shader, "model_normal", false, &mat3_identity); + shader_model_c_set_mat4(&default_shader, "uv_mat", false, &mat4_identity); + shader_model_c_set_vec4(&default_shader, "color", 1.0f, 1.0f, 1.0f, 1.0f); + shader_model_c_set_int(&default_shader, "BoneMatrix", 8); + + shader_model_g_set_int_array(&default_shader, "material", 8, ((int32_t[]){ 0, 1, 2, 3, 4, 5, 6, 7 })); + shader_model_g_set_int_array(&default_shader, "tex_mode", 8, ((int32_t[]){ 0, 0, 0, 0, 0, 0, 0, 0 })); + shader_model_g_set_bool(&default_shader, "use_bones", false); + shader_model_g_set_mat4(&default_shader, "model", false, &mat4_identity); + shader_model_g_set_mat4(&default_shader, "model_normal", false, &mat3_identity); + shader_model_g_set_mat4(&default_shader, "uv_mat", false, &mat4_identity); + shader_model_g_set_vec4(&default_shader, "color", 1.0f, 1.0f, 1.0f, 1.0f); + shader_model_g_set_int(&default_shader, "BoneMatrix", 8); + + shader_model_set_uniform_block_binding(&default_shader, "GlobalMatrices", 0); + + classes_process_render(classes, classes_count); + + glitter_particle_manager_calc_draw(gpm, glt_type, render_glitter_mesh_add_list); + + bool light_dir_tex_update = false; + bool light_point_tex_update = false; + for (task_render* i = tasks_render.begin; i != tasks_render.end; ) { if (i->type == TASK_RENDER_UPDATE) { task_render_update update = i->update; switch (update.type) { @@ -701,7 +1004,7 @@ static void render_update() { bool found = false; gl_object* gl_obj = 0; for (hash_ptr_gl_object* j = vec_gl_obj.begin; j != vec_gl_obj.end; j++) - if (j->hash == update.hash) { + if (HASH_COMPARE(j->hash, update.hash)) { found = true; gl_obj = j->data; break; @@ -710,50 +1013,191 @@ static void render_update() { if (!found) gl_obj = gl_object_init(); - for (hash_texture_set* j = vec_tex_set.begin; j != vec_tex_set.end; j++) - if (j->hash == update.gl_obj.texture) { - gl_object_update_texture(gl_obj, &j->data); - break; - } - - for (hash_shader_model* j = vec_shad.begin; j != vec_shad.end; j++) - if (j->hash == update.gl_obj.shader) { - gl_object_update_shader(gl_obj, &j->data); - break; - } - + bool found_vert = false; for (hash_ptr_vertex* j = vec_vert.begin; j != vec_vert.end; j++) - if (j->hash == update.gl_obj.texture) { + if (HASH_COMPARE(j->hash, update.gl_obj.vert)) { + found_vert = true; gl_object_update_vert(gl_obj, j->data); break; } - gl_object_update_instances(gl_obj, &update.gl_obj.instances); + if (!found_vert) + gl_object_update_vert(gl_obj, default_vertex); + + bool found_material = false; + for (hash_material* j = vec_mat.begin; j != vec_mat.end; j++) + if (HASH_COMPARE(j->hash, update.gl_obj.material)) { + found_material = true; + gl_object_update_material(gl_obj, &j->data); + break; + } + + if (!found_material) + gl_object_update_material(gl_obj, &default_material); + + bool found_shader = false; + for (hash_shader_model* j = vec_shad.begin; j != vec_shad.end; j++) + if (HASH_COMPARE(j->hash, update.gl_obj.shader)) { + found_shader = true; + gl_object_update_shader(gl_obj, &j->data); + break; + } + + if (!found_shader) + gl_object_update_shader(gl_obj, &default_shader); + + bool found_bone_mat = false; + for (hash_texture_bone_mat* j = vec_tex_bone_mat.begin; j != vec_tex_bone_mat.end; j++) + if (HASH_COMPARE(j->hash, update.gl_obj.bone_mat)) { + found_bone_mat = true; + gl_object_update_bone_mat(gl_obj, &j->data); + break; + } + + if (!found_bone_mat) + gl_object_update_bone_mat(gl_obj, &default_bone_mat); + if (!found) { hash_ptr_gl_object hash_gl_obj; hash_gl_obj.hash = update.hash; hash_gl_obj.data = gl_obj; vector_hash_ptr_gl_object_push_back(&vec_gl_obj, &hash_gl_obj); } + + gl_object_update_cull_face(gl_obj, update.gl_obj.cull_face); } break; - case TASK_RENDER_UPDATE_SHADER: { + case TASK_RENDER_UPDATE_MATERIAL: { bool found = false; - for (hash_shader_model* j = vec_shad.begin; j != vec_shad.end; j++) - if (j->hash == update.hash) { + material* mat; + for (hash_material* j = vec_mat.begin; j != vec_mat.end; j++) + if (HASH_COMPARE(j->hash, update.hash)) { found = true; + mat = &j->data; break; } if (!found) { - shader_model shad; - memset(&shad, 0, sizeof(shad)); - shader_model_load(&shad, &update.shad); + material m; + memset(&m, 0, sizeof(material)); + mat = &m; + } + + mat->blend = update.mat.blend; + mat->translucent = update.mat.translucent; + + bool found_texture = false; + for (hash_texture_set* j = vec_tex_set.begin; j != vec_tex_set.end; j++) + if (HASH_COMPARE(j->hash, update.mat.texture)) { + found_texture = true; + mat->texture = j->data; + break; + } + + if (!found_texture) + mat->texture = default_texture; + + if (!found) { + hash_material hash_mat; + hash_mat.hash = update.hash; + hash_mat.data = *mat; + vector_hash_material_push_back(&vec_mat, &hash_mat); + } + } break; + case TASK_RENDER_UPDATE_LIGHT_DIR: { + bool found = false; + light_dir* light; + for (hash_light_dir* j = vec_light_dir.begin; j != vec_light_dir.end; j++) + if (HASH_COMPARE(j->hash, update.hash)) { + found = true; + light = &j->data; + break; + } + + light_dir_update* l = &update.light_dir; + + vec3 color; + vec3 dir; + color = *(vec3*)&l->color; + vec3_mult_scalar(color, l->color.w, color); + vec3_normalize(l->dir, dir); + + if (!found) { + hash_light_dir hash_light_dir; + hash_light_dir.hash = update.hash; + hash_light_dir.data.dir = dir; + hash_light_dir.data.color = color; + vector_hash_light_dir_push_back(&vec_light_dir, &hash_light_dir); + } + else { + light->dir = dir; + light->color = color; + } + light_dir_tex_update = true; + } break; + case TASK_RENDER_UPDATE_LIGHT_POINT: { + bool found = false; + light_point* light; + for (hash_light_point* j = vec_light_point.begin; j != vec_light_point.end; j++) + if (HASH_COMPARE(j->hash, update.hash)) { + found = true; + light = &j->data; + break; + } + + light_point_update* l = &update.light_point; + + vec3 color; + color = *(vec3*)&l->color; + vec3_mult_scalar(color, l->color.w, color); + + float_t radius = light_point_calculate_radius(&color, + l->constant, l->linear, l->quadratic); + + if (!found) { + hash_light_point hash_light_point; + hash_light_point.hash = update.hash; + hash_light_point.data.position = l->position; + hash_light_point.data.color = color; + hash_light_point.data.constant = l->constant; + hash_light_point.data.linear = l->linear; + hash_light_point.data.quadratic = l->quadratic; + hash_light_point.data.radius = radius; + vector_hash_light_point_push_back(&vec_light_point, &hash_light_point); + } + else { + light->position = l->position; + light->color = color; + light->constant = l->constant; + light->linear = l->linear; + light->quadratic = l->quadratic; + light->radius = radius; + } + light_point_tex_update = true; + } break; + case TASK_RENDER_UPDATE_SHADER: { + bool found = false; + shader_model* shad; + for (hash_shader_model* j = vec_shad.begin; j != vec_shad.end; j++) + if (HASH_COMPARE(j->hash, update.hash)) { + found = true; + shad = &j->data; + break; + } + + if (!found) { + shader_model s; + memset(&s, 0, sizeof(s)); + shader_model_load(&s, &update.shad); hash_shader_model hash_shad; hash_shad.hash = update.hash; - hash_shad.data = shad; + hash_shad.data = s; vector_hash_shader_model_push_back(&vec_shad, &hash_shad); } + else { + shader_model_free(shad); + shader_model_load(shad, &update.shad); + } free(update.shad.frag_c); free(update.shad.frag_g); free(update.shad.vert); @@ -761,249 +1205,340 @@ static void render_update() { } break; case TASK_RENDER_UPDATE_TEXTURE: { bool found = false; - texture tex ; + texture* tex; for (hash_texture* j = vec_tex.begin; j != vec_tex.end; j++) - if (j->hash == update.hash) { + if (HASH_COMPARE(j->hash, update.hash)) { found = true; - tex = j->data; + tex = &j->data; break; } - if (!found) - memset(&tex, 0, sizeof(texture)); - - texture_load(&tex, &update.tex); - if (!found) { + texture t; + memset(&t, 0, sizeof(texture)); + texture_load(&t, &update.tex); hash_texture hash_tex; hash_tex.hash = update.hash; - hash_tex.data = tex; + hash_tex.data = t; vector_hash_texture_push_back(&vec_tex, &hash_tex); } + else + texture_load(tex, &update.tex); } break; case TASK_RENDER_UPDATE_TEXTURE_SET: { bool found = false; - texture_set tex_set; + texture_set* tex_set; for (hash_texture_set* j = vec_tex_set.begin; j != vec_tex_set.end; j++) - if (j->hash == update.hash) { + if (HASH_COMPARE(j->hash, update.hash)) { found = true; - tex_set = j->data; + tex_set = &j->data; break; } - if (!found) - memset(&tex_set, 0, sizeof(texture_set)); - - texture_set_load(&tex_set, &update.tex_set); - if (!found) { + texture_set t; + memset(&t, 0, sizeof(texture_set)); + texture_set_load(&t, &update.tex_set); + hash_texture_set hash_tex_set; hash_tex_set.hash = update.hash; - hash_tex_set.data = tex_set; + hash_tex_set.data = t; vector_hash_texture_set_push_back(&vec_tex_set, &hash_tex_set); } + else + texture_set_load(tex_set, &update.tex_set); } break; case TASK_RENDER_UPDATE_VERT: { bool found = false; vertex* vert = 0; for (hash_ptr_vertex* j = vec_vert.begin; j != vec_vert.end; j++) - if (j->hash == update.hash) { + if (HASH_COMPARE(j->hash, update.hash)) { found = true; vert = j->data; break; } - if (!found) - vert = vertex_init(); - - vertex_load(vert, &update.vert); - if (!found) { + vert = vertex_init(); + vertex_load(vert, &update.vert); + hash_ptr_vertex hash_vert; hash_vert.hash = update.hash; hash_vert.data = vert; vector_hash_ptr_vertex_push_back(&vec_vert, &hash_vert); } + else + vertex_load(vert, &update.vert); } break; } - memset(i, 0, sizeof(task_render)); } else if (i->type == TASK_RENDER_FREE) { task_render_free free_data = i->free; switch (free_data.type) { - case TASK_RENDER_UPDATE_GL_OBJECT: + case TASK_RENDER_FREE_GL_OBJECT: for (hash_ptr_gl_object* j = vec_gl_obj.begin; j != vec_gl_obj.end; j++) - if (j->hash == free_data.hash) { + if (HASH_COMPARE(j->hash, free_data.hash)) { gl_object_dispose(j->data); vector_hash_ptr_gl_object_erase(&vec_gl_obj, j - vec_gl_obj.begin); break; } break; - case TASK_RENDER_UPDATE_SHADER: + case TASK_RENDER_FREE_LIGHT_DIR: { + bool found = false; + for (hash_light_dir* j = vec_light_dir.begin; j != vec_light_dir.end; j++) + if (HASH_COMPARE(j->hash, free_data.hash)) { + found = true; + vector_hash_light_dir_erase(&vec_light_dir, j - vec_light_dir.begin); + break; + } + } break; + case TASK_RENDER_FREE_LIGHT_POINT: { + for (hash_light_point* j = vec_light_point.begin; j != vec_light_point.end; j++) + if (HASH_COMPARE(j->hash, free_data.hash)) { + vector_hash_light_point_erase(&vec_light_point, j - vec_light_point.begin); + break; + } + } break; + case TASK_RENDER_FREE_MATERIAL: + for (hash_material* j = vec_mat.begin; j != vec_mat.end; j++) + if (HASH_COMPARE(j->hash, free_data.hash)) { + vector_hash_material_erase(&vec_mat, j - vec_mat.begin); + break; + } + break; + case TASK_RENDER_FREE_SHADER: for (hash_shader_model* j = vec_shad.begin; j != vec_shad.end; j++) - if (j->hash == free_data.hash) { + if (HASH_COMPARE(j->hash, free_data.hash)) { shader_model_free(&j->data); vector_hash_shader_model_erase(&vec_shad, j - vec_shad.begin); break; } break; - case TASK_RENDER_UPDATE_TEXTURE: + case TASK_RENDER_FREE_TEXTURE: for (hash_texture* j = vec_tex.begin; j != vec_tex.end; j++) - if (j->hash == free_data.hash) { + if (HASH_COMPARE(j->hash, free_data.hash)) { texture_free(&j->data); vector_hash_texture_erase(&vec_tex, j - vec_tex.begin); break; } break; - case TASK_RENDER_UPDATE_TEXTURE_SET: + case TASK_RENDER_FREE_TEXTURE_SET: for (hash_texture_set* j = vec_tex_set.begin; j != vec_tex_set.end; j++) - if (j->hash == free_data.hash) { + if (HASH_COMPARE(j->hash, free_data.hash)) { texture_set_free(&j->data); vector_hash_texture_set_erase(&vec_tex_set, j - vec_tex_set.begin); break; } break; - case TASK_RENDER_UPDATE_VERT: + case TASK_RENDER_FREE_VERT: for (hash_ptr_vertex* j = vec_vert.begin; j != vec_vert.end; j++) - if (j->hash == free_data.hash) { + if (HASH_COMPARE(j->hash, free_data.hash)) { vertex_dispose(j->data); vector_hash_ptr_vertex_erase(&vec_vert, j - vec_vert.begin); break; } break; } - memset(i, 0, sizeof(task_render)); } else if (i->type == TASK_RENDER_UNIFORM) { - task_render_uniform uniform = i->uniform; + task_render_uniform uni = i->uniform; + shader_model* s = 0; for (hash_shader_model* j = vec_shad.begin; j != vec_shad.end; j++) - if (j->hash == uniform.shader_hash) { - shader_model* s = &j->data; - char* name = char_buffer_select(&uniform.name); - switch (uniform.type) { - case TASK_RENDER_UNIFORM_BOOL: { - task_render_uniform_bool uni_data = uniform.bool; - shader_model_set_bool(s, name, uni_data.value); - } break; - case TASK_RENDER_UNIFORM_INT32: { - task_render_uniform_int32 uni_data = uniform.int32; - shader_model_set_int(s, name, uni_data.value); - } break; - case TASK_RENDER_UNIFORM_FLOAT32: { - task_render_uniform_float32 uni_data = uniform.float32; - shader_model_set_float(s, name, uni_data.value); - } break; - case TASK_RENDER_UNIFORM_VEC2: { - task_render_uniform_vec2 uni_data = uniform.vec2; - shader_model_set_vec2(s, name, uni_data.value.x, uni_data.value.y); - } break; - case TASK_RENDER_UNIFORM_VEC2I: { - task_render_uniform_vec2i uni_data = uniform.vec2i; - shader_model_set_vec2i(s, name, uni_data.value.x, uni_data.value.y); - } break; - case TASK_RENDER_UNIFORM_VEC3: { - task_render_uniform_vec3 uni_data = uniform.vec3; - shader_model_set_vec3(s, name, uni_data.value.x, uni_data.value.y, uni_data.value.z); - } break; - case TASK_RENDER_UNIFORM_VEC3I: { - task_render_uniform_vec3i uni_data = uniform.vec3i; - shader_model_set_vec3i(s, name, uni_data.value.x, uni_data.value.y, uni_data.value.z); - } break; - case TASK_RENDER_UNIFORM_VEC4: { - task_render_uniform_vec4 uni_data = uniform.vec4; - shader_model_set_vec4(s, name, uni_data.value.x, - uni_data.value.y, uni_data.value.z, uni_data.value.w); - } break; - case TASK_RENDER_UNIFORM_VEC4I: { - task_render_uniform_vec4i uni_data = uniform.vec4i; - shader_model_set_vec4i(s, name, uni_data.value.x, - uni_data.value.y, uni_data.value.z, uni_data.value.w); - } break; - case TASK_RENDER_UNIFORM_MAT3: { - task_render_uniform_mat3 uni_data = uniform.mat3; - shader_model_set_mat3(s, name, uni_data.transpose, &uni_data.value); - } break; - case TASK_RENDER_UNIFORM_MAT4: { - task_render_uniform_mat4 uni_data = uniform.mat4; - shader_model_set_mat4(s, name, uni_data.transpose, &uni_data.value); - } break; - case TASK_RENDER_UNIFORM_INT32_ARRAY: { - task_render_uniform_int32_array uni_data = uniform.int32_array; - shader_model_set_int_array(s, name, (GLsizei)uni_data.count, uni_data.value); - free(uni_data.value); - } break; - case TASK_RENDER_UNIFORM_FLOAT32_ARRAY: { - task_render_uniform_float32_array uni_data = uniform.float32_array; - shader_model_set_float_array(s, name, (GLsizei)uni_data.count, uni_data.value); - free(uni_data.value); - } break; - case TASK_RENDER_UNIFORM_VEC2_ARRAY: { - task_render_uniform_vec2_array uni_data = uniform.vec2_array; - shader_model_set_vec2_array(s, name, (GLsizei)uni_data.count, uni_data.value); - free(uni_data.value); - } break; - case TASK_RENDER_UNIFORM_VEC2I_ARRAY: { - task_render_uniform_vec2i_array uni_data = uniform.vec2i_array; - shader_model_set_vec2i_array(s, name, (GLsizei)uni_data.count, uni_data.value); - free(uni_data.value); - } break; - case TASK_RENDER_UNIFORM_VEC3_ARRAY: { - task_render_uniform_vec3_array uni_data = uniform.vec3_array; - shader_model_set_vec3_array(s, name, (GLsizei)uni_data.count, uni_data.value); - free(uni_data.value); - } break; - case TASK_RENDER_UNIFORM_VEC3I_ARRAY: { - task_render_uniform_vec3i_array uni_data = uniform.vec3i_array; - shader_model_set_vec3i_array(s, name, (GLsizei)uni_data.count, uni_data.value); - free(uni_data.value); - } break; - case TASK_RENDER_UNIFORM_VEC4_ARRAY: { - task_render_uniform_vec4_array uni_data = uniform.vec4_array; - shader_model_set_vec4_array(s, name, (GLsizei)uni_data.count, uni_data.value); - free(uni_data.value); - } break; - case TASK_RENDER_UNIFORM_VEC4I_ARRAY: { - task_render_uniform_vec4i_array uni_data = uniform.vec4i_array; - shader_model_set_vec4i_array(s, name, (GLsizei)uni_data.count, uni_data.value); - free(uni_data.value); - } break; - case TASK_RENDER_UNIFORM_MAT3_ARRAY: { - task_render_uniform_mat3_array uni_data = uniform.mat3_array; - shader_model_set_mat3_array(s, name, (GLsizei)uni_data.count, - uni_data.transpose, uni_data.value); - free(uni_data.value); - } break; - case TASK_RENDER_UNIFORM_MAT4_ARRAY: { - task_render_uniform_mat4_array uni_data = uniform.mat4_array; - shader_model_set_mat4_array(s, name, (GLsizei)uni_data.count, - uni_data.transpose, uni_data.value); - free(uni_data.value); - } break; - } + if (HASH_COMPARE(j->hash, uni.shader_hash)) { + s = &j->data; break; } - char_buffer_dispose(&uniform.name); - memset(i, 0, sizeof(task_render)); + + if (!s) + s = &default_shader; + + render_update_uniform_c(&uni, s); + render_update_uniform_g(&uni, s); + char_buffer_dispose(&uni.name); + } + memset(i, 0, sizeof(task_render)); + vector_task_render_erase(&tasks_render, 0); + } + + if (light_dir_tex_update) { + size_t light_dir_count = vec_light_dir.end - vec_light_dir.begin; + if (light_dir_count) { + const size_t light_dir_size = 6; + float_t* light_dir_data = force_malloc_s(sizeof(float_t), light_dir_size * light_dir_count); + + for (size_t i = 0; i < light_dir_count; i++) { + light_dir* light = &vec_light_dir.begin[i].data; + light_dir_data[i * light_dir_size] = light->dir.x; + light_dir_data[i * light_dir_size + 1] = light->dir.y; + light_dir_data[i * light_dir_size + 2] = light->dir.z; + light_dir_data[i * light_dir_size + 3] = light->color.x; + light_dir_data[i * light_dir_size + 4] = light->color.y; + light_dir_data[i * light_dir_size + 5] = light->color.z; + } + + texture_data light_dir_tex_data = { + .type = TEXTURE_2D, + .width = 2, + .height = (int32_t)light_dir_count, + .depth = 0, + .data = light_dir_data, + .pixel_type = GL_FLOAT, + .pixel_format = GL_RGB, + .pixel_internal_format = GL_RGB32F, + .generate_mipmap = false, + .wrap_mode_s = GL_REPEAT, + .wrap_mode_t = GL_REPEAT, + .wrap_mode_r = GL_REPEAT, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST, + }; + + texture_load(&light_dir_tex, &light_dir_tex_data); + free(light_dir_data); + } + else { + texture_data light_dir_tex_data = { + .type = TEXTURE_2D, + .width = 2, + .height = 1, + .depth = 0, + .data = (void*)light_dir_data_default, + .pixel_type = GL_FLOAT, + .pixel_format = GL_RGBA, + .pixel_internal_format = GL_RGBA32F, + .generate_mipmap = false, + .wrap_mode_s = GL_REPEAT, + .wrap_mode_t = GL_REPEAT, + .wrap_mode_r = GL_REPEAT, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST, + }; + + texture_load(&light_dir_tex, &light_dir_tex_data); } } + if (light_point_tex_update) { + size_t light_point_count = vec_light_point.end - vec_light_point.begin; + + if (light_point_count) { + const size_t light_point_size = 12; + float_t* light_point_data = force_malloc_s(sizeof(float_t), light_point_size * light_point_count); + + for (size_t i = 0; i < light_point_count; i++) { + light_point* light = &vec_light_point.begin[i].data; + light_point_data[i * light_point_size] = light->position.x; + light_point_data[i * light_point_size + 1] = light->position.y; + light_point_data[i * light_point_size + 2] = light->position.z; + light_point_data[i * light_point_size + 3] = 0.0f; + light_point_data[i * light_point_size + 4] = light->color.x; + light_point_data[i * light_point_size + 5] = light->color.y; + light_point_data[i * light_point_size + 6] = light->color.z; + light_point_data[i * light_point_size + 7] = 0.0f; + light_point_data[i * light_point_size + 8] = light->constant; + light_point_data[i * light_point_size + 9] = light->linear; + light_point_data[i * light_point_size + 10] = light->quadratic; + light_point_data[i * light_point_size + 11] = light->radius; + } + + texture_data light_point_tex_data = { + .type = TEXTURE_2D, + .width = 3, + .height = (int32_t)light_point_count, + .depth = 0, + .data = light_point_data, + .pixel_type = GL_FLOAT, + .pixel_format = GL_RGBA, + .pixel_internal_format = GL_RGBA32F, + .generate_mipmap = false, + .wrap_mode_s = GL_REPEAT, + .wrap_mode_t = GL_REPEAT, + .wrap_mode_r = GL_REPEAT, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST, + }; + + texture_load(&light_point_tex, &light_point_tex_data); + free(light_point_data); + } + else { + texture_data light_point_tex_data = { + .type = TEXTURE_2D, + .width = 3, + .height = 1, + .depth = 0, + .data = (void*)light_point_data_default, + .pixel_type = GL_FLOAT, + .pixel_format = GL_RGBA, + .pixel_internal_format = GL_RGBA32F, + .generate_mipmap = false, + .wrap_mode_s = GL_REPEAT, + .wrap_mode_t = GL_REPEAT, + .wrap_mode_r = GL_REPEAT, + .min_filter = GL_NEAREST, + .mag_filter = GL_NEAREST, + }; + + texture_load(&light_point_tex, &light_point_tex_data); + } + } + + for (task_render_draw2d* i = tasks_render_draw2d_int.begin; i != tasks_render_draw2d_int.end; i++) { + for (task_render_uniform* j = i->uniforms.begin; j != i->uniforms.end; j++) + char_buffer_dispose(&j->name); + vector_task_render_uniform_free(&i->uniforms); + } + vector_task_render_draw2d_clear(&tasks_render_draw2d_int); + if (tasks_render_draw2d.end - tasks_render_draw2d.begin > 0) { - vector_task_render_draw2d_clear(&tasks_render_draw2d_int); vector_task_render_draw2d_append(&tasks_render_draw2d_int, tasks_render_draw2d.end - tasks_render_draw2d.begin); for (task_render_draw2d* i = tasks_render_draw2d.begin; i != tasks_render_draw2d.end; i++) vector_task_render_draw2d_push_back(&tasks_render_draw2d_int, i); - vector_task_render_draw2d_clear(&tasks_render_draw2d); } + vector_task_render_draw2d_clear(&tasks_render_draw2d); + + for (task_render_draw3d* i = tasks_render_draw3d_int.begin; i != tasks_render_draw3d_int.end; i++) { + for (task_render_uniform* j = i->uniforms.begin; j != i->uniforms.end; j++) + char_buffer_dispose(&j->name); + vector_task_render_uniform_free(&i->uniforms); + } + vector_task_render_draw3d_clear(&tasks_render_draw3d_int); if (tasks_render_draw3d.end - tasks_render_draw3d.begin > 0) { - vector_task_render_draw3d_clear(&tasks_render_draw3d_int); vector_task_render_draw3d_append(&tasks_render_draw3d_int, tasks_render_draw3d.end - tasks_render_draw3d.begin); for (task_render_draw3d* i = tasks_render_draw3d.begin; i != tasks_render_draw3d.end; i++) vector_task_render_draw3d_push_back(&tasks_render_draw3d_int, i); - vector_task_render_draw3d_clear(&tasks_render_draw3d); } + vector_task_render_draw3d_clear(&tasks_render_draw3d); + + /*cam.Set(camStruct); + + if (camStruct.DOF.HasValue) + { + ModelTrans dofMT = camStruct.DOF.Value; + + dof.Debug.Flags = 0; + dof.PV.DistanceToFocus = (dofMT.Trans - cam.Pos).Length; + dof.PV.FocusRange = dofMT.Scale.X; + dof.PV.FuzzingRange = dofMT.Rot.X; + dof.PV.Ratio = dofMT.Rot.Y; + dof.PV.Enable = camStruct.DOF.Value.Rot.Z > 0.000001f; + + if (dof.PV.Ratio > 0.0f && dof.PV.Enable) + { + double fov = cam.FOVIsHorizontal ? 2 * Math.Atan(1 / cam.Aspect * Math.Tan(cam.FOV / 2)) : cam.FOV; + float[] data = GetDOFData(ref dof, (float)fov); + + GL.BindBuffer(BufferTarget.UniformBuffer, dofCommonUBO); + GL.BufferSubData(BufferTarget.UniformBuffer, (IntPtr)0, data.Length * 4, data); + GL.BindBuffer(BufferTarget.UniformBuffer, 0); + } + }*/ + + //static bool show_demo_window; + //igShowDemoWindow(&show_demo_window); if (rad->update || inten->update) { rad->update = false; @@ -1015,10 +1550,10 @@ static void render_update() { vec4* radius = rad->val; vec4 v[GAUSSIAN_KERNEL_SIZE]; - for (int32_t i = 0; i < GAUSSIAN_KERNEL_SIZE; i++) + for (size_t i = 0; i < GAUSSIAN_KERNEL_SIZE; i++) vec4_mult(radius[i], rgba, v[i]); - for (int32_t i = 6; i < 12; i++) + for (size_t i = 6; i < 12; i++) shader_fbo_set_vec4_array(&bfbs[i], "gaussianKernel", GAUSSIAN_KERNEL_SIZE, v); } @@ -1032,124 +1567,192 @@ static void render_update() { pfbo->tone_map_method = tmd->tone_map_method; pfbo->scene_fade = tmd->scene_fade_alpha > 0.009999999f; - glBindBuffer(GL_UNIFORM_BUFFER, tone_map_ubo); + bind_uniform_buffer(tone_map_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0, 16 * sizeof(float_t), tmd->val); - glBindBuffer(GL_UNIFORM_BUFFER, 0); + bind_uniform_buffer(0); } - for (size_t i = 0; i < classes_count; i++) - if (classes[i].render) - classes[i].render(); + bool use_dof_f2 = false; + if (dof->debug.flags & DOF_DEBUG_USE_UI_PARAMS) { + if (dof->debug.flags & DOF_DEBUG_ENABLE_DOF) { + if (dof->debug.flags & DOF_DEBUG_ENABLE_PHYS_DOF) { + float_t dist_to_focus = dof->debug.distance_to_focus; + if (dof->debug.flags & DOF_DEBUG_AUTO_FOCUS && false) { + mat4 view_transpose; + mat4_transpose(&cam->view, &view_transpose); + vec3 chara_trans = vec3_null; + vec3_dot(cam->view_point, chara_trans, dist_to_focus); + dist_to_focus = -dist_to_focus - 0.1f; + } - /*cam.Set(camStruct); - - if (camStruct.DOF.HasValue) - { - ModelTrans dofMT = camStruct.DOF.Value; - - dof.Debug.Flags = 0; - dof.PV.DistanceToFocus = (dofMT.Trans - cam.Pos).Length; - dof.PV.FocusRange = dofMT.Scale.X; - dof.PV.FuzzingRange = dofMT.Rot.X; - dof.PV.Ratio = dofMT.Rot.Y; - dof.PV.Flags = camStruct.DOF.Value.Rot.Z > 0.0f ? Camera.DOFPVFlags.Enable : 0; - - if ((dof.PV.Flags & Camera.DOFPVFlags.Enable) != 0) - { - double_t fov = cam.FOVIsHorizontal ? 2 * Math.Atan(1 / cam.Aspect * Math.Tan(cam.FOV / 2)) : cam.FOV; - float_t[] data = GetDOFData(ref dof, (float_t)fov); - - glBindBuffer(BufferTarget.UniformBuffer, dofCommonUBO); - glBufferSubData(BufferTarget.UniformBuffer, (IntPtr)0, data.Length * 4, data); - glBindBuffer(BufferTarget.UniformBuffer, 0); + dist_to_focus = max(dist_to_focus, (float_t)cam->min_distance); + dof_calculate_physical(dof, internal_3d_res.y, + cam->min_distance, cam->max_distance, cam->fov, dist_to_focus, + dof->debug.focal_length, dof->debug.f_number); + } + else { + float_t fuzzing_range = max(dof->debug.f2.fuzzing_range, 0.01f); + dof_calculate_f2(dof, internal_3d_res.y, + cam->min_distance, cam->max_distance, cam->fov, dof->debug.f2.distance_to_focus, + dof->debug.f2.focus_range, fuzzing_range, dof->debug.f2.ratio); + use_dof_f2 = true; + } } - }*/ + } + else if (dof->pv.enable && dof->pv.f2.ratio > 0.0f) { + float_t fuzzing_range = max(dof->pv.f2.fuzzing_range, 0.01f); + dof_calculate_f2(dof, internal_3d_res.y, + cam->min_distance, cam->max_distance, cam->fov, dof->pv.f2.distance_to_focus, + dof->pv.f2.focus_range, fuzzing_range, dof->pv.f2.ratio); + dof->debug.flags |= DOF_DEBUG_ENABLE_DOF; + dof->debug.f2.distance_to_focus = dof->pv.f2.distance_to_focus; + dof->debug.f2.focus_range = dof->pv.f2.focus_range; + dof->debug.f2.fuzzing_range = dof->pv.f2.fuzzing_range; + dof->debug.f2.ratio = dof->pv.f2.ratio; + use_dof_f2 = true; + } + else + dof->debug.flags &= ~DOF_DEBUG_ENABLE_DOF; - shader_fbo* c_shader = rfbo->samples > 1 ? rfbo->samples > 2 ? rfbo->samples > 4 ? rfbo->samples > 8 ? - &rfbo->c_shader[9] : &rfbo->c_shader[8] : &rfbo->c_shader[7] : &rfbo->c_shader[6] : &rfbo->c_shader[5]; - shader_fbo_set_float(c_shader, "f", (float_t)cam->max_distance); + mat4 inv_vp; + mat4_inverse(&cam->view_projection, &inv_vp); + + shader_fbo* g_shader = rfbo->samples > 1 ? rfbo->samples > 2 ? rfbo->samples > 4 ? rfbo->samples > 8 ? + &rfbo->g_shader[4] : &rfbo->g_shader[3] : &rfbo->g_shader[2] : &rfbo->g_shader[1] : &rfbo->g_shader[0]; + shader_fbo_set_vec3(g_shader, "viewPos", cam->view_point.x, cam->view_point.y, cam->view_point.z); + shader_fbo_set_mat4(g_shader, "inv_vp", false, &inv_vp); uint8_t global_matrices[sizeof(mat4) * 4]; ((mat4*)global_matrices)[0] = cam->view_projection; ((mat4*)global_matrices)[1] = cam->view; ((mat4*)global_matrices)[2] = cam->projection; - ((vec3*)(global_matrices + sizeof(mat4) * 3))[0] = cam->position; - glBindBuffer(GL_UNIFORM_BUFFER, global_matrices_ubo); + ((vec3*)(global_matrices + sizeof(mat4) * 3))[0] = cam->view_point; + bind_uniform_buffer(global_matrices_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(mat4) * 4, global_matrices); - glBindBuffer(GL_UNIFORM_BUFFER, 0); + + bind_uniform_buffer(dof_common_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(dof->data), dof->data); + bind_uniform_buffer(0); } static void render_draw() { - glBindFramebuffer(GL_FRAMEBUFFER, 0); + static const GLfloat color_clear[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + static const GLfloat depth_clear = 1.0f; + static const GLint stencil_clear = 0; + + bind_framebuffer(0); glDrawBuffer(GL_COLOR_ATTACHMENT0); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearStencil(0); - glClearDepthf(1.0f); glDepthMask(true); - glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glStencilMask(0xFF); + glClearBufferfv(GL_COLOR, 0, color_clear); + glClearBufferfi(GL_DEPTH_STENCIL, 0, depth_clear, stencil_clear); + glStencilMask(0); glDepthMask(false); - if (back_2d || back_3d || g_front_3d || c_front_3d) { + for (int32_t i = 0; i < 32; i++) { + active_texture(i); + bind_tex1d(0); + bind_tex2d(0); + bind_tex2dms(0); + bind_tex3d(0); + bind_texcube(0); + } + + if (back_2d || g_back_3d || c_back_3d || g_front_3d || c_front_3d || glitter_3d) { glViewport(0, 0, internal_3d_res.x, internal_3d_res.y); glBindBufferBase(GL_UNIFORM_BUFFER, 0, common_ubo); if (back_2d) { - glBindFramebuffer(GL_FRAMEBUFFER, rfbo->fbo); - glDrawBuffers(2, fbo_render_c_attachments); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - render_back_2d(); + bind_framebuffer(rfbo->fbo); + glDrawBuffers(1, fbo_render_c_attachments); + glClearBufferfv(GL_COLOR, 0, color_clear); + render_2d(TASK_RENDER_DRAW2D_BACK); glBindBufferBase(GL_UNIFORM_BUFFER, 0, common_ubo); - glBindFramebuffer(GL_FRAMEBUFFER, hfbo->fbo[0]); + bind_framebuffer(hfbo->fbo[0]); fbo_render_draw_c(rfbo, false); } glBindBufferBase(GL_UNIFORM_BUFFER, 0, common_ubo); - if (back_3d || g_front_3d || c_front_3d) { - glBindFramebuffer(GL_FRAMEBUFFER, rfbo->fbo); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearStencil(0); - glClearDepthf(1.0f); + if (g_back_3d || c_back_3d || g_front_3d || c_front_3d || glitter_3d) { + bind_framebuffer(rfbo->fbo); glDepthMask(true); - glDrawBuffers(4, fbo_render_g_attachments); - glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glDrawBuffers(1, fbo_render_f_attachments); - glClearColor(background_color.color.x, background_color.color.y, background_color.color.z, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + glStencilMask(0xFF); + glClearBufferfi(GL_DEPTH_STENCIL, 0, depth_clear, stencil_clear); + glStencilMask(0); glDepthMask(false); - if (back_3d) - render_back_3d(); - if (g_front_3d) - render_g_front_3d(); - if (c_front_3d) - render_c_front_3d(); - glDrawBuffers(1, fbo_render_f_attachments); + vec4 color; + *(vec3*)&color = back3d_color; + color.w = 1.0f; + glDrawBuffers(1, fbo_render_c_attachments); + glClearBufferfv(GL_COLOR, 0, (GLfloat*)&color); + + if (c_back_3d) { + render_c_3d(TASK_RENDER_DRAW3D_BACK); + render_c_3d_translucent(TASK_RENDER_DRAW3D_BACK); + + glDepthMask(true); + glStencilMask(0xFF); + glClearBufferfi(GL_DEPTH_STENCIL, 0, depth_clear, stencil_clear); + glStencilMask(0); + glDepthMask(false); + } + + if (g_front_3d) + render_g_3d(TASK_RENDER_DRAW3D_G_FRONT); + + if (grid_3d) + render_grid_3d(); + + if (c_front_3d) + render_c_3d(TASK_RENDER_DRAW3D_C_FRONT); + + if (glitter_3d) + render_glitter_3d(0); + + if (glitter_3d) + render_glitter_3d(2); + + if (glitter_3d) + render_glitter_3d(1); + + if (c_front_3d) + render_c_3d_translucent(TASK_RENDER_DRAW3D_C_FRONT); + + glDrawBuffers(1, fbo_render_c_attachments); glBindBufferBase(GL_UNIFORM_BUFFER, 0, global_matrices_ubo); - glitter_particle_manager_reset_scene_disp_counter(gpm); - glitter_particle_manager_draw(gpm, 0); - glitter_particle_manager_draw(gpm, 2); - glitter_particle_manager_draw(gpm, 1); glBindBufferBase(GL_UNIFORM_BUFFER, 0, common_ubo); - glBindFramebuffer(GL_FRAMEBUFFER, hfbo->fbo[0]); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearStencil(0); - glClearDepthf(1.0f); + bind_framebuffer(hfbo->fbo[0]); glDepthMask(true); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClearBufferfv(GL_COLOR, 0, color_clear); + glClearBufferfv(GL_DEPTH, 0, &depth_clear); glDepthMask(false); - fbo_render_draw_c(rfbo, enable_dof); - if (enable_dof) - fbo_dof_draw(dfbo, hfbo->tcb[0], hfbo->tcb[1], hfbo->fbo[0], enable_dof_f2); + if (dof->debug.flags & DOF_DEBUG_USE_UI_PARAMS ? true : false) { + if (dof->debug.flags & DOF_DEBUG_ENABLE_DOF) { + fbo_render_draw_c(rfbo, true); + if (dof->debug.flags & DOF_DEBUG_ENABLE_PHYS_DOF) + fbo_dof_draw(dfbo, hfbo->tcb[0], hfbo->tcb[1], hfbo->fbo[0], false); + else + fbo_dof_draw(dfbo, hfbo->tcb[0], hfbo->tcb[1], hfbo->fbo[0], true); + } + else + fbo_render_draw_c(rfbo, false); + } + else if (dof->pv.enable && dof->pv.f2.ratio > 0.0f) { + fbo_render_draw_c(rfbo, true); + fbo_dof_draw(dfbo, hfbo->tcb[0], hfbo->tcb[1], hfbo->fbo[0], true); + } + else + fbo_render_draw_c(rfbo, false); } if (enable_post_process) fbo_pp_draw(pfbo, hfbo->tcb[0], hfbo->fbo[0], 1, fbo_hdr_f_attachments); fbo_hdr_draw_aa(hfbo); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + bind_framebuffer(0); glDrawBuffer(GL_COLOR_ATTACHMENT0); glViewport(0, 0, width, height); fbo_hdr_draw(hfbo); @@ -1160,13 +1763,14 @@ static void render_draw() { glViewport((width - internal_2d_res.x) / 2, (height - internal_2d_res.y) / 2, internal_2d_res.x, internal_2d_res.y); if (front_2d) - render_front_2d(); + render_2d(TASK_RENDER_DRAW2D_FRONT); if (ui) - render_ui(); + render_2d(TASK_RENDER_DRAW2D_UI); glViewport(0, 0, width, height); - if (micro_ui) - render_micro_ui(); } + + if (imgui) + render_imgui(); } static void render_dispose() { @@ -1187,58 +1791,85 @@ static void render_dispose() { char_buffer_dispose(&uniform.name); } } + vector_task_render_free(&tasks_render); + + for (task_render_draw2d* i = tasks_render_draw2d.begin; i != tasks_render_draw2d.end; i++) { + for (task_render_uniform* j = i->uniforms.begin; j != i->uniforms.end; j++) + char_buffer_dispose(&j->name); + vector_task_render_uniform_free(&i->uniforms); + } vector_task_render_draw2d_free(&tasks_render_draw2d); + + for (task_render_draw2d* i = tasks_render_draw2d_int.begin; i != tasks_render_draw2d_int.end; i++) { + for (task_render_uniform* j = i->uniforms.begin; j != i->uniforms.end; j++) + char_buffer_dispose(&j->name); + vector_task_render_uniform_free(&i->uniforms); + } vector_task_render_draw2d_free(&tasks_render_draw2d_int); + + for (task_render_draw3d* i = tasks_render_draw3d.begin; i != tasks_render_draw3d.end; i++) { + for (task_render_uniform* j = i->uniforms.begin; j != i->uniforms.end; j++) + char_buffer_dispose(&j->name); + vector_task_render_uniform_free(&i->uniforms); + } vector_task_render_draw3d_free(&tasks_render_draw3d); + + for (task_render_draw3d* i = tasks_render_draw3d_int.begin; i != tasks_render_draw3d_int.end; i++) { + for (task_render_uniform* j = i->uniforms.begin; j != i->uniforms.end; j++) + char_buffer_dispose(&j->name); + vector_task_render_uniform_free(&i->uniforms); + } vector_task_render_draw3d_free(&tasks_render_draw3d_int); + vector_task_render_draw3d_free(&temp_draw3d_tasks); + vector_gl_object_free(&temp_draw3d_objects); + for (hash_ptr_gl_object* j = vec_gl_obj.begin; j != vec_gl_obj.end; j++) gl_object_dispose(j->data); vector_hash_ptr_gl_object_free(&vec_gl_obj); + vector_hash_light_dir_free(&vec_light_dir); + + vector_hash_light_point_free(&vec_light_point); + + vector_hash_material_free(&vec_mat); + for (hash_shader_model* j = vec_shad.begin; j != vec_shad.end; j++) shader_model_free(&j->data); vector_hash_shader_model_free(&vec_shad); - for (hash_texture* j = vec_tex.begin; j != vec_tex.end; j++) - texture_free(&j->data); - vector_hash_texture_free(&vec_tex); - for (hash_texture_set* j = vec_tex_set.begin; j != vec_tex_set.end; j++) texture_set_free(&j->data); vector_hash_texture_set_free(&vec_tex_set); + for (hash_texture* j = vec_tex.begin; j != vec_tex.end; j++) + texture_free(&j->data); + vector_hash_texture_free(&vec_tex); + for (hash_ptr_vertex* j = vec_vert.begin; j != vec_vert.end; j++) vertex_dispose(j->data); vector_hash_ptr_vertex_free(&vec_vert); - for (size_t i = 0; i < classes_count; i++) - if (classes[i].dispose) - classes[i].dispose(); + classes_process_dispose(classes, classes_count); camera_dispose(cam); + dof_dispose(dof); radius_dispose(rad); intensity_dispose(inten); tone_map_sat_gamma_dispose(tmsg); tone_map_data_dispose(tmd); glitter_particle_manager_dispose(gpm); - free(muctx); - texture_free(&dir_lights); - texture_free(&point_lights); - texture_free(&mu_font); - - free(dir_light_data); - free(point_light_trans); - free(point_light_data); + texture_free(&light_dir_tex); + texture_free(&light_point_tex); fbo_render_dispose(rfbo); fbo_hdr_dispose(hfbo); fbo_dof_dispose(dfbo); fbo_pp_dispose(pfbo); - for (int32_t i = 0; i < 5; i++) { + for (size_t i = 0; i < 5; i++) { shader_fbo_free(&cfbs[i * 2]); shader_fbo_free(&cfbs[i * 2 + 1]); shader_fbo_free(&gfbs[i]); @@ -1248,197 +1879,225 @@ static void render_dispose() { shader_fbo_free(&hfbs[0]); shader_fbo_free(&hfbs[1]); - for (int32_t i = 0; i < 2; i++) + for (size_t i = 0; i < 2; i++) for (int32_t j = 0; j < 5; j++) shader_fbo_free(&dfbs[i * 5 + j]); - for (int32_t i = 0; i < 16; i++) + for (size_t i = 0; i < 16; i++) shader_fbo_free(&bfbs[i]); - + shader_fbo_free(&tfbs); shader_fbo_free(&particle_shader); shader_fbo_free(&sprite_shader); - shader_fbo_free(&mu_shader); + shader_fbo_free(&grid_shader); - glDeleteBuffers(1, &mu_vert_vbo); - glDeleteBuffers(1, &mu_uv_vbo); - glDeleteBuffers(1, &mu_color_vbo); - glDeleteBuffers(1, &mu_depth_vbo); - glDeleteVertexArrays(1, &mu_vao); + vertex_dispose(default_vertex); + texture_bone_mat_free(&default_bone_mat); + texture_set_free(&default_texture); + memset(&default_material, 0, sizeof(material)); + shader_model_free(&default_shader); glDeleteBuffers(1, &global_matrices_ubo); glDeleteBuffers(1, &dof_common_ubo); glDeleteBuffers(1, &common_ubo); glDeleteBuffers(1, &tone_map_ubo); + glDeleteBuffers(1, &grid_vbo); + glDeleteVertexArrays(1, &grid_vao); glDeleteBuffers(1, &fb_vbo); glDeleteVertexArrays(1, &fb_vao); + + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + igDestroyContext(ig); } -static void render_micro_ui() { - mu_Command* cmd; - size_t count; - mat4 mat; - - mat = mat4_identity; - mat.row0.x = 2.0f / width; - mat.row1.y = -2.0f / height; - mat.row2.z = -1.0f; - mat.row3 = (vec4){ -1.0f, 1.0f, 0.0f, 1.0f }; - - shader_fbo_set_mat4(&mu_shader, "mat", false, &mat); - glEnablei(GL_BLEND, 0); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_SCISSOR_TEST); - glScissor(0, 0, width, height); - cmd = 0; - count = 0; - while (mu_next_command(muctx, &cmd)) { - count++; - switch (cmd->type) { - case MU_COMMAND_TEXT: - render_mui_draw_text(cmd->text.str, cmd->text.pos, cmd->text.color); - break; - case MU_COMMAND_RECT: - render_mui_draw_rect(cmd->rect.rect, cmd->rect.color); - break; - case MU_COMMAND_ICON: - render_mui_draw_icon(cmd->icon.id, cmd->icon.rect, cmd->icon.color); - break; - case MU_COMMAND_CLIP: - render_mui_set_clip_rect(cmd->clip.rect); - break; - case MU_COMMAND_TEX: - render_mui_draw_texture(); - break; - } - - if (!cmd->type) - break; - } - render_mui_flush(); - glScissor(0, 0, width, height); - glDisablei(GL_BLEND, 0); - glDisable(GL_SCISSOR_TEST); +static void render_imgui() { + ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData()); } -static void render_ui() { +static void render_2d(task_render_draw2d_type type) { size_t count = 0; for (task_render_draw2d* i = tasks_render_draw2d_int.begin; i != tasks_render_draw2d_int.end; i++) - if (i->type == TASK_RENDER_DRAW2D_UI) + if (i->type == type) count++; if (!count) return; glDisable(GL_DEPTH_TEST); + glDepthMask(false); glDisable(GL_CULL_FACE); for (task_render_draw2d* i = tasks_render_draw2d_int.begin; i != tasks_render_draw2d_int.end; i++) { - if (i->type != TASK_RENDER_DRAW2D_UI) + if (i->type != type) continue; - if (i->blend) { - glEnablei(GL_BLEND, 0); - glBlendFuncSeparate(i->blend_src_factor_rgb, i->blend_dst_factor_rgb, - i->blend_src_factor_alpha, i->blend_dst_factor_alpha); - glBlendEquationSeparate(i->blend_mode_rgb, i->blend_mode_alpha); - } - else - glDisable(GL_BLEND); } glDisable(GL_BLEND); } -static void render_front_2d() { - size_t count = 0; - for (task_render_draw2d* i = tasks_render_draw2d_int.begin; i != tasks_render_draw2d_int.end; i++) - if (i->type == TASK_RENDER_DRAW2D_FRONT) - count++; - - if (!count) - return; - - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - for (task_render_draw2d* i = tasks_render_draw2d_int.begin; i != tasks_render_draw2d_int.end; i++) { - if (i->type != TASK_RENDER_DRAW2D_FRONT) - continue; - - if (i->blend) { - glEnablei(GL_BLEND, 0); - glBlendFuncSeparate(i->blend_src_factor_rgb, i->blend_dst_factor_rgb, - i->blend_src_factor_alpha, i->blend_dst_factor_alpha); - glBlendEquationSeparate(i->blend_mode_rgb, i->blend_mode_alpha); - } - else - glDisable(GL_BLEND); - } - glDisable(GL_BLEND); -} - -static void render_c_front_3d() { +static void render_c_3d(task_render_draw3d_type type) { size_t count = 0; for (task_render_draw3d* i = tasks_render_draw3d_int.begin; i != tasks_render_draw3d_int.end; i++) - if (i->type == TASK_RENDER_DRAW3D_C_FRONT) + if (i->type == type && !i->translucent) count++; if (!count) return; - glDrawBuffers(2, fbo_render_c_attachments); + glDrawBuffers(1, fbo_render_c_attachments); glBindBufferBase(GL_UNIFORM_BUFFER, 0, global_matrices_ubo); for (task_render_draw3d* i = tasks_render_draw3d_int.begin; i != tasks_render_draw3d_int.end; i++) { - if (i->type != TASK_RENDER_DRAW3D_C_FRONT) + if (i->type != type || i->translucent) continue; - uint64_t hash = i->hash; + hash h = i->hash; for (hash_ptr_gl_object* j = vec_gl_obj.begin; j != vec_gl_obj.end; j++) - if (j->hash == hash) { - if (i->blend) { - glEnablei(GL_BLEND, 0); - glBlendFuncSeparate(i->blend_src_factor_rgb, i->blend_dst_factor_rgb, - i->blend_src_factor_alpha, i->blend_dst_factor_alpha); - glBlendEquationSeparate(i->blend_mode_rgb, i->blend_mode_alpha); - } - else - glDisable(GL_BLEND); + if (HASH_COMPARE(j->hash, h)) { + shader_model* shad = &j->data->shader; + for (task_render_uniform* k = i->uniforms.begin; k != i->uniforms.end; k++) + render_update_uniform_c(k, shad); - if (i->depth) { - glEnable(GL_DEPTH_TEST); - glDepthFunc(i->depth_func); - glDepthMask(i->depth_mask); - } - else - glDisable(GL_DEPTH_TEST); - - if (i->cull_face) { - glEnable(GL_CULL_FACE); - glCullFace(i->cull_face_mode); - } - else - glDisable(GL_CULL_FACE); + shader_model_c_set_mat4(shad, "model", GL_FALSE, &i->model); + shader_model_c_set_mat3(shad, "model_normal", GL_FALSE, &i->model_normal); + shader_model_c_set_mat4(shad, "uv_mat", GL_FALSE, &i->uv_mat); + shader_model_c_set_vec4(shad, "color", i->color.x, i->color.y, i->color.z, i->color.w); gl_object_draw_c(j->data); break; } } + bind_vertex_array(0); + shader_model_c_use(0); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDepthMask(false); glDisable(GL_CULL_FACE); } -static void render_g_front_3d() { +static void render_c_3d_translucent(task_render_draw3d_type type) { size_t count = 0; for (task_render_draw3d* i = tasks_render_draw3d_int.begin; i != tasks_render_draw3d_int.end; i++) - if (i->type != TASK_RENDER_DRAW3D_G_FRONT) + if (i->type == type && i->translucent) count++; if (!count) return; - glDrawBuffers(4, fbo_render_g_attachments); + vector_task_render_draw3d_append(&temp_draw3d_tasks, count); + vector_gl_object_append(&temp_draw3d_objects, count); + + for (task_render_draw3d* i = tasks_render_draw3d_int.begin; i != tasks_render_draw3d_int.end; i++) { + if (i->type != type || !i->translucent) + continue; + + hash h = i->hash; + for (hash_ptr_gl_object* j = vec_gl_obj.begin; j != vec_gl_obj.end; j++) + if (HASH_COMPARE(j->hash, h)) { + vector_task_render_draw3d_push_back(&temp_draw3d_tasks, i); + vector_gl_object_push_back(&temp_draw3d_objects, j->data); + break; + } + } + + ssize_t draw_count = temp_draw3d_tasks.end - temp_draw3d_tasks.begin; + if (draw_count < 1) { + vector_task_render_draw3d_clear(&temp_draw3d_tasks); + vector_gl_object_clear(&temp_draw3d_objects); + return; + } + + glDrawBuffers(1, fbo_render_c_attachments); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, global_matrices_ubo); + + glDisable(GL_BLEND); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glDepthMask(true); + + for (ssize_t i = 0; i < draw_count; i++) { + task_render_draw3d* task = &temp_draw3d_tasks.begin[i]; + gl_object* obj = &temp_draw3d_objects.begin[i]; + shader_model* shad = &obj->shader; + for (task_render_uniform* k = task->uniforms.begin; k != task->uniforms.end; k++) + render_update_uniform_c(k, shad); + + shader_model_c_set_mat4(shad, "model", GL_FALSE, &task->model); + shader_model_c_set_mat3(shad, "model_normal", GL_FALSE, &task->model_normal); + shader_model_c_set_mat4(shad, "uv_mat", GL_FALSE, &task->uv_mat); + shader_model_c_set_vec4(shad, "color", task->color.x, task->color.y, task->color.z, task->color.w); + gl_object_draw_c_translucent_first_part(obj); + } + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glEnablei(GL_BLEND, 0); + + for (ssize_t i = 0; i < draw_count; i++) { + task_render_draw3d* task = &temp_draw3d_tasks.begin[i]; + gl_object* obj = &temp_draw3d_objects.begin[i]; + shader_model* shad = &obj->shader; + for (task_render_uniform* k = task->uniforms.begin; k != task->uniforms.end; k++) + render_update_uniform_c(k, shad); + + shader_model_c_set_mat4(shad, "model", GL_FALSE, &task->model); + shader_model_c_set_mat3(shad, "model_normal", GL_FALSE, &task->model_normal); + shader_model_c_set_mat4(shad, "uv_mat", GL_FALSE, &task->uv_mat); + shader_model_c_set_vec4(shad, "color", task->color.x, task->color.y, task->color.z, task->color.w); + gl_object_draw_c_translucent_second_part(obj); + } + bind_vertex_array(0); + shader_model_c_use(0); + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + glDisable(GL_CULL_FACE); + + vector_task_render_draw3d_clear(&temp_draw3d_tasks); + vector_gl_object_clear(&temp_draw3d_objects); +} + +static void render_grid_3d() { + glDrawBuffers(1, fbo_render_c_attachments); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, global_matrices_ubo); + + glEnablei(GL_BLEND, 0); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(true); + + shader_fbo_use(&grid_shader); + bind_vertex_array(grid_vao); + glDrawArrays(GL_LINES, 0, grid_vertex_count); + shader_fbo_use(0); + + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + glDisable(GL_BLEND); +} + +static void render_g_3d(task_render_draw3d_type type) { + static const GLfloat color_clear[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + static const GLfloat specular_clear[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + static const GLfloat normal_clear[] = { 0.5f, 0.5f, 0.5f, 0.0f }; + + glDrawBuffers(3, fbo_render_g_attachments); + glClearBufferfv(GL_COLOR, 0, color_clear); + glClearBufferfv(GL_COLOR, 1, specular_clear); + glClearBufferfv(GL_COLOR, 2, normal_clear); + + size_t count = 0; + for (task_render_draw3d* i = tasks_render_draw3d_int.begin; i != tasks_render_draw3d_int.end; i++) + if (i->type == type) + count++; + + if (!count) + return; + + glDrawBuffers(3, fbo_render_g_attachments); glBindBufferBase(GL_UNIFORM_BUFFER, 0, global_matrices_ubo); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); @@ -1448,30 +2107,26 @@ static void render_g_front_3d() { glDisable(GL_BLEND); for (task_render_draw3d* i = tasks_render_draw3d_int.begin; i != tasks_render_draw3d_int.end; i++) { - if (i->type != TASK_RENDER_DRAW3D_G_FRONT) + if (i->type != type) continue; - uint64_t hash = i->hash; + hash h = i->hash; for (hash_ptr_gl_object* j = vec_gl_obj.begin; j != vec_gl_obj.end; j++) - if (j->hash == hash) { - if (i->depth) { - glEnable(GL_DEPTH_TEST); - glDepthFunc(i->depth_func); - glDepthMask(i->depth_mask); - } - else - glDisable(GL_DEPTH_TEST); + if (HASH_COMPARE(j->hash, h)) { + shader_model* shad = &j->data->shader; + for (task_render_uniform* k = i->uniforms.begin; k != i->uniforms.end; k++) + render_update_uniform_g(k, shad); - if (i->cull_face) { - glEnable(GL_CULL_FACE); - glCullFace(i->cull_face_mode); - } - else - glDisable(GL_CULL_FACE); + shader_model_g_set_mat4(shad, "model", GL_FALSE, &i->model); + shader_model_g_set_mat3(shad, "model_normal", GL_FALSE, &i->model_normal); + shader_model_g_set_mat4(shad, "uv_mat", GL_FALSE, &i->uv_mat); + shader_model_g_set_vec4(shad, "color", i->color.x, i->color.y, i->color.z, i->color.w); gl_object_draw_g(j->data); break; } } + bind_vertex_array(0); + shader_model_g_use(0); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDepthMask(false); @@ -1479,88 +2134,16 @@ static void render_g_front_3d() { glStencilFunc(GL_EQUAL, 0xFF, 0xFF); glStencilMask(0x00); - fbo_render_draw_g(rfbo, dir_lights.id, dir_lights_count, point_lights.id, point_lights_count); + fbo_render_draw_g(rfbo, + light_dir_tex.id, (int32_t)(vec_light_dir.end - vec_light_dir.begin), + light_point_tex.id, (int32_t)(vec_light_point.end - vec_light_point.begin)); glDisable(GL_STENCIL_TEST); } -static void render_back_3d() { - size_t count = 0; - for (task_render_draw3d* i = tasks_render_draw3d_int.begin; i != tasks_render_draw3d_int.end; i++) - if (i->type == TASK_RENDER_DRAW3D_BACK) - count++; - - if (!count) - return; - - glDrawBuffers(2, fbo_render_c_attachments); +void render_glitter_3d(int32_t alpha) { + glDrawBuffers(1, fbo_render_c_attachments); glBindBufferBase(GL_UNIFORM_BUFFER, 0, global_matrices_ubo); - - for (task_render_draw3d* i = tasks_render_draw3d_int.begin; i != tasks_render_draw3d_int.end; i++) { - if (i->type != TASK_RENDER_DRAW3D_BACK) - continue; - - uint64_t hash = i->hash; - for (hash_ptr_gl_object* j = vec_gl_obj.begin; j != vec_gl_obj.end; j++) - if (j->hash == hash) { - if (i->blend) { - glEnablei(GL_BLEND, 0); - glBlendFuncSeparate(i->blend_src_factor_rgb, i->blend_dst_factor_rgb, - i->blend_src_factor_alpha, i->blend_dst_factor_alpha); - glBlendEquationSeparate(i->blend_mode_rgb, i->blend_mode_alpha); - } - else - glDisable(GL_BLEND); - - if (i->depth) { - glEnable(GL_DEPTH_TEST); - glDepthFunc(i->depth_func); - glDepthMask(i->depth_mask); - } - else - glDisable(GL_DEPTH_TEST); - - if (i->cull_face) { - glEnable(GL_CULL_FACE); - glCullFace(i->cull_face_mode); - } - else - glDisable(GL_CULL_FACE); - gl_object_draw_c(j->data); - break; - } - } - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glDepthMask(false); - glDisable(GL_CULL_FACE); -} - -static void render_back_2d() { - size_t count = 0; - for (task_render_draw2d* i = tasks_render_draw2d_int.begin; i != tasks_render_draw2d_int.end; i++) - if (i->type == TASK_RENDER_DRAW2D_BACK) - count++; - - if (!count) - return; - - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - for (task_render_draw2d* i = tasks_render_draw2d_int.begin; i != tasks_render_draw2d_int.end; i++) { - if (i->type != TASK_RENDER_DRAW2D_BACK) - continue; - - if (i->blend) { - glEnablei(GL_BLEND, 0); - glBlendFuncSeparate(i->blend_src_factor_rgb, i->blend_dst_factor_rgb, - i->blend_src_factor_alpha, i->blend_dst_factor_alpha); - glBlendEquationSeparate(i->blend_mode_rgb, i->blend_mode_alpha); - } - else - glDisable(GL_BLEND); - } - glDisable(GL_BLEND); + glitter_particle_manager_draw(GPM_VAL, alpha); } void render_set_scale(double_t value) { @@ -1582,15 +2165,37 @@ void render_set_scale(double_t value) { } static void render_get_aspect_correct_res(vec2i* res) { - int32_t width = res->x; - int32_t height = res->y; - double_t viewAspect = (double_t)width / (double_t)height; - res->x = (int32_t)round(height * aspect); - res->y = (int32_t)round(width / aspect); - if (viewAspect < aspect) - res->x = (int32_t)round(res->y * aspect); - else if (viewAspect > aspect) - res->y = (int32_t)round(res->x / aspect); + double_t width = (double_t)res->x; + double_t height = (double_t)res->y; + double_t view_aspect = width / height; + width = round(height * aspect); + height = round(width / aspect); + if (view_aspect < aspect) + width = round(height * aspect); + else if (view_aspect > aspect) + height = round(width / aspect); + res->x = (int32_t)width; + res->y = (int32_t)height; +} + +static void render_drop_glfw(GLFWwindow* window, int count, char** paths) { + if (!count || !paths) + return; + + size_t c = count; + wchar_t** wpaths = force_malloc_s(wchar_t*, count); + for (size_t i = 0, j = 0; i < count; i++) + if (paths[i]) + wpaths[j++] = char_string_to_wchar_t_string(paths[i]); + else + c--; + if (c) { + classes_process_drop(classes, classes_count, c, wpaths); + glfwFocusWindow(window); + } + for (size_t i = 0; i < c; i++) + free(wpaths[i]); + free(wpaths); } static void render_resize_fb_glfw(GLFWwindow* window, int32_t w, int32_t h) { @@ -1604,14 +2209,14 @@ static void render_resize_fb(bool change_fb) { if (internal_3d_res.x < 20) internal_3d_res.x = 20; if (internal_3d_res.y < 20) internal_3d_res.y = 20; - internal_2d_res.x = (int32_t)round((double_t)width * scale); - internal_2d_res.y = (int32_t)round((double_t)height * scale); + internal_2d_res.x = (int32_t)roundf((float_t)width * scale); + internal_2d_res.y = (int32_t)roundf((float_t)height * scale); render_get_aspect_correct_res(&internal_2d_res); internal_2d_res.x = clamp(internal_2d_res.x, 1, sv_max_texture_size); internal_2d_res.y = clamp(internal_2d_res.y, 1, sv_max_texture_size); - internal_3d_res.x = (int32_t)round((double_t)internal_res.x * scale); - internal_3d_res.y = (int32_t)round((double_t)internal_res.y * scale); + internal_3d_res.x = (int32_t)roundf((float_t)internal_res.x * scale); + internal_3d_res.y = (int32_t)roundf((float_t)internal_res.y * scale); render_get_aspect_correct_res(&internal_3d_res); internal_3d_res.x = clamp(internal_3d_res.x, 1, sv_max_texture_size); internal_3d_res.y = clamp(internal_3d_res.y, 1, sv_max_texture_size); @@ -1649,220 +2254,351 @@ static void render_resize_fb(bool change_fb) { 1.0f / (float_t)internal_3d_res.x, 1.0f / (float_t)internal_3d_res.y, }; - glBindBuffer(GL_UNIFORM_BUFFER, common_ubo); + bind_uniform_buffer(common_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(float_t) * 4, data); - glBindBuffer(GL_UNIFORM_BUFFER, 0); + bind_uniform_buffer(0); - float_t aspect = (float_t)width / (float_t)height; + float_t aspect; + aspect = (float_t)width / (float_t)height; aspect /= (float_t)internal_3d_res.x / (float_t)internal_3d_res.y; - shader_fbo_set_vec2(&ffbs, "scale", - aspect > 1.0f ? 1.0f / aspect : 1.0f, aspect < 1.0f ? aspect : 1.0f); + if (aspect > 1.0f) + shader_fbo_set_vec2(&ffbs, "scale", 1.0f / aspect, 1.0f); + else if (aspect < 1.0f) + shader_fbo_set_vec2(&ffbs, "scale", 1.0f, aspect); + else + shader_fbo_set_vec2(&ffbs, "scale", 1.0f, 1.0f); } } -static void render_input_text_glfw(GLFWwindow* window, uint32_t codepoint) { - WaitForSingleObject(mu_input_lock, INFINITE); - if (codepoint >= 0x80 && codepoint < 0x10000) { - vector_wchar_t_append(&mu_input, 1); - mu_input.end++; - mu_input.end[-2] = (wchar_t)codepoint; - mu_input.end[-1] = 0; - } - else if (codepoint < 0x80) { - vector_wchar_t_append(&mu_input, 1); - mu_input.end++; - mu_input.end[-2] = (wchar_t)codepoint; - mu_input.end[-1] = 0; - vector_char_append(&mu_input_ansi, 1); - mu_input_ansi.end++; - mu_input_ansi.end[-2] = (char)codepoint; - mu_input_ansi.end[-1] = 0; - } - ReleaseMutex(mu_input_lock); -} +static void render_dof_get_texcoords(vec2* data, float_t a2) { + size_t i; + size_t j; + float_t v6; + float_t v7; + float_t v8; + float_t v9; + double_t v11; + float_t v12; -static void render_input_mouse_scroll_glfw(GLFWwindow* window, double_t xoffset, double_t yoffset) { - extern void input_mouse_add_scroll_x(double_t value); - extern void input_mouse_add_scroll_y(double_t value); - - WaitForSingleObject(mu_input_lock, INFINITE); - input_mouse_add_scroll_x(xoffset); - input_mouse_add_scroll_y(yoffset); - ReleaseMutex(mu_input_lock); -} - -static void render_dof_get_texcoords(float_t* a1, float_t a2) { - int32_t v2, v3, v4; - float_t v5, v6, v7, v8; - double_t v9; - - v4 = 0; - v8 = a2 * 3.0f; - for (v2 = 0; v2 < 7; v2++) { - v5 = v2 / 3.0f - 1.0f; - for (v3 = 0; v3 < 7; v3++) { - v6 = v3 / 3.0f - 1.0f; - if (-v5 >= v6) { - if (v5 > v6) { - v7 = 4.0f + v5 / v6; - v6 = -v6; + const float_t t = (float_t)(1.0 / 3.0); + v12 = a2 * 3.0f; + for (i = 0; i < 7; i++) { + v6 = (float_t)i * t - 1.0f; + for (j = 0; j < 7; j++) { + v7 = (float_t)j * t - 1.0f; + if (-v6 >= v7) { + if (v7 < v6) { + v8 = -v7; + v9 = (v6 / v7) + 4.0f; + } + else if (v6 == 0.0f) { + v8 = 0.0f; + v9 = 0.0f; } - else if (v5 == 0.0) { - v7 = 0.0f; - v6 = 0.0f; } else { - v7 = 6.0f - v6 / v5; v6 = -v5; + v8 = -v6; + v9 = 6.0f - (v7 / v6); } } + else if (v6 < v7) { + v8 = (float_t)j * t - 1.0f; + v9 = v6 / v7; + } else { - if (v5 < v6) { - v7 = v5 / v6; - v6 = v3 / 3.0f - 1.0f; - } - else { - v7 = 2.0f - v6 / v5; - v6 = v2 / 3.0f - 1.0f; - } + v8 = (float_t)i * t - 1.0f; + v9 = 2.0f - (v7 / v6); } - v9 = v7 * 0.25 * M_PI; - a1[v4++] = (float_t)(cos(v9) * v6 * v8); - a1[v4++] = (float_t)(sin(v9) * v6 * v8); + v8 *= v12; + v11 = (double_t)v9 * (M_PI * 0.25); + vec2_mult_scalar(((vec2) { (float_t)cos(v11), (float_t)sin(v11) }), v8, *data++); } } } -static void render_mui_flush() { - if (mu_buf_idx == 0) - return; - - glBindBuffer(GL_ARRAY_BUFFER, mu_vert_vbo); - glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat) * mu_buf_idx, mu_vert_buf, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, mu_uv_vbo); - glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat) * mu_buf_idx, mu_uv_buf, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, mu_color_vbo); - glBufferData(GL_ARRAY_BUFFER, 4 * 4 * sizeof(GLfloat) * mu_buf_idx, mu_color_buf, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, mu_depth_vbo); - glBufferData(GL_ARRAY_BUFFER, 1 * 4 * sizeof(GLfloat) * mu_buf_idx, mu_depth_buf, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - shader_fbo_use(&mu_shader); - texture_bind(&mu_font, 0); - glBindVertexArray(mu_vao); - glDrawElements(GL_TRIANGLES, (GLsizei)(mu_buf_idx * 6), GL_UNSIGNED_INT, mu_index_buf); - shader_fbo_use(0); - texture_reset(&mu_font, 0); - glBindVertexArray(0); - mu_buf_idx = 0; -} - -static void render_mui_push_quad(mu_Rect dst, mu_Rect src, mu_Color color) { - if (mu_buf_idx >= MU_BUFFER_SIZE) { - render_mui_flush(); - mu_buf_idx = 0; - } - - size_t uv_idx = mu_buf_idx * 8; - size_t vert_idx = mu_buf_idx * 8; - size_t color_idx = mu_buf_idx * 16; - size_t depth_idx = mu_buf_idx * 4; - size_t element_idx = mu_buf_idx * 4; - size_t index_idx = mu_buf_idx * 6; - mu_buf_idx++; - - GLfloat x = (GLfloat)src.x * (GLfloat)(1.0f / ATLAS_WIDTH); - GLfloat y = (GLfloat)src.y * (GLfloat)(1.0f / ATLAS_HEIGHT); - GLfloat w = (GLfloat)src.w * (GLfloat)(1.0f / ATLAS_WIDTH); - GLfloat h = (GLfloat)src.h * (GLfloat)(1.0f / ATLAS_HEIGHT); - mu_uv_buf[uv_idx + 0] = x; - mu_uv_buf[uv_idx + 1] = y; - mu_uv_buf[uv_idx + 2] = x + w; - mu_uv_buf[uv_idx + 3] = y; - mu_uv_buf[uv_idx + 4] = x; - mu_uv_buf[uv_idx + 5] = y + h; - mu_uv_buf[uv_idx + 6] = x + w; - mu_uv_buf[uv_idx + 7] = y + h; - - mu_vert_buf[vert_idx + 0] = (GLfloat)dst.x; - mu_vert_buf[vert_idx + 1] = (GLfloat)dst.y; - mu_vert_buf[vert_idx + 2] = (GLfloat)dst.x + dst.w; - mu_vert_buf[vert_idx + 3] = (GLfloat)dst.y; - mu_vert_buf[vert_idx + 4] = (GLfloat)dst.x; - mu_vert_buf[vert_idx + 5] = (GLfloat)dst.y + dst.h; - mu_vert_buf[vert_idx + 6] = (GLfloat)dst.x + dst.w; - mu_vert_buf[vert_idx + 7] = (GLfloat)dst.y + dst.h; - - mu_color_buf[color_idx + 0] = (GLfloat)color.r * (1.0f / 255.0f); - mu_color_buf[color_idx + 1] = (GLfloat)color.g * (1.0f / 255.0f); - mu_color_buf[color_idx + 2] = (GLfloat)color.b * (1.0f / 255.0f); - mu_color_buf[color_idx + 3] = (GLfloat)color.a * (1.0f / 255.0f); - memcpy(&mu_color_buf[color_idx + 4], &mu_color_buf[color_idx + 0], sizeof(GLfloat) * 4); - memcpy(&mu_color_buf[color_idx + 8], &mu_color_buf[color_idx + 0], sizeof(GLfloat) * 4); - memcpy(&mu_color_buf[color_idx + 12], &mu_color_buf[color_idx + 0], sizeof(GLfloat) * 4); - - mu_depth_buf[depth_idx + 0] = (GLfloat)(MU_BUFFER_SIZE - 1 - mu_buf_idx) * (1.0f / (MU_BUFFER_SIZE - 1)); - memcpy(&mu_depth_buf[depth_idx + 1], &mu_depth_buf[depth_idx + 0], sizeof(GLfloat)); - memcpy(&mu_depth_buf[depth_idx + 2], &mu_depth_buf[depth_idx + 0], sizeof(GLfloat)); - memcpy(&mu_depth_buf[depth_idx + 3], &mu_depth_buf[depth_idx + 0], sizeof(GLfloat)); - - mu_index_buf[index_idx + 0] = (GLuint)(element_idx + 0); - mu_index_buf[index_idx + 1] = (GLuint)(element_idx + 1); - mu_index_buf[index_idx + 2] = (GLuint)(element_idx + 2); - mu_index_buf[index_idx + 3] = (GLuint)(element_idx + 2); - mu_index_buf[index_idx + 4] = (GLuint)(element_idx + 3); - mu_index_buf[index_idx + 5] = (GLuint)(element_idx + 1); -} - -static inline void render_mui_draw_rect(mu_Rect rect, mu_Color color) { - render_mui_push_quad(rect, atlas[ATLAS_WHITE], color); -} - -static inline void render_mui_draw_text(const char* text, mu_Vec2 pos, mu_Color color) { - mu_Rect dst = { pos.x, pos.y, 0, 0 }; - for (const char* p = text; *p; p++) { - if ((*p & 0xc0) == 0x80) +static void render_imgui_context_menu(classes_struct* classes, const size_t classes_count) { + for (size_t i = 0; i < classes_count; i++) { + if (!classes[i].enabled || !classes[i].name || ~classes[i].flags & CLASSES_IN_CONTEXT_MENU) continue; - mu_Rect src = atlas[ATLAS_FONT + mu_min(*p, 127)]; - dst.w = src.w; - dst.h = src.h; - render_mui_push_quad(dst, src, color); - dst.x += dst.w; + if (classes[i].sub_classes && classes[i].sub_classes_count) { + if (igBeginMenu(classes[i].name, *classes[i].enabled)) { + render_imgui_context_menu(classes[i].sub_classes, classes[i].sub_classes_count); + igEndMenu(); + } + } + else if (*classes[i].enabled) + igMenuItem_Bool(classes[i].name, 0, false, false); + else if (igMenuItem_Bool(classes[i].name, 0, false, true)) + if (classes[i].init) + classes[i].init(); } } -static inline void render_mui_draw_icon(int id, mu_Rect rect, mu_Color color) { - mu_Rect src = atlas[id]; - int x = rect.x + (rect.w - src.w) / 2; - int y = rect.y + (rect.h - src.h) / 2; - render_mui_push_quad(mu_rect(x, y, src.w, src.h), src, color); -} +static bool render_glitter_mesh_add_list(glitter_particle_mesh* mesh, vec4* color, mat4* model, mat4* uv_mat) { + bool found = false; + hash h; + gl_object* obj; -static inline void render_mui_set_clip_rect(mu_Rect rect) { - render_mui_flush(); - if (rect.w == 0x1000000 || rect.h == 0x1000000) - glScissor(0, 0, width, height); + hash object_mesh_hash = (hash){ .f = mesh->object_name_hash, .m = (uint32_t)mesh->object_name_hash }; + for (hash_ptr_gl_object* i = vec_gl_obj.begin; i != vec_gl_obj.end; i++) + if (HASH_COMPARE(i->hash, object_mesh_hash)) { + found = true; + h = i->hash; + obj = i->data; + break; + } + + if (!found) { + if (!gpm->draw_all || !gpm->draw_all_mesh) + return false; + + found = false; + hash dummy_hash = hash_char("Glitter Editor Dummy"); + for (hash_ptr_gl_object* i = vec_gl_obj.begin; i != vec_gl_obj.end; i++) + if (HASH_COMPARE(i->hash, dummy_hash)) { + found = true; + h = i->hash; + obj = i->data; + break; + } + + if (!found) + return false; + + found = false; + } + + mat4 m; + mat4 temp; + mat3 mn; + if (found) + m = *model; else - glScissor(rect.x, height - (rect.y + rect.h), rect.w, rect.h); + mat4_scale_rot(model, 0.05f, 0.05f, 0.05f, &m); + mat4_invtrans(&m, &temp); + mat3_from_mat4(&temp, &mn); + + task_render_draw3d task_draw; + memset(&task_draw, 0, sizeof(task_draw)); + task_draw.hash = h; + task_draw.type = TASK_RENDER_DRAW3D_C_FRONT; + task_draw.translucent = color->w < 1.0f || obj->vertex.translucent || obj->material.translucent; + task_draw.model = m; + task_draw.model_normal = mn; + task_draw.uv_mat = *uv_mat; + task_draw.color = *color; + task_draw.uniforms = (vector_task_render_uniform){ 0, 0, 0 }; + vector_task_render_draw3d_push_back(&tasks_render_draw3d, &task_draw); + return true; } -static inline void render_mui_draw_texture() { -} - -static int render_mui_get_text_width(mu_Font font, const char* text, size_t len) { - if (!len) - len = strlen(text); - - int res = 0; - for (const char* p = text; *p && len--; p++) { - if ((*p & 0xc0) == 0x80) - continue; - - res += atlas[ATLAS_FONT + mu_min(*p, 127)].w; +static void render_update_uniform_c(task_render_uniform* uniform, shader_model* s) { + task_render_uniform uni = *uniform; + char* name = char_buffer_select(&uni.name); + switch (uni.type) { + case TASK_RENDER_UNIFORM_BOOL: { + task_render_uniform_bool uni_data = uni.boolean; + shader_model_c_set_bool(s, name, uni_data.value); + } break; + case TASK_RENDER_UNIFORM_INT32: { + task_render_uniform_int32 uni_data = uni.int32; + shader_model_c_set_int(s, name, uni_data.value); + } break; + case TASK_RENDER_UNIFORM_FLOAT32: { + task_render_uniform_float32 uni_data = uni.float32; + shader_model_c_set_float(s, name, uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC2: { + task_render_uniform_vec2 uni_data = uni.vec2; + shader_model_c_set_vec2(s, name, uni_data.value.x, uni_data.value.y); + } break; + case TASK_RENDER_UNIFORM_VEC2I: { + task_render_uniform_vec2i uni_data = uni.vec2i; + shader_model_c_set_vec2i(s, name, uni_data.value.x, uni_data.value.y); + } break; + case TASK_RENDER_UNIFORM_VEC3: { + task_render_uniform_vec3 uni_data = uni.vec3; + shader_model_c_set_vec3(s, name, uni_data.value.x, uni_data.value.y, uni_data.value.z); + } break; + case TASK_RENDER_UNIFORM_VEC3I: { + task_render_uniform_vec3i uni_data = uni.vec3i; + shader_model_c_set_vec3i(s, name, uni_data.value.x, uni_data.value.y, uni_data.value.z); + } break; + case TASK_RENDER_UNIFORM_VEC4: { + task_render_uniform_vec4 uni_data = uni.vec4; + shader_model_c_set_vec4(s, name, uni_data.value.x, + uni_data.value.y, uni_data.value.z, uni_data.value.w); + } break; + case TASK_RENDER_UNIFORM_VEC4I: { + task_render_uniform_vec4i uni_data = uni.vec4i; + shader_model_c_set_vec4i(s, name, uni_data.value.x, + uni_data.value.y, uni_data.value.z, uni_data.value.w); + } break; + case TASK_RENDER_UNIFORM_MAT3: { + task_render_uniform_mat3 uni_data = uni.mat3; + shader_model_c_set_mat3(s, name, uni_data.transpose, &uni_data.value); + } break; + case TASK_RENDER_UNIFORM_MAT4: { + task_render_uniform_mat4 uni_data = uni.mat4; + shader_model_c_set_mat4(s, name, uni_data.transpose, &uni_data.value); + } break; + case TASK_RENDER_UNIFORM_INT32_ARRAY: { + task_render_uniform_int32_array uni_data = uni.int32_array; + shader_model_c_set_int_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_FLOAT32_ARRAY: { + task_render_uniform_float32_array uni_data = uni.float32_array; + shader_model_c_set_float_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC2_ARRAY: { + task_render_uniform_vec2_array uni_data = uni.vec2_array; + shader_model_c_set_vec2_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC2I_ARRAY: { + task_render_uniform_vec2i_array uni_data = uni.vec2i_array; + shader_model_c_set_vec2i_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC3_ARRAY: { + task_render_uniform_vec3_array uni_data = uni.vec3_array; + shader_model_c_set_vec3_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC3I_ARRAY: { + task_render_uniform_vec3i_array uni_data = uni.vec3i_array; + shader_model_c_set_vec3i_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC4_ARRAY: { + task_render_uniform_vec4_array uni_data = uni.vec4_array; + shader_model_c_set_vec4_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC4I_ARRAY: { + task_render_uniform_vec4i_array uni_data = uni.vec4i_array; + shader_model_c_set_vec4i_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_MAT3_ARRAY: { + task_render_uniform_mat3_array uni_data = uni.mat3_array; + shader_model_c_set_mat3_array(s, name, (GLsizei)uni_data.count, + uni_data.transpose, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_MAT4_ARRAY: { + task_render_uniform_mat4_array uni_data = uni.mat4_array; + shader_model_c_set_mat4_array(s, name, (GLsizei)uni_data.count, + uni_data.transpose, uni_data.value); + free(uni_data.value); + } break; } - return res; } -static int render_mui_get_text_height(mu_Font font) { - return 18; +static void render_update_uniform_g(task_render_uniform* uniform, shader_model* s) { + task_render_uniform uni = *uniform; + char* name = char_buffer_select(&uni.name); + switch (uni.type) { + case TASK_RENDER_UNIFORM_BOOL: { + task_render_uniform_bool uni_data = uni.boolean; + shader_model_g_set_bool(s, name, uni_data.value); + } break; + case TASK_RENDER_UNIFORM_INT32: { + task_render_uniform_int32 uni_data = uni.int32; + shader_model_g_set_int(s, name, uni_data.value); + } break; + case TASK_RENDER_UNIFORM_FLOAT32: { + task_render_uniform_float32 uni_data = uni.float32; + shader_model_g_set_float(s, name, uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC2: { + task_render_uniform_vec2 uni_data = uni.vec2; + shader_model_g_set_vec2(s, name, uni_data.value.x, uni_data.value.y); + } break; + case TASK_RENDER_UNIFORM_VEC2I: { + task_render_uniform_vec2i uni_data = uni.vec2i; + shader_model_g_set_vec2i(s, name, uni_data.value.x, uni_data.value.y); + } break; + case TASK_RENDER_UNIFORM_VEC3: { + task_render_uniform_vec3 uni_data = uni.vec3; + shader_model_g_set_vec3(s, name, uni_data.value.x, uni_data.value.y, uni_data.value.z); + } break; + case TASK_RENDER_UNIFORM_VEC3I: { + task_render_uniform_vec3i uni_data = uni.vec3i; + shader_model_g_set_vec3i(s, name, uni_data.value.x, uni_data.value.y, uni_data.value.z); + } break; + case TASK_RENDER_UNIFORM_VEC4: { + task_render_uniform_vec4 uni_data = uni.vec4; + shader_model_g_set_vec4(s, name, uni_data.value.x, + uni_data.value.y, uni_data.value.z, uni_data.value.w); + } break; + case TASK_RENDER_UNIFORM_VEC4I: { + task_render_uniform_vec4i uni_data = uni.vec4i; + shader_model_g_set_vec4i(s, name, uni_data.value.x, + uni_data.value.y, uni_data.value.z, uni_data.value.w); + } break; + case TASK_RENDER_UNIFORM_MAT3: { + task_render_uniform_mat3 uni_data = uni.mat3; + shader_model_g_set_mat3(s, name, uni_data.transpose, &uni_data.value); + } break; + case TASK_RENDER_UNIFORM_MAT4: { + task_render_uniform_mat4 uni_data = uni.mat4; + shader_model_g_set_mat4(s, name, uni_data.transpose, &uni_data.value); + } break; + case TASK_RENDER_UNIFORM_INT32_ARRAY: { + task_render_uniform_int32_array uni_data = uni.int32_array; + shader_model_g_set_int_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_FLOAT32_ARRAY: { + task_render_uniform_float32_array uni_data = uni.float32_array; + shader_model_g_set_float_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC2_ARRAY: { + task_render_uniform_vec2_array uni_data = uni.vec2_array; + shader_model_g_set_vec2_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC2I_ARRAY: { + task_render_uniform_vec2i_array uni_data = uni.vec2i_array; + shader_model_g_set_vec2i_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC3_ARRAY: { + task_render_uniform_vec3_array uni_data = uni.vec3_array; + shader_model_g_set_vec3_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC3I_ARRAY: { + task_render_uniform_vec3i_array uni_data = uni.vec3i_array; + shader_model_g_set_vec3i_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC4_ARRAY: { + task_render_uniform_vec4_array uni_data = uni.vec4_array; + shader_model_g_set_vec4_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_VEC4I_ARRAY: { + task_render_uniform_vec4i_array uni_data = uni.vec4i_array; + shader_model_g_set_vec4i_array(s, name, (GLsizei)uni_data.count, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_MAT3_ARRAY: { + task_render_uniform_mat3_array uni_data = uni.mat3_array; + shader_model_g_set_mat3_array(s, name, (GLsizei)uni_data.count, + uni_data.transpose, uni_data.value); + free(uni_data.value); + } break; + case TASK_RENDER_UNIFORM_MAT4_ARRAY: { + task_render_uniform_mat4_array uni_data = uni.mat4_array; + shader_model_g_set_mat4_array(s, name, (GLsizei)uni_data.count, + uni_data.transpose, uni_data.value); + free(uni_data.value); + } break; + } } diff --git a/src/CLOUD/render.h b/src/CLOUD/render.h index bc97ee00..f09fed4f 100644 --- a/src/CLOUD/render.h +++ b/src/CLOUD/render.h @@ -8,19 +8,6 @@ #include "shared.h" #include "../KKdLib/vec.h" #include "../KKdLib/vector.h" -#include "../CRE/gl_object.h" -#include "../CRE/hash.h" -#include "../CRE/shader.h" -#include "../CRE/task.h" -#include "../CRE/texture.h" -#include "../CRE/vertex.h" - -typedef enum render_state { - RENDER_CLOSED = -1, - RENDER_UNINITIALIZED = 0, - RENDER_INITIALIZING = 1, - RENDER_INITIALIZED = 2, -} render_state; typedef struct render_init_struct { vec2i res; @@ -28,19 +15,5 @@ typedef struct render_init_struct { float_t scale; } render_init_struct; -hash_ptr(gl_object) -hash(shader_model) -hash(texture) -hash(texture_set) -hash_ptr(vertex) - -extern shader_fbo particle_shader; - -vector(hash_ptr_gl_object) -vector(hash_shader_model) -vector(hash_texture) -vector(hash_texture_set) -vector(hash_ptr_vertex) - extern int32_t render_main(void* arg); extern void render_set_scale(double_t value); diff --git a/src/CLOUD/shared.c b/src/CLOUD/shared.c index eda91661..2e630ce2 100644 --- a/src/CLOUD/shared.c +++ b/src/CLOUD/shared.c @@ -5,58 +5,61 @@ #include "shared.h" -mu_Context* muctx; - -const classes_struct classes[] = { +classes_struct classes[] = { +#ifndef CLOUD_DEV { - .name = "BACKGROUND COLOR", + .name = "Data Test", .flags = CLASSES_IN_CONTEXT_MENU, - .enabled = &background_color.enabled, - .dispose = (void*)background_color_dispose, - .init = (void*)background_color_init, - .control = (void*)background_color_control, - .input = (void*)background_color_input, - .mui = (void*)background_color_mui, - .render = (void*)background_color_render, - .sound = (void*)background_color_sound, + .enabled = &data_test_enabled, + .dispose = (void*)0, + .init = (void*)0, + .control = (void*)0, + .drop = (void*)0, + .imgui = (void*)0, + .input = (void*)0, + .render = (void*)0, + .sound = (void*)0, + .lock = 0, + .sub_classes = data_test_classes, + .sub_classes_count = 1, }, - /*{ - .name = "GLITTER TEST", - //.flags = CLASSES_INIT_AT_STARTUP | CLASSES_IN_CONTEXT_MENU, - .flags = 0, - .enabled = &glitter_test.enabled, - .dispose = (void*)glitter_test_dispose, - .init = (void*)glitter_test_init, - .control = (void*)glitter_test_control, - .input = (void*)glitter_test_input, - .mui = (void*)glitter_test_mui, - .render = (void*)glitter_test_render, - .sound = (void*)glitter_test_sound, - },*/ +#endif { - .name = "POST PROCESS", + .name = "Graphics", .flags = CLASSES_IN_CONTEXT_MENU, - .enabled = &post_process.enabled, - .dispose = (void*)post_process_dispose, - .init = (void*)post_process_init, - .control = (void*)post_process_control, - .input = (void*)post_process_input, - .mui = (void*)post_process_mui, - .render = (void*)post_process_render, - .sound = (void*)post_process_sound, + .enabled = &graphics_enabled, + .dispose = (void*)0, + .init = (void*)0, + .control = (void*)0, + .drop = (void*)0, + .imgui = (void*)0, + .input = (void*)0, + .render = (void*)0, + .sound = (void*)0, + .lock = 0, + .sub_classes = graphics_classes, + .sub_classes_count = 3, }, +#ifdef CLOUD_DEV { - .name = "GLITTER EDITOR", + .name = "Glitter Editor", .flags = CLASSES_INIT_AT_STARTUP, - .enabled = &glitter_editor.enabled, + .enabled = &glitter_editor_enabled, .dispose = (void*)glitter_editor_dispose, .init = (void*)glitter_editor_init, - .control = (void*)glitter_editor_control, + .control = (void*)0, + .drop = (void*)glitter_editor_drop, + .imgui = (void*)glitter_editor_imgui, .input = (void*)glitter_editor_input, - .mui = (void*)glitter_editor_mui, .render = (void*)glitter_editor_render, - .sound = (void*)glitter_editor_sound, + .sound = (void*)0, + .lock = 0, + .sub_classes = 0, + .sub_classes_count = 0, }, +#endif }; const size_t classes_count = sizeof(classes) / sizeof(classes_struct); + +render_state state; diff --git a/src/CLOUD/shared.h b/src/CLOUD/shared.h index 478b67b7..717d02ab 100644 --- a/src/CLOUD/shared.h +++ b/src/CLOUD/shared.h @@ -5,32 +5,21 @@ #pragma once -#include "../KKdLib/default.h" -#include "../CRE/microui.h" -#include "Classes/background_color.h" -#include "Classes/glitter_editor.h" -#include "Classes/glitter_test.h" -#include "Classes/post_process.h" +#include "classes.h" +#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS +#include +#include "classes/data_test.h" +#include "classes/glitter_editor.h" +#include "classes/graphics.h" -typedef enum classes_enum { - CLASSES_INIT_AT_STARTUP = 0x01, - CLASSES_IN_CONTEXT_MENU = 0x02, -} classes_enum; +typedef enum render_state { + RENDER_UNINITIALIZED = 0, + RENDER_INITIALIZING = 1, + RENDER_INITIALIZED = 2, + RENDER_DISPOSING = 3, + RENDER_DISPOSED = 4, +} render_state; -typedef struct classes_struct { - char* name; - classes_enum flags; - bool* enabled; - void(FASTCALL* dispose)(); - void(FASTCALL* init)(); - void(FASTCALL* control)(); - void(FASTCALL* input)(); - void(FASTCALL* mui)(); - void(FASTCALL* render)(); - void(FASTCALL* sound)(); -} classes_struct; - -extern mu_Context* muctx; - -extern const classes_struct classes[]; +extern classes_struct classes[]; extern const size_t classes_count; +extern render_state state; diff --git a/src/CLOUD/sound.c b/src/CLOUD/sound.c index 9d8c5b6f..88073fa2 100644 --- a/src/CLOUD/sound.c +++ b/src/CLOUD/sound.c @@ -13,11 +13,12 @@ timer_val(sound); int32_t sound_main(void* arg) { timer_init(sound, "Sound"); + while (state != RENDER_INITIALIZED) + msleep(sound_timer, 0.0625); + while (!close) { timer_calc_pre(sound); - for (size_t i = 0; i < classes_count; i++) - if (classes[i].sound) - classes[i].sound(); + classes_process_sound(classes, classes_count); double_t cycle_time = timer_calc_post(sound); msleep(sound_timer, 1000.0 / FREQ - cycle_time); } diff --git a/src/CRE/Glitter/animation.c b/src/CRE/Glitter/animation.c index 5333ef9c..eb135f21 100644 --- a/src/CRE/Glitter/animation.c +++ b/src/CRE/Glitter/animation.c @@ -6,34 +6,107 @@ #include "animation.h" #include "curve.h" -void FASTCALL glitter_animation_parse_file(f2_struct* st, vector_ptr_glitter_curve* vec) { - if (!st || !st->header.data_size) +void FASTCALL glitter_animation_copy(GPM, + vector_ptr_glitter_curve* src, vector_ptr_glitter_curve* dst) { + if (!dst) return; + vector_ptr_glitter_curve_free(dst, glitter_curve_dispose); + + if (!src) + return; + + vector_ptr_glitter_curve_append(dst, src->end - src->begin); + for (glitter_curve** i = src->begin; i != src->end; i++) + if (*i) { + glitter_curve* c = glitter_curve_copy(GPM_VAL, *i); + if (c) + vector_ptr_glitter_curve_push_back(dst, &c); + } +} + +bool FASTCALL glitter_animation_parse_file(GPM, f2_struct* st, + vector_ptr_glitter_curve* vec, glitter_curve_type_flags flags) { + glitter_curve* c; + + if (!st || !st->header.data_size) + return false; + for (f2_struct* i = st->sub_structs.begin; i != st->sub_structs.end; i++) { if (!i->header.data_size) continue; - if (i->header.signature == 0x56525543) - glitter_curve_parse_file(i, vec); + if (i->header.signature == reverse_endianess_uint32_t('CURV') + && glitter_curve_parse_file(GPM_VAL, i, st->header.version, &c)) + if (flags & 1 << (size_t)(int32_t)c->type) + vector_ptr_glitter_curve_push_back(vec, &c); + else + glitter_curve_dispose(c); } + return true; } -bool FASTCALL glitter_animation_unparse_file(f2_struct* st, vector_ptr_glitter_curve* vec, bool use_big_endian) { +bool FASTCALL glitter_animation_unparse_file(GPM, f2_struct* st, + vector_ptr_glitter_curve* vec, glitter_curve_type_flags flags) { memset(st, 0, sizeof(f2_struct)); if (vec->end - vec->begin <= 0) return false; - f2_struct* s = f2_struct_init(); - for (glitter_curve** i = vec->begin; i != vec->end; i++) - if (*i) { - glitter_curve_unparse_file(s, *i, use_big_endian); - vector_f2_struct_push_back(&st->sub_structs, s); - } - free(s); + static const glitter_curve_type order[] = { + GLITTER_CURVE_COLOR_A, + GLITTER_CURVE_COLOR_R, + GLITTER_CURVE_COLOR_G, + GLITTER_CURVE_COLOR_B, + GLITTER_CURVE_COLOR_RGB_SCALE, + GLITTER_CURVE_COLOR_A_2ND, + GLITTER_CURVE_COLOR_R_2ND, + GLITTER_CURVE_COLOR_G_2ND, + GLITTER_CURVE_COLOR_B_2ND, + GLITTER_CURVE_COLOR_RGB_SCALE_2ND, + GLITTER_CURVE_TRANSLATION_X, + GLITTER_CURVE_TRANSLATION_Y, + GLITTER_CURVE_TRANSLATION_Z, + GLITTER_CURVE_ROTATION_X, + GLITTER_CURVE_ROTATION_Y, + GLITTER_CURVE_ROTATION_Z, + GLITTER_CURVE_SCALE_X, + GLITTER_CURVE_SCALE_Y, + GLITTER_CURVE_SCALE_Z, + GLITTER_CURVE_SCALE_ALL, + GLITTER_CURVE_EMISSION_INTERVAL, + GLITTER_CURVE_PARTICLES_PER_EMISSION, + GLITTER_CURVE_U_SCROLL, + GLITTER_CURVE_V_SCROLL, + GLITTER_CURVE_U_SCROLL_ALPHA, + GLITTER_CURVE_V_SCROLL_ALPHA, + GLITTER_CURVE_U_SCROLL_2ND, + GLITTER_CURVE_V_SCROLL_2ND, + GLITTER_CURVE_U_SCROLL_ALPHA_2ND, + GLITTER_CURVE_V_SCROLL_ALPHA_2ND, + }; - st->header.signature = 0x4D494E41; + for (int32_t i = GLITTER_CURVE_TRANSLATION_X; i <= GLITTER_CURVE_V_SCROLL_ALPHA_2ND; i++) { + if (!(flags & 1 << (size_t)order[i])) + continue; + + for (glitter_curve** j = vec->begin; j != vec->end; j++) { + glitter_curve* c = *j; + if (!c || c->type != order[i]) + continue; + + f2_struct s; + if (glitter_curve_unparse_file(GPM_VAL, &s, c)) { + vector_f2_struct_push_back(&st->sub_structs, &s); + break; + } + } + } + + if (st->sub_structs.end - st->sub_structs.begin < 1) + return false; + + st->header.signature = reverse_endianess_uint32_t('ANIM'); st->header.length = 0x20; st->header.use_big_endian = false; st->header.use_section_size = true; diff --git a/src/CRE/Glitter/animation.h b/src/CRE/Glitter/animation.h index 03ac31bc..daf08f94 100644 --- a/src/CRE/Glitter/animation.h +++ b/src/CRE/Glitter/animation.h @@ -7,5 +7,9 @@ #include "glitter.h" -extern void FASTCALL glitter_animation_parse_file(f2_struct* st, vector_ptr_glitter_curve* vec); -extern bool FASTCALL glitter_animation_unparse_file(f2_struct* st, vector_ptr_glitter_curve* vec, bool use_big_endian); +extern void FASTCALL glitter_animation_copy(GPM, + vector_ptr_glitter_curve* src, vector_ptr_glitter_curve* dst); +extern bool FASTCALL glitter_animation_parse_file(GPM, f2_struct* st, + vector_ptr_glitter_curve* vec, glitter_curve_type_flags flags); +extern bool FASTCALL glitter_animation_unparse_file(GPM, f2_struct* st, + vector_ptr_glitter_curve* vec, glitter_curve_type_flags flags); diff --git a/src/CRE/Glitter/counter.c b/src/CRE/Glitter/counter.c index 7a5d66aa..b0081d30 100644 --- a/src/CRE/Glitter/counter.c +++ b/src/CRE/Glitter/counter.c @@ -5,18 +5,6 @@ #include "counter.h" -extern glitter_particle_manager* gpm; - -int32_t FASTCALL glitter_counter_get() { - if (gpm->f2) - return gpm->counter & 0xFF; - else - return gpm->counter & 0xFFF; -} - -void FASTCALL glitter_counter_increment() { - if (gpm->f2) - gpm->counter++; - else - gpm->counter++; +int32_t FASTCALL glitter_counter_get(GPM) { + return ++gpm->counter; } diff --git a/src/CRE/Glitter/counter.h b/src/CRE/Glitter/counter.h index b20392c4..3449ddd0 100644 --- a/src/CRE/Glitter/counter.h +++ b/src/CRE/Glitter/counter.h @@ -7,5 +7,4 @@ #include "glitter.h" -extern int32_t FASTCALL glitter_counter_get(); -extern void FASTCALL glitter_counter_increment(); +extern int32_t FASTCALL glitter_counter_get(GPM); diff --git a/src/CRE/Glitter/curve.c b/src/CRE/Glitter/curve.c index 2e50b860..d64f12a8 100644 --- a/src/CRE/Glitter/curve.c +++ b/src/CRE/Glitter/curve.c @@ -5,230 +5,327 @@ #include "curve.h" #include "random.h" -#include "../../KKdLib/io_stream.h" +#include "../../KKdLib/interpolation.h" -extern glitter_particle_manager* gpm; +static const float_t glitter_curve_baked_reverse_bias[] = { + 0.00001f, + 0.0001f, + 0.001f, +}; -static float_t FASTCALL glitter_curve_apply_max_rand(glitter_curve* c, float_t value); -static void FASTCALL glitter_curve_get_key_indexes(vector_glitter_curve_key* keys, - float_t frame, size_t* curr, size_t* next); -static float_t FASTCALL glitter_curve_interpolate(glitter_curve* c, float_t frame, - glitter_curve_key* curr, glitter_curve_key* next, glitter_key_type type); -static void FASTCALL glitter_curve_key_pack_file(f2_struct* st, glitter_curve* c, bool use_big_endian); -static void FASTCALL glitter_curve_key_unpack_file(f2_struct* st, glitter_curve* c, uint32_t count); -static void FASTCALL glitter_curve_pack_file(f2_struct* st, - glitter_curve* c, bool use_big_endian, size_t keys_count); -static float_t FASTCALL glitter_curve_randomize(glitter_curve* c, glitter_curve_key* key); -static void FASTCALL glitter_curve_unpack_file(uint32_t* data, - glitter_curve* c, bool use_big_endian, uint32_t* keys_count); +static const float_t glitter_curve_baked_half_reverse_bias[] = { + 0.000001f, + 0.00001f, + 0.0001f, +}; -glitter_curve* FASTCALL glitter_curve_init() { +#ifdef CRE_DEV +static float_t FASTCALL glitter_curve_key_add_key(GPM, bool has_error, + bool has_error_lerp, bool has_error_hermite, float_t* a, float_t* b, int32_t frame, + const uint8_t step, size_t i, float_t t1, float_t t2, float_t t2_old, + vector_glitter_curve_key* keys_rev); +#endif +static void FASTCALL glitter_curve_key_pack_file(GPM, f2_struct* st, + glitter_curve* c, vector_glitter_curve_key* keys); +static void FASTCALL glitter_curve_key_unpack_file(GPM, f2_struct* st, glitter_curve* c, uint32_t count); +static void FASTCALL glitter_curve_pack_file(GPM, f2_struct* st, glitter_curve* c, size_t keys_count); +static void FASTCALL glitter_curve_unpack_file(GPM, void* data, + glitter_curve* c, uint32_t version, bool use_big_endian, uint32_t* keys_count); + +glitter_curve* FASTCALL glitter_curve_init(GPM) { glitter_curve* c = force_malloc(sizeof(glitter_curve)); - vector_glitter_curve_key_resize(&c->keys, 0x80); + c->version = glt_type == GLITTER_X ? 0x02 : 0x01; + c->keys_version = glt_type == GLITTER_X ? 0x03 : 0x02; return c; } -void FASTCALL glitter_curve_parse_file(f2_struct* st, vector_ptr_glitter_curve* vec) { +glitter_curve* FASTCALL glitter_curve_copy(GPM, glitter_curve* c) { + if (!c) + return 0; + + glitter_curve* cc = force_malloc(sizeof(glitter_curve)); + *cc = *c; + + cc->keys = (vector_glitter_curve_key){ 0, 0, 0 }; + vector_glitter_curve_key_append(&cc->keys, c->keys.end - c->keys.begin); + vector_glitter_curve_key_insert_range(&cc->keys, 0, c->keys.begin, c->keys.end); +#ifdef CRE_DEV + cc->keys_rev = (vector_glitter_curve_key){ 0, 0, 0 }; + vector_glitter_curve_key_append(&cc->keys_rev, c->keys_rev.end - c->keys_rev.begin); + vector_glitter_curve_key_insert_range(&cc->keys_rev, 0, c->keys_rev.begin, c->keys_rev.end); +#endif + return cc; +} + +bool FASTCALL glitter_curve_parse_file(GPM, f2_struct* st, uint32_t version, glitter_curve** c) { f2_struct* i; - glitter_curve* c; uint32_t keys_count; if (!st || !st->header.data_size) - return; + return false; - c = glitter_curve_init(); - c->version = st->header.version; - glitter_curve_unpack_file(st->data, c, st->header.use_big_endian, &keys_count); + *c = glitter_curve_init(GPM_VAL); + (*c)->version = st->header.version; + glitter_curve_unpack_file(GPM_VAL, st->data, *c, version, st->header.use_big_endian, &keys_count); if (keys_count) for (i = st->sub_structs.begin; i != st->sub_structs.end; i++) { if (!i->header.data_size) continue; - if (i->header.signature == 0x5359454B) { - glitter_curve_key_unpack_file(i, c, keys_count); + if (i->header.signature == reverse_endianess_uint32_t('KEYS')) { + glitter_curve_key_unpack_file(GPM_VAL, i, *c, keys_count); break; } } - vector_ptr_glitter_curve_push_back(vec, &c); + return true; } -void FASTCALL glitter_curve_unparse_file(f2_struct* st, glitter_curve* c, bool use_big_endian) { - glitter_curve_pack_file(st, c, use_big_endian, c->keys.end - c->keys.begin); +#ifdef CRE_DEV +void FASTCALL glitter_curve_recalculate(GPM, + glitter_curve* curve, vector_glitter_curve_key* dest) { + int32_t start_time = curve->start_time; + int32_t end_time = curve->end_time; + bool curve_baked = curve->flags & GLITTER_CURVE_BAKED ? true : false; - f2_struct* s = f2_struct_init(); - glitter_curve_key_pack_file(s, c, use_big_endian); - vector_f2_struct_push_back(&st->sub_structs, s); - free(s); + vector_glitter_curve_key keys = curve->keys_rev; + vector_glitter_curve_key_clear(dest); + if (keys.end - keys.begin == 1) + vector_glitter_curve_key_push_back(dest, &keys.begin[0]); + else if (keys.end - keys.begin > 1) { + if (!curve_baked) { + vector_glitter_curve_key_insert_range(dest, 0, keys.begin, keys.end); + return; + } + + bool curve_baked_half = false; + if (curve_baked && (glt_type == GLITTER_F2 + || (glt_type == GLITTER_X && ~curve->flags & GLITTER_CURVE_BAKED_FULL))) + curve_baked_half = true; + + ssize_t keys_count = keys.end - keys.begin; + size_t count = (size_t)end_time - start_time; + if (curve_baked_half) + count /= 2; + count++; + + const uint8_t step = curve_baked_half ? 2 : 1; + + glitter_curve_key first_key = keys.begin[0]; + glitter_curve_key last_key = keys.begin[keys_count - 1]; + + glitter_curve_key key; + memset(&key, 0, sizeof(glitter_curve_key)); + for (size_t i = 0; i < count; i++) { + int32_t frame = start_time + (int32_t)(i * step); + + if (frame <= first_key.frame) { + key.type = GLITTER_KEY_CONSTANT; + key.frame = frame; + key.value = first_key.value; + key.random_range = first_key.random_range; + vector_glitter_curve_key_push_back(dest, &key); + continue; + } + else if (frame >= last_key.frame) { + key.type = GLITTER_KEY_CONSTANT; + key.frame = frame; + key.value = last_key.value; + key.random_range = last_key.random_range; + vector_glitter_curve_key_push_back(dest, &key); + continue; + } + + size_t key_idx = 0; + size_t length = keys_count; + size_t temp; + while (length > 0) + if (frame > keys.begin[key_idx + (temp = length >> 1)].frame) { + key_idx += temp + 1; + length -= temp + 1; + } + else + length = temp; + + glitter_curve_key* curr_key = &keys.begin[key_idx - 1]; + glitter_curve_key* next_key = &keys.begin[key_idx]; + + float_t val; + float_t rand_range; + if (curr_key->type == GLITTER_KEY_CONSTANT) { + val = curr_key->value; + rand_range = curr_key->random_range; + } + else if (curr_key->type == GLITTER_KEY_HERMITE) { + val = interpolate_chs_value(curr_key->value, next_key->value, + curr_key->tangent2, next_key->tangent1, + (float_t)curr_key->frame, (float_t)next_key->frame, (float_t)frame); + rand_range = interpolate_chs_value(curr_key->random_range, next_key->random_range, + 0.0f, 0.0f, + (float_t)curr_key->frame, (float_t)next_key->frame, (float_t)frame); + float_t val1 = interpolate_chs_value(curr_key->value + curr_key->random_range, next_key->value + next_key->random_range, + curr_key->tangent2, next_key->tangent1, + (float_t)curr_key->frame, (float_t)next_key->frame, (float_t)frame); + } + else { + val = interpolate_linear_value(curr_key->value, next_key->value, + (float_t)curr_key->frame, (float_t)next_key->frame, (float_t)frame); + rand_range = interpolate_linear_value(curr_key->random_range, next_key->random_range, + (float_t)curr_key->frame, (float_t)next_key->frame, (float_t)frame); + } + + key.type = GLITTER_KEY_CONSTANT; + key.frame = frame; + key.value = val; + key.random_range = rand_range; + vector_glitter_curve_key_push_back(dest, &key); + } + } +} +#endif + +bool FASTCALL glitter_curve_unparse_file(GPM, f2_struct* st, glitter_curve* c) { +#ifndef CRE_DEV + vector_glitter_curve_key keys = c->keys; + if (keys.end - keys.begin < 1) + return false; +#else + vector_glitter_curve_key keys = { 0, 0, 0 }; + if (c->keys_rev.end - c->keys_rev.begin < 1) + return false; + + glitter_curve_recalculate(GPM_VAL, c, &keys); + if (!keys.begin) + return false; +#endif + glitter_curve_pack_file(GPM_VAL, st, c, keys.end - keys.begin); + + f2_struct s; + glitter_curve_key_pack_file(GPM_VAL, &s, c, &keys); + vector_f2_struct_push_back(&st->sub_structs, &s); +#ifdef CRE_DEV + vector_glitter_curve_key_free(&keys); +#endif + return true; } void FASTCALL glitter_curve_dispose(glitter_curve* c) { vector_glitter_curve_key_free(&c->keys); +#ifdef CRE_DEV + vector_glitter_curve_key_free(&c->keys_rev); +#endif free(c); } -static float_t FASTCALL glitter_curve_apply_max_rand(glitter_curve* c, float_t value) { - float_t max_rand; - - if (c->flags & GLITTER_CURVE_FLAG_RANDOMIZE) { - max_rand = c->max_rand; - max_rand = glitter_random_get_float_clamp(c->flags & GLITTER_CURVE_FLAG_NEGATIVE_RANDOM - ? -max_rand : 0.0f, max_rand); - - if (c->flags & GLITTER_CURVE_FLAG_MULT) - max_rand *= value; - return max_rand + value; - } - else - return value; -} - -static void FASTCALL glitter_curve_get_key_indexes(vector_glitter_curve_key* keys, float_t frame, size_t* curr, size_t* next) { - size_t v4; - glitter_curve_key* v6; +static void FASTCALL glitter_curve_key_pack_file(GPM, f2_struct* st, + glitter_curve* c, vector_glitter_curve_key* keys) { + size_t l; + size_t d; + glitter_key_type key_type; size_t count; - size_t v9; - size_t v10; - count = keys->end - keys->begin; - if (count <= 1) { - *curr = 0; - *next = 0; + memset(st, 0, sizeof(f2_struct)); + l = 0; + + uint32_t o; + vector_enrs_entry e = { 0, 0, 0 }; + enrs_entry ee; + + if (keys->begin == keys->end) { + st->header.signature = reverse_endianess_uint32_t('KEYS'); + st->header.length = 0x20; + st->header.use_big_endian = false; + st->header.use_section_size = true; + st->header.version = c->keys_version; return; } - v4 = 0; - v6 = keys->begin; - v9 = count - 1; - v10 = v9 / 2; - while (v4 <= v9) { - v10 = (v9 + v4) / 2; - if (frame <= v6[(v10 + 1) % count].frame) { - if (frame >= v6[v10].frame) - goto LABEL_12; - v9 = v10 - 1; - } - else - v4 = v10 + 1; - } - - if (frame > v6[v10].frame) { - LABEL_12: - *curr = v10; - *next = v10 + 1; - } - else { - *curr = v10 - 1; - *next = v10; - } - *next %= count; -} - -bool FASTCALL glitter_curve_get_value(glitter_curve* c, float_t frame, float_t* value, int32_t random) { - size_t keys_count; - int32_t _random; - bool negate; - float_t _value; - float_t t; - size_t key; - glitter_curve_key* curr_key; - glitter_curve_key* next_key; - size_t next_key_index; - size_t curr_key_index; - - keys_count = c->keys.end - c->keys.begin; - if (!keys_count) - return false; - - _random = glitter_random_get(); - glitter_random_set(random); - negate = c->flags & GLITTER_CURVE_FLAG_NEGATE && glitter_random_get_int_clamp(0, 0xFFFF) > 0x7FFF; - if (c->flags & GLITTER_CURVE_FLAG_STEP) - glitter_random_set(_random + 1); - - if (keys_count == 1) { - _value = glitter_curve_randomize(c, c->keys.begin); - _value = glitter_curve_apply_max_rand(c, _value); - *value = negate ? -_value : _value; - glitter_random_set(_random + 1); - return true; - } - - if (c->repeat && (c->start_time > frame || frame >= c->end_time)) { - t = (frame - c->start_time) / (c->end_time - c->start_time); - t = t <= 0.0f ? (float_t)(int32_t)t - 1.0f : (float_t)(int32_t)t; - frame -= t * (c->end_time - c->start_time); - } - - if (c->end_time <= frame) - _value = glitter_curve_randomize(c, &c->keys.begin[keys_count - 1]); - else if (c->start_time > frame) - _value = glitter_curve_randomize(c, c->keys.begin); - else if (c->flags & GLITTER_CURVE_FLAG_PLAIN) { - key = 0; - if (frame >= c->end_time) - key = keys_count - 1; - else if (frame > c->start_time) { - key = (size_t)((double_t)frame - c->start_time); - if (gpm->f2) - key /= 2; - - if (key >= keys_count) - key = keys_count - 1; - } - _value = glitter_curve_randomize(c, &c->keys.begin[key]); - } - else { - if (keys_count > 3) - glitter_curve_get_key_indexes(&c->keys, frame, &curr_key_index, &next_key_index); - else if (keys_count == 3 && frame >= c->keys.begin[1].frame) { - curr_key_index = 1; - next_key_index = 2; + if (c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) { + key_type = keys->begin->type; + if (key_type == GLITTER_KEY_HERMITE) { + ee = (enrs_entry){ 0, 2, 20, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 4, ENRS_TYPE_DWORD }); + l = 20; } else { - curr_key_index = 0; - next_key_index = 1; + ee = (enrs_entry){ 0, 2, 12, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_DWORD }); + l = 12; } - curr_key = &c->keys.begin[curr_key_index]; - next_key = &c->keys.begin[next_key_index]; - _value = glitter_curve_interpolate(c, frame, curr_key, next_key, curr_key->type); - } - _value = glitter_curve_apply_max_rand(c, _value); - *value = negate ? -_value : _value; - glitter_random_set(_random + 1); - return true; -} -static float_t FASTCALL glitter_curve_interpolate(glitter_curve* c, float_t frame, - glitter_curve_key* curr, glitter_curve_key* next, glitter_key_type type) { - float_t df; - float_t next_val; - float_t curr_val; - float_t t; - float_t v15; - float_t t_2; + count = 1; + for (glitter_curve_key* i = keys->begin + 1; i != keys->end; + i++, count++, l += key_type == GLITTER_KEY_HERMITE ? 20 : 12) { + if (i->type == key_type) + continue; - if (type == GLITTER_KEY_CONSTANT) - return glitter_curve_randomize(c, curr); + if (count > 0) { + ee.repeat_count = (uint32_t)count; + vector_enrs_entry_push_back(&e, &ee); + } - df = (float_t)(next->frame - curr->frame); - t = (frame - curr->frame) / df; - if (type == GLITTER_KEY_HERMITE) { - t_2 = (1.0f - t) * (1.0f - t); - next_val = glitter_curve_randomize(c, next); - curr_val = glitter_curve_randomize(c, curr); - v15 = t_2 * (next_val - curr_val) * (1.0f + 2.0f * t) + ((t_2 * curr->tangent2 + t * (t - 1.0f) * next->tangent1) * df) * t; - return glitter_curve_randomize(c, curr) + v15; + count = 1; + o = (uint32_t)((key_type == GLITTER_KEY_HERMITE ? 20 : 12) * count); + if (i->type == GLITTER_KEY_HERMITE) { + ee = (enrs_entry){ o, 2, 20, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 4, ENRS_TYPE_DWORD }); + } + else { + ee = (enrs_entry){ o, 2, 12, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_DWORD }); + } + key_type = i->type; + } } else { - curr_val = glitter_curve_randomize(c, curr); - next_val = glitter_curve_randomize(c, next); - return next_val * t + curr_val * (1.0f - t); - } -} + key_type = keys->begin->type; + if (key_type == GLITTER_KEY_HERMITE) { + ee = (enrs_entry){ 0, 2, 16, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 3, ENRS_TYPE_DWORD }); + l = 16; + } + else { + ee = (enrs_entry){ 0, 2, 8, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_DWORD }); + l = 8; + } -static void FASTCALL glitter_curve_key_pack_file(f2_struct* st, glitter_curve* c, bool use_big_endian) { - stream* s = io_open_memory(0, 0); - io_set_position(s, 0, SEEK_SET); + count = 1; + for (glitter_curve_key* i = keys->begin + 1; i != keys->end; + i++, count++, l += key_type == GLITTER_KEY_HERMITE ? 16 : 8) { + if (i->type == key_type) + continue; + + if (count > 0) { + ee.repeat_count = (uint32_t)count; + vector_enrs_entry_push_back(&e, &ee); + } + + count = 1; + o = (uint32_t)((key_type == GLITTER_KEY_HERMITE ? 16 : 8) * count); + if (i->type == GLITTER_KEY_HERMITE) { + ee = (enrs_entry){ o, 2, 16, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 3, ENRS_TYPE_DWORD }); + } + else { + ee = (enrs_entry){ o, 2, 8, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_DWORD }); + } + key_type = i->type; + } + } + + if (count > 0) { + ee.repeat_count = (uint32_t)count; + vector_enrs_entry_push_back(&e, &ee); + } float_t scale = 1.0f; if (c->keys_version == 0) @@ -236,7 +333,7 @@ static void FASTCALL glitter_curve_key_pack_file(f2_struct* st, glitter_curve* c case GLITTER_CURVE_ROTATION_X: case GLITTER_CURVE_ROTATION_Y: case GLITTER_CURVE_ROTATION_Z: - scale = (float_t)(180.0 / M_PI); + scale = RAD_TO_DEG_FLOAT; break; case GLITTER_CURVE_COLOR_R: case GLITTER_CURVE_COLOR_G: @@ -246,119 +343,94 @@ static void FASTCALL glitter_curve_key_pack_file(f2_struct* st, glitter_curve* c break; } - glitter_curve_key* i; - if (use_big_endian) - if (scale == 1.0f) - if (c->flags & GLITTER_CURVE_FLAG_RANDOM_RANGE) - for (i = c->keys.begin; i != c->keys.end; i++) { - io_write_int16_t(s, reverse_endianess_int16_t((int16_t)i->type)); - io_write_int16_t(s, reverse_endianess_int16_t((int16_t)i->frame)); - if (i->type == GLITTER_KEY_HERMITE) { - io_write_float_t(s, reverse_endianess_float_t(i->tangent1)); - io_write_float_t(s, reverse_endianess_float_t(i->tangent2)); - } - io_write_float_t(s, reverse_endianess_float_t(i->random_range)); - io_write_float_t(s, reverse_endianess_float_t(i->value)); + l = align_val(l, 0x10); + d = (size_t)force_malloc(l); + st->length = l; + st->data = (void*)d; + st->enrs = e; + + if (scale == 1.0f) + if (c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) + for (glitter_curve_key* i = keys->begin; i != keys->end; i++) { + *(int16_t*)d = (int16_t)i->type; + *(int16_t*)(d + 2) = (int16_t)i->frame; + if (i->type == GLITTER_KEY_HERMITE) { + *(float_t*)(d + 4) = i->tangent1; + *(float_t*)(d + 8) = i->tangent2; + *(float_t*)(d + 12) = i->random_range; + *(float_t*)(d + 16) = i->value; + d += 20; } - else - for (i = c->keys.begin; i != c->keys.end; i++) { - io_write_int16_t(s, reverse_endianess_int16_t((int16_t)i->type)); - io_write_int16_t(s, reverse_endianess_int16_t((int16_t)i->frame)); - if (i->type == GLITTER_KEY_HERMITE) { - io_write_float_t(s, reverse_endianess_float_t(i->tangent1)); - io_write_float_t(s, reverse_endianess_float_t(i->tangent2)); - } - io_write_float_t(s, reverse_endianess_float_t(i->value)); + else { + *(float_t*)(d + 4) = i->random_range; + *(float_t*)(d + 8) = i->value; + d += 12; } + } else - if (c->flags & GLITTER_CURVE_FLAG_RANDOM_RANGE) - for (i = c->keys.begin; i != c->keys.end; i++) { - io_write_int16_t(s, reverse_endianess_int16_t((int16_t)i->type)); - io_write_int16_t(s, reverse_endianess_int16_t((int16_t)i->frame)); - if (i->type == GLITTER_KEY_HERMITE) { - io_write_float_t(s, reverse_endianess_float_t(i->tangent1 * scale)); - io_write_float_t(s, reverse_endianess_float_t(i->tangent2 * scale)); - } - io_write_float_t(s, reverse_endianess_float_t(i->random_range * scale)); - io_write_float_t(s, reverse_endianess_float_t(i->value * scale)); + for (glitter_curve_key* i = keys->begin; i != keys->end; i++) { + *(int16_t*)d = (int16_t)i->type; + *(int16_t*)(d + 2) = (int16_t)i->frame; + if (i->type == GLITTER_KEY_HERMITE) { + *(float_t*)(d + 4) = i->tangent1; + *(float_t*)(d + 8) = i->tangent2; + *(float_t*)(d + 12) = i->value; + d += 16; } - else - for (i = c->keys.begin; i != c->keys.end; i++) { - io_write_int16_t(s, reverse_endianess_int16_t((int16_t)i->type)); - io_write_int16_t(s, reverse_endianess_int16_t((int16_t)i->frame)); - if (i->type == GLITTER_KEY_HERMITE) { - io_write_float_t(s, reverse_endianess_float_t(i->tangent1 * scale)); - io_write_float_t(s, reverse_endianess_float_t(i->tangent2 * scale)); - } - io_write_float_t(s, reverse_endianess_float_t(i->value* scale)); + else { + *(float_t*)(d + 4) = i->value; + d += 8; } + } else - if (scale == 1.0f) - if (c->flags & GLITTER_CURVE_FLAG_RANDOM_RANGE) - for (i = c->keys.begin; i != c->keys.end; i++) { - io_write_int16_t(s, (int16_t)i->type); - io_write_int16_t(s, (int16_t)i->frame); - if (i->type == GLITTER_KEY_HERMITE) { - io_write_float_t(s, i->tangent1); - io_write_float_t(s, i->tangent2); - } - io_write_float_t(s, i->random_range); - io_write_float_t(s, i->value); + if (c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) + for (glitter_curve_key* i = keys->begin; i != keys->end; i++) { + *(int16_t*)d = (int16_t)i->type; + *(int16_t*)(d + 2) = (int16_t)i->frame; + if (i->type == GLITTER_KEY_HERMITE) { + *(float_t*)(d + 4) = i->tangent1 * scale; + *(float_t*)(d + 8) = i->tangent2 * scale; + *(float_t*)(d + 12) = i->random_range * scale; + *(float_t*)(d + 16) = i->value * scale; + d += 20; } - else - for (i = c->keys.begin; i != c->keys.end; i++) { - io_write_int16_t(s, (int16_t)i->type); - io_write_int16_t(s, (int16_t)i->frame); - if (i->type == GLITTER_KEY_HERMITE) { - io_write_float_t(s, i->tangent1); - io_write_float_t(s, i->tangent2); - } - io_write_float_t(s, i->value); + else { + *(float_t*)(d + 4) = i->random_range * scale; + *(float_t*)(d + 8) = i->value * scale; + d += 12; } + } else - if (c->flags & GLITTER_CURVE_FLAG_RANDOM_RANGE) - for (i = c->keys.begin; i != c->keys.end; i++) { - io_write_int16_t(s, (int16_t)i->type); - io_write_int16_t(s, (int16_t)i->frame); - if (i->type == GLITTER_KEY_HERMITE) { - io_write_float_t(s, i->tangent1 * scale); - io_write_float_t(s, i->tangent2 * scale); - } - io_write_float_t(s, i->random_range * scale); - io_write_float_t(s, i->value * scale); + for (glitter_curve_key* i = keys->begin; i != keys->end; i++) { + *(int16_t*)d = (int16_t)i->type; + *(int16_t*)(d + 2) = (int16_t)i->frame; + if (i->type == GLITTER_KEY_HERMITE) { + *(float_t*)(d + 4) = i->tangent1 * scale; + *(float_t*)(d + 8) = i->tangent2 * scale; + *(float_t*)(d + 12) = i->value * scale; + d += 16; } - else - for (i = c->keys.begin; i != c->keys.end; i++) { - io_write_int16_t(s, (int16_t)i->type); - io_write_int16_t(s, (int16_t)i->frame); - if (i->type == GLITTER_KEY_HERMITE) { - io_write_float_t(s, i->tangent1 * scale); - io_write_float_t(s, i->tangent2 * scale); - } - io_write_float_t(s, i->value * scale); + else { + *(float_t*)(d + 4) = i->value * scale; + d += 8; } - io_set_position(s, 0, SEEK_END); - io_align(s, 0x10); + } - st->length = s->io.data.vec.end - s->io.data.vec.begin; - st->data = force_malloc(st->length); - memcpy(st->data, s->io.data.vec.begin, st->length); - io_dispose(s); - - st->header.signature = 0x5359454B; + st->header.signature = reverse_endianess_uint32_t('KEYS'); st->header.length = 0x20; - st->header.use_big_endian = use_big_endian ? true : false; + st->header.use_big_endian = false; st->header.use_section_size = true; st->header.version = c->keys_version; } -static void FASTCALL glitter_curve_key_unpack_file(f2_struct* st, glitter_curve* c, uint32_t count) { +static void FASTCALL glitter_curve_key_unpack_file(GPM, + f2_struct* st, glitter_curve* c, uint32_t count) { size_t i; glitter_curve_key key; - float_t scale; float_t* data; + float_t scale; - if (!st || !st->header.data_size) + if (!st || !st->header.data_size || count < 1) return; c->keys_version = st->header.version; @@ -371,41 +443,27 @@ static void FASTCALL glitter_curve_key_unpack_file(f2_struct* st, glitter_curve* key.tangent2 = 0.0f; key.random_range = 0.0f; - scale = 1.0f; - if (c->keys_version == 0) - switch (c->type) { - case GLITTER_CURVE_ROTATION_X: - case GLITTER_CURVE_ROTATION_Y: - case GLITTER_CURVE_ROTATION_Z: - scale = (float_t)(M_PI / 180.0); - break; - case GLITTER_CURVE_COLOR_R: - case GLITTER_CURVE_COLOR_G: - case GLITTER_CURVE_COLOR_B: - case GLITTER_CURVE_COLOR_A: - scale = (float_t)(1.0 / 255.0); - break; - } - - if (st->header.use_big_endian) - if (scale == 1.0f) - if (c->flags & GLITTER_CURVE_FLAG_RANDOM_RANGE) + vector_glitter_curve_key keys = { 0, 0, 0 }; + vector_glitter_curve_key_append(&keys, count); + if (glt_type == GLITTER_X && c->keys_version != 2) { + if (st->header.use_big_endian) + if (c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) for (i = count; i; i--) { key.type = reverse_endianess_int16_t(((int16_t*)data)[0]); key.frame = reverse_endianess_int16_t(((int16_t*)data)[1]); if (key.type == GLITTER_KEY_HERMITE) { - key.tangent1 = reverse_endianess_float_t(data[1]); - key.tangent2 = reverse_endianess_float_t(data[2]); - key.random_range = reverse_endianess_float_t(data[3]); - key.value = reverse_endianess_float_t(data[4]); - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 5; + key.tangent1 = reverse_endianess_float_t(data[4]); + key.tangent2 = reverse_endianess_float_t(data[5]); + key.random_range = reverse_endianess_float_t(data[6]); + key.value = reverse_endianess_float_t(data[7]); + vector_glitter_curve_key_push_back(&keys, &key); + data += 8; } else { - key.random_range = reverse_endianess_float_t(data[1]); - key.value = reverse_endianess_float_t(data[2]); - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 3; + key.random_range = reverse_endianess_float_t(data[2]); + key.value = reverse_endianess_float_t(data[3]); + vector_glitter_curve_key_push_back(&keys, &key); + data += 4; } } else @@ -416,71 +474,33 @@ static void FASTCALL glitter_curve_key_unpack_file(f2_struct* st, glitter_curve* key.tangent1 = reverse_endianess_float_t(data[1]); key.tangent2 = reverse_endianess_float_t(data[2]); key.value = reverse_endianess_float_t(data[3]); - vector_glitter_curve_key_push_back(&c->keys, &key); + vector_glitter_curve_key_push_back(&keys, &key); data += 4; } else { - key.value = reverse_endianess_float_t(data[1]); - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 2; + key.value = reverse_endianess_float_t(data[3]); + vector_glitter_curve_key_push_back(&keys, &key); + data += 4; } } else - if (c->flags & GLITTER_CURVE_FLAG_RANDOM_RANGE) - for (i = count; i; i--) { - key.type = reverse_endianess_int16_t(((int16_t*)data)[0]); - key.frame = reverse_endianess_int16_t(((int16_t*)data)[1]); - if (key.type == GLITTER_KEY_HERMITE) { - key.tangent1 = reverse_endianess_float_t(data[1]) * scale; - key.tangent2 = reverse_endianess_float_t(data[2]) * scale; - key.random_range = reverse_endianess_float_t(data[3]) * scale; - key.value = reverse_endianess_float_t(data[4]) * scale; - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 5; - } - else { - key.random_range = reverse_endianess_float_t(data[1]) * scale; - key.value = reverse_endianess_float_t(data[2]) * scale; - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 3; - } - } - else - for (i = count; i; i--) { - key.type = reverse_endianess_int16_t(((int16_t*)data)[0]); - key.frame = reverse_endianess_int16_t(((int16_t*)data)[1]); - if (key.type == GLITTER_KEY_HERMITE) { - key.tangent1 = reverse_endianess_float_t(data[1]) * scale; - key.tangent2 = reverse_endianess_float_t(data[2]) * scale; - key.value = reverse_endianess_float_t(data[3]) * scale; - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 4; - } - else { - key.value = reverse_endianess_float_t(data[1]) * scale; - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 2; - } - } - else - if (scale == 1.0f) - if (c->flags & GLITTER_CURVE_FLAG_RANDOM_RANGE) + if (c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) for (i = count; i; i--) { key.type = ((int16_t*)data)[0]; key.frame = ((int16_t*)data)[1]; if (key.type == GLITTER_KEY_HERMITE) { - key.tangent1 = data[1]; - key.tangent2 = data[2]; - key.random_range = data[3]; - key.value = data[4]; - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 5; + key.tangent1 = data[4]; + key.tangent2 = data[5]; + key.random_range = data[6]; + key.value = data[7]; + vector_glitter_curve_key_push_back(&keys, &key); + data += 8; } else { - key.random_range = data[1]; - key.value = data[2]; - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 3; + key.random_range = data[2]; + key.value = data[3]; + vector_glitter_curve_key_push_back(&keys, &key); + data += 4; } } else @@ -491,172 +511,588 @@ static void FASTCALL glitter_curve_key_unpack_file(f2_struct* st, glitter_curve* key.tangent1 = data[1]; key.tangent2 = data[2]; key.value = data[3]; - vector_glitter_curve_key_push_back(&c->keys, &key); + vector_glitter_curve_key_push_back(&keys, &key); data += 4; } else { - key.value = data[1]; - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 2; - } - } - else - if (c->flags & GLITTER_CURVE_FLAG_RANDOM_RANGE) - for (i = count; i; i--) { - key.type = ((int16_t*)data)[0]; - key.frame = ((int16_t*)data)[1]; - if (key.type == GLITTER_KEY_HERMITE) { - key.tangent1 = data[1] * scale; - key.tangent2 = data[2] * scale; - key.random_range = data[3] * scale; - key.value = data[4] * scale; - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 5; - } - else { - key.random_range = data[1] * scale; - key.value = data[2] * scale; - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 3; - } - } - else - for (i = count; i; i--) { - key.type = ((int16_t*)data)[0]; - key.frame = ((int16_t*)data)[1]; - if (key.type == GLITTER_KEY_HERMITE) { - key.tangent1 = data[1] * scale; - key.tangent2 = data[2] * scale; - key.value = data[3] * scale; - vector_glitter_curve_key_push_back(&c->keys, &key); + key.value = data[3]; + vector_glitter_curve_key_push_back(&keys, &key); data += 4; } - else { - key.value = data[1] * scale; - vector_glitter_curve_key_push_back(&c->keys, &key); - data += 2; - } } -} - -static void FASTCALL glitter_curve_pack_file(f2_struct* st, - glitter_curve* c, bool use_big_endian, size_t keys_count) { - uint32_t* d; - - memset(st, 0, sizeof(f2_struct)); - - d = force_malloc(0x20); - st->data = d; - st->length = 0x20; - - if (use_big_endian) { - d[0] = reverse_endianess_uint32_t(c->type); - d[1] = reverse_endianess_uint32_t(c->repeat ? 1 : 0); - d[2] = reverse_endianess_uint32_t(c->flags); - if (c->version == 1) - *(float_t*)&d[3] = reverse_endianess_float_t(c->max_rand); - else - switch (c->type) { - case GLITTER_CURVE_ROTATION_X: - case GLITTER_CURVE_ROTATION_Y: - case GLITTER_CURVE_ROTATION_Z: - *(float_t*)&d[3] = 0.0f; - break; - default: - *(float_t*)&d[3] = reverse_endianess_float_t(c->max_rand); - break; - } - ((uint16_t*)d)[8] = reverse_endianess_uint16_t((uint16_t)keys_count); - ((uint16_t*)d)[9] = reverse_endianess_uint16_t((uint16_t)roundf(c->start_time)); - ((uint16_t*)d)[10] = reverse_endianess_uint16_t((uint16_t)roundf(c->end_time)); } else { - d[0] = c->type; - d[1] = c->repeat ? 1 : 0; - d[2] = c->flags; - if (c->version == 1) - *(float_t*)&d[3] = c->max_rand; - else + scale = 1.0f; + if (c->keys_version == 0) switch (c->type) { case GLITTER_CURVE_ROTATION_X: case GLITTER_CURVE_ROTATION_Y: case GLITTER_CURVE_ROTATION_Z: - *(float_t*)&d[3] = 0.0f; + scale = DEG_TO_RAD_FLOAT; break; - default: - *(float_t*)&d[3] = c->max_rand; + case GLITTER_CURVE_COLOR_R: + case GLITTER_CURVE_COLOR_G: + case GLITTER_CURVE_COLOR_B: + case GLITTER_CURVE_COLOR_A: + scale = (float_t)(1.0 / 255.0); break; } - ((uint16_t*)d)[8] = (uint16_t)keys_count; - ((uint16_t*)d)[9] = (uint16_t)roundf(c->start_time); - ((uint16_t*)d)[10] = (uint16_t)roundf(c->end_time); + + if (st->header.use_big_endian) + if (scale == 1.0f) + if (c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) + for (i = count; i; i--) { + key.type = reverse_endianess_int16_t(((int16_t*)data)[0]); + key.frame = reverse_endianess_int16_t(((int16_t*)data)[1]); + if (key.type == GLITTER_KEY_HERMITE) { + key.tangent1 = reverse_endianess_float_t(data[1]); + key.tangent2 = reverse_endianess_float_t(data[2]); + key.random_range = reverse_endianess_float_t(data[3]); + key.value = reverse_endianess_float_t(data[4]); + vector_glitter_curve_key_push_back(&keys, &key); + data += 5; + } + else { + key.random_range = reverse_endianess_float_t(data[1]); + key.value = reverse_endianess_float_t(data[2]); + vector_glitter_curve_key_push_back(&keys, &key); + data += 3; + } + } + else + for (i = count; i; i--) { + key.type = reverse_endianess_int16_t(((int16_t*)data)[0]); + key.frame = reverse_endianess_int16_t(((int16_t*)data)[1]); + if (key.type == GLITTER_KEY_HERMITE) { + key.tangent1 = reverse_endianess_float_t(data[1]); + key.tangent2 = reverse_endianess_float_t(data[2]); + key.value = reverse_endianess_float_t(data[3]); + vector_glitter_curve_key_push_back(&keys, &key); + data += 4; + } + else { + key.value = reverse_endianess_float_t(data[1]); + vector_glitter_curve_key_push_back(&keys, &key); + data += 2; + } + } + else + if (c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) + for (i = count; i; i--) { + key.type = reverse_endianess_int16_t(((int16_t*)data)[0]); + key.frame = reverse_endianess_int16_t(((int16_t*)data)[1]); + if (key.type == GLITTER_KEY_HERMITE) { + key.tangent1 = reverse_endianess_float_t(data[1]) * scale; + key.tangent2 = reverse_endianess_float_t(data[2]) * scale; + key.random_range = reverse_endianess_float_t(data[3]) * scale; + key.value = reverse_endianess_float_t(data[4]) * scale; + vector_glitter_curve_key_push_back(&keys, &key); + data += 5; + } + else { + key.random_range = reverse_endianess_float_t(data[1]) * scale; + key.value = reverse_endianess_float_t(data[2]) * scale; + vector_glitter_curve_key_push_back(&keys, &key); + data += 3; + } + } + else + for (i = count; i; i--) { + key.type = reverse_endianess_int16_t(((int16_t*)data)[0]); + key.frame = reverse_endianess_int16_t(((int16_t*)data)[1]); + if (key.type == GLITTER_KEY_HERMITE) { + key.tangent1 = reverse_endianess_float_t(data[1]) * scale; + key.tangent2 = reverse_endianess_float_t(data[2]) * scale; + key.value = reverse_endianess_float_t(data[3]) * scale; + vector_glitter_curve_key_push_back(&keys, &key); + data += 4; + } + else { + key.value = reverse_endianess_float_t(data[1]) * scale; + vector_glitter_curve_key_push_back(&keys, &key); + data += 2; + } + } + else + if (scale == 1.0f) + if (c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) + for (i = count; i; i--) { + key.type = ((int16_t*)data)[0]; + key.frame = ((int16_t*)data)[1]; + if (key.type == GLITTER_KEY_HERMITE) { + key.tangent1 = data[1]; + key.tangent2 = data[2]; + key.random_range = data[3]; + key.value = data[4]; + vector_glitter_curve_key_push_back(&keys, &key); + data += 5; + } + else { + key.random_range = data[1]; + key.value = data[2]; + vector_glitter_curve_key_push_back(&keys, &key); + data += 3; + } + } + else + for (i = count; i; i--) { + key.type = ((int16_t*)data)[0]; + key.frame = ((int16_t*)data)[1]; + if (key.type == GLITTER_KEY_HERMITE) { + key.tangent1 = data[1]; + key.tangent2 = data[2]; + key.value = data[3]; + vector_glitter_curve_key_push_back(&keys, &key); + data += 4; + } + else { + key.value = data[1]; + vector_glitter_curve_key_push_back(&keys, &key); + data += 2; + } + } + else + if (c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) + for (i = count; i; i--) { + key.type = ((int16_t*)data)[0]; + key.frame = ((int16_t*)data)[1]; + if (key.type == GLITTER_KEY_HERMITE) { + key.tangent1 = data[1] * scale; + key.tangent2 = data[2] * scale; + key.random_range = data[3] * scale; + key.value = data[4] * scale; + vector_glitter_curve_key_push_back(&keys, &key); + data += 5; + } + else { + key.random_range = data[1] * scale; + key.value = data[2] * scale; + vector_glitter_curve_key_push_back(&keys, &key); + data += 3; + } + } + else + for (i = count; i; i--) { + key.type = ((int16_t*)data)[0]; + key.frame = ((int16_t*)data)[1]; + if (key.type == GLITTER_KEY_HERMITE) { + key.tangent1 = data[1] * scale; + key.tangent2 = data[2] * scale; + key.value = data[3] * scale; + vector_glitter_curve_key_push_back(&keys, &key); + data += 4; + } + else { + key.value = data[1] * scale; + vector_glitter_curve_key_push_back(&keys, &key); + data += 2; + } + } + } + c->keys = keys; + + if (c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE && keys.begin) { + bool has_key_random_range = false; + if (glt_type == GLITTER_F2) { + if (count > 1 && keys.begin[0].random_range != 0.0f + && keys.begin[1].random_range != 0.0f) + has_key_random_range = true; + else if (count > 1 && keys.begin[0].random_range != 0.0f + && keys.begin[1].random_range == 0.0f) { + keys.begin[0].value += keys.begin[0].random_range * 10.0f; + keys.begin[0].random_range = 0.0f; + } + + if (count > 1 && keys.begin[count - 2].random_range != 0.0f + && keys.begin[count - 1].random_range != 0.0f) + has_key_random_range = true; + else if (count > 1 && keys.begin[count - 2].random_range == 0.0f + && keys.begin[count - 1].random_range != 0.0f) { + keys.begin[count - 1].value += keys.begin[count - 1].random_range * 10.0f; + keys.begin[count - 1].random_range = 0.0f; + } + } + + if (!has_key_random_range) + for (i = 0; i < count; i++) + if (keys.begin[i].random_range != 0.0f) { + has_key_random_range = true; + break; + } + + if (!has_key_random_range) + c->flags &= ~GLITTER_CURVE_KEY_RANDOM_RANGE; } - st->header.signature = 0x56525543; +#ifdef CRE_DEV + c->keys_rev = (vector_glitter_curve_key){ 0, 0, 0 }; + bool curve_baked = c->flags & GLITTER_CURVE_BAKED ? true : false; + if (!curve_baked) { + vector_glitter_curve_key_insert_range(&c->keys_rev, 0, keys.begin, keys.end); + return; + } + else if (count == 1) { + keys.begin[0].frame = c->start_time; + vector_glitter_curve_key_push_back(&c->keys_rev, &keys.begin[0]); + return; + } + + bool curve_baked_half = false; + if (curve_baked && (glt_type == GLITTER_F2 + || (glt_type == GLITTER_X && ~c->flags & GLITTER_CURVE_BAKED_FULL))) + curve_baked_half = true; + + const uint8_t step = curve_baked_half ? 2 : 1; + + int32_t start_time = c->start_time; + int32_t end_time = c->start_time + (int32_t)((count - 1) * step); + c->end_time = end_time; + float_t* arr_a = force_malloc_s(float_t, count); + float_t* arr_b = force_malloc_s(float_t, count); + for (i = 0; i < count; i++) { + keys.begin[i].frame = start_time + (int32_t)(i * step); + arr_a[i] = keys.begin[i].value; + arr_b[i] = keys.begin[i].random_range; + } + + const float_t* reverse_bias = curve_baked_half + ? glitter_curve_baked_half_reverse_bias : glitter_curve_baked_reverse_bias; + const size_t reverse_min_count = curve_baked_half ? 5 : 4; + + vector_glitter_curve_key keys_rev = { 0, 0, 0 }; + float_t* a = arr_a; + float_t* b = arr_b; + size_t left_count = count; + int32_t frame = start_time; + int32_t prev_frame = start_time; + float_t t2_old = 0.0f; + float_t* val_arr = force_malloc_s(float_t, count); + while (left_count > 0) { + int32_t c = 0; + if (left_count < reverse_min_count) { + glitter_curve_key key; + memset(&key, 0, sizeof(glitter_curve_key)); + if (left_count == 1) { + key.type = GLITTER_KEY_CONSTANT; + key.frame = frame; + key.value = a[0]; + key.tangent1 = t2_old; + key.tangent2 = 0.0f; + key.random_range = b[0]; + vector_glitter_curve_key_push_back(&keys_rev, &key); + t2_old = 0.0f; + } + else { + bool has_error = false; + bool has_error_lerp = false; + for (size_t j = 1; j < left_count; j++) { + float_t val = lerp(a[0], a[left_count - 1], (float_t)j / (float_t)left_count); + if (fabsf(val - a[0]) > reverse_bias[0]) { + has_error = true; + if (fabsf(val - a[j]) > reverse_bias[1]) { + has_error_lerp = true; + break; + } + } + } + + t2_old = glitter_curve_key_add_key(GPM_VAL, + has_error, has_error_lerp, true, + a, b, frame, step, left_count, 0.0f, 0.0f, t2_old, &keys_rev); + } + break; + } + + float_t t1 = 0.0f; + float_t t2 = 0.0f; + float_t t1_prev = 0.0f; + float_t t2_prev = 0.0f; + bool has_prev_succeded = false; + bool constant = false; + bool prev_constant = false; + bool has_error = false; + bool has_error_lerp = false; + bool has_error_hermite = false; + bool has_prev_error = false; + bool has_prev_error_lerp = false; + bool has_prev_error_hermite = false; + for (i = reverse_min_count - 1; i < left_count; i++) { + double_t tt1 = 0.0; + double_t tt2 = 0.0; + for (size_t j = 1; j < i - 1; j++) { + float_t _t1 = 0.0f; + float_t _t2 = 0.0f; + interpolate_chs_reverse_step_value(a, left_count, &_t1, &_t2, 0, i, j, step); + tt1 += _t1; + tt2 += _t2; + } + t1 = (float_t)(tt1 / (double_t)(i - 2)); + t2 = (float_t)(tt2 / (double_t)(i - 2)); + + constant = false; + has_error = false; + has_error_lerp = false; + has_error_hermite = false; + for (size_t j = 1; j < i; j++) { + float_t val = interpolate_chs_value(a[0], a[i], t1, t2, 0.0f, + (float_t)(i * step), (float_t)(j * step)); + float_t val_lerp = lerp(a[0], a[i], (float_t)j / (float_t)i); + if (fabsf(val - a[0]) > reverse_bias[0]) { + has_error = true; + constant = false; + if (fabsf(val_lerp - a[j]) > reverse_bias[1]) { + has_error_lerp = true; + if (fabsf(val - a[j]) > reverse_bias[2]) { + has_error_hermite = true; + break; + } + } + } + else + constant = true; + } + + if (!has_error_hermite) { + t1_prev = t1; + t2_prev = t2; + prev_constant = constant; + has_prev_succeded = true; + has_prev_error = has_error; + has_prev_error_lerp = has_error_lerp; + has_prev_error_hermite = has_error_hermite; + if (i < left_count) + continue; + } + + if (has_prev_succeded) { + if (prev_constant && ((i < left_count - 1 && a[i] == a[i + 1]) || (frame + i == end_time))) + c = (int32_t)i; + else + c = (int32_t)(i - 1); + t1 = t1_prev; + t2 = t2_prev; + has_error = has_prev_error; + has_error_lerp = has_prev_error_lerp; + has_error_hermite = has_prev_error_hermite; + } + else + c = (int32_t)i; + + if (has_error_hermite) + c = 1; + + t2_old = glitter_curve_key_add_key(GPM_VAL, + has_error, has_error_lerp, has_error_hermite, + a, b, frame, step, c, t1, t2, t2_old, &keys_rev); + prev_constant = false; + has_prev_succeded = false; + break; + } + + if (has_prev_succeded) { + t2_old = glitter_curve_key_add_key(GPM_VAL, + has_prev_error, has_prev_error_lerp, has_prev_error_hermite, + a, b, frame, step, i, t1_prev, t2_prev, t2_old, &keys_rev); + c = (int32_t)i; + } + prev_frame = frame; + frame += c * step; + a += c; + b += c; + left_count -= c; + } + free(val_arr); + + memset(&key, 0, sizeof(glitter_curve_key)); + key.type = GLITTER_KEY_CONSTANT; + key.frame = start_time + (count - 1) * step; + key.value = arr_a[count - 1]; + key.tangent1 = t2_old; + key.tangent2 = 0.0f; + key.random_range = arr_b[count - 1]; + vector_glitter_curve_key_push_back(&keys_rev, &key); + free(arr_a); + free(arr_b); + c->keys_rev = keys_rev; + + glitter_curve_recalculate(GPM_VAL, c, &c->keys); +#endif +} + +#ifdef CRE_DEV +static float_t FASTCALL glitter_curve_key_add_key(GPM, bool has_error, + bool has_error_lerp, bool has_error_hermite, float_t* a, float_t* b, int32_t frame, + const uint8_t step, size_t i, float_t t1, float_t t2, float_t t2_old, + vector_glitter_curve_key* keys_rev) { + glitter_curve_key key; + memset(&key, 0, sizeof(glitter_curve_key)); + if (has_error && has_error_lerp && has_error_hermite) { + float_t _t2 = t2_old; + for (size_t j = 0; j < i; j++) { + key.type = GLITTER_KEY_CONSTANT; + key.frame = (int32_t)(frame + j * step); + key.value = a[j]; + key.tangent1 = _t2; + key.tangent2 = 0.0f; + key.random_range = b[j]; + vector_glitter_curve_key_push_back(keys_rev, &key); + _t2 = 0.0f; + } + } + else if (has_error && has_error_lerp) { + key.type = GLITTER_KEY_HERMITE; + key.frame = frame; + key.value = a[0]; + key.tangent1 = t2_old; + key.tangent2 = t1; + key.random_range = b[0]; + vector_glitter_curve_key_push_back(keys_rev, &key); + return t2; + } + else if (has_error || (i > 1 && b[0] != b[1])) { + key.type = GLITTER_KEY_LINEAR; + key.frame = frame; + key.value = a[0]; + key.tangent1 = 0.0f; + key.tangent2 = 0.0f; + key.random_range = b[0]; + vector_glitter_curve_key_push_back(keys_rev, &key); + } + else { + key.type = GLITTER_KEY_CONSTANT; + key.frame = frame; + key.value = a[0]; + key.tangent1 = 0.0f; + key.tangent2 = 0.0f; + key.random_range = b[0]; + vector_glitter_curve_key_push_back(keys_rev, &key); + } + return 0.0f; +} +#endif + +static void FASTCALL glitter_curve_pack_file(GPM, + f2_struct* st, glitter_curve* c, size_t keys_count) { + size_t l; + size_t d; + + memset(st, 0, sizeof(f2_struct)); + l = 0; + + uint32_t o; + vector_enrs_entry e = { 0, 0, 0 }; + enrs_entry ee; + + ee = (enrs_entry){ 0, 2, 32, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 4, ENRS_TYPE_DWORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 3, ENRS_TYPE_WORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 32; + + d = (size_t)force_malloc(l); + st->data = (void*)d; + st->length = l; + st->enrs = e; + + float_t random_range = c->random_range; + if (c->version == 0) + switch (c->type) { + case GLITTER_CURVE_ROTATION_X: + case GLITTER_CURVE_ROTATION_Y: + case GLITTER_CURVE_ROTATION_Z: + random_range = 0.0f; + break; + } + + *(uint32_t*)d = c->type; + *(uint32_t*)(d + 4) = c->repeat ? 1 : 0; + *(uint32_t*)(d + 8) = c->flags; + *(float_t*)(d + 12) = random_range; + *(int16_t*)(d + 16) = (int16_t)keys_count; + *(int16_t*)(d + 18) = (int16_t)c->start_time; + *(int16_t*)(d + 20) = (int16_t)c->end_time; + + st->header.signature = reverse_endianess_uint32_t('CURV'); st->header.length = 0x20; - st->header.use_big_endian = use_big_endian ? true : false; + st->header.use_big_endian = false; st->header.use_section_size = true; st->header.version = c->version; } -static float_t FASTCALL glitter_curve_randomize(glitter_curve* c, glitter_curve_key* key) { - float_t min_value; - float_t value; +static void FASTCALL glitter_curve_unpack_file(GPM, void* data, + glitter_curve* c, uint32_t version, bool use_big_endian, uint32_t* keys_count) { + size_t d; - if (~c->flags & GLITTER_CURVE_FLAG_RANDOM_RANGE) - return key->value; - - min_value = c->flags & GLITTER_CURVE_FLAG_NEGATIVE_RANDOM ? -key->random_range : 0.0f; - value = glitter_random_get_float_clamp(min_value, key->random_range); - - if (c->flags & GLITTER_CURVE_FLAG_MULT) - value *= key->value; - - return value + key->value; -} - -static void FASTCALL glitter_curve_unpack_file(uint32_t* data, - glitter_curve* c, bool use_big_endian, uint32_t* keys_count) { - if (use_big_endian) { - c->type = reverse_endianess_uint32_t(data[0]); - c->repeat = reverse_endianess_uint32_t(data[1]) != 0; - c->flags = reverse_endianess_uint32_t(data[2]); - if (c->version == 1) - c->max_rand = reverse_endianess_float_t(*(float_t*)&data[3]); - else - switch (c->type) { - case GLITTER_CURVE_ROTATION_X: - case GLITTER_CURVE_ROTATION_Y: - case GLITTER_CURVE_ROTATION_Z: - c->max_rand = 0.0f; - break; - default: - c->max_rand = reverse_endianess_float_t(*(float_t*)&data[3]); - break; + d = (size_t)data; + if (glt_type == GLITTER_X) { + if (version == 1) { + if (use_big_endian) { + c->type = reverse_endianess_uint32_t(*(uint32_t*)d); + c->repeat = reverse_endianess_uint32_t(*(uint32_t*)(d + 4)) != 0; + c->flags = reverse_endianess_uint32_t(*(uint32_t*)(d + 8)); + c->random_range = reverse_endianess_float_t(*(float_t*)(d + 12)); + *keys_count = reverse_endianess_int16_t(*(int16_t*)(d + 16)); + c->start_time = reverse_endianess_int16_t(*(int16_t*)(d + 18)); + c->end_time = reverse_endianess_int16_t(*(int16_t*)(d + 20)); } - *keys_count = reverse_endianess_uint16_t(((uint16_t*)data)[8]); - c->start_time = (float_t)reverse_endianess_uint16_t(((uint16_t*)data)[9]); - c->end_time = (float_t)reverse_endianess_uint16_t(((uint16_t*)data)[10]); + else { + c->type = *(uint32_t*)d; + c->repeat = *(uint32_t*)(d + 4) != 0; + c->flags = *(uint32_t*)(d + 8); + c->random_range = *(float_t*)(d + 12); + *keys_count = *(int16_t*)(d + 16); + c->start_time = *(int16_t*)(d + 18); + c->end_time = *(int16_t*)(d + 20); + } + } + else { + if (use_big_endian) { + c->type = reverse_endianess_uint32_t(*(uint32_t*)d); + c->repeat = reverse_endianess_uint32_t(*(uint32_t*)(d + 4)) != 0; + c->flags = reverse_endianess_uint32_t(*(uint32_t*)(d + 8)); + c->random_range = reverse_endianess_float_t(*(float_t*)(d + 12)); + *keys_count = reverse_endianess_uint16_t(*(int16_t*)(d + 28)); + c->start_time = reverse_endianess_uint16_t(*(int16_t*)(d + 30)); + c->end_time = reverse_endianess_uint16_t(*(int16_t*)(d + 32)); + } + else { + c->type = *(uint32_t*)d; + c->repeat = *(uint32_t*)(d + 4) != 0; + c->flags = *(uint32_t*)(d + 8); + c->random_range = *(float_t*)(d + 12); + *keys_count = *(int16_t*)(d + 28); + c->start_time = *(int16_t*)(d + 30); + c->end_time = *(int16_t*)(d + 32); + } + } } else { - c->type = data[0]; - c->repeat = data[1] != 0; - c->flags = data[2]; - if (c->version == 1) - c->max_rand = *(float_t*)&data[3]; - else + if (use_big_endian) { + c->type = reverse_endianess_uint32_t(*(uint32_t*)d); + c->repeat = reverse_endianess_uint32_t(*(uint32_t*)(d + 4)) != 0; + c->flags = reverse_endianess_uint32_t(*(uint32_t*)(d + 8)); + c->random_range = reverse_endianess_float_t(*(float_t*)(d + 12)); + *keys_count = reverse_endianess_uint16_t(*(int16_t*)(d + 16)); + c->start_time = reverse_endianess_uint16_t(*(int16_t*)(d + 18)); + c->end_time = reverse_endianess_uint16_t(*(int16_t*)(d + 20)); + } + else { + c->type = *(uint32_t*)d; + c->repeat = *(uint32_t*)(d + 4) != 0; + c->flags = *(uint32_t*)(d + 8); + c->random_range = *(float_t*)(d + 12); + *keys_count = *(int16_t*)(d + 16); + c->start_time = *(int16_t*)(d + 18); + c->end_time = *(int16_t*)(d + 20); + } + + if (c->version == 0) switch (c->type) { case GLITTER_CURVE_ROTATION_X: case GLITTER_CURVE_ROTATION_Y: case GLITTER_CURVE_ROTATION_Z: - c->max_rand = 0.0f; - break; - default: - c->max_rand = *(float_t*)&data[3]; + c->random_range = 0.0f; break; } - *keys_count = ((uint16_t*)data)[8]; - c->start_time = (float_t)((uint16_t*)data)[9]; - c->end_time = (float_t)((uint16_t*)data)[10]; } } diff --git a/src/CRE/Glitter/curve.h b/src/CRE/Glitter/curve.h index a777b956..74c36caf 100644 --- a/src/CRE/Glitter/curve.h +++ b/src/CRE/Glitter/curve.h @@ -7,9 +7,16 @@ #include "glitter.h" -extern glitter_curve* FASTCALL glitter_curve_init(); -extern bool FASTCALL glitter_curve_get_value(glitter_curve* c, - float_t frame, float_t* value, int32_t random); -extern void FASTCALL glitter_curve_parse_file(f2_struct* st, vector_ptr_glitter_curve* vec); -extern void FASTCALL glitter_curve_unparse_file(f2_struct* st, glitter_curve* c, bool use_big_endian); +extern glitter_curve* FASTCALL glitter_curve_init(GPM); +extern glitter_curve* FASTCALL glitter_curve_copy(GPM, glitter_curve* c); +extern bool FASTCALL glitter_curve_get_value(GPM, glitter_curve* c, + float_t frame, float_t* value, int32_t random_value, glitter_random* random); +extern bool FASTCALL glitter_curve_parse_file(GPM, + f2_struct* st, uint32_t version, glitter_curve** c); +#if defined(CRE_DEV) || defined(CLOUD_DEV) +extern void FASTCALL glitter_curve_recalculate(GPM, + glitter_curve* curve, vector_glitter_curve_key* dest); +#endif +extern bool FASTCALL glitter_curve_unparse_file(GPM, + f2_struct* st, glitter_curve* c); extern void FASTCALL glitter_curve_dispose(glitter_curve* c); diff --git a/src/CRE/Glitter/curve_get_value.c b/src/CRE/Glitter/curve_get_value.c new file mode 100644 index 00000000..74177674 --- /dev/null +++ b/src/CRE/Glitter/curve_get_value.c @@ -0,0 +1,198 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "curve.h" +#include "random.h" + +static void FASTCALL glitter_curve_get_key_indexes(vector_glitter_curve_key* keys, + float_t frame, size_t* curr, size_t* next); +static float_t FASTCALL glitter_curve_interpolate(GPM, glitter_curve* c, float_t frame, + glitter_curve_key* curr, glitter_curve_key* next, glitter_key_type key_type, glitter_random* random); +static float_t FASTCALL glitter_curve_randomize(GPM, + glitter_curve* c, float_t value, glitter_random* random); +static float_t FASTCALL glitter_curve_randomize_key(GPM, + glitter_curve* c, glitter_curve_key* key, glitter_random* random); + +bool FASTCALL glitter_curve_get_value(GPM, glitter_curve* c, + float_t frame, float_t* value, int32_t random_value, glitter_random* random) { + size_t keys_count; + int32_t random_val; + bool negate; + float_t _value; + + keys_count = c->keys.end - c->keys.begin; + if (!keys_count) + return false; + + random_val = glitter_random_get_value(random); + glitter_random_set_value(random, random_value); + negate = c->flags & GLITTER_CURVE_NEGATE + && glitter_random_get_int_min_max(GPM_VAL, random, 0, 0xFFFF) > 0x7FFF; + if (c->flags & GLITTER_CURVE_STEP) + glitter_random_set_value(random, random_val + 1); + + if (keys_count == 1) { + glitter_curve_key* key = &c->keys.begin[keys_count - 1]; + _value = glitter_curve_randomize_key(GPM_VAL, c, key, random); + goto End; + } + + float_t start_time = (float_t)c->start_time; + float_t end_time = (float_t)c->end_time; + if (c->repeat && (start_time > frame || frame >= end_time)) { + float_t t = (frame - start_time) / (end_time - start_time); + t = t <= 0.0f ? (float_t)(int32_t)t - 1.0f : (float_t)(int32_t)t; + frame -= t * (end_time - start_time); + } + + if (end_time <= frame) { + glitter_curve_key* key = &c->keys.begin[keys_count - 1]; + _value = glitter_curve_randomize_key(GPM_VAL, c, key, random); + } + else if (start_time > frame) { + glitter_curve_key* key = &c->keys.begin[0]; + _value = glitter_curve_randomize_key(GPM_VAL, c, key, random); + } + else if (c->flags & GLITTER_CURVE_BAKED) { + size_t key_index; + if (frame >= end_time) + key_index = keys_count - 1; + else if (frame > start_time) { + key_index = (size_t)frame - c->start_time; + if (glt_type == GLITTER_F2) + key_index /= 2; + + if (key_index >= keys_count) + key_index = keys_count - 1; + } + else + key_index = 0; + + glitter_curve_key* key = &c->keys.begin[key_index]; + _value = glitter_curve_randomize_key(GPM_VAL, c, key, random); + } + else { + size_t curr_key_index = 0; + size_t next_key_index = 0; + if (keys_count > 3) + glitter_curve_get_key_indexes(&c->keys, frame, &curr_key_index, &next_key_index); + else if (keys_count == 3 && frame >= c->keys.begin[1].frame) { + curr_key_index = 1; + next_key_index = 2; + } + else { + curr_key_index = 0; + next_key_index = 1; + } + glitter_curve_key* curr_key = &c->keys.begin[curr_key_index]; + glitter_curve_key* next_key = &c->keys.begin[next_key_index]; + _value = glitter_curve_interpolate(GPM_VAL, c, frame, curr_key, next_key, curr_key->type, random); + } + +End: + _value = glitter_curve_randomize(GPM_VAL, c, _value, random); + *value = negate ? -_value : _value; + glitter_random_set_value(random, random_val + 1); + return true; +} + +static void FASTCALL glitter_curve_get_key_indexes(vector_glitter_curve_key* keys, + float_t frame, size_t* curr, size_t* next) { + size_t v4; + glitter_curve_key* v6; + size_t count; + size_t v9; + size_t v10; + + count = keys->end - keys->begin; + if (count <= 1) { + *curr = 0; + *next = 0; + return; + } + + v4 = 0; + v6 = keys->begin; + v9 = count - 1; + v10 = v9 / 2; + while (v4 <= v9) { + v10 = (v9 + v4) / 2; + if (frame <= v6[(v10 + 1) % count].frame) { + if (frame >= v6[v10].frame) + goto LABEL_12; + v9 = v10 - 1; + } + else + v4 = v10 + 1; + } + + if (frame > v6[v10].frame) { + LABEL_12: + *curr = v10; + *next = v10 + 1; + } + else { + *curr = v10 - 1; + *next = v10; + } + *next %= count; +} + +static float_t FASTCALL glitter_curve_interpolate(GPM, glitter_curve* c, float_t frame, + glitter_curve_key* curr, glitter_curve_key* next, glitter_key_type key_type, glitter_random* random) { + float_t next_val; + float_t curr_val; + float_t val; + + if (key_type == GLITTER_KEY_CONSTANT) + return glitter_curve_randomize_key(GPM_VAL, c, curr, random); + + float_t df = frame - (float_t)curr->frame; + float_t t = df / (float_t)(next->frame - curr->frame); + if (key_type == GLITTER_KEY_HERMITE) { + float_t t_1 = t - 1.0f; + next_val = glitter_curve_randomize_key(GPM_VAL, c, next, random); + curr_val = glitter_curve_randomize_key(GPM_VAL, c, curr, random); + val = glitter_curve_randomize_key(GPM_VAL, c, curr, random); + val += t * t * (3.0f - 2.0f * t) * (next_val - curr_val) + + (t_1 * curr->tangent2 + t * next->tangent1) * df * t_1; + } + else { + curr_val = glitter_curve_randomize_key(GPM_VAL, c, curr, random); + next_val = glitter_curve_randomize_key(GPM_VAL, c, next, random); + val = curr_val + (next_val - curr_val) * t; + } + return val; +} + +static float_t FASTCALL glitter_curve_randomize(GPM, + glitter_curve* c, float_t value, glitter_random* random) { + float_t rand; + + if (~c->flags & GLITTER_CURVE_RANDOM_RANGE) + return value; + + rand = glitter_random_get_float_min_max(GPM_VAL, random, + c->flags & GLITTER_CURVE_RANDOM_RANGE_NEGATE ? -c->random_range : 0.0f, c->random_range); + + if (c->flags & GLITTER_CURVE_RANDOM_RANGE_MULT) + rand *= value * 0.01f; + return rand + value; +} + +static float_t FASTCALL glitter_curve_randomize_key(GPM, + glitter_curve* c, glitter_curve_key* key, glitter_random* random) { + float_t rand; + + if (~c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) + return key->value; + + rand = glitter_random_get_float_min_max(GPM_VAL, random, + c->flags & GLITTER_CURVE_RANDOM_RANGE_NEGATE ? -key->random_range : 0.0f, key->random_range); + + if (c->flags & GLITTER_CURVE_RANDOM_RANGE_MULT) + rand *= key->value * 0.01f; + return rand + key->value; +} diff --git a/src/CRE/Glitter/diva_effect.c b/src/CRE/Glitter/diva_effect.c index 464ce4ab..8991bc2f 100644 --- a/src/CRE/Glitter/diva_effect.c +++ b/src/CRE/Glitter/diva_effect.c @@ -6,21 +6,19 @@ #include "diva_effect.h" #include "effect_group.h" -extern glitter_particle_manager* gpm; - -bool FASTCALL glitter_diva_effect_parse_file(glitter_file_reader* fr, f2_struct* st) { +bool FASTCALL glitter_diva_effect_parse_file(GPM, glitter_file_reader* fr, f2_struct* st) { glitter_effect_group* effect_group; if (!st || !st->header.data_size) return false; - effect_group = glitter_effect_group_init(); + effect_group = glitter_effect_group_init(GPM_VAL); effect_group->hash = fr->hash; effect_group->emission = fr->emission; - if (fr->emission <= 0.0) + if (fr->emission <= 0.0f) effect_group->emission = gpm->emission; effect_group->version = st->header.version; - if (!glitter_effect_group_parse_file(effect_group, st)) { + if (!glitter_effect_group_parse_file(GPM_VAL, effect_group, st)) { glitter_effect_group_dispose(effect_group); return false; } @@ -28,7 +26,7 @@ bool FASTCALL glitter_diva_effect_parse_file(glitter_file_reader* fr, f2_struct* return true; } -bool FASTCALL glitter_diva_effect_unparse_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian) { - return glitter_effect_group_unparse_file(a1, st, use_big_endian); +bool FASTCALL glitter_diva_effect_unparse_file(GPM, glitter_effect_group* a1, f2_struct* st) { + return glitter_effect_group_unparse_file(GPM_VAL, a1, st); } diff --git a/src/CRE/Glitter/diva_effect.h b/src/CRE/Glitter/diva_effect.h index 7727875e..89871257 100644 --- a/src/CRE/Glitter/diva_effect.h +++ b/src/CRE/Glitter/diva_effect.h @@ -7,5 +7,5 @@ #include "glitter.h" -extern bool FASTCALL glitter_diva_effect_parse_file(glitter_file_reader* fr, f2_struct* st); -extern bool FASTCALL glitter_diva_effect_unparse_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian); +extern bool FASTCALL glitter_diva_effect_parse_file(GPM, glitter_file_reader* fr, f2_struct* st); +extern bool FASTCALL glitter_diva_effect_unparse_file(GPM, glitter_effect_group* a1, f2_struct* st); diff --git a/src/CRE/Glitter/diva_list.c b/src/CRE/Glitter/diva_list.c index e2edf31d..3f1d9a4e 100644 --- a/src/CRE/Glitter/diva_list.c +++ b/src/CRE/Glitter/diva_list.c @@ -25,17 +25,17 @@ bool FASTCALL glitter_diva_list_parse_file(glitter_effect_group* a1, f2_struct* return true; } -bool FASTCALL glitter_diva_list_unparse_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian) { +bool FASTCALL glitter_diva_list_unparse_file(glitter_effect_group* a1, f2_struct* st) { memset(st, 0, sizeof(f2_struct)); - f2_struct* s = f2_struct_init(); - if (!glitter_list_pack_file(a1, s, use_big_endian)) { - f2_struct_dispose(s); + f2_struct s; + memset(&s, 0, sizeof(f2_struct)); + if (!glitter_list_pack_file(a1, &s)) { + f2_struct_free(&s); return false; } - vector_f2_struct_push_back(&st->sub_structs, s); - free(s); + vector_f2_struct_push_back(&st->sub_structs, &s); st->header.signature = 0x5453494C; st->header.length = 0x20; diff --git a/src/CRE/Glitter/diva_list.h b/src/CRE/Glitter/diva_list.h index 69515068..4c888a86 100644 --- a/src/CRE/Glitter/diva_list.h +++ b/src/CRE/Glitter/diva_list.h @@ -8,4 +8,4 @@ #include "glitter.h" extern bool FASTCALL glitter_diva_list_parse_file(glitter_effect_group* a1, f2_struct* st); -extern bool FASTCALL glitter_diva_list_unparse_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian); +extern bool FASTCALL glitter_diva_list_unparse_file(glitter_effect_group* a1, f2_struct* st); diff --git a/src/CRE/Glitter/diva_resource.c b/src/CRE/Glitter/diva_resource.c index 6e44794b..2e974fda 100644 --- a/src/CRE/Glitter/diva_resource.c +++ b/src/CRE/Glitter/diva_resource.c @@ -25,17 +25,17 @@ bool FASTCALL glitter_diva_resource_parse_file(glitter_effect_group* a1, f2_stru return true; } -bool FASTCALL glitter_diva_resource_unparse_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian) { +bool FASTCALL glitter_diva_resource_unparse_file(glitter_effect_group* a1, f2_struct* st) { memset(st, 0, sizeof(f2_struct)); - f2_struct* s = f2_struct_init(); - if (!glitter_texture_resource_pack_file(a1, s, use_big_endian)) { - f2_struct_dispose(s); + f2_struct s; + memset(&s, 0, sizeof(f2_struct)); + if (!glitter_texture_resource_pack_file(a1, &s)) { + f2_struct_free(&s); return false; } - vector_f2_struct_push_back(&st->sub_structs, s); - free(s); + vector_f2_struct_push_back(&st->sub_structs, &s); st->header.signature = 0x53525644; st->header.length = 0x20; diff --git a/src/CRE/Glitter/diva_resource.h b/src/CRE/Glitter/diva_resource.h index e5e9f849..25debc1c 100644 --- a/src/CRE/Glitter/diva_resource.h +++ b/src/CRE/Glitter/diva_resource.h @@ -8,4 +8,4 @@ #include "glitter.h" extern bool FASTCALL glitter_diva_resource_parse_file(glitter_effect_group* a1, f2_struct* st); -extern bool FASTCALL glitter_diva_resource_unparse_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian); +extern bool FASTCALL glitter_diva_resource_unparse_file(glitter_effect_group* a1, f2_struct* st); diff --git a/src/CRE/Glitter/effect.c b/src/CRE/Glitter/effect.c index 3452ed6e..1bf90148 100644 --- a/src/CRE/Glitter/effect.c +++ b/src/CRE/Glitter/effect.c @@ -8,28 +8,58 @@ #include "curve.h" #include "emitter.h" -extern glitter_particle_manager* gpm; +static bool FASTCALL glitter_effect_pack_file(GPM, f2_struct* st, glitter_effect* a3); +static bool FASTCALL glitter_effect_unpack_file(GPM, + void* data, glitter_effect* a3, bool use_big_endian); -static bool FASTCALL glitter_effect_pack_file(f2_struct* st, glitter_effect* a3, bool use_big_endian); -static bool FASTCALL glitter_effect_unpack_file(int32_t* data, glitter_effect* a3, bool use_big_endian); - -glitter_effect* FASTCALL glitter_effect_init() { +glitter_effect* FASTCALL glitter_effect_init(GPM) { glitter_effect* e = force_malloc(sizeof(glitter_effect)); - e->data.name_hash = gpm->f2 ? 0x0CAD3078 : 0xCBF29CE44FD0BFC1; + e->scale = vec3_identity; + e->data.start_time = 0; + e->data.ext_anim = 0; + e->data.flags = 0; + e->data.name_hash = glt_type != GLITTER_AFT ? hash_murmurhash_empty : hash_fnv1a64_empty; + e->data.seed = 0; return e; } -bool FASTCALL glitter_effect_parse_file(glitter_effect_group* a1, - f2_struct* st, vector_ptr_glitter_effect* vec) { +glitter_effect* FASTCALL glitter_effect_copy(GPM, glitter_effect* e) { + if (!e) + return 0; + + glitter_effect* ec = force_malloc(sizeof(glitter_effect)); + *ec = *e; + + if (e->data.ext_anim) { + ec->data.ext_anim = force_malloc(sizeof(glitter_effect_ext_anim)); + memcpy(ec->data.ext_anim, e->data.ext_anim, sizeof(glitter_effect_ext_anim)); + } + + ec->emitters = (vector_ptr_glitter_emitter){ 0, 0, 0 }; + vector_ptr_glitter_emitter_append(&ec->emitters, e->emitters.end - e->emitters.begin); + for (glitter_emitter** i = e->emitters.begin; i != e->emitters.end; i++) + if (*i) { + glitter_emitter* e = glitter_emitter_copy(GPM_VAL, *i); + if (e) + vector_ptr_glitter_emitter_push_back(&ec->emitters, &e); + } + + ec->curve = (vector_ptr_glitter_curve){ 0, 0, 0 }; + glitter_animation_copy(GPM_VAL, &e->curve, &ec->curve); + return ec; +} + +bool FASTCALL glitter_effect_parse_file(GPM, + glitter_effect_group* a1, f2_struct* st, vector_ptr_glitter_effect* vec) { f2_struct* i; glitter_effect* effect; if (!st || !st->header.data_size) return false; - effect = glitter_effect_init(); + effect = glitter_effect_init(GPM_VAL); effect->version = st->header.version; - if (!glitter_effect_unpack_file(st->data, effect, st->header.use_big_endian)) { + if (!glitter_effect_unpack_file(GPM_VAL, st->data, effect, st->header.use_big_endian)) { glitter_effect_dispose(effect); return false; } @@ -38,253 +68,439 @@ bool FASTCALL glitter_effect_parse_file(glitter_effect_group* a1, if (!i->header.data_size) continue; - if (i->header.signature == 0x4D494E41) - glitter_animation_parse_file(i, &effect->curve); - else if (i->header.signature == 0x54494D45) - glitter_emitter_parse_file(a1, i, &effect->emitters, effect); + if (i->header.signature == reverse_endianess_uint32_t('ANIM')) + glitter_animation_parse_file(GPM_VAL, i, &effect->curve, glitter_effect_curve_flags); + else if (i->header.signature == reverse_endianess_uint32_t('EMIT')) + glitter_emitter_parse_file(GPM_VAL, a1, i, &effect->emitters, effect); } vector_ptr_glitter_effect_push_back(vec, &effect); return true; } -bool FASTCALL glitter_effect_unparse_file(glitter_effect_group* a1, - f2_struct* st, glitter_effect* a3, bool use_big_endian) { - if (!glitter_effect_pack_file(st, a3, use_big_endian)) +bool FASTCALL glitter_effect_unparse_file(GPM, + glitter_effect_group* a1, f2_struct* st, glitter_effect* a3) { + if (!glitter_effect_pack_file(GPM_VAL, st, a3)) return false; f2_struct s; - if (glitter_animation_unparse_file(&s, &a3->curve, use_big_endian)) + if (glitter_animation_unparse_file(GPM_VAL, &s, &a3->curve, glitter_effect_curve_flags)) vector_f2_struct_push_back(&st->sub_structs, &s); - for (glitter_emitter** i = a3->emitters.begin; i != a3->emitters.end; i++) - if (*i && glitter_emitter_unparse_file(a1, &s, *i, a3, use_big_endian)) + for (glitter_emitter** i = a3->emitters.begin; i != a3->emitters.end; i++) { + if (!*i) + continue; + + f2_struct s; + if (glitter_emitter_unparse_file(GPM_VAL, a1, &s, *i, a3)) vector_f2_struct_push_back(&st->sub_structs, &s); + } return true; } void FASTCALL glitter_effect_dispose(glitter_effect* e) { - free(e->data.a3da); - vector_ptr_glitter_curve_free(&e->curve, (void*)glitter_curve_dispose); - vector_ptr_glitter_emitter_free(&e->emitters, (void*)glitter_emitter_dispose); + free(e->data.ext_anim); + vector_ptr_glitter_curve_free(&e->curve, glitter_curve_dispose); + vector_ptr_glitter_emitter_free(&e->emitters, glitter_emitter_dispose); free(e); } -static bool FASTCALL glitter_effect_pack_file(f2_struct* st, glitter_effect* a2, bool use_big_endian) { +static bool FASTCALL glitter_effect_pack_file(GPM, f2_struct* st, glitter_effect* a2) { size_t l; - int32_t* d; - glitter_effect_a3da* a3da; + size_t d; + glitter_effect_ext_anim* ext_anim; glitter_effect_file_flag flags; if (a2->version != 6 && a2->version != 7) return false; - a3da = a2->data.a3da; + ext_anim = a2->data.ext_anim; memset(st, 0, sizeof(f2_struct)); - l = 52; + l = 0; - if (a2->version == 7) - l += 4; + uint32_t o; + vector_enrs_entry e = { 0, 0, 0 }; + enrs_entry ee; - if (a2->data.flags & GLITTER_EFFECT_FLAG_LOCAL) - l += 4; - else if (a3da) - if (a3da->flags & GLITTER_EFFECT_A3DA_FLAG_SET_A3DA_BY_OBJECT_INDEX) - l += 16; - else - l += 144; - - l = align_val(l, 0x10); - d = force_malloc(l); - st->length = l; - st->data = d; - - flags = 0; - if (a2->data.flags & GLITTER_EFFECT_FLAG_ALPHA) - flags |= GLITTER_EFFECT_FILE_FLAG_ALPHA; - - if (a2->data.flags & GLITTER_EFFECT_FLAG_FOG) - flags |= GLITTER_EFFECT_FILE_FLAG_FOG; - else if (a2->data.flags & GLITTER_EFFECT_FLAG_FOG_HEIGHT) - flags |= GLITTER_EFFECT_FILE_FLAG_FOG_HEIGHT; - - if (a2->data.flags & GLITTER_EFFECT_FLAG_EMISSION) - flags |= GLITTER_EFFECT_FILE_FLAG_EMISSION; - - if (use_big_endian) { - *(uint64_t*)d = reverse_endianess_uint64_t(a2->data.name_hash); - d[2] = reverse_endianess_int32_t((int32_t)roundf(a2->data.appear_time)); - d[3] = reverse_endianess_int32_t((int32_t)roundf(a2->data.life_time)); - d[4] = reverse_endianess_int32_t((int32_t)roundf(a2->data.start_time)); - d[5] = 0xFFFFFFFF; - d[6] = reverse_endianess_int32_t(a2->data.flags & GLITTER_EFFECT_FLAG_LOOP ? 1 : 0); - *(float_t*)&d[7] = reverse_endianess_float_t(a2->translation.x); - *(float_t*)&d[8] = reverse_endianess_float_t(a2->translation.y); - *(float_t*)&d[9] = reverse_endianess_float_t(a2->translation.z); - *(float_t*)&d[10] = reverse_endianess_float_t(a2->rotation.x); - *(float_t*)&d[11] = reverse_endianess_float_t(a2->rotation.y); - *(float_t*)&d[12] = reverse_endianess_float_t(a2->rotation.z); - d[13] = reverse_endianess_int32_t(flags); - } - else { - *(uint64_t*)d = a2->data.name_hash; - d[2] = (int32_t)roundf(a2->data.appear_time); - d[3] = (int32_t)roundf(a2->data.life_time); - d[4] = (int32_t)roundf(a2->data.start_time); - d[5] = 0xFFFFFFFF; - d[6] = a2->data.flags & GLITTER_EFFECT_FLAG_LOOP ? 1 : 0; - *(vec3*)&d[7] = a2->translation; - *(vec3*)&d[10] = a2->rotation; - d[13] = flags; - } + ee = (enrs_entry){ 0, 2, 56, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_QWORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 12, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 56; if (a2->version == 7) { - if (use_big_endian) - *(float_t*)&d[14] = reverse_endianess_float_t(a2->data.emission); - else - *(float_t*)&d[14] = a2->data.emission; - d++; + ee = (enrs_entry){ 0, 1, 4, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 4; } - if (a2->data.flags & GLITTER_EFFECT_FLAG_LOCAL) - d[14] = 1; - else if (a3da) - if (a3da->flags & GLITTER_EFFECT_A3DA_FLAG_SET_A3DA_BY_OBJECT_INDEX) { - d[14] = 2; - d += 15; - glitter_effect_a3da_flag a3da_flag = a3da->flags & ~GLITTER_EFFECT_A3DA_FLAG_SET_A3DA_BY_OBJECT_INDEX; - if (use_big_endian) { - d[0] = reverse_endianess_int32_t(a3da->object_index); - d[1] = reverse_endianess_int32_t(a3da_flag); - d[2] = reverse_endianess_int32_t(a3da->index); - } - else { - d[0] = a3da->object_index; - d[1] = a3da_flag; - d[2] = a3da->index; - } + ee = (enrs_entry){ 0, 1, 4, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 4; + + if (~a2->data.flags & GLITTER_EFFECT_LOCAL && ext_anim) + if (ext_anim->flags & GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM) { + ee = (enrs_entry){ 0, 1, 12, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 3, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 12; } else { - d[14] = 3; - d += 15; - if (use_big_endian) { - *(uint64_t*)d = reverse_endianess_uint64_t(a3da->object_hash); - d[2] = reverse_endianess_int32_t(a3da->flags); - } - else { - *(uint64_t*)d = a3da->object_hash; - d[2] = a3da->flags; - a3da->flags = d[2]; - } - memcpy((char*)(d + 12), a3da->mesh_name, 128); + ee = (enrs_entry){ 0, 2, 140, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_QWORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 140; } - st->header.signature = 0x54434645; + l = align_val(l, 0x10); + d = (size_t)force_malloc(l); + st->length = l; + st->data = (void*)d; + st->enrs = e; + + flags = 0; + if (a2->data.flags & GLITTER_EFFECT_ALPHA) + flags |= GLITTER_EFFECT_FILE_ALPHA; + + if (a2->data.flags & GLITTER_EFFECT_FOG) + flags |= GLITTER_EFFECT_FILE_FOG; + else if (a2->data.flags & GLITTER_EFFECT_FOG_HEIGHT) + flags |= GLITTER_EFFECT_FILE_FOG_HEIGHT; + + if (a2->data.flags & GLITTER_EFFECT_EMISSION) + flags |= GLITTER_EFFECT_FILE_EMISSION; + + *(uint64_t*)d = glt_type != GLITTER_AFT + ? hash_char_murmurhash(a2->name, 0, false) : hash_char_fnv1a64(a2->name);; + *(int32_t*)(d + 8) = a2->data.appear_time; + *(int32_t*)(d + 12) = a2->data.life_time; + *(int32_t*)(d + 16) = a2->data.start_time; + *(int32_t*)(d + 20) = 0xFFFFFFFF; + *(int32_t*)(d + 24) = a2->data.flags & GLITTER_EFFECT_LOOP ? 1 : 0; + *(vec3*)(d + 28) = a2->translation; + *(vec3*)(d + 40) = a2->rotation; + *(int32_t*)(d + 52) = flags; + d += 56; + + if (a2->version == 7) { + *(float_t*)d = a2->data.emission; + d += 4; + } + + if (a2->data.flags & GLITTER_EFFECT_LOCAL) { + *(int32_t*)d = 1; + d += 4; + } + else if (ext_anim) + if (ext_anim->flags & GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM) { + *(int32_t*)d = 2; + d += 4; + glitter_effect_ext_anim_flag ext_anim_flag = ext_anim->flags & ~GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM; + *(int32_t*)d = ext_anim->index; + *(int32_t*)(d + 4) = ext_anim_flag; + *(int32_t*)(d + 8) = ext_anim->node_index; + } + else { + *(int32_t*)d = 3; + d += 4; + *(uint64_t*)d = ext_anim->object_hash; + *(int32_t*)(d + 8) = ext_anim->flags; + memcpy((char*)(d + 12), ext_anim->mesh_name, 128); + } + else { + *(int32_t*)d = 0; + d += 4; + } + + st->header.signature = reverse_endianess_uint32_t('EFCT'); st->header.length = 0x20; - st->header.use_big_endian = use_big_endian ? true : false; + st->header.use_big_endian = false; st->header.use_section_size = true; st->header.version = a2->version; return true; } -static bool FASTCALL glitter_effect_unpack_file(int32_t* data, glitter_effect* a2, bool use_big_endian) { - glitter_effect_a3da* a3da; +static bool FASTCALL glitter_effect_unpack_file(GPM, + void* data, glitter_effect* a2, bool use_big_endian) { + size_t d; + glitter_effect_ext_anim* ext_anim; glitter_effect_file_flag flags; - a2->scale = vec3_identity; - a2->data.start_time = 0.0f; - a2->data.a3da = 0; - a2->data.flags = 0; - a2->data.name_hash = gpm->f2 ? 0x0CAD3078 : 0xCBF29CE44FD0BFC1; - if (a2->version != 6 && a2->version != 7) - return false; + if (glt_type == GLITTER_X) { + a2->scale = vec3_identity; + a2->data.start_time = 0; + a2->data.ext_anim = 0; + a2->data.flags = 0; + a2->data.name_hash = hash_murmurhash_empty; + a2->data.seed = 0; - if (use_big_endian) { - a2->data.name_hash = reverse_endianess_uint64_t(*(uint64_t*)data); - a2->data.appear_time = (float_t)reverse_endianess_int32_t(data[2]); - a2->data.life_time = (float_t)reverse_endianess_int32_t(data[3]); - a2->data.start_time = (float_t)reverse_endianess_int32_t(data[4]); - if (reverse_endianess_int32_t(data[6])) - a2->data.flags |= GLITTER_EFFECT_FLAG_LOOP; - a2->translation.x = reverse_endianess_float_t(*(float_t*)&data[7]); - a2->translation.y = reverse_endianess_float_t(*(float_t*)&data[8]); - a2->translation.z = reverse_endianess_float_t(*(float_t*)&data[9]); - a2->rotation.x = reverse_endianess_float_t(*(float_t*)&data[10]); - a2->rotation.y = reverse_endianess_float_t(*(float_t*)&data[11]); - a2->rotation.z = reverse_endianess_float_t(*(float_t*)&data[12]); - flags = reverse_endianess_int32_t(data[13]); - } - else { - a2->data.name_hash = *(uint64_t*)data; - a2->data.appear_time = (float_t)data[2]; - a2->data.life_time = (float_t)data[3]; - a2->data.start_time = (float_t)data[4]; - if (data[6]) - a2->data.flags |= GLITTER_EFFECT_FLAG_LOOP; - a2->translation = *(vec3*)&data[7]; - a2->rotation = *(vec3*)&data[10]; - flags = data[13]; - } + if (a2->version < 8 || a2->version > 12) + return false; - if (flags & GLITTER_EFFECT_FILE_FLAG_ALPHA) - a2->data.flags |= GLITTER_EFFECT_FLAG_ALPHA; - - if (flags & GLITTER_EFFECT_FILE_FLAG_FOG) - a2->data.flags |= GLITTER_EFFECT_FLAG_FOG; - else if (flags & GLITTER_EFFECT_FILE_FLAG_FOG_HEIGHT) - a2->data.flags |= GLITTER_EFFECT_FLAG_FOG_HEIGHT; - - if (flags & GLITTER_EFFECT_FILE_FLAG_EMISSION) - a2->data.flags |= GLITTER_EFFECT_FLAG_EMISSION; - - if (a2->version == 7) { - if (use_big_endian) - a2->data.emission = reverse_endianess_float_t(*(float_t*)&data[14]); - else - a2->data.emission = *(float_t*)&data[14]; - data++; - } - - if (data[14] == 1) - a2->data.flags |= GLITTER_EFFECT_FLAG_LOCAL; - else if (data[14] == 2) { - data += 15; - a3da = force_malloc(sizeof(glitter_effect_a3da)); - a2->data.a3da = a3da; - if (a3da) { - if (use_big_endian) { - a3da->object_index = reverse_endianess_int32_t(data[0]); - a3da->flags = reverse_endianess_int32_t(data[1]); - a3da->index = reverse_endianess_int32_t(data[2]); - } - else { - a3da->object_index = data[0]; - a3da->flags = data[1]; - a3da->index = data[2]; - } - a3da->flags |= GLITTER_EFFECT_A3DA_FLAG_SET_A3DA_BY_OBJECT_INDEX; - a3da->mesh_name[0] = 0; + d = (size_t)data; + if (use_big_endian) { + a2->data.name_hash = reverse_endianess_uint64_t(*(uint64_t*)d); + a2->data.appear_time = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + a2->data.life_time = reverse_endianess_int32_t(*(int32_t*)(d + 12)); + a2->data.start_time = reverse_endianess_int32_t(*(int32_t*)(d + 16)); + if (reverse_endianess_int32_t(*(int32_t*)(d + 24))) + a2->data.flags |= GLITTER_EFFECT_LOOP; + a2->translation.x = reverse_endianess_float_t(*(float_t*)(d + 28)); + a2->translation.y = reverse_endianess_float_t(*(float_t*)(d + 32)); + a2->translation.z = reverse_endianess_float_t(*(float_t*)(d + 36)); + a2->rotation.x = reverse_endianess_float_t(*(float_t*)(d + 40)); + a2->rotation.y = reverse_endianess_float_t(*(float_t*)(d + 44)); + a2->rotation.z = reverse_endianess_float_t(*(float_t*)(d + 48)); + flags = reverse_endianess_int32_t(*(int32_t*)(d + 52)); } - } - else if (data[14] == 3) { - data += 15; - //v10 = sub_14045A570(*(uint64_t*)data); - //if (v10 != -1) { - a3da = force_malloc(sizeof(glitter_effect_a3da)); - a2->data.a3da = a3da; - if (a3da) { - //a3da->object_index = v10; + else { + a2->data.name_hash = *(uint64_t*)data; + a2->data.appear_time = *(int32_t*)(d + 8); + a2->data.life_time = *(int32_t*)(d + 12); + a2->data.start_time = *(int32_t*)(d + 16); + if (*(int32_t*)(d + 24)) + a2->data.flags |= GLITTER_EFFECT_LOOP; + a2->translation = *(vec3*)(d + 28); + a2->rotation = *(vec3*)(d + 40); + flags = *(int32_t*)(d + 52); + } + + if (flags & GLITTER_EFFECT_FILE_ALPHA) + a2->data.flags |= GLITTER_EFFECT_ALPHA; + + if (flags & GLITTER_EFFECT_FILE_FOG) + a2->data.flags |= GLITTER_EFFECT_FOG; + else if (flags & GLITTER_EFFECT_FILE_FOG_HEIGHT) + a2->data.flags |= GLITTER_EFFECT_FOG_HEIGHT; + + if (flags & GLITTER_EFFECT_FILE_EMISSION) + a2->data.flags |= GLITTER_EFFECT_EMISSION; + + if (flags & GLITTER_EFFECT_FILE_USE_SEED) + a2->data.flags |= GLITTER_EFFECT_USE_SEED; + + if (a2->version != 8 && flags & 0x20) + a2->data.flags |= 0x80; + + if (use_big_endian) { + a2->data.emission = reverse_endianess_float_t(*(float_t*)(d + 56)); + a2->data.seed = reverse_endianess_int32_t(*(int32_t*)(d + 60)); + } + else { + a2->data.emission = *(float_t*)(d + 56); + a2->data.seed = *(int32_t*)(d + 60); + } + + int32_t type = a2->version != 8 ? *(int32_t*)(d + 76) : *(int32_t*)(d + 80); + if (use_big_endian) + type = reverse_endianess_int32_t(type); + d += a2->version != 8 ? 80 : 88; + + if (type == 1) + a2->data.flags |= GLITTER_EFFECT_LOCAL; + else if (type == 2) { + ext_anim = force_malloc(sizeof(glitter_effect_ext_anim)); + a2->data.ext_anim = ext_anim; + if (ext_anim) { if (use_big_endian) { - a3da->object_hash = reverse_endianess_uint64_t(*(uint64_t*)data); - a3da->flags = reverse_endianess_int32_t(data[2]); + ext_anim->index = reverse_endianess_int32_t(*(int32_t*)d); + ext_anim->flags = reverse_endianess_int32_t(*(int32_t*)(d + 4)); + ext_anim->node_index = reverse_endianess_int32_t(*(int32_t*)(d + 8)); } else { - a3da->object_hash = *(uint64_t*)data; - a3da->flags = data[2]; + ext_anim->index = *(int32_t*)d; + ext_anim->flags = *(int32_t*)(d + 4); + ext_anim->node_index = *(int32_t*)(d + 8); } - a3da->index = 201; - memcpy(a3da->mesh_name, (char*)(data + 12), 128); + ext_anim->flags |= GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM; + ext_anim->mesh_name[0] = 0; } - //} + } + else if (type == 3) { + if (a2->version == 8) { + ext_anim = force_malloc(sizeof(glitter_effect_ext_anim)); + a2->data.ext_anim = ext_anim; + if (ext_anim) { + if (use_big_endian) { + ext_anim->object_hash = reverse_endianess_uint64_t(*(uint64_t*)d); + ext_anim->flags = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + } + else { + ext_anim->object_hash = *(uint64_t*)d; + ext_anim->flags = *(int32_t*)(d + 8); + } + ext_anim->instance_id = 0; + ext_anim->some_hash = 0xCAD3078; + ext_anim->index = -1; + ext_anim->node_index = 18; + if (*(char*)(d + 12)) { + strncpy_s(ext_anim->mesh_name, 0x80, (char*)(d + 20), 0x80); + ext_anim->mesh_name[0x7F] = '\0'; + } + else + ext_anim->mesh_name[0] = 0; + } + } + else if (a2->version == 10) { + ext_anim = force_malloc(sizeof(glitter_effect_ext_anim)); + a2->data.ext_anim = ext_anim; + if (ext_anim) { + if (use_big_endian) { + ext_anim->object_hash = reverse_endianess_uint64_t(*(uint64_t*)d); + ext_anim->flags = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + } + else { + ext_anim->object_hash = *(uint64_t*)d; + ext_anim->flags = *(int32_t*)(d + 8); + } + ext_anim->instance_id = 0; + ext_anim->some_hash = 0xCAD3078; + ext_anim->index = -1; + ext_anim->node_index = 18; + if (*(char*)(d + 16)) { + strncpy_s(ext_anim->mesh_name, 0x80, (char*)(d + 16), 0x80); + ext_anim->mesh_name[0x7F] = '\0'; + } + else + ext_anim->mesh_name[0] = 0; + } + } + else { + ext_anim = force_malloc(sizeof(glitter_effect_ext_anim)); + a2->data.ext_anim = ext_anim; + if (ext_anim) { + if (use_big_endian) { + ext_anim->object_hash = reverse_endianess_uint64_t(*(uint64_t*)d); + ext_anim->flags = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + ext_anim->instance_id = reverse_endianess_int32_t(*(int32_t*)(d + 12)); + ext_anim->some_hash = reverse_endianess_uint64_t(*(uint64_t*)(d + 16)); + } + else { + ext_anim->object_hash = *(uint64_t*)d; + ext_anim->flags = *(int32_t*)(d + 8); + ext_anim->instance_id = *(int32_t*)(d + 12); + ext_anim->some_hash = *(uint64_t*)(d + 16); + } + ext_anim->index = -1; + ext_anim->node_index = 18; + if (*(char*)(d + 32)) { + strncpy_s(ext_anim->mesh_name, 0x80, (char*)(d + 32), 0x80); + ext_anim->mesh_name[0x7F] = '\0'; + } + else + ext_anim->mesh_name[0] = 0; + } + } + } + } + else { + a2->scale = vec3_identity; + a2->data.start_time = 0; + a2->data.ext_anim = 0; + a2->data.flags = 0; + a2->data.name_hash = glt_type != GLITTER_AFT ? hash_murmurhash_empty : hash_fnv1a64_empty; + a2->data.seed = 0; + + if (a2->version != 6 && a2->version != 7) + return false; + + d = (size_t)data; + if (use_big_endian) { + a2->data.name_hash = reverse_endianess_uint64_t(*(uint64_t*)d); + a2->data.appear_time = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + a2->data.life_time = reverse_endianess_int32_t(*(int32_t*)(d + 12)); + a2->data.start_time = reverse_endianess_int32_t(*(int32_t*)(d + 16)); + if (reverse_endianess_int32_t(*(int32_t*)(d + 24))) + a2->data.flags |= GLITTER_EFFECT_LOOP; + a2->translation.x = reverse_endianess_float_t(*(float_t*)(d + 28)); + a2->translation.y = reverse_endianess_float_t(*(float_t*)(d + 32)); + a2->translation.z = reverse_endianess_float_t(*(float_t*)(d + 36)); + a2->rotation.x = reverse_endianess_float_t(*(float_t*)(d + 40)); + a2->rotation.y = reverse_endianess_float_t(*(float_t*)(d + 44)); + a2->rotation.z = reverse_endianess_float_t(*(float_t*)(d + 48)); + flags = reverse_endianess_int32_t(*(int32_t*)(d + 52)); + } + else { + a2->data.name_hash = *(uint64_t*)data; + a2->data.appear_time = *(int32_t*)(d + 8); + a2->data.life_time = *(int32_t*)(d + 12); + a2->data.start_time = *(int32_t*)(d + 16); + if (*(int32_t*)(d + 24)) + a2->data.flags |= GLITTER_EFFECT_LOOP; + a2->translation = *(vec3*)(d + 28); + a2->rotation = *(vec3*)(d + 40); + flags = *(int32_t*)(d + 52); + } + d += 56; + + if (flags & GLITTER_EFFECT_FILE_ALPHA) + a2->data.flags |= GLITTER_EFFECT_ALPHA; + + if (flags & GLITTER_EFFECT_FILE_FOG) + a2->data.flags |= GLITTER_EFFECT_FOG; + else if (flags & GLITTER_EFFECT_FILE_FOG_HEIGHT) + a2->data.flags |= GLITTER_EFFECT_FOG_HEIGHT; + + if (flags & GLITTER_EFFECT_FILE_EMISSION) + a2->data.flags |= GLITTER_EFFECT_EMISSION; + + if (a2->version == 7) { + if (use_big_endian) + a2->data.emission = reverse_endianess_float_t(*(float_t*)d); + else + a2->data.emission = *(float_t*)d; + d += 4; + } + + int32_t type = *(int32_t*)d; + if (use_big_endian) + type = reverse_endianess_int32_t(type); + d += 4; + + if (type == 1) + a2->data.flags |= GLITTER_EFFECT_LOCAL; + else if (type == 2) { + ext_anim = force_malloc(sizeof(glitter_effect_ext_anim)); + a2->data.ext_anim = ext_anim; + if (ext_anim) { + if (use_big_endian) { + ext_anim->index = reverse_endianess_int32_t(*(int32_t*)d); + ext_anim->flags = reverse_endianess_int32_t(*(int32_t*)(d + 4)); + ext_anim->node_index = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + } + else { + ext_anim->index = *(int32_t*)d; + ext_anim->flags = *(int32_t*)(d + 4); + ext_anim->node_index = *(int32_t*)(d + 8); + } + ext_anim->flags |= GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM; + ext_anim->mesh_name[0] = 0; + } + } + else if (type == 3) { + ext_anim = force_malloc(sizeof(glitter_effect_ext_anim)); + a2->data.ext_anim = ext_anim; + if (ext_anim) { + ext_anim->index = -1; + if (use_big_endian) { + ext_anim->object_hash = reverse_endianess_uint64_t(*(uint64_t*)d); + ext_anim->flags = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + } + else { + ext_anim->object_hash = *(uint64_t*)d; + ext_anim->flags = *(int32_t*)(d + 8); + } + ext_anim->node_index = 18; + if (*(char*)(d + 12)) { + strncpy_s(ext_anim->mesh_name, 0x80, (char*)(d + 12), 0x80); + ext_anim->mesh_name[0x7F] = 0; + } + else + ext_anim->mesh_name[0x00] = 0; + } + } } return true; } diff --git a/src/CRE/Glitter/effect.h b/src/CRE/Glitter/effect.h index 178175ba..74635fba 100644 --- a/src/CRE/Glitter/effect.h +++ b/src/CRE/Glitter/effect.h @@ -7,9 +7,10 @@ #include "glitter.h" -extern glitter_effect* FASTCALL glitter_effect_init(); -extern bool FASTCALL glitter_effect_parse_file(glitter_effect_group* a1, - f2_struct* st, vector_ptr_glitter_effect* vec); -extern bool FASTCALL glitter_effect_unparse_file(glitter_effect_group* a1, - f2_struct* st, glitter_effect* a3, bool use_big_endian); +extern glitter_effect* FASTCALL glitter_effect_init(GPM); +extern glitter_effect* FASTCALL glitter_effect_copy(GPM, glitter_effect* e); +extern bool FASTCALL glitter_effect_parse_file(GPM, + glitter_effect_group* a1, f2_struct* st, vector_ptr_glitter_effect* vec); +extern bool FASTCALL glitter_effect_unparse_file(GPM, + glitter_effect_group* a1, f2_struct* st, glitter_effect* a3); extern void FASTCALL glitter_effect_dispose(glitter_effect* e); diff --git a/src/CRE/Glitter/effect_group.c b/src/CRE/Glitter/effect_group.c index d0e65a4a..9f15ab09 100644 --- a/src/CRE/Glitter/effect_group.c +++ b/src/CRE/Glitter/effect_group.c @@ -8,18 +8,19 @@ #include "scene.h" #include "texture.h" -glitter_effect_group* FASTCALL glitter_effect_group_init() { +glitter_effect_group* FASTCALL glitter_effect_group_init(GPM) { glitter_effect_group* eg = force_malloc(sizeof(glitter_effect_group)); eg->emission = 1.0f; + eg->version = glt_type == GLITTER_X ? 0x0C : 0x09; return eg; } -bool FASTCALL glitter_effect_group_parse_file(glitter_effect_group* a1, f2_struct* st) { +bool FASTCALL glitter_effect_group_parse_file(GPM, glitter_effect_group* a1, f2_struct* st) { for (f2_struct* i = st->sub_structs.begin; i != st->sub_structs.end; i++) { if (!i->header.data_size) continue; - if (i->header.signature == 0x54434645 && !glitter_effect_parse_file(a1, i, &a1->effects)) + if (i->header.signature == 0x54434645 && !glitter_effect_parse_file(GPM_VAL, a1, i, &a1->effects)) return false; else if (i->header.signature == 0x53525644 && !glitter_texture_hashes_unpack_file(a1, i)) return false; @@ -27,21 +28,23 @@ bool FASTCALL glitter_effect_group_parse_file(glitter_effect_group* a1, f2_struc return true; } -bool FASTCALL glitter_effect_group_unparse_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian) { +bool FASTCALL glitter_effect_group_unparse_file(GPM, glitter_effect_group* a1, f2_struct* st) { memset(st, 0, sizeof(f2_struct)); - f2_struct* s = f2_struct_init(); - for (glitter_effect** i = a1->effects.begin; i != a1->effects.end; i++) - if (*i && glitter_effect_unparse_file(a1, s, *i, use_big_endian)) - vector_f2_struct_push_back(&st->sub_structs, s); + for (glitter_effect** i = a1->effects.begin; i != a1->effects.end; i++) { + if (!*i) + continue; - if (!glitter_texture_hashes_pack_file(a1, s, use_big_endian)) { - f2_struct_dispose(s); - return false; + f2_struct s; + memset(&s, 0, sizeof(f2_struct)); + if (glitter_effect_unparse_file(GPM_VAL, a1, &s, *i)) + vector_f2_struct_push_back(&st->sub_structs, &s); } - vector_f2_struct_push_back(&st->sub_structs, s); - free(s); + f2_struct s; + memset(&s, 0, sizeof(f2_struct)); + if (glitter_texture_hashes_pack_file(a1, &s)) + vector_f2_struct_push_back(&st->sub_structs, &s); st->header.signature = 0x46455644; st->header.length = 0x20; @@ -52,12 +55,9 @@ bool FASTCALL glitter_effect_group_unparse_file(glitter_effect_group* a1, f2_str } void FASTCALL glitter_effect_group_dispose(glitter_effect_group* eg) { - vector_ptr_glitter_effect_free(&eg->effects, (void*)glitter_effect_dispose); - free(eg->resource_hashes); - if (eg->resources) - glDeleteTextures(eg->resources_count, eg->resources); - free(eg->resources); - if (eg->resources_tex) - txp_dispose(eg->resources_tex); + vector_ptr_glitter_effect_free(&eg->effects, glitter_effect_dispose); + vector_uint64_t_free(&eg->resource_hashes); + glitter_texture_unload(eg); + tex_set_free(&eg->resources_tex); free(eg); } diff --git a/src/CRE/Glitter/effect_group.h b/src/CRE/Glitter/effect_group.h index d07f4709..e14e22b3 100644 --- a/src/CRE/Glitter/effect_group.h +++ b/src/CRE/Glitter/effect_group.h @@ -7,7 +7,7 @@ #include "glitter.h" -extern glitter_effect_group* FASTCALL glitter_effect_group_init(); -extern bool FASTCALL glitter_effect_group_parse_file(glitter_effect_group* a1, f2_struct* st); -extern bool FASTCALL glitter_effect_group_unparse_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian); +extern glitter_effect_group* FASTCALL glitter_effect_group_init(GPM); +extern bool FASTCALL glitter_effect_group_parse_file(GPM, glitter_effect_group* a1, f2_struct* st); +extern bool FASTCALL glitter_effect_group_unparse_file(GPM, glitter_effect_group* a1, f2_struct* st); extern void FASTCALL glitter_effect_group_dispose(glitter_effect_group* eg); diff --git a/src/CRE/Glitter/effect_inst.c b/src/CRE/Glitter/effect_inst.c index b4682b4f..2c32b100 100644 --- a/src/CRE/Glitter/effect_inst.c +++ b/src/CRE/Glitter/effect_inst.c @@ -4,19 +4,24 @@ */ #include "effect_inst.h" +#include "counter.h" #include "curve.h" #include "emitter_inst.h" #include "random.h" -#include "scene.h" +#include "render_group.h" -static int32_t FASTCALL glitter_effect_inst_get_a3da_index(int32_t index); +static void FASTCALL glitter_effect_inst_get_ext_anim(GPM, glitter_effect_inst* a1); +static int32_t FASTCALL glitter_aft_effect_inst_get_ext_anim_bone_index(int32_t index); +static int32_t FASTCALL glitter_f2_effect_inst_get_ext_anim_bone_index(int32_t index); +static void FASTCALL glitter_effect_inst_get_value(GPM, glitter_effect_inst* a1, float_t frame); +static void FASTCALL glitter_effect_inst_reset_sub(GPM, glitter_effect_inst* a1, float_t emission); -glitter_effect_inst* FASTCALL glitter_effect_inst_init(glitter_effect* a1, - glitter_scene* a2, size_t id, bool appear_now) { +glitter_effect_inst* FASTCALL glitter_effect_inst_init(GPM, + glitter_effect* a1, size_t id, float_t emission, bool appear_now) { + glitter_effect_inst_ext_anim* inst_ext_anim; + glitter_effect_ext_anim* ext_anim; glitter_emitter** i; - glitter_effect_inst_a3da* inst_a3da; - glitter_effect_a3da* a3da; - glitter_emitter_inst* emitter; + glitter_emitter_inst* emitter_inst; glitter_effect_inst* ei = force_malloc(sizeof(glitter_effect_inst)); ei->effect = a1; @@ -24,145 +29,260 @@ glitter_effect_inst* FASTCALL glitter_effect_inst_init(glitter_effect* a1, ei->color = vec4_identity; ei->scale_all = 1.0f; ei->id = id; - glitter_random_set(ei->data.name_hash % glitter_random_get_max()); ei->translation = a1->translation; ei->rotation = a1->rotation; ei->scale = a1->scale; + glitter_random_reset(&ei->random_shared); + glitter_random_reset(&ei->random); if (appear_now) - ei->data.appear_time = 0.0f; + ei->frame = 0.0f; else - ei->frame = -ei->data.appear_time; + ei->frame = (float_t)-ei->data.appear_time; - if (ei->data.a3da) { - inst_a3da = force_malloc(sizeof(glitter_effect_inst_a3da)); - inst_a3da->dword00 = -1; - inst_a3da->object_index = -1; - inst_a3da->index = -1; - inst_a3da->mat = mat4_identity; + if (~a1->data.flags & GLITTER_EFFECT_LOCAL && ei->data.ext_anim) { + inst_ext_anim = force_malloc(sizeof(glitter_effect_inst_ext_anim)); + inst_ext_anim->dword00 = -1; + inst_ext_anim->object_hash = glt_type != GLITTER_AFT + ? hash_murmurhash_empty : hash_fnv1a64_empty; + inst_ext_anim->chara_index = -1; + inst_ext_anim->node_index = -1; + inst_ext_anim->mat = mat4_identity; - if (inst_a3da) { - a3da = ei->data.a3da; - if (a3da->flags & GLITTER_EFFECT_A3DA_FLAG_SET_A3DA_ONCE) - ei->flags |= GLITTER_EFFECT_INST_FLAG_SET_A3DA_ONCE; - if (a3da->flags & GLITTER_EFFECT_A3DA_FLAG_SET_A3DA_TRANS_ONLY) - ei->flags |= GLITTER_EFFECT_INST_FLAG_SET_A3DA_TRANS_ONLY; - if (a3da->flags & GLITTER_EFFECT_A3DA_FLAG_SET_A3DA_BY_OBJECT_INDEX) { - inst_a3da->index = glitter_effect_inst_get_a3da_index(a3da->index); - ei->flags |= GLITTER_EFFECT_INST_FLAG_SET_A3DA_BY_OBJECT_INDEX; + if (inst_ext_anim) { + ext_anim = ei->data.ext_anim; + if (ext_anim->flags & GLITTER_EFFECT_EXT_ANIM_SET_EXT_ANIM_ONCE) + ei->flags |= GLITTER_EFFECT_INST_SET_EXT_ANIM_ONCE; + if (ext_anim->flags & GLITTER_EFFECT_EXT_ANIM_EXT_ANIM_TRANS_ONLY) + ei->flags |= GLITTER_EFFECT_INST_EXT_ANIM_TRANS_ONLY; + + if (ext_anim->flags & GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM) { + inst_ext_anim->chara_index = ext_anim->index; + inst_ext_anim->node_index = glt_type == GLITTER_AFT + ? glitter_aft_effect_inst_get_ext_anim_bone_index(ext_anim->node_index) + : glitter_f2_effect_inst_get_ext_anim_bone_index(ext_anim->node_index); + ei->flags |= GLITTER_EFFECT_INST_CHARA_ANIM; + } + else { + inst_ext_anim->object_hash = ext_anim->object_hash; + inst_ext_anim->some_hash = ext_anim->some_hash; + inst_ext_anim->instance_id = ext_anim->instance_id; } - - inst_a3da->object_index = a3da->object_index; - size_t mesh_name_len = strlen(a3da->mesh_name); - if (mesh_name_len) { - inst_a3da->mesh_name = force_malloc(mesh_name_len + 1); - memcpy(inst_a3da->mesh_name, a3da->mesh_name, mesh_name_len); + size_t name_len = strlen(ext_anim->mesh_name); + if (name_len) { + inst_ext_anim->name = force_malloc(name_len + 1); + memcpy(inst_ext_anim->name, ext_anim->mesh_name, name_len); } else - inst_a3da->mesh_name = 0; + inst_ext_anim->name = 0; } - ei->a3da = inst_a3da; - ei->flags |= GLITTER_EFFECT_INST_FLAG_HAS_A3DA; - ei->flags |= GLITTER_EFFECT_INST_FLAG_HAS_A3DA_NON_INIT; - ei->flags |= GLITTER_EFFECT_INST_FLAG_SET_A3DA_BY_OBJECT_NAME; + ei->ext_anim = inst_ext_anim; + ei->flags |= GLITTER_EFFECT_INST_HAS_EXT_ANIM; + ei->flags |= GLITTER_EFFECT_INST_HAS_EXT_ANIM_NON_INIT; + ei->flags |= GLITTER_EFFECT_INST_SET_EXT_ANIM_BY_OBJECT_NAME; } + glitter_random_set_value(&ei->random_shared, ei->data.name_hash % glitter_random_get_max(GPM_VAL)); + ei->random.value = glitter_random_get_value(&ei->random_shared); + ei->mat = mat4_identity; - ei->random = glitter_random_get(); - vector_ptr_glitter_emitter_inst_resize(&ei->emitters, a1->emitters.end - a1->emitters.begin); + vector_ptr_glitter_emitter_inst_append(&ei->emitters, a1->emitters.end - a1->emitters.begin); for (i = a1->emitters.begin; i != a1->emitters.end; i++) { if (!*i) continue; - emitter = glitter_emitter_inst_init(*i, a2, ei); - vector_ptr_glitter_emitter_inst_push_back(&ei->emitters, &emitter); + emitter_inst = glitter_emitter_inst_init(GPM_VAL, *i, ei, emission); + vector_ptr_glitter_emitter_inst_push_back(&ei->emitters, &emitter_inst); } - glitter_effect_inst_reset_sub(ei, a2); + glitter_effect_inst_reset_sub(GPM_VAL, ei, emission); return ei; } -void FASTCALL glitter_effect_inst_copy(glitter_effect_inst* a1, - glitter_effect_inst* a2, glitter_scene* a3) { - int64_t emitters_count; // rbp - int64_t i; // rbx +void FASTCALL glitter_effect_inst_calc_draw(GPM, glitter_effect_inst* a1, + bool(FASTCALL* render_add_list_func)(glitter_particle_mesh*, vec4*, mat4*, mat4*)) { + glitter_render_group** i; + glitter_render_group* render_group; - a2->frame = a1->frame; - a2->color = a1->color; - a2->translation = a1->translation; - a2->rotation = a1->rotation; - a2->scale = a1->scale; - a2->mat = a1->mat; - a2->random = a1->random; + for (i = a1->render_groups.begin; i != a1->render_groups.end; i++) { + if (!*i) + continue; - emitters_count = a1->emitters.end - a1->emitters.begin; - if (emitters_count != a2->emitters.end - a2->emitters.begin) + render_group = *i; + if (render_group && (!glitter_render_group_cannot_draw(render_group) || gpm->draw_all)) + glitter_render_group_calc_draw(GPM_VAL, render_group, render_add_list_func); + } +} + +void FASTCALL glitter_effect_inst_draw(GPM, glitter_effect_inst* a1, int32_t alpha) { + glitter_render_group** i; + glitter_render_group* render_group; + + for (i = a1->render_groups.begin; i != a1->render_groups.end; i++) { + if (!*i) + continue; + + render_group = *i; + if (render_group && (render_group)->alpha == alpha + && (!glitter_render_group_cannot_draw(render_group) || gpm->draw_all)) + glitter_render_group_draw(GPM_VAL, render_group); + } +} + +int32_t FASTCALL glitter_effect_inst_get_alpha(glitter_effect_inst* a1) { + return (a1->data.flags & GLITTER_EFFECT_ALPHA) ? 2 : 1; +} + +size_t FASTCALL glitter_effect_inst_get_ctrl_count(glitter_effect_inst* a1, glitter_particle_type type) { + glitter_render_group** i; + glitter_render_group* render_group; + size_t ctrl; + + ctrl = 0; + for (i = a1->render_groups.begin; i != a1->render_groups.end; i++) { + if (!*i) + continue; + + render_group = *i; + if (render_group->type == type) + ctrl += render_group->ctrl; + } + return ctrl; +} + +size_t FASTCALL glitter_effect_inst_get_disp_count(glitter_effect_inst* a1, glitter_particle_type type) { + glitter_render_group** i; + glitter_render_group* render_group; + size_t disp; + + disp = 0; + for (i = a1->render_groups.begin; i != a1->render_groups.end; i++) { + if (!*i) + continue; + + render_group = *i; + if (render_group->type == type) + disp += render_group->disp; + } + return disp; +} + +int32_t FASTCALL glitter_effect_inst_get_fog(glitter_effect_inst* a1) { + if (a1->data.flags & GLITTER_EFFECT_FOG) + return 1; + else if (a1->data.flags & GLITTER_EFFECT_FOG_HEIGHT) + return 2; + else + return 0; +} + +bool FASTCALL glitter_effect_inst_has_ended(glitter_effect_inst* effect, bool a2) { + glitter_emitter_inst** i; + + if (~effect->flags & GLITTER_EFFECT_INST_FREE) + return false; + else if (!a2) + return true; + + for (i = effect->emitters.begin; i != effect->emitters.end; i++) + if (!glitter_emitter_inst_has_ended(*i, a2)) + return false; + return true; +} + +void FASTCALL glitter_effect_inst_reset(GPM, glitter_effect_inst* a1, float_t emission) { + glitter_emitter_inst** i; + + a1->frame = (float_t)-a1->data.appear_time; + a1->flags = 0; + for (i = a1->emitters.begin; i != a1->emitters.end; i++) + glitter_emitter_inst_reset(*i); + glitter_effect_inst_reset_sub(GPM_VAL, a1, emission); +} + +void FASTCALL glitter_effect_inst_update_value_frame(GPM, + glitter_effect_inst* effect, float_t delta_frame, float_t emission) { + vec3 scale; + glitter_emitter_inst** i; + glitter_render_group** j; + mat4 mat; + vec3 translation; + vec3 rotation; + + glitter_effect_inst_get_ext_anim(GPM_VAL, effect); + glitter_effect_inst_get_value(GPM_VAL, effect, effect->frame); + vec3_mult_scalar(effect->scale, effect->scale_all, scale); + rotation = effect->rotation; + if (effect->flags & GLITTER_EFFECT_INST_HAS_EXT_ANIM_TRANS && effect->ext_anim) { + vec3_add(effect->translation, effect->ext_anim->translation, translation); + mat4_translate_mult(&effect->ext_anim->mat, translation.x, translation.y, translation.z, &mat); + } + else { + translation = effect->translation; + mat4_translate(translation.x, translation.y, translation.z, &mat); + } + + mat4_rot(&mat, rotation.x, rotation.y, rotation.z, &mat); + mat4_scale_rot(&mat, scale.x, scale.y, scale.z, &effect->mat); + for (i = effect->emitters.begin; i != effect->emitters.end; ++i) + if (*i) + glitter_emitter_inst_update_value_frame(GPM_VAL, *i, effect, delta_frame); + + if (effect->frame >= 0.0f) + if (effect->frame < (float_t)effect->data.life_time) { + for (i = effect->emitters.begin; i != effect->emitters.end; i++) + if (*i) + glitter_emitter_inst_emit(GPM_VAL, *i, delta_frame, emission); + } + else if (effect->data.flags & GLITTER_EFFECT_LOOP) + effect->frame -= (float_t)effect->data.life_time; + else { + effect->flags |= GLITTER_EFFECT_INST_FREE; + for (i = effect->emitters.begin; i != effect->emitters.end; ++i) + if (*i) + glitter_emitter_inst_free(GPM_VAL, *i, emission); + } + + for (j = effect->render_groups.begin; j != effect->render_groups.end; j++) + if (*j) + glitter_render_group_get_value(GPM_VAL, *j, delta_frame, true); + effect->frame += delta_frame; +} + +void FASTCALL glitter_effect_inst_dispose(glitter_effect_inst* ei) { + if (ei->ext_anim) { + free(ei->ext_anim->name); + free(ei->ext_anim); + } + + vector_ptr_glitter_render_group_free(&ei->render_groups, glitter_render_group_dispose); + vector_ptr_glitter_emitter_inst_free(&ei->emitters, glitter_emitter_inst_dispose); + free(ei); +} + +static void FASTCALL glitter_effect_inst_get_ext_anim(GPM, glitter_effect_inst* a1) { + glitter_effect_inst_ext_anim* ext_anim; + + if (!a1->ext_anim) return; - for (i = 0; i < emitters_count; i++) - glitter_emitter_inst_copy(a1->emitters.begin[i], a2->emitters.begin[i], a3); -} + ext_anim = a1->ext_anim; + ext_anim->mat = mat4_identity; + ext_anim->translation = vec3_null; -void FASTCALL glitter_effect_inst_emit(glitter_effect_inst* a1, glitter_scene* a2, float_t delta_frame) { - glitter_emitter_inst** i; // rbx + if (~a1->flags & GLITTER_EFFECT_INST_HAS_EXT_ANIM + || (a1->flags & GLITTER_EFFECT_INST_SET_EXT_ANIM_ONCE + && a1->flags & GLITTER_EFFECT_INST_HAS_EXT_ANIM_TRANS)) + return; - if (a1->frame >= 0.0f) { - if (a1->frame < a1->data.life_time) - for (i = a1->emitters.begin; i != a1->emitters.end; ++i) - glitter_emitter_inst_emit_step(*i, a2, a1, delta_frame); - else if (a1->data.flags & GLITTER_EFFECT_FLAG_LOOP) - a1->frame -= a1->data.life_time; - else - glitter_effect_inst_free(a1, a2, false); - } - a1->frame += delta_frame; -} - -void FASTCALL glitter_effect_inst_emit_init(glitter_effect_inst* a1, glitter_scene* a2, float_t delta_frame) { - glitter_emitter_inst** i; - - if (a1->frame >= 0.0f) { - if (a1->frame < a1->data.life_time) - for (i = a1->emitters.begin; i != a1->emitters.end; i++) - glitter_emitter_inst_emit_init(*i, a2, a1, delta_frame); - else if (a1->data.flags & GLITTER_EFFECT_FLAG_LOOP) - a1->frame -= a1->data.life_time; - else - glitter_effect_inst_free(a1, a2, 0); - - for (i = a1->emitters.begin; i != a1->emitters.end; i++) - glitter_emitter_inst_render_group_init(*i, delta_frame); - } - a1->frame += delta_frame; -} - -void FASTCALL glitter_effect_inst_free(glitter_effect_inst* a1, glitter_scene* a2, bool free) { - glitter_emitter_inst** i; - - a1->flags |= GLITTER_EFFECT_INST_FLAG_FREE; - for (i = a1->emitters.begin; i != a1->emitters.end; ++i) - glitter_emitter_inst_free(*i, a2, free); -} - -void FASTCALL glitter_effect_inst_get_a3da(glitter_effect_inst* a1) { - glitter_effect_inst_a3da* v3; // rax - char* v4; // rax - int64_t v6; // rbx - mat4* v15; // r8 - int64_t v24; // rsi - int32_t v26; // ebx - char* v27; // r14 - int64_t v43; // rbx + /*char* v4; + int64_t v6; + mat4* v15; + int64_t v24; + int32_t chara_index; + int64_t v43; vec3 a2; - mat4 mat0; - mat4 mat1; - - if (~a1->flags & GLITTER_EFFECT_INST_FLAG_HAS_A3DA || !a1->a3da - || (a1->flags & GLITTER_EFFECT_INST_FLAG_SET_A3DA_ONCE - && a1->flags & GLITTER_EFFECT_INST_FLAG_HAS_A3DA_TRANS)) - return; - - return; + mat4 mat; int32_t(FASTCALL * sub_1401D5010)(int32_t a1) = (void*)0x00000001401D5010; @@ -185,295 +305,105 @@ void FASTCALL glitter_effect_inst_get_a3da(glitter_effect_inst* a1) { mat4* (FASTCALL * sub_140516750)(int64_t a1) = (void*)0x0000000140516750; - v3 = a1->a3da; - if (a1->flags & GLITTER_EFFECT_INST_FLAG_SET_A3DA_BY_OBJECT_INDEX) { + if (a1->flags & GLITTER_EFFECT_INST_CHARA_ANIM) { v4 = sub_1405320E0(); - if (v4 && sub_1405327B0(v4, v3->object_index) && (v6 = sub_140532030(v4, v3->object_index))) { - mat0 = *sub_140516750(v6); - vec4_length(mat0.row0, a2.x); - vec4_length(mat0.row1, a2.y); + if (v4 && sub_1405327B0(v4, ext_anim->chara_index) && (v6 = sub_140532030(v4, ext_anim->chara_index))) { + mat = *sub_140516750(v6); + vec4_length(mat.row0, a2.x); + vec4_length(mat.row1, a2.y); vec2_sub(*(vec2*)&a2, vec2_identity, *(vec2*)&a2); a2.z = 0.0f; - a1->a3da_scale = a2; - a1->flags |= GLITTER_EFFECT_INST_FLAG_HAS_A3DA_SCALE; - if (v3->index != 201) { - v15 = sub_140516730(v6, v3->index); - if (v15) { - mat1 = *v15; - mat4_mult(&mat0, &mat1, &mat0); - if (a1->flags & GLITTER_EFFECT_INST_FLAG_SET_A3DA_TRANS_ONLY) { - v3->mat = mat4_identity; - v3->translation = *(vec3*)&mat0.row3; - } - else - v3->mat = mat0; - goto SetFlags; - } - } - else { - if (a1->flags & GLITTER_EFFECT_INST_FLAG_SET_A3DA_TRANS_ONLY) { - v3->mat = mat4_identity; - v3->translation = *(vec3*)&mat0.row3; - } - else - v3->mat = mat0; - goto SetFlags; + a1->ext_anim_scale = a2; + a1->flags |= GLITTER_EFFECT_INST_HAS_EXT_ANIM_SCALE; + if (ext_anim->node_index == 201) + goto set_mat; + else if (v15 = sub_140516730(v6, ext_anim->node_index)) { + mat4_mult(&mat, v15, &mat); + goto set_mat; } } } - else if (~a1->flags & GLITTER_EFFECT_INST_FLAG_SET_A3DA_BY_OBJECT_NAME) { - if (v3->index < 0) { - if (!v3->mesh_name) + else if (~a1->flags & GLITTER_EFFECT_INST_SET_EXT_ANIM_BY_OBJECT_NAME) { + if (ext_anim->node_index < 0) { + if (!ext_anim->name) return; - v3->index = sub_140459DE0(v3->object_index, v3->mesh_name); + ext_anim->node_index = sub_140459DE0(ext_anim->object_hash, ext_anim->name); } - if (v3->index >= 0) { - v43 = sub_140459D40(v3->object_index, v3->index); + if (ext_anim->node_index >= 0) { + v43 = sub_140459D40(ext_anim->object_hash, ext_anim->node_index); if (v43) { - v3->translation = *(vec3*)(v43 + 4); - goto SetFlags; + ext_anim->translation = *(vec3*)(v43 + 4); + goto set_flags; } } } else { - if (v3->dword00 == -1 || !(v24 = sub_1401D5BC0(v3->dword00, v3->dword08, v3->object_is_hrc))) { - v3->dword00 = sub_1401D6090(v3->object_index, &v3->dword08, &v3->object_is_hrc); - if (v3->dword00 == -1) + if (ext_anim->dword00 == -1 || !(v24 = sub_1401D5BC0(ext_anim->dword00, + ext_anim->dword08, ext_anim->object_is_hrc))) { + ext_anim->dword00 = sub_1401D6090(ext_anim->object_hash, + &ext_anim->dword08, &ext_anim->object_is_hrc); + if (ext_anim->dword00 == -1) return; - v3->index = -1; - v24 = sub_1401D5BC0(v3->dword00, v3->dword08, v3->object_is_hrc); + ext_anim->node_index = -1; + v24 = sub_1401D5BC0(ext_anim->dword00, ext_anim->dword08, ext_anim->object_is_hrc); if (!v24) return; } - mat0 = mat4_identity; - v26 = sub_1401D5010(v3->dword00); - if (v26 >= 0 && v26 <= 5) { - v27 = sub_1405320E0(); - if (sub_1405327B0(v27, v26)) { - mat0 = *sub_140516750(sub_140532030(v27, v26)); - vec4_length(mat0.row0, a2.x); - vec4_length(mat0.row1, a2.y); + mat = mat4_identity; + chara_index = sub_1401D5010(ext_anim->dword00); + if (chara_index >= 0 && chara_index <= 5) { + v4 = sub_1405320E0(); + if (sub_1405327B0(v4, chara_index) && (v6 = sub_140532030(v4, chara_index))) { + mat = *sub_140516750(v6); + vec4_length(mat.row0, a2.x); + vec4_length(mat.row1, a2.y); vec2_sub(*(vec2*)&a2, vec2_identity, *(vec2*)&a2); a2.z = 0.0f; - a1->a3da_scale = a2; - a1->flags |= GLITTER_EFFECT_INST_FLAG_HAS_A3DA_SCALE; + a1->ext_anim_scale = a2; + a1->flags |= GLITTER_EFFECT_INST_HAS_EXT_ANIM_SCALE; } } - mat1 = *(mat4*)v24; - if (v3->mesh_name) { - if (v3->index < 0) { - v3->index = sub_140459DE0(v3->object_index, v3->mesh_name); - } + if (ext_anim->name) { + if (ext_anim->node_index < 0) + ext_anim->node_index = sub_140459DE0(ext_anim->object_hash, ext_anim->name); - if (v3->index >= 0) { - v43 = sub_140459D40(v3->object_index, v3->index); + if (ext_anim->node_index >= 0) { + v43 = sub_140459D40(ext_anim->object_hash, ext_anim->node_index); if (v43) { - mat4_mult(&mat0, &mat1, &v3->mat); - v3->translation = *(vec3*)(v43 + 4); - goto SetFlags; + mat4_mult(&mat, (mat4*)v24, &ext_anim->mat); + ext_anim->translation = *(vec3*)(v43 + 4); + goto set_flags; } } } else { - mat4_mult(&mat0, &mat1, &mat0); - if (a1->flags & GLITTER_EFFECT_INST_FLAG_SET_A3DA_TRANS_ONLY) { - v3->mat = mat4_identity; - v3->translation = *(vec3*)&mat0.row3; - } - else - v3->mat = mat0; - goto SetFlags; + mat4_mult(&mat, (mat4*)v24, &mat); + goto set_mat; } } return; -SetFlags: - if (a1->flags & GLITTER_EFFECT_INST_FLAG_HAS_A3DA_NON_INIT) { - a1->flags &= ~GLITTER_EFFECT_INST_FLAG_HAS_A3DA_NON_INIT; - a1->flags |= GLITTER_EFFECT_INST_FLAG_HAS_A3DA_TRANS; +set_mat: + if (a1->flags & GLITTER_EFFECT_INST_EXT_ANIM_TRANS_ONLY) { + ext_anim->mat = mat4_identity; + mat4_get_translation(&mat, ext_anim->translation); } -} - -int32_t FASTCALL glitter_effect_inst_get_alpha(glitter_effect_inst* a1) { - return (a1->data.flags & GLITTER_EFFECT_FLAG_ALPHA) ? 2 : 1; -} - -int32_t FASTCALL glitter_effect_inst_get_fog(glitter_effect_inst* a1) { - if (a1->data.flags & GLITTER_EFFECT_FLAG_FOG) - return 1; - else if (a1->data.flags & GLITTER_EFFECT_FLAG_FOG_HEIGHT) - return 2; else - return 0; + ext_anim->mat = mat; + +set_flags: + if (a1->flags & GLITTER_EFFECT_INST_HAS_EXT_ANIM_NON_INIT) { + a1->flags &= ~GLITTER_EFFECT_INST_HAS_EXT_ANIM_NON_INIT; + a1->flags |= GLITTER_EFFECT_INST_HAS_EXT_ANIM_TRANS; + }*/ } -void FASTCALL glitter_effect_inst_get_value(glitter_effect_inst* a1, float_t frame, int32_t random) { - int64_t length; - glitter_curve* curve; - float_t value; - - length = a1->effect->curve.end - a1->effect->curve.begin; - if (!length) - return; - - for (int32_t i = 0; i < length; i++) { - curve = a1->effect->curve.begin[i]; - if (!glitter_curve_get_value(curve, frame, &value, random + i)) - continue; - - switch (curve->type) { - case GLITTER_CURVE_TRANSLATION_X: - a1->translation.x = value; - break; - case GLITTER_CURVE_TRANSLATION_Y: - a1->translation.y = value; - break; - case GLITTER_CURVE_TRANSLATION_Z: - a1->translation.z = value; - break; - case GLITTER_CURVE_ROTATION_X: - a1->rotation.x = value; - break; - case GLITTER_CURVE_ROTATION_Y: - a1->rotation.y = value; - break; - case GLITTER_CURVE_ROTATION_Z: - a1->rotation.z = value; - break; - case GLITTER_CURVE_SCALE_X: - a1->scale.x = value; - break; - case GLITTER_CURVE_SCALE_Y: - a1->scale.y = value; - break; - case GLITTER_CURVE_SCALE_Z: - a1->scale.z = value; - break; - case GLITTER_CURVE_SCALE_ALL: - a1->scale_all = value; - break; - case GLITTER_CURVE_COLOR_R: - a1->color.x = value; - break; - case GLITTER_CURVE_COLOR_G: - a1->color.y = value; - break; - case GLITTER_CURVE_COLOR_B: - a1->color.z = value; - break; - case GLITTER_CURVE_COLOR_A: - a1->color.w = value; - break; - } - } -} - -bool FASTCALL glitter_effect_inst_has_ended(glitter_effect_inst* effect, bool a2) { - glitter_emitter_inst** i; - - if (~effect->flags & GLITTER_EFFECT_INST_FLAG_FREE) - return false; - else if (!a2) - return true; - - for (i = effect->emitters.begin; i != effect->emitters.end; i++) - if (!glitter_emitter_inst_has_ended(*i, a2)) - return false; - return true; -} - -void FASTCALL glitter_effect_inst_reset(glitter_effect_inst* a1, glitter_scene* a2) { - glitter_emitter_inst** i; - - a1->frame = -a1->data.appear_time; - a1->flags = 0; - for (i = a1->emitters.begin; i != a1->emitters.end; i++) - glitter_emitter_inst_reset(*i); - glitter_effect_inst_reset_sub(a1, a2); -} - -void FASTCALL glitter_effect_inst_reset_sub(glitter_effect_inst* a1, glitter_scene* a2) { - float_t delta_frame; - float_t start_time; - - if (a1->data.start_time <= 0.0f) - return; - - delta_frame = 2.0f; - for (start_time = a1->data.start_time; start_time > 0.0f; start_time -= delta_frame) { - a1->flags |= GLITTER_EFFECT_INST_FLAG_JUST_INIT; - if (start_time < delta_frame) - delta_frame -= start_time; - glitter_effect_inst_update_value_init(a1, delta_frame); - glitter_effect_inst_emit_init(a1, a2, delta_frame); - } - glitter_effect_inst_update_mat(a1); -} - -void FASTCALL glitter_effect_inst_update_mat(glitter_effect_inst* a1) { - glitter_emitter_inst** i; - vec3 scale; - - if (a1->flags & GLITTER_EFFECT_INST_FLAG_JUST_INIT) { - mat4_translate(a1->translation.x, a1->translation.y, a1->translation.z, &a1->mat); - mat4_rot(&a1->mat, a1->rotation.x, a1->rotation.y, a1->rotation.z, &a1->mat); - vec3_mult_scalar(a1->scale, a1->scale_all, scale); - mat4_scale_rot(&a1->mat, scale.x, scale.y, scale.z, &a1->mat); - for (i = a1->emitters.begin; i != a1->emitters.end; ++i) - glitter_emitter_inst_update_mat(*i, a1); - a1->flags &= ~GLITTER_EFFECT_INST_FLAG_JUST_INIT; - } -} - -void FASTCALL glitter_effect_inst_update_value_frame(glitter_effect_inst* effect, float_t delta_frame) { - vec3 scale; - glitter_emitter_inst** i; - mat4 mat; - vec3 translation; - - glitter_effect_inst_get_value(effect, effect->frame, effect->random); - vec3_mult_scalar(effect->scale, effect->scale_all, scale); - glitter_effect_inst_get_a3da(effect); - if (~effect->flags & GLITTER_EFFECT_INST_FLAG_HAS_A3DA_TRANS || !effect->a3da) - translation = effect->translation; - else - vec3_add(effect->translation, effect->a3da->translation, translation); - - mat4_translate(translation.x, translation.y, translation.z, &mat); - mat4_rot(&mat, effect->rotation.x, effect->rotation.y, effect->rotation.z, &mat); - mat4_scale_rot(&mat, scale.x, scale.y, scale.z, &mat); - effect->mat = mat; - for (i = effect->emitters.begin; i != effect->emitters.end; ++i) - glitter_emitter_inst_update_value_frame(*i, effect, delta_frame); -} - -void FASTCALL glitter_effect_inst_update_value_init(glitter_effect_inst* a1, float_t delta_frame) { - glitter_emitter_inst** i; - - if (a1->frame < 0.0f) - return; - - glitter_effect_inst_get_value(a1, a1->frame, a1->random); - for (i = a1->emitters.begin; i != a1->emitters.end; ++i) - glitter_emitter_inst_update_value_init(*i, a1->frame, delta_frame); -} - -void FASTCALL glitter_effect_inst_dispose(glitter_effect_inst* ei) { - if (ei->a3da) { - free(ei->a3da->mesh_name); - free(ei->a3da); - } - - vector_ptr_glitter_emitter_inst_free(&ei->emitters, (void*)glitter_emitter_inst_dispose); - free(ei); -} - -static int32_t FASTCALL glitter_effect_inst_get_a3da_index(int32_t index) { +static int32_t FASTCALL glitter_aft_effect_inst_get_ext_anim_bone_index(int32_t index) { switch (index) { case 0: return 15; @@ -515,3 +445,143 @@ static int32_t FASTCALL glitter_effect_inst_get_a3da_index(int32_t index) { return 201; } } + +static int32_t FASTCALL glitter_f2_effect_inst_get_ext_anim_bone_index(int32_t index) { + switch (index) { + case 0: + return 15; + case 1: + return 54; + case 2: + return 0; + case 3: + return 7; + case 4: + return 98; + case 5: + return 100; + case 6: + return 101; + case 7: + return 115; + case 8: + return 132; + case 9: + return 136; + case 10: + return 137; + case 11: + return 151; + case 12: + return 186; + case 13: + return 176; + case 14: + return 175; + case 15: + return 189; + case 16: + return 183; + case 17: + return 182; + default: + return 193; + } +} + +static void FASTCALL glitter_effect_inst_get_value(GPM, glitter_effect_inst* a1, float_t frame) { + int64_t length; + glitter_curve* curve; + float_t value; + + length = a1->effect->curve.end - a1->effect->curve.begin; + if (!length) + return; + + for (int32_t i = 0; i < length; i++) { + curve = a1->effect->curve.begin[i]; + if (!glitter_curve_get_value(GPM_VAL, curve, frame, &value, a1->random.value + i, &a1->random_shared)) + continue; + + switch (curve->type) { + case GLITTER_CURVE_TRANSLATION_X: + a1->translation.x = value; + break; + case GLITTER_CURVE_TRANSLATION_Y: + a1->translation.y = value; + break; + case GLITTER_CURVE_TRANSLATION_Z: + a1->translation.z = value; + break; + case GLITTER_CURVE_ROTATION_X: + a1->rotation.x = value; + break; + case GLITTER_CURVE_ROTATION_Y: + a1->rotation.y = value; + break; + case GLITTER_CURVE_ROTATION_Z: + a1->rotation.z = value; + break; + case GLITTER_CURVE_SCALE_X: + a1->scale.x = value; + break; + case GLITTER_CURVE_SCALE_Y: + a1->scale.y = value; + break; + case GLITTER_CURVE_SCALE_Z: + a1->scale.z = value; + break; + case GLITTER_CURVE_SCALE_ALL: + a1->scale_all = value; + break; + /*case GLITTER_CURVE_COLOR_R: + a1->color.x = value; + break; + case GLITTER_CURVE_COLOR_G: + a1->color.y = value; + break; + case GLITTER_CURVE_COLOR_B: + a1->color.z = value; + break; + case GLITTER_CURVE_COLOR_A: + a1->color.w = value; + break;*/ + } + } +} + +static void FASTCALL glitter_effect_inst_reset_sub(GPM, glitter_effect_inst* a1, float_t emission) { + glitter_emitter_inst** i; + glitter_render_group** j; + vec3 scale; + float_t delta_frame; + float_t start_time; + + if (a1->data.start_time <= 0) + return; + + delta_frame = 2.0f; + for (start_time = (float_t)a1->data.start_time; start_time > 0.0f; start_time -= delta_frame) { + if (start_time < delta_frame) + delta_frame -= start_time; + + glitter_effect_inst_get_value(GPM_VAL, a1, a1->frame); + mat4_translate(a1->translation.x, a1->translation.y, a1->translation.z, &a1->mat); + mat4_rot(&a1->mat, a1->rotation.x, a1->rotation.y, a1->rotation.z, &a1->mat); + vec3_mult_scalar(a1->scale, a1->scale_all, scale); + mat4_scale_rot(&a1->mat, scale.x, scale.y, scale.z, &a1->mat); + + for (i = a1->emitters.begin; i != a1->emitters.end; ++i) { + if (!*i) + continue; + + glitter_emitter_inst_update_value_init(GPM_VAL, *i, a1, delta_frame); + glitter_emitter_inst_emit(GPM_VAL, *i, delta_frame, emission); + } + + for (j = a1->render_groups.begin; j != a1->render_groups.end; j++) + if (*j) + glitter_render_group_get_value(GPM_VAL, *j, delta_frame, true); + a1->frame += delta_frame; + } +} diff --git a/src/CRE/Glitter/effect_inst.h b/src/CRE/Glitter/effect_inst.h index 405e88fa..c5bbf1c8 100644 --- a/src/CRE/Glitter/effect_inst.h +++ b/src/CRE/Glitter/effect_inst.h @@ -7,23 +7,17 @@ #include "glitter.h" -extern glitter_effect_inst* FASTCALL glitter_effect_inst_init(glitter_effect* a1, - glitter_scene* a2, size_t id, bool appear_now); -extern void FASTCALL glitter_effect_inst_copy(glitter_effect_inst* a1, - glitter_effect_inst* a2, glitter_scene* a3); -extern void FASTCALL glitter_effect_inst_emit(glitter_effect_inst* a1, - glitter_scene* a2, float_t delta_frame); -extern void FASTCALL glitter_effect_inst_emit_init(glitter_effect_inst* a1, - glitter_scene* a2, float_t delta_frame); -extern void FASTCALL glitter_effect_inst_free(glitter_effect_inst* a1, glitter_scene* a2, bool a3); -extern void FASTCALL glitter_effect_inst_get_a3da(glitter_effect_inst* a1); +extern glitter_effect_inst* FASTCALL glitter_effect_inst_init(GPM, + glitter_effect* a1, size_t id, float_t emission, bool appear_now); +extern void FASTCALL glitter_effect_inst_calc_draw(GPM, glitter_effect_inst* a1, + bool(FASTCALL* render_add_list_func)(glitter_particle_mesh*, vec4*, mat4*, mat4*)); +extern void FASTCALL glitter_effect_inst_draw(GPM, glitter_effect_inst* a1, int32_t alpha); extern int32_t FASTCALL glitter_effect_inst_get_alpha(glitter_effect_inst* a1); +extern size_t FASTCALL glitter_effect_inst_get_ctrl_count(glitter_effect_inst* a1, glitter_particle_type type); +extern size_t FASTCALL glitter_effect_inst_get_disp_count(glitter_effect_inst* a1, glitter_particle_type type); extern int32_t FASTCALL glitter_effect_inst_get_fog(glitter_effect_inst* a1); -extern void FASTCALL glitter_effect_inst_get_value(glitter_effect_inst* a1, float_t frame, int32_t random); extern bool FASTCALL glitter_effect_inst_has_ended(glitter_effect_inst* effect, bool a2); -extern void FASTCALL glitter_effect_inst_reset(glitter_effect_inst* a1, glitter_scene* a2); -extern void FASTCALL glitter_effect_inst_reset_sub(glitter_effect_inst* a1, glitter_scene* a2); -extern void FASTCALL glitter_effect_inst_update_mat(glitter_effect_inst* a1); -extern void FASTCALL glitter_effect_inst_update_value_frame(glitter_effect_inst* a1, float_t delta_frame); -extern void FASTCALL glitter_effect_inst_update_value_init(glitter_effect_inst* a1, float_t delta_frame); +extern void FASTCALL glitter_effect_inst_reset(GPM, glitter_effect_inst* a1, float_t emission); +extern void FASTCALL glitter_effect_inst_update_value_frame(GPM, glitter_effect_inst* a1, + float_t delta_frame, float_t emission); extern void FASTCALL glitter_effect_inst_dispose(glitter_effect_inst* ei); diff --git a/src/CRE/Glitter/emitter.c b/src/CRE/Glitter/emitter.c index b00e5f8b..80282cd5 100644 --- a/src/CRE/Glitter/emitter.c +++ b/src/CRE/Glitter/emitter.c @@ -8,15 +8,37 @@ #include "curve.h" #include "particle.h" -static bool FASTCALL glitter_emitter_pack_file(f2_struct* st, glitter_emitter* a2, bool use_big_endian); -static bool FASTCALL glitter_emitter_unpack_file(int32_t* data, glitter_emitter* a2, bool use_big_endian); +static bool FASTCALL glitter_emitter_pack_file(GPM, f2_struct* st, glitter_emitter* a2); +static bool FASTCALL glitter_emitter_unpack_file(GPM, int32_t* data, glitter_emitter* a2, bool use_big_endian); -glitter_emitter* FASTCALL glitter_emitter_init() { +glitter_emitter* FASTCALL glitter_emitter_init(GPM) { glitter_emitter* e = force_malloc(sizeof(glitter_emitter)); + e->version = glt_type == GLITTER_X ? 0x04 : 0x02; return e; } -bool FASTCALL glitter_emitter_parse_file(glitter_effect_group* a1, +glitter_emitter* FASTCALL glitter_emitter_copy(GPM, glitter_emitter* e) { + if (!e) + return 0; + + glitter_emitter* ec = force_malloc(sizeof(glitter_emitter)); + *ec = *e; + + ec->particles = (vector_ptr_glitter_particle){ 0, 0, 0 }; + vector_ptr_glitter_particle_append(&ec->particles, e->particles.end - e->particles.begin); + for (glitter_particle** i = e->particles.begin; i != e->particles.end; i++) + if (*i) { + glitter_particle* p = glitter_particle_copy(GPM_VAL, *i); + if (p) + vector_ptr_glitter_particle_push_back(&ec->particles, &p); + } + + ec->curve = (vector_ptr_glitter_curve){ 0, 0, 0 }; + glitter_animation_copy(GPM_VAL, &e->curve, &ec->curve); + return ec; +} + +bool FASTCALL glitter_emitter_parse_file(GPM, glitter_effect_group* a1, f2_struct* st, vector_ptr_glitter_emitter* vec, glitter_effect* effect) { f2_struct* i; glitter_emitter* emitter; @@ -24,9 +46,9 @@ bool FASTCALL glitter_emitter_parse_file(glitter_effect_group* a1, if (!st || !st->header.data_size) return false; - emitter = glitter_emitter_init(); + emitter = glitter_emitter_init(GPM_VAL); emitter->version = st->header.version; - if (!glitter_emitter_unpack_file(st->data, emitter, st->header.use_big_endian)) { + if (!glitter_emitter_unpack_file(GPM_VAL, st->data, emitter, st->header.use_big_endian)) { glitter_emitter_dispose(emitter); return false; } @@ -35,294 +57,393 @@ bool FASTCALL glitter_emitter_parse_file(glitter_effect_group* a1, if (!i->header.data_size) continue; - if (i->header.signature == 0x4D494E41) - glitter_animation_parse_file(i, &emitter->curve); - else if (i->header.signature == 0x4C435450) - glitter_particle_parse_file(a1, i, &emitter->particles, effect); + if (i->header.signature == reverse_endianess_uint32_t('ANIM')) + glitter_animation_parse_file(GPM_VAL, i, &emitter->curve, glitter_emitter_curve_flags); + else if (i->header.signature == reverse_endianess_uint32_t('PTCL')) + glitter_particle_parse_file(GPM_VAL, a1, i, &emitter->particles, effect); } vector_ptr_glitter_emitter_push_back(vec, &emitter); return true; } -bool FASTCALL glitter_emitter_unparse_file(glitter_effect_group* a1, - f2_struct* st, glitter_emitter* a3, glitter_effect* effect, bool use_big_endian) { - if (!glitter_emitter_pack_file(st, a3, use_big_endian)) +bool FASTCALL glitter_emitter_unparse_file(GPM, glitter_effect_group* a1, + f2_struct* st, glitter_emitter* a3, glitter_effect* effect) { + if (!glitter_emitter_pack_file(GPM_VAL, st, a3)) return false; f2_struct s; - if (glitter_animation_unparse_file(&s, &a3->curve, use_big_endian)) + if (glitter_animation_unparse_file(GPM_VAL, &s, &a3->curve, glitter_emitter_curve_flags)) vector_f2_struct_push_back(&st->sub_structs, &s); - for (glitter_particle** i = a3->particles.begin; i != a3->particles.end; i++) - if (*i && glitter_particle_unparse_file(a1, &s, *i, effect, use_big_endian)) + for (glitter_particle** i = a3->particles.begin; i != a3->particles.end; i++) { + if (!*i) + continue; + + f2_struct s; + if (glitter_particle_unparse_file(GPM_VAL, a1, &s, *i, effect)) vector_f2_struct_push_back(&st->sub_structs, &s); + } return true; } void FASTCALL glitter_emitter_dispose(glitter_emitter* e) { - vector_ptr_glitter_curve_free(&e->curve, (void*)glitter_curve_dispose); - vector_ptr_glitter_particle_free(&e->particles, (void*)glitter_particle_dispose); + vector_ptr_glitter_curve_free(&e->curve, glitter_curve_dispose); + vector_ptr_glitter_particle_free(&e->particles, glitter_particle_dispose); free(e); } -static bool FASTCALL glitter_emitter_pack_file(f2_struct* st, glitter_emitter* a2, bool use_big_endian) { +static bool FASTCALL glitter_emitter_pack_file(GPM, f2_struct* st, glitter_emitter* a2) { size_t l; - int32_t* d; + size_t d; - if (!a2->version) + if (a2->version != 1 && a2->version != 2) return false; - memset(st, 0, sizeof(f2_struct)); - l = 96; - switch (a2->data.type) { case GLITTER_EMITTER_BOX: - l += 12; - break; case GLITTER_EMITTER_CYLINDER: - l += 20; - break; case GLITTER_EMITTER_SPHERE: - l += 16; - break; case GLITTER_EMITTER_POLYGON: - l += 8; break; default: return false; } + memset(st, 0, sizeof(f2_struct)); + l = 0; + + uint32_t o; + vector_enrs_entry e = { 0, 0, 0 }; + enrs_entry ee; + + ee = (enrs_entry){ 0, 5, 96, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 5, ENRS_TYPE_DWORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_DWORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 15, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 96; + + switch (a2->data.type) { + case GLITTER_EMITTER_BOX: + ee = (enrs_entry){ o, 1, 12, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 3, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 12; + break; + case GLITTER_EMITTER_CYLINDER: + ee = (enrs_entry){ o, 1, 20, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 5, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 20; + break; + case GLITTER_EMITTER_SPHERE: + ee = (enrs_entry){ o, 1, 16, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 4, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 16; + break; + case GLITTER_EMITTER_POLYGON: + ee = (enrs_entry){ o, 1, 8, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 8; + break; + } + l = align_val(l, 0x10); - d = force_malloc(l); + d = (size_t)force_malloc(l); st->length = l; - st->data = d; + st->data = (void*)d; + st->enrs = e; - if (use_big_endian) { - d[0] = reverse_endianess_int32_t((int32_t)roundf(a2->data.start_time)); - d[1] = reverse_endianess_int32_t((int32_t)roundf(a2->data.life_time)); - d[2] = reverse_endianess_int32_t((int32_t)roundf(a2->data.loop_start_time)); - d[3] = reverse_endianess_int32_t((int32_t)roundf(a2->data.loop_end_time)); - d[4] = reverse_endianess_int32_t(a2->data.flags); - *((int16_t*)d + 10) = reverse_endianess_int16_t((int16_t)a2->data.type); - *((int16_t*)d + 11) = reverse_endianess_int16_t((int16_t)a2->data.direction); - *(float_t*)&d[6] = reverse_endianess_float_t(a2->data.emission_interval); - *(float_t*)&d[7] = reverse_endianess_float_t(a2->data.particles_per_emission); - //*((int16_t*)data + 16) = reverse_endianess_int16_t((int16_t)a3->data.dword2C); - /*if (a2->version > 1) - *((int16_t*)data + 17) = reverse_endianess_uint16_t((int16_t)a3->data.dword30);*/ + *(int32_t*)d = a2->data.start_time; + *(int32_t*)(d + 4) = a2->data.life_time; + *(int32_t*)(d + 8) = a2->data.loop_start_time; + *(int32_t*)(d + 12) = a2->data.loop_end_time; + *(int32_t*)(d + 16) = a2->data.flags; + *(int16_t*)(d + 20) = (int16_t)a2->data.type; + *(int16_t*)(d + 22) = (int16_t)a2->data.direction; + *(float_t*)(d + 24) = a2->data.emission_interval; + *(float_t*)(d + 28) = a2->data.particles_per_emission; + *(int16_t*)(d + 32) = 0; + *(int16_t*)(d + 34) = 0; - *(float_t*)&d[9] = reverse_endianess_float_t(a2->translation.x); - *(float_t*)&d[10] = reverse_endianess_float_t(a2->translation.y); - *(float_t*)&d[11] = reverse_endianess_float_t(a2->translation.z); - *(float_t*)&d[12] = reverse_endianess_float_t(a2->rotation.x); - *(float_t*)&d[13] = reverse_endianess_float_t(a2->rotation.y); - *(float_t*)&d[14] = reverse_endianess_float_t(a2->rotation.z); - *(float_t*)&d[15] = reverse_endianess_float_t(a2->scale.x); - *(float_t*)&d[16] = reverse_endianess_float_t(a2->scale.y); - *(float_t*)&d[17] = reverse_endianess_float_t(a2->scale.z); - *(float_t*)&d[18] = reverse_endianess_float_t(a2->data.rotation_add.x); - *(float_t*)&d[19] = reverse_endianess_float_t(a2->data.rotation_add.y); - *(float_t*)&d[20] = reverse_endianess_float_t(a2->data.rotation_add.z); - *(float_t*)&d[21] = reverse_endianess_float_t(a2->data.rotation_add_random.x); - *(float_t*)&d[22] = reverse_endianess_float_t(a2->data.rotation_add_random.y); - *(float_t*)&d[23] = reverse_endianess_float_t(a2->data.rotation_add_random.z); + *(vec3*)(d + 36) = a2->translation; + *(vec3*)(d + 48) = a2->rotation; + *(vec3*)(d + 60) = a2->scale; + *(vec3*)(d + 72) = a2->data.rotation_add; + *(vec3*)(d + 84) = a2->data.rotation_add_random; + d += 96; + + switch (a2->data.type) { + case GLITTER_EMITTER_BOX: + *(vec3*)d = a2->data.box.size; + break; + case GLITTER_EMITTER_CYLINDER: + *(float_t*)d = a2->data.cylinder.radius; + *(float_t*)(d + 4) = a2->data.cylinder.height; + *(float_t*)(d + 8) = a2->data.cylinder.start_angle; + *(float_t*)(d + 12) = a2->data.cylinder.end_angle; + *(int32_t*)(d + 16) = ((int32_t)a2->data.cylinder.direction << 1) + | (a2->data.cylinder.on_edge ? 1 : 0); + break; + case GLITTER_EMITTER_SPHERE: + *(float_t*)d = a2->data.sphere.radius; + *(float_t*)(d + 4) = a2->data.sphere.latitude; + *(float_t*)(d + 8) = a2->data.sphere.longitude; + *(int32_t*)(d + 12) = ((int32_t)a2->data.sphere.direction << 1) + | (a2->data.sphere.on_edge ? 1 : 0); + break; + case GLITTER_EMITTER_POLYGON: + *(float_t*)d = a2->data.polygon.size; + *(int32_t*)(d + 4) = a2->data.polygon.count; + break; } - else { - d[0] = (int32_t)roundf(a2->data.start_time); - d[1] = (int32_t)roundf(a2->data.life_time); - d[2] = (int32_t)roundf(a2->data.loop_start_time); - d[3] = (int32_t)roundf(a2->data.loop_end_time); - d[4] = a2->data.flags; - *((int16_t*)d + 10) = (int16_t)a2->data.type; - *((int16_t*)d + 11) = (int16_t)a2->data.direction; - *(float_t*)&d[6] = a2->data.emission_interval; - *(float_t*)&d[7] = a2->data.particles_per_emission; - //*((int16_t*)data + 16) = (int16_t)a3->data.dword2C; - /*if (a2->version > 1) - *((int16_t*)data + 17) = (int16_t)a3->data.dword30;*/ - *(vec3*)&d[9] = a2->translation; - *(vec3*)&d[12] = a2->rotation; - *(vec3*)&d[15] = a2->scale; - *(vec3*)&d[18] = a2->data.rotation_add; - *(vec3*)&d[21] = a2->data.rotation_add_random; - } - d += 24; - - if (use_big_endian) - switch (a2->data.type) { - case GLITTER_EMITTER_BOX: - *(float_t*)&d[0] = reverse_endianess_float_t(a2->data.box.size.x); - *(float_t*)&d[1] = reverse_endianess_float_t(a2->data.box.size.y); - *(float_t*)&d[2] = reverse_endianess_float_t(a2->data.box.size.z); - break; - case GLITTER_EMITTER_CYLINDER: - *(float_t*)&d[0] = reverse_endianess_float_t(a2->data.cylinder.radius); - *(float_t*)&d[1] = reverse_endianess_float_t(a2->data.cylinder.height); - *(float_t*)&d[2] = reverse_endianess_float_t(a2->data.cylinder.start_angle); - *(float_t*)&d[3] = reverse_endianess_float_t(a2->data.cylinder.end_angle); - d[4] = reverse_endianess_int32_t(((int32_t)a2->data.cylinder.direction << 1) - | (a2->data.cylinder.plain ? 1 : 0)); - break; - case GLITTER_EMITTER_SPHERE: - *(float_t*)&d[0] = reverse_endianess_float_t(a2->data.sphere.radius); - *(float_t*)&d[1] = reverse_endianess_float_t(a2->data.sphere.latitude); - *(float_t*)&d[2] = reverse_endianess_float_t(a2->data.sphere.longitude); - d[3] = reverse_endianess_int32_t(((int32_t)a2->data.cylinder.direction << 1) - | (a2->data.cylinder.plain ? 1 : 0)); - break; - case GLITTER_EMITTER_POLYGON: - *(float_t*)&d[0] = reverse_endianess_float_t(a2->data.polygon.scale); - d[1] = reverse_endianess_int32_t(a2->data.polygon.count); - break; - } - else - switch (a2->data.type) { - case GLITTER_EMITTER_BOX: - *(vec3*)&d[0] = a2->data.box.size; - break; - case GLITTER_EMITTER_CYLINDER: - *(float_t*)&d[0] = a2->data.cylinder.radius; - *(float_t*)&d[1] = a2->data.cylinder.height; - *(float_t*)&d[2] = a2->data.cylinder.start_angle; - *(float_t*)&d[3] = a2->data.cylinder.end_angle; - d[4] = ((int32_t)a2->data.cylinder.direction << 1) - | (a2->data.cylinder.plain ? 1 : 0); - break; - case GLITTER_EMITTER_SPHERE: - *(float_t*)&d[0] = a2->data.sphere.radius; - *(float_t*)&d[1] = a2->data.sphere.latitude; - *(float_t*)&d[2] = a2->data.sphere.longitude; - d[3] = ((int32_t)a2->data.cylinder.direction << 1) - | (a2->data.cylinder.plain ? 1 : 0); - break; - case GLITTER_EMITTER_POLYGON: - *(float_t*)&d[0] = a2->data.polygon.scale; - d[1] = a2->data.polygon.count; - break; - } - - st->header.signature = 0x54494D45; + st->header.signature = reverse_endianess_uint32_t('EMIT'); st->header.length = 0x20; - st->header.use_big_endian = use_big_endian ? true : false; + st->header.use_big_endian = false; st->header.use_section_size = true; st->header.version = a2->version; return true; } -static bool FASTCALL glitter_emitter_unpack_file(int32_t* data, glitter_emitter* a2, bool use_big_endian) { - if (use_big_endian) { - a2->data.start_time = (float_t)reverse_endianess_int32_t(data[0]); - a2->data.life_time = (float_t)reverse_endianess_int32_t(data[1]); - a2->data.loop_start_time = (float_t)reverse_endianess_int32_t(data[2]); - a2->data.loop_end_time = (float_t)reverse_endianess_int32_t(data[3]); - a2->data.flags = reverse_endianess_int32_t(data[4]); +static bool FASTCALL glitter_emitter_unpack_file(GPM, + int32_t* data, glitter_emitter* a2, bool use_big_endian) { + if (glt_type == GLITTER_X) { + if (use_big_endian) { + a2->data.start_time = reverse_endianess_int32_t(data[0]); + a2->data.life_time = reverse_endianess_int32_t(data[1]); + a2->data.loop_start_time = reverse_endianess_int32_t(data[2]); + a2->data.loop_end_time = reverse_endianess_int32_t(data[3]); + a2->data.flags = reverse_endianess_int32_t(data[4]); + } + else { + a2->data.start_time = data[0]; + a2->data.life_time = data[1]; + a2->data.loop_start_time = data[2]; + a2->data.loop_end_time = data[3]; + a2->data.flags = data[4]; + } + + if (a2->version != 3 && a2->version != 4) + return false; + + if (use_big_endian) { + a2->data.type = reverse_endianess_int16_t(*((int16_t*)data + 10)); + a2->data.direction = reverse_endianess_int16_t(*((int16_t*)data + 11)); + a2->data.emission_interval = reverse_endianess_float_t(*(float_t*)&data[6]); + a2->data.particles_per_emission = reverse_endianess_float_t(*(float_t*)&data[7]); + a2->data.timer = reverse_endianess_int16_t(*((int16_t*)data + 16)); + a2->data.seed = reverse_endianess_int32_t(data[9]); + } + else { + a2->data.type = *((int16_t*)data + 10); + a2->data.direction = *((int16_t*)data + 11); + a2->data.emission_interval = *(float_t*)&data[6]; + a2->data.particles_per_emission = *(float_t*)&data[7]; + a2->data.timer = *((int16_t*)data + 16); + a2->data.seed = data[9]; + } + data += a2->version == 3 ? 14 : 13; + + if (use_big_endian) { + a2->translation.x = reverse_endianess_float_t(*(float_t*)&data[0]); + a2->translation.y = reverse_endianess_float_t(*(float_t*)&data[1]); + a2->translation.z = reverse_endianess_float_t(*(float_t*)&data[2]); + a2->rotation.x = reverse_endianess_float_t(*(float_t*)&data[3]); + a2->rotation.y = reverse_endianess_float_t(*(float_t*)&data[4]); + a2->rotation.z = reverse_endianess_float_t(*(float_t*)&data[5]); + a2->scale.x = reverse_endianess_float_t(*(float_t*)&data[6]); + a2->scale.y = reverse_endianess_float_t(*(float_t*)&data[7]); + a2->scale.z = reverse_endianess_float_t(*(float_t*)&data[8]); + a2->data.rotation_add.x = reverse_endianess_float_t(*(float_t*)&data[9]); + a2->data.rotation_add.y = reverse_endianess_float_t(*(float_t*)&data[10]); + a2->data.rotation_add.z = reverse_endianess_float_t(*(float_t*)&data[11]); + a2->data.rotation_add_random.x = reverse_endianess_float_t(*(float_t*)&data[12]); + a2->data.rotation_add_random.y = reverse_endianess_float_t(*(float_t*)&data[13]); + a2->data.rotation_add_random.z = reverse_endianess_float_t(*(float_t*)&data[14]); + } + else { + a2->translation = *(vec3*)&data[0]; + a2->rotation = *(vec3*)&data[3]; + a2->scale = *(vec3*)&data[6]; + a2->data.rotation_add = *(vec3*)&data[9]; + a2->data.rotation_add_random = *(vec3*)&data[12]; + } + data += 15; + + if (use_big_endian) + switch (a2->data.type) { + case GLITTER_EMITTER_BOX: + a2->data.box.size.x = reverse_endianess_float_t(*(float_t*)&data[0]); + a2->data.box.size.y = reverse_endianess_float_t(*(float_t*)&data[1]); + a2->data.box.size.z = reverse_endianess_float_t(*(float_t*)&data[2]); + return true; + case GLITTER_EMITTER_CYLINDER: + a2->data.cylinder.radius = reverse_endianess_float_t(*(float_t*)&data[0]); + a2->data.cylinder.height = reverse_endianess_float_t(*(float_t*)&data[1]); + a2->data.cylinder.start_angle = reverse_endianess_float_t(*(float_t*)&data[2]); + a2->data.cylinder.end_angle = reverse_endianess_float_t(*(float_t*)&data[3]); + a2->data.cylinder.on_edge = reverse_endianess_int32_t(data[4]) & 1 ? true : false; + a2->data.cylinder.direction = reverse_endianess_int32_t(data[4]) >> 1; + return true; + case GLITTER_EMITTER_SPHERE: + a2->data.sphere.radius = reverse_endianess_float_t(*(float_t*)&data[0]); + a2->data.sphere.latitude = reverse_endianess_float_t(*(float_t*)&data[1]); + a2->data.sphere.longitude = reverse_endianess_float_t(*(float_t*)&data[2]); + a2->data.sphere.on_edge = reverse_endianess_int32_t(data[3]) & 1 ? true : false; + a2->data.sphere.direction = reverse_endianess_int32_t(data[3]) >> 1; + return true; + case GLITTER_EMITTER_POLYGON: + a2->data.polygon.size = reverse_endianess_float_t(*(float_t*)&data[0]); + a2->data.polygon.count = reverse_endianess_int32_t(data[1]); + a2->data.polygon.direction = reverse_endianess_int32_t(data[2]) >> 1; + return true; + default: + return false; + } + else + switch (a2->data.type) { + case GLITTER_EMITTER_BOX: + a2->data.box.size = *(vec3*)&data[0]; + return true; + case GLITTER_EMITTER_CYLINDER: + a2->data.cylinder.radius = *(float_t*)&data[0]; + a2->data.cylinder.height = *(float_t*)&data[1]; + a2->data.cylinder.start_angle = *(float_t*)&data[2]; + a2->data.cylinder.end_angle = *(float_t*)&data[3]; + a2->data.cylinder.on_edge = data[4] & 1 ? true : false; + a2->data.cylinder.direction = data[4] >> 1; + return true; + case GLITTER_EMITTER_SPHERE: + a2->data.sphere.radius = *(float_t*)&data[0]; + a2->data.sphere.latitude = *(float_t*)&data[1]; + a2->data.sphere.longitude = *(float_t*)&data[2]; + a2->data.sphere.on_edge = data[3] & 1 ? true : false; + a2->data.sphere.direction = data[3] >> 1; + return true; + case GLITTER_EMITTER_POLYGON: + a2->data.polygon.size = *(float_t*)&data[0]; + a2->data.polygon.count = data[1]; + a2->data.polygon.direction = data[2] >> 1; + return true; + default: + return false; + } } else { - a2->data.start_time = (float_t)data[0]; - a2->data.life_time = (float_t)data[1]; - a2->data.loop_start_time = (float_t)data[2]; - a2->data.loop_end_time = (float_t)data[3]; - a2->data.flags = data[4]; - } - - //a3->data.dword30 = 0; - if (!a2->version) - return false; - - if (use_big_endian) { - a2->data.type = reverse_endianess_int16_t(*((int16_t*)data + 10)); - a2->data.direction = reverse_endianess_int16_t(*((int16_t*)data + 11)); - a2->data.emission_interval = reverse_endianess_float_t(*(float_t*)&data[6]); - a2->data.particles_per_emission = reverse_endianess_float_t(*(float_t*)&data[7]); - //a3->data.dword2C = reverse_endianess_int16_t(*((int16_t*)data + 16)); - /*if (a2->version > 1) - a3->data.dword30 = reverse_endianess_uint16_t(*((uint16_t*)data + 17));*/ - - a2->translation.x = reverse_endianess_float_t(*(float_t*)&data[9]); - a2->translation.y = reverse_endianess_float_t(*(float_t*)&data[10]); - a2->translation.z = reverse_endianess_float_t(*(float_t*)&data[11]); - a2->rotation.x = reverse_endianess_float_t(*(float_t*)&data[12]); - a2->rotation.y = reverse_endianess_float_t(*(float_t*)&data[13]); - a2->rotation.z = reverse_endianess_float_t(*(float_t*)&data[14]); - a2->scale.x = reverse_endianess_float_t(*(float_t*)&data[15]); - a2->scale.y = reverse_endianess_float_t(*(float_t*)&data[16]); - a2->scale.z = reverse_endianess_float_t(*(float_t*)&data[17]); - a2->data.rotation_add.x = reverse_endianess_float_t(*(float_t*)&data[18]); - a2->data.rotation_add.y = reverse_endianess_float_t(*(float_t*)&data[19]); - a2->data.rotation_add.z = reverse_endianess_float_t(*(float_t*)&data[20]); - a2->data.rotation_add_random.x = reverse_endianess_float_t(*(float_t*)&data[21]); - a2->data.rotation_add_random.y = reverse_endianess_float_t(*(float_t*)&data[22]); - a2->data.rotation_add_random.z = reverse_endianess_float_t(*(float_t*)&data[23]); - } - else { - a2->data.type = *((int16_t*)data + 10); - a2->data.direction = *((int16_t*)data + 11); - a2->data.emission_interval = *(float_t*)&data[6]; - a2->data.particles_per_emission = *(float_t*)&data[7]; - //a3->data.dword2C = *((int16_t*)data + 16); - /*if (emit_version > 1) - a3->data.dword30 = *((uint16_t*)data + 17);*/ - - a2->translation = *(vec3*)&data[9]; - a2->rotation = *(vec3*)&data[12]; - a2->scale = *(vec3*)&data[15]; - a2->data.rotation_add = *(vec3*)&data[18]; - a2->data.rotation_add_random = *(vec3*)&data[21]; - } - data += 24; - - if (use_big_endian) - switch (a2->data.type) { - case GLITTER_EMITTER_BOX: - a2->data.box.size.x = reverse_endianess_float_t(*(float_t*)&data[0]); - a2->data.box.size.y = reverse_endianess_float_t(*(float_t*)&data[1]); - a2->data.box.size.z = reverse_endianess_float_t(*(float_t*)&data[2]); - return true; - case GLITTER_EMITTER_CYLINDER: - a2->data.cylinder.radius = reverse_endianess_float_t(*(float_t*)&data[0]); - a2->data.cylinder.height = reverse_endianess_float_t(*(float_t*)&data[1]); - a2->data.cylinder.start_angle = reverse_endianess_float_t(*(float_t*)&data[2]); - a2->data.cylinder.end_angle = reverse_endianess_float_t(*(float_t*)&data[3]); - a2->data.cylinder.plain = reverse_endianess_int32_t(data[4]) & 1 ? true : false; - a2->data.cylinder.direction = reverse_endianess_int32_t(data[4]) >> 1; - return true; - case GLITTER_EMITTER_SPHERE: - a2->data.sphere.radius = reverse_endianess_float_t(*(float_t*)&data[0]); - a2->data.sphere.latitude = reverse_endianess_float_t(*(float_t*)&data[1]); - a2->data.sphere.longitude = reverse_endianess_float_t(*(float_t*)&data[2]); - a2->data.sphere.plain = reverse_endianess_int32_t(data[3]) & 1 ? true : false; - a2->data.sphere.direction = reverse_endianess_int32_t(data[3]) >> 1; - return true; - case GLITTER_EMITTER_POLYGON: - a2->data.polygon.scale = reverse_endianess_float_t(*(float_t*)&data[0]); - a2->data.polygon.count = reverse_endianess_int32_t(data[1]); - return true; + if (use_big_endian) { + a2->data.start_time = reverse_endianess_int32_t(data[0]); + a2->data.life_time = reverse_endianess_int32_t(data[1]); + a2->data.loop_start_time = reverse_endianess_int32_t(data[2]); + a2->data.loop_end_time = reverse_endianess_int32_t(data[3]); + a2->data.flags = reverse_endianess_int32_t(data[4]); } - else - switch (a2->data.type) { - case GLITTER_EMITTER_BOX: - a2->data.box.size = *(vec3*)&data[0]; - return true; - case GLITTER_EMITTER_CYLINDER: - a2->data.cylinder.radius = *(float_t*)&data[0]; - a2->data.cylinder.height = *(float_t*)&data[1]; - a2->data.cylinder.start_angle = *(float_t*)&data[2]; - a2->data.cylinder.end_angle = *(float_t*)&data[3]; - a2->data.cylinder.plain = data[4] & 1 ? true : false; - a2->data.cylinder.direction = data[4] >> 1; - return true; - case GLITTER_EMITTER_SPHERE: - a2->data.sphere.radius = *(float_t*)&data[0]; - a2->data.sphere.latitude = *(float_t*)&data[1]; - a2->data.sphere.longitude = *(float_t*)&data[2]; - a2->data.sphere.plain = data[3] & 1 ? true : false; - a2->data.sphere.direction = data[3] >> 1; - return true; - case GLITTER_EMITTER_POLYGON: - a2->data.polygon.scale = *(float_t*)&data[0]; - a2->data.polygon.count = data[1]; - return true; + else { + a2->data.start_time = data[0]; + a2->data.life_time = data[1]; + a2->data.loop_start_time = data[2]; + a2->data.loop_end_time = data[3]; + a2->data.flags = data[4]; } - return false; + + a2->data.timer = GLITTER_EMITTER_TIMER_BY_TIME; + a2->data.seed = 0; + if (a2->version != 1 && a2->version != 2) + return false; + + if (use_big_endian) { + a2->data.type = reverse_endianess_int16_t(*((int16_t*)data + 10)); + a2->data.direction = reverse_endianess_int16_t(*((int16_t*)data + 11)); + a2->data.emission_interval = reverse_endianess_float_t(*(float_t*)&data[6]); + a2->data.particles_per_emission = reverse_endianess_float_t(*(float_t*)&data[7]); + a2->translation.x = reverse_endianess_float_t(*(float_t*)&data[9]); + a2->translation.y = reverse_endianess_float_t(*(float_t*)&data[10]); + a2->translation.z = reverse_endianess_float_t(*(float_t*)&data[11]); + a2->rotation.x = reverse_endianess_float_t(*(float_t*)&data[12]); + a2->rotation.y = reverse_endianess_float_t(*(float_t*)&data[13]); + a2->rotation.z = reverse_endianess_float_t(*(float_t*)&data[14]); + a2->scale.x = reverse_endianess_float_t(*(float_t*)&data[15]); + a2->scale.y = reverse_endianess_float_t(*(float_t*)&data[16]); + a2->scale.z = reverse_endianess_float_t(*(float_t*)&data[17]); + a2->data.rotation_add.x = reverse_endianess_float_t(*(float_t*)&data[18]); + a2->data.rotation_add.y = reverse_endianess_float_t(*(float_t*)&data[19]); + a2->data.rotation_add.z = reverse_endianess_float_t(*(float_t*)&data[20]); + a2->data.rotation_add_random.x = reverse_endianess_float_t(*(float_t*)&data[21]); + a2->data.rotation_add_random.y = reverse_endianess_float_t(*(float_t*)&data[22]); + a2->data.rotation_add_random.z = reverse_endianess_float_t(*(float_t*)&data[23]); + } + else { + a2->data.type = *((int16_t*)data + 10); + a2->data.direction = *((int16_t*)data + 11); + a2->data.emission_interval = *(float_t*)&data[6]; + a2->data.particles_per_emission = *(float_t*)&data[7]; + a2->translation = *(vec3*)&data[9]; + a2->rotation = *(vec3*)&data[12]; + a2->scale = *(vec3*)&data[15]; + a2->data.rotation_add = *(vec3*)&data[18]; + a2->data.rotation_add_random = *(vec3*)&data[21]; + } + data += 24; + + if (use_big_endian) + switch (a2->data.type) { + case GLITTER_EMITTER_BOX: + a2->data.box.size.x = reverse_endianess_float_t(*(float_t*)&data[0]); + a2->data.box.size.y = reverse_endianess_float_t(*(float_t*)&data[1]); + a2->data.box.size.z = reverse_endianess_float_t(*(float_t*)&data[2]); + return true; + case GLITTER_EMITTER_CYLINDER: + a2->data.cylinder.radius = reverse_endianess_float_t(*(float_t*)&data[0]); + a2->data.cylinder.height = reverse_endianess_float_t(*(float_t*)&data[1]); + a2->data.cylinder.start_angle = reverse_endianess_float_t(*(float_t*)&data[2]); + a2->data.cylinder.end_angle = reverse_endianess_float_t(*(float_t*)&data[3]); + a2->data.cylinder.on_edge = reverse_endianess_int32_t(data[4]) & 1 ? true : false; + a2->data.cylinder.direction = reverse_endianess_int32_t(data[4]) >> 1; + return true; + case GLITTER_EMITTER_SPHERE: + a2->data.sphere.radius = reverse_endianess_float_t(*(float_t*)&data[0]); + a2->data.sphere.latitude = reverse_endianess_float_t(*(float_t*)&data[1]); + a2->data.sphere.longitude = reverse_endianess_float_t(*(float_t*)&data[2]); + a2->data.sphere.on_edge = reverse_endianess_int32_t(data[3]) & 1 ? true : false; + a2->data.sphere.direction = reverse_endianess_int32_t(data[3]) >> 1; + return true; + case GLITTER_EMITTER_POLYGON: + a2->data.polygon.size = reverse_endianess_float_t(*(float_t*)&data[0]); + a2->data.polygon.count = reverse_endianess_int32_t(data[1]); + return true; + default: + return false; + } + else + switch (a2->data.type) { + case GLITTER_EMITTER_BOX: + a2->data.box.size = *(vec3*)&data[0]; + return true; + case GLITTER_EMITTER_CYLINDER: + a2->data.cylinder.radius = *(float_t*)&data[0]; + a2->data.cylinder.height = *(float_t*)&data[1]; + a2->data.cylinder.start_angle = *(float_t*)&data[2]; + a2->data.cylinder.end_angle = *(float_t*)&data[3]; + a2->data.cylinder.on_edge = data[4] & 1 ? true : false; + a2->data.cylinder.direction = data[4] >> 1; + return true; + case GLITTER_EMITTER_SPHERE: + a2->data.sphere.radius = *(float_t*)&data[0]; + a2->data.sphere.latitude = *(float_t*)&data[1]; + a2->data.sphere.longitude = *(float_t*)&data[2]; + a2->data.sphere.on_edge = data[3] & 1 ? true : false; + a2->data.sphere.direction = data[3] >> 1; + return true; + case GLITTER_EMITTER_POLYGON: + a2->data.polygon.size = *(float_t*)&data[0]; + a2->data.polygon.count = data[1]; + return true; + default: + return false; + } + } } diff --git a/src/CRE/Glitter/emitter.h b/src/CRE/Glitter/emitter.h index f6a90396..62f5db6b 100644 --- a/src/CRE/Glitter/emitter.h +++ b/src/CRE/Glitter/emitter.h @@ -7,9 +7,10 @@ #include "glitter.h" -extern glitter_emitter* FASTCALL glitter_emitter_init();; -extern bool FASTCALL glitter_emitter_parse_file(glitter_effect_group* a1, +extern glitter_emitter* FASTCALL glitter_emitter_init(GPM);; +extern glitter_emitter* FASTCALL glitter_emitter_copy(GPM, glitter_emitter* e); +extern bool FASTCALL glitter_emitter_parse_file(GPM, glitter_effect_group* a1, f2_struct* st, vector_ptr_glitter_emitter* vec, glitter_effect* effect); -extern bool FASTCALL glitter_emitter_unparse_file(glitter_effect_group* a1, - f2_struct* st, glitter_emitter* a3, glitter_effect* effect, bool use_big_endian); +extern bool FASTCALL glitter_emitter_unparse_file(GPM, glitter_effect_group* a1, + f2_struct* st, glitter_emitter* a3, glitter_effect* effect); extern void FASTCALL glitter_emitter_dispose(glitter_emitter* e); diff --git a/src/CRE/Glitter/emitter_inst.c b/src/CRE/Glitter/emitter_inst.c index dd682530..1a270fd8 100644 --- a/src/CRE/Glitter/emitter_inst.c +++ b/src/CRE/Glitter/emitter_inst.c @@ -5,19 +5,40 @@ #include "emitter_inst.h" #include "curve.h" -#include "effect_inst.h" #include "particle_inst.h" #include "random.h" +#include "../camera.h" -glitter_emitter_inst* FASTCALL glitter_emitter_inst_init(glitter_emitter* a1, - glitter_scene* a2, glitter_effect_inst* a3) { +extern camera* cam; + +static void FASTCALL glitter_emitter_inst_emit_particle(GPM, + glitter_emitter_inst* a1, float_t emission); +static void FASTCALL glitter_emitter_inst_get_value(GPM, + glitter_emitter_inst* a1, float_t frame); +static void FASTCALL glitter_emitter_inst_update_mat(GPM, + glitter_emitter_inst* a1, glitter_effect_inst* a2); + +glitter_emitter_inst* FASTCALL glitter_emitter_inst_init(GPM, + glitter_emitter* a1, glitter_effect_inst* a2, float_t emission) { glitter_particle** i; glitter_particle_inst* particle; + switch (a1->data.type) { + case GLITTER_EMITTER_BOX: + case GLITTER_EMITTER_CYLINDER: + case GLITTER_EMITTER_SPHERE: + case GLITTER_EMITTER_POLYGON: + break; + default: + return 0; + } + glitter_emitter_inst* ei = force_malloc(sizeof(glitter_emitter_inst)); ei->emitter = a1; ei->data = a1->data; + ei->random_ptr = &a2->random_shared; + ei->random.step = 1; ei->translation = a1->translation; ei->rotation = a1->rotation; ei->scale = a1->scale; @@ -26,56 +47,239 @@ glitter_emitter_inst* FASTCALL glitter_emitter_inst_init(glitter_emitter* a1, ei->scale_all = 1.0f; ei->emission_interval = ei->data.emission_interval; ei->particles_per_emission = ei->data.particles_per_emission; - ei->frame = -ei->data.start_time; + ei->frame = (float_t)-ei->data.start_time; if (ei->data.emission_interval >= -0.000001f) ei->emission = fabs(ei->data.emission_interval) <= 0.000001f ? GLITTER_EMITTER_EMISSION_ON_START : GLITTER_EMITTER_EMISSION_ON_TIMER; else ei->emission = GLITTER_EMITTER_EMISSION_ON_END; - ei->loop = ei->data.flags & GLITTER_EMITTER_FLAG_LOOP ? true : false; + ei->loop = ei->data.flags & GLITTER_EMITTER_LOOP ? true : false; - vector_ptr_glitter_particle_inst_resize(&ei->particles, a1->particles.end - a1->particles.begin); + vector_ptr_glitter_particle_inst_append(&ei->particles, a1->particles.end - a1->particles.begin); for (i = a1->particles.begin; i != a1->particles.end; i++) { if (!*i) continue; - particle = glitter_particle_inst_init(*i, a2, a3); + particle = glitter_particle_inst_init(GPM_VAL, *i, a2, ei, ei->random_ptr, emission); vector_ptr_glitter_particle_inst_push_back(&ei->particles, &particle); } - ei->random = glitter_random_get(); - glitter_random_set(glitter_random_get() + 1); + ei->random.value = glitter_random_get_value(ei->random_ptr); + glitter_random_step_value(ei->random_ptr); return ei; } -void FASTCALL glitter_emitter_inst_copy(glitter_emitter_inst* a1, glitter_emitter_inst* a2, glitter_scene* a3) { - int64_t particles_count; // rbp - int64_t i; // rbx +void FASTCALL glitter_emitter_inst_free(GPM, glitter_emitter_inst* a1, float_t emission) { + glitter_particle_inst** i; - a2->translation = a1->translation; - a2->rotation = a1->rotation; - a2->scale = a1->scale; - a2->mat = a1->mat; - a2->mat_no_scale = a1->mat_no_scale; - a2->scale_all = a1->scale_all; - a2->emission_timer = a1->emission_timer; - a2->emission_interval = a1->emission_interval; - a2->particles_per_emission = a1->particles_per_emission; - a2->random = a1->random; - a2->loop = a1->loop; - a2->emission = a1->emission; - a2->frame = a1->frame; - a2->ended = a1->ended; - - particles_count = a1->particles.end - a1->particles.begin; - if (particles_count != a2->particles.end - a2->particles.begin) + if (a1->ended) return; - for (i = 0; i < particles_count; ++i) - glitter_particle_inst_copy(a1->particles.begin[i], a2->particles.begin[i], a3); + if (a1->emission == GLITTER_EMITTER_EMISSION_ON_END) { + glitter_emitter_inst_emit_particle(GPM_VAL, a1, emission); + a1->emission = GLITTER_EMITTER_EMISSION_EMITTED; + } + + if (a1->loop && a1->data.loop_end_time >= 0.0f) + a1->loop = false; + + a1->ended = true; + if (a1->data.flags & GLITTER_EMITTER_KILL_ON_END) + for (i = a1->particles.begin; i != a1->particles.end; ++i) + glitter_particle_inst_free(*i, true); + else + for (i = a1->particles.begin; i != a1->particles.end; ++i) + glitter_particle_inst_free(*i, false); } -void FASTCALL glitter_emitter_inst_emit(glitter_emitter_inst* a1, glitter_scene* a2) { +void FASTCALL glitter_emitter_inst_emit(GPM, + glitter_emitter_inst* a1, float_t delta_frame, float_t emission) { + if (a1->frame < 0.0f) { + a1->frame += delta_frame; + return; + } + + if (!a1->ended) { + if (a1->emission == GLITTER_EMITTER_EMISSION_ON_TIMER) { + if (a1->emission_timer >= 0.0f || a1->emission_interval >= 0.0f) { + a1->emission_timer -= delta_frame; + while (a1->emission_timer <= 0.0) { + glitter_emitter_inst_emit_particle(GPM_VAL, a1, emission); + if (a1->emission_interval > 0.0f) + a1->emission_timer += a1->emission_interval; + else + a1->emission_timer = -1.0; + } + } + } + else if (a1->emission == GLITTER_EMITTER_EMISSION_ON_START && a1->data.timer == GLITTER_EMITTER_TIMER_BY_TIME) { + a1->emission_timer -= delta_frame; + if (a1->emission_timer < 0.0) { + glitter_emitter_inst_emit_particle(GPM_VAL, a1, emission); + a1->emission = GLITTER_EMITTER_EMISSION_EMITTED; + } + } + } + + if (!a1->loop && a1->frame >= a1->data.life_time) + glitter_emitter_inst_free(GPM_VAL, a1, emission); + a1->frame += delta_frame; +} + +void FASTCALL glitter_emitter_inst_get_mesh_by_type(GPM, glitter_emitter_inst* a1, + int32_t index, vec3* scale, vec3* base_translation, vec3* direction, glitter_random* random) { + float_t radius; + float_t angle; + float_t longitude; + float_t latitude; + vec3 dir; + + switch (a1->data.type) { + case GLITTER_EMITTER_BOX: + vec3_mult(a1->data.box.size, *scale, dir); + vec3_mult_scalar(dir, 0.5f, dir); + glitter_random_get_vec3(GPM_VAL, random, &dir, base_translation); + break; + case GLITTER_EMITTER_CYLINDER: + radius = a1->data.cylinder.radius * scale->x; + if (!a1->data.cylinder.on_edge) + radius = glitter_random_get_float_min_max(GPM_VAL, random, 0.0f, radius); + angle = glitter_random_get_float_min_max(GPM_VAL, random, + a1->data.cylinder.start_angle, a1->data.cylinder.end_angle); + dir.x = cosf(angle); + dir.y = 0.0f; + dir.z = sinf(angle); + base_translation->x = dir.x * radius; + base_translation->y = glitter_random_get_float(GPM_VAL, random, + a1->data.cylinder.height * scale->y * 0.5f); + base_translation->z = dir.z * radius; + if (a1->data.cylinder.direction == GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD) + *direction = dir; + else if (a1->data.cylinder.direction == GLITTER_EMITTER_EMISSION_DIRECTION_INWARD) + vec3_xor(dir, ((vec3){ -0.0f, 0.0f, -0.0f }), *direction); + break; + case GLITTER_EMITTER_SPHERE: + radius = a1->data.sphere.radius * scale->x; + if (!a1->data.sphere.on_edge) + radius = glitter_random_get_float_min_max(GPM_VAL, random, 0.0f, radius); + longitude = glitter_random_get_float_min_max(GPM_VAL, random, + a1->data.sphere.longitude * -0.5f, a1->data.sphere.longitude * 0.5f); + latitude = (float_t)M_PI_2 - glitter_random_get_float_min_max(GPM_VAL, random, + 0.0f, a1->data.sphere.latitude); + dir.x = sinf(longitude) * cosf(latitude); + dir.y = sinf(latitude); + dir.z = cosf(longitude) * cosf(latitude); + vec3_mult_scalar(dir, radius, *base_translation); + if (a1->data.sphere.direction == GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD) + *direction = dir; + else if (a1->data.sphere.direction == GLITTER_EMITTER_EMISSION_DIRECTION_INWARD) + vec3_negate(dir, *direction); + break; + case GLITTER_EMITTER_POLYGON: + base_translation->x = sinf((float_t)index / (float_t)a1->data.polygon.count * 2.0f + * (float_t)M_PI + (float_t)M_PI_2) * a1->data.polygon.size * scale->x; + base_translation->y = 0.0f; + break; + } +} + +bool FASTCALL glitter_emitter_inst_has_ended(glitter_emitter_inst* emitter, bool a2) { + glitter_particle_inst** i; + + if (!emitter->ended) + return false; + else if (!a2) + return true; + + for (i = emitter->particles.begin; i != emitter->particles.end; i++) + if (!glitter_particle_inst_has_ended(*i, a2)) + return false; + return true; +} + +uint8_t FASTCALL glitter_emitter_inst_random_get_step(glitter_emitter_inst* emitter) { + emitter->random.step++; + emitter->random.step++; + return (uint8_t)(emitter->random.step % 60); +} + +void FASTCALL glitter_emitter_inst_reset(glitter_emitter_inst* a1) { + glitter_particle_inst** i; + + a1->loop = a1->data.flags & GLITTER_EMITTER_LOOP ? true : false; + a1->frame = (float_t)-a1->data.start_time; + a1->ended = false; + a1->emission_timer = 0.0f; + if (a1->emission_interval >= -0.000001f) + a1->emission = fabsf(a1->emission_interval) <= 0.000001f + ? GLITTER_EMITTER_EMISSION_ON_START : GLITTER_EMITTER_EMISSION_ON_TIMER; + else + a1->emission = GLITTER_EMITTER_EMISSION_ON_END; + + for (i = a1->particles.begin; i != a1->particles.end; ++i) + glitter_particle_inst_reset(*i); +} + +void FASTCALL glitter_emitter_inst_update_value_frame(GPM, + glitter_emitter_inst* a1, glitter_effect_inst* a2, float_t delta_frame) { + vec3 rotation_add; + + if (a1->frame < 0.0f) + return; + + if (a1->loop) { + if (a1->data.loop_end_time < 0.0f || a1->frame < a1->data.loop_end_time) { + if (a1->frame >= a1->data.life_time) { + a1->frame -= a1->data.life_time; + if (a1->emission == GLITTER_EMITTER_EMISSION_EMITTED && a1->emission_interval > 0.0f) + a1->emission = GLITTER_EMITTER_EMISSION_ON_TIMER; + } + } + else + while (a1->frame > a1->data.loop_end_time) + a1->frame -= a1->data.loop_end_time - a1->data.loop_start_time; + } + + glitter_emitter_inst_get_value(GPM_VAL, a1, a1->frame); + vec3_mult_scalar(a1->data.rotation_add, delta_frame, rotation_add); + vec3_add(a1->rotation, rotation_add, a1->rotation); + glitter_emitter_inst_update_mat(GPM_VAL, a1, a2); +} + +void FASTCALL glitter_emitter_inst_update_value_init(GPM, + glitter_emitter_inst* a1, glitter_effect_inst* a2, float_t delta_frame) { + vec3 rotation_add; + + a1->has_distance = false; + if (a1->frame < 0.0f) + return; + + if (a1->loop) { + if (a1->data.loop_end_time < 0.0f || a1->frame < a1->data.loop_end_time) { + if (a1->frame >= a1->data.life_time) + a1->frame -= a1->data.life_time; + } + else + while (a1->frame > a1->data.loop_end_time) + a1->frame -= a1->data.loop_end_time - a1->data.loop_start_time; + } + + if (a1->frame < 0.0f) + return; + + glitter_emitter_inst_get_value(GPM_VAL, a1, a1->frame); + vec3_mult_scalar(a1->data.rotation_add, delta_frame, rotation_add); + vec3_add(a1->rotation, rotation_add, a1->rotation); + glitter_emitter_inst_update_mat(GPM_VAL, a1, a2); +} + +void FASTCALL glitter_emitter_inst_dispose(glitter_emitter_inst* ei) { + vector_ptr_glitter_particle_inst_free(&ei->particles, glitter_particle_inst_dispose); + free(ei); +} + +static void FASTCALL glitter_emitter_inst_emit_particle(GPM, + glitter_emitter_inst* a1, float_t emission) { int32_t count; glitter_particle_inst** i; @@ -85,173 +289,11 @@ void FASTCALL glitter_emitter_inst_emit(glitter_emitter_inst* a1, glitter_scene* count = 1; for (i = a1->particles.begin; i != a1->particles.end; ++i) - glitter_particle_inst_emit(*i, a2, a1, (int32_t)a1->particles_per_emission, count); + glitter_particle_inst_emit(GPM_VAL, *i, (int32_t)roundf(a1->particles_per_emission), count, emission); } -void FASTCALL glitter_emitter_inst_emit_init(glitter_emitter_inst* a1, - glitter_scene* a2, glitter_effect_inst* a3, float_t delta_frame) { - if (a1->frame < 0.0f) { - a1->frame += delta_frame; - return; - } - - if (!a1->ended) { - if (a1->emission == GLITTER_EMITTER_EMISSION_ON_TIMER) { - if (a1->emission_timer >= 0.0f || a1->emission_interval >= 0.0f) { - a1->emission_timer -= delta_frame; - if (a1->emission_timer <= 0.0f) { - glitter_effect_inst_update_mat(a3); - glitter_emitter_inst_emit(a1, a2); - if (a1->emission_interval > 0.0f) - a1->emission_timer += a1->emission_interval; - else - a1->emission_timer = -1.0f; - } - } - } - else if (a1->emission == GLITTER_EMITTER_EMISSION_ON_START) { - glitter_effect_inst_update_mat(a3); - glitter_emitter_inst_emit(a1, a2); - a1->emission = GLITTER_EMITTER_EMISSION_EMITTED; - } - } - - if (!a1->loop && a1->data.life_time <= a1->frame) - glitter_emitter_inst_free(a1, a2, 0); - - a1->frame += delta_frame; -} - -void FASTCALL glitter_emitter_inst_emit_step(glitter_emitter_inst* a1, - glitter_scene* a2, glitter_effect_inst* a3, float_t delta_frame) { - if (a1->frame < 0.0f) { - a1->frame += delta_frame; - return; - } - - if (!a1->ended) { - if (a1->emission == GLITTER_EMITTER_EMISSION_ON_TIMER) { - if (a1->emission_timer >= 0.0f || a1->emission_interval >= 0.0f) { - a1->emission_timer -= delta_frame; - if (a1->emission_timer <= 0.0f) { - glitter_emitter_inst_emit(a1, a2); - if (a1->emission_interval > 0.0f) - a1->emission_timer += a1->emission_interval; - else - a1->emission_timer = -1.0f; - } - } - } - else if (a1->emission == GLITTER_EMITTER_EMISSION_ON_START) { - a1->emission_timer -= delta_frame; - if (a1->emission_timer <= 0.0f) { - glitter_emitter_inst_emit(a1, a2); - a1->emission = GLITTER_EMITTER_EMISSION_EMITTED; - } - } - } - - if (!a1->loop && a1->data.life_time <= a1->frame) - glitter_emitter_inst_free(a1, a2, 0); - - a1->frame += delta_frame; -} - -void FASTCALL glitter_emitter_inst_free(glitter_emitter_inst* a1, glitter_scene* a2, bool free) { - glitter_particle_inst** i; - - if (a1->ended) { - if (free) - for (i = a1->particles.begin; i != a1->particles.end; ++i) - glitter_particle_inst_free(*i, true); - } - else { - if (a1->emission == GLITTER_EMITTER_EMISSION_ON_END) { - glitter_emitter_inst_emit(a1, a2); - a1->emission = GLITTER_EMITTER_EMISSION_EMITTED; - } - - if (a1->loop && a1->data.loop_end_time >= 0.0f) - a1->loop = false; - - a1->ended = true; - for (i = a1->particles.begin; i != a1->particles.end; ++i) - glitter_particle_inst_free(*i, false); - } -} - -void FASTCALL glitter_emitter_inst_get_mesh_by_type(glitter_emitter_inst* a1, - int32_t index, vec3* scale, vec3* base_translation, vec3* direction) { - float_t radius; // xmm8_4 - float_t angle; // xmm6_4 - float_t v15; // xmm7_4 - float_t v16; // xmm0_4 - float_t v17; // xmm2_4 - float_t v18; // xmm7_4 - float_t v19; // xmm6_4 - float_t longitude; // xmm8_4 - float_t latitude; // xmm6_4 - float_t v26; // xmm7_4 - vec3 v27; - - switch (a1->data.type) { - case GLITTER_EMITTER_BOX: - base_translation->x = glitter_random_get_float_clamp_min_max(a1->data.box.size.x * scale->x * 0.5f); - base_translation->y = glitter_random_get_float_clamp_min_max(a1->data.box.size.y * scale->y * 0.5f); - base_translation->z = glitter_random_get_float_clamp_min_max(a1->data.box.size.z * scale->z * 0.5f); - break; - case GLITTER_EMITTER_CYLINDER: - radius = a1->data.cylinder.radius * scale->x; - if (!a1->data.cylinder.plain) - radius = glitter_random_get_float_clamp(0.0f, radius); - angle = glitter_random_get_float_clamp(a1->data.cylinder.start_angle, a1->data.cylinder.end_angle); - v15 = cosf(angle); - v16 = sinf(angle); - v17 = 1.0f / sqrtf(v16 * v16 + v15 * v15); - v18 = v15 * v17; - v19 = v16 * v17; - base_translation->x = v18 * radius; - base_translation->y = glitter_random_get_float_clamp_min_max(a1->data.cylinder.height * scale->y * 0.5f); - base_translation->z = v19 * radius; - if (a1->data.cylinder.direction == GLITTER_EMITTER_EMISSION_DIRECTION_INWARD) { - direction->x = v18; - direction->y = 0.0f; - direction->z = v19; - } - else if(a1->data.cylinder.direction == GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD) { - direction->x = -v18; - direction->y = 0.0f; - direction->z = -v19; - } - break; - case GLITTER_EMITTER_SPHERE: - radius = a1->data.sphere.radius * scale->x; - if (!a1->data.sphere.plain) - radius = glitter_random_get_float_clamp(0.0f, radius); - longitude = glitter_random_get_float_clamp(a1->data.sphere.longitude * -0.5f, - a1->data.sphere.longitude * 0.5f); - latitude = (float_t)M_PI_2 - glitter_random_get_float_clamp(0.0f, a1->data.sphere.latitude); - v26 = cosf(latitude); - v27.x = sinf(longitude) * v26; - v27.y = sinf(latitude); - v27.z = cosf(longitude) * v26; - vec3_mult_scalar(v27, radius, *base_translation); - if (a1->data.sphere.direction == GLITTER_EMITTER_EMISSION_DIRECTION_INWARD) - *direction = v27; - else if (a1->data.sphere.direction == GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD) - vec3_negate(v27, *direction); - break; - case GLITTER_EMITTER_MESH: - break; - case GLITTER_EMITTER_POLYGON: - base_translation->x = sinf(((float_t)index / (float_t)a1->data.polygon.count * 2.0f) - / (float_t)M_PI + (float_t)M_PI_2) * a1->data.polygon.scale * scale->x; - base_translation->y = 0.0f; - break; - } -} - -void FASTCALL glitter_emitter_inst_get_value(glitter_emitter_inst* a1, float_t frame, int32_t random) { +static void FASTCALL glitter_emitter_inst_get_value(GPM, + glitter_emitter_inst* a1, float_t frame) { int64_t length; glitter_curve* curve; float_t value; @@ -262,7 +304,7 @@ void FASTCALL glitter_emitter_inst_get_value(glitter_emitter_inst* a1, float_t f for (int32_t i = 0; i < length; i++) { curve = a1->emitter->curve.begin[i]; - if (!glitter_curve_get_value(curve, frame, &value, random + i)) + if (!glitter_curve_get_value(GPM_VAL, curve, frame, &value, a1->random.value + i, a1->random_ptr)) continue; switch (curve->type) { @@ -306,208 +348,49 @@ void FASTCALL glitter_emitter_inst_get_value(glitter_emitter_inst* a1, float_t f } } -bool FASTCALL glitter_emitter_inst_has_ended(glitter_emitter_inst* emitter, bool a2) { - glitter_particle_inst** i; - - if (!emitter->ended) - return false; - else if (!a2) - return true; - - for (i = emitter->particles.begin; i != emitter->particles.end; i++) - if (!glitter_particle_inst_has_ended(*i, a2)) - return false; - return true; -} - -void FASTCALL glitter_emitter_inst_render_group_init(glitter_emitter_inst* emitter, float_t delta_frame) { - glitter_particle_inst** i; - - for (i = emitter->particles.begin; i != emitter->particles.end; ++i) - glitter_particle_inst_render_group_init(*i, delta_frame); -} - -void FASTCALL glitter_emitter_inst_reset(glitter_emitter_inst* a1) { - glitter_particle_inst** i; // rbx - - a1->loop = a1->data.flags & GLITTER_EMITTER_FLAG_LOOP ? true : false; - a1->frame = 0.0f; - a1->ended = false; - if (a1->emission_interval >= -0.000001f) - a1->emission = fabsf(a1->emission_interval) <= 0.000001f - ? GLITTER_EMITTER_EMISSION_ON_START : GLITTER_EMITTER_EMISSION_ON_TIMER; - else - a1->emission = GLITTER_EMITTER_EMISSION_ON_END; - - for (i = a1->particles.begin; i != a1->particles.end; ++i) - glitter_particle_inst_reset(*i); -} - -void FASTCALL glitter_emitter_inst_update_mat(glitter_emitter_inst* a1, glitter_effect_inst* a2) { +static void FASTCALL glitter_emitter_inst_update_mat(GPM, + glitter_emitter_inst* a1, glitter_effect_inst* a2) { + bool mult; + vec3 trans; + vec3 rot; vec3 scale; - bool v12; // bl - int64_t v14; // rax - int64_t v15; // r14 - glitter_particle_inst* v17; // rbx - mat4 mat1; - mat4 mat2; + mat4 mat; + mat4 direction_mat; + trans = a1->translation; + rot = a1->rotation; vec3_mult_scalar(a1->scale, a1->scale_all, scale); - mat1 = a2->mat; - v12 = true; + mult = true; switch (a1->data.direction) { - case GLITTER_DIRECTION_BILLBOARD: - mat2 = cam->view; - mat2.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - mat4_inverse(&mat2, &mat2); - mat4_mult(&mat1, &mat2, &mat2); - mat2.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - break; + case GLITTER_DIRECTION_BILLBOARD: { + mat4_invrot(&cam->view, &direction_mat); + direction_mat.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; + mat4_mult(&a2->mat, &direction_mat, &direction_mat); + direction_mat.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; + } break; case GLITTER_DIRECTION_Y_AXIS: - mat4_rotate_y((float_t)-M_PI_2, &mat2); + mat4_rotate_y((float_t)-M_PI_2, &direction_mat); break; case GLITTER_DIRECTION_X_AXIS: - mat4_rotate_x((float_t)-M_PI_2, &mat2); + mat4_rotate_x((float_t)-M_PI_2, &direction_mat); break; case GLITTER_DIRECTION_Z_AXIS: - mat4_rotate_z((float_t)-M_PI_2, &mat2); + mat4_rotate_z((float_t)-M_PI_2, &direction_mat); break; case GLITTER_DIRECTION_BILLBOARD_Y_ONLY: - mat4_rotate_y(cam->rotation.y, &mat2); + mat4_rotate_y(cam->rotation.y, &direction_mat); break; default: - v12 = false; + mult = false; break; } - mat4_translate_mult(&mat1, a1->translation.x, a1->translation.y, a1->translation.z, &mat1); - mat4_normalize_rotation(&mat1, &mat1); - if (v12) - mat4_mult(&mat2, &mat1, &mat1); - mat4_rot(&mat1, a1->rotation.x, a1->rotation.y, a1->rotation.z, &mat1); - a1->mat_no_scale = mat1; - mat4_scale_rot(&mat1, scale.x, scale.y, scale.z, &a1->mat); - - v14 = a1->particles.end - a1->particles.begin; - for (v15 = 0; v14 > 0; v15++, v14--) { - if (!a1->particles.begin[v15]) - continue; - - v17 = a1->particles.begin[v15]; - v17->mat = a1->mat; - v17->mat_no_scale = a1->mat_no_scale; - v17->mat_no_scale.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - glitter_particle_inst_set_mat(v17); - } -} - -void FASTCALL glitter_emitter_inst_update_value_frame(glitter_emitter_inst* a1, - glitter_effect_inst* a2, float_t delta_frame) { - int64_t v7; // r14 - vec3 rotation_add; - vec3 scale; - bool v22; // si - int64_t v24; // rbp - glitter_particle_inst* v26; // rsi - mat4 mat1; - mat4 mat2; - - if (a1->frame < 0.0f) - return; - - if (a1->loop) { - if (a1->data.loop_end_time < 0.0f || a1->frame < a1->data.loop_end_time) { - if (a1->frame >= a1->data.life_time) { - a1->frame -= a1->data.life_time; - if (a1->emission == GLITTER_EMITTER_EMISSION_EMITTED && a1->emission_interval > 0.0f) - a1->emission = GLITTER_EMITTER_EMISSION_ON_TIMER; - } - } - else - while (a1->frame > a1->data.loop_end_time) - a1->frame -= a1->data.loop_end_time - a1->data.loop_start_time; - } - - glitter_emitter_inst_get_value(a1, a1->frame, a1->random); - vec3_mult_scalar(a1->data.rotation_add, delta_frame, rotation_add); - vec3_add(a1->rotation, rotation_add, a1->rotation); - - vec3_mult_scalar(a1->scale, a1->scale_all, scale); - mat1 = a2->mat; - - v22 = true; - switch (a1->data.direction) { - case GLITTER_DIRECTION_BILLBOARD: - mat2 = cam->view; - mat2.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - mat4_inverse(&mat2, &mat2); - mat4_mult(&mat1, &mat2, &mat2); - mat2.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - break; - case GLITTER_DIRECTION_Y_AXIS: - mat4_rotate_y((float_t)-M_PI_2, &mat2); - break; - case GLITTER_DIRECTION_X_AXIS: - mat4_rotate_x((float_t)-M_PI_2, &mat2); - break; - case GLITTER_DIRECTION_Z_AXIS: - mat4_rotate_z((float_t)-M_PI_2, &mat2); - break; - case GLITTER_DIRECTION_BILLBOARD_Y_ONLY: - mat4_rotate_y(cam->rotation.y, &mat2); - break; - default: - v22 = false; - break; - } - - mat4_translate_mult(&mat1, a1->translation.x, a1->translation.y, a1->translation.z, &mat1); - mat4_normalize_rotation(&mat1, &mat1); - if (v22) - mat4_mult(&mat2, &mat1, &mat1); - mat4_rot(&mat1, a1->rotation.x, a1->rotation.y, a1->rotation.z, &mat1); - a1->mat_no_scale = mat1; - mat4_scale_rot(&mat1, scale.x, scale.y, scale.z, &a1->mat); - - v24 = a1->particles.end - a1->particles.begin; - for (v7 = 0; v24 > 0; v7++, v24--) { - if (!a1->particles.begin[v7]) - continue; - - v26 = a1->particles.begin[v7]; - v26->mat = a1->mat; - v26->mat_no_scale = a1->mat_no_scale; - v26->mat_no_scale.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - glitter_particle_inst_set_mat(v26); - } -} - -void FASTCALL glitter_emitter_inst_update_value_init(glitter_emitter_inst* a1, float_t frame, float_t delta_frame) { - vec3 rotation_add; - - if (a1->frame < 0.0f) - return; - - if (a1->loop) { - if (a1->data.loop_end_time < 0.0f || a1->frame < a1->data.loop_end_time) { - if (a1->frame >= a1->data.life_time) - a1->frame = a1->frame - a1->data.life_time; - } - else - while (a1->frame > a1->data.loop_end_time) - a1->frame -= a1->data.loop_end_time - a1->data.loop_start_time; - } - - if (a1->frame < 0.0f) - return; - - glitter_emitter_inst_get_value(a1, a1->frame, a1->random); - vec3_mult_scalar(a1->data.rotation_add, delta_frame, rotation_add); - vec3_add(a1->rotation, rotation_add, a1->rotation); -} - -void FASTCALL glitter_emitter_inst_dispose(glitter_emitter_inst* ei) { - vector_ptr_glitter_particle_inst_free(&ei->particles, (void*)glitter_particle_inst_dispose); - free(ei); + mat4_translate_mult(&a2->mat, trans.x, trans.y, trans.z, &mat); + mat4_normalize_rotation(&mat, &mat); + if (mult) + mat4_mult(&direction_mat, &mat, &mat); + mat4_rot(&mat, rot.x, rot.y, rot.z, &mat); + mat4_scale_rot(&mat, scale.x, scale.y, scale.z, &a1->mat); + a1->mat_no_scale = mat; } diff --git a/src/CRE/Glitter/emitter_inst.h b/src/CRE/Glitter/emitter_inst.h index 90d485ea..74dc47cc 100644 --- a/src/CRE/Glitter/emitter_inst.h +++ b/src/CRE/Glitter/emitter_inst.h @@ -7,25 +7,19 @@ #include "glitter.h" -extern glitter_emitter_inst* FASTCALL glitter_emitter_inst_init(glitter_emitter* a1, - glitter_scene* a2, glitter_effect_inst* a3); -extern void FASTCALL glitter_emitter_inst_copy(glitter_emitter_inst* a1, - glitter_emitter_inst* a2, glitter_scene* a3); -extern void FASTCALL glitter_emitter_inst_emit(glitter_emitter_inst* a1, glitter_scene* a2); -extern void FASTCALL glitter_emitter_inst_emit_init(glitter_emitter_inst* a1, - glitter_scene* a2, glitter_effect_inst* a3, float_t delta_frame); -extern void FASTCALL glitter_emitter_inst_emit_step(glitter_emitter_inst* a1, - glitter_scene* a2, glitter_effect_inst* a3, float_t delta_frame); -extern void FASTCALL glitter_emitter_inst_free(glitter_emitter_inst* a1, glitter_scene* a2, bool free); -extern void FASTCALL glitter_emitter_inst_get_mesh_by_type(glitter_emitter_inst* a1, - int32_t index, vec3* scale, vec3* base_translation, vec3* direction); -extern void FASTCALL glitter_emitter_inst_get_value(glitter_emitter_inst* a1, float_t frame, int32_t random); +extern glitter_emitter_inst* FASTCALL glitter_emitter_inst_init(GPM, + glitter_emitter* a1, glitter_effect_inst* a2, float_t emission); +extern void FASTCALL glitter_emitter_inst_free(GPM, + glitter_emitter_inst* a1, float_t emission); +extern void FASTCALL glitter_emitter_inst_emit(GPM, + glitter_emitter_inst* a1, float_t delta_frame, float_t emission); +extern void FASTCALL glitter_emitter_inst_get_mesh_by_type(GPM, glitter_emitter_inst* a1, + int32_t index, vec3* scale, vec3* base_translation, vec3* direction, glitter_random* random); extern bool FASTCALL glitter_emitter_inst_has_ended(glitter_emitter_inst* emitter, bool a2); -extern void FASTCALL glitter_emitter_inst_render_group_init(glitter_emitter_inst* emitter, float_t delta_frame); +extern uint8_t FASTCALL glitter_emitter_inst_random_get_step(glitter_emitter_inst* emitter); extern void FASTCALL glitter_emitter_inst_reset(glitter_emitter_inst* a1); -extern void FASTCALL glitter_emitter_inst_update_mat(glitter_emitter_inst* a1, glitter_effect_inst* a2); -extern void FASTCALL glitter_emitter_inst_update_value_frame(glitter_emitter_inst* a1, - glitter_effect_inst* a2, float_t delta_frame); -extern void FASTCALL glitter_emitter_inst_update_value_init(glitter_emitter_inst* a1, - float_t frame, float_t delta_frame); +extern void FASTCALL glitter_emitter_inst_update_value_frame(GPM, + glitter_emitter_inst* a1, glitter_effect_inst* a2, float_t delta_frame); +extern void FASTCALL glitter_emitter_inst_update_value_init(GPM, + glitter_emitter_inst* a1, glitter_effect_inst* a2, float_t delta_frame); extern void FASTCALL glitter_emitter_inst_dispose(glitter_emitter_inst* ei); diff --git a/src/CRE/Glitter/file_reader.c b/src/CRE/Glitter/file_reader.c index 2897f458..d3783457 100644 --- a/src/CRE/Glitter/file_reader.c +++ b/src/CRE/Glitter/file_reader.c @@ -11,79 +11,82 @@ #include "particle_manager.h" #include "scene.h" -glitter_file_reader* FASTCALL glitter_file_reader_init(wchar_t* path, - wchar_t* file, bool f2, float_t emission) { +glitter_file_reader* FASTCALL glitter_file_reader_init(GPM, + char* path, char* file, float_t emission) { glitter_file_reader* fr = force_malloc(sizeof(glitter_file_reader)); - fr->path = path_wadd_extension(path ? path : L"rom\\particle\\", 0); - fr->file = path_wadd_extension(file ? file : 0, 0); + fr->path = char_string_to_wchar_t_string(path ? path : "rom\\particle\\"); + fr->file = char_string_to_wchar_t_string(file ? file : 0); fr->emission = emission; - fr->hash = f2 - ? hash_wchar_t_murmurhash(file, 0, false) - : hash_wchar_t_fnv1a64(file); + fr->hash = glt_type != GLITTER_AFT + ? hash_wchar_t_murmurhash(fr->file, 0, false) + : hash_wchar_t_fnv1a64(fr->file); return fr; } -bool FASTCALL glitter_file_reader_read(glitter_file_reader* fr) { +glitter_file_reader* FASTCALL glitter_file_reader_winit(GPM, + wchar_t* path, wchar_t* file, float_t emission) { + glitter_file_reader* fr = force_malloc(sizeof(glitter_file_reader)); + fr->path = str_utils_wcopy(path ? path : L"rom\\particle\\"); + fr->file = str_utils_wcopy(file); + fr->emission = emission; + fr->hash = glt_type != GLITTER_AFT + ? hash_wchar_t_murmurhash(fr->file, 0, false) + : hash_wchar_t_fnv1a64(fr->file); + return fr; +} + +bool FASTCALL glitter_file_reader_read(GPM, glitter_file_reader* fr) { farc* f = farc_init(); - wchar_t* path_temp0; - wchar_t* path_temp1; - path_temp0 = path_wadd_extension(fr->file, L".farc"); - path_temp1 = path_wadd_extension(fr->path, path_temp0); - free(path_temp0); - farc_wread(f, path_temp1, true, false); - free(path_temp1); + wchar_t* file_temp; + wchar_t* path_temp; + file_temp = str_utils_wadd(fr->file, L".farc"); + path_temp = str_utils_wadd(fr->path, file_temp); + free(file_temp); + farc_wread(f, path_temp, true, false); + free(path_temp); farc_file* ff; bool ret = false; - path_temp0 = path_wadd_extension(fr->file, L".dve"); - ff = farc_wread_file(f, path_temp0); - free(path_temp0); + file_temp = str_utils_wadd(fr->file, L".dve"); + ff = farc_wread_file(f, file_temp); + free(file_temp); if (!ff) goto End; - f2_struct* st; - st = f2_struct_init(); - f2_struct_read_memory(st, ff->data, ff->size_uncompressed); - if (st->header.signature == 0x46455644) - ret = glitter_diva_effect_parse_file(fr, st); + f2_struct st; + f2_struct_read_memory(&st, ff->data, ff->size); + if (st.header.signature == 0x46455644) + ret = glitter_diva_effect_parse_file(GPM_VAL, fr, &st); else ret = false; - f2_struct_dispose(st); + f2_struct_free(&st); if (!ret) goto End; - path_temp0 = path_wadd_extension(fr->file, L".drs"); - ff = farc_wread_file(f, path_temp0); - free(path_temp0); + file_temp = str_utils_wadd(fr->file, L".drs"); + ff = farc_wread_file(f, file_temp); + free(file_temp); - ret = false; - if (!ff) - goto End; + if (ff) { + f2_struct st; + f2_struct_read_memory(&st, ff->data, ff->size); + if (st.header.signature == 0x53525644) + glitter_diva_resource_parse_file(fr->effect_group, &st); + f2_struct_free(&st); + } - st = f2_struct_init(); - f2_struct_read_memory(st, ff->data, ff->size_uncompressed); - if (st->header.signature == 0x53525644) - ret = glitter_diva_resource_parse_file(fr->effect_group, st); - else - ret = false; - f2_struct_dispose(st); + file_temp = str_utils_wadd(fr->file, L".lst"); + ff = farc_wread_file(f, file_temp); + free(file_temp); - if (!ret) - goto End; - - path_temp0 = path_wadd_extension(fr->file, L".lst"); - ff = farc_wread_file(f, path_temp0); - free(path_temp0); - - if (!ff) - goto End; - - st = f2_struct_init(); - f2_struct_read_memory(st, ff->data, ff->size_uncompressed); - if (st->header.signature == 0x5453494C) - glitter_diva_list_parse_file(fr->effect_group, st); - f2_struct_dispose(st); + if (ff) { + f2_struct st; + f2_struct_read_memory(&st, ff->data, ff->size); + if (st.header.signature == 0x5453494C) + glitter_diva_list_parse_file(fr->effect_group, &st); + f2_struct_free(&st); + } End: farc_dispose(f); diff --git a/src/CRE/Glitter/file_reader.h b/src/CRE/Glitter/file_reader.h index 568f2958..a3db13ed 100644 --- a/src/CRE/Glitter/file_reader.h +++ b/src/CRE/Glitter/file_reader.h @@ -7,7 +7,9 @@ #include "glitter.h" -extern glitter_file_reader* FASTCALL glitter_file_reader_init(wchar_t* path, - wchar_t* file, bool f2, float_t emission); -extern bool FASTCALL glitter_file_reader_read(glitter_file_reader* fr); +extern glitter_file_reader* FASTCALL glitter_file_reader_init(GPM, + char* path, char* file, float_t emission); +extern glitter_file_reader* FASTCALL glitter_file_reader_winit(GPM, + wchar_t* path, wchar_t* file, float_t emission); +extern bool FASTCALL glitter_file_reader_read(GPM, glitter_file_reader* fr); extern void FASTCALL glitter_file_reader_dispose(glitter_file_reader* fr); diff --git a/src/CRE/Glitter/glitter.c b/src/CRE/Glitter/glitter.c index d793a7e1..d8ef4550 100644 --- a/src/CRE/Glitter/glitter.c +++ b/src/CRE/Glitter/glitter.c @@ -18,3 +18,37 @@ vector_ptr_func(glitter_particle) vector_ptr_func(glitter_particle_inst) vector_ptr_func(glitter_render_group) vector_ptr_func(glitter_scene) + +const float_t glitter_min_emission = 0.01f; + +const glitter_curve_type_flags glitter_effect_curve_flags = 0 + | GLITTER_CURVE_TYPE_TRANSLATION_XYZ + | GLITTER_CURVE_TYPE_ROTATION_XYZ + | GLITTER_CURVE_TYPE_SCALE_XYZ + | GLITTER_CURVE_TYPE_SCALE_ALL; + +const glitter_curve_type_flags glitter_emitter_curve_flags = 0 + | GLITTER_CURVE_TYPE_TRANSLATION_XYZ + | GLITTER_CURVE_TYPE_ROTATION_XYZ + | GLITTER_CURVE_TYPE_SCALE_XYZ + | GLITTER_CURVE_TYPE_SCALE_ALL + | GLITTER_CURVE_TYPE_EMISSION_INTERVAL + | GLITTER_CURVE_TYPE_PARTICLES_PER_EMISSION; + +const glitter_curve_type_flags glitter_particle_curve_flags = 0 + | GLITTER_CURVE_TYPE_TRANSLATION_XYZ + | GLITTER_CURVE_TYPE_ROTATION_XYZ + | GLITTER_CURVE_TYPE_SCALE_XYZ + | GLITTER_CURVE_TYPE_SCALE_ALL + | GLITTER_CURVE_TYPE_COLOR_RGBA + | GLITTER_CURVE_TYPE_UV_SCROLL; + +const glitter_curve_type_flags glitter_particle_x_curve_flags = 0 + | GLITTER_CURVE_TYPE_TRANSLATION_XYZ + | GLITTER_CURVE_TYPE_ROTATION_XYZ + | GLITTER_CURVE_TYPE_SCALE_XYZ + | GLITTER_CURVE_TYPE_SCALE_ALL + | GLITTER_CURVE_TYPE_COLOR_RGBA + | GLITTER_CURVE_TYPE_COLOR_RGB_SCALE + | GLITTER_CURVE_TYPE_UV_SCROLL + | GLITTER_CURVE_TYPE_UV_SCROLL_2ND; diff --git a/src/CRE/Glitter/glitter.h b/src/CRE/Glitter/glitter.h index 1c792c8e..f0a2142a 100644 --- a/src/CRE/Glitter/glitter.h +++ b/src/CRE/Glitter/glitter.h @@ -8,14 +8,14 @@ #include "shared.h" typedef enum glitter_curve_flag { - GLITTER_CURVE_FLAG_RANDOMIZE = 0x01, - GLITTER_CURVE_FLAG_RANDOM_RANGE = 0x02, - GLITTER_CURVE_FLAG_NEGATIVE_RANDOM = 0x04, - GLITTER_CURVE_FLAG_ABSOLUTE = 0x04, - GLITTER_CURVE_FLAG_STEP = 0x08, - GLITTER_CURVE_FLAG_NEGATE = 0x10, - GLITTER_CURVE_FLAG_MULT = 0x20, - GLITTER_CURVE_FLAG_PLAIN = 0x40, + GLITTER_CURVE_RANDOM_RANGE = 0x01, + GLITTER_CURVE_KEY_RANDOM_RANGE = 0x02, + GLITTER_CURVE_RANDOM_RANGE_NEGATE = 0x04, + GLITTER_CURVE_STEP = 0x08, + GLITTER_CURVE_NEGATE = 0x10, + GLITTER_CURVE_RANDOM_RANGE_MULT = 0x20, + GLITTER_CURVE_BAKED = 0x40, + GLITTER_CURVE_BAKED_FULL = 0x80, } glitter_curve_flag; typedef enum glitter_curve_type { @@ -33,70 +33,129 @@ typedef enum glitter_curve_type { GLITTER_CURVE_COLOR_G = 11, GLITTER_CURVE_COLOR_B = 12, GLITTER_CURVE_COLOR_A = 13, - GLITTER_CURVE_UNK14 = 14, - GLITTER_CURVE_UNK15 = 15, - GLITTER_CURVE_UNK16 = 16, - GLITTER_CURVE_UNK17 = 17, - GLITTER_CURVE_UNK18 = 18, - GLITTER_CURVE_UNK19 = 19, + GLITTER_CURVE_COLOR_RGB_SCALE = 14, + GLITTER_CURVE_COLOR_R_2ND = 15, + GLITTER_CURVE_COLOR_G_2ND = 16, + GLITTER_CURVE_COLOR_B_2ND = 17, + GLITTER_CURVE_COLOR_A_2ND = 18, + GLITTER_CURVE_COLOR_RGB_SCALE_2ND = 19, GLITTER_CURVE_EMISSION_INTERVAL = 20, GLITTER_CURVE_PARTICLES_PER_EMISSION = 21, GLITTER_CURVE_U_SCROLL = 22, GLITTER_CURVE_V_SCROLL = 23, + GLITTER_CURVE_U_SCROLL_ALPHA = 24, + GLITTER_CURVE_V_SCROLL_ALPHA = 25, + GLITTER_CURVE_U_SCROLL_2ND = 26, + GLITTER_CURVE_V_SCROLL_2ND = 27, + GLITTER_CURVE_U_SCROLL_ALPHA_2ND = 28, + GLITTER_CURVE_V_SCROLL_ALPHA_2ND = 29, } glitter_curve_type; +typedef enum glitter_curve_type_flags { + GLITTER_CURVE_TYPE_TRANSLATION_X = 0x00000001, + GLITTER_CURVE_TYPE_TRANSLATION_Y = 0x00000002, + GLITTER_CURVE_TYPE_TRANSLATION_Z = 0x00000004, + GLITTER_CURVE_TYPE_ROTATION_X = 0x00000008, + GLITTER_CURVE_TYPE_ROTATION_Y = 0x00000010, + GLITTER_CURVE_TYPE_ROTATION_Z = 0x00000020, + GLITTER_CURVE_TYPE_SCALE_X = 0x00000040, + GLITTER_CURVE_TYPE_SCALE_Y = 0x00000080, + GLITTER_CURVE_TYPE_SCALE_Z = 0x00000100, + GLITTER_CURVE_TYPE_SCALE_ALL = 0x00000200, + GLITTER_CURVE_TYPE_COLOR_R = 0x00000400, + GLITTER_CURVE_TYPE_COLOR_G = 0x00000800, + GLITTER_CURVE_TYPE_COLOR_B = 0x00001000, + GLITTER_CURVE_TYPE_COLOR_A = 0x00002000, + GLITTER_CURVE_TYPE_COLOR_RGB_SCALE = 0x00004000, + GLITTER_CURVE_TYPE_COLOR_R_2ND = 0x00008000, + GLITTER_CURVE_TYPE_COLOR_G_2ND = 0x00010000, + GLITTER_CURVE_TYPE_COLOR_B_2ND = 0x00020000, + GLITTER_CURVE_TYPE_COLOR_A_2ND = 0x00040000, + GLITTER_CURVE_TYPE_COLOR_RGB_SCALE_2ND = 0x00080000, + GLITTER_CURVE_TYPE_EMISSION_INTERVAL = 0x00100000, + GLITTER_CURVE_TYPE_PARTICLES_PER_EMISSION = 0x00200000, + GLITTER_CURVE_TYPE_U_SCROLL = 0x00400000, + GLITTER_CURVE_TYPE_V_SCROLL = 0x00800000, + GLITTER_CURVE_TYPE_U_SCROLL_ALPHA = 0x01000000, + GLITTER_CURVE_TYPE_V_SCROLL_ALPHA = 0x02000000, + GLITTER_CURVE_TYPE_U_SCROLL_2ND = 0x04000000, + GLITTER_CURVE_TYPE_V_SCROLL_2ND = 0x08000000, + GLITTER_CURVE_TYPE_U_SCROLL_ALPHA_2ND = 0x10000000, + GLITTER_CURVE_TYPE_V_SCROLL_ALPHA_2ND = 0x20000000, + + GLITTER_CURVE_TYPE_TRANSLATION_XYZ = 0x00000001 | 0x00000002 | 0x00000004, + GLITTER_CURVE_TYPE_ROTATION_XYZ = 0x00000008 | 0x00000010 | 0x00000020, + GLITTER_CURVE_TYPE_SCALE_XYZ = 0x00000040 | 0x00000080 | 0x00000100, + GLITTER_CURVE_TYPE_COLOR_RGBA = 0x00000400 | 0x00000800 | 0x00001000 | 0x00002000, + GLITTER_CURVE_TYPE_COLOR_RGBA_2ND = 0x00008000 | 0x00010000 | 0x00020000 | 0x00040000, + GLITTER_CURVE_TYPE_UV_SCROLL = 0x00400000 | 0x00800000, + GLITTER_CURVE_TYPE_UV_SCROLL_ALPHA = 0x01000000 | 0x02000000, + GLITTER_CURVE_TYPE_UV_SCROLL_2ND = 0x04000000 | 0x08000000, + GLITTER_CURVE_TYPE_UV_SCROLL_ALPHA_2ND = 0x10000000 | 0x20000000, +} glitter_curve_type_flags; + typedef enum glitter_direction { GLITTER_DIRECTION_BILLBOARD = 0, GLITTER_DIRECTION_EMITTER_DIRECTION = 1, - GLITTER_DIRECTION_TYPE_2_DIR_ANGLE = 2, - GLITTER_DIRECTION_TYPE_3_DIR_ANGLE = 3, + GLITTER_DIRECTION_PREV_POSITION = 2, + GLITTER_DIRECTION_POSITION = 3, GLITTER_DIRECTION_Y_AXIS = 4, GLITTER_DIRECTION_X_AXIS = 5, GLITTER_DIRECTION_Z_AXIS = 6, GLITTER_DIRECTION_BILLBOARD_Y_ONLY = 7, - GLITTER_DIRECTION_TYPE_8_DIR_ANGLE = 8, + GLITTER_DIRECTION_PREV_POSITION_DUP = 8, GLITTER_DIRECTION_EMITTER_ROTATION = 9, GLITTER_DIRECTION_EFFECT_ROTATION = 10, GLITTER_DIRECTION_PARTICLE_ROTATION = 11, } glitter_direction; -typedef enum glitter_effect_a3da_flag { - GLITTER_EFFECT_A3DA_FLAG_SET_A3DA_ONCE = 0x00001, - GLITTER_EFFECT_A3DA_FLAG_SET_A3DA_TRANS_ONLY = 0x00002, - GLITTER_EFFECT_A3DA_FLAG_SET_A3DA_BY_OBJECT_INDEX = 0x10000, -} glitter_effect_a3da_flag; +typedef enum glitter_effect_ext_anim_flag { + GLITTER_EFFECT_EXT_ANIM_SET_EXT_ANIM_ONCE = 0x00001, + GLITTER_EFFECT_EXT_ANIM_EXT_ANIM_TRANS_ONLY = 0x00002, + GLITTER_EFFECT_EXT_ANIM_NO_TRANS_X = 0x00004, + GLITTER_EFFECT_EXT_ANIM_NO_TRANS_Y = 0x00008, + GLITTER_EFFECT_EXT_ANIM_NO_TRANS_Z = 0x00010, + GLITTER_EFFECT_EXT_ANIM_NO_DRAW_IF_NO_DATA = 0x00020, + GLITTER_EFFECT_EXT_ANIM_GET_THEN_UPDATE = 0x00040, + GLITTER_EFFECT_EXT_ANIM_CHARA_ANIM = 0x10000, +} glitter_effect_ext_anim_flag; typedef enum glitter_effect_flag { - GLITTER_EFFECT_FLAG_NONE = 0x00, - GLITTER_EFFECT_FLAG_LOOP = 0x01, - GLITTER_EFFECT_FLAG_LOCAL = 0x02, - GLITTER_EFFECT_FLAG_ALPHA = 0x04, - GLITTER_EFFECT_FLAG_FOG = 0x08, - GLITTER_EFFECT_FLAG_FOG_HEIGHT = 0x10, - GLITTER_EFFECT_FLAG_EMISSION = 0x20, + GLITTER_EFFECT_NONE = 0x00, + GLITTER_EFFECT_LOOP = 0x01, + GLITTER_EFFECT_LOCAL = 0x02, + GLITTER_EFFECT_ALPHA = 0x04, + GLITTER_EFFECT_FOG = 0x08, + GLITTER_EFFECT_FOG_HEIGHT = 0x10, + GLITTER_EFFECT_EMISSION = 0x20, + GLITTER_EFFECT_USE_SEED = 0x40, } glitter_effect_flag; typedef enum glitter_effect_file_flag { - GLITTER_EFFECT_FILE_FLAG_ALPHA = 0x01, - GLITTER_EFFECT_FILE_FLAG_FOG = 0x02, - GLITTER_EFFECT_FILE_FLAG_FOG_HEIGHT = 0x04, - GLITTER_EFFECT_FILE_FLAG_EMISSION = 0x08, + GLITTER_EFFECT_FILE_ALPHA = 0x01, + GLITTER_EFFECT_FILE_FOG = 0x02, + GLITTER_EFFECT_FILE_FOG_HEIGHT = 0x04, + GLITTER_EFFECT_FILE_EMISSION = 0x08, + GLITTER_EFFECT_FILE_USE_SEED = 0x10, } glitter_effect_file_flag; typedef enum glitter_effect_inst_flag { - GLITTER_EFFECT_INST_FLAG_NONE = 0x000, - GLITTER_EFFECT_INST_FLAG_FREE = 0x001, - GLITTER_EFFECT_INST_FLAG_JUST_INIT = 0x002, - GLITTER_EFFECT_INST_FLAG_HAS_A3DA = 0x004, - GLITTER_EFFECT_INST_FLAG_HAS_A3DA_TRANS = 0x008, - GLITTER_EFFECT_INST_FLAG_HAS_A3DA_NON_INIT = 0x010, - GLITTER_EFFECT_INST_FLAG_SET_A3DA_BY_OBJECT_INDEX = 0x020, - GLITTER_EFFECT_INST_FLAG_SET_A3DA_BY_OBJECT_NAME = 0x040, - GLITTER_EFFECT_INST_FLAG_SET_A3DA_ONCE = 0x080, - GLITTER_EFFECT_INST_FLAG_SET_A3DA_TRANS_ONLY = 0x100, - GLITTER_EFFECT_INST_FLAG_SET_MIN_COLOR = 0x200, - GLITTER_EFFECT_INST_FLAG_SET_ADD_MIN_COLOR = 0x400, - GLITTER_EFFECT_INST_FLAG_HAS_A3DA_SCALE = 0x800, + GLITTER_EFFECT_INST_NONE = 0x0000, + GLITTER_EFFECT_INST_FREE = 0x0001, + GLITTER_EFFECT_INST_JUST_INIT = 0x0002, + GLITTER_EFFECT_INST_HAS_EXT_ANIM = 0x0004, + GLITTER_EFFECT_INST_HAS_EXT_ANIM_TRANS = 0x0008, + GLITTER_EFFECT_INST_HAS_EXT_ANIM_NON_INIT = 0x0010, + GLITTER_EFFECT_INST_CHARA_ANIM = 0x0020, + GLITTER_EFFECT_INST_SET_EXT_ANIM_BY_OBJECT_NAME = 0x0040, + GLITTER_EFFECT_INST_SET_EXT_ANIM_ONCE = 0x0080, + GLITTER_EFFECT_INST_EXT_ANIM_TRANS_ONLY = 0x0100, + GLITTER_EFFECT_INST_HAS_EXT_ANIM_SCALE = 0x0200, + GLITTER_EFFECT_INST_NO_EXT_ANIM_TRANS_X = 0x0400, + GLITTER_EFFECT_INST_NO_EXT_ANIM_TRANS_Y = 0x0800, + GLITTER_EFFECT_INST_NO_EXT_ANIM_TRANS_Z = 0x1000, + GLITTER_EFFECT_INST_NO_EXT_ANIM_MAT = 0x2000, + GLITTER_EFFECT_INST_GET_EXT_ANIM_THEN_UPDATE = 0x4000, } glitter_effect_inst_flag; typedef enum glitter_emitter_emission { @@ -107,16 +166,23 @@ typedef enum glitter_emitter_emission { } glitter_emitter_emission; typedef enum glitter_emitter_emission_direction { - GLITTER_EMITTER_EMISSION_DIRECTION_PARTICLE_VELOCITY = 0, - GLITTER_EMITTER_EMISSION_DIRECTION_INWARD = 1, - GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD = 2, + GLITTER_EMITTER_EMISSION_DIRECTION_NONE = 0, + GLITTER_EMITTER_EMISSION_DIRECTION_OUTWARD = 1, + GLITTER_EMITTER_EMISSION_DIRECTION_INWARD = 2, } glitter_emitter_emission_direction; typedef enum glitter_emitter_flag { - GLITTER_EMITTER_FLAG_NONE = 0x00, - GLITTER_EMITTER_FLAG_LOOP = 0x01, + GLITTER_EMITTER_NONE = 0x00, + GLITTER_EMITTER_LOOP = 0x01, + GLITTER_EMITTER_KILL_ON_END = 0x02, + GLITTER_EMITTER_USE_SEED = 0x04, } glitter_emitter_flag; +typedef enum glitter_emitter_timer_type { + GLITTER_EMITTER_TIMER_BY_TIME = 0, + GLITTER_EMITTER_TIMER_BY_DISTANCE = 1, +} glitter_emitter_timer_type; + typedef enum glitter_emitter_type { GLITTER_EMITTER_BOX = 0, GLITTER_EMITTER_CYLINDER = 1, @@ -140,28 +206,36 @@ typedef enum glitter_particle_blend { GLITTER_PARTICLE_BLEND_PUNCH_THROUGH = 5, } glitter_particle_blend; +typedef enum glitter_particle_draw_flags { + GLITTER_PARTICLE_DRAW_NONE = 0x0, + GLITTER_PARTICLE_DRAW_NO_BILLBOARD_CULL = 0x1, +} glitter_particle_draw_flags; + typedef enum glitter_particle_flag { - GLITTER_PARTICLE_FLAG_NONE = 0x00000, - GLITTER_PARTICLE_FLAG_LOOP = 0x00001, - GLITTER_PARTICLE_FLAG_USE_MODEL_MAT = 0x00004, - GLITTER_PARTICLE_FLAG_SCALE_Y_BY_X = 0x00010, - GLITTER_PARTICLE_FLAG_REBOUND_PLANE = 0x00020, - GLITTER_PARTICLE_FLAG_TRANSLATE_BY_EMITTER = 0x00040, - GLITTER_PARTICLE_FLAG_SCALE = 0x00080, - GLITTER_PARTICLE_FLAG_SECOND_TEXTURE = 0x00100, - GLITTER_PARTICLE_FLAG_LOCAL = 0x10000, - GLITTER_PARTICLE_FLAG_EMISSION = 0x20000, + GLITTER_PARTICLE_NONE = 0x00000, + GLITTER_PARTICLE_LOOP = 0x00001, + GLITTER_PARTICLE_EMITTER_LOCAL = 0x00004, + GLITTER_PARTICLE_SCALE_Y_BY_X = 0x00010, + GLITTER_PARTICLE_REBOUND_PLANE = 0x00020, + GLITTER_PARTICLE_ROTATE_BY_EMITTER = 0x00040, + GLITTER_PARTICLE_SCALE = 0x00080, + GLITTER_PARTICLE_SECOND_TEXTURE = 0x00100, + GLITTER_PARTICLE_DEPTH_TEST = 0x00200, + GLITTER_PARTICLE_ROTATE_LOCUS = 0x00800, + GLITTER_PARTICLE_LOCAL = 0x10000, + GLITTER_PARTICLE_EMISSION = 0x20000, } glitter_particle_flag; typedef enum glitter_particle_inst_flag { - GLITTER_PARTICLE_INST_FLAG_NONE = 0x00, - GLITTER_PARTICLE_INST_FLAG_ENDED = 0x01, - GLITTER_PARTICLE_INST_FLAG_NO_CHILD = 0x02, + GLITTER_PARTICLE_INST_NONE = 0x00, + GLITTER_PARTICLE_INST_ENDED = 0x01, + GLITTER_PARTICLE_INST_NO_CHILD = 0x02, } glitter_particle_inst_flag; typedef enum glitter_particle_sub_flag { - GLITTER_PARTICLE_SUB_FLAG_NONE = 0x00000000, - GLITTER_PARTICLE_SUB_FLAG_USE_CURVE = 0x40000000, + GLITTER_PARTICLE_SUB_NONE = 0x00000000, + GLITTER_PARTICLE_SUB_USE_SECONDARY_UV = 0x00400000, + GLITTER_PARTICLE_SUB_USE_CURVE = 0x40000000, } glitter_particle_sub_flag; typedef enum glitter_particle_type { @@ -183,6 +257,12 @@ typedef enum glitter_pivot { GLITTER_PIVOT_BOTTOM_RIGHT = 8, } glitter_pivot; +typedef enum glitter_type { + GLITTER_AFT = 0, + GLITTER_F2 = 1, + GLITTER_X = 2, +} glitter_type; + typedef enum glitter_uv_index_type { GLITTER_UV_INDEX_FIXED = 0, GLITTER_UV_INDEX_INITIAL_RANDOM_FIXED = 1, @@ -197,11 +277,11 @@ typedef enum glitter_uv_index_type { typedef struct glitter_buffer glitter_buffer; typedef struct glitter_curve_key glitter_curve_key; typedef struct glitter_curve glitter_curve; -typedef struct glitter_effect_a3da glitter_effect_a3da; typedef struct glitter_effect_data glitter_effect_data; +typedef struct glitter_effect_ext_anim glitter_effect_ext_anim; typedef struct glitter_effect glitter_effect; typedef struct glitter_effect_group glitter_effect_group; -typedef struct glitter_effect_inst_a3da glitter_effect_inst_a3da; +typedef struct glitter_effect_inst_ext_anim glitter_effect_inst_ext_anim; typedef struct glitter_effect_inst glitter_effect_inst; typedef struct glitter_emitter_box glitter_emitter_box; typedef struct glitter_emitter_cylinder glitter_emitter_cylinder; @@ -214,16 +294,19 @@ typedef struct glitter_file_reader glitter_file_reader; typedef struct glitter_particle_manager glitter_particle_manager; typedef struct glitter_locus_history glitter_locus_history; typedef struct glitter_locus_history_data glitter_locus_history_data; +typedef struct glitter_particle_mesh glitter_particle_mesh; typedef struct glitter_particle_data glitter_particle_data; -typedef struct glitter_particle_sub glitter_particle_sub; typedef struct glitter_particle glitter_particle; typedef struct glitter_particle_inst_data glitter_particle_inst_data; typedef struct glitter_particle_inst glitter_particle_inst; -typedef struct glitter_render_group_sub glitter_render_group_sub; +typedef struct glitter_random glitter_random; +typedef struct glitter_render_element glitter_render_element; typedef struct glitter_render_group glitter_render_group; -typedef struct glitter_scene_sub glitter_scene_sub; typedef struct glitter_scene glitter_scene; +#define GPM glitter_particle_manager* gpm, glitter_type glt_type +#define GPM_VAL gpm, glt_type + vector(glitter_curve_key) vector_ptr(glitter_curve) vector_ptr(glitter_effect) @@ -238,10 +321,22 @@ vector_ptr(glitter_particle_inst) vector_ptr(glitter_render_group) vector_ptr(glitter_scene) +extern const float_t glitter_min_emission; +extern const glitter_curve_type_flags glitter_effect_curve_flags; +extern const glitter_curve_type_flags glitter_emitter_curve_flags; +extern const glitter_curve_type_flags glitter_particle_curve_flags; +extern const glitter_curve_type_flags glitter_particle_x_curve_flags; + +struct glitter_random { + uint32_t value; + uint8_t step; +}; + struct glitter_buffer { vec3 position; vec2 uv; - vec4 color; + vec3 color; + float_t alpha; }; struct glitter_curve_key { @@ -256,31 +351,37 @@ struct glitter_curve_key { struct glitter_curve { glitter_curve_type type; bool repeat; - float_t start_time; - float_t end_time; + int32_t start_time; + int32_t end_time; glitter_curve_flag flags; - float_t max_rand; + float_t random_range; vector_glitter_curve_key keys; +#if defined(CRE_DEV) || defined(CLOUD_DEV) + vector_glitter_curve_key keys_rev; +#endif uint32_t version; uint32_t keys_version; }; -struct glitter_effect_a3da { - uint64_t object_hash; - int32_t object_index; - glitter_effect_a3da_flag flags; - int32_t index; - char mesh_name[128]; -}; - struct glitter_effect_data { uint64_t name_hash; - float_t appear_time; - float_t life_time; - float_t start_time; - glitter_effect_a3da* a3da; + int32_t appear_time; + int32_t life_time; + int32_t start_time; + glitter_effect_ext_anim* ext_anim; glitter_effect_flag flags; float_t emission; + int32_t seed; +}; + +struct glitter_effect_ext_anim { + uint64_t object_hash; + glitter_effect_ext_anim_flag flags; + int32_t instance_id; + uint64_t some_hash; + int32_t index; + int32_t node_index; + char mesh_name[128]; }; struct glitter_effect { @@ -299,22 +400,25 @@ struct glitter_effect_group { uint64_t hash; float_t emission; uint32_t resources_count; - int64_t* resource_hashes; - int32_t* resources; - txp* resources_tex; + vector_uint64_t resource_hashes; + vector_txp resources_tex; + vector_int32_t resources; bool scene_init; bool buffer_init; uint32_t version; }; -struct glitter_effect_inst_a3da { +struct glitter_effect_inst_ext_anim { int32_t dword00; int64_t dword08; - int32_t object_index; - int32_t index; + int32_t instance_id; + uint64_t some_hash; + uint64_t object_hash; + int32_t chara_index; + int32_t node_index; mat4 mat; vec3 translation; - char* mesh_name; + char* name; bool object_is_hrc; }; @@ -328,13 +432,15 @@ struct glitter_effect_inst { vec3 scale; float_t scale_all; mat4 mat; + mat4 mat_ext_anim; vector_ptr_glitter_emitter_inst emitters; - int32_t random; + glitter_random random_shared; glitter_effect_inst_flag flags; size_t id; - glitter_effect_inst_a3da* a3da; - vec4 min_color; - vec3 a3da_scale; + glitter_effect_inst_ext_anim* ext_anim; + vec3 ext_anim_scale; + vector_ptr_glitter_render_group render_groups; + glitter_random random; }; struct glitter_emitter_box { @@ -346,34 +452,34 @@ struct glitter_emitter_cylinder { float_t height; float_t start_angle; float_t end_angle; - bool plain; + bool on_edge; glitter_emitter_emission_direction direction; }; struct glitter_emitter_polygon { - float_t scale; + float_t size; int32_t count; + glitter_emitter_emission_direction direction; }; struct glitter_emitter_sphere { float_t radius; float_t latitude; float_t longitude; - bool plain; + bool on_edge; glitter_emitter_emission_direction direction; }; struct glitter_emitter_data { - float_t start_time; - float_t life_time; - float_t loop_start_time; - float_t loop_end_time; + int32_t start_time; + int32_t life_time; + int32_t loop_start_time; + int32_t loop_end_time; glitter_emitter_flag flags; vec3 rotation_add; vec3 rotation_add_random; - //int32_t dword2C; - //int32_t dword30; + glitter_emitter_timer_type timer; float_t emission_interval; float_t particles_per_emission; glitter_direction direction; @@ -382,6 +488,7 @@ struct glitter_emitter_data { glitter_emitter_cylinder cylinder; glitter_emitter_sphere sphere; glitter_emitter_polygon polygon; + int32_t seed; }; @@ -408,11 +515,14 @@ struct glitter_emitter_inst { glitter_emitter_data data; float_t emission_interval; float_t particles_per_emission; - int32_t random; + glitter_random* random_ptr; bool loop; glitter_emitter_emission emission; float_t frame; bool ended; + bool has_distance; + uint32_t counter; + glitter_random random; }; struct glitter_file_reader { @@ -429,9 +539,9 @@ struct glitter_particle_manager { vector_ptr_glitter_effect_group effect_groups; float_t delta_frame; float_t emission; - uint32_t random; uint32_t counter; - bool f2; + bool draw_all; + bool draw_all_mesh; }; struct glitter_locus_history { @@ -439,14 +549,26 @@ struct glitter_locus_history { }; struct glitter_locus_history_data { - vec3 translation; vec4 color; + vec3 translation; float_t scale; }; +struct glitter_particle_mesh { + uint64_t object_name_hash; + uint64_t object_file_hash; + char object_mesh_name[64]; + uint64_t some_hash; +}; + struct glitter_particle_data { glitter_particle_flag flags; - float_t life_time; + int32_t life_time; + int32_t life_time_random; + int32_t fade_in; + int32_t fade_in_random; + int32_t fade_out; + int32_t fade_out_random; glitter_particle_type type; glitter_pivot pivot; glitter_direction draw_type; @@ -463,21 +585,23 @@ struct glitter_particle_data { float_t speed_random; float_t deceleration; float_t deceleration_random; - vec3 gravitational_acceleration; - vec3 external_acceleration; - vec3 external_acceleration_random; + vec3 gravity; + vec3 acceleration; + vec3 acceleration_random; float_t reflection_coeff; float_t reflection_coeff_random; float_t rebound_plane_y; vec4 color; glitter_uv_index_type uv_index_type; int32_t uv_index; - float_t frame_step_uv; + int32_t frame_step_uv; int32_t uv_index_start; int32_t uv_index_end; int32_t uv_index_count; vec2 uv_scroll_add; float_t uv_scroll_add_scale; + vec2 uv_scroll_2nd_add; + float_t uv_scroll_2nd_add_scale; vec2 split_uv; uint8_t split_u; uint8_t split_v; @@ -487,23 +611,18 @@ struct glitter_particle_data { int32_t count; int32_t locus_history_size; int32_t locus_history_size_random; - //int32_t dword118; + glitter_particle_draw_flags draw_flags; float_t emission; uint64_t tex_hash0; uint64_t tex_hash1; int32_t texture0; int32_t texture1; - //char dword138[0x20]; -}; - -struct glitter_particle_sub { - glitter_particle_data data; - int32_t max_count; + glitter_particle_mesh mesh; }; struct glitter_particle { vector_ptr_glitter_curve curve; - glitter_particle_sub data; + glitter_particle_data data; int32_t version; }; @@ -511,32 +630,33 @@ struct glitter_particle_inst_data { glitter_particle_data data; glitter_particle_inst_flag flags; glitter_render_group* render_group; - glitter_effect_inst* effect_inst; + glitter_random* random_ptr; + glitter_effect_inst* effect; + glitter_emitter_inst* emitter; glitter_particle_inst* parent; glitter_particle* particle; - vector_ptr_glitter_particle_inst particle_insts; + vector_ptr_glitter_particle_inst children; }; struct glitter_particle_inst { glitter_particle* particle; - mat4 mat; - mat4 mat_no_scale; - glitter_particle_inst_data sub; + glitter_particle_inst_data data; }; -struct glitter_render_group_sub { +struct glitter_render_element { bool alive; uint8_t uv_index; - int32_t random; + bool draw; float_t frame; float_t life_time; - float_t rebound_time; + float_t rebound_frame; float_t frame_step_uv; float_t speed; float_t deceleration; vec2 uv; vec4 color; vec3 base_translation; + vec3 base_direction; vec3 translation; vec3 translation_prev; vec3 direction; @@ -545,12 +665,14 @@ struct glitter_render_group_sub { vec3 scale; vec3 rotation; vec3 rotation_add; - float_t rot_z_cos; - float_t rot_z_sin; float_t scale_all; vec2 uv_scroll; + vec2 uv_scroll_2nd; + float_t fade_out_frames; + float_t fade_in_frames; mat4 mat; glitter_locus_history* locus_history; + glitter_random random; }; struct glitter_render_group { @@ -564,34 +686,30 @@ struct glitter_render_group { int32_t split_v; vec2 split_uv; float_t z_offset; - int32_t count; - int32_t ctrl; + size_t count; + size_t ctrl; + size_t disp; int32_t texture0; int32_t texture1; - //char dword48[32]; float_t frame; mat4 mat; mat4 mat_no_scale; - int32_t has_texture1; - glitter_render_group_sub* sub; + mat4 mat_draw; + glitter_render_element* elements; glitter_buffer* buffer; - int32_t max_count; - glitter_particle_inst* particle_inst; + size_t max_count; + glitter_particle_inst* particle; + glitter_random* random_ptr; int32_t alpha; int32_t fog; - int32_t buffer_index; int32_t vao; + int32_t vbo; + int32_t ebo; float_t emission; -}; - -struct glitter_scene_sub { - vector_ptr_glitter_render_group render_groups; - int32_t disp_quad; - int32_t disp_locus; - int32_t disp_line; - int32_t ctrl_quad; - int32_t ctrl_locus; - int32_t ctrl_line; + vector_int32_t vec_key; + vector_int32_t vec_val; + bool use_culling; + bool update_data; }; struct glitter_scene { @@ -599,5 +717,4 @@ struct glitter_scene { uint64_t hash; float_t emission; glitter_effect_group* effect_group; - glitter_scene_sub sub; }; diff --git a/src/CRE/Glitter/list.c b/src/CRE/Glitter/list.c index 36b04f21..23388953 100644 --- a/src/CRE/Glitter/list.c +++ b/src/CRE/Glitter/list.c @@ -5,8 +5,8 @@ #include "texture.h" -bool FASTCALL glitter_list_pack_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian) { - char* data; +bool FASTCALL glitter_list_pack_file(glitter_effect_group* a1, f2_struct* st) { + size_t data; glitter_effect** i; size_t length; @@ -15,30 +15,35 @@ bool FASTCALL glitter_list_pack_file(glitter_effect_group* a1, f2_struct* st, bo memset(st, 0, sizeof(f2_struct)); + vector_enrs_entry e = { 0, 0, 0 }; + enrs_entry ee; + + ee = (enrs_entry){ 0, 1, 4, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + length = 0; for (i = a1->effects.begin; i != a1->effects.end; i++) if (*i) length++; - data = force_malloc(0x10 + 0x80 * length); - st->data = data; + data = (size_t)force_malloc(0x10 + 0x80 * length); + st->data = (void*)data; st->length = 0x10 + 0x80 * length; + st->enrs = e; - if (use_big_endian) - *(uint32_t*)data = reverse_endianess_uint32_t((uint32_t)length); - else - *(uint32_t*)data = (uint32_t)length; - data += 0x04; + *(uint32_t*)data = (uint32_t)length; + data += 4; for (i = a1->effects.begin; i != a1->effects.end; i++) if (*i) { - memcpy(data, (*i)->name, 0x80); + memcpy((void*)data, (*i)->name, 0x80); data += 0x80; } st->header.signature = 0x46464547; st->header.length = 0x20; - st->header.use_big_endian = use_big_endian ? true : false; + st->header.use_big_endian = false; st->header.use_section_size = true; return true; } diff --git a/src/CRE/Glitter/list.h b/src/CRE/Glitter/list.h index 8919e7cc..b9273f80 100644 --- a/src/CRE/Glitter/list.h +++ b/src/CRE/Glitter/list.h @@ -7,5 +7,5 @@ #include "glitter.h" -extern bool FASTCALL glitter_list_pack_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian); +extern bool FASTCALL glitter_list_pack_file(glitter_effect_group* a1, f2_struct* st); extern bool FASTCALL glitter_list_unpack_file(glitter_effect_group* a1, f2_struct* st); diff --git a/src/CRE/Glitter/locus_history.c b/src/CRE/Glitter/locus_history.c index 068751f9..cedca6ef 100644 --- a/src/CRE/Glitter/locus_history.c +++ b/src/CRE/Glitter/locus_history.c @@ -7,48 +7,51 @@ glitter_locus_history* FASTCALL glitter_locus_history_init(size_t size) { glitter_locus_history* lh = force_malloc(sizeof(glitter_locus_history)); - vector_glitter_locus_history_data_resize(&lh->data, size); + vector_glitter_locus_history_data_append(&lh->data, size); return lh; } -void FASTCALL glitter_locus_history_append(glitter_locus_history* a1, - glitter_render_group_sub* a2, glitter_particle_inst* a3) { - glitter_locus_history_data* v5; - int64_t size; - int64_t i; +void FASTCALL glitter_locus_history_append(GPM, glitter_locus_history* a1, + glitter_render_element* a2, glitter_particle_inst* a3) { + glitter_locus_history_data* data; glitter_locus_history_data locus_history; + glitter_emitter_inst* emitter; + ssize_t size; + ssize_t i; vec3 temp; vec3 temp1; - v5 = a1->data.begin; + data = a1->data.begin; size = a1->data.end - a1->data.begin; - if (a3->sub.data.flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) - temp = *(vec3*)&a3->mat.row3; - else - temp = a2->translation; + temp = a2->translation; + if (a3->data.data.flags & GLITTER_PARTICLE_EMITTER_LOCAL && (emitter = a3->data.emitter)) { + vec3 emit_trans; + mat4_get_translation(&emitter->mat, &emit_trans); + vec3_add(temp, emit_trans, temp); + } - locus_history.translation = temp; locus_history.color = a2->color; + locus_history.translation = temp; locus_history.scale = a2->scale_particle.x * a2->scale.x * a2->scale_all; if (size < 1) vector_glitter_locus_history_data_push_back(&a1->data, &locus_history); else if (size == 1) { - locus_history.translation = v5->translation; + locus_history.translation = data->translation; if (a1->data.capacity_end - a1->data.begin > 1) vector_glitter_locus_history_data_push_back(&a1->data, &locus_history); - v5->translation = temp; + data->translation = temp; } else { - temp1 = v5[size - 1].translation; + temp1 = data[size - 1].translation; for (i = size - 1; i > 0; i--) - v5[i].translation = v5[i - 1].translation; + data[i].translation = data[i - 1].translation; if (size < a1->data.capacity_end - a1->data.begin) { locus_history.translation = temp1; vector_glitter_locus_history_data_push_back(&a1->data, &locus_history); } - v5->translation = temp; + data->translation = temp; } } diff --git a/src/CRE/Glitter/locus_history.h b/src/CRE/Glitter/locus_history.h index ce750e9c..47eb26d6 100644 --- a/src/CRE/Glitter/locus_history.h +++ b/src/CRE/Glitter/locus_history.h @@ -8,6 +8,6 @@ #include "glitter.h" extern glitter_locus_history* FASTCALL glitter_locus_history_init(size_t size); -extern void FASTCALL glitter_locus_history_append(glitter_locus_history* a1, - glitter_render_group_sub* a2, glitter_particle_inst* a3); +extern void FASTCALL glitter_locus_history_append(GPM, glitter_locus_history* a1, + glitter_render_element* a2, glitter_particle_inst* a3); extern void FASTCALL glitter_locus_history_dispose(glitter_locus_history* lh); diff --git a/src/CRE/Glitter/particle.c b/src/CRE/Glitter/particle.c index e18536bd..99fc9726 100644 --- a/src/CRE/Glitter/particle.c +++ b/src/CRE/Glitter/particle.c @@ -7,30 +7,40 @@ #include "animation.h" #include "curve.h" -extern glitter_particle_manager* gpm; - -static bool FASTCALL glitter_particle_pack_file(glitter_effect_group* a1, - f2_struct* st, glitter_particle* a3, glitter_effect* effect, bool use_big_endian); -static bool FASTCALL glitter_particle_unpack_file(glitter_effect_group* a1, +static bool FASTCALL glitter_particle_pack_file(GPM, glitter_effect_group* a1, + f2_struct* st, glitter_particle* a3, glitter_effect* effect); +static bool FASTCALL glitter_particle_unpack_file(GPM, glitter_effect_group* a1, void* data, glitter_particle* a3, glitter_effect* effect, bool use_big_endian); -glitter_particle* FASTCALL glitter_particle_init() { +glitter_particle* FASTCALL glitter_particle_init(GPM) { glitter_particle* p = force_malloc(sizeof(glitter_particle)); + p->version = glt_type == GLITTER_X ? 0x05 : 0x03; return p; } -bool FASTCALL glitter_particle_parse_file(glitter_effect_group* a1, +glitter_particle* FASTCALL glitter_particle_copy(GPM, glitter_particle* p) { + if (!p) + return 0; + + glitter_particle* pc = force_malloc(sizeof(glitter_particle)); + *pc = *p; + + pc->curve = (vector_ptr_glitter_curve){ 0, 0, 0 }; + glitter_animation_copy(GPM_VAL, &p->curve, &pc->curve); + return pc; +} + +bool FASTCALL glitter_particle_parse_file(GPM, glitter_effect_group* a1, f2_struct* st, vector_ptr_glitter_particle* vec, glitter_effect* effect) { f2_struct* i; glitter_particle* particle; - int32_t count; if (!st || !st->header.data_size) return false; - particle = glitter_particle_init(); + particle = glitter_particle_init(GPM_VAL); particle->version = st->header.version; - if (!glitter_particle_unpack_file(a1, st->data, particle, effect, st->header.use_big_endian)) { + if (!glitter_particle_unpack_file(GPM_VAL, a1, st->data, particle, effect, st->header.use_big_endian)) { glitter_particle_dispose(particle); return false; } @@ -39,37 +49,56 @@ bool FASTCALL glitter_particle_parse_file(glitter_effect_group* a1, if (!i->header.data_size) continue; - if (i->header.signature == 0x4D494E41) - glitter_animation_parse_file(i, &particle->curve); + if (i->header.signature == reverse_endianess_uint32_t('ANIM')) { + glitter_curve_type_flags flags = 0; + if (glt_type == GLITTER_X) + flags = glitter_particle_x_curve_flags; + else + flags = glitter_particle_curve_flags; + + if (particle->data.type != GLITTER_PARTICLE_MESH) { + flags &= ~GLITTER_CURVE_TYPE_UV_SCROLL_2ND; + if (particle->data.draw_type != GLITTER_DIRECTION_PARTICLE_ROTATION) + flags &= ~(GLITTER_CURVE_TYPE_ROTATION_X | GLITTER_CURVE_TYPE_ROTATION_Y); + } + glitter_animation_parse_file(GPM_VAL, i, &particle->curve, flags); + } } - count = particle->data.data.count; - if (count < 1 && particle->data.data.type == GLITTER_PARTICLE_LOCUS) - count = 30; - else if (count < 1) - count = 250; - particle->data.max_count = 4 * count; + vector_ptr_glitter_particle_push_back(vec, &particle); return true; } -bool FASTCALL glitter_particle_unparse_file(glitter_effect_group* a1, - f2_struct* st, glitter_particle* a3, glitter_effect* effect, bool use_big_endian) { - if (!glitter_particle_pack_file(a1, st, a3, effect, use_big_endian)) +bool FASTCALL glitter_particle_unparse_file(GPM, glitter_effect_group* a1, + f2_struct* st, glitter_particle* a3, glitter_effect* effect) { + if (!glitter_particle_pack_file(GPM_VAL, a1, st, a3, effect)) return false; + glitter_curve_type_flags flags = 0; + if (glt_type == GLITTER_X) + flags = glitter_particle_x_curve_flags; + else + flags = glitter_particle_curve_flags; + + if (a3->data.type != GLITTER_PARTICLE_MESH) { + flags &= ~GLITTER_CURVE_TYPE_UV_SCROLL_2ND; + if (a3->data.draw_type != GLITTER_DIRECTION_PARTICLE_ROTATION) + flags &= ~(GLITTER_CURVE_TYPE_ROTATION_X | GLITTER_CURVE_TYPE_ROTATION_Y); + } + f2_struct s; - if (glitter_animation_unparse_file(&s, &a3->curve, use_big_endian)) + if (glitter_animation_unparse_file(GPM_VAL, &s, &a3->curve, flags)) vector_f2_struct_push_back(&st->sub_structs, &s); return true; } void FASTCALL glitter_particle_dispose(glitter_particle* p) { - vector_ptr_glitter_curve_free(&p->curve, (void*)glitter_curve_dispose); + vector_ptr_glitter_curve_free(&p->curve, glitter_curve_dispose); free(p); } -static bool FASTCALL glitter_particle_pack_file(glitter_effect_group* a1, - f2_struct* st, glitter_particle* a3, glitter_effect* effect, bool use_big_endian) { +static bool FASTCALL glitter_particle_pack_file(GPM, + glitter_effect_group* a1, f2_struct* st, glitter_particle* a3, glitter_effect* effect) { size_t l; size_t d; glitter_particle_flag flags; @@ -78,403 +107,599 @@ static bool FASTCALL glitter_particle_pack_file(glitter_effect_group* a1, return false; memset(st, 0, sizeof(f2_struct)); - - l = 204; - if (a3->version >= 3) - l += 8; - - if (a3->data.data.type == GLITTER_PARTICLE_LOCUS || a3->data.data.type == GLITTER_PARTICLE_MESH) - l += 4; - l += 44; + l = 0; - if (a1->version >= 7) - l += 4; - l += 12; + uint32_t o; + vector_enrs_entry e = { 0, 0, 0 }; + enrs_entry ee; + + ee = (enrs_entry){ 0, 1, 204, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 51, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 204; + + if (a3->version == 3) { + ee = (enrs_entry){ o, 1, 8, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 8; + } + + if (a3->data.type == GLITTER_PARTICLE_LOCUS || a3->data.type == GLITTER_PARTICLE_MESH) { + ee = (enrs_entry){ o, 1, 4, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 4; + } + + ee = (enrs_entry){ o, 4, 44, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_QWORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 4, 5, ENRS_TYPE_DWORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_WORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 2, ENRS_TYPE_DWORD }); + if (a1->version >= 7) { + ee.count++; + ee.size += 4; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 48; + } + else { + vector_enrs_entry_push_back(&e, &ee); + l += o = 44; + } + + ee = (enrs_entry){ o, 2, 12, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_QWORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 12; l = align_val(l, 0x10); d = (size_t)force_malloc(l); st->length = l; st->data = (void*)d; + st->enrs = e; - flags = a3->data.data.flags; - if (effect->data.flags & GLITTER_EFFECT_FLAG_LOCAL) - flags &= ~GLITTER_PARTICLE_FLAG_LOCAL; - if (effect->data.flags & GLITTER_EFFECT_FLAG_EMISSION) - flags &= ~GLITTER_PARTICLE_FLAG_EMISSION; - flags &= ~GLITTER_PARTICLE_FLAG_EMISSION; + flags = a3->data.flags; + if (effect->data.flags & GLITTER_EFFECT_LOCAL) + flags &= ~GLITTER_PARTICLE_LOCAL; + if (effect->data.flags & GLITTER_EFFECT_EMISSION) + flags &= ~GLITTER_PARTICLE_EMISSION; - if (use_big_endian) { - *(int32_t*)d = reverse_endianess_int32_t((int32_t)roundf(a3->data.data.life_time)); - *(int32_t*)(d + 4) = reverse_endianess_int32_t(a3->data.data.type); - *(int32_t*)(d + 8) = reverse_endianess_int32_t(a3->data.data.draw_type); - *(float_t*)(d + 12) = reverse_endianess_float_t(a3->data.data.rotation.x); - *(float_t*)(d + 16) = reverse_endianess_float_t(a3->data.data.rotation.y); - *(float_t*)(d + 20) = reverse_endianess_float_t(a3->data.data.rotation.z); - *(float_t*)(d + 24) = reverse_endianess_float_t(a3->data.data.rotation_random.x); - *(float_t*)(d + 28) = reverse_endianess_float_t(a3->data.data.rotation_random.y); - *(float_t*)(d + 32) = reverse_endianess_float_t(a3->data.data.rotation_random.z); - *(float_t*)(d + 36) = reverse_endianess_float_t(a3->data.data.rotation_add.x); - *(float_t*)(d + 40) = reverse_endianess_float_t(a3->data.data.rotation_add.y); - *(float_t*)(d + 44) = reverse_endianess_float_t(a3->data.data.rotation_add.z); - *(float_t*)(d + 48) = reverse_endianess_float_t(a3->data.data.rotation_add_random.x); - *(float_t*)(d + 52) = reverse_endianess_float_t(a3->data.data.rotation_add_random.y); - *(float_t*)(d + 56) = reverse_endianess_float_t(a3->data.data.rotation_add_random.z); - *(float_t*)(d + 60) = reverse_endianess_float_t(a3->data.data.scale.x); - *(float_t*)(d + 64) = reverse_endianess_float_t(a3->data.data.scale.y); - *(float_t*)(d + 68) = reverse_endianess_float_t(a3->data.data.scale.z); - *(float_t*)(d + 72) = reverse_endianess_float_t(a3->data.data.scale_random.x); - *(float_t*)(d + 76) = reverse_endianess_float_t(a3->data.data.scale_random.y); - *(float_t*)(d + 80) = reverse_endianess_float_t(a3->data.data.scale_random.z); - *(float_t*)(d + 84) = reverse_endianess_float_t(a3->data.data.z_offset); - *(int32_t*)(d + 88) = reverse_endianess_int32_t(a3->data.data.pivot); - *(int32_t*)(d + 92) = reverse_endianess_int32_t(flags); - *(float_t*)(d + 96) = reverse_endianess_float_t(a3->data.data.speed); - *(float_t*)(d + 100) = reverse_endianess_float_t(a3->data.data.speed_random); - *(float_t*)(d + 104) = reverse_endianess_float_t(a3->data.data.deceleration); - *(float_t*)(d + 108) = reverse_endianess_float_t(a3->data.data.deceleration_random); - *(float_t*)(d + 112) = reverse_endianess_float_t(a3->data.data.direction.x); - *(float_t*)(d + 116) = reverse_endianess_float_t(a3->data.data.direction.y); - *(float_t*)(d + 120) = reverse_endianess_float_t(a3->data.data.direction.z); - *(float_t*)(d + 124) = reverse_endianess_float_t(a3->data.data.direction_random.x); - *(float_t*)(d + 128) = reverse_endianess_float_t(a3->data.data.direction_random.y); - *(float_t*)(d + 132) = reverse_endianess_float_t(a3->data.data.direction_random.z); - *(float_t*)(d + 136) = reverse_endianess_float_t(a3->data.data.gravitational_acceleration.x); - *(float_t*)(d + 140) = reverse_endianess_float_t(a3->data.data.gravitational_acceleration.y); - *(float_t*)(d + 144) = reverse_endianess_float_t(a3->data.data.gravitational_acceleration.z); - *(float_t*)(d + 148) = reverse_endianess_float_t(a3->data.data.external_acceleration.x); - *(float_t*)(d + 152) = reverse_endianess_float_t(a3->data.data.external_acceleration.y); - *(float_t*)(d + 156) = reverse_endianess_float_t(a3->data.data.external_acceleration.z); - *(float_t*)(d + 160) = reverse_endianess_float_t(a3->data.data.external_acceleration_random.x); - *(float_t*)(d + 164) = reverse_endianess_float_t(a3->data.data.external_acceleration_random.y); - *(float_t*)(d + 168) = reverse_endianess_float_t(a3->data.data.external_acceleration_random.z); - *(float_t*)(d + 172) = reverse_endianess_float_t(a3->data.data.reflection_coeff); - *(float_t*)(d + 176) = reverse_endianess_float_t(a3->data.data.reflection_coeff_random); - *(float_t*)(d + 180) = reverse_endianess_float_t(a3->data.data.rebound_plane_y); - *(float_t*)(d + 184) = reverse_endianess_float_t(a3->data.data.uv_scroll_add.x); - *(float_t*)(d + 188) = reverse_endianess_float_t(a3->data.data.uv_scroll_add.y); - *(float_t*)(d + 192) = reverse_endianess_float_t(a3->data.data.uv_scroll_add_scale); - *(int32_t*)(d + 196) = reverse_endianess_int32_t(a3->data.data.sub_flags); - *(int32_t*)(d + 200) = reverse_endianess_int32_t(a3->data.data.count); - } - else { - *(int32_t*)d = (int32_t)roundf(a3->data.data.life_time); - *(int32_t*)(d + 4) = a3->data.data.type; - *(int32_t*)(d + 8) = a3->data.data.draw_type; - *(vec3*)(d + 12) = a3->data.data.rotation; - *(vec3*)(d + 24) = a3->data.data.rotation_random; - *(vec3*)(d + 36) = a3->data.data.rotation_add; - *(vec3*)(d + 48) = a3->data.data.rotation_add_random; - *(vec3*)(d + 60) = a3->data.data.scale; - *(vec3*)(d + 72) = a3->data.data.scale_random; - *(float_t*)(d + 84) = a3->data.data.z_offset; - *(int32_t*)(d + 88) = a3->data.data.pivot; - *(int32_t*)(d + 92) = flags; - *(float_t*)(d + 96) = a3->data.data.speed; - *(float_t*)(d + 100) = a3->data.data.speed_random; - *(float_t*)(d + 104) = a3->data.data.deceleration; - *(float_t*)(d + 108) = a3->data.data.deceleration_random; - *(vec3*)(d + 112) = a3->data.data.direction; - *(vec3*)(d + 124) = a3->data.data.direction_random; - *(vec3*)(d + 136) = a3->data.data.gravitational_acceleration; - *(vec3*)(d + 148) = a3->data.data.external_acceleration; - *(vec3*)(d + 160) = a3->data.data.external_acceleration_random; - *(float_t*)(d + 172) = a3->data.data.reflection_coeff; - *(float_t*)(d + 176) = a3->data.data.reflection_coeff_random; - *(float_t*)(d + 180) = a3->data.data.rebound_plane_y; - *(vec2*)(d + 184) = a3->data.data.uv_scroll_add; - *(float_t*)(d + 192) = a3->data.data.uv_scroll_add_scale; - *(int32_t*)(d + 196) = a3->data.data.sub_flags; - *(int32_t*)(d + 200) = a3->data.data.count; - } + *(int32_t*)d = a3->data.life_time; + *(int32_t*)(d + 4) = a3->data.type; + *(int32_t*)(d + 8) = a3->data.draw_type; + *(vec3*)(d + 12) = a3->data.rotation; + *(vec3*)(d + 24) = a3->data.rotation_random; + *(vec3*)(d + 36) = a3->data.rotation_add; + *(vec3*)(d + 48) = a3->data.rotation_add_random; + *(vec3*)(d + 60) = a3->data.scale; + *(vec3*)(d + 72) = a3->data.scale_random; + *(float_t*)(d + 84) = a3->data.z_offset; + *(int32_t*)(d + 88) = a3->data.pivot; + *(int32_t*)(d + 92) = flags; + *(float_t*)(d + 96) = a3->data.speed; + *(float_t*)(d + 100) = a3->data.speed_random; + *(float_t*)(d + 104) = a3->data.deceleration; + *(float_t*)(d + 108) = a3->data.deceleration_random; + *(vec3*)(d + 112) = a3->data.direction; + *(vec3*)(d + 124) = a3->data.direction_random; + *(vec3*)(d + 136) = a3->data.gravity; + *(vec3*)(d + 148) = a3->data.acceleration; + *(vec3*)(d + 160) = a3->data.acceleration_random; + *(float_t*)(d + 172) = a3->data.reflection_coeff; + *(float_t*)(d + 176) = a3->data.reflection_coeff_random; + *(float_t*)(d + 180) = a3->data.rebound_plane_y; + *(vec2*)(d + 184) = a3->data.uv_scroll_add; + *(float_t*)(d + 192) = a3->data.uv_scroll_add_scale; + *(int32_t*)(d + 196) = a3->data.sub_flags; + *(int32_t*)(d + 200) = a3->data.count; d += 204; - if (a3->version >= 3) { - if (use_big_endian) { - //*(int32_t*)d = reverse_endianess_int32_t(a3->data.data.dword118); - *(float_t*)(d + 4) = reverse_endianess_float_t(a3->data.data.emission); - } - else { - //*(int32_t*)d = a3->data.data.dword118; - *(float_t*)(d + 4) = a3->data.data.emission; - } + if (a3->version == 3) { + *(int32_t*)d = 0; + *(float_t*)(d + 4) = a3->data.emission; d += 8; } - if (a3->data.data.type == GLITTER_PARTICLE_LOCUS || a3->data.data.type == GLITTER_PARTICLE_MESH) { - if (use_big_endian) { - *(uint16_t*)d = reverse_endianess_uint16_t(a3->data.data.locus_history_size); - *(uint16_t*)(d + 2) = reverse_endianess_uint16_t(a3->data.data.locus_history_size_random); - } - else { - *(uint16_t*)d = a3->data.data.locus_history_size; - *(uint16_t*)(d + 2) = a3->data.data.locus_history_size_random; - } + if (a3->data.type == GLITTER_PARTICLE_LOCUS || a3->data.type == GLITTER_PARTICLE_MESH) { + *(uint16_t*)d = a3->data.locus_history_size; + *(uint16_t*)(d + 2) = a3->data.locus_history_size_random; d += 4; } - if (use_big_endian) { - *(uint64_t*)d = reverse_endianess_uint64_t(a3->data.data.tex_hash0); - *(uint8_t*)(d + 8) = (uint8_t)roundf(clamp(a3->data.data.color.x, 0.0f, 1.0f) * 255.0f); - *(uint8_t*)(d + 9) = (uint8_t)roundf(clamp(a3->data.data.color.y, 0.0f, 1.0f) * 255.0f); - *(uint8_t*)(d + 10) = (uint8_t)roundf(clamp(a3->data.data.color.z, 0.0f, 1.0f) * 255.0f); - *(uint8_t*)(d + 11) = (uint8_t)roundf(clamp(a3->data.data.color.w, 0.0f, 1.0f) * 255.0f); - *(int32_t*)(d + 12) = reverse_endianess_int32_t(a3->data.data.blend_mode0); - *(int32_t*)(d + 20) = reverse_endianess_int32_t(a3->data.data.split_u); - *(int32_t*)(d + 24) = reverse_endianess_int32_t(a3->data.data.split_v); - *(int32_t*)(d + 28) = reverse_endianess_int32_t(a3->data.data.uv_index_type); - *(int16_t*)(d + 32) = reverse_endianess_int16_t(a3->data.data.uv_index); - *(int16_t*)(d + 34) = reverse_endianess_int16_t((int16_t)roundf(a3->data.data.frame_step_uv)); - *(int32_t*)(d + 36) = reverse_endianess_int32_t(a3->data.data.uv_index_start); - *(int32_t*)(d + 40) = reverse_endianess_int32_t(a3->data.data.uv_index_end); + *(uint64_t*)d = a3->data.tex_hash0; + *(uint8_t*)(d + 8) = (uint8_t)roundf(clamp(a3->data.color.x, 0.0f, 1.0f) * 255.0f); + *(uint8_t*)(d + 9) = (uint8_t)roundf(clamp(a3->data.color.y, 0.0f, 1.0f) * 255.0f); + *(uint8_t*)(d + 10) = (uint8_t)roundf(clamp(a3->data.color.z, 0.0f, 1.0f) * 255.0f); + *(uint8_t*)(d + 11) = (uint8_t)roundf(clamp(a3->data.color.w, 0.0f, 1.0f) * 255.0f); + *(int32_t*)(d + 12) = a3->data.blend_mode0; + *(int32_t*)(d + 16) = 0; + *(int32_t*)(d + 20) = a3->data.split_u; + *(int32_t*)(d + 24) = a3->data.split_v; + *(int32_t*)(d + 28) = a3->data.uv_index_type; + *(int16_t*)(d + 32) = a3->data.uv_index; + *(int16_t*)(d + 34) = (int16_t)a3->data.frame_step_uv; + *(int32_t*)(d + 36) = a3->data.uv_index_start; + *(int32_t*)(d + 40) = a3->data.uv_index_end; + if (a1->version >= 7) { + *(int32_t*)(d + 44) = 0; + d += 48; + } + else + d += 44; + + if (a3->data.flags & GLITTER_PARTICLE_SECOND_TEXTURE) { + *(uint64_t*)d = a3->data.tex_hash1; + *(int32_t*)(d + 8) = a3->data.blend_mode1; + d += 12; } else { - *(uint64_t*)d = a3->data.data.tex_hash0; - *(uint8_t*)(d + 8) = (uint8_t)roundf(clamp(a3->data.data.color.x, 0.0f, 1.0f) * 255.0f); - *(uint8_t*)(d + 9) = (uint8_t)roundf(clamp(a3->data.data.color.y, 0.0f, 1.0f) * 255.0f); - *(uint8_t*)(d + 10) = (uint8_t)roundf(clamp(a3->data.data.color.z, 0.0f, 1.0f) * 255.0f); - *(uint8_t*)(d + 11) = (uint8_t)roundf(clamp(a3->data.data.color.w, 0.0f, 1.0f) * 255.0f); - *(int32_t*)(d + 12) = a3->data.data.blend_mode0; - *(int32_t*)(d + 20) = a3->data.data.split_u; - *(int32_t*)(d + 24) = a3->data.data.split_v; - *(int32_t*)(d + 28) = a3->data.data.uv_index_type; - *(int16_t*)(d + 32) = a3->data.data.uv_index; - *(int16_t*)(d + 34) = (int16_t)roundf(a3->data.data.frame_step_uv); - *(int32_t*)(d + 36) = a3->data.data.uv_index_start; - *(int32_t*)(d + 40) = a3->data.data.uv_index_end; - } - d += 44; - - if (a3->data.data.flags & GLITTER_PARTICLE_FLAG_SECOND_TEXTURE) { - if (a1->version >= 7) { - d += 4; - } - - if (use_big_endian) { - *(uint64_t*)d = reverse_endianess_uint64_t(a3->data.data.tex_hash1); - *(int32_t*)(d + 8) = reverse_endianess_int32_t(a3->data.data.blend_mode1); - } - else { - *(uint64_t*)d = a3->data.data.tex_hash1; - *(int32_t*)(d + 8) = a3->data.data.blend_mode1; - } + *(uint64_t*)d = 0; + *(int32_t*)(d + 8) = 0; d += 12; } - st->header.signature = 0x4C435450; + st->header.signature = reverse_endianess_uint32_t('PTCL'); st->header.length = 0x20; - st->header.use_big_endian = use_big_endian ? true : false; + st->header.use_big_endian = false; st->header.use_section_size = true; st->header.version = a3->version; return true; } -static bool FASTCALL glitter_particle_unpack_file(glitter_effect_group* a1, +static bool FASTCALL glitter_particle_unpack_file(GPM, glitter_effect_group* a1, void* data, glitter_particle* a3, glitter_effect* effect, bool use_big_endian) { uint8_t r; uint8_t b; uint8_t g; uint8_t a; - int32_t blend_mode0; - int32_t uv_index_start; - int32_t frame_step_uv; - int32_t uv_index; + glitter_particle_blend blend_mode0; + glitter_particle_blend blend_mode1; uint64_t tex_hash0; + uint64_t tex_hash1; + int32_t frame_step_uv; + int32_t uv_index_start; + int32_t uv_index; int32_t uv_index_end; int32_t uv_index_type; int32_t uv_max_count; uint8_t split_u; uint8_t split_v; size_t d; + bool has_tex; - d = (size_t)data; - if (use_big_endian) { - a3->data.data.life_time = (float_t)reverse_endianess_int32_t(*(int32_t*)d); - a3->data.data.type = reverse_endianess_int32_t(*(int32_t*)(d + 4)); - a3->data.data.draw_type = reverse_endianess_int32_t(*(int32_t*)(d + 8)); - } - else { - a3->data.data.life_time = (float_t) * (int32_t*)d; - a3->data.data.type = *(int32_t*)(d + 4); - a3->data.data.draw_type = *(int32_t*)(d + 8); - } - - if (a3->version < 2) - return false; - - if (use_big_endian) { - a3->data.data.rotation.x = reverse_endianess_float_t(*(float_t*)(d + 12)); - a3->data.data.rotation.y = reverse_endianess_float_t(*(float_t*)(d + 16)); - a3->data.data.rotation.z = reverse_endianess_float_t(*(float_t*)(d + 20)); - a3->data.data.rotation_random.x = reverse_endianess_float_t(*(float_t*)(d + 24)); - a3->data.data.rotation_random.y = reverse_endianess_float_t(*(float_t*)(d + 28)); - a3->data.data.rotation_random.z = reverse_endianess_float_t(*(float_t*)(d + 32)); - a3->data.data.rotation_add.x = reverse_endianess_float_t(*(float_t*)(d + 36)); - a3->data.data.rotation_add.y = reverse_endianess_float_t(*(float_t*)(d + 40)); - a3->data.data.rotation_add.z = reverse_endianess_float_t(*(float_t*)(d + 44)); - a3->data.data.rotation_add_random.x = reverse_endianess_float_t(*(float_t*)(d + 48)); - a3->data.data.rotation_add_random.y = reverse_endianess_float_t(*(float_t*)(d + 52)); - a3->data.data.rotation_add_random.z = reverse_endianess_float_t(*(float_t*)(d + 56)); - a3->data.data.scale.x = reverse_endianess_float_t(*(float_t*)(d + 60)); - a3->data.data.scale.y = reverse_endianess_float_t(*(float_t*)(d + 64)); - a3->data.data.scale.z = reverse_endianess_float_t(*(float_t*)(d + 68)); - a3->data.data.scale_random.x = reverse_endianess_float_t(*(float_t*)(d + 72)); - a3->data.data.scale_random.y = reverse_endianess_float_t(*(float_t*)(d + 76)); - a3->data.data.scale_random.z = reverse_endianess_float_t(*(float_t*)(d + 80)); - a3->data.data.z_offset = reverse_endianess_float_t(*(float_t*)(d + 84)); - a3->data.data.pivot = reverse_endianess_int32_t(*(int32_t*)(d + 88)); - a3->data.data.flags = reverse_endianess_int32_t(*(int32_t*)(d + 92)); - } - else { - a3->data.data.rotation = *(vec3*)(d + 12); - a3->data.data.rotation_random = *(vec3*)(d + 24); - a3->data.data.rotation_add = *(vec3*)(d + 36); - a3->data.data.rotation_add_random = *(vec3*)(d + 48); - a3->data.data.scale = *(vec3*)(d + 60); - a3->data.data.scale_random = *(vec3*)(d + 72); - a3->data.data.z_offset = *(float_t*)(d + 84); - a3->data.data.pivot = *(int32_t*)(d + 88); - a3->data.data.flags = *(int32_t*)(d + 92); - } - - if (effect->data.flags & GLITTER_EFFECT_FLAG_LOCAL) - a3->data.data.flags |= GLITTER_PARTICLE_FLAG_LOCAL; - if (effect->data.flags & GLITTER_EFFECT_FLAG_EMISSION) - a3->data.data.flags |= GLITTER_PARTICLE_FLAG_EMISSION; - - if (use_big_endian) { - a3->data.data.speed = reverse_endianess_float_t(*(float_t*)(d + 96)); - a3->data.data.speed_random = reverse_endianess_float_t(*(float_t*)(d + 100)); - a3->data.data.deceleration = reverse_endianess_float_t(*(float_t*)(d + 104)); - a3->data.data.deceleration_random = reverse_endianess_float_t(*(float_t*)(d + 108)); - a3->data.data.direction.x = reverse_endianess_float_t(*(float_t*)(d + 112)); - a3->data.data.direction.y = reverse_endianess_float_t(*(float_t*)(d + 116)); - a3->data.data.direction.z = reverse_endianess_float_t(*(float_t*)(d + 120)); - a3->data.data.direction_random.x = reverse_endianess_float_t(*(float_t*)(d + 124)); - a3->data.data.direction_random.y = reverse_endianess_float_t(*(float_t*)(d + 128)); - a3->data.data.direction_random.z = reverse_endianess_float_t(*(float_t*)(d + 132)); - a3->data.data.gravitational_acceleration.x = reverse_endianess_float_t(*(float_t*)(d + 136)); - a3->data.data.gravitational_acceleration.y = reverse_endianess_float_t(*(float_t*)(d + 140)); - a3->data.data.gravitational_acceleration.z = reverse_endianess_float_t(*(float_t*)(d + 144)); - a3->data.data.external_acceleration.x = reverse_endianess_float_t(*(float_t*)(d + 148)); - a3->data.data.external_acceleration.y = reverse_endianess_float_t(*(float_t*)(d + 152)); - a3->data.data.external_acceleration.z = reverse_endianess_float_t(*(float_t*)(d + 156)); - a3->data.data.external_acceleration_random.x = reverse_endianess_float_t(*(float_t*)(d + 160)); - a3->data.data.external_acceleration_random.y = reverse_endianess_float_t(*(float_t*)(d + 164)); - a3->data.data.external_acceleration_random.z = reverse_endianess_float_t(*(float_t*)(d + 168)); - a3->data.data.reflection_coeff = reverse_endianess_float_t(*(float_t*)(d + 172)); - a3->data.data.reflection_coeff_random = reverse_endianess_float_t(*(float_t*)(d + 176)); - a3->data.data.rebound_plane_y = reverse_endianess_float_t(*(float_t*)(d + 180)); - a3->data.data.uv_scroll_add.x = reverse_endianess_float_t(*(float_t*)(d + 184)); - a3->data.data.uv_scroll_add.y = reverse_endianess_float_t(*(float_t*)(d + 188)); - a3->data.data.uv_scroll_add_scale = reverse_endianess_float_t(*(float_t*)(d + 192)); - a3->data.data.sub_flags = reverse_endianess_int32_t(*(int32_t*)(d + 196)); - a3->data.data.count = reverse_endianess_int32_t(*(int32_t*)(d + 200)); - } - else { - a3->data.data.speed = *(float_t*)(d + 96); - a3->data.data.speed_random = *(float_t*)(d + 100); - a3->data.data.deceleration = *(float_t*)(d + 104); - a3->data.data.deceleration_random = *(float_t*)(d + 108); - a3->data.data.direction = *(vec3*)(d + 112); - a3->data.data.direction_random = *(vec3*)(d + 124); - a3->data.data.gravitational_acceleration = *(vec3*)(d + 136); - a3->data.data.external_acceleration = *(vec3*)(d + 148); - a3->data.data.external_acceleration_random = *(vec3*)(d + 160); - a3->data.data.reflection_coeff = *(float_t*)(d + 172); - a3->data.data.reflection_coeff_random = *(float_t*)(d + 176); - a3->data.data.rebound_plane_y = *(float_t*)(d + 180); - a3->data.data.uv_scroll_add = *(vec2*)(d + 184); - a3->data.data.uv_scroll_add_scale = *(float_t*)(d + 192); - a3->data.data.sub_flags = *(int32_t*)(d + 196); - a3->data.data.count = *(int32_t*)(d + 200); - } - d += 204; - - a3->data.data.locus_history_size = 0; - a3->data.data.locus_history_size_random = 0; - //a3->data.data.dword118 = 0; - a3->data.data.emission = 0; - - if (a3->version >= 3) { + if (glt_type == GLITTER_X) { + d = (size_t)data; if (use_big_endian) { - //a3->data.data.dword118 = reverse_endianess_int32_t(*(int32_t*)d); - a3->data.data.emission = reverse_endianess_float_t(*(float_t*)(d + 4)); + a3->data.life_time = reverse_endianess_int32_t(*(int32_t*)d); + a3->data.life_time_random = reverse_endianess_int32_t(*(int32_t*)(d + 4)); + a3->data.fade_in = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + a3->data.fade_in_random = reverse_endianess_int32_t(*(int32_t*)(d + 12)); + a3->data.fade_out = reverse_endianess_int32_t(*(int32_t*)(d + 16)); + a3->data.fade_out_random = reverse_endianess_int32_t(*(int32_t*)(d + 20)); + a3->data.type = reverse_endianess_int32_t(*(int32_t*)(d + 24)); + a3->data.draw_type = reverse_endianess_int32_t(*(int32_t*)(d + 28)); } else { - //a3->data.data.dword118 = *(int32_t*)d; - a3->data.data.emission = *(float_t*)(d + 4); + a3->data.life_time = *(int32_t*)d; + a3->data.life_time_random = *(int32_t*)(d + 4); + a3->data.fade_in = *(int32_t*)(d + 8); + a3->data.fade_in_random = *(int32_t*)(d + 12); + a3->data.fade_out = *(int32_t*)(d + 16); + a3->data.fade_out_random = *(int32_t*)(d + 20); + a3->data.type = *(int32_t*)(d + 24); + a3->data.draw_type = *(int32_t*)(d + 28); } - if (a3->data.data.emission >= 0.0099999998f) - a3->data.data.flags |= GLITTER_PARTICLE_FLAG_EMISSION; - d += 8; - } + if (a3->version != 4 && a3->version != 5) + return false; - if (a3->data.data.type == GLITTER_PARTICLE_LOCUS || a3->data.data.type == GLITTER_PARTICLE_MESH) { if (use_big_endian) { - a3->data.data.locus_history_size = reverse_endianess_uint16_t(*(uint16_t*)d); - a3->data.data.locus_history_size_random = reverse_endianess_uint16_t(*(uint16_t*)(d + 2)); + a3->data.rotation.x = reverse_endianess_float_t(*(float_t*)(d + 32)); + a3->data.rotation.y = reverse_endianess_float_t(*(float_t*)(d + 36)); + a3->data.rotation.z = reverse_endianess_float_t(*(float_t*)(d + 40)); + a3->data.rotation_random.x = reverse_endianess_float_t(*(float_t*)(d + 44)); + a3->data.rotation_random.y = reverse_endianess_float_t(*(float_t*)(d + 48)); + a3->data.rotation_random.z = reverse_endianess_float_t(*(float_t*)(d + 52)); + a3->data.rotation_add.x = reverse_endianess_float_t(*(float_t*)(d + 56)); + a3->data.rotation_add.y = reverse_endianess_float_t(*(float_t*)(d + 60)); + a3->data.rotation_add.z = reverse_endianess_float_t(*(float_t*)(d + 64)); + a3->data.rotation_add_random.x = reverse_endianess_float_t(*(float_t*)(d + 68)); + a3->data.rotation_add_random.y = reverse_endianess_float_t(*(float_t*)(d + 72)); + a3->data.rotation_add_random.z = reverse_endianess_float_t(*(float_t*)(d + 76)); + a3->data.scale.x = reverse_endianess_float_t(*(float_t*)(d + 80)); + a3->data.scale.y = reverse_endianess_float_t(*(float_t*)(d + 84)); + a3->data.scale.z = reverse_endianess_float_t(*(float_t*)(d + 88)); + a3->data.scale_random.x = reverse_endianess_float_t(*(float_t*)(d + 92)); + a3->data.scale_random.y = reverse_endianess_float_t(*(float_t*)(d + 96)); + a3->data.scale_random.z = reverse_endianess_float_t(*(float_t*)(d + 100)); + a3->data.z_offset = reverse_endianess_float_t(*(float_t*)(d + 104)); + a3->data.pivot = reverse_endianess_int32_t(*(int32_t*)(d + 108)); + a3->data.flags = reverse_endianess_int32_t(*(int32_t*)(d + 112)); } else { - a3->data.data.locus_history_size = *(uint16_t*)d; - a3->data.data.locus_history_size_random = *(uint16_t*)(d + 2); + a3->data.rotation = *(vec3*)(d + 32); + a3->data.rotation_random = *(vec3*)(d + 44); + a3->data.rotation_add = *(vec3*)(d + 56); + a3->data.rotation_add_random = *(vec3*)(d + 68); + a3->data.scale = *(vec3*)(d + 80); + a3->data.scale_random = *(vec3*)(d + 92); + a3->data.z_offset = *(float_t*)(d + 104); + a3->data.pivot = *(int32_t*)(d + 108); + a3->data.flags = *(int32_t*)(d + 112); } - d += 4; - } - a3->data.data.texture0 = 0; - a3->data.data.texture1 = 0; - //a3->data.data.dword138[0] = 0; + if (effect->data.flags & GLITTER_EFFECT_LOCAL) + a3->data.flags |= GLITTER_PARTICLE_LOCAL; + if (effect->data.flags & GLITTER_EFFECT_EMISSION) + a3->data.flags |= GLITTER_PARTICLE_EMISSION; - if (use_big_endian) { - tex_hash0 = reverse_endianess_uint64_t(*(uint64_t*)d); - r = *(uint8_t*)(d + 8); - g = *(uint8_t*)(d + 9); - b = *(uint8_t*)(d + 10); - a = *(uint8_t*)(d + 11); - blend_mode0 = reverse_endianess_int32_t(*(int32_t*)(d + 12)); - split_u = (uint8_t)reverse_endianess_int32_t(*(int32_t*)(d + 20)); - split_v = (uint8_t)reverse_endianess_int32_t(*(int32_t*)(d + 24)); - uv_index_type = reverse_endianess_int32_t(*(int32_t*)(d + 28)); - uv_index = reverse_endianess_int16_t(*(int16_t*)(d + 32)); - frame_step_uv = reverse_endianess_int16_t(*(int16_t*)(d + 34)); - uv_index_start = reverse_endianess_int32_t(*(int32_t*)(d + 36)); - uv_index_end = reverse_endianess_int32_t(*(int32_t*)(d + 40)); + if (use_big_endian) { + a3->data.uv_scroll_2nd_add.x = reverse_endianess_float_t(*(float_t*)(d + 120)); + a3->data.uv_scroll_2nd_add.y = reverse_endianess_float_t(*(float_t*)(d + 124)); + a3->data.uv_scroll_2nd_add_scale = reverse_endianess_float_t(*(float_t*)(d + 128)); + a3->data.speed = reverse_endianess_float_t(*(float_t*)(d + 136)); + a3->data.speed_random = reverse_endianess_float_t(*(float_t*)(d + 140)); + a3->data.deceleration = reverse_endianess_float_t(*(float_t*)(d + 144)); + a3->data.deceleration_random = reverse_endianess_float_t(*(float_t*)(d + 148)); + a3->data.direction.x = reverse_endianess_float_t(*(float_t*)(d + 152)); + a3->data.direction.y = reverse_endianess_float_t(*(float_t*)(d + 156)); + a3->data.direction.z = reverse_endianess_float_t(*(float_t*)(d + 160)); + a3->data.direction_random.x = reverse_endianess_float_t(*(float_t*)(d + 164)); + a3->data.direction_random.y = reverse_endianess_float_t(*(float_t*)(d + 168)); + a3->data.direction_random.z = reverse_endianess_float_t(*(float_t*)(d + 172)); + a3->data.gravity.x = reverse_endianess_float_t(*(float_t*)(d + 176)); + a3->data.gravity.y = reverse_endianess_float_t(*(float_t*)(d + 180)); + a3->data.gravity.z = reverse_endianess_float_t(*(float_t*)(d + 184)); + a3->data.acceleration.x = reverse_endianess_float_t(*(float_t*)(d + 188)); + a3->data.acceleration.y = reverse_endianess_float_t(*(float_t*)(d + 192)); + a3->data.acceleration.z = reverse_endianess_float_t(*(float_t*)(d + 196)); + a3->data.acceleration_random.x = reverse_endianess_float_t(*(float_t*)(d + 200)); + a3->data.acceleration_random.y = reverse_endianess_float_t(*(float_t*)(d + 204)); + a3->data.acceleration_random.z = reverse_endianess_float_t(*(float_t*)(d + 208)); + a3->data.reflection_coeff = reverse_endianess_float_t(*(float_t*)(d + 212)); + a3->data.reflection_coeff_random = reverse_endianess_float_t(*(float_t*)(d + 216)); + a3->data.rebound_plane_y = reverse_endianess_float_t(*(float_t*)(d + 220)); + a3->data.uv_scroll_add.x = reverse_endianess_float_t(*(float_t*)(d + 224)); + a3->data.uv_scroll_add.y = reverse_endianess_float_t(*(float_t*)(d + 228)); + a3->data.uv_scroll_add_scale = reverse_endianess_float_t(*(float_t*)(d + 232)); + a3->data.sub_flags = reverse_endianess_int32_t(*(int32_t*)(d + 236)); + a3->data.count = reverse_endianess_int32_t(*(int32_t*)(d + 240)); + a3->data.draw_flags = reverse_endianess_int32_t(*(int32_t*)(d + 244)); + a3->data.emission = reverse_endianess_float_t(*(float_t*)(d + 252)); + } + else { + a3->data.uv_scroll_2nd_add.x = *(float_t*)(d + 120); + a3->data.uv_scroll_2nd_add.y = *(float_t*)(d + 124); + a3->data.uv_scroll_2nd_add_scale = *(float_t*)(d + 128); + a3->data.speed = *(float_t*)(d + 136); + a3->data.speed_random = *(float_t*)(d + 140); + a3->data.deceleration = *(float_t*)(d + 144); + a3->data.deceleration_random = *(float_t*)(d + 148); + a3->data.direction = *(vec3*)(d + 152); + a3->data.direction_random = *(vec3*)(d + 164); + a3->data.gravity = *(vec3*)(d + 176); + a3->data.acceleration = *(vec3*)(d + 188); + a3->data.acceleration_random = *(vec3*)(d + 200); + a3->data.reflection_coeff = *(float_t*)(d + 212); + a3->data.reflection_coeff_random = *(float_t*)(d + 216); + a3->data.rebound_plane_y = *(float_t*)(d + 220); + a3->data.uv_scroll_add = *(vec2*)(d + 224); + a3->data.uv_scroll_add_scale = *(float_t*)(d + 232); + a3->data.sub_flags = *(int32_t*)(d + 236); + a3->data.count = *(int32_t*)(d + 240); + a3->data.draw_flags = *(int32_t*)(d + 244); + a3->data.emission = *(float_t*)(d + 252); + } + d += 256; + + if (a3->version == 4) { + vec3_mult_scalar(a3->data.direction, 10.0f, a3->data.direction); + vec3_mult_scalar(a3->data.direction_random, 10.0f, a3->data.direction_random); + } + + if (a3->data.emission >= glitter_min_emission) + a3->data.flags |= GLITTER_PARTICLE_EMISSION; + + a3->data.locus_history_size = 0; + a3->data.locus_history_size_random = 0; + + if (a3->data.type == GLITTER_PARTICLE_MESH) + a3->data.type = GLITTER_PARTICLE_LINE; + else if (a3->data.type == GLITTER_PARTICLE_LINE) + a3->data.type = GLITTER_PARTICLE_MESH; + + if (a3->data.type == GLITTER_PARTICLE_QUAD) + has_tex = true; + else if (a3->data.type == GLITTER_PARTICLE_LINE) + has_tex = false; + else if (a3->data.type == GLITTER_PARTICLE_LOCUS) { + if (use_big_endian) { + a3->data.locus_history_size = reverse_endianess_uint16_t(*(uint16_t*)(d + 0)); + a3->data.locus_history_size_random = reverse_endianess_uint16_t(*(uint16_t*)(d + 2)); + } + else { + a3->data.locus_history_size = *(uint16_t*)(d + 0); + a3->data.locus_history_size_random = *(uint16_t*)(d + 2); + } + d += 4; + has_tex = true; + } + else if (a3->data.type == GLITTER_PARTICLE_MESH) { + a3->data.mesh.object_name_hash = *(uint64_t*)d; + a3->data.mesh.object_file_hash = *(uint64_t*)(d + 8); + memcpy(a3->data.mesh.object_mesh_name, (void*)(d + 16), 0x40); + a3->data.mesh.some_hash = *(uint64_t*)(d + 80); + d += 88; + has_tex = false; + } + else + return false; + + a3->data.texture0 = 0; + a3->data.texture1 = 0; + + tex_hash0 = hash_murmurhash_empty; + tex_hash1 = hash_murmurhash_empty; + + if (use_big_endian) { + if (has_tex) + tex_hash0 = reverse_endianess_uint64_t(*(uint64_t*)d); + r = *(uint8_t*)(d + 8); + g = *(uint8_t*)(d + 9); + b = *(uint8_t*)(d + 10); + a = *(uint8_t*)(d + 11); + blend_mode0 = reverse_endianess_int32_t(*(int32_t*)(d + 12)); + split_u = (uint8_t)reverse_endianess_int32_t(*(int32_t*)(d + 20)); + split_v = (uint8_t)reverse_endianess_int32_t(*(int32_t*)(d + 24)); + uv_index_type = reverse_endianess_int32_t(*(int32_t*)(d + 28)); + uv_index = reverse_endianess_int16_t(*(int16_t*)(d + 32)); + frame_step_uv = reverse_endianess_int16_t(*(int16_t*)(d + 34)); + uv_index_start = reverse_endianess_int32_t(*(int32_t*)(d + 36)); + uv_index_end = reverse_endianess_int32_t(*(int32_t*)(d + 40)); + } + else { + if (has_tex) + tex_hash0 = *(uint64_t*)d; + r = *(uint8_t*)(d + 8); + g = *(uint8_t*)(d + 9); + b = *(uint8_t*)(d + 10); + a = *(uint8_t*)(d + 11); + blend_mode0 = *(int32_t*)(d + 12); + split_u = (uint8_t) * (int32_t*)(d + 20); + split_v = (uint8_t) * (int32_t*)(d + 24); + uv_index_type = *(int32_t*)(d + 28); + uv_index = *(int16_t*)(d + 32); + frame_step_uv = *(int16_t*)(d + 34); + uv_index_start = *(int32_t*)(d + 36); + uv_index_end = *(int32_t*)(d + 40); + } + d += 48; + + if (a3->data.flags & GLITTER_PARTICLE_SECOND_TEXTURE) + if (use_big_endian) { + if (has_tex) + tex_hash1 = reverse_endianess_uint64_t(*(uint64_t*)d); + blend_mode1 = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + } + else { + if (has_tex) + tex_hash1 = *(uint64_t*)d; + blend_mode1 = *(int32_t*)(d + 8); + } + else + blend_mode1 = GLITTER_PARTICLE_BLEND_TYPICAL; } else { - tex_hash0 = *(uint64_t*)d; - r = *(uint8_t*)(d + 8); - g = *(uint8_t*)(d + 9); - b = *(uint8_t*)(d + 10); - a = *(uint8_t*)(d + 11); - blend_mode0 = *(int32_t*)(d + 12); - split_u = (uint8_t) * (int32_t*)(d + 20); - split_v = (uint8_t) * (int32_t*)(d + 24); - uv_index_type = *(int32_t*)(d + 28); - uv_index = *(int16_t*)(d + 32); - frame_step_uv = *(int16_t*)(d + 34); - uv_index_start = *(int32_t*)(d + 36); - uv_index_end = *(int32_t*)(d + 40); - } - d += 44; + d = (size_t)data; + if (use_big_endian) { + a3->data.life_time = reverse_endianess_int32_t(*(int32_t*)d); + a3->data.type = reverse_endianess_int32_t(*(int32_t*)(d + 4)); + a3->data.draw_type = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + } + else { + a3->data.life_time = *(int32_t*)d; + a3->data.type = *(int32_t*)(d + 4); + a3->data.draw_type = *(int32_t*)(d + 8); + } - a3->data.data.tex_hash0 = tex_hash0; - a3->data.data.tex_hash1 = gpm->f2 ? 0x0CAD3078 : 0xCBF29CE44FD0BFC1; - a3->data.data.color.x = (float_t)r * (float_t)(1.0 / 255.0); - a3->data.data.color.y = (float_t)g * (float_t)(1.0 / 255.0); - a3->data.data.color.z = (float_t)b * (float_t)(1.0 / 255.0); - a3->data.data.color.w = (float_t)a * (float_t)(1.0 / 255.0); - a3->data.data.blend_mode0 = blend_mode0; - a3->data.data.blend_mode1 = GLITTER_PARTICLE_BLEND_TYPICAL; - a3->data.data.split_u = split_u; - a3->data.data.split_v = split_v; - a3->data.data.uv_index_type = uv_index_type; - a3->data.data.uv_index = max(uv_index, 0); - a3->data.data.frame_step_uv = (float_t)frame_step_uv; - a3->data.data.uv_index_start = max(uv_index_start, 0); - a3->data.data.uv_index_end = uv_index_end; - a3->data.data.split_uv.x = 1.0f / (float_t)split_u; - a3->data.data.split_uv.y = 1.0f / (float_t)split_v; + if (a3->version != 2 && a3->version != 3) + return false; + + if (use_big_endian) { + a3->data.rotation.x = reverse_endianess_float_t(*(float_t*)(d + 12)); + a3->data.rotation.y = reverse_endianess_float_t(*(float_t*)(d + 16)); + a3->data.rotation.z = reverse_endianess_float_t(*(float_t*)(d + 20)); + a3->data.rotation_random.x = reverse_endianess_float_t(*(float_t*)(d + 24)); + a3->data.rotation_random.y = reverse_endianess_float_t(*(float_t*)(d + 28)); + a3->data.rotation_random.z = reverse_endianess_float_t(*(float_t*)(d + 32)); + a3->data.rotation_add.x = reverse_endianess_float_t(*(float_t*)(d + 36)); + a3->data.rotation_add.y = reverse_endianess_float_t(*(float_t*)(d + 40)); + a3->data.rotation_add.z = reverse_endianess_float_t(*(float_t*)(d + 44)); + a3->data.rotation_add_random.x = reverse_endianess_float_t(*(float_t*)(d + 48)); + a3->data.rotation_add_random.y = reverse_endianess_float_t(*(float_t*)(d + 52)); + a3->data.rotation_add_random.z = reverse_endianess_float_t(*(float_t*)(d + 56)); + a3->data.scale.x = reverse_endianess_float_t(*(float_t*)(d + 60)); + a3->data.scale.y = reverse_endianess_float_t(*(float_t*)(d + 64)); + a3->data.scale.z = reverse_endianess_float_t(*(float_t*)(d + 68)); + a3->data.scale_random.x = reverse_endianess_float_t(*(float_t*)(d + 72)); + a3->data.scale_random.y = reverse_endianess_float_t(*(float_t*)(d + 76)); + a3->data.scale_random.z = reverse_endianess_float_t(*(float_t*)(d + 80)); + a3->data.z_offset = reverse_endianess_float_t(*(float_t*)(d + 84)); + a3->data.pivot = reverse_endianess_int32_t(*(int32_t*)(d + 88)); + a3->data.flags = reverse_endianess_int32_t(*(int32_t*)(d + 92)); + } + else { + a3->data.rotation = *(vec3*)(d + 12); + a3->data.rotation_random = *(vec3*)(d + 24); + a3->data.rotation_add = *(vec3*)(d + 36); + a3->data.rotation_add_random = *(vec3*)(d + 48); + a3->data.scale = *(vec3*)(d + 60); + a3->data.scale_random = *(vec3*)(d + 72); + a3->data.z_offset = *(float_t*)(d + 84); + a3->data.pivot = *(int32_t*)(d + 88); + a3->data.flags = *(int32_t*)(d + 92); + } + + if (effect->data.flags & GLITTER_EFFECT_LOCAL) + a3->data.flags |= GLITTER_PARTICLE_LOCAL; + if (effect->data.flags & GLITTER_EFFECT_EMISSION) + a3->data.flags |= GLITTER_PARTICLE_EMISSION; + + if (use_big_endian) { + a3->data.speed = reverse_endianess_float_t(*(float_t*)(d + 96)); + a3->data.speed_random = reverse_endianess_float_t(*(float_t*)(d + 100)); + a3->data.deceleration = reverse_endianess_float_t(*(float_t*)(d + 104)); + a3->data.deceleration_random = reverse_endianess_float_t(*(float_t*)(d + 108)); + a3->data.direction.x = reverse_endianess_float_t(*(float_t*)(d + 112)); + a3->data.direction.y = reverse_endianess_float_t(*(float_t*)(d + 116)); + a3->data.direction.z = reverse_endianess_float_t(*(float_t*)(d + 120)); + a3->data.direction_random.x = reverse_endianess_float_t(*(float_t*)(d + 124)); + a3->data.direction_random.y = reverse_endianess_float_t(*(float_t*)(d + 128)); + a3->data.direction_random.z = reverse_endianess_float_t(*(float_t*)(d + 132)); + a3->data.gravity.x = reverse_endianess_float_t(*(float_t*)(d + 136)); + a3->data.gravity.y = reverse_endianess_float_t(*(float_t*)(d + 140)); + a3->data.gravity.z = reverse_endianess_float_t(*(float_t*)(d + 144)); + a3->data.acceleration.x = reverse_endianess_float_t(*(float_t*)(d + 148)); + a3->data.acceleration.y = reverse_endianess_float_t(*(float_t*)(d + 152)); + a3->data.acceleration.z = reverse_endianess_float_t(*(float_t*)(d + 156)); + a3->data.acceleration_random.x = reverse_endianess_float_t(*(float_t*)(d + 160)); + a3->data.acceleration_random.y = reverse_endianess_float_t(*(float_t*)(d + 164)); + a3->data.acceleration_random.z = reverse_endianess_float_t(*(float_t*)(d + 168)); + a3->data.reflection_coeff = reverse_endianess_float_t(*(float_t*)(d + 172)); + a3->data.reflection_coeff_random = reverse_endianess_float_t(*(float_t*)(d + 176)); + a3->data.rebound_plane_y = reverse_endianess_float_t(*(float_t*)(d + 180)); + a3->data.uv_scroll_add.x = reverse_endianess_float_t(*(float_t*)(d + 184)); + a3->data.uv_scroll_add.y = reverse_endianess_float_t(*(float_t*)(d + 188)); + a3->data.uv_scroll_add_scale = reverse_endianess_float_t(*(float_t*)(d + 192)); + a3->data.sub_flags = reverse_endianess_int32_t(*(int32_t*)(d + 196)); + a3->data.count = reverse_endianess_int32_t(*(int32_t*)(d + 200)); + } + else { + a3->data.speed = *(float_t*)(d + 96); + a3->data.speed_random = *(float_t*)(d + 100); + a3->data.deceleration = *(float_t*)(d + 104); + a3->data.deceleration_random = *(float_t*)(d + 108); + a3->data.direction = *(vec3*)(d + 112); + a3->data.direction_random = *(vec3*)(d + 124); + a3->data.gravity = *(vec3*)(d + 136); + a3->data.acceleration = *(vec3*)(d + 148); + a3->data.acceleration_random = *(vec3*)(d + 160); + a3->data.reflection_coeff = *(float_t*)(d + 172); + a3->data.reflection_coeff_random = *(float_t*)(d + 176); + a3->data.rebound_plane_y = *(float_t*)(d + 180); + a3->data.uv_scroll_add = *(vec2*)(d + 184); + a3->data.uv_scroll_add_scale = *(float_t*)(d + 192); + a3->data.sub_flags = *(int32_t*)(d + 196); + a3->data.count = *(int32_t*)(d + 200); + } + d += 204; + + a3->data.locus_history_size = 0; + a3->data.locus_history_size_random = 0; + a3->data.draw_flags = 0; + a3->data.emission = 0; + + if (a3->version == 3) { + if (use_big_endian) + a3->data.emission = reverse_endianess_float_t(*(float_t*)(d + 4)); + else + a3->data.emission = *(float_t*)(d + 4); + + if (a3->data.emission >= glitter_min_emission) + a3->data.flags |= GLITTER_PARTICLE_EMISSION; + d += 8; + } + + if (a3->data.type == GLITTER_PARTICLE_LOCUS || a3->data.type == GLITTER_PARTICLE_MESH) { + if (use_big_endian) { + a3->data.locus_history_size = reverse_endianess_uint16_t(*(uint16_t*)d); + a3->data.locus_history_size_random = reverse_endianess_uint16_t(*(uint16_t*)(d + 2)); + } + else { + a3->data.locus_history_size = *(uint16_t*)d; + a3->data.locus_history_size_random = *(uint16_t*)(d + 2); + } + d += 4; + } + + a3->data.texture0 = 0; + a3->data.texture1 = 0; + + if (use_big_endian) { + tex_hash0 = reverse_endianess_uint64_t(*(uint64_t*)d); + r = *(uint8_t*)(d + 8); + g = *(uint8_t*)(d + 9); + b = *(uint8_t*)(d + 10); + a = *(uint8_t*)(d + 11); + blend_mode0 = reverse_endianess_int32_t(*(int32_t*)(d + 12)); + split_u = (uint8_t)reverse_endianess_int32_t(*(int32_t*)(d + 20)); + split_v = (uint8_t)reverse_endianess_int32_t(*(int32_t*)(d + 24)); + uv_index_type = reverse_endianess_int32_t(*(int32_t*)(d + 28)); + uv_index = reverse_endianess_int16_t(*(int16_t*)(d + 32)); + frame_step_uv = reverse_endianess_int16_t(*(int16_t*)(d + 34)); + uv_index_start = reverse_endianess_int32_t(*(int32_t*)(d + 36)); + uv_index_end = reverse_endianess_int32_t(*(int32_t*)(d + 40)); + } + else { + tex_hash0 = *(uint64_t*)d; + r = *(uint8_t*)(d + 8); + g = *(uint8_t*)(d + 9); + b = *(uint8_t*)(d + 10); + a = *(uint8_t*)(d + 11); + blend_mode0 = *(int32_t*)(d + 12); + split_u = (uint8_t) * (int32_t*)(d + 20); + split_v = (uint8_t) * (int32_t*)(d + 24); + uv_index_type = *(int32_t*)(d + 28); + uv_index = *(int16_t*)(d + 32); + frame_step_uv = *(int16_t*)(d + 34); + uv_index_start = *(int32_t*)(d + 36); + uv_index_end = *(int32_t*)(d + 40); + } + + if (a1->version >= 7) + d += 48; + else + d += 44; + + if (a3->data.flags & GLITTER_PARTICLE_SECOND_TEXTURE) + if (use_big_endian) { + tex_hash1 = reverse_endianess_uint64_t(*(uint64_t*)d); + blend_mode1 = reverse_endianess_int32_t(*(int32_t*)(d + 8)); + } + else { + tex_hash1 = *(uint64_t*)d; + blend_mode1 = *(int32_t*)(d + 8); + } + else { + tex_hash1 = glt_type != GLITTER_AFT + ? hash_murmurhash_empty : hash_fnv1a64_empty; + blend_mode1 = GLITTER_PARTICLE_BLEND_TYPICAL; + } + } + + a3->data.tex_hash0 = tex_hash0; + a3->data.tex_hash1 = tex_hash1; + a3->data.color.x = (float_t)r; + a3->data.color.y = (float_t)g; + a3->data.color.z = (float_t)b; + a3->data.color.w = (float_t)a; + a3->data.blend_mode0 = blend_mode0; + a3->data.blend_mode1 = blend_mode1; + a3->data.split_u = split_u; + a3->data.split_v = split_v; + a3->data.uv_index_type = uv_index_type; + a3->data.uv_index = max(uv_index, 0); + a3->data.frame_step_uv = frame_step_uv; + a3->data.uv_index_start = max(uv_index_start, 0); + a3->data.uv_index_end = uv_index_end; + a3->data.split_uv.x = (float_t)split_u; + a3->data.split_uv.y = (float_t)split_v; + + vec2_rcp(a3->data.split_uv, a3->data.split_uv); + vec4_mult_scalar(a3->data.color, (float_t)(1.0 / 255.0), a3->data.color); uv_max_count = (int32_t)(split_u * split_v); if (uv_max_count) @@ -486,40 +711,26 @@ static bool FASTCALL glitter_particle_unpack_file(glitter_effect_group* a1, case GLITTER_UV_INDEX_FORWARD: case GLITTER_UV_INDEX_REVERSE: case GLITTER_UV_INDEX_USER: - a3->data.data.uv_index &= uv_max_count; + a3->data.uv_index &= uv_max_count; break; case GLITTER_UV_INDEX_INITIAL_RANDOM_FIXED: case GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD: case GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE: - if (a3->data.data.uv_index < a3->data.data.uv_index_start) - a3->data.data.uv_index = a3->data.data.uv_index_start; - else if (uv_index_end >= 0 && a3->data.data.uv_index > uv_index_end) - a3->data.data.uv_index = uv_index_end; + if (uv_index < uv_index_start) + a3->data.uv_index = uv_index_start; + else if (uv_index_end >= 0 && uv_index > uv_index_end) + a3->data.uv_index = uv_index_end; - a3->data.data.uv_index = max(a3->data.data.uv_index, uv_max_count); + a3->data.uv_index = min(a3->data.uv_index, uv_max_count); break; } if (uv_index_end >= 0) - a3->data.data.uv_index_count = uv_index_end - a3->data.data.uv_index_start + 1; + a3->data.uv_index_count = uv_index_end - uv_index_start + 1; else - a3->data.data.uv_index_count = uv_max_count - a3->data.data.uv_index_start; + a3->data.uv_index_count = uv_max_count - uv_index_start; - if (a3->data.data.uv_index_count < 0) - a3->data.data.uv_index_count = 0; - - if (a3->data.data.flags & GLITTER_PARTICLE_FLAG_SECOND_TEXTURE) { - if (a1->version >= 7) - d += 4; - - if (use_big_endian) { - a3->data.data.tex_hash1 = reverse_endianess_uint64_t(*(uint64_t*)d); - a3->data.data.blend_mode1 = reverse_endianess_int32_t(*(int32_t*)(d + 8)); - } - else { - a3->data.data.tex_hash1 = *(uint64_t*)d; - a3->data.data.blend_mode1 = *(int32_t*)(d + 8); - } - } + if (a3->data.uv_index_count < 0) + a3->data.uv_index_count = 0; return true; } diff --git a/src/CRE/Glitter/particle.h b/src/CRE/Glitter/particle.h index 99573663..098d5ef2 100644 --- a/src/CRE/Glitter/particle.h +++ b/src/CRE/Glitter/particle.h @@ -7,9 +7,10 @@ #include "glitter.h" -extern glitter_particle* FASTCALL glitter_particle_init(); -extern bool FASTCALL glitter_particle_parse_file(glitter_effect_group* a1, +extern glitter_particle* FASTCALL glitter_particle_init(GPM); +extern glitter_particle* FASTCALL glitter_particle_copy(GPM, glitter_particle* p); +extern bool FASTCALL glitter_particle_parse_file(GPM, glitter_effect_group* a1, f2_struct* st, vector_ptr_glitter_particle* vec, glitter_effect* effect); -extern bool FASTCALL glitter_particle_unparse_file(glitter_effect_group* a1, - f2_struct* st, glitter_particle* a3, glitter_effect* effect, bool use_big_endian); +extern bool FASTCALL glitter_particle_unparse_file(GPM, glitter_effect_group* a1, + f2_struct* st, glitter_particle* a3, glitter_effect* effect); extern void FASTCALL glitter_particle_dispose(glitter_particle* p); diff --git a/src/CRE/Glitter/particle_inst.c b/src/CRE/Glitter/particle_inst.c index c597be8c..153aa24d 100644 --- a/src/CRE/Glitter/particle_inst.c +++ b/src/CRE/Glitter/particle_inst.c @@ -4,291 +4,153 @@ */ #include "particle_inst.h" -#include "curve.h" #include "effect_inst.h" -#include "random.h" #include "render_group.h" -glitter_particle_inst* FASTCALL glitter_particle_inst_init(glitter_particle* a1, - glitter_scene* a2, glitter_effect_inst* a3) { +static glitter_particle_inst* FASTCALL glitter_particle_inst_init_child(GPM, + glitter_particle_inst* a1, float_t emission); + +glitter_particle_inst* FASTCALL glitter_particle_inst_init(GPM, glitter_particle* a1, + glitter_effect_inst* a2, glitter_emitter_inst* a3, glitter_random* random, float_t emission) { glitter_render_group* render_group; glitter_particle_inst* pi = force_malloc(sizeof(glitter_particle_inst)); pi->particle = a1; - pi->mat = mat4_identity; - pi->mat_no_scale = mat4_identity; - pi->sub.effect_inst = a3; - pi->sub.particle = a1; - pi->sub.data = a1->data.data; + pi->data.effect = a2; + pi->data.emitter = a3; + pi->data.particle = a1; + pi->data.data = a1->data; + pi->data.random_ptr = random; - if (pi->sub.data.type != GLITTER_PARTICLE_LOCUS) { - render_group = glitter_particle_inst_init_render_group(&a2->sub, pi); - render_group->alpha = glitter_effect_inst_get_alpha(a3); - render_group->fog = glitter_effect_inst_get_fog(a3); - if (pi->sub.data.blend_mode0 == GLITTER_PARTICLE_BLEND_PUNCH_THROUGH && pi->sub.data.type == GLITTER_PARTICLE_QUAD) + if (pi->data.data.type != GLITTER_PARTICLE_LOCUS) { + render_group = glitter_render_group_init(GPM_VAL, pi); + render_group->alpha = glitter_effect_inst_get_alpha(a2); + render_group->fog = glitter_effect_inst_get_fog(a2); + if (pi->data.data.blend_mode0 == GLITTER_PARTICLE_BLEND_PUNCH_THROUGH + && pi->data.data.type == GLITTER_PARTICLE_QUAD) render_group->alpha = 0; - if (pi->sub.data.emission >= 0.0099999998f) - render_group->emission = pi->sub.data.emission; - else if (a3->data.emission >= 0.0099999998f) - render_group->emission = a3->data.emission; + if (pi->data.data.draw_flags & GLITTER_PARTICLE_DRAW_NO_BILLBOARD_CULL) + render_group->use_culling = false; else - render_group->emission = a2->emission; - pi->sub.render_group = render_group; + render_group->use_culling = true; + + if (pi->data.data.emission >= glitter_min_emission) + render_group->emission = pi->data.data.emission; + else if (a2->data.emission >= glitter_min_emission) + render_group->emission = a2->data.emission; + else + render_group->emission = emission; + pi->data.render_group = render_group; + vector_ptr_glitter_render_group_push_back(&a2->render_groups, &render_group); } else - pi->sub.flags |= GLITTER_PARTICLE_INST_FLAG_NO_CHILD; + pi->data.flags |= GLITTER_PARTICLE_INST_NO_CHILD; return pi; } -void FASTCALL glitter_particle_inst_copy(glitter_particle_inst* a1, glitter_particle_inst* a2, glitter_scene* a3) { +void FASTCALL glitter_particle_inst_emit(GPM, + glitter_particle_inst* a2, int32_t a3, int32_t count, float_t emission) { glitter_particle_inst* particle; - glitter_particle_inst** i; - a2->mat = a1->mat; - a2->mat_no_scale = a1->mat_no_scale; - a2->sub.flags = a1->sub.flags; - if (a1->sub.render_group && a2->sub.render_group) - glitter_render_group_copy(a1->sub.render_group, a2->sub.render_group); - - vector_ptr_glitter_particle_inst_clear(&a2->sub.particle_insts, (void*)glitter_particle_inst_dispose); - for (i = a1->sub.particle_insts.begin; i != a1->sub.particle_insts.end; i++) { - particle = glitter_particle_inst_init_child(a3, a1); - vector_ptr_glitter_particle_inst_push_back(&a2->sub.particle_insts, &particle); - - particle->mat = a1->mat; - particle->mat_no_scale = a1->mat_no_scale; - glitter_particle_inst_copy(*i, particle, a3); - } -} - -void FASTCALL glitter_particle_inst_emit(glitter_particle_inst* a1, - glitter_scene* a2, glitter_emitter_inst* a3, int32_t a4, int32_t count) { - glitter_particle_inst* particle_inst; - - if (a1->sub.flags & GLITTER_PARTICLE_INST_FLAG_ENDED) + if (a2->data.flags & GLITTER_PARTICLE_INST_ENDED) return; - while (!a1->sub.parent && a1->sub.flags & GLITTER_PARTICLE_INST_FLAG_NO_CHILD) { - particle_inst = glitter_particle_inst_init_child(a2, a1); - vector_ptr_glitter_particle_inst_push_back(&a1->sub.particle_insts, &particle_inst); - particle_inst->mat = a1->mat; - particle_inst->mat_no_scale = a1->mat_no_scale; - a1 = particle_inst; - if (particle_inst->sub.flags & GLITTER_PARTICLE_INST_FLAG_ENDED) + while (!a2->data.parent && a2->data.flags & GLITTER_PARTICLE_INST_NO_CHILD) { + particle = glitter_particle_inst_init_child(GPM_VAL, a2, emission); + vector_ptr_glitter_particle_inst_push_back(&a2->data.children, &particle); + a2 = particle; + if (particle->data.flags & GLITTER_PARTICLE_INST_ENDED) return; } - if (a1->sub.render_group) - glitter_render_group_emit(a1->sub.render_group, &a1->sub, a3, a4, count); + if (a2->data.render_group) + glitter_render_group_emit(GPM_VAL, a2->data.render_group, &a2->data, a2->data.emitter, a3, count); } void FASTCALL glitter_particle_inst_free(glitter_particle_inst* a1, bool free) { glitter_particle_inst** i; - a1->sub.flags |= GLITTER_PARTICLE_INST_FLAG_ENDED; - if (free && a1->sub.render_group) - glitter_render_group_free(a1->sub.render_group); + a1->data.flags |= GLITTER_PARTICLE_INST_ENDED; + if (free && a1->data.render_group) + glitter_render_group_free(a1->data.render_group); - for (i = a1->sub.particle_insts.begin; i != a1->sub.particle_insts.end; i++) + for (i = a1->data.children.begin; i != a1->data.children.end; i++) glitter_particle_inst_free(*i, free); } -bool FASTCALL glitter_particle_inst_get_value(glitter_particle_inst* a1, - glitter_render_group_sub* a2, float_t frame) { - vec3 translation; - bool v4; // r13 - int64_t length; // rbp - glitter_curve* curve; // rdi - float_t value; // [rsp+40h] [rbp-39h] BYREF - bool visible; - - visible = true; - value = 0.0f; - v4 = false; - translation = vec3_null; - length = a1->particle->curve.end - a1->particle->curve.begin; - if (length) { - for (int32_t i = 0; i < length; i++) { - curve = a1->particle->curve.begin[i]; - if (!glitter_curve_get_value(curve, frame, &value, a2->random + i)) - continue; - - switch (curve->type) { - case GLITTER_CURVE_TRANSLATION_X: - translation.x = value; - v4 = true; - break; - case GLITTER_CURVE_TRANSLATION_Y: - translation.y = value; - v4 = true; - break; - case GLITTER_CURVE_TRANSLATION_Z: - translation.z = value; - v4 = true; - break; - case GLITTER_CURVE_ROTATION_X: - a2->rotation.x = value; - break; - case GLITTER_CURVE_ROTATION_Y: - a2->rotation.y = value; - break; - case GLITTER_CURVE_ROTATION_Z: - a2->rotation.z = value; - break; - case GLITTER_CURVE_SCALE_X: - a2->scale.x = value; - break; - case GLITTER_CURVE_SCALE_Y: - a2->scale.y = value; - break; - case GLITTER_CURVE_SCALE_Z: - a2->scale.z = value; - break; - case GLITTER_CURVE_SCALE_ALL: - a2->scale_all = value; - break; - case GLITTER_CURVE_COLOR_R: - a2->color.x = value; - break; - case GLITTER_CURVE_COLOR_G: - a2->color.y = value; - break; - case GLITTER_CURVE_COLOR_B: - a2->color.z = value; - break; - case GLITTER_CURVE_COLOR_A: - a2->color.w = value; - if (value < 0.0099999998f) - visible = false; - break; - case GLITTER_CURVE_U_SCROLL: - a2->uv_scroll.x = value; - break; - case GLITTER_CURVE_V_SCROLL: - a2->uv_scroll.y = value; - break; - } - } - } - - if (a1->sub.data.flags & GLITTER_PARTICLE_FLAG_TRANSLATE_BY_EMITTER || v4) { - vec3_add(translation, a2->base_translation, translation); - if (a1->sub.data.flags & GLITTER_PARTICLE_FLAG_TRANSLATE_BY_EMITTER) { - mat4_mult_vec3(&a2->mat, &translation, &translation); - vec3_add(translation, *(vec3*)&a2->mat.row3, translation); - } - a2->translation = translation; - } - return visible; -} - bool FASTCALL glitter_particle_inst_has_ended(glitter_particle_inst* particle, bool a2) { glitter_particle_inst** i; - if (~particle->sub.flags & GLITTER_PARTICLE_INST_FLAG_ENDED) + if (~particle->data.flags & GLITTER_PARTICLE_INST_ENDED) return false; else if (!a2) return true; - if (~particle->sub.flags & GLITTER_PARTICLE_INST_FLAG_NO_CHILD || particle->sub.parent) { - if (particle->sub.render_group && particle->sub.render_group->ctrl > 0) + if (~particle->data.flags & GLITTER_PARTICLE_INST_NO_CHILD || particle->data.parent) { + if (particle->data.render_group && particle->data.render_group->ctrl > 0) return false; return true; } - for (i = particle->sub.particle_insts.begin; i != particle->sub.particle_insts.end; i++) + for (i = particle->data.children.begin; i != particle->data.children.end; i++) if (!glitter_particle_inst_has_ended(*i, a2)) return false; return true; } -glitter_particle_inst* FASTCALL glitter_particle_inst_init_child(glitter_scene* a1, glitter_particle_inst* a2) { +void FASTCALL glitter_particle_inst_dispose(glitter_particle_inst* pi) { + if (pi->data.render_group) { + glitter_render_group_delete_buffers(pi->data.render_group, true); + pi->data.render_group = 0; + } + + vector_ptr_glitter_particle_inst_free(&pi->data.children, glitter_particle_inst_dispose); + free(pi); +} + +void FASTCALL glitter_particle_inst_reset(glitter_particle_inst* a1) { + glitter_particle_inst** i; + + a1->data.flags = 0; + if (a1->data.render_group) + glitter_render_group_free(a1->data.render_group); + + for (i = a1->data.children.begin; i != a1->data.children.end; ++i) + glitter_particle_inst_reset(*i); +} + +glitter_particle_inst* FASTCALL glitter_particle_inst_init_child(GPM, + glitter_particle_inst* a1, float_t emission) { glitter_render_group* render_group; glitter_effect_inst* effect; glitter_particle_inst* pi = force_malloc(sizeof(glitter_particle_inst)); - pi->particle = a2->particle; - pi->mat = mat4_identity; - pi->mat_no_scale = mat4_identity; - pi->sub.parent = a2; - vector_ptr_glitter_particle_inst_resize(&pi->sub.particle_insts, 0x200); + pi->particle = a1->particle; + pi->data.effect = a1->data.effect; + pi->data.emitter = a1->data.emitter; + pi->data.parent = a1; + vector_ptr_glitter_particle_inst_append(&pi->data.children, 0x200); - pi->sub.data = a2->sub.data; + pi->data.random_ptr = a1->data.random_ptr; + pi->data.data = a1->data.data; - pi->sub.particle = a2->sub.particle; - render_group = glitter_particle_inst_init_render_group(&a1->sub, pi); - effect = a2->sub.effect_inst; + pi->data.particle = a1->data.particle; + render_group = glitter_render_group_init(GPM_VAL, pi); + effect = a1->data.effect; render_group->alpha = glitter_effect_inst_get_alpha(effect); render_group->fog = glitter_effect_inst_get_fog(effect); - if (pi->sub.data.blend_mode0 == GLITTER_PARTICLE_BLEND_PUNCH_THROUGH && pi->sub.data.type == GLITTER_PARTICLE_QUAD) + if (pi->data.data.blend_mode0 == GLITTER_PARTICLE_BLEND_PUNCH_THROUGH + && pi->data.data.type == GLITTER_PARTICLE_QUAD) render_group->alpha = 0; - if (effect->data.emission >= 0.0099999998f) + if (effect->data.emission >= glitter_min_emission) render_group->emission = effect->data.emission; else - render_group->emission = a1->emission; - pi->sub.render_group = render_group; + render_group->emission = emission; + pi->data.render_group = render_group; + vector_ptr_glitter_render_group_push_back(&a1->data.effect->render_groups, &render_group); - if (pi->sub.data.type == GLITTER_PARTICLE_LOCUS) - pi->sub.flags |= GLITTER_PARTICLE_INST_FLAG_NO_CHILD; + if (pi->data.data.type == GLITTER_PARTICLE_LOCUS) + pi->data.flags |= GLITTER_PARTICLE_INST_NO_CHILD; return pi; } - -glitter_render_group* FASTCALL glitter_particle_inst_init_render_group(glitter_scene_sub* a1, - glitter_particle_inst* a2) { - int32_t count; - glitter_render_group* render_group; - - count = a2->sub.data.count; - if (count < 1) { - count = 250; - if (a2->sub.data.type == GLITTER_PARTICLE_LOCUS) - count = 30; - } - - render_group = glitter_render_group_init(count, a2); - vector_ptr_glitter_render_group_push_back(&a1->render_groups, &render_group); - return render_group; -} - -void FASTCALL glitter_particle_inst_dispose(glitter_particle_inst* pi) { - if (pi->sub.render_group) { - glitter_render_group_delete_buffers(pi->sub.render_group, true); - pi->sub.render_group = 0; - } - - vector_ptr_glitter_particle_inst_free(&pi->sub.particle_insts, (void*)glitter_particle_inst_dispose); - free(pi); -} - -void FASTCALL glitter_particle_inst_render_group_init(glitter_particle_inst* particle, float_t delta_frame) { - glitter_particle_inst** i; - - if (~particle->sub.flags & GLITTER_PARTICLE_INST_FLAG_NO_CHILD || particle->sub.parent) { - if (particle->sub.render_group) - glitter_render_group_copy_from_particle(particle->sub.render_group, delta_frame, false); - } - else - for (i = particle->sub.particle_insts.begin; i != particle->sub.particle_insts.end; i++) - glitter_particle_inst_render_group_init(*i, delta_frame); -} - -void FASTCALL glitter_particle_inst_reset(glitter_particle_inst* a1) { - glitter_particle_inst** i; // rbx - - a1->sub.flags = 0; - if (a1->sub.render_group) - glitter_render_group_free(a1->sub.render_group); - - for (i = a1->sub.particle_insts.begin; i != a1->sub.particle_insts.end; ++i) - glitter_particle_inst_reset(*i); -} - -void FASTCALL glitter_particle_inst_set_mat(glitter_particle_inst* a1) { - glitter_particle_inst** i; - - for (i = a1->sub.particle_insts.begin; i != a1->sub.particle_insts.end; i++) { - (*i)->mat = a1->mat; - (*i)->mat_no_scale = a1->mat_no_scale; - } -} diff --git a/src/CRE/Glitter/particle_inst.h b/src/CRE/Glitter/particle_inst.h index decb273f..1134aaf4 100644 --- a/src/CRE/Glitter/particle_inst.h +++ b/src/CRE/Glitter/particle_inst.h @@ -7,21 +7,11 @@ #include "glitter.h" -extern glitter_particle_inst* FASTCALL glitter_particle_inst_init(glitter_particle* a1, - glitter_scene* a2, glitter_effect_inst* a3); -extern void FASTCALL glitter_particle_inst_copy(glitter_particle_inst* a1, - glitter_particle_inst* a2, glitter_scene* a3); -extern void FASTCALL glitter_particle_inst_emit(glitter_particle_inst* a1, - glitter_scene* a2, glitter_emitter_inst* a3, int32_t a4, int32_t count); +extern glitter_particle_inst* FASTCALL glitter_particle_inst_init(GPM, glitter_particle* a1, + glitter_effect_inst* a2, glitter_emitter_inst* a3, glitter_random* random, float_t emission); +extern void FASTCALL glitter_particle_inst_emit(GPM, + glitter_particle_inst* a1, int32_t a3, int32_t count, float_t emission); extern void FASTCALL glitter_particle_inst_free(glitter_particle_inst* a1, bool free); -extern bool FASTCALL glitter_particle_inst_get_value(glitter_particle_inst* a1, - glitter_render_group_sub* a2, float_t frame); extern bool FASTCALL glitter_particle_inst_has_ended(glitter_particle_inst* particle, bool a2); -extern glitter_particle_inst* FASTCALL glitter_particle_inst_init_child(glitter_scene* a1, - glitter_particle_inst* a2); -extern glitter_render_group* FASTCALL glitter_particle_inst_init_render_group(glitter_scene_sub* a1, - glitter_particle_inst* a2); -extern void FASTCALL glitter_particle_inst_render_group_init(glitter_particle_inst* particle, float_t delta_frame); extern void FASTCALL glitter_particle_inst_reset(glitter_particle_inst* a1); -extern void FASTCALL glitter_particle_inst_set_mat(glitter_particle_inst* a1); extern void FASTCALL glitter_particle_inst_dispose(glitter_particle_inst* pi); diff --git a/src/CRE/Glitter/particle_manager.c b/src/CRE/Glitter/particle_manager.c index 5c70f01c..ea5c3ae9 100644 --- a/src/CRE/Glitter/particle_manager.c +++ b/src/CRE/Glitter/particle_manager.c @@ -9,19 +9,47 @@ #include "file_reader.h" #include "render_group.h" #include "scene.h" +#include "../GlitterX/effect_inst_x.h" glitter_particle_manager* FASTCALL glitter_particle_manager_init() { glitter_particle_manager* gpm = force_malloc(sizeof(glitter_particle_manager)); gpm->delta_frame = 2.0f; gpm->emission = 1.0f; - vector_ptr_glitter_scene_resize(&gpm->scenes, 0x100); - vector_ptr_glitter_file_reader_resize(&gpm->file_readers, 0x100); - vector_ptr_glitter_effect_group_resize(&gpm->effect_groups, 0x100); + vector_ptr_glitter_scene_append(&gpm->scenes, 0x100); + vector_ptr_glitter_file_reader_append(&gpm->file_readers, 0x100); + vector_ptr_glitter_effect_group_append(&gpm->effect_groups, 0x100); return gpm; } -bool FASTCALL glitter_particle_manager_check_effect_group(glitter_particle_manager* gpm, - uint64_t effect_group_hash) { +void FASTCALL glitter_particle_manager_calc_draw(GPM, + bool(FASTCALL* render_add_list_func)(glitter_particle_mesh*, vec4*, mat4*, mat4*)) { + glitter_scene** i; + glitter_scene* scene; + glitter_effect_inst** j; + + /*if (glt_type == GLITTER_X) + for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) { + if (!*i) + continue; + + scene = *i; + for (j = scene->effects.begin; j != scene->effects.end; j++) + if (*j) + glitter_x_effect_inst_calc_draw(GPM_VAL, *j, render_add_list_func); + } + else*/ + for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) { + if (!*i) + continue; + + scene = *i; + for (j = scene->effects.begin; j != scene->effects.end; j++) + if (*j) + glitter_effect_inst_calc_draw(GPM_VAL, *j, render_add_list_func); + } +} + +bool FASTCALL glitter_particle_manager_check_effect_group(GPM, uint64_t effect_group_hash) { glitter_effect_group** i; for (i = gpm->effect_groups.begin; i != gpm->effect_groups.end; i++) { @@ -32,8 +60,7 @@ bool FASTCALL glitter_particle_manager_check_effect_group(glitter_particle_manag return i != gpm->effect_groups.end; } -bool FASTCALL glitter_particle_manager_check_file_reader(glitter_particle_manager* gpm, - uint64_t effect_group_hash) { +bool FASTCALL glitter_particle_manager_check_file_reader(GPM, uint64_t effect_group_hash) { glitter_file_reader** i; for (i = gpm->file_readers.begin; i != gpm->file_readers.end; i++) { @@ -44,8 +71,7 @@ bool FASTCALL glitter_particle_manager_check_file_reader(glitter_particle_manage return i != gpm->file_readers.end; } -bool FASTCALL glitter_particle_manager_check_scene(glitter_particle_manager* gpm, - uint64_t effect_group_hash) { +bool FASTCALL glitter_particle_manager_check_scene(GPM, uint64_t effect_group_hash) { glitter_scene** i; for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) { @@ -56,20 +82,34 @@ bool FASTCALL glitter_particle_manager_check_scene(glitter_particle_manager* gpm return i != gpm->scenes.end; } -void FASTCALL glitter_particle_manager_draw(glitter_particle_manager* gpm, int32_t alpha) { - for (glitter_scene** i = gpm->scenes.begin; i != gpm->scenes.end; i++) { - if (!*i) - continue; +void FASTCALL glitter_particle_manager_draw(GPM, int32_t alpha) { + glitter_scene** i; + glitter_scene* scene; + glitter_effect_inst** j; - glitter_scene_sub* scene = &(*i)->sub; - for (glitter_render_group** j = scene->render_groups.begin; j != scene->render_groups.end; j++) - if (*j && (*j)->alpha == alpha) - glitter_render_group_draw(scene, *j); - } + /*if (glt_type == GLITTER_X) + for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) { + if (!*i) + continue; + + scene = *i; + for (j = scene->effects.begin; j != scene->effects.end; j++) + if (*j) + glitter_x_effect_inst_draw(GPM_VAL, *j, alpha); + } + else*/ + for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) { + if (!*i) + continue; + + scene = *i; + for (j = scene->effects.begin; j != scene->effects.end; j++) + if (*j) + glitter_effect_inst_draw(GPM_VAL, *j, alpha); + } } -bool FASTCALL glitter_particle_manager_free_effect_group(glitter_particle_manager* gpm, - uint64_t effect_group_hash) { +bool FASTCALL glitter_particle_manager_free_effect_group(GPM, uint64_t effect_group_hash) { glitter_effect_group** i; glitter_effect_group* effect_group; @@ -80,17 +120,18 @@ bool FASTCALL glitter_particle_manager_free_effect_group(glitter_particle_manage continue; } - if (effect_group) - glitter_effect_group_dispose(effect_group); - memmove(i, i + 1, sizeof(glitter_effect_group**) * (gpm->effect_groups.end - (i + 1))); - gpm->effect_groups.end--; + vector_ptr_glitter_effect_group_erase(&gpm->effect_groups, + i - gpm->effect_groups.begin, glitter_effect_group_dispose); break; } return i != gpm->effect_groups.end; } -bool FASTCALL glitter_particle_manager_free_scene(glitter_particle_manager* gpm, - uint64_t effect_group_hash) { +void FASTCALL glitter_particle_manager_free_effect_groups(GPM) { + vector_ptr_glitter_effect_group_clear(&gpm->effect_groups, glitter_effect_group_dispose); +} + +bool FASTCALL glitter_particle_manager_free_scene(GPM, uint64_t effect_group_hash) { glitter_scene** i; glitter_scene* scene; @@ -101,61 +142,55 @@ bool FASTCALL glitter_particle_manager_free_scene(glitter_particle_manager* gpm, continue; } - glitter_scene_dispose(scene); - memmove(i, i + 1, sizeof(glitter_scene**) * (gpm->scenes.end - (i + 1))); - gpm->scenes.end--; + vector_ptr_glitter_scene_erase(&gpm->scenes, i - gpm->scenes.begin, glitter_scene_dispose); break; } return i != gpm->scenes.end; } -size_t FASTCALL glitter_particle_manager_get_ctrl_count(glitter_particle_manager* gpm, - glitter_particle_type type) { +void FASTCALL glitter_particle_manager_free_scenes(GPM) { + vector_ptr_glitter_scene_clear(&gpm->scenes, glitter_scene_dispose); +} + +size_t FASTCALL glitter_particle_manager_get_ctrl_count(GPM, glitter_particle_type ptcl_type) { size_t ctrl; glitter_scene** i; + glitter_scene* scene; + glitter_effect_inst** j; ctrl = 0; - switch (type) { - case GLITTER_PARTICLE_QUAD: - for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) - ctrl += (*i)->sub.ctrl_quad; - break; - case GLITTER_PARTICLE_LINE: - for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) - ctrl += (*i)->sub.ctrl_line; - break; - case GLITTER_PARTICLE_LOCUS: - for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) - ctrl += (*i)->sub.ctrl_locus; - break; + for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) { + if (!*i) + continue; + + scene = *i; + for (j = scene->effects.begin; j != scene->effects.end; j++) + if (*j) + ctrl += glitter_effect_inst_get_ctrl_count(*j, ptcl_type); } return ctrl; } -size_t FASTCALL glitter_particle_manager_get_disp_count(glitter_particle_manager* gpm, - glitter_particle_type type) { +size_t FASTCALL glitter_particle_manager_get_disp_count(GPM, glitter_particle_type ptcl_type) { size_t disp; glitter_scene** i; + glitter_scene* scene; + glitter_effect_inst** j; disp = 0; - switch (type) { - case GLITTER_PARTICLE_QUAD: - for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) - disp += (*i)->sub.disp_quad; - break; - case GLITTER_PARTICLE_LINE: - for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) - disp += (*i)->sub.disp_line; - break; - case GLITTER_PARTICLE_LOCUS: - for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) - disp += (*i)->sub.disp_locus; - break; + for (i = gpm->scenes.begin; i != gpm->scenes.end; i++) { + if (!*i) + continue; + + scene = *i; + for (j = scene->effects.begin; j != scene->effects.end; j++) + if (*j) + disp += glitter_effect_inst_get_disp_count(*j, ptcl_type); } return disp; } -void glitter_particle_manager_get_frame(glitter_particle_manager* gpm, float_t* frame, float_t* life_time) { +void glitter_particle_manager_get_frame(GPM, float_t* frame, float_t* life_time) { glitter_scene* scene; glitter_effect_inst** i; glitter_effect_inst* effect; @@ -172,15 +207,15 @@ void glitter_particle_manager_get_frame(glitter_particle_manager* gpm, float_t* scene = *gpm->scenes.begin; for (i = scene->effects.begin; i != scene->effects.end; i++) { effect = *i; - if (effect && frame && life_time && effect->data.life_time > *life_time) { + if (effect && frame && life_time && (float_t)effect->data.life_time > *life_time) { if (*frame < effect->frame) *frame = effect->frame; - *life_time = effect->data.life_time; + *life_time = (float_t)effect->data.life_time; } } } -void glitter_particle_manager_get_start_end_frame(glitter_particle_manager* gpm, float_t* start_frame, float_t* end_frame) { +void glitter_particle_manager_get_start_end_frame(GPM, float_t* start_frame, float_t* end_frame) { glitter_scene* scene; glitter_effect_inst** i; glitter_effect_inst* effect; @@ -206,9 +241,9 @@ void glitter_particle_manager_get_start_end_frame(glitter_particle_manager* gpm, continue; effect = *i; - life_time = effect->data.life_time; - if (start_frame && effect->data.appear_time < *start_frame) - *start_frame = effect->data.appear_time; + life_time = (float_t)effect->data.life_time; + if (start_frame && (float_t)effect->data.appear_time < *start_frame) + *start_frame = (float_t)effect->data.appear_time; for (j = effect->emitters.begin; j != effect->emitters.end; j++) { if (!*j) @@ -216,18 +251,17 @@ void glitter_particle_manager_get_start_end_frame(glitter_particle_manager* gpm, emitter = *j; if (life_time < emitter->data.life_time) - life_time = emitter->data.life_time; + life_time = (float_t)emitter->data.life_time; } - life_time += effect->data.appear_time; + life_time += (float_t)effect->data.appear_time; if (end_frame && life_time > *end_frame) *end_frame = life_time; } } -bool FASTCALL glitter_particle_manager_load_effect(glitter_particle_manager* gpm, - uint64_t effect_group_hash, uint64_t effect_hash) { +bool FASTCALL glitter_particle_manager_load_effect(GPM, uint64_t effect_group_hash, uint64_t effect_hash) { glitter_effect_group** i; glitter_effect_group* effect_group; glitter_scene** j; @@ -255,15 +289,14 @@ bool FASTCALL glitter_particle_manager_load_effect(glitter_particle_manager* gpm for (k = effect_group->effects.begin, id = 1; k != effect_group->effects.end; k++, id++) { effect = *k; if (effect && effect->data.name_hash == effect_hash) - glitter_scene_init_effect(scene, effect, id, false); + glitter_scene_init_effect(GPM_VAL, scene, effect, id, false); } break; } return i != gpm->effect_groups.end; } -bool FASTCALL glitter_particle_manager_load_scene(glitter_particle_manager* gpm, - uint64_t effect_group_hash) { +bool FASTCALL glitter_particle_manager_load_scene(GPM, uint64_t effect_group_hash) { glitter_effect_group** i; glitter_effect_group* effect_group; glitter_scene** j; @@ -288,61 +321,50 @@ bool FASTCALL glitter_particle_manager_load_scene(glitter_particle_manager* gpm, } for (k = effect_group->effects.begin, id = 1; k != effect_group->effects.end; k++, id++) - glitter_scene_init_effect(scene, *k, id, false); + glitter_scene_init_effect(GPM_VAL, scene, *k, id, false); break; } return i != gpm->effect_groups.end; } -void FASTCALL glitter_particle_manager_reset_scene_disp_counter(glitter_particle_manager* gpm) { - for (glitter_scene** i = gpm->scenes.begin; i != gpm->scenes.end; i++) { - if (!*i) - continue; - - glitter_scene* scene = *i; - scene->sub.disp_quad = 0; - scene->sub.disp_locus = 0; - scene->sub.disp_line = 0; - } -} - -void FASTCALL glitter_particle_manager_set_frame(glitter_particle_manager* gpm, glitter_effect_group* effect_group, - glitter_scene** scene, float_t curr_frame, float_t prev_frame, uint32_t random, uint32_t counter, bool reset) { +void FASTCALL glitter_particle_manager_set_frame(GPM, glitter_effect_group* effect_group, + glitter_scene** scene, float_t curr_frame, float_t prev_frame, uint32_t counter, bool reset) { if (curr_frame < prev_frame || reset) { - for (glitter_scene** i = gpm->scenes.begin; i != gpm->scenes.end; ) - if (!*i) - vector_ptr_glitter_scene_erase(&gpm->scenes, i - gpm->scenes.begin); - else + for (glitter_scene** i = gpm->scenes.begin; i != gpm->scenes.end; ) { + if (*i != *scene) { i++; + continue; + } - gpm->random = random; + vector_ptr_glitter_scene_erase(&gpm->scenes, i - gpm->scenes.begin, glitter_scene_dispose); + } gpm->counter = counter; + glitter_scene* s = glitter_scene_init(effect_group); + vector_ptr_glitter_scene_push_back(&gpm->scenes, &s); glitter_effect_group* eg = effect_group; glitter_effect** i; size_t id = 1; for (i = eg->effects.begin, id = 1; i != eg->effects.end; i++, id++) if (*i) - glitter_scene_init_effect(*scene, *i, id, false); + glitter_scene_init_effect(GPM_VAL, s, *i, id, false); + *scene = s; prev_frame = 0.0f; } float_t delta = curr_frame - prev_frame; - float_t delta_frame = 2.0f; + float_t delta_frame = 1.0f; for (; delta > 0.0f; delta -= delta_frame) { if (delta_frame > delta) delta_frame = delta; glitter_scene* s = *scene; - if (s && !glitter_scene_has_ended(s, true)) { - glitter_scene_update_value_frame(s, delta_frame); - glitter_scene_emit(s, delta_frame); - glitter_scene_update_scene(s, delta_frame); - } + if (s && !glitter_scene_has_ended(s, true)) + glitter_scene_update_value_frame(GPM_VAL, s, delta_frame); } } -bool FASTCALL glitter_particle_manager_test_load_effect(glitter_particle_manager* gpm, +bool FASTCALL glitter_particle_manager_test_load_effect(GPM, uint64_t effect_group_hash, uint64_t effect_hash) { glitter_effect_group** i; glitter_effect_group* effect_group; @@ -371,15 +393,14 @@ bool FASTCALL glitter_particle_manager_test_load_effect(glitter_particle_manager for (k = effect_group->effects.begin, id = 1; k != effect_group->effects.end; k++, id++) { effect = *k; if (effect && effect->data.name_hash == effect_hash) - glitter_scene_init_effect(scene, effect, id, true); + glitter_scene_init_effect(GPM_VAL, scene, effect, id, true); } break; } return i != gpm->effect_groups.end; } -bool FASTCALL glitter_particle_manager_test_load_scene(glitter_particle_manager* gpm, - uint64_t effect_group_hash) { +bool FASTCALL glitter_particle_manager_test_load_scene(GPM, uint64_t effect_group_hash, bool appear_now) { glitter_effect_group** i; glitter_effect_group* effect_group; glitter_scene** j; @@ -404,17 +425,17 @@ bool FASTCALL glitter_particle_manager_test_load_scene(glitter_particle_manager* } for (k = effect_group->effects.begin, id = 1; k != effect_group->effects.end; k++, id++) - glitter_scene_init_effect(scene, *k, id, true); + glitter_scene_init_effect(GPM_VAL, scene, *k, id, appear_now); break; } return i != gpm->effect_groups.end; } -void FASTCALL glitter_particle_manager_update_file_reader(glitter_particle_manager* gpm) { +void FASTCALL glitter_particle_manager_update_file_reader(GPM) { for (glitter_file_reader** i = gpm->file_readers.begin; i != gpm->file_readers.end;) { if (*i) { glitter_file_reader* file_reader = *i; - if (glitter_file_reader_read(file_reader)) { + if (glitter_file_reader_read(GPM_VAL, file_reader)) { file_reader->effect_group->emission = file_reader->emission; if (file_reader->emission <= 0.0) file_reader->effect_group->emission = gpm->emission; @@ -422,37 +443,28 @@ void FASTCALL glitter_particle_manager_update_file_reader(glitter_particle_manag } else if (file_reader->effect_group) glitter_effect_group_dispose(file_reader->effect_group); - glitter_file_reader_dispose(file_reader); } - vector_ptr_glitter_file_reader_erase(&gpm->file_readers, i - gpm->file_readers.begin); + vector_ptr_glitter_file_reader_erase(&gpm->file_readers, + i - gpm->file_readers.begin, glitter_file_reader_dispose); } } -void FASTCALL glitter_particle_manager_update_scene(glitter_particle_manager* gpm) { +void FASTCALL glitter_particle_manager_update_scene(GPM) { gpm->delta_frame = get_frame_speed(); for (glitter_scene** i = gpm->scenes.begin; i != gpm->scenes.end;) { glitter_scene* scene = *i; - if (!scene) - goto copy_scenes; - - if (glitter_scene_has_ended(scene, true)) { - glitter_scene_dispose(scene); - - copy_scenes: - vector_ptr_glitter_scene_erase(&gpm->scenes, i - gpm->scenes.begin); - } - else { - glitter_scene_update_value_frame(scene, gpm->delta_frame); - glitter_scene_emit(scene, gpm->delta_frame); - glitter_scene_update_scene(scene, gpm->delta_frame); + if (scene && !glitter_scene_has_ended(scene, true)) { + glitter_scene_update_value_frame(GPM_VAL, scene, gpm->delta_frame); i++; } + else + vector_ptr_glitter_scene_erase(&gpm->scenes, i - gpm->scenes.begin, glitter_scene_dispose); } } void FASTCALL glitter_particle_manager_dispose(glitter_particle_manager* gpm) { - vector_ptr_glitter_scene_free(&gpm->scenes, (void*)glitter_scene_dispose); - vector_ptr_glitter_file_reader_free(&gpm->file_readers, (void*)glitter_file_reader_dispose); - vector_ptr_glitter_effect_group_free(&gpm->effect_groups, (void*)glitter_effect_group_dispose); + vector_ptr_glitter_scene_free(&gpm->scenes, glitter_scene_dispose); + vector_ptr_glitter_file_reader_free(&gpm->file_readers, glitter_file_reader_dispose); + vector_ptr_glitter_effect_group_free(&gpm->effect_groups, glitter_effect_group_dispose); free(gpm); } diff --git a/src/CRE/Glitter/particle_manager.h b/src/CRE/Glitter/particle_manager.h index 6f25287f..44f99163 100644 --- a/src/CRE/Glitter/particle_manager.h +++ b/src/CRE/Glitter/particle_manager.h @@ -8,37 +8,28 @@ #include "glitter.h" extern glitter_particle_manager* FASTCALL glitter_particle_manager_init(); -extern bool FASTCALL glitter_particle_manager_check_effect_group(glitter_particle_manager* gpm, - uint64_t effect_group_hash); -extern bool FASTCALL glitter_particle_manager_check_file_reader(glitter_particle_manager* gpm, - uint64_t effect_group_hash); -extern bool FASTCALL glitter_particle_manager_check_scene(glitter_particle_manager* gpm, - uint64_t effect_group_hash); -extern void FASTCALL glitter_particle_manager_draw(glitter_particle_manager* gpm, int32_t alpha); -extern bool FASTCALL glitter_particle_manager_free_scene(glitter_particle_manager* gpm, - uint64_t effect_group_hash); -extern bool FASTCALL glitter_particle_manager_free_effect_group(glitter_particle_manager* gpm, - uint64_t effect_group_hash); -extern size_t FASTCALL glitter_particle_manager_get_ctrl_count(glitter_particle_manager* gpm, - glitter_particle_type type); -extern size_t FASTCALL glitter_particle_manager_get_disp_count(glitter_particle_manager* gpm, - glitter_particle_type type); -extern void glitter_particle_manager_get_frame(glitter_particle_manager* gpm, - float_t* frame, float_t* life_time); -extern void glitter_particle_manager_get_start_end_frame(glitter_particle_manager* gpm, - float_t* start_frame, float_t* end_frame); -extern bool FASTCALL glitter_particle_manager_load_effect(glitter_particle_manager* gpm, - uint64_t effect_group_hash, uint64_t effect_hash); -extern bool FASTCALL glitter_particle_manager_load_scene(glitter_particle_manager* gpm, - uint64_t effect_group_hash); -extern void FASTCALL glitter_particle_manager_reset_scene_disp_counter(glitter_particle_manager* gpm); -extern void FASTCALL glitter_particle_manager_set_frame(glitter_particle_manager* gpm, +extern void FASTCALL glitter_particle_manager_calc_draw(GPM, + bool(FASTCALL* render_add_list_func)(glitter_particle_mesh*, vec4*, mat4*, mat4*)); +extern bool FASTCALL glitter_particle_manager_check_effect_group(GPM, uint64_t effect_group_hash); +extern bool FASTCALL glitter_particle_manager_check_file_reader(GPM, uint64_t effect_group_hash); +extern bool FASTCALL glitter_particle_manager_check_scene(GPM, uint64_t effect_group_hash); +extern void FASTCALL glitter_particle_manager_draw(GPM, int32_t alpha); +extern bool FASTCALL glitter_particle_manager_free_effect_group(GPM, uint64_t effect_group_hash); +extern void FASTCALL glitter_particle_manager_free_effect_groups(GPM); +extern bool FASTCALL glitter_particle_manager_free_scene(GPM, uint64_t effect_group_hash); +extern void FASTCALL glitter_particle_manager_free_scenes(GPM); +extern size_t FASTCALL glitter_particle_manager_get_ctrl_count(GPM, glitter_particle_type ptcl_type); +extern size_t FASTCALL glitter_particle_manager_get_disp_count(GPM, glitter_particle_type ptcl_type); +extern void glitter_particle_manager_get_frame(GPM, float_t* frame, float_t* life_time); +extern void glitter_particle_manager_get_start_end_frame(GPM, float_t* start_frame, float_t* end_frame); +extern bool FASTCALL glitter_particle_manager_load_effect(GPM, uint64_t effect_group_hash, uint64_t effect_hash); +extern bool FASTCALL glitter_particle_manager_load_scene(GPM, uint64_t effect_group_hash); +extern void FASTCALL glitter_particle_manager_set_frame(GPM, glitter_effect_group* effect_group, glitter_scene** scene, float_t curr_frame, - float_t prev_frame, uint32_t random, uint32_t counter, bool reset); -extern bool FASTCALL glitter_particle_manager_test_load_effect(glitter_particle_manager* gpm, + float_t prev_frame, uint32_t counter, bool reset); +extern bool FASTCALL glitter_particle_manager_test_load_effect(GPM, uint64_t effect_group_hash, uint64_t effect_hash); -extern bool FASTCALL glitter_particle_manager_test_load_scene(glitter_particle_manager* gpm, - uint64_t effect_group_hash); -extern void FASTCALL glitter_particle_manager_update_file_reader(glitter_particle_manager* gpm); -extern void FASTCALL glitter_particle_manager_update_scene(glitter_particle_manager* gpm); +extern bool FASTCALL glitter_particle_manager_test_load_scene(GPM, uint64_t effect_group_hash, bool appear_now); +extern void FASTCALL glitter_particle_manager_update_file_reader(GPM); +extern void FASTCALL glitter_particle_manager_update_scene(GPM); extern void FASTCALL glitter_particle_manager_dispose(glitter_particle_manager* gpm); diff --git a/src/CRE/Glitter/random.c b/src/CRE/Glitter/random.c index 0b6ff8ac..4094a42e 100644 --- a/src/CRE/Glitter/random.c +++ b/src/CRE/Glitter/random.c @@ -1105,67 +1105,278 @@ static const uint16_t glitter_short_int_table[] = { 0x31EB, 0x3F4F, 0x08A1, 0x5EC1, 0xD52D, 0xDAE8, 0x2363, 0x7A22, }; -extern glitter_particle_manager* gpm; +static const uint32_t glitter_x_float_table[] = { + 0x3ED6C16C, 0x3E444444, 0x3EFA4FA5, 0x3ECFA4FA, 0x3F271C72, 0x3F244444, + 0x3F1E93E9, 0x3F016C17, 0x3E527D28, 0x3E777777, 0x3E9DDDDE, 0x3F7D27D2, + 0x3F666666, 0x3EF60B61, 0x3E7A4FA5, 0x3E4CCCCD, 0x3F4E38E4, 0x3F4B60B6, + 0x3E0B60B6, 0x3E360B61, 0x3E666666, 0x3F51C71C, 0x3F47D27D, 0x3F19999A, + 0x3F64FA50, 0x3F355555, 0x3F3A4FA5, 0x3F4FA4FA, 0x3F7F49F5, 0x3EE4FA50, + 0x3DF49F4A, 0x3F177777, 0x3DC16C17, 0x3EDF49F5, 0x3F6B60B6, 0x3ECB60B6, + 0x3F088889, 0x3F4EEEEF, 0x3F638E39, 0x3E749F4A, 0x3F49F49F, 0x3F36C16C, + 0x3D4CCCCD, 0x3E000000, 0x3E5B05B0, 0x3F5BBBBC, 0x3EF49F4A, 0x3E24FA50, + 0x3D088888, 0x3EEC16C1, 0x3E9F49F5, 0x3F58E38E, 0x3F11C71C, 0x3E7D27D2, + 0x3F7E93E9, 0x3ECE38E4, 0x3C638E39, 0x3F7A4FA5, 0x3DCCCCCD, 0x3F0AAAAB, + 0x3F533333, 0x3F416C17, 0x3C360B61, 0x3EB05B06, 0x3F4C16C1, 0x3EE7D27D, + 0x3F488889, 0x3F511111, 0x3F111111, 0x3F0CCCCD, 0x3F160B61, 0x3F1A4FA5, + 0x3F705B06, 0x3F105B06, 0x3DAAAAAB, 0x3EF33333, 0x3F400000, 0x3EAC16C1, + 0x3F5F49F5, 0x3E927D28, 0x3F493E94, 0x3EF05B06, 0x3EAD82D8, 0x3EDB05B0, + 0x3E8CCCCD, 0x3E89F49F, 0x3F45B05B, 0x3F155555, 0x3EFD27D2, 0x3F29F49F, + 0x3F0FA4FA, 0x3F555555, 0x3CB60B61, 0x3E911111, 0x3E93E93F, 0x3ED9999A, + 0x3E96C16C, 0x3F40B60B, 0x3E9B05B0, 0x3EF8E38E, 0x3F711111, 0x3F133333, + 0x3EEEEEEF, 0x3F727D28, 0x3F093E94, 0x3F0B60B6, 0x3EFE93E9, 0x3F6EEEEF, + 0x3F733333, 0x3E416C17, 0x3F071C72, 0x3F09F49F, 0x3F238E39, 0x3E3BBBBC, + 0x3EC00000, 0x3E49F49F, 0x3F360B61, 0x3ECCCCCD, 0x3F305B06, 0x3F67D27D, + 0x3F200000, 0x3EF1C71C, 0x3F4D82D8, 0x3F582D83, 0x3EDDDDDE, 0x3D93E93F, + 0x3F327D28, 0x3ED82D83, 0x3F00B60B, 0x3F25B05B, 0x3F3DDDDE, 0x3EBA4FA5, + 0x3E333333, 0x3E5DDDDE, 0x3EE0B60B, 0x3D8E38E3, 0x3F0E38E4, 0x3E222222, + 0x3D82D82E, 0x3EDC71C7, 0x3F7DDDDE, 0x3EE93E94, 0x3E0E38E4, 0x3EA66666, + 0x3F022222, 0x3E2AAAAB, 0x3E111111, 0x3EC71C72, 0x3CE38E39, 0x3E982D83, + 0x3F288889, 0x3D582D83, 0x3E16C16C, 0x3E471C72, 0x3E800000, 0x3ED3E93F, + 0x3EA93E94, 0x3EA38E39, 0x3F382D83, 0x3F38E38E, 0x3F3BBBBC, 0x3F293E94, + 0x3F3B05B0, 0x3D99999A, 0x3F0D82D8, 0x3E1F49F5, 0x3F4CCCCD, 0x3F22D82E, + 0x3F577777, 0x3E02D82E, 0x3DE38E39, 0x3DD27D28, 0x3EE66666, 0x3F6CCCCD, + 0x3F149F4A, 0x3F44FA50, 0x3F600000, 0x3EC16C17, 0x3F2EEEEF, 0x3EB33333, + 0x3F333333, 0x3F2C16C1, 0x3F5C71C7, 0x3F066666, 0x3F466666, 0x3EB60B61, + 0x3F182D83, 0x3B360B62, 0x3F2AAAAB, 0x3C9F49F4, 0x3F2FA4FA, 0x3F3F49F5, + 0x3DB60B61, 0x3F311111, 0x3F755555, 0x3ED55555, 0x3EC2D82E, 0x3F622222, + 0x3EC5B05B, 0x3F7C71C7, 0x3F13E93F, 0x3F18E38E, 0x3D2AAAAB, 0x3E2D82D8, + 0x3F377777, 0x3F038E39, 0x3F5E93E9, 0x3DC71C72, 0x3F59999A, 0x3F222222, + 0x3DA4FA50, 0x3F53E93F, 0x3F1D27D2, 0x3BB60B62, 0x3EB8E38E, 0x3DBBBBBC, + 0x3F422222, 0x3E582D83, 0x3EAAAAAB, 0x3F644444, 0x3F0C16C1, 0x3D1F49F5, + 0x3DE93E94, 0x3F671C72, 0x3F04FA50, 0x3EE22222, 0x3CFA4FA5, 0x3F31C71C, + 0x3EC44444, 0x3E05B05B, 0x3F2CCCCD, 0x3E9C71C7, 0x3DB05B06, 0x3E99999A, + 0x3E8FA4FA, 0x3EA7D27D, 0x3F5A4FA5, 0x3F000000, 0x3E955555, 0x3E888889, + 0x3F5D27D2, 0x3E871C72, 0x3DEEEEEF, 0x3F2E38E4, 0x3D638E39, 0x3EFBBBBC, + 0x3F24FA50, 0x3F69F49F, 0x3E1C71C7, 0x3EBE93E9, 0x3D6EEEEF, 0x3DFA4FA5, + 0x3E6EEEEF, 0x3F6C16C1, 0x3F6D82D8, 0x3F71C71C, 0x3F505B06, 0x3D416C17, + 0x3DD82D83, 0x3F4AAAAB, 0x3F782D83, 0x3F349F4A, 0x3EB1C71C, 0x3F42D82E, + 0x3EBBBBBC, 0x3F1B05B0, 0x3F1F49F5, 0x3E816C17, 0x3D9F49F5, 0x3EC88889, + 0x3F127D28, 0x3F60B60B, 0x3F07D27D, 0x3E19999A, 0x3E693E94, 0x3EA22222, + 0x3ED27D28, 0x3E27D27D, 0x3F39999A, 0x3EB77777, 0x3E844444, 0x3E8B60B6, + 0x3D7A4FA5, 0x3E4FA4FA, 0x3EAEEEEF, 0x3F6AAAAB, 0x3F05B05B, 0x3F438E39, + 0x3E60B60B, 0x3F56C16C, 0x3EE38E39, 0x3E3E93E9, 0x3F549F4A, 0x3E555555, + 0x3EA0B60B, 0x3F2B60B6, 0x3F7BBBBC, 0x3F33E93F, 0x3EBD27D2, 0x3E71C71C, + 0x3F6FA4FA, 0x3E305B06, 0x3E38E38E, 0x3EED82D8, 0x3F65B05B, 0x3D13E93F, + 0x3F616C17, 0x3F0EEEEF, 0x3F1C71C7, 0x3E13E93F, 0x3DDDDDDE, 0x3F6E38E4, + 0x3F27D27D, 0x3ED11111, 0x3F777777, 0x3EEAAAAB, 0x3F1BBBBC, 0x3F1DDDDE, + 0x3F216C17, 0x3F78E38E, 0x3C888889, 0x3F3C71C7, 0x3F7B05B0, 0x3F3D27D2, + 0x3F79999A, 0x3F688889, 0x3E82D82E, 0x3EF77777, 0x3F2D82D8, 0x3F471C72, + 0x3C088888, 0x3F560B61, 0x3E088889, 0x3CCCCCCD, 0x3F266666, 0x3F20B60B, + 0x3F527D28, 0x3F02D82E, 0x3F760B61, 0x3F044444, 0x3F73E93F, 0x3F749F4A, + 0x3F76C16C, 0x3F693E94, 0x3E85B05B, 0x3F16C16C, 0x3F5B05B0, 0x3E638E39, + 0x3D360B61, 0x3F5DDDDE, 0x3F800000, 0x3F3E93E9, 0x3E6C16C1, 0x3F62D82E, + 0x3E8E38E4, 0x3EB49F4A, 0x3EA4FA50, 0x3D888889, 0x3EC9F49F, 0x3F444444, + 0x00000000, +}; -int32_t FASTCALL glitter_random_get() { - if (gpm->f2) - return gpm->random & 0xFF; - else - return gpm->random & 0xFFF; +static const uint32_t glitter_x_int_table[] = { + 0x01663B, 0x0093BA, 0x00B6DF, 0x0055FA, 0x00056F, 0x0171E9, + 0x0178BD, 0x011C5E, 0x00C875, 0x015832, 0x015785, 0x00C379, + 0x0037A2, 0x000FF8, 0x015A7B, 0x000E5C, 0x00AAE9, 0x00FD61, + 0x017CC5, 0x015F51, 0x005FF9, 0x00C80E, 0x0126BB, 0x002AAF, + 0x000819, 0x003108, 0x01558D, 0x017865, 0x008D3E, 0x012244, + 0x018678, 0x00D564, 0x005E24, 0x015636, 0x00A338, 0x0122E0, + 0x01514C, 0x014F2D, 0x0068E0, 0x013B24, 0x00E6D9, 0x011423, + 0x013816, 0x01781F, 0x00EF31, 0x003FAD, 0x00BEC7, 0x007246, + 0x0075B9, 0x006AEE, 0x000F74, 0x01359E, 0x00DC34, 0x004403, + 0x001824, 0x00EBE9, 0x015E3F, 0x00ED52, 0x0126D1, 0x016D82, + 0x0091B7, 0x006BF1, 0x00BFEA, 0x001196, 0x011653, 0x001449, + 0x0141B7, 0x00411C, 0x015AB9, 0x00801A, 0x00A886, 0x006090, + 0x006D66, 0x01158A, 0x009F27, 0x01445E, 0x00A906, 0x00AB11, + 0x00D04E, 0x017DB5, 0x0158C4, 0x016426, 0x006C1E, 0x009A72, + 0x00282E, 0x000FA1, 0x017C80, 0x00C25A, 0x003199, 0x0173A9, + 0x004F33, 0x015650, 0x00490F, 0x007A69, 0x0059BF, 0x016CD1, + 0x0055EB, 0x012437, 0x00844E, 0x0090D4, 0x01556B, 0x00FD65, + 0x00B7CD, 0x001B58, 0x017541, 0x011A31, 0x015541, 0x0127FE, + 0x0145F8, 0x00217F, 0x00455F, 0x00FDD8, 0x01274D, 0x00A8B1, + 0x001FF4, 0x001FB8, 0x004E42, 0x016D7F, 0x005B3C, 0x009095, + 0x00164C, 0x0100CB, 0x0002AB, 0x0142A3, 0x01069B, 0x0006EB, + 0x008435, 0x01515E, 0x0007F2, 0x018338, 0x014AAC, 0x00EE95, + 0x014270, 0x01142A, 0x0096B8, 0x00B296, 0x010F88, 0x004CD4, + 0x006AE6, 0x0171D5, 0x00AD6A, 0x00CCD6, 0x010438, 0x006666, + 0x001999, 0x004F4B, 0x014C6C, 0x007EB4, 0x00E148, 0x013BE6, + 0x000043, 0x016EEE, 0x009CE8, 0x0061EB, 0x00490F, 0x011738, + 0x00C02B, 0x00B9ED, 0x00EE7A, 0x00D519, 0x011F19, 0x0075D6, + 0x000F80, 0x0060D9, 0x004F77, 0x017B63, 0x007703, 0x0098D1, + 0x00C6F4, 0x014926, 0x00E2B6, 0x00BBBF, 0x001F02, 0x00C3AA, + 0x009C82, 0x0100A9, 0x00EA47, 0x0096D8, 0x012610, 0x018129, + 0x012C41, 0x00F131, 0x00F16E, 0x015509, 0x00D544, 0x011686, + 0x012F14, 0x016F80, 0x0012D6, 0x008D8D, 0x006245, 0x0155AF, + 0x007E83, 0x00B8E7, 0x002165, 0x016124, 0x01190D, 0x00D764, + 0x0127F5, 0x00163B, 0x0043C1, 0x010F0C, 0x00C855, 0x002D18, + 0x014DA5, 0x0176B9, 0x0017B8, 0x01351C, 0x011656, 0x00D94F, + 0x00FDAF, 0x015F3B, 0x00B41D, 0x013BAB, 0x0151CB, 0x00D8D3, + 0x00FFF2, 0x003DE4, 0x000D45, 0x0148C2, 0x016F76, 0x01661C, + 0x007CF7, 0x006069, 0x009101, 0x006D63, 0x00A21D, 0x006F29, + 0x00E4D9, 0x00A2EF, 0x010C9B, 0x0172E4, 0x002BB3, 0x016C4E, + 0x00C257, 0x010995, 0x0141F2, 0x013BE8, 0x005100, 0x01459E, + 0x00DE88, 0x00FB44, 0x00F02D, 0x0050CA, 0x004BF9, 0x014505, + 0x00083F, 0x006644, 0x008898, 0x00E94B, 0x005EB3, 0x0094D1, + 0x008948, 0x0180C8, 0x00D50F, 0x01372D, 0x00204E, 0x00D42A, + 0x0062EF, 0x001055, 0x00C41D, 0x0039A3, 0x002732, 0x004493, + 0x01070E, 0x015484, 0x0068F3, 0x0084F1, 0x00A7E4, 0x00ABE7, + 0x015650, 0x0063B1, 0x00A3C2, 0x00B8DD, 0x0128E3, 0x006306, + 0x012526, 0x0104BD, 0x007589, 0x005E02, 0x008BB4, 0x00DDD3, + 0x003A2C, 0x012687, 0x010E85, 0x017A83, 0x00F342, 0x00B1C4, + 0x006B1F, 0x016D1E, 0x00FA31, 0x0039B6, 0x012987, 0x0006B8, + 0x01319A, 0x009296, 0x0152B6, 0x007B87, 0x00E665, 0x012124, + 0x004CF2, 0x0133C8, 0x01838B, 0x009530, 0x017C0A, 0x01196B, + 0x0124EC, 0x01512F, 0x000008, 0x01019B, 0x00CA28, 0x00D76F, + 0x001882, 0x002191, 0x015356, 0x00499B, 0x013138, 0x0170E2, + 0x00F046, 0x01480E, 0x013456, 0x017BCB, 0x003691, 0x0004F3, + 0x00ECAE, 0x004AEA, 0x01460E, 0x0053CA, 0x000D17, 0x011A78, + 0x000869, 0x00C190, 0x0130BB, 0x00FFEF, 0x013B73, 0x0103DB, + 0x00885A, 0x00A503, 0x0038BC, 0x005B4A, 0x0150B5, 0x016CAB, + 0x0167AF, 0x006396, 0x00528E, 0x00156C, 0x016428, 0x00D508, + 0x0178F0, 0x00512B, 0x005CFC, 0x004098, 0x005897, 0x001F27, + 0x0073DA, 0x00F12C, 0x016CBA, 0x007417, 0x009A1C, 0x00D3D0, + 0x000001, +}; + +int32_t FASTCALL glitter_random_get_value(glitter_random* random) { + return random->value; } -float_t FASTCALL glitter_random_get_float_clamp(float_t min, float_t max) { +float_t FASTCALL glitter_random_get_float(GPM, glitter_random* random, float_t value) { + float_t val; + + switch (glt_type) { + default: + case GLITTER_AFT: + val = *(float_t*)&glitter_full_float_table[random->value % 0x1000]; + break; + case GLITTER_F2: + val = *(float_t*)&glitter_short_float_table[random->value % 0x100]; + break; + case GLITTER_X: + val = *(float_t*)&glitter_x_float_table[random->value % 0x169]; + break; + } + random->value += random->step; + return val * (value * 2.0f) - value; +} + +float_t FASTCALL glitter_random_get_float_min_max(GPM, glitter_random* random, float_t min, float_t max) { float_t value; - if (gpm->f2) - value = *(float_t*)&glitter_short_float_table[gpm->random++ & 0xFF]; - else - value = *(float_t*)&glitter_full_float_table[gpm->random++ & 0xFFF]; + switch (glt_type) { + default: + case GLITTER_AFT: + value = *(float_t*)&glitter_full_float_table[random->value % 0x1000]; + break; + case GLITTER_F2: + value = *(float_t*)&glitter_short_float_table[random->value % 0x100]; + break; + case GLITTER_X: + value = *(float_t*)&glitter_x_float_table[random->value % 0x169]; + break; + } + random->value += random->step; return value * (max - min) + min; } -float_t FASTCALL glitter_random_get_float_clamp_min_max(float_t value) { - return glitter_random_get_float_clamp(-value, value); +void FASTCALL glitter_random_get_vec3(GPM, glitter_random* random, vec3* src, vec3* dst) { + vec3 val; + vec3 t; + + switch (glt_type) { + default: + case GLITTER_AFT: + val.x = *(float_t*)&glitter_full_float_table[random->value % 0x1000]; + random->value += random->step; + val.y = *(float_t*)&glitter_full_float_table[random->value % 0x1000]; + random->value += random->step; + val.z = *(float_t*)&glitter_full_float_table[random->value % 0x1000]; + random->value += random->step; + break; + case GLITTER_F2: + val.x = *(float_t*)&glitter_short_float_table[random->value % 0x100]; + random->value += random->step; + val.y = *(float_t*)&glitter_short_float_table[random->value % 0x100]; + random->value += random->step; + val.z = *(float_t*)&glitter_short_float_table[random->value % 0x100]; + random->value += random->step; + break; + case GLITTER_X: + val.x = *(float_t*)&glitter_x_float_table[random->value % 0x169]; + random->value += random->step; + val.y = *(float_t*)&glitter_x_float_table[random->value % 0x169]; + random->value += random->step; + val.z = *(float_t*)&glitter_x_float_table[random->value % 0x169]; + random->value += random->step; + break; + } + t = *src; + vec3_add(t, t, t); + vec3_mult(val, t, t); + vec3_sub(t, *src, *dst); } -void FASTCALL glitter_random_get_float_vec3_clamp(vec3* src, vec3* dst) { - dst->x = glitter_random_get_float_clamp_min_max(src->x); - dst->y = glitter_random_get_float_clamp_min_max(src->y); - dst->z = glitter_random_get_float_clamp_min_max(src->z); -} - -int32_t FASTCALL glitter_random_get_int(int32_t value) { +int32_t FASTCALL glitter_random_get_int(GPM, glitter_random* random, int32_t value) { int32_t val; - if (gpm->f2) - val = glitter_short_int_table[gpm->random++ & 0xFF]; - else - val = glitter_full_int_table[gpm->random++ & 0xFFF]; + switch (glt_type) { + default: + case GLITTER_AFT: + val = glitter_full_int_table[random->value % 0x1000]; + break; + case GLITTER_F2: + val = glitter_short_int_table[random->value % 0x100]; + break; + case GLITTER_X: + val = glitter_x_int_table[random->value % 0x169]; + break; + } + random->value += random->step; return val % value; } -int32_t FASTCALL glitter_random_get_int_clamp(int32_t min, int32_t max) { +int32_t FASTCALL glitter_random_get_int_min_max(GPM, glitter_random* random, int32_t min, int32_t max) { int32_t value; if (max == min) return min; - if (gpm->f2) - value = glitter_short_int_table[gpm->random++ & 0xFF]; - else - value = glitter_full_int_table[gpm->random++ & 0xFFF]; + switch (glt_type) { + default: + case GLITTER_AFT: + value = glitter_full_int_table[random->value % 0x1000]; + break; + case GLITTER_F2: + value = glitter_short_int_table[random->value % 0x100]; + break; + case GLITTER_X: + value = glitter_x_int_table[random->value % 0x169]; + break; + } + random->value += random->step; return value % (max - min) + min; } -int32_t FASTCALL glitter_random_get_max() { - if (gpm->f2) - return 0x100; - else +int32_t FASTCALL glitter_random_get_max(GPM) { + switch (glt_type) { + default: + case GLITTER_AFT: return 0x1000; + case GLITTER_F2: + return 0x100; + case GLITTER_X: + return 0x169; + } } -void FASTCALL glitter_random_set(int32_t value) { - if (gpm->f2) - gpm->random = value & 0xFF; - else - gpm->random = value & 0xFFF; +void FASTCALL glitter_random_reset(glitter_random* random) { + random->value = 0; + random->step = 1; +} + +void FASTCALL glitter_random_set_step(glitter_random* random, uint8_t step) { + random->step = step; +} + +void FASTCALL glitter_random_set_value(glitter_random* random, int32_t value) { + random->value = value; +} + +void FASTCALL glitter_random_step_value(glitter_random* random) { + random->value += random->step; } diff --git a/src/CRE/Glitter/random.h b/src/CRE/Glitter/random.h index 78bba56a..8c037fb7 100644 --- a/src/CRE/Glitter/random.h +++ b/src/CRE/Glitter/random.h @@ -7,11 +7,19 @@ #include "glitter.h" -extern int32_t FASTCALL glitter_random_get(); -extern float_t FASTCALL glitter_random_get_float_clamp(float_t min, float_t max); -extern float_t FASTCALL glitter_random_get_float_clamp_min_max(float_t value); -extern void FASTCALL glitter_random_get_float_vec3_clamp(vec3* src, vec3* dst); -extern int32_t FASTCALL glitter_random_get_int(int32_t value); -extern int32_t FASTCALL glitter_random_get_int_clamp(int32_t min, int32_t max); -extern int32_t FASTCALL glitter_random_get_max(); -extern void FASTCALL glitter_random_set(int32_t value); +extern int32_t FASTCALL glitter_random_get_value(glitter_random* random); +extern float_t FASTCALL glitter_random_get_float(GPM, + glitter_random* random, float_t value); +extern float_t FASTCALL glitter_random_get_float_min_max(GPM, + glitter_random* random, float_t min, float_t max); +extern void FASTCALL glitter_random_get_vec3(GPM, + glitter_random* random, vec3* src, vec3* dst); +extern int32_t FASTCALL glitter_random_get_int(GPM, + glitter_random* random, int32_t value); +extern int32_t FASTCALL glitter_random_get_int_min_max(GPM, + glitter_random* random, int32_t min, int32_t max); +extern int32_t FASTCALL glitter_random_get_max(GPM); +extern void FASTCALL glitter_random_reset(glitter_random* random); +extern void FASTCALL glitter_random_set_step(glitter_random* random, uint8_t step); +extern void FASTCALL glitter_random_set_value(glitter_random* random, int32_t value); +extern void FASTCALL glitter_random_step_value(glitter_random* random); diff --git a/src/CRE/Glitter/render_element.c b/src/CRE/Glitter/render_element.c new file mode 100644 index 00000000..1ae0ca22 --- /dev/null +++ b/src/CRE/Glitter/render_element.c @@ -0,0 +1,468 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "render_element.h" +#include "counter.h" +#include "curve.h" +#include "emitter_inst.h" +#include "locus_history.h" +#include "particle_inst.h" +#include "random.h" + +static void FASTCALL glitter_render_element_accelerate(GPM, glitter_particle_inst* a1, + glitter_render_element* a2, float_t delta_frame, glitter_random* random); +static void FASTCALL glitter_render_element_step_uv(GPM, glitter_particle_inst* a1, + glitter_render_element* a2, float_t delta_frame, glitter_random* random); + +void FASTCALL glitter_render_element_emit(GPM, + glitter_particle_inst* a1, glitter_render_element* a2, glitter_emitter_inst* a3, + glitter_particle_inst_data* a4, int32_t index, uint8_t step, glitter_random* random) { + float_t speed; + float_t deceleration; + vec3 direction; + vec3 base_translation; + vec3 scale; + vec3 external_acceleration; + vec3 direction_random; + int32_t max_uv; + bool copy_mat; + + a2->random.value = glitter_random_get_value(random); + a2->random.step = step; + a2->frame = 0.0f; + a2->rebound_frame = 0.0f; + a2->uv = vec2_null; + a2->uv_index = a4->data.uv_index; + + a2->fade_in_frames = 0.0f; + a2->fade_out_frames = 0.0f; + a2->life_time = (float_t)a4->data.life_time; + + a2->color = a4->data.color; + if (a4->data.draw_type == GLITTER_DIRECTION_PARTICLE_ROTATION) { + a2->rotation.x = glitter_random_get_float(GPM_VAL, random, a4->data.rotation_random.x) + + a4->data.rotation.x; + a2->rotation_add.x = glitter_random_get_float(GPM_VAL, random, a4->data.rotation_add_random.x) + + a4->data.rotation_add.x; + a2->rotation.y = glitter_random_get_float(GPM_VAL, random, a4->data.rotation_random.y) + + a4->data.rotation.y; + a2->rotation_add.y = glitter_random_get_float(GPM_VAL, random, a4->data.rotation_add_random.y) + + a4->data.rotation_add.y; + } + else { + a2->rotation.x = 0.0f; + a2->rotation.y = 0.0f; + a2->rotation_add.x = 0.0f; + a2->rotation_add.y = 0.0f; + } + a2->rotation.z = glitter_random_get_float(GPM_VAL, random, a4->data.rotation_random.z) + + a4->data.rotation.z; + a2->rotation_add.z = glitter_random_get_float(GPM_VAL, random, a4->data.rotation_add_random.z) + + a4->data.rotation_add.z; + a2->uv_scroll = vec2_null; + a2->uv_scroll_2nd = vec2_null; + a2->scale = vec3_identity; + a2->scale_all = 1.0f; + a2->frame_step_uv = (float_t)a4->data.frame_step_uv; + + a2->scale_particle.x = glitter_random_get_float(GPM_VAL, random, a4->data.scale_random.x) + + a4->data.scale.x; + if (a4->data.flags & GLITTER_PARTICLE_SCALE_Y_BY_X) + a2->scale_particle.y = a2->scale_particle.x; + else + a2->scale_particle.y = glitter_random_get_float(GPM_VAL, random, a4->data.scale_random.y) + + a4->data.scale.y; + + max_uv = a4->data.split_u * a4->data.split_v; + if (max_uv > 1 && a4->data.uv_index_count > 1) { + switch (a4->data.uv_index_type) { + case GLITTER_UV_INDEX_INITIAL_RANDOM_FIXED: + case GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD: + case GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE: + a2->uv_index += glitter_random_get_int(GPM_VAL, random, a4->data.uv_index_count); + break; + } + a2->uv_index = min(a2->uv_index, a4->data.uv_index_end); + a2->uv.x = (float_t)(a2->uv_index % a1->data.data.split_u) * a1->data.data.split_uv.x; + a2->uv.y = (float_t)(a2->uv_index / a1->data.data.split_u) * a1->data.data.split_uv.y; + } + + if (a4->data.flags & (GLITTER_PARTICLE_EMITTER_LOCAL | GLITTER_PARTICLE_ROTATE_BY_EMITTER)) + a2->base_translation = vec3_null; + else + mat4_get_translation(&a3->mat, &a2->base_translation); + + direction = a4->data.direction; + base_translation = vec3_null; + if (a4->data.flags & GLITTER_PARTICLE_EMITTER_LOCAL) { + scale = vec3_identity; + glitter_emitter_inst_get_mesh_by_type(GPM_VAL, a3, index, &scale, &base_translation, &direction, random); + } + else { + vec3_mult_scalar(a3->scale, a3->scale_all, scale); + glitter_emitter_inst_get_mesh_by_type(GPM_VAL, a3, index, &scale, &base_translation, &direction, random); + mat4_mult_vec3(&a3->mat_no_scale, &base_translation, &base_translation); + } + + vec3_add(a2->base_translation, base_translation, a2->base_translation); + a2->translation = a2->base_translation; + a2->translation_prev = a2->base_translation; + glitter_random_get_vec3(GPM_VAL, random, &a4->data.direction_random, &direction_random); + vec3_add(direction, direction_random, direction); + vec3_normalize(direction, direction); + + if (~a4->data.flags & GLITTER_PARTICLE_EMITTER_LOCAL) + mat4_mult_vec3(&a3->mat_no_scale, &direction, &direction); + a2->base_direction = direction; + a2->direction = direction; + + speed = glitter_random_get_float(GPM_VAL, random, a4->data.speed_random) + a4->data.speed; + deceleration = glitter_random_get_float(GPM_VAL, random, a4->data.deceleration_random) + a4->data.deceleration; + a2->speed = speed * 60.0f; + a2->deceleration = max(deceleration * 60.0f, 0.0f); + + glitter_random_get_vec3(GPM_VAL, random, &a4->data.acceleration_random, &external_acceleration); + vec3_add(external_acceleration, a4->data.acceleration, external_acceleration); + vec3_add(external_acceleration, a4->data.gravity, a2->acceleration); + + copy_mat = false; + if (a4->data.flags & GLITTER_PARTICLE_ROTATE_BY_EMITTER + || a4->data.draw_type == GLITTER_DIRECTION_EMITTER_ROTATION) { + switch (a3->data.type) { + case GLITTER_EMITTER_CYLINDER: + if (a3->data.cylinder.direction != GLITTER_EMITTER_EMISSION_DIRECTION_NONE) { + float_t length; + vec3_length(a2->direction, length); + copy_mat = length <= 0.000001f; + } + else + copy_mat = true; + break; + case GLITTER_EMITTER_SPHERE: + if (a3->data.sphere.direction != GLITTER_EMITTER_EMISSION_DIRECTION_NONE) { + float_t length; + vec3_length(a2->direction, length); + copy_mat = length <= 0.000001f; + } + else + copy_mat = true; + break; + default: + copy_mat = true; + break; + } + } + + if (copy_mat) { + a2->mat = a3->mat; + if (a4->data.flags & GLITTER_PARTICLE_EMITTER_LOCAL) + a2->mat.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; + } + else + a2->mat = mat4_identity; + + if (a1->data.data.type == GLITTER_PARTICLE_LOCUS) { + uint32_t locus_history_size = glitter_random_get_int_min_max(GPM_VAL, random, + -a1->data.data.locus_history_size_random, a1->data.data.locus_history_size_random) + + a1->data.data.locus_history_size; + a2->locus_history = glitter_locus_history_init(locus_history_size); + } + glitter_random_step_value(random); +} + +void FASTCALL glitter_render_element_free(glitter_render_element* a1) { + a1->alive = false; + if (a1->locus_history) { + glitter_locus_history_dispose(a1->locus_history); + a1->locus_history = 0; + } +} + +void FASTCALL glitter_render_element_get_value(GPM, + glitter_render_group* a1, glitter_render_element* a2, float_t delta_frame) { + glitter_particle_inst* v4; + vec2 uv_scroll; + vec2 uv_scroll_2nd; + vec3 translation; + bool has_translation; + size_t length; + glitter_curve* curve; + float_t value; + float_t color_scale; + + glitter_random_set_step(a1->random_ptr, 1); + v4 = a1->particle; + if (!v4 || !((v4->data.data.flags & GLITTER_PARTICLE_LOOP + && !glitter_particle_inst_has_ended(v4, false)) || a2->frame <= a2->life_time)) { + a1->ctrl--; + a2->alive = false; + if (a2->locus_history) { + glitter_locus_history_dispose(a2->locus_history); + a2->locus_history = 0; + } + return; + } + + glitter_render_element_accelerate(GPM_VAL, v4, a2, delta_frame, a1->random_ptr); + if (v4->data.data.draw_type == GLITTER_DIRECTION_PARTICLE_ROTATION) { + a2->rotation.x += a2->rotation_add.x * delta_frame; + a2->rotation.y += a2->rotation_add.y * delta_frame; + } + a2->rotation.z += a2->rotation_add.z * delta_frame; + vec2_mult_scalar(v4->data.data.uv_scroll_add, + v4->data.data.uv_scroll_add_scale * delta_frame, uv_scroll); + vec2_add(a2->uv_scroll, uv_scroll, a2->uv_scroll); + vec2_mult_scalar(v4->data.data.uv_scroll_2nd_add, + v4->data.data.uv_scroll_2nd_add_scale * delta_frame, uv_scroll_2nd); + vec2_add(a2->uv_scroll_2nd, uv_scroll_2nd, a2->uv_scroll_2nd); + glitter_render_element_step_uv(GPM_VAL, v4, a2, delta_frame, a1->random_ptr); + a2->color = (vec4){ -1.0f, -1.0f, -1.0f, -1.0f }; + color_scale = -1.0f; + a2->draw = true; + + if (v4->data.data.sub_flags & GLITTER_PARTICLE_SUB_USE_CURVE) { + value = 0.0f; + has_translation = false; + translation = vec3_null; + + vector_ptr_glitter_curve curv = v4->particle->curve; + length = curv.end - curv.begin; + for (size_t i = 0; i < length; i++) { + curve = curv.begin[i]; + if (!glitter_curve_get_value(GPM_VAL, curve, a2->frame, &value, + (int32_t)(a2->random.value + i), a1->random_ptr)) + continue; + + switch (curve->type) { + case GLITTER_CURVE_TRANSLATION_X: + translation.x = value; + has_translation = true; + break; + case GLITTER_CURVE_TRANSLATION_Y: + translation.y = value; + has_translation = true; + break; + case GLITTER_CURVE_TRANSLATION_Z: + translation.z = value; + has_translation = true; + break; + case GLITTER_CURVE_ROTATION_X: + a2->rotation.x = value; + break; + case GLITTER_CURVE_ROTATION_Y: + a2->rotation.y = value; + break; + case GLITTER_CURVE_ROTATION_Z: + a2->rotation.z = value; + break; + case GLITTER_CURVE_SCALE_X: + a2->scale.x = value; + if (fabsf(value) < 0.000001f) + a2->draw = false; + break; + case GLITTER_CURVE_SCALE_Y: + a2->scale.y = value; + if (fabsf(value) < 0.000001f) + a2->draw = false; + break; + case GLITTER_CURVE_SCALE_Z: + a2->scale.z = value; + if (fabsf(value) < 0.000001f) + a2->draw = false; + break; + case GLITTER_CURVE_SCALE_ALL: + a2->scale_all = value; + if (fabsf(value) < 0.000001f) + a2->draw = false; + break; + case GLITTER_CURVE_COLOR_R: + a2->color.x = value; + break; + case GLITTER_CURVE_COLOR_G: + a2->color.y = value; + break; + case GLITTER_CURVE_COLOR_B: + a2->color.z = value; + break; + case GLITTER_CURVE_COLOR_A: + a2->color.w = value; + if (value < 0.01f) + a2->draw = false; + break; + case GLITTER_CURVE_U_SCROLL: + a2->uv_scroll.x = value; + break; + case GLITTER_CURVE_V_SCROLL: + a2->uv_scroll.y = value; + break; + } + } + + if (v4->data.data.flags & GLITTER_PARTICLE_ROTATE_BY_EMITTER || has_translation) { + vec3_add(translation, a2->base_translation, translation); + if (v4->data.data.flags & GLITTER_PARTICLE_ROTATE_BY_EMITTER) + mat4_mult_vec3_trans(&a2->mat, &translation, &translation); + a2->translation = translation; + } + } + + if (a2->draw) { + if (a2->color.x < 0.0f) + a2->color.x = v4->data.data.color.x; + if (a2->color.y < 0.0f) + a2->color.y = v4->data.data.color.y; + if (a2->color.z < 0.0f) + a2->color.z = v4->data.data.color.z; + if (a2->color.w < 0.0f) + a2->color.w = v4->data.data.color.w; + + if (color_scale >= 0.0f) + vec3_mult_scalar(*(vec3*)&a2->color, color_scale, *(vec3*)&a2->color); + + if (a2->fade_in_frames > 0.0 && (a2->life_time - a2->frame) < a2->fade_in_frames) + a2->color.w *= (a2->life_time - a2->frame) / a2->fade_in_frames; + else if (a2->fade_out_frames > 0.0 && a2->frame < a2->fade_out_frames) + a2->color.w *= a2->frame / a2->fade_out_frames; + + if (a2->color.w < 0.01f) + a2->draw = false; + } + + if (v4->data.data.type == GLITTER_PARTICLE_LOCUS) + glitter_locus_history_append(GPM_VAL, a2->locus_history, a2, v4); + + a2->frame += delta_frame; + if (v4->data.data.flags & GLITTER_PARTICLE_LOOP && a2->frame >= a2->life_time) + a2->frame -= a2->life_time; +} + +void FASTCALL glitter_render_element_rotate_to_position(mat3* mat, + glitter_render_group* a2, glitter_render_element* a3) { + vec3 vec1; + vec3 vec2; + float_t angle; + vec3 axis; + + if (a2->flags & GLITTER_PARTICLE_EMITTER_LOCAL) + vec2 = a3->translation; + else { + mat4_get_translation(&a2->mat, &vec2); + vec3_sub(vec2, a3->translation, vec2); + } + vec3_normalize(vec2, vec2); + + if (fabsf(vec2.y) >= 0.000001f) { + *mat = mat3_identity; + vec1 = (vec3){ 0.0f, 0.0f, 1.0f }; + axis_angle_from_vectors(&axis, &angle, &vec1, &vec2); + mat3_mult_axis_angle(mat, mat, &axis, angle); + } + else + mat3_rotate_z((float_t)M_PI, mat); +} + +void FASTCALL glitter_render_element_rotate_to_prev_position(mat3* mat, + glitter_render_group* a2, glitter_render_element* a3) { + vec3 vec1; + vec3 vec2; + float_t angle; + vec3 axis; + float_t length; + + vec3_sub(a3->translation, a3->translation_prev, vec2); + vec3_length_squared(vec2, length); + if (length < 0.000001f) + vec2 = a3->translation; + vec3_normalize(vec2, vec2); + + if (fabsf(vec2.y) >= 0.000001f) { + mat3_rotate_z((float_t)M_PI, mat); + vec1 = (vec3){ 0.0f, 1.0f, 0.0f }; + axis_angle_from_vectors(&axis, &angle, &vec1, &vec2); + mat3_mult_axis_angle(mat, mat, &axis, angle); + } + else + mat3_rotate_z((float_t)M_PI, mat); +} + +static void FASTCALL glitter_render_element_accelerate(GPM, glitter_particle_inst* a1, + glitter_render_element* a2, float_t delta_frame, glitter_random* random) { + vec3 acceleration; + vec3 direction; + float_t diff_time; + float_t delta_time; + float_t reflection_coeff; + float_t speed; + + a2->translation_prev = a2->translation; + delta_time = delta_frame * (float_t)(1.0 / 60.0); + diff_time = (a2->frame - a2->rebound_frame - delta_frame) * (float_t)(1.0 / 60.0); + vec3_mult_scalar(a2->acceleration, delta_time * (delta_time * 0.5f + diff_time), acceleration); + speed = a2->deceleration * delta_time * (delta_time * 0.5f - diff_time) + a2->speed; + if (speed >= 0.01f) { + vec3_mult_scalar(a2->direction, speed * delta_time, direction); + vec3_add(acceleration, direction, acceleration); + } + vec3_add(a2->translation, acceleration, a2->translation); + vec3_add(a2->base_translation, acceleration, a2->base_translation); + if (a1->data.data.flags & GLITTER_PARTICLE_REBOUND_PLANE + && a2->translation_prev.y > a1->data.data.rebound_plane_y + && a2->translation.y <= a1->data.data.rebound_plane_y) { + reflection_coeff = glitter_random_get_float(GPM_VAL, random, + a1->data.data.reflection_coeff_random) + a1->data.data.reflection_coeff; + a2->rebound_frame = a2->frame; + vec3_sub(a2->translation, a2->translation_prev, direction); + vec3_mult_scalar(direction, reflection_coeff * 60.0f, direction); + vec3_xor(direction, ((vec3){ 0.0f, -0.0f, 0.0f }), a2->direction); + a2->translation.y = a2->translation_prev.y; + } +} + +static void FASTCALL glitter_render_element_get_color(glitter_particle_inst* a1, + float_t* r, float_t* g, float_t* b, float_t* a) { + glitter_effect_inst* effect; + + effect = a1->data.effect; + if (!effect) { + if (!a1->data.parent) + return; + effect = a1->data.parent->data.effect; + if (!effect) + return; + } +} + +static void FASTCALL glitter_render_element_step_uv(GPM, glitter_particle_inst* a1, + glitter_render_element* a2, float_t delta_frame, glitter_random* random) { + if (a1->data.data.frame_step_uv <= 0.0f) + return; + + int32_t max_uv = a1->data.data.split_u * a1->data.data.split_v; + if (max_uv) + max_uv--; + + while (a2->frame_step_uv <= 0.0f) { + switch (a1->data.data.uv_index_type) { + case GLITTER_UV_INDEX_RANDOM: + a2->uv_index = a1->data.data.uv_index_start; + if (a1->data.data.uv_index_count > 1) + a2->uv_index += glitter_random_get_int(GPM_VAL, random, a1->data.data.uv_index_count); + break; + case GLITTER_UV_INDEX_FORWARD: + case GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD: + a2->uv_index = (uint8_t)(max_uv & (a2->uv_index + 1)); + break; + case GLITTER_UV_INDEX_REVERSE: + case GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE: + a2->uv_index = (uint8_t)(max_uv & (a2->uv_index - 1)); + break; + } + + a2->uv.x = (float_t)(a2->uv_index % a1->data.data.split_u) * a1->data.data.split_uv.x; + a2->uv.y = (float_t)(a2->uv_index / a1->data.data.split_u) * a1->data.data.split_uv.y; + a2->frame_step_uv += a1->data.data.frame_step_uv; + } + a2->frame_step_uv -= delta_frame; +} diff --git a/src/CRE/Glitter/render_element.h b/src/CRE/Glitter/render_element.h new file mode 100644 index 00000000..dc0b6b24 --- /dev/null +++ b/src/CRE/Glitter/render_element.h @@ -0,0 +1,23 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "glitter.h" + +extern void FASTCALL glitter_render_element_emit(GPM, + glitter_particle_inst* a1, glitter_render_element* a2, glitter_emitter_inst* a3, + glitter_particle_inst_data* a4, int32_t index, uint8_t step, glitter_random* random); +extern void FASTCALL glitter_render_element_free(glitter_render_element* a1); +extern void FASTCALL glitter_render_element_get_value(GPM, glitter_render_group* a1, + glitter_render_element* a2, float_t delta_frame); +extern void FASTCALL glitter_render_element_rotate_to_position(mat3* mat, + glitter_render_group* a2, glitter_render_element* a3); +extern void FASTCALL glitter_render_element_rotate_to_prev_position(mat3* mat, + glitter_render_group* a2, glitter_render_element* a3); +extern void FASTCALL glitter_render_element_x_rotate_to_position(mat3* mat, + glitter_render_group* a2, glitter_render_element* a3, vec3* pos, vec3* direction); +extern void FASTCALL glitter_render_element_x_rotate_to_prev_position(mat3* mat, + glitter_render_group* a2, glitter_render_element* a3, vec3* pos, vec3* direction); diff --git a/src/CRE/Glitter/render_group.c b/src/CRE/Glitter/render_group.c index 0579c21d..7e71b1c4 100644 --- a/src/CRE/Glitter/render_group.c +++ b/src/CRE/Glitter/render_group.c @@ -3,18 +3,42 @@ GitHub/GitLab: korenkonder */ -#include "render_group.h" -#include "counter.h" -#include "curve.h" #include "emitter_inst.h" -#include "locus_history.h" -#include "particle_inst.h" #include "random.h" -#include "..\shader.h" +#include "render_group.h" +#include "render_element.h" +#include "../camera.h" +#include "../shader.h" +#include "../shared.h" +#include "../static_var.h" +extern camera* cam; extern shader_fbo particle_shader; -glitter_render_group* FASTCALL glitter_render_group_init(int32_t count, glitter_particle_inst* a2) { +static glitter_render_element* FASTCALL glitter_render_group_add_render_element(glitter_render_group* a1, + glitter_render_element* a2); +static void FASTCALL glitter_render_group_calc_draw_line(GPM, glitter_render_group* a1); +static void FASTCALL glitter_render_group_calc_draw_locus(GPM, glitter_render_group* a1); +static void FASTCALL glitter_render_group_calc_draw_quad(GPM, glitter_render_group* a1); +static void FASTCALL glitter_render_group_draw_quad_normal(glitter_render_group* a1, + mat4* model_mat, mat3* direction_mat); +static void FASTCALL glitter_render_group_draw_quad_direction_rotation(glitter_render_group* a1, + mat4* model_mat, mat3* direction_mat, + void(FASTCALL* rotate_func)(mat3*, glitter_render_group*, glitter_render_element*)); +static void FASTCALL glitter_render_group_draw_set_pivot(glitter_pivot pivot, + float_t a2, float_t a3, float_t* v00, float_t* v01, float_t* v10, float_t* v11); +static bool FASTCALL glitter_render_group_get_ext_anim_scale(glitter_render_group* a1, vec3* a2); + +glitter_render_group* FASTCALL glitter_render_group_init(GPM, glitter_particle_inst* a1) { + size_t count = 0; + size_t max_count = 0; + + if (a1->data.data.count > 0) + count = a1->data.data.count; + else + count = a1->data.data.type == GLITTER_PARTICLE_LOCUS ? 30 : 250; + max_count = count * 4; + glitter_render_group* rg = force_malloc(sizeof(glitter_render_group)); rg->split_u = 1; rg->split_v = 1; @@ -22,52 +46,397 @@ glitter_render_group* FASTCALL glitter_render_group_init(int32_t count, glitter_ rg->count = count; rg->mat = mat4_identity; rg->mat_no_scale = mat4_identity; - rg->max_count = 6 * count; - rg->particle_inst = a2; + rg->mat_draw = mat4_identity; + rg->max_count = max_count; + rg->particle = a1; rg->alpha = 1; rg->emission = 1.0f; rg->blend_mode0 = GLITTER_PARTICLE_BLEND_TYPICAL; rg->blend_mode1 = GLITTER_PARTICLE_BLEND_TYPICAL; + rg->random_ptr = a1->data.random_ptr; + rg->buffer = 0; + rg->vao = 0; + rg->vbo = 0; + rg->ebo = 0; + rg->vec_key = (vector_int32_t){ 0, 0, 0 }; + rg->vec_val = (vector_int32_t){ 0, 0, 0 }; - rg->sub = force_malloc_s(sizeof(glitter_render_group_sub), count); - if (rg->particle_inst && rg->sub && rg->max_count > 0) { - rg->buffer = force_malloc(sizeof(glitter_buffer) * rg->max_count); - if (!rg->buffer) - rg->max_count = 0; - - glGenBuffers(1, &rg->buffer_index); - glGenVertexArrays(1, &rg->vao); - if (rg->buffer_index && rg->vao) { - glBindBuffer(GL_ARRAY_BUFFER, rg->buffer_index); - glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(sizeof(glitter_buffer) * rg->max_count), - rg->buffer, GL_DYNAMIC_DRAW); - glBindVertexArray(rg->vao); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(glitter_buffer), (void*)0x00); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(glitter_buffer), (void*)0x0C); - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 4, GL_FLOAT, false, sizeof(glitter_buffer), (void*)0x14); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - } - else { + rg->elements = force_malloc_s(glitter_render_element, rg->count); + if (!rg->elements) { rg->count = 0; rg->max_count = 0; + return rg; } + else if (!rg->max_count) + return rg; + + bool is_quad = a1->data.data.type == GLITTER_PARTICLE_QUAD; + + rg->buffer = force_malloc_s(glitter_buffer, rg->max_count); + if (!rg->buffer) + rg->max_count = 0; + + glGenVertexArrays(1, &rg->vao); + glGenBuffers(1, &rg->vbo); + + if (is_quad) { + size_t count = rg->max_count / 4 * 6; + int32_t* ebo_data = force_malloc_s(int32_t, count); + for (size_t i = 0, j = 0; i < count; i += 6, j += 4) { + ebo_data[i] = (int32_t)j; + ebo_data[i + 1] = (int32_t)(j + 1); + ebo_data[i + 2] = (int32_t)(j + 2); + ebo_data[i + 3] = (int32_t)(j + 0); + ebo_data[i + 4] = (int32_t)(j + 2); + ebo_data[i + 5] = (int32_t)(j + 3); + } + glGenBuffers(1, &rg->ebo); + bind_element_array_buffer(rg->ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int32_t) * count, ebo_data, GL_STATIC_DRAW); + bind_element_array_buffer(0); + free(ebo_data); + } + + static const GLsizei buffer_size = sizeof(glitter_buffer); + + bind_vertex_array(rg->vao); + bind_array_buffer(rg->vbo); + if (is_quad) + bind_element_array_buffer(rg->ebo); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(glitter_buffer, position)); // Pos + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(glitter_buffer, uv)); // UV + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(glitter_buffer, color)); // Color + bind_vertex_array(0); + bind_array_buffer(0); + if (is_quad) + bind_element_array_buffer(0); + + vector_int32_t_append(&rg->vec_key, rg->count); + vector_int32_t_append(&rg->vec_val, rg->count); + rg->update_data = true; return rg; } -glitter_render_group_sub* FASTCALL glitter_render_group_add_control(glitter_render_group* a1, - glitter_render_group_sub* a2) { - int64_t v3; - int64_t v4; +void FASTCALL glitter_render_group_calc_draw(GPM, glitter_render_group* a1, + bool(FASTCALL* render_add_list_func)(glitter_particle_mesh*, vec4*, mat4*, mat4*)) { + switch (a1->type) { + case GLITTER_PARTICLE_QUAD: + case GLITTER_PARTICLE_LINE: + case GLITTER_PARTICLE_LOCUS: + if (!a1->update_data && !cam->updated) + return; + break; + default: + a1->update_data = false; + return; + } + + a1->update_data = false; + a1->disp = 0; + switch (a1->type) { + case GLITTER_PARTICLE_QUAD: + glitter_render_group_calc_draw_quad(GPM_VAL, a1); + break; + case GLITTER_PARTICLE_LINE: + glitter_render_group_calc_draw_line(GPM_VAL, a1); + break; + case GLITTER_PARTICLE_LOCUS: + glitter_render_group_calc_draw_locus(GPM_VAL, a1); + break; + } +} + +bool FASTCALL glitter_render_group_cannot_draw(glitter_render_group* a1) { + glitter_effect_inst* effect; + glitter_particle_inst* particle; + + if (!(particle = a1->particle)) + return true; + else if (particle->data.effect) + return (particle->data.effect->flags & GLITTER_EFFECT_INST_HAS_EXT_ANIM_NON_INIT) != 0; + else if ((particle = particle->data.parent) && (effect = particle->data.effect)) + return (effect->flags & GLITTER_EFFECT_INST_HAS_EXT_ANIM_NON_INIT) != 0; + else + return true; +} + +void FASTCALL glitter_render_group_delete_buffers(glitter_render_group* a1, bool a2) { + if (a1->particle) { + if (!a2) + a1->particle->data.render_group = 0; + a1->particle = 0; + } + + if (a1->ebo) { + glDeleteBuffers(1, &a1->ebo); + a1->ebo = 0; + } + + if (a1->vbo) { + glDeleteBuffers(1, &a1->vbo); + a1->vbo = 0; + } + + if (a1->vao) { + glDeleteVertexArrays(1, &a1->vao); + a1->vao = 0; + } + free(a1->buffer); + + if (!a2 && a1->elements) { + glitter_render_group_free(a1); + free(a1->elements); + } +} + +void FASTCALL glitter_render_group_draw(GPM, glitter_render_group* a1) { + int32_t glitter_shader_flags[4]; + + if (a1->disp < 1) + return; + + size_t disp = 0; + switch (a1->type) { + case GLITTER_PARTICLE_QUAD: + disp = a1->disp * 4; + break; + case GLITTER_PARTICLE_LINE: + disp = a1->disp; + break; + case GLITTER_PARTICLE_LOCUS: + disp = a1->disp * 2; + break; + default: + return; + } + + glEnablei(GL_BLEND, 0); + switch (a1->blend_mode0) { + case GLITTER_PARTICLE_BLEND_ADD: + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); + break; + case GLITTER_PARTICLE_BLEND_MULTIPLY: + glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); + break; + default: + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + break; + } + glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); + + float_t emission; + if (a1->flags & GLITTER_PARTICLE_EMISSION || a1->blend_mode0 == GLITTER_PARTICLE_BLEND_TYPICAL) + emission = a1->emission; + else + emission = 1.0f; + + if (a1->type != GLITTER_PARTICLE_LINE && a1->texture0) { + bind_index_tex2d(0, a1->texture0); + if (a1->texture1) { + bind_index_tex2d(1, a1->texture1); + + glitter_shader_flags[0] = 2; + switch (a1->blend_mode1) { + default: + glitter_shader_flags[1] = 0; + break; + case GLITTER_PARTICLE_BLEND_MULTIPLY: + glitter_shader_flags[1] = 1; + break; + case GLITTER_PARTICLE_BLEND_ADD: + glitter_shader_flags[1] = 2; + break; + } + } + else { + bind_index_tex2d(1, 0); + glitter_shader_flags[0] = 1; + glitter_shader_flags[1] = 0; + } + } + else { + bind_index_tex2d(0, 0); + bind_index_tex2d(1, 0); + glitter_shader_flags[0] = 0; + glitter_shader_flags[1] = 0; + } + + switch (a1->type) { + case GLITTER_PARTICLE_QUAD: + switch (a1->fog) { + default: + glitter_shader_flags[2] = 0; + break; + case 1: + glitter_shader_flags[2] = 1; + break; + case 2: + glitter_shader_flags[2] = 2; + break; + } + + if (a1->blend_mode0 == GLITTER_PARTICLE_BLEND_PUNCH_THROUGH) { + glitter_shader_flags[3] = 1; + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(true); + } + else { + glitter_shader_flags[3] = a1->alpha ? 2 : 0; + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(false); + } + glEnablei(GL_BLEND, 0); + + if (a1->draw_type == GLITTER_DIRECTION_BILLBOARD) { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + } + else + glDisable(GL_CULL_FACE); + break; + case GLITTER_PARTICLE_LINE: + glitter_shader_flags[2] = 0; + glitter_shader_flags[3] = 2; + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(false); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + break; + case GLITTER_PARTICLE_LOCUS: + glitter_shader_flags[2] = 0; + glitter_shader_flags[3] = 2; + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(false); + glDisable(GL_CULL_FACE); + break; + } + + shader_fbo_use(&particle_shader); + shader_fbo_set_int_array(&particle_shader, "mode", 4, glitter_shader_flags); + shader_fbo_set_float(&particle_shader, "emission", emission); + shader_fbo_set_mat4(&particle_shader, "model", false, &a1->mat_draw); + + bind_array_buffer(a1->vbo); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(sizeof(glitter_buffer) * disp), a1->buffer, GL_DYNAMIC_DRAW); + bind_array_buffer(0); + + bind_vertex_array(a1->vao); + switch (a1->type) { + case GLITTER_PARTICLE_QUAD: + glDrawElements(GL_TRIANGLES, (GLsizei)(6 * a1->disp), GL_UNSIGNED_INT, 0); + break; + case GLITTER_PARTICLE_LINE: + case GLITTER_PARTICLE_LOCUS: { + GLenum mode = a1->type == GLITTER_PARTICLE_LINE ? GL_LINE_STRIP : GL_TRIANGLE_STRIP; + size_t count = a1->vec_key.end - a1->vec_key.begin; + for (size_t i = 0; i < count; i++) + glDrawArrays(mode, a1->vec_key.begin[i], a1->vec_val.begin[i]); + } break; + } + bind_vertex_array(0); + glDisablei(GL_BLEND, 0); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + shader_fbo_use(0); +} + +void FASTCALL glitter_render_group_emit(GPM, glitter_render_group* a1, + glitter_particle_inst_data* a2, glitter_emitter_inst* a3, int32_t a4, int32_t count) { + glitter_render_element* element; + int64_t i; + int32_t index; + + glitter_random_set_step(a1->random_ptr, 1); + for (element = 0, i = a4; i > 0; i--) + for (index = 0; index < count; index++, element++) { + element = glitter_render_group_add_render_element(a1, element); + if (!element) + break; + + glitter_render_element_emit(GPM_VAL, a1->particle, element, a3, a2, index, 1, a1->random_ptr); + } +} + +void FASTCALL glitter_render_group_free(glitter_render_group* a1) { + glitter_render_element* sub; + size_t i; + + sub = a1->elements; + for (i = 0; i < a1->count; i++, sub++) + glitter_render_element_free(sub); + a1->ctrl = 0; +} + +void FASTCALL glitter_render_group_get_value(GPM, + glitter_render_group* render_group, float_t delta_frame, bool copy_mats) { + glitter_particle_inst* particle_inst; + glitter_particle_inst_data* data; + glitter_emitter_inst* emitter; + size_t ctrl; + size_t i; + + if (!render_group->particle) + return; + + particle_inst = render_group->particle; + data = &particle_inst->data; + render_group->blend_mode0 = data->data.blend_mode0; + render_group->blend_mode1 = data->data.blend_mode1; + render_group->texture0 = data->data.texture0; + render_group->texture1 = data->data.texture1; + render_group->split_u = data->data.split_u; + render_group->split_v = data->data.split_v; + render_group->split_uv = data->data.split_uv; + render_group->type = data->data.type; + render_group->draw_type = data->data.draw_type; + render_group->z_offset = data->data.z_offset; + render_group->pivot = data->data.pivot; + render_group->flags = data->data.flags; + + if (copy_mats && (emitter = particle_inst->data.emitter)) { + render_group->mat = emitter->mat; + render_group->mat_no_scale = emitter->mat_no_scale; + } + + for (ctrl = render_group->ctrl, i = 0; ctrl > 0; i++) { + if (!render_group->elements[i].alive) + continue; + + glitter_render_element_get_value(GPM_VAL, render_group, &render_group->elements[i], delta_frame); + ctrl--; + } + render_group->frame += delta_frame; + render_group->update_data |= delta_frame != 0.0f; +} + +void FASTCALL glitter_render_group_dispose(glitter_render_group* rg) { + vector_int32_t_free(&rg->vec_key); + vector_int32_t_free(&rg->vec_val); + glitter_render_group_delete_buffers(rg, false); + free(rg); +} + +static glitter_render_element* FASTCALL glitter_render_group_add_render_element(glitter_render_group* a1, + glitter_render_element* a2) { + size_t v3; + size_t v4; if (!a2) - a2 = a1->sub; + a2 = a1->elements; - v3 = a1->count - (a2 - a1->sub); + v3 = a1->count - (a2 - a1->elements); v4 = 0; if (v3 <= 0) return 0; @@ -84,1179 +453,687 @@ glitter_render_group_sub* FASTCALL glitter_render_group_add_control(glitter_rend return a2; } -void FASTCALL glitter_render_group_copy(glitter_render_group* a1, glitter_render_group* a2) { - a2->flags = a1->flags; - a2->type = a1->type; - a2->draw_type = a1->draw_type; - a2->blend_mode0 = a1->blend_mode0; - a2->blend_mode1 = a1->blend_mode1; - a2->pivot = a1->pivot; - a2->split_u = a1->split_u; - a2->split_v = a1->split_v; - a2->split_uv = a1->split_uv; - a2->z_offset = a1->z_offset; - a2->count = min(a2->count, a1->count); - a2->ctrl = a1->ctrl; - a2->texture0 = a1->texture0; - a2->texture1 = a1->texture1; - a2->frame = a1->frame; - a2->mat = a1->mat; - a2->mat_no_scale = a1->mat_no_scale; - a2->has_texture1 = a1->has_texture1; - if (a2->count == a1->count) { - memmove(a2->sub, a1->sub, sizeof(glitter_render_group_sub) * a2->count); - a2->ctrl = a1->ctrl; - } -} - -void FASTCALL glitter_render_group_copy_from_particle(glitter_render_group* render_group, - float_t delta_frame, bool copy_mats) { - glitter_particle_inst* particle_inst; // rax - glitter_particle_inst_data* sub; - int32_t ctrl; // esi - int32_t i; - - if (!render_group->particle_inst) - return; - - particle_inst = render_group->particle_inst; - sub = &particle_inst->sub; - render_group->blend_mode0 = sub->data.blend_mode0; - render_group->blend_mode1 = sub->data.blend_mode1; - render_group->texture0 = sub->data.texture0; - render_group->texture1 = sub->data.texture1; - render_group->split_u = sub->data.split_u; - render_group->split_v = sub->data.split_v; - render_group->split_uv = sub->data.split_uv; - render_group->type = sub->data.type; - render_group->draw_type = sub->data.draw_type; - render_group->z_offset = sub->data.z_offset; - render_group->pivot = sub->data.pivot; - render_group->flags = sub->data.flags; - - //memcpy(render_group->dword48, sub->data.dword138, 32); - if (copy_mats) { - render_group->mat = particle_inst->mat; - render_group->mat_no_scale = particle_inst->mat_no_scale; - } - - render_group->has_texture1 = sub->data.texture1 != 0; - for (ctrl = render_group->ctrl, i = 0; ctrl > 0; i++) { - if (!render_group->sub[i].alive) - continue; - - glitter_render_group_sub_get_value(render_group, &render_group->sub[i], delta_frame); - ctrl--; - } - render_group->frame += delta_frame; -} - -void FASTCALL glitter_render_group_delete_buffers(glitter_render_group* a1, bool a2) { - if (a1->particle_inst) { - if (!a2) - a1->particle_inst->sub.render_group = 0; - a1->particle_inst = 0; - } - - if (a1->buffer_index) { - glDeleteBuffers(1, &a1->buffer_index); - a1->buffer_index = 0; - } - - if (a1->vao) { - glDeleteVertexArrays(1, &a1->vao); - a1->vao = 0; - } - free(a1->buffer); - - if (!a2 && a1->sub) { - glitter_render_group_free(a1); - free(a1->sub); - } -} - -void FASTCALL glitter_render_group_draw(glitter_scene_sub* a1, glitter_render_group* a2) { - switch (a2->type) { - case GLITTER_PARTICLE_QUAD: - glitter_render_group_draw_quad(a1, a2); - break; - case GLITTER_PARTICLE_LINE: - glitter_render_group_draw_line(a1, a2); - break; - case GLITTER_PARTICLE_LOCUS: - glitter_render_group_draw_locus(a1, a2); - break; - } -} - -void FASTCALL glitter_render_group_draw_line(glitter_scene_sub* a1, glitter_render_group* a2) { - int64_t v4; // er14 - int32_t v6; // edi - int32_t v7; // esi - glitter_render_group_sub* v8; // rbx - vec3 v14; // xmm8_4 - vec3 v15; - vec3 v16; - bool v17; - bool v18; - bool v19; - bool v20; - glitter_buffer* v23; // rbx - int32_t v24; // esi - int32_t v25; // eax - glitter_render_group_sub* v27; // r15 - glitter_locus_history* v30; // r12 - glitter_locus_history_data* v32; // rdx - int32_t v42; // ecx - float_t emission; // [rsp+20h] [rbp-28h] BYREF - mat4 mat; - vector_int32_t vec_key; - vector_int32_t vec_val; - - if (!a2->sub || !a2->buffer || a2->ctrl <= 0) - return; - - v4 = 0; - v6 = a2->ctrl; - v7 = 0; - v8 = a2->sub; - while (v7 < v6) { - if (v8->alive) { - if (v8->locus_history) { - int64_t length = v8->locus_history->data.end - v8->locus_history->data.begin; - if (length > 1) - v4 += length; - } - v6--; - } - v7++; - v8++; - } - - if (!v4 || v4 > a2->max_count) - return; - - glEnablei(GL_BLEND, 0); - switch (a2->blend_mode0) { - case GLITTER_PARTICLE_BLEND_ADD: - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - break; - case GLITTER_PARTICLE_BLEND_MULTIPLY: - glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); - break; - default: - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - break; - } - glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - - if (a2->flags & GLITTER_PARTICLE_FLAG_EMISSION || a2->blend_mode0 == GLITTER_PARTICLE_BLEND_TYPICAL) - emission = a2->emission; - else - emission = 1.0f; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, 0); - glitter_shader_flags[0] = 0; - glitter_shader_flags[1] = 0; - glitter_shader_flags[2] = 0; - glitter_shader_flags[3] = 2; - - glEnable(GL_DEPTH_TEST); - glDepthMask(false); - - shader_fbo_use(&particle_shader); - shader_fbo_set_int_array(&particle_shader, "mode", 4, glitter_shader_flags); - shader_fbo_set_float(&particle_shader, "emission", emission);; - glEnable(GL_CULL_FACE); - - mat = mat4_identity; - v14 = vec3_null; - v17 = false; - v18 = false; - v19 = false; - if (a2->flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) { - vec4_length(a2->mat.row0, v14.x); - vec4_length(a2->mat.row1, v14.y); - vec4_length(a2->mat.row2, v14.z); - vec3_sub(v14, ((vec3) { 1.0f, 1.0f, 1.0f }), v14); - v17 = fabsf(v14.x) > 0.000001f ? true : false; - v18 = fabsf(v14.y) > 0.000001f ? true : false; - v19 = fabsf(v14.z) > 0.000001f ? true : false; - mat4_normalize_rotation(&a2->mat, &mat); - } - shader_fbo_set_mat4(&particle_shader, "model", false, &mat); - v20 = v17 | v18 | v19; - - glBindBuffer(GL_ARRAY_BUFFER, a2->buffer_index); - v23 = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - - vec_key.begin = vec_key.end = vec_key.capacity_end = 0; - vec_val.begin = vec_val.end = vec_val.capacity_end = 0; - vector_int32_t_resize(&vec_key, 0x80); - vector_int32_t_resize(&vec_val, 0x80); - if (a2->ctrl > 0) { - v24 = 0; - v42 = 0; - v25 = a2->ctrl; - v27 = a2->sub; - while (v25 > 0) { - if (!v27->alive) { - v27++; - continue; - } - - v30 = v27->locus_history; - if (v30->data.end - v30->data.begin < 2) { - v25--; - v27++; - } - - for (v32 = v30->data.begin; v30->data.end != v32; v32++, v23++, v24++) { - v15 = v32->translation; - if (v20) { - vec3_sub(v15, v27->base_translation, v16); - vec3_mult(v16, v14, v16); - if (!v17) - v16.x = 0.0f; - if (!v18) - v16.y = 0.0f; - if (!v19) - v16.z = 0.0f; - vec3_add(v15, v16, v15); - } - v23->position = v15; - v23->uv = vec2_null; - v23->color = v32->color; - } - - vector_int32_t_push_back(&vec_key, &v42); - v42 = v24 - v42; - vector_int32_t_push_back(&vec_val, &v42); - v42 = v24; - - v25--; - v27++; - } - } - glUnmapBuffer(GL_ARRAY_BUFFER); - - glBindVertexArray(a2->vao); - if (v24 > 0) { - a1->disp_line += v24; - glMultiDrawArrays(GL_LINE_STRIP, vec_key.begin, vec_val.begin, (GLsizei)(vec_key.end - vec_key.begin)); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glDisablei(GL_BLEND, 0); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_ALPHA_TEST); - free(vec_key.begin); - free(vec_val.begin); -} - -void FASTCALL glitter_render_group_draw_locus(glitter_scene_sub* a1, glitter_render_group* a2) { - int64_t v4; // r14 - int32_t v6; // edi - int32_t v7; // esi - glitter_render_group_sub* v8; // rbx - vec3 v16; // xmm13_4 - bool v22; - bool v23; - bool v24; - bool v25; - int32_t v28; // er12 - int32_t v29; // ecx - glitter_render_group_sub* v32; // r14 - glitter_locus_history* v33; // rax - float_t v35; // xmm12_4 - float_t v36; // xmm9_4 - float_t v37; // xmm10_4 - float_t v38; // xmm11_4 - glitter_buffer* v41; // rsi - vec3 v43; // xmm6_4 - float_t emission; // [rsp+20h] [rbp-28h] BYREF - vec3 v73; // [rsp+58h] [rbp-A8h] - uint32_t v78; // [rsp+98h] [rbp-68h] - float_t v10; // [rsp+B0h] [rbp-50h] FORCED - float_t v11; // [rsp+C0h] [rbp-40h] BYREF - float_t v00; // [rsp+C8h] [rbp-38h] BYREF - float_t v01; // [rsp+CCh] [rbp-34h] BYREF +static void FASTCALL glitter_render_group_calc_draw_line(GPM, glitter_render_group* a1) { + size_t count; + size_t i; + size_t j; vec3 scale; - glitter_locus_history_data* v95; // [rsp+128h] [rbp+28h] BYREF - mat4 mat2; // [rsp+130h] [rbp+30h] BYREF - mat4 mat3; // [rsp+170h] [rbp+70h] BYREF - mat4 mat1; // [rsp+1B0h] [rbp+B0h] BYREF - vector_int32_t vec_key; - vector_int32_t vec_val; + vec3 pos; + vec3 pos_diff; + bool has_scale_x; + bool has_scale_y; + bool has_scale_z; + bool has_scale; + glitter_buffer* buf; + size_t disp; + glitter_render_element* elem; + glitter_locus_history* hist; + glitter_locus_history_data* hist_data; + size_t index; + uint32_t temp; - if (!a2->sub || a2->ctrl <= 0) + if (!a1->elements || !a1->buffer || a1->ctrl <= 0) return; - for (v4 = 0, v6 = a2->ctrl, v7 = 0, v8 = a2->sub; v7 < v6; v7++, v8++) { - if (!v8->alive) + for (count = 0, i = a1->ctrl, j = 0, elem = a1->elements; j < i; j++, elem++) { + if (!elem->alive) continue; - if (v8->locus_history) { - int64_t length = v8->locus_history->data.end - v8->locus_history->data.begin; + if (elem->locus_history) { + size_t length = elem->locus_history->data.end - elem->locus_history->data.begin; if (length > 1) - v4 += 2 * length; + count += length; } - v6--; + i--; } - if (!v4 || v4 > a2->max_count || !a2->buffer) + if (!count || count > a1->max_count) return; - glEnablei(GL_BLEND, 0); - switch (a2->blend_mode0) { - case GLITTER_PARTICLE_BLEND_ADD: - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - break; - case GLITTER_PARTICLE_BLEND_MULTIPLY: - glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); - break; - default: - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - break; + scale = vec3_null; + has_scale_x = false; + has_scale_y = false; + has_scale_z = false; + if (a1->flags & GLITTER_PARTICLE_EMITTER_LOCAL) { + mat4_get_scale(&a1->mat, &scale); + vec3_sub(scale, vec3_identity, scale); + if (!(has_scale_x = fabsf(scale.x) > 0.000001f ? true : false)) + scale.x = 0.0f; + if (!(has_scale_y = fabsf(scale.y) > 0.000001f ? true : false)) + scale.y = 0.0f; + if (!(has_scale_z = fabsf(scale.z) > 0.000001f ? true : false)) + scale.z = 0.0f; + mat4_normalize_rotation(&a1->mat, &a1->mat_draw); } - glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - - if (a2->flags & GLITTER_PARTICLE_FLAG_EMISSION || a2->blend_mode0 == GLITTER_PARTICLE_BLEND_TYPICAL) - emission = a2->emission; else - emission = 1.0f; - - glActiveTexture(GL_TEXTURE0); - if (a2->texture0) { - glBindTexture(GL_TEXTURE_2D, a2->texture0); - glActiveTexture(GL_TEXTURE1); - if (a2->texture1) { - glBindTexture(GL_TEXTURE_2D, a2->texture1); + a1->mat_draw = mat4_identity; - switch (a2->blend_mode1) { - case 2: - glitter_shader_flags[0] = 2; - glitter_shader_flags[1] = 2; - break; - case 3: - default: - glitter_shader_flags[0] = 2; - glitter_shader_flags[1] = 0; - break; - case 4: - glitter_shader_flags[0] = 2; - glitter_shader_flags[1] = 1; - break; - } - } - else { - glBindTexture(GL_TEXTURE_2D, 0); - glitter_shader_flags[0] = 1; - glitter_shader_flags[1] = 0; - } - } - else { - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, 0); - glitter_shader_flags[0] = 0; - glitter_shader_flags[1] = 0; - } + has_scale = has_scale_x || has_scale_y || has_scale_z; - glitter_shader_flags[2] = 0; - glitter_shader_flags[3] = 2; - - glEnable(GL_DEPTH_TEST); - glDepthMask(false); - - shader_fbo_use(&particle_shader); - shader_fbo_set_int_array(&particle_shader, "mode", 4, glitter_shader_flags); - shader_fbo_set_float(&particle_shader, "emission", emission);; - v16 = vec3_null; - scale = (vec3){ 1.0f, 0.0f, 0.0f }; - mat1 = cam->view; - if (a2->flags & GLITTER_PARTICLE_FLAG_LOCAL) { - mat4_inverse(&mat1, &mat2); - mat4_mult(&mat2, &a2->mat, &mat2); - mat4_mult(&mat1, &mat2, &mat1); - } - mat4_inverse(&cam->view, &mat2); - mat4_mult(&mat1, &mat2, &mat2); - shader_fbo_set_mat4(&particle_shader, "model", false, &mat2); - - mat2 = mat4_identity; - v73 = vec3_null; - v22 = false; - v23 = false; - v24 = false; - if (a2->flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) { - vec4_length(a2->mat.row0, v16.x); - vec4_length(a2->mat.row1, v16.y); - vec4_length(a2->mat.row2, v16.z); - if (a2->flags & GLITTER_PARTICLE_FLAG_SCALE) - scale.x = v16.x; - vec3_sub(v16, ((vec3) { 1.0f, 1.0f, 1.0f }), v16); - mat4_mult_vec3(&a2->mat_no_scale, &v16, &v16); - v22 = fabsf(v16.x) > 0.000001f ? true : false; - v23 = fabsf(v16.y) > 0.000001f ? true : false; - v24 = fabsf(v16.z) > 0.000001f ? true : false; - mat4_normalize_rotation(&a2->mat, &mat2); - } - mat3 = mat4_identity; - mat3.row3 = mat2.row3; - v25 = v22 | v23 | v24; - - mat1.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - mat4_inverse(&mat1, &mat1); - mat4_mult(&mat3, &mat1, &mat1); - mat1.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - - mat4_mult_vec3(&mat1, &scale, &scale); - - glBindBuffer(GL_ARRAY_BUFFER, a2->buffer_index); - v41 = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - - vec_key.begin = vec_key.end = vec_key.capacity_end = 0; - vec_val.begin = vec_val.end = vec_val.capacity_end = 0; - vector_int32_t_resize(&vec_key, 0x80); - vector_int32_t_resize(&vec_val, 0x80); - v78 = 0; - v00 = 0.0f; - v01 = 0.0f; - - v78 = 0; - for (v29 = a2->ctrl, v32 = a2->sub; v29 > 0; v32++) { - if (!v32->alive) + buf = a1->buffer; + elem = a1->elements; + disp = 0; + vector_int32_t_clear(&a1->vec_key); + vector_int32_t_clear(&a1->vec_val); + for (i = a1->ctrl, index = 0; i > 0; elem++) { + if (!elem->alive) continue; - v29--; - v33 = v32->locus_history; - if (!v33 || v33->data.end - v33->data.begin <= 1) + i--; + hist = elem->locus_history; + if (!elem->draw || !hist || hist->data.end - hist->data.begin < 2) continue; - v35 = v32->uv.x + v32->uv_scroll.x; - v36 = v32->uv.x + a2->split_uv.x + v32->uv_scroll.x; - v37 = v32->uv.y + a2->split_uv.y + v32->uv_scroll.y; - v38 = a2->split_uv.y / (float_t)(v33->data.end - v33->data.begin - 1); - - for (v28 = 0, v95 = v33->data.begin; v95 != v33->data.end; v28++, v41 += 2, v95++) { - v43 = v95->translation; - if (v25) { - vec3_sub(v43, v32->base_translation, v73); - vec3_mult(v73, v16, v73); - if (!v22) - v73.x = 0.0f; - if (!v23) - v73.y = 0.0f; - if (!v24) - v73.z = 0.0f; - mat4_mult_vec3(&mat2, &v73, &v73); - vec3_add(v43, v73, v43); + if (has_scale) + for (j = 0, hist_data = hist->data.begin; hist_data != hist->data.end; j++, buf++, hist_data++) { + pos = hist_data->translation; + vec3_sub(pos, elem->base_translation, pos_diff); + vec3_mult(pos_diff, scale, pos_diff); + vec3_add(pos, pos_diff, buf->position); + buf->uv = vec2_null; + buf->color = *(vec3*)&hist_data->color; + buf->alpha = hist_data->color.w; + } + else + for (j = 0, hist_data = hist->data.begin; hist_data != hist->data.end; j++, buf++, hist_data++) { + buf->position = hist_data->translation; + buf->uv = vec2_null; + buf->color = *(vec3*)&hist_data->color; + buf->alpha = hist_data->color.w; } - glitter_render_group_draw_set_pivot(a2->pivot, - v95->scale * v32->scale.x * v32->scale_all, - v32->scale.y * v32->scale_particle.y * v32->scale_all, + if (j > 0) { + disp += j; + temp = (uint32_t)index; + vector_int32_t_push_back(&a1->vec_key, &temp); + temp = (uint32_t)j; + vector_int32_t_push_back(&a1->vec_val, &temp); + index += j; + } + } + a1->disp = disp; +} + +static void FASTCALL glitter_render_group_calc_draw_locus(GPM, glitter_render_group* a1) { + size_t i; + size_t j; + size_t count; + vec3 scale; + bool has_scale_x; + bool has_scale_y; + bool has_scale_z; + bool has_scale; + glitter_render_element* elem; + glitter_locus_history* hist; + float_t uv_u; + float_t uv_u_2nd; + float_t uv_v_2nd; + float_t uv_v_scale; + glitter_buffer* buf; + size_t disp; + vec3 pos; + vec3 pos_diff; + size_t index; + uint32_t temp; + float_t v00; + float_t v01; + float_t v10; + float_t v11; + vec3 x_vec; + glitter_locus_history_data* hist_data; + mat4 mat; + mat3 model_mat; + + if (!a1->elements || !a1->buffer || a1->ctrl <= 0) + return; + + for (count = 0, i = a1->ctrl, j = 0, elem = a1->elements; j < i; j++, elem++) { + if (!elem->alive) + continue; + + if (elem->locus_history) { + size_t length = elem->locus_history->data.end - elem->locus_history->data.begin; + if (length > 1) + count += 2 * length; + } + i--; + } + + if (!count || count > a1->max_count) + return; + + scale = vec3_null; + x_vec = (vec3){ 1.0f, 0.0f, 0.0f }; + if (a1->flags & GLITTER_PARTICLE_LOCAL) { + mat4_mult(&cam->inv_view, &a1->mat, &mat); + mat4_mult(&cam->view, &mat, &mat); + mat4_mult(&mat, &cam->inv_view, &a1->mat_draw); + } + else + a1->mat_draw = mat4_identity; + + has_scale_x = false; + has_scale_y = false; + has_scale_z = false; + if (a1->flags & GLITTER_PARTICLE_EMITTER_LOCAL) { + mat4_get_scale(&a1->mat, &scale); + if (a1->flags & GLITTER_PARTICLE_SCALE) + x_vec.x = scale.x; + vec3_sub(scale, vec3_identity, scale); + if (!(has_scale_x = fabsf(scale.x) > 0.000001f ? true : false)) + scale.x = 0.0f; + if (!(has_scale_y = fabsf(scale.y) > 0.000001f ? true : false)) + scale.y = 0.0f; + if (!(has_scale_z = fabsf(scale.z) > 0.000001f ? true : false)) + scale.z = 0.0f; + mat4_mult_vec3(&a1->mat_no_scale, &scale, &scale); + mat4_normalize_rotation(&a1->mat, &mat); + mat3_from_mat4(&mat, &model_mat); + } + else + model_mat = mat3_identity; + + has_scale = has_scale_x || has_scale_y || has_scale_z; + + mat3_mult_vec(&cam->inv_view_mat3, &x_vec, &x_vec); + + buf = a1->buffer; + elem = a1->elements; + disp = 0; + vector_int32_t_clear(&a1->vec_key); + vector_int32_t_clear(&a1->vec_val); + for (i = a1->ctrl, index = 0; i > 0; elem++) { + if (!elem->alive) + continue; + + i--; + hist = elem->locus_history; + if (!elem->draw || !hist || hist->data.end - hist->data.begin < 2) + continue; + + uv_u = elem->uv.x + elem->uv_scroll.x; + uv_u_2nd = elem->uv.x + elem->uv_scroll.x + a1->split_uv.x; + uv_v_2nd = elem->uv.y + elem->uv_scroll.y + a1->split_uv.y; + uv_v_scale = a1->split_uv.y / (float_t)(hist->data.end - hist->data.begin - 1); + + uv_v_2nd = 1.0f - uv_v_2nd; + + for (j = 0, hist_data = hist->data.begin; hist_data != hist->data.end; j++, buf += 2, hist_data++) { + pos = hist_data->translation; + if (has_scale) { + vec3_sub(pos, elem->base_translation, pos_diff); + vec3_mult(pos_diff, scale, pos_diff); + mat3_mult_vec(&model_mat, &pos_diff, &pos_diff); + vec3_add(pos, pos_diff, pos); + } + + glitter_render_group_draw_set_pivot(a1->pivot, + hist_data->scale * elem->scale.x * elem->scale_all, + elem->scale.y * elem->scale_particle.y * elem->scale_all, &v00, &v01, &v10, &v11); - vec3_mult_scalar(scale, v00, v41[0].position); - vec3_add(v41[0].position, v43, v41[0].position); - v41[0].uv.x = v35; - v41[0].uv.y = 1.0f - (float_t)(v37 - (double_t)v28 * v38); - v41[0].color = v95->color; + vec3_mult_scalar(x_vec, v00, buf[0].position); + vec3_add(buf[0].position, pos, buf[0].position); + buf[0].uv.x = uv_u; + buf[0].uv.y = uv_v_2nd + (float_t)j * uv_v_scale; + buf[0].color = *(vec3*)&hist_data->color; + buf[0].alpha = hist_data->color.w; - vec3_mult_scalar(scale, v01, v41[1].position); - vec3_add(v41[1].position, v43, v41[1].position); - v41[1].uv.x = v36; - v41[1].uv.y = 1.0f - (float_t)(v37 - (double_t)v28 * v38); - v41[1].color = v95->color; + vec3_mult_scalar(x_vec, v01, buf[1].position); + vec3_add(buf[1].position, pos, buf[1].position); + buf[1].uv.x = uv_u_2nd; + buf[1].uv.y = uv_v_2nd + (float_t)j * uv_v_scale; + buf[1].color = *(vec3*)&hist_data->color; + buf[1].alpha = hist_data->color.w; } - if (v28 > 0) { - a1->disp_locus += v28; - vector_int32_t_push_back(&vec_key, &v78); - v78 = 2 * v28; - vector_int32_t_push_back(&vec_val, &v78); + if (j > 0) { + disp += j; + temp = (uint32_t)index; + vector_int32_t_push_back(&a1->vec_key, &temp); + temp = (uint32_t)(j * 2); + vector_int32_t_push_back(&a1->vec_val, &temp); + index += j * 2; } } - glUnmapBuffer(GL_ARRAY_BUFFER); - - glBindVertexArray(a2->vao); - glMultiDrawArrays(GL_TRIANGLE_STRIP, vec_key.begin, vec_val.begin, (GLsizei)(vec_key.end - vec_key.begin)); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glDisablei(GL_BLEND, 0); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_ALPHA_TEST); - free(vec_key.begin); - free(vec_val.begin); + a1->disp = disp; } -void FASTCALL glitter_render_group_draw_quad(glitter_scene_sub* a1, glitter_render_group* a2) { - mat4 mat1; - mat4 mat2; - mat4 mat3; - float_t emission; +static void FASTCALL glitter_render_group_calc_draw_quad(GPM, glitter_render_group* a1) { + mat4 model_mat; + mat3 direction_mat; + mat4 view_mat; + mat4 inv_view_mat; + mat3 inv_view_mat3; - if (a2->ctrl <= 0 || a2->ctrl * 6 > a2->max_count || !a2->buffer || !a2->sub) + if (!a1->elements || !a1->buffer || a1->ctrl <= 0) return; - glEnablei(GL_BLEND, 0); - switch (a2->blend_mode0) { - case GLITTER_PARTICLE_BLEND_ADD: - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - break; - case GLITTER_PARTICLE_BLEND_MULTIPLY: - glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); - break; - default: - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - break; - } - glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - - if (a2->flags & GLITTER_PARTICLE_FLAG_EMISSION || a2->blend_mode0 == GLITTER_PARTICLE_BLEND_TYPICAL) - emission = a2->emission; - else - emission = 1.0f; - - glActiveTexture(GL_TEXTURE0); - if (a2->texture0) { - glBindTexture(GL_TEXTURE_2D, a2->texture0); - glActiveTexture(GL_TEXTURE1); - if (a2->texture1) { - glBindTexture(GL_TEXTURE_2D, a2->texture1); - - switch (a2->blend_mode1) { - case 2: - glitter_shader_flags[0] = 2; - glitter_shader_flags[1] = 2; - break; - case 3: - default: - glitter_shader_flags[0] = 2; - glitter_shader_flags[1] = 0; - break; - case 4: - glitter_shader_flags[0] = 2; - glitter_shader_flags[1] = 1; - break; - } - } - else { - glBindTexture(GL_TEXTURE_2D, 0); - glitter_shader_flags[0] = 1; - glitter_shader_flags[1] = 0; - } + if (a1->flags & GLITTER_PARTICLE_EMITTER_LOCAL) { + model_mat = a1->mat; + mat4_normalize_rotation(&a1->mat, &view_mat); + mat4_mult(&view_mat, &cam->view, &view_mat); + mat4_inverse(&view_mat, &inv_view_mat); } else { - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, 0); - glitter_shader_flags[0] = 0; - glitter_shader_flags[1] = 0; + model_mat = mat4_identity; + view_mat = cam->view; + inv_view_mat = cam->inv_view; } - switch (a2->fog) { - default: - glitter_shader_flags[2] = 0; - break; - case 1: - glitter_shader_flags[2] = 1; - break; - case 2: - glitter_shader_flags[2] = 2; - break; + if (a1->flags & GLITTER_PARTICLE_LOCAL) { + mat4_mult(&inv_view_mat, &a1->mat, &inv_view_mat); + mat4_mult(&view_mat, &inv_view_mat, &view_mat); + mat4_inverse(&view_mat, &inv_view_mat); } + mat4_mult(&view_mat, &cam->inv_view, &a1->mat_draw); - if (a2->blend_mode0 == GLITTER_PARTICLE_BLEND_PUNCH_THROUGH) { - glitter_shader_flags[3] = 1; - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_ALWAYS, 0.0f); - glEnable(GL_DEPTH_TEST); - glDepthMask(true); - } - else { - glitter_shader_flags[3] = a2->alpha ? 2 : 0; - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_ALWAYS, 0.0f); - glDisable(GL_DEPTH_TEST); - glDepthMask(false); - glEnablei(GL_BLEND, 0); - } - - shader_fbo_use(&particle_shader); - shader_fbo_set_int_array(&particle_shader, "mode", 4, glitter_shader_flags); - shader_fbo_set_float(&particle_shader, "emission", emission); - - if (a2->flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) { - mat1 = a2->mat; - mat4_normalize_rotation(&mat1, &mat2); - mat4_mult(&mat2, &cam->view, &mat2); - } - else { - mat1 = mat4_identity; - mat2 = cam->view; - } - - if (a2->flags & GLITTER_PARTICLE_FLAG_LOCAL) { - mat4_inverse(&mat2, &mat3); - mat4_mult(&mat3, &a2->mat, &mat3); - mat4_mult(&mat2, &mat3, &mat2); - } - - mat4_inverse(&cam->view, &mat3); - mat4_mult(&mat2, &mat3, &mat3); - shader_fbo_set_mat4(&particle_shader, "model", false, &mat3); - - if (a2->draw_type == GLITTER_DIRECTION_BILLBOARD) - glEnable(GL_CULL_FACE); - else - glDisable(GL_CULL_FACE); - - switch (a2->draw_type) { + direction_mat = mat3_identity; + switch (a1->draw_type) { case GLITTER_DIRECTION_BILLBOARD: - mat2.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - mat4_inverse(&mat2, &mat2); - mat4_mult(&mat1, &mat2, &mat2); - mat2.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; + mat3_from_mat4(&model_mat, &direction_mat); + mat3_from_mat4(&inv_view_mat, &inv_view_mat3); + mat3_mult(&direction_mat, &inv_view_mat3, &direction_mat); break; case GLITTER_DIRECTION_EMITTER_DIRECTION: - mat2 = a2->mat_no_scale; + mat3_from_mat4(&a1->mat_no_scale, &direction_mat); break; - case GLITTER_DIRECTION_TYPE_2_DIR_ANGLE: - case GLITTER_DIRECTION_TYPE_3_DIR_ANGLE: - case GLITTER_DIRECTION_TYPE_8_DIR_ANGLE: - if (a2->flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) { - mat2 = a2->mat_no_scale; - mat2.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - } - else - mat2 = mat4_identity; + case GLITTER_DIRECTION_PREV_POSITION: + case GLITTER_DIRECTION_POSITION: + case GLITTER_DIRECTION_PREV_POSITION_DUP: + if (a1->flags & GLITTER_PARTICLE_EMITTER_LOCAL) + mat3_from_mat4(&a1->mat_no_scale, &direction_mat); break; case GLITTER_DIRECTION_Y_AXIS: - mat4_rotate_y((float_t)-M_PI_2, &mat2); + mat3_rotate_y((float_t)-M_PI_2, &direction_mat); break; case GLITTER_DIRECTION_X_AXIS: - mat4_rotate_x((float_t)-M_PI_2, &mat2); + mat3_rotate_x((float_t)-M_PI_2, &direction_mat); break; case GLITTER_DIRECTION_Z_AXIS: - mat4_rotate_z((float_t)-M_PI_2, &mat2); + mat3_rotate_z((float_t)-M_PI_2, &direction_mat); break; case GLITTER_DIRECTION_BILLBOARD_Y_ONLY: - mat4_rotate_y(cam->rotation.y, &mat2); + mat3_rotate_y(cam->rotation.y, &direction_mat); + break; + } + + switch (a1->draw_type) { + case GLITTER_DIRECTION_PREV_POSITION: + case GLITTER_DIRECTION_PREV_POSITION_DUP: + glitter_render_group_draw_quad_direction_rotation(a1, &model_mat, &direction_mat, + glitter_render_element_rotate_to_prev_position); + break; + case GLITTER_DIRECTION_POSITION: + glitter_render_group_draw_quad_direction_rotation(a1, &model_mat, &direction_mat, + glitter_render_element_rotate_to_position); break; default: - mat2 = mat4_identity; - break; - } - - switch (a2->draw_type) { - case GLITTER_DIRECTION_TYPE_2_DIR_ANGLE: - case GLITTER_DIRECTION_TYPE_8_DIR_ANGLE: - glitter_render_group_draw_quad_sub2(a1, a2, &mat1, &mat2, glitter_render_group_draw_quad_rotate_to_prev_position); - break; - case GLITTER_DIRECTION_TYPE_3_DIR_ANGLE: - glitter_render_group_draw_quad_sub2(a1, a2, &mat1, &mat2, glitter_render_group_draw_quad_rotate_to_position); - break; - default: - glitter_render_group_draw_quad_sub1(a1, a2, &mat1, &mat2); + glitter_render_group_draw_quad_normal(a1, &model_mat, &direction_mat); break; } } -void FASTCALL glitter_render_group_draw_quads(glitter_scene_sub* a1, int32_t count) { - if (count > 0) { - a1->disp_quad += count; - glDrawArrays(GL_TRIANGLES, 0, 6 * count); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glDisablei(GL_BLEND, 0); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_ALPHA_TEST); -} - -void FASTCALL glitter_render_group_draw_quad_rotate_to_prev_position(mat4* mat, - glitter_render_group* a2, glitter_render_group_sub* a3) { - vec3 vec1; - vec3 vec2; - float_t angle; - vec3 axis; - float_t length; - - vec3_sub(a3->translation, a3->translation_prev, vec2); - vec3_length_squared(vec2, length); - if (length < 0.000001f) - vec2 = a3->translation; - - vec3_normalize(vec2, vec2); - mat4_rotate_z((float_t)M_PI, mat); - - if (fabsf(vec2.y) >= 0.000001f) { - vec1 = (vec3){ 0.0f, 1.0f, 0.0f }; - axis_angle_from_vectors(&axis, &angle, &vec1, &vec2); - mat4_mult_axis_angle(mat, mat, &axis, angle); - } -} - -void FASTCALL glitter_render_group_draw_quad_rotate_to_position(mat4* mat, - glitter_render_group* a2, glitter_render_group_sub* a3) { - vec3 vec; - vec3 vec1; - vec3 vec2; - float_t angle; - vec3 axis; - - if (a2->flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) - vec = a3->translation; - else - vec3_sub(*(vec3*)&a2->mat.row3, a3->translation, vec); - - if (fabsf(vec.y) >= 0.000001f) { - vec1 = (vec3){ 0.0f, 0.0f, 1.0f }; - *mat = mat4_identity; - vec3_normalize(vec, vec2); - axis_angle_from_vectors(&axis, &angle, &vec1, &vec2); - mat4_mult_axis_angle(mat, mat, &axis, angle); - } - else - mat4_rotate_z((float_t)M_PI, mat); -} - -void FASTCALL glitter_render_group_draw_quad_sub1(glitter_scene_sub* a1, - glitter_render_group* a2, mat4* a3, mat4* a4) { - glitter_render_group_sub* v9; // rdi - int32_t i; // er12 - int32_t count; // er15 - int32_t v33; // er14 - glitter_buffer* v34; // rbx - vec3 v35; // xmm6_4 - bool v40; - bool v41; - bool v42; - bool v43; - int32_t j; // er12 - vec3 v49; // xmm11_4 - int64_t v65; // er15 - vec2* v66; // r14 - bool use_z_offset; // [rsp+45h] [rbp-BBh] - vec3 v119; // [rsp+48h] [rbp-B8h] - vec3 scale; // [rsp+5Ch] [rbp-A4h] - vec3 v124; // [rsp+68h] [rbp-98h] BYREF - vec3 v125; // [rsp+78h] [rbp-88h] BYREF - vec3 v129; // [rsp+B4h] [rbp-4Ch] - float_t v01; // [rsp+E0h] [rbp-20h] BYREF - float_t v11; // [rsp+F8h] [rbp-8h] BYREF - float_t v10; // [rsp+FCh] [rbp-4h] BYREF - float_t v00; // [rsp+100h] [rbp+0h] BYREF - vec2 v144[8]; // [rsp+120h] [rbp+20h] BYREF - vec3 v145; // [rsp+190h] [rbp+90h] BYREF - mat4 a1a; // [rsp+200h] [rbp+100h] BYREF - mat4 mat; // [rsp+240h] [rbp+140h] BYREF - mat4 v157; // [rsp+280h] [rbp+180h] BYREF - glitter_buffer buf[4]; - vec4 color; - vec2 uv_scroll; +static void FASTCALL glitter_render_group_draw_quad_normal(glitter_render_group* a1, + mat4* model_mat, mat3* direction_mat) { + size_t i; + size_t j; + size_t j_max; + size_t k; + glitter_render_element* elem; + size_t disp; + glitter_buffer* buf; + vec3 z_offset_dir; + bool has_scale_x; + bool has_scale_y; + bool has_scale_z; + bool has_scale; + vec3 pos; + bool use_z_offset; + bool emitter_local; + vec2 base_uv; + vec3 scale; + vec3 ext_scale; + vec3 x_vec; + vec3 y_vec; + vec3 dist_to_cam; + vec3 pos_diff; + vec2 scale_particle; + float_t v00; + float_t v01; + float_t v11; + float_t v10; + vec2 pos_add[4]; + vec2 uv_add[4]; + vec3 y_vec_rot; + vec3 x_vec_rot; + mat3 inv_model_mat; + mat4 z_offset_inv_mat; + mat3 ptc_rot; float_t rot_z_cos; float_t rot_z_sin; - memset(buf, 0, sizeof(glitter_buffer) * 4); - mat4_inverse(a3, &a1a); - a1a.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - v35 = vec3_null; - v124 = (vec3){ 1.0f, 0.0f, 0.0f }; - v125 = (vec3){ 0.0f, 1.0f, 0.0f }; + mat3_from_mat4_inverse(model_mat, &inv_model_mat); + + x_vec = (vec3){ 1.0f, 0.0f, 0.0f }; + y_vec = (vec3){ 0.0f, 1.0f, 0.0f }; use_z_offset = false; - scale = vec3_null; - v129 = vec3_null; - mat = mat4_identity; - if (fabsf(a2->z_offset) > 0.000001f) { + dist_to_cam = vec3_null; + z_offset_inv_mat = mat4_identity; + if (fabsf(a1->z_offset) > 0.000001f) { use_z_offset = true; - vec3_sub(cam->position, *(vec3*)&a3->row3, v129); - if (a2->flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) { - mat4_normalize_rotation(a3, &mat); - mat4_inverse(&mat, &mat); + mat4_get_translation(model_mat, &dist_to_cam); + vec3_sub(cam->view_point, dist_to_cam, dist_to_cam); + if (a1->flags & GLITTER_PARTICLE_EMITTER_LOCAL) { + mat4_normalize_rotation(model_mat, &z_offset_inv_mat); + mat4_inverse(&z_offset_inv_mat, &z_offset_inv_mat); } } - if (a2->flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) { - vec4_length(a3->row0, v145.x); - vec4_length(a3->row1, v145.y); - vec4_length(a3->row2, v145.z); - if (a2->flags & GLITTER_PARTICLE_FLAG_SCALE) { - v124.x = v145.x; - v125.y = v145.y; + has_scale_x = false; + has_scale_y = false; + has_scale_z = false; + emitter_local = false; + scale = vec3_null; + if (a1->flags & GLITTER_PARTICLE_EMITTER_LOCAL) { + mat4_get_scale(model_mat, &scale); + if (a1->flags & GLITTER_PARTICLE_SCALE) { + x_vec.x = scale.x; + y_vec.y = scale.y; } - vec3_sub(v145, ((vec3) { 1.0f, 1.0f, 1.0f }), v145); - mat4_mult_vec3(&a2->mat_no_scale, &v145, &scale); + vec3_sub(scale, vec3_identity, scale); + if (!(has_scale_x = fabsf(scale.x) > 0.000001f ? true : false)) + scale.x = 0.0f; + if (!(has_scale_y = fabsf(scale.y) > 0.000001f ? true : false)) + scale.y = 0.0f; + if (!(has_scale_z = fabsf(scale.z) > 0.000001f ? true : false)) + scale.z = 0.0f; + mat4_mult_vec3(&a1->mat_no_scale, &scale, &scale); + emitter_local = true; } - v119 = vec3_null; - if (glitter_render_group_get_a3da_scale(a2, &v119)) { - v124.x *= v119.x + 1.0f; - v125.y *= v119.y + 1.0f; + has_scale = has_scale_x || has_scale_y || has_scale_z; + + if (glitter_render_group_get_ext_anim_scale(a1, &ext_scale)) { + vec2_add(*(vec2*)&ext_scale, vec2_identity, *(vec2*)&ext_scale); + x_vec.x *= ext_scale.x; + y_vec.y *= ext_scale.y; } - if (a2->draw_type != GLITTER_DIRECTION_BILLBOARD) { - mat4_mult_vec3(a4, &v124, &v124); - mat4_mult_vec3(a4, &v125, &v125); + if (a1->draw_type != GLITTER_DIRECTION_BILLBOARD) { + mat3_mult_vec(direction_mat, &x_vec, &x_vec); + mat3_mult_vec(direction_mat, &y_vec, &y_vec); } else - mat4_mult(&a1a, a4, &a1a); + mat3_mult(&inv_model_mat, direction_mat, &inv_model_mat); - mat4_mult_vec3(&a1a, &v124, &v124); - mat4_mult_vec3(&a1a, &v125, &v125); + mat3_mult_vec(&inv_model_mat, &x_vec, &x_vec); + mat3_mult_vec(&inv_model_mat, &y_vec, &y_vec); - glBindBuffer(GL_ARRAY_BUFFER, a2->buffer_index); - v34 = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - - v40 = fabsf(scale.x) > 0.000001f ? true : false; - v41 = fabsf(scale.y) > 0.000001f ? true : false; - v42 = fabsf(scale.z) > 0.000001f ? true : false; - v43 = v40 | v41 | v42; - - v9 = a2->sub; - count = 0; - if (a2->draw_type == GLITTER_DIRECTION_PARTICLE_ROTATION) - for (i = a2->ctrl, v33 = 1024; i > 0; i -= v33) { - v33 = min(i, v33); - for (j = v33; j > 0; v9++) { - if (!v9->alive) + buf = a1->buffer; + elem = a1->elements; + disp = 0; + if (a1->draw_type == GLITTER_DIRECTION_PARTICLE_ROTATION) + for (i = a1->ctrl, j_max = 1024; i > 0; i -= j_max) { + j_max = min(i, j_max); + for (j = j_max; j > 0; elem++) { + if (!elem->alive) continue; j--; - if (v9->color.w < 0.0099999998f) + if (!elem->draw) continue; - count++; - color = v9->color; - uv_scroll = v9->uv_scroll; - v49 = v9->translation; - if (v43) { - vec3_sub(v49, v9->base_translation, v119); - vec3_mult(v119, scale, v119); - if (!v40) - v119.x = 0.0f; - if (!v41) - v119.y = 0.0f; - if (!v42) - v119.z = 0.0f; - mat4_mult_vec3(&a1a, &v119, &v119); - vec3_add(v49, v119, v49); + vec2_mult(*(vec2*)&elem->scale, elem->scale_particle, scale_particle); + vec2_mult_scalar(scale_particle, elem->scale_all, scale_particle); + + if (fabsf(scale_particle.x) < 0.000001f || fabsf(scale_particle.y) < 0.000001f) + continue; + + pos = elem->translation; + if (has_scale) { + vec3_sub(pos, elem->base_translation, pos_diff); + vec3_mult(pos_diff, scale, pos_diff); + mat3_mult_vec(&inv_model_mat, &pos_diff, &pos_diff); + vec3_add(pos, pos_diff, pos); } - glitter_render_group_draw_set_pivot(a2->pivot, - v9->scale.x * v9->scale_particle.x * v9->scale_all, - v9->scale.y * v9->scale_particle.y * v9->scale_all, + glitter_render_group_draw_set_pivot(a1->pivot, + scale_particle.x, + scale_particle.y, &v00, &v01, &v10, &v11); - v144[0].x = v00; - v144[0].y = v11; - v144[1].x = v9->uv.x; - v144[1].y = v9->uv.y; - v144[2].x = v00; - v144[2].y = v10; - v144[3].x = v9->uv.x; - v144[3].y = v9->uv.y + a2->split_uv.y; - v144[4].x = v01; - v144[4].y = v10; - v144[5].x = v9->uv.x + a2->split_uv.x; - v144[5].y = v9->uv.y + a2->split_uv.y; - v144[6].x = v01; - v144[6].y = v11; - v144[7].x = v9->uv.x + a2->split_uv.x; - v144[7].y = v9->uv.y; + pos_add[0].x = v00; + pos_add[0].y = v11; + uv_add[0].x = 0.0f; + uv_add[0].y = 0.0f; + pos_add[1].x = v00; + pos_add[1].y = v10; + uv_add[1].x = 0.0f; + uv_add[1].y = a1->split_uv.y; + pos_add[2].x = v01; + pos_add[2].y = v10; + uv_add[2].x = a1->split_uv.x; + uv_add[2].y = a1->split_uv.y; + pos_add[3].x = v01; + pos_add[3].y = v11; + uv_add[3].x = a1->split_uv.x; + uv_add[3].y = 0.0f; + + vec2_add(elem->uv_scroll, elem->uv, base_uv); if (use_z_offset) { - vec3_sub(v129, v49, v35); - vec3_normalize(v35, v35); + vec3_sub(dist_to_cam, pos, z_offset_dir); + vec3_normalize(z_offset_dir, z_offset_dir); - if (a2->flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) - mat4_mult_vec3(&mat, &v35, &v35); + if (emitter_local) + mat4_mult_vec3(&z_offset_inv_mat, &z_offset_dir, &z_offset_dir); - vec3_mult_scalar(v35, a2->z_offset, v35); + vec3_mult_scalar(z_offset_dir, a1->z_offset, z_offset_dir); + vec3_add(pos, z_offset_dir, pos); } - v66 = v144; - mat4_rotate(v9->rotation.x, v9->rotation.y, v9->rotation.z, &v157); - for (v65 = 0; v65 < 4; v65++, v66 += 2) { - v145.x = v124.x * v66[0].x; - v145.y = v125.y * v66[0].y; - v145.z = 0.0f; - mat4_mult_vec3(&v157, &v145, &v145); - vec3_add(v145, v49, v145); - vec3_add(v145, v35, buf[v65].position); - vec2_add(v66[1], uv_scroll, buf[v65].uv); - buf[v65].color = color; + mat3_rotate(elem->rotation.x, elem->rotation.y, elem->rotation.z, &ptc_rot); + for (k = 0; k < 4; k++, buf++) { + x_vec_rot.x = x_vec.x * pos_add[k].x; + x_vec_rot.y = y_vec.y * pos_add[k].y; + x_vec_rot.z = 0.0f; + mat3_mult_vec(&ptc_rot, &x_vec_rot, &x_vec_rot); + vec3_add(x_vec_rot, pos, buf->position); + vec2_add(base_uv, uv_add[k], buf->uv); + buf->color = *(vec3*)&elem->color; + buf->alpha = elem->color.w; } - - v34[0] = buf[0]; - v34[1] = buf[1]; - v34[2] = buf[2]; - v34[3] = buf[0]; - v34[4] = buf[2]; - v34[5] = buf[3]; - v34 += 6; + disp++; } } else - for (i = a2->ctrl, v33 = 1024; i > 0; i -= v33) { - v33 = min(i, v33); - for (j = v33; j > 0; v9++) { - if (!v9->alive) + for (i = a1->ctrl, j_max = 1024; i > 0; i -= j_max) { + j_max = min(i, j_max); + for (j = j_max; j > 0; elem++) { + if (!elem->alive) continue; j--; - if (v9->color.w < 0.0099999998f) + if (!elem->draw) continue; - count++; - color = v9->color; - uv_scroll = v9->uv_scroll; - v49 = v9->translation; - if (v43) { - vec3_sub(v49, v9->base_translation, v119); - vec3_mult(v119, scale, v119); - if (!v40) - v119.x = 0.0f; - if (!v41) - v119.y = 0.0f; - if (!v42) - v119.z = 0.0f; - mat4_mult_vec3(&a1a, &v119, &v119); - vec3_add(v49, v119, v49); + vec2_mult(*(vec2*)&elem->scale, elem->scale_particle, scale_particle); + vec2_mult_scalar(scale_particle, elem->scale_all, scale_particle); + + if (fabsf(scale_particle.x) < 0.000001f || fabsf(scale_particle.y) < 0.000001f) + continue; + + pos = elem->translation; + if (has_scale) { + vec3_sub(pos, elem->base_translation, pos_diff); + vec3_mult(pos_diff, scale, pos_diff); + mat3_mult_vec(&inv_model_mat, &pos_diff, &pos_diff); + vec3_add(pos, pos_diff, pos); } - glitter_render_group_draw_set_pivot(a2->pivot, - v9->scale.x * v9->scale_particle.x * v9->scale_all, - v9->scale.y * v9->scale_particle.y * v9->scale_all, + glitter_render_group_draw_set_pivot(a1->pivot, + scale_particle.x, + scale_particle.y, &v00, &v01, &v10, &v11); - v144[0].x = v00; - v144[0].y = v11; - v144[1].x = v9->uv.x; - v144[1].y = v9->uv.y; - v144[2].x = v00; - v144[2].y = v10; - v144[3].x = v9->uv.x; - v144[3].y = v9->uv.y + a2->split_uv.y; - v144[4].x = v01; - v144[4].y = v10; - v144[5].x = v9->uv.x + a2->split_uv.x; - v144[5].y = v9->uv.y + a2->split_uv.y; - v144[6].x = v01; - v144[6].y = v11; - v144[7].x = v9->uv.x + a2->split_uv.x; - v144[7].y = v9->uv.y; + pos_add[0].x = v00; + pos_add[0].y = v11; + uv_add[0].x = 0.0f; + uv_add[0].y = 0.0f; + pos_add[1].x = v00; + pos_add[1].y = v10; + uv_add[1].x = 0.0f; + uv_add[1].y = a1->split_uv.y; + pos_add[2].x = v01; + pos_add[2].y = v10; + uv_add[2].x = a1->split_uv.x; + uv_add[2].y = a1->split_uv.y; + pos_add[3].x = v01; + pos_add[3].y = v11; + uv_add[3].x = a1->split_uv.x; + uv_add[3].y = 0.0f; + + vec2_add(elem->uv_scroll, elem->uv, base_uv); if (use_z_offset) { - vec3_sub(v129, v49, v35); - vec3_normalize(v35, v35); + vec3_sub(dist_to_cam, pos, z_offset_dir); + vec3_normalize(z_offset_dir, z_offset_dir); - if (a2->flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) - mat4_mult_vec3(&mat, &v35, &v35); + if (emitter_local) + mat4_mult_vec3(&z_offset_inv_mat, &z_offset_dir, &z_offset_dir); - vec3_mult_scalar(v35, a2->z_offset, v35); + vec3_mult_scalar(z_offset_dir, a1->z_offset, z_offset_dir); + vec3_add(pos, z_offset_dir, pos); } - v66 = v144; - rot_z_cos = v9->rot_z_cos; - rot_z_sin = v9->rot_z_sin; - for (v65 = 0; v65 < 4; v65++, v66 += 2) { - vec3_mult_scalar(v125, rot_z_sin * v66[0].x + rot_z_cos * v66[0].y, v119); - vec3_mult_scalar(v124, rot_z_cos * v66[0].x - rot_z_sin * v66[0].y, v145); - vec3_add(v145, v119, v145); - vec3_add(v145, v49, v145); - vec3_add(v145, v35, buf[v65].position); - vec2_add(v66[1], uv_scroll, buf[v65].uv); - buf[v65].color = color; + rot_z_cos = cosf(elem->rotation.z); + rot_z_sin = sinf(elem->rotation.z); + for (k = 0; k < 4; k++, buf++) { + vec3_mult_scalar(x_vec, rot_z_cos * pos_add[k].x - rot_z_sin * pos_add[k].y, x_vec_rot); + vec3_mult_scalar(y_vec, rot_z_sin * pos_add[k].x + rot_z_cos * pos_add[k].y, y_vec_rot); + vec3_add(x_vec_rot, y_vec_rot, x_vec_rot); + vec3_add(x_vec_rot, pos, buf->position); + vec2_add(base_uv, uv_add[k], buf->uv); + buf->color = *(vec3*)&elem->color; + buf->alpha = elem->color.w; } - - v34[0] = buf[0]; - v34[1] = buf[1]; - v34[2] = buf[2]; - v34[3] = buf[0]; - v34[4] = buf[2]; - v34[5] = buf[3]; - v34 += 6; + disp++; } } - glUnmapBuffer(GL_ARRAY_BUFFER); - - glBindVertexArray(a2->vao); - glitter_render_group_draw_quads(a1, count); + a1->disp = disp; } -void FASTCALL glitter_render_group_draw_quad_sub2(glitter_scene_sub* a1, glitter_render_group* a2, - mat4* a3, mat4* a4, void(FASTCALL* func)(mat4*, glitter_render_group*, glitter_render_group_sub*)) { - glitter_render_group_sub* v9; // rdi - int32_t i; // er15 - int32_t v14; // er14 - int32_t count; // esi - glitter_buffer* v16; // rbx - int32_t j; // esi - float_t rot_z_cos; // xmm8_4 - float_t rot_z_sin; // xmm9_4 - vec2* v41; // rcx - int64_t v42; // rdx - vec3 v46; // xmm4_4 - vec3 v47; // xmm3_4 - float_t v11; // [rsp+7Ch] [rbp-84h] BYREF - float_t v10; // [rsp+80h] [rbp-80h] BYREF - float_t v01; // [rsp+84h] [rbp-7Ch] BYREF - float_t v00; // [rsp+88h] [rbp-78h] BYREF - vec2 v63[8]; // [rsp+A0h] [rbp-60h] BYREF - vec3 v72; // [rsp+180h] [rbp+80h] BYREF - vec3 v73; // [rsp+190h] [rbp+90h] BYREF - mat4 mat; // [rsp+1C0h] [rbp+C0h] BYREF - mat4 a1a; // [rsp+200h] [rbp+100h] BYREF +static void FASTCALL glitter_render_group_draw_quad_direction_rotation(glitter_render_group* a1, + mat4* model_mat, mat3* direction_mat, + void(FASTCALL* rotate_func)(mat3*, glitter_render_group*, glitter_render_element*)) { + size_t i; + size_t j; + size_t j_max; + size_t k; + glitter_render_element* elem; + size_t disp; + glitter_buffer* buf; + float_t rot_z_cos; + float_t rot_z_sin; + vec3 x_vec_rot; + vec3 y_vec_rot; + vec3 pos_add_rot; + vec3 pos; + vec2 scale_particle; + float_t v00; + float_t v01; + float_t v10; + float_t v11; + vec2 pos_add[4]; + vec2 uv_add[4]; + vec2 base_uv; + vec3 x_vec; + vec3 y_vec; + vec3 x_vec_base; + vec3 y_vec_base; + mat3 mat; + mat3 inv_model_mat; vec3 scale; - glitter_buffer buf[4]; + bool use_scale; - memset(buf, 0, sizeof(glitter_buffer) * 4); - mat4_inverse(a3, &a1a); - a1a.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; + mat3_from_mat4_inverse(model_mat, &inv_model_mat); - glBindBuffer(GL_ARRAY_BUFFER, a2->buffer_index); - v16 = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + x_vec_base = (vec3){ 1.0f, 0.0f, 0.0f }; + y_vec_base = (vec3){ 0.0f, 1.0f, 0.0f }; - vec4_length(a3->row0, scale.x); - vec4_length(a3->row1, scale.y); - vec4_length(a3->row2, scale.z); + mat3_mult_vec(&inv_model_mat, &x_vec_base, &x_vec_base); + mat3_mult_vec(&inv_model_mat, &y_vec_base, &y_vec_base); - v9 = a2->sub; - count = 0; - for (i = a2->ctrl, v14 = 1024; i > 0; i -= v14) { - v14 = min(i, v14); - for (j = v14; j > 0; v9++) { - if (!v9->alive) + mat4_get_scale(model_mat, &scale); + + use_scale = a1->flags & GLITTER_PARTICLE_SCALE ? true : false; + buf = a1->buffer; + elem = a1->elements; + disp = 0; + for (i = a1->ctrl, j_max = 1024; i > 0; i -= j_max) { + j_max = min(i, j_max); + for (j = j_max; j > 0; elem++) { + if (!elem->alive) continue; j--; - if (v9->color.w < 0.0099999998f) + if (!elem->draw) continue; - count++; - glitter_render_group_draw_set_pivot(a2->pivot, - v9->scale.x * v9->scale_particle.x * v9->scale_all, - v9->scale.y * v9->scale_particle.y * v9->scale_all, + vec2_mult(*(vec2*)&elem->scale, elem->scale_particle, scale_particle); + vec2_mult_scalar(scale_particle, elem->scale_all, scale_particle); + + if (fabsf(scale_particle.x) < 0.000001f || fabsf(scale_particle.y) < 0.000001f) + continue; + + pos = elem->translation; + + glitter_render_group_draw_set_pivot(a1->pivot, + scale_particle.x, + scale_particle.y, &v00, &v01, &v10, &v11); - v63[0].x = v00; - v63[0].y = v11; - v63[1].x = v9->uv.x; - v63[1].y = v9->uv.y; - v63[2].x = v00; - v63[2].y = v10; - v63[3].x = v9->uv.x; - v63[3].y = v9->uv.y + a2->split_uv.y; - v63[4].x = v01; - v63[4].y = v10; - v63[5].x = v9->uv.x + a2->split_uv.x; - v63[5].y = v9->uv.y + a2->split_uv.y; - v63[6].x = v01; - v63[6].y = v11; - v63[7].x = v9->uv.x + a2->split_uv.x; - v63[7].y = v9->uv.y; + pos_add[0].x = v00; + pos_add[0].y = v11; + uv_add[0].x = 0.0f; + uv_add[0].y = 0.0f; + pos_add[1].x = v00; + pos_add[1].y = v10; + uv_add[1].x = 0.0f; + uv_add[1].y = a1->split_uv.y; + pos_add[2].x = v01; + pos_add[2].y = v10; + uv_add[2].x = a1->split_uv.x; + uv_add[2].y = a1->split_uv.y; + pos_add[3].x = v01; + pos_add[3].y = v11; + uv_add[3].x = a1->split_uv.x; + uv_add[3].y = 0.0f; - func(&mat, a2, v9); - mat4_mult(a4, &mat, &mat); - v73 = (vec3){ 1.0f, 0.0f, 0.0f }; - mat4_mult_vec3(&mat, &v73, &v73); - mat4_mult_vec3(&a1a, &v73, &v73); - v72 = (vec3){ 0.0f, 1.0f, 0.0f }; - mat4_mult_vec3(&mat, &v72, &v72); - mat4_mult_vec3(&a1a, &v72, &v72); + vec2_add(elem->uv_scroll, elem->uv, base_uv); + rotate_func(&mat, a1, elem); + mat3_mult(direction_mat, &mat, &mat); + mat3_mult_vec(&mat, &x_vec_base, &x_vec); + mat3_mult_vec(&mat, &y_vec_base, &y_vec); - if (a2->flags & GLITTER_PARTICLE_FLAG_SCALE) - vec3_mult(v73, scale, v73); + if (use_scale) + vec3_mult(x_vec, scale, x_vec); - rot_z_cos = cosf(v9->rotation.z); - rot_z_sin = sinf(v9->rotation.z); - for (v41 = v63, v42 = 0; v42 < 4; v41 += 2, v42++) { - vec3_mult_scalar(v72, v41[0].x * rot_z_sin + v41[0].y * rot_z_cos, v47); - vec3_mult_scalar(v73, v41[0].x * rot_z_cos - v41[0].y * rot_z_sin, v46); - vec3_add(v47, v46, v47); - vec3_add(v47, v9->translation, buf[v42].position); - vec2_add(v9->uv_scroll, v41[1], buf[v42].uv); - buf[v42].color = v9->color; + rot_z_cos = cosf(elem->rotation.z); + rot_z_sin = sinf(elem->rotation.z); + for (k = 0; k < 4; k++, buf++) { + vec3_mult_scalar(x_vec, pos_add[k].x * rot_z_cos - pos_add[k].y * rot_z_sin, x_vec_rot); + vec3_mult_scalar(y_vec, pos_add[k].x * rot_z_sin + pos_add[k].y * rot_z_cos, y_vec_rot); + vec3_add(x_vec_rot, y_vec_rot, pos_add_rot); + vec3_add(pos, pos_add_rot, buf->position); + vec2_add(base_uv, uv_add[k], buf->uv); + buf->color = *(vec3*)&elem->color; + buf->alpha = elem->color.w; } - - v16[0] = buf[0]; - v16[1] = buf[1]; - v16[2] = buf[2]; - v16[3] = buf[0]; - v16[4] = buf[2]; - v16[5] = buf[3]; - v16 += 6; + disp++; } } - glUnmapBuffer(GL_ARRAY_BUFFER); - - glBindVertexArray(a2->vao); - glitter_render_group_draw_quads(a1, count); + a1->disp = disp; } -void FASTCALL glitter_render_group_emit(glitter_render_group* a1, - glitter_particle_inst_data* a2, glitter_emitter_inst* a3, int32_t a4, int32_t count) { - glitter_render_group_sub* sub; - int64_t i; - int32_t index; - - for (sub = 0, i = a4; i > 0; i--) - for (index = 0; index < count; index++, sub = sub + 1) { - sub = glitter_render_group_add_control(a1, sub); - if (!sub) - break; - - glitter_render_group_sub_emit(a1->particle_inst, sub, a3, a2, index); - } -} - -void FASTCALL glitter_render_group_free(glitter_render_group* a1) { - glitter_render_group_sub* sub; - int32_t i; - - sub = a1->sub; - for (i = 0; i < a1->count; i++, sub++) { - sub->alive = false; - if (sub->locus_history) { - glitter_locus_history_dispose(sub->locus_history); - sub->locus_history = 0; - } - } - a1->ctrl = 0; -} - -bool FASTCALL glitter_render_group_get_a3da_scale(glitter_render_group* a1, vec3* a2) { - glitter_effect_inst* effect_inst; // rcx - - if (!a1->particle_inst) - return false; - - if (a1->particle_inst->sub.effect_inst) - effect_inst = a1->particle_inst->sub.effect_inst; - else { - if (!a1->particle_inst->sub.parent) - return false; - - effect_inst = a1->particle_inst->sub.parent->sub.effect_inst; - if (!effect_inst) - return false; - } - - if (~effect_inst->flags & GLITTER_EFFECT_INST_FLAG_HAS_A3DA_SCALE) - return false; - - if (a2) - *a2 = effect_inst->a3da_scale; - return true; -} - -void FASTCALL glitter_render_group_draw_set_pivot(glitter_pivot pivot, +static void FASTCALL glitter_render_group_draw_set_pivot(glitter_pivot pivot, float_t a2, float_t a3, float_t* v00, float_t* v01, float_t* v10, float_t* v11) { switch (pivot) { case GLITTER_PIVOT_TOP_LEFT: @@ -1317,346 +1194,27 @@ void FASTCALL glitter_render_group_draw_set_pivot(glitter_pivot pivot, } } -void FASTCALL glitter_render_group_sub_accelerate(glitter_particle_inst* a1, - glitter_render_group_sub* a2, float_t rebound_time, float_t delta_frame) { - vec3 acceleration; - vec3 direction; - float_t delta_time; - float_t reflection_coeff; - float_t deceleration; +static bool FASTCALL glitter_render_group_get_ext_anim_scale(glitter_render_group* a1, vec3* a2) { + glitter_effect_inst* effect_inst; - a2->translation_prev = a2->translation; - delta_time = delta_frame * (float_t)(1.0 / 60.0); - rebound_time -= a2->rebound_time + delta_time; - deceleration = a2->deceleration * delta_time * (delta_time * 0.5f - rebound_time) + a2->speed; - vec3_mult_scalar(a2->acceleration, delta_time * (delta_time * 0.5f + rebound_time), acceleration); - if (deceleration >= 0.0099999998f) { - vec3_mult_scalar(a2->direction, deceleration * delta_time, direction); - vec3_add(acceleration, direction, acceleration); - } + if (!a1->particle) + return false; - vec3_add(a2->translation, acceleration, a2->translation); - vec3_add(a2->base_translation, acceleration, a2->base_translation); - if (a1->sub.data.flags & GLITTER_PARTICLE_FLAG_REBOUND_PLANE - && a2->translation_prev.y > a1->sub.data.rebound_plane_y - && a2->translation.y <= a1->sub.data.rebound_plane_y) { - reflection_coeff = glitter_random_get_float_clamp_min_max(a1->sub.data.reflection_coeff_random) - + a1->sub.data.reflection_coeff; - a2->rebound_time = rebound_time; - vec3_sub(a2->translation, a2->translation_prev, direction); - vec3_mult_scalar(direction, reflection_coeff * 60.0f, direction); - vec3_xor(direction, ((vec3){ 0.0f, -0.0f, 0.0f }), a2->direction); - a2->translation.y = a2->translation_prev.y; - } -} - -void FASTCALL glitter_render_group_sub_clamp_color(glitter_particle_inst* a1, - float_t* r, float_t* g, float_t* b, float_t* a) { - glitter_effect_inst* effect; - - effect = a1->sub.effect_inst; - if (!effect) { - if (!a1->sub.parent) - return; - effect = a1->sub.parent->sub.effect_inst; - if (!effect) - return; - } - - if (~effect->flags & GLITTER_EFFECT_INST_FLAG_SET_ADD_MIN_COLOR) - return; - - if (effect->flags & GLITTER_EFFECT_INST_FLAG_SET_MIN_COLOR) { - if (effect->min_color.x >= 0.0f) - *r = effect->min_color.x; - if (effect->min_color.y >= 0.0f) - *g = effect->min_color.y; - if (effect->min_color.z >= 0.0f) - *b = effect->min_color.z; - if (effect->min_color.w >= 0.0f) - *a = effect->min_color.w; - } + if (a1->particle->data.effect) + effect_inst = a1->particle->data.effect; else { - *r += effect->min_color.x; - *g += effect->min_color.y; - *b += effect->min_color.z; - *a += effect->min_color.w; + if (!a1->particle->data.parent) + return false; + + effect_inst = a1->particle->data.parent->data.effect; + if (!effect_inst) + return false; } - if (*r < 0.0f) - *r = 0.0f; - if (*g < 0.0f) - *g = 0.0f; - if (*b < 0.0f) - *b = 0.0f; - if (*a < 0.0f) - *a = 0.0f; -} - -void FASTCALL glitter_render_group_sub_emit(glitter_particle_inst* a1, glitter_render_group_sub* a2, - glitter_emitter_inst* a3, glitter_particle_inst_data* a4, int32_t index) { - float_t speed; - float_t deceleration; - vec3 direction; - vec3 base_translation; - vec3 scale; - vec3 external_acceleration; - vec3 direction_random; - int32_t max_uv; // ecx - bool v19; // zf - uint32_t locus_history_size; - - a2->uv_index = a4->data.uv_index; - glitter_counter_increment(); - glitter_random_set(glitter_counter_get()); - a2->random = glitter_random_get_int(glitter_random_get_max()); - a2->frame = 0.0f; - a2->rebound_time = 0.0f; - a2->uv = vec2_null; - a2->life_time = a4->data.life_time; - a2->color = a4->data.color; - if (a4->data.draw_type == GLITTER_DIRECTION_PARTICLE_ROTATION) { - a2->rotation.x = glitter_random_get_float_clamp_min_max(a4->data.rotation_random.x) - + a4->data.rotation.x; - a2->rotation_add.x = glitter_random_get_float_clamp_min_max(a4->data.rotation_add_random.x) - + a4->data.rotation_add.x; - a2->rotation.y = glitter_random_get_float_clamp_min_max(a4->data.rotation_random.y) - + a4->data.rotation.y; - a2->rotation_add.y = glitter_random_get_float_clamp_min_max(a4->data.rotation_add_random.y) - + a4->data.rotation_add.y; + if (effect_inst->flags & GLITTER_EFFECT_INST_HAS_EXT_ANIM_SCALE) { + if (a2) + *a2 = effect_inst->ext_anim_scale; + return true; } - else { - a2->rotation.x = 0.0f; - a2->rotation.y = 0.0f; - a2->rotation_add.x = 0.0f; - a2->rotation_add.y = 0.0f; - } - a2->rot_z_cos = 1.0f; - a2->rot_z_sin = 0.0f; - a2->rotation.z = glitter_random_get_float_clamp_min_max(a4->data.rotation_random.z) - + a4->data.rotation.z; - a2->rotation_add.z = glitter_random_get_float_clamp_min_max(a4->data.rotation_add_random.z) - + a4->data.rotation_add.z; - a2->uv_scroll = vec2_null; - a2->scale = vec3_identity; - a2->scale_all = 1.0f; - a2->frame_step_uv = a4->data.frame_step_uv; - - a2->scale_particle.x = glitter_random_get_float_clamp_min_max(a4->data.scale_random.x) - + a4->data.scale.x; - if (a4->data.flags & GLITTER_PARTICLE_FLAG_SCALE_Y_BY_X) - a2->scale_particle.y = a2->scale_particle.x; - else - a2->scale_particle.y = glitter_random_get_float_clamp_min_max(a4->data.scale_random.y) - + a4->data.scale.y; - - max_uv = a4->data.split_u * a4->data.split_v; - if (max_uv && max_uv - 1 > 1) { - if (((a4->data.uv_index_type - 1) & 0xFFFFFFFA) == 0 - && a4->data.uv_index_type != 2 && a4->data.uv_index_count > 1) - a2->uv_index = a4->data.uv_index_start + glitter_random_get_int(a4->data.uv_index_count); - - a2->uv.x = (float_t)(a2->uv_index % a1->sub.data.split_u) * a1->sub.data.split_uv.x; - a2->uv.y = (float_t)(a2->uv_index / a1->sub.data.split_u) * a1->sub.data.split_uv.y; - } - - if (a4->data.flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT || a4->data.flags & GLITTER_PARTICLE_FLAG_TRANSLATE_BY_EMITTER) - a2->base_translation = vec3_null; - else - a2->base_translation = *(vec3*)&a3->mat.row3; - - direction = a4->data.direction; - base_translation = vec3_null; - if (a4->data.flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) { - scale = vec3_identity; - glitter_emitter_inst_get_mesh_by_type(a3, index, &scale, &base_translation, &direction); - } - else { - vec3_mult_scalar(a3->scale, a3->scale_all, scale); - glitter_emitter_inst_get_mesh_by_type(a3, index, &scale, &base_translation, &direction); - mat4_mult_vec3(&a3->mat_no_scale, &base_translation, &base_translation); - } - - vec3_add(a2->base_translation, base_translation, a2->base_translation); - a2->translation = a2->base_translation; - a2->translation_prev = a2->base_translation; - glitter_random_get_float_vec3_clamp(&a4->data.direction_random, &direction_random); - vec3_add(direction, direction_random, direction); - vec3_normalize(direction, direction); - - if (~a4->data.flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) - mat4_mult_vec3(&a3->mat_no_scale, &direction, &direction); - - speed = glitter_random_get_float_clamp_min_max(a4->data.speed_random) + a4->data.speed; - deceleration = glitter_random_get_float_clamp_min_max(a4->data.deceleration_random) + a4->data.deceleration; - a2->direction = direction; - a2->speed = speed * 60.0f; - a2->deceleration = max(deceleration * 60.0f, 0.0f); - - glitter_random_get_float_vec3_clamp(&a4->data.external_acceleration_random, &external_acceleration); - vec3_add(external_acceleration, a4->data.external_acceleration, external_acceleration); - vec3_add(external_acceleration, a4->data.gravitational_acceleration, a2->acceleration); - - if (a4->data.flags & GLITTER_PARTICLE_FLAG_TRANSLATE_BY_EMITTER - || a4->data.draw_type == GLITTER_DIRECTION_EMITTER_ROTATION) { - switch (a3->data.type) { - case GLITTER_EMITTER_CYLINDER: - v19 = a3->data.cylinder.direction == GLITTER_EMITTER_EMISSION_DIRECTION_PARTICLE_VELOCITY; - if (!v19) { - float_t length; - vec3_length(a2->direction, length); - v19 = length <= 0.000001f; - } - break; - case GLITTER_EMITTER_SPHERE: - v19 = a3->data.sphere.direction == GLITTER_EMITTER_EMISSION_DIRECTION_PARTICLE_VELOCITY; - if (!v19) { - float_t length; - vec3_length(a2->direction, length); - v19 = length <= 0.000001f; - } - break; - default: - v19 = true; - break; - } - - if (v19) { - a2->mat = a3->mat; - if (a4->data.flags & GLITTER_PARTICLE_FLAG_USE_MODEL_MAT) - a2->mat.row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; - } - else - a2->mat = mat4_identity; - } - else - a2->mat = mat4_identity; - - if (a1->sub.data.type == GLITTER_PARTICLE_LOCUS) { - locus_history_size = glitter_random_get_int_clamp(-a1->sub.data.locus_history_size_random, - a1->sub.data.locus_history_size_random) + a1->sub.data.locus_history_size; - a2->locus_history = glitter_locus_history_init(locus_history_size); - } - glitter_random_set(glitter_random_get() + 1); -} - -void FASTCALL glitter_render_group_sub_get_color(glitter_particle_inst* a1, glitter_render_group_sub* a2) { - float_t r; - float_t g; - float_t b; - float_t a; - - r = a2->color.x; - if (r < 0.0f) - r = a1->sub.data.color.x; - g = a2->color.y; - if (g < 0.0f) - g = a1->sub.data.color.y; - b = a2->color.z; - if (b < 0.0f) - b = a1->sub.data.color.z; - a = a2->color.w; - if (a < 0.0f) - a = a1->sub.data.color.w; - glitter_render_group_sub_clamp_color(a1, &r, &g, &b, &a); - a2->color.x = r; - a2->color.y = g; - a2->color.z = b; - a2->color.w = a; -} - -void FASTCALL glitter_render_group_sub_get_value(glitter_render_group* a1, - glitter_render_group_sub* a2, float_t delta_frame) { - glitter_particle_inst* v4; - vec2 uv_scroll; - bool visible; - - v4 = a1->particle_inst; - if ((v4->sub.data.flags & GLITTER_PARTICLE_FLAG_LOOP - && !glitter_particle_inst_has_ended(v4, false)) || a2->frame <= a2->life_time) { - glitter_render_group_sub_accelerate(v4, a2, a2->frame / 60.0f, delta_frame); - if (v4->sub.data.draw_type == GLITTER_DIRECTION_PARTICLE_ROTATION) { - a2->rotation.x += a2->rotation_add.x * delta_frame; - a2->rotation.y += a2->rotation_add.y * delta_frame; - } - a2->rotation.z += a2->rotation_add.z * delta_frame; - vec2_mult_scalar(v4->sub.data.uv_scroll_add, v4->sub.data.uv_scroll_add_scale * delta_frame, uv_scroll); - vec2_add(a2->uv_scroll, uv_scroll, a2->uv_scroll); - glitter_render_group_sub_step_uv(v4, a2, delta_frame); - a2->color = (vec4){ -1.0f, -1.0f, -1.0f, -1.0f }; - - visible = true; - if (v4->sub.data.sub_flags & GLITTER_PARTICLE_SUB_FLAG_USE_CURVE) - visible = glitter_particle_inst_get_value(v4, a2, a2->frame) != 0; - - if (v4->sub.data.draw_type == GLITTER_DIRECTION_PARTICLE_ROTATION - || fabs(a2->rotation.z) <= 0.000001f) { - a2->rot_z_cos = 1.0f; - a2->rot_z_sin = 0.0f; - } - else { - a2->rot_z_cos = cosf(a2->rotation.z); - a2->rot_z_sin = sinf(a2->rotation.z); - } - - if (visible) - glitter_render_group_sub_get_color(v4, a2); - - if (v4->sub.data.type == GLITTER_PARTICLE_LOCUS) - glitter_locus_history_append(a2->locus_history, a2, v4); - - a2->frame += delta_frame; - if (v4->sub.data.flags & GLITTER_PARTICLE_FLAG_LOOP && a2->frame >= a2->life_time) - a2->frame -= a2->life_time; - return; - } - else { - a2->alive = false; - if (a2->locus_history) { - glitter_locus_history_dispose(a2->locus_history); - a2->locus_history = 0; - } - a1->ctrl--; - } -} - -void FASTCALL glitter_render_group_sub_step_uv(glitter_particle_inst* a1, - glitter_render_group_sub* a2, float_t delta_frame) { - int32_t max_uv; - - if (a1->sub.data.frame_step_uv <= 0.0f) - return; - - while (a2->frame_step_uv <= 0.0f) { - max_uv = a1->sub.data.split_u * a1->sub.data.split_v; - if (max_uv) - max_uv = max_uv - 1; - - switch (a1->sub.data.uv_index_type) { - case GLITTER_UV_INDEX_RANDOM: - a2->uv_index = a1->sub.data.uv_index_start; - if (a1->sub.data.uv_index_count > 1) - a2->uv_index += a1->sub.data.uv_index_start - + glitter_random_get_int(a1->sub.data.uv_index_count); - break; - case GLITTER_UV_INDEX_FORWARD: - case GLITTER_UV_INDEX_INITIAL_RANDOM_FORWARD: - a2->uv_index = (uint8_t)(max_uv & (a2->uv_index + 1)); - break; - case GLITTER_UV_INDEX_REVERSE: - case GLITTER_UV_INDEX_INITIAL_RANDOM_REVERSE: - a2->uv_index = (uint8_t)(max_uv & (a2->uv_index - 1)); - break; - } - - a2->uv.x = (a2->uv_index % a1->sub.data.split_u) * a1->sub.data.split_uv.x; - a2->uv.y = (a2->uv_index / a1->sub.data.split_u) * a1->sub.data.split_uv.y; - a2->frame_step_uv += a1->sub.data.frame_step_uv; - } - a2->frame_step_uv -= delta_frame; -} - -void FASTCALL glitter_render_group_dispose(glitter_render_group* rg) { - glitter_render_group_delete_buffers(rg, false); - free(rg); + return false; } diff --git a/src/CRE/Glitter/render_group.h b/src/CRE/Glitter/render_group.h index a303a253..e9e2ce35 100644 --- a/src/CRE/Glitter/render_group.h +++ b/src/CRE/Glitter/render_group.h @@ -7,42 +7,15 @@ #include "glitter.h" -extern glitter_render_group* FASTCALL glitter_render_group_init(int32_t count, glitter_particle_inst* a2); -extern glitter_render_group_sub* FASTCALL glitter_render_group_add_control(glitter_render_group* a1, - glitter_render_group_sub* a2); -extern void FASTCALL glitter_render_group_copy(glitter_render_group* a1, glitter_render_group* a2); -extern void FASTCALL glitter_render_group_copy_from_particle(glitter_render_group* render_group, - float_t delta_frame, bool copy_mats); +extern glitter_render_group* FASTCALL glitter_render_group_init(GPM, glitter_particle_inst* a1); +extern void FASTCALL glitter_render_group_calc_draw(GPM, glitter_render_group* a1, + bool(FASTCALL* render_add_list_func)(glitter_particle_mesh*, vec4*, mat4*, mat4*)); +extern bool FASTCALL glitter_render_group_cannot_draw(glitter_render_group* a1); extern void FASTCALL glitter_render_group_delete_buffers(glitter_render_group* a1, bool a2); -extern void FASTCALL glitter_render_group_draw(glitter_scene_sub* a1, glitter_render_group* a2); -extern void FASTCALL glitter_render_group_draw_line(glitter_scene_sub* a1, glitter_render_group* a2); -extern void FASTCALL glitter_render_group_draw_locus(glitter_scene_sub* a1, glitter_render_group* a2); -extern void FASTCALL glitter_render_group_draw_quad(glitter_scene_sub* a1, glitter_render_group* a2); -extern void FASTCALL glitter_render_group_draw_quad_rotate_to_prev_position(mat4* mat, - glitter_render_group* a2, glitter_render_group_sub* a3); -extern void FASTCALL glitter_render_group_draw_quad_rotate_to_position(mat4* mat, - glitter_render_group* a2, glitter_render_group_sub* a3); -extern void FASTCALL glitter_render_group_draw_quad_sub1(glitter_scene_sub* a1, - glitter_render_group* a2, mat4* a3, mat4* a4); -extern void FASTCALL glitter_render_group_draw_quad_sub2(glitter_scene_sub* a1, - glitter_render_group* a2, mat4* a3, mat4* a4, - void(FASTCALL* a5)(mat4*, glitter_render_group*, glitter_render_group_sub*)); -extern void FASTCALL glitter_render_group_draw_quads(glitter_scene_sub* a1, int32_t count); -extern void FASTCALL glitter_render_group_draw_set_pivot(glitter_pivot pivot, - float_t a2, float_t a3, float_t* v00, float_t* v01, float_t* v10, float_t* v11); -extern void FASTCALL glitter_render_group_emit(glitter_render_group* a1, +extern void FASTCALL glitter_render_group_draw(GPM, glitter_render_group* a1); +extern void FASTCALL glitter_render_group_emit(GPM, glitter_render_group* a1, glitter_particle_inst_data* a2, glitter_emitter_inst* a3, int32_t a4, int32_t count); extern void FASTCALL glitter_render_group_free(glitter_render_group* a1); -extern bool FASTCALL glitter_render_group_get_a3da_scale(glitter_render_group* a1, vec3* a2); -extern void FASTCALL glitter_render_group_sub_accelerate(glitter_particle_inst* a1, - glitter_render_group_sub* a2, float_t rebound_time, float_t delta_frame); -extern void FASTCALL glitter_render_group_sub_clamp_color(glitter_particle_inst* a1, - float_t* r, float_t* g, float_t* b, float_t* a); -extern void FASTCALL glitter_render_group_sub_emit(glitter_particle_inst* a1, - glitter_render_group_sub* a2, glitter_emitter_inst* a3, glitter_particle_inst_data* a4, int32_t a5); -extern void FASTCALL glitter_render_group_sub_get_color(glitter_particle_inst* a1, glitter_render_group_sub* a2); -extern void FASTCALL glitter_render_group_sub_get_value(glitter_render_group* a1, - glitter_render_group_sub* a2, float_t delta_frame); -extern void FASTCALL glitter_render_group_sub_step_uv(glitter_particle_inst* a1, - glitter_render_group_sub* a2, float_t delta_frame); +extern void FASTCALL glitter_render_group_get_value(GPM, + glitter_render_group* render_group, float_t delta_frame, bool copy_mats); extern void FASTCALL glitter_render_group_dispose(glitter_render_group* rg); diff --git a/src/CRE/Glitter/scene.c b/src/CRE/Glitter/scene.c index e391776c..976c7234 100644 --- a/src/CRE/Glitter/scene.c +++ b/src/CRE/Glitter/scene.c @@ -5,43 +5,20 @@ #include "scene.h" #include "effect_inst.h" -#include "render_group.h" +#include "../GlitterX/effect_inst_x.h" glitter_scene* FASTCALL glitter_scene_init(glitter_effect_group* eg) { glitter_scene* s = force_malloc(sizeof(glitter_scene)); s->emission = 1.0f; s->effect_group = eg; s->hash = eg->hash; - vector_ptr_glitter_render_group_resize(&s->sub.render_groups, 0x40); if (eg) { - vector_ptr_glitter_effect_inst_resize(&s->effects, eg->effects.end - eg->effects.begin); + vector_ptr_glitter_effect_inst_append(&s->effects, eg->effects.end - eg->effects.begin); s->emission = eg->emission; } return s; } -bool FASTCALL glitter_scene_copy(glitter_scene* a1, glitter_effect_inst* a2, glitter_scene* a3) { - glitter_effect_inst** i; - - if (a1->effects.begin == a1->effects.end) - return false; - - for (i = a1->effects.begin; i != a1->effects.end; i++) - if (*i && (*i)->id == a2->id) { - glitter_effect_inst_copy(*i, a2, a3); - return true; - } - return false; -} - -void FASTCALL glitter_scene_emit(glitter_scene* a1, float_t frame_speed) { - glitter_effect_inst** i; - - for (i = a1->effects.begin; i != a1->effects.end; ++i) - if (*i) - glitter_effect_inst_emit(*i, a1, frame_speed); -} - bool FASTCALL glitter_scene_has_ended(glitter_scene* scene, bool a2) { glitter_effect_inst** i; @@ -51,7 +28,7 @@ bool FASTCALL glitter_scene_has_ended(glitter_scene* scene, bool a2) { return true; } -void FASTCALL glitter_scene_init_effect(glitter_scene* a1, +void FASTCALL glitter_scene_init_effect(GPM, glitter_scene* a1, glitter_effect* a2, size_t id, bool appear_now) { glitter_effect_inst** i; glitter_effect_inst* effect; @@ -59,55 +36,51 @@ void FASTCALL glitter_scene_init_effect(glitter_scene* a1, if (!a2) return; - for (i = a1->effects.begin; i != a1->effects.end; i++) - if (*i && (*i)->id == id) { - glitter_effect_inst_reset(*i, a1); - return; - } + /*if (glt_type == GLITTER_X) { + for (i = a1->effects.begin; i != a1->effects.end; i++) + if (*i && (*i)->id == id) { + glitter_x_effect_inst_reset(GPM_VAL, *i, a1->emission); + return; + } - effect = glitter_effect_inst_init(a2, a1, id, appear_now); - vector_ptr_glitter_effect_inst_push_back(&a1->effects, &effect); -} + effect = glitter_x_effect_inst_init(GPM_VAL, a2, id, a1->emission, appear_now); + vector_ptr_glitter_effect_inst_push_back(&a1->effects, &effect); + } + else*/ { + for (i = a1->effects.begin; i != a1->effects.end; i++) + if (*i && (*i)->id == id) { + glitter_effect_inst_reset(GPM_VAL, *i, a1->emission); + return; + } -void FASTCALL glitter_scene_update_scene(glitter_scene* a1, float_t delta_frame) { - glitter_render_group** i; - glitter_render_group* render_group; - glitter_scene_sub* sub; - - sub = &a1->sub; - sub->ctrl_quad = 0; - sub->ctrl_line = 0; - sub->ctrl_locus = 0; - for (i = sub->render_groups.begin; i != sub->render_groups.end; i++) { - if (!*i) - continue; - - render_group = *i; - switch (render_group->type) { - case GLITTER_PARTICLE_QUAD: - sub->ctrl_quad += render_group->ctrl; - break; - case GLITTER_PARTICLE_LINE: - sub->ctrl_line += render_group->ctrl; - break; - case GLITTER_PARTICLE_LOCUS: - sub->ctrl_locus += render_group->ctrl; - break; - } - glitter_render_group_copy_from_particle(render_group, delta_frame, true); + effect = glitter_effect_inst_init(GPM_VAL, a2, id, a1->emission, appear_now); + vector_ptr_glitter_effect_inst_push_back(&a1->effects, &effect); } } -void FASTCALL glitter_scene_update_value_frame(glitter_scene* a1, float_t delta_frame) { +void FASTCALL glitter_scene_update_value_frame(GPM, glitter_scene* a1, float_t delta_frame) { glitter_effect_inst** i; + glitter_effect_inst* effect; - for (i = a1->effects.begin; i != a1->effects.end; ++i) - if (*i) - glitter_effect_inst_update_value_frame(*i, delta_frame); + /*if (glt_type == GLITTER_X) + for (i = a1->effects.begin; i != a1->effects.end; ++i) { + if (!*i) + continue; + + effect = *i; + glitter_x_effect_inst_update_value_frame(GPM_VAL, effect, delta_frame, a1->emission); + } + else*/ + for (i = a1->effects.begin; i != a1->effects.end; ++i) { + if (!*i) + continue; + + effect = *i; + glitter_effect_inst_update_value_frame(GPM_VAL, effect, delta_frame, a1->emission); + } } void FASTCALL glitter_scene_dispose(glitter_scene* s) { - vector_ptr_glitter_effect_inst_free(&s->effects, (void*)glitter_effect_inst_dispose); - vector_ptr_glitter_render_group_free(&s->sub.render_groups, (void*)glitter_render_group_dispose); + vector_ptr_glitter_effect_inst_free(&s->effects, glitter_effect_inst_dispose); free(s); } diff --git a/src/CRE/Glitter/scene.h b/src/CRE/Glitter/scene.h index 39843385..990af48e 100644 --- a/src/CRE/Glitter/scene.h +++ b/src/CRE/Glitter/scene.h @@ -8,11 +8,8 @@ #include "glitter.h" extern glitter_scene* FASTCALL glitter_scene_init(glitter_effect_group* eg); -extern bool FASTCALL glitter_scene_copy(glitter_scene* a1, glitter_effect_inst* a2, glitter_scene* a3); -extern void FASTCALL glitter_scene_emit(glitter_scene* a1, float_t frame_speed); extern bool FASTCALL glitter_scene_has_ended(glitter_scene* scene, bool a2); -extern void FASTCALL glitter_scene_init_effect(glitter_scene* a1, +extern void FASTCALL glitter_scene_init_effect(GPM, glitter_scene* a1, glitter_effect* a2, size_t id, bool appear_now); -extern void FASTCALL glitter_scene_update_scene(glitter_scene* a1, float_t delta_frame); -extern void FASTCALL glitter_scene_update_value_frame(glitter_scene* a1, float_t delta_frame); +extern void FASTCALL glitter_scene_update_value_frame(GPM, glitter_scene* a1, float_t delta_frame); extern void FASTCALL glitter_scene_dispose(glitter_scene* s); diff --git a/src/CRE/Glitter/shared.c b/src/CRE/Glitter/shared.c index d2349c28..4bdab0ae 100644 --- a/src/CRE/Glitter/shared.c +++ b/src/CRE/Glitter/shared.c @@ -9,8 +9,6 @@ float_t frame_speed = 1.0f; float_t target_fps = 60.0f; extern double_t render_freq; -int32_t glitter_shader_flags[4]; - float_t get_frame_speed() { return (float_t)(clamp(target_fps / render_freq, 0.0, 1.0) * frame_speed); } @@ -40,6 +38,21 @@ void FASTCALL axis_angle_from_vectors(vec3* axis, float_t* angle, vec3* vec1, ve *angle = (float_t)M_PI - *angle; } +void FASTCALL mat3_mult_axis_angle(mat3* src, mat3* dst, vec3* axis, float_t angle) { + quat q1; + quat q2; + quat q3; + + quat_from_mat3(src->row0.x, src->row0.y, src->row0.z, src->row1.x, + src->row1.y, src->row1.z, src->row2.x, src->row2.y, src->row2.z, &q1); + quat_from_axis_angle(axis, angle, &q2); + q3.x = q1.x * q2.w - q1.y * q2.z + q1.z * q2.y + q1.w * q2.x; + q3.y = q1.x * q2.z + q1.y * q2.w - q1.z * q2.x + q1.w * q2.y; + q3.z = -q1.x * q2.y + q1.y * q2.x + q1.z * q2.w + q1.w * q2.z; + q3.w = -q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w; + mat3_from_quat(&q3, dst); +} + void FASTCALL mat4_mult_axis_angle(mat4* src, mat4* dst, vec3* axis, float_t angle) { quat q1; quat q2; @@ -57,4 +70,8 @@ void FASTCALL mat4_mult_axis_angle(mat4* src, mat4* dst, vec3* axis, float_t ang *(vec3*)&dst->row0 = yt.row0; *(vec3*)&dst->row1 = yt.row1; *(vec3*)&dst->row2 = yt.row2; + dst->row0.w = src->row0.w; + dst->row1.w = src->row2.w; + dst->row2.w = src->row3.w; + dst->row3 = src->row3; } diff --git a/src/CRE/Glitter/shared.h b/src/CRE/Glitter/shared.h index 124c344e..3b108470 100644 --- a/src/CRE/Glitter/shared.h +++ b/src/CRE/Glitter/shared.h @@ -10,14 +10,13 @@ #include "../../KKdLib/f2_struct.h" #include "../../KKdLib/farc.h" #include "../../KKdLib/hash.h" -#include "../../KKdLib/io_path.h" #include "../../KKdLib/mat.h" #include "../../KKdLib/quat.h" +#include "../../KKdLib/str_utils.h" #include "../../KKdLib/txp.h" #include "../../KKdLib/utf8.h" #include "../../KKdLib/vec.h" #include "../../KKdLib/vector.h" -#include "../camera.h" #define GLEW_STATIC #include @@ -25,9 +24,7 @@ extern float_t frame_speed; extern float_t target_fps; extern float_t current_fps; -extern int32_t glitter_shader_flags[4]; -extern camera* cam; - extern float_t get_frame_speed(); extern void FASTCALL axis_angle_from_vectors(vec3* axis, float_t* angle, vec3* vec0, vec3* vec1); +extern void FASTCALL mat3_mult_axis_angle(mat3* src, mat3* dst, vec3* axis, float_t angle); extern void FASTCALL mat4_mult_axis_angle(mat4* src, mat4* dst, vec3* axis, float_t angle); diff --git a/src/CRE/Glitter/texture.c b/src/CRE/Glitter/texture.c index 60e95f64..47322769 100644 --- a/src/CRE/Glitter/texture.c +++ b/src/CRE/Glitter/texture.c @@ -4,47 +4,46 @@ */ #include "texture.h" +#include "../texture.h" -static void load_texture_data(txp_sub_data* data, int32_t mipmap); - -bool FASTCALL glitter_texture_hashes_pack_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian) { - char* data; +bool FASTCALL glitter_texture_hashes_pack_file(glitter_effect_group* a1, f2_struct* st) { + size_t l; + size_t d; size_t count; - uint64_t* resource_hashes; - size_t i; - if (!a1->effects.begin) + if (a1->effects.end - a1->effects.begin < 1 || !a1->resources_count + || a1->resource_hashes.end - a1->resource_hashes.begin < 1) return false; - memset(st, 0, sizeof(f2_struct)); count = a1->resources_count; - data = force_malloc(align_val(0x08 + 0x08 * count, 0x10)); - st->data = data; - st->length = align_val(0x08 + 0x08 * count, 0x10); - if (use_big_endian) - *(int32_t*)data = reverse_endianess_int32_t((int32_t)count); - else - *(int32_t*)data = (int32_t)count; - data += 0x04; - *(int32_t*)data = 0; - data += 0x04; + memset(st, 0, sizeof(f2_struct)); + l = 0; - if (count) { - resource_hashes = a1->resource_hashes; - if (!resource_hashes) - return false; + vector_enrs_entry e = { 0, 0, 0 }; + enrs_entry ee; - if (use_big_endian) - for (i = 0; i < count; i++, data += sizeof(uint64_t)) - *(uint64_t*)data = reverse_endianess_uint64_t(resource_hashes[i]); - else - memcpy(data, resource_hashes, sizeof(uint64_t) * count); - } + ee = (enrs_entry){ 0, 2, (uint32_t)(8 + count * 8), 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 1, ENRS_TYPE_DWORD }); + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 4, (uint32_t)count, ENRS_TYPE_QWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += 8 + count * 8; + + l = align_val(l, 0x10); + d = (size_t)force_malloc(l); + st->data = (void*)d; + st->length = l; + st->enrs = e; + + *(int32_t*)d = (int32_t)count; + *(int32_t*)(d + 4) = 0; + d += 8; + + memcpy((void*)d, a1->resource_hashes.begin, sizeof(uint64_t) * count); st->header.signature = 0x53525644; st->header.length = 0x20; - st->header.use_big_endian = use_big_endian ? true : false; + st->header.use_big_endian = false; st->header.use_section_size = true; return true; } @@ -55,7 +54,7 @@ bool FASTCALL glitter_texture_hashes_unpack_file(glitter_effect_group* a1, f2_st uint64_t* resource_hashes; size_t i; - if (a1->resource_hashes) + if (a1->resources_count && a1->resource_hashes.end - a1->resource_hashes.begin > 0) return true; if (!st || !st->header.data_size) @@ -73,8 +72,10 @@ bool FASTCALL glitter_texture_hashes_unpack_file(glitter_effect_group* a1, f2_st a1->resources_count = count; if (count) { - resource_hashes = force_malloc_s(sizeof(uint64_t), count); - a1->resource_hashes = resource_hashes; + resource_hashes = force_malloc_s(uint64_t, count); + a1->resource_hashes.begin = resource_hashes; + a1->resource_hashes.end = resource_hashes + count; + a1->resource_hashes.capacity_end = resource_hashes + count; if (!resource_hashes) return false; @@ -87,154 +88,95 @@ bool FASTCALL glitter_texture_hashes_unpack_file(glitter_effect_group* a1, f2_st return true; } -bool FASTCALL glitter_texture_resource_pack_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian) { - if (!a1->resources_tex) +bool FASTCALL glitter_texture_resource_pack_file(glitter_effect_group* a1, f2_struct* st) { + if (a1->resources_tex.end - a1->resources_tex.begin < 1) return false; memset(st, 0, sizeof(f2_struct)); - txp_pack_file(a1->resources_tex, &st->data, &st->length, use_big_endian); + if (!tex_set_produce_enrs(&a1->resources_tex, &st->enrs)) + return false; + + tex_set_pack_file(&a1->resources_tex, &st->data, &st->length, false); st->header.signature = 0x43505854; st->header.length = 0x20; - st->header.use_big_endian = use_big_endian ? true : false; + st->header.use_big_endian = false; st->header.use_section_size = true; return true; } bool FASTCALL glitter_texture_resource_unpack_file(glitter_effect_group* a1, f2_struct* st) { - size_t i; - size_t j; - size_t k; - txp_data* tex_data; - txp_sub_data** tex_sub_data; - txp_sub_data* tex_sub_sub_data; - glitter_effect** l; - glitter_effect* effect; - glitter_emitter** m; - glitter_emitter* emitter; - glitter_particle** n; - glitter_particle* particle; - if (!st || !st->header.data_size) return false; - txp* t = txp_init(); - if (!txp_unpack_file(t, st->data, st->header.use_big_endian) || !a1->resources_count || a1->resources_count != t->count) - goto End; - - if (!a1->resources) { - a1->resources = force_malloc_s(sizeof(int32_t), a1->resources_count); - glGenTextures(a1->resources_count, a1->resources); + tex_set_unpack_file(&a1->resources_tex, st->data, st->header.use_big_endian); + return glitter_texture_load(a1); +} - tex_data = t->data; - for (i = 0; i < t->count; i++, tex_data++) { - glBindTexture(GL_TEXTURE_2D, a1->resources[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - tex_data->mipmaps_count > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, tex_data->mipmaps_count - 1); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, 16.0f); - tex_sub_data = tex_data->data; - for (j = 0; j < tex_data->array_size; j++, tex_sub_data++) { - tex_sub_sub_data = *tex_sub_data; - for (k = 0; k < tex_data->mipmaps_count; k++, tex_sub_sub_data++) - load_texture_data(tex_sub_sub_data, (int32_t)k); - break; - } - glGenerateMipmap(GL_TEXTURE_2D); - } - glBindTexture(GL_TEXTURE_2D, 0); - } +bool FASTCALL glitter_texture_load(glitter_effect_group* a1) { + if (!a1->resources_count) + return false; - for (i = 0; i < a1->resources_count; i++) - for (l = a1->effects.begin; l != a1->effects.end; l++) { - effect = *l; - if (!effect) + size_t count = a1->resources_tex.end - a1->resources_tex.begin; + + if (!count || !a1->resources_count || a1->resources_count != count) + return false; + + if (!texture_txp_load(&a1->resources_tex, &a1->resources)) + return false; + + for (glitter_effect** l = a1->effects.begin; l != a1->effects.end; l++) { + if (!*l) + continue; + + glitter_effect* effect = *l; + for (glitter_emitter** m = effect->emitters.begin; m != effect->emitters.end; m++) { + if (!*m) continue; - for (m = effect->emitters.begin; m != effect->emitters.end; m++) { - emitter = *m; - if (!emitter) + glitter_emitter* emitter = *m; + for (glitter_particle** n = emitter->particles.begin; n != emitter->particles.end; n++) { + if (!*n) continue; - for (n = emitter->particles.begin; n != emitter->particles.end; n++) { - particle = *n; - if (!particle) + glitter_particle* particle = *n; + particle->data.texture0 = 0; + particle->data.texture1 = 0; + } + } + } + + for (size_t i = 0; i < a1->resources_count; i++) + for (glitter_effect** l = a1->effects.begin; l != a1->effects.end; l++) { + if (!*l) + continue; + + glitter_effect* effect = *l; + for (glitter_emitter** m = effect->emitters.begin; m != effect->emitters.end; m++) { + if (!*m) + continue; + + glitter_emitter* emitter = *m; + for (glitter_particle** n = emitter->particles.begin; n != emitter->particles.end; n++) { + if (!*n) continue; - if (particle->data.data.tex_hash0 == a1->resource_hashes[i]) - particle->data.data.texture0 = a1->resources[i]; - if (particle->data.data.tex_hash1 == a1->resource_hashes[i]) - particle->data.data.texture1 = a1->resources[i]; + glitter_particle* particle = *n; + if (particle->data.type == GLITTER_PARTICLE_LINE + || particle->data.type == GLITTER_PARTICLE_MESH) + continue; + + if (particle->data.tex_hash0 == a1->resource_hashes.begin[i]) + particle->data.texture0 = a1->resources.begin[i]; + if (particle->data.tex_hash1 == a1->resource_hashes.begin[i]) + particle->data.texture1 = a1->resources.begin[i]; } } } -End: - a1->resources_tex = t; return true; } -static void load_texture_data(txp_sub_data* data, int32_t mipmap) { - switch (data->format) { - case TXP_A8: - glTexImage2D(GL_TEXTURE_2D, mipmap, GL_ALPHA8, data->width, data->height, - 0, GL_ALPHA, GL_UNSIGNED_BYTE, data->data); - break; - case TXP_RGB8: - glTexImage2D(GL_TEXTURE_2D, mipmap, GL_RGB8, data->width, data->height, - 0, GL_RGB, GL_UNSIGNED_BYTE, data->data); - break; - case TXP_RGBA8: - glTexImage2D(GL_TEXTURE_2D, mipmap, GL_RGBA8, data->width, data->height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, data->data); - break; - case TXP_RGB5: - glTexImage2D(GL_TEXTURE_2D, mipmap, GL_RGB5, data->width, data->height, - 0, GL_RGB, GL_UNSIGNED_SHORT_5_5_5_1, data->data); - break; - case TXP_RGB5A1: - glTexImage2D(GL_TEXTURE_2D, mipmap, GL_RGB5_A1, data->width, data->height, - 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, data->data); - break; - case TXP_RGBA4: - glTexImage2D(GL_TEXTURE_2D, mipmap, GL_RGBA4, data->width, data->height, - 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data->data); - break; - case TXP_DXT1: - glCompressedTexImage2D(GL_TEXTURE_2D, mipmap, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - data->width, data->height, 0, data->size, data->data); - break; - case TXP_DXT1a: - glCompressedTexImage2D(GL_TEXTURE_2D, mipmap, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, - data->width, data->height, 0, data->size, data->data); - break; - case TXP_DXT3: - glCompressedTexImage2D(GL_TEXTURE_2D, mipmap, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, - data->width, data->height, 0, data->size, data->data); - break; - case TXP_DXT5: - glCompressedTexImage2D(GL_TEXTURE_2D, mipmap, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, - data->width, data->height, 0, data->size, data->data); - break; - case TXP_ATI1: - glCompressedTexImage2D(GL_TEXTURE_2D, mipmap, GL_COMPRESSED_RED_RGTC1_EXT, - data->width, data->height, 0, data->size, data->data); - break; - case TXP_ATI2: - glCompressedTexImage2D(GL_TEXTURE_2D, mipmap, GL_COMPRESSED_RED_GREEN_RGTC2_EXT, - data->width, data->height, 0, data->size, data->data); - break; - case TXP_L8: - glTexImage2D(GL_TEXTURE_2D, mipmap, GL_LUMINANCE8, data->width, data->height, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data->data); - break; - case TXP_L8A8: - glTexImage2D(GL_TEXTURE_2D, mipmap, GL_LUMINANCE8_ALPHA8, data->width, data->height, - 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data->data); - break; - } +void FASTCALL glitter_texture_unload(glitter_effect_group* a1) { + texture_txp_unload(&a1->resources); } diff --git a/src/CRE/Glitter/texture.h b/src/CRE/Glitter/texture.h index a9c4e3a2..672340c2 100644 --- a/src/CRE/Glitter/texture.h +++ b/src/CRE/Glitter/texture.h @@ -7,7 +7,9 @@ #include "glitter.h" -extern bool FASTCALL glitter_texture_hashes_pack_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian); +extern bool FASTCALL glitter_texture_hashes_pack_file(glitter_effect_group* a1, f2_struct* st); extern bool FASTCALL glitter_texture_hashes_unpack_file(glitter_effect_group* a1, f2_struct* st); -extern bool FASTCALL glitter_texture_resource_pack_file(glitter_effect_group* a1, f2_struct* st, bool use_big_endian); +extern bool FASTCALL glitter_texture_resource_pack_file(glitter_effect_group* a1, f2_struct* st); extern bool FASTCALL glitter_texture_resource_unpack_file(glitter_effect_group* a1, f2_struct* st); +extern bool FASTCALL glitter_texture_load(glitter_effect_group* a1); +extern void FASTCALL glitter_texture_unload(glitter_effect_group* a1); diff --git a/src/CRE/GlitterX/curve_x.h b/src/CRE/GlitterX/curve_x.h new file mode 100644 index 00000000..df578d38 --- /dev/null +++ b/src/CRE/GlitterX/curve_x.h @@ -0,0 +1,11 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../Glitter/glitter.h" + +extern bool FASTCALL glitter_x_curve_get_value(GPM, glitter_curve* c, + float_t frame, float_t* value, int32_t random_value, glitter_random* random); diff --git a/src/CRE/GlitterX/curve_x_get_value.c b/src/CRE/GlitterX/curve_x_get_value.c new file mode 100644 index 00000000..5164b683 --- /dev/null +++ b/src/CRE/GlitterX/curve_x_get_value.c @@ -0,0 +1,198 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "curve_x.h" +#include "../Glitter/random.h" + +static void FASTCALL glitter_x_curve_get_key_indexes(vector_glitter_curve_key* keys, + float_t frame, size_t* curr, size_t* next); +static float_t FASTCALL glitter_x_curve_interpolate(GPM, glitter_curve* c, float_t frame, + glitter_curve_key* curr, glitter_curve_key* next, glitter_key_type key_type, glitter_random* random); +static float_t FASTCALL glitter_x_curve_randomize(GPM, + glitter_curve* c, float_t value, glitter_random* random); +static float_t FASTCALL glitter_x_curve_randomize_key(GPM, + glitter_curve* c, glitter_curve_key* key, glitter_random* random); + +bool FASTCALL glitter_x_curve_get_value(GPM, glitter_curve* c, + float_t frame, float_t* value, int32_t random_value, glitter_random* random) { + size_t keys_count; + int32_t random_val; + bool negate; + float_t _value; + + keys_count = c->keys.end - c->keys.begin; + if (!keys_count) + return false; + + random_val = glitter_random_get_value(random); + glitter_random_set_value(random, random_value); + negate = c->flags & GLITTER_CURVE_NEGATE + && glitter_random_get_int_min_max(GPM_VAL, random, 0, 0xFFFF) > 0x7FFF; + if (c->flags & GLITTER_CURVE_STEP) + glitter_random_set_value(random, random_val + 1); + + if (keys_count == 1) { + glitter_curve_key* curr_key = &c->keys.begin[keys_count - 1]; + _value = glitter_x_curve_randomize_key(GPM_VAL, c, curr_key, random); + goto End; + } + + float_t start_time = (float_t)c->start_time; + float_t end_time = (float_t)c->end_time; + if (c->repeat && (start_time > frame || frame >= end_time)) { + float_t t = (frame - start_time) / (end_time - start_time); + t = t <= 0.0f ? (float_t)(int32_t)t - 1.0f : (float_t)(int32_t)t; + frame -= t * (end_time - start_time); + } + + if (end_time <= frame) { + glitter_curve_key* key = &c->keys.begin[keys_count - 1]; + _value = glitter_x_curve_randomize_key(GPM_VAL, c, key, random); + } + else if (start_time > frame) { + glitter_curve_key* key = &c->keys.begin[0]; + _value = glitter_x_curve_randomize_key(GPM_VAL, c, key, random); + } + else if (c->flags & GLITTER_CURVE_BAKED) { + size_t key_index; + if (frame >= end_time) + key_index = keys_count - 1; + else if (frame > start_time) { + key_index = (size_t)frame - c->start_time; + if (~c->flags & GLITTER_CURVE_BAKED_FULL) + key_index /= 2; + + if (key_index >= keys_count) + key_index = keys_count - 1; + } + else + key_index = 0; + + glitter_curve_key* key = &c->keys.begin[key_index]; + _value = glitter_x_curve_randomize_key(GPM_VAL, c, key, random); + } + else { + size_t curr_key_index = 0; + size_t next_key_index = 0; + if (keys_count > 3) + glitter_x_curve_get_key_indexes(&c->keys, frame, &curr_key_index, &next_key_index); + else if (keys_count == 3 && frame >= c->keys.begin[1].frame) { + curr_key_index = 1; + next_key_index = 2; + } + else { + curr_key_index = 0; + next_key_index = 1; + } + glitter_curve_key* curr_key = &c->keys.begin[curr_key_index]; + glitter_curve_key* next_key = &c->keys.begin[next_key_index]; + _value = glitter_x_curve_interpolate(GPM_VAL, c, frame, curr_key, next_key, curr_key->type, random); + } + +End: + _value = glitter_x_curve_randomize(GPM_VAL, c, _value, random); + *value = negate ? -_value : _value; + glitter_random_set_value(random, random_val + 1); + return true; +} + +static void FASTCALL glitter_x_curve_get_key_indexes(vector_glitter_curve_key* keys, + float_t frame, size_t* curr, size_t* next) { + size_t v4; + glitter_curve_key* v6; + size_t count; + size_t v9; + size_t v10; + + count = keys->end - keys->begin; + if (count <= 1) { + *curr = 0; + *next = 0; + return; + } + + v4 = 0; + v6 = keys->begin; + v9 = count - 1; + v10 = v9 / 2; + while (v4 <= v9) { + v10 = (v9 + v4) / 2; + if (frame <= v6[(v10 + 1) % count].frame) { + if (frame >= v6[v10].frame) + goto LABEL_12; + v9 = v10 - 1; + } + else + v4 = v10 + 1; + } + + if (frame > v6[v10].frame) { + LABEL_12: + *curr = v10; + *next = v10 + 1; + } + else { + *curr = v10 - 1; + *next = v10; + } + *next %= count; +} + +static float_t FASTCALL glitter_x_curve_interpolate(GPM, glitter_curve* c, float_t frame, + glitter_curve_key* curr, glitter_curve_key* next, glitter_key_type key_type, glitter_random* random) { + float_t next_val; + float_t curr_val; + float_t val; + + if (key_type == GLITTER_KEY_CONSTANT) + return glitter_x_curve_randomize_key(GPM_VAL, c, curr, random); + + float_t df = frame - (float_t)curr->frame; + float_t t = df / (float_t)(next->frame - curr->frame); + if (key_type == GLITTER_KEY_HERMITE) { + float_t t_1 = t - 1.0f; + next_val = glitter_x_curve_randomize_key(GPM_VAL, c, next, random); + curr_val = glitter_x_curve_randomize_key(GPM_VAL, c, curr, random); + val = glitter_x_curve_randomize_key(GPM_VAL, c, curr, random); + val += t * t * (3.0f - 2.0f * t) * (next_val - curr_val) + + (t_1 * curr->tangent2 + t * next->tangent1) * df * t_1; + } + else { + curr_val = glitter_x_curve_randomize_key(GPM_VAL, c, curr, random); + next_val = glitter_x_curve_randomize_key(GPM_VAL, c, next, random); + val = curr_val + (next_val - curr_val) * t; + } + return val; +} + +static float_t FASTCALL glitter_x_curve_randomize(GPM, + glitter_curve* c, float_t value, glitter_random* random) { + float_t rand; + + if (~c->flags & GLITTER_CURVE_RANDOM_RANGE) + return value; + + rand = glitter_random_get_float_min_max(GPM_VAL, random, + c->flags & GLITTER_CURVE_RANDOM_RANGE_NEGATE ? -c->random_range : 0.0f, c->random_range); + + if (c->flags & GLITTER_CURVE_RANDOM_RANGE_MULT) + rand *= value * 0.01f; + return rand + value; +} + +static float_t FASTCALL glitter_x_curve_randomize_key(GPM, + glitter_curve* c, glitter_curve_key* key, glitter_random* random) { + float_t rand; + + if (~c->flags & GLITTER_CURVE_KEY_RANDOM_RANGE) + return key->value; + + rand = glitter_random_get_float_min_max(GPM_VAL, random, + c->flags & GLITTER_CURVE_RANDOM_RANGE_NEGATE ? -key->random_range : 0.0f, key->random_range); + + if (c->flags & GLITTER_CURVE_RANDOM_RANGE_MULT) + rand *= key->value * 0.01f; + return rand + key->value; +} diff --git a/src/CRE/GlitterX/effect_inst_x.c b/src/CRE/GlitterX/effect_inst_x.c new file mode 100644 index 00000000..a52d230d --- /dev/null +++ b/src/CRE/GlitterX/effect_inst_x.c @@ -0,0 +1,56 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "effect_inst_x.h" +#include "../Glitter/counter.h" +#include "../Glitter/random.h" +#include "curve_x.h" +#include "emitter_inst_x.h" +#include "render_group_x.h" + +static int32_t FASTCALL glitter_x_effect_inst_get_ext_anim_bone_index(int32_t index); + +static int32_t FASTCALL glitter_x_effect_inst_get_ext_anim_bone_index(int32_t index) { + switch (index) { + case 0: + return 15; + case 1: + return 54; + case 2: + return 0; + case 3: + return 7; + case 4: + return 98; + case 5: + return 100; + case 6: + return 101; + case 7: + return 115; + case 8: + return 132; + case 9: + return 136; + case 10: + return 137; + case 11: + return 151; + case 12: + return 186; + case 13: + return 176; + case 14: + return 175; + case 15: + return 189; + case 16: + return 183; + case 17: + return 182; + default: + return 193; + } +} \ No newline at end of file diff --git a/src/CRE/GlitterX/effect_inst_x.h b/src/CRE/GlitterX/effect_inst_x.h new file mode 100644 index 00000000..f90d5a6f --- /dev/null +++ b/src/CRE/GlitterX/effect_inst_x.h @@ -0,0 +1,8 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../Glitter/glitter.h" diff --git a/src/CRE/GlitterX/emitter_inst_x.c b/src/CRE/GlitterX/emitter_inst_x.c new file mode 100644 index 00000000..59930126 --- /dev/null +++ b/src/CRE/GlitterX/emitter_inst_x.c @@ -0,0 +1,12 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "emitter_inst_x.h" +#include "../Glitter/random.h" +#include "curve_x.h" +#include "particle_inst_x.h" +#include "../camera.h" + +extern camera* cam; diff --git a/src/CRE/GlitterX/emitter_inst_x.h b/src/CRE/GlitterX/emitter_inst_x.h new file mode 100644 index 00000000..f90d5a6f --- /dev/null +++ b/src/CRE/GlitterX/emitter_inst_x.h @@ -0,0 +1,8 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../Glitter/glitter.h" diff --git a/src/CRE/GlitterX/locus_history_x.c b/src/CRE/GlitterX/locus_history_x.c new file mode 100644 index 00000000..a3604c34 --- /dev/null +++ b/src/CRE/GlitterX/locus_history_x.c @@ -0,0 +1,64 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "locus_history_x.h" + +glitter_locus_history* FASTCALL glitter_x_locus_history_init(size_t size) { + glitter_locus_history* lh = force_malloc(sizeof(glitter_locus_history)); + vector_glitter_locus_history_data_append(&lh->data, size); + return lh; +} + +void FASTCALL glitter_x_locus_history_append(GPM, glitter_locus_history* a1, + glitter_render_element* a2, glitter_particle_inst* a3) { + glitter_locus_history_data* data; + glitter_locus_history_data locus_history; + glitter_emitter_inst* emitter; + ssize_t size; + ssize_t i; + vec3 temp; + vec3 temp1; + + data = a1->data.begin; + size = a1->data.end - a1->data.begin; + temp = a2->translation; + if (a3->data.data.flags & GLITTER_PARTICLE_EMITTER_LOCAL && (emitter = a3->data.emitter)) { + vec3 emit_trans; + mat4_get_translation(&emitter->mat, &emit_trans); + vec3_add(temp, emit_trans, temp); + if (glt_type == GLITTER_X && a3->data.emitter + && a3->data.data.flags & GLITTER_PARTICLE_ROTATE_LOCUS) + mat4_mult_vec3(&a3->data.emitter->mat_no_scale, &temp, &temp); + } + + locus_history.color = a2->color; + locus_history.translation = temp; + locus_history.scale = a2->scale_particle.x * a2->scale.x * a2->scale_all; + if (size < 1) + vector_glitter_locus_history_data_push_back(&a1->data, &locus_history); + else if (size == 1) { + locus_history.translation = data->translation; + if (a1->data.capacity_end - a1->data.begin > 1) + vector_glitter_locus_history_data_push_back(&a1->data, &locus_history); + data->translation = temp; + } + else { + temp1 = data[size - 1].translation; + + for (i = size - 1; i > 0; i--) + data[i].translation = data[i - 1].translation; + + if (size < a1->data.capacity_end - a1->data.begin) { + locus_history.translation = temp1; + vector_glitter_locus_history_data_push_back(&a1->data, &locus_history); + } + data->translation = temp; + } +} + +void FASTCALL glitter_x_locus_history_dispose(glitter_locus_history* lh) { + vector_glitter_locus_history_data_free(&lh->data); + free(lh); +} diff --git a/src/CRE/GlitterX/locus_history_x.h b/src/CRE/GlitterX/locus_history_x.h new file mode 100644 index 00000000..e4b59e40 --- /dev/null +++ b/src/CRE/GlitterX/locus_history_x.h @@ -0,0 +1,13 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../Glitter/glitter.h" + +extern glitter_locus_history* FASTCALL glitter_x_locus_history_init(size_t size); +extern void FASTCALL glitter_x_locus_history_append(GPM, glitter_locus_history* a1, + glitter_render_element* a2, glitter_particle_inst* a3); +extern void FASTCALL glitter_x_locus_history_dispose(glitter_locus_history* lh); diff --git a/src/CRE/GlitterX/particle_inst_x.c b/src/CRE/GlitterX/particle_inst_x.c new file mode 100644 index 00000000..25be49cb --- /dev/null +++ b/src/CRE/GlitterX/particle_inst_x.c @@ -0,0 +1,8 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "particle_inst_x.h" +#include "effect_inst_x.h" +#include "render_group_x.h" diff --git a/src/CRE/GlitterX/particle_inst_x.h b/src/CRE/GlitterX/particle_inst_x.h new file mode 100644 index 00000000..f90d5a6f --- /dev/null +++ b/src/CRE/GlitterX/particle_inst_x.h @@ -0,0 +1,8 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../Glitter/glitter.h" diff --git a/src/CRE/GlitterX/render_element_x.c b/src/CRE/GlitterX/render_element_x.c new file mode 100644 index 00000000..58ed3c5c --- /dev/null +++ b/src/CRE/GlitterX/render_element_x.c @@ -0,0 +1,12 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "render_element_x.h" +#include "../Glitter/counter.h" +#include "../Glitter/random.h" +#include "curve_x.h" +#include "emitter_inst_x.h" +#include "locus_history_x.h" +#include "particle_inst_x.h" diff --git a/src/CRE/GlitterX/render_element_x.h b/src/CRE/GlitterX/render_element_x.h new file mode 100644 index 00000000..f90d5a6f --- /dev/null +++ b/src/CRE/GlitterX/render_element_x.h @@ -0,0 +1,8 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../Glitter/glitter.h" diff --git a/src/CRE/GlitterX/render_group_x.c b/src/CRE/GlitterX/render_group_x.c new file mode 100644 index 00000000..0dc086c3 --- /dev/null +++ b/src/CRE/GlitterX/render_group_x.c @@ -0,0 +1,16 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "emitter_inst_x.h" +#include "../Glitter/random.h" +#include "render_group_x.h" +#include "render_element_x.h" +#include "../camera.h" +#include "../shader.h" +#include "../shared.h" +#include "../static_var.h" + +extern camera* cam; +extern shader_fbo particle_shader; diff --git a/src/CRE/GlitterX/render_group_x.h b/src/CRE/GlitterX/render_group_x.h new file mode 100644 index 00000000..f90d5a6f --- /dev/null +++ b/src/CRE/GlitterX/render_group_x.h @@ -0,0 +1,8 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../Glitter/glitter.h" diff --git a/src/CRE/camera.c b/src/CRE/camera.c index c4a24551..83b88bd2 100644 --- a/src/CRE/camera.c +++ b/src/CRE/camera.c @@ -10,28 +10,28 @@ camera* camera_init() { return c; } -void camera_update_focal_length(camera* c); -void camera_rebuild_projection(camera* c); -void camera_calculate_rotation(camera* c); -void camera_calculate(camera* c); +static void camera_calculate_projection(camera* c); +static void camera_calculate_view(camera* c); +static void camera_calculate_forward(camera* c); void camera_initialize(camera* c, double_t aspect, double_t fov) { c->aspect = aspect; c->fov = fov; - c->up = (vec3){ 0.0f, 1.0f, 0.0f }; - c->position = vec3_null; - c->target = (vec3){ 0.0f, 0.0f, -1.0f }; + c->view_point = (vec3){ 0.0, 0.0f, 0.0f }; + c->interest = (vec3){ 0.0f, 0.0f, -1.0f }; c->view = mat4_identity; c->projection = mat4_identity; c->view_projection = mat4_identity; + c->inv_projection = mat4_identity; + c->inv_view = mat4_identity; c->min_distance = 0.05; c->max_distance = 6000.0; + c->changed_proj = true; + c->changed_view = true; camera_set_pitch(c, 0.0); camera_set_yaw(c, 0.0); camera_set_roll(c, 0.0); - camera_calculate_rotation(c); - camera_rebuild_projection(c); - camera_calculate(c); + camera_update(c); } double_t camera_get_min_distance(camera* c) { @@ -41,7 +41,7 @@ double_t camera_get_min_distance(camera* c) { void camera_set_min_distance(camera* c, double_t value) { if (value != c->min_distance) { c->min_distance = value; - camera_rebuild_projection(c); + c->changed_proj = true; } } @@ -52,63 +52,10 @@ double_t camera_get_max_distance(camera* c) { void camera_set_max_distance(camera* c, double_t value) { if (value != c->max_distance) { c->max_distance = value; - camera_rebuild_projection(c); + c->changed_proj = true; } } -double_t camera_get_camera_aperture_w(camera* c) { - return c->camera_aperture_w; -} - -void camera_set_camera_aperture_w(camera* c, double_t value) { - if (value != c->camera_aperture_w) { - c->camera_aperture_w = value; - camera_rebuild_projection(c); - } -} - -double_t camera_get_camera_aperture_h(camera* c) { - return c->camera_aperture_h; -} - -void camera_set_camera_aperture_h(camera* c, double_t value) { - if (value != c->camera_aperture_h) { - c->camera_aperture_h = value; - camera_rebuild_projection(c); - } -} - -double_t camera_get_focal_length(camera* c) { - return c->focal_length; -} - -void camera_set_focal_length(camera* c, double_t value) { - if (value != c->focal_length) { - c->focal_length = value; - camera_rebuild_projection(c); - } -} - -bool camera_get_fov_horizontal(camera* c) { - return c->fov_horizontal; -} - -void camera_set_fov_horizontal(camera* c, bool value) { - if (value != c->fov_horizontal) { - c->fov_horizontal = value; - camera_rebuild_projection(c); - } -} - -void camera_update_focal_length(camera* c) { - camera_set_aspect(c, c->camera_aperture_w / c->camera_aperture_h); - if (c->camera_aperture_w == 0 || c->camera_aperture_h == 0 || c->focal_length == 0) - return; - - c->fov = atan(c->camera_aperture_h * 12.7 / c->focal_length); - camera_set_fov(c, c->fov * 180.0 / M_PI * 2.0); -} - double_t camera_get_aspect(camera* c) { return c->aspect; } @@ -116,7 +63,7 @@ double_t camera_get_aspect(camera* c) { void camera_set_aspect(camera* c, double_t value) { if (value != c->aspect) { c->aspect = value; - camera_rebuild_projection(c); + c->changed_proj = true; } } @@ -128,46 +75,24 @@ void camera_set_fov(camera* c, double_t value) { value = clamp(value, 1.0, 180.0); if (value != c->fov) { c->fov = value; - camera_rebuild_projection(c); + c->changed_proj = true; } } -void camera_rebuild_projection(camera* c) { - double_t fov = c->fov; - if (c->fov_horizontal) - fov = 2.0 * atan(1.0 / c->aspect * tan(fov * 0.5)); - fov = fov * M_PI / 180.0; - - double_t max_y = c->min_distance * tan(fov * 0.5); - double_t min_y = -max_y; - double_t max_x = max_y * c->aspect; - double_t min_x = min_y * c->aspect; - - double_t x = max_x - min_x; - double_t y = max_y - min_y; - double_t a = (max_x + min_x) / x; - double_t b = (max_y + min_y) / y; - double_t e = c->max_distance - c->min_distance; - double_t d = -(2.0f * c->max_distance * c->min_distance) / e; - - x = 2.0f * c->min_distance / x; - y = 2.0f * c->min_distance / y; - e = -(c->max_distance + c->min_distance) / e; - - c->projection.row0 = (vec4){ (float_t)x, 0.0f, 0.0f, 0.0f }; - c->projection.row1 = (vec4){ 0.0f, (float_t)y, 0.0f, 0.0f }; - c->projection.row2 = (vec4){ (float_t)a, (float_t)b, (float_t)e, -1.0f }; - c->projection.row3 = (vec4){ 0.0f, 0.0f, (float_t)d, 0.0f }; - - mat4_mult(&c->view, &c->projection, &c->view_projection); -} - double_t camera_get_pitch(camera* c) { return c->pitch; } void camera_set_pitch(camera* c, double_t value) { - c->pitch = clamp(value, -89.5, 89.5); + while (value > 180.0) + value -= 360.0; + while (value < -180.0) + value += 360.0; + value = clamp(value, -89.5, 89.5); + if (c->pitch != value) { + c->pitch = value; + c->changed_view = true; + } } double_t camera_get_yaw(camera* c) { @@ -179,11 +104,15 @@ void camera_set_yaw(camera* c, double_t value) { value -= 360.0; while (value < -180.0) value += 360.0; - c->yaw = value - 90.0; + value -= 90.0; + if (c->yaw != value) { + c->yaw = value; + c->changed_view = true; + } } double_t camera_get_roll(camera* c) { - return c->roll; + return -c->roll; } void camera_set_roll(camera* c, double_t value) { @@ -191,132 +120,181 @@ void camera_set_roll(camera* c, double_t value) { value -= 360.0; while (value < -180.0) value += 360.0; - c->roll = value; + value = -value; + if (c->roll != value) { + c->roll = value; + c->changed_view = true; + } +} + +void camera_get_view_point(camera* c, vec3* value) { + +} + +void camera_set_view_point(camera* c, vec3* value) { + if (c->view_point.x != value->x + || c->view_point.y != value->y + || c->view_point.z != value->z) { + c->view_point = *value; + c->changed_view = true; + } +} + +void camera_get_interest_point(camera* c, vec3* value) { + *value = c->interest; +} + +void camera_set_interest_point(camera* c, vec3* value) { + if (c->interest.x != value->x + || c->interest.y != value->y + || c->interest.z != value->z) { + c->interest = *value; + c->changed_view = true; + } } void camera_reset(camera* c) { camera_set_pitch(c, 0.0); camera_set_yaw(c, 0.0); camera_set_roll(c, 0.0); - c->position = vec3_null; - camera_calculate_rotation(c); - camera_calculate(c); + camera_calculate_forward(c); + camera_set_position(c, &(vec3){ 0.0, 0.0f, 0.0f}); + camera_update(c); } -void camera_set_point(camera* c, vec3* view_point, vec3* interest_point, - vec3* trans, vec3* rot, vec3* scale, double_t roll, double_t fov) { - if (fov > 0.0) - camera_set_fov(c, fov); - - while (roll > 180.0) - roll -= 360.0; - while (roll < -180.0) - roll += 360.0; - c->position = *view_point; - c->target = *interest_point; - c->up.x = (float_t)sin(-c->roll * 180.0 / M_PI); - c->up.y = (float_t)cos(c->roll * 180.0 / M_PI); - c->up.z = 0; - - mat4 trans_rot = mat4_identity; - mat4_rotate_x_mult(&trans_rot, (float_t)rot->x, &trans_rot); - mat4_rotate_y_mult(&trans_rot, (float_t)rot->y, &trans_rot); - mat4_rotate_z_mult(&trans_rot, (float_t)rot->z, &trans_rot); - trans_rot.row3 = (vec4){ trans->x, trans->y, trans->z, 1.0f }; - - /* - mat4* cam = mat4::CreateScale(scale) * transRot; - c->position = new vec3(new Vector4(c->position, 1) * cam); - c->target = new vec3(new Vector4(c->target, 1) * cam); - vec3 tempVar(new Vector4(c->up, 1) * cam); - c->up = (&tempVar)->NormalizeAlt();*/ - camera_set(c, &c->position, &c->target, &c->up); -} - -void camera_set(camera* c, vec3* eye, vec3* target, vec3* up) { - camera_look_at(c, eye, target, up, &c->view); - mat4_mult(&c->view, &c->projection, &c->view_projection); -} - -void camera_rotate_vec2(camera* c, vec2* rotate) { - if (rotate->x != 0 || rotate->y != 0) { - camera_set_yaw(c, camera_get_yaw(c) + rotate->x); - camera_set_pitch(c, camera_get_pitch(c) + rotate->y); - camera_calculate_rotation(c); - camera_calculate(c); - } -} - -void camera_move_vec2(camera* c, vec2* move) { - if (move->x != 0 || move->y != 0) { +void camera_move(camera* c, vec2d* move) { + if (move->x != 0.0 || move->y != 0.0) { vec3 temp; - vec3_cross(c->forward, c->up, temp); + vec3 view_point; + vec3 interest; + vec3_cross(c->forward, ((vec3) { 0.0f, 1.0f, 0.0f}), temp); vec3_normalize(temp, temp); - vec3_mult_scalar(temp, move->y, temp); - vec3_add(c->position, temp, c->position); - vec3_mult_scalar(c->forward, move->x, temp); - vec3_add(c->position, temp, c->position); - camera_calculate(c); + vec3_mult_scalar(temp, (float_t)move->y, temp); + vec3_add(c->view_point, temp, view_point); + vec3_mult_scalar(c->forward, (float_t)move->x, temp); + vec3_add(view_point, temp, view_point); + + vec3_add(view_point, c->forward, interest); + camera_set_view_point(c, &view_point); + camera_set_interest_point(c, &interest); } } -void camera_move_vec3(camera* c, vec3* move) { - if (move->x != 0 || move->y != 0 || move->z != 0) { - c->position = *move; - camera_calculate(c); +void camera_rotate(camera* c, vec2d* rotate) { + if (rotate->x != 0.0) + camera_set_yaw(c, camera_get_yaw(c) + rotate->x); + + if (rotate->y != 0.0) + camera_set_pitch(c, camera_get_pitch(c) + rotate->y); + + if (rotate->x != 0.0 || rotate->y != 0.0) { + camera_calculate_forward(c); + + vec3 interest; + vec3_add(c->view_point, c->forward, interest); + camera_set_interest_point(c, &interest); } } -void camera_calculate_rotation(camera* c) { - c->right.x = 0; - c->right.y = (float_t)cos(c->pitch * M_PI / 180.0); - c->right.z = (float_t)sin(c->pitch * M_PI / 180.0); - c->forward.x = (float_t)(cos(c->pitch * M_PI / 180.0) * cos(c->yaw * M_PI / 180.0)); - c->forward.y = (float_t)sin(c->pitch * M_PI / 180.0); - c->forward.z = (float_t)(cos(c->pitch * M_PI / 180.0) * sin(c->yaw * M_PI / 180.0)); - //c->up.x = (float_t)sin(c->roll * M_PI / 180.0); - //c->up.y = (float_t)cos(c->roll * M_PI / 180.0); - //c->up.z = 0; +void camera_roll(camera* c, double_t roll) { + if (roll != 0.0f) + camera_set_roll(c, camera_get_roll(c) + roll); } -void camera_calculate(camera* c) { - vec3_add(c->position, c->forward, c->target); - camera_look_at(c, &c->position, &c->target, &c->up, &c->view); - mat4_mult(&c->view, &c->projection, &c->view_projection); +void camera_set(camera* c, vec3* view_point, vec3* interest, + vec3* trans, vec3* rot, vec3* scale, double_t roll, double_t fov) { + vec3 _vp; + vec3 _int; + double_t _roll; + double_t _fov; + + _vp = *view_point; + _int = *interest; + _roll = roll; + _fov = fov; + while (_roll > 180.0) + _roll -= 360.0; + while (_roll < -180.0) + _roll += 360.0; + + mat4 cam; + mat4_translate(trans->x, trans->y, trans->z, &cam); + mat4_rotate_mult(&cam, rot->x, rot->y, rot->z, &cam); + mat4_scale_rot(&cam, scale->x, scale->y, scale->z, &cam); + mat4_mult_vec3_trans(&cam, &_vp, &_vp); + mat4_mult_vec3_trans(&cam, &_int, &_int); + + camera_set_view_point(c, &_vp); + camera_set_interest_point(c, &_int); + camera_set_roll(c, _roll); + camera_set_fov(c, _fov); } -void camera_look_at(camera* c, vec3* eye, vec3* target, vec3* up, mat4* view) { - vec3 x, y, z; - float_t t; - vec3 xyz; +void camera_set_position(camera* c, vec3* pos) { + vec3 interest; + vec3_add(*pos, c->forward, interest); + camera_set_view_point(c, pos); + camera_set_interest_point(c, &interest); +} - vec3_sub(*eye, *target, z); - vec3_normalize(z, z); +void camera_update(camera* c) { + if (c->changed_proj) + camera_calculate_projection(c); - vec3_cross(*up, z, x); - vec3_normalize(x, x); - vec3_length(x, t); - if (t == 0.0f) - x = (vec3){ 1.0f, 0.0f, 0.0f }; - vec3_cross(z, x, y); - vec3_normalize(y, y); + if (c->changed_view) + camera_calculate_view(c); - vec3_dot(x, *eye, xyz.x); - vec3_dot(y, *eye, xyz.y); - vec3_dot(z, *eye, xyz.z); - view->row0 = (vec4){ x.x, y.x, z.x, 0.0f }; - view->row1 = (vec4){ x.y, y.y, z.y, 0.0f }; - view->row2 = (vec4){ x.z, y.z, z.z, 0.0f }; - *(vec3*)&view->row3 = xyz; - view->row3.w = -1.0f; - vec4_negate(view->row3, view->row3); - - c->rotation.x = asinf(view->row1.z); - c->rotation.y = atan2f(-view->row0.z, view->row2.z); - c->rotation.z = atan2f(-view->row1.x, view->row1.y); - vec3_negate(c->rotation, c->rotation); + if (c->changed_proj || c->changed_view) { + mat4_mult(&c->view, &c->projection, &c->view_projection); + c->changed_proj = false; + c->changed_view = false; + c->updated = true; + } + else + c->updated = false; } void camera_dispose(camera* c) { free(c); } + +static void camera_calculate_forward(camera* c) { + c->forward.x = (float_t)(cos(c->pitch * DEG_TO_RAD) * cos(c->yaw * DEG_TO_RAD)); + c->forward.y = (float_t)sin(c->pitch * DEG_TO_RAD); + c->forward.z = (float_t)(cos(c->pitch * DEG_TO_RAD) * sin(c->yaw * DEG_TO_RAD)); +} + +static void camera_calculate_projection(camera* c) { + double_t tan_fov = tan(c->fov * 0.5); + + double_t max_d = c->max_distance; + double_t min_d = c->min_distance; + + double_t x = 1.0 / (c->aspect * tan_fov); + double_t y = 1.0 / tan_fov; + double_t d = -(2.0 * max_d * min_d) / (max_d - min_d); + double_t e = -(max_d + min_d) / (max_d - min_d); + + c->projection.row0 = (vec4){ (float_t)x, 0.0f, 0.0f, 0.0f }; + c->projection.row1 = (vec4){ 0.0f, (float_t)y, 0.0f, 0.0f }; + c->projection.row2 = (vec4){ 0.0f, 0.0f, (float_t)e, -1.0f }; + c->projection.row3 = (vec4){ 0.0f, 0.0f, (float_t)d, 0.0f }; + + mat4_inverse(&c->projection, &c->inv_projection); +} + +static void camera_calculate_view(camera* c) { + vec3 dist; + vec3_sub(c->view_point, c->interest, dist); + c->rotation.x = atan2f(-dist.y, sqrtf(dist.x * dist.x + dist.z * dist.z)); + c->rotation.y = atan2f(dist.x, dist.z); + c->rotation.z = (float_t)(c->roll * DEG_TO_RAD); + c->view = mat4_identity; + mat4_rot_z(&c->view, -c->rotation.z, &c->view); + mat4_rot_x(&c->view, -c->rotation.x, &c->view); + mat4_rot_y(&c->view, -c->rotation.y, &c->view); + mat4_translate_mult(&c->view, -c->view_point.x, -c->view_point.y, -c->view_point.z, &c->view); + mat4_inverse(&c->view, &c->inv_view); + mat3_from_mat4(&c->view, &c->view_mat3); + mat3_inverse(&c->view_mat3, &c->inv_view_mat3); +} diff --git a/src/CRE/camera.h b/src/CRE/camera.h index aec25622..4f38a2b0 100644 --- a/src/CRE/camera.h +++ b/src/CRE/camera.h @@ -13,23 +13,24 @@ typedef struct camera { mat4 view; mat4 projection; mat4 view_projection; - vec3 position; - vec3 target; - vec3 up; - vec3 right; + mat4 inv_projection; + mat4 inv_view; + mat3 view_mat3; + mat3 inv_view_mat3; vec3 forward; vec3 rotation; + vec3 view_point; + vec3 interest; double_t yaw; double_t pitch; double_t roll; - double_t camera_aperture_w; - double_t camera_aperture_h; double_t aspect; - double_t focal_length; double_t fov; - bool fov_horizontal; double_t max_distance; double_t min_distance; + bool changed_proj; + bool changed_view; + bool updated; } camera; extern camera* camera_init(); @@ -38,14 +39,6 @@ extern double_t camera_get_min_distance(camera* c); extern void camera_set_min_distance(camera* c, double_t value); extern double_t camera_get_max_distance(camera* c); extern void camera_set_max_distance(camera* c, double_t value); -extern double_t camera_get_camera_aperture_w(camera* c); -extern void camera_set_camera_aperture_w(camera* c, double_t value); -extern double_t camera_get_camera_aperture_h(camera* c); -extern void camera_set_camera_aperture_h(camera* c, double_t value); -extern double_t camera_get_focal_length(camera* c); -extern void camera_set_focal_length(camera* c, double_t value); -extern bool camera_get_fov_horizontal(camera* c); -extern void camera_set_fov_horizontal(camera* c, bool value); extern double_t camera_get_aspect(camera* c); extern void camera_set_aspect(camera* c, double_t value); extern double_t camera_get_fov(camera* c); @@ -56,12 +49,16 @@ extern double_t camera_get_yaw(camera* c); extern void camera_set_yaw(camera* c, double_t value); extern double_t camera_get_roll(camera* c); extern void camera_set_roll(camera* c, double_t value); +extern void camera_get_view_point(camera* c, vec3* value); +extern void camera_set_view_point(camera* c, vec3* value); +extern void camera_get_interest_point(camera* c, vec3* value); +extern void camera_set_interest_point(camera* c, vec3* value); extern void camera_reset(camera* c); -extern void camera_set_point(camera* c, vec3* view_point, vec3* interest_point, +extern void camera_move(camera* c, vec2d* move); +extern void camera_rotate(camera* c, vec2d* rotate); +extern void camera_roll(camera* c, double_t roll); +extern void camera_set(camera* c, vec3* view_point, vec3* interest, vec3* trans, vec3* rot, vec3* scale, double_t roll, double_t fov); -extern void camera_set(camera* c, vec3* eye, vec3* target, vec3* up); -extern void camera_rotate_vec2(camera* c, vec2* rotate); -extern void camera_move_vec2(camera* c, vec2* move); -extern void camera_move_vec3(camera* c, vec3* move); -extern void camera_look_at(camera* c, vec3* eye, vec3* target, vec3* up, mat4* view); +extern void camera_set_position(camera* c, vec3* pos); +extern void camera_update(camera* c); extern void camera_dispose(camera* c); diff --git a/src/CRE/dof.c b/src/CRE/dof.c new file mode 100644 index 00000000..8b71e26d --- /dev/null +++ b/src/CRE/dof.c @@ -0,0 +1,108 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "dof.h" + +static const dof_debug dof_debug_default = { + .flags = 0, + .distance_to_focus = 10.0f, + .focal_length = 40.0f, + .f_number = 1.4f, + .f2 = { + .distance_to_focus = 10.0f, + .focus_range = 1.0f, + .fuzzing_range = 0.5f, + .ratio = 1.0f, + }, +}; + +static const dof_pv dof_pv_default = { + .enable = false, + .f2 = { + .distance_to_focus = 10.0f, + .focus_range = 1.0f, + .fuzzing_range = 0.5f, + .ratio = 1.0f, + }, +}; + +static void dof_calculate(dof_struct* d, size_t height, double_t min_dist, double_t max_dist, double_t fov, + float_t dist, float_t focal_length, float_t f_number, float_t focus_range, float_t fuzzing_range, float_t ratio); + +dof_struct* dof_init() { + dof_struct* d = force_malloc(sizeof(dof_struct)); + return d; +} + +void dof_initialize(dof_struct* d, dof_debug* debug, dof_pv* pv) { + if (debug) + d->debug = *debug; + else + d->debug = dof_debug_default; + + if (pv) + d->pv = *pv; + else + d->pv = dof_pv_default; +} + +void dof_get_dof_debug(dof_struct* d, dof_debug* debug) { + if (debug) + *debug = d->debug; +} + +void dof_set_dof_debug(dof_struct* d, dof_debug* debug) { + if (debug) + d->debug = *debug; + else + d->debug = dof_debug_default; +} + +void dof_get_dof_pv(dof_struct* d, dof_pv* pv) { + if (pv) + *pv = d->pv; +} + +void dof_set_dof_pv(dof_struct* d, dof_pv* pv) { + if (pv) + d->pv = *pv; + else + d->pv = dof_pv_default; +} +void dof_calculate_physical(dof_struct* d, size_t height, + double_t min_dist, double_t max_dist, double_t fov, float_t dist, + float_t focal_length, float_t f_number) { + dof_calculate(d, height, min_dist, max_dist, fov, dist, focal_length, f_number, 0.0f, 1.0f, 0.0f); +} + +void dof_calculate_f2(dof_struct* d, size_t height, + double_t min_dist, double_t max_dist, double_t fov, float_t dist, + float_t focus_range, float_t fuzzing_range, float_t ratio) { + dof_calculate(d, height, min_dist, max_dist, fov, dist, 0.0f, 1.0f, focus_range, fuzzing_range, ratio); +} + +void dof_dispose(dof_struct* d) { + free(d); +} + +static void dof_calculate(dof_struct* d, size_t height, double_t min_dist, double_t max_dist, double_t fov, + float_t dist, float_t focal_length, float_t f_number, float_t focus_range, float_t fuzzing_range, float_t ratio) { + double_t fl = (double_t)focal_length; + if (dist <= focal_length) + fl = (double_t)dist + 0.1; + fl = fl * fl * (1.0 / ((dist - fl) * f_number)); + d->data[0] = (float_t)((min_dist - max_dist) / (min_dist * max_dist)); + d->data[1] = (float_t)(1.0 / min_dist); + d->data[2] = -(float_t)(((fl * dist) * (min_dist - max_dist)) * (1.0 / (min_dist * max_dist))); + d->data[3] = (float_t)((1.0 - dist * (1.0 / min_dist)) * fl); + d->data[4] = (float_t)((double_t)height / (tan(fov * 0.5) * 2.0 * min_dist)); + d->data[5] = d->data[4] * (float_t)(1.0 / 3.0); + d->data[6] = (float_t)(1.0 / 3.0); + d->data[7] = 3.0; + d->data[8] = dist; + d->data[9] = focus_range; + d->data[10] = -4.5f / (fuzzing_range * fuzzing_range); + d->data[11] = ratio * 8.0f; +} diff --git a/src/CRE/dof.h b/src/CRE/dof.h new file mode 100644 index 00000000..e759dd72 --- /dev/null +++ b/src/CRE/dof.h @@ -0,0 +1,53 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/default.h" +#include "../KKdLib/mat.h" +#include "../KKdLib/vec.h" + +typedef enum dof_debug_flags { + DOF_DEBUG_USE_UI_PARAMS = 0x1, + DOF_DEBUG_ENABLE_DOF = 0x2, + DOF_DEBUG_ENABLE_PHYS_DOF = 0x4, + DOF_DEBUG_AUTO_FOCUS = 0x8, +} dof_debug_flags; + +typedef struct dof_f2 { + float_t distance_to_focus; + float_t focus_range; + float_t fuzzing_range; + float_t ratio; +} dof_f2; + +typedef struct dof_debug { + dof_debug_flags flags; + float_t distance_to_focus; + float_t focal_length; + float_t f_number; + dof_f2 f2; +} dof_debug; + +typedef struct dof_pv { + bool enable; + dof_f2 f2; +} dof_pv; + +typedef struct dof_struct { + dof_debug debug; + dof_pv pv; + float_t data[12]; +} dof_struct; + +extern dof_struct* dof_init(); +extern void dof_initialize(dof_struct* d, dof_debug* debug, dof_pv* pv); +extern void dof_calculate_physical(dof_struct* d, size_t height, + double_t min_dist, double_t max_dist, double_t fov, float_t dist, + float_t focal_length, float_t f_number); +extern void dof_calculate_f2(dof_struct* d, size_t height, + double_t min_dist, double_t max_dist, double_t fov, float_t dist, + float_t focus_range, float_t fuzzing_range, float_t ratio); +extern void dof_dispose(dof_struct* d); diff --git a/src/CRE/fbo_dof.c b/src/CRE/fbo_dof.c index b407eb3b..c8a299cd 100644 --- a/src/CRE/fbo_dof.c +++ b/src/CRE/fbo_dof.c @@ -53,19 +53,19 @@ static void fbo_dof_bind_fbo(fbo_dof* dfbo, vec2i* res) { dfbo->res_20.x = res->x > 20 ? res->x / 20 : 1; dfbo->res_20.y = res->y > 20 ? res->y / 20 : 1; - glBindFramebuffer(GL_FRAMEBUFFER, dfbo->fbo[0]); + bind_framebuffer(dfbo->fbo[0]); glDrawBuffers(1, fbo_dof_s_attachments); fbo_helper_gen_texture_image_ms(dfbo->tcb[0], dfbo->res_20.x, dfbo->res_20.y, 1, GL_RG16F, GL_RG, GL_HALF_FLOAT, 0); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, dfbo->fbo[1]); + bind_framebuffer(dfbo->fbo[1]); glDrawBuffers(1, fbo_dof_s_attachments); fbo_helper_gen_texture_image_ms(dfbo->tcb[1], dfbo->res_20.x, dfbo->res_20.y, 1, GL_RG16F, GL_RG, GL_HALF_FLOAT, 0); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, dfbo->fbo[2]); + bind_framebuffer(dfbo->fbo[2]); glDrawBuffers(2, fbo_dof_d_attachments); fbo_helper_gen_texture_image_ms(dfbo->tcb[2], dfbo->res_2.x, dfbo->res_2.y, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); @@ -73,17 +73,18 @@ static void fbo_dof_bind_fbo(fbo_dof* dfbo, vec2i* res) { 1, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, 1); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, dfbo->fbo[3]); + bind_framebuffer(dfbo->fbo[3]); glDrawBuffers(2, fbo_dof_d_attachments); fbo_helper_gen_texture_image_ms(dfbo->tcb[4], dfbo->res_2.x, dfbo->res_2.y, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); fbo_helper_gen_texture_image_ms(dfbo->tcb[5], dfbo->res_2.x, dfbo->res_2.y, 1, GL_R16F, GL_RED, GL_HALF_FLOAT, 1); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + bind_framebuffer(0); } -void fbo_dof_draw(fbo_dof* dfbo, int32_t color_tcb, int32_t depth_tcb, int32_t out_fbo, bool dof_f2) { +void fbo_dof_draw(fbo_dof* dfbo, int32_t color_tcb, int32_t depth_tcb, + int32_t out_fbo, bool dof_f2) { if (!dfbo) return; @@ -93,52 +94,39 @@ void fbo_dof_draw(fbo_dof* dfbo, int32_t color_tcb, int32_t depth_tcb, int32_t o glBindBufferBase(GL_UNIFORM_BUFFER, 2, dfbo->texcoords_ubo); glViewport(0, 0, dfbo->res_20.x, dfbo->res_20.y); - glBindFramebuffer(GL_FRAMEBUFFER, dfbo->fbo[0]); + bind_framebuffer(dfbo->fbo[0]); shader_fbo_use(&dfbo->d_shader[o]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, depth_tcb); + bind_index_tex2d(0, depth_tcb); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindFramebuffer(GL_FRAMEBUFFER, dfbo->fbo[1]); + bind_framebuffer(dfbo->fbo[1]); shader_fbo_use(&dfbo->d_shader[o + 1]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, dfbo->tcb[0]); + bind_index_tex2d(0, dfbo->tcb[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, dfbo->res_2.x, dfbo->res_2.y); - glBindFramebuffer(GL_FRAMEBUFFER, dfbo->fbo[2]); + bind_framebuffer(dfbo->fbo[2]); shader_fbo_use(&dfbo->d_shader[o + 2]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, depth_tcb); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, color_tcb); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, dfbo->tcb[1]); + bind_index_tex2d(0, depth_tcb); + bind_index_tex2d(1, color_tcb); + bind_index_tex2d(2, dfbo->tcb[1]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindFramebuffer(GL_FRAMEBUFFER, dfbo->fbo[3]); + bind_framebuffer(dfbo->fbo[3]); shader_fbo_use(&dfbo->d_shader[o + 3]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, dfbo->tcb[3]); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, dfbo->tcb[2]); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, dfbo->tcb[1]); + bind_index_tex2d(0, dfbo->tcb[3]); + bind_index_tex2d(1, dfbo->tcb[2]); + bind_index_tex2d(2, dfbo->tcb[1]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, dfbo->res.x, dfbo->res.y); - glBindFramebuffer(GL_FRAMEBUFFER, out_fbo); + bind_framebuffer(out_fbo); shader_fbo_use(&dfbo->d_shader[o + 4]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, dfbo->tcb[4]); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, dfbo->tcb[5]); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, dfbo->tcb[1]); - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, color_tcb); - glActiveTexture(GL_TEXTURE4); - glBindTexture(GL_TEXTURE_2D, depth_tcb); + bind_index_tex2d(0, dfbo->tcb[4]); + bind_index_tex2d(1, dfbo->tcb[5]); + bind_index_tex2d(2, dfbo->tcb[1]); + bind_index_tex2d(3, color_tcb); + bind_index_tex2d(4, depth_tcb); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } diff --git a/src/CRE/fbo_dof.h b/src/CRE/fbo_dof.h index 1525ab58..30875083 100644 --- a/src/CRE/fbo_dof.h +++ b/src/CRE/fbo_dof.h @@ -28,5 +28,6 @@ extern fbo_dof* fbo_dof_init(); extern void fbo_dof_initialize(fbo_dof* dfbo, vec2i* res, int32_t vao, shader_fbo* d_shader, int32_t dof_common_ubo, int32_t texcoords_ubo); extern void fbo_dof_resize(fbo_dof* dfbo, vec2i* res); -extern void fbo_dof_draw(fbo_dof* dfbo, int32_t color_tcb, int32_t depth_tcb, int32_t out_fbo, bool f2); +extern void fbo_dof_draw(fbo_dof* dfbo, int32_t color_tcb, int32_t depth_tcb, + int32_t out_fbo, bool dof_f2); extern void fbo_dof_dispose(fbo_dof* dfbo); diff --git a/src/CRE/fbo_hdr.c b/src/CRE/fbo_hdr.c index 5aad2f9e..d73f8296 100644 --- a/src/CRE/fbo_hdr.c +++ b/src/CRE/fbo_hdr.c @@ -8,7 +8,7 @@ const GLenum fbo_hdr_c_attachments[] = { GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1, + GL_DEPTH_ATTACHMENT, }; const GLenum fbo_hdr_f_attachments[] = { @@ -49,17 +49,18 @@ static void fbo_hdr_bind_fbo(fbo_hdr* hfbo, vec2i* res, vec2i* res_2d) { hfbo->res_2d.x = res_2d->x > 1 ? res_2d->x : 1; hfbo->res_2d.y = res_2d->y > 1 ? res_2d->y : 1; - glBindFramebuffer(GL_FRAMEBUFFER, hfbo->fbo[0]); + bind_framebuffer(hfbo->fbo[0]); fbo_helper_gen_texture_image_ms(hfbo->tcb[0], hfbo->res.x, hfbo->res.y, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); - fbo_helper_gen_texture_image_ms(hfbo->tcb[1], hfbo->res.x, hfbo->res.y, 1, GL_R16F, GL_RED, GL_HALF_FLOAT, 1); + fbo_helper_gen_texture_image_ms(hfbo->tcb[1], hfbo->res.x, hfbo->res.y, 1, + GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 16); glDrawBuffers(2, fbo_hdr_c_attachments); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, hfbo->fbo[1]); + bind_framebuffer(hfbo->fbo[1]); fbo_helper_gen_texture_image_ms(hfbo->tcb[2], hfbo->res_2d.x, hfbo->res_2d.y, 1, GL_RGBA8, GL_RGBA, GL_BYTE, 0); glDrawBuffers(1, fbo_hdr_f_attachments); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + bind_framebuffer(0); } void fbo_hdr_draw_aa(fbo_hdr* hfbo) { @@ -67,11 +68,10 @@ void fbo_hdr_draw_aa(fbo_hdr* hfbo) { return; glViewport(0, 0, hfbo->res_2d.x, hfbo->res_2d.y); - glBindFramebuffer(GL_FRAMEBUFFER, hfbo->fbo[1]); + bind_framebuffer(hfbo->fbo[1]); shader_fbo_use(&hfbo->h_shader[hfbo->fxaa ? 1 : 0]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, hfbo->tcb[0]); - glBindVertexArray(hfbo->vao); + bind_index_tex2d(0, hfbo->tcb[0]); + bind_vertex_array(hfbo->vao); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -80,9 +80,8 @@ void fbo_hdr_draw(fbo_hdr* hfbo) { return; shader_fbo_use(&hfbo->f_shader); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, hfbo->tcb[2]); - glBindVertexArray(hfbo->vao); + bind_index_tex2d(0, hfbo->tcb[2]); + bind_vertex_array(hfbo->vao); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } diff --git a/src/CRE/fbo_helper.c b/src/CRE/fbo_helper.c index f66127b3..806e09de 100644 --- a/src/CRE/fbo_helper.c +++ b/src/CRE/fbo_helper.c @@ -8,7 +8,7 @@ void fbo_helper_gen_texture_image_ms(int32_t tcb, int32_t width, int32_t height, int32_t samples, GLenum internal_format, GLenum format, GLenum type, int32_t attachment) { if (samples > 1) { - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tcb); + bind_tex2dms(tcb); glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, internal_format, width, height, true); glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -18,7 +18,7 @@ void fbo_helper_gen_texture_image_ms(int32_t tcb, int32_t width, int32_t height, glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { - glBindTexture(GL_TEXTURE_2D, tcb); + bind_tex2d(tcb); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, type, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -28,17 +28,10 @@ void fbo_helper_gen_texture_image_ms(int32_t tcb, int32_t width, int32_t height, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachment, tcb, 0); -} - -void fbo_helper_gen_renderbuffer(int32_t rbo, int32_t width, int32_t height, int32_t samples, GLenum internal_format) { - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - if (samples > 1) - glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internal_format, width, height); - else - glRenderbufferStorage(GL_RENDERBUFFER, internal_format, width, height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); + if (attachment >= 0 && attachment <= 15) + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachment, tcb, 0); + else if (attachment == 16) + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, tcb, 0); } void fbo_helper_get_error_code() { diff --git a/src/CRE/fbo_helper.h b/src/CRE/fbo_helper.h index 73ebf446..90cf66ac 100644 --- a/src/CRE/fbo_helper.h +++ b/src/CRE/fbo_helper.h @@ -6,11 +6,8 @@ #pragma once #include "../KKdLib/default.h" -#define GLEW_STATIC -#include +#include "static_var.h" extern void fbo_helper_gen_texture_image_ms(int32_t tcb, int32_t width, int32_t height, int32_t samples, GLenum internal_format, GLenum format, GLenum type, int32_t attachment); -extern void fbo_helper_gen_renderbuffer(int32_t rbo, int32_t width, - int32_t height, int32_t samples, GLenum internal_format); extern void fbo_helper_get_error_code(); diff --git a/src/CRE/fbo_pp.c b/src/CRE/fbo_pp.c index 8cb3ef57..b4b6037e 100644 --- a/src/CRE/fbo_pp.c +++ b/src/CRE/fbo_pp.c @@ -107,67 +107,68 @@ void fbo_pp_initialize(fbo_pp* pfbo, vec2i* res, int32_t vao, glGenFramebuffers(11, pfbo->fbo); glGenTextures(16, pfbo->tcb); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[0]); + bind_framebuffer(pfbo->fbo[0]); fbo_helper_gen_texture_image_ms(pfbo->tcb[0], 256, 144, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); fbo_helper_gen_texture_image_ms(pfbo->tcb[1], 256, 144, 1, GL_R16F, GL_RED, GL_HALF_FLOAT, 1); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[1]); + bind_framebuffer(pfbo->fbo[1]); fbo_helper_gen_texture_image_ms(pfbo->tcb[2], 128, 72, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); fbo_helper_gen_texture_image_ms(pfbo->tcb[3], 128, 72, 1, GL_R16F, GL_RED, GL_HALF_FLOAT, 1); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[2]); + bind_framebuffer(pfbo->fbo[2]); glDrawBuffers(1, fbo_pp_s_attachments); fbo_helper_gen_texture_image_ms(pfbo->tcb[4], 128, 72, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[3]); + bind_framebuffer(pfbo->fbo[3]); fbo_helper_gen_texture_image_ms(pfbo->tcb[5], 64, 36, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); fbo_helper_gen_texture_image_ms(pfbo->tcb[6], 64, 36, 1, GL_R16F, GL_RED, GL_HALF_FLOAT, 1); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[4]); + bind_framebuffer(pfbo->fbo[4]); glDrawBuffers(1, fbo_pp_s_attachments); fbo_helper_gen_texture_image_ms(pfbo->tcb[7], 64, 36, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[5]); + bind_framebuffer(pfbo->fbo[5]); fbo_helper_gen_texture_image_ms(pfbo->tcb[8], 32, 18, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); fbo_helper_gen_texture_image_ms(pfbo->tcb[9], 32, 18, 1, GL_R16F, GL_RED, GL_HALF_FLOAT, 1); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[6]); + bind_framebuffer(pfbo->fbo[6]); glDrawBuffers(1, fbo_pp_s_attachments); fbo_helper_gen_texture_image_ms(pfbo->tcb[10], 32, 18, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[7]); + bind_framebuffer(pfbo->fbo[7]); glDrawBuffers(1, fbo_pp_s_attachments); fbo_helper_gen_texture_image_ms(pfbo->tcb[11], 8, 8, 1, GL_R32F, GL_RED, GL_FLOAT, 0); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[8]); + bind_framebuffer(pfbo->fbo[8]); glDrawBuffers(1, fbo_pp_s_attachments); fbo_helper_gen_texture_image_ms(pfbo->tcb[12], 256, 144, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[9]); + bind_framebuffer(pfbo->fbo[9]); glDrawBuffers(1, fbo_pp_s_attachments); fbo_helper_gen_texture_image_ms(pfbo->tcb[13], 1, 1, 1, GL_R32F, GL_RED, GL_FLOAT, 0); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[10]); + bind_framebuffer(pfbo->fbo[10]); glDrawBuffers(1, fbo_pp_s_attachments); fbo_helper_gen_texture_image_ms(pfbo->tcb[14], 1, 1, 1, GL_R32F, GL_RED, GL_FLOAT, 0); fbo_helper_get_error_code(); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[15]); + bind_tex2d(pfbo->tcb[15]); glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 32, 1, 0, GL_RED, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + bind_tex2d(0); fbo_pp_bind_fbo(pfbo, res); } @@ -218,27 +219,27 @@ static void fbo_pp_bind_fbo(fbo_pp* pfbo, vec2i* res) { vec2i* res_down = pfbo->res_down; if (!fbo_down) - fbo_down = force_malloc_s(sizeof(int32_t), i); + fbo_down = force_malloc_s(int32_t, i); else if (pfbo->count_down < i) { - void* temp = force_malloc_s(sizeof(int32_t), i); + void* temp = force_malloc_s(int32_t, i); memcpy(temp, fbo_down, sizeof(int32_t) * pfbo->count_down); free(fbo_down); fbo_down = temp; } if (!tcb_down) - tcb_down = force_malloc_s(sizeof(int32_t), i); + tcb_down = force_malloc_s(int32_t, i); else if (pfbo->count_down < i) { - void* temp = force_malloc_s(sizeof(int32_t), i); + void* temp = force_malloc_s(int32_t, i); memcpy(temp, tcb_down, sizeof(int32_t) * pfbo->count_down); free(tcb_down); tcb_down = temp; } if (!res_down) - res_down = force_malloc_s(sizeof(vec2i), i); + res_down = force_malloc_s(vec2i, i); else if (pfbo->count_down < i) { - void* temp = force_malloc_s(sizeof(vec2i), i); + void* temp = force_malloc_s(vec2i, i); memcpy(temp, res_down, sizeof(vec2i) * pfbo->count_down); free(res_down); res_down = temp; @@ -266,14 +267,14 @@ static void fbo_pp_bind_fbo(fbo_pp* pfbo, vec2i* res) { (float_t)r.x, (float_t)r.y, 1.0f / (float_t)r.x, 1.0f / (float_t)r.y); for (i = 0; i < pfbo->count_down; i++) { - glBindFramebuffer(GL_FRAMEBUFFER, fbo_down[i]); + bind_framebuffer(fbo_down[i]); glDrawBuffers(1, fbo_pp_s_attachments); fbo_helper_gen_texture_image_ms(tcb_down[i], res_down[i].x, res_down[i].y, 1, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); fbo_helper_get_error_code(); } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + bind_framebuffer(0); pfbo->fbo_down = fbo_down; pfbo->tcb_down = tcb_down; @@ -286,155 +287,131 @@ void fbo_pp_draw(fbo_pp* pfbo, int32_t in_tcb, int32_t out_fbo, if (pfbo->dst_pixel > 31) pfbo->dst_pixel = 0; - glBindVertexArray(pfbo->vao); + bind_vertex_array(pfbo->vao); int i = 0; if (pfbo->count_down > 0) { shader_fbo_use(&pfbo->b_shader[0]); for (; i < pfbo->count_down; i++) { glViewport(0, 0, pfbo->res_down[i].x, pfbo->res_down[i].y); // 0 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo_down[i]); + bind_framebuffer(pfbo->fbo_down[i]); shader_fbo_set_vec4(&pfbo->b_shader[0], "res", (float_t)pfbo->res_down[i].x, (float_t)pfbo->res_down[i].y, 1.0f / (float_t)pfbo->res_down[i].x, 1.0f / (float_t)pfbo->res_down[i].y); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, i == 0 ? in_tcb : pfbo->tcb_down[i - 1]); + bind_index_tex2d(0, i == 0 ? in_tcb : pfbo->tcb_down[i - 1]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } i--; } glViewport(0, 0, 256, 144); // 1 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[0]); + bind_framebuffer(pfbo->fbo[0]); glDrawBuffers(2, fbo_pp_d_attachments); shader_fbo_use(&pfbo->b_shader[1]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->count_down > 0 ? pfbo->tcb_down[i] : in_tcb); + bind_index_tex2d(0, pfbo->count_down > 0 ? pfbo->tcb_down[i] : in_tcb); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 128, 72); // 2 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[1]); + bind_framebuffer(pfbo->fbo[1]); glDrawBuffers(2, fbo_pp_d_attachments); shader_fbo_use(&pfbo->b_shader[2]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[0]); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[1]); + bind_index_tex2d(0, pfbo->tcb[0]); + bind_index_tex2d(1, pfbo->tcb[1]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 64, 36); // 3 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[3]); + bind_framebuffer(pfbo->fbo[3]); glDrawBuffers(2, fbo_pp_d_attachments); shader_fbo_use(&pfbo->b_shader[3]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[2]); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[3]); + bind_index_tex2d(0, pfbo->tcb[2]); + bind_index_tex2d(1, pfbo->tcb[3]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 32, 18); // 4 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[5]); + bind_framebuffer(pfbo->fbo[5]); glDrawBuffers(2, fbo_pp_d_attachments); shader_fbo_use(&pfbo->b_shader[4]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[5]); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[6]); + bind_index_tex2d(0, pfbo->tcb[5]); + bind_index_tex2d(1, pfbo->tcb[6]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 8, 8); // 5 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[7]); + bind_framebuffer(pfbo->fbo[7]); shader_fbo_use(&pfbo->b_shader[5]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[9]); + bind_index_tex2d(0, pfbo->tcb[9]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 128, 72); // 6 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[2]); + bind_framebuffer(pfbo->fbo[2]); shader_fbo_use(&pfbo->b_shader[6]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[2]); + bind_index_tex2d(0, pfbo->tcb[2]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 64, 36); // 7 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[4]); + bind_framebuffer(pfbo->fbo[4]); shader_fbo_use(&pfbo->b_shader[7]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[5]); + bind_index_tex2d(0, pfbo->tcb[5]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 32, 18); // 8 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[6]); + bind_framebuffer(pfbo->fbo[6]); shader_fbo_use(&pfbo->b_shader[8]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[8]); + bind_index_tex2d(0, pfbo->tcb[8]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 128, 72); // 9 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[1]); + bind_framebuffer(pfbo->fbo[1]); glDrawBuffers(1, fbo_pp_s_attachments); shader_fbo_use(&pfbo->b_shader[9]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[4]); + bind_index_tex2d(0, pfbo->tcb[4]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 64, 36); // 10 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[3]); + bind_framebuffer(pfbo->fbo[3]); glDrawBuffers(1, fbo_pp_s_attachments); shader_fbo_use(&pfbo->b_shader[10]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[7]); + bind_index_tex2d(0, pfbo->tcb[7]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 32, 18); // 11 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[5]); + bind_framebuffer(pfbo->fbo[5]); glDrawBuffers(1, fbo_pp_s_attachments); shader_fbo_use(&pfbo->b_shader[11]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[10]); + bind_index_tex2d(0, pfbo->tcb[10]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 256, 144); // 12 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[8]); + bind_framebuffer(pfbo->fbo[8]); shader_fbo_use(&pfbo->b_shader[12]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[0]); + bind_index_tex2d(0, pfbo->tcb[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 256, 144); // 13 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[0]); + bind_framebuffer(pfbo->fbo[0]); glDrawBuffers(1, fbo_pp_s_attachments); shader_fbo_use(&pfbo->b_shader[13]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[12]); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[2]); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[5]); - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[8]); + bind_index_tex2d(0, pfbo->tcb[12]); + bind_index_tex2d(1, pfbo->tcb[2]); + bind_index_tex2d(2, pfbo->tcb[5]); + bind_index_tex2d(3, pfbo->tcb[8]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glViewport(0, 0, 1, 1); // 14 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[9]); + bind_framebuffer(pfbo->fbo[9]); shader_fbo_use(&pfbo->b_shader[14]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[11]); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[6]); + bind_index_tex2d(0, pfbo->tcb[11]); + bind_index_tex2d(1, pfbo->tcb[6]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[9]); + bind_framebuffer(pfbo->fbo[9]); glReadBuffer(GL_COLOR_ATTACHMENT0); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[15]); + bind_index_tex2d(0, pfbo->tcb[15]); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, pfbo->dst_pixel, 0, 0, 0, 1, 1); glViewport(0, 0, 1, 1); // 15 - glBindFramebuffer(GL_FRAMEBUFFER, pfbo->fbo[10]); + bind_framebuffer(pfbo->fbo[10]); shader_fbo_use(&pfbo->b_shader[15]); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[15]); + bind_index_tex2d(0, pfbo->tcb[15]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); int32_t tone_map_shader_flags[8]; @@ -443,20 +420,15 @@ void fbo_pp_draw(fbo_pp* pfbo, int32_t in_tcb, int32_t out_fbo, tone_map_shader_flags[3] = pfbo->scene_fade ? 1 : 0; glBindBufferBase(GL_UNIFORM_BUFFER, 1, pfbo->tone_map_ubo); glViewport(0, 0, pfbo->res.x, pfbo->res.y); // 16 - glBindFramebuffer(GL_FRAMEBUFFER, out_fbo); + bind_framebuffer(out_fbo); glDrawBuffers(out_fbo_attachments_count, out_fbo_attachments); shader_fbo_use(&pfbo->t_shader); shader_fbo_set_int_array(&pfbo->t_shader, "mode", 8, tone_map_shader_flags); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, in_tcb); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[0]); - if (pfbo->tone_map_method == 0) { - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_1D, pfbo->tone_map.id); - } - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, pfbo->tcb[14]); + bind_index_tex2d(0, in_tcb); + bind_index_tex2d(1, pfbo->tcb[0]); + if (pfbo->tone_map_method == 0) + bind_index_tex1d(2, pfbo->tone_map.id); + bind_index_tex2d(3, pfbo->tcb[14]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } diff --git a/src/CRE/fbo_render.c b/src/CRE/fbo_render.c index e3b29273..bef93875 100644 --- a/src/CRE/fbo_render.c +++ b/src/CRE/fbo_render.c @@ -5,23 +5,18 @@ #include "fbo_render.h" #include "fbo_helper.h" +#include "shared.h" extern int32_t sv_samples; const GLenum fbo_render_c_attachments[] = { - GL_COLOR_ATTACHMENT4, - GL_COLOR_ATTACHMENT0, -}; - -const GLenum fbo_render_f_attachments[] = { - GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT3, }; const GLenum fbo_render_g_attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, - GL_COLOR_ATTACHMENT3, }; static void fbo_render_bind_fbo(fbo_render* rfbo, vec2i* res); @@ -29,7 +24,6 @@ static void fbo_render_bind_fbo(fbo_render* rfbo, vec2i* res); fbo_render* fbo_render_init() { fbo_render* rfbo = force_malloc(sizeof(fbo_render)); glGenFramebuffers(1, &rfbo->fbo); - glGenRenderbuffers(1, &rfbo->rbo); glGenTextures(5, rfbo->tcb); return rfbo; } @@ -57,21 +51,20 @@ static void fbo_render_bind_fbo(fbo_render* rfbo, vec2i* res) { rfbo->res.y = res->y > 1 ? res->y : 1; rfbo->samples = sv_samples; - glBindFramebuffer(GL_FRAMEBUFFER, rfbo->fbo); + bind_framebuffer(rfbo->fbo); rfbo->target = rfbo->samples > 1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; fbo_helper_gen_texture_image_ms(rfbo->tcb[0], rfbo->res.x, rfbo->res.y, - rfbo->samples, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 0); + rfbo->samples, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 16); fbo_helper_gen_texture_image_ms(rfbo->tcb[1], rfbo->res.x, rfbo->res.y, - rfbo->samples, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE, 1); + rfbo->samples, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, 0); fbo_helper_gen_texture_image_ms(rfbo->tcb[2], rfbo->res.x, rfbo->res.y, - rfbo->samples, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, 2); + rfbo->samples, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, 1); fbo_helper_gen_texture_image_ms(rfbo->tcb[3], rfbo->res.x, rfbo->res.y, - rfbo->samples, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, 3); + rfbo->samples, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_10_10_10_2, 2); fbo_helper_gen_texture_image_ms(rfbo->tcb[4], rfbo->res.x, rfbo->res.y, - rfbo->samples, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 4); - fbo_helper_gen_renderbuffer(rfbo->rbo, rfbo->res.x, rfbo->res.y, rfbo->samples, GL_DEPTH24_STENCIL8); + rfbo->samples, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, 3); fbo_helper_get_error_code(); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + bind_framebuffer(0); } void fbo_render_draw_c(fbo_render* rfbo, bool depth) { @@ -87,49 +80,50 @@ void fbo_render_draw_c(fbo_render* rfbo, bool depth) { shader_fbo* c_shader = rfbo->samples > 1 ? rfbo->samples > 2 ? rfbo->samples > 4 ? rfbo->samples > 8 ? &rfbo->c_shader[9] : &rfbo->c_shader[8] : &rfbo->c_shader[7] : &rfbo->c_shader[6] : &rfbo->c_shader[5]; shader_fbo_use(c_shader); - glActiveTexture(GL_TEXTURE0); - glBindTexture(rfbo->target, rfbo->tcb[4]); - glActiveTexture(GL_TEXTURE1); - glBindTexture(rfbo->target, rfbo->tcb[0]); + bind_index_tex2d(0, rfbo->tcb[4]); + bind_index_tex2d(1, rfbo->tcb[0]); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glDepthMask(true); } else { shader_fbo* c_shader = rfbo->samples > 1 ? rfbo->samples > 2 ? rfbo->samples > 4 ? rfbo->samples > 8 ? &rfbo->c_shader[4] : &rfbo->c_shader[3] : &rfbo->c_shader[2] : &rfbo->c_shader[1] : &rfbo->c_shader[0]; shader_fbo_use(c_shader); - glActiveTexture(GL_TEXTURE0); - glBindTexture(rfbo->target, rfbo->tcb[4]); + bind_index_tex2d(0, rfbo->tcb[4]); + glDisable(GL_DEPTH_TEST); + glDepthMask(false); } - glBindVertexArray(rfbo->vao); + bind_vertex_array(rfbo->vao); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDisable(GL_DEPTH_TEST); + glDepthMask(false); glDisablei(GL_BLEND, 0); glDisable(GL_STENCIL_TEST); } -void fbo_render_draw_g(fbo_render* rfbo, int32_t dir_lights_tcb, - int32_t dir_lights_count, int32_t point_lights_tcb, int32_t point_lights_count) { +void fbo_render_draw_g(fbo_render* rfbo, + int32_t light_dir_tcb, int32_t light_dir_count, + int32_t light_point_tcb, int32_t light_point_count) { if (!rfbo) return; - glBindFramebuffer(GL_FRAMEBUFFER, rfbo->fbo); - glDrawBuffers(1, fbo_render_f_attachments); + glDrawBuffers(1, fbo_render_c_attachments); shader_fbo* g_shader = rfbo->samples > 1 ? rfbo->samples > 2 ? rfbo->samples > 4 ? rfbo->samples > 8 ? &rfbo->g_shader[4] : &rfbo->g_shader[3] : &rfbo->g_shader[2] : &rfbo->g_shader[1] : &rfbo->g_shader[0]; shader_fbo_use(g_shader); - for (int32_t i = 0; i < 4; i++) { - glActiveTexture(GL_TEXTURE0 + i); - glBindTexture(rfbo->target, rfbo->tcb[i]); - } - shader_fbo_set_int(g_shader, "dirLightsCount", dir_lights_count); - shader_fbo_set_int(g_shader, "pointLightsCount", point_lights_count); - glActiveTexture(GL_TEXTURE4); - glBindTexture(GL_TEXTURE_2D, dir_lights_tcb); - glActiveTexture(GL_TEXTURE5); - glBindTexture(GL_TEXTURE_2D, point_lights_tcb); + shader_fbo_set_int(g_shader, "lightDirCount", light_dir_count); + shader_fbo_set_int(g_shader, "lightPointCount", light_point_count); + + for (int32_t i = 0; i < 4; i++) + bind_index_tex2d(i, rfbo->tcb[i]); + bind_index_tex2d(4, light_dir_tcb); + bind_index_tex2d(5, light_point_tcb); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 0xFF, 0xFF); glStencilMask(0xFF); - glBindVertexArray(rfbo->vao); + bind_vertex_array(rfbo->vao); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisable(GL_STENCIL_TEST); } @@ -139,7 +133,6 @@ void fbo_render_dispose(fbo_render* rfbo) { return; glDeleteFramebuffers(1, &rfbo->fbo); - glDeleteRenderbuffers(1, &rfbo->rbo); glDeleteTextures(5, rfbo->tcb); free(rfbo); } diff --git a/src/CRE/fbo_render.h b/src/CRE/fbo_render.h index b21d2c96..a14df128 100644 --- a/src/CRE/fbo_render.h +++ b/src/CRE/fbo_render.h @@ -12,7 +12,6 @@ typedef struct fbo_render { int32_t vao; int32_t fbo; - int32_t rbo; int32_t tcb[5]; int32_t samples; shader_fbo c_shader[10]; @@ -22,7 +21,6 @@ typedef struct fbo_render { } fbo_render; extern const GLenum fbo_render_c_attachments[]; -extern const GLenum fbo_render_f_attachments[]; extern const GLenum fbo_render_g_attachments[]; extern fbo_render* fbo_render_init(); @@ -30,6 +28,7 @@ extern void fbo_render_initialize(fbo_render* rfbo, vec2i* res, int32_t vao, shader_fbo* c_shader, shader_fbo* g_shader); extern void fbo_render_resize(fbo_render* rfbo, vec2i* res); extern void fbo_render_draw_c(fbo_render* rfbo, bool depth); -extern void fbo_render_draw_g(fbo_render* rfbo, int32_t dir_lights_tcb, - int32_t dir_lights_count, int32_t point_lights_tcb, int32_t point_lights_count); +extern void fbo_render_draw_g(fbo_render* rfbo, + int32_t light_dir_tcb, int32_t light_dir_count, + int32_t light_point_tcb, int32_t light_point_count); extern void fbo_render_dispose(fbo_render* rfbo); diff --git a/src/CRE/gl_object.c b/src/CRE/gl_object.c index 9425fd66..bf733654 100644 --- a/src/CRE/gl_object.c +++ b/src/CRE/gl_object.c @@ -4,20 +4,22 @@ */ #include "gl_object.h" +#include "static_var.h" + +extern const gl_object_cull_face gl_object_cull_face_default = { + .enable = true, + .mode = GL_BACK, +}; static void gl_object_generate_vbo(gl_object* obj); static void gl_object_bind_vbo(gl_object* obj); -static void gl_object_generate_ivbo(gl_object* obj); -static void gl_object_bind_ivbo(gl_object* obj); static void gl_object_generate_ebo(gl_object* obj); static void gl_object_bind_ebo(gl_object* obj); static void gl_object_generate_vao(gl_object* obj); -static void gl_object_draw(gl_object* obj); gl_object* gl_object_init() { gl_object* obj = force_malloc(sizeof(gl_object)); gl_object_generate_vbo(obj); - gl_object_generate_ivbo(obj); gl_object_generate_ebo(obj); gl_object_generate_vao(obj); return obj; @@ -26,13 +28,13 @@ gl_object* gl_object_init() { void gl_object_update_vert(gl_object* obj, vertex* vert) { switch (vert->type) { case VERTEX_SIMPLE: - obj->type = obj->instances.count > 0 ? GL_OBJECT_INSTANCED_SIMPLE : GL_OBJECT_SIMPLE; + obj->type = GL_OBJECT_SIMPLE; obj->vertex = *vert; gl_object_bind_vbo(obj); gl_object_bind_ebo(obj); break; case VERTEX_BONED: - obj->type = obj->instances.count > 0 ? GL_OBJECT_INSTANCED_BONED : GL_OBJECT_BONED; + obj->type = GL_OBJECT_BONED; obj->vertex = *vert; gl_object_bind_vbo(obj); gl_object_bind_ebo(obj); @@ -40,11 +42,11 @@ void gl_object_update_vert(gl_object* obj, vertex* vert) { } } -void gl_object_update_texture(gl_object* obj, texture_set* texture) { - if (texture) - obj->texture = *texture; +void gl_object_update_material(gl_object* obj, material* mat) { + if (mat) + obj->material = *mat; else - memset(&obj->texture, 0, sizeof(texture_set)); + memset(&obj->material, 0, sizeof(material)); } void gl_object_update_shader(gl_object* obj, shader_model* shader) { @@ -54,24 +56,15 @@ void gl_object_update_shader(gl_object* obj, shader_model* shader) { memset(&obj->shader, 0, sizeof(shader_model)); } -void gl_object_update_instances(gl_object* obj, gl_object_instances* instances) { - if (instances->count > 0) - switch (obj->type) { - case GL_OBJECT_SIMPLE: - obj->type = GL_OBJECT_INSTANCED_SIMPLE; - break; - case GL_OBJECT_BONED: - obj->type = GL_OBJECT_INSTANCED_BONED; - break; - } +void gl_object_update_bone_mat(gl_object* obj, texture_bone_mat* bone_mat_tex) { + if (bone_mat_tex) + obj->bone_mat_tex = *bone_mat_tex; + else + memset(&obj->bone_mat_tex, 0, sizeof(texture_bone_mat)); +} - switch (obj->type) { - case GL_OBJECT_INSTANCED_SIMPLE: - case GL_OBJECT_INSTANCED_BONED: - obj->instances = *instances; - gl_object_bind_ivbo(obj); - break; - } +void gl_object_update_cull_face(gl_object* obj, gl_object_cull_face cull_face) { + obj->cull_face = cull_face; } static void gl_object_generate_vbo(gl_object* obj) { @@ -80,23 +73,10 @@ static void gl_object_generate_vbo(gl_object* obj) { } static void gl_object_bind_vbo(gl_object* obj) { - glBindBuffer(GL_ARRAY_BUFFER, obj->vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(uint32_t) * obj->vertex.vert_count, obj->vertex.vert, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -static void gl_object_generate_ivbo(gl_object* obj) { - glGenBuffers(1, &obj->instances_trans_vbo); - glGenBuffers(1, &obj->instances_data_vbo); - gl_object_bind_ivbo(obj); -} - -static void gl_object_bind_ivbo(gl_object* obj) { - glBindBuffer(GL_ARRAY_BUFFER, obj->instances_trans_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(mat4) * obj->instances.count, obj->instances.trans, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, obj->instances_data_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(mat4) * obj->instances.count, obj->instances.data, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + bind_array_buffer(obj->vbo); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(sizeof(vertex_data) * obj->vertex.vert_count), + (void*)obj->vertex.vert, GL_DYNAMIC_DRAW); + bind_array_buffer(0); } static void gl_object_generate_ebo(gl_object* obj) { @@ -105,125 +85,203 @@ static void gl_object_generate_ebo(gl_object* obj) { } static void gl_object_bind_ebo(gl_object* obj) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj->vbo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * obj->vertex.ind_count, obj->vertex.ind, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + bind_element_array_buffer(obj->ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)(sizeof(uint32_t) * obj->vertex.ind_count), + obj->vertex.ind, GL_DYNAMIC_DRAW); + bind_element_array_buffer(0); } static void gl_object_generate_vao(gl_object* obj) { - glGenVertexArrays(1, &obj->vao); - glBindVertexArray(obj->vao); - switch (obj->type) { - case GL_OBJECT_SIMPLE: - case GL_OBJECT_INSTANCED_SIMPLE: - glBindBuffer(GL_ARRAY_BUFFER, obj->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj->ebo); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, false, 40, (void*)0); // Pos - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_HALF_FLOAT, false, 40, (void*)12); // UV - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_HALF_FLOAT, false, 40, (void*)16); // UV2 - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 4, GL_HALF_FLOAT, false, 40, (void*)20); // Color - glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 3, GL_HALF_FLOAT, false, 40, (void*)28); // Normal - glEnableVertexAttribArray(5); - glVertexAttribPointer(5, 3, GL_HALF_FLOAT, false, 40, (void*)34); // Tangent - break; - case GL_OBJECT_BONED: - case GL_OBJECT_INSTANCED_BONED: - glBindBuffer(GL_ARRAY_BUFFER, obj->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj->ebo); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, false, 56, (void*)0); // Pos - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_HALF_FLOAT, false, 56, (void*)12); // UV - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_HALF_FLOAT, false, 56, (void*)16); // UV2 - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 4, GL_HALF_FLOAT, false, 56, (void*)20); // Color - glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 3, GL_HALF_FLOAT, false, 56, (void*)28); // Normal - glEnableVertexAttribArray(5); - glVertexAttribPointer(5, 3, GL_HALF_FLOAT, false, 56, (void*)34); // Tangent - glEnableVertexAttribArray(6); - glVertexAttribPointer(6, 4, GL_UNSIGNED_SHORT, false, 56, (void*)40); // Bone Index - glEnableVertexAttribArray(7); - glVertexAttribPointer(7, 4, GL_HALF_FLOAT, false, 56, (void*)48); // Bone Weight - break; - } + static const GLsizei data_size = sizeof(vertex_data); - switch (obj->type) { - case GL_OBJECT_INSTANCED_SIMPLE: - case GL_OBJECT_INSTANCED_BONED: - glBindBuffer(GL_ARRAY_BUFFER, obj->instances_trans_vbo); - glEnableVertexAttribArray(8); - glVertexAttribPointer(8, 4, GL_FLOAT, false, 64, (void*)0); // Trans[0] - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); - glVertexAttribPointer(9, 4, GL_FLOAT, false, 64, (void*)16); // Trans[1] - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); - glVertexAttribPointer(10, 4, GL_FLOAT, false, 64, (void*)32); // Trans[2] - glVertexAttribDivisor(10, 1); - glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_FLOAT, false, 64, (void*)48); // Trans[3] - glVertexAttribDivisor(11, 1); - glBindBuffer(GL_ARRAY_BUFFER, obj->instances_data_vbo); - glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_FLOAT, false, 64, (void*)0); // Data[0] - glVertexAttribDivisor(12, 1); - glEnableVertexAttribArray(13); - glVertexAttribPointer(13, 4, GL_FLOAT, false, 64, (void*)16); // Data[1] - glVertexAttribDivisor(13, 1); - glEnableVertexAttribArray(14); - glVertexAttribPointer(14, 4, GL_FLOAT, false, 64, (void*)32); // Data[2] - glVertexAttribDivisor(14, 1); - glEnableVertexAttribArray(15); - glVertexAttribPointer(15, 4, GL_FLOAT, false, 64, (void*)48); // Data[3] - glVertexAttribDivisor(15, 1); - break; - } - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glGenVertexArrays(1, &obj->vao); + bind_vertex_array(obj->vao); + bind_array_buffer(obj->vbo); + bind_element_array_buffer(obj->ebo); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, data_size, + (void*)offsetof(vertex_data, pos)); // Pos + glEnableVertexAttribArray(1); + glVertexAttribIPointer(1, 4, GL_UNSIGNED_INT, data_size, + (void*)offsetof(vertex_data, uv)); // UV/Color + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 3, GL_SHORT, GL_TRUE, data_size, + (void*)offsetof(vertex_data, normal)); // Normal + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 3, GL_SHORT, GL_TRUE, data_size, + (void*)offsetof(vertex_data, tangent)); // Tangent + glEnableVertexAttribArray(4); + glVertexAttribIPointer(4, 4, GL_UNSIGNED_SHORT, data_size, + (void*)offsetof(vertex_data, bone_index)); // Bone Index + glEnableVertexAttribArray(5); + glVertexAttribPointer(5, 4, GL_UNSIGNED_BYTE, GL_TRUE, data_size, + (void*)offsetof(vertex_data, bone_weight)); // Bone Weight + bind_vertex_array(0); + bind_array_buffer(0); + bind_element_array_buffer(0); } void gl_object_draw_c(gl_object* obj) { if (obj->type == GL_OBJECT_NONE) return; + if (obj->material.blend.enable) { + glEnablei(GL_BLEND, 0); + glBlendFuncSeparate(obj->material.blend.src_factor_rgb, obj->material.blend.dst_factor_rgb, + obj->material.blend.src_factor_alpha, obj->material.blend.dst_factor_alpha); + glBlendEquationSeparate(obj->material.blend.mode_rgb, obj->material.blend.mode_alpha); + } + else + glDisable(GL_BLEND); + + if (obj->cull_face.enable) { + glEnable(GL_CULL_FACE); + glCullFace(obj->cull_face.mode); + } + else + glDisable(GL_CULL_FACE); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glDepthMask(true); + + bool use_bones; + switch (obj->type) { + case GL_OBJECT_BONED: + use_bones = true; + break; + default: + use_bones = false; + break; + } + + GLint tex_mode[8]; + for (int32_t i = 0; i < 8; i++) + tex_mode[i] = obj->material.texture.tex[i].mode; + shader_model_c_use(&obj->shader); - gl_object_draw(obj); - shader_model_c_use(0); + shader_model_c_set_int_array(&obj->shader, "tex_mode", 8, tex_mode); + shader_model_c_set_bool(&obj->shader, "use_bones", use_bones); + shader_model_c_set_bool(&obj->shader, "write_only_depth", false); + texture_set_bind(&obj->material.texture); + + texture_bone_mat_bind(&obj->bone_mat_tex, 8); + bind_vertex_array(obj->vao); + glDrawElements(GL_TRIANGLES, (GLsizei)obj->vertex.ind_count, GL_UNSIGNED_INT, 0); + texture_set_reset(&obj->material.texture); + texture_bone_mat_reset(&obj->bone_mat_tex, 8); +} + +void gl_object_draw_c_translucent_first_part(gl_object* obj) { + if (obj->type == GL_OBJECT_NONE) + return; + + if (obj->cull_face.enable) { + glEnable(GL_CULL_FACE); + glCullFace(obj->cull_face.mode); + } + + bool use_bones; + switch (obj->type) { + case GL_OBJECT_BONED: + use_bones = true; + break; + default: + use_bones = false; + break; + } + + shader_model_c_use(&obj->shader); + shader_model_c_set_bool(&obj->shader, "use_bones", use_bones); + shader_model_c_set_bool(&obj->shader, "write_only_depth", true); + texture_set_reset(&obj->material.texture); + + texture_bone_mat_bind(&obj->bone_mat_tex, 8); + bind_vertex_array(obj->vao); + glDrawElements(GL_TRIANGLES, (GLsizei)obj->vertex.ind_count, GL_UNSIGNED_INT, 0); + texture_bone_mat_reset(&obj->bone_mat_tex, 8); +} + +void gl_object_draw_c_translucent_second_part(gl_object* obj) { + if (obj->type == GL_OBJECT_NONE) + return; + + glBlendFuncSeparate(obj->material.blend.src_factor_rgb, obj->material.blend.dst_factor_rgb, + obj->material.blend.src_factor_alpha, obj->material.blend.dst_factor_alpha); + glBlendEquationSeparate(obj->material.blend.mode_rgb, obj->material.blend.mode_alpha); + + if (obj->cull_face.enable) { + glEnable(GL_CULL_FACE); + glCullFace(obj->cull_face.mode); + } + else + glDisable(GL_CULL_FACE); + + bool use_bones; + switch (obj->type) { + case GL_OBJECT_BONED: + use_bones = true; + break; + default: + use_bones = false; + break; + } + + GLint tex_mode[8]; + for (int32_t i = 0; i < 8; i++) + tex_mode[i] = obj->material.texture.tex[i].mode; + + shader_model_c_use(&obj->shader); + shader_model_c_set_int_array(&obj->shader, "tex_mode", 8, tex_mode); + shader_model_c_set_bool(&obj->shader, "use_bones", use_bones); + shader_model_c_set_bool(&obj->shader, "write_only_depth", false); + texture_set_bind(&obj->material.texture); + + texture_bone_mat_bind(&obj->bone_mat_tex, 8); + bind_vertex_array(obj->vao); + glDrawElements(GL_TRIANGLES, (GLsizei)obj->vertex.ind_count, GL_UNSIGNED_INT, 0); + texture_set_reset(&obj->material.texture); + texture_bone_mat_reset(&obj->bone_mat_tex, 8); } void gl_object_draw_g(gl_object* obj) { if (obj->type == GL_OBJECT_NONE) return; - shader_model_g_use(&obj->shader); - gl_object_draw(obj); - shader_model_c_use(0); -} + if (obj->cull_face.enable) { + glEnable(GL_CULL_FACE); + glCullFace(obj->cull_face.mode); + } + else + glDisable(GL_CULL_FACE); -static void gl_object_draw(gl_object* obj) { - texture_set_bind(&obj->texture); - glBindVertexArray(obj->vao); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glDepthMask(true); + + bool use_bones; switch (obj->type) { - case GL_OBJECT_SIMPLE: case GL_OBJECT_BONED: - glDrawElements(GL_TRIANGLES, (GLsizei)obj->vertex.ind_count, GL_UNSIGNED_INT, 0); + use_bones = true; break; - case GL_OBJECT_INSTANCED_SIMPLE: - case GL_OBJECT_INSTANCED_BONED: - glDrawElementsInstanced(GL_TRIANGLES, (GLsizei)obj->vertex.ind_count, - GL_UNSIGNED_INT, 0, (GLsizei)obj->instances.count); + default: + use_bones = false; break; } - texture_set_reset(&obj->texture); - glBindVertexArray(0); + + GLint tex_mode[8]; + for (int32_t i = 0; i < 8; i++) + tex_mode[i] = obj->material.texture.tex[i].mode; + + shader_model_g_use(&obj->shader); + shader_model_g_set_int_array(&obj->shader, "tex_mode", 8, tex_mode); + shader_model_g_set_bool(&obj->shader, "use_bones", use_bones); + texture_set_bind(&obj->material.texture); + texture_bone_mat_bind(&obj->bone_mat_tex, 8); + bind_vertex_array(obj->vao); + glDrawElements(GL_TRIANGLES, (GLsizei)obj->vertex.ind_count, GL_UNSIGNED_INT, 0); + texture_set_reset(&obj->material.texture); + texture_bone_mat_reset(&obj->bone_mat_tex, 8); } void gl_object_dispose(gl_object* obj) { @@ -233,9 +291,5 @@ void gl_object_dispose(gl_object* obj) { glDeleteBuffers(1, &obj->ebo); if (obj->vao) glDeleteVertexArrays(1, &obj->vao); - if (obj->instances_trans_vbo) - glDeleteBuffers(1, &obj->instances_trans_vbo); - if (obj->instances_data_vbo) - glDeleteBuffers(1, &obj->instances_data_vbo); free(obj); } diff --git a/src/CRE/gl_object.h b/src/CRE/gl_object.h index eaaa394f..95b7f5b9 100644 --- a/src/CRE/gl_object.h +++ b/src/CRE/gl_object.h @@ -7,49 +7,53 @@ #include "../KKdLib/default.h" #include "../KKdLib/mat.h" +#include "hash.h" +#include "material.h" #include "shader.h" #include "texture.h" #include "vertex.h" +typedef struct gl_object_cull_face { + bool enable; + int16_t mode; +} gl_object_cull_face; + typedef enum gl_object_type { GL_OBJECT_NONE = 0, GL_OBJECT_SIMPLE, GL_OBJECT_BONED, - GL_OBJECT_INSTANCED_SIMPLE, - GL_OBJECT_INSTANCED_BONED, } gl_object_type; -typedef struct gl_object_instances { - size_t count; - mat4* trans; - mat4* data; -} gl_object_instances; - typedef struct gl_object { gl_object_type type; int32_t vao; int32_t vbo; int32_t ebo; - texture_set texture; - shader_model shader; vertex vertex; - int32_t instances_trans_vbo; - int32_t instances_data_vbo; - gl_object_instances instances; + material material; + shader_model shader; + texture_bone_mat bone_mat_tex; + gl_object_cull_face cull_face; } gl_object; typedef struct gl_object_update { - uint64_t texture; - uint64_t shader; - uint64_t vert; - gl_object_instances instances; + hash vert; + hash material; + hash shader; + hash bone_mat; + gl_object_cull_face cull_face; } gl_object_update; +extern const gl_object_cull_face gl_object_cull_face_default; + extern gl_object* gl_object_init(); extern void gl_object_update_vert(gl_object* obj, vertex* vert); -extern void gl_object_update_texture(gl_object* obj, texture_set* texture); +extern void gl_object_update_material(gl_object* obj, material* material); extern void gl_object_update_shader(gl_object* obj, shader_model* shader); -extern void gl_object_update_instances(gl_object* obj, gl_object_instances* instances); +extern void gl_object_update_bone_mat(gl_object* obj, texture_bone_mat* bone_mat_tex); +extern void gl_object_update_cull_face(gl_object* obj, gl_object_cull_face cull_face); extern void gl_object_draw_c(gl_object* obj); +extern void gl_object_draw_c_translucent_first_part(gl_object* obj); +extern void gl_object_draw_c_translucent_second_part(gl_object* obj); extern void gl_object_draw_g(gl_object* obj); extern void gl_object_dispose(gl_object* obj); diff --git a/src/CRE/hash.c b/src/CRE/hash.c index cb7cb35b..145a0d9d 100644 --- a/src/CRE/hash.c +++ b/src/CRE/hash.c @@ -6,18 +6,17 @@ #include "hash.h" #include "../KKdLib/hash.h" -uint64_t hash_char(char* data) { +inline hash hash_char(char* data) { return hash_data(data, strlen(data)); } -uint64_t hash_wchar_t(wchar_t* data) { +inline hash hash_wchar_t(wchar_t* data) { return hash_data(data, wcslen(data)); } -uint64_t hash_data(void* data, size_t length) { - uint64_t hash, hash1, hash2; - hash1 = hash_fnv1a64(data, length); - hash2 = hash_murmurhash(data, length, 0, false, false); - hash = hash1 | (hash2 << 32); +inline hash hash_data(void* data, size_t length) { + hash hash; + hash.f = hash_fnv1a64(data, length); + hash.m = hash_murmurhash(data, length, 0, false, false); return hash; } diff --git a/src/CRE/hash.h b/src/CRE/hash.h index 2da95a01..164b9426 100644 --- a/src/CRE/hash.h +++ b/src/CRE/hash.h @@ -7,18 +7,26 @@ #include "../KKdLib/default.h" -#define hash(t) \ +typedef struct hash { + uint64_t f; + uint32_t m; +} hash; + +#define hash_dat(t) \ typedef struct hash_##t { \ - uint64_t hash; \ + hash hash; \ t data; \ } hash_##t; #define hash_ptr(t) \ typedef struct hash_ptr_##t { \ - uint64_t hash; \ + hash hash; \ t* data; \ } hash_ptr_##t; -extern uint64_t hash_char(char* data); -extern uint64_t hash_wchar_t(wchar_t* data); -extern uint64_t hash_data(void* data, size_t length); +#define HASH_COMPARE(a, b) \ +(((a).f == (b).f) || ((a).m == (b).m)) + +extern hash hash_char(char* data); +extern hash hash_wchar_t(wchar_t* data); +extern hash hash_data(void* data, size_t length); diff --git a/src/CRE/light.c b/src/CRE/light.c new file mode 100644 index 00000000..361e7ca6 --- /dev/null +++ b/src/CRE/light.c @@ -0,0 +1,16 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "light.h" + +inline float_t light_point_calculate_radius(vec3* color, + float_t constant, float_t linear, float_t quadratic) { + vec3 c = *color; + float_t light_max = max(max(c.x, c.y), c.z); + + double_t t_sqrt = sqrt(linear * linear - 4 * quadratic * (constant - (256.0 / 1.0) * light_max)); + double_t radius = (-linear + t_sqrt) / (2.0 * quadratic); + return (float_t)radius; +} diff --git a/src/CRE/light.h b/src/CRE/light.h new file mode 100644 index 00000000..bf706541 --- /dev/null +++ b/src/CRE/light.h @@ -0,0 +1,44 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/vec.h" +#include "../KKdLib/vector.h" + +typedef struct light_dir { + vec3 dir; + vec3 color; +} light_dir; + +typedef struct light_point { + vec3 position; + vec3 color; + union { + struct { + float_t constant; + float_t linear; + float_t quadratic; + float_t radius; + }; + vec4 clqr; + }; +} light_point; + +typedef struct light_dir_update { + vec3 dir; + vec4 color; +} light_dir_update; + +typedef struct light_point_update { + vec3 position; + vec4 color; + float_t constant; + float_t linear; + float_t quadratic; +} light_point_update; + +extern float_t light_point_calculate_radius(vec3* color, + float_t constant, float_t linear, float_t quadratic); diff --git a/src/CRE/lock.h b/src/CRE/lock.h new file mode 100644 index 00000000..e8b322d7 --- /dev/null +++ b/src/CRE/lock.h @@ -0,0 +1,35 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/default.h" + +#define lock_val(name) \ +CRITICAL_SECTION name; \ +BOOL name##_init + +#define lock_extern_val(name) \ +extern CRITICAL_SECTION name; \ +extern BOOL name##_init + +#define lock_init(val) \ +(val##_init) = InitializeCriticalSectionAndSpinCount(&(val), 0); + +#define lock_check_init(val) \ +(val##_init) + +#define lock_lock(val) \ +if (val##_init) { \ +EnterCriticalSection(&(val)); + +#define lock_unlock(val) \ +LeaveCriticalSection(&(val)); \ +} + +#define lock_dispose(val) \ +if (val##_init) \ + DeleteCriticalSection(&(val)); \ +(val##_init) = FALSE diff --git a/src/CRE/material.c b/src/CRE/material.c new file mode 100644 index 00000000..6f7efba9 --- /dev/null +++ b/src/CRE/material.c @@ -0,0 +1,16 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "material.h" + +const material_blend material_blend_default = { + .enable = true, + .src_factor_rgb = GL_SRC_ALPHA, + .dst_factor_rgb = GL_ONE_MINUS_SRC_ALPHA, + .src_factor_alpha = GL_ONE, + .dst_factor_alpha = GL_ONE_MINUS_SRC_ALPHA, + .mode_rgb = GL_FUNC_ADD, + .mode_alpha = GL_FUNC_ADD, +}; diff --git a/src/CRE/material.h b/src/CRE/material.h new file mode 100644 index 00000000..51406918 --- /dev/null +++ b/src/CRE/material.h @@ -0,0 +1,34 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/default.h" +#include "hash.h" +#include "texture.h" + +typedef struct material_blend { + bool enable; + int16_t src_factor_rgb; + int16_t dst_factor_rgb; + int16_t src_factor_alpha; + int16_t dst_factor_alpha; + int16_t mode_rgb; + int16_t mode_alpha; +} material_blend; + +typedef struct material { + texture_set texture; + material_blend blend; + bool translucent; +} material; + +typedef struct material_update { + hash texture; + material_blend blend; + bool translucent; +} material_update; + +extern const material_blend material_blend_default; diff --git a/src/CRE/microui.c b/src/CRE/microui.c deleted file mode 100644 index 9b57eb6f..00000000 --- a/src/CRE/microui.c +++ /dev/null @@ -1,1250 +0,0 @@ -/* -** Copyright (c) 2020 rxi -** -** Permission is hereby granted, free of charge, to any person obtaining a copy -** of this software and associated documentation files (the "Software"), to -** deal in the Software without restriction, including without limitation the -** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -** sell copies of the Software, and to permit persons to whom the Software is -** furnished to do so, subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in -** all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -** IN THE SOFTWARE. -*/ - -#include -#include -#include -#include -#include "microui.h" - -#define unused(x) ((void) (x)) - -#define expect(x) do { \ - if (!(x)) { \ - fprintf(stderr, "Fatal error: %s:%d: assertion '%s' failed\n", \ - __FILE__, __LINE__, #x); \ - abort(); \ - } \ - } while (0) - -#define push(stk, val) do { \ - expect((stk).idx < (int) (sizeof((stk).items) / sizeof(*(stk).items))); \ - (stk).items[(stk).idx] = (val); \ - (stk).idx++; /* incremented after incase `val` uses this value */ \ - } while (0) - -#define pop(stk) do { \ - expect((stk).idx > 0); \ - (stk).idx--; \ - } while (0) - -static mu_Rect unclipped_rect = { 0, 0, 0x1000000, 0x1000000 }; - -static mu_Style default_style = { - /* font | size | padding | spacing | indent */ - NULL, { 68, 10 }, 5, 4, 24, - /* title_height | scrollbar_size | thumb_size */ - 24, 12, 8, - { - { 230, 230, 230, 255 }, /* MU_COLOR_TEXT */ - { 25, 25, 25, 255 }, /* MU_COLOR_BORDER */ - { 50, 50, 50, 255 }, /* MU_COLOR_WINDOWBG */ - { 25, 25, 25, 255 }, /* MU_COLOR_TITLEBG */ - { 240, 240, 240, 255 }, /* MU_COLOR_TITLETEXT */ - { 0, 0, 0, 0 }, /* MU_COLOR_PANELBG */ - { 75, 75, 75, 255 }, /* MU_COLOR_BUTTON */ - { 95, 95, 95, 255 }, /* MU_COLOR_BUTTONHOVER */ - { 115, 115, 115, 255 }, /* MU_COLOR_BUTTONFOCUS */ - { 30, 30, 30, 255 }, /* MU_COLOR_BASE */ - { 35, 35, 35, 255 }, /* MU_COLOR_BASEHOVER */ - { 40, 40, 40, 255 }, /* MU_COLOR_BASEFOCUS */ - { 30, 30, 30, 255 }, /* MU_COLOR_SCROLLBASE */ - { 73, 73, 73, 255 }, /* MU_COLOR_SCROLLTHUMB */ - } -}; - -mu_Vec2 mu_vec2(int32_t x, int32_t y) { - mu_Vec2 res; - res.x = x; - res.y = y; - return res; -} - -mu_Rect mu_rect(int32_t x, int32_t y, int32_t w, int32_t h) { - mu_Rect res; - res.x = x; - res.y = y; - res.w = w; - res.h = h; - return res; -} - -mu_Color mu_color(int32_t r, int32_t g, int32_t b, int32_t a) { - mu_Color res; - res.r = (uint8_t)clamp(r, 0, 255); - res.g = (uint8_t)clamp(g, 0, 255); - res.b = (uint8_t)clamp(b, 0, 255); - res.a = (uint8_t)clamp(a, 0, 255); - return res; -} - -mu_Color mu_color_real(float_t r, float_t g, float_t b, float_t a) { - mu_Color res; - res.r = (uint8_t)roundf(clamp(r, 0.0f, 1.0f) * 255.0f); - res.g = (uint8_t)roundf(clamp(g, 0.0f, 1.0f) * 255.0f); - res.b = (uint8_t)roundf(clamp(b, 0.0f, 1.0f) * 255.0f); - res.a = (uint8_t)roundf(clamp(a, 0.0f, 1.0f) * 255.0f); - return res; -} - -static mu_Rect expand_rect(mu_Rect rect, int32_t n) { - return mu_rect(rect.x - n, rect.y - n, rect.w + n * 2, rect.h + n * 2); -} - -static mu_Rect intersect_rects(mu_Rect r1, mu_Rect r2) { - int x1 = mu_max(r1.x, r2.x); - int y1 = mu_max(r1.y, r2.y); - int x2 = mu_min(r1.x + r1.w, r2.x + r2.w); - int y2 = mu_min(r1.y + r1.h, r2.y + r2.h); - if (x2 < x1) - x2 = x1; - if (y2 < y1) - y2 = y1; - return mu_rect(x1, y1, x2 - x1, y2 - y1); -} - -static bool rect_overlaps_vec2(mu_Rect r, mu_Vec2 p) { - return p.x >= r.x && p.x < r.x + r.w && p.y >= r.y && p.y < r.y + r.h; -} - -static void draw_frame(mu_Context *ctx, mu_Rect rect, int colorid) { - mu_draw_rect(ctx, rect, ctx->style->colors[colorid]); - if (colorid == MU_COLOR_SCROLLBASE || - colorid == MU_COLOR_SCROLLTHUMB || - colorid == MU_COLOR_TITLEBG) - return; - /* draw border */ - if (ctx->style->colors[MU_COLOR_BORDER].a) - mu_draw_box(ctx, expand_rect(rect, 1), ctx->style->colors[MU_COLOR_BORDER]); -} - -void mu_init(mu_Context *ctx) { - memset(ctx, 0, sizeof(*ctx)); - ctx->draw_frame = draw_frame; - ctx->_style = default_style; - ctx->style = &ctx->_style; -} - -void mu_begin(mu_Context *ctx) { - expect(ctx->text_width && ctx->text_height); - ctx->command_list.idx = 0; - ctx->root_list.idx = 0; - ctx->scroll_target = NULL; - ctx->hover_root = ctx->next_hover_root; - ctx->next_hover_root = NULL; - ctx->mouse_delta.x = ctx->mouse_pos.x - ctx->last_mouse_pos.x; - ctx->mouse_delta.y = ctx->mouse_pos.y - ctx->last_mouse_pos.y; - ctx->frame++; - ctx->text_input = false; -} - -static int compare_zindex(const void *a, const void *b) { - return (*(mu_Container**) a)->zindex - (*(mu_Container**) b)->zindex; -} - -void mu_end(mu_Context *ctx) { - size_t i, n; - /* check stacks */ - expect(ctx->container_stack.idx == 0); - expect(ctx->clip_stack.idx == 0); - expect(ctx->id_stack.idx == 0); - expect(ctx->layout_stack.idx == 0); - - /* handle scroll input */ - if (ctx->scroll_target) - if (ctx->scroll_target->swap_scroll) { - ctx->scroll_target->scroll.x += ctx->scroll_delta.y; - ctx->scroll_target->scroll.y += ctx->scroll_delta.x; - } - else { - ctx->scroll_target->scroll.x += ctx->scroll_delta.x; - ctx->scroll_target->scroll.y += ctx->scroll_delta.y; - } - - /* unset focus if focus id was not touched this frame */ - if (!ctx->updated_focus) - ctx->focus = 0; - ctx->updated_focus = false; - - /* bring hover root to front if mouse was pressed */ - if (ctx->mouse_pressed && ctx->next_hover_root && - ctx->next_hover_root->zindex < ctx->last_zindex && - ctx->next_hover_root->zindex >= 0) - mu_bring_to_front(ctx, ctx->next_hover_root); - - /* reset input state */ - ctx->key_pressed = 0; - ctx->input_text[0] = '\0'; - ctx->mouse_pressed = 0; - ctx->scroll_delta = mu_vec2(0, 0); - ctx->last_mouse_pos = ctx->mouse_pos; - - /* sort root containers by zindex */ - n = ctx->root_list.idx; - qsort(ctx->root_list.items, n, sizeof(mu_Container*), compare_zindex); - - /* set root container jump commands */ - for (i = 0; i < n; i++) { - mu_Container *cnt = ctx->root_list.items[i]; - /* if this is the first container then make the first command jump to it. - ** otherwise set the previous container's tail to jump to this one */ - if (i == 0) { - mu_Command *cmd = (mu_Command*) ctx->command_list.items; - cmd->jump.dst = (char*) cnt->head + sizeof(mu_JumpCommand); - } - else { - mu_Container *prev = ctx->root_list.items[i - 1]; - prev->tail->jump.dst = (char*) cnt->head + sizeof(mu_JumpCommand); - } - /* make the last container's tail jump to the end of command list */ - if (i == n - 1) - cnt->tail->jump.dst = ctx->command_list.items + ctx->command_list.idx; - } -} - -void mu_set_focus(mu_Context *ctx, mu_Id id) { - ctx->focus = id; - ctx->updated_focus = true; -} - -/* 32bit fnv-1a hash */ -#define HASH_INITIAL 2166136261 - -static void hash(mu_Id *hash, const void *data, size_t size) { - const unsigned char *p = data; - while (size--) - *hash = (*hash ^ *p++) * 16777619; -} - -mu_Id mu_get_id(mu_Context *ctx, const void *data, size_t size) { - size_t idx = ctx->id_stack.idx; - mu_Id res = (idx > 0) ? ctx->id_stack.items[idx - 1] : HASH_INITIAL; - hash(&res, data, size); - ctx->last_id = res; - return res; -} - -void mu_push_id(mu_Context *ctx, const void *data, size_t size) { - push(ctx->id_stack, mu_get_id(ctx, data, size)); -} - -void mu_pop_id(mu_Context *ctx) { - pop(ctx->id_stack); -} - -void mu_push_clip_rect(mu_Context *ctx, mu_Rect rect) { - mu_Rect last = mu_get_clip_rect(ctx); - push(ctx->clip_stack, intersect_rects(rect, last)); -} - -void mu_pop_clip_rect(mu_Context *ctx) { - pop(ctx->clip_stack); -} - -mu_Rect mu_get_clip_rect(mu_Context *ctx) { - expect(ctx->clip_stack.idx > 0); - return ctx->clip_stack.items[ctx->clip_stack.idx - 1]; -} - -mu_clip_enum mu_check_clip(mu_Context *ctx, mu_Rect r) { - mu_Rect cr = mu_get_clip_rect(ctx); - if (r.x > cr.x + cr.w || r.x + r.w < cr.x || - r.y > cr.y + cr.h || r.y + r.h < cr.y ) - return MU_CLIP_ALL; - if (r.x >= cr.x && r.x + r.w <= cr.x + cr.w && - r.y >= cr.y && r.y + r.h <= cr.y + cr.h ) - return 0; - return MU_CLIP_PART; -} - -static void push_layout(mu_Context *ctx, mu_Rect body, mu_Vec2 scroll) { - mu_Layout layout; - int width = 0; - memset(&layout, 0, sizeof(layout)); - layout.body = mu_rect(body.x - scroll.x, body.y - scroll.y, body.w, body.h); - layout.max = mu_vec2(-0x1000000, -0x1000000); - push(ctx->layout_stack, layout); - mu_layout_row(ctx, 1, &width, 0); -} - -static mu_Layout* get_layout(mu_Context *ctx) { - return &ctx->layout_stack.items[ctx->layout_stack.idx - 1]; -} - -static void pop_container(mu_Context *ctx) { - mu_Container *cnt = mu_get_current_container(ctx); - mu_Layout *layout = get_layout(ctx); - cnt->content_size.x = layout->max.x - layout->body.x; - cnt->content_size.y = layout->max.y - layout->body.y; - /* pop container, layout and id */ - pop(ctx->container_stack); - pop(ctx->layout_stack); - mu_pop_id(ctx); -} - -mu_Container* mu_get_current_container(mu_Context *ctx) { - expect(ctx->container_stack.idx > 0); - return ctx->container_stack.items[ ctx->container_stack.idx - 1 ]; -} - -static mu_Container* get_container(mu_Context *ctx, mu_Id id, mu_opt_enum opt) { - mu_Container *cnt; - /* try to get existing container from pool */ - int idx = mu_pool_get(ctx, ctx->container_pool, MU_CONTAINERPOOL_SIZE, id); - if (idx >= 0) { - if (ctx->containers[idx].open || ~opt & MU_OPT_CLOSED) - mu_pool_update(ctx, ctx->container_pool, idx); - return &ctx->containers[idx]; - } - if (opt & MU_OPT_CLOSED) - return NULL; - /* container not found in pool: init new container */ - idx = mu_pool_init(ctx, ctx->container_pool, MU_CONTAINERPOOL_SIZE, id); - cnt = &ctx->containers[idx]; - memset(cnt, 0, sizeof(*cnt)); - cnt->open = true; - mu_bring_to_front(ctx, cnt); - return cnt; -} - -mu_Container* mu_get_container(mu_Context *ctx, const char *name) { - mu_Id id = mu_get_id(ctx, name, strlen(name)); - return get_container(ctx, id, 0); -} - -void mu_bring_to_front(mu_Context *ctx, mu_Container *cnt) { - cnt->zindex = ++ctx->last_zindex; -} - -/*============================================================================ -** pool -**============================================================================*/ - -int mu_pool_init(mu_Context *ctx, mu_PoolItem *items, size_t len, mu_Id id) { - int i, n = -1, f = ctx->frame; - for (i = 0; i < len; i++) - if (items[i].last_update < f) { - f = items[i].last_update; - n = i; - } - expect(n > -1); - items[n].id = id; - mu_pool_update(ctx, items, n); - return n; -} - -int mu_pool_get(mu_Context *ctx, mu_PoolItem *items, size_t len, mu_Id id) { - int i; - unused(ctx); - for (i = 0; i < len; i++) { - if (items[i].id == id) - return i; - } - return -1; -} - -void mu_pool_update(mu_Context *ctx, mu_PoolItem *items, int idx) { - items[idx].last_update = ctx->frame; -} - -/*============================================================================ -** input handlers -**============================================================================*/ - -void mu_input_mousemove(mu_Context *ctx, int x, int y) { - ctx->mouse_pos = mu_vec2(x, y); -} - -void mu_input_mousedown(mu_Context *ctx, mu_mouse_enum btn) { - ctx->mouse_down |= btn; - ctx->mouse_pressed |= btn; -} - -void mu_input_mouseup(mu_Context *ctx, mu_mouse_enum btn) { - ctx->mouse_down &= ~btn; -} - -void mu_input_scroll(mu_Context *ctx, int x, int y) { - ctx->scroll_delta.x += x; - ctx->scroll_delta.y += y; -} - -void mu_input_keydown(mu_Context *ctx, mu_key_enum key) { - ctx->key_pressed |= key; - ctx->key_down |= key; -} - -void mu_input_keyup(mu_Context *ctx, mu_key_enum key) { - ctx->key_down &= ~key; -} - -void mu_input_text(mu_Context *ctx, const char *text) { - size_t len = strlen(ctx->input_text); - size_t size = strlen(text) + 1; - expect(len + size <= sizeof(ctx->input_text)); - memcpy(ctx->input_text + len, text, size); -} - -/*============================================================================ -** commandlist -**============================================================================*/ - -mu_Command* mu_push_command(mu_Context *ctx, mu_command_enum type, size_t size) { - mu_Command *cmd = (mu_Command*) (ctx->command_list.items + ctx->command_list.idx); - expect(ctx->command_list.idx + size < MU_COMMANDLIST_SIZE); - cmd->base.type = type; - cmd->base.size = size; - ctx->command_list.idx += size; - return cmd; -} - -bool mu_next_command(mu_Context *ctx, mu_Command **cmd) { - if (*cmd) - *cmd = (mu_Command*)(((char*)*cmd) + (*cmd)->base.size); - else - *cmd = (mu_Command*) ctx->command_list.items; - - while ((char*) *cmd != ctx->command_list.items + ctx->command_list.idx) { - if ((*cmd)->type != MU_COMMAND_JUMP) - return true; - *cmd = (*cmd)->jump.dst; - } - return false; -} - -static mu_Command* push_jump(mu_Context *ctx, mu_Command *dst) { - mu_Command *cmd; - cmd = mu_push_command(ctx, MU_COMMAND_JUMP, sizeof(mu_JumpCommand)); - cmd->jump.dst = dst; - return cmd; -} - -void mu_set_clip(mu_Context *ctx, mu_Rect rect) { - mu_Command *cmd; - cmd = mu_push_command(ctx, MU_COMMAND_CLIP, sizeof(mu_ClipCommand)); - cmd->clip.rect = rect; -} - -void mu_draw_rect(mu_Context *ctx, mu_Rect rect, mu_Color color) { - mu_Command *cmd; - rect = intersect_rects(rect, mu_get_clip_rect(ctx)); - if (rect.w > 0 && rect.h > 0) { - cmd = mu_push_command(ctx, MU_COMMAND_RECT, sizeof(mu_RectCommand)); - cmd->rect.rect = rect; - cmd->rect.color = color; - } -} - -void mu_draw_box(mu_Context *ctx, mu_Rect rect, mu_Color color) { - mu_draw_rect(ctx, mu_rect(rect.x + 1, rect.y, rect.w - 2, 1), color); - mu_draw_rect(ctx, mu_rect(rect.x + 1, rect.y + rect.h - 1, rect.w - 2, 1), color); - mu_draw_rect(ctx, mu_rect(rect.x, rect.y, 1, rect.h), color); - mu_draw_rect(ctx, mu_rect(rect.x + rect.w - 1, rect.y, 1, rect.h), color); -} - -void mu_draw_text(mu_Context *ctx, mu_Font font, const char *str, size_t len, mu_Vec2 pos, mu_Color color) { - mu_Command *cmd; - mu_Rect rect = mu_rect( - pos.x, pos.y, ctx->text_width(font, str, len), ctx->text_height(font)); - int clipped = mu_check_clip(ctx, rect); - if (clipped == MU_CLIP_ALL) - return; - if (clipped == MU_CLIP_PART) - mu_set_clip(ctx, mu_get_clip_rect(ctx)); - /* add command */ - if (!len) - len = strlen(str); - cmd = mu_push_command(ctx, MU_COMMAND_TEXT, sizeof(mu_TextCommand) + len); - memcpy(cmd->text.str, str, len); - cmd->text.str[len] = '\0'; - cmd->text.pos = pos; - cmd->text.color = color; - cmd->text.font = font; - /* reset clipping if it was set */ - if (clipped) - mu_set_clip(ctx, unclipped_rect); -} - -void mu_draw_icon(mu_Context *ctx, int id, mu_Rect rect, mu_Color color) { - mu_Command *cmd; - /* do clip command if the rect isn't fully contained within the cliprect */ - int clipped = mu_check_clip(ctx, rect); - if (clipped == MU_CLIP_ALL) - return; - if (clipped == MU_CLIP_PART) - mu_set_clip(ctx, mu_get_clip_rect(ctx)); - /* do icon command */ - cmd = mu_push_command(ctx, MU_COMMAND_ICON, sizeof(mu_IconCommand)); - cmd->icon.id = id; - cmd->icon.rect = rect; - cmd->icon.color = color; - /* reset clipping if it was set */ - if (clipped) - mu_set_clip(ctx, unclipped_rect); -} - -/*============================================================================ -** layout -**============================================================================*/ - -void mu_layout_begin_column(mu_Context *ctx) { - push_layout(ctx, mu_layout_next(ctx), mu_vec2(0, 0)); -} - -void mu_layout_end_column(mu_Context *ctx) { - mu_Layout *a, *b; - b = get_layout(ctx); - pop(ctx->layout_stack); - /* inherit position/next_row/max from child layout if they are greater */ - a = get_layout(ctx); - a->position.x = mu_max(a->position.x, b->position.x + b->body.x - a->body.x); - a->next_row = mu_max(a->next_row, b->next_row + b->body.y - a->body.y); - a->max.x = mu_max(a->max.x, b->max.x); - a->max.y = mu_max(a->max.y, b->max.y); -} - -void mu_layout_row(mu_Context *ctx, int items, const int *widths, int height) { - mu_Layout *layout = get_layout(ctx); - if (widths) { - expect(items <= MU_MAX_WIDTHS); - memcpy(layout->widths, widths, items * sizeof(widths[0])); - } - layout->items = items; - layout->position = mu_vec2(layout->indent, layout->next_row); - layout->size.y = height; - layout->item_index = 0; -} - -void mu_layout_width(mu_Context *ctx, int width) { - get_layout(ctx)->size.x = width; -} - -void mu_layout_height(mu_Context *ctx, int height) { - get_layout(ctx)->size.y = height; -} - -void mu_layout_set_next(mu_Context *ctx, mu_Rect r, int relative) { - mu_Layout *layout = get_layout(ctx); - layout->next = r; - layout->next_type = relative ? MU_LAYOUT_RELATIVE : MU_LAYOUT_ABSOLUTE; -} - -void mu_layout_get_next(mu_Context *ctx, mu_Layout* layout) { - *layout = *get_layout(ctx); -} - -mu_Rect mu_layout_next(mu_Context *ctx) { - mu_Layout *layout = get_layout(ctx); - mu_Style *style = ctx->style; - mu_Rect res; - - if (layout->next_type) { - /* handle rect set by `mu_layout_set_next` */ - mu_layout_enum type = layout->next_type; - layout->next_type = MU_LAYOUT_NONE; - res = layout->next; - if (type == MU_LAYOUT_ABSOLUTE) - return (ctx->last_rect = res); - } - else { - /* handle next row */ - if (layout->item_index == layout->items) - mu_layout_row(ctx, layout->items, NULL, layout->size.y); - - /* position */ - res.x = layout->position.x; - res.y = layout->position.y; - - /* size */ - res.w = layout->items > 0 ? layout->widths[layout->item_index] : layout->size.x; - res.h = layout->size.y; - if (res.w == 0) - res.w = style->size.x + style->padding * 2; - if (res.h == 0) - res.h = style->size.y + style->padding * 2; - if (res.w < 0) - res.w += layout->body.w - res.x + 1; - if (res.h < 0) - res.h += layout->body.h - res.y + 1; - - layout->item_index++; - } - - /* update position */ - layout->position.x += res.w + style->spacing; - layout->next_row = mu_max(layout->next_row, res.y + res.h + style->spacing); - - /* apply body offset */ - res.x += layout->body.x; - res.y += layout->body.y; - - /* update max position */ - layout->max.x = mu_max(layout->max.x, res.x + res.w); - layout->max.y = mu_max(layout->max.y, res.y + res.h); - - return (ctx->last_rect = res); -} - -/*============================================================================ -** controls -**============================================================================*/ - -static bool in_hover_root(mu_Context *ctx) { - size_t i = ctx->container_stack.idx; - while (i--) { - if (ctx->container_stack.items[i] == ctx->hover_root) - return true; - /* only root containers have their `head` field set; stop searching if we've - ** reached the current root container */ - if (ctx->container_stack.items[i]->head) - break; - } - return false; -} - -void mu_draw_control_frame(mu_Context *ctx, mu_Id id, mu_Rect rect, int colorid, mu_opt_enum opt) { - if (opt & MU_OPT_NOFRAME) - return; - colorid += (ctx->focus == id) ? 2 : (ctx->hover == id) ? 1 : 0; - ctx->draw_frame(ctx, rect, colorid); -} - -void mu_draw_control_text(mu_Context *ctx, const char *str, mu_Rect rect, int colorid, mu_opt_enum opt) { - mu_Vec2 pos; - mu_Font font = ctx->style->font; - int tw = ctx->text_width(font, str, 0); - mu_push_clip_rect(ctx, rect); - if (opt & MU_OPT_ALIGNCENTER) - pos.x = rect.x + (rect.w - tw) / 2; - else if (opt & MU_OPT_ALIGNRIGHT) - pos.x = rect.x + rect.w - tw - ctx->style->padding; - else - pos.x = rect.x + ctx->style->padding; - - if (opt & MU_OPT_ALIGNTOP) - pos.y = rect.y + ctx->style->padding; - else if (opt & MU_OPT_ALIGNBOTTOM) - pos.y = rect.y + rect.h - ctx->text_height(font) - ctx->style->padding; - else - pos.y = rect.y + (rect.h - ctx->text_height(font)) / 2; - - mu_draw_text(ctx, font, str, 0, pos, ctx->style->colors[colorid]); - mu_pop_clip_rect(ctx); -} - -bool mu_mouse_over(mu_Context *ctx, mu_Rect rect) { - return rect_overlaps_vec2(rect, ctx->mouse_pos) - && rect_overlaps_vec2(mu_get_clip_rect(ctx), ctx->mouse_pos) - && in_hover_root(ctx); -} - -void mu_update_control(mu_Context *ctx, mu_Id id, mu_Rect rect, mu_opt_enum opt) { - int mouseover = mu_mouse_over(ctx, rect); - - if (ctx->focus == id) - ctx->updated_focus = true; - if (opt & MU_OPT_NOINTERACT) - return; - if (mouseover && !ctx->mouse_down) - ctx->hover = id; - - if (ctx->focus == id) { - if (ctx->mouse_pressed && !mouseover) - mu_set_focus(ctx, 0); - if (!ctx->mouse_down && ~opt & MU_OPT_HOLDFOCUS) - mu_set_focus(ctx, 0); - } - - if (ctx->hover == id) { - if (ctx->mouse_pressed) - mu_set_focus(ctx, id); - else if (!mouseover) - ctx->hover = 0; - } -} - -void mu_text(mu_Context *ctx, const char *text) { - const char *start, *end, *p = text; - int width = -1; - mu_Font font = ctx->style->font; - mu_Color color = ctx->style->colors[MU_COLOR_TEXT]; - mu_layout_begin_column(ctx); - mu_layout_row(ctx, 1, &width, ctx->text_height(font)); - do { - mu_Rect r = mu_layout_next(ctx); - int w = 0; - start = end = p; - do { - const char* word = p; - while (*p && *p != ' ' && *p != '\n') - p++; - w += ctx->text_width(font, word, p - word); - if (w > r.w && end != start) - break; - w += ctx->text_width(font, p, 1); - end = p++; - } while (*end && *end != '\n'); - mu_draw_text(ctx, font, start, end - start, mu_vec2(r.x, r.y), color); - p = end + 1; - } while (*end); - mu_layout_end_column(ctx); -} - -void mu_label(mu_Context *ctx, const char *text) { - mu_draw_control_text(ctx, text, mu_layout_next(ctx), MU_COLOR_TEXT, 0); -} - -mu_res_enum mu_button_ex(mu_Context *ctx, const char *label, int icon, mu_opt_enum opt) { - mu_res_enum res = 0; - mu_Id id = label ? mu_get_id(ctx, label, strlen(label)) - : mu_get_id(ctx, &icon, sizeof(icon)); - mu_Rect r = mu_layout_next(ctx); - mu_update_control(ctx, id, r, opt); - /* handle click */ - if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id) - res |= MU_RES_SUBMIT; - /* draw */ - mu_draw_control_frame(ctx, id, r, MU_COLOR_BUTTON, opt); - if (label) - mu_draw_control_text(ctx, label, r, MU_COLOR_TEXT, opt); - if (icon) - mu_draw_icon(ctx, icon, r, ctx->style->colors[MU_COLOR_TEXT]); - return res; -} - -mu_res_enum mu_checkbox(mu_Context *ctx, const char *label, bool *state) { - mu_res_enum res = 0; - mu_Id id = mu_get_id(ctx, &state, sizeof(state)); - mu_Rect r = mu_layout_next(ctx); - mu_Rect box = mu_rect(r.x, r.y, r.h, r.h); - mu_update_control(ctx, id, r, 0); - /* handle click */ - if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id) { - res |= MU_RES_CHANGE; - *state = !*state; - } - /* draw */ - mu_draw_control_frame(ctx, id, box, MU_COLOR_BASE, 0); - if (*state) - mu_draw_icon(ctx, MU_ICON_CHECK, box, ctx->style->colors[MU_COLOR_TEXT]); - r = mu_rect(r.x + box.w, r.y, r.w - box.w, r.h); - mu_draw_control_text(ctx, label, r, MU_COLOR_TEXT, 0); - return res; -} - -mu_res_enum mu_textbox_raw(mu_Context *ctx, char *buf, size_t bufsz, mu_Id id, mu_Rect r, mu_opt_enum opt) { - mu_res_enum res = 0; - mu_update_control(ctx, id, r, opt | MU_OPT_HOLDFOCUS); - - if (ctx->focus == id) { - ctx->text_input = true; - /* handle text input */ - size_t len = strlen(buf); - size_t n = mu_min(bufsz - len - 1, strlen(ctx->input_text)); - if (n > 0) { - memcpy(buf + len, ctx->input_text, n); - len += n; - buf[len] = '\0'; - res |= MU_RES_CHANGE; - } - /* handle backspace */ - if (ctx->key_pressed & MU_KEY_BACKSPACE && len > 0) { - /* skip utf-8 continuation bytes */ - while ((buf[--len] & 0xc0) == 0x80 && len > 0); - buf[len] = '\0'; - res |= MU_RES_CHANGE; - } - /* handle return */ - if (ctx->key_pressed & MU_KEY_RETURN) { - mu_set_focus(ctx, 0); - res |= MU_RES_SUBMIT; - } - } - - /* draw */ - mu_draw_control_frame(ctx, id, r, MU_COLOR_BASE, opt); - if (ctx->focus == id) { - mu_Color color = ctx->style->colors[MU_COLOR_TEXT]; - mu_Font font = ctx->style->font; - int textw = ctx->text_width(font, buf, 0); - int texth = ctx->text_height(font); - int ofx = r.w - ctx->style->padding - textw - 1; - int textx = r.x + mu_min(ofx, ctx->style->padding); - int texty = r.y + (r.h - texth) / 2; - mu_push_clip_rect(ctx, r); - mu_draw_text(ctx, font, buf, 0, mu_vec2(textx, texty), color); - mu_draw_rect(ctx, mu_rect(textx + textw, texty, 1, texth), color); - mu_pop_clip_rect(ctx); - } - else - mu_draw_control_text(ctx, buf, r, MU_COLOR_TEXT, opt); - - return res; -} - -static bool number_textbox(mu_Context *ctx, mu_Real *value, mu_Rect r, mu_Id id) { - if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->key_down & MU_KEY_SHIFT && ctx->hover == id) { - ctx->number_edit = id; - sprintf_s(ctx->number_edit_buf, MU_MAX_FMT, MU_REAL_FMT, *value); - } - if (ctx->number_edit == id) { - mu_res_enum res = mu_textbox_raw( - ctx, ctx->number_edit_buf, sizeof(ctx->number_edit_buf), id, r, 0); - if (res & MU_RES_SUBMIT || ctx->focus != id) { - *value = strtof(ctx->number_edit_buf, NULL); - ctx->number_edit = 0; - } - else - return true; - } - return false; -} - -mu_res_enum mu_textbox_ex(mu_Context *ctx, char *buf, size_t bufsz, mu_opt_enum opt) { - mu_Id id = mu_get_id(ctx, &buf, sizeof(buf)); - mu_Rect r = mu_layout_next(ctx); - return mu_textbox_raw(ctx, buf, bufsz, id, r, opt); -} - -mu_res_enum mu_slider_ex(mu_Context *ctx, mu_Real *value, mu_Real low, - mu_Real high, mu_Real step, const char *fmt, mu_opt_enum opt) { - char buf[MU_MAX_FMT + 1]; - mu_Rect thumb; - int x, w; - mu_res_enum res = 0; - mu_Real last = *value, v = last; - mu_Id id = mu_get_id(ctx, &value, sizeof(value)); - mu_Rect base = mu_layout_next(ctx); - - /* handle text input mode */ - if (number_textbox(ctx, &v, base, id)) - return res; - - /* handle normal mode */ - mu_update_control(ctx, id, base, opt); - - /* handle input */ - if (ctx->focus == id && (ctx->mouse_down | ctx->mouse_pressed) == MU_MOUSE_LEFT) { - v = low + (ctx->mouse_pos.x - base.x) * (high - low) / base.w; - if (step != 0.0f) - v = roundf(v / step) * step; - } - /* clamp and store value, update res */ - *value = v = mu_clamp(v, low, high); - if (last != v) - res |= MU_RES_CHANGE; - - /* draw base */ - mu_draw_control_frame(ctx, id, base, MU_COLOR_BASE, opt); - /* draw thumb */ - w = ctx->style->thumb_size; - x = (int)((v - low) * (base.w - w) / (high - low)); - thumb = mu_rect(base.x + x, base.y, w, base.h); - mu_draw_control_frame(ctx, id, thumb, MU_COLOR_BUTTON, opt); - /* draw text */ - sprintf_s(buf, MU_MAX_FMT + 1, fmt, v); - mu_draw_control_text(ctx, buf, base, MU_COLOR_TEXT, opt); - return res; -} - -mu_res_enum mu_number_ex(mu_Context *ctx, mu_Real *value, mu_Real step, const char *fmt, mu_opt_enum opt) { - char buf[MU_MAX_FMT + 1]; - mu_res_enum res = 0; - mu_Id id = mu_get_id(ctx, &value, sizeof(value)); - mu_Rect base = mu_layout_next(ctx); - mu_Real last = *value; - - /* handle text input mode */ - if (number_textbox(ctx, value, base, id)) - return res; - - /* handle normal mode */ - mu_update_control(ctx, id, base, opt); - - /* handle input */ - if (ctx->focus == id && ctx->mouse_down == MU_MOUSE_LEFT) - *value += ctx->mouse_delta.x * step; - /* set flag if value changed */ - if (*value != last) - res |= MU_RES_CHANGE; - - /* draw base */ - mu_draw_control_frame(ctx, id, base, MU_COLOR_BASE, opt); - /* draw text */ - sprintf_s(buf, MU_MAX_FMT + 1, fmt, *value); - mu_draw_control_text(ctx, buf, base, MU_COLOR_TEXT, opt); - return res; -} - -static mu_res_enum header(mu_Context *ctx, const char *label, int istreenode, mu_opt_enum opt) { - mu_Rect r; - int active, expanded; - mu_Id id = mu_get_id(ctx, label, strlen(label)); - int idx = mu_pool_get(ctx, ctx->treenode_pool, MU_TREENODEPOOL_SIZE, id); - int width = -1; - mu_layout_row(ctx, 1, &width, 0); - - active = (idx >= 0); - expanded = (opt & MU_OPT_EXPANDED) ? !active : active; - r = mu_layout_next(ctx); - mu_update_control(ctx, id, r, 0); - - /* handle click */ - active ^= (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id); - - /* update pool ref */ - if (idx >= 0) { - if (active) - mu_pool_update(ctx, ctx->treenode_pool, idx); - else - memset(&ctx->treenode_pool[idx], 0, sizeof(mu_PoolItem)); - } - else if (active) - mu_pool_init(ctx, ctx->treenode_pool, MU_TREENODEPOOL_SIZE, id); - - /* draw */ - if (!istreenode) - mu_draw_control_frame(ctx, id, r, MU_COLOR_BUTTON, 0); - else if (ctx->hover == id) - ctx->draw_frame(ctx, r, MU_COLOR_BUTTONHOVER); - - mu_draw_icon( - ctx, expanded ? MU_ICON_EXPANDED : MU_ICON_COLLAPSED, - mu_rect(r.x, r.y, r.h, r.h), ctx->style->colors[MU_COLOR_TEXT]); - r.x += r.h - ctx->style->padding; - r.w -= r.h - ctx->style->padding; - mu_draw_control_text(ctx, label, r, MU_COLOR_TEXT, 0); - return expanded ? MU_RES_ACTIVE : 0; -} - -mu_res_enum mu_header_ex(mu_Context *ctx, const char *label, mu_opt_enum opt) { - return header(ctx, label, 0, opt); -} - -mu_res_enum mu_begin_treenode_ex(mu_Context *ctx, const char *label, mu_opt_enum opt) { - mu_res_enum res = header(ctx, label, 1, opt); - if (res & MU_RES_ACTIVE) { - get_layout(ctx)->indent += ctx->style->indent; - push(ctx->id_stack, ctx->last_id); - } - return res; -} - -void mu_end_treenode(mu_Context *ctx) { - get_layout(ctx)->indent -= ctx->style->indent; - mu_pop_id(ctx); -} - -#define scrollbar(ctx, cnt, b, cs, x, y, w, h) \ - do { \ - /* only add scrollbar if content size is larger than body */ \ - int maxscroll = cs.y - b.h; \ - \ - if (maxscroll > 0 && b.h > 0) { \ - mu_Rect base, thumb; \ - mu_Id id = mu_get_id(ctx, "!scrollbar" #y, 11); \ - \ - /* get sizing / positioning */ \ - base = b; \ - base.x = b.x + b.w; \ - base.w = ctx->style->scrollbar_size; \ - \ - /* handle input */ \ - mu_update_control(ctx, id, base, 0); \ - if (ctx->focus == id && ctx->mouse_down == MU_MOUSE_LEFT) \ - cnt->scroll.y += ctx->mouse_delta.y * cs.y / base.h; \ - /* clamp scroll to limits */ \ - cnt->scroll.y = mu_clamp(cnt->scroll.y, 0, maxscroll); \ - \ - /* draw base and thumb */ \ - ctx->draw_frame(ctx, base, MU_COLOR_SCROLLBASE); \ - thumb = base; \ - thumb.h = mu_max(ctx->style->thumb_size, base.h * b.h / cs.y); \ - thumb.y += cnt->scroll.y * (base.h - thumb.h) / maxscroll; \ - ctx->draw_frame(ctx, thumb, MU_COLOR_SCROLLTHUMB); \ - \ - /* set this as the scroll_target (will get scrolled on mousewheel) */ \ - /* if the mouse is over it */ \ - if (mu_mouse_over(ctx, b)) \ - ctx->scroll_target = cnt; \ - } \ - else \ - cnt->scroll.y = 0; \ - } while (0) - -static void push_container_body(mu_Context *ctx, mu_Container *cnt, mu_Rect body, mu_opt_enum opt, bool swap_scroll) { - if (~opt & MU_OPT_NOSCROLL) { - cnt->swap_scroll = swap_scroll; - int sz = ctx->style->scrollbar_size; - mu_Vec2 cs = cnt->content_size; - cs.x += ctx->style->padding * 2; - cs.y += ctx->style->padding * 2; - mu_push_clip_rect(ctx, body); - /* resize body to make room for scrollbars */ - if (cs.y > cnt->body.h) - body.w -= sz; - if (cs.x > cnt->body.w) - body.h -= sz; - /* to create a horizontal or vertical scrollbar almost-identical code is - ** used; only the references to `x|y` `w|h` need to be switched */ - scrollbar(ctx, cnt, body, cs, x, y, w, h); - scrollbar(ctx, cnt, body, cs, y, x, h, w); - mu_pop_clip_rect(ctx); - } - - push_layout(ctx, expand_rect(body, -ctx->style->padding), cnt->scroll); - cnt->body = body; -} - -static void begin_root_container(mu_Context *ctx, mu_Container *cnt) { - push(ctx->container_stack, cnt); - /* push container to roots list and push head command */ - push(ctx->root_list, cnt); - cnt->head = push_jump(ctx, NULL); - /* set as hover root if the mouse is overlapping this container and it has a - ** higher zindex than the current hover root */ - if (rect_overlaps_vec2(cnt->rect, ctx->mouse_pos) - && (!ctx->next_hover_root || cnt->zindex > ctx->next_hover_root->zindex)) - ctx->next_hover_root = cnt; - /* clipping is reset here in case a root-container is made within - ** another root-containers's begin/end block; this prevents the inner - ** root-container being clipped to the outer */ - push(ctx->clip_stack, unclipped_rect); -} - -static void end_root_container(mu_Context *ctx) { - /* push tail 'goto' jump command and set head 'skip' command. the final steps - ** on initing these are done in mu_end() */ - mu_Container *cnt = mu_get_current_container(ctx); - cnt->tail = push_jump(ctx, NULL); - cnt->head->jump.dst = ctx->command_list.items + ctx->command_list.idx; - /* pop base clip rect and container */ - mu_pop_clip_rect(ctx); - pop_container(ctx); -} - -mu_res_enum mu_begin_window_ex(mu_Context *ctx, const char *title, - mu_Rect rect, mu_opt_enum opt, bool reset_pos, bool reset_size, bool swap_scroll) { - mu_Rect body; - mu_Id id = mu_get_id(ctx, title, strlen(title)); - mu_Container *cnt = get_container(ctx, id, opt); - if (!cnt || !cnt->open) - return 0; - push(ctx->id_stack, id); - - if (cnt->rect.w == 0) - cnt->rect = rect; - - if (reset_size) { - cnt->rect.w = rect.w; - cnt->rect.h = rect.h; - } - - if (reset_pos) { - cnt->rect.x = rect.x; - cnt->rect.y = rect.y; - } - - begin_root_container(ctx, cnt); - rect = body = cnt->rect; - - /* draw frame */ - if (~opt & MU_OPT_NOFRAME) - ctx->draw_frame(ctx, rect, MU_COLOR_WINDOWBG); - - /* do title bar */ - if (~opt & MU_OPT_NOTITLE) { - mu_Rect tr = rect; - tr.h = ctx->style->title_height; - ctx->draw_frame(ctx, tr, MU_COLOR_TITLEBG); - - /* do title text */ - if (~opt & MU_OPT_NOTITLE) { - mu_Id id = mu_get_id(ctx, "!title", 6); - mu_update_control(ctx, id, tr, opt); - mu_draw_control_text(ctx, title, tr, MU_COLOR_TITLETEXT, opt); - if (id == ctx->focus && ctx->mouse_down == MU_MOUSE_LEFT) { - cnt->rect.x += ctx->mouse_delta.x; - cnt->rect.y += ctx->mouse_delta.y; - } - body.y += tr.h; - body.h -= tr.h; - } - - /* do `close` button */ - if (~opt & MU_OPT_NOCLOSE) { - mu_Id id = mu_get_id(ctx, "!close", 6); - mu_Rect r = mu_rect(tr.x + tr.w - tr.h, tr.y, tr.h, tr.h); - tr.w -= r.w; - mu_draw_icon(ctx, MU_ICON_CLOSE, r, ctx->style->colors[MU_COLOR_TITLETEXT]); - mu_update_control(ctx, id, r, opt); - if (ctx->mouse_pressed == MU_MOUSE_LEFT && id == ctx->focus) - cnt->open = false; - } - } - - push_container_body(ctx, cnt, body, opt, swap_scroll); - - /* resize to content size */ - if (opt & MU_OPT_AUTOSIZE) { - mu_Rect r = get_layout(ctx)->body; - cnt->rect.w = cnt->content_size.x + (cnt->rect.w - r.w); - cnt->rect.h = cnt->content_size.y + (cnt->rect.h - r.h); - } - - /* close if this is a popup window and elsewhere was clicked */ - if (opt & MU_OPT_POPUP && ctx->mouse_pressed && ctx->hover_root != cnt) - cnt->open = false; - - mu_push_clip_rect(ctx, cnt->body); - return MU_RES_ACTIVE; -} - -void mu_end_window(mu_Context *ctx) { - mu_pop_clip_rect(ctx); - end_root_container(ctx); -} - -void mu_open_popup(mu_Context *ctx, const char *name) { - mu_Container *cnt = mu_get_container(ctx, name); - /* set as hover root so popup isn't closed in begin_window_ex() */ - ctx->hover_root = ctx->next_hover_root = cnt; - /* position at mouse cursor, open and bring-to-front */ - cnt->rect = mu_rect(ctx->mouse_pos.x, ctx->mouse_pos.y, 1, 1); - cnt->open = true; - mu_bring_to_front(ctx, cnt); -} - -mu_res_enum mu_begin_popup(mu_Context *ctx, const char *name) { - mu_opt_enum opt = MU_OPT_POPUP | MU_OPT_AUTOSIZE | - MU_OPT_NOSCROLL | MU_OPT_NOTITLE | MU_OPT_CLOSED; - return mu_begin_window_ex(ctx, name, mu_rect(0, 0, 0, 0), opt, false, false, false); -} - -void mu_end_popup(mu_Context *ctx) { - mu_end_window(ctx); -} - -void mu_begin_panel_ex(mu_Context *ctx, const char *name, mu_opt_enum opt, bool swap_scroll) { - mu_Container *cnt; - mu_push_id(ctx, name, strlen(name)); - cnt = get_container(ctx, ctx->last_id, opt); - cnt->rect = mu_layout_next(ctx); - if (~opt & MU_OPT_NOFRAME) - ctx->draw_frame(ctx, cnt->rect, MU_COLOR_PANELBG); - push(ctx->container_stack, cnt); - push_container_body(ctx, cnt, cnt->rect, opt, swap_scroll); - mu_push_clip_rect(ctx, cnt->body); -} - -void mu_end_panel(mu_Context *ctx) { - mu_pop_clip_rect(ctx); - pop_container(ctx); -} - -/*============================================================================ -** tabs -**============================================================================*/ - -void mu_tabs_get_title_size(mu_Context* muctx, int32_t min, int32_t max, - int32_t* w, int32_t* h, char** temp, int32_t* temp_w) { - const mu_Font font = muctx->style->font; - const int32_t spacing = muctx->style->spacing; - int32_t title_width = 0; - for (int32_t i = min; i < max; i++) { - temp_w[i] = muctx->text_width(font, temp[i], strlen(temp[i])) + spacing * 2; - title_width += temp_w[i] + spacing; - } - - if (title_width > *w) - *h += muctx->style->scrollbar_size; -} - -bool mu_tabs_set(mu_Context* muctx, int32_t min, int32_t max, char** temp, - int32_t* temp_w, int32_t temp_c, int32_t* selector, char* name, mu_Rect rect, bool focus_reset) { - if (!mu_begin_window_ex(muctx, name, rect, - MU_OPT_NOINTERACT | MU_OPT_NOCLOSE | MU_OPT_NOTITLE, true, true, true)) - return false; - - bool has_focus = !muctx->updated_focus; - if (!has_focus && muctx->focus == mu_get_id(muctx, name, strlen(name))) - has_focus = true; - - mu_layout_row(muctx, temp_c, temp_w, 0); - for (int32_t i = min; i < max; i++) { - mu_push_id(muctx, &i, sizeof(i)); - if (i == *selector) - mu_draw_control_text(muctx, temp[i], mu_layout_next(muctx), MU_COLOR_TEXT, MU_OPT_ALIGNCENTER); - else if (mu_button(muctx, temp[i])) - *selector = i; - - if (!has_focus && muctx->focus == mu_get_id(muctx, temp[i], strlen(temp[i]))) - has_focus = true; - mu_pop_id(muctx); - } - mu_end_window(muctx); - - if (!has_focus && focus_reset) - *selector = -1; - return true; -} - -/*============================================================================ -** custom funcs -**============================================================================*/ - -mu_res_enum mu_slider_uint8_t(mu_Context* ctx, uint8_t* value, int32_t low, int32_t high) { - static float_t tmp; - mu_push_id(ctx, &value, sizeof(value)); - tmp = *value; - mu_res_enum res = mu_slider_ex(ctx, &tmp, (mu_Real)low, (mu_Real)high, 1, "%.0f", MU_OPT_ALIGNCENTER); - *value = (uint8_t)tmp; - mu_pop_id(ctx); - return res; -} - -mu_res_enum mu_slider_uint8_t_label(mu_Context* ctx, uint8_t* value, int32_t low, int32_t high, const char* label) { - static float_t tmp; - mu_push_id(ctx, &value, sizeof(value)); - tmp = *value; - mu_res_enum res = mu_slider_ex(ctx, &tmp, (mu_Real)low, (mu_Real)high, 1, label, MU_OPT_ALIGNCENTER); - *value = (uint8_t)tmp; - mu_pop_id(ctx); - return res; -} - -/*============================================================================ -** misc -**============================================================================*/ - -int32_t mu_misc_get_max_text_width(mu_Context* muctx, char** temp, size_t temp_c) { - int32_t max_w, w; - const mu_Font font = muctx->style->font; - const int32_t spacing = muctx->style->spacing; - max_w = 0; - for (size_t i = 0; i < temp_c; i++) { - w = muctx->text_width(font, temp[i], strlen(temp[i])) + spacing * 2; - if (max_w < w) - max_w = w; - } - return max_w; -} diff --git a/src/CRE/microui.h b/src/CRE/microui.h deleted file mode 100644 index 6cec8aab..00000000 --- a/src/CRE/microui.h +++ /dev/null @@ -1,379 +0,0 @@ -/* -** Copyright (c) 2020 rxi -** -** This library is free software; you can redistribute it and/or modify it -** under the terms of the MIT license. See `microui.c` for details. -*/ - -#pragma once - -#include "../KKdLib/default.h" - -#define MU_VERSION "2.01" - -#define MU_COMMANDLIST_SIZE (256 * 1024) -#define MU_ROOTLIST_SIZE 32 -#define MU_CONTAINERSTACK_SIZE 32 -#define MU_CLIPSTACK_SIZE 32 -#define MU_IDSTACK_SIZE 32 -#define MU_LAYOUTSTACK_SIZE 16 -#define MU_CONTAINERPOOL_SIZE 48 -#define MU_TREENODEPOOL_SIZE 48 -#define MU_MAX_WIDTHS 16 -#define MU_REAL float -#define MU_REAL_FMT "%g" -#define MU_SLIDER_FMT "%.2f" -#define MU_MAX_FMT 127 - -#define mu_stack(T, n) struct { size_t idx; T items[n]; } -#define mu_min(a, b) ((a) < (b) ? (a) : (b)) -#define mu_max(a, b) ((a) > (b) ? (a) : (b)) -#define mu_clamp(x, a, b) mu_min(b, mu_max(a, x)) - -typedef enum mu_clip_enum { - MU_CLIP_NONE = 0, - MU_CLIP_PART, - MU_CLIP_ALL -} mu_clip_enum; - -typedef enum mu_command_enum { - MU_COMMAND_NONE = 0, - MU_COMMAND_JUMP, - MU_COMMAND_CLIP, - MU_COMMAND_RECT, - MU_COMMAND_TEXT, - MU_COMMAND_ICON, - MU_COMMAND_TEX, - MU_COMMAND_MAX -} mu_command_enum; - -typedef enum mu_color_enum { - MU_COLOR_TEXT = 0, - MU_COLOR_BORDER, - MU_COLOR_WINDOWBG, - MU_COLOR_TITLEBG, - MU_COLOR_TITLETEXT, - MU_COLOR_PANELBG, - MU_COLOR_BUTTON, - MU_COLOR_BUTTONHOVER, - MU_COLOR_BUTTONFOCUS, - MU_COLOR_BASE, - MU_COLOR_BASEHOVER, - MU_COLOR_BASEFOCUS, - MU_COLOR_SCROLLBASE, - MU_COLOR_SCROLLTHUMB, - MU_COLOR_MAX -} mu_color_enum; - -typedef enum mu_icon_enum { - MU_ICON_NONE = 0, - MU_ICON_CLOSE, - MU_ICON_CHECK, - MU_ICON_COLLAPSED, - MU_ICON_EXPANDED, - MU_ICON_MAX -} mu_icon_enum; - -typedef enum mu_res_enum { - MU_RES_ACTIVE = (1 << 0), - MU_RES_SUBMIT = (1 << 1), - MU_RES_CHANGE = (1 << 2), -} mu_res_enum; - -typedef enum mu_opt_enum { - MU_OPT_ALIGNCENTER = (1 << 0), - MU_OPT_ALIGNRIGHT = (1 << 1), - MU_OPT_NOINTERACT = (1 << 2), - MU_OPT_NOFRAME = (1 << 3), - MU_OPT_NOSCROLL = (1 << 4), - MU_OPT_NOCLOSE = (1 << 5), - MU_OPT_NOTITLE = (1 << 6), - MU_OPT_HOLDFOCUS = (1 << 7), - MU_OPT_AUTOSIZE = (1 << 8), - MU_OPT_POPUP = (1 << 9), - MU_OPT_CLOSED = (1 << 10), - MU_OPT_EXPANDED = (1 << 11), - MU_OPT_ALIGNTOP = (1 << 12), - MU_OPT_ALIGNBOTTOM = (1 << 13), -} mu_opt_enum; - -typedef enum mu_mouse_enum { - MU_MOUSE_LEFT = (1 << 0), - MU_MOUSE_RIGHT = (1 << 1), - MU_MOUSE_MIDDLE = (1 << 2), -} mu_mouse_enum; - -typedef enum mu_key_enum { - MU_KEY_SHIFT = (1 << 0), - MU_KEY_CTRL = (1 << 1), - MU_KEY_ALT = (1 << 2), - MU_KEY_BACKSPACE = (1 << 3), - MU_KEY_RETURN = (1 << 4), -} mu_key_enum; - -typedef enum mu_layout_enum { - MU_LAYOUT_NONE = 0, - MU_LAYOUT_RELATIVE, - MU_LAYOUT_ABSOLUTE, -} mu_layout_enum; - -typedef struct mu_Context mu_Context; -typedef unsigned mu_Id; -typedef MU_REAL mu_Real; -typedef void* mu_Font; - -typedef struct mu_Vec2 { - int32_t x; - int32_t y; -} mu_Vec2; - -typedef struct mu_Rect { - int32_t x; - int32_t y; - int32_t w; - int32_t h; -} mu_Rect; - -typedef struct mu_Color { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -} mu_Color; - -typedef struct mu_PoolItem { - mu_Id id; - int last_update; -} mu_PoolItem; - -typedef struct mu_BaseCommand { - mu_command_enum type; - size_t size; -} mu_BaseCommand; - -typedef struct mu_JumpCommand { - mu_BaseCommand base; - void *dst; -} mu_JumpCommand; - -typedef struct mu_ClipCommand { - mu_BaseCommand base; - mu_Rect rect; -} mu_ClipCommand; - -typedef struct mu_RectCommand { - mu_BaseCommand base; - mu_Rect rect; - mu_Color color; -} mu_RectCommand; - -typedef struct mu_TextCommand { - mu_BaseCommand base; - mu_Font font; - mu_Vec2 pos; - mu_Color color; - char str[1]; -} mu_TextCommand; - -typedef struct mu_IconCommand { - mu_BaseCommand base; - mu_Rect rect; - int id; - mu_Color color; -} mu_IconCommand; - -typedef struct mu_TexCommand { - mu_BaseCommand base; - mu_Rect rect; - mu_Rect draw; - mu_Color color; -} mu_TexCommand; - -typedef union mu_Command { - mu_command_enum type; - mu_BaseCommand base; - mu_JumpCommand jump; - mu_ClipCommand clip; - mu_RectCommand rect; - mu_TextCommand text; - mu_IconCommand icon; - mu_TexCommand tex; -} mu_Command; - -typedef struct mu_Layout { - mu_Rect body; - mu_Rect next; - mu_Vec2 position; - mu_Vec2 size; - mu_Vec2 max; - int widths[MU_MAX_WIDTHS]; - int items; - int item_index; - int next_row; - mu_layout_enum next_type; - int indent; -} mu_Layout; - -typedef struct mu_Container { - mu_Command *head, *tail; - mu_Rect rect; - mu_Rect body; - mu_Vec2 content_size; - mu_Vec2 scroll; - int zindex; - bool open; - bool swap_scroll; -} mu_Container; - -typedef struct mu_Style { - mu_Font font; - mu_Vec2 size; - int padding; - int spacing; - int indent; - int title_height; - int scrollbar_size; - int thumb_size; - mu_Color colors[MU_COLOR_MAX]; -} mu_Style; - -struct mu_Context { - /* callbacks */ - int (*text_width)(mu_Font font, const char *str, size_t len); - int (*text_height)(mu_Font font); - void (*draw_frame)(mu_Context *ctx, mu_Rect rect, int colorid); - /* core state */ - mu_Style _style; - mu_Style *style; - mu_Id hover; - mu_Id focus; - mu_Id last_id; - mu_Rect last_rect; - int last_zindex; - bool updated_focus; - int frame; - mu_Container *hover_root; - mu_Container *next_hover_root; - mu_Container *scroll_target; - char number_edit_buf[MU_MAX_FMT]; - mu_Id number_edit; - /* stacks */ - mu_stack(char, MU_COMMANDLIST_SIZE) command_list; - mu_stack(mu_Container*, MU_ROOTLIST_SIZE) root_list; - mu_stack(mu_Container*, MU_CONTAINERSTACK_SIZE) container_stack; - mu_stack(mu_Rect, MU_CLIPSTACK_SIZE) clip_stack; - mu_stack(mu_Id, MU_IDSTACK_SIZE) id_stack; - mu_stack(mu_Layout, MU_LAYOUTSTACK_SIZE) layout_stack; - /* retained state pools */ - mu_PoolItem container_pool[MU_CONTAINERPOOL_SIZE]; - mu_Container containers[MU_CONTAINERPOOL_SIZE]; - mu_PoolItem treenode_pool[MU_TREENODEPOOL_SIZE]; - /* input state */ - mu_Vec2 mouse_pos; - mu_Vec2 last_mouse_pos; - mu_Vec2 mouse_delta; - mu_Vec2 scroll_delta; - mu_mouse_enum mouse_down; - mu_mouse_enum mouse_pressed; - mu_key_enum key_down; - mu_key_enum key_pressed; - char input_text[32]; - bool text_input; -}; - -mu_Vec2 mu_vec2(int32_t x, int32_t y); -mu_Rect mu_rect(int32_t x, int32_t y, int32_t w, int32_t h); -mu_Color mu_color(int32_t r, int32_t g, int32_t b, int32_t a); -mu_Color mu_color_real(float_t r, float_t g, float_t b, float_t a); - -void mu_init(mu_Context *ctx); -void mu_begin(mu_Context *ctx); -void mu_end(mu_Context *ctx); -void mu_set_focus(mu_Context *ctx, mu_Id id); -mu_Id mu_get_id(mu_Context *ctx, const void *data, size_t size); -void mu_push_id(mu_Context *ctx, const void *data, size_t size); -void mu_pop_id(mu_Context *ctx); -void mu_push_clip_rect(mu_Context *ctx, mu_Rect rect); -void mu_pop_clip_rect(mu_Context *ctx); -mu_Rect mu_get_clip_rect(mu_Context *ctx); -mu_clip_enum mu_check_clip(mu_Context *ctx, mu_Rect r); -mu_Container* mu_get_current_container(mu_Context *ctx); -mu_Container* mu_get_container(mu_Context *ctx, const char *name); -void mu_bring_to_front(mu_Context *ctx, mu_Container *cnt); - -int mu_pool_init(mu_Context *ctx, mu_PoolItem *items, size_t len, mu_Id id); -int mu_pool_get(mu_Context *ctx, mu_PoolItem *items, size_t len, mu_Id id); -void mu_pool_update(mu_Context *ctx, mu_PoolItem *items, int idx); - -void mu_input_mousemove(mu_Context *ctx, int x, int y); -void mu_input_mousedown(mu_Context *ctx, mu_mouse_enum btn); -void mu_input_mouseup(mu_Context *ctx, mu_mouse_enum btn); -void mu_input_scroll(mu_Context *ctx, int x, int y); -void mu_input_keydown(mu_Context *ctx, mu_key_enum key); -void mu_input_keyup(mu_Context *ctx, mu_key_enum key); -void mu_input_text(mu_Context *ctx, const char *text); - -mu_Command* mu_push_command(mu_Context *ctx, mu_command_enum type, size_t size); -bool mu_next_command(mu_Context *ctx, mu_Command **cmd); -void mu_set_clip(mu_Context *ctx, mu_Rect rect); -void mu_draw_rect(mu_Context *ctx, mu_Rect rect, mu_Color color); -void mu_draw_box(mu_Context *ctx, mu_Rect rect, mu_Color color); -void mu_draw_text(mu_Context *ctx, mu_Font font, const char *str, size_t len, mu_Vec2 pos, mu_Color color); -void mu_draw_icon(mu_Context *ctx, int id, mu_Rect rect, mu_Color color); - -void mu_layout_row(mu_Context *ctx, int items, const int *widths, int height); -void mu_layout_width(mu_Context *ctx, int width); -void mu_layout_height(mu_Context *ctx, int height); -void mu_layout_begin_column(mu_Context *ctx); -void mu_layout_end_column(mu_Context *ctx); -void mu_layout_set_next(mu_Context *ctx, mu_Rect r, int relative); -void mu_layout_get_next(mu_Context* ctx, mu_Layout* layout); -mu_Rect mu_layout_next(mu_Context *ctx); - -void mu_draw_control_frame(mu_Context *ctx, mu_Id id, mu_Rect rect, int colorid, mu_opt_enum opt); -void mu_draw_control_text(mu_Context *ctx, const char *str, mu_Rect rect, int colorid, mu_opt_enum opt); -bool mu_mouse_over(mu_Context *ctx, mu_Rect rect); -void mu_update_control(mu_Context *ctx, mu_Id id, mu_Rect rect, mu_opt_enum opt); - -#define mu_button(ctx, label) mu_button_ex(ctx, label, 0, MU_OPT_ALIGNCENTER) -#define mu_textbox(ctx, buf, bufsz) mu_textbox_ex(ctx, buf, bufsz, 0) -#define mu_slider(ctx, value, lo, hi) mu_slider_ex(ctx, value, lo, hi, 0, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER) -#define mu_number(ctx, value, step) mu_number_ex(ctx, value, step, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER) -#define mu_header(ctx, label) mu_header_ex(ctx, label, 0) -#define mu_begin_treenode(ctx, label) mu_begin_treenode_ex(ctx, label, 0) -#define mu_begin_window(ctx, title, rect) mu_begin_window_ex(ctx, title, rect, 0, false, false, false) -#define mu_begin_panel(ctx, name) mu_begin_panel_ex(ctx, name, 0, false) - -#define mu_slider_step(ctx, value, low, high, step) \ -mu_slider_ex(ctx, value, low, high, step, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER); -#define mu_slider_fmt(ctx, value, low, high, step, fmt) \ -mu_slider_ex(ctx, value, low, high, step, fmt, MU_OPT_ALIGNCENTER); -#define mu_number_fmt(ctx, value, step, fmt) \ -mu_number_ex(ctx, value, step, fmt, MU_OPT_ALIGNCENTER) - -void mu_text(mu_Context *ctx, const char *text); -void mu_label(mu_Context *ctx, const char *text); -mu_res_enum mu_button_ex(mu_Context *ctx, const char *label, int icon, mu_opt_enum opt); -mu_res_enum mu_checkbox(mu_Context *ctx, const char *label, bool *state); -mu_res_enum mu_textbox_raw(mu_Context *ctx, char *buf, size_t bufsz, mu_Id id, mu_Rect r, mu_opt_enum opt); -mu_res_enum mu_textbox_ex(mu_Context *ctx, char *buf, size_t bufsz, mu_opt_enum opt); -mu_res_enum mu_slider_ex(mu_Context *ctx, mu_Real *value, mu_Real low, mu_Real high, mu_Real step, const char *fmt, mu_opt_enum opt); -mu_res_enum mu_number_ex(mu_Context *ctx, mu_Real *value, mu_Real step, const char *fmt, mu_opt_enum opt); -mu_res_enum mu_header_ex(mu_Context *ctx, const char *label, mu_opt_enum opt); -mu_res_enum mu_begin_treenode_ex(mu_Context *ctx, const char *label, mu_opt_enum opt); -void mu_end_treenode(mu_Context *ctx); -mu_res_enum mu_begin_window_ex(mu_Context *ctx, const char *title, - mu_Rect rect, mu_opt_enum opt, bool reset_pos, bool reset_size, bool swap_scroll); -void mu_end_window(mu_Context *ctx); -void mu_open_popup(mu_Context *ctx, const char *name); -mu_res_enum mu_begin_popup(mu_Context *ctx, const char *name); -void mu_end_popup(mu_Context *ctx); -void mu_begin_panel_ex(mu_Context *ctx, const char *name, mu_opt_enum opt, bool swap_scroll); -void mu_end_panel(mu_Context *ctx); -void mu_tabs_get_title_size(mu_Context* muctx, int32_t min, int32_t max, - int32_t* w, int32_t* h, char** temp, int32_t* temp_w); -bool mu_tabs_set(mu_Context* muctx, int32_t min, int32_t max, char** temp, - int32_t* temp_w, int32_t temp_c, int32_t* selector, char* name, mu_Rect rect, bool focus_reset); -mu_res_enum mu_slider_uint8_t(mu_Context* ctx, uint8_t* value, int32_t low, int32_t high); -mu_res_enum mu_slider_uint8_t_label(mu_Context* ctx, uint8_t* value, int32_t low, int32_t high, const char* label); -int32_t mu_misc_get_max_text_width(mu_Context* muctx, char** temp, size_t temp_c); diff --git a/src/CRE/microui_atlas.inl b/src/CRE/microui_atlas.inl deleted file mode 100644 index 79901413..00000000 --- a/src/CRE/microui_atlas.inl +++ /dev/null @@ -1,994 +0,0 @@ - -enum { ATLAS_WHITE = MU_ICON_MAX, ATLAS_FONT }; -enum { ATLAS_WIDTH = 128, ATLAS_HEIGHT = 128 }; - - -static unsigned char atlas_texture[ATLAS_WIDTH * ATLAS_HEIGHT] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xc0, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x32, 0x0b, 0x00, 0x00, 0x00, - 0x00, 0x31, 0x35, 0x01, 0x00, 0x00, 0x00, 0x15, 0x35, 0x1d, 0x30, 0x19, - 0x00, 0x00, 0x0f, 0x35, 0x06, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x2d, 0x00, 0x00, 0x00, - 0x14, 0x26, 0x00, 0x00, 0x31, 0x2a, 0x00, 0x00, 0x00, 0x10, 0x31, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x3e, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x3e, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, - 0x31, 0x35, 0x2f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x41, - 0x37, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x21, 0xe0, 0xea, 0x2c, 0x00, 0x00, 0x00, 0x00, - 0x36, 0xc4, 0xdb, 0xb2, 0xd9, 0xc1, 0x1a, 0x00, 0x00, 0xea, 0xff, 0x39, - 0x00, 0x00, 0x00, 0x9e, 0xff, 0x88, 0xbe, 0x9c, 0x00, 0x00, 0x72, 0xff, - 0x48, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xe4, 0xce, 0x8d, 0x00, 0x00, 0xb5, 0x60, 0x00, 0x00, - 0xea, 0xfa, 0x2c, 0x00, 0x00, 0x4e, 0xeb, 0x00, 0x00, 0x1c, 0x8f, 0xea, - 0xea, 0xee, 0x92, 0x1f, 0x00, 0x00, 0x1c, 0x8f, 0xea, 0xea, 0xee, 0x92, - 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x42, 0xf3, 0xcd, 0xf5, 0x3a, 0x00, 0x00, 0x00, 0xea, 0xf2, 0xef, 0xe5, - 0x8f, 0x2f, 0x00, 0x00, 0x0f, 0xa0, 0xfe, 0xf2, 0xf1, 0xfa, 0x33, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, - 0xe0, 0xea, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x35, 0xdc, 0x33, 0x00, 0x06, - 0x00, 0x5a, 0xd7, 0x13, 0x00, 0xea, 0xd8, 0x92, 0x00, 0x00, 0x09, 0xf0, - 0xd9, 0x88, 0x7b, 0xda, 0x00, 0x00, 0xb9, 0xe9, 0x91, 0x00, 0x05, 0xf4, - 0x03, 0x35, 0x02, 0x32, 0x1f, 0x00, 0x04, 0x37, 0x24, 0x00, 0x5b, 0xa9, - 0x1b, 0xe7, 0x01, 0x44, 0xd0, 0x02, 0x00, 0x00, 0xea, 0xe4, 0xc3, 0x01, - 0x00, 0x4e, 0xeb, 0x00, 0x00, 0x8f, 0xd8, 0x42, 0x01, 0x3a, 0xd0, 0x9b, - 0x00, 0x00, 0x8f, 0xd8, 0x42, 0x01, 0x3a, 0xd0, 0x9b, 0x00, 0x2e, 0x1a, - 0x00, 0x03, 0x36, 0x19, 0x00, 0x04, 0x36, 0x00, 0xa3, 0xa0, 0x00, 0xb5, - 0x8d, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x01, 0x3d, 0xac, 0xe5, 0x03, 0x00, - 0xa1, 0xeb, 0x63, 0x0c, 0x03, 0x2e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xe1, 0xeb, 0x2d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xd6, 0x38, 0x37, 0xb4, 0xd6, 0xe9, 0x35, 0x9e, 0x5c, - 0x00, 0xea, 0x87, 0xe8, 0x03, 0x00, 0x56, 0xcc, 0xba, 0x88, 0x38, 0xff, - 0x1a, 0x09, 0xf7, 0x84, 0xd9, 0x00, 0x39, 0xfe, 0x0e, 0xff, 0xb7, 0xe1, - 0xf3, 0x94, 0xbc, 0xde, 0xfb, 0x97, 0x73, 0x9b, 0x0b, 0xfb, 0x0b, 0xcf, - 0x44, 0x01, 0x00, 0x00, 0xea, 0x65, 0xf7, 0x63, 0x00, 0x4e, 0xeb, 0x00, - 0x01, 0xe0, 0x79, 0x00, 0x00, 0x00, 0x6b, 0xea, 0x03, 0x01, 0xe0, 0x79, - 0x00, 0x00, 0x00, 0x6b, 0xea, 0x03, 0xb0, 0xa4, 0x00, 0x39, 0xfe, 0xa0, - 0x00, 0x3d, 0xfd, 0x00, 0x6e, 0xe0, 0x5b, 0xef, 0x41, 0x00, 0x00, 0x00, - 0xea, 0x6d, 0x00, 0x00, 0x17, 0xfd, 0x47, 0x18, 0xff, 0x8f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x21, 0xe1, 0xeb, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xe3, - 0x00, 0xc5, 0x51, 0x00, 0xd4, 0x37, 0x61, 0x99, 0x00, 0xea, 0x4d, 0xe9, - 0x45, 0x00, 0xb2, 0x70, 0xbf, 0x88, 0x04, 0xf0, 0x59, 0x48, 0xe9, 0x18, - 0xfd, 0x23, 0x77, 0xd4, 0x0e, 0xff, 0x9f, 0x02, 0x54, 0xff, 0x86, 0x00, - 0x69, 0xf0, 0x39, 0xd1, 0x61, 0xca, 0x60, 0xb6, 0x6f, 0xe3, 0x98, 0x00, - 0xea, 0x4a, 0x7f, 0xec, 0x15, 0x4e, 0xeb, 0x00, 0x32, 0xff, 0x36, 0x00, - 0x00, 0x00, 0x29, 0xff, 0x3e, 0x32, 0xff, 0x36, 0x00, 0x00, 0x00, 0x29, - 0xff, 0x3f, 0x68, 0xe6, 0x00, 0x83, 0xaf, 0xe7, 0x01, 0x80, 0xc9, 0x00, - 0x18, 0xf4, 0xff, 0x53, 0x00, 0x15, 0x3b, 0x00, 0xea, 0x6d, 0x00, 0x00, - 0x00, 0xc5, 0xa2, 0x41, 0xff, 0x39, 0x00, 0x40, 0x73, 0x73, 0x35, 0x00, - 0x00, 0x00, 0x3d, 0xed, 0x45, 0x00, 0x00, 0x00, 0x22, 0xe1, 0xeb, 0x2d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0xb3, 0x12, 0xf9, 0x04, 0x03, - 0xef, 0x2c, 0x6a, 0x94, 0x00, 0xea, 0x4d, 0x95, 0x9e, 0x14, 0xf6, 0x18, - 0xc1, 0x88, 0x00, 0xb2, 0x96, 0x8e, 0xa4, 0x00, 0xcb, 0x6a, 0xb5, 0x92, - 0x0e, 0xff, 0x59, 0x00, 0x27, 0xff, 0x3d, 0x00, 0x3a, 0xff, 0x04, 0x71, - 0xae, 0x40, 0xe0, 0x2e, 0xee, 0x1e, 0xd5, 0x00, 0xea, 0x4d, 0x08, 0xd9, - 0xa0, 0x4b, 0xeb, 0x00, 0x20, 0xfe, 0x45, 0x00, 0x00, 0x00, 0x37, 0xff, - 0x2c, 0x20, 0xfe, 0x45, 0x00, 0x00, 0x00, 0x37, 0xff, 0x3b, 0x21, 0xff, - 0x29, 0xcc, 0x4a, 0xe9, 0x30, 0xc3, 0x81, 0x14, 0xdf, 0xab, 0xbd, 0xcd, - 0x14, 0x9c, 0xb5, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0xdc, 0xa6, 0x20, - 0xfe, 0x42, 0x00, 0x63, 0xb2, 0xf4, 0x76, 0x00, 0x00, 0x00, 0x13, 0xd0, - 0xf6, 0x45, 0x00, 0x22, 0xe1, 0xeb, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3f, 0xe7, 0x03, 0xd7, 0x5e, 0x75, 0xf7, 0x8d, 0xc7, 0x4a, - 0x00, 0xea, 0x4d, 0x3c, 0xf0, 0x71, 0xb7, 0x00, 0xc1, 0x88, 0x00, 0x70, - 0xc9, 0xcb, 0x5d, 0x00, 0x83, 0xa2, 0xe9, 0x4f, 0x0e, 0xff, 0x43, 0x00, - 0x26, 0xff, 0x2d, 0x00, 0x39, 0xff, 0x00, 0x00, 0x00, 0x7c, 0x9a, 0x1f, - 0xf1, 0x00, 0xaf, 0x00, 0xea, 0x4d, 0x00, 0x44, 0xfe, 0x83, 0xeb, 0x00, - 0x00, 0xcd, 0x89, 0x00, 0x00, 0x00, 0x7b, 0xd9, 0x00, 0x00, 0xcd, 0x89, - 0x00, 0x00, 0x00, 0x7b, 0xf8, 0x08, 0x00, 0xd8, 0x75, 0xf8, 0x0d, 0xa7, - 0x79, 0xf7, 0x39, 0x5b, 0xfc, 0x0a, 0x09, 0xba, 0xd4, 0xf6, 0x39, 0x00, - 0xea, 0x6d, 0x00, 0x00, 0x31, 0xff, 0x75, 0x00, 0xcc, 0x8f, 0x00, 0x00, - 0x00, 0xdb, 0x76, 0x00, 0x00, 0x00, 0x00, 0x13, 0xd0, 0xf6, 0x63, 0xe1, - 0xeb, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xf3, - 0x44, 0x2c, 0x96, 0x87, 0x29, 0xa3, 0x64, 0x00, 0x00, 0xea, 0x4d, 0x01, - 0xe1, 0xf3, 0x5b, 0x00, 0xc1, 0x88, 0x00, 0x2e, 0xf7, 0xf5, 0x17, 0x00, - 0x3a, 0xec, 0xfc, 0x10, 0x0e, 0xff, 0x43, 0x00, 0x26, 0xff, 0x2d, 0x00, - 0x39, 0xff, 0x00, 0x00, 0x17, 0xe6, 0x19, 0x02, 0xee, 0x13, 0xd0, 0x00, - 0xea, 0x4d, 0x00, 0x00, 0xa5, 0xf6, 0xeb, 0x00, 0x00, 0x7d, 0xec, 0x7a, - 0x24, 0x73, 0xe7, 0x87, 0x00, 0x00, 0x7d, 0xec, 0x7a, 0x24, 0x73, 0xe7, - 0x9c, 0x00, 0x00, 0x91, 0xda, 0xbd, 0x00, 0x61, 0xd9, 0xed, 0x03, 0x2b, - 0xfe, 0x67, 0x1d, 0x70, 0xfc, 0xf0, 0x1a, 0x00, 0xea, 0x7f, 0x31, 0x81, - 0xdc, 0xdc, 0x0a, 0x00, 0x79, 0xef, 0x83, 0x23, 0x1c, 0xe1, 0x76, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x13, 0xd0, 0xff, 0xec, 0x2e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0xdc, 0x78, 0x20, 0x0d, - 0x3c, 0x3b, 0x00, 0x00, 0x00, 0xea, 0x4d, 0x00, 0x8a, 0xf3, 0x0b, 0x00, - 0xc1, 0x88, 0x00, 0x01, 0xea, 0xce, 0x00, 0x00, 0x03, 0xed, 0xc9, 0x00, - 0x0e, 0xff, 0x43, 0x00, 0x26, 0xff, 0x2d, 0x00, 0x39, 0xff, 0x00, 0x00, - 0x98, 0x7e, 0x00, 0x00, 0x78, 0xe7, 0xb0, 0x00, 0xea, 0x4d, 0x00, 0x00, - 0x18, 0xef, 0xeb, 0x00, 0x00, 0x06, 0x54, 0xb6, 0xfb, 0xbb, 0x57, 0x07, - 0x00, 0x00, 0x06, 0x54, 0xb6, 0xfc, 0xff, 0x8d, 0x01, 0x00, 0x00, 0x49, - 0xff, 0x74, 0x00, 0x1b, 0xfe, 0xa8, 0x00, 0x00, 0x7f, 0xde, 0xff, 0xe7, - 0x72, 0xb1, 0xdb, 0x00, 0xea, 0xff, 0xf8, 0xd6, 0x92, 0x13, 0x00, 0x00, - 0x06, 0x52, 0xb4, 0xfb, 0xff, 0xe5, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x13, 0xbc, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x44, 0xb7, 0xde, 0xdb, 0xad, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1b, 0xda, 0xbb, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, - 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0xe6, - 0xa0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x17, 0x00, 0x00, 0x00, - 0x2a, 0x1e, 0x00, 0x35, 0x13, 0x00, 0x00, 0x00, 0x2c, 0x1c, 0x00, 0x00, - 0x0c, 0x27, 0x00, 0x29, 0x09, 0x00, 0x00, 0x00, 0x3c, 0x24, 0x00, 0x00, - 0x00, 0x31, 0x35, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, - 0x1f, 0x00, 0x00, 0x31, 0x17, 0x00, 0x00, 0x13, 0x35, 0x00, 0x31, 0x35, - 0x2b, 0x02, 0x00, 0x00, 0x00, 0x31, 0x35, 0x2a, 0x02, 0x00, 0x00, 0x33, - 0x16, 0x00, 0x00, 0x00, 0x0f, 0x35, 0x27, 0x28, 0x00, 0x00, 0x00, 0x1f, - 0x2e, 0x0b, 0xbc, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x13, 0xbc, 0x2a, 0x0b, 0xbc, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0xc9, 0x8e, 0x00, 0xfc, - 0x5b, 0x00, 0x00, 0x00, 0xd2, 0x84, 0x00, 0x00, 0x59, 0xa9, 0x00, 0xea, - 0x0f, 0x00, 0x00, 0x34, 0xfe, 0xce, 0x00, 0x00, 0x00, 0xea, 0xf2, 0xed, - 0xfa, 0xce, 0x1a, 0x00, 0x09, 0xb5, 0xfd, 0xe7, 0xf5, 0xaf, 0x00, 0xea, - 0x6d, 0x00, 0x0c, 0xcf, 0xa7, 0x00, 0xea, 0xf2, 0xf3, 0xea, 0x94, 0x00, - 0x00, 0xea, 0xf4, 0xf6, 0xec, 0x9d, 0x00, 0xc0, 0x9e, 0x00, 0x00, 0x00, - 0x7a, 0xe5, 0x58, 0xf8, 0x26, 0x00, 0x0d, 0xe4, 0x7a, 0x0e, 0xff, 0x43, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xff, 0x39, 0x0e, - 0xff, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, - 0x6d, 0x00, 0x00, 0x00, 0xc9, 0x8e, 0x00, 0xfc, 0x5b, 0x00, 0x00, 0x00, - 0xd2, 0x84, 0x00, 0x00, 0x89, 0x79, 0x1c, 0xdd, 0x00, 0x00, 0x00, 0x93, - 0xad, 0xf9, 0x2e, 0x00, 0x00, 0xea, 0x6d, 0x00, 0x19, 0xe3, 0x8c, 0x00, - 0xab, 0xe1, 0x4f, 0x02, 0x07, 0x1f, 0x00, 0xea, 0x6d, 0x03, 0xb2, 0xc6, - 0x08, 0x00, 0xea, 0x6d, 0x03, 0x4d, 0xff, 0x33, 0x00, 0xea, 0x6d, 0x03, - 0x49, 0xff, 0x3a, 0x67, 0xee, 0x06, 0x00, 0x00, 0xd0, 0x8e, 0x00, 0xb3, - 0xbb, 0x00, 0x8e, 0xcf, 0x05, 0x0e, 0xff, 0x41, 0x12, 0x25, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x20, 0x18, 0xff, 0x39, 0x0e, 0xff, 0x41, 0x2e, 0x33, - 0x01, 0x00, 0x03, 0x35, 0x01, 0x2e, 0x34, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x39, 0x05, 0x00, 0x00, 0x03, 0x36, 0x02, 0x11, 0x25, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, - 0xc9, 0x8e, 0x00, 0xfc, 0x5b, 0x00, 0x00, 0x00, 0xd2, 0x84, 0x41, 0xd3, - 0xf0, 0xe3, 0xdd, 0xf4, 0xd3, 0x00, 0x06, 0xec, 0x52, 0xb4, 0x8d, 0x00, - 0x00, 0xea, 0x6d, 0x00, 0x06, 0xdd, 0x86, 0x0b, 0xfc, 0x81, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xea, 0x6d, 0x8d, 0xdd, 0x15, 0x00, 0x00, 0xea, 0x6d, - 0x00, 0x07, 0xf3, 0x64, 0x00, 0xea, 0x6d, 0x00, 0x0a, 0xf4, 0x69, 0x13, - 0xfa, 0x4a, 0x00, 0x27, 0xff, 0x34, 0x00, 0x1c, 0xf1, 0x86, 0xf7, 0x33, - 0x00, 0x0e, 0xff, 0xaa, 0xd3, 0xf8, 0xab, 0x01, 0x00, 0x87, 0xf6, 0xda, - 0xa5, 0xff, 0x39, 0x0e, 0xff, 0xc0, 0xe5, 0xf2, 0xd5, 0x03, 0x0e, 0xff, - 0xb4, 0xe5, 0xf2, 0xd6, 0x04, 0x00, 0x00, 0x00, 0x00, 0x6d, 0xe7, 0xdd, - 0xe7, 0x6d, 0x00, 0x0e, 0xff, 0x98, 0xd2, 0xf8, 0xab, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xea, 0xe9, 0xd9, 0xd9, 0xd9, 0xf7, 0x8e, 0x00, 0xfc, - 0x5b, 0x00, 0x00, 0x00, 0xd2, 0x84, 0x09, 0x1d, 0xec, 0x2e, 0x93, 0x87, - 0x1d, 0x00, 0x52, 0xf1, 0x09, 0x5d, 0xe8, 0x04, 0x00, 0xea, 0xe4, 0xd3, - 0xf6, 0xb1, 0x0d, 0x3c, 0xff, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, - 0xc9, 0xff, 0x60, 0x00, 0x00, 0x00, 0xea, 0x8a, 0x49, 0x9e, 0xf1, 0x0d, - 0x00, 0xea, 0xa6, 0x71, 0xbb, 0xe1, 0x1a, 0x00, 0xb4, 0xa0, 0x00, 0x7d, - 0xda, 0x00, 0x00, 0x00, 0x74, 0xff, 0x93, 0x00, 0x00, 0x0e, 0xff, 0x9c, - 0x02, 0x2a, 0xff, 0x32, 0x0e, 0xfa, 0x5a, 0x00, 0x6f, 0xff, 0x39, 0x0e, - 0xff, 0xa6, 0x04, 0x1e, 0xff, 0x42, 0x0e, 0xff, 0xa5, 0x04, 0x1e, 0xff, - 0x42, 0x00, 0x00, 0x00, 0x07, 0xf1, 0x59, 0x00, 0x55, 0xf2, 0x09, 0x0e, - 0xff, 0x99, 0x01, 0x2d, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, - 0x98, 0x4c, 0x4c, 0x4c, 0xd9, 0x8e, 0x00, 0xfc, 0x5b, 0x00, 0x00, 0x00, - 0xd2, 0x84, 0x37, 0x58, 0xef, 0x4a, 0xc6, 0x83, 0x38, 0x00, 0xb1, 0xd5, - 0x6f, 0x7d, 0xff, 0x4c, 0x00, 0xea, 0x94, 0x47, 0x70, 0xe7, 0x83, 0x22, - 0xff, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0xd2, 0xaf, 0xe2, 0x10, - 0x00, 0x00, 0xea, 0xf5, 0xda, 0x94, 0x3e, 0x00, 0x00, 0xea, 0xd6, 0xc4, - 0xfd, 0x27, 0x00, 0x00, 0x5b, 0xef, 0x06, 0xd3, 0x81, 0x00, 0x00, 0x01, - 0xbc, 0xeb, 0xd2, 0x06, 0x00, 0x0e, 0xff, 0x56, 0x00, 0x00, 0xdd, 0x77, - 0x50, 0xfb, 0x0c, 0x00, 0x23, 0xff, 0x39, 0x0e, 0xff, 0x5c, 0x00, 0x00, - 0xeb, 0x68, 0x0e, 0xff, 0x5c, 0x00, 0x00, 0xeb, 0x68, 0x00, 0x00, 0x00, - 0x4c, 0xfb, 0x0b, 0x00, 0x08, 0xf8, 0x51, 0x0e, 0xff, 0x52, 0x00, 0x00, - 0xde, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, - 0xc9, 0x8e, 0x00, 0xd3, 0x85, 0x00, 0x00, 0x09, 0xf4, 0x6b, 0x7b, 0xc7, - 0xdf, 0xa7, 0xfd, 0xa9, 0x7f, 0x16, 0xfa, 0xc4, 0xb8, 0xb8, 0xe2, 0xab, - 0x00, 0xea, 0x6d, 0x00, 0x00, 0x8e, 0xdf, 0x00, 0xd2, 0x89, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xea, 0x6d, 0x0f, 0xe0, 0xa1, 0x00, 0x00, 0xea, 0x6d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x01, 0xc6, 0xa5, 0x00, 0x00, - 0x0c, 0xf5, 0x69, 0xff, 0x28, 0x00, 0x00, 0x60, 0xec, 0x21, 0xe4, 0x80, - 0x00, 0x0e, 0xff, 0x65, 0x00, 0x01, 0xea, 0x67, 0x43, 0xfe, 0x12, 0x00, - 0x25, 0xff, 0x39, 0x0e, 0xff, 0x43, 0x00, 0x00, 0xea, 0x68, 0x0e, 0xff, - 0x43, 0x00, 0x00, 0xea, 0x68, 0x00, 0x00, 0x00, 0x4c, 0xfe, 0x16, 0x00, - 0x11, 0xfd, 0x40, 0x0e, 0xff, 0x65, 0x00, 0x01, 0xeb, 0x67, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0xc9, 0x8e, 0x00, 0x72, - 0xdf, 0x4b, 0x23, 0x8c, 0xfa, 0x28, 0x00, 0x7c, 0x81, 0x1a, 0xe5, 0x00, - 0x00, 0x70, 0xeb, 0x05, 0x00, 0x00, 0x5c, 0xf8, 0x00, 0xea, 0x7f, 0x22, - 0x4a, 0xdd, 0x95, 0x00, 0x84, 0xed, 0x7c, 0x1d, 0x24, 0x32, 0x00, 0xea, - 0x6d, 0x00, 0x40, 0xfd, 0x52, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xea, 0x6d, 0x00, 0x31, 0xfc, 0x49, 0x00, 0x00, 0xa8, 0xe3, 0xcd, - 0x00, 0x00, 0x17, 0xed, 0x62, 0x00, 0x54, 0xf9, 0x2d, 0x0e, 0xff, 0xbc, - 0x1d, 0x5f, 0xff, 0x21, 0x07, 0xf5, 0x7e, 0x11, 0x8d, 0xff, 0x39, 0x0e, - 0xff, 0x43, 0x00, 0x00, 0xea, 0x68, 0x0e, 0xff, 0x43, 0x00, 0x00, 0xea, - 0x68, 0x00, 0x00, 0x00, 0x14, 0xf2, 0x88, 0x15, 0x82, 0xe8, 0x03, 0x0e, - 0xff, 0xbc, 0x1e, 0x61, 0xff, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, - 0x6d, 0x00, 0x00, 0x00, 0xc9, 0x8e, 0x00, 0x10, 0x85, 0xdc, 0xfe, 0xd9, - 0x4c, 0x00, 0x00, 0xaa, 0x50, 0x4b, 0xb4, 0x00, 0x00, 0xcf, 0x97, 0x00, - 0x00, 0x00, 0x0c, 0xf4, 0x00, 0xea, 0xff, 0xff, 0xdd, 0x93, 0x1c, 0x00, - 0x08, 0x5c, 0xc0, 0xfe, 0xed, 0x7b, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x8d, - 0xea, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, - 0x00, 0x95, 0xe0, 0x00, 0x00, 0x4f, 0xff, 0x74, 0x00, 0x00, 0xa8, 0xc3, - 0x01, 0x00, 0x00, 0xb7, 0xca, 0x0e, 0xfd, 0x6f, 0xd4, 0xe5, 0x72, 0x00, - 0x00, 0x5c, 0xd9, 0xdb, 0x63, 0xef, 0x39, 0x0e, 0xff, 0x43, 0x00, 0x00, - 0xea, 0x68, 0x0e, 0xff, 0x43, 0x00, 0x00, 0xea, 0x68, 0x00, 0x00, 0x00, - 0x00, 0x43, 0xdb, 0xfc, 0xb7, 0x46, 0x00, 0x0e, 0xff, 0x8c, 0xd4, 0xe4, - 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, - 0x00, 0x00, 0x00, 0x0e, 0xff, 0x43, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, - 0xff, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x33, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x79, - 0x00, 0x00, 0x00, 0x00, 0x58, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0a, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, - 0x14, 0x00, 0x00, 0x04, 0x32, 0x3b, 0x03, 0x00, 0x00, 0x00, 0x21, 0x38, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3b, 0x0f, 0x00, 0x2e, 0x35, 0x35, - 0x35, 0x16, 0x00, 0x00, 0x03, 0x26, 0x49, 0x1f, 0x1e, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x00, 0x00, 0x18, 0x3a, 0x05, 0x00, 0x00, 0x00, 0x14, 0x37, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, - 0x00, 0x31, 0x35, 0x35, 0x35, 0x27, 0x00, 0x31, 0x35, 0x35, 0x35, 0x26, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xa6, 0xea, 0x9e, 0x53, 0x0f, 0x03, - 0x5f, 0xa3, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, - 0xe9, 0xea, 0xb4, 0x23, 0x00, 0x07, 0x98, 0xff, 0x61, 0x00, 0x27, 0xd4, - 0xee, 0xe8, 0xe8, 0x2f, 0x32, 0xcf, 0xdd, 0xe5, 0xef, 0x33, 0x00, 0x00, - 0x00, 0x89, 0xff, 0x41, 0x00, 0xea, 0xf9, 0xf6, 0xf6, 0x64, 0x00, 0x25, - 0xcf, 0xfe, 0xd1, 0x6c, 0x90, 0xf6, 0xf6, 0xf6, 0xf9, 0xff, 0x00, 0xa0, - 0xea, 0xca, 0xee, 0x3e, 0x00, 0x9e, 0xf3, 0xe2, 0xe3, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0xea, 0xf4, 0xec, - 0xec, 0xac, 0x00, 0xea, 0xf4, 0xec, 0xec, 0xa9, 0x00, 0x00, 0x00, 0x00, - 0x17, 0x3a, 0x05, 0x30, 0x0c, 0x06, 0x36, 0x0c, 0x00, 0x00, 0x34, 0x13, - 0x16, 0xf6, 0x91, 0xc3, 0x79, 0x5b, 0x80, 0xed, 0xc9, 0xd9, 0xdb, 0xcb, - 0x00, 0x00, 0x31, 0xa9, 0x00, 0x00, 0x06, 0xf7, 0x57, 0x0c, 0xbd, 0x88, - 0x05, 0xc6, 0xb6, 0xed, 0x61, 0x00, 0x08, 0x64, 0x05, 0x02, 0xbf, 0x9d, - 0x04, 0x3a, 0x00, 0x01, 0xbe, 0xa2, 0x00, 0x00, 0x3d, 0xd1, 0xfc, 0x41, - 0x02, 0xfc, 0x41, 0x00, 0x00, 0x00, 0x00, 0xc9, 0xa9, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x90, 0xbf, 0x23, 0xfe, 0x27, 0x00, 0x9b, 0xaf, - 0x2b, 0xfc, 0x21, 0x00, 0xa9, 0xb1, 0x00, 0x00, 0x00, 0x01, 0x50, 0xce, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x98, 0x1e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xc1, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0x00, 0xea, - 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xf6, 0xdf, 0xbf, 0xf9, - 0x39, 0x1d, 0xff, 0x38, 0x00, 0x00, 0xf6, 0x5c, 0x30, 0xff, 0x55, 0xa7, - 0x00, 0x00, 0x06, 0x21, 0xdd, 0xeb, 0x45, 0x0c, 0x00, 0x00, 0x3a, 0xc8, - 0x00, 0x00, 0x35, 0xfd, 0x09, 0x00, 0x77, 0xc1, 0x00, 0x44, 0x03, 0xee, - 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xa9, 0x00, 0x00, 0x00, 0x09, - 0xdb, 0x79, 0x00, 0x0d, 0xdc, 0x43, 0xff, 0x41, 0x13, 0xff, 0x38, 0x0f, - 0x00, 0x00, 0x36, 0xff, 0x34, 0x26, 0x05, 0x00, 0x00, 0x00, 0x00, 0x12, - 0xf3, 0x4e, 0x0a, 0xf1, 0x6b, 0x16, 0xce, 0x80, 0x6e, 0xda, 0x00, 0x00, - 0x58, 0xe9, 0x00, 0x01, 0x50, 0xce, 0xbc, 0x44, 0x49, 0xab, 0xab, 0xab, - 0xab, 0xa8, 0x0f, 0x78, 0xe1, 0x98, 0x1f, 0x00, 0x00, 0x01, 0xdb, 0x62, - 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0x00, 0xea, 0x6a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0e, 0xfa, 0x58, 0x00, 0x6f, 0xff, 0x39, 0x1d, 0xff, 0x38, - 0x00, 0x00, 0xf6, 0x5c, 0x00, 0x90, 0xfc, 0xdd, 0x46, 0x00, 0x00, 0x8b, - 0xbb, 0x75, 0xce, 0x06, 0x41, 0x8d, 0xa7, 0xe7, 0x8d, 0x8d, 0x6b, 0xe3, - 0x00, 0x00, 0x52, 0xf5, 0x00, 0x00, 0x00, 0xf0, 0x61, 0x00, 0x00, 0x00, - 0x00, 0x31, 0xf8, 0x3f, 0x00, 0x33, 0xcb, 0xf8, 0x85, 0x05, 0x00, 0x9c, - 0x8e, 0x08, 0xff, 0x41, 0x1f, 0xfd, 0xfe, 0xfa, 0xb8, 0x2d, 0x5b, 0xf2, - 0xc9, 0xe6, 0xe7, 0x5a, 0x00, 0x00, 0x00, 0x7c, 0xd9, 0x02, 0x00, 0x37, - 0xfb, 0xf8, 0xa4, 0x02, 0x2e, 0xfd, 0x49, 0x26, 0xbd, 0xfe, 0x35, 0xce, - 0xac, 0x34, 0x00, 0x00, 0x24, 0x55, 0x55, 0x55, 0x55, 0x53, 0x00, 0x00, - 0x08, 0x68, 0xd8, 0x98, 0x00, 0x3b, 0xf4, 0x0d, 0x00, 0xea, 0xe8, 0xd6, - 0xd6, 0x6f, 0x00, 0xea, 0xb6, 0x82, 0x82, 0x42, 0x00, 0x00, 0x4f, 0xfb, - 0x0c, 0x00, 0x23, 0xff, 0x39, 0x1d, 0xff, 0x38, 0x00, 0x00, 0xf6, 0x5c, - 0x00, 0x00, 0x3a, 0xe4, 0xf4, 0x89, 0x00, 0x24, 0x30, 0x0c, 0x48, 0x00, - 0x34, 0x72, 0x92, 0xe1, 0x72, 0x72, 0x5e, 0xea, 0x00, 0x00, 0x59, 0xee, - 0x00, 0x00, 0x00, 0xf0, 0x61, 0x00, 0x00, 0x00, 0x22, 0xe6, 0x76, 0x00, - 0x00, 0x15, 0x57, 0x82, 0xe7, 0x79, 0x4d, 0xd5, 0x09, 0x08, 0xff, 0x41, - 0x00, 0x13, 0x03, 0x2c, 0xcd, 0xa5, 0x6f, 0xfc, 0x30, 0x01, 0x81, 0xd3, - 0x00, 0x00, 0x09, 0xe9, 0x6a, 0x00, 0x0f, 0xc5, 0xb2, 0x78, 0xed, 0x63, - 0x00, 0x7f, 0xe4, 0xe4, 0xa5, 0xeb, 0x34, 0xc4, 0xcd, 0x64, 0x0a, 0x00, - 0x2e, 0x6c, 0x6c, 0x6c, 0x6c, 0x6a, 0x00, 0x00, 0x29, 0x92, 0xe4, 0x93, - 0x00, 0x9a, 0xa3, 0x00, 0x00, 0xea, 0x96, 0x48, 0x48, 0x25, 0x00, 0xea, - 0xc8, 0xa1, 0xa1, 0x52, 0x00, 0x00, 0x43, 0xfe, 0x12, 0x00, 0x23, 0xff, - 0x39, 0x1c, 0xff, 0x3d, 0x00, 0x1c, 0xff, 0x5c, 0x06, 0x00, 0x17, 0xa7, - 0x8a, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc8, - 0x00, 0x00, 0x25, 0xff, 0x0f, 0x00, 0x7f, 0xb8, 0x00, 0x00, 0x00, 0xf0, - 0x61, 0x00, 0x00, 0x20, 0xe0, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x84, 0xe4, 0xc4, 0xf0, 0xe2, 0xe3, 0xff, 0xe9, 0x00, 0x00, 0x00, 0x00, - 0x7b, 0xdd, 0x4b, 0xf3, 0x07, 0x00, 0x47, 0xf8, 0x00, 0x00, 0x68, 0xed, - 0x0b, 0x00, 0x5f, 0xe3, 0x02, 0x00, 0x5d, 0xeb, 0x00, 0x00, 0x01, 0x00, - 0xaa, 0xbd, 0x00, 0x00, 0x35, 0xa5, 0xea, 0x90, 0x3f, 0x92, 0x92, 0x92, - 0x92, 0x90, 0x34, 0xbe, 0xe0, 0x74, 0x10, 0x00, 0x09, 0xf0, 0x44, 0x00, - 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0x00, 0xea, 0x6a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xf5, 0x7b, 0x10, 0x8b, 0xff, 0x39, 0x02, 0xe4, 0x8c, - 0x10, 0x86, 0xff, 0x5c, 0x60, 0xd2, 0xa9, 0xea, 0xfd, 0x77, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x91, 0x00, 0x00, 0x01, 0xea, - 0x87, 0x2f, 0xd5, 0x81, 0x00, 0x00, 0x00, 0xf0, 0x61, 0x00, 0x1f, 0xdf, - 0x9f, 0x29, 0x29, 0x29, 0x36, 0x28, 0x04, 0x29, 0xcd, 0x9c, 0x2a, 0x35, - 0x35, 0x3b, 0xff, 0x69, 0x28, 0x37, 0x09, 0x32, 0xd3, 0x81, 0x16, 0xef, - 0x7f, 0x18, 0xa7, 0xaf, 0x00, 0x03, 0xdb, 0x87, 0x00, 0x00, 0x3e, 0xf5, - 0x26, 0x05, 0x88, 0xc7, 0x00, 0x06, 0x1b, 0x75, 0xf4, 0x48, 0x00, 0x00, - 0x00, 0x00, 0x1b, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x56, - 0x04, 0x00, 0x00, 0x00, 0x5a, 0xe2, 0x02, 0x00, 0x00, 0xea, 0x81, 0x24, - 0x24, 0x1a, 0x00, 0xea, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, - 0xda, 0xda, 0x71, 0xff, 0x39, 0x00, 0x68, 0xe4, 0xfa, 0xa6, 0xd0, 0x5c, - 0x09, 0x38, 0x74, 0xc9, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xb5, 0xef, 0x82, 0x10, - 0x00, 0x00, 0x00, 0xf0, 0x61, 0x00, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x5f, 0xdc, 0xfc, 0xe9, 0xa6, 0x22, 0x00, 0x00, 0x00, 0x08, 0xff, 0x41, - 0x3e, 0xd7, 0xfd, 0xe4, 0x95, 0x17, 0x00, 0x47, 0xdc, 0xfb, 0xb2, 0x30, - 0x00, 0x55, 0xfa, 0x1b, 0x00, 0x00, 0x00, 0x90, 0xe3, 0xf2, 0xbf, 0x3c, - 0x00, 0xec, 0xfc, 0xde, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb9, 0x85, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xff, 0xba, 0x00, 0xea, - 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x1a, 0xff, - 0x39, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x0d, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xff, 0x39, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x14, 0xc2, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x17, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x43, 0x14, 0x00, 0x2d, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x32, 0x1b, 0x00, 0x00, 0x00, 0x26, 0x1c, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x00, 0x00, 0x1d, 0x17, 0x00, 0x00, 0x00, 0x00, 0x8c, 0xa9, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xbc, 0x2f, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x7a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x35, 0x35, - 0x35, 0x2b, 0x0d, 0x35, 0x04, 0x35, 0x0e, 0x00, 0x12, 0x41, 0x0e, 0x00, - 0x2f, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0x00, 0xa1, - 0xf9, 0xe4, 0xfe, 0x7c, 0xc9, 0xf0, 0xf6, 0xfe, 0xf0, 0xf0, 0x9e, 0xd1, - 0x02, 0x00, 0x14, 0xf1, 0x7c, 0xf0, 0xf0, 0xf0, 0xf8, 0xff, 0x00, 0x00, - 0xbd, 0xae, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xb2, 0x74, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xaa, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x60, 0x60, 0x60, 0xaa, 0x33, 0xfc, - 0x02, 0xf9, 0x36, 0x9f, 0xeb, 0xd6, 0xf7, 0x5d, 0xa5, 0x99, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0x2b, 0xfe, 0x2d, 0x00, 0x1a, 0x15, - 0x00, 0x00, 0x6c, 0xea, 0x00, 0x00, 0x1d, 0xf7, 0x58, 0x00, 0x8a, 0xda, - 0x00, 0x00, 0x00, 0x08, 0xd5, 0x9c, 0x00, 0x35, 0xc9, 0xd2, 0x34, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x03, 0x35, 0x42, 0x09, 0x00, - 0x00, 0x00, 0x07, 0x38, 0x03, 0x00, 0x00, 0x00, 0x28, 0x48, 0x36, 0x36, - 0x0e, 0xff, 0x40, 0x00, 0x0e, 0x36, 0x34, 0x17, 0x00, 0x00, 0x0f, 0x36, - 0x25, 0x2c, 0x00, 0x00, 0x1a, 0x35, 0x33, 0x1a, 0x00, 0x00, 0x10, 0x36, - 0x00, 0x00, 0x58, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x95, 0x00, 0x00, 0x00, 0x95, 0x1f, 0xea, 0x00, 0xe6, 0x22, 0x1c, - 0x04, 0x00, 0x7a, 0xcf, 0x46, 0xef, 0x09, 0x00, 0x00, 0x00, 0x04, 0x3e, - 0x21, 0x00, 0x04, 0x36, 0x34, 0x06, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, - 0x00, 0x00, 0x24, 0xff, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xea, - 0x00, 0x00, 0x00, 0x8b, 0xd9, 0x1d, 0xf5, 0x54, 0x00, 0x00, 0x00, 0x8b, - 0xe0, 0x0e, 0x00, 0xac, 0x58, 0x54, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xa7, 0xd5, 0xc6, 0xf3, 0x42, 0x00, 0x6d, 0xe1, 0xc7, - 0xe1, 0x49, 0x02, 0xca, 0xbd, 0xb6, 0xff, 0xb2, 0x0e, 0xff, 0x40, 0x0c, - 0xc7, 0xae, 0xba, 0xa4, 0x00, 0x00, 0x7f, 0xdf, 0x46, 0xfb, 0x38, 0x08, - 0xd8, 0x97, 0xb6, 0xb1, 0x00, 0x00, 0x81, 0xe2, 0x00, 0x00, 0x58, 0xaa, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, - 0x00, 0x95, 0x0a, 0xa3, 0x00, 0xa1, 0x0d, 0x00, 0x00, 0x02, 0xa9, 0xb9, - 0x03, 0xe3, 0x58, 0x00, 0x00, 0x70, 0xe7, 0xdd, 0xf7, 0x11, 0xe9, 0xe3, - 0xd8, 0xcf, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x84, - 0xfb, 0xb6, 0x33, 0x00, 0x00, 0x00, 0x6c, 0xea, 0x00, 0x00, 0x00, 0x12, - 0xef, 0xd9, 0xc8, 0x01, 0x00, 0x00, 0x3b, 0xfb, 0x42, 0x00, 0x26, 0xdf, - 0x04, 0x02, 0xd1, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, - 0x00, 0x00, 0xa7, 0xa5, 0x07, 0xf1, 0x3f, 0x00, 0x77, 0xba, 0x45, 0xf4, - 0x06, 0x01, 0xe9, 0x66, 0x0e, 0xff, 0x45, 0xbc, 0xbb, 0x07, 0x59, 0xf3, - 0x0a, 0x00, 0xd8, 0x80, 0x00, 0x95, 0xd5, 0x8f, 0xdb, 0x0b, 0x50, 0xf9, - 0x13, 0x00, 0xd8, 0x85, 0x00, 0x00, 0x58, 0xaa, 0x00, 0x00, 0x2c, 0xb1, - 0xcf, 0x88, 0x4c, 0x89, 0x00, 0x95, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x9a, 0xd6, 0x1d, 0x00, 0x86, 0xb7, 0x00, - 0x07, 0xf1, 0x62, 0x00, 0x06, 0x58, 0xf8, 0x20, 0x00, 0x08, 0x00, 0x00, - 0x00, 0xea, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0xbe, 0xfe, 0x5a, - 0x00, 0x00, 0x6c, 0xea, 0x00, 0x00, 0x00, 0x00, 0x79, 0xff, 0x40, 0x00, - 0x00, 0x0a, 0xda, 0x92, 0x00, 0x00, 0x9a, 0x75, 0x00, 0x00, 0x53, 0xc0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x8b, 0xbf, 0xe6, 0xc5, - 0x49, 0xfe, 0xc3, 0xc2, 0xd2, 0xfc, 0x36, 0xfe, 0x39, 0x2b, 0xf8, 0x29, - 0x0e, 0xff, 0xc7, 0xf9, 0x18, 0x00, 0x09, 0xef, 0x57, 0x32, 0xfd, 0x20, - 0x00, 0x0b, 0xe0, 0xff, 0x3d, 0x00, 0x04, 0xe5, 0x69, 0x31, 0xfe, 0x25, - 0x00, 0x00, 0x58, 0xaa, 0x00, 0x00, 0x49, 0x3a, 0x47, 0x91, 0xbd, 0x67, - 0x00, 0x95, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x43, 0xe6, 0x15, 0x00, 0x00, 0x28, 0xfb, 0x1a, 0x4a, 0xfb, 0x0d, 0x00, - 0x00, 0x11, 0xc2, 0xf4, 0x90, 0x19, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xbe, 0x00, 0x00, 0x6c, 0xea, - 0x00, 0x00, 0x00, 0x00, 0x47, 0xff, 0x12, 0x00, 0x00, 0x91, 0xda, 0x0a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x27, 0xfc, 0x6a, 0x1e, 0x9a, 0xc5, 0x3b, 0xfd, 0x42, 0x31, - 0x31, 0x31, 0x00, 0x9f, 0xe5, 0xb3, 0x5d, 0x00, 0x0e, 0xff, 0xac, 0xd2, - 0xa4, 0x00, 0x00, 0x97, 0xac, 0x88, 0xbc, 0x00, 0x00, 0x2b, 0xf7, 0xee, - 0x75, 0x00, 0x00, 0x82, 0xbf, 0x86, 0xc3, 0x00, 0x00, 0x00, 0x58, 0xaa, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, - 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x5b, 0x00, 0x00, - 0x00, 0x00, 0xc7, 0x76, 0x40, 0xfe, 0x15, 0x00, 0x00, 0x00, 0x01, 0x4f, - 0xd1, 0xdf, 0x00, 0x00, 0x00, 0xea, 0x83, 0x27, 0x27, 0x23, 0x39, 0x44, - 0x14, 0x2b, 0xd1, 0x7b, 0x00, 0x00, 0x6c, 0xea, 0x00, 0x00, 0x00, 0x00, - 0x47, 0xff, 0x12, 0x00, 0x40, 0xfd, 0x60, 0x27, 0x27, 0x27, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xf6, - 0x0f, 0x1f, 0xe4, 0xc5, 0x01, 0xe0, 0x89, 0x0e, 0x07, 0x31, 0x08, 0xfa, - 0x4e, 0x24, 0x0a, 0x00, 0x0e, 0xff, 0x40, 0x2b, 0xf5, 0x65, 0x00, 0x36, - 0xef, 0xd1, 0x5b, 0x00, 0x05, 0xcd, 0x9e, 0x4b, 0xf8, 0x2d, 0x00, 0x1e, - 0xf6, 0xda, 0x63, 0x00, 0x00, 0x00, 0x58, 0xaa, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x68, 0xd4, - 0x04, 0xec, 0x8a, 0x14, 0x3f, 0x27, 0x2c, 0x01, 0x54, 0xee, 0x00, 0x00, - 0x00, 0xea, 0xff, 0xff, 0xff, 0xe6, 0x51, 0xdb, 0xfd, 0xea, 0xa3, 0x11, - 0x00, 0x00, 0x6c, 0xea, 0x00, 0x00, 0x00, 0x00, 0x47, 0xff, 0x12, 0x00, - 0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc8, 0xf7, 0xdf, 0x83, 0xc5, - 0x00, 0x3f, 0xae, 0xf4, 0xfc, 0x9f, 0x0a, 0xd2, 0xfc, 0xfb, 0xf7, 0x90, - 0x0e, 0xff, 0x40, 0x00, 0x65, 0xf6, 0x00, 0x00, 0xd4, 0xf0, 0x09, 0x00, - 0x83, 0xe5, 0x10, 0x00, 0xa2, 0xd0, 0x00, 0x00, 0xb4, 0xf4, 0x0d, 0x00, - 0x00, 0x00, 0x58, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xc6, 0x95, 0x95, 0x95, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x82, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x11, 0xf7, 0x00, 0x4f, 0xbf, 0xfe, - 0xf1, 0x57, 0xe9, 0xf3, 0xde, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, - 0x0a, 0x00, 0xaa, 0x94, 0x08, 0x02, 0x4e, 0xf8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0xbf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x58, 0xaa, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x0f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xae, - 0x37, 0x49, 0xae, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xc3, - 0xf1, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x58, 0xaa, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x79, 0xb0, 0x96, 0x5c, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x9f, 0x3a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3d, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xff, 0x5a, 0xff, 0x8f, 0x00, - 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x8f, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3c, 0xaa, 0x3c, 0x8f, 0xff, 0x8f, 0x00, 0x00, 0x8f, 0xff, - 0x8f, 0x00, 0x8f, 0xff, 0x8f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x8f, 0xff, 0x8f, 0x00, 0x00, 0x8f, 0xff, 0x8f, 0xff, 0x8f, - 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, - 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x6e, 0xaa, 0x00, 0x3c, 0xaa, 0x3c, 0x00, 0x00, 0x8f, - 0xff, 0x8f, 0x00, 0x00, 0x8f, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x86, 0xbd, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x17, - 0x00, 0x00, 0x00, 0x0a, 0x35, 0x13, 0x00, 0x00, 0x30, 0x20, 0x1d, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x31, 0x17, 0x00, 0x33, 0x15, 0x07, 0x35, 0x35, - 0x26, 0x35, 0x31, 0x03, 0x7f, 0x18, 0x03, 0x7f, 0x18, 0x0b, 0xbc, 0x31, - 0x00, 0x00, 0x0d, 0x35, 0x00, 0x00, 0x00, 0x5e, 0xff, 0x70, 0x00, 0x00, - 0x00, 0x00, 0x70, 0xff, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, - 0xff, 0x00, 0x5a, 0xff, 0x5a, 0x00, 0x8f, 0xff, 0x8f, 0x00, 0x00, 0x00, - 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x81, 0xd8, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x4f, 0x3b, 0x00, 0x00, 0x00, 0xb5, 0xf5, 0xb0, 0xe7, 0x28, 0x00, 0x26, - 0xff, 0x55, 0x00, 0x3e, 0xe7, 0x4c, 0xdc, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xea, 0x6d, 0x00, 0xf4, 0x64, 0x22, 0xff, 0xcb, 0x8e, 0xd6, 0xeb, 0x0b, - 0xc5, 0x2f, 0x0b, 0xc5, 0x2f, 0x0e, 0xff, 0x43, 0x00, 0x00, 0x33, 0xfc, - 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0x70, 0x00, 0x00, 0x70, 0xff, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x8f, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x17, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xcd, 0xa8, 0x36, 0x03, 0x35, 0x00, 0x24, 0x0b, 0xcf, 0x85, 0x36, 0x00, - 0x32, 0xfd, 0x1b, 0x01, 0xbb, 0x85, 0x00, 0x19, 0xff, 0x48, 0x01, 0xca, - 0x70, 0x01, 0xca, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x2c, 0x09, 0x00, 0x2c, 0x08, 0x00, 0xea, 0x6d, 0x00, 0xf4, - 0x64, 0x22, 0xff, 0x12, 0x00, 0x46, 0xeb, 0x03, 0x36, 0x0e, 0x03, 0x36, - 0x0e, 0x0e, 0xff, 0x43, 0x00, 0x00, 0x1f, 0xea, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x70, 0xff, 0x70, 0x70, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x55, 0x37, 0x00, 0x37, 0x55, 0x00, 0x1e, 0x55, 0x1e, 0xff, 0x8f, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xcc, - 0xcc, 0xe8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x98, 0xf3, 0xe6, 0xc9, 0x0e, - 0xff, 0x85, 0xfc, 0x93, 0xfb, 0xde, 0xc9, 0x00, 0x41, 0xf6, 0x00, 0x00, - 0x9e, 0x99, 0x00, 0x0c, 0xff, 0x3c, 0x2c, 0xff, 0x0f, 0x00, 0x69, 0xd0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x54, - 0x20, 0xf8, 0x51, 0x00, 0xea, 0x6d, 0x00, 0xf4, 0x64, 0x22, 0xff, 0x12, - 0x00, 0x46, 0xeb, 0x0e, 0xff, 0x43, 0x0e, 0xff, 0x43, 0x0e, 0xff, 0x43, - 0x00, 0x00, 0x0a, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, - 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xa5, 0x00, 0xa5, - 0xff, 0x00, 0x5a, 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xe6, 0x6f, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc7, 0x8b, 0x00, 0x0e, 0xff, 0xc7, 0x1f, 0x00, - 0xee, 0x64, 0x00, 0x00, 0x64, 0xe7, 0x00, 0x00, 0x8f, 0xba, 0x00, 0x01, - 0xfd, 0x2f, 0x54, 0xe5, 0x00, 0x00, 0x41, 0xf6, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x45, 0x09, 0x03, 0x46, 0x09, 0x00, - 0xea, 0x6d, 0x00, 0xf4, 0x64, 0x22, 0xff, 0x12, 0x00, 0x46, 0xeb, 0x0e, - 0xff, 0x43, 0x0e, 0xff, 0x43, 0x0e, 0xff, 0x43, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0x70, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x55, 0x37, 0x00, 0x37, 0x55, 0x00, 0x1e, 0x55, - 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xb1, 0xb6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc7, 0x8b, 0x00, 0x0e, 0xff, 0x5d, 0x00, 0x00, 0xee, 0x64, 0x00, 0x9b, - 0xe8, 0x53, 0x00, 0x00, 0x23, 0xc4, 0xd7, 0x00, 0xf1, 0x22, 0x7b, 0xbe, - 0x00, 0x00, 0x1a, 0xff, 0x00, 0x00, 0x00, 0x62, 0xa4, 0xa4, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, 0xf4, - 0x64, 0x22, 0xff, 0x12, 0x00, 0x46, 0xeb, 0x0e, 0xff, 0x43, 0x0e, 0xff, - 0x43, 0x0e, 0xff, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x70, 0xff, 0x70, 0x70, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, - 0xe8, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x8b, 0x00, 0x0e, - 0xff, 0x43, 0x00, 0x00, 0xee, 0x64, 0x00, 0x52, 0xcc, 0xa7, 0x00, 0x00, - 0x4e, 0xea, 0x76, 0x00, 0x75, 0x0c, 0x6f, 0xca, 0x00, 0x00, 0x26, 0xff, - 0x00, 0x00, 0x00, 0x49, 0x7a, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xea, 0x6d, 0x00, 0xf4, 0x64, 0x22, 0xff, 0x12, - 0x00, 0x46, 0xeb, 0x0e, 0xff, 0x43, 0x0e, 0xff, 0x43, 0x0e, 0xff, 0x43, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0x70, 0x00, - 0x00, 0x70, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xf5, 0x4c, 0x03, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc7, 0x8b, 0x00, 0x0e, 0xff, 0x43, 0x00, 0x00, - 0xd0, 0x8f, 0x05, 0x00, 0x4a, 0xf5, 0x00, 0x00, 0x99, 0xa2, 0x00, 0x08, - 0x75, 0x17, 0x47, 0xf2, 0x01, 0x00, 0x4e, 0xeb, 0x09, 0x56, 0x17, 0x00, - 0x00, 0x00, 0x08, 0x75, 0x17, 0x08, 0x75, 0x17, 0x09, 0x56, 0x17, 0x00, - 0xea, 0x6d, 0x00, 0xf4, 0x64, 0x22, 0xff, 0x12, 0x00, 0x46, 0xeb, 0x0e, - 0xff, 0x43, 0x0e, 0xff, 0x43, 0x0e, 0xff, 0x43, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x5e, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, - 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x9a, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc7, 0x8b, 0x00, 0x0e, 0xff, 0x43, 0x00, 0x00, 0x62, 0xee, 0xfc, 0x00, - 0x41, 0xf7, 0x00, 0x00, 0x9f, 0x99, 0x00, 0x27, 0xfe, 0x4f, 0x1a, 0xfc, - 0x27, 0x00, 0x82, 0xba, 0x3d, 0xf9, 0x14, 0x00, 0x00, 0x00, 0x27, 0xfe, - 0x4f, 0x27, 0xfe, 0x4f, 0x3d, 0xf9, 0x14, 0x00, 0xea, 0x6d, 0x00, 0xf6, - 0x60, 0x22, 0xff, 0x12, 0x00, 0x46, 0xeb, 0x0e, 0xff, 0x43, 0x0e, 0xff, - 0x43, 0x0e, 0xff, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, - 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0e, 0x00, 0x13, 0xf7, 0x74, 0x3a, - 0xe1, 0x6d, 0x00, 0x00, 0x12, 0x00, 0x00, 0x97, 0x9e, 0x0d, 0xeb, 0x3d, - 0x71, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x12, 0x00, - 0x71, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x33, 0xff, 0x25, 0x22, 0xff, 0x3c, - 0x20, 0x67, 0xeb, 0x00, 0x00, 0x00, 0x17, 0xff, 0x42, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, - 0xc1, 0xc1, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xa8, 0x8b, 0x86, 0x0d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x16, 0xc8, 0x5c, 0x97, 0x00, 0x49, 0x33, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x33, 0x00, 0x00, - 0x00, 0x00, 0xf9, 0xad, 0x00, 0x1c, 0xd1, 0xd1, 0x95, 0xd1, 0xc0, 0x00, - 0x00, 0x00, 0xba, 0xf7, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - - -static mu_Rect atlas[] = { - [MU_ICON_CLOSE] = { 88, 68, 16, 16 }, - [MU_ICON_CHECK] = { 0, 0, 18, 18 }, - [MU_ICON_EXPANDED] = { 118, 68, 7, 5 }, - [MU_ICON_COLLAPSED] = { 113, 68, 5, 7 }, - [ATLAS_WHITE] = { 125, 68, 3, 3 }, - [ATLAS_FONT + 32] = { 84, 68, 2, 17 }, - [ATLAS_FONT + 33] = { 39, 68, 3, 17 }, - [ATLAS_FONT + 34] = { 114, 51, 5, 17 }, - [ATLAS_FONT + 35] = { 34, 17, 7, 17 }, - [ATLAS_FONT + 36] = { 28, 34, 6, 17 }, - [ATLAS_FONT + 37] = { 58, 0, 9, 17 }, - [ATLAS_FONT + 38] = { 103, 0, 8, 17 }, - [ATLAS_FONT + 39] = { 86, 68, 2, 17 }, - [ATLAS_FONT + 40] = { 42, 68, 3, 17 }, - [ATLAS_FONT + 41] = { 45, 68, 3, 17 }, - [ATLAS_FONT + 42] = { 34, 34, 6, 17 }, - [ATLAS_FONT + 43] = { 40, 34, 6, 17 }, - [ATLAS_FONT + 44] = { 48, 68, 3, 17 }, - [ATLAS_FONT + 45] = { 51, 68, 3, 17 }, - [ATLAS_FONT + 46] = { 54, 68, 3, 17 }, - [ATLAS_FONT + 47] = { 124, 34, 4, 17 }, - [ATLAS_FONT + 48] = { 46, 34, 6, 17 }, - [ATLAS_FONT + 49] = { 52, 34, 6, 17 }, - [ATLAS_FONT + 50] = { 58, 34, 6, 17 }, - [ATLAS_FONT + 51] = { 64, 34, 6, 17 }, - [ATLAS_FONT + 52] = { 70, 34, 6, 17 }, - [ATLAS_FONT + 53] = { 76, 34, 6, 17 }, - [ATLAS_FONT + 54] = { 82, 34, 6, 17 }, - [ATLAS_FONT + 55] = { 88, 34, 6, 17 }, - [ATLAS_FONT + 56] = { 94, 34, 6, 17 }, - [ATLAS_FONT + 57] = { 100, 34, 6, 17 }, - [ATLAS_FONT + 58] = { 57, 68, 3, 17 }, - [ATLAS_FONT + 59] = { 60, 68, 3, 17 }, - [ATLAS_FONT + 60] = { 106, 34, 6, 17 }, - [ATLAS_FONT + 61] = { 112, 34, 6, 17 }, - [ATLAS_FONT + 62] = { 118, 34, 6, 17 }, - [ATLAS_FONT + 63] = { 119, 51, 5, 17 }, - [ATLAS_FONT + 64] = { 18, 0, 10, 17 }, - [ATLAS_FONT + 65] = { 41, 17, 7, 17 }, - [ATLAS_FONT + 66] = { 48, 17, 7, 17 }, - [ATLAS_FONT + 67] = { 55, 17, 7, 17 }, - [ATLAS_FONT + 68] = { 111, 0, 8, 17 }, - [ATLAS_FONT + 69] = { 0, 35, 6, 17 }, - [ATLAS_FONT + 70] = { 6, 35, 6, 17 }, - [ATLAS_FONT + 71] = { 119, 0, 8, 17 }, - [ATLAS_FONT + 72] = { 18, 17, 8, 17 }, - [ATLAS_FONT + 73] = { 63, 68, 3, 17 }, - [ATLAS_FONT + 74] = { 66, 68, 3, 17 }, - [ATLAS_FONT + 75] = { 62, 17, 7, 17 }, - [ATLAS_FONT + 76] = { 12, 51, 6, 17 }, - [ATLAS_FONT + 77] = { 28, 0, 10, 17 }, - [ATLAS_FONT + 78] = { 67, 0, 9, 17 }, - [ATLAS_FONT + 79] = { 76, 0, 9, 17 }, - [ATLAS_FONT + 80] = { 69, 17, 7, 17 }, - [ATLAS_FONT + 81] = { 85, 0, 9, 17 }, - [ATLAS_FONT + 82] = { 76, 17, 7, 17 }, - [ATLAS_FONT + 83] = { 18, 51, 6, 17 }, - [ATLAS_FONT + 84] = { 24, 51, 6, 17 }, - [ATLAS_FONT + 85] = { 26, 17, 8, 17 }, - [ATLAS_FONT + 86] = { 83, 17, 7, 17 }, - [ATLAS_FONT + 87] = { 38, 0, 10, 17 }, - [ATLAS_FONT + 88] = { 90, 17, 7, 17 }, - [ATLAS_FONT + 89] = { 30, 51, 6, 17 }, - [ATLAS_FONT + 90] = { 36, 51, 6, 17 }, - [ATLAS_FONT + 91] = { 69, 68, 3, 17 }, - [ATLAS_FONT + 92] = { 124, 51, 4, 17 }, - [ATLAS_FONT + 93] = { 72, 68, 3, 17 }, - [ATLAS_FONT + 94] = { 42, 51, 6, 17 }, - [ATLAS_FONT + 95] = { 15, 68, 4, 17 }, - [ATLAS_FONT + 96] = { 48, 51, 6, 17 }, - [ATLAS_FONT + 97] = { 54, 51, 6, 17 }, - [ATLAS_FONT + 98] = { 97, 17, 7, 17 }, - [ATLAS_FONT + 99] = { 0, 52, 5, 17 }, - [ATLAS_FONT + 100] = { 104, 17, 7, 17 }, - [ATLAS_FONT + 101] = { 60, 51, 6, 17 }, - [ATLAS_FONT + 102] = { 19, 68, 4, 17 }, - [ATLAS_FONT + 103] = { 66, 51, 6, 17 }, - [ATLAS_FONT + 104] = { 111, 17, 7, 17 }, - [ATLAS_FONT + 105] = { 75, 68, 3, 17 }, - [ATLAS_FONT + 106] = { 78, 68, 3, 17 }, - [ATLAS_FONT + 107] = { 72, 51, 6, 17 }, - [ATLAS_FONT + 108] = { 81, 68, 3, 17 }, - [ATLAS_FONT + 109] = { 48, 0, 10, 17 }, - [ATLAS_FONT + 110] = { 118, 17, 7, 17 }, - [ATLAS_FONT + 111] = { 0, 18, 7, 17 }, - [ATLAS_FONT + 112] = { 7, 18, 7, 17 }, - [ATLAS_FONT + 113] = { 14, 34, 7, 17 }, - [ATLAS_FONT + 114] = { 23, 68, 4, 17 }, - [ATLAS_FONT + 115] = { 5, 52, 5, 17 }, - [ATLAS_FONT + 116] = { 27, 68, 4, 17 }, - [ATLAS_FONT + 117] = { 21, 34, 7, 17 }, - [ATLAS_FONT + 118] = { 78, 51, 6, 17 }, - [ATLAS_FONT + 119] = { 94, 0, 9, 17 }, - [ATLAS_FONT + 120] = { 84, 51, 6, 17 }, - [ATLAS_FONT + 121] = { 90, 51, 6, 17 }, - [ATLAS_FONT + 122] = { 10, 68, 5, 17 }, - [ATLAS_FONT + 123] = { 31, 68, 4, 17 }, - [ATLAS_FONT + 124] = { 96, 51, 6, 17 }, - [ATLAS_FONT + 125] = { 35, 68, 4, 17 }, - [ATLAS_FONT + 126] = { 102, 51, 6, 17 }, - [ATLAS_FONT + 127] = { 108, 51, 6, 17 }, -}; diff --git a/src/CRE/post_process.c b/src/CRE/post_process.c index b5a48645..64a8b3be 100644 --- a/src/CRE/post_process.c +++ b/src/CRE/post_process.c @@ -361,7 +361,7 @@ static void tone_map_data_calculate(tone_map_data* tmd) { vec3 tone_trans, tone_trans_scale, tone_trans_offset; vec3_sub(tmd->tone_trans_end, tmd->tone_trans_start, tone_trans); - vec3_div(vec3_identity, tone_trans, tone_trans_scale); + vec3_rcp(tone_trans, tone_trans_scale); vec3_mult(tone_trans_scale, tmd->tone_trans_start, tone_trans_offset); vec3_negate(tone_trans_offset, tone_trans_offset); diff --git a/src/CRE/shader.c b/src/CRE/shader.c index 8bcfcce2..f47296d9 100644 --- a/src/CRE/shader.c +++ b/src/CRE/shader.c @@ -5,7 +5,159 @@ #include "shader.h" #include "../CRE/hash.h" -#include "../KKdLib/io_path.h" +#include "../KKdLib/str_utils.h" + +static const char* process_mat_string = + "uniform bool use_bones;\n" + "\n" + "uniform sampler2D BoneMatrix;\n" + "\n" + "vec4 P = vec4(0.0);\n" + "vec3 N = vec3(0.0);\n" + "vec3 T = vec3(0.0);\n" + "\n" + "vec4 position;\n" + "vec3 normal;\n" + "vec3 tangent;\n" + "\n" + "void getBone(int bone_index, float bone_weight)\n" + "{\n" + " vec4 v0 = texelFetch(BoneMatrix, ivec2(0, bone_index), 0);\n" + " vec4 v1 = texelFetch(BoneMatrix, ivec2(1, bone_index), 0);\n" + " vec4 v2 = texelFetch(BoneMatrix, ivec2(2, bone_index), 0);\n" + " vec4 v3 = texelFetch(BoneMatrix, ivec2(3, bone_index), 0);\n" + " vec3 v4 = texelFetch(BoneMatrix, ivec2(4, bone_index), 0).xyz;\n" + " vec3 v5 = texelFetch(BoneMatrix, ivec2(5, bone_index), 0).xyz;\n" + " vec3 v6 = texelFetch(BoneMatrix, ivec2(6, bone_index), 0).xyz;\n" + " mat4 model_bone = mat4(v0, v1, v2, v3);\n" + " mat3 model_bone_normal = mat3(v4, v5, v6);\n" + " P += (model_bone * position) * bone_weight;\n" + " N += (model_bone_normal * normal) * bone_weight;\n" + " T += (model_bone_normal * tangent) * bone_weight;\n" + "}\n" + "\n" + "void PROCESSMAT()\n" + "{\n" + " if (use_bones && (aBoneWeight[0] != 0.0 || aBoneWeight[1] != 0.0 || aBoneWeight[2] != 0.0 || aBoneWeight[3] != 0.0))\n" + " {\n" + " P = vec4(0.0);\n" + " N = vec3(0.0);\n" + " T = vec3(0.0);\n" + " if (aBoneWeight[0] != 0.0)\n" + " getBone(int(aBoneIndex[0]), aBoneWeight[0]);\n" + " if (aBoneWeight[1] != 0.0)\n" + " getBone(int(aBoneIndex[1]), aBoneWeight[1]);\n" + " if (aBoneWeight[2] != 0.0)\n" + " getBone(int(aBoneIndex[2]), aBoneWeight[2]);\n" + " if (aBoneWeight[3] != 0.0)\n" + " getBone(int(aBoneIndex[3]), aBoneWeight[3]);\n" + "\n" + " N = normalize(N);\n" + " T = normalize(T);\n" + " T = normalize(T - dot(N, T) * N);\n" + " }\n" + " else\n" + " {\n" + " P = position;\n" + " N = normal;\n" + " T = tangent;\n" + " }\n" + "\n" + " P = model * P;\n" + " N = model_normal * N;\n" + " T = model_normal * T;\n" + "\n" + " N = normalize(N);\n" + " T = normalize(T);\n" + " T = normalize(T - dot(N, T) * N);\n" + "}"; + +static const char* tex_decode_string = + "uniform sampler2D[8] material;\n" + "uniform int[8] tex_mode;\n" + "\n" + "// Tex ID\n" + "// 0 - diffuse\n" + "// 1 - specular\n" + "// 2 - displacement\n" + "// 3 - normal\n" + "// 4 - albedo\n" + "// 5 - ao\n" + "// 6 - metallic\n" + "// 7 - roughness\n" + "\n" + "// Tex Mode\n" + "// 0 - default\n" + "// 1 - YCbCr BC4\n" + "// 2 - YCbCr BC5\n" + "// 3 - Normal Map BC5 Unsigned\n" + "// 4 - Normal Map BC5 Signed\n" + "// 5 - Normal Map Unsigned\n" + "// 6 - Normal Map Signed\n" + "\n" + "const vec3 _red_coef_709 = vec3( 1.5748, 1.0, 0.0000);\n" + "const vec3 _grn_coef_709 = vec3(-0.4681, 1.0, -0.1873);\n" + "const vec3 _blu_coef_709 = vec3( 0.0000, 1.0, 1.8556);\n" + "\n" + "const float cbcr_mult = 256.0 / 255.0;\n" + "const float cbcr_sub = 128.5 / 255.0;\n" + "\n" + "vec4 TEXDECODE(int id, vec2 uv)\n" + "{\n" + " vec4 data = vec4(0.0);\n" + " int mode = tex_mode[id];\n" + " if (mode == 1)\n" + " {\n" + " vec3 tmp;\n" + " tmp.y = textureLod(material[id], uv, 0).x;\n" + " tmp.x = textureLod(material[id], uv, 1).x;\n" + " tmp.z = textureLod(material[id], uv, 2).x;\n" + " tmp.xz = tmp.xz * cbcr_mult - cbcr_sub;\n" + "\n" + " vec4 c;\n" + " c.r = dot(tmp.xyz, _red_coef_709);\n" + " c.g = dot(tmp.xyz, _grn_coef_709);\n" + " c.b = dot(tmp.xyz, _blu_coef_709);\n" + " c.a = 1.0;\n" + " data = c;\n" + " }\n" + " else if (mode == 2)\n" + " {\n" + " vec4 tmp;\n" + " tmp.yw = textureLod(material[id], uv, 0).xy;\n" + " tmp.xz = textureLod(material[id], uv, 1).yx;\n" + " tmp.xz = tmp.xz * cbcr_mult - cbcr_sub;\n" + "\n" + " vec4 c;\n" + " c.r = dot(tmp.xyz, _red_coef_709);\n" + " c.g = dot(tmp.xyz, _grn_coef_709);\n" + " c.b = dot(tmp.xyz, _blu_coef_709);\n" + " c.a = tmp.a;\n" + " data = c;\n" + " }\n" + " else if (mode == 3)\n" + " {\n" + " vec3 normal;\n" + " normal.xy = texture(material[id], uv).xy * 2.0 - 1.0;\n" + " normal.z = sqrt(1.0 - normal.x * normal.x - normal.y * normal.y);\n" + " data = vec4(normal, 0.0);\n" + " }\n" + " else if (mode == 4)\n" + " {\n" + " vec3 normal;\n" + " normal.xy = texture(material[id], uv).xy;\n" + " normal.z = sqrt(1.0 - normal.x * normal.x - normal.y * normal.y);\n" + " data = vec4(normal, 0.0);\n" + " }\n" + " else if (mode == 5)\n" + " {\n" + " vec3 normal = texture(material[id], uv).xyz * 2.0 - 1.0;\n" + " data = vec4(normal, 0.0);\n" + " }\n" + " else\n" + " data = texture(material[id], uv);\n" + " return data;\n" + "}"; static int32_t program = 0; @@ -21,7 +173,7 @@ static char* shader_parse_define(char* data, shader_param* param) { for (size_t i = 0; i < s; i++) if (param->param[i]) { - sprintf_s(temp, 0x100, "#define %s\n", param->param[i]); + sprintf_s(temp, sizeof(temp), "#define %s\n", param->param[i]); temp_len[i] = strlen(temp); } else @@ -30,28 +182,54 @@ static char* shader_parse_define(char* data, shader_param* param) { char* def = strstr(data, "//DEF\n"); if (!def) return data; - size_t len_b = def - data; + + size_t len_a = def - data; def += 5; - size_t len_a = strlen(def); + size_t len_b = strlen(def); size_t len = 0; for (size_t i = 0; i < s; i++) len += temp_len[i]; if (!len) def++; - len += len_b + len_a; + len += len_a + len_b; char* temp_data = force_malloc(len + 1); size_t pos = 0; - memcpy(temp_data + pos, data, len_b); - pos += len_b; + memcpy(temp_data + pos, data, len_a); + pos += len_a; for (size_t i = 0; i < s; i++) { if (param->param[i]) { - sprintf_s(temp, 0x100, "#define %s\n", param->param[i]); - memcpy(temp_data + pos, temp, len_b); + sprintf_s(temp, sizeof(temp), "#define %s\n", param->param[i]); + memcpy(temp_data + pos, temp, len_a); } pos += temp_len[i]; } - memcpy(temp_data + pos, def, len_a); + memcpy(temp_data + pos, def, len_b); + free(data); + return temp_data; +} + +static char* shader_parse(char* data, char* parse_string, const char* replace_string) { + if (!data) + return data; + + char* def = strstr(data, parse_string); + if (!def) + return data; + + size_t len_a = def - data; + def += strlen(parse_string); + size_t len_b = strlen(replace_string); + size_t len_c = strlen(def); + size_t len = len_a + len_b + len_c; + + char* temp_data = force_malloc(len + 1); + size_t pos = 0; + memcpy(temp_data + pos, data, len_a); + pos += len_a; + memcpy(temp_data + pos, replace_string, len_b); + pos += len_b; + memcpy(temp_data + pos, def, len_c); free(data); return temp_data; } @@ -67,16 +245,32 @@ static GLuint shader_compile(GLenum type, char* data) { } void shader_fbo_load(shader_fbo* s, farc* f, shader_param* param) { - wchar_t_buffer_init(&s->name, param->name); - wchar_t* temp_frag = path_wadd_extension(param->frag, L".frag"); - wchar_t* temp_vert = path_wadd_extension(param->vert, L".vert"); - wchar_t* temp_geom = path_wadd_extension(param->geom, L".geom"); + if (!s || !f || !param) + return; + + wchar_t temp[0x1000]; + temp[0] = 0; + wcscat_s(temp, sizeof(temp) / sizeof(wchar_t), param->name); + for (size_t i = 0; i < SHADER_PARAM_NUM_PARAMS; i++) + if (param->param[i]) { + wchar_t* t = char_string_to_wchar_t_string(param->param[i]); + wcscat_s(temp, sizeof(temp) / sizeof(wchar_t), L"#"); + wcscat_s(temp, sizeof(temp) / sizeof(wchar_t), t); + free(t); + } + else + break; + wchar_t_buffer_init(&s->name, temp); + + wchar_t* temp_frag = str_utils_wadd(param->frag, L".frag"); + wchar_t* temp_vert = str_utils_wadd(param->vert, L".vert"); + wchar_t* temp_geom = str_utils_wadd(param->geom, L".geom"); farc_file* frag = farc_wread_file(f, temp_frag); farc_file* vert = farc_wread_file(f, temp_vert); farc_file* geom = farc_wread_file(f, temp_geom); - size_t frag_length = !frag ? 0 : frag->size_uncompressed; - size_t vert_length = !vert ? 0 : vert->size_uncompressed; - size_t geom_length = !geom ? 0 : geom->size_uncompressed; + size_t frag_length = !frag ? 0 : frag->size; + size_t vert_length = !vert ? 0 : vert->size; + size_t geom_length = !geom ? 0 : geom->size; char* frag_data = !frag ? 0 : force_malloc(frag_length + 1); char* vert_data = !vert ? 0 : force_malloc(vert_length + 1); char* geom_data = !geom ? 0 : force_malloc(geom_length + 1); @@ -126,8 +320,11 @@ void shader_fbo_load(shader_fbo* s, farc* f, shader_param* param) { glGetProgramiv(s->program, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(s->program, 0x200, 0, info_log); - wprintf(L"Program Shader linking error: %ls\n", param->name); - printf("%s\n", info_log); + printf("Program FBO Shader linking error: "); + wprintf(param->name); + putchar('\n'); + printf(info_log); + putchar('\n'); } if (frag_shad) @@ -138,7 +335,7 @@ void shader_fbo_load(shader_fbo* s, farc* f, shader_param* param) { glDeleteShader(geom_shad); } -void shader_fbo_use(shader_fbo* s) { +inline void shader_fbo_use(shader_fbo* s) { if (s) { if (program == s->program) return; @@ -178,7 +375,23 @@ void shader_fbo_free(shader_fbo* s) { } void shader_model_load(shader_model* s, shader_model_update* upd) { - wchar_t_buffer_init(&s->name, upd->param.name); + if (!s || !upd) + return; + + wchar_t temp[0x1000]; + temp[0] = 0; + wcscat_s(temp, sizeof(temp) / sizeof(wchar_t), upd->param.name); + for (size_t i = 0; i < SHADER_PARAM_NUM_PARAMS; i++) + if (upd->param.param[i]) { + wchar_t* t = char_string_to_wchar_t_string(upd->param.param[i]); + wcscat_s(temp, sizeof(temp) / sizeof(wchar_t), L"#"); + wcscat_s(temp, sizeof(temp) / sizeof(wchar_t), t); + free(t); + } + else + break; + wchar_t_buffer_init(&s->name, temp); + size_t frag_c_length = !upd->frag_c ? 0 : strlen(upd->frag_c); size_t frag_g_length = !upd->frag_g ? 0 : strlen(upd->frag_g); size_t vert_length = !upd->vert ? 0 : strlen(upd->vert); @@ -213,6 +426,13 @@ void shader_model_load(shader_model* s, shader_model_update* upd) { vert_data = shader_parse_define(vert_data, &upd->param); geom_data = shader_parse_define(geom_data, &upd->param); + vert_data = shader_parse(vert_data, "//PROCESSMAT", process_mat_string); + + frag_c_data = shader_parse(frag_c_data, "//TEXDECODE", tex_decode_string); + frag_g_data = shader_parse(frag_g_data, "//TEXDECODE", tex_decode_string); + vert_data = shader_parse(vert_data, "//TEXDECODE", tex_decode_string); + geom_data = shader_parse(geom_data, "//TEXDECODE", tex_decode_string); + GLuint frag_c_shad = shader_compile(GL_FRAGMENT_SHADER, frag_c_data); GLuint frag_g_shad = shader_compile(GL_FRAGMENT_SHADER, frag_g_data); GLuint vert_shad = shader_compile(GL_VERTEX_SHADER, vert_data); @@ -224,7 +444,6 @@ void shader_model_load(shader_model* s, shader_model_update* upd) { free(geom_data); GLint success; - GLchar info_log[0x200]; s->c_program = glCreateProgram(); s->g_program = glCreateProgram(); if (frag_c_shad) @@ -237,9 +456,14 @@ void shader_model_load(shader_model* s, shader_model_update* upd) { glGetProgramiv(s->c_program, GL_LINK_STATUS, &success); if (!success) { - glGetProgramInfoLog(s->c_program, 0x200, 0, info_log); - wprintf(L"Program C Shader linking error: %ls\n", upd->param.name); - printf("%s\n", info_log); + GLchar* info_log = force_malloc(0x10000); + glGetProgramInfoLog(s->c_program, 0x10000, 0, info_log); + printf("Program C Shader linking error: "); + wprintf(upd->param.name); + putchar('\n'); + printf(info_log); + putchar('\n'); + free(info_log); } if (frag_g_shad) @@ -252,9 +476,14 @@ void shader_model_load(shader_model* s, shader_model_update* upd) { glGetProgramiv(s->g_program, GL_LINK_STATUS, &success); if (!success) { + GLchar* info_log = force_malloc(0x10000); glGetProgramInfoLog(s->g_program, 0x200, 0, info_log); - wprintf(L"Program G Shader linking error: %ls\n", upd->param.name); - printf("%s\n", info_log); + printf("Program G Shader linking error: "); + wprintf(upd->param.name); + putchar('\n'); + printf(info_log); + putchar('\n'); + free(info_log); } if (frag_c_shad) @@ -267,7 +496,7 @@ void shader_model_load(shader_model* s, shader_model_update* upd) { glDeleteShader(geom_shad); } -void shader_model_c_use(shader_model* s) { +inline void shader_model_c_use(shader_model* s) { if (s) { if (program == s->c_program) return; @@ -281,7 +510,7 @@ void shader_model_c_use(shader_model* s) { } } -void shader_model_g_use(shader_model* s) { +inline void shader_model_g_use(shader_model* s) { if (s) { if (program == s->g_program) return; @@ -302,7 +531,7 @@ GLint shader_model_c_get_uniform_location(shader_model* s, GLchar* name) { shader_model_c_use(s); GLint location = glGetUniformLocation(s->c_program, name); if (location == -1) - printf("Location \"%s\" in program %d isn't found", name, s->c_program);; + printf("Location \"%s\" in program %d isn't found\n", name, s->c_program);; return location; } @@ -313,7 +542,7 @@ GLint shader_model_g_get_uniform_location(shader_model* s, GLchar* name) { shader_model_g_use(s); GLint location = glGetUniformLocation(s->g_program, name); if (location == -1) - printf("Location \"%s\" in program %d isn't found", name, s->g_program);; + printf("Location \"%s\" in program %d isn't found\n", name, s->g_program);; return location; } diff --git a/src/CRE/shader.h b/src/CRE/shader.h index 5af60c40..0345896e 100644 --- a/src/CRE/shader.h +++ b/src/CRE/shader.h @@ -118,86 +118,128 @@ glUniformMatrix3fv(shader_fbo_get_uniform_location(s, name), count, transpose, ( #define shader_fbo_set_mat4_array(s, name, count, transpose, mat) \ glUniformMatrix4fv(shader_fbo_get_uniform_location(s, name), count, transpose, (GLfloat*)mat) -#define shader_model_set_bool(s, name, value) \ -glUniform1i(shader_model_c_get_uniform_location(s, name), value ? 1 : 0); \ +#define shader_model_c_set_bool(s, name, value) \ +glUniform1i(shader_model_c_get_uniform_location(s, name), value ? 1 : 0) + +#define shader_model_c_set_int(s, name, value) \ +glUniform1i(shader_model_c_get_uniform_location(s, name), value) + +#define shader_model_c_set_float(s, name, value) \ +glUniform1f(shader_model_c_get_uniform_location(s, name), value) + +#define shader_model_c_set_vec2i(s, name, x, y) \ +glUniform2i(shader_model_c_get_uniform_location(s, name), x, y) + +#define shader_model_c_set_vec2(s, name, x, y) \ +glUniform2f(shader_model_c_get_uniform_location(s, name), x, y) + +#define shader_model_c_set_vec3i(s, name, x, y, z) \ +glUniform3i(shader_model_c_get_uniform_location(s, name), x, y, z) + +#define shader_model_c_set_vec3(s, name, x, y, z) \ +glUniform3f(shader_model_c_get_uniform_location(s, name), x, y, z) + +#define shader_model_c_set_vec4i(s, name, x, y, z, w) \ +glUniform4i(shader_model_c_get_uniform_location(s, name), x, y, z, w) + +#define shader_model_c_set_vec4(s, name, x, y, z, w) \ +glUniform4f(shader_model_c_get_uniform_location(s, name), x, y, z, w) + +#define shader_model_c_set_mat3(s, name, transpose, mat) \ +glUniformMatrix3fv(shader_model_c_get_uniform_location(s, name), 1, transpose, (GLfloat*)mat) + +#define shader_model_c_set_mat4(s, name, transpose, mat) \ +glUniformMatrix4fv(shader_model_c_get_uniform_location(s, name), 1, transpose, (GLfloat*)mat) + +#define shader_model_c_set_int_array(s, name, count, value) \ +glUniform1iv(shader_model_c_get_uniform_location(s, name), count, value) + +#define shader_model_c_set_float_array(s, name, count, value) \ +glUniform1fv(shader_model_c_get_uniform_location(s, name), count, value) + +#define shader_model_c_set_vec2i_array(s, name, count, value) \ +glUniform2iv(shader_model_c_get_uniform_location(s, name), count, (GLint*)value) + +#define shader_model_c_set_vec2_array(s, name, count, value) \ +glUniform2fv(shader_model_c_get_uniform_location(s, name), count, (GLfloat*)value) + +#define shader_model_c_set_vec3i_array(s, name, count, value) \ +glUniform3iv(shader_model_c_get_uniform_location(s, name), count, (GLint*)value) + +#define shader_model_c_set_vec3_array(s, name, count, value) \ +glUniform3fv(shader_model_c_get_uniform_location(s, name), count, (GLfloat*)value) + +#define shader_model_c_set_vec4i_array(s, name, count, value) \ +glUniform4iv(shader_model_c_get_uniform_location(s, name), count, (GLint*)value) + +#define shader_model_c_set_vec4_array(s, name, count, value) \ +glUniform4fv(shader_model_c_get_uniform_location(s, name), count, (GLfloat*)value) + +#define shader_model_c_set_mat3_array(s, name, count, transpose, mat) \ +glUniformMatrix3fv(shader_model_c_get_uniform_location(s, name), count, transpose, (GLfloat*)mat) + +#define shader_model_c_set_mat4_array(s, name, count, transpose, mat) \ +glUniformMatrix4fv(shader_model_c_get_uniform_location(s, name), count, transpose, (GLfloat*)mat) + +#define shader_model_g_set_bool(s, name, value) \ glUniform1i(shader_model_g_get_uniform_location(s, name), value ? 1 : 0) -#define shader_model_set_int(s, name, value) \ -glUniform1i(shader_model_c_get_uniform_location(s, name), value); \ +#define shader_model_g_set_int(s, name, value) \ glUniform1i(shader_model_g_get_uniform_location(s, name), value) -#define shader_model_set_float(s, name, value) \ -glUniform1f(shader_model_c_get_uniform_location(s, name), value); \ +#define shader_model_g_set_float(s, name, value) \ glUniform1f(shader_model_g_get_uniform_location(s, name), value) -#define shader_model_set_vec2i(s, name, x, y) \ -glUniform2i(shader_model_c_get_uniform_location(s, name), x, y); \ +#define shader_model_g_set_vec2i(s, name, x, y) \ glUniform2i(shader_model_g_get_uniform_location(s, name), x, y) -#define shader_model_set_vec2(s, name, x, y) \ -glUniform2f(shader_model_c_get_uniform_location(s, name), x, y); \ +#define shader_model_g_set_vec2(s, name, x, y) \ glUniform2f(shader_model_g_get_uniform_location(s, name), x, y) -#define shader_model_set_vec3i(s, name, x, y, z) \ -glUniform3i(shader_model_c_get_uniform_location(s, name), x, y, z); \ +#define shader_model_g_set_vec3i(s, name, x, y, z) \ glUniform3i(shader_model_g_get_uniform_location(s, name), x, y, z) -#define shader_model_set_vec3(s, name, x, y, z) \ -glUniform3f(shader_model_c_get_uniform_location(s, name), x, y, z); \ +#define shader_model_g_set_vec3(s, name, x, y, z) \ glUniform3f(shader_model_g_get_uniform_location(s, name), x, y, z) -#define shader_model_set_vec4i(s, name, x, y, z, w) \ -glUniform4i(shader_model_c_get_uniform_location(s, name), x, y, z, w); \ +#define shader_model_g_set_vec4i(s, name, x, y, z, w) \ glUniform4i(shader_model_g_get_uniform_location(s, name), x, y, z, w) -#define shader_model_set_vec4(s, name, x, y, z, w) \ -glUniform4f(shader_model_c_get_uniform_location(s, name), x, y, z, w); \ +#define shader_model_g_set_vec4(s, name, x, y, z, w) \ glUniform4f(shader_model_g_get_uniform_location(s, name), x, y, z, w) -#define shader_model_set_mat3(s, name, transpose, mat) \ -glUniformMatrix3fv(shader_model_c_get_uniform_location(s, name), 1, transpose, (GLfloat*)mat); \ +#define shader_model_g_set_mat3(s, name, transpose, mat) \ glUniformMatrix3fv(shader_model_g_get_uniform_location(s, name), 1, transpose, (GLfloat*)mat) -#define shader_model_set_mat4(s, name, transpose, mat) \ -glUniformMatrix4fv(shader_model_c_get_uniform_location(s, name), 1, transpose, (GLfloat*)mat); \ +#define shader_model_g_set_mat4(s, name, transpose, mat) \ glUniformMatrix4fv(shader_model_g_get_uniform_location(s, name), 1, transpose, (GLfloat*)mat) -#define shader_model_set_int_array(s, name, count, value) \ -glUniform1iv(shader_model_c_get_uniform_location(s, name), count, value); \ +#define shader_model_g_set_int_array(s, name, count, value) \ glUniform1iv(shader_model_g_get_uniform_location(s, name), count, value) -#define shader_model_set_float_array(s, name, count, value) \ -glUniform1fv(shader_model_c_get_uniform_location(s, name), count, value); \ +#define shader_model_g_set_float_array(s, name, count, value) \ glUniform1fv(shader_model_g_get_uniform_location(s, name), count, value) -#define shader_model_set_vec2i_array(s, name, count, value) \ -glUniform2iv(shader_model_c_get_uniform_location(s, name), count, (GLint*)value); \ +#define shader_model_g_set_vec2i_array(s, name, count, value) \ glUniform2iv(shader_model_g_get_uniform_location(s, name), count, (GLint*)value) -#define shader_model_set_vec2_array(s, name, count, value) \ -glUniform2fv(shader_model_c_get_uniform_location(s, name), count, (GLfloat*)value); \ +#define shader_model_g_set_vec2_array(s, name, count, value) \ glUniform2fv(shader_model_g_get_uniform_location(s, name), count, (GLfloat*)value) -#define shader_model_set_vec3i_array(s, name, count, value) \ -glUniform3iv(shader_model_c_get_uniform_location(s, name), count, (GLint*)value); \ +#define shader_model_g_set_vec3i_array(s, name, count, value) \ glUniform3iv(shader_model_g_get_uniform_location(s, name), count, (GLint*)value) -#define shader_model_set_vec3_array(s, name, count, value) \ -glUniform3fv(shader_model_c_get_uniform_location(s, name), count, (GLfloat*)value); \ +#define shader_model_g_set_vec3_array(s, name, count, value) \ glUniform3fv(shader_model_g_get_uniform_location(s, name), count, (GLfloat*)value) -#define shader_model_set_vec4i_array(s, name, count, value) \ -glUniform4iv(shader_model_c_get_uniform_location(s, name), count, (GLint*)value); \ +#define shader_model_g_set_vec4i_array(s, name, count, value) \ glUniform4iv(shader_model_g_get_uniform_location(s, name), count, (GLint*)value) -#define shader_model_set_vec4_array(s, name, count, value) \ -glUniform4fv(shader_model_c_get_uniform_location(s, name), count, (GLfloat*)value); \ +#define shader_model_g_set_vec4_array(s, name, count, value) \ glUniform4fv(shader_model_g_get_uniform_location(s, name), count, (GLfloat*)value) -#define shader_model_set_mat3_array(s, name, count, transpose, mat) \ -glUniformMatrix3fv(shader_model_c_get_uniform_location(s, name), count, transpose, (GLfloat*)mat); \ +#define shader_model_g_set_mat3_array(s, name, count, transpose, mat) \ glUniformMatrix3fv(shader_model_g_get_uniform_location(s, name), count, transpose, (GLfloat*)mat) -#define shader_model_set_mat4_array(s, name, count, transpose, mat) \ -glUniformMatrix4fv(shader_model_c_get_uniform_location(s, name), count, transpose, (GLfloat*)mat); \ +#define shader_model_g_set_mat4_array(s, name, count, transpose, mat) \ glUniformMatrix4fv(shader_model_g_get_uniform_location(s, name), count, transpose, (GLfloat*)mat) diff --git a/src/CRE/shared.c b/src/CRE/shared.c new file mode 100644 index 00000000..db5ca4d2 --- /dev/null +++ b/src/CRE/shared.c @@ -0,0 +1,16 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "shared.h" + +vector_func(hash_ptr_gl_object) +vector_func(hash_light_dir) +vector_func(hash_light_point) +vector_func(hash_material) +vector_func(hash_shader_model) +vector_func(hash_texture) +vector_func(hash_texture_set) +vector_func(hash_texture_bone_mat) +vector_func(hash_ptr_vertex) diff --git a/src/CRE/shared.h b/src/CRE/shared.h new file mode 100644 index 00000000..8d1ef857 --- /dev/null +++ b/src/CRE/shared.h @@ -0,0 +1,38 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/str_utils.h" +#include "../KKdLib/vec.h" +#include "../KKdLib/vector.h" +#include "gl_object.h" +#include "hash.h" +#include "light.h" +#include "lock.h" +#include "shader.h" +#include "task.h" +#include "texture.h" +#include "vertex.h" + +hash_ptr(gl_object) +hash_dat(light_dir) +hash_dat(light_point) +hash_dat(material) +hash_dat(shader_model) +hash_dat(texture) +hash_dat(texture_set) +hash_dat(texture_bone_mat) +hash_ptr(vertex) + +vector(hash_ptr_gl_object) +vector(hash_light_dir) +vector(hash_light_point) +vector(hash_material) +vector(hash_shader_model) +vector(hash_texture) +vector(hash_texture_set) +vector(hash_texture_bone_mat) +vector(hash_ptr_vertex) diff --git a/src/CRE/static_var.c b/src/CRE/static_var.c index d6e2578e..b9294de0 100644 --- a/src/CRE/static_var.c +++ b/src/CRE/static_var.c @@ -22,6 +22,18 @@ bool sv_fxaa_changed = false; bool sv_old_fxaa = false; bool sv_fxaa = false; +static int32_t active_tex; +static int32_t current_fbo; +static int32_t current_vao; +static int32_t current_vbo; +static int32_t current_ebo; +static int32_t current_ubo; +static int32_t current_tex1d[32]; +static int32_t current_tex2d[32]; +static int32_t current_tex2dms[32]; +static int32_t current_tex3d[32]; +static int32_t current_texcube[32]; + const vec3 sv_rgb_to_luma = { 0.2126f, 0.7152f, 0.0722f }; @@ -62,3 +74,120 @@ void sv_fxaa_set(bool value) { sv_fxaa_changed = true; sv_old_fxaa = sv_fxaa; } + +inline void bind_index_tex1d(int32_t index, int32_t id) { + if (current_tex1d[index] != id) { + active_texture(index); + glBindTexture(GL_TEXTURE_1D, id); + current_tex1d[index] = id; + } +} + +inline void bind_index_tex2d(int32_t index, int32_t id) { + if (current_tex2d[index] != id) { + active_texture(index); + glBindTexture(GL_TEXTURE_2D, id); + current_tex2d[index] = id; + } +} + +inline void bind_index_tex2dms(int32_t index, int32_t id) { + if (current_tex2dms[index] != id) { + active_texture(index); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, id); + current_tex2dms[index] = id; + } +} + +inline void bind_index_tex3d(int32_t index, int32_t id) { + if (current_tex3d[index] != id) { + active_texture(index); + glBindTexture(GL_TEXTURE_3D, id); + current_tex3d[index] = id; + } +} + +inline void bind_index_texcube(int32_t index, int32_t id) { + if (current_texcube[index] != id) { + active_texture(index); + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + current_texcube[index] = id; + } +} + +inline void active_texture(int32_t index) { + if (active_tex != index) { + glActiveTexture(GL_TEXTURE0 + index); + active_tex = index; + } +} + +inline void bind_framebuffer(int32_t fbo) { + if (current_fbo != fbo) { + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + current_fbo = fbo; + } +} + +inline void bind_vertex_array(int32_t vao) { + if (current_vao != vao) { + glBindVertexArray(vao); + current_vao = vao; + } +} + +inline void bind_array_buffer(int32_t vbo) { + if (current_vbo != vbo) { + glBindBuffer(GL_ARRAY_BUFFER, vbo); + current_vbo = vbo; + } +} + +inline void bind_element_array_buffer(int32_t ebo) { + if (current_ebo != ebo) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + current_ebo = ebo; + } +} + +inline void bind_uniform_buffer(int32_t ubo) { + if (current_ubo != ubo) { + glBindBuffer(GL_UNIFORM_BUFFER, ubo); + current_ubo = ubo; + } +} + +inline void bind_tex1d(int32_t id) { + if (current_tex1d[active_tex] != id) { + glBindTexture(GL_TEXTURE_1D, id); + current_tex1d[active_tex] = id; + } +} + +inline void bind_tex2d(int32_t id) { + if (current_tex2d[active_tex] != id) { + glBindTexture(GL_TEXTURE_2D, id); + current_tex2d[active_tex] = id; + } +} + +inline void bind_tex2dms(int32_t id) { + if (current_tex2dms[active_tex] != id) { + glBindTexture(GL_TEXTURE_2D, id); + current_tex2dms[active_tex] = id; + } +} + +inline void bind_tex3d(int32_t id) { + if (current_tex3d[active_tex] != id) { + glBindTexture(GL_TEXTURE_3D, id); + current_tex3d[active_tex] = id; + } +} + +inline void bind_texcube(int32_t id) { + if (current_texcube[active_tex] != id) { + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + current_texcube[active_tex] = id; + } +} diff --git a/src/CRE/static_var.h b/src/CRE/static_var.h index dc442a53..f955046a 100644 --- a/src/CRE/static_var.h +++ b/src/CRE/static_var.h @@ -8,6 +8,8 @@ #include "../KKdLib/default.h" #include "../KKdLib/vec.h" #include "../KKdLib/mat.h" +#define GLEW_STATIC +#include extern int32_t sv_max_samples; extern int32_t sv_max_texture_buffer_size; @@ -31,3 +33,20 @@ extern bool sv_can_use_msaa(); extern void sv_anisotropy_set(int32_t value); extern void sv_samples_set(int32_t value); extern void sv_fxaa_set(bool value); + +extern void bind_index_tex1d(int32_t index, int32_t id); +extern void bind_index_tex2d(int32_t index, int32_t id); +extern void bind_index_tex2dms(int32_t index, int32_t id); +extern void bind_index_tex3d(int32_t index, int32_t id); +extern void bind_index_texcube(int32_t index, int32_t id); +extern void active_texture(int32_t index); +extern void bind_framebuffer(int32_t fbo); +extern void bind_vertex_array(int32_t vao); +extern void bind_array_buffer(int32_t vbo); +extern void bind_element_array_buffer(int32_t ebo); +extern void bind_uniform_buffer(int32_t ubo); +extern void bind_tex1d(int32_t id); +extern void bind_tex2d(int32_t id); +extern void bind_tex2dms(int32_t id); +extern void bind_tex3d(int32_t id); +extern void bind_texcube(int32_t id); diff --git a/src/CRE/task.c b/src/CRE/task.c index 93626eb1..dbb77e66 100644 --- a/src/CRE/task.c +++ b/src/CRE/task.c @@ -5,6 +5,7 @@ #include "task.h" +vector_func(task_render_uniform) vector_func(task_render) vector_func(task_render_draw2d) vector_func(task_render_draw3d) diff --git a/src/CRE/task.h b/src/CRE/task.h index c0d084c6..4270d124 100644 --- a/src/CRE/task.h +++ b/src/CRE/task.h @@ -11,14 +11,31 @@ #include "../KKdLib/vec.h" #include "../KKdLib/vector.h" #include "../CRE/gl_object.h" +#include "../CRE/light.h" #include "../CRE/shader.h" -#include "../CRE/texture.h" +#include "../CRE/material.h" #include "../CRE/vertex.h" +#include + +typedef enum task_render_free_type { + TASK_RENDER_FREE_NONE = 0, + TASK_RENDER_FREE_GL_OBJECT, + TASK_RENDER_FREE_LIGHT_DIR, + TASK_RENDER_FREE_LIGHT_POINT, + TASK_RENDER_FREE_SHADER, + TASK_RENDER_FREE_MATERIAL, + TASK_RENDER_FREE_TEXTURE, + TASK_RENDER_FREE_TEXTURE_SET, + TASK_RENDER_FREE_VERT, +} task_render_free_type; typedef enum task_render_update_type { TASK_RENDER_UPDATE_NONE = 0, TASK_RENDER_UPDATE_GL_OBJECT, + TASK_RENDER_UPDATE_LIGHT_DIR, + TASK_RENDER_UPDATE_LIGHT_POINT, TASK_RENDER_UPDATE_SHADER, + TASK_RENDER_UPDATE_MATERIAL, TASK_RENDER_UPDATE_TEXTURE, TASK_RENDER_UPDATE_TEXTURE_SET, TASK_RENDER_UPDATE_VERT, @@ -71,11 +88,14 @@ typedef enum task_render_draw3d_type { } task_render_draw3d_type; typedef struct task_render_update { + hash hash; task_render_update_type type; - uint64_t hash; union { gl_object_update gl_obj; + light_dir_update light_dir; + light_point_update light_point; shader_model_update shad; + material_update mat; texture_data tex; texture_set_data tex_set; vertex_update vert; @@ -83,8 +103,8 @@ typedef struct task_render_update { } task_render_update; typedef struct task_render_free { - task_render_update_type type; - uint64_t hash; + hash hash; + task_render_free_type type; } task_render_free; typedef struct task_render_uniform_bool { @@ -186,11 +206,11 @@ typedef struct task_render_uniform_mat4_array { } task_render_uniform_mat4_array; typedef struct task_render_uniform { - uint64_t shader_hash; + hash shader_hash; char_buffer name; task_render_uniform_type type; union { - task_render_uniform_bool bool; + task_render_uniform_bool boolean; task_render_uniform_int32 int32; task_render_uniform_float32 float32; task_render_uniform_vec2 vec2; @@ -223,33 +243,23 @@ typedef struct task_render { }; } task_render; +vector(task_render_uniform) + typedef struct task_render_draw2d { + hash hash; task_render_draw2d_type type; - uint64_t hash; - bool blend; - int16_t blend_src_factor_rgb; - int16_t blend_dst_factor_rgb; - int16_t blend_src_factor_alpha; - int16_t blend_dst_factor_alpha; - int16_t blend_mode_rgb; - int16_t blend_mode_alpha; + vector_task_render_uniform uniforms; } task_render_draw2d; typedef struct task_render_draw3d { + hash hash; task_render_draw3d_type type; - uint64_t hash; - bool blend; - int16_t blend_src_factor_rgb; - int16_t blend_dst_factor_rgb; - int16_t blend_src_factor_alpha; - int16_t blend_dst_factor_alpha; - int16_t blend_mode_rgb; - int16_t blend_mode_alpha; - bool depth; - int16_t depth_func; - bool depth_mask; - bool cull_face; - int16_t cull_face_mode; + bool translucent; + mat4 model; + mat3 model_normal; + mat4 uv_mat; + vec4 color; + vector_task_render_uniform uniforms; } task_render_draw3d; vector(task_render) diff --git a/src/CRE/texture.c b/src/CRE/texture.c index d7851180..53744cab 100644 --- a/src/CRE/texture.c +++ b/src/CRE/texture.c @@ -4,13 +4,17 @@ */ #include "texture.h" +#include "../KKdLib/mat.h" +#include "../KKdLib/txp.h" #include "static_var.h" -void texture_1d_load(texture* tex, texture_data* data) { - if (!data->data || data->width < 1) - return; +static void load_texture_data(GLenum target, txp_format format, + uint32_t width, uint32_t height, uint32_t level, void* data); - glBindTexture(GL_TEXTURE_1D, tex->id); +static void texture_1d_load(texture* tex, texture_data* data) { + uint32_t width = max(data->width, 0); + + bind_tex1d(tex->id); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, data->wrap_mode_s); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, data->min_filter); @@ -18,24 +22,24 @@ void texture_1d_load(texture* tex, texture_data* data) { glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAX_ANISOTROPY, sv_anisotropy); - glTexImage1D(GL_TEXTURE_1D, 0, data->pixel_internal_format, data->width, + glTexImage1D(GL_TEXTURE_1D, 0, data->pixel_internal_format, width, 0, data->pixel_format, data->pixel_type, data->data); if (data->generate_mipmap) glGenerateMipmap(GL_TEXTURE_1D); - glBindTexture(GL_TEXTURE_1D, 0); + bind_tex1d(0); } -void texture_1d_update(texture* tex) { - glBindTexture(GL_TEXTURE_1D, tex->id); +static void texture_1d_update(texture* tex) { + bind_tex1d(tex->id); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAX_ANISOTROPY, sv_anisotropy); - glBindTexture(GL_TEXTURE_1D, 0); + bind_tex1d(0); } -void texture_2d_load(texture* tex, texture_data* data) { - if (!data->data || data->width < 1 || data->height < 1) - return; +static void texture_2d_load(texture* tex, texture_data* data) { + uint32_t width = max(data->width, 0); + uint32_t height = max(data->height, 0); - glBindTexture(GL_TEXTURE_2D, tex->id); + bind_tex2d(tex->id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, data->wrap_mode_s); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, data->wrap_mode_t); @@ -44,24 +48,25 @@ void texture_2d_load(texture* tex, texture_data* data) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, sv_anisotropy); - glTexImage2D(GL_TEXTURE_2D, 0, data->pixel_internal_format, data->width, data->height, + glTexImage2D(GL_TEXTURE_2D, 0, data->pixel_internal_format, width, height, 0, data->pixel_format, data->pixel_type, data->data); if (data->generate_mipmap) glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); + bind_tex2d(0); } -void texture_2d_update(texture* tex) { - glBindTexture(GL_TEXTURE_2D, tex->id); +static void texture_2d_update(texture* tex) { + bind_tex2d(tex->id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, sv_anisotropy); - glBindTexture(GL_TEXTURE_2D, 0); + bind_tex2d(0); } -void texture_3d_load(texture* tex, texture_data* data) { - if (!data->data) - return; +static void texture_3d_load(texture* tex, texture_data* data) { + uint32_t width = max(data->width, 0); + uint32_t height = max(data->height, 0); + uint32_t depth = max(data->depth, 0); - glBindTexture(GL_TEXTURE_3D, tex->id); + bind_tex3d(tex->id); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, data->wrap_mode_s); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, data->wrap_mode_t); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, data->wrap_mode_r); @@ -71,24 +76,34 @@ void texture_3d_load(texture* tex, texture_data* data) { glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_ANISOTROPY, sv_anisotropy); - glTexImage3D(GL_TEXTURE_3D, 0, data->pixel_internal_format, data->width, data->height, - data->depth, 0, data->pixel_format, data->pixel_type, data->data); + glTexImage3D(GL_TEXTURE_3D, 0, data->pixel_internal_format, width, height, + depth, 0, data->pixel_format, data->pixel_type, data->data); if (data->generate_mipmap) glGenerateMipmap(GL_TEXTURE_3D); - glBindTexture(GL_TEXTURE_3D, 0); + bind_tex3d(0); } -void texture_3d_update(texture* tex) { - glBindTexture(GL_TEXTURE_3D, tex->id); +static void texture_3d_update(texture* tex) { + bind_tex3d(tex->id); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_ANISOTROPY, sv_anisotropy); - glBindTexture(GL_TEXTURE_3D, 0); + bind_tex3d(0); } -void texture_cube_load(texture* tex, texture_cube_data* data) { - if (!data->px.data || !data->nx.data || !data->py.data || !data->ny.data || !data->pz.data || !data->nz.data) - return; +static void texture_cube_load(texture* tex, texture_cube_data* data) { + uint32_t px_width = max(data->px.width, 0); + uint32_t px_height = max(data->px.height, 0); + uint32_t nx_width = max(data->nx.width, 0); + uint32_t nx_height = max(data->nx.height, 0); + uint32_t py_width = max(data->py.width, 0); + uint32_t py_height = max(data->py.height, 0); + uint32_t ny_width = max(data->ny.width, 0); + uint32_t ny_height = max(data->ny.height, 0); + uint32_t pz_width = max(data->pz.width, 0); + uint32_t pz_height = max(data->pz.height, 0); + uint32_t nz_width = max(data->nz.width, 0); + uint32_t nz_height = max(data->nz.height, 0); - glBindTexture(GL_TEXTURE_CUBE_MAP, tex->id); + bind_texcube(tex->id); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, data->wrap_mode_s); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, data->wrap_mode_t); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, data->wrap_mode_r); @@ -98,33 +113,40 @@ void texture_cube_load(texture* tex, texture_cube_data* data) { glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY, sv_anisotropy); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, data->pixel_internal_format, data->px.width, - data->px.height, 0, data->px.pixel_format, data->px.pixel_type, data->px.data); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, data->pixel_internal_format, data->nx.width, - data->nx.height, 0, data->nx.pixel_format, data->nx.pixel_type, data->nx.data); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, data->pixel_internal_format, data->py.width, - data->py.height, 0, data->py.pixel_format, data->py.pixel_type, data->py.data); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, data->pixel_internal_format, data->ny.width, - data->ny.height, 0, data->ny.pixel_format, data->ny.pixel_type, data->ny.data); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, data->pixel_internal_format, data->pz.width, - data->pz.height, 0, data->pz.pixel_format, data->pz.pixel_type, data->pz.data); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, data->pixel_internal_format, data->nz.width, - data->nz.height, 0, data->nz.pixel_format, data->nz.pixel_type, data->nz.data); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, data->pixel_internal_format, px_width, + px_height, 0, data->px.pixel_format, data->px.pixel_type, data->px.data); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, data->pixel_internal_format, nx_width, + nx_height, 0, data->nx.pixel_format, data->nx.pixel_type, data->nx.data); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, data->pixel_internal_format, py_width, + py_height, 0, data->py.pixel_format, data->py.pixel_type, data->py.data); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, data->pixel_internal_format, ny_width, + ny_height, 0, data->ny.pixel_format, data->ny.pixel_type, data->ny.data); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, data->pixel_internal_format, pz_width, + pz_height, 0, data->pz.pixel_format, data->pz.pixel_type, data->pz.data); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, data->pixel_internal_format, nz_width, + nz_height, 0, data->nz.pixel_format, data->nz.pixel_type, data->nz.data); if (data->generate_mipmap) glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + bind_texcube(0); } -void texture_cube_update(texture* tex) { - glBindTexture(GL_TEXTURE_CUBE_MAP, tex->id); +static void texture_cube_update(texture* tex) { + bind_texcube(tex->id); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY, sv_anisotropy); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + bind_texcube(0); } void texture_load(texture* tex, texture_data* data) { + if (!tex) + return; + if (tex->id == 0) glGenTextures(1, &tex->id); + if (!data) + return; + + tex->mode = TEXTURE_MODE_DEFAULT; tex->type = data->type; switch (tex->type) { case TEXTURE_1D: @@ -143,52 +165,49 @@ void texture_load(texture* tex, texture_data* data) { } void texture_bind(texture* tex, int32_t index) { - GLenum target = 0; + if (!tex) + return; + switch (tex->type) { case TEXTURE_1D: - target = GL_TEXTURE_1D; + bind_index_tex1d(index, tex->id); break; case TEXTURE_2D: - target = GL_TEXTURE_2D; + bind_index_tex2d(index, tex->id); break; case TEXTURE_3D: - target = GL_TEXTURE_3D; + bind_index_tex3d(index, tex->id); break; case TEXTURE_CUBE: - target = GL_TEXTURE_CUBE_MAP; + bind_index_texcube(index, tex->id); break; } - - if (target) { - glActiveTexture(GL_TEXTURE0 + index); - glBindTexture(target, tex->id); - } } void texture_reset(texture* tex, int32_t index) { - GLenum target = 0; + if (!tex) + return; + switch (tex->type) { case TEXTURE_1D: - target = GL_TEXTURE_1D; + bind_index_tex1d(index, 0); break; case TEXTURE_2D: - target = GL_TEXTURE_2D; + bind_index_tex2d(index, 0); break; case TEXTURE_3D: - target = GL_TEXTURE_3D; + bind_index_tex3d(index, 0); break; case TEXTURE_CUBE: - target = GL_TEXTURE_CUBE_MAP; + bind_index_texcube(index, 0); break; } - - if (target) { - glActiveTexture(GL_TEXTURE0 + index); - glBindTexture(target, 0); - } } void texture_update(texture* tex) { + if (!tex) + return; + switch (tex->type) { case TEXTURE_1D: texture_1d_update(tex); @@ -206,32 +225,300 @@ void texture_update(texture* tex) { } void texture_free(texture* tex) { + if (!tex) + return; + if (tex->id) glDeleteTextures(1, &tex->id); tex->id = 0; } void texture_set_load(texture_set* tex, texture_set_data* data) { - for (int32_t i = 0; i < 8; i++) - texture_load(&tex->tex[i], data->tex[i]); + if (!tex) + return; + + if (data) + for (int32_t i = 0; i < 8; i++) + texture_load(&tex->tex[i], data->tex[i]); + else + for (int32_t i = 0; i < 8; i++) + texture_load(&tex->tex[i], 0); } void texture_set_bind(texture_set* tex) { + if (!tex) + return; + for (int32_t i = 0; i < 8; i++) texture_bind(&tex->tex[i], i); } void texture_set_reset(texture_set* tex) { + if (!tex) + return; + for (int32_t i = 0; i < 8; i++) texture_reset(&tex->tex[i], i); } void texture_set_update(texture_set* tex) { + if (!tex) + return; + for (int32_t i = 0; i < 8; i++) texture_update(&tex->tex[i]); } void texture_set_free(texture_set* tex) { + if (!tex) + return; + for (int32_t i = 0; i < 8; i++) texture_free(&tex->tex[i]); } + +void texture_bone_mat_load(texture_bone_mat* tex, texture_bone_mat_data* data) { + if (!tex) + return; + + if (tex->id == 0) + glGenTextures(1, &tex->id); + + if (!data || !data->data || data->count < 1) + return; + + mat4* mat = data->data; + void* temp_data = force_malloc_s(mat4, data->count * 2LL); + mat4* d = temp_data; + for (int32_t i = 0; i < data->count; i++, mat++, d += 2) { + d[0] = *mat; + mat4_invtrans(mat, &d[1]); + } + + bind_tex2d(tex->id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, sizeof(mat4) / sizeof(vec4) * 2, + data->count, 0, GL_RGBA, GL_FLOAT, temp_data); + bind_tex2d(0); + free(temp_data); +} + +void texture_bone_mat_bind(texture_bone_mat* tex, int32_t index) { + if (!tex) + return; + + bind_index_tex2d(index, tex->id); +} + +void texture_bone_mat_reset(texture_bone_mat* tex, int32_t index) { + if (!tex) + return; + + bind_index_tex2d(index, tex->id); +} + +void texture_bone_mat_free(texture_bone_mat* tex) { + if (!tex) + return; + + if (tex->id) + glDeleteTextures(1, &tex->id); + tex->id = 0; +} + +bool texture_txp_load(vector_txp* tex, vector_int32_t* textures) { + static const GLenum target_cubemap_array[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + }; + + if (!tex || !textures) + return false; + + size_t count = tex->end - tex->begin; + if (count < 1) + return false; + + if (textures->end - textures->begin != 0) + texture_txp_unload(textures); + + vector_int32_t_append(textures, count); + for (uint32_t i = 0; i < count; i++) + vector_int32_t_push_back(textures, &i); + glGenTextures((GLsizei)count, textures->begin); + + txp* tex_data = tex->begin; + for (size_t i = 0; i < count; i++, tex_data++) + if ((tex_data->has_cubemap && tex_data->array_size == 6) || tex_data->array_size == 1) { + GLenum target = tex_data->has_cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + uint32_t mipmaps_count = tex_data->mipmaps_count; + if (tex_data->has_cubemap) + bind_texcube(textures->begin[i]); + else + bind_tex2d(textures->begin[i]); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, (float_t*)&vec4_null); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, + mipmaps_count > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, mipmaps_count - 1); + glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY, tex_data->has_cubemap ? 1.0f : 16.0f); + txp_mipmap* tex_mipmap = tex_data->data.begin; + if (tex_data->has_cubemap) + for (uint32_t j = 0; j < 6; j++, tex_data++) { + uint32_t width = tex_mipmap->width; + uint32_t height = tex_mipmap->height; + txp_format format = tex_mipmap->format; + for (uint32_t k = 0; k < mipmaps_count; k++, tex_mipmap++) + load_texture_data(target_cubemap_array[j], format, + max(width >> k, 1), max(height >> k, 1), k, tex_mipmap->data); + } + else { + uint32_t width = tex_mipmap->width; + uint32_t height = tex_mipmap->height; + txp_format format = tex_mipmap->format; + for (uint32_t k = 0; k < mipmaps_count; k++, tex_mipmap++) + load_texture_data(target, format, + max(width >> k, 1), max(height >> k, 1), k, tex_mipmap->data); + } + glBindTexture(target, 0); + } + bind_tex2d(0); + bind_texcube(0); + return true; +} + +void texture_txp_unload(vector_int32_t* textures) { + if (!textures) + return; + + if (textures->end - textures->begin != 0) + glDeleteTextures((GLsizei)(textures->end - textures->begin), textures->begin); + vector_int32_t_free(textures); +} + +static void load_texture_data(GLenum target, txp_format format, + uint32_t width, uint32_t height, uint32_t level, void* data) { + static const GLint textureswizzles_a8 [] = { GL_ZERO, GL_ZERO , GL_ZERO, GL_RED }; + static const GLint textureswizzles_ati1[] = { GL_RED , GL_RED , GL_RED , GL_ONE }; + static const GLint textureswizzles_ati2[] = { GL_RED , GL_GREEN, GL_ZERO, GL_RED }; + static const GLint textureswizzles_l8 [] = { GL_RED , GL_RED , GL_RED , GL_ONE }; + static const GLint textureswizzles_l8a8[] = { GL_RED , GL_RED , GL_RED , GL_GREEN }; + + static const GLint* textureswizzles[] = { + [TXP_A8] = textureswizzles_a8, + [TXP_RGB8] = 0, + [TXP_RGBA8] = 0, + [TXP_RGB5] = 0, + [TXP_RGB5A1] = 0, + [TXP_RGBA4] = 0, + [TXP_DXT1] = 0, + [TXP_DXT1a] = 0, + [TXP_DXT3] = 0, + [TXP_DXT5] = 0, + [TXP_ATI1] = textureswizzles_ati1, + [TXP_ATI2] = textureswizzles_ati2, + [TXP_L8] = textureswizzles_l8, + [TXP_L8A8] = textureswizzles_l8a8, + }; + + static const GLenum types[] = { + [TXP_A8] = GL_UNSIGNED_BYTE, + [TXP_RGB8] = GL_UNSIGNED_BYTE, + [TXP_RGBA8] = GL_UNSIGNED_BYTE, + [TXP_RGB5] = GL_UNSIGNED_SHORT_5_6_5_REV, + [TXP_RGB5A1] = GL_UNSIGNED_SHORT_1_5_5_5_REV, + [TXP_RGBA4] = GL_UNSIGNED_SHORT_4_4_4_4_REV, + [TXP_DXT1] = 0, + [TXP_DXT1a] = 0, + [TXP_DXT3] = 0, + [TXP_DXT5] = 0, + [TXP_ATI1] = 0, + [TXP_ATI2] = 0, + [TXP_L8] = GL_UNSIGNED_BYTE, + [TXP_L8A8] = GL_UNSIGNED_BYTE, + }; + + static const GLenum formats[] = { + [TXP_A8] = GL_RED, + [TXP_RGB8] = GL_RGB, + [TXP_RGBA8] = GL_RGBA, + [TXP_RGB5] = GL_RGB, + [TXP_RGB5A1] = GL_RGBA, + [TXP_RGBA4] = GL_RGBA, + [TXP_DXT1] = 0, + [TXP_DXT1a] = 0, + [TXP_DXT3] = 0, + [TXP_DXT5] = 0, + [TXP_ATI1] = 0, + [TXP_ATI2] = 0, + [TXP_L8] = GL_RED, + [TXP_L8A8] = GL_RG, + }; + + static const GLenum internalformats[] = { + [TXP_A8] = GL_R8, + [TXP_RGB8] = GL_RGB8, + [TXP_RGBA8] = GL_RGBA8, + [TXP_RGB5] = GL_RGB5, + [TXP_RGB5A1] = GL_RGB5_A1, + [TXP_RGBA4] = GL_RGBA4, + [TXP_DXT1] = GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + [TXP_DXT1a] = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, + [TXP_DXT3] = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, + [TXP_DXT5] = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, + [TXP_ATI1] = GL_COMPRESSED_RED_RGTC1_EXT, + [TXP_ATI2] = GL_COMPRESSED_RED_GREEN_RGTC2_EXT, + [TXP_L8] = GL_R8, + [TXP_L8A8] = GL_RG8, + }; + + switch (format) { + case TXP_A8: + case TXP_L8: + case TXP_L8A8: + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, textureswizzles[format]); + glTexImage2D(target, level, internalformats[format], + width, height, 0, formats[format], types[format], data); + break; + case TXP_RGB8: + case TXP_RGBA8: + case TXP_RGB5: + case TXP_RGB5A1: + case TXP_RGBA4: + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(target, level, internalformats[format], + width, height, 0, formats[format], types[format], data); + break; + case TXP_DXT1: + case TXP_DXT1a: + case TXP_DXT3: + case TXP_DXT5: { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + uint32_t size = txp_get_size(format, width, height); + glCompressedTexImage2D(target, level, internalformats[format], + width, height, 0, size, data); + } break; + case TXP_ATI1: + case TXP_ATI2: { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, textureswizzles[format]); + uint32_t size = txp_get_size(format, width, height); + glCompressedTexImage2D(target, level, internalformats[format], + width, height, 0, size, data); + } break; + } +} \ No newline at end of file diff --git a/src/CRE/texture.h b/src/CRE/texture.h index 31348d5f..6f12a625 100644 --- a/src/CRE/texture.h +++ b/src/CRE/texture.h @@ -6,6 +6,7 @@ #pragma once #include "../KKdLib/default.h" +#include "../KKdLib/txp.h" #define GLEW_STATIC #include @@ -17,6 +18,16 @@ typedef enum texture_type { TEXTURE_CUBE, } texture_type; +typedef enum texture_mode { + TEXTURE_MODE_DEFAULT = 0, + TEXTURE_MODE_YCBCR_BC4 = 1, + TEXTURE_MODE_YCBCR_BC5 = 2, + TEXTURE_MODE_NORMAL_BC5U = 3, + TEXTURE_MODE_NORMAL_BC5S = 4, + TEXTURE_MODE_NORMAL_U = 5, + TEXTURE_MODE_NORMAL_S = 6, +} texture_mode; + typedef struct texture_data { texture_type type; int32_t width; @@ -60,6 +71,7 @@ typedef struct texture_cube_data { typedef struct texture { int32_t id; + texture_mode mode; texture_type type; } texture; @@ -91,6 +103,15 @@ typedef union texture_set { texture tex[8]; } texture_set; +typedef struct texture_bone_mat_data { + int32_t count; + void* data; +} texture_bone_mat_data; + +typedef struct texture_bone_mat { + int32_t id; +} texture_bone_mat; + extern void texture_load(texture* tex, texture_data* data); extern void texture_bind(texture* tex, int32_t index); extern void texture_reset(texture* tex, int32_t index); @@ -101,3 +122,9 @@ extern void texture_set_bind(texture_set* tex); extern void texture_set_reset(texture_set* tex); extern void texture_set_update(texture_set* tex); extern void texture_set_free(texture_set* tex); +extern void texture_bone_mat_load(texture_bone_mat* tex, texture_bone_mat_data* data); +extern void texture_bone_mat_bind(texture_bone_mat* tex, int32_t index); +extern void texture_bone_mat_reset(texture_bone_mat* tex, int32_t index); +extern void texture_bone_mat_free(texture_bone_mat* tex); +extern bool texture_txp_load(vector_txp* tex, vector_int32_t* textures); +extern void texture_txp_unload(vector_int32_t* textures); diff --git a/src/CRE/timer.h b/src/CRE/timer.h index 72541666..6d0f0ad1 100644 --- a/src/CRE/timer.h +++ b/src/CRE/timer.h @@ -6,6 +6,7 @@ #pragma once #include "../KKdLib/default.h" +#include "lock.h" extern LARGE_INTEGER performance_frequency; @@ -16,7 +17,7 @@ double_t name##_history[HISTORY_COUNT]; \ uint8_t name##_history_counter; \ LARGE_INTEGER name##_curr_time, name##_prev_time; \ double_t name##_freq = 0.0; \ -HANDLE name##_freq_lock = 0; \ +lock_val(name##_freq_lock); \ HANDLE name##_timer #define timer_init(name, mutex_name) \ @@ -25,35 +26,31 @@ name##_history_counter = 0; \ name##_curr_time.QuadPart = 0; \ name##_prev_time.QuadPart = 0; \ name##_freq = 0; \ -name##_freq_lock = CreateMutexW(0, false, L##mutex_name##L" Freq"); \ +lock_init(name##_freq_lock); \ name##_timer = create_timer() #define timer_calc_pre(name) \ -if (name##_freq_lock) { \ - WaitForSingleObject(name##_freq_lock, INFINITE); \ - double_t time = timer_get_msec(name##_prev_time); \ - QueryPerformanceCounter(&name##_prev_time); \ - double_t freq = 0; \ - for (uint8_t i = 0; i < name##_history_counter; i++) \ - freq += name##_history[i]; \ - freq += name##_history[name##_history_counter] = 1000.0 / time; \ - for (uint8_t i = name##_history_counter + 1; i < HISTORY_COUNT; i++) \ - freq += name##_history[i]; \ - name##_freq = freq / HISTORY_COUNT; \ - name##_history_counter++; \ - if (name##_history_counter >= HISTORY_COUNT) \ - name##_history_counter = 0; \ - ReleaseMutex(name##_freq_lock); \ -} +lock_lock(name##_freq_lock); \ +double_t time = timer_get_msec(name##_prev_time); \ +QueryPerformanceCounter(&name##_prev_time); \ +double_t freq = 0; \ +for (uint8_t i = 0; i < name##_history_counter; i++) \ + freq += name##_history[i]; \ +freq += name##_history[name##_history_counter] = 1000.0 / time; \ +for (uint8_t i = name##_history_counter + 1; i < HISTORY_COUNT; i++) \ + freq += name##_history[i]; \ +name##_freq = freq / HISTORY_COUNT; \ +name##_history_counter++; \ +if (name##_history_counter >= HISTORY_COUNT) \ + name##_history_counter = 0; \ +lock_unlock(name##_freq_lock); #define timer_calc_post(name) \ timer_get_msec(name##_prev_time) #define timer_dispose(name) \ -if (name##_freq_lock) \ - CloseHandle(name##_freq_lock); \ -dispose_timer(name##_timer); \ -name##_freq_lock = 0 +lock_dispose(name##_freq_lock); \ +dispose_timer(name##_timer) extern double_t timer_get_msec(LARGE_INTEGER t); extern HANDLE create_timer(); diff --git a/src/CRE/vertex.c b/src/CRE/vertex.c index 808d523d..23b1b4e2 100644 --- a/src/CRE/vertex.c +++ b/src/CRE/vertex.c @@ -5,20 +5,23 @@ #include "vertex.h" #include "../KKdLib/half_t.h" -#include "../KKdLib/vec.h" +#include "../KKdLib/hash.h" #include "../KKdLib/vector.h" -typedef struct vertex_data { +#pragma pack(push, 1) +typedef struct vertex_pre_data { vec3 pos; - vec2 uv[2]; + vec2 uv; + vec2 uv2; vec4 color; vec3 normal; vec3 tangent; - uint16_t bone_index[4]; - float_t bone_weight[4]; -} vertex_data; + vec4i bone_index; + vec4 bone_weight; +} vertex_pre_data; +#pragma pack(pop) -vector(vertex_data) +vector(vertex_pre_data) vertex* vertex_init() { vertex* v = force_malloc(sizeof(vertex)); @@ -38,6 +41,8 @@ void vertex_load(vertex* v, vertex_update* upd) { if (!upd->data || !upd->length) return; + bool use_bone_data = false; + bool translucent = false; float_t* data = upd->data; size_t length = upd->length; bool uv = upd->uv; @@ -47,21 +52,27 @@ void vertex_load(vertex* v, vertex_update* upd) { bool bones = upd->bones; size_t len = 3LL + (uv ? (2LL + (uv2 ? 2 : 0)) : 0) + (color ? 4 : 0) + (normal ? 3 : 0) + (bones ? 8 : 0); length /= len; - vertex_data* verts = force_malloc_s(sizeof(vertex_data), length); + vertex_pre_data* verts = force_malloc_s(vertex_pre_data, length); if (bones) { for (size_t i = 0; i < length; i++) { - vertex_data* v = &verts[i]; + vertex_pre_data* v = &verts[i]; v->pos.x = *data++; v->pos.y = *data++; v->pos.z = *data++; if (uv) { - v->uv[0].x = *data++; - v->uv[0].y = *data++; + v->uv.x = *data++; + v->uv.y = *data++; if (uv2) { - v->uv[1].x = *data++; - v->uv[1].y = *data++; + v->uv2.x = *data++; + v->uv2.y = *data++; } + else + v->uv2 = vec2_null; + } + else { + v->uv = vec2_null; + v->uv2 = vec2_null; } if (color) { @@ -69,6 +80,8 @@ void vertex_load(vertex* v, vertex_update* upd) { v->color.y = *data++; v->color.z = *data++; v->color.w = *data++; + if (v->color.w < 1.0f) + translucent = true; } else v->color = vec4_identity; @@ -79,28 +92,51 @@ void vertex_load(vertex* v, vertex_update* upd) { v->normal.z = *data++; vec3_normalize(v->normal, v->normal); } + else + v->normal = vec3_null; - for (int32_t j = 0; j < 4; j++) - v->bone_index[j] = (uint16_t)*data++; + v->tangent = vec3_null; - for (int32_t j = 0; j < 4; j++) - v->bone_weight[j] = *data++; + v->bone_index.x = (int32_t)*data++; + v->bone_index.y = (int32_t)*data++; + v->bone_index.z = (int32_t)*data++; + v->bone_index.w = (int32_t)*data++; + + vec4 bone_weight; + bone_weight.x = *data++; + bone_weight.y = *data++; + bone_weight.z = *data++; + bone_weight.w = *data++; + vec4_normalize(bone_weight, bone_weight); + + float_t bone_weight_length; + vec4_length_squared(bone_weight, bone_weight_length); + if (bone_weight_length != 0.0f) + use_bone_data = true; + + v->bone_weight = bone_weight; } } else { for (size_t i = 0; i < length; i++) { - vertex_data* v = &verts[i]; + vertex_pre_data* v = &verts[i]; v->pos.x = *data++; v->pos.y = *data++; v->pos.z = *data++; if (uv) { - v->uv[0].x = *data++; - v->uv[0].y = *data++; + v->uv.x = *data++; + v->uv.y = *data++; if (uv2) { - v->uv[1].x = *data++; - v->uv[1].y = *data++; + v->uv2.x = *data++; + v->uv2.y = *data++; } + else + v->uv2 = vec2_null; + } + else { + v->uv = vec2_null; + v->uv2 = vec2_null; } if (color) { @@ -108,6 +144,8 @@ void vertex_load(vertex* v, vertex_update* upd) { v->color.y = *data++; v->color.z = *data++; v->color.w = *data++; + if (v->color.w < 1.0f) + translucent = true; } else v->color = vec4_identity; @@ -118,138 +156,160 @@ void vertex_load(vertex* v, vertex_update* upd) { v->normal.z = *data++; vec3_normalize(v->normal, v->normal); } + else + v->normal = vec3_null; + + v->tangent = vec3_null; + v->bone_index = vec4i_null; + v->bone_weight = vec4_null; } } + v->translucent = translucent; v->ind_count = length; - v->ind = force_malloc_s(sizeof(uint32_t), v->ind_count); + v->ind = force_malloc_s(uint32_t, v->ind_count); + + vector_vertex_pre_data vert_list = { 0, 0, 0 }; + vector_vertex_pre_data_append(&vert_list, length); + for (size_t i = 0; i < length; i++) { + vertex_pre_data* vert = &verts[i]; - vector_vertex_data vert_list; - vert_list.begin = vert_list.end = vert_list.capacity_end = 0; - for (size_t i = 0, j = 0; i < length; i++) { bool found = false; - size_t count = vert_list.end - vert_list.begin; - for (j = 0; j < count; i++) - if (!memcmp(&vert_list.begin[j], &verts[i], sizeof(vertex_data))) { + vertex_pre_data* j = vert_list.begin; + uint32_t k = 0; + for (; j != vert_list.end; j++, k++) + if (!memcmp(j, vert, sizeof(vertex_pre_data))) { found = true; break; } if (!found) - vector_vertex_data_push_back(&vert_list, &verts[i]); - v->ind[i] = (uint32_t)j; + vector_vertex_pre_data_push_back(&vert_list, vert); + v->ind[i] = k; } - vector_size_t r; - vec3 edge0, edge1, t; - vec2 uv0, uv1; - r.begin = r.end = r.capacity_end = 0; - for (vertex_data* i = vert_list.begin; i != vert_list.end; i++) { - vec3 p = i->pos; - vec3 n = i->normal; - vec3 pos, normal; - for (size_t j = 0; j < length; j++) { - pos = verts[j].pos; - normal = verts[j].normal; - if (p.x == pos.x && p.y == pos.y && p.z == pos.z - && n.x == normal.x && n.y == normal.y && n.z == normal.z) - vector_size_t_push_back(&r, &j); - } - - if (r.end - r.begin < 1) { - vector_size_t_clear(&r); - continue; - } - - t = vec3_null; - for (size_t* j = r.begin; j != r.end; j++) { - vec3 t0, t1; - vertex_data* v1 = &verts[*j / 3 * 3 + 0]; - vertex_data* v2 = &verts[*j / 3 * 3 + 1]; - vertex_data* v3 = &verts[*j / 3 * 3 + 2]; - vec2_sub(v2->uv[0], v1->uv[0], uv0); - vec2_sub(v3->uv[0], v1->uv[0], uv1); - if (uv0.x * uv1.y - uv1.x * uv0.y != 0) { - vec3_sub(v2->pos, v1->pos, edge0); - vec3_sub(v3->pos, v1->pos, edge1); - vec3_mult_scalar(edge0, uv1.y, t0); - vec3_mult_scalar(edge1, uv0.y, t1); - vec3_sub(t0, t1, t1); - vec3_mult_scalar(t1, 1.0f / (uv0.x * uv1.y - uv1.x * uv0.y), t1); - vec3_normalize(t1, t1); - vec3_add(t, t1, t); + if (normal) { + vec3 edge0, edge1, t; + vec2 uv0, uv1; + vector_size_t r = { 0, 0, 0 }; + vector_size_t_append(&r, length); + for (vertex_pre_data* i = vert_list.begin; i != vert_list.end; i++) { + vec3 p = i->pos; + vec3 n = i->normal; + for (size_t j = 0; j < length; j++) { + vec3 pos = verts[j].pos; + vec3 normal = verts[j].normal; + if (p.x == pos.x && p.y == pos.y && p.z == pos.z + && n.x == normal.x && n.y == normal.y && n.z == normal.z) + vector_size_t_push_back(&r, &j); } + + if (r.end - r.begin < 1) { + vector_size_t_clear(&r); + continue; + } + + t = vec3_null; + for (size_t* j = r.begin; j != r.end; j++) { + vec3 t0, t1; + vertex_pre_data* v1 = &verts[*j / 3 * 3 + 0]; + vertex_pre_data* v2 = &verts[*j / 3 * 3 + 1]; + vertex_pre_data* v3 = &verts[*j / 3 * 3 + 2]; + vec2_sub(v2->uv, v1->uv, uv0); + vec2_sub(v3->uv, v1->uv, uv1); + if (uv0.x * uv1.y - uv1.x * uv0.y != 0) { + vec3_sub(v2->pos, v1->pos, edge0); + vec3_sub(v3->pos, v1->pos, edge1); + vec3_mult_scalar(edge0, uv1.y, t0); + vec3_mult_scalar(edge1, uv0.y, t1); + vec3_sub(t0, t1, t1); + vec3_mult_scalar(t1, 1.0f / (uv0.x * uv1.y - uv1.x * uv0.y), t1); + vec3_normalize(t1, t1); + vec3_add(t, t1, t); + } + } + vec3_mult_scalar(t, 1.0f / (float_t)(r.end - r.begin), t); + vec3_normalize(t, i->tangent); + vector_size_t_clear(&r); } - vector_size_t_clear(&r); - vec3_mult_scalar(t, 1.0f / (float_t)(r.end - r.begin), t); - vec3_normalize(t, i->tangent); + vector_size_t_free(&r); } - free(r.begin); + free(verts); v->vert_count = vert_list.end - vert_list.begin; - if (bones) { + if (use_bone_data) v->type = VERTEX_BONED; - v->vert = force_malloc_s(56, v->vert_count); - uint64_t vert_ptr = (uint64_t)v->vert; - for (size_t i = 0; i < v->vert_count; i++) { - vertex_data* vert = &vert_list.begin[i]; - *(float_t*)(vert_ptr + 0) = vert->pos.x; - *(float_t*)(vert_ptr + 4) = vert->pos.y; - *(float_t*)(vert_ptr + 8) = vert->pos.z; - *(half_t*)(vert_ptr + 12) = float_to_half(vert->uv[0].x); - *(half_t*)(vert_ptr + 14) = float_to_half(vert->uv[0].y); - *(half_t*)(vert_ptr + 16) = float_to_half(vert->uv[1].x); - *(half_t*)(vert_ptr + 18) = float_to_half(vert->uv[1].y); - *(half_t*)(vert_ptr + 20) = float_to_half(vert->color.x); - *(half_t*)(vert_ptr + 22) = float_to_half(vert->color.y); - *(half_t*)(vert_ptr + 24) = float_to_half(vert->color.z); - *(half_t*)(vert_ptr + 26) = float_to_half(vert->color.w); - *(half_t*)(vert_ptr + 28) = float_to_half(vert->normal.x); - *(half_t*)(vert_ptr + 30) = float_to_half(vert->normal.y); - *(half_t*)(vert_ptr + 32) = float_to_half(vert->normal.z); - *(half_t*)(vert_ptr + 34) = float_to_half(vert->tangent.x); - *(half_t*)(vert_ptr + 36) = float_to_half(vert->tangent.y); - *(half_t*)(vert_ptr + 38) = float_to_half(vert->tangent.z); - *(uint16_t*)(vert_ptr + 40) = vert->bone_index[0]; - *(uint16_t*)(vert_ptr + 42) = vert->bone_index[1]; - *(uint16_t*)(vert_ptr + 44) = vert->bone_index[2]; - *(uint16_t*)(vert_ptr + 46) = vert->bone_index[3]; - *(half_t*)(vert_ptr + 48) = float_to_half(vert->bone_weight[0]); - *(half_t*)(vert_ptr + 50) = float_to_half(vert->bone_weight[1]); - *(half_t*)(vert_ptr + 52) = float_to_half(vert->bone_weight[2]); - *(half_t*)(vert_ptr + 54) = float_to_half(vert->bone_weight[3]); - vert_ptr += 56; - } - } - else { + else v->type = VERTEX_SIMPLE; - v->vert = force_malloc_s(40, v->vert_count); - uint64_t vert_ptr = (uint64_t)v->vert; - for (size_t i = 0; i < v->vert_count; i++) { - vertex_data* vert = &vert_list.begin[i]; - *(float_t*)(vert_ptr + 0) = vert->pos.x; - *(float_t*)(vert_ptr + 4) = vert->pos.y; - *(float_t*)(vert_ptr + 8) = vert->pos.z; - *(half_t*)(vert_ptr + 12) = float_to_half(vert->uv[0].x); - *(half_t*)(vert_ptr + 14) = float_to_half(vert->uv[0].y); - *(half_t*)(vert_ptr + 16) = float_to_half(vert->uv[1].x); - *(half_t*)(vert_ptr + 18) = float_to_half(vert->uv[1].y); - *(half_t*)(vert_ptr + 20) = float_to_half(vert->color.x); - *(half_t*)(vert_ptr + 22) = float_to_half(vert->color.y); - *(half_t*)(vert_ptr + 24) = float_to_half(vert->color.z); - *(half_t*)(vert_ptr + 26) = float_to_half(vert->color.w); - *(half_t*)(vert_ptr + 28) = float_to_half(vert->normal.x); - *(half_t*)(vert_ptr + 30) = float_to_half(vert->normal.y); - *(half_t*)(vert_ptr + 32) = float_to_half(vert->normal.z); - *(half_t*)(vert_ptr + 34) = float_to_half(vert->tangent.x); - *(half_t*)(vert_ptr + 36) = float_to_half(vert->tangent.y); - *(half_t*)(vert_ptr + 38) = float_to_half(vert->tangent.z); - vert_ptr += 40; - } + + v->vert = force_malloc_s(vertex_data, v->vert_count); + if (!v->vert) { + vector_vertex_pre_data_free(&vert_list); + vertex_bounding_box bound_box; + bound_box.min = vec3_null; + bound_box.max = vec3_null; + v->bound_box = bound_box; + return; } - free(vert_list.begin); - free(verts); + vec3 bound_box_min = (vec3){ FLT_MAX, FLT_MAX, FLT_MAX }; + vec3 bound_box_max = (vec3){ -FLT_MAX, -FLT_MAX, -FLT_MAX }; + + vertex_data* vert_ptr = v->vert; + for (vertex_pre_data* i = vert_list.begin; i != vert_list.end; i++) { + vec3 pos; + vec2 uv; + vec2 uv2; + vec4 color; + vec3 normal; + vec3 tangent; + vec4i bone_index; + vec4 bone_weight; + + pos = i->pos; + uv = i->uv; + uv2 = i->uv2; + color = i->color; + normal = i->normal; + tangent = i->tangent; + bone_index = i->bone_index; + bone_weight = i->bone_weight; + + vec3_min(bound_box_min, pos, bound_box_min); + vec3_max(bound_box_max, pos, bound_box_max); + + vec3_mult_min_max_scalar(normal, -32768.0f, 32767.0f, normal); + vec3_mult_min_max_scalar(tangent, -32768.0f, 32767.0f, tangent); + vec4_mult_scalar(bone_weight, 255.0f, bone_weight); + + vert_ptr->pos = pos; + vert_ptr->uv.x = float_to_half(uv.x); + vert_ptr->uv.y = float_to_half(uv.y); + vert_ptr->uv2.x = float_to_half(uv2.x); + vert_ptr->uv2.y = float_to_half(uv2.y); + vert_ptr->color.r = float_to_half(color.x); + vert_ptr->color.g = float_to_half(color.y); + vert_ptr->color.b = float_to_half(color.z); + vert_ptr->color.a = float_to_half(color.w); + vert_ptr->normal.x = (int16_t)normal.x; + vert_ptr->normal.y = (int16_t)normal.y; + vert_ptr->normal.z = (int16_t)normal.z; + vert_ptr->tangent.x = (int16_t)tangent.x; + vert_ptr->tangent.y = (int16_t)tangent.y; + vert_ptr->tangent.z = (int16_t)tangent.z; + vert_ptr->bone_index.x = (uint16_t)bone_index.x; + vert_ptr->bone_index.y = (uint16_t)bone_index.y; + vert_ptr->bone_index.z = (uint16_t)bone_index.z; + vert_ptr->bone_index.w = (uint16_t)bone_index.w; + vert_ptr->bone_weight.x = (uint8_t)bone_weight.x; + vert_ptr->bone_weight.y = (uint8_t)bone_weight.y; + vert_ptr->bone_weight.z = (uint8_t)bone_weight.z; + vert_ptr->bone_weight.w = (uint8_t)bone_weight.w; + vert_ptr++; + } + vector_vertex_pre_data_free(&vert_list); + v->bound_box.min = bound_box_min; + v->bound_box.max = bound_box_max; } void vertex_dispose(vertex* v) { @@ -261,4 +321,4 @@ void vertex_dispose(vertex* v) { free(v); } -vector_func(vertex_data) +vector_func(vertex_pre_data) diff --git a/src/CRE/vertex.h b/src/CRE/vertex.h index c9b31e30..f01efec6 100644 --- a/src/CRE/vertex.h +++ b/src/CRE/vertex.h @@ -6,6 +6,7 @@ #pragma once #include "../KKdLib/default.h" +#include "../KKdLib/vec.h" typedef enum vertex_type { VERTEX_NONE = 0, @@ -13,12 +14,61 @@ typedef enum vertex_type { VERTEX_BONED, } vertex_type; +typedef struct vertex_bounding_box { + vec3 min; + vec3 max; +}vertex_bounding_box; + +#pragma pack(push, 1) +typedef struct vertex_data { + vec3 pos; + struct { + half_t x; + half_t y; + } uv; + struct { + half_t x; + half_t y; + } uv2; + struct { + half_t r; + half_t g; + half_t b; + half_t a; + } color; + struct { + half_t x; + half_t y; + half_t z; + } normal; + struct { + half_t x; + half_t y; + half_t z; + } tangent; + struct { + half_t x; + half_t y; + half_t z; + half_t w; + } bone_index; + struct { + half_t x; + half_t y; + half_t z; + half_t w; + } bone_weight; +} vertex_data; +#pragma pack(pop) + typedef struct vertex { vertex_type type; - void* vert; + bool translucent; + vertex_data* vert; size_t vert_count; uint32_t* ind; size_t ind_count; + vertex_bounding_box bound_box; } vertex; typedef struct vertex_update { diff --git a/src/KKdLib/a3dai.c b/src/KKdLib/a3dai.c index df7ab526..788fad4d 100644 --- a/src/KKdLib/a3dai.c +++ b/src/KKdLib/a3dai.c @@ -4,6 +4,9 @@ */ #include "a3dai.h" +#include "interpolation.h" + +static void a3dai_interpolate(a3dai* interp); a3dai* a3da_key_to_a3dai(auth_3d_key* key, float_t interpolation_framerate, float_t requested_framerate) { if (!key) @@ -66,102 +69,25 @@ a3dai* a3da_head_to_a3dai(auth_3d_struct* s, float_t interpolation_framerate, fl return interp; } -FORCE_INLINE void a3dai_set_interpolation_framerate(a3dai* interp, float_t interpolation_framerate) { +inline void a3dai_set_interpolation_framerate(a3dai* interp, float_t interpolation_framerate) { interp->interpolation_framerate = interpolation_framerate; interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; } -FORCE_INLINE void a3dai_set_requested_framerate(a3dai* interp, float_t requested_framerate) { +inline void a3dai_set_requested_framerate(a3dai* interp, float_t requested_framerate) { interp->requested_framerate = requested_framerate; interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; } -FORCE_INLINE void a3dai_update(a3dai* interp) { +inline void a3dai_update(a3dai* interp) { interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; } -FORCE_INLINE void a3dai_reset(a3dai* interp) { +inline void a3dai_reset(a3dai* interp) { interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; interp->frame = -interp->delta_frame; interp->time = interp->frame / interp->requested_framerate; } -static void a3dai_interpolate(a3dai* interp) { - float_t delta_frame, offset = 0.0f; - float_t frame = interp->frame; - - kft3 first_key = *interp->first_key; - kft3 last_key = *interp->last_key; - if (frame <= first_key.frame) { - delta_frame = first_key.frame - frame; - switch (interp->auth_3d->ep_type_pre) { - case AUTH_3D_EP_TYPE_LINEAR: - interp->value = first_key.value - delta_frame * first_key.tangent2; - return; - case AUTH_3D_EP_TYPE_CYCLE: - frame = last_key.frame - fmodf(delta_frame, interp->auth_3d->frame_delta); - break; - case AUTH_3D_EP_TYPE_CYCLE_OFFSET: - frame = last_key.frame - fmodf(delta_frame, interp->auth_3d->frame_delta); - offset = -(float_t)((int32_t)(delta_frame / interp->auth_3d->frame_delta) + 1) * interp->auth_3d->value_delta; - break; - default: - interp->value = first_key.value; - return; - } - } - else if (frame >= last_key.frame) { - delta_frame = frame - last_key.frame; - switch (interp->auth_3d->ep_type_post) { - case AUTH_3D_EP_TYPE_LINEAR: - interp->value = last_key.value + delta_frame * last_key.tangent1; - return; - case AUTH_3D_EP_TYPE_CYCLE: - frame = first_key.frame + fmodf(delta_frame, interp->auth_3d->frame_delta); - break; - case AUTH_3D_EP_TYPE_CYCLE_OFFSET: - frame = first_key.frame + fmodf(delta_frame, interp->auth_3d->frame_delta); - offset = (float_t)((int32_t)(delta_frame / interp->auth_3d->frame_delta) + 1) * interp->auth_3d->value_delta; - break; - default: - interp->value = last_key.value; - return; - } - } - - auth_3d_key_type type = interp->auth_3d->type; - kft3* keys = interp->auth_3d->keys; - size_t key = 0; - size_t length = interp->auth_3d->length; - size_t temp; - while (length > 0) - if (frame > keys[key + (temp = length >> 1)].frame) { - key += temp + 1; - length -= temp + 1; - } - else - length = temp; - - kft3 c, n; - c = keys[key - 1]; - n = keys[key]; - - if (frame <= c.frame || frame > n.frame) - interp->value = frame > c.frame ? n.value : c.value; - else if (type == AUTH_3D_KEY_TYPE_LINEAR) { - float_t t = (frame - c.frame) / (n.frame - c.frame); - interp->value = (1.0f - t) * c.value + t * n.value; - } - else if (type == AUTH_3D_KEY_TYPE_HERMITE) { - float_t t = (frame - c.frame) / (n.frame - c.frame); - float_t t_2 = (1.0f - t) * (1.0f - t); - interp->value = t_2 * c.value * (1.0f + 2.0f * t) + (t * n.value * (3.0f - 2.0f * t) + - (t_2 * c.tangent2 + t * (t - 1.0f) * n.tangent1) * (n.frame - c.frame)) * t; - } - else - interp->value = c.value; - interp->value += offset; -} - float_t a3dai_set_time(a3dai* interp, float_t time) { if (!interp || !interp->auth_3d || !interp->auth_3d->keys || !interp->auth_3d->length) return 0.0f; @@ -253,3 +179,79 @@ float_t a3dai_next_frame(a3dai* interp) { } return interp->value; } + +static void a3dai_interpolate(a3dai* interp) { + float_t offset; + float_t frame = interp->frame; + + kft3 first_key = *interp->first_key; + kft3 last_key = *interp->last_key; + if (frame <= first_key.frame) { + float_t delta_frame = first_key.frame - frame; + switch (interp->auth_3d->ep_type_pre) { + case AUTH_3D_EP_TYPE_LINEAR: + interp->value = first_key.value - delta_frame * first_key.tangent2; + return; + case AUTH_3D_EP_TYPE_CYCLE: + frame = last_key.frame - fmodf(delta_frame, interp->auth_3d->frame_delta); + offset = 0.0f; + break; + case AUTH_3D_EP_TYPE_CYCLE_OFFSET: + frame = last_key.frame - fmodf(delta_frame, interp->auth_3d->frame_delta); + offset = -(float_t)((int32_t)(delta_frame / interp->auth_3d->frame_delta) + 1) * interp->auth_3d->value_delta; + break; + default: + interp->value = first_key.value; + return; + } + } + else if (frame >= last_key.frame) { + float_t delta_frame = frame - last_key.frame; + switch (interp->auth_3d->ep_type_post) { + case AUTH_3D_EP_TYPE_LINEAR: + interp->value = last_key.value + delta_frame * last_key.tangent1; + return; + case AUTH_3D_EP_TYPE_CYCLE: + frame = first_key.frame + fmodf(delta_frame, interp->auth_3d->frame_delta); + offset = 0.0f; + break; + case AUTH_3D_EP_TYPE_CYCLE_OFFSET: + frame = first_key.frame + fmodf(delta_frame, interp->auth_3d->frame_delta); + offset = (float_t)((int32_t)(delta_frame / interp->auth_3d->frame_delta) + 1) * interp->auth_3d->value_delta; + break; + default: + interp->value = last_key.value; + return; + } + } + else + offset = 0.0f; + + auth_3d_key_type type = interp->auth_3d->type; + kft3* keys = interp->auth_3d->keys; + size_t key = 0; + size_t length = interp->auth_3d->length; + size_t temp; + while (length > 0) + if (frame > keys[key + (temp = length >> 1)].frame) { + key += temp + 1; + length -= temp + 1; + } + else + length = temp; + + kft3 c, n; + c = keys[key - 1]; + n = keys[key]; + + if (frame <= c.frame || frame > n.frame) + interp->value = frame > c.frame ? n.value : c.value; + else if (type == AUTH_3D_KEY_TYPE_LINEAR) + interp->value = interpolate_linear_value(c.value, n.value, c.frame, n.frame, frame); + else if (type == AUTH_3D_KEY_TYPE_HERMITE) + interp->value = interpolate_chs_value(c.value, n.value, + c.tangent2, n.tangent1, c.frame, n.frame, frame); + else + interp->value = c.value; + interp->value += offset; +} diff --git a/src/KKdLib/add_param.c b/src/KKdLib/add_param.c deleted file mode 100644 index 61644e0f..00000000 --- a/src/KKdLib/add_param.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#include "add_param.h" -#include "f2_struct.h" -#include "io_path.h" -#include "io_stream.h" -#include "msgpack.h" -#include "io_json.h" -#include "io_msgpack.h" - -add_param* add_param_init() { - add_param* a = force_malloc(sizeof(add_param)); - return a; -} - -void add_param_dispose(add_param* a) { - if (!a) - return; - - free(a->data); - free(a); -} - -void add_param_read_adp(add_param* a, char* path) { - if (!a || !path) - return; - - wchar_t* path_buf = char_string_to_wchar_t_string(path); - add_param_wread_adp(a, path_buf); - free(path_buf); -} - -void add_param_wread_adp(add_param* a, wchar_t* path) { - if (!a || !path) - return; - - memset(a, 0, sizeof(add_param)); - wchar_t* path_adp = path_wadd_extension(path, L".adp"); - stream* s = io_wopen(path_adp, L"rb"); - if (s->io.stream) { - size_t count = io_read_uint64_t(s); - size_t data_length = io_read_uint64_t(s); - size_t data_offset = io_read_uint64_t(s); - a->length = count; - a->data = force_malloc_s(sizeof(add_param_struct), count); - io_read(s, a->data, sizeof(add_param_struct) * count); - a->ready = true; - } - io_dispose(s); - free(path_adp); -} - -void add_param_write_adp(add_param* a, char* path) { - if (!a || !path || !a->ready) - return; - - wchar_t* path_buf = char_string_to_wchar_t_string(path); - add_param_wwrite_adp(a, path_buf); - free(path_buf); -} - -void add_param_wwrite_adp(add_param* a, wchar_t* path) { - if (!a || !path || !a->ready) - return; - - wchar_t* path_adp = path_wadd_extension(path, L".adp"); - stream* s = io_wopen(path_adp, L"wb"); - if (s->io.stream) { - size_t count = a->length; - io_write_uint64_t(s, count); - io_write_uint64_t(s, count * 0x20); - io_write_uint64_t(s, 0x18); - io_write(s, a->data, sizeof(add_param_struct) * count); - } - io_dispose(s); - free(path_adp); -} - -void add_param_read_mp(add_param* a, char* path, bool json) { - if (!a || !path) - return; - - wchar_t* path_buf = char_string_to_wchar_t_string(path); - add_param_wread_mp(a, path_buf, json); - free(path_buf); -} - -void add_param_wread_mp(add_param* a, wchar_t* path, bool json) { - if (!a || !path) - return; - - memset(a, 0, sizeof(add_param)); - wchar_t* path_mp = path_wadd_extension(path, json ? L".json" : L".mp"); - stream* s = io_wopen(path_mp, L"rb"); - msgpack* msg; - if (json) - msg = io_json_read(s); - else - msg = io_msgpack_read(s); - - msgpack* add_param = msgpack_read(msg, L"AddParam"); - if (add_param && add_param->type == MSGPACK_ARRAY) { - msgpack_array* ptr = SELECT_MSGPACK(msgpack_array, add_param); - a->length = ptr->length; - a->data = force_malloc_s(sizeof(add_param_struct), a->length); - for (size_t i = 0; i < a->length; i++) { - if (ptr->data[i].type != MSGPACK_MAP) - continue; - - msgpack* m = &ptr->data[i]; - add_param_struct* adps = &a->data[i]; - adps->time = msgpack_read_float_t(m, L"Time"); - adps->flags = msgpack_read_int32_t(m, L"Flags"); - adps->frame = msgpack_read_int32_t(m, L"Frame"); - adps->pv_branch = msgpack_read_int32_t(m, L"PVBranch"); - adps->id = msgpack_read_int32_t(m, L"ID"); - adps->value = msgpack_read_int32_t(m, L"Value"); - } - a->ready = true; - } - msgpack_dispose(msg); - io_dispose(s); - free(path_mp); -} - -void add_param_write_mp(add_param* a, char* path, bool json) { - if (!a || !path || !a->ready) - return; - - wchar_t* path_buf = char_string_to_wchar_t_string(path); - add_param_wwrite_mp(a, path_buf, json); - free(path_buf); -} - -void add_param_wwrite_mp(add_param* a, wchar_t* path, bool json) { - if (!a || !path || !a->ready) - return; - - wchar_t* path_mp = path_wadd_extension(path, json ? L".json" : L".mp"); - stream* s = io_wopen(path_mp, L"wb"); - if (s->io.stream) { - msgpack* msg = msgpack_init_map(0); - msgpack* add_param = msgpack_init_array(L"AddParam", a->length); - msgpack_array* ptr = SELECT_MSGPACK(msgpack_array, add_param); - for (size_t i = 0; i < a->length; i++) { - msgpack* m = &ptr->data[i]; - add_param_struct* adps = &a->data[i]; - msgpack_set_map_empty(m, 0); - msgpack_append_float_t(m, L"Time", adps->time); - msgpack_append_int32_t(m, L"Flags", adps->flags); - msgpack_append_int32_t(m, L"Frame", adps->frame); - if (adps->pv_branch) - msgpack_append_int32_t(m, L"PVBranch", adps->pv_branch); - msgpack_append_int32_t(m, L"ID", adps->id); - msgpack_append_int32_t(m, L"Value", adps->value); - } - msgpack_append(msg, add_param); - msgpack_dispose(add_param); - if (json) - io_json_write(s, msg); - else - io_msgpack_write(s, msg); - msgpack_dispose(msg); - } - io_dispose(s); - free(path_mp); -} diff --git a/src/KKdLib/add_param.h b/src/KKdLib/add_param.h deleted file mode 100644 index 72e2f1ad..00000000 --- a/src/KKdLib/add_param.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#pragma once - -#include "default.h" - -typedef struct add_param_struct { - float_t time; - int32_t flags; - int32_t frame; - int32_t padding_0C; - int32_t pv_branch; - int32_t id; - int32_t value; - int32_t padding_1C; -} add_param_struct; - -typedef struct add_param { - bool ready; - size_t length; - add_param_struct* data; -} add_param; - -extern add_param* add_param_init(); -extern void add_param_dispose(add_param* a); -extern void add_param_read_adp(add_param* a, char* path); -extern void add_param_wread_adp(add_param* a, wchar_t* path); -extern void add_param_write_adp(add_param* a, char* path); -extern void add_param_wwrite_adp(add_param* a, wchar_t* path); -extern void add_param_read_mp(add_param* a, char* path, bool json); -extern void add_param_wread_mp(add_param* a, wchar_t* path, bool json); -extern void add_param_write_mp(add_param* a, char* path, bool json); -extern void add_param_wwrite_mp(add_param* a, wchar_t* path, bool json); diff --git a/src/KKdLib/aes.c b/src/KKdLib/aes.c index 7bb1f98a..edd90762 100644 --- a/src/KKdLib/aes.c +++ b/src/KKdLib/aes.c @@ -1,5 +1,5 @@ /* - Original: https://github.com/kokke/tiny-AES-c + Original: https://github.com/kokke/tiny-AES-c */ /* diff --git a/src/KKdLib/auth_3d.c b/src/KKdLib/auth_3d.c new file mode 100644 index 00000000..82ed8bd8 --- /dev/null +++ b/src/KKdLib/auth_3d.c @@ -0,0 +1,6 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "auth_3d.h" diff --git a/src/KKdLib/auth_3d.h b/src/KKdLib/auth_3d.h index 0ad92408..82bf02d6 100644 --- a/src/KKdLib/auth_3d.h +++ b/src/KKdLib/auth_3d.h @@ -11,16 +11,16 @@ #include "vec.h" typedef enum auth_3d_ambient_flags { - AUTH_3D_AMBIENT_LIGHT = 0b01, - AUTH_3D_AMBIENT_RIM_LIGHT = 0b10, + AUTH_3D_AMBIENT_LIGHT = 0x1, + AUTH_3D_AMBIENT_RIM_LIGHT = 0x2, } auth_3d_ambient_flags; typedef enum auth_3d_camera_auxiliary_flags { - AUTH_3D_CAMERA_EXPOSURE = 0b00001, - AUTH_3D_CAMERA_GAMMA = 0b00010, - AUTH_3D_CAMERA_SATURATE = 0b00100, - AUTH_3D_CAMERA_AUTO_EXPOSURE = 0b01000, - AUTH_3D_CAMERA_GAMMA_RATE = 0b10000, + AUTH_3D_CAMERA_EXPOSURE = 0x01, + AUTH_3D_CAMERA_GAMMA = 0x02, + AUTH_3D_CAMERA_SATURATE = 0x04, + AUTH_3D_CAMERA_AUTO_EXPOSURE = 0x08, + AUTH_3D_CAMERA_GAMMA_RATE = 0x10, } auth_3d_camera_auxiliary_flags; typedef enum auth_3d_compress_f16 { @@ -37,10 +37,10 @@ typedef enum auth_3d_ep_type { } auth_3d_ep_type; // Pre/Post Infinity typedef enum auth_3d_fog_flags { - AUTH_3D_FOG_DENSITY = 0b0001, - AUTH_3D_FOG_START = 0b0010, - AUTH_3D_FOG_END = 0b0100, - AUTH_3D_FOG_DIFFUSE = 0b1000, + AUTH_3D_FOG_DENSITY = 0x1, + AUTH_3D_FOG_START = 0x2, + AUTH_3D_FOG_END = 0x4, + AUTH_3D_FOG_DIFFUSE = 0x8, } auth_3d_fog_flags; typedef enum auth_3d_key_type { @@ -52,10 +52,10 @@ typedef enum auth_3d_key_type { } auth_3d_key_type; typedef enum auth_3d_light_flags { - AUTH_3D_LIGHT_AMBIENT = 0b0001, - AUTH_3D_LIGHT_DIFFUSE = 0b0010, - AUTH_3D_LIGHT_SPECULAR = 0b0100, - AUTH_3D_LIGHT_INCANDESCENCE = 0b1000, + AUTH_3D_LIGHT_AMBIENT = 0x1, + AUTH_3D_LIGHT_DIFFUSE = 0x2, + AUTH_3D_LIGHT_SPECULAR = 0x4, + AUTH_3D_LIGHT_INCANDESCENCE = 0x8, } auth_3d_light_flags; typedef enum auth_3d_material_list_flags { @@ -64,25 +64,25 @@ typedef enum auth_3d_material_list_flags { } auth_3d_material_list_flags; typedef enum auth_3d_object_tex_transform_flags { - AUTH_3D_OBJECT_TEX_TRANSFORM_COVERAGE_U = 0b0000000001, - AUTH_3D_OBJECT_TEX_TRANSFORM_COVERAGE_V = 0b0000000010, - AUTH_3D_OBJECT_TEX_TRANSFORM_REPEAT_U = 0b0000000100, - AUTH_3D_OBJECT_TEX_TRANSFORM_REPEAT_V = 0b0000001000, - AUTH_3D_OBJECT_TEX_TRANSFORM_TRANSLATE_FRAME_U = 0b0000010000, - AUTH_3D_OBJECT_TEX_TRANSFORM_TRANSLATE_FRAME_V = 0b0000100000, - AUTH_3D_OBJECT_TEX_TRANSFORM_OFFSET_U = 0b0001000000, - AUTH_3D_OBJECT_TEX_TRANSFORM_OFFSET_V = 0b0010000000, - AUTH_3D_OBJECT_TEX_TRANSFORM_ROTATE_FRAME = 0b0100000000, - AUTH_3D_OBJECT_TEX_TRANSFORM_ROTATE = 0b1000000000, + AUTH_3D_OBJECT_TEX_TRANSFORM_COVERAGE_U = 0x001, + AUTH_3D_OBJECT_TEX_TRANSFORM_COVERAGE_V = 0x002, + AUTH_3D_OBJECT_TEX_TRANSFORM_REPEAT_U = 0x004, + AUTH_3D_OBJECT_TEX_TRANSFORM_REPEAT_V = 0x008, + AUTH_3D_OBJECT_TEX_TRANSFORM_TRANSLATE_FRAME_U = 0x010, + AUTH_3D_OBJECT_TEX_TRANSFORM_TRANSLATE_FRAME_V = 0x020, + AUTH_3D_OBJECT_TEX_TRANSFORM_OFFSET_U = 0x040, + AUTH_3D_OBJECT_TEX_TRANSFORM_OFFSET_V = 0x080, + AUTH_3D_OBJECT_TEX_TRANSFORM_ROTATE_FRAME = 0x100, + AUTH_3D_OBJECT_TEX_TRANSFORM_ROTATE = 0x200, } auth_3d_object_tex_transform_flags; typedef enum auth_3d_post_process_flags { - AUTH_3D_POST_PROCESS_LENS_FLARE = 0b000001, - AUTH_3D_POST_PROCESS_LENS_SHAFT = 0b000010, - AUTH_3D_POST_PROCESS_LENS_GHOST = 0b000100, - AUTH_3D_POST_PROCESS_RADIUS = 0b001000, - AUTH_3D_POST_PROCESS_INTENSITY = 0b010000, - AUTH_3D_POST_PROCESS_SCENE_FADE = 0b100000, + AUTH_3D_POST_PROCESS_LENS_FLARE = 0x01, + AUTH_3D_POST_PROCESS_LENS_SHAFT = 0x02, + AUTH_3D_POST_PROCESS_LENS_GHOST = 0x04, + AUTH_3D_POST_PROCESS_RADIUS = 0x08, + AUTH_3D_POST_PROCESS_INTENSITY = 0x10, + AUTH_3D_POST_PROCESS_SCENE_FADE = 0x20, } auth_3d_post_process_flags; typedef struct auth_3d_key_raw_data { @@ -115,6 +115,7 @@ typedef struct auth_3d_key { } auth_3d_key; v3(auth_3d_key) +v4(auth_3d_key) typedef struct auth_3d_model_transform { bool written; @@ -125,8 +126,6 @@ typedef struct auth_3d_model_transform { auth_3d_key visibility; } auth_3d_model_transform; -v4(auth_3d_key) - typedef struct auth_3d__ { auth_3d_compress_f16 compress_f16; char* file_name; diff --git a/src/KKdLib/char_buffer.c b/src/KKdLib/char_buffer.c index 5b2af4be..81874de4 100644 --- a/src/KKdLib/char_buffer.c +++ b/src/KKdLib/char_buffer.c @@ -16,17 +16,25 @@ void char_buffer_init(char_buffer* c, char* str) { memcpy(c->data, str, c->length + 1); } +inline char* char_buffer_select(char_buffer* c) { + return c->length > CHAR_BUFFER_LENGTH - 1 ? c->ptr : c->data; +} + void char_buffer_dispose(char_buffer* c) { if (c->length > CHAR_BUFFER_LENGTH - 1) free(c->ptr); memset(c, 0, sizeof(char_buffer)); } +inline wchar_t* wchar_t_buffer_select(wchar_t_buffer* c) { + return c->length > WCHAR_T_BUFFER_LENGTH - 1 ? c->ptr : c->data; +} + void wchar_t_buffer_init(wchar_t_buffer* c, wchar_t* str) { memset(c, 0, sizeof(wchar_t_buffer)); c->length = wcslen(str); if (c->length > WCHAR_T_BUFFER_LENGTH - 1) { - c->ptr = force_malloc_s(sizeof(wchar_t), c->length + 1); + c->ptr = force_malloc_s(wchar_t, c->length + 1); memcpy(c->ptr, str, sizeof(wchar_t) * (c->length + 1)); } else @@ -38,6 +46,3 @@ void wchar_t_buffer_dispose(wchar_t_buffer* c) { free(c->ptr); memset(c, 0, sizeof(wchar_t_buffer)); } -/* -extern char* char_buffer_select(char_buffer* c); -extern wchar_t* wchar_t_buffer_select(wchar_t_buffer* c);*/ diff --git a/src/KKdLib/char_buffer.h b/src/KKdLib/char_buffer.h index 0e79f8d5..a2bd9668 100644 --- a/src/KKdLib/char_buffer.h +++ b/src/KKdLib/char_buffer.h @@ -27,14 +27,8 @@ typedef struct wchar_t_buffer { } wchar_t_buffer; extern void char_buffer_init(char_buffer* c, char* str); +extern char* char_buffer_select(char_buffer* c); extern void char_buffer_dispose(char_buffer* c); extern void wchar_t_buffer_init(wchar_t_buffer* c, wchar_t* str); +extern wchar_t* wchar_t_buffer_select(wchar_t_buffer* c); extern void wchar_t_buffer_dispose(wchar_t_buffer* c); - -static inline char* char_buffer_select(char_buffer* c) { - return c->length > CHAR_BUFFER_LENGTH - 1 ? c->ptr : c->data; -} - -static inline wchar_t* wchar_t_buffer_select(wchar_t_buffer* c) { - return c->length > WCHAR_T_BUFFER_LENGTH - 1 ? c->ptr : c->data; -} diff --git a/src/KKdLib/dds.c b/src/KKdLib/dds.c new file mode 100644 index 00000000..72106443 --- /dev/null +++ b/src/KKdLib/dds.c @@ -0,0 +1,467 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "dds.h" +#include "io_stream.h" +#include "str_utils.h" + +#pragma pack(push, 1) + +const uint32_t DDS_MAGIC = 'DDS '; + +typedef struct DDS_PIXELFORMAT { + uint32_t size; + uint32_t flags; + uint32_t fourCC; + uint32_t RGBBitCount; + uint32_t RBitMask; + uint32_t GBitMask; + uint32_t BBitMask; + uint32_t ABitMask; +} DDS_PIXELFORMAT; + +#define DDSD_CAPS 0x00000001 +#define DDSD_HEIGHT 0x00000002 +#define DDSD_WIDTH 0x00000004 +#define DDSD_PITCH 0x00000008 +#define DDSD_PIXELFORMAT 0x00001000 +#define DDSD_MIPMAPCOUNT 0x00020000 +#define DDSD_LINEARSIZE 0x00080000 +#define DDSD_DEPTH 0x00800000 + +#define DDS_FOURCC 0x00000004 // DDPF_FOURCC +#define DDS_RGB 0x00000040 // DDPF_RGB +#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS +#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE +#define DDS_LUMINANCEA 0x00020001 // DDPF_LUMINANCE | DDPF_ALPHAPIXELS +#define DDS_ALPHAPIXELS 0x00000001 // DDPF_ALPHAPIXELS +#define DDS_ALPHA 0x00000002 // DDPF_ALPHA + +#define DDSGLOBALCONST extern const +#define DDSCONST extern const + +#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT +#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT +#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH +#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH +#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE + +#define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT +#define DDS_WIDTH 0x00000004 // DDSD_WIDTH + +#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE +#define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP +#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX + +#define DDS_CUBEMAP_ALLFACES ( 0x00000400 | 0x00000800 |\ + 0x00001000 | 0x00002000 |\ + 0x00004000 | 0x00008000 | 0x00000200 ) + +#define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP + +#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME + +typedef struct DDS_HEADER { + uint32_t size; + uint32_t flags; + uint32_t height; + uint32_t width; + uint32_t pitchOrLinearSize; + uint32_t depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags + uint32_t mipMapCount; + uint32_t reserved1[11]; + DDS_PIXELFORMAT ddspf; + uint32_t caps; + uint32_t caps2; + uint32_t caps3; + uint32_t caps4; + uint32_t reserved2; +} DDS_HEADER; + +#pragma pack(pop) + +DDSCONST DDS_PIXELFORMAT DDSPF_DXT1 = +{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, '1TXD', 0, 0, 0, 0, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_DXT3 = +{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, '3TXD', 0, 0, 0, 0, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_DXT5 = +{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, '5TXD', 0, 0, 0, 0, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_ATI1 = +{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, '1ITA', 0, 0, 0, 0, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_ATI2 = +{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, '2ITA', 0, 0, 0, 0, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_BC4_UNORM = +{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 'U4CB', 0, 0, 0, 0, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_BC5_UNORM = +{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 'U5CB', 0, 0, 0, 0, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_A8R8G8B8 = +{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_A8B8G8R8 = +{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_R5G6B5 = +{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_B5G6R5 = +{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x001f, 0x07e0, 0xf800, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_A1R5G5B5 = +{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_A1B5G5R5 = +{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x001f, 0x03e0, 0x7c00, 0x8000 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_A4R4G4B4 = +{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_A4B4G4R4 = +{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x000f, 0x00f0, 0x0f00, 0xf000 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_R8G8B8 = +{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_B8G8R8 = +{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0x0000ff, 0x00ff00, 0xff0000, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_L8 = +{ sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0xff, 0, 0, 0 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_A8L8 = +{ sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0x00ff, 0, 0, 0xff00 }; + +DDSCONST DDS_PIXELFORMAT DDSPF_L8A8 = +{ sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0xff00, 0, 0, 0x00ff }; + +DDSCONST DDS_PIXELFORMAT DDSPF_A8 = +{ sizeof(DDS_PIXELFORMAT), DDS_ALPHA, 0, 8, 0, 0, 0, 0xff }; + +static void dds_reverse_rgb(txp_format format, ssize_t size, uint8_t* data); +static bool dds_check_is_dxt1a(ssize_t size, uint8_t* data); + +dds* dds_init() { + dds* d = force_malloc(sizeof(dds)); + return d; +} + +void dds_read(dds* d, char* path) { + if (!d || !path) + return; + + wchar_t* path_buf = char_string_to_wchar_t_string(path); + dds_wread(d, path_buf); + free(path_buf); +} + +void dds_wread(dds* d, wchar_t* path) { + if (!d || !path) + return; + + vector_ptr_void_free(&d->data, 0); + memset(d, 0, sizeof(dds)); + wchar_t* path_dds = str_utils_wadd(path, L".dds"); + stream* s = io_wopen(path_dds, L"rb"); + if (s->io.stream) { + if (io_read_uint32_t_reverse_endianess(s, true) != DDS_MAGIC) + goto End; + + DDS_HEADER dds_h; + memset(&dds_h, 0, sizeof(DDS_HEADER)); + if (io_read(s, &dds_h, sizeof(DDS_HEADER)) != sizeof(DDS_HEADER)) + goto End; + + if (!((dds_h.flags & DDSD_CAPS) && (dds_h.flags & DDSD_HEIGHT) + && (dds_h.flags & DDSD_WIDTH) && (dds_h.flags & DDSD_PIXELFORMAT))) + goto End; + else if ((dds_h.flags & DDSD_PITCH) || (dds_h.flags & DDSD_DEPTH)) + goto End; + else if (!(dds_h.caps & DDS_SURFACE_FLAGS_TEXTURE)) + goto End; + else if ((dds_h.caps2 & DDS_CUBEMAP) && (~dds_h.caps2 & DDS_CUBEMAP_ALLFACES) || (dds_h.flags & DDS_FLAGS_VOLUME)) + goto End; + + bool reverse = false; + if (!memcmp(&dds_h.ddspf, &DDSPF_A8, sizeof(DDS_PIXELFORMAT))) + d->format = TXP_A8; + else if (!memcmp(&dds_h.ddspf, &DDSPF_R8G8B8, sizeof(DDS_PIXELFORMAT))) { + d->format = TXP_RGB8; + reverse = true; + } + else if (!memcmp(&dds_h.ddspf, &DDSPF_B8G8R8, sizeof(DDS_PIXELFORMAT))) + d->format = TXP_RGB8; + else if (!memcmp(&dds_h.ddspf, &DDSPF_A8R8G8B8, sizeof(DDS_PIXELFORMAT))) { + d->format = TXP_RGBA8; + reverse = true; + } + else if (!memcmp(&dds_h.ddspf, &DDSPF_A8B8G8R8, sizeof(DDS_PIXELFORMAT))) + d->format = TXP_RGBA8; + else if (!memcmp(&dds_h.ddspf, &DDSPF_R5G6B5, sizeof(DDS_PIXELFORMAT))) { + d->format = TXP_RGB5; + reverse = true; + } + else if (!memcmp(&dds_h.ddspf, &DDSPF_B5G6R5, sizeof(DDS_PIXELFORMAT))) + d->format = TXP_RGB5; + else if (!memcmp(&dds_h.ddspf, &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT))) { + d->format = TXP_RGB5A1; + reverse = true; + } + else if (!memcmp(&dds_h.ddspf, &DDSPF_A1B5G5R5, sizeof(DDS_PIXELFORMAT))) + d->format = TXP_A8; + else if (!memcmp(&dds_h.ddspf, &DDSPF_A4R4G4B4, sizeof(DDS_PIXELFORMAT))) { + d->format = TXP_RGBA4; + reverse = true; + } + else if (!memcmp(&dds_h.ddspf, &DDSPF_A4B4G4R4, sizeof(DDS_PIXELFORMAT))) + d->format = TXP_RGBA4; + else if (!memcmp(&dds_h.ddspf, &DDSPF_DXT1, sizeof(uint32_t) * 3)) + d->format = TXP_DXT1; + else if (!memcmp(&dds_h.ddspf, &DDSPF_DXT3, sizeof(uint32_t) * 3)) + d->format = TXP_DXT3; + else if (!memcmp(&dds_h.ddspf, &DDSPF_DXT5, sizeof(uint32_t) * 3)) + d->format = TXP_DXT5; + else if (!memcmp(&dds_h.ddspf, &DDSPF_ATI1, sizeof(uint32_t) * 3)) + d->format = TXP_ATI1; + else if (!memcmp(&dds_h.ddspf, &DDSPF_BC4_UNORM, sizeof(uint32_t) * 3)) + d->format = TXP_ATI1; + else if (!memcmp(&dds_h.ddspf, &DDSPF_ATI2, sizeof(uint32_t) * 3)) + d->format = TXP_ATI2; + else if (!memcmp(&dds_h.ddspf, &DDSPF_BC5_UNORM, sizeof(uint32_t) * 3)) + d->format = TXP_ATI2; + else if (!memcmp(&dds_h.ddspf, &DDSPF_L8, sizeof(DDS_PIXELFORMAT))) + d->format = TXP_L8; + else if (!memcmp(&dds_h.ddspf, &DDSPF_L8A8, sizeof(DDS_PIXELFORMAT))) { + d->format = TXP_L8A8; + reverse = true; + } + else if (!memcmp(&dds_h.ddspf, &DDSPF_A8L8, sizeof(DDS_PIXELFORMAT))) + d->format = TXP_L8A8; + else + goto End; + + d->width = dds_h.width; + d->height = dds_h.height; + d->mipmaps_count = dds_h.flags & DDSD_MIPMAPCOUNT ? dds_h.mipMapCount : 1; + d->has_cubemap = dds_h.caps2 & DDS_CUBEMAP ? true : false; + vector_ptr_void_append(&d->data, d->has_cubemap ? d->mipmaps_count * 6LL : d->mipmaps_count); + + do + for (uint32_t i = 0; i < d->mipmaps_count; i++) { + uint32_t width = max(d->width >> i, 1); + uint32_t height = max(d->height >> i, 1); + uint32_t size = txp_get_size(d->format, + max(d->width >> i, 1), max(d->height >> i, 1)); + void* data = force_malloc(size); + io_read(s, data, size); + if (reverse) + dds_reverse_rgb(d->format, size, data); + else if (d->format == TXP_DXT1 && dds_check_is_dxt1a(size, data)) + d->format = TXP_DXT1a; + vector_ptr_void_push_back(&d->data, &data); + } + while (d->has_cubemap && (d->data.end - d->data.begin) / d->mipmaps_count < 6); + } +End: + io_dispose(s); + free(path_dds); +} + +void dds_write(dds* d, char* path) { + if (!d || !path || d->data.end - d->data.begin < 1) + return; + + wchar_t* path_buf = char_string_to_wchar_t_string(path); + dds_wwrite(d, path_buf); + free(path_buf); +} + +void dds_wwrite(dds* d, wchar_t* path) { + if (!d || !path || d->data.end - d->data.begin < 1) + return; + + wchar_t* path_dds = str_utils_wadd(path, L".dds"); + stream* s = io_wopen(path_dds, L"wb"); + if (s->io.stream) { + DDS_HEADER dds_h; + memset(&dds_h, 0, sizeof(DDS_HEADER)); + dds_h.size = sizeof(DDS_HEADER); + dds_h.flags = DDS_HEADER_FLAGS_TEXTURE | DDSD_LINEARSIZE; + if (d->mipmaps_count > 1) + dds_h.flags |= DDSD_MIPMAPCOUNT; + dds_h.height = d->height; + dds_h.width = d->width; + dds_h.pitchOrLinearSize = txp_get_size(d->format, d->width, d->height); + dds_h.mipMapCount = d->mipmaps_count; + dds_h.caps |= DDS_SURFACE_FLAGS_TEXTURE; + if (d->has_cubemap) + dds_h.caps |= DDS_SURFACE_FLAGS_CUBEMAP; + + if (d->mipmaps_count > 1) + dds_h.caps |= DDS_SURFACE_FLAGS_MIPMAP; + + if (d->has_cubemap) + dds_h.caps2 |= DDS_CUBEMAP_ALLFACES; + + switch (d->format) { + case TXP_A8: + dds_h.ddspf = DDSPF_A8; + break; + case TXP_RGB8: + dds_h.ddspf = DDSPF_R8G8B8; + break; + case TXP_RGBA8: + dds_h.ddspf = DDSPF_A8R8G8B8; + break; + case TXP_RGB5: + dds_h.ddspf = DDSPF_R5G6B5; + break; + case TXP_RGB5A1: + dds_h.ddspf = DDSPF_A1R5G5B5; + break; + case TXP_RGBA4: + dds_h.ddspf = DDSPF_A4R4G4B4; + break; + case TXP_DXT1: + case TXP_DXT1a: + dds_h.ddspf = DDSPF_DXT1; + break; + case TXP_DXT3: + dds_h.ddspf = DDSPF_DXT3; + break; + case TXP_DXT5: + dds_h.ddspf = DDSPF_DXT5; + break; + case TXP_ATI1: + dds_h.ddspf = DDSPF_ATI1; + break; + case TXP_ATI2: + dds_h.ddspf = DDSPF_ATI2; + break; + case TXP_L8: + dds_h.ddspf = DDSPF_L8; + break; + case TXP_L8A8: + dds_h.ddspf = DDSPF_L8A8; + break; + } + + io_write_uint32_t_reverse_endianess(s, DDS_MAGIC, true); + io_write(s, &dds_h, sizeof(DDS_HEADER)); + + uint32_t index = 0; + do + for (uint32_t i = 0; i < d->mipmaps_count; i++) { + uint32_t size = txp_get_size(d->format, + max(d->width >> i, 1), max(d->height >> i, 1)); + void* data = force_malloc(size); + memcpy(data, d->data.begin[index], size); + dds_reverse_rgb(d->format, size, data); + io_write(s, data, size); + free(data); + index++; + } + while (d->has_cubemap && index / d->mipmaps_count < 6); + } + io_dispose(s); + free(path_dds); +} + +void dds_dispose(dds* d) { + if (!d) + return; + + vector_ptr_void_free(&d->data, 0); + free(d); +} + +static void dds_reverse_rgb(txp_format format, ssize_t size, uint8_t* data) { + uint8_t l, r, g, b, a; + switch (format) { + case TXP_RGB8: + while (size > 0) { + b = data[0]; + g = data[1]; + r = data[2]; + data[0] = r; + data[1] = g; + data[2] = b; + data += 3; + size -= 3; + } + break; + case TXP_RGBA8: + while (size > 0) { + b = data[0]; + g = data[1]; + r = data[2]; + a = data[3]; + data[0] = r; + data[1] = g; + data[2] = b; + data[3] = a; + data += 4; + size -= 4; + } + break; + case TXP_RGB5: + while (size > 0) { + b = (uint8_t)(*(uint16_t*)data) & 0x1F; + g = (uint8_t)(*(uint16_t*)data >> 5) & 0x3F; + r = (uint8_t)(*(uint16_t*)data >> 11) & 0x1F; + *(uint16_t*)data = (b << 11) | (g << 5) | r; + data += 2; + size -= 2; + } + break; + case TXP_RGB5A1: + while (size > 0) { + b = (uint8_t)(*(uint16_t*)data) & 0x1F; + g = (uint8_t)(*(uint16_t*)data >> 5) & 0x1F; + r = (uint8_t)(*(uint16_t*)data >> 10) & 0x1F; + a = (uint8_t)(*(uint16_t*)data >> 15) & 0x01; + *(uint16_t*)data = (a << 15) | (b << 10) | (g << 5) | r; + data += 2; + size -= 2; + } + break; + case TXP_RGBA4: + while (size > 0) { + b = (uint8_t)(*(uint16_t*)data) & 0x0F; + g = (uint8_t)(*(uint16_t*)data >> 4) & 0x0F; + r = (uint8_t)(*(uint16_t*)data >> 8) & 0x0F; + a = (uint8_t)(*(uint16_t*)data >> 12) & 0x0F; + *(uint16_t*)data = (a << 12) | (b << 8) | (g << 4) | r; + data += 2; + size -= 2; + } + break; + case TXP_L8A8: + while (size > 0) { + a = data[0]; + l = data[1]; + data[0] = l; + data[1] = a; + data += 2; + size -= 2; + } + break; + } +} + +static bool dds_check_is_dxt1a(ssize_t size, uint8_t* data) { + while (size > 0) { + if (*(uint16_t*)data <= *(uint16_t*)(data + 2)) + return true; + data += 8; + size -= 8; + } + return false; +} \ No newline at end of file diff --git a/src/KKdLib/dds.h b/src/KKdLib/dds.h new file mode 100644 index 00000000..2fdab3d8 --- /dev/null +++ b/src/KKdLib/dds.h @@ -0,0 +1,26 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "default.h" +#include "txp.h" +#include "vector.h" + +typedef struct dds { + txp_format format; + uint32_t width; + uint32_t height; + uint32_t mipmaps_count; + bool has_cubemap; + vector_ptr_void data; +} dds; + +extern dds* dds_init(); +extern void dds_read(dds* d, char* path); +extern void dds_wread(dds* d, wchar_t* path); +extern void dds_write(dds* d, char* path); +extern void dds_wwrite(dds* d, wchar_t* path); +extern void dds_dispose(dds* d); diff --git a/src/KKdLib/default.c b/src/KKdLib/default.c index 54f16c56..183a4810 100644 --- a/src/KKdLib/default.c +++ b/src/KKdLib/default.c @@ -13,14 +13,6 @@ void* force_malloc(size_t size) { return buf; } -void* force_malloc_s(size_t s, size_t size) { - void* buf = 0; - while (!buf) - buf = malloc(size * s); - memset(buf, 0, size * s); - return buf; -} - void char_append_data(char** buf, size_t* buf_len, size_t* act_buf_len, char* data, size_t length) { if (length < 1) return; @@ -109,7 +101,7 @@ wchar_t* char_string_to_wchar_t_string(char* s) { return 0; size_t len = strlen(s); - wchar_t* t = force_malloc_s(sizeof(wchar_t), len + 1); + wchar_t* t = force_malloc_s(wchar_t, len + 1); for (size_t i = 0; i < len; i++) t[i] = (wchar_t)s[i]; return t; diff --git a/src/KKdLib/default.h b/src/KKdLib/default.h index 8123ad1f..a6cd7fd5 100644 --- a/src/KKdLib/default.h +++ b/src/KKdLib/default.h @@ -17,12 +17,9 @@ #define free(ptr) \ { \ - if (ptr) { \ + if (ptr) \ free(ptr); \ - (ptr) = 0; \ - } \ - else \ - (ptr) = 0; \ + (ptr) = 0; \ } #define null(t) \ @@ -113,14 +110,40 @@ pointer_ptr(char) #define clamp(a, b, c) (min(max(a, b), c)) -#define align_val(a, b) (((a) % (b) == 0) ? (a) : ((a) + (b) - (a) % (b))) +#define align_val(a, b) ((((a) + (b) - 1) / (b)) * (b)) -#define align_val_divide(a, b, c) ((((a) % (b) == 0) ? (a) : ((a) + (b) - (a) % (b))) / (c)) +#define align_val_divide(a, b, c) (((a) + (b) - 1) / (c)) #define BUF_SIZE 4096 +#define RAD_TO_DEG (180.0 / M_PI) + +#define DEG_TO_RAD (M_PI / 180.0) + +#define RAD_TO_DEG_FLOAT ((float_t)(180.0 / M_PI)) + +#define DEG_TO_RAD_FLOAT ((float_t)(M_PI / 180.0)) + +#define ctgf(x) (1.0f / tanf(x)) + +#define ctghf(x) (1.0f / tanhf(x)) + +#define actgf(x) (1.0f / atanf(x)) + +#define actghf(x) (1.0f / atanhf(x)) + +#define ctg(x) (1.0 / tan(x)) + +#define ctgh(x) (1.0 / tanh(x)) + +#define actg(x) (1.0 / atan(x)) + +#define actgh(x) (1.0 / atanh(x)) + +#define lerp(x, y, blend) ((x) + (blend) * ((y) - (x))) + extern void* force_malloc(size_t size); -extern void* force_malloc_s(size_t s, size_t size); +#define force_malloc_s(s, size) force_malloc(sizeof(s) * (size)) extern void char_append_data(char** buf, size_t * buf_len, size_t * act_buf_len, char* data, size_t length); extern void char_append_data_s(size_t s, char** buf, size_t* buf_len, diff --git a/src/KKdLib/divafile.c b/src/KKdLib/divafile.c index dec97d5b..165be7fd 100644 --- a/src/KKdLib/divafile.c +++ b/src/KKdLib/divafile.c @@ -5,8 +5,8 @@ #include "divafile.h" #include "aes.h" -#include "io_path.h" #include "io_stream.h" +#include "str_utils.h" static const uint8_t key[] = { 0x66, 0x69, 0x6C, 0x65, 0x20, 0x61, 0x63, 0x63, @@ -20,7 +20,7 @@ void divafile_decrypt(char* file) { } void divafile_wdecrypt(wchar_t* file) { - wchar_t* file_temp = path_wadd_extension(file, L"_dec"); + wchar_t* file_temp = str_utils_wadd(file, L"_dec"); stream* s_enc = io_wopen(file, L"rb"); uint64_t signature = io_read_uint64_t(s_enc); if (signature == 0x454C494641564944) { @@ -49,7 +49,7 @@ void divafile_encrypt(char* file) { } void divafile_wencrypt(wchar_t* file) { - wchar_t* file_temp = path_wadd_extension(file, L"_enc"); + wchar_t* file_temp = str_utils_wadd(file, L"_enc"); stream* s_dec = io_wopen(file, L"rb"); size_t len = s_dec->length; size_t len_align = align_val(len, 0x10); diff --git a/src/KKdLib/dsc.c b/src/KKdLib/dsc.c index bfcc7932..539edc13 100644 --- a/src/KKdLib/dsc.c +++ b/src/KKdLib/dsc.c @@ -5,130 +5,820 @@ #include "dsc.h" -int32_t dsc_ac101_get_func_length(int32_t id) { +static const dsc_func dsc_ac101_func[] = { + { 0, 0, L"END" }, + { 1, 1, L"TIME" }, + { 2, 3, L"MIKU_MOVE" }, + { 3, 1, L"MIKU_ROT" }, + { 4, 1, L"MIKU_DISP" }, + { 5, 1, L"MIKU_SHADOW" }, + { 6, 7, L"TARGET" }, + { 7, 3, L"SET_MOTION" }, + { 8, 1, L"SET_PLAYDATA" }, + { 9, 5, L"EFFECT" }, + { 10, 2, L"FADEIN_FIELD" }, + { 11, 1, L"EFFECT_OFF" }, + { 12, 6, L"SET_CAMERA" }, + { 13, 2, L"DATA_CAMERA" }, + { 14, 1, L"CHANGE_FIELD" }, + { 15, 1, L"HIDE_FIELD" }, + { 16, 3, L"MOVE_FIELD" }, + { 17, 2, L"FADEOUT_FIELD" }, + { 18, 2, L"EYE_ANIM" }, + { 19, 3, L"MOUTH_ANIM" }, + { 20, 4, L"HAND_ANIM" }, + { 21, 3, L"LOOK_ANIM" }, + { 22, 3, L"EXPRESSION" }, + { 23, 4, L"LOOK_CAMERA" }, + { 24, 1, L"LYRIC" }, + { 25, 0, L"MUSIC_PLAY" }, + { 26, 1, L"MODE_SELECT" }, + { 27, 2, L"EDIT_MOTION" }, + { 28, 2, L"BAR_TIME_SET" }, + { 29, 1, L"SHADOWHEIGHT" }, + { 30, 2, L"EDIT_FACE" }, + { 31, 19, L"MOVE_CAMERA" }, + { 32, 0, L"PV_END" }, + { 33, 2, L"SHADOWPOS" }, + { 34, 2, L"NEAR_CLIP" }, + { 35, 1, L"CLOTH_WET" }, + { 36, 6, L"SCENE_FADE" }, // AC110 + { 37, 6, L"TONE_TRANS" }, // AC120 + { 38, 1, L"SATURATE" }, + { 39, 1, L"FADE_MODE" }, +}; + +static const dsc_func_ac dsc_ac_func[] = { + { 0, 0, 0, L"END" }, + { 1, 1, 1, L"TIME" }, + { 2, 3, 4, L"MIKU_MOVE" }, + { 3, 1, 2, L"MIKU_ROT" }, + { 4, 1, 2, L"MIKU_DISP" }, + { 5, 1, 2, L"MIKU_SHADOW" }, + { 6, 7, 7, L"TARGET" }, + { 7, 3, 4, L"SET_MOTION" }, + { 8, 1, 2, L"SET_PLAYDATA" }, + { 9, 5, 6, L"EFFECT" }, + { 10, 2, 2, L"FADEIN_FIELD" }, + { 11, 1, 1, L"EFFECT_OFF" }, + { 12, 6, 6, L"SET_CAMERA" }, + { 13, 2, 2, L"DATA_CAMERA" }, + { 14, 1, 1, L"CHANGE_FIELD" }, + { 15, 1, 1, L"HIDE_FIELD" }, + { 16, 3, 3, L"MOVE_FIELD" }, + { 17, 2, 2, L"FADEOUT_FIELD" }, + { 18, 2, 3, L"EYE_ANIM" }, + { 19, 3, 5, L"MOUTH_ANIM" }, + { 20, 4, 5, L"HAND_ANIM" }, + { 21, 3, 4, L"LOOK_ANIM" }, + { 22, 3, 4, L"EXPRESSION" }, + { 23, 4, 5, L"LOOK_CAMERA" }, + { 24, 1, 2, L"LYRIC" }, + { 25, 0, 0, L"MUSIC_PLAY" }, + { 26, 1, 2, L"MODE_SELECT" }, + { 27, 2, 4, L"EDIT_MOTION" }, + { 28, 2, 2, L"BAR_TIME_SET" }, + { 29, 1, 2, L"SHADOWHEIGHT" }, + { 30, 2, 1, L"EDIT_FACE" }, + { 31, 19, 21, L"MOVE_CAMERA" }, + { 32, 0, 0, L"PV_END" }, + { 33, 2, 3, L"SHADOWPOS" }, + { 34, 2, 2, L"EDIT_LYRIC" }, + { 35, 5, 5, L"EDIT_TARGET" }, + { 36, 1, 1, L"EDIT_MOUTH" }, + { 37, 1, 1, L"SET_CHARA" }, + { 38, 7, 7, L"EDIT_MOVE" }, + { 39, 1, 1, L"EDIT_SHADOW" }, + { 40, 1, 1, L"EDIT_EYELID" }, + { 41, 2, 2, L"EDIT_EYE" }, + { 42, 1, 1, L"EDIT_ITEM" }, + { 43, 2, 2, L"EDIT_EFFECT" }, + { 44, 1, 1, L"EDIT_DISP" }, + { 45, 2, 2, L"EDIT_HAND_ANIM" }, + { 46, 3, 3, L"AIM" }, + { 47, 3, 3, L"HAND_ITEM" }, + { 48, 1, 1, L"EDIT_BLUSH" }, + { 49, 2, 2, L"NEAR_CLIP" }, + { 50, 1, 2, L"CLOTH_WET" }, + { 51, 3, 3, L"LIGHT_ROT" }, + { 52, 6, 6, L"SCENE_FADE" }, + { 53, 6, 6, L"TONE_TRANS" }, + { 54, 1, 1, L"SATURATE" }, + { 55, 1, 1, L"FADE_MODE" }, + { 56, 2, 2, L"AUTO_BLINK" }, + { 57, 3, 3, L"PARTS_DISP" }, + { 58, 1, 1, L"TARGET_FLYING_TIME" }, // AC210 + { 59, 2, 2, L"CHARA_SIZE" }, + { 60, 2, 2, L"CHARA_HEIGHT_ADJUST" }, + { 61, 4, 4, L"ITEM_ANIM" }, + { 62, 4, 4, L"CHARA_POS_ADJUST" }, + { 63, 1, 1, L"SCENE_ROT" }, + { 64, 2, 2, L"EDIT_MOT_SMOOTH_LEN" }, // AC500 + { 65, 1, 1, L"PV_BRANCH_MODE" }, // AC510 + { 66, 2, 2, L"DATA_CAMERA_START" }, + { 67, 1, 1, L"MOVIE_PLAY" }, + { 68, 1, 1, L"MOVIE_DISP" }, + { 69, 3, 3, L"WIND" }, + { 70, 3, 3, L"OSAGE_STEP" }, + { 71, 3, 3, L"OSAGE_MV_CCL" }, + { 72, 2, 2, L"CHARA_COLOR" }, + { 73, 1, 1, L"SE_EFFECT" }, + { 74, 9, 9, L"EDIT_MOVE_XYZ" }, + { 75, 3, 3, L"EDIT_EYELID_ANIM" }, + { 76, 2, 2, L"EDIT_INSTRUMENT_ITEM" }, + { 77, 4, 4, L"EDIT_MOTION_LOOP" }, + { 78, 2, 2, L"EDIT_EXPRESSION" }, + { 79, 3, 3, L"EDIT_EYE_ANIM" }, + { 80, 2, 2, L"EDIT_MOUTH_ANIM" }, + { 81, 24, 24, L"EDIT_CAMERA" }, + { 82, 1, 1, L"EDIT_MODE_SELECT" }, + { 83, 2, 2, L"PV_END_FADEOUT" }, + { 84, 1, 1, L"TARGET_FLAG" }, + { 85, 3, 3, L"ITEM_ANIM_ATTACH" }, + { 86, 1, 1, L"SHADOW_RANGE" }, + { 87, 3, 3, L"HAND_SCALE" }, // AFT101 + { 88, 4, 4, L"LIGHT_POS" }, + { 89, 1, 1, L"FACE_TYPE" }, // AFT200 + { 90, 2, 2, L"SHADOW_CAST" }, // AFT300 + { 91, 6, 6, L"EDIT_MOTION_F" }, // AFT310 + { 92, 3, 3, L"FOG" }, // AFT410 + { 93, 2, 2, L"f2_header" }, + { 94, 3, 3, L"COLOR_COLLE" }, + { 95, 3, 3, L"DOF" }, + { 96, 4, 4, L"CHARA_ALPHA" }, + { 97, 1, 1, L"AOTO_CAP" }, + { 98, 1, 1, L"MAN_CAP" }, + { 99, 3, 3, L"TOON" }, + { 100, 3, 3, L"SHIMMER" }, + { 101, 4, 4, L"ITEM_ALPHA" }, + { 102, 1, 1, L"MOVIE_CUT_CHG" }, + { 103, 3, 3, L"CHARA_LIGHT" }, + { 104, 3, 3, L"STAGE_LIGHT" }, + { 105, 8, 8, L"AGEAGE_CTRL" }, // AFT701 + { 106, 2, 2, L"PSE" }, // FT +}; + +static const dsc_func_ac dsc_f_func[] = { + { 0, 0, 0, L"END" }, + { 1, 1, 1, L"TIME" }, + { 2, 3, 4, L"MIKU_MOVE" }, + { 3, 1, 2, L"MIKU_ROT" }, + { 4, 1, 2, L"MIKU_DISP" }, + { 5, 1, 2, L"MIKU_SHADOW" }, + { 6, 7, 11, L"TARGET" }, + { 7, 3, 4, L"SET_MOTION" }, + { 8, 1, 2, L"SET_PLAYDATA" }, + { 9, 5, 6, L"EFFECT" }, + { 10, 2, 2, L"FADEIN_FIELD" }, + { 11, 1, 1, L"EFFECT_OFF" }, + { 12, 6, 6, L"SET_CAMERA" }, + { 13, 2, 2, L"DATA_CAMERA" }, + { 14, 1, 1, L"CHANGE_FIELD" }, + { 15, 1, 1, L"HIDE_FIELD" }, + { 16, 3, 3, L"MOVE_FIELD" }, + { 17, 2, 2, L"FADEOUT_FIELD" }, + { 18, 2, 3, L"EYE_ANIM" }, + { 19, 3, 5, L"MOUTH_ANIM" }, + { 20, 4, 5, L"HAND_ANIM" }, + { 21, 3, 4, L"LOOK_ANIM" }, + { 22, 3, 4, L"EXPRESSION" }, + { 23, 4, 5, L"LOOK_CAMERA" }, + { 24, 1, 2, L"LYRIC" }, + { 25, 0, 0, L"MUSIC_PLAY" }, + { 26, 1, 2, L"MODE_SELECT" }, + { 27, 2, 4, L"EDIT_MOTION" }, + { 28, 2, 2, L"BAR_TIME_SET" }, + { 29, 1, 2, L"SHADOWHEIGHT" }, + { 30, 2, 1, L"EDIT_FACE" }, + { 31, 19, 21, L"MOVE_CAMERA" }, + { 32, 0, 0, L"PV_END" }, + { 33, 2, 3, L"SHADOWPOS" }, + { 34, 2, 2, L"EDIT_LYRIC" }, + { 35, 5, 5, L"EDIT_TARGET" }, + { 36, 1, 1, L"EDIT_MOUTH" }, + { 37, 1, 1, L"SET_CHARA" }, + { 38, 7, 7, L"EDIT_MOVE" }, + { 39, 1, 1, L"EDIT_SHADOW" }, + { 40, 1, 1, L"EDIT_EYELID" }, + { 41, 2, 2, L"EDIT_EYE" }, + { 42, 1, 1, L"EDIT_ITEM" }, + { 43, 2, 2, L"EDIT_EFFECT" }, + { 44, 1, 1, L"EDIT_DISP" }, + { 45, 2, 2, L"EDIT_HAND_ANIM" }, + { 46, 3, 3, L"AIM" }, + { 47, 3, 3, L"HAND_ITEM" }, + { 48, 1, 1, L"EDIT_BLUSH" }, + { 49, 2, 2, L"NEAR_CLIP" }, + { 50, 1, 2, L"CLOTH_WET" }, + { 51, 3, 3, L"LIGHT_ROT" }, + { 52, 6, 6, L"SCENE_FADE" }, + { 53, 6, 6, L"TONE_TRANS" }, + { 54, 1, 1, L"SATURATE" }, + { 55, 1, 1, L"FADE_MODE" }, + { 56, 2, 2, L"AUTO_BLINK" }, + { 57, 3, 3, L"PARTS_DISP" }, + { 58, 1, 1, L"TARGET_FLYING_TIME" }, + { 59, 2, 2, L"CHARA_SIZE" }, + { 60, 2, 2, L"CHARA_HEIGHT_ADJUST" }, + { 61, 4, 4, L"ITEM_ANIM" }, + { 62, 4, 4, L"CHARA_POS_ADJUST" }, + { 63, 1, 1, L"SCENE_ROT" }, + { 64, 2, 2, L"EDIT_MOT_SMOOTH_LEN" }, + { 65, 1, 1, L"PV_BRANCH_MODE" }, + { 66, 2, 2, L"DATA_CAMERA_START" }, + { 67, 1, 1, L"MOVIE_PLAY" }, + { 68, 1, 1, L"MOVIE_DISP" }, + { 69, 3, 3, L"WIND" }, + { 70, 3, 3, L"OSAGE_STEP" }, + { 71, 3, 3, L"OSAGE_MV_CCL" }, + { 72, 2, 2, L"CHARA_COLOR" }, + { 73, 1, 1, L"SE_EFFECT" }, + { 74, 9, 9, L"EDIT_MOVE_XYZ" }, + { 75, 3, 3, L"EDIT_EYELID_ANIM" }, + { 76, 2, 2, L"EDIT_INSTRUMENT_ITEM" }, + { 77, 4, 4, L"EDIT_MOTION_LOOP" }, + { 78, 2, 2, L"EDIT_EXPRESSION" }, + { 79, 3, 3, L"EDIT_EYE_ANIM" }, + { 80, 2, 2, L"EDIT_MOUTH_ANIM" }, + { 81, 24, 24, L"EDIT_CAMERA" }, + { 82, 1, 1, L"EDIT_MODE_SELECT" }, + { 83, 2, 2, L"PV_END_FADEOUT" }, +}; + +static const dsc_func dsc_f2_func[] = { + { 0, 0, L"END" }, + { 1, 1, L"TIME" }, + { 2, 4, L"MIKU_MOVE" }, + { 3, 2, L"MIKU_ROT" }, + { 4, 2, L"MIKU_DISP" }, + { 5, 2, L"MIKU_SHADOW" }, + { 6, 12, L"TARGET" }, + { 7, 4, L"SET_MOTION" }, + { 8, 2, L"SET_PLAYDATA" }, + { 9, 6, L"EFFECT" }, + { 10, 2, L"FADEIN_FIELD" }, + { 11, 1, L"EFFECT_OFF" }, + { 12, 6, L"SET_CAMERA" }, + { 13, 2, L"DATA_CAMERA" }, + { 14, 2, L"CHANGE_FIELD" }, + { 15, 1, L"HIDE_FIELD" }, + { 16, 3, L"MOVE_FIELD" }, + { 17, 2, L"FADEOUT_FIELD" }, + { 18, 3, L"EYE_ANIM" }, + { 19, 5, L"MOUTH_ANIM" }, + { 20, 5, L"HAND_ANIM" }, + { 21, 4, L"LOOK_ANIM" }, + { 22, 4, L"EXPRESSION" }, + { 23, 5, L"LOOK_CAMERA" }, + { 24, 2, L"LYRIC" }, + { 25, 0, L"MUSIC_PLAY" }, + { 26, 2, L"MODE_SELECT" }, + { 27, 4, L"EDIT_MOTION" }, + { 28, 2, L"BAR_TIME_SET" }, + { 29, 2, L"SHADOWHEIGHT" }, + { 30, 1, L"EDIT_FACE" }, + { 31, 21, L"MOVE_CAMERA" }, + { 32, 0, L"PV_END" }, + { 33, 3, L"SHADOWPOS" }, + { 34, 2, L"EDIT_LYRIC" }, + { 35, 5, L"EDIT_TARGET" }, + { 36, 1, L"EDIT_MOUTH" }, + { 37, 1, L"SET_CHARA" }, + { 38, 7, L"EDIT_MOVE" }, + { 39, 1, L"EDIT_SHADOW" }, + { 40, 1, L"EDIT_EYELID" }, + { 41, 2, L"EDIT_EYE" }, + { 42, 1, L"EDIT_ITEM" }, + { 43, 2, L"EDIT_EFFECT" }, + { 44, 1, L"EDIT_DISP" }, + { 45, 2, L"EDIT_HAND_ANIM" }, + { 46, 3, L"AIM" }, + { 47, 3, L"HAND_ITEM" }, + { 48, 1, L"EDIT_BLUSH" }, + { 49, 2, L"NEAR_CLIP" }, + { 50, 2, L"CLOTH_WET" }, + { 51, 3, L"LIGHT_ROT" }, + { 52, 6, L"SCENE_FADE" }, + { 53, 6, L"TONE_TRANS" }, + { 54, 1, L"SATURATE" }, + { 55, 1, L"FADE_MODE" }, + { 56, 2, L"AUTO_BLINK" }, + { 57, 3, L"PARTS_DISP" }, + { 58, 1, L"TARGET_FLYING_TIME" }, + { 59, 2, L"CHARA_SIZE" }, + { 60, 2, L"CHARA_HEIGHT_ADJUST" }, + { 61, 4, L"ITEM_ANIM" }, + { 62, 4, L"CHARA_POS_ADJUST" }, + { 63, 1, L"SCENE_ROT" }, + { 64, 2, L"EDIT_MOT_SMOOTH_LEN" }, + { 65, 1, L"PV_BRANCH_MODE" }, + { 66, 2, L"DATA_CAMERA_START" }, + { 67, 1, L"MOVIE_PLAY" }, + { 68, 1, L"MOVIE_DISP" }, + { 69, 3, L"WIND" }, + { 70, 3, L"OSAGE_STEP" }, + { 71, 3, L"OSAGE_MV_CCL" }, + { 72, 2, L"CHARA_COLOR" }, + { 73, 1, L"SE_EFFECT" }, + { 74, 9, L"EDIT_MOVE_XYZ" }, + { 75, 3, L"EDIT_EYELID_ANIM" }, + { 76, 2, L"EDIT_INSTRUMENT_ITEM" }, + { 77, 4, L"EDIT_MOTION_LOOP" }, + { 78, 2, L"EDIT_EXPRESSION" }, + { 79, 3, L"EDIT_EYE_ANIM" }, + { 80, 2, L"EDIT_MOUTH_ANIM" }, + { 81, 22, L"EDIT_CAMERA" }, + { 82, 1, L"EDIT_MODE_SELECT" }, + { 83, 2, L"PV_END_FADEOUT" }, + { 84, 1, L"RESERVE" }, + { 85, 6, L"RESERVE" }, + { 86, 1, L"RESERVE" }, + { 87, 9, L"RESERVE" }, + { 88, 2, L"PV_AUTH_LIGHT_PRIORITY" }, + { 89, 3, L"PV_CHARA_LIGHT" }, + { 90, 3, L"PV_STAGE_LIGHT" }, + { 91, 11, L"TARGET_EFFECT" }, + { 92, 3, L"FOG" }, + { 93, 2, L"f2_header" }, + { 94, 3, L"COLOR_CORRECTION" }, + { 95, 3, L"DOF" }, + { 96, 4, L"CHARA_ALPHA" }, + { 97, 1, L"AUTO_CAPTURE_BEGIN" }, + { 98, 1, L"MANUAL_CAPTURE" }, + { 99, 3, L"TOON_EDGE" }, + { 100, 3, L"SHIMMER" }, + { 101, 4, L"ITEM_ALPHA" }, + { 102, 1, L"MOVIE_CUT" }, + { 103, 1, L"CROSSFADE" }, + { 104, 1, L"SUBFRAMERENDER" }, + { 105, 36, L"EVENT_JUDGE" }, + { 106, 2, L"TOON\uFF3FEDGE" }, + { 107, 2, L"FOG_ENABLE" }, + { 108, 112, L"EDIT_CAMERA_BOX" }, + { 109, 1, L"EDIT_STAGE_PARAM" }, + { 110, 1, L"EDIT_CHANGE_FIELD" }, +}; + +static const dsc_func dsc_x_func[] = { + { 0, 0, L"END" }, + { 1, 1, L"TIME" }, + { 2, 4, L"MIKU_MOVE" }, + { 3, 2, L"MIKU_ROT" }, + { 4, 2, L"MIKU_DISP" }, + { 5, 2, L"MIKU_SHADOW" }, + { 6, 12, L"TARGET" }, + { 7, 4, L"SET_MOTION" }, + { 8, 2, L"SET_PLAYDATA" }, + { 9, 6, L"EFFECT" }, + { 10, 2, L"FADEIN_FIELD" }, + { 11, 1, L"EFFECT_OFF" }, + { 12, 6, L"SET_CAMERA" }, + { 13, 2, L"DATA_CAMERA" }, + { 14, 2, L"CHANGE_FIELD" }, + { 15, 1, L"HIDE_FIELD" }, + { 16, 3, L"MOVE_FIELD" }, + { 17, 2, L"FADEOUT_FIELD" }, + { 18, 3, L"EYE_ANIM" }, + { 19, 5, L"MOUTH_ANIM" }, + { 20, 5, L"HAND_ANIM" }, + { 21, 4, L"LOOK_ANIM" }, + { 22, 4, L"EXPRESSION" }, + { 23, 5, L"LOOK_CAMERA" }, + { 24, 2, L"LYRIC" }, + { 25, 0, L"MUSIC_PLAY" }, + { 26, 2, L"MODE_SELECT" }, + { 27, 4, L"EDIT_MOTION" }, + { 28, 2, L"BAR_TIME_SET" }, + { 29, 2, L"SHADOWHEIGHT" }, + { 30, 1, L"EDIT_FACE" }, + { 31, 21, L"DUMMY" }, + { 32, 0, L"PV_END" }, + { 33, 3, L"SHADOWPOS" }, + { 34, 2, L"EDIT_LYRIC" }, + { 35, 5, L"EDIT_TARGET" }, + { 36, 1, L"EDIT_MOUTH" }, + { 37, 1, L"SET_CHARA" }, + { 38, 7, L"EDIT_MOVE" }, + { 39, 1, L"EDIT_SHADOW" }, + { 40, 1, L"EDIT_EYELID" }, + { 41, 2, L"EDIT_EYE" }, + { 42, 1, L"EDIT_ITEM" }, + { 43, 2, L"EDIT_EFFECT" }, + { 44, 1, L"EDIT_DISP" }, + { 45, 2, L"EDIT_HAND_ANIM" }, + { 46, 3, L"AIM" }, + { 47, 3, L"HAND_ITEM" }, + { 48, 1, L"EDIT_BLUSH" }, + { 49, 2, L"NEAR_CLIP" }, + { 50, 2, L"CLOTH_WET" }, + { 51, 3, L"LIGHT_ROT" }, + { 52, 6, L"SCENE_FADE" }, + { 53, 6, L"TONE_TRANS" }, + { 54, 1, L"SATURATE" }, + { 55, 1, L"FADE_MODE" }, + { 56, 2, L"AUTO_BLINK" }, + { 57, 3, L"PARTS_DISP" }, + { 58, 1, L"TARGET_FLYING_TIME" }, + { 59, 2, L"CHARA_SIZE" }, + { 60, 2, L"CHARA_HEIGHT_ADJUST" }, + { 61, 4, L"ITEM_ANIM" }, + { 62, 4, L"CHARA_POS_ADJUST" }, + { 63, 1, L"SCENE_ROT" }, + { 64, 2, L"EDIT_MOT_SMOOTH_LEN" }, + { 65, 1, L"PV_BRANCH_MODE" }, + { 66, 2, L"DATA_CAMERA_START" }, + { 67, 1, L"MOVIE_PLAY" }, + { 68, 1, L"MOVIE_DISP" }, + { 69, 3, L"WIND" }, + { 70, 3, L"OSAGE_STEP" }, + { 71, 3, L"OSAGE_MV_CCL" }, + { 72, 2, L"CHARA_COLOR" }, + { 73, 1, L"SE_EFFECT" }, + { 74, 2, L"CHARA_SHADOW_QUALITY" }, + { 75, 2, L"STAGE_SHADOW_QUALITY" }, + { 76, 2, L"COMMON_LIGHT" }, + { 77, 2, L"TONE_MAP" }, + { 78, 2, L"IBL_COLOR" }, + { 79, 2, L"REFLECTION" }, + { 80, 3, L"CHROMATIC_ABERRATION" }, + { 81, 2, L"STAGE_SHADOW" }, + { 82, 2, L"REFLECTION_QUALITY" }, + { 83, 2, L"PV_END_FADEOUT" }, + { 84, 1, L"CREDIT_TITLE" }, + { 85, 1, L"BAR_POINT" }, + { 86, 1, L"BEAT_POINT" }, + { 87, 0, L"RESERVE" }, + { 88, 2, L"PV_AUTH_LIGHT_PRIORITY" }, + { 89, 3, L"PV_CHARA_LIGHT" }, + { 90, 3, L"PV_STAGE_LIGHT" }, + { 91, 11, L"TARGET_EFFECT" }, + { 92, 3, L"FOG" }, + { 93, 2, L"f2_header" }, + { 94, 3, L"COLOR_CORRECTION" }, + { 95, 3, L"DOF" }, + { 96, 4, L"CHARA_ALPHA" }, + { 97, 1, L"AUTO_CAPTURE_BEGIN" }, + { 98, 1, L"MANUAL_CAPTURE" }, + { 99, 3, L"TOON_EDGE" }, + { 100, 3, L"SHIMMER" }, + { 101, 4, L"ITEM_ALPHA" }, + { 102, 1, L"MOVIE_CUT" }, + { 103, 112, L"EDIT_CAMERA_BOX" }, + { 104, 1, L"EDIT_STAGE_PARAM" }, + { 105, 1, L"EDIT_CHANGE_FIELD" }, + { 106, 7, L"MIKUDAYO_ADJUST" }, + { 107, 2, L"LYRIC_2" }, + { 108, 2, L"LYRIC_READ" }, + { 109, 2, L"LYRIC_READ_2" }, + { 110, 5, L"ANNOTATION" }, + { 111, 2, L"STAGE_EFFECT" }, + { 112, 3, L"SONG_EFFECT" }, + { 113, 3, L"SONG_EFFECT_ATTACH" }, + { 114, 2, L"LIGHT_AUTH" }, + { 115, 2, L"FADE" }, + { 116, 2, L"SET_STAGE_EFFECT_ENV" }, + { 117, 2, L"RESERVE" }, + { 118, 2, L"COMMON_EFFECT_AET_FRONT" }, + { 119, 2, L"COMMON_EFFECT_AET_FRONT_LOW" }, + { 120, 2, L"COMMON_EFFECT_PARTICLE" }, + { 121, 3, L"SONG_EFFECT_ALPHA_SORT" }, + { 122, 5, L"LOOK_CAMERA_FACE_LIMIT" }, + { 123, 3, L"ITEM_LIGHT" }, + { 124, 3, L"CHARA_EFFECT" }, + { 125, 2, L"MARKER" }, + { 126, 3, L"CHARA_EFFECT_CHARA_LIGHT" }, + { 127, 2, L"ENABLE_COMMON_LIGHT_TO_CHARA" }, + { 128, 2, L"ENABLE_FXAA" }, + { 129, 2, L"ENABLE_TEMPORAL_AA" }, + { 130, 2, L"ENABLE_REFLECTION" }, + { 131, 2, L"BANK_BRANCH" }, + { 132, 2, L"BANK_END" }, + { 133, 2, L"" }, + { 134, 2, L"" }, + { 135, 2, L"" }, + { 136, 2, L"" }, + { 137, 2, L"" }, + { 138, 2, L"" }, + { 139, 2, L"" }, + { 140, 2, L"" }, + { 141, 2, L"VR_LIVE_MOVIE" }, + { 142, 2, L"VR_CHEER" }, + { 143, 2, L"VR_CHARA_PSMOVE" }, + { 144, 2, L"VR_MOVE_PATH" }, + { 145, 2, L"VR_SET_BASE" }, + { 146, 2, L"VR_TECH_DEMO_EFFECT" }, + { 147, 2, L"VR_TRANSFORM" }, + { 148, 2, L"GAZE" }, + { 149, 2, L"TECH_DEMO_GESUTRE" }, + { 150, 2, L"VR_CHEMICAL_LIGHT_COLOR" }, + { 151, 5, L"VR_LIVE_MOB" }, + { 152, 9, L"VR_LIVE_HAIR_OSAGE" }, + { 153, 9, L"VR_LIVE_LOOK_CAMERA" }, + { 154, 5, L"VR_LIVE_CHEER" }, + { 155, 3, L"VR_LIVE_GESTURE" }, + { 156, 7, L"VR_LIVE_CLONE" }, + { 157, 7, L"VR_LOOP_EFFECT" }, + { 158, 6, L"VR_LIVE_ONESHOT_EFFECT" }, + { 159, 9, L"VR_LIVE_PRESENT" }, + { 160, 5, L"VR_LIVE_TRANSFORM" }, + { 161, 5, L"VR_LIVE_FLY" }, + { 162, 2, L"VR_LIVE_CHARA_VOICE" }, +}; + +static const dsc_func dsc_vrfl_func[] = { + { 0, 0, L"END" }, + { 1, 1, L"TIME" }, + { 2, 4, L"MIKU_MOVE" }, + { 3, 2, L"MIKU_ROT" }, + { 4, 2, L"MIKU_DISP" }, + { 5, 2, L"MIKU_SHADOW" }, + { 6, 12, L"TARGET" }, + { 7, 4, L"SET_MOTION" }, + { 8, 2, L"SET_PLAYDATA" }, + { 9, 6, L"EFFECT" }, + { 10, 2, L"FADEIN_FIELD" }, + { 11, 1, L"EFFECT_OFF" }, + { 12, 6, L"SET_CAMERA" }, + { 13, 2, L"DATA_CAMERA" }, + { 14, 2, L"CHANGE_FIELD" }, + { 15, 1, L"HIDE_FIELD" }, + { 16, 3, L"MOVE_FIELD" }, + { 17, 2, L"FADEOUT_FIELD" }, + { 18, 3, L"EYE_ANIM" }, + { 19, 5, L"MOUTH_ANIM" }, + { 20, 5, L"HAND_ANIM" }, + { 21, 4, L"LOOK_ANIM" }, + { 22, 4, L"EXPRESSION" }, + { 23, 5, L"LOOK_CAMERA" }, + { 24, 2, L"LYRIC" }, + { 25, 0, L"MUSIC_PLAY" }, + { 26, 2, L"MODE_SELECT" }, + { 27, 4, L"EDIT_MOTION" }, + { 28, 2, L"BAR_TIME_SET" }, + { 29, 2, L"SHADOWHEIGHT" }, + { 30, 1, L"EDIT_FACE" }, + { 31, 21, L"DUMMY" }, + { 32, 0, L"PV_END" }, + { 33, 3, L"SHADOWPOS" }, + { 34, 2, L"EDIT_LYRIC" }, + { 35, 5, L"EDIT_TARGET" }, + { 36, 1, L"EDIT_MOUTH" }, + { 37, 1, L"SET_CHARA" }, + { 38, 7, L"EDIT_MOVE" }, + { 39, 1, L"EDIT_SHADOW" }, + { 40, 1, L"EDIT_EYELID" }, + { 41, 2, L"EDIT_EYE" }, + { 42, 1, L"EDIT_ITEM" }, + { 43, 2, L"EDIT_EFFECT" }, + { 44, 1, L"EDIT_DISP" }, + { 45, 2, L"EDIT_HAND_ANIM" }, + { 46, 3, L"AIM" }, + { 47, 3, L"HAND_ITEM" }, + { 48, 1, L"EDIT_BLUSH" }, + { 49, 2, L"NEAR_CLIP" }, + { 50, 2, L"CLOTH_WET" }, + { 51, 3, L"LIGHT_ROT" }, + { 52, 6, L"SCENE_FADE" }, + { 53, 6, L"TONE_TRANS" }, + { 54, 1, L"SATURATE" }, + { 55, 1, L"FADE_MODE" }, + { 56, 2, L"AUTO_BLINK" }, + { 57, 3, L"PARTS_DISP" }, + { 58, 1, L"TARGET_FLYING_TIME" }, + { 59, 2, L"CHARA_SIZE" }, + { 60, 2, L"CHARA_HEIGHT_ADJUST" }, + { 61, 4, L"ITEM_ANIM" }, + { 62, 4, L"CHARA_POS_ADJUST" }, + { 63, 1, L"SCENE_ROT" }, + { 64, 2, L"EDIT_MOT_SMOOTH_LEN" }, + { 65, 1, L"PV_BRANCH_MODE" }, + { 66, 2, L"DATA_CAMERA_START" }, + { 67, 1, L"MOVIE_PLAY" }, + { 68, 1, L"MOVIE_DISP" }, + { 69, 3, L"WIND" }, + { 70, 3, L"OSAGE_STEP" }, + { 71, 3, L"OSAGE_MV_CCL" }, + { 72, 2, L"CHARA_COLOR" }, + { 73, 1, L"SE_EFFECT" }, + { 74, 2, L"CHARA_SHADOW_QUALITY" }, + { 75, 2, L"STAGE_SHADOW_QUALITY" }, + { 76, 2, L"COMMON_LIGHT" }, + { 77, 2, L"TONE_MAP" }, + { 78, 2, L"IBL_COLOR" }, + { 79, 2, L"REFLECTION" }, + { 80, 3, L"CHROMATIC_ABERRATION" }, + { 81, 2, L"STAGE_SHADOW" }, + { 82, 2, L"REFLECTION_QUALITY" }, + { 83, 2, L"PV_END_FADEOUT" }, + { 84, 1, L"CREDIT_TITLE" }, + { 85, 1, L"BAR_POINT" }, + { 86, 1, L"BEAT_POINT" }, + { 87, 0, L"RESERVE" }, + { 88, 2, L"PV_AUTH_LIGHT_PRIORITY" }, + { 89, 3, L"PV_CHARA_LIGHT" }, + { 90, 3, L"PV_STAGE_LIGHT" }, + { 91, 11, L"TARGET_EFFECT" }, + { 92, 3, L"FOG" }, + { 93, 2, L"f2_header" }, + { 94, 3, L"COLOR_CORRECTION" }, + { 95, 3, L"DOF" }, + { 96, 4, L"CHARA_ALPHA" }, + { 97, 1, L"AUTO_CAPTURE_BEGIN" }, + { 98, 1, L"MANUAL_CAPTURE" }, + { 99, 3, L"TOON_EDGE" }, + { 100, 3, L"SHIMMER" }, + { 101, 4, L"ITEM_ALPHA" }, + { 102, 1, L"MOVIE_CUT" }, + { 103, 112, L"EDIT_CAMERA_BOX" }, + { 104, 1, L"EDIT_STAGE_PARAM" }, + { 105, 1, L"EDIT_CHANGE_FIELD" }, + { 106, 7, L"MIKUDAYO_ADJUST" }, + { 107, 2, L"LYRIC_2" }, + { 108, 2, L"LYRIC_READ" }, + { 109, 2, L"LYRIC_READ_2" }, + { 110, 5, L"ANNOTATION" }, + { 111, 2, L"STAGE_EFFECT" }, + { 112, 3, L"SONG_EFFECT" }, + { 113, 3, L"SONG_EFFECT_ATTACH" }, + { 114, 2, L"LIGHT_AUTH" }, + { 115, 2, L"FADE" }, + { 116, 2, L"SET_STAGE_EFFECT_ENV" }, + { 117, 2, L"RESERVE" }, + { 118, 2, L"COMMON_EFFECT_AET_FRONT" }, + { 119, 2, L"COMMON_EFFECT_AET_FRONT_LOW" }, + { 120, 2, L"COMMON_EFFECT_PARTICLE" }, + { 121, 3, L"SONG_EFFECT_ALPHA_SORT" }, + { 122, 5, L"LOOK_CAMERA_FACE_LIMIT" }, + { 123, 3, L"ITEM_LIGHT" }, + { 124, 3, L"CHARA_EFFECT" }, + { 125, 2, L"MARKER" }, + { 126, 3, L"CHARA_EFFECT_CHARA_LIGHT" }, + { 127, 2, L"ENABLE_COMMON_LIGHT_TO_CHARA" }, + { 128, 2, L"ENABLE_FXAA" }, + { 129, 2, L"ENABLE_TEMPORAL_AA" }, + { 130, 2, L"ENABLE_REFLECTION" }, + { 131, 2, L"BANK_BRANCH" }, + { 132, 2, L"BANK_END" }, + { 133, 2, L"" }, + { 134, 2, L"" }, + { 135, 2, L"" }, + { 136, 2, L"" }, + { 137, 2, L"" }, + { 138, 2, L"VR_LIVE_CHARA_MONITOR_UPDATE_Y" }, + { 139, 2, L"VR_LIVE_POINT_FINGER" }, + { 140, 2, L"VR_LIVE_CHARA_MONITOR" }, + { 141, 2, L"VR_LIVE_MOVIE" }, + { 142, 2, L"VR_CHEER" }, + { 143, 2, L"VR_CHARA_PSMOVE" }, + { 144, 2, L"VR_MOVE_PATH" }, + { 145, 2, L"VR_SET_BASE" }, + { 146, 2, L"VR_TECH_DEMO_EFFECT" }, + { 147, 2, L"VR_TRANSFORM" }, + { 148, 2, L"GAZE" }, + { 149, 2, L"TECH_DEMO_GESUTRE" }, + { 150, 2, L"VR_CHEMICAL_LIGHT_COLOR" }, + { 151, 5, L"VR_LIVE_MOB" }, + { 152, 9, L"VR_LIVE_HAIR_OSAGE" }, + { 153, 9, L"VR_LIVE_LOOK_CAMERA" }, + { 154, 5, L"VR_LIVE_CHEER" }, + { 155, 3, L"VR_LIVE_GESTURE" }, + { 156, 7, L"VR_LIVE_CLONE" }, + { 157, 7, L"VR_LOOP_EFFECT" }, + { 158, 6, L"VR_LIVE_ONESHOT_EFFECT" }, + { 159, 9, L"VR_LIVE_PRESENT" }, + { 160, 7, L"VR_LIVE_TRANSFORM" }, + { 161, 5, L"VR_LIVE_FLY" }, + { 162, 2, L"VR_LIVE_CHARA_VOICE" }, +}; + +inline int32_t dsc_ac101_get_func_length(int32_t id) { return id > -1 && id < 36 ? dsc_ac101_func[id].length : -1; } -int32_t dsc_ac110_get_func_length(int32_t id) { +inline int32_t dsc_ac110_get_func_length(int32_t id) { return id > -1 && id < 37 ? dsc_ac101_func[id].length : -1; } -int32_t dsc_ac120_get_func_length(int32_t id) { +inline int32_t dsc_ac120_get_func_length(int32_t id) { return id > -1 && id < 40 ? dsc_ac101_func[id].length : -1; } -int32_t dsc_ac200_get_func_length(int32_t id) { +inline int32_t dsc_ac200_get_func_length(int32_t id) { return id > -1 && id < 58 ? dsc_ac_func[id].length : -1; } -int32_t dsc_ac210_get_func_length(int32_t id) { +inline int32_t dsc_ac210_get_func_length(int32_t id) { return id > -1 && id < 64 ? dsc_ac_func[id].length : -1; } -int32_t dsc_ac500_get_func_length(int32_t id) { +inline int32_t dsc_ac500_get_func_length(int32_t id) { return id > -1 && id < 65 ? dsc_ac_func[id].length : -1; } -int32_t dsc_ac510_get_func_length(int32_t id) { +inline int32_t dsc_ac510_get_func_length(int32_t id) { return id > -1 && id < 87 ? dsc_ac_func[id].length : -1; } -int32_t dsc_aft101_get_func_length(int32_t id) { +inline int32_t dsc_aft101_get_func_length(int32_t id) { return id > -1 && id < 88 ? dsc_ac_func[id].length : -1; } -int32_t dsc_aft200_get_func_length(int32_t id) { +inline int32_t dsc_aft200_get_func_length(int32_t id) { return id > -1 && id < 90 ? dsc_ac_func[id].length : -1; } -int32_t dsc_aft300_get_func_length(int32_t id) { +inline int32_t dsc_aft300_get_func_length(int32_t id) { return id > -1 && id < 91 ? dsc_ac_func[id].length : -1; } -int32_t dsc_aft310_get_func_length(int32_t id) { +inline int32_t dsc_aft310_get_func_length(int32_t id) { return id > -1 && id < 92 ? dsc_ac_func[id].length : -1; } -int32_t dsc_aft410_get_func_length(int32_t id) { +inline int32_t dsc_aft410_get_func_length(int32_t id) { return id > -1 && id < 105 ? dsc_ac_func[id].length : -1; } -int32_t dsc_aft701_get_func_length(int32_t id) { +inline int32_t dsc_aft701_get_func_length(int32_t id) { return id > -1 && id < 106 ? dsc_ac_func[id].length : -1; } -int32_t dsc_ft_get_func_length(int32_t id) { +inline int32_t dsc_ft_get_func_length(int32_t id) { return id > -1 && id < 107 ? dsc_ac_func[id].length : -1; } -int32_t dsc_psp_get_func_length(int32_t id) { +inline int32_t dsc_psp_get_func_length(int32_t id) { return id > -1 && id < 36 ? dsc_ac101_func[id].length : -1; } -int32_t dsc_2nd_get_func_length(int32_t id) { +inline int32_t dsc_2nd_get_func_length(int32_t id) { return id > -1 && id < 64 ? dsc_f_func[id].length : -1; } -int32_t dsc_f_get_func_length(int32_t id) { +inline int32_t dsc_f_get_func_length(int32_t id) { return id > -1 && id < 84 ? dsc_f_func[id].length : -1; } -int32_t dsc_f2_get_func_length(int32_t id) { +inline int32_t dsc_f2_get_func_length(int32_t id) { return id > -1 && id < 111 ? dsc_f2_func[id].length : -1; } -int32_t dsc_mgf_get_func_length(int32_t id) { +inline int32_t dsc_mgf_get_func_length(int32_t id) { return id > -1 && id < 111 ? dsc_f2_func[id].length : -1; } -int32_t dsc_x_get_func_length(int32_t id) { +inline int32_t dsc_x_get_func_length(int32_t id) { return id > -1 && id < 163 ? dsc_x_func[id].length : -1; } -int32_t dsc_ac200_get_func_length_old(int32_t id) { +inline int32_t dsc_vrfl_get_func_length(int32_t id) { + return id > -1 && id < 163 ? dsc_x_func[id].length : -1; +} + +inline int32_t dsc_ac200_get_func_length_old(int32_t id) { return id > -1 && id < 58 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_ac210_get_func_length_old(int32_t id) { +inline int32_t dsc_ac210_get_func_length_old(int32_t id) { return id > -1 && id < 64 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_ac500_get_func_length_old(int32_t id) { +inline int32_t dsc_ac500_get_func_length_old(int32_t id) { return id > -1 && id < 65 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_ac510_get_func_length_old(int32_t id) { +inline int32_t dsc_ac510_get_func_length_old(int32_t id) { return id > -1 && id < 87 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_aft101_get_func_length_old(int32_t id) { +inline int32_t dsc_aft101_get_func_length_old(int32_t id) { return id > -1 && id < 88 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_aft200_get_func_length_old(int32_t id) { +inline int32_t dsc_aft200_get_func_length_old(int32_t id) { return id > -1 && id < 90 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_aft300_get_func_length_old(int32_t id) { +inline int32_t dsc_aft300_get_func_length_old(int32_t id) { return id > -1 && id < 91 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_aft310_get_func_length_old(int32_t id) { +inline int32_t dsc_aft310_get_func_length_old(int32_t id) { return id > -1 && id < 92 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_aft410_get_func_length_old(int32_t id) { +inline int32_t dsc_aft410_get_func_length_old(int32_t id) { return id > -1 && id < 105 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_aft701_get_func_length_old(int32_t id) { +inline int32_t dsc_aft701_get_func_length_old(int32_t id) { return id > -1 && id < 106 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_ft_get_func_length_old(int32_t id) { +inline int32_t dsc_ft_get_func_length_old(int32_t id) { return id > -1 && id < 107 ? dsc_ac_func[id].length_old : -1; } -int32_t dsc_f_get_func_length_old(int32_t id) { +inline int32_t dsc_f_get_func_length_old(int32_t id) { return id > -1 && id < 84 ? dsc_f_func[id].length_old : -1; } diff --git a/src/KKdLib/dsc.h b/src/KKdLib/dsc.h index 123bee53..88f90bd4 100644 --- a/src/KKdLib/dsc.h +++ b/src/KKdLib/dsc.h @@ -8,11 +8,11 @@ #include "default.h" typedef enum dsc_diff { - DSC_DIFF_EASY = 0, - DSC_DIFF_NORMAL = 1, - DSC_DIFF_HARD = 2, + DSC_DIFF_EASY = 0, + DSC_DIFF_NORMAL = 1, + DSC_DIFF_HARD = 2, DSC_DIFF_EXTREME = 3, - DSC_DIFF_ENCORE = 4, + DSC_DIFF_ENCORE = 4, } dsc_diff; typedef struct dsc_type { @@ -22,9 +22,9 @@ typedef struct dsc_type { typedef enum dsc_f2_mode { DSC_MODE_SYSTEM = 0, - DSC_MODE_MOUTH = 1, - DSC_MODE_SCENE = 2, - DSC_MODE_DAYO = 3, + DSC_MODE_MOUTH = 1, + DSC_MODE_SCENE = 2, + DSC_MODE_DAYO = 3, } dsc_f2_mode; typedef struct dsc_f2_type { @@ -246,526 +246,6 @@ typedef enum dsc_target_id_x { } dsc_target_id_x; #pragma endregion -static const dsc_func dsc_ac101_func[] = { - { 0, 0, L"END" }, - { 1, 1, L"TIME" }, - { 2, 3, L"MIKU_MOVE" }, - { 3, 1, L"MIKU_ROT" }, - { 4, 1, L"MIKU_DISP" }, - { 5, 1, L"MIKU_SHADOW" }, - { 6, 7, L"TARGET" }, - { 7, 3, L"SET_MOTION" }, - { 8, 1, L"SET_PLAYDATA" }, - { 9, 5, L"EFFECT" }, - { 10, 2, L"FADEIN_FIELD" }, - { 11, 1, L"EFFECT_OFF" }, - { 12, 6, L"SET_CAMERA" }, - { 13, 2, L"DATA_CAMERA" }, - { 14, 1, L"CHANGE_FIELD" }, - { 15, 1, L"HIDE_FIELD" }, - { 16, 3, L"MOVE_FIELD" }, - { 17, 2, L"FADEOUT_FIELD" }, - { 18, 2, L"EYE_ANIM" }, - { 19, 3, L"MOUTH_ANIM" }, - { 20, 4, L"HAND_ANIM" }, - { 21, 3, L"LOOK_ANIM" }, - { 22, 3, L"EXPRESSION" }, - { 23, 4, L"LOOK_CAMERA" }, - { 24, 1, L"LYRIC" }, - { 25, 0, L"MUSIC_PLAY" }, - { 26, 1, L"MODE_SELECT" }, - { 27, 2, L"EDIT_MOTION" }, - { 28, 2, L"BAR_TIME_SET" }, - { 29, 1, L"SHADOWHEIGHT" }, - { 30, 2, L"EDIT_FACE" }, - { 31, 19, L"MOVE_CAMERA" }, - { 32, 0, L"PV_END" }, - { 33, 2, L"SHADOWPOS" }, - { 34, 2, L"NEAR_CLIP" }, - { 35, 1, L"CLOTH_WET" }, - { 36, 6, L"SCENE_FADE" }, // AC110 - { 37, 6, L"TONE_TRANS" }, // AC120 - { 38, 1, L"SATURATE" }, - { 39, 1, L"FADE_MODE" }, -}; - -static const dsc_func_ac dsc_ac_func[] = { - { 0, 0, 0, L"END" }, - { 1, 1, 1, L"TIME" }, - { 2, 3, 4, L"MIKU_MOVE" }, - { 3, 1, 2, L"MIKU_ROT" }, - { 4, 1, 2, L"MIKU_DISP" }, - { 5, 1, 2, L"MIKU_SHADOW" }, - { 6, 7, 7, L"TARGET" }, - { 7, 3, 4, L"SET_MOTION" }, - { 8, 1, 2, L"SET_PLAYDATA" }, - { 9, 5, 6, L"EFFECT" }, - { 10, 2, 2, L"FADEIN_FIELD" }, - { 11, 1, 1, L"EFFECT_OFF" }, - { 12, 6, 6, L"SET_CAMERA" }, - { 13, 2, 2, L"DATA_CAMERA" }, - { 14, 1, 1, L"CHANGE_FIELD" }, - { 15, 1, 1, L"HIDE_FIELD" }, - { 16, 3, 3, L"MOVE_FIELD" }, - { 17, 2, 2, L"FADEOUT_FIELD" }, - { 18, 2, 3, L"EYE_ANIM" }, - { 19, 3, 5, L"MOUTH_ANIM" }, - { 20, 4, 5, L"HAND_ANIM" }, - { 21, 3, 4, L"LOOK_ANIM" }, - { 22, 3, 4, L"EXPRESSION" }, - { 23, 4, 5, L"LOOK_CAMERA" }, - { 24, 1, 2, L"LYRIC" }, - { 25, 0, 0, L"MUSIC_PLAY" }, - { 26, 1, 2, L"MODE_SELECT" }, - { 27, 2, 4, L"EDIT_MOTION" }, - { 28, 2, 2, L"BAR_TIME_SET" }, - { 29, 1, 2, L"SHADOWHEIGHT" }, - { 30, 2, 1, L"EDIT_FACE" }, - { 31, 19, 21, L"MOVE_CAMERA" }, - { 32, 0, 0, L"PV_END" }, - { 33, 2, 3, L"SHADOWPOS" }, - { 34, 2, 2, L"EDIT_LYRIC" }, - { 35, 5, 5, L"EDIT_TARGET" }, - { 36, 1, 1, L"EDIT_MOUTH" }, - { 37, 1, 1, L"SET_CHARA" }, - { 38, 7, 7, L"EDIT_MOVE" }, - { 39, 1, 1, L"EDIT_SHADOW" }, - { 40, 1, 1, L"EDIT_EYELID" }, - { 41, 2, 2, L"EDIT_EYE" }, - { 42, 1, 1, L"EDIT_ITEM" }, - { 43, 2, 2, L"EDIT_EFFECT" }, - { 44, 1, 1, L"EDIT_DISP" }, - { 45, 2, 2, L"EDIT_HAND_ANIM" }, - { 46, 3, 3, L"AIM" }, - { 47, 3, 3, L"HAND_ITEM" }, - { 48, 1, 1, L"EDIT_BLUSH" }, - { 49, 2, 2, L"NEAR_CLIP" }, - { 50, 1, 2, L"CLOTH_WET" }, - { 51, 3, 3, L"LIGHT_ROT" }, - { 52, 6, 6, L"SCENE_FADE" }, - { 53, 6, 6, L"TONE_TRANS" }, - { 54, 1, 1, L"SATURATE" }, - { 55, 1, 1, L"FADE_MODE" }, - { 56, 2, 2, L"AUTO_BLINK" }, - { 57, 3, 3, L"PARTS_DISP" }, - { 58, 1, 1, L"TARGET_FLYING_TIME" }, // AC210 - { 59, 2, 2, L"CHARA_SIZE" }, - { 60, 2, 2, L"CHARA_HEIGHT_ADJUST" }, - { 61, 4, 4, L"ITEM_ANIM" }, - { 62, 4, 4, L"CHARA_POS_ADJUST" }, - { 63, 1, 1, L"SCENE_ROT" }, - { 64, 2, 2, L"EDIT_MOT_SMOOTH_LEN" }, // AC500 - { 65, 1, 1, L"PV_BRANCH_MODE" }, // AC510 - { 66, 2, 2, L"DATA_CAMERA_START" }, - { 67, 1, 1, L"MOVIE_PLAY" }, - { 68, 1, 1, L"MOVIE_DISP" }, - { 69, 3, 3, L"WIND" }, - { 70, 3, 3, L"OSAGE_STEP" }, - { 71, 3, 3, L"OSAGE_MV_CCL" }, - { 72, 2, 2, L"CHARA_COLOR" }, - { 73, 1, 1, L"SE_EFFECT" }, - { 74, 9, 9, L"EDIT_MOVE_XYZ" }, - { 75, 3, 3, L"EDIT_EYELID_ANIM" }, - { 76, 2, 2, L"EDIT_INSTRUMENT_ITEM" }, - { 77, 4, 4, L"EDIT_MOTION_LOOP" }, - { 78, 2, 2, L"EDIT_EXPRESSION" }, - { 79, 3, 3, L"EDIT_EYE_ANIM" }, - { 80, 2, 2, L"EDIT_MOUTH_ANIM" }, - { 81, 24, 24, L"EDIT_CAMERA" }, - { 82, 1, 1, L"EDIT_MODE_SELECT" }, - { 83, 2, 2, L"PV_END_FADEOUT" }, - { 84, 1, 1, L"TARGET_FLAG" }, - { 85, 3, 3, L"ITEM_ANIM_ATTACH" }, - { 86, 1, 1, L"SHADOW_RANGE" }, - { 87, 3, 3, L"HAND_SCALE" }, // AFT101 - { 88, 4, 4, L"LIGHT_POS" }, - { 89, 1, 1, L"FACE_TYPE" }, // AFT200 - { 90, 2, 2, L"SHADOW_CAST" }, // AFT300 - { 91, 6, 6, L"EDIT_MOTION_F" }, // AFT310 - { 92, 3, 3, L"FOG" }, // AFT410 - { 93, 2, 2, L"f2_header" }, - { 94, 3, 3, L"COLOR_COLLE" }, - { 95, 3, 3, L"DOF" }, - { 96, 4, 4, L"CHARA_ALPHA" }, - { 97, 1, 1, L"AOTO_CAP" }, - { 98, 1, 1, L"MAN_CAP" }, - { 99, 3, 3, L"TOON" }, - { 100, 3, 3, L"SHIMMER" }, - { 101, 4, 4, L"ITEM_ALPHA" }, - { 102, 1, 1, L"MOVIE_CUT_CHG" }, - { 103, 3, 3, L"CHARA_LIGHT" }, - { 104, 3, 3, L"STAGE_LIGHT" }, - { 105, 8, 8, L"AGEAGE_CTRL" }, // AFT701 - { 106, 2, 2, L"PSE" }, // FT -}; - -static const dsc_func_ac dsc_f_func[] = { - { 0, 0, 0, L"END" }, - { 1, 1, 1, L"TIME" }, - { 2, 3, 4, L"MIKU_MOVE" }, - { 3, 1, 2, L"MIKU_ROT" }, - { 4, 1, 2, L"MIKU_DISP" }, - { 5, 1, 2, L"MIKU_SHADOW" }, - { 6, 7, 11, L"TARGET" }, - { 7, 3, 4, L"SET_MOTION" }, - { 8, 1, 2, L"SET_PLAYDATA" }, - { 9, 5, 6, L"EFFECT" }, - { 10, 2, 2, L"FADEIN_FIELD" }, - { 11, 1, 1, L"EFFECT_OFF" }, - { 12, 6, 6, L"SET_CAMERA" }, - { 13, 2, 2, L"DATA_CAMERA" }, - { 14, 1, 1, L"CHANGE_FIELD" }, - { 15, 1, 1, L"HIDE_FIELD" }, - { 16, 3, 3, L"MOVE_FIELD" }, - { 17, 2, 2, L"FADEOUT_FIELD" }, - { 18, 2, 3, L"EYE_ANIM" }, - { 19, 3, 5, L"MOUTH_ANIM" }, - { 20, 4, 5, L"HAND_ANIM" }, - { 21, 3, 4, L"LOOK_ANIM" }, - { 22, 3, 4, L"EXPRESSION" }, - { 23, 4, 5, L"LOOK_CAMERA" }, - { 24, 1, 2, L"LYRIC" }, - { 25, 0, 0, L"MUSIC_PLAY" }, - { 26, 1, 2, L"MODE_SELECT" }, - { 27, 2, 4, L"EDIT_MOTION" }, - { 28, 2, 2, L"BAR_TIME_SET" }, - { 29, 1, 2, L"SHADOWHEIGHT" }, - { 30, 2, 1, L"EDIT_FACE" }, - { 31, 19, 21, L"MOVE_CAMERA" }, - { 32, 0, 0, L"PV_END" }, - { 33, 2, 3, L"SHADOWPOS" }, - { 34, 2, 2, L"EDIT_LYRIC" }, - { 35, 5, 5, L"EDIT_TARGET" }, - { 36, 1, 1, L"EDIT_MOUTH" }, - { 37, 1, 1, L"SET_CHARA" }, - { 38, 7, 7, L"EDIT_MOVE" }, - { 39, 1, 1, L"EDIT_SHADOW" }, - { 40, 1, 1, L"EDIT_EYELID" }, - { 41, 2, 2, L"EDIT_EYE" }, - { 42, 1, 1, L"EDIT_ITEM" }, - { 43, 2, 2, L"EDIT_EFFECT" }, - { 44, 1, 1, L"EDIT_DISP" }, - { 45, 2, 2, L"EDIT_HAND_ANIM" }, - { 46, 3, 3, L"AIM" }, - { 47, 3, 3, L"HAND_ITEM" }, - { 48, 1, 1, L"EDIT_BLUSH" }, - { 49, 2, 2, L"NEAR_CLIP" }, - { 50, 1, 2, L"CLOTH_WET" }, - { 51, 3, 3, L"LIGHT_ROT" }, - { 52, 6, 6, L"SCENE_FADE" }, - { 53, 6, 6, L"TONE_TRANS" }, - { 54, 1, 1, L"SATURATE" }, - { 55, 1, 1, L"FADE_MODE" }, - { 56, 2, 2, L"AUTO_BLINK" }, - { 57, 3, 3, L"PARTS_DISP" }, - { 58, 1, 1, L"TARGET_FLYING_TIME" }, - { 59, 2, 2, L"CHARA_SIZE" }, - { 60, 2, 2, L"CHARA_HEIGHT_ADJUST" }, - { 61, 4, 4, L"ITEM_ANIM" }, - { 62, 4, 4, L"CHARA_POS_ADJUST" }, - { 63, 1, 1, L"SCENE_ROT" }, - { 64, 2, 2, L"EDIT_MOT_SMOOTH_LEN" }, - { 65, 1, 1, L"PV_BRANCH_MODE" }, - { 66, 2, 2, L"DATA_CAMERA_START" }, - { 67, 1, 1, L"MOVIE_PLAY" }, - { 68, 1, 1, L"MOVIE_DISP" }, - { 69, 3, 3, L"WIND" }, - { 70, 3, 3, L"OSAGE_STEP" }, - { 71, 3, 3, L"OSAGE_MV_CCL" }, - { 72, 2, 2, L"CHARA_COLOR" }, - { 73, 1, 1, L"SE_EFFECT" }, - { 74, 9, 9, L"EDIT_MOVE_XYZ" }, - { 75, 3, 3, L"EDIT_EYELID_ANIM" }, - { 76, 2, 2, L"EDIT_INSTRUMENT_ITEM" }, - { 77, 4, 4, L"EDIT_MOTION_LOOP" }, - { 78, 2, 2, L"EDIT_EXPRESSION" }, - { 79, 3, 3, L"EDIT_EYE_ANIM" }, - { 80, 2, 2, L"EDIT_MOUTH_ANIM" }, - { 81, 24, 24, L"EDIT_CAMERA" }, - { 82, 1, 1, L"EDIT_MODE_SELECT" }, - { 83, 2, 2, L"PV_END_FADEOUT" }, -}; - -static const dsc_func dsc_f2_func[] = { - { 0, 0, L"END" }, - { 1, 1, L"TIME" }, - { 2, 4, L"MIKU_MOVE" }, - { 3, 2, L"MIKU_ROT" }, - { 4, 2, L"MIKU_DISP" }, - { 5, 2, L"MIKU_SHADOW" }, - { 6, 12, L"TARGET" }, - { 7, 4, L"SET_MOTION" }, - { 8, 2, L"SET_PLAYDATA" }, - { 9, 6, L"EFFECT" }, - { 10, 2, L"FADEIN_FIELD" }, - { 11, 1, L"EFFECT_OFF" }, - { 12, 6, L"SET_CAMERA" }, - { 13, 2, L"DATA_CAMERA" }, - { 14, 2, L"CHANGE_FIELD" }, - { 15, 1, L"HIDE_FIELD" }, - { 16, 3, L"MOVE_FIELD" }, - { 17, 2, L"FADEOUT_FIELD" }, - { 18, 3, L"EYE_ANIM" }, - { 19, 5, L"MOUTH_ANIM" }, - { 20, 5, L"HAND_ANIM" }, - { 21, 4, L"LOOK_ANIM" }, - { 22, 4, L"EXPRESSION" }, - { 23, 5, L"LOOK_CAMERA" }, - { 24, 2, L"LYRIC" }, - { 25, 0, L"MUSIC_PLAY" }, - { 26, 2, L"MODE_SELECT" }, - { 27, 4, L"EDIT_MOTION" }, - { 28, 2, L"BAR_TIME_SET" }, - { 29, 2, L"SHADOWHEIGHT" }, - { 30, 1, L"EDIT_FACE" }, - { 31, 21, L"MOVE_CAMERA" }, - { 32, 0, L"PV_END" }, - { 33, 3, L"SHADOWPOS" }, - { 34, 2, L"EDIT_LYRIC" }, - { 35, 5, L"EDIT_TARGET" }, - { 36, 1, L"EDIT_MOUTH" }, - { 37, 1, L"SET_CHARA" }, - { 38, 7, L"EDIT_MOVE" }, - { 39, 1, L"EDIT_SHADOW" }, - { 40, 1, L"EDIT_EYELID" }, - { 41, 2, L"EDIT_EYE" }, - { 42, 1, L"EDIT_ITEM" }, - { 43, 2, L"EDIT_EFFECT" }, - { 44, 1, L"EDIT_DISP" }, - { 45, 2, L"EDIT_HAND_ANIM" }, - { 46, 3, L"AIM" }, - { 47, 3, L"HAND_ITEM" }, - { 48, 1, L"EDIT_BLUSH" }, - { 49, 2, L"NEAR_CLIP" }, - { 50, 2, L"CLOTH_WET" }, - { 51, 3, L"LIGHT_ROT" }, - { 52, 6, L"SCENE_FADE" }, - { 53, 6, L"TONE_TRANS" }, - { 54, 1, L"SATURATE" }, - { 55, 1, L"FADE_MODE" }, - { 56, 2, L"AUTO_BLINK" }, - { 57, 3, L"PARTS_DISP" }, - { 58, 1, L"TARGET_FLYING_TIME" }, - { 59, 2, L"CHARA_SIZE" }, - { 60, 2, L"CHARA_HEIGHT_ADJUST" }, - { 61, 4, L"ITEM_ANIM" }, - { 62, 4, L"CHARA_POS_ADJUST" }, - { 63, 1, L"SCENE_ROT" }, - { 64, 2, L"EDIT_MOT_SMOOTH_LEN" }, - { 65, 1, L"PV_BRANCH_MODE" }, - { 66, 2, L"DATA_CAMERA_START" }, - { 67, 1, L"MOVIE_PLAY" }, - { 68, 1, L"MOVIE_DISP" }, - { 69, 3, L"WIND" }, - { 70, 3, L"OSAGE_STEP" }, - { 71, 3, L"OSAGE_MV_CCL" }, - { 72, 2, L"CHARA_COLOR" }, - { 73, 1, L"SE_EFFECT" }, - { 74, 9, L"EDIT_MOVE_XYZ" }, - { 75, 3, L"EDIT_EYELID_ANIM" }, - { 76, 2, L"EDIT_INSTRUMENT_ITEM" }, - { 77, 4, L"EDIT_MOTION_LOOP" }, - { 78, 2, L"EDIT_EXPRESSION" }, - { 79, 3, L"EDIT_EYE_ANIM" }, - { 80, 2, L"EDIT_MOUTH_ANIM" }, - { 81, 22, L"EDIT_CAMERA" }, - { 82, 1, L"EDIT_MODE_SELECT" }, - { 83, 2, L"PV_END_FADEOUT" }, - { 84, 1, L"RESERVE" }, - { 85, 6, L"RESERVE" }, - { 86, 1, L"RESERVE" }, - { 87, 9, L"RESERVE" }, - { 88, 2, L"PV_AUTH_LIGHT_PRIORITY" }, - { 89, 3, L"PV_CHARA_LIGHT" }, - { 90, 3, L"PV_STAGE_LIGHT" }, - { 91, 11, L"TARGET_EFFECT" }, - { 92, 3, L"FOG" }, - { 93, 2, L"f2_header" }, - { 94, 3, L"COLOR_CORRECTION" }, - { 95, 3, L"DOF" }, - { 96, 4, L"CHARA_ALPHA" }, - { 97, 1, L"AUTO_CAPTURE_BEGIN" }, - { 98, 1, L"MANUAL_CAPTURE" }, - { 99, 3, L"TOON_EDGE" }, - { 100, 3, L"SHIMMER" }, - { 101, 4, L"ITEM_ALPHA" }, - { 102, 1, L"MOVIE_CUT" }, - { 103, 1, L"CROSSFADE" }, - { 104, 1, L"SUBFRAMERENDER" }, - { 105, 36, L"EVENT_JUDGE" }, - { 106, 2, L"TOON\uFF3FEDGE" }, - { 107, 2, L"FOG_ENABLE" }, - { 108, 112, L"EDIT_CAMERA_BOX" }, - { 109, 1, L"EDIT_STAGE_PARAM" }, - { 110, 1, L"EDIT_CHANGE_FIELD" }, -}; - -static const dsc_func dsc_x_func[] = { - { 0, 0, L"END" }, - { 1, 1, L"TIME" }, - { 2, 4, L"MIKU_MOVE" }, - { 3, 2, L"MIKU_ROT" }, - { 4, 2, L"MIKU_DISP" }, - { 5, 2, L"MIKU_SHADOW" }, - { 6, 12, L"TARGET" }, - { 7, 4, L"SET_MOTION" }, - { 8, 2, L"SET_PLAYDATA" }, - { 9, 6, L"EFFECT" }, - { 10, 2, L"FADEIN_FIELD" }, - { 11, 1, L"EFFECT_OFF" }, - { 12, 6, L"SET_CAMERA" }, - { 13, 2, L"DATA_CAMERA" }, - { 14, 2, L"CHANGE_FIELD" }, - { 15, 1, L"HIDE_FIELD" }, - { 16, 3, L"MOVE_FIELD" }, - { 17, 2, L"FADEOUT_FIELD" }, - { 18, 3, L"EYE_ANIM" }, - { 19, 5, L"MOUTH_ANIM" }, - { 20, 5, L"HAND_ANIM" }, - { 21, 4, L"LOOK_ANIM" }, - { 22, 4, L"EXPRESSION" }, - { 23, 5, L"LOOK_CAMERA" }, - { 24, 2, L"LYRIC" }, - { 25, 0, L"MUSIC_PLAY" }, - { 26, 2, L"MODE_SELECT" }, - { 27, 4, L"EDIT_MOTION" }, - { 28, 2, L"BAR_TIME_SET" }, - { 29, 2, L"SHADOWHEIGHT" }, - { 30, 1, L"EDIT_FACE" }, - { 31, 21, L"DUMMY" }, - { 32, 0, L"PV_END" }, - { 33, 3, L"SHADOWPOS" }, - { 34, 2, L"EDIT_LYRIC" }, - { 35, 5, L"EDIT_TARGET" }, - { 36, 1, L"EDIT_MOUTH" }, - { 37, 1, L"SET_CHARA" }, - { 38, 7, L"EDIT_MOVE" }, - { 39, 1, L"EDIT_SHADOW" }, - { 40, 1, L"EDIT_EYELID" }, - { 41, 2, L"EDIT_EYE" }, - { 42, 1, L"EDIT_ITEM" }, - { 43, 2, L"EDIT_EFFECT" }, - { 44, 1, L"EDIT_DISP" }, - { 45, 2, L"EDIT_HAND_ANIM" }, - { 46, 3, L"AIM" }, - { 47, 3, L"HAND_ITEM" }, - { 48, 1, L"EDIT_BLUSH" }, - { 49, 2, L"NEAR_CLIP" }, - { 50, 2, L"CLOTH_WET" }, - { 51, 3, L"LIGHT_ROT" }, - { 52, 6, L"SCENE_FADE" }, - { 53, 6, L"TONE_TRANS" }, - { 54, 1, L"SATURATE" }, - { 55, 1, L"FADE_MODE" }, - { 56, 2, L"AUTO_BLINK" }, - { 57, 3, L"PARTS_DISP" }, - { 58, 1, L"TARGET_FLYING_TIME" }, - { 59, 2, L"CHARA_SIZE" }, - { 60, 2, L"CHARA_HEIGHT_ADJUST" }, - { 61, 4, L"ITEM_ANIM" }, - { 62, 4, L"CHARA_POS_ADJUST" }, - { 63, 1, L"SCENE_ROT" }, - { 64, 2, L"EDIT_MOT_SMOOTH_LEN" }, - { 65, 1, L"PV_BRANCH_MODE" }, - { 66, 2, L"DATA_CAMERA_START" }, - { 67, 1, L"MOVIE_PLAY" }, - { 68, 1, L"MOVIE_DISP" }, - { 69, 3, L"WIND" }, - { 70, 3, L"OSAGE_STEP" }, - { 71, 3, L"OSAGE_MV_CCL" }, - { 72, 2, L"CHARA_COLOR" }, - { 73, 1, L"SE_EFFECT" }, - { 74, 2, L"CHARA_SHADOW_QUALITY" }, - { 75, 2, L"STAGE_SHADOW_QUALITY" }, - { 76, 2, L"COMMON_LIGHT" }, - { 77, 2, L"TONE_MAP" }, - { 78, 2, L"IBL_COLOR" }, - { 79, 2, L"REFLECTION" }, - { 80, 3, L"CHROMATIC_ABERRATION" }, - { 81, 2, L"STAGE_SHADOW" }, - { 82, 2, L"REFLECTION_QUALITY" }, - { 83, 2, L"PV_END_FADEOUT" }, - { 84, 1, L"CREDIT_TITLE" }, - { 85, 1, L"BAR_POINT" }, - { 86, 1, L"BEAT_POINT" }, - { 87, 0, L"RESERVE" }, - { 88, 2, L"PV_AUTH_LIGHT_PRIORITY" }, - { 89, 3, L"PV_CHARA_LIGHT" }, - { 90, 3, L"PV_STAGE_LIGHT" }, - { 91, 11, L"TARGET_EFFECT" }, - { 92, 3, L"FOG" }, - { 93, 2, L"f2_header" }, - { 94, 3, L"COLOR_CORRECTION" }, - { 95, 3, L"DOF" }, - { 96, 4, L"CHARA_ALPHA" }, - { 97, 1, L"AUTO_CAPTURE_BEGIN" }, - { 98, 1, L"MANUAL_CAPTURE" }, - { 99, 3, L"TOON_EDGE" }, - { 100, 3, L"SHIMMER" }, - { 101, 4, L"ITEM_ALPHA" }, - { 102, 1, L"MOVIE_CUT" }, - { 103, 112, L"EDIT_CAMERA_BOX" }, - { 104, 1, L"EDIT_STAGE_PARAM" }, - { 105, 1, L"EDIT_CHANGE_FIELD" }, - { 106, 7, L"MIKUDAYO_ADJUST" }, - { 107, 2, L"LYRIC_2" }, - { 108, 2, L"LYRIC_READ" }, - { 109, 2, L"LYRIC_READ_2" }, - { 110, 5, L"ANNOTATION" }, - { 111, 2, L"STAGE_EFFECT" }, - { 112, 3, L"SONG_EFFECT" }, - { 113, 3, L"SONG_EFFECT_ATTACH" }, - { 114, 2, L"LIGHT_AUTH" }, - { 115, 2, L"FADE" }, - { 116, 2, L"SET_STAGE_EFFECT_ENV" }, - { 117, 2, L"RESERVE" }, - { 118, 2, L"COMMON_EFFECT_AET_FRONT" }, - { 119, 2, L"COMMON_EFFECT_AET_FRONT_LOW" }, - { 120, 2, L"COMMON_EFFECT_PARTICLE" }, - { 121, 3, L"SONG_EFFECT_ALPHA_SORT" }, - { 122, 5, L"LOOK_CAMERA_FACE_LIMIT" }, - { 123, 3, L"ITEM_LIGHT" }, - { 124, 3, L"CHARA_EFFECT" }, - { 125, 2, L"MARKER" }, - { 126, 3, L"CHARA_EFFECT_CHARA_LIGHT" }, - { 127, 2, L"ENABLE_COMMON_LIGHT_TO_CHARA" }, - { 128, 2, L"ENABLE_FXAA" }, - { 129, 2, L"ENABLE_TEMPORAL_AA" }, - { 130, 2, L"ENABLE_REFLECTION" }, - { 131, 2, L"BANK_BRANCH" }, - { 132, 2, L"BANK_END" }, - { 133, 2, L"" }, - { 134, 2, L"" }, - { 135, 2, L"" }, - { 136, 2, L"" }, - { 137, 2, L"" }, - { 138, 2, L"" }, - { 139, 2, L"" }, - { 140, 2, L"" }, - { 141, 2, L"VR_LIVE_MOVIE" }, - { 142, 2, L"VR_CHEER" }, - { 143, 2, L"VR_CHARA_PSMOVE" }, - { 144, 2, L"VR_MOVE_PATH" }, - { 145, 2, L"VR_SET_BASE" }, - { 146, 2, L"VR_TECH_DEMO_EFFECT" }, - { 147, 2, L"VR_TRANSFORM" }, - { 148, 2, L"GAZE" }, - { 149, 2, L"TECH_DEMO_GESUTRE" }, - { 150, 2, L"VR_CHEMICAL_LIGHT_COLOR" }, - { 151, 5, L"VR_LIVE_MOB" }, - { 152, 9, L"VR_LIVE_HAIR_OSAGE" }, - { 153, 9, L"VR_LIVE_LOOK_CAMERA" }, - { 154, 5, L"VR_LIVE_CHEER" }, - { 155, 3, L"VR_LIVE_GESTURE" }, - { 156, 7, L"VR_LIVE_CLONE" }, - { 157, 7, L"VR_LOOP_EFFECT" }, - { 158, 6, L"VR_LIVE_ONESHOT_EFFECT" }, - { 159, 9, L"VR_LIVE_PRESENT" }, - { 160, 5, L"VR_LIVE_TRANSFORM" }, - { 161, 5, L"VR_LIVE_FLY" }, - { 162, 2, L"VR_LIVE_CHARA_VOICE" }, -}; - extern int32_t dsc_ac101_get_func_length(int32_t id); extern int32_t dsc_ac110_get_func_length(int32_t id); extern int32_t dsc_ac120_get_func_length(int32_t id); @@ -786,6 +266,7 @@ extern int32_t dsc_f_get_func_length(int32_t id); extern int32_t dsc_f2_get_func_length(int32_t id); extern int32_t dsc_mgf_get_func_length(int32_t id); extern int32_t dsc_x_get_func_length(int32_t id); +extern int32_t dsc_vrfl_get_func_length(int32_t id); extern int32_t dsc_ac200_get_func_length_old(int32_t id); extern int32_t dsc_ac210_get_func_length_old(int32_t id); diff --git a/src/KKdLib/enbaya.c b/src/KKdLib/enbaya.c index 6482bd64..0a48f586 100644 --- a/src/KKdLib/enbaya.c +++ b/src/KKdLib/enbaya.c @@ -100,7 +100,7 @@ int32_t enb_initialize(uint8_t* data, enb_play_head** play_head) { ph->data_header = head; enb_init(ph, head); - ph->track_data = force_malloc_s(sizeof(enb_track), head->track_count); + ph->track_data = force_malloc_s(enb_track, head->track_count); if (!ph->track_data) { free(ph); diff --git a/src/KKdLib/f2_enrs.c b/src/KKdLib/f2_enrs.c index 8785bcb8..9fcc3914 100644 --- a/src/KKdLib/f2_enrs.c +++ b/src/KKdLib/f2_enrs.c @@ -5,23 +5,51 @@ #include "f2_enrs.h" +typedef enum enrs_value { + ENRS_VALUE_INT8 = 0x0, + ENRS_VALUE_INT16 = 0x1, + ENRS_VALUE_INT32 = 0x2, + ENRS_VALUE_INVALID = 0x3, +} enrs_value; + vector_func(enrs_sub_entry) vector_func(enrs_entry) +static inline bool enrs_length_get_size_type(uint32_t* length, size_t val); +static inline bool enrs_length_get_size(uint32_t* length, size_t val); static bool enrs_read_packed_value_type(stream* s, uint32_t* val, enrs_type* type); static bool enrs_read_packed_value(stream* s, uint32_t* val); static bool enrs_write_packed_value_type(stream* s, uint32_t val, enrs_type type); static bool enrs_write_packed_value(stream* s, uint32_t val); -void enrs_dispose(vector_enrs_entry* e) { +uint32_t enrs_length(vector_enrs_entry* enrs) { enrs_entry* i; + enrs_sub_entry* j; + uint32_t l; - if (!e) - return; + l = 0x10; + for (i = enrs->begin; i != enrs->end; i++) { + i->count = (uint32_t)(i->sub.end - i->sub.begin); + enrs_entry entry = *i; + if (enrs_length_get_size(&l, entry.offset) + || enrs_length_get_size(&l, entry.count) + || enrs_length_get_size(&l, entry.size) + || enrs_length_get_size(&l, entry.repeat_count)) + goto End; - for (i = e->begin; i != e->end; i++) - free(i->sub.begin); - free(e->begin); + if (entry.repeat_count < 1 || entry.count > 0x40000000) + continue; + + for (j = entry.sub.begin; j != entry.sub.end; j++) { + enrs_sub_entry sub = *j; + if (enrs_length_get_size_type(&l, sub.skip_bytes) + || enrs_length_get_size(&l, sub.repeat_count)) + goto End; + } + } +End: + l = align_val(l, 0x10); + return l; } void enrs_read(stream* s, vector_enrs_entry* enrs) { @@ -107,6 +135,28 @@ End: io_write_uint8_t(s, 0); } +void enrs_dispose(vector_enrs_entry* e) { + if (!e) + return; + + for (enrs_entry* i = e->begin; i != e->end; i++) + vector_enrs_sub_entry_free(&i->sub); + vector_enrs_entry_free(e); +} + +static inline bool enrs_length_get_size_type(uint32_t* length, size_t val) { + *length += val < 0x10 ? 1 : val < 0x1000 ? 2 : val < 0x10000000 ? 4 : 1; + return val >= 0x10000000; +} + +static inline bool enrs_length_get_size(uint32_t* length, size_t val) { + if (!length) + return true; + + *length += val < 0x40 ? 1 : val < 0x4000 ? 2 : val < 0x40000000 ? 4 : 1; + return val >= 0x40000000; +} + static bool enrs_read_packed_value_type(stream* s, uint32_t* val, enrs_type* type) { *val = io_read_char(s); enrs_value value = (enrs_value)((*val >> 6) & 0x3); @@ -180,46 +230,3 @@ static bool enrs_write_packed_value(stream* s, uint32_t val) { } return false; } - -FORCE_INLINE bool enrs_length_get_size_type(uint32_t* length, size_t val) { - *length += val < 0x10 ? 1 : val < 0x1000 ? 2 : val < 0x10000000 ? 4 : 1; - return val >= 0x10000000; -} - -FORCE_INLINE bool enrs_length_get_size(uint32_t* length, size_t val) { - if (!length) - return true; - - *length += val < 0x40 ? 1 : val < 0x4000 ? 2 : val < 0x40000000 ? 4 : 1; - return val >= 0x40000000; -} - -uint32_t enrs_length(vector_enrs_entry* enrs) { - enrs_entry* i; - enrs_sub_entry* j; - uint32_t l; - - l = 0x10; - for (i = enrs->begin; i != enrs->end; i++) { - i->count = (uint32_t)(i->sub.end - i->sub.begin); - enrs_entry entry = *i; - if (enrs_length_get_size(&l, entry.offset) - || enrs_length_get_size(&l, entry.count) - || enrs_length_get_size(&l, entry.size) - || enrs_length_get_size(&l, entry.repeat_count)) - goto End; - - if (entry.repeat_count < 1 || entry.count > 0x40000000) - continue; - - for (j = entry.sub.begin; j != entry.sub.end; j++) { - enrs_sub_entry sub = *j; - if (enrs_length_get_size_type(&l, sub.skip_bytes) - || enrs_length_get_size(&l, sub.repeat_count)) - goto End; - } - } -End: - l = align_val(l, 0x10); - return l; -} diff --git a/src/KKdLib/f2_enrs.h b/src/KKdLib/f2_enrs.h index 1d3b56e3..91e22c84 100644 --- a/src/KKdLib/f2_enrs.h +++ b/src/KKdLib/f2_enrs.h @@ -10,19 +10,12 @@ #include "vector.h" typedef enum enrs_type { - ENRS_TYPE_WORD = 0b00, - ENRS_TYPE_DWORD = 0b01, - ENRS_TYPE_QWORD = 0b10, - ENRS_TYPE_INVALID = 0b11, + ENRS_TYPE_WORD = 0x0, + ENRS_TYPE_DWORD = 0x1, + ENRS_TYPE_QWORD = 0x2, + ENRS_TYPE_INVALID = 0x3, } enrs_type; -typedef enum enrs_value { - ENRS_VALUE_INT8 = 0b00, - ENRS_VALUE_INT16 = 0b01, - ENRS_VALUE_INT32 = 0b10, - ENRS_VALUE_INVALID = 0b11, -} enrs_value; - typedef struct enrs_sub_entry { uint32_t skip_bytes; uint32_t repeat_count; @@ -41,7 +34,7 @@ typedef struct enrs_entry { vector(enrs_entry) -void enrs_dispose(vector_enrs_entry* e); +extern uint32_t enrs_length(vector_enrs_entry* enrs); extern void enrs_read(stream* s, vector_enrs_entry* enrs); extern void enrs_write(stream* s, vector_enrs_entry* enrs); -extern uint32_t enrs_length(vector_enrs_entry* enrs); +void enrs_dispose(vector_enrs_entry* e); diff --git a/src/KKdLib/f2_header.c b/src/KKdLib/f2_header.c index 3febaaa8..9b5aecc7 100644 --- a/src/KKdLib/f2_header.c +++ b/src/KKdLib/f2_header.c @@ -5,18 +5,6 @@ #include "f2_header.h" -f2_header* f2_header_init() { - f2_header* h = force_malloc(sizeof(f2_header)); - return h; -} - -void f2_header_dispose(f2_header* h) { - if (!h) - return; - - free(h); -} - void f2_header_read(stream* s, f2_header* h) { memset(h, 0, sizeof(f2_header)); diff --git a/src/KKdLib/f2_header.h b/src/KKdLib/f2_header.h index 5809b5e1..005d259d 100644 --- a/src/KKdLib/f2_header.h +++ b/src/KKdLib/f2_header.h @@ -9,7 +9,10 @@ #include "io_stream.h" typedef struct f2_header { - uint32_t signature; // 0x00 + union { + char signature_char[0x04]; // 0x00 + uint32_t signature; // 0x00 + }; uint32_t data_size; // 0x04 uint32_t length; // 0x08 union { // 0x0C @@ -31,8 +34,6 @@ typedef struct f2_header { uint32_t unknown2[3]; // 0x34 } f2_header; -extern f2_header* f2_header_init(); -extern void f2_header_dispose(f2_header* h); extern void f2_header_read(stream* s, f2_header* h); extern void f2_header_write(stream* s, f2_header* h, bool extended); extern void f2_header_write_end_of_container(stream* s, uint32_t depth); \ No newline at end of file diff --git a/src/KKdLib/f2_pof.c b/src/KKdLib/f2_pof.c index 70908c66..678304b5 100644 --- a/src/KKdLib/f2_pof.c +++ b/src/KKdLib/f2_pof.c @@ -5,9 +5,17 @@ #include "f2_pof.h" +typedef enum pof_value { + POF_VALUE_INVALID = 0x0, + POF_VALUE_INT8 = 0x1, + POF_VALUE_INT16 = 0x2, + POF_VALUE_INT32 = 0x3, +} pof_value; + +static inline bool pof_length_get_size(uint32_t* length, size_t val); static bool pof_write_packed_value(stream* s, size_t val); -FORCE_INLINE size_t pof_read_offsets_count(stream* s) { +inline size_t pof_read_offsets_count(stream* s) { size_t pos = io_get_position(s); size_t i, j, l; pof_value val; @@ -116,31 +124,6 @@ void pof_write(stream* s, vector_size_t* pof, bool shift_x) { io_write_uint8_t(s, 0); } -static bool pof_write_packed_value(stream* s, size_t val) { - if (val < 0x40) - io_write_uint8_t(s, (uint8_t)((POF_VALUE_INT8 << 6) | (val & 0x3F))); - else if (val < 0x4000) { - io_write_uint8_t(s, (uint8_t)((POF_VALUE_INT16 << 6) | ((val >> 8) & 0x3F))); - io_write_uint8_t(s, (uint8_t)val); - } - else if (val < 0x40000000) { - io_write_uint8_t(s, (uint8_t)((POF_VALUE_INT32 << 6) | ((val >> 24) & 0x3F))); - io_write_uint8_t(s, (uint8_t)(val >> 16)); - io_write_uint8_t(s, (uint8_t)(val >> 8)); - io_write_uint8_t(s, (uint8_t)val); - } - else { - io_write_uint8_t(s, POF_VALUE_INVALID << 6); - return true; - } - return false; -} - -FORCE_INLINE bool pof_length_get_size(uint32_t* length, size_t val) { - *length += val < 0x40 ? 1 : val < 0x4000 ? 2 : val < 0x40000000 ? 4 : 1; - return val >= 0x40000000; -} - uint32_t pof_length(vector_size_t* pof, bool shift_x) { vector_size_t p; size_t* i; @@ -174,3 +157,28 @@ uint32_t pof_length(vector_size_t* pof, bool shift_x) { } return l; } + +static inline bool pof_length_get_size(uint32_t* length, size_t val) { + *length += val < 0x40 ? 1 : val < 0x4000 ? 2 : val < 0x40000000 ? 4 : 1; + return val >= 0x40000000; +} + +static bool pof_write_packed_value(stream* s, size_t val) { + if (val < 0x40) + io_write_uint8_t(s, (uint8_t)((POF_VALUE_INT8 << 6) | (val & 0x3F))); + else if (val < 0x4000) { + io_write_uint8_t(s, (uint8_t)((POF_VALUE_INT16 << 6) | ((val >> 8) & 0x3F))); + io_write_uint8_t(s, (uint8_t)val); + } + else if (val < 0x40000000) { + io_write_uint8_t(s, (uint8_t)((POF_VALUE_INT32 << 6) | ((val >> 24) & 0x3F))); + io_write_uint8_t(s, (uint8_t)(val >> 16)); + io_write_uint8_t(s, (uint8_t)(val >> 8)); + io_write_uint8_t(s, (uint8_t)val); + } + else { + io_write_uint8_t(s, POF_VALUE_INVALID << 6); + return true; + } + return false; +} diff --git a/src/KKdLib/f2_pof.h b/src/KKdLib/f2_pof.h index 89c47b5d..b5a6db5d 100644 --- a/src/KKdLib/f2_pof.h +++ b/src/KKdLib/f2_pof.h @@ -9,13 +9,6 @@ #include "io_stream.h" #include "vector.h" -typedef enum pof_value { - POF_VALUE_INVALID = 0b00, - POF_VALUE_INT8 = 0b01, - POF_VALUE_INT16 = 0b10, - POF_VALUE_INT32 = 0b11, -} pof_value; - extern void pof_read(stream* s, vector_size_t* pof, bool shift_x); extern void pof_write(stream* s, vector_size_t* pof, bool shift_x); extern uint32_t pof_length(vector_size_t* pof, bool shift_x); diff --git a/src/KKdLib/f2_struct.c b/src/KKdLib/f2_struct.c index 4e15159e..b330a9c0 100644 --- a/src/KKdLib/f2_struct.c +++ b/src/KKdLib/f2_struct.c @@ -7,22 +7,13 @@ vector_func(f2_struct) -static void f2_struct_dispose_sub(f2_struct* s); static void f2_struct_read_data(stream* s, f2_struct* st, f2_header* h); static void f2_struct_write_inner(stream* s, f2_struct* st, uint32_t depth, bool use_depth, bool shift_x); static void f2_struct_get_length(f2_struct* s, bool shift_x); static void f2_struct_write_pof(stream* s, vector_size_t* pof, uint32_t depth, bool shift_x); static void f2_struct_write_enrs(stream* s, vector_enrs_entry* enrs, uint32_t depth); -f2_struct* f2_struct_init() { - f2_struct* st = force_malloc(sizeof(f2_struct)); - return st; -} - -void f2_struct_dispose(f2_struct* st) { - if (!st) - return; - +void f2_struct_free(f2_struct* st) { if (st->data) free(st->data); if (st->pof.begin) @@ -31,23 +22,8 @@ void f2_struct_dispose(f2_struct* st) { enrs_dispose(&st->enrs); if (st->sub_structs.begin) { for (f2_struct* i = st->sub_structs.begin; i != st->sub_structs.end; i++) - f2_struct_dispose_sub(i); - free(st->sub_structs.begin); - } - free(st); -} - -static void f2_struct_dispose_sub(f2_struct* st) { - if (st->data) - free(st->data); - if (st->pof.begin) - vector_size_t_free(&st->pof); - if (st->enrs.begin) - enrs_dispose(&st->enrs); - if (st->sub_structs.begin) { - for (f2_struct* i = st->sub_structs.begin; i != st->sub_structs.end; i++) - f2_struct_dispose_sub(i); - free(st->sub_structs.begin); + f2_struct_free(i); + vector_f2_struct_free(&st->sub_structs); } } @@ -109,6 +85,45 @@ void f2_struct_write_memory(f2_struct* st, void** data, size_t* length, bool use io_dispose(s); } +static void f2_struct_get_length(f2_struct* s, bool shift_x) { + bool has_enrs, has_pof, has_sub_structs; + f2_struct* i; + uint32_t l; + vector_f2_struct ls; + + has_pof = s->pof.end - s->pof.begin > 0 ? true : false; + has_enrs = s->enrs.end - s->enrs.begin > 0 ? true : false; + has_sub_structs = s->sub_structs.end - s->sub_structs.begin > 0 ? true : false; + + s->header.section_size = s->data ? (uint32_t)s->length : 0; + + l = s->header.section_size; + if (has_enrs) { + uint32_t len = enrs_length(&s->enrs); + l += 0x20 + align_val(len, 0x10); + } + + if (has_pof) { + uint32_t len = pof_length(&s->pof, shift_x); + l += 0x20 + align_val(len, 0x10); + } + + if (has_sub_structs) { + ls = s->sub_structs; + for (i = ls.begin; i != ls.end; i++) { + f2_struct_get_length(i, shift_x); + l += i->header.data_size; + l += i->header.length; + } + s->sub_structs = ls; + } + + if (has_pof || has_sub_structs) + l += 0x20; + + s->header.data_size = l; +} + static void f2_struct_read_data(stream* s, f2_struct* st, f2_header* h) { uint32_t l = h->use_section_size ? h->section_size : h->data_size; uint32_t depth = h->depth; @@ -146,8 +161,8 @@ static void f2_struct_read_data(stream* s, f2_struct* st, f2_header* h) { lastSig = sig; } - if (!(st->sub_structs.end - st->sub_structs.begin)) - free(st->sub_structs.begin); + if (st->sub_structs.end - st->sub_structs.begin < 1) + vector_f2_struct_free(&st->sub_structs); } static void f2_struct_write_inner(stream* s, f2_struct* st, uint32_t depth, bool use_depth, bool shift_x) { @@ -168,45 +183,6 @@ static void f2_struct_write_inner(stream* s, f2_struct* st, uint32_t depth, bool f2_header_write_end_of_container(s, 0); } -static void f2_struct_get_length(f2_struct* s, bool shift_x) { - bool has_enrs, has_pof, has_sub_structs; - f2_struct* i; - uint32_t l; - vector_f2_struct ls; - - has_pof = (s->pof.end - s->pof.begin) > 0 ? true : false; - has_enrs = (s->enrs.end - s->enrs.begin) > 0 ? true : false; - has_sub_structs = (s->sub_structs.end - s->sub_structs.begin) > 0 ? true : false; - - s->header.section_size = s->data ? (uint32_t)s->length : 0; - - l = s->header.section_size; - if (has_enrs) { - uint32_t len = enrs_length(&s->enrs); - l += 0x20 + align_val(len, 0x10); - } - - if (has_pof) { - uint32_t len = pof_length(&s->pof, shift_x); - l += 0x20 + align_val(len, 0x10); - } - - if (has_sub_structs) { - ls = s->sub_structs; - for (i = ls.begin; i != ls.end; i++) { - f2_struct_get_length(i, shift_x); - l += i->header.data_size; - l += i->header.length; - } - s->sub_structs = ls; - } - - if (has_pof || has_sub_structs) - l += 0x20; - - s->header.data_size = l; -} - static void f2_struct_write_pof(stream* s, vector_size_t* pof, uint32_t depth, bool shift_x) { size_t len = pof_length(pof, shift_x); f2_header h; diff --git a/src/KKdLib/f2_struct.h b/src/KKdLib/f2_struct.h index 4094408f..4ae2426f 100644 --- a/src/KKdLib/f2_struct.h +++ b/src/KKdLib/f2_struct.h @@ -25,8 +25,7 @@ struct f2_struct { vector_size_t pof; }; -extern f2_struct* f2_struct_init(); -extern void f2_struct_dispose(f2_struct* st); +extern void f2_struct_free(f2_struct* s); extern void f2_struct_read(f2_struct* st, char* path); extern void f2_struct_wread(f2_struct* st, wchar_t* path); extern void f2_struct_read_memory(f2_struct* st, void* data, size_t length); diff --git a/src/KKdLib/farc.c b/src/KKdLib/farc.c index adbfd71f..4ce46cf7 100644 --- a/src/KKdLib/farc.c +++ b/src/KKdLib/farc.c @@ -7,6 +7,7 @@ #include "aes.h" #include "io_deflate.h" #include "io_path.h" +#include "str_utils.h" #include "utf8.h" static const char key[] = { @@ -21,32 +22,17 @@ static const char keyFT[] = { vector_func(farc_file) +static errno_t farc_get_files(farc* f); +static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool get_files); static errno_t farc_read_header(farc* f, stream* s); static void farc_unpack_files(farc* f, stream* s, bool save); static void farc_unpack_file(farc* f, stream* s, farc_file* ff); -static errno_t farc_get_files(farc* f); -static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool get_files); farc* farc_init() { farc* f = force_malloc(sizeof(farc)); return f; } -void farc_dispose(farc* f) { - if (!f) - return; - - for (farc_file* i = f->files.begin; i != f->files.end; i++) { - free(i->name); - free(i->data); - } - - vector_farc_file_free(&f->files); - free(f->file_path); - free(f->directory_path); - free(f); -} - void farc_read(farc* f, char* path, bool unpack, bool save) { if (!f || !path) return; @@ -62,22 +48,20 @@ void farc_wread(farc* f, wchar_t* path, bool unpack, bool save) { memset(f, 0, sizeof(farc)); - wchar_t* full_path_buf = force_malloc_s(sizeof(wchar_t), MAX_PATH); - full_path_buf = _wfullpath(full_path_buf, path, MAX_PATH); + wchar_t full_path_buf[MAX_PATH]; + wchar_t* full_path = _wfullpath(full_path_buf, path, MAX_PATH); - if (!full_path_buf) + if (!full_path) return; - else if (!path_wcheck_file_exists(full_path_buf)) { - free(full_path_buf); + else if (!path_wcheck_file_exists(full_path_buf)) return; - } size_t full_path_buf_len = wcslen(full_path_buf); - f->file_path = force_malloc_s(sizeof(wchar_t), full_path_buf_len + 1); - memcpy(f->file_path, full_path_buf, sizeof(wchar_t) * (full_path_buf_len + 1)); - free(full_path_buf); - - f->directory_path = path_wget_without_extension(f->file_path); + wcsncpy_s(f->file_path, MAX_PATH, full_path_buf, full_path_buf_len + 1); + wcsncpy_s(f->directory_path, MAX_PATH, full_path_buf, full_path_buf_len + 1); + wchar_t* dot = wcsrchr(f->directory_path, L'.'); + if (dot) + *dot = 0; stream* s = io_wopen(f->file_path, L"rb"); if (s->io.stream && !farc_read_header(f, s) && unpack) @@ -85,240 +69,6 @@ void farc_wread(farc* f, wchar_t* path, bool unpack, bool save) { io_dispose(s); } -static errno_t farc_read_header(farc* f, stream* s) { - if (!f || !s) - return -1; - - f->signature = io_read_int32_t(s); - if (f->signature != FARC_FArc && f->signature != FARC_FArC && f->signature != FARC_FARC) - return -2; - - f->ft = false; - - int32_t header_length = io_read_int32_t_reverse_endianess(s, true); - if (f->signature == FARC_FARC) { - f->type = (farc_type)io_read_int32_t_reverse_endianess(s, true); - io_read_int32_t(s); - int32_t farc_mode = io_read_int32_t_reverse_endianess(s, true); - - f->ft = (f->type & FARC_DATA_AES) && (farc_mode & (farc_mode - 1)); - } - - for (farc_file* i = f->files.begin; i != f->files.end; i++) { - free(i->data); - free(i->name); - } - vector_farc_file_free(&f->files); - if (f->ft) { - io_set_position(s, 0x10, IO_SEEK_SET); - - header_length -= 0x08; - uint8_t* d_t = force_malloc(header_length); - io_read(s, d_t, header_length); - - struct aes_ctx ctx; - aes_init_ctx(&ctx, keyFT); - aes_cbc_decrypt_buffer(&ctx, d_t, header_length); - - uint8_t* dt = d_t; - dt += 0x10 + sizeof(int32_t); - int32_t length; - length = reverse_endianess_int32_t(*(int32_t*)dt); - if (length == 1) { - dt += sizeof(int32_t); - length = reverse_endianess_int32_t(*(int32_t*)dt); - } - else - length = 0; - dt += sizeof(int32_t) * 2; - - if (length == 0) { - size_t count = 0; - uint8_t* position = dt; - while (dt - d_t < header_length) { - while (*dt) - dt++; - dt++; - dt += sizeof(int32_t) * 4; - count++; - } - dt = position; - length = (int32_t)count; - } - - vector_farc_file_append(&f->files, length); - f->files.end = &f->files.begin[length]; - - char* file = force_malloc(BUF_SIZE); - for (farc_file* i = f->files.begin; i != f->files.end; i++) { - size_t f_len = 0; - while (*dt) { - file[f_len] = *dt; - f_len++; - dt++; - } - dt++; - file[f_len] = 0; - - i->name = utf8_decode(file); - i->offset = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[0]); - i->size_compressed = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[1]); - i->size_uncompressed = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[2]); - i->type = reverse_endianess_int32_t(((int32_t*)dt)[3]); - dt += sizeof(int32_t) * 4; - } - free(file); - free(d_t); - } - else { - int32_t length = 0; - if (f->signature == FARC_FARC && io_read_int32_t_reverse_endianess(s, true) == 1) - length = io_read_int32_t_reverse_endianess(s, true); - - io_read_int32_t(s); - - if (length == 0) { - size_t count = 0; - size_t position = io_get_position(s); - while (io_get_position(s) < header_length) { - while (io_read_char(s)); - io_read_int32_t(s); - if (f->signature != FARC_FArc) - io_read_int32_t(s); - io_read_int32_t(s); - count++; - } - io_set_position(s, position, IO_SEEK_SET); - length = (int32_t)count; - } - - vector_farc_file_append(&f->files, length); - f->files.end = &f->files.begin[length]; - - char* file = force_malloc(BUF_SIZE); - for (farc_file* i = f->files.begin; i != f->files.end; i++) { - char c; - size_t f_len = 0; - while (c = io_read_char(s)) { - file[f_len] = c; - f_len++; - } - file[f_len] = 0; - - i->name = utf8_decode(file); - i->offset = (size_t)io_read_int32_t_reverse_endianess(s, true); - if (f->signature != FARC_FArc) - i->size_compressed = (size_t)io_read_int32_t_reverse_endianess(s, true); - i->size_uncompressed = (size_t)io_read_int32_t_reverse_endianess(s, true); - } - free(file); - } - return 0; -} - -static void farc_unpack_files(farc* f, stream* s, bool save) { - if (!f || !s) - return; - - if (!save) { - for (farc_file* i = f->files.begin; i != f->files.end; i++) - farc_unpack_file(f, s, i); - return; - } - - size_t max_path_len = 0; - size_t dir_len = wcslen(f->directory_path); - for (farc_file* i = f->files.begin; i != f->files.end; i++) { - size_t path_len = dir_len + 1 + wcslen(i->name); - if (max_path_len < path_len) - max_path_len = path_len; - } - - CreateDirectoryW(f->directory_path, 0); - wchar_t* temp_path = force_malloc_s(sizeof(wchar_t), max_path_len + 1); - memcpy(temp_path, f->directory_path, sizeof(wchar_t) * dir_len); - temp_path[dir_len] = L'\\'; - - for (farc_file* i = f->files.begin; i != f->files.end; i++) { - farc_unpack_file(f, s, i); - - size_t path_len = wcslen(i->name); - memcpy(temp_path + dir_len + 1, i->name, sizeof(wchar_t) * path_len); - temp_path[dir_len + 1 + path_len] = L'\0'; - - if (i->data) { - stream* temp_s = io_wopen(temp_path, L"wb"); - if (temp_s->io.stream) - io_write(temp_s, i->data, i->size_uncompressed); - io_dispose(temp_s); - free(i->data); - } - } - free(temp_path); -} - -static void farc_unpack_file(farc* f, stream* s, farc_file* ff) { - if (!f || !s) - return; - - if (ff->data) - free(ff->data); - - ff->data = force_malloc(ff->size_uncompressed); - io_set_position(s, ff->offset, IO_SEEK_SET); - - if (f->signature != FARC_FARC) { - if (f->signature == FARC_FArC) { - void* temp_comp = force_malloc(ff->size_compressed); - io_read(s, temp_comp, ff->size_compressed); - deflate_decompress(temp_comp, ff->size_compressed, - &ff->data, ff->size_uncompressed, DEFLATE_MODE_GZIP); - free(temp_comp); - } - else - io_read(s, ff->data, ff->size_uncompressed); - } - else { - bool aes = (f->type | ff->type) & FARC_DATA_AES; - bool gzip = (f->type | ff->type) & FARC_DATA_GZIP; - if (aes | gzip) { - size_t size_comp = aes ? align_val(ff->size_compressed, 0x10LL) : ff->size_compressed; - void* temp_comp = force_malloc(size_comp); - io_read(s, temp_comp, size_comp); - - if (aes) { - struct aes_ctx ctx; - if (f->ft) { - aes_init_ctx(&ctx, keyFT); - aes_cbc_decrypt_buffer(&ctx, temp_comp, size_comp); - } - else { - aes_init_ctx(&ctx, key); - aes_ecb_decrypt_buffer(&ctx, temp_comp, size_comp); - } - } - - if (aes && f->ft) { - if (gzip) - deflate_decompress((void*)((uint64_t)temp_comp + 0x10), size_comp - 0x10, - &ff->data, ff->size_uncompressed, DEFLATE_MODE_GZIP); - else - memcpy(ff->data, (void*)((uint64_t)temp_comp + 0x10), ff->size_uncompressed); - } - else { - if (gzip) - deflate_decompress(temp_comp, size_comp, - &ff->data, ff->size_uncompressed, DEFLATE_MODE_GZIP); - else - memcpy(ff->data, temp_comp, ff->size_uncompressed); - } - free(temp_comp); - } - else - io_read(s, ff->data, ff->size_uncompressed); - } -} - farc_file* farc_read_file(farc* f, char* name) { if (!f || !name) return 0; @@ -355,22 +105,18 @@ void farc_wwrite(farc* f, wchar_t* path, farc_compress_mode mode, bool get_files if (get_files) memset(f, 0, sizeof(farc)); - wchar_t* full_path_buf = force_malloc_s(sizeof(wchar_t), MAX_PATH); - full_path_buf = _wfullpath(full_path_buf, path, MAX_PATH); + wchar_t full_path_buf[MAX_PATH]; + wchar_t* full_path = _wfullpath(full_path_buf, path, MAX_PATH); - if (!full_path_buf) + if (!full_path) return; - else if (get_files && !path_wcheck_directory_exists(full_path_buf)) { - free(full_path_buf); + else if (get_files && !path_wcheck_directory_exists(full_path_buf)) return; - } size_t full_path_buf_len = wcslen(full_path_buf); - f->directory_path = force_malloc_s(sizeof(wchar_t), full_path_buf_len + 1); - memcpy(f->directory_path, full_path_buf, sizeof(wchar_t) * (full_path_buf_len + 1)); - free(full_path_buf); - - f->file_path = path_wadd_extension(f->directory_path, L".farc"); + wcsncpy_s(f->directory_path, MAX_PATH, full_path_buf, full_path_buf_len + 1); + wcsncpy_s(f->file_path, MAX_PATH, full_path_buf, full_path_buf_len + 1); + wcsncat_s(f->file_path, MAX_PATH, L".farc", 6); if (!get_files || (get_files && !farc_get_files(f))) { stream* s = io_wopen(f->file_path, L"wb"); @@ -380,6 +126,19 @@ void farc_wwrite(farc* f, wchar_t* path, farc_compress_mode mode, bool get_files } } +void farc_dispose(farc* f) { + if (!f) + return; + + for (farc_file* i = f->files.begin; i != f->files.end; i++) { + free(i->name); + free(i->data); + } + + vector_farc_file_free(&f->files); + free(f); +} + static errno_t farc_get_files(farc* f) { for (farc_file* i = f->files.begin; i != f->files.end; i++) { free(i->data); @@ -390,7 +149,7 @@ static errno_t farc_get_files(farc* f) { vector_ptr_wchar_t files = (vector_ptr_wchar_t){ 0, 0, 0 }; path_wget_files(&files, f->directory_path); - if (!(files.end - files.begin)) { + if (files.end - files.begin < 1) { vector_ptr_wchar_t_free(&files, 0); return -1; } @@ -400,7 +159,7 @@ static errno_t farc_get_files(farc* f) { for (farc_file* i = f->files.begin; i != f->files.end; i++) { memset(i, 0, sizeof(farc_file)); size_t len = wcslen(files.begin[i - f->files.begin]); - i->name = force_malloc_s(sizeof(wchar_t), len + 1); + i->name = force_malloc_s(wchar_t, len + 1); memcpy(i->name, files.begin[i - f->files.begin], sizeof(wchar_t) * (len + 1)); } vector_ptr_wchar_t_free(&files, 0); @@ -410,7 +169,7 @@ static errno_t farc_get_files(farc* f) { static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool get_files) { bool plain = false; for (farc_file* i = f->files.begin; i != f->files.end; i++) { - wchar_t* ext = path_wget_extension(i->name); + wchar_t* ext = str_utils_wget_extension(i->name); bool is_a3da = wcscmp(ext, L".a3da") == 0; bool is_diva = wcscmp(ext, L".diva") == 0; bool is_farc = wcscmp(ext, L".farc") == 0; @@ -454,7 +213,7 @@ static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool ge break; } - char** files_utf8 = force_malloc_s(sizeof(char*), f->files.end - f->files.begin); + char** files_utf8 = force_malloc_s(char*, f->files.end - f->files.begin); if (mode == FARC_COMPRESS_FArc) for (farc_file* i = f->files.begin; i != f->files.end; i++) { files_utf8[i - f->files.begin] = utf8_encode(i->name); @@ -477,7 +236,7 @@ static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool ge aes_init_ctx(&ctx, key); if (get_files) { - wchar_t* temp = force_malloc_s(sizeof(wchar_t), dir_len + 2 + MAX_PATH); + wchar_t* temp = force_malloc_s(wchar_t, dir_len + 2 + MAX_PATH); memcpy(temp, f->directory_path, sizeof(wchar_t) * dir_len); temp[dir_len] = L'\\'; for (farc_file* i = f->files.begin; i != f->files.end; i++) { @@ -494,7 +253,7 @@ static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool ge size_t file_len = io_get_position(s_t); io_set_position(s_t, 0, IO_SEEK_SET); - i->size_uncompressed = file_len; + i->size = file_len; void* t = force_malloc(file_len); io_read(s_t, t, file_len); @@ -552,14 +311,14 @@ static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool ge else for (farc_file* i = f->files.begin; i != f->files.end; i++) { i->offset = io_get_position(s); - size_t file_len = i->size_uncompressed; + size_t file_len = i->size; void* t = i->data; if (mode == FARC_COMPRESS_FARC_AES || mode == FARC_COMPRESS_FARC_GZIP_AES) { void* t1; size_t t1_len; if (mode == FARC_COMPRESS_FARC_GZIP_AES) { - deflate_compress(t, file_len, &t1, &t1_len, 9, DEFLATE_MODE_GZIP); + deflate_compress(t, file_len, &t1, &t1_len, 12, DEFLATE_MODE_GZIP); free(t); } else { @@ -613,19 +372,19 @@ static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool ge io_write_int32_t_reverse_endianess(s, (int32_t)header_length, true); io_write_int32_t_reverse_endianess(s, f->type, true); io_write_int32_t_reverse_endianess(s, 0x00, true); - io_write_int32_t_reverse_endianess(s, 0x10, true); + io_write_int32_t_reverse_endianess(s, 0x40, true); io_write_int32_t_reverse_endianess(s, 0x00, true); io_write_int32_t_reverse_endianess(s, 0x00, true); break; case FARC_COMPRESS_FArC: io_write_int32_t(s, FARC_FArC); io_write_int32_t_reverse_endianess(s, (int32_t)header_length, true); - io_write_int32_t_reverse_endianess(s, 0x10, true); + io_write_int32_t_reverse_endianess(s, 0x01, true); break; default: io_write_int32_t(s, FARC_FArc); io_write_int32_t_reverse_endianess(s, (int32_t)header_length, true); - io_write_int32_t_reverse_endianess(s, 0x10, true); + io_write_int32_t_reverse_endianess(s, 0x01, true); break; } @@ -634,7 +393,7 @@ static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool ge io_write(s, files_utf8[i - f->files.begin], strlen(files_utf8[i - f->files.begin])); io_write_uint8_t(s, 0x00); io_write_int32_t_reverse_endianess(s, (int32_t)i->offset, true); - io_write_int32_t_reverse_endianess(s, (int32_t)i->size_uncompressed, true); + io_write_int32_t_reverse_endianess(s, (int32_t)i->size, true); } else for (farc_file* i = f->files.begin; i != f->files.end; i++) { @@ -642,7 +401,7 @@ static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool ge io_write_uint8_t(s, 0x00); io_write_int32_t_reverse_endianess(s, (int32_t)i->offset, true); io_write_int32_t_reverse_endianess(s, (int32_t)i->size_compressed, true); - io_write_int32_t_reverse_endianess(s, (int32_t)i->size_uncompressed, true); + io_write_int32_t_reverse_endianess(s, (int32_t)i->size, true); } align = align_val(align, 0x10) - align; @@ -657,3 +416,234 @@ static void farc_pack_files(farc* f, stream* s, farc_compress_mode mode, bool ge free(files_utf8[i - f->files.begin]); free(files_utf8); } + +static errno_t farc_read_header(farc* f, stream* s) { + if (!f || !s) + return -1; + + io_set_position(s, 0, IO_SEEK_SET); + f->signature = io_read_int32_t(s); + if (f->signature != FARC_FArc && f->signature != FARC_FArC && f->signature != FARC_FARC) + return -2; + + f->ft = false; + + int32_t header_length = io_read_int32_t_reverse_endianess(s, true); + if (f->signature == FARC_FARC) { + f->type = (farc_type)io_read_int32_t_reverse_endianess(s, true); + io_read_int32_t(s); + int32_t farc_mode = io_read_int32_t_reverse_endianess(s, true); + + f->ft = (f->type & FARC_DATA_AES) && (farc_mode & (farc_mode - 1)); + if (f->ft) + header_length -= 0x08; + else + header_length -= 0x0C; + } + + for (farc_file* i = f->files.begin; i != f->files.end; i++) { + free(i->data); + free(i->name); + } + vector_farc_file_free(&f->files); + + uint8_t* d_t; + uint8_t* dt; + int32_t length = 0; + + dt = d_t = force_malloc(header_length); + io_read(s, d_t, header_length); + if (f->ft) { + io_set_position(s, 0x10, IO_SEEK_SET); + + struct aes_ctx ctx; + aes_init_ctx(&ctx, keyFT); + aes_cbc_decrypt_buffer(&ctx, d_t, header_length); + dt += 0x10 + sizeof(int32_t); + } + + bool has_per_file_flags = false; + if (f->signature == FARC_FARC) { + if (reverse_endianess_int32_t(*(int32_t*)dt) == 1) { + dt += sizeof(int32_t); + length = reverse_endianess_int32_t(*(int32_t*)dt); + has_per_file_flags = true; + } + dt += sizeof(int32_t); + } + dt += sizeof(int32_t); + + if (length == 0) { + size_t count = 0; + uint8_t* position = dt; + size_t size; + if (has_per_file_flags) + size = sizeof(int32_t) * 4; + else if (f->signature != FARC_FArc) + size = sizeof(int32_t) * 3; + else + size = sizeof(int32_t) * 2; + + while (dt - d_t < header_length) { + while (*dt) + dt++; + dt++; + dt += size; + count++; + } + dt = position; + length = (int32_t)count; + } + + vector_farc_file_append(&f->files, length); + f->files.end = &f->files.begin[length]; + + char* file = force_malloc(BUF_SIZE); + if (has_per_file_flags) + for (farc_file* i = f->files.begin; i != f->files.end; i++) { + size_t f_len = 0; + while (*dt) + file[f_len++] = *dt++; + dt++; + file[f_len] = 0; + + i->name = utf8_decode(file); + i->offset = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[0]); + i->size_compressed = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[1]); + i->size = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[2]); + i->type = reverse_endianess_int32_t(((int32_t*)dt)[3]); + dt += sizeof(int32_t) * 4; + } + else if (f->signature != FARC_FArc) + for (farc_file* i = f->files.begin; i != f->files.end; i++) { + size_t f_len = 0; + while (*dt) + file[f_len++] = *dt++; + dt++; + file[f_len] = 0; + + i->name = utf8_decode(file); + i->offset = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[0]); + i->size_compressed = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[1]); + i->size = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[2]); + dt += sizeof(int32_t) * 3; + } + else + for (farc_file* i = f->files.begin; i != f->files.end; i++) { + size_t f_len = 0; + while (*dt) + file[f_len++] = *dt++; + dt++; + file[f_len] = 0; + + i->name = utf8_decode(file); + i->offset = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[0]); + i->size = (size_t)reverse_endianess_int32_t(((int32_t*)dt)[1]); + dt += sizeof(int32_t) * 2; + } + free(file); + return 0; +} + +static void farc_unpack_files(farc* f, stream* s, bool save) { + if (!f || !s) + return; + + if (!save) { + for (farc_file* i = f->files.begin; i != f->files.end; i++) + farc_unpack_file(f, s, i); + return; + } + + size_t max_path_len = 0; + size_t dir_len = wcslen(f->directory_path); + for (farc_file* i = f->files.begin; i != f->files.end; i++) { + size_t path_len = dir_len + 1 + wcslen(i->name); + if (max_path_len < path_len) + max_path_len = path_len; + } + + CreateDirectoryW(f->directory_path, 0); + wchar_t* temp_path = force_malloc_s(wchar_t, max_path_len + 1); + memcpy(temp_path, f->directory_path, sizeof(wchar_t) * dir_len); + temp_path[dir_len] = L'\\'; + + for (farc_file* i = f->files.begin; i != f->files.end; i++) { + farc_unpack_file(f, s, i); + + size_t path_len = wcslen(i->name); + memcpy(temp_path + dir_len + 1, i->name, sizeof(wchar_t) * path_len); + temp_path[dir_len + 1 + path_len] = L'\0'; + + if (i->data) { + stream* temp_s = io_wopen(temp_path, L"wb"); + if (temp_s->io.stream) + io_write(temp_s, i->data, i->size); + io_dispose(temp_s); + free(i->data); + } + } + free(temp_path); +} + +static void farc_unpack_file(farc* f, stream* s, farc_file* ff) { + if (!f || !s) + return; + + if (ff->data) + free(ff->data); + + ff->data = force_malloc(ff->size); + io_set_position(s, ff->offset, IO_SEEK_SET); + + if (f->signature != FARC_FARC) { + if (f->signature == FARC_FArC) { + void* temp_comp = force_malloc(ff->size_compressed); + io_read(s, temp_comp, ff->size_compressed); + deflate_decompress(temp_comp, ff->size_compressed, + &ff->data, ff->size, DEFLATE_MODE_GZIP); + free(temp_comp); + } + else + io_read(s, ff->data, ff->size); + } + else { + bool aes = (f->type | ff->type) & FARC_DATA_AES; + bool gzip = (f->type | ff->type) & FARC_DATA_GZIP; + if (aes | gzip) { + size_t size_comp = aes ? align_val(ff->size_compressed, 0x10LL) : ff->size_compressed; + void* temp_comp = force_malloc(size_comp); + io_read(s, temp_comp, size_comp); + + if (aes) { + struct aes_ctx ctx; + if (f->ft) { + aes_init_ctx(&ctx, keyFT); + aes_cbc_decrypt_buffer(&ctx, temp_comp, size_comp); + } + else { + aes_init_ctx(&ctx, key); + aes_ecb_decrypt_buffer(&ctx, temp_comp, size_comp); + } + } + + if (aes && f->ft) { + if (gzip) + deflate_decompress((void*)((uint64_t)temp_comp + 0x10), size_comp - 0x10, + &ff->data, ff->size, DEFLATE_MODE_GZIP); + else + memcpy(ff->data, (void*)((uint64_t)temp_comp + 0x10), ff->size); + } + else { + if (gzip) + deflate_decompress(temp_comp, size_comp, + &ff->data, ff->size, DEFLATE_MODE_GZIP); + else + memcpy(ff->data, temp_comp, ff->size); + } + free(temp_comp); + } + else + io_read(s, ff->data, ff->size); + } +} diff --git a/src/KKdLib/farc.h b/src/KKdLib/farc.h index ad65e75b..08a249ee 100644 --- a/src/KKdLib/farc.h +++ b/src/KKdLib/farc.h @@ -16,8 +16,8 @@ typedef enum farc_signature { } farc_signature; typedef enum farc_type { - FARC_DATA_GZIP = 0b010, - FARC_DATA_AES = 0b100, + FARC_DATA_GZIP = 0x2, + FARC_DATA_AES = 0x4, } farc_type; typedef enum farc_compress_mode { @@ -31,8 +31,8 @@ typedef enum farc_compress_mode { typedef struct farc_file { size_t offset; + size_t size; size_t size_compressed; - size_t size_uncompressed; wchar_t* name; uint8_t* data; farc_type type; @@ -41,8 +41,8 @@ typedef struct farc_file { vector(farc_file) typedef struct farc { - wchar_t* file_path; - wchar_t* directory_path; + wchar_t file_path[MAX_PATH]; + wchar_t directory_path[MAX_PATH]; vector_farc_file files; farc_signature signature; farc_type type; @@ -51,10 +51,10 @@ typedef struct farc { } farc; extern farc* farc_init(); -extern void farc_dispose(farc* f); extern void farc_read(farc* f, char* path, bool unpack, bool save); extern void farc_wread(farc* f, wchar_t* path, bool unpack, bool save); extern farc_file* farc_read_file(farc* f, char* name); extern farc_file* farc_wread_file(farc* f, wchar_t* name); extern void farc_write(farc* f, char* path, farc_compress_mode mode, bool get_files); extern void farc_wwrite(farc* f, wchar_t* path, farc_compress_mode mode, bool get_files); +extern void farc_dispose(farc* f); diff --git a/src/KKdLib/half_t.h b/src/KKdLib/half_t.h index 0ab99f42..212b93e7 100644 --- a/src/KKdLib/half_t.h +++ b/src/KKdLib/half_t.h @@ -15,6 +15,9 @@ #define FLOAT16_POSITIVE_INF ((half_t)0x7C00) #define FLOAT16_NEGATIVE_INF ((half_t)0xFC00) +#define HALF_MAX 65504 +#define HALF_MIN 0.00006103515625 + typedef unsigned short half_t; extern half_t reverse_endianess_half_t(half_t value); diff --git a/src/KKdLib/hash.c b/src/KKdLib/hash.c index f06d39a6..cc8f45a2 100644 --- a/src/KKdLib/hash.c +++ b/src/KKdLib/hash.c @@ -6,21 +6,25 @@ #include "hash.h" #include "utf8.h" +const uint64_t hash_fnv1a64_empty = 0xCBF29CE44FD0BFC1; +const uint32_t hash_murmurhash_empty = 0x0CAD3078; + uint64_t hash_fnv1a64(uint8_t* data, size_t length) { // 0x1403B04D0 in SBZV_7.10; FNV 1a 64-bit uint64_t hash = 0xCBF29CE484222325; - for (size_t i = 0; i < length; i++) { - hash ^= data[i]; - hash *= 0x100000001B3; - } + if (data) + for (size_t i = 0; i < length; i++) { + hash ^= data[i]; + hash *= 0x100000001B3; + } return (hash >> 32) ^ hash; } -uint64_t hash_char_fnv1a64(char* data) { +inline uint64_t hash_char_fnv1a64(char* data) { uint64_t hash = hash_fnv1a64((uint8_t*)data, strlen(data)); return hash; } -uint64_t hash_wchar_t_fnv1a64(wchar_t* data) { +inline uint64_t hash_wchar_t_fnv1a64(wchar_t* data) { char* temp = utf8_encode(data); uint64_t hash = hash_fnv1a64((uint8_t*)temp, strlen(temp)); free(temp); @@ -37,119 +41,116 @@ uint32_t hash_murmurhash(uint8_t* data, size_t length, const int32_t r = 16; hash = seed + 0xDEADBEEF; - if (already_upper) { - if (big_endian) - for (i = 0; length > 3; length -= 4, i += 4) { - b = (uint32_t)data[i + 3] | ((uint32_t)data[i + 2] << 8) - | ((uint32_t)data[i + 1] << 16) | ((uint32_t)data[i + 0] << 24); - hash += b; - hash *= m; - hash ^= hash >> r; - } - else - for (i = 0; length > 3; length -= 4, i += 4) { - b = (uint32_t)data[i + 0] | ((uint32_t)data[i + 1] << 8) - | ((uint32_t)data[i + 2] << 16) | ((uint32_t)data[i + 3] << 24); - hash += b; - hash *= m; - hash ^= hash >> r; - } - - if (length > 0) { - if (length > 1) { - if (length > 2) - hash += (uint32_t)data[i + 2] << 16; - hash += (uint32_t)data[i + 1] << 8; - } - hash += data[i]; - hash *= m; - hash ^= hash >> r; - } - } - else { - if (big_endian) - for (i = 0; length > 3; length -= 4, i += 4) { - b = (uint32_t)data[i + 3] | ((uint32_t)data[i + 2] << 8) - | ((uint32_t)data[i + 1] << 16) | ((uint32_t)data[i + 0] << 24); - - a = b & 0xFF; - if (a > 0x60 && a < 0x7B) - a -= 0x20; - b = (b & 0xFFFFFF00) | a; - - a = (b >> 8) & 0xFF; - if (a > 0x60 && a < 0x7B) - a -= 0x20; - b = (b & 0xFFFF00FF) | (a << 8); - - a = (b >> 16) & 0xFF; - if (a > 0x60 && a < 0x7B) - a -= 0x20; - b = (b & 0xFF00FFFF) | (a << 16); - - a = (b >> 24) & 0xFF; - if (a > 0x60 && a < 0x7B) - a -= 0x20; - b = (b & 0x00FFFFFF) | (a << 24); - - hash += b; - hash *= m; - hash ^= hash >> r; - } - else - for (i = 0; length > 3; length -= 4, i += 4) { - b = (uint32_t)data[i + 0] | ((uint32_t)data[i + 1] << 8) - | ((uint32_t)data[i + 2] << 16) | ((uint32_t)data[i + 3] << 24); - - a = b & 0xFF; - if (a > 0x60 && a < 0x7B) - a -= 0x20; - b = (b & 0xFFFFFF00) | a; - - a = (b >> 8) & 0xFF; - if (a > 0x60 && a < 0x7B) - a -= 0x20; - b = (b & 0xFFFF00FF) | (a << 8); - - a = (b >> 16) & 0xFF; - if (a > 0x60 && a < 0x7B) - a -= 0x20; - b = (b & 0xFF00FFFF) | (a << 16); - - a = (b >> 24) & 0xFF; - if (a > 0x60 && a < 0x7B) - a -= 0x20; - b = (b & 0x00FFFFFF) | (a << 24); - - hash += b; - hash *= m; - hash ^= hash >> r; - } - - if (length > 0) { - if (length > 1) { - if (length > 2) { - b = data[i + 2]; - if (b > 0x60 && b < 0x7B) - b -= 0x20; - hash += b << 16; + if (data) + if (already_upper) { + if (big_endian) + for (i = 0; length > 3; length -= 4, i += 4) { + b = reverse_endianess_uint32_t(*(uint32_t*)&data[i]); + hash += b; + hash *= m; + hash ^= hash >> r; + } + else + for (i = 0; length > 3; length -= 4, i += 4) { + b = *(uint32_t*)&data[i]; + hash += b; + hash *= m; + hash ^= hash >> r; } - b = data[i + 1]; + if (length > 0) { + if (length > 1) { + if (length > 2) + hash += (uint32_t)data[i + 2] << 16; + hash += (uint32_t)data[i + 1] << 8; + } + hash += data[i]; + hash *= m; + hash ^= hash >> r; + } + } + else { + if (big_endian) + for (i = 0; length > 3; length -= 4, i += 4) { + b = reverse_endianess_uint32_t(*(uint32_t*)&data[i]); + + a = b & 0xFF; + if (a > 0x60 && a < 0x7B) + a -= 0x20; + b = (b & 0xFFFFFF00) | a; + + a = (b >> 8) & 0xFF; + if (a > 0x60 && a < 0x7B) + a -= 0x20; + b = (b & 0xFFFF00FF) | (a << 8); + + a = (b >> 16) & 0xFF; + if (a > 0x60 && a < 0x7B) + a -= 0x20; + b = (b & 0xFF00FFFF) | (a << 16); + + a = (b >> 24) & 0xFF; + if (a > 0x60 && a < 0x7B) + a -= 0x20; + b = (b & 0x00FFFFFF) | (a << 24); + + hash += b; + hash *= m; + hash ^= hash >> r; + } + else + for (i = 0; length > 3; length -= 4, i += 4) { + b = *(uint32_t*)&data[i]; + + a = b & 0xFF; + if (a > 0x60 && a < 0x7B) + a -= 0x20; + b = (b & 0xFFFFFF00) | a; + + a = (b >> 8) & 0xFF; + if (a > 0x60 && a < 0x7B) + a -= 0x20; + b = (b & 0xFFFF00FF) | (a << 8); + + a = (b >> 16) & 0xFF; + if (a > 0x60 && a < 0x7B) + a -= 0x20; + b = (b & 0xFF00FFFF) | (a << 16); + + a = (b >> 24) & 0xFF; + if (a > 0x60 && a < 0x7B) + a -= 0x20; + b = (b & 0x00FFFFFF) | (a << 24); + + hash += b; + hash *= m; + hash ^= hash >> r; + } + + if (length > 0) { + if (length > 1) { + if (length > 2) { + b = data[i + 2]; + if (b > 0x60 && b < 0x7B) + b -= 0x20; + hash += b << 16; + } + + b = data[i + 1]; + if (b > 0x60 && b < 0x7B) + b -= 0x20; + hash += b << 8; + } + + b = data[i]; if (b > 0x60 && b < 0x7B) b -= 0x20; - hash += b << 8; + hash += b; + + hash *= m; + hash ^= hash >> r; } - - b = data[i]; - if (b > 0x60 && b < 0x7B) - b -= 0x20; - hash += b; - - hash *= m; - hash ^= hash >> r; } - } hash *= m; hash ^= hash >> 10; @@ -158,12 +159,12 @@ uint32_t hash_murmurhash(uint8_t* data, size_t length, return hash; } -uint32_t hash_char_murmurhash(char* data, uint32_t seed, bool already_upper) { +inline uint32_t hash_char_murmurhash(char* data, uint32_t seed, bool already_upper) { uint32_t hash = hash_murmurhash((uint8_t*)data, strlen(data), seed, already_upper, false); return hash; } -uint32_t hash_wchar_t_murmurhash(wchar_t* data, uint32_t seed, bool already_upper) { +inline uint32_t hash_wchar_t_murmurhash(wchar_t* data, uint32_t seed, bool already_upper) { char* temp = utf8_encode(data); uint32_t hash = hash_murmurhash((uint8_t*)temp, strlen(temp), seed, already_upper, false); free(temp); diff --git a/src/KKdLib/hash.h b/src/KKdLib/hash.h index 1f717b67..7486758b 100644 --- a/src/KKdLib/hash.h +++ b/src/KKdLib/hash.h @@ -7,6 +7,9 @@ #include "default.h" +extern const uint64_t hash_fnv1a64_empty; +extern const uint32_t hash_murmurhash_empty; + extern uint64_t hash_fnv1a64(uint8_t* data, size_t length); extern uint64_t hash_char_fnv1a64(char* data); extern uint64_t hash_wchar_t_fnv1a64(wchar_t* data); diff --git a/src/KKdLib/interpolation.c b/src/KKdLib/interpolation.c new file mode 100644 index 00000000..caa3a1d9 --- /dev/null +++ b/src/KKdLib/interpolation.c @@ -0,0 +1,268 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "interpolation.h" + +inline float_t interpolate_linear_value(float_t p1, float_t p2, float_t f1, float_t f2, float_t f) { + float_t t = (f - f1) / (f2 - f1); + return p1 + t * (p2 - p1); +} + +inline void interpolate_linear_value_vec2(vec2* p1, vec2* p2, vec2* f1, vec2* f2, vec2* f, vec2* value) { + __m128 _p1; + __m128 _p2; + __m128 _f1; + __m128 _f2; + __m128 _f; + *(vec2*)&_p1 = *p1; + *(vec2*)&_p2 = *p2; + *(vec2*)&_f1 = *f1; + *(vec2*)&_f2 = *f2; + *(vec2*)&_f = *f; + + __m128 df = _mm_sub_ps(_f2, _f1); + __m128 t = _mm_div_ps(_mm_sub_ps(_f, _f1), df); + __m128 val = _mm_add_ps(_p1, _mm_mul_ps(_mm_sub_ps(_p2, _p1), t)); + *value = *(vec2*)&val; +} + +inline void interpolate_linear_value_vec3(vec3* p1, vec3* p2, vec3* f1, vec3* f2, vec3* f, vec3* value) { + __m128 _p1; + __m128 _p2; + __m128 _f1; + __m128 _f2; + __m128 _f; + *(vec3*)&_p1 = *p1; + *(vec3*)&_p2 = *p2; + *(vec3*)&_f1 = *f1; + *(vec3*)&_f2 = *f2; + *(vec3*)&_f = *f; + + __m128 df = _mm_sub_ps(_f2, _f1); + __m128 t = _mm_div_ps(_mm_sub_ps(_f, _f1), df); + __m128 val = _mm_add_ps(_p1, _mm_mul_ps(t, _mm_sub_ps(_p2, _p1))); + *value = *(vec3*)&val; +} + +inline void interpolate_linear_value_vec4(vec4* p1, vec4* p2, vec4* f1, vec4* f2, vec4* f, vec4* value) { + __m128 _p1; + __m128 _p2; + __m128 _f1; + __m128 _f2; + __m128 _f; + _p1 = p1->data; + _p2 = p2->data; + _f1 = f1->data; + _f2 = f2->data; + _f = f->data; + + __m128 df = _mm_sub_ps(_f2, _f1); + __m128 t = _mm_div_ps(_mm_sub_ps(_f, _f1), df); + value->data = _mm_add_ps(_p1, _mm_mul_ps(t, _mm_sub_ps(_p2, _p1))); +} + +inline void interpolate_linear(float_t p1, float_t p2, + size_t f1, size_t f2, float_t** arr, size_t* length) { + *length = f2 - f1 + 1; + *arr = force_malloc_s(float_t, *length); + + float_t* a = *arr; + float_t l = (float_t)*length; + for (size_t i = 0; i < l; i++, a++) + *a = interpolate_linear_value(p1, p2, + (float_t)f1, (float_t)f2, (float_t)(f1 + i)); +} + +inline float_t interpolate_chs_value(float_t p1, float_t p2, + float_t t1, float_t t2, float_t f1, float_t f2, float_t f) { + float_t df = f - f1; + float_t t = df / (f2 - f1); + float_t t_1 = t - 1.0f; + return p1 + t * t * (3.0f - 2.0f * t) * (p2 - p1) + (t_1 * t1 + t * t2) * df * t_1; +} + +inline void interpolate_chs_value_vec2(vec2* p1, vec2* p2, vec2* t1, vec2* t2, vec2* f1, vec2* f2, vec2* f, vec2* value) { + __m128 _p1; + __m128 _p2; + __m128 _t1; + __m128 _t2; + __m128 _f1; + __m128 _f2; + __m128 _f; + *(vec2*)&_p1 = *p1; + *(vec2*)&_p2 = *p2; + *(vec2*)&_t1 = *t1; + *(vec2*)&_t2 = *t2; + *(vec2*)&_f1 = *f1; + *(vec2*)&_f2 = *f2; + *(vec2*)&_f = *f; + + const __m128 _1 = _mm_set_ps1(1.0f); + const __m128 _2 = _mm_set_ps1(2.0f); + const __m128 _3 = _mm_set_ps1(3.0f); + + __m128 df = _mm_sub_ps(_f, _f1); + __m128 t = _mm_div_ps(df, _mm_sub_ps(_f2, _f1)); + __m128 t_1 = _mm_sub_ps(t, _1); + + __m128 delta = _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(t, t), _mm_sub_ps(_3, _mm_mul_ps(_2, t))), _mm_sub_ps(_p2, _p1)); + __m128 tangent = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(t_1, _t1), _mm_mul_ps(t, _t2)), _mm_mul_ps(df, t_1)); + __m128 val = _mm_add_ps(_mm_add_ps(_p1, delta), tangent); + *value = *(vec2*)&val; +} + +inline void interpolate_chs_value_vec3(vec3* p1, vec3* p2, vec3* t1, vec3* t2, vec3* f1, vec3* f2, vec3* f, vec3* value) { + __m128 _p1; + __m128 _p2; + __m128 _t1; + __m128 _t2; + __m128 _f1; + __m128 _f2; + __m128 _f; + *(vec3*)&_p1 = *p1; + *(vec3*)&_p2 = *p2; + *(vec3*)&_t1 = *t1; + *(vec3*)&_t2 = *t2; + *(vec3*)&_f1 = *f1; + *(vec3*)&_f2 = *f2; + *(vec3*)&_f = *f; + + const __m128 _1 = _mm_set_ps1(1.0f); + const __m128 _2 = _mm_set_ps1(2.0f); + const __m128 _3 = _mm_set_ps1(3.0f); + + __m128 df = _mm_sub_ps(_f, _f1); + __m128 t = _mm_div_ps(df, _mm_sub_ps(_f2, _f1)); + __m128 t_1 = _mm_sub_ps(t, _1); + + __m128 delta = _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(t, t), _mm_sub_ps(_3, _mm_mul_ps(_2, t))), _mm_sub_ps(_p2, _p1)); + __m128 tangent = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(t_1, _t1), _mm_mul_ps(t, _t2)), _mm_mul_ps(df, t_1)); + __m128 val = _mm_add_ps(_mm_add_ps(_p1, delta), tangent); + *value = *(vec3*)&val; +} + +inline void interpolate_chs_value_vec4(vec4* p1, vec4* p2, vec4* t1, vec4* t2, vec4* f1, vec4* f2, vec4* f, vec4* value) { + __m128 _p1; + __m128 _p2; + __m128 _t1; + __m128 _t2; + __m128 _f1; + __m128 _f2; + __m128 _f; + _p1 = p1->data; + _p2 = p2->data; + _t1 = t1->data; + _t2 = t2->data; + _f1 = f1->data; + _f2 = f2->data; + _f = f->data; + + const __m128 _1 = _mm_set_ps1(1.0f); + const __m128 _2 = _mm_set_ps1(2.0f); + const __m128 _3 = _mm_set_ps1(3.0f); + + __m128 df = _mm_sub_ps(_f, _f1); + __m128 t = _mm_div_ps(df, _mm_sub_ps(_f2, _f1)); + __m128 t_1 = _mm_sub_ps(t, _1); + + __m128 delta = _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(t, t), _mm_sub_ps(_3, _mm_mul_ps(_2, t))), _mm_sub_ps(_p2, _p1)); + __m128 tangent = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(t_1, _t1), _mm_mul_ps(t, _t2)), _mm_mul_ps(df, t_1)); + value->data = _mm_add_ps(_mm_add_ps(_p1, delta), tangent); +} + +inline void interpolate_chs(float_t p1, float_t p2, + float_t t1, float_t t2, size_t f1, size_t f2, float_t** arr, size_t* length) { + *length = f2 - f1 + 1; + *arr = force_malloc_s(float_t, *length); + + float_t* a = *arr; + float_t l = (float_t)*length; + for (size_t i = 0; i < l; i++, a++) + *a = interpolate_chs_value(p1, p2, t1, t2, (float_t)f1, (float_t)f2, (float_t)(f1 + i)); +} + +void interpolate_chs_reverse_value(float_t* arr, size_t length, + float_t* t1, float_t* t2, size_t f1, size_t f2, size_t f) { + *t1 = *t2 = 0.0f; + + if (!arr || length < 2 || f - f1 + 1 >= length || f < 1 || f < f1 || f + 2 > f2) + return; + + float_t df_1 = (float_t)(f - f1); + float_t df_2 = (float_t)(f - f1 + 1); + float_t _t1 = df_1 / (float_t)(f2 - f1); + float_t _t2 = df_2 / (float_t)(f2 - f1); + float_t t1_1 = _t1 - 1.0f; + float_t t2_1 = _t2 - 1.0f; + + float_t t1_t2_1 = arr[f] - arr[f1] - _t1 * _t1 * (3.0f - 2.0f * _t1) * (arr[f2] - arr[f1]); + float_t t1_t2_2 = arr[f + 1] - arr[f1] - _t2 * _t2 * (3.0f - 2.0f * _t2) * (arr[f2] - arr[f1]); + t1_t2_1 /= df_1 * t1_1; + t1_t2_2 /= df_2 * t2_1; + + *t1 = (t1_t2_1 * _t2 - t1_t2_2 * _t1) / (_t1 - _t2); + *t2 = (-t1_t2_1 * t2_1 + t1_t2_2 * t1_1) / (_t1 - _t2); +} + +void interpolate_chs_reverse(float_t* arr, size_t length, + float_t* t1, float_t* t2, size_t f1, size_t f2) { + *t1 = *t2 = 0.0f; + if (f2 - f1 - 2 < 1) + return; + + float_t _t1 = 0.0f; + float_t _t2 = 0.0f; + double_t tt1 = 0.0; + double_t tt2 = 0.0; + for (size_t i = f1 + 1; i < f2 - 1; i++) { + interpolate_chs_reverse_value(arr, length, &_t1, &_t2, f1, f2, i); + tt1 += _t1; + tt2 += _t2; + } + *t1 = (float_t)(tt1 / (double_t)(f2 - f1 - 2)); + *t2 = (float_t)(tt2 / (double_t)(f2 - f1 - 2)); +} + +void interpolate_chs_reverse_step_value(float_t* arr, size_t length, + float_t* t1, float_t* t2, size_t f1, size_t f2, size_t f, uint8_t step) { + *t1 = *t2 = 0.0f; + + if (!arr || length < 2 || f - f1 + 1 >= length || f < 1 || f < f1 || f + 2 > f2) + return; + + float_t df_1 = (float_t)((f - f1) * step); + float_t df_2 = (float_t)((f - f1 + 1) * step); + float_t _t1 = df_1 / (float_t)((f2 - f1) * step); + float_t _t2 = df_2 / (float_t)((f2 - f1) * step); + float_t t1_1 = _t1 - 1.0f; + float_t t2_1 = _t2 - 1.0f; + + float_t t1_t2_1 = arr[f] - arr[f1] - _t1 * _t1 * (3.0f - 2.0f * _t1) * (arr[f2] - arr[f1]); + float_t t1_t2_2 = arr[f + 1] - arr[f1] - _t2 * _t2 * (3.0f - 2.0f * _t2) * (arr[f2] - arr[f1]); + t1_t2_1 /= df_1 * t1_1; + t1_t2_2 /= df_2 * t2_1; + + *t1 = (t1_t2_1 * _t2 - t1_t2_2 * _t1) / (_t1 - _t2); + *t2 = (-t1_t2_1 * t2_1 + t1_t2_2 * t1_1) / (_t1 - _t2); +} + +void interpolate_chs_reverse_step(float_t* arr, size_t length, + float_t* t1, float_t* t2, size_t f1, size_t f2, uint8_t step) { + *t1 = *t2 = 0.0f; + if (f2 - f1 - 2 < 1) + return; + + float_t _t1 = 0.0f; + float_t _t2 = 0.0f; + double_t tt1 = 0.0; + double_t tt2 = 0.0; + for (size_t i = f1 + 1; i < f2 - 1; i++) { + interpolate_chs_reverse_step_value(arr, length, &_t1, &_t2, f1, f2, i, step); + tt1 += _t1; + tt2 += _t2; + } + *t1 = (float_t)(tt1 / (double_t)(f2 - f1 - 2)); + *t2 = (float_t)(tt2 / (double_t)(f2 - f1 - 2)); +} diff --git a/src/KKdLib/interpolation.h b/src/KKdLib/interpolation.h new file mode 100644 index 00000000..0c8aa248 --- /dev/null +++ b/src/KKdLib/interpolation.h @@ -0,0 +1,33 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "default.h" +#include "vec.h" + +extern float_t interpolate_linear_value(float_t p1, float_t p2, float_t f1, float_t f2, float_t f); +extern void interpolate_linear_value_vec2(vec2* p1, vec2* p2, vec2* f1, vec2* f2, vec2* f, vec2* value); +extern void interpolate_linear_value_vec3(vec3* p1, vec3* p2, vec3* f1, vec3* f2, vec3* f, vec3* value); +extern void interpolate_linear_value_vec4(vec4* p1, vec4* p2, vec4* f1, vec4* f2, vec4* f, vec4* value); +extern void interpolate_linear(float_t p1, float_t p2, size_t f1, size_t f2, float_t** arr, size_t* length); +extern float_t interpolate_chs_value(float_t p1, float_t p2, + float_t t1, float_t t2, float_t f1, float_t f2, float_t f); +extern void interpolate_chs_value_vec2(vec2* p1, vec2* p2, + vec2* t1, vec2* t2, vec2* f1, vec2* f2, vec2* f, vec2* value); +extern void interpolate_chs_value_vec3(vec3* p1, vec3* p2, + vec3* t1, vec3* t2, vec3* f1, vec3* f2, vec3* f, vec3* value); +extern void interpolate_chs_value_vec4(vec4* p1, vec4* p2, + vec4* t1, vec4* t2, vec4* f1, vec4* f2, vec4* f, vec4* value); +extern void interpolate_chs(float_t p1, float_t p2, + float_t t1, float_t t2, size_t f1, size_t f2, float_t** arr, size_t* length); +extern void interpolate_chs_reverse_value(float_t* arr, size_t length, + float_t* t1, float_t* t2, size_t f1, size_t f2, size_t f); +extern void interpolate_chs_reverse(float_t* arr, size_t length, + float_t* t1, float_t* t2, size_t f1, size_t f2); +extern void interpolate_chs_reverse_step_value(float_t* arr, size_t length, + float_t* t1, float_t* t2, size_t f1, size_t f2, size_t f, uint8_t step); +extern void interpolate_chs_reverse_step(float_t* arr, size_t length, + float_t* t1, float_t* t2, size_t f1, size_t f2, uint8_t step); diff --git a/src/KKdLib/io_deflate.c b/src/KKdLib/io_deflate.c index 8e46ad58..023c21f2 100644 --- a/src/KKdLib/io_deflate.c +++ b/src/KKdLib/io_deflate.c @@ -6,6 +6,74 @@ #include "io_deflate.h" #include +static size_t compress_static(struct libdeflate_compressor* c, void* src, size_t src_length, + void** dst, size_t* dst_length, int32_t compression_level, deflate_mode mode); +static size_t decompress_static(struct libdeflate_decompressor* d, void* src, size_t src_length, + void** dst, size_t* dst_length, size_t* dst_act_length, deflate_mode mode); + +size_t deflate_compress(void* src, size_t src_length, void** dst, + size_t* dst_length, int32_t compression_level, deflate_mode mode) { + if (!src_length) + return -1; + else if (!src) + return -2; + else if (!dst) + return -3; + else if (!dst_length) + return -4; + else if (mode < DEFLATE_MODE_DEFLATE || mode > DEFLATE_MODE_ZLIB) + return -5; + + struct libdeflate_compressor* c = libdeflate_alloc_compressor(compression_level); + if (!c) + return -5; + + size_t result = compress_static(c, src, src_length, dst, dst_length, compression_level, mode); + libdeflate_free_compressor(c); + return result >= 0 ? result : result - 0x10; +} + +size_t deflate_decompress(void* src, size_t src_length, void** dst, + size_t dst_length, deflate_mode mode) { + if (!src_length) + return -1; + else if (!src) + return -2; + else if (!dst) + return -3; + else if (!dst_length) + return -4; + else if (mode < DEFLATE_MODE_DEFLATE || mode > DEFLATE_MODE_ZLIB) + return -5; + + size_t dst_act_length = 0; + struct libdeflate_decompressor* d = libdeflate_alloc_decompressor(); + size_t result = decompress_static(d, src, src_length, dst, &dst_length, &dst_act_length, mode); + libdeflate_free_decompressor(d); + return result >= 0 ? result : result - 0x10; +} + +size_t deflate_decompress_unknown(void* src, size_t src_length, void** dst, + size_t* dst_length, deflate_mode mode) { + if (!src_length) + return -1; + else if (!src) + return -2; + else if (!dst) + return -3; + else if (!dst_length) + return -4; + else if (mode < DEFLATE_MODE_DEFLATE || mode > DEFLATE_MODE_ZLIB) + return -5; + + *dst_length = 1; + size_t dst_act_length = 1; + struct libdeflate_decompressor* d = libdeflate_alloc_decompressor(); + size_t result = decompress_static(d, src, src_length, dst, dst_length, &dst_act_length, mode); + libdeflate_free_decompressor(d); + return result >= 0 ? result : result - 0x10; +} + static size_t compress_static(struct libdeflate_compressor* c, void* src, size_t src_length, void** dst, size_t* dst_length, int32_t compression_level, deflate_mode mode) { size_t dst_max_length; @@ -103,66 +171,3 @@ static size_t decompress_static(struct libdeflate_decompressor* d, void* src, si } return 0; } - -size_t deflate_compress(void* src, size_t src_length, void** dst, - size_t* dst_length, int32_t compression_level, deflate_mode mode) { - if (!src_length) - return -1; - else if (!src) - return -2; - else if (!dst) - return -3; - else if (!dst_length) - return -4; - else if (mode < DEFLATE_MODE_DEFLATE || mode > DEFLATE_MODE_ZLIB) - return -5; - - struct libdeflate_compressor* c = libdeflate_alloc_compressor(compression_level); - if (!c) - return -5; - - size_t result = compress_static(c, src, src_length, dst, dst_length, compression_level, mode); - libdeflate_free_compressor(c); - return result >= 0 ? result : result - 0x10; -} - -size_t deflate_decompress(void* src, size_t src_length, void** dst, - size_t dst_length, deflate_mode mode) { - if (!src_length) - return -1; - else if (!src) - return -2; - else if (!dst) - return -3; - else if (!dst_length) - return -4; - else if (mode < DEFLATE_MODE_DEFLATE || mode > DEFLATE_MODE_ZLIB) - return -5; - - size_t dst_act_length = 0; - struct libdeflate_decompressor* d = libdeflate_alloc_decompressor(); - size_t result = decompress_static(d, src, src_length, dst, &dst_length, &dst_act_length, mode); - libdeflate_free_decompressor(d); - return result >= 0 ? result : result - 0x10; -} - -size_t deflate_decompress_unknown(void* src, size_t src_length, void** dst, - size_t* dst_length, deflate_mode mode) { - if (!src_length) - return -1; - else if (!src) - return -2; - else if (!dst) - return -3; - else if (!dst_length) - return -4; - else if (mode < DEFLATE_MODE_DEFLATE || mode > DEFLATE_MODE_ZLIB) - return -5; - - *dst_length = 1; - size_t dst_act_length = 1; - struct libdeflate_decompressor* d = libdeflate_alloc_decompressor(); - size_t result = decompress_static(d, src, src_length, dst, dst_length, &dst_act_length, mode); - libdeflate_free_decompressor(d); - return result >= 0 ? result : result - 0x10; -} diff --git a/src/KKdLib/io_json.c b/src/KKdLib/io_json.c index 6e18d1af..694faef6 100644 --- a/src/KKdLib/io_json.c +++ b/src/KKdLib/io_json.c @@ -311,7 +311,7 @@ static void io_json_read_string(stream* s, wchar_t* name, msgpack* msg, int32_t* free(temp); } -FORCE_INLINE void io_json_read_skip_whitespace(stream* s, int32_t* c) { +static inline void io_json_read_skip_whitespace(stream* s, int32_t* c) { while ((*c = io_read_char(s)) != IO_EOF) { if (CHECK_WHITESPACE(*c)) continue; @@ -327,7 +327,7 @@ static void io_json_read_map(stream* s, wchar_t* name, msgpack* msg, int32_t* c) if (*c != '}') { map.length = 0; map.fulllength = 1; - map.data = force_malloc_s(sizeof(msgpack), 1); + map.data = force_malloc_s(msgpack, 1); while (true) { io_json_read_skip_whitespace(s, c); @@ -360,7 +360,7 @@ static void io_json_read_map(stream* s, wchar_t* name, msgpack* msg, int32_t* c) if (i == map.fulllength) { map.fulllength *= 2; map.fulllength++; - msgpack* t_m = force_malloc_s(sizeof(msgpack), map.fulllength); + msgpack* t_m = force_malloc_s(msgpack, map.fulllength); memcpy(t_m, map.data, sizeof(msgpack) * i); free(map.data); map.data = t_m; @@ -369,7 +369,7 @@ static void io_json_read_map(stream* s, wchar_t* name, msgpack* msg, int32_t* c) } if (i < map.fulllength) { - msgpack* t_m = force_malloc_s(sizeof(msgpack), i); + msgpack* t_m = force_malloc_s(msgpack, i); memcpy(t_m, map.data, sizeof(msgpack) * i); free(map.data); map.data = t_m; @@ -396,7 +396,7 @@ static void io_json_read_array(stream* s, wchar_t* name, msgpack* msg, int32_t* if (*c != ']') { array.length = 0; array.fulllength = 1; - array.data = force_malloc_s(sizeof(msgpack), 1); + array.data = force_malloc_s(msgpack, 1); while (true) { io_json_read_skip_whitespace(s, c); @@ -417,7 +417,7 @@ static void io_json_read_array(stream* s, wchar_t* name, msgpack* msg, int32_t* if (i == array.fulllength) { array.fulllength *= 2; array.fulllength++; - msgpack* t_m = force_malloc_s(sizeof(msgpack), array.fulllength); + msgpack* t_m = force_malloc_s(msgpack, array.fulllength); memcpy(t_m, array.data, sizeof(msgpack) * i); free(array.data); array.data = t_m; @@ -426,7 +426,7 @@ static void io_json_read_array(stream* s, wchar_t* name, msgpack* msg, int32_t* } if (i < array.fulllength) { - msgpack* t_m = force_malloc_s(sizeof(msgpack), i); + msgpack* t_m = force_malloc_s(msgpack, i); memcpy(t_m, array.data, sizeof(msgpack) * i); free(array.data); array.data = t_m; diff --git a/src/KKdLib/io_path.c b/src/KKdLib/io_path.c index a7aa59e7..539fe835 100644 --- a/src/KKdLib/io_path.c +++ b/src/KKdLib/io_path.c @@ -53,36 +53,6 @@ bool path_wcheck_directory_exists(wchar_t* dir_path) { return ftyp & FILE_ATTRIBUTE_DIRECTORY ? true : false; } -bool path_check_ends_with(char* str, char* mask) { - size_t mask_len = strlen(mask); - size_t len = strlen(str); - char* t = str; - while (t) { - t = strstr(t, mask); - if (t) { - t += mask_len; - if (t == str + len) - return true; - } - } - return false; -} - -bool path_wcheck_ends_with(wchar_t* str, wchar_t* mask) { - size_t mask_len = wcslen(mask); - size_t len = wcslen(str); - wchar_t* t = str; - while (t) { - t = wcsstr(t, mask); - if (t) { - t += mask_len; - if (t == str + len) - return true; - } - } - return false; -} - void path_get_files(vector_ptr_char* files, char* dir_path) { vector_ptr_char_free(files, 0); @@ -111,7 +81,7 @@ void path_get_files(vector_ptr_char* files, char* dir_path) { count++; while (FindNextFileA(hFind, &fdata)); - bool* found = force_malloc_s(sizeof(bool*), count); + bool* found = force_malloc_s(bool*, count); hFind = FindFirstFileA(dir, &fdata); size_t t_count = 0; @@ -140,7 +110,7 @@ void path_get_files(vector_ptr_char* files, char* dir_path) { for (size_t i = 0, j = 0; i < count; i++) { if (found[i]) { size_t len = strlen(fdata.cFileName); - char* file = force_malloc_s(sizeof(char*), len + 1); + char* file = force_malloc_s(char*, len + 1); memcpy(file, fdata.cFileName, (len + 1)); vector_ptr_char_push_back(files, &file); j++; @@ -158,7 +128,7 @@ void path_wget_files(vector_ptr_wchar_t* files, wchar_t* dir_path) { vector_ptr_wchar_t_free(files, 0); size_t dir_len = wcslen(dir_path); - wchar_t* dir = force_malloc_s(sizeof(wchar_t), dir_len + 3); + wchar_t* dir = force_malloc_s(wchar_t, dir_len + 3); memcpy(dir, dir_path, sizeof(wchar_t) * dir_len); dir[dir_len] = L'\\'; dir[dir_len + 1] = L'*'; @@ -177,9 +147,9 @@ void path_wget_files(vector_ptr_wchar_t* files, wchar_t* dir_path) { count++; while (FindNextFileW(hFind, &fdata)); - bool* found = force_malloc_s(sizeof(bool), count); + bool* found = force_malloc_s(bool, count); - wchar_t* temp = force_malloc_s(sizeof(wchar_t), dir_len + 2 + MAX_PATH); + wchar_t* temp = force_malloc_s(wchar_t, dir_len + 2 + MAX_PATH); memcpy(temp, dir_path, sizeof(wchar_t) * dir_len); temp[dir_len] = L'\\'; hFind = FindFirstFileW(dir, &fdata); @@ -209,7 +179,7 @@ void path_wget_files(vector_ptr_wchar_t* files, wchar_t* dir_path) { for (size_t i = 0, j = 0; i < count; i++) { if (found[i]) { size_t len = wcslen(fdata.cFileName); - wchar_t* file = force_malloc_s(sizeof(wchar_t*), len + 1); + wchar_t* file = force_malloc_s(wchar_t*, len + 1); memcpy(file, fdata.cFileName, sizeof(wchar_t) * (len + 1)); vector_ptr_wchar_t_push_back(files, &file); j++; @@ -221,67 +191,3 @@ void path_wget_files(vector_ptr_wchar_t* files, wchar_t* dir_path) { free(found); free(dir); } - -char* path_get_extension(char* path) { - char* t = strrchr(path, '\\'); - t = strrchr(t ? t : path, '.'); - size_t len = t ? t - path : 0; - char* ext = force_malloc(len + 1); - memcpy(ext, t ? t : path, len + 1); - return ext; -} - -wchar_t* path_wget_extension(wchar_t* path) { - wchar_t* t = wcsrchr(path, L'\\'); - t = wcsrchr(t ? t : path, L'.'); - size_t len = t ? t - path : 0; - wchar_t* ext = force_malloc_s(sizeof(wchar_t), len + 1); - memcpy(ext, t ? t : path, sizeof(wchar_t) * (len + 1)); - return ext; -} - -char* path_get_without_extension(char* path) { - char* t = strrchr(path, '\\'); - t = strrchr(t ? t : path, '.'); - size_t len = t ? t - path : strlen(path); - char* p = force_malloc(len + 1); - memcpy(p, path, len); - p[len] = '\0'; - return p; -} - -wchar_t* path_wget_without_extension(wchar_t* path) { - wchar_t* t = wcsrchr(path, L'\\'); - t = wcsrchr(t ? t : path, L'.'); - size_t len = t ? t - path : wcslen(path); - wchar_t* p = force_malloc_s(sizeof(wchar_t), len + 1); - memcpy(p, path, sizeof(wchar_t) * len); - p[len] = L'\0'; - return p; -} - -char* path_add_extension(char* path, char* ext) { - if (!path) - return 0; - - size_t len = strlen(path); - size_t ext_len = ext ? strlen(ext) : 0; - char* p = force_malloc(len + ext_len + 1); - memcpy(p, path, len); - memcpy(p + len, ext, ext_len); - p[len + ext_len] = '\0'; - return p; -} - -wchar_t* path_wadd_extension(wchar_t* path, wchar_t* ext) { - if (!path) - return 0; - - size_t len = wcslen(path); - size_t ext_len = ext ? wcslen(ext) : 0; - wchar_t* p = force_malloc_s(sizeof(wchar_t), len + ext_len + 1); - memcpy(p, path, sizeof(wchar_t) * len); - memcpy(p + len, ext, sizeof(wchar_t) * ext_len); - p[len + ext_len] = L'\0'; - return p; -} diff --git a/src/KKdLib/io_path.h b/src/KKdLib/io_path.h index 0fd712f5..7c5951c5 100644 --- a/src/KKdLib/io_path.h +++ b/src/KKdLib/io_path.h @@ -14,13 +14,5 @@ extern bool path_check_file_exists(char* file_path); extern bool path_wcheck_file_exists(wchar_t* file_path); extern bool path_check_directory_exists(char* dir_path); extern bool path_wcheck_directory_exists(wchar_t* dir_path); -extern bool path_check_ends_with(char* str, char* mask); -extern bool path_wcheck_ends_with(wchar_t* str, wchar_t* mask); extern void path_get_files(vector_ptr_char* files, char* dir_path); -extern void path_wget_files(vector_ptr_wchar_t* files, wchar_t* dir_path); -extern char* path_get_extension(char* path); -extern wchar_t* path_wget_extension(wchar_t* path); -extern char* path_get_without_extension(char* path); -extern wchar_t* path_wget_without_extension(wchar_t* path); -extern char* path_add_extension(char* path, char* ext); -extern wchar_t* path_wadd_extension(wchar_t* path, wchar_t* ext); +extern void path_wget_files(vector_ptr_wchar_t* files, wchar_t* dir_path); \ No newline at end of file diff --git a/src/KKdLib/io_stream.c b/src/KKdLib/io_stream.c index 11703af1..cfb9f348 100644 --- a/src/KKdLib/io_stream.c +++ b/src/KKdLib/io_stream.c @@ -44,24 +44,6 @@ stream* io_open_memory(void* data, size_t length) { return s; } -void io_dispose(stream* s) { - if (!s) - return; - - switch (s->type) { - case STREAM_FILE: - if (s->io.stream) { - fflush(s->io.stream); - fclose(s->io.stream); - } - break; - case STREAM_MEMORY: - vector_uint8_t_free(&s->io.data.vec); - break; - } - free(s); -} - void io_align(stream* s, size_t align) { size_t position; switch (s->type) { @@ -95,6 +77,17 @@ void io_align(stream* s, size_t align) { } } +int io_flush(stream* s) { + switch (s->type) { + case STREAM_FILE: + return fflush(s->io.stream); + case STREAM_MEMORY: + return 0; + default: + return 0; + } +} + ssize_t io_get_position(stream* s) { switch (s->type) { case STREAM_FILE: @@ -262,6 +255,24 @@ void io_write_uint8_t(stream* s, uint8_t val) { io_write_char(s, (char)val); } +void io_dispose(stream* s) { + if (!s) + return; + + switch (s->type) { + case STREAM_FILE: + if (s->io.stream) { + fflush(s->io.stream); + fclose(s->io.stream); + } + break; + case STREAM_MEMORY: + vector_uint8_t_free(&s->io.data.vec); + break; + } + free(s); +} + #define io_read_write(t) \ t io_read_##t(stream* s) { \ io_read(s, s->buf, sizeof(t)); \ diff --git a/src/KKdLib/io_stream.h b/src/KKdLib/io_stream.h index 42beb4cf..89746f6d 100644 --- a/src/KKdLib/io_stream.h +++ b/src/KKdLib/io_stream.h @@ -36,14 +36,15 @@ typedef struct stream { extern stream* io_open(char* path, char* mode); extern stream* io_wopen(wchar_t* path, wchar_t* mode); extern stream* io_open_memory(void* data, size_t length); -extern void io_dispose(stream* s); extern void io_align(stream* s, size_t align); +extern int io_flush(stream* s); extern ssize_t io_get_position(stream* s); extern int32_t io_set_position(stream* s, ssize_t pos, int32_t seek); extern size_t io_read(stream* s, void* buf, size_t count); extern size_t io_write(stream* s, void* buf, size_t count); extern int32_t io_read_char(stream* s); extern int32_t io_write_char(stream* s, char c); +extern void io_dispose(stream* s); int8_t io_read_int8_t(stream* s); uint8_t io_read_uint8_t(stream* s); diff --git a/src/KKdLib/kkc.c b/src/KKdLib/kkc.c index 8f0249da..fd3cb5bb 100644 --- a/src/KKdLib/kkc.c +++ b/src/KKdLib/kkc.c @@ -8,34 +8,13 @@ #define XOR32(val) ((val & 0xFF) ^ (((val) >> 8) & 0xFF) ^ (((val) >> 16) & 0xFF) ^ (((val) >> 24) & 0xFF)) +static inline void next_rand_uint8_t_pointer(uint8_t* arr, size_t length, uint32_t* state); + kkc* kkc_init() { kkc* k = force_malloc(sizeof(kkc)); return k; } -void kkc_dispose(kkc* c) { - if (!c) - return; - - free(c->key.data); - free(c->k); - free(c); -} - -FORCE_INLINE void next_rand_uint8_t_pointer(uint8_t* arr, size_t length, uint32_t* state) { - if (!arr || length < 1) - return; - - for (size_t i = 0; i < length; i++) { - uint32_t x = *state; - x ^= x << 13; - x ^= x >> 17; - x ^= x << 5; - *state = x; - arr[i] = (uint8_t)x; - } -} - void FASTCALL kkc_get_key(kkc_key* key, uint32_t seed, kkc_key_mode mode, kkc_key_type type) { key->data = 0; key->mode = 0; @@ -85,7 +64,7 @@ void FASTCALL kkc_init_from_key_mode(kkc* c, vector_uint8_t* key, kkc_key_mode m c->state = 1; c->error = KKC_ERROR_NONE; - if (!key || !key->begin || !(key->end - key->begin)) { + if (!key || !key->begin || key->end - key->begin < 1) { c->error = KKC_ERROR_INVALID_KEY; return; } @@ -254,7 +233,7 @@ void FASTCALL kkc_prepare_cursing_table(kkc* c) { if (c->k) free(c->k); - c->k = force_malloc_s(sizeof(uint32_t), kl); + c->k = force_malloc_s(uint32_t, kl); if (!c->k) return; @@ -557,3 +536,26 @@ void FASTCALL kkc_decurse(kkc* c, uint8_t* src, uint8_t* dst, size_t length) { } *c = e; } + +void kkc_dispose(kkc* c) { + if (!c) + return; + + free(c->key.data); + free(c->k); + free(c); +} + +static inline void next_rand_uint8_t_pointer(uint8_t* arr, size_t length, uint32_t* state) { + if (!arr || length < 1) + return; + + for (size_t i = 0; i < length; i++) { + uint32_t x = *state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + *state = x; + arr[i] = (uint8_t)x; + } +} diff --git a/src/KKdLib/kkc.h b/src/KKdLib/kkc.h index 3303d8ef..2108c75f 100644 --- a/src/KKdLib/kkc.h +++ b/src/KKdLib/kkc.h @@ -54,15 +54,15 @@ typedef struct kkc { } kkc; extern kkc* kkc_init(); -extern void kkc_dispose(kkc* c); -extern void FASTCALL kkc_get_key(kkc_key* key, uint32_t seed, kkc_key_mode mode, kkc_key_type type); -extern void FASTCALL kkc_init_from_key_mode(kkc* c, vector_uint8_t* key, kkc_key_mode mode); -extern void FASTCALL kkc_init_from_type_mode(kkc* c, kkc_key_type type, kkc_key_mode mode); -extern void FASTCALL kkc_init_from_seed_type_mode(kkc* c, uint32_t seed, kkc_key_type type, kkc_key_mode mode); -extern void FASTCALL kkc_init_from_key(kkc* c, kkc_key* key); -extern void FASTCALL kkc_prepare_cursing_table(kkc* c); -extern void FASTCALL kkc_reset(kkc* c); -extern void FASTCALL kkc_reset_iv(kkc* c, uint32_t iv); -extern void FASTCALL kkc_reset_iv4(kkc* c, uint32_t iv0, uint32_t iv1, uint32_t iv2, uint32_t iv3); -extern void FASTCALL kkc_curse(kkc* c, uint8_t* src, uint8_t* dst, size_t length); -extern void FASTCALL kkc_decurse(kkc* c, uint8_t* src, uint8_t* dst, size_t length); \ No newline at end of file +extern void kkc_get_key(kkc_key* key, uint32_t seed, kkc_key_mode mode, kkc_key_type type); +extern void kkc_init_from_key_mode(kkc* c, vector_uint8_t* key, kkc_key_mode mode); +extern void kkc_init_from_type_mode(kkc* c, kkc_key_type type, kkc_key_mode mode); +extern void kkc_init_from_seed_type_mode(kkc* c, uint32_t seed, kkc_key_type type, kkc_key_mode mode); +extern void kkc_init_from_key(kkc* c, kkc_key* key); +extern void kkc_prepare_cursing_table(kkc* c); +extern void kkc_reset(kkc* c); +extern void kkc_reset_iv(kkc* c, uint32_t iv); +extern void kkc_reset_iv4(kkc* c, uint32_t iv0, uint32_t iv1, uint32_t iv2, uint32_t iv3); +extern void kkc_curse(kkc* c, uint8_t* src, uint8_t* dst, size_t length); +extern void kkc_decurse(kkc* c, uint8_t* src, uint8_t* dst, size_t length); +extern void kkc_dispose(kkc* c); \ No newline at end of file diff --git a/src/KKdLib/kkfs.c b/src/KKdLib/kkfs.c index 378b438e..f8698951 100644 --- a/src/KKdLib/kkfs.c +++ b/src/KKdLib/kkfs.c @@ -9,20 +9,6 @@ #include #include -FORCE_INLINE void next_rand_uint8_t_pointer(uint8_t* arr, size_t length, uint32_t* state) { - if (!arr || length < 1) - return; - - for (size_t i = 0; i < length; i++) { - uint32_t x = *state; - x ^= x << 13; - x ^= x >> 17; - x ^= x << 5; - *state = x; - arr[i] = (uint8_t)x; - } -} - static const uint8_t boot_code[] = { 0x33, 0xC9, 0x8E, 0xD1, 0xBC, 0xF4, 0x7B, 0x8E, 0xC1, 0x8E, 0xD9, 0xBD, 0x00, 0x7C, 0x88, 0x56, 0x40, 0x88, 0x4E, 0x02, 0x8A, 0x56, 0x40, 0xB4, 0x41, 0xBB, 0xAA, 0x55, 0xCD, 0x13, 0x72, 0x10, @@ -53,267 +39,26 @@ static const uint8_t boot_code[] = { 0xB9, 0x01, 0x00, 0x00 }; -kkfs_storage fs_storage; +static uint32_t kkfs_allocate_sectors(kkfs* fs, uint32_t sectors); +static uint32_t kkfs_allocate_sector(kkfs* fs); +static uint32_t kkfs_append_sector(kkfs* fs, uint32_t sector); +static uint32_t kkfs_calculate_key_hash(kkc* curse); +static bool kkfs_find(kkfs* fs, kkfs_data* data, wchar_t* path); +static bool kkfs_free(kkfs* fs, wchar_t* path); +static void kkfs_free_sector(kkfs* fs, uint32_t sector); +static uint64_t kkfs_get_current_time_ticks(); +static uint32_t kkfs_get_free_sector(kkfs* fs, uint32_t sector); +static void kkfs_write_changes(kkfs* fs); +static void kkfs_write_first_sector(kkfs* fs); +static bool kkfs_write_kkfs_data(kkfs* fs, kkfs_data* data); +static void kkfs_write_sector_info(kkfs* fs); +static inline void next_rand_uint8_t_pointer(uint8_t* arr, size_t length, uint32_t* state); kkfs* kkfs_init() { kkfs* fs = force_malloc(sizeof(kkfs)); return fs; } -void kkfs_dispose(kkfs* fs) { - if (!fs) - return; - - free(fs->current_directory); - free(fs->sector_info); - free(fs); -} - -static uint64_t kkfs_get_current_time_ticks() { - FILETIME time; - GetSystemTimeAsFileTime(&time); - return *(uint64_t*)&time + 504911232000000000; -} - -static uint32_t kkfs_calculate_key_hash(kkc* curse) { - if (!curse) - return 0; - - size_t kl = (size_t)curse->key.type * 8; - return hash_murmurhash((uint8_t*)curse->key.data, kl, 0, false, false); -} - -static void kkfs_write_first_sector(kkfs* fs) { - _fseeki64(fs->io, 0x00, SEEK_SET); - fwrite(&fs->data, sizeof(kkfs_struct), 1, fs->io); -} - -static void kkfs_write_sector_info(kkfs* fs) { - _fseeki64(fs->io, fs->data.header.sector_size, SEEK_SET); - size_t length = fs->data.header.sectors_count; - size_t temp = length * sizeof(kkfs_sector_info); - size_t temp_aligned = align_val(temp, fs->data.header.sector_size); - - uint8_t* td = force_malloc(fs->data.header.sector_size); - fwrite(fs->sector_info, sizeof(kkfs_sector_info), length, fs->io); - if (temp_aligned - temp) - fwrite(td, 1, temp_aligned - temp, fs->io); - free(td); -} - -static void kkfs_write_changes(kkfs* fs) { - if (fs->data.header.flags & KKFS_DIRECTORY_READ_ONLY) - return; - - if (fs->data_changed) { - kkfs_write_first_sector(fs); - fs->data_changed = false; - } - - if (fs->sector_info_changed) { - kkfs_write_sector_info(fs); - fs->sector_info_changed = false; - } -} - -static uint32_t kkfs_get_free_sector(kkfs* fs, uint32_t sector) { - if (sector) { - for (size_t i = sector + 1LL; i < fs->data.header.sectors_count; i++) - if (fs->sector_info[i] == KKFS_SECTOR_FREE) - return (uint32_t)i; - - for (size_t i = 0; i < sector; i++) - if (fs->sector_info[i] == KKFS_SECTOR_FREE) - return (uint32_t)i; - } - else - for (size_t i = 0; i < fs->data.header.sectors_count; i++) - if (fs->sector_info[i] == KKFS_SECTOR_FREE) - return (uint32_t)i; - return 0; -} - -static uint32_t kkfs_allocate_sector(kkfs* fs) { - fs->free_sector = kkfs_get_free_sector(fs, fs->free_sector); - if (fs->free_sector) { - fs->sector_info_changed = true; - fs->sector_info[fs->free_sector] = KKFS_SECTOR_END_OF_CHAIN; - } - return fs->free_sector; -} - -static uint32_t kkfs_append_sector(kkfs* fs, uint32_t sector) { - uint32_t prev_sector = sector ? sector : fs->free_sector; - fs->free_sector = kkfs_get_free_sector(fs, prev_sector); - if (fs->free_sector) { - fs->sector_info_changed = true; - fs->sector_info[prev_sector] = fs->free_sector; - } - fs->sector_info[fs->free_sector] = KKFS_SECTOR_END_OF_CHAIN; - return fs->free_sector; -} - -static void kkfs_free_sector(kkfs* fs, uint32_t sector) { - uint32_t info; - do { - info = (uint32_t)fs->sector_info[sector]; - fs->sector_info[sector] = KKFS_SECTOR_FREE; - sector = info; - } while (info > KKFS_SECTOR_RESERVED && info != KKFS_SECTOR_END_OF_CHAIN); -} - -static uint32_t kkfs_allocate_sectors(kkfs* fs, uint32_t sectors) { - if (!sectors) - return 0; - - fs->free_sector = kkfs_get_free_sector(fs, fs->free_sector); - if (!fs->free_sector) - return 0; - - fs->sector_info_changed = true; - fs->sector_info[fs->free_sector] = KKFS_SECTOR_END_OF_CHAIN; - uint32_t first_sector = fs->free_sector; - for (size_t i = 1; i < sectors; i++) { - kkfs_append_sector(fs, 0); - if (!fs->free_sector) { - kkfs_free_sector(fs, first_sector); - return 0; - } - } - return first_sector; -} - -static bool kkfs_write_kkfs_data(kkfs* fs, kkfs_data* data) { - size_t pos; - size_t sector; - kkfs_data dat; - uint32_t info; - uint64_t time_ticks; - - kkfs_directory* curr_dir = &fs->current_directory[fs->current_directory_index]; - size_t data_sector = curr_dir->data_sector; - - _fseeki64(fs->io, data_sector * fs->data.header.sector_size, SEEK_SET); - do { - fread(&dat, sizeof(kkfs_data), 1, fs->io); - pos = _ftelli64(fs->io); - - if ((dat.type == KKFS_DIRECTORY || dat.type == KKFS_FILE) - && (data->type == KKFS_DIRECTORY || data->type == KKFS_FILE)) { - wchar_t* name0 = dat.type == KKFS_DIRECTORY ? dat.dir.name : dat.file.name; - wchar_t* name1 = data->type == KKFS_DIRECTORY ? data->dir.name : data->file.name; - if (!memcmp(name0, name1, sizeof(wchar_t) * KKFS_NAME_LENGTH)) - return false; - } - - - sector = pos / fs->data.header.sector_size; - if (!(pos % fs->data.header.sector_size)) { - info = (uint32_t)fs->sector_info[sector - 1]; - if (info > KKFS_SECTOR_RESERVED && info != KKFS_SECTOR_END_OF_CHAIN) { - sector = info; - pos = sector * fs->data.header.sector_size; - - if (dat.type == KKFS_DIRECTORY || dat.type == KKFS_FILE) - _fseeki64(fs->io, pos, SEEK_SET); - } - } - } while (dat.type == KKFS_DIRECTORY || dat.type == KKFS_FILE); - - time_ticks = kkfs_get_current_time_ticks(); - if (!(pos % fs->data.header.sector_size)) - kkfs_append_sector(fs, (uint32_t)(sector - 1)); - - if (dat.type == KKFS_EMPTY || dat.type == KKFS_DELETED) - pos -= sizeof(kkfs_data); - - _fseeki64(fs->io, pos, SEEK_SET); - fwrite(data, sizeof(kkfs_data), 1, fs->io); - return true; -} - -static bool kkfs_find(kkfs* fs, kkfs_data* data, wchar_t* path) { - size_t pos; - size_t sector; - kkfs_data dat; - uint32_t info; - - size_t path_length = min(KKFS_NAME_LENGTH, wcslen(path) + 1); - kkfs_directory* curr_dir = &fs->current_directory[fs->current_directory_index]; - size_t data_sector = curr_dir->data_sector; - - _fseeki64(fs->io, data_sector * fs->data.header.sector_size, SEEK_SET); - do { - fread(&dat, sizeof(kkfs_data), 1, fs->io); - pos = _ftelli64(fs->io); - - if (dat.type == KKFS_DIRECTORY || dat.type == KKFS_FILE) { - wchar_t* name = dat.type == KKFS_DIRECTORY ? dat.dir.name : dat.file.name; - if (!memcmp(name, path, sizeof(wchar_t) * path_length)) { - *data = dat; - return true; - } - } - - sector = pos / fs->data.header.sector_size; - if (!(pos % fs->data.header.sector_size)) { - info = (uint32_t)fs->sector_info[sector - 1]; - if (info > KKFS_SECTOR_RESERVED && info != KKFS_SECTOR_END_OF_CHAIN) { - sector = info; - pos = sector * fs->data.header.sector_size; - - if (dat.type) - _fseeki64(fs->io, pos, SEEK_SET); - } - } - } while (dat.type); - return false; -} - -static bool kkfs_free(kkfs* fs, wchar_t* path) { - size_t pos; - size_t sector; - kkfs_data dat; - uint32_t info; - uint64_t time_ticks; - - size_t path_length = min(KKFS_NAME_LENGTH, wcslen(path) + 1); - kkfs_directory* curr_dir = &fs->current_directory[fs->current_directory_index]; - size_t data_sector = curr_dir->data_sector; - - _fseeki64(fs->io, data_sector * fs->data.header.sector_size, SEEK_SET); - do { - fread(&dat, sizeof(kkfs_data), 1, fs->io); - pos = _ftelli64(fs->io); - - if (dat.type == KKFS_DIRECTORY || dat.type == KKFS_FILE) { - wchar_t* name = dat.type == KKFS_DIRECTORY ? dat.dir.name : dat.file.name; - if (!memcmp(name, path, sizeof(wchar_t) * path_length)) { - time_ticks = kkfs_get_current_time_ticks(); - - memset(&dat, 0, sizeof(kkfs_data)); - dat.type = KKFS_DELETED; - _fseeki64(fs->io, pos - sizeof(kkfs_data), SEEK_SET); - fwrite(&dat, sizeof(kkfs_data), 1, fs->io); - return true; - } - } - - sector = pos / fs->data.header.sector_size; - if (!(pos % fs->data.header.sector_size)) { - info = (uint32_t)fs->sector_info[sector - 1]; - if (info > KKFS_SECTOR_RESERVED && info != KKFS_SECTOR_END_OF_CHAIN) { - sector = info; - pos = sector * fs->data.header.sector_size; - - if (dat.type) - _fseeki64(fs->io, pos, SEEK_SET); - } - } - } while (dat.type); - return false; -} - void kkfs_initialize(kkfs* fs, char* path, uint32_t sector_size, size_t length, kkfs_directory_flags flags, kkc* curse, uint32_t parent_hash, kkc* parent_curse) { if (!fs || !path) @@ -347,7 +92,7 @@ void kkfs_winitialize(kkfs* fs, wchar_t* path, uint32_t sector_size, size_t leng size_t t = sectors_count * sizeof(kkfs_sector_info); t = align_val_divide(t, sector_size, sector_size); - fs->sector_info = force_malloc_s(sizeof(kkfs_sector_info), sectors_count); + fs->sector_info = force_malloc_s(kkfs_sector_info, sectors_count); fs->sector_info[0] = KKFS_SECTOR_RESERVED; for (size_t i = 0; i < t; i++) fs->sector_info[1 + i] = KKFS_SECTOR_RESERVED; @@ -374,7 +119,7 @@ void kkfs_winitialize(kkfs* fs, wchar_t* path, uint32_t sector_size, size_t leng size_t root_directory_sector = (align_val(sizeof(kkfs_struct), sector_size) + align_val(sectors_count * sizeof(kkfs_sector_info), sector_size)) / sector_size; fs->current_directory_index = 0; - fs->current_directory = force_malloc_s(sizeof(kkfs_directory), KKFS_DIRECTORY_RECURSION); + fs->current_directory = force_malloc_s(kkfs_directory, KKFS_DIRECTORY_RECURSION); fs->current_directory[0].type = KKFS_DIRECTORY; fs->current_directory[0].data_sector = (uint32_t)root_directory_sector; fs->current_directory[0].flags = fs->data.header.flags; @@ -431,11 +176,11 @@ void kkfs_wopen(kkfs* fs, wchar_t* path, kkc* curse, uint64_t parent_hash, kkc* size_t root_directory_sector = (align_val(sizeof(kkfs_struct), sector_size) + align_val(sectors_count * sizeof(kkfs_sector_info), sector_size)) / sector_size; fs->current_directory_index = 0; - fs->current_directory = force_malloc_s(sizeof(kkfs_directory), KKFS_DIRECTORY_RECURSION); + fs->current_directory = force_malloc_s(kkfs_directory, KKFS_DIRECTORY_RECURSION); fs->current_directory[0].data_sector = (uint32_t)root_directory_sector; fs->current_directory[0].flags = fs->data.header.flags; - fs->sector_info = force_malloc_s(sizeof(kkfs_sector_info), sectors_count); + fs->sector_info = force_malloc_s(kkfs_sector_info, sectors_count); _fseeki64(fs->io, KKFS_SECTOR_SIZE, SEEK_SET); fread(fs->sector_info, sizeof(kkfs_sector_info), sectors_count, fs->io); } @@ -715,54 +460,270 @@ void kkfs_close(kkfs* fs) { fs->io = 0; } -void kkfs_storage_init() { - memset(&fs_storage, 0, sizeof(kkfs_storage)); - - size_t size = BUF_SIZE / sizeof(kkfs*); - fs_storage.begin = force_malloc_s(sizeof(kkfs*), size); - fs_storage.end = fs_storage.begin; - fs_storage.capacity_end = fs_storage.begin + size; -} - -void kkfs_storage_dispose() { - size_t size = fs_storage.end - fs_storage.begin; - for (size_t i = 0; i < size; i++) - kkfs_dispose(fs_storage.begin[i]); - free(fs_storage.begin); - memset(&fs_storage, 0, sizeof(kkfs_storage)); -} - -void kkfs_storage_append(kkfs* fs) { +void kkfs_dispose(kkfs* fs) { if (!fs) return; - size_t size = fs_storage.end - fs_storage.begin; - size_t capacity = fs_storage.capacity_end - fs_storage.begin; - while (size >= capacity) { - kkfs** temp = force_malloc_s(sizeof(kkfs*), capacity * 2 + 1); - memcpy(temp, fs_storage.begin, sizeof(kkfs*) * size); - free(fs_storage.begin); - fs_storage.begin = temp; - fs_storage.end = temp + size; - fs_storage.capacity_end = temp + capacity * 2 + 1; - } - - *fs_storage.end++ = fs; + free(fs->current_directory); + free(fs->sector_info); + free(fs); } -void kkfs_storage_delete(kkfs* fs) { - if (!fs) +static uint32_t kkfs_allocate_sectors(kkfs* fs, uint32_t sectors) { + if (!sectors) + return 0; + + fs->free_sector = kkfs_get_free_sector(fs, fs->free_sector); + if (!fs->free_sector) + return 0; + + fs->sector_info_changed = true; + fs->sector_info[fs->free_sector] = KKFS_SECTOR_END_OF_CHAIN; + uint32_t first_sector = fs->free_sector; + for (size_t i = 1; i < sectors; i++) { + kkfs_append_sector(fs, 0); + if (!fs->free_sector) { + kkfs_free_sector(fs, first_sector); + return 0; + } + } + return first_sector; +} + +static uint32_t kkfs_allocate_sector(kkfs* fs) { + fs->free_sector = kkfs_get_free_sector(fs, fs->free_sector); + if (fs->free_sector) { + fs->sector_info_changed = true; + fs->sector_info[fs->free_sector] = KKFS_SECTOR_END_OF_CHAIN; + } + return fs->free_sector; +} + +static uint32_t kkfs_append_sector(kkfs* fs, uint32_t sector) { + uint32_t prev_sector = sector ? sector : fs->free_sector; + fs->free_sector = kkfs_get_free_sector(fs, prev_sector); + if (fs->free_sector) { + fs->sector_info_changed = true; + fs->sector_info[prev_sector] = fs->free_sector; + } + fs->sector_info[fs->free_sector] = KKFS_SECTOR_END_OF_CHAIN; + return fs->free_sector; +} + +static uint32_t kkfs_calculate_key_hash(kkc* curse) { + if (!curse) + return 0; + + size_t kl = (size_t)curse->key.type * 8; + return hash_murmurhash((uint8_t*)curse->key.data, kl, 0, false, false); +} + +static bool kkfs_find(kkfs* fs, kkfs_data* data, wchar_t* path) { + size_t pos; + size_t sector; + kkfs_data dat; + uint32_t info; + + size_t path_length = min(KKFS_NAME_LENGTH, wcslen(path) + 1); + kkfs_directory* curr_dir = &fs->current_directory[fs->current_directory_index]; + size_t data_sector = curr_dir->data_sector; + + _fseeki64(fs->io, data_sector * fs->data.header.sector_size, SEEK_SET); + do { + fread(&dat, sizeof(kkfs_data), 1, fs->io); + pos = _ftelli64(fs->io); + + if (dat.type == KKFS_DIRECTORY || dat.type == KKFS_FILE) { + wchar_t* name = dat.type == KKFS_DIRECTORY ? dat.dir.name : dat.file.name; + if (!memcmp(name, path, sizeof(wchar_t) * path_length)) { + *data = dat; + return true; + } + } + + sector = pos / fs->data.header.sector_size; + if (!(pos % fs->data.header.sector_size)) { + info = (uint32_t)fs->sector_info[sector - 1]; + if (info > KKFS_SECTOR_RESERVED && info != KKFS_SECTOR_END_OF_CHAIN) { + sector = info; + pos = sector * fs->data.header.sector_size; + + if (dat.type) + _fseeki64(fs->io, pos, SEEK_SET); + } + } + } while (dat.type); + return false; +} + +static bool kkfs_free(kkfs* fs, wchar_t* path) { + size_t pos; + size_t sector; + kkfs_data dat; + uint32_t info; + uint64_t time_ticks; + + size_t path_length = min(KKFS_NAME_LENGTH, wcslen(path) + 1); + kkfs_directory* curr_dir = &fs->current_directory[fs->current_directory_index]; + size_t data_sector = curr_dir->data_sector; + + _fseeki64(fs->io, data_sector * fs->data.header.sector_size, SEEK_SET); + do { + fread(&dat, sizeof(kkfs_data), 1, fs->io); + pos = _ftelli64(fs->io); + + if (dat.type == KKFS_DIRECTORY || dat.type == KKFS_FILE) { + wchar_t* name = dat.type == KKFS_DIRECTORY ? dat.dir.name : dat.file.name; + if (!memcmp(name, path, sizeof(wchar_t) * path_length)) { + time_ticks = kkfs_get_current_time_ticks(); + + memset(&dat, 0, sizeof(kkfs_data)); + dat.type = KKFS_DELETED; + _fseeki64(fs->io, pos - sizeof(kkfs_data), SEEK_SET); + fwrite(&dat, sizeof(kkfs_data), 1, fs->io); + return true; + } + } + + sector = pos / fs->data.header.sector_size; + if (!(pos % fs->data.header.sector_size)) { + info = (uint32_t)fs->sector_info[sector - 1]; + if (info > KKFS_SECTOR_RESERVED && info != KKFS_SECTOR_END_OF_CHAIN) { + sector = info; + pos = sector * fs->data.header.sector_size; + + if (dat.type) + _fseeki64(fs->io, pos, SEEK_SET); + } + } + } while (dat.type); + return false; +} + +static void kkfs_free_sector(kkfs* fs, uint32_t sector) { + uint32_t info; + do { + info = (uint32_t)fs->sector_info[sector]; + fs->sector_info[sector] = KKFS_SECTOR_FREE; + sector = info; + } while (info > KKFS_SECTOR_RESERVED && info != KKFS_SECTOR_END_OF_CHAIN); +} + +static uint64_t kkfs_get_current_time_ticks() { + FILETIME time; + GetSystemTimeAsFileTime(&time); + return *(uint64_t*)&time + 504911232000000000; +} + +static uint32_t kkfs_get_free_sector(kkfs* fs, uint32_t sector) { + if (sector) { + for (size_t i = sector + 1LL; i < fs->data.header.sectors_count; i++) + if (fs->sector_info[i] == KKFS_SECTOR_FREE) + return (uint32_t)i; + + for (size_t i = 0; i < sector; i++) + if (fs->sector_info[i] == KKFS_SECTOR_FREE) + return (uint32_t)i; + } + else + for (size_t i = 0; i < fs->data.header.sectors_count; i++) + if (fs->sector_info[i] == KKFS_SECTOR_FREE) + return (uint32_t)i; + return 0; +} + +static void kkfs_write_changes(kkfs* fs) { + if (fs->data.header.flags & KKFS_DIRECTORY_READ_ONLY) return; - size_t size = fs_storage.end - fs_storage.begin; - for (size_t i = 0; i < size; i++) { - if (fs_storage.begin[i] != fs) - continue; + if (fs->data_changed) { + kkfs_write_first_sector(fs); + fs->data_changed = false; + } - kkfs_dispose(fs); - memmove(&fs_storage.begin[i], &fs_storage.begin[i + 1], fs_storage.end - &fs_storage.begin[i]); - memset(&fs_storage.begin[size - 1], 0, sizeof(kkfs*)); - fs_storage.end--; - break; + if (fs->sector_info_changed) { + kkfs_write_sector_info(fs); + fs->sector_info_changed = false; + } +} + +static void kkfs_write_first_sector(kkfs* fs) { + _fseeki64(fs->io, 0x00, SEEK_SET); + fwrite(&fs->data, sizeof(kkfs_struct), 1, fs->io); +} + +static bool kkfs_write_kkfs_data(kkfs* fs, kkfs_data* data) { + size_t pos; + size_t sector; + kkfs_data dat; + uint32_t info; + uint64_t time_ticks; + + kkfs_directory* curr_dir = &fs->current_directory[fs->current_directory_index]; + size_t data_sector = curr_dir->data_sector; + + _fseeki64(fs->io, data_sector * fs->data.header.sector_size, SEEK_SET); + do { + fread(&dat, sizeof(kkfs_data), 1, fs->io); + pos = _ftelli64(fs->io); + + if ((dat.type == KKFS_DIRECTORY || dat.type == KKFS_FILE) + && (data->type == KKFS_DIRECTORY || data->type == KKFS_FILE)) { + wchar_t* name0 = dat.type == KKFS_DIRECTORY ? dat.dir.name : dat.file.name; + wchar_t* name1 = data->type == KKFS_DIRECTORY ? data->dir.name : data->file.name; + if (!memcmp(name0, name1, sizeof(wchar_t) * KKFS_NAME_LENGTH)) + return false; + } + + + sector = pos / fs->data.header.sector_size; + if (!(pos % fs->data.header.sector_size)) { + info = (uint32_t)fs->sector_info[sector - 1]; + if (info > KKFS_SECTOR_RESERVED && info != KKFS_SECTOR_END_OF_CHAIN) { + sector = info; + pos = sector * fs->data.header.sector_size; + + if (dat.type == KKFS_DIRECTORY || dat.type == KKFS_FILE) + _fseeki64(fs->io, pos, SEEK_SET); + } + } + } while (dat.type == KKFS_DIRECTORY || dat.type == KKFS_FILE); + + time_ticks = kkfs_get_current_time_ticks(); + if (!(pos % fs->data.header.sector_size)) + kkfs_append_sector(fs, (uint32_t)(sector - 1)); + + if (dat.type == KKFS_EMPTY || dat.type == KKFS_DELETED) + pos -= sizeof(kkfs_data); + + _fseeki64(fs->io, pos, SEEK_SET); + fwrite(data, sizeof(kkfs_data), 1, fs->io); + return true; +} + +static void kkfs_write_sector_info(kkfs* fs) { + _fseeki64(fs->io, fs->data.header.sector_size, SEEK_SET); + size_t length = fs->data.header.sectors_count; + size_t temp = length * sizeof(kkfs_sector_info); + size_t temp_aligned = align_val(temp, fs->data.header.sector_size); + + uint8_t* td = force_malloc(fs->data.header.sector_size); + fwrite(fs->sector_info, sizeof(kkfs_sector_info), length, fs->io); + if (temp_aligned - temp) + fwrite(td, 1, temp_aligned - temp, fs->io); + free(td); +} + +static inline void next_rand_uint8_t_pointer(uint8_t* arr, size_t length, uint32_t* state) { + if (!arr || length < 1) + return; + + for (size_t i = 0; i < length; i++) { + uint32_t x = *state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + *state = x; + arr[i] = (uint8_t)x; } } diff --git a/src/KKdLib/kkfs.h b/src/KKdLib/kkfs.h index 40c4a38b..dcad489a 100644 --- a/src/KKdLib/kkfs.h +++ b/src/KKdLib/kkfs.h @@ -7,6 +7,7 @@ #include "default.h" #include "kkc.h" +#include "vector.h" #define KKFS_SECTOR_SIZE 0x200 #define KKFS_DIRECTORY_RECURSION 0x100 @@ -20,12 +21,12 @@ typedef enum kkfs_sector_info { } kkfs_sector_info; typedef enum kkfs_directory_flags { - KKFS_DIRECTORY_READ_ONLY = 0b01, + KKFS_DIRECTORY_READ_ONLY = 0x1, } kkfs_directory_flags; typedef enum kkfs_file_flags { - KKFS_FILE_READ_ONLY = 0b01, - KKFS_FILE_CURSED = 0b10, + KKFS_FILE_READ_ONLY = 0x1, + KKFS_FILE_CURSED = 0x2, } kkfs_file_flags; typedef enum kkfs_type { @@ -99,16 +100,7 @@ typedef struct kkfs { bool sector_info_changed; } kkfs; -typedef struct kkfs_storage { - kkfs** begin; - kkfs** end; - kkfs** capacity_end; -} kkfs_storage; - -extern kkfs_storage fs_storage; - extern kkfs* kkfs_init(); -extern void kkfs_dispose(kkfs* fs); extern void kkfs_initialize(kkfs* fs, char* path, uint32_t sector_size, size_t length, kkfs_directory_flags flags, kkc* curse, uint32_t parent_hash, kkc* parent_curse); extern void kkfs_winitialize(kkfs* fs, wchar_t* path, uint32_t sector_size, size_t length, @@ -131,7 +123,4 @@ extern bool kkfs_wwrite_file(kkfs* fs, wchar_t* path, void* data, size_t data_le extern bool kkfs_delete_file(kkfs* fs, char* path); extern bool kkfs_wdelete_file(kkfs* fs, wchar_t* path); extern void kkfs_close(kkfs* fs); -extern void kkfs_storage_init(); -extern void kkfs_storage_dispose(); -extern void kkfs_storage_append(kkfs* fs); -extern void kkfs_storage_delete(kkfs* fs); +extern void kkfs_dispose(kkfs* fs); diff --git a/src/KKdLib/mat.c b/src/KKdLib/mat.c index 6aec14ce..c77187ed 100644 --- a/src/KKdLib/mat.c +++ b/src/KKdLib/mat.c @@ -32,7 +32,7 @@ const mat4 mat4_null = { { 0.0f, 0.0f, 0.0f, 0.0f }, }; -void FASTCALL mat3_add(mat3* x, mat3* y, mat3* z) { +inline void FASTCALL mat3_add(mat3* x, mat3* y, mat3* z) { __m128 xt; __m128 yt; __m128 zt; @@ -50,7 +50,7 @@ void FASTCALL mat3_add(mat3* x, mat3* y, mat3* z) { z->row2 = *(vec3*)&zt; } -void FASTCALL mat3_sub(mat3* x, mat3* y, mat3* z) { +inline void FASTCALL mat3_sub(mat3* x, mat3* y, mat3* z) { __m128 xt; __m128 yt; __m128 zt; @@ -68,7 +68,7 @@ void FASTCALL mat3_sub(mat3* x, mat3* y, mat3* z) { z->row2 = *(vec3*)&zt; } -void FASTCALL mat3_mult(mat3* x, mat3* y, mat3* z) { +inline void FASTCALL mat3_mult(mat3* x, mat3* y, mat3* z) { __m128 t0; __m128 t1; __m128 t2; @@ -81,40 +81,44 @@ void FASTCALL mat3_mult(mat3* x, mat3* y, mat3* z) { *(vec3*)&xt1 = x->row1; *(vec3*)&xt2 = x->row2; *(vec3*)&yt = y->row0; - t0 = _mm_mul_ps(xt0, _mm_shuffle_ps(yt, yt, 0b00000000)); - t1 = _mm_mul_ps(xt1, _mm_shuffle_ps(yt, yt, 0b01010101)); - t2 = _mm_mul_ps(xt2, _mm_shuffle_ps(yt, yt, 0b10101010)); + t0 = _mm_mul_ps(xt0, _mm_shuffle_ps(yt, yt, 0x00)); + t1 = _mm_mul_ps(xt1, _mm_shuffle_ps(yt, yt, 0x55)); + t2 = _mm_mul_ps(xt2, _mm_shuffle_ps(yt, yt, 0xAA)); zt = _mm_add_ps(_mm_add_ps(t0, t1), t2); z->row0 = *(vec3*)&zt; *(vec3*)&yt = y->row1; - t0 = _mm_mul_ps(xt0, _mm_shuffle_ps(yt, yt, 0b00000000)); - t1 = _mm_mul_ps(xt1, _mm_shuffle_ps(yt, yt, 0b01010101)); - t2 = _mm_mul_ps(xt2, _mm_shuffle_ps(yt, yt, 0b10101010)); + t0 = _mm_mul_ps(xt0, _mm_shuffle_ps(yt, yt, 0x00)); + t1 = _mm_mul_ps(xt1, _mm_shuffle_ps(yt, yt, 0x55)); + t2 = _mm_mul_ps(xt2, _mm_shuffle_ps(yt, yt, 0xAA)); zt = _mm_add_ps(_mm_add_ps(t0, t1), t2); z->row1 = *(vec3*)&zt; *(vec3*)&yt = y->row2; - t0 = _mm_mul_ps(xt0, _mm_shuffle_ps(yt, yt, 0b00000000)); - t1 = _mm_mul_ps(xt1, _mm_shuffle_ps(yt, yt, 0b01010101)); - t2 = _mm_mul_ps(xt2, _mm_shuffle_ps(yt, yt, 0b10101010)); + t0 = _mm_mul_ps(xt0, _mm_shuffle_ps(yt, yt, 0x00)); + t1 = _mm_mul_ps(xt1, _mm_shuffle_ps(yt, yt, 0x55)); + t2 = _mm_mul_ps(xt2, _mm_shuffle_ps(yt, yt, 0xAA)); zt = _mm_add_ps(_mm_add_ps(t0, t1), t2); z->row2 = *(vec3*)&zt; } -void FASTCALL mat3_mult_vec(mat3* x, vec3* y, vec3* z) { +inline void FASTCALL mat3_mult_vec(mat3* x, vec3* y, vec3* z) { __m128 xt; __m128 yt; __m128 zt; - *(vec3*)&xt = x->row0; + __m128 zt0; + __m128 zt1; + __m128 zt2; *(vec3*)&yt = *y; - zt = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0b00000000)); + *(vec3*)&xt = x->row0; + zt0 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0x00)); *(vec3*)&xt = x->row1; - zt = _mm_add_ps(zt, _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0b01010101))); + zt1 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0x55)); *(vec3*)&xt = x->row2; - zt = _mm_add_ps(zt, _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0b10101010))); + zt2 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0xAA)); + zt = _mm_add_ps(_mm_add_ps(zt0, zt1), zt2); *z = *(vec3*)&zt; } -void FASTCALL mat3_mult_scalar(mat3* x, float_t y, mat3* z) { +inline void FASTCALL mat3_mult_scalar(mat3* x, float_t y, mat3* z) { __m128 xt; __m128 yt; __m128 zt; @@ -131,7 +135,7 @@ void FASTCALL mat3_mult_scalar(mat3* x, float_t y, mat3* z) { z->row2 = *(vec3*)&zt; } -void FASTCALL mat3_transpose(mat3* x, mat3* z) { +inline void FASTCALL mat3_transpose(mat3* x, mat3* z) { __m128 xt0; __m128 xt1; __m128 xt2; @@ -146,7 +150,7 @@ void FASTCALL mat3_transpose(mat3* x, mat3* z) { *(vec3*)&xt0 = x->row0; *(vec3*)&xt1 = x->row1; *(vec3*)&xt2 = x->row2; - xt3 = (__m128){ .m128_f32 = { 0.0f, 0.0f, 0.0f, 0.0f } }; + xt3 = vec4_null.data; yt0 = _mm_unpacklo_ps(xt0, xt1); yt1 = _mm_unpackhi_ps(xt0, xt1); yt2 = _mm_unpacklo_ps(xt2, xt3); @@ -204,8 +208,8 @@ void FASTCALL mat3_inverse(mat3* x, mat3* z) { wt = _mm_movelh_ps(_mm_unpacklo_ps(zt0, zt1), zt2); *(vec3*)&yt = xt0; + yt.m128_f32[3] = 0.0f; wt = _mm_mul_ps(yt, wt); - wt.m128_f32[3] = 0.0f; wt = _mm_hadd_ps(wt, wt); wt = _mm_hadd_ps(wt, wt); if (wt.m128_f32[0] != 0.0f) @@ -219,37 +223,39 @@ void FASTCALL mat3_inverse(mat3* x, mat3* z) { z->row2 = *(vec3*)&yt; } -void FASTCALL mat3_invtrans(mat3* x, mat3* z) { +inline void FASTCALL mat3_invtrans(mat3* x, mat3* z) { mat3 t = *x; mat3_inverse(&t, &t); mat3_transpose(&t, &t); *z = t; } -void FASTCALL mat3_normalize(mat3* x, mat3* z) { +inline void FASTCALL mat3_normalize(mat3* x, mat3* z) { __m128 det; - __m128 xt; + __m128 xt0; + __m128 xt1; + __m128 xt2; det = _mm_set_ss(mat3_determinant(x)); if (det.m128_f32[0] != 0.0f) det.m128_f32[0] = 1.0f / det.m128_f32[0]; det = _mm_shuffle_ps(det, det, 0); - *(vec3*)&xt = x->row0; - xt = _mm_mul_ps(xt, det); - z->row0 = *(vec3*)&xt; - *(vec3*)&xt = x->row1; - xt = _mm_mul_ps(xt, det); - z->row1 = *(vec3*)&xt; - *(vec3*)&xt = x->row2; - xt = _mm_mul_ps(xt, det); - z->row2 = *(vec3*)&xt; + *(vec3*)&xt0 = x->row0; + *(vec3*)&xt1 = x->row1; + *(vec3*)&xt2 = x->row2; + xt0 = _mm_mul_ps(xt0, det); + xt1 = _mm_mul_ps(xt1, det); + xt2 = _mm_mul_ps(xt2, det); + z->row0 = *(vec3*)&xt0; + z->row1 = *(vec3*)&xt1; + z->row2 = *(vec3*)&xt2; } void FASTCALL mat3_normalize_rotation(mat3* x, mat3* z) { __m128 xt; __m128 yt; *(vec3*)&xt = x->row0; + xt.m128_f32[3] = 0.0f; yt = _mm_mul_ps(xt, xt); - yt.m128_f32[3] = 0.0f; yt = _mm_hadd_ps(yt, yt); yt = _mm_sqrt_ss(_mm_hadd_ps(yt, yt)); if (yt.m128_f32[0] != 0.0f) @@ -257,8 +263,8 @@ void FASTCALL mat3_normalize_rotation(mat3* x, mat3* z) { xt = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0)); z->row0 = *(vec3*)&xt; *(vec3*)&xt = x->row1; + xt.m128_f32[3] = 0.0f; yt = _mm_mul_ps(xt, xt); - yt.m128_f32[3] = 0.0f; yt = _mm_hadd_ps(yt, yt); yt = _mm_sqrt_ss(_mm_hadd_ps(yt, yt)); if (yt.m128_f32[0] != 0.0f) @@ -266,8 +272,8 @@ void FASTCALL mat3_normalize_rotation(mat3* x, mat3* z) { xt = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0)); z->row1 = *(vec3*)&xt; *(vec3*)&xt = x->row2; + xt.m128_f32[3] = 0.0f; yt = _mm_mul_ps(xt, xt); - yt.m128_f32[3] = 0.0f; yt = _mm_hadd_ps(yt, yt); yt = _mm_sqrt_ss(_mm_hadd_ps(yt, yt)); if (yt.m128_f32[0] != 0.0f) @@ -276,7 +282,7 @@ void FASTCALL mat3_normalize_rotation(mat3* x, mat3* z) { z->row2 = *(vec3*)&xt; } -float_t FASTCALL mat3_determinant(mat3* x) { +inline float_t FASTCALL mat3_determinant(mat3* x) { vec3 xt0; vec3 xt1; vec3 xt2; @@ -292,7 +298,7 @@ float_t FASTCALL mat3_determinant(mat3* x) { return b00 + b01 + b02 - b03 - b04 - b05; } -void FASTCALL mat3_rotate(float_t x, float_t y, float_t z, mat3* d) { +inline void FASTCALL mat3_rotate(float_t x, float_t y, float_t z, mat3* d) { mat3 dt; dt = mat3_identity; if (z != 0.0f) @@ -304,7 +310,7 @@ void FASTCALL mat3_rotate(float_t x, float_t y, float_t z, mat3* d) { *d = dt; } -void FASTCALL mat3_rotate_x(float_t x, mat3* y) { +inline void FASTCALL mat3_rotate_x(float_t x, mat3* y) { mat3 yt; float_t x_sin = sinf(x); float_t x_cos = cosf(x); @@ -316,7 +322,7 @@ void FASTCALL mat3_rotate_x(float_t x, mat3* y) { *y = yt; } -void FASTCALL mat3_rotate_y(float_t x, mat3* y) { +inline void FASTCALL mat3_rotate_y(float_t x, mat3* y) { mat3 yt; float_t x_sin = sinf(x); float_t x_cos = cosf(x); @@ -328,7 +334,7 @@ void FASTCALL mat3_rotate_y(float_t x, mat3* y) { *y = yt; } -void FASTCALL mat3_rotate_z(float_t x, mat3* y) { +inline void FASTCALL mat3_rotate_z(float_t x, mat3* y) { mat3 yt; float_t x_sin = sinf(x); float_t x_cos = cosf(x); @@ -340,7 +346,7 @@ void FASTCALL mat3_rotate_z(float_t x, mat3* y) { *y = yt; } -void FASTCALL mat3_rotate_mult(mat3* s, float_t x, float_t y, float_t z, mat3* d) { +inline void FASTCALL mat3_rotate_mult(mat3* s, float_t x, float_t y, float_t z, mat3* d) { mat3 dt; dt = *s; if (z != 0.0f) @@ -352,7 +358,7 @@ void FASTCALL mat3_rotate_mult(mat3* s, float_t x, float_t y, float_t z, mat3* d *d = dt; } -void FASTCALL mat3_rotate_x_mult(mat3* x, float_t y, mat3* z) { +inline void FASTCALL mat3_rotate_x_mult(mat3* x, float_t y, mat3* z) { mat3 yt; float_t y_sin = sinf(y); float_t y_cos = cosf(y); @@ -364,7 +370,7 @@ void FASTCALL mat3_rotate_x_mult(mat3* x, float_t y, mat3* z) { mat3_mult(x, &yt, z); } -void FASTCALL mat3_rotate_y_mult(mat3* x, float_t y, mat3* z) { +inline void FASTCALL mat3_rotate_y_mult(mat3* x, float_t y, mat3* z) { mat3 yt; float_t y_sin = sinf(y); float_t y_cos = cosf(y); @@ -376,7 +382,7 @@ void FASTCALL mat3_rotate_y_mult(mat3* x, float_t y, mat3* z) { mat3_mult(x, &yt, z); } -void FASTCALL mat3_rotate_z_mult(mat3* x, float_t y, mat3* z) { +inline void FASTCALL mat3_rotate_z_mult(mat3* x, float_t y, mat3* z) { mat3 yt; float_t y_sin = sinf(y); float_t y_cos = cosf(y); @@ -388,7 +394,7 @@ void FASTCALL mat3_rotate_z_mult(mat3* x, float_t y, mat3* z) { mat3_mult(x, &yt, z); } -void FASTCALL mat3_scale(float_t x, float_t y, float_t z, mat3* d) { +inline void FASTCALL mat3_scale(float_t x, float_t y, float_t z, mat3* d) { mat3 dt; dt = mat3_identity; if (x != 1.0f) @@ -400,28 +406,28 @@ void FASTCALL mat3_scale(float_t x, float_t y, float_t z, mat3* d) { *d = dt; } -void FASTCALL mat3_scale_x(float_t x, mat3* y) { +inline void FASTCALL mat3_scale_x(float_t x, mat3* y) { mat3 yt; yt = mat3_identity; yt.row0.x = x; *y = yt; } -void FASTCALL mat3_scale_y(float_t x, mat3* y) { +inline void FASTCALL mat3_scale_y(float_t x, mat3* y) { mat3 yt; yt = mat3_identity; yt.row1.y = x; *y = yt; } -void FASTCALL mat3_scale_z(float_t x, mat3* y) { +inline void FASTCALL mat3_scale_z(float_t x, mat3* y) { mat3 yt; yt = mat3_identity; yt.row2.z = x; *y = yt; } -void FASTCALL mat3_scale_mult(mat3* s, float_t x, float_t y, float_t z, mat3* d) { +inline void FASTCALL mat3_scale_mult(mat3* s, float_t x, float_t y, float_t z, mat3* d) { mat3 st; mat3 dt; if (x != 1.0f || y != 1.0f || z != 1.0f) { @@ -437,28 +443,28 @@ void FASTCALL mat3_scale_mult(mat3* s, float_t x, float_t y, float_t z, mat3* d) *d = *s; } -void FASTCALL mat3_scale_x_mult(mat3* x, float_t y, mat3* z) { +inline void FASTCALL mat3_scale_x_mult(mat3* x, float_t y, mat3* z) { mat3 yt; yt = mat3_identity; yt.row0.x = y; mat3_mult(x, &yt, z); } -void FASTCALL mat3_scale_y_mult(mat3* x, float_t y, mat3* z) { +inline void FASTCALL mat3_scale_y_mult(mat3* x, float_t y, mat3* z) { mat3 yt; yt = mat3_identity; yt.row1.y = y; mat3_mult(x, &yt, z); } -void FASTCALL mat3_scale_z_mult(mat3* x, float_t y, mat3* z) { +inline void FASTCALL mat3_scale_z_mult(mat3* x, float_t y, mat3* z) { mat3 yt; yt = mat3_identity; yt.row2.z = y; mat3_mult(x, &yt, z); } -void FASTCALL mat3_from_quat(quat* quat, mat3* mat) { +inline void FASTCALL mat3_from_quat(quat* quat, mat3* mat) { float_t y; float_t x; float_t z; @@ -500,21 +506,42 @@ void FASTCALL mat3_from_quat(quat* quat, mat3* mat) { mat->row2.z = 1.0f - yy - xx; } -void FASTCALL mat4_add(mat4* x, mat4* y, mat4* z) { - *(__m128*)& z->row0 = _mm_add_ps(*(__m128*) & x->row0, *(__m128*) & y->row0); - *(__m128*)& z->row1 = _mm_add_ps(*(__m128*) & x->row1, *(__m128*) & y->row1); - *(__m128*)& z->row2 = _mm_add_ps(*(__m128*) & x->row2, *(__m128*) & y->row2); - *(__m128*)& z->row3 = _mm_add_ps(*(__m128*) & x->row3, *(__m128*) & y->row3); +inline void FASTCALL mat3_from_mat4(mat4* x, mat3* z) { + z->row0 = *(vec3*)&x->row0; + z->row1 = *(vec3*)&x->row1; + z->row2 = *(vec3*)&x->row2; } -void FASTCALL mat4_sub(mat4* x, mat4* y, mat4* z) { - *(__m128*)& z->row0 = _mm_sub_ps(*(__m128*) & x->row0, *(__m128*) & y->row0); - *(__m128*)& z->row1 = _mm_sub_ps(*(__m128*) & x->row1, *(__m128*) & y->row1); - *(__m128*)& z->row2 = _mm_sub_ps(*(__m128*) & x->row2, *(__m128*) & y->row2); - *(__m128*)& z->row3 = _mm_sub_ps(*(__m128*) & x->row3, *(__m128*) & y->row3); +inline void FASTCALL mat3_from_mat4_inverse(mat4* x, mat3* z) { + mat4 yt; + + mat4_inverse(x, &yt); + z->row0 = *(vec3*)&yt.row0; + z->row1 = *(vec3*)&yt.row1; + z->row2 = *(vec3*)&yt.row2; } -void FASTCALL mat4_mult(mat4* x, mat4* y, mat4* z) { +inline void FASTCALL mat3_get_scale(mat3* x, vec3* z) { + vec3_length(x->row0, z->x); + vec3_length(x->row1, z->y); + vec3_length(x->row2, z->z); +} + +inline void FASTCALL mat4_add(mat4* x, mat4* y, mat4* z) { + z->row0.data = _mm_add_ps(x->row0.data, y->row0.data); + z->row1.data = _mm_add_ps(x->row1.data, y->row1.data); + z->row2.data = _mm_add_ps(x->row2.data, y->row2.data); + z->row3.data = _mm_add_ps(x->row3.data, y->row3.data); +} + +inline void FASTCALL mat4_sub(mat4* x, mat4* y, mat4* z) { + z->row0.data = _mm_sub_ps(x->row0.data, y->row0.data); + z->row1.data = _mm_sub_ps(x->row1.data, y->row1.data); + z->row2.data = _mm_sub_ps(x->row2.data, y->row2.data); + z->row3.data = _mm_sub_ps(x->row3.data, y->row3.data); +} + +inline void FASTCALL mat4_mult(mat4* x, mat4* y, mat4* z) { __m128 t0; __m128 t1; __m128 t2; @@ -524,100 +551,123 @@ void FASTCALL mat4_mult(mat4* x, mat4* y, mat4* z) { __m128 y1; __m128 y2; __m128 y3; - __m128 zt; - *(vec4*)&y0 = y->row0; - *(vec4*)&y1 = y->row1; - *(vec4*)&y2 = y->row2; - *(vec4*)&y3 = y->row3; - *(vec4*)&xt = x->row0; - t0 = _mm_mul_ps(y0, _mm_shuffle_ps(xt, xt, 0b00000000)); - t1 = _mm_mul_ps(y1, _mm_shuffle_ps(xt, xt, 0b01010101)); - t2 = _mm_mul_ps(y2, _mm_shuffle_ps(xt, xt, 0b10101010)); - t3 = _mm_mul_ps(y3, _mm_shuffle_ps(xt, xt, 0b11111111)); - zt = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); - z->row0 = *(vec4*)&zt; - *(vec4*)&xt = x->row1; - t0 = _mm_mul_ps(y0, _mm_shuffle_ps(xt, xt, 0b00000000)); - t1 = _mm_mul_ps(y1, _mm_shuffle_ps(xt, xt, 0b01010101)); - t2 = _mm_mul_ps(y2, _mm_shuffle_ps(xt, xt, 0b10101010)); - t3 = _mm_mul_ps(y3, _mm_shuffle_ps(xt, xt, 0b11111111)); - zt = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); - z->row1 = *(vec4*)&zt; - *(vec4*)&xt = x->row2; - t0 = _mm_mul_ps(y0, _mm_shuffle_ps(xt, xt, 0b00000000)); - t1 = _mm_mul_ps(y1, _mm_shuffle_ps(xt, xt, 0b01010101)); - t2 = _mm_mul_ps(y2, _mm_shuffle_ps(xt, xt, 0b10101010)); - t3 = _mm_mul_ps(y3, _mm_shuffle_ps(xt, xt, 0b11111111)); - zt = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); - z->row2 = *(vec4*)&zt; - *(vec4*)&xt = x->row3; - t0 = _mm_mul_ps(y0, _mm_shuffle_ps(xt, xt, 0b00000000)); - t1 = _mm_mul_ps(y1, _mm_shuffle_ps(xt, xt, 0b01010101)); - t2 = _mm_mul_ps(y2, _mm_shuffle_ps(xt, xt, 0b10101010)); - t3 = _mm_mul_ps(y3, _mm_shuffle_ps(xt, xt, 0b11111111)); - zt = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); - z->row3 = *(vec4*)&zt; + y0 = y->row0.data; + y1 = y->row1.data; + y2 = y->row2.data; + y3 = y->row3.data; + xt = x->row0.data; + t0 = _mm_mul_ps(y0, _mm_shuffle_ps(xt, xt, 0x00)); + t1 = _mm_mul_ps(y1, _mm_shuffle_ps(xt, xt, 0x55)); + t2 = _mm_mul_ps(y2, _mm_shuffle_ps(xt, xt, 0xAA)); + t3 = _mm_mul_ps(y3, _mm_shuffle_ps(xt, xt, 0xFF)); + z->row0.data = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); + xt = x->row1.data; + t0 = _mm_mul_ps(y0, _mm_shuffle_ps(xt, xt, 0x00)); + t1 = _mm_mul_ps(y1, _mm_shuffle_ps(xt, xt, 0x55)); + t2 = _mm_mul_ps(y2, _mm_shuffle_ps(xt, xt, 0xAA)); + t3 = _mm_mul_ps(y3, _mm_shuffle_ps(xt, xt, 0xFF)); + z->row1.data = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); + xt = x->row2.data; + t0 = _mm_mul_ps(y0, _mm_shuffle_ps(xt, xt, 0x00)); + t1 = _mm_mul_ps(y1, _mm_shuffle_ps(xt, xt, 0x55)); + t2 = _mm_mul_ps(y2, _mm_shuffle_ps(xt, xt, 0xAA)); + t3 = _mm_mul_ps(y3, _mm_shuffle_ps(xt, xt, 0xFF)); + z->row2.data = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); + xt = x->row3.data; + t0 = _mm_mul_ps(y0, _mm_shuffle_ps(xt, xt, 0x00)); + t1 = _mm_mul_ps(y1, _mm_shuffle_ps(xt, xt, 0x55)); + t2 = _mm_mul_ps(y2, _mm_shuffle_ps(xt, xt, 0xAA)); + t3 = _mm_mul_ps(y3, _mm_shuffle_ps(xt, xt, 0xFF)); + z->row3.data = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); } -void FASTCALL mat4_mult_vec3(mat4* x, vec3* y, vec3* z) { +inline void FASTCALL mat4_mult_vec3(mat4* x, vec3* y, vec3* z) { __m128 xt; __m128 yt; __m128 zt; - *(vec3*)&xt = *(vec3*)&x->row0; + __m128 zt0; + __m128 zt1; + __m128 zt2; *(vec3*)&yt = *y; - zt = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0b00000000)); + *(vec3*)&xt = *(vec3*)&x->row0; + zt0 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0x00)); *(vec3*)&xt = *(vec3*)&x->row1; - zt = _mm_add_ps(zt, _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0b01010101))); + zt1 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0x55)); *(vec3*)&xt = *(vec3*)&x->row2; - zt = _mm_add_ps(zt, _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0b10101010))); + zt2 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0xAA)); + zt = _mm_add_ps(_mm_add_ps(zt0, zt1), zt2); *z = *(vec3*)&zt; } -void FASTCALL mat4_mult_vec(mat4* x, vec4* y, vec4* z) { +inline void FASTCALL mat4_mult_vec3_trans(mat4* x, vec3* y, vec3* z) { + __m128 xt; __m128 yt; __m128 zt; - *(vec4*)&yt = *y; - zt = _mm_mul_ps(*(__m128*) & x->row0, _mm_shuffle_ps(yt, yt, 0b00000000)); - zt = _mm_add_ps(zt, _mm_mul_ps(*(__m128*) & x->row1, _mm_shuffle_ps(yt, yt, 0b01010101))); - zt = _mm_add_ps(zt, _mm_mul_ps(*(__m128*) & x->row2, _mm_shuffle_ps(yt, yt, 0b10101010))); - zt = _mm_add_ps(zt, _mm_mul_ps(*(__m128*) & x->row3, _mm_shuffle_ps(yt, yt, 0b11111111))); - *z = *(vec4*)&zt; + __m128 zt0; + __m128 zt1; + __m128 zt2; + __m128 zt3; + *(vec3*)&yt = *y; + *(vec3*)&xt = *(vec3*)&x->row0; + zt0 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0x00)); + *(vec3*)&xt = *(vec3*)&x->row1; + zt1 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0x55)); + *(vec3*)&xt = *(vec3*)&x->row2; + zt2 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0xAA)); + *(vec3*)&zt3 = *(vec3*)&x->row3; + zt = _mm_add_ps(_mm_add_ps(zt0, zt1), _mm_add_ps(zt2, zt3)); + *z = *(vec3*)&zt; } -void FASTCALL mat4_mult_scalar(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_mult_vec(mat4* x, vec4* y, vec4* z) { + __m128 yt; + __m128 zt0; + __m128 zt1; + __m128 zt2; + __m128 zt3; + yt = y->data; + zt0 = _mm_mul_ps(x->row0.data, _mm_shuffle_ps(yt, yt, 0x00)); + zt1 = _mm_mul_ps(x->row1.data, _mm_shuffle_ps(yt, yt, 0x55)); + zt2 = _mm_mul_ps(x->row2.data, _mm_shuffle_ps(yt, yt, 0xAA)); + zt3 = _mm_mul_ps(x->row3.data, _mm_shuffle_ps(yt, yt, 0xFF)); + z->data = _mm_add_ps(_mm_add_ps(zt0, zt1), _mm_add_ps(zt2, zt3)); +} + +inline void FASTCALL mat4_mult_scalar(mat4* x, float_t y, mat4* z) { __m128 yt; yt = _mm_set_ss(y); yt = _mm_shuffle_ps(yt, yt, 0); - *(__m128*)& z->row0 = _mm_mul_ps(*(__m128*) & x->row0, yt); - *(__m128*)& z->row1 = _mm_mul_ps(*(__m128*) & x->row1, yt); - *(__m128*)& z->row2 = _mm_mul_ps(*(__m128*) & x->row2, yt); - *(__m128*)& z->row3 = _mm_mul_ps(*(__m128*) & x->row3, yt); + z->row0.data = _mm_mul_ps(x->row0.data, yt); + z->row1.data = _mm_mul_ps(x->row1.data, yt); + z->row2.data = _mm_mul_ps(x->row2.data, yt); + z->row3.data = _mm_mul_ps(x->row3.data, yt); } -void FASTCALL mat4_transpose(mat4* x, mat4* z) { +inline void FASTCALL mat4_transpose(mat4* x, mat4* z) { __m128 yt0; __m128 yt1; __m128 yt2; __m128 yt3; - yt0 = _mm_unpacklo_ps(*(__m128*) & x->row0, *(__m128*) & x->row1); - yt1 = _mm_unpackhi_ps(*(__m128*) & x->row0, *(__m128*) & x->row1); - yt2 = _mm_unpacklo_ps(*(__m128*) & x->row2, *(__m128*) & x->row3); - yt3 = _mm_unpackhi_ps(*(__m128*) & x->row2, *(__m128*) & x->row3); - *(__m128*)& z->row0 = _mm_movelh_ps(yt0, yt2); - *(__m128*)& z->row1 = _mm_movehl_ps(yt2, yt0); - *(__m128*)& z->row2 = _mm_movelh_ps(yt1, yt3); - *(__m128*)& z->row3 = _mm_movehl_ps(yt3, yt1); + yt0 = _mm_unpacklo_ps(x->row0.data, x->row1.data); + yt1 = _mm_unpackhi_ps(x->row0.data, x->row1.data); + yt2 = _mm_unpacklo_ps(x->row2.data, x->row3.data); + yt3 = _mm_unpackhi_ps(x->row2.data, x->row3.data); + z->row0.data = _mm_movelh_ps(yt0, yt2); + z->row1.data = _mm_movehl_ps(yt2, yt0); + z->row2.data = _mm_movelh_ps(yt1, yt3); + z->row3.data = _mm_movehl_ps(yt3, yt1); } void FASTCALL mat4_inverse(mat4* x, mat4* z) { - static const __m128 xor0 = { .m128_u32 = { 0x80000000, 0x00000000, 0x80000000, 0x00000000 } }; - static const __m128 xor1 = { .m128_u32 = { 0x00000000, 0x80000000, 0x00000000, 0x80000000 } }; + static const __m128 xor0 = { .m128_f32 = { -0.0f, 0.0f, -0.0f, 0.0f } }; + static const __m128 xor1 = { .m128_f32 = { 0.0f, -0.0f, 0.0f, -0.0f } }; vec4 xt0, xt1, xt2, xt3; __m128 yt00, yt01, yt02, yt03, yt04, yt05, yt06, yt07, yt08, yt09, yt10, yt11; __m128 zt0, zt1, zt2, zt3; __m128 wt; __m128 wt0, wt1, wt2; + __m128 t0, t1, t2, t3, t4, t5; xt0 = x->row0; xt1 = x->row1; xt2 = x->row2; @@ -634,14 +684,23 @@ void FASTCALL mat4_inverse(mat4* x, mat4* z) { yt09 = _mm_set_ps(xt0.x, xt0.x, xt0.x, xt1.x); yt10 = _mm_set_ps(xt1.x, xt1.x, xt2.x, xt2.x); yt11 = _mm_set_ps(xt2.x, xt3.x, xt3.x, xt3.x); - wt0 = _mm_mul_ps(_mm_xor_ps(yt00, xor1), _mm_sub_ps(_mm_mul_ps(yt03, yt04), _mm_mul_ps(yt05, yt06))); - wt1 = _mm_mul_ps(_mm_xor_ps(yt01, xor0), _mm_sub_ps(_mm_mul_ps(yt07, yt04), _mm_mul_ps(yt08, yt06))); - wt2 = _mm_mul_ps(_mm_xor_ps(yt02, xor1), _mm_sub_ps(_mm_mul_ps(yt07, yt05), _mm_mul_ps(yt08, yt03))); + + t0 = _mm_sub_ps(_mm_mul_ps(yt03, yt04), _mm_mul_ps(yt05, yt06)); + t1 = _mm_sub_ps(_mm_mul_ps(yt07, yt04), _mm_mul_ps(yt08, yt06)); + t2 = _mm_sub_ps(_mm_mul_ps(yt07, yt05), _mm_mul_ps(yt08, yt03)); + + t3 = _mm_xor_ps(yt09, xor0); + t4 = _mm_xor_ps(yt10, xor1); + t5 = _mm_xor_ps(yt11, xor0); + + wt0 = _mm_mul_ps(_mm_xor_ps(yt00, xor1), t0); + wt1 = _mm_mul_ps(_mm_xor_ps(yt01, xor0), t1); + wt2 = _mm_mul_ps(_mm_xor_ps(yt02, xor1), t2); zt0 = _mm_add_ps(_mm_add_ps(wt0, wt1), wt2); - wt0 = _mm_mul_ps(_mm_xor_ps(yt09, xor0), _mm_sub_ps(_mm_mul_ps(yt03, yt04), _mm_mul_ps(yt05, yt06))); - wt1 = _mm_mul_ps(_mm_xor_ps(yt10, xor1), _mm_sub_ps(_mm_mul_ps(yt07, yt04), _mm_mul_ps(yt08, yt06))); - wt2 = _mm_mul_ps(_mm_xor_ps(yt11, xor0), _mm_sub_ps(_mm_mul_ps(yt07, yt05), _mm_mul_ps(yt08, yt03))); + wt0 = _mm_mul_ps(t3, t0); + wt1 = _mm_mul_ps(t4, t1); + wt2 = _mm_mul_ps(t5, t2); zt1 = _mm_add_ps(_mm_add_ps(wt0, wt1), wt2); wt0 = _mm_mul_ps(_mm_xor_ps(yt09, xor1), _mm_sub_ps(_mm_mul_ps(yt01, yt04), _mm_mul_ps(yt05, yt02))); @@ -649,49 +708,60 @@ void FASTCALL mat4_inverse(mat4* x, mat4* z) { wt2 = _mm_mul_ps(_mm_xor_ps(yt11, xor1), _mm_sub_ps(_mm_mul_ps(yt00, yt05), _mm_mul_ps(yt08, yt01))); zt2 = _mm_add_ps(_mm_add_ps(wt0, wt1), wt2); - wt0 = _mm_mul_ps(_mm_xor_ps(yt09, xor0), _mm_sub_ps(_mm_mul_ps(yt01, yt06), _mm_mul_ps(yt03, yt02))); - wt1 = _mm_mul_ps(_mm_xor_ps(yt10, xor1), _mm_sub_ps(_mm_mul_ps(yt00, yt06), _mm_mul_ps(yt07, yt02))); - wt2 = _mm_mul_ps(_mm_xor_ps(yt11, xor0), _mm_sub_ps(_mm_mul_ps(yt00, yt03), _mm_mul_ps(yt07, yt01))); + wt0 = _mm_mul_ps(t3, _mm_sub_ps(_mm_mul_ps(yt01, yt06), _mm_mul_ps(yt03, yt02))); + wt1 = _mm_mul_ps(t4, _mm_sub_ps(_mm_mul_ps(yt00, yt06), _mm_mul_ps(yt07, yt02))); + wt2 = _mm_mul_ps(t5, _mm_sub_ps(_mm_mul_ps(yt00, yt03), _mm_mul_ps(yt07, yt01))); zt3 = _mm_add_ps(_mm_add_ps(wt0, wt1), wt2); wt = _mm_movelh_ps(_mm_unpacklo_ps(zt0, zt1), _mm_unpacklo_ps(zt2, zt3)); - wt = _mm_mul_ps(*(__m128*) & xt0, wt); + wt = _mm_mul_ps(xt0.data, wt); wt = _mm_hadd_ps(wt, wt); wt = _mm_hadd_ps(wt, wt); if (wt.m128_f32[0] != 0.0f) wt.m128_f32[0] = 1.0f / wt.m128_f32[0]; wt = _mm_shuffle_ps(wt, wt, 0); - *(__m128*)& z->row0 = _mm_mul_ps(zt0, wt); - *(__m128*)& z->row1 = _mm_mul_ps(zt1, wt); - *(__m128*)& z->row2 = _mm_mul_ps(zt2, wt); - *(__m128*)& z->row3 = _mm_mul_ps(zt3, wt); + z->row0.data = _mm_mul_ps(zt0, wt); + z->row1.data = _mm_mul_ps(zt1, wt); + z->row2.data = _mm_mul_ps(zt2, wt); + z->row3.data = _mm_mul_ps(zt3, wt); } -void FASTCALL mat4_invtrans(mat4* x, mat4* z) { +inline void FASTCALL mat4_invtrans(mat4* x, mat4* z) { mat4 t = *x; mat4_inverse(&t, &t); mat4_transpose(&t, &t); *z = t; } -void FASTCALL mat4_normalize(mat4* x, mat4* z) { +inline void FASTCALL mat4_invrot(mat4* x, mat4* z) { + mat3 yt; + mat3_from_mat4(x, &yt); + mat3_inverse(&yt, &yt); + mat4_from_mat3(&yt, z); + z->row0.w = x->row0.w; + z->row1.w = x->row1.w; + z->row2.w = x->row2.w; + z->row3 = x->row3; +} + +inline void FASTCALL mat4_normalize(mat4* x, mat4* z) { __m128 det; det = _mm_set_ss(mat4_determinant(x)); if (det.m128_f32[0] != 0.0f) det.m128_f32[0] = 1.0f / det.m128_f32[0]; det = _mm_shuffle_ps(det, det, 0); - *(__m128*)& z->row0 = _mm_mul_ps(*(__m128*) & x->row0, det); - *(__m128*)& z->row1 = _mm_mul_ps(*(__m128*) & x->row1, det); - *(__m128*)& z->row2 = _mm_mul_ps(*(__m128*) & x->row2, det); - *(__m128*)& z->row3 = _mm_mul_ps(*(__m128*) & x->row3, det); + z->row0.data = _mm_mul_ps(x->row0.data, det); + z->row1.data = _mm_mul_ps(x->row1.data, det); + z->row2.data = _mm_mul_ps(x->row2.data, det); + z->row3.data = _mm_mul_ps(x->row3.data, det); } void FASTCALL mat4_normalize_rotation(mat4* x, mat4* z) { __m128 xt; __m128 yt; *(vec3*)&xt = *(vec3*)&x->row0; + xt.m128_f32[3] = 0.0f; yt = _mm_mul_ps(xt, xt); - yt.m128_f32[3] = 0.0f; yt = _mm_hadd_ps(yt, yt); yt = _mm_sqrt_ss(_mm_hadd_ps(yt, yt)); if (yt.m128_f32[0] != 0.0f) @@ -699,8 +769,8 @@ void FASTCALL mat4_normalize_rotation(mat4* x, mat4* z) { xt = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0)); *(vec3*)&z->row0 = *(vec3*)&xt; *(vec3*)&xt = *(vec3*)&x->row1; + xt.m128_f32[3] = 0.0f; yt = _mm_mul_ps(xt, xt); - yt.m128_f32[3] = 0.0f; yt = _mm_hadd_ps(yt, yt); yt = _mm_sqrt_ss(_mm_hadd_ps(yt, yt)); if (yt.m128_f32[0] != 0.0f) @@ -708,8 +778,8 @@ void FASTCALL mat4_normalize_rotation(mat4* x, mat4* z) { xt = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0)); *(vec3*)&z->row1 = *(vec3*)&xt; *(vec3*)&xt = *(vec3*)&x->row2; + xt.m128_f32[3] = 0.0f; yt = _mm_mul_ps(xt, xt); - yt.m128_f32[3] = 0.0f; yt = _mm_hadd_ps(yt, yt); yt = _mm_sqrt_ss(_mm_hadd_ps(yt, yt)); if (yt.m128_f32[0] != 0.0f) @@ -722,7 +792,7 @@ void FASTCALL mat4_normalize_rotation(mat4* x, mat4* z) { z->row3 = x->row3; } -float_t FASTCALL mat4_determinant(mat4* x) { +inline float_t FASTCALL mat4_determinant(mat4* x) { vec4 xt0; vec4 xt1; vec4 xt2; @@ -746,7 +816,7 @@ float_t FASTCALL mat4_determinant(mat4* x) { return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; } -void FASTCALL mat4_rotate(float_t x, float_t y, float_t z, mat4* d) { +inline void FASTCALL mat4_rotate(float_t x, float_t y, float_t z, mat4* d) { mat4 dt; dt = mat4_identity; if (z != 0.0f) @@ -758,7 +828,7 @@ void FASTCALL mat4_rotate(float_t x, float_t y, float_t z, mat4* d) { *d = dt; } -void FASTCALL mat4_rotate_x(float_t x, mat4* y) { +inline void FASTCALL mat4_rotate_x(float_t x, mat4* y) { mat4 yt; float_t x_sin = sinf(x); float_t x_cos = cosf(x); @@ -770,7 +840,7 @@ void FASTCALL mat4_rotate_x(float_t x, mat4* y) { *y = yt; } -void FASTCALL mat4_rotate_y(float_t x, mat4* y) { +inline void FASTCALL mat4_rotate_y(float_t x, mat4* y) { mat4 yt; float_t x_sin = sinf(x); float_t x_cos = cosf(x); @@ -782,7 +852,7 @@ void FASTCALL mat4_rotate_y(float_t x, mat4* y) { *y = yt; } -void FASTCALL mat4_rotate_z(float_t x, mat4* y) { +inline void FASTCALL mat4_rotate_z(float_t x, mat4* y) { mat4 yt; float_t x_sin = sinf(x); float_t x_cos = cosf(x); @@ -794,7 +864,7 @@ void FASTCALL mat4_rotate_z(float_t x, mat4* y) { *y = yt; } -void FASTCALL mat4_rotate_mult(mat4* s, float_t x, float_t y, float_t z, mat4* d) { +inline void FASTCALL mat4_rotate_mult(mat4* s, float_t x, float_t y, float_t z, mat4* d) { mat4 dt; dt = *s; if (z != 0.0f) @@ -806,7 +876,7 @@ void FASTCALL mat4_rotate_mult(mat4* s, float_t x, float_t y, float_t z, mat4* d *d = dt; } -void FASTCALL mat4_rotate_x_mult(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_rotate_x_mult(mat4* x, float_t y, mat4* z) { mat4 yt; float_t y_sin = sinf(y); float_t y_cos = cosf(y); @@ -818,7 +888,7 @@ void FASTCALL mat4_rotate_x_mult(mat4* x, float_t y, mat4* z) { mat4_mult(x, &yt, z); } -void FASTCALL mat4_rotate_y_mult(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_rotate_y_mult(mat4* x, float_t y, mat4* z) { mat4 yt; float_t y_sin = sinf(y); float_t y_cos = cosf(y); @@ -830,7 +900,7 @@ void FASTCALL mat4_rotate_y_mult(mat4* x, float_t y, mat4* z) { mat4_mult(x, &yt, z); } -void FASTCALL mat4_rotate_z_mult(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_rotate_z_mult(mat4* x, float_t y, mat4* z) { mat4 yt; float_t y_sin = sinf(y); float_t y_cos = cosf(y); @@ -842,7 +912,7 @@ void FASTCALL mat4_rotate_z_mult(mat4* x, float_t y, mat4* z) { mat4_mult(x, &yt, z); } -void FASTCALL mat4_rot(mat4* s, float_t x, float_t y, float_t z, mat4* d) { +inline void FASTCALL mat4_rot(mat4* s, float_t x, float_t y, float_t z, mat4* d) { mat4 dt; dt = *s; if (z != 0.0f) @@ -854,7 +924,7 @@ void FASTCALL mat4_rot(mat4* s, float_t x, float_t y, float_t z, mat4* d) { *d = dt; } -void FASTCALL mat4_rot_x(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_rot_x(mat4* x, float_t y, mat4* z) { mat3 xt; mat3 yt; mat3 zt; @@ -878,7 +948,7 @@ void FASTCALL mat4_rot_x(mat4* x, float_t y, mat4* z) { z->row3 = x->row3; } -void FASTCALL mat4_rot_y(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_rot_y(mat4* x, float_t y, mat4* z) { mat3 xt; mat3 yt; mat3 zt; @@ -902,7 +972,7 @@ void FASTCALL mat4_rot_y(mat4* x, float_t y, mat4* z) { z->row3 = x->row3; } -void FASTCALL mat4_rot_z(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_rot_z(mat4* x, float_t y, mat4* z) { mat3 xt; mat3 yt; mat3 zt; @@ -926,7 +996,7 @@ void FASTCALL mat4_rot_z(mat4* x, float_t y, mat4* z) { z->row3 = x->row3; } -void FASTCALL mat4_scale(float_t x, float_t y, float_t z, mat4* d) { +inline void FASTCALL mat4_scale(float_t x, float_t y, float_t z, mat4* d) { mat4 dt; dt = mat4_identity; if (x != 1.0f) @@ -938,28 +1008,28 @@ void FASTCALL mat4_scale(float_t x, float_t y, float_t z, mat4* d) { *d = dt; } -void FASTCALL mat4_scale_x(float_t x, mat4* y) { +inline void FASTCALL mat4_scale_x(float_t x, mat4* y) { mat4 yt; yt = mat4_identity; yt.row0.x = x; *y = yt; } -void FASTCALL mat4_scale_y(float_t x, mat4* y) { +inline void FASTCALL mat4_scale_y(float_t x, mat4* y) { mat4 yt; yt = mat4_identity; yt.row1.y = x; *y = yt; } -void FASTCALL mat4_scale_z(float_t x, mat4* y) { +inline void FASTCALL mat4_scale_z(float_t x, mat4* y) { mat4 yt; yt = mat4_identity; yt.row2.z = x; *y = yt; } -void FASTCALL mat4_scale_mult(mat4* s, float_t x, float_t y, float_t z, mat4* d) { +inline void FASTCALL mat4_scale_mult(mat4* s, float_t x, float_t y, float_t z, mat4* d) { mat4 dt; if (x != 1.0f || y != 1.0f || z != 1.0f) { dt = mat4_identity; @@ -972,28 +1042,28 @@ void FASTCALL mat4_scale_mult(mat4* s, float_t x, float_t y, float_t z, mat4* d) *d = *s; } -void FASTCALL mat4_scale_x_mult(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_scale_x_mult(mat4* x, float_t y, mat4* z) { mat4 yt; yt = mat4_identity; yt.row0.x = y; mat4_mult(x, &yt, z); } -void FASTCALL mat4_scale_y_mult(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_scale_y_mult(mat4* x, float_t y, mat4* z) { mat4 yt; yt = mat4_identity; yt.row1.y = y; mat4_mult(x, &yt, z); } -void FASTCALL mat4_scale_z_mult(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_scale_z_mult(mat4* x, float_t y, mat4* z) { mat4 yt; yt = mat4_identity; yt.row2.z = y; mat4_mult(x, &yt, z); } -void FASTCALL mat4_scale_rot(mat4* s, float_t x, float_t y, float_t z, mat4* d) { +inline void FASTCALL mat4_scale_rot(mat4* s, float_t x, float_t y, float_t z, mat4* d) { mat3 st; mat3 dt; if (x != 1.0f || y != 1.0f || z != 1.0f) { @@ -1017,7 +1087,7 @@ void FASTCALL mat4_scale_rot(mat4* s, float_t x, float_t y, float_t z, mat4* d) *d = *s; } -void FASTCALL mat4_scale_x_rot(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_scale_x_rot(mat4* x, float_t y, mat4* z) { mat3 xt; mat3 yt; mat3 zt; @@ -1036,7 +1106,7 @@ void FASTCALL mat4_scale_x_rot(mat4* x, float_t y, mat4* z) { z->row3 = x->row3; } -void FASTCALL mat4_scale_y_rot(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_scale_y_rot(mat4* x, float_t y, mat4* z) { mat3 xt; mat3 yt; mat3 zt; @@ -1055,7 +1125,7 @@ void FASTCALL mat4_scale_y_rot(mat4* x, float_t y, mat4* z) { z->row3 = x->row3; } -void FASTCALL mat4_scale_z_rot(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_scale_z_rot(mat4* x, float_t y, mat4* z) { mat3 xt; mat3 yt; mat3 zt; @@ -1074,7 +1144,7 @@ void FASTCALL mat4_scale_z_rot(mat4* x, float_t y, mat4* z) { z->row3 = x->row3; } -void FASTCALL mat4_translate(float_t x, float_t y, float_t z, mat4* d) { +inline void FASTCALL mat4_translate(float_t x, float_t y, float_t z, mat4* d) { mat4 dt; dt = mat4_identity; dt.row3.x = x; @@ -1083,28 +1153,28 @@ void FASTCALL mat4_translate(float_t x, float_t y, float_t z, mat4* d) { *d = dt; } -void FASTCALL mat4_translate_x(float_t x, mat4* y) { +inline void FASTCALL mat4_translate_x(float_t x, mat4* y) { mat4 yt; yt = mat4_identity; yt.row3.x = x; *y = yt; } -void FASTCALL mat4_translate_y(float_t x, mat4* y) { +inline void FASTCALL mat4_translate_y(float_t x, mat4* y) { mat4 yt; yt = mat4_identity; yt.row3.y = x; *y = yt; } -void FASTCALL mat4_translate_z(float_t x, mat4* y) { +inline void FASTCALL mat4_translate_z(float_t x, mat4* y) { mat4 yt; yt = mat4_identity; yt.row3.z = x; *y = yt; } -void FASTCALL mat4_translate_mult(mat4* s, float_t x, float_t y, float_t z, mat4* d) { +inline void FASTCALL mat4_translate_mult(mat4* s, float_t x, float_t y, float_t z, mat4* d) { __m128 yt0; __m128 yt1; __m128 yt2; @@ -1130,7 +1200,7 @@ void FASTCALL mat4_translate_mult(mat4* s, float_t x, float_t y, float_t z, mat4 *d = *s; } -void FASTCALL mat4_translate_x_mult(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_translate_x_mult(mat4* x, float_t y, mat4* z) { __m128 yt0; __m128 yt1; __m128 yt2; @@ -1147,7 +1217,7 @@ void FASTCALL mat4_translate_x_mult(mat4* x, float_t y, mat4* z) { *z = *x; } -void FASTCALL mat4_translate_y_mult(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_translate_y_mult(mat4* x, float_t y, mat4* z) { __m128 yt0; __m128 yt1; __m128 yt2; @@ -1164,7 +1234,7 @@ void FASTCALL mat4_translate_y_mult(mat4* x, float_t y, mat4* z) { *z = *x; } -void FASTCALL mat4_translate_z_mult(mat4* x, float_t y, mat4* z) { +inline void FASTCALL mat4_translate_z_mult(mat4* x, float_t y, mat4* z) { __m128 yt0; __m128 yt1; __m128 yt2; @@ -1181,7 +1251,47 @@ void FASTCALL mat4_translate_z_mult(mat4* x, float_t y, mat4* z) { *z = *x; } -void FASTCALL mat4_from_quat(quat* quat, mat4* mat) { +inline void FASTCALL mat4_translate_add(mat4* s, float_t x, float_t y, float_t z, mat4* d) { + if (x != 0.0f || y != 0.0f || z != 0.0f) { + if (s != d) + *d = *s; + d->row3.data = _mm_add_ps(s->row3.data, _mm_set_ps(x, y, z, 0.0f)); + } + else if (s != d) + *d = *s; +} + +inline void FASTCALL mat4_translate_x_add(mat4* x, float_t y, mat4* z) { + if (y != 0.0f) { + if (x != z) + *z = *x; + z->row3.x += y; + } + else if (x != z) + *z = *x; +} + +inline void FASTCALL mat4_translate_y_add(mat4* x, float_t y, mat4* z) { + if (y != 0.0f) { + if (x != z) + *z = *x; + z->row3.y += y; + } + else if (x != z) + *z = *x; +} + +inline void FASTCALL mat4_translate_z_add(mat4* x, float_t y, mat4* z) { + if (y != 0.0f) { + if (x != z) + *z = *x; + z->row3.z += y; + } + else if (x != z) + *z = *x; +} + +inline void FASTCALL mat4_from_quat(quat* quat, mat4* mat) { float_t y; float_t x; float_t z; @@ -1224,8 +1334,63 @@ void FASTCALL mat4_from_quat(quat* quat, mat4* mat) { mat->row2.y = yz - wx; mat->row2.z = 1.0f - yy - xx; mat->row2.w = 0.0f; - mat->row3.x = 0.0f; - mat->row3.y = 0.0f; - mat->row3.z = 0.0f; - mat->row3.w = 1.0f; + mat->row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; +} + +inline void FASTCALL mat4_from_mat3(mat3* x, mat4* z) { + *(vec3*)&z->row0 = x->row0; + z->row0.w = 0.0f; + *(vec3*)&z->row1 = x->row1; + z->row1.w = 0.0f; + *(vec3*)&z->row2 = x->row2; + z->row2.w = 0.0f; + z->row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; +} + +inline void FASTCALL mat4_from_mat3_inverse(mat3* x, mat4* z) { + mat3 yt; + + mat3_inverse(x, &yt); + *(vec3*)&z->row0 = yt.row0; + z->row0.w = 0.0f; + *(vec3*)&z->row1 = yt.row1; + z->row1.w = 0.0f; + *(vec3*)&z->row2 = yt.row2; + z->row2.w = 0.0f; + z->row3 = (vec4){ 0.0f, 0.0f, 0.0f, 1.0f }; +} + +inline void FASTCALL mat4_clear_rot(mat4* x, mat4* z) { + mat4 yt; + + yt = *x; + *z = mat4_identity; + z->row0.w = yt.row0.w; + z->row1.w = yt.row1.w; + z->row2.w = yt.row2.w; + z->row3 = yt.row3; +} + +inline void FASTCALL mat4_clear_trans(mat4* x, mat4* z) { + mat4 yt; + + yt = *x; + *z = mat4_identity; + *(vec3*)&z->row0 = *(vec3*)&yt.row0; + *(vec3*)&z->row1 = *(vec3*)&yt.row1; + *(vec3*)&z->row2 = *(vec3*)&yt.row2; +} + +inline void FASTCALL mat4_get_scale(mat4* x, vec3* z) { + vec4_length(x->row0, z->x); + vec4_length(x->row1, z->y); + vec4_length(x->row2, z->z); +} + +inline void FASTCALL mat4_get_translation(mat4* x, vec3* z) { + *z = *(vec3*)&x->row3; +} + +inline void FASTCALL mat4_set_translation(mat4* x, vec3* z) { + *(vec3*)&x->row3 = *z; } diff --git a/src/KKdLib/mat.h b/src/KKdLib/mat.h index 847c404a..dc844d49 100644 --- a/src/KKdLib/mat.h +++ b/src/KKdLib/mat.h @@ -55,16 +55,21 @@ extern void FASTCALL mat3_scale_x_mult(mat3* x, float_t y, mat3* z); extern void FASTCALL mat3_scale_y_mult(mat3* x, float_t y, mat3* z); extern void FASTCALL mat3_scale_z_mult(mat3* x, float_t y, mat3* z); extern void FASTCALL mat3_from_quat(quat* quat, mat3* mat); +extern void FASTCALL mat3_from_mat4(mat4* x, mat3* z); +extern void FASTCALL mat3_from_mat4_inverse(mat4* x, mat3* z); +extern void FASTCALL mat3_get_scale(mat3* x, vec3* z); extern void FASTCALL mat4_add(mat4* x, mat4* y, mat4* z); extern void FASTCALL mat4_sub(mat4* x, mat4* y, mat4* z); extern void FASTCALL mat4_mult(mat4* x, mat4* y, mat4* z); extern void FASTCALL mat4_mult_vec3(mat4* x, vec3* y, vec3* z); +extern void FASTCALL mat4_mult_vec3_trans(mat4* x, vec3* y, vec3* z); extern void FASTCALL mat4_mult_vec(mat4* x, vec4* y, vec4* z); extern void FASTCALL mat4_mult_scalar(mat4* x, float_t y, mat4* z); extern void FASTCALL mat4_transpose(mat4* x, mat4* z); extern void FASTCALL mat4_inverse(mat4* x, mat4* z); extern void FASTCALL mat4_invtrans(mat4* x, mat4* z); +extern void FASTCALL mat4_invrot(mat4* x, mat4* z); extern void FASTCALL mat4_normalize(mat4* x, mat4* z); extern void FASTCALL mat4_normalize_rotation(mat4* x, mat4* z); extern float_t FASTCALL mat4_determinant(mat4* x); @@ -100,4 +105,15 @@ extern void FASTCALL mat4_translate_mult(mat4* s, float_t x, float_t y, float_t extern void FASTCALL mat4_translate_x_mult(mat4* x, float_t y, mat4* z); extern void FASTCALL mat4_translate_y_mult(mat4* x, float_t y, mat4* z); extern void FASTCALL mat4_translate_z_mult(mat4* x, float_t y, mat4* z); +extern void FASTCALL mat4_translate_add(mat4* s, float_t x, float_t y, float_t z, mat4* d); +extern void FASTCALL mat4_translate_x_add(mat4* x, float_t y, mat4* z); +extern void FASTCALL mat4_translate_y_add(mat4* x, float_t y, mat4* z); +extern void FASTCALL mat4_translate_z_add(mat4* x, float_t y, mat4* z); extern void FASTCALL mat4_from_quat(quat* quat, mat4* mat); +extern void FASTCALL mat4_from_mat3(mat3* x, mat4* z); +extern void FASTCALL mat4_from_mat3_inverse(mat3* x, mat4* z); +extern void FASTCALL mat4_clear_rot(mat4* x, mat4* z); +extern void FASTCALL mat4_clear_trans(mat4* x, mat4* z); +extern void FASTCALL mat4_get_scale(mat4* x, vec3* z); +extern void FASTCALL mat4_get_translation(mat4* x, vec3* z); +extern void FASTCALL mat4_set_translation(mat4* x, vec3* z); diff --git a/src/KKdLib/math.c b/src/KKdLib/math.c deleted file mode 100644 index ccb8216c..00000000 --- a/src/KKdLib/math.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#define _USE_MATH_DEFINES -#include "math.h" -#include - -FORCE_INLINE float_t ctgf(float_t x) { - return 1.0f / tanf(x); -} - -FORCE_INLINE float_t ctghf(float_t x) { - return 1.0f / tanhf(x); -} - -FORCE_INLINE float_t actgf(float_t x) { - return 1.0f / atanf(x); -} - -FORCE_INLINE float_t actghf(float_t x) { - return 1.0f / atanhf(x); -} - -FORCE_INLINE double_t ctg(double_t x) { - return 1.0 / tan(x); -} - -FORCE_INLINE double_t ctgh(double_t x) { - return 1.0 / tanh(x); -} - -FORCE_INLINE double_t actg(double_t x) { - return 1.0 / atan(x); -} - -FORCE_INLINE double_t actgh(double_t x) { - return 1.0 / atanh(x); -} - -FORCE_INLINE float_t lerpf(float_t x, float_t y, float_t blend) { - return x * (1.0f - blend) + y * blend; -} - -FORCE_INLINE double_t lerp(double_t x, double_t y, double_t blend) { - return x * (1.0 - blend) + y * blend; -} diff --git a/src/KKdLib/math.h b/src/KKdLib/math.h deleted file mode 100644 index 3e76f32a..00000000 --- a/src/KKdLib/math.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#pragma once - -#include "types.h" - -extern float_t ctgf(float_t x); -extern float_t ctghf(float_t x); -extern float_t actgf(float_t x); -extern float_t actghf(float_t x); -extern double_t ctg(double_t x); -extern double_t ctgh(double_t x); -extern double_t actg(double_t x); -extern double_t actgh(double_t x); -extern float_t lerpf(float_t x, float_t y, float_t blend); -extern double_t lerp(double_t x, double_t y, double_t blend); diff --git a/src/KKdLib/mot.c b/src/KKdLib/mot.c new file mode 100644 index 00000000..7e33fda0 --- /dev/null +++ b/src/KKdLib/mot.c @@ -0,0 +1,170 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "mot.h" +#include "f2_struct.h" +#include "io_stream.h" +#include "msgpack.h" +#include "io_json.h" +#include "io_msgpack.h" +#include "str_utils.h" + +mot* mot_init() { + mot* m = force_malloc(sizeof(mot)); + return m; +} + +void mot_read_mot(mot* m, char* path) { + if (!m || !path) + return; + + wchar_t* path_buf = char_string_to_wchar_t_string(path); + mot_wread_mot(m, path_buf); + free(path_buf); +} + +void mot_wread_mot(mot* m, wchar_t* path) { + if (!m || !path) + return; + + memset(m, 0, sizeof(mot)); + wchar_t* path_mot = str_utils_wadd(path, L".mot"); + stream* s = io_wopen(path_mot, L"rb"); + if (s->io.stream) { + size_t count = io_read_uint64_t(s); + /*size_t data_length =*/ io_read_uint64_t(s); + /*size_t data_offset =*/ io_read_uint64_t(s); + m->length = count; + m->data = force_malloc_s(mot_struct, count); + io_read(s, m->data, sizeof(mot_struct) * count); + m->ready = true; + } + io_dispose(s); + free(path_mot); +} + +void mot_write_mot(mot* m, char* path) { + if (!m || !path || !m->ready) + return; + + wchar_t* path_buf = char_string_to_wchar_t_string(path); + mot_wwrite_mot(m, path_buf); + free(path_buf); +} + +void mot_wwrite_mot(mot* m, wchar_t* path) { + if (!m || !path || !m->ready) + return; + + wchar_t* path_mot = str_utils_wadd(path, L".mot"); + stream* s = io_wopen(path_mot, L"wb"); + if (s->io.stream) { + size_t count = m->length; + io_write_uint64_t(s, count); + io_write_uint64_t(s, count * 0x20); + io_write_uint64_t(s, 0x18); + io_write(s, m->data, sizeof(mot_struct) * count); + } + io_dispose(s); + free(path_mot); +} + +void mot_read_mp(mot* m, char* path, bool json) { + if (!m || !path) + return; + + wchar_t* path_buf = char_string_to_wchar_t_string(path); + mot_wread_mp(m, path_buf, json); + free(path_buf); +} + +void mot_wread_mp(mot* m, wchar_t* path, bool json) { + if (!m || !path) + return; + + memset(m, 0, sizeof(mot)); + wchar_t* path_mp = str_utils_wadd(path, json ? L".json" : L".mp"); + stream* s = io_wopen(path_mp, L"rb"); + msgpack* msg; + if (json) + msg = io_json_read(s); + else + msg = io_msgpack_read(s); + + msgpack* mot = msgpack_read(msg, L"AddParam"); + if (mot && mot->type == MSGPACK_ARRAY) { + msgpack_array* ptr = SELECT_MSGPACK(msgpack_array, mot); + m->length = ptr->length; + m->data = force_malloc_s(mot_struct, m->length); + for (size_t i = 0; i < m->length; i++) { + if (ptr->data[i].type != MSGPACK_MAP) + continue; + + msgpack* _m = &ptr->data[i]; + mot_struct* mots = &m->data[i]; + mots->time = msgpack_read_float_t(_m, L"Time"); + mots->flags = msgpack_read_int32_t(_m, L"Flags"); + mots->frame = msgpack_read_int32_t(_m, L"Frame"); + mots->pv_branch = msgpack_read_int32_t(_m, L"PVBranch"); + mots->id = msgpack_read_int32_t(_m, L"ID"); + mots->value = msgpack_read_int32_t(_m, L"Value"); + } + m->ready = true; + } + msgpack_dispose(msg); + io_dispose(s); + free(path_mp); +} + +void mot_write_mp(mot* m, char* path, bool json) { + if (!m || !path || !m->ready) + return; + + wchar_t* path_buf = char_string_to_wchar_t_string(path); + mot_wwrite_mp(m, path_buf, json); + free(path_buf); +} + +void mot_wwrite_mp(mot* m, wchar_t* path, bool json) { + if (!m || !path || !m->ready) + return; + + wchar_t* path_mp = str_utils_wadd(path, json ? L".json" : L".mp"); + stream* s = io_wopen(path_mp, L"wb"); + if (s->io.stream) { + msgpack* msg = msgpack_init_map(0); + msgpack* mot = msgpack_init_array(L"AddParam", m->length); + msgpack_array* ptr = SELECT_MSGPACK(msgpack_array, mot); + for (size_t i = 0; i < m->length; i++) { + msgpack* _m = &ptr->data[i]; + mot_struct* mots = &m->data[i]; + msgpack_set_map_empty(_m, 0); + msgpack_append_float_t(_m, L"Time", mots->time); + msgpack_append_int32_t(_m, L"Flags", mots->flags); + msgpack_append_int32_t(_m, L"Frame", mots->frame); + if (mots->pv_branch) + msgpack_append_int32_t(_m, L"PVBranch", mots->pv_branch); + msgpack_append_int32_t(_m, L"ID", mots->id); + msgpack_append_int32_t(_m, L"Value", mots->value); + } + msgpack_append(msg, mot); + msgpack_dispose(mot); + if (json) + io_json_write(s, msg); + else + io_msgpack_write(s, msg); + msgpack_dispose(msg); + } + io_dispose(s); + free(path_mp); +} + +void mot_dispose(mot* m) { + if (!m) + return; + + free(m->data); + free(m); +} diff --git a/src/KKdLib/mot.h b/src/KKdLib/mot.h new file mode 100644 index 00000000..9c83e511 --- /dev/null +++ b/src/KKdLib/mot.h @@ -0,0 +1,36 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "default.h" + +typedef struct mot_struct { + float_t time; + int32_t flags; + int32_t frame; + int32_t padding_0C; + int32_t pv_branch; + int32_t id; + int32_t value; + int32_t padding_1C; +} mot_struct; + +typedef struct mot { + bool ready; + size_t length; + mot_struct* data; +} mot; + +extern mot* mot_init(); +extern void mot_read_mot(mot* m, char* path); +extern void mot_wread_mot(mot* m, wchar_t* path); +extern void mot_write_mot(mot* m, char* path); +extern void mot_wwrite_mot(mot* m, wchar_t* path); +extern void mot_read_mp(mot* m, char* path, bool json); +extern void mot_wread_mp(mot* m, wchar_t* path, bool json); +extern void mot_write_mp(mot* m, char* path, bool json); +extern void mot_wwrite_mp(mot* m, wchar_t* path, bool json); +extern void mot_dispose(mot* m); diff --git a/src/KKdLib/pdi.c b/src/KKdLib/moti.c similarity index 65% rename from src/KKdLib/pdi.c rename to src/KKdLib/moti.c index 0b36e6cf..12a880b1 100644 --- a/src/KKdLib/pdi.c +++ b/src/KKdLib/moti.c @@ -3,13 +3,14 @@ GitHub/GitLab: korenkonder */ -#include "pdi.h" +#include "moti.h" +#include "interpolation.h" -pdi* kft2_array_to_pdi(kft2* array, size_t length, float_t interpolation_framerate, float_t requested_framerate) { +moti* kft2_array_to_moti(kft2* array, size_t length, float_t interpolation_framerate, float_t requested_framerate) { if (!array || !length) return 0; - pdi* interp = force_malloc(sizeof(pdi)); + moti* interp = force_malloc(sizeof(moti)); interp->time = 0.0f; interp->array = array; interp->length = length; @@ -19,7 +20,7 @@ pdi* kft2_array_to_pdi(kft2* array, size_t length, float_t interpolation_framera interp->requested_framerate = requested_framerate; interp->value = 0.0f; interp->first_key = interp->last_key = 0; - pdi_reset(interp); + moti_reset(interp); if (array && length) { interp->first_key = array; @@ -28,26 +29,26 @@ pdi* kft2_array_to_pdi(kft2* array, size_t length, float_t interpolation_framera return interp; } -FORCE_INLINE void pdi_set_interpolation_framerate(pdi* interp, float_t interpolation_framerate) { +inline void moti_set_interpolation_framerate(moti* interp, float_t interpolation_framerate) { interp->interpolation_framerate = interpolation_framerate; interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; } -FORCE_INLINE void pdi_set_requested_framerate(pdi* interp, float_t requested_framerate) { +inline void moti_set_requested_framerate(moti* interp, float_t requested_framerate) { interp->requested_framerate = requested_framerate; interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; } -FORCE_INLINE void pdi_update(pdi* interp) { +inline void moti_update(moti* interp) { interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; } -FORCE_INLINE void pdi_reset(pdi* interp) { +inline void moti_reset(moti* interp) { interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; interp->frame = -interp->delta_frame; interp->time = interp->frame / interp->requested_framerate; } -static void pdi_interpolate(pdi* interp) { +static void moti_interpolate(moti* interp) { float_t frame = interp->frame; kft2* keys = interp->array; @@ -68,58 +69,51 @@ static void pdi_interpolate(pdi* interp) { if (frame <= c.frame || frame >= n.frame) interp->value = frame > c.frame ? n.value : c.value; - else if (n.tangent == c.tangent && n.tangent == 0.0f) { - float_t t = (frame - c.frame) / (n.frame - c.frame); - interp->value = (1.0f - t) * c.value + t * n.value; - } - else { - float_t t = (frame - c.frame) / (n.frame - c.frame); - float_t t_1 = t - 1.0f; - interp->value = (t_1 * 2.0f - 1.0f) * (c.value - n.value) * t * t + - (t_1 * c.tangent + t * n.tangent) * t_1 * (frame - c.frame) + c.value; - } + else + interp->value = interpolate_chs_value(c.value, n.value, + c.tangent, n.tangent, c.frame, n.frame, frame); } -float_t pdi_set_time(pdi* interp, float_t time) { +float_t moti_set_time(moti* interp, float_t time) { if (!interp || !interp->array || !interp->length) return 0.0f; interp->frame = time * interp->interpolation_framerate; interp->time = time; - pdi_interpolate(interp); + moti_interpolate(interp); return interp->value; } -float_t pdi_set_frame(pdi* interp, float_t frame) { +float_t moti_set_frame(moti* interp, float_t frame) { if (!interp || !interp->array || !interp->length) return 0.0f; interp->frame = frame * interp->delta_frame; interp->time = frame / interp->requested_framerate; - pdi_interpolate(interp); + moti_interpolate(interp); return interp->value; } -float_t pdi_add_time(pdi* interp, float_t time) { +float_t moti_add_time(moti* interp, float_t time) { if (!interp || !interp->array || !interp->length) return 0.0f; interp->frame = time * interp->interpolation_framerate; interp->time += time; - pdi_interpolate(interp); + moti_interpolate(interp); return interp->value; } -float_t pdi_next_frame(pdi* interp) { +float_t moti_next_frame(moti* interp) { if (!interp || !interp->array || !interp->length) return 0.0f; interp->frame += interp->delta_frame; interp->time = interp->frame / interp->interpolation_framerate; - pdi_interpolate(interp); + moti_interpolate(interp); return interp->value; } \ No newline at end of file diff --git a/src/KKdLib/moti.h b/src/KKdLib/moti.h new file mode 100644 index 00000000..d90fe86e --- /dev/null +++ b/src/KKdLib/moti.h @@ -0,0 +1,36 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "default.h" +#include "kf.h" + +typedef struct moti { + kft2* array; + size_t length; + + float_t frame; + float_t time; + float_t value; + float_t delta_frame; + float_t interpolation_framerate; + float_t requested_framerate; + + kft2* first_key; + kft2* last_key; +} moti; + +extern moti* kft2_array_to_moti(kft2* array, size_t length, + float_t interpolation_framerate, float_t requested_framerate); +extern void moti_set_interpolation_framerate(moti* interp, float_t interpolation_framerate); +extern void moti_set_requested_framerate(moti* interp, float_t requested_framerate); +extern void moti_update(moti* interp); +extern void moti_reset(moti* interp); +extern float_t moti_set_time(moti* interp, float_t time); +extern float_t moti_set_frame(moti* interp, float_t frame); +extern float_t moti_add_time(moti* interp, float_t time); +extern float_t moti_next_frame(moti* interp); + diff --git a/src/KKdLib/msgpack.c b/src/KKdLib/msgpack.c index 652f80aa..a68c8004 100644 --- a/src/KKdLib/msgpack.c +++ b/src/KKdLib/msgpack.c @@ -6,40 +6,33 @@ #include "msgpack.h" #define ALLOCATE_MSGPACK(a, b) \ -{ \ - if (CHECK_MSGPACK(a)) \ - ((a*)##b.ptr) = force_malloc(sizeof(a)); \ -} -#define ALLOCATE_MSGPACK_PTR(a, b) \ -{ \ - if (CHECK_MSGPACK(a)) \ - ((a*)##b->ptr) = force_malloc(sizeof(a)); \ -} +if (CHECK_MSGPACK(a)) \ + ((a*)##b->ptr) = force_malloc(sizeof(a)); static void msgpack_dispose_inner(msgpack* msg); msgpack* msgpack_init_map(wchar_t* name) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_MAP; - ALLOCATE_MSGPACK_PTR(msgpack_map, msg); + ALLOCATE_MSGPACK(msgpack_map, msg); wchar_t_buffer_init(&msg->name, name); msgpack_map* ptr = SELECT_MSGPACK(msgpack_map, msg); ptr->length = 0; ptr->fulllength = 1; - ptr->data = force_malloc_s(sizeof(msgpack), 1); + ptr->data = force_malloc_s(msgpack, 1); return msg; } msgpack* msgpack_init_array(wchar_t* name, size_t length) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_ARRAY; - ALLOCATE_MSGPACK_PTR(msgpack_array, msg); + ALLOCATE_MSGPACK(msgpack_array, msg); wchar_t_buffer_init(&msg->name, name); msgpack_array* ptr = SELECT_MSGPACK(msgpack_array, msg); ptr->length = ptr->fulllength = length; - ptr->data = force_malloc_s(sizeof(msgpack), length); + ptr->data = force_malloc_s(msgpack, length); return msg; } @@ -53,7 +46,7 @@ msgpack* msgpack_init_null(wchar_t* name) { msgpack* msgpack_init_bool(wchar_t* name, bool val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_BOOL; - ALLOCATE_MSGPACK_PTR(bool, msg); + ALLOCATE_MSGPACK(bool, msg); wchar_t_buffer_init(&msg->name, name); bool* ptr = SELECT_MSGPACK(bool, msg); @@ -64,7 +57,7 @@ msgpack* msgpack_init_bool(wchar_t* name, bool val) { msgpack* msgpack_init_int8_t(wchar_t* name, int8_t val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_INT8; - ALLOCATE_MSGPACK_PTR(int8_t, msg); + ALLOCATE_MSGPACK(int8_t, msg); wchar_t_buffer_init(&msg->name, name); int8_t* ptr = SELECT_MSGPACK(int8_t, msg); @@ -75,7 +68,7 @@ msgpack* msgpack_init_int8_t(wchar_t* name, int8_t val) { msgpack* msgpack_init_uint8_t(wchar_t* name, uint8_t val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_UINT8; - ALLOCATE_MSGPACK_PTR(uint8_t, msg); + ALLOCATE_MSGPACK(uint8_t, msg); wchar_t_buffer_init(&msg->name, name); uint8_t* ptr = SELECT_MSGPACK(uint8_t, msg); @@ -86,7 +79,7 @@ msgpack* msgpack_init_uint8_t(wchar_t* name, uint8_t val) { msgpack* msgpack_init_int16_t(wchar_t* name, int16_t val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_INT16; - ALLOCATE_MSGPACK_PTR(int16_t, msg); + ALLOCATE_MSGPACK(int16_t, msg); wchar_t_buffer_init(&msg->name, name); int16_t* ptr = SELECT_MSGPACK(int16_t, msg); @@ -97,7 +90,7 @@ msgpack* msgpack_init_int16_t(wchar_t* name, int16_t val) { msgpack* msgpack_init_uint16_t(wchar_t* name, uint16_t val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_UINT16; - ALLOCATE_MSGPACK_PTR(uint16_t, msg); + ALLOCATE_MSGPACK(uint16_t, msg); wchar_t_buffer_init(&msg->name, name); uint16_t* ptr = SELECT_MSGPACK(uint16_t, msg); @@ -108,7 +101,7 @@ msgpack* msgpack_init_uint16_t(wchar_t* name, uint16_t val) { msgpack* msgpack_init_int32_t(wchar_t* name, int32_t val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_INT32; - ALLOCATE_MSGPACK_PTR(int32_t, msg); + ALLOCATE_MSGPACK(int32_t, msg); wchar_t_buffer_init(&msg->name, name); int32_t* ptr = SELECT_MSGPACK(int32_t, msg); @@ -119,7 +112,7 @@ msgpack* msgpack_init_int32_t(wchar_t* name, int32_t val) { msgpack* msgpack_init_uint32_t(wchar_t* name, uint32_t val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_UINT32; - ALLOCATE_MSGPACK_PTR(uint32_t, msg); + ALLOCATE_MSGPACK(uint32_t, msg); wchar_t_buffer_init(&msg->name, name); uint32_t* ptr = SELECT_MSGPACK(uint32_t, msg); @@ -130,7 +123,7 @@ msgpack* msgpack_init_uint32_t(wchar_t* name, uint32_t val) { msgpack* msgpack_init_int64_t(wchar_t* name, int64_t val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_INT64; - ALLOCATE_MSGPACK_PTR(int64_t, msg); + ALLOCATE_MSGPACK(int64_t, msg); wchar_t_buffer_init(&msg->name, name); int64_t* ptr = SELECT_MSGPACK(int64_t, msg); @@ -141,7 +134,7 @@ msgpack* msgpack_init_int64_t(wchar_t* name, int64_t val) { msgpack* msgpack_init_uint64_t(wchar_t* name, uint64_t val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_UINT64; - ALLOCATE_MSGPACK_PTR(uint64_t, msg); + ALLOCATE_MSGPACK(uint64_t, msg); wchar_t_buffer_init(&msg->name, name); uint64_t* ptr = SELECT_MSGPACK(uint64_t, msg); @@ -152,7 +145,7 @@ msgpack* msgpack_init_uint64_t(wchar_t* name, uint64_t val) { msgpack* msgpack_init_float_t(wchar_t* name, float_t val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_FLOAT; - ALLOCATE_MSGPACK_PTR(float_t, msg); + ALLOCATE_MSGPACK(float_t, msg); wchar_t_buffer_init(&msg->name, name); float_t* ptr = SELECT_MSGPACK(float_t, msg); @@ -163,7 +156,7 @@ msgpack* msgpack_init_float_t(wchar_t* name, float_t val) { msgpack* msgpack_init_double_t(wchar_t* name, double_t val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_DOUBLE; - ALLOCATE_MSGPACK_PTR(double_t, msg); + ALLOCATE_MSGPACK(double_t, msg); wchar_t_buffer_init(&msg->name, name); double_t* ptr = SELECT_MSGPACK(double_t, msg); @@ -174,66 +167,12 @@ msgpack* msgpack_init_double_t(wchar_t* name, double_t val) { msgpack* msgpack_init_string(wchar_t* name, wchar_t* val) { msgpack* msg = force_malloc(sizeof(msgpack)); msg->type = MSGPACK_STRING; - ALLOCATE_MSGPACK_PTR(wchar_t_buffer, msg); + ALLOCATE_MSGPACK(wchar_t_buffer, msg); wchar_t_buffer_init(&msg->name, name); wchar_t_buffer_init(SELECT_MSGPACK(wchar_t_buffer, msg), val); return msg; } -void msgpack_dispose(msgpack* msg) { - if (!msg) - return; - - switch (msg->type) { - case MSGPACK_STRING: - wchar_t_buffer_dispose(SELECT_MSGPACK(wchar_t_buffer, msg)); - break; - case MSGPACK_ARRAY: { - msgpack_array* ptr = SELECT_MSGPACK(msgpack_array, msg); - for (size_t i = 0; i < ptr->length; i++) - msgpack_dispose_inner(&ptr->data[i]); - free(ptr->data); - } break; - case MSGPACK_MAP: { - msgpack_map* ptr = SELECT_MSGPACK(msgpack_map, msg); - for (size_t i = 0; i < ptr->length; i++) - msgpack_dispose_inner(&ptr->data[i]); - free(ptr->data); - } break; - } - - if (msg->type != MSGPACK_ARRAY && msg->type != MSGPACK_MAP && msg->type == MSGPACK_NONE) - memset(msg, 0, sizeof(msgpack)); - else - free(msg); -} - -static void msgpack_dispose_inner(msgpack* msg) { - if (!msg) - return; - - wchar_t_buffer_dispose(&msg->name); - - switch (msg->type) { - case MSGPACK_STRING: - wchar_t_buffer_dispose(SELECT_MSGPACK(wchar_t_buffer, msg)); - break; - case MSGPACK_ARRAY: { - msgpack_array* ptr = SELECT_MSGPACK(msgpack_array, msg); - for (size_t i = 0; i < ptr->length; i++) - msgpack_dispose_inner(&ptr->data[i]); - free(ptr->data); - } break; - case MSGPACK_MAP: { - msgpack_map* ptr = SELECT_MSGPACK(msgpack_map, msg); - for (size_t i = 0; i < ptr->length; i++) - msgpack_dispose_inner(&ptr->data[i]); - free(ptr->data); - } break; - } - memset(msg, 0, sizeof(msgpack)); -} - bool msgpack_check_null(msgpack* msg) { if (msg->type == MSGPACK_ARRAY) return SELECT_MSGPACK(msgpack_array, msg)->data == 0; @@ -406,7 +345,7 @@ void msgpack_set_array(msgpack* msg, wchar_t* name, msgpack_array* val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_ARRAY; - ALLOCATE_MSGPACK_PTR(msgpack_array, msg); + ALLOCATE_MSGPACK(msgpack_array, msg); wchar_t_buffer_init(&msg->name, name); msgpack_array* ptr = SELECT_MSGPACK(msgpack_array, msg); @@ -419,7 +358,7 @@ void msgpack_set_map(msgpack* msg, wchar_t* name, msgpack_map* val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_MAP; - ALLOCATE_MSGPACK_PTR(msgpack_map, msg); + ALLOCATE_MSGPACK(msgpack_map, msg); wchar_t_buffer_init(&msg->name, name); msgpack_map* ptr = SELECT_MSGPACK(msgpack_map, msg); @@ -432,13 +371,13 @@ void msgpack_set_map_empty(msgpack* msg, wchar_t* name) { msgpack_dispose_inner(msg); msg->type = MSGPACK_MAP; - ALLOCATE_MSGPACK_PTR(msgpack_map, msg); + ALLOCATE_MSGPACK(msgpack_map, msg); wchar_t_buffer_init(&msg->name, name); msgpack_map* ptr = SELECT_MSGPACK(msgpack_map, msg); ptr->length = 0; ptr->fulllength = 1; - ptr->data = force_malloc_s(sizeof(msgpack), 1); + ptr->data = force_malloc_s(msgpack, 1); } void msgpack_set_bool(msgpack* msg, wchar_t* name, bool val) { @@ -447,7 +386,7 @@ void msgpack_set_bool(msgpack* msg, wchar_t* name, bool val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_BOOL; - ALLOCATE_MSGPACK_PTR(bool, msg); + ALLOCATE_MSGPACK(bool, msg); wchar_t_buffer_init(&msg->name, name); bool* ptr = SELECT_MSGPACK(bool, msg); @@ -460,7 +399,7 @@ void msgpack_set_int8_t(msgpack* msg, wchar_t* name, int8_t val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_INT8; - ALLOCATE_MSGPACK_PTR(int8_t, msg); + ALLOCATE_MSGPACK(int8_t, msg); wchar_t_buffer_init(&msg->name, name); int8_t* ptr = SELECT_MSGPACK(int8_t, msg); @@ -473,7 +412,7 @@ void msgpack_set_uint8_t(msgpack* msg, wchar_t* name, uint8_t val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_UINT8; - ALLOCATE_MSGPACK_PTR(uint8_t, msg); + ALLOCATE_MSGPACK(uint8_t, msg); wchar_t_buffer_init(&msg->name, name); uint8_t* ptr = SELECT_MSGPACK(uint8_t, msg); @@ -486,7 +425,7 @@ void msgpack_set_int16_t(msgpack* msg, wchar_t* name, int16_t val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_INT16; - ALLOCATE_MSGPACK_PTR(int16_t, msg); + ALLOCATE_MSGPACK(int16_t, msg); wchar_t_buffer_init(&msg->name, name); int16_t* ptr = SELECT_MSGPACK(int16_t, msg); @@ -499,7 +438,7 @@ void msgpack_set_uint16_t(msgpack* msg, wchar_t* name, uint16_t val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_UINT16; - ALLOCATE_MSGPACK_PTR(uint16_t, msg); + ALLOCATE_MSGPACK(uint16_t, msg); wchar_t_buffer_init(&msg->name, name); uint16_t* ptr = SELECT_MSGPACK(uint16_t, msg); @@ -512,7 +451,7 @@ void msgpack_set_int32_t(msgpack* msg, wchar_t* name, int32_t val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_INT32; - ALLOCATE_MSGPACK_PTR(int32_t, msg); + ALLOCATE_MSGPACK(int32_t, msg); wchar_t_buffer_init(&msg->name, name); int32_t* ptr = SELECT_MSGPACK(int32_t, msg); @@ -525,7 +464,7 @@ void msgpack_set_uint32_t(msgpack* msg, wchar_t* name, uint32_t val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_UINT32; - ALLOCATE_MSGPACK_PTR(uint32_t, msg); + ALLOCATE_MSGPACK(uint32_t, msg); wchar_t_buffer_init(&msg->name, name); uint32_t* ptr = SELECT_MSGPACK(uint32_t, msg); @@ -538,7 +477,7 @@ void msgpack_set_int64_t(msgpack* msg, wchar_t* name, int64_t val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_INT64; - ALLOCATE_MSGPACK_PTR(int64_t, msg); + ALLOCATE_MSGPACK(int64_t, msg); wchar_t_buffer_init(&msg->name, name); int64_t* ptr = SELECT_MSGPACK(int64_t, msg); @@ -551,7 +490,7 @@ void msgpack_set_uint64_t(msgpack* msg, wchar_t* name, uint64_t val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_UINT64; - ALLOCATE_MSGPACK_PTR(uint64_t, msg); + ALLOCATE_MSGPACK(uint64_t, msg); wchar_t_buffer_init(&msg->name, name); uint64_t* ptr = SELECT_MSGPACK(uint64_t, msg); @@ -564,7 +503,7 @@ void msgpack_set_float_t(msgpack* msg, wchar_t* name, float_t val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_FLOAT; - ALLOCATE_MSGPACK_PTR(float_t, msg); + ALLOCATE_MSGPACK(float_t, msg); wchar_t_buffer_init(&msg->name, name); float_t* ptr = SELECT_MSGPACK(float_t, msg); @@ -577,7 +516,7 @@ void msgpack_set_double_t(msgpack* msg, wchar_t* name, double_t val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_DOUBLE; - ALLOCATE_MSGPACK_PTR(double_t, msg); + ALLOCATE_MSGPACK(double_t, msg); wchar_t_buffer_init(&msg->name, name); double_t* ptr = SELECT_MSGPACK(double_t, msg); @@ -590,7 +529,7 @@ void msgpack_set_string(msgpack* msg, wchar_t* name, wchar_t* val) { msgpack_dispose_inner(msg); msg->type = MSGPACK_STRING; - ALLOCATE_MSGPACK_PTR(wchar_t_buffer, msg); + ALLOCATE_MSGPACK(wchar_t_buffer, msg); wchar_t_buffer_init(&msg->name, name); wchar_t_buffer_init(SELECT_MSGPACK(wchar_t_buffer, msg), val); } @@ -850,9 +789,63 @@ wchar_t* msgpack_read_string(msgpack* msg, wchar_t* name) { if (m && m->type == MSGPACK_STRING) { wchar_t_buffer* ptr = SELECT_MSGPACK(wchar_t_buffer, m); - wchar_t* val = force_malloc_s(sizeof(wchar_t), ptr->length + 1); + wchar_t* val = force_malloc_s(wchar_t, ptr->length + 1); memcpy(val, wchar_t_buffer_select(ptr), sizeof(wchar_t) * (ptr->length + 1)); return val; } return 0; } + +void msgpack_dispose(msgpack* msg) { + if (!msg) + return; + + switch (msg->type) { + case MSGPACK_STRING: + wchar_t_buffer_dispose(SELECT_MSGPACK(wchar_t_buffer, msg)); + break; + case MSGPACK_ARRAY: { + msgpack_array* ptr = SELECT_MSGPACK(msgpack_array, msg); + for (size_t i = 0; i < ptr->length; i++) + msgpack_dispose_inner(&ptr->data[i]); + free(ptr->data); + } break; + case MSGPACK_MAP: { + msgpack_map* ptr = SELECT_MSGPACK(msgpack_map, msg); + for (size_t i = 0; i < ptr->length; i++) + msgpack_dispose_inner(&ptr->data[i]); + free(ptr->data); + } break; + } + + if (msg->type != MSGPACK_ARRAY && msg->type != MSGPACK_MAP && msg->type == MSGPACK_NONE) + memset(msg, 0, sizeof(msgpack)); + else + free(msg); +} + +static void msgpack_dispose_inner(msgpack* msg) { + if (!msg) + return; + + wchar_t_buffer_dispose(&msg->name); + + switch (msg->type) { + case MSGPACK_STRING: + wchar_t_buffer_dispose(SELECT_MSGPACK(wchar_t_buffer, msg)); + break; + case MSGPACK_ARRAY: { + msgpack_array* ptr = SELECT_MSGPACK(msgpack_array, msg); + for (size_t i = 0; i < ptr->length; i++) + msgpack_dispose_inner(&ptr->data[i]); + free(ptr->data); + } break; + case MSGPACK_MAP: { + msgpack_map* ptr = SELECT_MSGPACK(msgpack_map, msg); + for (size_t i = 0; i < ptr->length; i++) + msgpack_dispose_inner(&ptr->data[i]); + free(ptr->data); + } break; + } + memset(msg, 0, sizeof(msgpack)); +} diff --git a/src/KKdLib/msgpack.h b/src/KKdLib/msgpack.h index 4968a4e9..b86be88f 100644 --- a/src/KKdLib/msgpack.h +++ b/src/KKdLib/msgpack.h @@ -37,7 +37,7 @@ typedef struct msgpack { } msgpack; #define CHECK_MSGPACK(a) sizeof(a) > 0x20 -#define SELECT_MSGPACK(a, b) (CHECK_MSGPACK(a) ? (##a##*)##b->ptr : (##a##*)##b->data) +#define SELECT_MSGPACK(a, b) (CHECK_MSGPACK(a) ? (a*)(b)->ptr : (##a##*)(b)->data) typedef struct msgpack_array { msgpack* data; @@ -66,7 +66,6 @@ extern msgpack* msgpack_init_uint64_t(wchar_t* name, uint64_t val); extern msgpack* msgpack_init_float_t(wchar_t* name, float_t val); extern msgpack* msgpack_init_double_t(wchar_t* name, double_t val); extern msgpack* msgpack_init_string(wchar_t* name, wchar_t* val); -extern void msgpack_dispose(msgpack* msg); extern bool msgpack_check_null(msgpack* msg); extern bool msgpack_check_not_null(msgpack* msg); extern msgpack* msgpack_get_by_index(msgpack* msg, size_t index); @@ -115,3 +114,4 @@ extern uint64_t msgpack_read_uint64_t(msgpack* msg, wchar_t* name); extern float_t msgpack_read_float_t(msgpack* msg, wchar_t* name); extern double_t msgpack_read_double_t(msgpack* msg, wchar_t* name); extern wchar_t* msgpack_read_string(msgpack* msg, wchar_t* name); +extern void msgpack_dispose(msgpack* msg); diff --git a/src/KKdLib/pdi.h b/src/KKdLib/pdi.h deleted file mode 100644 index 7ea0e860..00000000 --- a/src/KKdLib/pdi.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#pragma once - -#include "default.h" -#include "kf.h" - -typedef struct pdi { - kft2* array; - size_t length; - - float_t frame; - float_t time; - float_t value; - float_t delta_frame; - float_t interpolation_framerate; - float_t requested_framerate; - - kft2* first_key; - kft2* last_key; -} pdi; - -extern pdi* kft2_array_to_pdi(kft2* array, size_t length, - float_t interpolation_framerate, float_t requested_framerate); -extern void pdi_set_interpolation_framerate(pdi* interp, float_t interpolation_framerate); -extern void pdi_set_requested_framerate(pdi* interp, float_t requested_framerate); -extern void pdi_update(pdi* interp); -extern void pdi_reset(pdi* interp); -extern float_t pdi_set_time(pdi* interp, float_t time); -extern float_t pdi_set_frame(pdi* interp, float_t frame); -extern float_t pdi_add_time(pdi* interp, float_t time); -extern float_t pdi_next_frame(pdi* interp); - diff --git a/src/KKdLib/pv_db.h b/src/KKdLib/pv_db.h index 84336d51..c2ecdf77 100644 --- a/src/KKdLib/pv_db.h +++ b/src/KKdLib/pv_db.h @@ -281,11 +281,9 @@ typedef struct field_ac200 { vector_ptr_char ex_auth_3d_list; // AC510/AC511/AC520/AC521/AC600 char* aet_back; - char* aet_back_low; // not AC200 char* aet_front; char* aet_front_low; // not AC200 char* aet_id_back; - char* aet_id_back_low; // not AC200 char* aet_id_front; char* aet_id_front_low; // not AC200 char* auth_3d; @@ -300,11 +298,9 @@ typedef struct field_ac500 { vector_ptr_char auth_3d_list; char* aet_back; - char* aet_back_low; char* aet_front; char* aet_front_low; char* aet_id_back; - char* aet_id_back_low; char* aet_id_front; char* aet_id_front_low; char* auth_3d; @@ -321,11 +317,9 @@ typedef struct field_aft101 { vector_ptr_char ex_auth_3d_list; char* aet_back; - char* aet_back_low; char* aet_front; char* aet_front_low; char* aet_id_back; - char* aet_id_back_low; char* aet_id_front; char* aet_id_front_low; char* auth_3d; @@ -360,13 +354,11 @@ typedef struct field_aft300 { char* aet_back; int32_t aet_back_frame; - char* aet_back_low; char* aet_front; int32_t aet_front_frame; char* aet_front_low; int32_t aet_front_low_frame; char* aet_id_back; - char* aet_id_back_low; char* aet_id_front; char* aet_id_front_low; char* auth_3d; @@ -405,7 +397,6 @@ typedef struct field_aft500 { char* aet_back; int32_t aet_back_frame; - char* aet_back_low; char* aet_front; char* aet_front_3d_surf; int32_t aet_front_3d_surf_frame; @@ -413,7 +404,6 @@ typedef struct field_aft500 { char* aet_front_low; int32_t aet_front_low_frame; char* aet_id_back; - char* aet_id_back_low; char* aet_id_front; char* aet_id_front_3d_surf; char* aet_id_front_low; diff --git a/src/KKdLib/qti.c b/src/KKdLib/qti.c index 8a1fcc2b..3a987585 100644 --- a/src/KKdLib/qti.c +++ b/src/KKdLib/qti.c @@ -29,21 +29,21 @@ qti* quat_trans_array_to_qti(quat_trans* array, size_t length, return interp; } -FORCE_INLINE void qti_set_interpolation_framerate(qti* interp, float_t interpolation_framerate) { +inline void qti_set_interpolation_framerate(qti* interp, float_t interpolation_framerate) { interp->interpolation_framerate = interpolation_framerate; interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; } -FORCE_INLINE void qti_set_requested_framerate(qti* interp, float_t requested_framerate) { +inline void qti_set_requested_framerate(qti* interp, float_t requested_framerate) { interp->requested_framerate = requested_framerate; interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; } -FORCE_INLINE void qti_update(qti* interp) { +inline void qti_update(qti* interp) { interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; } -FORCE_INLINE void qti_reset(qti* interp) { +inline void qti_reset(qti* interp) { interp->delta_frame = interp->interpolation_framerate / interp->requested_framerate; interp->frame = -interp->delta_frame; interp->time = interp->frame / interp->requested_framerate; } diff --git a/src/KKdLib/quat_trans.c b/src/KKdLib/quat_trans.c index 2d40d0fa..e4d46d0c 100644 --- a/src/KKdLib/quat_trans.c +++ b/src/KKdLib/quat_trans.c @@ -13,6 +13,6 @@ void lerp_quat_trans(quat_trans* x, quat_trans* y, quat_trans* z, float_t blend) blend = 0.0f; quat_slerp(&x->quat, &y->quat, &z->quat, blend); - vec3_lerp(x->trans, y->trans, z->trans, blend); - z->time = lerpf(x->time, y->time, blend); + vec3_lerp_scalar(x->trans, y->trans, z->trans, blend); + z->time = lerp(x->time, y->time, blend); } diff --git a/src/KKdLib/sort.c b/src/KKdLib/sort.c index 0e2341ee..6913695e 100644 --- a/src/KKdLib/sort.c +++ b/src/KKdLib/sort.c @@ -7,8 +7,10 @@ #include "sort.h" -FORCE_INLINE int32_t digit(int32_t n, size_t k, size_t m) { - return (n >> (RADIX * k) & (m - 1)); +#define RADIX 8 + +inline int32_t digit(int32_t n, size_t k, size_t m) { + return (int32_t)(((ssize_t)n >> (RADIX * k) & (m - 1))); } void radix_sort(int32_t* array, size_t length) { diff --git a/src/KKdLib/sort.h b/src/KKdLib/sort.h index 6f0d6e82..9bad483c 100644 --- a/src/KKdLib/sort.h +++ b/src/KKdLib/sort.h @@ -9,6 +9,4 @@ #include "default.h" -#define RADIX 8 - extern void radix_sort(int32_t* array, size_t length); diff --git a/src/KKdLib/sound_diva.c b/src/KKdLib/sound_diva.c index a0f9ae3d..9594c571 100644 --- a/src/KKdLib/sound_diva.c +++ b/src/KKdLib/sound_diva.c @@ -5,8 +5,8 @@ #include "sound_diva.h" #include "sound_wav.h" -#include "io_path.h" #include "io_stream.h" +#include "str_utils.h" static const int8_t ima_index_table[] = { -1, -1, -1, -1, 2, 4, 6, 8, @@ -37,10 +37,6 @@ diva* diva_init() { return d; } -void diva_dispose(diva* d) { - free(d); -} - void diva_read(diva* d, char* path) { wchar_t* path_buf = char_string_to_wchar_t_string(path); diva_wread(d, path_buf); @@ -48,7 +44,7 @@ void diva_read(diva* d, char* path) { } void diva_wread(diva* d, wchar_t* path) { - wchar_t* path_diva = path_wadd_extension(path, L".diva"); + wchar_t* path_diva = str_utils_wadd(path, L".diva"); stream* s = io_wopen(path_diva, L"rb"); if (s->io.stream) { uint32_t signature = io_read_uint32_t(s); @@ -70,9 +66,9 @@ void diva_wread(diva* d, wchar_t* path) { size_t ch = d->channels; size_t samples_count = d->samples_count; - float_t* data = force_malloc_s(sizeof(float_t), samples_count * ch); - int32_t* current = force_malloc_s(sizeof(int32_t), ch); - int32_t* current_clamp = force_malloc_s(sizeof(int32_t), ch); + float_t* data = force_malloc_s(float_t, samples_count * ch); + int32_t* current = force_malloc_s(int32_t, ch); + int32_t* current_clamp = force_malloc_s(int32_t, ch); int8_t* step_index = force_malloc(ch); float_t* temp_data = data; @@ -110,7 +106,7 @@ void diva_wwrite(diva* d, wchar_t* path) { if (!data) return; - wchar_t* path_diva = path_wadd_extension(path, L".diva"); + wchar_t* path_diva = str_utils_wadd(path, L".diva"); stream* s = io_wopen(path_diva, L"wb"); if (s->io.stream) { io_write_uint32_t(s, 0x41564944); @@ -132,8 +128,8 @@ void diva_wwrite(diva* d, wchar_t* path) { size_t ch = d->channels; size_t samples_count = d->samples_count; - int32_t* current = force_malloc_s(sizeof(int32_t), ch); - int32_t* current_clamp = force_malloc_s(sizeof(int32_t), ch); + int32_t* current = force_malloc_s(int32_t, ch); + int32_t* current_clamp = force_malloc_s(int32_t, ch); int8_t* step_index = force_malloc(ch); float_t* temp_data = data; @@ -159,10 +155,14 @@ void diva_wwrite(diva* d, wchar_t* path) { free(data); } +void diva_dispose(diva* d) { + free(d); +} + static void diva_read_wav(diva* d, wchar_t* path, float_t** data) { *data = 0; size_t samples = 0; - wchar_t* path_wav = path_wadd_extension(path, L".wav"); + wchar_t* path_wav = str_utils_wadd(path, L".wav"); wav* w = wav_init(); wav_wread(w, path_wav, data, &samples); d->channels = w->channels; @@ -173,7 +173,7 @@ static void diva_read_wav(diva* d, wchar_t* path, float_t** data) { } static void diva_write_wav(diva* d, wchar_t* path, float_t* data) { - wchar_t* path_wav = path_wadd_extension(path, L".wav"); + wchar_t* path_wav = str_utils_wadd(path, L".wav"); wav* w = wav_init(); w->bytes = 4; w->channels = d->channels; diff --git a/src/KKdLib/sound_diva.h b/src/KKdLib/sound_diva.h index 7e545866..f61e3eff 100644 --- a/src/KKdLib/sound_diva.h +++ b/src/KKdLib/sound_diva.h @@ -17,8 +17,8 @@ typedef struct diva { } diva; extern diva* diva_init(); -extern void diva_dispose(diva* d); extern void diva_read(diva* d, char* path); extern void diva_wread(diva* d, wchar_t* path); extern void diva_write(diva* d, char* path); extern void diva_wwrite(diva* d, wchar_t* path); +extern void diva_dispose(diva* d); diff --git a/src/KKdLib/sound_vag.c b/src/KKdLib/sound_vag.c index 7bb73119..451abbaa 100644 --- a/src/KKdLib/sound_vag.c +++ b/src/KKdLib/sound_vag.c @@ -7,6 +7,7 @@ #include "sound_wav.h" #include "io_path.h" #include "io_stream.h" +#include "str_utils.h" static const int8_t shift_factor_table[] = { 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1 @@ -108,10 +109,6 @@ vag* vag_init() { return v; } -void vag_dispose(vag* v) { - free(v); -} - void vag_read(vag* v, char* path) { wchar_t* path_buf = char_string_to_wchar_t_string(path); vag_wread(v, path_buf); @@ -119,7 +116,7 @@ void vag_read(vag* v, char* path) { } void vag_wread(vag* v, wchar_t* path) { - wchar_t* path_vag = path_wadd_extension(path, L".vag"); + wchar_t* path_vag = str_utils_wadd(path, L".vag"); stream* s = io_wopen(path_vag, L"rb"); if (s->io.stream) { uint32_t signature = io_read_uint32_t(s); @@ -147,8 +144,8 @@ void vag_wread(vag* v, wchar_t* path) { size_t vag_block_size = BLOCK_SIZE * ch; size_t num_blocks = (v->size / v->channels) >> 4; - int32_t* samp = force_malloc_s(sizeof(int32_t), ch * 4); - float_t* data = force_malloc_s(sizeof(float_t), num_blocks * vag_block_size); + int32_t* samp = force_malloc_s(int32_t, ch * 4); + float_t* data = force_malloc_s(float_t, num_blocks * vag_block_size); uint8_t* flags = force_malloc(num_blocks); uint8_t nibble[BLOCK_SIZE]; @@ -226,8 +223,8 @@ void vag_wwrite(vag* v, wchar_t* path, vag_option option) { v->size = align_val_divide(num_samples, BLOCK_SIZE, BLOCK_SIZE); - wchar_t* temp_path = path_wget_without_extension(path); - wchar_t* path_vag = path_wadd_extension(temp_path, L".vag"); + wchar_t* temp_path = str_utils_wget_without_extension(path); + wchar_t* path_vag = str_utils_wadd(temp_path, L".vag"); stream* s = io_wopen(path_vag, L"wb"); if (s->io.stream) { int32_t coef_index_count; @@ -267,7 +264,7 @@ void vag_wwrite(vag* v, wchar_t* path, vag_option option) { size_t c, i, i1, i2; int32_t ch = v->channels; - int32_t* samp = force_malloc_s(sizeof(int32_t), hevag ? v->channels * 8LL : 4LL); + int32_t* samp = force_malloc_s(int32_t, hevag ? v->channels * 8LL : 4LL); if (hevag && coef_index_count > 29) { uint8_t flag, sample; int32_t temp_data[BLOCK_SIZE]; @@ -378,10 +375,14 @@ void vag_wwrite(vag* v, wchar_t* path, vag_option option) { free(data); } +void vag_dispose(vag* v) { + free(v); +} + static void vag_read_wav_straight(vag* v, wchar_t* path, float_t** data, size_t* samples) { *data = 0; *samples = 0; - wchar_t* path_wav = path_wadd_extension(path, L".wav"); + wchar_t* path_wav = str_utils_wadd(path, L".wav"); wav* w = wav_init(); wav_wread(w, path_wav, data, samples); v->channels = w->channels; @@ -394,14 +395,14 @@ static void vag_read_wav(vag* v, wchar_t* path, float_t** data, size_t* samples, *data = 0; *samples = 0; *flags = 0; - if (!path_wcheck_ends_with(path, L".0")) { + if (!str_utils_wcheck_ends_with(path, L".0")) { vag_read_wav_straight(v, path, data, samples); return; } wchar_t temp[MAX_PATH]; size_t count = 0; - wchar_t* temp_path = path_wget_without_extension(path); + wchar_t* temp_path = str_utils_wget_without_extension(path); vector_bool loop; bool n, l; bool add_loop = false; @@ -431,8 +432,8 @@ static void vag_read_wav(vag* v, wchar_t* path, float_t** data, size_t* samples, } count += add_loop; - float_t** wav_data = force_malloc_s(sizeof(float_t*), count); - size_t* wav_samples = force_malloc_s(sizeof(size_t), count); + float_t** wav_data = force_malloc_s(float_t*, count); + size_t* wav_samples = force_malloc_s(size_t, count); wav* w = wav_init(); for (size_t i = 0; i < count; i++) { @@ -469,7 +470,7 @@ static void vag_read_wav(vag* v, wchar_t* path, float_t** data, size_t* samples, l = false; size_t ch = v->channels; - *data = force_malloc_s(sizeof(float_t), *samples * ch); + *data = force_malloc_s(float_t, *samples * ch); float_t* data_temp = *data; for (size_t i = 0; i < count; i++) { size_t i3; @@ -543,7 +544,7 @@ static void vag_write_wav_straight(vag* v, wchar_t* path, float_t* data, size_t break; } - wchar_t* path_wav = path_wadd_extension(path, L".wav"); + wchar_t* path_wav = str_utils_wadd(path, L".wav"); wav* w = wav_init(); w->bytes = 4; w->channels = v->channels; diff --git a/src/KKdLib/sound_vag.h b/src/KKdLib/sound_vag.h index ef0797b1..b54e3c30 100644 --- a/src/KKdLib/sound_vag.h +++ b/src/KKdLib/sound_vag.h @@ -25,8 +25,8 @@ typedef struct vag { } vag; extern vag* vag_init(); -extern void vag_dispose(vag* f); extern void vag_read(vag* v, char* path); extern void vag_wread(vag* v, wchar_t* path); extern void vag_write(vag* v, char* path, vag_option option); extern void vag_wwrite(vag* v, wchar_t* path, vag_option option); +extern void vag_dispose(vag* f); diff --git a/src/KKdLib/sound_wav.c b/src/KKdLib/sound_wav.c index 7e12e6ab..97468249 100644 --- a/src/KKdLib/sound_wav.c +++ b/src/KKdLib/sound_wav.c @@ -11,10 +11,6 @@ wav* wav_init() { return w; } -void wav_dispose(wav* f) { - free(f); -} - void wav_read(wav* w, char* path, float_t** data, size_t* samples) { wchar_t* path_buf = char_string_to_wchar_t_string(path); wav_wread(w, path_buf, data, samples); @@ -69,7 +65,7 @@ void wav_wread(wav* w, wchar_t* path, float_t** data, size_t* samples) { *w = w_t; *samples = w->size / w->channels / w->bytes; - *data = force_malloc_s(sizeof(float_t), w->size / w->bytes); + *data = force_malloc_s(float_t, w->size / w->bytes); size_t t_s = *samples; float_t* t_d = *data; @@ -208,4 +204,8 @@ void wav_wwrite(wav* w, wchar_t* path, float_t* data, size_t samples) { } } io_dispose(s); +} + +void wav_dispose(wav* f) { + free(f); } \ No newline at end of file diff --git a/src/KKdLib/sound_wav.h b/src/KKdLib/sound_wav.h index a47b73c8..a36decc4 100644 --- a/src/KKdLib/sound_wav.h +++ b/src/KKdLib/sound_wav.h @@ -19,8 +19,8 @@ typedef struct wav { } wav; extern wav* wav_init(); -extern void wav_dispose(wav* w); extern void wav_read(wav* w, char* path, float_t** data, size_t* samples); extern void wav_wread(wav* w, wchar_t* path, float_t** data, size_t* samples); extern void wav_write(wav* w, char* path, float_t* data, size_t samples); extern void wav_wwrite(wav* w, wchar_t* path, float_t* data, size_t samples); +extern void wav_dispose(wav* w); diff --git a/src/KKdLib/str_utils.c b/src/KKdLib/str_utils.c new file mode 100644 index 00000000..f29a1172 --- /dev/null +++ b/src/KKdLib/str_utils.c @@ -0,0 +1,362 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "str_utils.h" + +bool str_utils_check_ends_with(char* str, char* mask) { + if (!str || !mask) + return false; + + size_t mask_len = strlen(mask); + size_t len = strlen(str); + char* t = str; + while (t) { + t = strstr(t, mask); + if (t) { + t += mask_len; + if (t == str + len) + return true; + } + } + return false; +} + +bool str_utils_wcheck_ends_with(wchar_t* str, wchar_t* mask) { + if (!str || !mask) + return false; + + size_t mask_len = wcslen(mask); + size_t len = wcslen(str); + wchar_t* t = str; + while (t) { + t = wcsstr(t, mask); + if (t) { + t += mask_len; + if (t == str + len) + return true; + } + } + return false; +} + +char* str_utils_split_get_right(char* str, char split) { + if (!str) + return 0; + + char* t = strchr(str, split); + if (!t) + return str_utils_copy(str); + t++; + + size_t len = strlen(t); + char* p = force_malloc(len + 1); + memcpy(p, t, len); + p[len] = 0; + return p; +} + +wchar_t* str_utils_wsplit_get_right(wchar_t* str, wchar_t split) { + if (!str) + return 0; + + wchar_t* t = wcschr(str, split); + if (!t) + return str_utils_wcopy(str); + t++; + + size_t len = wcslen(t); + wchar_t* p = force_malloc_s(wchar_t, len + 1); + memcpy(p, t, sizeof(wchar_t) * len); + p[len] = 0; + return p; +} + +char* str_utils_split_get_left(char* str, char split) { + if (!str) + return 0; + + char* t = strchr(str, split); + + size_t len = t ? t - str : strlen(str); + char* p = force_malloc(len + 1); + memcpy(p, str, len); + p[len] = 0; + return p; +} + +wchar_t* str_utils_wsplit_get_left(wchar_t* str, wchar_t split) { + if (!str) + return 0; + + wchar_t* t = wcschr(str, split); + + size_t len = t ? t - str : wcslen(str); + wchar_t* p = force_malloc_s(wchar_t, len + 1); + memcpy(p, str, sizeof(wchar_t) * len); + p[len] = 0; + return p; +} + +char* str_utils_split_get_right_include(char* str, char split) { + if (!str) + return 0; + + char* t = strchr(str, split); + if (!t) + return str_utils_copy(str); + + size_t len = strlen(t); + char* p = force_malloc(len + 1); + memcpy(p, t, len); + p[len] = 0; + return p; +} + +wchar_t* str_utils_wsplit_get_right_include(wchar_t* str, wchar_t split) { + if (!str) + return 0; + + wchar_t* t = wcschr(str, split); + if (!t) + return str_utils_wcopy(str); + + size_t len = wcslen(t); + wchar_t* p = force_malloc_s(wchar_t, len + 1); + memcpy(p, t, sizeof(wchar_t) * len); + p[len] = 0; + return p; +} + +char* str_utils_split_get_left_include(char* str, char split) { + if (!str) + return 0; + + char* t = strchr(str, split); + t++; + + size_t len = t ? t - str : strlen(str); + char* p = force_malloc(len + 1); + memcpy(p, str, len); + p[len] = 0; + return p; +} + +wchar_t* str_utils_wsplit_get_left_include(wchar_t* str, wchar_t split) { + if (!str) + return 0; + + wchar_t* t = wcschr(str, split); + t++; + + size_t len = t ? t - str : wcslen(str); + wchar_t* p = force_malloc_s(wchar_t, len + 1); + memcpy(p, str, sizeof(wchar_t) * len); + p[len] = 0; + return p; +} + +char* str_utils_split_right_get_right(char* str, char split) { + if (!str) + return 0; + + char* t = strrchr(str, split); + if (!t) + return str_utils_copy(str); + t++; + + size_t len = t - str; + char* p = force_malloc(len + 1); + memcpy(p, t, len); + p[len] = 0; + return p; +} + +wchar_t* str_utils_wsplit_right_get_right(wchar_t* str, wchar_t split) { + if (!str) + return 0; + + wchar_t* t = wcsrchr(str, split); + if (!t) + return str_utils_wcopy(str); + t++; + + size_t len = t - str; + wchar_t* p = force_malloc_s(wchar_t, len + 1); + memcpy(p, t, sizeof(wchar_t) * len); + p[len] = 0; + return p; +} + +char* str_utils_split_right_get_left(char* str, char split) { + if (!str) + return 0; + + char* t = strrchr(str, split); + + size_t len = t ? t - str : strlen(str); + char* p = force_malloc(len + 1); + memcpy(p, str, len); + p[len] = 0; + return p; +} + +wchar_t* str_utils_wsplit_right_get_left(wchar_t* str, wchar_t split) { + if (!str) + return 0; + + wchar_t* t = wcsrchr(str, split); + + size_t len = t ? t - str : wcslen(str); + wchar_t* p = force_malloc_s(wchar_t, len + 1); + memcpy(p, str, sizeof(wchar_t) * len); + p[len] = 0; + return p; +} + +char* str_utils_split_right_get_right_include(char* str, char split) { + if (!str) + return 0; + + char* t = strrchr(str, split); + if (!t) + return str_utils_copy(str); + + size_t len = t - str + 1; + char* p = force_malloc(len + 1); + memcpy(p, t, len); + p[len] = 0; + return p; +} + +wchar_t* str_utils_wsplit_right_get_right_include(wchar_t* str, wchar_t split) { + if (!str) + return 0; + + wchar_t* t = wcsrchr(str, split); + if (!t) + return str_utils_wcopy(str); + + size_t len = t - str + 1; + wchar_t* p = force_malloc_s(wchar_t, len + 1); + memcpy(p, t, sizeof(wchar_t) * len); + p[len] = 0; + return p; +} + +char* str_utils_split_right_get_left_include(char* str, char split) { + if (!str) + return 0; + + char* t = strrchr(str, split); + if (t) + t++; + + size_t len = t ? t - str : strlen(str); + char* p = force_malloc(len + 1); + memcpy(p, str, len); + p[len] = 0; + return p; +} + +wchar_t* str_utils_wsplit_right_get_left_include(wchar_t* str, wchar_t split) { + if (!str) + return 0; + + wchar_t* t = wcsrchr(str, split); + if (t) + t++; + + size_t len = t ? t - str : wcslen(str); + wchar_t* p = force_malloc_s(wchar_t, len + 1); + memcpy(p, str, sizeof(wchar_t) * len); + p[len] = 0; + return p; +} + +char* str_utils_get_extension(char* str) { + if (!str) + return 0; + + char* t = strrchr(str, '\\'); + return str_utils_split_right_get_right_include(t ? t + 1 : str, '.'); +} + +wchar_t* str_utils_wget_extension(wchar_t* str) { + if (!str) + return 0; + + wchar_t* t = wcsrchr(str, L'\\'); + return str_utils_wsplit_right_get_right_include(t ? t + 1 : str, L'.'); +} + +char* str_utils_get_without_extension(char* str) { + if (!str) + return 0; + + char* t = strrchr(str, '\\'); + return str_utils_split_right_get_left(t ? t + 1 : str, '.'); +} + +wchar_t* str_utils_wget_without_extension(wchar_t* str) { + if (!str) + return 0; + + wchar_t* t = wcsrchr(str, L'\\'); + return str_utils_wsplit_right_get_left(t ? t + 1 : str, L'.'); +} + +char* str_utils_add(char* str0, char* str1) { + if (str0 && str1) { + size_t str0_len = strlen(str0) + 1; + size_t str1_len = strlen(str1) + 1; + char* p = force_malloc(str0_len - 1 + str1_len); + memcpy(p, str0, str0_len); + memcpy(p + str0_len - 1, str1, str1_len); + return p; + } + else if (str0) + return str_utils_copy(str0); + else if (str1) + return str_utils_copy(str1); + else + return 0; +} + +wchar_t* str_utils_wadd(wchar_t* str0, wchar_t* str1) { + if (str0 && str1) { + size_t str0_len = wcslen(str0) + 1; + size_t str1_len = wcslen(str1) + 1; + wchar_t* p = force_malloc_s(wchar_t, str0_len - 1 + str1_len); + memcpy(p, str0, sizeof(wchar_t) * str0_len); + memcpy(p + str0_len - 1, str1, sizeof(wchar_t) * str1_len); + return p; + } + else if (str0) + return str_utils_wcopy(str0); + else if (str1) + return str_utils_wcopy(str1); + else + return 0; +} + +char* str_utils_copy(char* str) { + if (!str) + return 0; + + size_t len = strlen(str) + 1; + char* p = force_malloc(len); + memcpy(p, str, len); + return p; +} + +wchar_t* str_utils_wcopy(wchar_t* str) { + if (!str) + return 0; + + size_t len = wcslen(str) + 1; + wchar_t* p = force_malloc_s(wchar_t, len); + memcpy(p, str, sizeof(wchar_t) * len); + return p; +} diff --git a/src/KKdLib/str_utils.h b/src/KKdLib/str_utils.h new file mode 100644 index 00000000..c986f131 --- /dev/null +++ b/src/KKdLib/str_utils.h @@ -0,0 +1,35 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "default.h" + +extern bool str_utils_check_ends_with(char* str, char* mask); +extern bool str_utils_wcheck_ends_with(wchar_t* str, wchar_t* mask); +extern char* str_utils_split_get_right(char* str, char split); +extern wchar_t* str_utils_wsplit_get_right(wchar_t* str, wchar_t split); +extern char* str_utils_split_get_left(char* str, char split); +extern wchar_t* str_utils_wsplit_get_left(wchar_t* str, wchar_t split); +extern char* str_utils_split_get_right_include(char* str, char split); +extern wchar_t* str_utils_wsplit_get_right_include(wchar_t* str, wchar_t split); +extern char* str_utils_split_get_left_include(char* str, char split); +extern wchar_t* str_utils_wsplit_get_left_include(wchar_t* str, wchar_t split); +extern char* str_utils_split_right_get_right(char* str, char split); +extern wchar_t* str_utils_wsplit_right_get_right(wchar_t* str, wchar_t split); +extern char* str_utils_split_right_get_left(char* str, char split); +extern wchar_t* str_utils_wsplit_right_get_left(wchar_t* str, wchar_t split); +extern char* str_utils_split_right_get_right_include(char* str, char split); +extern wchar_t* str_utils_wsplit_right_get_right_include(wchar_t* str, wchar_t split); +extern char* str_utils_split_right_get_left_include(char* str, char split); +extern wchar_t* str_utils_wsplit_right_get_left_include(wchar_t* str, wchar_t split); +extern char* str_utils_get_extension(char* str); +extern wchar_t* str_utils_wget_extension(wchar_t* str); +extern char* str_utils_get_without_extension(char* str); +extern wchar_t* str_utils_wget_without_extension(wchar_t* str); +extern char* str_utils_add(char* str0, char* str1); +extern wchar_t* str_utils_wadd(wchar_t* str0, wchar_t* str1); +extern char* str_utils_copy(char* str); +extern wchar_t* str_utils_wcopy(wchar_t* str); diff --git a/src/KKdLib/txp.c b/src/KKdLib/txp.c index cc209e16..ede98dd5 100644 --- a/src/KKdLib/txp.c +++ b/src/KKdLib/txp.c @@ -6,100 +6,161 @@ #include "txp.h" #include "io_stream.h" -static void txp_dispose_sub(txp* t); +vector_func(txp_mipmap) +vector_func(txp) -txp* txp_init() { - txp* t = force_malloc(sizeof(txp)); - return t; +void txp_copy(txp* src, txp* dst) { + memset(dst, 0, sizeof(txp)); + dst->has_cubemap = src->has_cubemap; + dst->array_size = src->array_size; + dst->mipmaps_count = src->mipmaps_count; + vector_txp_mipmap_append(&dst->data, src->data.end - src->data.begin); + txp_mipmap* tex_mipmap = src->data.begin; + for (size_t j = 0; j < src->array_size; j++) { + for (size_t k = 0; k < src->mipmaps_count; k++, tex_mipmap++) { + txp_mipmap t_mip; + t_mip.width = tex_mipmap->width; + t_mip.height = tex_mipmap->height; + t_mip.format = tex_mipmap->format; + t_mip.size = tex_mipmap->size; + + ssize_t size = txp_get_size(t_mip.format, t_mip.width, t_mip.height); + t_mip.data = force_malloc(max(size, t_mip.size)); + memcpy(t_mip.data, tex_mipmap->data, t_mip.size); + size -= t_mip.size; + if (size > 0) + memset((void*)((size_t)t_mip.data + t_mip.size), 0, size); + } + } } -void txp_pack_file(txp* t, void** data, size_t* length, bool use_big_endian) { - txp_data* t_data; - txp_sub_data** t_sub_data; - txp_sub_data* t_sub_sub_data; +uint32_t txp_get_size(txp_format format, uint32_t width, uint32_t height) { + uint32_t size = width * height; + switch (format) { + case TXP_A8: + return size; + case TXP_RGB8: + return size * 3; + case TXP_RGBA8: + return size * 4; + case TXP_RGB5: + return size * 2; + case TXP_RGB5A1: + return size * 2; + case TXP_RGBA4: + return size * 2; + case TXP_L8: + return size; + case TXP_L8A8: + return size * 2; + case TXP_DXT1: + case TXP_DXT1a: + case TXP_DXT3: + case TXP_DXT5: + case TXP_ATI1: + case TXP_ATI2: + width = align_val(width, 4); + height = align_val(height, 4); + size = width * height; + switch (format) { + case TXP_DXT1: + return size / 2; + case TXP_DXT1a: + return size / 2; + case TXP_DXT3: + return size; + case TXP_DXT5: + return size; + case TXP_ATI1: + return size / 2; + case TXP_ATI2: + return size; + } + break; + } + return 0; +} + +void txp_free(txp* t) { + if (!t) + return; + + for (txp_mipmap* i = t->data.begin; i != t->data.end; i++) + free(i->data); + vector_txp_mipmap_free(&t->data); +} + +bool tex_set_pack_file(vector_txp* t, void** data, size_t* length, bool use_big_endian) { + size_t l; + txp* tex; + txp_mipmap* tex_mipmap; if (!t || !data || !length) - return; + return false; *data = 0; *length = 0; - if (!t->count || !t->data) - return; + size_t count = t->end - t->begin; + if (count < 1) + return false; - size_t* txp4_offset = force_malloc_s(sizeof(size_t), t->count); - size_t** txp2_offset = force_malloc_s(sizeof(size_t*), t->count); - t_data = t->data; - for (size_t i = 0; i < t->count; i++, t_data++) - txp2_offset[i] = force_malloc_s(sizeof(size_t), (size_t)t_data->mipmaps_count * t_data->array_size); + size_t* txp4_offset = force_malloc_s(size_t, count); + size_t** txp2_offset = force_malloc_s(size_t*, count); + tex = t->begin; + for (size_t i = 0; i < count; i++, tex++) + txp2_offset[i] = force_malloc_s(size_t, (size_t)tex->mipmaps_count * tex->array_size); - stream* s = io_open_memory(0, 0); - s->is_big_endian = use_big_endian; - io_write_uint32_t(s, 0); - io_write_uint32_t(s, 0); - io_write_uint32_t(s, 0); - for (size_t i = 0; i < t->count; i++) - io_write_uint32_t(s, 0); + l = 12 + count * 4; - t_data = t->data; - for (size_t i = 0; i < t->count; i++, t_data++) { - txp4_offset[i] = io_get_position(s); + tex = t->begin; + for (size_t i = 0; i < count; i++, tex++) { + txp4_offset[i] = l; + l += 12 + (size_t)tex->array_size * tex->mipmaps_count * 4; - io_write_uint32_t(s, 0); - io_write_uint32_t(s, 0); - io_write_uint32_t(s, 0); - for (size_t j = 0; j < t_data->array_size; j++) - for (size_t k = 0; k < t_data->mipmaps_count; k++) - io_write_uint32_t(s, 0); - - t_sub_data = t_data->data; - for (size_t j = 0; j < t_data->array_size; j++, t_sub_data++) { - t_sub_sub_data = *t_sub_data; - for (size_t k = 0; k < t_data->mipmaps_count; k++, t_sub_sub_data++) { - txp2_offset[i][j * t_data->mipmaps_count + k] = io_get_position(s); - io_write_uint32_t(s, 0); - io_write_uint32_t(s, 0); - io_write_uint32_t(s, 0); - io_write_uint32_t(s, 0); - io_write_uint32_t(s, 0); - io_write_uint32_t(s, 0); - io_write(s, t_sub_sub_data->data, t_sub_sub_data->size); + tex_mipmap = tex->data.begin; + for (size_t j = 0; j < tex->array_size; j++) { + for (size_t k = 0; k < tex->mipmaps_count; k++, tex_mipmap++) { + txp2_offset[i][j * tex->mipmaps_count + k] = l; + l += 24; + l += tex_mipmap->size; } } } - io_set_position(s, 0, SEEK_SET); + stream* s = io_open_memory(0, l); + s->is_big_endian = use_big_endian; io_write_uint32_t_stream_reverse_endianess(s, 0x03505854); - io_write_uint32_t_stream_reverse_endianess(s, t->count); - io_write_uint32_t_stream_reverse_endianess(s, (uint8_t)t->count | 0x01010100); - for (size_t i = 0; i < t->count; i++) + io_write_uint32_t_stream_reverse_endianess(s, (uint32_t)count); + io_write_uint32_t_stream_reverse_endianess(s, (uint8_t)count | 0x01010100); + for (size_t i = 0; i < count; i++) io_write_uint32_t_stream_reverse_endianess(s, (uint32_t)txp4_offset[i]); - t_data = t->data; - for (size_t i = 0; i < t->count; i++, t_data++) { + tex = t->begin; + for (size_t i = 0; i < count; i++, tex++) { io_set_position(s, txp4_offset[i], SEEK_SET); - io_write_uint32_t_stream_reverse_endianess(s, t_data->array_size > 1 ? 0x05505854 : 0x04505854); - io_write_uint32_t_stream_reverse_endianess(s, t_data->mipmaps_count * t_data->array_size); - io_write_uint32_t_stream_reverse_endianess(s, (uint8_t)t_data->mipmaps_count - | ((uint8_t)t_data->array_size << 8) | 0x01010000); - for (size_t j = 0; j < t_data->array_size; j++) - for (size_t k = 0; k < t_data->mipmaps_count; k++) + io_write_uint32_t_stream_reverse_endianess(s, tex->array_size > 1 ? 0x05505854 : 0x04505854); + io_write_uint32_t_stream_reverse_endianess(s, tex->mipmaps_count * tex->array_size); + io_write_uint32_t_stream_reverse_endianess(s, (uint8_t)tex->mipmaps_count + | ((uint8_t)tex->array_size << 8) | 0x01010000); + for (size_t j = 0; j < tex->array_size; j++) + for (size_t k = 0; k < tex->mipmaps_count; k++) io_write_uint32_t_stream_reverse_endianess(s, - (uint32_t)(txp2_offset[i][j * t_data->mipmaps_count + k] - txp4_offset[i])); + (uint32_t)(txp2_offset[i][j * tex->mipmaps_count + k] - txp4_offset[i])); - t_sub_data = t_data->data; - for (size_t j = 0; j < t_data->array_size; j++, t_sub_data++) { - t_sub_sub_data = *t_sub_data; - for (size_t k = 0; k < t_data->mipmaps_count; k++, t_sub_sub_data++) { - io_set_position(s, txp2_offset[i][j * t_data->mipmaps_count + k], SEEK_SET); + tex_mipmap = tex->data.begin; + for (size_t j = 0; j < tex->array_size; j++) + for (size_t k = 0; k < tex->mipmaps_count; k++, tex_mipmap++) { + io_set_position(s, txp2_offset[i][j * tex->mipmaps_count + k], SEEK_SET); io_write_uint32_t_stream_reverse_endianess(s, 0x02505854); - io_write_uint32_t_stream_reverse_endianess(s, t_sub_sub_data->width); - io_write_uint32_t_stream_reverse_endianess(s, t_sub_sub_data->height); - io_write_uint32_t_stream_reverse_endianess(s, t_sub_sub_data->format); - io_write_uint32_t_stream_reverse_endianess(s, (uint32_t)(j * t_data->mipmaps_count + k)); - io_write_uint32_t_stream_reverse_endianess(s, t_sub_sub_data->size); + io_write_uint32_t_stream_reverse_endianess(s, tex_mipmap->width); + io_write_uint32_t_stream_reverse_endianess(s, tex_mipmap->height); + io_write_uint32_t_stream_reverse_endianess(s, tex_mipmap->format); + io_write_uint32_t_stream_reverse_endianess(s, (uint32_t)(j * tex->mipmaps_count + k)); + io_write_uint32_t_stream_reverse_endianess(s, tex_mipmap->size); + io_write(s, tex_mipmap->data, tex_mipmap->size); + io_align(s, 0x04); } - } } io_set_position(s, 0, SEEK_END); io_align(s, 0x10); @@ -109,22 +170,77 @@ void txp_pack_file(txp* t, void** data, size_t* length, bool use_big_endian) { memcpy(*data, s->io.data.vec.begin, *length); io_dispose(s); - for (size_t i = 0; i < t->count; i++) + for (size_t i = 0; i < count; i++) free(txp2_offset[i]); free(txp2_offset); free(txp4_offset); + return true; } -bool txp_unpack_file(txp* t, void* data, bool use_big_endian) { +bool tex_set_produce_enrs(vector_txp* t, vector_enrs_entry* enrs) { + size_t l; + txp* tex; + txp_mipmap* tex_mipmap; + + if (!t || !enrs) + return false; + + *enrs = (vector_enrs_entry){ 0, 0, 0 }; + l = 0; + + size_t count = t->end - t->begin; + if (count < 1) + return false; + + uint32_t o; + vector_enrs_entry e = { 0, 0, 0 }; + enrs_entry ee; + + ee = (enrs_entry){ 0, 1, 12, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 3, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 12; + + ee = (enrs_entry){ o, 1, (uint32_t)(count * 4), 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, (uint32_t)count, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += (size_t)(o = (uint32_t)(count * 4LL)); + + tex = t->begin; + for (size_t i = 0; i < count; i++, tex++) { + ee = (enrs_entry){ o, 1, 12, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 3, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += o = 12; + + ee = (enrs_entry){ o, 1, tex->array_size * 4, tex->mipmaps_count, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, tex->array_size, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += (size_t)(o = (uint32_t)((size_t)tex->array_size * tex->mipmaps_count * 4)); + + tex_mipmap = tex->data.begin; + for (size_t j = 0; j < tex->array_size; j++) { + for (size_t k = 0; k < tex->mipmaps_count; k++, tex_mipmap++) { + ee = (enrs_entry){ o, 1, 24, 1, { 0, 0, 0 } }; + vector_enrs_sub_entry_push_back(&ee.sub, &(enrs_sub_entry){ 0, 6, ENRS_TYPE_DWORD }); + vector_enrs_entry_push_back(&e, &ee); + l += (size_t)(o = (uint32_t)(24 + tex_mipmap->size)); + } + } + } + + *enrs = e; + return true; +} + +bool tex_set_unpack_file(vector_txp* t, void* data, bool use_big_endian) { uint32_t sign; - uint32_t t_count; - txp_data* t_data; - txp_sub_data** t_sub_data; - txp_sub_data* t_sub_sub_data; + uint32_t tex_count; + txp tex; + txp_mipmap tex_mipmap; + size_t set_d; size_t d; - size_t sub_d; - size_t sub_sub_d; - size_t sub_sub_tex_d; + size_t mipmap_d; uint32_t sub_tex_count; uint32_t info; @@ -139,106 +255,95 @@ bool txp_unpack_file(txp* t, void* data, bool use_big_endian) { if (sign != 0x03505854) return false; - txp_dispose_sub(t); - d = (size_t)data; - t_count = *(uint32_t*)(d + 4); - t->count = t_count; - t_data = force_malloc_s(sizeof(txp_data), t_count); - t->data = t_data; - for (size_t i = 0; i < t_count; i++, t_data++) { - sub_d = d + (size_t)((uint32_t*)(d + 12))[i]; - if (use_big_endian) - sign = reverse_endianess_uint32_t(*(uint32_t*)sub_d); - else - sign = *(uint32_t*)sub_d; + tex_set_free(t); + set_d = (size_t)data; + if (use_big_endian) + tex_count = reverse_endianess_uint32_t(*(uint32_t*)(set_d + 4)); + else + tex_count = *(uint32_t*)(set_d + 4); + + *t = (vector_txp){ 0, 0, 0 }; + vector_txp_append(t, tex_count); + for (size_t i = 0; i < tex_count; i++) { + if (use_big_endian) { + d = set_d + (size_t)reverse_endianess_uint32_t(((uint32_t*)(set_d + 12))[i]); + sign = reverse_endianess_uint32_t(*(uint32_t*)d); + } + else { + d = set_d + (size_t)((uint32_t*)(set_d + 12))[i]; + sign = *(uint32_t*)d; + } if (sign != 0x04505854 && sign != 0x05505854) continue; if (use_big_endian) { - sub_tex_count = reverse_endianess_uint32_t(*(uint32_t*)(sub_d + 4)); - info = reverse_endianess_uint32_t(*(uint32_t*)(sub_d + 8)); + sub_tex_count = reverse_endianess_uint32_t(*(uint32_t*)(d + 4)); + info = reverse_endianess_uint32_t(*(uint32_t*)(d + 8)); } else { - sub_tex_count = *(uint32_t*)(sub_d + 4); - info = *(uint32_t*)(sub_d + 8); + sub_tex_count = *(uint32_t*)(d + 4); + info = *(uint32_t*)(d + 8); } - t_data->mipmaps_count = info & 0xFF; - t_data->array_size = (info >> 8) & 0xFF; + memset(&tex, 0, sizeof(txp)); + tex.has_cubemap = sign == 0x05505854; + tex.mipmaps_count = info & 0xFF; + tex.array_size = (info >> 8) & 0xFF; - if (t_data->array_size == 1 && t_data->mipmaps_count != sub_tex_count) - t_data->mipmaps_count = sub_tex_count & 0xFF; - - t_sub_data = force_malloc_s(sizeof(txp_sub_data*), t_data->array_size); - t_data->data = t_sub_data; - for (size_t j = 0; j < t_data->array_size; j++, t_sub_data++) { - t_sub_sub_data = force_malloc_s(sizeof(txp_sub_data), t_data->mipmaps_count); - *t_sub_data = t_sub_sub_data; - for (size_t k = 0; k < t_data->mipmaps_count; k++, t_sub_sub_data++) { - sub_sub_d = sub_d + (size_t)((uint32_t*)(sub_d + 12))[j * t_data->mipmaps_count + k]; - if (use_big_endian) - sign = reverse_endianess_uint32_t(*(uint32_t*)sub_sub_d); - else - sign = *(uint32_t*)sub_sub_d; - - if (sign != 0x02505854) - continue; + if (tex.array_size == 1 && tex.mipmaps_count != sub_tex_count) + tex.mipmaps_count = sub_tex_count & 0xFF; + uint32_t mipmaps_count = tex.mipmaps_count; + tex.data = (vector_txp_mipmap){ 0, 0, 0 }; + vector_txp_mipmap_append(&tex.data, (size_t)tex.array_size * tex.mipmaps_count); + for (size_t j = 0; j < tex.array_size; j++) + for (size_t k = 0; k < tex.mipmaps_count; k++) { if (use_big_endian) { - t_sub_sub_data->width = reverse_endianess_uint32_t(*(uint32_t*)(sub_sub_d + 4)); - t_sub_sub_data->height = reverse_endianess_uint32_t(*(uint32_t*)(sub_sub_d + 8)); - t_sub_sub_data->format = reverse_endianess_uint32_t(*(uint32_t*)(sub_sub_d + 12)); - t_sub_sub_data->size = reverse_endianess_uint32_t(*(uint32_t*)(sub_sub_d + 20)); + mipmap_d = d + (size_t)reverse_endianess_uint32_t(((uint32_t*)(d + 12))[j * mipmaps_count + k]); + sign = reverse_endianess_uint32_t(*(uint32_t*)mipmap_d); } else { - t_sub_sub_data->width = *(uint32_t*)(sub_sub_d + 4); - t_sub_sub_data->height = *(uint32_t*)(sub_sub_d + 8); - t_sub_sub_data->format = *(uint32_t*)(sub_sub_d + 12); - t_sub_sub_data->size = *(uint32_t*)(sub_sub_d + 20); + mipmap_d = d + (size_t)((uint32_t*)(d + 12))[j * mipmaps_count + k]; + sign = *(uint32_t*)mipmap_d; } - sub_sub_tex_d = sub_sub_d + 24; - t_sub_sub_data->data = force_malloc(t_sub_sub_data->size); - memcpy(t_sub_sub_data->data, (void*)sub_sub_tex_d, t_sub_sub_data->size); + memset(&tex_mipmap, 0, sizeof(txp_mipmap)); + + if (use_big_endian) { + tex_mipmap.width = reverse_endianess_uint32_t(*(uint32_t*)(mipmap_d + 4)); + tex_mipmap.height = reverse_endianess_uint32_t(*(uint32_t*)(mipmap_d + 8)); + tex_mipmap.format = reverse_endianess_uint32_t(*(uint32_t*)(mipmap_d + 12)); + tex_mipmap.size = reverse_endianess_uint32_t(*(uint32_t*)(mipmap_d + 20)); + } + else { + tex_mipmap.width = *(uint32_t*)(mipmap_d + 4); + tex_mipmap.height = *(uint32_t*)(mipmap_d + 8); + tex_mipmap.format = *(uint32_t*)(mipmap_d + 12); + tex_mipmap.size = *(uint32_t*)(mipmap_d + 20); + } + + ssize_t size = txp_get_size(tex_mipmap.format, tex_mipmap.width, tex_mipmap.height); + tex_mipmap.data = force_malloc(max(size, tex_mipmap.size)); + memcpy(tex_mipmap.data, (void*)(mipmap_d + 24), tex_mipmap.size); + size -= tex_mipmap.size; + if (size > 0) + memset((void*)((size_t)tex_mipmap.data + tex_mipmap.size), 0, size); + vector_txp_mipmap_push_back(&tex.data, &tex_mipmap); } - } + vector_txp_push_back(t, &tex); } return true; } -static void txp_dispose_sub(txp* t) { - size_t i; - size_t j; - size_t k; - uint32_t t_count; - txp_data* t_data; - txp_sub_data** t_sub_data; - txp_sub_data* t_sub_sub_data; +void tex_set_free(vector_txp* t) { if (!t) return; - t_count = t->count; - t_data = t->data; - for (i = 0; i < t_count; i++, t_data++) { - if (!t_data->data) - continue; - - t_sub_data = t_data->data; - for (j = 0; j < t_data->array_size; j++, t_sub_data++) { - if (!*t_sub_data) - continue; - - t_sub_sub_data = *t_sub_data; - for (k = 0; k < t_data->mipmaps_count; k++, t_sub_sub_data++) - free(t_sub_sub_data->data); - free(*t_sub_data); - } - free(t_data->data); + for (txp* i = t->begin; i != t->end; i++) { + for (txp_mipmap* j = i->data.begin; j != i->data.end; j++) + free(j->data); + vector_txp_mipmap_free(&i->data); } -} - -void txp_dispose(txp* t) { - txp_dispose_sub(t); - free(t); + vector_txp_free(t); } diff --git a/src/KKdLib/txp.h b/src/KKdLib/txp.h index 12723c0f..b42255fc 100644 --- a/src/KKdLib/txp.h +++ b/src/KKdLib/txp.h @@ -6,6 +6,8 @@ #pragma once #include "default.h" +#include "f2_enrs.h" +#include "vector.h" typedef enum txp_format { TXP_A8 = 0, @@ -24,26 +26,29 @@ typedef enum txp_format { TXP_L8A8 = 13, } txp_format; -typedef struct txp_sub_data { +typedef struct txp_mipmap { uint32_t width; uint32_t height; txp_format format; uint32_t size; void* data; -} txp_sub_data; +} txp_mipmap; -typedef struct txp_data { - uint32_t array_size; - uint32_t mipmaps_count; - txp_sub_data** data; -} txp_data; +vector(txp_mipmap) typedef struct txp { - uint32_t count; - txp_data* data; + bool has_cubemap; + uint32_t array_size; + uint32_t mipmaps_count; + vector_txp_mipmap data; } txp; -extern txp* txp_init(); -extern void txp_pack_file(txp* t, void** data, size_t* length, bool use_big_endian); -extern bool txp_unpack_file(txp* t, void* data, bool use_big_endian); -extern void txp_dispose(txp* t); +vector(txp) + +extern void txp_copy(txp* src, txp* dst); +extern uint32_t txp_get_size(txp_format format, uint32_t width, uint32_t height); +extern void txp_free(txp* t); +extern bool tex_set_pack_file(vector_txp* t, void** data, size_t* length, bool use_big_endian); +extern bool tex_set_produce_enrs(vector_txp* t, vector_enrs_entry* enrs); +extern bool tex_set_unpack_file(vector_txp* t, void* data, bool use_big_endian); +extern void tex_set_free(vector_txp* t); diff --git a/src/KKdLib/types.h b/src/KKdLib/types.h index 0a8eb7b0..49a5bbec 100644 --- a/src/KKdLib/types.h +++ b/src/KKdLib/types.h @@ -5,18 +5,12 @@ #pragma once +#include +#include #include -#define FORCE_INLINE __forceinline #define FASTCALL __fastcall - -#ifdef bool -#undef bool -#endif - -typedef char bool; -#define true (1) -#define false (0) +#define ALIGN(n) __declspec(align(n)) #ifdef ssize_t #undef ssize_t; diff --git a/src/KKdLib/utf8.c b/src/KKdLib/utf8.c index d282186a..dbaa45e8 100644 --- a/src/KKdLib/utf8.c +++ b/src/KKdLib/utf8.c @@ -71,7 +71,7 @@ wchar_t* utf8_decode(char* s) { length++; } - wchar_t* str = force_malloc_s(sizeof(wchar_t), length + 1); + wchar_t* str = force_malloc_s(wchar_t, length + 1); for (size_t i = 0, j = 0; i < len; i++) { char t = s[i]; if (~t & 0x80) { diff --git a/src/KKdLib/vec.c b/src/KKdLib/vec.c index 6737c411..ddd3fc09 100644 --- a/src/KKdLib/vec.c +++ b/src/KKdLib/vec.c @@ -5,9 +5,11 @@ #include "vec.h" -const __m128 vec2_negate = { .m128_u32 = { 0x80000000, 0x80000000, 0x00000000, 0x00000000 } }; -const __m128 vec3_negate = { .m128_u32 = { 0x80000000, 0x80000000, 0x80000000, 0x00000000 } }; -const __m128 vec4_negate = { .m128_u32 = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 } }; +const __m128 vec2_negate = { .m128_f32 = { -0.0, -0.0, 0.0, 0.0 } }; +const __m128 vec3_negate = { .m128_f32 = { -0.0, -0.0, -0.0, 0.0 } }; +const __m128 vec4_negate = { .m128_f32 = { -0.0, -0.0, -0.0, -0.0 } }; + +const __m128d vec2d_negate = { -0.0, -0.0 }; const vec2 vec2_identity = { 1.0f, 1.0f }; const vec3 vec3_identity = { 1.0f, 1.0f, 1.0f }; @@ -16,3 +18,11 @@ const vec4 vec4_identity = { 1.0f, 1.0f, 1.0f, 1.0f }; const vec2 vec2_null = { 0.0f, 0.0f }; const vec3 vec3_null = { 0.0f, 0.0f, 0.0f }; const vec4 vec4_null = { 0.0f, 0.0f, 0.0f, 0.0f }; + +const vec2i vec2i_null = { 0, 0 }; +const vec3i vec3i_null = { 0, 0, 0 }; +const vec4i vec4i_null = { 0, 0, 0, 0 }; + +const vec2d vec2d_identity = { 1.0f, 1.0f }; + +const vec2d vec2d_null = { 0.0f, 0.0f }; diff --git a/src/KKdLib/vec.h b/src/KKdLib/vec.h index 91b3a1d6..6541898d 100644 --- a/src/KKdLib/vec.h +++ b/src/KKdLib/vec.h @@ -6,45 +6,31 @@ #pragma once #include "default.h" +#include "half_t.h" #include #include -#define v2(t) typedef struct vec2_##t { \ +#define v2(t) \ +typedef struct vec2_##t { \ t x; \ t y; \ } vec2_##t; -#define v3(t) typedef struct vec3_##t { \ +#define v3(t) \ +typedef struct vec3_##t { \ t x; \ t y; \ t z; \ } vec3_##t; -#define v4(t) typedef struct vec4_##t { \ +#define v4(t) \ +typedef struct vec4_##t { \ t x; \ t y; \ t z; \ t w; \ } vec4_##t; -typedef struct vec2i { - int32_t x; - int32_t y; -} vec2i; - -typedef struct vec3i { - int32_t x; - int32_t y; - int32_t z; -} vec3i; - -typedef struct vec4i { - int32_t x; - int32_t y; - int32_t z; - int32_t w; -} vec4i; - typedef struct vec2 { float_t x; float_t y; @@ -56,17 +42,51 @@ typedef struct vec3 { float_t z; } vec3; -typedef struct vec4 { - float_t x; - float_t y; - float_t z; - float_t w; +typedef union vec4 { + struct { + float_t x; + float_t y; + float_t z; + float_t w; + }; + __m128 data; } vec4; +typedef struct vec2i { + int32_t x; + int32_t y; +} vec2i; + +typedef struct vec3i { + int32_t x; + int32_t y; + int32_t z; +} vec3i; + +typedef union vec4i { + struct { + int32_t x; + int32_t y; + int32_t z; + int32_t w; + }; + __m128i data; +} vec4i; + +typedef struct vec2d { + struct { + double_t x; + double_t y; + }; + __m128d data; +} vec2d; + extern const __m128 vec2_negate; extern const __m128 vec3_negate; extern const __m128 vec4_negate; +extern const __m128 vec4_negate; + extern const vec2 vec2_identity; extern const vec3 vec3_identity; extern const vec4 vec4_identity; @@ -75,6 +95,14 @@ extern const vec2 vec2_null; extern const vec3 vec3_null; extern const vec4 vec4_null; +extern const vec2i vec2i_null; +extern const vec3i vec3i_null; +extern const vec4i vec4i_null; + +extern const vec2d vec2d_identity; + +extern const vec2d vec2d_null; + #define vec2_add(x, y, z) \ { \ __m128 xt; \ @@ -271,18 +299,28 @@ extern const vec4 vec4_null; #define vec2_lerp(x, y, z, blend) \ { \ - __m128 b0; \ - __m128 b1; \ + __m128 b; \ __m128 xt; \ __m128 yt; \ __m128 zt; \ *(vec2*)&xt = (x); \ *(vec2*)&yt = (y); \ - b0 = _mm_set_ss(1.0f - blend); \ - b0 = _mm_shuffle_ps(b0, b0, 0); \ - b1 = _mm_set_ss(blend); \ - b1 = _mm_shuffle_ps(b1, b1, 0); \ - zt = _mm_add_ps(_mm_mul_ps(xt, b0), _mm_mul_ps(yt, b1)); \ + *(vec2*)&b = (blend); \ + zt = _mm_add_ps(xt, _mm_mul_ps(_mm_sub_ps(yt, xt), b)); \ + (z) = *(vec2*)&zt; \ +} + +#define vec2_lerp_scalar(x, y, z, blend) \ +{ \ + __m128 b; \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + *(vec2*)&xt = (x); \ + *(vec2*)&yt = (y); \ + b = _mm_set_ss(blend); \ + b = _mm_shuffle_ps(b, b, 0); \ + zt = _mm_add_ps(xt, _mm_mul_ps(_mm_sub_ps(yt, xt), b)); \ (z) = *(vec2*)&zt; \ } @@ -299,6 +337,99 @@ extern const vec4 vec4_null; (z) = *(vec2*)&zt; \ } +#define vec2_rcp(x, z) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + *(vec2*)&xt = (x); \ + *(vec2*)&yt = vec2_identity; \ + zt = _mm_div_ps(yt, xt); \ + (z) = *(vec2*)&zt; \ +} + +#define vec2_min(x, y, z) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + *(vec2*)&xt = (x); \ + *(vec2*)&yt = (y); \ + zt = _mm_min_ps(xt, yt); \ + (z) = *(vec2*)&zt; \ +} + +#define vec2_max(x, y, z) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + *(vec2*)&xt = (x); \ + *(vec2*)&yt = (y); \ + zt = _mm_max_ps(xt, yt); \ + (z) = *(vec2*)&zt; \ +} + +#define vec2_clamp(x, y, z, w) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + __m128 wt; \ + *(vec2*)&xt = (x); \ + *(vec2*)&yt = (y); \ + *(vec2*)&zt = (z); \ + wt = _mm_min_ps(_mm_max_ps(xt, yt), zt); \ + (w) = *(vec2*)&wt; \ +} + +#define vec2_clamp_scalar(x, y, z, w) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + __m128 wt; \ + *(vec2*)&xt = (x); \ + yt = _mm_set_ss(y); \ + zt = _mm_set_ss(z); \ + wt = _mm_min_ps(_mm_max_ps(xt, _mm_shuffle_ps(yt, yt, 0)), _mm_shuffle_ps(zt, zt, 0)); \ + (w) = *(vec2*)&wt; \ +} + +#define vec2_mult_min_max(x, y, z, w) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + __m128 wt; \ + *(vec2*)&xt = (x); \ + *(vec2*)&yt = (y); \ + *(vec2*)&zt = (z); \ + yt = _mm_xor_ps(yt, vec2_negate); \ + wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, vec4_null.data)), \ + _mm_and_ps(zt, _mm_cmpgt_ps(xt, vec4_null.data))); \ + wt = _mm_mul_ps(xt, wt); \ + (w) = *(vec2*)&wt; \ +} + +#define vec2_mult_min_max_scalar(x, y, z, w) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + __m128 wt; \ + *(vec2*)&xt = (x); \ + yt = _mm_set_ss(y); \ + yt = _mm_shuffle_ps(yt, yt, 0); \ + zt = _mm_set_ss(z); \ + zt = _mm_shuffle_ps(zt, zt, 0); \ + yt = _mm_xor_ps(yt, vec2_negate); \ + wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, vec4_null.data)), \ + _mm_and_ps(zt, _mm_cmpgt_ps(xt, vec4_null.data))); \ + wt = _mm_mul_ps(xt, wt); \ + (w) = *(vec2*)&wt; \ +} + #define vec3_add(x, y, z) \ { \ __m128 xt; \ @@ -446,9 +577,10 @@ extern const vec4 vec4_null; __m128 yt; \ __m128 zt; \ *(vec3*)&xt = (x); \ + xt.m128_f32[3] = 0.0f; \ *(vec3*)&yt = (y); \ + yt.m128_f32[3] = 0.0f; \ zt = _mm_mul_ps(xt, yt); \ - zt.m128_f32[3] = 0.0f; \ zt = _mm_hadd_ps(zt, zt); \ (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ } @@ -458,8 +590,8 @@ extern const vec4 vec4_null; __m128 xt; \ __m128 zt; \ *(vec3*)&xt = (x); \ + xt.m128_f32[3] = 0.0f; \ zt = _mm_mul_ps(xt, xt); \ - zt.m128_f32[3] = 0.0f; \ zt = _mm_hadd_ps(zt, zt); \ (z) = _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); \ } @@ -469,8 +601,8 @@ extern const vec4 vec4_null; __m128 xt; \ __m128 zt; \ *(vec3*)&xt = (x); \ + xt.m128_f32[3] = 0.0f; \ zt = _mm_mul_ps(xt, xt); \ - zt.m128_f32[3] = 0.0f; \ zt = _mm_hadd_ps(zt, zt); \ (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ } @@ -481,10 +613,11 @@ extern const vec4 vec4_null; __m128 yt; \ __m128 zt; \ *(vec3*)&xt = (x); \ + xt.m128_f32[3] = 0.0f; \ *(vec3*)&yt = (y); \ + yt.m128_f32[3] = 0.0f; \ zt = _mm_sub_ps(xt, yt); \ zt = _mm_mul_ps(zt, zt); \ - zt.m128_f32[3] = 0.0f; \ zt = _mm_hadd_ps(zt, zt); \ (z) = _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); \ } @@ -495,28 +628,39 @@ extern const vec4 vec4_null; __m128 yt; \ __m128 zt; \ *(vec3*)&xt = (x); \ + xt.m128_f32[3] = 0.0f; \ *(vec3*)&yt = (y); \ + yt.m128_f32[3] = 0.0f; \ zt = _mm_sub_ps(xt, yt); \ zt = _mm_mul_ps(zt, zt); \ - zt.m128_f32[3] = 0.0f; \ zt = _mm_hadd_ps(zt, zt); \ (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ } #define vec3_lerp(x, y, z, blend) \ { \ - __m128 b0; \ - __m128 b1; \ + __m128 b; \ __m128 xt; \ __m128 yt; \ __m128 zt; \ *(vec3*)&xt = (x); \ *(vec3*)&yt = (y); \ - b0 = _mm_set_ss(1.0f - blend); \ - b0 = _mm_shuffle_ps(b0, b0, 0); \ - b1 = _mm_set_ss(blend); \ - b1 = _mm_shuffle_ps(b1, b1, 0); \ - zt = _mm_add_ps(_mm_mul_ps(xt, b0), _mm_mul_ps(yt, b1)); \ + *(vec3*)&b = (blend); \ + zt = _mm_add_ps(xt, _mm_mul_ps(_mm_sub_ps(yt, xt), b)); \ + (z) = *(vec3*)&zt; \ +} + +#define vec3_lerp_scalar(x, y, z, blend) \ +{ \ + __m128 b; \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + *(vec3*)&xt = (x); \ + *(vec3*)&yt = (y); \ + b = _mm_set_ss(blend); \ + b = _mm_shuffle_ps(b, b, 0); \ + zt = _mm_add_ps(xt, _mm_mul_ps(_mm_sub_ps(yt, xt), b)); \ (z) = *(vec3*)&zt; \ } @@ -525,8 +669,8 @@ extern const vec4 vec4_null; __m128 xt; \ __m128 zt; \ *(vec3*)&xt = (x); \ + xt.m128_f32[3] = 0.0f; \ zt = _mm_mul_ps(xt, xt); \ - zt.m128_f32[3] = 0.0f; \ zt = _mm_hadd_ps(zt, zt); \ zt = _mm_sqrt_ss(_mm_hadd_ps(zt, zt)); \ if (zt.m128_f32[0] != 0.0f) \ @@ -535,6 +679,99 @@ extern const vec4 vec4_null; (z) = *(vec3*)&zt; \ } +#define vec3_rcp(x, z) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + *(vec3*)&xt = (x); \ + *(vec3*)&yt = vec3_identity; \ + zt = _mm_div_ps(yt, xt); \ + (z) = *(vec3*)&zt; \ +} + +#define vec3_min(x, y, z) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + *(vec3*)&xt = (x); \ + *(vec3*)&yt = (y); \ + zt = _mm_min_ps(xt, yt); \ + (z) = *(vec3*)&zt; \ +} + +#define vec3_max(x, y, z) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + *(vec3*)&xt = (x); \ + *(vec3*)&yt = (y); \ + zt = _mm_max_ps(xt, yt); \ + (z) = *(vec3*)&zt; \ +} + +#define vec3_clamp(x, y, z, w) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + __m128 wt; \ + *(vec3*)&xt = (x); \ + *(vec3*)&yt = (y); \ + *(vec3*)&zt = (z); \ + wt = _mm_min_ps(_mm_max_ps(xt, yt), zt); \ + (w) = *(vec3*)&wt; \ +} + +#define vec3_clamp_scalar(x, y, z, w) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + __m128 wt; \ + *(vec3*)&xt = (x); \ + yt = _mm_set_ss(y); \ + zt = _mm_set_ss(z); \ + wt = _mm_min_ps(_mm_max_ps(xt, _mm_shuffle_ps(yt, yt, 0)), _mm_shuffle_ps(zt, zt, 0)); \ + (w) = *(vec3*)&wt; \ +} + +#define vec3_mult_min_max(x, y, z, w) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + __m128 wt; \ + *(vec3*)&xt = (x); \ + *(vec3*)&yt = (y); \ + *(vec3*)&zt = (z); \ + yt = _mm_xor_ps(yt, vec3_negate); \ + wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, vec4_null.data)), \ + _mm_and_ps(zt, _mm_cmpgt_ps(xt, vec4_null.data))); \ + wt = _mm_mul_ps(xt, wt); \ + (w) = *(vec3*)&wt; \ +} + +#define vec3_mult_min_max_scalar(x, y, z, w) \ +{ \ + __m128 xt; \ + __m128 yt; \ + __m128 zt; \ + __m128 wt; \ + *(vec3*)&xt = (x); \ + yt = _mm_set_ss(y); \ + yt = _mm_shuffle_ps(yt, yt, 0); \ + zt = _mm_set_ss(z); \ + zt = _mm_shuffle_ps(zt, zt, 0); \ + yt = _mm_xor_ps(yt, vec3_negate); \ + wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, vec4_null.data)), \ + _mm_and_ps(zt, _mm_cmpgt_ps(xt, vec4_null.data))); \ + wt = _mm_mul_ps(xt, wt); \ + (w) = *(vec3*)&wt; \ +} + #define vec3_cross(x, y, z) \ { \ __m128 xt; \ @@ -543,97 +780,93 @@ extern const vec4 vec4_null; *(vec3*)&xt = (x); \ *(vec3*)&yt = (y); \ zt = _mm_sub_ps( \ - _mm_mul_ps(_mm_shuffle_ps(xt, xt, 0b001001), _mm_shuffle_ps(yt, yt, 0b010010)), \ - _mm_mul_ps(_mm_shuffle_ps(xt, xt, 0b010010), _mm_shuffle_ps(yt, yt, 0b001001)) \ + _mm_mul_ps(_mm_shuffle_ps(xt, xt, 0x09), _mm_shuffle_ps(yt, yt, 0x12)), \ + _mm_mul_ps(_mm_shuffle_ps(xt, xt, 0x12), _mm_shuffle_ps(yt, yt, 0x09)) \ ); \ (z) = *(vec3*)&zt; \ } #define vec4_add(x, y, z) \ { \ - *(__m128*)&(z) = _mm_add_ps(*(__m128*)&(x), *(__m128*)&(y)); \ + (z).data = _mm_add_ps((x).data, (y).data); \ } #define vec4_add_scalar(x, y, z) \ { \ __m128 yt; \ yt = _mm_set_ss(y); \ - *(__m128*)&(z) = _mm_add_ps(*(__m128*)&(x), _mm_shuffle_ps(yt, yt, 0)); \ + (z).data = _mm_add_ps((x).data, _mm_shuffle_ps(yt, yt, 0)); \ } #define vec4_sub(x, y, z) \ { \ - *(__m128*)&(z) = _mm_sub_ps(*(__m128*)&(x), *(__m128*)&(y)); \ + (z).data = _mm_sub_ps((x).data, (y).data); \ } #define vec4_sub_scalar(x, y, z) \ { \ __m128 yt; \ yt = _mm_set_ss(y); \ - *(__m128*)&(z) = _mm_sub_ps(*(__m128*)&(x), _mm_shuffle_ps(yt, yt, 0)); \ + (z).data = _mm_sub_ps((x).data, _mm_shuffle_ps(yt, yt, 0)); \ } #define vec4_mult(x, y, z) \ { \ - *(__m128*)&(z) = _mm_mul_ps(*(__m128*)&(x), *(__m128*)&(y)); \ + (z).data = _mm_mul_ps((x).data, (y).data); \ } #define vec4_mult_scalar(x, y, z) \ { \ __m128 yt; \ yt = _mm_set_ss(y); \ - *(__m128*)&(z) = _mm_mul_ps(*(__m128*)&(x), _mm_shuffle_ps(yt, yt, 0)); \ + (z).data = _mm_mul_ps((x).data, _mm_shuffle_ps(yt, yt, 0)); \ } #define vec4_div(x, y, z) \ { \ - *(__m128*)&(z) = _mm_div_ps(*(__m128*)&(x), *(__m128*)&(y)); \ + (z).data = _mm_div_ps((x).data, (y).data); \ } #define vec4_div_scalar(x, y, z) \ { \ __m128 yt; \ yt = _mm_set_ss(y); \ - *(__m128*)&(z) = _mm_div_ps(*(__m128*)&(x), _mm_shuffle_ps(yt, yt, 0)); \ + (z).data = _mm_div_ps((x).data, _mm_shuffle_ps(yt, yt, 0)); \ } #define vec4_and(x, y, z) \ { \ - *(__m128*)&(z) = _mm_and_ps(*(__m128*)&(x), *(__m128*)&(y)); \ + (z).data = _mm_and_ps((x).data, (y).data); \ } #define vec4_and_scalar(x, y, z) \ { \ __m128 yt; \ yt = _mm_set_ss(y); \ - *(__m128*)&(z) = _mm_and_ps(*(__m128*)&(x), _mm_shuffle_ps(yt, yt, 0)); \ + (z).data = _mm_and_ps((x).data, _mm_shuffle_ps(yt, yt, 0)); \ } #define vec4_xor(x, y, z) \ { \ - *(__m128*)&(z) = _mm_xor_ps(*(__m128*)&(x), *(__m128*)&(y)); \ + (z).data = _mm_xor_ps((x).data, (y).data); \ } #define vec4_xor_scalar(x, y, z) \ { \ __m128 yt; \ yt = _mm_set_ss(y); \ - *(__m128*)&(z) = _mm_xor_ps(*(__m128*)&(x), _mm_shuffle_ps(yt, yt, 0)); \ + (z).data = _mm_xor_ps((x).data, _mm_shuffle_ps(yt, yt, 0)); \ } #define vec4_negate(x, z) \ { \ - *(__m128*)&(z) = _mm_xor_ps(*(__m128*)&(x), vec4_negate); \ + (z).data = _mm_xor_ps((x).data, vec4_negate); \ } #define vec4_dot(x, y, z) \ { \ - __m128 xt; \ - __m128 yt; \ __m128 zt; \ - *(vec4*)&xt = (x); \ - *(vec4*)&yt = (y); \ - zt = _mm_mul_ps(xt, yt); \ + zt = _mm_mul_ps((x).data, (y).data); \ zt = _mm_hadd_ps(zt, zt); \ (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ } @@ -642,7 +875,7 @@ extern const vec4 vec4_null; { \ __m128 xt; \ __m128 zt; \ - *(vec4*)&xt = (x); \ + xt = (x).data; \ zt = _mm_mul_ps(xt, xt); \ zt = _mm_hadd_ps(zt, zt); \ (z) = _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); \ @@ -652,7 +885,7 @@ extern const vec4 vec4_null; { \ __m128 xt; \ __m128 zt; \ - *(vec4*)&xt = (x); \ + xt = (x).data; \ zt = _mm_mul_ps(xt, xt); \ zt = _mm_hadd_ps(zt, zt); \ (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ @@ -660,12 +893,8 @@ extern const vec4 vec4_null; #define vec4_distance(x, y, z) \ { \ - __m128 xt; \ - __m128 yt; \ __m128 zt; \ - *(vec4*)&xt = (x); \ - *(vec4*)&yt = (y); \ - zt = _mm_sub_ps(xt, yt); \ + zt = _mm_sub_ps((x).data, (y).data); \ zt = _mm_mul_ps(zt, zt); \ zt = _mm_hadd_ps(zt, zt); \ (z) = _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); \ @@ -673,45 +902,442 @@ extern const vec4 vec4_null; #define vec4_distance_squared(x, y, z) \ { \ - __m128 xt; \ - __m128 yt; \ __m128 zt; \ - *(vec4*)&xt = (x); \ - *(vec4*)&yt = (y); \ - zt = _mm_sub_ps(xt, yt); \ + zt = _mm_sub_ps((x).data, (y).data); \ zt = _mm_mul_ps(zt, zt); \ - zt.m128_f32[3] = 0.0f; \ zt = _mm_hadd_ps(zt, zt); \ (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ } #define vec4_lerp(x, y, z, blend) \ { \ - __m128 b0; \ - __m128 b1; \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec4*)&xt = (x); \ - *(vec4*)&yt = (y); \ - b0 = _mm_set_ss(1.0f - blend); \ - b0 = _mm_shuffle_ps(b0, b0, 0); \ - b1 = _mm_set_ss(blend); \ - b1 = _mm_shuffle_ps(b1, b1, 0); \ - zt = _mm_add_ps(_mm_mul_ps(xt, b0), _mm_mul_ps(yt, b1)); \ - (z) = *(vec4*)&zt; \ + (z).data = _mm_add_ps((x).data, _mm_mul_ps(_mm_sub_ps((y).data, (x).data), (blend).data)); \ +} + +#define vec4_lerp_scalar(x, y, z, blend) \ +{ \ + __m128 b; \ + b = _mm_set_ss(blend); \ + b = _mm_shuffle_ps(b, b, 0); \ + (z).data = _mm_add_ps((x).data, _mm_mul_ps(_mm_sub_ps((y).data, (x).data), b)); \ } #define vec4_normalize(x, z) \ { \ __m128 xt; \ __m128 zt; \ - *(vec4*)&xt = (x); \ + xt = (x).data; \ zt = _mm_mul_ps(xt, xt); \ zt = _mm_hadd_ps(zt, zt); \ zt = _mm_sqrt_ss(_mm_hadd_ps(zt, zt)); \ if (zt.m128_f32[0] != 0.0f) \ zt.m128_f32[0] = 1.0f / zt.m128_f32[0]; \ - zt = _mm_mul_ps(xt, _mm_shuffle_ps(zt, zt, 0)); \ - (z) = *(vec4*)&zt; \ + (z).data = _mm_mul_ps(xt, _mm_shuffle_ps(zt, zt, 0)); \ +} + +#define vec4_rcp(x, z) \ +{ \ + (z).data = _mm_div_ps(vec4_identity.data, (x).data); \ +} + +#define vec4_min(x, y, z) \ +{ \ + (z).data = _mm_min_ps((x).data, (y).data); \ +} + +#define vec4_max(x, y, z) \ +{ \ + (z).data = _mm_max_ps((x).data, (y).data); \ +} + +#define vec4_clamp(x, y, z, w) \ +{ \ + (w).data = _mm_min_ps(_mm_max_ps((x).data, (y).data), (z).data); \ +} + +#define vec4_clamp_scalar(x, y, z, w) \ +{ \ + __m128 yt; \ + __m128 zt; \ + yt = _mm_set_ss(y); \ + zt = _mm_set_ss(z); \ + (w).data = _mm_min_ps(_mm_max_ps((x).data, _mm_shuffle_ps(yt, yt, 0)), _mm_shuffle_ps(zt, zt, 0)); \ +} + +#define vec4_mult_min_max(x, y, z, w) \ +{ \ + __m128 yt; \ + __m128 zt; \ + __m128 wt; \ + yt = _mm_xor_ps((y).data, vec4_negate); \ + wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps((x).data, vec4_null.data)), \ + _mm_and_ps((z).data, _mm_cmpgt_ps((x).data, vec4_null.data))); \ + (w).data = _mm_mul_ps((x).data, wt); \ +} + +#define vec4_mult_min_max_scalar(x, y, z, w) \ +{ \ + __m128 wt; \ + yt = _mm_set_ss(y); \ + yt = _mm_shuffle_ps(yt, yt, 0); \ + zt = _mm_set_ss(z); \ + zt = _mm_shuffle_ps(zt, zt, 0); \ + yt = _mm_xor_ps(yt, vec4_negate); \ + wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps((x).data, vec4_null.data)), \ + _mm_and_ps(zt, _mm_cmpgt_ps((x).data, vec4_null.data))); \ + (w).data = _mm_mul_ps((x).data, wt); \ +} + +#define vec2i_add(x, y, z) \ +{ \ + __m128i xt; \ + __m128i yt; \ + __m128i zt; \ + *(vec2i*)&xt = (x); \ + *(vec2i*)&yt = (y); \ + zt = _mm_add_epi32(xt, yt); \ + (z) = *(vec2i*)&zt; \ +} + +#define vec2i_add_scalar(x, y, z) \ +{ \ + __m128i xt; \ + __m128i yt; \ + __m128i zt; \ + *(vec2i*)&xt = (x); \ + yt = _mm_set1_epi32(y); \ + zt = _mm_add_epi32(xt, _mm_shuffle_epi32(yt, yt, 0)); \ + (z) = *(vec2i*)&zt; \ +} + +#define vec2i_sub(x, y, z) \ +{ \ + __m128i xt; \ + __m128i yt; \ + __m128i zt; \ + *(vec2i*)&xt = (x); \ + *(vec2i*)&yt = (y); \ + zt = _mm_sub_epi32(xt, yt); \ + (z) = *(vec2i*)&zt; \ +} + +#define vec2i_sub_scalar(x, y, z) \ +{ \ + __m128i xt; \ + __m128i yt; \ + __m128i zt; \ + *(vec2i*)&xt = (x); \ + yt = _mm_set1_epi32(y); \ + zt = _mm_sub_epi32(xt, _mm_shuffle_epi32(yt, yt, 0)); \ + (z) = *(vec2i*)&zt; \ +} + +#define vec2_to_vec2i(x, z) \ +{ \ + __m128 xt; \ + __m128i zt; \ + *(vec2*)&xt = (x); \ + zt = _mm_cvtps_epi32(xt); \ + (z) = *(vec2i*)&zt; \ +} + +#define vec2i_to_vec2(x, z) \ +{ \ + __m128i xt; \ + __m128 zt; \ + *(vec2i*)&xt = (x); \ + zt = _mm_cvtepi32_ps(xt); \ + (z) = *(vec2*)&zt; \ +} + +#define vec3i_add(x, y, z) \ +{ \ + __m128i xt; \ + __m128i yt; \ + __m128i zt; \ + *(vec3i*)&xt = (x); \ + *(vec3i*)&yt = (y); \ + zt = _mm_add_epi32(xt, yt); \ + (z) = *(vec3i*)&zt; \ +} + +#define vec3i_add_scalar(x, y, z) \ +{ \ + __m128i xt; \ + __m128i yt; \ + __m128i zt; \ + *(vec3i*)&xt = (x); \ + yt = _mm_set1_epi32(y); \ + zt = _mm_add_epi32(xt, _mm_shuffle_epi32(yt, yt, 0)); \ + (z) = *(vec3i*)&zt; \ +} + +#define vec3i_sub(x, y, z) \ +{ \ + __m128i xt; \ + __m128i yt; \ + __m128i zt; \ + *(vec3i*)&xt = (x); \ + *(vec3i*)&yt = (y); \ + zt = _mm_sub_epi32(xt, yt); \ + (z) = *(vec3i*)&zt; \ +} + +#define vec3i_sub_scalar(x, y, z) \ +{ \ + __m128i xt; \ + __m128i yt; \ + __m128i zt; \ + *(vec3i*)&xt = (x); \ + yt = _mm_set1_epi32(y); \ + zt = _mm_sub_epi32(xt, _mm_shuffle_epi32(yt, yt, 0)); \ + (z) = *(vec3i*)&zt; \ +} + +#define vec3_to_vec3i(x, z) \ +{ \ + __m128 xt; \ + __m128i zt; \ + *(vec3*)&xt = (x); \ + zt = _mm_cvtps_epi32(xt); \ + (z) = *(vec3i*)&zt; \ +} + +#define vec3i_to_vec3(x, z) \ +{ \ + __m128i xt; \ + __m128 zt; \ + *(vec3i*)&xt = (x); \ + zt = _mm_cvtepi32_ps(xt); \ + (z) = *(vec3*)&zt; \ +} + +#define vec4i_add(x, y, z) \ +{ \ + (z).data = _mm_add_epi32((x).data, (y).data); \ +} + +#define vec4i_add_scalar(x, y, z) \ +{ \ + __m128i yt; \ + yt = _mm_set1_epi32(y); \ + (z).data = _mm_add_epi32((x).data, _mm_shuffle_epi32(yt, yt, 0)); \ +} + +#define vec4i_sub(x, y, z) \ +{ \ + (z).data = _mm_sub_epi32((x).data, (y).data); \ +} + +#define vec4i_sub_scalar(x, y, z) \ +{ \ + __m128i yt; \ + yt = _mm_set1_epi32(y); \ + (z).data = _mm_sub_epi32((x).data, _mm_shuffle_epi32(yt, yt, 0)); \ +} + +#define vec4_to_vec4i(x, z) \ +{ \ + (z).data = _mm_cvtps_epi32((x).data); \ +} + +#define vec4i_to_vec4(x, z) \ +{ \ + (z).data = _mm_cvtepi32_ps((x).data); \ +} + +#define vec2d_add(x, y, z) \ +{ \ + (z).data = _mm_add_pd((x).data, (y).data); \ +} + +#define vec2d_add_scalar(x, y, z) \ +{ \ + __m128d yt; \ + yt = _mm_set_sd(y); \ + (z).data = _mm_add_pd((x).data, _mm_shuffle_pd(yt, yt, 0)); \ +} + +#define vec2d_sub(x, y, z) \ +{ \ + (z).data = _mm_sub_pd((x).data, (y).data); \ +} + +#define vec2d_sub_scalar(x, y, z) \ +{ \ + __m128d yt; \ + yt = _mm_set_sd(y); \ + (z).data = _mm_sub_pd((x).data, _mm_shuffle_pd(yt, yt, 0)); \ +} + +#define vec2d_mult(x, y, z) \ +{ \ + (z).data = _mm_mul_pd((x).data, (y).data); \ +} + +#define vec2d_mult_scalar(x, y, z) \ +{ \ + __m128d yt; \ + yt = _mm_set_sd(y); \ + (z).data = _mm_mul_pd((x).data, _mm_shuffle_pd(yt, yt, 0)); \ +} + +#define vec2d_div(x, y, z) \ +{ \ + (z).data = _mm_div_pd((x).data, (y).data); \ +} + +#define vec2d_div_scalar(x, y, z) \ +{ \ + __m128d yt; \ + yt = _mm_set_sd(y); \ + (z).data = _mm_div_pd((x).data, _mm_shuffle_pd(yt, yt, 0)); \ +} + +#define vec2d_and(x, y, z) \ +{ \ + (z).data = _mm_and_pd((x).data, (y).data); \ +} + +#define vec2d_and_scalar(x, y, z) \ +{ \ + __m128d yt; \ + yt = _mm_set_sd(y); \ + (z).data = _mm_and_pd((x).data, _mm_shuffle_pd(yt, yt, 0)); \ +} + +#define vec2d_xor(x, y, z) \ +{ \ + (z).data = _mm_xor_pd((x).data, (y).data); \ +} + +#define vec2d_xor_scalar(x, y, z) \ +{ \ + __m128d yt; \ + yt = _mm_set_sd(y); \ + (z).data = _mm_xor_pd((x).data, _mm_shuffle_pd(yt, yt, 0)); \ +} + +#define vec2d_negate(x, z) \ +{ \ + (z).data = _mm_xor_pd((x).data, vec2d_negate); \ +} + +#define vec2d_dot(x, y, z) \ +{ \ + __m128d zt; \ + zt = _mm_mul_pd((x).data, (y).data); \ + (z) = _mm_cvtsd_f64(_mm_hadd_pd(zt, zt)); \ +} + +#define vec2d_length(x, z) \ +{ \ + __m128d zt; \ + zt = _mm_mul_pd((x).data, (x).data); \ + (z) = _mm_cvtsd_f64(_mm_sqrt_sd(_mm_hadd_pd(zt, zt))); \ +} + +#define vec2d_length_squared(x, z) \ +{ \ + __m128d zt; \ + zt = _mm_mul_pd((x).data, (x).data); \ + (z) = _mm_cvtsd_f64(_mm_hadd_pd(zt, zt)); \ +} + +#define vec2d_distance(x, y, z) \ +{ \ + __m128d zt; \ + zt = _mm_sub_pd((x).data, (y).data); \ + zt = _mm_mul_pd(zt, zt); \ + (z) = _mm_cvtsd_f64(_mm_sqrt_sd(_mm_hadd_pd(zt, zt))); \ +} + +#define vec2d_distance_squared(x, y, z) \ +{ \ + __m128d zt; \ + zt = _mm_sub_pd((x).data, (y).data); \ + zt = _mm_mul_pd(zt, zt); \ + (z) = _mm_cvtsd_f64(_mm_hadd_pd(zt, zt)); \ +} + +#define vec2d_lerp(x, y, z, blend) \ +{ \ + (z).data = _mm_add_pd((x).data, _mm_mul_pd(_mm_sub_pd((y).data, (z).data), (blend).data)); \ +} + +#define vec2d_lerp_scalar(x, y, z, blend) \ +{ \ + __m128d b; \ + b = _mm_set_sd(blend); \ + b = _mm_shuffle_pd(b, b, 0); \ + (z).data = _mm_add_pd((x).data, _mm_mul_pd(_mm_sub_pd((y).data, (z).data), b)); \ +} + +#define vec2d_normalize(x, z) \ +{ \ + __m128d zt; \ + zt = _mm_mul_pd((x).data, (x).data); \ + zt = _mm_sqrt_sd(_mm_hadd_pd(zt, zt)); \ + if (zt.m128d_f64[0] != 0.0) \ + zt.m128d_f64[0] = 1.0 / zt.m128d_f64[0]; \ + (z).data = _mm_mul_pd((x).data, _mm_shuffle_pd(zt, zt, 0)); \ +} + +#define vec2d_rcp(x, z) \ +{ \ + (z).data = _mm_div_pd(vec2d_identity.data, (x).data); \ +} + +#define vec2d_min(x, y, z) \ +{ \ + (z).data = _mm_min_pd((x).data, (y).data); \ +} + +#define vec2d_max(x, y, z) \ +{ \ + (z).data = _mm_max_pd((x).data, (y).data); \ +} + +#define vec2d_clamp(x, y, z, w) \ +{ \ + (w).data = _mm_min_pd(_mm_max_pd((x).data, (y).data), (z).data); \ +} + +#define vec2d_clamp_scalar(x, y, z, w) \ +{ \ + __m128d yt; \ + __m128d zt; \ + __m128d wt; \ + yt = _mm_set_sd(y); \ + zt = _mm_set_sd(z); \ + wt = _mm_min_pd(_mm_max_pd((x).data, _mm_shuffle_pd(yt, yt, 0)), _mm_shuffle_pd(zt, zt, 0)); \ + (w) = *(vec2d*)&wt; \ +} + +#define vec2d_mult_min_max(x, y, z, w) \ +{ \ + __m128d yt; \ + __m128d zt; \ + __m128d wt; \ + yt = (y).data; \ + zt = (z).data; \ + yt = _mm_xor_pd(yt, vec2d_negate); \ + wt = _mm_or_pd(_mm_and_pd(yt, _mm_cmplt_pd((x).data, vec2d_null.data)), \ + _mm_and_pd(zt, _mm_cmpgt_pd((x).data, vec2d_null.data))); \ + (w).data = _mm_mul_pd((x).data, wt); \ +} + +#define vec2d_mult_min_max_scalar(x, y, z, w) \ +{ \ + __m128d yt; \ + __m128d zt; \ + __m128d wt; \ + yt = _mm_set_sd(y); \ + yt = _mm_shuffle_pd(yt, yt, 0); \ + zt = _mm_set_sd(z); \ + zt = _mm_shuffle_pd(zt, zt, 0); \ + yt = _mm_xor_pd(yt, vec2d_negate); \ + wt = _mm_or_pd(_mm_and_pd(yt, _mm_cmplt_pd((x).data, vec2d_null.data)), \ + _mm_and_pd(zt, _mm_cmpgt_pd((x).data, vec2d_null.data))); \ + (w).data = _mm_mul_pd((x).data, wt); \ } diff --git a/src/KKdLib/vector.c b/src/KKdLib/vector.c index 039c979c..98c0205f 100644 --- a/src/KKdLib/vector.c +++ b/src/KKdLib/vector.c @@ -18,6 +18,9 @@ vector_func(int64_t) vector_func(uint64_t) vector_func(size_t) vector_func(ssize_t) +vector_func(half_t) +vector_func(float_t) +vector_func(double_t) vector_ptr_func(char) vector_ptr_func(wchar_t) vector_ptr_func(bool) @@ -31,3 +34,7 @@ vector_ptr_func(int64_t) vector_ptr_func(uint64_t) vector_ptr_func(size_t) vector_ptr_func(ssize_t) +vector_ptr_func(half_t) +vector_ptr_func(float_t) +vector_ptr_func(double_t) +vector_ptr_func(void) diff --git a/src/KKdLib/vector.h b/src/KKdLib/vector.h index 541f3fce..fb3b7c86 100644 --- a/src/KKdLib/vector.h +++ b/src/KKdLib/vector.h @@ -6,6 +6,9 @@ #pragma once #include "default.h" +#include "half_t.h" + +#define vector_dispose_func(t) void(FASTCALL* dispose_func)(t* data) #define vector(t) \ typedef struct vector_##t { \ @@ -14,10 +17,14 @@ typedef struct vector_##t { \ t* capacity_end; \ } vector_##t; \ \ -extern void FASTCALL vector_##t##_push_back(vector_##t* vec, t* element); \ -extern void FASTCALL vector_##t##_append(vector_##t* vec, uint64_t size); \ -extern void FASTCALL vector_##t##_resize(vector_##t* vec, uint64_t size); \ -extern void FASTCALL vector_##t##_erase(vector_##t* vec, uint64_t index); \ +extern void FASTCALL vector_##t##_append(vector_##t* vec, ssize_t count); \ +extern void FASTCALL vector_##t##_push_back(vector_##t* vec, t* val); \ +extern void FASTCALL vector_##t##_pop_back(vector_##t* vec); \ +extern void FASTCALL vector_##t##_insert(vector_##t* vec, ssize_t position, t* val); \ +extern void FASTCALL vector_##t##_insert_range(vector_##t* vec, ssize_t position, t* first, t* last); \ +extern void FASTCALL vector_##t##_erase(vector_##t* vec, ssize_t position); \ +extern void FASTCALL vector_##t##_erase_range(vector_##t* vec, ssize_t first, ssize_t last); \ +extern void FASTCALL vector_##t##_swap(vector_##t* vec1, vector_##t* vec2); \ extern void FASTCALL vector_##t##_clear(vector_##t* vec); \ extern void FASTCALL vector_##t##_free(vector_##t* vec); @@ -28,80 +35,104 @@ typedef struct vector_ptr_##t { \ t** capacity_end; \ } vector_ptr_##t; \ \ -extern void FASTCALL vector_ptr_##t##_push_back(vector_ptr_##t* vec, t** element); \ -extern void FASTCALL vector_ptr_##t##_append(vector_ptr_##t* vec, uint64_t size); \ -extern void FASTCALL vector_ptr_##t##_resize(vector_ptr_##t* vec, uint64_t size); \ -extern void FASTCALL vector_ptr_##t##_erase(vector_ptr_##t* vec, uint64_t index); \ -extern void FASTCALL vector_ptr_##t##_clear(vector_ptr_##t* vec, \ - void* FASTCALL dispose_func(void* data)); \ -extern void FASTCALL vector_ptr_##t##_free(vector_ptr_##t* vec, \ - void* FASTCALL dispose_func(void* data)); +extern void FASTCALL vector_ptr_##t##_append(vector_ptr_##t* vec, ssize_t count); \ +extern void FASTCALL vector_ptr_##t##_push_back(vector_ptr_##t* vec, t** val); \ +extern void FASTCALL vector_ptr_##t##_pop_back(vector_ptr_##t* vec, vector_dispose_func(t)); \ +extern void FASTCALL vector_ptr_##t##_insert(vector_ptr_##t* vec, ssize_t position, t** val); \ +extern void FASTCALL vector_ptr_##t##_insert_range(vector_ptr_##t* vec, ssize_t position, t** first, t** last); \ +extern void FASTCALL vector_ptr_##t##_erase(vector_ptr_##t* vec, \ + ssize_t position, vector_dispose_func(t)); \ +extern void FASTCALL vector_ptr_##t##_erase_range(vector_ptr_##t* vec, \ + ssize_t first, ssize_t last, vector_dispose_func(t)); \ +extern void FASTCALL vector_ptr_##t##_swap(vector_ptr_##t* vec1, vector_ptr_##t* vec2); \ +extern void FASTCALL vector_ptr_##t##_clear(vector_ptr_##t* vec, vector_dispose_func(t)); \ +extern void FASTCALL vector_ptr_##t##_free(vector_ptr_##t* vec, vector_dispose_func(t)); #define vector_func(t) \ -void FASTCALL vector_##t##_push_back(vector_##t* vec, t* element) { \ - int64_t old_length; \ +void FASTCALL vector_##t##_push_back(vector_##t* vec, t* val) { \ + if (!vec || !val) \ + return; \ \ - if (element >= vec->end || vec->begin > element) { \ - if (vec->end == vec->capacity_end) \ - vector_##t##_append(vec, 1); \ + if (vec->capacity_end - vec->end < 1) \ + vector_##t##_append(vec, 1); \ \ - if (vec->end) \ - *vec->end = *element; \ - } \ - else { \ - old_length = element - vec->begin; \ - if (vec->end == vec->capacity_end) \ - vector_##t##_append(vec, 1); \ -\ - if (vec->end) \ - *vec->end = vec->begin[old_length]; \ - } \ + *vec->end = *val; \ vec->end++; \ } \ \ -void FASTCALL vector_##t##_append(vector_##t* vec, uint64_t size) { \ - int64_t length; \ - uint64_t capacity; \ - uint64_t temp_length; \ -\ - if (vec->capacity_end - vec->end < (int64_t)size) { \ - length = vec->end - vec->begin; \ - capacity = vec->capacity_end - vec->begin; \ - if (UINT64_MAX / sizeof(t) - (capacity >> 1) >= capacity) \ - temp_length = (capacity >> 1) + capacity; \ - else \ - temp_length = 0; \ -\ - if (temp_length < length + size) \ - temp_length = length + size; \ - vector_##t##_resize(vec, temp_length); \ - } \ -} \ -\ -void FASTCALL vector_##t##_resize(vector_##t* vec, uint64_t size) { \ - t* temp; \ - int64_t length; \ -\ - temp = 0; \ - if (size) \ - temp = force_malloc_s(sizeof(t), size); \ -\ - if (!temp) \ +void FASTCALL vector_##t##_pop_back(vector_##t* vec) { \ + if (!vec) \ return; \ \ - memmove(temp, vec->begin, sizeof(t) * (vec->end - vec->begin)); \ - length = vec->end - vec->begin; \ - free(vec->begin); \ - vec->capacity_end = &temp[size]; \ - vec->end = &temp[length]; \ - vec->begin = temp; \ + if (vec->end - vec->begin > 0) \ + vec->end--; \ } \ \ -void FASTCALL vector_##t##_erase(vector_##t* vec, uint64_t index) { \ - memmove(&vec->begin[index], &vec->begin[index + 1], sizeof(t*) * (vec->end - &vec->begin[index + 1])); \ +void FASTCALL vector_##t##_insert(vector_##t* vec, ssize_t position, t* val) { \ + if (!vec || !val || vec->end - vec->begin < position) \ + return; \ +\ + if (vec->capacity_end - vec->end < 1) \ + vector_##t##_append(vec, 1); \ +\ + t* t0 = vec->begin + position; \ + t* t1 = vec->begin + position + 1; \ + memmove(t1, t0, sizeof(t) * (vec->end - t0)); \ + *t0 = *val; \ + vec->end++; \ +} \ +\ +void FASTCALL vector_##t##_insert_range(vector_##t* vec, ssize_t position, t* first, t* last) { \ + if (!vec || !first || !last || vec->end - vec->begin < position) \ + return; \ +\ + ssize_t s = last - first; \ + if (s < 1) \ + return; \ +\ + if (vec->capacity_end - vec->end < s) \ + vector_##t##_append(vec, s); \ + \ + t* t0 = vec->begin + position; \ + t* t1 = vec->begin + position + s; \ + memmove(t1, t0, sizeof(t) * (vec->end - t0)); \ + memmove(t0, first, sizeof(t) * s); \ + vec->end += s; \ +} \ +\ +void FASTCALL vector_##t##_erase(vector_##t* vec, ssize_t position) { \ + if (!vec || vec->end - vec->begin <= position) \ + return; \ +\ + t* t0 = vec->begin + position; \ + t* t1 = vec->begin + position + 1; \ + memmove(t0, t1, sizeof(t) * (vec->end - t1)); \ vec->end--; \ } \ \ +void FASTCALL vector_##t##_erase_range(vector_##t* vec, ssize_t first, ssize_t last) { \ + if (!vec || !last || last - first < 1) \ + return; \ +\ + ssize_t s = min(last - first, (ssize_t)(vec->end - vec->begin)); \ + if (s < 1) \ + return; \ + \ + t* t0 = vec->begin + s; \ + t* t1 = vec->begin + s + 1; \ + memmove(t0, t1, sizeof(t) * (vec->end - t1)); \ + vec->end -= s; \ +} \ +\ +void FASTCALL vector_##t##_swap(vector_##t* vec1, vector_##t* vec2) { \ + if (!vec1 || !vec2) \ + return; \ +\ + vector_##t vec = *vec1; \ + *vec1 = *vec2; \ + *vec2 = vec; \ +} \ +\ void FASTCALL vector_##t##_clear(vector_##t* vec) { \ vec->end = vec->begin; \ } \ @@ -111,56 +142,195 @@ void FASTCALL vector_##t##_free(vector_##t* vec) { \ vec->begin = 0; \ vec->end = 0; \ vec->capacity_end = 0; \ +} \ +\ +void FASTCALL vector_##t##_append(vector_##t* vec, ssize_t count) { \ + if (vec->capacity_end - vec->end >= count) \ + return; \ +\ + ssize_t length = vec->end - vec->begin; \ + ssize_t capacity = vec->capacity_end - vec->begin; \ + ssize_t _count; \ + if ((ssize_t)(INT64_MAX / sizeof(t) - (capacity >> 1)) >= capacity) \ + _count = (capacity >> 1) + capacity; \ + else \ + _count = 0; \ + count = max(_count, length + count); \ +\ + t* temp = 0; \ + if (count) \ + temp = force_malloc_s(t, count); \ +\ + if (!temp) \ + return; \ +\ + memmove(temp, vec->begin, sizeof(t) * (vec->end - vec->begin)); \ + length = vec->end - vec->begin; \ + free(vec->begin); \ + vec->capacity_end = &temp[count]; \ + vec->end = &temp[length]; \ + vec->begin = temp; \ } #define vector_ptr_func(t) \ -void FASTCALL vector_ptr_##t##_push_back(vector_ptr_##t* vec, t** element) { \ - int64_t old_length; \ +void FASTCALL vector_ptr_##t##_push_back(vector_ptr_##t* vec, t** val) { \ + if (!vec || !val) \ + return; \ \ - if (element >= vec->end || vec->begin > element) { \ - if (vec->end == vec->capacity_end) \ - vector_ptr_##t##_append(vec, 1); \ + if (vec->capacity_end - vec->end < 1) \ + vector_ptr_##t##_append(vec, 1); \ \ - if (vec->end) \ - *vec->end = *element; \ + *vec->end++ = *val; \ +} \ +\ +void FASTCALL vector_ptr_##t##_pop_back(vector_ptr_##t* vec, vector_dispose_func(t)) { \ + if (!vec) \ + return; \ +\ + if (vec->end - vec->begin > 0) { \ + if (dispose_func) \ + dispose_func(vec->end[1]); \ + else \ + free(vec->end[-1]); \ + vec->end--; \ } \ - else { \ - old_length = element - vec->begin; \ - if (vec->end == vec->capacity_end) \ - vector_ptr_##t##_append(vec, 1); \ +} \ \ - if (vec->end) \ - *vec->end = vec->begin[old_length]; \ - } \ +void FASTCALL vector_ptr_##t##_insert(vector_ptr_##t* vec, ssize_t position, t** val) { \ + if (!vec || !val || vec->end - vec->begin < position) \ + return; \ +\ + if (vec->capacity_end - vec->end < 1) \ + vector_ptr_##t##_append(vec, 1); \ +\ + t** t0 = vec->begin + position; \ + t** t1 = vec->begin + position + 1; \ + memmove(t1, t0, sizeof(t*) * (vec->end - t0)); \ + *t0 = *val; \ vec->end++; \ } \ \ -void FASTCALL vector_ptr_##t##_append(vector_ptr_##t* vec, uint64_t size) { \ - int64_t length; \ - uint64_t capacity; \ - uint64_t temp_length; \ +void FASTCALL vector_ptr_##t##_insert_range(vector_ptr_##t* vec, ssize_t position, t** first, t** last) { \ + if (!vec || !first || !last || vec->end - vec->begin < position) \ + return; \ \ - if (vec->capacity_end - vec->end < (int64_t)size) { \ - length = vec->end - vec->begin; \ - capacity = vec->capacity_end - vec->begin; \ - if (UINT64_MAX / sizeof(t*) - (capacity >> 1) >= capacity) \ - temp_length = (capacity >> 1) + capacity; \ - else \ - temp_length = 0; \ + ssize_t s = last - first; \ + if (s < 1) \ + return; \ \ - if (temp_length < length + size) \ - temp_length = length + size; \ - vector_ptr_##t##_resize(vec, temp_length); \ - } \ + if (vec->capacity_end - vec->end < s) \ + vector_ptr_##t##_append(vec, s); \ + \ + t** t0 = vec->begin + position; \ + t** t1 = vec->begin + position + s; \ + memmove(t1, t0, sizeof(t*) * (vec->end - t0)); \ + memmove(t0, first, sizeof(t*) * s); \ + vec->end += s; \ } \ \ -void FASTCALL vector_ptr_##t##_resize(vector_ptr_##t* vec, uint64_t size) { \ - t** temp; \ - int64_t length; \ +void FASTCALL vector_ptr_##t##_erase(vector_ptr_##t* vec, \ + ssize_t position, vector_dispose_func(t)) { \ + if (!vec || vec->end - vec->begin <= position) \ + return; \ \ - temp = 0; \ - if (size) \ - temp = force_malloc_s(sizeof(t*), size); \ + t** t0 = vec->begin + position; \ + t** t1 = vec->begin + position + 1; \ + if (*t0) \ + if (dispose_func) \ + dispose_func(*t0); \ + else \ + free(*t0); \ +\ + memmove(t0, t1, sizeof(t*) * (vec->end - t1)); \ + vec->end--; \ +} \ +\ +void FASTCALL vector_ptr_##t##_erase_range(vector_ptr_##t* vec, \ + ssize_t first, ssize_t last, vector_dispose_func(t)) { \ + if (!vec || !last || last - first < 1) \ + return; \ +\ + ssize_t s = min(last - first, (ssize_t)(vec->end - vec->begin)); \ + if (s < 1) \ + return; \ + \ + t** t0 = vec->begin + first; \ + t** t1 = vec->begin + first + s; \ + if (dispose_func) \ + for (ssize_t i = 0; i < s; i++) \ + if (t0[i]) { \ + dispose_func(t0[i]); \ + t0[i] = 0; \ + } \ + else \ + for (ssize_t i = 0; i < s; i++) \ + free(t0[i]); \ +\ + memmove(t0, t1, sizeof(t*) * (vec->end - t1)); \ + vec->end -= s; \ +} \ +\ +void FASTCALL vector_ptr_##t##_swap(vector_ptr_##t* vec1, vector_ptr_##t* vec2) { \ + if (!vec1 || !vec2) \ + return; \ +\ + vector_ptr_##t vec = *vec1; \ + *vec1 = *vec2; \ + *vec2 = vec; \ +} \ +\ +void FASTCALL vector_ptr_##t##_clear(vector_ptr_##t* vec, vector_dispose_func(t)) { \ + if (!vec) \ + return; \ +\ + if (dispose_func) \ + for (t** i = vec->begin; i != vec->end; i++) \ + if (*i) { \ + dispose_func(*i); \ + *i = 0; \ + } \ + else \ + for (t** i = vec->begin; i != vec->end; i++) \ + free(*i); \ + vec->end = vec->begin; \ +} \ +\ +void FASTCALL vector_ptr_##t##_free(vector_ptr_##t* vec, vector_dispose_func(t)) { \ + if (!vec) \ + return; \ +\ + if (dispose_func) \ + for (t** i = vec->begin; i != vec->end; i++) \ + if (*i) { \ + dispose_func(*i); \ + *i = 0; \ + } \ + else \ + for (t** i = vec->begin; i != vec->end; i++) \ + free(*i); \ +\ + free(vec->begin); \ + vec->begin = 0; \ + vec->end = 0; \ + vec->capacity_end = 0; \ +} \ +\ +void FASTCALL vector_ptr_##t##_append(vector_ptr_##t* vec, ssize_t count) { \ + if (vec->capacity_end - vec->end >= count) \ + return; \ +\ + ssize_t length = vec->end - vec->begin; \ + ssize_t capacity = vec->capacity_end - vec->begin; \ + ssize_t _count; \ + if ((ssize_t)(INT64_MAX / sizeof(t*) - (capacity >> 1)) >= capacity) \ + _count = (capacity >> 1) + capacity; \ + else \ + _count = 0; \ + count = max(_count, length + count); \ +\ + t** temp = 0; \ + if (count) \ + temp = force_malloc_s(t*, count); \ \ if (!temp) \ return; \ @@ -168,50 +338,9 @@ void FASTCALL vector_ptr_##t##_resize(vector_ptr_##t* vec, uint64_t size) { \ memmove(temp, vec->begin, sizeof(t*) * (vec->end - vec->begin)); \ length = vec->end - vec->begin; \ free(vec->begin); \ - vec->capacity_end = &temp[size]; \ + vec->capacity_end = &temp[count]; \ vec->end = &temp[length]; \ vec->begin = temp; \ -} \ -\ -void FASTCALL vector_ptr_##t##_erase(vector_ptr_##t* vec, uint64_t index) { \ - memmove(&vec->begin[index], &vec->begin[index + 1], sizeof(t**) * (vec->end - &vec->begin[index + 1])); \ - vec->end--; \ -} \ -\ -void FASTCALL vector_ptr_##t##_clear(vector_ptr_##t* vec, \ - void* FASTCALL dispose_func(void* data)) { \ - t** i; \ -\ - if (dispose_func) \ - for (i = vec->begin; i != vec->end; i++) \ - if (*i) { \ - dispose_func(*i); \ - *i = 0; \ - } \ - else \ - for (i = vec->begin; i != vec->end; i++) \ - free(*i); \ - vec->end = vec->begin; \ -} \ -\ -void FASTCALL vector_ptr_##t##_free(vector_ptr_##t* vec, \ - void* FASTCALL dispose_func(void* data)) { \ - t** i; \ -\ - if (dispose_func) \ - for (i = vec->begin; i != vec->end; i++) \ - if (*i) { \ - dispose_func(*i); \ - *i = 0; \ - } \ - else \ - for (i = vec->begin; i != vec->end; i++) \ - free(*i); \ -\ - free(vec->begin); \ - vec->begin = 0; \ - vec->end = 0; \ - vec->capacity_end = 0; \ } vector(char) @@ -227,6 +356,9 @@ vector(int64_t) vector(uint64_t) vector(size_t) vector(ssize_t) +vector(half_t) +vector(float_t) +vector(double_t) vector_ptr(char) vector_ptr(wchar_t) vector_ptr(bool) @@ -240,3 +372,7 @@ vector_ptr(int64_t) vector_ptr(uint64_t) vector_ptr(size_t) vector_ptr(ssize_t) +vector_ptr(half_t) +vector_ptr(float_t) +vector_ptr(double_t) +vector_ptr(void) diff --git a/thirdparty.txt b/thirdparty.txt index 4de7cce0..36e3443a 100644 --- a/thirdparty.txt +++ b/thirdparty.txt @@ -129,16 +129,18 @@ MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. ------------------------------------------------------------------------------- -microui +cimgui -Copyright (c) 2020 rxi +The MIT License (MIT) -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: +Copyright (c) 2015 Stephan Dilly + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. @@ -150,3 +152,61 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- + +imgui + +The MIT License (MIT) + +Copyright (c) 2014-2021 Omar Cornut + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- + +MikuWow and MikuShoot icons + +By irarugii +https://twitter.com/irarugii/status/1218673550749511680 + +------------------------------------------------------------------------------- + +DirectXTex (DDS.h) + + The MIT License (MIT) + +Copyright (c) 2011-2021 Microsoft Corp + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file

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