From a15befd8fb7e8b8347b2adeafa08ec2162900606 Mon Sep 17 00:00:00 2001 From: korenkonder Date: Mon, 3 Oct 2022 15:54:28 +0300 Subject: [PATCH] Temp commit. Sound --- extern/lib/libdeflatestatic.lib | Bin 77554 -> 79674 bytes extern/lib/libogg.lib | Bin 0 -> 85994 bytes extern/lib/libogg.pdb | Bin 0 -> 77824 bytes extern/lib/liboggd.lib | Bin 0 -> 96474 bytes extern/lib/liboggd.pdb | Bin 0 -> 77824 bytes extern/lib/libvorbis.lib | Bin 0 -> 3002828 bytes extern/lib/libvorbis.pdb | Bin 0 -> 118784 bytes extern/lib/libvorbisd.lib | Bin 0 -> 1462530 bytes extern/lib/libvorbisd.pdb | Bin 0 -> 118784 bytes extern/lib/libvorbisfile.lib | Bin 0 -> 167196 bytes extern/lib/libvorbisfile.pdb | Bin 0 -> 94208 bytes extern/lib/libvorbisfiled.lib | Bin 0 -> 128880 bytes extern/lib/libvorbisfiled.pdb | Bin 0 -> 94208 bytes extern/src/libdeflate.h | 18 +- extern/src/ogg/ogg.h | 209 + extern/src/ogg/os_types.h | 158 + extern/src/vorbis/codec.h | 242 ++ extern/src/vorbis/vorbisenc.h | 435 ++ extern/src/vorbis/vorbisfile.h | 205 + src/CRE/Glitter/curve.cpp | 12 +- src/CRE/Glitter/effect.cpp | 163 - src/CRE/Glitter/effect_group.cpp | 2 +- src/CRE/Glitter/effect_inst.cpp | 183 +- src/CRE/Glitter/emitter.cpp | 145 - src/CRE/Glitter/file_reader.cpp | 14 +- src/CRE/Glitter/file_writer.cpp | 716 +++- src/CRE/Glitter/glitter.cpp | 2 +- src/CRE/Glitter/glitter.hpp | 40 +- src/CRE/Glitter/locus_history.cpp | 8 +- src/CRE/Glitter/particle.cpp | 192 +- src/CRE/Glitter/particle_inst.cpp | 8 +- src/CRE/Glitter/particle_manager.cpp | 8 +- src/CRE/Glitter/render_element.cpp | 4 +- src/CRE/Glitter/render_group.cpp | 34 +- src/CRE/Glitter/render_scene.cpp | 16 +- src/CRE/Glitter/scene.cpp | 6 +- src/CRE/auth_3d.cpp | 74 +- src/CRE/auth_3d.hpp | 6 +- src/CRE/camera.cpp | 138 +- src/CRE/camera.hpp | 18 +- src/CRE/data.cpp | 401 +- src/CRE/data.hpp | 2 + src/CRE/draw_object.cpp | 73 +- src/CRE/draw_pass.cpp | 39 +- src/CRE/draw_task.cpp | 90 +- src/CRE/fbo.cpp | 2 +- src/CRE/file_handler.cpp | 160 +- src/CRE/item_table.cpp | 20 +- src/CRE/item_table.hpp | 6 + src/CRE/light_param.cpp | 24 +- src/CRE/light_param.hpp | 2 + src/CRE/light_param/fog.cpp | 3 +- src/CRE/light_param/light.cpp | 127 +- src/CRE/light_param/light.hpp | 25 +- src/CRE/light_param/wind.cpp | 2 +- src/CRE/lock.cpp | 14 - src/CRE/lock.hpp | 49 +- src/CRE/object.cpp | 628 ++- src/CRE/ogg_vorbis.cpp | 583 +++ src/CRE/ogg_vorbis.hpp | 150 + src/CRE/post_process.cpp | 42 +- src/CRE/post_process.hpp | 2 +- src/CRE/post_process/aa.cpp | 32 +- src/CRE/post_process/aa.hpp | 2 +- src/CRE/post_process/blur.cpp | 40 +- src/CRE/post_process/dof.cpp | 57 +- src/CRE/post_process/exposure.cpp | 11 +- src/CRE/post_process/exposure.hpp | 2 + src/CRE/post_process/tone_map.cpp | 99 +- src/CRE/post_process/tone_map.hpp | 2 + src/CRE/pv_db.cpp | 4 +- src/CRE/pv_expression.cpp | 3 +- src/CRE/pv_param.cpp | 71 +- src/CRE/random.cpp | 12 +- src/CRE/render_context.cpp | 474 ++- src/CRE/render_context.hpp | 4 +- src/CRE/render_texture.cpp | 8 +- src/CRE/rob/ex_block.cpp | 39 +- src/CRE/rob/rob.cpp | 264 +- src/CRE/rob/rob.hpp | 1 + src/CRE/shader.cpp | 167 +- src/CRE/shader.hpp | 2 +- src/CRE/shader_ft.cpp | 314 +- src/CRE/shader_ft.hpp | 129 +- src/CRE/shader_glsl.cpp | 41 +- src/CRE/sound.cpp | 1775 +++++++++ src/CRE/sound.hpp | 352 ++ src/CRE/stage.cpp | 2 +- src/CRE/stage_modern.cpp | 6 +- src/CRE/static_var.cpp | 2 +- src/CRE/static_var.hpp | 6 +- src/CRE/task.cpp | 8 +- src/CRE/task_effect.cpp | 9 +- src/CRE/task_effect.hpp | 2 - src/CRE/texture.cpp | 141 +- src/CRE/texture.hpp | 6 +- src/CRE/timer.cpp | 125 +- src/CRE/timer.hpp | 21 +- src/CRE/waitable_timer.hpp | 57 + src/DivaGL/DivaGL.vcxproj | 8 +- src/DivaGL/bone_data.cpp | 24 +- src/DivaGL/inject.cpp | 4 +- src/DivaGL/shader_table.cpp | 4 +- src/DivaGL/string.cpp | 20 +- src/DivaGL/vector.hpp | 26 +- src/KKdLib/a3da.cpp | 54 +- src/KKdLib/aes.cpp | 88 +- src/KKdLib/aes.hpp | 66 +- src/KKdLib/aet.cpp | 189 + src/KKdLib/aet.hpp | 386 +- src/KKdLib/database/auth_3d.cpp | 37 +- src/KKdLib/database/bone.cpp | 128 +- src/KKdLib/database/bone.hpp | 1 + src/KKdLib/database/item_table.cpp | 37 +- src/KKdLib/database/motion.cpp | 19 +- src/KKdLib/database/object.cpp | 111 +- src/KKdLib/database/object.hpp | 1 + src/KKdLib/database/sprite.cpp | 765 ++++ src/KKdLib/database/sprite.hpp | 96 + src/KKdLib/database/stage.cpp | 73 +- src/KKdLib/database/stage.hpp | 1 + src/KKdLib/database/texture.cpp | 133 +- src/KKdLib/database/texture.hpp | 1 + src/KKdLib/dds.cpp | 30 +- src/KKdLib/default.cpp | 297 -- src/KKdLib/default.hpp | 366 +- src/KKdLib/deflate.cpp | 44 +- src/KKdLib/deflate.hpp | 2 + src/KKdLib/divafile.cpp | 53 +- src/KKdLib/divafile.hpp | 4 +- src/KKdLib/dsc.cpp | 1638 ++++---- src/KKdLib/dsc.hpp | 3 +- src/KKdLib/enbaya.cpp | 32 +- src/KKdLib/f2/header.cpp | 32 +- src/KKdLib/f2/struct.cpp | 65 +- src/KKdLib/farc.cpp | 454 +-- src/KKdLib/farc.hpp | 15 +- src/KKdLib/half_t.cpp | 12 - src/KKdLib/half_t.hpp | 15 +- src/KKdLib/hash.cpp | 101 +- src/KKdLib/hash.hpp | 66 +- src/KKdLib/image.cpp | 32 +- src/KKdLib/image.hpp | 2 + src/KKdLib/interpolation.cpp | 236 +- src/KKdLib/interpolation.hpp | 211 +- src/KKdLib/io/file_stream.cpp | 176 + src/KKdLib/io/file_stream.hpp | 39 + src/KKdLib/io/json.cpp | 186 +- src/KKdLib/io/memory_stream.cpp | 255 ++ src/KKdLib/io/memory_stream.hpp | 45 + src/KKdLib/io/msgpack.cpp | 145 +- src/KKdLib/io/path.cpp | 407 +- src/KKdLib/io/path.hpp | 20 +- src/KKdLib/io/stream.cpp | 475 +-- src/KKdLib/io/stream.hpp | 68 +- src/KKdLib/key_val.cpp | 37 +- src/KKdLib/light_param/face.cpp | 35 +- src/KKdLib/light_param/fog.cpp | 35 +- src/KKdLib/light_param/glow.cpp | 35 +- src/KKdLib/light_param/ibl.cpp | 25 +- src/KKdLib/light_param/light.cpp | 77 +- src/KKdLib/light_param/light.hpp | 22 +- src/KKdLib/light_param/wind.cpp | 35 +- src/KKdLib/mat.cpp | 132 +- src/KKdLib/mot.cpp | 292 +- src/KKdLib/mot.hpp | 4 + src/KKdLib/msgpack.cpp | 815 ++-- src/KKdLib/msgpack.hpp | 340 +- src/KKdLib/obj.cpp | 1039 +++-- src/KKdLib/obj.hpp | 1 + src/KKdLib/post_process_table/dof.cpp | 83 +- src/KKdLib/post_process_table/dof.hpp | 1 + src/KKdLib/pv_exp.cpp | 192 +- src/KKdLib/pv_exp.hpp | 1 + src/KKdLib/pvpp.cpp | 31 +- src/KKdLib/pvpp.hpp | 1 + src/KKdLib/pvsr.cpp | 31 +- src/KKdLib/pvsr.hpp | 1 + src/KKdLib/quat.cpp | 54 +- src/KKdLib/quat.hpp | 319 +- src/KKdLib/quat_trans.cpp | 6 +- src/KKdLib/sort.cpp | 63 +- src/KKdLib/sort.hpp | 2 + src/KKdLib/sound/diva.cpp | 367 +- src/KKdLib/sound/diva.hpp | 15 +- src/KKdLib/sound/vag.cpp | 899 +++-- src/KKdLib/sound/vag.hpp | 15 +- src/KKdLib/sound/wav.cpp | 412 +- src/KKdLib/sound/wav.hpp | 15 +- src/KKdLib/str_utils.cpp | 28 +- src/KKdLib/str_utils.hpp | 12 +- src/KKdLib/txp.cpp | 24 +- src/KKdLib/vec.cpp | 6 +- src/KKdLib/vec.hpp | 3524 ++++++++++------- src/MMPlusDec/MMPlusDec.cpp | 23 +- src/ReDIVA/classes.cpp | 69 +- src/ReDIVA/classes.hpp | 2 +- src/ReDIVA/classes/data_view/auth_3d.cpp | 17 +- src/ReDIVA/classes/data_view/draw_task.cpp | 41 +- src/ReDIVA/classes/data_view/glitter.cpp | 25 +- src/ReDIVA/classes/data_view/object.cpp | 25 +- src/ReDIVA/classes/data_view/texture.cpp | 25 +- src/ReDIVA/classes/glitter_editor.cpp | 2264 +++++------ src/ReDIVA/classes/graphics.cpp | 2 +- .../classes/graphics/background_color.cpp | 9 +- src/ReDIVA/classes/graphics/face_light.cpp | 20 +- src/ReDIVA/classes/graphics/fog.cpp | 111 +- src/ReDIVA/classes/graphics/glitter.cpp | 4 +- src/ReDIVA/classes/graphics/light.cpp | 286 +- src/ReDIVA/classes/graphics/light.hpp | 1 + src/ReDIVA/classes/graphics/post_process.cpp | 9 +- .../classes/graphics/render_settings.cpp | 25 +- .../classes/information/frame_speed.cpp | 4 +- src/ReDIVA/data_initialize.cpp | 33 +- src/ReDIVA/data_test/auth_3d_test.cpp | 8 +- src/ReDIVA/data_test/glitter_test.cpp | 12 +- src/ReDIVA/data_test/stage_test.cpp | 6 +- src/ReDIVA/game_state.cpp | 6 +- src/ReDIVA/imgui_helper.cpp | 347 +- src/ReDIVA/imgui_helper.hpp | 22 +- src/ReDIVA/main.cpp | 44 +- src/ReDIVA/main.hpp | 1 - src/ReDIVA/pv_game.cpp | 68 +- src/ReDIVA/render.cpp | 506 ++- src/ReDIVA/render.hpp | 2 +- src/ReDIVA/shared.cpp | 4 - src/ReDIVA/shared.hpp | 17 - src/ReDIVA/sound.cpp | 54 - src/ReDIVA/sound.hpp | 10 - src/ReDIVA/x_pv_game.cpp | 994 +++-- src/ReDIVA/x_pv_game.hpp | 14 +- thirdparty.txt | 68 + 232 files changed, 19396 insertions(+), 12396 deletions(-) create mode 100644 extern/lib/libogg.lib create mode 100644 extern/lib/libogg.pdb create mode 100644 extern/lib/liboggd.lib create mode 100644 extern/lib/liboggd.pdb create mode 100644 extern/lib/libvorbis.lib create mode 100644 extern/lib/libvorbis.pdb create mode 100644 extern/lib/libvorbisd.lib create mode 100644 extern/lib/libvorbisd.pdb create mode 100644 extern/lib/libvorbisfile.lib create mode 100644 extern/lib/libvorbisfile.pdb create mode 100644 extern/lib/libvorbisfiled.lib create mode 100644 extern/lib/libvorbisfiled.pdb create mode 100644 extern/src/ogg/ogg.h create mode 100644 extern/src/ogg/os_types.h create mode 100644 extern/src/vorbis/codec.h create mode 100644 extern/src/vorbis/vorbisenc.h create mode 100644 extern/src/vorbis/vorbisfile.h create mode 100644 src/CRE/ogg_vorbis.cpp create mode 100644 src/CRE/ogg_vorbis.hpp create mode 100644 src/CRE/sound.cpp create mode 100644 src/CRE/sound.hpp create mode 100644 src/CRE/waitable_timer.hpp create mode 100644 src/KKdLib/io/file_stream.cpp create mode 100644 src/KKdLib/io/file_stream.hpp create mode 100644 src/KKdLib/io/memory_stream.cpp create mode 100644 src/KKdLib/io/memory_stream.hpp delete mode 100644 src/ReDIVA/sound.cpp delete mode 100644 src/ReDIVA/sound.hpp diff --git a/extern/lib/libdeflatestatic.lib b/extern/lib/libdeflatestatic.lib index 0cc709c5dd23a5ef94d0dd8fa6016e0364aec26d..d7ccbf5fd670e74a6754602bd9e6c7d9e19c1ac4 100644 GIT binary patch delta 10324 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

}4* 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 HADR9MXl4xH diff --git a/extern/lib/libogg.lib b/extern/lib/libogg.lib new file mode 100644 index 0000000000000000000000000000000000000000..21130191e35c913cd662b1a0f6e4fee4a4a80051 GIT binary patch literal 85994 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 JUjWr6{|~M<52pYC literal 0 HcmV?d00001 diff --git a/extern/lib/libogg.pdb b/extern/lib/libogg.pdb new file mode 100644 index 0000000000000000000000000000000000000000..218f8bf95e4ec11d468eed6e084c2f1fa89fed23 GIT binary patch literal 77824 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 BXMz9# literal 0 HcmV?d00001 diff --git a/extern/lib/liboggd.lib b/extern/lib/liboggd.lib new file mode 100644 index 0000000000000000000000000000000000000000..b4e201f395b91631b056e9e3bcc08ed0a9a9a4cb GIT binary patch literal 96474 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 aKoAfF1OY)n5D)|e0YN|z5ClHm2>dTkgLD!A literal 0 HcmV?d00001 diff --git a/extern/lib/libvorbis.lib b/extern/lib/libvorbis.lib new file mode 100644 index 0000000000000000000000000000000000000000..f62912dcc018ae697e58a2c7937371f5e04faaa9 GIT binary patch literal 3002828 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 z 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%0Dsuk9~cb`8+F0B23JGOJn*GIZMBCZ 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%0Dwpe-fw48E^*T-w0=V{^Ed*gRj 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 z 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

cIvdc*!tP{E~ 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%0A?-N8B7w$&neI+2 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 RI|lz}$LCZUj5Hkge*lpEwsHUf literal 0 HcmV?d00001 diff --git a/extern/lib/libvorbis.pdb b/extern/lib/libvorbis.pdb new file mode 100644 index 0000000000000000000000000000000000000000..7c5cba005abd98603ea1ad5f1f2b165c121041f2 GIT binary patch literal 118784 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%0D?f**2eLwUO^LMRQ5O$a~A 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 z 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%0DKSO78N4*aAVi-5xfzD?g^}2}f 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%0A|?UblR; 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�q+I!lVW_T9k~F=cF#Ey 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 literal 0 HcmV?d00001 diff --git a/extern/lib/libvorbisd.pdb b/extern/lib/libvorbisd.pdb new file mode 100644 index 0000000000000000000000000000000000000000..116f0c825a720284e1900f9f40d2fa20352c3871 GIT binary patch literal 118784 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 literal 0 HcmV?d00001 diff --git a/extern/lib/libvorbisfile.lib b/extern/lib/libvorbisfile.lib new file mode 100644 index 0000000000000000000000000000000000000000..14286a1b781f9b50ba0839c1fe663a33a0225189 GIT binary patch literal 167196 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 $u*Z8Aaj5g~sh3Zm9 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

T6eXOgNN09XMc*KCxMrq}E$Xv0V| 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 B;%xu` literal 0 HcmV?d00001 diff --git a/extern/lib/libvorbisfile.pdb b/extern/lib/libvorbisfile.pdb new file mode 100644 index 0000000000000000000000000000000000000000..7f603bf69055b7fd39cb92398affff77d34f08a4 GIT binary patch literal 94208 zcmeHw37i~Nwf?E9$s|As!x9K#8^acY8D^3gLSzZqNFb0vR$-*+>FJp?^mI4fJy{Si z{E0k3Rtfv6AWx7*M13rZz*AfRSwuuYkwrj6AOWB3dEa;I+^*`Lo&lfl{U1+n{idd> z?mg$+bH97;ty^99oH{s@D&|Z1u5$CVJ*Mrxd-K8bXEyKI(%QQ5h9jrX7i>);9u8Y! zpT}!#!^4C7?+|bZI0PI54grUNL%<>65O4@M1RMem0f)f<5d?mpy?ede90Cpjhk!%C zA>a^j2si{B0uBL(fJ49`;1Kx7MxbfcKX(0G?HmFQ0f&G?z#-rea0oaA90Cpjhk!%C zA>a^Lzy8D5KYX3*`?-hzqJ<0V*9Yc;IPoNY93z9^2C&MHsCkyiNs>BuqZGwaJsq>AN4HlIpn(}_YplPjl-rBHmm9F)eg z8dT;;@irTTvUX&7NDHtJ!d_?;874!T%1B3wG$M_BgK-RXR2dDP?EBGrbtcQnzB(~g z_1RG64phgU-fTJ3v9g>_)QGFjsNgwNWsZ?xvyF!bvJtLDfK(>el?S#=+Zbs>q^HBC zv3y^|A7*GtPxp>QJtX_q$D*%wGVKO@Ds7ANk*Z4od|?aovdL6>X+GPTF3MWk3vA5a zELQfAe(a?Y?M4Y~qaBSbkuAW-vWDZxHrf(24WQW+*G*wY|+~ z=e;VMHbF}qsdU>^==>(iBG2|Hhbqv9j>QR&_3fxpwpTejROEO~#`e_KY4<}7W}dM< z_JL85Ke$GI|78r8owSUdwG6A@C|rL^_xgA=%C5>gT6t~%u)Ov82FV!Z+gHh ztj{+{_ENsd%E$4n04(fywzsBRdDNSBwh#8cx(||lkxm=kPx*LmWWY{rJ!s?mW3Ol9 zQJ(PnZHak8qRXXO8j+@Opx+23fdA84FnQq2Kzsa1#jx1&zYl(rm7Z_>2 zJ=N1^e19b#8D5E<_AfqHE#= z(RsnRGfg`4NMBzj$6Cs?c5}AsHM#B_ZEkn>qI|ILh3x&P~r9P)@$P zJ5gGhOC?I>WI2>mon+*UtETrR| zsXt#e3YUxNWKV4^Vu?mpeSR&pvs8%j*CrbNi38!#f%)k%@miRK0r>LE5}5jDJCdnm z!fAgz!SLPTh4bHV&dIrRDc@U6rRB|V4$L|J5Gke8$0R#o1!i8nxv{Z)S63-rwscGz zA?aMF&YjN#p3Rb9Y4a&(iexi6D8jk*=IAT4B$QE79;VF`>QJ4|3FH#!P|PH=xqQTb zloV1u*>tYEytHJ?IUnUNm1P-weIc$3vMgn|&02lAX+$z$EZboQ}xq$5)<7Xf^fc9E2lJ%uol7+eJ1t`by8vA!7BBm8BZ z_WBZBU*s?Au-BL3dUOyqDEsY}7(6dSy4_|4)t$7zerxY_Y~M zuEa5%|NBi>#m-4@)7joUxA%jqaZT(v9`c^ZG5#8)QQp^MGDt_h({+4nHnip$&e)pT zUpZe)cBj=&m^M_pGTCg@4ozsga&Ix0?u^p5klq|eo_N{_S&BAJ7x}1Y?T+%cm5zMp z$}p9<;+ew#26VFOe03O(0u6CNgOiY+)nZ zHy`rkzMDL`{}Eq)^d(>Bz7xpat5NUAJQ@01JR4mc$n>oPS-n#rm+mU^QnxR!!B}VB z=*h2F1ajODMUu^)EItCyY^MhDonjytK8kxBenNQa8j)m`wT`F?e=^~dOi2Kt0zHE~AWv~4_d3i)2zZm1m;|KZjml=2-9fo`1 zd|w{#38e5+AU`U2G6Dv1+({x6r-;0Kx+l{Y2XfCbf!w_+kkcoKJbJS)m*ZEE>%Zd5 zf@kq89eA?mBFO$(Ap5-U%Ns8Qa_G~6Jo-nGx1Iy-8c$}u0X!b?q;&^RuDd3Xk@v#l zyg+XJiO4ti2xQOQJh|n5;PMMk4*85P!_UE8Z=5fMTYS0wn~-y1AYXjJlfV2VkY8p* z-n-V5EjAFj;c}5@3ceiV2lBy5o(w-#W`uyzMBGX3t^8HC@qi01% zw)%4MLbS~qkx`fV^5!tK`T~(I==hzTJb7xoFJDJ}N4@RI8RrCY)=xaS;eE6_@*lq$ zHvLy$9$Nu<55X?+3&HHMf&2^FZp3!J+;ylY-#pQi)q{Nb!(Tl);$4*aWsH4j!*A{G zOK#sl?z|9>fcJbCX)U)pDb9s1sXr6)&yPUMLVed&J2lS?-CWa<%tBu8UT ze1k79ALYw(lr!UHJeN%tSu`$?LA$`V&huoC*I*;tqX~xia`Jw_Ma^~+%ge-!!oNZ7~xKwdi3m**3KWKKqXj}PSeE76AN zH#eXjN0deGoEpd`$9QtkZJr$Y@36m{0-1bKAisOam)%kS%Qi&+y&#aUUg67Ez9Vv9 zmoGbRiarHQnsb4ydoGY?G9o{@(3ds@`1sS~p8N#;aMc%l`TfCxd^7LKy&LN?o=s~Cjd^X0>( zA~*H=(ty5w!4i>cPx0l+H+}gYY;ix&lf8$EJT@79b~VOW@Grr6TU#LCm=F8h6n$)h zCr1PKv!L4p$ZNa=AlKa{(usa@B7Q_1 z{+7sIdGJs5yh^dB(%Q?F1V;1Y`4t%RTuie-JwaHZvLh%ZE*U*_Rhahz#CE zpj^46 z5O4@M1RMemf&X>{*0i*FcfH?|!n9M?oqzlzuWo$X^wWlZaQemXy)O6-LH5Wcd+a^j2si{B0uBL(fJ49`@JU2q2$Y(G z{UGcOcqhf}jU7a`#__U7tVO|VG`uRqDtWxy#ZG#>-o?5Iu3_McIa^j2si{B0uBL(fJ49`;1Kv^B7jGHw>bnH0uBL(fJ49`;1F;KI0PI54grUN zL%<>M4~{@Aw8<34Lt(rFxE5oJ;vHNMzf8tBu(5R*H-T{|NEgw=FBx=X^ZcgD zc^Kn{@e(2)Prju*wf(9%Q1oEP?zs&Ip0&- z!>ZyngfSItoC@*`(KrhU#OJW-jP1~5;w*$Q8b~+7TpOyj)EzFk{%t73ZeiSo{&Wv9 z`AU_p@I_Z$?^IoFy+}vgBm8{%fzsZkw6={%OAIVMk6f*Bx61WFK^9o;B_i8#%9#FammCn|O zShJj3n|nyc#pp)WQ1i!B#;=s_4z-Q2A1p)2$xJ>Mi`~&6 zsinzWE}bn!b}&SWj1FXCeo)t;jGw}!L~o&h0Emp2!gSb=rswiKnOrifa+$Y9B`=#_ z9^-+HDbMmut~0;f+9R=TmQ=nojo?Ix9#ViT#v#HQ9sk#;i`_vLwtkYzxLIYL@O|GS`c+swSf%d$gsu zrD|*++UKWjo+&wsFVt$&3kVm4kV;mk2{yf=Rmk&4;4w+ZS8L0}Z-Ez%!(q)LyIJC; z6ZwSN80gx)j>4LSc)_%h*VQwrWHKJp%BI~V*D%c`>#Mp zyRGm{?3`Grtjc|;6id|mXBg{`ZBE;Y+s3Q7rXBqmN7_UEm|@}V%>WtQ?RZ(a-@UH< z_P)Tf-oPF&Yb~x>);gsvR^9Kkp<-ZscQnvqTuP zelRuvE$Cpk(IyU&mS4Ai;aF5%AH=KB`utVvWBWVDa*kWo^ntvi^zSOY#ftQnmUaU5 zJV2X(eP`ku?Q!1EogEEK2;-75}{wBsdvtt*o zNAMbBitXE!1G_^^G&^WTW5-S=UE`mr4APG_>6L-Wj0a5rv=oZz^a|X%3;8VX=-Nk^ z*D7fQUCSoBRSt2(7`NEc@OqLgu8ejL^&{q&=Gh!=NkZyLeB zqOod;bZ2|h2}}mUv5;+fl$0|)HEBzwE1S<3LqgS`v<1W%D}|}1zMMa-5C+%7Em)(* zas1l?oni~%Y`0bR9{e%l|It=1sbec!LSAHJh?RqD(vHB<+6QTPUO%2A#zhVr2?QAL z!sJNDj#!czAM1~)h#{CyB`|Bt}itpVD1*SFKPC!u`jmSlz!}ER*ikIpUsmf_8!}I3FCp| zwvYKk#g1vCM}_I-d?A{zc7|yN7^@>`mr6NbPG&LL3u(7QIkcl>jCVziU6Swk8oOlL zsycSb^wo9j@>DUw-Z?>D%b1b~Ht%n5+5`;P&apN*Kuk&68|8D3Z)2G@Lx#1tPgTyt zdk!%qPdEqk5GyOR(Vc4Os%_bmU6gKDrHkx5dY0R*PTphaC$zoYD|zAEf%5G=igv+! z)L5jEwnb@qP8(%i;$w0v(xUPaM@#v}RcNF7+2_m&nrH8+9`qt^EIX1F$V8R3r_xgg z#&isIuyf!D>&Z&DNar3`fmUccor$jAT*{1-{Cyyd&l#nC7JPVC$mUDwFj4yq+iQfB z)7fm8OuOLo!rn-?8=kj6GG?g7i}P^qrp?h`i1WUX#d__BV`wL#ZE%hiVd2UCN;kDa z=QmMr^4Qqf?1Q}b?t`6p601nYAeo^uW-6c6i}c({%eJ6ivy^srg*F&oKo0eXy&}GD z7!RNH@iL?G8f1>jI9O%a=V9_hbe_yrx_OndLc8R>x!NXtIZSEi*U(ajTH1w5yQo5I z`=>89Z%Hg~e^woJw|R%h@;Ele^V(y1VV{Zm?~$5k?c2_W>|869706MbW7{Vyvch_E zT&S%}N@+Wl*5Xgu?7O6|=4p^F<>^))i$7};;V+U=x}%kjdBi?m->l}@ayb^z#<s4P#Gsf^`H7oUUjdEeqvIU=n9 zTB|elr-#u>m2;fRfzC}+kYj(RI$qOR_6ayAHnvSp)I8e{*(PSLige;++a<(jkgP%) z+x;Zv+Xa1zeomyd^c8)P&hofN^&TQ8?a7 zh!(LbmG<;HvPt`8q(}6DoT2n**3h$`)7EYMdF1GEw&4$Lo#PI5h~)WluF4PlNqA3V ze%L>wYd+st8@1m7psfDdoif7q9xNB23~S5e;eE_tt~MIdHONIVT}fA~>m@Ncv?-2{ z-0c|0bM}eLKsQS7OQeIA<)Y5*IL8?xIXnf3`8~}?rLI7l-I^pef2=c~>`=L(&Y1M^ z(OPA*P7RDRjaj^%XYuzRJb#DtTD{jX4bMFlohWOBM9(*zBf}@pzbdAe`K>uNA?|OE z9N`|0^|oH_=n!xSI0PI54grV2KL-LX{=bX=@8bXC8OFu`ck%yS{C^k!|DWTw?`r7~ za0oaA90CpjhrmBE0vr9j&6~vf<6X+tc$e@1zTJmaZR_z~9sk2OWM|-A1b2{_n1CeL zZ^7c#NPJ6V@_3D5-aCY+SX~o-W0lPMKE3H!u-Nx_zNYir^jINMEAPMbZTbe4Y2W|Z z_dfyB2Vv*?sObIHAZbJz-`x#XKAsyH4W88h9%>@4m-*Numm~E_MeQkTLzO#F9eaAS zBP&!e_n`JlQ$5!j+Xq`;E0Uy@Sv@Om@R=rP4%)`p#^wNA5U#pb0`kh~Yvsl?f zq`tj0;{7YNV;k*=w&J!0_*m9(9BD`PUE!vvCFJ82m^YZ+F*QMmq;?)C9#lwFl~wDQ{iVR`HG4U#d+x4ZJ$ciZ*p0~xFI zElO|OisjVjX^>XsX;U6sFN=je_U*roGG2KnD6cJ#W%XCyMCI92c`O#BCyw>`2FYH^ zH(B|(E}>woC>-bZ)^sb6dehGMUcImGgJfT%(?<7GKAsyH=ufsDwDJA1*R%1d%0Er{ z)t?^EAjpYQI1sJg!0<@u$=ztlT@A#<%wg~S3i8~RO!=7&$bTKM$A35 zW_(_%bj%|iH#>G8U6J9LJUa)-GF|T_<{WlpG2>WE49va2Nb@C+G-In3d43beX4;>v z53k8v#7EoYh1F0Y~Gx)}EbG53D%xYSE^H^n`T#puYkL3FDC8a$@X>Iv-4OZB0(K^o4luqY-qo8JN zOC);Q#!c!BCw<{L<_NPpCsE+osdcW(n5o7c#VNvghFr?@oc|H3tO1zDD|dQi_5#&@M!f9ki&tgT+Dh8os`6Y15W z{x9$n4Rwfo4o2p#tejZ!mdE_#r+ig}*-AViFxAtDgcIOzw-Hu;8=PJ7^ zAeVjPN*u%azu$CK?40yAo$bwYdq21u*TjzFChyr$Q?5Z8<$XOSgLLFOUB@@B+k^KZ zY#_oI_NOkKkzdkKF;0{fzoRC!UAecIOLsFTA-aa{L^^|VF~pNkT(&dyBUI1cA?iDjkbg(4m~yAtpxvE^|-+J`PALwhuCc_qr? z^X`ez4f7=m6rQy2qKDg600`jfSoTDsH!FJFGZ9VC45F5?m&=rnh zHos2UnH-jy+B)w{oom}5XB(kZq2qkKFP*j({I}T-UxhA1K!?voRBVOMF|~YM+ICh) z`mog2op@Uvxn93EAD+#)Nfpg_ZRPw5WhtGpIaAS?9L_frnH(IPGo1(@QN))l;eD6L z;Wv)1e9SHfus3)eM|!;*l^6Au&}A8ZW$V`BnaSA8^`NWF8kQIHj0<4v_M*)TZ@i}c zqG35IE7qT4WhJv+Cd@!YH<0d(2ViZ9K0CPIrH_f#hrf6AX)84awui0HeX27(suSsO zyti_Hjy#wx{p%_=Frkjz((+O&nd_?1d;l74yU-apHey(;{u~)`2e8 zCqj9Ju&<{#;Abovv!LTWmgOdSP#^^yj+rIrsr1ivxXSx{S+G)YkNE>|@7fU_{X| zeEGXmB9Y|JaQOW+^lh?w*Yx*3<4FBB46&};ejU~AM}MNOd;vjD)>X!s@5QlTqpRIm zc{Mg%HNFhc|1rczc01s`0OO0rm3~;9F~Gbk?a@>ZSEEHFzdkO}_+{~pwUKEVj29R! zKc*bqvn(c6_7jfEl{%aPJmKlt6}OkK5qG+>p)6b10_ZT_=NNJZ^I>d0Ejsxa2kDb1F_95eOJ^hgBGo~&)04E8gOrN`WzO41V z5IZI=oPXH#Ii#O6d+MUOhfSS5f9C8tGZHhF%$s}Ig88IaG;LCAV&S|44%>hFjD1>H zwC>r~Y8VfhJ#Fsv88}^N&kpE;b~9#`_z!R%JRPb)!~rXt$95Ga!{0oWDFMjCQ0P zO-IXoTqDp1qkX=n?fy4#C(GHMu2ih$`V_l=?}|(|lPs>JMMl;!YTD%XdBr>eaP&0u z8NJjzdc~xPyR|PiQEp1j2f@+39VR|IG&P*Iw6=_E9Y0}GOKW>ChRad)w5%#@A$s!y z%pB^MioRE=@87OK4~zf1>QF*!r#t^{F&Ga*EIvY+s`eca+*G0PafODhbjXYaGndSt zeo*^_mPwWN>Lo%Ii~U=z@xQ`aZHiU(9Y~QXld0Her1?kS`mqc(k~VPn=xebN=SS$l z`r2{(BXp{6nU9b=u&jy^e{4MmmS+v`V~fL_vSCYptNsDpKOe;Y3+xYJe;E5C*dN7y z9LBX@;y7^GF}wfR#fK96?*L1nUwB_>X=xAta64-c@8!H{x1=x*9jG+*ZnZ!py5I9A zeOMZgx25!)1=9|wzW=urIy*Qg3AP+0oSEN`oli-RV}A_$x<2=~E1rVi<+dV=PWELa zj9-U)JDw4fYv(`tm%EFJpfc`|q(gZzr+~_R-ic{)Wh&F9h<| z{(-!=0=}jlc=xnU%aAKZyelBOJi`Uxq=C&J_H1uMOmTFN)lZ4}~i1G)6`SUZskWbGZkwEW1EU7^#1 zYeeq84_N*hvNreR4Dg(CRv^b-=1Kl*zP$K0;vC!;$Pcy;&fWP!k769Uz$sS+_k`ywrxDwVbeg0GZBmH8eeXmj29J<@!qMv9CNZKE#LB` zV~j5iSECO5`|=jr{|CbYc^dQTMps##8kdyGc-=WXo9pjsx-2MXE^7pWt zX9M%{1Ms`eA>a^j2si{B0uBL(fJ49`;1F;K{I4SrU;qCEej&IG&wPVx*8d-c#~AKI zpzTr|xgDmzSNy#{;kNTPe*Bc%vNU|Bya{yRf-yW^$>IOaWh9oHwFfAQ-#KX9a&wg9 zW5>@JGF8j!^W$7U?@jbq!uE6zqPUl_gaJ}1^DM|~z&;)_2YQEN`Sq1f?AM@B&gGEN zh#fyMaE)BwcR{iDA?6hct}TYwfsgOy@hEI`x?Qiw;2P`H`pQxzYIHJz<*iKG2G?9{ zqcVT1*LVasW&BCYn4s5x(d*CY^>DoJB0nCn4gC&!jh`&c^**>}eRsk27=4dE9M_4^ zGeK7@==-~Tp^S+9CH~%N-xc?zHSa(Zmejtd8$p@Ny6l37EM@eQS4trEXg_%c=Gk>1 zR%TdYmhm4A#?|Q*7nQZU(W6vZc@fVWU6V&nD^vNb{;9Z*HF;HaYcp6z%WdN2)$mo- zyC%=n+v>vg{aC@1vdY9|*5;AX;>9)hT=`RrS9N+dUXv{*mMPY5HF-vVTh=tgrz=om zI98`umsOod&7(CxnrF4B*hf`5#l`eHP<2=9HF;J)t`P?oIb9-Cu_>lU$x-=>Li&m* z+ZI}erdQXeIxnn`<>T7gXD`WXwb;Rh& z6}fj($L@4FbkmCZ^Ic5mI*G*6be13dh+%b)Zn{9FgB+cEs4c2`ocq@olm6P^U0`TunMxE!*{nwvLpeViM5`*l6tsWAbW# zWt{vfzMxu{JTlb0BoK;D@wR-{DhwJwbEDtcWUr6urXf+YK%)q(MH z*}qDKY=+-Du<5pcad_bpS6jz;I_^t7TwiQ?7{8aYFg#;*awO~0u>4dpUn()f%3|zY z(xca#HjU@i*g>LBUd0xeXUEhUJ1|XZn9&xtT*l>Pxf~5~!ytPF`#v_oT<}`?ee%uV zPNJx-`3}5C*UZ^6853FWYj~Z^k4Q!1?|rm+{lXelQWt?JpYP8r`LWOC*tz#WYyNmo zwz?-Er*^$*c(;%2=W^)TrR$)re8$ID-J^A&cJ#w2XZz@`5nZ^JPuFqUe7*@+IcB}E zy5oGmbX^f&*H~|DbHcbxn=ziqDB#kBeFN+Tte2o~75&!etJR7$ z`d0CG3i4n~q}!bAh&@1>Jr3%_>-_(T8-IVO#f=yfw|$UT54RaeC+|$<<#_@09QSbV z*bMRIWft;2g`K|PecR3X|M&HoZ;&OxidgbD9JYz|DeOz@{QrrQ^ZyUOF+{)H$WPz- z|JTM8aQ^>@VW1B%`p`bb#xQXH|L8o%@7nqQn`jPr?xs(^^Z$4L|Lhsf(XSYxd1xGy z|0y501)pFax46H^6PTm*=P&Xbi`4hucoN#ITg$d|n?t}M;1F;KI0PI54grUN zL%<>65O4@M1pZb8od3V`|9AfX|8xHT2fqsYLM(^t&lR}^aWClG!i~QzeZSe9x_=G< zhk!%CA>a^j2si{B0uBL(fJ5N_3j*==|4-wYWW}fY`u`&ooN(u(%PJhXIsbnX{@D5d z!xk9#;7>3P#vE|||B*kQ^Z$=x133SG>*F8B2CzPhTq7R&-$y=+On3hOVH}N)5Th_I zfb;)1u|=H!e`p)d|36*vXLkPok&m_W|3_c|=l^fUO6UKNZ>2@P@y`FhWa40Gkd`QJ z!at+`|C*LI@2>Y-5Un1o%g;alkykgqZTe|LKREs3_g+UFK#@Ii_-a}SPK^8jB0s$v z9&s=mT|~J(edu^*xy>Qq5O4@M1RMem0f&G?z#-rea0oaA90Cr3Pa*=0=|2biLD(Bc zhZ=qhYXG*!>1Bu?#rOS;!?ihfda^j2si{jfe38z3Dn7{65O4@M1RMem p0f&G?z#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(z~6?ze*%WTK5qa3 literal 0 HcmV?d00001 diff --git a/extern/lib/libvorbisfiled.lib b/extern/lib/libvorbisfiled.lib new file mode 100644 index 0000000000000000000000000000000000000000..cae3e83df6563d032e654fb3edd54fe6409d1789 GIT binary patch literal 128880 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

xp zWM3OcBYxM^^4viB06)xAB9t%&cRM1I$^h#i!ZFy{Ap9dO9}u}E<__2({C&x4c{p1UYg9>SdoVxMbh~GQ-y@wy?K1k=|_W^$G@%tFR2l3-YpZu-EkM7>ZZ#I5BGR!*6a478T z#;_iIt}!5(3POspl^U~1$_@R2lR8$9iV$b`5j-G&nH21@q8Y1 z7wBcsJ)lnHj=iAeK=*;Ngzg9BvB3vGSsD+6^3=YsKv@#M17!yP9+bK1Bq;OiDNyFN zA3$FM{SkC6=vmMYLC=Bm2;lRer$FicXV8nFtVe$VWxtT)6X_SyCMqhy2AFT4hq*Vsypy`!;B8q3z$HjSOr*hP)q)YxAdW6LFBVOt_$rlL!*RvKe#CRjg> z4c8cFgT(C=jXk2V$27J?V_$3RxW>+E?1ILMBaX#iuI&{+s%Wgb#+b&!*Ir{?HP%C8 zgETfwV;LID)YvkOt}?>q0dmV?7t{<(%KZdJd5UAH=l9tSW8o%-Pi_#DtV5+T;cu!3Kj%uqmdk zh+1PJ808Azx0=truy0rioV)FweenQ5S$||74wv$f&Ge z9I*>GsbN&CId)2K8tds27nAT+Ojb7f{$F50QedoeOH94S5ILh*)ZM)?S?5Z)vwn6= zyWoafhKPs4bxXMI#$}>B_~CAMPufkm?SgG7^>21q9LVk~2QPr)aF{iA++ZUOj|Hjs zlY8Ncupo$tb#9Gyo@tiNqsT*XRLEqk0m2GabJbA7Q4R%?(S3|w9EqcC_H#JU_?!}} z<|thYdgJAJu3x~UrE76Co)BGEz!8HEe7(Ky*%+NVj2Q*op6eH4T>W=pX*V~?Y>Dw~ z!$BpqV$hIHE6-bym)Y*c^XLj|y>r1)|EhcT4(xiq>vmpuM_h5cVy~+kS$qPCMURHh z;o!K_PlYzNUKh+onY;*e*3C@UTpSa{wX@T(D5{&o9dXsQWFMny-VN8>*?4tf0tZ`- zcgmOGzLaE(4+$DzJm6^yY<6&Bg1T^E2@u zQD|H!X|8@#@;vITc?_fYz^vp0c)FxFyK(+gL>X@`w2}R>-ZH_%*_@re6w&RXwg#Y4>kGX&Fz3XI9UsQp;F8jnio z`JSw;Y_DUH`0wB)hs3OtVm(qvx$&HZDt&SpkL zpe(TDe!D;U(b(Nk9HUrvHBeP0r>Xm%<=)Ef_+Ivqcm@dd6`UEv7_UHe^f+2N);cCQ zD+kCsjEM1`d*DjqU98c=xyLyXayw8JVJf^8nLY8VeVX5xZ{J6N&VA%x9NLG}KvK>OZ-QORk;RML`#O|j*(1{;rpwhb8Oc*)rhC-mgG z0b9oyN1TQ6gG`+C(g4Su24ce~FFTM^UpP|3SP@?_)7W9$P%#w>gc>=FdDY23KI)go zfbHz0l1Bx*I~<&(8{^Bs2pl|P=hxw5CM71MsWf69OI4EV1qR^ui4~5OINh=tc54hV z^Pv5m-ucYF3Y@oUPfkkY<(kZ0jJz)D6aHm%LPke90%i&67FZpd8b;&7%oWBeY`P1D z60nA`-tjox+)xW|sd>O6QBgOg!0M-N>IrZP6e;X}Q|ZAo6sRn*C>13$%xBuEKzR{A zDo?05vH0@hRK`T&XSrVpI~6i<_|YHob5L;r{#vHIWr5QW)H4N4jiC{yE`du-O-)Wk z#D}Pi>@(J24N?j}Tkp~sPg>1FHz@#o6fr%$Ib_0!UjxNG*h=3*JO|IufPMkG8kBX! zT2L;{dli&*-#SpvcdiHR0Qx#8bNvQT7UoT$$)N9nGVi?)%8~bG&}TtE24(;1bI{$O z*`TaP@NJpDgKh_PAdBq)EeM(mN?r7RQ0}5V2FmgF_n_Q0dj^zQ@(0jvpg)232K^b7 zM-E;Fr9R~#3EoF2B{RXrX=o!#1pcgIfe#SUsC9+Zcz3BKS;RPI z+JcQ(eJYUNV%mg*kEZDEZ(#Qs}8MTvoyw1DA-AjnLGB}JF~eAG6NSJM5X5-mDE5a3pDS< zql_J7;%%f~M5iStC8-_?+jezW6K9}og=LxlR1K+>j;#I*i&d>f1&n8o+3#=MV-hF|1kWCcNWudKNmQ`1vMQ2}G03 zEnddl(CT1qaHnmO60Xt1?BLIly#yaGsJl-@>?o6Oz#)$L6&Vo>e7Fiz>nx^ITBwa66-ru;?T<8_ z&X{B~MteHqn6+kiJy$v*3UJX;*8#1Yq!qur)s34_v$kMW)q#vl_~)AY4p&t@!3e^q zdyXu8mwrl=U_*-)kJ#4I6Nk0iTVi4(+TM(EJ-?kX7;Z(Hdhl|jza-jo@_ZMrvr14t zMSTQ6kYlFD;mkCt>SOB#?(gP`Ie;Bu+!nSAYTtm2dRPF4BTBlIcOU%OeHX`~7cJ?k ziYcDRD{f~H7O3GAv!Agzts72L55~V4#grnun{!upXW#unZd{C7FBj*f1;tR2+cAAw zP3ClZeW8-In_hh>UtS2Zih=zBu~=%wOo-_uXp)&Tsaa-b<#YqHFEz}}(C(dC%P1HI z)>UFN&VT=xspCC=0yb8dvV(jEY(tRffog@1=uy`KtFEvOu!#l0)V80sjiX^Un1M!3*hE9i6#aKWf`$*f@d-$HR41|34p)o^ojd(n>~P(}<~JW)Q!9XLDhXdYUo)y>!_}JsRQYm+52w>` zvY0az2Tbn5K`hTZ;*ACYkD;INK*$9Z!l}urCv3(U z0ocz76=WdPjf+)hflWEPpwR3%0-+c!3FTubo-B{68&RtJNHtFowO(xhsVgZDro+l% zX9sSDgQk$UL*aaneG>uq8FR2n>=_5c<_5x0OOJ*6Q!3=x@8Mo_2|_=t8v7IhdCbHe zII514h6j9VTr%ztD1{(fYpd*4YfJ@(<|)NH+0hN5Vf^t5d+Rgu#-E?gj!9?>_g~gl zKndTErE^vQ$fI|kv5ZtyEbF~i){PvKYVufWZLVa5{>f1p7t9J~MgJoKM5qFl&W)+E zX9q9@PUr#qAaq3i`6c!IiQ_(FiNjKL1{q$ePOInG1$miM0eog`MyqF84aSmKSv||y zdJiJ~BGq$4WRa386?$uItin3s-Xiu3$EpAzQz(8p9#BHA7s*le9-v+~P~oP!ooXaZ z3E+m6N-C?$oQBVmJZ4oM6^&M0Im??x^UN6V!8!H`S zp^@dDLTX8=X{E-MnpQr4hTk*zQJZQlccYy@YHq1$rdTlb zLOAAPt)aE`uaRCsVcm8VY@P6HZsLd0&1JoJ1hfh0*PztD9tDj8{RXrzD0F0*@u1&< zP6PcObT;T&P_BPF56TtT(4l312zm*07wBcsBcM~Dcf0~x1hfSrpeSf0XdEb$D+HAF ze<@IA_%fg=pyfb4pyfeX$}50A16mRE70^ncuY%qO`Wk3W(04&=fpYy@IOsmmdY~sj zF`t+DJ!nf%>X%xBvOu*1y#e|FXfec1d(g6=4}x+XTvyO0puIr3BB~E4^|pOMx%(Zu zz|4W5gFr`s4gsA6iWM!H)6HkBk0!;*62RagT6XNu1pnrna2W0_k3|bGg31~0#InI0@4cZj=G|*HTEx!y``~@8v90LJWoN~GT%s8u4#-t z8o{`NPWYHF1RJU`>Kz56-ck6NF9chuu@5x%vBq|4Y`4a)XpDCuh&%)7C-MSKTd+|= zW1N8zzEF*YX{@=%cu1b`_0(8jjqy-)@q>q=3*Rh_F~0ayq(sZ5e-T(Vvr><1%oLTK#rYJ0| z-;n`SUzT_)Q(xKI)K{|3m2ym*tp5{?$`HY(m^NAeCm7`l-?y4CAAMzse_LOf=oiWV zbNb2#&`aX0jE0~LRwK~Tpp8LU`E}BfMw?WAg0b=wY?bDFR%3qp$^@ma93uM4e*Z`M zN+^fj?gX6X5PKlVU9ac?b-G!;I!i7(wimzl!&6?Jx9B;klDm18!>!(54 z1O68%^_I_o)&PALlzPkOK^Y}4fKqR{8nhqi%b+Z(FM=kU&yztZhv~=n%(F~&Dd@C` z-cm5?Ed`_AQm}~{qux?5>MezDjmBQl*cOdZWgvXiR*Ks*8v9jaziW)zO5x)GUfid@A5DCTtDSVG>jJ;mLKG4|5 z8v90L-)XEMd=h!VrY+du*h#Q98dGXQJQXoYqv;nv?0e}sBNnP|%IuFF%MV5MQ@fTU zqoG$^1+St!=R0AAzB)Vf9GN2witt=~&Mq zwN|&22MfcY>Gphm_dsmI?^$;olV@~;pL1t0*06Osyi>E|xb?3L92%WGyQ3CQ&y4XL z?l$knOg9wsQR;@BPOeTlTqGak2~;;&1}?zGfLmPyaawwVU0Jtg%`EicEI7YVAY#8O zc0YCyIG{#e;B?>3iHSIpu`A~8mTuToyY75p_}Oe1)Y6&!@E@XGoeoAvV2g7}q$4I< zmYfH*!V=(a|4s3JqOL>pD+mktv(Jcy)OVCk=C)t;-W3Q)=Kk6#6XW7wk_@M zB3v^IZ6>);C@La5$`zYE5@(;@-4f$G7=u9VacAWO#Na4Yj^D8g`m$s4)92$64lb(q zTvl5H?EUHVKh}e@VGp`JZ3{98U2uJ93w<>xyno8}e%I_<;{S)1|GDr#7x5E<_!$|s z(9zAgJ0{|*jGa`(=io%v9hids#WDG*^K4X9G97`%H%j2?s8}5DhJfrsK<3?@+1>IV z>2sKOJ^G|i{(*>cet|G}wrsf>w7|Kbt3yQt66=#@R&u>`VMr`J>HI0`cXcegBXQhG;I_P&g4_^6_p-~2j0A(U&&?X3g2xYq6IF-2+R* zSA?x*^2|GgYXFumfOTOo(jv_DcFu+3QJ(D=3hPs5V;AH8l^D;URxzG&pp)D&o-^30 zJv3@a)Zk$`E#P!GQa2E5Ijud=&%q`;pV_Fp)m!TPccDxLs$H*pl4sbGYK$ z2^+`Xc6+-k2=!;4>GA5QT&qELAShcBF>0KJ_IB9FF-d88ub8sbnZkNM8YwyX?tTS) z;e5)tp|%`TX?_=hz@&y&iBqZS(?oM+F7@_JmE%Lsw;V}E!+;6KbZ1PS=DVp{W6E{W zC&7=NL%;xN`@e@a`kl$RVcaRmmg0xdcMs+`^jbT znyn7nCugmI3}dz#I=fp?UwOb?)^Dm$9$_&2dAbS|MU`qVCF(8b9mgzVFhu=b7lQSC z-Yx`VKMCJaN6GlzX}PrbVc>mrz7dz*J5QhmAc+_Eg}P z+@M2=yOoeyYIcN!0qjus+QD5K&l?m+C#8?);`n)rYl^e5QPZgJ?4-QoPHxFkJpY!9 z=p9C!;`_{56Gv+GG2ANIT1<8rp}^(c);uQ%$n*kMaVwXD;lk~tH2d^`tvU5>x%Zy?R?vsTy7uZg?XOV4(*a$OPdbEz z0X@oB#)Hl(h%fsTf+^;n21*Z6$y7td8>J(PU=BK}8@I4bX`u3jF>q4hCmaP3^d?3P zBMDcPbEb(Q=%U_D3}}cD48hsTF^&{tpJSDmkI5tD$W6|iyrH-q;FbZySfrMeVYwDQ z5_uT;AXV1nFe_bDF5>W2a=WP&mZHWM2TOd2axsD%53JI5PC4NKfFlws_=g=qIPriH z;p++ap(Lw_kZBjzq;Zme9VnCedBP$vTCvEN@g7-mG6bGLwKUvi3 zb6phkG-aJsvQIb~0Ap(YjjToa$&zyw8fjV9m)A#iKLKq-{<5+{@{<*!;^clU>#7Rp z9>mi9m<1d1cd}CQla-=mHCD;aZycbW6VcQ(R&uIfB8-`3EaIH!GjzpoG=5LxHyb~W z>mnIVreVcp8jR~o8lzQUnPL(6wZ+fc3*a->ONSf3v0f%X<_Mp$-U1Eg8S5?6FZ5V% zm4@uG-fCj_B8)2aSdRnCb-+`Q#c+a~^e8F-duQxc;D%vehBZtt{8pIwTBr=!FK0$l?7 zA?O;=k3cz(_6aEGM6yBO1>Fkz3Fr<`R9il*`VKnK5D+_yc^xU0D2nqWzaLA?}Gja`U&WH z&~2bUfwE-%4EiJJ1yI&s7eSE)jbA`n=UxKkyxL{ZTA)`z>w{heZ4OF#oL{>E8VC9Z zXd>vJpscF?0?h=y4Y~~U4k&l!-UVF?iWLi)8$eMRWpd`^7I5x|D2V5MpuwPDgBAj1 zi7Nt1MLMP+61%&C}%`MKs$p{PIu5Upe$__K;u9wg0i-&1Ud)w zKG21rl|h$+RsmfOS`~CPXn9b!0<}Ru1q}yf@1PFoQP8@eoc*W=dIPipD2_rlKE`*k z)60CoK0qVj>^V{mCHe~5g4GQYf(u9Wj#<+J!`1)y#yA1^6LIrXAw8nVFv0$9n z6F$!C3C6Wef^imDuK#<<%++{S8*vw4CI));fHV9dL;6*1B^ zHdkW{G{(Fud@pN^D@X;~sxjP*WMW4&c3Wduf27_9^T=Y8ud>E?$+yVkQ3Js821K=AK4oFQe#*RVfxFxLBjW&#;O#sul_vU(AXmyo2jwKG`2)z+k-55)JjNPozxiaz%a4MK2Va1iZtAu-|XhO)yZ=*RvqR( zBSbdPXKf2tnv}uVBLMws9QPZ9QZFPcV*@9bqaqYX9@rNZalP;4Dn6P}S(6J*Xxd+a{Ku!4Cpbtibx=@p(QUUqF9Dvl6so}r~Q;z4qPJ@_67#B1(A3Ozz2pfL9OmT zyZ!9`v+EzOc;#QHZ8xWM_-VSE&;IlP08AyURr5|I_P^us%BQo>iJ8#^5zF44b#}ff z*zSDWYuDZZZW-n?_O&^K{IUslLSKh@uM21`(0I^D&<8;|Wf}|0nC=D|2RaCpQ8XAd z9drn2251~8b)elr8Noe3p8@R&`aEbaP==*9=vL4^pa($vg0iPWc_%^Xe|=E)R;2Gm zn;hmY*g*4burXHiP0-kKjXkNcH5z+GV>>kVg~pC(j5A5%FUJAmZves}SaH)Px7-TW zSYte?Ofagn#4QV$U?Vj)R%0HGE!Eg-8e@-3+z8!d(t-Qy+knUOj;ebPVPI&%4s;0bn%k@Ee>b22;nxCry|qZo2m{#~MYu;I|4rM77^T2-^Qm zWVk$_6vSuN^?YUphuz>RWfp@r#q)B|W}r(!87F*Z%C*!fN1Lpa5{y0y#xMz%q%o$2 zU<)+HunP9A#*o4~o#p_|d(UPdFdF8j0lw*^ChI4u7J@l7pS_*`wT!Mb9F3K)@{eI) z*u8Ul6yk?(JAe}JXvWw5I=*O=i+BX<4=%x&(*H<5og|YA#Q|^ zU*8eGem=1eC3Tw0@D3IABbCmTm6w?R_wF)y2>#!DA;$mET?UPjBN%tBKpB6n%^bpZ zM(RS^?VXhDQr)vz*Hy)6~ zDk2Wf?d&lXPkFB@XaX*NA}b1}gBUhL%pU*NRR#6^%P)r|V(P2TBk$G1cHaqO(oip} zeAd&8gR^BN!TvXwUT}u+Kf9K|TH({}-_BU3HdSeXSr_Vd)7rSeFTlQD^9$HBOa~i7 z4OC6|phGGvd)ldXE#@t(Irs&8hu24*&EXi^q($!@gCks5*xffT`}m^NAJ zDi|v%;bSEw80YE*`&476H1?y$7QrXsTV~pD5%Y(cc<)Hdd%ICQIP6@u3_N+)WtIj; zB3`l(>8gXB`ptf^mK=L- zx$1Dl-T#Iw{FZCcOK{eDOpvu@`Dr|kbT#_jHUBZ#c)`K|&xvTy#K=xq%hQSjb{r#k z-9F9lnrpxg@b8>jj^}*d&2fceyJu2CtU%dOA}ZoLUPuoou<=010covpto}9E;5+77 zo7j=ceZE~rk919l#mNDl{lB_?+J(b7_d~8aee>Ws1Osb=%-hxmb1a?|Hrf@AZ*qmp zs62954oeVMbp@(9PS$32_TXNFyxHSd@Ylre7=8)9*#k$Q<+Ev#Lt49~3RN{qHwX@e z08ACAIwuM?2M$V4NS-i4CaQDPTmBoaMwOgc8m_SANY7eOE!#)11*rkMeQaEJNEhDO zDD@rH!Uj5(L3AuAF)+bceAO{!&6N=h3HpKj6kA{}AZn($P=UkVTpgH4jmp5R6%bg> zX&ug;>GChtbFk7Dh(GZoM&P3r!&baxJH+^BC0k0_%>(Ex9mHM*@;aG; zoX;?ZApwTtmv;&+Nb#wE`HiDlQ4YXc2BL?d>eYCg_*3EzB;c{KKv#yIL0K4v>ZxYVrFZ$5{2B;qZWt&E zm)(lYwQMrNy(I7(m}e0oC>mlWn|o5Gn0rz>A|@m+(IySGU~H%bn`+vMsMB-=qg>(p zR`dOTzS(GpD73THuXxJaclB;IM*K~-`ls_t|Npk*|90CEZG z)BYtnvY*582uBz)f!_LL9jg< zV+A4DNsV36*l!xEfDj2E*MHC!tPZyjtbxX2H6KT0!Z%oBaT=SUvDq4XUSlt6j17kP zQPi~gHywPRU(>M*p^wP3%(f^n8a5r%kh8?7k%QGWR0rAquWLUL(0`{1nPxU2kC;tJ zG~z~@5ZW+33^{@^#|oCAu}qDf)YuOivzw597bZbn$BbgvTqO#? zjdA`({A>MiP})TM>H~8J!#=m?+&S`ix<_J6fqTu|3CGf7I9V8}4ildl=g!(0wlk#We-EgawQ8gz_$FjL532j>AB56!8Eud$Zu>=60ZiU*RsHr_2Dq}+*OYi#5r$yl>5LFzcxBAccW7X`vNw77lO7`;GfHH0|^Q~?pY7g2P&yk=VL8CzX zfJTGHgLVO(4cZx$RWhI1yXJd-Mpsa#Q!FT}V)lTg*w7}uc)=Klg0UAb7<=)8Ez}q{ z2@3X>#x`o~GmUN4*a?lD(%3H=V=fbUw>9QK*aYiq+KLzhG!{wyKx17zZ)MC@kf|%`JS-Ym9A+U@S@^k3~r^_G$z>sj-V1yP`4n zQG|~LNZdLK1{ejK2B^wQ(hTe{Dd2FTL9lGB(H1JKT7dwg0M1dSv0U)2xL}V%Y|MA! zf?U1uvrK-nIc@ATllggXSmuNs*1W-XZb*Haqkpmoi`d2f5E^ zxn#8B;_u{2Tu^3NxU)=t;a#KTI)ZU4ee;4waMOY*0iCEg=#$tON3V*jKx_hG zc7bsVQU6o53$f7!r{$f7$^nl{4)As{NxKjmUA%iwKhm@dvC+kcelD7*@W{W(+J)HY z;&X9P%4w9s&Vs<Eu`zzmNJxqX8bwjMt=hwK#ds55 zrjFQ{I^v34(l>(zCO`S-MZPc?mRyF~4uja}m&m2eIi?Ge{N!G~=a*6;C|@cze(Cjp z{8HiNmx_&FDz5T=X@2r~cme83xS{d>QacP{d=UT*_qY zZ<+k$@)`!GQQB#`T}6aP$;U;H%r zFT@XJ^5{FuuUrVHPXr$ zm3}C0l=!l&5!Af2a%Z{blel3Vh>dX|uE|x{D}?#^)6wV4ExAl(J1k;j-V?c$S^6L3 z#>khu3gC>;ibhaMp}2yLApmBW5cQvWEUEFt#xL(7A!;0KH2$rO5&lD2qx_fUj1t?* zBi$<~SC#~Rv$*3oi!Bs3kw7k9v0<6~{Cddz`e4I=Uk3a#;FkfvjQ_|l`orrtER&yK zgM4Dz`Ub|daP!;6#+a6Gpv-OmAU9rOx@NFZGd;j4jnnyDeTx~c=0y!xYLOI%=t2H7 z%}gERVxzC4BxLN1{7^*kSuXfi_!uU!mC!E8#Zic5@{>K@mOTQ?{=sUw_&eF+f?QNJ zSSCN&JP1*0HE+3$QQ`LWLF7{AvzAcJ>FZ{imPRHv zI}Bo@Um}+>sS>nIesbTIug2ZJZPNmcmLqWWaEG8P1y2TMOP|KKf6JK%sk_C-uY6BJ z#+n3iMl(nK=e|j71y(K?Cb9AR#Ra)`;%AxsWOKWv-G{N{@~dtCZ68D~WnQ#|YEEA_ zTa;W!wW3C~5g|skz9o!m&0R*d)XG;Xovd)6Ty~ih3gD((%goVVE;fGKPLbj@T5e~t zgJx+LVxx<_%0-0+#X40@D{E95QN}2T*1c56;)jB-1f48+0I}XvM8tuF;%E0I??9eq z=4#nuqikNyh5YL(Xt+icLf!>!Ds90I%NgiA?NV%Xc}!g9(G|Sn<%%OkNq4c))%W?j z;vAc0dTCc;qpKhPHk2P(&Om!>mtv#K3*xeTuu&d$Rr$V!jq(_wmv377O39NYRC-5E~_Mb8h}IG~CN2^;+_+Vx!C7#burts_*5hpLQiSy1Ff{sstNVnwK=HJYMli z`IBW2l+G@h5)xNJrSk%~vP^$1L2Q)ZM30MgQm|3BZ&{;kbKLcL2w!`kcy`g0B5`y% zg8xi2KuZuCC9vOy62uY4Z>(`_7kn#xES+L20h_p>+#kI{m!E8x$Ob2k6%rO2+ke{! zkxQB0IXOSM+%(NnkLdf4!c4gzz>#J0lU+$-v;ww=qK{pnZ)u}K^HN5ILuIa%IvJ8p zmt8F9pbzU96&vHMnjNDfs0FrN@U8GMM#aV$6&I9S(JMytlU>^ESdx%%D%uIyqdMdOO7yog*5F3SwmUoJL&TQia3rR{BGv4alM zF2qI`t>t^zHgLBVjOBuFg^zJ1HpZ2>AeVPdlArAMBAdD7Kax$kYw@#8ezH5smlnmg zyyiGc<#9EZQL)56o@F>oFExeO_)T5?;>cT9IYhe<8(s7g7qzhd5o3@_*HnFWpm<8L zxS~CaG^StNENz*gT7uXpp}$B_wM22$62*+Ny-Qvxani0Ocx-}Y;av{2QNm|Hj&S>ag@lMQ zc@(&1@{>DX%O#f;Cx0hb;)F6+lEpOn$z81E=AFIZ^t5FXbt;LCU+{#u%BKf3(Q*dL zt%p)-#YUG;i%Tq5DmT2;m5`HWy{JkbSH0P0ly)sPx_&`ofxUw-F>lb9)9tn^<_qCv zI*N_yD6S~`bIDS$S??J=wtU`}LTfazpX6d!swNWRHejVpMF5lMN!fiK|nM(FKiv>g`f~n2-GJUh>Ci`C_B| z50w1W;jpR&Cm<)=^8uNbv?G4fe#XUR!w#cxMHzMdj51|P{rXDtw|=W1`Qh`w{5iAjm^lM-zf z91WB>qG8I2;YN)@Bg@pT_<6quQET6H2VF*L%z>$F|SC+@{&W`Y(O? z#=akB9;|<(aNkwi97j9Xi+(Pvd-A+}v+ts$8%BPTPMS zZd9$xz>lA=^G1O&-Hcs*TYTE&ZAb3DO1q8WKfbzS#Nrp%jrr)4a+%qsnos-f+1H+5 zwE5v~10LpY-1Q?DKsV2M(^&F{jGPw7${duRYSvQ}g_H9lGue`*p*C zFMeyf)Kw+5&++o>CV%((`pr$JZ4YafGT{F3;f?mJJu~W?1wD#%SyH-I?@9aiT`m3m zqMw$0JEToe+tdO#ebaJ=FTI}4;|h2_J9xK z62A7VFWjVDYVUKMPS^Y5;Ek%|Iv@SH_t-jrP1wJ!`S4dl7Ke;U8u)we-kiUFFPZVc zZ&OdTx|6y->f^RA4ESbD@?-P+{%c47CgsML-T8jpbH9H2L}YSC#mK9hHZ`8vd|bZ= zQcf&>-FiQ1$Ki0#Pd7Y?^;@(p^i;)!_T_V*Nv>Ttpx@$^yDp#XnqDAk@t2jdPnO)> zGca}I&{O5UD%xQ3^4*;`Snhw%SaoAfk4e>j%Utks`*MxiBnZS)64 z*8KEljed8grfj(K&BuGJ_!+(F`Mb@ktm*sKBh@lTTLFfX;$rt6MmokO8J^q`(>1vJ7D&y`>pSpRQJXwN#8zM#(Mu@(cu$se7p5= z>;29tT>`fpnws6KPlqYHC!Ma``&OCwN51~)vnM)brx)q7{0AHK z@7F51^v7PRg(I4t(?m*0)gF4e8(1LKF6 z`u6O_731q%U3UE7q7~U2x8K}*qWEX-+%48~-uKq?OUsVEIQPfYj5CeKydSgpk22Q= zUHtLP!HoTN7k~8C`cp$Lo(rhhE@RJ}vkUtF6tU3tWbH>kJMv`v+FL>!EqQkAf~&XA zj2zK#{<6XE|Ixbm*PS*DEVVo!()q)HaqFj9-s$HAI6 z=hSz-@ag*LXB$PnSYS+6M#r~*98&4u<$vX|`QPq{KlJ>P2i^!CJ$FQ7Oa43GpV~aQ z$6MK}7fqjLBrhvz$=@|+((ApuWtH9VY5(kpe;!w&?ZuxPzIDEXb3{n>rAswEVO8-1hTGjA-d zv8Ls-56nBe;&F?=bgz=#l71~U?D})Ln;yCn9TOAKd~)EUrP{T;d2G(gp<$P9Z$Gi; z+}E`t&bE#o)pyB;)cO4@AE;fjb;e_}&wbEtX`KyCO4XW{+p9z3V>`E&$(8l;t$zz%QMdE;+hG4PFd zT-)~aFS`AO&)=N5zV)o8xj7524NRZ#+M+MRK0fg2<;rENmZ~)2X0PY6e|&S+qTN}o zx?gu3{A}};8555e-hH)0`Oddqa&*3LYsREUD&KtZos{-D9~bh>bi|zh?zsjJJTqiU z>>evW7kazNomN8z-oEL%uk6N09Fup?IlJk**rZPq_8<5%c;QQ zkUa5+!tteQTF(tzPdG5Q|FAk1|HMD{zu4zg|HtP{=-u<=2S>_(KHM|>zB4WNTkjvJ zS^MaTF>l_o+-F=`v%Jc#FP?8Yslbbm3|ZS_-=-1oebeyUQr~TVt!DX}@AWIVs8;Jw z+jZ{{{blLzz8TzM;LH-!MwfrLMvW%Nr%ZgIZ`7IjQ}?_wC$`6o7SA5r|6JP5-`*~< z%yVS>JF(%x(|Z(e`NOP7zF(41YTLMkkzr|D%Dh@{P=~prS3SDm$lh;SG~489ajEq; z#YXPCJha2BzwZ5c`9m|}o^0~r?B#v0zP`#TUl)I#koo?fk1X0$viqH^Qe&o^d0}VM z;6z88*XvX{`+fNicM{G7Kl4ZVV=FiAtJuEqi{H-~8`=N0v!B0v)^cyv7r*{Gc-@iW z$%_^}*W&GvPM@}V`2Gp^C%qomuu(+fg2?i7*I4{3J8#@QyNEY7m{qyNITaLA9nqGFp+yY6ndwd^} zP@($1kTQ*Lte-jkv6qI84F3AF+6_*3bZ$CzyZd{;J8L$5yXrG*uFm_-8FTUML(Zx_ zF4vk>kfE zIpg09Pa4s(MRe(j&rIz$BckD_L$9X~iT?60$FM?|t~B5NV%4FWx-YB#N~bF5N-7hX zkUT!6;g}IyCkHz2-epHQa%5tBTEoVTmpL3bi(Mg8l9L*aA3;@yAxOg!sfh_`QxYkH zJz=NAQk)PG({M!M@X4dX)ToFqosLy961NyY8>S_ur-hAIx)k;Q-6&=!ws33mZ)lKRLyKIvvIFpP?9;_+&ou!?#XHG#D5% znqq!(IE-{UUcrB+%GjSDZ{;5z4k?`uZWX6Q8ke7(5TH&6)$5Gs7cRXs*Iy1}>OE zqZMJJ3GtJ|MZQkQ75ry-Zmm9>=r4yk!s++~a_)nTrj(x?OuB=Is&A&i+a2Cn=r0G8 z^5EG6k6OS+Q^rpYChfsP)hFXHrRDpx{N+$h;&hzz`mS<*a+umqM}7Qf{5)3d5=sk% z`jiXCiqo+gFk_sif}fm9K%I^{>MfMMt4ATq^U7hYI2}o5n8{knPflgUvljmuotIw=b~5qRP~cnP4RHR&u{;DSnCLX zIn@=<8}KL^HkxXFa%uo|IykVWoJ}tjjq{firg#=WP9$tJHT>k%1nP89xxpG_-JP?W z{N>bAJUBfBdrZXC^pjIt@lZ9ycs|njrEq^afZ$go{9?(csqH6+DelBM{^EM~OE-@B z%R$tGrYpiDhKIaHWB9pmty-_^Z* zONh%Wr=j9u{;}$x27YoHDITioC}-lKcUSn!X{>lMQII>pM$^bo4r_QPj&2v%l}{{t z)n5)%$?3>Ic&vJ?iJzQiiid3%&El#bUG|sL9B)ug@gKofrkS6d`+++hT%gKUD)E`< zxBca?)^R$5;8}Ggg=b%}w(@Q-sJe4HX5v3%cki9QJpOW+N=`={7_9u$(oarn#ZwkM zY&qI}y!9!6Ic*eAwwIjNesWMO;g{7eou0<2eTK}tedk-rhgQ82;U|Za*iOeCIAzOG zqV>89{&F5rJUE$5=fie>a@s4NLHN(KXy4-MGyZZS6_0nixA&71rFeGWKU1LXn&POi z^L`g|pVP4!u$6zJ{N!|0JZz!p`la8$J?$?iTJfC3f94IEj(&1F0d+dMsJG}x8Ip#-PHjsN_vzf!j5`iF;arM3Cr@P`I zY~{mlesX#!9xjDrtNG2g9i#l^^i(`a5YhoQnjU^~dI5Dh?j4@qiYL%3JiYwnu!eU! z*n6S5+P3v`{^9A1H%`X^{I~K?A3r${DITld$l3T>qQ9Jeisu}{!~9C~ke{6XK%EXQ zN38@~lblD6`^y=icv=;*+vWa#avoMZ_l}=|ipM*>9`=(nNby+lGxS7dG!A*weX!#3 zj-Nq(a)v0LIrvZ4yB3~)-(Sv9#lyDJik~5Va)v1$)@GD*X#Uq5{pG|do=C59G0aa+ zyyD?vAaulxx(`%K_m?wV@njY;j7MRkiT9I}02J*z{3+QIb#)%cX-D5$r-13-1v_o|2OqvlHy_infaAwoS&TWK%EZuIvBfu z1!k`F4-b1I7^i^2YA?q7$w^i`R(tWmYj5V$pHERd-{QYj-jn_0OjJC-;y<#PG3L;v z%KqU=RXiMjRe_CWqMw{eK>w*8OH(}j@E{6-ndB#DGEk@E-r<>|czCP06`sj{a;7St zd)FH%D)1}FD?C&E7fzc=t475BR`tRWQ|Z)OY^Ws3Yis0H;t4tkzN|9 zZz7X4f`b^9nW~XKCNfAP!%U=)M#h=QG=(6Q$4nS0Rb(g4lWy`vXe7%-5;TI-l$D9M z#MWFpNp;;_0zK&0qnWtK9HG!O3yp{b*hS|(CkBUs60u%@G{XBt#L)L)xcOn+q%^ZhwZfC^!!t4|IayUl${BgaCyq}@VfVxvnUu&* zmPW#2yEkcVK9d$SfV40HwKPc~%`F6-65+YuLO6c+A?rWEASDQ^&ipTKwYnF0V+I026l}o2= zSGlGu#pB~wrgCNZ86b0@$qY( za%K7TXth`R*{+(Kt`v`tUyu6uwRFPX61FRxWu%Pa@$qZEc14DodmpYTdPqJEFkLAg zAHUe!l@S?ZW7*}{Alua#)0N`!@oS-SW#z+(=WDMOogQFgn(0dM`1tjha%IKgfMe-@ z*sd0ut`v`tUmhR7a;~pwAbLOgwaRp*czpa?|3bzg_qj-G$TC7}of0vBS$&Nb( zl~FuCek}oR$05JVc7>Y-l~FuCel1n5y#12#JK1qxpfZZb$FF6;ZNJX+85Lu@3N(c& z9v{D!YgZI|$6a!+%mwfXckn5rczpbN9JuY*j$?;f*sdCzt`v`tUr#7k<@q1K6}g?) z*{(X6t`v`tUn_k4n)cb44YsR(rYptc0uTD2*nhXib#Heto%kkZKjHWEx%ipR&V z7nLikK4cu)uF_3cipR&Vmy|2-IJ8|YGF>SiAHQDq@r!Y2yL!=drFeY&dPTYNjzink zX4948@$qY|k6(>eyq;;h+Gn~_JU)KCs$5xdSgQJ=FGQ~e*uZ{dWfYH(U+aL|d4q9i zyZXa)rFeY&dQG{q;;_oY125aIT*2a(;_>loy^mjiopUy_U19H&GK$B?uh*3;?>Mww z{Xcb`36xaD6^4669TXK%5f>H>gMhNlFb*mbKn%tWL_LWsZO=@@jMGfd>7H>I%`ut~ zm!qBtt}%&AT+k?pJ02C(s1Zd)5jRkSQ4|+MgDWn%_pe)Z>vlgMXNG>a{;&S3TlK2@ z^}N?TUMOgc*PX^|+Nh5PDMk0zV1veZEd<5uVFmqMx9GK_-QP-B-Xat<#*5$0(i|T0 zL+&M|elHX>#_KLne(jz6(7P8aHD4%bjMrl0_2Gb?KPk09C}@n=-JpC9SN0v(q|_rq zL1Vn`F|JXQK-0HBBgJ zjMqcKiyoww9y5BC`x`6oH3|id@uELYME$zpvoF?TxpBt2Z7)&k8=;^vUXO$F^YDh$AEzkQi<3kfG{)-* zimKPrYxm!z)P6!iW4!(a%6ok<`KkMqI!q{NjMtOKYsT@b&Q)rLP|z5!r$G7fI={#C z1C*L06g0-`Y2$V8Z7u&)YQ9j=7_WbW;^!3JuDE@5clY-%-n&yMXpGl0RH``~{Pt-} zlzLn!XpGl#P=4*5mpx>fQmci6#&|tzyslq-&j6)9777~U^_=lqzvn3jD^;;0719Qc z@mfJq?bo`B4G$~TS14$V*YlwKcok26e}PgXgo4I+yKSi#g}HH=P|z5!wWQVKYw!(|`YCmbP|z5!w?Oec!A8p`bBd?|=$9JaV^NlzLw%XpGl?jMvoc*+(n2MJQ;D*E&%C_!_Zf>J)d) z358R=d-Cs83L4|}E=4tm3;r;mw^Bodg2s6L7nDD~x|-6BN*y8;G{);a<28NR_1`OX zyim{>ulGUu93Itl#BEBQArv&mYrXNhyJGStrOp!y8sqf=sDAXDx5|pgHo5D6c<&ma zpfO$_QmN+fz)Ah4DRq}n&={``pt^I_wDJ3g?wTdudrBy1jMqn0s$O?ad1io8tA&Eb zczq0NDE+RWpX1&dbJO^6e7z?WG{)-_#W4wMe zUXvExNFVaH4aIo7OekoK*H2VR*Anw@`kAuw{S8XpDik!vix(Nq;nSVFOi^m7P|z5! z3Q#d7PehRoLq1A)_84x?!-Y#O&1Cp<5g+;b@#k+ zIi*^Jg2s69b$!~ep>w|Osni8RL1VnO1LenS_kDU^tJFZ>R3QfjtP&={}Y z#_O25TSh8%kxK*`da8Ztk1_P~(C$AyB%cmBDM1P|z4JzE4NzA^#0gscm^cXoJRh^#$dR<(p4@dH#06YcHXo zFx43s?^OwL1VlI7_TigU$0Q=L7|{A zUIRh-HLB(BRcn-bRw!tU*WSjfZSC>Hm3m7kXpGlB!Heh4+`+HS8WnQ5NhoNH*Ds7$ z>YRQzE7h$J*F^UMvBr1}0>zbb4u4$w=`l+65egdPRb{+RxNTlvrG^Owjqw@`iq~HD zdUejrmnbz}C}@n=zQ!wm{>=|7HC-rZjMorQe!P|(`t%~DvO+;)yoMUDckaFPbEUe3 zg2s3aGhUxuaa4b$E)@zIT?iUIg<25`` zocY01Udxr5 zC=@itYYZqq4=-Gtu2YIW!4(@c#;ewNRZiUdT&0?Xg2s3q0Lq`6zkY20?e_^e{GCwH z7_U0xwe_!-?y1xjLP2A^#)2A7?WYH+t7f0H^Pu2$hfvTMFTUSdpHn_KwE7CAo)8L} z)X0Kfad!|X9xLAVx_>GC-U^TDE4hSX%~pmw7}VCH8$V*^14?ZWiZzxR2g*Nxz4Z3( zA1d{&P^_`kA%;44#hd?7s&`-41lCw;JSgA7{d%pYHyC`sh6%+QOa0PNV_sPjweTRJ zSYxRPpnSi^)=!PHafDE;asC;JaLa8y6H$+UJ+|kx0h2vLcNPi78oI)EX0E-Xm~E5+ z;CkHWlbpbjNvP*kUl{%$$(QBU)nflp=e2z(lm~Qrkjl@Rl`eL*Hqf=>&F#A9?jQ(- zg)Cp38+PkEX3oqObicEZZ_ny3e=#v`vjNafSCh}i7nwGhne2$;Lag3Ypf9T(&Ka zg(}@A7~+z9m%BLN8W>0F=`N_2V)I$qltk&%Yi4I#+YReu1_x zi7M^rH>%Q3JAW0h`$9?4xg*QTN*`mAqtX5wgw0MUW3qLIgwoa<6k zHrGZl!macnO|H|}Z7XD{O|%ZA(wW9aT^`bOgF;J3TX_Ke3WvO{L)5fBXWJW^((Yg? zrf{Uvs>6NH&z#BYCe4u|edrY3gjMLw6k^}mnU-w2G24)D%pwn6DK`OmEO@TeqxxI_-8KD3z#`%`!Y^n+f-QSrnR8?0Wn5wGJH0LCrRdr)hRUNI| z!YZoXWuXdp5k&h9O_}D_s?kxzDdLFJRF`Suh||=RY2t{}j49K^5pA%$?@k*m`zpXP zqUCPa7DtPZ6~+aM;HEtlx?NiwgCUnC>s*v|zr<;!ArfUZ#9WQYYluae4Kb%fZbK}} zZiqP@@*84KSIeUiVoqmc+HYNAwHr|^>PQrgx)MdB&P36uJ5f{{pv$^8Ac{o|h@w#g zqG;5BC>k{&ifRL*rxI;J9E_R}hod&c;iwUDIBG>4)@E>W_=rzwBQ)eH#c``aS7k{s zYHXd)ow6k8lm{g#OM=>Q9+Z-fYsgiINv=U>T@rLkO!HD@ zNwD17J^5+keFYLvsM-*we#6vpCQ52^txqa(K1gXIlT@Oe!L%w#WE69iW41(5*O=0% z(_+4qX-lI{i{+|JTN-s*3|yJEG@8&clXOaKsKeykcE&J?MM<4Cl%Yi_A43U~=#)ya!-uQD+& ze6)>c!?ozSr8Im&zG{eZlXMGPhRpVgCCTV zQwMKnPbjL~+!vt))QoN#&%H(8Se-i@BXxFOZyn9x9pq^49tfsj(6f`%r(hMbC~ zf`(k)OenIG6J6g6!h9q)^sz8@Wx6r2v^pDe_0=ZmY|QBnNYL3>)CoQ&_!K?rMF^G1 z+}V4HP=b+EPVFO|kHi`Fu{gy(=5(}bP^x?^OyMXNnZ|D-M9wB0$)ooeB6SpAGqq^G;-?#Y6H z;Ugj4sC z)xGDOd+z_9yLH`r>d;K8m@nl!%gxjFo;G@P^P%%+Ht*9icI@Vx4xc_>a5RZ{xNL`W z9-nax4KMD$L%<>65O4@M1RMem0f&G?z#-rea0oaA90LDC5Gc&K{{we81RMem0f&G? zz#-rea0oaA90Cpjhk!%CA@IK&fz_+u{okEImpg}mL%<>65O4@M1RMem0f&G?z#-re za0oaAK6wAN_g~}sexBjKXyL*K9|Y!sF!3gS9VG*>4Pdn&QS&a5$+!1(O3Q%x4%4g_hieN_EqI{qDEYGL7s0)y}-u& ztzu~p>cd_dQErsLGWw*EC9)0pnAT8SSw`D}rU5it;<*XuCOE6hwL!K+7)Ln=}-mQ&~doowZ0uS%FZfhmx>&($=IISI_-Y2!OSzZ z$2u?q@(0$)?>miwva6=Co2Fs)8-eFf=vg0+M%hDoM=GzaAC|X1-vAk^_AX4<=IDhEEc3E zj`jHl$iB)qS^3zW6@Z0p&-T-BE0229&i2RITlWES0K#db2Pz-$jSSd{%?EA#Ae{AV ze5&$KQ~o$^v|*-SKkY`Dp}aGdmuVM3PaC!R&q5sWsGt4-nT`Dcn~pEiOz`= zM8^f=&NShSBYl0DY-=gg+RfRj*W|imw7Fefi}JgTRMgf zlXR{_$Ij;i&t}Q5vhkENMY5S36yex{I64m-sztw^g?pUQo6y~1;={1t- zDHdTs39Cbh19?uX#4&GSIP2Is(w-@oivT_fyI4xe?m`$y3@(OlR|zttSYLwYVgB+C z`+O;$FZP$W+vm&hJTiz1l=XI7G@h3u+#a)n>Pp&Iy|sNE%bjfuPuqU+UZg?RK`!gq zmAHoEf4}Lf*gffOILn*&wm-NU&%}=HA^SwO@z)@X@~(}^ARYNm*Y>U1(3&}%u{E{7 za=w`CN~@hPY_N1@ve~E{noxG-o?>3smnx; zI9=q5&!As=z?Uu3zU+ITCoc~R#=n(XU^L=@uJCMRlf!ts4WEc$M z_>)B@P7!(ebm+M_kb9Q}a?k2OPM;w1*e$+XfnPyxIM0^_&tfhec(TtT$o@$n`@iSQ z>n{Xy_|t(r_6LzSp9Ae$PiDRD$@&L98M})o*IyIJ@cUqKULZI9NaP!P2eQwep4|EX z=8O+}a@ePQ8F~(Sy>Y%2ZuRBPZ$QpPfqdZwPyX_wKz^PPdG|U`w%J7F#w$dgDfn`T zAIRTM_GIX3B1gR*$S(tteUSDm(B~(&iA)>r%XcRQvfZ;H!^iq^$wE&aSSvE(a$nvU zf)ZIE(g_{Ey{jirjrZkR&1Zh=kz)tARtLf#{=OZ-AG zdrTl-LfH-5$(QdR?#VY!@?^~bUw;2rPmX#AX?_K5AIk8XqkYL85Xkx~fHN%P@Tnr3 zZ3yHvM*V6kAXFOS{k$q!BpWWlE}9(&c3o7Ri84)Ej= zj6BwzhBEvy<{bYfvM1!Og+1*zJdpc9|HJF>tHRru7r{Puy3v#EANA#D?|ZW6Z&0?s z_T;KkAaC7|yu)sGKi89|ABFv)jIM<)$CiBg>JEV%_M9gzC;RecVEhVr#yuLycaQYs zu7oG=KIu!_Y_LP$2d?zwn9qv*YExgjp7G?;%{`fVR3OQb7!%*<%ge|3vI6PMcp3Au z$s&u!1u|fF*w*=;?ENZiWM>q?AYV>75V+hba(XMq@bav&e9fF1ln2P13PXv-V1^GQ8kms*N8KU0YhVp*`Qku+`-m^2k^jp#6`6ElAYWbQ%X!}xS>Nf)C$~hM0w&G5KsG)X z$TJy{A6?{2D;#|M@d;0UgnGF8^S=D<&_KSC_vF6KeOWTym$|_E&94P=RU_>6Voz55 z+Lt4r@nv&h@ZA$V+3sqQ=eI`_@hwk&zZ-0IBW(LmXf)pS<^821H~09`fVzF*5|Qgp z_2tPoe7POAc%bLWeuG6GpNu-Y25l_(m*Bp&HIT2*hkb5|IyS+RV}biw(CtCQHC~GL zZm=h>1HX4Z=gWzoLmk^QkaPD(TX78XTZEmRjS90P${rZLdoOq=2lA=U1u_=4`z@5+ zQ(K69>JiY+2;_TLBJEf4{0m>c)57u-Ie*7MuD?U11NG!2v~ok=6xlZq{;8fk`w-fL zhkV&36UgNc1ab$;_tdL>*$#E}q)P*t1G^m!eDAsealc30S3TJu?bbc#irnL)-0uuz z)JTytuJh%NWFXhHiLCt(w22D?xf2jJzZQrOd&t7B*FA{w@Oz&8>TX}gHu$n0_apw~ z%SFRInT@brVPl6qf;zLplOMAYKMXcA8THGDO?}0e7lw%p++F00Y1Fk*f$Vss$YPYu zf4uC==ikA2WiyNq&hq7@cLLb}-5*9hpZ`iAe|-(*^OP??2mZhMjxX6BPf{OvvJ2YX zdwT-8`)$;Xc2C~l2KF$>lXK^aJOx~ihP~~9e0}v`PYS5#o1rdUag#5Dlb$?!1?m*e z&U-|D+w9A??h9n@wrJZ=4rJdo&|UkheYb=yH{;nI4grUNL%<>65O4@M1RMhY=?Dyh z#CbRm!P$T@DUYi@A+kNLmp5WAfMN7DxaZIkLq+_ShWQRo{x*VPyKIgVB=}u~zm>Sd zA>a^j2si{B0uBL(fJ49`;1F;KI0PI54uOv&0(iA0b8yDz|1azk&HtBTa?dp65O4@M1RMem0f&G?z#-rea0oaAK5ht{{YR`Z z{UX+it_!4m0@lVp>&x=11G(haSm*sX)(@}7`sB^9b`)z&*WZja=0Ef0{x4!Z@Y`6I zy$1Up9`|H0)~OzMN#NH1dv5)|TmSFY|GV}7ZvDSo|Nn98>770f0f&G?z#-rea0oaA zLIh&2O{UNv3jH0FO;qIX;0C z7hQF|TXnVhA{}v$@bl$+O8b4KwPi$FVqoccT0&r%xT?XMO7YdlbGEw)D&W zc#hKZPbK0XOv^6{Sd|3vwITHy=xUQOr8gG%?1(%JkFYo=3c zbB`$fqe{;-!@NeiKBjTj&k=pB7~QBEa{jo=_=VElrM3~)gXM5JnaSs3zB?KuwKSQ_ zrL(2T4hBh)-hqtI59&IY{!vrAdnC5alFE0a;hYHGLkf^ZKSbE0+cMJs7^n5;#q~_AC(kPVb4pKM`n!qS z`3vL&H8Bfq1wJyA@5LA&=|a9>Xfx<(^Vq(>;XL(S6#9&z|CZ4Cr?r(qVcSwt=P_~H zBCT;CV`;;7DN%7E!*J$ln7|8XCfAi%o`kuEWkEkh&C*p&=6c{()kIWekF@kQRrT#d z``pXMnUo{{LSt=s0q%m}QpxHx!G>3~3VHqjJSJ)TYHgYLE%3s2ILujOH%q*9BA-wj z16`ZfUU{Zo$9UC#jTqM9vCYlpt$el#OA$r|5o+?wu!5&J6hc2n^nV3@{}t$HkCmSB zofC7FRq2OHu|VxVLtlR^bJ|wiHvWWX+R>kJr9IU585VYL2FR$l<71`2drkRmzreI! z#~Dv+1D=`IMx`xQ^>@-e(wB8-_on4144 zbg;)r+D(*p6#NQuucplhb+#w#o6Q$-h-_yQ*-YgORyjK9nS)~f&$b4C6aAgpwhPb0_>4Bi z)@{mx-N7fCZM34cV^A#P~n7F!xVPm;xz_HRGQRmDw_6r8Z7i;HbuKtHRGdNdFI;*RS{!}(X#RxOdP zY)?9Y!9ds+vMi60a;Cc`Y^ii+^Z8;(sQQz(03TzeFx2FiYH+O|)o-2t(R-R*$qL6R@D$I2dkWmWm^6)XF( zv9hP_OrR{f7mV4{B{nx7EVC(n*vG6I`(QnrCz0lQHrbC)N!lCbbBu3&nKna)wYN`H?!!KZ7?LL( z1A6e4724>oHFVXs?8)v*w};Y2b{@^;_N){4IO+*)Z*(Ot96M0H?W1TH?4!mYjI=FE z%X``=^Ac~9$096BAAYoyZ(M~o%AcKQPS7~pr+UzfxH0WWRv;5q);>y49q7|B)WME{ zBdjMY-69=(Tm@R8?Q|qMdvYn$PV)DG&_8Ds_G$28u8_@_(qW+18J5>DDW|j9Fqn41 z`NDn(w+H6iAL=vI;>B?|PgCZoFU0u($YQ<@#5J^&&^9>6im>qHAf=mHq4S%lH+ih@ zY}P^cz5C-Np2RAWF+gUhjG4-3^&&k_(y}b5*DR%-U7-zz77#=IVXyG78~Vd1eLT%5 zy#|@1G7eQ4c0Np=h|ZI_N;j{PR%n;(o2zZYmm`#Rehn>ksHI(~w2LaVwto6zr8`#X7)R{m`ORvaO_yx}ZHy=Fjy$jn91W6F zd3oir>26s?=gDzOS5&%4r^pv|xmE^Jh|=<8xyo3fbn!7L=ld3y$`xS+&|00TKRt}B zQaQ(~9O&FM1u^z_suMJvX`hIDVq?qXB#pE6kY!@Vst6}ewp>Dd2FPlJvD{BqzTHum z=;wsAmcF7d!kHe=DBpwR6g*SL8eG{1)Y{q)phJXbAg3z*mz3Vted65O4@M1RMhY8VI=c|IYuv^Z$=IjPw8R{Qo=u|IYvazecz3a_JCo2si{B0uBL( zz`rm8oBg!ao5cL%UCPyXm+&CI-G^0eAK<+@{)cbK&cM3}o**&b1R%M73l^_N;zuHr z$7>Ap-XXlj>YDHyt7O*q=}pIh#lFY$HJsn3#|n{JdH>M2=^Iq0eg9|Q{{#phfRpc| zqW4<^q!D3!cQ;V^cyDAhcvAm+sEN2<=3|dsj?^m@xu>j6Rc?QI?C!~yGki}JE&-0j zRYz3t9IP@&>AR-Q@GM-zW7c?w>)$p<*dXa{w_!{l0Q*A>ZCGyn)^4g;PMDQK=|mxK zmfeIOTdfQLtx`7VcYgh?VrdVO`u5U@_pj8B zW%Nmu6_0Je$FzpxN;|Ue3b({_6V6R=R+npoY=?wVJdcenXnq`gYVPJFA>sDssFgV|!W$X!qfFu069}oOQsyCymSRJB@*| ztERD=reXCPf#*-?Ss#x^*+Y3pDzB{{mbX6N02!rxqm|FT+pbR^$QY$>QF>ceOs76i zgN#+4R^_qzvRK$_@A}&)tO z!gg*y4Y%^BH|>n?)qCqcKn_4SZS+9p_jvH;5>DN!Y zQD!LbOyy>^7JD5f_tuIF@ZJW~C z{9DZIwYTjw%F)W3P+prKrqfq`lFHMrJaNo=>xXZhDt%h%S=NEti0MOX+UKQ8$2ijQ zux2%CD0&2#NM54QO+@y|h z&==lgj4(ukq12I>f*tDp>Fdj6TT7YNZq8P{ z>aQ1{+tsxwUu@5m5;HUS@;gUV)j`lQY_repR}S~%@GIQ9Kwj6K$AXNU`s>a=Y~P*V zw6@>0mH$KbzOgP`sB-F$S4|#bTb1m}Amjhr4}A7TAJ*W~sd$18t7 zYqjh1efV15yL2x}xQ2^E@lw90h+Px0b@t)<;$%ClptA3)NwAdznz_vk*pZOso|BT<=dms3BbOuG9(;7LP7bRew9htn@IGoQVmX}r(ikNbCCa|BxrpNJUFS?Kn<N3HgxB5ScaMi_bhOX#iX}E5@7w+5|0r^&Ej!{;mU^}RTHlN&Y5Npk`p(|{|YzOs!QFlRFMas%ipqlOj5JpBULyuE1S!j9LJU(_r| zX~pVOEUjd=)3_Ok==#&0{s62kanBC=yY#YHe)xM=ud-58V0qa5tXG}6qdJie+j}eb zr-*~ua(`XL1}4;zTUt>{C3Bq>n!kZY%P!mu9BVNwR)39XA`CJe>Z~KGZyP}us}rHT zLYP-;D}Sz~=}K3X*{wF7BfYS;R_b$I`E2}vk;Q>~Wjf84rKqgAx3QNUn}!id$MEIv zPKiX4Kf~eo({OK-)w`y?_i9J#mtlx?-STU%EdY75%U) z;i~qfpZbp`KC;_>`vSBt7FX`W;)ns}RVk0Adbk=bBKh@kiP|rVZ>)?=$)LSJYxxo7 zpwF_HRM}71Dp&GwD)7Wk&(65Le2utsD;v_Xc`bkr?R}0eXD}W%ZOP2ZZQZ3+rHK>T zvYGbKnA+e4Wc;|cMf1mvZ51t^49;THAtrK3i%#bUtod zC$x;)w`Kg;*74)p+B3PfS@}|V$)t&GE0M~yIW6gxkn^g_8Ix)rGrOJ=nOrK{(~+)? zMLlfmJ8Dd8%lMXY{SZ_~rLb|ejS`XfD#1r)n#bhw*?d>NdCcPRIG2oR9@CLYc42s3 z&ZJ6{Q~7L9cdmKN+;KSDTk#JZ(-+S^Y&-&{A2xl))P)D*CV`OYa~IE-4ex7y8Mtu% z5!2_)!QGtMQy0xWV(RSqGiT44k(jY$-rOS=%qPX7X_Lk#7S22Ph=Zoj*njNGvHP@+ zHH?SNo;G*-4BRfXcL#Svvl+8W{0Arxo!&g=V2J1}OvXO*RHg&~k4#Nofvw5KMA_VT z=8N+&*a#ysISk8ji@hl6A~wTLW^NDeXdbg*TJxBhI5DKj7mMjazF3CDJcj2ek&jyV zT2Qo0Ti$;Mce0%A?o7o>tXHxJ^{mWfGs)sAT4H1sBc@Gmn^(-k@kVzu=jNs6kt-)n z+_P=5@orOUJ_H-w+hE$WLleVo%h;B2W5-XJ)H1fM2hHS&dRkT`wh*;=0Y(h3DlAr>E^OjY^z3vQ}V_^3j|QaWtLf|*O^Pd}t>Ld&E| zdG!#XipBoD*7%RGR-0l~e*06T%490`8EO6@xPBx8wWV}* zpWo3^=xFD=*KG#~N8=CRlz*YD@!^0xGz3fZw4w0WHeYtZn=0Tfz^3(?S zVw~p74S(}w(32uxLmm0W(}BEycpw*?97yM@o{TMclDW#0bXy?X--maETL&`rcY!>E zxURV(dlUk>858?&w|VBbmbPbnd3LlXe|lWxz25|K=6jypfFBB9I$GrS$9ZzyP9m+> z!_VRqfy_HIkjp-YwG){@Hr(Y)%l)400i7OND{{|zkx%~;vbOf*4Dg(KRv^b+?n(Y@ zzP$Jr{2Z(gdcu>1^F6s0y3F|s-ihuS z$Q{sQ&5^!L+%u3_OGPexERbJfrNj8!5x%P@7tajj-2*%s`DyHBUgt}5DUk0k@T7GI zPj=Zdkm5}E;=0C{Z%xLF3dnf(G+&mT;z`RleQ6)%OT*R3!$H2h`MxJ_JnYGN13kGh za^j2si{B0{`s@ta}Q6mv$6cbc!#-ah-LyCl}y)^TI&Bj_Vay__7w)YjDok$Cu}E zeHrItIDdz;8FRSZagM}!3Ff8yyb#En2VoAi627L|F|Wk@_2-)e@&V?k-@6AssVDfd z;VsND_Y`^m2fjSUUw#&N za>^E%v!39~eVG4U`YT^^7$d2+=D#th`H2ht^4N?a0oaA90Cpjhk!%CA>a^j z2si}(OAv7T|K0w7xBoxf*W>p8*V|+6_WyGa828s<2fy3@k996_Jly{O+CBXZ;`aY@ zAEn#>@1w=Q&-<0{ZSbD^NZtN_xBovsWs2EL?DqdJ0}>m}H{N>t4RHJa-TwdjemmU$ z|8m;;m*Cj+AKm}&-v7Jz|8D*N|G)MB?)|?R^tyiz0f&G?z#-rea0oaA90Cpjhrq`G zf%yCXr?Dn^=_jzayvF}Owt@>!E?r)YD~}`8x4}Q_%B77ye((aiWohVBZVM)Y6Wgoh z$p7Rt5-W`FK_s=&_^;a<>G(LYjX|brTD_cf^x-#2y@j-;ySw4O5H1WMl|J##g1iQt z;~}#@A5NBET{^|QLWFXzfQ&|**kV8*xxIZs#rz=|7fE=w7+w!P`sKq`c%##u`aBBH z@Kf7cmMT%BQ!3w)PFb1sn?Rq7JE+Xx=rgw9n>7BYX-v@Pzv%O4^?4}#U6CJK><#@c z`V5x^=6QcSGrzmzd6fFm8;a*d_+^rS6Gu)f zQ~9j^skn|caaDP1HCRUOHsk5l@KxozCeGyB>O%ki@Zg!U%EV>X#*xwDwNJvL#ddtG!!) z+gWk_9MMRxv{h8BooXaaXS$qPii{=kDHr%=v^s3UIQmP3Uu)wtIP|DpX_E&t9uC;k zsd55d?N%gD`!vAbtjkM+c#-;I`H+H>{u0HWa8Jz#c7wVqO!2@hDpGueD-5AcN;WRfYyK@X33vc3t#EN2)ek!dU&14*2Lo)f+Sa_&Y z7(T8hoNq0y|6!X)%26?i$OCrd`|;2yzS2&f7lwuIIf0keX;B!y)Ov%pwnUwfh7C9V zHfz$yOQUjs=`+59t;#bz#zkmM2i60m75a~dO<3J*IKVUx*KPQcP&YUgHx6toWv}!a z4r_v!-&{E=d*xH>?dfhu)w20*3uP9QD-z{=Ia$@_Y8*US_l`R<o(;69J%X*A_ zQKs>FYVp%>$}_dx)Z!Q(HSrZ4PmiT#1jg*XHZH9GkuK-Q@<&gh7E28`d1JW6V{I%g z<60DHS>K}BFwS^BwsI~A!|c}uDrIsk!k5C4W&*Cj+cRAWc*V~ob5WTbAM&x5Cg8{n zo+%@Ltrtac6}>Kr!V;a?e3Es~>aYfJtY4)! zC#x(p&+twj$+|2|KUK_^N{q0wzNGZ1^`=bYaW!_3s1sMQ1;*KSx5f@kks4-{g-!QN zO_!}9It;Q`uvro-rDwh+C08; zQQJ@0c>2++#KUW6t|tqJqmi%h{(SzjPqw-zAg9*fblBTR_HzaF>{LJKc5FX7(mnD6 z9c$&Ro_j=ep)X(c<80&U6;ClR{=#j4Ve7~W#G^qo{&y{I^!3lYBjHp6-?r<7v0M7% z5eHpY#{C-C^KG6mpG?T-vgp$+FTbe*Uh|y_t6x<)r1H6PCf7sX{}#WxIGfQ@B$wZm z!57zzPBsr!zKPYpv6boO|8D+o{Yty}Kia40w}Gm;ke$oxT*%CKY`^yXx@j zIhoF@-TXf`CwKGzXw2f~|Iv7}9erBmcL6v5H^1My`G5EutDFC)EAtsQ|BvQaZvKxS z2HgDLw3TlDk8h<#b7MFEFX4Aae520I|3%iew0gI_*OF?$d)KYsxOT$LZ|*ha&UJr& zrR$o5Z|Aoa_Ris}X(fTU({W;0s8YkS~3+Xq(iJy~X zFwV_!a!UYzE5K_ScQ^zb0uBL(fJ49`;1F;KI0PI54grUNL%<>MF+^aSkD*RZC5M1R zz#-rea0oaA90Cpjhk!%CA>a^j2si{B0uBL(fJ49`;1F;KI0PI54grUNL%<>65O4@M J1pYn*{vVH2NF4wG literal 0 HcmV?d00001 diff --git a/extern/src/libdeflate.h b/extern/src/libdeflate.h index a13ac71e..74c65bea 100644 --- a/extern/src/libdeflate.h +++ b/extern/src/libdeflate.h @@ -10,15 +10,15 @@ extern "C" { #endif #define LIBDEFLATE_VERSION_MAJOR 1 -#define LIBDEFLATE_VERSION_MINOR 12 -#define LIBDEFLATE_VERSION_STRING "1.12" +#define LIBDEFLATE_VERSION_MINOR 14 +#define LIBDEFLATE_VERSION_STRING "1.14" #include #include /* * On Windows, if you want to link to the DLL version of libdeflate, then - * #define LIBDEFLATE_DLL. Note that the calling convention is "stdcall". + * #define LIBDEFLATE_DLL. Note that the calling convention is "cdecl". */ #ifdef LIBDEFLATE_DLL # ifdef BUILDING_LIBDEFLATE @@ -31,12 +31,6 @@ extern "C" { # define LIBDEFLATEEXPORT #endif -#if defined(_WIN32) && !defined(_WIN64) && defined(LIBDEFLATE_DLL) -# define LIBDEFLATEAPI_ABI __stdcall -#else -# define LIBDEFLATEAPI_ABI -#endif - #if defined(BUILDING_LIBDEFLATE) && defined(__GNUC__) && \ defined(_WIN32) && !defined(_WIN64) /* @@ -44,13 +38,11 @@ extern "C" { * Realign the stack when entering libdeflate to avoid crashing in SSE/AVX * code when called from an MSVC-compiled application. */ -# define LIBDEFLATEAPI_STACKALIGN __attribute__((force_align_arg_pointer)) +# define LIBDEFLATEAPI __attribute__((force_align_arg_pointer)) #else -# define LIBDEFLATEAPI_STACKALIGN +# define LIBDEFLATEAPI #endif -#define LIBDEFLATEAPI LIBDEFLATEAPI_ABI LIBDEFLATEAPI_STACKALIGN - /* ========================================================================== */ /* Compression */ /* ========================================================================== */ diff --git a/extern/src/ogg/ogg.h b/extern/src/ogg/ogg.h new file mode 100644 index 00000000..c4325aa7 --- /dev/null +++ b/extern/src/ogg/ogg.h @@ -0,0 +1,209 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: toplevel libogg include + + ********************************************************************/ +#ifndef _OGG_H +#define _OGG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct { + void *iov_base; + size_t iov_len; +} ogg_iovec_t; + +typedef struct { + long endbyte; + int endbit; + + unsigned char *buffer; + unsigned char *ptr; + long storage; +} oggpack_buffer; + +/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ + +typedef struct { + unsigned char *header; + long header_len; + unsigned char *body; + long body_len; +} ogg_page; + +/* ogg_stream_state contains the current encode/decode state of a logical + Ogg bitstream **********************************************************/ + +typedef struct { + unsigned char *body_data; /* bytes from packet bodies */ + long body_storage; /* storage elements allocated */ + long body_fill; /* elements stored; fill mark */ + long body_returned; /* elements of fill returned */ + + + int *lacing_vals; /* The values that will go to the segment table */ + ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + + unsigned char header[282]; /* working space for header encode */ + int header_fill; + + int e_o_s; /* set when we have buffered the last packet in the + logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + long serialno; + long pageno; + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ + ogg_int64_t granulepos; + +} ogg_stream_state; + +/* ogg_packet is used to encapsulate the data and metadata belonging + to a single raw Ogg/Vorbis packet *************************************/ + +typedef struct { + unsigned char *packet; + long bytes; + long b_o_s; + long e_o_s; + + ogg_int64_t granulepos; + + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ +} ogg_packet; + +typedef struct { + unsigned char *data; + int storage; + int fill; + int returned; + + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/ + +extern void oggpack_writeinit(oggpack_buffer *b); +extern int oggpack_writecheck(oggpack_buffer *b); +extern void oggpack_writetrunc(oggpack_buffer *b,long bits); +extern void oggpack_writealign(oggpack_buffer *b); +extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpack_reset(oggpack_buffer *b); +extern void oggpack_writeclear(oggpack_buffer *b); +extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpack_look(oggpack_buffer *b,int bits); +extern long oggpack_look1(oggpack_buffer *b); +extern void oggpack_adv(oggpack_buffer *b,int bits); +extern void oggpack_adv1(oggpack_buffer *b); +extern long oggpack_read(oggpack_buffer *b,int bits); +extern long oggpack_read1(oggpack_buffer *b); +extern long oggpack_bytes(oggpack_buffer *b); +extern long oggpack_bits(oggpack_buffer *b); +extern unsigned char *oggpack_get_buffer(oggpack_buffer *b); + +extern void oggpackB_writeinit(oggpack_buffer *b); +extern int oggpackB_writecheck(oggpack_buffer *b); +extern void oggpackB_writetrunc(oggpack_buffer *b,long bits); +extern void oggpackB_writealign(oggpack_buffer *b); +extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpackB_reset(oggpack_buffer *b); +extern void oggpackB_writeclear(oggpack_buffer *b); +extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpackB_look(oggpack_buffer *b,int bits); +extern long oggpackB_look1(oggpack_buffer *b); +extern void oggpackB_adv(oggpack_buffer *b,int bits); +extern void oggpackB_adv1(oggpack_buffer *b); +extern long oggpackB_read(oggpack_buffer *b,int bits); +extern long oggpackB_read1(oggpack_buffer *b); +extern long oggpackB_bytes(oggpack_buffer *b); +extern long oggpackB_bits(oggpack_buffer *b); +extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b); + +/* Ogg BITSTREAM PRIMITIVES: encoding **************************/ + +extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); +extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, + int count, long e_o_s, ogg_int64_t granulepos); +extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill); +extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill); + +/* Ogg BITSTREAM PRIMITIVES: decoding **************************/ + +extern int ogg_sync_init(ogg_sync_state *oy); +extern int ogg_sync_clear(ogg_sync_state *oy); +extern int ogg_sync_reset(ogg_sync_state *oy); +extern int ogg_sync_destroy(ogg_sync_state *oy); +extern int ogg_sync_check(ogg_sync_state *oy); + +extern char *ogg_sync_buffer(ogg_sync_state *oy, long size); +extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes); +extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og); +extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og); +extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op); +extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op); + +/* Ogg BITSTREAM PRIMITIVES: general ***************************/ + +extern int ogg_stream_init(ogg_stream_state *os,int serialno); +extern int ogg_stream_clear(ogg_stream_state *os); +extern int ogg_stream_reset(ogg_stream_state *os); +extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno); +extern int ogg_stream_destroy(ogg_stream_state *os); +extern int ogg_stream_check(ogg_stream_state *os); +extern int ogg_stream_eos(ogg_stream_state *os); + +extern void ogg_page_checksum_set(ogg_page *og); + +extern int ogg_page_version(const ogg_page *og); +extern int ogg_page_continued(const ogg_page *og); +extern int ogg_page_bos(const ogg_page *og); +extern int ogg_page_eos(const ogg_page *og); +extern ogg_int64_t ogg_page_granulepos(const ogg_page *og); +extern int ogg_page_serialno(const ogg_page *og); +extern long ogg_page_pageno(const ogg_page *og); +extern int ogg_page_packets(const ogg_page *og); + +extern void ogg_packet_clear(ogg_packet *op); + + +#ifdef __cplusplus +} +#endif + +#endif /* _OGG_H */ diff --git a/extern/src/ogg/os_types.h b/extern/src/ogg/os_types.h new file mode 100644 index 00000000..e655a1d6 --- /dev/null +++ b/extern/src/ogg/os_types.h @@ -0,0 +1,158 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: Define a consistent set of types on each platform. + + ********************************************************************/ +#ifndef _OS_TYPES_H +#define _OS_TYPES_H + +/* make it easy on the folks that want to compile the libs with a + different malloc than stdlib */ +#define _ogg_malloc malloc +#define _ogg_calloc calloc +#define _ogg_realloc realloc +#define _ogg_free free + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; +# elif defined(__MINGW32__) +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; +# elif defined(__MWERKS__) + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; +# else +# if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */ +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; +# else + /* MSVC/Borland */ + typedef __int64 ogg_int64_t; + typedef __int32 ogg_int32_t; + typedef unsigned __int32 ogg_uint32_t; + typedef unsigned __int64 ogg_uint64_t; + typedef __int16 ogg_int16_t; + typedef unsigned __int16 ogg_uint16_t; +# endif +# endif + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t ogg_int16_t; + typedef u_int16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef u_int32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef u_int64_t ogg_uint64_t; + +#elif defined(__HAIKU__) + + /* Haiku */ +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short ogg_int16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + +#elif defined(R5900) + + /* PS2 EE */ + typedef long ogg_int64_t; + typedef unsigned long ogg_uint64_t; + typedef int ogg_int32_t; + typedef unsigned ogg_uint32_t; + typedef short ogg_int16_t; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + typedef unsigned long long int ogg_uint64_t; + +#elif defined(__TMS320C6X__) + + /* TI C64x compiler */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + typedef unsigned long long int ogg_uint64_t; + +#else + +# include + +#endif + +#endif /* _OS_TYPES_H */ diff --git a/extern/src/vorbis/codec.h b/extern/src/vorbis/codec.h new file mode 100644 index 00000000..f8a912bc --- /dev/null +++ b/extern/src/vorbis/codec.h @@ -0,0 +1,242 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the Xiph.Org Foundation https://xiph.org/ * + + ******************************************************************** + + function: libvorbis codec headers + + ********************************************************************/ + +#ifndef _vorbis_codec_h_ +#define _vorbis_codec_h_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include + +typedef struct vorbis_info{ + int version; + int channels; + long rate; + + /* The below bitrate declarations are *hints*. + Combinations of the three values carry the following implications: + + all three set to the same value: + implies a fixed rate bitstream + only nominal set: + implies a VBR stream that averages the nominal bitrate. No hard + upper/lower limit + upper and or lower set: + implies a VBR bitstream that obeys the bitrate limits. nominal + may also be set to give a nominal rate. + none set: + the coder does not care to speculate. + */ + + long bitrate_upper; + long bitrate_nominal; + long bitrate_lower; + long bitrate_window; + + void *codec_setup; +} vorbis_info; + +/* vorbis_dsp_state buffers the current vorbis audio + analysis/synthesis state. The DSP state belongs to a specific + logical bitstream ****************************************************/ +typedef struct vorbis_dsp_state{ + int analysisp; + vorbis_info *vi; + + float **pcm; + float **pcmret; + int pcm_storage; + int pcm_current; + int pcm_returned; + + int preextrapolate; + int eofflag; + + long lW; + long W; + long nW; + long centerW; + + ogg_int64_t granulepos; + ogg_int64_t sequence; + + ogg_int64_t glue_bits; + ogg_int64_t time_bits; + ogg_int64_t floor_bits; + ogg_int64_t res_bits; + + void *backend_state; +} vorbis_dsp_state; + +typedef struct vorbis_block{ + /* necessary stream state for linking to the framing abstraction */ + float **pcm; /* this is a pointer into local storage */ + oggpack_buffer opb; + + long lW; + long W; + long nW; + int pcmend; + int mode; + + int eofflag; + ogg_int64_t granulepos; + ogg_int64_t sequence; + vorbis_dsp_state *vd; /* For read-only access of configuration */ + + /* local storage to avoid remallocing; it's up to the mapping to + structure it */ + void *localstore; + long localtop; + long localalloc; + long totaluse; + struct alloc_chain *reap; + + /* bitmetrics for the frame */ + long glue_bits; + long time_bits; + long floor_bits; + long res_bits; + + void *internal; + +} vorbis_block; + +/* vorbis_block is a single block of data to be processed as part of +the analysis/synthesis stream; it belongs to a specific logical +bitstream, but is independent from other vorbis_blocks belonging to +that logical bitstream. *************************************************/ + +struct alloc_chain{ + void *ptr; + struct alloc_chain *next; +}; + +/* vorbis_info contains all the setup information specific to the + specific compression/decompression mode in progress (eg, + psychoacoustic settings, channel setup, options, codebook + etc). vorbis_info and substructures are in backends.h. +*********************************************************************/ + +/* the comments are not part of vorbis_info so that vorbis_info can be + static storage */ +typedef struct vorbis_comment{ + /* unlimited user comment fields. libvorbis writes 'libvorbis' + whatever vendor is set to in encode */ + char **user_comments; + int *comment_lengths; + int comments; + char *vendor; + +} vorbis_comment; + + +/* libvorbis encodes in two abstraction layers; first we perform DSP + and produce a packet (see docs/analysis.txt). The packet is then + coded into a framed OggSquish bitstream by the second layer (see + docs/framing.txt). Decode is the reverse process; we sync/frame + the bitstream and extract individual packets, then decode the + packet back into PCM audio. + + The extra framing/packetizing is used in streaming formats, such as + files. Over the net (such as with UDP), the framing and + packetization aren't necessary as they're provided by the transport + and the streaming layer is not used */ + +/* Vorbis PRIMITIVES: general ***************************************/ + +extern void vorbis_info_init(vorbis_info *vi); +extern void vorbis_info_clear(vorbis_info *vi); +extern int vorbis_info_blocksize(vorbis_info *vi,int zo); +extern void vorbis_comment_init(vorbis_comment *vc); +extern void vorbis_comment_add(vorbis_comment *vc, const char *comment); +extern void vorbis_comment_add_tag(vorbis_comment *vc, + const char *tag, const char *contents); +extern char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count); +extern int vorbis_comment_query_count(vorbis_comment *vc, const char *tag); +extern void vorbis_comment_clear(vorbis_comment *vc); + +extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb); +extern int vorbis_block_clear(vorbis_block *vb); +extern void vorbis_dsp_clear(vorbis_dsp_state *v); +extern double vorbis_granule_time(vorbis_dsp_state *v, + ogg_int64_t granulepos); + +extern const char *vorbis_version_string(void); + +/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/ + +extern int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi); +extern int vorbis_commentheader_out(vorbis_comment *vc, ogg_packet *op); +extern int vorbis_analysis_headerout(vorbis_dsp_state *v, + vorbis_comment *vc, + ogg_packet *op, + ogg_packet *op_comm, + ogg_packet *op_code); +extern float **vorbis_analysis_buffer(vorbis_dsp_state *v,int vals); +extern int vorbis_analysis_wrote(vorbis_dsp_state *v,int vals); +extern int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb); +extern int vorbis_analysis(vorbis_block *vb,ogg_packet *op); + +extern int vorbis_bitrate_addblock(vorbis_block *vb); +extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd, + ogg_packet *op); + +/* Vorbis PRIMITIVES: synthesis layer *******************************/ +extern int vorbis_synthesis_idheader(ogg_packet *op); +extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc, + ogg_packet *op); + +extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi); +extern int vorbis_synthesis_restart(vorbis_dsp_state *v); +extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op); +extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op); +extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb); +extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm); +extern int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm); +extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples); +extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op); + +extern int vorbis_synthesis_halfrate(vorbis_info *v,int flag); +extern int vorbis_synthesis_halfrate_p(vorbis_info *v); + +/* Vorbis ERRORS and return codes ***********************************/ + +#define OV_FALSE -1 +#define OV_EOF -2 +#define OV_HOLE -3 + +#define OV_EREAD -128 +#define OV_EFAULT -129 +#define OV_EIMPL -130 +#define OV_EINVAL -131 +#define OV_ENOTVORBIS -132 +#define OV_EBADHEADER -133 +#define OV_EVERSION -134 +#define OV_ENOTAUDIO -135 +#define OV_EBADPACKET -136 +#define OV_EBADLINK -137 +#define OV_ENOSEEK -138 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/extern/src/vorbis/vorbisenc.h b/extern/src/vorbis/vorbisenc.h new file mode 100644 index 00000000..085b15e6 --- /dev/null +++ b/extern/src/vorbis/vorbisenc.h @@ -0,0 +1,435 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: vorbis encode-engine setup + + ********************************************************************/ + +/** \file + * Libvorbisenc is a convenient API for setting up an encoding + * environment using libvorbis. Libvorbisenc encapsulates the + * actions needed to set up the encoder properly. + */ + +#ifndef _OV_ENC_H_ +#define _OV_ENC_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include "codec.h" + +/** + * This is the primary function within libvorbisenc for setting up managed + * bitrate modes. + * + * Before this function is called, the \ref vorbis_info + * struct should be initialized by using vorbis_info_init() from the libvorbis + * API. After encoding, vorbis_info_clear() should be called. + * + * The max_bitrate, nominal_bitrate, and min_bitrate settings are used to set + * constraints for the encoded file. This function uses these settings to + * select the appropriate encoding mode and set it up. + * + * \param vi Pointer to an initialized \ref vorbis_info struct. + * \param channels The number of channels to be encoded. + * \param rate The sampling rate of the source audio. + * \param max_bitrate Desired maximum bitrate (limit). -1 indicates unset. + * \param nominal_bitrate Desired average, or central, bitrate. -1 indicates unset. + * \param min_bitrate Desired minimum bitrate. -1 indicates unset. + * + * \return Zero for success, and negative values for failure. + * + * \retval 0 Success. + * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption. + * \retval OV_EINVAL Invalid setup request, eg, out of range argument. + * \retval OV_EIMPL Unimplemented mode; unable to comply with bitrate request. + */ +extern int vorbis_encode_init(vorbis_info *vi, + long channels, + long rate, + + long max_bitrate, + long nominal_bitrate, + long min_bitrate); + +/** + * This function performs step-one of a three-step bitrate-managed encode + * setup. It functions similarly to the one-step setup performed by \ref + * vorbis_encode_init but allows an application to make further encode setup + * tweaks using \ref vorbis_encode_ctl before finally calling \ref + * vorbis_encode_setup_init to complete the setup process. + * + * Before this function is called, the \ref vorbis_info struct should be + * initialized by using vorbis_info_init() from the libvorbis API. After + * encoding, vorbis_info_clear() should be called. + * + * The max_bitrate, nominal_bitrate, and min_bitrate settings are used to set + * constraints for the encoded file. This function uses these settings to + * select the appropriate encoding mode and set it up. + * + * \param vi Pointer to an initialized vorbis_info struct. + * \param channels The number of channels to be encoded. + * \param rate The sampling rate of the source audio. + * \param max_bitrate Desired maximum bitrate (limit). -1 indicates unset. + * \param nominal_bitrate Desired average, or central, bitrate. -1 indicates unset. + * \param min_bitrate Desired minimum bitrate. -1 indicates unset. + * + * \return Zero for success, and negative for failure. + * + * \retval 0 Success + * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption. + * \retval OV_EINVAL Invalid setup request, eg, out of range argument. + * \retval OV_EIMPL Unimplemented mode; unable to comply with bitrate request. + */ +extern int vorbis_encode_setup_managed(vorbis_info *vi, + long channels, + long rate, + + long max_bitrate, + long nominal_bitrate, + long min_bitrate); + +/** + * This function performs step-one of a three-step variable bitrate + * (quality-based) encode setup. It functions similarly to the one-step setup + * performed by \ref vorbis_encode_init_vbr() but allows an application to + * make further encode setup tweaks using \ref vorbis_encode_ctl() before + * finally calling \ref vorbis_encode_setup_init to complete the setup + * process. + * + * Before this function is called, the \ref vorbis_info struct should be + * initialized by using \ref vorbis_info_init() from the libvorbis API. After + * encoding, vorbis_info_clear() should be called. + * + * \param vi Pointer to an initialized vorbis_info struct. + * \param channels The number of channels to be encoded. + * \param rate The sampling rate of the source audio. + * \param quality Desired quality level, currently from -0.1 to 1.0 (lo to hi). + * + * \return Zero for success, and negative values for failure. + * + * \retval 0 Success + * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption. + * \retval OV_EINVAL Invalid setup request, eg, out of range argument. + * \retval OV_EIMPL Unimplemented mode; unable to comply with quality level request. + */ +extern int vorbis_encode_setup_vbr(vorbis_info *vi, + long channels, + long rate, + + float quality + ); + +/** + * This is the primary function within libvorbisenc for setting up variable + * bitrate ("quality" based) modes. + * + * + * Before this function is called, the vorbis_info struct should be + * initialized by using vorbis_info_init() from the libvorbis API. After + * encoding, vorbis_info_clear() should be called. + * + * \param vi Pointer to an initialized vorbis_info struct. + * \param channels The number of channels to be encoded. + * \param rate The sampling rate of the source audio. + * \param base_quality Desired quality level, currently from -0.1 to 1.0 (lo to hi). + * + * + * \return Zero for success, or a negative number for failure. + * + * \retval 0 Success + * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption. + * \retval OV_EINVAL Invalid setup request, eg, out of range argument. + * \retval OV_EIMPL Unimplemented mode; unable to comply with quality level request. + */ +extern int vorbis_encode_init_vbr(vorbis_info *vi, + long channels, + long rate, + + float base_quality + ); + +/** + * This function performs the last stage of three-step encoding setup, as + * described in the API overview under managed bitrate modes. + * + * Before this function is called, the \ref vorbis_info struct should be + * initialized by using vorbis_info_init() from the libvorbis API, one of + * \ref vorbis_encode_setup_managed() or \ref vorbis_encode_setup_vbr() called to + * initialize the high-level encoding setup, and \ref vorbis_encode_ctl() + * called if necessary to make encoding setup changes. + * vorbis_encode_setup_init() finalizes the highlevel encoding structure into + * a complete encoding setup after which the application may make no further + * setup changes. + * + * After encoding, vorbis_info_clear() should be called. + * + * \param vi Pointer to an initialized \ref vorbis_info struct. + * + * \return Zero for success, and negative values for failure. + * + * \retval 0 Success. + * \retval OV_EFAULT Internal logic fault; indicates a bug or heap/stack corruption. + * + * \retval OV_EINVAL Attempt to use vorbis_encode_setup_init() without first + * calling one of vorbis_encode_setup_managed() or vorbis_encode_setup_vbr() to + * initialize the high-level encoding setup + * + */ +extern int vorbis_encode_setup_init(vorbis_info *vi); + +/** + * This function implements a generic interface to miscellaneous encoder + * settings similar to the classic UNIX 'ioctl()' system call. Applications + * may use vorbis_encode_ctl() to query or set bitrate management or quality + * mode details by using one of several \e request arguments detailed below. + * vorbis_encode_ctl() must be called after one of + * vorbis_encode_setup_managed() or vorbis_encode_setup_vbr(). When used + * to modify settings, \ref vorbis_encode_ctl() must be called before \ref + * vorbis_encode_setup_init(). + * + * \param vi Pointer to an initialized vorbis_info struct. + * + * \param number Specifies the desired action; See \ref encctlcodes "the list + * of available requests". + * + * \param arg void * pointing to a data structure matching the request + * argument. + * + * \retval 0 Success. Any further return information (such as the result of a + * query) is placed into the storage pointed to by *arg. + * + * \retval OV_EINVAL Invalid argument, or an attempt to modify a setting after + * calling vorbis_encode_setup_init(). + * + * \retval OV_EIMPL Unimplemented or unknown request + */ +extern int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg); + +/** + * \deprecated This is a deprecated interface. Please use vorbis_encode_ctl() + * with the \ref ovectl_ratemanage2_arg struct and \ref + * OV_ECTL_RATEMANAGE2_GET and \ref OV_ECTL_RATEMANAGE2_SET calls in new code. + * + * The \ref ovectl_ratemanage_arg structure is used with vorbis_encode_ctl() + * and the \ref OV_ECTL_RATEMANAGE_GET, \ref OV_ECTL_RATEMANAGE_SET, \ref + * OV_ECTL_RATEMANAGE_AVG, \ref OV_ECTL_RATEMANAGE_HARD calls in order to + * query and modify specifics of the encoder's bitrate management + * configuration. +*/ +struct ovectl_ratemanage_arg { + int management_active; /**< nonzero if bitrate management is active*/ +/** hard lower limit (in kilobits per second) below which the stream bitrate + will never be allowed for any given bitrate_hard_window seconds of time.*/ + long bitrate_hard_min; +/** hard upper limit (in kilobits per second) above which the stream bitrate + will never be allowed for any given bitrate_hard_window seconds of time.*/ + long bitrate_hard_max; +/** the window period (in seconds) used to regulate the hard bitrate minimum + and maximum*/ + double bitrate_hard_window; +/** soft lower limit (in kilobits per second) below which the average bitrate + tracker will start nudging the bitrate higher.*/ + long bitrate_av_lo; +/** soft upper limit (in kilobits per second) above which the average bitrate + tracker will start nudging the bitrate lower.*/ + long bitrate_av_hi; +/** the window period (in seconds) used to regulate the average bitrate + minimum and maximum.*/ + double bitrate_av_window; +/** Regulates the relative centering of the average and hard windows; in + libvorbis 1.0 and 1.0.1, the hard window regulation overlapped but + followed the average window regulation. In libvorbis 1.1 a bit-reservoir + interface replaces the old windowing interface; the older windowing + interface is simulated and this field has no effect.*/ + double bitrate_av_window_center; +}; + +/** + * \name struct ovectl_ratemanage2_arg + * + * The ovectl_ratemanage2_arg structure is used with vorbis_encode_ctl() and + * the OV_ECTL_RATEMANAGE2_GET and OV_ECTL_RATEMANAGE2_SET calls in order to + * query and modify specifics of the encoder's bitrate management + * configuration. + * +*/ +struct ovectl_ratemanage2_arg { + int management_active; /**< nonzero if bitrate management is active */ +/** Lower allowed bitrate limit in kilobits per second */ + long bitrate_limit_min_kbps; +/** Upper allowed bitrate limit in kilobits per second */ + long bitrate_limit_max_kbps; + long bitrate_limit_reservoir_bits; /**struct ovectl_ratemanage2_arg * + * + * Used to query the current encoder bitrate management setting. Also used to + * initialize fields of an ovectl_ratemanage2_arg structure for use with + * \ref OV_ECTL_RATEMANAGE2_SET. + */ +#define OV_ECTL_RATEMANAGE2_GET 0x14 + +/** + * Set the current encoder bitrate management settings. + * + * Argument: struct ovectl_ratemanage2_arg * + * + * Used to set the current encoder bitrate management settings to the values + * listed in the ovectl_ratemanage2_arg. Passing a NULL pointer will disable + * bitrate management. +*/ +#define OV_ECTL_RATEMANAGE2_SET 0x15 + +/** + * Returns the current encoder hard-lowpass setting (kHz) in the double + * pointed to by arg. + * + * Argument: double * +*/ +#define OV_ECTL_LOWPASS_GET 0x20 + +/** + * Sets the encoder hard-lowpass to the value (kHz) pointed to by arg. Valid + * lowpass settings range from 2 to 99. + * + * Argument: double * +*/ +#define OV_ECTL_LOWPASS_SET 0x21 + +/** + * Returns the current encoder impulse block setting in the double pointed + * to by arg. + * + * Argument: double * +*/ +#define OV_ECTL_IBLOCK_GET 0x30 + +/** + * Sets the impulse block bias to the the value pointed to by arg. + * + * Argument: double * + * + * Valid range is -15.0 to 0.0 [default]. A negative impulse block bias will + * direct to encoder to use more bits when incoding short blocks that contain + * strong impulses, thus improving the accuracy of impulse encoding. + */ +#define OV_ECTL_IBLOCK_SET 0x31 + +/** + * Returns the current encoder coupling setting in the int pointed + * to by arg. + * + * Argument: int * +*/ +#define OV_ECTL_COUPLING_GET 0x40 + +/** + * Enables/disables channel coupling in multichannel encoding according to arg. + * + * Argument: int * + * + * Zero disables channel coupling for multichannel inputs, nonzer enables + * channel coupling. Setting has no effect on monophonic encoding or + * multichannel counts that do not offer coupling. At present, coupling is + * available for stereo and 5.1 encoding. + */ +#define OV_ECTL_COUPLING_SET 0x41 + + /* deprecated rate management supported only for compatibility */ + +/** + * Old interface to querying bitrate management settings. + * + * Deprecated after move to bit-reservoir style management in 1.1 rendered + * this interface partially obsolete. + + * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_GET instead. + * + * Argument: struct ovectl_ratemanage_arg * + */ +#define OV_ECTL_RATEMANAGE_GET 0x10 +/** + * Old interface to modifying bitrate management settings. + * + * deprecated after move to bit-reservoir style management in 1.1 rendered + * this interface partially obsolete. + * + * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_SET instead. + * + * Argument: struct ovectl_ratemanage_arg * + */ +#define OV_ECTL_RATEMANAGE_SET 0x11 +/** + * Old interface to setting average-bitrate encoding mode. + * + * Deprecated after move to bit-reservoir style management in 1.1 rendered + * this interface partially obsolete. + * + * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_SET instead. + * + * Argument: struct ovectl_ratemanage_arg * + */ +#define OV_ECTL_RATEMANAGE_AVG 0x12 +/** + * Old interface to setting bounded-bitrate encoding modes. + * + * deprecated after move to bit-reservoir style management in 1.1 rendered + * this interface partially obsolete. + * + * \deprecated Please use \ref OV_ECTL_RATEMANAGE2_SET instead. + * + * Argument: struct ovectl_ratemanage_arg * + */ +#define OV_ECTL_RATEMANAGE_HARD 0x13 + +/*@}*/ + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/extern/src/vorbis/vorbisfile.h b/extern/src/vorbis/vorbisfile.h new file mode 100644 index 00000000..3d65393f --- /dev/null +++ b/extern/src/vorbis/vorbisfile.h @@ -0,0 +1,205 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + + ********************************************************************/ + +#ifndef _OV_FILE_H_ +#define _OV_FILE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include +#include "codec.h" + +/* The function prototypes for the callbacks are basically the same as for + * the stdio functions fread, fseek, fclose, ftell. + * The one difference is that the FILE * arguments have been replaced with + * a void * - this is to be used as a pointer to whatever internal data these + * functions might need. In the stdio case, it's just a FILE * cast to a void * + * + * If you use other functions, check the docs for these functions and return + * the right values. For seek_func(), you *MUST* return -1 if the stream is + * unseekable + */ +typedef struct { + size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource); + int (*seek_func) (void *datasource, ogg_int64_t offset, int whence); + int (*close_func) (void *datasource); + long (*tell_func) (void *datasource); +} ov_callbacks; + +#ifndef OV_EXCLUDE_STATIC_CALLBACKS + +/* a few sets of convenient callbacks, especially for use under + * Windows where ov_open_callbacks() should always be used instead of + * ov_open() to avoid problems with incompatible crt.o version linking + * issues. */ + +static int _ov_header_fseek_wrap(FILE *f,ogg_int64_t off,int whence){ + if(f==NULL)return(-1); + +#ifdef __MINGW32__ + return fseeko64(f,off,whence); +#elif defined (_WIN32) + return _fseeki64(f,off,whence); +#else + return fseek(f,off,whence); +#endif +} + +/* These structs below (OV_CALLBACKS_DEFAULT etc) are defined here as + * static data. That means that every file which includes this header + * will get its own copy of these structs whether it uses them or + * not unless it #defines OV_EXCLUDE_STATIC_CALLBACKS. + * These static symbols are essential on platforms such as Windows on + * which several different versions of stdio support may be linked to + * by different DLLs, and we need to be certain we know which one + * we're using (the same one as the main application). + */ + +static ov_callbacks OV_CALLBACKS_DEFAULT = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap, + (int (*)(void *)) fclose, + (long (*)(void *)) ftell +}; + +static ov_callbacks OV_CALLBACKS_NOCLOSE = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap, + (int (*)(void *)) NULL, + (long (*)(void *)) ftell +}; + +static ov_callbacks OV_CALLBACKS_STREAMONLY = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) NULL, + (int (*)(void *)) fclose, + (long (*)(void *)) NULL +}; + +static ov_callbacks OV_CALLBACKS_STREAMONLY_NOCLOSE = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) NULL, + (int (*)(void *)) NULL, + (long (*)(void *)) NULL +}; + +#endif + +#define NOTOPEN 0 +#define PARTOPEN 1 +#define OPENED 2 +#define STREAMSET 3 +#define INITSET 4 + +typedef struct OggVorbis_File { + void *datasource; /* Pointer to a FILE *, etc. */ + int seekable; + ogg_int64_t offset; + ogg_int64_t end; + ogg_sync_state oy; + + /* If the FILE handle isn't seekable (eg, a pipe), only the current + stream appears */ + int links; + ogg_int64_t *offsets; + ogg_int64_t *dataoffsets; + long *serialnos; + ogg_int64_t *pcmlengths; /* overloaded to maintain binary + compatibility; x2 size, stores both + beginning and end values */ + vorbis_info *vi; + vorbis_comment *vc; + + /* Decoding working state local storage */ + ogg_int64_t pcm_offset; + int ready_state; + long current_serialno; + int current_link; + + double bittrack; + double samptrack; + + ogg_stream_state os; /* take physical pages, weld into a logical + stream of packets */ + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + + ov_callbacks callbacks; + +} OggVorbis_File; + + +extern int ov_clear(OggVorbis_File *vf); +extern int ov_fopen(const char *path,OggVorbis_File *vf); +extern int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes); +extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf, + const char *initial, long ibytes, ov_callbacks callbacks); + +extern int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes); +extern int ov_test_callbacks(void *datasource, OggVorbis_File *vf, + const char *initial, long ibytes, ov_callbacks callbacks); +extern int ov_test_open(OggVorbis_File *vf); + +extern long ov_bitrate(OggVorbis_File *vf,int i); +extern long ov_bitrate_instant(OggVorbis_File *vf); +extern long ov_streams(OggVorbis_File *vf); +extern long ov_seekable(OggVorbis_File *vf); +extern long ov_serialnumber(OggVorbis_File *vf,int i); + +extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i); +extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i); +extern double ov_time_total(OggVorbis_File *vf,int i); + +extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_time_seek(OggVorbis_File *vf,double pos); +extern int ov_time_seek_page(OggVorbis_File *vf,double pos); + +extern int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_time_seek_lap(OggVorbis_File *vf,double pos); +extern int ov_time_seek_page_lap(OggVorbis_File *vf,double pos); + +extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf); +extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf); +extern double ov_time_tell(OggVorbis_File *vf); + +extern vorbis_info *ov_info(OggVorbis_File *vf,int link); +extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link); + +extern long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int samples, + int *bitstream); +extern long ov_read_filter(OggVorbis_File *vf,char *buffer,int length, + int bigendianp,int word,int sgned,int *bitstream, + void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param); +extern long ov_read(OggVorbis_File *vf,char *buffer,int length, + int bigendianp,int word,int sgned,int *bitstream); +extern int ov_crosslap(OggVorbis_File *vf1,OggVorbis_File *vf2); + +extern int ov_halfrate(OggVorbis_File *vf,int flag); +extern int ov_halfrate_p(OggVorbis_File *vf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/src/CRE/Glitter/curve.cpp b/src/CRE/Glitter/curve.cpp index a88dbe3a..fd7c6e0e 100644 --- a/src/CRE/Glitter/curve.cpp +++ b/src/CRE/Glitter/curve.cpp @@ -275,7 +275,7 @@ namespace Glitter { 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); + float_t val = lerp_def(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]) { @@ -312,7 +312,7 @@ namespace Glitter { 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); + interpolate_chs_reverse_step_value(a, left_count, _t1, _t2, 0, i, j, step); tt1 += _t1; tt2 += _t2; } @@ -326,7 +326,7 @@ namespace Glitter { 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); + float_t val_lerp = lerp_def(a[0], a[i], (float_t)j / (float_t)i); if (fabsf(val - a[0]) > reverse_bias[0]) { has_error = true; constant = false; @@ -342,7 +342,7 @@ namespace Glitter { constant = true; } - if (fabsf(t1) > 1.0f || fabsf(t2) > 1.0f) + if (fabsf(t1) > 0.5f || fabsf(t2) > 0.5f) has_error_hermite = true; if (!has_error_hermite) { @@ -401,8 +401,8 @@ namespace Glitter { key.tangent2 = 0.0f; key.random_range = arr_b[count - 1]; keys_rev.push_back(key); - free(arr_a); - free(arr_b); + free_def(arr_a); + free_def(arr_b); Recalculate(GLT_VAL); } diff --git a/src/CRE/Glitter/effect.cpp b/src/CRE/Glitter/effect.cpp index b47b9c3a..ed00a1ed 100644 --- a/src/CRE/Glitter/effect.cpp +++ b/src/CRE/Glitter/effect.cpp @@ -31,166 +31,3 @@ namespace Glitter { delete i; } } - -/* -#include "effect.hpp" -#include "animation.hpp" -#include "emitter.hpp" - -static bool glitter_effect_pack_file(GLT, f2_struct* st, glitter_effect* a3); - -glitter_effect::glitter_effect(GLT) : name(), translation(), rotation(), data() { -} - -glitter_effect::~glitter_effect() { - free(data.ext_anim); - for (glitter_emitter*& i : emitters) - delete i; -} - -bool glitter_effect_parse_file(EffectGroup* a1, - f2_struct* st, std::vector* vec, object_database* obj_db) { - glitter_effect* effect; - - if (!st || !st->header.data_size) - return false; - - effect = new glitter_effect(a1->type); - effect->version = st->header.version; - if (!glitter_effect_unpack_file(a1->type, st->data.data(), - effect, st->header.use_big_endian, obj_db)) { - delete effect; - return false; - } - - for (f2_struct& i : st->sub_structs) { - if (!i.header.data_size) - continue; - - if (i.header.signature == reverse_endianness_uint32_t('ANIM')) - glitter_animation_parse_file(a1->type, &i, &effect->animation, glitter_effect_curve_flags); - else if (i.header.signature == reverse_endianness_uint32_t('EMIT')) - glitter_emitter_parse_file(a1, &i, &effect->emitters, effect); - } - vec->push_back(effect); - return true; -} - -static bool glitter_effect_pack_file(GLT, f2_struct* st, glitter_effect* a2) { - size_t l; - size_t d; - glitter_effect_ext_anim* ext_anim; - glitter_effect_file_flag flags; - - if (a2->version != 6 && a2->version != 7) - return false; - - ext_anim = a2->data.ext_anim; - l = 0; - - uint32_t o; - enrs e; - enrs_entry ee; - - ee = { 0, 2, 56, 1 }; - ee.append(0, 1, ENRS_QWORD); - ee.append(0, 12, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 56; - - if (a2->version == 7) { - ee = { 0, 1, 4, 1 }; - ee.append(0, 1, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 4; - } - - ee = { 0, 1, 4, 1 }; - ee.append(0, 1, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 4; - - if (~a2->data.flags & EFFECT_LOCAL && ext_anim) - if (ext_anim->flags & EFFECT_EXT_ANIM_CHARA_ANIM) { - ee = { 0, 1, 12, 1 }; - ee.append(0, 3, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 12; - } - else { - ee = { 0, 2, 140, 1 }; - ee.append(0, 1, ENRS_QWORD); - ee.append(0, 1, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 140; - } - - l = align_val(l, 0x10); - st->data.resize(l); - d = (size_t)st->data.data(); - st->enrs = e; - - flags = (glitter_effect_file_flag)0; - if (a2->data.flags & EFFECT_ALPHA) - enum_or(flags, EFFECT_FILE_ALPHA); - - if (a2->data.flags & EFFECT_FOG) - enum_or(flags, EFFECT_FILE_FOG); - else if (a2->data.flags & EFFECT_FOG_HEIGHT) - enum_or(flags, EFFECT_FILE_FOG_HEIGHT); - - if (a2->data.flags & EFFECT_EMISSION) - enum_or(flags, EFFECT_FILE_EMISSION); - - *(uint64_t*)d = GLT_VAL != Glitter::FT - ? hash_utf8_murmurhash(a2->name) - : hash_utf8_fnv1a64m(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 & 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 & EFFECT_LOCAL) { - *(int32_t*)d = 1; - d += 4; - } - else if (ext_anim) - if (ext_anim->flags & EFFECT_EXT_ANIM_CHARA_ANIM) { - *(int32_t*)d = 2; - d += 4; - glitter_effect_ext_anim_flag ext_anim_flag - = (glitter_effect_ext_anim_flag)(ext_anim->flags & ~EFFECT_EXT_ANIM_CHARA_ANIM); - *(int32_t*)d = ext_anim->chara_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((uint8_t*)(d + 12), ext_anim->mesh_name, 128); - } - else { - *(int32_t*)d = 0; - d += 4; - } - - st->header.signature = reverse_endianness_uint32_t('EFCT'); - st->header.length = 0x20; - st->header.use_big_endian = false; - st->header.use_section_size = true; - st->header.version = a2->version; - return true; -} -*/ \ No newline at end of file diff --git a/src/CRE/Glitter/effect_group.cpp b/src/CRE/Glitter/effect_group.cpp index 082a1814..ff0a38ef 100644 --- a/src/CRE/Glitter/effect_group.cpp +++ b/src/CRE/Glitter/effect_group.cpp @@ -23,7 +23,7 @@ namespace Glitter { if (resources) { for (texture** i = resources; *i; i++) texture_free(*i); - free(resources); + free_def(resources); resources = 0; } diff --git a/src/CRE/Glitter/effect_inst.cpp b/src/CRE/Glitter/effect_inst.cpp index 3a525f3e..6bf1af52 100644 --- a/src/CRE/Glitter/effect_inst.cpp +++ b/src/CRE/Glitter/effect_inst.cpp @@ -110,7 +110,7 @@ namespace Glitter { random_ptr = &GPM_VAL->random; ext_anim = 0; - if (~eff->data.flags & EFFECT_LOCAL && data.ext_anim) { + if (!(eff->data.flags & EFFECT_LOCAL) && data.ext_anim) { F2EffectInst::ExtAnim* inst_ext_anim = new F2EffectInst::ExtAnim; if (inst_ext_anim) { Effect::ExtAnim* ext_anim = data.ext_anim; @@ -240,7 +240,7 @@ namespace Glitter { } bool F2EffectInst::HasEnded(bool a2) { - if (~flags & EFFECT_INST_FREE) + if (!(flags & EFFECT_INST_FREE)) return false; else if (!a2) return true; @@ -256,7 +256,7 @@ namespace Glitter { frame1 = 0.0; flags = (EffectInstFlag)0; - if (~data.flags & EFFECT_LOCAL && data.ext_anim) { + if (!(data.flags & EFFECT_LOCAL) && data.ext_anim) { if (ext_anim) { Effect::ExtAnim* ext_anim = data.ext_anim; if (ext_anim->flags & EFFECT_EXT_ANIM_SET_ONCE) @@ -328,7 +328,7 @@ namespace Glitter { } void F2EffectInst::CtrlMat(GPM, GLT) { - if (~flags & EFFECT_INST_JUST_INIT) + if (!(flags & EFFECT_INST_JUST_INIT)) return; vec3 trans = translation; @@ -359,12 +359,10 @@ namespace Glitter { if (!ext_anim || !data.ext_anim) return; - if (~flags & EFFECT_INST_HAS_EXT_ANIM || (flags & EFFECT_INST_SET_EXT_ANIM_ONCE + if (!(flags & EFFECT_INST_HAS_EXT_ANIM) || (flags & EFFECT_INST_SET_EXT_ANIM_ONCE && flags & EFFECT_INST_HAS_EXT_ANIM_TRANS)) return; - mat4* obj_mat = 0; - mat4 temp; mat4 mat; int32_t chara_id; @@ -398,8 +396,69 @@ namespace Glitter { ext_anim->mat = mat; goto SetFlags; } + else if (flags & EFFECT_INST_GET_EXT_ANIM_MAT) { + mat4 temp; + mat4* obj_mat = 0; + if (ext_anim->a3da_id != -1) + obj_mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id, + ext_anim->object_index, ext_anim->object_is_hrc, &temp); - if (~flags & EFFECT_INST_GET_EXT_ANIM_MAT) { + if (!obj_mat) { + ext_anim->a3da_id = auth_3d_data_get_auth_3d_id(ext_anim->object, + &ext_anim->object_index, &ext_anim->object_is_hrc); + if (ext_anim->a3da_id == -1) + return; + + ext_anim->mesh_index = -1; + obj_mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id, + ext_anim->object_index, ext_anim->object_is_hrc, &temp); + if (!obj_mat) + return; + } + + mat = mat4_identity; + chara_id = auth_3d_data_get_chara_id(ext_anim->a3da_id); + if (chara_id >= 0 && chara_id < ROB_CHARA_COUNT) { + rob_chara* rob_chr = rob_chara_array_get(chara_id); + if (rob_chr) { + mat = rob_chr->data.adjust_data.mat; + + vec3 scale; + mat4_get_scale(&mat, &scale); + vec3_sub_scalar(scale, 1.0f, ext_anim_scale); + ext_anim_scale.z = 0.0f; + enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_SCALE); + } + } + + if (ext_anim->mesh_name) { + if (ext_anim->mesh_index == -1) + ext_anim->mesh_index = object_storage_get_obj_mesh_index( + ext_anim->object, ext_anim->mesh_name); + + if (ext_anim->mesh_index != -1) { + obj_mesh* mesh = object_storage_get_obj_mesh_by_index( + ext_anim->object, ext_anim->mesh_index); + if (mesh) { + mat4_mult(obj_mat, &mat, &mat); + ext_anim->mat = mat; + ext_anim->translation = mesh->bounding_sphere.center; + goto SetFlags; + } + } + } + else { + mat4_mult(obj_mat, &mat, &mat); + if (flags & EFFECT_INST_EXT_ANIM_TRANS_ONLY) { + ext_anim->mat = mat4_identity; + mat4_get_translation(&mat, &ext_anim->translation); + } + else + ext_anim->mat = mat; + goto SetFlags; + } + } + else { if (ext_anim->mesh_index == -1) { if (!ext_anim->mesh_name) return; @@ -416,66 +475,6 @@ namespace Glitter { goto SetFlags; } } - return; - } - - if (ext_anim->a3da_id != -1) - obj_mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id, - ext_anim->object_index, ext_anim->object_is_hrc, &temp); - - if (!obj_mat) { - ext_anim->a3da_id = auth_3d_data_get_auth_3d_id(ext_anim->object, - &ext_anim->object_index, &ext_anim->object_is_hrc, 0); - if (ext_anim->a3da_id == -1) - return; - - ext_anim->mesh_index = -1; - obj_mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id, - ext_anim->object_index, ext_anim->object_is_hrc, &temp); - if (!obj_mat) - return; - } - - mat = mat4_identity; - chara_id = auth_3d_data_get_chara_id(ext_anim->a3da_id); - if (chara_id >= 0 && chara_id < ROB_CHARA_COUNT) { - rob_chara* rob_chr = rob_chara_array_get(chara_id); - if (rob_chr) { - mat = rob_chr->data.adjust_data.mat; - - vec3 scale; - mat4_get_scale(&mat, &scale); - vec3_sub_scalar(scale, 1.0f, ext_anim_scale); - ext_anim_scale.z = 0.0f; - enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_SCALE); - } - } - - if (ext_anim->mesh_name) { - if (ext_anim->mesh_index == -1) - ext_anim->mesh_index = object_storage_get_obj_mesh_index( - ext_anim->object, ext_anim->mesh_name); - - if (ext_anim->mesh_index != -1) { - obj_mesh* mesh = object_storage_get_obj_mesh_by_index( - ext_anim->object, ext_anim->mesh_index); - if (mesh) { - mat4_mult(obj_mat, &mat, &mat); - ext_anim->mat = mat; - ext_anim->translation = mesh->bounding_sphere.center; - goto SetFlags; - } - } - } - else { - mat4_mult(obj_mat, &mat, &mat); - if (flags & EFFECT_INST_EXT_ANIM_TRANS_ONLY) { - ext_anim->mat = mat4_identity; - mat4_get_translation(&mat, &ext_anim->translation); - } - else - ext_anim->mat = mat; - goto SetFlags; } return; @@ -487,7 +486,7 @@ namespace Glitter { } bool F2EffectInst::GetExtAnimMat(mat4* mat) { - if (~flags & EFFECT_INST_HAS_EXT_ANIM_TRANS || !ext_anim) + if (!(flags & EFFECT_INST_HAS_EXT_ANIM_TRANS) || !ext_anim) return false; vec3 trans = ext_anim->translation; @@ -496,7 +495,7 @@ namespace Glitter { } void F2EffectInst::GetExtColor(float_t& r, float_t& g, float_t& b, float_t& a) { - if (~flags & EFFECT_INST_EXT_COLOR) + if (!(flags & EFFECT_INST_EXT_COLOR)) return; if (flags & EFFECT_INST_SET_EXT_COLOR) { @@ -623,7 +622,7 @@ namespace Glitter { random = GPM_VAL->CounterGet(); random_shared.value = random; - if (~eff->data.flags & EFFECT_LOCAL && data.ext_anim_x) { + if (!(eff->data.flags & EFFECT_LOCAL) && data.ext_anim_x) { XEffectInst::ExtAnim* inst_ext_anim = new XEffectInst::ExtAnim; if (inst_ext_anim) { Effect::ExtAnimX* ext_anim = data.ext_anim_x; @@ -777,7 +776,7 @@ namespace Glitter { } bool XEffectInst::HasEnded(bool a2) { - if (~flags & EFFECT_INST_FREE) + if (!(flags & EFFECT_INST_FREE)) return false; else if (!a2) return true; @@ -793,7 +792,7 @@ namespace Glitter { frame1 = 0.0; flags = (EffectInstFlag)0; - if (~data.flags & EFFECT_LOCAL && data.ext_anim_x) { + if (!(data.flags & EFFECT_LOCAL) && data.ext_anim_x) { if (ext_anim) { Effect::ExtAnimX* ext_anim = data.ext_anim_x; if (ext_anim->flags & EFFECT_EXT_ANIM_SET_ONCE) @@ -876,7 +875,7 @@ namespace Glitter { } void XEffectInst::CtrlMat(GPM) { - if (~flags & EFFECT_INST_JUST_INIT) + if (!(flags & EFFECT_INST_JUST_INIT)) return; vec3 trans = translation; @@ -911,7 +910,7 @@ namespace Glitter { if (!ext_anim || !data.ext_anim_x) return; - if (~flags & EFFECT_INST_HAS_EXT_ANIM || (flags & EFFECT_INST_SET_EXT_ANIM_ONCE + if (!(flags & EFFECT_INST_HAS_EXT_ANIM) || (flags & EFFECT_INST_SET_EXT_ANIM_ONCE && flags & EFFECT_INST_HAS_EXT_ANIM_TRANS)) return; @@ -925,10 +924,10 @@ namespace Glitter { if (!rob_chr) return; - mat4& mat = rob_chr->data.adjust_data.mat; + mat4* mat = &rob_chr->data.adjust_data.mat; vec3 scale; - mat4_get_scale(&mat, &scale); + mat4_get_scale(mat, &scale); vec3_sub_scalar(scale, 1.0f, ext_anim_scale); ext_anim_scale.z = 0.0f; enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_SCALE); @@ -942,19 +941,19 @@ namespace Glitter { if (bone_index != -1) { mat4* bone_mat = rob_chr->get_bone_data_mat(bone_index); if (bone_mat) - SetExtAnim(&mat, bone_mat, 0, set_flags); + SetExtAnim(mat, bone_mat, 0, set_flags); } else - SetExtAnim(&mat, 0, 0, set_flags); + SetExtAnim(mat, 0, 0, set_flags); } else if (flags & EFFECT_INST_GET_EXT_ANIM_MAT) { mat4 temp; - mat4* mat = 0; + mat4* obj_mat = 0; if (ext_anim->a3da_id != -1) - mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id, + obj_mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id, ext_anim->object_index, ext_anim->object_is_hrc, &temp); - if (!mat) { + if (!obj_mat) { ext_anim->a3da_id = auth_3d_data_get_auth_3d_id( ext_anim->file_name_hash, ext_anim->object_hash, &ext_anim->object_index, &ext_anim->object_is_hrc, ext_anim->instance_id); @@ -962,18 +961,22 @@ namespace Glitter { return; ext_anim->mesh_index = -1; - mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id, + obj_mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id, ext_anim->object_index, ext_anim->object_is_hrc, &temp); - if (!mat) + if (!obj_mat) return; } + const mat4* mat = &mat4_identity; + int32_t chara_id = auth_3d_data_get_chara_id(ext_anim->a3da_id); if (chara_id >= 0 && chara_id < ROB_CHARA_COUNT) { rob_chara* rob_chr = rob_chara_array_get(chara_id); if (rob_chr) { + mat = &rob_chr->data.adjust_data.mat; + vec3 scale; - mat4_get_scale(&rob_chr->data.adjust_data.mat, &scale); + mat4_get_scale(mat, &scale); vec3_sub_scalar(scale, 1.0f, ext_anim_scale); ext_anim_scale.z = 0.0f; enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_SCALE); @@ -990,12 +993,12 @@ namespace Glitter { ext_anim->object_hash, ext_anim->mesh_index); if (mesh) { vec3* trans = &mesh->bounding_sphere.center; - SetExtAnim(mat, 0, trans, true); + SetExtAnim(mat, obj_mat, trans, true); } } } else - SetExtAnim(mat, 0, 0, true); + SetExtAnim(mat, obj_mat, 0, true); } else if (ext_anim->object_hash != hash_murmurhash_empty) { @@ -1019,7 +1022,7 @@ namespace Glitter { } bool XEffectInst::GetExtAnimMat(mat4* mat) { - if (~flags & EFFECT_INST_HAS_EXT_ANIM_TRANS || !ext_anim) + if (!(flags & EFFECT_INST_HAS_EXT_ANIM_TRANS) || !ext_anim) return false; vec3 trans = ext_anim->translation; @@ -1028,7 +1031,7 @@ namespace Glitter { } void XEffectInst::GetExtColor(float_t& r, float_t& g, float_t& b, float_t& a) { - if (~flags & EFFECT_INST_EXT_COLOR) + if (!(flags & EFFECT_INST_EXT_COLOR)) return; if (flags & EFFECT_INST_SET_EXT_COLOR) { @@ -1125,7 +1128,7 @@ namespace Glitter { } } - void XEffectInst::SetExtAnim(mat4* a2, mat4* a3, vec3* trans, bool set_flags) { + void XEffectInst::SetExtAnim(const mat4* a2, const mat4* a3, const vec3* trans, bool set_flags) { EffectInstFlag flags = this->flags; if (a2) { mat4 mat = *a2; diff --git a/src/CRE/Glitter/emitter.cpp b/src/CRE/Glitter/emitter.cpp index 7886cd21..81f8e5f3 100644 --- a/src/CRE/Glitter/emitter.cpp +++ b/src/CRE/Glitter/emitter.cpp @@ -40,148 +40,3 @@ namespace Glitter { delete i; } } - -/* -#include "emitter.hpp" -#include "animation.hpp" -#include "curve.hpp" -#include "particle.hpp" - -static bool glitter_emitter_pack_file(GLT, f2_struct* st, glitter_emitter* a2); - -bool glitter_emitter_unparse_file(GLT, EffectGroup* a1, - f2_struct* st, glitter_emitter* a3, glitter_effect* effect) { - if (!glitter_emitter_pack_file(GLT_VAL, st, a3)) - return false; - - f2_struct s; - if (glitter_animation_unparse_file(GLT_VAL, &s, &a3->animation, glitter_emitter_curve_flags)) - st->sub_structs.push_back(s); - - for (glitter_particle*& i : a3->particles) { - if (!i) - continue; - - f2_struct s; - if (glitter_particle_unparse_file(GLT_VAL, a1, &s, i, effect)) - st->sub_structs.push_back(s); - } - return true; -} - -static bool glitter_emitter_pack_file(GLT, f2_struct* st, glitter_emitter* a2) { - size_t l; - size_t d; - - if (a2->version != 1 && a2->version != 2) - return false; - - switch (a2->data.type) { - case EMITTER_BOX: - case EMITTER_CYLINDER: - case EMITTER_SPHERE: - case EMITTER_POLYGON: - break; - default: - return false; - } - - l = 0; - - uint32_t o; - enrs e; - enrs_entry ee; - - ee = { 0, 5, 96, 1 }; - ee.append(0, 5, ENRS_DWORD); - ee.append(0, 2, ENRS_WORD); - ee.append(0, 2, ENRS_DWORD); - ee.append(0, 2, ENRS_WORD); - ee.append(0, 15, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 96; - - switch (a2->data.type) { - case EMITTER_BOX: - ee = { o, 1, 12, 1 }; - ee.append(0, 3, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 12; - break; - case EMITTER_CYLINDER: - ee = { o, 1, 20, 1 }; - ee.append(0, 5, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 20; - break; - case EMITTER_SPHERE: - ee = { o, 1, 16, 1 }; - ee.append(0, 4, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 16; - break; - case EMITTER_POLYGON: - ee = { o, 1, 8, 1 }; - ee.append(0, 2, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 8; - break; - } - - l = align_val(l, 0x10); - st->data.resize(l); - d = (size_t)st->data.data(); - st->enrs = e; - - *(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; - - *(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 EMITTER_BOX: - *(vec3*)d = a2->data.box.size; - break; - case 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 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 EMITTER_POLYGON: - *(float_t*)d = a2->data.polygon.size; - *(int32_t*)(d + 4) = a2->data.polygon.count; - break; - } - - st->header.signature = reverse_endianness_uint32_t('EMIT'); - st->header.length = 0x20; - st->header.use_big_endian = false; - st->header.use_section_size = true; - st->header.version = a2->version; - return true; -} -*/ \ No newline at end of file diff --git a/src/CRE/Glitter/file_reader.cpp b/src/CRE/Glitter/file_reader.cpp index 9c585b2b..1ed51067 100644 --- a/src/CRE/Glitter/file_reader.cpp +++ b/src/CRE/Glitter/file_reader.cpp @@ -42,8 +42,8 @@ namespace Glitter { this->hash = GLT_VAL != Glitter::FT ? hash_utf8_murmurhash(file_temp) : hash_utf8_fnv1a64m(file_temp); - free(path_temp); - free(file_temp); + free_def(path_temp); + free_def(file_temp); } FileReader::~FileReader() { @@ -760,10 +760,10 @@ namespace Glitter { } if (!texture_txp_set_load(&eff_group->resources_tex, &eff_group->resources, ids)) { - free(ids); + free_def(ids); return false; } - free(ids); + free_def(ids); for (Effect*& i : eff_group->effects) { if (!i) @@ -1853,9 +1853,9 @@ namespace Glitter { ptcl->data.split_u = split_u; ptcl->data.split_v = split_v; ptcl->data.uv_index_type = uv_index_type; - ptcl->data.uv_index = max(uv_index, 0); + ptcl->data.uv_index = max_def(uv_index, 0); ptcl->data.frame_step_uv = frame_step_uv; - ptcl->data.uv_index_start = max(uv_index_start, 0); + ptcl->data.uv_index_start = max_def(uv_index_start, 0); ptcl->data.uv_index_end = uv_index_end; ptcl->data.split_uv.x = (float_t)split_u; ptcl->data.split_uv.y = (float_t)split_v; @@ -1885,7 +1885,7 @@ namespace Glitter { else if (uv_index_end >= 0 && uv_index > uv_index_end) ptcl->data.uv_index = uv_index_end; - ptcl->data.uv_index = min(ptcl->data.uv_index, uv_max_count); + ptcl->data.uv_index = min_def(ptcl->data.uv_index, uv_max_count); break; } diff --git a/src/CRE/Glitter/file_writer.cpp b/src/CRE/Glitter/file_writer.cpp index b6d2bc2f..a0848e59 100644 --- a/src/CRE/Glitter/file_writer.cpp +++ b/src/CRE/Glitter/file_writer.cpp @@ -4,6 +4,7 @@ */ #include "glitter.hpp" +#include "../../KKdLib/io/file_stream.hpp" #include "../../KKdLib/io/path.hpp" #include "../../KKdLib/interpolation.hpp" #include "../../KKdLib/farc.hpp" @@ -15,7 +16,7 @@ namespace Glitter { } - void FileWriter::PackCurve(f2_struct* st, Curve* c) { + void FileWriter::PackCurve(f2_struct* st, Curve* c, bool big_endian) { if (!c->keys.size()) { st->header.signature = reverse_endianness_uint32_t('KEYS'); st->header.length = 0x20; @@ -144,83 +145,153 @@ namespace Glitter { st->data.resize(l); size_t d = (size_t)st->data.data(); - if (scale == 1.0f) - if (c->flags & CURVE_KEY_RANDOM_RANGE) - for (Curve::Key& i : c->keys) { - *(int16_t*)d = (int16_t)i.type; - *(int16_t*)(d + 2) = (int16_t)i.frame; - if (i.type == 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; + if (scale == 1.0f) { + if (big_endian) + if (c->flags & CURVE_KEY_RANDOM_RANGE) + for (Curve::Key& i : c->keys) { + store_reverse_endianness_int16_t((int16_t*)d, (int16_t)i.type); + store_reverse_endianness_int16_t((int16_t*)(d + 2), (int16_t)i.frame); + if (i.type == KEY_HERMITE) { + store_reverse_endianness_float_t((float_t*)(d + 4), i.tangent1); + store_reverse_endianness_float_t((float_t*)(d + 8), i.tangent2); + store_reverse_endianness_float_t((float_t*)(d + 12), i.random_range); + store_reverse_endianness_float_t((float_t*)(d + 16), i.value); + d += 20; + } + else { + store_reverse_endianness_float_t((float_t*)(d + 4), i.random_range); + store_reverse_endianness_float_t((float_t*)(d + 8), i.value); + d += 12; + } } - else { - *(float_t*)(d + 4) = i.random_range; - *(float_t*)(d + 8) = i.value; - d += 12; + else + for (Curve::Key& i : c->keys) { + store_reverse_endianness_int16_t((int16_t*)d, (int16_t)i.type); + store_reverse_endianness_int16_t((int16_t*)(d + 2), (int16_t)i.frame); + if (i.type == KEY_HERMITE) { + store_reverse_endianness_float_t((float_t*)(d + 4), i.tangent1); + store_reverse_endianness_float_t((float_t*)(d + 8), i.tangent2); + store_reverse_endianness_float_t((float_t*)(d + 12), i.value); + d += 16; + } + else { + store_reverse_endianness_float_t((float_t*)(d + 4), i.value); + d += 8; + } } - } else - for (Curve::Key& i : c->keys) { - *(int16_t*)d = (int16_t)i.type; - *(int16_t*)(d + 2) = (int16_t)i.frame; - if (i.type == KEY_HERMITE) { - *(float_t*)(d + 4) = i.tangent1; - *(float_t*)(d + 8) = i.tangent2; - *(float_t*)(d + 12) = i.value; - d += 16; + if (c->flags & CURVE_KEY_RANDOM_RANGE) + for (Curve::Key& i : c->keys) { + *(int16_t*)d = (int16_t)i.type; + *(int16_t*)(d + 2) = (int16_t)i.frame; + if (i.type == 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 { + *(float_t*)(d + 4) = i.random_range; + *(float_t*)(d + 8) = i.value; + d += 12; + } } - else { - *(float_t*)(d + 4) = i.value; - d += 8; + else + for (Curve::Key& i : c->keys) { + *(int16_t*)d = (int16_t)i.type; + *(int16_t*)(d + 2) = (int16_t)i.frame; + if (i.type == KEY_HERMITE) { + *(float_t*)(d + 4) = i.tangent1; + *(float_t*)(d + 8) = i.tangent2; + *(float_t*)(d + 12) = i.value; + d += 16; + } + else { + *(float_t*)(d + 4) = i.value; + d += 8; + } } - } - else - if (c->flags & CURVE_KEY_RANDOM_RANGE) - for (Curve::Key& i : c->keys) { - *(int16_t*)d = (int16_t)i.type; - *(int16_t*)(d + 2) = (int16_t)i.frame; - if (i.type == 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 { + if (big_endian) + if (c->flags & CURVE_KEY_RANDOM_RANGE) + for (Curve::Key& i : c->keys) { + store_reverse_endianness_int16_t((int16_t*)d, (int16_t)i.type); + store_reverse_endianness_int16_t((int16_t*)(d + 2), (int16_t)i.frame); + if (i.type == KEY_HERMITE) { + store_reverse_endianness_float_t((float_t*)(d + 4), i.tangent1 * scale); + store_reverse_endianness_float_t((float_t*)(d + 8), i.tangent2 * scale); + store_reverse_endianness_float_t((float_t*)(d + 12), i.random_range * scale); + store_reverse_endianness_float_t((float_t*)(d + 16), i.value * scale); + d += 20; + } + else { + store_reverse_endianness_float_t((float_t*)(d + 4), i.random_range * scale); + store_reverse_endianness_float_t((float_t*)(d + 8), i.value * scale); + d += 12; + } } - else { - *(float_t*)(d + 4) = i.random_range * scale; - *(float_t*)(d + 8) = i.value * scale; - d += 12; + else + for (Curve::Key& i : c->keys) { + store_reverse_endianness_int16_t((int16_t*)d, (int16_t)i.type); + store_reverse_endianness_int16_t((int16_t*)(d + 2), (int16_t)i.frame); + if (i.type == KEY_HERMITE) { + store_reverse_endianness_float_t((float_t*)(d + 4), i.tangent1 * scale); + store_reverse_endianness_float_t((float_t*)(d + 8), i.tangent2 * scale); + store_reverse_endianness_float_t((float_t*)(d + 12), i.value * scale); + d += 16; + } + else { + store_reverse_endianness_float_t((float_t*)(d + 4), i.value * scale); + d += 8; + } } - } else - for (Curve::Key& i : c->keys) { - *(int16_t*)d = (int16_t)i.type; - *(int16_t*)(d + 2) = (int16_t)i.frame; - if (i.type == 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; + if (c->flags & CURVE_KEY_RANDOM_RANGE) + for (Curve::Key& i : c->keys) { + *(int16_t*)d = (int16_t)i.type; + *(int16_t*)(d + 2) = (int16_t)i.frame; + if (i.type == 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 { + *(float_t*)(d + 4) = i.random_range * scale; + *(float_t*)(d + 8) = i.value * scale; + d += 12; + } } - else { - *(float_t*)(d + 4) = i.value * scale; - d += 8; + else + for (Curve::Key& i : c->keys) { + *(int16_t*)d = (int16_t)i.type; + *(int16_t*)(d + 2) = (int16_t)i.frame; + if (i.type == 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 { + *(float_t*)(d + 4) = i.value * scale; + d += 8; + } } - } + } st->enrs = e; st->header.signature = reverse_endianness_uint32_t('KEYS'); st->header.length = 0x20; - st->header.use_big_endian = false; + st->header.use_big_endian = big_endian; st->header.use_section_size = true; st->header.version = c->keys_version; } - bool FileWriter::PackDivaList(EffectGroup* eff_group, f2_struct* st) { + bool FileWriter::PackDivaList(EffectGroup* eff_group, f2_struct* st, bool big_endian) { if (!eff_group->effects.size()) return false; @@ -239,12 +310,15 @@ namespace Glitter { st->data.resize(0x10 + 0x80 * length); size_t d = (size_t)st->data.data(); - *(uint32_t*)d = (uint32_t)length; + if (big_endian) + store_reverse_endianness_uint32_t((uint32_t*)d, (uint32_t)length); + else + *(uint32_t*)d = (uint32_t)length; d += 4; for (Effect*& i : eff_group->effects) if (i) { - size_t size = min(i->name.size(), 0x7F); + size_t size = min_def(i->name.size(), 0x7F); memcpy((void*)d, i->name.c_str(), size); memset((void*)(d + size), 0, 0x80 - size); d += 0x80; @@ -254,7 +328,7 @@ namespace Glitter { st->header.signature = reverse_endianness_uint32_t('GEFF'); st->header.length = 0x20; - st->header.use_big_endian = false; + st->header.use_big_endian = big_endian; st->header.use_section_size = true; return true; } @@ -275,7 +349,7 @@ namespace Glitter { return true; } - bool FileWriter::PackDivaResourceHashes(EffectGroup* eff_group, f2_struct* st) { + bool FileWriter::PackDivaResourceHashes(EffectGroup* eff_group, f2_struct* st, bool big_endian) { if (eff_group->effects.size() < 1 || !eff_group->resources_count || eff_group->resource_hashes.size() < 1) return false; @@ -297,22 +371,32 @@ namespace Glitter { st->data.resize(l); size_t d = (size_t)st->data.data(); - *(int32_t*)d = (int32_t)count; + if (big_endian) + store_reverse_endianness_int32_t((int32_t*)d, (int32_t)count); + else + *(int32_t*)d = (int32_t)count; *(int32_t*)(d + 4) = 0; d += 8; - memcpy((void*)d, eff_group->resource_hashes.data(), sizeof(uint64_t) * count); + if (big_endian) { + uint64_t* hashes_src = eff_group->resource_hashes.data(); + uint64_t* hashes_dst = (uint64_t*)(void*)d; + for (size_t i = 0; i < count; i++) + store_reverse_endianness_uint64_t(hashes_dst++, *hashes_src++); + } + else + memcpy((void*)d, eff_group->resource_hashes.data(), sizeof(uint64_t) * count); st->enrs = e; st->header.signature = reverse_endianness_uint32_t('DVRS'); st->header.length = 0x20; - st->header.use_big_endian = false; + st->header.use_big_endian = big_endian; st->header.use_section_size = true; return true; } - bool FileWriter::PackEffect(f2_struct* st, Effect* eff) { + bool FileWriter::PackEffect(f2_struct* st, Effect* eff, bool big_endian) { if (eff->version != 6 && eff->version != 7) return false; @@ -373,45 +457,88 @@ namespace Glitter { if (eff->data.flags & EFFECT_EMISSION) enum_or(flags, EFFECT_FILE_EMISSION); - *(uint64_t*)d = type != Glitter::FT - ? hash_string_murmurhash(eff->name) : hash_string_fnv1a64m(eff->name); - *(int32_t*)(d + 8) = eff->data.appear_time; - *(int32_t*)(d + 12) = eff->data.life_time; - *(int32_t*)(d + 16) = eff->data.start_time; - *(int32_t*)(d + 20) = 0xFFFFFFFF; - *(int32_t*)(d + 24) = eff->data.flags & EFFECT_LOOP ? 1 : 0; - *(vec3*)(d + 28) = eff->translation; - *(vec3*)(d + 40) = eff->rotation; - *(int32_t*)(d + 52) = flags; + if (big_endian) { + store_reverse_endianness_uint64_t((uint64_t*)d, type != Glitter::FT + ? hash_string_murmurhash(eff->name) : hash_string_fnv1a64m(eff->name)); + store_reverse_endianness_int32_t((int32_t*)(d + 8), eff->data.appear_time); + store_reverse_endianness_int32_t((int32_t*)(d + 12), eff->data.life_time); + store_reverse_endianness_int32_t((int32_t*)(d + 16), eff->data.start_time); + store_reverse_endianness_int32_t((int32_t*)(d + 20), 0xFFFFFFFF); + store_reverse_endianness_int32_t((int32_t*)(d + 24), eff->data.flags & EFFECT_LOOP ? 1 : 0); + store_reverse_endianness_float_t((float_t*)(d + 28), eff->translation.x); + store_reverse_endianness_float_t((float_t*)(d + 32), eff->translation.y); + store_reverse_endianness_float_t((float_t*)(d + 36), eff->translation.z); + store_reverse_endianness_float_t((float_t*)(d + 40), eff->rotation.x); + store_reverse_endianness_float_t((float_t*)(d + 40), eff->rotation.y); + store_reverse_endianness_float_t((float_t*)(d + 40), eff->rotation.z); + store_reverse_endianness_int32_t((int32_t*)(d + 52), flags); + } + else { + *(uint64_t*)d = type != Glitter::FT + ? hash_string_murmurhash(eff->name) : hash_string_fnv1a64m(eff->name); + *(int32_t*)(d + 8) = eff->data.appear_time; + *(int32_t*)(d + 12) = eff->data.life_time; + *(int32_t*)(d + 16) = eff->data.start_time; + *(int32_t*)(d + 20) = 0xFFFFFFFF; + *(int32_t*)(d + 24) = eff->data.flags & EFFECT_LOOP ? 1 : 0; + *(vec3*)(d + 28) = eff->translation; + *(vec3*)(d + 40) = eff->rotation; + *(int32_t*)(d + 52) = flags; + } d += 56; if (eff->version == 7) { - *(float_t*)d = eff->data.emission; + if (big_endian) + store_reverse_endianness_float_t((float_t*)d, eff->data.emission); + else + *(float_t*)d = eff->data.emission; d += 4; } if (eff->data.flags & EFFECT_LOCAL) { - *(int32_t*)d = 1; + if (big_endian) + store_reverse_endianness_int32_t((int32_t*)d, 1); + else + *(int32_t*)d = 1; d += 4; } else if (ext_anim) { if (ext_anim->flags & EFFECT_EXT_ANIM_CHARA_ANIM) { - *(int32_t*)d = 2; + if (big_endian) + store_reverse_endianness_int32_t((int32_t*)d, 2); + else + *(int32_t*)d = 2; d += 4; EffectExtAnimFlag ext_anim_flag = ext_anim->flags; enum_and(ext_anim_flag, ~EFFECT_EXT_ANIM_CHARA_ANIM); - *(int32_t*)d = ext_anim->chara_index; - *(int32_t*)(d + 4) = ext_anim_flag; - *(int32_t*)(d + 8) = ext_anim->node_index; + if (big_endian) { + store_reverse_endianness_int32_t((int32_t*)d, ext_anim->chara_index); + store_reverse_endianness_int32_t((int32_t*)(d + 4), ext_anim_flag); + store_reverse_endianness_int32_t((int32_t*)(d + 8), ext_anim->node_index); + } + else { + *(int32_t*)d = ext_anim->chara_index; + *(int32_t*)(d + 4) = ext_anim_flag; + *(int32_t*)(d + 8) = ext_anim->node_index; + } } else { - *(int32_t*)d = 3; + if (big_endian) + store_reverse_endianness_int32_t((int32_t*)d, 3); + else + *(int32_t*)d = 3; d += 4; - *(uint64_t*)d = ext_anim->object_hash; - *(int32_t*)(d + 8) = ext_anim->flags; + if (big_endian) { + store_reverse_endianness_uint64_t((uint64_t*)d, ext_anim->object_hash); + store_reverse_endianness_int32_t((int32_t*)(d + 8), ext_anim->flags); + } + else { + *(uint64_t*)d = ext_anim->object_hash; + *(int32_t*)(d + 8) = ext_anim->flags; + } strncpy_s((char*)(d + 12), 0x80, ext_anim->mesh_name, 0x80); ((char*)(d + 12))[0x7F] = '\0'; } @@ -425,13 +552,13 @@ namespace Glitter { st->header.signature = reverse_endianness_uint32_t('EFCT'); st->header.length = 0x20; - st->header.use_big_endian = false; + st->header.use_big_endian = big_endian; st->header.use_section_size = true; st->header.version = eff->version; return true; } - bool FileWriter::PackEmitter(f2_struct* st, Emitter* emit) { + bool FileWriter::PackEmitter(f2_struct* st, Emitter* emit, bool big_endian) { if (emit->version != 1 && emit->version != 2) return false; @@ -491,47 +618,109 @@ namespace Glitter { st->data.resize(l); size_t d = (size_t)st->data.data(); - *(int32_t*)d = emit->data.start_time; - *(int32_t*)(d + 4) = emit->data.life_time; - *(int32_t*)(d + 8) = emit->data.loop_start_time; - *(int32_t*)(d + 12) = emit->data.loop_end_time; - *(int32_t*)(d + 16) = emit->data.flags; - *(int16_t*)(d + 20) = (int16_t)emit->data.type; - *(int16_t*)(d + 22) = (int16_t)emit->data.direction; - *(float_t*)(d + 24) = emit->data.emission_interval; - *(float_t*)(d + 28) = emit->data.particles_per_emission; - *(int16_t*)(d + 32) = 0; - *(int16_t*)(d + 34) = 0; + if (big_endian) { + store_reverse_endianness_int32_t((int32_t*)d, emit->data.start_time); + store_reverse_endianness_int32_t((int32_t*)(d + 4), emit->data.life_time); + store_reverse_endianness_int32_t((int32_t*)(d + 8), emit->data.loop_start_time); + store_reverse_endianness_int32_t((int32_t*)(d + 12), emit->data.loop_end_time); + store_reverse_endianness_int32_t((int32_t*)(d + 16), emit->data.flags); + store_reverse_endianness_int32_t((int16_t*)(d + 20), (int16_t)emit->data.type); + store_reverse_endianness_int32_t((int16_t*)(d + 22), (int16_t)emit->data.direction); + store_reverse_endianness_float_t((float_t*)(d + 24), emit->data.emission_interval); + store_reverse_endianness_float_t((float_t*)(d + 28), emit->data.particles_per_emission); + store_reverse_endianness_int16_t((int16_t*)(d + 32), (uint16_t)0); + store_reverse_endianness_int16_t((int16_t*)(d + 34), (uint16_t)0); - *(vec3*)(d + 36) = emit->translation; - *(vec3*)(d + 48) = emit->rotation; - *(vec3*)(d + 60) = emit->scale; - *(vec3*)(d + 72) = emit->data.rotation_add; - *(vec3*)(d + 84) = emit->data.rotation_add_random; + store_reverse_endianness_float_t((float_t*)(d + 36), emit->translation.x); + store_reverse_endianness_float_t((float_t*)(d + 40), emit->translation.y); + store_reverse_endianness_float_t((float_t*)(d + 44), emit->translation.z); + store_reverse_endianness_float_t((float_t*)(d + 48), emit->rotation.x); + store_reverse_endianness_float_t((float_t*)(d + 52), emit->rotation.y); + store_reverse_endianness_float_t((float_t*)(d + 56), emit->rotation.z); + store_reverse_endianness_float_t((float_t*)(d + 60), emit->scale.x); + store_reverse_endianness_float_t((float_t*)(d + 64), emit->scale.y); + store_reverse_endianness_float_t((float_t*)(d + 68), emit->scale.z); + store_reverse_endianness_float_t((float_t*)(d + 72), emit->data.rotation_add.x); + store_reverse_endianness_float_t((float_t*)(d + 76), emit->data.rotation_add.y); + store_reverse_endianness_float_t((float_t*)(d + 80), emit->data.rotation_add.z); + store_reverse_endianness_float_t((float_t*)(d + 84), emit->data.rotation_add_random.x); + store_reverse_endianness_float_t((float_t*)(d + 88), emit->data.rotation_add_random.y); + store_reverse_endianness_float_t((float_t*)(d + 92), emit->data.rotation_add_random.z); + } + else { + *(int32_t*)d = emit->data.start_time; + *(int32_t*)(d + 4) = emit->data.life_time; + *(int32_t*)(d + 8) = emit->data.loop_start_time; + *(int32_t*)(d + 12) = emit->data.loop_end_time; + *(int32_t*)(d + 16) = emit->data.flags; + *(int16_t*)(d + 20) = (int16_t)emit->data.type; + *(int16_t*)(d + 22) = (int16_t)emit->data.direction; + *(float_t*)(d + 24) = emit->data.emission_interval; + *(float_t*)(d + 28) = emit->data.particles_per_emission; + *(int16_t*)(d + 32) = 0; + *(int16_t*)(d + 34) = 0; + + *(vec3*)(d + 36) = emit->translation; + *(vec3*)(d + 48) = emit->rotation; + *(vec3*)(d + 60) = emit->scale; + *(vec3*)(d + 72) = emit->data.rotation_add; + *(vec3*)(d + 84) = emit->data.rotation_add_random; + } d += 96; switch (emit->data.type) { case EMITTER_BOX: - *(vec3*)d = emit->data.box.size; + if (big_endian) { + store_reverse_endianness_float_t((float_t*)d, emit->data.box.size.x); + store_reverse_endianness_float_t((float_t*)(d + 4), emit->data.box.size.y); + store_reverse_endianness_float_t((float_t*)(d + 8), emit->data.box.size.z); + } + else + *(vec3*)d = emit->data.box.size; break; case EMITTER_CYLINDER: - *(float_t*)d = emit->data.cylinder.radius; - *(float_t*)(d + 4) = emit->data.cylinder.height; - *(float_t*)(d + 8) = emit->data.cylinder.start_angle; - *(float_t*)(d + 12) = emit->data.cylinder.end_angle; - *(int32_t*)(d + 16) = ((int32_t)emit->data.cylinder.direction << 1) - | (emit->data.cylinder.on_edge ? 1 : 0); + if (big_endian) { + store_reverse_endianness_float_t((float_t*)d, emit->data.cylinder.radius); + store_reverse_endianness_float_t((float_t*)(d + 4), emit->data.cylinder.height); + store_reverse_endianness_float_t((float_t*)(d + 8), emit->data.cylinder.start_angle); + store_reverse_endianness_float_t((float_t*)(d + 12), emit->data.cylinder.end_angle); + store_reverse_endianness_int32_t((int32_t*)(d + 16), ((int32_t)emit->data.cylinder.direction << 1) + | (emit->data.cylinder.on_edge ? 1 : 0)); + } + else { + *(float_t*)d = emit->data.cylinder.radius; + *(float_t*)(d + 4) = emit->data.cylinder.height; + *(float_t*)(d + 8) = emit->data.cylinder.start_angle; + *(float_t*)(d + 12) = emit->data.cylinder.end_angle; + *(int32_t*)(d + 16) = ((int32_t)emit->data.cylinder.direction << 1) + | (emit->data.cylinder.on_edge ? 1 : 0); + } break; case EMITTER_SPHERE: - *(float_t*)d = emit->data.sphere.radius; - *(float_t*)(d + 4) = emit->data.sphere.latitude; - *(float_t*)(d + 8) = emit->data.sphere.longitude; - *(int32_t*)(d + 12) = ((int32_t)emit->data.sphere.direction << 1) - | (emit->data.sphere.on_edge ? 1 : 0); + if (big_endian) { + store_reverse_endianness_float_t((float_t*)d, emit->data.sphere.radius); + store_reverse_endianness_float_t((float_t*)(d + 4), emit->data.sphere.latitude); + store_reverse_endianness_float_t((float_t*)(d + 8), emit->data.sphere.longitude); + store_reverse_endianness_int32_t((int32_t*)(d + 12), ((int32_t)emit->data.sphere.direction << 1) + | (emit->data.sphere.on_edge ? 1 : 0)); + } + else { + *(float_t*)d = emit->data.sphere.radius; + *(float_t*)(d + 4) = emit->data.sphere.latitude; + *(float_t*)(d + 8) = emit->data.sphere.longitude; + *(int32_t*)(d + 12) = ((int32_t)emit->data.sphere.direction << 1) + | (emit->data.sphere.on_edge ? 1 : 0); + } break; case EMITTER_POLYGON: - *(float_t*)d = emit->data.polygon.size; - *(int32_t*)(d + 4) = emit->data.polygon.count; + if (big_endian) { + store_reverse_endianness_float_t((float_t*)d, emit->data.polygon.size); + store_reverse_endianness_int32_t((int32_t*)(d + 4), emit->data.polygon.count); + } + else { + *(float_t*)d = emit->data.polygon.size; + *(int32_t*)(d + 4) = emit->data.polygon.count; + } break; } @@ -539,13 +728,14 @@ namespace Glitter { st->header.signature = reverse_endianness_uint32_t('EMIT'); st->header.length = 0x20; - st->header.use_big_endian = false; + st->header.use_big_endian = big_endian; st->header.use_section_size = true; st->header.version = emit->version; return true; } - bool FileWriter::PackParticle(EffectGroup* eff_group, f2_struct* st, Particle* ptcl, Effect* eff) { + bool FileWriter::PackParticle(EffectGroup* eff_group, + f2_struct* st, Particle* ptcl, Effect* eff, bool big_endian) { if (ptcl->version < 2) return false; @@ -615,72 +805,164 @@ namespace Glitter { else type = ptcl->data.type; - *(int32_t*)d = ptcl->data.life_time; - *(int32_t*)(d + 4) = type; - *(int32_t*)(d + 8) = ptcl->data.draw_type; - *(vec3*)(d + 12) = ptcl->data.rotation; - *(vec3*)(d + 24) = ptcl->data.rotation_random; - *(vec3*)(d + 36) = ptcl->data.rotation_add; - *(vec3*)(d + 48) = ptcl->data.rotation_add_random; - *(vec3*)(d + 60) = ptcl->data.scale; - *(vec3*)(d + 72) = ptcl->data.scale_random; - *(float_t*)(d + 84) = ptcl->data.z_offset; - *(int32_t*)(d + 88) = ptcl->data.pivot; - *(int32_t*)(d + 92) = flags; - *(float_t*)(d + 96) = ptcl->data.speed; - *(float_t*)(d + 100) = ptcl->data.speed_random; - *(float_t*)(d + 104) = ptcl->data.deceleration; - *(float_t*)(d + 108) = ptcl->data.deceleration_random; - *(vec3*)(d + 112) = ptcl->data.direction; - *(vec3*)(d + 124) = ptcl->data.direction_random; - *(vec3*)(d + 136) = ptcl->data.gravity; - *(vec3*)(d + 148) = ptcl->data.acceleration; - *(vec3*)(d + 160) = ptcl->data.acceleration_random; - *(float_t*)(d + 172) = ptcl->data.reflection_coeff; - *(float_t*)(d + 176) = ptcl->data.reflection_coeff_random; - *(float_t*)(d + 180) = ptcl->data.rebound_plane_y; - *(vec2*)(d + 184) = ptcl->data.uv_scroll_add; - *(float_t*)(d + 192) = ptcl->data.uv_scroll_add_scale; - *(int32_t*)(d + 196) = ptcl->data.sub_flags; - *(int32_t*)(d + 200) = ptcl->data.count; + if (big_endian) { + store_reverse_endianness_int32_t((int32_t*)d, ptcl->data.life_time); + store_reverse_endianness_int32_t((int32_t*)(d + 4), type); + store_reverse_endianness_int32_t((int32_t*)(d + 8), ptcl->data.draw_type); + store_reverse_endianness_float_t((float_t*)(d + 12), ptcl->data.rotation.x); + store_reverse_endianness_float_t((float_t*)(d + 16), ptcl->data.rotation.y); + store_reverse_endianness_float_t((float_t*)(d + 20), ptcl->data.rotation.z); + store_reverse_endianness_float_t((float_t*)(d + 24), ptcl->data.rotation_random.x); + store_reverse_endianness_float_t((float_t*)(d + 28), ptcl->data.rotation_random.y); + store_reverse_endianness_float_t((float_t*)(d + 32), ptcl->data.rotation_random.z); + store_reverse_endianness_float_t((float_t*)(d + 36), ptcl->data.rotation_add.x); + store_reverse_endianness_float_t((float_t*)(d + 40), ptcl->data.rotation_add.y); + store_reverse_endianness_float_t((float_t*)(d + 44), ptcl->data.rotation_add.z); + store_reverse_endianness_float_t((float_t*)(d + 48), ptcl->data.rotation_add_random.x); + store_reverse_endianness_float_t((float_t*)(d + 52), ptcl->data.rotation_add_random.y); + store_reverse_endianness_float_t((float_t*)(d + 56), ptcl->data.rotation_add_random.z); + store_reverse_endianness_float_t((float_t*)(d + 60), ptcl->data.scale.x); + store_reverse_endianness_float_t((float_t*)(d + 64), ptcl->data.scale.y); + store_reverse_endianness_float_t((float_t*)(d + 68), ptcl->data.scale.z); + store_reverse_endianness_float_t((float_t*)(d + 72), ptcl->data.scale_random.x); + store_reverse_endianness_float_t((float_t*)(d + 76), ptcl->data.scale_random.y); + store_reverse_endianness_float_t((float_t*)(d + 80), ptcl->data.scale_random.z); + store_reverse_endianness_float_t((float_t*)(d + 84), ptcl->data.z_offset); + store_reverse_endianness_int32_t((int32_t*)(d + 88), ptcl->data.pivot); + store_reverse_endianness_int32_t((int32_t*)(d + 92), flags); + store_reverse_endianness_float_t((float_t*)(d + 96), ptcl->data.speed); + store_reverse_endianness_float_t((float_t*)(d + 100), ptcl->data.speed_random); + store_reverse_endianness_float_t((float_t*)(d + 104), ptcl->data.deceleration); + store_reverse_endianness_float_t((float_t*)(d + 108), ptcl->data.deceleration_random); + store_reverse_endianness_float_t((float_t*)(d + 112), ptcl->data.direction.x); + store_reverse_endianness_float_t((float_t*)(d + 116), ptcl->data.direction.y); + store_reverse_endianness_float_t((float_t*)(d + 120), ptcl->data.direction.z); + store_reverse_endianness_float_t((float_t*)(d + 124), ptcl->data.direction_random.x); + store_reverse_endianness_float_t((float_t*)(d + 128), ptcl->data.direction_random.y); + store_reverse_endianness_float_t((float_t*)(d + 132), ptcl->data.direction_random.z); + store_reverse_endianness_float_t((float_t*)(d + 136), ptcl->data.gravity.x); + store_reverse_endianness_float_t((float_t*)(d + 140), ptcl->data.gravity.y); + store_reverse_endianness_float_t((float_t*)(d + 144), ptcl->data.gravity.z); + store_reverse_endianness_float_t((float_t*)(d + 148), ptcl->data.acceleration.x); + store_reverse_endianness_float_t((float_t*)(d + 152), ptcl->data.acceleration.y); + store_reverse_endianness_float_t((float_t*)(d + 156), ptcl->data.acceleration.z); + store_reverse_endianness_float_t((float_t*)(d + 160), ptcl->data.acceleration_random.x); + store_reverse_endianness_float_t((float_t*)(d + 164), ptcl->data.acceleration_random.y); + store_reverse_endianness_float_t((float_t*)(d + 168), ptcl->data.acceleration_random.z); + store_reverse_endianness_float_t((float_t*)(d + 172), ptcl->data.reflection_coeff); + store_reverse_endianness_float_t((float_t*)(d + 176), ptcl->data.reflection_coeff_random); + store_reverse_endianness_float_t((float_t*)(d + 180), ptcl->data.rebound_plane_y); + store_reverse_endianness_float_t((float_t*)(d + 184), ptcl->data.uv_scroll_add.x); + store_reverse_endianness_float_t((float_t*)(d + 188), ptcl->data.uv_scroll_add.y); + store_reverse_endianness_float_t((float_t*)(d + 192), ptcl->data.uv_scroll_add_scale); + store_reverse_endianness_int32_t((int32_t*)(d + 196), ptcl->data.sub_flags); + store_reverse_endianness_int32_t((int32_t*)(d + 200), ptcl->data.count); + } + else { + *(int32_t*)d = ptcl->data.life_time; + *(int32_t*)(d + 4) = type; + *(int32_t*)(d + 8) = ptcl->data.draw_type; + *(vec3*)(d + 12) = ptcl->data.rotation; + *(vec3*)(d + 24) = ptcl->data.rotation_random; + *(vec3*)(d + 36) = ptcl->data.rotation_add; + *(vec3*)(d + 48) = ptcl->data.rotation_add_random; + *(vec3*)(d + 60) = ptcl->data.scale; + *(vec3*)(d + 72) = ptcl->data.scale_random; + *(float_t*)(d + 84) = ptcl->data.z_offset; + *(int32_t*)(d + 88) = ptcl->data.pivot; + *(int32_t*)(d + 92) = flags; + *(float_t*)(d + 96) = ptcl->data.speed; + *(float_t*)(d + 100) = ptcl->data.speed_random; + *(float_t*)(d + 104) = ptcl->data.deceleration; + *(float_t*)(d + 108) = ptcl->data.deceleration_random; + *(vec3*)(d + 112) = ptcl->data.direction; + *(vec3*)(d + 124) = ptcl->data.direction_random; + *(vec3*)(d + 136) = ptcl->data.gravity; + *(vec3*)(d + 148) = ptcl->data.acceleration; + *(vec3*)(d + 160) = ptcl->data.acceleration_random; + *(float_t*)(d + 172) = ptcl->data.reflection_coeff; + *(float_t*)(d + 176) = ptcl->data.reflection_coeff_random; + *(float_t*)(d + 180) = ptcl->data.rebound_plane_y; + *(vec2*)(d + 184) = ptcl->data.uv_scroll_add; + *(float_t*)(d + 192) = ptcl->data.uv_scroll_add_scale; + *(int32_t*)(d + 196) = ptcl->data.sub_flags; + *(int32_t*)(d + 200) = ptcl->data.count; + } d += 204; if (ptcl->version == 3) { *(int32_t*)d = 0; - *(float_t*)(d + 4) = ptcl->data.emission; + if (big_endian) + store_reverse_endianness_float_t((float_t*)(d + 4), ptcl->data.emission); + else + *(float_t*)(d + 4) = ptcl->data.emission; d += 8; } if (ptcl->data.type == PARTICLE_LOCUS || ptcl->data.type == PARTICLE_MESH) { - *(uint16_t*)d = ptcl->data.locus_history_size; - *(uint16_t*)(d + 2) = ptcl->data.locus_history_size_random; + if (big_endian) { + store_reverse_endianness_uint16_t((uint16_t*)d, (uint16_t)ptcl->data.locus_history_size); + store_reverse_endianness_uint16_t((uint16_t*)(d + 2), (uint16_t)ptcl->data.locus_history_size_random); + } + else { + *(uint16_t*)d = (uint16_t)ptcl->data.locus_history_size; + *(uint16_t*)(d + 2) = (uint16_t)ptcl->data.locus_history_size_random; + } d += 4; } - *(uint64_t*)d = ptcl->data.tex_hash; - *(uint8_t*)(d + 8) = (uint8_t)roundf(clamp(ptcl->data.color.x, 0.0f, 1.0f) * 255.0f); - *(uint8_t*)(d + 9) = (uint8_t)roundf(clamp(ptcl->data.color.y, 0.0f, 1.0f) * 255.0f); - *(uint8_t*)(d + 10) = (uint8_t)roundf(clamp(ptcl->data.color.z, 0.0f, 1.0f) * 255.0f); - *(uint8_t*)(d + 11) = (uint8_t)roundf(clamp(ptcl->data.color.w, 0.0f, 1.0f) * 255.0f); - *(int32_t*)(d + 12) = ptcl->data.blend_mode; - *(int32_t*)(d + 16) = ptcl->data.unk0; - *(int32_t*)(d + 20) = ptcl->data.split_u; - *(int32_t*)(d + 24) = ptcl->data.split_v; - *(int32_t*)(d + 28) = ptcl->data.uv_index_type; - *(int16_t*)(d + 32) = ptcl->data.uv_index; - *(int16_t*)(d + 34) = (int16_t)ptcl->data.frame_step_uv; - *(int32_t*)(d + 36) = ptcl->data.uv_index_start; - *(int32_t*)(d + 40) = ptcl->data.uv_index_end; + if (big_endian) { + store_reverse_endianness_uint64_t((uint64_t*)d, ptcl->data.tex_hash); + *(uint8_t*)(d + 8) = (uint8_t)roundf(clamp_def(ptcl->data.color.x, 0.0f, 1.0f) * 255.0f); + *(uint8_t*)(d + 9) = (uint8_t)roundf(clamp_def(ptcl->data.color.y, 0.0f, 1.0f) * 255.0f); + *(uint8_t*)(d + 10) = (uint8_t)roundf(clamp_def(ptcl->data.color.z, 0.0f, 1.0f) * 255.0f); + *(uint8_t*)(d + 11) = (uint8_t)roundf(clamp_def(ptcl->data.color.w, 0.0f, 1.0f) * 255.0f); + store_reverse_endianness_int32_t((int32_t*)(d + 12), ptcl->data.blend_mode); + store_reverse_endianness_int32_t((int32_t*)(d + 16), ptcl->data.unk0); + store_reverse_endianness_int32_t((int32_t*)(d + 20), ptcl->data.split_u); + store_reverse_endianness_int32_t((int32_t*)(d + 24), ptcl->data.split_v); + store_reverse_endianness_int32_t((int32_t*)(d + 28), ptcl->data.uv_index_type); + store_reverse_endianness_int16_t((int16_t*)(d + 32), (int16_t)ptcl->data.uv_index); + store_reverse_endianness_int16_t((int16_t*)(d + 34), (int16_t)ptcl->data.frame_step_uv); + store_reverse_endianness_int32_t((int32_t*)(d + 36), ptcl->data.uv_index_start); + store_reverse_endianness_int32_t((int32_t*)(d + 40), ptcl->data.uv_index_end); + } + else { + *(uint64_t*)d = ptcl->data.tex_hash; + *(uint8_t*)(d + 8) = (uint8_t)roundf(clamp_def(ptcl->data.color.x, 0.0f, 1.0f) * 255.0f); + *(uint8_t*)(d + 9) = (uint8_t)roundf(clamp_def(ptcl->data.color.y, 0.0f, 1.0f) * 255.0f); + *(uint8_t*)(d + 10) = (uint8_t)roundf(clamp_def(ptcl->data.color.z, 0.0f, 1.0f) * 255.0f); + *(uint8_t*)(d + 11) = (uint8_t)roundf(clamp_def(ptcl->data.color.w, 0.0f, 1.0f) * 255.0f); + *(int32_t*)(d + 12) = ptcl->data.blend_mode; + *(int32_t*)(d + 16) = ptcl->data.unk0; + *(int32_t*)(d + 20) = ptcl->data.split_u; + *(int32_t*)(d + 24) = ptcl->data.split_v; + *(int32_t*)(d + 28) = ptcl->data.uv_index_type; + *(int16_t*)(d + 32) = (int16_t)ptcl->data.uv_index; + *(int16_t*)(d + 34) = (int16_t)ptcl->data.frame_step_uv; + *(int32_t*)(d + 36) = ptcl->data.uv_index_start; + *(int32_t*)(d + 40) = ptcl->data.uv_index_end; + } + d += 44; + if (eff_group->version >= 7) { - *(int32_t*)(d + 44) = ptcl->data.unk1; - d += 48; + if (big_endian) + store_reverse_endianness_int32_t((int32_t*)d, ptcl->data.unk1); + else + *(int32_t*)d = ptcl->data.unk1; + d += 4; } else - d += 44; if (ptcl->data.flags & PARTICLE_TEXTURE_MASK) { - *(uint64_t*)d = ptcl->data.mask_tex_hash; - *(int32_t*)(d + 8) = ptcl->data.mask_blend_mode; + if (big_endian) { + store_reverse_endianness_uint64_t((uint64_t*)d, ptcl->data.mask_tex_hash); + store_reverse_endianness_int32_t((int32_t*)(d + 8), ptcl->data.mask_blend_mode); + } + else { + *(uint64_t*)d = ptcl->data.mask_tex_hash; + *(int32_t*)(d + 8) = ptcl->data.mask_blend_mode; + } d += 12; } else { @@ -693,13 +975,13 @@ namespace Glitter { st->header.signature = reverse_endianness_uint32_t('PTCL'); st->header.length = 0x20; - st->header.use_big_endian = false; + st->header.use_big_endian = big_endian; st->header.use_section_size = true; st->header.version = ptcl->version; return true; } - bool FileWriter::UnparseAnimation(f2_struct* st, Animation* anim, CurveTypeFlags flags) { + bool FileWriter::UnparseAnimation(f2_struct* st, Animation* anim, CurveTypeFlags flags, bool big_endian) { if (anim->curves.size() < 1) return false; @@ -746,7 +1028,7 @@ namespace Glitter { continue; f2_struct s; - if (UnparseCurve(&s, c)) { + if (UnparseCurve(&s, c, big_endian)) { st->sub_structs.push_back(s); break; } @@ -758,12 +1040,12 @@ namespace Glitter { st->header.signature = reverse_endianness_uint32_t('ANIM'); st->header.length = 0x20; - st->header.use_big_endian = false; + st->header.use_big_endian = big_endian; st->header.use_section_size = true; return true; } - bool FileWriter::UnparseCurve(f2_struct* st, Curve* c) { + bool FileWriter::UnparseCurve(f2_struct* st, Curve* c, bool big_endian) { #if !defined(CRE_DEV) if (c->keys.size() < 1) return false; @@ -806,24 +1088,35 @@ namespace Glitter { 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)c->keys.size(); - *(int16_t*)(d + 18) = (int16_t)c->start_time; - *(int16_t*)(d + 20) = (int16_t)c->end_time; + if (big_endian) { + store_reverse_endianness_uint32_t((uint32_t*)d, c->type); + store_reverse_endianness_uint32_t((uint32_t*)(d + 4), c->repeat ? 1 : 0); + store_reverse_endianness_uint32_t((uint32_t*)(d + 8), c->flags); + store_reverse_endianness_float_t((float_t*)(d + 12), random_range); + store_reverse_endianness_int16_t((int16_t*)(d + 16), (int16_t)c->keys.size()); + store_reverse_endianness_int16_t((int16_t*)(d + 18), (int16_t)c->start_time); + store_reverse_endianness_int16_t((int16_t*)(d + 20), (int16_t)c->end_time); + } + else { + *(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)c->keys.size(); + *(int16_t*)(d + 18) = (int16_t)c->start_time; + *(int16_t*)(d + 20) = (int16_t)c->end_time; + } st->enrs = e; st->header.signature = reverse_endianness_uint32_t('CURV'); st->header.length = 0x20; - st->header.use_big_endian = false; + st->header.use_big_endian = big_endian; st->header.use_section_size = true; st->header.version = c->version; f2_struct s; - PackCurve(&s, c); + PackCurve(&s, c, big_endian); st->sub_structs.push_back(s); #if defined(CRE_DEV) @@ -832,8 +1125,8 @@ namespace Glitter { return true; } - bool FileWriter::UnparseDivaEffect(EffectGroup* eff_group, f2_struct* st) { - UnparseEffectGroup(eff_group, st); + bool FileWriter::UnparseDivaEffect(EffectGroup* eff_group, f2_struct* st, bool big_endian) { + UnparseEffectGroup(eff_group, st, big_endian); st->header.signature = reverse_endianness_uint32_t('DVEF'); st->header.length = 0x20; @@ -843,16 +1136,16 @@ namespace Glitter { return true; } - bool FileWriter::UnparseDivaList(EffectGroup* eff_group, f2_struct* st) { + bool FileWriter::UnparseDivaList(EffectGroup* eff_group, f2_struct* st, bool big_endian) { f2_struct s; - if (!PackDivaList(eff_group, &s)) + if (!PackDivaList(eff_group, &s, big_endian)) return false; st->sub_structs.push_back(s); st->header.signature = reverse_endianness_uint32_t('LIST'); st->header.length = 0x20; - st->header.use_big_endian = false; + st->header.use_big_endian = big_endian; st->header.use_section_size = true; return true; } @@ -872,12 +1165,12 @@ namespace Glitter { return true; } - bool FileWriter::UnparseEffect(EffectGroup* eff_group, f2_struct* st, Effect* eff) { - if (!PackEffect(st, eff)) + bool FileWriter::UnparseEffect(EffectGroup* eff_group, f2_struct* st, Effect* eff, bool big_endian) { + if (!PackEffect(st, eff, big_endian)) return false; f2_struct s; - if (UnparseAnimation(&s, &eff->animation, effect_curve_flags)) + if (UnparseAnimation(&s, &eff->animation, effect_curve_flags, big_endian)) st->sub_structs.push_back(s); for (Emitter*& i : eff->emitters) { @@ -885,33 +1178,34 @@ namespace Glitter { continue; f2_struct s; - if (UnparseEmitter(eff_group, &s, i, eff)) + if (UnparseEmitter(eff_group, &s, i, eff, big_endian)) st->sub_structs.push_back(s); } return true; } - void FileWriter::UnparseEffectGroup(EffectGroup* eff_group, f2_struct* st) { + void FileWriter::UnparseEffectGroup(EffectGroup* eff_group, f2_struct* st, bool big_endian) { for (Effect*& i : eff_group->effects) { if (!i) continue; f2_struct s; - if (UnparseEffect(eff_group, &s, i)) + if (UnparseEffect(eff_group, &s, i, big_endian)) st->sub_structs.push_back(s); } f2_struct s; - if (PackDivaResourceHashes(eff_group, &s)) + if (PackDivaResourceHashes(eff_group, &s, big_endian)) st->sub_structs.push_back(s); } - bool FileWriter::UnparseEmitter(EffectGroup* eff_group, f2_struct* st, Emitter* emit, Effect* eff) { - if (!PackEmitter(st, emit)) + bool FileWriter::UnparseEmitter(EffectGroup* eff_group, + f2_struct* st, Emitter* emit, Effect* eff, bool big_endian) { + if (!PackEmitter(st, emit, big_endian)) return false; f2_struct s; - if (UnparseAnimation(&s, &emit->animation, emitter_curve_flags)) + if (UnparseAnimation(&s, &emit->animation, emitter_curve_flags, big_endian)) st->sub_structs.push_back(s); for (Particle*& i : emit->particles) { @@ -919,14 +1213,15 @@ namespace Glitter { continue; f2_struct s; - if (UnparseParticle(eff_group, &s, i, eff)) + if (UnparseParticle(eff_group, &s, i, eff, big_endian)) st->sub_structs.push_back(s); } return true; } - bool FileWriter::UnparseParticle(EffectGroup* eff_group, f2_struct* st, Particle* ptcl, Effect* eff) { - if (!PackParticle(eff_group, st, ptcl, eff)) + bool FileWriter::UnparseParticle(EffectGroup* eff_group, + f2_struct* st, Particle* ptcl, Effect* eff, bool big_endian) { + if (!PackParticle(eff_group, st, ptcl, eff, big_endian)) return false; CurveTypeFlags flags; @@ -942,19 +1237,20 @@ namespace Glitter { } f2_struct s; - if (UnparseAnimation(&s, &ptcl->animation, flags)) + if (UnparseAnimation(&s, &ptcl->animation, flags, big_endian)) st->sub_structs.push_back(s); return true; } - void FileWriter::Write(GLT, EffectGroup* eff_group, const char* path, const char* file, bool compress) { + void FileWriter::Write(GLT, EffectGroup* eff_group, + const char* path, const char* file, bool compress, bool big_endian) { FileWriter fr; fr.type = GLT_VAL; farc f; { f2_struct st; - if (fr.UnparseDivaEffect(eff_group, &st)) { + if (fr.UnparseDivaEffect(eff_group, &st, big_endian)) { f.add_file(); farc_file& ff_drs = f.files.back(); st.write(&ff_drs.data, &ff_drs.size); @@ -976,7 +1272,7 @@ namespace Glitter { if (fr.type == Glitter::FT) { f2_struct st; - if (fr.UnparseDivaList(eff_group, &st)) { + if (fr.UnparseDivaList(eff_group, &st, big_endian)) { f.add_file(); farc_file& ff_lst = f.files.back(); st.write(&ff_lst.data, &ff_lst.size); @@ -995,18 +1291,18 @@ namespace Glitter { char* temp = str_utils_add(path, file); if (glt_type != Glitter::FT) { char* list_temp = str_utils_add(temp, ".glitter.txt"); - stream s; + file_stream s; s.open(list_temp, "wb"); - if (s.io.stream) { + if (s.check_not_null()) { for (Glitter::Effect*& i : eff_group->effects) if (i) { s.write_string(i->name); s.write_char('\n'); } } - free(list_temp); + free_def(list_temp); } f.write(temp, mode, false); - free(temp); + free_def(temp); } } diff --git a/src/CRE/Glitter/glitter.cpp b/src/CRE/Glitter/glitter.cpp index cdcb9bbf..5daf006c 100644 --- a/src/CRE/Glitter/glitter.cpp +++ b/src/CRE/Glitter/glitter.cpp @@ -268,7 +268,7 @@ namespace Glitter { vec3_cross(*vec1, *vec2, *axis); vec3_length(*axis, *angle); if (*angle >= 0.000001f) - *angle = asinf(min(*angle, 1.0f)); + *angle = asinf(min_def(*angle, 1.0f)); else { *angle = 0.0f; axis->x = vec1->z; diff --git a/src/CRE/Glitter/glitter.hpp b/src/CRE/Glitter/glitter.hpp index b8bacf67..4835df84 100644 --- a/src/CRE/Glitter/glitter.hpp +++ b/src/CRE/Glitter/glitter.hpp @@ -941,7 +941,7 @@ namespace Glitter { void GetExtColor(float_t& r, float_t& g, float_t& b, float_t& a); FogType GetFog(); void GetValue(); - void SetExtAnim(mat4* a2, mat4* a3, vec3* trans, bool set_flags); + void SetExtAnim(const mat4* a2, const mat4* a3, const vec3* trans, bool set_flags); }; class Emitter : public Node { @@ -1130,24 +1130,28 @@ namespace Glitter { FileWriter(); - void PackCurve(f2_struct* st, Curve* c); - bool PackDivaList(EffectGroup* eff_group, f2_struct* st); + void PackCurve(f2_struct* st, Curve* c, bool big_endian); + bool PackDivaList(EffectGroup* eff_group, f2_struct* st, bool big_endian); bool PackDivaResource(EffectGroup* eff_group, f2_struct* st); - bool PackDivaResourceHashes(EffectGroup* eff_group, f2_struct* st); - bool PackEffect(f2_struct* st, Effect* eff); - bool PackEmitter(f2_struct* st, Emitter* emit); - bool PackParticle(EffectGroup* eff_group, f2_struct* st, Particle* ptcl, Effect* eff); - bool UnparseAnimation(f2_struct* st, Animation* anim, CurveTypeFlags flags); - bool UnparseCurve(f2_struct* st, Curve* c); - bool UnparseDivaEffect(EffectGroup* eff_group, f2_struct* st); - bool UnparseDivaList(EffectGroup* eff_group, f2_struct* st); + bool PackDivaResourceHashes(EffectGroup* eff_group, f2_struct* st, bool big_endian); + bool PackEffect(f2_struct* st, Effect* eff, bool big_endian); + bool PackEmitter(f2_struct* st, Emitter* emit, bool big_endian); + bool PackParticle(EffectGroup* eff_group, + f2_struct* st, Particle* ptcl, Effect* eff, bool big_endian); + bool UnparseAnimation(f2_struct* st, Animation* anim, CurveTypeFlags flags, bool big_endian); + bool UnparseCurve(f2_struct* st, Curve* c, bool big_endian); + bool UnparseDivaEffect(EffectGroup* eff_group, f2_struct* st, bool big_endian); + bool UnparseDivaList(EffectGroup* eff_group, f2_struct* st, bool big_endian); bool UnparseDivaResource(EffectGroup* eff_group, f2_struct* st); - bool UnparseEffect(EffectGroup* eff_group, f2_struct* st, Effect* eff); - void UnparseEffectGroup(EffectGroup* eff_group, f2_struct* st); - bool UnparseEmitter(EffectGroup* eff_group, f2_struct* st, Emitter* emit, Effect* eff); - bool UnparseParticle(EffectGroup* eff_group, f2_struct* st, Particle* ptcl, Effect* eff); + bool UnparseEffect(EffectGroup* eff_group, f2_struct* st, Effect* eff, bool big_endian); + void UnparseEffectGroup(EffectGroup* eff_group, f2_struct* st, bool big_endian); + bool UnparseEmitter(EffectGroup* eff_group, + f2_struct* st, Emitter* emit, Effect* eff, bool big_endian); + bool UnparseParticle(EffectGroup* eff_group, + f2_struct* st, Particle* ptcl, Effect* eff, bool big_endian); - static void Write(GLT, EffectGroup* eff_group, const char* path, const char* file, bool compress); + static void Write(GLT, EffectGroup* eff_group, + const char* path, const char* file, bool compress, bool big_endian = false); }; struct LocusHistory { @@ -1155,6 +1159,8 @@ namespace Glitter { vec4 color; vec3 translation; float_t scale; + + Data(); }; std::vector data; @@ -1234,6 +1240,8 @@ namespace Glitter { int32_t unk0; int32_t unk1; Particle::Mesh mesh; + + Data(); }; Particle::Data data; diff --git a/src/CRE/Glitter/locus_history.cpp b/src/CRE/Glitter/locus_history.cpp index 50732cc2..9acd363f 100644 --- a/src/CRE/Glitter/locus_history.cpp +++ b/src/CRE/Glitter/locus_history.cpp @@ -6,6 +6,10 @@ #include "glitter.hpp" namespace Glitter { + LocusHistory::LocusHistory::Data::Data() :scale() { + + } + LocusHistory::LocusHistory(size_t size) { data.reserve(size); } @@ -21,7 +25,7 @@ namespace Glitter { if (ptcl_inst->data.data.flags & PARTICLE_EMITTER_LOCAL && ptcl_inst->data.emitter) { vec3 emit_trans; mat4_get_translation(&ptcl_inst->data.emitter->mat, &emit_trans); - vec3_add(temp, emit_trans, temp); + temp += emit_trans; } LocusHistory::Data locus_history; @@ -57,7 +61,7 @@ namespace Glitter { if (ptcl_inst->data.data.flags & PARTICLE_EMITTER_LOCAL && ptcl_inst->data.emitter) { vec3 emit_trans; mat4_get_translation(&ptcl_inst->data.emitter->mat, &emit_trans); - vec3_add(temp, emit_trans, temp); + temp += emit_trans; if (ptcl_inst->data.data.flags & PARTICLE_ROTATE_LOCUS) mat4_mult_vec3(&ptcl_inst->data.emitter->mat_rot, &temp, &temp); } diff --git a/src/CRE/Glitter/particle.cpp b/src/CRE/Glitter/particle.cpp index 72a0a810..60c474aa 100644 --- a/src/CRE/Glitter/particle.cpp +++ b/src/CRE/Glitter/particle.cpp @@ -6,6 +6,16 @@ #include "glitter.hpp" namespace Glitter { + Particle::Data::Data() : flags(), life_time(), life_time_random(), fade_in(), fade_in_random(), + fade_out(), fade_out_random(), type(), pivot(), draw_type(), z_offset(), speed(), speed_random(), + deceleration(), deceleration_random(), reflection_coeff(), reflection_coeff_random(), rebound_plane_y(), + uv_index_type(), uv_index(), frame_step_uv(), uv_index_start(), uv_index_end(), uv_index_count(), + uv_scroll_add_scale(), uv_scroll_2nd_add_scale(), split_u(), split_v(), blend_mode(), mask_blend_mode(), + sub_flags(), count(), locus_history_size(), locus_history_size_random(), draw_flags(), + emission(), tex_hash(), mask_tex_hash(), texture(), mask_texture(), unk0(), unk1(), mesh() { + + } + Particle::Particle(GLT) : data() { version = GLT_VAL == Glitter::X ? 0x05 : 0x03; data.pivot = PIVOT_MIDDLE_CENTER; @@ -40,185 +50,3 @@ namespace Glitter { } } - -/* -#include "particle.hpp" -#include "animation.hpp" -#include "curve.hpp" - -static bool glitter_particle_pack_file(GLT, EffectGroup* a1, - f2_struct* st, glitter_particle* a3, glitter_effect* effect); - -bool glitter_particle_unparse_file(GLT, EffectGroup* a1, - f2_struct* st, glitter_particle* a3, glitter_effect* effect) { - if (!glitter_particle_pack_file(GLT_VAL, a1, st, a3, effect)) - return false; - - glitter_curve_type_flags flags = (glitter_curve_type_flags)0; - if (a1->type == Glitter::X) - flags = glitter_particle_x_curve_flags; - else - flags = glitter_particle_curve_flags; - - if (a3->data.type != PARTICLE_MESH) { - enum_and(flags, ~CURVE_TYPE_UV_SCROLL_2ND); - if (a3->data.draw_type != DIRECTION_PARTICLE_ROTATION) - enum_and(flags, ~(CURVE_TYPE_ROTATION_X | CURVE_TYPE_ROTATION_Y)); - } - - f2_struct s; - if (glitter_animation_unparse_file(GLT_VAL, &s, &a3->animation, flags)) - st->sub_structs.push_back(s); - return true; -} - -static bool glitter_particle_pack_file(GLT, - EffectGroup* a1, f2_struct* st, glitter_particle* a3, glitter_effect* effect) { - size_t l; - size_t d; - glitter_particle_flag flags; - - if (a3->version < 2) - return false; - - l = 0; - - uint32_t o; - enrs e; - enrs_entry ee; - - ee = { 0, 1, 204, 1 }; - ee.append(0, 51, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 204; - - if (a3->version == 3) { - ee = { o, 1, 8, 1 }; - ee.append(0, 2, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 8; - } - - if (a3->data.type == PARTICLE_LOCUS || a3->data.type == PARTICLE_MESH) { - ee = { o, 1, 4, 1 }; - ee.append(0, 2, ENRS_WORD); - e.vec.push_back(ee); - l += o = 4; - } - - ee = { o, 4, 44, 1 }; - ee.append(0, 1, ENRS_QWORD); - ee.append(4, 5, ENRS_DWORD); - ee.append(0, 2, ENRS_WORD); - ee.append(0, 2, ENRS_DWORD); - if (a1->version >= 7) { - ee.count++; - ee.size += 4; - ee.append.push_back(0, 1, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 48; - } - else { - e.vec.push_back(ee); - l += o = 44; - } - - ee = { o, 2, 12, 1 }; - ee.append.push_back(0, 1, ENRS_QWORD); - ee.append.push_back(0, 1, ENRS_DWORD); - e.vec.push_back(ee); - l += o = 12; - - l = align_val(l, 0x10); - st->data.resize(l); - d = (size_t)st->data.data(); - st->enrs = e; - - flags = a3->data.flags; - if (effect->data.flags & EFFECT_LOCAL) - enum_and(flags, ~PARTICLE_LOCAL); - if (effect->data.flags & EFFECT_EMISSION) - enum_and(flags, ~PARTICLE_EMISSION); - - *(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) { - *(int32_t*)d = 0; - *(float_t*)(d + 4) = a3->data.emission; - d += 8; - } - - if (a3->data.type == PARTICLE_LOCUS || a3->data.type == PARTICLE_MESH) { - *(uint16_t*)d = a3->data.locus_history_size; - *(uint16_t*)(d + 2) = a3->data.locus_history_size_random; - d += 4; - } - - *(uint64_t*)d = a3->data.tex_hash; - *(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_mode; - *(int32_t*)(d + 16) = a3->data.unk0; - *(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) = a3->data.unk1; - d += 48; - } - else - d += 44; - - if (a3->data.flags & PARTICLE_TEXTURE_MASK) { - *(uint64_t*)d = a3->data.mask_tex_hash; - *(int32_t*)(d + 8) = a3->data.mask_blend_mode; - d += 12; - } - else { - *(uint64_t*)d = 0; - *(int32_t*)(d + 8) = 0; - d += 12; - } - - st->header.signature = reverse_endianness_uint32_t('PTCL'); - st->header.length = 0x20; - st->header.use_big_endian = false; - st->header.use_section_size = true; - st->header.version = a3->version; - return true; -} -*/ \ No newline at end of file diff --git a/src/CRE/Glitter/particle_inst.cpp b/src/CRE/Glitter/particle_inst.cpp index e61344dd..0b42e0a5 100644 --- a/src/CRE/Glitter/particle_inst.cpp +++ b/src/CRE/Glitter/particle_inst.cpp @@ -236,7 +236,7 @@ namespace Glitter { + random->F2GetInt(GLT_VAL, ptcl_inst_data->data.uv_index_count); break; } - rend_elem->uv_index = min(rend_elem->uv_index, ptcl_inst_data->data.uv_index_end); + rend_elem->uv_index = min_def(rend_elem->uv_index, ptcl_inst_data->data.uv_index_end); rend_elem->uv.x = (float_t)(rend_elem->uv_index % ptcl_inst_data->data.split_u) * ptcl_inst_data->data.split_uv.x; rend_elem->uv.y = (float_t)(rend_elem->uv_index @@ -559,7 +559,7 @@ namespace Glitter { float_t time = rend_elem->frame * (float_t)(1.0 / 60.0); float_t diff_time = time - rend_elem->rebound_time - (float_t)(1.0 / 60.0); float_t speed = rend_elem->speed * delta_frame; - diff_time = max(diff_time, 0.0f) * (float_t)(1.0 / 60.0); + diff_time = max_def(diff_time, 0.0f) * (float_t)(1.0 / 60.0); vec3 acceleration; vec3_mult_scalar(rend_elem->acceleration, @@ -593,7 +593,7 @@ namespace Glitter { speed = rend_elem->base_speed + (float_t)(1.0 / 7200.0) * rend_elem->deceleration - diff_time * rend_elem->deceleration; - rend_elem->speed = max(speed, 0.0f); + rend_elem->speed = max_def(speed, 0.0f); } void XParticleInst::Copy(XParticleInst* dst, float_t emission) { @@ -711,7 +711,7 @@ namespace Glitter { + random->XGetInt(ptcl_inst_data->data.uv_index_count); break; } - rend_elem->uv_index = min(rend_elem->uv_index, ptcl_inst_data->data.uv_index_end); + rend_elem->uv_index = min_def(rend_elem->uv_index, ptcl_inst_data->data.uv_index_end); rend_elem->uv.x = (float_t)(rend_elem->uv_index % ptcl_inst_data->data.split_u) * ptcl_inst_data->data.split_uv.x; rend_elem->uv.y = (float_t)(rend_elem->uv_index diff --git a/src/CRE/Glitter/particle_manager.cpp b/src/CRE/Glitter/particle_manager.cpp index 91870d7e..3973d78b 100644 --- a/src/CRE/Glitter/particle_manager.cpp +++ b/src/CRE/Glitter/particle_manager.cpp @@ -761,7 +761,7 @@ namespace Glitter { id++; } CheckSceneHasLocalEffect(j); - + SceneCounter counter = j->counter; if (j->type == Glitter::X) counter.index = (uint8_t)id; @@ -789,7 +789,7 @@ namespace Glitter { } CheckSceneHasLocalEffect(scene); scenes.push_back(scene); - + if (scene->type == Glitter::X) counter.index = (uint8_t)id; return counter; @@ -922,7 +922,7 @@ namespace Glitter { break; } } - + void GltParticleManager::SetSceneFrameRate(SceneCounter scene_counter, FrameRateControl* frame_rate) { for (Scene*& i : scenes) if (i && i->counter.counter == scene_counter.counter) { @@ -930,7 +930,7 @@ namespace Glitter { break; } } - + void GltParticleManager::SetSceneName(uint64_t hash, const char* name) { std::map::iterator elem = effect_groups.find(hash); if (elem != effect_groups.end()) diff --git a/src/CRE/Glitter/render_element.cpp b/src/CRE/Glitter/render_element.cpp index 72944046..745f1c52 100644 --- a/src/CRE/Glitter/render_element.cpp +++ b/src/CRE/Glitter/render_element.cpp @@ -75,7 +75,7 @@ namespace Glitter { float_t deceleration = random->F2GetFloat(GLT_VAL, ptcl_inst_data->data.deceleration_random) + ptcl_inst_data->data.deceleration; this->speed = speed * 60.0f; - this->deceleration = max(deceleration * 60.0f, 0.0f); + this->deceleration = max_def(deceleration * 60.0f, 0.0f); vec3 acceleration; random->F2GetVec3(GLT_VAL, ptcl_inst_data->data.acceleration_random, acceleration); @@ -123,7 +123,7 @@ namespace Glitter { ptcl_inst_data->data.deceleration_random) + ptcl_inst_data->data.deceleration; base_speed = speed; this->speed = speed; - this->deceleration = max(deceleration, 0.0f); + this->deceleration = max_def(deceleration, 0.0f); vec3 acceleration; random->XGetVec3(ptcl_inst_data->data.acceleration_random, acceleration); diff --git a/src/CRE/Glitter/render_group.cpp b/src/CRE/Glitter/render_group.cpp index 2a8160a9..23a8d965 100644 --- a/src/CRE/Glitter/render_group.cpp +++ b/src/CRE/Glitter/render_group.cpp @@ -100,8 +100,8 @@ namespace Glitter { glGenBuffers(1, &ebo); gl_state_bind_element_array_buffer(ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int32_t) * count, ebo_data, GL_STATIC_DRAW);; - free(ebo_data); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int32_t) * count, ebo_data, GL_STATIC_DRAW); + free_def(ebo_data); } static const GLsizei buffer_size = sizeof(Buffer); @@ -214,16 +214,13 @@ namespace Glitter { particle->AccelerateParticle(GLT_VAL, rend_elem, rend_elem->frame * (float_t)(1.0 / 60.0), delta_frame, random_ptr); - if (particle->data.data.draw_type == DIRECTION_PARTICLE_ROTATION) { - rend_elem->rotation.x += rend_elem->rotation_add.x * delta_frame; - rend_elem->rotation.y += rend_elem->rotation_add.y * delta_frame; - } - rend_elem->rotation.z += rend_elem->rotation_add.z * delta_frame; + if (particle->data.data.draw_type == DIRECTION_PARTICLE_ROTATION) + rend_elem->rotation += rend_elem->rotation_add * delta_frame; + else + rend_elem->rotation.z += rend_elem->rotation_add.z * delta_frame; - vec2 uv_scroll; - vec2_mult_scalar(particle->data.data.uv_scroll_add, - particle->data.data.uv_scroll_add_scale * delta_frame, uv_scroll); - vec2_add(rend_elem->uv_scroll, uv_scroll, rend_elem->uv_scroll); + rend_elem->uv_scroll += particle->data.data.uv_scroll_add + * (particle->data.data.uv_scroll_add_scale * delta_frame); particle->StepUVParticle(GLT_VAL, rend_elem, delta_frame, random_ptr); rend_elem->disp = true; @@ -453,8 +450,8 @@ namespace Glitter { glGenBuffers(1, &ebo); gl_state_bind_element_array_buffer(ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int32_t) * count, ebo_data, GL_STATIC_DRAW);; - free(ebo_data); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int32_t) * count, ebo_data, GL_STATIC_DRAW); + free_def(ebo_data); } if (!is_mesh) { @@ -574,11 +571,10 @@ namespace Glitter { particle->AccelerateParticle(rend_elem, delta_frame, random_ptr); if (particle->data.data.draw_type == DIRECTION_PARTICLE_ROTATION - || particle->data.data.type == PARTICLE_MESH) { - rend_elem->rotation.x += rend_elem->rotation_add.x * delta_frame; - rend_elem->rotation.y += rend_elem->rotation_add.y * delta_frame; - } - rend_elem->rotation.z += rend_elem->rotation_add.z * delta_frame; + || particle->data.data.type == PARTICLE_MESH) + rend_elem->rotation += rend_elem->rotation_add * delta_frame; + else + rend_elem->rotation.z += rend_elem->rotation_add.z * delta_frame; vec2 uv_scroll; vec2_mult_scalar(particle->data.data.uv_scroll_add, @@ -642,7 +638,7 @@ namespace Glitter { if (!a2 && elements) { Free(); - free(elements); + free_def(elements); } } void XRenderGroup::Emit(XParticleInst::Data* ptcl_inst_data, diff --git a/src/CRE/Glitter/render_scene.cpp b/src/CRE/Glitter/render_scene.cpp index 063b0726..7750db58 100644 --- a/src/CRE/Glitter/render_scene.cpp +++ b/src/CRE/Glitter/render_scene.cpp @@ -485,7 +485,7 @@ namespace Glitter { RenderElement* elem = rend_group->elements; size_t disp = 0; for (size_t i = rend_group->ctrl, j_max = 1024; i > 0; i -= j_max) { - j_max = min(i, j_max); + j_max = min_def(i, j_max); for (size_t j = j_max; j > 0; elem++) { if (!elem->alive) continue; @@ -639,7 +639,7 @@ namespace Glitter { size_t disp = 0; if (rend_group->draw_type == DIRECTION_PARTICLE_ROTATION) for (size_t i = rend_group->ctrl, j_max = 1024; i > 0; i -= j_max) { - j_max = min(i, j_max); + j_max = min_def(i, j_max); for (size_t j = j_max; j > 0; elem++) { if (!elem->alive) continue; @@ -722,7 +722,7 @@ namespace Glitter { } else for (size_t i = rend_group->ctrl, j_max = 1024; i > 0; i -= j_max) { - j_max = min(i, j_max); + j_max = min_def(i, j_max); for (size_t j = j_max; j > 0; elem++) { if (!elem->alive) continue; @@ -1020,7 +1020,6 @@ namespace Glitter { case PARTICLE_QUAD: { gl_state_bind_vertex_array(rend_group->vao); shaders_ft.draw_elements(GL_TRIANGLES, (GLsizei)(6 * rend_group->disp), GL_UNSIGNED_INT, 0); - gl_state_bind_vertex_array(0); } break; case PARTICLE_LINE: @@ -1029,7 +1028,6 @@ namespace Glitter { const GLenum mode = rend_group->type == PARTICLE_LINE ? GL_LINE_STRIP : GL_TRIANGLE_STRIP; for (std::pair& i : rend_group->draw_list) shaders_ft.draw_arrays(mode, i.first, i.second); - gl_state_bind_vertex_array(0); } break; } @@ -1457,7 +1455,7 @@ namespace Glitter { RenderElement* elem = rend_group->elements; size_t disp = 0; for (size_t i = rend_group->ctrl, j_max = 1024; i > 0; i -= j_max) { - j_max = min(i, j_max); + j_max = min_def(i, j_max); for (size_t j = j_max; j > 0; elem++) { if (!elem->alive) continue; @@ -1628,7 +1626,7 @@ namespace Glitter { RenderElement* elem = rend_group->elements; size_t disp = 0; for (size_t i = rend_group->ctrl, j_max = 1024; i > 0; i -= j_max) { - j_max = min(i, j_max); + j_max = min_def(i, j_max); for (size_t j = j_max; j > 0; elem++) { if (!elem->alive) continue; @@ -1778,7 +1776,7 @@ namespace Glitter { size_t disp = 0; if (rend_group->draw_type == DIRECTION_PARTICLE_ROTATION) for (size_t i = rend_group->ctrl, j_max = 1024; i > 0; i -= j_max) { - j_max = min(i, j_max); + j_max = min_def(i, j_max); for (size_t j = j_max; j > 0; elem++) { if (!elem->alive) continue; @@ -1856,7 +1854,7 @@ namespace Glitter { } else for (size_t i = rend_group->ctrl, j_max = 1024; i > 0; i -= j_max) { - j_max = min(i, j_max); + j_max = min_def(i, j_max); for (size_t j = j_max; j > 0; elem++) { if (!elem->alive) continue; diff --git a/src/CRE/Glitter/scene.cpp b/src/CRE/Glitter/scene.cpp index 08acc512..8683e1d2 100644 --- a/src/CRE/Glitter/scene.cpp +++ b/src/CRE/Glitter/scene.cpp @@ -76,7 +76,7 @@ namespace Glitter { continue; EffectInst* eff = i.ptr; - + bool v13 = false; bool v14 = false; if (v14) @@ -259,7 +259,7 @@ namespace Glitter { return false; return true; } - + bool Scene::HasEnded(size_t id, bool a3) { for (SceneEffect& i : effects) if (i.ptr && i.disp && i.ptr->id == id && !i.ptr->HasEnded(a3)) @@ -320,7 +320,7 @@ namespace Glitter { return false; } #endif - + if (type == Glitter::FT && effect_hash == hash_fnv1a64m_empty || type != Glitter::FT && effect_hash == hash_murmurhash_empty) { for (SceneEffect& i : effects) diff --git a/src/CRE/auth_3d.cpp b/src/CRE/auth_3d.cpp index a29ee180..cf04badb 100644 --- a/src/CRE/auth_3d.cpp +++ b/src/CRE/auth_3d.cpp @@ -4,6 +4,7 @@ */ #include "auth_3d.hpp" +#include "../KKdLib/io/file_stream.hpp" #include "../KKdLib/io/json.hpp" #include "../KKdLib/io/path.hpp" #include "../KKdLib/hash.hpp" @@ -75,9 +76,9 @@ static int32_t auth_3d_get_auth_3d_object_index_by_hash(auth_3d* auth, uint32_t object_hash, int32_t instance); static mat4* auth_3d_get_auth_3d_object_hrc_bone_mats(auth_3d* auth, size_t index); static int32_t auth_3d_get_auth_3d_object_hrc_index_by_object_info(auth_3d* auth, - object_info obj_info, int32_t instance); + object_info obj_info, int32_t instance = -1); static int32_t auth_3d_get_auth_3d_object_hrc_index_by_hash(auth_3d* auth, - uint32_t object_hash, int32_t instance); + uint32_t object_hash, int32_t instance = -1); static void auth_3d_read_file(auth_3d* auth, auth_3d_database* auth_3d_db); static void auth_3d_read_file_modern(auth_3d* auth); static void auth_3d_set_material_list(auth_3d* auth, render_context* rctx); @@ -339,8 +340,8 @@ void auth_3d::ctrl(render_context* rctx) { auth_3d_post_process_ctrl(&post_process, frame); auth_3d_post_process_set(&post_process, rctx); - auth_3d_camera_auxiliary_set(&camera_auxiliary, rctx); auth_3d_camera_auxiliary_ctrl(&camera_auxiliary, frame); + auth_3d_camera_auxiliary_set(&camera_auxiliary, rctx); if (camera_root_update) for (auth_3d_camera_root& i : camera_root) { @@ -1146,7 +1147,7 @@ void auth_3d_light::reset() { linear_init = 0.0f; quadratic_init = 0.0f; specular_init = vec4_null; - tone_curve_init = vec3_null; + tone_curve_init = {}; } auth_3d_m_object_hrc::auth_3d_m_object_hrc() { @@ -2303,7 +2304,7 @@ static void a3da_msgpack_read(const char* path, const char* file, a3da* auth_fil msgpack msg; - stream s; + file_stream s; s.open(buf, "rb"); io_json_read(s, &msg); s.close(); @@ -2311,9 +2312,9 @@ static void a3da_msgpack_read(const char* path, const char* file, a3da* auth_fil if (msg.type != MSGPACK_MAP) return; - msgpack* m_objhrcs = msg.read("m_objhrc"); + msgpack* m_objhrcs = msg.read_array("m_objhrc"); if (m_objhrcs) { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, m_objhrcs); + msgpack_array* ptr = m_objhrcs->data.arr; for (msgpack& i : *ptr) { msgpack& m_objhrc = i; @@ -2324,9 +2325,9 @@ static void a3da_msgpack_read(const char* path, const char* file, a3da* auth_fil if (name_hash != hash_string_murmurhash(j.name)) continue; - msgpack* instances = m_objhrc.read("instance"); + msgpack* instances = m_objhrc.read_array("instance"); if (instances) { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, instances); + msgpack_array* ptr = instances->data.arr; for (msgpack& k : *ptr) { msgpack& instance = k; @@ -2340,9 +2341,9 @@ static void a3da_msgpack_read(const char* path, const char* file, a3da* auth_fil } } - msgpack* objhrcs = msg.read("objhrc"); + msgpack* objhrcs = msg.read_array("objhrc"); if (objhrcs) { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, objhrcs); + msgpack_array* ptr = objhrcs->data.arr; for (msgpack& i : *ptr) { msgpack& objhrc = i; @@ -2364,7 +2365,7 @@ static bool auth_3d_key_detect_fast_change(auth_3d_key* data, float_t frame, flo if (data->type < AUTH_3D_KEY_LINEAR || data->type > AUTH_3D_KEY_HOLD) return false; - frame = clamp(frame, 0.0f, data->max_frame); + frame = clamp_def(frame, 0.0f, data->max_frame); size_t length = data->length; if (!length) return false; @@ -2622,25 +2623,39 @@ static mat4* auth_3d_get_auth_3d_object_hrc_bone_mats(auth_3d* auth, size_t inde static int32_t auth_3d_get_auth_3d_object_hrc_index_by_object_info(auth_3d* auth, object_info obj_info, int32_t instance) { - int32_t obj_instance = 0; - for (auth_3d_object_hrc& i : auth->object_hrc) - if (obj_info == i.object_info) { - if (obj_instance == instance) + if (instance < 0) { + for (auth_3d_object_hrc& i : auth->object_hrc) + if (obj_info == i.object_info) return (int32_t)(&i - auth->object_hrc.data()); - obj_instance++; - } + } + else { + int32_t obj_instance = 0; + for (auth_3d_object_hrc& i : auth->object_hrc) + if (obj_info == i.object_info) { + if (obj_instance == instance) + return (int32_t)(&i - auth->object_hrc.data()); + obj_instance++; + } + } return -1; } static int32_t auth_3d_get_auth_3d_object_hrc_index_by_hash(auth_3d* auth, uint32_t object_hash, int32_t instance) { - int32_t obj_instance = 0; - for (auth_3d_object_hrc& i : auth->object_hrc) - if (object_hash == i.object_hash) { - if (obj_instance == instance) + if (instance < 0) { + for (auth_3d_object_hrc& i : auth->object_hrc) + if (object_hash == i.object_hash) return (int32_t)(&i - auth->object_hrc.data()); - obj_instance++; - } + } + else { + int32_t obj_instance = 0; + for (auth_3d_object_hrc& i : auth->object_hrc) + if (object_hash == i.object_hash) { + if (obj_instance == instance) + return (int32_t)(&i - auth->object_hrc.data()); + obj_instance++; + } + } return -1; } @@ -2954,8 +2969,7 @@ static void auth_3d_dof_set(auth_3d_dof* d, render_context* rctx) { vec3 view_point; rctx->camera->get_view_point(view_point); - float_t focus; - vec3_distance(d->model_transform.translation_value, view_point, focus); + float_t focus = vec3::distance(d->model_transform.translation_value, view_point); dof_pv pv; pv.enable = fabsf(d->model_transform.rotation_value.z) > 0.000001f; @@ -3281,7 +3295,11 @@ static void auth_3d_light_set(auth_3d_light* l, render_context* rctx) { enum_or(l->flags_init, AUTH_3D_LIGHT_TONE_CURVE); } - data->set_tone_curve(*(vec3*)&l->tone_curve.value); + light_tone_curve tone_curve; + tone_curve.start_point = l->tone_curve.value.x; + tone_curve.end_point = l->tone_curve.value.y; + tone_curve.coefficient = l->tone_curve.value.z; + data->set_tone_curve(tone_curve); } } @@ -4679,7 +4697,7 @@ static void Auth3dTestTask__SetStage(Auth3dTestTask* tt) { if (!v7) break; - if (memcmp(v7, "STG", min(v5, 3))) { + if (memcmp(v7, "STG", min_def(v5, 3))) { v5 += v6 - v7 - 1; v6 = v7 + 1; continue; diff --git a/src/CRE/auth_3d.hpp b/src/CRE/auth_3d.hpp index b9a9262a..bed7522b 100644 --- a/src/CRE/auth_3d.hpp +++ b/src/CRE/auth_3d.hpp @@ -430,7 +430,7 @@ struct auth_3d_light { float_t linear_init; float_t quadratic_init; vec4 specular_init; - vec3 tone_curve_init; + light_tone_curve tone_curve_init; auth_3d_light(); ~auth_3d_light(); @@ -852,9 +852,9 @@ extern bool auth_3d_data_check_id_loaded(int32_t* id); extern auth_3d* auth_3d_data_get_auth_3d(int32_t id); extern int32_t auth_3d_data_get_auth_3d_id(const char* object_name); extern int32_t auth_3d_data_get_auth_3d_id(object_info obj_info, - int32_t* object_index, bool* hrc, int32_t instance); + int32_t* object_index, bool* hrc, int32_t instance = -1); extern int32_t auth_3d_data_get_auth_3d_id(uint32_t file_name_hash, uint32_t object_hash, - int32_t* object_index, bool* hrc, int32_t instance); + int32_t* object_index, bool* hrc, int32_t instance = -1); extern mat4* auth_3d_data_get_auth_3d_object_mat(int32_t id, size_t index, bool hrc, mat4* mat); extern int32_t auth_3d_data_get_chara_id(int32_t id); extern bool auth_3d_data_get_enable(int32_t* id); diff --git a/src/CRE/camera.cpp b/src/CRE/camera.cpp index 27218e19..158275ee 100644 --- a/src/CRE/camera.cpp +++ b/src/CRE/camera.cpp @@ -6,14 +6,14 @@ #include "camera.hpp" static void camera_calculate_projection(camera* c); +static void camera_calculate_projection_aet(camera* c); static void camera_calculate_view(camera* c); static void camera_calculate_forward(camera* c); -camera::camera() : view(), inv_view(), projection(), inv_projection(), view_projection(), -inv_view_projection(), view_projection_prev(), inv_view_projection_prev(), view_mat3(), inv_view_mat3(), -view_rot(), inv_view_rot(), forward(), rotation(), view_point(), interest(), width(), height(), field_1E4(), -field_1F0(), field_1FC(), field_208(), yaw(), pitch(), roll(), aspect(), fov(), fov_rad(),max_distance(), -min_distance(), changed_view(), changed_proj(), fast_change(), fast_change_hist0(), fast_change_hist1() { +camera::camera() : forward(), rotation(), view_point(), interest(), render_width(), render_height(), +sprite_width(), sprite_height(), field_1E4(), field_1F0(), field_1FC(), field_208(), yaw(), +pitch(), roll(), aspect(), fov(), fov_rad(), max_distance(), min_distance(), changed_view(), +changed_proj(), changed_proj_aet(), fast_change(), fast_change_hist0(), fast_change_hist1() { } @@ -21,15 +21,18 @@ camera::~camera() { } -void camera::initialize(double_t aspect, int32_t width, int32_t height) { +void camera::initialize(double_t aspect, int32_t render_width, + int32_t render_height, int32_t sprite_width, int32_t sprite_height) { this->aspect = aspect; fov = 0.0; forward = { 0.0f, 0.0f, -1.0f }; rotation = { 0.0f, 0.0f, 0.0f }; view_point = { 0.0, 0.0f, 0.0f }; interest = { 0.0f, 0.0f, -1.0f }; - this->width = width; - this->height = height; + this->render_width = render_width; + this->render_height = render_height; + this->sprite_width = sprite_width; + this->sprite_height = sprite_height; view = mat4_identity; inv_view = mat4_identity; projection = mat4_identity; @@ -41,6 +44,7 @@ void camera::initialize(double_t aspect, int32_t width, int32_t height) { min_distance = 0.05; max_distance = 6000.0; changed_proj = true; + changed_proj_aet = true; changed_view = true; fast_change = false; fast_change_hist0 = false; @@ -62,6 +66,7 @@ void camera::set_min_distance(double_t value) { if (value != min_distance) { min_distance = value; changed_proj = true; + changed_proj_aet = true; } } @@ -92,7 +97,7 @@ double_t camera::get_fov() { } void camera::set_fov(double_t value) { - value = clamp(value, 1.0, 180.0); + value = clamp_def(value, 1.0, 180.0); if (value != fov) { fov = value; fov_rad = value * DEG_TO_RAD; @@ -106,7 +111,7 @@ double_t camera::get_pitch() { void camera::set_pitch(double_t value) { value = fmod(value, 360.0); - value = clamp(value, -89.5, 89.5); + value = clamp_def(value, -89.5, 89.5); if (pitch != value) { pitch = value; changed_view = true; @@ -173,16 +178,24 @@ void camera::set_interest(const vec3&& value) { } } -void camera::get_res(int32_t& width, int32_t& height) { - width = this->width; - height = this->height; +void camera::get_res(int32_t& render_width, int32_t& render_height, + int32_t& sprite_width, int32_t& sprite_height) { + render_width = this->render_width; + render_height = this->render_height; + sprite_width = this->sprite_width; + sprite_height = this->sprite_height; } -void camera::set_res(int32_t width, int32_t height) { - if (this->width != width || this->height != height) { - this->width = width; - this->height = height; +void camera::set_res(int32_t render_width, int32_t render_height, + int32_t sprite_width, int32_t sprite_height) { + if (this->render_width != render_width || this->render_height != render_height + || this->sprite_width != sprite_width || this->sprite_height != sprite_height) { + this->render_width = render_width; + this->render_height = render_height; + this->sprite_width = sprite_width; + this->sprite_height = sprite_height; changed_proj = true; + changed_proj_aet = true; } } @@ -215,20 +228,12 @@ void camera::reset() { void camera::move(double_t move_x, double_t move_y) { if (move_x != 0.0 || move_y != 0.0) { - vec3 temp; - vec3 view_point; - vec3 interest; vec3 up = { 0.0f, 1.0f, 0.0f }; - vec3_cross(forward, up, temp); - vec3_normalize(temp, temp); - vec3_mult_scalar(temp, (float_t)move_y, temp); - vec3_add(this->view_point, temp, view_point); - vec3_mult_scalar(forward, (float_t)move_x, temp); - vec3_add(view_point, temp, view_point); - - vec3_add(view_point, forward, interest); + vec3 view_point = this->view_point; + view_point += vec3::normalize(vec3::cross(forward, up)) * (float_t)move_y; + view_point += forward * (float_t)move_x; set_view_point(view_point); - set_interest(interest); + set_interest(view_point + forward); } } @@ -242,9 +247,7 @@ void camera::rotate(double_t rotate_x, double_t rotate_y) { if (rotate_x != 0.0 || rotate_y != 0.0) { camera_calculate_forward(this); - vec3 interest; - vec3_add(view_point, forward, interest); - set_interest(interest); + set_interest(view_point + forward); } } @@ -279,17 +282,13 @@ void camera::set(const vec3&& view_point, const vec3&& interest, } void camera::set_position(const vec3& pos) { - vec3 interest; - vec3_add(pos, forward, interest); set_view_point(pos); - set_interest(interest); + set_interest(pos + forward); } void camera::set_position(const vec3&& pos) { - vec3 interest; - vec3_add(pos, forward, interest); set_view_point(pos); - set_interest(interest); + set_interest(pos + forward); } void camera::update() { @@ -304,6 +303,9 @@ void camera::update_data() { if (changed_proj) camera_calculate_projection(this); + if (changed_proj_aet) + camera_calculate_projection_aet(this); + if (changed_view) camera_calculate_view(this); @@ -313,6 +315,7 @@ void camera::update_data() { } changed_proj = false; + changed_proj_aet = false; changed_view = false; } @@ -326,31 +329,67 @@ static void camera_calculate_projection(camera* c) { mat4_persp(c->fov_rad, c->aspect, c->min_distance, c->max_distance, &c->projection); mat4_inverse(&c->projection, &c->inv_projection); - float_t fov_correct_height = (float_t)(((double_t)c->height * 0.5) / tan(c->fov_rad * 0.5)); - float_t height = (float_t)c->height * 0.5f; - float_t width = (float_t)c->height * (float_t)c->aspect * 0.5f; + float_t fov_correct_height = (float_t)(((double_t)c->render_height * 0.5) / tan(c->fov_rad * 0.5)); + float_t height = (float_t)c->render_height * 0.5f; + float_t width = (float_t)c->render_height * (float_t)c->aspect * 0.5f; c->field_1E4.x = fov_correct_height; c->field_1E4.y = 0.0f; c->field_1E4.z = -width; - vec3_normalize(c->field_1E4, c->field_1E4); + c->field_1E4 = vec3::normalize(c->field_1E4); c->field_1F0.x = -fov_correct_height; c->field_1F0.y = 0.0f; c->field_1F0.z = -width; - vec3_normalize(c->field_1F0, c->field_1F0); + c->field_1F0 = vec3::normalize(c->field_1F0); c->field_1FC.x = 0.0f; c->field_1FC.y = fov_correct_height; c->field_1FC.z = -height; - vec3_normalize(c->field_1FC, c->field_1FC); + c->field_1FC = vec3::normalize(c->field_1FC); c->field_208.x = 0.0f; c->field_208.y = -fov_correct_height; c->field_208.z = -height; - vec3_normalize(c->field_208, c->field_208); + c->field_208 = vec3::normalize(c->field_208); +} + +static void camera_calculate_projection_aet(camera* c) { + float_t sprite_half_width = (float_t)c->sprite_width * 0.5f; + float_t sprite_half_height = (float_t)c->sprite_height * 0.5f; + float_t render_half_width = (float_t)c->render_width * 0.5f; + float_t render_half_height = (float_t)c->render_height * 0.5f; + + float_t aet_depth = sprite_half_height / (tanf(0.34557518363f) * 0.75f); + + float_t v8a = (float_t)c->min_distance / aet_depth * sprite_half_width; + float_t v8b = (float_t)c->min_distance / aet_depth * sprite_half_height; + + mat4 spr_2d_proj; + mat4_frustrum(-v8a, v8a, v8b, -v8b, c->min_distance, 3000.0, &spr_2d_proj); + + vec3 spr_2d_viewpoint = { sprite_half_width, sprite_half_height, aet_depth }; + vec3 spr_2d_interest = { sprite_half_width, sprite_half_height, 0.0f }; + vec3 spr_2d_up = { 0.0f, 1.0f, 0.0f }; + mat4 spr_2d_view; + mat4_look_at(&spr_2d_viewpoint, &spr_2d_interest, &spr_2d_up, &spr_2d_view); + + mat4_mult(&spr_2d_view, &spr_2d_proj, &c->projection_aet_2d); + + float_t v13a = (float_t)c->min_distance / aet_depth * render_half_width; + float_t v13b = (float_t)c->min_distance / aet_depth * render_half_height; + + mat4 spr_3d_proj; + mat4_frustrum(-v13a, v13a, v13b, -v13b, c->min_distance, 3000.0, &spr_3d_proj); + + vec3 spr_3d_viewpoint = { render_half_width, render_half_height, render_half_height }; + vec3 spr_3d_interest = { render_half_width, render_half_height, 0.0f }; + vec3 spr_3d_up = { 0.0f, 1.0f, 0.0f }; + mat4 spr_3d_view; + mat4_look_at(&spr_3d_viewpoint, &spr_3d_interest, &spr_3d_up, &spr_3d_view); + + mat4_mult(&spr_3d_view, &spr_3d_proj, &c->projection_aet_3d); } static void camera_calculate_view(camera* c) { - vec3 direction; - vec3_sub(c->view_point, c->interest, direction); + vec3 direction = c->view_point - c->interest; vec3 rotation; rotation.x = atan2f(-direction.y, sqrtf(direction.x * direction.x + direction.z * direction.z)); @@ -358,10 +397,9 @@ static void camera_calculate_view(camera* c) { rotation.z = (float_t)(c->roll * DEG_TO_RAD); c->rotation = rotation; - vec3_negate(rotation, rotation); + rotation = -rotation; - vec3 view_point; - vec3_negate(c->view_point, view_point); + vec3 view_point = -c->view_point; mat4_rotate_z(rotation.z, &c->view); mat4_rotate_x_mult(&c->view, rotation.x, &c->view); diff --git a/src/CRE/camera.hpp b/src/CRE/camera.hpp index 72735058..05763aae 100644 --- a/src/CRE/camera.hpp +++ b/src/CRE/camera.hpp @@ -22,12 +22,16 @@ struct camera { mat3 inv_view_mat3; mat4 view_rot; mat4 inv_view_rot; + mat4 projection_aet_2d; + mat4 projection_aet_3d; vec3 forward; vec3 rotation; vec3 view_point; vec3 interest; - int32_t width; - int32_t height; + int32_t render_width; + int32_t render_height; + int32_t sprite_width; + int32_t sprite_height; vec3 field_1E4; vec3 field_1F0; vec3 field_1FC; @@ -42,6 +46,7 @@ struct camera { double_t min_distance; bool changed_view; bool changed_proj; + bool changed_proj_aet; bool fast_change; bool fast_change_hist0; bool fast_change_hist1; @@ -49,7 +54,8 @@ struct camera { camera(); virtual ~camera(); - void initialize(double_t aspect, int32_t width, int32_t height); + void initialize(double_t aspect, int32_t render_width, int32_t render_height, + int32_t sprite_width, int32_t sprite_height); double_t get_min_distance(); void set_min_distance(double_t value); double_t get_max_distance(); @@ -70,8 +76,10 @@ struct camera { void get_interest(vec3& value); void set_interest(const vec3& value); void set_interest(const vec3&& value); - void get_res(int32_t& width, int32_t& height); - void set_res(int32_t width, int32_t height); + void get_res(int32_t& render_width, int32_t& render_height, + int32_t& sprite_width, int32_t& sprite_height); + void set_res(int32_t render_width, int32_t render_height, + int32_t sprite_width, int32_t sprite_height); void set_fast_change(bool value); void set_fast_change_hist0(bool value); void set_fast_change_hist1(bool value); diff --git a/src/CRE/data.cpp b/src/CRE/data.cpp index fc3b7ca7..e4f197a3 100644 --- a/src/CRE/data.cpp +++ b/src/CRE/data.cpp @@ -4,8 +4,9 @@ */ #include "data.hpp" +#include "../KKdLib/io/file_stream.hpp" +#include "../KKdLib/io/memory_stream.hpp" #include "../KKdLib/io/path.hpp" -#include "../KKdLib/io/stream.hpp" #include "../KKdLib/hash.hpp" #include "../KKdLib/str_utils.hpp" #include "mdata_manager.hpp" @@ -27,26 +28,30 @@ void data_struct_init() { } void data_struct_load(const char* path) { - stream s; + file_stream s; s.open(path, "rb"); - if (s.io.stream) + if (s.check_not_null()) data_load_inner(s); else { s.close(); - s.open(default_config, 7); - data_load_inner(s); + + memory_stream ms; + ms.open(default_config, 7); + data_load_inner(ms); } } void data_struct_load(const wchar_t* path) { - stream s; + file_stream s; s.open(path, L"rb"); - if (s.io.stream) + if (s.check_not_null()) data_load_inner(s); else { s.close(); - s.open(default_config, 7); - data_load_inner(s); + + memory_stream ms; + ms.open(default_config, 7); + data_load_inner(ms); } } @@ -93,6 +98,16 @@ void data_struct_load_db() { d->obj_db.add(&obj_db_file); } + for (std::string& i : prefixes) { + std::string file = i + "spr_db.bin"; + + sprite_database_file spr_db_file; + spr_db_file.modern = false; + ds->load_file(&spr_db_file, "rom/2d/", file.c_str(), + sprite_database_file::load_file); + d->spr_db.add(&spr_db_file); + } + for (std::string& i : prefixes) { std::string file = i + "stage_data.bin"; @@ -247,39 +262,22 @@ bool data_struct::check_directory_exists(const char* dir) { dir_len--; } - size_t max_len = 0; - for (data_struct_path& i : data_paths) - for (data_struct_directory& j : i.data) - if (max_len < j.path.size()) - max_len = j.path.size(); + std::string dir_temp(dir, dir_len); - char* dir_temp = force_malloc_s(char, dir_len + 1); - memcpy(dir_temp, dir, dir_len + 1); - - char* t = dir_temp; + char* t = (char*)dir_temp.c_str(); while (t = strchr(t, '/')) *t = '\\'; - char* temp = force_malloc_s(char, max_len + dir_len + 2); + std::string temp; for (data_struct_path& i : data_paths) for (data_struct_directory& j : i.data) { - const char* path = j.path.c_str(); - size_t path_len = j.path.size(); + temp.assign(j.path); + temp += '\\'; + temp.append(dir_temp); - memcpy(temp, path, path_len); - memcpy(&temp[path_len], "\\", 2); - if (dir_len) - memcpy(&temp[path_len + 1], dir_temp, dir_len + 1); - - if (path_check_directory_exists(temp)) { - free(dir_temp); - free(temp); + if (path_check_directory_exists(temp.c_str())) return true; - } } - - free(dir_temp); - free(temp); return false; } @@ -339,44 +337,24 @@ bool data_struct::check_file_exists(const char* dir, const char* file) { dir_len--; } - size_t max_len = 0; - for (data_struct_path& i : data_paths) - for (data_struct_directory& j : i.data) - if (max_len < j.path.size()) - max_len = j.path.size(); + std::string dir_temp(dir, dir_len); - char* dir_temp = force_malloc_s(char, dir_len + 1); - memcpy(dir_temp, dir, dir_len + 1); - - char* t = dir_temp; + char* t = (char*)dir_temp.c_str(); while (t = strchr(t, '/')) *t = '\\'; - char* temp = force_malloc_s(char, max_len + dir_len + file_len + 2); + std::string temp; for (data_struct_path& i : data_paths) for (data_struct_directory& j : i.data) { - const char* path = j.path.c_str(); - size_t path_len = j.path.size(); + temp.assign(j.path); + temp += '\\'; + temp.append(dir_temp); + temp.append(file, file_len); - memcpy(temp, path, path_len); - memcpy(&temp[path_len], "\\", 2); - if (dir_len) { - memcpy(&temp[path_len + 1], dir_temp, dir_len + 1); - memcpy(&temp[path_len + dir_len + 1], file, file_len + 1); - } - else - memcpy(&temp[path_len + 1], file, file_len + 1); - - if (path_check_file_exists(temp)) { - free(dir_temp); - free(temp); + if (path_check_file_exists(temp.c_str())) return true; - } } - free(dir_temp); - free(temp); - if (f2) return check_file_exists("rom/data/", file); return false; @@ -407,32 +385,20 @@ bool data_struct::check_file_exists(const char* dir, uint32_t hash) { dir_len--; } - size_t max_len = 0; - for (data_struct_path& i : data_paths) - for (data_struct_directory& j : i.data) - if (max_len < j.path.size()) - max_len = j.path.size(); + std::string dir_temp(dir, dir_len); - char* dir_temp = force_malloc_s(char, dir_len + 1); - memcpy(dir_temp, dir, dir_len + 1); - - char* t = dir_temp; + char* t = (char*)dir_temp.c_str(); while (t = strchr(t, '/')) *t = '\\'; - char* temp = force_malloc_s(char, max_len + dir_len + 2); + std::string temp; for (data_struct_path& i : data_paths) for (data_struct_directory& j : i.data) { - const char* path = j.path.c_str(); - size_t path_len = j.path.size(); + temp.assign(j.path); + temp += '\\'; + temp.append(dir_temp); - memcpy(temp, path, path_len); - memcpy(&temp[path_len], "\\", 2); - if (dir_len) - memcpy(&temp[path_len + 1], dir_temp, dir_len + 1); - - std::vector files; - path_get_files(&files, temp); + std::vector files = path_get_files(temp.c_str()); if (!files.size()) continue; @@ -449,16 +415,10 @@ bool data_struct::check_file_exists(const char* dir, uint32_t hash) { } for (uint32_t& l : files_murmurhash) - if (l == hash) { - free(dir_temp); - free(temp); + if (l == hash) return true; - } } - free(dir_temp); - free(temp); - if (f2) return check_file_exists("rom/data/", hash); return false; @@ -492,32 +452,20 @@ void data_struct::get_directory_files(const char* dir, std::vector files; - path_get_files(&files, temp); + std::vector files = path_get_files(temp.c_str()); if (!files.size()) continue; @@ -533,14 +481,11 @@ void data_struct::get_directory_files(const char* dir, std::vector files; - path_get_files(&files, temp); + std::vector files = path_get_files(temp.c_str()); if (!files.size()) continue; @@ -608,17 +541,12 @@ bool data_struct::get_file(const char* dir, uint32_t hash, const char* ext, std: t = l.c_str(); if (hash_murmurhash(t, t_len) == hash) { - file = l; - free(dir_temp); - free(temp); + file.assign(l); return true; } } } - free(dir_temp); - free(temp); - if (f2) return get_file("rom/data/", hash, ext, file); return false; @@ -682,39 +610,22 @@ bool data_struct::load_file(void* data, const char* dir, const char* file, dir_len--; } - size_t max_len = 0; - for (data_struct_path& i : data_paths) - for (data_struct_directory& j : i.data) - if (max_len < j.path.size()) - max_len = j.path.size(); + std::string dir_temp(dir, dir_len); - char* dir_temp = force_malloc_s(char, dir_len + 1); - memcpy(dir_temp, dir, dir_len + 1); - - char* t = dir_temp; + char* t = (char*)dir_temp.c_str(); while(t = strchr(t, '/')) *t = '\\'; - char* temp = force_malloc_s(char, max_len + dir_len + file_len + 2); + std::string temp; for (data_struct_path& i : data_paths) for (data_struct_directory& j : i.data) { - const char* path = j.path.c_str(); - size_t path_len = j.path.size(); + temp.assign(j.path); + temp += '\\'; + temp.append(dir_temp); + temp.append(file, file_len); - memcpy(temp, path, path_len); - memcpy(&temp[path_len], "\\", 2); - if (dir_len) { - memcpy(&temp[path_len + 1], dir_temp, dir_len + 1); - memcpy(&temp[path_len + dir_len + 1], file, file_len + 1); - } - else - memcpy(&temp[path_len + 1], file, file_len + 1); - - if (path_check_file_exists(temp)) { - if (dir_len) - temp[path_len + dir_len + 1] = 0; - else - temp[path_len + 1] = 0; + if (path_check_file_exists(temp.c_str())) { + temp.resize(temp.size() - file_len); const char* l_str = file; const char* t = strrchr(l_str, '.'); @@ -725,17 +636,11 @@ bool data_struct::load_file(void* data, const char* dir, const char* file, l_len = file_len; uint32_t h = hash_murmurhash(l_str, l_len); - if (load_func(data, temp, l_str, h)) { - free(dir_temp); - free(temp); + if (load_func(data, temp.c_str(), l_str, h)) return true; - } } } - free(dir_temp); - free(temp); - if (f2) return load_file(data, "rom/data/", file, load_func); return false; @@ -767,32 +672,20 @@ bool data_struct::load_file(void* data, const char* dir, uint32_t hash, const ch dir_len--; } - size_t max_len = 0; - for (data_struct_path& i : data_paths) - for (data_struct_directory& j : i.data) - if (max_len < j.path.size()) - max_len = j.path.size(); + std::string dir_temp(dir, dir_len); - char* dir_temp = force_malloc_s(char, dir_len + 1); - memcpy(dir_temp, dir, dir_len + 1); - - char* t = dir_temp; + char* t = (char*)dir_temp.c_str(); while (t = strchr(t, '/')) *t = '\\'; - char* temp = force_malloc_s(char, max_len + dir_len + 2); + std::string temp; for (data_struct_path& i : data_paths) for (data_struct_directory& j : i.data) { - const char* path = j.path.c_str(); - size_t path_len = j.path.size(); + temp.assign(j.path); + temp += '\\'; + temp.append(dir_temp); - memcpy(temp, path, path_len); - memcpy(&temp[path_len], "\\", 2); - if (dir_len) - memcpy(&temp[path_len + 1], dir_temp, dir_len + 1); - - std::vector files; - path_get_files(&files, temp); + std::vector files = path_get_files(temp.c_str()); if (!files.size()) continue; @@ -807,17 +700,11 @@ bool data_struct::load_file(void* data, const char* dir, uint32_t hash, const ch t = l.c_str(); if (hash_murmurhash(t, t_len) == hash - && load_func(data, temp, l.c_str(), hash)) { - free(dir_temp); - free(temp); + && load_func(data, temp.c_str(), l.c_str(), hash)) return true; - } } } - free(dir_temp); - free(temp); - if (f2) return load_file(data, "rom/data/", hash, ext, load_func); return false; @@ -918,11 +805,11 @@ static void data_load_inner(stream& s) { char* buf; char** lines; size_t count; - if (!str_utils_text_file_parse(data, length, &buf, &lines, &count)) { - free(data); + if (!str_utils_text_file_parse(data, length, buf, lines, count)) { + free_def(data); return; } - free(data); + free_def(data); for (size_t i = 0; i < count; i++) { char* s = lines[i]; @@ -1002,36 +889,15 @@ static void data_load_inner(stream& s) { count++; } - size_t max_len = 0; - t = data_paths; - for (size_t j = 0; j < count; j++) { - size_t len = utf8_length(t); - if (max_len < len) - max_len = len; - t += len + 1; - } - size_t main_rom_len = utf8_length(main_rom); size_t add_data_len = utf8_length(add_data); size_t add_data_rom_len = utf8_length(add_data_rom); - char* main_rom_path = force_malloc_s(char, max_len + main_rom_len + 3); - if (!main_rom_path) { - data_free_inner(ds); - continue; - } - - char* add_data_rom_path = force_malloc_s(char, max_len + add_data_len + 3); - if (!add_data_rom_path) { - free(main_rom_path); - data_free_inner(ds); - continue; - } + std::string main_rom_path; + std::string add_data_rom_path; ssize_t* t_len = force_malloc_s(ssize_t, count); if (!t_len) { - free(main_rom_path); - free(add_data_rom_path); data_free_inner(ds); continue; } @@ -1048,94 +914,77 @@ static void data_load_inner(stream& s) { data_path.data = {}; ds->data_paths.push_back(data_path); } - free(t_len); + free_def(t_len); for (data_struct_path& j : ds->data_paths) { const char* data_path = j.path.c_str(); size_t data_path_length = j.path.size(); if (!main_rom_len) - memcpy(main_rom_path, data_path, data_path_length); + main_rom_path.assign(j.path); else if (data_path_length) { - memcpy(main_rom_path, data_path, data_path_length); - main_rom_path[data_path_length] = '\\'; - memcpy(&main_rom_path[data_path_length + 1], main_rom, main_rom_len + 1); + main_rom_path.assign(j.path); + main_rom_path += '\\'; + main_rom_path.append(main_rom, main_rom_len); } else - memcpy(main_rom_path, main_rom, main_rom_len + 1); + main_rom_path.assign(main_rom, main_rom_len); if (!add_data_len) - memcpy(add_data_rom_path, data_path, data_path_length); + add_data_rom_path.assign(j.path); else if (data_path_length) { - memcpy(add_data_rom_path, data_path, data_path_length); - add_data_rom_path[data_path_length] = '\\'; - memcpy(&add_data_rom_path[data_path_length + 1], add_data, add_data_len + 1); + add_data_rom_path.assign(j.path); + add_data_rom_path += '\\'; + add_data_rom_path.append(add_data, add_data_len); } else - memcpy(add_data_rom_path, add_data, add_data_len + 1); + add_data_rom_path.assign(add_data, add_data_len); - size_t main_rom_path_len = utf8_length(main_rom_path); - if (main_rom_path_len && main_rom_path[main_rom_path_len - 1] == '\\') { - main_rom_path[main_rom_path_len - 1] = 0; - main_rom_path_len--; - } + if (main_rom_path.size() && main_rom_path.back() == '\\') + main_rom_path.pop_back(); - size_t add_data_rom_path_len = utf8_length(add_data_rom_path); - if (add_data_rom_path_len && add_data_rom_path[add_data_rom_path_len - 1] == '\\') { - add_data_rom_path[add_data_rom_path_len - 1] = 0; - add_data_rom_path_len--; - } + if (add_data_rom_path.size() && add_data_rom_path.back() == '\\') + add_data_rom_path.pop_back(); - std::vector data_directories; - path_get_directories(&data_directories, add_data_rom_path, &main_rom_path, 1); + const char* exclude_list[1]; + exclude_list[0] = main_rom_path.c_str(); + std::vector data_directories + = path_get_directories(add_data_rom_path.c_str(), exclude_list, 1); - max_len = 0; - for (std::string& k : data_directories) { - size_t len = k.size(); - if (max_len < len) - max_len = len; - } - - char* data_dir_path_temp = force_malloc_s(char, add_data_rom_path_len + max_len + add_data_rom_len + 3); - if (data_dir_path_temp) { + std::string data_dir_path; + if (data_directories.size()) { j.data.reserve(data_directories.size() + 1); - memcpy(data_dir_path_temp, add_data_rom_path, add_data_rom_path_len); - data_dir_path_temp[add_data_rom_path_len] = '\\'; + data_dir_path.assign(add_data_rom_path); + data_dir_path += '\\'; for (std::vector::reverse_iterator k = data_directories.rbegin(); k != data_directories.rend(); k++) { - memcpy(&data_dir_path_temp[add_data_rom_path_len + 1], k->c_str(), k->size() + 1); - if (add_data_rom_len) { - data_dir_path_temp[add_data_rom_path_len + 1 + k->size()] = '\\'; - memcpy(&data_dir_path_temp[add_data_rom_path_len + 1 + k->size() + 1], - add_data_rom, add_data_rom_len + 1); - } - data_struct_directory data_dir; - data_dir.path = data_dir_path_temp; - data_dir.name = *k; + data_dir.path.assign(data_dir_path); + data_dir.path.append(*k); + if (add_data_rom_len) { + data_dir.path += '\\'; + data_dir.path.append(add_data_rom, add_data_rom_len); + } + data_dir.name.assign(*k); j.data.push_back(data_dir); } } else j.data.reserve(1); - free(data_dir_path_temp); data_struct_directory data_dir; data_dir.path = main_rom_path; data_dir.name = {}; j.data.push_back(data_dir); - free(data_dir_path_temp); } - free(main_rom_path); - free(add_data_rom_path); ds->ready = true; } - free(buf); - free(lines); + free_def(buf); + free_def(lines); } #if defined(CRE_DEV) static void data_load_glitter_list(data_struct* ds, const char* path) { - stream s; + file_stream s; s.open(path, "rb"); size_t length = s.length; uint8_t* data = force_malloc_s(uint8_t, length); @@ -1145,7 +994,7 @@ static void data_load_glitter_list(data_struct* ds, const char* path) { char* buf; char** lines; size_t count; - if (str_utils_text_file_parse(data, length, &buf, &lines, &count)) { + if (str_utils_text_file_parse(data, length, buf, lines, count)) { for (size_t i = 0; i < count; i++) { char* t = strstr(lines[i], "#(?)"); if (t) @@ -1156,7 +1005,7 @@ static void data_load_glitter_list(data_struct* ds, const char* path) { glitter_list_names.reserve(count); for (size_t i = 0; i < count; i++) { size_t len = utf8_length(lines[i]); - std::string name = std::string(lines[i], min(len, 0x7F)); + std::string name = std::string(lines[i], min_def(len, 0x7F)); glitter_list_names.push_back(name); } @@ -1183,9 +1032,9 @@ static void data_load_glitter_list(data_struct* ds, const char* path) { break; } - free(buf); - free(lines); + free_def(buf); + free_def(lines); } - free(data); + free_def(data); } #endif diff --git a/src/CRE/data.hpp b/src/CRE/data.hpp index d3e710ff..4a668a2c 100644 --- a/src/CRE/data.hpp +++ b/src/CRE/data.hpp @@ -12,6 +12,7 @@ #include "../KKdLib/database/bone.hpp" #include "../KKdLib/database/motion.hpp" #include "../KKdLib/database/object.hpp" +#include "../KKdLib/database/sprite.hpp" #include "../KKdLib/database/stage.hpp" #include "../KKdLib/database/texture.hpp" #include "../KKdLib/vec.hpp" @@ -68,6 +69,7 @@ struct data_ft { bone_database bone_data; motion_database mot_db; object_database obj_db; + sprite_database spr_db; stage_database stage_data; texture_database tex_db; diff --git a/src/CRE/draw_object.cpp b/src/CRE/draw_object.cpp index a5098d3a..062939ec 100644 --- a/src/CRE/draw_object.cpp +++ b/src/CRE/draw_object.cpp @@ -66,8 +66,7 @@ void draw_object_draw(render_context* rctx, draw_object* draw, mat4* model, if (!show_vector) { - gl_state_bind_vertex_array(rctx->object_data.get_vertex_array( - draw->array_buffer, draw->morph_array_buffer)); + gl_state_bind_vertex_array(rctx->object_data.get_vertex_array(draw)); draw_object_func(rctx, draw); } uniform_value[U_BONE_MAT] = 0; @@ -315,20 +314,17 @@ inline void model_mat_face_camera_position(mat4* view, mat4* src, mat4* dst) { vec3 trans; mat4_get_translation(view, &trans); mat4_mult_vec3_inv_trans(view, &trans, &trans); - vec3_negate(trans, trans); + trans = -trans; - vec3 dir; - vec3_sub(trans, *(vec3*)&src->row3, dir); - vec3_normalize(dir, dir); + vec3 dir = vec3::normalize(trans - *(vec3*)&src->row3); vec3 x_rot; vec3 y_rot; vec3 z_rot; y_rot = *(vec3*)&src->row1; - vec3_cross(y_rot, dir, x_rot); - vec3_normalize(x_rot, x_rot); - vec3_cross(x_rot, y_rot, z_rot); + x_rot = vec3::normalize(vec3::cross(y_rot, dir)); + z_rot = vec3::cross(x_rot, y_rot); *(vec3*)&dst->row0 = x_rot; *(vec3*)&dst->row1 = y_rot; @@ -552,22 +548,23 @@ static void draw_object_material_set_default(render_context* rctx, draw_object* else { gl_state_active_bind_texture_2d(tex_index, tex_id); - GLenum wrap_s = 0; + GLenum wrap_s; if (texdata->attrib.m.mirror_u) wrap_s = GL_MIRRORED_REPEAT; else if (texdata->attrib.m.repeat_u) wrap_s = GL_REPEAT; + else + wrap_s = GL_CLAMP_TO_EDGE; - GLenum wrap_t = 0; + GLenum wrap_t; if (texdata->attrib.m.mirror_v) wrap_t = GL_MIRRORED_REPEAT; else if (texdata->attrib.m.repeat_v) wrap_t = GL_REPEAT; + else + wrap_t = GL_CLAMP_TO_EDGE; - if (wrap_s) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s); - if (wrap_t) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t); + texture_storage_set_texture_wrap(tex_id, wrap_s, wrap_t); } if (material->material.shader.index == SHADER_FT_SKY) { @@ -615,9 +612,8 @@ static void draw_object_material_set_default(render_context* rctx, draw_object* vec4 specular = material->material.color.specular; shaders_ft.state_material_set_specular(false, specular); - float_t luma; vec3 luma_coeff = { 0.30f, 0.59f, 0.11f }; - vec3_dot(*(vec3*)&specular, luma_coeff, luma); + float_t luma = vec3::dot(*(vec3*)&specular, luma_coeff); if (luma >= 0.0099999998f || draw->texture_color_coeff.w >= 0.1f) uniform_value[U_SPECULAR_IBL] = 1; else @@ -654,7 +650,7 @@ static void draw_object_material_set_default(render_context* rctx, draw_object* shininess = 10.0f; else { shininess = (material->material.color.shininess - 16.0f) * (float_t)(1.0 / 112.0); - shininess = max(shininess, 0.0f); + shininess = max_def(shininess, 0.0f); } shaders_ft.state_material_set_shininess(false, shininess, 0.0f, 0.0f, 1.0f); @@ -668,7 +664,7 @@ static void draw_object_material_set_default(render_context* rctx, draw_object* shaders_ft.local_vert_set(0, fresnel, 0.18f, line_light, 0.0f); shaders_ft.local_frag_set(9, fresnel, 0.18f, line_light, 0.0f); - shininess = max(material->material.color.shininess, 1.0f); + shininess = max_def(material->material.color.shininess, 1.0f); shaders_ft.local_vert_set(1, shininess, 0.0f, 0.0f, 0.0f); shaders_ft.local_frag_set(3, shininess, 0.0f, 0.0f, 0.0f); @@ -724,7 +720,7 @@ static void draw_object_material_set_parameter(render_context* rctx, obj_materia inv_bump_depth = (1.0f - bump_depth) * 256.0f + 1.0f; } - intensity = max(intensity, 1.0f); + intensity = max_def(intensity, 1.0f); shaders_ft.local_vert_set(2, inv_bump_depth, bump_depth, 0.0f, 0.0f); shaders_ft.local_frag_set(0, inv_bump_depth, bump_depth, 0.0f, 0.0f); @@ -735,7 +731,7 @@ static void draw_object_material_set_parameter(render_context* rctx, obj_materia vec4 specular; shaders_ft.env_vert_get(17, specular); - vec3_mult(*(vec3*)&specular, *(vec3*)&mat_data->material.color.specular, *(vec3*)&specular); + *(vec3*)&specular = *(vec3*)&specular * *(vec3*)&mat_data->material.color.specular; shaders_ft.env_vert_set(18, specular); } @@ -768,22 +764,23 @@ static void draw_object_material_set_reflect(render_context* rctx, draw_object* gl_state_active_bind_texture_2d(i, tex_id); - GLenum wrap_s = 0; + GLenum wrap_s; if (texdata->attrib.m.mirror_u) wrap_s = GL_MIRRORED_REPEAT; else if (texdata->attrib.m.repeat_u) wrap_s = GL_REPEAT; + else + wrap_s = GL_CLAMP_TO_EDGE; - GLenum wrap_t = 0; + GLenum wrap_t; if (texdata->attrib.m.mirror_v) wrap_t = GL_MIRRORED_REPEAT; else if (texdata->attrib.m.repeat_v) wrap_t = GL_REPEAT; + else + wrap_t = GL_CLAMP_TO_EDGE; - if (wrap_s) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s); - if (wrap_t) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t); + texture_storage_set_texture_wrap(tex_id, wrap_s, wrap_t); } vec4 ambient; @@ -940,18 +937,30 @@ static void draw_object_vertex_attrib_set_default(draw_object* draw) { if (vertex_format & OBJ_VERTEX_BONE_DATA) uniform_value[U_BONE_MAT] = 1; + else + uniform_value[U_BONE_MAT] = 0; if (draw->morph_array_buffer) { uniform_value[U_MORPH] = 1; if (vertex_format & OBJ_VERTEX_COLOR0) uniform_value[U_MORPH_COLOR] = 1; + else + uniform_value[U_MORPH_COLOR] = 0; shaders_ft.env_vert_set(13, draw->morph_value, 1.0f - draw->morph_value, 0.0f, 0.0f); } + else { + uniform_value[U_MORPH] = 0; + uniform_value[U_MORPH_COLOR] = 0; + + shaders_ft.env_vert_set(13, 0.0f, 1.0f, 0.0f, 0.0f); + } if (draw->instances_count) uniform_value[U_INSTANCE] = 1; + else + uniform_value[U_INSTANCE] = 0; } static void draw_object_vertex_attrib_set_reflect(draw_object* draw) { @@ -977,13 +986,23 @@ static void draw_object_vertex_attrib_set_reflect(draw_object* draw) { if (vertex_format & OBJ_VERTEX_BONE_DATA) uniform_value[U_BONE_MAT] = 1; + else + uniform_value[U_BONE_MAT] = 0; if (draw->morph_array_buffer) { uniform_value[U_MORPH] = 1; if (vertex_format & OBJ_VERTEX_COLOR0) uniform_value[U_MORPH_COLOR] = 1; + else + uniform_value[U_MORPH_COLOR] = 0; shaders_ft.env_vert_set(13, draw->morph_value, 1.0f - draw->morph_value, 0.0f, 0.0f); } + else { + uniform_value[U_MORPH] = 0; + uniform_value[U_MORPH_COLOR] = 0; + + shaders_ft.env_vert_set(13, 0.0f, 1.0f, 0.0f, 0.0f); + } } diff --git a/src/CRE/draw_pass.cpp b/src/CRE/draw_pass.cpp index c8f5f6ae..4cbba764 100644 --- a/src/CRE/draw_pass.cpp +++ b/src/CRE/draw_pass.cpp @@ -109,10 +109,16 @@ void draw_pass_main(render_context* rctx) { break; case DRAW_PASS_CLEAR: { rctx->post_process.rend_texture.bind(); - vec4 _clear_color; - vec4u8_to_vec4(clear_color, _clear_color); - vec4_mult_scalar(_clear_color, (float_t)(1.0 / 255.0), _clear_color); - glClearBufferfv(GL_COLOR, 0, (GLfloat*)&_clear_color); + if (set_clear_color) { + vec4 _clear_color; + vec4u8_to_vec4(clear_color, _clear_color); + _clear_color *= (float_t)(1.0 / 255.0); + glClearBufferfv(GL_COLOR, 0, (GLfloat*)&_clear_color); + } + else { + vec4 _clear_color = {}; + glClearBufferfv(GL_COLOR, 0, (GLfloat*)&_clear_color); + } //sub_140501470(rctx, &rctx->draw_pass); } break; case DRAW_PASS_PRE_SPRITE: @@ -523,11 +529,8 @@ static void draw_pass_sss_contour(render_context* rctx, post_process* pp) { camera* cam = rctx->camera; float_t v3 = 1.0f / tanf((float_t)(cam->fov_rad * 0.5)); - vec3 direction; - vec3_sub(cam->interest, cam->view_point, direction); - vec3_normalize(direction, direction); - float_t length; - vec3_length(direction, length); + vec3 direction = cam->interest - cam->view_point; + float_t length = vec3::length(direction); float_t v7 = direction.y; if (length != 0.0) v7 /= length; @@ -607,7 +610,7 @@ static void draw_pass_sss_filter(render_context* rctx, sss_data* a1) { mat4* mat = rob_chara_bone_data_get_mats_mat(v16, MOTION_BONE_N_HARA_CP); if (mat) { mat4_get_translation(mat, &chara_position[i]); - vec3_distance(view_point, chara_position[i], chara_distance[i]); + chara_distance[i] = vec3::distance(view_point, chara_position[i]); } } } @@ -620,13 +623,11 @@ static void draw_pass_sss_filter(render_context* rctx, sss_data* a1) { else closest_chara_position = chara_position[0]; - float_t length; - vec3_distance(interest, closest_chara_position, length); + float_t length = vec3::distance(interest, closest_chara_position); if (length > 1.25f) interest = chara_position[0]; - float_t v29; - vec3_distance(view_point, interest, v29); + float_t v29 = vec3::distance(view_point, interest); if (v29 < 0.25f) v29 = 0.25f; float_t v31 = tanf((float_t)(rctx->camera->fov_rad * 0.5)) * 5.0f; @@ -634,7 +635,7 @@ static void draw_pass_sss_filter(render_context* rctx, sss_data* a1) { v31 = 0.25f; float_t v32 = v31 * v29; float_t v33 = 0.6f; - float_t v34 = 1.0f / clamp(v32, 0.25f, 100.0f); + float_t v34 = 1.0f / clamp_def(v32, 0.25f, 100.0f); if (v34 < 0.145) { float_t v36 = v34 - 0.02f; if (v34 < 0.0f) @@ -718,11 +719,13 @@ static void draw_pass_reflect(render_context* rctx, draw_pass* a1) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); rctx->draw_state.shader_index = SHADER_FT_S_REFL; - bool clip_plane[4]; + light_set* set = &rctx->light_set[LIGHT_SET_MAIN]; + light_clip_plane clip_plane; set->lights[LIGHT_SPOT].get_clip_plane(clip_plane); uniform_value[U_REFLECT] = 2; - uniform_value[U_CLIP_PLANE] = clip_plane[1]; + uniform_value[U_CLIP_PLANE] = clip_plane.data[1]; + gl_state_enable_depth_test(); gl_state_set_depth_func(GL_LEQUAL); gl_state_set_depth_mask(GL_TRUE); @@ -737,7 +740,7 @@ static void draw_pass_reflect(render_context* rctx, draw_pass* a1) { if (a1->reflect_type == STAGE_DATA_REFLECT_REFLECT_MAP) { uniform_value[U_REFLECT] = a1->field_31E; - uniform_value[U_CLIP_PLANE] = clip_plane[0]; + uniform_value[U_CLIP_PLANE] = clip_plane.data[0]; draw_task_draw_objects_by_type(rctx, DRAW_OBJECT_REFLECT_CHARA_OPAQUE, 0, 0, 1, -1); } gl_state_disable_depth_test(); diff --git a/src/CRE/draw_task.cpp b/src/CRE/draw_task.cpp index 4b7f4b89..b51fe128 100644 --- a/src/CRE/draw_task.cpp +++ b/src/CRE/draw_task.cpp @@ -170,7 +170,7 @@ void draw_task_draw_objects_by_type(render_context* rctx, draw_object_type type, switch (task->type) { case DRAW_TASK_OBJECT: { int32_t a = (int32_t)(task->data.object.blend_color.w * 255.0f); - a = clamp(a, 0, 255); + a = clamp_def(a, 0, 255); if (a == alpha) { draw_object_draw(rctx, &task->data.object, &task->mat, draw_object_func, show_vector); @@ -180,7 +180,7 @@ void draw_task_draw_objects_by_type(render_context* rctx, draw_object_type type, for (int32_t j = 0; j < task->data.object_translucent.count; j++) { draw_object* object = task->data.object_translucent.objects[j]; int32_t a = (int32_t)(object->blend_color.w * 255.0f); - a = clamp(a, 0, 255); + a = clamp_def(a, 0, 255); if (a == alpha) draw_object_draw(rctx, object, &task->mat, draw_object_func, show_vector); @@ -228,15 +228,16 @@ void draw_task_draw_objects_by_type_translucent(render_context* rctx, bool opaqu && draw_task_get_count(rctx, translucent) < 1) return; + post_process* pp = &rctx->post_process; + int32_t alpha_array[256]; int32_t count = draw_task_translucent_sort_count_layers(rctx, alpha_array, opaque, transparent, translucent); for (int32_t i = 0; i < count; i++) { int32_t alpha = alpha_array[i]; - fbo::blit(rctx->post_process.rend_texture.fbos[0], - rctx->post_process.alpha_layer_texture.fbos[0], - 0, 0, rctx->post_process.render_width, rctx->post_process.render_height, - 0, 0, rctx->post_process.render_width, rctx->post_process.render_height, + fbo::blit(pp->rend_texture.fbos[0], pp->alpha_layer_texture.fbos[0], + 0, 0, pp->render_width, pp->render_height, + 0, 0, pp->render_width, pp->render_height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); if (opaque_enable && draw_task_get_count(rctx, opaque)) @@ -249,17 +250,16 @@ void draw_task_draw_objects_by_type_translucent(render_context* rctx, bool opaqu gl_state_disable_blend(); } - rctx->post_process.buf_texture.bind(); - render_texture::shader_set_glsl(&rctx->post_process.alpha_layer_shader); - gl_state_active_bind_texture_2d(0, rctx->post_process.alpha_layer_texture.color_texture->tex); - gl_state_active_bind_texture_2d(1, rctx->post_process.rend_texture.color_texture->tex); + pp->buf_texture.bind(); + render_texture::shader_set_glsl(&pp->alpha_layer_shader); + gl_state_active_bind_texture_2d(0, pp->alpha_layer_texture.color_texture->tex); + gl_state_active_bind_texture_2d(1, pp->rend_texture.color_texture->tex); glUniform1f(0, (float_t)(alpha * (1.0 / 255.0))); render_texture::draw_custom_glsl(); - fbo::blit(rctx->post_process.buf_texture.fbos[0], - rctx->post_process.rend_texture.fbos[0], - 0, 0, rctx->post_process.render_width, rctx->post_process.render_height, - 0, 0, rctx->post_process.render_width, rctx->post_process.render_height, + fbo::blit(pp->buf_texture.fbos[0], pp->rend_texture.fbos[0], + 0, 0, pp->render_width, pp->render_height, + 0, 0, pp->render_width, pp->render_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); } } @@ -430,7 +430,7 @@ bool draw_task_add_draw_object(render_context* rctx, obj* object, if (!has_blend_color) _blend_color = *blend_color; else - vec4_mult(_blend_color, *blend_color, _blend_color); + _blend_color *= *blend_color; } bool has_emission = false; @@ -711,7 +711,7 @@ void draw_task_add_draw_object_by_object_info_object_skin(render_context* rctx, if (texture_data && !texture_data->field_0) { vec4 value; object_data->get_texture_color_coeff(texture_color_coeff); - vec3_mult(texture_data->texture_color_coeff, *(vec3*)&texture_color_coeff, *(vec3*)&value); + *(vec3*)&value = texture_data->texture_color_coeff * *(vec3*)&texture_color_coeff; value.w = 0.0f; object_data->set_texture_color_coeff(value); @@ -721,7 +721,7 @@ void draw_task_add_draw_object_by_object_info_object_skin(render_context* rctx, object_data->set_texture_color_offset(value); object_data->get_texture_specular_coeff(texture_specular_coeff); - vec3_mult(texture_data->texture_specular_coeff, *(vec3*)&texture_specular_coeff, *(vec3*)&value); + *(vec3*)&value = texture_data->texture_specular_coeff * *(vec3*)&texture_specular_coeff; value.w = 0.0f; object_data->set_texture_specular_coeff(value); @@ -778,9 +778,9 @@ void draw_task_sort(render_context* rctx, draw_object_type type, int32_t compare for (uint32_t j = 0; j < sub_mesh->bone_indices_count; j++) { center = sub_mesh->bounding_sphere.center; mat4_mult_vec3_trans(&task->data.object.mats[j], ¢er, ¢er); - vec3_add(center_sum, center, center_sum); + center_sum += center; } - vec3_mult_scalar(center_sum, 1.0f / (float_t)sub_mesh->bone_indices_count, center); + center_sum *= 1.0f / (float_t)sub_mesh->bone_indices_count; } task->bounding_radius = task->data.object.mesh->bounding_sphere.radius; } @@ -807,33 +807,15 @@ void draw_task_sort(render_context* rctx, draw_object_type type, int32_t compare int32_t obj_axis_aligned_bounding_box_check_visibility( obj_axis_aligned_bounding_box* aabb, camera* cam, mat4* mat) { - vec3 size; vec3 points[8]; - vec3 neg; - neg = { 0.0f, 0.0f, 0.0f }; - vec3_xor(aabb->size, neg, size); - vec3_add(aabb->center, size, points[0]); - neg = { -0.0f, -0.0f, -0.0f }; - vec3_xor(aabb->size, neg, size); - vec3_add(aabb->center, size, points[1]); - neg = { -0.0f, 0.0f, 0.0f }; - vec3_xor(aabb->size, neg, size); - vec3_add(aabb->center, size, points[2]); - neg = { 0.0f, -0.0f, -0.0f }; - vec3_xor(aabb->size, neg, size); - vec3_add(aabb->center, size, points[3]); - neg = { 0.0f, -0.0f, 0.0f }; - vec3_xor(aabb->size, neg, size); - vec3_add(aabb->center, size, points[4]); - neg = { -0.0f, 0.0f, -0.0f }; - vec3_xor(aabb->size, neg, size); - vec3_add(aabb->center, size, points[5]); - neg = { 0.0f, 0.0f, -0.0f }; - vec3_xor(aabb->size, neg, size); - vec3_add(aabb->center, size, points[6]); - neg = { -0.0f, -0.0f, 0.0f }; - vec3_xor(aabb->size, neg, size); - vec3_add(aabb->center, size, points[7]); + points[0] = aabb->center + (aabb->size ^ vec3( 0.0f, 0.0f, 0.0f)); + points[1] = aabb->center + (aabb->size ^ vec3(-0.0f, -0.0f, -0.0f)); + points[2] = aabb->center + (aabb->size ^ vec3(-0.0f, 0.0f, 0.0f)); + points[3] = aabb->center + (aabb->size ^ vec3( 0.0f, -0.0f, -0.0f)); + points[4] = aabb->center + (aabb->size ^ vec3( 0.0f, -0.0f, 0.0f)); + points[5] = aabb->center + (aabb->size ^ vec3(-0.0f, 0.0f, -0.0f)); + points[6] = aabb->center + (aabb->size ^ vec3( 0.0f, 0.0f, -0.0f)); + points[7] = aabb->center + (aabb->size ^ vec3(-0.0f, -0.0f, 0.0f)); mat4 view_mat; mat4_mult(mat, &cam->view, &view_mat); @@ -856,9 +838,7 @@ int32_t obj_axis_aligned_bounding_box_check_visibility( for (int32_t i = 0; i < 6; i++) for (int32_t j = 0; j < 8; j++) { - float_t v34 = 0.0f; - vec3_dot(*(vec3*)&v2[i], points[j], v34); - v34 += v2[i].w; + float_t v34 = vec3::dot(*(vec3*)&v2[i], points[j]) + v2[i].w; if (v34 > 0.0f) break; @@ -883,23 +863,19 @@ int32_t object_bounding_sphere_check_visibility(obj_bounding_sphere* sphere, if (-cam->min_distance < min_depth || -cam->max_distance > max_depth) return 0; - float_t v5; - vec3_dot(cam->field_1E4, center, v5); + float_t v5 = vec3::dot(cam->field_1E4, center); if (v5 < -radius) return 0; - float_t v6; - vec3_dot(cam->field_1F0, center, v6); + float_t v6 = vec3::dot(cam->field_1F0, center); if (v6 < -radius) return 0; - float_t v7; - vec3_dot(cam->field_1FC, center, v7); + float_t v7 = vec3::dot(cam->field_1FC, center); if (v7 < -radius) return 0; - float_t v8; - vec3_dot(cam->field_208, center, v8); + float_t v8 = vec3::dot(cam->field_208, center); if (v8 < -radius) return 0; @@ -1018,7 +994,7 @@ inline static void draw_task_translucent_sort_has_objects(render_context* rctx, continue; int32_t alpha = (int32_t)(task->data.object.blend_color.w * 255.0f); - alpha = clamp(alpha, 0, 255); + alpha = clamp_def(alpha, 0, 255); arr[alpha] = true; } } diff --git a/src/CRE/fbo.cpp b/src/CRE/fbo.cpp index 8d270b71..9f664a4b 100644 --- a/src/CRE/fbo.cpp +++ b/src/CRE/fbo.cpp @@ -26,7 +26,7 @@ void fbo::init_data(int32_t width, int32_t height, textures = 0; } - count = min(count, 8); + count = min_def(count, 8); this->width = width; this->height = height; diff --git a/src/CRE/file_handler.cpp b/src/CRE/file_handler.cpp index bfc6a77b..b054a684 100644 --- a/src/CRE/file_handler.cpp +++ b/src/CRE/file_handler.cpp @@ -4,6 +4,7 @@ */ #include +#include "../KKdLib/io/file_stream.hpp" #include "../KKdLib/hash.hpp" #include "file_handler.hpp" #include "data.hpp" @@ -56,42 +57,50 @@ reading(), cache(), callback(), size(), data(), ds() { } file_handler::~file_handler() { - free(data); + if (data) { + free(data); + data = 0; + } } void file_handler::call_callback(int32_t index) { if (index >= 2) return; - std::unique_lock u_lock(mtx); - const void* data = this->data; - void(*callback_func)(void*, const void*, size_t) = this->callback[index].func; - void* callback_data = this->callback[index].data; - bool ready = this->callback[index].ready; - this->callback[index].ready = true; - u_lock.unlock(); + const void* data = 0; + size_t size = 0; + void(*callback_func)(void*, const void*, size_t) = 0; + void* callback_data = 0; + bool ready = false; + + { + std::unique_lock u_lock(mtx); + data = this->data; + size = this->size; + callback_func = this->callback[index].func; + callback_data = this->callback[index].data; + ready = this->callback[index].ready; + this->callback[index].ready = true; + } if (!ready && callback_func) - callback_func(callback_data, data, this->size); + callback_func(callback_data, data, size); } void file_handler::set_file(const char* file) { std::unique_lock u_lock(mtx); - this->file = file; - u_lock.unlock(); + this->file.assign(file); } void file_handler::set_farc_file(const char* farc_file, bool cache) { std::unique_lock u_lock(mtx); - this->farc_file = farc_file; + this->farc_file.assign(farc_file); this->cache = cache; - u_lock.unlock(); } void file_handler::set_dir(const char* dir) { std::unique_lock u_lock(mtx); - this->dir = dir; - u_lock.unlock(); + this->dir.assign(dir); } void file_handler::set_callback_data(int32_t index, PFNFILEHANDLERCALLBACK* func, void* data) { @@ -101,20 +110,21 @@ void file_handler::set_callback_data(int32_t index, PFNFILEHANDLERCALLBACK* func callback[index].data = data; callback[index].ready = false; } - u_lock.unlock(); } void file_handler::free_data_lock() { - std::unique_lock u_lock(mtx); - if (count > 0) { - count--; - bool free_fhndl = count == 0; - u_lock.unlock(); - if (free_fhndl) - delete this; + bool free_fhndl = false; + + { + std::unique_lock u_lock(mtx); + if (count <= 0) + return; + + free_fhndl = --count == 0; } - else - u_lock.unlock(); + + if (free_fhndl) + delete this; } farc_read_handler::farc_read_handler() : cache(), farc() { @@ -159,8 +169,8 @@ bool farc_read_handler::read_data(void* data, size_t size, std::string& file) { if (farc) { farc_file* ff = farc->read_file(file.c_str()); if (ff) { - memcpy(data, ff->data, min(size, ff->size)); - if (!cache) { + memcpy(data, ff->data, min_def(size, ff->size)); + if (!cache && ff->data) { free(ff->data); ff->data = 0; } @@ -191,27 +201,30 @@ void file_handler_storage_init() { void file_handler_storage_ctrl() { file_handler_storage_ctrl_list(); - std::unique_lock u_lock(file_handler_storage_data->mtx); - if (!file_handler_storage_data->deque.size()) { - for (file_handler*& i : file_handler_storage_data->list) - if (i->not_ready && !i->reading) { - std::unique_lock u_lock(i->mtx); - i->count++; - u_lock.unlock(); - file_handler_storage_data->deque.push_back(i); - } + { + std::unique_lock u_lock(file_handler_storage_data->mtx); + if (!file_handler_storage_data->deque.size()) { + for (file_handler*& i : file_handler_storage_data->list) + if (i->not_ready && !i->reading) { + { + std::unique_lock u_lock(i->mtx); + i->count++; + } + file_handler_storage_data->deque.push_back(i); + } - if (file_handler_storage_data->deque.size()) - file_handler_storage_data->cnd.notify_all(); + if (file_handler_storage_data->deque.size()) + file_handler_storage_data->cnd.notify_all(); + } } - u_lock.unlock(); } void file_handler_storage_free() { - std::unique_lock u_lock(file_handler_storage_data->mtx); - file_handler_storage_data->exit = true; - file_handler_storage_data->cnd.notify_one(); - u_lock.unlock(); + { + std::unique_lock u_lock(file_handler_storage_data->mtx); + file_handler_storage_data->exit = true; + file_handler_storage_data->cnd.notify_one(); + } file_handler_storage_data->thread->join(); delete file_handler_storage_data->thread; @@ -233,11 +246,13 @@ static bool file_handler_load_file(void* data, const char* dir, const char* file if (!fhndl->data) return false; - stream s; + file_stream s; s.open(file_path.c_str(), "rb"); - bool ret = s.io.stream && s.read(fhndl->data, fhndl->size); - if (!ret) + bool ret = s.check_not_null() && s.read(fhndl->data, fhndl->size); + if (!ret && fhndl->data) { free(fhndl->data); + fhndl->data = 0; + } return ret; } @@ -266,14 +281,14 @@ static bool file_handler_load_farc_file(void* data, const char* dir, const char* fhndl->size = 1; fhndl->data = malloc(fhndl->size); - if (fhndl->data && farc_read_hndl->read_data(fhndl->data, fhndl->size, fhndl->file)) { - u_lock.unlock(); + if (fhndl->data && farc_read_hndl->read_data(fhndl->data, fhndl->size, fhndl->file)) return true; - } } - free(fhndl->data); - u_lock.unlock(); + if (fhndl->data) { + free(fhndl->data); + fhndl->data = 0; + } return false; } @@ -313,14 +328,12 @@ static void file_handler_storage_thread_ctrl() { i->dir.c_str(), i->file.c_str(), file_handler_load_file); } i->reading = false; - u_lock.unlock(); } i->free_data_lock(); } file_handler_storage_data->deque.clear(); } file_handler_storage_data->exit = false; - u_lock.unlock(); } p_file_handler::p_file_handler() { @@ -355,10 +368,12 @@ void p_file_handler::free_data() { if (!ptr) return; - std::unique_lock u_lock(ptr->mtx); - for (int32_t i = 0; i < 2; i++) - ptr->callback[i] = {}; - u_lock.unlock(); + { + std::unique_lock u_lock(ptr->mtx); + for (int32_t i = 0; i < 2; i++) + ptr->callback[i] = {}; + } + ptr->free_data_lock(); ptr = 0; } @@ -410,18 +425,21 @@ bool p_file_handler::read_file(void* data, const char* dir, ptr->ds = data; - std::unique_lock u_lock(ptr->mtx); - ptr->count++; - u_lock.unlock(); + { + std::unique_lock u_lock(ptr->mtx); + ptr->count++; + } ptr->set_dir(dir); if (farc_file) ptr->set_farc_file(farc_file, cache); ptr->set_file(file); - std::unique_lock u_lock1(ptr->mtx); - ptr->count++; - u_lock1.unlock(); + { + std::unique_lock u_lock(ptr->mtx); + ptr->count++; + } + file_handler_storage_data->list.push_back(ptr); return true; } @@ -450,16 +468,19 @@ bool p_file_handler::read_file(void* data, const char* dir, uint32_t hash, const ptr->ds = data; - std::unique_lock u_lock(ptr->mtx); - ptr->count++; - u_lock.unlock(); + { + std::unique_lock u_lock(ptr->mtx); + ptr->count++; + } ptr->set_dir(dir); ptr->set_file(file.c_str()); - std::unique_lock u_lock1(ptr->mtx); - ptr->count++; - u_lock1.unlock(); + { + std::unique_lock u_lock(ptr->mtx); + ptr->count++; + } + file_handler_storage_data->list.push_back(ptr); return true; } @@ -485,7 +506,6 @@ void p_file_handler::read_now() { ptr->not_ready = false; } ptr->reading = false; - u_lock.unlock(); } file_handler_storage_ctrl_list(); diff --git a/src/CRE/item_table.cpp b/src/CRE/item_table.cpp index 6c22991b..8e7d17ea 100644 --- a/src/CRE/item_table.cpp +++ b/src/CRE/item_table.cpp @@ -3,6 +3,7 @@ GitHub/GitLab: korenkonder */ +#include "../KKdLib/io/memory_stream.hpp" #include "../KKdLib/io/path.hpp" #include "../KKdLib/str_utils.hpp" #include "data.hpp" @@ -72,6 +73,19 @@ item_table_item_data_obj::item_table_item_data_obj() : rpk() { } +item_table_item_data_ofs::item_table_item_data_ofs() : sub_id(), no() { + +} + +item_table_item_data_tex::item_table_item_data_tex() { + org = -1; + chg = -1; +} + +item_table_item_data_col::item_table_item_data_col() : flag() { + tex_id = -1; +} + item_table_item_data::item_table_item_data() { } @@ -111,7 +125,7 @@ static bool item_table_array_read(data_struct* data, const char* path) { char* path_farc = str_utils_add(path, ".farc"); if (!path_check_file_exists(path_farc)) { - free(path_farc); + free_def(path_farc); return false; } @@ -155,7 +169,7 @@ static bool item_table_array_read(data_struct* data, const char* path) { farc_file* ff = f.read_file(file); if (ff) { - stream s; + memory_stream s; s.open(ff->data, ff->size); itm_table itm; itm.read(ff->data, ff->size); @@ -163,7 +177,7 @@ static bool item_table_array_read(data_struct* data, const char* path) { item_table_load(data, &item_table_array[i], &itm); } } - free(path_farc); + free_def(path_farc); return true; } diff --git a/src/CRE/item_table.hpp b/src/CRE/item_table.hpp index 590a3906..e2938872 100644 --- a/src/CRE/item_table.hpp +++ b/src/CRE/item_table.hpp @@ -24,17 +24,23 @@ struct item_table_item_data_ofs { vec3 position; vec3 rotation; vec3 scale; + + item_table_item_data_ofs(); }; struct item_table_item_data_tex { uint32_t org; uint32_t chg; + + item_table_item_data_tex(); }; struct item_table_item_data_col { uint32_t tex_id; int32_t flag; color_tone col_tone; + + item_table_item_data_col(); }; struct item_table_item_data { diff --git a/src/CRE/light_param.cpp b/src/CRE/light_param.cpp index a309b0c2..3b860155 100644 --- a/src/CRE/light_param.cpp +++ b/src/CRE/light_param.cpp @@ -70,6 +70,14 @@ void light_param_data_storage_data_init() { light_param_data_storage_data = new light_param_data_storage; } +int32_t light_param_data_storage_data_get_pv_id() { + return light_param_data_storage_data->pv_id; +} + +int32_t light_param_data_storage_data_get_stage_index() { + return light_param_data_storage_data->stage_index; +} + void light_param_data_storage_data_free_file_handlers() { light_param_storage_free_file_handlers(light_param_data_storage_data); } @@ -226,7 +234,7 @@ static void light_param_data_get_stage_name_string(std::string* str, int32_t sta s[length] = '\0'; *str = std::string(s, length); - free(s); + free_def(s); } static void light_param_data_get_stage_name_string(std::string* str, @@ -267,7 +275,7 @@ static void light_param_data_get_stage_name_string(std::string* str, s[length] = '\0'; *str = std::string(s, length); - free(s); + free_def(s); } static int32_t light_param_data_load_file(light_param_data* a1, p_file_handler* a2) { @@ -318,27 +326,27 @@ static void light_param_data_load_file_pv_cut(std::map 6 && name[5] == '_') { + if (!strncmp(name, "light", min_def(name_len, 5)) && name_len > 6 && name[5] == '_') { type = 1; name += 6; name_len -= 6; } - else if (!strncmp(name, "fog", min(name_len, 3)) && name_len > 4 && name[3] == '_') { + else if (!strncmp(name, "fog", min_def(name_len, 3)) && name_len > 4 && name[3] == '_') { type = 2; name += 4; name_len -= 4; } - else if (!strncmp(name, "glow", min(name_len, 4)) && name_len > 5 && name[4] == '_') { + else if (!strncmp(name, "glow", min_def(name_len, 4)) && name_len > 5 && name[4] == '_') { type = 3; name += 5; name_len -= 5; } - else if (!strncmp(name, "wind", min(name_len, 4)) && name_len > 5 && name[4] == '_') { + else if (!strncmp(name, "wind", min_def(name_len, 4)) && name_len > 5 && name[4] == '_') { type = 4; name += 5; name_len -= 5; } - else if (!strncmp(name, "face", min(name_len, 4)) && name_len > 5 && name[4] == '_') { + else if (!strncmp(name, "face", min_def(name_len, 4)) && name_len > 5 && name[4] == '_') { type = 5; name += 5; name_len -= 5; @@ -576,7 +584,7 @@ static void light_param_storage_load_stages(light_param_data_storage* a1, continue; size_t name_len = name.size(); - if (!strncmp(name.c_str(), "pv0", min(name_len, 3))) + if (!strncmp(name.c_str(), "pv0", min_def(name_len, 3))) name[2] = '8'; std::map::iterator elem = a1->stage.find(i); diff --git a/src/CRE/light_param.hpp b/src/CRE/light_param.hpp index cba27fb4..76871fe8 100644 --- a/src/CRE/light_param.hpp +++ b/src/CRE/light_param.hpp @@ -69,6 +69,8 @@ struct light_param_data_storage { extern void light_param_data_storage_data_init(); extern void light_param_data_storage_data_free_file_handlers(); +extern int32_t light_param_data_storage_data_get_pv_id(); +extern int32_t light_param_data_storage_data_get_stage_index(); extern int32_t light_param_data_storage_data_load_file(); extern void light_param_data_storage_data_load_stage(int32_t stage_index); extern void light_param_data_storage_data_load_stage(uint32_t stage_hash, stage_database* stage_data); diff --git a/src/CRE/light_param/fog.cpp b/src/CRE/light_param/fog.cpp index 64ce4e71..fc9e04f3 100644 --- a/src/CRE/light_param/fog.cpp +++ b/src/CRE/light_param/fog.cpp @@ -91,8 +91,7 @@ void fog::data_set(fog_id id) { shaders_ft.env_vert_set(29, color); shaders_ft.env_frag_set(4, color); - vec4_mult_scalar(color, (float_t)(1.0 / 8.0), color); - shaders_ft.state_fog_set_color(color); + shaders_ft.state_fog_set_color(color * (float_t)(1.0 / 8.0)); shaders_ft.state_fog_set_params(params); } break; case FOG_HEIGHT: { diff --git a/src/CRE/light_param/light.cpp b/src/CRE/light_param/light.cpp index c8af70a5..5aef63e9 100644 --- a/src/CRE/light_param/light.cpp +++ b/src/CRE/light_param/light.cpp @@ -13,8 +13,8 @@ extern vec4 npr_spec_color; static void light_get_direction_from_position(vec4* pos_dir, light_data* light, bool force); light_data::light_data() : type(), ambient(), diffuse(), specular(), position(), -spot_direction(), spot_exponent(), spot_cutoff(), constant(), linear(), quadratic(), -ibl_specular(), ibl_back(), ibl_direction(), tone_curve(),clip_plane() { +spot_direction(), spot_exponent(), spot_cutoff(), attenuation(), +ibl_specular(), ibl_back(), ibl_direction(), tone_curve(), clip_plane() { set_type(LIGHT_OFF); set_ambient({ 0.0f, 0.0, 0.0f, 1.0f }); set_diffuse({ 1.0f, 1.0, 1.0f, 0.0f }); @@ -207,45 +207,39 @@ void light_data::set_spot_cutoff(float_t value) { } float_t light_data::get_constant() { - return constant; + return attenuation.constant; } void light_data::set_constant(float_t value) { - constant = value; + attenuation.constant = value; } float_t light_data::get_linear() { - return linear; + return attenuation.linear; } void light_data::set_linear(float_t value) { - linear = value; + attenuation.linear = value; } float_t light_data::get_quadratic() { - return quadratic; + return attenuation.quadratic; } void light_data::set_quadratic(float_t value) { - quadratic = value; + attenuation.quadratic = value; } -void light_data::get_attenuation(vec3& value) { - value.x = constant; - value.y = linear; - value.z = quadratic; +void light_data::get_attenuation(light_attenuation& value) { + value = attenuation; } -void light_data::set_attenuation(const vec3& value) { - constant = value.x; - linear = value.y; - quadratic = value.z; +void light_data::set_attenuation(const light_attenuation& value) { + attenuation = value; } -void light_data::set_attenuation(const vec3&& value) { - constant = value.x; - linear = value.y; - quadratic = value.z; +void light_data::set_attenuation(const light_attenuation&& value) { + attenuation = value; } void light_data::get_ibl_specular(vec4& value) { @@ -284,30 +278,28 @@ void light_data::set_ibl_direction(const vec4&& value) { ibl_direction = value; } -void light_data::get_tone_curve(vec3& value) { +void light_data::get_tone_curve(light_tone_curve& value) { value = tone_curve; } -void light_data::set_tone_curve(const vec3& value) { +void light_data::set_tone_curve(const light_tone_curve& value) { tone_curve = value; } -void light_data::set_tone_curve(const vec3&& value) { +void light_data::set_tone_curve(const light_tone_curve&& value) { tone_curve = value; } -void light_data::get_clip_plane(bool value[4]) { - value[0] = clip_plane[0]; - value[1] = clip_plane[1]; - value[2] = clip_plane[2]; - value[3] = clip_plane[3]; +void light_data::get_clip_plane(light_clip_plane& value) { + value = clip_plane; } -void light_data::set_clip_plane(const bool value[4]) { - clip_plane[0] = value[0]; - clip_plane[1] = value[1]; - clip_plane[2] = value[2]; - clip_plane[3] = value[3]; +void light_data::set_clip_plane(const light_clip_plane& value) { + clip_plane = value; +} + +void light_data::set_clip_plane(const light_clip_plane&& value) { + clip_plane = value; } void light_set::get_ambient_intensity(vec4& value) { @@ -364,8 +356,9 @@ void light_set::data_set(face& face, light_set_id id) { light_get_direction_from_position(&light_position, 0, true); shaders_ft.state_light_set_position(i, light_position); + light_attenuation attenuation = light->attenuation; shaders_ft.state_light_set_attenuation(i, - light->constant, light->linear, light->quadratic, light->spot_exponent); + attenuation.constant, attenuation.linear, attenuation.quadratic, light->spot_exponent); vec3 spot_direction = light->spot_direction; shaders_ft.state_light_set_spot_direction(i, @@ -393,21 +386,19 @@ void light_set::data_set(face& face, light_set_id id) { shaders_ft.env_vert_set(5, position); shaders_ft.env_frag_set(5, position); - vec4_mult(diffuse, ibl_specular, temp); + temp = diffuse * ibl_specular; shaders_ft.env_vert_set(6, temp); shaders_ft.env_frag_set(6, temp); - vec4_mult(specular, ibl_specular, temp); - vec4_mult_scalar(temp, spec_coef, temp); + temp = specular * ibl_specular * spec_coef; shaders_ft.env_vert_set(7, temp); shaders_ft.env_frag_set(7, temp); - vec4_mult_scalar(ibl_specular, luce_coef, temp); + temp = ibl_specular * luce_coef; shaders_ft.env_vert_set(8, temp); shaders_ft.env_frag_set(8, temp); - vec4_mult(specular, ibl_back, temp); - vec4_mult_scalar(temp, spec_coef, temp); + temp = specular * ibl_back * spec_coef; shaders_ft.env_vert_set(9, temp); shaders_ft.env_frag_set(9, temp); @@ -420,12 +411,11 @@ void light_set::data_set(face& face, light_set_id id) { shaders_ft.env_vert_set(10, position); shaders_ft.env_frag_set(14, position); - vec4_mult(diffuse, ibl_specular, temp); + temp = diffuse * ibl_specular; shaders_ft.env_vert_set(11, temp); shaders_ft.env_frag_set(16, temp); - vec4_mult(specular, ibl_specular, temp); - vec4_mult_scalar(temp, spec_coef, temp); + temp = specular * ibl_specular * spec_coef; shaders_ft.env_vert_set(12, temp); shaders_ft.env_frag_set(17, temp); @@ -439,7 +429,7 @@ void light_set::data_set(face& face, light_set_id id) { float_t offset = face.get_offset(); float_t v28 = (float_t)(1.0 - exp(offset * -0.44999999)) * 2.0f; - offset = max(offset, 0.0f); + offset = max_def(offset, 0.0f); shaders_ft.env_vert_set(0x11, v28 * 0.1f, offset * 0.06f, 1.0, 1.0); if (lights[LIGHT_CHARA_COLOR].get_type() == LIGHT_PARALLEL) { @@ -466,19 +456,20 @@ void light_set::data_set(face& face, light_set_id id) { lights[LIGHT_TONE_CURVE].get_diffuse(diffuse); lights[LIGHT_TONE_CURVE].get_specular(specular); - vec3 tone_curve; + light_tone_curve tone_curve; lights[LIGHT_TONE_CURVE].get_tone_curve(tone_curve); - tone_curve.y = min(tone_curve.y, 1.0f) - tone_curve.x; - if (tone_curve.y > 0.0f) - tone_curve.y = 1.0f / tone_curve.y; + tone_curve.end_point = min_def(tone_curve.end_point, 1.0f) - tone_curve.start_point; + if (tone_curve.end_point > 0.0f) + tone_curve.end_point = 1.0f / tone_curve.end_point; else - tone_curve.y = 0.0f; + tone_curve.end_point = 0.0f; shaders_ft.env_frag_set(36, position); shaders_ft.env_frag_set(37, ambient); shaders_ft.env_frag_set(38, diffuse); shaders_ft.env_frag_set(39, specular); - shaders_ft.env_frag_set(40, tone_curve.x, tone_curve.y, tone_curve.z, 0.0f); + shaders_ft.env_frag_set(40, tone_curve.start_point, + tone_curve.end_point, tone_curve.coefficient, 0.0f); } else { uniform_value[U_TONE_CURVE] = 0; @@ -493,10 +484,9 @@ void light_set::data_set(face& face, light_set_id id) { if (fabs(position.x) <= 0.000001f && fabs(position.z) <= 0.000001f && fabs(position.z) <= 0.000001f) position = { 0.0f, 1.0f, 0.0f, 1.0f }; else { - float_t length; - vec3_length(*(vec3*)&position, length); + float_t length = vec3::length(*(vec3*)&position); if (length != 0.0f) - vec3_mult_scalar(*(vec3*)&position, 1.0f / length, *(vec3*)&position); + *(vec3*)&position = *(vec3*)&position * (1.0f / length); } shaders_ft.env_vert_set(15, position.x, position.y, position.z, 1.0f); @@ -505,11 +495,10 @@ void light_set::data_set(face& face, light_set_id id) { if (lights[LIGHT_REFLECT].get_type() == LIGHT_SPOT) { vec4 spot_direction; lights[LIGHT_REFLECT].get_spot_direction(*(vec3*)&spot_direction); - vec3_negate(*(vec3*)&spot_direction, *(vec3*)&spot_direction); + *(vec3*)&spot_direction = -*(vec3*)&spot_direction; light_get_direction_from_position(&spot_direction, &lights[LIGHT_REFLECT], true); lights[LIGHT_REFLECT].get_position(position); - vec3_dot(*(vec3*)&position, *(vec3*)&spot_direction, spot_direction.w); - spot_direction.w = -spot_direction.w; + spot_direction.w = -vec3::dot(*(vec3*)&position, *(vec3*)&spot_direction); shaders_ft.env_vert_set(28, spot_direction); shaders_ft.env_frag_set(22, spot_direction); @@ -529,27 +518,22 @@ void light_set::data_set(face& face, light_set_id id) { lights[LIGHT_CHARA].get_ibl_direction(ibl_direction); lights[LIGHT_CHARA].get_position(position); - float_t length; - vec3_length(*(vec3*)&ibl_direction, length); + float_t length = vec3::length(*(vec3*)&ibl_direction); if (length >= 0.000001f) { - vec3_mult_scalar(*(vec3*)&ibl_direction, 1.0f / length, *(vec3*)&ibl_direction); + *(vec3*)&ibl_direction = *(vec3*)&ibl_direction * (1.0f / length); - vec3_length(*(vec3*)&position, length); + length = vec3::length(*(vec3*)&position); if (length >= 0.000001f) { - vec3_mult_scalar(*(vec3*)&position, 1.0f / length, *(vec3*)&position); + *(vec3*)&position = *(vec3*)&position * (1.0f / length); - vec3 axis; - vec3_cross(*(vec3*)&ibl_direction, *(vec3*)&position, axis) - - vec3_length(axis, length); - - float_t v52; - vec3_dot(*(vec3*)&position, *(vec3*)&ibl_direction, v52); + vec3 axis = vec3::cross(*(vec3*)&ibl_direction, *(vec3*)&position); + length = vec3::length(axis); + float_t v52 = vec3::dot(*(vec3*)&position, *(vec3*)&ibl_direction); float_t angle = fabsf(atan2f(length, v52)); if (angle >= 0.01f && angle <= 3.131592653589793f) { if (length != 0.0f) - vec3_mult_scalar(axis, 1.0f / length, axis); + axis *= 1.0f / length; mat4_from_axis_angle(&axis, -angle, &v63); mat4_from_axis_angle(&axis, -angle, &v64); @@ -566,12 +550,11 @@ void light_set::data_set(face& face, light_set_id id) { static void light_get_direction_from_position(vec4* pos_dir, light_data* light, bool force) { if (force || light->get_type() == LIGHT_PARALLEL) { - float_t length; - vec3_length(*(vec3*)pos_dir, length); + float_t length = vec3::length(*(vec3*)pos_dir); if (length <= 0.000001) *(vec3*)pos_dir = { 0.0f, 1.0f, 0.0f }; else - vec3_mult_scalar(*(vec3*)pos_dir, 1.0f / length, *(vec3*)pos_dir); + *(vec3*)pos_dir = *(vec3*)pos_dir * (1.0f / length); pos_dir->w = 0.0f; } } diff --git a/src/CRE/light_param/light.hpp b/src/CRE/light_param/light.hpp index e103da5c..1505cdcd 100644 --- a/src/CRE/light_param/light.hpp +++ b/src/CRE/light_param/light.hpp @@ -20,14 +20,12 @@ struct light_data { vec3 spot_direction; float_t spot_exponent; float_t spot_cutoff; - float_t constant; - float_t linear; - float_t quadratic; + light_attenuation attenuation; vec4 ibl_specular; vec4 ibl_back; vec4 ibl_direction; - vec3 tone_curve; - bool clip_plane[4]; + light_tone_curve tone_curve; + light_clip_plane clip_plane; light_data(); @@ -67,9 +65,9 @@ struct light_data { void set_linear(float_t value); float_t get_quadratic(); void set_quadratic(float_t value); - void get_attenuation(vec3& value); - void set_attenuation(const vec3& value); - void set_attenuation(const vec3&& value); + void get_attenuation(light_attenuation& value); + void set_attenuation(const light_attenuation& value); + void set_attenuation(const light_attenuation&& value); void get_ibl_specular(vec4& value); void set_ibl_specular(const vec4& value); void set_ibl_specular(const vec4&& value); @@ -79,11 +77,12 @@ struct light_data { void get_ibl_direction(vec4& value); void set_ibl_direction(const vec4& value); void set_ibl_direction(const vec4&& value); - void get_tone_curve(vec3& value); - void set_tone_curve(const vec3& value); - void set_tone_curve(const vec3&& value); - void get_clip_plane(bool value[4]); - void set_clip_plane(const bool value[4]); + void get_tone_curve(light_tone_curve& value); + void set_tone_curve(const light_tone_curve& value); + void set_tone_curve(const light_tone_curve&& value); + void get_clip_plane(light_clip_plane& value); + void set_clip_plane(const light_clip_plane& value); + void set_clip_plane(const light_clip_plane&& value); }; struct light_set { diff --git a/src/CRE/light_param/wind.cpp b/src/CRE/light_param/wind.cpp index 60c323dd..b696f03c 100644 --- a/src/CRE/light_param/wind.cpp +++ b/src/CRE/light_param/wind.cpp @@ -95,7 +95,7 @@ static void wind_ctrl(wind* w) { vec3 wind_direction = vec3_null; wind_direction.x = value; mat4_mult_vec3(&mat, &wind_direction, &wind_direction); - vec3_mult_scalar(wind_direction, w->strength, w->wind_direction); + w->wind_direction = wind_direction * w->strength; if (w->strength >= 1.0f) w->strength = 1.0f; else diff --git a/src/CRE/lock.cpp b/src/CRE/lock.cpp index f1f5397d..1422d62f 100644 --- a/src/CRE/lock.cpp +++ b/src/CRE/lock.cpp @@ -4,17 +4,3 @@ */ #include "lock.hpp" - -inline void lock_init(lock* l) { - l->init = InitializeCriticalSectionAndSpinCount(&l->cs, 0); -} - -inline bool lock_check_init(lock* l) { - return l->init; -} - -inline void lock_free(lock* l) { - if (l->init) - DeleteCriticalSection(&l->cs); - l->init = FALSE; -} diff --git a/src/CRE/lock.hpp b/src/CRE/lock.hpp index e36dd723..dd4166a4 100644 --- a/src/CRE/lock.hpp +++ b/src/CRE/lock.hpp @@ -10,12 +10,49 @@ struct lock { CRITICAL_SECTION cs; bool init; + + inline lock() : cs() { + init = InitializeCriticalSectionAndSpinCount(&cs, 0); + } + + inline ~lock() { + if (init) + DeleteCriticalSection(&cs); + cs = {}; + init = false; + } + + inline bool check_init() { + if (!this) + return false; + return init; + } }; -struct lock_data { - lock* lock; - void* lock_data; - void(*lock_free)(void* data); +struct lock_uint32_t { +private: + volatile uint32_t value; + +public: + inline lock_uint32_t() { + _InterlockedExchange(&value, 0); + } + + inline uint32_t get() { + _m_prefetchw(&value); + int32_t v3 = value; + while (true) { + int32_t v4 = v3; + v3 = _InterlockedCompareExchange(&value, v3, v3); + if (v4 == v3) + break; + } + return v3; + } + + inline void set(uint32_t value) { + _InterlockedExchange(&this->value, value); + } }; #define lock_lock(val) \ @@ -28,7 +65,3 @@ if ((val) && (val)->init && TryEnterCriticalSection(&(val)->cs)) { #define lock_unlock(val) \ LeaveCriticalSection(&(val)->cs); \ } - -extern void lock_init(lock* l); -extern bool lock_check_init(lock* l); -extern void lock_free(lock* l); diff --git a/src/CRE/object.cpp b/src/CRE/object.cpp index ee8f298c..9c308a00 100644 --- a/src/CRE/object.cpp +++ b/src/CRE/object.cpp @@ -10,6 +10,7 @@ #include "data.hpp" #include "gl_state.hpp" #include "shader_ft.hpp" +#include "../KKdLib/io/file_stream.hpp" #include "../KKdLib/io/json.hpp" #include "../KKdLib/io/path.hpp" #include "../KKdLib/dds.hpp" @@ -97,7 +98,7 @@ bool obj_mesh_index_buffer::load(obj_mesh& mesh) { } bool ret = load_data((size_t)indices_count * sizeof(uint16_t), indices); - free(indices); + free_def(indices); return ret; } @@ -146,54 +147,6 @@ bool obj_mesh_vertex_buffer::load(obj_mesh& mesh) { if (!mesh.num_vertex || !mesh.vertex) return false; - { - const vec4 attib_default = { 0.0f, 0.0f, 0.0f, 1.0f }; - - obj_vertex_format vertex_format = mesh.vertex_format; - obj_vertex_data* vertex_file = mesh.vertex; - int32_t num_vertex = mesh.num_vertex; - obj_vertex_format _vertex_format = vertex_format; - enum_and(_vertex_format, ~(OBJ_VERTEX_TEXCOORD0 | OBJ_VERTEX_TEXCOORD1 | OBJ_VERTEX_TEXCOORD2 - | OBJ_VERTEX_TEXCOORD3 | OBJ_VERTEX_COLOR0 | OBJ_VERTEX_COLOR1 | OBJ_VERTEX_BONE_DATA | OBJ_VERTEX_UNKNOWN)); - for (int32_t i = 0; i < num_vertex && _vertex_format != vertex_format; i++) { - if (~_vertex_format & OBJ_VERTEX_TEXCOORD0 && vertex_format & OBJ_VERTEX_TEXCOORD0 - && memcmp(&vertex_file[i].texcoord0, &vec2_null, sizeof(vec2))) - enum_or(_vertex_format, OBJ_VERTEX_TEXCOORD0); - - if (~_vertex_format & OBJ_VERTEX_TEXCOORD1 && vertex_format & OBJ_VERTEX_TEXCOORD1 - && memcmp(&vertex_file[i].texcoord1, &vec2_null, sizeof(vec2))) - enum_or(_vertex_format, OBJ_VERTEX_TEXCOORD1); - - if (~_vertex_format & OBJ_VERTEX_TEXCOORD2 && vertex_format & OBJ_VERTEX_TEXCOORD2 - && memcmp(&vertex_file[i].texcoord2, &vec2_null, sizeof(vec2))) - enum_or(_vertex_format, OBJ_VERTEX_TEXCOORD2); - - if (~_vertex_format & OBJ_VERTEX_TEXCOORD3 && vertex_format & OBJ_VERTEX_TEXCOORD3 - && memcmp(&vertex_file[i].texcoord3, &vec2_null, sizeof(vec2))) - enum_or(_vertex_format, OBJ_VERTEX_TEXCOORD3); - - if (~_vertex_format & OBJ_VERTEX_COLOR0 && vertex_format & OBJ_VERTEX_COLOR0 - && memcmp(&vertex_file[i].color0, &vec4_identity, sizeof(vec4))) - enum_or(_vertex_format, OBJ_VERTEX_COLOR0); - - if (~_vertex_format & OBJ_VERTEX_COLOR1 && vertex_format & OBJ_VERTEX_COLOR1 - && memcmp(&vertex_file[i].color1, &vec4_identity, sizeof(vec4))) - enum_or(_vertex_format, OBJ_VERTEX_COLOR1); - - if (~_vertex_format & OBJ_VERTEX_BONE_DATA && vertex_format & OBJ_VERTEX_BONE_DATA - && memcmp(&vertex_file[i].bone_index, &vec4i_null, sizeof(vec4i)) - && memcmp(&vertex_file[i].bone_weight, &vec4_null, sizeof(vec4))) - enum_or(_vertex_format, OBJ_VERTEX_BONE_DATA); - - if (~_vertex_format & OBJ_VERTEX_UNKNOWN && vertex_format & OBJ_VERTEX_UNKNOWN - && memcmp(&vertex_file[i].unknown, &attib_default, sizeof(vec4))) - enum_or(_vertex_format, OBJ_VERTEX_UNKNOWN); - } - - if (mesh.vertex_format != _vertex_format) - mesh.vertex_format = _vertex_format; - } - size_t size_vertex; if (!mesh.attrib.m.compressed) size_vertex = obj_vertex_format_get_vertex_size(mesh.vertex_format); @@ -279,16 +232,14 @@ bool obj_mesh_vertex_buffer::load(obj_mesh& mesh) { } if (vertex_format & OBJ_VERTEX_NORMAL) { - vec3 normal; - vec3_mult_scalar(vertex_file[i].normal, 32727.0f, normal); + vec3 normal = vertex_file[i].normal * 32727.0f; vec3_to_vec3i16(normal, *(vec3i16*)d); *(int16_t*)(d + 6) = 0; d += 8; } if (vertex_format & OBJ_VERTEX_TANGENT) { - vec4 tangent = vertex_file[i].tangent; - vec4_mult_scalar(tangent, 32727.0f, tangent); + vec4 tangent = vertex_file[i].tangent * 32727.0f; vec4_to_vec4i16(tangent, *(vec4i16*)d); d += 8; } @@ -320,8 +271,7 @@ bool obj_mesh_vertex_buffer::load(obj_mesh& mesh) { } if (vertex_format & OBJ_VERTEX_BONE_DATA) { - vec4 bone_weight = vertex_file[i].bone_weight; - vec4_mult_scalar(bone_weight, 65535.0f, bone_weight); + vec4 bone_weight = vertex_file[i].bone_weight * 65535.0f; vec4_to_vec4u16(bone_weight, *(vec4u16*)d); d += 8; @@ -335,7 +285,7 @@ bool obj_mesh_vertex_buffer::load(obj_mesh& mesh) { mesh.size_vertex = (int32_t)size_vertex; bool ret = load_data(size_vertex * mesh.num_vertex, vertex, mesh.attrib.m.double_buffer ? 2 : 1); - free(vertex); + free_def(vertex); return ret; } @@ -426,7 +376,7 @@ index_buffer_num(), index_buffer_data(), load_count(), modern() { obj_set_handler::~obj_set_handler() { for (uint32_t i = 0; i < tex_num; i++) texture_free(tex_data[i]); - free(tex_data); + free_def(tex_data); obj_set_handler_index_buffer_free(this); obj_set_handler_vertex_buffer_free(this); @@ -534,7 +484,7 @@ void object_material_msgpack_read(const char* path, const char* set_name, msgpack msg; - stream s; + file_stream s; s.open(buf, "rb"); io_json_read(s, &msg); s.close(); @@ -542,7 +492,7 @@ void object_material_msgpack_read(const char* path, const char* set_name, if (msg.type != MSGPACK_ARRAY) return; - msgpack_array* ptr = MSGPACK_SELECT(msgpack_array, msg); + msgpack_array* ptr = msg.data.arr; for (msgpack& i : *ptr) { msgpack& object = i; @@ -555,9 +505,9 @@ void object_material_msgpack_read(const char* path, const char* set_name, if (name_hash != hash_string_murmurhash(obj.name)) continue; - msgpack* materials = object.read("material"); + msgpack* materials = object.read_array("material"); if (materials) { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, materials); + msgpack_array* ptr = materials->data.arr; for (msgpack& j : *ptr) { msgpack& material = j; @@ -594,7 +544,7 @@ void object_material_msgpack_read(const char* path, const char* set_name, msgpack* _shader_name = material.read("shader_name"); if (_shader_name) { std::string shader_name = _shader_name->read_string(); - size_t name_length = min(sizeof(mat.shader.name) - 1, shader_name.size()); + size_t name_length = min_def(sizeof(mat.shader.name) - 1, shader_name.size()); memcpy_s(mat.shader.name, sizeof(mat.shader.name) - 1, shader_name.c_str(), name_length); mat.shader.name[name_length] = 0; } @@ -669,7 +619,7 @@ void object_material_msgpack_read(const char* path, const char* set_name, msgpack* _ex_shader = material.read("ex_shader"); if (_ex_shader) { std::string shader_name = _ex_shader->read_string(); - size_t name_length = min(sizeof(l.ex_shader) - 1, shader_name.size()); + size_t name_length = min_def(sizeof(l.ex_shader) - 1, shader_name.size()); memcpy_s(l.ex_shader, sizeof(l.ex_shader) - 1, shader_name.c_str(), name_length); l.ex_shader[name_length] = 0; } @@ -678,13 +628,13 @@ void object_material_msgpack_read(const char* path, const char* set_name, if (weight) l.weight = weight->read_float_t(); - msgpack* tex_coord_mat = tex->read("tex_coord_mat"); + msgpack* tex_coord_mat = tex->read_array("tex_coord_mat"); if (tex_coord_mat) { - msgpack_array* tex_coord_mat_ptr = MSGPACK_SELECT_PTR(msgpack_array, tex_coord_mat); + msgpack_array* tex_coord_mat_ptr = tex_coord_mat->data.arr; { msgpack& row0 = tex_coord_mat_ptr->data()[0]; - msgpack_array* row0_ptr = MSGPACK_SELECT(msgpack_array, row0); + msgpack_array* row0_ptr = row0.data.arr; l.tex_coord_mat.row0.x = row0_ptr->data()[0].read_float_t(); l.tex_coord_mat.row0.y = row0_ptr->data()[1].read_float_t(); l.tex_coord_mat.row0.z = row0_ptr->data()[2].read_float_t(); @@ -693,7 +643,7 @@ void object_material_msgpack_read(const char* path, const char* set_name, { msgpack& row1 = tex_coord_mat_ptr->data()[1]; - msgpack_array* row1_ptr = MSGPACK_SELECT(msgpack_array, row1); + msgpack_array* row1_ptr = row1.data.arr; l.tex_coord_mat.row1.x = row1_ptr->data()[0].read_float_t(); l.tex_coord_mat.row1.y = row1_ptr->data()[1].read_float_t(); l.tex_coord_mat.row1.z = row1_ptr->data()[2].read_float_t(); @@ -702,7 +652,7 @@ void object_material_msgpack_read(const char* path, const char* set_name, { msgpack& row2 = tex_coord_mat_ptr->data()[2]; - msgpack_array* row2_ptr = MSGPACK_SELECT(msgpack_array, row2); + msgpack_array* row2_ptr = row2.data.arr; l.tex_coord_mat.row2.x = row2_ptr->data()[0].read_float_t(); l.tex_coord_mat.row2.y = row2_ptr->data()[1].read_float_t(); l.tex_coord_mat.row2.z = row2_ptr->data()[2].read_float_t(); @@ -711,7 +661,7 @@ void object_material_msgpack_read(const char* path, const char* set_name, { msgpack& row3 = tex_coord_mat_ptr->data()[3]; - msgpack_array* row3_ptr = MSGPACK_SELECT(msgpack_array, row3); + msgpack_array* row3_ptr = row3.data.arr; l.tex_coord_mat.row3.x = row3_ptr->data()[0].read_float_t(); l.tex_coord_mat.row3.y = row3_ptr->data()[1].read_float_t(); l.tex_coord_mat.row3.z = row3_ptr->data()[2].read_float_t(); @@ -719,9 +669,9 @@ void object_material_msgpack_read(const char* path, const char* set_name, } } - msgpack* reserved = tex->read("reserved"); + msgpack* reserved = tex->read_array("reserved"); if (reserved) { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, reserved); + msgpack_array* ptr = reserved->data.arr; for (int32_t m = 0; m < 8; m++) l.reserved[m] = ptr->data()[m].read_uint32_t(); } @@ -811,9 +761,9 @@ void object_material_msgpack_read(const char* path, const char* set_name, if (bump_depth) mat.radius = bump_depth->read_float_t(); - msgpack* reserved = material.read("reserved"); + msgpack* reserved = material.read_array("reserved"); if (reserved) { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, reserved); + msgpack_array* ptr = reserved->data.arr; for (int32_t m = 0; m < 15; m++) mat.reserved[m] = ptr->data()[m].read_uint32_t(); } @@ -822,9 +772,9 @@ void object_material_msgpack_read(const char* path, const char* set_name, } } - msgpack* meshes = object.read("mesh"); + msgpack* meshes = object.read_array("mesh"); if (meshes) { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, meshes); + msgpack_array* ptr = meshes->data.arr; for (msgpack& j : *ptr) { msgpack& _mesh = j; @@ -837,8 +787,11 @@ void object_material_msgpack_read(const char* path, const char* set_name, if (name_hash != hash_string_murmurhash(mesh.name)) continue; - msgpack* sub_meshes = _mesh.read("sub_mesh"); - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, sub_meshes); + msgpack* sub_meshes = _mesh.read_array("sub_mesh"); + if (!sub_meshes) + continue; + + msgpack_array* ptr = sub_meshes->data.arr; for (size_t l = 0; l < mesh.num_submesh; l++) { obj_sub_mesh& sub_mesh = mesh.submesh_array[l]; msgpack& _sub_mesh = ptr->data()[l]; @@ -884,10 +837,10 @@ void object_material_msgpack_read(const char* path, const char* set_name, sprintf_s(buf, sizeof(buf), "%s\\%s\\config_tex.json", path, set_name_buf); if (!path_check_file_exists(buf)) return; - + msgpack msg; - stream s; + file_stream s; s.open(buf, "rb"); io_json_read(s, &msg); s.close(); @@ -895,10 +848,10 @@ void object_material_msgpack_read(const char* path, const char* set_name, if (msg.type != MSGPACK_MAP) return; - msgpack* add = msg.read("Add"); + msgpack* add = msg.read_array("Add"); if (add) { std::vector ids; - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, add); + msgpack_array* ptr = add->data.arr; for (msgpack& i : *ptr) { std::string name = i.read_string(); if (!name.size()) @@ -934,8 +887,8 @@ void object_material_msgpack_read(const char* path, const char* set_name, do for (uint32_t i = 0; i < tex->mipmaps_count; i++) { txp_mipmap tex_mip; - tex_mip.width = max(d.width >> i, 1); - tex_mip.height = max(d.height >> i, 1); + tex_mip.width = max_def(d.width >> i, 1); + tex_mip.height = max_def(d.height >> i, 1); tex_mip.format = d.format; uint32_t size = txp::get_size(tex_mip.format, tex_mip.width, tex_mip.height); @@ -954,7 +907,7 @@ void object_material_msgpack_read(const char* path, const char* set_name, if (set->tex_id_num != tex_id_num) { uint32_t* tex_id_data = force_malloc_s(uint32_t, tex_id_num); memmove(tex_id_data, set->tex_id_data, sizeof(uint32_t) * set->tex_id_num); - free(set->tex_id_data); + free_def(set->tex_id_data); memmove(&tex_id_data[set->tex_id_num], ids.data(), sizeof(uint32_t) * (tex_id_num - set->tex_id_num)); @@ -965,9 +918,9 @@ void object_material_msgpack_read(const char* path, const char* set_name, } - msgpack* replace = msg.read("Replace"); + msgpack* replace = msg.read_array("Replace"); if (replace) { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, replace); + msgpack_array* ptr = replace->data.arr; for (msgpack& i : *ptr) { std::string name = i.read_string(); if (!name.size()) @@ -1005,8 +958,8 @@ void object_material_msgpack_read(const char* path, const char* set_name, do for (uint32_t i = 0; i < tex->mipmaps_count; i++) { txp_mipmap tex_mip; - tex_mip.width = max(d.width >> i, 1); - tex_mip.height = max(d.height >> i, 1); + tex_mip.width = max_def(d.width >> i, 1); + tex_mip.height = max_def(d.height >> i, 1); tex_mip.format = d.format; uint32_t size = txp::get_size(tex_mip.format, tex_mip.width, tex_mip.height); @@ -1031,290 +984,282 @@ void object_material_msgpack_write(const char* path, const char* set_name, uint3 if (!path_check_directory_exists(buf) && !CreateDirectoryA(buf, 0)) return; - msgpack_array objects; - objects.resize(obj_set->obj_num); + msgpack_array objects(obj_set->obj_num); for (uint32_t i = 0; i < obj_set->obj_num; i++) { obj& obj = obj_set->obj_data[i]; msgpack& object = objects.data()[i]; - object = msgpack(0, false, 0); - object.append(msgpack("name", obj.name)); - object.append(msgpack("material", true, obj.num_material)); - object.append(msgpack("mesh", true, obj.num_mesh)); + object = msgpack(msgpack_map()); + object.append("name", obj.name); - msgpack* materials = object.get_by_name("material"); - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, materials); - for (size_t j = 0; j < obj.num_material; j++) { - obj_material& mat = obj.material_array[j].material; - msgpack& material = ptr->data()[j]; - material = msgpack(0, false, 0); + msgpack* materials = object.append("material", msgpack_array()); + if (materials) { + msgpack_array* ptr = materials->data.arr; + ptr->resize(obj.num_material); + for (size_t j = 0; j < obj.num_material; j++) { + obj_material& mat = obj.material_array[j].material; + msgpack& material = ptr->data()[j]; + material = msgpack_map(); - { - msgpack shader_compo = msgpack("shader_compo", false, 0); - shader_compo.append({ "color", (bool)mat.shader_compo.m.color }); - shader_compo.append({ "color_a", (bool)mat.shader_compo.m.color_a }); - shader_compo.append({ "color_l1", (bool)mat.shader_compo.m.color_l1 }); - shader_compo.append({ "color_l1_a", (bool)mat.shader_compo.m.color_l1_a }); - shader_compo.append({ "color_l2", (bool)mat.shader_compo.m.color_l2 }); - shader_compo.append({ "color_l2_a", (bool)mat.shader_compo.m.color_l2_a }); - shader_compo.append({ "transparency", (bool)mat.shader_compo.m.transparency }); - shader_compo.append({ "specular", (bool)mat.shader_compo.m.specular }); - shader_compo.append({ "normal_01", (bool)mat.shader_compo.m.normal_01 }); - shader_compo.append({ "normal_02", (bool)mat.shader_compo.m.normal_02 }); - shader_compo.append({ "envmap", (bool)mat.shader_compo.m.envmap }); - shader_compo.append({ "color_l3", (bool)mat.shader_compo.m.color_l3 }); - shader_compo.append({ "color_l3_a", (bool)mat.shader_compo.m.color_l3_a }); - shader_compo.append({ "translucency", (bool)mat.shader_compo.m.translucency }); - shader_compo.append({ "flag_14", (bool)mat.shader_compo.m.flag_14 }); - shader_compo.append({ "override_ibl", (bool)mat.shader_compo.m.override_ibl }); - shader_compo.append({ "dummy", mat.shader_compo.m.dummy }); - material.append(shader_compo); - } + msgpack* shader_compo = material.append("shader_compo", msgpack_map()); + if (shader_compo) { + shader_compo->append("color", (bool)mat.shader_compo.m.color); + shader_compo->append("color_a", (bool)mat.shader_compo.m.color_a); + shader_compo->append("color_l1", (bool)mat.shader_compo.m.color_l1); + shader_compo->append("color_l1_a", (bool)mat.shader_compo.m.color_l1_a); + shader_compo->append("color_l2", (bool)mat.shader_compo.m.color_l2); + shader_compo->append("color_l2_a", (bool)mat.shader_compo.m.color_l2_a); + shader_compo->append("transparency", (bool)mat.shader_compo.m.transparency); + shader_compo->append("specular", (bool)mat.shader_compo.m.specular); + shader_compo->append("normal_01", (bool)mat.shader_compo.m.normal_01); + shader_compo->append("normal_02", (bool)mat.shader_compo.m.normal_02); + shader_compo->append("envmap", (bool)mat.shader_compo.m.envmap); + shader_compo->append("color_l3", (bool)mat.shader_compo.m.color_l3); + shader_compo->append("color_l3_a", (bool)mat.shader_compo.m.color_l3_a); + shader_compo->append("translucency", (bool)mat.shader_compo.m.translucency); + shader_compo->append("flag_14", (bool)mat.shader_compo.m.flag_14); + shader_compo->append("override_ibl", (bool)mat.shader_compo.m.override_ibl); + shader_compo->append("dummy", mat.shader_compo.m.dummy); + } - material.append({ "shader_name", mat.shader.name }); + material.append("shader_name", mat.shader.name); - { - msgpack shader_info = msgpack("shader_info", false, 0); - shader_info.append({ "vtx_trans_type", mat.shader_info.m.vtx_trans_type }); - shader_info.append({ "col_src", mat.shader_info.m.col_src }); - shader_info.append({ "is_lgt_diffuse", (bool)mat.shader_info.m.is_lgt_diffuse }); - shader_info.append({ "is_lgt_specular", (bool)mat.shader_info.m.is_lgt_specular }); - shader_info.append({ "is_lgt_per_pixel",(bool)mat.shader_info.m.is_lgt_per_pixel }); - shader_info.append({ "is_lgt_double", (bool)mat.shader_info.m.is_lgt_double }); - shader_info.append({ "bump_map_type", mat.shader_info.m.bump_map_type }); - shader_info.append({ "fresnel_type", mat.shader_info.m.fresnel_type }); - shader_info.append({ "line_light", mat.shader_info.m.line_light }); - shader_info.append({ "recieve_shadow", (bool)mat.shader_info.m.recieve_shadow }); - shader_info.append({ "cast_shadow", (bool)mat.shader_info.m.cast_shadow }); - shader_info.append({ "specular_quality", mat.shader_info.m.specular_quality }); - shader_info.append({ "aniso_direction", mat.shader_info.m.aniso_direction }); - shader_info.append({ "dummy", mat.shader_info.m.dummy }); - material.append(shader_info); - } + msgpack* shader_info = material.append("shader_info", msgpack_map()); + if (shader_info) { + shader_info->append("vtx_trans_type", mat.shader_info.m.vtx_trans_type); + shader_info->append("col_src", mat.shader_info.m.col_src); + shader_info->append("is_lgt_diffuse", (bool)mat.shader_info.m.is_lgt_diffuse); + shader_info->append("is_lgt_specular", (bool)mat.shader_info.m.is_lgt_specular); + shader_info->append("is_lgt_per_pixel", (bool)mat.shader_info.m.is_lgt_per_pixel); + shader_info->append("is_lgt_double", (bool)mat.shader_info.m.is_lgt_double); + shader_info->append("bump_map_type", mat.shader_info.m.bump_map_type); + shader_info->append("fresnel_type", mat.shader_info.m.fresnel_type); + shader_info->append("line_light", mat.shader_info.m.line_light); + shader_info->append("recieve_shadow", (bool)mat.shader_info.m.recieve_shadow); + shader_info->append("cast_shadow", (bool)mat.shader_info.m.cast_shadow); + shader_info->append("specular_quality", mat.shader_info.m.specular_quality); + shader_info->append("aniso_direction", mat.shader_info.m.aniso_direction); + shader_info->append("dummy", mat.shader_info.m.dummy); + } - { - msgpack texdata = msgpack("texdata", false, 0); - for (obj_material_texture_data& k : mat.texdata) { - if (!k.tex_index || k.tex_index == -1 - || k.tex_index == hash_murmurhash_empty || k.tex_index == hash_murmurhash_null) - continue; + msgpack* texdata = material.append("texdata", msgpack_map()); + if (texdata) { + for (obj_material_texture_data& k : mat.texdata) { + if (!k.tex_index || k.tex_index == -1 + || k.tex_index == hash_murmurhash_empty || k.tex_index == hash_murmurhash_null) + continue; - sprintf_s(buf, sizeof(buf), "%d", (int32_t)(&k - mat.texdata)); - msgpack tex = msgpack(buf, false, 0); + sprintf_s(buf, sizeof(buf), "%d", (int32_t)(&k - mat.texdata)); + msgpack& tex = *texdata->append(buf, msgpack_map()); - { - msgpack attrib = msgpack("attrib", false, 0); - attrib.append({ "repeat_u", (bool)k.attrib.m.repeat_u }); - attrib.append({ "repeat_v", (bool)k.attrib.m.repeat_v }); - attrib.append({ "mirror_u", (bool)k.attrib.m.mirror_u }); - attrib.append({ "mirror_v", (bool)k.attrib.m.mirror_v }); - attrib.append({ "ignore_alpha", (bool)k.attrib.m.ignore_alpha }); - attrib.append({ "blend", k.attrib.m.blend }); - attrib.append({ "alpha_blend", k.attrib.m.alpha_blend }); - attrib.append({ "border", (bool)k.attrib.m.border }); - attrib.append({ "clamp2edge", (bool)k.attrib.m.clamp2edge }); - attrib.append({ "filter", k.attrib.m.filter }); - attrib.append({ "mipmap", k.attrib.m.mipmap }); - attrib.append({ "mipmap_bias", k.attrib.m.mipmap_bias }); - attrib.append({ "flag_29", (bool)k.attrib.m.flag_29 }); - attrib.append({ "anisotropic_filter", k.attrib.m.anisotropic_filter }); - tex.append(attrib); - } - - tex.append({ "tex_name", tex_db->get_texture_name(k.tex_index) }); - - { - msgpack shader_info = msgpack("shader_info", false, 0); - shader_info.append({ "tex_type", k.shader_info.m.tex_type }); - shader_info.append({ "uv_idx", k.shader_info.m.uv_idx }); - shader_info.append({ "texcoord_trans", k.shader_info.m.texcoord_trans }); - shader_info.append({ "dummy", k.shader_info.m.dummy }); - tex.append(shader_info); - } - - tex.append({ "ex_shader", k.ex_shader }); - tex.append({ "weight", k.weight }); - - { - msgpack tex_coord_mat = msgpack("tex_coord_mat", true, 4); - msgpack_array* tex_coord_mat_ptr = MSGPACK_SELECT(msgpack_array, tex_coord_mat); - - { - msgpack& row0 = tex_coord_mat_ptr->data()[0]; - row0 = msgpack(0, true, 4); - msgpack_array* row0_ptr = MSGPACK_SELECT(msgpack_array, row0); - row0_ptr->data()[0] = { 0, k.tex_coord_mat.row0.x }; - row0_ptr->data()[1] = { 0, k.tex_coord_mat.row0.y }; - row0_ptr->data()[2] = { 0, k.tex_coord_mat.row0.z }; - row0_ptr->data()[3] = { 0, k.tex_coord_mat.row0.w }; + msgpack* attrib = tex.append("attrib", msgpack_map()); + if (attrib) { + attrib->append("repeat_u", (bool)k.attrib.m.repeat_u); + attrib->append("repeat_v", (bool)k.attrib.m.repeat_v); + attrib->append("mirror_u", (bool)k.attrib.m.mirror_u); + attrib->append("mirror_v", (bool)k.attrib.m.mirror_v); + attrib->append("ignore_alpha", (bool)k.attrib.m.ignore_alpha); + attrib->append("blend", k.attrib.m.blend); + attrib->append("alpha_blend", k.attrib.m.alpha_blend); + attrib->append("border", (bool)k.attrib.m.border); + attrib->append("clamp2edge", (bool)k.attrib.m.clamp2edge); + attrib->append("filter", k.attrib.m.filter); + attrib->append("mipmap", k.attrib.m.mipmap); + attrib->append("mipmap_bias", k.attrib.m.mipmap_bias); + attrib->append("flag_29", (bool)k.attrib.m.flag_29); + attrib->append("anisotropic_filter", k.attrib.m.anisotropic_filter); } - { - msgpack& row1 = tex_coord_mat_ptr->data()[1]; - row1 = msgpack(0, true, 4); - msgpack_array* row1_ptr = MSGPACK_SELECT(msgpack_array, row1); - row1_ptr->data()[0] = { 0, k.tex_coord_mat.row1.x }; - row1_ptr->data()[1] = { 0, k.tex_coord_mat.row1.y }; - row1_ptr->data()[2] = { 0, k.tex_coord_mat.row1.z }; - row1_ptr->data()[3] = { 0, k.tex_coord_mat.row1.w }; + tex.append("tex_name", tex_db->get_texture_name(k.tex_index)); + + msgpack* shader_info = tex.append("shader_info", msgpack_map()); + if (shader_info) { + shader_info->append("tex_type", k.shader_info.m.tex_type); + shader_info->append("uv_idx", k.shader_info.m.uv_idx); + shader_info->append("texcoord_trans", k.shader_info.m.texcoord_trans); + shader_info->append("dummy", k.shader_info.m.dummy); } - { - msgpack& row2 = tex_coord_mat_ptr->data()[2]; - row2 = msgpack(0, true, 4); - msgpack_array* row2_ptr = MSGPACK_SELECT(msgpack_array, row2); - row2_ptr->data()[0] = { 0, k.tex_coord_mat.row2.x }; - row2_ptr->data()[1] = { 0, k.tex_coord_mat.row2.y }; - row2_ptr->data()[2] = { 0, k.tex_coord_mat.row2.z }; - row2_ptr->data()[3] = { 0, k.tex_coord_mat.row2.w }; + tex.append("ex_shader", k.ex_shader); + tex.append("weight", k.weight); + + msgpack* tex_coord_mat = tex.append("tex_coord_mat", msgpack_array()); + if (tex_coord_mat) { + msgpack_array* tex_coord_mat_ptr = tex_coord_mat->data.arr; + tex_coord_mat_ptr->resize(4); + + { + msgpack& row0 = tex_coord_mat_ptr->data()[0]; + row0 = msgpack_array(); + msgpack_array* row0_ptr = row0.data.arr; + row0_ptr->resize(4); + row0_ptr->data()[0] = k.tex_coord_mat.row0.x; + row0_ptr->data()[1] = k.tex_coord_mat.row0.y; + row0_ptr->data()[2] = k.tex_coord_mat.row0.z; + row0_ptr->data()[3] = k.tex_coord_mat.row0.w; + } + + { + msgpack& row1 = tex_coord_mat_ptr->data()[1]; + row1 = msgpack_array(); + msgpack_array* row1_ptr = row1.data.arr; + row1_ptr->resize(4); + row1_ptr->data()[0] = k.tex_coord_mat.row1.x; + row1_ptr->data()[1] = k.tex_coord_mat.row1.y; + row1_ptr->data()[2] = k.tex_coord_mat.row1.z; + row1_ptr->data()[3] = k.tex_coord_mat.row1.w; + } + + { + msgpack& row2 = tex_coord_mat_ptr->data()[2]; + row2 = msgpack_array(); + msgpack_array* row2_ptr = row2.data.arr; + row2_ptr->resize(4); + row2_ptr->data()[0] = k.tex_coord_mat.row2.x; + row2_ptr->data()[1] = k.tex_coord_mat.row2.y; + row2_ptr->data()[2] = k.tex_coord_mat.row2.z; + row2_ptr->data()[3] = k.tex_coord_mat.row2.w; + } + + { + msgpack& row3 = tex_coord_mat_ptr->data()[3]; + row3 = msgpack_array(); + msgpack_array* row3_ptr = row3.data.arr; + row3_ptr->resize(4); + row3_ptr->data()[0] = k.tex_coord_mat.row3.x; + row3_ptr->data()[1] = k.tex_coord_mat.row3.y; + row3_ptr->data()[2] = k.tex_coord_mat.row3.z; + row3_ptr->data()[3] = k.tex_coord_mat.row3.w; + } } - { - msgpack& row3 = tex_coord_mat_ptr->data()[3]; - row3 = msgpack(0, true, 4); - msgpack_array* row3_ptr = MSGPACK_SELECT(msgpack_array, row3); - row3_ptr->data()[0] = { 0, k.tex_coord_mat.row3.x }; - row3_ptr->data()[1] = { 0, k.tex_coord_mat.row3.y }; - row3_ptr->data()[2] = { 0, k.tex_coord_mat.row3.z }; - row3_ptr->data()[3] = { 0, k.tex_coord_mat.row3.w }; + msgpack* reserved = tex.append("reserved", msgpack_array()); + if (reserved) { + msgpack_array* ptr = reserved->data.arr; + ptr->resize(8); + for (int32_t l = 0; l < 8; l++) + ptr->data()[l] = k.reserved[l]; } + } + } - tex.append(tex_coord_mat); + msgpack* attrib = material.append("attrib", msgpack_map()); + if (attrib) { + attrib->append("alpha_texture", (bool)mat.attrib.m.alpha_texture); + attrib->append("alpha_material", (bool)mat.attrib.m.alpha_material); + attrib->append("punch_through", (bool)mat.attrib.m.punch_through); + attrib->append("double_sided", (bool)mat.attrib.m.double_sided); + attrib->append("normal_dir_light", (bool)mat.attrib.m.normal_dir_light); + attrib->append("src_blend_factor", mat.attrib.m.src_blend_factor); + attrib->append("dst_blend_factor", mat.attrib.m.dst_blend_factor); + attrib->append("blend_operation", mat.attrib.m.blend_operation); + attrib->append("zbias", mat.attrib.m.zbias); + attrib->append("no_fog", (bool)mat.attrib.m.no_fog); + attrib->append("translucent_priority", mat.attrib.m.translucent_priority); + attrib->append("has_fog_height", (bool)mat.attrib.m.has_fog_height); + attrib->append("flag_28", (bool)mat.attrib.m.flag_28); + attrib->append("fog_height", (bool)mat.attrib.m.fog_height); + attrib->append("flag_30", (bool)mat.attrib.m.flag_30); + attrib->append("flag_31", (bool)mat.attrib.m.flag_31); + } + + msgpack* color = material.append("color", msgpack_map()); + if (color) { + msgpack* diffuse = color->append("diffuse", msgpack_map()); + if (diffuse) { + diffuse->append("r", mat.color.diffuse.x); + diffuse->append("g", mat.color.diffuse.y); + diffuse->append("b", mat.color.diffuse.z); + diffuse->append("a", mat.color.diffuse.w); } - { - msgpack reserved = msgpack("reserved", true, 8); - msgpack_array* ptr = MSGPACK_SELECT(msgpack_array, reserved); - for (int32_t l = 0; l < 8; l++) - ptr->data()[l] = { 0, k.reserved[l] }; - tex.append(reserved); + msgpack* ambient = color->append("ambient", msgpack_map()); + if (ambient) { + ambient->append("r", mat.color.ambient.x); + ambient->append("g", mat.color.ambient.y); + ambient->append("b", mat.color.ambient.z); + ambient->append("a", mat.color.ambient.w); } - texdata.append(tex); + msgpack* specular = color->append("specular", msgpack_map()); + if (specular) { + specular->append("r", mat.color.specular.x); + specular->append("g", mat.color.specular.y); + specular->append("b", mat.color.specular.z); + specular->append("a", mat.color.specular.w); + } + + msgpack* emission = color->append("emission", msgpack_map()); + if (emission) { + emission->append("r", mat.color.emission.x); + emission->append("g", mat.color.emission.y); + emission->append("b", mat.color.emission.z); + emission->append("a", mat.color.emission.w); + } + + color->append("shininess", mat.color.shininess); + color->append("intensity", mat.color.intensity); + } - material.append(texdata); - } - - { - msgpack attrib = msgpack("attrib", false, 0); - attrib.append({ "alpha_texture", (bool)mat.attrib.m.alpha_texture }); - attrib.append({ "alpha_material", (bool)mat.attrib.m.alpha_material }); - attrib.append({ "punch_through", (bool)mat.attrib.m.punch_through }); - attrib.append({ "double_sided", (bool)mat.attrib.m.double_sided }); - attrib.append({ "normal_dir_light", (bool)mat.attrib.m.normal_dir_light }); - attrib.append({ "src_blend_factor", mat.attrib.m.src_blend_factor }); - attrib.append({ "dst_blend_factor", mat.attrib.m.dst_blend_factor }); - attrib.append({ "blend_operation", mat.attrib.m.blend_operation }); - attrib.append({ "zbias", mat.attrib.m.zbias }); - attrib.append({ "no_fog", (bool)mat.attrib.m.no_fog }); - attrib.append({ "translucent_priority", mat.attrib.m.translucent_priority }); - attrib.append({ "has_fog_height", (bool)mat.attrib.m.has_fog_height }); - attrib.append({ "flag_28", (bool)mat.attrib.m.flag_28 }); - attrib.append({ "fog_height", (bool)mat.attrib.m.fog_height }); - attrib.append({ "flag_30", (bool)mat.attrib.m.flag_30 }); - attrib.append({ "flag_31", (bool)mat.attrib.m.flag_31 }); - material.append(attrib); - } - - { - msgpack color = msgpack("color", false, 0); - - { - msgpack diffuse = msgpack("diffuse", false, 0); - diffuse.append({ "r", mat.color.diffuse.x }); - diffuse.append({ "g", mat.color.diffuse.y }); - diffuse.append({ "b", mat.color.diffuse.z }); - diffuse.append({ "a", mat.color.diffuse.w }); - color.append(diffuse); + msgpack* center = material.append("center", msgpack_map()); + if (center) { + center->append("x", mat.center.x); + center->append("y", mat.center.y); + center->append("z", mat.center.z); } - { - msgpack ambient = msgpack("ambient", false, 0); - ambient.append({ "r", mat.color.ambient.x }); - ambient.append({ "g", mat.color.ambient.y }); - ambient.append({ "b", mat.color.ambient.z }); - ambient.append({ "a", mat.color.ambient.w }); - color.append(ambient); + material.append("radius", mat.radius); + material.append("name", mat.name); + material.append("bump_depth", mat.bump_depth); + + msgpack* reserved = material.append("reserved", msgpack_array()); + if (reserved) { + msgpack_array* ptr = reserved->data.arr; + ptr->resize(15); + for (int32_t k = 0; k < 15; k++) + ptr->data()[k] = mat.reserved[k]; } - - { - msgpack specular = msgpack("specular", false, 0); - specular.append({ "r", mat.color.specular.x }); - specular.append({ "g", mat.color.specular.y }); - specular.append({ "b", mat.color.specular.z }); - specular.append({ "a", mat.color.specular.w }); - color.append(specular); - } - - { - msgpack emission = msgpack("emission", false, 0); - emission.append({ "r", mat.color.emission.x }); - emission.append({ "g", mat.color.emission.y }); - emission.append({ "b", mat.color.emission.z }); - emission.append({ "a", mat.color.emission.w }); - color.append(emission); - } - - color.append({ "shininess", mat.color.shininess }); - color.append({ "intensity", mat.color.intensity }); - - material.append(color); - } - - { - msgpack center = msgpack("center", false, 0); - center.append({ "x", mat.center.x }); - center.append({ "y", mat.center.y }); - center.append({ "z", mat.center.z }); - material.append(center); - } - - material.append({ "radius", mat.radius }); - material.append({ "name", mat.name }); - material.append({ "bump_depth", mat.bump_depth }); - - { - msgpack reserved = msgpack("reserved", true, 15); - msgpack_array* ptr = MSGPACK_SELECT(msgpack_array, reserved); - for (int32_t k = 0; k < 15; k++) - ptr->data()[k] = { 0, mat.reserved[k] }; - material.append(reserved); } } - msgpack* meshes = object.get_by_name("mesh"); - ptr = MSGPACK_SELECT_PTR(msgpack_array, meshes); - for (size_t j = 0; j < obj.num_mesh; j++) { - obj_mesh& mesh = obj.mesh_array[j]; - msgpack& _mesh = ptr->data()[j]; - _mesh = msgpack(0, false, 0); + msgpack* meshes = object.append("mesh", msgpack_array()); + if (meshes) { + msgpack_array* ptr = meshes->data.arr; + ptr->resize(obj.num_mesh); + for (size_t j = 0; j < obj.num_mesh; j++) { + obj_mesh& mesh = obj.mesh_array[j]; + msgpack& _mesh = ptr->data()[j]; + _mesh = msgpack_map(); - _mesh.append(msgpack("name", mesh.name)); - _mesh.append(msgpack("sub_mesh", true, mesh.num_submesh)); + _mesh.append("name", mesh.name); - msgpack* sub_meshes = _mesh.get_by_name("sub_mesh"); - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, sub_meshes); - for (size_t k = 0; k < mesh.num_submesh; k++) { - obj_sub_mesh& sub_mesh = mesh.submesh_array[k]; - msgpack& _sub_mesh = ptr->data()[k]; - _sub_mesh = msgpack(0, false, 0); + msgpack* sub_meshes = _mesh.append("sub_mesh", msgpack_array()); + if (sub_meshes) { + msgpack_array* ptr = sub_meshes->data.arr; + ptr->resize(mesh.num_submesh); + for (size_t k = 0; k < mesh.num_submesh; k++) { + obj_sub_mesh& sub_mesh = mesh.submesh_array[k]; + msgpack& _sub_mesh = ptr->data()[k]; + _sub_mesh = msgpack_map(); - { - msgpack attrib = msgpack("attrib", false, 0); - attrib.append({ "recieve_shadow", (bool)sub_mesh.attrib.m.recieve_shadow }); - attrib.append({ "cast_shadow", (bool)sub_mesh.attrib.m.cast_shadow }); - _sub_mesh.append(attrib); + { + msgpack attrib = msgpack_map(); + attrib.append("recieve_shadow", (bool)sub_mesh.attrib.m.recieve_shadow); + attrib.append("cast_shadow", (bool)sub_mesh.attrib.m.cast_shadow); + _sub_mesh.append("attrib", attrib); + } + } } } } } - msgpack msg = msgpack(0, true, objects); + msgpack msg = objects; sprintf_s(buf, sizeof(buf), "%s\\%s\\config.json", path, set_name); - stream s; + file_stream s; s.open(buf, "wb"); io_json_write(s, &msg); s.close(); @@ -1338,7 +1283,7 @@ void object_material_msgpack_write(const char* path, const char* set_name, uint3 uint32_t index = 0; do for (uint32_t j = 0; j < tex.mipmaps_count; j++) { - uint32_t size = txp::get_size(format, max(width >> j, 1), max(height >> j, 1)); + uint32_t size = txp::get_size(format, max_def(width >> j, 1), max_def(height >> j, 1)); void* data = force_malloc(size); memcpy(data, tex.mipmaps[index].data.data(), size); d.data.push_back(data); @@ -2048,7 +1993,7 @@ inline void object_storage_unload_set(object_database* obj_db, const char* name) int32_t tex_num = handler->tex_num; for (int32_t i = 0; i < tex_num; i++) texture_free(tex_data[i]); - free(tex_data); + free_def(tex_data); handler->tex_data = 0; handler->tex_num = 0; @@ -2080,7 +2025,7 @@ inline void object_storage_unload_set(uint32_t set_id) { int32_t tex_num = handler->tex_num; for (int32_t i = 0; i < tex_num; i++) texture_free(tex_data[i]); - free(tex_data); + free_def(tex_data); handler->tex_data = 0; handler->tex_num = 0; @@ -2128,21 +2073,18 @@ static void obj_set_handler_calc_axis_aligned_bounding_box(obj_set_handler* hand continue; vec3 pos = vertex[indices[l]].position; - vec3_min(_min, pos, _min); - vec3_max(_max, pos, _max); + _min = vec3::min(_min, pos); + _max = vec3::max(_max, pos); } else for (uint32_t l = 0; l < indices_count; l++) { vec3 pos = vertex[indices[l]].position; - vec3_min(_min, pos, _min); - vec3_max(_max, pos, _max); + _min = vec3::min(_min, pos); + _max = vec3::max(_max, pos); } - vec3 center; - vec3 size; - vec3_add(_max, _min, center); - vec3_mult_scalar(center, 0.5f, center); - vec3_sub(_max, center, size); + vec3 center = (_max + _min) * 0.5f; + vec3 size = _max - center; sub_mesh.axis_aligned_bounding_box.center = center; sub_mesh.axis_aligned_bounding_box.size = size; } @@ -2320,7 +2262,7 @@ inline static void obj_skin_block_node_load(obj_skin_block_node* node, } inline static void obj_skin_block_node_free(obj_skin_block_node* node) { - free(node->parent_name); + free_def(node->parent_name); } inline static size_t obj_vertex_format_get_vertex_size(obj_vertex_format format) { diff --git a/src/CRE/ogg_vorbis.cpp b/src/CRE/ogg_vorbis.cpp new file mode 100644 index 00000000..6ee54b9d --- /dev/null +++ b/src/CRE/ogg_vorbis.cpp @@ -0,0 +1,583 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "ogg_vorbis.hpp" +#include "../KKdLib/str_utils.hpp" +#include "../KKdLib/vec.hpp" +#include + +static int32_t ogg_file_counter = 0; +static int32_t ogg_file_handler_counter = 0; + +OggFileBufferChannelData::OggFileBufferChannelData() : left(), right() { + +} + +OggFileBufferData::OggFileBufferData() { + time = -1.0; +} + +OggFileBuffer::OggFileBuffer() : first_sample(), last_sample() { + size = 0x40999; + data.resize(size); +} + +OggFileBuffer::~OggFileBuffer() { + +} + +void OggFileBuffer::Reset() { + data.clear(); + data.resize(size); + first_sample = 0; + last_sample = 0; +} + +OggFile::OggFile() : file(), info(), comments() { + loop_begin = -1; + loop_end = -1; + + thread = new std::thread(OggFile::ThreadMain, this); + if (thread) { + wchar_t buf[0x80]; + swprintf_s(buf, sizeof(buf) / sizeof(wchar_t), L"Ogg File #%d", ogg_file_counter++); + SetThreadDescription((HANDLE)thread->native_handle(), buf); + } +} + +OggFile::~OggFile() { + Reset(); + if (thread) { + thread_state.set(1); + thread->join(); + delete thread; + thread = 0; + } +} + +void OggFile::Ctrl(size_t samples_count) { + std::unique_lock u_lock(file_mtx); + if (!file || !info || !comments) + return; + + OggFileBufferData* _buffer_data = buffer.data.data(); + size_t _buffer_size = buffer.data.size(); + + while (samples_count) { + size_t free_samples_count = GetBufferFreeSamplesCount(); + if (free_samples_count <= 0) + break; + + int64_t samples_to_read = min_def(samples_count, free_samples_count); + int64_t position = ov_pcm_tell(file); + double_t time_start = ov_time_tell(file); + if (loop_end >= 0 && position + samples_to_read > loop_end) { + if (loop_end - position <= 0) { + size_t seek = 0i64; + if (loop_begin >= 0) + seek = loop_begin; + ov_pcm_seek_lap(file, seek); + } + else + samples_to_read = loop_end - position; + } + + float_t** pcm_channels = 0; + int32_t bitstream = 0; + size_t samples_read = ov_read_float(file, &pcm_channels, (int32_t)samples_to_read, &bitstream); + if (samples_read < 1 || !pcm_channels) + break; + + int32_t channels = info->channels; + bool mono = channels == 1; + + std::unique_lock u_lock(mtx); + for (size_t i = 0; i < samples_read; i++) { + OggFileBufferData data; + data.time = (double_t)(int32_t)i / (double_t)info->rate + time_start; + if (channels > 0) { + if (mono) { + float_t value = pcm_channels[0][i]; + data.channel_pair[0].left = value; + data.channel_pair[0].right = value; + } + else { + float_t** _pcm_channels = pcm_channels; + for (int32_t j = 0; j < channels; j += 2, _pcm_channels += 2) { + int32_t pair = j / 2; + if (pair >= 4) + break; + + data.channel_pair[pair].left = _pcm_channels[0][i]; + data.channel_pair[pair].right = _pcm_channels[1][i]; + } + } + } + + if (_buffer_size) { + size_t last_sample = buffer.last_sample; + size_t new_last_sample = last_sample + 1; + if (new_last_sample >= buffer.size) + new_last_sample = 0; + if (new_last_sample != buffer.first_sample) { + _buffer_data[last_sample] = data; + buffer.last_sample = new_last_sample; + } + } + } + samples_count -= samples_read; + } +} + +size_t OggFile::FillBufferData(OggFileBufferData* buffer_data, size_t samples_count) { + std::unique_lock u_lock(mtx); + OggFileBufferData* _buffer_data = buffer.data.data(); + size_t _buffer_size = buffer.data.size(); + size_t _samples_count = 0; + for (; samples_count && buffer.first_sample != buffer.last_sample; + samples_count--, buffer_data++, _samples_count++) { + if (_buffer_size) + *buffer_data = _buffer_data[buffer.first_sample]; + else + *buffer_data = {}; + + if (_buffer_size) { + size_t first_sample = buffer.first_sample; + if (first_sample != buffer.last_sample) { + _buffer_data[first_sample++] = {}; + if (first_sample >= buffer.size) + first_sample = 0; + buffer.first_sample = first_sample; + } + } + } + return _samples_count; +} + +size_t OggFile::GetBufferFreeSamplesCount() { + std::unique_lock u_lock(mtx); + size_t last_sample = buffer.last_sample; + size_t first_sample = buffer.first_sample; + size_t samples_count; + if (last_sample < first_sample) + samples_count = buffer.size - first_sample + last_sample; + else + samples_count = last_sample - first_sample; + return buffer.size - samples_count - 1; +} + +size_t OggFile::GetBufferSamplesCount() { + std::unique_lock u_lock(mtx); + size_t last_sample = buffer.last_sample; + size_t first_sample = buffer.first_sample; + if (last_sample < first_sample) + return buffer.size - first_sample + last_sample; + else + return last_sample - first_sample; +} + +int32_t OggFile::GetChannelPairsCount() { + std::unique_lock u_lock(file_mtx); + if (info) + return (info->channels + 1) / 2; + return 0; +} + +double_t OggFile::GetDuration() { + std::unique_lock u_lock(file_mtx); + if (file) + return ov_time_total(file, -1); + return 0.0; +} + +int32_t OggFile::GetRate() { + std::unique_lock u_lock(file_mtx); + if (info) + return info->rate; + return 0; +} + +bool OggFile::HasLoop() { + std::unique_lock u_lock(file_mtx); + return loop_end >= 0; +} + +bool OggFile::OpenFile(const char* path, double_t time_seek) { + { + std::unique_lock u_lock(file_mtx); + if (file) + goto Reset; + + file = force_malloc_s(OggVorbis_File, 1); + if (!file) + goto Reset; + + if (ov_fopen(path, file) < 0) + goto Reset; + + info = ov_info(file, -1); + comments = ov_comment(file, -1); + loop_begin = -1; + loop_end = -1; + + if (!info || !comments) { + info = 0; + comments = 0; + goto Reset; + } + + char** user_comments = comments->user_comments; + while (*user_comments) { + std::string user_comment = *user_comments++; + for (char& c : user_comment) + if (c > 0x40 && c < 0x5B) + c += 0x20; + + if (user_comment.size() >= 10 && !memcmp(user_comment.c_str(), "loop_begin", 10)) { + const char* t = strchr(user_comment.c_str(), '='); + if (t) { + t++; + sscanf_s(t, "%lld", &loop_begin); + } + } + else if (user_comment.size() >= 8 && !memcmp(user_comment.c_str(), "loop_end", 8)) { + const char* t = strchr(user_comment.c_str(), '='); + if (t) { + t++; + sscanf_s(t, "%lld", &loop_end); + } + } + } + + if (ov_time_seek(this->file, time_seek) >= 0) + return true; + } + +Reset: + Reset(); + return false; +} + +void OggFile::Reset() { + std::unique_lock u_lock(file_mtx); + if (file) { + ov_clear(file); + free(file); + } + + buffer.Reset(); + file = 0; + info = 0; + comments = 0; + loop_begin = -1; + loop_end = -1; +} + +void OggFile::ThreadMain(OggFile* of) { + if (!of) + return; + + waitable_timer timer; + while (!of->thread_state.get()) { + of->Ctrl(of->info ? of->info->rate : 44100); + timer.sleep(8); + } + of->thread_state.set(0); +} + +OggFileHandler::OggFileHandler(size_t index) : time_seek(), channel_pairs_count(), +duration(), time(), channel_pairs_count_dup(), duration_dup(), time_dup(), +channel_pair_volume_pan(), master_volume(), channel_pair_volume(), req_time(), loop() { + this->index = index; + + for (int32_t i = 0; i < 4; i++) + for (int32_t j = 0; j < 2; j++) + for (int32_t k = 0; k < 4; k++) + channel_pair_volume_pan[i][j][k] = -10000; + + channel_pair_volume_pan[0][0][0] = 0; + channel_pair_volume_pan[0][1][1] = 0; + rate = 1; + + thread = new std::thread(OggFileHandler::ThreadMain, this); + if (thread) { + wchar_t buf[0x80]; + swprintf_s(buf, sizeof(buf) / sizeof(wchar_t), L"Ogg File Handler #%d", ogg_file_handler_counter++); + SetThreadDescription((HANDLE)thread->native_handle(), buf); + } +} + +OggFileHandler::~OggFileHandler() { + Reset(); + if (thread) { + thread_state.set(1); + thread->join(); + delete thread; + thread = 0; + } +} + +void OggFileHandler::Ctrl() { + int32_t _playback_state = 0; + { + std::unique_lock u_lock(mtx); + _playback_state = playback_state.get(); + playback_state.set(OGG_FILE_HANDLER_PLAYBACK_STATE_NONE); + switch (_playback_state) { + case OGG_FILE_HANDLER_PLAYBACK_STATE_PLAY: + Reset(false); + file_state.set(OGG_FILE_HANDLER_FILE_STATE_LOADING); + OpenFile(); + file_state.set(OGG_FILE_HANDLER_FILE_STATE_READY); + req_time = 0.0; + ReadBufferProt(0, 0); + break; + case OGG_FILE_HANDLER_PLAYBACK_STATE_STOP: + Reset(true); + break; + } + } + + sound::wasapi::System* sound_wasapi_system = sound_wasapi_system_data_get(); + if (sound_wasapi_system) { + sound::wasapi::Mixer* mixer = sound_wasapi_system->mixer; + if (mixer) { + sound::wasapi::StreamingChannel* streaming_channel = mixer->GetStreamingChannel(index); + if (streaming_channel) { + switch (_playback_state) { + case OGG_FILE_HANDLER_PLAYBACK_STATE_PLAY: + if (sound_wasapi_system->pClockAdjustment) + sound_wasapi_system->pClockAdjustment->SetSampleRate((float_t)rate); + + streaming_channel->SetMasterVolume(1.0f); + streaming_channel->SetCallback(OggFileHandler::FillBufferStatic, this); + break; + case OGG_FILE_HANDLER_PLAYBACK_STATE_STOP: + streaming_channel->reset_state.set(1); + break; + } + } + } + } + + int32_t _channel_pairs_count = 0; + double_t _duration = 0.0; + double_t _time = 0.0; + + { + std::unique_lock u_lock(file_mtx); + _channel_pairs_count = channel_pairs_count; + _duration = duration; + _time = time; + } + + { + std::unique_lock u_lock(dup_mtx); + channel_pairs_count_dup = _channel_pairs_count; + duration_dup = _duration; + time_dup = _time; + } + + int32_t value = ratio_to_db(1.0); + if (!_channel_pairs_count) + _channel_pairs_count = 2; + + if (_channel_pairs_count >= 3 && _channel_pairs_count <= 4) { + for (int32_t i = 0; i < 2; i++) { + SetChannelPairVolumePan(i, 0, 0, value); + SetChannelPairVolumePan(i, 1, 1, value); + SetChannelPairVolumePan(i, 0, 2, -10000); + SetChannelPairVolumePan(i, 1, 3, -10000); + } + + for (int32_t i = _channel_pairs_count - 2; i < _channel_pairs_count; i++) { + SetChannelPairVolumePan(i, 0, 0, -10000); + SetChannelPairVolumePan(i, 1, 1, -10000); + SetChannelPairVolumePan(i, 0, 2, value); + SetChannelPairVolumePan(i, 1, 3, value); + } + } + else + for (int32_t i = 0; i < _channel_pairs_count; i++) { + SetChannelPairVolumePan(i, 0, 0, value); + SetChannelPairVolumePan(i, 1, 1, value); + SetChannelPairVolumePan(i, 0, 2, value); + SetChannelPairVolumePan(i, 1, 3, value); + } +} + +void OggFileHandler::FillBuffer(sound_buffer_data* buffer, size_t samples_count) { + int32_t _file_state = file_state.get(); + file_state.set(OGG_FILE_HANDLER_FILE_STATE_NONE); + + int32_t _playback_state = playback_state.get(); + playback_state.set(0); + + if (_file_state == OGG_FILE_HANDLER_FILE_STATE_PLAYING + && _playback_state != OGG_FILE_HANDLER_PLAYBACK_STATE_STOP) { + std::unique_lock u_lock(mtx); + ReadBufferProt(buffer, samples_count); + } +} + +void OggFileHandler::OpenFile() { + std::unique_lock u_lock(file_mtx); + if (file.OpenFile(path.c_str(), time_seek)) { + channel_pairs_count = file.GetChannelPairsCount(); + duration = file.GetDuration(); + time = 0.0; + rate = file.GetRate(); + loop = file.HasLoop(); + } +} + +void OggFileHandler::ReadBuffer(sound_buffer_data* buffer, size_t samples_count) { + if (!samples_count) + return; + + vec4 channel_pair_volume_pan[4][2]; + float_t channel_pair_volume[4]; + { + std::unique_lock u_lock(volume_mtx); + float_t master_volume = db_to_ratio(this->master_volume); + for (int32_t i = 0; i < 4; i++) { + for (int32_t j = 0; j < 2; j++) + for (int32_t k = 0; k < 4; k++) + ((float_t*)&channel_pair_volume_pan[i][j])[k] + = db_to_ratio(this->channel_pair_volume_pan[i][j][k]); + channel_pair_volume[i] = db_to_ratio(this->channel_pair_volume[i]) * master_volume; + } + } + + size_t samples_count_in_buffer = file.GetBufferSamplesCount(); + if (samples_count > samples_count_in_buffer) { + file.Ctrl(samples_count - samples_count_in_buffer); + file.GetBufferSamplesCount(); + } + + buffer_data.resize(samples_count); + if (!buffer_data.size()) + return; + + OggFileBufferData* _buffer_data = buffer_data.data(); + size_t _samples_count = file.FillBufferData(_buffer_data, samples_count); + if (_samples_count) + req_time = _buffer_data->time; + else { + double_t _samples_count = (double_t)(int32_t)samples_count; + if (samples_count < 0) + _samples_count += 1.844674407370955e19; + req_time += _samples_count / (double_t)rate; + } + + if (_samples_count) { + for (size_t i = _samples_count; i; i--, buffer++, _buffer_data++) { + OggFileBufferChannelData* channel_pair = _buffer_data->channel_pair; + vec4 value = vec4_null; + for (size_t j = 0; j < 4; j++, channel_pair++) { + value += (channel_pair_volume_pan[j][0] * (channel_pair_volume[j] * channel_pair->left)); + value += (channel_pair_volume_pan[j][1] * (channel_pair_volume[j] * channel_pair->right)); + } + *(vec4*)buffer = value; + } + } + else + memset(buffer, 0, sizeof(sound_buffer_data) * samples_count); +} + +void OggFileHandler::ReadBufferProt(sound_buffer_data* buffer, size_t samples_count) { + file_state.set(OGG_FILE_HANDLER_FILE_STATE_PLAYING); + if (pause_state.get() != OGG_FILE_HANDLER_PAUSE_STATE_PLAY) + samples_count = 0; + + bool process = false; + { + std::unique_lock u_lock(file_mtx); + time = req_time; + process = req_time < duration; + } + + if (process || loop) + ReadBuffer(buffer, samples_count); + else + playback_state.set(OGG_FILE_HANDLER_PLAYBACK_STATE_STOP); +} + +void OggFileHandler::Reset(bool reset) { + if (reset) { + SetFileState(OGG_FILE_HANDLER_FILE_STATE_STOPPING); + std::unique_lock u_lock(file_mtx); + channel_pairs_count = 0; + duration = 0.0; + time = 0.0; + } + + file.Reset(); + if (reset) { + SetFileState(OGG_FILE_HANDLER_FILE_STATE_STOPPED); + SetFileState(OGG_FILE_HANDLER_FILE_STATE_NONE); + } +} + +void OggFileHandler::SetChannelPairVolumePan(size_t src_channel_pair, + int32_t src_channel, int32_t dst_channel, int32_t value) { + if (src_channel_pair < 0 || src_channel_pair >= 4 || src_channel < 0 + || src_channel >= 2 || dst_channel < 0 || dst_channel >= 4) + return; + + value = clamp_def(value, -10000, 0); + + std::unique_lock u_lock(volume_mtx); + channel_pair_volume_pan[src_channel_pair][src_channel][dst_channel] = value; +} + +void OggFileHandler::SetFileState(OggFileHandlerFileState state) { + file_state.set(state); + if (state == OGG_FILE_HANDLER_PLAYBACK_STATE_MAX) + Reset(false); +} + +void OggFileHandler::SetPath(std::string& path) { + std::unique_lock u_lock(mtx); + file_state.set(1); + playback_state.set(OGG_FILE_HANDLER_PLAYBACK_STATE_PLAY); + + { + std::unique_lock u_lock(file_mtx); + this->path.assign(path); + channel_pairs_count = 0; + duration = 0.0; + time = 0.0; + } +} + +void OggFileHandler::SetPath(std::string&& path) { + SetPath(*(std::string*)&path); +} + +void OggFileHandler::FillBufferStatic(sound_buffer_data* buffer, size_t samples_count, void* data) { + if (data) + ((OggFileHandler*)data)->FillBuffer(buffer, samples_count); +} + +bool OggFileHandler::LoadFile(void* data, const char* path, const char* file, uint32_t hash) { + OggFileHandler* ofh = (OggFileHandler*)data; + ofh->SetPath(std::string(path) + file); + return true; +} + +void OggFileHandler::ThreadMain(OggFileHandler* ofh) { + if (!ofh) + return; + + waitable_timer timer; + while (!ofh->thread_state.get()) { + ofh->Ctrl(); + timer.sleep(8); + } + ofh->playback_state.set(OGG_FILE_HANDLER_PLAYBACK_STATE_STOP); + ofh->Ctrl(); + ofh->thread_state.set(0); +} diff --git a/src/CRE/ogg_vorbis.hpp b/src/CRE/ogg_vorbis.hpp new file mode 100644 index 00000000..663b9c4e --- /dev/null +++ b/src/CRE/ogg_vorbis.hpp @@ -0,0 +1,150 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/default.hpp" +#include "../CRE/waitable_timer.hpp" +#include "lock.hpp" +#include "sound.hpp" +#include +#include +#include +#include +#include +#include + +enum AudioBitFormat { + AUDIO_BIT_FORMAT_S16 = 0, + AUDIO_BIT_FORMAT_S24, + AUDIO_BIT_FORMAT_S32, + AUDIO_BIT_FORMAT_F32, +}; + +enum OggFileHandlerFileState { + OGG_FILE_HANDLER_FILE_STATE_NONE = 0, + OGG_FILE_HANDLER_FILE_STATE_LOADING, + OGG_FILE_HANDLER_FILE_STATE_READY, + OGG_FILE_HANDLER_FILE_STATE_PLAYING, + OGG_FILE_HANDLER_FILE_STATE_STOPPING, + OGG_FILE_HANDLER_FILE_STATE_STOPPED, + OGG_FILE_HANDLER_FILE_STATE_MAX, +}; + +enum OggFileHandlerPauseState { + OGG_FILE_HANDLER_PAUSE_STATE_PLAY = 0, + OGG_FILE_HANDLER_PAUSE_STATE_PAUSE, + OGG_FILE_HANDLER_PAUSE_STATE_MAX, +}; + +enum OggFileHandlerPlaybackState { + OGG_FILE_HANDLER_PLAYBACK_STATE_NONE = 0, + OGG_FILE_HANDLER_PLAYBACK_STATE_PLAY, + OGG_FILE_HANDLER_PLAYBACK_STATE_STOP, + OGG_FILE_HANDLER_PLAYBACK_STATE_MAX, +}; + +struct OggFileBufferChannelData { + float_t left; + float_t right; + + OggFileBufferChannelData(); +}; + +struct OggFileBufferData { + double_t time; + OggFileBufferChannelData channel_pair[4]; + + OggFileBufferData(); +}; + +struct OggFileBuffer { + size_t size; + std::vector data; + size_t first_sample; + size_t last_sample; + + OggFileBuffer(); + ~OggFileBuffer(); + + void Reset(); +}; + +struct OggFile { + std::mutex mtx; + lock_uint32_t thread_state; + std::thread* thread; + OggFileBuffer buffer; + OggVorbis_File* file; + vorbis_info* info; + vorbis_comment* comments; + int64_t loop_begin; + int64_t loop_end; + std::mutex file_mtx; + + OggFile(); + virtual ~OggFile(); + + void Ctrl(size_t samples_count); + size_t FillBufferData(OggFileBufferData* buffer_data, size_t samples_count); + size_t GetBufferFreeSamplesCount(); + size_t GetBufferSamplesCount(); + int32_t GetChannelPairsCount(); + double_t GetDuration(); + int32_t GetRate(); + bool HasLoop(); + bool OpenFile(const char* path, double_t time_seek); + void Reset(); + + static void ThreadMain(OggFile* of); +}; + +struct OggFileHandler { + std::mutex mtx; + lock_uint32_t thread_state; + std::thread* thread; + size_t index; + OggFile file; + std::mutex file_mtx; + std::string path; + float_t time_seek; + int32_t channel_pairs_count; + double_t duration; + double_t time; + std::mutex dup_mtx; + int32_t channel_pairs_count_dup; + double_t duration_dup; + double_t time_dup; + std::mutex volume_mtx; + int32_t channel_pair_volume_pan[4][2][4]; + int32_t master_volume; + int32_t channel_pair_volume[4]; + lock_uint32_t file_state; + lock_uint32_t playback_state; + lock_uint32_t pause_state; + double_t req_time; + int32_t rate; + bool loop; + std::vector buffer_data; + + OggFileHandler(size_t index = 0); + virtual ~OggFileHandler(); + + void Ctrl(); + void FillBuffer(sound_buffer_data* buffer, size_t samples_count); + void OpenFile(); + void ReadBuffer(sound_buffer_data* buffer, size_t samples_count); + void ReadBufferProt(sound_buffer_data* buffer, size_t samples_count); + void Reset(bool reset = false); + void SetChannelPairVolumePan(size_t src_channel_pair, + int32_t src_channel, int32_t dst_channel, int32_t value); + void SetFileState(OggFileHandlerFileState state); + void SetPath(std::string& path); + void SetPath(std::string&& path); + + static void FillBufferStatic(sound_buffer_data* buffer, size_t samples_count, void* data); + static bool LoadFile(void* data, const char* path, const char* file, uint32_t hash); + static void ThreadMain(OggFileHandler* ofh); +}; diff --git a/src/CRE/post_process.cpp b/src/CRE/post_process.cpp index cdbb721b..c1037af5 100644 --- a/src/CRE/post_process.cpp +++ b/src/CRE/post_process.cpp @@ -15,7 +15,7 @@ extern bool task_stage_is_modern; -post_process::post_process() : ssaa(), mlaa(), parent_bone_node(), render_textures_data(), +post_process::post_process() : ssaa(), mlaa(), ss_alpha_mask(), render_textures_data(), movie_textures_data(), lens_flare_texture(), lens_shaft_texture(), lens_ghost_texture(), lens_flare_count(), lens_flare_pos(), lens_shaft_scale(), lens_shaft_inv_scale(), lens_flare_power(), field_A10(), lens_flare_appear_power(), render_width(), render_height(), @@ -39,7 +39,7 @@ sprite_height(), screen_x_offset(), screen_y_offset(), screen_width(), screen_he "layout(location = 0) out vec4 result;\n" "\n" "void main() {\n" - " result = vec4(0.0); \n" + " result = vec4(0.0);\n" "}\n"; static const char* alpha_layer_vert_shader = @@ -86,12 +86,12 @@ sprite_height(), screen_x_offset(), screen_y_offset(), screen_width(), screen_he glGenSamplers(2, samplers); glSamplerParameteri(samplers[0], GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(samplers[0], GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glSamplerParameteri(samplers[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glSamplerParameteri(samplers[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glSamplerParameteri(samplers[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(samplers[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glSamplerParameteri(samplers[1], GL_TEXTURE_MAG_FILTER, GL_NEAREST); glSamplerParameteri(samplers[1], GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glSamplerParameteri(samplers[1], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glSamplerParameteri(samplers[1], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glSamplerParameteri(samplers[1], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(samplers[1], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); const float_t verts_quad[] = { -1.0f, 1.0f, 0.15f, 0.85f, @@ -192,7 +192,7 @@ void post_process::apply(camera* cam, texture* light_proj_tex, int32_t npr_param blur->tex[0].color_texture->tex, exposure->exposure.color_texture->tex, npr_param); if (mlaa) - aa->apply_mlaa(&rend_texture, &buf_texture, samplers, parent_bone_node); + aa->apply_mlaa(&rend_texture, &buf_texture, samplers, ss_alpha_mask); for (int32_t i = 0; i < 16; i++) { if (!render_textures_data[i]) @@ -223,12 +223,12 @@ void post_process::apply(camera* cam, texture* light_proj_tex, int32_t npr_param if (ssaa) { gl_state_active_bind_texture_2d(0, rend_texture.color_texture->tex); gl_state_bind_sampler(0, samplers[0]); - uniform_value[U01] = parent_bone_node ? 1 : 0; + uniform_value[U_ALPHA_MASK] = ss_alpha_mask ? 1 : 0; uniform_value[U_REDUCE] = 0; shaders_ft.set(SHADER_FT_REDUCE); render_texture::draw_params(&shaders_ft, render_width, render_height, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); - uniform_value[U01] = 0; + uniform_value[U_ALPHA_MASK] = 0; } else { gl_state_active_bind_texture_2d(0, rend_texture.color_texture->tex); @@ -279,19 +279,12 @@ void post_process::ctrl(camera* cam) { reset_exposure = cam->fast_change_hist1 && !cam->fast_change_hist0; if (reset_exposure) { - float_t view_point_dist; - vec3_distance(view_point, view_point_prev, view_point_dist); + float_t view_point_dist = vec3::distance(view_point, view_point_prev); - vec3 dir; - vec3_sub(interest, view_point, dir); - vec3_normalize(dir, dir); + vec3 dir = vec3::normalize(interest - view_point); + vec3 dir_prev = vec3::normalize(interest_prev - view_point_prev); - vec3 dir_prev; - vec3_sub(interest_prev, view_point_prev, dir_prev); - vec3_normalize(dir_prev, dir_prev); - - float_t dir_diff_angle; - vec3_dot(dir, dir_prev, dir_diff_angle); + float_t dir_diff_angle = vec3::dot(dir, dir_prev); if (dir_diff_angle < 0.5f) dir_diff_angle = 0.0f; if (view_point_dist < dir_diff_angle * 0.4f) @@ -310,7 +303,6 @@ void post_process::draw_query_samples(GLuint query, float_t scale, mat4& mat) { gl_state_bind_vertex_array(0); glEndQuery(GL_SAMPLES_PASSED); } - void post_process::init_fbo(int32_t render_width, int32_t render_height, int32_t sprite_width, int32_t sprite_height, int32_t screen_width, int32_t screen_height) { if (this->render_width == render_width && this->render_height == render_height @@ -323,12 +315,12 @@ void post_process::init_fbo(int32_t render_width, int32_t render_height, dof->init_fbo(render_width, render_height); exposure->init_fbo(); tone_map->init_fbo(); - rend_texture.init(render_width, render_height, 0, GL_RGBA16F, GL_DEPTH24_STENCIL8); + rend_texture.init(render_width, render_height, 0, GL_RGBA16F, GL_DEPTH_COMPONENT32F); buf_texture.init(render_width, render_height, 0, GL_RGBA16F, 0); - sss_contour_texture.init(render_width, render_height, 0, GL_RGBA16F, GL_DEPTH24_STENCIL8); + sss_contour_texture.init(render_width, render_height, 0, GL_RGBA16F, GL_DEPTH_COMPONENT32F); pre_texture.init(render_width, render_height, 0, GL_RGBA16F, 0); post_texture.init(render_width, render_height, 0, GL_RGBA16F, 0); - alpha_layer_texture.init(render_width, render_height, 0, GL_RGBA16F, GL_DEPTH24_STENCIL8); + alpha_layer_texture.init(render_width, render_height, 0, GL_RGBA16F, GL_DEPTH_COMPONENT32F); gl_state_bind_texture_2d(rend_texture.depth_texture->tex); GLint swizzle[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle); @@ -347,7 +339,7 @@ void post_process::init_fbo(int32_t render_width, int32_t render_height, if (this->screen_width != screen_width || this->screen_height != screen_height) { fbo_texture.init(screen_width, screen_height, 0, GL_RGBA16F, 0); - screen_texture.init(screen_width, screen_height, 0, GL_R11F_G11F_B10F, 0); + screen_texture.init(screen_width, screen_height, 0, GL_RGBA16F, 0); // Was GL_R11F_G11F_B10F this->screen_width = screen_width; this->screen_height = screen_height; } diff --git a/src/CRE/post_process.hpp b/src/CRE/post_process.hpp index 9e2ab75c..10a76389 100644 --- a/src/CRE/post_process.hpp +++ b/src/CRE/post_process.hpp @@ -27,7 +27,7 @@ enum post_process_mag_filter_type { struct post_process { bool ssaa; bool mlaa; - int32_t parent_bone_node; + int32_t ss_alpha_mask; render_texture rend_texture; render_texture buf_texture; render_texture sss_contour_texture; diff --git a/src/CRE/post_process/aa.cpp b/src/CRE/post_process/aa.cpp index 6c106f3f..09a6eb63 100644 --- a/src/CRE/post_process/aa.cpp +++ b/src/CRE/post_process/aa.cpp @@ -36,12 +36,14 @@ post_process_aa::~post_process_aa() { } void post_process_aa::apply_mlaa(render_texture* rt, - render_texture* buf_rt, GLuint* samplers, int32_t a4) { + render_texture* buf_rt, GLuint* samplers, int32_t ss_alpha_mask) { mlaa_buffer->bind(); gl_state_active_bind_texture_2d(0, rt->color_texture->tex); gl_state_bind_sampler(0, samplers[1]); - uniform_value[U_MLAA] = 0; - shaders_ft.set(SHADER_FT_MLAA); + //uniform_value[U_MLAA] = 0; + //shaders_ft.set(SHADER_FT_MLAA); + uniform_value[U_ALPHA_MASK] = 0; + shaders_ft.set(SHADER_FT_MLAA_EDGE); render_texture::draw_params(&shaders_ft, width, height, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); mlaa_buffer[1].bind(); @@ -49,20 +51,24 @@ void post_process_aa::apply_mlaa(render_texture* rt, gl_state_active_bind_texture_2d(1, mlaa_area_texture); gl_state_bind_sampler(0, samplers[0]); gl_state_bind_sampler(1, samplers[1]); - uniform_value[U20] = 2; - uniform_value[U_MLAA] = 1; - shaders_ft.set(SHADER_FT_MLAA); + //uniform_value[U_MLAA_SEARCH] = 2; + //uniform_value[U_MLAA] = 1; + //shaders_ft.set(SHADER_FT_MLAA); + uniform_value[U_MLAA_SEARCH] = 2; + shaders_ft.set(SHADER_FT_MLAA_AREA); render_texture::draw_params(&shaders_ft, width, height, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); buf_rt->bind(); gl_state_active_bind_texture_2d(0, rt->color_texture->tex); gl_state_active_bind_texture_2d(1, mlaa_buffer[1].color_texture->tex); gl_state_bind_sampler(0, samplers[1]); - uniform_value[U_MLAA] = 2; - uniform_value[U01] = a4 ? 1 : 0; - shaders_ft.set(SHADER_FT_MLAA); + //uniform_value[U_MLAA] = 2; + //uniform_value[U_ALPHA_MASK] = ss_alpha_mask ? 1 : 0; + //shaders_ft.set(SHADER_FT_MLAA); + uniform_value[U_ALPHA_MASK] = ss_alpha_mask ? 1 : 0; + shaders_ft.set(SHADER_FT_MLAA_BLEND); render_texture::draw_params(&shaders_ft, width, height, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); - uniform_value[U01] = 0; + uniform_value[U_ALPHA_MASK] = 0; gl_state_active_bind_texture_2d(0, 0); gl_state_active_bind_texture_2d(1, 0); @@ -75,8 +81,8 @@ void post_process_aa::init_fbo(int32_t width, int32_t height) { if (!this || (this->width == width && this->height == height)) return; - this->width = max(width, 1); - this->height = max(height, 1); + this->width = max_def(width, 1); + this->height = max_def(height, 1); mlaa_buffer[0].init(this->width, this->height, 0, GL_RGBA8, 0); mlaa_buffer[1].init(this->width, this->height, 0, GL_RGBA8, 0); @@ -101,7 +107,7 @@ static void post_process_aa_calculate_area_texture_data_sub(float_t* a2, float_t v8 = 0.0f; float_t v10 = 0.0f; int32_t v11 = a6 + a7 + 1; - v11 = min(v11, 7); + v11 = min_def(v11, 7); int32_t v12; if (((a6 + a7 + 1) & 1) != 0) diff --git a/src/CRE/post_process/aa.hpp b/src/CRE/post_process/aa.hpp index 7d96babb..0c90e819 100644 --- a/src/CRE/post_process/aa.hpp +++ b/src/CRE/post_process/aa.hpp @@ -20,6 +20,6 @@ struct post_process_aa { virtual ~post_process_aa(); void apply_mlaa(render_texture* rt, - render_texture* buf_rt, GLuint* samplers, int32_t a4); + render_texture* buf_rt, GLuint* samplers, int32_t ss_alpha_mask); void init_fbo(int32_t width, int32_t height); }; diff --git a/src/CRE/post_process/blur.cpp b/src/CRE/post_process/blur.cpp index 09a8e472..c86e74da 100644 --- a/src/CRE/post_process/blur.cpp +++ b/src/CRE/post_process/blur.cpp @@ -29,13 +29,13 @@ post_process_blur:: ~post_process_blur() { for (int32_t i = 0; i < count_down; i++) tex_down[i].free_data(); - free(tex_down); - free(height_down); - free(width_down); + free_def(tex_down); + free_def(height_down); + free_def(width_down); } void post_process_blur::get_blur(render_texture* rt) { - uniform_value[U01] = 0; + uniform_value[U_ALPHA_MASK] = 0; int32_t i = 0; if (count_down > 0) { @@ -110,7 +110,7 @@ void post_process_blur::get_blur(render_texture* rt) { vec3 v[POST_PROCESS_BLUR_GAUSSIAN_KERNEL_SIZE]; for (int32_t i = 0; i < POST_PROCESS_BLUR_GAUSSIAN_KERNEL_SIZE; i++) - vec3_mult(gauss[i], intensity, v[i]); + v[i] = gauss[i] * intensity; uniform_value[U_GAUSS] = 0; render_texture::shader_set(&shaders_ft, SHADER_FT_GAUSS); @@ -205,7 +205,7 @@ void post_process_blur::init_fbo(int32_t width, int32_t height) { else if (count_down < i) { render_texture* temp = force_malloc_s(render_texture, i); memcpy(temp, tex_down, sizeof(render_texture) * count_down); - free(tex_down); + free_def(tex_down); tex_down = temp; } @@ -214,7 +214,7 @@ void post_process_blur::init_fbo(int32_t width, int32_t height) { else if (count_down < i) { int32_t* temp = force_malloc_s(int32_t, i); memcpy(temp, width_down, sizeof(int32_t) * count_down); - free(width_down); + free_def(width_down); width_down = temp; } @@ -223,7 +223,7 @@ void post_process_blur::init_fbo(int32_t width, int32_t height) { else if (count_down < i) { int32_t* temp = force_malloc_s(int32_t, i); memcpy(temp, height_down, sizeof(int32_t) * count_down); - free(height_down); + free_def(height_down); height_down = temp; } @@ -249,12 +249,12 @@ void post_process_blur::init_fbo(int32_t width, int32_t height) { } void post_process_blur::initialize_data(const vec3& radius, const vec3& intensity) { - data.radius.x = clamp(radius.x, 1.0f, 3.0f); - data.radius.y = clamp(radius.y, 1.0f, 3.0f); - data.radius.z = clamp(radius.z, 1.0f, 3.0f); - data.intensity.x = clamp(intensity.x, 0.0f, 2.0f); - data.intensity.y = clamp(intensity.y, 0.0f, 2.0f); - data.intensity.z = clamp(intensity.z, 0.0f, 2.0f); + data.radius.x = clamp_def(radius.x, 1.0f, 3.0f); + data.radius.y = clamp_def(radius.y, 1.0f, 3.0f); + data.radius.z = clamp_def(radius.z, 1.0f, 3.0f); + data.intensity.x = clamp_def(intensity.x, 0.0f, 2.0f); + data.intensity.y = clamp_def(intensity.y, 0.0f, 2.0f); + data.intensity.z = clamp_def(intensity.z, 0.0f, 2.0f); post_process_blur_radius_calculate(this); } @@ -263,9 +263,9 @@ vec3 post_process_blur::get_intensity() { } void post_process_blur::set_intensity(const vec3& value) { - data.intensity.x = clamp(value.x, 0.0f, 2.0f); - data.intensity.y = clamp(value.y, 0.0f, 2.0f); - data.intensity.z = clamp(value.z, 0.0f, 2.0f); + data.intensity.x = clamp_def(value.x, 0.0f, 2.0f); + data.intensity.y = clamp_def(value.y, 0.0f, 2.0f); + data.intensity.z = clamp_def(value.z, 0.0f, 2.0f); } vec3 post_process_blur::get_radius() { @@ -274,9 +274,9 @@ vec3 post_process_blur::get_radius() { void post_process_blur::set_radius(const vec3& value) { vec3 temp; - temp.x = clamp(value.x, 1.0f, 3.0f); - temp.y = clamp(value.y, 1.0f, 3.0f); - temp.z = clamp(value.z, 1.0f, 3.0f); + temp.x = clamp_def(value.x, 1.0f, 3.0f); + temp.y = clamp_def(value.y, 1.0f, 3.0f); + temp.z = clamp_def(value.z, 1.0f, 3.0f); if (memcmp(&temp, &data.radius, sizeof(vec3))) { data.radius = temp; post_process_blur_radius_calculate(this); diff --git a/src/CRE/post_process/dof.cpp b/src/CRE/post_process/dof.cpp index fae07c29..d3ed1aba 100644 --- a/src/CRE/post_process/dof.cpp +++ b/src/CRE/post_process/dof.cpp @@ -566,8 +566,14 @@ static const char* dof_frag_shader_upsample = " is thinly combined with the actual resolution because it's not good\n" " combined_factor = clamp(combined_factor, 0.0, 1.0);\n" "#endif\n" +"#if 1\n" +" // Fix alpha\n" +" result.rgb = max(tone_map(mix(half_res.rgb, full_res.rgb, combined_factor), 1.0), vec3(0.0));\n" +" result.a = full_res.a;\n" +"#else\n" " result = mix(half_res, full_res, combined_factor);\n" " result.rgb = max(tone_map(result.rgb, 1.0), vec3(0.0));\n" +"#endif\n" "}\n"; static const dof_debug dof_debug_default = { @@ -668,20 +674,20 @@ void post_process_dof::apply(render_texture* rt, GLuint* samplers, camera* cam) mat4 view_transpose; mat4_transpose(&cam->view, &view_transpose); - vec3_dot(*(vec3*)&view_transpose.row2, chara_trans, focus); - focus = -focus - view_transpose.row2.w - 0.1f; + focus = -vec3::dot(*(vec3*)&view_transpose.row2, chara_trans) + - view_transpose.row2.w - 0.1f; break; } } - focus = max(focus, (float_t)cam->min_distance); + focus = max_def(focus, (float_t)cam->min_distance); renderer::DOF3::apply_physical(this, rt, samplers, rt->color_texture->tex, rt->depth_texture->tex, (float_t)cam->min_distance, (float_t)cam->max_distance, focus, data.debug.focal_length, (float_t)cam->fov_rad, data.debug.f_number); } else { - float_t fuzzing_range = max(data.debug.f2.fuzzing_range, 0.01f); + float_t fuzzing_range = max_def(data.debug.f2.fuzzing_range, 0.01f); renderer::DOF3::apply_f2(this, rt, samplers, rt->color_texture->tex, rt->depth_texture->tex, (float_t)cam->min_distance, (float_t)cam->max_distance, (float_t)cam->fov_rad, @@ -691,7 +697,7 @@ void post_process_dof::apply(render_texture* rt, GLuint* samplers, camera* cam) } } else if (data.pv.enable && data.pv.f2.ratio > 0.0f) { - float_t fuzzing_range = max(data.pv.f2.fuzzing_range, 0.01f); + float_t fuzzing_range = max_def(data.pv.f2.fuzzing_range, 0.01f); renderer::DOF3::apply_f2(this, rt, samplers, rt->color_texture->tex, rt->depth_texture->tex, (float_t)cam->min_distance, (float_t)cam->max_distance, (float_t)cam->fov_rad, @@ -725,10 +731,10 @@ void post_process_dof::init_fbo(int32_t width, int32_t height) { this->width = width; this->height = height; - int32_t w20 = max(width / 20, 1); - int32_t h20 = max(height / 20, 1); - int32_t w2 = max(width / 2, 1); - int32_t h2 = max(height / 2, 1); + int32_t w20 = max_def(width / 20, 1); + int32_t h20 = max_def(height / 20, 1); + int32_t w2 = max_def(width / 2, 1); + int32_t h2 = max_def(height / 2, 1); glGenTextures(6, textures); gl_state_bind_texture_2d(textures[0]); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RG16F, w20, h20); @@ -828,10 +834,7 @@ static void post_process_dof_calculate_texcoords(vec2* data, float_t size) { v8 *= size; v11 = v9 * (float_t)(M_PI * 0.25); - vec2 t; - t.x = cosf(v11); - t.y = sinf(v11); - vec2_mult_scalar(t, v8, *data++); + *data++ = vec2(cosf(v11), sinf(v11)) * v8; } } } @@ -865,27 +868,27 @@ static void post_process_dof_load_shaders(post_process_dof* dof) { t0 = str_utils_copy(dof_frag_shader_version); t1 = str_utils_add(t0, shared); frag_shader_string[1 + i * 4] = str_utils_add(t1, dof_frag_shader_render_tiles_part_1); - free(t0); - free(t1); + free_def(t0); + free_def(t1); t0 = str_utils_copy(dof_frag_shader_version); t1 = str_utils_add(t0, shared); frag_shader_string[2 + i * 4] = str_utils_add(t1, dof_frag_shader_downsample); - free(t0); - free(t1); + free_def(t0); + free_def(t1); t0 = str_utils_copy(dof_frag_shader_version); t1 = str_utils_add(t0, shared); frag_shader_string[3 + i * 4] = str_utils_add(t1, dof_frag_shader_apply_main_filter); - free(t0); - free(t1); + free_def(t0); + free_def(t1); t0 = str_utils_copy(dof_frag_shader_version); t1 = str_utils_add(t0, shared); frag_shader_string[4 + i * 4] = str_utils_add(t1, dof_frag_shader_upsample); - free(t0); - free(t1); - free(shared); + free_def(t0); + free_def(t1); + free_def(shared); } GLuint vert_shader = post_process_dof_shader_compile(GL_VERTEX_SHADER, dof_vert_shader); @@ -893,7 +896,7 @@ static void post_process_dof_load_shaders(post_process_dof* dof) { GLuint frag_shader = post_process_dof_shader_compile(GL_FRAGMENT_SHADER, frag_shader_string[i]); dof->program[i] = post_process_dof_program_link(vert_shader, frag_shader); glDeleteShader(frag_shader); - free(frag_shader_string[i]); + free_def(frag_shader_string[i]); } glDeleteShader(vert_shader); } @@ -911,10 +914,10 @@ static GLuint post_process_dof_shader_compile(GLenum type, const char* data) { if (!success) { GLchar* info_log = force_malloc_s(GLchar, 0x10000); glGetShaderInfoLog(shader, 0x10000, 0, info_log); - printf("Shader compile error: "); + printf("DOF Shader compile error: "); printf(info_log); putchar('\n'); - free(info_log); + free_def(info_log); } return shader; } @@ -932,10 +935,10 @@ static GLuint post_process_dof_program_link(GLuint vert_shad, GLuint frag_shad) if (!success) { GLchar* info_log = force_malloc_s(GLchar, 0x10000); glGetProgramInfoLog(program, 0x10000, 0, info_log); - printf("DOF Program Shader linking error:\n"); + printf("DOF shader linking error:\n"); printf(info_log); putchar('\n'); - free(info_log); + free_def(info_log); glDeleteProgram(program); return 0; } diff --git a/src/CRE/post_process/exposure.cpp b/src/CRE/post_process/exposure.cpp index 274deabe..c5ac1e41 100644 --- a/src/CRE/post_process/exposure.cpp +++ b/src/CRE/post_process/exposure.cpp @@ -12,15 +12,14 @@ static void sub_1405163C0(rob_chara* rob_chr, int32_t a2, mat4* mat); +post_process_exposure_chara_data::post_process_exposure_chara_data() : field_80(), query(), query_data() { + for (GLuint& i : query_data) + i = -1; +} + post_process_exposure::post_process_exposure() : exposure_history_counter(), chara_data(), query_index() { chara_data = new post_process_exposure_chara_data[ROB_CHARA_COUNT]; - for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) { - memset(&chara_data[i], 0, sizeof(post_process_exposure_chara_data)); - chara_data[i].query_data[0] = -1; - chara_data[i].query_data[1] = -1; - chara_data[i].query_data[2] = -1; - } } post_process_exposure::~post_process_exposure() { diff --git a/src/CRE/post_process/exposure.hpp b/src/CRE/post_process/exposure.hpp index c2df9111..136962ed 100644 --- a/src/CRE/post_process/exposure.hpp +++ b/src/CRE/post_process/exposure.hpp @@ -16,6 +16,8 @@ struct post_process_exposure_chara_data { float_t field_80; GLuint query[3]; GLuint query_data[3]; + + post_process_exposure_chara_data(); }; struct post_process_exposure { diff --git a/src/CRE/post_process/tone_map.cpp b/src/CRE/post_process/tone_map.cpp index c2eafb59..f88d937c 100644 --- a/src/CRE/post_process/tone_map.cpp +++ b/src/CRE/post_process/tone_map.cpp @@ -12,7 +12,13 @@ static void post_process_tone_map_calculate_data(post_process_tone_map* tm); static void post_process_tone_map_calculate_tex(post_process_tone_map* tm); -post_process_tone_map::post_process_tone_map() : data(), shader_data(), tone_map() { +post_process_tone_map_data::post_process_tone_map_data() : tex(), exposure(), auto_exposure(), gamma(), +gamma_rate(), saturate_power(), saturate_coeff(), scene_fade_blend_func(), tone_map_method(), lens_flare(), +lens_shaft(), lens_ghost(), lens_flare_power(), lens_flare_appear_power(), update(), update_tex() { + +} + +post_process_tone_map::post_process_tone_map() : shader_data(), tone_map() { } @@ -130,24 +136,24 @@ void post_process_tone_map::initialize_data(float_t exposure, bool auto_exposure float_t gamma, float_t gamma_rate, int32_t saturate_power, float_t saturate_coeff, const vec3& scene_fade_color, float_t scene_fade_alpha, int32_t scene_fade_blend_func, const vec3& tone_trans_start, const vec3& tone_trans_end, tone_map_method tone_map_method) { - data.exposure = clamp(exposure, 0.0f, 4.0f); + data.exposure = clamp_def(exposure, 0.0f, 4.0f); data.auto_exposure = auto_exposure; - data.gamma = clamp(gamma, 0.2f, 2.2f); - data.gamma_rate = clamp(gamma_rate, 0.5f, 2.0f); - data.saturate_power = clamp(saturate_power, 1, 6); - data.saturate_coeff = clamp(saturate_coeff, 0.0f, 1.0f); - data.scene_fade.x = clamp(scene_fade_color.x, 0.0f, 1.0f); - data.scene_fade.y = clamp(scene_fade_color.y, 0.0f, 1.0f); - data.scene_fade.z = clamp(scene_fade_color.z, 0.0f, 1.0f); - data.scene_fade.w = clamp(scene_fade_alpha, 0.0f, 1.0f); - data.scene_fade_blend_func = clamp(scene_fade_blend_func, 0, 2); - data.tone_trans_start.x = clamp(tone_trans_start.x, 0.0f, 1.0f); - data.tone_trans_start.y = clamp(tone_trans_start.y, 0.0f, 1.0f); - data.tone_trans_start.z = clamp(tone_trans_start.z, 0.0f, 1.0f); - data.tone_trans_end.x = clamp(tone_trans_end.x, 0.0f, 1.0f); - data.tone_trans_end.y = clamp(tone_trans_end.y, 0.0f, 1.0f); - data.tone_trans_end.z = clamp(tone_trans_end.z, 0.0f, 1.0f); - data.tone_map_method = clamp(tone_map_method, TONE_MAP_YCC_EXPONENT, TONE_MAP_RGB_LINEAR2); + data.gamma = clamp_def(gamma, 0.2f, 2.2f); + data.gamma_rate = clamp_def(gamma_rate, 0.5f, 2.0f); + data.saturate_power = clamp_def(saturate_power, 1, 6); + data.saturate_coeff = clamp_def(saturate_coeff, 0.0f, 1.0f); + data.scene_fade.x = clamp_def(scene_fade_color.x, 0.0f, 1.0f); + data.scene_fade.y = clamp_def(scene_fade_color.y, 0.0f, 1.0f); + data.scene_fade.z = clamp_def(scene_fade_color.z, 0.0f, 1.0f); + data.scene_fade.w = clamp_def(scene_fade_alpha, 0.0f, 1.0f); + data.scene_fade_blend_func = clamp_def(scene_fade_blend_func, 0, 2); + data.tone_trans_start.x = clamp_def(tone_trans_start.x, 0.0f, 1.0f); + data.tone_trans_start.y = clamp_def(tone_trans_start.y, 0.0f, 1.0f); + data.tone_trans_start.z = clamp_def(tone_trans_start.z, 0.0f, 1.0f); + data.tone_trans_end.x = clamp_def(tone_trans_end.x, 0.0f, 1.0f); + data.tone_trans_end.y = clamp_def(tone_trans_end.y, 0.0f, 1.0f); + data.tone_trans_end.z = clamp_def(tone_trans_end.z, 0.0f, 1.0f); + data.tone_map_method = clamp_def(tone_map_method, TONE_MAP_YCC_EXPONENT, TONE_MAP_RGB_LINEAR2); data.update_tex = false; data.update = true; data.update_tex = true; @@ -170,7 +176,7 @@ float_t post_process_tone_map::get_exposure() { } void post_process_tone_map::set_exposure(float_t value) { - value = clamp(value, 0.0f, 4.0f); + value = clamp_def(value, 0.0f, 4.0f); if (value != data.exposure) { data.exposure = value; data.update = true; @@ -183,7 +189,7 @@ float_t post_process_tone_map::get_gamma() { } void post_process_tone_map::set_gamma(float_t value) { - value = clamp(value, 0.2f, 2.2f); + value = clamp_def(value, 0.2f, 2.2f); if (value != data.gamma) { data.gamma = value; data.update = true; @@ -196,7 +202,7 @@ float_t post_process_tone_map::get_gamma_rate() { } void post_process_tone_map::set_gamma_rate(float_t value) { - value = clamp(value, 0.5f, 2.0f); + value = clamp_def(value, 0.5f, 2.0f); if (value != data.gamma_rate) { data.gamma_rate = value; data.update_tex = true; @@ -208,7 +214,7 @@ float_t post_process_tone_map::get_lens_flare() { } void post_process_tone_map::set_lens_flare(float_t value) { - value = clamp(value, 0.0f, 1.0f); + value = clamp_def(value, 0.0f, 1.0f); if (value != data.lens_flare) { data.lens_flare = value; data.update = true; @@ -220,7 +226,7 @@ float_t post_process_tone_map::get_lens_ghost() { } void post_process_tone_map::set_lens_ghost(float_t value) { - data.lens_ghost = clamp(value, 0.0f, 1.0f); + data.lens_ghost = clamp_def(value, 0.0f, 1.0f); } float_t post_process_tone_map::get_lens_shaft() { @@ -228,7 +234,7 @@ float_t post_process_tone_map::get_lens_shaft() { } void post_process_tone_map::set_lens_shaft(float_t value) { - value = clamp(value, 0.0f, 1.0f); + value = clamp_def(value, 0.0f, 1.0f); if (value != data.lens_shaft) { data.lens_shaft = value; data.update = true; @@ -240,7 +246,7 @@ float_t post_process_tone_map::get_saturate_coeff() { } void post_process_tone_map::set_saturate_coeff(float_t value) { - value = clamp(value, 0.0f, 1.0f); + value = clamp_def(value, 0.0f, 1.0f); if (value != data.saturate_coeff) { data.saturate_coeff = value; data.update_tex = true; @@ -252,7 +258,7 @@ int32_t post_process_tone_map::get_saturate_power() { } void post_process_tone_map::set_saturate_power(int32_t value) { - value = clamp(value, 1, 6); + value = clamp_def(value, 1, 6); if (value != data.saturate_power) { data.saturate_power = value; data.update_tex = true; @@ -265,10 +271,10 @@ vec4 post_process_tone_map::get_scene_fade() { void post_process_tone_map::set_scene_fade(const vec4& value) { vec4 temp; - temp.x = clamp(value.x, 0.0f, 1.0f); - temp.y = clamp(value.y, 0.0f, 1.0f); - temp.z = clamp(value.z, 0.0f, 1.0f); - temp.z = clamp(value.w, 0.0f, 1.0f); + temp.x = clamp_def(value.x, 0.0f, 1.0f); + temp.y = clamp_def(value.y, 0.0f, 1.0f); + temp.z = clamp_def(value.z, 0.0f, 1.0f); + temp.z = clamp_def(value.w, 0.0f, 1.0f); if (memcmp(&temp, &data.scene_fade, sizeof(vec4))) { data.scene_fade = temp; data.update = true; @@ -280,7 +286,7 @@ float_t post_process_tone_map::get_scene_fade_alpha() { } void post_process_tone_map::set_scene_fade_alpha(float_t value) { - value = clamp(value, 0.0f, 1.0f); + value = clamp_def(value, 0.0f, 1.0f); if (value != data.scene_fade.w) { data.scene_fade.w = value; data.update = true; @@ -292,7 +298,7 @@ int32_t post_process_tone_map::get_scene_fade_blend_func() { } void post_process_tone_map::set_scene_fade_blend_func(int32_t value) { - value = clamp(value, 0, 2); + value = clamp_def(value, 0, 2); if (value != data.scene_fade_blend_func) { data.scene_fade_blend_func = value; data.update = true; @@ -305,9 +311,9 @@ vec3 post_process_tone_map::get_scene_fade_color() { void post_process_tone_map::set_scene_fade_color(const vec3& value) { vec3 temp; - temp.x = clamp(value.x, 0.0f, 1.0f); - temp.y = clamp(value.y, 0.0f, 1.0f); - temp.z = clamp(value.z, 0.0f, 1.0f); + temp.x = clamp_def(value.x, 0.0f, 1.0f); + temp.y = clamp_def(value.y, 0.0f, 1.0f); + temp.z = clamp_def(value.z, 0.0f, 1.0f); if (memcmp(&temp, &data.scene_fade, sizeof(vec3))) { *(vec3*)&data.scene_fade = temp; data.update = true; @@ -319,7 +325,7 @@ tone_map_method post_process_tone_map::get_tone_map_method() { } void post_process_tone_map::set_tone_map_method(tone_map_method value) { - value = clamp(value, TONE_MAP_YCC_EXPONENT, TONE_MAP_RGB_LINEAR2); + value = clamp_def(value, TONE_MAP_YCC_EXPONENT, TONE_MAP_RGB_LINEAR2); if (value != data.tone_map_method) { data.tone_map_method = value; data.update = true; @@ -342,9 +348,9 @@ vec3 post_process_tone_map::get_tone_trans_end() { void post_process_tone_map::set_tone_trans_end(const vec3& value) { vec3 temp; - temp.x = clamp(value.x, 0.0f, 1.0f); - temp.y = clamp(value.y, 0.0f, 1.0f); - temp.z = clamp(value.z, 0.0f, 1.0f); + temp.x = clamp_def(value.x, 0.0f, 1.0f); + temp.y = clamp_def(value.y, 0.0f, 1.0f); + temp.z = clamp_def(value.z, 0.0f, 1.0f); if (memcmp(&temp, &data.tone_trans_end, sizeof(vec3))) { data.tone_trans_end = temp; data.update = true; @@ -357,9 +363,9 @@ vec3 post_process_tone_map::get_tone_trans_start() { void post_process_tone_map::set_tone_trans_start(const vec3& value) { vec3 temp; - temp.x = clamp(value.x, 0.0f, 1.0f); - temp.y = clamp(value.y, 0.0f, 1.0f); - temp.z = clamp(value.z, 0.0f, 1.0f); + temp.x = clamp_def(value.x, 0.0f, 1.0f); + temp.y = clamp_def(value.y, 0.0f, 1.0f); + temp.z = clamp_def(value.z, 0.0f, 1.0f); if (memcmp(&temp, &data.tone_trans_start, sizeof(vec3))) { data.tone_trans_start = temp; data.update = true; @@ -367,11 +373,8 @@ void post_process_tone_map::set_tone_trans_start(const vec3& value) { } static void post_process_tone_map_calculate_data(post_process_tone_map* tm) { - vec3 tone_trans, tone_trans_scale, tone_trans_offset; - vec3_sub(tm->data.tone_trans_end, tm->data.tone_trans_start, tone_trans); - vec3_rcp(tone_trans, tone_trans_scale); - vec3_mult(tone_trans_scale, tm->data.tone_trans_start, tone_trans_offset); - vec3_negate(tone_trans_offset, tone_trans_offset); + vec3 tone_trans_scale = vec3::rcp(tm->data.tone_trans_end - tm->data.tone_trans_start); + vec3 tone_trans_offset = -(tone_trans_scale * tm->data.tone_trans_start); post_process_tone_map_shader_data* v = &tm->shader_data; v->p_exposure.x = tm->data.exposure; @@ -385,7 +388,7 @@ static void post_process_tone_map_calculate_data(post_process_tone_map* tm) { v->p_flare_coef.w = 0.0f; v->p_fade_color = tm->data.scene_fade; if (tm->data.scene_fade_blend_func == 1 || tm->data.scene_fade_blend_func == 2) - vec3_mult_scalar(*(vec3*)&v->p_fade_color, v->p_fade_color.w, *(vec3*)&v->p_fade_color); + *(vec3*)&v->p_fade_color = *(vec3*)&v->p_fade_color * v->p_fade_color.w; v->p_tone_scale.x = tone_trans_scale.x; v->p_tone_scale.y = tone_trans_scale.y; v->p_tone_scale.z = tone_trans_scale.z; diff --git a/src/CRE/post_process/tone_map.hpp b/src/CRE/post_process/tone_map.hpp index 9c7488ad..79b90dc9 100644 --- a/src/CRE/post_process/tone_map.hpp +++ b/src/CRE/post_process/tone_map.hpp @@ -43,6 +43,8 @@ struct post_process_tone_map_data { float_t lens_flare_appear_power; bool update; bool update_tex; + + post_process_tone_map_data(); }; struct post_process_tone_map { diff --git a/src/CRE/pv_db.cpp b/src/CRE/pv_db.cpp index dc75cb71..f9da3635 100644 --- a/src/CRE/pv_db.cpp +++ b/src/CRE/pv_db.cpp @@ -775,7 +775,7 @@ namespace pv_db { if (!kv.has_key(buf) || !kv.open_scope(buf)) return false; - size_t base_scope_index = kv.curr_scope - kv.scope.data();; + size_t base_scope_index = kv.curr_scope - kv.scope.data(); std::string song_name; if (!kv.read("song_name", song_name)) { @@ -1777,7 +1777,7 @@ namespace pv_db { if (!kv.open_scope_fmt("%02d", k)) continue; - pv_db_pv_field field;; + pv_db_pv_field field; const char* stage; if (kv.read("stage", stage)) diff --git a/src/CRE/pv_expression.cpp b/src/CRE/pv_expression.cpp index 8905321c..2a84ec9a 100644 --- a/src/CRE/pv_expression.cpp +++ b/src/CRE/pv_expression.cpp @@ -37,7 +37,7 @@ struct pv_expression { bool set_motion(uint32_t, int32_t motion_id); }; -pv_expression pv_expression_array[6]; +pv_expression pv_expression_array[ROB_CHARA_COUNT]; extern render_context* rctx_ptr; @@ -178,6 +178,7 @@ void pv_expression_file_unload(const char* file) { i->file_handler.free_data(); } + delete i; pv_expression_file_storage.erase(pv_expression_file_storage.begin() + (&i - pv_expression_file_storage.data())); diff --git a/src/CRE/pv_param.cpp b/src/CRE/pv_param.cpp index 163ef593..14e4a67d 100644 --- a/src/CRE/pv_param.cpp +++ b/src/CRE/pv_param.cpp @@ -6,6 +6,7 @@ #include "pv_param.hpp" #include "post_process.hpp" #include "render_context.hpp" +#include "../KKdLib/io/file_stream.hpp" #include "../KKdLib/str_utils.hpp" extern render_context* rctx_ptr; @@ -100,13 +101,13 @@ namespace pv_param { char* buf; char** lines; size_t count; - if (!str_utils_text_file_parse(data.c_str(), data.size(), &buf, &lines, &count)) + if (!str_utils_text_file_parse(data.c_str(), data.size(), buf, lines, count)) return false; if (count <= 1 || str_utils_compare(lines[0], "ID,ColorR,ColorG,ColorB,BrightpassR,BrightpassG,BrightpassB,Range")) { - free(buf); - free(lines); + free_def(buf); + free_def(lines); return false; } @@ -128,8 +129,8 @@ namespace pv_param { lines--; - free(buf); - free(lines); + free_def(buf); + free_def(lines); return true; } @@ -141,13 +142,13 @@ namespace pv_param { char* buf; char** lines; size_t count; - if (!str_utils_text_file_parse(data.c_str(), data.size(), &buf, &lines, &count)) + if (!str_utils_text_file_parse(data.c_str(), data.size(), buf, lines, count)) return false; if (count <= 1 || str_utils_compare(lines[0], "ID,Hue,Saturation,Lightness,Exposure,GammaR,GammaG,GammaB,Contrast")) { - free(buf); - free(lines); + free_def(buf); + free_def(lines); return false; } @@ -169,8 +170,8 @@ namespace pv_param { lines--; - free(buf); - free(lines); + free_def(buf); + free_def(lines); return true; } @@ -182,13 +183,13 @@ namespace pv_param { char* buf; char** lines; size_t count; - if (!str_utils_text_file_parse(data.c_str(), data.size(), &buf, &lines, &count)) + if (!str_utils_text_file_parse(data.c_str(), data.size(), buf, lines, count)) return false; if (count <= 1 || str_utils_compare(lines[0], "ID,Focus,FocusRange,FuzzingRange,Ratio,Quality")) { - free(buf); - free(lines); + free_def(buf); + free_def(lines); return false; } @@ -210,8 +211,8 @@ namespace pv_param { lines--; - free(buf); - free(lines); + free_def(buf); + free_def(lines); return true; } @@ -410,14 +411,14 @@ namespace pv_param { } static bool load_text_file(void* data, const char* path, const char* file, uint32_t hash) { - stream s; + file_stream s; s.open((std::string(path) + file).c_str(), "rb"); - if (!s.io.stream) - return false; - - *(std::string*)data = s.read_string(s.length); - s.close(); - return true; + if (s.check_not_null()) { + *(std::string*)data = s.read_string(s.length); + s.close(); + return true; + } + return false; } } @@ -459,7 +460,7 @@ namespace pv_param_task { else if (duration < 0.0f) value = data.data_prev.color; else - vec3_lerp_scalar(data.data_prev.color, data.data.color, value, frame / duration); + value = vec3::lerp(data.data_prev.color, data.data.color, frame / duration); rctx_ptr->post_process.blur->set_intensity(value); @@ -509,10 +510,10 @@ namespace pv_param_task { } else { float_t t = frame / duration; - saturation = lerp(data.data_prev.saturation, data.data.saturation, t); - exposure = lerp(data.data_prev.exposure, data.data.exposure, t); - vec3_lerp_scalar(data.data_prev.gamma, data.data.gamma, gamma, t); - contrast = lerp(data.data_prev.contrast, data.data.contrast, t); + saturation = lerp_def(data.data_prev.saturation, data.data.saturation, t); + exposure = lerp_def(data.data_prev.exposure, data.data.exposure, t); + gamma = vec3::lerp(data.data_prev.gamma, data.data.gamma, t); + contrast = lerp_def(data.data_prev.contrast, data.data.contrast, t); } post_process_tone_map* tone_map = rctx_ptr->post_process.tone_map; @@ -536,7 +537,7 @@ namespace pv_param_task { } void PostProcessCtrlCC::CalcToneTrans(float_t value, float_t& tone_trans_start, float_t& tone_trans_end) { - float_t pow = max(value, 0.125f) * 0.5f; + float_t pow = max_def(value, 0.125f) * 0.5f; if (fabsf(value - 2.0f) < 0.000001f) { tone_trans_start = 0.0f; tone_trans_end = 1.0f; @@ -582,7 +583,7 @@ namespace pv_param_task { else if (i.duration <= 0.0) value = i.prev_alpha; else - value = lerp(i.prev_alpha, i.alpha, i.frame / i.duration); + value = lerp_def(i.prev_alpha, i.alpha, i.frame / i.duration); draw_task_flags draw_task_flags; switch (i.type) { @@ -642,7 +643,7 @@ namespace pv_param_task { else if (i.duration <= 0.0) value = i.prev_alpha; else - value = lerp(i.prev_alpha, i.alpha, i.frame / i.duration); + value = lerp_def(i.prev_alpha, i.alpha, i.frame / i.duration); if (callback) callback[index](callback_data[index], index, i.type, value); @@ -707,7 +708,7 @@ namespace pv_param_task { cam->get_view_point(view_point); float_t fov = (float_t)cam->get_fov(); - vec3_distance(trans, view_point, focus); + focus = vec3::distance(trans, view_point); float_t v5 = tanf(fov * DEG_TO_RAD_FLOAT * 0.5f); float_t v6 = focus * 1000.0f; @@ -773,10 +774,10 @@ namespace pv_param_task { } else { float_t t = frame / duration; - focus = lerp(data.data_prev.focus, data.data.focus, t); - focus_range = lerp(data.data_prev.focus_range, data.data.focus_range, t); - fuzzing_range = lerp(data.data_prev.fuzzing_range, data.data.fuzzing_range, t); - ratio = lerp(data.data_prev.ratio, data.data.ratio, t); + focus = lerp_def(data.data_prev.focus, data.data.focus, t); + focus_range = lerp_def(data.data_prev.focus_range, data.data.focus_range, t); + fuzzing_range = lerp_def(data.data_prev.fuzzing_range, data.data.fuzzing_range, t); + ratio = lerp_def(data.data_prev.ratio, data.data.ratio, t); } #if DOF_FIX diff --git a/src/CRE/random.cpp b/src/CRE/random.cpp index fd26cc80..6375aedc 100644 --- a/src/CRE/random.cpp +++ b/src/CRE/random.cpp @@ -15,17 +15,17 @@ RandState::~RandState() { } -inline void rand_state_array_init() { +void rand_state_array_init() { rand_state_array = new RandState[5]; } -inline RandState* rand_state_array_get(int32_t id) { +RandState* rand_state_array_get(int32_t id) { if (id > -1 && id < 5) return &rand_state_array[id]; return 0; } -inline float_t rand_state_array_get_float(int32_t id) { +float_t rand_state_array_get_float(int32_t id) { RandState* rand_state = rand_state_array_get(id); if (rand_state) { std::uniform_int_distribution dis; @@ -34,7 +34,7 @@ inline float_t rand_state_array_get_float(int32_t id) { return 0.0f; } -inline uint32_t rand_state_array_get_int(int32_t id) { +uint32_t rand_state_array_get_int(int32_t id) { RandState* rand_state = rand_state_array_get(id); if (rand_state) { std::uniform_int_distribution dis; @@ -43,7 +43,7 @@ inline uint32_t rand_state_array_get_int(int32_t id) { return 0; } -inline uint32_t rand_state_array_get_int(uint32_t min, uint32_t max, int32_t id) { +uint32_t rand_state_array_get_int(uint32_t min, uint32_t max, int32_t id) { uint64_t _min = min; uint64_t _max = max; RandState* rand_state = rand_state_array_get(id); @@ -54,6 +54,6 @@ inline uint32_t rand_state_array_get_int(uint32_t min, uint32_t max, int32_t id) return 0; } -inline void rand_state_array_free() { +void rand_state_array_free() { delete[] rand_state_array; } diff --git a/src/CRE/render_context.cpp b/src/CRE/render_context.cpp index 88ecb20b..347f3a1d 100644 --- a/src/CRE/render_context.cpp +++ b/src/CRE/render_context.cpp @@ -10,6 +10,7 @@ #include "draw_task.hpp" #include "file_handler.hpp" #include "shader_ft.hpp" +#include "sound.hpp" #include "stage.hpp" float_t delta_frame_history = 0; @@ -24,7 +25,7 @@ sss_data::sss_data() : init(), enable(), npr_contour(), param() { npr_contour = true; param = { 0.0f, 0.0f, 0.0f, 1.0f }; - textures[0].init(640, 360, 0, GL_RGBA16F, GL_DEPTH24_STENCIL8); + textures[0].init(640, 360, 0, GL_RGBA16F, GL_DEPTH_COMPONENT32F); textures[1].init(320, 180, 0, GL_RGBA16F, GL_ZERO); textures[2].init(320, 180, 0, GL_RGBA16F, GL_ZERO); textures[3].init(320, 180, 0, GL_RGBA16F, GL_ZERO); @@ -46,8 +47,8 @@ field_2F8(), sss_texture(), npr_param(), field_31C(), field_31D(), field_31E(), alpha_z_sort = true; for (bool& i : draw_pass_3d) i = true; - reflect_texture.init(512, 256, 0, GL_RGBA16F, GL_DEPTH24_STENCIL8); - refract_texture.init(512, 256, 0, GL_RGBA8, GL_DEPTH24_STENCIL8); + reflect_texture.init(512, 256, 0, GL_RGBA16F, GL_DEPTH_COMPONENT32F); + refract_texture.init(512, 256, 0, GL_RGBA8, GL_DEPTH_COMPONENT32F); shadow_ptr = new ::shadow; if (shadow_ptr) shadow_ptr->init_data(); @@ -99,9 +100,9 @@ texture_transform_struct::texture_transform_struct(uint32_t id, mat4& mat) : id( } light_proj::light_proj(int32_t width, int32_t height) : enable(), texture_id() { - shadow_texture[0].init(2048, 512, 0, GL_R32F, GL_DEPTH24_STENCIL8); + shadow_texture[0].init(2048, 512, 0, GL_R32F, GL_DEPTH_COMPONENT32F); shadow_texture[1].init(2048, 512, 0, GL_R32F, GL_ZERO); - draw_texture.init(width, height, 0, GL_RGBA8, GL_DEPTH24_STENCIL8); + draw_texture.init(width, height, 0, GL_RGBA8, GL_DEPTH_COMPONENT32F); } light_proj::~light_proj() { @@ -112,7 +113,7 @@ void light_proj::resize(int32_t width, int32_t height) { if (!this) return; - draw_texture.init(width, height, 0, GL_RGBA8, GL_DEPTH24_STENCIL8); + draw_texture.init(width, height, 0, GL_RGBA8, GL_DEPTH_COMPONENT32F); } bool light_proj::set(render_context* rctx) { @@ -183,16 +184,13 @@ bool light_proj::set_mat(render_context* rctx, bool set_mat) { data->get_position(position); data->get_spot_direction(spot_direction); - float_t length; - vec3_length_squared(spot_direction, length); - if (length <= 0.000001f) + if (vec3::length_squared(spot_direction) <= 0.000001f) return false; float_t spot_cutoff = data->get_spot_cutoff(); float_t fov = atanf(tanf(spot_cutoff * DEG_TO_RAD_FLOAT) * 0.25f) * (RAD_TO_DEG_FLOAT * 2.0f); - vec3 interest; - vec3_add(position, spot_direction, interest); + vec3 interest = position + spot_direction; if (set_mat) { mat4 mat; get_proj_mat(&position, &interest, fov, &mat); @@ -215,7 +213,7 @@ object_data_buffer::object_data_buffer() { } object_data_buffer::~object_data_buffer() { - free(data); + free_def(data); } draw_task* object_data_buffer::add_draw_task(draw_task_type type) { @@ -297,15 +295,33 @@ void object_data::add_vertex_array(draw_object* draw) { GLuint array_buffer = draw->array_buffer; GLuint morph_array_buffer = draw->morph_array_buffer; + int32_t texcoord_array[2] = { -1, -1 }; + int32_t color_tex_index = 0; + for (obj_material_texture_data& i : material->material.texdata) { + if (i.tex_index == -1) + continue; + + int32_t texcoord_index = obj_material_texture_type_get_texcoord_index( + i.shader_info.m.tex_type, color_tex_index); + if (texcoord_index < 0) + continue; + + texcoord_array[texcoord_index] = sub_mesh->uv_index[&i - material->material.texdata]; + + if (i.shader_info.m.tex_type == OBJ_MATERIAL_TEXTURE_COLOR) + color_tex_index++; + } + object_data_vertex_array* vertex_array_data = 0; for (object_data_vertex_array& i : vertex_array_cache) - if (i.alive_time >= 0 && i.array_buffer == array_buffer && i.morph_array_buffer == morph_array_buffer) { + if (i.alive_time >= 0 && i.array_buffer == array_buffer && i.morph_array_buffer == morph_array_buffer + && !memcmp(i.texcoord_array, texcoord_array, sizeof(texcoord_array))) { if (!i.vertex_array) { vertex_array_data = &i; break; } - i.alive_time = 60; + i.alive_time = 2; return; } @@ -327,7 +343,8 @@ void object_data::add_vertex_array(draw_object* draw) { vertex_array_data->array_buffer = array_buffer; vertex_array_data->morph_array_buffer = morph_array_buffer; - vertex_array_data->alive_time = 60; + vertex_array_data->alive_time = 2; + memcpy(&vertex_array_data->texcoord_array, texcoord_array, sizeof(texcoord_array)); bool compressed = mesh->attrib.m.compressed; GLsizei size_vertex = (GLsizei)mesh->size_vertex; @@ -339,15 +356,26 @@ void object_data::add_vertex_array(draw_object* draw) { size_t offset = 0; if (vertex_format & OBJ_VERTEX_POSITION) { - glEnableVertexAttribArray(0); + if (!vertex_array_data->vertex_attrib_array[0]) { + glEnableVertexAttribArray(0); + vertex_array_data->vertex_attrib_array[0] = true; + } + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 12; } - else + else if (vertex_array_data->vertex_attrib_array[0]) { + glDisableVertexAttribArray(0); glVertexAttrib4f(0, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[0] = false; + } if (vertex_format & OBJ_VERTEX_NORMAL) { - glEnableVertexAttribArray(2); + if (!vertex_array_data->vertex_attrib_array[2]) { + glEnableVertexAttribArray(2); + vertex_array_data->vertex_attrib_array[2] = true; + } + if (!compressed) { glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 12; @@ -357,11 +385,18 @@ void object_data::add_vertex_array(draw_object* draw) { offset += 8; } } - else + else if (vertex_array_data->vertex_attrib_array[2]) { + glDisableVertexAttribArray(2); glVertexAttrib4f(2, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[2] = false; + } if (vertex_format & OBJ_VERTEX_TANGENT) { - glEnableVertexAttribArray(6); + if (!vertex_array_data->vertex_attrib_array[6]) { + glEnableVertexAttribArray(6); + vertex_array_data->vertex_attrib_array[6] = true; + } + if (!compressed) { glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; @@ -371,42 +406,40 @@ void object_data::add_vertex_array(draw_object* draw) { offset += 8; } } - else - glVertexAttrib4f(5, 0.0f, 0.0f, 0.0f, 1.0f); + else if (vertex_array_data->vertex_attrib_array[6]) { + glDisableVertexAttribArray(6); + glVertexAttrib4f(6, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[6] = false; + } if (!compressed && vertex_format & OBJ_VERTEX_BINORMAL) offset += 12; - bool texture_vertex_attrib_array_set[4] = { false }; - for (int32_t i = 0, j = 0, l = 0; i < 4; i++) { - if (material->material.texdata[i].tex_index == -1) + for (int32_t i = 0; i < 2; i++) { + int32_t texcoord_index = texcoord_array[i]; + if (texcoord_index < 0) { + if (vertex_array_data->vertex_attrib_array[8 + i]) { + glDisableVertexAttribArray(8 + i); + glVertexAttrib4f(8 + i, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[8 + i] = false; + } continue; - - int32_t texcoord_index = obj_material_texture_type_get_texcoord_index( - material->material.texdata[i].shader_info.m.tex_type, j); - if (texcoord_index < 0) - continue; - - if (material->material.texdata[i].shader_info.m.tex_type == OBJ_MATERIAL_TEXTURE_COLOR) - j++; - - if (vertex_format & (OBJ_VERTEX_TEXCOORD0 << sub_mesh->uv_index[l]) - && !texture_vertex_attrib_array_set[sub_mesh->uv_index[l]]) { - glEnableVertexAttribArray(8 + texcoord_index); - if (!compressed) - glVertexAttribPointer(8 + texcoord_index, 2, GL_FLOAT, GL_FALSE, - size_vertex, (void*)(offset + 8ULL * sub_mesh->uv_index[l])); - else - glVertexAttribPointer(8 + texcoord_index, 2, GL_HALF_FLOAT, GL_FALSE, - size_vertex, (void*)(offset + 4ULL * sub_mesh->uv_index[l])); - texture_vertex_attrib_array_set[sub_mesh->uv_index[l]] = true; } - l++; - } - for (int32_t i = 0; i < 4; i++) - if (!texture_vertex_attrib_array_set[i]) - glVertexAttrib4f(8 + i, 0.0f, 0.0f, 0.0f, 1.0f); + if (vertex_format & (OBJ_VERTEX_TEXCOORD0 << i)) { + if (!vertex_array_data->vertex_attrib_array[8 + i]) { + glEnableVertexAttribArray(8 + i); + vertex_array_data->vertex_attrib_array[8 + i] = true; + } + + if (!compressed) + glVertexAttribPointer(8 + i, 2, GL_FLOAT, GL_FALSE, + size_vertex, (void*)(offset + 8ULL * texcoord_index)); + else + glVertexAttribPointer(8 + i, 2, GL_HALF_FLOAT, GL_FALSE, + size_vertex, (void*)(offset + 4ULL * texcoord_index)); + } + } if (!compressed) { if (vertex_format & OBJ_VERTEX_TEXCOORD0) @@ -430,7 +463,11 @@ void object_data::add_vertex_array(draw_object* draw) { } if (vertex_format & OBJ_VERTEX_COLOR0) { - glEnableVertexAttribArray(3); + if (!vertex_array_data->vertex_attrib_array[3]) { + glEnableVertexAttribArray(3); + vertex_array_data->vertex_attrib_array[3] = true; + } + if (!compressed) { glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; @@ -440,14 +477,21 @@ void object_data::add_vertex_array(draw_object* draw) { offset += 8; } } - else + else if (vertex_array_data->vertex_attrib_array[3]) { + glDisableVertexAttribArray(3); glVertexAttrib4f(3, 1.0f, 1.0f, 1.0f, 1.0f); + vertex_array_data->vertex_attrib_array[3] = false; + } if (vertex_format & OBJ_VERTEX_COLOR1) offset += 16; if (vertex_format & OBJ_VERTEX_BONE_DATA) { - glEnableVertexAttribArray(1); + if (!vertex_array_data->vertex_attrib_array[1]) { + glEnableVertexAttribArray(1); + vertex_array_data->vertex_attrib_array[1] = true; + } + if (!compressed) { glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; @@ -457,7 +501,11 @@ void object_data::add_vertex_array(draw_object* draw) { offset += 8; } - glEnableVertexAttribArray(15); + if (!vertex_array_data->vertex_attrib_array[15]) { + glEnableVertexAttribArray(15); + vertex_array_data->vertex_attrib_array[15] = true; + } + if (!compressed) { glVertexAttribPointer(15, 4, GL_INT, GL_FALSE, size_vertex, (void*)offset); offset += 16; @@ -468,32 +516,59 @@ void object_data::add_vertex_array(draw_object* draw) { } } else { - glVertexAttrib4f(1, 0.0f, 0.0f, 0.0f, 0.0f); - glVertexAttrib4f(15, 0.0f, 0.0f, 0.0f, 0.0f); + if (vertex_array_data->vertex_attrib_array[1]) { + glDisableVertexAttribArray(1); + glVertexAttrib4f(1, 0.0f, 0.0f, 0.0f, 0.0f); + vertex_array_data->vertex_attrib_array[1] = false; + } + + if (vertex_array_data->vertex_attrib_array[15]) { + glDisableVertexAttribArray(15); + glVertexAttrib4f(15, 0.0f, 0.0f, 0.0f, 0.0f); + vertex_array_data->vertex_attrib_array[15] = false; + } } if (!compressed && vertex_format & OBJ_VERTEX_UNKNOWN) { - glEnableVertexAttribArray(7); + if (!vertex_array_data->vertex_attrib_array[7]) { + glEnableVertexAttribArray(7); + vertex_array_data->vertex_attrib_array[7] = true; + } + glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; } - else + else if (vertex_array_data->vertex_attrib_array[7]) { + glDisableVertexAttribArray(7); glVertexAttrib4f(7, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[7] = false; + } if (draw->morph_array_buffer) { gl_state_bind_array_buffer(draw->morph_array_buffer); offset = 0; if (vertex_format & OBJ_VERTEX_POSITION) { - glEnableVertexAttribArray(10); + if (!vertex_array_data->vertex_attrib_array[10]) { + glEnableVertexAttribArray(10); + vertex_array_data->vertex_attrib_array[10] = true; + } + glVertexAttribPointer(10, 3, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 12; } - else + else if (vertex_array_data->vertex_attrib_array[10]) { + glDisableVertexAttribArray(10); glVertexAttrib4f(10, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[10] = false; + } if (vertex_format & OBJ_VERTEX_NORMAL) { - glEnableVertexAttribArray(11); + if (!vertex_array_data->vertex_attrib_array[11]) { + glEnableVertexAttribArray(11); + vertex_array_data->vertex_attrib_array[11] = true; + } + if (!compressed) { glVertexAttribPointer(11, 3, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 12; @@ -503,11 +578,18 @@ void object_data::add_vertex_array(draw_object* draw) { offset += 8; } } - else + else if (vertex_array_data->vertex_attrib_array[11]) { + glDisableVertexAttribArray(11); glVertexAttrib4f(11, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[11] = false; + } if (vertex_format & OBJ_VERTEX_TANGENT) { - glEnableVertexAttribArray(12); + if (!vertex_array_data->vertex_attrib_array[12]) { + glEnableVertexAttribArray(12); + vertex_array_data->vertex_attrib_array[12] = true; + } + if (!compressed) { glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; @@ -517,14 +599,21 @@ void object_data::add_vertex_array(draw_object* draw) { offset += 8; } } - else + else if (vertex_array_data->vertex_attrib_array[12]) { + glDisableVertexAttribArray(12); glVertexAttrib4f(12, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[12] = false; + } if (!compressed && vertex_format & OBJ_VERTEX_BINORMAL) offset += 12; if (vertex_format & OBJ_VERTEX_TEXCOORD0) { - glEnableVertexAttribArray(13); + if (!vertex_array_data->vertex_attrib_array[13]) { + glEnableVertexAttribArray(13); + vertex_array_data->vertex_attrib_array[13] = true; + } + if (!compressed) { glVertexAttribPointer(13, 2, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 8; @@ -534,11 +623,18 @@ void object_data::add_vertex_array(draw_object* draw) { offset += 4; } } - else + else if (vertex_array_data->vertex_attrib_array[13]) { + glDisableVertexAttribArray(13); glVertexAttrib4f(13, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[13] = false; + } if (vertex_format & OBJ_VERTEX_TEXCOORD1) { - glEnableVertexAttribArray(14); + if (!vertex_array_data->vertex_attrib_array[14]) { + glEnableVertexAttribArray(14); + vertex_array_data->vertex_attrib_array[14] = true; + } + if (!compressed) { glVertexAttribPointer(14, 2, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 8; @@ -548,8 +644,11 @@ void object_data::add_vertex_array(draw_object* draw) { offset += 4; } } - else + else if (vertex_array_data->vertex_attrib_array[14]) { + glDisableVertexAttribArray(14); glVertexAttrib4f(14, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[14] = false; + } if (!compressed) { if (vertex_format & OBJ_VERTEX_TEXCOORD2) @@ -567,7 +666,11 @@ void object_data::add_vertex_array(draw_object* draw) { if (vertex_format & OBJ_VERTEX_COLOR0) { uniform_value[U_MORPH_COLOR] = 1; - glEnableVertexAttribArray(5); + if (!vertex_array_data->vertex_attrib_array[5]) { + glEnableVertexAttribArray(5); + vertex_array_data->vertex_attrib_array[5] = true; + } + if (!compressed) { glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; @@ -577,8 +680,11 @@ void object_data::add_vertex_array(draw_object* draw) { offset += 8; } } - else + else if (vertex_array_data->vertex_attrib_array[5]) { + glDisableVertexAttribArray(5); glVertexAttrib4f(5, 1.0f, 1.0f, 1.0f, 1.0f); + vertex_array_data->vertex_attrib_array[5] = false; + } if (!compressed) { if (vertex_format & OBJ_VERTEX_COLOR1) @@ -594,9 +700,45 @@ void object_data::add_vertex_array(draw_object* draw) { if (vertex_format & OBJ_VERTEX_BONE_DATA) offset += 16; } - - shaders_ft.env_vert_set(13, draw->morph_value, 1.0f - draw->morph_value, 0.0f, 0.0f); } + else { + if (vertex_array_data->vertex_attrib_array[10]) { + glDisableVertexAttribArray(10); + glVertexAttrib4f(10, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[10] = false; + } + + if (vertex_array_data->vertex_attrib_array[11]) { + glDisableVertexAttribArray(11); + glVertexAttrib4f(11, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[11] = false; + } + + if (vertex_array_data->vertex_attrib_array[12]) { + glDisableVertexAttribArray(12); + glVertexAttrib4f(12, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[12] = false; + } + + if (vertex_array_data->vertex_attrib_array[13]) { + glDisableVertexAttribArray(13); + glVertexAttrib4f(13, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[13] = false; + } + + if (vertex_array_data->vertex_attrib_array[14]) { + glDisableVertexAttribArray(14); + glVertexAttrib4f(14, 0.0f, 0.0f, 0.0f, 1.0f); + vertex_array_data->vertex_attrib_array[14] = false; + } + + if (vertex_array_data->vertex_attrib_array[5]) { + glDisableVertexAttribArray(5); + glVertexAttrib4f(5, 1.0f, 1.0f, 1.0f, 1.0f); + vertex_array_data->vertex_attrib_array[5] = false; + } + } + gl_state_bind_array_buffer(0); gl_state_bind_vertex_array(0); gl_state_bind_element_array_buffer(0); @@ -611,9 +753,35 @@ void object_data::check_vertex_arrays() { } } -GLuint object_data::get_vertex_array(GLuint array_buffer, GLuint morph_array_buffer) { +GLuint object_data::get_vertex_array(draw_object* draw) { + obj_mesh* mesh = draw->mesh; + obj_sub_mesh* sub_mesh = draw->sub_mesh; + obj_material_data* material = draw->material; + + GLuint array_buffer = draw->array_buffer; + GLuint morph_array_buffer = draw->morph_array_buffer; + + int32_t texcoord_array[2] = { -1, -1 }; + int32_t color_tex_index = 0; + for (obj_material_texture_data& i : material->material.texdata) { + if (i.tex_index == -1) + continue; + + int32_t texcoord_index = obj_material_texture_type_get_texcoord_index( + i.shader_info.m.tex_type, color_tex_index); + if (texcoord_index < 0) + continue; + + texcoord_array[texcoord_index] = sub_mesh->uv_index[&i - material->material.texdata]; + + if (i.shader_info.m.tex_type == OBJ_MATERIAL_TEXTURE_COLOR) + color_tex_index++; + } + + object_data_vertex_array* vertex_array_data = 0; for (object_data_vertex_array& i : vertex_array_cache) - if (i.alive_time > 0 && i.array_buffer == array_buffer && i.morph_array_buffer == morph_array_buffer) + if (i.alive_time > 0 && i.array_buffer == array_buffer && i.morph_array_buffer == morph_array_buffer + && !memcmp(i.texcoord_array, texcoord_array, sizeof(texcoord_array))) return i.vertex_array; return 0; } @@ -836,7 +1004,7 @@ void render_context::ctrl() { rctx_ptr = this; app::TaskWork::Ctrl(); - + sound_ctrl(); file_handler_storage_ctrl(); draw_pass.shadow_ptr->ctrl(this); @@ -1006,7 +1174,7 @@ void render_context::light_param_data_ibl_set( light_data* l = &set->lights[LIGHT_CHARA]; l->get_position(pos); - vec3_length(pos, len); + len = vec3::length(pos); if (fabsf(len - 1.0f) < 0.02f) l->set_position(ibl->lit_dir[0]); @@ -1016,7 +1184,7 @@ void render_context::light_param_data_ibl_set( l = &set->lights[LIGHT_STAGE]; l->get_position(pos); - vec3_length(pos, len); + len = vec3::length(pos); if (fabsf(len - 1.0f) < 0.02f) l->set_position(ibl->lit_dir[1]); @@ -1081,8 +1249,7 @@ field_1A8(), view_point_shared(), interest_shared(), field_2F0() { field_2E0 = 0.05f; ambient = 0.4f; field_2EC = 0; - direction = { 0.0f, -1.0f, -1.0f }; - vec3_mult_scalar(direction, 1.0f / sqrtf(2.0f), direction); + direction = vec3(0.0f, -1.0f, -1.0f) * (1.0f / sqrtf(2.0f)); field_2E8 = false; self_shadow = true; blur_filter_enable[0] = true; @@ -1107,14 +1274,12 @@ void shadow::ctrl(render_context* rctx) { light_data* data = &set->lights[LIGHT_CHARA]; vec3 position; - float_t length; data->get_position(position); - vec3_negate(position, position); - vec3_length(position, length); - if (length < 0.000001) + float_t length = vec3::length(position); + if (length < 0.000001f) direction = { 0.0f, 1.0f, 0.0f }; else - vec3_mult_scalar(position, 1.0f / length, direction); + direction = -position * (1.0f / length); for (int32_t i = 0; i < 2; i++) if (draw_task_get_count(rctx, (draw_object_type)((int32_t)DRAW_OBJECT_SHADOW_CHARA + i))) @@ -1140,23 +1305,18 @@ void shadow::ctrl(render_context* rctx) { vec3 v7 = vec3_null; for (vec3& j : field_1D0[i]) - vec3_add(v7, j, v7); + v7 += j; float_t v14 = (float_t)(int32_t)field_1D0[i].size(); if (v14 < 0.0f) v14 += 1.8446744e19f; - vec3_mult_scalar(v7, 1.0f / v14, v7); + v7 *= 1.0f / v14; float_t v15 = 0.0f; for (vec3& j : field_1D0[i]) { - vec3 v22; - vec3_sub(v7, j, v22); - float_t v23; - vec3_dot(v22, direction, v23); - vec3 v25; - vec3_mult_scalar(direction, v23, v25); - float_t v24; - vec3_distance(v25, v22, v24); + vec3 v22 = v7 - j; + vec3 v25 = direction * vec3::dot(v22, direction); + float_t v24 = vec3::distance(v25, v22); v24 -= 0.25f; if (v24 < 0.0f) v24 = 0.0f; @@ -1174,49 +1334,35 @@ void shadow::ctrl(render_context* rctx) { if (!field_2F0[i]) continue; - vec3 v11; - vec3_mult_scalar(direction, field_208, v11); - vec3_sub(field_1A8[i], v11, v11); - float_t v9; - vec3_distance(this->view_point[i], v11, v9); - - float_t v12; - vec3_distance(this->interest[i], field_1A8[i], v12); + vec3 v11 = field_1A8[i] - direction * field_208; + float_t v9 = vec3::distance(this->view_point[i], v11); + float_t v12 = vec3::distance(this->interest[i], field_1A8[i]); if (v9 > 0.1f || v12 > 0.1f) { this->view_point[i] = v11; this->interest[i] = field_1A8[i]; } - vec3_add(view_point, this->view_point[i], view_point); - vec3_add(interest, this->interest[i], interest); + view_point += this->view_point[i]; + interest += this->interest[i]; } - vec3_mult_scalar(view_point, 1.0f / field_2EC, view_point_shared); - vec3_mult_scalar(interest, 1.0f / field_2EC, interest_shared); + view_point_shared = view_point * (1.0f / field_2EC); + interest_shared = interest * (1.0f / field_2EC); } - float_t v2 = max(field_1C8[0], field_1C8[1]); + float_t v2 = max_def(field_1C8[0], field_1C8[1]); field_2F5 = false; view_region = v2 + 1.2f; field_200[0] = 0; field_200[1] = 1; if (field_2EC >= 2) { - vec3 v12; - vec3_sub(field_1A8[0], interest_shared, v12); + vec3 v12 = field_1A8[0] - interest_shared; + vec3 v14 = field_1A8[1] - interest_shared; + float_t v15 = vec3::dot(v12, direction); - vec3 v14; - vec3_sub(field_1A8[1], interest_shared, v14); + vec3 v6 = direction * v15 - v12; - float_t v15; - vec3_dot(v12, direction, v15); - - vec3 v6; - vec3_mult_scalar(direction, v15, v6); - vec3_sub(v6, v12, v6); - - float_t v16; - vec3_length(v6, v16); - v16 -= 0.25f; + float_t v16 = vec3::length(v6) - 0.25f; if (v16 < 0.0f) v16 = 0.0f; @@ -1227,11 +1373,7 @@ void shadow::ctrl(render_context* rctx) { else view_region = v2 + 1.2f + v16; - float_t t3; - float_t t4; - vec3_dot(v12, direction, t3); - vec3_dot(v14, direction, t4); - if (t3 < t4) { + if (vec3::dot(v12, direction) < vec3::dot(v14, direction)) { field_200[1] = 0; field_200[0] = 1; } @@ -1241,11 +1383,9 @@ void shadow::ctrl(render_context* rctx) { vec3 v3; vec3 v86; if (direction.y * direction.y < 0.99f) { - vec3 up = { 0.0f, 1.0f, 0.0f }; - vec3_cross(direction, up, v86); - vec3_cross(v86, direction, v3); - vec3_normalize(v3, v3); - vec3_normalize(v86, v86); + v86 = vec3::cross(direction, vec3(0.0f, 1.0f, 0.0f)); + v3 = vec3::normalize(vec3::cross(v86, direction)); + v86 = vec3::normalize(v86); } else { v3 = { 0.0f, 0.0f, 1.0f }; @@ -1260,7 +1400,7 @@ void shadow::ctrl(render_context* rctx) { vec3 v22 = vec3_null; for (vec3& j : field_1D0[i]) - vec3_add(v22, j, v22); + v22 += j; int32_t v27 = (int32_t)field_1D0[i].size(); float_t v29 = (float_t)v27; @@ -1268,18 +1408,12 @@ void shadow::ctrl(render_context* rctx) { v29 += 1.8446744e19f; float_t v30 = 0.0f; - vec3 v31; - vec3_mult_scalar(v22, 1.0f / v29, v31); + vec3 v31 = v22 * (1.0f / v29); for (vec3& j : field_1D0[i]) { - vec3 v34; - vec3_sub(v31, j, v34); - float_t v38; - float_t v39; - vec3_dot(v34, v3, v38); - vec3_dot(v34, v86, v39); - v38 = fabsf(v38); - v39 = fabsf(v39); + vec3 v34 = v31 - j; + float_t v38 = fabsf(vec3::dot(v34, v3)); + float_t v39 = fabsf(vec3::dot(v34, v86)); if (v39 >= v38) v38 = v39; if (v30 < v38) @@ -1294,13 +1428,9 @@ void shadow::ctrl(render_context* rctx) { if (!field_2F0[i]) continue; - float_t v51; - vec3 v53; - float_t v54; - vec3_mult_scalar(direction, field_208, v53); - vec3_sub(field_1A8[i], v53, v53); - vec3_distance(view_point[i], v53, v51); - vec3_distance(interest[i], field_1A8[i], v54); + vec3 v53 = field_1A8[i] - direction * field_208; + float_t v51 = vec3::distance(view_point[i], v53); + float_t v54 = vec3::distance(interest[i], field_1A8[i]); if (v51 > 0.1f || v54 > 0.1f) { view_point[i] = v53; interest[i] = field_1A8[i]; @@ -1312,47 +1442,40 @@ void shadow::ctrl(render_context* rctx) { int32_t count = 0; for (int32_t i = 0; i < 2; i++) { int32_t c = (int32_t)field_1D0[i].size(); - vec3 view_point_temp; - vec3 interest_temp; - vec3_mult_scalar(this->view_point[i], (float_t)c, view_point_temp); - vec3_mult_scalar(this->interest[i], (float_t)c, interest_temp); - vec3_add(view_point, view_point_temp, view_point); - vec3_add(interest, interest_temp, interest); + view_point += this->view_point[i] * (float_t)c; + interest += this->interest[i] * (float_t)c; count += c; } - vec3_mult_scalar(view_point, 1.0f / (float_t)count, view_point_shared); - vec3_mult_scalar(interest, 1.0f / (float_t)count, interest_shared); + view_point_shared = view_point * (1.0f / (float_t)count); + interest_shared = interest * (1.0f / (float_t)count); } - float_t v2 = 0.0; - float_t v67 = max(field_1C8[0], field_1C8[1]); + float_t v2 = 0.0f; + float_t v67 = max_def(field_1C8[0], field_1C8[1]); field_2F5 = false; view_region = v67 + 1.2f; field_200[0] = 0; field_200[1] = 1; if (field_2EC >= 2) { - float_t v68 = 0.0; - float_t v69 = 0.0; - float_t v70 = 0.0; + float_t v68 = 0.0f; + float_t v69 = 0.0f; + float_t v70 = 0.0f; for (int32_t i = 0; i < 2; i++) { if (!field_2F0[i]) continue; for (vec3& j : field_1D0[i]) { - vec3 v74; - vec3_sub(j, interest_shared, v74); + vec3 v74 = j - interest_shared; - float_t v77; - vec3_dot(v74, v86, v77); - if (v77 < v2) + float_t v77 = vec3::dot(v74, v86); + if (v2 > v77) v2 = v77; else if (v69 < v77) v69 = v77; - float_t v78; - vec3_dot(v74, v3, v78); - if (v78 < v68) + float_t v78 = vec3::dot(v74, v3); + if (v68 > v78) v68 = v78; else if (v70 < v78) v70 = v78; @@ -1374,15 +1497,8 @@ void shadow::ctrl(render_context* rctx) { else view_region = v79 + 1.2f; - vec3 interest_chara; - vec3 interest_stage; - float_t interest_chara_cos; - float_t interest_stage_cos; - vec3_sub(field_1A8[0], interest_shared, interest_chara); - vec3_dot(interest_chara, direction, interest_chara_cos); - vec3_sub(field_1A8[1], interest_shared, interest_stage); - vec3_dot(interest_stage, direction, interest_stage_cos); - if (interest_chara_cos < interest_stage_cos) { + if (vec3::dot(field_1A8[0] - interest_shared, direction) + < vec3::dot(field_1A8[1] - interest_shared, direction)) { field_200[1] = 0; field_200[0] = 1; } @@ -1401,7 +1517,7 @@ int32_t shadow::init_data() { GLenum color_format; GLenum depth_format; } init_params[] = { - { 0x800, 0x800, 0, GL_RGBA8, GL_DEPTH24_STENCIL8 }, + { 0x800, 0x800, 0, GL_RGBA8, GL_DEPTH_COMPONENT32F }, { 0x200, 0x200, 3, GL_RGBA8, GL_ZERO }, { 0x200, 0x200, 3, GL_RGBA8, GL_ZERO }, { 0x800, 0x800, 0, GL_R32F, GL_ZERO }, diff --git a/src/CRE/render_context.hpp b/src/CRE/render_context.hpp index 15c72816..f737a586 100644 --- a/src/CRE/render_context.hpp +++ b/src/CRE/render_context.hpp @@ -441,6 +441,8 @@ struct object_data_vertex_array { GLuint morph_array_buffer; int32_t alive_time; GLuint vertex_array; + bool vertex_attrib_array[16]; + int32_t texcoord_array[2]; }; struct object_data { @@ -480,7 +482,7 @@ struct object_data { void add_vertex_array(draw_object* draw); void check_vertex_arrays(); - GLuint get_vertex_array(GLuint array_buffer, GLuint morph_array_buffer); + GLuint get_vertex_array(draw_object* draw); bool get_chara_color(); ::draw_task_flags get_draw_task_flags(); void get_material_list(int32_t& count, material_list_struct*& value); diff --git a/src/CRE/render_texture.cpp b/src/CRE/render_texture.cpp index 849ba8bf..056c9fc4 100644 --- a/src/CRE/render_texture.cpp +++ b/src/CRE/render_texture.cpp @@ -78,7 +78,7 @@ int32_t render_texture::init(int32_t width, int32_t height, if (max_level < 0) return -1; - max_level = min(max_level, 15); + max_level = min_def(max_level, 15); if (max_level < 0) return 0; free_data(); @@ -158,8 +158,8 @@ void render_texture::draw_custom_glsl() { void render_texture::draw_params(shader_set_data* set, int32_t width, int32_t height, float_t scale, float_t param_x, float_t param_y, float_t param_z, float_t param_w) { - float_t w = (float_t)max(width, 1); - float_t h = (float_t)max(height, 1); + float_t w = (float_t)max_def(width, 1); + float_t h = (float_t)max_def(height, 1); set->local_vert_set(0, scale / w, scale / h, w, h); set->local_frag_set(0, scale / w, scale / h, w, h); set->local_vert_set(3, param_x, param_y, param_z, param_w); @@ -211,7 +211,7 @@ void render_texture_data_init() { "layout(binding = 0) uniform sampler2D g_color;\n" "\n" "void main() {\n" - " result = texture(g_color, frg.texcoord); \n" + " result = texture(g_color, frg.texcoord);\n" "}\n"; shader_glsl_param param = {}; diff --git a/src/CRE/rob/ex_block.cpp b/src/CRE/rob/ex_block.cpp index b08a9b2e..2b6fc7a3 100644 --- a/src/CRE/rob/ex_block.cpp +++ b/src/CRE/rob/ex_block.cpp @@ -177,9 +177,8 @@ static const exp_func_op3 exp_func_op3_array[] = { osage_setting osage_setting_data; size_t qword_140FBDF88 = 0; - -static const int32_t rob_cloth_update_vertices_flags = 0x03; -static const bool rob_cloth_update_normals_select = false; +int32_t rob_cloth_update_vertices_flags = 0x03; +bool rob_cloth_update_normals_select = false; ExNodeBlock::ExNodeBlock() : bone_node_ptr(), type(), name(), parent_bone_node(), parent_name(), parent_node(), item_equip_object(), field_58(), field_59(), has_children_node() { @@ -337,10 +336,10 @@ skin_param_hinge::~skin_param_hinge() { } void skin_param_hinge::limit() { - ymin = max(ymin, -179.0f) * DEG_TO_RAD_FLOAT; - ymax = min(ymax, 179.0f) * DEG_TO_RAD_FLOAT; - zmin = max(zmin, -179.0f) * DEG_TO_RAD_FLOAT; - zmax = min(zmax, 179.0f) * DEG_TO_RAD_FLOAT; + ymin = max_def(ymin, -179.0f) * DEG_TO_RAD_FLOAT; + ymax = min_def(ymax, 179.0f) * DEG_TO_RAD_FLOAT; + zmin = max_def(zmin, -179.0f) * DEG_TO_RAD_FLOAT; + zmax = min_def(zmax, 179.0f) * DEG_TO_RAD_FLOAT; } skin_param_osage_node::skin_param_osage_node() : coli_r(0.0f), weight(1.0f), inertial_cancel(0.0f) { @@ -1559,8 +1558,8 @@ void RobOsage::SetForce(float_t force, float_t force_gain) { } void RobOsage::SetHinge(float_t hinge_y, float_t hinge_z) { - hinge_y = min(hinge_y, 179.0f); - hinge_z = min(hinge_z, 179.0f); + hinge_y = min_def(hinge_y, 179.0f); + hinge_z = min_def(hinge_z, 179.0f); hinge_y = hinge_y * DEG_TO_RAD_FLOAT; hinge_z = hinge_z * DEG_TO_RAD_FLOAT; RobOsageNode* i_begin = nodes.data() + 1; @@ -1716,8 +1715,8 @@ void RobOsage::SetOsagePlayData(mat4* parent_mat, for (RobOsageNode* j = j_begin; j != j_end; j++) { float_t rot_y = j->field_1B0.field_0.rotation.y; float_t rot_z = j->field_1B0.field_0.rotation.z; - rot_y = clamp(rot_y, (float_t)-M_PI, (float_t)M_PI); - rot_z = clamp(rot_z, (float_t)-M_PI, (float_t)M_PI); + rot_y = clamp_def(rot_y, (float_t)-M_PI, (float_t)M_PI); + rot_z = clamp_def(rot_z, (float_t)-M_PI, (float_t)M_PI); mat4_rotate_z_mult(&v85, rot_z, &v85); mat4_rotate_y_mult(&v85, rot_y, &v85); j->bone_node_ptr->exp_data.parent_scale = parent_scale; @@ -1920,7 +1919,7 @@ void ExOsageBlock::Field_50() { rob.ColiSet(mats); sub_14047C770(&rob, parent_bone_node->ex_data_mat, &parent_scale, step, 1); float_t step = 0.5f * this->step; - this->step = max(step, 1.0f); + this->step = max_def(step, 1.0f); } void ExOsageBlock::Field_58() { @@ -2288,11 +2287,11 @@ void ExConstraintBlock::sub_1401EB410(mat4* mat, vec3* a2, vec3* target_offset) float_t v18; vec3_dot(v3, v4, v18); - v18 = clamp(v18, -1.0f, 1.0f); + v18 = clamp_def(v18, -1.0f, 1.0f); float_t v19 = 1.0f - v18; float_t v20 = 1.0f - v18 * v18; - v20 = sqrtf(clamp(v20, 0.0f, 1.0f)); + v20 = sqrtf(clamp_def(v20, 0.0f, 1.0f)); sub_1405F10D0(mat, &v13, v18, v20); } @@ -2440,7 +2439,7 @@ void ExExpressionBlock::InitData(rob_chara_item_equip_object* itm_eq_obj, std::string value_type; expression = str_utils_get_next_string(expression, value_type, ' '); if (!value_type.size() || !memcmp(value_type.c_str(), "error", - min(value_type.size(), 5)) && value_type.size() == 5) + min_def(value_type.size(), 5)) && value_type.size() == 5) break; if (value_type[0] == 'n') { @@ -2616,7 +2615,7 @@ void skin_param_osage_root_parse(void* kv, const char* name, float_t air_res = 0.0f; if (_kv->read("air_res", air_res)) - skp_root.air_res = min(air_res, 0.9f); + skp_root.air_res = min_def(air_res, 0.9f); float_t rot_y = 0.0f; float_t rot_z = 0.0f; @@ -3016,11 +3015,11 @@ static float_t exp_lt(float_t v1, float_t v2) { } static float_t exp_max(float_t v1, float_t v2) { - return max(v1, v2); + return max_def(v1, v2); } static float_t exp_min(float_t v1, float_t v2) { - return min(v1, v2); + return min_def(v1, v2); } static float_t exp_mul(float_t v1, float_t v2) { @@ -4029,7 +4028,7 @@ static int32_t sub_140483EA0(vec3* a1, vec3* a2, osage_coli* a3, float_t radius) vec3_dot(v63, a3->bone_pos_diff, v36); v36 *= v25; float_t v37 = v36 * v36; - v37 = min(v37, 1.0f); + v37 = min_def(v37, 1.0f); v22 *= 0.5f; float_t v38 = v22 * v22 - v61; if (v38 < 0.0f) @@ -4468,7 +4467,7 @@ static void sub_140482100(struc_476* a1, opd_blend_data* a2, struc_477* a3) { } static void sub_140482DF0(struc_477* dst, struc_477* src0, struc_477* src1, float_t blend) { - dst->length = lerp(src0->length, src1->length, blend); + dst->length = lerp_def(src0->length, src1->length, blend); vec3_lerp_scalar(src0->rotation, src1->rotation, dst->rotation, blend); } diff --git a/src/CRE/rob/rob.cpp b/src/CRE/rob/rob.cpp index ebd06d1b..9a027ee1 100644 --- a/src/CRE/rob/rob.cpp +++ b/src/CRE/rob/rob.cpp @@ -14,7 +14,7 @@ #include "../random.hpp" #include "../pv_expression.hpp" #include "../stage.hpp" -#include "../timer.hpp" +#include "../waitable_timer.hpp" struct MotFile { motion_set_info* mot_set_info; @@ -249,6 +249,7 @@ public: ReqData(); ReqData(::chara_index chara_index, int32_t count); virtual ~ReqData(); + virtual void Reset(); }; @@ -259,6 +260,7 @@ public: ReqDataObj(); ReqDataObj(::chara_index chara_index, int32_t count); virtual ~ReqDataObj() override; + virtual void Reset() override; }; @@ -845,7 +847,6 @@ static void osage_play_data_manager_get_opd_file_data(object_info obj_info, static bool pv_osage_manager_array_get_disp(int32_t* chara_id); static PvOsageManager* pv_osage_manager_array_get(int32_t chara_id); -static void pv_osage_manager_array_set_not_reset_true(); static int pv_data_set_motion_quicksort_compare_func(void const* src1, void const* src2); @@ -2219,7 +2220,7 @@ void rob_free() { rob_chara_pv_data_array = 0; } - free(rob_cmn_mottbl_data); + free_def(rob_cmn_mottbl_data); if (rob_thread_handler) { delete rob_thread_handler; @@ -3197,15 +3198,21 @@ static void rob_chara_set_face_motion(rob_chara* rob_chr, static void rob_chara_set_hand_l_motion(rob_chara* rob_chr, RobHandMotion* motion, int32_t type, motion_database* mot_db) { - if (type == 2) + if (type == 2) { rob_chr->data.motion.field_3B0.hand_l.data = motion->data; - else if (type == 1) + if (!(rob_chr->data.motion.field_29 & 0x08) || (rob_chr->data.motion.field_2A & 0x04)) + return; + } + else if (type == 1) { + rob_chr->data.motion.hand_r.data = motion->data; + if ((rob_chr->data.motion.field_29 & 0x08) || !(rob_chr->data.motion.field_2A & 0x04)) + return; + } + else { rob_chr->data.motion.field_150.hand_l.data = motion->data; - else - rob_chr->data.motion.hand_l.data = motion->data; - - if (!(rob_chr->data.motion.field_29 & 0x08) || rob_chr->data.motion.field_2A & 0x04) - return; + if ((rob_chr->data.motion.field_29 & 0x08) || (rob_chr->data.motion.field_2A & 0x04)) + return; + } rob_chara_bone_data_load_hand_l_motion(rob_chr->bone_data, motion->data.motion_id, mot_db); rob_chara_bone_data_set_hand_l_frame(rob_chr->bone_data, motion->data.frame); @@ -3216,15 +3223,21 @@ static void rob_chara_set_hand_l_motion(rob_chara* rob_chr, static void rob_chara_set_hand_r_motion(rob_chara* rob_chr, RobHandMotion* motion, int32_t type, motion_database* mot_db) { - if (type == 2) + if (type == 2) { rob_chr->data.motion.field_3B0.hand_r.data = motion->data; - else if (type == 1) - rob_chr->data.motion.field_150.hand_r.data = motion->data; - else + if (!(rob_chr->data.motion.field_29 & 0x10) || (rob_chr->data.motion.field_2A & 0x08)) + return; + } + else if (type == 1) { rob_chr->data.motion.hand_r.data = motion->data; - - if (!(rob_chr->data.motion.field_29 & 0x10) || rob_chr->data.motion.field_2A & 0x08) - return; + if ((rob_chr->data.motion.field_29 & 0x10) || !(rob_chr->data.motion.field_2A & 0x08)) + return; + } + else { + rob_chr->data.motion.field_150.hand_r.data = motion->data; + if ((rob_chr->data.motion.field_29 & 0x10) || (rob_chr->data.motion.field_2A & 0x08)) + return; + } rob_chara_bone_data_load_hand_r_motion(rob_chr->bone_data, motion->data.motion_id, mot_db); rob_chara_bone_data_set_hand_r_frame(rob_chr->bone_data, motion->data.frame); @@ -3468,10 +3481,10 @@ void rob_chara::set_eyes_mottbl_motion(int32_t type, } static void sub_140553970(rob_chara* rob_chr, object_info a2, int32_t type) { - if (type == 1) - rob_chr->data.motion.field_150.head_object = a2; - else + if (type != 1 && type == 2) rob_chr->data.motion.field_3B0.head_object = a2; + else + rob_chr->data.motion.field_150.head_object = a2; } void rob_chara::set_face_mottbl_motion(int32_t type, @@ -4224,8 +4237,8 @@ static void bone_data_mult_ik(bone_data* a1, int32_t skeleton_select) { rot_cos = (v28 + ik_segment_length) / (2.0f * v10); rot_2nd_cos = (v28 - ik_segment_length) / (2.0f * ik_2nd_segment_length); - rot_cos = clamp(rot_cos, -1.0f, 1.0f); - rot_2nd_cos = clamp(rot_2nd_cos, -1.0f, 1.0f); + rot_cos = clamp_def(rot_cos, -1.0f, 1.0f); + rot_2nd_cos = clamp_def(rot_2nd_cos, -1.0f, 1.0f); rot_sin = sqrtf(1.0f - rot_cos * rot_cos); rot_2nd_sin = sqrtf(1.0f - rot_2nd_cos * rot_2nd_cos); @@ -6192,7 +6205,7 @@ static void motion_blend_mot_set_blend(motion_blend_mot* a1, case MOTION_BLEND_COMBINE: a1->blend = &a1->combine; a1->combine.Reset(); - a1->combine.blend = clamp(blend, 0.0f, 1.0f); + a1->combine.blend = clamp_def(blend, 0.0f, 1.0f); break; } } @@ -6239,11 +6252,6 @@ static PvOsageManager* pv_osage_manager_array_get(int32_t chara_id) { return &pv_osage_manager_array[chara_id]; } -static void pv_osage_manager_array_set_not_reset_true() { - for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) - pv_osage_manager_array_get(i)->SetNotReset(true); -} - static int pv_data_set_motion_quicksort_compare_func(void const* src1, void const* src2) { pv_data_set_motion* pv1 = (pv_data_set_motion*)src1; pv_data_set_motion* pv2 = (pv_data_set_motion*)src2; @@ -6375,13 +6383,13 @@ void rob_chara_data_adjust_ctrl(rob_chara* rob_chr, rob_chara_data_adjust* adjus float_t blend = (adjust->transition_frame + 1.0f) / (adjust->force_duration + 1.0f); vec3_lerp_scalar(adjust_prev->curr_external_force, adjust->curr_external_force, adjust->curr_external_force, blend); - adjust->curr_force = lerp(adjust_prev->curr_force, adjust->curr_force, blend); + adjust->curr_force = lerp_def(adjust_prev->curr_force, adjust->curr_force, blend); } if (adjust->strength_transition > adjust->transition_frame && fabsf(adjust->strength_transition - adjust->transition_frame) > 0.000001f) { float_t blend = (adjust->transition_frame + 1.0f) / (adjust->strength_transition + 1.0f); - adjust->curr_strength = lerp(adjust_prev->curr_strength, adjust->curr_strength, blend); + adjust->curr_strength = lerp_def(adjust_prev->curr_strength, adjust->curr_strength, blend); } else if (!transition_frame_step) return; @@ -7831,7 +7839,6 @@ static void sub_140407280(struc_258* a1, std::vector* a2, mat4* mat, vec3_normalize(v67, v67); vec3_mult_scalar(v67, v28, v68); - float_t v39; vec2_length(*(vec2*)&v67, v39); @@ -8300,7 +8307,6 @@ static void rob_chara_set_hand_adjust(rob_chara* rob_chr, switch (adjust->type) { case ROB_CHARA_DATA_HAND_ADJUST_NORMAL: - case 15: adjust->scale = chara_size_table_get_value(1); break; case ROB_CHARA_DATA_HAND_ADJUST_SHORT: @@ -8310,10 +8316,10 @@ static void rob_chara_set_hand_adjust(rob_chara* rob_chr, adjust->scale = chara_size_table_get_value(0); break; case ROB_CHARA_DATA_HAND_ADJUST_MIN: - adjust->scale = min(opposite_chara_scale, chara_scale); + adjust->scale = min_def(opposite_chara_scale, chara_scale); break; case ROB_CHARA_DATA_HAND_ADJUST_MAX: - adjust->scale = max(opposite_chara_scale, chara_scale); + adjust->scale = max_def(opposite_chara_scale, chara_scale); break; case ROB_CHARA_DATA_HAND_ADJUST_OPPOSITE_CHARA: adjust->scale = opposite_chara_scale; @@ -8355,7 +8361,7 @@ static void rob_chara_set_hand_adjust(rob_chara* rob_chr, if (fabsf(prev_scale - scale * adjust->scale_blend) <= 0.000001f || adjust->duration <= adjust->current_time || fabsf(adjust->duration - adjust->current_time) <= 0.000001f) { - adjust->current_scale = lerp(prev_scale, scale, adjust->scale_blend); + adjust->current_scale = lerp_def(prev_scale, scale, adjust->scale_blend); if (fabsf(adjust->current_scale - chara_scale) <= 0.000001f) { adjust->current_scale = chara_scale; adjust->enable = false; @@ -8363,7 +8369,7 @@ static void rob_chara_set_hand_adjust(rob_chara* rob_chr, } else { float_t t = (adjust->current_time + 1.0f) / (adjust->duration + 1.0f); - adjust->current_scale = lerp(prev_scale, scale, t * adjust->scale_blend); + adjust->current_scale = lerp_def(prev_scale, scale, t * adjust->scale_blend); adjust->current_time += rob_chr->data.motion.step_data.frame; } } @@ -8640,7 +8646,7 @@ static bool sub_14053B580(rob_chara* rob_chr, int32_t a2) { float_t v32 = v0.field_8 - v30 + 1.0f; if (fabsf(v32) > 0.000001f) { v31 = (v0.field_8 - v29) / v32; - v31 = clamp(v31, 0.0f, 1.0f); + v31 = clamp_def(v31, 0.0f, 1.0f); } int32_t v33 = v0.field_0; @@ -8786,7 +8792,7 @@ static void sub_1403FA040(vec3* a1, float_t a2, mat4* a3, float_t ymin, if (fabsf(v16.z) > 0.000001f) { vec3_normalize(v16, v16); vec3_mult_scalar(v16, a2, v16); - v16.z = clamp(v16.z, zmin, zmax); + v16.z = clamp_def(v16.z, zmin, zmax); } goto LABEL_66; } @@ -8838,7 +8844,7 @@ static void sub_1403FA040(vec3* a1, float_t a2, mat4* a3, float_t ymin, if (fabsf(v16.y) > 0.000001f) { vec3_normalize(v16, v16); vec3_mult_scalar(v16, a2, v16); - v16.y = clamp(v16.y, ymin, ymax); + v16.y = clamp_def(v16.y, ymin, ymax); } goto LABEL_66; } @@ -9141,7 +9147,7 @@ static void sub_140406920(vec3* a1, bone_data* a2, bone_data* a3, float_t heel_h v12 = 0.0f; a2->ik_target.x = v18.x; - a2->ik_target.y = v18.y + lerp(v12, v11, a5->z); + a2->ik_target.y = v18.y + lerp_def(v12, v11, a5->z); a2->ik_target.z = v18.z; } @@ -9723,10 +9729,11 @@ static void rob_chara_bone_data_interpolate(rob_chara_bone_data* rob_bone_data) } static void rob_chara_bone_data_motion_blend_mot_free(rob_chara_bone_data* rob_bone_data) { - rob_bone_data->motion_indices.clear(); + rob_chara_bone_data_motion_blend_mot_list_free(rob_bone_data, 0); for (motion_blend_mot*& i : rob_bone_data->motions) delete i; rob_bone_data->motions.clear(); + rob_bone_data->motion_indices.clear(); } static void rob_chara_bone_data_motion_blend_mot_init(rob_chara_bone_data* rob_bone_data) { @@ -11925,7 +11932,7 @@ static void rob_chara_set_pv_data(rob_chara* rob_chr, int8_t chara_id, } static void rob_cmn_mottbl_read(void* a1, const void* data, size_t size) { - free(rob_cmn_mottbl_data); + free_def(rob_cmn_mottbl_data); farc f; f.read(data, size, true); @@ -12042,6 +12049,11 @@ bool pv_osage_manager_array_get_disp() { return disp; } +void pv_osage_manager_array_set_not_reset_true() { + for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) + pv_osage_manager_array_get(i)->SetNotReset(true); +} + void pv_osage_manager_array_set_pv_id(int32_t chara_id, int32_t pv_id, bool reset) { pv_osage_manager_array_get(chara_id)->SetPvId(pv_id, chara_id, reset); } @@ -12350,11 +12362,11 @@ void MotionBlendCross::Blend(bone_data* a2, bone_data* a3) { break; case BONE_DATABASE_BONE_POSITION_ROTATION: if (field_21) { - a2->trans.x = lerp(a3->trans.x, a2->trans.x, blend); - a2->trans.z = lerp(a3->trans.z, a2->trans.z, blend); + a2->trans.x = lerp_def(a3->trans.x, a2->trans.x, blend); + a2->trans.z = lerp_def(a3->trans.z, a2->trans.z, blend); } if (field_20) - a2->trans.y = lerp(a3->trans.y, a2->trans.y, blend); + a2->trans.y = lerp_def(a3->trans.y, a2->trans.y, blend); break; case BONE_DATABASE_BONE_HEAD_IK_ROTATION: if (a2->motion_bone_index == MOTION_BONE_CL_MUNE) { @@ -12520,11 +12532,11 @@ void MotionBlendFreeze::Blend(bone_data* a2, bone_data* a3) { break; case BONE_DATABASE_BONE_POSITION_ROTATION: if (field_21) { - a2->trans.x = lerp(a2->trans_prev[field_24].x, a2->trans.x, blend); - a2->trans.z = lerp(a2->trans_prev[field_24].z, a2->trans.z, blend); + a2->trans.x = lerp_def(a2->trans_prev[field_24].x, a2->trans.x, blend); + a2->trans.z = lerp_def(a2->trans_prev[field_24].z, a2->trans.z, blend); } if (field_20) - a2->trans.y = lerp(a2->trans_prev[field_24].y, a2->trans.y, blend); + a2->trans.y = lerp_def(a2->trans_prev[field_24].y, a2->trans.y, blend); break; case BONE_DATABASE_BONE_HEAD_IK_ROTATION: if (a2->motion_bone_index == MOTION_BONE_CL_MUNE) { @@ -13248,7 +13260,7 @@ void rob_chara_item_equip_object::reset_external_force() { void rob_chara_item_equip_object::set_alpha_draw_task_flags(float_t alpha, int32_t flags) { draw_task_flags = (::draw_task_flags)flags; - this->alpha = clamp(alpha, 0.0f, 1.0f); + this->alpha = clamp_def(alpha, 0.0f, 1.0f); } bool rob_chara_item_equip_object::set_boc( @@ -14412,6 +14424,21 @@ int32_t expression_id_to_mottbl_index(int32_t expression_id) { return 6; } +/* +195 CMN_HAND_OPEN 0 +196 CMN_HAND_CLOSE 1 +194 CMN_HAND_NORMAL 2 +197 CMN_HAND_PEACE 3 +201 CMN_HAND_NEGI 4 +198 CMN_HAND_MIC 5 +199 CMN_HAND_ONE 6 +202 CMN_HAND_SIZEN 7 +203 CMN_HAND_PICK 8 +192 (null) 9 +200 CMN_HAND_THREE 10 +204 CMN_HAND_MIC 11,12,13 +193 CMN_HAND_RESET 14*/ + int32_t hand_anim_id_to_mottbl_index(int32_t hand_anim_id) { static const int32_t hand_anim_id_to_mottbl_index_table[] = { 195, 196, 194, 197, 201, 198, 199, 202, @@ -15562,9 +15589,7 @@ bool OpdMaker::InitThread(rob_chara* rob_chr, std::vector* motion_ids, bool OpdMaker::IsWaiting() { std::unique_lock u_lock(waiting_mtx); - bool ret = waiting; - u_lock.unlock(); - return ret; + return waiting; } void OpdMaker::Reset() { @@ -15594,20 +15619,16 @@ bool OpdMaker::SetOsagePlayInitData(int32_t motion_id) { void OpdMaker::SetWaiting(bool value) { std::unique_lock u_lock(waiting_mtx); waiting = value; - u_lock.unlock(); } void OpdMaker::sub_140475AE0() { std::unique_lock u_lock(field_40); field_18 = true; - u_lock.unlock(); } bool OpdMaker::sub_140478330() { std::unique_lock u_lock(field_40); - bool ret = field_18; - u_lock.unlock(); - return ret; + return field_18; } void OpdMaker::ThreadMain(OpdMaker* opd_maker) { @@ -16191,15 +16212,21 @@ PvOsageManager::PvOsageManager() : state(), chara_id(), reset(), field_74(), motion_index(), pv(), thread(), disp(), not_reset(), exit(), field_D4() { Reset(); - std::unique_lock u_disp_mtx_lock(disp_mtx); - disp = false; - u_disp_mtx_lock.unlock(); - std::unique_lock u_not_reset_mtx_lock(not_reset_mtx); - not_reset = false; - u_not_reset_mtx_lock.unlock(); - std::unique_lock u_exit_mtx_lock(exit_mtx); - exit = false; - u_exit_mtx_lock.unlock(); + { + std::unique_lock u_lock(disp_mtx); + disp = false; + } + + { + std::unique_lock u_lock(not_reset_mtx); + not_reset = false; + } + + { + std::unique_lock u_lock(exit_mtx); + exit = false; + } + thread = new std::thread(PvOsageManager::ThreadMain, this); if (thread) { @@ -16210,9 +16237,11 @@ motion_index(), pv(), thread(), disp(), not_reset(), exit(), field_D4() { } PvOsageManager::~PvOsageManager() { - std::unique_lock u_lock(exit_mtx); - exit = true; - u_lock.unlock(); + { + std::unique_lock u_lock(exit_mtx); + exit = true; + } + cnd.notify_one(); thread->join(); delete thread; @@ -16275,45 +16304,38 @@ void PvOsageManager::AddMotionFrameResetData(int32_t stage_index, int32_t motion } bool PvOsageManager::CheckResetFrameNotFound(int32_t motion_id, float_t frame) { - return reset_frames_list.find(frame) == reset_frames_list.end(); + return reset_frames_list.find(frame) == reset_frames_list.end(); } bool PvOsageManager::GetDisp() { std::unique_lock u_lock(disp_mtx); - bool disp = this->disp; - u_lock.unlock(); return disp; } bool PvOsageManager::GetNotReset() { std::unique_lock u_lock(not_reset_mtx); - bool not_reset = this->not_reset; - u_lock.unlock(); return not_reset; } void PvOsageManager::SetDisp(bool value) { std::unique_lock u_lock(disp_mtx); disp = value; - u_lock.unlock(); } void PvOsageManager::SetNotReset(bool value) { std::unique_lock u_lock(not_reset_mtx); not_reset = value; - u_lock.unlock(); } void PvOsageManager::SetPvId(int32_t pv_id, int32_t chara_id, bool reset) { if (!pv_set_motion.size()) return; - HANDLE timer = timer_handle_init(); + waitable_timer timer; while (GetDisp()) { SetNotReset(true); - timer_handle_sleep(timer, 1.0); + timer.sleep(1); } - timer_handle_dispose(timer); SetDisp(true); SetNotReset(false); @@ -16329,7 +16351,7 @@ void PvOsageManager::SetPvId(int32_t pv_id, int32_t chara_id, bool reset) { } void PvOsageManager::SetPvSetMotion(std::vector& set_motion) { - pv_set_motion = set_motion; + pv_set_motion.assign(set_motion.begin(), set_motion.end()); } void PvOsageManager::sub_1404F77E0() { @@ -16343,6 +16365,7 @@ void PvOsageManager::sub_1404F77E0() { && i->frame_stage_index.first == i_next->frame_stage_index.first) { memmove(i, i_next, sizeof(pv_data_set_motion) * (i_end - i_next)); pv_set_motion.pop_back(); + i_end--; continue; } else { @@ -16406,18 +16429,21 @@ void PvOsageManager::Reset() { void PvOsageManager::sub_1404F82F0() { do { - std::unique_lock u_not_reset_lock(not_reset_mtx); - bool not_reset = this->not_reset; - u_not_reset_lock.unlock(); - if (not_reset) - break; + { + std::unique_lock u_lock(not_reset_mtx); + if (not_reset) + break; + } sub_1404F8AA0(); } while (sub_1404F7AF0()); - std::unique_lock u_not_reset_lock(not_reset_mtx); - bool not_reset = this->not_reset; - u_not_reset_lock.unlock(); + bool not_reset = false; + { + std::unique_lock u_lock(not_reset_mtx); + not_reset = this->not_reset; + } + sub_1404F7BD0(not_reset); } @@ -16618,26 +16644,29 @@ void PvOsageManager::ThreadMain(PvOsageManager* pv_osg_mgr) { std::unique_lock u_lock(pv_osg_mgr->mtx); while (true) { pv_osg_mgr->cnd.wait(u_lock); - std::unique_lock u_exit_lock(pv_osg_mgr->exit_mtx); - bool exit = pv_osg_mgr->exit; - u_exit_lock.unlock(); - if (exit) - break; + + { + std::unique_lock u_lock(pv_osg_mgr->exit_mtx); + if (pv_osg_mgr->exit) + break; + } pv_osg_mgr->sub_1404F82F0(); - std::unique_lock u_not_reset_lock(pv_osg_mgr->not_reset_mtx); - u_not_reset_lock.unlock(); + { + std::unique_lock u_lock(pv_osg_mgr->not_reset_mtx); + } - std::unique_lock u_disp_lock(pv_osg_mgr->disp_mtx); - pv_osg_mgr->disp = false; - u_disp_lock.unlock(); + { + std::unique_lock u_lock(pv_osg_mgr->disp_mtx); + pv_osg_mgr->disp = false; + } } - std::unique_lock u_disp_lock(pv_osg_mgr->disp_mtx); - pv_osg_mgr->disp = false; - u_disp_lock.unlock(); - u_lock.unlock(); + { + std::unique_lock u_lock(pv_osg_mgr->disp_mtx); + pv_osg_mgr->disp = false; + } } RobThreadParent::RobThreadParent() : exit(), thread() { @@ -16650,9 +16679,11 @@ RobThreadParent::RobThreadParent() : exit(), thread() { } RobThreadParent::~RobThreadParent() { - std::unique_lock u_lock(mtx); - exit = true; - u_lock.unlock(); + { + std::unique_lock u_lock(mtx); + exit = true; + } + cnd.notify_one(); thread->join(); delete thread; @@ -16666,7 +16697,6 @@ void RobThreadParent::AppendRobCharaFunc(rob_chara* rob_chr, void(*rob_chr_func) thrd.func = rob_chr_func; AppendRobThread(&thrd); cnd.notify_one(); - u_lock.unlock(); } void RobThreadHandler::sub_14054E3F0() { @@ -16677,26 +16707,24 @@ void RobThreadHandler::sub_14054E3F0() { void RobThreadParent::AppendRobThread(RobThread* thread) { std::unique_lock u_lock(threads_mtx); threads.push_back(*thread); - u_lock.unlock(); } bool RobThreadParent::CheckThreadsNotNull() { std::unique_lock u_lock(threads_mtx); - bool not_null = !!threads.size(); - u_lock.unlock(); - return not_null; + return !!threads.size(); } void RobThreadParent::sub_14054E0D0() { - std::unique_lock u_lock(threads_mtx); - threads.pop_front(); - bool v5 = this->threads.size() == 0; - u_lock.unlock(); + bool threads_null = false; + { + std::unique_lock u_lock(threads_mtx); + threads.pop_front(); + threads_null = threads.size() == 0; + } - if (v5) { + if (threads_null) { std::unique_lock u_lock(field_28); field_30.notify_one(); - u_lock.unlock(); } } @@ -16704,7 +16732,6 @@ void RobThreadParent::sub_14054E370() { std::unique_lock u_lock(field_28); if (CheckThreadsNotNull()) field_30.wait(u_lock); - u_lock.unlock(); } void RobThreadParent::ThreadMain(RobThreadParent* rob_thrd_parent) { @@ -16719,7 +16746,6 @@ void RobThreadParent::ThreadMain(RobThreadParent* rob_thrd_parent) { else rob_thrd_parent->cnd.wait(u_lock); } - u_lock.unlock(); } RobThreadHandler::RobThreadHandler() { @@ -18063,7 +18089,7 @@ static void sub_1404156B0(mot_play_data* a1) { switch (frame_data->field_1C) { case 0: default: - frame_data->frame = min(frame_data->frame, frame_data->frame_count); + frame_data->frame = min_def(frame_data->frame, frame_data->frame_count); break; case 1: { if (frame_data->field_24 >= 0.0f && frame_data->field_24 <= last_frame) diff --git a/src/CRE/rob/rob.hpp b/src/CRE/rob/rob.hpp index 89510cb6..a5ba3d54 100644 --- a/src/CRE/rob/rob.hpp +++ b/src/CRE/rob/rob.hpp @@ -3273,6 +3273,7 @@ extern void rob_chara_array_set_alpha_draw_task_flags(int32_t chara_id, float_t extern bool rob_chara_pv_data_array_check_chara_id(int32_t chara_id); extern bool pv_osage_manager_array_get_disp(); +extern void pv_osage_manager_array_set_not_reset_true(); extern void pv_osage_manager_array_set_pv_id(int32_t chara_id, int32_t pv_id, bool reset); extern void pv_osage_manager_array_set_pv_set_motion( int32_t chara_id, std::vector& set_motion); diff --git a/src/CRE/shader.cpp b/src/CRE/shader.cpp index 4e2b62a4..5418e797 100644 --- a/src/CRE/shader.cpp +++ b/src/CRE/shader.cpp @@ -4,6 +4,7 @@ */ #include "shader.hpp" +#include "../KKdLib/io/file_stream.hpp" #include "../KKdLib/io/path.hpp" #include "../KKdLib/hash.hpp" #include "../KKdLib/str_utils.hpp" @@ -100,7 +101,7 @@ env_update_data(), buffer_update_data(), state_ubo(), state_matrix_ubo(), env_ub } -int32_t shader::bind(uint32_t sub_index) { +int32_t shader::bind(shader_set_data* set, uint32_t sub_index) { int32_t sub_shader_index = 0; if (num_sub < 1) return -1; @@ -125,12 +126,12 @@ int32_t shader::bind(uint32_t sub_index) { int32_t i = 0; for (i = 0; i < num_uniform && i < 16; i++) { int32_t unival_max = use_permut[i] - ? max(vp_unival_max[i], fp_unival_max[i]) : 0; - unival += unival_curr * min(uniform_value[(int32_t)use_uniform[i]], unival_max); + ? max_def(vp_unival_max[i], fp_unival_max[i]) : 0; + unival += unival_curr * min_def(uniform_value[(int32_t)use_uniform[i]], unival_max); unival_curr *= unival_max + 1; - int32_t unival_max_glsl = max(vp_unival_max[i], fp_unival_max[i]); - uniform_val[i] = min(uniform_value[use_uniform[i]], unival_max_glsl); + int32_t unival_max_glsl = max_def(vp_unival_max[i], fp_unival_max[i]); + uniform_val[i] = min_def(uniform_value[use_uniform[i]], unival_max_glsl); } for (; i < 16; i++) @@ -260,8 +261,8 @@ void shader_set_data::load(farc* f, bool ignore_cache, bool not_load_cache, } if (!vert_data || !frag_data) { - free(vert_data); - free(frag_data); + free_def(vert_data); + free_def(frag_data); continue; } @@ -308,7 +309,7 @@ void shader_set_data::load(farc* f, bool ignore_cache, bool not_load_cache, const int32_t* fp_unival_max = sub_table->fp_unival_max; for (size_t k = 0; k < num_uniform; k++) { size_t unival_max = shader->use_permut[k] - ? max(vp_unival_max[k], fp_unival_max[k]) : 0; + ? max_def(vp_unival_max[k], fp_unival_max[k]) : 0; unival_count += unival_curr * unival_max; unival_curr *= unival_max + 1; } @@ -339,16 +340,16 @@ void shader_set_data::load(farc* f, bool ignore_cache, bool not_load_cache, for (size_t k = 0; k < unival_count; k++) { for (size_t l = 0, m = k; l < num_uniform; l++) { size_t unival_max = (size_t)(shader->use_permut[l] - ? max(vp_unival_max[l], fp_unival_max[l]) : 0) + 1; - vec_vert[l] = (uint32_t)(min(m % unival_max, vp_unival_max[l])); + ? max_def(vp_unival_max[l], fp_unival_max[l]) : 0) + 1; + vec_vert[l] = (uint32_t)(min_def(m % unival_max, vp_unival_max[l])); m /= unival_max; vert_buf[vert_buf_pos + l] = (char)('0' + vec_vert[l]); } for (size_t l = 0, m = k; l < num_uniform; l++) { size_t unival_max = (size_t)(shader->use_permut[l] - ? max(vp_unival_max[l], fp_unival_max[l]) : 0) + 1; - vec_frag[l] = (uint32_t)(min(m % unival_max, fp_unival_max[l])); + ? max_def(vp_unival_max[l], fp_unival_max[l]) : 0) + 1; + vec_frag[l] = (uint32_t)(min_def(m % unival_max, fp_unival_max[l])); m /= unival_max; frag_buf[frag_buf_pos + l] = (char)('0' + vec_frag[l]); } @@ -436,7 +437,7 @@ void shader_set_data::load(farc* f, bool ignore_cache, bool not_load_cache, shader_cache_file = &shader_cache_farc.files.back(); } else - free(shader_cache_file->data); + free_def(shader_cache_file->data); size_t bin_count = program_data_binary.size(); size_t bin_size = sizeof(uint64_t) * 2 + bin_count * sizeof(program_binary); @@ -459,14 +460,14 @@ void shader_set_data::load(farc* f, bool ignore_cache, bool not_load_cache, bin_data_base += sizeof(program_binary); bin_data += k.length; void* binary = (void*)k.binary; - free(binary); + free_def(binary); k.binary = 0; bin++; } } - free(vert_data); - free(frag_data); + free_def(vert_data); + free_def(frag_data); program_data_binary.clear(); } vec_vert.clear(); @@ -478,9 +479,9 @@ void shader_set_data::load(farc* f, bool ignore_cache, bool not_load_cache, break; } } - free(binary); - free(temp_vert); - free(temp_frag); + free_def(binary); + free_def(temp_vert); + free_def(temp_frag); if (shader_cache_changed) shader_cache_farc.write(temp_buf, FARC_COMPRESS_FArC, false); @@ -514,7 +515,7 @@ void shader_set_data::set(uint32_t index) { if (shader->bind_func) shader->bind_func(this, shader); else - shader->bind(shader->sub[0].sub_index); + shader->bind(this, shader->sub[0].sub_index); gl_state_bind_uniform_buffer_range(0, data.state_ubo, 0, sizeof(data.state)); gl_state_bind_uniform_buffer_range(1, data.state_matrix_ubo, 0, sizeof(data.state_matrix)); gl_state_bind_uniform_buffer_range(2, data.env_ubo, 0, sizeof(data.env)); @@ -544,7 +545,7 @@ void shader_set_data::unload() { const int32_t* fp_unival_max = sub->fp_unival_max; for (size_t k = 0; k < num_uniform; k++) { size_t unival_max = shader->use_permut[k] - ? max(vp_unival_max[k], fp_unival_max[k]) : 0; + ? max_def(vp_unival_max[k], fp_unival_max[k]) : 0; unival_count += unival_curr * unival_max; unival_curr *= unival_max + 1; } @@ -552,17 +553,17 @@ void shader_set_data::unload() { if (sub->program) for (size_t k = 0; k < unival_count; k++) glDeleteProgram(sub->program[k]); - free(sub->program); + free_def(sub->program); } else { if (sub->program) glDeleteProgram(sub->program[0]); - free(sub->program); + free_def(sub->program); } } - free(shader->sub); + free_def(shader->sub); } - free(shaders); + free_def(shaders); } void shader_set_data::buffer_get(size_t index, vec4& data) { @@ -1187,12 +1188,8 @@ void shader_set_data::state_light_set_ambient(size_t index, float_t x, float_t y this->data.state.light[index].ambient = data; this->data.state_update_data = true; - vec4 lightprod_front; - vec4 lightprod_back; - vec4_mult(this->data.state.light[index].ambient, - this->data.state.material[0].ambient, lightprod_front); - vec4_mult(this->data.state.light[index].ambient, - this->data.state.material[1].ambient, lightprod_back); + vec4 lightprod_front = this->data.state.light[index].ambient * this->data.state.material[0].ambient; + vec4 lightprod_back = this->data.state.light[index].ambient * this->data.state.material[1].ambient; state_lightprod_set_ambient(false, index, lightprod_front); state_lightprod_set_ambient(true, index, lightprod_back); } @@ -1207,12 +1204,8 @@ void shader_set_data::state_light_set_ambient(size_t index, const vec4& data) { this->data.state.light[index].ambient = data; this->data.state_update_data = true; - vec4 lightprod_front; - vec4 lightprod_back; - vec4_mult(this->data.state.light[index].ambient, - this->data.state.material[0].ambient, lightprod_front); - vec4_mult(this->data.state.light[index].ambient, - this->data.state.material[1].ambient, lightprod_back); + vec4 lightprod_front = this->data.state.light[index].ambient * this->data.state.material[0].ambient; + vec4 lightprod_back = this->data.state.light[index].ambient * this->data.state.material[1].ambient; state_lightprod_set_ambient(false, index, lightprod_front); state_lightprod_set_ambient(true, index, lightprod_back); } @@ -1228,12 +1221,8 @@ void shader_set_data::state_light_set_diffuse(size_t index, float_t x, float_t y this->data.state.light[index].diffuse = data; this->data.state_update_data = true; - vec4 lightprod_front; - vec4 lightprod_back; - vec4_mult(this->data.state.light[index].diffuse, - this->data.state.material[0].diffuse, lightprod_front); - vec4_mult(this->data.state.light[index].diffuse, - this->data.state.material[1].diffuse, lightprod_back); + vec4 lightprod_front = this->data.state.light[index].diffuse * this->data.state.material[0].diffuse; + vec4 lightprod_back = this->data.state.light[index].diffuse * this->data.state.material[1].diffuse; state_lightprod_set_diffuse(false, index, lightprod_front); state_lightprod_set_diffuse(true, index, lightprod_back); } @@ -1248,12 +1237,8 @@ void shader_set_data::state_light_set_diffuse(size_t index, const vec4& data) { this->data.state.light[index].diffuse = data; this->data.state_update_data = true; - vec4 lightprod_front; - vec4 lightprod_back; - vec4_mult(this->data.state.light[index].diffuse, - this->data.state.material[0].diffuse, lightprod_front); - vec4_mult(this->data.state.light[index].diffuse, - this->data.state.material[1].diffuse, lightprod_back); + vec4 lightprod_front = this->data.state.light[index].diffuse * this->data.state.material[0].diffuse; + vec4 lightprod_back = this->data.state.light[index].diffuse * this->data.state.material[1].diffuse; state_lightprod_set_diffuse(false, index, lightprod_front); state_lightprod_set_diffuse(true, index, lightprod_back); } @@ -1269,12 +1254,8 @@ void shader_set_data::state_light_set_specular(size_t index, float_t x, float_t this->data.state.light[index].specular = data; this->data.state_update_data = true; - vec4 lightprod_front; - vec4 lightprod_back; - vec4_mult(this->data.state.light[index].specular, - this->data.state.material[0].specular, lightprod_front); - vec4_mult(this->data.state.light[index].specular, - this->data.state.material[1].specular, lightprod_back); + vec4 lightprod_front = this->data.state.light[index].specular * this->data.state.material[0].diffuse; + vec4 lightprod_back = this->data.state.light[index].specular * this->data.state.material[1].diffuse; state_lightprod_set_specular(false, index, lightprod_front); state_lightprod_set_specular(true, index, lightprod_back); } @@ -1289,12 +1270,8 @@ void shader_set_data::state_light_set_specular(size_t index, const vec4& data) { this->data.state.light[index].specular = data; this->data.state_update_data = true; - vec4 lightprod_front; - vec4 lightprod_back; - vec4_mult(this->data.state.light[index].specular, - this->data.state.material[0].specular, lightprod_front); - vec4_mult(this->data.state.light[index].specular, - this->data.state.material[1].specular, lightprod_back); + vec4 lightprod_front = this->data.state.light[index].specular * this->data.state.material[0].diffuse; + vec4 lightprod_back = this->data.state.light[index].specular * this->data.state.material[1].diffuse; state_lightprod_set_specular(false, index, lightprod_front); state_lightprod_set_specular(true, index, lightprod_back); } @@ -1540,9 +1517,8 @@ void shader_set_data::state_material_set_ambient(bool back, float_t x, float_t y this->data.state_update_data = true; for (int32_t index = 0; index < SHADER_MAX_LIGHTS; index++) { - vec4 lightprod; - vec4_mult(this->data.state.light[index].ambient, - this->data.state.material[back ? 1 : 0].ambient, lightprod); + vec4 lightprod = this->data.state.light[index].ambient + * this->data.state.material[back ? 1 : 0].ambient; state_lightprod_set_ambient(back, index, lightprod); } } @@ -1558,9 +1534,8 @@ void shader_set_data::state_material_set_ambient(bool back, const vec4& data) { this->data.state_update_data = true; for (int32_t index = 0; index < SHADER_MAX_LIGHTS; index++) { - vec4 lightprod; - vec4_mult(this->data.state.light[index].ambient, - this->data.state.material[back ? 1 : 0].ambient, lightprod); + vec4 lightprod = this->data.state.light[index].ambient + * this->data.state.material[back ? 1 : 0].ambient; state_lightprod_set_ambient(back, index, lightprod); } } @@ -1575,11 +1550,10 @@ void shader_set_data::state_material_set_diffuse(bool back, float_t x, float_t y this->data.state.material[back ? 1 : 0].diffuse = data; this->data.state_update_data = true; - vec4 lightprod; for (int32_t index = 0; index < SHADER_MAX_LIGHTS; index++) { - vec4_mult(this->data.state.light[index].diffuse, - this->data.state.material[back ? 1 : 0].diffuse, lightprod); + vec4 lightprod = this->data.state.light[index].diffuse + * this->data.state.material[back ? 1 : 0].diffuse; state_lightprod_set_diffuse(back, index, lightprod); } } @@ -1595,9 +1569,8 @@ void shader_set_data::state_material_set_diffuse(bool back, const vec4& data) { this->data.state_update_data = true; for (int32_t index = 0; index < SHADER_MAX_LIGHTS; index++) { - vec4 lightprod; - vec4_mult(this->data.state.light[index].diffuse, - this->data.state.material[back ? 1 : 0].diffuse, lightprod); + vec4 lightprod = this->data.state.light[index].diffuse + * this->data.state.material[back ? 1 : 0].diffuse; state_lightprod_set_diffuse(back, index, lightprod); } } @@ -1614,9 +1587,8 @@ void shader_set_data::state_material_set_specular(bool back, float_t x, float_t this->data.state_update_data = true; for (int32_t index = 0; index < SHADER_MAX_LIGHTS; index++) { - vec4 lightprod; - vec4_mult(this->data.state.light[index].specular, - this->data.state.material[back ? 1 : 0].specular, lightprod); + vec4 lightprod = this->data.state.light[index].specular + * this->data.state.material[back ? 1 : 0].specular; state_lightprod_set_specular(back, index, lightprod); } } @@ -1632,9 +1604,8 @@ void shader_set_data::state_material_set_specular(bool back, const vec4& data) { this->data.state_update_data = true; for (int32_t index = 0; index < SHADER_MAX_LIGHTS; index++) { - vec4 lightprod; - vec4_mult(this->data.state.light[index].specular, - this->data.state.material[back ? 1 : 0].specular, lightprod); + vec4 lightprod = this->data.state.light[index].specular + * this->data.state.material[back ? 1 : 0].specular; state_lightprod_set_specular(back, index, lightprod); } } @@ -2118,7 +2089,7 @@ static GLuint shader_compile_shader(GLenum type, const char* data, const char* f printf("file: %s\n", file); printf(info_log); putchar('\n'); - free(info_log); + free_def(info_log); glDeleteShader(shader); #if defined(CRE_DEV) @@ -2138,7 +2109,7 @@ static GLuint shader_compile_shader(GLenum type, const char* data, const char* f L"%ls\\shader_error\\%hs", temp_buf, file); buf[sizeof(buf) / sizeof(wchar_t) - 1] = 0; - stream s; + file_stream s; s.open(buf, L"wb"); s.write(data, utf8_length(data)); } @@ -2173,7 +2144,7 @@ static GLuint shader_compile(const char* vert, const char* frag, const char* vp, printf("vp: %s; fp: %s\n", vp, fp); printf(info_log); putchar('\n'); - free(info_log); + free_def(info_log); glDeleteProgram(program); return 0; } @@ -2211,7 +2182,7 @@ static GLuint shader_compile_binary(const char* vert, const char* frag, const ch printf("vp: %s; fp: %s\n", vp, fp); printf(info_log); putchar('\n'); - free(info_log); + free_def(info_log); glDeleteProgram(program); return 0; } @@ -2225,7 +2196,7 @@ static GLuint shader_compile_binary(const char* vert, const char* frag, const ch if (!glGetError()) break; - free(*binary); + free_def(*binary); *buffer_size <<= 1; *binary = force_malloc(*buffer_size); } @@ -2274,7 +2245,7 @@ static bool shader_parse_define(const char* data, int32_t num_uniform, len += len_a + len_b; if (len + 1 > *temp_size) { - free(*temp); + free_def(*temp); *temp_size = len + 1; *temp = force_malloc_s(char, *temp_size); } @@ -2288,7 +2259,7 @@ static bool shader_parse_define(const char* data, int32_t num_uniform, return true; } - const int32_t s = min(0x100, num_uniform); + const int32_t s = min_def(0x100, num_uniform); size_t t_len[0x100]; char t[0x100]; @@ -2310,7 +2281,7 @@ static bool shader_parse_define(const char* data, int32_t num_uniform, len += len_a + len_b; if (len + 1 > *temp_size) { - free(*temp); + free_def(*temp); *temp_size = len + 1; *temp = force_malloc_s(char, *temp_size); } @@ -2353,10 +2324,10 @@ static char* shader_parse_include(char* data, farc* f) { char** temp_ptr0 = force_malloc_s(char*, count); char** temp_ptr1 = force_malloc_s(char*, count); if (!temp || !temp_len || !temp_ptr0 || !temp_ptr1) { - free(temp); - free(temp_len); - free(temp_ptr0); - free(temp_ptr1); + free_def(temp); + free_def(temp_len); + free_def(temp_ptr0); + free_def(temp_ptr1); return data; } @@ -2381,7 +2352,7 @@ static char* shader_parse_include(char* data, farc* f) { t[s] = 0; farc_file* ff = f->read_file(t); - free(t); + free_def(t); if (!ff) continue; @@ -2430,13 +2401,13 @@ static char* shader_parse_include(char* data, farc* f) { } temp_data[pos] = 0; - free(data); + free_def(data); for (size_t i = 0; i < count; i++) - free(temp[i]); - free(temp); - free(temp_len); - free(temp_ptr0); - free(temp_ptr1); + free_def(temp[i]); + free_def(temp); + free_def(temp_len); + free_def(temp_ptr0); + free_def(temp_ptr1); return temp_data; } diff --git a/src/CRE/shader.hpp b/src/CRE/shader.hpp index e0d632f9..f1139c7c 100644 --- a/src/CRE/shader.hpp +++ b/src/CRE/shader.hpp @@ -229,7 +229,7 @@ struct shader { const bool* use_permut; PFNSHADERBINDFUNCPROC bind_func; - int32_t bind(uint32_t sub_index); + int32_t bind(shader_set_data* set, uint32_t sub_index); static void unbind(); }; diff --git a/src/CRE/shader_ft.cpp b/src/CRE/shader_ft.cpp index fbfe9b2a..7f20f95f 100644 --- a/src/CRE/shader_ft.cpp +++ b/src/CRE/shader_ft.cpp @@ -7,75 +7,78 @@ #include "gl_state.hpp" enum shader_ft_sub_enum { - SHADER_FT_SUB_SHADER_FFP = 0x00, - SHADER_FT_SUB_BLINN_VERT = 0x01, - SHADER_FT_SUB_BLINN_FRAG = 0x02, - SHADER_FT_SUB_ITEM_BLINN = 0x03, - SHADER_FT_SUB_STAGE_BLINN = 0x04, - SHADER_FT_SUB_SKIN_DEFAULT = 0x05, - SHADER_FT_SUB_SSS_SKIN = 0x06, - SHADER_FT_SUB_SSS_FILTER = 0x07, - SHADER_FT_SUB_HAIR_DEFAULT = 0x08, - SHADER_FT_SUB_HAIR_ANISO = 0x09, - SHADER_FT_SUB_HAIR_NPR1 = 0x0A, - SHADER_FT_SUB_CLOTH_DEFAULT = 0x0B, - SHADER_FT_SUB_CLOTH_ANISO = 0x0C, - SHADER_FT_SUB_CLOTH_NPR1 = 0x0D, - SHADER_FT_SUB_TIGHTS = 0x0E, - SHADER_FT_SUB_SKY_DEFAULT = 0x0F, - SHADER_FT_SUB_EYE_BALL = 0x10, - SHADER_FT_SUB_EYE_LENS = 0x11, - SHADER_FT_SUB_GLASS_EYE = 0x12, - SHADER_FT_SUB_MEMBRANE = 0x13, - SHADER_FT_SUB_SHADOWMAP = 0x14, - SHADER_FT_SUB_ESM = 0x15, - SHADER_FT_SUB_ESM_GAUSS = 0x16, - SHADER_FT_SUB_ESM_FILTER = 0x17, - SHADER_FT_SUB_LIT_PROJ = 0x18, - SHADER_FT_SUB_SIMPLE = 0x19, - SHADER_FT_SUB_SILHOUETTE = 0x1A, - SHADER_FT_SUB_LAMBERT = 0x1B, - SHADER_FT_SUB_CONSTANT = 0x1C, - SHADER_FT_SUB_PEEL = 0x1D, - SHADER_FT_SUB_TONEMAP = 0x1E, - SHADER_FT_SUB_TONEMAP_NPR1 = 0x1F, - SHADER_FT_SUB_REDUCE_TEX = 0x20, - SHADER_FT_SUB_MAGNIFY = 0x21, - SHADER_FT_SUB_MLAA = 0x22, - SHADER_FT_SUB_CONTOUR = 0x23, - SHADER_FT_SUB_EXPOSURE = 0x24, - SHADER_FT_SUB_PP_GAUSS = 0x25, - SHADER_FT_SUB_SUN = 0x26, - SHADER_FT_SUB_FADE = 0x27, - SHADER_FT_SUB_WATER01 = 0x28, - SHADER_FT_SUB_WATER02 = 0x29, - SHADER_FT_SUB_WATER_RING = 0x2A, - SHADER_FT_SUB_WATER_PARTICLE = 0x2B, - SHADER_FT_SUB_SNOW_PARTICLE = 0x2C, - SHADER_FT_SUB_LEAF_PARTICLE = 0x2D, - SHADER_FT_SUB_STAR = 0x2E, - SHADER_FT_SUB_SNOW_RING = 0x2F, - SHADER_FT_SUB_SNOW_FOOTPRINT = 0x30, - SHADER_FT_SUB_SNOW_TEX_SPACE_LIGHT = 0x31, - SHADER_FT_SUB_SNOW_CALC_NORMAL = 0x32, - SHADER_FT_SUB_FLOOR = 0x33, - SHADER_FT_SUB_PUDDLE = 0x34, - SHADER_FT_SUB_SIMPLE_REFLECT = 0x35, - SHADER_FT_SUB_SIMPLE_REFRACT = 0x36, - SHADER_FT_SUB_RIPPLE_EMIT = 0x37, - SHADER_FT_SUB_RAIN = 0x38, - SHADER_FT_SUB_VOLUME_LIGHT = 0x39, - SHADER_FT_SUB_FENCE_ALPHA = 0x3A, - SHADER_FT_SUB_RIPPLE = 0x3B, - SHADER_FT_SUB_FOG_PTCL = 0x3C, - SHADER_FT_SUB_PARTICLE = 0x3D, - SHADER_FT_SUB_GLITTER_PARTICLE = 0x3E, - SHADER_FT_SUB_SHOW_VECTOR = 0x3F, - SHADER_FT_SUB_FONT = 0x40, - SHADER_FT_SUB_MOVIE = 0x41, - SHADER_FT_SUB_IMGFILTER = 0x42, - SHADER_FT_SUB_SPRITE = 0x43, - SHADER_FT_SUB_SHADER_END = 0x44, + SHADER_FT_SUB_SHADER_FFP = 0, + SHADER_FT_SUB_BLINN_VERT, + SHADER_FT_SUB_BLINN_FRAG, + SHADER_FT_SUB_ITEM_BLINN, + SHADER_FT_SUB_STAGE_BLINN, + SHADER_FT_SUB_SKIN_DEFAULT, + SHADER_FT_SUB_SSS_SKIN, + SHADER_FT_SUB_SSS_FILTER, + SHADER_FT_SUB_HAIR_DEFAULT, + SHADER_FT_SUB_HAIR_ANISO, + SHADER_FT_SUB_HAIR_NPR1, + SHADER_FT_SUB_CLOTH_DEFAULT, + SHADER_FT_SUB_CLOTH_ANISO, + SHADER_FT_SUB_CLOTH_NPR1, + SHADER_FT_SUB_TIGHTS, + SHADER_FT_SUB_SKY_DEFAULT, + SHADER_FT_SUB_EYE_BALL, + SHADER_FT_SUB_EYE_LENS, + SHADER_FT_SUB_GLASS_EYE, + SHADER_FT_SUB_MEMBRANE, + SHADER_FT_SUB_SHADOWMAP, + SHADER_FT_SUB_ESM, + SHADER_FT_SUB_ESM_GAUSS, + SHADER_FT_SUB_ESM_FILTER, + SHADER_FT_SUB_LIT_PROJ, + SHADER_FT_SUB_SIMPLE, + SHADER_FT_SUB_SILHOUETTE, + SHADER_FT_SUB_LAMBERT, + SHADER_FT_SUB_CONSTANT, + SHADER_FT_SUB_PEEL, + SHADER_FT_SUB_TONEMAP, + SHADER_FT_SUB_TONEMAP_NPR1, + SHADER_FT_SUB_REDUCE_TEX, + SHADER_FT_SUB_MAGNIFY, + //SHADER_FT_SUB_MLAA, + SHADER_FT_SUB_MLAA_EDGE, + SHADER_FT_SUB_MLAA_AREA, + SHADER_FT_SUB_MLAA_BLEND, + SHADER_FT_SUB_CONTOUR, + SHADER_FT_SUB_EXPOSURE, + SHADER_FT_SUB_PP_GAUSS, + SHADER_FT_SUB_SUN, + SHADER_FT_SUB_FADE, + SHADER_FT_SUB_WATER01, + SHADER_FT_SUB_WATER02, + SHADER_FT_SUB_WATER_RING, + SHADER_FT_SUB_WATER_PARTICLE, + SHADER_FT_SUB_SNOW_PARTICLE, + SHADER_FT_SUB_LEAF_PARTICLE, + SHADER_FT_SUB_STAR, + SHADER_FT_SUB_SNOW_RING, + SHADER_FT_SUB_SNOW_FOOTPRINT, + SHADER_FT_SUB_SNOW_TEX_SPACE_LIGHT, + SHADER_FT_SUB_SNOW_CALC_NORMAL, + SHADER_FT_SUB_FLOOR, + SHADER_FT_SUB_PUDDLE, + SHADER_FT_SUB_SIMPLE_REFLECT, + SHADER_FT_SUB_SIMPLE_REFRACT, + SHADER_FT_SUB_RIPPLE_EMIT, + SHADER_FT_SUB_RAIN, + SHADER_FT_SUB_VOLUME_LIGHT, + SHADER_FT_SUB_FENCE_ALPHA, + SHADER_FT_SUB_RIPPLE, + SHADER_FT_SUB_FOG_PTCL, + SHADER_FT_SUB_PARTICLE, + SHADER_FT_SUB_GLITTER_PARTICLE, + SHADER_FT_SUB_SHOW_VECTOR, + SHADER_FT_SUB_FONT, + SHADER_FT_SUB_MOVIE, + SHADER_FT_SUB_IMGFILTER, + SHADER_FT_SUB_SPRITE, + SHADER_FT_SUB_SHADER_END, }; static const int32_t blinn_vert_vpt_unival_max[] = { @@ -342,12 +345,38 @@ static const int32_t magnify_fpt_unival_max[] = { 7, }; -static const int32_t mlaa_vpt_unival_max[] = { - 0, 0, 2, 0, +/*static const int32_t mlaa_vpt_unival_max[] = { + //0, 0, 2, 0, + 0, 2, 0, // 1st removed }; static const int32_t mlaa_fpt_unival_max[] = { - 1, 1, 2, 2, + //1, 1, 2, 2, + 1, 2, 2, // 1st removed +};*/ + +static const int32_t mlaa_edge_vpt_unival_max[] = { + 0, +}; + +static const int32_t mlaa_edge_fpt_unival_max[] = { + 1, +}; + +static const int32_t mlaa_area_vpt_unival_max[] = { + 0, +}; + +static const int32_t mlaa_area_fpt_unival_max[] = { + 2, +}; + +static const int32_t mlaa_blend_vpt_unival_max[] = { + 0, +}; + +static const int32_t mlaa_blend_fpt_unival_max[] = { + 1, }; static const int32_t contour_vpt_unival_max[] = { @@ -926,7 +955,7 @@ static const shader_sub_table MAGNIFY_table[] = { }, }; -static const shader_sub_table MLAA_table[] = { +/*static const shader_sub_table MLAA_table[] = { { SHADER_FT_SUB_MLAA, mlaa_vpt_unival_max, @@ -934,6 +963,36 @@ static const shader_sub_table MLAA_table[] = { "mlaa", "mlaa", }, +};*/ + +static const shader_sub_table MLAA_EDGE_table[] = { + { + SHADER_FT_SUB_MLAA_EDGE, + mlaa_edge_vpt_unival_max, + mlaa_edge_fpt_unival_max, + "mlaa_edge", + "mlaa_edge", + }, +}; + +static const shader_sub_table MLAA_AREA_table[] = { + { + SHADER_FT_SUB_MLAA_AREA, + mlaa_area_vpt_unival_max, + mlaa_area_fpt_unival_max, + "mlaa_area", + "mlaa_area", + }, +}; + +static const shader_sub_table MLAA_BLEND_table[] = { + { + SHADER_FT_SUB_MLAA_BLEND, + mlaa_blend_vpt_unival_max, + mlaa_blend_fpt_unival_max, + "mlaa_blend", + "mlaa_blend", + }, }; static const shader_sub_table CONTOUR_table[] = { @@ -1524,18 +1583,30 @@ static const uniform_name TONEMAP_uniform[] = { static const uniform_name REDUCE_uniform[] = { U_REDUCE, - U01, + U_ALPHA_MASK, }; static const uniform_name MAGNIFY_uniform[] = { U_MAGNIFY, }; -static const uniform_name MLAA_uniform[] = { - U16, - U01, +/*static const uniform_name MLAA_uniform[] = { + //U16, // 1st removed + U_ALPHA_MASK, U_MLAA, - U20, + U_MLAA_SEARCH, +};*/ + +static const uniform_name MLAA_EDGE_uniform[] = { + U_ALPHA_MASK, +}; + +static const uniform_name MLAA_AREA_uniform[] = { + U_MLAA_SEARCH, +}; + +static const uniform_name MLAA_BLEND_uniform[] = { + U_ALPHA_MASK, }; static const uniform_name CONTOUR_uniform[] = { @@ -1786,8 +1857,8 @@ static const bool SSS_SKIN_permut[] = { static const bool SSS_FILT_permut[] = { true, - false, - false, + true, + true, }; static const bool HAIR_permut[] = { @@ -1969,32 +2040,44 @@ static const bool TONEMAP_permut[] = { }; static const bool REDUCE_permut[] = { - false, - false, + true, + true, }; static const bool MAGNIFY_permut[] = { - false, + true, }; -static const bool MLAA_permut[] = { - false, - false, +/*static const bool MLAA_permut[] = { + //true, // 1st removed true, true, + true, +};*/ + +static const bool MLAA_EDGE_permut[] = { + true, +}; + +static const bool MLAA_AREA_permut[] = { + true, +}; + +static const bool MLAA_BLEND_permut[] = { + true, }; static const bool CONTOUR_permut[] = { - false, + true, false, }; static const bool EXPOSURE_permut[] = { - false, + true, }; static const bool GAUSS_permut[] = { - false, + true, }; static const bool SUN_permut[] = { @@ -2150,7 +2233,7 @@ static const bool MOVIE_permut[] = { }; static const bool IMGFILT_permut[] = { - false, + true, }; static const bool SPRITE_permut[] = { @@ -2236,7 +2319,10 @@ static const shader_table shader_ft_table[] = { shader_table_struct(TONEMAP), shader_table_struct(REDUCE), shader_table_struct(MAGNIFY), - shader_table_struct(MLAA), + //shader_table_struct(MLAA), + shader_table_struct(MLAA_EDGE), + shader_table_struct(MLAA_AREA), + shader_table_struct(MLAA_BLEND), shader_table_struct(CONTOUR), shader_table_struct(EXPOSURE), shader_table_struct(GAUSS), @@ -2356,9 +2442,9 @@ static void glass_eye_calc(glass_eye_struct* glass_eye) { float_t v2 = glass_eye->field_28; glass_eye->field_64 = glass_eye->field_2C / v2; glass_eye->field_90 = glass_eye->field_58; - vec3_mult_scalar(glass_eye->field_30, v2, glass_eye->field_68); - vec3_mult_scalar(glass_eye->field_3C, v2, glass_eye->field_74); - vec3_mult_scalar(glass_eye->field_48, v2, glass_eye->field_80); + glass_eye->field_68 = glass_eye->field_30 * v2; + glass_eye->field_74 = glass_eye->field_3C * v2; + glass_eye->field_80 = glass_eye->field_48 * v2; glass_eye->field_8C = glass_eye->field_54 * v2; if (glass_eye->field_B0 == 0) { glass_eye->field_A0 = vec4_null; @@ -2386,9 +2472,9 @@ static void glass_eye_calc(glass_eye_struct* glass_eye) { static void glass_eye_set(glass_eye_struct* glass_eye, shader_set_data* set) { vec4 temp; - vec3_mult(glass_eye->field_68, glass_eye->field_68, *(vec3*)&temp); + *(vec3*)&temp = glass_eye->field_68 * glass_eye->field_68; temp.w = temp.z; - vec3_div(vec3_identity, *(vec3*)&temp, *(vec3*)&temp); + *(vec3*)&temp = vec3::rcp(*(vec3*)&temp); set->local_vert_set(0x0A, temp); set->local_frag_set(0x0A, temp); @@ -2402,17 +2488,17 @@ static void glass_eye_set(glass_eye_struct* glass_eye, shader_set_data* set) { temp = glass_eye->field_A0; set->local_vert_set(0x0D, temp); - vec3_mult(glass_eye->field_90, glass_eye->field_90, *(vec3*)&temp); + *(vec3*)&temp = glass_eye->field_90 * glass_eye->field_90; temp.w = temp.z; - vec3_div(vec3_identity, *(vec3*)&temp, *(vec3*)&temp); + *(vec3*)&temp = vec3::rcp(*(vec3*)&temp); set->local_vert_set(0x0E, temp); temp = glass_eye->field_10; set->local_vert_set(0x0F, temp); - vec3_mult(glass_eye->field_68, glass_eye->field_68, *(vec3*)&temp); + *(vec3*)&temp = glass_eye->field_68 * glass_eye->field_68; temp.w = temp.z; - vec3_div(vec3_identity, *(vec3*)&temp, *(vec3*)&temp); + *(vec3*)&temp = vec3::rcp(*(vec3*)&temp); set->local_vert_set(0x0E, temp); float_t v2 = (glass_eye->field_20 - glass_eye->field_24) / (glass_eye->field_20 + glass_eye->field_24); @@ -2425,46 +2511,46 @@ static void glass_eye_set(glass_eye_struct* glass_eye, shader_set_data* set) { float_t v4 = (glass_eye->field_24 * glass_eye->field_24) / (glass_eye->field_20 * glass_eye->field_20); set->local_frag_set(0x0E, v4, 1.0f - v4, glass_eye->field_24 / glass_eye->field_20, 0.0f); - vec3_mult(glass_eye->field_74, glass_eye->field_74, *(vec3*)&temp); + *(vec3*)&temp = glass_eye->field_74 * glass_eye->field_74; temp.w = -1.0f; - vec3_div(vec3_identity, *(vec3*)&temp, *(vec3*)&temp); + *(vec3*)&temp = vec3::rcp(*(vec3*)&temp); set->local_frag_set(0x0F, temp); - vec3_mult(glass_eye->field_68, glass_eye->field_68, *(vec3*)&temp); + *(vec3*)&temp = glass_eye->field_68 * glass_eye->field_68; temp.w = -1.0f; - vec3_div(vec3_identity, *(vec3*)&temp, *(vec3*)&temp); + *(vec3*)&temp = vec3::rcp(*(vec3*)&temp); set->local_frag_set(0x10, temp); - vec3_mult(glass_eye->field_80, glass_eye->field_80, *(vec3*)&temp); + *(vec3*)&temp = glass_eye->field_80 * glass_eye->field_80; temp.w = -1.0f; - vec3_div(vec3_identity, *(vec3*)&temp, *(vec3*)&temp); + *(vec3*)&temp = vec3::rcp(*(vec3*)&temp); set->local_frag_set(0x11, temp); - vec2_mult(*(vec2*)&glass_eye->field_0, *(vec2*)&glass_eye->field_74, *(vec2*)&temp); + *(vec2*)&temp = *(vec2*)&glass_eye->field_0 * *(vec2*)&glass_eye->field_74; temp.z = glass_eye->field_64 * 1.442695f; temp.w = glass_eye->field_8C; - vec2_div(vec2_identity, *(vec2*)&temp, *(vec2*)&temp); + *(vec2*)&temp = vec2::rcp(*(vec2*)&temp); set->local_frag_set(0x12, temp); } static void shader_bind_blinn(shader_set_data* set, shader* shad) { - shad->bind(uniform_value[U_NORMAL] + shad->bind(set, uniform_value[U_NORMAL] ? SHADER_FT_SUB_BLINN_FRAG : SHADER_FT_SUB_BLINN_VERT); } static void shader_bind_cloth(shader_set_data* set, shader* shad) { - shad->bind(uniform_value[U_NPR] ? SHADER_FT_SUB_CLOTH_NPR1 + shad->bind(set, uniform_value[U_NPR] ? SHADER_FT_SUB_CLOTH_NPR1 : (uniform_value[U_ANISO] ? SHADER_FT_SUB_CLOTH_ANISO : SHADER_FT_SUB_CLOTH_DEFAULT)); } static void shader_bind_hair(shader_set_data* set, shader* shad) { - shad->bind(uniform_value[U_NPR] ? SHADER_FT_SUB_HAIR_NPR1 + shad->bind(set, uniform_value[U_NPR] ? SHADER_FT_SUB_HAIR_NPR1 : (uniform_value[U_ANISO] ? SHADER_FT_SUB_HAIR_ANISO : SHADER_FT_SUB_HAIR_DEFAULT)); } static void shader_bind_membrane(shader_set_data* set, shader* shad) { uniform_value[U_MEMBRANE] = 3; - if (shad->bind(SHADER_FT_SUB_MEMBRANE) < 0) + if (shad->bind(set, SHADER_FT_SUB_MEMBRANE) < 0) return; /*uint32_t(* sub_140192E00)() = (void*)0x0000000140192E00; @@ -2481,13 +2567,13 @@ static void shader_bind_membrane(shader_set_data* set, shader* shad) { static void shader_bind_eye_ball(shader_set_data* set, shader* shad) { uniform_value[U18] = 0; - if (set->shaders[SHADER_FT_GLASEYE].bind(SHADER_FT_SUB_GLASS_EYE) >= 0) { + if (set->shaders[SHADER_FT_GLASEYE].bind(set, SHADER_FT_SUB_GLASS_EYE) >= 0) { glass_eye_calc(&glass_eye); glass_eye_set(&glass_eye, set); } } static void shader_bind_tone_map(shader_set_data* set, shader* shad) { - shad->bind(uniform_value[U_NPR] == 1 + shad->bind(set, uniform_value[U_NPR] == 1 ? SHADER_FT_SUB_TONEMAP_NPR1 : SHADER_FT_SUB_TONEMAP); } diff --git a/src/CRE/shader_ft.hpp b/src/CRE/shader_ft.hpp index e7343239..dcf2bb4d 100644 --- a/src/CRE/shader_ft.hpp +++ b/src/CRE/shader_ft.hpp @@ -9,69 +9,72 @@ #include "shader.hpp" enum shader_ft_enum { - SHADER_FT_FFP = 0x00, - SHADER_FT_BLINN = 0x01, - SHADER_FT_ITEM = 0x02, - SHADER_FT_STAGE = 0x03, - SHADER_FT_SKIN = 0x04, - SHADER_FT_SSS_SKIN = 0x05, - SHADER_FT_SSS_FILT = 0x06, - SHADER_FT_HAIR = 0x07, - SHADER_FT_CLOTH = 0x08, - SHADER_FT_TIGHTS = 0x09, - SHADER_FT_SKY = 0x0A, - SHADER_FT_EYEBALL = 0x0B, - SHADER_FT_EYELENS = 0x0C, - SHADER_FT_GLASEYE = 0x0D, - SHADER_FT_MEMBRAN = 0x0E, - SHADER_FT_SHDMAP = 0x0F, - SHADER_FT_ESM = 0x10, - SHADER_FT_ESMGAUSS = 0x11, - SHADER_FT_ESMFILT = 0x12, - SHADER_FT_LITPROJ = 0x13, - SHADER_FT_SIMPLE = 0x14, - SHADER_FT_SIL = 0x15, - SHADER_FT_LAMBERT = 0x16, - SHADER_FT_CONSTANT = 0x17, - SHADER_FT_PEEL = 0x18, - SHADER_FT_TONEMAP = 0x19, - SHADER_FT_REDUCE = 0x1A, - SHADER_FT_MAGNIFY = 0x1B, - SHADER_FT_MLAA = 0x1C, - SHADER_FT_CONTOUR = 0x1D, - SHADER_FT_EXPOSURE = 0x1E, - SHADER_FT_GAUSS = 0x1F, - SHADER_FT_SUN = 0x20, - SHADER_FT_FADE = 0x21, - SHADER_FT_WATER01 = 0x22, - SHADER_FT_WATER02 = 0x23, - SHADER_FT_WATRING = 0x24, - SHADER_FT_W_PTCL = 0x25, - SHADER_FT_SNOW_PT = 0x26, - SHADER_FT_LEAF_PT = 0x27, - SHADER_FT_STAR = 0x28, - SHADER_FT_SNORING = 0x29, - SHADER_FT_SN_FOOT = 0x2A, - SHADER_FT_SN_TSL = 0x2B, - SHADER_FT_SN_NRM = 0x2C, - SHADER_FT_FLOOR = 0x2D, - SHADER_FT_PUDDLE = 0x2E, - SHADER_FT_S_REFL = 0x2F, - SHADER_FT_S_REFR = 0x30, - SHADER_FT_RIPEMIT = 0x31, - SHADER_FT_RAIN = 0x32, - SHADER_FT_VOLLIT = 0x33, - SHADER_FT_FENCE = 0x34, - SHADER_FT_RIPPLE = 0x35, - SHADER_FT_FOGPTCL = 0x36, - SHADER_FT_PARTICL = 0x37, - SHADER_FT_GLITTER_PT = 0x38, - SHADER_FT_SHOWVEC = 0x39, - SHADER_FT_FONT = 0x3A, - SHADER_FT_MOVIE = 0x3B, - SHADER_FT_IMGFILT = 0x3C, - SHADER_FT_SPRITE = 0x3D, - SHADER_FT_END = 0x3E, + SHADER_FT_FFP = 0, + SHADER_FT_BLINN, + SHADER_FT_ITEM, + SHADER_FT_STAGE, + SHADER_FT_SKIN, + SHADER_FT_SSS_SKIN, + SHADER_FT_SSS_FILT, + SHADER_FT_HAIR, + SHADER_FT_CLOTH, + SHADER_FT_TIGHTS, + SHADER_FT_SKY, + SHADER_FT_EYEBALL, + SHADER_FT_EYELENS, + SHADER_FT_GLASEYE, + SHADER_FT_MEMBRAN, + SHADER_FT_SHDMAP, + SHADER_FT_ESM, + SHADER_FT_ESMGAUSS, + SHADER_FT_ESMFILT, + SHADER_FT_LITPROJ, + SHADER_FT_SIMPLE, + SHADER_FT_SIL, + SHADER_FT_LAMBERT, + SHADER_FT_CONSTANT, + SHADER_FT_PEEL, + SHADER_FT_TONEMAP, + SHADER_FT_REDUCE, + SHADER_FT_MAGNIFY, + //SHADER_FT_MLAA, + SHADER_FT_MLAA_EDGE, + SHADER_FT_MLAA_AREA, + SHADER_FT_MLAA_BLEND, + SHADER_FT_CONTOUR, + SHADER_FT_EXPOSURE, + SHADER_FT_GAUSS, + SHADER_FT_SUN, + SHADER_FT_FADE, + SHADER_FT_WATER01, + SHADER_FT_WATER02, + SHADER_FT_WATRING, + SHADER_FT_W_PTCL, + SHADER_FT_SNOW_PT, + SHADER_FT_LEAF_PT, + SHADER_FT_STAR, + SHADER_FT_SNORING, + SHADER_FT_SN_FOOT, + SHADER_FT_SN_TSL, + SHADER_FT_SN_NRM, + SHADER_FT_FLOOR, + SHADER_FT_PUDDLE, + SHADER_FT_S_REFL, + SHADER_FT_S_REFR, + SHADER_FT_RIPEMIT, + SHADER_FT_RAIN, + SHADER_FT_VOLLIT, + SHADER_FT_FENCE, + SHADER_FT_RIPPLE, + SHADER_FT_FOGPTCL, + SHADER_FT_PARTICL, + SHADER_FT_GLITTER_PT, + SHADER_FT_SHOWVEC, + SHADER_FT_FONT, + SHADER_FT_MOVIE, + SHADER_FT_IMGFILT, + SHADER_FT_SPRITE, + SHADER_FT_END, }; extern shader_set_data shaders_ft; diff --git a/src/CRE/shader_glsl.cpp b/src/CRE/shader_glsl.cpp index b7e913f5..3d477e68 100644 --- a/src/CRE/shader_glsl.cpp +++ b/src/CRE/shader_glsl.cpp @@ -4,6 +4,7 @@ */ #include "shader_glsl.hpp" +#include "../KKdLib/io/file_stream.hpp" #include "../KKdLib/hash.hpp" #include "../KKdLib/str_utils.hpp" #include "gl_state.hpp" @@ -73,9 +74,9 @@ void shader_glsl::load(const char* vert, const char* frag, GLuint vert_shad = shader_compile(GL_VERTEX_SHADER, vert_data); GLuint geom_shad = shader_compile(GL_GEOMETRY_SHADER, geom_data); - free(frag_data); - free(vert_data); - free(geom_data); + free_def(frag_data); + free_def(vert_data); + free_def(geom_data); program = glCreateProgram(); if (frag_shad) @@ -91,10 +92,10 @@ void shader_glsl::load(const char* vert, const char* frag, if (!success) { GLchar* info_log = force_malloc_s(GLchar, 0x10000); glGetProgramInfoLog(program, 0x10000, 0, info_log); - printf("Program FBO Shader linking error: %s\n", param->name); + printf("Program linking error: %s\n", param->name); printf(info_log); putchar('\n'); - free(info_log); + free_def(info_log); } if (frag_shad) @@ -113,7 +114,7 @@ void shader_glsl::load_file(const char* vert_path, const char* frag_path, uniform.clear(); uniform_block.clear(); - stream st; + file_stream st; size_t l; char* vert = 0; @@ -121,7 +122,7 @@ void shader_glsl::load_file(const char* vert_path, const char* frag_path, char* geom = 0; st.open(vert_path, "rb"); - if (st.io.stream) { + if (st.check_not_null()) { l = st.length; vert = force_malloc_s(char, l + 1); st.read(vert, l); @@ -130,7 +131,7 @@ void shader_glsl::load_file(const char* vert_path, const char* frag_path, st.close(); st.open(frag_path, "rb"); - if (st.io.stream) { + if (st.check_not_null()) { l = st.length; frag = force_malloc_s(char, l + 1); st.read(frag, l); @@ -139,7 +140,7 @@ void shader_glsl::load_file(const char* vert_path, const char* frag_path, st.close(); st.open(geom_path, "rb"); - if (st.io.stream) { + if (st.check_not_null()) { l = st.length; geom = force_malloc_s(char, l + 1); st.read(geom, l); @@ -148,8 +149,8 @@ void shader_glsl::load_file(const char* vert_path, const char* frag_path, st.close(); load(vert, frag, geom, param); - free(vert); - free(frag); + free_def(vert); + free_def(frag); } void shader_glsl::load_file(const wchar_t* vert_path, const wchar_t* frag_path, @@ -160,7 +161,7 @@ void shader_glsl::load_file(const wchar_t* vert_path, const wchar_t* frag_path, uniform.clear(); uniform_block.clear(); - stream st; + file_stream st; size_t l; char* vert = 0; @@ -168,7 +169,7 @@ void shader_glsl::load_file(const wchar_t* vert_path, const wchar_t* frag_path, char* geom = 0; st.open(vert_path, L"rb"); - if (st.io.stream) { + if (st.check_not_null()) { l = st.length; vert = force_malloc_s(char, l + 1); st.read(vert, l); @@ -177,7 +178,7 @@ void shader_glsl::load_file(const wchar_t* vert_path, const wchar_t* frag_path, st.close(); st.open(frag_path, L"rb"); - if (st.io.stream) { + if (st.check_not_null()) { l = st.length; frag = force_malloc_s(char, l + 1); st.read(frag, l); @@ -186,7 +187,7 @@ void shader_glsl::load_file(const wchar_t* vert_path, const wchar_t* frag_path, st.close(); st.open(geom_path, L"rb"); - if (st.io.stream) { + if (st.check_not_null()) { l = st.length; geom = force_malloc_s(char, l + 1); st.read(geom, l); @@ -195,8 +196,8 @@ void shader_glsl::load_file(const wchar_t* vert_path, const wchar_t* frag_path, st.close(); load(vert, frag, geom, param); - free(vert); - free(frag); + free_def(vert); + free_def(frag); } void shader_glsl::set(const char* name, bool value) { @@ -448,7 +449,7 @@ static GLuint shader_compile(GLenum type, const char* data) { printf("Shader compile error: "); printf(info_log); putchar('\n'); - free(info_log); + free_def(info_log); } return shader; } @@ -513,7 +514,7 @@ static char* shader_parse(char* data, const char* parse_string, const char* repl memcpy(temp_data + pos, replace_string, len_b); pos += len_b; memcpy(temp_data + pos, def, len_c); - free(data); + free_def(data); return temp_data; } @@ -561,6 +562,6 @@ static char* shader_parse_define(char* data, shader_glsl_param* param) { pos += temp_len[i]; } memcpy(temp_data + pos, def, len_b); - free(data); + free_def(data); return temp_data; } diff --git a/src/CRE/sound.cpp b/src/CRE/sound.cpp new file mode 100644 index 00000000..4f863892 --- /dev/null +++ b/src/CRE/sound.cpp @@ -0,0 +1,1775 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "sound.hpp" +#include "../KKdLib/io/file_stream.hpp" +#include "../KKdLib/key_val.hpp" +#include "../KKdLib/str_utils.hpp" +#include "../KKdLib/vec.hpp" +#include "data.hpp" +#include "timer.hpp" +#include +#include + +struct ima_storage { + int32_t step_index; + int32_t current; + + inline ima_storage() : step_index(), current() { + + } +}; + +struct SoundCueQueueVolume { + float_t min; + float_t max; +}; + +SoundWork* sound_work; +sound::wasapi::System* sound_wasapi_system_data; +std::map wave_audio_storage; + +static int32_t sound_cue_counter = 0; +static int32_t sound_wasapi_system_counter = 0; + +static const int8_t ima_index_table[] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8, +}; + +static const int16_t ima_step_table[] = { + 7, 8, 9, 10, 11, 12, 13, 14, + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, + 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, + 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, + 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767 +}; + +static const SoundCueQueueVolume sound_cue_queue_volume_array[SOUND_WORK_SE_QUEUE_COUNT] = { + { 0.0f, 1.0f, }, + { 0.0f, 1.0f, }, + { 0.0f, 1.0f, }, + { 0.3f, 1.0f, }, + { 0.3f, 1.0f, }, +}; + +static size_t ima_decode(int16_t* dst, size_t dst_size, uint8_t* data, size_t samples_count, + size_t channels, ima_storage* storage, size_t storage_size); + +namespace sound { + namespace wasapi { + System::System() : wave_format(), pEnumerator(), pDevice(), pAudioClient(), + samples_count(), pRenderClient(), pClockAdjustment(), hEvent(), + channels(), sample_rate(), bit_depth(), mixer(), thread(), format() { + + } + + System::~System() { + Reset(); + } + + void System::Init(size_t se_channels_count, size_t streaming_channels_count, + bool separate_speakers_headphones) { + if (FAILED(CoCreateInstance(__uuidof(MMDeviceEnumerator), + 0, 1, __uuidof(IMMDeviceEnumerator), (LPVOID*)&pEnumerator)) + || FAILED(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice))) + return; + + if (FAILED(pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient))) + return; + + WAVEFORMATEXTENSIBLE* mix_format; + if (FAILED(pAudioClient->GetMixFormat((WAVEFORMATEX**)&mix_format))) + return; + + int32_t channels = separate_speakers_headphones ? 4 : 2; + int32_t sample_rate; + int32_t bit_depth; + if (mix_format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + wave_format = *mix_format; + sample_rate = mix_format->Format.nSamplesPerSec; + bit_depth = mix_format->Samples.wValidBitsPerSample; + } + else { + wave_format.Format = mix_format->Format; + sample_rate = mix_format->Format.nSamplesPerSec; + bit_depth = 16; + } + + if (mix_format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE + && !memcmp(&wave_format.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID))) { + bit_depth = 32; + format = AUDIO_FORMAT_F32; + wave_format.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } + else { + switch (bit_depth) { + default: + bit_depth = 16; + case 16: + format = AUDIO_FORMAT_I16; + break; + case 24: + format = AUDIO_FORMAT_I24; + break; + case 32: + format = AUDIO_FORMAT_I32; + break; + } + + wave_format.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + + wave_format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wave_format.Format.nChannels = (WORD)channels; + wave_format.Format.nSamplesPerSec = (DWORD)sample_rate; + wave_format.Format.nAvgBytesPerSec = (DWORD)(sample_rate * (bit_depth / 8) * channels); + wave_format.Format.nBlockAlign = (WORD)((bit_depth / 8) * channels); + wave_format.Format.wBitsPerSample = (WORD)bit_depth; + wave_format.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + wave_format.Samples.wValidBitsPerSample = (WORD)bit_depth; + wave_format.dwChannelMask = channels == 4 ? KSAUDIO_SPEAKER_QUAD : KSAUDIO_SPEAKER_STEREO; + + WAVEFORMATEXTENSIBLE* closest_format; + if (FAILED(pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, + &wave_format.Format, (WAVEFORMATEX**)&closest_format))) { + wave_format = {}; + return; + } + + this->channels = channels; + this->sample_rate = sample_rate; + this->bit_depth = bit_depth; + + mixer = new Mixer(this); + if (!mixer) + return; + + REFERENCE_TIME hnsPeriod; + if (FAILED(pAudioClient->GetDevicePeriod(&hnsPeriod, 0))) + return; + + if (pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_RATEADJUST | AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + hnsPeriod, 0, &wave_format.Format, 0) == AUDCLNT_ERR(0x019)) { + if (FAILED(pAudioClient->GetBufferSize(&samples_count))) + return; + + pAudioClient->Release(); + + if (FAILED(pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient))) + return; + + hnsPeriod = (REFERENCE_TIME)((double_t)(int32_t)samples_count + * 10000000.0 / (double_t)sample_rate + 0.5); + + if (FAILED(pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_RATEADJUST | AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + hnsPeriod, 0, &wave_format.Format, 0))) + return; + } + + if (FAILED(pAudioClient->GetBufferSize(&samples_count))) + return; + + // Rounding to prev base 2 + while (true) { + uint32_t _samples_count = samples_count; + _samples_count--; + _samples_count |= _samples_count >> 1; + _samples_count |= _samples_count >> 2; + _samples_count |= _samples_count >> 4; + _samples_count |= _samples_count >> 8; + _samples_count |= _samples_count >> 16; + _samples_count++; + _samples_count >>= 1; + if (_samples_count + (_samples_count >> 1) < samples_count) { + samples_count = _samples_count; + break; + } + samples_count = _samples_count; + } + + if (!mixer->Init(se_channels_count, streaming_channels_count, samples_count)) + return; + + hEvent = CreateEventW(0, 0, 0, 0); + if (!hEvent) + return; + + thread = new std::thread(System::ThreadMain, this); + if (thread) { + wchar_t buf[0x80]; + swprintf_s(buf, sizeof(buf) / sizeof(wchar_t), L"sound::wasapi::System #%d", sound_wasapi_system_counter++); + SetThreadDescription((HANDLE)thread->native_handle(), buf); + } + + if (!thread || !SetThreadPriority((HANDLE)thread->native_handle(), THREAD_PRIORITY_HIGHEST)) + return; + + if (FAILED(pAudioClient->SetEventHandle(hEvent))) + return; + + if (SUCCEEDED(pAudioClient->GetService(__uuidof(IAudioRenderClient), (void**)&pRenderClient))) { + void* data = 0; + if (SUCCEEDED(pRenderClient->GetBuffer(samples_count, (BYTE**)&data)) + && SUCCEEDED(pRenderClient->ReleaseBuffer(samples_count, AUDCLNT_BUFFERFLAGS_SILENT))) + pAudioClient->Start(); + } + + if (SUCCEEDED(pAudioClient->GetService(__uuidof(IAudioClockAdjustment), (void**)&pClockAdjustment))) + pClockAdjustment->SetSampleRate((float_t)44100); + } + + void System::Reset() { + if (thread) { + thread_state.set(1); + thread->join(); + delete thread; + thread = 0; + } + + if (pAudioClient) + pAudioClient->Stop(); + + if (pClockAdjustment) { + pClockAdjustment->Release(); + pClockAdjustment = 0; + } + + if (pRenderClient) { + pRenderClient->Release(); + pRenderClient = 0; + } + + if (pAudioClient) { + pAudioClient->Release(); + pAudioClient = 0; + } + + if (pDevice) { + pDevice->Release(); + pDevice = 0; + } + + if (pEnumerator) { + pEnumerator->Release(); + pEnumerator = 0; + } + + if (hEvent) { + CloseHandle(hEvent); + hEvent = 0; + } + + if (mixer) { + delete mixer; + mixer = 0; + } + } + + void System::ThreadMain(System* system) { + if (!system) + return; + + while (!system->thread_state.get()) { + WaitForSingleObject(system->hEvent, -1); + void* data = 0; + if (SUCCEEDED(system->pRenderClient->GetBuffer(system->samples_count, (BYTE**)&data))) { + if (system->mixer && data) + system->mixer->FillBuffer(data, + system->samples_count, false, false, system->format); + + if (FAILED(system->pRenderClient->ReleaseBuffer(system->samples_count, 0))) + break; + } + } + system->thread_state.set(0); + } + + Mixer::Mixer(System* system) : se_channels(), se_channels_count(), + streaming_channels(), streaming_channels_count(), mix_buffer(), mix_buffer_size() { + this->system = system; + master_volume = 1.0f; + channels_volume[0] = 1.0f; + channels_volume[1] = 1.0f; + channels_volume[2] = 1.0f; + channels_volume[3] = 1.0f; + } + + Mixer::~Mixer() { + Reset(); + } + + void Mixer::FillBuffer(void* buffer, size_t samples_count, + bool disable_headphones_volume, bool invert_phase, AudioFormat format) { + if (!system) + return; + + float_t spk_l_volume = 0.0f; + float_t spk_r_volume = 0.0f; + float_t hph_l_volume = 0.0f; + float_t hph_r_volume = 0.0f; + + { + std::unique_lock u_lock(volume_mtx); + float_t master_volume = this->master_volume; + spk_l_volume = master_volume * channels_volume[0]; + spk_r_volume = master_volume * channels_volume[1]; + hph_l_volume = master_volume * channels_volume[2]; + hph_r_volume = master_volume * channels_volume[3]; + } + + if (disable_headphones_volume) { + hph_l_volume = spk_l_volume; + hph_r_volume = spk_r_volume; + } + else if (invert_phase) { + spk_l_volume = -spk_l_volume; + spk_l_volume = -spk_l_volume; + hph_l_volume = -hph_l_volume; + hph_r_volume = -hph_r_volume; + } + + memset(mix_buffer, 0, mix_buffer_size); + if (streaming_channels) + for (size_t i = 0; i < streaming_channels_count; i++) + streaming_channels[i].FillBuffer(mix_buffer, samples_count, 1.0f); + + if (se_channels) + for (size_t i = 0; i < se_channels_count; i++) + se_channels[i].FillBuffer(mix_buffer, samples_count, 1.0f); + + sound_buffer_data* _mix_buffer = mix_buffer; + switch (format) { + case AUDIO_FORMAT_I16: { + int16_t* _buffer = (int16_t*)buffer; + switch (system->channels) { + case 2: + for (size_t i = samples_count; i; i--, _mix_buffer++) { + int32_t hph_l = (int32_t)(_mix_buffer->hph_l * hph_l_volume * (float_t)0x7FFF); + int32_t hph_r = (int32_t)(_mix_buffer->hph_r * hph_r_volume * (float_t)0x7FFF); + *_buffer++ = (int16_t)clamp_def(hph_l, -0x8000, 0x7FFF); + *_buffer++ = (int16_t)clamp_def(hph_r, -0x8000, 0x7FFF); + } + break; + case 4: + for (size_t i = samples_count; i; i--, _mix_buffer++) { + int32_t spk_l = (int32_t)(_mix_buffer->spk_l * spk_l_volume * (float_t)0x7FFF); + int32_t spk_r = (int32_t)(_mix_buffer->spk_r * spk_r_volume * (float_t)0x7FFF); + int32_t hph_l = (int32_t)(_mix_buffer->hph_l * hph_l_volume * (float_t)0x7FFF); + int32_t hph_r = (int32_t)(_mix_buffer->hph_r * hph_r_volume * (float_t)0x7FFF); + *_buffer++ = (int16_t)clamp_def(spk_l, -0x8000, 0x7FFF); + *_buffer++ = (int16_t)clamp_def(spk_r, -0x8000, 0x7FFF); + *_buffer++ = (int16_t)clamp_def(hph_l, -0x8000, 0x7FFF); + *_buffer++ = (int16_t)clamp_def(hph_r, -0x8000, 0x7FFF); + } + break; + } + } break; + case AUDIO_FORMAT_I24: { + int8_t* _buffer = (int8_t*)buffer; + switch (system->channels) { + case 2: + for (size_t i = samples_count; i; i--, _mix_buffer++) { + int32_t hph_l = (int32_t)(_mix_buffer->hph_l * hph_l_volume * (float_t)0x7FFFFF); + int32_t hph_r = (int32_t)(_mix_buffer->hph_r * hph_r_volume * (float_t)0x7FFFFF); + hph_l = clamp_def(hph_l, -0x800000, 0x7FFFFF); + hph_r = clamp_def(hph_r, -0x800000, 0x7FFFFF); + *(uint16_t*)&_buffer[0] = (uint16_t)hph_l; + *(uint8_t*)&_buffer[2] = (uint8_t)(hph_l >> 16); + *(uint16_t*)&_buffer[3] = (uint16_t)hph_r; + *(uint8_t*)&_buffer[5] = (uint8_t)(hph_r >> 16); + _buffer += 6; + } + break; + case 4: + for (size_t i = samples_count; i; i--, _mix_buffer++) { + int32_t spk_l = (int32_t)(_mix_buffer->spk_l * spk_l_volume * (float_t)0x7FFFFF); + int32_t spk_r = (int32_t)(_mix_buffer->spk_r * spk_r_volume * (float_t)0x7FFFFF); + int32_t hph_l = (int32_t)(_mix_buffer->hph_l * hph_l_volume * (float_t)0x7FFFFF); + int32_t hph_r = (int32_t)(_mix_buffer->hph_r * hph_r_volume * (float_t)0x7FFFFF); + spk_l = clamp_def(spk_l, -0x800000, 0x7FFFFF); + spk_r = clamp_def(spk_r, -0x800000, 0x7FFFFF); + hph_l = clamp_def(hph_l, -0x800000, 0x7FFFFF); + hph_r = clamp_def(hph_r, -0x800000, 0x7FFFFF); + *(uint16_t*)&_buffer[0] = (uint16_t)spk_l; + *(uint8_t*)&_buffer[2] = (uint8_t)(spk_l >> 16); + *(uint16_t*)&_buffer[3] = (uint16_t)spk_r; + *(uint8_t*)&_buffer[5] = (uint8_t)(spk_r >> 16); + *(uint16_t*)&_buffer[6] = (uint16_t)hph_l; + *(uint8_t*)&_buffer[8] = (uint8_t)(hph_l >> 16); + *(uint16_t*)&_buffer[9] = (uint16_t)hph_r; + *(uint8_t*)&_buffer[11] = (uint8_t)(hph_r >> 16); + _buffer += 12; + } + break; + } + } break; + case AUDIO_FORMAT_I32: { + int32_t* _buffer = (int32_t*)buffer; + switch (system->channels) { + case 2: + for (size_t i = samples_count; i; i--, _mix_buffer++) { + int64_t hph_l = (int64_t)((double_t)_mix_buffer->hph_l * hph_l_volume * (double_t)0x7FFFFFFF); + int64_t hph_r = (int64_t)((double_t)_mix_buffer->hph_r * hph_r_volume * (double_t)0x7FFFFFFF); + *_buffer++ = (int32_t)clamp_def(hph_l, -0x80000000LL, 0x7FFFFFFFLL); + *_buffer++ = (int32_t)clamp_def(hph_r, -0x80000000LL, 0x7FFFFFFFLL); + } + break; + case 4: + for (size_t i = samples_count; i; i--, _mix_buffer++) { + int64_t spk_l = (int64_t)((double_t)_mix_buffer->spk_l * spk_l_volume * (double_t)0x7FFFFFFF); + int64_t spk_r = (int64_t)((double_t)_mix_buffer->spk_r * spk_r_volume * (double_t)0x7FFFFFFF); + int64_t hph_l = (int64_t)((double_t)_mix_buffer->hph_l * hph_l_volume * (double_t)0x7FFFFFFF); + int64_t hph_r = (int64_t)((double_t)_mix_buffer->hph_r * hph_r_volume * (double_t)0x7FFFFFFF); + *_buffer++ = (int32_t)clamp_def(spk_l, -0x80000000LL, 0x7FFFFFFFLL); + *_buffer++ = (int32_t)clamp_def(spk_r, -0x80000000LL, 0x7FFFFFFFLL); + *_buffer++ = (int32_t)clamp_def(hph_l, -0x80000000LL, 0x7FFFFFFFLL); + *_buffer++ = (int32_t)clamp_def(hph_r, -0x80000000LL, 0x7FFFFFFFLL); + } + break; + } + } break; + case AUDIO_FORMAT_F32: { + float_t* _buffer = (float_t*)buffer; + switch (system->channels) { + case 2: + for (size_t i = samples_count; i; i--, _mix_buffer++) { + *_buffer++ = _mix_buffer->hph_l * hph_l_volume; + *_buffer++ = _mix_buffer->hph_r * hph_r_volume; + } + break; + case 4: + for (size_t i = samples_count; i; i--, _mix_buffer++) { + *_buffer++ = _mix_buffer->spk_l * spk_l_volume; + *_buffer++ = _mix_buffer->spk_r * spk_r_volume; + *_buffer++ = _mix_buffer->hph_l * hph_l_volume; + *_buffer++ = _mix_buffer->hph_r * hph_r_volume; + } + break; + } + } break; + } + } + + SEChannel* Mixer::GetSEChannel(size_t channel) { + if (channel < se_channels_count && se_channels) + return &se_channels[channel]; + return 0; + } + + StreamingChannel* Mixer::GetStreamingChannel(size_t channel) { + if (channel < streaming_channels_count && streaming_channels) + return &streaming_channels[channel]; + return 0; + } + + bool Mixer::Init(size_t se_channels_count, size_t streaming_channels_count, size_t samples_count) { + if (this->se_channels_count || this->streaming_channels_count) { + Reset(); + return false; + } + + mix_buffer_size = sizeof(sound_buffer_data) * samples_count; + mix_buffer = (sound_buffer_data*)malloc(mix_buffer_size); + if (!mix_buffer) { + Reset(); + return false; + } + memset(mix_buffer, 0, mix_buffer_size); + + if (se_channels_count) { + se_channels = new SEChannel[se_channels_count]; + if (!se_channels) { + Reset(); + return false; + } + + for (size_t i = 0; i < se_channels_count; i++) + se_channels[i].Init(this); + } + this->se_channels_count = se_channels_count; + + if (streaming_channels_count) { + streaming_channels = new StreamingChannel[streaming_channels_count]; + if (!streaming_channels) { + Reset(); + return false; + } + + for (size_t i = 0; i < streaming_channels_count; i++) + streaming_channels[i].Init(this, samples_count); + } + this->streaming_channels_count = streaming_channels_count; + return true; + } + + void Mixer::Reset() { + if (streaming_channels) { + for (size_t i = 0; i < streaming_channels_count; i++) + streaming_channels[i].Reset(); + + delete[] streaming_channels; + streaming_channels = 0; + } + streaming_channels_count = 0; + + if (se_channels) { + for (size_t i = 0; i < se_channels_count; i++) + se_channels[i].Reset(); + + delete[] se_channels; + se_channels = 0; + } + se_channels_count = 0; + + if (mix_buffer) { + free(mix_buffer); + mix_buffer = 0; + } + mix_buffer_size = 0; + } + + void Mixer::SetChannelsVolume(int32_t mask, float_t value) { + std::unique_lock u_lock(volume_mtx); + for (int32_t i = 0; i < 4; i++) + if (mask & (1 << i)) + channels_volume[i] = value; + } + + void Mixer::SetMasterVolume(float_t value) { + std::unique_lock u_lock(volume_mtx); + master_volume = value; + } + + SEChannel::SEChannel() : mixer(), buffer(), buffer_size(), channels(), + samples_count(), sample_rate(), loop_start(), loop_end(), current_sample() { + master_volume = 1.0f; + channels_volume[0] = 1.0f; + channels_volume[1] = 1.0f; + channels_volume[2] = 1.0f; + channels_volume[3] = 1.0f; + } + + SEChannel::~SEChannel() { + Reset(); + } + + void SEChannel::FillBuffer(sound_buffer_data* buffer, size_t samples_count, float_t volume) { + std::unique_lock u_lock(mtx); + if (!play_state.get() || !buffer) + return; + + float_t master_volume = this->master_volume; + float_t spk_l_volume = master_volume * channels_volume[0]; + float_t spk_r_volume = master_volume * channels_volume[1]; + float_t hph_l_volume = master_volume * channels_volume[2]; + float_t hph_r_volume = master_volume * channels_volume[3]; + + vec4 channels_volume(spk_l_volume, spk_r_volume, hph_l_volume, hph_r_volume); + + size_t _samples_count = this->samples_count; + if (channels == 1) + for (size_t i = samples_count; i && current_sample < _samples_count; i--, buffer++) { + float_t* _buffer = this->buffer + current_sample; + *(vec4*)buffer = channels_volume * _buffer[0] + *(vec4*)buffer; + + current_sample++; + if ((loop_start || loop_end) && current_sample > loop_end) + current_sample = loop_start; + } + if (channels == 2) + for (size_t i = samples_count; i && current_sample < _samples_count; i--, buffer++) { + float_t* _buffer = this->buffer + current_sample * 2; + *(vec4*)buffer = channels_volume * vec4(_buffer[0], _buffer[1], + _buffer[0], _buffer[1]) + *(vec4*)buffer; + + current_sample++; + if ((loop_start || loop_end) && current_sample > loop_end) + current_sample = loop_start; + } + else if (channels == 4) + for (size_t i = samples_count; i && current_sample < _samples_count; i--, buffer++) { + float_t* _buffer = this->buffer + current_sample * 4; + *(vec4*)buffer = channels_volume * *(vec4*)_buffer + *(vec4*)buffer; + + current_sample++; + if ((loop_start || loop_end) && current_sample > loop_end) + current_sample = loop_start; + } + + if (current_sample >= _samples_count) + ResetData(); + } + + bool SEChannel::Init(Mixer* mixer) { + bool ret = false; + { + std::unique_lock u_lock(mtx); + if (!this->mixer) { + this->mixer = mixer; + buffer = 0; + buffer_size = 0; + ret = true; + } + } + + if (!ret) + Reset(); + return ret; + } + + float_t* SEChannel::InitBuffer(size_t channels, size_t samples_count, size_t sample_rate) { + std::unique_lock u_lock(mtx); + ResetData(); + buffer = (float_t*)malloc(sizeof(float_t) * samples_count * channels); + if (!buffer) + return 0; + + buffer_size = sizeof(float_t) * samples_count * channels; + memset(buffer, 0, buffer_size); + this->channels = channels; + this->sample_rate = sample_rate; + this->samples_count = samples_count; + loop_start = 0; + loop_end = 0; + return buffer; + } + + bool SEChannel::Play(size_t loop_start, size_t loop_end) { + std::unique_lock u_lock(mtx); + if (!buffer) + return false; + + this->loop_start = loop_start; + this->loop_end = loop_end; + current_sample = 0; + play_state.set(1); + return true; + } + + void SEChannel::Reset() { + std::unique_lock u_lock(mtx); + ResetData(); + } + + void SEChannel::ResetData() { + play_state.set(0); + if (buffer) { + free(buffer); + buffer = 0; + } + buffer_size = 0; + channels = 0; + samples_count = 0; + sample_rate = 0; + loop_start = 0; + loop_end = 0; + current_sample = 0; + } + + void SEChannel::ResetDataProt() { + if (!play_state.get()) + return; + + std::unique_lock u_lock(mtx); + ResetData(); + } + + void SEChannel::SetChannelsVolume(int32_t mask, float_t value) { + std::unique_lock u_lock(mtx); + for (int32_t i = 0; i < 4; i++) + if (mask & (1 << i)) + channels_volume[i] = value; + } + + void SEChannel::SetMasterVolume(float_t value) { + std::unique_lock u_lock(mtx); + master_volume = value; + } + + StreamingChannel::StreamingChannel() : mixer(), buffer(), + buffer_size(), callback_func(), callback_data() { + master_volume = 1.0f; + channels_volume[0] = 1.0f; + channels_volume[1] = 1.0f; + channels_volume[2] = 1.0f; + channels_volume[3] = 1.0f; + } + + StreamingChannel::~StreamingChannel() { + Reset(); + } + + void StreamingChannel::FillBuffer(sound_buffer_data* buffer, size_t samples_count, float_t volume) { + if (playing_state.get() && reset_state.get()) { + std::unique_lock u_lock(mtx); + ResetData(); + } + + if (!playing_state.get() || !this->buffer || !buffer) + return; + + float_t spk_l_volume = 0.0f; + float_t spk_r_volume = 0.0f; + float_t hph_l_volume = 0.0f; + float_t hph_r_volume = 0.0f; + { + std::unique_lock u_lock(mtx); + if (!callback_func) + return; + + memset(this->buffer, 0, buffer_size); + + callback_func(this->buffer, samples_count, callback_data); + + float_t master_volume = this->master_volume; + spk_l_volume = master_volume * channels_volume[0]; + spk_r_volume = master_volume * channels_volume[1]; + hph_l_volume = master_volume * channels_volume[2]; + hph_r_volume = master_volume * channels_volume[3]; + } + + vec4 channels_volume(spk_l_volume, spk_r_volume, hph_l_volume, hph_r_volume); + + sound_buffer_data* _buffer = this->buffer; + for (size_t i = samples_count; i; i--, buffer++, _buffer++) + *(vec4*)buffer = channels_volume * *(vec4*)_buffer + *(vec4*)buffer; + } + + bool StreamingChannel::Init(Mixer* mixer, size_t samples_count) { + if (this->mixer) { + Reset(); + return false; + } + + this->mixer = mixer; + buffer_size = sizeof(sound_buffer_data) * samples_count; + buffer = (sound_buffer_data*)malloc(buffer_size); + if (!buffer) { + Reset(); + return false; + } + + memset(buffer, 0, buffer_size); + return true; + } + + void StreamingChannel::Reset() { + reset_state.set(1); + FillBuffer(0, 0, 0.0f); + if (buffer) { + free(buffer); + buffer = 0; + } + mixer = 0; + buffer_size = 0; + } + + void StreamingChannel::ResetData() { + playing_state.set(0); + reset_state.set(0); + callback_func = 0; + callback_data = 0; + } + + bool StreamingChannel::SetCallback(void(*func)(sound_buffer_data* buffer, + size_t samples_count, void* data), void* data) { + std::unique_lock u_lock(mtx); + ResetData(); + callback_func = func; + callback_data = data; + playing_state.set(1); + return true; + } + + void StreamingChannel::SetChannelsVolume(int32_t mask, float_t value) { + std::unique_lock u_lock(mtx); + for (int32_t i = 0; i < 4; i++) + if (mask & (1 << i)) + channels_volume[i] = value; + } + + void StreamingChannel::SetMasterVolume(float_t value) { + std::unique_lock u_lock(mtx); + master_volume = value; + } + } +} + +sound_db_farc::sound_db_farc() : loaded() { + +} + +sound_db_farc::~sound_db_farc() { + +} + +bool sound_db_farc::load() { + if (loaded) + return false; + else if (file_handler.check_not_ready()) + return true; + + + farc.read(file_handler.get_data(), file_handler.get_size()); + if (farc.files.size() && sound_work->ParseProperty(this)) + loaded = true; + return false; +} + +bool sound_db_farc::read(const char* file_path) { + if (loaded) + unload(); + + this->file_path.assign(file_path); + return file_handler.read_file(&data_list[DATA_AFT], file_path); +} + +bool sound_db_farc::unload() { + sound_work_release_farc_se(file_path.c_str()); + if (!sound_work->UnloadProperty(file_path.c_str())) + return false; + + file_path.clear(); + loaded = false; + file_handler.free_data(); + return true; +} + +sound_db_property::sound_db_property() : farc(), +volume(), loop_start(), loop_end(), release_time()/*, field_48()*/ { + +} + +sound_db_property::~sound_db_property() { + +} + +SoundCue::SoundCue() : thread(), property(), counter(), release_time(), se_channel() { + queue_index = SOUND_WORK_SE_QUEUE_COUNT; + volume = new SoundCueVolume(this); +} + +SoundCue::~SoundCue() { + if (thread) { + thread_state.set(1); + cnd.notify_one(); + thread->join(); + delete thread; + thread = 0; + } + + if (volume) { + delete volume; + volume = 0; + } +} + +bool SoundCue::CanPlay() { + if (se_channel && se_channel->play_state.get()) + return true; + return !!load_state.get(); +} + +void SoundCue::Ctrl() { + std::unique_lock u_lock(mtx); + while (!thread_state.get()) { + if (!data_state.get()) + cnd.wait(u_lock); + + int32_t _data_state = data_state.get(); + data_state.set(SOUND_CUE_DATA_STATE_NONE); + switch (_data_state) { + case SOUND_CUE_DATA_STATE_LOAD: + LoadData(); + break; + case SOUND_CUE_DATA_STATE_RESET: + ResetData(); + break; + } + } + thread_state.set(0); +} + +int32_t SoundCue::Load(int32_t queue_index, const char* name, float_t volume) { + ReleaseProt(true); + std::unique_lock u_lock(mtx); + if (!se_channel) + return 0; + + sound_db_property* property = sound_work->FindProperty(name); + if (!property) + return 0; + + this->name.assign(name); + this->property = property; + this->queue_index = queue_index; + this->volume->SetValue(volume); + + Play(); + load_state.set(1); + data_state.set(SOUND_CUE_DATA_STATE_LOAD); + cnd.notify_one(); + counter = sound_work->counter; + if (++sound_work->counter <= -1) + sound_work->counter = 1; + return counter; +} + +void SoundCue::LoadData() { + WaveAudio* _wave_audio = 0; + if (!property || !property->farc) { + load_state.set(0); + return; + } + + WaveAudio* wave_audio = wave_audio_storage_get_wave_audio(name); + if (!wave_audio) { + _wave_audio = new WaveAudio; + if (_wave_audio && _wave_audio->Read(property->farc, property->file_name.c_str())) + wave_audio = _wave_audio; + } + + if (wave_audio) { + float_t* buffer = se_channel->InitBuffer(wave_audio->data.channels, + wave_audio->data.samples_count, wave_audio->data.sample_rate); + if (buffer) { + memmove(buffer, wave_audio->buffer, wave_audio->buffer_size); + se_channel->Play(property->loop_start, property->loop_end); + } + } + + if (_wave_audio) { + _wave_audio->Reset(); + delete _wave_audio; + } + load_state.set(0); +} + +void SoundCue::Play() { + if (se_channel && !property) + return; + + bool master_volume_set = false; + float_t master_volume = property->volume * volume->value; + + if (volume->set) { + volume->set = false; + master_volume_set = true; + } + + if (release_time > 0.0f) { + double_t release_time = this->release_time * 1000.0; + double_t current_time = time.calc_time(); + double_t remain_time; + if (current_time >= release_time) { + remain_time = 0.0; + Release(true); + } + else + remain_time = release_time - current_time; + + master_volume_set = true; + master_volume = (float_t)(remain_time / release_time) * master_volume; + } + + if (se_channel) { + if (master_volume_set) + se_channel->SetMasterVolume(master_volume); + + if (!queue_index) + se_channel->SetChannelsVolume(0x03, get_max_speakers_volume()); + } + return; +} + +void SoundCue::PlayProt() { + std::unique_lock u_lock(mtx); + Play(); +} + +void SoundCue::Release(bool force_release) { + if (!property || fabsf(property->release_time) <= 0.000001f || force_release) { + data_state.set(SOUND_CUE_DATA_STATE_RESET); + cnd.notify_one(); + queue_index = SOUND_WORK_SE_QUEUE_COUNT; + name.clear(); + property = 0; + counter = 0; + release_time = 0.0f; + } + else + release_time = property->release_time; + + time.get_timestamp(); +} + +void SoundCue::ReleaseProt(bool force_release) { + std::unique_lock u_lock(mtx); + Release(force_release); +} + +void SoundCue::Reset() { + ReleaseProt(true); + + if (thread) { + thread_state.set(1); + cnd.notify_one(); + thread->join(); + delete thread; + thread = 0; + } +} + +void SoundCue::ResetData() { + if (se_channel) + se_channel->ResetDataProt(); +} + +void SoundCue::SetSEChannel(sound::wasapi::SEChannel* se_channel) { + this->se_channel = se_channel; + if (se_channel) + se_channel->SetMasterVolume(1.0f); + + thread = new std::thread(SoundCue::ThreadMain, this); + if (thread) { + wchar_t buf[0x80]; + swprintf_s(buf, sizeof(buf) / sizeof(wchar_t), L"SoundCue #%d", sound_cue_counter++); + SetThreadDescription((HANDLE)thread->native_handle(), buf); + } +} + +void SoundCue::ThreadMain(SoundCue* cue) { + if (cue) + cue->Ctrl(); +} + +WaveAudioData::WaveAudioData() : format(), channels(), sample_rate(), bit_depth(), +samples_count(), position(), data_size(), has_loop(), loop_start(), loop_end() { + +} + +WaveAudioData::~WaveAudioData() { + +} + +bool WaveAudioData::Read(WaveAudioDataFileMemoryStream* fms) { + Reset(); + return ReadDiva(fms)/* || ReadRiff(fms)*/; +} + +bool WaveAudioData::ReadData(const void* data, size_t size) { + if (!this || !data || !size) + return false; + + WaveAudioDataFileMemoryStream fms(data, size); + return Read(&fms); +} + +bool WaveAudioData::ReadDiva(WaveAudioDataFileMemoryStream* fms) { + struct DivaAudioHeader { + uint32_t signature; + uint8_t pad_4[4]; + uint32_t size; + uint32_t sample_rate; + uint32_t samples_count; + uint32_t loop_start; + uint32_t loop_end; + uint8_t channels; + uint8_t pad_1D[3]; + uint8_t reserved1[32]; + } header; + + if (fms->file) { + if (fseek(fms->file, 0, SEEK_SET)) + return false; + } + else { + if (!fms->data || !fms->size) + return false; + fms->position = 0; + } + + size_t read_bytes = 0; + if (fms->file) + read_bytes = fread(&header, sizeof(DivaAudioHeader), 1, fms->file); + else if (fms->data && fms->size && fms->position + sizeof(DivaAudioHeader) <= fms->size) { + memmove(&header, (uint8_t*)fms->data + fms->position, sizeof(DivaAudioHeader)); + read_bytes = sizeof(DivaAudioHeader); + } + + if (!read_bytes || header.signature != reverse_endianness_uint32_t('DIVA')) + return false; + + format = WAVE_AUDIO_DATA_FORMAT_DIVA; + channels = header.channels; + sample_rate = header.sample_rate; + bit_depth = 0; + samples_count = header.samples_count; + position = 0; + data_size = 0; + has_loop = header.loop_start < header.loop_end; + loop_start = header.loop_start; + loop_end = header.loop_end; + return true; +} + +void WaveAudioData::Reset() { + format = WAVE_AUDIO_DATA_FORMAT_NONE; + channels = 0; + sample_rate = 0; + bit_depth = 0; + samples_count = 0; + position = 0; + data_size = 0; + has_loop = false; + loop_start = 0; + loop_end = 0; +} + +WaveAudio::WaveAudio() : buffer(), buffer_size() { + +} + +bool WaveAudio::Read(sound_db_farc* farc, const char* file_name) { + if (!this) + return false; + + if (!farc) { + Reset(); + return false; + } + + ::farc* f = &farc->farc; + farc_file* ff = f->read_file(file_name); + if (!ff || !ff->data || !ff->size) { + Reset(); + return false; + } + + data.ReadData(ff->data, ff->size); + + size_t buffer_size = sizeof(float_t) * data.samples_count * data.channels; + float_t* buffer = (float_t*)malloc(buffer_size); + this->buffer_size = buffer_size; + this->buffer = buffer; + + if (!buffer) { + Reset(); + return false; + } + + bool ret = false; + memset(buffer, 0, buffer_size); + if (data.format == WAVE_AUDIO_DATA_FORMAT_DIVA) { + size_t buf_size = sizeof(int16_t) * data.samples_count * data.channels; + int16_t* buf = (int16_t*)malloc(buf_size); + if (!buf) { + Reset(); + return false; + } + + memset(buf, 0, buf_size); + + { + std::vector storage(data.channels); + data.samples_count = ima_decode(buf, buf_size, (uint8_t*)ff->data + data.position, + data.samples_count, data.channels, storage.data(), storage.size()); + } + + int16_t* _buf = buf; + float_t* buffer = this->buffer; + size_t channels = data.channels; + size_t samples_count = data.samples_count; + for (size_t i = samples_count; i; i--) + for (size_t j = channels; j; j--) + *buffer++ = (float_t)*_buf++ * (float_t)(1.0 / (double_t)0x7FFF); + + free(buf); + ret = true; + } + + if (!ret) { + Reset(); + return false; + } + return true; +} + +void WaveAudio::Reset() { + if (buffer) { + free(buffer); + buffer = 0; + } + buffer_size = 0; + data.Reset(); +} + +SoundWork::SoundWork() : se_queue_enable(), streaming_enable(), se_queue_volume() { + counter = 1; + speakers_volume = get_max_speakers_volume(); + speakers_volume_changed = true; + headphones_volume = get_min_headphones_volume(); + headphones_volume_changed = true; + se_volume = 1.0f; + + for (bool& i : se_queue_enable) + i = true; + + for (bool& i : streaming_enable) + i = true; + + for (int32_t i = 0; i < SOUND_WORK_SE_QUEUE_COUNT; i++) + se_queue_volume[i] = sound_cue_queue_volume_array_get_max(i); +} + +SoundWork::~SoundWork() { + +} + +sound_db_property* SoundWork::FindProperty(const char* name) { + auto elem = properties.find(name); + if (elem != properties.end()) + return &elem->second; + return 0; +} + +bool SoundWork::ParseProperty(sound_db_farc* snd_db_farc) { + if (!snd_db_farc) + return false; + + farc& f = snd_db_farc->farc; + farc_file* property_ff = f.read_file("property.txt"); + if (!property_ff || !property_ff->data || !property_ff->size) + return false; + + key_val kv; + kv.parse(property_ff->data, property_ff->size); + + int32_t max; + float_t volume_bias; + if (!kv.read("max", max) || !kv.read("volume_bias", volume_bias)) + return false; + + for (int32_t i = 0, j = 1; i < max; i++, j++) { + if (!kv.open_scope_fmt("%zu", j)) + continue; + + std::string name; + std::string file_name; + if (!kv.read("name", name) || !kv.read("file_name", file_name) + || !kv.has_key("volume") || !f.has_file(file_name.c_str())) { + kv.close_scope(); + continue; + } + + uint32_t loop_start = 0; + if (kv.open_scope("loop_start")) { + kv.read(loop_start); + kv.close_scope(); + } + + uint32_t loop_end = 0; + if (kv.open_scope("loop_end")) { + kv.read(loop_end); + kv.close_scope(); + } + + float_t release_time = 0.0f; + if (kv.open_scope("release_time")) { + kv.read(release_time); + release_time *= 0.001f; + kv.close_scope(); + } + + float_t volume = 0.0f; + kv.read("volume", volume); + + sound_db_property property; + property.farc = snd_db_farc; + property.file_name.assign(file_name); + property.volume = volume * volume_bias; + property.loop_start = loop_start; + property.loop_end = loop_end; + property.release_time = release_time; + properties.insert_or_assign(name, property); + kv.close_scope(); + } + return true; +} + +bool SoundWork::UnloadProperty(const char* file_path) { + for (std::map::iterator i + = properties.begin(); i != properties.end(); i++) + if (!i->second.farc->file_path.compare(file_path)) { + properties.erase(i); + break; + } + return true; +} + +extern float_t get_min_headphones_volume() { + return 1.0f;//0.02f; +} + +extern float_t get_max_headphones_volume() { + return 0.45f; +} + +extern float_t get_min_speakers_volume() { + return 0.0f; +} + +extern float_t get_max_speakers_volume() { + return 0.8f; +} + +float_t db_to_ratio(int32_t value) { + if (value <= -10000) + return 0.0f; + else if (value >= 0) + return 1.0f; + else + return powf(10.0, (float_t)value * 0.0005f); +} + +int32_t ratio_to_db(float_t value) { + if (value <= 0.0f) + return -10000; + else if (value >= 1.0f) + return 0; + else + return (int32_t)(log10f(value) * 20.0f * 100.0f); +} + +void sound_init() { + IMMDeviceEnumerator* mmEnumerator; + if (SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, + CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&mmEnumerator))) { + IMMDeviceCollection* collection; + if (SUCCEEDED(mmEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &collection))) { + UINT count; + if (SUCCEEDED(collection->GetCount(&count))) { + for (UINT i = 0; i < count; i++) { + IMMDevice* device; + if (FAILED(collection->Item(i, &device))) + continue; + + wchar_t* wstrID; + if (SUCCEEDED(device->GetId((LPWSTR*)&wstrID))) { + IPropertyStore* store; + if (SUCCEEDED(device->OpenPropertyStore(STGM_READ, &store))) { + PROPVARIANT pv; + + PropVariantInit(&pv); + if (SUCCEEDED(store->GetValue(PKEY_Device_FriendlyName, &pv))) + printf("%ls\n", pv.pwszVal); + PropVariantClear(&pv); + + store->Release(); + } + CoTaskMemFree((LPVOID)wstrID); + } + device->Release(); + } + } + collection->Release(); + } + mmEnumerator->Release(); + } + + if (!sound_work) + sound_work = new SoundWork; + + if (!sound_wasapi_system_data) + sound_wasapi_system_data = new sound::wasapi::System; + + sound_wasapi_system_data->Init(32, 4); + + sound::wasapi::Mixer* mixer = sound_wasapi_system_data->mixer; + if (mixer) { + mixer->SetMasterVolume(1.0f); + mixer->SetChannelsVolume(0x03, 1.0f); + mixer->SetChannelsVolume(0x0C, get_min_headphones_volume()); + + size_t se_channels_count = mixer->se_channels_count; + for (size_t i = 0; i < se_channels_count; i++) { + sound::wasapi::SEChannel* se_channel = mixer->GetSEChannel(i); + se_channel->SetChannelsVolume(0x03, get_max_speakers_volume()); + se_channel->SetChannelsVolume(0x0C, 1.0f); + } + + size_t streaming_channels_count = mixer->streaming_channels_count; + for (size_t i = 0; i < streaming_channels_count; i++) { + sound::wasapi::StreamingChannel* streaming_channel = mixer->GetStreamingChannel(i); + streaming_channel->SetChannelsVolume(0x03, get_max_speakers_volume()); + streaming_channel->SetChannelsVolume(0x0C, 1.0f); + } + + SoundCue* sound_cue = sound_work->cues; + for (size_t i = 0; i < se_channels_count + && i < sizeof(sound_work->cues) / sizeof(SoundCue); i++, sound_cue++) { + sound::wasapi::SEChannel* se_channel = mixer->GetSEChannel(i); + if (se_channel) + sound_cue->SetSEChannel(se_channel); + } + } + + //sub_140622E00(); +} + +void sound_ctrl() { + sound::wasapi::System* sound_wasapi_system = sound_wasapi_system_data_get(); + if (sound_wasapi_system) { + sound::wasapi::Mixer* mixer = sound_wasapi_system->mixer; + if (mixer) { + if (sound_work->headphones_volume_changed) + mixer->SetChannelsVolume(0x0C, sound_work_get_headphones_volume()); + + if (sound_work->speakers_volume_changed) { + size_t se_channels_count = mixer->se_channels_count; + for (size_t i = 0; i < se_channels_count; i++) { + sound::wasapi::SEChannel* se_channel = mixer->GetSEChannel(i); + se_channel->SetChannelsVolume(0x03, sound_work_get_speakers_volume()); + } + + size_t streaming_channels_count = mixer->streaming_channels_count; + for (size_t i = 0; i < streaming_channels_count; i++) { + sound::wasapi::StreamingChannel* streaming_channel = mixer->GetStreamingChannel(i); + streaming_channel->SetChannelsVolume(0x03, sound_work_get_speakers_volume()); + } + } + } + } + sound_work->speakers_volume_changed = false; + sound_work->headphones_volume_changed = false; + + for (SoundCue& i : sound_work->cues) { + if (i.CanPlay()) + i.PlayProt(); + else + i.ReleaseProt(true); + } + + //sub_140622AD0(); + + sound_work->names_list.clear(); +} + +void sound_free() { + if (sound_work) { + delete sound_work; + sound_work = 0; + } + + if (sound_wasapi_system_data) { + delete sound_wasapi_system_data; + sound_wasapi_system_data = 0; + } +} + +bool sound_work_cue_can_play(int32_t queue_index, const char* name) { + if (!name) + return false; + + SoundCue* cue = sound_work_get_cue(queue_index, name); + if (cue) + return cue->CanPlay(); + return false; +} + +SoundCue* sound_work_get_cue(int32_t queue_index, const char* name) { + for (SoundCue& i : sound_work->cues) + if ((!i.se_channel || i.property) && i.queue_index == queue_index + && !i.name.compare(name)) + return &i; + return 0; +} + +bool sound_work_get_cue_release(int32_t queue_index, const char* name, bool force_release) { + if (!name) + return false; + + SoundCue* cue = sound_work_get_cue(queue_index, name); + if (cue) { + cue->ReleaseProt(force_release); + return true; + } + return false; +} + +sound_db_farc* sound_work_get_farc(const char* file_path) { + for (sound_db_farc& i : sound_work->farcs) + if (!i.file_path.compare(file_path)) + return &i; + return 0; +} + +float_t sound_work_get_headphones_volume() { + return sound_work->headphones_volume; +} + +float_t sound_work_get_speakers_volume() { + return sound_work->speakers_volume; +} + +bool sound_work_has_property(const char* name) { + return !!sound_work->FindProperty(name); +} + +bool sound_work_load_farc(const char* file_path) { + if (!file_path) + return false; + + sound_db_farc* snd_db_farc = sound_work_get_farc(file_path); + if (snd_db_farc) + return snd_db_farc->load(); + return false; +} + +int32_t sound_work_play_se(int32_t queue_index, const char* name, float_t volume) { + if (!str_utils_compare(name, "sys_kettei_aif")) + name = "sys_kettei.aif"; + + bool found = false; + for (std::string& i : sound_work->names_list) + if (!i.compare(name)) { + found = true; + break; + } + + if (found || queue_index < 0 || queue_index >= SOUND_WORK_SE_QUEUE_COUNT || !sound_work->se_queue_enable[queue_index]) + return 0; + + SoundCue* cue = 0; + for (SoundCue& i : sound_work->cues) + if (i.se_channel && !i.property) { + cue = &i; + break; + } + + if (!cue) { + int32_t min_counter = sound_work->counter; + for (SoundCue& i : sound_work->cues) + if (!i.name.compare(name) && min_counter > i.counter) { + cue = &i; + min_counter = i.counter; + } + + if (!cue) { + int32_t min_counter = sound_work->counter; + for (SoundCue& i : sound_work->cues) + if (min_counter > i.counter) { + cue = &i; + min_counter = i.counter; + } + + if (!cue) + return 0; + } + + cue->ReleaseProt(true); + } + + float_t cue_volume = volume * sound_work->se_queue_volume[queue_index]; + if (queue_index < 3 || queue_index > 4) + cue_volume *= sound_work->se_volume; + + int32_t counter = cue->Load(queue_index, name, cue_volume); + if (counter) + sound_work->names_list.push_back(name); + return counter; +} + +bool sound_work_read_farc(const char* file_path) { + if (!file_path || sound_work_get_farc(file_path)) + return false; + + sound_db_farc* snd_db_farc = 0; + for (sound_db_farc& i : sound_work->farcs) + if (!i.file_path.size()) { + snd_db_farc = &i; + break; + } + + if (snd_db_farc) + return snd_db_farc->read(file_path); + return false; +} + +void sound_work_release_farc_se(const char* file_path) { + if (!file_path) + return; + + for (SoundCue& i : sound_work->cues) { + if (i.se_channel && !i.property || i.property->farc) + continue; + + sound_db_farc* snd_db_farc = i.property->farc; + if (!snd_db_farc) + continue; + + if (!snd_db_farc->farc.file_path.compare(file_path)) + i.ReleaseProt(true); + } +} + +bool sound_work_release_se(const char* name, bool release) { + if (!name) + return false; + + bool found = false; + for (SoundCue& i : sound_work->cues) + if ((!i.se_channel || i.property) && !i.name.compare(name)) { + i.ReleaseProt(release); + found = true; + } + return found; +} + +float_t sound_cue_queue_volume_array_get_max(int32_t queue_index) { + if (queue_index >= 0 && queue_index < SOUND_WORK_SE_QUEUE_COUNT) + return sound_cue_queue_volume_array[queue_index].max; + return 1.0f; +} + +float_t sound_cue_queue_volume_array_get_min(int32_t queue_index) { + if (queue_index >= 0 && queue_index < SOUND_WORK_SE_QUEUE_COUNT) + return sound_cue_queue_volume_array[queue_index].min; + return 0.0f; +} + +sound::wasapi::System* sound_wasapi_system_data_get() { + return sound_wasapi_system_data; +} + +void sound_work_set_headphones_volume(float_t value) { + float_t min = get_min_headphones_volume(); + float_t max = get_max_headphones_volume(); + value = clamp_def(value, min, max); + if (fabsf(sound_work->headphones_volume - value) > 0.000001f) { + sound_work->headphones_volume = value; + sound_work->headphones_volume_changed = true; + } +} + +void sound_work_set_se_queue_volume(int32_t queue_index, float_t value) { + if (queue_index < 0 || queue_index >= SOUND_WORK_SE_QUEUE_COUNT) + return; + + const SoundCueQueueVolume& vol = sound_cue_queue_volume_array[queue_index]; + sound_work->se_queue_volume[queue_index] = clamp_def(value, vol.min, vol.max); +} + +void sound_work_set_speakers_volume(float_t value) { + float_t min = get_min_speakers_volume(); + float_t max = get_max_speakers_volume(); + value = clamp_def(value, min, max); + if (fabsf(sound_work->speakers_volume - value) > 0.000001f) { + sound_work->speakers_volume = value; + sound_work->speakers_volume_changed = true; + } +} + +bool sound_work_unload_farc(const char* file_path) { + if (!file_path) + return false; + + sound_db_farc* snd_db_farc = sound_work_get_farc(file_path); + if (snd_db_farc) + return snd_db_farc->unload(); + return false; +} + +void wave_audio_storage_init() { + wave_audio_storage = {}; +} + +void wave_audio_storage_clear() { + wave_audio_storage.clear(); +} + +WaveAudio* wave_audio_storage_get_wave_audio(std::string& name) { + auto elem = wave_audio_storage.find(name); + if (elem != wave_audio_storage.end()) + return &elem->second; + return 0; +} + +bool wave_audio_storage_load_wave_audio(std::string& name) { + wave_audio_storage_unload_wave_audio(name); + + sound_db_property* property = sound_work->FindProperty(name.c_str()); + if (!property) + return false; + + WaveAudio wave_audio; + if (wave_audio.Read(property->farc, property->file_name.c_str())) { + wave_audio_storage.insert({ name, wave_audio }); + return true; + } + return false; +} + +void wave_audio_storage_unload_wave_audio(std::string& name) { + auto elem = wave_audio_storage.find(name); + if (elem != wave_audio_storage.end()) { + elem->second.Reset(); + wave_audio_storage.erase(elem); + } +} + +void wave_audio_storage_free() { + wave_audio_storage.clear(); +} + +static size_t ima_decode(int16_t* dst, size_t dst_size, uint8_t* data, size_t samples_count, + size_t channels, ima_storage* storage, size_t storage_size) { + if (!dst || !dst_size || !data || !samples_count || !storage || channels > storage_size) + return 0; + + bool odd_sample = false; + size_t act_samp_count = 0; + for (size_t i = min_def(samples_count, dst_size / sizeof(int16_t)); i; i--, act_samp_count++) { + for (size_t j = channels, k = 0; j; j--, k++, odd_sample ^= true) { + ima_storage& _storage = storage[k]; + int16_t step = ima_step_table[_storage.step_index]; + + uint8_t nibble = (odd_sample ? *data : (*data >> 4)) & 0x0F; + + int32_t diff = step >> 3; + if (nibble & 0x01) + diff += step >> 2; + if (nibble & 0x02) + diff += step >> 1; + if (nibble & 0x04) + diff += step; + if (nibble & 0x08) + diff = -diff; + + int32_t current = _storage.current + diff; + current = clamp_def(current, -0x8000, 0x7FFF); + _storage.current = current; + + int32_t step_index = _storage.step_index + ima_index_table[nibble]; + _storage.step_index = clamp_def(step_index, 0, 88); + + *dst++ = current; + + if (odd_sample) + data++; + } + } + return act_samp_count; +} \ No newline at end of file diff --git a/src/CRE/sound.hpp b/src/CRE/sound.hpp new file mode 100644 index 00000000..d46d4e30 --- /dev/null +++ b/src/CRE/sound.hpp @@ -0,0 +1,352 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/default.hpp" +#include "../KKdLib/farc.hpp" +#include "file_handler.hpp" +#include "lock.hpp" +#include "time.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct sound_buffer_data { + float_t spk_l; + float_t spk_r; + float_t hph_l; + float_t hph_r; +}; + +namespace sound { + namespace wasapi { + enum AudioFormat { + AUDIO_FORMAT_I16 = 0, + AUDIO_FORMAT_I24, + AUDIO_FORMAT_I32, + AUDIO_FORMAT_F32, + }; + + struct Mixer; + struct SEChannel; + struct StreamingChannel; + + struct System { + WAVEFORMATEXTENSIBLE wave_format; + IMMDeviceEnumerator* pEnumerator; + IMMDevice* pDevice; + IAudioClient* pAudioClient; + uint32_t samples_count; + IAudioRenderClient* pRenderClient; + IAudioClockAdjustment* pClockAdjustment; + HANDLE hEvent; + int32_t channels; + int32_t sample_rate; + int32_t bit_depth; + Mixer* mixer; + std::thread* thread; + lock_uint32_t thread_state; + AudioFormat format; + + System(); + virtual ~System(); + + void Init(size_t se_channels_count, size_t streaming_channels_count, + bool separate_speakers_headphones = false); + void Reset(); + + static void ThreadMain(System* system); + }; + + struct Mixer { + System* system; + SEChannel* se_channels; + size_t se_channels_count; + StreamingChannel* streaming_channels; + size_t streaming_channels_count; + sound_buffer_data* mix_buffer; + size_t mix_buffer_size; + std::mutex volume_mtx; + float_t master_volume; + float_t channels_volume[4]; + + Mixer(System* system); + virtual ~Mixer(); + + void FillBuffer(void* buffer, size_t samples_count, + bool disable_headphones_volume, bool invert_phase, AudioFormat format); + SEChannel* GetSEChannel(size_t channel); + StreamingChannel* GetStreamingChannel(size_t channel); + bool Init(size_t se_channels_count, size_t streaming_channels_count, size_t samples_count); + void Reset(); + void SetChannelsVolume(int32_t mask, float_t value); + void SetMasterVolume(float_t value); + }; + + struct SEChannel { + Mixer* mixer; + lock_uint32_t play_state; + std::mutex mtx; + float_t master_volume; + float_t channels_volume[4]; + float_t* buffer; + size_t buffer_size; + size_t channels; + size_t samples_count; + size_t sample_rate; + size_t loop_start; + size_t loop_end; + size_t current_sample; + + SEChannel(); + virtual ~SEChannel(); + + void FillBuffer(sound_buffer_data* buffer, size_t samples_count, float_t volume); + bool Init(Mixer* mixer); + float_t* InitBuffer(size_t channels, size_t samples_count, size_t sample_rate); + bool Play(size_t loop_start = 0, size_t loop_end = 0); + void Reset(); + void ResetData(); + void ResetDataProt(); + void SetChannelsVolume(int32_t mask, float_t value); + void SetMasterVolume(float_t value); + }; + + struct StreamingChannel { + Mixer* mixer; + sound_buffer_data* buffer; + size_t buffer_size; + lock_uint32_t playing_state; + lock_uint32_t reset_state; + std::mutex mtx; + float_t master_volume; + float_t channels_volume[4]; + void(*callback_func)(sound_buffer_data* buffer, size_t samples_count, void* data); + void* callback_data; + + StreamingChannel(); + virtual ~StreamingChannel(); + + void FillBuffer(sound_buffer_data* buffer, size_t samples_count, float_t volume); + bool Init(Mixer* mixer, size_t samples_count); + void Reset(); + void ResetData(); + bool SetCallback(void(*func)(sound_buffer_data* buffer, + size_t samples_count, void* data), void* data); + void SetChannelsVolume(int32_t mask, float_t value); + void SetMasterVolume(float_t value); + }; + } +} + +enum SoundCueDataState { + SOUND_CUE_DATA_STATE_NONE = 0, + SOUND_CUE_DATA_STATE_LOAD, + SOUND_CUE_DATA_STATE_RESET, + SOUND_CUE_DATA_STATE_MAX, +}; + +enum WaveAudioDataFormat { + WAVE_AUDIO_DATA_FORMAT_NONE = 0, + WAVE_AUDIO_DATA_FORMAT_RIFF = 1, + WAVE_AUDIO_DATA_FORMAT_DIVA = 3, +}; + +struct sound_db_farc { + std::string file_path; + bool loaded; + p_file_handler file_handler; + farc farc; + + sound_db_farc(); + ~sound_db_farc(); + + bool load(); + bool read(const char* file_path); + bool unload(); +}; + +struct sound_db_property { + sound_db_farc* farc; + std::string file_name; + float_t volume; + size_t loop_start; + size_t loop_end; + float_t release_time; + //std::string field_28; + //int32_t field_48; + + sound_db_property(); + ~sound_db_property(); +}; + +struct SoundCue; + +struct SoundCueVolume { + SoundCue* cue; + float_t value; + bool set; + + inline SoundCueVolume(SoundCue* cue) : cue(cue), value(), set() { + + } + + inline void SetValue(float_t value) { + this->value = value; + set = true; + } +}; + +struct SoundCue { + lock_uint32_t thread_state; + lock_uint32_t data_state; + std::thread* thread; + std::mutex mtx; + std::condition_variable cnd; + SoundCueVolume* volume; + int32_t queue_index; + std::string name; + sound_db_property* property; + int32_t counter; + float_t release_time; + time_struct time; + lock_uint32_t load_state; + sound::wasapi::SEChannel* se_channel; + + SoundCue(); + ~SoundCue(); + + bool CanPlay(); + void Ctrl(); + int32_t Load(int32_t queue_index, const char* name, float_t volume); + void LoadData(); + void Play(); + void PlayProt(); + void Release(bool force_release); + void ReleaseProt(bool force_release); + void Reset(); + void ResetData(); + void SetSEChannel(sound::wasapi::SEChannel* se_channel); + + static void ThreadMain(SoundCue* cue); +}; + +struct WaveAudioDataFileMemoryStream { + FILE* file; + const void* data; + size_t size; + size_t position; + + inline WaveAudioDataFileMemoryStream(const void* data, size_t size) : file(), + data(data), size(size), position() { + + } +}; + +struct WaveAudioData { + WaveAudioDataFormat format; + size_t channels; + size_t sample_rate; + size_t bit_depth; + size_t samples_count; + size_t position; + size_t data_size; + bool has_loop; + size_t loop_start; + size_t loop_end; + + WaveAudioData(); + ~WaveAudioData(); + + bool Read(WaveAudioDataFileMemoryStream* fms); + bool ReadData(const void* data, size_t size); + bool ReadDiva(WaveAudioDataFileMemoryStream* fms); + void Reset(); +}; + +struct WaveAudio { + float_t* buffer; + size_t buffer_size; + WaveAudioData data; + + WaveAudio(); + + bool Read(sound_db_farc* farc, const char* file_name); + void Reset(); +}; + +#define SOUND_WORK_SE_QUEUE_COUNT 5 +#define SOUND_WORK_STREAMING_COUNT 3 + +struct SoundWork { + std::map properties; + sound_db_farc farcs[16]; + SoundCue cues[32]; + int32_t counter; + std::vector names_list; + bool se_queue_enable[SOUND_WORK_SE_QUEUE_COUNT]; + bool streaming_enable[SOUND_WORK_STREAMING_COUNT]; + float_t speakers_volume; + bool speakers_volume_changed; + float_t headphones_volume; + bool headphones_volume_changed; + float_t se_queue_volume[5]; + float_t se_volume; + + SoundWork(); + virtual ~SoundWork(); + + sound_db_property* FindProperty(const char* name); + bool ParseProperty(sound_db_farc* snd_db_farc); + bool UnloadProperty(const char* file_path); +}; + +extern float_t get_min_headphones_volume(); +extern float_t get_max_headphones_volume(); +extern float_t get_max_speakers_volume(); + +extern float_t db_to_ratio(int32_t value); +extern int32_t ratio_to_db(float_t value); + +extern void sound_init(); +extern void sound_ctrl(); +extern void sound_free(); + +extern float_t sound_cue_queue_volume_array_get_max(int32_t queue_index); +extern float_t sound_cue_queue_volume_array_get_min(int32_t queue_index); + +extern bool sound_work_cue_release(int32_t queue_index, const char* name, bool force_release = true); +extern SoundCue* sound_work_get_cue(int32_t queue_index, const char* name); +extern bool sound_work_get_cue_can_play(int32_t queue_index, const char* name); +extern sound_db_farc* sound_work_get_farc(const char* file_path); +extern float_t sound_work_get_headphones_volume(); +extern float_t sound_work_get_speakers_volume(); +extern bool sound_work_has_property(const char* name); +extern bool sound_work_load_farc(const char* file_path); +extern int32_t sound_work_play_se(int32_t queue_index, const char* name, float_t volume); +extern bool sound_work_read_farc(const char* file_path); +extern void sound_work_release_farc_se(const char* file_path); +extern bool sound_work_release_se(const char* name, bool force_release = true); +extern float_t sound_cue_queue_volume_array_get_max(int32_t queue_index); +extern float_t sound_cue_queue_volume_array_get_min(int32_t queue_index); +extern sound::wasapi::System* sound_wasapi_system_data_get(); +extern void sound_work_set_headphones_volume(float_t value); +extern void sound_work_set_se_queue_volume(int32_t queue_index, float_t value); +extern void sound_work_set_speakers_volume(float_t value); +extern bool sound_work_unload_farc(const char* file_path); + +extern void wave_audio_storage_init(); +extern void wave_audio_storage_clear(); +extern WaveAudio* wave_audio_storage_get_wave_audio(std::string& name); +extern bool wave_audio_storage_load_wave_audio(std::string& name); +extern void wave_audio_storage_unload_wave_audio(std::string& name); +extern void wave_audio_storage_free(); diff --git a/src/CRE/stage.cpp b/src/CRE/stage.cpp index a211e1e9..ef1a3023 100644 --- a/src/CRE/stage.cpp +++ b/src/CRE/stage.cpp @@ -237,7 +237,7 @@ static void stage_detail::TaskStage_CtrlInner(stage_detail::TaskStage* a1) { if (!a1->state) { a1->state = 3; int32_t stage_count = (int32_t)a1->load_stage_indices.size(); - stage_count = min(stage_count, TASK_STAGE_STAGE_COUNT); + stage_count = min_def(stage_count, TASK_STAGE_STAGE_COUNT); for (int32_t i = 0; i < stage_count; i++) if (a1->stages[i].index == -1) stage_set_by_stage_index(&a1->stages[i], a1->load_stage_indices[i], stage_counter++); diff --git a/src/CRE/stage_modern.cpp b/src/CRE/stage_modern.cpp index d5510ac1..1a6680fb 100644 --- a/src/CRE/stage_modern.cpp +++ b/src/CRE/stage_modern.cpp @@ -208,7 +208,7 @@ static void stage_detail::TaskStageModern_CtrlInner(stage_detail::TaskStageModer if (!a1->state) { a1->state = 3; int32_t stage_count = (int32_t)a1->load_stage_hashes.size(); - stage_count = min(stage_count, TASK_STAGE_STAGE_COUNT); + stage_count = min_def(stage_count, TASK_STAGE_STAGE_COUNT); for (int32_t i = 0; i < stage_count; i++) if (a1->stages[i].hash == -1 || a1->stages[i].hash == hash_murmurhash_empty) stage_modern_set_by_stage_hash(&a1->stages[i], @@ -687,11 +687,11 @@ static void stage_modern_set_by_stage_hash(stage_modern* s, int32_t stage_hash, char set_name[11]; set_name[0] = 0; - if (!strncmp(name, "STGPV", min(name_len, 5))) { + if (!strncmp(name, "STGPV", min_def(name_len, 5))) { memcpy(set_name, name, 8); set_name[8] = 0; } - else if (!strncmp(name, "STGD2PV", min(name_len, 7))) { + else if (!strncmp(name, "STGD2PV", min_def(name_len, 7))) { memcpy(set_name, name, 10); set_name[10] = 0; } diff --git a/src/CRE/static_var.cpp b/src/CRE/static_var.cpp index 0209577c..e90ef439 100644 --- a/src/CRE/static_var.cpp +++ b/src/CRE/static_var.cpp @@ -43,7 +43,7 @@ const mat3 sv_ypbpr_to_rgb = { }; void sv_anisotropy_set(int32_t value) { - sv_anisotropy = 1 << (int32_t)roundf(log2f((float_t)clamp(value, 1, sv_max_texture_max_anisotropy))); + sv_anisotropy = 1 << (int32_t)roundf(log2f((float_t)clamp_def(value, 1, sv_max_texture_max_anisotropy))); if (sv_anisotropy != sv_old_anisotropy) sv_anisotropy_changed = true; sv_old_anisotropy = sv_anisotropy; diff --git a/src/CRE/static_var.hpp b/src/CRE/static_var.hpp index 6a0fdf2b..96479da6 100644 --- a/src/CRE/static_var.hpp +++ b/src/CRE/static_var.hpp @@ -22,7 +22,7 @@ enum draw_pass_3d_type { enum uniform_name { U_NONE = 0x00, - U01 = 0x01, + U_ALPHA_MASK = 0x01, U_ALPHA_TEST = 0x02, U_ANISO = 0x03, U_AET_BACK = 0x04, @@ -53,7 +53,7 @@ enum uniform_name { U_MAGNIFY = 0x1D, U_MEMBRANE = 0x1E, U_MLAA = 0x1F, - U20 = 0x20, + U_MLAA_SEARCH = 0x20, U_MORPH_COLOR = 0x21, U_MORPH = 0x22, U_MOVIE = 0x23, @@ -102,7 +102,7 @@ extern int32_t sv_max_texture_max_anisotropy; extern bool sv_anisotropy_changed; extern int32_t sv_anisotropy; -extern int32_t uniform_value[]; +extern int32_t uniform_value[U_MAX]; extern const vec3 sv_rgb_to_luma; extern const mat3 sv_rgb_to_ypbpr; diff --git a/src/CRE/task.cpp b/src/CRE/task.cpp index 8a545f2b..33e74331 100644 --- a/src/CRE/task.cpp +++ b/src/CRE/task.cpp @@ -116,7 +116,7 @@ namespace app { } size_t len = utf8_length(name); - len = min(len, sizeof(this->name) - 1); + len = min_def(len, sizeof(this->name) - 1); memmove(&this->name, name, len); this->name[len] = 0; } @@ -231,7 +231,7 @@ namespace app { for (Task*& i : task_work->tasks) i->SetDest(); } - + void TaskWork::Disp() { task_work->disp = true; for (int32_t i = 0; i < 3; i++) @@ -369,7 +369,7 @@ namespace app { uint32_t frame_counter = get_frame_counter(); if (frame_counter == (frame_counter / 300) * 300) t->calc_time_max = 0; - t->calc_time = max(t->calc_time, t->calc_time_max); + t->calc_time = max_def(t->calc_time, t->calc_time_max); } static void Task_set_disp_time(Task* t, uint32_t disp_time) { @@ -377,7 +377,7 @@ namespace app { uint32_t frame_counter = get_frame_counter(); if (frame_counter == (frame_counter / 300) * 300) t->disp_time_max = 0; - t->disp_time = max(t->disp_time, t->disp_time_max); + t->disp_time = max_def(t->disp_time, t->disp_time_max); } static bool Task_sub_14019B810(Task* t, int32_t a2) { diff --git a/src/CRE/task_effect.cpp b/src/CRE/task_effect.cpp index 1e9b29a4..bcb9da8d 100644 --- a/src/CRE/task_effect.cpp +++ b/src/CRE/task_effect.cpp @@ -300,7 +300,7 @@ void TaskEffectFogAnim::Data::Ctrl() { float_t v4 = field_C[0] * DEG_TO_RAD_FLOAT; float_t v7 = (sinf(v4 - 1.5f) + 1.0f) * 0.5f + field_34.x; - v7 = min(v7, 1.0f) * field_24; + v7 = min_def(v7, 1.0f) * field_24; float_t v8 = sinf(v4) * v7; float_t v9 = cosf(v4); @@ -309,7 +309,7 @@ void TaskEffectFogAnim::Data::Ctrl() { color.y = (float_t)(1.0 - v8 * 0.345686 - ((double_t)v9 * v7) * 0.714486); color.z = (float_t)(v8 * 1.771 + 1.0); color.w = 1.0f; - vec3_max(*(vec3*)&color, vec3_null, *(vec3*)&color); + *(vec3*)&color = vec3::max(*(vec3*)&color, vec3_null); for (int32_t i = 0; i < 3; i++) { float_t v20 = (field_18[i] * 10.0f) + field_C[i]; @@ -321,8 +321,7 @@ void TaskEffectFogAnim::Data::Ctrl() { fog& fog = rctx_ptr->fog[FOG_DEPTH]; fog.set_color(color); - vec3_add_scalar(*(vec3*)&color, 1.0f, *(vec3*)&color); - vec3_mult_scalar(*(vec3*)&color, 0.8f, *(vec3*)&color); + *(vec3*)&color = (*(vec3*)&color + 1.0f) * 0.8f; light_set& light_set = rctx_ptr->light_set[LIGHT_SET_MAIN]; light_set.lights[LIGHT_CHARA].set_diffuse(color); @@ -415,7 +414,7 @@ bool TaskEffectFogRing::Init() { bool TaskEffectFogRing::Ctrl() { data.delta_frame = data.frame_rate_control->GetDeltaFrame(); - data.Ctrl();; + data.Ctrl(); return 0; } diff --git a/src/CRE/task_effect.hpp b/src/CRE/task_effect.hpp index f02a22c3..e0a6827f 100644 --- a/src/CRE/task_effect.hpp +++ b/src/CRE/task_effect.hpp @@ -63,8 +63,6 @@ public: virtual void Field_A8(int32_t a2, int8_t* a3); }; -; - struct struc_621 { int32_t stage_index; std::vector auth_3d_ids; diff --git a/src/CRE/texture.cpp b/src/CRE/texture.cpp index ab1293b9..e7ade2d7 100644 --- a/src/CRE/texture.cpp +++ b/src/CRE/texture.cpp @@ -8,6 +8,15 @@ #include "../KKdLib/txp.hpp" #include "gl_state.hpp" #include "static_var.hpp" +#include +#include + +struct texture_params { + GLenum target; + GLint wrap_s; + GLint wrap_t; + GLint wrap_r; +}; static void texture_get_format_type_by_internal_format(GLenum internal_format, GLenum* format, GLenum* type); static uint32_t texture_get_height_align_mip_level(texture* tex, int32_t mip_level); @@ -21,10 +30,11 @@ static int32_t texture_load(GLenum target, GLenum internal_format, static texture* texture_load_tex(texture_id id, GLenum target, GLenum internal_format, int32_t width, int32_t height, int32_t max_mipmap_level, void** data_ptr, bool use_high_anisotropy); -static void texture_set_params(GLenum target, int32_t max_mipmap_level, bool use_high_anisotropy); +static void texture_set_params(GLuint texture, GLenum target, int32_t max_mipmap_level, bool use_high_anisotropy); static GLenum texture_txp_get_internal_format(txp* t); std::vector texture_storage; +std::map texture_params_storage; texture_id::texture_id() : id(0), index(0) { @@ -86,7 +96,7 @@ void texture_apply_color_tone(texture* chg_tex, } glBindTexture(org_tex->target, 0); glGetError(); - free(data); + free_def(data); } } @@ -119,7 +129,7 @@ texture* texture_copy(texture_id id, texture* org_tex) { org_tex->width, org_tex->height, org_tex->max_mipmap_level, vec_data.data(), true); for (void*& i : vec_data) - free(i); + free_def(i); return tex; } @@ -156,7 +166,7 @@ texture* texture_txp_load(txp* t, texture_id id) { tex = texture_load_tex_cube_map(id, internal_format, width, height, max_mipmap_level, data_ptr); else tex = texture_load_tex_2d(id, internal_format, width, height, max_mipmap_level, data_ptr, true); - free(data_ptr); + free_def(data_ptr); return tex; } @@ -192,6 +202,7 @@ bool texture_txp_set_load(txp_set* t, texture*** texs, texture_id* ids) { inline void texture_storage_init() { texture_storage = {}; + texture_params_storage = {}; } inline texture* texture_storage_create_texture(texture_id id) { @@ -241,6 +252,7 @@ inline void texture_storage_delete_texture(texture_id id) { break; } + texture_params_storage.erase(tex->tex); glDeleteTextures(1, &tex->tex); delete tex; i = texture_storage.erase(i); @@ -248,12 +260,90 @@ inline void texture_storage_delete_texture(texture_id id) { } } +inline void texture_storage_set_texture_wrap(GLuint texture, GLint wrap_s, GLint wrap_t) { + auto elem = texture_params_storage.find(texture); + if (elem == texture_params_storage.end()) + return; + + texture_params& params = elem->second; + if (params.wrap_s != wrap_s) { + glTexParameteri(params.target, GL_TEXTURE_WRAP_S, wrap_s); + params.wrap_s = wrap_s; + } + + if (params.wrap_t != wrap_t) { + glTexParameteri(params.target, GL_TEXTURE_WRAP_T, wrap_t); + params.wrap_t = wrap_t; + } +} + +inline void texture_storage_set_texture_wrap(GLuint texture, GLint wrap_s, GLint wrap_t, GLint wrap_r) { + auto elem = texture_params_storage.find(texture); + if (elem == texture_params_storage.end()) + return; + + texture_params& params = elem->second; + if (params.wrap_s != wrap_s) { + glTexParameteri(params.target, GL_TEXTURE_WRAP_S, wrap_s); + params.wrap_s = wrap_s; + } + + if (params.wrap_t != wrap_t) { + glTexParameteri(params.target, GL_TEXTURE_WRAP_T, wrap_t); + params.wrap_t = wrap_t; + } + + if (params.wrap_r != wrap_r) { + glTexParameteri(params.target, GL_TEXTURE_WRAP_R, wrap_r); + params.wrap_r = wrap_r; + } +} + +inline void texture_storage_set_texture_wrap_s(GLuint texture, GLint wrap) { + auto elem = texture_params_storage.find(texture); + if (elem == texture_params_storage.end()) + return; + + texture_params& params = elem->second; + if (params.wrap_s != wrap) { + glTexParameteri(params.target, GL_TEXTURE_WRAP_S, wrap); + params.wrap_s = wrap; + } +} + +inline void texture_storage_set_texture_wrap_t(GLuint texture, GLint wrap) { + auto elem = texture_params_storage.find(texture); + if (elem == texture_params_storage.end()) + return; + + texture_params& params = elem->second; + if (params.wrap_t != wrap) { + glTexParameteri(params.target, GL_TEXTURE_WRAP_T, wrap); + params.wrap_t = wrap; + } +} + +inline void texture_storage_set_texture_wrap_r(GLuint texture, GLint wrap) { + auto elem = texture_params_storage.find(texture); + if (elem == texture_params_storage.end()) + return; + + texture_params& params = elem->second; + if (params.wrap_r != wrap) { + glTexParameteri(params.target, GL_TEXTURE_WRAP_R, wrap); + params.wrap_r = wrap; + } +} + inline void texture_storage_free() { for (texture*& i : texture_storage) { - if (i) + if (i) { + texture_params_storage.erase(i->tex); glDeleteTextures(1, &i->tex); + } delete i; } + texture_params_storage.clear(); texture_storage.clear(); texture_storage.shrink_to_fit(); } @@ -372,13 +462,13 @@ static void texture_get_format_type_by_internal_format(GLenum internal_format, G inline static uint32_t texture_get_height_align_mip_level(texture* tex, int32_t mip_level) { uint32_t height = tex->height >> mip_level; if (tex->flags & TEXTURE_BLOCK_COMPRESSION) - return max(height, 4); - return max(height, 1); + return max_def(height, 4); + return max_def(height, 1); } inline static uint32_t texture_get_height_mip_level(texture* tex, int32_t mip_level) { uint32_t height = tex->height >> mip_level; - return max(height, 1); + return max_def(height, 1); } static int32_t texture_get_size(GLenum internal_format, int32_t width, int32_t height) { @@ -431,19 +521,19 @@ static int32_t texture_get_size(GLenum internal_format, int32_t width, int32_t h inline static int32_t texture_get_size_mip_level(texture* tex, int32_t mip_level) { int32_t width = tex->width >> mip_level; int32_t height = tex->height >> mip_level; - return texture_get_size(tex->internal_format, max(width, 1), max(height, 1)); + return texture_get_size(tex->internal_format, max_def(width, 1), max_def(height, 1)); } inline static uint32_t texture_get_width_align_mip_level(texture* tex, int32_t mip_level) { uint32_t width = tex->width >> mip_level; if (tex->flags & TEXTURE_BLOCK_COMPRESSION) - return max(width, 4); - return max(width, 1); + return max_def(width, 4); + return max_def(width, 1); } inline static uint32_t texture_get_width_mip_level(texture* tex, int32_t mip_level) { uint32_t width = tex->width >> mip_level; - return max(width, 1); + return max_def(width, 1); } static int32_t texture_load(GLenum target, GLenum internal_format, @@ -478,6 +568,7 @@ static texture* texture_load_tex(texture_id id, GLenum target, return tex; glGenTextures(1, &tex->tex); + texture_params_storage.insert({ tex->tex, { target } }); switch (target) { case GL_TEXTURE_2D: gl_state_bind_texture_2d(tex->tex); @@ -486,7 +577,7 @@ static texture* texture_load_tex(texture_id id, GLenum target, gl_state_bind_texture_cube_map(tex->tex); break; } - texture_set_params(target, max_mipmap_level, use_high_anisotropy); + texture_set_params(tex->tex, target, max_mipmap_level, use_high_anisotropy); GLint swizzle[4]; switch (internal_format) { @@ -534,8 +625,8 @@ static texture* texture_load_tex(texture_id id, GLenum target, if (target == GL_TEXTURE_CUBE_MAP) for (int32_t i = 0; i < 6; i++) for (int32_t j = 0; j <= max_mipmap_level; j++) { - int32_t mip_width = max(width >> j, 1); - int32_t mip_height = max(height >> j, 1); + int32_t mip_width = max_def(width >> j, 1); + int32_t mip_height = max_def(height >> j, 1); void* data; if (data_ptr) data = data_ptr[i * (max_mipmap_level + 1) + j]; @@ -555,8 +646,8 @@ static texture* texture_load_tex(texture_id id, GLenum target, } else for (int32_t i = 0; i <= max_mipmap_level; i++) { - int32_t mip_width = max(width >> i, 1); - int32_t mip_height = max(height >> i, 1); + int32_t mip_width = max_def(width >> i, 1); + int32_t mip_height = max_def(height >> i, 1); void* data; if (data_ptr) data = data_ptr[i]; @@ -611,24 +702,20 @@ fail: return 0; } -static void texture_set_params(GLenum target, int32_t max_mipmap_level, bool use_high_anisotropy) { - 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); +static void texture_set_params(GLuint texture, GLenum target, int32_t max_mipmap_level, bool use_high_anisotropy) { + texture_storage_set_texture_wrap(target, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, (float_t*)&vec4_null); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - GLenum min_filter = GL_LINEAR; - if (max_mipmap_level > 0) - min_filter = GL_LINEAR_MIPMAP_LINEAR; - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filter); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, + max_mipmap_level > 0 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, max_mipmap_level); float_t max_anisotropy; if (use_high_anisotropy) - max_anisotropy = 16.0; + max_anisotropy = 16.0f; else - max_anisotropy = 1.0; + max_anisotropy = 1.0f; glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy); } diff --git a/src/CRE/texture.hpp b/src/CRE/texture.hpp index cd1444ea..3d022c81 100644 --- a/src/CRE/texture.hpp +++ b/src/CRE/texture.hpp @@ -5,7 +5,6 @@ #pragma once -#include #include "../KKdLib/default.hpp" #include "../KKdLib/image.hpp" #include "../KKdLib/txp.hpp" @@ -83,4 +82,9 @@ extern texture* texture_storage_get_texture(texture_id id); extern size_t texture_storage_get_texture_count(); extern texture* texture_storage_get_texture_by_index(size_t index); extern void texture_storage_delete_texture(texture_id id); +extern void texture_storage_set_texture_wrap(GLuint texture, GLint wrap_s, GLint wrap_t); +extern void texture_storage_set_texture_wrap(GLuint texture, GLint wrap_s, GLint wrap_t, GLint wrap_r); +extern void texture_storage_set_texture_wrap_s(GLuint texture, GLint wrap); +extern void texture_storage_set_texture_wrap_t(GLuint texture, GLint wrap); +extern void texture_storage_set_texture_wrap_r(GLuint texture, GLint wrap); extern void texture_storage_free(); diff --git a/src/CRE/timer.cpp b/src/CRE/timer.cpp index b3eab31b..bd8bb9c7 100644 --- a/src/CRE/timer.cpp +++ b/src/CRE/timer.cpp @@ -5,109 +5,106 @@ #include "timer.hpp" -timer::timer(double_t freq) : history() { +timer::timer(double_t freq) : history(), curr_time(), prev_time(), inv_freq() { for (double_t& i : history) i = freq; history_counter = 0; this->freq = freq; this->freq_hist = freq; - lock_init(&freq_lock); - lock_init(&freq_hist_lock); - timer_handle = timer_handle_init(); + + LARGE_INTEGER frequency; + if (QueryPerformanceFrequency(&frequency)) + inv_freq = 1000.0 / (double_t)frequency.LowPart; + else + inv_freq = 0.0; + + if (!QueryPerformanceCounter(&curr_time)) + curr_time.QuadPart = 0; + if (!QueryPerformanceCounter(&prev_time)) + prev_time.QuadPart = 0; } timer::~timer() { - lock_free(&freq_lock); - lock_free(&freq_hist_lock); - timer_handle_dispose(timer_handle); + } void timer::start_of_cycle() { - double_t time = prev_time.calc_time(); - prev_time.get_timestamp(); - double_t freq = 0; + LARGE_INTEGER timestamp; + if (!QueryPerformanceCounter(×tamp)) + timestamp.QuadPart = 0; + + double_t time = (timestamp.QuadPart - curr_time.QuadPart) * inv_freq; + + if (!QueryPerformanceCounter(&curr_time)) + curr_time.QuadPart = 0; + + history[history_counter] = time; + + double_t freq = 0.0; for (uint8_t i = 0; i < history_counter; i++) freq += history[i]; - freq += history[history_counter] = 1000.0 / time; + freq += time; for (uint8_t i = history_counter + 1; i < HISTORY_COUNT; i++) freq += history[i]; + history_counter++; if (history_counter >= HISTORY_COUNT) history_counter = 0; - lock_lock(&freq_hist_lock); - freq_hist = freq / HISTORY_COUNT; - lock_unlock(&freq_hist_lock); + + std::unique_lock u_lock(freq_mtx); + freq_hist = 1000.0 / (freq / HISTORY_COUNT); } void timer::end_of_cycle() { - double_t msec = 1000.0 / get_freq() - prev_time.calc_time(); - timer_handle_sleep(timer_handle, msec); + LONGLONG& curr_timestamp = curr_time.QuadPart; + LONGLONG& prev_timestamp = prev_time.QuadPart; + + double_t msec = 1000.0 / get_freq() - (curr_timestamp - prev_timestamp) * inv_freq; + if (floor(msec) > 0) + wait_timer.sleep_float(msec); + + if (msec < -get_freq() / 4.0) + prev_timestamp = curr_timestamp - (LONGLONG)(get_freq() / 4.0 / inv_freq); + else + prev_timestamp = curr_timestamp + (LONGLONG)(msec / inv_freq); } double_t timer::get_freq() { - double_t freq = 0.0; - lock_lock(&freq_lock); - freq = this->freq; - lock_unlock(&freq_lock); + std::unique_lock u_lock(freq_mtx); return freq; } void timer::set_freq(double_t freq) { - lock_lock(&freq_lock); + std::unique_lock u_lock(freq_mtx); this->freq = freq; - lock_unlock(&freq_lock); } double_t timer::get_freq_hist() { - double_t freq = 0.0; - lock_lock(&freq_hist_lock); - freq = freq_hist; - lock_unlock(&freq_hist_lock); - return freq; + std::unique_lock u_lock(freq_hist_mtx); + return freq_hist; } double_t timer::get_freq_ratio() { - double_t freq = 0.0; - lock_lock(&freq_lock); - freq = this->freq; - lock_unlock(&freq_lock); - lock_lock(&freq_hist_lock); - freq /= freq_hist; - lock_unlock(&freq_hist_lock); - return freq; + double_t freq_ratio = 0.0; + { + std::unique_lock u_lock(freq_mtx); + freq_ratio = freq; + } + + { + std::unique_lock u_lock(freq_hist_mtx); + freq_ratio /= freq_hist; + } + return freq_ratio; } void timer::reset() { - curr_time.get_timestamp(); - prev_time.get_timestamp(); + if (!QueryPerformanceCounter(&curr_time)) + curr_time.QuadPart = 0; + if (!QueryPerformanceCounter(&prev_time)) + prev_time.QuadPart = 0; } void timer::sleep(double_t msec) { - timer_handle_sleep(timer_handle, msec); -} - -inline HANDLE timer_handle_init() { - return CreateWaitableTimerW(0, 0, 0); -} - -inline void timer_handle_sleep(HANDLE timer, double_t msec) { - if (msec <= 0.0) - return; - - if (timer) { - LARGE_INTEGER t; - t.QuadPart = (LONGLONG)round(msec * -10000.0); - SetWaitableTimer(timer, &t, 0, 0, 0, 0); - WaitForSingleObject(timer, INFINITE); - } - else { - DWORD msec_dw = (DWORD)round(msec); - if (msec_dw) - Sleep(msec_dw); - } -} - -inline void timer_handle_dispose(HANDLE timer) { - if (timer) - CloseHandle(timer); + wait_timer.sleep_float(msec); } diff --git a/src/CRE/timer.hpp b/src/CRE/timer.hpp index 5255a248..3663f3da 100644 --- a/src/CRE/timer.hpp +++ b/src/CRE/timer.hpp @@ -6,21 +6,22 @@ #pragma once #include "../KKdLib/default.hpp" -#include "lock.hpp" -#include "time.hpp" +#include "waitable_timer.hpp" +#include #define HISTORY_COUNT 0x08 struct timer { double_t history[HISTORY_COUNT]; uint8_t history_counter; - time_struct curr_time; - time_struct prev_time; + LARGE_INTEGER curr_time; + LARGE_INTEGER prev_time; + double_t inv_freq; double_t freq; double_t freq_hist; - lock freq_lock; - lock freq_hist_lock; - HANDLE timer_handle; + std::mutex freq_mtx; + std::mutex freq_hist_mtx; + waitable_timer wait_timer; timer(double_t freq); virtual ~timer(); @@ -34,9 +35,3 @@ struct timer { void reset(); void sleep(double_t msec); }; - -extern LARGE_INTEGER performance_frequency; - -extern HANDLE timer_handle_init(); -extern void timer_handle_sleep(HANDLE timer, double_t msec); -extern void timer_handle_dispose(HANDLE timer); diff --git a/src/CRE/waitable_timer.hpp b/src/CRE/waitable_timer.hpp new file mode 100644 index 00000000..be394cf4 --- /dev/null +++ b/src/CRE/waitable_timer.hpp @@ -0,0 +1,57 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/default.hpp" + +struct waitable_timer { + HANDLE handle; + + inline waitable_timer() { + handle = CreateWaitableTimerW(0, 0, 0); + } + + inline ~waitable_timer() { + if (handle) { + CloseHandle(handle); + handle = 0; + } + } + + inline void sleep(int64_t msec) { + if (msec <= 0.0) + return; + + if (handle) { + LARGE_INTEGER t; + t.QuadPart = (LONGLONG)(msec * -10000); + SetWaitableTimer(handle, &t, 0, 0, 0, 0); + WaitForSingleObject(handle, INFINITE); + } + else { + DWORD msec_dw = (DWORD)msec; + if (msec_dw) + Sleep(msec_dw); + } + } + + inline void sleep_float(double_t msec) { + if (msec <= 0.0) + return; + + if (handle) { + LARGE_INTEGER t; + t.QuadPart = (LONGLONG)round(msec * -10000.0); + SetWaitableTimer(handle, &t, 0, 0, 0, 0); + WaitForSingleObject(handle, INFINITE); + } + else { + DWORD msec_dw = (DWORD)round(msec); + if (msec_dw) + Sleep(msec_dw); + } + } +}; diff --git a/src/DivaGL/DivaGL.vcxproj b/src/DivaGL/DivaGL.vcxproj index 7e8ac966..63847aa7 100644 --- a/src/DivaGL/DivaGL.vcxproj +++ b/src/DivaGL/DivaGL.vcxproj @@ -248,7 +248,7 @@ del "$(SolutionDir)bin\$(TargetName).lib" NotUsing Level3 - MaxSpeed + Full WIN32;DEBUG;%(PreprocessorDefinitions) $(SolutionDir)extern\src true @@ -286,7 +286,7 @@ del "$(SolutionDir)bin\$(TargetName).lib" NotUsing Level3 - MaxSpeed + Full WIN32;DEBUG;DIVAGL_DEV;%(PreprocessorDefinitions) $(SolutionDir)extern\src true @@ -417,7 +417,7 @@ del "$(SolutionDir)bin\$(TargetName).lib" NotSet false ProgramDatabase - OnlyExplicitInline + AnySuitable true FastCall CompileAsCpp @@ -459,7 +459,7 @@ del "$(SolutionDir)bin\$(TargetName).lib" NotSet false ProgramDatabase - OnlyExplicitInline + AnySuitable true FastCall CompileAsCpp diff --git a/src/DivaGL/bone_data.cpp b/src/DivaGL/bone_data.cpp index da50b265..0e7544bc 100644 --- a/src/DivaGL/bone_data.cpp +++ b/src/DivaGL/bone_data.cpp @@ -1193,8 +1193,8 @@ void bone_data_mult_ik(bone_data* a1, int32_t skeleton_select) { v23 = (v28 + v21) / (2.0f * v10); v22 = (v28 - v21) / (2.0f * v20); - v23 = clamp(v23, -1.0f, 1.0f); - v22 = clamp(v22, -1.0f, 1.0f); + v23 = clamp_def(v23, -1.0f, 1.0f); + v22 = clamp_def(v22, -1.0f, 1.0f); v24 = sqrtf(1.0f - v23 * v23); v25 = sqrtf(1.0f - v22 * v22); @@ -2982,7 +2982,7 @@ static void sub_140412BB0(motion_blend_mot* a1, vector_old_bone_data* a2) { } static void sub_1403FBF10(MotionBlend* a1, float_t a2) { - a1->blend = clamp(a2, 0.0f, 1.0f); + a1->blend = clamp_def(a2, 0.0f, 1.0f); a1->field_8 = 1; a1->rot_y = true; } @@ -3690,10 +3690,10 @@ void rob_chara_reset_data(rob_chara* a1, rob_chara_pv_data* a2) { } static void skin_param_hinge_limit(skin_param_hinge* hinge) { - hinge->ymin = max(hinge->ymin, -179.0f) * DEG_TO_RAD_FLOAT; - hinge->ymax = min(hinge->ymax, 179.0f) * DEG_TO_RAD_FLOAT; - hinge->zmin = max(hinge->zmin, -179.0f) * DEG_TO_RAD_FLOAT; - hinge->zmax = min(hinge->zmax, 179.0f) * DEG_TO_RAD_FLOAT; + hinge->ymin = max_def(hinge->ymin, -179.0f) * DEG_TO_RAD_FLOAT; + hinge->ymax = min_def(hinge->ymax, 179.0f) * DEG_TO_RAD_FLOAT; + hinge->zmin = max_def(hinge->zmin, -179.0f) * DEG_TO_RAD_FLOAT; + hinge->zmax = min_def(hinge->zmax, 179.0f) * DEG_TO_RAD_FLOAT; } static void rob_osage_node_data_init(rob_osage_node_data *node_data) { @@ -4505,7 +4505,7 @@ static int32_t sub_140483EA0(vec3* a1, vec3* a2, osage_coli* a3, float_t radius) vec3_dot(v63, a3->bone_pos_diff, v36); v36 *= v25; float_t v37 = v36 * v36; - v37 = min(v37, 1.0f); + v37 = min_def(v37, 1.0f); v22 *= 0.5f; float_t v38 = v22 * v22 - v61; if (v38 < 0.0f) @@ -5075,7 +5075,7 @@ void ExOsageBlock__Field_20(ExOsageBlock* osg) { } void sub_140482DF0(struc_477* dst, struc_477* src0, struc_477* src1, float_t blend) { - dst->length = lerp(src0->length, src1->length, blend); + dst->length = lerp_def(src0->length, src1->length, blend); vec3_lerp_scalar(src0->angle, src1->angle, dst->angle, blend); } @@ -5188,8 +5188,8 @@ void sub_14047E240(rob_osage* rob_osg, mat4* a2, vec3* a3, vector_old_opd_blend_ for (rob_osage_node* i = rob_osg->nodes.begin + 1; i != rob_osg->nodes.end; i++) { float_t v54 = i->field_1B0.field_0.angle.y; float_t v55 = i->field_1B0.field_0.angle.z; - v54 = clamp(v54, (float_t)-M_PI, (float_t)M_PI); - v55 = clamp(v55, (float_t)-M_PI, (float_t)M_PI); + v54 = clamp_def(v54, (float_t)-M_PI, (float_t)M_PI); + v55 = clamp_def(v55, (float_t)-M_PI, (float_t)M_PI); mat4_rotate_z_mult(&v85, v55, &v85); mat4_rotate_y_mult(&v85, v54, &v85); mat4_transpose(&v85, &v85); @@ -5273,7 +5273,7 @@ void ExOsageBlock__Field_50(ExOsageBlock* osg) { rob_osage_coli_set(&osg->rob, osg->mat); sub_14047C770(&osg->rob, parent_node->ex_data_mat, &parent_scale, osg->step, 1); float_t step = 0.5f * osg->step; - osg->step = max(step, 1.0f); + osg->step = max_def(step, 1.0f); } bool sub_14053D1B0(vec3* l_trans, vec3* r_trans, diff --git a/src/DivaGL/inject.cpp b/src/DivaGL/inject.cpp index dca1aa2d..2a8131ce 100644 --- a/src/DivaGL/inject.cpp +++ b/src/DivaGL/inject.cpp @@ -100,7 +100,7 @@ void inject_patches() { for (int32_t i = 0; i < sizeof(patch_data) / sizeof(patch_struct); i++) if (patch_data[i].func_ptr) { - free(patch_data[i].orig_data); + free_def(patch_data[i].orig_data); memcpy(&buf[2], &patch_data[i].func_ptr, sizeof(uint64_t)); patch_data[i].orig_data = inject_data(patch_data[i].address, buf, 12); } @@ -125,7 +125,7 @@ void inject_restore() { for (int32_t i = 0; i < sizeof(patch_data) / sizeof(patch_struct); i++) if (patch_data[i].func_ptr) { void* data = inject_data(patch_data[i].address, patch_data[i].orig_data, 12); - free(data); + free_def(data); } inject_uint64_t((void*)0x0000000140966008, (uint64_t)glutMainLoop); diff --git a/src/DivaGL/shader_table.cpp b/src/DivaGL/shader_table.cpp index b6fc8908..fc8dc64e 100644 --- a/src/DivaGL/shader_table.cpp +++ b/src/DivaGL/shader_table.cpp @@ -197,8 +197,8 @@ int32_t FASTCALL shader_bind(shader* shader, shader_sub_enum name) { int32_t* fp_unival_max = subshader->fp_unival_max; for (size_t i = 0; i < use_unis_count; i++) { int32_t unival = uniform->array[shader->use_uniform[i]]; - unival_vp += unival_vp_curr * min(unival, vp_unival_max[i]); - unival_fp += unival_fp_curr * min(unival, fp_unival_max[i]); + unival_vp += unival_vp_curr * min_def(unival, vp_unival_max[i]); + unival_fp += unival_fp_curr * min_def(unival, fp_unival_max[i]); unival_vp_curr *= vp_unival_max[i] + 1; unival_fp_curr *= fp_unival_max[i] + 1; } diff --git a/src/DivaGL/string.cpp b/src/DivaGL/string.cpp index ab58161f..a5426289 100644 --- a/src/DivaGL/string.cpp +++ b/src/DivaGL/string.cpp @@ -111,7 +111,7 @@ inline void string_copy(string* src, string* dst) { inline void string_copy_wstring(wstring* src, string* dst) { char* temp = utf16_to_utf8(wstring_data(src)); string_init(dst, temp); - free(temp); + free_def(temp); } inline void string_replace(string* src, string* dst) { @@ -123,7 +123,7 @@ inline void string_replace_wstring(wstring* src, string* dst) { char* temp = utf16_to_utf8(wstring_data(src)); string_free(dst); string_init(dst, temp); - free(temp); + free_def(temp); } inline bool string_compare(string* str0, string* str1) { @@ -135,7 +135,7 @@ inline bool string_compare(string* str0, string* str1) { inline void string_free(string* s) { if (s->capacity > STRING_NULL_LENGTH) - free(s->ptr); + free_def(s->ptr); *s = string_empty; } @@ -220,7 +220,7 @@ inline void wstring_copy(wstring* src, wstring* dst) { inline void wstring_copy_string(string* src, wstring* dst) { wchar_t* temp = utf8_to_utf16(string_data(src)); wstring_init(dst, temp); - free(temp); + free_def(temp); } inline void wstring_replace(wstring* src, wstring* dst) { @@ -232,7 +232,7 @@ inline void wstring_replace_string(string* src, wstring* dst) { wchar_t* temp = utf8_to_utf16(string_data(src)); wstring_free(dst); wstring_init(dst, temp); - free(temp); + free_def(temp); } inline bool wstring_compare(wstring* str0, wstring* str1) { @@ -244,7 +244,7 @@ inline bool wstring_compare(wstring* str0, wstring* str1) { inline void wstring_free(wstring* s) { if (s->capacity > WSTRING_NULL_LENGTH) - free(s->ptr); + free_def(s->ptr); *s = wstring_empty; } @@ -257,7 +257,7 @@ static void string_reserve(string* s, ssize_t size) { capacity = (capacity >> 1) + capacity; else capacity = 0; - capacity = max(capacity, s->length + size); + capacity = max_def(capacity, s->length + size); capacity |= STRING_NULL_LENGTH; char* src = string_data(s); @@ -274,7 +274,7 @@ static void string_reserve(string* s, ssize_t size) { s->ptr = dst; if (s->capacity > STRING_NULL_LENGTH) - free(src); + free_def(src); s->capacity = capacity; } @@ -288,7 +288,7 @@ static void wstring_reserve(wstring* s, ssize_t size) { capacity = (capacity >> 1) + capacity; else capacity = 0; - capacity = max(capacity, s->length + size); + capacity = max_def(capacity, s->length + size); capacity |= WSTRING_NULL_LENGTH; wchar_t* src = wstring_data(s); @@ -305,7 +305,7 @@ static void wstring_reserve(wstring* s, ssize_t size) { s->ptr = dst; if (s->capacity > STRING_NULL_LENGTH) - free(src); + free_def(src); s->capacity = capacity; } diff --git a/src/DivaGL/vector.hpp b/src/DivaGL/vector.hpp index f9933c4b..dc980bd3 100644 --- a/src/DivaGL/vector.hpp +++ b/src/DivaGL/vector.hpp @@ -65,7 +65,7 @@ void vector_old_##t##_reserve(vector_old_##t* vec, ssize_t size) { \ capacity = (capacity >> 1) + capacity; \ else \ capacity = 0; \ - capacity = max(capacity, vec->end - vec->begin + size); \ + capacity = max_def(capacity, vec->end - vec->begin + size); \ \ t* temp = 0; \ if (capacity) \ @@ -76,7 +76,7 @@ void vector_old_##t##_reserve(vector_old_##t* vec, ssize_t size) { \ \ memmove(temp, vec->begin, sizeof(t) * (vec->end - vec->begin)); \ ssize_t length = vec->end - vec->begin; \ - free(vec->begin); \ + free_def(vec->begin); \ vec->capacity_end = &temp[capacity]; \ vec->end = &temp[length]; \ vec->begin = temp; \ @@ -182,7 +182,7 @@ void vector_old_##t##_erase_range(vector_old_##t* vec, \ if (!vec || !last || last - first < 1) \ return; \ \ - ssize_t s = min(last - first, (ssize_t)(vec->end - vec->begin)); \ + ssize_t s = min_def(last - first, (ssize_t)(vec->end - vec->begin)); \ if (s < 1) \ return; \ \ @@ -214,7 +214,7 @@ void vector_old_##t##_free(vector_old_##t* vec, vector_old_dispose_func(t)) { \ for (t* i = vec->begin; i != vec->end; i++) \ dispose_func(i); \ \ - free(vec->begin); \ + free_def(vec->begin); \ vec->begin = 0; \ vec->end = 0; \ vec->capacity_end = 0; \ @@ -230,7 +230,7 @@ void vector_old_ptr_##t##_reserve(vector_old_ptr_##t* vec, ssize_t size) { \ capacity = (capacity >> 1) + capacity; \ else \ capacity = 0; \ - capacity = max(capacity, vec->end - vec->begin + size); \ + capacity = max_def(capacity, vec->end - vec->begin + size); \ \ t** temp = 0; \ if (capacity) \ @@ -241,7 +241,7 @@ void vector_old_ptr_##t##_reserve(vector_old_ptr_##t* vec, ssize_t size) { \ \ memmove(temp, vec->begin, sizeof(t*) * (vec->end - vec->begin)); \ ssize_t length = vec->end - vec->begin; \ - free(vec->begin); \ + free_def(vec->begin); \ vec->capacity_end = &temp[capacity]; \ vec->end = &temp[length]; \ vec->begin = temp; \ @@ -290,7 +290,7 @@ void vector_old_ptr_##t##_pop_back(vector_old_ptr_##t* vec, vector_old_dispose_f if (dispose_func) \ dispose_func(vec->end[-1]); \ else \ - free(vec->end[-1]); \ + free_def(vec->end[-1]); \ vec->end--; \ } \ } \ @@ -340,7 +340,7 @@ void vector_old_ptr_##t##_erase(vector_old_ptr_##t* vec, \ if (dispose_func) \ dispose_func(*t0); \ else \ - free(*t0); \ + free_def(*t0); \ \ memmove(t0, t1, sizeof(t*) * (vec->end - t1)); \ vec->end--; \ @@ -351,7 +351,7 @@ void vector_old_ptr_##t##_erase_range(vector_old_ptr_##t* vec, \ if (!vec || !last || last - first < 1) \ return; \ \ - ssize_t s = min(last - first, (ssize_t)(vec->end - vec->begin)); \ + ssize_t s = min_def(last - first, (ssize_t)(vec->end - vec->begin)); \ if (s < 1) \ return; \ \ @@ -366,7 +366,7 @@ void vector_old_ptr_##t##_erase_range(vector_old_ptr_##t* vec, \ } \ else \ for (ssize_t i = 0; i < s; i++) \ - free(t0[i]); \ + free_def(t0[i]); \ \ memmove(t0, t1, sizeof(t*) * (vec->end - t1)); \ vec->end -= s; \ @@ -385,7 +385,7 @@ void vector_old_ptr_##t##_clear(vector_old_ptr_##t* vec, vector_old_dispose_func } \ else \ for (t** i = vec->begin; i != vec->end; i++) \ - free(*i); \ + free_def(*i); \ vec->end = vec->begin; \ } \ \ @@ -402,9 +402,9 @@ void vector_old_ptr_##t##_free(vector_old_ptr_##t* vec, vector_old_dispose_func( } \ else \ for (t** i = vec->begin; i != vec->end; i++) \ - free(*i); \ + free_def(*i); \ \ - free(vec->begin); \ + free_def(vec->begin); \ vec->begin = 0; \ vec->end = 0; \ vec->capacity_end = 0; \ diff --git a/src/KKdLib/a3da.cpp b/src/KKdLib/a3da.cpp index 4b0f4a42..f47fddae 100644 --- a/src/KKdLib/a3da.cpp +++ b/src/KKdLib/a3da.cpp @@ -5,8 +5,9 @@ #include "a3da.hpp" #include "f2/struct.hpp" +#include "io/file_stream.hpp" +#include "io/memory_stream.hpp" #include "io/path.hpp" -#include "io/stream.hpp" #include "half_t.hpp" #include "hash.hpp" #include "key_val.hpp" @@ -104,12 +105,12 @@ void a3da::read(const char* path) { char* path_a3da = str_utils_add(path, (char*)".a3da"); if (path_check_file_exists(path_a3da)) { - stream s; + file_stream s; s.open(path_a3da, "rb"); - if (s.io.stream) + if (s.check_not_null()) a3da_read_inner(this, s); } - free(path_a3da); + free_def(path_a3da); } void a3da::read(const wchar_t* path) { @@ -118,19 +119,19 @@ void a3da::read(const wchar_t* path) { wchar_t* path_a3da = str_utils_add(path, (wchar_t*)L".a3da"); if (path_check_file_exists(path_a3da)) { - stream s; + file_stream s; s.open(path_a3da, L"rb"); - if (s.io.stream) + if (s.check_not_null()) a3da_read_inner(this, s); } - free(path_a3da); + free_def(path_a3da); } void a3da::read(const void* data, size_t size) { if (!data || !size) return; - stream s; + memory_stream s; s.open(data, size); a3da_read_inner(this, s); } @@ -140,11 +141,11 @@ void a3da::write(const char* path) { return; char* path_a3da = str_utils_add(path, ".a3da"); - stream s; + file_stream s; s.open(path_a3da, "wb"); - if (s.io.stream) + if (s.check_not_null()) a3da_write_inner(this, s); - free(path_a3da); + free_def(path_a3da); } void a3da::write(const wchar_t* path) { @@ -152,19 +153,18 @@ void a3da::write(const wchar_t* path) { return; wchar_t* path_a3da = str_utils_add(path, L".a3da"); - stream s; + file_stream s; s.open(path_a3da, L"wb"); - if (s.io.stream) + if (s.check_not_null()) a3da_write_inner(this, s); - free(path_a3da); + free_def(path_a3da); } void a3da::write(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; - s.open(); + memory_stream s; a3da_write_inner(this, s); s.copy(data, size); } @@ -394,7 +394,7 @@ static void a3da_read_inner(a3da* a, stream& s) { uint32_t signature = s.read_uint32_t(); s.set_position(0x00, SEEK_SET); - stream _s; + memory_stream _s; if (signature == reverse_endianness_int32_t('A3DA')) { f2_struct st; st.read(s); @@ -406,7 +406,7 @@ static void a3da_read_inner(a3da* a, stream& s) { void* data = force_malloc(length); s.read(data, length); _s.open(data, length); - free(data); + free_def(data); } void* a3da_data; @@ -451,7 +451,7 @@ static void a3da_read_inner(a3da* a, stream& s) { _s.read(a3da_data, header.string_length); ((uint8_t*)a3da_data)[header.string_length] = 0; a3da_read_text(a, a3da_data, header.string_length); - free(a3da_data); + free_def(a3da_data); if (signature == reverse_endianness_int32_t('C___')) { a->compressed = true; @@ -459,7 +459,7 @@ static void a3da_read_inner(a3da* a, stream& s) { void* a3dc_data = force_malloc(header.binary_length); _s.read(a3dc_data, header.binary_length); a3da_read_data(a, a3dc_data, header.binary_length); - free(a3dc_data); + free_def(a3dc_data); } a->ready = true; } @@ -479,7 +479,7 @@ static void a3da_write_inner(a3da* a, stream& s) { size_t a3da_data_length = 0; a3da_write_text(a, &a3da_data, &a3da_data_length, a3dc); - stream s_a3da; + memory_stream s_a3da; stream& _s = s; if (a->format > A3DA_FORMAT_AFT) { s_a3da.open(); @@ -515,11 +515,11 @@ static void a3da_write_inner(a3da* a, stream& s) { _s.write(a3da_data, a3da_data_length); _s.align_write(0x20); _s.write(a3dc_data, a3dc_data_length); - free(a3dc_data); + free_def(a3dc_data); } else _s.write(a3da_data, a3da_data_length); - free(a3da_data); + free_def(a3da_data); if (a->format > A3DA_FORMAT_AFT) { f2_struct st; @@ -1115,7 +1115,7 @@ static void a3da_write_text(a3da* a, void** data, size_t* size, bool a3dc) { char a3da_timestamp[0x100]; a3da_get_time_stamp(a3da_timestamp, 0x100); - stream s; + memory_stream s; s.open(); if (a3dc) { @@ -1985,7 +1985,7 @@ static void a3da_read_data(a3da* a, void* data, size_t size) { static void a3da_write_data(a3da* a, void** data, size_t* size) { a3da_compress_f16& _compress_f16 = a->_compress_f16; - stream s; + memory_stream s; s.open(); for (a3da_camera_root& i : a->camera_root) { @@ -2539,10 +2539,10 @@ static bool key_val_read_raw_data(key_val* kv, fs -= c * 4; } break; default: - free(fs); + free_def(fs); return false; } - free(fs); + free_def(fs); value.raw_data = true; return true; diff --git a/src/KKdLib/aes.cpp b/src/KKdLib/aes.cpp index 2096f793..ceec68e6 100644 --- a/src/KKdLib/aes.cpp +++ b/src/KKdLib/aes.cpp @@ -306,12 +306,12 @@ static void key_expansion_aes256(uint8_t* RoundKey, const uint8_t* Key) { inline static __m128i key_expansion_aes128_ni_assist(__m128i temp1, __m128i temp2) { __m128i temp3; - temp2 = _mm_shuffle_epi32(temp2, 0xff); - temp3 = _mm_slli_si128(temp1, 0x4); + temp2 = _mm_shuffle_epi32(temp2, 0xFF); + temp3 = _mm_slli_si128(temp1, 0x04); temp1 = _mm_xor_si128(temp1, temp3); - temp3 = _mm_slli_si128(temp3, 0x4); + temp3 = _mm_slli_si128(temp3, 0x04); temp1 = _mm_xor_si128(temp1, temp3); - temp3 = _mm_slli_si128(temp3, 0x4); + temp3 = _mm_slli_si128(temp3, 0x04); temp1 = _mm_xor_si128(temp1, temp3); temp1 = _mm_xor_si128(temp1, temp2); return temp1; @@ -321,16 +321,16 @@ static void key_expansion_aes128_ni(__m128i* RoundKey, const uint8_t* Key) { __m128i temp1, temp2; temp1 = _mm_loadu_si128((__m128i*)&Key[0]); RoundKey[0] = temp1; - temp2 = _mm_aeskeygenassist_si128(temp1, 0x1); + temp2 = _mm_aeskeygenassist_si128(temp1, 0x01); temp1 = key_expansion_aes128_ni_assist(temp1, temp2); RoundKey[1] = temp1; - temp2 = _mm_aeskeygenassist_si128(temp1, 0x2); + temp2 = _mm_aeskeygenassist_si128(temp1, 0x02); temp1 = key_expansion_aes128_ni_assist(temp1, temp2); RoundKey[2] = temp1; - temp2 = _mm_aeskeygenassist_si128(temp1, 0x4); + temp2 = _mm_aeskeygenassist_si128(temp1, 0x04); temp1 = key_expansion_aes128_ni_assist(temp1, temp2); RoundKey[3] = temp1; - temp2 = _mm_aeskeygenassist_si128(temp1, 0x8); + temp2 = _mm_aeskeygenassist_si128(temp1, 0x08); temp1 = key_expansion_aes128_ni_assist(temp1, temp2); RoundKey[4] = temp1; temp2 = _mm_aeskeygenassist_si128(temp1, 0x10); @@ -345,7 +345,7 @@ static void key_expansion_aes128_ni(__m128i* RoundKey, const uint8_t* Key) { temp2 = _mm_aeskeygenassist_si128(temp1, 0x80); temp1 = key_expansion_aes128_ni_assist(temp1, temp2); RoundKey[8] = temp1; - temp2 = _mm_aeskeygenassist_si128(temp1, 0x1b); + temp2 = _mm_aeskeygenassist_si128(temp1, 0x1B); temp1 = key_expansion_aes128_ni_assist(temp1, temp2); RoundKey[9] = temp1; temp2 = _mm_aeskeygenassist_si128(temp1, 0x36); @@ -365,15 +365,15 @@ static void key_expansion_aes128_ni(__m128i* RoundKey, const uint8_t* Key) { inline static void key_expansion_aes192_ni_assist(__m128i* temp1, __m128i* temp2, __m128i* temp3) { __m128i temp4; *temp2 = _mm_shuffle_epi32(*temp2, 0x55); - temp4 = _mm_slli_si128(*temp1, 0x4); + temp4 = _mm_slli_si128(*temp1, 0x04); *temp1 = _mm_xor_si128(*temp1, temp4); - temp4 = _mm_slli_si128(temp4, 0x4); + temp4 = _mm_slli_si128(temp4, 0x04); *temp1 = _mm_xor_si128(*temp1, temp4); - temp4 = _mm_slli_si128(temp4, 0x4); + temp4 = _mm_slli_si128(temp4, 0x04); *temp1 = _mm_xor_si128(*temp1, temp4); *temp1 = _mm_xor_si128(*temp1, *temp2); - *temp2 = _mm_shuffle_epi32(*temp1, 0xff); - temp4 = _mm_slli_si128(*temp3, 0x4); + *temp2 = _mm_shuffle_epi32(*temp1, 0xFF); + temp4 = _mm_slli_si128(*temp3, 0x04); *temp3 = _mm_xor_si128(*temp3, temp4); *temp3 = _mm_xor_si128(*temp3, *temp2); } @@ -384,19 +384,19 @@ static void key_expansion_aes192_ni(__m128i* RoundKey, const uint8_t* Key) { temp3 = _mm_loadu_si128((__m128i*)&Key[16]); RoundKey[0] = temp1; RoundKey[1] = temp3; - temp2 = _mm_aeskeygenassist_si128(temp3, 0x1); + temp2 = _mm_aeskeygenassist_si128(temp3, 0x01); key_expansion_aes192_ni_assist(&temp1, &temp2, &temp3); *(__m128d*)& RoundKey[1] = _mm_shuffle_pd(*(__m128d*)&RoundKey[1], *(__m128d*)&temp1, 0); *(__m128d*)& RoundKey[2] = _mm_shuffle_pd(*(__m128d*)&temp1, *(__m128d*)&temp3, 1); - temp2 = _mm_aeskeygenassist_si128(temp3, 0x2); + temp2 = _mm_aeskeygenassist_si128(temp3, 0x02); key_expansion_aes192_ni_assist(&temp1, &temp2, &temp3); RoundKey[3] = temp1; RoundKey[4] = temp3; - temp2 = _mm_aeskeygenassist_si128(temp3, 0x4); + temp2 = _mm_aeskeygenassist_si128(temp3, 0x04); key_expansion_aes192_ni_assist(&temp1, &temp2, &temp3); *(__m128d*)& RoundKey[4] = _mm_shuffle_pd(*(__m128d*)&RoundKey[4], *(__m128d*)&temp1, 0); *(__m128d*)& RoundKey[5] = _mm_shuffle_pd(*(__m128d*)&temp1, *(__m128d*)&temp3, 1); - temp2 = _mm_aeskeygenassist_si128(temp3, 0x8); + temp2 = _mm_aeskeygenassist_si128(temp3, 0x08); key_expansion_aes192_ni_assist(&temp1, &temp2, &temp3); RoundKey[6] = temp1; RoundKey[7] = temp3; @@ -430,25 +430,25 @@ static void key_expansion_aes192_ni(__m128i* RoundKey, const uint8_t* Key) { inline static void key_expansion_aes256_ni_assist_1(__m128i* temp1, __m128i* temp2) { __m128i temp4; - *temp2 = _mm_shuffle_epi32(*temp2, 0xff); - temp4 = _mm_slli_si128(*temp1, 0x4); + *temp2 = _mm_shuffle_epi32(*temp2, 0xFF); + temp4 = _mm_slli_si128(*temp1, 0x04); *temp1 = _mm_xor_si128(*temp1, temp4); - temp4 = _mm_slli_si128(temp4, 0x4); + temp4 = _mm_slli_si128(temp4, 0x04); *temp1 = _mm_xor_si128(*temp1, temp4); - temp4 = _mm_slli_si128(temp4, 0x4); + temp4 = _mm_slli_si128(temp4, 0x04); *temp1 = _mm_xor_si128(*temp1, temp4); *temp1 = _mm_xor_si128(*temp1, *temp2); } inline static void key_expansion_aes256_ni_assist_2(__m128i* temp1, __m128i* temp3) { __m128i temp2, temp4; - temp4 = _mm_aeskeygenassist_si128(*temp1, 0x0); - temp2 = _mm_shuffle_epi32(temp4, 0xaa); - temp4 = _mm_slli_si128(*temp3, 0x4); + temp4 = _mm_aeskeygenassist_si128(*temp1, 0x00); + temp2 = _mm_shuffle_epi32(temp4, 0xAA); + temp4 = _mm_slli_si128(*temp3, 0x04); *temp3 = _mm_xor_si128(*temp3, temp4); - temp4 = _mm_slli_si128(temp4, 0x4); + temp4 = _mm_slli_si128(temp4, 0x04); *temp3 = _mm_xor_si128(*temp3, temp4); - temp4 = _mm_slli_si128(temp4, 0x4); + temp4 = _mm_slli_si128(temp4, 0x04); *temp3 = _mm_xor_si128(*temp3, temp4); *temp3 = _mm_xor_si128(*temp3, temp2); } @@ -508,42 +508,47 @@ static void key_expansion_aes256_ni(__m128i* RoundKey, const uint8_t* Key) { } void aes128_init_ctx(aes128_ctx* ctx, const uint8_t* key) { - key_expansion_aes128(ctx->RoundKey, key); if (aes_ni) key_expansion_aes128_ni(ctx->RoundKeyNI, key); + else + key_expansion_aes128(ctx->RoundKey, key); } void aes192_init_ctx(aes192_ctx* ctx, const uint8_t* key) { - key_expansion_aes192(ctx->RoundKey, key); if (aes_ni) key_expansion_aes192_ni(ctx->RoundKeyNI, key); + else + key_expansion_aes192(ctx->RoundKey, key); } void aes256_init_ctx(aes256_ctx* ctx, const uint8_t* key) { - key_expansion_aes256(ctx->RoundKey, key); if (aes_ni) key_expansion_aes256_ni(ctx->RoundKeyNI, key); + else + key_expansion_aes256(ctx->RoundKey, key); } -#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) void aes128_init_ctx_iv(aes128_ctx* ctx, const uint8_t* key, const uint8_t* iv) { - key_expansion_aes128(ctx->RoundKey, key); if (aes_ni) key_expansion_aes128_ni(ctx->RoundKeyNI, key); + else + key_expansion_aes128(ctx->RoundKey, key); memcpy(ctx->Iv, iv, AES_BLOCKLEN); } void aes192_init_ctx_iv(aes192_ctx* ctx, const uint8_t* key, const uint8_t* iv) { - key_expansion_aes192(ctx->RoundKey, key); if (aes_ni) key_expansion_aes192_ni(ctx->RoundKeyNI, key); + else + key_expansion_aes192(ctx->RoundKey, key); memcpy(ctx->Iv, iv, AES_BLOCKLEN); } void aes256_init_ctx_iv(aes256_ctx* ctx, const uint8_t* key, const uint8_t* iv) { - key_expansion_aes256(ctx->RoundKey, key); if (aes_ni) key_expansion_aes256_ni(ctx->RoundKeyNI, key); + else + key_expansion_aes256(ctx->RoundKey, key); memcpy(ctx->Iv, iv, AES_BLOCKLEN); } @@ -558,7 +563,6 @@ void aes192_ctx_set_iv(aes192_ctx* ctx, const uint8_t* iv) { void aes256_ctx_set_iv(aes256_ctx* ctx, const uint8_t* iv) { memcpy(ctx->Iv, iv, AES_BLOCKLEN); } -#endif // This function adds the round key to state. // The round key is added to the state by an XOR function. @@ -633,7 +637,6 @@ inline static uint8_t Multiply(uint8_t x, uint8_t y) { (((y >> 3) & 0x01) * xtime(xtime(xtime(x)))); } -#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) // MixColumns function mixes the columns of the state matrix. // The method used to multiply may be difficult to understand for the inexperienced. // Please use the references to gain more information. @@ -688,7 +691,6 @@ inline static void inv_shift_rows(state_t* state) { (*state)[2][3] = (*state)[3][3]; (*state)[3][3] = temp; } -#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) // Cipher is the main function that encrypts the PlainText. inline static void cipher_aes128(state_t* state, const uint8_t* RoundKey) { @@ -814,7 +816,6 @@ inline static void cipher_aes256_ni(void* state, __m128i* round_key) { _mm_storeu_si128((__m128i*)state, m); } -#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) inline static void inv_cipher_aes128(state_t* state, const uint8_t* RoundKey) { uint8_t round = 0; @@ -935,12 +936,9 @@ inline static void inv_cipher_aes256_ni(void* state, __m128i* round_key) { _mm_storeu_si128((__m128i*)state, m); } -#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) - /*****************************************************************************/ /* Public functions: */ /*****************************************************************************/ -#if defined(ECB) && (ECB == 1) void aes128_ecb_encrypt(aes128_ctx* ctx, uint8_t* buf) { // The next function call encrypts the PlainText with the Key using AES algorithm. if (aes_ni) @@ -1042,9 +1040,7 @@ void aes256_ecb_decrypt_buffer(aes256_ctx* ctx, uint8_t* buf, size_t length) { for (size_t i = 0; i < length; i += AES_BLOCKLEN, buf += AES_BLOCKLEN) inv_cipher_aes256((state_t*)buf, ctx->RoundKey); } -#endif // #if defined(ECB) && (ECB == 1) -#if defined(CBC) && (CBC == 1) inline static void XorWithIv(uint8_t* buf, const uint8_t* Iv) { _mm_storeu_si128((__m128i*)buf, _mm_xor_si128( @@ -1258,9 +1254,6 @@ void aes256_cbc_decrypt_buffer(aes256_ctx* ctx, uint8_t* buf, size_t length) { } } -#endif // #if defined(CBC) && (CBC == 1) - -#if defined(CTR) && (CTR == 1) /* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */ void aes128_ctr_xcrypt_buffer(aes128_ctx* ctx, uint8_t* buf, uint32_t length) { uint8_t buffer[AES_BLOCKLEN]; @@ -1351,6 +1344,3 @@ void aes256_ctr_xcrypt_buffer(aes256_ctx* ctx, uint8_t* buf, uint32_t length) { buf[i] ^= buffer[bi]; } } - -#endif // #if defined(CTR) && (CTR == 1) - diff --git a/src/KKdLib/aes.hpp b/src/KKdLib/aes.hpp index 3525c01f..1c3e0c85 100644 --- a/src/KKdLib/aes.hpp +++ b/src/KKdLib/aes.hpp @@ -8,26 +8,6 @@ #include "default.hpp" #include -// #define the macros below to 1/0 to enable/disable the mode of operation. -// -// CBC enables AES encryption in CBC-mode of operation. -// CTR enables encryption in counter-mode. -// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously. - -// The #ifndef-guard allows it to be configured before #include'ing or at compile time. -#ifndef CBC - #define CBC 1 -#endif - -#ifndef ECB - #define ECB 1 -#endif - -#ifndef CTR - #define CTR 1 -#endif - - //#define AES128 1 //#define AES192 1 //#define AES256 1 @@ -42,45 +22,41 @@ #define AES256_keyExpSize 240 struct aes128_ctx { - uint8_t RoundKey[AES128_keyExpSize]; - __m128i RoundKeyNI[AES128_keyExpSize / sizeof(__m128i) + 9]; -#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + union { + uint8_t RoundKey[AES128_keyExpSize]; + __m128i RoundKeyNI[AES128_keyExpSize / sizeof(__m128i) + 9]; + }; uint8_t Iv[AES_BLOCKLEN]; -#endif }; struct aes192_ctx { - uint8_t RoundKey[AES192_keyExpSize]; - __m128i RoundKeyNI[AES192_keyExpSize / sizeof(__m128i) + 11]; -#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + union { + uint8_t RoundKey[AES192_keyExpSize]; + __m128i RoundKeyNI[AES192_keyExpSize / sizeof(__m128i) + 11]; + }; uint8_t Iv[AES_BLOCKLEN]; -#endif }; struct aes256_ctx { - uint8_t RoundKey[AES256_keyExpSize]; - __m128i RoundKeyNI[AES256_keyExpSize / sizeof(__m128i) + 13]; -#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + union { + uint8_t RoundKey[AES256_keyExpSize]; + __m128i RoundKeyNI[AES256_keyExpSize / sizeof(__m128i) + 13]; + }; uint8_t Iv[AES_BLOCKLEN]; -#endif }; void aes128_init_ctx(aes128_ctx* ctx, const uint8_t* key); void aes192_init_ctx(aes192_ctx* ctx, const uint8_t* key); void aes256_init_ctx(aes256_ctx* ctx, const uint8_t* key); -#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) void aes128_init_ctx_iv(aes128_ctx* ctx, const uint8_t* key, const uint8_t* iv); void aes192_init_ctx_iv(aes192_ctx* ctx, const uint8_t* key, const uint8_t* iv); void aes256_init_ctx_iv(aes256_ctx* ctx, const uint8_t* key, const uint8_t* iv); void aes128_ctx_set_iv(aes128_ctx* ctx, const uint8_t* iv); void aes192_ctx_set_iv(aes192_ctx* ctx, const uint8_t* iv); void aes256_ctx_set_iv(aes256_ctx* ctx, const uint8_t* iv); -#endif -#if defined(ECB) && (ECB == 1) // buffer size is exactly AES_BLOCKLEN bytes; // you need only AES_init_ctx as IV is not used in ECB -// NB: ECB is considered insecure for most uses void aes128_ecb_encrypt(aes128_ctx* ctx, uint8_t* buf); void aes192_ecb_encrypt(aes192_ctx* ctx, uint8_t* buf); void aes256_ecb_encrypt(aes256_ctx* ctx, uint8_t* buf); @@ -94,14 +70,7 @@ void aes128_ecb_decrypt_buffer(aes128_ctx* ctx, uint8_t* buf, size_t length); void aes192_ecb_decrypt_buffer(aes192_ctx* ctx, uint8_t* buf, size_t length); void aes256_ecb_decrypt_buffer(aes256_ctx* ctx, uint8_t* buf, size_t length); -#endif // #if defined(ECB) && (ECB == !) - -#if defined(CBC) && (CBC == 1) -// buffer size MUST be mutile of AES_BLOCKLEN; -// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme -// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() -// no IV should ever be reused with the same key void aes128_cbc_encrypt(aes128_ctx* ctx, uint8_t buf[AES_BLOCKLEN]); void aes192_cbc_encrypt(aes192_ctx* ctx, uint8_t buf[AES_BLOCKLEN]); void aes256_cbc_encrypt(aes256_ctx* ctx, uint8_t buf[AES_BLOCKLEN]); @@ -115,20 +84,9 @@ void aes128_cbc_decrypt_buffer(aes128_ctx* ctx, uint8_t* buf, size_t length); void aes192_cbc_decrypt_buffer(aes192_ctx* ctx, uint8_t* buf, size_t length); void aes256_cbc_decrypt_buffer(aes256_ctx* ctx, uint8_t* buf, size_t length); -#endif // #if defined(CBC) && (CBC == 1) - -#if defined(CTR) && (CTR == 1) - -// Same function for encrypting as for decrypting. -// IV is incremented for every block, and used after encryption as XOR-compliment for output -// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme -// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() -// no IV should ever be reused with the same key void aes128_ctr_xcrypt_buffer(aes128_ctx* ctx, uint8_t* buf, uint32_t length); void aes192_ctr_xcrypt_buffer(aes192_ctx* ctx, uint8_t* buf, uint32_t length); void aes256_ctr_xcrypt_buffer(aes256_ctx* ctx, uint8_t* buf, uint32_t length); -#endif // #if defined(CTR) && (CTR == 1) - #endif // _AES_H_ diff --git a/src/KKdLib/aet.cpp b/src/KKdLib/aet.cpp index 0ea03f9f..e7e599a5 100644 --- a/src/KKdLib/aet.cpp +++ b/src/KKdLib/aet.cpp @@ -4,3 +4,192 @@ */ #include "aet.hpp" +#include "f2/struct.hpp" +#include "io/path.hpp" +#include "io/memory_stream.hpp" + +static void aet_set_classic_read_inner(aet_set* as, stream& s); +static void aet_set_classic_write_inner(aet_set* as, stream& s); +static void aet_set_modern_read_inner(aet_set* as, stream& s); +static void aet_set_modern_write_inner(aet_set* as, stream& s); + +aet_marker::aet_marker() : time() { + +} + +aet_marker::~aet_marker() { + +} + +aet_layer_video_3d::aet_layer_video_3d() { + +} + +aet_layer_video_3d::~aet_layer_video_3d() { + +} + +aet_transfer_mode::aet_transfer_mode() : mode(), flag(), matte() { + +} + +aet_layer_video::aet_layer_video() : _3d_init() { + +} + +aet_layer_video::~aet_layer_video() { + +} + +aet_layer_audio::aet_layer_audio() { + +} + +aet_layer_audio::~aet_layer_audio() { + +} + +aet_color::aet_color() : r(), g(), b() { + +} + +aet_video_src::aet_video_src() : sprite_index() { + +} + +aet_video_src::~aet_video_src() { + +} + +aet_video::aet_video() : width(), height(), fpf() { + +} + +aet_video::~aet_video() { + +} + +aet_audio::aet_audio() : sound_index() { + +} + +aet_layer::aet_layer() : start_time(), end_time(), offset_time(), time_scale(), flags(), +quality(), item_type(), item(), parent(), video(), video_init(), audio(), audio_init() { + +} + +aet_layer::~aet_layer() { + +} + +aet_camera::aet_camera() { + +} + +aet_camera::~aet_camera() { + +} + +aet_scene::aet_scene() : start_time(), end_time(), fps(), width(), height(), camera_init() { + +} + +aet_scene::~aet_scene() { + +} + +aet_set::aet_set() : ready(), modern(), big_endian(), is_x() { + +} + +aet_set::~aet_set() { + +} + +void aet_set::pack_file(void** data, size_t* size) { + if (!data || !ready) + return; + + memory_stream s; + s.open(); + if (!modern) + aet_set_classic_write_inner(this, s); + else + aet_set_modern_write_inner(this, s); + s.align_write(0x10); + s.copy(data, size); +} + +void aet_set::unpack_file(const void* data, size_t size, bool modern) { + if (!data || !size) + return; + + memory_stream s; + s.open(data, size); + if (!modern) + aet_set_classic_read_inner(this, s); + else + aet_set_modern_read_inner(this, s); +} + +static void aet_set_classic_read_inner(aet_set* as, stream& s) { + as->ready = true; + as->modern = false; + as->big_endian = false; + as->is_x = false; +} + +static void aet_set_classic_write_inner(aet_set* as, stream& s) { + +} + +static void aet_set_modern_read_inner(aet_set* as, stream& s) { + f2_struct st; + st.read(s); + if (st.header.signature != reverse_endianness_uint32_t('AETC') || !st.data.size()) + return; + + bool big_endian = st.header.use_big_endian; + + memory_stream s_aetc; + s_aetc.open(st.data); + s_aetc.big_endian = big_endian; + + bool is_x = false; + + as->ready = true; + as->modern = true; + as->big_endian = big_endian; + as->is_x = is_x; +} + +static void aet_set_modern_write_inner(aet_set* as, stream& s) { + bool big_endian = as->big_endian; + bool is_x = as->is_x; + + memory_stream s_aetc; + s_aetc.open(); + s_aetc.big_endian = big_endian; + + uint32_t off; + enrs e; + enrs_entry ee; + pof pof; + + off = align_val(0, 0x10); + + f2_struct st; + s_aetc.align_write(0x10); + s_aetc.copy(st.data); + s_aetc.close(); + + st.enrs = e; + st.pof = pof; + + st.header.signature = reverse_endianness_uint32_t('AETC'); + st.header.length = 0x20; + st.header.use_big_endian = big_endian; + st.header.use_section_size = true; + + st.write(s, true, is_x); +} diff --git a/src/KKdLib/aet.hpp b/src/KKdLib/aet.hpp index 29d6b60a..cb7c3beb 100644 --- a/src/KKdLib/aet.hpp +++ b/src/KKdLib/aet.hpp @@ -11,66 +11,91 @@ #include #include "default.hpp" #include "kf.hpp" -#include "vec.hpp" -enum aet_blend_mode { - AET_BLEND_MODE_NONE = 0, - AET_BLEND_MODE_COPY = 1, - AET_BLEND_MODE_BEHIND = 2, - AET_BLEND_MODE_NORMAL = 3, - AET_BLEND_MODE_DISSOLVE = 4, - AET_BLEND_MODE_ADD = 5, - AET_BLEND_MODE_MULTIPLY = 6, - AET_BLEND_MODE_SCREEN = 7, - AET_BLEND_MODE_OVERLAY = 8, - AET_BLEND_MODE_SOFT_LIGHT = 9, - AET_BLEND_MODE_HARD_LIGHT = 10, - AET_BLEND_MODE_DARKER = 11, - AET_BLEND_MODE_LIGHTEN = 12, - AET_BLEND_MODE_CLASSIC_DIFFERENCE = 13, - AET_BLEND_MODE_HUE = 14, - AET_BLEND_MODE_SATURATION = 15, - AET_BLEND_MODE_COLOR = 16, - AET_BLEND_MODE_LUMINOSITY = 17, - AET_BLEND_MODE_STENCIL_ALPHA = 18, - AET_BLEND_MODE_STENCIL_LUMA = 19, - AET_BLEND_MODE_SILHOUETTE_ALPHA = 20, - AET_BLEND_MODE_SILHOUETTE_LUMA = 21, - AET_BLEND_MODE_LUMINESCENT_PREMULTYPLY = 22, - AET_BLEND_MODE_ALPHA_ADD = 23, - AET_BLEND_MODE_CLASSIC_COLOR_DODGE = 24, - AET_BLEND_MODE_CLASSIC_COLOR_BURN = 25, - AET_BLEND_MODE_EXCLUSION = 26, - AET_BLEND_MODE_DIFFERENCE = 27, - AET_BLEND_MODE_COLOR_DODGE = 28, - AET_BLEND_MODE_COLOR_BURN = 29, - AET_BLEND_MODE_LINEAR_DODGE = 30, - AET_BLEND_MODE_LINEAR_BURN = 31, - AET_BLEND_MODE_LINEAR_LIGHT = 32, - AET_BLEND_MODE_VIVID_LIGHT = 33, - AET_BLEND_MODE_PIN_LIGHT = 34, - AET_BLEND_MODE_HARD_MIX = 35, - AET_BLEND_MODE_LIGHTER_COLOR = 36, - AET_BLEND_MODE_DARKER_COLOR = 37, - AET_BLEND_MODE_SUBTRACT = 38, - AET_BLEND_MODE_DIVIDE = 39, +enum aet_blend_mode : uint8_t { + AET_BLEND_MODE_NONE = 0, // Unsupported + AET_BLEND_MODE_COPY = 1, // Unsupported + AET_BLEND_MODE_BEHIND = 2, // Unsupported + AET_BLEND_MODE_NORMAL = 3, + AET_BLEND_MODE_DISSOLVE = 4, // Unsupported + AET_BLEND_MODE_ADD = 5, + AET_BLEND_MODE_MULTIPLY = 6, + AET_BLEND_MODE_SCREEN = 7, + AET_BLEND_MODE_OVERLAY = 8, // Unsupported + AET_BLEND_MODE_SOFT_LIGHT = 9, // Unsupported + AET_BLEND_MODE_HARD_LIGHT = 10, // Unsupported + AET_BLEND_MODE_DARKER = 11, // Unsupported + AET_BLEND_MODE_LIGHTEN = 12, // Unsupported + AET_BLEND_MODE_CLASSIC_DIFFERENCE = 13, // Unsupported + AET_BLEND_MODE_HUE = 14, // Unsupported + AET_BLEND_MODE_SATURATION = 15, // Unsupported + AET_BLEND_MODE_COLOR = 16, // Unsupported + AET_BLEND_MODE_LUMINOSITY = 17, // Unsupported + AET_BLEND_MODE_STENCIL_ALPHA = 18, // Unsupported + AET_BLEND_MODE_STENCIL_LUMA = 19, // Unsupported + AET_BLEND_MODE_SILHOUETTE_ALPHA = 20, // Unsupported + AET_BLEND_MODE_SILHOUETTE_LUMA = 21, // Unsupported + AET_BLEND_MODE_LUMINESCENT_PREMULTYPLY = 22, // Unsupported + AET_BLEND_MODE_ALPHA_ADD = 23, // Unsupported + AET_BLEND_MODE_CLASSIC_COLOR_DODGE = 24, // Unsupported + AET_BLEND_MODE_CLASSIC_COLOR_BURN = 25, // Unsupported + AET_BLEND_MODE_EXCLUSION = 26, // Unsupported + AET_BLEND_MODE_DIFFERENCE = 27, // Unsupported + AET_BLEND_MODE_COLOR_DODGE = 28, // Unsupported + AET_BLEND_MODE_COLOR_BURN = 29, // Unsupported + AET_BLEND_MODE_LINEAR_DODGE = 30, // Unsupported + AET_BLEND_MODE_LINEAR_BURN = 31, // Unsupported + AET_BLEND_MODE_LINEAR_LIGHT = 32, // Unsupported + AET_BLEND_MODE_VIVID_LIGHT = 33, // Unsupported + AET_BLEND_MODE_PIN_LIGHT = 34, // Unsupported + AET_BLEND_MODE_HARD_MIX = 35, // Unsupported + AET_BLEND_MODE_LIGHTER_COLOR = 36, // Unsupported + AET_BLEND_MODE_DARKER_COLOR = 37, // Unsupported + AET_BLEND_MODE_SUBTRACT = 38, // Unsupported + AET_BLEND_MODE_DIVIDE = 39, // Unsupported }; -enum aet_item_type { +enum aet_item_type : uint8_t { AET_ITEM_TYPE_NONE = 0, AET_ITEM_TYPE_VIDEO = 1, AET_ITEM_TYPE_AUDIO = 2, AET_ITEM_TYPE_COMPOSITION = 3, }; -enum aet_layer_quality { +enum aet_layer_flags : uint16_t { + AET_LAYER_FLAGS_VIDEO_ACTIVE = 0x000001, + AET_LAYER_FLAGS_AUDIO_ACTIVE = 0x000002, + AET_LAYER_FLAGS_EFFECTS_ACTIVE = 0x000004, + AET_LAYER_FLAGS_MOTION_BLUR = 0x000008, + AET_LAYER_FLAGS_FRAME_BLENDING = 0x000010, + AET_LAYER_FLAGS_LOCKED = 0x000020, + AET_LAYER_FLAGS_SHY = 0x000040, + AET_LAYER_FLAGS_COLLAPSE = 0x000080, + AET_LAYER_FLAGS_AUTO_ORIENT_ROTATION = 0x000100, + AET_LAYER_FLAGS_ADJUSTMENT_LAYER = 0x000200, + AET_LAYER_FLAGS_TIME_REMAPPING = 0x000400, + AET_LAYER_FLAGS_LAYER_IS_3D = 0x000800, + AET_LAYER_FLAGS_LOOK_AT_CAMERA = 0x001000, + AET_LAYER_FLAGS_LOOK_AT_POINT_OF_INTEREST = 0x002000, + AET_LAYER_FLAGS_SOLO = 0x004000, + AET_LAYER_FLAGS_MARKERS_LOCKED = 0x008000, + // Should be there but they don't fit in 16 bits + //AET_LAYER_FLAGS_NULL_LAYER = 0x010000, + //AET_LAYER_FLAGS_HIDE_LOCKED_MASKS = 0x020000, + //AET_LAYER_FLAGS_GUIDE_LAYER = 0x040000, + //AET_LAYER_FLAGS_ADVANCED_FRAME_BLENDING = 0x080000, + //AET_LAYER_FLAGS_SUB_LAYERS_RENDER_SEPARATELY = 0x100000, + //AET_LAYER_FLAGS_ENVIRONMENT_LAYER = 0x200000, +}; + +enum aet_layer_quality : uint8_t { AET_LAYER_QUALITY_NONE = 0, AET_LAYER_QUALITY_WIREFRAME = 1, AET_LAYER_QUALITY_DRAFT = 2, AET_LAYER_QUALITY_BEST = 3, }; -enum aet_track_matte { +enum aet_track_matte : uint8_t { AET_TRACK_MATTE_NONE = 0, AET_TRACK_MATTE_ALPHA = 1, AET_TRACK_MATTE_NOT_ALPHA = 2, @@ -78,157 +103,174 @@ enum aet_track_matte { AET_TRACK_MATTE_NOT_LUMA = 4, }; -struct aet_layer_flags { - // Toggles layer visuals on or off - uint16_t video_active : 1; - // Toggles layer sounds on or off - uint16_t audio_active : 1; - uint16_t effects_active : 1; - // Toggles motion blur on or off for the layer - uint16_t motion_blur : 1; - uint16_t frame_blending : 1; - // Locks layer contents, preventing all changes - uint16_t locked : 1; - // Hides the current layer when the "Hide Shy Layers" composition switch is selected - uint16_t shy : 1; - uint16_t collapse : 1; - uint16_t auto_orient_rotation : 1; - // Identifies the layer as an adjustment layer - uint16_t adjustment_layer : 1; - uint16_t time_remapping : 1; - // Identifies the layer as a 3D layer - uint16_t layer_is_3d : 1; - uint16_t look_at_camera : 1; - uint16_t look_at_point_of_interest : 1; - // Includes the current layer in previews and renders, ignoring layers without this switch set - uint16_t solo : 1; - uint16_t markers_locked : 1; -}; - -struct aet_transfer_flags { - uint8_t preserve_alpha : 1; - uint8_t randomize_dissolve : 1; -}; - -struct aet_audio { - uint32_t sound_id; -}; - -struct aet_video_source { - std::string name; - int32_t name_offset; - uint32_t id; -}; - -struct aet_layer_audio { - std::vector volume_left; - std::vector volume_right; - std::vector pan_left; - std::vector pan_right; -}; - -struct aet_layer_transfer_mode { - aet_blend_mode blend_mode; - aet_transfer_flags transfer_flags; - aet_track_matte track_matte; -}; - -struct aet_layer_video_3d { - std::vector anchor_z; - std::vector position_z; - std::vector direction_x; - std::vector direction_y; - std::vector direction_z; - std::vector rotation_x; - std::vector rotation_y; - std::vector scale_z; -}; - -struct aet_layer_video { - aet_layer_transfer_mode transfer_mode; - uint8_t padding; - std::vector anchor_x; - std::vector anchor_y; - std::vector positionx; - std::vector position_y; - std::vector rotation; - std::vector scale_x; - std::vector scale_y; - std::vector opacit_y; - aet_layer_video_3d* video_3d; +enum aet_transfer_flags : uint8_t { + AET_TRANSFRER_FLAGS_PRESERVE_ALPHA = 0x01, + AET_TRANSFRER_FLAGS_RANDOMIZE_DISSOLVE = 0x02, }; struct aet_marker { - float_t frame; + float_t time; std::string name; - int32_t name_offset; + + aet_marker(); + ~aet_marker(); +}; + +typedef std::vector aet_fcurve; + +struct aet_layer_video_3d { + aet_fcurve anchor_z; + aet_fcurve pos_z; + aet_fcurve dir_x; + aet_fcurve dir_y; + aet_fcurve dir_z; + aet_fcurve rot_x; + aet_fcurve rot_y; + aet_fcurve scale_z; + + aet_layer_video_3d(); + ~aet_layer_video_3d(); +}; + +struct aet_transfer_mode { + aet_blend_mode mode; + aet_transfer_flags flag; + aet_track_matte matte; + + aet_transfer_mode(); +}; + +struct aet_layer_video { + aet_transfer_mode transfer_mode; + aet_fcurve anchor_x; + aet_fcurve anchor_y; + aet_fcurve pos_x; + aet_fcurve pos_y; + aet_fcurve rot_z; + aet_fcurve scale_x; + aet_fcurve scale_y; + aet_fcurve opacity; + aet_layer_video_3d _3d; + bool _3d_init; + + aet_layer_video(); + ~aet_layer_video(); +}; + +struct aet_layer_audio { + aet_fcurve volume_l; + aet_fcurve volume_r; + aet_fcurve pan_l; + aet_fcurve pan_r; + + aet_layer_audio(); + ~aet_layer_audio(); +}; + +struct aet_color { + uint8_t r; + uint8_t g; + uint8_t b; + + aet_color(); +}; + +struct aet_video_src { + std::string sprite_name; + int32_t sprite_index; + + aet_video_src(); + ~aet_video_src(); +}; + +struct aet_video { + aet_color color; + uint16_t width; + uint16_t height; + float_t fpf; + std::vector sources; + + aet_video(); + ~aet_video(); +}; + +struct aet_audio { + uint32_t sound_index; + + aet_audio(); }; struct aet_layer { std::string name; - int32_t name_offset; - float_t start_frame; - float_t end_frame; - float_t offset_frame; + float_t start_time; + float_t end_time; + float_t offset_time; float_t time_scale; aet_layer_flags flags; aet_layer_quality quality; - aet_item_type type; - int32_t video_item_offset; - int32_t parent_layer_offset; - std::vector marker; - std::vector video; - std::vector audio; + aet_item_type item_type; + void* item; + aet_layer* parent; + std::vector markers; + aet_layer_video video; + bool video_init; + aet_layer_audio audio; + bool audio_init; - int32_t DataID; + aet_layer(); + ~aet_layer(); }; -struct aet_composition { - int32_t count; - int32_t offset; - aet_layer* elements; -}; - -struct aet_video { - int32_t offset; - uint32_t color; - uint16_t width; - uint16_t height; - float_t frames; - std::vector video_source; -}; +typedef std::vector aet_comp; struct aet_camera { - std::vector eye_x; - std::vector eye_y; - std::vector eye_z; - std::vector position_x; - std::vector position_y; - std::vector position_z; - std::vector direction_x; - std::vector direction_y; - std::vector direction_z; - std::vector rotation_x; - std::vector rotation_y; - std::vector rotation_z; - std::vector zoom; + aet_fcurve eye_x; + aet_fcurve eye_y; + aet_fcurve eye_z; + aet_fcurve pos_x; + aet_fcurve pos_y; + aet_fcurve pos_z; + aet_fcurve dir_x; + aet_fcurve dir_y; + aet_fcurve dir_z; + aet_fcurve rot_x; + aet_fcurve rot_y; + aet_fcurve rot_z; + aet_fcurve zoom; + + aet_camera(); + ~aet_camera(); }; struct aet_scene { std::string name; - int32_t name_offset; - float_t start_frame; - float_t end_frame; - float_t frame_rate; - uint32_t back_color; + float_t start_time; + float_t end_time; + float_t fps; + aet_color color; uint32_t width; uint32_t height; - std::vector camera; - std::vector composition; + aet_camera camera; + bool camera_init; + std::vector comp; std::vector video; std::vector audio; + + aet_scene(); + ~aet_scene(); }; -struct aet_header { - aet_scene scene; +struct aet_set { + bool ready; + bool modern; + bool big_endian; + bool is_x; + + std::vector scenes; + + aet_set(); + virtual ~aet_set(); + + void pack_file(void** data, size_t* size); + void unpack_file(const void* data, size_t size, bool modern); }; diff --git a/src/KKdLib/database/auth_3d.cpp b/src/KKdLib/database/auth_3d.cpp index dc13f387..c1f3fe7b 100644 --- a/src/KKdLib/database/auth_3d.cpp +++ b/src/KKdLib/database/auth_3d.cpp @@ -4,8 +4,9 @@ */ #include "auth_3d.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../key_val.hpp" #include "../hash.hpp" #include "../sort.hpp" @@ -35,12 +36,12 @@ void auth_3d_database_file::read(const char* path) { char* path_bin = str_utils_add(path, ".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, "rb"); - if (s.io.stream) + if (s.check_not_null()) auth_3d_database_file_read_inner(this, s); } - free(path_bin); + free_def(path_bin); } void auth_3d_database_file::read(const wchar_t* path) { @@ -49,19 +50,19 @@ void auth_3d_database_file::read(const wchar_t* path) { wchar_t* path_bin = str_utils_add(path, L".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, L"rb"); - if (s.io.stream) + if (s.check_not_null()) auth_3d_database_file_read_inner(this, s); } - free(path_bin); + free_def(path_bin); } void auth_3d_database_file::read(const void* data, size_t size) { if (!data || !size) return; - stream s; + memory_stream s; s.open(data, size); auth_3d_database_file_read_inner(this, s); } @@ -71,11 +72,11 @@ void auth_3d_database_file::write(const char* path) { return; char* path_bin = str_utils_add(path, ".bin"); - stream s; + file_stream s; s.open(path_bin, "wb"); - if (s.io.stream) + if (s.check_not_null()) auth_3d_database_file_write_inner(this, s); - free(path_bin); + free_def(path_bin); } void auth_3d_database_file::write(const wchar_t* path) { @@ -83,18 +84,18 @@ void auth_3d_database_file::write(const wchar_t* path) { return; wchar_t* path_bin = str_utils_add(path, L".bin"); - stream s; + file_stream s; s.open(path_bin, L"wb"); - if (s.io.stream) + if (s.check_not_null()) auth_3d_database_file_write_inner(this, s); - free(path_bin); + free_def(path_bin); } void auth_3d_database_file::write(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; + memory_stream s; s.open(); auth_3d_database_file_write_inner(this, s); s.copy(data, size); @@ -304,7 +305,7 @@ static void auth_3d_database_file_read_inner(auth_3d_database_file* auth_3d_db_f void* a3da_data = force_malloc(string_length); s.read(a3da_data, string_length); auth_3d_database_file_read_text(auth_3d_db_file, a3da_data, string_length); - free(a3da_data); + free_def(a3da_data); auth_3d_db_file->ready = true; } @@ -314,7 +315,7 @@ static void auth_3d_database_file_write_inner(auth_3d_database_file* auth_3d_db_ size_t a3da_data_length = 0; auth_3d_database_file_write_text(auth_3d_db_file, &a3da_data, &a3da_data_length); s.write(a3da_data, a3da_data_length); - free(a3da_data); + free_def(a3da_data); } static void auth_3d_database_file_read_text(auth_3d_database_file* auth_3d_db_file, void* data, size_t size) { @@ -367,7 +368,7 @@ static void auth_3d_database_file_read_text(auth_3d_database_file* auth_3d_db_fi } static void auth_3d_database_file_write_text(auth_3d_database_file* auth_3d_db_file, void** data, size_t* size) { - stream s; + memory_stream s; s.open(); s.write("#A3DA__________\n", 16); diff --git a/src/KKdLib/database/bone.cpp b/src/KKdLib/database/bone.cpp index 944ee7ca..48f82b8d 100644 --- a/src/KKdLib/database/bone.cpp +++ b/src/KKdLib/database/bone.cpp @@ -5,8 +5,9 @@ #include "bone.hpp" #include "../f2/struct.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../hash.hpp" #include "../str_utils.hpp" @@ -28,7 +29,7 @@ static int64_t bone_database_strings_get_string_offset(std::vector& std::vector& vec_off, const char* str); static bool bone_database_strings_push_back_check(std::vector& vec, const char* str); -bone_database::bone_database() : ready(), modern(), is_x() { +bone_database::bone_database() : ready(), modern(), big_endian(), is_x() { } @@ -43,18 +44,18 @@ void bone_database::read(const char* path, bool modern) { if (!modern) { char* path_bin = str_utils_add(path, ".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, "rb"); - if (s.io.stream) { + if (s.check_not_null()) { uint8_t* data = force_malloc_s(uint8_t, s.length); s.read(data, s.length); - stream s_bin; + memory_stream s_bin; s_bin.open(data, s.length); bone_database_classic_read_inner(this, s_bin); - free(data); + free_def(data); } } - free(path_bin); + free_def(path_bin); } else { char* path_bon = str_utils_add(path, ".bon"); @@ -62,13 +63,13 @@ void bone_database::read(const char* path, bool modern) { f2_struct st; st.read(path_bon); if (st.header.signature == reverse_endianness_uint32_t('BONE')) { - stream s_bone; + memory_stream s_bone; s_bone.open(st.data); - s_bone.is_big_endian = st.header.use_big_endian; + s_bone.big_endian = st.header.use_big_endian; bone_database_modern_read_inner(this, s_bone, st.header.length); } } - free(path_bon); + free_def(path_bon); } } @@ -79,18 +80,18 @@ void bone_database::read(const wchar_t* path, bool modern) { if (!modern) { wchar_t* path_bin = str_utils_add(path, L".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, L"rb"); - if (s.io.stream) { + if (s.check_not_null()) { uint8_t* data = force_malloc_s(uint8_t, s.length); s.read(data, s.length); - stream s_bin; + memory_stream s_bin; s_bin.open(data, s.length); bone_database_classic_read_inner(this, s_bin); - free(data); + free_def(data); } } - free(path_bin); + free_def(path_bin); } else { wchar_t* path_bon = str_utils_add(path, L".bon"); @@ -98,13 +99,13 @@ void bone_database::read(const wchar_t* path, bool modern) { f2_struct st; st.read(path_bon); if (st.header.signature == reverse_endianness_uint32_t('BONE')) { - stream s_bone; + memory_stream s_bone; s_bone.open(st.data); - s_bone.is_big_endian = st.header.use_big_endian; + s_bone.big_endian = st.header.use_big_endian; bone_database_modern_read_inner(this, s_bone, st.header.length); } } - free(path_bon); + free_def(path_bon); } } @@ -113,7 +114,7 @@ void bone_database::read(const void* data, size_t size, bool modern) { return; if (!modern) { - stream s; + memory_stream s; s.open(data, size); bone_database_classic_read_inner(this, s); } @@ -121,9 +122,9 @@ void bone_database::read(const void* data, size_t size, bool modern) { f2_struct st; st.read(data, size); if (st.header.signature == reverse_endianness_uint32_t('BONE')) { - stream s_bone; + memory_stream s_bone; s_bone.open(st.data); - s_bone.is_big_endian = st.header.use_big_endian; + s_bone.big_endian = st.header.use_big_endian; bone_database_modern_read_inner(this, s_bone, st.header.length); } } @@ -135,19 +136,19 @@ void bone_database::write(const char* path) { if (!modern) { char* path_bin = str_utils_add(path, ".bin"); - stream s; + file_stream s; s.open(path_bin, "wb"); - if (s.io.stream) + if (s.check_not_null()) bone_database_classic_write_inner(this, s); - free(path_bin); + free_def(path_bin); } else { char* path_bon = str_utils_add(path, ".bon"); - stream s; + file_stream s; s.open(path_bon, "wb"); - if (s.io.stream) + if (s.check_not_null()) bone_database_modern_write_inner(this, s); - free(path_bon); + free_def(path_bon); } } @@ -157,19 +158,19 @@ void bone_database::write(const wchar_t* path) { if (!modern) { wchar_t* path_bin = str_utils_add(path, L".bin"); - stream s; + file_stream s; s.open(path_bin, L"wb"); - if (s.io.stream) + if (s.check_not_null()) bone_database_classic_write_inner(this, s); - free(path_bin); + free_def(path_bin); } else { wchar_t* path_bon = str_utils_add(path, L".bon"); - stream s; + file_stream s; s.open(path_bon, L"wb"); - if (s.io.stream) + if (s.check_not_null()) bone_database_modern_write_inner(this, s); - free(path_bon); + free_def(path_bon); } } @@ -177,7 +178,7 @@ void bone_database::write(void** data, size_t* size) { if (!data || !ready) return; - stream s; + memory_stream s; s.open(); if (!modern) bone_database_classic_write_inner(this, s); @@ -569,9 +570,10 @@ static void bone_database_classic_read_inner(bone_database* bone_data, stream& s bone_data->skeleton[i].name = s.read_string_null_terminated_offset(s.read_uint32_t()); s.position_pop(); - bone_data->is_x = false; - bone_data->modern = false; bone_data->ready = true; + bone_data->modern = false; + bone_data->big_endian = false; + bone_data->is_x = false; } static void bone_database_classic_write_inner(bone_database* bone_data, stream& s) { @@ -707,7 +709,7 @@ static void bone_database_classic_write_inner(bone_database* bone_data, stream& for (uint32_t i = 0; i < skeleton_count; i++) s.write_uint32_t((uint32_t)skeleton_offsets[i]); s.position_pop(); - free(skeleton_offsets); + free_def(skeleton_offsets); } static void bone_database_modern_read_inner(bone_database* bone_data, stream& s, uint32_t header_length) { @@ -715,6 +717,7 @@ static void bone_database_modern_read_inner(bone_database* bone_data, stream& s, if (signature != 0x09102720) return; + bool big_endian = s.big_endian; bool is_x = true; s.set_position(0x0C, SEEK_SET); @@ -870,7 +873,7 @@ static void bone_database_modern_read_inner(bone_database* bone_data, stream& s, s.position_push(parent_indices_offset, SEEK_SET); s.read(skel->parent_index.data(), motion_bone_count * sizeof(uint16_t)); - if (s.is_big_endian) { + if (big_endian) { uint16_t* parent_index = skel->parent_index.data(); for (uint32_t j = 0; j < motion_bone_count; j++) parent_index[j] = reverse_endianness_uint16_t(parent_index[j]); @@ -891,21 +894,25 @@ static void bone_database_modern_read_inner(bone_database* bone_data, stream& s, s.read_offset_x()); s.position_pop(); - bone_data->is_x = is_x; - bone_data->modern = true; bone_data->ready = true; + bone_data->modern = true; + bone_data->big_endian = big_endian; + bone_data->is_x = is_x; } static void bone_database_modern_write_inner(bone_database* bone_data, stream& s) { - stream s_bone; + bool big_endian = bone_data->big_endian; + bool is_x = bone_data->is_x; + + memory_stream s_bone; s_bone.open(); + s_bone.big_endian = big_endian; + uint32_t off; enrs e; enrs_entry ee; pof pof; - bool is_x = bone_data->is_x; - uint32_t skeleton_count = (uint32_t)bone_data->skeleton.size(); if (!is_x) { @@ -1280,24 +1287,24 @@ static void bone_database_modern_write_inner(bone_database* bone_data, stream& s s_bone.position_push(skh[i].offset, SEEK_SET); if (!is_x) { s_bone.write_offset_f2(skh[i].bones_offset, 0x40); - s_bone.write_uint32_t(position_count); + s_bone.write_uint32_t_reverse_endianness(position_count); s_bone.write_offset_f2(skh[i].positions_offset, 0x40); s_bone.write_offset_f2(skh[i].unknown_value_offset, 0x40); - s_bone.write_uint32_t(object_bone_count); + s_bone.write_uint32_t_reverse_endianness(object_bone_count); s_bone.write_offset_f2(skh[i].object_bone_names_offset, 0x40); - s_bone.write_uint32_t(motion_bone_count); + s_bone.write_uint32_t_reverse_endianness(motion_bone_count); s_bone.write_offset_f2(skh[i].motion_bone_names_offset, 0x40); s_bone.write_offset_f2(skh[i].parent_indices_offset, 0x40); s_bone.write(0x14); } else { s_bone.write_offset_x(skh[i].bones_offset); - s_bone.write_uint32_t(position_count); + s_bone.write_uint32_t_reverse_endianness(position_count); s_bone.write_offset_x(skh[i].positions_offset); s_bone.write_offset_x(skh[i].unknown_value_offset); - s_bone.write_uint32_t(object_bone_count); + s_bone.write_uint32_t_reverse_endianness(object_bone_count); s_bone.write_offset_x(skh[i].object_bone_names_offset); - s_bone.write_uint32_t(motion_bone_count); + s_bone.write_uint32_t_reverse_endianness(motion_bone_count); s_bone.write_offset_x(skh[i].motion_bone_names_offset); s_bone.write_offset_x(skh[i].parent_indices_offset); s_bone.write(0x28); @@ -1345,11 +1352,15 @@ static void bone_database_modern_write_inner(bone_database* bone_data, stream& s s_bone.position_pop(); s_bone.position_push(skh[i].positions_offset, SEEK_SET); - s_bone.write(skel->position.data(), sizeof(vec3)* position_count); + for (vec3& j : skel->position) { + s_bone.write_float_t_reverse_endianness(j.x); + s_bone.write_float_t_reverse_endianness(j.y); + s_bone.write_float_t_reverse_endianness(j.z); + } s_bone.position_pop(); s_bone.position_push(skh[i].unknown_value_offset, SEEK_SET); - s_bone.write_float_t(skel->heel_height); + s_bone.write_float_t_reverse_endianness(skel->heel_height); s_bone.position_pop(); s_bone.position_push(skh[i].object_bone_names_offset, SEEK_SET); @@ -1374,13 +1385,14 @@ static void bone_database_modern_write_inner(bone_database* bone_data, stream& s s_bone.position_pop(); s_bone.position_push(skh[i].parent_indices_offset, SEEK_SET); - s_bone.write(skel->parent_index.data(), sizeof(uint16_t) * motion_bone_count); + for (uint16_t& j : skel->parent_index) + s_bone.write_uint16_t_reverse_endianness(j); s_bone.position_pop(); } s_bone.position_push(0x00, SEEK_SET); - s_bone.write_uint32_t(0x09102720); - s_bone.write_uint32_t(skeleton_count); + s_bone.write_uint32_t_reverse_endianness(0x09102720); + s_bone.write_uint32_t_reverse_endianness(skeleton_count); s_bone.write_offset(skeleton_offsets_offset, 0x40, is_x); s_bone.write_offset(skeleton_name_offsets_offset, 0x40, is_x); s_bone.position_pop(); @@ -1405,7 +1417,7 @@ static void bone_database_modern_write_inner(bone_database* bone_data, stream& s string_offsets, i.name.c_str())); s_bone.position_pop(); - free(skh); + free_def(skh); f2_struct st; s_bone.align_write(0x10); @@ -1417,7 +1429,7 @@ static void bone_database_modern_write_inner(bone_database* bone_data, stream& s st.header.signature = reverse_endianness_uint32_t('BONE'); st.header.length = is_x ? 0x20 : 0x40; - st.header.use_big_endian = false; + st.header.use_big_endian = big_endian; st.header.use_section_size = true; st.write(s, true, is_x); @@ -1427,7 +1439,7 @@ inline static int64_t bone_database_strings_get_string_offset(std::vector& vec_off, const char* str) { size_t len = utf8_length(str); for (std::string& i : vec) - if (!memcmp(str, i.c_str(), min(len, i.size()) + 1)) + if (!memcmp(str, i.c_str(), min_def(len, i.size()) + 1)) return vec_off[&i - vec.data()]; return 0; } @@ -1435,7 +1447,7 @@ inline static int64_t bone_database_strings_get_string_offset(std::vector& vec, const char* str) { size_t len = utf8_length(str); for (std::string& i : vec) - if (!memcmp(str, i.c_str(), min(len, i.size()) + 1)) + if (!memcmp(str, i.c_str(), min_def(len, i.size()) + 1)) return false; vec.push_back(std::string(str, len)); diff --git a/src/KKdLib/database/bone.hpp b/src/KKdLib/database/bone.hpp index c03572e3..89bdcdec 100644 --- a/src/KKdLib/database/bone.hpp +++ b/src/KKdLib/database/bone.hpp @@ -64,6 +64,7 @@ struct bone_database_skeleton { struct bone_database { bool ready; bool modern; + bool big_endian; bool is_x; std::vector skeleton; diff --git a/src/KKdLib/database/item_table.cpp b/src/KKdLib/database/item_table.cpp index f13ab403..4461bc1b 100644 --- a/src/KKdLib/database/item_table.cpp +++ b/src/KKdLib/database/item_table.cpp @@ -4,8 +4,9 @@ */ #include "item_table.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../key_val.hpp" #include "../sort.hpp" #include "../str_utils.hpp" @@ -85,12 +86,12 @@ void itm_table::read(const char* path) { char* path_bin = str_utils_add(path, ".txt"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, "rb"); - if (s.io.stream) + if (s.check_not_null()) itm_table_read_inner(this, s); } - free(path_bin); + free_def(path_bin); } void itm_table::read(const wchar_t* path) { @@ -99,19 +100,19 @@ void itm_table::read(const wchar_t* path) { wchar_t* path_bin = str_utils_add(path, L".txt"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, L"rb"); - if (s.io.stream) + if (s.check_not_null()) itm_table_read_inner(this, s); } - free(path_bin); + free_def(path_bin); } void itm_table::read(const void* data, size_t size) { if (!data || !size) return; - stream s; + memory_stream s; s.open(data, size); itm_table_read_inner(this, s); } @@ -121,11 +122,11 @@ void itm_table::write(const char* path) { return; char* path_bin = str_utils_add(path, ".txt"); - stream s; + file_stream s; s.open(path_bin, "wb"); - if (s.io.stream) + if (s.check_not_null()) itm_table_write_inner(this, s); - free(path_bin); + free_def(path_bin); } void itm_table::write(const wchar_t* path) { @@ -133,18 +134,18 @@ void itm_table::write(const wchar_t* path) { return; wchar_t* path_bin = str_utils_add(path, L".txt"); - stream s; + file_stream s; s.open(path_bin, L"wb"); - if (s.io.stream) + if (s.check_not_null()) itm_table_write_inner(this, s); - free(path_bin); + free_def(path_bin); } void itm_table::write(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; + memory_stream s; s.open(); itm_table_write_inner(this, s); s.copy(data, size); @@ -264,7 +265,7 @@ static void itm_table_read_inner(itm_table* itm_tbl, stream& s) { void* itm_tbl_data = force_malloc(s.length); s.read(itm_tbl_data, s.length); itm_table_read_text(itm_tbl, itm_tbl_data, s.length); - free(itm_tbl_data); + free_def(itm_tbl_data); itm_tbl->ready = true; } @@ -274,7 +275,7 @@ static void itm_table_write_inner(itm_table* itm_tbl, stream& s) { size_t itm_tbl_data_length = 0; itm_table_write_text(itm_tbl, &itm_tbl_data, &itm_tbl_data_length); s.write(itm_tbl_data, itm_tbl_data_length); - free(itm_tbl_data); + free_def(itm_tbl_data); } static void itm_table_read_text(itm_table* itm_tbl, void* data, size_t size) { @@ -518,7 +519,7 @@ static void itm_table_read_text(itm_table* itm_tbl, void* data, size_t size) { } static void itm_table_write_text(itm_table* itm_tbl, void** data, size_t* size) { - stream s; + memory_stream s; s.open(); key_val_out kv; diff --git a/src/KKdLib/database/motion.cpp b/src/KKdLib/database/motion.cpp index b2fdbf6d..d618405b 100644 --- a/src/KKdLib/database/motion.cpp +++ b/src/KKdLib/database/motion.cpp @@ -4,8 +4,9 @@ */ #include "motion.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../farc.hpp" #include "../hash.hpp" #include "../str_utils.hpp" @@ -32,12 +33,12 @@ void motion_database_file::read(const char* path) { farc_file* ff = f.read_file("mot_db.bin"); if (ff) { - stream s; + memory_stream s; s.open(ff->data, ff->size); motion_database_file_read_inner(this, s); } } - free(path_farc); + free_def(path_farc); } void motion_database_file::read(const wchar_t* path) { @@ -51,19 +52,19 @@ void motion_database_file::read(const wchar_t* path) { farc_file* ff = f.read_file("mot_db.bin"); if (ff) { - stream s; + memory_stream s; s.open(ff->data, ff->size); motion_database_file_read_inner(this, s); } } - free(path_farc); + free_def(path_farc); } void motion_database_file::read(const void* data, size_t size) { if (!data || !size) return; - stream s; + memory_stream s; s.open(data, size); motion_database_file_read_inner(this, s); } @@ -77,7 +78,7 @@ void motion_database_file::write(const char* path) { f.add_file("mot_db.bin"); farc_file* ff = &f.files.back(); - stream s; + memory_stream s; s.open(); motion_database_file_write_inner(this, s); s.copy(&ff->data, &ff->size); @@ -94,7 +95,7 @@ void motion_database_file::write(const wchar_t* path) { f.add_file("mot_db.bin"); farc_file* ff = &f.files.back(); - stream s; + memory_stream s; s.open(); motion_database_file_write_inner(this, s); s.copy(&ff->data, &ff->size); @@ -106,7 +107,7 @@ void motion_database_file::write(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; + memory_stream s; s.open(); motion_database_file_write_inner(this, s); s.copy(data, size); diff --git a/src/KKdLib/database/object.cpp b/src/KKdLib/database/object.cpp index 7a1932ee..2b5961a3 100644 --- a/src/KKdLib/database/object.cpp +++ b/src/KKdLib/database/object.cpp @@ -5,8 +5,9 @@ #include "object.hpp" #include "../f2/struct.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../hash.hpp" #include "../sort.hpp" #include "../str_utils.hpp" @@ -62,7 +63,7 @@ object_info_data::~object_info_data() { } -object_database_file::object_database_file() : ready(), modern(), is_x() { +object_database_file::object_database_file() : ready(), modern(), big_endian(), is_x() { } @@ -77,18 +78,18 @@ void object_database_file::read(const char* path, bool modern) { if (!modern) { char* path_bin = str_utils_add(path, ".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, "rb"); - if (s.io.stream) { + if (s.check_not_null()) { uint8_t* data = force_malloc_s(uint8_t, s.length); s.read(data, s.length); - stream s_bin; + memory_stream s_bin; s_bin.open(data, s.length); object_database_file_classic_read_inner(this, s_bin); - free(data); + free_def(data); } } - free(path_bin); + free_def(path_bin); } else { char* path_osi = str_utils_add(path, ".osi"); @@ -96,13 +97,13 @@ void object_database_file::read(const char* path, bool modern) { f2_struct st; st.read(path_osi); if (st.header.signature == reverse_endianness_uint32_t('MOSI')) { - stream s_mosi; + memory_stream s_mosi; s_mosi.open(st.data); - s_mosi.is_big_endian = st.header.use_big_endian; + s_mosi.big_endian = st.header.use_big_endian; object_database_file_modern_read_inner(this, s_mosi, st.header.length); } } - free(path_osi); + free_def(path_osi); } } @@ -113,18 +114,18 @@ void object_database_file::read(const wchar_t* path, bool modern) { if (!modern) { wchar_t* path_bin = str_utils_add(path, L".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, L"rb"); - if (s.io.stream) { + if (s.check_not_null()) { uint8_t* data = force_malloc_s(uint8_t, s.length); s.read(data, s.length); - stream s_bin; + memory_stream s_bin; s_bin.open(data, s.length); object_database_file_classic_read_inner(this, s_bin); - free(data); + free_def(data); } } - free(path_bin); + free_def(path_bin); } else { wchar_t* path_osi = str_utils_add(path, L".osi"); @@ -132,13 +133,13 @@ void object_database_file::read(const wchar_t* path, bool modern) { f2_struct st; st.read(path_osi); if (st.header.signature == reverse_endianness_uint32_t('MOSI')) { - stream s_mosi; + memory_stream s_mosi; s_mosi.open(st.data); - s_mosi.is_big_endian = st.header.use_big_endian; + s_mosi.big_endian = st.header.use_big_endian; object_database_file_modern_read_inner(this, s_mosi, st.header.length); } } - free(path_osi); + free_def(path_osi); } } @@ -147,7 +148,7 @@ void object_database_file::read(const void* data, size_t size, bool modern) { return; if (!modern) { - stream s; + memory_stream s; s.open(data, size); object_database_file_classic_read_inner(this, s); } @@ -155,9 +156,9 @@ void object_database_file::read(const void* data, size_t size, bool modern) { f2_struct st; st.read(data, size); if (st.header.signature == reverse_endianness_uint32_t('MOSI')) { - stream s_mosi; + memory_stream s_mosi; s_mosi.open(st.data); - s_mosi.is_big_endian = st.header.use_big_endian; + s_mosi.big_endian = st.header.use_big_endian; object_database_file_modern_read_inner(this, s_mosi, st.header.length); } } @@ -169,19 +170,19 @@ void object_database_file::write(const char* path) { if (!modern) { char* path_bin = str_utils_add(path, ".bin"); - stream s; + file_stream s; s.open(path_bin, "wb"); - if (s.io.stream) + if (s.check_not_null()) object_database_file_classic_write_inner(this, s); - free(path_bin); + free_def(path_bin); } else { char* path_osi = str_utils_add(path, ".osi"); - stream s; + file_stream s; s.open(path_osi, "wb"); - if (s.io.stream) + if (s.check_not_null()) object_database_file_modern_write_inner(this, s); - free(path_osi); + free_def(path_osi); } } @@ -191,19 +192,19 @@ void object_database_file::write(const wchar_t* path) { if (!modern) { wchar_t* path_bin = str_utils_add(path, L".bin"); - stream s; + file_stream s; s.open(path_bin, L"wb"); - if (s.io.stream) + if (s.check_not_null()) object_database_file_classic_write_inner(this, s); - free(path_bin); + free_def(path_bin); } else { wchar_t* path_osi = str_utils_add(path, L".osi"); - stream s; + file_stream s; s.open(path_osi, L"wb"); - if (s.io.stream) + if (s.check_not_null()) object_database_file_modern_write_inner(this, s); - free(path_osi); + free_def(path_osi); } } @@ -211,7 +212,7 @@ void object_database_file::write(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; + memory_stream s; s.open(); if (!modern) object_database_file_classic_write_inner(this, s); @@ -494,7 +495,7 @@ static void object_database_file_classic_read_inner(object_database_file* obj_db for (uint32_t i = 0; i < object_set_count; i++) object_set[i].object.reserve(object_set_object_count[i]); - free(object_set_object_count); + free_def(object_set_object_count); s.position_push(objects_offset, SEEK_SET); for (uint32_t i = 0; i < object_count; i++) { @@ -518,9 +519,10 @@ static void object_database_file_classic_read_inner(object_database_file* obj_db } s.position_pop(); - obj_db->is_x = false; - obj_db->modern = false; obj_db->ready = true; + obj_db->modern = false; + obj_db->big_endian = false; + obj_db->is_x = false; } static void object_database_file_classic_write_inner(object_database_file* obj_db, stream& s) { @@ -532,7 +534,6 @@ static void object_database_file_classic_write_inner(object_database_file* obj_d s.write_uint32_t(0x90669066); s.write_uint32_t(0x90669066); s.write_uint32_t(0x90669066); - s.align_write(0x20); uint32_t object_set_count = (uint32_t)obj_db->object_set.size(); @@ -585,8 +586,7 @@ static void object_database_file_classic_write_inner(object_database_file* obj_d for (object_set_info_file& i : obj_db->object_set) { uint16_t set_id = (uint16_t)i.id; for (object_info_data_file& j : i.object) { - s.write_uint16_t((uint16_t)j.id); - s.write_uint16_t(set_id); + s.write_uint32_t((uint32_t)((set_id << 16) | (uint16_t)j.id)); s.write_uint32_t((uint32_t)string_offsets[off_idx++]); } } @@ -604,6 +604,7 @@ static void object_database_file_classic_write_inner(object_database_file* obj_d } static void object_database_file_modern_read_inner(object_database_file* obj_db, stream& s, uint32_t header_length) { + bool big_endian = s.big_endian; bool is_x = true; s.set_position(0x0C, SEEK_SET); @@ -677,7 +678,7 @@ static void object_database_file_modern_read_inner(object_database_file* obj_db, for (uint32_t i = 0; i < object_set_count; i++) object_set[i].object.reserve(object_set_object_count[i]); - free(object_set_object_count); + free_def(object_set_object_count); s.position_push(objects_offset, SEEK_SET); if (!is_x) @@ -712,21 +713,25 @@ static void object_database_file_modern_read_inner(object_database_file* obj_db, } s.position_pop(); - obj_db->is_x = is_x; - obj_db->modern = true; obj_db->ready = true; + obj_db->modern = true; + obj_db->big_endian = big_endian; + obj_db->is_x = is_x; } static void object_database_file_modern_write_inner(object_database_file* obj_db, stream& s) { - stream s_mosi; + bool big_endian = obj_db->big_endian; + bool is_x = obj_db->is_x; + + memory_stream s_mosi; s_mosi.open(); + s_mosi.big_endian = big_endian; + uint32_t off; enrs e; enrs_entry ee; pof pof; - bool is_x = obj_db->is_x; - uint32_t object_set_count = (uint32_t)obj_db->object_set.size(); uint32_t object_count = 0; @@ -828,7 +833,7 @@ static void object_database_file_modern_write_inner(object_database_file* obj_db for (object_set_info_file& i : obj_db->object_set) { io_write_offset_f2_pof_add(s_mosi, object_database_strings_get_string_offset(strings, string_offsets, i.name), 0x20, &pof); - s_mosi.write_uint32_t(i.id); + s_mosi.write_uint32_t_reverse_endianness(i.id); io_write_offset_f2_pof_add(s_mosi, object_database_strings_get_string_offset(strings, string_offsets, i.object_file_name), 0x20, &pof); io_write_offset_f2_pof_add(s_mosi, object_database_strings_get_string_offset(strings, @@ -841,7 +846,7 @@ static void object_database_file_modern_write_inner(object_database_file* obj_db for (object_set_info_file& i : obj_db->object_set) { io_write_offset_x_pof_add(s_mosi, object_database_strings_get_string_offset(strings, string_offsets, i.name), &pof); - s_mosi.write_uint32_t(i.id); + s_mosi.write_uint32_t_reverse_endianness(i.id); io_write_offset_x_pof_add(s_mosi, object_database_strings_get_string_offset(strings, string_offsets, i.object_file_name), &pof); io_write_offset_x_pof_add(s_mosi, object_database_strings_get_string_offset(strings, @@ -856,8 +861,8 @@ static void object_database_file_modern_write_inner(object_database_file* obj_db for (object_set_info_file& i : obj_db->object_set) { uint32_t set_id = i.id; for (object_info_data_file& j : i.object) { - s_mosi.write_uint32_t(j.id); - s_mosi.write_uint32_t(set_id); + s_mosi.write_uint32_t_reverse_endianness(j.id); + s_mosi.write_uint32_t_reverse_endianness(set_id); io_write_offset_f2_pof_add(s_mosi, object_database_strings_get_string_offset(strings, string_offsets, j.name), 0x20, &pof); } @@ -866,8 +871,8 @@ static void object_database_file_modern_write_inner(object_database_file* obj_db for (object_set_info_file& i : obj_db->object_set) { uint32_t set_id = i.id; for (object_info_data_file& j : i.object) { - s_mosi.write_uint32_t(j.id); - s_mosi.write_uint32_t(set_id); + s_mosi.write_uint32_t_reverse_endianness(j.id); + s_mosi.write_uint32_t_reverse_endianness(set_id); io_write_offset_x_pof_add(s_mosi, object_database_strings_get_string_offset(strings, string_offsets, j.name), &pof); } @@ -884,7 +889,7 @@ static void object_database_file_modern_write_inner(object_database_file* obj_db st.header.signature = reverse_endianness_uint32_t('MOSI'); st.header.length = 0x20; - st.header.use_big_endian = false; + st.header.use_big_endian = big_endian; st.header.use_section_size = true; st.write(s, true, is_x); diff --git a/src/KKdLib/database/object.hpp b/src/KKdLib/database/object.hpp index 95f3c986..45a7515f 100644 --- a/src/KKdLib/database/object.hpp +++ b/src/KKdLib/database/object.hpp @@ -98,6 +98,7 @@ struct object_set_info { struct object_database_file { bool ready; bool modern; + bool big_endian; bool is_x; std::vector object_set; diff --git a/src/KKdLib/database/sprite.cpp b/src/KKdLib/database/sprite.cpp index c8c8724f..740f5a34 100644 --- a/src/KKdLib/database/sprite.cpp +++ b/src/KKdLib/database/sprite.cpp @@ -4,3 +4,768 @@ */ #include "sprite.hpp" +#include "../f2/struct.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" +#include "../io/path.hpp" +#include "../hash.hpp" +#include "../sort.hpp" +#include "../str_utils.hpp" + +static void sprite_database_file_classic_read_inner(sprite_database_file* spr_db, stream& s); +static void sprite_database_file_classic_write_inner(sprite_database_file* spr_db, stream& s); +static void sprite_database_file_modern_read_inner(sprite_database_file* spr_db, stream& s, uint32_t header_length); +static void sprite_database_file_modern_write_inner(sprite_database_file* spr_db, stream& s); +static int64_t sprite_database_file_strings_get_string_offset(std::vector& vec, + std::vector& vec_off, std::string& str); +static bool sprite_database_file_strings_push_back_check(std::vector& vec, std::string& str); + +sprite_info_file::sprite_info_file() : id(), index() { + +} + +sprite_info_file::~sprite_info_file() { + +} + +sprite_info::sprite_info() : id(), index() { + name_hash = hash_murmurhash_empty; +} + +sprite_info::~sprite_info() { + +} + +sprite_texture_info_file::sprite_texture_info_file() : id(), index() { + +} + +sprite_texture_info_file::~sprite_texture_info_file() { + +} + +sprite_texture_info::sprite_texture_info() : id(), index() { + name_hash = hash_murmurhash_empty; +} + +sprite_texture_info::~sprite_texture_info() { + +} + +sprite_set_file::sprite_set_file() : id(), index(){ + +} + +sprite_set_file::~sprite_set_file() { + +} + +sprite_set::sprite_set() : id(), index() { + name_hash = hash_murmurhash_empty; + file_name_hash = hash_murmurhash_empty; +} + +sprite_set::~sprite_set() { + +} + +sprite_database_file::sprite_database_file() : ready(), modern(), big_endian(), is_x() { + +} + +sprite_database_file::~sprite_database_file() { + +} + +void sprite_database_file::read(const char* path, bool modern) { + if (!path) + return; + + if (!modern) { + char* path_bin = str_utils_add(path, ".bin"); + if (path_check_file_exists(path_bin)) { + file_stream s; + s.open(path_bin, "rb"); + if (s.check_not_null()) { + uint8_t* data = force_malloc_s(uint8_t, s.length); + s.read(data, s.length); + memory_stream s_bin; + s_bin.open(data, s.length); + sprite_database_file_classic_read_inner(this, s_bin); + free_def(data); + } + } + free_def(path_bin); + } + else { + char* path_spi = str_utils_add(path, ".spi"); + if (path_check_file_exists(path_spi)) { + f2_struct st; + st.read(path_spi); + if (st.header.signature == reverse_endianness_uint32_t('SPDB')) { + memory_stream s_spdb; + s_spdb.open(st.data); + s_spdb.big_endian = st.header.use_big_endian; + sprite_database_file_modern_read_inner(this, s_spdb, st.header.length); + } + } + free_def(path_spi); + } +} + +void sprite_database_file::read(const wchar_t* path, bool modern) { + if (!path) + return; + + if (!modern) { + wchar_t* path_bin = str_utils_add(path, L".bin"); + if (path_check_file_exists(path_bin)) { + file_stream s; + s.open(path_bin, L"rb"); + if (s.check_not_null()) { + uint8_t* data = force_malloc_s(uint8_t, s.length); + s.read(data, s.length); + memory_stream s_bin; + s_bin.open(data, s.length); + sprite_database_file_classic_read_inner(this, s_bin); + free_def(data); + } + } + free_def(path_bin); + } + else { + wchar_t* path_spi = str_utils_add(path, L".spi"); + if (path_check_file_exists(path_spi)) { + f2_struct st; + st.read(path_spi); + if (st.header.signature == reverse_endianness_uint32_t('SPDB')) { + memory_stream s_spdb; + s_spdb.open(st.data); + s_spdb.big_endian = st.header.use_big_endian; + sprite_database_file_modern_read_inner(this, s_spdb, st.header.length); + } + } + free_def(path_spi); + } +} + +void sprite_database_file::read(const void* data, size_t size, bool modern) { + if (!data || !size) + return; + + if (!modern) { + memory_stream s; + s.open(data, size); + sprite_database_file_classic_read_inner(this, s); + } + else { + f2_struct st; + st.read(data, size); + if (st.header.signature == reverse_endianness_uint32_t('SPDB')) { + memory_stream s_spdb; + s_spdb.open(st.data); + s_spdb.big_endian = st.header.use_big_endian; + sprite_database_file_modern_read_inner(this, s_spdb, st.header.length); + } + } +} + +void sprite_database_file::write(const char* path) { + if (!path || !ready) + return; + + if (!modern) { + char* path_bin = str_utils_add(path, ".bin"); + file_stream s; + s.open(path_bin, "wb"); + if (s.check_not_null()) + sprite_database_file_classic_write_inner(this, s); + free_def(path_bin); + } + else { + char* path_spi = str_utils_add(path, ".spi"); + file_stream s; + s.open(path_spi, "wb"); + if (s.check_not_null()) + sprite_database_file_modern_write_inner(this, s); + free_def(path_spi); + } +} + +void sprite_database_file::write(const wchar_t* path) { + if (!path || !ready) + return; + + if (!modern) { + wchar_t* path_bin = str_utils_add(path, L".bin"); + file_stream s; + s.open(path_bin, L"wb"); + if (s.check_not_null()) + sprite_database_file_classic_write_inner(this, s); + free_def(path_bin); + } + else { + wchar_t* path_spi = str_utils_add(path, L".spi"); + file_stream s; + s.open(path_spi, L"wb"); + if (s.check_not_null()) + sprite_database_file_modern_write_inner(this, s); + free_def(path_spi); + } +} + +void sprite_database_file::write(void** data, size_t* size) { + if (!data || !size || !ready) + return; + + memory_stream s; + s.open(); + if (!modern) + sprite_database_file_classic_write_inner(this, s); + else + sprite_database_file_modern_write_inner(this, s); + s.align_write(0x10); + s.copy(data, size); +} + +bool sprite_database_file::load_file(void* data, const char* path, const char* file, uint32_t hash) { + size_t file_len = utf8_length(file); + + const char* t = strrchr(file, '.'); + if (t) + file_len = t - file; + + std::string s = path + std::string(file, file_len); + + sprite_database_file* spr_db = (sprite_database_file*)data; + spr_db->read(s.c_str(), spr_db->modern); + + return spr_db->ready; +} + +sprite_database::sprite_database() { + +} + +sprite_database::~sprite_database() { + +} + +void sprite_database::add(sprite_database_file* spr_db_file) { + if (!spr_db_file || !spr_db_file->ready) + return; + + sprite_set_file* sprite_set = spr_db_file->sprite_set.data(); + + size_t sprite_sets_count = this->sprite_set.size(); + + this->sprite_set.reserve(spr_db_file->sprite_set.size()); + + for (sprite_set_file& i : spr_db_file->sprite_set) { + uint32_t id = i.id; + + ::sprite_set* set_info = 0; + for (::sprite_set& j : this->sprite_set) + if (id == j.id) { + set_info = &j; + break; + } + + if (!set_info) { + this->sprite_set.push_back({}); + set_info = &this->sprite_set.back(); + } + + set_info->id = i.id; + set_info->name.assign(i.name); + set_info->name_hash = hash_string_murmurhash(set_info->name); + set_info->file_name.assign(i.file_name); + set_info->file_name_hash = hash_string_murmurhash(set_info->file_name); + + set_info->sprite.clear(); + set_info->sprite.reserve(i.sprite.size()); + + for (sprite_info_file& j : i.sprite) { + set_info->sprite.push_back({}); + sprite_info& info = set_info->sprite.back(); + info.id = j.id; + info.name.assign(j.name); + info.name_hash = hash_string_murmurhash(info.name); + } + + set_info->texture.clear(); + set_info->texture.reserve(i.texture.size()); + + for (sprite_texture_info_file& j : i.texture) { + set_info->texture.push_back({}); + sprite_texture_info& info = set_info->texture.back(); + info.id = j.id; + info.name.assign(j.name); + info.name_hash = hash_string_murmurhash(info.name); + } + + set_info->index = (uint32_t)(sprite_sets_count + i.index); + } +} + +static void sprite_database_file_classic_read_inner(sprite_database_file* spr_db, stream& s) { + uint32_t sprite_sets_count = s.read_uint32_t(); + uint32_t sprite_sets_offset = s.read_uint32_t(); + uint32_t sprites_count = s.read_uint32_t(); + uint32_t sprites_offset = s.read_uint32_t(); + + spr_db->sprite_set.resize(sprite_sets_count); + + sprite_set_file* sprite_set = spr_db->sprite_set.data(); + + s.position_push(sprite_sets_offset, SEEK_SET); + for (uint32_t i = 0; i < sprite_sets_count; i++) { + sprite_set_file& set_info = sprite_set[i]; + set_info.id = s.read_uint32_t(); + set_info.name = s.read_string_null_terminated_offset(s.read_uint32_t()); + set_info.file_name = s.read_string_null_terminated_offset(s.read_uint32_t()); + set_info.index = s.read_uint32_t(); + } + s.position_pop(); + + s.position_push(sprites_offset, SEEK_SET); + for (uint32_t i = 0; i < sprites_count; i++) { + uint32_t id = s.read_uint32_t(); + uint32_t name_offset = s.read_uint32_t(); + uint32_t info = s.read_uint32_t(); + + uint16_t index = (uint16_t)(info & 0xFFFF); + uint16_t set_index = (uint16_t)((info >> 16) & 0x0FFF); + + sprite_set_file& set_info = sprite_set[set_index]; + + if ((info >> 16) & 0x1000) { + set_info.texture.push_back({}); + sprite_texture_info_file& info = set_info.texture.back(); + info.id = id; + info.name.assign(s.read_string_null_terminated_offset(name_offset)); + info.index = index; + } + else { + set_info.sprite.push_back({}); + sprite_info_file& info = set_info.sprite.back(); + info.id = id; + info.name.assign(s.read_string_null_terminated_offset(name_offset)); + info.index = index; + } + } + s.position_pop(); + + spr_db->ready = true; + spr_db->modern = false; + spr_db->big_endian = false; + spr_db->is_x = false; +} + +static void sprite_database_file_classic_write_inner(sprite_database_file* spr_db, stream& s) { + s.write_uint32_t(0x90669066); + s.write_uint32_t(0x90669066); + s.write_uint32_t(0x90669066); + s.write_uint32_t(0x90669066); + s.write_uint32_t(0x90669066); + s.write_uint32_t(0x90669066); + s.write_uint32_t(0x90669066); + s.write_uint32_t(0x90669066); + s.align_write(0x20); + + size_t sprite_sets_count = spr_db->sprite_set.size(); + + size_t sprites_count = 0; + for (sprite_set_file& i : spr_db->sprite_set) + sprites_count += i.sprite.size() + i.texture.size(); + + int64_t sprites_offset = s.get_position(); + s.write(0x0C * sprites_count); + s.align_write(0x20); + + int64_t sprite_sets_offset = s.get_position(); + s.write(0x10 * spr_db->sprite_set.size()); + s.align_write(0x20); + + std::vector strings; + std::vector string_offsets; + + strings.reserve(sprite_sets_count + sprites_count); + + for (sprite_set_file& i : spr_db->sprite_set) { + for (sprite_texture_info_file& j : i.texture) + if (sprite_database_file_strings_push_back_check(strings, j.name)) { + string_offsets.push_back(s.get_position()); + s.write_string_null_terminated(j.name); + } + + for (sprite_info_file& j : i.sprite) + if (sprite_database_file_strings_push_back_check(strings, j.name)) { + string_offsets.push_back(s.get_position()); + s.write_string_null_terminated(j.name); + } + } + s.align_write(0x04); + + for (sprite_set_file& i : spr_db->sprite_set) { + if (sprite_database_file_strings_push_back_check(strings, i.name)) { + string_offsets.push_back(s.get_position()); + s.write_string_null_terminated(i.name); + } + + if (sprite_database_file_strings_push_back_check(strings, i.file_name)) { + string_offsets.push_back(s.get_position()); + s.write_string_null_terminated(i.file_name); + } + } + s.align_write(0x04); + + s.position_push(sprites_offset, SEEK_SET); + for (sprite_set_file& i : spr_db->sprite_set) { + uint16_t sprite_set_index = (uint16_t)(i.index & 0x0FFF); + + for (sprite_texture_info_file& j : i.texture) { + s.write_uint32_t(j.id); + s.write_uint32_t((uint32_t)sprite_database_file_strings_get_string_offset(strings, + string_offsets, j.name)); + s.write_uint32_t(((0x1000 | sprite_set_index) << 16) | j.index); + } + + for (sprite_info_file& j : i.sprite) { + s.write_uint32_t(j.id); + s.write_uint32_t((uint32_t)sprite_database_file_strings_get_string_offset(strings, + string_offsets, j.name)); + s.write_uint32_t((sprite_set_index << 16) | j.index); + } + } + s.position_pop(); + + s.position_push(sprite_sets_offset, SEEK_SET); + for (sprite_set_file& i : spr_db->sprite_set) { + s.write_uint32_t(i.id); + s.write_uint32_t((uint32_t)sprite_database_file_strings_get_string_offset(strings, + string_offsets, i.name)); + s.write_uint32_t((uint32_t)sprite_database_file_strings_get_string_offset(strings, + string_offsets, i.file_name)); + s.write_uint32_t(i.index); + } + s.position_pop(); + + s.position_push(0x00, SEEK_SET); + s.write_uint32_t((uint32_t)sprite_sets_count); + s.write_uint32_t((uint32_t)sprite_sets_offset); + s.write_uint32_t((uint32_t)sprites_count); + s.write_uint32_t((uint32_t)sprites_offset); + s.position_pop(); +} + +static void sprite_database_file_modern_read_inner(sprite_database_file* spr_db, stream& s, uint32_t header_length) { + bool big_endian = s.big_endian; + bool is_x = true; + + s.set_position(0x04, SEEK_SET); + is_x &= s.read_uint32_t_reverse_endianness() == 0; + + s.set_position(0x00, SEEK_SET); + + uint32_t sprite_sets_count = s.read_uint32_t_reverse_endianness(); + int64_t sprite_sets_offset = s.read_offset(header_length, is_x); + uint32_t sprites_count = s.read_uint32_t_reverse_endianness(); + int64_t sprites_offset = s.read_offset(header_length, is_x); + + spr_db->sprite_set.resize(sprite_sets_count); + + sprite_set_file* sprite_set = spr_db->sprite_set.data(); + + s.position_push(sprite_sets_offset, SEEK_SET); + if (!is_x) + for (uint32_t i = 0; i < sprite_sets_count; i++) { + sprite_set_file& set_info = sprite_set[i]; + set_info.id = s.read_uint32_t_reverse_endianness(); + set_info.name = s.read_string_null_terminated_offset(s.read_offset_f2(header_length)); + set_info.file_name = s.read_string_null_terminated_offset(s.read_offset_f2(header_length)); + set_info.index = s.read_uint32_t_reverse_endianness(); + } + else + for (uint32_t i = 0; i < sprite_sets_count; i++) { + sprite_set_file& set_info = sprite_set[i]; + set_info.id = s.read_uint32_t_reverse_endianness(); + set_info.name = s.read_string_null_terminated_offset(s.read_offset_x()); + set_info.file_name = s.read_string_null_terminated_offset(s.read_offset_x()); + set_info.index = s.read_uint32_t_reverse_endianness(); + s.align_read(0x08); + } + s.position_pop(); + + s.position_push(sprites_offset, SEEK_SET); + if (!is_x) + for (uint32_t i = 0; i < sprites_count; i++) { + uint32_t id = s.read_uint32_t_reverse_endianness(); + int64_t name_offset = s.read_offset_f2(header_length); + uint32_t info = s.read_uint32_t_reverse_endianness(); + + uint16_t index = (uint16_t)(info & 0xFFFF); + uint16_t set_index = (uint16_t)((info >> 16) & 0x0FFF); + + sprite_set_file& set_info = sprite_set[set_index]; + + if ((info >> 16) & 0x1000) { + set_info.texture.push_back({}); + sprite_texture_info_file& info = set_info.texture.back(); + info.id = id; + info.name.assign(s.read_string_null_terminated_offset(name_offset)); + info.index = index; + } + else { + set_info.sprite.push_back({}); + sprite_info_file& info = set_info.sprite.back(); + info.id = id; + info.name.assign(s.read_string_null_terminated_offset(name_offset)); + info.index = index; + } + } + else + for (uint32_t i = 0; i < sprites_count; i++) { + uint32_t id = s.read_uint32_t_reverse_endianness(); + int64_t name_offset = s.read_offset_x(); + uint32_t info = s.read_uint32_t_reverse_endianness(); + s.align_read(0x08); + + uint16_t index = (uint16_t)(info & 0xFFFF); + uint16_t set_index = (uint16_t)((info >> 16) & 0x0FFF); + + sprite_set_file& set_info = sprite_set[set_index]; + + if ((info >> 16) & 0x1000) { + set_info.texture.push_back({}); + sprite_texture_info_file& info = set_info.texture.back(); + info.id = id; + info.name.assign(s.read_string_null_terminated_offset(name_offset)); + info.index = index; + } + else { + set_info.sprite.push_back({}); + sprite_info_file& info = set_info.sprite.back(); + info.id = id; + info.name.assign(s.read_string_null_terminated_offset(name_offset)); + info.index = index; + } + } + s.position_pop(); + + spr_db->ready = true; + spr_db->modern = true; + spr_db->big_endian = big_endian; + spr_db->is_x = is_x; +} + +static void sprite_database_file_modern_write_inner(sprite_database_file* spr_db, stream& s) { + bool big_endian = spr_db->big_endian; + bool is_x = spr_db->is_x; + + memory_stream s_spdb; + s_spdb.open(); + s_spdb.big_endian = big_endian; + + uint32_t off; + enrs e; + enrs_entry ee; + pof pof; + + size_t sprite_sets_count = spr_db->sprite_set.size(); + + size_t sprites_count = 0; + for (sprite_set_file& i : spr_db->sprite_set) + sprites_count += i.sprite.size() + i.texture.size(); + + if (!is_x) { + ee = { 0, 1, 16, 1 }; + ee.append(0, 4, ENRS_DWORD); + e.vec.push_back(ee); + off = 16; + off = align_val(off, 0x10); + + ee = { off, 1, 16, (uint32_t)sprite_sets_count }; + ee.append(0, 4, ENRS_DWORD); + e.vec.push_back(ee); + off = (uint32_t)(sprite_sets_count * 16ULL); + off = align_val(off, 0x10); + + ee = { off, 1, 12, (uint32_t)sprites_count }; + ee.append(0, 3, ENRS_DWORD); + e.vec.push_back(ee); + off = (uint32_t)(sprites_count * 12ULL); + off = align_val(off, 0x10); + } + else { + ee = { 0, 4, 32, 1 }; + ee.append(0, 1, ENRS_DWORD); + ee.append(4, 1, ENRS_QWORD); + ee.append(0, 1, ENRS_DWORD); + ee.append(4, 1, ENRS_QWORD); + e.vec.push_back(ee); + off = 32; + off = align_val(off, 0x10); + + ee = { off, 3, 32, (uint32_t)sprite_sets_count }; + ee.append(0, 1, ENRS_DWORD); + ee.append(4, 2, ENRS_QWORD); + ee.append(0, 1, ENRS_DWORD); + e.vec.push_back(ee); + off = (uint32_t)(sprite_sets_count * 32ULL); + off = align_val(off, 0x10); + + ee = { off, 3, 24, (uint32_t)sprites_count }; + ee.append(0, 1, ENRS_DWORD); + ee.append(4, 1, ENRS_QWORD); + ee.append(0, 1, ENRS_DWORD); + e.vec.push_back(ee); + off = (uint32_t)(sprites_count * 24ULL); + off = align_val(off, 0x10); + } + + s_spdb.write(is_x ? 0x20 : 0x10); + s_spdb.align_write(0x10); + + int64_t sprite_sets_offset = s_spdb.get_position(); + s_spdb.write(sprite_sets_count * (is_x ? 0x20ULL : 0x10ULL)); + s_spdb.align_write(0x10); + + int64_t sprites_offset = s_spdb.get_position(); + s_spdb.write(sprites_count * (is_x ? 0x18ULL : 0x0CULL)); + s_spdb.align_write(0x10); + + std::vector strings; + std::vector string_offsets; + + strings.reserve(sprite_sets_count + sprites_count); + + for (sprite_set_file& i : spr_db->sprite_set) { + if (sprite_database_file_strings_push_back_check(strings, i.name)) { + string_offsets.push_back(s_spdb.get_position()); + s_spdb.write_string_null_terminated(i.name); + } + + if (sprite_database_file_strings_push_back_check(strings, i.file_name)) { + string_offsets.push_back(s_spdb.get_position()); + s_spdb.write_string_null_terminated(i.file_name); + } + } + + for (sprite_set_file& i : spr_db->sprite_set) { + for (sprite_texture_info_file& j : i.texture) + if (sprite_database_file_strings_push_back_check(strings, j.name)) { + string_offsets.push_back(s_spdb.get_position()); + s_spdb.write_string_null_terminated(j.name); + } + + for (sprite_info_file& j : i.sprite) + if (sprite_database_file_strings_push_back_check(strings, j.name)) { + string_offsets.push_back(s_spdb.get_position()); + s_spdb.write_string_null_terminated(j.name); + } + } + s_spdb.align_write(0x10); + + s_spdb.position_push(0x00, SEEK_SET); + s_spdb.write_uint32_t_reverse_endianness((uint32_t)sprite_sets_count); + io_write_offset_pof_add(s_spdb, sprite_sets_offset, 0x20, is_x, &pof); + s_spdb.write_uint32_t_reverse_endianness((uint32_t)sprites_count); + io_write_offset_pof_add(s_spdb, sprites_offset, 0x20, is_x, &pof); + s_spdb.position_pop(); + + s_spdb.position_push(sprite_sets_offset, SEEK_SET); + if (!is_x) + for (sprite_set_file& i : spr_db->sprite_set) { + s_spdb.write_uint32_t_reverse_endianness(i.id); + io_write_offset_f2_pof_add(s_spdb, sprite_database_file_strings_get_string_offset(strings, + string_offsets, i.name), 0x20, &pof); + io_write_offset_f2_pof_add(s_spdb, sprite_database_file_strings_get_string_offset(strings, + string_offsets, i.file_name), 0x20, &pof); + s_spdb.write_uint32_t_reverse_endianness(i.index); + } + else + for (sprite_set_file& i : spr_db->sprite_set) { + s_spdb.write_uint32_t_reverse_endianness(i.id); + io_write_offset_x_pof_add(s_spdb, sprite_database_file_strings_get_string_offset(strings, + string_offsets, i.name), &pof); + io_write_offset_x_pof_add(s_spdb, sprite_database_file_strings_get_string_offset(strings, + string_offsets, i.file_name), &pof); + s_spdb.write_uint32_t_reverse_endianness(i.index); + } + s_spdb.position_pop(); + + s_spdb.position_push(sprites_offset, SEEK_SET); + for (sprite_set_file& i : spr_db->sprite_set) { + uint16_t sprite_set_index = (uint16_t)(i.index & 0x0FFF); + + if (!is_x) + for (sprite_texture_info_file& j : i.texture) { + s_spdb.write_uint32_t_reverse_endianness(j.id); + io_write_offset_f2_pof_add(s_spdb, sprite_database_file_strings_get_string_offset(strings, + string_offsets, j.name), 0x20, &pof); + s_spdb.write_uint32_t_reverse_endianness(((0x1000 | sprite_set_index) << 16) | j.index); + } + else + for (sprite_texture_info_file& j : i.texture) { + s_spdb.write_uint32_t_reverse_endianness(j.id); + io_write_offset_x_pof_add(s_spdb, sprite_database_file_strings_get_string_offset(strings, + string_offsets, j.name), &pof); + s_spdb.write_uint32_t_reverse_endianness(((0x1000 | sprite_set_index) << 16) | j.index); + s_spdb.align_write(0x08); + } + + if (!is_x) + for (sprite_info_file& j : i.sprite) { + s_spdb.write_uint32_t_reverse_endianness(j.id); + io_write_offset_f2_pof_add(s_spdb, sprite_database_file_strings_get_string_offset(strings, + string_offsets, j.name), 0x20, &pof); + s_spdb.write_uint32_t_reverse_endianness((sprite_set_index << 16) | j.index); + } + else + for (sprite_info_file& j : i.sprite) { + s_spdb.write_uint32_t_reverse_endianness(j.id); + io_write_offset_x_pof_add(s_spdb, sprite_database_file_strings_get_string_offset(strings, + string_offsets, j.name), &pof); + s_spdb.write_uint32_t_reverse_endianness((sprite_set_index << 16) | j.index); + s_spdb.align_write(0x08); + } + } + s_spdb.position_pop(); + + f2_struct st; + s_spdb.align_write(0x10); + s_spdb.copy(st.data); + s_spdb.close(); + + st.enrs = e; + st.pof = pof; + + st.header.signature = reverse_endianness_uint32_t('SPDB'); + st.header.length = 0x20; + st.header.use_big_endian = big_endian; + st.header.use_section_size = true; + + st.write(s, true, spr_db->is_x); +} + +inline static int64_t sprite_database_file_strings_get_string_offset(std::vector& vec, + std::vector& vec_off, std::string& str) { + uint64_t hash_fnv1a64m = hash_string_fnv1a64m(str); + uint64_t hash_murmurhash = hash_string_murmurhash(str); + for (string_hash& i : vec) + if (hash_fnv1a64m == i.hash_fnv1a64m && hash_murmurhash == i.hash_murmurhash) + return vec_off[&i - vec.data()]; + return 0; +} + +inline static bool sprite_database_file_strings_push_back_check(std::vector& vec, std::string& str) { + uint64_t hash_fnv1a64m = hash_string_fnv1a64m(str); + uint64_t hash_murmurhash = hash_string_murmurhash(str); + for (string_hash& i : vec) + if (hash_fnv1a64m == i.hash_fnv1a64m && hash_murmurhash == i.hash_murmurhash) + return false; + + vec.push_back(str); + return true; +} diff --git a/src/KKdLib/database/sprite.hpp b/src/KKdLib/database/sprite.hpp index 3b25d82b..996f9248 100644 --- a/src/KKdLib/database/sprite.hpp +++ b/src/KKdLib/database/sprite.hpp @@ -6,3 +6,99 @@ #pragma once #include "../default.hpp" +#include +#include + +struct sprite_info_file { + uint32_t id; + std::string name; + uint16_t index; + + sprite_info_file(); + ~sprite_info_file(); +}; + +struct sprite_info { + uint32_t id; + std::string name; + uint32_t name_hash; + uint16_t index; + + sprite_info(); + ~sprite_info(); +}; + +struct sprite_texture_info_file { + uint32_t id; + std::string name; + uint16_t index; + + sprite_texture_info_file(); + ~sprite_texture_info_file(); +}; + +struct sprite_texture_info { + uint32_t id; + std::string name; + uint32_t name_hash; + uint16_t index; + + sprite_texture_info(); + ~sprite_texture_info(); +}; + +struct sprite_set_file { + uint32_t id; + std::string name; + std::string file_name; + std::vector sprite; + std::vector texture; + uint32_t index; + + sprite_set_file(); + ~sprite_set_file(); +}; + +struct sprite_set { + uint32_t id; + std::string name; + uint32_t name_hash; + std::string file_name; + uint32_t file_name_hash; + std::vector sprite; + std::vector texture; + uint32_t index; + + sprite_set(); + ~sprite_set(); +}; + +struct sprite_database_file { + bool ready; + bool modern; + bool big_endian; + bool is_x; + + std::vector sprite_set; + + sprite_database_file(); + virtual ~sprite_database_file(); + + void read(const char* path, bool modern); + void read(const wchar_t* path, bool modern); + void read(const void* data, size_t size, bool modern); + void write(const char* path); + void write(const wchar_t* path); + void write(void** data, size_t* size); + + static bool load_file(void* data, const char* path, const char* file, uint32_t hash); +}; + +struct sprite_database { + std::vector sprite_set; + + sprite_database(); + virtual ~sprite_database(); + + void add(sprite_database_file* spr_db_file); +}; diff --git a/src/KKdLib/database/stage.cpp b/src/KKdLib/database/stage.cpp index fb78d3cd..6847b182 100644 --- a/src/KKdLib/database/stage.cpp +++ b/src/KKdLib/database/stage.cpp @@ -5,8 +5,9 @@ #include "stage.hpp" #include "../f2/struct.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../hash.hpp" #include "../str_utils.hpp" @@ -65,7 +66,7 @@ stage_data_modern::~stage_data_modern() { } -stage_database_file::stage_database_file() : ready(), modern(), is_x(), format() { +stage_database_file::stage_database_file() : ready(), modern(), big_endian(), is_x(), format() { } @@ -80,18 +81,18 @@ void stage_database_file::read(const char* path, bool modern) { if (!modern) { char* path_bin = str_utils_add(path, ".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, "rb"); - if (s.io.stream) { + if (s.check_not_null()) { uint8_t* data = force_malloc_s(uint8_t, s.length); s.read(data, s.length); - stream s_bin; + memory_stream s_bin; s_bin.open(data, s.length); stage_database_file_classic_read_inner(this, s_bin); - free(data); + free_def(data); } } - free(path_bin); + free_def(path_bin); } else { char* path_stg = str_utils_add(path, ".stg"); @@ -99,13 +100,13 @@ void stage_database_file::read(const char* path, bool modern) { f2_struct st; st.read(path_stg); if (st.header.signature == reverse_endianness_uint32_t('STGC')) { - stream s_stgc; + memory_stream s_stgc; s_stgc.open(st.data); - s_stgc.is_big_endian = st.header.use_big_endian; + s_stgc.big_endian = st.header.use_big_endian; stage_database_file_modern_read_inner(this, s_stgc, st.header.length); } } - free(path_stg); + free_def(path_stg); } } @@ -116,18 +117,18 @@ void stage_database_file::read(const wchar_t* path, bool modern) { if (!modern) { wchar_t* path_bin = str_utils_add(path, L".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, L"rb"); - if (s.io.stream) { + if (s.check_not_null()) { uint8_t* data = force_malloc_s(uint8_t, s.length); s.read(data, s.length); - stream s_bin; + memory_stream s_bin; s_bin.open(data, s.length); stage_database_file_classic_read_inner(this, s_bin); - free(data); + free_def(data); } } - free(path_bin); + free_def(path_bin); } else { wchar_t* path_stg = str_utils_add(path, L".stg"); @@ -135,13 +136,13 @@ void stage_database_file::read(const wchar_t* path, bool modern) { f2_struct st; st.read(path_stg); if (st.header.signature == reverse_endianness_uint32_t('STGC')) { - stream s_stgc; + memory_stream s_stgc; s_stgc.open(st.data); - s_stgc.is_big_endian = st.header.use_big_endian; + s_stgc.big_endian = st.header.use_big_endian; stage_database_file_modern_read_inner(this, s_stgc, st.header.length); } } - free(path_stg); + free_def(path_stg); } } @@ -150,7 +151,7 @@ void stage_database_file::read(const void* data, size_t size, bool modern) { return; if (!modern) { - stream s; + memory_stream s; s.open(data, size); stage_database_file_classic_read_inner(this, s); } @@ -158,9 +159,9 @@ void stage_database_file::read(const void* data, size_t size, bool modern) { f2_struct st; st.read(data, size); if (st.header.signature == reverse_endianness_uint32_t('STGC')) { - stream s_stgc; + memory_stream s_stgc; s_stgc.open(st.data); - s_stgc.is_big_endian = st.header.use_big_endian; + s_stgc.big_endian = st.header.use_big_endian; stage_database_file_modern_read_inner(this, s_stgc, st.header.length); } } @@ -172,19 +173,19 @@ void stage_database_file::write(const char* path) { if (!modern) { char* path_bin = str_utils_add(path, ".bin"); - stream s; + file_stream s; s.open(path_bin, "wb"); - if (s.io.stream) + if (s.check_not_null()) stage_database_file_classic_write_inner(this, s); - free(path_bin); + free_def(path_bin); } else { char* path_stg = str_utils_add(path, ".stg"); - stream s; + file_stream s; s.open(path_stg, "wb"); - if (s.io.stream) + if (s.check_not_null()) stage_database_file_modern_write_inner(this, s); - free(path_stg); + free_def(path_stg); } } @@ -194,19 +195,19 @@ void stage_database_file::write(const wchar_t* path) { if (!modern) { wchar_t* path_bin = str_utils_add(path, L".bin"); - stream s; + file_stream s; s.open(path_bin, L"wb"); - if (s.io.stream) + if (s.check_not_null()) stage_database_file_classic_write_inner(this, s); - free(path_bin); + free_def(path_bin); } else { wchar_t* path_stg = str_utils_add(path, L".stg"); - stream s; + file_stream s; s.open(path_stg, L"wb"); - if (s.io.stream) + if (s.check_not_null()) stage_database_file_modern_write_inner(this, s); - free(path_stg); + free_def(path_stg); } } @@ -214,7 +215,7 @@ void stage_database_file::write(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; + memory_stream s; s.open(); if (!modern) stage_database_file_classic_write_inner(this, s); @@ -408,6 +409,7 @@ static void stage_database_file_classic_read_inner(stage_database_file* stage_da if (stage_data->format == STAGE_DATA_UNK) { stage_data->ready = false; stage_data->modern = false; + stage_data->big_endian = false; stage_data->is_x = false; return; } @@ -571,6 +573,7 @@ static void stage_database_file_classic_read_inner(stage_database_file* stage_da stage_data->ready = true; stage_data->modern = false; + stage_data->big_endian = false; stage_data->is_x = false; } @@ -579,6 +582,7 @@ static void stage_database_file_classic_write_inner(stage_database_file* stage_d } static void stage_database_file_modern_read_inner(stage_database_file* stage_data, stream& s, uint32_t header_length) { + bool big_endian = s.big_endian; bool is_x = true; s.set_position(0x04, SEEK_SET); @@ -686,6 +690,7 @@ static void stage_database_file_modern_read_inner(stage_database_file* stage_dat stage_data->ready = true; stage_data->modern = true; + stage_data->big_endian = big_endian; stage_data->is_x = is_x; stage_data->format = STAGE_DATA_UNK; } diff --git a/src/KKdLib/database/stage.hpp b/src/KKdLib/database/stage.hpp index 7a011108..b13826c0 100644 --- a/src/KKdLib/database/stage.hpp +++ b/src/KKdLib/database/stage.hpp @@ -231,6 +231,7 @@ struct stage_data_modern { struct stage_database_file { bool ready; bool modern; + bool big_endian; bool is_x; stage_data_format format; diff --git a/src/KKdLib/database/texture.cpp b/src/KKdLib/database/texture.cpp index e0e81130..189dd541 100644 --- a/src/KKdLib/database/texture.cpp +++ b/src/KKdLib/database/texture.cpp @@ -5,8 +5,9 @@ #include "texture.hpp" #include "../f2/struct.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../hash.hpp" #include "../sort.hpp" #include "../str_utils.hpp" @@ -15,9 +16,9 @@ static void texture_database_file_classic_read_inner(texture_database_file* tex_ static void texture_database_file_classic_write_inner(texture_database_file* tex_db, stream& s); static void texture_database_file_modern_read_inner(texture_database_file* tex_db, stream& s, uint32_t header_length); static void texture_database_file_modern_write_inner(texture_database_file* tex_db, stream& s); -static int64_t texture_database_file_strings_get_string_offset(std::vector& vec, +static int64_t texture_database_file_strings_get_string_offset(std::vector& vec, std::vector& vec_off, std::string& str); -static void texture_database_file_strings_push_back_check(std::vector& vec, std::string& str); +static void texture_database_file_strings_push_back_check(std::vector& vec, std::string& str); texture_info_file::texture_info_file() { id = (uint32_t)-1; @@ -36,7 +37,7 @@ texture_info::~texture_info() { } -texture_database_file::texture_database_file() : ready(), modern(), is_x() { +texture_database_file::texture_database_file() : ready(), modern(), big_endian(), is_x() { } @@ -51,18 +52,18 @@ void texture_database_file::read(const char* path, bool modern) { if (!modern) { char* path_bin = str_utils_add(path, ".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, "rb"); - if (s.io.stream) { + if (s.check_not_null()) { uint8_t* data = force_malloc_s(uint8_t, s.length); s.read(data, s.length); - stream s_bin; + memory_stream s_bin; s_bin.open(data, s.length); texture_database_file_classic_read_inner(this, s_bin); - free(data); + free_def(data); } } - free(path_bin); + free_def(path_bin); } else { char* path_txi = str_utils_add(path, ".txi"); @@ -70,13 +71,13 @@ void texture_database_file::read(const char* path, bool modern) { f2_struct st; st.read(path_txi); if (st.header.signature == reverse_endianness_uint32_t('MTXI')) { - stream s_mtxi; + memory_stream s_mtxi; s_mtxi.open(st.data); - s_mtxi.is_big_endian = st.header.use_big_endian; + s_mtxi.big_endian = st.header.use_big_endian; texture_database_file_modern_read_inner(this, s_mtxi, st.header.length); } } - free(path_txi); + free_def(path_txi); } } @@ -87,18 +88,18 @@ void texture_database_file::read(const wchar_t* path, bool modern) { if (!modern) { wchar_t* path_bin = str_utils_add(path, L".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, L"rb"); - if (s.io.stream) { + if (s.check_not_null()) { uint8_t* data = force_malloc_s(uint8_t, s.length); s.read(data, s.length); - stream s_bin; + memory_stream s_bin; s_bin.open(data, s.length); texture_database_file_classic_read_inner(this, s_bin); - free(data); + free_def(data); } } - free(path_bin); + free_def(path_bin); } else { wchar_t* path_txi = str_utils_add(path, L".txi"); @@ -106,13 +107,13 @@ void texture_database_file::read(const wchar_t* path, bool modern) { f2_struct st; st.read(path_txi); if (st.header.signature == reverse_endianness_uint32_t('MTXI')) { - stream s_mtxi; + memory_stream s_mtxi; s_mtxi.open(st.data); - s_mtxi.is_big_endian = st.header.use_big_endian; + s_mtxi.big_endian = st.header.use_big_endian; texture_database_file_modern_read_inner(this, s_mtxi, st.header.length); } } - free(path_txi); + free_def(path_txi); } } @@ -121,7 +122,7 @@ void texture_database_file::read(const void* data, size_t size, bool modern) { return; if (!modern) { - stream s; + memory_stream s; s.open(data, size); texture_database_file_classic_read_inner(this, s); } @@ -129,9 +130,9 @@ void texture_database_file::read(const void* data, size_t size, bool modern) { f2_struct st; st.read(data, size); if (st.header.signature == reverse_endianness_uint32_t('MTXI')) { - stream s_mtxi; + memory_stream s_mtxi; s_mtxi.open(st.data); - s_mtxi.is_big_endian = st.header.use_big_endian; + s_mtxi.big_endian = st.header.use_big_endian; texture_database_file_modern_read_inner(this, s_mtxi, st.header.length); } } @@ -143,19 +144,19 @@ void texture_database_file::write(const char* path) { if (!modern) { char* path_bin = str_utils_add(path, ".bin"); - stream s; + file_stream s; s.open(path_bin, "wb"); - if (s.io.stream) + if (s.check_not_null()) texture_database_file_classic_write_inner(this, s); - free(path_bin); + free_def(path_bin); } else { char* path_txi = str_utils_add(path, ".txi"); - stream s; + file_stream s; s.open(path_txi, "wb"); - if (s.io.stream) + if (s.check_not_null()) texture_database_file_modern_write_inner(this, s); - free(path_txi); + free_def(path_txi); } } @@ -165,19 +166,19 @@ void texture_database_file::write(const wchar_t* path) { if (!modern) { wchar_t* path_bin = str_utils_add(path, L".bin"); - stream s; + file_stream s; s.open(path_bin, L"wb"); - if (s.io.stream) + if (s.check_not_null()) texture_database_file_classic_write_inner(this, s); - free(path_bin); + free_def(path_bin); } else { wchar_t* path_txi = str_utils_add(path, L".txi"); - stream s; + file_stream s; s.open(path_txi, L"wb"); - if (s.io.stream) + if (s.check_not_null()) texture_database_file_modern_write_inner(this, s); - free(path_txi); + free_def(path_txi); } } @@ -185,7 +186,7 @@ void texture_database_file::write(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; + memory_stream s; s.open(); if (!modern) texture_database_file_classic_write_inner(this, s); @@ -283,9 +284,10 @@ static void texture_database_file_classic_read_inner(texture_database_file* tex_ } s.position_pop(); - tex_db->is_x = false; - tex_db->modern = false; tex_db->ready = true; + tex_db->modern = false; + tex_db->big_endian = false; + tex_db->is_x = false; } static void texture_database_file_classic_write_inner(texture_database_file* tex_db, stream& s) { @@ -327,6 +329,7 @@ static void texture_database_file_classic_write_inner(texture_database_file* tex } static void texture_database_file_modern_read_inner(texture_database_file* tex_db, stream& s, uint32_t header_length) { + bool big_endian = s.big_endian; bool is_x = true; s.set_position(0x04, SEEK_SET); @@ -356,31 +359,35 @@ static void texture_database_file_modern_read_inner(texture_database_file* tex_d } s.position_pop(); - tex_db->is_x = is_x; - tex_db->modern = true; tex_db->ready = true; + tex_db->modern = true; + tex_db->big_endian = big_endian; + tex_db->is_x = is_x; } static void texture_database_file_modern_write_inner(texture_database_file* tex_db, stream& s) { - stream s_mtxi; + bool big_endian = tex_db->big_endian; + bool is_x = tex_db->is_x; + + memory_stream s_mtxi; s_mtxi.open(); + s_mtxi.big_endian = big_endian; + uint32_t off; enrs e; enrs_entry ee; pof pof; - bool is_x = tex_db->is_x; - uint32_t textures_count = (uint32_t)tex_db->texture.size(); if (!is_x) { - ee = { 0, 2, 8, textures_count }; - ee.append(0, 9, ENRS_DWORD); + ee = { 0, 1, 8, textures_count }; + ee.append(0, 2, ENRS_DWORD); e.vec.push_back(ee); off = 8; off = align_val(off, 0x10); - ee = { off, 2, 8, textures_count }; + ee = { off, 1, 8, textures_count }; ee.append(0, 2, ENRS_DWORD); e.vec.push_back(ee); off = (uint32_t)(textures_count * 16ULL); @@ -395,7 +402,7 @@ static void texture_database_file_modern_write_inner(texture_database_file* tex_ textures_count--; } - s_mtxi.write_int32_t(0); + s_mtxi.write_int32_t_reverse_endianness(0); s_mtxi.write_offset(0, 0x20, is_x); s_mtxi.align_write(0x10); @@ -403,7 +410,7 @@ static void texture_database_file_modern_write_inner(texture_database_file* tex_ s_mtxi.write(textures_count * (is_x ? 0x10ULL : 0x08ULL)); s_mtxi.align_write(0x10); - std::vector strings; + std::vector strings; std::vector string_offsets; strings.reserve(textures_count); @@ -411,29 +418,29 @@ static void texture_database_file_modern_write_inner(texture_database_file* tex_ for (texture_info_file& i : tex_db->texture) texture_database_file_strings_push_back_check(strings, i.name); - quicksort_string(strings.data(), strings.size()); + quicksort_string_hash(strings.data(), strings.size()); string_offsets.reserve(strings.size()); - for (std::string& i : strings) { + for (string_hash& i : strings) { string_offsets.push_back(s_mtxi.get_position()); - s_mtxi.write_string_null_terminated(i); + s_mtxi.write_string_null_terminated(i.str); } s_mtxi.align_write(0x10); s_mtxi.position_push(0x00, SEEK_SET); - s_mtxi.write_uint32_t(textures_count); + s_mtxi.write_uint32_t_reverse_endianness(textures_count); io_write_offset_pof_add(s_mtxi, textures_offset, 0x20, is_x, &pof); s_mtxi.align_write(0x10); if (!is_x) for (texture_info_file& i : tex_db->texture) { - s_mtxi.write_uint32_t(i.id); + s_mtxi.write_uint32_t_reverse_endianness(i.id); int64_t offset = texture_database_file_strings_get_string_offset(strings, string_offsets, i.name); io_write_offset_f2_pof_add(s_mtxi, offset, 0x20, &pof); } else for (texture_info_file& i : tex_db->texture) { - s_mtxi.write_uint32_t(i.id); + s_mtxi.write_uint32_t_reverse_endianness(i.id); int64_t offset = texture_database_file_strings_get_string_offset(strings, string_offsets, i.name); io_write_offset_x_pof_add(s_mtxi, offset, &pof); @@ -450,23 +457,27 @@ static void texture_database_file_modern_write_inner(texture_database_file* tex_ st.header.signature = reverse_endianness_uint32_t('MTXI'); st.header.length = 0x20; - st.header.use_big_endian = false; + st.header.use_big_endian = big_endian; st.header.use_section_size = true; st.write(s, true, tex_db->is_x); } -inline static int64_t texture_database_file_strings_get_string_offset(std::vector& vec, +inline static int64_t texture_database_file_strings_get_string_offset(std::vector& vec, std::vector& vec_off, std::string& str) { - for (std::string& i : vec) - if (str == i) + uint64_t hash_fnv1a64m = hash_string_fnv1a64m(str); + uint64_t hash_murmurhash = hash_string_murmurhash(str); + for (string_hash& i : vec) + if (hash_fnv1a64m == i.hash_fnv1a64m && hash_murmurhash == i.hash_murmurhash) return vec_off[&i - vec.data()]; return 0; } -inline static void texture_database_file_strings_push_back_check(std::vector& vec, std::string& str) { - for (std::string& i : vec) - if (str == i) +inline static void texture_database_file_strings_push_back_check(std::vector& vec, std::string& str) { + uint64_t hash_fnv1a64m = hash_string_fnv1a64m(str); + uint64_t hash_murmurhash = hash_string_murmurhash(str); + for (string_hash& i : vec) + if (hash_fnv1a64m == i.hash_fnv1a64m && hash_murmurhash == i.hash_murmurhash) return; vec.push_back(str); diff --git a/src/KKdLib/database/texture.hpp b/src/KKdLib/database/texture.hpp index 6df6cabe..84af7f8b 100644 --- a/src/KKdLib/database/texture.hpp +++ b/src/KKdLib/database/texture.hpp @@ -29,6 +29,7 @@ struct texture_info { struct texture_database_file { bool ready; bool modern; + bool big_endian; bool is_x; std::vector texture; diff --git a/src/KKdLib/dds.cpp b/src/KKdLib/dds.cpp index 9935f06e..832824c5 100644 --- a/src/KKdLib/dds.cpp +++ b/src/KKdLib/dds.cpp @@ -4,7 +4,7 @@ */ #include "dds.hpp" -#include "io/stream.hpp" +#include "io/file_stream.hpp" #include "str_utils.hpp" #pragma pack(push, 1) @@ -154,7 +154,7 @@ dds::dds() : format(), width(), height(), mipmaps_count(), has_cube_map() { dds::~dds() { for (void*& i : data) { - free(i); + free_def(i); i = 0; } } @@ -165,7 +165,7 @@ void dds::read( const char* path) { wchar_t* path_buf = utf8_to_utf16(path); read(path_buf); - free(path_buf); + free_def(path_buf); } void dds::read(const wchar_t* path) { @@ -181,9 +181,9 @@ void dds::read(const wchar_t* path) { data.shrink_to_fit(); wchar_t* path_dds = str_utils_add(path, L".dds"); - stream s; + file_stream s; s.open(path_dds, L"rb"); - if (s.io.stream) { + if (s.check_not_null()) { if (s.read_uint32_t_reverse_endianness(true) != DDS_MAGIC) goto End; @@ -268,10 +268,10 @@ void dds::read(const wchar_t* path) { do for (uint32_t i = 0; i < mipmaps_count; i++) { - uint32_t width = max(this->width >> i, 1); - uint32_t height = max(this->height >> i, 1); + uint32_t width = max_def(this->width >> i, 1); + uint32_t height = max_def(this->height >> i, 1); uint32_t size = txp::get_size(format, - max(this->width >> i, 1), max(this->height >> i, 1)); + max_def(this->width >> i, 1), max_def(this->height >> i, 1)); void* data = force_malloc(size); s.read(data, size); if (reverse) @@ -283,7 +283,7 @@ void dds::read(const wchar_t* path) { while (has_cube_map && data.size() / mipmaps_count < 6); } End: - free(path_dds); + free_def(path_dds); } void dds::write(const char* path) { @@ -292,7 +292,7 @@ void dds::write(const char* path) { wchar_t* path_buf = utf8_to_utf16(path); write( path_buf); - free(path_buf); + free_def(path_buf); } void dds::write(const wchar_t* path) { @@ -300,9 +300,9 @@ void dds::write(const wchar_t* path) { return; wchar_t* path_dds = str_utils_add(path, L".dds"); - stream s; + file_stream s; s.open(path_dds, L"wb"); - if (s.io.stream) { + if (s.check_not_null()) { DDS_HEADER dds_h; memset(&dds_h, 0, sizeof(DDS_HEADER)); dds_h.size = sizeof(DDS_HEADER); @@ -373,17 +373,17 @@ void dds::write(const wchar_t* path) { do for (uint32_t i = 0; i < mipmaps_count; i++) { uint32_t size = txp::get_size(format, - max(width >> i, 1), max(height >> i, 1)); + max_def(width >> i, 1), max_def(height >> i, 1)); void* data = force_malloc(size); memcpy(data, this->data[index], size); dds_reverse_rgb(format, size, (uint8_t*)data); s.write(data, size); - free(data); + free_def(data); index++; } while (has_cube_map && index / mipmaps_count < 6); } - free(path_dds); + free_def(path_dds); } static void dds_reverse_rgb(txp_format format, int64_t size, uint8_t* data) { diff --git a/src/KKdLib/default.cpp b/src/KKdLib/default.cpp index 1c0650cf..799ae375 100644 --- a/src/KKdLib/default.cpp +++ b/src/KKdLib/default.cpp @@ -16,214 +16,6 @@ void* force_malloc(size_t size) { return buf; } -inline int16_t load_reverse_endianness_int16_t(const void* ptr) { - return (int16_t)_byteswap_ushort(*(uint16_t*)ptr); -} - -inline uint16_t load_reverse_endianness_uint16_t(const void* ptr) { - return (uint16_t)_byteswap_ushort(*(uint16_t*)ptr); -} - -inline int32_t load_reverse_endianness_int32_t(const void* ptr) { - return (int32_t)_byteswap_ulong(*(uint32_t*)ptr); -} - -inline uint32_t load_reverse_endianness_uint32_t(const void* ptr) { - return (uint32_t)_byteswap_ulong(*(uint32_t*)ptr); -} - -inline int64_t load_reverse_endianness_int64_t(const void* ptr) { - return (int64_t)_byteswap_uint64(*(uint64_t*)ptr); -} - -inline uint64_t load_reverse_endianness_uint64_t(const void* ptr) { - return (uint64_t)_byteswap_uint64(*(uint64_t*)ptr); -} - -inline ssize_t load_reverse_endianness_ssize_t(const void* ptr) { - return (ssize_t)_byteswap_uint64(*(uint64_t*)ptr); -} - -inline size_t load_reverse_endianness_size_t(const void* ptr) { - return (size_t)_byteswap_uint64(*(uint64_t*)ptr); -} - -inline float_t load_reverse_endianness_float_t(const void* ptr) { - uint32_t v = (uint32_t)_byteswap_ulong(*(uint32_t*)ptr); - return *(float_t*)&v; -} - -inline double_t load_reverse_endianness_double_t(const void* ptr) { - uint64_t v = (uint64_t)_byteswap_uint64(*(uint64_t*)ptr); - return *(double_t*)&v; -} - -inline void store_reverse_endianness_int16_t(int16_t value, void* ptr) { - *(int16_t*)ptr = (int16_t)_byteswap_ushort((uint16_t)value); -} - -inline void store_reverse_endianness_int16_t(uint16_t value, void* ptr) { - *(int16_t*)ptr = (int16_t)_byteswap_ushort(value); -} - -inline void store_reverse_endianness_uint16_t(int16_t value, void* ptr) { - *(uint16_t*)ptr = (uint16_t)_byteswap_ushort((uint16_t)value); -} - -inline void store_reverse_endianness_uint16_t(uint16_t value, void* ptr) { - *(uint16_t*)ptr = (uint16_t)_byteswap_ushort(value); -} - -inline void store_reverse_endianness_int32_t(int32_t value, void* ptr) { - *(int32_t*)ptr = (int32_t)_byteswap_ulong((uint32_t)value); -} - -inline void store_reverse_endianness_int32_t(uint32_t value, void* ptr) { - *(int32_t*)ptr = (int32_t)_byteswap_ulong(value); -} - -inline void store_reverse_endianness_uint32_t(int32_t value, void* ptr) { - *(uint32_t*)ptr = (uint32_t)_byteswap_ulong((uint32_t)value); -} - -inline void store_reverse_endianness_uint32_t(uint32_t value, void* ptr) { - *(uint32_t*)ptr = (uint32_t)_byteswap_ulong(value); -} - -inline void store_reverse_endianness_int64_t(int64_t value, void* ptr) { - *(int64_t*)ptr = (int64_t)_byteswap_uint64((uint64_t)value); -} - -inline void store_reverse_endianness_int64_t(uint64_t value, void* ptr) { - *(int64_t*)ptr = (int64_t)_byteswap_uint64(value); -} - -inline void store_reverse_endianness_uint64_t(int64_t value, void* ptr) { - *(uint64_t*)ptr = (uint64_t)_byteswap_uint64((uint64_t)value); -} - -inline void store_reverse_endianness_uint64_t(uint64_t value, void* ptr) { - *(uint64_t*)ptr = (uint64_t)_byteswap_uint64(value); -} - -inline void store_reverse_endianness_ssize_t(ssize_t value, void* ptr) { - *(ssize_t*)ptr = (ssize_t)_byteswap_uint64((uint64_t)value); -} - -inline void store_reverse_endianness_ssize_t(size_t value, void* ptr) { - *(ssize_t*)ptr = (ssize_t)_byteswap_uint64((uint64_t)value); -} - -inline void store_reverse_endianness_size_t(ssize_t value, void* ptr) { - *(size_t*)ptr = (size_t)_byteswap_uint64((uint64_t)value); -} - -inline void store_reverse_endianness_size_t(size_t value, void* ptr) { - *(size_t*)ptr = (size_t)_byteswap_uint64((uint64_t)value); -} - -inline void store_reverse_endianness_float_t(float_t value, void* ptr) { - *(uint32_t*)ptr = (uint32_t)_byteswap_ulong(*(uint32_t*)&value); -} - -inline void store_reverse_endianness_double_t(double_t value, void* ptr) { - *(uint64_t*)ptr = (uint64_t)_byteswap_uint64(*(uint64_t*)&value); -} - -inline int16_t reverse_endianness_int16_t(int16_t value) { - return (int16_t)_byteswap_ushort((uint16_t)value); -} - -inline int16_t reverse_endianness_int16_t(uint16_t value) { - return (int16_t)_byteswap_ushort(value); -} - -inline uint16_t reverse_endianness_uint16_t(int16_t value) { - return (uint16_t)_byteswap_ushort((uint16_t)value); -} - -inline uint16_t reverse_endianness_uint16_t(uint16_t value) { - return (uint16_t)_byteswap_ushort(value); -} - -inline int32_t reverse_endianness_int32_t(int32_t value) { - return (int32_t)_byteswap_ulong((uint32_t)value); -} - -inline int32_t reverse_endianness_int32_t(uint32_t value) { - return (int32_t)_byteswap_ulong(value); -} - -inline uint32_t reverse_endianness_uint32_t(int32_t value) { - return (uint32_t)_byteswap_ulong((uint32_t)value); -} - -inline uint32_t reverse_endianness_uint32_t(uint32_t value) { - return (uint32_t)_byteswap_ulong(value); -} - -inline int64_t reverse_endianness_int64_t(int64_t value) { - return (int64_t)_byteswap_uint64((uint64_t)value); -} - -inline int64_t reverse_endianness_int64_t(uint64_t value) { - return (int64_t)_byteswap_uint64(value); -} - -inline uint64_t reverse_endianness_uint64_t(int64_t value) { - return (uint64_t)_byteswap_uint64((uint64_t)value); -} - -inline uint64_t reverse_endianness_uint64_t(uint64_t value) { - return (uint64_t)_byteswap_uint64(value); -} - -inline ssize_t reverse_endianness_ssize_t(ssize_t value) { - return (ssize_t)_byteswap_uint64((uint64_t)value); -} - -inline ssize_t reverse_endianness_ssize_t(size_t value) { - return (ssize_t)_byteswap_uint64((uint64_t)value); -} - -inline size_t reverse_endianness_size_t(ssize_t value) { - return (size_t)_byteswap_uint64((uint64_t)value); -} - -inline size_t reverse_endianness_size_t(size_t value) { - return (size_t)_byteswap_uint64((uint64_t)value); -} - -inline float_t reverse_endianness_float_t(float_t value) { - uint32_t v = (uint32_t)_byteswap_ulong(*(uint32_t*)&value); - return *(float_t*)&v; -} - -inline double_t reverse_endianness_double_t(double_t value) { - uint64_t v = (uint64_t)_byteswap_uint64(*(uint64_t*)&value); - return *(double_t*)&v; -} - -constexpr size_t utf8_length(const char* s) { - if (!s) - return 0; - - size_t len = 0; - while (*s++) - len++; - return len; -} - -constexpr size_t utf16_length(const wchar_t* s) { - if (!s) - return 0; - - size_t len = 0; - while (*s++) - len++; - return len; -} - wchar_t* utf8_to_utf16(const char* s) { if (!s) return 0; @@ -331,95 +123,6 @@ char* utf16_to_utf8(const wchar_t* s) { return str; } -constexpr bool utf8_check_for_ascii_only(const char* s) { - char c = 0; - while (c = *s++) - if (c & 0x80) - return false; - return true; -} - -constexpr size_t utf8_to_utf16_length(const char* s) { - if (!s) - return 0; - - uint32_t c = 0; - size_t length = 0; - size_t l = 0; - - while (*s) { - char t = *s++; - if (~t & 0x80) { - l = 0; - length++; - c = 0; - continue; - } - else if ((t & 0xFC) == 0xF8) - continue; - else if ((t & 0xF8) == 0xF0) { - c = t & 0x07; - l = 3; - } - else if ((t & 0xF0) == 0xE0) { - c = t & 0x0F; - l = 2; - } - else if ((t & 0xE0) == 0xC0) { - c = t & 0x1F; - l = 1; - } - else if ((t & 0xC0) == 0x80) { - c = (c << 6) | (t & 0x3F); - l--; - } - - if (!l) { - if (c <= 0xD7FF || (c >= 0xE000 && c <= 0xFFFF)) - length++; - else if (c >= 0x10000 && c <= 0x10FFFF) { - length++; - length++; - } - c = 0; - } - } - return length; -} - -constexpr size_t utf16_to_utf8_length(const wchar_t* s) { - uint32_t c = 0; - size_t length = 0; - while (*s) { - c = *s++; - if ((c & 0xFC00) == 0xD800) { - if (!*s) - break; - - wchar_t _c = *s++; - if ((_c & 0xFC00) != 0xDC00) - continue; - - c &= 0x3FF; - c <<= 10; - c |= _c & 0x3FF; - c += 0x10000; - } - else if ((c & 0xFC00) == 0xDC00) - continue; - - if (c <= 0x7F) - length++; - else if (c <= 0x7FF) - length += 2; - else if ((c >= 0x800 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFF)) - length += 3; - else if (c >= 0x10000 && c <= 0x10FFFF) - length += 4; - } - return length; -} - std::wstring utf8_to_utf16(const std::string& s) { if (!s.size()) return {}; diff --git a/src/KKdLib/default.hpp b/src/KKdLib/default.hpp index afdc2be0..ff9de82d 100644 --- a/src/KKdLib/default.hpp +++ b/src/KKdLib/default.hpp @@ -5,6 +5,7 @@ #pragma once +#define NOMINMAX #define _USE_MATH_DEFINES #include "types.hpp" #include @@ -19,7 +20,7 @@ #pragma warning( push ) #pragma warning( disable: 26812 ) -#define free(ptr) \ +#define free_def(ptr) \ { \ if (ptr) \ free(ptr); \ @@ -46,19 +47,15 @@ null(double_t) null(size_t) null(ssize_t) -#ifndef max -#define max(a, b) (((a) > (b)) ? (a) : (b)) -#endif +#define max_def(a, b) (((a) > (b)) ? (a) : (b)) -#ifndef min -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif +#define min_def(a, b) (((a) < (b)) ? (a) : (b)) -#define mult_min_max(a, b, c) (((a) >= 0) ? ((a) * (b)) : ((a) * (c))) +#define mult_min_max_def(a, b, c) (((a) >= 0) ? ((a) * (b)) : ((a) * (c))) -#define div_min_max(a, b, c) (((a) >= 0) ? ((a) / (b)) : ((a) / (c))) +#define div_min_max_def(a, b, c) (((a) >= 0) ? ((a) / (b)) : ((a) / (c))) -#define clamp(a, b, c) (((((a) > (b)) ? (a) : (b)) < (c)) ? (((a) > (b)) ? (a) : (b)) : (c)) +#define clamp_def(a, b, c) (((((a) > (b)) ? (a) : (b)) < (c)) ? (((a) > (b)) ? (a) : (b)) : (c)) #define align_val(a, b) ((((a) + (b) - 1) / (b)) * (b)) @@ -90,7 +87,7 @@ null(ssize_t) #define actgh(x) (1.0 / atanh(x)) -#define lerp(x, y, blend) ((1.0f - (blend)) * (x) + (blend) * (y)) +#define lerp_def(x, y, blend) ((1.0f - (blend)) * (x) + (blend) * (y)) extern void* force_malloc(size_t size); #define force_malloc_s(s, size) (s*)force_malloc(sizeof(s) * (size)) @@ -107,59 +104,304 @@ extern void* force_malloc(size_t size); #define enum_not(s0, s1) \ (s0) = (decltype(s0))(~(int32_t)(s0)) -extern int16_t load_reverse_endianness_int16_t(const void* ptr); -extern uint16_t load_reverse_endianness_uint16_t(const void* ptr); -extern int32_t load_reverse_endianness_int32_t(const void* ptr); -extern uint32_t load_reverse_endianness_uint32_t(const void* ptr); -extern int64_t load_reverse_endianness_int64_t(const void* ptr); -extern uint64_t load_reverse_endianness_uint64_t(const void* ptr); -extern ssize_t load_reverse_endianness_ssize_t(const void* ptr); -extern size_t load_reverse_endianness_size_t(const void* ptr); -extern float_t load_reverse_endianness_float_t(const void* ptr); -extern double_t load_reverse_endianness_double_t(const void* ptr); -extern void store_reverse_endianness_int16_t(int16_t value, void* ptr); -extern void store_reverse_endianness_int16_t(uint16_t value, void* ptr); -extern void store_reverse_endianness_uint16_t(int16_t value, void* ptr); -extern void store_reverse_endianness_uint16_t(uint16_t value, void* ptr); -extern void store_reverse_endianness_int32_t(int32_t value, void* ptr); -extern void store_reverse_endianness_int32_t(uint32_t value, void* ptr); -extern void store_reverse_endianness_uint32_t(int32_t value, void* ptr); -extern void store_reverse_endianness_uint32_t(uint32_t value, void* ptr); -extern void store_reverse_endianness_int64_t(int64_t value, void* ptr); -extern void store_reverse_endianness_int64_t(uint64_t value, void* ptr); -extern void store_reverse_endianness_uint64_t(int64_t value, void* ptr); -extern void store_reverse_endianness_uint64_t(uint64_t value, void* ptr); -extern void store_reverse_endianness_ssize_t(ssize_t value, void* ptr); -extern void store_reverse_endianness_ssize_t(size_t value, void* ptr); -extern void store_reverse_endianness_size_t(ssize_t value, void* ptr); -extern void store_reverse_endianness_size_t(size_t value, void* ptr); -extern void store_reverse_endianness_float_t(float_t value, void* ptr); -extern void store_reverse_endianness_double_t(double_t value, void* ptr); -extern int16_t reverse_endianness_int16_t(int16_t value); -extern int16_t reverse_endianness_int16_t(uint16_t value); -extern uint16_t reverse_endianness_uint16_t(int16_t value); -extern uint16_t reverse_endianness_uint16_t(uint16_t value); -extern int32_t reverse_endianness_int32_t(int32_t value); -extern int32_t reverse_endianness_int32_t(uint32_t value); -extern uint32_t reverse_endianness_uint32_t(int32_t value); -extern uint32_t reverse_endianness_uint32_t(uint32_t value); -extern int64_t reverse_endianness_int64_t(int64_t value); -extern int64_t reverse_endianness_int64_t(uint64_t value); -extern uint64_t reverse_endianness_uint64_t(int64_t value); -extern uint64_t reverse_endianness_uint64_t(uint64_t value); -extern ssize_t reverse_endianness_ssize_t(ssize_t value); -extern ssize_t reverse_endianness_ssize_t(size_t value); -extern size_t reverse_endianness_size_t(ssize_t value); -extern size_t reverse_endianness_size_t(size_t value); -extern float_t reverse_endianness_float_t(float_t value); -extern double_t reverse_endianness_double_t(double_t value); +inline int16_t load_reverse_endianness_int16_t(const void* ptr) { + return (int16_t)_byteswap_ushort(*(uint16_t*)ptr); +} + +inline uint16_t load_reverse_endianness_uint16_t(const void* ptr) { + return (uint16_t)_byteswap_ushort(*(uint16_t*)ptr); +} + +inline int32_t load_reverse_endianness_int32_t(const void* ptr) { + return (int32_t)_byteswap_ulong(*(uint32_t*)ptr); +} + +inline uint32_t load_reverse_endianness_uint32_t(const void* ptr) { + return (uint32_t)_byteswap_ulong(*(uint32_t*)ptr); +} + +inline int64_t load_reverse_endianness_int64_t(const void* ptr) { + return (int64_t)_byteswap_uint64(*(uint64_t*)ptr); +} + +inline uint64_t load_reverse_endianness_uint64_t(const void* ptr) { + return (uint64_t)_byteswap_uint64(*(uint64_t*)ptr); +} + +inline ssize_t load_reverse_endianness_ssize_t(const void* ptr) { + return (ssize_t)_byteswap_uint64(*(uint64_t*)ptr); +} + +inline size_t load_reverse_endianness_size_t(const void* ptr) { + return (size_t)_byteswap_uint64(*(uint64_t*)ptr); +} + +inline float_t load_reverse_endianness_float_t(const void* ptr) { + uint32_t v = (uint32_t)_byteswap_ulong(*(uint32_t*)ptr); + return *(float_t*)&v; +} + +inline double_t load_reverse_endianness_double_t(const void* ptr) { + uint64_t v = (uint64_t)_byteswap_uint64(*(uint64_t*)ptr); + return *(double_t*)&v; +} + +inline void store_reverse_endianness_int16_t(void* ptr, int16_t value) { + *(int16_t*)ptr = (int16_t)_byteswap_ushort((uint16_t)value); +} + +inline void store_reverse_endianness_int16_t(void* ptr, uint16_t value) { + *(int16_t*)ptr = (int16_t)_byteswap_ushort(value); +} + +inline void store_reverse_endianness_uint16_t(void* ptr, int16_t value) { + *(uint16_t*)ptr = (uint16_t)_byteswap_ushort((uint16_t)value); +} + +inline void store_reverse_endianness_uint16_t(void* ptr, uint16_t value) { + *(uint16_t*)ptr = (uint16_t)_byteswap_ushort(value); +} + +inline void store_reverse_endianness_int32_t(void* ptr, int32_t value) { + *(int32_t*)ptr = (int32_t)_byteswap_ulong((uint32_t)value); +} + +inline void store_reverse_endianness_int32_t(void* ptr, uint32_t value) { + *(int32_t*)ptr = (int32_t)_byteswap_ulong(value); +} + +inline void store_reverse_endianness_uint32_t(void* ptr, int32_t value) { + *(uint32_t*)ptr = (uint32_t)_byteswap_ulong((uint32_t)value); +} + +inline void store_reverse_endianness_uint32_t(void* ptr, uint32_t value) { + *(uint32_t*)ptr = (uint32_t)_byteswap_ulong(value); +} + +inline void store_reverse_endianness_int64_t(void* ptr, int64_t value) { + *(int64_t*)ptr = (int64_t)_byteswap_uint64((uint64_t)value); +} + +inline void store_reverse_endianness_int64_t(void* ptr, uint64_t value) { + *(int64_t*)ptr = (int64_t)_byteswap_uint64(value); +} + +inline void store_reverse_endianness_uint64_t(void* ptr, int64_t value) { + *(uint64_t*)ptr = (uint64_t)_byteswap_uint64((uint64_t)value); +} + +inline void store_reverse_endianness_uint64_t(void* ptr, uint64_t value) { + *(uint64_t*)ptr = (uint64_t)_byteswap_uint64(value); +} + +inline void store_reverse_endianness_ssize_t(void* ptr, ssize_t value) { + *(ssize_t*)ptr = (ssize_t)_byteswap_uint64((uint64_t)value); +} + +inline void store_reverse_endianness_ssize_t(void* ptr, size_t value) { + *(ssize_t*)ptr = (ssize_t)_byteswap_uint64((uint64_t)value); +} + +inline void store_reverse_endianness_size_t(void* ptr, ssize_t value) { + *(size_t*)ptr = (size_t)_byteswap_uint64((uint64_t)value); +} + +inline void store_reverse_endianness_size_t(void* ptr, size_t value) { + *(size_t*)ptr = (size_t)_byteswap_uint64((uint64_t)value); +} + +inline void store_reverse_endianness_float_t(void* ptr, float_t value) { + *(uint32_t*)ptr = (uint32_t)_byteswap_ulong(*(uint32_t*)&value); +} + +inline void store_reverse_endianness_double_t(void* ptr, double_t value) { + *(uint64_t*)ptr = (uint64_t)_byteswap_uint64(*(uint64_t*)&value); +} + +inline int16_t reverse_endianness_int16_t(int16_t value) { + return (int16_t)_byteswap_ushort((uint16_t)value); +} + +inline int16_t reverse_endianness_int16_t(uint16_t value) { + return (int16_t)_byteswap_ushort(value); +} + +inline uint16_t reverse_endianness_uint16_t(int16_t value) { + return (uint16_t)_byteswap_ushort((uint16_t)value); +} + +inline uint16_t reverse_endianness_uint16_t(uint16_t value) { + return (uint16_t)_byteswap_ushort(value); +} + +inline int32_t reverse_endianness_int32_t(int32_t value) { + return (int32_t)_byteswap_ulong((uint32_t)value); +} + +inline int32_t reverse_endianness_int32_t(uint32_t value) { + return (int32_t)_byteswap_ulong(value); +} + +inline uint32_t reverse_endianness_uint32_t(int32_t value) { + return (uint32_t)_byteswap_ulong((uint32_t)value); +} + +inline uint32_t reverse_endianness_uint32_t(uint32_t value) { + return (uint32_t)_byteswap_ulong(value); +} + +inline int64_t reverse_endianness_int64_t(int64_t value) { + return (int64_t)_byteswap_uint64((uint64_t)value); +} + +inline int64_t reverse_endianness_int64_t(uint64_t value) { + return (int64_t)_byteswap_uint64(value); +} + +inline uint64_t reverse_endianness_uint64_t(int64_t value) { + return (uint64_t)_byteswap_uint64((uint64_t)value); +} + +inline uint64_t reverse_endianness_uint64_t(uint64_t value) { + return (uint64_t)_byteswap_uint64(value); +} + +inline ssize_t reverse_endianness_ssize_t(ssize_t value) { + return (ssize_t)_byteswap_uint64((uint64_t)value); +} + +inline ssize_t reverse_endianness_ssize_t(size_t value) { + return (ssize_t)_byteswap_uint64((uint64_t)value); +} + +inline size_t reverse_endianness_size_t(ssize_t value) { + return (size_t)_byteswap_uint64((uint64_t)value); +} + +inline size_t reverse_endianness_size_t(size_t value) { + return (size_t)_byteswap_uint64((uint64_t)value); +} + +inline float_t reverse_endianness_float_t(float_t value) { + uint32_t v = (uint32_t)_byteswap_ulong(*(uint32_t*)&value); + return *(float_t*)&v; +} + +inline double_t reverse_endianness_double_t(double_t value) { + uint64_t v = (uint64_t)_byteswap_uint64(*(uint64_t*)&value); + return *(double_t*)&v; +} + +inline constexpr size_t utf8_length(const char* s) { + if (!s) + return 0; + + size_t len = 0; + while (*s++) + len++; + return len; +} + +inline constexpr size_t utf16_length(const wchar_t* s) { + if (!s) + return 0; + + size_t len = 0; + while (*s++) + len++; + return len; +} + +inline constexpr bool utf8_check_for_ascii_only(const char* s) { + char c = 0; + while (c = *s++) + if (c & 0x80) + return false; + return true; +} + +inline constexpr size_t utf8_to_utf16_length(const char* s) { + if (!s) + return 0; + + uint32_t c = 0; + size_t length = 0; + size_t l = 0; + + while (*s) { + char t = *s++; + if (~t & 0x80) { + l = 0; + length++; + c = 0; + continue; + } + else if ((t & 0xFC) == 0xF8) + continue; + else if ((t & 0xF8) == 0xF0) { + c = t & 0x07; + l = 3; + } + else if ((t & 0xF0) == 0xE0) { + c = t & 0x0F; + l = 2; + } + else if ((t & 0xE0) == 0xC0) { + c = t & 0x1F; + l = 1; + } + else if ((t & 0xC0) == 0x80) { + c = (c << 6) | (t & 0x3F); + l--; + } + + if (!l) { + if (c <= 0xD7FF || (c >= 0xE000 && c <= 0xFFFF)) + length++; + else if (c >= 0x10000 && c <= 0x10FFFF) { + length++; + length++; + } + c = 0; + } + } + return length; +} + +inline constexpr size_t utf16_to_utf8_length(const wchar_t* s) { + uint32_t c = 0; + size_t length = 0; + while (*s) { + c = *s++; + if ((c & 0xFC00) == 0xD800) { + if (!*s) + break; + + wchar_t _c = *s++; + if ((_c & 0xFC00) != 0xDC00) + continue; + + c &= 0x3FF; + c <<= 10; + c |= _c & 0x3FF; + c += 0x10000; + } + else if ((c & 0xFC00) == 0xDC00) + continue; + + if (c <= 0x7F) + length++; + else if (c <= 0x7FF) + length += 2; + else if ((c >= 0x800 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFF)) + length += 3; + else if (c >= 0x10000 && c <= 0x10FFFF) + length += 4; + } + return length; +} -extern constexpr size_t utf8_length(const char* s); -extern constexpr size_t utf16_length(const wchar_t* s); extern wchar_t* utf8_to_utf16(const char* s); extern char* utf16_to_utf8(const wchar_t* s); -extern constexpr bool utf8_check_for_ascii_only(const char* s); -extern constexpr size_t utf8_to_utf16_length(const char* s); -extern constexpr size_t utf16_to_utf8_length(const wchar_t* s); extern std::wstring utf8_to_utf16(const std::string& s); extern std::string utf16_to_utf8(const std::wstring& s); diff --git a/src/KKdLib/deflate.cpp b/src/KKdLib/deflate.cpp index 20176df5..24c95078 100644 --- a/src/KKdLib/deflate.cpp +++ b/src/KKdLib/deflate.cpp @@ -34,6 +34,37 @@ namespace deflate { return result >= 0 ? result : result - 0x10; } + int32_t compress_gzip(const void* src, size_t src_length, void** dst, + size_t* dst_length, int32_t compression_level, const char* file_name) { + if (!src_length) + return -1; + else if (!src) + return -2; + else if (!dst) + return -3; + else if (!dst_length) + return -4; + + struct libdeflate_compressor* c = libdeflate_alloc_compressor(compression_level); + if (!c) + return -5; + + int32_t result = compress_static(c, src, src_length, dst, dst_length, compression_level, MODE_GZIP); + libdeflate_free_compressor(c); + if (result < 0) + return result - 0x10; + + size_t file_name_length = utf8_length(file_name); + void* temp = force_malloc(*dst_length + file_name_length + 1); + size_t t = (size_t)temp; + size_t d = (size_t)*dst; + memcpy((void*)t, (void*)d, 0x0A); + memcpy((void*)(t + 0x0A), file_name, file_name_length + 1); + memcpy((void*)(t + 0x0A + file_name_length + 1), (void*)(d + 0x0A), *dst_length - 0x0A); + ((uint8_t*)t)[0x03] |= 0x08; + return result; + } + int32_t decompress(const void* src, size_t src_length, void** dst, size_t* dst_length, mode mode) { if (!src_length) @@ -69,6 +100,7 @@ namespace deflate { dst_max_length = libdeflate_deflate_compress_bound(c, src_length); break; } + *dst = force_malloc(dst_max_length); if (!*dst) return -1; @@ -93,12 +125,12 @@ namespace deflate { void* temp = force_malloc(dst_act_length); if (!temp) { - free(*dst); + free_def(*dst); return -2; } memcpy(temp, *dst, dst_act_length); - free(*dst); + free_def(*dst); *dst = temp; *dst_length = dst_act_length; return 0; @@ -126,11 +158,11 @@ namespace deflate { switch (result) { case LIBDEFLATE_BAD_DATA: - free(*dst); + free_def(*dst); return -2; break; case LIBDEFLATE_INSUFFICIENT_SPACE: - free(*dst); + free_def(*dst); *dst_length *= 2; decompress_static(d, src, src_length, dst, dst_length, mode); break; @@ -140,12 +172,12 @@ namespace deflate { void* temp = force_malloc(dst_act_length); if (!temp) { - free(*dst); + free_def(*dst); return -3; } memcpy(temp, *dst, dst_act_length); - free(*dst); + free_def(*dst); *dst = temp; *dst_length = dst_act_length; break; diff --git a/src/KKdLib/deflate.hpp b/src/KKdLib/deflate.hpp index c63f892f..e62904b4 100644 --- a/src/KKdLib/deflate.hpp +++ b/src/KKdLib/deflate.hpp @@ -16,6 +16,8 @@ namespace deflate { extern int32_t compress(const void* src, size_t src_length, void** dst, size_t* dst_length, int32_t compression_level, mode mode); + extern int32_t compress_gzip(const void* src, size_t src_length, void** dst, + size_t* dst_length, int32_t compression_level, const char* file_name = 0); extern int32_t decompress(const void* src, size_t src_length, void** dst, size_t* dst_length, mode mode); } diff --git a/src/KKdLib/divafile.cpp b/src/KKdLib/divafile.cpp index 2aa2d987..3802ed9c 100644 --- a/src/KKdLib/divafile.cpp +++ b/src/KKdLib/divafile.cpp @@ -4,6 +4,7 @@ */ #include "divafile.hpp" +#include "io/file_stream.hpp" #include "aes.hpp" #include "str_utils.hpp" @@ -16,14 +17,14 @@ namespace divafile { void decrypt(const char* path) { wchar_t* file_buf = utf8_to_utf16(path); decrypt(file_buf); - free(file_buf); + free_def(file_buf); } void decrypt(const wchar_t* path) { wchar_t* file_temp = str_utils_add(path, L"_dec"); - stream s_enc; + file_stream s_enc; s_enc.open(path, L"rb"); - if (s_enc.io.stream) { + if (s_enc.check_not_null()) { uint64_t signature = s_enc.read_uint64_t(); if (signature == 0x454C494641564944) { uint32_t stream_length = s_enc.read_uint32_t(); @@ -35,13 +36,13 @@ namespace divafile { aes128_init_ctx(&ctx, key); aes128_ecb_decrypt_buffer(&ctx, (uint8_t*)data, stream_length); - stream s_dec; + file_stream s_dec; s_dec.open(file_temp, L"wb"); - s_dec.write(data, min(file_length, stream_length)); - free(data); + s_dec.write(data, min_def(file_length, stream_length)); + free_def(data); } } - free(file_temp); + free_def(file_temp); } void decrypt(void* enc_data, void** dec_data, size_t* dec_size) { @@ -70,38 +71,46 @@ namespace divafile { *dec_size = file_length; } - void decrypt(stream& s) { - size_t pos = s.get_position(); - uint64_t signature = s.read_uint64_t(); + void decrypt(stream& enc, memory_stream& dec) { + size_t pos = enc.get_position(); + uint64_t signature = enc.read_uint64_t(); if (signature != 0x454C494641564944) { - s.set_position(pos, SEEK_SET); + std::vector data; + enc.set_position(0, SEEK_SET); + int64_t length = enc.get_length(); + data.resize(length); + enc.read(data.data(), length); + enc.set_position(pos, SEEK_SET); + dec.open(data); return; } - uint32_t stream_length = s.read_uint32_t(); - uint32_t file_length = s.read_uint32_t(); + uint32_t stream_length = enc.read_uint32_t(); + uint32_t file_length = enc.read_uint32_t(); void* data = force_malloc(stream_length); - s.read(data, stream_length); + enc.read(data, stream_length); aes128_ctx ctx; aes128_init_ctx(&ctx, key); aes128_ecb_decrypt_buffer(&ctx, (uint8_t*)data, stream_length); - s.open(data, file_length); - free(data); + dec.open(data, file_length); + free_def(data); + } + void decrypt(memory_stream& s) { } void encrypt(const char* path) { wchar_t* file_buf = utf8_to_utf16(path); encrypt(file_buf); - free(file_buf); + free_def(file_buf); } void encrypt(const wchar_t* path) { wchar_t* file_temp = str_utils_add(path, L"_enc"); - stream s_dec; + file_stream s_dec; s_dec.open(path, L"rb"); - if (s_dec.io.stream) { + if (s_dec.check_not_null()) { size_t len = s_dec.length; size_t len_align = align_val(len, 0x10); @@ -112,15 +121,15 @@ namespace divafile { aes128_init_ctx(&ctx, key); aes128_ecb_encrypt_buffer(&ctx, (uint8_t*)data, len_align); - stream s_enc; + file_stream s_enc; s_enc.open(file_temp, L"wb"); s_enc.write_uint64_t(0x454C494641564944); s_enc.write_uint32_t((uint32_t)len_align); s_enc.write_uint32_t((uint32_t)len); s_enc.write(data, len_align); - free(data); + free_def(data); } - free(file_temp); + free_def(file_temp); } void encrypt(void* dec_data, size_t dec_size, void** enc_data, size_t* enc_size) { diff --git a/src/KKdLib/divafile.hpp b/src/KKdLib/divafile.hpp index debe1ea3..005df9bd 100644 --- a/src/KKdLib/divafile.hpp +++ b/src/KKdLib/divafile.hpp @@ -6,13 +6,13 @@ #pragma once #include "default.hpp" -#include "io/stream.hpp" +#include "io/memory_stream.hpp" namespace divafile { extern void decrypt(const char* path); extern void decrypt(const wchar_t* path); extern void decrypt(void* enc_data, void** dec_data, size_t* dec_size); - extern void decrypt(stream& s); + extern void decrypt(stream& enc, memory_stream& dec); extern void encrypt(const char* path); extern void encrypt(const wchar_t* path); extern void encrypt(void* dec_data, size_t dec_size, void** enc_data, size_t* enc_size); diff --git a/src/KKdLib/dsc.cpp b/src/KKdLib/dsc.cpp index 39cbc6ed..84b879f2 100644 --- a/src/KKdLib/dsc.cpp +++ b/src/KKdLib/dsc.cpp @@ -1,812 +1,813 @@ -/* +/* by korenkonder GitHub/GitLab: korenkonder */ #include "dsc.hpp" #include "f2/struct.hpp" +#include "io/file_stream.hpp" #include "hash.hpp" #include "sort.hpp" #include "str_utils.hpp" static const dsc_func dsc_ac101_func[] = { - { 0, 0, "END" }, - { 1, 1, "TIME" }, - { 2, 3, "MIKU_MOVE" }, - { 3, 1, "MIKU_ROT" }, - { 4, 1, "MIKU_DISP" }, - { 5, 1, "MIKU_SHADOW" }, - { 6, 7, "TARGET" }, - { 7, 3, "SET_MOTION" }, - { 8, 1, "SET_PLAYDATA" }, - { 9, 5, "EFFECT" }, - { 10, 2, "FADEIN_FIELD" }, - { 11, 1, "EFFECT_OFF" }, - { 12, 6, "SET_CAMERA" }, - { 13, 2, "DATA_CAMERA" }, - { 14, 1, "CHANGE_FIELD" }, - { 15, 1, "HIDE_FIELD" }, - { 16, 3, "MOVE_FIELD" }, - { 17, 2, "FADEOUT_FIELD" }, - { 18, 2, "EYE_ANIM" }, - { 19, 3, "MOUTH_ANIM" }, - { 20, 4, "HAND_ANIM" }, - { 21, 3, "LOOK_ANIM" }, - { 22, 3, "EXPRESSION" }, - { 23, 4, "LOOK_CAMERA" }, - { 24, 1, "LYRIC" }, - { 25, 0, "MUSIC_PLAY" }, - { 26, 1, "MODE_SELECT" }, - { 27, 2, "EDIT_MOTION" }, - { 28, 2, "BAR_TIME_SET" }, - { 29, 1, "SHADOWHEIGHT" }, - { 30, 2, "EDIT_FACE" }, - { 31, 19, "MOVE_CAMERA" }, - { 32, 0, "PV_END" }, - { 33, 2, "SHADOWPOS" }, - { 34, 2, "NEAR_CLIP" }, - { 35, 1, "CLOTH_WET" }, - { 36, 6, "SCENE_FADE" }, // AC110 - { 37, 6, "TONE_TRANS" }, // AC120 - { 38, 1, "SATURATE" }, - { 39, 1, "FADE_MODE" }, + { 0, 0, u8"END" }, + { 1, 1, u8"TIME" }, + { 2, 3, u8"MIKU_MOVE" }, + { 3, 1, u8"MIKU_ROT" }, + { 4, 1, u8"MIKU_DISP" }, + { 5, 1, u8"MIKU_SHADOW" }, + { 6, 7, u8"TARGET" }, + { 7, 3, u8"SET_MOTION" }, + { 8, 1, u8"SET_PLAYDATA" }, + { 9, 5, u8"EFFECT" }, + { 10, 2, u8"FADEIN_FIELD" }, + { 11, 1, u8"EFFECT_OFF" }, + { 12, 6, u8"SET_CAMERA" }, + { 13, 2, u8"DATA_CAMERA" }, + { 14, 1, u8"CHANGE_FIELD" }, + { 15, 1, u8"HIDE_FIELD" }, + { 16, 3, u8"MOVE_FIELD" }, + { 17, 2, u8"FADEOUT_FIELD" }, + { 18, 2, u8"EYE_ANIM" }, + { 19, 3, u8"MOUTH_ANIM" }, + { 20, 4, u8"HAND_ANIM" }, + { 21, 3, u8"LOOK_ANIM" }, + { 22, 3, u8"EXPRESSION" }, + { 23, 4, u8"LOOK_CAMERA" }, + { 24, 1, u8"LYRIC" }, + { 25, 0, u8"MUSIC_PLAY" }, + { 26, 1, u8"MODE_SELECT" }, + { 27, 2, u8"EDIT_MOTION" }, + { 28, 2, u8"BAR_TIME_SET" }, + { 29, 1, u8"SHADOWHEIGHT" }, + { 30, 2, u8"EDIT_FACE" }, + { 31, 19, u8"MOVE_CAMERA" }, + { 32, 0, u8"PV_END" }, + { 33, 2, u8"SHADOWPOS" }, + { 34, 2, u8"NEAR_CLIP" }, + { 35, 1, u8"CLOTH_WET" }, + { 36, 6, u8"SCENE_FADE" }, // AC110 + { 37, 6, u8"TONE_TRANS" }, // AC120 + { 38, 1, u8"SATURATE" }, + { 39, 1, u8"FADE_MODE" }, }; static const dsc_func_ac dsc_ac_func[] = { - { 0, 0, 0, "END" }, - { 1, 1, 1, "TIME" }, - { 2, 3, 4, "MIKU_MOVE" }, - { 3, 1, 2, "MIKU_ROT" }, - { 4, 1, 2, "MIKU_DISP" }, - { 5, 1, 2, "MIKU_SHADOW" }, - { 6, 7, 7, "TARGET" }, - { 7, 3, 4, "SET_MOTION" }, - { 8, 1, 2, "SET_PLAYDATA" }, - { 9, 5, 6, "EFFECT" }, - { 10, 2, 2, "FADEIN_FIELD" }, - { 11, 1, 1, "EFFECT_OFF" }, - { 12, 6, 6, "SET_CAMERA" }, - { 13, 2, 2, "DATA_CAMERA" }, - { 14, 1, 1, "CHANGE_FIELD" }, - { 15, 1, 1, "HIDE_FIELD" }, - { 16, 3, 3, "MOVE_FIELD" }, - { 17, 2, 2, "FADEOUT_FIELD" }, - { 18, 2, 3, "EYE_ANIM" }, - { 19, 3, 5, "MOUTH_ANIM" }, - { 20, 4, 5, "HAND_ANIM" }, - { 21, 3, 4, "LOOK_ANIM" }, - { 22, 3, 4, "EXPRESSION" }, - { 23, 4, 5, "LOOK_CAMERA" }, - { 24, 1, 2, "LYRIC" }, - { 25, 0, 0, "MUSIC_PLAY" }, - { 26, 1, 2, "MODE_SELECT" }, - { 27, 2, 4, "EDIT_MOTION" }, - { 28, 2, 2, "BAR_TIME_SET" }, - { 29, 1, 2, "SHADOWHEIGHT" }, - { 30, 2, 1, "EDIT_FACE" }, - { 31, 19, 21, "MOVE_CAMERA" }, - { 32, 0, 0, "PV_END" }, - { 33, 2, 3, "SHADOWPOS" }, - { 34, 2, 2, "EDIT_LYRIC" }, - { 35, 5, 5, "EDIT_TARGET" }, - { 36, 1, 1, "EDIT_MOUTH" }, - { 37, 1, 1, "SET_CHARA" }, - { 38, 7, 7, "EDIT_MOVE" }, - { 39, 1, 1, "EDIT_SHADOW" }, - { 40, 1, 1, "EDIT_EYELID" }, - { 41, 2, 2, "EDIT_EYE" }, - { 42, 1, 1, "EDIT_ITEM" }, - { 43, 2, 2, "EDIT_EFFECT" }, - { 44, 1, 1, "EDIT_DISP" }, - { 45, 2, 2, "EDIT_HAND_ANIM" }, - { 46, 3, 3, "AIM" }, - { 47, 3, 3, "HAND_ITEM" }, - { 48, 1, 1, "EDIT_BLUSH" }, - { 49, 2, 2, "NEAR_CLIP" }, - { 50, 1, 2, "CLOTH_WET" }, - { 51, 3, 3, "LIGHT_ROT" }, - { 52, 6, 6, "SCENE_FADE" }, - { 53, 6, 6, "TONE_TRANS" }, - { 54, 1, 1, "SATURATE" }, - { 55, 1, 1, "FADE_MODE" }, - { 56, 2, 2, "AUTO_BLINK" }, - { 57, 3, 3, "PARTS_DISP" }, - { 58, 1, 1, "TARGET_FLYING_TIME" }, // AC210 - { 59, 2, 2, "CHARA_SIZE" }, - { 60, 2, 2, "CHARA_HEIGHT_ADJUST" }, - { 61, 4, 4, "ITEM_ANIM" }, - { 62, 4, 4, "CHARA_POS_ADJUST" }, - { 63, 1, 1, "SCENE_ROT" }, - { 64, 2, 2, "EDIT_MOT_SMOOTH_LEN" }, // AC500 - { 65, 1, 1, "PV_BRANCH_MODE" }, // AC510 - { 66, 2, 2, "DATA_CAMERA_START" }, - { 67, 1, 1, "MOVIE_PLAY" }, - { 68, 1, 1, "MOVIE_DISP" }, - { 69, 3, 3, "WIND" }, - { 70, 3, 3, "OSAGE_STEP" }, - { 71, 3, 3, "OSAGE_MV_CCL" }, - { 72, 2, 2, "CHARA_COLOR" }, - { 73, 1, 1, "SE_EFFECT" }, - { 74, 9, 9, "EDIT_MOVE_XYZ" }, - { 75, 3, 3, "EDIT_EYELID_ANIM" }, - { 76, 2, 2, "EDIT_INSTRUMENT_ITEM" }, - { 77, 4, 4, "EDIT_MOTION_LOOP" }, - { 78, 2, 2, "EDIT_EXPRESSION" }, - { 79, 3, 3, "EDIT_EYE_ANIM" }, - { 80, 2, 2, "EDIT_MOUTH_ANIM" }, - { 81, 24, 24, "EDIT_CAMERA" }, - { 82, 1, 1, "EDIT_MODE_SELECT" }, - { 83, 2, 2, "PV_END_FADEOUT" }, - { 84, 1, 1, "TARGET_FLAG" }, - { 85, 3, 3, "ITEM_ANIM_ATTACH" }, - { 86, 1, 1, "SHADOW_RANGE" }, - { 87, 3, 3, "HAND_SCALE" }, // AFT101 - { 88, 4, 4, "LIGHT_POS" }, - { 89, 1, 1, "FACE_TYPE" }, // AFT200 - { 90, 2, 2, "SHADOW_CAST" }, // AFT300 - { 91, 6, 6, "EDIT_MOTION_F" }, // AFT310 - { 92, 3, 3, "FOG" }, // AFT410 - { 93, 2, 2, "BLOOM" }, - { 94, 3, 3, "COLOR_COLLE" }, - { 95, 3, 3, "DOF" }, - { 96, 4, 4, "CHARA_ALPHA" }, - { 97, 1, 1, "AOTO_CAP" }, - { 98, 1, 1, "MAN_CAP" }, - { 99, 3, 3, "TOON" }, - { 100, 3, 3, "SHIMMER" }, - { 101, 4, 4, "ITEM_ALPHA" }, - { 102, 1, 1, "MOVIE_CUT_CHG" }, - { 103, 3, 3, "CHARA_LIGHT" }, - { 104, 3, 3, "STAGE_LIGHT" }, - { 105, 8, 8, "AGEAGE_CTR" }, // AFT701 - { 106, 2, 2, "PSE" }, // FT + { 0, 0, 0, u8"END" }, + { 1, 1, 1, u8"TIME" }, + { 2, 3, 4, u8"MIKU_MOVE" }, + { 3, 1, 2, u8"MIKU_ROT" }, + { 4, 1, 2, u8"MIKU_DISP" }, + { 5, 1, 2, u8"MIKU_SHADOW" }, + { 6, 7, 7, u8"TARGET" }, + { 7, 3, 4, u8"SET_MOTION" }, + { 8, 1, 2, u8"SET_PLAYDATA" }, + { 9, 5, 6, u8"EFFECT" }, + { 10, 2, 2, u8"FADEIN_FIELD" }, + { 11, 1, 1, u8"EFFECT_OFF" }, + { 12, 6, 6, u8"SET_CAMERA" }, + { 13, 2, 2, u8"DATA_CAMERA" }, + { 14, 1, 1, u8"CHANGE_FIELD" }, + { 15, 1, 1, u8"HIDE_FIELD" }, + { 16, 3, 3, u8"MOVE_FIELD" }, + { 17, 2, 2, u8"FADEOUT_FIELD" }, + { 18, 2, 3, u8"EYE_ANIM" }, + { 19, 3, 5, u8"MOUTH_ANIM" }, + { 20, 4, 5, u8"HAND_ANIM" }, + { 21, 3, 4, u8"LOOK_ANIM" }, + { 22, 3, 4, u8"EXPRESSION" }, + { 23, 4, 5, u8"LOOK_CAMERA" }, + { 24, 1, 2, u8"LYRIC" }, + { 25, 0, 0, u8"MUSIC_PLAY" }, + { 26, 1, 2, u8"MODE_SELECT" }, + { 27, 2, 4, u8"EDIT_MOTION" }, + { 28, 2, 2, u8"BAR_TIME_SET" }, + { 29, 1, 2, u8"SHADOWHEIGHT" }, + { 30, 2, 1, u8"EDIT_FACE" }, + { 31, 19, 21, u8"MOVE_CAMERA" }, + { 32, 0, 0, u8"PV_END" }, + { 33, 2, 3, u8"SHADOWPOS" }, + { 34, 2, 2, u8"EDIT_LYRIC" }, + { 35, 5, 5, u8"EDIT_TARGET" }, + { 36, 1, 1, u8"EDIT_MOUTH" }, + { 37, 1, 1, u8"SET_CHARA" }, + { 38, 7, 7, u8"EDIT_MOVE" }, + { 39, 1, 1, u8"EDIT_SHADOW" }, + { 40, 1, 1, u8"EDIT_EYELID" }, + { 41, 2, 2, u8"EDIT_EYE" }, + { 42, 1, 1, u8"EDIT_ITEM" }, + { 43, 2, 2, u8"EDIT_EFFECT" }, + { 44, 1, 1, u8"EDIT_DISP" }, + { 45, 2, 2, u8"EDIT_HAND_ANIM" }, + { 46, 3, 3, u8"AIM" }, + { 47, 3, 3, u8"HAND_ITEM" }, + { 48, 1, 1, u8"EDIT_BLUSH" }, + { 49, 2, 2, u8"NEAR_CLIP" }, + { 50, 1, 2, u8"CLOTH_WET" }, + { 51, 3, 3, u8"LIGHT_ROT" }, + { 52, 6, 6, u8"SCENE_FADE" }, + { 53, 6, 6, u8"TONE_TRANS" }, + { 54, 1, 1, u8"SATURATE" }, + { 55, 1, 1, u8"FADE_MODE" }, + { 56, 2, 2, u8"AUTO_BLINK" }, + { 57, 3, 3, u8"PARTS_DISP" }, + { 58, 1, 1, u8"TARGET_FLYING_TIME" }, // AC210 + { 59, 2, 2, u8"CHARA_SIZE" }, + { 60, 2, 2, u8"CHARA_HEIGHT_ADJUST" }, + { 61, 4, 4, u8"ITEM_ANIM" }, + { 62, 4, 4, u8"CHARA_POS_ADJUST" }, + { 63, 1, 1, u8"SCENE_ROT" }, + { 64, 2, 2, u8"EDIT_MOT_SMOOTH_LEN" }, // AC500 + { 65, 1, 1, u8"PV_BRANCH_MODE" }, // AC510 + { 66, 2, 2, u8"DATA_CAMERA_START" }, + { 67, 1, 1, u8"MOVIE_PLAY" }, + { 68, 1, 1, u8"MOVIE_DISP" }, + { 69, 3, 3, u8"WIND" }, + { 70, 3, 3, u8"OSAGE_STEP" }, + { 71, 3, 3, u8"OSAGE_MV_CCL" }, + { 72, 2, 2, u8"CHARA_COLOR" }, + { 73, 1, 1, u8"SE_EFFECT" }, + { 74, 9, 9, u8"EDIT_MOVE_XYZ" }, + { 75, 3, 3, u8"EDIT_EYELID_ANIM" }, + { 76, 2, 2, u8"EDIT_INSTRUMENT_ITEM" }, + { 77, 4, 4, u8"EDIT_MOTION_LOOP" }, + { 78, 2, 2, u8"EDIT_EXPRESSION" }, + { 79, 3, 3, u8"EDIT_EYE_ANIM" }, + { 80, 2, 2, u8"EDIT_MOUTH_ANIM" }, + { 81, 24, 24, u8"EDIT_CAMERA" }, + { 82, 1, 1, u8"EDIT_MODE_SELECT" }, + { 83, 2, 2, u8"PV_END_FADEOUT" }, + { 84, 1, 1, u8"TARGET_FLAG" }, + { 85, 3, 3, u8"ITEM_ANIM_ATTACH" }, + { 86, 1, 1, u8"SHADOW_RANGE" }, + { 87, 3, 3, u8"HAND_SCALE" }, // AFT101 + { 88, 4, 4, u8"LIGHT_POS" }, + { 89, 1, 1, u8"FACE_TYPE" }, // AFT200 + { 90, 2, 2, u8"SHADOW_CAST" }, // AFT300 + { 91, 6, 6, u8"EDIT_MOTION_F" }, // AFT310 + { 92, 3, 3, u8"FOG" }, // AFT410 + { 93, 2, 2, u8"BLOOM" }, + { 94, 3, 3, u8"COLOR_COLLE" }, + { 95, 3, 3, u8"DOF" }, + { 96, 4, 4, u8"CHARA_ALPHA" }, + { 97, 1, 1, u8"AOTO_CAP" }, + { 98, 1, 1, u8"MAN_CAP" }, + { 99, 3, 3, u8"TOON" }, + { 100, 3, 3, u8"SHIMMER" }, + { 101, 4, 4, u8"ITEM_ALPHA" }, + { 102, 1, 1, u8"MOVIE_CUT_CHG" }, + { 103, 3, 3, u8"CHARA_LIGHT" }, + { 104, 3, 3, u8"STAGE_LIGHT" }, + { 105, 8, 8, u8"AGEAGE_CTR" }, // AFT701 + { 106, 2, 2, u8"PSE" }, // FT }; static const dsc_func_ac dsc_f_func[] = { - { 0, 0, 0, "END" }, - { 1, 1, 1, "TIME" }, - { 2, 3, 4, "MIKU_MOVE" }, - { 3, 1, 2, "MIKU_ROT" }, - { 4, 1, 2, "MIKU_DISP" }, - { 5, 1, 2, "MIKU_SHADOW" }, - { 6, 7, 11, "TARGET" }, - { 7, 3, 4, "SET_MOTION" }, - { 8, 1, 2, "SET_PLAYDATA" }, - { 9, 5, 6, "EFFECT" }, - { 10, 2, 2, "FADEIN_FIELD" }, - { 11, 1, 1, "EFFECT_OFF" }, - { 12, 6, 6, "SET_CAMERA" }, - { 13, 2, 2, "DATA_CAMERA" }, - { 14, 1, 1, "CHANGE_FIELD" }, - { 15, 1, 1, "HIDE_FIELD" }, - { 16, 3, 3, "MOVE_FIELD" }, - { 17, 2, 2, "FADEOUT_FIELD" }, - { 18, 2, 3, "EYE_ANIM" }, - { 19, 3, 5, "MOUTH_ANIM" }, - { 20, 4, 5, "HAND_ANIM" }, - { 21, 3, 4, "LOOK_ANIM" }, - { 22, 3, 4, "EXPRESSION" }, - { 23, 4, 5, "LOOK_CAMERA" }, - { 24, 1, 2, "LYRIC" }, - { 25, 0, 0, "MUSIC_PLAY" }, - { 26, 1, 2, "MODE_SELECT" }, - { 27, 2, 4, "EDIT_MOTION" }, - { 28, 2, 2, "BAR_TIME_SET" }, - { 29, 1, 2, "SHADOWHEIGHT" }, - { 30, 2, 1, "EDIT_FACE" }, - { 31, 19, 21, "MOVE_CAMERA" }, - { 32, 0, 0, "PV_END" }, - { 33, 2, 3, "SHADOWPOS" }, - { 34, 2, 2, "EDIT_LYRIC" }, - { 35, 5, 5, "EDIT_TARGET" }, - { 36, 1, 1, "EDIT_MOUTH" }, - { 37, 1, 1, "SET_CHARA" }, - { 38, 7, 7, "EDIT_MOVE" }, - { 39, 1, 1, "EDIT_SHADOW" }, - { 40, 1, 1, "EDIT_EYELID" }, - { 41, 2, 2, "EDIT_EYE" }, - { 42, 1, 1, "EDIT_ITEM" }, - { 43, 2, 2, "EDIT_EFFECT" }, - { 44, 1, 1, "EDIT_DISP" }, - { 45, 2, 2, "EDIT_HAND_ANIM" }, - { 46, 3, 3, "AIM" }, - { 47, 3, 3, "HAND_ITEM" }, - { 48, 1, 1, "EDIT_BLUSH" }, - { 49, 2, 2, "NEAR_CLIP" }, // DT 2nd - { 50, 1, 2, "CLOTH_WET" }, - { 51, 3, 3, "LIGHT_ROT" }, - { 52, 6, 6, "SCENE_FADE" }, - { 53, 6, 6, "TONE_TRANS" }, - { 54, 1, 1, "SATURATE" }, - { 55, 1, 1, "FADE_MODE" }, - { 56, 2, 2, "AUTO_BLINK" }, - { 57, 3, 3, "PARTS_DISP" }, - { 58, 1, 1, "TARGET_FLYING_TIME" }, - { 59, 2, 2, "CHARA_SIZE" }, - { 60, 2, 2, "CHARA_HEIGHT_ADJUST" }, - { 61, 4, 4, "ITEM_ANIM" }, - { 62, 4, 4, "CHARA_POS_ADJUST" }, - { 63, 1, 1, "SCENE_ROT" }, - { 64, 2, 2, "EDIT_MOT_SMOOTH_LEN" }, // F - { 65, 1, 1, "PV_BRANCH_MODE" }, - { 66, 2, 2, "DATA_CAMERA_START" }, - { 67, 1, 1, "MOVIE_PLAY" }, - { 68, 1, 1, "MOVIE_DISP" }, - { 69, 3, 3, "WIND" }, - { 70, 3, 3, "OSAGE_STEP" }, - { 71, 3, 3, "OSAGE_MV_CCL" }, - { 72, 2, 2, "CHARA_COLOR" }, - { 73, 1, 1, "SE_EFFECT" }, - { 74, 9, 9, "EDIT_MOVE_XYZ" }, - { 75, 3, 3, "EDIT_EYELID_ANIM" }, - { 76, 2, 2, "EDIT_INSTRUMENT_ITEM" }, - { 77, 4, 4, "EDIT_MOTION_LOOP" }, - { 78, 2, 2, "EDIT_EXPRESSION" }, - { 79, 3, 3, "EDIT_EYE_ANIM" }, - { 80, 2, 2, "EDIT_MOUTH_ANIM" }, - { 81, 24, 24, "EDIT_CAMERA" }, - { 82, 1, 1, "EDIT_MODE_SELECT" }, - { 83, 2, 2, "PV_END_FADEOUT" }, + { 0, 0, 0, u8"END" }, + { 1, 1, 1, u8"TIME" }, + { 2, 3, 4, u8"MIKU_MOVE" }, + { 3, 1, 2, u8"MIKU_ROT" }, + { 4, 1, 2, u8"MIKU_DISP" }, + { 5, 1, 2, u8"MIKU_SHADOW" }, + { 6, 7, 11, u8"TARGET" }, + { 7, 3, 4, u8"SET_MOTION" }, + { 8, 1, 2, u8"SET_PLAYDATA" }, + { 9, 5, 6, u8"EFFECT" }, + { 10, 2, 2, u8"FADEIN_FIELD" }, + { 11, 1, 1, u8"EFFECT_OFF" }, + { 12, 6, 6, u8"SET_CAMERA" }, + { 13, 2, 2, u8"DATA_CAMERA" }, + { 14, 1, 1, u8"CHANGE_FIELD" }, + { 15, 1, 1, u8"HIDE_FIELD" }, + { 16, 3, 3, u8"MOVE_FIELD" }, + { 17, 2, 2, u8"FADEOUT_FIELD" }, + { 18, 2, 3, u8"EYE_ANIM" }, + { 19, 3, 5, u8"MOUTH_ANIM" }, + { 20, 4, 5, u8"HAND_ANIM" }, + { 21, 3, 4, u8"LOOK_ANIM" }, + { 22, 3, 4, u8"EXPRESSION" }, + { 23, 4, 5, u8"LOOK_CAMERA" }, + { 24, 1, 2, u8"LYRIC" }, + { 25, 0, 0, u8"MUSIC_PLAY" }, + { 26, 1, 2, u8"MODE_SELECT" }, + { 27, 2, 4, u8"EDIT_MOTION" }, + { 28, 2, 2, u8"BAR_TIME_SET" }, + { 29, 1, 2, u8"SHADOWHEIGHT" }, + { 30, 2, 1, u8"EDIT_FACE" }, + { 31, 19, 21, u8"MOVE_CAMERA" }, + { 32, 0, 0, u8"PV_END" }, + { 33, 2, 3, u8"SHADOWPOS" }, + { 34, 2, 2, u8"EDIT_LYRIC" }, + { 35, 5, 5, u8"EDIT_TARGET" }, + { 36, 1, 1, u8"EDIT_MOUTH" }, + { 37, 1, 1, u8"SET_CHARA" }, + { 38, 7, 7, u8"EDIT_MOVE" }, + { 39, 1, 1, u8"EDIT_SHADOW" }, + { 40, 1, 1, u8"EDIT_EYELID" }, + { 41, 2, 2, u8"EDIT_EYE" }, + { 42, 1, 1, u8"EDIT_ITEM" }, + { 43, 2, 2, u8"EDIT_EFFECT" }, + { 44, 1, 1, u8"EDIT_DISP" }, + { 45, 2, 2, u8"EDIT_HAND_ANIM" }, + { 46, 3, 3, u8"AIM" }, + { 47, 3, 3, u8"HAND_ITEM" }, + { 48, 1, 1, u8"EDIT_BLUSH" }, + { 49, 2, 2, u8"NEAR_CLIP" }, // DT 2nd + { 50, 1, 2, u8"CLOTH_WET" }, + { 51, 3, 3, u8"LIGHT_ROT" }, + { 52, 6, 6, u8"SCENE_FADE" }, + { 53, 6, 6, u8"TONE_TRANS" }, + { 54, 1, 1, u8"SATURATE" }, + { 55, 1, 1, u8"FADE_MODE" }, + { 56, 2, 2, u8"AUTO_BLINK" }, + { 57, 3, 3, u8"PARTS_DISP" }, + { 58, 1, 1, u8"TARGET_FLYING_TIME" }, + { 59, 2, 2, u8"CHARA_SIZE" }, + { 60, 2, 2, u8"CHARA_HEIGHT_ADJUST" }, + { 61, 4, 4, u8"ITEM_ANIM" }, + { 62, 4, 4, u8"CHARA_POS_ADJUST" }, + { 63, 1, 1, u8"SCENE_ROT" }, + { 64, 2, 2, u8"EDIT_MOT_SMOOTH_LEN" }, // F + { 65, 1, 1, u8"PV_BRANCH_MODE" }, + { 66, 2, 2, u8"DATA_CAMERA_START" }, + { 67, 1, 1, u8"MOVIE_PLAY" }, + { 68, 1, 1, u8"MOVIE_DISP" }, + { 69, 3, 3, u8"WIND" }, + { 70, 3, 3, u8"OSAGE_STEP" }, + { 71, 3, 3, u8"OSAGE_MV_CCL" }, + { 72, 2, 2, u8"CHARA_COLOR" }, + { 73, 1, 1, u8"SE_EFFECT" }, + { 74, 9, 9, u8"EDIT_MOVE_XYZ" }, + { 75, 3, 3, u8"EDIT_EYELID_ANIM" }, + { 76, 2, 2, u8"EDIT_INSTRUMENT_ITEM" }, + { 77, 4, 4, u8"EDIT_MOTION_LOOP" }, + { 78, 2, 2, u8"EDIT_EXPRESSION" }, + { 79, 3, 3, u8"EDIT_EYE_ANIM" }, + { 80, 2, 2, u8"EDIT_MOUTH_ANIM" }, + { 81, 24, 24, u8"EDIT_CAMERA" }, + { 82, 1, 1, u8"EDIT_MODE_SELECT" }, + { 83, 2, 2, u8"PV_END_FADEOUT" }, }; static const dsc_func dsc_f2_func[] = { - { 0, 0, "END" }, - { 1, 1, "TIME" }, - { 2, 4, "MIKU_MOVE" }, - { 3, 2, "MIKU_ROT" }, - { 4, 2, "MIKU_DISP" }, - { 5, 2, "MIKU_SHADOW" }, - { 6, 12, "TARGET" }, - { 7, 4, "SET_MOTION" }, - { 8, 2, "SET_PLAYDATA" }, - { 9, 6, "EFFECT" }, - { 10, 2, "FADEIN_FIELD" }, - { 11, 1, "EFFECT_OFF" }, - { 12, 6, "SET_CAMERA" }, - { 13, 2, "DATA_CAMERA" }, - { 14, 2, "CHANGE_FIELD" }, - { 15, 1, "HIDE_FIELD" }, - { 16, 3, "MOVE_FIELD" }, - { 17, 2, "FADEOUT_FIELD" }, - { 18, 3, "EYE_ANIM" }, - { 19, 5, "MOUTH_ANIM" }, - { 20, 5, "HAND_ANIM" }, - { 21, 4, "LOOK_ANIM" }, - { 22, 4, "EXPRESSION" }, - { 23, 5, "LOOK_CAMERA" }, - { 24, 2, "LYRIC" }, - { 25, 0, "MUSIC_PLAY" }, - { 26, 2, "MODE_SELECT" }, - { 27, 4, "EDIT_MOTION" }, - { 28, 2, "BAR_TIME_SET" }, - { 29, 2, "SHADOWHEIGHT" }, - { 30, 1, "EDIT_FACE" }, - { 31, 21, "MOVE_CAMERA" }, - { 32, 0, "PV_END" }, - { 33, 3, "SHADOWPOS" }, - { 34, 2, "EDIT_LYRIC" }, - { 35, 5, "EDIT_TARGET" }, - { 36, 1, "EDIT_MOUTH" }, - { 37, 1, "SET_CHARA" }, - { 38, 7, "EDIT_MOVE" }, - { 39, 1, "EDIT_SHADOW" }, - { 40, 1, "EDIT_EYELID" }, - { 41, 2, "EDIT_EYE" }, - { 42, 1, "EDIT_ITEM" }, - { 43, 2, "EDIT_EFFECT" }, - { 44, 1, "EDIT_DISP" }, - { 45, 2, "EDIT_HAND_ANIM" }, - { 46, 3, "AIM" }, - { 47, 3, "HAND_ITEM" }, - { 48, 1, "EDIT_BLUSH" }, - { 49, 2, "NEAR_CLIP" }, - { 50, 2, "CLOTH_WET" }, - { 51, 3, "LIGHT_ROT" }, - { 52, 6, "SCENE_FADE" }, - { 53, 6, "TONE_TRANS" }, - { 54, 1, "SATURATE" }, - { 55, 1, "FADE_MODE" }, - { 56, 2, "AUTO_BLINK" }, - { 57, 3, "PARTS_DISP" }, - { 58, 1, "TARGET_FLYING_TIME" }, - { 59, 2, "CHARA_SIZE" }, - { 60, 2, "CHARA_HEIGHT_ADJUST" }, - { 61, 4, "ITEM_ANIM" }, - { 62, 4, "CHARA_POS_ADJUST" }, - { 63, 1, "SCENE_ROT" }, - { 64, 2, "EDIT_MOT_SMOOTH_LEN" }, - { 65, 1, "PV_BRANCH_MODE" }, - { 66, 2, "DATA_CAMERA_START" }, - { 67, 1, "MOVIE_PLAY" }, - { 68, 1, "MOVIE_DISP" }, - { 69, 3, "WIND" }, - { 70, 3, "OSAGE_STEP" }, - { 71, 3, "OSAGE_MV_CCL" }, - { 72, 2, "CHARA_COLOR" }, - { 73, 1, "SE_EFFECT" }, - { 74, 9, "EDIT_MOVE_XYZ" }, - { 75, 3, "EDIT_EYELID_ANIM" }, - { 76, 2, "EDIT_INSTRUMENT_ITEM" }, - { 77, 4, "EDIT_MOTION_LOOP" }, - { 78, 2, "EDIT_EXPRESSION" }, - { 79, 3, "EDIT_EYE_ANIM" }, - { 80, 2, "EDIT_MOUTH_ANIM" }, - { 81, 22, "EDIT_CAMERA" }, - { 82, 1, "EDIT_MODE_SELECT" }, - { 83, 2, "PV_END_FADEOUT" }, - { 84, 1, "RESERVE" }, - { 85, 6, "RESERVE" }, - { 86, 1, "RESERVE" }, - { 87, 9, "RESERVE" }, - { 88, 2, "PV_AUTH_LIGHT_PRIORITY" }, - { 89, 3, "PV_CHARA_LIGHT" }, - { 90, 3, "PV_STAGE_LIGHT" }, - { 91, 11, "TARGET_EFFECT" }, - { 92, 3, "FOG" }, - { 93, 2, "BLOOM" }, - { 94, 3, "COLOR_CORRECTION" }, - { 95, 3, "DOF" }, - { 96, 4, "CHARA_ALPHA" }, - { 97, 1, "AUTO_CAPTURE_BEGIN" }, - { 98, 1, "MANUAL_CAPTURE" }, - { 99, 3, "TOON_EDGE" }, - { 100, 3, "SHIMMER" }, - { 101, 4, "ITEM_ALPHA" }, - { 102, 1, "MOVIE_CUT" }, - { 103, 112, "EDIT_CAMERA_BOX" }, - { 104, 1, "EDIT_STAGE_PARAM" }, - { 105, 1, "EDIT_CHANGE_FIELD" }, - { 106, 7, "MIKUDAYO_ADJUST" }, - { 107, 2, "LYRIC_2" }, // US/EU - { 108, 2, "LYRIC_READ" }, - { 109, 2, "LYRIC_READ_2" }, - { 110, 5, "ANNOTATION" }, + { 0, 0, u8"END" }, + { 1, 1, u8"TIME" }, + { 2, 4, u8"MIKU_MOVE" }, + { 3, 2, u8"MIKU_ROT" }, + { 4, 2, u8"MIKU_DISP" }, + { 5, 2, u8"MIKU_SHADOW" }, + { 6, 12, u8"TARGET" }, + { 7, 4, u8"SET_MOTION" }, + { 8, 2, u8"SET_PLAYDATA" }, + { 9, 6, u8"EFFECT" }, + { 10, 2, u8"FADEIN_FIELD" }, + { 11, 1, u8"EFFECT_OFF" }, + { 12, 6, u8"SET_CAMERA" }, + { 13, 2, u8"DATA_CAMERA" }, + { 14, 2, u8"CHANGE_FIELD" }, + { 15, 1, u8"HIDE_FIELD" }, + { 16, 3, u8"MOVE_FIELD" }, + { 17, 2, u8"FADEOUT_FIELD" }, + { 18, 3, u8"EYE_ANIM" }, + { 19, 5, u8"MOUTH_ANIM" }, + { 20, 5, u8"HAND_ANIM" }, + { 21, 4, u8"LOOK_ANIM" }, + { 22, 4, u8"EXPRESSION" }, + { 23, 5, u8"LOOK_CAMERA" }, + { 24, 2, u8"LYRIC" }, + { 25, 0, u8"MUSIC_PLAY" }, + { 26, 2, u8"MODE_SELECT" }, + { 27, 4, u8"EDIT_MOTION" }, + { 28, 2, u8"BAR_TIME_SET" }, + { 29, 2, u8"SHADOWHEIGHT" }, + { 30, 1, u8"EDIT_FACE" }, + { 31, 21, u8"MOVE_CAMERA" }, + { 32, 0, u8"PV_END" }, + { 33, 3, u8"SHADOWPOS" }, + { 34, 2, u8"EDIT_LYRIC" }, + { 35, 5, u8"EDIT_TARGET" }, + { 36, 1, u8"EDIT_MOUTH" }, + { 37, 1, u8"SET_CHARA" }, + { 38, 7, u8"EDIT_MOVE" }, + { 39, 1, u8"EDIT_SHADOW" }, + { 40, 1, u8"EDIT_EYELID" }, + { 41, 2, u8"EDIT_EYE" }, + { 42, 1, u8"EDIT_ITEM" }, + { 43, 2, u8"EDIT_EFFECT" }, + { 44, 1, u8"EDIT_DISP" }, + { 45, 2, u8"EDIT_HAND_ANIM" }, + { 46, 3, u8"AIM" }, + { 47, 3, u8"HAND_ITEM" }, + { 48, 1, u8"EDIT_BLUSH" }, + { 49, 2, u8"NEAR_CLIP" }, + { 50, 2, u8"CLOTH_WET" }, + { 51, 3, u8"LIGHT_ROT" }, + { 52, 6, u8"SCENE_FADE" }, + { 53, 6, u8"TONE_TRANS" }, + { 54, 1, u8"SATURATE" }, + { 55, 1, u8"FADE_MODE" }, + { 56, 2, u8"AUTO_BLINK" }, + { 57, 3, u8"PARTS_DISP" }, + { 58, 1, u8"TARGET_FLYING_TIME" }, + { 59, 2, u8"CHARA_SIZE" }, + { 60, 2, u8"CHARA_HEIGHT_ADJUST" }, + { 61, 4, u8"ITEM_ANIM" }, + { 62, 4, u8"CHARA_POS_ADJUST" }, + { 63, 1, u8"SCENE_ROT" }, + { 64, 2, u8"EDIT_MOT_SMOOTH_LEN" }, + { 65, 1, u8"PV_BRANCH_MODE" }, + { 66, 2, u8"DATA_CAMERA_START" }, + { 67, 1, u8"MOVIE_PLAY" }, + { 68, 1, u8"MOVIE_DISP" }, + { 69, 3, u8"WIND" }, + { 70, 3, u8"OSAGE_STEP" }, + { 71, 3, u8"OSAGE_MV_CCL" }, + { 72, 2, u8"CHARA_COLOR" }, + { 73, 1, u8"SE_EFFECT" }, + { 74, 9, u8"EDIT_MOVE_XYZ" }, + { 75, 3, u8"EDIT_EYELID_ANIM" }, + { 76, 2, u8"EDIT_INSTRUMENT_ITEM" }, + { 77, 4, u8"EDIT_MOTION_LOOP" }, + { 78, 2, u8"EDIT_EXPRESSION" }, + { 79, 3, u8"EDIT_EYE_ANIM" }, + { 80, 2, u8"EDIT_MOUTH_ANIM" }, + { 81, 22, u8"EDIT_CAMERA" }, + { 82, 1, u8"EDIT_MODE_SELECT" }, + { 83, 2, u8"PV_END_FADEOUT" }, + { 84, 1, u8"RESERVE" }, + { 85, 6, u8"RESERVE" }, + { 86, 1, u8"RESERVE" }, + { 87, 9, u8"RESERVE" }, + { 88, 2, u8"PV_AUTH_LIGHT_PRIORITY" }, + { 89, 3, u8"PV_CHARA_LIGHT" }, + { 90, 3, u8"PV_STAGE_LIGHT" }, + { 91, 11, u8"TARGET_EFFECT" }, + { 92, 3, u8"FOG" }, + { 93, 2, u8"BLOOM" }, + { 94, 3, u8"COLOR_CORRECTION" }, + { 95, 3, u8"DOF" }, + { 96, 4, u8"CHARA_ALPHA" }, + { 97, 1, u8"AUTO_CAPTURE_BEGIN" }, + { 98, 1, u8"MANUAL_CAPTURE" }, + { 99, 3, u8"TOON_EDGE" }, + { 100, 3, u8"SHIMMER" }, + { 101, 4, u8"ITEM_ALPHA" }, + { 102, 1, u8"MOVIE_CUT" }, + { 103, 112, u8"EDIT_CAMERA_BOX" }, + { 104, 1, u8"EDIT_STAGE_PARAM" }, + { 105, 1, u8"EDIT_CHANGE_FIELD" }, + { 106, 7, u8"MIKUDAYO_ADJUST" }, + { 107, 2, u8"LYRIC_2" }, // US/EU + { 108, 2, u8"LYRIC_READ" }, + { 109, 2, u8"LYRIC_READ_2" }, + { 110, 5, u8"ANNOTATION" }, }; static const dsc_func dsc_mgf_func[] = { - { 0, 0, "END" }, - { 1, 1, "TIME" }, - { 2, 4, "MIKU_MOVE" }, - { 3, 2, "MIKU_ROT" }, - { 4, 2, "MIKU_DISP" }, - { 5, 2, "MIKU_SHADOW" }, - { 6, 12, "TARGET" }, - { 7, 4, "SET_MOTION" }, - { 8, 2, "SET_PLAYDATA" }, - { 9, 6, "EFFECT" }, - { 10, 2, "FADEIN_FIELD" }, - { 11, 1, "EFFECT_OFF" }, - { 12, 6, "SET_CAMERA" }, - { 13, 2, "DATA_CAMERA" }, - { 14, 2, "CHANGE_FIELD" }, - { 15, 1, "HIDE_FIELD" }, - { 16, 3, "MOVE_FIELD" }, - { 17, 2, "FADEOUT_FIELD" }, - { 18, 3, "EYE_ANIM" }, - { 19, 5, "MOUTH_ANIM" }, - { 20, 5, "HAND_ANIM" }, - { 21, 4, "LOOK_ANIM" }, - { 22, 4, "EXPRESSION" }, - { 23, 5, "LOOK_CAMERA" }, - { 24, 2, "LYRIC" }, - { 25, 0, "MUSIC_PLAY" }, - { 26, 2, "MODE_SELECT" }, - { 27, 4, "EDIT_MOTION" }, - { 28, 2, "BAR_TIME_SET" }, - { 29, 2, "SHADOWHEIGHT" }, - { 30, 1, "EDIT_FACE" }, - { 31, 21, "MOVE_CAMERA" }, - { 32, 0, "PV_END" }, - { 33, 3, "SHADOWPOS" }, - { 34, 2, "EDIT_LYRIC" }, - { 35, 5, "EDIT_TARGET" }, - { 36, 1, "EDIT_MOUTH" }, - { 37, 1, "SET_CHARA" }, - { 38, 7, "EDIT_MOVE" }, - { 39, 1, "EDIT_SHADOW" }, - { 40, 1, "EDIT_EYELID" }, - { 41, 2, "EDIT_EYE" }, - { 42, 1, "EDIT_ITEM" }, - { 43, 2, "EDIT_EFFECT" }, - { 44, 1, "EDIT_DISP" }, - { 45, 2, "EDIT_HAND_ANIM" }, - { 46, 3, "AIM" }, - { 47, 3, "HAND_ITEM" }, - { 48, 1, "EDIT_BLUSH" }, - { 49, 2, "NEAR_CLIP" }, - { 50, 2, "CLOTH_WET" }, - { 51, 3, "LIGHT_ROT" }, - { 52, 6, "SCENE_FADE" }, - { 53, 6, "TONE_TRANS" }, - { 54, 1, "SATURATE" }, - { 55, 1, "FADE_MODE" }, - { 56, 2, "AUTO_BLINK" }, - { 57, 3, "PARTS_DISP" }, - { 58, 1, "TARGET_FLYING_TIME" }, - { 59, 2, "CHARA_SIZE" }, - { 60, 2, "CHARA_HEIGHT_ADJUST" }, - { 61, 4, "ITEM_ANIM" }, - { 62, 4, "CHARA_POS_ADJUST" }, - { 63, 1, "SCENE_ROT" }, - { 64, 2, "EDIT_MOT_SMOOTH_LEN" }, - { 65, 1, "PV_BRANCH_MODE" }, - { 66, 2, "DATA_CAMERA_START" }, - { 67, 1, "MOVIE_PLAY" }, - { 68, 1, "MOVIE_DISP" }, - { 69, 3, "WIND" }, - { 70, 3, "OSAGE_STEP" }, - { 71, 3, "OSAGE_MV_CCL" }, - { 72, 2, "CHARA_COLOR" }, - { 73, 1, "SE_EFFECT" }, - { 74, 9, "EDIT_MOVE_XYZ" }, - { 75, 3, "EDIT_EYELID_ANIM" }, - { 76, 2, "EDIT_INSTRUMENT_ITEM" }, - { 77, 4, "EDIT_MOTION_LOOP" }, - { 78, 2, "EDIT_EXPRESSION" }, - { 79, 3, "EDIT_EYE_ANIM" }, - { 80, 2, "EDIT_MOUTH_ANIM" }, - { 81, 22, "EDIT_CAMERA" }, - { 82, 1, "EDIT_MODE_SELECT" }, - { 83, 2, "PV_END_FADEOUT" }, - { 84, 1, "RESERVE" }, - { 85, 6, "RESERVE" }, - { 86, 1, "RESERVE" }, - { 87, 9, "RESERVE" }, - { 88, 2, "PV_AUTH_LIGHT_PRIORITY" }, - { 89, 3, "PV_CHARA_LIGHT" }, - { 90, 3, "PV_STAGE_LIGHT" }, - { 91, 11, "TARGET_EFFECT" }, - { 92, 3, "FOG" }, - { 93, 2, "BLOOM" }, - { 94, 3, "COLOR_CORRECTION" }, - { 95, 3, "DOF" }, - { 96, 4, "CHARA_ALPHA" }, - { 97, 1, "AUTO_CAPTURE_BEGIN" }, - { 98, 1, "MANUAL_CAPTURE" }, - { 99, 3, "TOON_EDGE" }, - { 100, 3, "SHIMMER" }, - { 101, 4, "ITEM_ALPHA" }, - { 102, 1, "MOVIE_CUT" }, - { 103, 1, "CROSSFADE" }, - { 104, 1, "SUBFRAMERENDER" }, - { 105, 36, "EVENT_JUDGE" }, - { 106, 2, "TOON_EDGE" }, - { 107, 2, "FOG_ENABLE" }, - { 108, 112, "EDIT_CAMERA_BOX" }, - { 109, 1, "EDIT_STAGE_PARAM" }, - { 110, 1, "EDIT_CHANGE_FIELD" }, + { 0, 0, u8"END" }, + { 1, 1, u8"TIME" }, + { 2, 4, u8"MIKU_MOVE" }, + { 3, 2, u8"MIKU_ROT" }, + { 4, 2, u8"MIKU_DISP" }, + { 5, 2, u8"MIKU_SHADOW" }, + { 6, 12, u8"TARGET" }, + { 7, 4, u8"SET_MOTION" }, + { 8, 2, u8"SET_PLAYDATA" }, + { 9, 6, u8"EFFECT" }, + { 10, 2, u8"FADEIN_FIELD" }, + { 11, 1, u8"EFFECT_OFF" }, + { 12, 6, u8"SET_CAMERA" }, + { 13, 2, u8"DATA_CAMERA" }, + { 14, 2, u8"CHANGE_FIELD" }, + { 15, 1, u8"HIDE_FIELD" }, + { 16, 3, u8"MOVE_FIELD" }, + { 17, 2, u8"FADEOUT_FIELD" }, + { 18, 3, u8"EYE_ANIM" }, + { 19, 5, u8"MOUTH_ANIM" }, + { 20, 5, u8"HAND_ANIM" }, + { 21, 4, u8"LOOK_ANIM" }, + { 22, 4, u8"EXPRESSION" }, + { 23, 5, u8"LOOK_CAMERA" }, + { 24, 2, u8"LYRIC" }, + { 25, 0, u8"MUSIC_PLAY" }, + { 26, 2, u8"MODE_SELECT" }, + { 27, 4, u8"EDIT_MOTION" }, + { 28, 2, u8"BAR_TIME_SET" }, + { 29, 2, u8"SHADOWHEIGHT" }, + { 30, 1, u8"EDIT_FACE" }, + { 31, 21, u8"MOVE_CAMERA" }, + { 32, 0, u8"PV_END" }, + { 33, 3, u8"SHADOWPOS" }, + { 34, 2, u8"EDIT_LYRIC" }, + { 35, 5, u8"EDIT_TARGET" }, + { 36, 1, u8"EDIT_MOUTH" }, + { 37, 1, u8"SET_CHARA" }, + { 38, 7, u8"EDIT_MOVE" }, + { 39, 1, u8"EDIT_SHADOW" }, + { 40, 1, u8"EDIT_EYELID" }, + { 41, 2, u8"EDIT_EYE" }, + { 42, 1, u8"EDIT_ITEM" }, + { 43, 2, u8"EDIT_EFFECT" }, + { 44, 1, u8"EDIT_DISP" }, + { 45, 2, u8"EDIT_HAND_ANIM" }, + { 46, 3, u8"AIM" }, + { 47, 3, u8"HAND_ITEM" }, + { 48, 1, u8"EDIT_BLUSH" }, + { 49, 2, u8"NEAR_CLIP" }, + { 50, 2, u8"CLOTH_WET" }, + { 51, 3, u8"LIGHT_ROT" }, + { 52, 6, u8"SCENE_FADE" }, + { 53, 6, u8"TONE_TRANS" }, + { 54, 1, u8"SATURATE" }, + { 55, 1, u8"FADE_MODE" }, + { 56, 2, u8"AUTO_BLINK" }, + { 57, 3, u8"PARTS_DISP" }, + { 58, 1, u8"TARGET_FLYING_TIME" }, + { 59, 2, u8"CHARA_SIZE" }, + { 60, 2, u8"CHARA_HEIGHT_ADJUST" }, + { 61, 4, u8"ITEM_ANIM" }, + { 62, 4, u8"CHARA_POS_ADJUST" }, + { 63, 1, u8"SCENE_ROT" }, + { 64, 2, u8"EDIT_MOT_SMOOTH_LEN" }, + { 65, 1, u8"PV_BRANCH_MODE" }, + { 66, 2, u8"DATA_CAMERA_START" }, + { 67, 1, u8"MOVIE_PLAY" }, + { 68, 1, u8"MOVIE_DISP" }, + { 69, 3, u8"WIND" }, + { 70, 3, u8"OSAGE_STEP" }, + { 71, 3, u8"OSAGE_MV_CCL" }, + { 72, 2, u8"CHARA_COLOR" }, + { 73, 1, u8"SE_EFFECT" }, + { 74, 9, u8"EDIT_MOVE_XYZ" }, + { 75, 3, u8"EDIT_EYELID_ANIM" }, + { 76, 2, u8"EDIT_INSTRUMENT_ITEM" }, + { 77, 4, u8"EDIT_MOTION_LOOP" }, + { 78, 2, u8"EDIT_EXPRESSION" }, + { 79, 3, u8"EDIT_EYE_ANIM" }, + { 80, 2, u8"EDIT_MOUTH_ANIM" }, + { 81, 22, u8"EDIT_CAMERA" }, + { 82, 1, u8"EDIT_MODE_SELECT" }, + { 83, 2, u8"PV_END_FADEOUT" }, + { 84, 1, u8"RESERVE" }, + { 85, 6, u8"RESERVE" }, + { 86, 1, u8"RESERVE" }, + { 87, 9, u8"RESERVE" }, + { 88, 2, u8"PV_AUTH_LIGHT_PRIORITY" }, + { 89, 3, u8"PV_CHARA_LIGHT" }, + { 90, 3, u8"PV_STAGE_LIGHT" }, + { 91, 11, u8"TARGET_EFFECT" }, + { 92, 3, u8"FOG" }, + { 93, 2, u8"BLOOM" }, + { 94, 3, u8"COLOR_CORRECTION" }, + { 95, 3, u8"DOF" }, + { 96, 4, u8"CHARA_ALPHA" }, + { 97, 1, u8"AUTO_CAPTURE_BEGIN" }, + { 98, 1, u8"MANUAL_CAPTURE" }, + { 99, 3, u8"TOON_EDGE" }, + { 100, 3, u8"SHIMMER" }, + { 101, 4, u8"ITEM_ALPHA" }, + { 102, 1, u8"MOVIE_CUT" }, + { 103, 1, u8"CROSSFADE" }, + { 104, 1, u8"SUBFRAMERENDER" }, + { 105, 36, u8"EVENT_JUDGE" }, + { 106, 2, u8"TOON_EDGE" }, + { 107, 2, u8"FOG_ENABLE" }, + { 108, 112, u8"EDIT_CAMERA_BOX" }, + { 109, 1, u8"EDIT_STAGE_PARAM" }, + { 110, 1, u8"EDIT_CHANGE_FIELD" }, }; static const dsc_func dsc_x_func[] = { - { 0, 0, "END" }, - { 1, 1, "TIME" }, - { 2, 4, "MIKU_MOVE" }, - { 3, 2, "MIKU_ROT" }, - { 4, 2, "MIKU_DISP" }, - { 5, 2, "MIKU_SHADOW" }, - { 6, 12, "TARGET" }, - { 7, 4, "SET_MOTION" }, - { 8, 2, "SET_PLAYDATA" }, - { 9, 6, "EFFECT" }, - { 10, 2, "FADEIN_FIELD" }, - { 11, 1, "EFFECT_OFF" }, - { 12, 6, "SET_CAMERA" }, - { 13, 2, "DATA_CAMERA" }, - { 14, 2, "CHANGE_FIELD" }, - { 15, 1, "HIDE_FIELD" }, - { 16, 3, "MOVE_FIELD" }, - { 17, 2, "FADEOUT_FIELD" }, - { 18, 3, "EYE_ANIM" }, - { 19, 5, "MOUTH_ANIM" }, - { 20, 5, "HAND_ANIM" }, - { 21, 4, "LOOK_ANIM" }, - { 22, 4, "EXPRESSION" }, - { 23, 5, "LOOK_CAMERA" }, - { 24, 2, "LYRIC" }, - { 25, 0, "MUSIC_PLAY" }, - { 26, 2, "MODE_SELECT" }, - { 27, 4, "EDIT_MOTION" }, - { 28, 2, "BAR_TIME_SET" }, - { 29, 2, "SHADOWHEIGHT" }, - { 30, 1, "EDIT_FACE" }, - { 31, 21, "DUMMY" }, - { 32, 0, "PV_END" }, - { 33, 3, "SHADOWPOS" }, - { 34, 2, "EDIT_LYRIC" }, - { 35, 5, "EDIT_TARGET" }, - { 36, 1, "EDIT_MOUTH" }, - { 37, 1, "SET_CHARA" }, - { 38, 7, "EDIT_MOVE" }, - { 39, 1, "EDIT_SHADOW" }, - { 40, 1, "EDIT_EYELID" }, - { 41, 2, "EDIT_EYE" }, - { 42, 1, "EDIT_ITEM" }, - { 43, 2, "EDIT_EFFECT" }, - { 44, 1, "EDIT_DISP" }, - { 45, 2, "EDIT_HAND_ANIM" }, - { 46, 3, "AIM" }, - { 47, 3, "HAND_ITEM" }, - { 48, 1, "EDIT_BLUSH" }, - { 49, 2, "NEAR_CLIP" }, - { 50, 2, "CLOTH_WET" }, - { 51, 3, "LIGHT_ROT" }, - { 52, 6, "SCENE_FADE" }, - { 53, 6, "TONE_TRANS" }, - { 54, 1, "SATURATE" }, - { 55, 1, "FADE_MODE" }, - { 56, 2, "AUTO_BLINK" }, - { 57, 3, "PARTS_DISP" }, - { 58, 1, "TARGET_FLYING_TIME" }, - { 59, 2, "CHARA_SIZE" }, - { 60, 2, "CHARA_HEIGHT_ADJUST" }, - { 61, 4, "ITEM_ANIM" }, - { 62, 4, "CHARA_POS_ADJUST" }, - { 63, 1, "SCENE_ROT" }, - { 64, 2, "EDIT_MOT_SMOOTH_LEN" }, - { 65, 1, "PV_BRANCH_MODE" }, - { 66, 2, "DATA_CAMERA_START" }, - { 67, 1, "MOVIE_PLAY" }, - { 68, 1, "MOVIE_DISP" }, - { 69, 3, "WIND" }, - { 70, 3, "OSAGE_STEP" }, - { 71, 3, "OSAGE_MV_CCL" }, - { 72, 2, "CHARA_COLOR" }, - { 73, 1, "SE_EFFECT" }, - { 74, 2, "CHARA_SHADOW_QUALITY" }, - { 75, 2, "STAGE_SHADOW_QUALITY" }, - { 76, 2, "COMMON_LIGHT" }, - { 77, 2, "TONE_MAP" }, - { 78, 2, "IBL_COLOR" }, - { 79, 2, "REFLECTION" }, - { 80, 3, "CHROMATIC_ABERRATION" }, - { 81, 2, "STAGE_SHADOW" }, - { 82, 2, "REFLECTION_QUALITY" }, - { 83, 2, "PV_END_FADEOUT" }, - { 84, 1, "CREDIT_TITLE" }, - { 85, 1, "BAR_POINT" }, - { 86, 1, "BEAT_POINT" }, - { 87, 0, "RESERVE" }, - { 88, 2, "PV_AUTH_LIGHT_PRIORITY" }, - { 89, 3, "PV_CHARA_LIGHT" }, - { 90, 3, "PV_STAGE_LIGHT" }, - { 91, 11, "TARGET_EFFECT" }, - { 92, 3, "FOG" }, - { 93, 2, "BLOOM" }, - { 94, 3, "COLOR_CORRECTION" }, - { 95, 3, "DOF" }, - { 96, 4, "CHARA_ALPHA" }, - { 97, 1, "AUTO_CAPTURE_BEGIN" }, - { 98, 1, "MANUAL_CAPTURE" }, - { 99, 3, "TOON_EDGE" }, - { 100, 3, "SHIMMER" }, - { 101, 4, "ITEM_ALPHA" }, - { 102, 1, "MOVIE_CUT" }, - { 103, 112, "EDIT_CAMERA_BOX" }, - { 104, 1, "EDIT_STAGE_PARAM" }, - { 105, 1, "EDIT_CHANGE_FIELD" }, - { 106, 7, "MIKUDAYO_ADJUST" }, - { 107, 2, "LYRIC_2" }, - { 108, 2, "LYRIC_READ" }, - { 109, 2, "LYRIC_READ_2" }, - { 110, 5, "ANNOTATION" }, - { 111, 2, "STAGE_EFFECT" }, - { 112, 3, "SONG_EFFECT" }, - { 113, 3, "SONG_EFFECT_ATTACH" }, - { 114, 2, "LIGHT_AUTH" }, - { 115, 2, "FADE" }, - { 116, 2, "SET_STAGE_EFFECT_ENV" }, - { 117, 2, "RESERVE" }, - { 118, 2, "COMMON_EFFECT_AET_FRONT" }, - { 119, 2, "COMMON_EFFECT_AET_FRONT_LOW" }, - { 120, 2, "COMMON_EFFECT_PARTICLE" }, - { 121, 3, "SONG_EFFECT_ALPHA_SORT" }, - { 122, 5, "LOOK_CAMERA_FACE_LIMIT" }, - { 123, 3, "ITEM_LIGHT" }, - { 124, 3, "CHARA_EFFECT" }, - { 125, 2, "MARKER" }, - { 126, 3, "CHARA_EFFECT_CHARA_LIGHT" }, - { 127, 2, "ENABLE_COMMON_LIGHT_TO_CHARA" }, - { 128, 2, "ENABLE_FXAA" }, - { 129, 2, "ENABLE_TEMPORAL_AA" }, - { 130, 2, "ENABLE_REFLECTION" }, - { 131, 2, "BANK_BRANCH" }, - { 132, 2, "BANK_END" }, - { 133, 2, "" }, - { 134, 2, "" }, - { 135, 2, "" }, - { 136, 2, "" }, - { 137, 2, "" }, - { 138, 2, "" }, - { 139, 2, "" }, - { 140, 2, "" }, - { 141, 2, "VR_LIVE_MOVIE" }, - { 142, 2, "VR_CHEER" }, - { 143, 2, "VR_CHARA_PSMOVE" }, - { 144, 2, "VR_MOVE_PATH" }, - { 145, 2, "VR_SET_BASE" }, - { 146, 2, "VR_TECH_DEMO_EFFECT" }, - { 147, 2, "VR_TRANSFORM" }, - { 148, 2, "GAZE" }, - { 149, 2, "TECH_DEMO_GESUTRE" }, - { 150, 2, "VR_CHEMICAL_LIGHT_COLOR" }, - { 151, 5, "VR_LIVE_MOB" }, - { 152, 9, "VR_LIVE_HAIR_OSAGE" }, - { 153, 9, "VR_LIVE_LOOK_CAMERA" }, - { 154, 5, "VR_LIVE_CHEER" }, - { 155, 3, "VR_LIVE_GESTURE" }, - { 156, 7, "VR_LIVE_CLONE" }, - { 157, 7, "VR_LOOP_EFFECT" }, - { 158, 6, "VR_LIVE_ONESHOT_EFFECT" }, - { 159, 9, "VR_LIVE_PRESENT" }, - { 160, 5, "VR_LIVE_TRANSFORM" }, - { 161, 5, "VR_LIVE_FLY" }, - { 162, 2, "VR_LIVE_CHARA_VOICE" }, + { 0, 0, u8"END" }, + { 1, 1, u8"TIME" }, + { 2, 4, u8"MIKU_MOVE" }, + { 3, 2, u8"MIKU_ROT" }, + { 4, 2, u8"MIKU_DISP" }, + { 5, 2, u8"MIKU_SHADOW" }, + { 6, 12, u8"TARGET" }, + { 7, 4, u8"SET_MOTION" }, + { 8, 2, u8"SET_PLAYDATA" }, + { 9, 6, u8"EFFECT" }, + { 10, 2, u8"FADEIN_FIELD" }, + { 11, 1, u8"EFFECT_OFF" }, + { 12, 6, u8"SET_CAMERA" }, + { 13, 2, u8"DATA_CAMERA" }, + { 14, 2, u8"CHANGE_FIELD" }, + { 15, 1, u8"HIDE_FIELD" }, + { 16, 3, u8"MOVE_FIELD" }, + { 17, 2, u8"FADEOUT_FIELD" }, + { 18, 3, u8"EYE_ANIM" }, + { 19, 5, u8"MOUTH_ANIM" }, + { 20, 5, u8"HAND_ANIM" }, + { 21, 4, u8"LOOK_ANIM" }, + { 22, 4, u8"EXPRESSION" }, + { 23, 5, u8"LOOK_CAMERA" }, + { 24, 2, u8"LYRIC" }, + { 25, 0, u8"MUSIC_PLAY" }, + { 26, 2, u8"MODE_SELECT" }, + { 27, 4, u8"EDIT_MOTION" }, + { 28, 2, u8"BAR_TIME_SET" }, + { 29, 2, u8"SHADOWHEIGHT" }, + { 30, 1, u8"EDIT_FACE" }, + { 31, 21, u8"DUMMY" }, + { 32, 0, u8"PV_END" }, + { 33, 3, u8"SHADOWPOS" }, + { 34, 2, u8"EDIT_LYRIC" }, + { 35, 5, u8"EDIT_TARGET" }, + { 36, 1, u8"EDIT_MOUTH" }, + { 37, 1, u8"SET_CHARA" }, + { 38, 7, u8"EDIT_MOVE" }, + { 39, 1, u8"EDIT_SHADOW" }, + { 40, 1, u8"EDIT_EYELID" }, + { 41, 2, u8"EDIT_EYE" }, + { 42, 1, u8"EDIT_ITEM" }, + { 43, 2, u8"EDIT_EFFECT" }, + { 44, 1, u8"EDIT_DISP" }, + { 45, 2, u8"EDIT_HAND_ANIM" }, + { 46, 3, u8"AIM" }, + { 47, 3, u8"HAND_ITEM" }, + { 48, 1, u8"EDIT_BLUSH" }, + { 49, 2, u8"NEAR_CLIP" }, + { 50, 2, u8"CLOTH_WET" }, + { 51, 3, u8"LIGHT_ROT" }, + { 52, 6, u8"SCENE_FADE" }, + { 53, 6, u8"TONE_TRANS" }, + { 54, 1, u8"SATURATE" }, + { 55, 1, u8"FADE_MODE" }, + { 56, 2, u8"AUTO_BLINK" }, + { 57, 3, u8"PARTS_DISP" }, + { 58, 1, u8"TARGET_FLYING_TIME" }, + { 59, 2, u8"CHARA_SIZE" }, + { 60, 2, u8"CHARA_HEIGHT_ADJUST" }, + { 61, 4, u8"ITEM_ANIM" }, + { 62, 4, u8"CHARA_POS_ADJUST" }, + { 63, 1, u8"SCENE_ROT" }, + { 64, 2, u8"EDIT_MOT_SMOOTH_LEN" }, + { 65, 1, u8"PV_BRANCH_MODE" }, + { 66, 2, u8"DATA_CAMERA_START" }, + { 67, 1, u8"MOVIE_PLAY" }, + { 68, 1, u8"MOVIE_DISP" }, + { 69, 3, u8"WIND" }, + { 70, 3, u8"OSAGE_STEP" }, + { 71, 3, u8"OSAGE_MV_CCL" }, + { 72, 2, u8"CHARA_COLOR" }, + { 73, 1, u8"SE_EFFECT" }, + { 74, 2, u8"CHARA_SHADOW_QUALITY" }, + { 75, 2, u8"STAGE_SHADOW_QUALITY" }, + { 76, 2, u8"COMMON_LIGHT" }, + { 77, 2, u8"TONE_MAP" }, + { 78, 2, u8"IBL_COLOR" }, + { 79, 2, u8"REFLECTION" }, + { 80, 3, u8"CHROMATIC_ABERRATION" }, + { 81, 2, u8"STAGE_SHADOW" }, + { 82, 2, u8"REFLECTION_QUALITY" }, + { 83, 2, u8"PV_END_FADEOUT" }, + { 84, 1, u8"CREDIT_TITLE" }, + { 85, 1, u8"BAR_POINT" }, + { 86, 1, u8"BEAT_POINT" }, + { 87, 0, u8"RESERVE" }, + { 88, 2, u8"PV_AUTH_LIGHT_PRIORITY" }, + { 89, 3, u8"PV_CHARA_LIGHT" }, + { 90, 3, u8"PV_STAGE_LIGHT" }, + { 91, 11, u8"TARGET_EFFECT" }, + { 92, 3, u8"FOG" }, + { 93, 2, u8"BLOOM" }, + { 94, 3, u8"COLOR_CORRECTION" }, + { 95, 3, u8"DOF" }, + { 96, 4, u8"CHARA_ALPHA" }, + { 97, 1, u8"AUTO_CAPTURE_BEGIN" }, + { 98, 1, u8"MANUAL_CAPTURE" }, + { 99, 3, u8"TOON_EDGE" }, + { 100, 3, u8"SHIMMER" }, + { 101, 4, u8"ITEM_ALPHA" }, + { 102, 1, u8"MOVIE_CUT" }, + { 103, 112, u8"EDIT_CAMERA_BOX" }, + { 104, 1, u8"EDIT_STAGE_PARAM" }, + { 105, 1, u8"EDIT_CHANGE_FIELD" }, + { 106, 7, u8"MIKUDAYO_ADJUST" }, + { 107, 2, u8"LYRIC_2" }, + { 108, 2, u8"LYRIC_READ" }, + { 109, 2, u8"LYRIC_READ_2" }, + { 110, 5, u8"ANNOTATION" }, + { 111, 2, u8"STAGE_EFFECT" }, + { 112, 3, u8"SONG_EFFECT" }, + { 113, 3, u8"SONG_EFFECT_ATTACH" }, + { 114, 2, u8"LIGHT_AUTH" }, + { 115, 2, u8"FADE" }, + { 116, 2, u8"SET_STAGE_EFFECT_ENV" }, + { 117, 2, u8"RESERVE" }, + { 118, 2, u8"COMMON_EFFECT_AET_FRONT" }, + { 119, 2, u8"COMMON_EFFECT_AET_FRONT_LOW" }, + { 120, 2, u8"COMMON_EFFECT_PARTICLE" }, + { 121, 3, u8"SONG_EFFECT_ALPHA_SORT" }, + { 122, 5, u8"LOOK_CAMERA_FACE_LIMIT" }, + { 123, 3, u8"ITEM_LIGHT" }, + { 124, 3, u8"CHARA_EFFECT" }, + { 125, 2, u8"MARKER" }, + { 126, 3, u8"CHARA_EFFECT_CHARA_LIGHT" }, + { 127, 2, u8"ENABLE_COMMON_LIGHT_TO_CHARA" }, + { 128, 2, u8"ENABLE_FXAA" }, + { 129, 2, u8"ENABLE_TEMPORAL_AA" }, + { 130, 2, u8"ENABLE_REFLECTION" }, + { 131, 2, u8"BANK_BRANCH" }, + { 132, 2, u8"BANK_END" }, + { 133, 2, u8"" }, + { 134, 2, u8"" }, + { 135, 2, u8"" }, + { 136, 2, u8"" }, + { 137, 2, u8"" }, + { 138, 2, u8"" }, + { 139, 2, u8"" }, + { 140, 2, u8"" }, + { 141, 2, u8"VR_LIVE_MOVIE" }, + { 142, 2, u8"VR_CHEER" }, + { 143, 2, u8"VR_CHARA_PSMOVE" }, + { 144, 2, u8"VR_MOVE_PATH" }, + { 145, 2, u8"VR_SET_BASE" }, + { 146, 2, u8"VR_TECH_DEMO_EFFECT" }, + { 147, 2, u8"VR_TRANSFORM" }, + { 148, 2, u8"GAZE" }, + { 149, 2, u8"TECH_DEMO_GESUTRE" }, + { 150, 2, u8"VR_CHEMICAL_LIGHT_COLOR" }, + { 151, 5, u8"VR_LIVE_MOB" }, + { 152, 9, u8"VR_LIVE_HAIR_OSAGE" }, + { 153, 9, u8"VR_LIVE_LOOK_CAMERA" }, + { 154, 5, u8"VR_LIVE_CHEER" }, + { 155, 3, u8"VR_LIVE_GESTURE" }, + { 156, 7, u8"VR_LIVE_CLONE" }, + { 157, 7, u8"VR_LOOP_EFFECT" }, + { 158, 6, u8"VR_LIVE_ONESHOT_EFFECT" }, + { 159, 9, u8"VR_LIVE_PRESENT" }, + { 160, 5, u8"VR_LIVE_TRANSFORM" }, + { 161, 5, u8"VR_LIVE_FLY" }, + { 162, 2, u8"VR_LIVE_CHARA_VOICE" }, }; static const dsc_func dsc_vrfl_func[] = { - { 0, 0, "END" }, - { 1, 1, "TIME" }, - { 2, 4, "MIKU_MOVE" }, - { 3, 2, "MIKU_ROT" }, - { 4, 2, "MIKU_DISP" }, - { 5, 2, "MIKU_SHADOW" }, - { 6, 12, "TARGET" }, - { 7, 4, "SET_MOTION" }, - { 8, 2, "SET_PLAYDATA" }, - { 9, 6, "EFFECT" }, - { 10, 2, "FADEIN_FIELD" }, - { 11, 1, "EFFECT_OFF" }, - { 12, 6, "SET_CAMERA" }, - { 13, 2, "DATA_CAMERA" }, - { 14, 2, "CHANGE_FIELD" }, - { 15, 1, "HIDE_FIELD" }, - { 16, 3, "MOVE_FIELD" }, - { 17, 2, "FADEOUT_FIELD" }, - { 18, 3, "EYE_ANIM" }, - { 19, 5, "MOUTH_ANIM" }, - { 20, 5, "HAND_ANIM" }, - { 21, 4, "LOOK_ANIM" }, - { 22, 4, "EXPRESSION" }, - { 23, 5, "LOOK_CAMERA" }, - { 24, 2, "LYRIC" }, - { 25, 0, "MUSIC_PLAY" }, - { 26, 2, "MODE_SELECT" }, - { 27, 4, "EDIT_MOTION" }, - { 28, 2, "BAR_TIME_SET" }, - { 29, 2, "SHADOWHEIGHT" }, - { 30, 1, "EDIT_FACE" }, - { 31, 21, "DUMMY" }, - { 32, 0, "PV_END" }, - { 33, 3, "SHADOWPOS" }, - { 34, 2, "EDIT_LYRIC" }, - { 35, 5, "EDIT_TARGET" }, - { 36, 1, "EDIT_MOUTH" }, - { 37, 1, "SET_CHARA" }, - { 38, 7, "EDIT_MOVE" }, - { 39, 1, "EDIT_SHADOW" }, - { 40, 1, "EDIT_EYELID" }, - { 41, 2, "EDIT_EYE" }, - { 42, 1, "EDIT_ITEM" }, - { 43, 2, "EDIT_EFFECT" }, - { 44, 1, "EDIT_DISP" }, - { 45, 2, "EDIT_HAND_ANIM" }, - { 46, 3, "AIM" }, - { 47, 3, "HAND_ITEM" }, - { 48, 1, "EDIT_BLUSH" }, - { 49, 2, "NEAR_CLIP" }, - { 50, 2, "CLOTH_WET" }, - { 51, 3, "LIGHT_ROT" }, - { 52, 6, "SCENE_FADE" }, - { 53, 6, "TONE_TRANS" }, - { 54, 1, "SATURATE" }, - { 55, 1, "FADE_MODE" }, - { 56, 2, "AUTO_BLINK" }, - { 57, 3, "PARTS_DISP" }, - { 58, 1, "TARGET_FLYING_TIME" }, - { 59, 2, "CHARA_SIZE" }, - { 60, 2, "CHARA_HEIGHT_ADJUST" }, - { 61, 4, "ITEM_ANIM" }, - { 62, 4, "CHARA_POS_ADJUST" }, - { 63, 1, "SCENE_ROT" }, - { 64, 2, "EDIT_MOT_SMOOTH_LEN" }, - { 65, 1, "PV_BRANCH_MODE" }, - { 66, 2, "DATA_CAMERA_START" }, - { 67, 1, "MOVIE_PLAY" }, - { 68, 1, "MOVIE_DISP" }, - { 69, 3, "WIND" }, - { 70, 3, "OSAGE_STEP" }, - { 71, 3, "OSAGE_MV_CCL" }, - { 72, 2, "CHARA_COLOR" }, - { 73, 1, "SE_EFFECT" }, - { 74, 2, "CHARA_SHADOW_QUALITY" }, - { 75, 2, "STAGE_SHADOW_QUALITY" }, - { 76, 2, "COMMON_LIGHT" }, - { 77, 2, "TONE_MAP" }, - { 78, 2, "IBL_COLOR" }, - { 79, 2, "REFLECTION" }, - { 80, 3, "CHROMATIC_ABERRATION" }, - { 81, 2, "STAGE_SHADOW" }, - { 82, 2, "REFLECTION_QUALITY" }, - { 83, 2, "PV_END_FADEOUT" }, - { 84, 1, "CREDIT_TITLE" }, - { 85, 1, "BAR_POINT" }, - { 86, 1, "BEAT_POINT" }, - { 87, 0, "RESERVE" }, - { 88, 2, "PV_AUTH_LIGHT_PRIORITY" }, - { 89, 3, "PV_CHARA_LIGHT" }, - { 90, 3, "PV_STAGE_LIGHT" }, - { 91, 11, "TARGET_EFFECT" }, - { 92, 3, "FOG" }, - { 93, 2, "BLOOM" }, - { 94, 3, "COLOR_CORRECTION" }, - { 95, 3, "DOF" }, - { 96, 4, "CHARA_ALPHA" }, - { 97, 1, "AUTO_CAPTURE_BEGIN" }, - { 98, 1, "MANUAL_CAPTURE" }, - { 99, 3, "TOON_EDGE" }, - { 100, 3, "SHIMMER" }, - { 101, 4, "ITEM_ALPHA" }, - { 102, 1, "MOVIE_CUT" }, - { 103, 112, "EDIT_CAMERA_BOX" }, - { 104, 1, "EDIT_STAGE_PARAM" }, - { 105, 1, "EDIT_CHANGE_FIELD" }, - { 106, 7, "MIKUDAYO_ADJUST" }, - { 107, 2, "LYRIC_2" }, - { 108, 2, "LYRIC_READ" }, - { 109, 2, "LYRIC_READ_2" }, - { 110, 5, "ANNOTATION" }, - { 111, 2, "STAGE_EFFECT" }, - { 112, 3, "SONG_EFFECT" }, - { 113, 3, "SONG_EFFECT_ATTACH" }, - { 114, 2, "LIGHT_AUTH" }, - { 115, 2, "FADE" }, - { 116, 2, "SET_STAGE_EFFECT_ENV" }, - { 117, 2, "RESERVE" }, - { 118, 2, "COMMON_EFFECT_AET_FRONT" }, - { 119, 2, "COMMON_EFFECT_AET_FRONT_LOW" }, - { 120, 2, "COMMON_EFFECT_PARTICLE" }, - { 121, 3, "SONG_EFFECT_ALPHA_SORT" }, - { 122, 5, "LOOK_CAMERA_FACE_LIMIT" }, - { 123, 3, "ITEM_LIGHT" }, - { 124, 3, "CHARA_EFFECT" }, - { 125, 2, "MARKER" }, - { 126, 3, "CHARA_EFFECT_CHARA_LIGHT" }, - { 127, 2, "ENABLE_COMMON_LIGHT_TO_CHARA" }, - { 128, 2, "ENABLE_FXAA" }, - { 129, 2, "ENABLE_TEMPORAL_AA" }, - { 130, 2, "ENABLE_REFLECTION" }, - { 131, 2, "BANK_BRANCH" }, - { 132, 2, "BANK_END" }, - { 133, 2, "" }, - { 134, 2, "" }, - { 135, 2, "" }, - { 136, 2, "" }, - { 137, 2, "" }, - { 138, 2, "VR_LIVE_CHARA_MONITOR_UPDATE_Y" }, - { 139, 2, "VR_LIVE_POINT_FINGER" }, - { 140, 2, "VR_LIVE_CHARA_MONITOR" }, - { 141, 2, "VR_LIVE_MOVIE" }, - { 142, 2, "VR_CHEER" }, - { 143, 2, "VR_CHARA_PSMOVE" }, - { 144, 2, "VR_MOVE_PATH" }, - { 145, 2, "VR_SET_BASE" }, - { 146, 2, "VR_TECH_DEMO_EFFECT" }, - { 147, 2, "VR_TRANSFORM" }, - { 148, 2, "GAZE" }, - { 149, 2, "TECH_DEMO_GESUTRE" }, - { 150, 2, "VR_CHEMICAL_LIGHT_COLOR" }, - { 151, 5, "VR_LIVE_MOB" }, - { 152, 9, "VR_LIVE_HAIR_OSAGE" }, - { 153, 9, "VR_LIVE_LOOK_CAMERA" }, - { 154, 5, "VR_LIVE_CHEER" }, - { 155, 3, "VR_LIVE_GESTURE" }, - { 156, 7, "VR_LIVE_CLONE" }, - { 157, 7, "VR_LOOP_EFFECT" }, - { 158, 6, "VR_LIVE_ONESHOT_EFFECT" }, - { 159, 9, "VR_LIVE_PRESENT" }, - { 160, 7, "VR_LIVE_TRANSFORM" }, - { 161, 5, "VR_LIVE_FLY" }, - { 162, 2, "VR_LIVE_CHARA_VOICE" }, + { 0, 0, u8"END" }, + { 1, 1, u8"TIME" }, + { 2, 4, u8"MIKU_MOVE" }, + { 3, 2, u8"MIKU_ROT" }, + { 4, 2, u8"MIKU_DISP" }, + { 5, 2, u8"MIKU_SHADOW" }, + { 6, 12, u8"TARGET" }, + { 7, 4, u8"SET_MOTION" }, + { 8, 2, u8"SET_PLAYDATA" }, + { 9, 6, u8"EFFECT" }, + { 10, 2, u8"FADEIN_FIELD" }, + { 11, 1, u8"EFFECT_OFF" }, + { 12, 6, u8"SET_CAMERA" }, + { 13, 2, u8"DATA_CAMERA" }, + { 14, 2, u8"CHANGE_FIELD" }, + { 15, 1, u8"HIDE_FIELD" }, + { 16, 3, u8"MOVE_FIELD" }, + { 17, 2, u8"FADEOUT_FIELD" }, + { 18, 3, u8"EYE_ANIM" }, + { 19, 5, u8"MOUTH_ANIM" }, + { 20, 5, u8"HAND_ANIM" }, + { 21, 4, u8"LOOK_ANIM" }, + { 22, 4, u8"EXPRESSION" }, + { 23, 5, u8"LOOK_CAMERA" }, + { 24, 2, u8"LYRIC" }, + { 25, 0, u8"MUSIC_PLAY" }, + { 26, 2, u8"MODE_SELECT" }, + { 27, 4, u8"EDIT_MOTION" }, + { 28, 2, u8"BAR_TIME_SET" }, + { 29, 2, u8"SHADOWHEIGHT" }, + { 30, 1, u8"EDIT_FACE" }, + { 31, 21, u8"DUMMY" }, + { 32, 0, u8"PV_END" }, + { 33, 3, u8"SHADOWPOS" }, + { 34, 2, u8"EDIT_LYRIC" }, + { 35, 5, u8"EDIT_TARGET" }, + { 36, 1, u8"EDIT_MOUTH" }, + { 37, 1, u8"SET_CHARA" }, + { 38, 7, u8"EDIT_MOVE" }, + { 39, 1, u8"EDIT_SHADOW" }, + { 40, 1, u8"EDIT_EYELID" }, + { 41, 2, u8"EDIT_EYE" }, + { 42, 1, u8"EDIT_ITEM" }, + { 43, 2, u8"EDIT_EFFECT" }, + { 44, 1, u8"EDIT_DISP" }, + { 45, 2, u8"EDIT_HAND_ANIM" }, + { 46, 3, u8"AIM" }, + { 47, 3, u8"HAND_ITEM" }, + { 48, 1, u8"EDIT_BLUSH" }, + { 49, 2, u8"NEAR_CLIP" }, + { 50, 2, u8"CLOTH_WET" }, + { 51, 3, u8"LIGHT_ROT" }, + { 52, 6, u8"SCENE_FADE" }, + { 53, 6, u8"TONE_TRANS" }, + { 54, 1, u8"SATURATE" }, + { 55, 1, u8"FADE_MODE" }, + { 56, 2, u8"AUTO_BLINK" }, + { 57, 3, u8"PARTS_DISP" }, + { 58, 1, u8"TARGET_FLYING_TIME" }, + { 59, 2, u8"CHARA_SIZE" }, + { 60, 2, u8"CHARA_HEIGHT_ADJUST" }, + { 61, 4, u8"ITEM_ANIM" }, + { 62, 4, u8"CHARA_POS_ADJUST" }, + { 63, 1, u8"SCENE_ROT" }, + { 64, 2, u8"EDIT_MOT_SMOOTH_LEN" }, + { 65, 1, u8"PV_BRANCH_MODE" }, + { 66, 2, u8"DATA_CAMERA_START" }, + { 67, 1, u8"MOVIE_PLAY" }, + { 68, 1, u8"MOVIE_DISP" }, + { 69, 3, u8"WIND" }, + { 70, 3, u8"OSAGE_STEP" }, + { 71, 3, u8"OSAGE_MV_CCL" }, + { 72, 2, u8"CHARA_COLOR" }, + { 73, 1, u8"SE_EFFECT" }, + { 74, 2, u8"CHARA_SHADOW_QUALITY" }, + { 75, 2, u8"STAGE_SHADOW_QUALITY" }, + { 76, 2, u8"COMMON_LIGHT" }, + { 77, 2, u8"TONE_MAP" }, + { 78, 2, u8"IBL_COLOR" }, + { 79, 2, u8"REFLECTION" }, + { 80, 3, u8"CHROMATIC_ABERRATION" }, + { 81, 2, u8"STAGE_SHADOW" }, + { 82, 2, u8"REFLECTION_QUALITY" }, + { 83, 2, u8"PV_END_FADEOUT" }, + { 84, 1, u8"CREDIT_TITLE" }, + { 85, 1, u8"BAR_POINT" }, + { 86, 1, u8"BEAT_POINT" }, + { 87, 0, u8"RESERVE" }, + { 88, 2, u8"PV_AUTH_LIGHT_PRIORITY" }, + { 89, 3, u8"PV_CHARA_LIGHT" }, + { 90, 3, u8"PV_STAGE_LIGHT" }, + { 91, 11, u8"TARGET_EFFECT" }, + { 92, 3, u8"FOG" }, + { 93, 2, u8"BLOOM" }, + { 94, 3, u8"COLOR_CORRECTION" }, + { 95, 3, u8"DOF" }, + { 96, 4, u8"CHARA_ALPHA" }, + { 97, 1, u8"AUTO_CAPTURE_BEGIN" }, + { 98, 1, u8"MANUAL_CAPTURE" }, + { 99, 3, u8"TOON_EDGE" }, + { 100, 3, u8"SHIMMER" }, + { 101, 4, u8"ITEM_ALPHA" }, + { 102, 1, u8"MOVIE_CUT" }, + { 103, 112, u8"EDIT_CAMERA_BOX" }, + { 104, 1, u8"EDIT_STAGE_PARAM" }, + { 105, 1, u8"EDIT_CHANGE_FIELD" }, + { 106, 7, u8"MIKUDAYO_ADJUST" }, + { 107, 2, u8"LYRIC_2" }, + { 108, 2, u8"LYRIC_READ" }, + { 109, 2, u8"LYRIC_READ_2" }, + { 110, 5, u8"ANNOTATION" }, + { 111, 2, u8"STAGE_EFFECT" }, + { 112, 3, u8"SONG_EFFECT" }, + { 113, 3, u8"SONG_EFFECT_ATTACH" }, + { 114, 2, u8"LIGHT_AUTH" }, + { 115, 2, u8"FADE" }, + { 116, 2, u8"SET_STAGE_EFFECT_ENV" }, + { 117, 2, u8"RESERVE" }, + { 118, 2, u8"COMMON_EFFECT_AET_FRONT" }, + { 119, 2, u8"COMMON_EFFECT_AET_FRONT_LOW" }, + { 120, 2, u8"COMMON_EFFECT_PARTICLE" }, + { 121, 3, u8"SONG_EFFECT_ALPHA_SORT" }, + { 122, 5, u8"LOOK_CAMERA_FACE_LIMIT" }, + { 123, 3, u8"ITEM_LIGHT" }, + { 124, 3, u8"CHARA_EFFECT" }, + { 125, 2, u8"MARKER" }, + { 126, 3, u8"CHARA_EFFECT_CHARA_LIGHT" }, + { 127, 2, u8"ENABLE_COMMON_LIGHT_TO_CHARA" }, + { 128, 2, u8"ENABLE_FXAA" }, + { 129, 2, u8"ENABLE_TEMPORAL_AA" }, + { 130, 2, u8"ENABLE_REFLECTION" }, + { 131, 2, u8"BANK_BRANCH" }, + { 132, 2, u8"BANK_END" }, + { 133, 2, u8"" }, + { 134, 2, u8"" }, + { 135, 2, u8"" }, + { 136, 2, u8"" }, + { 137, 2, u8"" }, + { 138, 2, u8"VR_LIVE_CHARA_MONITOR_UPDATE_Y" }, + { 139, 2, u8"VR_LIVE_POINT_FINGER" }, + { 140, 2, u8"VR_LIVE_CHARA_MONITOR" }, + { 141, 2, u8"VR_LIVE_MOVIE" }, + { 142, 2, u8"VR_CHEER" }, + { 143, 2, u8"VR_CHARA_PSMOVE" }, + { 144, 2, u8"VR_MOVE_PATH" }, + { 145, 2, u8"VR_SET_BASE" }, + { 146, 2, u8"VR_TECH_DEMO_EFFECT" }, + { 147, 2, u8"VR_TRANSFORM" }, + { 148, 2, u8"GAZE" }, + { 149, 2, u8"TECH_DEMO_GESUTRE" }, + { 150, 2, u8"VR_CHEMICAL_LIGHT_COLOR" }, + { 151, 5, u8"VR_LIVE_MOB" }, + { 152, 9, u8"VR_LIVE_HAIR_OSAGE" }, + { 153, 9, u8"VR_LIVE_LOOK_CAMERA" }, + { 154, 5, u8"VR_LIVE_CHEER" }, + { 155, 3, u8"VR_LIVE_GESTURE" }, + { 156, 7, u8"VR_LIVE_CLONE" }, + { 157, 7, u8"VR_LOOP_EFFECT" }, + { 158, 6, u8"VR_LIVE_ONESHOT_EFFECT" }, + { 159, 9, u8"VR_LIVE_PRESENT" }, + { 160, 7, u8"VR_LIVE_TRANSFORM" }, + { 161, 5, u8"VR_LIVE_FLY" }, + { 162, 2, u8"VR_LIVE_CHARA_VOICE" }, }; #define DSC_AC101_FUNC_COUNT 36 @@ -2746,7 +2747,7 @@ void dsc::merge(int32_t count, ...) { } } -bool dsc::parse(void* data, size_t size, dsc_type type) { +bool dsc::parse(const void* data, size_t size, dsc_type type) { if (!data || !(size / 4) || type < DSC_AC101 || type > DSC_VRFL) return false; @@ -2837,6 +2838,77 @@ bool dsc::parse(void* data, size_t size, dsc_type type) { return true; } +bool dsc::parse_text(const void* data, size_t size, dsc_type type) { + if (!data || !size || type < DSC_AC101 || type > DSC_VRFL) + return false; + + this->type = type; + + dsc_get_func_id get_func_id = dsc_type_get_dsc_get_func_id(type); + dsc_get_func_length get_func_length = get_dsc_get_func_length(); + dsc_get_func_name get_func_name = dsc_type_get_dsc_get_func_name(type); + + char* buf = 0; + char** lines = 0; + size_t count = 0; + if (!str_utils_text_file_parse(data, size, buf, lines, count)) + return false; + + std::vector data_buf; + + char func_buf[0x200]; + this->data.reserve(count); + for (size_t i = 0; i < count; i++) { + const char* line = lines[i]; + const char* ch = strchr(line, '('); + if (!ch) + continue; + + strncpy_s(func_buf, sizeof(func_buf), line, ch - line); + + int32_t func_id = get_func_id(func_buf); + if (func_id == -1) + continue; + + int32_t func_length = get_func_length(func_id); + const char* func_name = get_func_name(func_id); + + line += utf8_length(func_name) + 1; + + data_buf.clear(); + for (int32_t j = func_length; j > 0; j--) { + const char* ch = strchr(line, ','); + if (!ch) { + ch = strchr(line, ')'); + if (!ch) + break; + } + + strncpy_s(func_buf, sizeof(func_buf), line, ch - line); + + int32_t t; + if (sscanf_s(func_buf, "%d", &t) != 1) + break; + + data_buf.push_back((uint32_t)t); + + line += strlen(func_buf) + 1; + + while (*line == ' ') + line++; + } + + if (func_length != data_buf.size()) + break; + + uint32_t* data = add_func(func_name, func_id, func_length); + memcpy(data, data_buf.data(), sizeof(uint32_t) * func_length); + } + + free_def(buf); + return true; +} + void dsc::unparse(void** data, size_t* size) { if (!data || !size) return; @@ -2931,7 +3003,7 @@ int32_t dsc::calculate_target_flying_time(int32_t bpm, int32_t time_signature) { bool dsc::load_file(void* data, const char* path, const char* file, uint32_t hash) { std::string s = path + std::string(file); - stream dsc_s; + file_stream dsc_s; dsc_s.open(s.c_str(), "rb"); void* dsc_data = force_malloc(dsc_s.length); size_t dsc_length = dsc_s.length; @@ -2940,7 +3012,7 @@ bool dsc::load_file(void* data, const char* path, const char* file, uint32_t has dsc* d = (dsc*)data; bool ret = d->parse(dsc_data, dsc_length, d->type); - free(dsc_data); + free_def(dsc_data); return ret; } diff --git a/src/KKdLib/dsc.hpp b/src/KKdLib/dsc.hpp index 55cfeb46..44f676ac 100644 --- a/src/KKdLib/dsc.hpp +++ b/src/KKdLib/dsc.hpp @@ -292,7 +292,8 @@ struct dsc { dsc_get_func_length get_dsc_get_func_length(); uint32_t* get_func_data(dsc_data* data); void merge(int32_t count, ...); - bool parse(void* data, size_t size, dsc_type type); + bool parse(const void* data, size_t size, dsc_type type); + bool parse_text(const void* data, size_t size, dsc_type type); void rebuild(); void unparse(void** data, size_t* size); diff --git a/src/KKdLib/enbaya.cpp b/src/KKdLib/enbaya.cpp index 5907cc58..ca4df1c1 100644 --- a/src/KKdLib/enbaya.cpp +++ b/src/KKdLib/enbaya.cpp @@ -44,7 +44,7 @@ int32_t enb_process(uint8_t* data_in, uint8_t** data_out, code = enb_initialize(data_in, &play_head); if (code) { - free(*data_out); + free_def(*data_out); return code - 0x10; } @@ -105,7 +105,7 @@ int32_t enb_initialize(uint8_t* data, enb_play_head** play_head) { ph->track_data = force_malloc_s(enb_track, head->track_count); if (!ph->track_data) { - free(ph); + free_def(ph); return -4; } @@ -119,8 +119,8 @@ void enb_free(enb_play_head** play_head) { if (!play_head || !*play_head) return; - free((*play_head)->track_data); - free(*play_head); + free_def((*play_head)->track_data); + free_def(*play_head); *play_head = 0; } @@ -670,16 +670,10 @@ static void enb_calc_track_init(enb_play_head* play_head) { // 0x08A086CC in ULJ C010 = track_data->quat; C020 = track_data->trans; - C100.x = C010.x * S030; - C100.y = C010.y * S030; - C100.z = C010.z * S030; - C100.w = C010.w * S030; + C100 = C010 * S030; + C110 = C020 * S030; - C110.x = C020.x * S030; - C110.y = C020.y * S030; - C110.z = C020.z * S030; - - vec4_normalize(C100, C100); + C100 = quat::normalize(C100); track_data->qt[0].quat = C100; track_data->qt[0].trans = C110; @@ -723,16 +717,10 @@ static void enb_calc_track(enb_play_head* play_head, float_t time, bool forward) C120 = track_data->qt[s0].quat; C130 = track_data->qt[s0].trans; - C100.x = C010.x * S030 + C120.x; - C100.y = C010.y * S030 + C120.y; - C100.z = C010.z * S030 + C120.z; - C100.w = C010.w * S030 + C120.w; + C100 = C010 * S030 + C120; + C110 = C020 * S030 + C130; - C110.x = C020.x * S030 + C130.x; - C110.y = C020.y * S030 + C130.y; - C110.z = C020.z * S030 + C130.z; - - vec4_normalize(C100, C100); + C100 = quat::normalize(C100); track_data->qt[s1].quat = C100; track_data->qt[s1].trans = C110; diff --git a/src/KKdLib/f2/header.cpp b/src/KKdLib/f2/header.cpp index 193378ce..9e64841b 100644 --- a/src/KKdLib/f2/header.cpp +++ b/src/KKdLib/f2/header.cpp @@ -8,18 +8,8 @@ void f2_header_read(stream& s, f2_header* h) { memset(h, 0, sizeof(f2_header)); - switch (s.type) { - case STREAM_FILE: - if (!s.io.stream) - return; - break; - case STREAM_MEMORY: - if (!s.io.data.vec.size()) - return; - break; - default: + if (s.check_null()) return; - } s.read(h, 0x20); if (h->length == 0x40) @@ -27,32 +17,16 @@ void f2_header_read(stream& s, f2_header* h) { } void f2_header_write(stream& s, f2_header* h, bool extended) { - switch (s.type) { - case STREAM_FILE: - if (!s.io.stream) - return; - break; - case STREAM_MEMORY: - break; - default: + if (s.check_null()) return; - } h->length = extended ? 0x40 : 0x20; s.write(h, h->length); } void f2_header_write_end_of_container(stream& s, uint32_t depth) { - switch (s.type) { - case STREAM_FILE: - if (!s.io.stream) - return; - break; - case STREAM_MEMORY: - break; - default: + if (s.check_null()) return; - } f2_header h; memset(&h, 0, sizeof(f2_header)); diff --git a/src/KKdLib/f2/struct.cpp b/src/KKdLib/f2/struct.cpp index a52d81e9..a94fa3dd 100644 --- a/src/KKdLib/f2/struct.cpp +++ b/src/KKdLib/f2/struct.cpp @@ -4,8 +4,9 @@ */ #include "struct.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../divafile.hpp" static void f2_struct_read_data(stream& s, f2_struct* st, f2_header* h); @@ -26,14 +27,15 @@ void f2_struct::read(const char* path) { if (!path) return; - stream s; + file_stream s; s.open(path, "rb"); - if (&s.io.stream) { - divafile::decrypt(s); + if (s.check_not_null()) { + memory_stream ms; + divafile::decrypt(s, ms); f2_header h; - f2_header_read(s, &h); - f2_struct_read_data(s, this, &h); + f2_header_read(ms, &h); + f2_struct_read_data(ms, this, &h); } } @@ -41,14 +43,15 @@ void f2_struct::read(const wchar_t* path) { if (!path) return; - stream s; + file_stream s; s.open(path, L"rb"); - if (&s.io.stream) { - divafile::decrypt(s); + if (s.check_not_null()) { + memory_stream ms; + divafile::decrypt(s, ms); f2_header h; - f2_header_read(s, &h); - f2_struct_read_data(s, this, &h); + f2_header_read(ms, &h); + f2_struct_read_data(ms, this, &h); } } @@ -56,35 +59,37 @@ void f2_struct::read(const void* data, size_t size) { if (!data || !size) return; - stream s; + memory_stream s; s.open(data, size); - if (&s.io.data.data) { - divafile::decrypt(s); + if (s.check_not_null()) { + memory_stream ms; + divafile::decrypt(s, ms); f2_header h; - f2_header_read(s, &h); - f2_struct_read_data(s, this, &h); + f2_header_read(ms, &h); + f2_struct_read_data(ms, this, &h); } } void f2_struct::read(stream& s) { - if (s.io.check_null()) + if (s.check_null()) return; - divafile::decrypt(s); + memory_stream ms; + divafile::decrypt(s, ms); f2_header h; - f2_header_read(s, &h); - f2_struct_read_data(s, this, &h); + f2_header_read(ms, &h); + f2_struct_read_data(ms, this, &h); } void f2_struct::write(const char* path, bool use_depth, bool shift_x) { if (!path) return; - stream s; + file_stream s; s.open(path, "wb"); - if (s.io.stream) { + if (s.check_not_null()) { f2_struct_get_length(this, shift_x); f2_struct_write_inner(s, this, 0, use_depth, shift_x); } @@ -94,9 +99,9 @@ void f2_struct::write(const wchar_t* path, bool use_depth, bool shift_x) { if (!path) return; - stream s; + file_stream s; s.open(path, L"wb"); - if (s.io.stream) { + if (s.check_not_null()) { f2_struct_get_length(this, shift_x); f2_struct_write_inner(s, this, 0, use_depth, shift_x); } @@ -107,7 +112,7 @@ void f2_struct::write(void** data, size_t* size, bool use_depth, bool shift_x) { return; f2_struct_get_length(this, shift_x); - stream s; + memory_stream s; s.open(0, header.data_size + 0x40ULL); f2_struct_write_inner(s, this, 0, use_depth, shift_x); @@ -115,13 +120,13 @@ void f2_struct::write(void** data, size_t* size, bool use_depth, bool shift_x) { } void f2_struct::write(stream& s, bool use_depth, bool shift_x) { - if (s.io.check_null()) + if (s.check_null()) return; - if (s.io.stream || s.type == STREAM_MEMORY) { - f2_struct_get_length(this, shift_x); - f2_struct_write_inner(s, this, 0, use_depth, shift_x); - } + + f2_struct_get_length(this, shift_x); + f2_struct_write_inner(s, this, 0, use_depth, shift_x); + } static void f2_struct_get_length(f2_struct* s, bool shift_x) { diff --git a/src/KKdLib/farc.cpp b/src/KKdLib/farc.cpp index 95aea10a..429a83b1 100644 --- a/src/KKdLib/farc.cpp +++ b/src/KKdLib/farc.cpp @@ -5,6 +5,8 @@ #include "farc.hpp" #include "io/path.hpp" +#include "io/file_stream.hpp" +#include "io/memory_stream.hpp" #include "aes.hpp" #include "deflate.hpp" #include "hash.hpp" @@ -24,12 +26,15 @@ 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, farc_file* ff); static void farc_unpack_file(farc* f, stream& s, farc_file* ff, bool save = false, char* temp_path = 0, size_t dir_len = 0); +static void farc_write_padding(farc* f, stream& s, size_t size, bool x = false); farc::farc() : flags(), ft() { signature = FARC_FArC; compression_level = 12; + alignment = 0x10; } farc::~farc() { @@ -37,13 +42,13 @@ farc::~farc() { } farc_file::farc_file() : offset(), size(), size_compressed(), -data(), data_compressed(), compressed(), encrypted(), data_changed() { +data(), data_compressed(), flags(), data_changed() { } farc_file::~farc_file() { - free(data); - free(data_compressed); + free_def(data); + free_def(data_compressed); } void farc::add_file(const char* name) { @@ -66,7 +71,7 @@ void farc::add_file(const char* name) { data_temp[i * 2 + 0] = 0; data_temp[i * 2 + 1] = 0; } - free(data_temp); + free_def(data_temp); } void farc::add_file(const wchar_t* name) { @@ -83,7 +88,7 @@ void farc::add_file(const wchar_t* name) { if (name) { char* name_temp = utf16_to_utf8(name); files.back().name = name_temp; - free(name_temp); + free_def(name_temp); } for (size_t i = 0; i < files_count; i++) { @@ -92,7 +97,7 @@ void farc::add_file(const wchar_t* name) { data_temp[i * 2 + 0] = 0; data_temp[i * 2 + 1] = 0; } - free(data_temp); + free_def(data_temp); } const char* farc::get_file_name(uint32_t hash) { @@ -179,7 +184,7 @@ void farc::read(const char* path, bool unpack, bool save) { wchar_t* path_buf = utf8_to_utf16(path); read(path_buf, unpack, save); - free(path_buf); + free_def(path_buf); } void farc::read(const wchar_t* path, bool unpack, bool save) { @@ -201,15 +206,15 @@ void farc::read(const wchar_t* path, bool unpack, bool save) { size_t dir_temp_len = utf8_length(dir_temp); file_path = std::string(dir_temp, dir_temp_len); directory_path = std::string(dir_temp, dir_temp_len); - free(dir_temp); + free_def(dir_temp); const char* dot = strrchr(directory_path.c_str(), '.'); if (dot) directory_path = directory_path.substr(0, dot - directory_path.c_str()); - stream s; + file_stream s; s.open(file_path.c_str(), "rb"); - if (s.io.stream && !farc_read_header(this, s) && unpack) + if (s.check_not_null() && !farc_read_header(this, s) && unpack) farc_unpack_files(this, s, save); } @@ -223,7 +228,7 @@ void farc::read(const void* data, size_t size, bool unpack) { file_path = {}; directory_path = {}; - stream s; + memory_stream s; s.open(data, size); if (!farc_read_header(this, s) && unpack) farc_unpack_files(this, s, false); @@ -234,21 +239,11 @@ farc_file* farc::read_file(const char* name) { return 0; uint32_t name_hash = hash_utf8_murmurhash(name); - for (farc_file& i : files) { - if (hash_string_murmurhash(i.name) != name_hash) - continue; - - if (!i.data && i.data_compressed) - deflate::decompress(i.data_compressed, i.size_compressed, - &i.data, &i.size, deflate::MODE_GZIP); - else if (!i.data) { - stream s; - s.open(file_path.c_str(), "rb"); - if (s.io.stream) - farc_unpack_file(this, s, &i); + for (farc_file& i : files) + if (hash_string_murmurhash(i.name) == name_hash) { + farc_unpack_file(this, &i); + return &i; } - return &i; - } return 0; } @@ -257,21 +252,11 @@ farc_file* farc::read_file(const wchar_t* name) { return 0; uint32_t name_hash = hash_utf16_murmurhash(name); - for (farc_file& i : files) { - if (hash_string_murmurhash(i.name) != name_hash) - continue; - - if (!i.data && i.data_compressed) - deflate::decompress(i.data_compressed, i.size_compressed, - &i.data, &i.size, deflate::MODE_GZIP); - else if (!i.data) { - stream s; - s.open(file_path.c_str(), "rb"); - if (s.io.stream) - farc_unpack_file(this, s, &i); + for (farc_file& i : files) + if (hash_string_murmurhash(i.name) == name_hash) { + farc_unpack_file(this, &i); + return &i; } - return &i; - } return 0; } @@ -286,19 +271,10 @@ farc_file* farc::read_file(uint32_t hash) { if (t) l_len = t - l_str; - if (hash_murmurhash(l_str, l_len) != hash) - continue; - - if (!i.data && i.data_compressed) - deflate::decompress(i.data_compressed, i.size_compressed, - &i.data, &i.size, deflate::MODE_GZIP); - else if (!i.data) { - stream s; - s.open(file_path.c_str(), "rb"); - if (s.io.stream) - farc_unpack_file(this, s, &i); + if (hash_murmurhash(l_str, l_len) == hash) { + farc_unpack_file(this, &i); + return &i; } - return &i; } return 0; } @@ -309,7 +285,7 @@ void farc::write(const char* path, farc_compress_mode mode, bool get_files) { wchar_t* path_buf = utf8_to_utf16(path); write(path_buf, mode, get_files); - free(path_buf); + free_def(path_buf); } void farc::write(const wchar_t* path, farc_compress_mode mode, bool get_files) { @@ -334,12 +310,12 @@ void farc::write(const wchar_t* path, farc_compress_mode mode, bool get_files) { directory_path = std::string(dir_temp, dir_temp_len); file_path = std::string(dir_temp, dir_temp_len); file_path += ".farc", 6; - free(dir_temp); + free_def(dir_temp); if (!get_files || (get_files && !farc_get_files(this))) { - stream s; + file_stream s; s.open(file_path.c_str(), "wb"); - if (s.io.stream) + if (s.check_not_null()) farc_pack_files(this, s, mode, get_files); } } @@ -351,7 +327,7 @@ void farc::write(void** data, size_t* size, farc_compress_mode mode) { directory_path = {}; file_path = {}; - stream s; + memory_stream s; s.open(); farc_pack_files(this, s, mode, false); } @@ -380,8 +356,7 @@ static errno_t farc_get_files(farc* f) { f->files.clear(); f->files.shrink_to_fit(); - std::vector files; - path_get_files(&files, f->directory_path.c_str()); + std::vector files = path_get_files(f->directory_path.c_str()); if (files.size() < 1) return -1; @@ -398,7 +373,7 @@ static void farc_pack_files(farc* f, stream& s, farc_compress_mode mode, bool ge bool is_a3da = str_utils_compare(ext, ".a3da") == 0; bool is_diva = str_utils_compare(ext, ".diva") == 0; bool is_vag = str_utils_compare(ext, ".vag") == 0; - free(ext); + free_def(ext); if (is_a3da || is_diva || is_vag) { plain = true; @@ -449,14 +424,14 @@ static void farc_pack_files(farc* f, stream& s, farc_compress_mode mode, bool ge } size_t align = header_length + 8; - s.set_position(align_val(align, 0x10), SEEK_SET); + s.set_position(align_val(align, f->alignment), SEEK_SET); size_t dir_len = f->directory_path.size(); aes128_ctx ctx; if (mode == FARC_COMPRESS_FARC_AES || mode == FARC_COMPRESS_FARC_GZIP_AES) aes128_init_ctx(&ctx, key); - f->compression_level = clamp(f->compression_level, 0, 12); + f->compression_level = clamp_def(f->compression_level, 0, 12); if (get_files) { char* temp = force_malloc_s(char, dir_len + 2 + MAX_PATH); memcpy(temp, f->directory_path.c_str(), sizeof(char) * dir_len); @@ -469,11 +444,10 @@ static void farc_pack_files(farc* f, stream& s, farc_compress_mode mode, bool ge i.offset = s.get_position(); - stream s_t; + file_stream s_t; s_t.open(temp, "rb"); - if (!s_t.io.stream) { + if (s_t.check_null()) continue; - } s_t.set_position(0, SEEK_END); size_t file_len = s_t.get_position(); @@ -488,20 +462,24 @@ static void farc_pack_files(farc* f, stream& s, farc_compress_mode mode, bool ge void* t1; size_t t1_len; if (mode == FARC_COMPRESS_FARC_GZIP_AES) { - deflate::compress(t, file_len, &t1, &t1_len, - f->compression_level, deflate::MODE_GZIP); - free(t); + if (!i.data_compressed || i.data_changed) { + free_def(i.data_compressed); + deflate::compress_gzip(i.data, file_len, &i.data_compressed, + &i.size_compressed, f->compression_level, i.name.c_str()); + } + t1 = i.data_compressed; + t1_len = i.size_compressed; } else { - t1 = t; - t1_len = file_len; + free_def(i.data_compressed); + t1 = i.data; + t1_len = i.size; } - size_t t2_len = align_val(t1_len, 0x10); + size_t t2_len = align_val(t1_len, f->alignment); size_t a = t2_len - t1_len; void* t2 = force_malloc(t2_len); memcpy(t2, t1, t1_len); - free(t1); for (size_t j = 0; j < a; j++) ((uint8_t*)t2)[t1_len + j] = 0x78; @@ -509,33 +487,27 @@ static void farc_pack_files(farc* f, stream& s, farc_compress_mode mode, bool ge aes128_ecb_encrypt_buffer(&ctx, (uint8_t*)t2, t2_len); s.write(t2, t2_len); - i.size_compressed = t1_len; - t = t2; + free_def(t2); } else if (mode == FARC_COMPRESS_FArC || mode == FARC_COMPRESS_FARC_GZIP) { - void* t1; - size_t t1_len; - deflate::compress(t, file_len, &t1, &t1_len, - f->compression_level, deflate::MODE_GZIP); - free(t); - s.write(t1, t1_len); - size_t a = align_val(t1_len, 0x10) - t1_len; - for (size_t j = 0; j < a; j++) - s.write_uint8_t(0x78); - i.size_compressed = t1_len; - t = t1; + if (!i.data_compressed || i.data_changed) { + free_def(i.data_compressed); + deflate::compress_gzip(i.data, file_len, &i.data_compressed, + &i.size_compressed, f->compression_level, i.name.c_str()); + } + s.write(i.data_compressed, i.size_compressed); + farc_write_padding(f, s, i.size_compressed, mode != FARC_COMPRESS_FArc); } else { - s.write(t, file_len); - size_t a = align_val(file_len, 0x10) - file_len; - for (size_t j = 0; j < a; j++) - s.write_uint8_t(0x00); + free_def(i.data_compressed); + s.write(i.data, file_len); + farc_write_padding(f, s, i.size_compressed); } - free(t); + free_def(t); i.data = 0; i.data_changed = false; } - free(temp); + free_def(temp); } else for (farc_file& i : f->files) { @@ -547,20 +519,20 @@ static void farc_pack_files(farc* f, stream& s, farc_compress_mode mode, bool ge size_t t1_len; if (mode == FARC_COMPRESS_FARC_GZIP_AES) { if (!i.data_compressed || i.data_changed) { - free(i.data_compressed); - deflate::compress(i.data, file_len, &i.data_compressed, - &i.size_compressed, f->compression_level, deflate::MODE_GZIP); + free_def(i.data_compressed); + deflate::compress_gzip(i.data, file_len, &i.data_compressed, + &i.size_compressed, f->compression_level, i.name.c_str()); } t1 = i.data_compressed; t1_len = i.size_compressed; } else { - free(i.data_compressed); + free_def(i.data_compressed); t1 = i.data; t1_len = i.size; } - size_t t2_len = align_val(t1_len, 0x10); + size_t t2_len = align_val(t1_len, f->alignment); size_t a = t2_len - t1_len; void* t2 = force_malloc(t2_len); memcpy(t2, t1, t1_len); @@ -571,25 +543,21 @@ static void farc_pack_files(farc* f, stream& s, farc_compress_mode mode, bool ge aes128_ecb_encrypt_buffer(&ctx, (uint8_t*)t2, t2_len); s.write(t2, t2_len); - free(t2); + free_def(t2); } else if (mode == FARC_COMPRESS_FArC || mode == FARC_COMPRESS_FARC_GZIP) { if (!i.data_compressed || i.data_changed) { - free(i.data_compressed); - deflate::compress(i.data, file_len, &i.data_compressed, - &i.size_compressed, f->compression_level, deflate::MODE_GZIP); + free_def(i.data_compressed); + deflate::compress_gzip(i.data, file_len, &i.data_compressed, + &i.size_compressed, f->compression_level, i.name.c_str()); } s.write(i.data_compressed, i.size_compressed); - size_t a = align_val(i.size_compressed, 0x10) - i.size_compressed; - for (size_t j = 0; j < a; j++) - s.write_uint8_t(0x78); + farc_write_padding(f, s, i.size_compressed, mode != FARC_COMPRESS_FArc); } else { - free(i.data_compressed); + free_def(i.data_compressed); s.write(i.data, file_len); - size_t a = align_val(file_len, 0x10) - file_len; - for (size_t j = 0; j < a; j++) - s.write_uint8_t(0x00); + farc_write_padding(f, s, i.size_compressed); } i.data_changed = false; } @@ -598,26 +566,26 @@ static void farc_pack_files(farc* f, stream& s, farc_compress_mode mode, bool ge switch (mode) { case FARC_COMPRESS_FArc: default: - s.write_int32_t_reverse_endianness(FARC_FArc, true); - s.write_int32_t_reverse_endianness((int32_t)header_length, true); - s.write_int32_t_reverse_endianness(0x01, true); + s.write_uint32_t_reverse_endianness(FARC_FArc, true); + s.write_uint32_t_reverse_endianness((int32_t)header_length, true); + s.write_uint32_t_reverse_endianness(f->alignment, true); break; case FARC_COMPRESS_FArC: - s.write_int32_t_reverse_endianness(FARC_FArC, true); - s.write_int32_t_reverse_endianness((int32_t)header_length, true); - s.write_int32_t_reverse_endianness(0x01, true); + s.write_uint32_t_reverse_endianness(FARC_FArC, true); + s.write_uint32_t_reverse_endianness((int32_t)header_length, true); + s.write_uint32_t_reverse_endianness(f->alignment, true); break; case FARC_COMPRESS_FARC: case FARC_COMPRESS_FARC_GZIP: case FARC_COMPRESS_FARC_AES: case FARC_COMPRESS_FARC_GZIP_AES: - s.write_int32_t_reverse_endianness(FARC_FARC, true); - s.write_int32_t_reverse_endianness((int32_t)header_length, true); - s.write_int32_t_reverse_endianness(f->flags, true); - s.write_int32_t_reverse_endianness(0x00, true); - s.write_int32_t_reverse_endianness(0x40, true); - s.write_int32_t_reverse_endianness(0x00, true); - s.write_int32_t_reverse_endianness(0x00, true); + s.write_uint32_t_reverse_endianness(FARC_FARC, true); + s.write_uint32_t_reverse_endianness((int32_t)header_length, true); + s.write_uint32_t_reverse_endianness(f->flags, true); + s.write_uint32_t_reverse_endianness(0x00, true); + s.write_uint32_t_reverse_endianness(f->alignment, true); + s.write_uint32_t_reverse_endianness(0x00, true); + s.write_uint32_t_reverse_endianness(0x00, true); break; } @@ -641,55 +609,46 @@ static void farc_pack_files(farc* f, stream& s, farc_compress_mode mode, bool ge s.write_int32_t_reverse_endianness((int32_t)i.offset, true); s.write_int32_t_reverse_endianness((int32_t)i.size, true); } + else if (compressed) + for (farc_file& i : f->files) { + s.write_string_null_terminated(i.name); + s.write_int32_t_reverse_endianness((int32_t)i.offset, true); + s.write_int32_t_reverse_endianness((int32_t)i.size_compressed, true); + s.write_int32_t_reverse_endianness((int32_t)i.size, true); + } else for (farc_file& i : f->files) { s.write_string_null_terminated(i.name); s.write_int32_t_reverse_endianness((int32_t)i.offset, true); - s.write_int32_t_reverse_endianness((int32_t)(compressed ? i.size_compressed : i.size), true); - s.write_int32_t_reverse_endianness((int32_t)(compressed ? i.size : 0), true); + s.write_int32_t_reverse_endianness((int32_t)i.size, true); + s.write_int32_t_reverse_endianness((int32_t)0, true); } - align = align_val(align, 0x10) - align; - if (mode == FARC_COMPRESS_FArc) { - uint8_t padding[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - s.write(padding, align); - } - else { - uint8_t padding[] = { - 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, - 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, - }; - s.write(padding, align); - } + farc_write_padding(f, s, header_length + 0x08, mode != FARC_COMPRESS_FArc); } static errno_t farc_read_header(farc* f, stream& s) { - if (!f || s.io.check_null()) + if (!f || s.check_null()) return -1; s.set_position(0, SEEK_SET); - f->signature = (farc_signature)s.read_int32_t_reverse_endianness(true); + f->signature = (farc_signature)s.read_uint32_t_reverse_endianness(true); if (f->signature != FARC_FArc && f->signature != FARC_FArC && f->signature != FARC_FARC) return -2; f->ft = false; - int32_t header_length = s.read_int32_t_reverse_endianness(true); + uint32_t header_length = s.read_uint32_t_reverse_endianness(true); if (f->signature == FARC_FARC) { - f->flags = (farc_flags)s.read_int32_t_reverse_endianness(true); - s.read_int32_t(); - int32_t alignment = s.read_int32_t_reverse_endianness(true); + f->flags = (farc_flags)s.read_uint32_t_reverse_endianness(true); + s.read_uint32_t(); + uint32_t alignment = s.read_uint32_t_reverse_endianness(true); + bool modern = !!s.read_uint32_t_reverse_endianness(true); - f->ft = (f->flags & FARC_AES) && (alignment & (alignment - 1)); - if (f->ft) { - header_length -= 0x08; - s.set_position(-0x04, SEEK_CUR); - } - else - header_length -= 0x0C; + // If alignment is way too big, then it might be part of IV + f->ft = (f->flags & FARC_AES) && modern && alignment > 0x1000; + s.set_position(0x10, SEEK_SET); + header_length -= 0x08; } f->files.clear(); @@ -710,74 +669,85 @@ static errno_t farc_read_header(farc* f, stream& s) { aes128_cbc_decrypt_buffer(&ctx, dt, header_length); header_length -= ((uint8_t*)dt)[header_length - 1]; // PKCS7 Padding - dt += sizeof(int32_t); } - bool has_per_file_flags = false; + if (f->ft) { + f->alignment = load_reverse_endianness_uint32_t((void*)dt); + uint32_t files_count = load_reverse_endianness_uint32_t((void*)(dt + 8)); + uint32_t entry_size = load_reverse_endianness_uint32_t((void*)(dt + 12)); + dt += sizeof(uint32_t) * 4; + + f->files.clear(); + f->files.reserve(files_count); + while ((dt - d_t < header_length + 0x08LL) && files_count) { + size_t length = 0; + while (dt[length]) + length++; + + farc_file ff; + ff.name = std::string((const char*)dt, length); + dt += length + 1; + ff.offset = (size_t)load_reverse_endianness_uint32_t((void*)dt); + ff.size_compressed = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 4)); + ff.size = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 8)); + ff.flags = (farc_flags)load_reverse_endianness_uint32_t((void*)(dt + 12)); + dt += entry_size; + files_count--; + } + + free_def(d_t); + return 0; + } + + size_t entry_size; if (f->signature == FARC_FARC) { - if (load_reverse_endianness_int32_t((void*)dt) == 1) { - dt += sizeof(int32_t); - length = load_reverse_endianness_int32_t((void*)dt); - has_per_file_flags = true; - } - dt += sizeof(int32_t); - } - dt += sizeof(int32_t); + f->alignment = load_reverse_endianness_uint32_t((void*)dt); + uint32_t entry_offset = load_reverse_endianness_uint32_t((void*)(dt + 4)); + uint32_t header_offset = load_reverse_endianness_uint32_t((void*)(dt + 8)); + dt += sizeof(uint32_t) * 3; - 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 += size; - count++; - } - dt = position; - length = (int32_t)count; + entry_size = sizeof(uint32_t) * 3 + entry_offset; } + else if (f->signature != FARC_FArc) { + f->alignment = load_reverse_endianness_uint32_t((void*)dt); + dt += sizeof(uint32_t); + + entry_size = sizeof(uint32_t) * 3; + } + else { + f->alignment = load_reverse_endianness_uint32_t((void*)dt); + dt += sizeof(uint32_t); + + entry_size = sizeof(uint32_t) * 2; + } + + size_t count = 0; + uint8_t* position = dt; + + while (dt - d_t < header_length) { + while (*dt++); + dt += entry_size; + count++; + } + dt = position; bool encrypted = !!(f->flags & FARC_AES); f->files.clear(); - f->files.resize(length); - if (has_per_file_flags) + f->files.resize(count); + if (f->signature != FARC_FArc) for (farc_file& i : f->files) { size_t length = 0; while (dt[length]) length++; i.name = std::string((const char*)dt, length); dt += length + 1; - i.offset = (size_t)load_reverse_endianness_int32_t((void*)dt); - i.size_compressed = (size_t)load_reverse_endianness_int32_t((void*)(dt + 4)); - i.size = (size_t)load_reverse_endianness_int32_t((void*)(dt + 8)); - farc_flags flags = (farc_flags)load_reverse_endianness_int32_t((void*)(dt + 12)); + i.offset = (size_t)load_reverse_endianness_uint32_t((void*)dt); + i.size_compressed = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 4)); + i.size = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 8)); - i.compressed = !!i.size || !!(flags & FARC_GZIP); - i.encrypted = encrypted || !!(flags & FARC_AES); - dt += sizeof(int32_t) * 4; - } - else if (f->signature != FARC_FArc) - for (farc_file& i : f->files) { - size_t length = 0; - while (dt[length]) - length++; - i.name = std::string((const char*)dt, length); - dt += length + 1; - i.offset = (size_t)load_reverse_endianness_int32_t((void*)dt); - i.size_compressed = (size_t)load_reverse_endianness_int32_t((void*)(dt + 4)); - i.size = (size_t)load_reverse_endianness_int32_t((void*)(dt + 8)); - - i.compressed = !!i.size; - i.encrypted = encrypted; - dt += sizeof(int32_t) * 3; + i.flags = (farc_flags)((encrypted ? FARC_AES : 0) | (!!i.size ? FARC_GZIP : 0)); + dt += entry_size; } else for (farc_file& i : f->files) { @@ -786,20 +756,20 @@ static errno_t farc_read_header(farc* f, stream& s) { length++; i.name = std::string((const char*)dt, length); dt += length + 1; - i.offset = (size_t)load_reverse_endianness_int32_t((void*)dt); - i.size = (size_t)load_reverse_endianness_int32_t((void*)(dt + 4)); + i.offset = (size_t)load_reverse_endianness_uint32_t((void*)dt); + i.size = (size_t)load_reverse_endianness_uint32_t((void*)(dt + 4)); i.size_compressed = 0; - i.compressed = false; - i.encrypted = false; + i.flags = (farc_flags)0; dt += sizeof(int32_t) * 2; } - free(d_t); + + free_def(d_t); return 0; } static void farc_unpack_files(farc* f, stream& s, bool save) { - if (!f || s.io.check_null()) + if (!f || s.check_null()) return; size_t max_path_len = 0; @@ -813,7 +783,7 @@ static void farc_unpack_files(farc* f, stream& s, bool save) { if (save) { wchar_t* dir_temp = utf8_to_utf16(f->directory_path.c_str()); CreateDirectoryW(dir_temp, 0); - free(dir_temp); + free_def(dir_temp); } char* temp_path = force_malloc_s(char, max_path_len + 1); @@ -823,15 +793,30 @@ static void farc_unpack_files(farc* f, stream& s, bool save) { for (farc_file& i : f->files) farc_unpack_file(f, s, &i, save, temp_path, dir_len); - free(temp_path); + free_def(temp_path); +} + +static void farc_unpack_file(farc* f, farc_file* ff) { + if (ff->data) + return; + else if (ff->data_compressed) { + deflate::decompress(ff->data_compressed, ff->size_compressed, + &ff->data, &ff->size, deflate::MODE_GZIP); + return; + } + + file_stream s; + s.open(f->file_path.c_str(), "rb"); + if (s.check_not_null()) + farc_unpack_file(f, s, ff); } static void farc_unpack_file(farc* f, stream& s, farc_file* ff, bool save, char* temp_path, size_t dir_len) { - if (!f || s.io.check_null()) + if (!f || s.check_null()) return; if (ff->data) - free(ff->data); + free_def(ff->data); s.set_position(ff->offset, SEEK_SET); @@ -846,13 +831,14 @@ static void farc_unpack_file(farc* f, stream& s, farc_file* ff, bool save, char* deflate::decompress(ff->data_compressed, ff->size_compressed, &ff->data, &ff->size, deflate::MODE_GZIP); } - else if (ff->encrypted || ff->compressed) { - size_t temp_s = ff->encrypted ? align_val(ff->size_compressed, 0x10) : ff->size_compressed; + else if (ff->flags) { + size_t temp_s = ff->flags & FARC_AES + ? align_val(ff->size_compressed, f->alignment) : ff->size_compressed; void* temp = force_malloc(temp_s); s.read(temp, temp_s); void* t = temp; - if (ff->encrypted) + if (ff->flags & FARC_AES) if (f->ft) { temp_s -= 0x10; t = (void*)((uint64_t)t + 0x10); @@ -869,18 +855,18 @@ static void farc_unpack_file(farc* f, stream& s, farc_file* ff, bool save, char* aes128_ecb_decrypt_buffer(&ctx, (uint8_t*)t, temp_s); } - if (!ff->compressed) { - ff->data_compressed = 0; - ff->data = force_malloc(ff->size); - memcpy(ff->data, t, ff->size); - } - else { + if (ff->flags & FARC_GZIP) { ff->data_compressed = force_malloc(ff->size_compressed); memcpy(ff->data_compressed, t, ff->size_compressed); deflate::decompress(ff->data_compressed, ff->size_compressed, &ff->data, &ff->size, deflate::MODE_GZIP); } - free(temp); + else { + ff->data_compressed = 0; + ff->data = force_malloc(ff->size); + memcpy(ff->data, t, ff->size); + } + free_def(temp); } else { ff->data_compressed = 0; @@ -897,17 +883,35 @@ static void farc_unpack_file(farc* f, stream& s, farc_file* ff, bool save, char* memcpy(temp_path + dir_len + 1, ff->name.c_str(), ff->name.size()); temp_path[dir_len + 1 + ff->name.size()] = '\0'; - stream temp_s; + file_stream temp_s; temp_s.open(temp_path, "wb"); - if (temp_s.io.stream) + if (temp_s.check_not_null()) temp_s.write(ff->data, ff->size); } - free(ff->data); + free_def(ff->data); ff->data = 0; } if (ff->data_compressed) { - free(ff->data_compressed); + free_def(ff->data_compressed); ff->data_compressed = 0; } } + +static void farc_write_padding(farc* f, stream& s, size_t size, bool x) { + size_t align = align_val(size, f->alignment) - size; + if (!x) { + uint8_t padding[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + s.write(padding, align); + } + else { + uint8_t padding[] = { + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + }; + s.write(padding, align); + } +} diff --git a/src/KKdLib/farc.hpp b/src/KKdLib/farc.hpp index be24b91a..e3c5cac7 100644 --- a/src/KKdLib/farc.hpp +++ b/src/KKdLib/farc.hpp @@ -8,7 +8,6 @@ #include #include #include "default.hpp" -#include "io/stream.hpp" enum farc_signature { FARC_FArc = 'FArc', @@ -37,8 +36,7 @@ struct farc_file { size_t size_compressed; void* data; void* data_compressed; - bool compressed; - bool encrypted; + farc_flags flags; bool data_changed; farc_file(); @@ -52,6 +50,7 @@ struct farc { farc_signature signature; farc_flags flags; int32_t compression_level; + uint32_t alignment; bool ft; farc(); @@ -65,14 +64,14 @@ struct farc { bool has_file(const char* name); bool has_file(const wchar_t* name); bool has_file(uint32_t hash); - void read(const char* path, bool unpack, bool save); - void read(const wchar_t* path, bool unpack, bool save); - void read(const void* data, size_t size, bool unpack); + void read(const char* path, bool unpack = true, bool save = false); + void read(const wchar_t* path, bool unpack = true, bool save = false); + void read(const void* data, size_t size, bool unpack = true); farc_file* read_file(const char* name); farc_file* read_file(const wchar_t* name); farc_file* read_file(uint32_t hash); - void write(const char* path, farc_compress_mode mode, bool get_files); - void write(const wchar_t* path, farc_compress_mode mode, bool get_files); + void write(const char* path, farc_compress_mode mode, bool get_files = true); + void write(const wchar_t* path, farc_compress_mode mode, bool get_files = true); void write(void** data, size_t* size, farc_compress_mode mode); static bool load_file(void* data, const char* path, const char* file, uint32_t hash); diff --git a/src/KKdLib/half_t.cpp b/src/KKdLib/half_t.cpp index 8483d5a5..0af93ddf 100644 --- a/src/KKdLib/half_t.cpp +++ b/src/KKdLib/half_t.cpp @@ -8,18 +8,6 @@ extern bool f16c; -inline half_t load_reverse_endianness_half_t(void* ptr) { - return (half_t)_byteswap_ushort(*(uint16_t*)ptr); -} - -inline void store_reverse_endianness_half_t(half_t value, void* ptr) { - *(half_t*)ptr = (half_t)_byteswap_ushort((uint16_t)value); -} - -inline half_t reverse_endianness_half_t(half_t value) { - return (half_t)_byteswap_ushort((uint16_t)value); -} - float_t half_to_float(half_t h) { if (f16c) return _mm_cvtss_f32( _mm_cvtph_ps(_mm_cvtsi32_si128((uint16_t)h))); diff --git a/src/KKdLib/half_t.hpp b/src/KKdLib/half_t.hpp index 23615f27..fe765985 100644 --- a/src/KKdLib/half_t.hpp +++ b/src/KKdLib/half_t.hpp @@ -20,9 +20,18 @@ typedef unsigned short half_t; -extern half_t load_reverse_endianness_half_t(void* ptr); -extern void store_reverse_endianness_half_t(half_t value, void* ptr); -extern half_t reverse_endianness_half_t(half_t value); +inline half_t load_reverse_endianness_half_t(void* ptr) { + return (half_t)_byteswap_ushort(*(uint16_t*)ptr); +} + +inline void store_reverse_endianness_half_t(void* ptr, half_t value) { + *(half_t*)ptr = (half_t)_byteswap_ushort((uint16_t)value); +} + +inline half_t reverse_endianness_half_t(half_t value) { + return (half_t)_byteswap_ushort((uint16_t)value); +} + extern float_t half_to_float(half_t h); extern half_t float_to_half(float_t val); extern double_t half_to_double(half_t h); diff --git a/src/KKdLib/hash.cpp b/src/KKdLib/hash.cpp index d3bbf586..743c2f39 100644 --- a/src/KKdLib/hash.cpp +++ b/src/KKdLib/hash.cpp @@ -50,37 +50,26 @@ const uint32_t hash_murmurhash_null = 0x5A009B23; const uint32_t hash_crc16_ccitt_empty = 0xFFFF; string_hash::string_hash() { - hash = hash_murmurhash_empty; + hash_fnv1a64m = hash_fnv1a64m_empty; + hash_murmurhash = hash_murmurhash_empty; } string_hash::string_hash(const char* str) { - this->str = str; - this->hash = hash_string_murmurhash(this->str); -} - -string_hash::string_hash(const char* str, uint32_t hash) { - this->str = str; - this->hash = hash; + this->str.assign(str); + this->hash_fnv1a64m = hash_string_fnv1a64m(this->str); + this->hash_murmurhash = hash_string_murmurhash(this->str); } string_hash::string_hash(std::string& str) { - this->str = str; - this->hash = hash_string_murmurhash(this->str); + this->str.assign(str); + this->hash_fnv1a64m = hash_string_fnv1a64m(this->str); + this->hash_murmurhash = hash_string_murmurhash(this->str); } string_hash::string_hash(std::string&& str) { - this->str = str; - this->hash = hash_string_murmurhash(this->str); -} - -string_hash::string_hash(std::string& str, uint32_t hash) { - this->str = str; - this->hash = hash; -} - -string_hash::string_hash(std::string&& str, uint32_t hash) { - this->str = str; - this->hash = hash; + this->str.assign(str); + this->hash_fnv1a64m = hash_string_fnv1a64m(this->str); + this->hash_murmurhash = hash_string_murmurhash(this->str); } string_hash::~string_hash() { @@ -93,47 +82,23 @@ const char* string_hash::c_str() { // FNV 1a 64-bit Modified // 0x1403B04D0 in SBZV_7.10 -constexpr uint64_t hash_fnv1a64m(const void* data, size_t size, bool make_upper) { +uint64_t hash_fnv1a64m(const void* data, size_t size, bool make_upper) { const uint8_t* d = (const uint8_t*)data; uint64_t hash = 0xCBF29CE484222325; if (data) - if (make_upper) // Modification for only uppercase latin text - for (size_t i = size; i; i--) { - uint8_t a = *d++; - if (a > 0x60 && a < 0x7B) - a -= 0x20; - hash ^= a; - hash *= 0x100000001B3; - } - else - for (size_t i = size; i; i--) { - hash ^= *d++; - hash *= 0x100000001B3; - } + for (size_t i = size; i; i--) { + hash ^= *d++; + hash *= 0x100000001B3; + } return (hash >> 32) ^ hash; // Actual Modification } -constexpr uint64_t hash_utf8_fnv1a64m(const char* data, bool make_upper) { - return hash_fnv1a64m(data, utf8_length(data), make_upper); -} - -inline uint64_t hash_utf16_fnv1a64m(const wchar_t* data, bool make_upper) { - char* temp = utf16_to_utf8(data); - uint64_t hash = hash_fnv1a64m(temp, utf8_length(temp), make_upper); - free(temp); - return hash; -} - -constexpr uint64_t hash_string_fnv1a64m(const std::string& data, bool make_upper) { - return hash_fnv1a64m(data.c_str(), data.size(), make_upper); -} - // MurmurHash // 0x814D7A9C in PCSB00554 // 0x8134C304 in PCSB01007 // 0x0069CEA4 in NPEB02013 -constexpr uint32_t hash_murmurhash(const void* data, size_t size, +uint32_t hash_murmurhash(const void* data, size_t size, uint32_t seed, bool upper, bool big_endian) { const uint8_t* d = (const uint8_t*)data; @@ -264,24 +229,9 @@ constexpr uint32_t hash_murmurhash(const void* data, size_t size, return hash; } -constexpr uint32_t hash_utf8_murmurhash(const char* data, uint32_t seed, bool upper) { - return hash_murmurhash(data, utf8_length(data), seed, upper); -} - -inline uint32_t hash_utf16_murmurhash(const wchar_t* data, uint32_t seed, bool upper) { - char* temp = utf16_to_utf8(data); - uint32_t hash = hash_murmurhash(temp, utf8_length(temp), seed, upper); - free(temp); - return hash; -} - -constexpr uint32_t hash_string_murmurhash(const std::string& data, uint32_t seed, bool upper) { - return hash_murmurhash(data.c_str(), data.size(), seed, upper); -} - // CRC16-CCITT // 0x140011A90 in SBZV_7.10 -constexpr uint16_t hash_crc16_ccitt(const void* data, size_t size, bool make_upper) { +uint16_t hash_crc16_ccitt(const void* data, size_t size, bool make_upper) { const uint8_t* d = (const uint8_t*)data; uint16_t hash = 0xFFFF; @@ -297,18 +247,3 @@ constexpr uint16_t hash_crc16_ccitt(const void* data, size_t size, bool make_upp hash = (uint16_t)(hash_crc16_ccitt_table[(hash >> 8) ^ *d++] ^ (hash << 8)); return hash; } - -constexpr uint16_t hash_utf8_crc16_ccitt(const char* data, bool make_upper) { - return hash_crc16_ccitt(data, utf8_length(data), make_upper); -} - -inline uint16_t hash_utf16_crc16_ccitt(const wchar_t* data, bool make_upper) { - char* temp = utf16_to_utf8(data); - uint32_t hash = hash_crc16_ccitt(temp, utf8_length(temp), make_upper); - free(temp); - return hash; -} - -constexpr uint16_t hash_string_crc16_ccitt(const std::string& data, bool make_upper) { - return hash_crc16_ccitt(data.c_str(), data.size(), make_upper); -} diff --git a/src/KKdLib/hash.hpp b/src/KKdLib/hash.hpp index b7be8dec..6f4ea430 100644 --- a/src/KKdLib/hash.hpp +++ b/src/KKdLib/hash.hpp @@ -19,30 +19,64 @@ extern const uint32_t hash_crc16_ccitt_empty; struct string_hash { std::string str; - uint32_t hash; + uint64_t hash_fnv1a64m; + uint32_t hash_murmurhash; string_hash(); string_hash(const char* str); - string_hash(const char* str, uint32_t hash); string_hash(std::string& str); string_hash(std::string&& str); - string_hash(std::string& str, uint32_t hash); - string_hash(std::string&& str, uint32_t hash); ~string_hash(); const char* c_str(); }; -extern constexpr uint64_t hash_fnv1a64m(const void* data, size_t size, bool make_upper = false); -extern constexpr uint64_t hash_utf8_fnv1a64m(const char* data, bool make_upper = false); -extern inline uint64_t hash_utf16_fnv1a64m(const wchar_t* data, bool make_upper = false); -extern constexpr uint64_t hash_string_fnv1a64m(const std::string& data, bool make_upper = false); -extern constexpr uint32_t hash_murmurhash(const void* data, size_t size, +extern uint64_t hash_fnv1a64m(const void* data, size_t size, bool make_upper = false); +extern uint32_t hash_murmurhash(const void* data, size_t size, uint32_t seed = 0, bool upper = false, bool big_endian = false); -extern constexpr uint32_t hash_utf8_murmurhash(const char* data, uint32_t seed = 0, bool upper = false); -extern inline uint32_t hash_utf16_murmurhash(const wchar_t* data, uint32_t seed = 0, bool upper = false); -extern constexpr uint32_t hash_string_murmurhash(const std::string& data, uint32_t seed = 0, bool upper = false); -extern constexpr uint16_t hash_crc16_ccitt(const void* data, size_t size, bool make_upper = false); -extern constexpr uint16_t hash_utf8_crc16_ccitt(const char* data, bool make_upper = false); -extern inline uint16_t hash_utf16_crc16_ccitt(const wchar_t* data, bool make_upper = false); -extern constexpr uint16_t hash_string_crc16_ccitt(const std::string& data, bool make_upper = false); +extern uint16_t hash_crc16_ccitt(const void* data, size_t size, bool make_upper = false); + +inline uint64_t hash_utf8_fnv1a64m(const char* data, bool make_upper = false) { + return hash_fnv1a64m(data, utf8_length(data), make_upper); +} + +inline uint64_t hash_utf16_fnv1a64m(const wchar_t* data, bool make_upper = false) { + char* temp = utf16_to_utf8(data); + uint64_t hash = hash_fnv1a64m(temp, utf8_length(temp), make_upper); + free_def(temp); + return hash; +} + +inline uint64_t hash_string_fnv1a64m(const std::string& data, bool make_upper = false) { + return hash_fnv1a64m(data.c_str(), data.size(), make_upper); +} + +inline uint32_t hash_utf8_murmurhash(const char* data, uint32_t seed = 0, bool upper = false) { + return hash_murmurhash(data, utf8_length(data), seed, upper); +} + +inline uint32_t hash_utf16_murmurhash(const wchar_t* data, uint32_t seed = 0, bool upper = false) { + char* temp = utf16_to_utf8(data); + uint32_t hash = hash_murmurhash(temp, utf8_length(temp), seed, upper); + free_def(temp); + return hash; +} + +inline uint32_t hash_string_murmurhash(const std::string& data, uint32_t seed = 0, bool upper = false) { + return hash_murmurhash(data.c_str(), data.size(), seed, upper); +} + +inline uint16_t hash_utf8_crc16_ccitt(const char* data, bool make_upper = false) { + return hash_crc16_ccitt(data, utf8_length(data), make_upper); +} + +inline uint16_t hash_utf16_crc16_ccitt(const wchar_t* data, bool make_upper = false) { + char* temp = utf16_to_utf8(data); + uint32_t hash = hash_crc16_ccitt(temp, utf8_length(temp), make_upper); + free_def(temp); + return hash; +} + +inline uint16_t hash_string_crc16_ccitt(const std::string& data, bool make_upper = false) { + return hash_crc16_ccitt(data.c_str(), data.size(), make_upper); +} diff --git a/src/KKdLib/image.cpp b/src/KKdLib/image.cpp index e8b13d03..f9075725 100644 --- a/src/KKdLib/image.cpp +++ b/src/KKdLib/image.cpp @@ -4,12 +4,16 @@ */ #include "image.hpp" -; + static rgb565 rgb565_apply_color_tone(rgb565 col, color_tone* col_tone); static void rgb_to_ycc(vec3& rgb, vec3& ycc); static void ycc_apply_col_tone_hue(vec3& ycc, color_tone* col_tone); static void ycc_to_rgb(vec3& ycc, vec3& rgb); +color_tone::color_tone() : hue(), saturation(), value(), contrast(), inverse() { + +} + void dxt1_image_apply_color_tone(int32_t width, int32_t height, int32_t size, dxt1_block* data, color_tone* col_tone) { if (size <= 0) @@ -71,24 +75,20 @@ static rgb565 rgb565_apply_color_tone(rgb565 col, color_tone* col_tone) { rgb.z = (float_t)col.b; } - vec3_mult(rgb, inv_scale, rgb); - vec3_mult(rgb, col_tone->blend, rgb); - vec3_add(rgb, col_tone->offset, rgb); - vec3_clamp_scalar(rgb, 0.0f, 1.0f, rgb); + rgb = vec3::clamp(rgb * inv_scale * col_tone->blend + col_tone->offset, 0.0f, 1.0f); vec3 ycc; rgb_to_ycc(rgb, ycc); - vec2_mult_scalar(*(vec2*)&ycc.y, col_tone->saturation, *(vec2*)&ycc.y); + *(vec2*)&ycc.y = *(vec2*)&ycc.y * col_tone->saturation; ycc_apply_col_tone_hue(ycc, col_tone); ycc.x = (ycc.x + col_tone->value - 0.5f) * col_tone->contrast + 0.5f; - ycc.x = clamp(ycc.x, 0.0f, 1.0f); - vec2_clamp_scalar(*(vec2*)&ycc.y, -0.5f, 0.5f, *(vec2*)&ycc.y); + ycc.x = clamp_def(ycc.x, 0.0f, 1.0f); + *(vec2*)&ycc.y = vec2::clamp(*(vec2*)&ycc.y, -0.5f, 0.5f); ycc_to_rgb(ycc, rgb); - vec3_clamp_scalar(rgb, 0.0f, 1.0f, rgb); - vec3_mult(rgb, scale, rgb); + rgb = vec3::clamp(rgb, 0.0f, 1.0f) * scale; col.r = (uint8_t)rgb.x; col.g = (uint8_t)rgb.y; @@ -101,9 +101,9 @@ inline static void rgb_to_ycc(vec3& rgb, vec3& ycc) { const vec3 _cb_coef_601 = { -0.16874f, -0.33126f, 0.5f }; const vec3 _cr_coef_601 = { 0.5f, -0.41869f, -0.08131f }; - vec3_dot(rgb, _y_coef_601, ycc.x); - vec3_dot(rgb, _cb_coef_601, ycc.y); - vec3_dot(rgb, _cr_coef_601, ycc.z); + ycc.x = vec3::dot(rgb, _y_coef_601); + ycc.y = vec3::dot(rgb, _cb_coef_601); + ycc.z = vec3::dot(rgb, _cr_coef_601); } inline static void ycc_apply_col_tone_hue(vec3& ycc, color_tone* col_tone) { @@ -119,7 +119,7 @@ inline static void ycc_to_rgb(vec3& ycc, vec3& rgb) { const vec3 _grn_coef_601 = { 1.0f, -0.34414f, -0.71414f }; const vec3 _blu_coef_601 = { 1.0f, 1.772f, 0.0f }; - vec3_dot(ycc, _red_coef_601, rgb.x); - vec3_dot(ycc, _grn_coef_601, rgb.y); - vec3_dot(ycc, _blu_coef_601, rgb.z); + rgb.x = vec3::dot(ycc, _red_coef_601); + rgb.y = vec3::dot(ycc, _grn_coef_601); + rgb.z = vec3::dot(ycc, _blu_coef_601); } \ No newline at end of file diff --git a/src/KKdLib/image.hpp b/src/KKdLib/image.hpp index 9d9734e9..16fb1e0c 100644 --- a/src/KKdLib/image.hpp +++ b/src/KKdLib/image.hpp @@ -16,6 +16,8 @@ struct color_tone { float_t value; float_t contrast; bool inverse; + + color_tone(); }; struct rgb565 { diff --git a/src/KKdLib/interpolation.cpp b/src/KKdLib/interpolation.cpp index da4b3af0..c495e8bb 100644 --- a/src/KKdLib/interpolation.cpp +++ b/src/KKdLib/interpolation.cpp @@ -5,199 +5,10 @@ #include "interpolation.hpp" -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 (1.0f - t) * p1 + t * p2; -} - -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; - - const __m128 _1 = _mm_set_ps1(1.0f); - - __m128 df = _mm_sub_ps(_f2, _f1); - __m128 t = _mm_div_ps(_mm_sub_ps(_f, _f1), df); - __m128 t1 = _mm_sub_ps(_1, t); - __m128 val = _mm_add_ps(_mm_mul_ps(_p1, t1), _mm_mul_ps(_p2, 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; - - const __m128 _1 = _mm_set_ps1(1.0f); - - __m128 df = _mm_sub_ps(_f2, _f1); - __m128 t = _mm_div_ps(_mm_sub_ps(_f, _f1), df); - __m128 t1 = _mm_sub_ps(_1, t); - __m128 val = _mm_add_ps(_mm_mul_ps(_p1, t1), _mm_mul_ps(_p2, t)); - *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 = _mm_loadu_ps((float*)p1); - _p2 = _mm_loadu_ps((float*)p2); - _f1 = _mm_loadu_ps((float*)f1); - _f2 = _mm_loadu_ps((float*)f2); - _f = _mm_loadu_ps((float*)f); - - const __m128 _1 = _mm_set_ps1(1.0f); - - __m128 df = _mm_sub_ps(_f2, _f1); - __m128 t = _mm_div_ps(_mm_sub_ps(_f, _f1), df); - __m128 t1 = _mm_sub_ps(_1, t); - _mm_storeu_ps((float*)value, _mm_add_ps(_mm_mul_ps(_p1, t1), _mm_mul_ps(_p2, t))); -} - -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 = _mm_loadu_ps((float*)p1); - _p2 = _mm_loadu_ps((float*)p2); - _t1 = _mm_loadu_ps((float*)t1); - _t2 = _mm_loadu_ps((float*)t2); - _f1 = _mm_loadu_ps((float*)f1); - _f2 = _mm_loadu_ps((float*)f2); - _f = _mm_loadu_ps((float*)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)); - _mm_storeu_ps((float*)value, _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; + float_t& t1, float_t& t2, size_t f1, size_t f2, size_t f) { + t1 = 0.0f; + t2 = 0.0f; if (!arr || length < 2 || f - f1 + 1 >= length || f < 1 || f < f1 || f + 2 > f2) return; @@ -214,13 +25,15 @@ void interpolate_chs_reverse_value(float_t* arr, size_t length, 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); + 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; + float_t& t1, float_t& t2, size_t f1, size_t f2) { + t1 = 0.0f; + t2 = 0.0f; + if (f2 - f1 - 2 < 1) return; @@ -229,17 +42,18 @@ void interpolate_chs_reverse(float_t* arr, size_t length, 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); + 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)); + 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; + float_t& t1, float_t& t2, size_t f1, size_t f2, size_t f, uint8_t step) { + t1 = 0.0f; + t2 = 0.0f; if (!arr || length < 2 || f - f1 + 1 >= length || f < 1 || f < f1 || f + 2 > f2) return; @@ -256,13 +70,15 @@ void interpolate_chs_reverse_step_value(float_t* arr, size_t length, 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); + 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; + float_t& t1, float_t& t2, size_t f1, size_t f2, uint8_t step) { + t1 = 0.0f; + t2 = 0.0f; + if (f2 - f1 - 2 < 1) return; @@ -271,12 +87,12 @@ void interpolate_chs_reverse_step(float_t* arr, size_t length, 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); + 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)); + t1 = (float_t)(tt1 / (double_t)(f2 - f1 - 2)); + t2 = (float_t)(tt2 / (double_t)(f2 - f1 - 2)); } int32_t interpolate_chs_reverse_sequence(std::vector& values_src, std::vector& values) { @@ -350,7 +166,7 @@ int32_t interpolate_chs_reverse_sequence(std::vector& values_src, std:: for (size_t j = 1; j < i; j++) { float_t _t1 = 0.0f; float_t _t2 = 0.0f; - interpolate_chs_reverse_value(a, left_count, &_t1, &_t2, 0, i, j); + interpolate_chs_reverse_value(a, left_count, _t1, _t2, 0, i, j); tt1 += _t1; tt2 += _t2; } @@ -366,7 +182,7 @@ int32_t interpolate_chs_reverse_sequence(std::vector& values_src, std:: } } - if (fabsf(t1) > 1.0f || fabsf(t2) > 1.0f) + if (fabsf(t1) > 0.5f || fabsf(t2) > 0.5f) has_error = true; if (!has_error) { diff --git a/src/KKdLib/interpolation.hpp b/src/KKdLib/interpolation.hpp index 49fdde09..e5f64b03 100644 --- a/src/KKdLib/interpolation.hpp +++ b/src/KKdLib/interpolation.hpp @@ -10,27 +10,200 @@ #include "vec.hpp" #include -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); +inline float_t interpolate_linear_value(const float_t p1, const float_t p2, + const float_t f1, const float_t f2, const float_t f) { + float_t t = (f - f1) / (f2 - f1); + return (1.0f - t) * p1 + t * p2; +} + +inline vec2 interpolate_linear_value(const vec2 p1, const vec2 p2, + const vec2 f1, const vec2 f2, const vec2 f) { + __m128 _p1; + __m128 _p2; + __m128 _f1; + __m128 _f2; + __m128 _f; + _p1 = vec2::load_xmm(p1); + _p2 = vec2::load_xmm(p2); + _f1 = vec2::load_xmm(f1); + _f2 = vec2::load_xmm(f2); + _f = vec2::load_xmm(f); + + const __m128 _1 = vec4::load_xmm(1.0f); + + __m128 df = _mm_sub_ps(_f2, _f1); + __m128 t = _mm_div_ps(_mm_sub_ps(_f, _f1), df); + __m128 t1 = _mm_sub_ps(_1, t); + return vec2::store_xmm(_mm_add_ps(_mm_mul_ps(_p1, t1), _mm_mul_ps(_p2, t))); +} + +inline vec3 interpolate_linear_value(const vec3 p1, const vec3 p2, + const vec3 f1, const vec3 f2, const vec3 f) { + __m128 _p1; + __m128 _p2; + __m128 _f1; + __m128 _f2; + __m128 _f; + _p1 = vec3::load_xmm(p1); + _p2 = vec3::load_xmm(p2); + _f1 = vec3::load_xmm(f1); + _f2 = vec3::load_xmm(f2); + _f = vec3::load_xmm(f); + + const __m128 _1 = vec4::load_xmm(1.0f); + + __m128 df = _mm_sub_ps(_f2, _f1); + __m128 t = _mm_div_ps(_mm_sub_ps(_f, _f1), df); + __m128 t1 = _mm_sub_ps(_1, t); + return vec3::store_xmm(_mm_add_ps(_mm_mul_ps(_p1, t1), _mm_mul_ps(_p2, t))); +} + +inline vec4 interpolate_linear_value(const vec4 p1, const vec4 p2, + const vec4 f1, const vec4 f2, const vec4 f) { + __m128 _p1; + __m128 _p2; + __m128 _f1; + __m128 _f2; + __m128 _f; + _p1 = vec4::load_xmm(p1); + _p2 = vec4::load_xmm(p2); + _f1 = vec4::load_xmm(f1); + _f2 = vec4::load_xmm(f2); + _f = vec4::load_xmm(f); + + const __m128 _1 = vec4::load_xmm(1.0f); + + __m128 df = _mm_sub_ps(_f2, _f1); + __m128 t = _mm_div_ps(_mm_sub_ps(_f, _f1), df); + __m128 t1 = _mm_sub_ps(_1, t); + return vec4::store_xmm(_mm_add_ps(_mm_mul_ps(_p1, t1), _mm_mul_ps(_p2, t))); +} + +inline std::vector interpolate_linear(float_t p1, float_t p2, size_t f1, size_t f2) { + size_t length = f2 - f1 + 1; + std::vector arr(length); + float_t* a = arr.data(); + for (size_t i = 0, j = length; j; i++, j--, a++) + *a = interpolate_linear_value(p1, p2, + (float_t)f1, (float_t)f2, (float_t)(f1 + i)); + return arr; +} + +inline float_t interpolate_chs_value(const float_t p1, const float_t p2, + const float_t t1, const float_t t2, const float_t f1, const float_t f2, const 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 vec2 interpolate_chs_value(const vec2 p1, const vec2 p2, + const vec2 t1, const vec2 t2, const vec2 f1, const vec2 f2, const vec2 f) { + __m128 _p1; + __m128 _p2; + __m128 _t1; + __m128 _t2; + __m128 _f1; + __m128 _f2; + __m128 _f; + _p1 = vec2::load_xmm(p1); + _p2 = vec2::load_xmm(p2); + _t1 = vec2::load_xmm(t1); + _t2 = vec2::load_xmm(t2); + _f1 = vec2::load_xmm(f1); + _f2 = vec2::load_xmm(f2); + _f = vec2::load_xmm(f); + + const __m128 _1 = vec4::load_xmm(1.0f); + const __m128 _2 = vec4::load_xmm(2.0f); + const __m128 _3 = vec4::load_xmm(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)); + return vec2::store_xmm(_mm_add_ps(_mm_add_ps(_p1, delta), tangent)); +} + +inline vec3 interpolate_chs_value(const vec3 p1, const vec3 p2, + const vec3 t1, const vec3 t2, const vec3 f1, const vec3 f2, const vec3 f) { + __m128 _p1; + __m128 _p2; + __m128 _t1; + __m128 _t2; + __m128 _f1; + __m128 _f2; + __m128 _f; + _p1 = vec3::load_xmm(p1); + _p2 = vec3::load_xmm(p2); + _t1 = vec3::load_xmm(t1); + _t2 = vec3::load_xmm(t2); + _f1 = vec3::load_xmm(f1); + _f2 = vec3::load_xmm(f2); + _f = vec3::load_xmm(f); + + const __m128 _1 = vec4::load_xmm(1.0f); + const __m128 _2 = vec4::load_xmm(2.0f); + const __m128 _3 = vec4::load_xmm(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)); + return vec3::store_xmm(_mm_add_ps(_mm_add_ps(_p1, delta), tangent)); +} + +inline vec4 interpolate_chs_value(const vec4 p1, const vec4 p2, + const vec4 t1, const vec4 t2, const vec4 f1, const vec4 f2, const vec4 f) { + __m128 _p1; + __m128 _p2; + __m128 _t1; + __m128 _t2; + __m128 _f1; + __m128 _f2; + __m128 _f; + _p1 = vec4::load_xmm(p1); + _p2 = vec4::load_xmm(p2); + _t1 = vec4::load_xmm(t1); + _t2 = vec4::load_xmm(t2); + _f1 = vec4::load_xmm(f1); + _f2 = vec4::load_xmm(f2); + _f = vec4::load_xmm(f); + + const __m128 _1 = vec4::load_xmm(1.0f); + const __m128 _2 = vec4::load_xmm(2.0f); + const __m128 _3 = vec4::load_xmm(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)); + return vec4::store_xmm(_mm_add_ps(_mm_add_ps(_p1, delta), tangent)); +} + +inline std::vector interpolate_chs(const float_t p1, const float_t p2, + const float_t t1, const float_t t2, const size_t f1, const size_t f2) { + size_t length = f2 - f1 + 1; + std::vector arr(length); + float_t* a = arr.data(); + for (size_t i = 0, j = length; j; i++, j--, a++) + *a = interpolate_chs_value(p1, p2, t1, t2, + (float_t)f1, (float_t)f2, (float_t)(f1 + i)); + return arr; +} + 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); + 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); + 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); + 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); + float_t& t1, float_t& t2, size_t f1, size_t f2, uint8_t step); extern int32_t interpolate_chs_reverse_sequence(std::vector& values_src, std::vector& values); diff --git a/src/KKdLib/io/file_stream.cpp b/src/KKdLib/io/file_stream.cpp new file mode 100644 index 00000000..6fac13d7 --- /dev/null +++ b/src/KKdLib/io/file_stream.cpp @@ -0,0 +1,176 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "file_stream.hpp" +#include + +file_stream::file_stream() : stream() { + +} + +file_stream::~file_stream() { + close(); +} + +int file_stream::flush() { + return fflush(stream); +} + +void file_stream::close() { + if (!this) + return; + + if (stream) { + fflush(stream); + fclose(stream); + stream = 0; + } + stream::close(); +} + +bool file_stream::check_null() { + return !stream; +} + +bool file_stream::check_not_null() { + return !!stream; +} + +void file_stream::align_read(size_t align) { + int64_t position = _ftelli64(stream); + size_t temp_align = align - position % align; + if (align != temp_align) + _fseeki64(stream, position + temp_align, 0); +} + +void file_stream::align_write(size_t align) { + int64_t position = _ftelli64(stream); + size_t temp_align = align - position % align; + if (align != temp_align) { + memset(buf, 0, min_def(sizeof(buf), temp_align)); + size_t i = temp_align; + while (i >= sizeof(buf)) { + fwrite(buf, 1, sizeof(buf), stream); + i -= sizeof(buf); + } + + if (i > 0) + fwrite(buf, 1, i, stream); + } +} + +size_t file_stream::read(size_t count) { + return read((void*)0, count); +} + +size_t file_stream::read(void* buf, size_t count) { + if (!buf) { + int64_t act_count = 0; + while (count > 0) { + act_count += fread(this->buf, 1, min_def(count, sizeof(this->buf)), stream); + count -= sizeof(this->buf); + } + return act_count; + } + else + return fread(buf, 1, count, stream); +} + +size_t file_stream::read(void* buf, size_t size, size_t count) { + if (!buf) { + int64_t act_count = 0; + while (count > 0) { + act_count += fread(this->buf, size, min_def(count, sizeof(this->buf) / size), stream); + count -= sizeof(this->buf); + } + return act_count; + } + else + return fread(buf, size, count, stream); +} + +size_t file_stream::write(size_t count) { + return write((void*)0, count); +} + +size_t file_stream::write(const void* buf, size_t count) { + if (!buf) { + memset(this->buf, 0, sizeof(this->buf)); + int64_t act_count = 0; + while (count > 0) { + act_count += fwrite(this->buf, 1, min_def(count, sizeof(this->buf)), stream); + count -= sizeof(this->buf); + } + return act_count; + } + else + return fwrite(buf, 1, count, stream); +} + +size_t file_stream::write(const void* buf, size_t size, size_t count) { + if (!buf) { + memset(this->buf, 0, sizeof(this->buf)); + int64_t act_count = 0; + while (count > 0) { + act_count += fwrite(this->buf, 1, min_def(count, sizeof(this->buf) / size), stream); + count -= sizeof(this->buf) / size; + } + return act_count; + } + else + return fwrite(buf, size, count, stream); +} + +int32_t file_stream::read_char() { + return fgetc(stream); +} + +int32_t file_stream::write_char(char c) { + return fputc(c, stream); +} + +int64_t file_stream::get_length() { + if (stream) { + size_t temp = _ftelli64(stream); + _fseeki64(stream, 0, SEEK_END); + length = _ftelli64(stream); + _fseeki64(stream, temp, SEEK_SET); + } + else + length = 0; + return length; +} + +int64_t file_stream::get_position() { + return _ftelli64(stream); +} + +int32_t file_stream::set_position(int64_t pos, int32_t seek) { + return _fseeki64(stream, pos, seek); +} + +void file_stream::open(const char* path, const char* mode) { + close(); + + if (!path || !mode) + return; + + wchar_t* temp_path = utf8_to_utf16(path); + wchar_t* temp_mode = utf8_to_utf16(mode); + stream = _wfsopen(temp_path, temp_mode, _SH_DENYNO); + get_length(); + free_def(temp_path); + free_def(temp_mode); +} + +void file_stream::open(const wchar_t* path, const wchar_t* mode) { + close(); + + if (!path || !mode) + return; + + stream = _wfsopen(path, mode, _SH_DENYNO); + get_length(); +} diff --git a/src/KKdLib/io/file_stream.hpp b/src/KKdLib/io/file_stream.hpp new file mode 100644 index 00000000..e95b344f --- /dev/null +++ b/src/KKdLib/io/file_stream.hpp @@ -0,0 +1,39 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "stream.hpp" + +class file_stream : public stream { +private: + FILE* stream; + +public: + file_stream(); + virtual ~file_stream(); + + virtual int flush() override; + virtual void close() override; + virtual bool check_null() override; + virtual bool check_not_null() override; + + virtual void align_read(size_t align) override; + virtual void align_write(size_t align) override; + virtual size_t read(size_t count) override; + virtual size_t read(void* buf, size_t count) override; + virtual size_t read(void* buf, size_t size, size_t count) override; + virtual size_t write(size_t count) override; + virtual size_t write(const void* buf, size_t count) override; + virtual size_t write(const void* buf, size_t size, size_t count) override; + virtual int32_t read_char() override; + virtual int32_t write_char(char c) override; + virtual int64_t get_length() override; + virtual int64_t get_position() override; + virtual int32_t set_position(int64_t pos, int32_t seek) override; + + void open(const char* path, const char* mode); + void open(const wchar_t* path, const wchar_t* mode); +}; diff --git a/src/KKdLib/io/json.cpp b/src/KKdLib/io/json.cpp index 69ba4b9f..68585f37 100644 --- a/src/KKdLib/io/json.cpp +++ b/src/KKdLib/io/json.cpp @@ -16,16 +16,16 @@ struct io_json_read_buffer { static int32_t io_json_read_char(stream& s, io_json_read_buffer* buf); static void io_json_seek(stream& s, io_json_read_buffer* buf, int64_t offset); static void io_json_seek_one(stream& s, io_json_read_buffer* buf); -static void io_json_read_inner(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c); +static void io_json_read_inner(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c); static void io_json_read_digit(stream& s, io_json_read_buffer* buf, int32_t* c, char** dig_buf, char* dig_buf_end); -static void io_json_read_float(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c); +static void io_json_read_float(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c); static uint8_t io_json_read_string_hex(int32_t c); static char* io_json_read_string_inner(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c); -static void io_json_read_string(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c); -static void io_json_read_map(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c); -static void io_json_read_array(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c); -static void io_json_read_bool(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c); -static void io_json_read_null(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c); +static void io_json_read_string(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c); +static void io_json_read_map(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c); +static void io_json_read_array(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c); +static void io_json_read_bool(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c); +static void io_json_read_null(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c); static void io_json_write_inner(stream& s, msgpack* msg, size_t tabs); static void io_json_write_null(stream& s); static void io_json_write_bool(stream& s, bool val); @@ -39,10 +39,10 @@ static void io_json_write_int64_t(stream& s, int64_t val); static void io_json_write_uint64_t(stream& s, uint64_t val); static void io_json_write_float_t(stream& s, float_t val); static void io_json_write_double_t(stream& s, double_t val); -static void io_json_write_string(stream& s, std::string* val); +static void io_json_write_string(stream& s, std::string& val); void io_json_read(stream& s, msgpack* msg) { - if (!msg || !s.io.stream) + if (!msg || s.check_null()) return; io_json_read_buffer buf; @@ -51,12 +51,19 @@ void io_json_read(stream& s, msgpack* msg) { buf.data[0] = 0; buf.data[IO_JSON_READ_BUF_SIZE - 1] = 0; int32_t c = io_json_read_char(s, &buf); - io_json_read_inner(s, &buf, 0, msg, &c); + io_json_read_inner(s, &buf, msg, &c); +} + +void io_json_write(stream& s, msgpack* msg) { + if (s.check_null() || !msg) + return; + + io_json_write_inner(s, msg, 0); } #define CHECK_WHITESPACE(c) (c == 0x20 || c == 0x0A || c == 0x0D || c == 0x09) -static int32_t io_json_read_char(stream& s, io_json_read_buffer* buf) { +inline static int32_t io_json_read_char(stream& s, io_json_read_buffer* buf) { if (buf->length == 0) { buf->first = 1; buf->data[0] = buf->data[IO_JSON_READ_BUF_SIZE - 1]; @@ -72,7 +79,7 @@ static int32_t io_json_read_char(stream& s, io_json_read_buffer* buf) { return c; } -static void io_json_seek(stream& s, io_json_read_buffer* buf, int64_t offset) { +inline static void io_json_seek(stream& s, io_json_read_buffer* buf, int64_t offset) { if (buf->first < offset || offset >= buf->length - 1LL) { int64_t pos = s.get_position() - buf->length - offset; int64_t off = pos % IO_JSON_READ_BUF_SIZE; @@ -101,38 +108,38 @@ inline static void io_json_seek_one(stream& s, io_json_read_buffer* buf) { buf->length++; } -static void io_json_read_inner(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c) { - *msg = msgpack(name); +static void io_json_read_inner(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c) { + *msg = {}; while (*c != EOF) { if (CHECK_WHITESPACE(*c)) *c = io_json_read_char(s, buf); - if (isdigit(*c)) { - io_json_read_float(s, buf, name, msg, c); + if (*c >= '0' && *c <= '9') { + io_json_read_float(s, buf, msg, c); return; } switch (*c) { case '\"': - io_json_read_string(s, buf, name, msg, c); + io_json_read_string(s, buf, msg, c); break; case '{': - io_json_read_map(s, buf, name, msg, c); + io_json_read_map(s, buf, msg, c); break; case '[': - io_json_read_array(s, buf, name, msg, c); + io_json_read_array(s, buf, msg, c); break; case '-': - io_json_read_float(s, buf, name, msg, c); + io_json_read_float(s, buf, msg, c); break; case 't': - io_json_read_bool(s, buf, name, msg, c); + io_json_read_bool(s, buf, msg, c); break; case 'f': - io_json_read_bool(s, buf, name, msg, c); + io_json_read_bool(s, buf, msg, c); break; case 'n': - io_json_read_null(s, buf, name, msg, c); + io_json_read_null(s, buf, msg, c); break; } return; @@ -141,7 +148,7 @@ static void io_json_read_inner(stream& s, io_json_read_buffer* buf, const char* inline static void io_json_read_digit(stream& s, io_json_read_buffer* buf, int32_t* c, char** dig_buf, char* dig_buf_end) { char* b = *dig_buf; - while (isdigit(*c) && b < dig_buf_end) { + while (*c >= '0' && *c <= '9' && b < dig_buf_end) { *b++ = *c; if ((*c = io_json_read_char(s, buf)) == EOF) break; @@ -149,7 +156,7 @@ inline static void io_json_read_digit(stream& s, io_json_read_buffer* buf, int32 *dig_buf = b; } -static void io_json_read_float(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c) { +static void io_json_read_float(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c) { char dig_buf[0x100]; char* t_buf = dig_buf; char* buf_end = dig_buf + 0x100; @@ -186,9 +193,9 @@ static void io_json_read_float(stream& s, io_json_read_buffer* buf, const char* if (zero && !fraction) { if (negate) - *msg = msgpack(name, -0.0f); + *msg = -0.0f; else - *msg = msgpack(name, 0); + *msg = 0; io_json_seek_one(s, buf); return; } @@ -198,19 +205,19 @@ static void io_json_read_float(stream& s, io_json_read_buffer* buf, const char* return; if (val >= 0x00 && val < 0xFF) - *msg = msgpack(name, (uint8_t)val); + *msg = (uint8_t)val; else if (val >= (int8_t)0x80 && val <= (int8_t)0x7F) - *msg = msgpack(name, (int8_t)val); + *msg = (int8_t)val; else if (val >= 0x0000 && val < 0xFFFF) - *msg = msgpack(name, (uint16_t)val); + *msg = (uint16_t)val; else if (val >= (int16_t)0x8000 && val <= (int16_t)0x7FFF) - *msg = msgpack(name, (int16_t)val); + *msg = (int16_t)val; else if (val >= 0x00000000 && val <= 0xFFFFFFFF) - *msg = msgpack(name, (uint32_t)val); + *msg = (uint32_t)val; else if (val >= (int32_t)0x80000000 && val <= (int32_t)0x7FFFFFFF) - *msg = msgpack(name, (int32_t)val); + *msg = (int32_t)val; else - *msg = msgpack(name, val); + *msg = val; io_json_seek_one(s, buf); return; } @@ -233,9 +240,9 @@ static void io_json_read_float(stream& s, io_json_read_buffer* buf, const char* return; if ((float_t)val == val) - *msg = msgpack(name, (float_t)val); + *msg = (float_t)val; else - *msg = msgpack(name, val); + *msg = val; io_json_seek_one(s, buf); } @@ -374,10 +381,10 @@ static char* io_json_read_string_inner(stream& s, io_json_read_buffer* buf, msgp return temp; } -inline static void io_json_read_string(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c) { +inline static void io_json_read_string(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c) { char* temp = io_json_read_string_inner(s, buf, msg, c); - *msg = msgpack(name, temp); - free(temp); + *msg = temp; + free_def(temp); } inline static void io_json_read_skip_whitespace(stream& s, io_json_read_buffer* buf, int32_t* c) { @@ -388,10 +395,10 @@ inline static void io_json_read_skip_whitespace(stream& s, io_json_read_buffer* } } -static void io_json_read_map(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c) { +static void io_json_read_map(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c) { size_t i = 0; msgpack m; - msgpack_array map; + msgpack_map map; if (*c != '}') { while (true) { io_json_read_skip_whitespace(s, buf, c); @@ -405,14 +412,14 @@ static void io_json_read_map(stream& s, io_json_read_buffer* buf, const char* na io_json_read_skip_whitespace(s, buf, c); if (*c != ':') { - free(key); + free_def(key); return; } io_json_read_skip_whitespace(s, buf, c); - map.push_back({}); - io_json_read_inner(s, buf, key, &map.back(), c); - free(key); + map.push_back({ key, {} }); + io_json_read_inner(s, buf, &map.back().second, c); + free_def(key); io_json_read_skip_whitespace(s, buf, c); @@ -423,10 +430,10 @@ static void io_json_read_map(stream& s, io_json_read_buffer* buf, const char* na } } - *msg = msgpack(name, false, map); + *msg = map; } -static void io_json_read_array(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c) { +static void io_json_read_array(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c) { size_t i = 0; msgpack m; msgpack_array array; @@ -438,7 +445,7 @@ static void io_json_read_array(stream& s, io_json_read_buffer* buf, const char* break; array.push_back({}); - io_json_read_inner(s, buf, 0, &array.back(), c); + io_json_read_inner(s, buf, &array.back(), c); io_json_read_skip_whitespace(s, buf, c); @@ -449,10 +456,10 @@ static void io_json_read_array(stream& s, io_json_read_buffer* buf, const char* } } - *msg = msgpack(name, true, array); + *msg = array; } -inline static void io_json_read_bool(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c) { +inline static void io_json_read_bool(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c) { if (*c != 't') { if ((*c = io_json_read_char(s, buf)) == EOF || *c != 'a') return; @@ -462,7 +469,7 @@ inline static void io_json_read_bool(stream& s, io_json_read_buffer* buf, const return; if ((*c = io_json_read_char(s, buf)) == EOF || *c != 'e') return; - *msg = msgpack(name, false); + *msg = false; } else { if ((*c = io_json_read_char(s, buf)) == EOF || *c != 'r') @@ -471,11 +478,11 @@ inline static void io_json_read_bool(stream& s, io_json_read_buffer* buf, const return; if ((*c = io_json_read_char(s, buf)) == EOF || *c != 'e') return; - *msg = msgpack(name, true); + *msg = true; } } -inline static void io_json_read_null(stream& s, io_json_read_buffer* buf, const char* name, msgpack* msg, int32_t* c) { +inline static void io_json_read_null(stream& s, io_json_read_buffer* buf, msgpack* msg, int32_t* c) { if ((*c = io_json_read_char(s, buf)) == EOF || *c != 'u') return; if ((*c = io_json_read_char(s, buf)) == EOF || *c != 'l') @@ -483,70 +490,62 @@ inline static void io_json_read_null(stream& s, io_json_read_buffer* buf, const if ((*c = io_json_read_char(s, buf)) == EOF || *c != 'l') return; - *msg = msgpack(name); + *msg = {}; } -void io_json_write(stream& s, msgpack* msg) { - if (!s.io.stream || !msg) - return; - - io_json_write_inner(s, msg, 0); -} - -void io_json_write_inner(stream& s, msgpack* msg, size_t tabs) { - for (size_t i = 0; i < tabs; i++) - s.write(" ", 2); - - if (msg->name.size()) { - io_json_write_string(s, &msg->name); - s.write(": ", 2); - } - +inline static void io_json_write_inner(stream& s, msgpack* msg, size_t tabs) { switch (msg->type) { case MSGPACK_NULL: io_json_write_null(s); break; case MSGPACK_BOOL: - io_json_write_bool(s, *MSGPACK_SELECT_PTR(bool, msg)); + io_json_write_bool(s, msg->data.b); break; case MSGPACK_INT8: { - io_json_write_int8_t(s, *MSGPACK_SELECT_PTR(int8_t, msg)); + io_json_write_int8_t(s, msg->data.i8); } break; case MSGPACK_UINT8: - io_json_write_uint8_t(s, *MSGPACK_SELECT_PTR(uint8_t, msg)); + io_json_write_uint8_t(s, msg->data.u8); break; case MSGPACK_INT16: - io_json_write_int16_t(s, *MSGPACK_SELECT_PTR(int16_t, msg)); + io_json_write_int16_t(s, msg->data.i16); break; case MSGPACK_UINT16: - io_json_write_uint16_t(s, *MSGPACK_SELECT_PTR(uint16_t, msg)); + io_json_write_uint16_t(s, msg->data.u16); break; case MSGPACK_INT32: - io_json_write_int32_t(s, *MSGPACK_SELECT_PTR(int32_t, msg)); + io_json_write_int32_t(s, msg->data.i32); break; case MSGPACK_UINT32: - io_json_write_uint32_t(s, *MSGPACK_SELECT_PTR(uint32_t, msg)); + io_json_write_uint32_t(s, msg->data.u32); break; case MSGPACK_INT64: - io_json_write_int64_t(s, *MSGPACK_SELECT_PTR(int64_t, msg)); + io_json_write_int64_t(s, msg->data.i64); break; case MSGPACK_UINT64: - io_json_write_uint64_t(s, *MSGPACK_SELECT_PTR(uint64_t, msg)); + io_json_write_uint64_t(s, msg->data.u64); break; case MSGPACK_FLOAT: - io_json_write_float_t(s, *MSGPACK_SELECT_PTR(float_t, msg)); + io_json_write_float_t(s, msg->data.f32); break; case MSGPACK_DOUBLE: - io_json_write_double_t(s, *MSGPACK_SELECT_PTR(double_t, msg)); + io_json_write_double_t(s, msg->data.f64); break; case MSGPACK_STRING: - io_json_write_string(s, MSGPACK_SELECT_PTR(std::string, msg)); + io_json_write_string(s, *msg->data.str); break; case MSGPACK_ARRAY: { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, msg); + msgpack_array* ptr = msg->data.arr; + if (!ptr->size()) { + s.write("[]", 2); + break; + } + s.write("[\n", 2); for (msgpack& i : *ptr) { + for (size_t i = 0; i <= tabs; i++) + s.write(" ", 2); io_json_write_inner(s, &i, tabs + 1); if (&i + 1 != ptr->data() + ptr->size()) s.write_char(','); @@ -558,11 +557,20 @@ void io_json_write_inner(stream& s, msgpack* msg, size_t tabs) { s.write_char(']'); } break; case MSGPACK_MAP: { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, msg); + msgpack_map* ptr = msg->data.map; + if (!ptr->size()) { + s.write("{}", 2); + break; + } + s.write("{\n", 2); - for (msgpack& i : *ptr) { - io_json_write_inner(s, &i, tabs + 1); + for (msgpack_key_value& i : *ptr) { + for (size_t i = 0; i <= tabs; i++) + s.write(" ", 2); + io_json_write_string(s, i.first); + s.write(": ", 2); + io_json_write_inner(s, &i.second, tabs + 1); if (&i + 1 != ptr->data() + ptr->size()) s.write_char(','); s.write_char('\n'); @@ -646,10 +654,10 @@ inline static void io_json_write_double_t(stream& s, double_t val) { s.write(temp, len); } -inline static void io_json_write_string(stream& s, std::string* val) { +inline static void io_json_write_string(stream& s, std::string& val) { s.write_char('\"'); - const char* str = val->c_str(); - size_t len = val->size(); + const char* str = val.c_str(); + size_t len = val.size(); for (size_t i = len; i; i--, str++) switch (*str) { case 0x00: diff --git a/src/KKdLib/io/memory_stream.cpp b/src/KKdLib/io/memory_stream.cpp new file mode 100644 index 00000000..737f100e --- /dev/null +++ b/src/KKdLib/io/memory_stream.cpp @@ -0,0 +1,255 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "memory_stream.hpp" + +memory_stream::memory_stream() { + +} + +memory_stream::~memory_stream() { + close(); +} + +int memory_stream::flush() { + return 0; +} + +void memory_stream::close() { + if (!this) + return; + + data.vec.clear(); + data.vec.shrink_to_fit(); + data.data = data.vec.begin(); + stream::close(); +} + +bool memory_stream::check_null() { + return !data.vec.size(); +} + +bool memory_stream::check_not_null() { + return !!data.vec.size(); +} + +void memory_stream::align_read(size_t align) { + size_t position = data.data - data.vec.begin(); + size_t temp_align = align - position % align; + if (align != temp_align) { + size_t pos = data.data - data.vec.begin(); + if (data.vec.size() < (size_t)(pos + temp_align)) { + size_t size = data.vec.size(); + data.vec.resize(pos + temp_align); + data.data = data.vec.begin() + pos; + memset(data.data._Ptr, 0, temp_align); + } + data.data += temp_align; + } +} + +void memory_stream::align_write(size_t align) { + size_t position = data.data - data.vec.begin(); + size_t temp_align = align - position % align; + if (align != temp_align) { + size_t pos = data.data - data.vec.begin(); + if (data.vec.size() < (size_t)(pos + temp_align)) { + size_t size = data.vec.size(); + data.vec.resize(pos + temp_align); + data.data = data.vec.begin() + pos; + memset(data.data._Ptr, 0, temp_align); + } + data.data += temp_align; + } +} + +size_t memory_stream::read(size_t count) { + return read((void*)0, count); +} + +size_t memory_stream::read(void* buf, size_t count) { + if (data.data >= data.vec.end()) + return EOF; + + size_t _count = data.vec.end() - data.data; + if (_count >= count) + _count = count; + if (buf) + memcpy(buf, data.data._Ptr, _count); + data.data += _count; + return _count; +} + +size_t memory_stream::read(void* buf, size_t size, size_t count) { + if (data.data >= data.vec.end()) + return EOF; + + size_t _count = data.vec.end() - data.data; + if (_count >= size * count) + _count = size * count; + if (buf) + memcpy(buf, data.data._Ptr, _count); + data.data += _count; + return _count; +} + +size_t memory_stream::write(size_t count) { + return write((void*)0, count); +} + +size_t memory_stream::write(const void* buf, size_t count) { + size_t pos = data.data - data.vec.begin(); + if (data.vec.size() < pos + count) { + data.vec.resize(pos + count); + data.data = data.vec.begin() + pos; + } + if (buf) + memcpy(data.data._Ptr, buf, count); + else + memset(data.data._Ptr, 0, count); + data.data += count; + return count; +} + +size_t memory_stream::write(const void* buf, size_t size, size_t count) { + size_t pos = data.data - data.vec.begin(); + size_t _count = size * count; + if (data.vec.size() < (size_t)(pos + _count)) { + data.vec.resize(pos + _count); + data.data = data.vec.begin() + pos; + } + if (buf) + memcpy(data.data._Ptr, buf, _count); + else + memset(data.data._Ptr, 0, _count); + data.data += _count; + return _count; +} + +int32_t memory_stream::read_char() { + if (data.data >= data.vec.end()) + return EOF; + return *(data.data++); +} + +int32_t memory_stream::write_char(char c) { + size_t pos = data.data - data.vec.begin(); + if (data.vec.size() < (size_t)(pos + 1)) { + size_t size = data.vec.size(); + data.vec.resize(pos + 1); + data.data = data.vec.begin() + pos; + } + *(data.data++) = c; + return 0; +} + +int64_t memory_stream::get_length() { + length = data.vec.size(); + return length; +} + +int64_t memory_stream::get_position() { + return data.data - data.vec.begin(); +} + +int32_t memory_stream::set_position(int64_t pos, int32_t seek) { + switch (seek) { + case SEEK_SET: { + if (pos < 0) + return EOF; + + if (data.vec.size() < (size_t)pos) { + size_t size = data.vec.size(); + data.vec.resize(pos); + memset(data.vec.data() + size, 0, pos - size); + } + data.data = data.vec.begin() + pos; + } return 0; + case SEEK_CUR: { + if (pos > 0) { + size_t _pos = data.data - data.vec.begin(); + if (data.vec.size() < (size_t)(_pos + pos)) { + size_t size = data.vec.size(); + data.vec.resize(_pos + pos); + memset(data.vec.data() + size, 0, _pos + pos - size); + data.data = data.vec.begin() + _pos; + } + data.data += pos; + } + else if (pos < 0) { + if (data.data - data.vec.begin() < -pos) + return EOF; + else + data.data += pos; + } + } return 0; + case SEEK_END: { + if (pos < 0) + break; + + if (data.vec.size() < (size_t)pos) + break; + + data.data = data.vec.end() - pos; + } return 0; + } + return EOF; +} + +void memory_stream::open() { + close(); + + length = 0; +} + +void memory_stream::open(const void* data, size_t size) { + close(); + + if (!size) { + length = 0; + return; + } + + this->data.vec.clear(); + this->data.vec.resize(size); + if (this->data.vec.data()) + if (data) + memcpy(this->data.vec.data(), data, size); + else + memset(this->data.vec.data(), 0, size); + this->data.data = this->data.vec.begin(); + length = size; +} + +void memory_stream::open(std::vector& data) { + close(); + + if (!data.size()) { + length = 0; + return; + } + + this->data.vec = data; + this->data.data = this->data.vec.begin(); + length = data.size(); +} + +void memory_stream::copy(void** data, size_t* size) { + if (!this || !data || !size) + return; + + *size = this->data.vec.size(); + *data = force_malloc(*size); + memcpy(*data, this->data.vec.data(), *size); +} + +void memory_stream::copy(std::vector& data) { + if (!this) + return; + + size_t length = this->data.vec.size(); + data.resize(length); + memcpy(data.data(), this->data.vec.data(), length); +} diff --git a/src/KKdLib/io/memory_stream.hpp b/src/KKdLib/io/memory_stream.hpp new file mode 100644 index 00000000..5a638cf9 --- /dev/null +++ b/src/KKdLib/io/memory_stream.hpp @@ -0,0 +1,45 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "stream.hpp" + +class memory_stream : public stream { +private: + struct data { + std::vector::iterator data; + std::vector vec; + } data; + +public: + memory_stream(); + virtual ~memory_stream(); + + virtual int flush() override; + virtual void close() override; + virtual bool check_null() override; + virtual bool check_not_null() override; + + virtual void align_read(size_t align) override; + virtual void align_write(size_t align) override; + virtual size_t read(size_t count) override; + virtual size_t read(void* buf, size_t count) override; + virtual size_t read(void* buf, size_t size, size_t count) override; + virtual size_t write(size_t count) override; + virtual size_t write(const void* buf, size_t count) override; + virtual size_t write(const void* buf, size_t size, size_t count) override; + virtual int32_t read_char() override; + virtual int32_t write_char(char c) override; + virtual int64_t get_length() override; + virtual int64_t get_position() override; + virtual int32_t set_position(int64_t pos, int32_t seek) override; + + void open(); + void open(const void* data, size_t size); + void open(std::vector& data); + void copy(void** data, size_t* size); + void copy(std::vector& data); +}; diff --git a/src/KKdLib/io/msgpack.cpp b/src/KKdLib/io/msgpack.cpp index 3c4c868b..54c1a528 100644 --- a/src/KKdLib/io/msgpack.cpp +++ b/src/KKdLib/io/msgpack.cpp @@ -5,10 +5,10 @@ #include "msgpack.hpp" -static void io_msgpack_read_inner(stream& s, const char* name, msgpack* msg); -static void io_msgpack_read_string(stream& s, const char* name, msgpack* msg, size_t length); -static void io_msgpack_read_array(stream& s, const char* name, msgpack* msg, size_t length); -static void io_msgpack_read_map(stream& s, const char* name, msgpack* msg, size_t length); +static void io_msgpack_read_inner(stream& s, msgpack* msg); +static void io_msgpack_read_string(stream& s, msgpack* msg, size_t length); +static void io_msgpack_read_array(stream& s, msgpack* msg, size_t length); +static void io_msgpack_read_map(stream& s, msgpack* msg, size_t length); static void io_msgpack_write_inner(stream& s, msgpack* msg); static void io_msgpack_write_null(stream& s); static void io_msgpack_write_bool(stream& s, bool val); @@ -27,13 +27,23 @@ static void io_msgpack_write_array(stream& s, size_t val); static void io_msgpack_write_map(stream& s, size_t val); void io_msgpack_read(stream& s, msgpack* msg) { - io_msgpack_read_inner(s, 0, msg); + if (s.check_null() || !msg) + return; + + io_msgpack_read_inner(s, msg); } -static void io_msgpack_read_inner(stream& s, const char* name, msgpack* msg) { +void io_msgpack_write(stream& s, msgpack* msg) { + if (s.check_null() || !msg) + return; + + io_msgpack_write_inner(s, msg); +} + +inline static void io_msgpack_read_inner(stream& s, msgpack* msg) { uint8_t type = s.read_uint8_t(); - *msg = msgpack(name); + *msg = {}; switch (type >> 4) { case 0x0: case 0x1: @@ -46,17 +56,17 @@ static void io_msgpack_read_inner(stream& s, const char* name, msgpack* msg) { case 0xE: case 0xF: default: - *msg = msgpack(name, (int8_t)type); + *msg = (int8_t)type; return; case 0x8: - io_msgpack_read_map(s, name, msg, type & 0x0F); + io_msgpack_read_map(s, msg, type & 0x0F); return; case 0x9: - io_msgpack_read_array(s, name, msg, type & 0x0F); + io_msgpack_read_array(s, msg, type & 0x0F); return; case 0xA: case 0xB: - io_msgpack_read_string(s, name, msg, type & 0x1F); + io_msgpack_read_string(s, msg, type & 0x1F); return; case 0xC: case 0xD: @@ -65,10 +75,10 @@ static void io_msgpack_read_inner(stream& s, const char* name, msgpack* msg) { switch (type) { case 0xC2: - *msg = msgpack(name, false); + *msg = false; break; case 0xC3: - *msg = msgpack(name, true); + *msg = true; break; case 0xC4: s.set_position(s.read_uint8_t(), SEEK_CUR); @@ -89,34 +99,34 @@ static void io_msgpack_read_inner(stream& s, const char* name, msgpack* msg) { s.set_position(s.read_uint32_t_reverse_endianness(true) + 1ULL, SEEK_CUR); break; case 0xCA: - *msg = msgpack(name, s.read_float_t_reverse_endianness(true)); + *msg = s.read_float_t_reverse_endianness(true); break; case 0xCB: - *msg = msgpack(name, s.read_double_t_reverse_endianness(true)); + *msg = s.read_double_t_reverse_endianness(true); break; case 0xCC: - *msg = msgpack(name, s.read_uint8_t()); + *msg = s.read_uint8_t(); break; case 0xCD: - *msg = msgpack(name, s.read_uint16_t_reverse_endianness(true)); + *msg = s.read_uint16_t_reverse_endianness(true); break; case 0xCE: - *msg = msgpack(name, s.read_uint32_t_reverse_endianness(true)); + *msg = s.read_uint32_t_reverse_endianness(true); break; case 0xCF: - *msg = msgpack(name, s.read_uint64_t_reverse_endianness(true)); + *msg = s.read_uint64_t_reverse_endianness(true); break; case 0xD0: - *msg = msgpack(name, s.read_int8_t()); + *msg = s.read_int8_t(); break; case 0xD1: - *msg = msgpack(name, s.read_int16_t_reverse_endianness(true)); + *msg = s.read_int16_t_reverse_endianness(true); break; case 0xD2: - *msg = msgpack(name, s.read_int32_t_reverse_endianness(true)); + *msg = s.read_int32_t_reverse_endianness(true); break; case 0xD3: - *msg = msgpack(name, s.read_int64_t_reverse_endianness(true)); + *msg = s.read_int64_t_reverse_endianness(true); break; case 0xD4: s.set_position(2, SEEK_CUR); @@ -134,119 +144,110 @@ static void io_msgpack_read_inner(stream& s, const char* name, msgpack* msg) { s.set_position(17, SEEK_CUR); break; case 0xD9: - io_msgpack_read_string(s, name, msg, s.read_uint8_t()); + io_msgpack_read_string(s, msg, s.read_uint8_t()); break; case 0xDA: - io_msgpack_read_string(s, name, msg, s.read_uint16_t_reverse_endianness(true)); + io_msgpack_read_string(s, msg, s.read_uint16_t_reverse_endianness(true)); break; case 0xDB: - io_msgpack_read_string(s, name, msg, s.read_uint32_t_reverse_endianness(true)); + io_msgpack_read_string(s, msg, s.read_uint32_t_reverse_endianness(true)); break; case 0xDC: - io_msgpack_read_array(s, name, msg, s.read_uint16_t_reverse_endianness(true)); + io_msgpack_read_array(s, msg, s.read_uint16_t_reverse_endianness(true)); break; case 0xDD: - io_msgpack_read_array(s, name, msg, s.read_uint32_t_reverse_endianness(true)); + io_msgpack_read_array(s, msg, s.read_uint32_t_reverse_endianness(true)); break; case 0xDE: - io_msgpack_read_map(s, name, msg, s.read_uint16_t_reverse_endianness(true)); + io_msgpack_read_map(s, msg, s.read_uint16_t_reverse_endianness(true)); break; case 0xDF: - io_msgpack_read_map(s, name, msg, s.read_uint16_t_reverse_endianness(true)); + io_msgpack_read_map(s, msg, s.read_uint16_t_reverse_endianness(true)); break; } } -inline static void io_msgpack_read_string(stream& s, const char* name, msgpack* msg, size_t length) { - std::string str; - str = s.read_string(length); - *msg = msgpack(name, &str); +inline static void io_msgpack_read_string(stream& s, msgpack* msg, size_t length) { + *msg = s.read_string(length); } -inline static void io_msgpack_read_array(stream& s, const char* name, msgpack* msg, size_t length) { - *msg = msgpack(name, true, length); - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, msg); +inline static void io_msgpack_read_array(stream& s, msgpack* msg, size_t length) { + *msg = msgpack_array(); + msgpack_array* ptr = msg->data.arr; + ptr->resize(length); for (size_t i = 0; i < length; i++) - io_msgpack_read_inner(s, 0, &ptr->data()[i]); + io_msgpack_read_inner(s, &ptr->data()[i]); } -inline static void io_msgpack_read_map(stream& s, const char* name, msgpack* msg, size_t length) { - *msg = msgpack(name, false, length); - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, msg); +inline static void io_msgpack_read_map(stream& s, msgpack* msg, size_t length) { + *msg = msgpack_map(); + msgpack_map* ptr = msg->data.map; + ptr->resize(length); for (size_t i = 0; i < length; i++) { msgpack t_m = msgpack(); - io_msgpack_read_inner(s, 0, &t_m); + io_msgpack_read_inner(s, &t_m); - const char* n = 0; if (t_m.type == MSGPACK_STRING) - n = MSGPACK_SELECT(std::string, t_m)->c_str(); + ptr->data()[i].first = t_m.data.str->c_str(); - io_msgpack_read_inner(s, n, &ptr->data()[i]); + io_msgpack_read_inner(s, &ptr->data()[i].second); } } -void io_msgpack_write(stream& s, msgpack* msg) { - if (!s.io.stream || !msg) - return; - - io_msgpack_write_inner(s, msg); -} - -static void io_msgpack_write_inner(stream& s, msgpack* msg) { - if (msg->name.size()) - io_msgpack_write_string(s, msg->name); - +inline static void io_msgpack_write_inner(stream& s, msgpack* msg) { switch (msg->type) { case MSGPACK_NULL: io_msgpack_write_null(s); break; case MSGPACK_BOOL: - io_msgpack_write_bool(s, *MSGPACK_SELECT_PTR(bool, msg)); + io_msgpack_write_bool(s, msg->data.b); break; case MSGPACK_INT8: { - io_msgpack_write_int8_t(s, *MSGPACK_SELECT_PTR(int8_t, msg)); + io_msgpack_write_int8_t(s, msg->data.i8); } break; case MSGPACK_UINT8: - io_msgpack_write_uint8_t(s, *MSGPACK_SELECT_PTR(uint8_t, msg)); + io_msgpack_write_uint8_t(s, msg->data.u8); break; case MSGPACK_INT16: - io_msgpack_write_int16_t(s, *MSGPACK_SELECT_PTR(int16_t, msg)); + io_msgpack_write_int16_t(s, msg->data.i16); break; case MSGPACK_UINT16: - io_msgpack_write_uint16_t(s, *MSGPACK_SELECT_PTR(uint16_t, msg)); + io_msgpack_write_uint16_t(s, msg->data.u16); break; case MSGPACK_INT32: - io_msgpack_write_int32_t(s, *MSGPACK_SELECT_PTR(int32_t, msg)); + io_msgpack_write_int32_t(s, msg->data.i32); break; case MSGPACK_UINT32: - io_msgpack_write_uint32_t(s, *MSGPACK_SELECT_PTR(uint32_t, msg)); + io_msgpack_write_uint32_t(s, msg->data.u32); break; case MSGPACK_INT64: - io_msgpack_write_int64_t(s, *MSGPACK_SELECT_PTR(int64_t, msg)); + io_msgpack_write_int64_t(s, msg->data.i64); break; case MSGPACK_UINT64: - io_msgpack_write_uint64_t(s, *MSGPACK_SELECT_PTR(uint64_t, msg)); + io_msgpack_write_uint64_t(s, msg->data.u64); break; case MSGPACK_FLOAT: - io_msgpack_write_float_t(s, *MSGPACK_SELECT_PTR(float_t, msg)); + io_msgpack_write_float_t(s, msg->data.f32); break; case MSGPACK_DOUBLE: - io_msgpack_write_double_t(s, *MSGPACK_SELECT_PTR(double_t, msg)); + io_msgpack_write_double_t(s, msg->data.f64); break; case MSGPACK_STRING: - io_msgpack_write_string(s, *MSGPACK_SELECT_PTR(std::string, msg)); + io_msgpack_write_string(s, *msg->data.str); break; case MSGPACK_ARRAY: { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, msg); + msgpack_array* ptr = msg->data.arr; io_msgpack_write_array(s, ptr->size()); for (msgpack& i : *ptr) io_msgpack_write_inner(s, &i); } break; case MSGPACK_MAP: { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, msg); + msgpack_map* ptr = msg->data.map; io_msgpack_write_map(s, ptr->size()); - for (msgpack& i : *ptr) - io_msgpack_write_inner(s, &i); + for (msgpack_key_value& i : *ptr) { + io_msgpack_write_string(s, i.first); + io_msgpack_write_inner(s, &i.second); + } } break; } } diff --git a/src/KKdLib/io/path.cpp b/src/KKdLib/io/path.cpp index 3bacb1f1..35afbfda 100644 --- a/src/KKdLib/io/path.cpp +++ b/src/KKdLib/io/path.cpp @@ -9,7 +9,7 @@ bool path_check_path_exists(const char* path) { wchar_t* path_temp = utf8_to_utf16(path); DWORD ftyp = GetFileAttributesW(path_temp); - free(path_temp); + free_def(path_temp); if (ftyp == INVALID_FILE_ATTRIBUTES) return false; else @@ -27,7 +27,7 @@ bool path_check_path_exists(const wchar_t* path) { bool path_check_file_exists(const char* path) { wchar_t* path_temp = utf8_to_utf16(path); DWORD ftyp = GetFileAttributesW(path_temp); - free(path_temp); + free_def(path_temp); if (ftyp == INVALID_FILE_ATTRIBUTES) return false; else @@ -45,7 +45,7 @@ bool path_check_file_exists(const wchar_t* path) { bool path_check_directory_exists(const char* path) { wchar_t* path_temp = utf8_to_utf16(path); DWORD ftyp = GetFileAttributesW(path_temp); - free(path_temp); + free_def(path_temp); if (ftyp == INVALID_FILE_ATTRIBUTES) return false; else @@ -60,136 +60,89 @@ bool path_check_directory_exists(const wchar_t* path) { return ftyp & FILE_ATTRIBUTE_DIRECTORY ? true : false; } -void path_get_files(std::vector* files, const char* path) { - files->clear(); - files->shrink_to_fit(); - +std::vector path_get_files(const char* path) { wchar_t* dir_temp = utf8_to_utf16(path); size_t dir_len = utf16_length(dir_temp); if (!dir_temp) - return; + return {}; - wchar_t* dir; - if (dir_temp[dir_len - 1] != L'\\') { - dir = force_malloc_s(wchar_t, dir_len + 3); - memcpy(dir, dir_temp, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'\\'; - dir[dir_len + 1] = L'*'; - dir[dir_len + 2] = 0; - } - else { - dir = force_malloc_s(wchar_t, dir_len + 2); - memcpy(dir, dir_temp, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'*'; - dir[dir_len + 1] = 0; - } - free(dir_temp); + std::wstring dir; + dir.assign(dir_temp, dir_len); + if (dir.size() && dir.back() != L'\\') + dir.push_back(L'\\'); + dir.push_back(L'*'); + free_def(dir_temp); WIN32_FIND_DATAW fdata; memset(&fdata, 0, sizeof(WIN32_FIND_DATAW)); - HANDLE h = FindFirstFileW(dir, &fdata); - if (h == INVALID_HANDLE_VALUE) { - free(dir); - return; - } + HANDLE h = FindFirstFileW(dir.c_str(), &fdata); + if (h == INVALID_HANDLE_VALUE) + return {}; + std::vector files; do { if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; char* file_temp = utf16_to_utf8(fdata.cFileName); - if (file_temp) - files->push_back(file_temp); - free(file_temp); + if (file_temp) { + files.push_back(file_temp); + free(file_temp); + } } while (FindNextFileW(h, &fdata)); FindClose(h); - free(dir); + return files; } -void path_get_files(std::vector* files, const wchar_t* path) { - files->clear(); - files->shrink_to_fit(); - +std::vector path_get_files(const wchar_t* path) { size_t dir_len = utf16_length(path); - wchar_t* dir; - if (path[dir_len - 1] != L'\\') { - dir = force_malloc_s(wchar_t, dir_len + 3); - memcpy(dir, path, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'\\'; - dir[dir_len + 1] = L'*'; - dir[dir_len + 2] = 0; - } - else { - dir = force_malloc_s(wchar_t, dir_len + 2); - memcpy(dir, path, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'*'; - dir[dir_len + 1] = 0; - } + std::wstring dir; + dir.assign(path, dir_len); + if (dir.size() && dir.back() != L'\\') + dir.push_back(L'\\'); + dir.push_back(L'*'); WIN32_FIND_DATAW fdata; memset(&fdata, 0, sizeof(WIN32_FIND_DATAW)); - HANDLE h = FindFirstFileW(dir, &fdata); - if (h == INVALID_HANDLE_VALUE) { - free(dir); - return; - } + HANDLE h = FindFirstFileW(dir.c_str(), &fdata); + if (h == INVALID_HANDLE_VALUE) + return {}; + std::vector files; do { if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; - std::wstring file = std::wstring(fdata.cFileName); - files->push_back(file); + files.push_back(fdata.cFileName); } while (FindNextFileW(h, &fdata)); FindClose(h); - free(dir); + return files; } -void path_get_directories(std::vector* directories, - const char* path, char** exclude_list, size_t exclude_count) { - directories->clear(); - directories->shrink_to_fit(); - +std::vector path_get_directories( + const char* path, const char** exclude_list, size_t exclude_count) { wchar_t* dir_temp = utf8_to_utf16(path); size_t dir_len = utf16_length(dir_temp); if (!dir_temp) - return; + return {}; - wchar_t* dir; - wchar_t* temp; - if (dir_temp[dir_len - 1] != L'\\') { - dir = force_malloc_s(wchar_t, dir_len + 3); - memcpy(dir, dir_temp, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'\\'; - dir[dir_len + 1] = L'*'; - dir[dir_len + 2] = 0; - - temp = force_malloc_s(wchar_t, dir_len + 2 + MAX_PATH); - memcpy(temp, dir_temp, sizeof(wchar_t) * dir_len); - temp[dir_len] = L'\\'; - dir_len++; - } - else { - dir = force_malloc_s(wchar_t, dir_len + 2); - memcpy(dir, dir_temp, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'*'; - dir[dir_len + 1] = 0; - - temp = force_malloc_s(wchar_t, dir_len + 1 + MAX_PATH); - memcpy(temp, dir_temp, sizeof(wchar_t) * dir_len); - } - free(dir_temp); + std::wstring dir; + std::wstring temp; + dir.assign(dir_temp, dir_len); + if (dir.size() && dir.back() != L'\\') + dir.push_back(L'\\'); + temp.assign(dir); + dir.push_back(L'*'); + free_def(dir_temp); WIN32_FIND_DATAW fdata; memset(&fdata, 0, sizeof(WIN32_FIND_DATAW)); - HANDLE h = FindFirstFileW(dir, &fdata); - if (h == INVALID_HANDLE_VALUE) { - free(dir); - free(temp); - return; - } + HANDLE h = FindFirstFileW(dir.c_str(), &fdata); + if (h == INVALID_HANDLE_VALUE) + return {}; + std::vector directories; do { if (~fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; @@ -199,17 +152,16 @@ void path_get_directories(std::vector* directories, if (exclude_list && exclude_count) { size_t len = utf16_length(fdata.cFileName); - memcpy(temp + dir_len, fdata.cFileName, sizeof(wchar_t) * len); - temp[dir_len + len] = L'\0'; + temp.append(fdata.cFileName, len); + std::string temp_utf8 = utf16_to_utf8(temp); bool exclude = false; - char* temp_utf8 = utf16_to_utf8(temp); for (size_t i = 0; i < exclude_count; i++) - if (!str_utils_compare(exclude_list[i], temp_utf8)) { + if (!temp_utf8.compare(exclude_list[i])) { exclude = true; break; } - free(temp_utf8); + temp.resize(temp.size() - len); if (exclude) continue; @@ -217,54 +169,32 @@ void path_get_directories(std::vector* directories, char* directory_temp = utf16_to_utf8(fdata.cFileName); if (directory_temp) - directories->push_back(directory_temp); - free(directory_temp); + directories.push_back(directory_temp); + free_def(directory_temp); } while (FindNextFileW(h, &fdata)); FindClose(h); - free(temp); - free(dir); + return directories; } -void path_get_directories(std::vector* directories, +std::vector path_get_directories( const wchar_t* path, wchar_t** exclude_list, size_t exclude_count) { - directories->clear(); - directories->shrink_to_fit(); - size_t dir_len = utf16_length(path); - wchar_t* dir; - wchar_t* temp; - if (path[dir_len - 1] != L'\\') { - dir = force_malloc_s(wchar_t, dir_len + 3); - memcpy(dir, path, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'\\'; - dir[dir_len + 1] = L'*'; - dir[dir_len + 2] = 0; - - temp = force_malloc_s(wchar_t, dir_len + 2 + MAX_PATH); - memcpy(temp, path, sizeof(wchar_t) * dir_len); - temp[dir_len] = L'\\'; - dir_len++; - } - else { - dir = force_malloc_s(wchar_t, dir_len + 2); - memcpy(dir, path, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'*'; - dir[dir_len + 1] = 0; - - temp = force_malloc_s(wchar_t, dir_len + 1 + MAX_PATH); - memcpy(temp, path, sizeof(wchar_t) * dir_len); - } + std::wstring dir; + std::wstring temp; + dir.assign(path, dir_len); + if (dir.size() && dir.back() != L'\\') + dir.push_back(L'\\'); + temp.assign(dir); + dir.push_back(L'*'); WIN32_FIND_DATAW fdata; memset(&fdata, 0, sizeof(WIN32_FIND_DATAW)); - HANDLE h = FindFirstFileW(dir, &fdata); - if (h == INVALID_HANDLE_VALUE) { - free(dir); - free(temp); - return; - } + HANDLE h = FindFirstFileW(dir.c_str(), &fdata); + if (h == INVALID_HANDLE_VALUE) + return {}; + std::vector directories; do { if (~fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; @@ -274,71 +204,47 @@ void path_get_directories(std::vector* directories, if (exclude_list && exclude_count) { size_t len = utf16_length(fdata.cFileName); - memcpy(temp + dir_len + 1, fdata.cFileName, sizeof(wchar_t) * len); - temp[dir_len + 1 + len] = L'\0'; + temp.append(fdata.cFileName, len); bool exclude = false; for (size_t i = 0; i < exclude_count; i++) - if (!str_utils_compare(exclude_list[i], temp)) { + if (!temp.compare(exclude_list[i])) { exclude = true; break; } + temp.resize(temp.size() - len); if (exclude) continue; } - std::wstring directory = std::wstring(fdata.cFileName); - directories->push_back(directory); + directories.push_back(fdata.cFileName); } while (FindNextFileW(h, &fdata)); FindClose(h); - free(temp); - free(dir); + return directories; } -void path_get_directories_recursive(std::vector* directories, - const char* path, char** exclude_list, size_t exclude_count) { - directories->clear(); - directories->shrink_to_fit(); - +std::vector path_get_directories_recursive( + const char* path, const char** exclude_list, size_t exclude_count) { wchar_t* dir_temp = utf8_to_utf16(path); size_t dir_len = utf16_length(dir_temp); if (!dir_temp) - return; + return {}; - wchar_t* dir; - wchar_t* temp; - if (dir_temp[dir_len - 1] != L'\\') { - dir = force_malloc_s(wchar_t, dir_len + 3); - memcpy(dir, dir_temp, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'\\'; - dir[dir_len + 1] = L'*'; - dir[dir_len + 2] = 0; - - temp = force_malloc_s(wchar_t, dir_len + 2 + MAX_PATH); - memcpy(temp, dir_temp, sizeof(wchar_t) * dir_len); - temp[dir_len] = L'\\'; - dir_len++; - } - else { - dir = force_malloc_s(wchar_t, dir_len + 2); - memcpy(dir, dir_temp, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'*'; - dir[dir_len + 1] = 0; - - temp = force_malloc_s(wchar_t, dir_len + 1 + MAX_PATH); - memcpy(temp, dir_temp, sizeof(wchar_t) * dir_len); - } - free(dir_temp); + std::wstring dir; + std::wstring temp; + dir.assign(dir_temp, dir_len); + if (dir.size() && dir.back() != L'\\') + dir.push_back(L'\\'); + temp.assign(dir); + dir.push_back(L'*'); + free_def(dir_temp); WIN32_FIND_DATAW fdata; memset(&fdata, 0, sizeof(WIN32_FIND_DATAW)); - HANDLE h = FindFirstFileW(dir, &fdata); - if (h == INVALID_HANDLE_VALUE) { - free(dir); - free(temp); - return; - } + HANDLE h = FindFirstFileW(dir.c_str(), &fdata); + if (h == INVALID_HANDLE_VALUE) + return {}; std::vector temp_vec; do { @@ -350,17 +256,16 @@ void path_get_directories_recursive(std::vector* directories, if (exclude_list && exclude_count) { size_t len = utf16_length(fdata.cFileName); - memcpy(temp + dir_len + 1, fdata.cFileName, sizeof(wchar_t) * len); - temp[dir_len + 1 + len] = L'\0'; + temp.append(fdata.cFileName, len); + std::string temp_utf8 = utf16_to_utf8(temp); bool exclude = false; - char* temp_utf8 = utf16_to_utf8(temp); for (size_t i = 0; i < exclude_count; i++) - if (!str_utils_compare(exclude_list[i], temp_utf8)) { + if (!temp_utf8.compare(exclude_list[i])) { exclude = true; break; } - free(temp_utf8); + temp.resize(temp.size() - len); if (exclude) continue; @@ -368,11 +273,9 @@ void path_get_directories_recursive(std::vector* directories, char* directory_temp = utf16_to_utf8(fdata.cFileName); temp_vec.push_back(directory_temp); - free(directory_temp); + free_def(directory_temp); } while (FindNextFileW(h, &fdata)); FindClose(h); - free(temp); - free(dir); size_t max_len = 0; for (std::string& i : temp_vec) { @@ -381,17 +284,17 @@ void path_get_directories_recursive(std::vector* directories, max_len = len; } - size_t path_length = utf8_length(path); - char* path_temp = force_malloc_s(char, path_length + max_len + 2); - memcpy(path_temp, path, path_length); - path_temp[path_length] = '\\'; + std::vector directories; + std::string path_temp; + path_temp.assign(path); + path_temp += '\\'; for (std::string& i : temp_vec) { - memcpy(&path_temp[path_length + 1], i.c_str(), i.size() + 1); + path_temp.append(i); + std::vector temp = path_get_directories_recursive( + path_temp.c_str(), exclude_list, exclude_count); + path_temp.resize(path_temp.size() - i.size()); - std::vector temp; - path_get_directories_recursive(&temp, path_temp, exclude_list, exclude_count); - - directories->push_back(i); + directories.push_back(i); if (temp.size() < 1) continue; @@ -403,62 +306,34 @@ void path_get_directories_recursive(std::vector* directories, max_len = len; } - size_t sub_path_length = i.size(); - char* sub_path_temp = force_malloc_s(char, sub_path_length + max_len + 1); - if (sub_path_temp) { - memcpy(sub_path_temp, i.c_str(), sub_path_length); - sub_path_temp[sub_path_length] = '\\'; - for (std::string& j : temp) { - memcpy(&sub_path_temp[sub_path_length + 1], j.c_str(), j.size()); - - std::string directory = std::string(sub_path_temp, sub_path_length + 1 + j.size()); - temp_vec.push_back(directory); - } + if (i.size()) { + std::string sub_path_temp; + sub_path_temp.assign(i); + sub_path_temp += '\\'; + for (std::string& j : temp) + directories.push_back(sub_path_temp + j); } - free(sub_path_temp); } - free(path_temp); + return directories; } -void path_get_directories_recursive(std::vector* directories, - const wchar_t* path, wchar_t** exclude_list, size_t exclude_count) { - directories->clear(); - directories->shrink_to_fit(); - +std::vector path_get_directories_recursive( + const wchar_t* path, const wchar_t** exclude_list, size_t exclude_count) { size_t dir_len = utf16_length(path); - wchar_t* dir; - wchar_t* temp; - if (path[dir_len - 1] != L'\\') { - dir = force_malloc_s(wchar_t, dir_len + 3); - memcpy(dir, path, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'\\'; - dir[dir_len + 1] = L'*'; - dir[dir_len + 2] = 0; - - temp = force_malloc_s(wchar_t, dir_len + 2 + MAX_PATH); - memcpy(temp, path, sizeof(wchar_t) * dir_len); - temp[dir_len] = L'\\'; - dir_len++; - } - else { - dir = force_malloc_s(wchar_t, dir_len + 2); - memcpy(dir, path, sizeof(wchar_t) * dir_len); - dir[dir_len] = L'*'; - dir[dir_len + 1] = 0; - - temp = force_malloc_s(wchar_t, dir_len + 1 + MAX_PATH); - memcpy(temp, path, sizeof(wchar_t) * dir_len); - } + std::wstring dir; + std::wstring temp; + dir.assign(path, dir_len); + if (dir.size() && dir.back() != L'\\') + dir.push_back(L'\\'); + temp.assign(dir); + dir.push_back(L'*'); WIN32_FIND_DATAW fdata; memset(&fdata, 0, sizeof(WIN32_FIND_DATAW)); - HANDLE h = FindFirstFileW(dir, &fdata); - if (h == INVALID_HANDLE_VALUE) { - free(dir); - free(temp); - return; - } + HANDLE h = FindFirstFileW(dir.c_str(), &fdata); + if (h == INVALID_HANDLE_VALUE) + return {}; std::vector temp_vec; do { @@ -470,15 +345,15 @@ void path_get_directories_recursive(std::vector* directories, if (exclude_list && exclude_count) { size_t len = utf16_length(fdata.cFileName); - memcpy(temp + dir_len + 1, fdata.cFileName, sizeof(wchar_t) * len); - temp[dir_len + 1 + len] = L'\0'; + temp.append(fdata.cFileName, len); bool exclude = false; for (size_t i = 0; i < exclude_count; i++) - if (!str_utils_compare(exclude_list[i], temp)) { + if (!temp.compare(exclude_list[i])) { exclude = true; break; } + temp.resize(temp.size() - len); if (exclude) continue; @@ -488,8 +363,6 @@ void path_get_directories_recursive(std::vector* directories, temp_vec.push_back(directory); } while (FindNextFileW(h, &fdata)); FindClose(h); - free(temp); - free(dir); size_t max_len = 0; for (std::wstring& i : temp_vec) { @@ -498,17 +371,17 @@ void path_get_directories_recursive(std::vector* directories, max_len = len; } - size_t path_length = utf16_length(path); - wchar_t* path_temp = force_malloc_s(wchar_t, path_length + max_len + 2); - memcpy(path_temp, path, sizeof(wchar_t) * path_length); - path_temp[path_length] = '\\'; + std::vector directories; + std::wstring path_temp; + path_temp.assign(path); + path_temp.push_back(L'\\'); for (std::wstring& i : temp_vec) { - memcpy(&path_temp[path_length + 1], i.c_str(), sizeof(wchar_t) * (i.size() + 1)); + path_temp.append(i); + std::vector temp = path_get_directories_recursive( + path_temp.c_str(), exclude_list, exclude_count); + path_temp.resize(path_temp.size() - i.size()); - std::vector temp; - path_get_directories_recursive(&temp, path_temp, exclude_list, exclude_count); - - directories->push_back(i); + directories.push_back(i); if (temp.size() < 1) continue; @@ -520,19 +393,13 @@ void path_get_directories_recursive(std::vector* directories, max_len = len; } - size_t sub_path_length = i.size(); - wchar_t* sub_path_temp = force_malloc_s(wchar_t, sub_path_length + max_len + 1); - if (sub_path_temp) { - memcpy(sub_path_temp, i.c_str(), sizeof(wchar_t) * sub_path_length); - sub_path_temp[sub_path_length] = '\\'; - for (std::wstring& j : temp) { - memcpy(&sub_path_temp[sub_path_length + 1], j.c_str(), sizeof(wchar_t) * j.size()); - - std::wstring directory = std::wstring(sub_path_temp, sub_path_length + 1 + j.size()); - directories->push_back(directory); - } + if (i.size()) { + std::wstring sub_path_temp; + sub_path_temp.assign(i); + sub_path_temp.push_back(L'\\'); + for (std::wstring& j : temp) + directories.push_back(sub_path_temp + j); } - free(sub_path_temp); } - free(path_temp); + return directories; } diff --git a/src/KKdLib/io/path.hpp b/src/KKdLib/io/path.hpp index 4e61ccc3..970ed3bd 100644 --- a/src/KKdLib/io/path.hpp +++ b/src/KKdLib/io/path.hpp @@ -15,13 +15,13 @@ extern bool path_check_file_exists(const char* path); extern bool path_check_file_exists(const wchar_t* path); extern bool path_check_directory_exists(const char* path); extern bool path_check_directory_exists(const wchar_t* path); -extern void path_get_files(std::vector* files, const char* path); -extern void path_get_files(std::vector* files, const wchar_t* path); -extern void path_get_directories(std::vector* directories, - const char* path, char** exclude_list, size_t exclude_count); -extern void path_get_directories(std::vector* directories, - const wchar_t* path, wchar_t** exclude_list, size_t exclude_count); -extern void path_get_directories_recursive(std::vector* directories, - const char* path, char** exclude_list, size_t exclude_count); -extern void path_get_directories_recursive(std::vector* directories, - const wchar_t* path, wchar_t** exclude_list, size_t exclude_count); \ No newline at end of file +extern std::vector path_get_files(const char* path); +extern std::vector path_get_files(const wchar_t* path); +extern std::vector path_get_directories( + const char* path, const char** exclude_list, size_t exclude_count); +extern std::vector path_get_directories( + const wchar_t* path, const wchar_t** exclude_list, size_t exclude_count); +extern std::vector path_get_directories_recursive( + const char* path, const char** exclude_list, size_t exclude_count); +extern std::vector path_get_directories_recursive( + const wchar_t* path, const wchar_t** exclude_list, size_t exclude_count); \ No newline at end of file diff --git a/src/KKdLib/io/stream.cpp b/src/KKdLib/io/stream.cpp index f5a93eac..f21c92f8 100644 --- a/src/KKdLib/io/stream.cpp +++ b/src/KKdLib/io/stream.cpp @@ -4,37 +4,8 @@ */ #include "stream.hpp" -#include -stream::io::io() : stream(), data() { - -} - -stream::io::~io() { - -} - -bool stream::io::check_null() { - return !stream && !data.vec.size(); -} - -bool stream::io::check_not_null() { - return stream || data.vec.size(); -} - -void stream::io::close() { - if (stream) { - fflush(stream); - fclose(stream); - stream = 0; - } - - data.vec.clear(); - data.vec.shrink_to_fit(); - data.data = data.vec.begin(); -} - -stream::stream() : buf(), length(), type(), is_big_endian() { +stream::stream() : buf(), length(), big_endian() { } @@ -42,196 +13,17 @@ stream::~stream() { close(); } -void stream::open() { - close(); - - type = STREAM_MEMORY; - length = 0; -} - -void stream::open(const char* path, const char* mode) { - close(); - - if (!path || !mode) - return; - - wchar_t* temp_path = utf8_to_utf16(path); - wchar_t* temp_mode = utf8_to_utf16((char*)mode); - io.stream = _wfsopen(temp_path, temp_mode, _SH_DENYNO); - type = io.stream && !ferror(io.stream) ? STREAM_FILE : STREAM_NONE; - get_length(); - free(temp_path); - free(temp_mode); -} - -void stream::open(const wchar_t* path, const wchar_t* mode) { - close(); - - if (!path || !mode) - return; - - io.stream = _wfsopen(path, mode, _SH_DENYNO); - type = io.stream && !ferror(io.stream) ? STREAM_FILE : STREAM_NONE; - get_length(); -} - -void stream::open(const void* data, size_t size) { - close(); - - if (!data || !size) { - type = STREAM_MEMORY; - length = 0; - return; - } - - io.data.vec = {}; - io.data.vec.resize(size); - if (io.data.vec.data() && data) - memcpy(io.data.vec.data(), data, size); - io.data.data = io.data.vec.begin(); - type = STREAM_MEMORY; - length = size; -} - -void stream::open(std::vector& data) { - close(); - - if (!data.size()) { - type = STREAM_MEMORY; - length = 0; - return; - } - - io.data.vec = data; - io.data.data = io.data.vec.begin(); - type = STREAM_MEMORY; - length = data.size(); -} - -void stream::copy(void** data, size_t* size) { - if (!this || !data || !size || type != STREAM_MEMORY) - return; - - *size = io.data.vec.size(); - *data = force_malloc(*size); - memcpy(*data, io.data.vec.data(), *size); -} - -void stream::copy(std::vector& data) { - if (!this || type != STREAM_MEMORY) - return; - - size_t length = io.data.vec.size(); - data.resize(length); - memcpy(data.data(), io.data.vec.data(), length); -} - -int stream::flush() { - switch (type) { - case STREAM_FILE: - return fflush(io.stream); - case STREAM_MEMORY: - return 0; - default: - return 0; - } -} - void stream::close() { if (!this) return; memset(buf, 0, sizeof(buf)); - io.close(); length = 0; - type = STREAM_NONE; - is_big_endian = false; + big_endian = false; position_stack.clear(); position_stack.shrink_to_fit(); } -int64_t stream::get_length() { - switch (type) { - case STREAM_FILE: - if (io.stream) { - size_t temp = _ftelli64(io.stream); - _fseeki64(io.stream, 0, SEEK_END); - length = _ftelli64(io.stream); - _fseeki64(io.stream, temp, SEEK_SET); - } - else - length = 0; - break; - case STREAM_MEMORY: - length = io.data.vec.size(); - break; - default: - length = 0; - break; - } - return length; -} - -int64_t stream::get_position() { - switch (type) { - case STREAM_FILE: - return _ftelli64(io.stream); - case STREAM_MEMORY: - return io.data.data - io.data.vec.begin(); - default: - return EOF; - } -} - -int32_t stream::set_position(int64_t pos, int32_t seek) { - switch (type) { - case STREAM_FILE: - return _fseeki64(io.stream, pos, seek); - case STREAM_MEMORY: - switch (seek) { - case SEEK_SET: { - if (pos < 0) - return EOF; - - if (io.data.vec.size() < (size_t)pos) { - size_t size = io.data.vec.size(); - io.data.vec.resize(pos); - memset(io.data.vec.data() + size, 0, pos - size); - } - io.data.data = io.data.vec.begin() + pos; - } return 0; - case SEEK_CUR: { - if (pos > 0) { - size_t _pos = io.data.data - io.data.vec.begin(); - if (io.data.vec.size() < (size_t)(_pos + pos)) { - size_t size = io.data.vec.size(); - io.data.vec.resize(_pos + pos); - memset(io.data.vec.data() + size, 0, _pos + pos - size); - io.data.data = io.data.vec.begin() + _pos; - } - io.data.data += pos; - } - else if (pos < 0) { - if (io.data.data - io.data.vec.begin() < -pos) - return EOF; - else - io.data.data += pos; - } - } return 0; - case SEEK_END: { - if (pos < 0) - break; - - if (io.data.vec.size() < (size_t)pos) - break; - - io.data.data = io.data.vec.end() - pos; - } return 0; - } - } - return EOF; -} - int32_t stream::position_push(int64_t pos, int32_t seek) { position_stack.push_back(get_position()); return set_position(pos, seek); @@ -247,181 +39,6 @@ void stream::position_pop() { flush(); } -void stream::align_read(int64_t align) { - int64_t position; - switch (type) { - case STREAM_FILE: - position = _ftelli64(io.stream); - break; - case STREAM_MEMORY: - position = io.data.data - io.data.vec.begin(); - break; - default: - return; - } - - size_t temp_align = align - position % align; - if (align != temp_align) - switch (type) { - case STREAM_FILE: - _fseeki64(io.stream, position + temp_align, 0); - break; - case STREAM_MEMORY: { - size_t pos = io.data.data - io.data.vec.begin(); - if (io.data.vec.size() < (size_t)(pos + temp_align)) { - size_t size = io.data.vec.size(); - io.data.vec.resize(pos + temp_align); - io.data.data = io.data.vec.begin() + pos; - memset(io.data.data._Ptr, 0, temp_align); - } - io.data.data += temp_align; - } break; - } -} - -void stream::align_write(int64_t align) { - int64_t position; - switch (type) { - case STREAM_FILE: - position = _ftelli64(io.stream); - break; - case STREAM_MEMORY: - position = io.data.data - io.data.vec.begin(); - break; - default: - return; - } - - size_t temp_align = align - position % align; - if (align != temp_align) - switch (type) { - case STREAM_FILE: { - memset(buf, 0, min(sizeof(buf), temp_align)); - size_t i = temp_align; - while (i >= sizeof(buf)) { - fwrite(buf, 1, sizeof(buf), io.stream); - i -= sizeof(buf); - } - - if (i > 0) - fwrite(buf, 1, i, io.stream); - } break; - case STREAM_MEMORY: { - size_t pos = io.data.data - io.data.vec.begin(); - if (io.data.vec.size() < (size_t)(pos + temp_align)) { - size_t size = io.data.vec.size(); - io.data.vec.resize(pos + temp_align); - io.data.data = io.data.vec.begin() + pos; - memset(io.data.data._Ptr, 0, temp_align); - } - io.data.data += temp_align; - } break; - } -} - -int64_t stream::read(int64_t count) { - return read((void*)0, count); -} - -int64_t stream::read(void* buf, int64_t count) { - switch (type) { - case STREAM_FILE: - if (!buf) { - int64_t act_count = 0; - while (count > 0) { - act_count += fread(this->buf, 1, min(count, sizeof(this->buf)), io.stream); - count -= sizeof(this->buf); - } - return act_count; - } - else - return fread(buf, 1, count, io.stream); - case STREAM_MEMORY: { - if (io.data.data >= io.data.vec.end()) - return EOF; - - size_t _count = io.data.vec.end() - io.data.data; - if (_count >= (size_t)count) - _count = count; - if (buf) - memcpy(buf, io.data.data._Ptr, _count); - io.data.data += _count; - return _count; - } - default: - return EOF; - } -} - -int64_t stream::write(int64_t count) { - return write(0, count); -} - -int64_t stream::write(const void* buf, int64_t count) { - switch (type) { - case STREAM_FILE: - if (!buf) { - memset(this->buf, 0, sizeof(this->buf)); - int64_t act_count = 0; - while (count > 0) { - act_count += fwrite(this->buf, 1, min(count, sizeof(this->buf)), io.stream); - count -= sizeof(this->buf); - } - return act_count; - } - else - return fwrite(buf, 1, count, io.stream); - case STREAM_MEMORY: { - size_t pos = io.data.data - io.data.vec.begin(); - if (io.data.vec.size() < (size_t)(pos + count)) { - size_t size = io.data.vec.size(); - io.data.vec.resize(pos + count); - io.data.data = io.data.vec.begin() + pos; - } - if (buf) - memcpy(io.data.data._Ptr, buf, count); - else - memset(io.data.data._Ptr, 0, count); - io.data.data += count; - return count; - } - default: - return EOF; - } -} - -int32_t stream::read_char() { - switch (type) { - case STREAM_FILE: - return fgetc(io.stream); - case STREAM_MEMORY: - if (io.data.data >= io.data.vec.end()) - return EOF; - return *(io.data.data++); - default: - return EOF; - } -} - -int32_t stream::write_char(char c) { - switch (type) { - case STREAM_FILE: - return fputc(c, io.stream); - case STREAM_MEMORY: { - size_t pos = io.data.data - io.data.vec.begin(); - if (io.data.vec.size() < (size_t)(pos + 1)) { - size_t size = io.data.vec.size(); - io.data.vec.resize(pos + 1); - io.data.data = io.data.vec.begin() + pos; - } - *(io.data.data++) = c; - return 0; - } - default: - return EOF; - } -} - int8_t stream::read_int8_t() { int32_t c = read_char(); if (c != EOF) @@ -437,11 +54,11 @@ uint8_t stream::read_uint8_t() { } void stream::write_int8_t(int8_t val) { - stream::write_char((char)val); + write_char((char)val); } void stream::write_uint8_t(uint8_t val) { - stream::write_char((char)val); + write_char((char)val); } std::string stream::read_string(size_t length) { @@ -449,7 +66,7 @@ std::string stream::read_string(size_t length) { read(temp, length); temp[length] = 0; std::string str = std::string(temp, length); - free(temp); + free_def(temp); return str; } @@ -458,7 +75,7 @@ std::wstring stream::read_wstring(size_t length) { read(temp, sizeof(wchar_t) * length); temp[length] = 0; std::wstring str = std::wstring(temp, length); - free(temp); + free_def(temp); return str; } @@ -467,7 +84,7 @@ std::string stream::read_string_null_terminated() { int64_t length = 0; char* temp = read_utf8_string_null_terminated_offset_length(offset, &length); std::string str = std::string(temp, length); - free(temp); + free_def(temp); return str; } @@ -476,7 +93,7 @@ std::wstring stream::read_wstring_null_terminated() { int64_t length = 0; wchar_t* temp = read_utf16_string_null_terminated_offset_length(offset, &length); std::wstring str = std::wstring(temp, length); - free(temp); + free_def(temp); return str; } @@ -485,7 +102,7 @@ std::string stream::read_string_null_terminated_offset(int64_t offset) { int64_t length = 0; char* temp = read_utf8_string_null_terminated_offset_length(offset, &length); std::string str = std::string(temp, length); - free(temp); + free_def(temp); return str; } else { @@ -499,7 +116,7 @@ std::wstring stream::read_wstring_null_terminated_offset(int64_t offset) { int64_t length = 0; wchar_t* temp = read_utf16_string_null_terminated_offset_length(offset, &length); std::wstring str = std::wstring(temp, length); - free(temp); + free_def(temp); return str; } else { @@ -597,7 +214,7 @@ int16_t stream::read_int16_t() { int16_t stream::read_int16_t_reverse_endianness() { read(buf, sizeof(int16_t)); int16_t val; - if (is_big_endian) + if (big_endian) val = load_reverse_endianness_int16_t(buf); else val = *(int16_t*)buf; @@ -620,8 +237,8 @@ void stream::write_int16_t(int16_t val) { } void stream::write_int16_t_reverse_endianness(int16_t val) { - if (is_big_endian) - store_reverse_endianness_int16_t(val, buf); + if (big_endian) + store_reverse_endianness_int16_t(buf, val); else *(int16_t*)buf = val; write(buf, sizeof(int16_t)); @@ -629,7 +246,7 @@ void stream::write_int16_t_reverse_endianness(int16_t val) { void stream::write_int16_t_reverse_endianness(int16_t val, bool big_endian) { if (big_endian) - store_reverse_endianness_int16_t(val, buf); + store_reverse_endianness_int16_t(buf, val); else *(int16_t*)buf = val; write(buf, sizeof(int16_t)); @@ -643,7 +260,7 @@ uint16_t stream::read_uint16_t() { uint16_t stream::read_uint16_t_reverse_endianness() { read(buf, sizeof(uint16_t)); uint16_t val; - if (is_big_endian) + if (big_endian) val = load_reverse_endianness_uint16_t(buf); else val = *(uint16_t*)buf; @@ -666,8 +283,8 @@ void stream::write_uint16_t(uint16_t val) { } void stream::write_uint16_t_reverse_endianness(uint16_t val) { - if (is_big_endian) - store_reverse_endianness_uint16_t(val, buf); + if (big_endian) + store_reverse_endianness_uint16_t(buf, val); else *(uint16_t*)buf = val; write(buf, sizeof(uint16_t)); @@ -675,7 +292,7 @@ void stream::write_uint16_t_reverse_endianness(uint16_t val) { void stream::write_uint16_t_reverse_endianness(uint16_t val, bool big_endian) { if (big_endian) - store_reverse_endianness_uint16_t(val, buf); + store_reverse_endianness_uint16_t(buf, val); else *(uint16_t*)buf = val; write(buf, sizeof(uint16_t)); @@ -689,7 +306,7 @@ int32_t stream::read_int32_t() { int32_t stream::read_int32_t_reverse_endianness() { read(buf, sizeof(int32_t)); int32_t val; - if (is_big_endian) + if (big_endian) val = load_reverse_endianness_int32_t(buf); else val = *(int32_t*)buf; @@ -712,8 +329,8 @@ void stream::write_int32_t(int32_t val) { } void stream::write_int32_t_reverse_endianness(int32_t val) { - if (is_big_endian) - store_reverse_endianness_int32_t(val, buf); + if (big_endian) + store_reverse_endianness_int32_t(buf, val); else *(int32_t*)buf = val; write(buf, sizeof(int32_t)); @@ -721,7 +338,7 @@ void stream::write_int32_t_reverse_endianness(int32_t val) { void stream::write_int32_t_reverse_endianness(int32_t val, bool big_endian) { if (big_endian) - store_reverse_endianness_int32_t(val, buf); + store_reverse_endianness_int32_t(buf, val); else *(int32_t*)buf = val; write(buf, sizeof(int32_t)); @@ -735,7 +352,7 @@ uint32_t stream::read_uint32_t() { uint32_t stream::read_uint32_t_reverse_endianness() { read(buf, sizeof(uint32_t)); uint32_t val; - if (is_big_endian) + if (big_endian) val = load_reverse_endianness_uint32_t(buf); else val = *(uint32_t*)buf; @@ -758,8 +375,8 @@ void stream::write_uint32_t(uint32_t val) { } void stream::write_uint32_t_reverse_endianness(uint32_t val) { - if (is_big_endian) - store_reverse_endianness_uint32_t(val, buf); + if (big_endian) + store_reverse_endianness_uint32_t(buf, val); else *(uint32_t*)buf = val; write(buf, sizeof(uint32_t)); @@ -767,7 +384,7 @@ void stream::write_uint32_t_reverse_endianness(uint32_t val) { void stream::write_uint32_t_reverse_endianness(uint32_t val, bool big_endian) { if (big_endian) - store_reverse_endianness_uint32_t(val, buf); + store_reverse_endianness_uint32_t(buf, val); else *(uint32_t*)buf = val; write(buf, sizeof(uint32_t)); @@ -781,7 +398,7 @@ int64_t stream::read_int64_t() { int64_t stream::read_int64_t_reverse_endianness() { read(buf, sizeof(int64_t)); int64_t val; - if (is_big_endian) + if (big_endian) val = load_reverse_endianness_int64_t(buf); else val = *(int64_t*)buf; @@ -804,8 +421,8 @@ void stream::write_int64_t(int64_t val) { } void stream::write_int64_t_reverse_endianness(int64_t val) { - if (is_big_endian) - store_reverse_endianness_int64_t(val, buf); + if (big_endian) + store_reverse_endianness_int64_t(buf, val); else *(int64_t*)buf = val; write(buf, sizeof(int64_t)); @@ -813,7 +430,7 @@ void stream::write_int64_t_reverse_endianness(int64_t val) { void stream::write_int64_t_reverse_endianness(int64_t val, bool big_endian) { if (big_endian) - store_reverse_endianness_int64_t(val, buf); + store_reverse_endianness_int64_t(buf, val); else *(int64_t*)buf = val; write(buf, sizeof(int64_t)); @@ -827,7 +444,7 @@ uint64_t stream::read_uint64_t() { uint64_t stream::read_uint64_t_reverse_endianness() { read(buf, sizeof(uint64_t)); uint64_t val; - if (is_big_endian) + if (big_endian) val = load_reverse_endianness_uint64_t(buf); else val = *(uint64_t*)buf; @@ -850,8 +467,8 @@ void stream::write_uint64_t(uint64_t val) { } void stream::write_uint64_t_reverse_endianness(uint64_t val) { - if (is_big_endian) - store_reverse_endianness_uint64_t(val, buf); + if (big_endian) + store_reverse_endianness_uint64_t(buf, val); else *(uint64_t*)buf = val; write(buf, sizeof(uint64_t)); @@ -859,7 +476,7 @@ void stream::write_uint64_t_reverse_endianness(uint64_t val) { void stream::write_uint64_t_reverse_endianness(uint64_t val, bool big_endian) { if (big_endian) - store_reverse_endianness_uint64_t(val, buf); + store_reverse_endianness_uint64_t(buf, val); else *(uint64_t*)buf = val; write(buf, sizeof(uint64_t)); @@ -873,7 +490,7 @@ half_t stream::read_half_t() { half_t stream::read_half_t_reverse_endianness() { read(buf, sizeof(half_t)); half_t val; - if (is_big_endian) + if (big_endian) val = load_reverse_endianness_half_t(buf); else val = *(half_t*)buf; @@ -896,8 +513,8 @@ void stream::write_half_t(half_t val) { } void stream::write_half_t_reverse_endianness(half_t val) { - if (is_big_endian) - store_reverse_endianness_half_t(val, buf); + if (big_endian) + store_reverse_endianness_half_t(buf, val); else *(half_t*)buf = val; write(buf, sizeof(half_t)); @@ -905,7 +522,7 @@ void stream::write_half_t_reverse_endianness(half_t val) { void stream::write_half_t_reverse_endianness(half_t val, bool big_endian) { if (big_endian) - store_reverse_endianness_half_t(val, buf); + store_reverse_endianness_half_t(buf, val); else *(half_t*)buf = val; write(buf, sizeof(half_t)); @@ -919,7 +536,7 @@ float_t stream::read_float_t() { float_t stream::read_float_t_reverse_endianness() { read(buf, sizeof(float_t)); float_t val; - if (is_big_endian) + if (big_endian) val = load_reverse_endianness_float_t(buf); else val = *(float_t*)buf; @@ -942,8 +559,8 @@ void stream::write_float_t(float_t val) { } void stream::write_float_t_reverse_endianness(float_t val) { - if (is_big_endian) - store_reverse_endianness_float_t(val, buf); + if (big_endian) + store_reverse_endianness_float_t(buf, val); else *(float_t*)buf = val; write(buf, sizeof(float_t)); @@ -951,7 +568,7 @@ void stream::write_float_t_reverse_endianness(float_t val) { void stream::write_float_t_reverse_endianness(float_t val, bool big_endian) { if (big_endian) - store_reverse_endianness_float_t(val, buf); + store_reverse_endianness_float_t(buf, val); else *(float_t*)buf = val; write(buf, sizeof(float_t)); @@ -965,7 +582,7 @@ double_t stream::read_double_t() { double_t stream::read_double_t_reverse_endianness() { read(buf, sizeof(double_t)); double_t val; - if (is_big_endian) + if (big_endian) val = load_reverse_endianness_double_t(buf); else val = *(double_t*)buf; @@ -988,8 +605,8 @@ void stream::write_double_t(double_t val) { } void stream::write_double_t_reverse_endianness(double_t val) { - if (is_big_endian) - store_reverse_endianness_double_t(val, buf); + if (big_endian) + store_reverse_endianness_double_t(buf, val); else *(double_t*)buf = val; write(buf, sizeof(double_t)); @@ -997,7 +614,7 @@ void stream::write_double_t_reverse_endianness(double_t val) { void stream::write_double_t_reverse_endianness(double_t val, bool big_endian) { if (big_endian) - store_reverse_endianness_double_t(val, buf); + store_reverse_endianness_double_t(buf, val); else *(double_t*)buf = val; write(buf, sizeof(double_t)); diff --git a/src/KKdLib/io/stream.hpp b/src/KKdLib/io/stream.hpp index bf2c4108..d545797a 100644 --- a/src/KKdLib/io/stream.hpp +++ b/src/KKdLib/io/stream.hpp @@ -10,62 +10,38 @@ #include "../default.hpp" #include "../half_t.hpp" -enum stream_type { - STREAM_NONE = 0, - STREAM_FILE, - STREAM_MEMORY, -}; - -struct stream { - +class stream { +public: uint8_t buf[0x100]; - struct io { - FILE* stream; - struct data { - std::vector::iterator data; - std::vector vec; - } data; - - io(); - ~io(); - - bool check_null(); - bool check_not_null(); - void close(); - } io; int64_t length; - stream_type type; - bool is_big_endian; + bool big_endian; std::vector position_stack; stream(); - ~stream(); + virtual ~stream(); - void open(); - void open(const char* path, const char* mode); - void open(const wchar_t* path, const wchar_t* mode); - void open(const void* data, size_t size); - void open(std::vector& data); - void copy(void** data, size_t* size); - void copy(std::vector& data); - int flush(); - void close(); + virtual int flush() = 0; + virtual void close(); + virtual bool check_null() = 0; + virtual bool check_not_null() = 0; + + virtual void align_read(size_t align) = 0; + virtual void align_write(size_t align) = 0; + virtual size_t read(size_t count) = 0; + virtual size_t read(void* buf, size_t count) = 0; + virtual size_t read(void* buf, size_t size, size_t count) = 0; + virtual size_t write(size_t count) = 0; + virtual size_t write(const void* buf, size_t count) = 0; + virtual size_t write(const void* buf, size_t size, size_t count) = 0; + virtual int32_t read_char() = 0; + virtual int32_t write_char(char c) = 0; + virtual int64_t get_length() = 0; + virtual int64_t get_position() = 0; + virtual int32_t set_position(int64_t pos, int32_t seek) = 0; - int64_t get_length(); - int64_t get_position(); - int32_t set_position(int64_t pos, int32_t seek); int32_t position_push(int64_t pos, int32_t seek); void position_pop(); - void align_read(int64_t align); - void align_write(int64_t align); - int64_t read(int64_t count); - int64_t read(void* buf, int64_t count); - int64_t write(int64_t count); - int64_t write(const void* buf, int64_t count); - int32_t read_char(); - int32_t write_char(char c); - int8_t read_int8_t(); uint8_t read_uint8_t(); void write_int8_t(int8_t val); diff --git a/src/KKdLib/key_val.cpp b/src/KKdLib/key_val.cpp index c5758a03..9c668a18 100644 --- a/src/KKdLib/key_val.cpp +++ b/src/KKdLib/key_val.cpp @@ -4,6 +4,7 @@ */ #include "key_val.hpp" +#include "io/file_stream.hpp" #include "io/path.hpp" #include "hash.hpp" #include "str_utils.hpp" @@ -47,7 +48,7 @@ key_val::key_val() : curr_scope(), buf(), scope_size() { } key_val::~key_val() { - free(buf); + free_def(buf); } void key_val::close_scope() { @@ -67,13 +68,13 @@ void key_val::file_read(const char* path) { if (!path || !path_check_file_exists(path)) return; - stream s; + file_stream s; s.open(path, "rb"); - if (s.io.stream) { + if (s.check_not_null()) { char* d = force_malloc_s(char, s.length); s.read(d, s.length); parse((uint8_t*)d, s.length); - free(d); + free_def(d); } } @@ -81,13 +82,13 @@ void key_val::file_read(const wchar_t* path) { if (!path || !path_check_file_exists(path)) return; - stream s; + file_stream s; s.open(path, L"rb"); - if (s.io.stream) { + if (s.check_not_null()) { char* d = force_malloc_s(char, s.length); s.read(d, s.length); parse((uint8_t*)d, s.length); - free(d); + free_def(d); } } @@ -120,8 +121,8 @@ bool key_val::has_key(std::string& str) { bool key_val::open_scope(const char* str) { if (!str || !*str) { scope_size++; - if ((size_t)scope_size > scope.size()) - scope.resize(scope_size + (scope_size >> 1) + 1);; + if ((size_t)scope_size >= scope.size()) + scope.resize(scope_size + (scope_size >> 1) + 1); curr_scope = &scope[scope_size]; key_val_scope* prev_scope = curr_scope - 1; @@ -153,7 +154,7 @@ bool key_val::open_scope(const char* str) { scope_size++; if ((size_t)scope_size >= scope.size()) - scope.resize(scope_size + (scope_size >> 1) + 1);; + scope.resize(scope_size + (scope_size >> 1) + 1); curr_scope = &scope[scope_size]; if (curr_scope[-1].key.size()) { @@ -178,7 +179,7 @@ bool key_val::open_scope(std::string& str) { if (!str.size()) { scope_size++; if ((size_t)scope_size >= scope.size()) - scope.resize(scope_size + (scope_size >> 1) + 1);; + scope.resize(scope_size + (scope_size >> 1) + 1); curr_scope = &scope[scope_size]; key_val_scope* prev_scope = curr_scope - 1; @@ -210,7 +211,7 @@ bool key_val::open_scope(std::string& str) { scope_size++; if ((size_t)scope_size >= scope.size()) - scope.resize(scope_size + (scope_size >> 1) + 1);; + scope.resize(scope_size + (scope_size >> 1) + 1); curr_scope = &scope[scope_size]; if (curr_scope[-1].key.size()) { @@ -261,7 +262,7 @@ void key_val::parse(const void* data, size_t size) { char** lines; size_t count; - if (!str_utils_text_file_parse(data, size, &buf, &lines, &count)) + if (!str_utils_text_file_parse(data, size, buf, lines, count)) return; key.reserve(count); @@ -299,7 +300,7 @@ void key_val::parse(const void* data, size_t size) { curr_scope->count = key.size(); key_val_sort(this); - free(lines) + free_def(lines) } bool key_val::read(bool& value) { @@ -1080,10 +1081,14 @@ static int64_t key_val_find_first_key(key_val* kv, int64_t low, int64_t high, key_val_pair* l = &k[mid = (low + high) / 2]; if (l->length > offset && s_len <= l->length - offset) { res = memcmp(s, l->str + offset, s_len); + if (!res && l->str[offset + s_len] && l->str[offset + s_len] != '.') + res = -1; full = true; } else { res = str_utils_compare_length(s, s_len, l->str + offset, l->length - offset); + if (!res && s[l->length - offset]) + res = 1; full = false; } @@ -1112,10 +1117,14 @@ static int64_t key_val_find_last_key(key_val* kv, int64_t low, int64_t high, key_val_pair* l = &k[mid = (low + high) / 2]; if (l->length > offset && s_len <= l->length - offset) { res = memcmp(s, l->str + offset, s_len); + if (!res && l->str[offset + s_len] && l->str[offset + s_len] != '.') + res = -1; full = true; } else { res = str_utils_compare_length(s, s_len, l->str + offset, l->length - offset); + if (!res && s[l->length - offset]) + res = 1; full = false; } diff --git a/src/KKdLib/light_param/face.cpp b/src/KKdLib/light_param/face.cpp index 1d8cc3b8..e26e17e4 100644 --- a/src/KKdLib/light_param/face.cpp +++ b/src/KKdLib/light_param/face.cpp @@ -4,8 +4,9 @@ */ #include "face.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../str_utils.hpp" static void light_param_face_read_inner(light_param_face* face, stream& s); @@ -25,27 +26,27 @@ light_param_face::~light_param_face() { void light_param_face::read(const char* path) { char* path_txt = str_utils_add(path, ".txt"); if (path_check_file_exists(path_txt)) { - stream s; + file_stream s; s.open(path_txt, "rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_face_read_inner(this, s); } - free(path_txt); + free_def(path_txt); } void light_param_face::read(const wchar_t* path) { wchar_t* path_txt = str_utils_add(path, L".txt"); if (path_check_file_exists(path_txt)) { - stream s; + file_stream s; s.open(path_txt, L"rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_face_read_inner(this, s); } - free(path_txt); + free_def(path_txt); } void light_param_face::read(const void* data, size_t size) { - stream s; + memory_stream s; s.open(data, size); light_param_face_read_inner(this, s); } @@ -55,11 +56,11 @@ void light_param_face::write(const char* path) { return; char* path_txt = str_utils_add(path, ".txt"); - stream s; + file_stream s; s.open(path_txt, "wb"); - if (s.io.stream) + if (s.check_not_null()) light_param_face_write_inner(this, s); - free(path_txt); + free_def(path_txt); } void light_param_face::write(const wchar_t* path) { @@ -67,18 +68,18 @@ void light_param_face::write(const wchar_t* path) { return; wchar_t* path_txt = str_utils_add(path, L".txt"); - stream s; + file_stream s; s.open(path_txt, L"wb"); - if (s.io.stream) + if (s.check_not_null()) light_param_face_write_inner(this, s); - free(path_txt); + free_def(path_txt); } void light_param_face::write(void** data, size_t* size) { if (!data || !ready) return; - stream s; + memory_stream s; s.open(); light_param_face_write_inner(this, s); s.copy(data, size); @@ -130,12 +131,12 @@ static void light_param_face_read_inner(light_param_face* face, stream& s) { } } - free(data); + free_def(data); face->ready = true; return; End: - free(data); + free_def(data); } static void light_param_face_write_inner(light_param_face* face, stream& s) { diff --git a/src/KKdLib/light_param/fog.cpp b/src/KKdLib/light_param/fog.cpp index 8b156196..76032ed6 100644 --- a/src/KKdLib/light_param/fog.cpp +++ b/src/KKdLib/light_param/fog.cpp @@ -4,8 +4,9 @@ */ #include "fog.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../str_utils.hpp" static void light_param_fog_read_inner(light_param_fog* fog, stream& s); @@ -25,27 +26,27 @@ light_param_fog::~light_param_fog() { void light_param_fog::read(const char* path) { char* path_txt = str_utils_add(path, ".txt"); if (path_check_file_exists(path_txt)) { - stream s; + file_stream s; s.open(path_txt, "rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_fog_read_inner(this, s); } - free(path_txt); + free_def(path_txt); } void light_param_fog::read(const wchar_t* path) { wchar_t* path_txt = str_utils_add(path, L".txt"); if (path_check_file_exists(path_txt)) { - stream s; + file_stream s; s.open(path_txt, L"rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_fog_read_inner(this, s); } - free(path_txt); + free_def(path_txt); } void light_param_fog::read(const void* data, size_t size) { - stream s; + memory_stream s; s.open(data, size); light_param_fog_read_inner(this, s); } @@ -55,11 +56,11 @@ void light_param_fog::write(const char* path) { return; char* path_txt = str_utils_add(path, ".txt"); - stream s; + file_stream s; s.open(path_txt, "wb"); - if (s.io.stream) + if (s.check_not_null()) light_param_fog_write_inner(this, s); - free(path_txt); + free_def(path_txt); } void light_param_fog::write(const wchar_t* path) { @@ -67,18 +68,18 @@ void light_param_fog::write(const wchar_t* path) { return; wchar_t* path_txt = str_utils_add(path, L".txt"); - stream s; + file_stream s; s.open(path_txt, L"wb"); - if (s.io.stream) + if (s.check_not_null()) light_param_fog_write_inner(this, s); - free(path_txt); + free_def(path_txt); } void light_param_fog::write(void** data, size_t* size) { if (!data || !ready) return; - stream s; + memory_stream s; s.open(); light_param_fog_write_inner(this, s); s.copy(data, size); @@ -177,12 +178,12 @@ static void light_param_fog_read_inner(light_param_fog* fog, stream& s) { } } - free(data); + free_def(data); fog->ready = true; return; End: - free(data); + free_def(data); } static void light_param_fog_write_inner(light_param_fog* fog, stream& s) { diff --git a/src/KKdLib/light_param/glow.cpp b/src/KKdLib/light_param/glow.cpp index 7948adf4..9fbb31b2 100644 --- a/src/KKdLib/light_param/glow.cpp +++ b/src/KKdLib/light_param/glow.cpp @@ -4,8 +4,9 @@ */ #include "glow.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../str_utils.hpp" static void light_param_glow_read_inner(light_param_glow* glow, stream& s); @@ -29,27 +30,27 @@ light_param_glow::~light_param_glow() { void light_param_glow::read(const char* path) { char* path_txt = str_utils_add(path, ".txt"); if (path_check_file_exists(path_txt)) { - stream s; + file_stream s; s.open(path_txt, "rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_glow_read_inner(this, s); } - free(path_txt); + free_def(path_txt); } void light_param_glow::read(const wchar_t* path) { wchar_t* path_txt = str_utils_add(path, L".txt"); if (path_check_file_exists(path_txt)) { - stream s; + file_stream s; s.open(path_txt, L"rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_glow_read_inner(this, s); } - free(path_txt); + free_def(path_txt); } void light_param_glow::read(const void* data, size_t size) { - stream s; + memory_stream s; s.open(data, size); light_param_glow_read_inner(this, s); } @@ -59,11 +60,11 @@ void light_param_glow::write(const char* path) { return; char* path_txt = str_utils_add(path, ".txt"); - stream s; + file_stream s; s.open(path_txt, "wb"); - if (s.io.stream) + if (s.check_not_null()) light_param_glow_write_inner(this, s); - free(path_txt); + free_def(path_txt); } void light_param_glow::write(const wchar_t* path) { @@ -71,18 +72,18 @@ void light_param_glow::write(const wchar_t* path) { return; wchar_t* path_txt = str_utils_add(path, L".txt"); - stream s; + file_stream s; s.open(path_txt, L"wb"); - if (s.io.stream) + if (s.check_not_null()) light_param_glow_write_inner(this, s); - free(path_txt); + free_def(path_txt); } void light_param_glow::write(void** data, size_t* size) { if (!data || !ready) return; - stream s; + memory_stream s; s.open(); light_param_glow_write_inner(this, s); s.copy(data, size); @@ -194,12 +195,12 @@ static void light_param_glow_read_inner(light_param_glow* glow, stream& s) { } } - free(data); + free_def(data); glow->ready = true; return; End: - free(data); + free_def(data); } static void light_param_glow_write_inner(light_param_glow* glow, stream& s) { diff --git a/src/KKdLib/light_param/ibl.cpp b/src/KKdLib/light_param/ibl.cpp index d63a68c6..cd33eaa4 100644 --- a/src/KKdLib/light_param/ibl.cpp +++ b/src/KKdLib/light_param/ibl.cpp @@ -4,8 +4,9 @@ */ #include "ibl.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../str_utils.hpp" static void light_param_ibl_read_inner(light_param_ibl* ibl, stream& s); @@ -24,27 +25,27 @@ light_param_ibl::~light_param_ibl() { void light_param_ibl::read(const char* path) { char* path_ibl = str_utils_add(path, ".ibl"); if (path_check_file_exists(path_ibl)) { - stream s; + file_stream s; s.open(path_ibl, "rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_ibl_read_inner(this, s); } - free(path_ibl); + free_def(path_ibl); } void light_param_ibl::read(const wchar_t* path) { wchar_t* path_ibl = str_utils_add(path, L".ibl"); if (path_check_file_exists(path_ibl)) { - stream s; + file_stream s; s.open(path_ibl, L"rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_ibl_read_inner(this, s); } - free(path_ibl); + free_def(path_ibl); } void light_param_ibl::read(const void* data, size_t size) { - stream s; + memory_stream s; s.open(data, size); light_param_ibl_read_inner(this, s); } @@ -220,12 +221,12 @@ static void light_param_ibl_read_inner(light_param_ibl* ibl, stream& s) { goto End; } - free(data); + free_def(data); ibl->ready = true; return; End: - free(data); + free_def(data); } static const char* light_param_ibl_read_line(char* buf, int32_t size, const char* src) { @@ -284,8 +285,8 @@ static void light_param_ibl_specular_generate_mipmaps(light_param_ibl_specular* for (size_t j = 0; j < data_size_2; j++) data[j] = float_to_half(temp[j]); } - free(data_f32[0]); - free(data_f32[1]); + free_def(data_f32[0]); + free_def(data_f32[1]); } static void light_param_ibl_specular_generate_mipmap(float_t* src, float_t* dst, size_t size) { diff --git a/src/KKdLib/light_param/light.cpp b/src/KKdLib/light_param/light.cpp index 63bed58c..c50bdb6f 100644 --- a/src/KKdLib/light_param/light.cpp +++ b/src/KKdLib/light_param/light.cpp @@ -4,8 +4,9 @@ */ #include "light.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../str_utils.hpp" static void light_param_light_read_inner(light_param_light* light, stream& s); @@ -25,27 +26,27 @@ light_param_light::~light_param_light() { void light_param_light::read(const char* path) { char* path_txt = str_utils_add(path, ".txt"); if (path_check_file_exists(path_txt)) { - stream s; + file_stream s; s.open(path_txt, "rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_light_read_inner(this, s); } - free(path_txt); + free_def(path_txt); } void light_param_light::read(const wchar_t* path) { wchar_t* path_txt = str_utils_add(path, L".txt"); if (path_check_file_exists(path_txt)) { - stream s; + file_stream s; s.open(path_txt, L"rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_light_read_inner(this, s); } - free(path_txt); + free_def(path_txt); } void light_param_light::read(const void* data, size_t size) { - stream s; + memory_stream s; s.open(data, size); light_param_light_read_inner(this, s); } @@ -55,11 +56,11 @@ void light_param_light::write(const char* path) { return; char* path_txt = str_utils_add(path, ".txt"); - stream s; + file_stream s; s.open(path_txt, "wb"); - if (s.io.stream) + if (s.check_not_null()) light_param_light_write_inner(this, s); - free(path_txt); + free_def(path_txt); } void light_param_light::write(const wchar_t* path) { @@ -67,18 +68,18 @@ void light_param_light::write(const wchar_t* path) { return; wchar_t* path_txt = str_utils_add(path, L".txt"); - stream s; + file_stream s; s.open(path_txt, L"wb"); - if (s.io.stream) + if (s.check_not_null()) light_param_light_write_inner(this, s); - free(path_txt); + free_def(path_txt); } void light_param_light::write(void** data, size_t* size) { if (!data || !ready) return; - stream s; + memory_stream s; s.open(); light_param_light_write_inner(this, s); s.copy(data, size); @@ -245,9 +246,9 @@ static void light_param_light_read_inner(light_param_light* light, stream& s) { light->has_spot_cutoff = true; } else if (!str_utils_compare_length(buf, sizeof(buf), "attenuation", 11)) { - vec3& attenuation = light->attenuation; + light_attenuation& attenuation = light->attenuation; if (buf[11] != ' ' || sscanf_s(buf + 12, "%f %f %f", - &attenuation.x, &attenuation.y, &attenuation.z) != 3) + &attenuation.constant, &attenuation.linear, &attenuation.quadratic) != 3) goto End; light->has_attenuation = true; @@ -258,28 +259,28 @@ static void light_param_light_read_inner(light_param_light* light, stream& s) { &clip_plane[0], &clip_plane[1], &clip_plane[2], &clip_plane[3]) != 4) goto End; - light->clip_plane[0] = clip_plane[0] ? true : false; - light->clip_plane[1] = clip_plane[1] ? true : false; - light->clip_plane[2] = clip_plane[2] ? true : false; - light->clip_plane[3] = clip_plane[3] ? true : false; + light->clip_plane.data[0] = clip_plane[0] ? true : false; + light->clip_plane.data[1] = clip_plane[1] ? true : false; + light->clip_plane.data[2] = clip_plane[2] ? true : false; + light->clip_plane.data[3] = clip_plane[3] ? true : false; light->has_clip_plane = true; } else if (!str_utils_compare_length(buf, sizeof(buf), "tonecurve", 9)) { - vec3& tone_curve = light->tone_curve; + light_tone_curve& tone_curve = light->tone_curve; if (buf[9] != ' ' || sscanf_s(buf + 10, "%f %f %f", - &tone_curve.x, &tone_curve.y, &tone_curve.z) != 3) + &tone_curve.start_point, &tone_curve.end_point, &tone_curve.coefficient) != 3) goto End; light->has_tone_curve = true; } } - free(data); + free_def(data); light->ready = true; return; End: - free(data); + free_def(data); } static void light_param_light_write_inner(light_param_light* light, stream& s) { @@ -367,30 +368,30 @@ static void light_param_light_write_inner(light_param_light* light, stream& s) { } if (light->has_attenuation) { - vec3& attenuation = light->attenuation; + light_attenuation& attenuation = light->attenuation; s.write("attenuation", 11); - light_param_light_write_float_t(s, buf, sizeof(buf), attenuation.x); - light_param_light_write_float_t(s, buf, sizeof(buf), attenuation.y); - light_param_light_write_float_t(s, buf, sizeof(buf), attenuation.z); + light_param_light_write_float_t(s, buf, sizeof(buf), attenuation.constant); + light_param_light_write_float_t(s, buf, sizeof(buf), attenuation.linear); + light_param_light_write_float_t(s, buf, sizeof(buf), attenuation.quadratic); s.write_char('\n'); } if (light->has_clip_plane) { - bool* clip_plane = light->clip_plane; + light_clip_plane& clip_plane = light->clip_plane; s.write("clipplane", 10); - light_param_light_write_int32_t(s, buf, sizeof(buf), clip_plane[0] ? 1 : 0); - light_param_light_write_int32_t(s, buf, sizeof(buf), clip_plane[1] ? 1 : 0); - light_param_light_write_int32_t(s, buf, sizeof(buf), clip_plane[2] ? 1 : 0); - light_param_light_write_int32_t(s, buf, sizeof(buf), clip_plane[3] ? 1 : 0); + light_param_light_write_int32_t(s, buf, sizeof(buf), clip_plane.data[0] ? 1 : 0); + light_param_light_write_int32_t(s, buf, sizeof(buf), clip_plane.data[1] ? 1 : 0); + light_param_light_write_int32_t(s, buf, sizeof(buf), clip_plane.data[2] ? 1 : 0); + light_param_light_write_int32_t(s, buf, sizeof(buf), clip_plane.data[3] ? 1 : 0); s.write_char('\n'); } if (light->has_tone_curve) { - vec3& tone_curve = light->tone_curve; + light_tone_curve& tone_curve = light->tone_curve; s.write("tonecurve", 10); - light_param_light_write_float_t(s, buf, sizeof(buf), tone_curve.x); - light_param_light_write_float_t(s, buf, sizeof(buf), tone_curve.y); - light_param_light_write_float_t(s, buf, sizeof(buf), tone_curve.z); + light_param_light_write_float_t(s, buf, sizeof(buf), tone_curve.start_point); + light_param_light_write_float_t(s, buf, sizeof(buf), tone_curve.end_point); + light_param_light_write_float_t(s, buf, sizeof(buf), tone_curve.coefficient); s.write_char('\n'); } diff --git a/src/KKdLib/light_param/light.hpp b/src/KKdLib/light_param/light.hpp index 2676ecb1..208e90b8 100644 --- a/src/KKdLib/light_param/light.hpp +++ b/src/KKdLib/light_param/light.hpp @@ -32,6 +32,22 @@ enum light_type { LIGHT_SPOT = 0x03, }; +struct light_attenuation { + float_t constant; + float_t linear; + float_t quadratic; +}; + +struct light_clip_plane { + bool data[4]; +}; + +struct light_tone_curve { + float_t start_point; + float_t end_point; + float_t coefficient; +}; + struct light_param_light_data { bool has_type; light_type type; @@ -50,11 +66,11 @@ struct light_param_light_data { vec3 spot_direction; float_t spot_exponent; float_t spot_cutoff; - vec3 attenuation; + light_attenuation attenuation; bool has_clip_plane; - bool clip_plane[4]; + light_clip_plane clip_plane; bool has_tone_curve; - vec3 tone_curve; + light_tone_curve tone_curve; light_param_light_data(); ~light_param_light_data(); diff --git a/src/KKdLib/light_param/wind.cpp b/src/KKdLib/light_param/wind.cpp index e027beb3..2e1f55fa 100644 --- a/src/KKdLib/light_param/wind.cpp +++ b/src/KKdLib/light_param/wind.cpp @@ -4,8 +4,9 @@ */ #include "wind.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../str_utils.hpp" static void light_param_wind_read_inner(light_param_wind* wind, stream& s); @@ -26,27 +27,27 @@ light_param_wind::~light_param_wind() { void light_param_wind::read(const char* path) { char* path_txt = str_utils_add(path, ".txt"); if (path_check_file_exists(path_txt)) { - stream s; + file_stream s; s.open(path_txt, "rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_wind_read_inner(this, s); } - free(path_txt); + free_def(path_txt); } void light_param_wind::read(const wchar_t* path) { wchar_t* path_txt = str_utils_add(path, L".txt"); if (path_check_file_exists(path_txt)) { - stream s; + file_stream s; s.open(path_txt, L"rb"); - if (s.io.stream) + if (s.check_not_null()) light_param_wind_read_inner(this, s); } - free(path_txt); + free_def(path_txt); } void light_param_wind::read(const void* data, size_t size) { - stream s; + memory_stream s; s.open(data, size); light_param_wind_read_inner(this, s); } @@ -56,11 +57,11 @@ void light_param_wind::write(const char* path) { return; char* path_txt = str_utils_add(path, ".txt"); - stream s; + file_stream s; s.open(path_txt, "wb"); - if (s.io.stream) + if (s.check_not_null()) light_param_wind_write_inner(this, s); - free(path_txt); + free_def(path_txt); } void light_param_wind::write(const wchar_t* path) { @@ -68,18 +69,18 @@ void light_param_wind::write(const wchar_t* path) { return; wchar_t* path_txt = str_utils_add(path, L".txt"); - stream s; + file_stream s; s.open(path_txt, L"wb"); - if (s.io.stream) + if (s.check_not_null()) light_param_wind_write_inner(this, s); - free(path_txt); + free_def(path_txt); } void light_param_wind::write(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; + memory_stream s; s.open(); light_param_wind_write_inner(this, s); s.copy(data, size); @@ -156,12 +157,12 @@ static void light_param_wind_read_inner(light_param_wind* wind, stream& s) { } } - free(data); + free_def(data); wind->ready = true; return; End: - free(data); + free_def(data); } static void light_param_wind_write_inner(light_param_wind* wind, stream& s) { diff --git a/src/KKdLib/mat.cpp b/src/KKdLib/mat.cpp index 62abe618..3c5c6bed 100644 --- a/src/KKdLib/mat.cpp +++ b/src/KKdLib/mat.cpp @@ -655,7 +655,7 @@ inline void mat3_from_quat(const quat* quat, mat3* mat) { y = quat->y; z = quat->z; w = quat->w; - vec4_length_squared(*quat, len); + len = quat::length_squared(*quat); len = len > 0.0f ? 2.0f / len : 0.0f; xx = x * x * len; xy = x * y * len; @@ -719,9 +719,9 @@ inline void mat3_get_rotation(const mat3* x, vec3* z) { } inline void mat3_get_scale(const mat3* x, vec3* z) { - vec3_length(x->row0, z->x); - vec3_length(x->row1, z->y); - vec3_length(x->row2, z->z); + z->x = vec3::length(x->row0); + z->y = vec3::length(x->row1); + z->z = vec3::length(x->row2); } inline float_t mat3_get_max_scale(const mat3* x) { @@ -730,13 +730,13 @@ inline float_t mat3_get_max_scale(const mat3* x) { float_t length; float_t max = 0.0f; - vec3_length(mat.row0, length); + length = vec3::length(mat.row0); if (max < length) max = length; - vec3_length(mat.row1, length); + length = vec3::length(mat.row1); if (max < length) max = length; - vec3_length(mat.row2, length); + length = vec3::length(mat.row2); if (max < length) max = length; return max; @@ -1030,12 +1030,12 @@ inline void mat4_inverse_normalized(const mat4* x, mat4* z) { mat3 yt; mat3_from_mat4(x, &yt); vec3 row3; - vec3_dot(*(vec3*)&x->row0, *(vec3*)&x->row3, row3.x); - vec3_dot(*(vec3*)&x->row1, *(vec3*)&x->row3, row3.y); - vec3_dot(*(vec3*)&x->row2, *(vec3*)&x->row3, row3.z); + row3.x = vec3::dot(*(vec3*)&x->row0, *(vec3*)&x->row3); + row3.y = vec3::dot(*(vec3*)&x->row1, *(vec3*)&x->row3); + row3.z = vec3::dot(*(vec3*)&x->row2, *(vec3*)&x->row3); mat3_transpose(&yt, &yt); mat4_from_mat3(&yt, z); - vec3_negate(row3, *(vec3*)&z->row3); + *(vec3*)&z->row3 = -row3; z->row0.w = 0.0f; z->row1.w = 0.0f; z->row2.w = 0.0f; @@ -1686,7 +1686,7 @@ inline void mat4_from_quat(const quat* quat, mat4* mat) { y = quat->y; z = quat->z; w = quat->w; - vec4_length_squared(*quat, len); + len = quat::length_squared(*quat); len = len > 0.0f ? 2.0f / len : 0.0f; xx = x * x * len; xy = x * y * len; @@ -1713,12 +1713,9 @@ inline void mat4_from_quat(const quat* quat, mat4* mat) { } float_t vec3_angle_between_two_vectors(const vec3* x, const vec3* y) { - vec3 z_t; - vec3_cross(*x, *y, z_t); - float_t v2; - vec3_length(z_t, v2); - float_t v3; - vec3_dot(*x, *y, v3); + vec3 z_t = vec3::cross(*x, *y); + float_t v2 = vec3::length(z_t); + float_t v3 = vec3::dot(*x, *y); return fabsf(atan2f(v2, v3)); } @@ -1727,19 +1724,15 @@ void mat4_from_two_vectors(const vec3* x, const vec3* y, mat4* mat) { if (x->x == y->x && y->y == x->y && y->z == x->z) return; - float_t v5; - vec3_dot(*x, *y, v5); - if (fabsf(1.0f - v5) <= 0.000001f) + if (fabsf(1.0f - vec3::dot(*x, *y)) <= 0.000001f) return; - vec3 axis; - vec3_cross(*x, *y, axis); - float_t axis_length; - vec3_length(axis, axis_length); + vec3 axis = vec3::cross(*x, *y); + float_t axis_length = vec3::length(axis); if (axis_length > 0.000001f) { float_t angle = vec3_angle_between_two_vectors(x, y); if (axis_length != 0.0) - vec3_mult_scalar(axis, 1.0f / axis_length, axis); + axis *= 1.0f / axis_length; mat4_from_axis_angle(&axis, angle, mat); } } @@ -1756,18 +1749,18 @@ inline void mat4_from_axis_angle(const vec3* axis, float_t angle, mat4* mat) { angle_cos = cosf(angle); angle_cos_1 = 1.0f - angle_cos; - vec3_normalize(*axis, _axis); + _axis = vec3::normalize(*axis); - vec3_mult_scalar(_axis, angle_sin, _axis_sin); - vec3_mult_scalar(_axis, _axis.x * angle_cos_1, temp); + _axis_sin = _axis * angle_sin; + temp = _axis * (_axis.x * angle_cos_1); mat->row0.x = temp.x + angle_cos; mat->row1.x = temp.y - _axis_sin.z; mat->row2.x = temp.z + _axis_sin.y; - vec3_mult_scalar(_axis, _axis.y * angle_cos_1, temp); + temp = _axis * (_axis.y * angle_cos_1); mat->row0.y = temp.x + _axis_sin.z; mat->row1.y = temp.y + angle_cos; mat->row2.y = temp.z - _axis_sin.x; - vec3_mult_scalar(_axis, _axis.z * angle_cos_1, temp); + temp = _axis * (_axis.z * angle_cos_1); mat->row0.z = temp.x - _axis_sin.y; mat->row1.z = temp.y + _axis_sin.x; mat->row2.z = temp.z + angle_cos; @@ -1837,9 +1830,9 @@ inline void mat4_get_rotation(const mat4* x, vec3* z) { } inline void mat4_get_scale(const mat4* x, vec3* z) { - vec4_length(x->row0, z->x); - vec4_length(x->row1, z->y); - vec4_length(x->row2, z->z); + z->x = vec4::length(x->row0); + z->y = vec4::length(x->row1); + z->z = vec4::length(x->row2); } inline void mat4_get_translation(const mat4* x, vec3* z) { @@ -1851,12 +1844,12 @@ inline void mat4_set_translation(mat4* x, vec3* z) { } inline void mat4_blend(const mat4* x, const mat4* y, mat4* z, float_t blend) { + quat q0; quat q1; quat q2; - quat q3; quat_from_mat3(x->row0.x, x->row1.x, x->row2.x, x->row0.y, - x->row1.y, x->row2.y, x->row0.z, x->row1.z, x->row2.z, &q1); + x->row1.y, x->row2.y, x->row0.z, x->row1.z, x->row2.z, &q0); quat_from_mat3(y->row0.x, y->row1.x, y->row2.x, y->row0.y, y->row1.y, y->row2.y, y->row0.z, y->row1.z, y->row2.z, &q1); @@ -1866,10 +1859,10 @@ inline void mat4_blend(const mat4* x, const mat4* y, mat4* z, float_t blend) { mat4_get_translation(x, &t1); mat4_get_translation(y, &t2); - quat_slerp(&q3, &q1, &q2, blend); - vec3_lerp_scalar(t1, t2, t3, blend); + q2 = quat::slerp(q0, q1, blend); + t3 = vec3::lerp(t1, t2, blend); - mat4_from_quat(&q3, z); + mat4_from_quat(&q2, z); mat4_set_translation(z, &t3); } @@ -1882,20 +1875,18 @@ inline void mat4_blend_rotation(const mat4* x, const mat4* y, mat4* z, float_t b x->row1.y, x->row2.y, x->row0.z, x->row1.z, x->row2.z, &q1); quat_from_mat3(y->row0.x, y->row1.x, y->row2.x, y->row0.y, y->row1.y, y->row2.y, y->row0.z, y->row1.z, y->row2.z, &q1); - quat_slerp(&q0, &q1, &q2, blend); + q2 = quat::slerp(q0, q1, blend); mat4_from_quat(&q2, z); } void mat4_lerp_rotation(mat4* dst, const mat4* src0, const mat4* src1, float_t blend) { vec3 m0; vec3 m1; - vec3_lerp_scalar(*(vec3*)&src0->row0, *(vec3*)&src1->row0, m0, blend); - vec3_lerp_scalar(*(vec3*)&src0->row1, *(vec3*)&src1->row1, m1, blend); + m0 = vec3::lerp(*(vec3*)&src0->row0, *(vec3*)&src1->row0, blend); + m1 = vec3::lerp(*(vec3*)&src0->row1, *(vec3*)&src1->row1, blend); - float_t m0_len_sq; - float_t m1_len_sq; - vec3_length_squared(m0, m0_len_sq); - vec3_length_squared(m1, m1_len_sq); + float_t m0_len_sq = vec3::length_squared(m0); + float_t m1_len_sq = vec3::length_squared(m1); if (m0_len_sq <= 0.000001f || m1_len_sq <= 0.000001f) { *dst = *src1; @@ -1903,12 +1894,12 @@ void mat4_lerp_rotation(mat4* dst, const mat4* src0, const mat4* src1, float_t b } vec3 m2; - vec3_cross(m0, m1, m2); - vec3_cross(m2, m0, m1); + m2 = vec3::cross(m0, m1); + m1 = vec3::cross(m2, m0); float_t m2_len_sq; - vec3_length_squared(m1, m1_len_sq); - vec3_length_squared(m2, m2_len_sq); + m1_len_sq = vec3::length_squared(m1); + m2_len_sq = vec3::length_squared(m2); if (m2_len_sq <= 0.000001f || m1_len_sq <= 0.000001) { *dst = *src1; return; @@ -1916,15 +1907,15 @@ void mat4_lerp_rotation(mat4* dst, const mat4* src0, const mat4* src1, float_t b float_t m0_len = sqrtf(m0_len_sq); if (m0_len != 0.0f) - vec3_div_scalar(m0, 1.0f / m0_len, m0); + m0 *= 1.0f / m0_len; float_t m1_len = sqrtf(m1_len_sq); if (m1_len != 0.0f) - vec3_div_scalar(m1, 1.0f / m1_len, m1); + m1 *= 1.0f / m1_len; float_t m2_len = sqrtf(m2_len_sq); if (m2_len != 0.0f) - vec3_div_scalar(m2, 1.0f / m2_len, m2); + m2 *= 1.0f / m2_len; *dst = mat4_identity; *(vec3*)&dst->row0 = m0; @@ -1938,13 +1929,13 @@ inline float_t mat4_get_max_scale(const mat4* x) { float_t length; float_t max = 0.0f; - vec3_length(*(vec3*)&mat.row0, length); + length = vec3::length(*(vec3*)&mat.row0); if (max < length) max = length; - vec3_length(*(vec3*)&mat.row1, length); + length = vec3::length(*(vec3*)&mat.row1); if (max < length) max = length; - vec3_length(*(vec3*)&mat.row2, length); + length = vec3::length(*(vec3*)&mat.row2); if (max < length) max = length; return max; @@ -2010,39 +2001,32 @@ inline void mat4_persp(double_t fov_y, double_t aspect, double_t z_near, double_ inline void mat4_look_at(const vec3* eye, const vec3* target, const vec3* up, mat4* mat) { vec3 x_axis, y_axis, z_axis; - float_t t; vec3 xyz; - vec3_sub(*eye, *target, z_axis); - vec3_normalize(z_axis, z_axis); + z_axis = vec3::normalize(*eye - *target); - vec3_cross(*up, z_axis, x_axis); - vec3_normalize(x_axis, x_axis); - vec3_length(x_axis, t); - if (t == 0.0f) + x_axis = vec3::normalize(vec3::cross(*up, z_axis)); + if (vec3::length(x_axis) == 0.0f) x_axis = { 1.0f, 0.0f, 0.0f }; - vec3_cross(z_axis, x_axis, y_axis); - vec3_normalize(y_axis, y_axis); - vec3_dot(x_axis, *eye, xyz.x); - vec3_dot(y_axis, *eye, xyz.y); - vec3_dot(z_axis, *eye, xyz.z); + y_axis = vec3::normalize(vec3::cross(z_axis, x_axis)); + + xyz.x = vec3::dot(x_axis, *eye); + xyz.y = vec3::dot(y_axis, *eye); + xyz.z = vec3::dot(z_axis, *eye); mat->row0 = { x_axis.x, y_axis.x, z_axis.x, 0.0f }; mat->row1 = { x_axis.y, y_axis.y, z_axis.y, 0.0f }; mat->row2 = { x_axis.z, y_axis.z, z_axis.z, 0.0f }; - vec3_negate(xyz, xyz); - *(vec3*)&mat->row3 = xyz; + *(vec3*)&mat->row3 = -xyz; mat->row3.w = 1.0f; } inline void mat4_look_at(const vec3* eye, const vec3* target, mat4* mat) { vec3 up = { 0.0f, 1.0f, 0.0f }; vec3 dir; - float_t length; - vec3_sub(*target, *eye, dir); - vec3_length_squared(dir, length); - if (length <= 0.000001f) { + dir = *target - *eye; + if (vec3::length_squared(dir) <= 0.000001f) { up.x = 0.0f; up.y = 0.0f; if (dir.z < 0.0f) diff --git a/src/KKdLib/mot.cpp b/src/KKdLib/mot.cpp index 8366ace7..400a860a 100644 --- a/src/KKdLib/mot.cpp +++ b/src/KKdLib/mot.cpp @@ -6,7 +6,7 @@ #include "mot.hpp" #include "f2/struct.hpp" #include "io/path.hpp" -#include "io/stream.hpp" +#include "io/memory_stream.hpp" #include "interpolation.hpp" #include "half_t.hpp" #include "hash.hpp" @@ -60,7 +60,7 @@ mot_data::~mot_data() { } -mot_set::mot_set() : ready(), modern(), is_x() { +mot_set::mot_set() : ready(), modern(), big_endian(), is_x() { } @@ -72,7 +72,7 @@ void mot_set::pack_file(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; + memory_stream s; s.open(); if (!modern) mot_classic_write_inner(this, s); @@ -85,7 +85,7 @@ void mot_set::unpack_file(const void* data, size_t size, bool modern) { if (!data || !size) return; - stream s; + memory_stream s; s.open(data, size); if (!modern) mot_classic_read_inner(this, s); @@ -93,6 +93,228 @@ void mot_set::unpack_file(const void* data, size_t size, bool modern) { mot_modern_read_inner(this, s); } +inline static float_t interpolate_mot_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 (t_1 * t1 + t * t2) * t_1 * df + (t * 2.0f - 3.0f) * (t * t) * (p1 - p2) + p1; +} + +inline static void interpolate_mot_reverse_value(float_t* arr, size_t length, + float_t* t1, float_t* t2, size_t f1, size_t f2, size_t f) { + *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 * 2.0f - 3.0f) * (_t1 * _t1) * (arr[f1] - arr[f2]); + float_t t1_t2_2 = arr[f + 1] - arr[f1] - (_t2 * 2.0f - 3.0f) * (_t2 * _t2) * (arr[f1] - arr[f2]); + 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); +} + +inline static void mot_set_add_key(uint16_t frame, float_t v, float_t t, + std::vector& frames, std::vector& values) { + frames.push_back(frame); + values.push_back(v); + values.push_back(t); +} + +inline static float_t mot_set_add_key(bool has_error, float_t* a, int32_t frame, + size_t i, float_t t1, float_t t2, float_t t2_old, + std::vector& frames, std::vector& values) { + if (has_error) { + float_t _t2 = t2_old; + for (size_t j = 0; j < i; j++) { + mot_set_add_key((uint16_t)(frame + j), a[j], _t2, frames, values); + _t2 = 0.0f; + mot_set_add_key((uint16_t)(frame + j), a[j], 0.0f, frames, values); + } + return 0.0f; + } + else { + mot_set_add_key((uint16_t)frame, a[0], t2_old, frames, values); + if (t2_old == 0.0f) + mot_set_add_key((uint16_t)frame, a[0], t2_old, frames, values); + if (t1 != t2_old) { + mot_set_add_key((uint16_t)frame, a[0], t1, frames, values); + if (t1 == 0.0f) + mot_set_add_key((uint16_t)frame, a[0], t1, frames, values); + } + return t2; + } +} + +mot_key_set_type mot_set::fit_keys_into_curve(std::vector& values_src, + std::vector& frames, std::vector& values) { + size_t count = values_src.size(); + if (!count) + return MOT_KEY_SET_NONE; + else if (count == 1) { + if (values_src[0] != 0.0f) { + values.push_back(values_src[0]); + return MOT_KEY_SET_STATIC; + } + else + return MOT_KEY_SET_NONE; + } + else { + uint32_t val = *(uint32_t*)&values_src.data()[0]; + uint32_t* arr = (uint32_t*)&values_src.data()[1]; + for (size_t i = count - 1; i; i--) + if (val != *arr++) + break; + + if (arr == (uint32_t*)(values_src.data() + count)) + if (values_src[0] != 0.0f) { + values.push_back(values_src[0]); + return MOT_KEY_SET_STATIC; + } + else + return MOT_KEY_SET_NONE; + } + + int32_t start_time = 0; + int32_t end_time = (int32_t)(count - 1); + + float_t* arr = values_src.data(); + + const float_t reverse_bias = 0.0001f; + const int32_t reverse_min_count = 4; + + float_t* a = arr; + size_t left_count = count; + int32_t frame = start_time; + int32_t prev_frame = start_time; + float_t t2_old = 0.0f; + while (left_count > 0) { + if (left_count < reverse_min_count) { + if (left_count > 1) + t2_old = mot_set_add_key(true, a, frame, left_count - 1, 0.0f, 0.0f, t2_old, frames, values); + break; + } + + size_t i = 0; + size_t i_prev = 0; + 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 has_error = false; + bool has_prev_error = false; + + int32_t c = 0; + for (i = reverse_min_count - 1, i_prev = i; i < left_count; i++) { + double_t tt1 = 0.0; + double_t tt2 = 0.0; + for (size_t j = 1; j < i; j++) { + float_t _t1 = 0.0f; + float_t _t2 = 0.0f; + interpolate_mot_reverse_value(a, left_count, &_t1, &_t2, 0, i, j); + tt1 += _t1; + tt2 += _t2; + } + t1 = (float_t)(tt1 / (double_t)(i - 2)); + t2 = (float_t)(tt2 / (double_t)(i - 2)); + + has_error = false; + for (size_t j = 1; j < i - 1; j++) { + float_t val = interpolate_mot_value(a[0], a[i], t1, t2, 0.0f, (float_t)i, (float_t)j); + if (fabsf(val - a[j]) > reverse_bias) { + has_error = true; + break; + } + } + + if (fabsf(t1) > 0.5f || fabsf(t2) > 0.5f) + has_error = true; + + if (!has_error) { + i_prev = i; + t1_prev = t1; + t2_prev = t2; + has_prev_succeded = true; + has_prev_error = has_error; + if (i < left_count) + continue; + } + + if (has_prev_succeded) { + i = i_prev; + t1 = t1_prev; + t2 = t2_prev; + has_error = has_prev_error; + } + + if (!has_error) + c = (int32_t)i; + else + c = 1; + + t2_old = mot_set_add_key(has_error, a, frame, c, t1, t2, t2_old, frames, values); + has_prev_succeded = false; + break; + + if (!has_error) { + i_prev = i; + t1_prev = t1; + t2_prev = t2; + has_prev_succeded = true; + has_prev_error = has_error; + if (i < left_count) + continue; + } + break; + } + + if (has_prev_succeded) { + t2_old = mot_set_add_key(has_error, a, frame, c, t1_prev, t2_prev, t2_old, frames, values); + c = (int32_t)i; + } + + prev_frame = frame; + frame += c; + a += c; + left_count -= c; + } + + mot_set_add_key((uint16_t)(start_time + (count - 1)), arr[count - 1], t2_old, frames, values); + if (t2_old != 0.0f) + mot_set_add_key((uint16_t)(start_time + (count - 1)), arr[count - 1], 0.0f, frames, values); + + + count = values.size() / 2; + arr = values.data(); + for (size_t i = count; i; i--) + if (*arr++ != 0.0f) + break; + + if (arr != values.data() + count) + return MOT_KEY_SET_HERMITE_TANGENT; + + float_t* arr_src = values.data(); + float_t* arr_dst = values.data(); + for (size_t i = count; i; i--) { + *arr_dst = *arr_src; + arr_src++; + arr_dst += 2; + } + values.resize(count); + return MOT_KEY_SET_HERMITE; +} + static void mot_classic_read_inner(mot_set* ms, stream& s) { size_t count = 0; while (s.read_uint64_t() != 0) { @@ -103,6 +325,7 @@ static void mot_classic_read_inner(mot_set* ms, stream& s) { if (count == 0) { ms->ready = false; ms->modern = false; + ms->big_endian = false; ms->is_x = false; } @@ -183,10 +406,11 @@ static void mot_classic_read_inner(mot_set* ms, stream& s) { } } } - free(mh); + free_def(mh); ms->ready = true; ms->modern = false; + ms->big_endian = false; ms->is_x = false; } @@ -262,7 +486,7 @@ static void mot_classic_write_inner(mot_set* ms, stream& s) { s.write_uint32_t(mh[i].key_set_offset); s.write_uint32_t(mh[i].bone_info_offset); } - free(mh); + free_def(mh); } static void mot_modern_read_inner(mot_set* ms, stream& s) { @@ -271,13 +495,16 @@ static void mot_modern_read_inner(mot_set* ms, stream& s) { if (st.header.signature != reverse_endianness_uint32_t('MOTC') || !st.data.size()) { ms->ready = false; ms->modern = false; + ms->big_endian = false; ms->is_x = false; return; } - stream s_motc; + bool big_endian = st.header.use_big_endian; + + memory_stream s_motc; s_motc.open(st.data); - s_motc.is_big_endian = st.header.use_big_endian; + s_motc.big_endian = big_endian; s_motc.set_position(0x0C, SEEK_SET); bool is_x = s_motc.read_uint32_t_reverse_endianness() == 0; @@ -394,15 +621,18 @@ static void mot_modern_read_inner(mot_set* ms, stream& s) { ms->ready = true; ms->modern = true; + ms->big_endian = big_endian; ms->is_x = is_x; } static void mot_modern_write_inner(mot_set* ms, stream& s) { - stream s_motc; - s_motc.open(); - + bool big_endian = ms->big_endian; bool is_x = ms->is_x; + memory_stream s_motc; + s_motc.open(); + s_motc.big_endian = big_endian; + uint32_t o; enrs e; enrs_entry ee; @@ -535,8 +765,8 @@ static void mot_modern_write_inner(mot_set* ms, stream& s) { mh.hash = hash_string_murmurhash(m->name); mh.key_set_count_offset = s_motc.get_position(); - s_motc.write_uint16_t(m->info); - s_motc.write_uint16_t(m->frame_count); + s_motc.write_uint16_t_reverse_endianness(m->info); + s_motc.write_uint16_t_reverse_endianness(m->frame_count); mh.key_set_types_offset = s_motc.get_position(); uint16_t key_set_type_buf = 0; @@ -548,13 +778,13 @@ static void mot_modern_write_inner(mot_set* ms, stream& s) { key_set_type_buf |= ((uint16_t)type & 0x03) << (j % 8 * 2); if (j % 8 == 7) { - s_motc.write_uint16_t(key_set_type_buf); + s_motc.write_uint16_t_reverse_endianness(key_set_type_buf); key_set_type_buf = 0; } } if (m->key_set_count % 8 != 0) - s_motc.write_uint16_t(key_set_type_buf); + s_motc.write_uint16_t_reverse_endianness(key_set_type_buf); s_motc.align_write(0x04); mh.key_set_offset = s_motc.get_position(); @@ -562,34 +792,34 @@ static void mot_modern_write_inner(mot_set* ms, stream& s) { mot_key_set_data* mks = &m->key_set[j]; if (mks->type == MOT_KEY_SET_STATIC) { if (mks->values[0] != 0.0f) - s.write_float_t(mks->values[0]); + s.write_float_t_reverse_endianness(mks->values[0]); } else if (mks->type != MOT_KEY_SET_NONE) { bool has_tangents = mks->type != MOT_KEY_SET_HERMITE; uint16_t keys_count = mks->keys_count; mot_key_set_data_type data_type = mks->data_type; - s_motc.write_uint16_t(keys_count); - s_motc.write_uint16_t((uint16_t)data_type); + s_motc.write_uint16_t_reverse_endianness(keys_count); + s_motc.write_uint16_t_reverse_endianness((uint16_t)data_type); uint8_t step = has_tangents ? 2 : 1; if (has_tangents) { float_t* values = &mks->values[1]; for (int32_t k = 0; k < keys_count; k++, values += step) - s_motc.write_float_t(*values); + s_motc.write_float_t_reverse_endianness(*values); } float_t* values = mks->values.data(); if (data_type == MOT_KEY_SET_DATA_F16) for (int32_t k = 0; k < keys_count; k++, values += step) - s_motc.write_half_t(float_to_half(*values)); + s_motc.write_half_t_reverse_endianness(float_to_half(*values)); else for (int32_t k = 0; k < keys_count; k++, values += step) - s_motc.write_float_t(*values); + s_motc.write_float_t_reverse_endianness(*values); s_motc.align_write(0x04); int16_t* frames = (int16_t*)mks->frames.data(); for (int32_t k = 0; k < keys_count; k++) - s_motc.write_int16_t(*frames++); + s_motc.write_int16_t_reverse_endianness(*frames++); s_motc.align_write(0x04); } } @@ -607,7 +837,7 @@ static void mot_modern_write_inner(mot_set* ms, stream& s) { mh.bone_hash_offset = s_motc.get_position(); for (int32_t j = 0; j < m->bone_info_count; j++) - s_motc.write_uint64_t(hash_string_murmurhash(m->bone_info[j].name)); + s_motc.write_uint64_t_reverse_endianness(hash_string_murmurhash(m->bone_info[j].name)); s_motc.align_write(0x10); mh.name_offset = s_motc.get_position(); @@ -627,36 +857,36 @@ static void mot_modern_write_inner(mot_set* ms, stream& s) { else for (int32_t j = 0; j < m->bone_info_count; j++) s_motc.write_offset_x(bone_info_offsets[j]); - free(bone_info_offsets); + free_def(bone_info_offsets); s_motc.set_position(0x00, SEEK_SET); if (!is_x) { - s_motc.write_uint64_t((uint64_t)mh.hash); + s_motc.write_uint64_t_reverse_endianness((uint64_t)mh.hash); s_motc.write_offset_f2(mh.name_offset, 0x40); s_motc.write_offset_f2(mh.key_set_count_offset, 0x40); s_motc.write_offset_f2(mh.key_set_types_offset, 0x40); s_motc.write_offset_f2(mh.key_set_offset, 0x40); s_motc.write_offset_f2(mh.bone_info_offset, 0x40); s_motc.write_offset_f2(mh.bone_hash_offset, 0x40); - s_motc.write_int32_t(mh.bone_info_count); + s_motc.write_int32_t_reverse_endianness(mh.bone_info_count); } else { - s_motc.write_uint64_t((uint64_t)mh.hash); + s_motc.write_uint64_t_reverse_endianness((uint64_t)mh.hash); s_motc.write_offset_x(mh.name_offset); s_motc.write_offset_x(mh.key_set_count_offset); s_motc.write_offset_x(mh.key_set_types_offset); s_motc.write_offset_x(mh.key_set_offset); s_motc.write_offset_x(mh.bone_info_offset); s_motc.write_offset_x(mh.bone_hash_offset); - s_motc.write_int32_t(mh.bone_info_count); + s_motc.write_int32_t_reverse_endianness(mh.bone_info_count); } if (m->div_frames > 0) { - s_motc.write_uint16_t(m->div_frames); + s_motc.write_uint16_t_reverse_endianness(m->div_frames); s_motc.write_uint8_t(m->div_count); } else { - s_motc.write_uint16_t(0); + s_motc.write_uint16_t_reverse_endianness(0); s_motc.write_uint8_t(0); } @@ -673,7 +903,7 @@ static void mot_modern_write_inner(mot_set* ms, stream& s) { st.header.signature = reverse_endianness_uint32_t('MOTC'); st.header.length = 0x40; - st.header.use_big_endian = false; + st.header.use_big_endian = big_endian; st.header.use_section_size = true; st.header.murmurhash = murmurhash; st.header.inner_signature = 0xFF010008; diff --git a/src/KKdLib/mot.hpp b/src/KKdLib/mot.hpp index 494b9b80..b800c011 100644 --- a/src/KKdLib/mot.hpp +++ b/src/KKdLib/mot.hpp @@ -67,6 +67,7 @@ struct mot_data { struct mot_set { bool ready; bool modern; + bool big_endian; bool is_x; std::string name; @@ -77,4 +78,7 @@ struct mot_set { void pack_file(void** data, size_t* size); void unpack_file(const void* data, size_t size, bool modern); + + static mot_key_set_type fit_keys_into_curve(std::vector& values_src, + std::vector& frames, std::vector& values); }; diff --git a/src/KKdLib/msgpack.cpp b/src/KKdLib/msgpack.cpp index 2bbacee8..0ec2b063 100644 --- a/src/KKdLib/msgpack.cpp +++ b/src/KKdLib/msgpack.cpp @@ -4,407 +4,12 @@ */ #include "msgpack.hpp" -#include "str_utils.hpp" - -#define MSGPACK_ALLOCATE(a, b) \ -if (MSGPACK_CHECK(a)) \ - (b).data.ptr = new (a); -#define MSGPACK_ALLOCATE_PTR(a, b) \ -if (MSGPACK_CHECK(a)) \ - (b)->data.ptr = new (a); - -msgpack::msgpack() : data() { - type = MSGPACK_NULL; -} - -msgpack::msgpack(const msgpack& m) : type(), data() { - if (this == &m) - return; - - switch (m.type) { - case MSGPACK_BOOL: { - MSGPACK_ALLOCATE_PTR(double_t, this); - bool* s_ptr = MSGPACK_SELECT(bool, m); - bool* d_ptr = MSGPACK_SELECT_PTR(bool, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_INT8: { - MSGPACK_ALLOCATE_PTR(int8_t, this); - int8_t* s_ptr = MSGPACK_SELECT(int8_t, m); - int8_t* d_ptr = MSGPACK_SELECT_PTR(int8_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_UINT8: { - MSGPACK_ALLOCATE_PTR(uint8_t, this); - uint8_t* s_ptr = MSGPACK_SELECT(uint8_t, m); - uint8_t* d_ptr = MSGPACK_SELECT_PTR(uint8_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_INT16: { - MSGPACK_ALLOCATE_PTR(int16_t, this); - int16_t* s_ptr = MSGPACK_SELECT(int16_t, m); - int16_t* d_ptr = MSGPACK_SELECT_PTR(int16_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_UINT16: { - MSGPACK_ALLOCATE_PTR(uint16_t, this); - uint16_t* s_ptr = MSGPACK_SELECT(uint16_t, m); - uint16_t* d_ptr = MSGPACK_SELECT_PTR(uint16_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_INT32: { - MSGPACK_ALLOCATE_PTR(int32_t, this); - int32_t* s_ptr = MSGPACK_SELECT(int32_t, m); - int32_t* d_ptr = MSGPACK_SELECT_PTR(int32_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_UINT32: { - MSGPACK_ALLOCATE_PTR(uint32_t, this); - uint32_t* s_ptr = MSGPACK_SELECT(uint32_t, m); - uint32_t* d_ptr = MSGPACK_SELECT_PTR(uint32_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_INT64: { - MSGPACK_ALLOCATE_PTR(int64_t, this); - int64_t* s_ptr = MSGPACK_SELECT(int64_t, m); - int64_t* d_ptr = MSGPACK_SELECT_PTR(int64_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_UINT64: { - MSGPACK_ALLOCATE_PTR(uint64_t, this); - uint64_t* s_ptr = MSGPACK_SELECT(uint64_t, m); - uint64_t* d_ptr = MSGPACK_SELECT_PTR(uint64_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_FLOAT: { - MSGPACK_ALLOCATE_PTR(float_t, this); - float_t* s_ptr = MSGPACK_SELECT(float_t, m); - float_t* d_ptr = MSGPACK_SELECT_PTR(float_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_DOUBLE: { - MSGPACK_ALLOCATE_PTR(double_t, this); - double_t* s_ptr = MSGPACK_SELECT(double_t, m); - double_t* d_ptr = MSGPACK_SELECT_PTR(double_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_STRING: { - MSGPACK_ALLOCATE_PTR(std::string, this); - std::string* s_ptr = MSGPACK_SELECT(std::string, m); - std::string* d_ptr = MSGPACK_SELECT_PTR(std::string, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_ARRAY: - case MSGPACK_MAP: { - MSGPACK_ALLOCATE_PTR(msgpack_array, this); - msgpack_array* s_ptr = MSGPACK_SELECT(msgpack_array, m); - msgpack_array* d_ptr = MSGPACK_SELECT_PTR(msgpack_array, this); - *d_ptr = *s_ptr; - } break; - } - type = m.type; - name = m.name; -} - -msgpack::msgpack(const char* name, bool array, size_t length) : data() { - type = array ? MSGPACK_ARRAY : MSGPACK_MAP; - MSGPACK_ALLOCATE_PTR(msgpack_array, this); - if (name) - this->name = std::string(name); - - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, this); - *ptr = {}; - ptr->resize(length); -} - -msgpack::msgpack(const char* name, bool array, msgpack_array& val) : data() { - type = array ? MSGPACK_ARRAY : MSGPACK_MAP; - MSGPACK_ALLOCATE_PTR(msgpack_array, this); - if (name) - this->name = std::string(name); - - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, this); - *ptr = val; -} - -msgpack::msgpack(const char* name) : data() { - type = MSGPACK_NULL; - if (name) - this->name = std::string(name); -} - -msgpack::msgpack(const char* name, bool val) : data() { - type = MSGPACK_BOOL; - MSGPACK_ALLOCATE_PTR(bool, this); - if (name) - this->name = std::string(name); - - bool* ptr = MSGPACK_SELECT_PTR(bool, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, int8_t val) : data() { - type = MSGPACK_INT8; - MSGPACK_ALLOCATE_PTR(int8_t, this); - if (name) - this->name = std::string(name); - - int8_t* ptr = MSGPACK_SELECT_PTR(int8_t, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, uint8_t val) : data() { - type = MSGPACK_UINT8; - MSGPACK_ALLOCATE_PTR(uint8_t, this); - if (name) - this->name = std::string(name); - - uint8_t* ptr = MSGPACK_SELECT_PTR(uint8_t, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, int16_t val) : data() { - type = MSGPACK_INT16; - MSGPACK_ALLOCATE_PTR(int16_t, this); - if (name) - this->name = std::string(name); - - int16_t* ptr = MSGPACK_SELECT_PTR(int16_t, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, uint16_t val) : data() { - type = MSGPACK_UINT16; - MSGPACK_ALLOCATE_PTR(uint16_t, this); - if (name) - this->name = std::string(name); - - uint16_t* ptr = MSGPACK_SELECT_PTR(uint16_t, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, int32_t val) : data() { - type = MSGPACK_INT32; - MSGPACK_ALLOCATE_PTR(int32_t, this); - if (name) - this->name = std::string(name); - - int32_t* ptr = MSGPACK_SELECT_PTR(int32_t, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, uint32_t val) : data() { - type = MSGPACK_UINT32; - MSGPACK_ALLOCATE_PTR(uint32_t, this); - if (name) - this->name = std::string(name); - - uint32_t* ptr = MSGPACK_SELECT_PTR(uint32_t, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, int64_t val) : data() { - type = MSGPACK_INT64; - MSGPACK_ALLOCATE_PTR(int64_t, this); - if (name) - this->name = std::string(name); - - int64_t* ptr = MSGPACK_SELECT_PTR(int64_t, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, uint64_t val) : data() { - type = MSGPACK_UINT64; - MSGPACK_ALLOCATE_PTR(uint64_t, this); - if (name) - this->name = std::string(name); - - uint64_t* ptr = MSGPACK_SELECT_PTR(uint64_t, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, float_t val) : data() { - type = MSGPACK_FLOAT; - MSGPACK_ALLOCATE_PTR(float_t, this); - if (name) - this->name = std::string(name); - - float_t* ptr = MSGPACK_SELECT_PTR(float_t, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, double_t val) : data() { - type = MSGPACK_DOUBLE; - MSGPACK_ALLOCATE_PTR(double_t, this); - if (name) - this->name = std::string(name); - - double_t* ptr = MSGPACK_SELECT_PTR(double_t, this); - *ptr = val; -} - -msgpack::msgpack(const char* name, const char* val) : data() { - type = MSGPACK_STRING; - MSGPACK_ALLOCATE_PTR(std::string, this); - if (name) - this->name = std::string(name); - std::string* ptr = MSGPACK_SELECT_PTR(std::string, this); - *ptr = {}; - if (val) - *ptr = std::string(val); -} - -msgpack::msgpack(const char* name, const wchar_t* val) : data() { - type = MSGPACK_STRING; - MSGPACK_ALLOCATE_PTR(std::string, this); - if (name) - this->name = std::string(name); - std::string* ptr = MSGPACK_SELECT_PTR(std::string, this); - *ptr = {}; - if (val) - *ptr = utf16_to_utf8(val); -} - -msgpack::msgpack(const char* name, std::string& val) : data() { - type = MSGPACK_STRING; - MSGPACK_ALLOCATE_PTR(std::string, this); - if (name) - this->name = std::string(name); - std::string* ptr = MSGPACK_SELECT_PTR(std::string, this); - *ptr = {}; - if (val.size()) - *ptr = val; -} - -msgpack::msgpack(const char* name, std::wstring& val) : data() { - type = MSGPACK_STRING; - MSGPACK_ALLOCATE_PTR(std::string, this); - if (name) - this->name = std::string(name); - std::string* ptr = MSGPACK_SELECT_PTR(std::string, this); - *ptr = {}; - if (val.size()) - *ptr = utf16_to_utf8(val); -} - -msgpack::~msgpack() { - switch (type) { - case MSGPACK_BOOL: { - bool* ptr = MSGPACK_SELECT_PTR(bool, this); - if (MSGPACK_CHECK(bool)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_INT8: { - int8_t* ptr = MSGPACK_SELECT_PTR(int8_t, this); - if (MSGPACK_CHECK(int8_t)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_UINT8: { - uint8_t* ptr = MSGPACK_SELECT_PTR(uint8_t, this); - if (MSGPACK_CHECK(uint8_t)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_INT16: { - int16_t* ptr = MSGPACK_SELECT_PTR(int16_t, this); - if (MSGPACK_CHECK(int16_t)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_UINT16: { - uint16_t* ptr = MSGPACK_SELECT_PTR(uint16_t, this); - if (MSGPACK_CHECK(uint16_t)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_INT32: { - int32_t* ptr = MSGPACK_SELECT_PTR(int32_t, this); - if (MSGPACK_CHECK(int32_t)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_UINT32: { - uint32_t* ptr = MSGPACK_SELECT_PTR(uint32_t, this); - if (MSGPACK_CHECK(uint32_t)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_INT64: { - int64_t* ptr = MSGPACK_SELECT_PTR(int64_t, this); - if (MSGPACK_CHECK(int64_t)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_UINT64: { - uint64_t* ptr = MSGPACK_SELECT_PTR(uint64_t, this); - if (MSGPACK_CHECK(uint64_t)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_FLOAT: { - float_t* ptr = MSGPACK_SELECT_PTR(float_t, this); - if (MSGPACK_CHECK(float_t)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_DOUBLE: { - double_t* ptr = MSGPACK_SELECT_PTR(double_t, this); - if (MSGPACK_CHECK(double_t)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_STRING: { - std::string* ptr = MSGPACK_SELECT_PTR(std::string, this); - ptr->clear(); - ptr->shrink_to_fit(); - if (MSGPACK_CHECK(std::string)) { - delete ptr; - data.ptr = 0; - } - } break; - case MSGPACK_ARRAY: - case MSGPACK_MAP: { - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, this); - ptr->clear(); - ptr->shrink_to_fit(); - if (MSGPACK_CHECK(msgpack_array)) { - delete ptr; - data.ptr = 0; - } - } break; - } -} - -bool msgpack::check_null() { - if (type == MSGPACK_ARRAY || type == MSGPACK_MAP) - return MSGPACK_SELECT_PTR(msgpack_array, this)->size() == 0; - return type == MSGPACK_NONE; -} - -bool msgpack::check_not_null() { - if (type == MSGPACK_ARRAY || type == MSGPACK_MAP) - return MSGPACK_SELECT_PTR(msgpack_array, this)->size() != 0; - return type != MSGPACK_NONE; -} msgpack* msgpack::get_by_index(size_t index) { if (type != MSGPACK_ARRAY) return 0; - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, this); + msgpack_array* ptr = data.arr; if (index < ptr->size()) return &ptr->data()[index]; return 0; @@ -414,10 +19,9 @@ void msgpack::set_by_index(msgpack* m, size_t index) { if (type != MSGPACK_ARRAY) return; - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, this); + msgpack_array* ptr = data.arr; if (index < ptr->size()) { msgpack& msg = ptr->data()[index]; - msg.~msgpack(); msg = *m; } } @@ -426,54 +30,77 @@ msgpack* msgpack::get_by_name(const char* name) { if (type != MSGPACK_MAP) return 0; - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, this); - for (msgpack& i : *ptr) - if (!i.name.compare(name)) - return &i; + msgpack_map* ptr = data.map; + for (msgpack_key_value& i : *ptr) + if (!i.first.compare(name)) + return &i.second; return 0; } -void msgpack::set_by_name(msgpack* m) { +void msgpack::set_by_name(const char* name, msgpack* m) { if (type != MSGPACK_MAP) return; - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, this); - for (msgpack& i : *ptr) - if (!i.name.compare(m->name)) { - i.~msgpack(); - i = *m; + msgpack_map* ptr = data.map; + for (msgpack_key_value& i : *ptr) + if (!i.first.compare(name)) { + i.second = *m; return; } - append(m); + append(name, m); } -void msgpack::append(msgpack* m) { +msgpack* msgpack::append(const char* name, msgpack* m) { if (type != MSGPACK_MAP) - return; + return 0; - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, this); - ptr->push_back(*m); - *m = {}; + msgpack* tm = get_by_name(name); + if (tm) { + *tm = *m; + m->clear(); + return tm; + } + else { + data.map->push_back({ name, *m }); + m->clear(); + return &data.map->back().second; + } } -void msgpack::append(msgpack& m) { +msgpack* msgpack::append(const char* name, msgpack& m) { if (type != MSGPACK_MAP) - return; + return 0; - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, this); - ptr->push_back(m); - m = {}; + msgpack* tm = get_by_name(name); + if (tm) { + *tm = m; + m.clear(); + return tm; + } + else { + data.map->push_back({ name, m }); + m.clear(); + return &data.map->back().second; + } } -void msgpack::append(msgpack&& m) { +msgpack* msgpack::append(const char* name, msgpack&& m) { if (type != MSGPACK_MAP) - return; + return 0; - msgpack_array* ptr = MSGPACK_SELECT_PTR(msgpack_array, this); - ptr->push_back(m); - m = {}; + msgpack* tm = get_by_name(name); + if (tm) { + *tm = m; + m.clear(); + return tm; + } + else { + data.map->push_back({ name, m }); + m.clear(); + return &data.map->back().second; + } } msgpack* msgpack::read(const char* name) { @@ -483,13 +110,43 @@ msgpack* msgpack::read(const char* name) { return name ? get_by_name(name) : this; } +msgpack* msgpack::read(const char* name, msgpack_type type) { + if (!this) + return 0; + + msgpack* m = name ? get_by_name(name) : this; + if (m && m->type == type) + return m; + return 0; +} + +msgpack* msgpack::read_array(const char* name) { + if (!this) + return 0; + + msgpack* m = name ? get_by_name(name) : this; + if (m && m->type == MSGPACK_ARRAY) + return m; + return 0; +} + +msgpack* msgpack::read_map(const char* name) { + if (!this) + return 0; + + msgpack* m = name ? get_by_name(name) : this; + if (m && m->type == MSGPACK_MAP) + return m; + return 0; +} + bool msgpack::read_bool(const char* name) { if (!this) return 0; msgpack* m = name ? get_by_name(name) : this; if (m && m->type == MSGPACK_BOOL) - return *MSGPACK_SELECT_PTR(bool, m); + return m->data.b; return 0; } @@ -502,9 +159,9 @@ int8_t msgpack::read_int8_t(const char* name) { return 0; if (m->type == MSGPACK_INT8) - return *MSGPACK_SELECT_PTR(int8_t, m); + return m->data.i8; else if (m->type == MSGPACK_UINT8) - return (int8_t)*MSGPACK_SELECT_PTR(uint8_t, m); + return (int8_t)m->data.u8; return 0; } @@ -517,9 +174,9 @@ uint8_t msgpack::read_uint8_t(const char* name) { return 0; if (m->type == MSGPACK_INT8) - return (uint8_t)*MSGPACK_SELECT_PTR(int8_t, m); + return (uint8_t)m->data.i8; else if (m->type == MSGPACK_UINT8) - return *MSGPACK_SELECT_PTR(uint8_t, m); + return m->data.u8; return 0; } @@ -532,13 +189,13 @@ int16_t msgpack::read_int16_t(const char* name) { return 0; if (m->type == MSGPACK_INT8) - return *MSGPACK_SELECT_PTR(int8_t, m); + return m->data.i8; else if (m->type == MSGPACK_UINT8) - return *MSGPACK_SELECT_PTR(uint8_t, m); + return m->data.u8; else if (m->type == MSGPACK_INT16) - return *MSGPACK_SELECT_PTR(int16_t, m); + return m->data.i16; else if (m->type == MSGPACK_UINT16) - return (int16_t)*MSGPACK_SELECT_PTR(uint16_t, m); + return (int16_t)m->data.u16; return 0; } @@ -551,13 +208,13 @@ uint16_t msgpack::read_uint16_t(const char* name) { return 0; if (m->type == MSGPACK_INT8) - return (uint16_t)(int16_t)*MSGPACK_SELECT_PTR(int8_t, m); + return (uint16_t)(int16_t)m->data.i8; else if (m->type == MSGPACK_UINT8) - return *MSGPACK_SELECT_PTR(uint8_t, m); + return m->data.u8; else if (m->type == MSGPACK_INT16) - return (uint16_t)(int16_t)*MSGPACK_SELECT_PTR(int16_t, m); + return (uint16_t)(int16_t)m->data.i16; else if (m->type == MSGPACK_UINT16) - return *MSGPACK_SELECT_PTR(uint16_t, m); + return m->data.u16; return 0; } @@ -570,17 +227,17 @@ int32_t msgpack::read_int32_t(const char* name) { return 0; if (m->type == MSGPACK_INT8) - return *MSGPACK_SELECT_PTR(int8_t, m); + return m->data.i8; else if (m->type == MSGPACK_UINT8) - return *MSGPACK_SELECT_PTR(uint8_t, m); + return m->data.u8; else if (m->type == MSGPACK_INT16) - return *MSGPACK_SELECT_PTR(int16_t, m); + return m->data.i16; else if (m->type == MSGPACK_UINT16) - return *MSGPACK_SELECT_PTR(uint16_t, m); + return m->data.u16; else if (m->type == MSGPACK_INT32) - return *MSGPACK_SELECT_PTR(int32_t, m); + return m->data.i32; else if (m->type == MSGPACK_UINT32) - return (int32_t)*MSGPACK_SELECT_PTR(uint32_t, m); + return (int32_t)m->data.u32; return 0; } @@ -593,17 +250,17 @@ uint32_t msgpack::read_uint32_t(const char* name) { return 0; if (m->type == MSGPACK_INT8) - return (uint32_t)(int32_t)*MSGPACK_SELECT_PTR(int8_t, m); + return (uint32_t)(int32_t)m->data.i8; else if (m->type == MSGPACK_UINT8) - return *MSGPACK_SELECT_PTR(uint8_t, m); + return m->data.u8; else if (m->type == MSGPACK_INT16) - return (uint32_t)(int32_t)*MSGPACK_SELECT_PTR(int16_t, m); + return (uint32_t)(int32_t)m->data.i16; else if (m->type == MSGPACK_UINT16) - return *MSGPACK_SELECT_PTR(uint16_t, m); + return m->data.u16; else if (m->type == MSGPACK_INT32) - return (uint32_t)(int32_t)*MSGPACK_SELECT_PTR(int32_t, m); + return (uint32_t)(int32_t)m->data.i32; else if (m->type == MSGPACK_UINT32) - return *MSGPACK_SELECT_PTR(uint32_t, m); + return m->data.u32; return 0; } @@ -616,21 +273,21 @@ int64_t msgpack::read_int64_t(const char* name) { return 0; if (m->type == MSGPACK_INT8) - return *MSGPACK_SELECT_PTR(int8_t, m); + return m->data.i8; else if (m->type == MSGPACK_UINT8) - return *MSGPACK_SELECT_PTR(uint8_t, m); + return m->data.u8; else if (m->type == MSGPACK_INT16) - return *MSGPACK_SELECT_PTR(int16_t, m); + return m->data.i16; else if (m->type == MSGPACK_UINT16) - return *MSGPACK_SELECT_PTR(uint16_t, m); + return m->data.u16; else if (m->type == MSGPACK_INT32) - return *MSGPACK_SELECT_PTR(int32_t, m); + return m->data.i32; else if (m->type == MSGPACK_UINT32) - return *MSGPACK_SELECT_PTR(uint32_t, m); + return m->data.u32; else if (m->type == MSGPACK_INT64) - return *MSGPACK_SELECT_PTR(int64_t, m); + return m->data.i64; else if (m->type == MSGPACK_UINT64) - return (int64_t)*MSGPACK_SELECT_PTR(uint64_t, m); + return (int64_t)m->data.u64; return 0; } @@ -643,21 +300,21 @@ uint64_t msgpack::read_uint64_t(const char* name) { return 0; if (m->type == MSGPACK_INT8) - return (uint64_t)(int64_t)*MSGPACK_SELECT_PTR(int8_t, m); + return (uint64_t)(int64_t)m->data.i8; else if (m->type == MSGPACK_UINT8) - return *MSGPACK_SELECT_PTR(uint8_t, m); + return m->data.u8; else if (m->type == MSGPACK_INT16) - return (uint64_t)(int64_t)*MSGPACK_SELECT_PTR(int16_t, m); + return (uint64_t)(int64_t)m->data.i16; else if (m->type == MSGPACK_UINT16) - return *MSGPACK_SELECT_PTR(uint16_t, m); + return m->data.u16; else if (m->type == MSGPACK_INT32) - return (uint64_t)(int64_t)*MSGPACK_SELECT_PTR(int32_t, m); + return (uint64_t)(int64_t)m->data.i32; else if (m->type == MSGPACK_UINT32) - return *MSGPACK_SELECT_PTR(uint32_t, m); + return m->data.u32; else if (m->type == MSGPACK_INT32) - return (uint64_t)*MSGPACK_SELECT_PTR(int64_t, m); + return (uint64_t)m->data.i64; else if (m->type == MSGPACK_UINT32) - return *MSGPACK_SELECT_PTR(uint64_t, m); + return m->data.u64; return 0; } @@ -670,25 +327,25 @@ float_t msgpack::read_float_t(const char* name) { return 0; if (m->type == MSGPACK_INT8) - return *MSGPACK_SELECT_PTR(int8_t, m); + return m->data.i8; else if (m->type == MSGPACK_UINT8) - return *MSGPACK_SELECT_PTR(uint8_t, m); + return m->data.u8; else if (m->type == MSGPACK_INT16) - return *MSGPACK_SELECT_PTR(int16_t, m); + return m->data.i16; else if (m->type == MSGPACK_UINT16) - return *MSGPACK_SELECT_PTR(uint16_t, m); + return m->data.u16; else if (m->type == MSGPACK_INT32) - return (float_t)*MSGPACK_SELECT_PTR(int32_t, m); + return (float_t)m->data.i32; else if (m->type == MSGPACK_UINT32) - return (float_t)*MSGPACK_SELECT_PTR(uint32_t, m); + return (float_t)m->data.u32; else if (m->type == MSGPACK_INT64) - return (float_t)*MSGPACK_SELECT_PTR(int64_t, m); + return (float_t)m->data.i64; else if (m->type == MSGPACK_UINT64) - return (float_t)*MSGPACK_SELECT_PTR(uint64_t, m); + return (float_t)m->data.u64; else if (m->type == MSGPACK_FLOAT) - return *MSGPACK_SELECT_PTR(float_t, m); + return m->data.f32; else if (m->type == MSGPACK_DOUBLE) - return (float_t)*MSGPACK_SELECT_PTR(double_t, m); + return (float_t)m->data.f64; return 0; } @@ -701,25 +358,25 @@ double_t msgpack::read_double_t(const char* name) { return 0; if (m->type == MSGPACK_INT8) - return *MSGPACK_SELECT_PTR(int8_t, m); + return m->data.i8; else if (m->type == MSGPACK_UINT8) - return *MSGPACK_SELECT_PTR(uint8_t, m); + return m->data.u8; else if (m->type == MSGPACK_INT16) - return *MSGPACK_SELECT_PTR(int16_t, m); + return m->data.i16; else if (m->type == MSGPACK_UINT16) - return *MSGPACK_SELECT_PTR(uint16_t, m); + return m->data.u16; else if (m->type == MSGPACK_INT32) - return *MSGPACK_SELECT_PTR(int32_t, m); + return m->data.i32; else if (m->type == MSGPACK_UINT32) - return *MSGPACK_SELECT_PTR(uint32_t, m); + return m->data.u32; else if (m->type == MSGPACK_INT64) - return (double_t)*MSGPACK_SELECT_PTR(int64_t, m); + return (double_t)m->data.i64; else if (m->type == MSGPACK_UINT64) - return (double_t)*MSGPACK_SELECT_PTR(uint64_t, m); + return (double_t)m->data.u64; else if (m->type == MSGPACK_FLOAT) - return *MSGPACK_SELECT_PTR(float_t, m); + return m->data.f32; else if (m->type == MSGPACK_DOUBLE) - return *MSGPACK_SELECT_PTR(double_t, m); + return m->data.f64; return 0; } @@ -728,12 +385,10 @@ char* msgpack::read_utf8_string(const char* name) { return 0; msgpack* m = name ? get_by_name(name) : this; - if (m && m->type == MSGPACK_STRING) { - std::string* ptr = MSGPACK_SELECT_PTR(std::string, m); - size_t length = ptr->size(); + size_t length = m->data.str->size(); char* val = force_malloc_s(char, length + 1); - memcpy(val, ptr->c_str(), length); + memcpy(val, m->data.str->c_str(), length); val[length] = 0; return val; } @@ -745,11 +400,8 @@ wchar_t* msgpack::read_utf16_string(const char* name) { return 0; msgpack* m = name ? get_by_name(name) : this; - - if (m && m->type == MSGPACK_STRING) { - std::string* ptr = MSGPACK_SELECT_PTR(std::string, m); - return utf8_to_utf16(ptr->c_str()); - } + if (m && m->type == MSGPACK_STRING) + return utf8_to_utf16(m->data.str->c_str()); return 0; } @@ -758,11 +410,8 @@ std::string msgpack::read_string(const char* name) { return {}; msgpack* m = name ? get_by_name(name) : this; - - if (m && m->type == MSGPACK_STRING) { - std::string* ptr = MSGPACK_SELECT_PTR(std::string, m); - return *ptr; - } + if (m && m->type == MSGPACK_STRING) + return *m->data.str; return {}; } @@ -771,11 +420,8 @@ std::wstring msgpack::read_wstring(const char* name) { return {}; msgpack* m = name ? get_by_name(name) : this; - - if (m && m->type == MSGPACK_STRING) { - std::string* ptr = MSGPACK_SELECT_PTR(std::string, m); - return utf8_to_utf16(*ptr); - } + if (m && m->type == MSGPACK_STRING) + return utf8_to_utf16(*m->data.str); return {}; } @@ -784,86 +430,89 @@ msgpack& msgpack::operator=(const msgpack& m) { return *this; switch (m.type) { - case MSGPACK_BOOL: { - MSGPACK_ALLOCATE_PTR(double_t, this); - bool* s_ptr = MSGPACK_SELECT(bool, m); - bool* d_ptr = MSGPACK_SELECT_PTR(bool, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_INT8: { - MSGPACK_ALLOCATE_PTR(int8_t, this); - int8_t* s_ptr = MSGPACK_SELECT(int8_t, m); - int8_t* d_ptr = MSGPACK_SELECT_PTR(int8_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_UINT8: { - MSGPACK_ALLOCATE_PTR(uint8_t, this); - uint8_t* s_ptr = MSGPACK_SELECT(uint8_t, m); - uint8_t* d_ptr = MSGPACK_SELECT_PTR(uint8_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_INT16: { - MSGPACK_ALLOCATE_PTR(int16_t, this); - int16_t* s_ptr = MSGPACK_SELECT(int16_t, m); - int16_t* d_ptr = MSGPACK_SELECT_PTR(int16_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_UINT16: { - MSGPACK_ALLOCATE_PTR(uint16_t, this); - uint16_t* s_ptr = MSGPACK_SELECT(uint16_t, m); - uint16_t* d_ptr = MSGPACK_SELECT_PTR(uint16_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_INT32: { - MSGPACK_ALLOCATE_PTR(int32_t, this); - int32_t* s_ptr = MSGPACK_SELECT(int32_t, m); - int32_t* d_ptr = MSGPACK_SELECT_PTR(int32_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_UINT32: { - MSGPACK_ALLOCATE_PTR(uint32_t, this); - uint32_t* s_ptr = MSGPACK_SELECT(uint32_t, m); - uint32_t* d_ptr = MSGPACK_SELECT_PTR(uint32_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_INT64: { - MSGPACK_ALLOCATE_PTR(int64_t, this); - int64_t* s_ptr = MSGPACK_SELECT(int64_t, m); - int64_t* d_ptr = MSGPACK_SELECT_PTR(int64_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_UINT64: { - MSGPACK_ALLOCATE_PTR(uint64_t, this); - uint64_t* s_ptr = MSGPACK_SELECT(uint64_t, m); - uint64_t* d_ptr = MSGPACK_SELECT_PTR(uint64_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_FLOAT: { - MSGPACK_ALLOCATE_PTR(float_t, this); - float_t* s_ptr = MSGPACK_SELECT(float_t, m); - float_t* d_ptr = MSGPACK_SELECT_PTR(float_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_DOUBLE: { - MSGPACK_ALLOCATE_PTR(double_t, this); - double_t* s_ptr = MSGPACK_SELECT(double_t, m); - double_t* d_ptr = MSGPACK_SELECT_PTR(double_t, this); - *d_ptr = *s_ptr; - } break; - case MSGPACK_STRING: { - MSGPACK_ALLOCATE_PTR(std::string, this); - std::string* s_ptr = MSGPACK_SELECT(std::string, m); - std::string* d_ptr = MSGPACK_SELECT_PTR(std::string, this); - *d_ptr = *s_ptr; - } break; + case MSGPACK_BOOL: + case MSGPACK_INT8: + case MSGPACK_UINT8: + case MSGPACK_INT16: + case MSGPACK_UINT16: + case MSGPACK_INT32: + case MSGPACK_UINT32: + case MSGPACK_INT64: + case MSGPACK_UINT64: + case MSGPACK_FLOAT: + case MSGPACK_DOUBLE: + switch (type) { + case MSGPACK_STRING: + delete data.str; + break; + case MSGPACK_ARRAY: + delete data.arr; + break; + case MSGPACK_MAP: + delete data.map; + break; + } + + memcpy(&data, &m.data, sizeof(data)); + break; + case MSGPACK_STRING: + switch (type) { + case MSGPACK_STRING: + break; + case MSGPACK_ARRAY: + delete data.arr; + data.str = new std::string; + break; + case MSGPACK_MAP: + delete data.map; + data.str = new std::string; + break; + default: + data.str = new std::string; + break; + } + data.str->assign(*m.data.str); + break; case MSGPACK_ARRAY: - case MSGPACK_MAP: { - MSGPACK_ALLOCATE_PTR(msgpack_array, this); - msgpack_array* s_ptr = MSGPACK_SELECT(msgpack_array, m); - msgpack_array* d_ptr = MSGPACK_SELECT_PTR(msgpack_array, this); - *d_ptr = *s_ptr; - } break;} + switch (type) { + case MSGPACK_STRING: + delete data.str; + data.arr = new msgpack_array; + break; + case MSGPACK_ARRAY: + break; + case MSGPACK_MAP: + delete data.map; + data.arr = new msgpack_array; + break; + default: + data.arr = new msgpack_array; + break; + } + data.arr->assign(m.data.arr->begin(), m.data.arr->end()); + break; + case MSGPACK_MAP: + switch (type) { + case MSGPACK_STRING: + delete data.str; + data.map = new msgpack_map; + break; + case MSGPACK_ARRAY: + delete data.arr; + data.map = new msgpack_map; + break; + case MSGPACK_MAP: + break; + default: + data.map = new msgpack_map; + break; + } + data.map->assign(m.data.map->begin(), m.data.map->end()); + break; + default: + memset(&data, 0, sizeof(data)); + break; + } type = m.type; - name = m.name; return *this; } diff --git a/src/KKdLib/msgpack.hpp b/src/KKdLib/msgpack.hpp index e2235021..ceac9395 100644 --- a/src/KKdLib/msgpack.hpp +++ b/src/KKdLib/msgpack.hpp @@ -31,53 +31,41 @@ enum msgpack_type : uint32_t { struct msgpack; typedef std::vector msgpack_array; +typedef std::pair msgpack_key_value; +typedef std::vector msgpack_map; union msgpack_data { - uint8_t data[0x08]; - union { - void* ptr; - std::string* str; - msgpack_array* arr; - }; + bool b; + int8_t i8; + uint8_t u8; + int16_t i16; + uint16_t u16; + int32_t i32; + uint32_t u32; + int64_t i64; + uint64_t u64; + float_t f32; + double_t f64; + std::string* str; + msgpack_array* arr; + msgpack_map* map; }; struct msgpack { msgpack_type type; - std::string name; msgpack_data data; - msgpack(); - msgpack(const msgpack& m); - msgpack(const char* name); - msgpack(const char* name, bool array, size_t length); - msgpack(const char* name, bool array, msgpack_array& val); - msgpack(const char* name, bool val); - msgpack(const char* name, int8_t val); - msgpack(const char* name, uint8_t val); - msgpack(const char* name, int16_t val); - msgpack(const char* name, uint16_t val); - msgpack(const char* name, int32_t val); - msgpack(const char* name, uint32_t val); - msgpack(const char* name, int64_t val); - msgpack(const char* name, uint64_t val); - msgpack(const char* name, float_t val); - msgpack(const char* name, double_t val); - msgpack(const char* name, const char* val); - msgpack(const char* name, const wchar_t* val); - msgpack(const char* name, std::string& val); - msgpack(const char* name, std::wstring& val); - ~msgpack(); - - bool check_null(); - bool check_not_null(); msgpack* get_by_index(size_t index); void set_by_index(msgpack* m, size_t index); msgpack* get_by_name(const char* name); - void set_by_name(msgpack* m); - void append(msgpack* m); - void append(msgpack& m); - void append(msgpack&& m); + void set_by_name(const char* name, msgpack* m); + msgpack* append(const char* name, msgpack* m); + msgpack* append(const char* name, msgpack& m); + msgpack* append(const char* name, msgpack&& m); msgpack* read(const char* name); + msgpack* read(const char* name, msgpack_type type); + msgpack* read_array(const char* name = 0); + msgpack* read_map(const char* name = 0); bool read_bool(const char* name = 0); int8_t read_int8_t(const char* name = 0); uint8_t read_uint8_t(const char* name = 0); @@ -95,8 +83,282 @@ struct msgpack { std::wstring read_wstring(const char* name = 0); msgpack& operator=(const msgpack& m); -}; -#define MSGPACK_CHECK(a) (sizeof(a) > 0x08) -#define MSGPACK_SELECT(a, b) (MSGPACK_CHECK(a) ? (a*)(b).data.ptr : (##a##*)(b).data.data) -#define MSGPACK_SELECT_PTR(a, b) (MSGPACK_CHECK(a) ? (a*)(b)->data.ptr : (##a##*)(b)->data.data) + inline msgpack() : data() { + type = MSGPACK_NULL; + } + + inline msgpack(const msgpack& m) : type(), data() { + if (this == &m) + return; + + switch (m.type) { + case MSGPACK_BOOL: + case MSGPACK_INT8: + case MSGPACK_UINT8: + case MSGPACK_INT16: + case MSGPACK_UINT16: + case MSGPACK_INT32: + case MSGPACK_UINT32: + case MSGPACK_INT64: + case MSGPACK_UINT64: + case MSGPACK_FLOAT: + case MSGPACK_DOUBLE: + switch (type) { + case MSGPACK_STRING: + delete data.str; + break; + case MSGPACK_ARRAY: + delete data.arr; + break; + case MSGPACK_MAP: + delete data.map; + break; + } + + memcpy(&data, &m.data, sizeof(data)); + break; + case MSGPACK_STRING: + switch (type) { + case MSGPACK_STRING: + break; + case MSGPACK_ARRAY: + delete data.arr; + data.str = new std::string; + break; + case MSGPACK_MAP: + delete data.map; + data.str = new std::string; + break; + default: + data.str = new std::string; + break; + } + data.str->assign(*m.data.str); + break; + case MSGPACK_ARRAY: + switch (type) { + case MSGPACK_STRING: + delete data.str; + data.arr = new msgpack_array; + break; + case MSGPACK_ARRAY: + break; + case MSGPACK_MAP: + delete data.map; + data.arr = new msgpack_array; + break; + default: + data.arr = new msgpack_array; + break; + } + data.arr->assign(m.data.arr->begin(), m.data.arr->end()); + break; + case MSGPACK_MAP: + switch (type) { + case MSGPACK_STRING: + delete data.str; + data.map = new msgpack_map; + break; + case MSGPACK_ARRAY: + delete data.arr; + data.map = new msgpack_map; + break; + case MSGPACK_MAP: + break; + default: + data.map = new msgpack_map; + break; + } + data.map->assign(m.data.map->begin(), m.data.map->end()); + break; + default: + memset(&data, 0, sizeof(data)); + break; + } + type = m.type; + } + + inline msgpack(msgpack_array& val) : data() { + type = MSGPACK_ARRAY; + data.arr = new msgpack_array; + data.arr->assign(val.begin(), val.end()); + val.clear(); + val.shrink_to_fit(); + } + + inline msgpack(msgpack_array&& val) : data() { + type = MSGPACK_ARRAY; + data.arr = new msgpack_array; + data.arr->assign(val.begin(), val.end()); + val.clear(); + val.shrink_to_fit(); + } + + inline msgpack(msgpack_map& val) : data() { + type = MSGPACK_MAP; + data.map = new msgpack_map; + data.map->assign(val.begin(), val.end()); + val.clear(); + val.shrink_to_fit(); + } + inline msgpack(msgpack_map&& val) : data() { + type = MSGPACK_MAP; + data.map = new msgpack_map; + data.map->assign(val.begin(), val.end()); + val.clear(); + val.shrink_to_fit(); + } + + inline msgpack(bool val) : data() { + type = MSGPACK_BOOL; + data.b = val; + } + + inline msgpack(int8_t val) : data() { + type = MSGPACK_INT8; + data.i64 = val; + } + + inline msgpack(uint8_t val) : data() { + type = MSGPACK_UINT8; + data.u64 = val; + } + + inline msgpack(int16_t val) : data() { + type = MSGPACK_INT16; + data.i64 = val; + } + + inline msgpack(uint16_t val) : data() { + type = MSGPACK_UINT16; + data.u64 = val; + } + + inline msgpack(int32_t val) : data() { + type = MSGPACK_INT32; + data.i64 = val; + } + + inline msgpack(uint32_t val) : data() { + type = MSGPACK_UINT32; + data.u64 = val; + } + + inline msgpack(int64_t val) : data() { + type = MSGPACK_INT64; + data.i64 = val; + } + + inline msgpack(uint64_t val) : data() { + type = MSGPACK_UINT64; + data.u64 = val; + } + + inline msgpack(float_t val) : data() { + type = MSGPACK_FLOAT; + data.f32 = val; + } + + inline msgpack(double_t val) : data() { + type = MSGPACK_DOUBLE; + data.f64 = val; + } + + inline msgpack(const char* val) : data() { + type = MSGPACK_STRING; + data.str = new std::string; + if (val) + data.str->assign(val); + } + + inline msgpack(const wchar_t* val) : data() { + type = MSGPACK_STRING; + data.str = new std::string; + if (val) { + char* temp = utf16_to_utf8(val); + data.str->assign(temp); + free_def(temp); + } + } + + inline msgpack(std::string& val) : data() { + type = MSGPACK_STRING; + data.str = new std::string; + if (val.size()) + data.str->assign(val); + } + + inline msgpack(std::string&& val) : data() { + type = MSGPACK_STRING; + data.str = new std::string; + if (val.size()) + data.str->assign(val); + } + + inline msgpack(std::wstring& val) : data() { + type = MSGPACK_STRING; + data.str = new std::string; + if (val.size()) { + char* temp = utf16_to_utf8(val.c_str()); + data.str->assign(temp); + free_def(temp); + } + } + + inline msgpack(std::wstring&& val) : data() { + type = MSGPACK_STRING; + data.str = new std::string; + if (val.size()) { + char* temp = utf16_to_utf8(val.c_str()); + data.str->assign(temp); + free_def(temp); + } + } + + inline ~msgpack() { + switch (type) { + case MSGPACK_STRING: + delete data.str; + break; + case MSGPACK_ARRAY: + delete data.arr; + break; + case MSGPACK_MAP: + delete data.map; + break; + } + } + + inline bool check_null() { + if (type == MSGPACK_ARRAY) + return data.arr->size() == 0; + else if (type == MSGPACK_MAP) + return data.map->size() == 0; + return type == MSGPACK_NONE; + } + + inline bool check_not_null() { + if (type == MSGPACK_ARRAY) + return data.arr->size() != 0; + else if (type == MSGPACK_MAP) + return data.map->size() != 0; + return type != MSGPACK_NONE; + } + + inline void clear() { + switch (type) { + case MSGPACK_STRING: + delete data.str; + break; + case MSGPACK_ARRAY: + delete data.arr; + break; + case MSGPACK_MAP: + delete data.map; + break; + } + type = MSGPACK_NONE; + memset(&data, 0, sizeof(data)); + } +}; diff --git a/src/KKdLib/obj.cpp b/src/KKdLib/obj.cpp index d79da3af..429dc8fe 100644 --- a/src/KKdLib/obj.cpp +++ b/src/KKdLib/obj.cpp @@ -5,9 +5,8 @@ #include "obj.hpp" #include +#include "io/memory_stream.hpp" #include "f2/struct.hpp" -#include "io/path.hpp" -#include "io/stream.hpp" #include "half_t.hpp" #include "hash.hpp" #include "sort.hpp" @@ -129,47 +128,47 @@ static void obj_classic_write_skin(obj* obj, stream& s, int64_t base_offset); static void obj_classic_read_skin_block_cloth(obj_skin_block_cloth* b, stream& s, char** str); static void obj_classic_write_skin_block_cloth(obj_skin_block_cloth* b, - stream& s, std::vector& strings, std::vector& string_offsets, + stream& s, std::vector& strings, std::vector& string_offsets, int64_t* mats_offset, int64_t* root_offset, int64_t* nodes_offset, int64_t* mesh_indices_offset, int64_t* backface_mesh_indices_offset); static void obj_classic_read_skin_block_cloth_root_bone_weight(obj_skin_block_cloth_root_bone_weight* sub, stream& s, char** str); static void obj_classic_write_skin_block_cloth_root_bone_weight(obj_skin_block_cloth_root_bone_weight* sub, - stream& s, std::vector& strings, std::vector& string_offsets); + stream& s, std::vector& strings, std::vector& string_offsets); static void obj_classic_read_skin_block_constraint(obj_skin_block_constraint* b, stream& s, char** str); static void obj_classic_write_skin_block_constraint(obj_skin_block_constraint* b, - stream& s, std::vector& strings, std::vector& string_offsets, + stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, int64_t* offsets); static void obj_classic_read_skin_block_constraint_attach_point(obj_skin_block_constraint_attach_point* ap, stream& s, char** str); static void obj_classic_write_skin_block_constraint_attach_point(obj_skin_block_constraint_attach_point* ap, - stream& s, std::vector& strings, std::vector& string_offsets); + stream& s, std::vector& strings, std::vector& string_offsets); static void obj_classic_read_skin_block_constraint_up_vector_old(obj_skin_block_constraint_up_vector* up, stream& s, char** str); static void obj_classic_write_skin_block_constraint_up_vector_old(obj_skin_block_constraint_up_vector* up, - stream& s, std::vector& strings, std::vector& string_offsets); + stream& s, std::vector& strings, std::vector& string_offsets); static void obj_classic_read_skin_block_expression(obj_skin_block_expression* b, stream& s, char** str); static void obj_classic_write_skin_block_expression(obj_skin_block_expression* b, - stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names); + stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names); static void obj_classic_read_skin_block_motion(obj_skin_block_motion* b, stream& s, char** str); static void obj_classic_write_skin_block_motion(obj_skin_block_motion* b, - stream& s, std::vector& strings, std::vector& string_offsets, + stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, int64_t* bone_names_offset, int64_t* bone_matrices_offset); static void obj_classic_read_skin_block_node(obj_skin_block_node* b, stream& s, char** str); static void obj_classic_write_skin_block_node(obj_skin_block_node* b, - stream& s, std::vector& strings, std::vector& string_offsets); + stream& s, std::vector& strings, std::vector& string_offsets); static void obj_classic_read_skin_block_osage(obj_skin_block_osage* b, stream& s, char** str); static void obj_classic_write_skin_block_osage(obj_skin_block_osage* b, - stream& s, std::vector& strings, std::vector& string_offsets, int64_t* nodes_offset); + stream& s, std::vector& strings, std::vector& string_offsets, int64_t* nodes_offset); static void obj_classic_read_skin_param(obj_skin_skin_param* skp, stream& s, char** str); static void obj_classic_write_skin_param(obj_skin_skin_param* skp, - stream& s, std::vector& strings, std::vector& string_offsets); + stream& s, std::vector& strings, std::vector& string_offsets); static void obj_classic_read_vertex(obj* obj, stream& s, int64_t* vertex, obj_mesh* mesh, int64_t base_offset, uint32_t num_vertex, obj_vertex_format_file vertex_format_file); static void obj_classic_write_vertex(obj* obj, stream& s, int64_t* vertex, obj_mesh* mesh, @@ -191,56 +190,56 @@ static void obj_modern_write_skin(obj* obj, stream& s, static void obj_modern_read_skin_block_cloth(obj_skin_block_cloth* b, stream& s, uint32_t header_length, char** str, bool is_x); static void obj_modern_write_skin_block_cloth(obj_skin_block_cloth* b, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x, + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x, int64_t* mats_offset, int64_t* root_offset, int64_t* nodes_offset, int64_t* mesh_indices_offset, int64_t* backface_mesh_indices_offset); static void obj_modern_read_skin_block_cloth_root_bone_weight(obj_skin_block_cloth_root_bone_weight* sub, stream& s, uint32_t header_length, char** str, bool is_x); static void obj_modern_write_skin_block_cloth_root_bone_weight(obj_skin_block_cloth_root_bone_weight* sub, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x); + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x); static void obj_modern_read_skin_block_constraint(obj_skin_block_constraint* b, stream& s, uint32_t header_length, char** str, bool is_x); static void obj_modern_write_skin_block_constraint(obj_skin_block_constraint* b, - stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, + stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, bool is_x, int64_t* offsets); static void obj_modern_read_skin_block_constraint_attach_point(obj_skin_block_constraint_attach_point* ap, stream& s, uint32_t header_length, char** str, bool is_x); static void obj_modern_write_skin_block_constraint_attach_point(obj_skin_block_constraint_attach_point* ap, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x); + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x); static void obj_modern_read_skin_block_constraint_up_vector_old(obj_skin_block_constraint_up_vector* up, stream& s, uint32_t header_length, char** str, bool is_x); static void obj_modern_write_skin_block_constraint_up_vector_old(obj_skin_block_constraint_up_vector* up, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x); + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x); static void obj_modern_read_skin_block_expression(obj_skin_block_expression* b, stream& s, uint32_t header_length, char** str, bool is_x); static void obj_modern_write_skin_block_expression(obj_skin_block_expression* b, - stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, bool is_x); + stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, bool is_x); static void obj_modern_read_skin_block_motion(obj_skin_block_motion* b, stream& s, uint32_t header_length, char** str, bool is_x); static void obj_modern_write_skin_block_motion(obj_skin_block_motion* b, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x, + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x, char** bone_names, int64_t* bone_names_offset, int64_t* bone_matrices_offset); static void obj_modern_read_skin_block_node(obj_skin_block_node* b, stream& s, uint32_t header_length, char** str, bool is_x); static void obj_modern_write_skin_block_node(obj_skin_block_node* b, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x); + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x); static void obj_modern_read_skin_block_osage(obj_skin_block_osage* b, stream& s, uint32_t header_length, char** str, bool is_x); static void obj_modern_write_skin_block_osage(obj_skin_block_osage* b, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x); + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x); static void obj_modern_read_vertex(obj* obj, stream& s, int64_t* vertex, obj_mesh* mesh, const uint32_t attrib_flags, uint32_t num_vertex, uint32_t size_vertex); static void obj_modern_write_vertex(obj* obj, stream& s, bool is_x, int64_t* vertex, obj_mesh* mesh, uint32_t* attrib_flags, uint32_t* num_vertex, uint32_t* size_vertex, f2_struct* ovtx); static void obj_skin_block_node_free(obj_skin_block_node* b); -static uint32_t obj_skin_strings_get_string_index(std::vector& vec, const char* str); -static int64_t obj_skin_strings_get_string_offset(std::vector& vec, +static uint32_t obj_skin_strings_get_string_index(std::vector& vec, const char* str); +static int64_t obj_skin_strings_get_string_offset(std::vector& vec, std::vector& vec_off, const char* str); -static int64_t obj_skin_strings_get_string_offset_by_index(std::vector& vec, +static int64_t obj_skin_strings_get_string_offset_by_index(std::vector& vec, std::vector& vec_off, char** strings, uint32_t index); -static void obj_skin_strings_push_back_check(std::vector& vec, const char* str); -static void obj_skin_strings_push_back_check_by_index(std::vector& vec, +static void obj_skin_strings_push_back_check(std::vector& vec, const char* str); +static void obj_skin_strings_push_back_check_by_index(std::vector& vec, char** strings, uint32_t index); obj_bounding_sphere::obj_bounding_sphere() : radius() { @@ -308,7 +307,7 @@ obj_mesh* obj::get_obj_mesh(const char* name) { return -1; } -obj_set::obj_set() : ready(), modern(), is_x(), obj_data(), +obj_set::obj_set() : ready(), modern(), big_endian(), is_x(), obj_data(), obj_num(), tex_id_data(), tex_id_num(), reserved() { } @@ -317,59 +316,59 @@ obj_set::~obj_set() { for (uint32_t i = 0; i < obj_num; i++) { obj* obj = &obj_data[i]; for (uint32_t j = 0; j < obj->skin.bones_count; j++) - free(obj->skin.bones[j].name); - free(obj->skin.bones); + free_def(obj->skin.bones[j].name); + free_def(obj->skin.bones); for (uint32_t j = 0; j < obj->skin.ex_data.blocks_count; j++) { obj_skin_block* block = &obj->skin.ex_data.blocks[j]; switch (block->type) { case OBJ_SKIN_BLOCK_CLOTH: { obj_skin_block_cloth* cloth = &block->cloth; - free(cloth->mesh_name); - free(cloth->backface_mesh_name); + free_def(cloth->mesh_name); + free_def(cloth->backface_mesh_name); for (uint32_t k = 0; k < cloth->root_count; k++) { obj_skin_block_cloth_root* sub = &cloth->root[k]; for (uint32_t l = 0; l < 4; l++) - free(sub->bone_weights[l].bone_name); + free_def(sub->bone_weights[l].bone_name); } - free(cloth->root); - free(cloth->nodes); - free(cloth->mesh_indices); - free(cloth->backface_mesh_indices); - free(cloth->skin_param.coli); + free_def(cloth->root); + free_def(cloth->nodes); + free_def(cloth->mesh_indices); + free_def(cloth->backface_mesh_indices); + free_def(cloth->skin_param.coli); } break; case OBJ_SKIN_BLOCK_CONSTRAINT: { obj_skin_block_constraint* constraint = &block->constraint; obj_skin_block_node_free(&constraint->base); - free(constraint->source_node_name); + free_def(constraint->source_node_name); } break; case OBJ_SKIN_BLOCK_EXPRESSION: { obj_skin_block_expression* expression = &block->expression; obj_skin_block_node_free(&expression->base); for (uint32_t k = 0; k < 9; k++) - free(expression->expressions[k]); + free_def(expression->expressions[k]); } break; case OBJ_SKIN_BLOCK_MOTION: { obj_skin_block_motion* motion = &block->motion; obj_skin_block_node_free(&motion->base); if (is_x) - free(motion->name); - free(motion->nodes); + free_def(motion->name); + free_def(motion->nodes); } break; case OBJ_SKIN_BLOCK_OSAGE: { obj_skin_block_osage* osage = &block->osage; obj_skin_block_node_free(&osage->base); - free(osage->skin_param.coli); - free(osage->nodes); + free_def(osage->skin_param.coli); + free_def(osage->nodes); } break; } } - free(obj->skin.ex_data.blocks); - free(obj->skin.ex_data.osage_nodes); - free(obj->skin.ex_data.bone_names_buf); - free(obj->skin.ex_data.bone_names); - free(obj->skin.ex_data.osage_sibling_infos); + free_def(obj->skin.ex_data.blocks); + free_def(obj->skin.ex_data.osage_nodes); + free_def(obj->skin.ex_data.bone_names_buf); + free_def(obj->skin.ex_data.bone_names); + free_def(obj->skin.ex_data.osage_sibling_infos); if (obj->mesh_array) for (uint32_t j = 0; j < obj->num_mesh; j++) { @@ -377,25 +376,25 @@ obj_set::~obj_set() { if (mesh->submesh_array) for (uint32_t k = 0; k < mesh->num_submesh; k++) { obj_sub_mesh* sub_mesh = &mesh->submesh_array[k]; - free(sub_mesh->bone_indices); - free(sub_mesh->indices); + free_def(sub_mesh->bone_indices); + free_def(sub_mesh->indices); } - free(mesh->vertex); - free(mesh->submesh_array); + free_def(mesh->vertex); + free_def(mesh->submesh_array); } - free(obj->mesh_array); - free(obj->material_array); - free(obj->name); + free_def(obj->mesh_array); + free_def(obj->material_array); + free_def(obj->name); } - free(obj_data); - free(tex_id_data); + free_def(obj_data); + free_def(tex_id_data); } void obj_set::pack_file(void** data, size_t* size) { if (!data || !ready) return; - stream s; + memory_stream s; s.open(); if (!modern) obj_set_classic_write_inner(this, s); @@ -409,7 +408,7 @@ void obj_set::unpack_file(const void* data, size_t size, bool modern) { if (!data || !size) return; - stream s; + memory_stream s; s.open(data, size); if (!modern) obj_set_classic_read_inner(this, s); @@ -419,7 +418,7 @@ void obj_set::unpack_file(const void* data, size_t size, bool modern) { static void obj_material_texture_enrs_table_init() { if (!obj_material_texture_enrs_table_initialized) { - stream s; + memory_stream s; s.open((void*)&obj_material_texture_enrs_table_bin, sizeof(obj_material_texture_enrs_table_bin)); obj_material_texture_enrs_table.read(s); @@ -459,41 +458,27 @@ static void calculate_tangent(obj_vertex_data* vtx, obj_vertex_data* vtx_b = &vtx[b]; obj_vertex_data* vtx_c = &vtx[c]; - vec3 pos_a; - vec3 pos_b; - vec3_sub(vtx_c->position, vtx_a->position, pos_a); - vec3_sub(vtx_b->position, vtx_a->position, pos_b); + vec3 pos_a = vtx_c->position - vtx_a->position; + vec3 pos_b = vtx_b->position - vtx_a->position; - vec2 uv_a; - vec2 uv_b; - vec2_sub(vtx_c->texcoord0, vtx_a->texcoord0, uv_a); - vec2_sub(vtx_b->texcoord0, vtx_a->texcoord0, uv_b); + vec2 uv_a = vtx_c->texcoord0 - vtx_a->texcoord0; + vec2 uv_b = vtx_b->texcoord0 - vtx_a->texcoord0; - vec3 tangent; - vec3 bitangent; - - vec3 temp1; - vec3 temp2; - vec3_mult_scalar(pos_a, uv_b.y, temp1); - vec3_mult_scalar(pos_b, uv_a.y, temp2); - vec3_sub(temp1, temp2, tangent); - - vec3_mult_scalar(pos_b, uv_a.x, temp1); - vec3_mult_scalar(pos_a, uv_b.x, temp2); - vec3_sub(temp1, temp2, bitangent); + vec3 tangent = pos_a * uv_b.y - pos_b * uv_a.y; + vec3 bitangent = pos_b * uv_a.x - pos_a * uv_b.x; if (uv_a.x * uv_b.y - uv_a.y * uv_b.x <= 0.0f) { - vec3_negate(tangent, tangent); - vec3_negate(bitangent, bitangent); + tangent = -tangent; + bitangent = -bitangent; } - vec3_add(tangents[a], tangent, tangents[a]); - vec3_add(tangents[b], tangent, tangents[b]); - vec3_add(tangents[c], tangent, tangents[c]); - - vec3_add(bitangents[a], bitangent, bitangents[a]); - vec3_add(bitangents[b], bitangent, bitangents[b]); - vec3_add(bitangents[c], bitangent, bitangents[c]); + tangents[a] += tangent; + tangents[b] += tangent; + tangents[c] += tangent; + + bitangents[a] += bitangent; + bitangents[b] += bitangent; + bitangents[c] += bitangent; } static void obj_vertex_generate_tangents(obj* obj, obj_mesh* mesh) { @@ -560,29 +545,15 @@ static void obj_vertex_generate_tangents(obj* obj, obj_mesh* mesh) { for (uint32_t i = 0; i < num_vertex; i++) { vec3 normal = vtx[i].normal; - vec3 tangent; - vec3 bitangent; - vec3_normalize(tangents[i], tangent); - vec3_normalize(bitangents[i], bitangent); + vec3 tangent = vec3::normalize(tangents[i]); + vec3 bitangent = vec3::normalize(bitangents[i]); - float_t temp1; - vec3 temp2; - vec3_dot(tangent, normal, temp1); - vec3_mult_scalar(normal, temp1, temp2); - vec3_sub(tangent, temp2, tangent); - vec3_normalize(tangent, tangent); + tangent = vec3::normalize(tangent - normal * vec3::dot(tangent, normal)); + bitangent = vec3::normalize(bitangent - normal * vec3::dot(bitangent, normal)); - vec3_dot(bitangent, normal, temp1); - vec3_mult_scalar(normal, temp1, temp2); - vec3_sub(bitangent, temp2, bitangent); - vec3_normalize(bitangent, bitangent); + vec3 binormal = vec3::normalize(vec3::cross(normal, tangent)); - vec3 binormal; - vec3_cross(normal, tangent, binormal); - vec3_normalize(binormal, binormal); - - float_t dir_check; - vec3_dot(binormal, bitangent, dir_check); + float_t dir_check = vec3::dot(binormal, bitangent); *(vec3*)&vtx[i].tangent = tangent; vtx[i].tangent.w = dir_check > 0.0f ? 1.0f : -1.0f; @@ -607,8 +578,7 @@ static void obj_vertex_generate_tangents(obj* obj, obj_mesh* mesh) { if (i == j || !memcmp(&tangent_to_compare, &vec3_null, sizeof(vec3))) continue; - float_t distance; - vec3_distance_squared(position, position_to_compare, distance); + float_t distance = vec3::distance_squared(position, position_to_compare); if (current_distance >= distance) { nearest_vtx_idx = j; @@ -623,26 +593,21 @@ static void obj_vertex_generate_tangents(obj* obj, obj_mesh* mesh) { const vec3 up = { 0.0f, 1.0f, 0.0f }; const vec3 left = { 1.0f, 0.0f, 0.0f }; - vec3 temp1; - vec3 temp2; - vec3_cross(normal, up, temp1); - vec3_cross(normal, left, temp2); + vec3 temp1 = vec3::cross(normal, up); + vec3 temp2 = vec3::cross(normal, left); - float_t temp3; - float_t temp4; - vec3_length_squared(temp1, temp3); - vec3_length_squared(temp2, temp4); + float_t temp3 = vec3::length_squared(temp1); + float_t temp4 = vec3::length_squared(temp2); - vec3 tangent = temp3 > temp4 ? temp1 : temp2; - vec3_normalize(tangent, tangent); + vec3 tangent = vec3::normalize(temp3 > temp4 ? temp1 : temp2); *(vec3*)&vtx[i].tangent = tangent; vtx[i].tangent.w = 1.0f; } } - free(tangents); - free(bitangents); + free_def(tangents); + free_def(bitangents); enum_or(mesh->vertex_format, OBJ_VERTEX_TANGENT); } @@ -665,7 +630,7 @@ static void obj_vertex_validate_bone_data(vec4& bone_weight, vec4i& bone_index) float_t sum = _bone_weight.x + _bone_weight.y + _bone_weight.z + _bone_weight.w; if (sum > 0.0f && fabsf(sum - 1.0f) > 0.000001f) - vec4_div_scalar(_bone_weight, sum, _bone_weight); + _bone_weight *= 1.0f / sum; bone_weight = _bone_weight; bone_index = _bone_index; @@ -674,9 +639,10 @@ static void obj_vertex_validate_bone_data(vec4& bone_weight, vec4i& bone_index) static void obj_set_classic_read_inner(obj_set* os, stream& s) { uint32_t version = s.read_uint32_t(); if (version != 0x05062500) { - os->is_x = false; - os->modern = false; os->ready = false; + os->modern = false; + os->big_endian = false; + os->is_x = false; return; } @@ -748,13 +714,14 @@ static void obj_set_classic_read_inner(obj_set* os, stream& s) { os->tex_id_data[i] = s.read_uint32_t(); } - free(obj_datas); - free(obj_skin_datas); - free(obj_name_datas); + free_def(obj_datas); + free_def(obj_skin_datas); + free_def(obj_name_datas); - os->is_x = false; - os->modern = false; os->ready = true; + os->modern = false; + os->big_endian = false; + os->is_x = false; } static void obj_set_classic_write_inner(obj_set* os, stream& s) { @@ -794,7 +761,7 @@ static void obj_set_classic_write_inner(obj_set* os, stream& s) { for (uint32_t i = 0; i < obj_num; i++) s.write_uint32_t(obj_datas[i]); s.position_pop(); - free(obj_datas); + free_def(obj_datas); osh.obj_id_data = s.get_position(); for (uint32_t i = 0; i < obj_num; i++) { @@ -816,7 +783,7 @@ static void obj_set_classic_write_inner(obj_set* os, stream& s) { for (uint32_t i = 0; i < obj_num; i++) s.write_int32_t(obj_name_datas[i]); s.align_write(0x10); - free(obj_name_datas); + free_def(obj_name_datas); osh.tex_id_data = s.get_position(); for (uint32_t i = 0; i < os->tex_id_num; i++) @@ -844,7 +811,7 @@ static void obj_set_classic_write_inner(obj_set* os, stream& s) { for (uint32_t i = 0; i < obj_num; i++) s.write_int32_t(obj_skin_datas[i]); s.position_pop(); - free(obj_skin_datas); + free_def(obj_skin_datas); s.position_push(0x00, SEEK_SET); s.write_uint32_t(0x05062500); @@ -1179,7 +1146,7 @@ static void obj_classic_write_model(obj* obj, stream& s, int64_t base_offset) { s.write_char('\0'); } s.position_pop(); - free(mhs); + free_def(mhs); } if (obj->num_material) { @@ -1281,7 +1248,7 @@ static void obj_classic_read_skin(obj* obj, stream& s, int64_t base_offset) { sk->bones[i].parent = s.read_uint32_t(); } } - free(bone_names_offsets); + free_def(bone_names_offsets); } if (sh.ex_data_offset) { @@ -1325,7 +1292,7 @@ static void obj_classic_read_skin(obj* obj, stream& s, int64_t base_offset) { bone_names.push_back({}); buf_size += bone_names.back().size() + 1; } - free(strings_offsets); + free_def(strings_offsets); if (bone_names.size()) { ex->bone_names_buf = force_malloc_s(char, buf_size); @@ -1425,7 +1392,7 @@ static void obj_classic_read_skin(obj* obj, stream& s, int64_t base_offset) { break; } } - free(bhs); + free_def(bhs); } if (exh.osage_sibling_infos_offset) { @@ -1485,9 +1452,9 @@ static void obj_classic_write_skin(obj* obj, stream& s, int64_t base_offset) { s.write(0x0C); s.align_write(0x10); - std::vector strings; + std::vector strings; std::vector string_offsets; - std::vector bone_names; + std::vector bone_names; if (sk->bones) { sh.bone_ids_offset = s.get_position(); for (uint32_t i = 0; i < sk->bones_count; i++) @@ -1745,7 +1712,7 @@ static void obj_classic_write_skin(obj* obj, stream& s, int64_t base_offset) { exh.bone_names_count = (int32_t)bone_names.size(); exh.bone_names_offset = s.get_position(); - for (std::string& i : bone_names) + for (string_hash& i : bone_names) s.write_int32_t(0); s.align_write(0x10); @@ -1958,16 +1925,16 @@ static void obj_classic_write_skin(obj* obj, stream& s, int64_t base_offset) { } if (sk->bones || sk->ex_data_init) { - quicksort_string(strings.data(), strings.size()); + quicksort_string_hash(strings.data(), strings.size()); string_offsets.reserve(strings.size()); - for (std::string& i : strings) { + for (string_hash& i : strings) { string_offsets.push_back(s.get_position()); - s.write_string_null_terminated(i); + s.write_string_null_terminated(i.str); } } s.align_write(0x10); - std::vector osage_names; + std::vector osage_names; if (sk->ex_data_init) { obj_skin_ex_data* ex = &sk->ex_data; @@ -2092,7 +2059,7 @@ static void obj_classic_write_skin(obj* obj, stream& s, int64_t base_offset) { s.write_int32_t(0); s.write_int32_t(0); s.position_pop(); - free(bhs); + free_def(bhs); } } @@ -2111,7 +2078,7 @@ static void obj_classic_write_skin(obj* obj, stream& s, int64_t base_offset) { if (ex->blocks_count > 0) { s.position_push(exh.bone_names_offset, SEEK_SET); - for (std::string& i : bone_names) { + for (string_hash& i : bone_names) { size_t str_offset = obj_skin_strings_get_string_offset(strings, string_offsets, i.c_str()); s.write_uint32_t((uint32_t)str_offset); @@ -2142,7 +2109,7 @@ static void obj_classic_write_skin(obj* obj, stream& s, int64_t base_offset) { exh.osage_count = (int32_t)osage_names.size(); exh.osage_count -= exh.cloth_count; s.position_push(exh.osage_names_offset, SEEK_SET); - for (std::string& i : osage_names) { + for (string_hash& i : osage_names) { size_t str_offset = obj_skin_strings_get_string_offset(strings, string_offsets, i.c_str()); s.write_uint32_t((uint32_t)str_offset); @@ -2312,7 +2279,7 @@ static void obj_classic_read_skin_block_cloth(obj_skin_block_cloth* b, } static void obj_classic_write_skin_block_cloth(obj_skin_block_cloth* b, - stream& s, std::vector& strings, std::vector& string_offsets, + stream& s, std::vector& strings, std::vector& string_offsets, int64_t* mats_offset, int64_t* root_offset, int64_t* nodes_offset, int64_t* mesh_indices_offset, int64_t* backface_mesh_indices_offset) { int64_t skin_param_offset = 0; @@ -2437,7 +2404,7 @@ static void obj_classic_read_skin_block_cloth_root_bone_weight(obj_skin_block_cl } static void obj_classic_write_skin_block_cloth_root_bone_weight(obj_skin_block_cloth_root_bone_weight* sub, - stream& s, std::vector& strings, std::vector& string_offsets) { + stream& s, std::vector& strings, std::vector& string_offsets) { int64_t bone_name_offset = obj_skin_strings_get_string_offset(strings, string_offsets, sub->bone_name); s.write_uint32_t((uint32_t)bone_name_offset); @@ -2462,7 +2429,7 @@ static void obj_classic_read_skin_block_constraint(obj_skin_block_constraint* b, b->name_index = 0x8000 | (int32_t)(i - str); break; } - free(name); + free_def(name); b->coupling = (obj_skin_block_constraint_coupling)s.read_int32_t(); @@ -2507,11 +2474,11 @@ static void obj_classic_read_skin_block_constraint(obj_skin_block_constraint* b, } else b->type = OBJ_SKIN_BLOCK_CONSTRAINT_NONE; - free(type); + free_def(type); } static void obj_classic_write_skin_block_constraint(obj_skin_block_constraint* b, - stream& s, std::vector& strings, std::vector& string_offsets, + stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, int64_t* offsets) { obj_classic_write_skin_block_node(&b->base, s, strings, string_offsets); @@ -2588,7 +2555,7 @@ static void obj_classic_read_skin_block_constraint_attach_point(obj_skin_block_c } static void obj_classic_write_skin_block_constraint_attach_point(obj_skin_block_constraint_attach_point* ap, - stream& s, std::vector& strings, std::vector& string_offsets) { + stream& s, std::vector& strings, std::vector& string_offsets) { s.write_int32_t(ap->affected_by_orientation ? 1 : 0); s.write_int32_t(ap->affected_by_scaling ? 1 : 0); s.write_float_t(ap->offset.x); @@ -2612,7 +2579,7 @@ static void obj_classic_read_skin_block_constraint_up_vector_old(obj_skin_block_ } static void obj_classic_write_skin_block_constraint_up_vector_old(obj_skin_block_constraint_up_vector* up, - stream& s, std::vector& strings, std::vector& string_offsets) { + stream& s, std::vector& strings, std::vector& string_offsets) { s.write_int32_t(up->active ? 1 : 0); s.write_float_t(up->roll); s.write_float_t(up->affected_axis.x); @@ -2640,10 +2607,10 @@ static void obj_classic_read_skin_block_expression(obj_skin_block_expression* b, b->name_index = 0x8000 | (int32_t)(i - str); break; } - free(name); + free_def(name); b->expressions_count = s.read_int32_t(); - b->expressions_count = min(b->expressions_count, 9); + b->expressions_count = min_def(b->expressions_count, 9); for (uint32_t i = 0; i < b->expressions_count; i++) { uint32_t expression_offset = s.read_uint32_t(); if (expression_offset) @@ -2655,14 +2622,14 @@ static void obj_classic_read_skin_block_expression(obj_skin_block_expression* b, } static void obj_classic_write_skin_block_expression(obj_skin_block_expression* b, - stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names) { + stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names) { obj_classic_write_skin_block_node(&b->base, s, strings, string_offsets); int64_t name_offset = obj_skin_strings_get_string_offset_by_index(strings, string_offsets, bone_names, b->name_index); s.write_uint32_t((uint32_t)name_offset); - s.write_int32_t(min(b->expressions_count, 9)); + s.write_int32_t(min_def(b->expressions_count, 9)); for (uint32_t i = 0; i < b->expressions_count && i < 9; i++) { int64_t expression_offset = obj_skin_strings_get_string_offset(strings, string_offsets, b->expressions[i]); @@ -2690,7 +2657,7 @@ static void obj_classic_read_skin_block_motion(obj_skin_block_motion* b, b->name_index = 0x8000 | (int32_t)(i - str); break; } - free(name); + free_def(name); b->nodes = 0; @@ -2732,7 +2699,7 @@ static void obj_classic_read_skin_block_motion(obj_skin_block_motion* b, } static void obj_classic_write_skin_block_motion(obj_skin_block_motion* b, - stream& s, std::vector& strings, std::vector& string_offsets, + stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, int64_t* bone_names_offset, int64_t* bone_matrices_offset) { obj_classic_write_skin_block_node(&b->base, s, strings, string_offsets); @@ -2792,7 +2759,7 @@ static void obj_classic_read_skin_block_node(obj_skin_block_node* b, } static void obj_classic_write_skin_block_node(obj_skin_block_node* b, - stream& s, std::vector& strings, std::vector& string_offsets) { + stream& s, std::vector& strings, std::vector& string_offsets) { int64_t parent_name_offset = obj_skin_strings_get_string_offset(strings, string_offsets, b->parent_name); s.write_uint32_t((uint32_t)parent_name_offset); @@ -2829,7 +2796,7 @@ static void obj_classic_read_skin_block_osage(obj_skin_block_osage* b, b->nodes = force_malloc_s(obj_skin_osage_node, b->count); s.position_push(offset, SEEK_SET); - if (~s.read_uint32_t() & 0x8000) { + if (!(s.read_uint32_t() & 0x8000)) { obj_classic_read_skin_param(&b->skin_param, s, str); b->skin_param_init = true; } @@ -2849,7 +2816,7 @@ static void obj_classic_read_skin_block_osage(obj_skin_block_osage* b, } static void obj_classic_write_skin_block_osage(obj_skin_block_osage* b, - stream& s, std::vector& strings, std::vector& string_offsets, int64_t* nodes_offset) { + stream& s, std::vector& strings, std::vector& string_offsets, int64_t* nodes_offset) { int64_t skin_param_offset = 0; if (b->skin_param_init) { skin_param_offset = s.get_position(); @@ -2935,7 +2902,7 @@ static void obj_classic_read_skin_param(obj_skin_skin_param* skp, } static void obj_classic_write_skin_param(obj_skin_skin_param* skp, - stream& s, std::vector& strings, std::vector& string_offsets) { + stream& s, std::vector& strings, std::vector& string_offsets) { int64_t coli_offset = 0; if (skp->coli) { coli_offset = s.get_position(); @@ -3020,7 +2987,7 @@ static void obj_classic_read_vertex(obj* obj, stream& s, int64_t* vertex, obj_me obj_vertex_data* vtx = force_malloc_s(obj_vertex_data, num_vertex); for (uint32_t i = 0; i < 20; i++) { obj_vertex_format_file attribute = (obj_vertex_format_file)(1 << i); - if (~vertex_format_file & attribute) + if (!(vertex_format_file & attribute)) continue; s.set_position(base_offset + vertex[i], SEEK_SET); @@ -3327,15 +3294,18 @@ static void obj_set_modern_read_inner(obj_set* os, stream& s) { if (st.header.signature != reverse_endianness_uint32_t('MOSD') || !st.data.size()) return; - stream s_mosd; + bool big_endian = st.header.use_big_endian; + + memory_stream s_mosd; s_mosd.open(st.data); - s_mosd.is_big_endian = st.header.use_big_endian; + s_mosd.big_endian = big_endian; uint32_t version = s_mosd.read_uint32_t_reverse_endianness(); if (version != 0x05062501) { - os->is_x = false; - os->modern = false; os->ready = false; + os->modern = false; + os->big_endian = false; + os->is_x = false; return; } @@ -3433,9 +3403,9 @@ static void obj_set_modern_read_inner(obj_set* os, stream& s) { os->obj_data[i].id = s_mosd.read_uint32_t_reverse_endianness(); } - free(obj_datas); - free(obj_skin_datas); - free(obj_name_datas); + free_def(obj_datas); + free_def(obj_skin_datas); + free_def(obj_name_datas); if (osh.tex_id_data) { s_mosd.set_position(osh.tex_id_data, SEEK_SET); @@ -3460,34 +3430,34 @@ static void obj_set_modern_read_inner(obj_set* os, stream& s) { else if (!ovtx && j.header.signature == reverse_endianness_uint32_t('OVTX')) ovtx = &j; - stream s_oskn; - stream s_oidx; - stream s_ovtx; + memory_stream s_oskn; + memory_stream s_oidx; + memory_stream s_ovtx; stream* s_oskn_ptr = 0; stream* s_oidx_ptr = 0; stream* s_ovtx_ptr = 0; if (oskn) { s_oskn.open(oskn->data); - s_oskn.is_big_endian = oskn->header.use_big_endian; + s_oskn.big_endian = oskn->header.use_big_endian; s_oskn_ptr = &s_oskn; } if (oidx) { s_oidx.open(oidx->data); - s_oidx.is_big_endian = oidx->header.use_big_endian; + s_oidx.big_endian = oidx->header.use_big_endian; s_oidx_ptr = &s_oidx; } if (ovtx) { s_ovtx.open(ovtx->data); - s_ovtx.is_big_endian = ovtx->header.use_big_endian; + s_ovtx.big_endian = ovtx->header.use_big_endian; s_ovtx_ptr = &s_ovtx; } obj* obj = &os->obj_data[omdl_index]; - stream s_omdl; + memory_stream s_omdl; s_omdl.open(i.data); - s_omdl.is_big_endian = i.header.use_big_endian; + s_omdl.big_endian = i.header.use_big_endian; obj_modern_read_model(obj, s_omdl, 0, i.header.length, is_x, s_oidx_ptr, s_ovtx_ptr); s_omdl.close(); @@ -3496,14 +3466,19 @@ static void obj_set_modern_read_inner(obj_set* os, stream& s) { omdl_index++; } - os->is_x = is_x; - os->modern = true; os->ready = true; + os->modern = true; + os->big_endian = big_endian; + os->is_x = is_x; } static void obj_set_modern_write_inner(obj_set* os, stream& s) { - stream s_mosd; + bool big_endian = s.big_endian; + + memory_stream s_mosd; s_mosd.open(); + s_mosd.big_endian = big_endian; + uint32_t off; enrs e; enrs_entry ee; @@ -3627,12 +3602,12 @@ static void obj_set_modern_write_inner(obj_set* os, stream& s) { osh.obj_id_data = s_mosd.get_position(); for (uint32_t i = 0; i < obj_num; i++) - s_mosd.write_uint32_t(os->obj_data[i].id); + s_mosd.write_uint32_t_reverse_endianness(os->obj_data[i].id); s_mosd.align_write(0x10); osh.tex_id_data = s_mosd.get_position(); for (uint32_t i = 0; i < os->tex_id_num; i++) - s_mosd.write_uint32_t(os->tex_id_data[i]); + s_mosd.write_uint32_t_reverse_endianness(os->tex_id_data[i]); s_mosd.align_write(0x10); int64_t* obj_name_datas = force_malloc_s(int64_t, obj_num); @@ -3650,34 +3625,34 @@ static void obj_set_modern_write_inner(obj_set* os, stream& s) { for (uint32_t i = 0; i < obj_num; i++) s_mosd.write_offset_x(obj_name_datas[i]); s_mosd.position_pop(); - free(obj_name_datas); + free_def(obj_name_datas); s_mosd.position_push(0x00, SEEK_SET); if (!is_x) { - s_mosd.write_uint32_t(0x05062501); - s_mosd.write_int32_t(os->obj_num); - s_mosd.write_int32_t(-1); + s_mosd.write_uint32_t_reverse_endianness(0x05062501); + s_mosd.write_int32_t_reverse_endianness(os->obj_num); + s_mosd.write_int32_t_reverse_endianness(-1); s_mosd.write_offset_f2(osh.obj_data, 0x20); s_mosd.write_offset_f2(osh.obj_skin_data, 0x20); s_mosd.write_offset_f2(osh.obj_name_data, 0x20); s_mosd.write_offset_f2(osh.obj_id_data, 0x20); s_mosd.write_offset_f2(osh.tex_id_data, 0x20); - s_mosd.write_int32_t(os->tex_id_num); - s_mosd.write_uint32_t(os->reserved[0]); - s_mosd.write_uint32_t(os->reserved[1]); + s_mosd.write_int32_t_reverse_endianness(os->tex_id_num); + s_mosd.write_uint32_t_reverse_endianness(os->reserved[0]); + s_mosd.write_uint32_t_reverse_endianness(os->reserved[1]); } else { - s_mosd.write_uint32_t(0x05062501); - s_mosd.write_int32_t(os->obj_num); - s_mosd.write_int32_t(-1); + s_mosd.write_uint32_t_reverse_endianness(0x05062501); + s_mosd.write_int32_t_reverse_endianness(os->obj_num); + s_mosd.write_int32_t_reverse_endianness(-1); s_mosd.write_offset_x(osh.obj_data); s_mosd.write_offset_x(osh.obj_skin_data); s_mosd.write_offset_x(osh.obj_name_data); s_mosd.write_offset_x(osh.obj_id_data); s_mosd.write_offset_x(osh.tex_id_data); - s_mosd.write_int32_t(os->tex_id_num); - s_mosd.write_uint32_t(os->reserved[0]); - s_mosd.write_uint32_t(os->reserved[1]); + s_mosd.write_int32_t_reverse_endianness(os->tex_id_num); + s_mosd.write_uint32_t_reverse_endianness(os->reserved[0]); + s_mosd.write_uint32_t_reverse_endianness(os->reserved[1]); } s_mosd.position_pop(); @@ -3688,15 +3663,17 @@ static void obj_set_modern_write_inner(obj_set* os, stream& s) { st.sub_structs.push_back({}); f2_struct* omdl = &st.sub_structs.back(); - stream s_omdl; + memory_stream s_omdl; s_omdl.open(); + s_omdl.big_endian = big_endian; if (obj->skin_init) { st.sub_structs.push_back({}); f2_struct* oskn = &st.sub_structs.back(); - stream s_oskn; + memory_stream s_oskn; s_oskn.open(); + s_oskn.big_endian = big_endian; obj_modern_write_skin(obj, s_oskn, 0, is_x, oskn); @@ -3706,7 +3683,7 @@ static void obj_set_modern_write_inner(obj_set* os, stream& s) { oskn->header.signature = reverse_endianness_uint32_t('OSKN'); oskn->header.length = 0x20; - oskn->header.use_big_endian = false; + oskn->header.use_big_endian = big_endian; oskn->header.use_section_size = true; } @@ -3718,7 +3695,7 @@ static void obj_set_modern_write_inner(obj_set* os, stream& s) { omdl->header.signature = reverse_endianness_uint32_t('OMDL'); omdl->header.length = 0x20; - omdl->header.use_big_endian = false; + omdl->header.use_big_endian = big_endian; omdl->header.use_section_size = true; } @@ -3731,7 +3708,7 @@ static void obj_set_modern_write_inner(obj_set* os, stream& s) { st.header.signature = reverse_endianness_uint32_t('MOSD'); st.header.length = 0x20; - st.header.use_big_endian = false; + st.header.use_big_endian = big_endian; st.header.use_section_size = true; st.write(s, true, os->is_x); @@ -3808,11 +3785,11 @@ static void obj_modern_write_index(obj* obj, stream& s, bool is_x, break; case OBJ_INDEX_U16: for (uint32_t i = 0; i < _indices_count; i++) - s.write_uint16_t((uint16_t)indices[i]); + s.write_uint16_t_reverse_endianness((uint16_t)indices[i]); break; case OBJ_INDEX_U32: for (uint32_t i = 0; i < _indices_count; i++) - s.write_uint32_t(indices[i]); + s.write_uint32_t_reverse_endianness(indices[i]); break; } s.align_write(0x04); @@ -3951,7 +3928,7 @@ static void obj_modern_read_model(obj* obj, stream& s, int64_t base_offset, sub_mesh->bone_indices = force_malloc_s(uint16_t, sub_mesh->bone_indices_count); s.set_position(base_offset + smh.bone_indices_offset, SEEK_SET); s.read(sub_mesh->bone_indices, sub_mesh->bone_indices_count * sizeof(uint16_t)); - if (s.is_big_endian) { + if (s.big_endian) { uint16_t* bone_indices = sub_mesh->bone_indices; for (uint32_t k = 0; k < sub_mesh->bone_indices_count; k++) bone_indices[k] = reverse_endianness_uint16_t(bone_indices[k]); @@ -3978,7 +3955,7 @@ static void obj_modern_read_model(obj* obj, stream& s, int64_t base_offset, obj_material_data mat_data; s.read(&mat_data, sizeof(obj_material_data)); - if (s.is_big_endian) + if (s.big_endian) obj_material_texture_enrs_table.apply(&mat_data); for (obj_material_texture_data& j : mat_data.material.texdata) @@ -3990,6 +3967,8 @@ static void obj_modern_read_model(obj* obj, stream& s, int64_t base_offset, static void obj_modern_write_model(obj* obj, stream& s, int64_t base_offset, bool is_x, f2_struct* omdl) { + bool big_endian = s.big_endian; + const size_t mesh_size = is_x ? 0x130 : 0xD8; const size_t sub_mesh_size = is_x ? 0x80 : 0x70; @@ -3998,10 +3977,12 @@ static void obj_modern_write_model(obj* obj, stream& s, f2_struct* oidx = &omdl->sub_structs.end()[-2]; f2_struct* ovtx = &omdl->sub_structs.back(); - stream s_oidx; - stream s_ovtx; + memory_stream s_oidx; + memory_stream s_ovtx; s_oidx.open(); s_ovtx.open(); + s_oidx.big_endian = big_endian; + s_ovtx.big_endian = big_endian; uint32_t off; enrs e; @@ -4277,28 +4258,28 @@ static void obj_modern_write_model(obj* obj, stream& s, obj_sub_mesh* sub_mesh = &mesh->submesh_array[j]; obj_sub_mesh_header* smh = &smhs[j]; - s.write_uint32_t(sub_mesh->flags); - s.write_float_t(sub_mesh->bounding_sphere.center.x); - s.write_float_t(sub_mesh->bounding_sphere.center.y); - s.write_float_t(sub_mesh->bounding_sphere.center.z); - s.write_float_t(sub_mesh->bounding_sphere.radius); - s.write_uint32_t(sub_mesh->material_index); + s.write_uint32_t_reverse_endianness(sub_mesh->flags); + s.write_float_t_reverse_endianness(sub_mesh->bounding_sphere.center.x); + s.write_float_t_reverse_endianness(sub_mesh->bounding_sphere.center.y); + s.write_float_t_reverse_endianness(sub_mesh->bounding_sphere.center.z); + s.write_float_t_reverse_endianness(sub_mesh->bounding_sphere.radius); + s.write_uint32_t_reverse_endianness(sub_mesh->material_index); s.write(&sub_mesh->uv_index, 0x08); - s.write_int32_t(sub_mesh->bone_indices_count); + s.write_int32_t_reverse_endianness(sub_mesh->bone_indices_count); s.write_offset(smh->bone_indices_offset, 0x20, is_x); - s.write_uint32_t(sub_mesh->bones_per_vertex); - s.write_uint32_t(sub_mesh->primitive_type); - s.write_uint32_t(sub_mesh->index_format); - s.write_int32_t(sub_mesh->indices_count); + s.write_uint32_t_reverse_endianness(sub_mesh->bones_per_vertex); + s.write_uint32_t_reverse_endianness(sub_mesh->primitive_type); + s.write_uint32_t_reverse_endianness(sub_mesh->index_format); + s.write_int32_t_reverse_endianness(sub_mesh->indices_count); s.write_offset(smh->indices_offset, 0, is_x); - s.write_uint32_t(sub_mesh->attrib.w); + s.write_uint32_t_reverse_endianness(sub_mesh->attrib.w); s.write(0x10); - s.write_float_t(sub_mesh->bounding_box.center.x); - s.write_float_t(sub_mesh->bounding_box.center.y); - s.write_float_t(sub_mesh->bounding_box.center.z); - s.write_float_t(sub_mesh->bounding_box.size.x); - s.write_float_t(sub_mesh->bounding_box.size.y); - s.write_float_t(sub_mesh->bounding_box.size.z); + s.write_float_t_reverse_endianness(sub_mesh->bounding_box.center.x); + s.write_float_t_reverse_endianness(sub_mesh->bounding_box.center.y); + s.write_float_t_reverse_endianness(sub_mesh->bounding_box.center.z); + s.write_float_t_reverse_endianness(sub_mesh->bounding_box.size.x); + s.write_float_t_reverse_endianness(sub_mesh->bounding_box.size.y); + s.write_float_t_reverse_endianness(sub_mesh->bounding_box.size.z); uint32_t index_max = 0; for (uint32_t k = 0; k < sub_mesh->indices_count; k++) @@ -4307,23 +4288,23 @@ static void obj_modern_write_model(obj* obj, stream& s, switch (sub_mesh->index_format) { case OBJ_INDEX_U8: - s.write_uint32_t(index_max << 24); + s.write_uint32_t_reverse_endianness(index_max << 24); break; case OBJ_INDEX_U16: - s.write_uint32_t(index_max << 16); + s.write_uint32_t_reverse_endianness(index_max << 16); break; case OBJ_INDEX_U32: - s.write_uint32_t(index_max); + s.write_uint32_t_reverse_endianness(index_max); break; } - s.write_uint32_t(sub_mesh->indices_offset); + s.write_uint32_t_reverse_endianness(sub_mesh->indices_offset); if (is_x) s.write(0x04); } s.position_pop(); } - free(smhs); + free_def(smhs); } s.position_push(base_offset + oh.mesh_array, SEEK_SET); @@ -4331,18 +4312,18 @@ static void obj_modern_write_model(obj* obj, stream& s, obj_mesh* mesh = &obj->mesh_array[i]; obj_mesh_header* mh = &mhs[i]; - s.write_uint32_t(mesh->flags); - s.write_float_t(mesh->bounding_sphere.center.x); - s.write_float_t(mesh->bounding_sphere.center.y); - s.write_float_t(mesh->bounding_sphere.center.z); - s.write_float_t(mesh->bounding_sphere.radius); - s.write_int32_t(mesh->num_submesh); + s.write_uint32_t_reverse_endianness(mesh->flags); + s.write_float_t_reverse_endianness(mesh->bounding_sphere.center.x); + s.write_float_t_reverse_endianness(mesh->bounding_sphere.center.y); + s.write_float_t_reverse_endianness(mesh->bounding_sphere.center.z); + s.write_float_t_reverse_endianness(mesh->bounding_sphere.radius); + s.write_int32_t_reverse_endianness(mesh->num_submesh); if (mh->submesh_array && !is_x) mh->submesh_array += 0x20; s.write_offset(mh->submesh_array, 0, is_x); - s.write_uint32_t(mh->format); - s.write_int32_t(mh->size_vertex); - s.write_int32_t(mh->num_vertex); + s.write_uint32_t_reverse_endianness(mh->format); + s.write_int32_t_reverse_endianness(mh->size_vertex); + s.write_int32_t_reverse_endianness(mh->num_vertex); if (!is_x) for (uint32_t j = 0; j < 20; j++) @@ -4351,20 +4332,20 @@ static void obj_modern_write_model(obj* obj, stream& s, for (uint32_t j = 0; j < 20; j++) s.write_offset_x(mh->vertex[j]); - s.write_uint32_t(mesh->attrib.w); - s.write_uint32_t(mh->vertex_flags); - s.write_uint32_t(mesh->reserved[0]); - s.write_uint32_t(mesh->reserved[1]); - s.write_uint32_t(mesh->reserved[2]); - s.write_uint32_t(mesh->reserved[3]); - s.write_uint32_t(mesh->reserved[4]); - s.write_uint32_t(mesh->reserved[5]); + s.write_uint32_t_reverse_endianness(mesh->attrib.w); + s.write_uint32_t_reverse_endianness(mh->vertex_flags); + s.write_uint32_t_reverse_endianness(mesh->reserved[0]); + s.write_uint32_t_reverse_endianness(mesh->reserved[1]); + s.write_uint32_t_reverse_endianness(mesh->reserved[2]); + s.write_uint32_t_reverse_endianness(mesh->reserved[3]); + s.write_uint32_t_reverse_endianness(mesh->reserved[4]); + s.write_uint32_t_reverse_endianness(mesh->reserved[5]); s.write(&mesh->name, sizeof(mesh->name) - 1); s.write_char('\0'); } s.position_pop(); - free(mhs); - free(smhss); + free_def(mhs); + free_def(smhss); } if (obj->material_array) { @@ -4380,51 +4361,51 @@ static void obj_modern_write_model(obj* obj, stream& s, s.position_push(base_offset, SEEK_SET); if (!is_x) { - s.write_uint32_t(0x10000); // version - s.write_uint32_t(0x00); // flags - s.write_float_t(obj->bounding_sphere.center.x); - s.write_float_t(obj->bounding_sphere.center.y); - s.write_float_t(obj->bounding_sphere.center.z); - s.write_float_t(obj->bounding_sphere.radius); - s.write_int32_t(obj->num_mesh); + s.write_uint32_t_reverse_endianness(0x10000); // version + s.write_uint32_t_reverse_endianness(0x00); // flags + s.write_float_t_reverse_endianness(obj->bounding_sphere.center.x); + s.write_float_t_reverse_endianness(obj->bounding_sphere.center.y); + s.write_float_t_reverse_endianness(obj->bounding_sphere.center.z); + s.write_float_t_reverse_endianness(obj->bounding_sphere.radius); + s.write_int32_t_reverse_endianness(obj->num_mesh); s.write_offset_f2(oh.mesh_array, 0x20); - s.write_int32_t(obj->num_material); + s.write_int32_t_reverse_endianness(obj->num_material); s.write_offset_f2(oh.material_array, 0x20); - s.write_uint32_t(obj->reserved[0]); - s.write_uint32_t(obj->reserved[1]); - s.write_uint32_t(obj->reserved[2]); - s.write_uint32_t(obj->reserved[3]); - s.write_uint32_t(obj->reserved[4]); - s.write_uint32_t(obj->reserved[5]); - s.write_uint32_t(obj->reserved[6]); - s.write_uint32_t(obj->reserved[7]); - s.write_uint32_t(obj->reserved[8]); - s.write_uint32_t(obj->reserved[9]); + s.write_uint32_t_reverse_endianness(obj->reserved[0]); + s.write_uint32_t_reverse_endianness(obj->reserved[1]); + s.write_uint32_t_reverse_endianness(obj->reserved[2]); + s.write_uint32_t_reverse_endianness(obj->reserved[3]); + s.write_uint32_t_reverse_endianness(obj->reserved[4]); + s.write_uint32_t_reverse_endianness(obj->reserved[5]); + s.write_uint32_t_reverse_endianness(obj->reserved[6]); + s.write_uint32_t_reverse_endianness(obj->reserved[7]); + s.write_uint32_t_reverse_endianness(obj->reserved[8]); + s.write_uint32_t_reverse_endianness(obj->reserved[9]); } else { - s.write_uint32_t(0x10000); // version - s.write_uint32_t(0x00); // flags - s.write_int32_t(obj->num_mesh); - s.write_int32_t(obj->num_material); - s.write_float_t(obj->bounding_sphere.center.x); - s.write_float_t(obj->bounding_sphere.center.y); - s.write_float_t(obj->bounding_sphere.center.z); - s.write_float_t(obj->bounding_sphere.radius); + s.write_uint32_t_reverse_endianness(0x10000); // version + s.write_uint32_t_reverse_endianness(0x00); // flags + s.write_int32_t_reverse_endianness(obj->num_mesh); + s.write_int32_t_reverse_endianness(obj->num_material); + s.write_float_t_reverse_endianness(obj->bounding_sphere.center.x); + s.write_float_t_reverse_endianness(obj->bounding_sphere.center.y); + s.write_float_t_reverse_endianness(obj->bounding_sphere.center.z); + s.write_float_t_reverse_endianness(obj->bounding_sphere.radius); s.write_offset_x(oh.mesh_array); s.write_offset_x(oh.material_array); s.write(0x10); s.write_uint8_t(obj->flags); s.write(0x07); - s.write_uint32_t(obj->reserved[0]); - s.write_uint32_t(obj->reserved[1]); - s.write_uint32_t(obj->reserved[2]); - s.write_uint32_t(obj->reserved[3]); - s.write_uint32_t(obj->reserved[4]); - s.write_uint32_t(obj->reserved[5]); - s.write_uint32_t(obj->reserved[6]); - s.write_uint32_t(obj->reserved[7]); - s.write_uint32_t(obj->reserved[8]); - s.write_uint32_t(obj->reserved[9]); + s.write_uint32_t_reverse_endianness(obj->reserved[0]); + s.write_uint32_t_reverse_endianness(obj->reserved[1]); + s.write_uint32_t_reverse_endianness(obj->reserved[2]); + s.write_uint32_t_reverse_endianness(obj->reserved[3]); + s.write_uint32_t_reverse_endianness(obj->reserved[4]); + s.write_uint32_t_reverse_endianness(obj->reserved[5]); + s.write_uint32_t_reverse_endianness(obj->reserved[6]); + s.write_uint32_t_reverse_endianness(obj->reserved[7]); + s.write_uint32_t_reverse_endianness(obj->reserved[8]); + s.write_uint32_t_reverse_endianness(obj->reserved[9]); } s.position_pop(); @@ -4437,7 +4418,7 @@ static void obj_modern_write_model(obj* obj, stream& s, oidx->header.signature = reverse_endianness_uint32_t('OIDX'); oidx->header.length = 0x20; - oidx->header.use_big_endian = false; + oidx->header.use_big_endian = big_endian; oidx->header.use_section_size = true; s_ovtx.align_write(0x10); @@ -4446,7 +4427,7 @@ static void obj_modern_write_model(obj* obj, stream& s, ovtx->header.signature = reverse_endianness_uint32_t('OVTX'); ovtx->header.length = 0x20; - ovtx->header.use_big_endian = false; + ovtx->header.use_big_endian = big_endian; ovtx->header.use_section_size = true; } @@ -4530,7 +4511,7 @@ static void obj_modern_read_skin(obj* obj, stream& s, int64_t base_offset, sk->bones[i].parent = s.read_uint32_t_reverse_endianness(); } } - free(bone_names_offsets); + free_def(bone_names_offsets); } if (sh.ex_data_offset) { @@ -4595,7 +4576,7 @@ static void obj_modern_read_skin(obj* obj, stream& s, int64_t base_offset, bone_names.push_back({}); buf_size += bone_names.back().size() + 1; } - free(strings_offsets); + free_def(strings_offsets); if (bone_names.size()) { ex->bone_names_buf = force_malloc_s(char, buf_size); @@ -4709,7 +4690,7 @@ static void obj_modern_read_skin(obj* obj, stream& s, int64_t base_offset, break; } } - free(bhs); + free_def(bhs); } if (exh.osage_sibling_infos_offset) { @@ -4803,9 +4784,9 @@ static void obj_modern_write_skin(obj* obj, stream& s, off = align_val(off, 0x10); } - std::vector strings; + std::vector strings; std::vector string_offsets; - std::vector bone_names; + std::vector bone_names; obj_skin_ex_data_header exh = {}; @@ -5332,12 +5313,12 @@ static void obj_modern_write_skin(obj* obj, stream& s, if (sk->bones_count) { sh.bone_ids_offset = s.get_position(); for (uint32_t i = 0; i < sk->bones_count; i++) - s.write_int32_t(sk->bones[i].id); + s.write_int32_t_reverse_endianness(sk->bones[i].id); s.align_write(0x10); sh.bone_parent_ids_offset = s.get_position(); for (uint32_t i = 0; i < sk->bones_count; i++) - s.write_int32_t(sk->bones[i].parent); + s.write_int32_t_reverse_endianness(sk->bones[i].parent); s.align_write(0x10); sh.bone_names_offset = s.get_position(); @@ -5356,22 +5337,22 @@ static void obj_modern_write_skin(obj* obj, stream& s, sh.bone_matrices_offset = s.get_position(); for (uint32_t i = 0; i < sk->bones_count; i++) { mat4& mat = sk->bones[i].inv_bind_pose_mat; - s.write_float_t(mat.row0.x); - s.write_float_t(mat.row1.x); - s.write_float_t(mat.row2.x); - s.write_float_t(mat.row3.x); - s.write_float_t(mat.row0.y); - s.write_float_t(mat.row1.y); - s.write_float_t(mat.row2.y); - s.write_float_t(mat.row3.y); - s.write_float_t(mat.row0.z); - s.write_float_t(mat.row1.z); - s.write_float_t(mat.row2.z); - s.write_float_t(mat.row3.z); - s.write_float_t(mat.row0.w); - s.write_float_t(mat.row1.w); - s.write_float_t(mat.row2.w); - s.write_float_t(mat.row3.w); + s.write_float_t_reverse_endianness(mat.row0.x); + s.write_float_t_reverse_endianness(mat.row1.x); + s.write_float_t_reverse_endianness(mat.row2.x); + s.write_float_t_reverse_endianness(mat.row3.x); + s.write_float_t_reverse_endianness(mat.row0.y); + s.write_float_t_reverse_endianness(mat.row1.y); + s.write_float_t_reverse_endianness(mat.row2.y); + s.write_float_t_reverse_endianness(mat.row3.y); + s.write_float_t_reverse_endianness(mat.row0.z); + s.write_float_t_reverse_endianness(mat.row1.z); + s.write_float_t_reverse_endianness(mat.row2.z); + s.write_float_t_reverse_endianness(mat.row3.z); + s.write_float_t_reverse_endianness(mat.row0.w); + s.write_float_t_reverse_endianness(mat.row1.w); + s.write_float_t_reverse_endianness(mat.row2.w); + s.write_float_t_reverse_endianness(mat.row3.w); } s.align_write(0x10); } @@ -5462,10 +5443,10 @@ static void obj_modern_write_skin(obj* obj, stream& s, exh.bone_names_offset = s.get_position(); if (!is_x) - for (std::string& i : bone_names) + for (string_hash& i : bone_names) io_write_offset_f2_pof_add(s, 0, 0x20, &pof); else - for (std::string& i : bone_names) + for (string_hash& i : bone_names) io_write_offset_x_pof_add(s, 0, &pof); s.align_write(0x10); @@ -5844,16 +5825,16 @@ static void obj_modern_write_skin(obj* obj, stream& s, } if (sk->bones || sk->ex_data_init) { - quicksort_string(strings.data(), strings.size()); + quicksort_string_hash(strings.data(), strings.size()); string_offsets.reserve(strings.size()); - for (std::string& i : strings) { + for (string_hash& i : strings) { string_offsets.push_back(s.get_position()); - s.write_string_null_terminated(i); + s.write_string_null_terminated(i.str); } } s.align_write(0x10); - std::vector osage_names; + std::vector osage_names; if (sk->ex_data_init) { obj_skin_ex_data* ex = &sk->ex_data; @@ -6013,7 +5994,7 @@ static void obj_modern_write_skin(obj* obj, stream& s, s.write_offset_x(0); } s.position_pop(); - free(bhs); + free_def(bhs); } } @@ -6040,13 +6021,13 @@ static void obj_modern_write_skin(obj* obj, stream& s, if (ex->blocks_count > 0) { s.position_push(exh.bone_names_offset, SEEK_SET); if (!is_x) - for (std::string& i : bone_names) { + for (string_hash& i : bone_names) { size_t str_offset = obj_skin_strings_get_string_offset(strings, string_offsets, i.c_str()); s.write_offset_f2(str_offset, 0x20); } else - for (std::string& i : bone_names) { + for (string_hash& i : bone_names) { size_t str_offset = obj_skin_strings_get_string_offset(strings, string_offsets, i.c_str()); s.write_offset_x(str_offset); @@ -6056,18 +6037,18 @@ static void obj_modern_write_skin(obj* obj, stream& s, s.position_push(exh.osage_nodes_offset, SEEK_SET); for (uint32_t i = 0; i < ex->osage_nodes_count; i++) { obj_skin_osage_node* osage_node = &ex->osage_nodes[i]; - s.write_uint32_t(osage_node->name_index); - s.write_float_t(osage_node->length); - s.write_uint32_t(0); + s.write_uint32_t_reverse_endianness(osage_node->name_index); + s.write_float_t_reverse_endianness(osage_node->length); + s.write_uint32_t_reverse_endianness(0); } s.position_pop(); s.position_push(exh.osage_sibling_infos_offset, SEEK_SET); for (uint32_t i = 0; i < ex->osage_sibling_infos_count; i++) { obj_skin_osage_sibling_info* osage_sibling_info = &ex->osage_sibling_infos[i]; - s.write_uint32_t(osage_sibling_info->name_index); - s.write_uint32_t(osage_sibling_info->sibling_name_index); - s.write_float_t(osage_sibling_info->max_distance); + s.write_uint32_t_reverse_endianness(osage_sibling_info->name_index); + s.write_uint32_t_reverse_endianness(osage_sibling_info->sibling_name_index); + s.write_float_t_reverse_endianness(osage_sibling_info->max_distance); } s.write_int32_t(0); s.write_int32_t(0); @@ -6078,13 +6059,13 @@ static void obj_modern_write_skin(obj* obj, stream& s, exh.osage_count -= exh.cloth_count; s.position_push(exh.osage_names_offset, SEEK_SET); if (!is_x) - for (std::string& i : osage_names) { + for (string_hash& i : osage_names) { size_t str_offset = obj_skin_strings_get_string_offset(strings, string_offsets, i.c_str()); s.write_offset_f2(str_offset, 0x20); } else - for (std::string& i : osage_names) { + for (string_hash& i : osage_names) { size_t str_offset = obj_skin_strings_get_string_offset(strings, string_offsets, i.c_str()); s.write_offset_x(str_offset); @@ -6094,16 +6075,16 @@ static void obj_modern_write_skin(obj* obj, stream& s, s.position_push(sh.ex_data_offset, SEEK_SET); if (!is_x) { - s.write_int32_t(exh.osage_count); - s.write_int32_t(ex->osage_nodes_count); + s.write_int32_t_reverse_endianness(exh.osage_count); + s.write_int32_t_reverse_endianness(ex->osage_nodes_count); s.write(0x04); s.write_offset_f2(exh.osage_nodes_offset, 0x20); s.write_offset_f2(exh.osage_names_offset, 0x20); s.write_offset_f2(exh.blocks_offset, 0x20); - s.write_int32_t(exh.bone_names_count); + s.write_int32_t_reverse_endianness(exh.bone_names_count); s.write_offset_f2(exh.bone_names_offset, 0x20); s.write_offset_f2(exh.osage_sibling_infos_offset, 0x20); - s.write_int32_t(exh.cloth_count); + s.write_int32_t_reverse_endianness(exh.cloth_count); s.write_offset_f2(ex->reserved[0], 0x20); s.write_offset_f2(ex->reserved[1], 0x20); s.write_offset_f2(ex->reserved[2], 0x20); @@ -6113,16 +6094,16 @@ static void obj_modern_write_skin(obj* obj, stream& s, s.write_offset_f2(ex->reserved[6], 0x20); } else { - s.write_int32_t(exh.osage_count); - s.write_int32_t(ex->osage_nodes_count); + s.write_int32_t_reverse_endianness(exh.osage_count); + s.write_int32_t_reverse_endianness(ex->osage_nodes_count); s.write(0x08); s.write_offset_x(exh.osage_nodes_offset); s.write_offset_x(exh.osage_names_offset); s.write_offset_x(exh.blocks_offset); - s.write_int32_t(exh.bone_names_count); + s.write_int32_t_reverse_endianness(exh.bone_names_count); s.write_offset_x(exh.bone_names_offset); s.write_offset_x(exh.osage_sibling_infos_offset); - s.write_int32_t(exh.cloth_count); + s.write_int32_t_reverse_endianness(exh.cloth_count); s.write_offset_x(ex->reserved[0]); s.write_offset_x(ex->reserved[1]); s.write_offset_x(ex->reserved[2]); @@ -6140,7 +6121,7 @@ static void obj_modern_write_skin(obj* obj, stream& s, s.write_offset_f2(sh.bone_matrices_offset, 0x20); s.write_offset_f2(sh.bone_names_offset, 0x20); s.write_offset_f2(sh.ex_data_offset, 0x20); - s.write_int32_t(sk->bones_count); + s.write_int32_t_reverse_endianness(sk->bones_count); s.write_offset_f2(sh.bone_parent_ids_offset, 0x20); s.write(0x0C); } @@ -6149,7 +6130,7 @@ static void obj_modern_write_skin(obj* obj, stream& s, s.write_offset_x(sh.bone_matrices_offset); s.write_offset_x(sh.bone_names_offset); s.write_offset_x(sh.ex_data_offset); - s.write_int32_t(sk->bones_count); + s.write_int32_t_reverse_endianness(sk->bones_count); s.write_offset_x(sh.bone_parent_ids_offset); s.write(0x18); } @@ -6274,7 +6255,7 @@ static void obj_modern_read_skin_block_cloth(obj_skin_block_cloth* b, b->mesh_indices_count = s.read_uint16_t_reverse_endianness(); b->mesh_indices = force_malloc_s(uint16_t, b->mesh_indices_count); s.read(b->mesh_indices, b->mesh_indices_count * sizeof(uint16_t)); - if (s.is_big_endian) { + if (s.big_endian) { uint16_t* mesh_indices = b->mesh_indices; for (int32_t i = 0; i < b->mesh_indices_count; i++) mesh_indices[i] = reverse_endianness_uint16_t(mesh_indices[i]); @@ -6287,7 +6268,7 @@ static void obj_modern_read_skin_block_cloth(obj_skin_block_cloth* b, b->backface_mesh_indices_count = s.read_uint16_t_reverse_endianness(); b->backface_mesh_indices = force_malloc_s(uint16_t, b->backface_mesh_indices_count); s.read(b->backface_mesh_indices, b->backface_mesh_indices_count * sizeof(uint16_t)); - if (s.is_big_endian) { + if (s.big_endian) { uint16_t* backface_mesh_indices = b->backface_mesh_indices; for (int32_t i = 0; i < b->backface_mesh_indices_count; i++) backface_mesh_indices[i] = reverse_endianness_uint16_t(backface_mesh_indices[i]); @@ -6298,7 +6279,7 @@ static void obj_modern_read_skin_block_cloth(obj_skin_block_cloth* b, } static void obj_modern_write_skin_block_cloth(obj_skin_block_cloth* b, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x, + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x, int64_t* mats_offset, int64_t* root_offset, int64_t* nodes_offset, int64_t* mesh_indices_offset, int64_t* backface_mesh_indices_offset) { int64_t mesh_name_offset = obj_skin_strings_get_string_offset(strings, @@ -6309,54 +6290,54 @@ static void obj_modern_write_skin_block_cloth(obj_skin_block_cloth* b, if (!is_x) { s.write_offset_f2(mesh_name_offset, 0x20); s.write_offset_f2(backface_mesh_name_offset, 0x20); - s.write_int32_t(b->field_8); - s.write_int32_t(b->root_count); - s.write_int32_t(b->nodes_count); - s.write_int32_t(b->field_14); + s.write_int32_t_reverse_endianness(b->field_8); + s.write_int32_t_reverse_endianness(b->root_count); + s.write_int32_t_reverse_endianness(b->nodes_count); + s.write_int32_t_reverse_endianness(b->field_14); s.write_offset_f2(b->nodes_count ? *mats_offset : 0, 0x20); s.write_offset_f2(b->root ? *root_offset : 0, 0x20); s.write_offset_f2(b->nodes ? *nodes_offset : 0, 0x20); s.write_offset_f2(b->mesh_indices ? *mesh_indices_offset : 0, 0x20); s.write_offset_f2(b->backface_mesh_indices ? *backface_mesh_indices_offset : 0, 0x20); - s.write_uint32_t(0); - s.write_uint32_t(b->reserved); + s.write_uint32_t_reverse_endianness(0); + s.write_uint32_t_reverse_endianness(b->reserved); } else { s.write_offset_x(mesh_name_offset); s.write_offset_x(backface_mesh_name_offset); - s.write_int32_t(b->field_8); - s.write_int32_t(b->root_count); - s.write_int32_t(b->nodes_count); - s.write_int32_t(b->field_14); + s.write_int32_t_reverse_endianness(b->field_8); + s.write_int32_t_reverse_endianness(b->root_count); + s.write_int32_t_reverse_endianness(b->nodes_count); + s.write_int32_t_reverse_endianness(b->field_14); s.write_offset_x(b->nodes_count ? *mats_offset : 0); s.write_offset_x(b->root ? *root_offset : 0); s.write_offset_x(b->nodes ? *nodes_offset : 0); s.write_offset_x(b->mesh_indices ? *mesh_indices_offset : 0); s.write_offset_x(b->backface_mesh_indices ? *backface_mesh_indices_offset : 0); - s.write_uint32_t(0); - s.write_uint32_t(b->reserved); + s.write_uint32_t_reverse_endianness(0); + s.write_uint32_t_reverse_endianness(b->reserved); } if (b->mats) { s.position_push(*mats_offset, SEEK_SET); for (uint32_t i = 0; i < b->mats_count; i++) { mat4& mat = b->mats[i]; - s.write_float_t(mat.row0.x); - s.write_float_t(mat.row1.x); - s.write_float_t(mat.row2.x); - s.write_float_t(mat.row3.x); - s.write_float_t(mat.row0.y); - s.write_float_t(mat.row1.y); - s.write_float_t(mat.row2.y); - s.write_float_t(mat.row3.y); - s.write_float_t(mat.row0.z); - s.write_float_t(mat.row1.z); - s.write_float_t(mat.row2.z); - s.write_float_t(mat.row3.z); - s.write_float_t(mat.row0.w); - s.write_float_t(mat.row1.w); - s.write_float_t(mat.row2.w); - s.write_float_t(mat.row3.w); + s.write_float_t_reverse_endianness(mat.row0.x); + s.write_float_t_reverse_endianness(mat.row1.x); + s.write_float_t_reverse_endianness(mat.row2.x); + s.write_float_t_reverse_endianness(mat.row3.x); + s.write_float_t_reverse_endianness(mat.row0.y); + s.write_float_t_reverse_endianness(mat.row1.y); + s.write_float_t_reverse_endianness(mat.row2.y); + s.write_float_t_reverse_endianness(mat.row3.y); + s.write_float_t_reverse_endianness(mat.row0.z); + s.write_float_t_reverse_endianness(mat.row1.z); + s.write_float_t_reverse_endianness(mat.row2.z); + s.write_float_t_reverse_endianness(mat.row3.z); + s.write_float_t_reverse_endianness(mat.row0.w); + s.write_float_t_reverse_endianness(mat.row1.w); + s.write_float_t_reverse_endianness(mat.row2.w); + s.write_float_t_reverse_endianness(mat.row3.w); *mats_offset += sizeof(mat4); } s.position_pop(); @@ -6366,16 +6347,16 @@ static void obj_modern_write_skin_block_cloth(obj_skin_block_cloth* b, s.position_push(*root_offset, SEEK_SET); for (uint32_t i = 0; i < b->root_count; i++) { obj_skin_block_cloth_root* f = &b->root[i]; - s.write_float_t(f->trans.x); - s.write_float_t(f->trans.y); - s.write_float_t(f->trans.z); - s.write_float_t(f->normal.x); - s.write_float_t(f->normal.y); - s.write_float_t(f->normal.z); - s.write_float_t(f->field_18); - s.write_int32_t(f->field_1C); - s.write_int32_t(f->field_20); - s.write_int32_t(f->field_24); + s.write_float_t_reverse_endianness(f->trans.x); + s.write_float_t_reverse_endianness(f->trans.y); + s.write_float_t_reverse_endianness(f->trans.z); + s.write_float_t_reverse_endianness(f->normal.x); + s.write_float_t_reverse_endianness(f->normal.y); + s.write_float_t_reverse_endianness(f->normal.z); + s.write_float_t_reverse_endianness(f->field_18); + s.write_int32_t_reverse_endianness(f->field_1C); + s.write_int32_t_reverse_endianness(f->field_20); + s.write_int32_t_reverse_endianness(f->field_24); for (uint32_t j = 0; j < 4; j++) obj_modern_write_skin_block_cloth_root_bone_weight(&f->bone_weights[j], @@ -6395,17 +6376,17 @@ static void obj_modern_write_skin_block_cloth(obj_skin_block_cloth* b, for (uint32_t i = 0; i < b->nodes_count - 1; i++) for (uint32_t j = 0; j < b->root_count; j++) { obj_skin_block_cloth_node* f = &b->nodes[i * b->root_count + j]; - s.write_uint32_t(f->flags); - s.write_float_t(f->trans.x); - s.write_float_t(f->trans.y); - s.write_float_t(f->trans.z); - s.write_float_t(f->trans_diff.x); - s.write_float_t(f->trans_diff.y); - s.write_float_t(f->trans_diff.z); - s.write_float_t(f->dist_top); - s.write_float_t(f->dist_bottom); - s.write_float_t(f->dist_right); - s.write_float_t(f->dist_left); + s.write_uint32_t_reverse_endianness(f->flags); + s.write_float_t_reverse_endianness(f->trans.x); + s.write_float_t_reverse_endianness(f->trans.y); + s.write_float_t_reverse_endianness(f->trans.z); + s.write_float_t_reverse_endianness(f->trans_diff.x); + s.write_float_t_reverse_endianness(f->trans_diff.y); + s.write_float_t_reverse_endianness(f->trans_diff.z); + s.write_float_t_reverse_endianness(f->dist_top); + s.write_float_t_reverse_endianness(f->dist_bottom); + s.write_float_t_reverse_endianness(f->dist_right); + s.write_float_t_reverse_endianness(f->dist_left); } s.position_pop(); *nodes_offset += (11 * sizeof(int32_t)) * b->root_count * (b->nodes_count - 1ULL); @@ -6413,16 +6394,18 @@ static void obj_modern_write_skin_block_cloth(obj_skin_block_cloth* b, if (b->mesh_indices) { s.position_push(*mesh_indices_offset, SEEK_SET); - s.write_uint16_t((uint16_t)b->mesh_indices_count); - s.write(b->mesh_indices, b->mesh_indices_count * sizeof(uint16_t)); + s.write_uint16_t_reverse_endianness((uint16_t)b->mesh_indices_count); + for (size_t i = 0; i < b->mesh_indices_count; i++) + s.write_uint16_t_reverse_endianness(b->mesh_indices[i]); s.position_pop(); *mesh_indices_offset += sizeof(uint16_t) + b->mesh_indices_count * sizeof(uint16_t); } if (b->backface_mesh_indices) { s.position_push(*backface_mesh_indices_offset, SEEK_SET); - s.write_uint16_t((uint16_t)b->backface_mesh_indices_count); - s.write(b->backface_mesh_indices, b->backface_mesh_indices_count * sizeof(uint16_t)); + s.write_uint16_t_reverse_endianness((uint16_t)b->backface_mesh_indices_count); + for (size_t i = 0; i < b->backface_mesh_indices_count; i++) + s.write_uint16_t_reverse_endianness(b->backface_mesh_indices[i]); s.position_pop(); *backface_mesh_indices_offset += sizeof(uint16_t) + b->backface_mesh_indices_count * sizeof(uint16_t); } @@ -6440,13 +6423,13 @@ static void obj_modern_read_skin_block_cloth_root_bone_weight(obj_skin_block_clo } static void obj_modern_write_skin_block_cloth_root_bone_weight(obj_skin_block_cloth_root_bone_weight* sub, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x) { + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x) { int64_t bone_name_offset = obj_skin_strings_get_string_offset(strings, string_offsets, sub->bone_name); s.write_offset(bone_name_offset, 0x20, is_x); - s.write_float_t(sub->weight); - s.write_uint32_t(sub->matrix_index); - s.write_uint32_t(sub->reserved); + s.write_float_t_reverse_endianness(sub->weight); + s.write_uint32_t_reverse_endianness(sub->matrix_index); + s.write_uint32_t_reverse_endianness(sub->reserved); if (is_x) s.write(0x04); } @@ -6467,7 +6450,7 @@ static void obj_modern_read_skin_block_constraint(obj_skin_block_constraint* b, b->name_index = 0x8000 | (int32_t)(i - str); break; } - free(name); + free_def(name); b->coupling = (obj_skin_block_constraint_coupling)s.read_int32_t_reverse_endianness(); @@ -6512,11 +6495,11 @@ static void obj_modern_read_skin_block_constraint(obj_skin_block_constraint* b, } else b->type = OBJ_SKIN_BLOCK_CONSTRAINT_NONE; - free(type); + free_def(type); } static void obj_modern_write_skin_block_constraint(obj_skin_block_constraint* b, - stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, + stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, bool is_x, int64_t* offsets) { obj_modern_write_skin_block_node(&b->base, s, strings, string_offsets, is_x); @@ -6541,7 +6524,7 @@ static void obj_modern_write_skin_block_constraint(obj_skin_block_constraint* b, string_offsets, bone_names, b->name_index); s.write_offset(name_offset, 0x20, is_x); - s.write_int32_t(b->coupling); + s.write_int32_t_reverse_endianness(b->coupling); int64_t source_node_name_offset = obj_skin_strings_get_string_offset(strings, string_offsets, b->source_node_name); @@ -6549,19 +6532,19 @@ static void obj_modern_write_skin_block_constraint(obj_skin_block_constraint* b, switch (b->type) { case OBJ_SKIN_BLOCK_CONSTRAINT_ORIENTATION: - s.write_float_t(b->orientation.offset.x); - s.write_float_t(b->orientation.offset.y); - s.write_float_t(b->orientation.offset.z); + s.write_float_t_reverse_endianness(b->orientation.offset.x); + s.write_float_t_reverse_endianness(b->orientation.offset.y); + s.write_float_t_reverse_endianness(b->orientation.offset.z); break; case OBJ_SKIN_BLOCK_CONSTRAINT_DIRECTION: obj_modern_write_skin_block_constraint_up_vector_old(&b->direction.up_vector, s, strings, string_offsets, is_x); - s.write_float_t(b->direction.align_axis.x); - s.write_float_t(b->direction.align_axis.y); - s.write_float_t(b->direction.align_axis.z); - s.write_float_t(b->direction.target_offset.x); - s.write_float_t(b->direction.target_offset.y); - s.write_float_t(b->direction.target_offset.z); + s.write_float_t_reverse_endianness(b->direction.align_axis.x); + s.write_float_t_reverse_endianness(b->direction.align_axis.y); + s.write_float_t_reverse_endianness(b->direction.align_axis.z); + s.write_float_t_reverse_endianness(b->direction.target_offset.x); + s.write_float_t_reverse_endianness(b->direction.target_offset.y); + s.write_float_t_reverse_endianness(b->direction.target_offset.z); break; case OBJ_SKIN_BLOCK_CONSTRAINT_POSITION: obj_modern_write_skin_block_constraint_up_vector_old(&b->position.up_vector, @@ -6574,7 +6557,7 @@ static void obj_modern_write_skin_block_constraint(obj_skin_block_constraint* b, case OBJ_SKIN_BLOCK_CONSTRAINT_DISTANCE: obj_modern_write_skin_block_constraint_up_vector_old(&b->distance.up_vector, s, strings, string_offsets, is_x); - s.write_float_t(b->distance.distance); + s.write_float_t_reverse_endianness(b->distance.distance); obj_modern_write_skin_block_constraint_attach_point(&b->distance.constrained_object, s, strings, string_offsets, is_x); obj_modern_write_skin_block_constraint_attach_point(&b->distance.constraining_object, @@ -6593,12 +6576,12 @@ static void obj_modern_read_skin_block_constraint_attach_point(obj_skin_block_co } static void obj_modern_write_skin_block_constraint_attach_point(obj_skin_block_constraint_attach_point* ap, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x) { - s.write_int32_t(ap->affected_by_orientation ? 1 : 0); - s.write_int32_t(ap->affected_by_scaling ? 1 : 0); - s.write_float_t(ap->offset.x); - s.write_float_t(ap->offset.y); - s.write_float_t(ap->offset.z); + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x) { + s.write_int32_t_reverse_endianness(ap->affected_by_orientation ? 1 : 0); + s.write_int32_t_reverse_endianness(ap->affected_by_scaling ? 1 : 0); + s.write_float_t_reverse_endianness(ap->offset.x); + s.write_float_t_reverse_endianness(ap->offset.y); + s.write_float_t_reverse_endianness(ap->offset.z); } static void obj_modern_read_skin_block_constraint_up_vector_old(obj_skin_block_constraint_up_vector* up, @@ -6617,15 +6600,15 @@ static void obj_modern_read_skin_block_constraint_up_vector_old(obj_skin_block_c } static void obj_modern_write_skin_block_constraint_up_vector_old(obj_skin_block_constraint_up_vector* up, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x) { - s.write_int32_t(up->active ? 1 : 0); - s.write_float_t(up->roll); - s.write_float_t(up->affected_axis.x); - s.write_float_t(up->affected_axis.y); - s.write_float_t(up->affected_axis.z); - s.write_float_t(up->point_at.x); - s.write_float_t(up->point_at.y); - s.write_float_t(up->point_at.z); + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x) { + s.write_int32_t_reverse_endianness(up->active ? 1 : 0); + s.write_float_t_reverse_endianness(up->roll); + s.write_float_t_reverse_endianness(up->affected_axis.x); + s.write_float_t_reverse_endianness(up->affected_axis.y); + s.write_float_t_reverse_endianness(up->affected_axis.z); + s.write_float_t_reverse_endianness(up->point_at.x); + s.write_float_t_reverse_endianness(up->point_at.y); + s.write_float_t_reverse_endianness(up->point_at.z); int64_t name_offset = obj_skin_strings_get_string_offset(strings, string_offsets, up->name); @@ -6645,10 +6628,10 @@ static void obj_modern_read_skin_block_expression(obj_skin_block_expression* b, b->name_index = 0x8000 | (int32_t)(i - str); break; } - free(name); + free_def(name); b->expressions_count = s.read_int32_t_reverse_endianness(); - b->expressions_count = min(b->expressions_count, 9); + b->expressions_count = min_def(b->expressions_count, 9); if (!is_x) for (uint32_t i = 0; i < b->expressions_count; i++) { int64_t expression_offset = s.read_offset_f2(header_length); @@ -6667,14 +6650,14 @@ static void obj_modern_read_skin_block_expression(obj_skin_block_expression* b, } static void obj_modern_write_skin_block_expression(obj_skin_block_expression* b, - stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, bool is_x) { + stream& s, std::vector& strings, std::vector& string_offsets, char** bone_names, bool is_x) { obj_modern_write_skin_block_node(&b->base, s, strings, string_offsets, is_x); int64_t name_offset = obj_skin_strings_get_string_offset_by_index(strings, string_offsets, bone_names, b->name_index); s.write_offset(name_offset, 0x20, is_x); - s.write_int32_t(min(b->expressions_count, 9)); + s.write_int32_t_reverse_endianness(min_def(b->expressions_count, 9)); if (!is_x) { for (uint32_t i = 0; i < b->expressions_count && i < 9; i++) { int64_t expression_offset = obj_skin_strings_get_string_offset(strings, @@ -6714,7 +6697,7 @@ static void obj_modern_read_skin_block_motion(obj_skin_block_motion* b, b->name_index = 0x8000 | (int32_t)(i - str); break; } - free(name); + free_def(name); } else b->name = s.read_utf8_string_null_terminated_offset(name_offset); @@ -6759,7 +6742,7 @@ static void obj_modern_read_skin_block_motion(obj_skin_block_motion* b, } static void obj_modern_write_skin_block_motion(obj_skin_block_motion* b, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x, + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x, char** bone_names, int64_t* bone_names_offset, int64_t* bone_matrices_offset) { obj_modern_write_skin_block_node(&b->base, s, strings, string_offsets, is_x); @@ -6771,36 +6754,36 @@ static void obj_modern_write_skin_block_motion(obj_skin_block_motion* b, name_offset = obj_skin_strings_get_string_offset(strings, string_offsets, b->name); s.write_offset(name_offset, 0x20, is_x); - s.write_int32_t(b->nodes_count); + s.write_int32_t_reverse_endianness(b->nodes_count); s.write_offset(b->nodes ? *bone_names_offset : 0, 0x20, is_x); s.write_offset(b->nodes ? *bone_matrices_offset : 0, 0x20, is_x); if (b->nodes) { s.position_push(*bone_names_offset, SEEK_SET); for (uint32_t i = 0; i < b->nodes_count; i++) - s.write_uint32_t(b->nodes[i].name_index); + s.write_uint32_t_reverse_endianness(b->nodes[i].name_index); s.position_pop(); *bone_names_offset += b->nodes_count * sizeof(uint32_t); s.position_push(*bone_matrices_offset, SEEK_SET); for (uint32_t i = 0; i < b->nodes_count; i++) { mat4& mat = b->nodes[i].inv_bind_pose_mat; - s.write_float_t(mat.row0.x); - s.write_float_t(mat.row1.x); - s.write_float_t(mat.row2.x); - s.write_float_t(mat.row3.x); - s.write_float_t(mat.row0.y); - s.write_float_t(mat.row1.y); - s.write_float_t(mat.row2.y); - s.write_float_t(mat.row3.y); - s.write_float_t(mat.row0.z); - s.write_float_t(mat.row1.z); - s.write_float_t(mat.row2.z); - s.write_float_t(mat.row3.z); - s.write_float_t(mat.row0.w); - s.write_float_t(mat.row1.w); - s.write_float_t(mat.row2.w); - s.write_float_t(mat.row3.w); + s.write_float_t_reverse_endianness(mat.row0.x); + s.write_float_t_reverse_endianness(mat.row1.x); + s.write_float_t_reverse_endianness(mat.row2.x); + s.write_float_t_reverse_endianness(mat.row3.x); + s.write_float_t_reverse_endianness(mat.row0.y); + s.write_float_t_reverse_endianness(mat.row1.y); + s.write_float_t_reverse_endianness(mat.row2.y); + s.write_float_t_reverse_endianness(mat.row3.y); + s.write_float_t_reverse_endianness(mat.row0.z); + s.write_float_t_reverse_endianness(mat.row1.z); + s.write_float_t_reverse_endianness(mat.row2.z); + s.write_float_t_reverse_endianness(mat.row3.z); + s.write_float_t_reverse_endianness(mat.row0.w); + s.write_float_t_reverse_endianness(mat.row1.w); + s.write_float_t_reverse_endianness(mat.row2.w); + s.write_float_t_reverse_endianness(mat.row3.w); } s.position_pop(); *bone_matrices_offset += b->nodes_count * sizeof(mat4); @@ -6826,20 +6809,20 @@ static void obj_modern_read_skin_block_node(obj_skin_block_node* b, } static void obj_modern_write_skin_block_node(obj_skin_block_node* b, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x) { + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x) { int64_t parent_name_offset = obj_skin_strings_get_string_offset(strings, string_offsets, b->parent_name); s.write_offset(parent_name_offset, 0x20, is_x); - s.write_float_t(b->position.x); - s.write_float_t(b->position.y); - s.write_float_t(b->position.z); - s.write_float_t(b->rotation.x); - s.write_float_t(b->rotation.y); - s.write_float_t(b->rotation.z); - s.write_float_t(b->scale.x); - s.write_float_t(b->scale.y); - s.write_float_t(b->scale.z); + s.write_float_t_reverse_endianness(b->position.x); + s.write_float_t_reverse_endianness(b->position.y); + s.write_float_t_reverse_endianness(b->position.z); + s.write_float_t_reverse_endianness(b->rotation.x); + s.write_float_t_reverse_endianness(b->rotation.y); + s.write_float_t_reverse_endianness(b->rotation.z); + s.write_float_t_reverse_endianness(b->scale.x); + s.write_float_t_reverse_endianness(b->scale.y); + s.write_float_t_reverse_endianness(b->scale.z); if (is_x) s.write(0x04); } @@ -6867,13 +6850,13 @@ static void obj_modern_read_skin_block_osage(obj_skin_block_osage* b, } static void obj_modern_write_skin_block_osage(obj_skin_block_osage* b, - stream& s, std::vector& strings, std::vector& string_offsets, bool is_x) { + stream& s, std::vector& strings, std::vector& string_offsets, bool is_x) { obj_modern_write_skin_block_node(&b->base, s, strings, string_offsets, is_x); - s.write_int32_t(b->start_index); - s.write_int32_t(b->count); - s.write_uint32_t(b->external_name_index); - s.write_uint32_t(b->name_index); + s.write_int32_t_reverse_endianness(b->start_index); + s.write_int32_t_reverse_endianness(b->count); + s.write_uint32_t_reverse_endianness(b->external_name_index); + s.write_uint32_t_reverse_endianness(b->name_index); if (!is_x) s.write(0x14); @@ -6920,15 +6903,14 @@ static void obj_modern_read_vertex(obj* obj, stream& s, int64_t* vertex, obj_mes normal.y = (float_t)s.read_int16_t_reverse_endianness(); normal.z = (float_t)s.read_int16_t_reverse_endianness(); s.read(0, 0x02); - vec3_div_min_max_scalar(normal, -32768.0f, 32767.0f, vtx[i].normal); + vtx[i].normal = vec3::div_min_max(normal, -32768.0f, 32767.0f); vec4 tangent; tangent.x = (float_t)s.read_int16_t_reverse_endianness(); tangent.y = (float_t)s.read_int16_t_reverse_endianness(); tangent.z = (float_t)s.read_int16_t_reverse_endianness(); tangent.w = (float_t)s.read_int16_t_reverse_endianness(); - vec4_div_min_max_scalar(tangent, -32768.0f, 32767.0f, tangent); - vtx[i].tangent = tangent; + vtx[i].tangent = vec4::div_min_max(tangent, -32768.0f, 32767.0f); vec2h texcoord0; texcoord0.x = s.read_half_t_reverse_endianness(); @@ -6971,7 +6953,7 @@ static void obj_modern_read_vertex(obj* obj, stream& s, int64_t* vertex, obj_mes bone_weight.y = (float_t)s.read_int16_t_reverse_endianness(); bone_weight.z = (float_t)s.read_int16_t_reverse_endianness(); bone_weight.w = (float_t)s.read_int16_t_reverse_endianness(); - vec4_div_min_max_scalar(bone_weight, -32768.0f, 32767.0f, bone_weight); + bone_weight = vec4::div_min_max(bone_weight, -32768.0f, 32767.0f); vec4i bone_index; bone_index.x = (int32_t)s.read_uint8_t(); @@ -7057,69 +7039,66 @@ static void obj_modern_write_vertex(obj* obj, stream& s, bool is_x, vertex[13] = s.get_position(); for (uint32_t i = 0; i < _num_vertex; i++) { vec3 position = vtx[i].position; - s.write_float_t(position.x); - s.write_float_t(position.y); - s.write_float_t(position.z); + s.write_float_t_reverse_endianness(position.x); + s.write_float_t_reverse_endianness(position.y); + s.write_float_t_reverse_endianness(position.z); - vec3 normal; - vec3_mult_min_max_scalar(vtx[i].normal, -32768.0f, 32767.0f, normal); - s.write_int16_t((int16_t)roundf(normal.x)); - s.write_int16_t((int16_t)roundf(normal.y)); - s.write_int16_t((int16_t)roundf(normal.z)); + vec3 normal = vec3::mult_min_max(vtx[i].normal, -32768.0f, 32767.0f); + s.write_int16_t_reverse_endianness((int16_t)roundf(normal.x)); + s.write_int16_t_reverse_endianness((int16_t)roundf(normal.y)); + s.write_int16_t_reverse_endianness((int16_t)roundf(normal.z)); s.write(0x02); - vec4 tangent = vtx[i].tangent; - vec4_mult_min_max_scalar(tangent, -32768.0f, 32767.0f, tangent); - s.write_int16_t((int16_t)roundf(tangent.x)); - s.write_int16_t((int16_t)roundf(tangent.y)); - s.write_int16_t((int16_t)roundf(tangent.z)); - s.write_int16_t((int16_t)roundf(tangent.w)); + vec4 tangent = vec4::mult_min_max(vtx[i].tangent, -32768.0f, 32767.0f); + s.write_int16_t_reverse_endianness((int16_t)roundf(tangent.x)); + s.write_int16_t_reverse_endianness((int16_t)roundf(tangent.y)); + s.write_int16_t_reverse_endianness((int16_t)roundf(tangent.z)); + s.write_int16_t_reverse_endianness((int16_t)roundf(tangent.w)); vec2h texcoord0; vec2_to_vec2h(vtx[i].texcoord0, texcoord0); - s.write_half_t(texcoord0.x); - s.write_half_t(texcoord0.y); + s.write_half_t_reverse_endianness(texcoord0.x); + s.write_half_t_reverse_endianness(texcoord0.y); vec2h texcoord1; vec2_to_vec2h(vtx[i].texcoord1, texcoord1); - s.write_half_t(texcoord1.x); - s.write_half_t(texcoord1.y); + s.write_half_t_reverse_endianness(texcoord1.x); + s.write_half_t_reverse_endianness(texcoord1.y); if (_vertex_flags == 0x06) { vec2h texcoord2; vec2_to_vec2h(vtx[i].texcoord2, texcoord2); - s.write_half_t(texcoord2.x); - s.write_half_t(texcoord2.y); + s.write_half_t_reverse_endianness(texcoord2.x); + s.write_half_t_reverse_endianness(texcoord2.y); } else if (_vertex_flags == 0x0A) { vec2h texcoord2; vec2_to_vec2h(vtx[i].texcoord2, texcoord2); - s.write_half_t(texcoord2.x); - s.write_half_t(texcoord2.y); + s.write_half_t_reverse_endianness(texcoord2.x); + s.write_half_t_reverse_endianness(texcoord2.y); vec2h texcoord3; vec2_to_vec2h(vtx[i].texcoord3, texcoord3); - s.write_half_t(texcoord3.x); - s.write_half_t(texcoord3.y); + s.write_half_t_reverse_endianness(texcoord3.x); + s.write_half_t_reverse_endianness(texcoord3.y); } vec4h color; vec4_to_vec4h(vtx[i].color0, color); - s.write_half_t(color.x); - s.write_half_t(color.y); - s.write_half_t(color.z); - s.write_half_t(color.w); + s.write_half_t_reverse_endianness(color.x); + s.write_half_t_reverse_endianness(color.y); + s.write_half_t_reverse_endianness(color.z); + s.write_half_t_reverse_endianness(color.w); if (_vertex_flags == 0x04) { - vec4 bone_weight = vtx[i].bone_weight; - vec4_mult_min_max_scalar(bone_weight, -32768.0f, 32767.0f, bone_weight); - s.write_int16_t((int16_t)bone_weight.x); - s.write_int16_t((int16_t)bone_weight.y); - s.write_int16_t((int16_t)bone_weight.z); - s.write_int16_t((int16_t)bone_weight.w); + vec4 bone_weight = vec4::mult_min_max(vtx[i].bone_weight, -32768.0f, 32767.0f); + s.write_int16_t_reverse_endianness((int16_t)bone_weight.x); + s.write_int16_t_reverse_endianness((int16_t)bone_weight.y); + s.write_int16_t_reverse_endianness((int16_t)bone_weight.z); + s.write_int16_t_reverse_endianness((int16_t)bone_weight.w); vec4u8 bone_index; - vec4_to_vec4u8(vtx[i].bone_index, bone_index) + vec4i_to_vec4u8(vtx[i].bone_index, bone_index); s.write_uint8_t(bone_index.x); s.write_uint8_t(bone_index.y); s.write_uint8_t(bone_index.z); @@ -7133,58 +7112,68 @@ static void obj_modern_write_vertex(obj* obj, stream& s, bool is_x, } inline static void obj_skin_block_node_free(obj_skin_block_node* b) { - free(b->parent_name); + free_def(b->parent_name); } -inline static uint32_t obj_skin_strings_get_string_index(std::vector& vec, const char* str) { +inline static uint32_t obj_skin_strings_get_string_index(std::vector& vec, const char* str) { size_t len = utf8_length(str); - for (std::string& i : vec) - if (!memcmp(str, i.c_str(), min(len, i.size()) + 1)) + uint64_t hash_fnv1a64m = hash_string_fnv1a64m(str); + uint64_t hash_murmurhash = hash_string_murmurhash(str); + for (string_hash& i : vec) + if (hash_fnv1a64m == i.hash_fnv1a64m && hash_murmurhash == i.hash_murmurhash) return (uint32_t)(0x8000 | &i - vec.data()); return 0x8000; } -inline static int64_t obj_skin_strings_get_string_offset(std::vector& vec, +inline static int64_t obj_skin_strings_get_string_offset(std::vector& vec, std::vector& vec_off, const char* str) { size_t len = utf8_length(str); - for (std::string& i : vec) - if (!memcmp(str, i.c_str(), min(len, i.size()) + 1)) + uint64_t hash_fnv1a64m = hash_string_fnv1a64m(str); + uint64_t hash_murmurhash = hash_string_murmurhash(str); + for (string_hash& i : vec) + if (hash_fnv1a64m == i.hash_fnv1a64m && hash_murmurhash == i.hash_murmurhash) return vec_off[&i - vec.data()]; return 0; } -inline static int64_t obj_skin_strings_get_string_offset_by_index(std::vector& vec, +inline static int64_t obj_skin_strings_get_string_offset_by_index(std::vector& vec, std::vector& vec_off, char** strings, uint32_t index) { if (~index & 0x8000) return 0; char* str = strings[index & 0x7FFF]; size_t len = utf8_length(str); - for (std::string& i : vec) - if (!memcmp(str, i.c_str(), min(len, i.size()) + 1)) + uint64_t hash_fnv1a64m = hash_string_fnv1a64m(str); + uint64_t hash_murmurhash = hash_string_murmurhash(str); + for (string_hash& i : vec) + if (hash_fnv1a64m == i.hash_fnv1a64m && hash_murmurhash == i.hash_murmurhash) return vec_off[&i - vec.data()]; return 0; } -inline static void obj_skin_strings_push_back_check(std::vector& vec, const char* str) { +inline static void obj_skin_strings_push_back_check(std::vector& vec, const char* str) { size_t len = utf8_length(str); - for (std::string& i : vec) - if (!memcmp(str, i.c_str(), min(len, i.size()) + 1)) + uint64_t hash_fnv1a64m = hash_string_fnv1a64m(str); + uint64_t hash_murmurhash = hash_string_murmurhash(str); + for (string_hash& i : vec) + if (hash_fnv1a64m == i.hash_fnv1a64m && hash_murmurhash == i.hash_murmurhash) return; - vec.push_back(std::string(str, len)); + vec.push_back(str); } -inline static void obj_skin_strings_push_back_check_by_index(std::vector& vec, +inline static void obj_skin_strings_push_back_check_by_index(std::vector& vec, char** strings, uint32_t index) { if (~index & 0x8000) return; char* str = strings[index & 0x7FFF]; size_t len = utf8_length(str); - for (std::string& i : vec) - if (!memcmp(str, i.c_str(), min(len, i.size()) + 1)) + uint64_t hash_fnv1a64m = hash_string_fnv1a64m(str); + uint64_t hash_murmurhash = hash_string_murmurhash(str); + for (string_hash& i : vec) + if (hash_fnv1a64m == i.hash_fnv1a64m && hash_murmurhash == i.hash_murmurhash) return; - vec.push_back(std::string(str, len)); + vec.push_back(str); } diff --git a/src/KKdLib/obj.hpp b/src/KKdLib/obj.hpp index 600fae7c..95b2bd4b 100644 --- a/src/KKdLib/obj.hpp +++ b/src/KKdLib/obj.hpp @@ -642,6 +642,7 @@ struct obj { struct obj_set { bool ready; bool modern; + bool big_endian; bool is_x; obj* obj_data; diff --git a/src/KKdLib/post_process_table/dof.cpp b/src/KKdLib/post_process_table/dof.cpp index c371d274..bb740edf 100644 --- a/src/KKdLib/post_process_table/dof.cpp +++ b/src/KKdLib/post_process_table/dof.cpp @@ -5,15 +5,16 @@ #include "dof.hpp" #include "../f2/struct.hpp" +#include "../io/file_stream.hpp" +#include "../io/memory_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../hash.hpp" #include "../str_utils.hpp" static void dof_read_inner(dof* d, stream& s, uint32_t header_length); static void dof_write_inner(dof* d, stream& s); -dof::dof() : ready(), is_x() { +dof::dof() : ready(), big_endian(), is_x() { murmurhash = hash_murmurhash_empty; } @@ -30,13 +31,13 @@ void dof::read(const char* path) { f2_struct st; st.read(path_dft); if (st.header.signature == reverse_endianness_uint32_t('DOFT')) { - stream s_doft; + memory_stream s_doft; s_doft.open(st.data); - s_doft.is_big_endian = st.header.use_big_endian; + s_doft.big_endian = st.header.use_big_endian; dof_read_inner(this, s_doft, st.header.length); } } - free(path_dft); + free_def(path_dft); } void dof::read(const wchar_t* path) { @@ -48,13 +49,13 @@ void dof::read(const wchar_t* path) { f2_struct st; st.read(path_dex); if (st.header.signature == reverse_endianness_uint32_t('DOFT')) { - stream s_doft; + memory_stream s_doft; s_doft.open(st.data); - s_doft.is_big_endian = st.header.use_big_endian; + s_doft.big_endian = st.header.use_big_endian; dof_read_inner(this, s_doft, st.header.length); } } - free(path_dex); + free_def(path_dex); } void dof::read(const void* data, size_t size) { @@ -65,9 +66,9 @@ void dof::read(const void* data, size_t size) { f2_struct st; st.read(data, size); if (st.header.signature == reverse_endianness_uint32_t('DOFT')) { - stream s_doft; + memory_stream s_doft; s_doft.open(st.data); - s_doft.is_big_endian = st.header.use_big_endian; + s_doft.big_endian = st.header.use_big_endian; dof_read_inner(this, s_doft, st.header.length); } } @@ -77,11 +78,11 @@ void dof::write(const char* path) { return; char* path_dex = str_utils_add(path, ".dft"); - stream s; + file_stream s; s.open(path_dex, "wb"); - if (s.io.stream) + if (s.check_not_null()) dof_write_inner(this, s); - free(path_dex); + free_def(path_dex); } void dof::write(const wchar_t* path) { @@ -89,18 +90,18 @@ void dof::write(const wchar_t* path) { return; wchar_t* path_dex = str_utils_add(path, L".dft"); - stream s; + file_stream s; s.open(path_dex, L"wb"); - if (s.io.stream) + if (s.check_not_null()) dof_write_inner(this, s); - free(path_dex); + free_def(path_dex); } void dof::write(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; + memory_stream s; s.open(); dof_write_inner(this, s); s.align_write(0x10); @@ -132,6 +133,7 @@ static void dof_read_inner(dof* d, stream& s, uint32_t header_length) { d->data.resize(count); + bool big_endian = s.big_endian; bool is_x = false; if (offset) { s.position_push(offset, SEEK_SET); @@ -165,15 +167,18 @@ static void dof_read_inner(dof* d, stream& s, uint32_t header_length) { } d->ready = true; + d->big_endian = big_endian; d->is_x = is_x; } static void dof_write_inner(dof* d, stream& s) { - stream s_motc; - s_motc.open(); - + bool big_endian = d->big_endian; bool is_x = d->is_x; + memory_stream s_doft; + s_doft.open(); + s_doft.big_endian = big_endian; + uint32_t o; enrs e; enrs_entry ee; @@ -205,35 +210,35 @@ static void dof_write_inner(dof* d, stream& s) { } if (!is_x) { - s_motc.write_uint32_t((uint32_t)d->data.size()); + s_doft.write_uint32_t((uint32_t)d->data.size()); pof.add(s, 0x40); s.write_offset_x(0x50); s.align_write(0x10); for (dof_data& i : d->data) { - s.write_uint32_t(i.flags); - s.write_float_t(i.focus); - s.write_float_t(i.focus_range); - s.write_float_t(i.fuzzing_range); - s.write_float_t(i.ratio); - s.write_float_t(i.quality); + s.write_uint32_t_reverse_endianness(i.flags); + s.write_float_t_reverse_endianness(i.focus); + s.write_float_t_reverse_endianness(i.focus_range); + s.write_float_t_reverse_endianness(i.fuzzing_range); + s.write_float_t_reverse_endianness(i.ratio); + s.write_float_t_reverse_endianness(i.quality); } } else { - s_motc.write_uint32_t((uint32_t)d->data.size()); + s_doft.write_uint32_t((uint32_t)d->data.size()); s.align_write(0x08); pof.add(s, 0x00); s.write_offset_x(0x10); s.align_write(0x10); for (dof_data& i : d->data) { - s.write_uint32_t(i.flags); - s.write_float_t(i.focus); - s.write_float_t(i.focus_range); - s.write_float_t(i.fuzzing_range); - s.write_float_t(i.ratio); - s.write_float_t(i.quality); - s.write_int32_t(i.chara_id); + s.write_uint32_t_reverse_endianness(i.flags); + s.write_float_t_reverse_endianness(i.focus); + s.write_float_t_reverse_endianness(i.focus_range); + s.write_float_t_reverse_endianness(i.fuzzing_range); + s.write_float_t_reverse_endianness(i.ratio); + s.write_float_t_reverse_endianness(i.quality); + s.write_int32_t_reverse_endianness(i.chara_id); } } @@ -241,16 +246,16 @@ static void dof_write_inner(dof* d, stream& s) { } f2_struct st; - s_motc.align_write(0x10); - s_motc.copy(st.data); - s_motc.close(); + s_doft.align_write(0x10); + s_doft.copy(st.data); + s_doft.close(); st.enrs = e; st.pof = pof; st.header.signature = reverse_endianness_uint32_t('DOFT'); st.header.length = 0x40; - st.header.use_big_endian = false; + st.header.use_big_endian = big_endian; st.header.use_section_size = true; st.header.murmurhash = murmurhash; st.header.inner_signature = 0x03; diff --git a/src/KKdLib/post_process_table/dof.hpp b/src/KKdLib/post_process_table/dof.hpp index 226199f3..84665896 100644 --- a/src/KKdLib/post_process_table/dof.hpp +++ b/src/KKdLib/post_process_table/dof.hpp @@ -29,6 +29,7 @@ struct dof_data { struct dof { bool ready; + bool big_endian; bool is_x; uint32_t murmurhash; diff --git a/src/KKdLib/pv_exp.cpp b/src/KKdLib/pv_exp.cpp index 6e4761a9..8ec0b34f 100644 --- a/src/KKdLib/pv_exp.cpp +++ b/src/KKdLib/pv_exp.cpp @@ -5,8 +5,9 @@ #include "pv_exp.hpp" #include "f2/struct.hpp" +#include "io/file_stream.hpp" +#include "io/memory_stream.hpp" #include "io/path.hpp" -#include "io/stream.hpp" #include "str_utils.hpp" static void pv_exp_classic_read_inner(pv_exp* exp, stream& s); @@ -30,7 +31,7 @@ pv_exp_mot::~pv_exp_mot() { } } -pv_exp::pv_exp() : ready(), modern(), is_x() { +pv_exp::pv_exp() : ready(), modern(), big_endian(), is_x() { } @@ -45,18 +46,18 @@ void pv_exp::read(const char* path, bool modern) { if (!modern) { char* path_bin = str_utils_add(path, ".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, "rb"); - if (s.io.stream) { + if (s.check_not_null()) { uint8_t* data = force_malloc_s(uint8_t, s.length); s.read(data, s.length); - stream s_bin; + memory_stream s_bin; s_bin.open(data, s.length); pv_exp_classic_read_inner(this, s_bin); - free(data); + free_def(data); } } - free(path_bin); + free_def(path_bin); } else { char* path_dex = str_utils_add(path, ".dex"); @@ -64,13 +65,13 @@ void pv_exp::read(const char* path, bool modern) { f2_struct st; st.read(path_dex); if (st.header.signature == reverse_endianness_uint32_t('EXPC')) { - stream s_expc; + memory_stream s_expc; s_expc.open(st.data); - s_expc.is_big_endian = st.header.use_big_endian; + s_expc.big_endian = st.header.use_big_endian; pv_exp_modern_read_inner(this, s_expc, st.header.length); } } - free(path_dex); + free_def(path_dex); } } @@ -81,18 +82,18 @@ void pv_exp::read(const wchar_t* path, bool modern) { if (!modern) { wchar_t* path_bin = str_utils_add(path, L".bin"); if (path_check_file_exists(path_bin)) { - stream s; + file_stream s; s.open(path_bin, L"rb"); - if (s.io.stream) { + if (s.check_not_null()) { uint8_t* data = force_malloc_s(uint8_t, s.length); s.read(data, s.length); - stream s_bin; + memory_stream s_bin; s_bin.open(data, s.length); pv_exp_classic_read_inner(this, s_bin); - free(data); + free_def(data); } } - free(path_bin); + free_def(path_bin); } else { wchar_t* path_dex = str_utils_add(path, L".dex"); @@ -100,13 +101,13 @@ void pv_exp::read(const wchar_t* path, bool modern) { f2_struct st; st.read(path_dex); if (st.header.signature == reverse_endianness_uint32_t('EXPC')) { - stream s_expc; + memory_stream s_expc; s_expc.open(st.data); - s_expc.is_big_endian = st.header.use_big_endian; + s_expc.big_endian = st.header.use_big_endian; pv_exp_modern_read_inner(this, s_expc, st.header.length); } } - free(path_dex); + free_def(path_dex); } } @@ -115,7 +116,7 @@ void pv_exp::read(const void* data, size_t size, bool modern) { return; if (!modern) { - stream s; + memory_stream s; s.open(data, size); pv_exp_classic_read_inner(this, s); } @@ -123,9 +124,9 @@ void pv_exp::read(const void* data, size_t size, bool modern) { f2_struct st; st.read(data, size); if (st.header.signature == reverse_endianness_uint32_t('EXPC')) { - stream s_expc; + memory_stream s_expc; s_expc.open(st.data); - s_expc.is_big_endian = st.header.use_big_endian; + s_expc.big_endian = st.header.use_big_endian; pv_exp_modern_read_inner(this, s_expc, st.header.length); } } @@ -137,19 +138,19 @@ void pv_exp::write(const char* path) { if (!modern) { char* path_bin = str_utils_add(path, ".bin"); - stream s; + file_stream s; s.open(path_bin, "wb"); - if (s.io.stream) + if (s.check_not_null()) pv_exp_classic_write_inner(this, s); - free(path_bin); + free_def(path_bin); } else { char* path_dex = str_utils_add(path, ".dex"); - stream s; + file_stream s; s.open(path_dex, "wb"); - if (s.io.stream) + if (s.check_not_null()) pv_exp_modern_write_inner(this, s); - free(path_dex); + free_def(path_dex); } } @@ -159,19 +160,19 @@ void pv_exp::write(const wchar_t* path) { if (!modern) { wchar_t* path_bin = str_utils_add(path, L".bin"); - stream s; + file_stream s; s.open(path_bin, L"wb"); - if (s.io.stream) + if (s.check_not_null()) pv_exp_classic_write_inner(this, s); - free(path_bin); + free_def(path_bin); } else { wchar_t* path_dex = str_utils_add(path, L".dex"); - stream s; + file_stream s; s.open(path_dex, L"wb"); - if (s.io.stream) + if (s.check_not_null()) pv_exp_modern_write_inner(this, s); - free(path_dex); + free_def(path_dex); } } @@ -179,7 +180,7 @@ void pv_exp::write(void** data, size_t* size) { if (!data || !size || !ready) return; - stream s; + memory_stream s; s.open(); if (!modern) pv_exp_classic_write_inner(this, s); @@ -208,6 +209,7 @@ static void pv_exp_classic_read_inner(pv_exp* exp, stream& s) { if (s.read_uint32_t() != 0x64) { exp->ready = false; exp->modern = false; + exp->big_endian = false; exp->is_x = false; return; } @@ -247,8 +249,15 @@ static void pv_exp_classic_read_inner(pv_exp* exp, stream& s) { s.position_pop(); i.face_data = new pv_exp_data[face_count]; + pv_exp_data* face_data = i.face_data; s.position_push(face_offset[&i - exp->motion_data.data()], SEEK_SET); - s.read(i.face_data, sizeof(pv_exp_data) * face_count); + for (size_t j = face_count; j; j--, face_data++) { + face_data->frame = s.read_float_t(); + face_data->type = s.read_int16_t(); + face_data->id = s.read_int16_t(); + face_data->value = s.read_float_t(); + face_data->trans = s.read_float_t(); + } s.position_pop(); } @@ -264,8 +273,15 @@ static void pv_exp_classic_read_inner(pv_exp* exp, stream& s) { s.position_pop(); i.face_cl_data = new pv_exp_data[face_cl_count]; + pv_exp_data* face_cl_data = i.face_cl_data; s.position_push(face_cl_offset[&i - exp->motion_data.data()], SEEK_SET); - s.read(i.face_cl_data, sizeof(pv_exp_data) * face_cl_count); + for (size_t j = face_cl_count; j; j--, face_cl_data++) { + face_cl_data->frame = s.read_float_t(); + face_cl_data->type = s.read_int16_t(); + face_cl_data->id = s.read_int16_t(); + face_cl_data->value = s.read_float_t(); + face_cl_data->trans = s.read_float_t(); + } s.position_pop(); } @@ -273,12 +289,13 @@ static void pv_exp_classic_read_inner(pv_exp* exp, stream& s) { i.name = s.read_string_null_terminated_offset(name_offset[&i - exp->motion_data.data()]); } - free(face_offset); - free(face_cl_offset); - free(name_offset); + free_def(face_offset); + free_def(face_cl_offset); + free_def(name_offset); exp->ready = true; exp->modern = false; + exp->big_endian = false; exp->is_x = false; } @@ -308,12 +325,16 @@ static void pv_exp_classic_write_inner(pv_exp* exp, stream& s) { face_offset[&i - exp->motion_data.data()] = s.get_position(); pv_exp_data* face_data = i.face_data; - while (face_data->type != -1) { + while (true) { s.write_float_t(face_data->frame); s.write_int16_t(face_data->type); s.write_int16_t(face_data->id); s.write_float_t(face_data->value); s.write_float_t(face_data->trans); + + if (face_data->type == -1) + break; + face_data++; } s.align_write(0x20); @@ -321,12 +342,16 @@ static void pv_exp_classic_write_inner(pv_exp* exp, stream& s) { face_cl_offset[&i - exp->motion_data.data()] = s.get_position(); pv_exp_data* face_cl_data = i.face_cl_data; - while (face_cl_data->type != -1) { + while (true) { s.write_float_t(face_cl_data->frame); s.write_int16_t(face_cl_data->type); s.write_int16_t(face_cl_data->id); s.write_float_t(face_cl_data->value); s.write_float_t(face_cl_data->trans); + + if (face_cl_data->type == -1) + break; + face_cl_data++; } s.align_write(0x20); @@ -348,9 +373,9 @@ static void pv_exp_classic_write_inner(pv_exp* exp, stream& s) { for (pv_exp_mot& i : exp->motion_data) s.write_uint32_t((uint32_t)name_offset[&i - exp->motion_data.data()]); - free(face_offset); - free(face_cl_offset); - free(name_offset); + free_def(face_offset); + free_def(face_cl_offset); + free_def(name_offset); s.position_pop(); s.write_uint32_t((uint32_t)name_offsets_offset); @@ -360,10 +385,12 @@ static void pv_exp_modern_read_inner(pv_exp* exp, stream& s, uint32_t header_len if (s.read_uint32_t() != 0x64) { exp->ready = false; exp->modern = false; + exp->big_endian = false; exp->is_x = false; return; } + bool big_endian = s.big_endian; bool is_x = false; exp->motion_data.resize(0); @@ -415,8 +442,15 @@ static void pv_exp_modern_read_inner(pv_exp* exp, stream& s, uint32_t header_len s.position_pop(); i.face_data = new pv_exp_data[face_count]; + pv_exp_data* face_data = i.face_data; s.position_push(face_offset[&i - exp->motion_data.data()], SEEK_SET); - s.read(i.face_data, sizeof(pv_exp_data) * face_count); + for (size_t j = face_count; j; j--, face_data++) { + face_data->frame = s.read_float_t_reverse_endianness(); + face_data->type = s.read_int16_t_reverse_endianness(); + face_data->id = s.read_int16_t_reverse_endianness(); + face_data->value = s.read_float_t_reverse_endianness(); + face_data->trans = s.read_float_t_reverse_endianness(); + } s.position_pop(); } @@ -432,8 +466,15 @@ static void pv_exp_modern_read_inner(pv_exp* exp, stream& s, uint32_t header_len s.position_pop(); i.face_cl_data = new pv_exp_data[face_cl_count]; + pv_exp_data* face_cl_data = i.face_cl_data; s.position_push(face_cl_offset[&i - exp->motion_data.data()], SEEK_SET); - s.read(i.face_cl_data, sizeof(pv_exp_data) * face_cl_count); + for (size_t j = face_cl_count; j; j--, face_cl_data++) { + face_cl_data->frame = s.read_float_t_reverse_endianness(); + face_cl_data->type = s.read_int16_t_reverse_endianness(); + face_cl_data->id = s.read_int16_t_reverse_endianness(); + face_cl_data->value = s.read_float_t_reverse_endianness(); + face_cl_data->trans = s.read_float_t_reverse_endianness(); + } s.position_pop(); } @@ -441,23 +482,26 @@ static void pv_exp_modern_read_inner(pv_exp* exp, stream& s, uint32_t header_len i.name = s.read_string_null_terminated_offset(name_offset[&i - exp->motion_data.data()]); } - free(face_offset); - free(face_cl_offset); - free(name_offset); + free_def(face_offset); + free_def(face_cl_offset); + free_def(name_offset); exp->ready = true; exp->modern = true; + exp->big_endian = big_endian; exp->is_x = is_x; } static void pv_exp_modern_write_inner(pv_exp* exp, stream& s) { - stream s_expc; - s_expc.open(); - + bool big_endian = exp->big_endian; bool is_x = exp->is_x; - s_expc.write_uint32_t(0x64); - s_expc.write_int32_t((int32_t)exp->motion_data.size()); + memory_stream s_expc; + s_expc.open(); + s_expc.big_endian = big_endian; + + s_expc.write_uint32_t_reverse_endianness(0x64); + s_expc.write_int32_t_reverse_endianness((int32_t)exp->motion_data.size()); s_expc.write_offset(is_x ? 0x28 : 0x20, 0x20, is_x); s_expc.position_push(s_expc.get_position(), SEEK_SET); @@ -488,12 +532,16 @@ static void pv_exp_modern_write_inner(pv_exp* exp, stream& s) { face_offset[&i - exp->motion_data.data()] = s_expc.get_position(); pv_exp_data* face_data = i.face_data; - while (face_data->type != -1) { - s_expc.write_float_t(face_data->frame); - s_expc.write_int16_t(face_data->type); - s_expc.write_int16_t(face_data->id); - s_expc.write_float_t(face_data->value); - s_expc.write_float_t(face_data->trans); + while (true) { + s_expc.write_float_t_reverse_endianness(face_data->frame); + s_expc.write_int16_t_reverse_endianness(face_data->type); + s_expc.write_int16_t_reverse_endianness(face_data->id); + s_expc.write_float_t_reverse_endianness(face_data->value); + s_expc.write_float_t_reverse_endianness(face_data->trans); + + if (face_data->type == -1) + break; + face_data++; } s_expc.align_write(0x20); @@ -501,12 +549,16 @@ static void pv_exp_modern_write_inner(pv_exp* exp, stream& s) { face_cl_offset[&i - exp->motion_data.data()] = s_expc.get_position(); pv_exp_data* face_cl_data = i.face_cl_data; - while (face_cl_data->type != -1) { - s_expc.write_float_t(face_cl_data->frame); - s_expc.write_int16_t(face_cl_data->type); - s_expc.write_int16_t(face_cl_data->id); - s_expc.write_float_t(face_cl_data->value); - s_expc.write_float_t(face_cl_data->trans); + while (true) { + s_expc.write_float_t_reverse_endianness(face_cl_data->frame); + s_expc.write_int16_t_reverse_endianness(face_cl_data->type); + s_expc.write_int16_t_reverse_endianness(face_cl_data->id); + s_expc.write_float_t_reverse_endianness(face_cl_data->value); + s_expc.write_float_t_reverse_endianness(face_cl_data->trans); + + if (face_cl_data->type == -1) + break; + face_cl_data++; } s_expc.align_write(0x20); @@ -538,9 +590,9 @@ static void pv_exp_modern_write_inner(pv_exp* exp, stream& s) { for (pv_exp_mot& i : exp->motion_data) s_expc.write_offset_x(name_offset[&i - exp->motion_data.data()]); - free(face_offset); - free(face_cl_offset); - free(name_offset); + free_def(face_offset); + free_def(face_cl_offset); + free_def(name_offset); s_expc.position_pop(); @@ -553,7 +605,7 @@ static void pv_exp_modern_write_inner(pv_exp* exp, stream& s) { st.header.signature = reverse_endianness_uint32_t('EXPC'); st.header.length = 0x20; - st.header.use_big_endian = false; + st.header.use_big_endian = big_endian; st.header.use_section_size = true; st.write(s, true, exp->is_x); diff --git a/src/KKdLib/pv_exp.hpp b/src/KKdLib/pv_exp.hpp index efed5152..ebf81001 100644 --- a/src/KKdLib/pv_exp.hpp +++ b/src/KKdLib/pv_exp.hpp @@ -29,6 +29,7 @@ struct pv_exp_mot { struct pv_exp { bool ready; bool modern; + bool big_endian; bool is_x; std::vector motion_data; diff --git a/src/KKdLib/pvpp.cpp b/src/KKdLib/pvpp.cpp index 3870ff98..bd20e1c6 100644 --- a/src/KKdLib/pvpp.cpp +++ b/src/KKdLib/pvpp.cpp @@ -5,8 +5,9 @@ #include "pvpp.hpp" #include "f2/struct.hpp" +#include "io/file_stream.hpp" +#include "io/memory_stream.hpp" #include "io/path.hpp" -#include "io/stream.hpp" #include "str_utils.hpp" static void pvpp_auth_3d_read(string_hash* a3d, stream& s); @@ -70,7 +71,7 @@ pvpp_glitter::~pvpp_glitter() { } -pvpp::pvpp() : ready() { +pvpp::pvpp() : ready(), big_endian() { } @@ -84,12 +85,12 @@ void pvpp::read(const char* path) { char* path_pvpp = str_utils_add(path, ".pvpp"); if (path_check_file_exists(path_pvpp)) { - stream s; + file_stream s; s.open(path_pvpp, "rb"); - if (s.io.stream) + if (s.check_not_null()) pvpp_read_inner(this, s); } - free(path_pvpp); + free_def(path_pvpp); } void pvpp::read(const wchar_t* path) { @@ -98,19 +99,19 @@ void pvpp::read(const wchar_t* path) { wchar_t* path_pvpp = str_utils_add(path, L".pvpp"); if (path_check_file_exists(path_pvpp)) { - stream s; + file_stream s; s.open(path_pvpp, L"rb"); - if (s.io.stream) + if (s.check_not_null()) pvpp_read_inner(this, s); } - free(path_pvpp); + free_def(path_pvpp); } void pvpp::read(const void* data, size_t size) { if (!data || !size) return; - stream s; + memory_stream s; s.open(data, size); pvpp_read_inner(this, s); } @@ -316,12 +317,17 @@ static void pvpp_object_set_read(string_hash* objset, stream& s) { static void pvpp_read_inner(pvpp* pp, stream& s) { f2_struct st; st.read(s); - if (st.header.signature != reverse_endianness_uint32_t('PVPP') || !st.data.data()) + if (st.header.signature != reverse_endianness_uint32_t('PVPP') || !st.data.data()) { + pp->ready = false; + pp->big_endian = false; return; + } - stream s_pvpp; + bool big_endian = st.header.use_big_endian; + + memory_stream s_pvpp; s_pvpp.open(st.data); - s_pvpp.is_big_endian = st.header.use_big_endian; + s_pvpp.big_endian = big_endian; s_pvpp.read_uint32_t_reverse_endianness(); int8_t chara_count = s_pvpp.read_int8_t(); @@ -356,4 +362,5 @@ static void pvpp_read_inner(pvpp* pp, stream& s) { } pp->ready = true; + pp->big_endian = true; } diff --git a/src/KKdLib/pvpp.hpp b/src/KKdLib/pvpp.hpp index 8c83ee73..64ba32e6 100644 --- a/src/KKdLib/pvpp.hpp +++ b/src/KKdLib/pvpp.hpp @@ -108,6 +108,7 @@ struct pvpp_chara { struct pvpp { bool ready; + bool big_endian; std::vector chara; std::vector effect; diff --git a/src/KKdLib/pvsr.cpp b/src/KKdLib/pvsr.cpp index 8bedaacc..8eb61366 100644 --- a/src/KKdLib/pvsr.cpp +++ b/src/KKdLib/pvsr.cpp @@ -5,8 +5,9 @@ #include "pvsr.hpp" #include "f2/struct.hpp" +#include "io/file_stream.hpp" +#include "io/memory_stream.hpp" #include "io/path.hpp" -#include "io/stream.hpp" #include "str_utils.hpp" static void pvsr_auth_3d_read(pvsr_auth_3d* a3d, stream& s); @@ -86,7 +87,7 @@ pvsr_stage_effect_env::~pvsr_stage_effect_env() { } -pvsr::pvsr() : ready() { +pvsr::pvsr() : ready(), big_endian() { } @@ -100,12 +101,12 @@ void pvsr::read(const char* path) { char* path_pvsr = str_utils_add(path, ".pvsr"); if (path_check_file_exists(path_pvsr)) { - stream s; + file_stream s; s.open(path_pvsr, "rb"); - if (s.io.stream) + if (s.check_not_null()) pvsr_read_inner(this, s); } - free(path_pvsr); + free_def(path_pvsr); } void pvsr::read(const wchar_t* path) { @@ -114,19 +115,19 @@ void pvsr::read(const wchar_t* path) { wchar_t* path_pvsr = str_utils_add(path, L".pvsr"); if (path_check_file_exists(path_pvsr)) { - stream s; + file_stream s; s.open(path_pvsr, L"rb"); - if (s.io.stream) + if (s.check_not_null()) pvsr_read_inner(this, s); } - free(path_pvsr); + free_def(path_pvsr); } void pvsr::read(const void* data, size_t size) { if (!data || !size) return; - stream s; + memory_stream s; s.open(data, size); pvsr_read_inner(this, s); } @@ -175,12 +176,17 @@ static void pvsr_glitter_read(pvsr_glitter* glt, stream& s) { static void pvsr_read_inner(pvsr* sr, stream& s) { f2_struct st; st.read(s); - if (st.header.signature != reverse_endianness_uint32_t('PVSR') || !st.data.data()) + if (st.header.signature != reverse_endianness_uint32_t('PVSR') || !st.data.data()) { + sr->ready = false; + sr->big_endian = false; return; + } - stream s_pvsr; + bool big_endian = st.header.use_big_endian; + + memory_stream s_pvsr; s_pvsr.open(st.data); - s_pvsr.is_big_endian = st.header.use_big_endian; + s_pvsr.big_endian = big_endian; int32_t x00 = s_pvsr.read_int32_t_reverse_endianness(); uint8_t x04 = s_pvsr.read_uint8_t(); @@ -273,6 +279,7 @@ static void pvsr_read_inner(pvsr* sr, stream& s) { } sr->ready = true; + sr->big_endian = big_endian; } static void pvsr_stage_change_effect_read(pvsr_stage_change_effect* stg_chg_eff, stream& s) { diff --git a/src/KKdLib/pvsr.hpp b/src/KKdLib/pvsr.hpp index 61756585..34982e52 100644 --- a/src/KKdLib/pvsr.hpp +++ b/src/KKdLib/pvsr.hpp @@ -130,6 +130,7 @@ struct pvsr_stage_effect_env { struct pvsr { bool ready; + bool big_endian; std::vector effect; std::vector emcs; diff --git a/src/KKdLib/quat.cpp b/src/KKdLib/quat.cpp index 8b1c532f..1b37117c 100644 --- a/src/KKdLib/quat.cpp +++ b/src/KKdLib/quat.cpp @@ -16,8 +16,8 @@ inline void quat_mult(const quat* x, const quat* y, quat* z) { __m128 zt2; __m128 zt3; - xt = x->data; - yt = y->data; + xt = _mm_loadu_ps((const float*)x); + yt = _mm_loadu_ps((const float*)y); zt0 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0x1B)); zt1 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0x4E)); zt2 = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0xB1)); @@ -37,45 +37,6 @@ inline void quat_mult(const quat* x, const quat* y, quat* z) { *z = zt; } -void quat_slerp(const quat* x, const quat* y, quat* z, const float_t blend) { - quat x_t; - quat y_t; - quat z_t; - quat zt0; - quat zt1; - vec4_normalize(*x, x_t); - vec4_normalize(*y, y_t); - - float_t dot; - vec4_dot(x_t, y_t, dot); - if (dot < 0.0f) { - vec4_negate(y_t, z_t); - dot = -dot; - } - else - z_t = y_t; - - const float_t DOT_THRESHOLD = 0.9995f; - float_t s0, s1; - if (dot <= DOT_THRESHOLD) { - float_t theta_0 = acosf(dot); - float_t theta = theta_0 * blend; - float_t sin_theta = sinf(theta); - float_t sin_theta_0 = sinf(theta_0); - - s0 = cosf(theta) - dot * sin_theta / sin_theta_0; - s1 = sin_theta / sin_theta_0; - } - else { - s0 = (1.0f - blend); - s1 = blend; - } - vec4_mult_scalar(*x, s0, zt0); - vec4_mult_scalar(z_t, s0, zt1); - vec4_add(zt0, zt1, z_t); - vec4_normalize(z_t, *z); -} - void quat_from_mat3(float_t m00, float_t m01, float_t m02, float_t m10, float_t m11, float_t m12, float_t m20, float_t m21, float_t m22, quat* quat) { float_t sq; @@ -115,13 +76,6 @@ void quat_from_mat3(float_t m00, float_t m01, float_t m02, float_t m10, } inline void quat_from_axis_angle(const vec3* axis, const float_t angle, quat* quat) { - float_t angle_sin; - float_t angle_cos; - vec3 _axis; - - angle_sin = sinf(angle * 0.5f); - angle_cos = cosf(angle * 0.5f); - vec3_normalize(*axis, _axis); - quat->w = angle_cos; - vec3_mult_scalar(_axis, angle_sin, *(vec3*)quat); + *(vec3*)quat = vec3::normalize(*axis) * sinf(angle * 0.5f); + quat->w = cosf(angle * 0.5f); } diff --git a/src/KKdLib/quat.hpp b/src/KKdLib/quat.hpp index 5fc1d3f6..2e110f07 100644 --- a/src/KKdLib/quat.hpp +++ b/src/KKdLib/quat.hpp @@ -8,20 +8,321 @@ #include "default.hpp" #include "vec.hpp" -union quat { - struct { - float_t x; - float_t y; - float_t z; - float_t w; - }; - __m128 data; +struct quat { + float_t x; + float_t y; + float_t z; + float_t w; + + static float_t dot(const quat& left, const quat& right); + static float_t length(const quat& left); + static float_t length_squared(const quat& left); + static float_t distance(const quat& left, const quat& right); + static float_t distance_squared(const quat& left, const quat& right); + static quat slerp(const quat& left, const quat& right, const float_t blend); + static quat normalize(const quat& left); + static quat rcp(const quat& left); + static quat min(const quat& left, const quat& right); + static quat max(const quat& left, const quat& right); + static quat clamp(const quat& left, const quat& min, const quat& max); + static quat clamp(const quat& left, const float_t min, const float_t max); + static quat mult_min_max(const quat& left, const quat& min, const quat& max); + static quat mult_min_max(const quat& left, const float_t min, const float_t max); + static quat div_min_max(const quat& left, const quat& min, const quat& max); + static quat div_min_max(const quat& left, const float_t min, const float_t max); }; static const quat quat_identity = { 0.0f, 0.0f, 0.0f, 1.0f }; +inline quat operator +(const quat& left, const quat& right) { + __m128 yt; + quat z; + *(quat*)&yt = right; + _mm_storeu_ps((float*)&z, _mm_add_ps(_mm_loadu_ps((const float*)&left), yt)); + return z; +} + +inline quat operator +(const quat& left, const float_t right) { + __m128 yt; + quat z; + yt = _mm_set_ss(right); + _mm_storeu_ps((float*)&z, _mm_add_ps(_mm_loadu_ps((const float*)&left), _mm_shuffle_ps(yt, yt, 0))); + return z; +} + +inline quat operator -(const quat& left, const quat& right) { + __m128 yt; + quat z; + *(quat*)&yt = right; + _mm_storeu_ps((float*)&z, _mm_sub_ps(_mm_loadu_ps((const float*)&left), yt)); + return z; +} + +inline quat operator -(const quat& left, const float_t right) { + __m128 yt; + quat z; + yt = _mm_set_ss(right); + _mm_storeu_ps((float*)&z, _mm_sub_ps(_mm_loadu_ps((const float*)&left), _mm_shuffle_ps(yt, yt, 0))); + return z; +} + +inline quat operator *(const quat& left, const quat& right) { + __m128 yt; + quat z; + *(quat*)&yt = right; + _mm_storeu_ps((float*)&z, _mm_mul_ps(_mm_loadu_ps((const float*)&left), yt)); + return z; +} + +inline quat operator *(const quat& left, const float_t right) { + __m128 yt; + quat z; + yt = _mm_set_ss(right); + _mm_storeu_ps((float*)&z, _mm_mul_ps(_mm_loadu_ps((const float*)&left), _mm_shuffle_ps(yt, yt, 0))); + return z; +} + +inline quat operator /(const quat& left, const quat& right) { + __m128 yt; + quat z; + *(quat*)&yt = right; + _mm_storeu_ps((float*)&z, _mm_div_ps(_mm_loadu_ps((const float*)&left), yt)); + return z; +} + +inline quat operator /(const quat& left, const float_t right) { + __m128 yt; + quat z; + yt = _mm_set_ss(right); + _mm_storeu_ps((float*)&z, _mm_div_ps(_mm_loadu_ps((const float*)&left), _mm_shuffle_ps(yt, yt, 0))); + return z; +} + +inline quat operator &(const quat& left, const quat& right) { + __m128 yt; + quat z; + *(quat*)&yt = right; + _mm_storeu_ps((float*)&z, _mm_and_ps(_mm_loadu_ps((const float*)&left), yt)); + return z; +} + +inline quat operator &(const quat& left, const float_t right) { + __m128 yt; + quat z; + yt = _mm_set_ss(right); + _mm_storeu_ps((float*)&z, _mm_and_ps(_mm_loadu_ps((const float*)&left), _mm_shuffle_ps(yt, yt, 0))); + return z; +} + +inline quat operator ^(const quat& left, const quat& right) { + __m128 yt; + quat z; + *(quat*)&yt = right; + _mm_storeu_ps((float*)&z, _mm_xor_ps(_mm_loadu_ps((const float*)&left), yt)); + return z; +} + +inline quat operator ^(const quat& left, const float_t right) { + __m128 yt; + quat z; + yt = _mm_set_ss(right); + _mm_storeu_ps((float*)&z, _mm_xor_ps(_mm_loadu_ps((const float*)&left), _mm_shuffle_ps(yt, yt, 0))); + return z; +} + +inline quat operator -(const quat& left) { + quat z; + _mm_storeu_ps((float*)&z, _mm_xor_ps(_mm_loadu_ps((const float*)&left), vec4_neg)); + return z; +} + +inline float_t quat::dot(const quat& left, const quat& right) { + __m128 zt; + zt = _mm_mul_ps(_mm_loadu_ps((const float*)&(left)), _mm_loadu_ps((const float*)&(right))); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline float_t quat::length(const quat& left) { + __m128 xt; + __m128 zt; + xt = _mm_loadu_ps((const float*)&left); + zt = _mm_mul_ps(xt, xt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); +} + +inline float_t quat::length_squared(const quat& left) { + __m128 xt; + __m128 zt; + xt = _mm_loadu_ps((const float*)&left); + zt = _mm_mul_ps(xt, xt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline float_t quat::distance(const quat& left, const quat& right) { + __m128 zt; + zt = _mm_sub_ps(_mm_loadu_ps((const float*)&(left)), _mm_loadu_ps((const float*)&(right))); + zt = _mm_mul_ps(zt, zt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); +} + +inline float_t quat::distance_squared(const quat& left, const quat& right) { + __m128 zt; + zt = _mm_sub_ps(_mm_loadu_ps((const float*)&(left)), _mm_loadu_ps((const float*)&(right))); + zt = _mm_mul_ps(zt, zt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline quat quat::slerp(const quat& left, const quat& right, const float_t blend) { + quat x_t; + quat y_t; + quat z_t; + x_t = quat::normalize(left); + y_t = quat::normalize(right); + + float_t dot = quat::dot(x_t, y_t); + if (dot < 0.0f) { + z_t = -y_t; + dot = -dot; + } + else + z_t = y_t; + + const float_t DOT_THRESHOLD = 0.9995f; + float_t s0, s1; + if (dot <= DOT_THRESHOLD) { + float_t theta_0 = acosf(dot); + float_t theta = theta_0 * blend; + float_t sin_theta = sinf(theta); + float_t sin_theta_0 = sinf(theta_0); + + s0 = cosf(theta) - dot * sin_theta / sin_theta_0; + s1 = sin_theta / sin_theta_0; + } + else { + s0 = (1.0f - blend); + s1 = blend; + } + return quat::normalize(left * s0 + z_t * s0); +} + +inline quat quat::normalize(const quat& left) { + __m128 xt; + __m128 zt; + quat z; + xt = _mm_loadu_ps((const float*)&left); + 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]; + _mm_storeu_ps((float*)&z, _mm_mul_ps(xt, _mm_shuffle_ps(zt, zt, 0))); + return z; +} + +inline quat quat::rcp(const quat& left) { + quat z; + _mm_storeu_ps((float*)&z, _mm_div_ps(_mm_loadu_ps((const float*)&(quat_identity)), _mm_loadu_ps((const float*)&left))); + return z; +} + +inline quat quat::min(const quat& left, const quat& right) { + quat z; + _mm_storeu_ps((float*)&z, _mm_min_ps(_mm_loadu_ps((const float*)&(left)), _mm_loadu_ps((const float*)&(right)))); + return z; +} + +inline quat quat::max(const quat& left, const quat& right) { + quat z; + _mm_storeu_ps((float*)&z, _mm_max_ps(_mm_loadu_ps((const float*)&(left)), _mm_loadu_ps((const float*)&(right)))); + return z; +} + +inline quat quat::clamp(const quat& left, const quat& min, const quat& max) { + quat w; + _mm_storeu_ps((float*)&w, _mm_min_ps(_mm_max_ps(_mm_loadu_ps((const float*)&left), + _mm_loadu_ps((const float*)&(min))), _mm_loadu_ps((const float*)&(max)))); + return w; +} + +inline quat quat::clamp(const quat& left, const float_t min, const float_t max) { + __m128 yt; + __m128 zt; + quat w; + yt = _mm_set_ss(min); + zt = _mm_set_ss(max); + _mm_storeu_ps((float*)&w, _mm_min_ps(_mm_max_ps(_mm_loadu_ps((const float*)&left), + _mm_shuffle_ps(yt, yt, 0)), _mm_shuffle_ps(zt, zt, 0))); + return w; +} + +inline quat quat::mult_min_max(const quat& left, const quat& min, const quat& max) { + __m128 xt; + __m128 yt; + __m128 wt; + quat w; + xt = _mm_loadu_ps((const float*)&left); + yt = _mm_xor_ps(_mm_loadu_ps((const float*)&(min)), vec4_neg); + wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, _mm_loadu_ps((const float*)&(vec4_null)))), + _mm_and_ps(_mm_loadu_ps((const float*)&(max)), _mm_cmpge_ps(xt, _mm_loadu_ps((const float*)&(vec4_null))))); + _mm_storeu_ps((float*)&w, _mm_mul_ps(xt, wt)); + return w; +} + +inline quat quat::mult_min_max(const quat& left, const float_t min, const float_t max) { + __m128 xt; + __m128 yt; + __m128 zt; + __m128 wt; + quat w; + xt = _mm_loadu_ps((const float*)&left); + yt = _mm_set_ss(min); + yt = _mm_shuffle_ps(yt, yt, 0); + zt = _mm_set_ss(max); + zt = _mm_shuffle_ps(zt, zt, 0); + yt = _mm_xor_ps(yt, vec4_neg); + wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, _mm_loadu_ps((const float*)&(vec4_null)))), + _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((const float*)&(vec4_null))))); + _mm_storeu_ps((float*)&w, _mm_mul_ps(xt, wt)); + return w; +} + +inline quat quat::div_min_max(const quat& left, const quat& min, const quat& max) { + __m128 xt; + __m128 yt; + __m128 wt; + quat w; + xt = _mm_loadu_ps((const float*)&left); + yt = _mm_xor_ps(_mm_loadu_ps((const float*)&(min)), vec4_neg); + wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, _mm_loadu_ps((const float*)&(vec4_null)))), + _mm_and_ps(_mm_loadu_ps((const float*)&(max)), _mm_cmpge_ps(xt, _mm_loadu_ps((const float*)&(vec4_null))))); + _mm_storeu_ps((float*)&w, _mm_div_ps(xt, wt)); + return w; +} + +inline quat quat::div_min_max(const quat& left, const float_t min, const float_t max) { + __m128 xt; + __m128 yt; + __m128 zt; + __m128 wt; + quat w; + xt = _mm_loadu_ps((const float*)&left); + yt = _mm_set_ss(min); + yt = _mm_shuffle_ps(yt, yt, 0); + zt = _mm_set_ss(max); + zt = _mm_shuffle_ps(zt, zt, 0); + yt = _mm_xor_ps(yt, vec4_neg); + wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, _mm_loadu_ps((const float*)&(vec4_null)))), + _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((const float*)&(vec4_null))))); + _mm_storeu_ps((float*)&w, _mm_div_ps(xt, wt)); + return w; +} + extern void quat_mult(const quat* x, const quat* y, quat* z); -extern void quat_slerp(const quat* x, const quat* y, quat* z, const float_t blend); extern void quat_from_mat3(float_t m00, float_t m01, float_t m02, float_t m10, float_t m11, float_t m12, float_t m20, float_t m21, float_t m22, quat* quat); extern void quat_from_axis_angle(const vec3* axis, const float_t angle, quat* quat); diff --git a/src/KKdLib/quat_trans.cpp b/src/KKdLib/quat_trans.cpp index 80227df4..8953f521 100644 --- a/src/KKdLib/quat_trans.cpp +++ b/src/KKdLib/quat_trans.cpp @@ -11,7 +11,7 @@ void lerp_quat_trans(quat_trans* x, quat_trans* y, quat_trans* z, float_t blend) else if (blend < 0.0f) blend = 0.0f; - quat_slerp(&x->quat, &y->quat, &z->quat, blend); - vec3_lerp_scalar(x->trans, y->trans, z->trans, blend); - z->time = lerp(x->time, y->time, blend); + z->quat = quat::slerp(x->quat, y->quat, blend); + z->trans = vec3::lerp(x->trans, y->trans, blend); + z->time = lerp_def(x->time, y->time, blend); } diff --git a/src/KKdLib/sort.cpp b/src/KKdLib/sort.cpp index fb825313..170b30f6 100644 --- a/src/KKdLib/sort.cpp +++ b/src/KKdLib/sort.cpp @@ -26,8 +26,9 @@ static int quicksort_char_ptr_compare(void const* src1, void const* src2); static int quicksort_wchar_t_ptr_compare(void const* src1, void const* src2); static int quicksort_std_string_compare(void const* src1, void const* src2); static int quicksort_std_wstring_compare(void const* src1, void const* src2); +static int quicksort_string_hash_compare(void const* src1, void const* src2); -inline void radix_sort_int8_t(int8_t* arr, size_t n) { +void radix_sort_int8_t(int8_t* arr, size_t n) { if (n <= 1) return; @@ -71,10 +72,10 @@ void radix_sort_uint8_t(uint8_t* arr, size_t n) { memmove(arr, o, sizeof(uint8_t) * n); } - free(o); + free_def(o); } -inline void radix_sort_int16_t(int16_t* arr, size_t n) { +void radix_sort_int16_t(int16_t* arr, size_t n) { if (n <= 1) return; @@ -118,10 +119,10 @@ void radix_sort_uint16_t(uint16_t* arr, size_t n) { memmove(arr, o, sizeof(uint16_t) * n); } - free(o); + free_def(o); } -inline void radix_sort_int32_t(int32_t* arr, size_t n) { +void radix_sort_int32_t(int32_t* arr, size_t n) { if (n <= 1) return; @@ -165,10 +166,10 @@ void radix_sort_uint32_t(uint32_t* arr, size_t n) { memmove(arr, o, sizeof(uint32_t) * n); } - free(o); + free_def(o); } -inline void radix_sort_int64_t(int64_t* arr, size_t n) { +void radix_sort_int64_t(int64_t* arr, size_t n) { if (n <= 1) return; @@ -212,10 +213,10 @@ void radix_sort_uint64_t(uint64_t* arr, size_t n) { memmove(arr, o, sizeof(uint64_t) * n); } - free(o); + free_def(o); } -inline void radix_sort_ssize_t(ssize_t* arr, size_t n) { +void radix_sort_ssize_t(ssize_t* arr, size_t n) { if (n <= 1) return; @@ -259,7 +260,7 @@ void radix_sort_size_t(size_t* arr, size_t n) { memmove(arr, o, sizeof(size_t) * n); } - free(o); + free_def(o); } void radix_sort_custom(void* arr, size_t n, size_t size, size_t idx_len, radix_index_func idx_func) { @@ -298,46 +299,46 @@ void radix_sort_custom(void* arr, size_t n, size_t size, size_t idx_len, radix_i memmove(a, o, size * n); } - free(o); + free_def(o); } -inline void quicksort_int8_t(int8_t* arr, size_t n) { +void quicksort_int8_t(int8_t* arr, size_t n) { qsort(arr, n, sizeof(int8_t), quicksort_int8_t_compare); } -inline void quicksort_uint8_t(uint8_t* arr, size_t n) { +void quicksort_uint8_t(uint8_t* arr, size_t n) { qsort(arr, n, sizeof(uint8_t), quicksort_uint8_t_compare); } -inline void quicksort_int16_t(int16_t* arr, size_t n) { +void quicksort_int16_t(int16_t* arr, size_t n) { qsort(arr, n, sizeof(int16_t), quicksort_int16_t_compare); } -inline void quicksort_uint16_t(uint16_t* arr, size_t n) { +void quicksort_uint16_t(uint16_t* arr, size_t n) { qsort(arr, n, sizeof(uint16_t), quicksort_uint16_t_compare); } -inline void quicksort_int32_t(int32_t* arr, size_t n) { +void quicksort_int32_t(int32_t* arr, size_t n) { qsort(arr, n, sizeof(int32_t), quicksort_int32_t_compare); } -inline void quicksort_uint32_t(uint32_t* arr, size_t n) { +void quicksort_uint32_t(uint32_t* arr, size_t n) { qsort(arr, n, sizeof(uint32_t), quicksort_uint32_t_compare); } -inline void quicksort_int64_t(int64_t* arr, size_t n) { +void quicksort_int64_t(int64_t* arr, size_t n) { qsort(arr, n, sizeof(int64_t), quicksort_int64_t_compare); } -inline void quicksort_uint64_t(uint64_t* arr, size_t n) { +void quicksort_uint64_t(uint64_t* arr, size_t n) { qsort(arr, n, sizeof(uint64_t), quicksort_uint64_t_compare); } -inline void quicksort_ssize_t(ssize_t* arr, size_t n) { +void quicksort_ssize_t(ssize_t* arr, size_t n) { qsort(arr, n, sizeof(ssize_t), quicksort_ssize_t_compare); } -inline void quicksort_size_t(size_t* arr, size_t n) { +void quicksort_size_t(size_t* arr, size_t n) { qsort(arr, n, sizeof(size_t), quicksort_size_t_compare); } @@ -349,15 +350,19 @@ void quicksort_wchar_t_ptr(wchar_t** arr, size_t n) { qsort(arr, n, sizeof(wchar_t*), quicksort_wchar_t_ptr_compare); } -inline void quicksort_string(std::string* arr, size_t n) { +void quicksort_string(std::string* arr, size_t n) { qsort(arr, n, sizeof(std::string), quicksort_std_string_compare); } -inline void quicksort_wstring(std::wstring* arr, size_t n) { +void quicksort_wstring(std::wstring* arr, size_t n) { qsort(arr, n, sizeof(std::wstring), quicksort_std_wstring_compare); } -inline void quicksort_custom(void* arr, size_t n, size_t s, quicksort_compare_func comp_finc) { +void quicksort_string_hash(string_hash* arr, size_t n) { + qsort(arr, n, sizeof(string_hash), quicksort_string_hash_compare); +} + +void quicksort_custom(void* arr, size_t n, size_t s, quicksort_compare_func comp_finc) { qsort(arr, n, s, comp_finc); } @@ -436,11 +441,17 @@ static int quicksort_wchar_t_ptr_compare(void const* src1, void const* src2) { static int quicksort_std_string_compare(void const* src1, void const* src2) { std::string* str1 = (std::string*)src1; std::string* str2 = (std::string*)src2; - return str_utils_compare_length(str1->c_str(), str1->size(), str2->c_str(), str2->size()); + return str_utils_compare(str1->c_str(), str2->c_str()); } static int quicksort_std_wstring_compare(void const* src1, void const* src2) { std::wstring* str1 = (std::wstring*)src1; std::wstring* str2 = (std::wstring*)src2; - return str_utils_compare_length(str1->c_str(), str1->size(), str2->c_str(), str2->size()); + return str_utils_compare(str1->c_str(), str2->c_str()); +} + +static int quicksort_string_hash_compare(void const* src1, void const* src2) { + string_hash* str1 = (string_hash*)src1; + string_hash* str2 = (string_hash*)src2; + return str_utils_compare(str1->c_str(), str2->c_str()); } diff --git a/src/KKdLib/sort.hpp b/src/KKdLib/sort.hpp index c4fb73d9..422ac707 100644 --- a/src/KKdLib/sort.hpp +++ b/src/KKdLib/sort.hpp @@ -9,6 +9,7 @@ #include #include "default.hpp" +#include "hash.hpp" typedef size_t(*radix_index_func)(void* data, size_t index); typedef int(*quicksort_compare_func)(void const* src1, void const* src2); @@ -77,4 +78,5 @@ extern void quicksort_char_ptr(char** arr, size_t n); extern void quicksort_wchar_t_ptr(wchar_t** arr, size_t n); extern void quicksort_string(std::string* arr, size_t n); extern void quicksort_wstring(std::wstring* arr, size_t n); +extern void quicksort_string_hash(string_hash* arr, size_t n); extern void quicksort_custom(void* arr, size_t n, size_t s, quicksort_compare_func comp_finc); diff --git a/src/KKdLib/sound/diva.cpp b/src/KKdLib/sound/diva.cpp index 4d600a6b..945e92ad 100644 --- a/src/KKdLib/sound/diva.cpp +++ b/src/KKdLib/sound/diva.cpp @@ -5,7 +5,8 @@ #include "diva.hpp" #include "wav.hpp" -#include "../io/stream.hpp" +#include "../io/file_stream.hpp" +#include "../io/path.hpp" #include "../str_utils.hpp" struct ima_storage { @@ -16,6 +17,7 @@ struct ima_storage { static const int8_t ima_index_table[] = { -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8, }; static const int16_t ima_step_table[] = { @@ -33,196 +35,235 @@ static const int16_t ima_step_table[] = { 32767 }; -static void diva_read_wav(diva* d, const wchar_t* path, float_t** data); +static bool diva_read_inner(diva* d, stream& s, float_t*& data); +static void diva_write_inner(diva* d, stream& s, float_t* data); +static void diva_read_wav(diva* d, const wchar_t* path, float_t*& data); static void diva_write_wav(diva* d, const wchar_t* path, float_t* data); static void ima_decode(uint8_t value, ima_storage* storage); static uint8_t ima_encode(int32_t sample, ima_storage* storage); -diva* diva_init() { - diva* d = force_malloc_s(diva, 1); - return d; +diva::diva() : size(), sample_rate(), samples_count(), loop_start(), loop_end(), channels() { + } -void diva_read(diva* d, const char* path) { - wchar_t* path_buf = utf8_to_utf16(path); - diva_read(d, path_buf); - free(path_buf); +diva::~diva() { + } -void diva_read(diva* d, const wchar_t* path) { - wchar_t* path_diva = str_utils_add(path, L".diva"); - stream s; - s.open(path_diva, L"rb"); - if (s.io.stream) { - uint32_t signature = s.read_uint32_t_reverse_endianness(true); - if (signature != 'DIVA') - goto End; +void diva::read(const char* path) { + if (!path) + return; - s.read_uint32_t(); - d->size = s.read_uint32_t(); - d->sample_rate = s.read_uint32_t(); - d->samples_count = s.read_uint32_t(); - d->loop_start = s.read_uint32_t(); - d->loop_end = s.read_uint32_t(); - d->channels = s.read_uint32_t(); - s.set_position(s.get_position() + 0x20, SEEK_SET); - - uint8_t nibble = 0; - uint8_t value = 0; - size_t current_sample = 0; - size_t ch = d->channels; - size_t samples_count = d->samples_count; - - float_t* data = force_malloc_s(float_t, samples_count * ch); - ima_storage* storage = force_malloc_s(ima_storage, ch); - - float_t* temp_data = data; - for (size_t i = 0; i < samples_count; i++) - for (size_t c = 0; c < ch; c++, current_sample++) { - if (~current_sample & 0x01) - value = s.read_uint8_t(); - - nibble = (current_sample & 1 ? value : value >> 4) & 0x0F; - ima_decode(nibble, &storage[c]); - *temp_data++ = (float_t)(storage[c].current / 32768.0); - } - free(storage); - - diva_write_wav(d, path, data); - free(data); + char* path_diva = str_utils_add(path, ".diva"); + file_stream s; + s.open(path_diva, "rb"); + if (s.check_not_null()) { + float_t* data = 0; + if (diva_read_inner(this, s, data)) { + wchar_t* path_temp = utf8_to_utf16(path); + diva_write_wav(this, path_temp, data); + free_def(path_temp); + free_def(data); + } } -End: - free(path_diva); + free_def(path_diva); } -void diva_write(diva* d, const char* path) { - wchar_t* path_buf = utf8_to_utf16(path); - diva_write(d, path_buf); - free(path_buf); +void diva::read(const wchar_t* path) { + if (!path) + return; + + wchar_t* path_diva = str_utils_add(path, L".diva"); + file_stream s; + s.open(path_diva, L"rb"); + if (s.check_not_null()) { + float_t* data = 0; + if (diva_read_inner(this, s, data)) { + diva_write_wav(this, path, data); + free_def(data); + } + } + free_def(path_diva); } -void diva_write(diva* d, const wchar_t* path) { - float_t* data; +void diva::write(const char* path) { + if (!path) + return; - diva_read_wav(d, path, &data); + wchar_t* path_temp = utf8_to_utf16(path); + float_t* data = 0; + diva_read_wav(this, path_temp, data); + if (!data) { + free_def(path_temp); + return; + } + + char* path_diva = str_utils_add(path, ".diva"); + file_stream s; + s.open(path_diva, "wb"); + if (s.check_not_null()) + diva_write_inner(this, s, data); + free_def(path_diva); + free_def(data); + free_def(path_temp); +} + +void diva::write(const wchar_t* path) { + if (!path) + return; + + float_t* data = 0; + diva_read_wav(this, path, data); if (!data) return; wchar_t* path_diva = str_utils_add(path, L".diva"); - stream s; + file_stream s; s.open(path_diva, L"wb"); - if (s.io.stream) { - s.write_uint32_t_reverse_endianness('DIVA', true); - s.write_uint32_t(0); - s.write_uint32_t(align_val_divide(d->samples_count * d->channels, 2, 2)); - s.write_uint32_t(d->sample_rate); - s.write_uint32_t(d->samples_count); - s.write_uint32_t(0); - s.write_uint32_t(0); - s.write_uint32_t(d->channels); - s.write_uint64_t(0); - s.write_uint64_t(0); - s.write_uint64_t(0); - s.write_uint64_t(0); - - uint8_t nibble = 0; - uint8_t value = 0; - size_t current_sample = 0; - size_t ch = d->channels; - size_t samples_count = d->samples_count; - - ima_storage* storage = force_malloc_s(ima_storage, ch); - - float_t* temp_data = data; - for (size_t i = 0; i < samples_count; i++) - for (size_t c = 0; c < ch; c++, current_sample++) { - nibble = ima_encode((int32_t)round(*temp_data++ * 32768.0), &storage[c]); - value |= current_sample & 1 ? nibble : nibble << 4; - if (current_sample & 1) { - s.write_uint8_t(value); - value = 0; - } - } - - if (current_sample & 1) - s.write_uint8_t(value); - free(storage); - } - free(path_diva); - free(data); + if (s.check_not_null()) + diva_write_inner(this, s, data); + free_def(path_diva); + free_def(data); } void diva_dispose(diva* d) { - free(d); + free_def(d); } -static void diva_read_wav(diva* d, const wchar_t* path, float_t** data) { - *data = 0; +static bool diva_read_inner(diva* d, stream& s, float_t*& data) { + uint32_t signature = s.read_uint32_t_reverse_endianness(true); + if (signature != 'DIVA') + return false; + + s.read_uint32_t(); + d->size = s.read_uint32_t(); + d->sample_rate = s.read_uint32_t(); + d->samples_count = s.read_uint32_t(); + d->loop_start = s.read_uint32_t(); + d->loop_end = s.read_uint32_t(); + d->channels = s.read_uint32_t(); + s.set_position(s.get_position() + 0x20, SEEK_SET); + + uint8_t nibble = 0; + uint8_t value = 0; + size_t current_sample = 0; + size_t ch = d->channels; + size_t samples_count = d->samples_count; + + data = force_malloc_s(float_t, samples_count * ch); + ima_storage* storage = force_malloc_s(ima_storage, ch); + + float_t* temp_data = data; + for (size_t i = 0; i < samples_count; i++) + for (size_t c = 0; c < ch; c++, current_sample++) { + if (~current_sample & 0x01) + value = s.read_uint8_t(); + + nibble = (current_sample & 1 ? value : value >> 4) & 0x0F; + ima_decode(nibble, &storage[c]); + *temp_data++ = (float_t)(storage[c].current / 32768.0); + } + free_def(storage); + return true; +} + +static void diva_write_inner(diva* d, stream& s, float_t* data) { + s.write_uint32_t_reverse_endianness('DIVA', true); + s.write_uint32_t(0); + s.write_uint32_t(align_val_divide(d->samples_count * d->channels, 2, 2)); + s.write_uint32_t(d->sample_rate); + s.write_uint32_t(d->samples_count); + s.write_uint32_t(0); + s.write_uint32_t(0); + s.write_uint32_t(d->channels); + s.write_uint64_t(0); + s.write_uint64_t(0); + s.write_uint64_t(0); + s.write_uint64_t(0); + + uint8_t nibble = 0; + uint8_t value = 0; + size_t current_sample = 0; + size_t ch = d->channels; + size_t samples_count = d->samples_count; + + ima_storage* storage = force_malloc_s(ima_storage, ch); + + float_t* temp_data = data; + for (size_t i = 0; i < samples_count; i++) + for (size_t c = 0; c < ch; c++, current_sample++) { + nibble = ima_encode((int32_t)round(*temp_data++ * 32768.0), &storage[c]); + value |= current_sample & 1 ? nibble : nibble << 4; + if (current_sample & 1) { + s.write_uint8_t(value); + value = 0; + } + } + + if (current_sample & 1) + s.write_uint8_t(value); + free_def(storage); +} + +static void diva_read_wav(diva* d, const wchar_t* path, float_t*& data) { + data = 0; size_t samples = 0; wchar_t* path_av = str_utils_add(path, L".wav"); - wav* w = wav_init(); - wav_read(w, path_av, data, &samples); - d->channels = w->channels; - d->sample_rate = w->sample_rate; + wav w; + w.read(path_av, data, samples); + d->channels = w.channels; + d->sample_rate = w.sample_rate; d->samples_count = (uint32_t)samples; - wav_dispose(w); - free(path_av); + free_def(path_av); } static void diva_write_wav(diva* d, const wchar_t* path, float_t* data) { wchar_t* path_av = str_utils_add(path, L".wav"); - wav* w = wav_init(); - w->bytes = 4; - w->channels = d->channels; - w->format = 0x03; - w->sample_rate = d->sample_rate; - wav_write(w, path_av, data, d->samples_count); - wav_dispose(w); - free(path_av); + wav w; + w.bytes = 4; + w.channels = d->channels; + w.format = 0x03; + w.sample_rate = d->sample_rate; + w.write(path_av, data, d->samples_count); + free_def(path_av); } static void ima_decode(uint8_t value, ima_storage* storage) { - int32_t c = storage->current; - int32_t cc = storage->current_clamp; - int32_t si = storage->step_index; - int16_t step = ima_step_table[si]; + int32_t current = storage->current; + int32_t current_clamp = storage->current_clamp; + int32_t step_index = storage->step_index; + int16_t step = ima_step_table[step_index]; int32_t diff = step >> 3; - if ((value & 1) == 1) diff += step >> 2; - if ((value & 2) == 2) diff += step >> 1; - if ((value & 4) == 4) diff += step; + if (value & 1) + diff += step >> 2; + if (value & 2) + diff += step >> 1; + if (value & 4) + diff += step; + if ((value & 8) == 8) + diff = -diff; - if ((value & 8) == 8) { - cc -= diff; - c = cc; - if (cc < -0x8000) - cc = -0x8000; - } - else { - cc += diff; - c = cc; - if (cc > 0x7FFF) - cc = 0x7FFF; - } + current_clamp += diff; + current = current_clamp; + current_clamp = clamp_def(current_clamp, -0x8000, 0x7FFF); - si += ima_index_table[value & 0x07]; - if (si < 0) - si = 0; - if (si > 88) - si = 88; - storage->current = c; - storage->current_clamp = cc; - storage->step_index = si; + step_index += ima_index_table[value]; + step_index = clamp_def(step_index, 0, 88); + + storage->current = current; + storage->current_clamp = current_clamp; + storage->step_index = step_index; } static uint8_t ima_encode(int32_t sample, ima_storage* storage) { - int32_t c = storage->current; - int32_t cc = storage->current_clamp; - int32_t si = storage->step_index; + int32_t current = storage->current; + int32_t current_clamp = storage->current_clamp; + int32_t step_index = storage->step_index; uint8_t value = 0; - int16_t step = ima_step_table[si]; + int16_t step = ima_step_table[step_index]; - int32_t delta = sample - c; + int32_t delta = sample - current; if (delta < 0) { value |= 8; @@ -249,26 +290,18 @@ static uint8_t ima_encode(int32_t sample, ima_storage* storage) { diff += step; } - if ((value & 8) == 8) { - cc -= diff; - c = cc; - if (cc < -0x8000) - cc = -0x8000; - } - else { - cc += diff; - c = cc; - if (cc > 0x7FFF) - cc = 0x7FFF; - } + if ((value & 8) == 8) + diff = -diff; - si += ima_index_table[value & 0x07]; - if (si < 0) - si = 0; - if (si > 88) - si = 88; - storage->current = c; - storage->current_clamp = cc; - storage->step_index = si; + current_clamp += diff; + current = current_clamp; + current_clamp = clamp_def(current_clamp, -0x8000, 0x7FFF); + + step_index += ima_index_table[value]; + step_index = clamp_def(step_index, 0, 88); + + storage->current = current; + storage->current_clamp = current_clamp; + storage->step_index = step_index; return value; } diff --git a/src/KKdLib/sound/diva.hpp b/src/KKdLib/sound/diva.hpp index 9c0c0914..af4ec496 100644 --- a/src/KKdLib/sound/diva.hpp +++ b/src/KKdLib/sound/diva.hpp @@ -14,11 +14,12 @@ struct diva { uint32_t loop_start; uint32_t loop_end; uint32_t channels; -}; -extern diva* diva_init(); -extern void diva_read(diva* d, const char* path); -extern void diva_read(diva* d, const wchar_t* path); -extern void diva_write(diva* d, const char* path); -extern void diva_write(diva* d, const wchar_t* path); -extern void diva_dispose(diva* d); + diva(); + virtual ~diva(); + + void read(const char* path); + void read(const wchar_t* path); + void write(const char* path); + void write(const wchar_t* path); +}; diff --git a/src/KKdLib/sound/vag.cpp b/src/KKdLib/sound/vag.cpp index e220cf70..e60ea372 100644 --- a/src/KKdLib/sound/vag.cpp +++ b/src/KKdLib/sound/vag.cpp @@ -5,96 +5,154 @@ #include "vag.hpp" #include "wav.hpp" +#include "../io/file_stream.hpp" #include "../io/path.hpp" -#include "../io/stream.hpp" #include "../str_utils.hpp" +#include static const int8_t shift_factor_table[] = { 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1 }; -static const int16_t hevag1_table[] = { - 0, 7680, 14720, 12544, 15616, 14731, 14507, 13920, - 13133, 12028, 10764, 9359, 7832, 6201, 4488, 2717, - 910, -910, -2717, -4488, -6201, -7832, -9359, -10764, - -12028, -13133, -13920, -14507, -14731, 5376, -6400, -10496, - -167, -7430, -8001, 6018, 3798, -8237, 9199, 13021, - 13112, -1668, 7819, 9571, 10032, -4745, -5896, -1193, - 2783, -7334, 6127, 9457, 7876, -7172, -7358, -9170, - -2638, 1873, 9214, 13204, 12437, -2653, 9331, 1642, - 4246, -8988, -2562, 3182, 7937, 10069, 8400, -8529, - 9477, 75, -9143, -7270, -2740, 8993, 13101, 9543, - 5272, -7696, 7309, 10275, 10940, 24, -8122, -8511, - 326, 8895, 12073, 8729, 12950, 10038, 9385, -4720, - 7869, 2450, 10192, 11313, 10154, 9638, 3854, 6699, - 11082, -1026, 10396, 10287, 7953, 12689, 6641, -2348, - 9290, 4633, 11247, 9807, 9736, 8440, 9307, 1698, - 10214, 8390, 7201, -88, 6193, 12325, 13064, 5333, -}; - -static const int16_t hevag2_table[] = { - 0, 0, -6656, -7040, -7680, -7059, -7366, -7522, - -7680, -7680, -7680, -7680, -7680, -7680, -7680, -7680, - -7680, -7680, -7680, -7680, -7680, -7680, -7680, -7680, - -7680, -7680, -7522, -7366, -7059, -9216, -7168, -7424, - -2722, -2221, -3166, -4750, -6946, -2596, 1982, -3044, - -4487, -3744, -4328, -1336, -2562, -4122, 2378, -9117, - -7108, -2062, -2577, -1858, -4483, -1795, -2102, -3509, - -2647, 9183, 1859, -3012, -4792, -1144, -1048, -620, - -7585, -3891, -2735, -483, -3844, -2609, -3297, -2775, - -1882, -2241, -4160, -1958, 3745, 1948, -2835, -1961, - -4270, -3383, 2523, -2867, -3721, -310, -2411, -3067, - -3846, 2194, -1876, -3423, -3847, -2570, -2757, -5006, - -4326, -8597, -2763, -4213, -2716, -1417, -4554, -5659, - -3908, -9810, -3746, 988, 3878, -3375, 3166, -7354, - -4039, -6403, -4125, -2284, -1536, -3436, -1021, -9025, - -2791, 3248, 3316, -7809, -5189, -1290, -4075, 2999, -}; - -static const int16_t hevag3_table[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3328, -3328, -3584, - -494, -2298, -2814, 2649, 3875, -2071, -1382, -3792, - -2250, -6456, 2111, -757, 300, -5486, -4787, -1237, - -1575, -2212, -315, 102, 2126, -2069, -2233, -2674, - -1929, 1860, -1124, -4139, -256, -3182, -828, -946, - -533, -2807, -1730, -714, 2821, 314, 1551, -2432, - 108, -298, -2963, -2156, 5936, -683, -3854, 130, - 3124, -2907, 434, 391, 665, -1262, -2311, -2337, - 419, -541, -2017, 1674, -3007, 302, 1008, -2852, - 2135, 1299, 360, 833, 345, -737, 2843, 2249, - 728, -805, 1367, -1915, -764, -3354, 231, -1944, - 1885, 1748, 802, 219, -706, 1562, -835, 688, - 368, -758, 46, -538, 2760, -3284, -2824, 775, -}; - -static const int16_t hevag4_table[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, -3072, -2304, -1024, - -541, 424, 289, -1298, -1216, 227, -2316, 1267, - 1665, 840, -506, 487, 199, -1493, -6947, -3114, - -1447, 446, -18, 258, -538, 482, 440, -391, - -1637, -5746, -2427, 1370, 622, -6878, 507, -4229, - -2259, 44, -1899, -1421, -1019, 195, -155, -336, - 256, -6937, 5, 460, -1089, -2704, 1055, 250, - -3157, -456, -2461, 172, 97, 320, -271, 163, - -933, -2880, -601, -169, 1946, 198, 41, -1161, - -501, -2780, 181, 53, 185, 482, -3397, -1074, - 80, -3462, -96, -1437, -3263, 2079, -2089, -4122, - -246, -1619, 61, 222, 473, -176, 509, -3037, - 179, -2989, -2614, -4571, -1245, 253, 1877, -1132, +static const int16_t hevag_table[128][4] = { + { 0, 0, 0, 0 }, + { 7680, 0, 0, 0 }, + { 14720, -6656, 0, 0 }, + { 12544, -7040, 0, 0 }, + { 15616, -7680, 0, 0 }, + { 14731, -7059, 0, 0 }, + { 14507, -7366, 0, 0 }, + { 13920, -7522, 0, 0 }, + { 13133, -7680, 0, 0 }, + { 12028, -7680, 0, 0 }, + { 10764, -7680, 0, 0 }, + { 9359, -7680, 0, 0 }, + { 7832, -7680, 0, 0 }, + { 6201, -7680, 0, 0 }, + { 4488, -7680, 0, 0 }, + { 2717, -7680, 0, 0 }, + { 910, -7680, 0, 0 }, + { -910, -7680, 0, 0 }, + { -2717, -7680, 0, 0 }, + { -4488, -7680, 0, 0 }, + { -6201, -7680, 0, 0 }, + { -7832, -7680, 0, 0 }, + { -9359, -7680, 0, 0 }, + { -10764, -7680, 0, 0 }, + { -12028, -7680, 0, 0 }, + { -13133, -7680, 0, 0 }, + { -13920, -7522, 0, 0 }, + { -14507, -7366, 0, 0 }, + { -14731, -7059, 0, 0 }, + { 5376, -9216, 3328, -3072 }, + { -6400, -7168, -3328, -2304 }, + { -10496, -7424, -3584, -1024 }, + { -167, -2722, -494, -541 }, + { -7430, -2221, -2298, 424 }, + { -8001, -3166, -2814, 289 }, + { 6018, -4750, 2649, -1298 }, + { 3798, -6946, 3875, -1216 }, + { -8237, -2596, -2071, 227 }, + { 9199, 1982, -1382, -2316 }, + { 13021, -3044, -3792, 1267 }, + { 13112, -4487, -2250, 1665 }, + { -1668, -3744, -6456, 840 }, + { 7819, -4328, 2111, -506 }, + { 9571, -1336, -757, 487 }, + { 10032, -2562, 300, 199 }, + { -4745, -4122, -5486, -1493 }, + { -5896, 2378, -4787, -6947 }, + { -1193, -9117, -1237, -3114 }, + { 2783, -7108, -1575, -1447 }, + { -7334, -2062, -2212, 446 }, + { 6127, -2577, -315, -18 }, + { 9457, -1858, 102, 258 }, + { 7876, -4483, 2126, -538 }, + { -7172, -1795, -2069, 482 }, + { -7358, -2102, -2233, 440 }, + { -9170, -3509, -2674, -391 }, + { -2638, -2647, -1929, -1637 }, + { 1873, 9183, 1860, -5746 }, + { 9214, 1859, -1124, -2427 }, + { 13204, -3012, -4139, 1370 }, + { 12437, -4792, -256, 622 }, + { -2653, -1144, -3182, -6878 }, + { 9331, -1048, -828, 507 }, + { 1642, -620, -946, -4229 }, + { 4246, -7585, -533, -2259 }, + { -8988, -3891, -2807, 44 }, + { -2562, -2735, -1730, -1899 }, + { 3182, -483, -714, -1421 }, + { 7937, -3844, 2821, -1019 }, + { 10069, -2609, 314, 195 }, + { 8400, -3297, 1551, -155 }, + { -8529, -2775, -2432, -336 }, + { 9477, -1882, 108, 256 }, + { 75, -2241, -298, -6937 }, + { -9143, -4160, -2963, 5 }, + { -7270, -1958, -2156, 460 }, + { -2740, 3745, 5936, -1089 }, + { 8993, 1948, -683, -2704 }, + { 13101, -2835, -3854, 1055 }, + { 9543, -1961, 130, 250 }, + { 5272, -4270, 3124, -3157 }, + { -7696, -3383, -2907, -456 }, + { 7309, 2523, 434, -2461 }, + { 10275, -2867, 391, 172 }, + { 10940, -3721, 665, 97 }, + { 24, -310, -1262, 320 }, + { -8122, -2411, -2311, -271 }, + { -8511, -3067, -2337, 163 }, + { 326, -3846, 419, -933 }, + { 8895, 2194, -541, -2880 }, + { 12073, -1876, -2017, -601 }, + { 8729, -3423, 1674, -169 }, + { 12950, -3847, -3007, 1946 }, + { 10038, -2570, 302, 198 }, + { 9385, -2757, 1008, 41 }, + { -4720, -5006, -2852, -1161 }, + { 7869, -4326, 2135, -501 }, + { 2450, -8597, 1299, -2780 }, + { 10192, -2763, 360, 181 }, + { 11313, -4213, 833, 53 }, + { 10154, -2716, 345, 185 }, + { 9638, -1417, -737, 482 }, + { 3854, -4554, 2843, -3397 }, + { 6699, -5659, 2249, -1074 }, + { 11082, -3908, 728, 80 }, + { -1026, -9810, -805, -3462 }, + { 10396, -3746, 1367, -96 }, + { 10287, 988, -1915, -1437 }, + { 7953, 3878, -764, -3263 }, + { 12689, -3375, -3354, 2079 }, + { 6641, 3166, 231, -2089 }, + { -2348, -7354, -1944, -4122 }, + { 9290, -4039, 1885, -246 }, + { 4633, -6403, 1748, -1619 }, + { 11247, -4125, 802, 61 }, + { 9807, -2284, 219, 222 }, + { 9736, -1536, -706, 473 }, + { 8440, -3436, 1562, -176 }, + { 9307, -1021, -835, 509 }, + { 1698, -9025, 688, -3037 }, + { 10214, -2791, 368, 179 }, + { 8390, 3248, -758, -2989 }, + { 7201, 3316, 46, -2614 }, + { -88, -7809, -538, -4571 }, + { 6193, -5189, 2760, -1245 }, + { 12325, -1290, -3284, 253 }, + { 13064, -4075, -2824, 1877 }, + { 5333, 2999, 775, -1132 }, }; #define BLOCK_SIZE 28 -static void vag_read_wav_straight(vag* v, const wchar_t* path, float_t** data, size_t* samples); -static void vag_read_wav(vag* v, const wchar_t* path, float_t** data, size_t* samples, uint8_t** flags); -static void vag_write_wav_straight(vag* v, const wchar_t* path, float_t* data, size_t num_blocks, uint8_t* flags); -static void vag_write_wav(vag* v, const wchar_t* path, float_t* data, size_t num_blocks, uint8_t* flags); +static bool vag_read_inner(vag* v, stream& s, float_t*& data, size_t& num_blocks, uint8_t*& flags); +static void vag_write_inner(vag* v, stream& s, const float_t* data, const uint8_t* flags, vag_option option); +static void vag_read_wav_straight(vag* v, const wchar_t* path, float_t*& data, size_t& samples); +static void vag_read_wav(vag* v, const wchar_t* path, float_t*& data, size_t& samples, uint8_t*& flags); +static void vag_write_wav_straight(vag* v, const wchar_t* path, const float_t* data, size_t num_blocks, const uint8_t* flags); +static void vag_write_wav(vag* v, const wchar_t* path, const float_t* data, size_t num_blocks, const uint8_t* flags); static void calculate_4_bits_vag(int32_t* data, int8_t* four_bit, int32_t* coef_index, int32_t* shift_factor, int32_t* v, int32_t* tv, int32_t coef_index_count); static void calculate_4_bits_hevag(int32_t* data, int8_t* four_bit, int32_t* coef_index, @@ -104,297 +162,335 @@ static void calculate_4_bits_vag_inner(int32_t* data, int8_t* four_bit, int32_t static void calculate_4_bits_hevag_inner(int32_t* data, int8_t* four_bit, int32_t coef_index, int32_t* shift_factor, int32_t* v, int32_t* tv, int32_t* os, int32_t* ots); -vag* vag_init() { - vag* v = force_malloc_s(vag, 1); - return v; +vag::vag() : version(), sample_rate(), channels(), size() { + } -void vag_read(vag* v, const char* path) { - wchar_t* path_buf = utf8_to_utf16(path); - vag_read(v, path_buf); - free(path_buf); +vag::~vag() { + } -void vag_read(vag* v, const wchar_t* path) { - wchar_t* path_vag = str_utils_add(path, L".vag"); - stream s; - s.open(path_vag, L"rb"); - if (s.io.stream) { - uint32_t signature = s.read_uint32_t_reverse_endianness(true); - if (signature != 'VAGp') - goto End; - - v->version = s.read_uint32_t_reverse_endianness(true); - s.read_uint32_t(); - v->size = s.read_uint32_t_reverse_endianness(true); - v->sample_rate = s.read_uint32_t_reverse_endianness(true); - s.read_uint32_t(); - s.read_uint32_t(); - s.read_uint16_t(); - v->channels = s.read_uint16_t(); - if (v->channels < 2) - v->channels = 1; - s.read_uint64_t(); - s.read_uint64_t(); - - bool hevag = v->version == 0x00020001 || v->version == 0x00030000; - if (!hevag) - v->channels = 1; - - size_t ch = v->channels; - size_t vag_block_size = BLOCK_SIZE * ch; - - size_t num_blocks = (v->size / v->channels) >> 4; - 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_s(uint8_t, num_blocks); - - uint8_t nibble[BLOCK_SIZE]; - float_t* temp_data = data; - int16_t hevag1, hevag2, hevag3, hevag4; - int32_t s1, s2, s3, s4, sample; - size_t c, i, i1, i2; - uint8_t coef_index, d, shift_factor; - for (i1 = 0; i1 < num_blocks; i1++, temp_data += vag_block_size) - for (c = 0; c < ch; c++) { - d = s.read_uint8_t(); - coef_index = (d & 0xF0) >> 4; - shift_factor = d & 0x0F; - d = s.read_uint8_t(); - coef_index = (d & 0xF0) | coef_index; - flags[i1] = d & 0x0F; - - if (coef_index > 127) - coef_index = 0; - - for (i = 0, i2 = 1; i < BLOCK_SIZE; i += 2, i2 += 2) { - d = s.read_uint8_t(); - nibble[i] = d & 0x0F; - nibble[i2] = (d & 0xF0) >> 4; - } - - hevag1 = hevag1_table[coef_index]; - hevag2 = hevag2_table[coef_index]; - hevag3 = hevag3_table[coef_index]; - hevag4 = hevag4_table[coef_index]; - s1 = samp[c * 4 + 0]; - s2 = samp[c * 4 + 1]; - s3 = samp[c * 4 + 2]; - s4 = samp[c * 4 + 3]; - shift_factor = 20 - shift_factor; - for (i = 0; i < BLOCK_SIZE; i++) { - sample = shift_factor_table[nibble[i]] << shift_factor; - sample += (s1 * hevag1 + s2 * hevag2 + s3 * hevag3 + s4 * hevag4) >> 5; - s4 = s3; - s3 = s2; - s2 = s1; - s1 = sample >> 8; - temp_data[i * ch + c] = (float_t)(sample / 8388608.0); - } - samp[c * 4 + 0] = s1; - samp[c * 4 + 1] = s2; - samp[c * 4 + 2] = s3; - samp[c * 4 + 3] = s4; - } - free(samp); - - vag_write_wav(v, path, data, num_blocks, flags); - free(flags); - free(data); +void vag::read(const char* path) { + char* path_vag = str_utils_add(path, ".vag"); + file_stream s; + s.open(path_vag, "rb"); + if (s.check_not_null()) { + float_t* data; + size_t num_blocks; + uint8_t* flags; + if (vag_read_inner(this, s, data, num_blocks, flags)) { + wchar_t* path_temp = utf8_to_utf16(path); + vag_write_wav(this, path_temp, data, num_blocks, flags); + free_def(path_temp); + free_def(flags); + free_def(data); + } } -End: - free(path_vag); + free_def(path_vag); } -void vag_write(vag* v, const char* path, vag_option option) { - wchar_t* path_buf = utf8_to_utf16(path); - vag_write(v, path_buf, option); - free(path_buf); +void vag::read(const wchar_t* path) { + wchar_t* path_vag = str_utils_add(path, L".vag"); + file_stream s; + s.open(path_vag, L"rb"); + if (s.check_not_null()) { + float_t* data; + size_t num_blocks; + uint8_t* flags; + if (vag_read_inner(this, s, data, num_blocks, flags)) { + vag_write_wav(this, path, data, num_blocks, flags); + free_def(flags); + free_def(data); + } + } + free_def(path_vag); } -void vag_write(vag* v, const wchar_t* path, vag_option option) { - size_t num_samples; +void vag::write(const char* path, vag_option option) { float_t* data; + size_t num_samples; uint8_t* flags; - vag_read_wav(v, path, &data, &num_samples, &flags); + wchar_t* path_temp = utf8_to_utf16(path); + vag_read_wav(this, path_temp, data, num_samples, flags); + free_def(path_temp); if (!data || !num_samples) return; - v->size = align_val_divide(num_samples, BLOCK_SIZE, BLOCK_SIZE); + size = align_val_divide(num_samples, BLOCK_SIZE, BLOCK_SIZE); - wchar_t* temp_path = str_utils_get_without_extension(path); - wchar_t* path_vag = str_utils_add(temp_path, L".vag"); - stream s; + char* path_vag = str_utils_add(path, ".vag"); + file_stream s; + s.open(path_vag, "wb"); + if (s.check_not_null()) + vag_write_inner(this, s, data, flags, option); + free_def(path_vag); + free_def(flags); + free_def(data); +} + +void vag::write(const wchar_t* path, vag_option option) { + float_t* data; + size_t num_samples; + uint8_t* flags; + + vag_read_wav(this, path, data, num_samples, flags); + if (!data || !num_samples) + return; + + size = align_val_divide(num_samples, BLOCK_SIZE, BLOCK_SIZE); + + wchar_t* path_vag = str_utils_add(path, L".vag"); + file_stream s; s.open(path_vag, L"wb"); - if (s.io.stream) { - int32_t coef_index_count; - switch (option) { - case VAG_OPTION_HEVAG_FAST: - coef_index_count = 16; - break; - case VAG_OPTION_HEVAG_MEDIUM: - coef_index_count = 32; - break; - case VAG_OPTION_HEVAG_SLOW: - coef_index_count = 64; - break; - case VAG_OPTION_HEVAG_SLOWEST: - coef_index_count = 96; - break; - case VAG_OPTION_HEVAG_SLOWASHELL: - coef_index_count = 128; - break; - default: - coef_index_count = 5; - break; - } + if (s.check_not_null()) + vag_write_inner(this, s, data, flags, option); + free_def(path_vag); + free_def(flags); + free_def(data); +} - bool hevag = option != VAG_OPTION_VAG; - s.write_uint32_t_reverse_endianness('VAGp', true); - s.write_uint32_t_reverse_endianness(hevag ? 0x00020001 : 0x00000020, true); - s.write_uint32_t(0); - s.write_uint32_t_reverse_endianness((uint32_t)(((v->size + 1) * (hevag ? v->channels : 1)) << 4), true); - s.write_uint32_t_reverse_endianness(v->sample_rate, true); - s.write_uint32_t(0); - s.write_uint32_t(0); - s.write_uint16_t(0); - s.write_uint16_t(hevag ? v->channels : 1); - s.write_uint64_t(0); - s.write_uint64_t(0); +static bool vag_read_inner(vag* v, stream& s, float_t*& data, size_t& num_blocks, uint8_t*& flags) { + data = 0; + num_blocks = 0; + flags = 0; - size_t c, i, i1, i2; - int32_t ch = v->channels; - int32_t* samp = force_malloc_s(int32_t, hevag ? v->channels * 8ULL : 4ULL); - if (hevag && coef_index_count > 29) { - uint8_t flag, sample; - int32_t temp_data[BLOCK_SIZE]; - int8_t four_bit[BLOCK_SIZE]; - int32_t coef_index, shift_factor; - size_t size = v->size; - for (i1 = 0; i1 < size; i1++) - for (c = 0; c < ch; c++) { - for (i = 0; i < BLOCK_SIZE; i++) { - float_t t_s = data[i1 * BLOCK_SIZE * ch + i * ch + c]; - temp_data[i] = (int32_t)round(t_s * 8388608.0); - } + uint32_t signature = s.read_uint32_t_reverse_endianness(true); + if (signature != 'VAGp') + return false; - calculate_4_bits_hevag(temp_data, four_bit, &coef_index, - &shift_factor, samp + c * 8, samp + c * 8 + 4, coef_index_count); + v->version = s.read_uint32_t_reverse_endianness(true); + s.read_uint32_t(); + v->size = s.read_uint32_t_reverse_endianness(true); + v->sample_rate = s.read_uint32_t_reverse_endianness(true); + s.read_uint32_t(); + s.read_uint32_t(); + s.read_uint16_t(); + v->channels = s.read_uint16_t(); + if (v->channels < 2) + v->channels = 1; + s.read_uint64_t(); + s.read_uint64_t(); - flag = flags ? (flags[i1] & 0x0F) : (i1 + 1 == size) ? 0x01 : 0; - sample = ((coef_index & 0x0F) << 4) | (shift_factor & 0x0F); - s.write_uint8_t(sample); - sample = (coef_index & 0xF0) | flag; - s.write_uint8_t(sample); - for (i = 0, i2 = 1; i < BLOCK_SIZE; i += 2, i2 += 2) { - sample = ((four_bit[i2] & 0x0F) << 4) | (four_bit[i] & 0x0F); - s.write_uint8_t(sample); - } - } - for (c = 0; c < ch; c++) { - s.write_uint64_t(0x7777777777770700); - s.write_uint64_t(0x7777777777777777); + bool is_hevag = v->version == 0x00020001 || v->version == 0x00030000; + if (!is_hevag) + v->channels = 1; + + size_t ch = v->channels; + size_t vag_block_size = BLOCK_SIZE * ch; + + num_blocks = (v->size / v->channels) >> 4; + int32_t* samp = force_malloc_s(int32_t, ch * 4); + data = force_malloc_s(float_t, num_blocks * vag_block_size); + flags = force_malloc_s(uint8_t, num_blocks); + + uint8_t nibble[BLOCK_SIZE]; + float_t* temp_data = data; + int16_t hevag1, hevag2, hevag3, hevag4; + int32_t s1, s2, s3, s4, sample; + size_t c, i, i1, i2, j; + uint8_t coef_index, d, shift_factor; + for (i1 = 0; i1 < num_blocks; i1++, temp_data += vag_block_size) + for (c = 0; c < ch; c++) { + d = s.read_uint8_t(); + coef_index = (d & 0xF0) >> 4; + shift_factor = d & 0x0F; + d = s.read_uint8_t(); + coef_index = (d & 0x70) | coef_index; + flags[i1] = d & 0x0F; + + if (coef_index > 127) + coef_index = 0; + + for (i = 0, i2 = 1, j = BLOCK_SIZE; j; i += 2, i2 += 2, j -= 2) { + d = s.read_uint8_t(); + nibble[i] = d & 0x0F; + nibble[i2] = (d & 0xF0) >> 4; } - } - else if (hevag) { - uint8_t flag, sample; - int32_t temp_data[BLOCK_SIZE]; - int8_t four_bit[BLOCK_SIZE]; - int32_t coef_index, shift_factor; - size_t size = v->size; - for (i1 = 0; i1 < size; i1++) - for (c = 0; c < ch; c++) { - for (i = 0; i < BLOCK_SIZE; i++) { - float_t t_s = data[i1 * BLOCK_SIZE * ch + i * ch + c]; - temp_data[i] = (int32_t)round(t_s * 8388608.0); - } - calculate_4_bits_vag(temp_data, four_bit, &coef_index, - &shift_factor, samp + c * 4, samp + c * 4 + 2, coef_index_count); - - flag = flags ? (flags[i1] & 0x0F) : (i1 + 1 == size) ? 0x01 : 0; - sample = ((coef_index & 0x0F) << 4) | (shift_factor & 0x0F); - s.write_uint8_t(sample); - sample = (coef_index & 0xF0) | flag; - s.write_uint8_t(sample); - for (i = 0, i2 = 1; i < BLOCK_SIZE; i += 2, i2 += 2) { - sample = ((four_bit[i2] & 0x0F) << 4) | (four_bit[i] & 0x0F); - s.write_uint8_t(sample); - } - } - - for (c = 0; c < ch; c++) { - s.write_uint64_t(0x7777777777770700); - s.write_uint64_t(0x7777777777777777); + hevag1 = hevag_table[coef_index][0]; + hevag2 = hevag_table[coef_index][1]; + hevag3 = hevag_table[coef_index][2]; + hevag4 = hevag_table[coef_index][3]; + s1 = samp[c * 4 + 0]; + s2 = samp[c * 4 + 1]; + s3 = samp[c * 4 + 2]; + s4 = samp[c * 4 + 3]; + shift_factor = 20 - shift_factor; + for (i = 0, j = BLOCK_SIZE; j; i++, j--) { + sample = shift_factor_table[nibble[i]] << shift_factor; + sample += (s1 * hevag1 + s2 * hevag2 + s3 * hevag3 + s4 * hevag4) >> 5; + s4 = s3; + s3 = s2; + s2 = s1; + s1 = sample >> 8; + temp_data[i * ch + c] = (float_t)((double_t)sample / 8388608.0); } - } - else { - uint8_t flag, sample; - int32_t temp_data[BLOCK_SIZE]; - int8_t four_bit[BLOCK_SIZE]; - int32_t coef_index, shift_factor; - size_t size = v->size; - for (i1 = 0; i1 < size; i1++) { - for (i = 0; i < BLOCK_SIZE; i++) { - float_t t_s = 0.0f; - for (c = 0; c < ch; c++) - t_s += data[i1 * BLOCK_SIZE * ch + i * ch + c]; - t_s /= ch; + samp[c * 4 + 0] = s1; + samp[c * 4 + 1] = s2; + samp[c * 4 + 2] = s3; + samp[c * 4 + 3] = s4; + } + free_def(samp); + return true; +} + +static void vag_write_inner(vag* v, stream& s, const float_t* data, const uint8_t* flags, vag_option option) { + int32_t coef_index_count; + switch (option) { + case VAG_OPTION_HEVAG_FAST: + coef_index_count = 16; + break; + case VAG_OPTION_HEVAG_MEDIUM: + coef_index_count = 32; + break; + case VAG_OPTION_HEVAG_SLOW: + coef_index_count = 64; + break; + case VAG_OPTION_HEVAG_SLOWEST: + coef_index_count = 96; + break; + case VAG_OPTION_HEVAG_SLOWASHELL: + coef_index_count = 128; + break; + default: + coef_index_count = 5; + break; + } + + bool hevag = option != VAG_OPTION_VAG; + s.write_uint32_t_reverse_endianness('VAGp', true); + s.write_uint32_t_reverse_endianness(hevag ? 0x00020001 : 0x00000020, true); + s.write_uint32_t(0); + s.write_uint32_t_reverse_endianness((uint32_t)(((v->size + 1) * (hevag ? v->channels : 1)) << 4), true); + s.write_uint32_t_reverse_endianness(v->sample_rate, true); + s.write_uint32_t(0); + s.write_uint32_t(0); + s.write_uint16_t(0); + s.write_uint16_t(hevag ? v->channels : 1); + s.write_uint64_t(0); + s.write_uint64_t(0); + + size_t c, i, i1, i2, j; + int32_t ch = v->channels; + int32_t* samp = force_malloc_s(int32_t, hevag ? v->channels * 8ULL : 4ULL); + if (hevag && coef_index_count > 29) { + uint8_t flag, sample; + int32_t temp_data[BLOCK_SIZE]; + int8_t four_bit[BLOCK_SIZE]; + int32_t coef_index, shift_factor; + size_t size = v->size; + for (i1 = 0; i1 < size; i1++) + for (c = 0; c < ch; c++) { + for (i = 0, j = BLOCK_SIZE; j; i++, j--) { + float_t t_s = data[i1 * BLOCK_SIZE * ch + i * ch + c]; temp_data[i] = (int32_t)round(t_s * 8388608.0); } - calculate_4_bits_vag(temp_data, four_bit, &coef_index, - &shift_factor, samp, samp + 2, coef_index_count); - - for (i = 0, i2 = 0; i < BLOCK_SIZE; i++) - if (!four_bit[i]) - i2++; + calculate_4_bits_hevag(temp_data, four_bit, &coef_index, + &shift_factor, samp + c * 8, samp + c * 8 + 4, coef_index_count); flag = flags ? (flags[i1] & 0x0F) : (i1 + 1 == size) ? 0x01 : 0; sample = ((coef_index & 0x0F) << 4) | (shift_factor & 0x0F); s.write_uint8_t(sample); sample = (coef_index & 0xF0) | flag; s.write_uint8_t(sample); - for (i = 0, i2 = 1; i < BLOCK_SIZE; i += 2, i2 += 2) { + for (i = 0, i2 = 1, j = BLOCK_SIZE; j; i += 2, i2 += 2, j -= 2) { sample = ((four_bit[i2] & 0x0F) << 4) | (four_bit[i] & 0x0F); s.write_uint8_t(sample); } } + + for (c = 0; c < ch; c++) { s.write_uint64_t(0x7777777777770700); s.write_uint64_t(0x7777777777777777); } - s.write_uint64_t(0x1010101010101010); - s.write_uint64_t(0x1010101010101010); - free(samp); } - free(path_vag); - free(temp_path); - free(flags); - free(data); + else if (hevag) { + uint8_t flag, sample; + int32_t temp_data[BLOCK_SIZE]; + int8_t four_bit[BLOCK_SIZE]; + int32_t coef_index, shift_factor; + size_t size = v->size; + for (i1 = 0; i1 < size; i1++) + for (c = 0; c < ch; c++) { + for (i = 0, j = BLOCK_SIZE; j; i++, j--) { + float_t t_s = data[i1 * BLOCK_SIZE * ch + i * ch + c]; + temp_data[i] = (int32_t)round(t_s * 8388608.0); + } + + calculate_4_bits_vag(temp_data, four_bit, &coef_index, + &shift_factor, samp + c * 4, samp + c * 4 + 2, coef_index_count); + + flag = flags ? (flags[i1] & 0x0F) : (i1 + 1 == size) ? 0x01 : 0; + sample = ((coef_index & 0x0F) << 4) | (shift_factor & 0x0F); + s.write_uint8_t(sample); + sample = (coef_index & 0xF0) | flag; + s.write_uint8_t(sample); + for (i = 0, i2 = 1, j = BLOCK_SIZE; j; i += 2, i2 += 2, j -= 2) { + sample = ((four_bit[i2] & 0x0F) << 4) | (four_bit[i] & 0x0F); + s.write_uint8_t(sample); + } + } + + for (c = 0; c < ch; c++) { + s.write_uint64_t(0x7777777777770700); + s.write_uint64_t(0x7777777777777777); + } + } + else { + uint8_t flag, sample; + int32_t temp_data[BLOCK_SIZE]; + int8_t four_bit[BLOCK_SIZE]; + int32_t coef_index, shift_factor; + size_t size = v->size; + for (i1 = 0; i1 < size; i1++) { + for (i = 0, j = BLOCK_SIZE; j; i++, j--) { + float_t t_s = 0.0f; + for (c = 0; c < ch; c++) + t_s += data[i1 * BLOCK_SIZE * ch + i * ch + c]; + t_s /= ch; + temp_data[i] = (int32_t)round(t_s * 8388608.0); + } + + calculate_4_bits_vag(temp_data, four_bit, &coef_index, + &shift_factor, samp, samp + 2, coef_index_count); + + flag = flags ? (flags[i1] & 0x0F) : (i1 + 1 == size) ? 0x01 : 0; + sample = ((coef_index & 0x0F) << 4) | (shift_factor & 0x0F); + s.write_uint8_t(sample); + sample = (coef_index & 0xF0) | flag; + s.write_uint8_t(sample); + for (i = 0, i2 = 1, j = BLOCK_SIZE; j; i += 2, i2 += 2, j -= 2) { + sample = ((four_bit[i2] & 0x0F) << 4) | (four_bit[i] & 0x0F); + s.write_uint8_t(sample); + } + } + s.write_uint64_t(0x7777777777770700); + s.write_uint64_t(0x7777777777777777); + } + s.write_uint64_t(0x1010101010101010); + s.write_uint64_t(0x1010101010101010); + free_def(samp); } -void vag_dispose(vag* v) { - free(v); +static void vag_read_wav_straight(vag* v, const wchar_t* path, float_t*& data, size_t& samples) { + data = 0; + samples = 0; + wchar_t* path_wav = str_utils_add(path, L".wav"); + wav w; + w.read(path_wav, data, samples); + v->channels = w.channels; + v->sample_rate = w.sample_rate; + free_def(path_wav); } -static void vag_read_wav_straight(vag* v, const wchar_t* path, float_t** data, size_t* samples) { - *data = 0; - *samples = 0; - wchar_t* path_av = str_utils_add(path, L".wav"); - wav* w = wav_init(); - wav_read(w, path_av, data, samples); - v->channels = w->channels; - v->sample_rate = w->sample_rate; - wav_dispose(w); - free(path_av); -} +static void vag_read_wav(vag* v, const wchar_t* path, float_t*& data, size_t& samples, uint8_t*& flags) { + data = 0; + samples = 0; + flags = 0; -static void vag_read_wav(vag* v, const wchar_t* path, float_t** data, size_t* samples, uint8_t** flags) { - *data = 0; - *samples = 0; - *flags = 0; if (!str_utils_check_ends_with(path, L".0")) { vag_read_wav_straight(v, path, data, samples); return; @@ -425,7 +521,7 @@ static void vag_read_wav(vag* v, const wchar_t* path, float_t** data, size_t* sa } if (!count) { - free(temp_path); + free_def(temp_path); return; } @@ -433,42 +529,39 @@ static void vag_read_wav(vag* v, const wchar_t* path, float_t** data, size_t* sa 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++) { if (add_loop && i + 1 == count) continue; swprintf_s(temp, MAX_PATH, loop[i] ? L"%ls.%llu.loop.wav" : L"%ls.%llu.wav", temp_path, i); - wav_read(w, temp, &wav_data[i], &wav_samples[i]); + wav w; + w.read(temp, wav_data[i], wav_samples[i]); if (i == 0) { - v->channels = w->channels; - v->sample_rate = w->sample_rate; + v->channels = w.channels; + v->sample_rate = w.sample_rate; } - else if (v->channels != w->channels || v->sample_rate != w->sample_rate) { - wav_dispose(w); - + else if (v->channels != w.channels || v->sample_rate != w.sample_rate) { for (size_t i1 = 0; i1 <= i; i1++) - free(wav_data[i1]); + free_def(wav_data[i1]); - free(wav_samples); - free(wav_data); - free(temp_path); + free_def(wav_samples); + free_def(wav_data); + free_def(temp_path); return; } } - wav_dispose(w); - *samples = 0; + samples = 0; for (size_t i = 0; i < count; i++) if (add_loop && i + 1 == count) - *samples += BLOCK_SIZE; + samples += BLOCK_SIZE; else - *samples += align_val(wav_samples[i], BLOCK_SIZE); + samples += align_val(wav_samples[i], BLOCK_SIZE); l = false; size_t ch = v->channels; - *data = force_malloc_s(float_t, *samples * ch); - float_t* data_temp = *data; + data = force_malloc_s(float_t, samples * ch); + float_t* data_temp = data; for (size_t i = 0; i < count; i++) { size_t i3; if (add_loop && i + 1 == count) @@ -486,8 +579,8 @@ static void vag_read_wav(vag* v, const wchar_t* path, float_t** data, size_t* sa } l = false; - *flags = force_malloc_s(uint8_t, *samples / BLOCK_SIZE); - uint8_t* f = *flags; + flags = force_malloc_s(uint8_t, samples / BLOCK_SIZE); + uint8_t* f = flags; for (size_t i = 0; i < count; i++) { size_t num_blocks; if (add_loop && i + 1 == count) @@ -521,14 +614,14 @@ static void vag_read_wav(vag* v, const wchar_t* path, float_t** data, size_t* sa } for (size_t i = 0; i < count; i++) - free(wav_data[i]); + free_def(wav_data[i]); - free(wav_samples); - free(wav_data); - free(temp_path); + free_def(wav_samples); + free_def(wav_data); + free_def(temp_path); } -static void vag_write_wav_straight(vag* v, const wchar_t* path, float_t* data, size_t num_blocks, uint8_t* flags) { +static void vag_write_wav_straight(vag* v, const wchar_t* path, const float_t* data, size_t num_blocks, const uint8_t* flags) { size_t i = 0; for (i = 0; i < num_blocks; i++) { uint8_t flag = flags[i]; @@ -540,34 +633,28 @@ static void vag_write_wav_straight(vag* v, const wchar_t* path, float_t* data, s break; } - wchar_t* path_av = str_utils_add(path, L".wav"); - wav* w = wav_init(); - w->bytes = 4; - w->channels = v->channels; - w->format = 0x03; - w->sample_rate = v->sample_rate; - wav_write(w, path_av, data, i * BLOCK_SIZE); - wav_dispose(w); - free(path_av); + wchar_t* path_wav = str_utils_add(path, L".wav"); + wav w; + w.bytes = 4; + w.channels = v->channels; + w.format = 0x03; + w.sample_rate = v->sample_rate; + w.write(path_wav, data, i * BLOCK_SIZE); + free_def(path_wav); } -static void vag_write_wav(vag* v, const wchar_t* path, float_t* data, size_t num_blocks, uint8_t* flags) { +static void vag_write_wav(vag* v, const wchar_t* path, const float_t* data, size_t num_blocks, const uint8_t* flags) { uint8_t flag = flags[0]; if (flag == 5 || flag == 7) return; wchar_t temp[MAX_PATH]; - wav* w = wav_init(); - w->bytes = 4; - w->channels = v->channels; - w->format = 0x03; - w->sample_rate = v->sample_rate; bool loop = false; size_t i = 0, i2 = 0; size_t ch = v->channels; size_t vag_block_size = BLOCK_SIZE * ch; - float_t* temp_data = data; - float_t* temp_data_last = data; + const float_t* temp_data = data; + const float_t* temp_data_last = data; for (size_t i1 = 0; i1 < num_blocks; i1++, temp_data += vag_block_size) { flag = flags[i1]; if (flag == 5 || flag == 7) @@ -575,7 +662,12 @@ static void vag_write_wav(vag* v, const wchar_t* path, float_t* data, size_t num else if (flag == 3 || flag == 6) { if (i) { swprintf_s(temp, MAX_PATH, loop ? L"%ls.%llu.loop.wav" : L"%ls.%llu.wav", path, i2); - wav_write(w, temp, temp_data_last, i * BLOCK_SIZE); + wav w; + w.bytes = 4; + w.channels = v->channels; + w.format = 0x03; + w.sample_rate = v->sample_rate; + w.write(temp, temp_data_last, i * BLOCK_SIZE); i2++; } @@ -592,29 +684,34 @@ static void vag_write_wav(vag* v, const wchar_t* path, float_t* data, size_t num if (i) { swprintf_s(temp, MAX_PATH, L"%ls.%llu.wav", path, i2); - wav_write(w, temp, temp_data_last, i * BLOCK_SIZE); + wav w; + w.bytes = 4; + w.channels = v->channels; + w.format = 0x03; + w.sample_rate = v->sample_rate; + w.write(temp, temp_data_last, i * BLOCK_SIZE); } - wav_dispose(w); } static void calculate_4_bits_vag(int32_t* data, int8_t* four_bit, int32_t* coef_index, int32_t* shift_factor, int32_t* v, int32_t* tv, int32_t coef_index_count) { - int32_t d0, e, g, i, j; + int32_t d0, e, g, i, j, k, l; int32_t err, min, s1, s2, c_f; c_f = 0; min = 0x7FFFFFFF; - for (j = 0; j < coef_index_count; j++) { + for (j = 0, l = coef_index_count; l; j++, l--) { calculate_4_bits_vag_inner(data, four_bit, j, shift_factor, v, tv, 0, 0); - int32_t vag1 = hevag1_table[j]; - int32_t vag2 = hevag2_table[j]; + int32_t vag1 = hevag_table[j][0]; + int32_t vag2 = hevag_table[j][1]; + int32_t _shift_factor = *shift_factor; s1 = v[0]; s2 = v[1]; err = 0; - for (i = 0; i < BLOCK_SIZE; i++) { - d0 = four_bit[i] << *shift_factor; + for (i = 0, k = BLOCK_SIZE; k; i++, k--) { + d0 = four_bit[i] << _shift_factor; g = ((s1 * vag1 + s2 * vag2) >> 5) + d0; s2 = s1; @@ -637,15 +734,15 @@ static void calculate_4_bits_vag(int32_t* data, int8_t* four_bit, int32_t* coef_ static void calculate_4_bits_vag_inner(int32_t* data, int8_t* four_bit, int32_t coef_index, int32_t* shift_factor, int32_t* v, int32_t* tv, int32_t* os, int32_t* ots) { - int32_t d0, d1, e, g, i, s_f, t_s_f, m, shift_max; + int32_t d0, d1, e, g, i, j, s_f, t_s_f, m, shift_max; int32_t temp[BLOCK_SIZE]; - int32_t vag1 = hevag1_table[coef_index]; - int32_t vag2 = hevag2_table[coef_index]; + int32_t vag1 = hevag_table[coef_index][0]; + int32_t vag2 = hevag_table[coef_index][1]; int32_t s1 = v[0]; int32_t s2 = v[1]; - for (i = 0, m = 0; i < BLOCK_SIZE; i++) { + for (i = 0, j = BLOCK_SIZE, m = 0; j; i++, j--) { g = data[i]; e = (s1 * vag1 + s2 * vag2) >> 5; e = g - e; @@ -670,7 +767,7 @@ static void calculate_4_bits_vag_inner(int32_t* data, int8_t* four_bit, int32_t os[1] = s2; } - for (s_f = 12, shift_max = 0x400000; s_f > 0; s_f--, shift_max >>= 1) + for (s_f = 12, shift_max = 0x400000; s_f; s_f--, shift_max >>= 1) if ((shift_max & (m + (shift_max >> 4))) == shift_max) break; @@ -679,7 +776,7 @@ static void calculate_4_bits_vag_inner(int32_t* data, int8_t* four_bit, int32_t int32_t ts1 = tv[0]; int32_t ts2 = tv[1]; - for (i = 0; i < BLOCK_SIZE; i++) { + for (i = 0, j = BLOCK_SIZE; j; i++, j--) { g = temp[i]; e = (ts1 * vag1 + ts2 * vag2) >> 5; e = g - e; @@ -708,26 +805,26 @@ static void calculate_4_bits_vag_inner(int32_t* data, int8_t* four_bit, int32_t static void calculate_4_bits_hevag(int32_t* data, int8_t* four_bit, int32_t* coef_index, int32_t* shift_factor, int32_t* v, int32_t* tv, int32_t coef_index_count) { - int32_t d0, e, g, i, j; + int32_t d0, e, g, i, j, k, l; int32_t err, min, s1, s2, s3, s4, c_f; c_f = 0; min = 0x7FFFFFFF; - for (j = 0; j < coef_index_count; j++) { + for (j = 0, l = coef_index_count; l; j++, l--) { calculate_4_bits_hevag_inner(data, four_bit, j, shift_factor, v, tv, 0, 0); - int32_t hevag1 = hevag1_table[j]; - int32_t hevag2 = hevag2_table[j]; - int32_t hevag3 = hevag3_table[j]; - int32_t hevag4 = hevag4_table[j]; - + int32_t hevag1 = hevag_table[j][0]; + int32_t hevag2 = hevag_table[j][1]; + int32_t hevag3 = hevag_table[j][2]; + int32_t hevag4 = hevag_table[j][3]; s1 = v[0]; s2 = v[1]; s3 = v[2]; s4 = v[3]; + int32_t _shift_factor = *shift_factor; err = 0; - for (i = 0; i < BLOCK_SIZE; i++) { - d0 = four_bit[i] << *shift_factor; + for (i = 0, k = BLOCK_SIZE; k; i++, k--) { + d0 = four_bit[i] << _shift_factor; g = ((s1 * hevag1 + s2 * hevag2 + s3 * hevag3 + s4 * hevag4) >> 5) + d0; s4 = s3; @@ -752,22 +849,21 @@ static void calculate_4_bits_hevag(int32_t* data, int8_t* four_bit, int32_t* coe static void calculate_4_bits_hevag_inner(int32_t* data, int8_t* four_bit, int32_t coef_index, int32_t* shift_factor, int32_t* v, int32_t* tv, int32_t* os, int32_t* ots) { - int32_t d0, d1, e, g, i, s_f, t_s_f, m, shift_max; + int32_t d0, d1, e, g, i, j, s_f, t_s_f, m, shift_max; int32_t temp[BLOCK_SIZE]; - int32_t hevag1 = hevag1_table[coef_index]; - int32_t hevag2 = hevag2_table[coef_index]; - int32_t hevag3 = hevag3_table[coef_index]; - int32_t hevag4 = hevag4_table[coef_index]; + int32_t hevag1 = hevag_table[coef_index][0]; + int32_t hevag2 = hevag_table[coef_index][1]; + int32_t hevag3 = hevag_table[coef_index][2]; + int32_t hevag4 = hevag_table[coef_index][3]; int32_t s1 = v[0]; int32_t s2 = v[1]; int32_t s3 = v[2]; int32_t s4 = v[3]; - for (i = 0, m = 0; i < BLOCK_SIZE; i++) { + for (i = 0, j = BLOCK_SIZE, m = 0; j; i++, j--) { g = data[i]; - e = (s1 * hevag1 + s2 * hevag2 + s3 * hevag3 + s4 * hevag4) >> 5; - e = g - e; + e = g - ((s1 * hevag1 + s2 * hevag2 + s3 * hevag3 + s4 * hevag4) >> 5); s4 = s3; s3 = s2; s2 = s1; @@ -793,7 +889,7 @@ static void calculate_4_bits_hevag_inner(int32_t* data, int8_t* four_bit, int32_ os[3] = s4; } - for (s_f = 12, shift_max = 0x400000; s_f > 0; s_f--, shift_max >>= 1) + for (s_f = 12, shift_max = 0x400000; s_f; s_f--, shift_max >>= 1) if ((shift_max & (m + (shift_max >> 4))) == shift_max) break; @@ -804,10 +900,10 @@ static void calculate_4_bits_hevag_inner(int32_t* data, int8_t* four_bit, int32_ int32_t ts2 = tv[1]; int32_t ts3 = tv[2]; int32_t ts4 = tv[3]; - for (i = 0; i < BLOCK_SIZE; i++) { + + for (i = 0, j = BLOCK_SIZE; j; i++, j--) { g = temp[i]; - e = (ts1 * hevag1 + ts2 * hevag2 + ts3 * hevag3 + ts4 * hevag4) >> 5; - e = g - e; + e = g - ((ts1 * hevag1 + ts2 * hevag2 + ts3 * hevag3 + ts4 * hevag4) >> 5); d1 = e << s_f; d0 = (d1 + 0x80000) >> 20; @@ -825,6 +921,7 @@ static void calculate_4_bits_hevag_inner(int32_t* data, int8_t* four_bit, int32_ ts2 = ts1; ts1 = (d0 - e) >> 8; } + *shift_factor = t_s_f; if (ots) { diff --git a/src/KKdLib/sound/vag.hpp b/src/KKdLib/sound/vag.hpp index 9198d0b0..b068e4de 100644 --- a/src/KKdLib/sound/vag.hpp +++ b/src/KKdLib/sound/vag.hpp @@ -22,11 +22,12 @@ struct vag { uint32_t sample_rate; uint32_t channels; size_t size; -}; -extern vag* vag_init(); -extern void vag_read(vag* v, const char* path); -extern void vag_read(vag* v, const wchar_t* path); -extern void vag_write(vag* v, const char* path, vag_option option); -extern void vag_write(vag* v, const wchar_t* path, vag_option option); -extern void vag_dispose(vag* f); + vag(); + virtual ~vag(); + + void read(const char* path); + void read(const wchar_t* path); + void write(const char* path, vag_option option); + void write(const wchar_t* path, vag_option option); +}; diff --git a/src/KKdLib/sound/wav.cpp b/src/KKdLib/sound/wav.cpp index 08eee041..13fcb5d9 100644 --- a/src/KKdLib/sound/wav.cpp +++ b/src/KKdLib/sound/wav.cpp @@ -4,211 +4,241 @@ */ #include "wav.hpp" -#include "../io/stream.hpp" +#include "../io/file_stream.hpp" + +static void wav_read_inner(wav* w, stream& s, float_t*& data, size_t& samples); +static void wav_write_inner(wav* w, stream& s, const float_t* data, size_t samples); + +wav::wav() : size(), sample_rate(), header_size(), +channel_mask(), is_supported(), bytes(), format(), channels() { + +} + +wav::~wav() { + +} + +void wav::read(const char* path, float_t*& data, size_t& samples) { + data = 0; + samples = 0; + + if (!path) + return; + + file_stream s; + s.open(path, "rb"); + if (s.check_not_null()) + wav_read_inner(this, s, data, samples); +} + +void wav::read(const wchar_t* path, float_t*& data, size_t& samples) { + data = 0; + samples = 0; + + if (!path) + return; + + file_stream s; + s.open(path, L"rb"); + if (s.check_not_null()) + wav_read_inner(this, s, data, samples); +} + +void wav::write(const char* path, const float_t* data, size_t samples) { + if (!data || !samples || !path) + return; + + file_stream s; + s.open(path, "wb"); + if (s.check_not_null()) + wav_write_inner(this, s, data, samples); +} + +void wav::write(const wchar_t* path, const float_t* data, size_t samples) { + if (!data || !samples || !path) + return; + + file_stream s; + s.open(path, L"wb"); + if (s.check_not_null()) + wav_write_inner(this, s, data, samples); +} wav* wav_init() { wav* w = force_malloc_s(wav, 1); return w; } -void wav_read(wav* w, const char* path, float_t** data, size_t* samples) { - wchar_t* path_buf = utf8_to_utf16(path); - wav_read(w, path_buf, data, samples); - free(path_buf); -} +static void wav_read_inner(wav* w, stream& s, float_t*& data, size_t& samples) { + wav w_t; + if (s.read_uint32_t() != 0x46464952) + return; + s.read_uint32_t(); + if (s.read_uint32_t() != 0x45564157 || s.read_uint32_t() != 0x20746D66) + return; + size_t offset = s.read_uint32_t(); + w_t.format = s.read_uint16_t(); + if (w_t.format != 0x01 && w_t.format != 0x03 && w_t.format != 0xFFFE) + return; -void wav_read(wav* w, const wchar_t* path, float_t** data, size_t* samples) { - *data = 0; - *samples = 0; - memset(w, 0, sizeof(wav)); - - stream s; - s.open(path, L"rb"); - if (s.io.stream) { - wav w_t; - if (s.read_uint32_t() != 0x46464952) - return; + w_t.channels = s.read_uint16_t(); + w_t.sample_rate = s.read_uint32_t(); + s.read_uint32_t(); + s.read_uint16_t(); + w_t.bytes = s.read_uint16_t(); + if (w_t.bytes % 8 || !(w_t.bytes / 8)) + return; + if (w_t.format == 0xFFFE) { s.read_uint32_t(); - if (s.read_uint32_t() != 0x45564157 || s.read_uint32_t() != 0x20746D66) - return; - size_t offset = s.read_uint32_t(); + w_t.channel_mask = s.read_uint32_t(); w_t.format = s.read_uint16_t(); - if (w_t.format != 0x01 && w_t.format != 0x03 && w_t.format != 0xFFFE) - return; - - w_t.channels = s.read_uint16_t(); - w_t.sample_rate = s.read_uint32_t(); - s.read_uint32_t(); - s.read_uint16_t(); - w_t.bytes = s.read_uint16_t(); - if (w_t.bytes % 8 || !(w_t.bytes / 8)) - return; - if (w_t.format == 0xFFFE) { - s.read_uint32_t(); - w_t.channel_mask = s.read_uint32_t(); - w_t.format = s.read_uint16_t(); - } - - w_t.bytes >>= 3; - if (w_t.bytes < 1 || (w_t.bytes > 4 && w_t.bytes != 8)) - return; - else if (w_t.bytes > 0 && w_t.bytes < 4 && w_t.format == 3) - return; - else if (w_t.bytes == 8 && w_t.format == 1) - return; - - s.set_position(offset + 0x14, SEEK_SET); - if (s.read_uint32_t() != 0x61746164) - return; - w_t.size = s.read_uint32_t(); - w_t.header_size = (int32_t)s.get_position(); - w_t.is_supported = true; - *w = w_t; - - *samples = w->size / w->channels / w->bytes; - *data = force_malloc_s(float_t, w->size / w->bytes); - - size_t t_s = *samples; - float_t* t_d = *data; - - size_t ch = w->channels; - if (w->bytes == 0x01 && w->format == 0x01) - for (size_t i = 0; i < t_s; i++) - for (size_t c = 0; c < ch; c++) { - double_t sample = s.read_int8_t(); - sample = div_min_max(sample, -128.0, 127.0); - t_d[i * ch + c] = (float_t)sample; - } - else if (w->bytes == 0x02 && (w->format == 0x01 || w->format == 0xFFFE)) - for (size_t i = 0; i < t_s; i++) - for (size_t c = 0; c < ch; c++) { - double_t sample = s.read_int16_t(); - sample = div_min_max(sample, -32768.0, 32767.0); - t_d[i * ch + c] = (float_t)sample; - } - else if (w->bytes == 0x03 && w->format == 0x01) - for (size_t i = 0; i < t_s; i++) - for (size_t c = 0; c < ch; c++) { - int32_t samp; - s.read(&samp, 3); - double_t sample = (samp << 8) >> 8; - sample = div_min_max(sample, -8388608.0, 8388607.0); - t_d[i * ch + c] = (float_t)sample; - } - else if (w->bytes == 0x04 && w->format == 0x01) - for (size_t i = 0; i < t_s; i++) - for (size_t c = 0; c < ch; c++) { - double_t sample = s.read_int32_t(); - sample = div_min_max(sample, -2147483648.0, 2147483647.0); - t_d[i * ch + c] = (float_t)sample; - } - else if (w->bytes == 0x04 && (w->format == 0x03 || w->format == 0xFFFE)) - for (size_t i = 0; i < t_s; i++) - for (size_t c = 0; c < ch; c++) { - float_t sample = s.read_float_t(); - t_d[i * ch + c] = sample; - } - else if (w->bytes == 0x08 && (w->format == 0x03 || w->format == 0xFFFE)) - for (size_t i = 0; i < t_s; i++) - for (size_t c = 0; c < ch; c++) { - double_t sample = s.read_double_t(); - t_d[i * ch + c] = (float_t)sample; - } } + + w_t.bytes >>= 3; + if (w_t.bytes < 1 || (w_t.bytes > 4 && w_t.bytes != 8)) + return; + else if (w_t.bytes > 0 && w_t.bytes < 4 && w_t.format == 3) + return; + else if (w_t.bytes == 8 && w_t.format == 1) + return; + + s.set_position(offset + 0x14, SEEK_SET); + if (s.read_uint32_t() != 0x61746164) + return; + w_t.size = s.read_uint32_t(); + w_t.header_size = (int32_t)s.get_position(); + w_t.is_supported = true; + *w = w_t; + + samples = w->size / w->channels / w->bytes; + data = force_malloc_s(float_t, w->size / w->bytes); + + size_t t_s = samples; + float_t* t_d = data; + + size_t ch = w->channels; + if (w->bytes == 0x01 && w->format == 0x01) + for (size_t i = 0; i < t_s; i++) + for (size_t c = 0; c < ch; c++) { + double_t sample = s.read_int8_t(); + sample = div_min_max_def(sample, -128.0, 127.0); + t_d[i * ch + c] = (float_t)sample; + } + else if (w->bytes == 0x02 && (w->format == 0x01 || w->format == 0xFFFE)) + for (size_t i = 0; i < t_s; i++) + for (size_t c = 0; c < ch; c++) { + double_t sample = s.read_int16_t(); + sample = div_min_max_def(sample, -32768.0, 32767.0); + t_d[i * ch + c] = (float_t)sample; + } + else if (w->bytes == 0x03 && w->format == 0x01) + for (size_t i = 0; i < t_s; i++) + for (size_t c = 0; c < ch; c++) { + int32_t samp; + s.read(&samp, 3); + double_t sample = (samp << 8) >> 8; + sample = div_min_max_def(sample, -8388608.0, 8388607.0); + t_d[i * ch + c] = (float_t)sample; + } + else if (w->bytes == 0x04 && w->format == 0x01) + for (size_t i = 0; i < t_s; i++) + for (size_t c = 0; c < ch; c++) { + double_t sample = s.read_int32_t(); + sample = div_min_max_def(sample, -2147483648.0, 2147483647.0); + t_d[i * ch + c] = (float_t)sample; + } + else if (w->bytes == 0x04 && (w->format == 0x03 || w->format == 0xFFFE)) + for (size_t i = 0; i < t_s; i++) + for (size_t c = 0; c < ch; c++) { + float_t sample = s.read_float_t(); + t_d[i * ch + c] = sample; + } + else if (w->bytes == 0x08 && (w->format == 0x03 || w->format == 0xFFFE)) + for (size_t i = 0; i < t_s; i++) + for (size_t c = 0; c < ch; c++) { + double_t sample = s.read_double_t(); + t_d[i * ch + c] = (float_t)sample; + } } -void wav_write(wav* w, const char* path, float_t* data, size_t samples) { - wchar_t* path_buf = utf8_to_utf16(path); - wav_write(w, path_buf, data, samples); - free(path_buf); -} +static void wav_write_inner(wav* w, stream& s, const float_t* data, size_t samples) { + w->size = (int32_t)(samples * w->channels * w->bytes); -void wav_write(wav* w, const wchar_t* path, float_t* data, size_t samples) { - stream s; - s.open(path, L"wb"); - if (s.io.stream && data) { - w->size = (int32_t)(samples * w->channels * w->bytes); + if (w->bytes == 0x01 && w->format == 0x01); + else if (w->bytes == 0x02 && w->format == 0x01); + else if (w->bytes == 0x04 && w->format == 0x01); + else if (w->bytes == 0x04 && (w->format == 0x03 || w->format == 0xFFFE)); + else if (w->bytes == 0x08 && (w->format == 0x03 || w->format == 0xFFFE)); + else + w->size = 0; - if (w->bytes == 0x01 && w->format == 0x01); - else if (w->bytes == 0x02 && w->format == 0x01); - else if (w->bytes == 0x04 && w->format == 0x01); - else if (w->bytes == 0x04 && (w->format == 0x03 || w->format == 0xFFFE)); - else if (w->bytes == 0x08 && (w->format == 0x03 || w->format == 0xFFFE)); - else - w->size = 0; - - s.write_uint32_t(0x46464952); - s.write_uint32_t(w->size + (w->format != 0xFFFE ? 0x24 : 0x3C)); - s.write_uint32_t(0x45564157); - s.write_uint32_t(0x20746D66); - s.write_uint32_t(w->format != 0xFFFE ? 0x10 : 0x28); - s.write_uint16_t(w->format); - s.write_uint16_t(w->channels); - s.write_uint32_t(w->sample_rate); - s.write_uint32_t(w->sample_rate * w->channels * w->bytes); - s.write_uint16_t((uint16_t)(w->channels * w->bytes)); + s.write_uint32_t(0x46464952); + s.write_uint32_t(w->size + (w->format != 0xFFFE ? 0x24 : 0x3C)); + s.write_uint32_t(0x45564157); + s.write_uint32_t(0x20746D66); + s.write_uint32_t(w->format != 0xFFFE ? 0x10 : 0x28); + s.write_uint16_t(w->format); + s.write_uint16_t(w->channels); + s.write_uint32_t(w->sample_rate); + s.write_uint32_t(w->sample_rate * w->channels * w->bytes); + s.write_uint16_t((uint16_t)(w->channels * w->bytes)); + s.write_uint16_t((uint16_t)(w->bytes << 3)); + if (w->format == 0xFFFE) { + s.write_uint16_t(0x16); s.write_uint16_t((uint16_t)(w->bytes << 3)); - if (w->format == 0xFFFE) { - s.write_uint16_t(0x16); - s.write_uint16_t((uint16_t)(w->bytes << 3)); - s.write_uint32_t(w->channel_mask); - s.write_uint32_t(w->bytes == 2 ? 0x01 : 0x03); - s.write_uint32_t(0x00100000); - s.write_uint32_t(0xAA000080); - s.write_uint32_t(0x719B3800); - } - s.write_uint32_t(0x61746164); - s.write_uint32_t(w->size); - - size_t ch = w->channels; - if (w->bytes == 0x01 && w->format == 0x01) - for (size_t i = 0; i < samples; i++) - for (size_t c = 0; c < ch; c++) { - double_t sample = data[i * ch + c]; - sample = clamp(sample, -1.0, 1.0); - sample = mult_min_max(sample, -128.0, 127.0); - s.write_int8_t((int8_t)round(sample)); - } - else if (w->bytes == 0x02 && (w->format == 0x01 || w->format == 0xFFFE)) - for (size_t i = 0; i < samples; i++) - for (size_t c = 0; c < ch; c++) { - double_t sample = data[i * ch + c]; - sample = clamp(sample, -1.0, 1.0); - sample = mult_min_max(sample, -32768.0, 32767.0); - s.write_int16_t((int16_t)round(sample)); - } - else if (w->bytes == 0x03 && w->format == 0x01) - for (size_t i = 0; i < samples; i++) - for (size_t c = 0; c < ch; c++) { - double_t sample = data[i * ch + c]; - sample = clamp(sample, -1.0, 1.0); - sample = mult_min_max(sample, -8388608.0, 8388607.0); - int32_t samp = (int32_t)round(sample); - s.write(&samp, 3); - } - else if (w->bytes == 0x04 && w->format == 0x01) - for (size_t i = 0; i < samples; i++) - for (size_t c = 0; c < ch; c++) { - double_t sample = data[i * ch + c]; - sample = clamp(sample, -1.0, 1.0); - sample = mult_min_max(sample, -2147483648.0, 2147483647.0); - s.write_int32_t((int32_t)round(sample)); - } - else if (w->bytes == 0x04 && (w->format == 0x03 || w->format == 0xFFFE)) - for (size_t i = 0; i < samples; i++) - for (size_t c = 0; c < ch; c++) { - float_t sample = data[i * ch + c]; - s.write_float_t(sample); - } - else if (w->bytes == 0x08 && (w->format == 0x03 || w->format == 0xFFFE)) - for (size_t i = 0; i < samples; i++) - for (size_t c = 0; c < ch; c++) { - double_t sample = data[i * ch + c]; - s.write_double_t(sample); - } + s.write_uint32_t(w->channel_mask); + s.write_uint32_t(w->bytes == 2 ? 0x01 : 0x03); + s.write_uint32_t(0x00100000); + s.write_uint32_t(0xAA000080); + s.write_uint32_t(0x719B3800); } -} + s.write_uint32_t(0x61746164); + s.write_uint32_t(w->size); -void wav_dispose(wav* f) { - free(f); -} \ No newline at end of file + size_t ch = w->channels; + if (w->bytes == 0x01 && w->format == 0x01) + for (size_t i = 0; i < samples; i++) + for (size_t c = 0; c < ch; c++) { + double_t sample = data[i * ch + c]; + sample = clamp_def(sample, -1.0, 1.0); + sample = mult_min_max_def(sample, -128.0, 127.0); + s.write_int8_t((int8_t)round(sample)); + } + else if (w->bytes == 0x02 && (w->format == 0x01 || w->format == 0xFFFE)) + for (size_t i = 0; i < samples; i++) + for (size_t c = 0; c < ch; c++) { + double_t sample = data[i * ch + c]; + sample = clamp_def(sample, -1.0, 1.0); + sample = mult_min_max_def(sample, -32768.0, 32767.0); + s.write_int16_t((int16_t)round(sample)); + } + else if (w->bytes == 0x03 && w->format == 0x01) + for (size_t i = 0; i < samples; i++) + for (size_t c = 0; c < ch; c++) { + double_t sample = data[i * ch + c]; + sample = clamp_def(sample, -1.0, 1.0); + sample = mult_min_max_def(sample, -8388608.0, 8388607.0); + int32_t samp = (int32_t)round(sample); + s.write(&samp, 3); + } + else if (w->bytes == 0x04 && w->format == 0x01) + for (size_t i = 0; i < samples; i++) + for (size_t c = 0; c < ch; c++) { + double_t sample = data[i * ch + c]; + sample = clamp_def(sample, -1.0, 1.0); + sample = mult_min_max_def(sample, -2147483648.0, 2147483647.0); + s.write_int32_t((int32_t)round(sample)); + } + else if (w->bytes == 0x04 && (w->format == 0x03 || w->format == 0xFFFE)) + for (size_t i = 0; i < samples; i++) + for (size_t c = 0; c < ch; c++) { + float_t sample = data[i * ch + c]; + s.write_float_t(sample); + } + else if (w->bytes == 0x08 && (w->format == 0x03 || w->format == 0xFFFE)) + for (size_t i = 0; i < samples; i++) + for (size_t c = 0; c < ch; c++) { + double_t sample = data[i * ch + c]; + s.write_double_t(sample); + } +} diff --git a/src/KKdLib/sound/wav.hpp b/src/KKdLib/sound/wav.hpp index ba35244e..e39d0f8d 100644 --- a/src/KKdLib/sound/wav.hpp +++ b/src/KKdLib/sound/wav.hpp @@ -16,11 +16,12 @@ struct wav { uint16_t bytes; uint16_t format; uint16_t channels; -}; -extern wav* wav_init(); -extern void wav_read(wav* w, const char* path, float_t** data, size_t* samples); -extern void wav_read(wav* w, const wchar_t* path, float_t** data, size_t* samples); -extern void wav_write(wav* w, const char* path, float_t* data, size_t samples); -extern void wav_write(wav* w, const wchar_t* path, float_t* data, size_t samples); -extern void wav_dispose(wav* w); + wav(); + virtual ~wav(); + + void read(const char* path, float_t*& data, size_t& samples); + void read(const wchar_t* path, float_t*& data, size_t& samples); + void write(const char* path, const float_t* data, size_t samples); + void write(const wchar_t* path, const float_t* data, size_t samples); +}; diff --git a/src/KKdLib/str_utils.cpp b/src/KKdLib/str_utils.cpp index 32f40127..fc06153e 100644 --- a/src/KKdLib/str_utils.cpp +++ b/src/KKdLib/str_utils.cpp @@ -419,14 +419,6 @@ wchar_t* str_utils_copy(const wchar_t* str) { return p; } -inline int32_t str_utils_compare(const char* str0, const char* str1) { - return strcmp(str0, str1); -} - -inline int32_t str_utils_compare(const wchar_t* str0, const wchar_t* str1) { - return wcscmp(str0, str1); -} - inline int32_t str_utils_compare_length(const char* str0, size_t str0_len, const char* str1, size_t str1_len) { if (!str0_len) return -*str1; @@ -550,16 +542,16 @@ size_t str_utils_get_substring_offset(const wchar_t* str0, size_t str0_len, } bool str_utils_text_file_parse(const void* data, size_t size, - char** buf, char*** lines, size_t* count) { - if (!data || !size || !buf || !lines || !count) + char*& buf, char**& lines, size_t& count) { + if (!data || !size) return false; const char* d = (const char*)data; bool del = false; size_t c; - *buf = 0; - *lines = 0; - *count = 0; + buf = 0; + lines = 0; + count = 0; if ((uint8_t)d[0] == 0x00) return false; else if (d[0] == 0xFF) { @@ -584,7 +576,7 @@ bool str_utils_text_file_parse(const void* data, size_t size, d = utf16_to_utf8(w_d); size = utf8_length(d); del = true; - free(w_d); + free_def(w_d); goto decode_utf8_ansi; } else if ((uint8_t)d[0] == 0xEF) { @@ -681,14 +673,14 @@ bool str_utils_text_file_parse(const void* data, size_t size, } } - *buf = temp_buf; - *lines = temp_lines; - *count = c; + buf = temp_buf; + lines = temp_lines; + count = c; } if (del) { void* data = (void*)d; - free(data); + free_def(data); } return true; } diff --git a/src/KKdLib/str_utils.hpp b/src/KKdLib/str_utils.hpp index 021d34e0..798c01e8 100644 --- a/src/KKdLib/str_utils.hpp +++ b/src/KKdLib/str_utils.hpp @@ -8,6 +8,14 @@ #include #include "default.hpp" +inline int32_t str_utils_compare(const char* str0, const char* str1) { + return strcmp(str0, str1); +} + +inline int32_t str_utils_compare(const wchar_t* str0, const wchar_t* str1) { + return wcscmp(str0, str1); +} + extern bool str_utils_check_ends_with(const char* str, const char* mask); extern bool str_utils_check_ends_with(const wchar_t* str, const wchar_t* mask); extern const char* str_utils_get_next_int32_t(const char* str, int32_t& value, char separator); @@ -40,8 +48,6 @@ extern char* str_utils_add(const char* str0, const char* str1); extern wchar_t* str_utils_add(const wchar_t* str0, const wchar_t* str1); extern char* str_utils_copy(const char* str); extern wchar_t* str_utils_copy(const wchar_t* str); -extern int32_t str_utils_compare(const char* str0, const char* str1); -extern int32_t str_utils_compare(const wchar_t* str0, const wchar_t* str1); extern int32_t str_utils_compare_length(const char* str0, size_t str0_len, const char* str1, size_t str1_len); extern int32_t str_utils_compare_length(const wchar_t* str0, size_t str0_len, const wchar_t* str1, size_t str1_len); extern size_t str_utils_get_substring_offset(const char* str0, size_t str0_len, @@ -49,4 +55,4 @@ extern size_t str_utils_get_substring_offset(const char* str0, size_t str0_len, extern size_t str_utils_get_substring_offset(const wchar_t* str0, size_t str0_len, size_t str0_off, const wchar_t* str1, size_t str1_len); extern bool str_utils_text_file_parse(const void* data, size_t size, - char** buf, char*** lines, size_t* count); + char*& buf, char**& lines, size_t& count); diff --git a/src/KKdLib/txp.cpp b/src/KKdLib/txp.cpp index 873392ac..198ec97e 100644 --- a/src/KKdLib/txp.cpp +++ b/src/KKdLib/txp.cpp @@ -5,7 +5,7 @@ #include "txp.hpp" #include "f2/struct.hpp" -#include "io/stream.hpp" +#include "io/memory_stream.hpp" txp_mipmap::txp_mipmap() : width(), height(), format(), size() { @@ -116,9 +116,9 @@ bool txp_set::pack_file(void** data, size_t* size, bool big_endian) { } } - stream s; + memory_stream s; s.open(0, l); - s.is_big_endian = big_endian; + s.big_endian = big_endian; s.write_uint32_t_reverse_endianness(0x03505854); s.write_uint32_t_reverse_endianness((uint32_t)count); s.write_uint32_t_reverse_endianness((uint8_t)count | 0x01010100); @@ -157,9 +157,9 @@ bool txp_set::pack_file(void** data, size_t* size, bool big_endian) { s.copy(data, size); for (size_t i = 0; i < count; i++) - free(txp2_offset[i]); - free(txp2_offset); - free(txp4_offset); + free_def(txp2_offset[i]); + free_def(txp2_offset); + free_def(txp4_offset); return true; } @@ -198,9 +198,9 @@ bool txp_set::pack_file(std::vector& data, bool big_endian) { } } - stream s; + memory_stream s; s.open(0, l); - s.is_big_endian = big_endian; + s.big_endian = big_endian; s.write_uint32_t_reverse_endianness(0x03505854); s.write_uint32_t_reverse_endianness((uint32_t)count); s.write_uint32_t_reverse_endianness((uint8_t)count | 0x01010100); @@ -239,9 +239,9 @@ bool txp_set::pack_file(std::vector& data, bool big_endian) { s.copy(data); for (size_t i = 0; i < count; i++) - free(txp2_offset[i]); - free(txp2_offset); - free(txp4_offset); + free_def(txp2_offset[i]); + free_def(txp2_offset); + free_def(txp4_offset); return true; } @@ -405,7 +405,7 @@ bool txp_set::unpack_file(const void* data, bool big_endian) { } ssize_t size = txp::get_size(tex_mipmap->format, tex_mipmap->width, tex_mipmap->height); - tex_mipmap->data.resize(max(size, tex_mipmap->size)); + tex_mipmap->data.resize(max_def(size, tex_mipmap->size)); memcpy(tex_mipmap->data.data(), (void*)(mipmap_d + 24), tex_mipmap->size); size -= tex_mipmap->size; if (size > 0) diff --git a/src/KKdLib/vec.cpp b/src/KKdLib/vec.cpp index 19ea7c26..774d38d8 100644 --- a/src/KKdLib/vec.cpp +++ b/src/KKdLib/vec.cpp @@ -5,9 +5,9 @@ #include "vec.hpp" -const __m128 vec2_negate = { -0.0f, -0.0f, 0.0f, 0.0f }; -const __m128 vec3_negate = { -0.0f, -0.0f, -0.0f, 0.0f }; -const __m128 vec4_negate = { -0.0f, -0.0f, -0.0f, -0.0f }; +const __m128 vec2_neg = { -0.0f, -0.0f, 0.0f, 0.0f }; +const __m128 vec3_neg = { -0.0f, -0.0f, -0.0f, 0.0f }; +const __m128 vec4_neg = { -0.0f, -0.0f, -0.0f, -0.0f }; const vec4i vec4_mask_vec2 = { (int32_t)0xFFFFFFFF, (int32_t)0xFFFFFFFF, (int32_t)0x00000000, (int32_t)0x00000000 }; const vec4i vec4_mask_vec3 = { (int32_t)0xFFFFFFFF, (int32_t)0xFFFFFFFF, (int32_t)0xFFFFFFFF, (int32_t)0x00000000 }; diff --git a/src/KKdLib/vec.hpp b/src/KKdLib/vec.hpp index bbfbbffd..543b1d91 100644 --- a/src/KKdLib/vec.hpp +++ b/src/KKdLib/vec.hpp @@ -9,6 +9,8 @@ #include "half_t.hpp" #include #include +#include +#include struct vec2i8 { int8_t x; @@ -284,17 +286,34 @@ struct vec2 { float_t x; float_t y; - inline vec2() : x(), y() { + vec2(); + vec2(float_t value); + vec2(float_t x, float_t y); - } + static __m128 load_xmm(const float_t data); + static __m128 load_xmm(const vec2& data); + static __m128 load_xmm(const vec2&& data); + static vec2 store_xmm(const __m128& data); + static vec2 store_xmm(const __m128&& data); - inline vec2(float_t value) : x(value), y(value) { - - } - - inline vec2(float_t x, float_t y) : x(x), y(y) { - - } + static float_t angle(const vec2& left, const vec2& right); + static float_t dot(const vec2& left, const vec2& right); + static float_t length(const vec2& left); + static float_t length_squared(const vec2& left); + static float_t distance(const vec2& left, const vec2& right); + static float_t distance_squared(const vec2& left, const vec2& right); + static vec2 lerp(const vec2& left, const vec2& right, const vec2& blend); + static vec2 lerp(const vec2& left, const vec2& right, const float_t blend); + static vec2 normalize(const vec2& left); + static vec2 rcp(const vec2& left); + static vec2 min(const vec2& left, const vec2& right); + static vec2 max(const vec2& left, const vec2& right); + static vec2 clamp(const vec2& left, const vec2& min, const vec2& max); + static vec2 clamp(const vec2& left, const float_t min, const float_t max); + static vec2 mult_min_max(const vec2& left, const vec2& min, const vec2& max); + static vec2 mult_min_max(const vec2& left, const float_t min, const float_t max); + static vec2 div_min_max(const vec2& left, const vec2& min, const vec2& max); + static vec2 div_min_max(const vec2& left, const float_t min, const float_t max); }; struct vec3 { @@ -302,17 +321,35 @@ struct vec3 { float_t y; float_t z; - inline vec3() : x(), y(), z() { + vec3(); + vec3(float_t value); + vec3(float_t x, float_t y, float_t z); - } + static __m128 load_xmm(const float_t data); + static __m128 load_xmm(const vec3& data); + static __m128 load_xmm(const vec3&& data); + static vec3 store_xmm(const __m128& data); + static vec3 store_xmm(const __m128&& data); - inline vec3(float_t value) : x(value), y(value), z(value) { - - } - - inline vec3(float_t x, float_t y, float_t z) : x(x), y(y), z(z) { - - } + static float_t angle(const vec3& left, const vec3& right); + static float_t dot(const vec3& left, const vec3& right); + static float_t length(const vec3& left); + static float_t length_squared(const vec3& left); + static float_t distance(const vec3& left, const vec3& right); + static float_t distance_squared(const vec3& left, const vec3& right); + static vec3 lerp(const vec3& left, const vec3& right, const vec3& blend); + static vec3 lerp(const vec3& left, const vec3& right, const float_t blend); + static vec3 normalize(const vec3& left); + static vec3 rcp(const vec3& left); + static vec3 min(const vec3& left, const vec3& right); + static vec3 max(const vec3& left, const vec3& right); + static vec3 clamp(const vec3& left, const vec3& min, const vec3& max); + static vec3 clamp(const vec3& left, const float_t min, const float_t max); + static vec3 mult_min_max(const vec3& left, const vec3& min, const vec3& max); + static vec3 mult_min_max(const vec3& left, const float_t min, const float_t max); + static vec3 div_min_max(const vec3& left, const vec3& min, const vec3& max); + static vec3 div_min_max(const vec3& left, const float_t min, const float_t max); + static vec3 cross(const vec3& left, const vec3& right); }; struct vec4 { @@ -321,34 +358,54 @@ struct vec4 { float_t z; float_t w; - inline vec4() : x(), y(), z(), w() { + vec4(); + vec4(float_t value); + vec4(float_t x, float_t y, float_t z, float_t w); - } + static __m128 load_xmm(const float_t data); + static __m128 load_xmm(const vec4& data); + static __m128 load_xmm(const vec4&& data); + static vec4 store_xmm(const __m128& data); + static vec4 store_xmm(const __m128&& data); - inline vec4(float_t value) : x(value), y(value), z(value), w(value) { - - } - - inline vec4(float_t x, float_t y, float_t z, float_t w) : x(x), y(y), z(z), w(w) { - - } + static float_t angle(const vec4& left, const vec4& right); + static float_t dot(const vec4& left, const vec4& right); + static float_t length(const vec4& left); + static float_t length_squared(const vec4& left); + static float_t distance(const vec4& left, const vec4& right); + static float_t distance_squared(const vec4& left, const vec4& right); + static vec4 lerp(const vec4& left, const vec4& right, const vec4& blend); + static vec4 lerp(const vec4& left, const vec4& right, const float_t blend); + static vec4 normalize(const vec4& left); + static vec4 rcp(const vec4& left); + static vec4 min(const vec4& min, const vec4& max); + static vec4 max(const vec4& min, const vec4& max); + static vec4 clamp(const vec4& left, const vec4& min, const vec4& max); + static vec4 clamp(const vec4& left, const float_t min, const float_t max); + static vec4 mult_min_max(const vec4& left, const vec4& min, const vec4& max); + static vec4 mult_min_max(const vec4& left, const float_t min, const float_t max); + static vec4 div_min_max(const vec4& left, const vec4& min, const vec4& max); + static vec4 div_min_max(const vec4& left, const float_t min, const float_t max); }; struct vec2i { int32_t x; int32_t y; - inline vec2i() : x(), y() { + vec2i(); + vec2i(int32_t value); + vec2i(int32_t x, int32_t y); - } + static __m128i load_xmm(const int32_t data); + static __m128i load_xmm(const vec2i& data); + static __m128i load_xmm(const vec2i&& data); + static vec2i store_xmm(const __m128i& data); + static vec2i store_xmm(const __m128i&& data); - inline vec2i(int32_t value) : x(value), y(value) { - - } - - inline vec2i(int32_t x, int32_t y) : x(x), y(y) { - - } + static vec2i min(const vec2i& left, const vec2i& right); + static vec2i max(const vec2i& left, const vec2i& right); + static vec2i clamp(const vec2i& left, const vec2i& min, const vec2i& max); + static vec2i clamp(const vec2i& left, const int32_t min, const int32_t max); }; struct vec3i { @@ -356,17 +413,20 @@ struct vec3i { int32_t y; int32_t z; - inline vec3i() : x(), y(), z() { + vec3i(); + vec3i(int32_t value); + vec3i(int32_t x, int32_t y, int32_t z); - } + static __m128i load_xmm(const int32_t data); + static __m128i load_xmm(const vec3i& data); + static __m128i load_xmm(const vec3i&& data); + static vec3i store_xmm(const __m128i& data); + static vec3i store_xmm(const __m128i&& data); - inline vec3i(int32_t value) : x(value), y(value), z(value) { - - } - - inline vec3i(int32_t x, int32_t y, int32_t z) : x(x), y(y), z(z) { - - } + static vec3i min(const vec3i& left, const vec3i& right); + static vec3i max(const vec3i& left, const vec3i& right); + static vec3i clamp(const vec3i& left, const vec3i& min, const vec3i& max); + static vec3i clamp(const vec3i& left, const int32_t min, const int32_t max); }; struct vec4i { @@ -375,28 +435,29 @@ struct vec4i { int32_t z; int32_t w; - inline vec4i() : x(), y(), z(), w() { + vec4i(); + vec4i(int32_t value); + vec4i(int32_t x, int32_t y, int32_t z, int32_t w); - } + static __m128i load_xmm(const int32_t data); + static __m128i load_xmm(const vec4i& data); + static __m128i load_xmm(const vec4i&& data); + static vec4i store_xmm(const __m128i& data); + static vec4i store_xmm(const __m128i&& data); - inline vec4i(int32_t value) : x(value), y(value), z(value), w(value) { - - } - - inline vec4i(int32_t x, int32_t y, int32_t z, int32_t w) : x(x), y(y), z(z), w(w) { - - } + static vec4i min(const vec4i& left, const vec4i& right); + static vec4i max(const vec4i& left, const vec4i& right); + static vec4i clamp(const vec4i& left, const vec4i& min, const vec4i& max); + static vec4i clamp(const vec4i& left, const int32_t min, const int32_t max); }; -extern const __m128 vec2_negate; -extern const __m128 vec3_negate; -extern const __m128 vec4_negate; +extern const __m128 vec2_neg; +extern const __m128 vec3_neg; +extern const __m128 vec4_neg; extern const vec4i vec4_mask_vec2; extern const vec4i vec4_mask_vec3; -extern const __m128 vec4_negate; - extern const vec2 vec2_identity; extern const vec3 vec3_identity; extern const vec4 vec4_identity; @@ -408,1463 +469,1922 @@ extern const vec4 vec4_null; extern const vec2i vec2i_null; extern const vec3i vec3i_null; extern const vec4i vec4i_null; -#define vec2i8_to_vec2(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; - -#define vec3i8_to_vec3(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; \ -(dst).z = (float_t)(src).z; - -#define vec4i8_to_vec4(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; \ -(dst).z = (float_t)(src).z; \ -(dst).w = (float_t)(src).w; - -#define vec2_to_vec2i8(src, dst) \ -(dst).x = (int8_t)(src).x; \ -(dst).y = (int8_t)(src).y; - -#define vec3_to_vec3i8(src, dst) \ -(dst).x = (int8_t)(src).x; \ -(dst).y = (int8_t)(src).y; \ -(dst).z = (int8_t)(src).z; - -#define vec4_to_vec4i8(src, dst) \ -(dst).x = (int8_t)(src).x; \ -(dst).y = (int8_t)(src).y; \ -(dst).z = (int8_t)(src).z; \ -(dst).w = (int8_t)(src).w; - -#define vec2u8_to_vec2(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; - -#define vec3u8_to_vec3(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; \ -(dst).z = (float_t)(src).z; - -#define vec4u8_to_vec4(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; \ -(dst).z = (float_t)(src).z; \ -(dst).w = (float_t)(src).w; - -#define vec2_to_vec2u8(src, dst) \ -(dst).x = (uint8_t)(src).x; \ -(dst).y = (uint8_t)(src).y; - -#define vec3_to_vec3u8(src, dst) \ -(dst).x = (uint8_t)(src).x; \ -(dst).y = (uint8_t)(src).y; \ -(dst).z = (uint8_t)(src).z; - -#define vec4_to_vec4u8(src, dst) \ -(dst).x = (uint8_t)(src).x; \ -(dst).y = (uint8_t)(src).y; \ -(dst).z = (uint8_t)(src).z; \ -(dst).w = (uint8_t)(src).w; - -#define vec2i16_to_vec2(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; - -#define vec3i16_to_vec3(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; \ -(dst).z = (float_t)(src).z; - -#define vec4i16_to_vec4(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; \ -(dst).z = (float_t)(src).z; \ -(dst).w = (float_t)(src).w; - -#define vec2_to_vec2i16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; - -#define vec3_to_vec3i16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; \ -(dst).z = (uint16_t)(src).z; - -#define vec4_to_vec4i16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; \ -(dst).z = (uint16_t)(src).z; \ -(dst).w = (uint16_t)(src).w; - -#define vec2u16_to_vec2(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; - -#define vec3u16_to_vec3(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; \ -(dst).z = (float_t)(src).z; - -#define vec4u16_to_vec4(src, dst) \ -(dst).x = (float_t)(src).x; \ -(dst).y = (float_t)(src).y; \ -(dst).z = (float_t)(src).z; \ -(dst).w = (float_t)(src).w; - -#define vec2_to_vec2u16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; - -#define vec3_to_vec3u16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; \ -(dst).z = (uint16_t)(src).z; - -#define vec4_to_vec4u16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; \ -(dst).z = (uint16_t)(src).z; \ -(dst).w = (uint16_t)(src).w; - -#define vec2h_to_vec2(src, dst) \ -(dst).x = half_to_float((src).x); \ -(dst).y = half_to_float((src).y); - -#define vec3h_to_vec3(src, dst) \ -(dst).x = half_to_float((src).x); \ -(dst).y = half_to_float((src).y); \ -(dst).z = half_to_float((src).z); - -#define vec4h_to_vec4(src, dst) \ -(dst).x = half_to_float((src).x); \ -(dst).y = half_to_float((src).y); \ -(dst).z = half_to_float((src).z); \ -(dst).w = half_to_float((src).w); - -#define vec2_to_vec2h(src, dst) \ -(dst).x = float_to_half((src).x); \ -(dst).y = float_to_half((src).y); - -#define vec3_to_vec3h(src, dst) \ -(dst).x = float_to_half((src).x); \ -(dst).y = float_to_half((src).y); \ -(dst).z = float_to_half((src).z); - -#define vec4_to_vec4h(src, dst) \ -(dst).x = float_to_half((src).x); \ -(dst).y = float_to_half((src).y); \ -(dst).z = float_to_half((src).z); \ -(dst).w = float_to_half((src).w); - -#define vec2i8_to_vec2i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; - -#define vec3i8_to_vec3i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; \ -(dst).z = (int32_t)(src).z; - -#define vec4i8_to_vec4i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; \ -(dst).z = (int32_t)(src).z; \ -(dst).w = (int32_t)(src).w; - -#define vec2i_to_vec2i8(src, dst) \ -(dst).x = (int8_t)(src).x; \ -(dst).y = (int8_t)(src).y; - -#define vec3i_to_vec3i8(src, dst) \ -(dst).x = (int8_t)(src).x; \ -(dst).y = (int8_t)(src).y; \ -(dst).z = (int8_t)(src).z; - -#define vec4i_to_vec4i8(src, dst) \ -(dst).x = (int8_t)(src).x; \ -(dst).y = (int8_t)(src).y; \ -(dst).z = (int8_t)(src).z; \ -(dst).w = (int8_t)(src).w; - -#define vec2u8_to_vec2i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; - -#define vec3u8_to_vec3i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; \ -(dst).z = (int32_t)(src).z; - -#define vec4u8_to_vec4i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; \ -(dst).z = (int32_t)(src).z; \ -(dst).w = (int32_t)(src).w; - -#define vec2i_to_vec2u8(src, dst) \ -(dst).x = (uint8_t)(src).x; \ -(dst).y = (uint8_t)(src).y; - -#define vec3i_to_vec3u8(src, dst) \ -(dst).x = (uint8_t)(src).x; \ -(dst).y = (uint8_t)(src).y; \ -(dst).z = (uint8_t)(src).z; - -#define vec4i_to_vec4u8(src, dst) \ -(dst).x = (uint8_t)(src).x; \ -(dst).y = (uint8_t)(src).y; \ -(dst).z = (uint8_t)(src).z; \ -(dst).w = (uint8_t)(src).w; - -#define vec2i16_to_vec2i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; - -#define vec3i16_to_vec3i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; \ -(dst).z = (int32_t)(src).z; - -#define vec4i16_to_vec4i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; \ -(dst).z = (int32_t)(src).z; \ -(dst).w = (int32_t)(src).w; - -#define vec2i_to_vec2i16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; - -#define vec3i_to_vec3i16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; \ -(dst).z = (uint16_t)(src).z; - -#define vec4i_to_vec4i16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; \ -(dst).z = (uint16_t)(src).z; \ -(dst).w = (uint16_t)(src).w; - -#define vec2u16_to_vec2i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; - -#define vec3u16_to_vec3i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; \ -(dst).z = (int32_t)(src).z; - -#define vec4u16_to_vec4i(src, dst) \ -(dst).x = (int32_t)(src).x; \ -(dst).y = (int32_t)(src).y; \ -(dst).z = (int32_t)(src).z; \ -(dst).w = (int32_t)(src).w; - -#define vec2i_to_vec2u16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; - -#define vec3i_to_vec3u16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; \ -(dst).z = (uint16_t)(src).z; - -#define vec4i_to_vec4u16(src, dst) \ -(dst).x = (uint16_t)(src).x; \ -(dst).y = (uint16_t)(src).y; \ -(dst).z = (uint16_t)(src).z; \ -(dst).w = (uint16_t)(src).w; - -#define vec2_add(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - zt = _mm_add_ps(xt, yt); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_add_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_add_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_sub(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - zt = _mm_sub_ps(xt, yt); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_sub_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_sub_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_mult(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - zt = _mm_mul_ps(xt, yt); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_mult_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_div(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - zt = _mm_div_ps(xt, yt); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_div_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_div_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_and(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - zt = _mm_and_ps(xt, yt); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_and_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_and_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_xor(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - zt = _mm_xor_ps(xt, yt); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_xor_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_xor_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_negate(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - zt = _mm_xor_ps(xt, vec2_negate); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_dot(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - zt = _mm_mul_ps(xt, yt); \ - (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ -} - -#define vec2_length(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - zt = _mm_mul_ps(xt, xt); \ - (z) = _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); \ -} - -#define vec2_length_squared(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - zt = _mm_mul_ps(xt, xt); \ - (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ -} - -#define vec2_distance(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - zt = _mm_sub_ps(xt, yt); \ - zt = _mm_mul_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); \ -} - -#define vec2_distance_squared(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - zt = _mm_sub_ps(xt, yt); \ - zt = _mm_mul_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ -} - -#define vec2_lerp(x, y, z, blend) \ -{ \ - __m128 b1; \ - __m128 b2; \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - *(vec3*)&b1 = (blend); \ - *(vec3*)&b2 = vec3_identity; \ - b2 = _mm_sub_ps(b2, b1); \ - zt = _mm_add_ps(_mm_mul_ps(xt, b2), _mm_mul_ps(yt, b1)); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_lerp_scalar(x, y, z, blend) \ -{ \ - __m128 b1; \ - __m128 b2; \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - *(vec2*)&yt = (y); \ - b1 = _mm_set_ss(blend); \ - b1 = _mm_shuffle_ps(b1, b1, 0); \ - *(vec2*)&b2 = vec2_identity; \ - b2 = _mm_sub_ps(b2, b1); \ - zt = _mm_add_ps(_mm_mul_ps(xt, b2), _mm_mul_ps(yt, b1)); \ - (z) = *(vec2*)&zt; \ -} - -#define vec2_normalize(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - *(vec2*)&xt = (x); \ - zt = _mm_mul_ps(xt, xt); \ - 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) = *(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, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - 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, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - wt = _mm_mul_ps(xt, wt); \ - (w) = *(vec2*)&wt; \ -} - -#define vec2_div_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, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - wt = _mm_div_ps(xt, wt); \ - (w) = *(vec2*)&wt; \ -} - -#define vec2_div_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, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - wt = _mm_div_ps(xt, wt); \ - (w) = *(vec2*)&wt; \ -} - -#define vec3_add(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - *(vec3*)&yt = (y); \ - zt = _mm_add_ps(xt, yt); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_add_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_add_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_sub(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - *(vec3*)&yt = (y); \ - zt = _mm_sub_ps(xt, yt); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_sub_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_sub_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_mult(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - *(vec3*)&yt = (y); \ - zt = _mm_mul_ps(xt, yt); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_mult_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_div(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - *(vec3*)&yt = (y); \ - zt = _mm_div_ps(xt, yt); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_div_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_div_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_and(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - *(vec3*)&yt = (y); \ - zt = _mm_and_ps(xt, yt); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_and_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_and_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_xor(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - *(vec3*)&yt = (y); \ - zt = _mm_xor_ps(xt, yt); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_xor_scalar(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - yt = _mm_set_ss(y); \ - zt = _mm_xor_ps(xt, _mm_shuffle_ps(yt, yt, 0)); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_negate(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - zt = _mm_xor_ps(xt, vec3_negate); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_dot(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - xt = _mm_and_ps(xt, _mm_loadu_ps((float*)&(vec4_mask_vec3))); \ - *(vec3*)&yt = (y); \ - yt = _mm_and_ps(yt, _mm_loadu_ps((float*)&(vec4_mask_vec3))); \ - zt = _mm_mul_ps(xt, yt); \ - zt = _mm_hadd_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ -} - -#define vec3_length(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - xt = _mm_and_ps(xt, _mm_loadu_ps((float*)&(vec4_mask_vec3))); \ - zt = _mm_mul_ps(xt, xt); \ - zt = _mm_hadd_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); \ -} - -#define vec3_length_squared(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - xt = _mm_and_ps(xt, _mm_loadu_ps((float*)&(vec4_mask_vec3))); \ - zt = _mm_mul_ps(xt, xt); \ - zt = _mm_hadd_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ -} - -#define vec3_distance(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - xt = _mm_and_ps(xt, _mm_loadu_ps((float*)&(vec4_mask_vec3))); \ - *(vec3*)&yt = (y); \ - yt = _mm_and_ps(yt, _mm_loadu_ps((float*)&(vec4_mask_vec3))); \ - zt = _mm_sub_ps(xt, yt); \ - zt = _mm_mul_ps(zt, zt); \ - zt = _mm_hadd_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); \ -} - -#define vec3_distance_squared(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - xt = _mm_and_ps(xt, _mm_loadu_ps((float*)&(vec4_mask_vec3))); \ - *(vec3*)&yt = (y); \ - yt = _mm_and_ps(yt, _mm_loadu_ps((float*)&(vec4_mask_vec3))); \ - zt = _mm_sub_ps(xt, yt); \ - zt = _mm_mul_ps(zt, zt); \ - zt = _mm_hadd_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ -} - -#define vec3_lerp(x, y, z, blend) \ -{ \ - __m128 b1; \ - __m128 b2; \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - *(vec3*)&yt = (y); \ - *(vec3*)&b1 = (blend); \ - *(vec3*)&b2 = vec3_identity; \ - b2 = _mm_sub_ps(b2, b1); \ - zt = _mm_add_ps(_mm_mul_ps(xt, b2), _mm_mul_ps(yt, b1)); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_lerp_scalar(x, y, z, blend) \ -{ \ - __m128 b1; \ - __m128 b2; \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - *(vec3*)&yt = (y); \ - b1 = _mm_set_ss(blend); \ - b1 = _mm_shuffle_ps(b1, b1, 0); \ - *(vec3*)&b2 = vec3_identity; \ - b2 = _mm_sub_ps(b2, b1); \ - zt = _mm_add_ps(_mm_mul_ps(xt, b2), _mm_mul_ps(yt, b1)); \ - (z) = *(vec3*)&zt; \ -} - -#define vec3_normalize(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - xt = _mm_and_ps(xt, _mm_loadu_ps((float*)&(vec4_mask_vec3))); \ - 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) = *(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, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - 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, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - wt = _mm_mul_ps(xt, wt); \ - (w) = *(vec3*)&wt; \ -} - -#define vec3_div_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, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - wt = _mm_div_ps(xt, wt); \ - (w) = *(vec3*)&wt; \ -} - -#define vec3_div_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, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - wt = _mm_div_ps(xt, wt); \ - (w) = *(vec3*)&wt; \ -} - -#define vec3_cross(x, y, z) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - *(vec3*)&xt = (x); \ - *(vec3*)&yt = (y); \ - zt = _mm_sub_ps( \ - _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0x09)), \ - _mm_mul_ps(yt, _mm_shuffle_ps(xt, xt, 0x09)) \ - ); \ - zt = _mm_shuffle_ps(zt, zt, 0x09); \ - (z) = *(vec3*)&zt; \ -} - -#define vec4_add(x, y, z) \ -{ \ - _mm_storeu_ps((float*)&(z), _mm_add_ps(_mm_loadu_ps((float*)&(x)), _mm_loadu_ps((float*)&(y)))); \ -} - -#define vec4_add_scalar(x, y, z) \ -{ \ - __m128 yt; \ - yt = _mm_set_ss(y); \ - _mm_storeu_ps((float*)&(z), _mm_add_ps(_mm_loadu_ps((float*)&(x)), _mm_shuffle_ps(yt, yt, 0))); \ -} - -#define vec4_sub(x, y, z) \ -{ \ - _mm_storeu_ps((float*)&(z), _mm_sub_ps(_mm_loadu_ps((float*)&(x)), _mm_loadu_ps((float*)&(y)))); \ -} - -#define vec4_sub_scalar(x, y, z) \ -{ \ - __m128 yt; \ - yt = _mm_set_ss(y); \ - _mm_storeu_ps((float*)&(z), _mm_sub_ps(_mm_loadu_ps((float*)&(x)), _mm_shuffle_ps(yt, yt, 0))); \ -} - -#define vec4_mult(x, y, z) \ -{ \ - _mm_storeu_ps((float*)&(z), _mm_mul_ps(_mm_loadu_ps((float*)&(x)), _mm_loadu_ps((float*)&(y)))); \ -} - -#define vec4_mult_scalar(x, y, z) \ -{ \ - __m128 yt; \ - yt = _mm_set_ss(y); \ - _mm_storeu_ps((float*)&(z), _mm_mul_ps(_mm_loadu_ps((float*)&(x)), _mm_shuffle_ps(yt, yt, 0))); \ -} - -#define vec4_div(x, y, z) \ -{ \ - _mm_storeu_ps((float*)&(z), _mm_div_ps(_mm_loadu_ps((float*)&(x)), _mm_loadu_ps((float*)&(y)))); \ -} - -#define vec4_div_scalar(x, y, z) \ -{ \ - __m128 yt; \ - yt = _mm_set_ss(y); \ - _mm_storeu_ps((float*)&(z), _mm_div_ps(_mm_loadu_ps((float*)&(x)), _mm_shuffle_ps(yt, yt, 0))); \ -} - -#define vec4_and(x, y, z) \ -{ \ - _mm_storeu_ps((float*)&(z), _mm_and_ps(_mm_loadu_ps((float*)&(x)), _mm_loadu_ps((float*)&(y)))); \ -} - -#define vec4_and_scalar(x, y, z) \ -{ \ - __m128 yt; \ - yt = _mm_set_ss(y); \ - _mm_storeu_ps((float*)&(z), _mm_and_ps(_mm_loadu_ps((float*)&(x)), _mm_shuffle_ps(yt, yt, 0))); \ -} - -#define vec4_xor(x, y, z) \ -{ \ - _mm_storeu_ps((float*)&(z), _mm_xor_ps(_mm_loadu_ps((float*)&(x)), _mm_loadu_ps((float*)&(y)))); \ + +inline vec2::vec2() : x(), y() { + +} + +inline vec2::vec2(float_t value) : x(value), y(value) { + +} + +inline vec2::vec2(float_t x, float_t y) : x(x), y(y) { + +} + +inline __m128 vec2::load_xmm(const float_t data) { + __m128 _data = _mm_set_ss(data); + return _mm_shuffle_ps(_data, _data, 0); +} + +inline __m128 vec2::load_xmm(const vec2& data) { + return _mm_castsi128_ps(_mm_loadl_epi64((const __m128i*) & data)); +} + +inline __m128 vec2::load_xmm(const vec2&& data) { + return _mm_castsi128_ps(_mm_loadl_epi64((const __m128i*) & data)); +} + +inline vec2 vec2::store_xmm(const __m128& data) { + vec2 _data; + _mm_storel_epi64((__m128i*) & _data, _mm_castps_si128(data)); + return _data; +} + +inline vec2 vec2::store_xmm(const __m128&& data) { + vec2 _data; + _mm_storel_epi64((__m128i*) & _data, _mm_castps_si128(data)); + return _data; +} + +inline __m128 vec3::load_xmm(const float_t data) { + __m128 _data = _mm_set_ss(data); + return _mm_shuffle_ps(_data, _data, 0); +} + +inline __m128 vec3::load_xmm(const vec3& data) { + return _mm_movelh_ps(_mm_castsi128_ps(_mm_loadl_epi64((const __m128i*) & data)), _mm_set_ss(data.z)); +} + +inline __m128 vec3::load_xmm(const vec3&& data) { + return _mm_movelh_ps(_mm_castsi128_ps(_mm_loadl_epi64((const __m128i*) & data)), _mm_set_ss(data.z)); +} + +inline vec3 vec3::store_xmm(const __m128& data) { + vec3 _data; + _mm_storel_epi64((__m128i*) & _data, _mm_castps_si128(data)); + *(int32_t*)&_data.z = _mm_cvtsi128_si32(_mm_srli_si128(_mm_castps_si128(data), 8)); + return _data; +} + +inline vec3 vec3::store_xmm(const __m128&& data) { + vec3 _data; + _mm_storel_epi64((__m128i*) & _data, _mm_castps_si128(data)); + *(int32_t*)&_data.z = _mm_cvtsi128_si32(_mm_srli_si128(_mm_castps_si128(data), 8)); + return _data; +} + +inline __m128 vec4::load_xmm(const float_t data) { + __m128 _data = _mm_set_ss(data); + return _mm_shuffle_ps(_data, _data, 0); +} + +inline __m128 vec4::load_xmm(const vec4& data) { + return _mm_loadu_ps((const float*)&data); +} + +inline __m128 vec4::load_xmm(const vec4&& data) { + return _mm_loadu_ps((const float*)&data); +} + +inline vec4 vec4::store_xmm(const __m128& data) { + vec4 _data; + _mm_storeu_ps((float*)&_data, data); + return _data; +} + +inline vec4 vec4::store_xmm(const __m128&& data) { + vec4 _data; + _mm_storeu_ps((float*)&_data, data); + return _data; +} + +inline __m128i vec2i::load_xmm(const int32_t data) { + __m128i _data = _mm_cvtsi32_si128(data); + return _mm_shuffle_epi32(_data, 0); +} + +inline __m128i vec2i::load_xmm(const vec2i& data) { + return _mm_loadl_epi64((const __m128i*) & data); +} + +inline __m128i vec2i::load_xmm(const vec2i&& data) { + return _mm_loadl_epi64((const __m128i*) & data); +} + +inline vec2i vec2i::store_xmm(const __m128i& data) { + vec2i _data; + _mm_storel_epi64((__m128i*) & _data, data); + return _data; +} + +inline vec2i vec2i::store_xmm(const __m128i&& data) { + vec2i _data; + _mm_storel_epi64((__m128i*) & _data, data); + return _data; +} + +inline __m128i vec3i::load_xmm(const int32_t data) { + __m128i _data = _mm_cvtsi32_si128(data); + return _mm_shuffle_epi32(_data, 0); +} + +inline __m128i vec3i::load_xmm(const vec3i& data) { + return _mm_unpacklo_epi64(_mm_loadl_epi64((const __m128i*) & data), _mm_cvtsi32_si128(data.z)); +} + +inline __m128i vec3i::load_xmm(const vec3i&& data) { + return _mm_unpacklo_epi64(_mm_loadl_epi64((const __m128i*) & data), _mm_cvtsi32_si128(data.z)); +} + +inline vec3i vec3i::store_xmm(const __m128i& data) { + vec3i _data; + _mm_storel_epi64((__m128i*) & _data, data); + _data.z = _mm_cvtsi128_si32(_mm_srli_si128(data, 8)); + return _data; +} + +inline vec3i vec3i::store_xmm(const __m128i&& data) { + vec3i _data; + _mm_storel_epi64((__m128i*) & _data, data); + _data.z = _mm_cvtsi128_si32(_mm_srli_si128(data, 8)); + return _data; +} + +inline __m128i vec4i::load_xmm(const int32_t data) { + __m128i _data = _mm_cvtsi32_si128(data); + return _mm_shuffle_epi32(_data, 0); +} + +inline __m128i vec4i::load_xmm(const vec4i& data) { + return _mm_loadu_si128((const __m128i*)&data); +} + +inline __m128i vec4i::load_xmm(const vec4i&& data) { + return _mm_loadu_si128((const __m128i*)&data); +} + +inline vec4i vec4i::store_xmm(const __m128i& data) { + vec4i _data; + _mm_storeu_si128((__m128i*)&_data, data); + return _data; +} + +inline vec4i vec4i::store_xmm(const __m128i&& data) { + vec4i _data; + _mm_storeu_si128((__m128i*)&_data, data); + return _data; +} + +inline vec2 operator +(const vec2& left, const vec2& right) { + return vec2::store_xmm(_mm_add_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator +(const vec2& left, const float_t right) { + return vec2::store_xmm(_mm_add_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator +(const float_t left, const vec2& right) { + return vec2::store_xmm(_mm_add_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator +=(vec2& left, const vec2& right) { + left = vec2::store_xmm(_mm_add_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator +=(vec2& left, const float_t right) { + left = vec2::store_xmm(_mm_add_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator -(const vec2& left, const vec2& right) { + return vec2::store_xmm(_mm_sub_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator -(const vec2& left, const float_t right) { + return vec2::store_xmm(_mm_sub_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator -(const float_t left, const vec2& right) { + return vec2::store_xmm(_mm_sub_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator -=(vec2& left, const vec2& right) { + left = vec2::store_xmm(_mm_sub_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator -=(vec2& left, const float_t right) { + left = vec2::store_xmm(_mm_sub_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator *(const vec2& left, const vec2& right) { + return vec2::store_xmm(_mm_mul_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator *(const vec2& left, const float_t right) { + return vec2::store_xmm(_mm_mul_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator *(const float_t left, const vec2& right) { + return vec2::store_xmm(_mm_mul_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator *=(vec2& left, const vec2& right) { + left = vec2::store_xmm(_mm_mul_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator *=(vec2& left, const float_t right) { + left = vec2::store_xmm(_mm_mul_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator /(const vec2& left, const vec2& right) { + return vec2::store_xmm(_mm_div_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator /(const vec2& left, const float_t right) { + return vec2::store_xmm(_mm_div_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator /(const float_t left, const vec2& right) { + return vec2::store_xmm(_mm_div_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator /=(vec2& left, const vec2& right) { + left = vec2::store_xmm(_mm_div_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator /=(vec2& left, const float_t right) { + left = vec2::store_xmm(_mm_div_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator &(const vec2& left, const vec2& right) { + return vec2::store_xmm(_mm_and_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator &(const vec2& left, const float_t right) { + return vec2::store_xmm(_mm_and_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator &(const float_t left, const vec2& right) { + return vec2::store_xmm(_mm_and_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator &=(vec2& left, const vec2& right) { + left = vec2::store_xmm(_mm_and_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator &=(vec2& left, const float_t right) { + left = vec2::store_xmm(_mm_and_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator ^(const vec2& left, const vec2& right) { + return vec2::store_xmm(_mm_xor_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator ^(const vec2& left, const float_t right) { + return vec2::store_xmm(_mm_xor_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator ^(const float_t left, const vec2& right) { + return vec2::store_xmm(_mm_xor_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator ^=(vec2& left, const vec2& right) { + left = vec2::store_xmm(_mm_xor_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline void operator ^=(vec2& left, const float_t right) { + left = vec2::store_xmm(_mm_xor_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 operator -(const vec2& left) { + return vec2::store_xmm(_mm_xor_ps(vec2::load_xmm(left), vec2_neg)); +} + +inline float_t vec2::angle(const vec2& left, const vec2& right) { + return acosf(vec2::dot(left, right) / (vec2::length(left) * vec2::length(right))); +} + +inline float_t vec2::dot(const vec2& left, const vec2& right) { + __m128 zt; + zt = _mm_mul_ps(vec2::load_xmm(left), vec2::load_xmm(right)); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline float_t vec2::length(const vec2& left) { + __m128 xt; + __m128 zt; + xt = vec2::load_xmm(left); + zt = _mm_mul_ps(xt, xt); + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); +} + +inline float_t vec2::length_squared(const vec2& left) { + __m128 xt; + __m128 zt; + xt = vec2::load_xmm(left); + zt = _mm_mul_ps(xt, xt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline float_t vec2::distance(const vec2& left, const vec2& right) { + __m128 zt; + zt = _mm_sub_ps(vec2::load_xmm(left), vec2::load_xmm(right)); + zt = _mm_mul_ps(zt, zt); + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); +} + +inline float_t vec2::distance_squared(const vec2& left, const vec2& right) { + __m128 zt; + zt = _mm_sub_ps(vec2::load_xmm(left), vec2::load_xmm(right)); + zt = _mm_mul_ps(zt, zt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline vec2 vec2::lerp(const vec2& left, const vec2& right, const vec2& blend) { + __m128 b1; + __m128 b2; + b1 = vec2::load_xmm(blend); + b2 = _mm_sub_ps(vec2::load_xmm(1.0f), b1); + return vec2::store_xmm(_mm_add_ps(_mm_mul_ps(vec2::load_xmm(left), b2), + _mm_mul_ps(vec2::load_xmm(right), b1))); +} + +inline vec2 vec2::lerp(const vec2& left, const vec2& right, const float_t blend) { + __m128 b1; + __m128 b2; + b1 = vec2::load_xmm(blend); + b2 = _mm_sub_ps(vec2::load_xmm(1.0f), b1); + return vec2::store_xmm(_mm_add_ps(_mm_mul_ps(vec2::load_xmm(left), b2), + _mm_mul_ps(vec2::load_xmm(right), b1))); +} + +inline vec2 vec2::normalize(const vec2& left) { + __m128 xt; + __m128 zt; + xt = vec2::load_xmm(left); + zt = _mm_mul_ps(xt, xt); + 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]; + return vec2::store_xmm(_mm_mul_ps(xt, _mm_shuffle_ps(zt, zt, 0))); +} + +inline vec2 vec2::rcp(const vec2& left) { + return vec2::store_xmm(_mm_div_ps(vec2::load_xmm(1.0f), vec2::load_xmm(left))); +} + +inline vec2 vec2::min(const vec2& left, const vec2& right) { + return vec2::store_xmm(_mm_min_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 vec2::max(const vec2& left, const vec2& right) { + return vec2::store_xmm(_mm_max_ps(vec2::load_xmm(left), vec2::load_xmm(right))); +} + +inline vec2 vec2::clamp(const vec2& left, const vec2& min, const vec2& max) { + return vec2::store_xmm(_mm_min_ps(_mm_max_ps(vec2::load_xmm(left), + vec2::load_xmm(min)), vec2::load_xmm(max))); +} + +inline vec2 vec2::clamp(const vec2& left, const float_t min, const float_t max) { + return vec2::store_xmm(_mm_min_ps(_mm_max_ps(vec2::load_xmm(left), + vec2::load_xmm(min)), vec2::load_xmm(max))); +} + +inline vec2 vec2::mult_min_max(const vec2& left, const vec2& min, const vec2& max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec2::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec2::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec2::load_xmm(max)); + return vec2::store_xmm(_mm_mul_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec2 vec2::mult_min_max(const vec2& left, const float_t min, const float_t max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec2::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec2::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec2::load_xmm(max)); + return vec2::store_xmm(_mm_mul_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec2 vec2::div_min_max(const vec2& left, const vec2& min, const vec2& max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec2::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec2::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec2::load_xmm(max)); + return vec2::store_xmm(_mm_div_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec2 vec2::div_min_max(const vec2& left, const float_t min, const float_t max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec2::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec2::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec2::load_xmm(max)); + return vec2::store_xmm(_mm_div_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec3::vec3() : x(), y(), z() { + +} + +inline vec3::vec3(float_t value) : x(value), y(value), z(value) { + +} + +inline vec3::vec3(float_t x, float_t y, float_t z) : x(x), y(y), z(z) { + +} + +inline vec3 operator +(const vec3& left, const vec3& right) { + return vec3::store_xmm(_mm_add_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator +(const vec3& left, const float_t right) { + return vec3::store_xmm(_mm_add_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator +(const float_t left, const vec3& right) { + return vec3::store_xmm(_mm_add_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator +=(vec3& left, const vec3& right) { + left = vec3::store_xmm(_mm_add_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator +=(vec3& left, const float_t right) { + left = vec3::store_xmm(_mm_add_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator -(const vec3& left, const vec3& right) { + return vec3::store_xmm(_mm_sub_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator -(const vec3& left, const float_t right) { + return vec3::store_xmm(_mm_sub_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator -(const float_t left, const vec3& right) { + return vec3::store_xmm(_mm_sub_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator -=(vec3& left, const vec3& right) { + left = vec3::store_xmm(_mm_sub_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator -=(vec3& left, const float_t right) { + left = vec3::store_xmm(_mm_sub_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator *(const vec3& left, const vec3& right) { + return vec3::store_xmm(_mm_mul_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator *(const vec3& left, const float_t right) { + return vec3::store_xmm(_mm_mul_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator *(const float_t left, const vec3& right) { + return vec3::store_xmm(_mm_mul_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator *=(vec3& left, const vec3& right) { + left = vec3::store_xmm(_mm_mul_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator *=(vec3& left, const float_t right) { + left = vec3::store_xmm(_mm_mul_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator /(const vec3& left, const vec3& right) { + return vec3::store_xmm(_mm_div_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator /(const vec3& left, const float_t right) { + return vec3::store_xmm(_mm_div_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator /(const float_t left, const vec3& right) { + return vec3::store_xmm(_mm_div_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator /=(vec3& left, const vec3& right) { + left = vec3::store_xmm(_mm_div_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator /=(vec3& left, const float_t right) { + left = vec3::store_xmm(_mm_div_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator &(const vec3& left, const vec3& right) { + return vec3::store_xmm(_mm_and_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator &(const vec3& left, const float_t right) { + return vec3::store_xmm(_mm_and_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator &(const float_t left, const vec3& right) { + return vec3::store_xmm(_mm_and_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator &=(vec3& left, const vec3& right) { + left = vec3::store_xmm(_mm_and_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator &=(vec3& left, const float_t right) { + left = vec3::store_xmm(_mm_and_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator ^(const vec3& left, const vec3& right) { + return vec3::store_xmm(_mm_xor_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator ^(const vec3& left, const float_t right) { + return vec3::store_xmm(_mm_xor_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator ^(const float_t left, const vec3& right) { + return vec3::store_xmm(_mm_xor_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator ^=(vec3& left, const vec3& right) { + left = vec3::store_xmm(_mm_xor_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline void operator ^=(vec3& left, const float_t right) { + left = vec3::store_xmm(_mm_xor_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 operator -(const vec3& left) { + return vec3::store_xmm(_mm_xor_ps(vec3::load_xmm(left), vec3_neg)); +} + +inline float_t vec3::angle(const vec3& left, const vec3& right) { + return acosf(vec3::dot(left, right) / (vec3::length(left) * vec3::length(right))); +} + +inline float_t vec3::dot(const vec3& left, const vec3& right) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec3::load_xmm(left); + xt = _mm_and_ps(xt, _mm_castsi128_ps(vec4i::load_xmm(vec4_mask_vec3))); + yt = vec3::load_xmm(right); + yt = _mm_and_ps(yt, _mm_castsi128_ps(vec4i::load_xmm(vec4_mask_vec3))); + zt = _mm_mul_ps(xt, yt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline float_t vec3::length(const vec3& left) { + __m128 xt; + __m128 zt; + xt = _mm_and_ps(vec3::load_xmm(left), _mm_castsi128_ps(vec4i::load_xmm(vec4_mask_vec3))); + zt = _mm_mul_ps(xt, xt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); +} + +inline float_t vec3::length_squared(const vec3& left) { + __m128 xt; + __m128 zt; + xt = _mm_and_ps(vec3::load_xmm(left), _mm_castsi128_ps(vec4i::load_xmm(vec4_mask_vec3))); + zt = _mm_mul_ps(xt, xt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline float_t vec3::distance(const vec3& left, const vec3& right) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = _mm_and_ps(vec3::load_xmm(left), _mm_castsi128_ps(vec4i::load_xmm(vec4_mask_vec3))); + yt = _mm_and_ps(vec3::load_xmm(right), _mm_castsi128_ps(vec4i::load_xmm(vec4_mask_vec3))); + zt = _mm_sub_ps(xt, yt); + zt = _mm_mul_ps(zt, zt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); +} + +inline float_t vec3::distance_squared(const vec3& left, const vec3& right) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = _mm_and_ps(vec3::load_xmm(left), _mm_castsi128_ps(vec4i::load_xmm(vec4_mask_vec3))); + yt = _mm_and_ps(vec3::load_xmm(right), _mm_castsi128_ps(vec4i::load_xmm(vec4_mask_vec3))); + zt = _mm_sub_ps(xt, yt); + zt = _mm_mul_ps(zt, zt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline vec3 vec3::lerp(const vec3& left, const vec3& right, const vec3& blend) { + __m128 b1; + __m128 b2; + b1 = vec3::load_xmm(blend); + b2 = _mm_sub_ps(vec3::load_xmm(1.0f), b1); + return vec3::store_xmm(_mm_add_ps(_mm_mul_ps(vec3::load_xmm(left), b2), + _mm_mul_ps(vec3::load_xmm(right), b1))); +} + +inline vec3 vec3::lerp(const vec3& left, const vec3& right, const float_t blend) { + __m128 b1; + __m128 b2; + b1 = vec3::load_xmm(blend); + b2 = _mm_sub_ps(vec3::load_xmm(1.0f), b1); + return vec3::store_xmm(_mm_add_ps(_mm_mul_ps(vec3::load_xmm(left), b2), + _mm_mul_ps(vec3::load_xmm(right), b1))); +} + +inline vec3 vec3::normalize(const vec3& left) { + __m128 xt; + __m128 zt; + xt = vec3::load_xmm(left); + xt = _mm_and_ps(xt, _mm_castsi128_ps(vec4i::load_xmm(vec4_mask_vec3))); + 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]; + return vec3::store_xmm(_mm_mul_ps(xt, _mm_shuffle_ps(zt, zt, 0))); +} + +inline vec3 vec3::rcp(const vec3& left) { + return vec3::store_xmm(_mm_div_ps(vec3::load_xmm(1.0f), vec3::load_xmm(left))); +} + +inline vec3 vec3::min(const vec3& left, const vec3& right) { + return vec3::store_xmm(_mm_min_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 vec3::max(const vec3& left, const vec3& right) { + return vec3::store_xmm(_mm_max_ps(vec3::load_xmm(left), vec3::load_xmm(right))); +} + +inline vec3 vec3::clamp(const vec3& left, const vec3& min, const vec3& max) { + return vec3::store_xmm(_mm_min_ps(_mm_max_ps(vec3::load_xmm(left), + vec3::load_xmm(min)), vec3::load_xmm(max))); +} + +inline vec3 vec3::clamp(const vec3& left, const float_t min, const float_t max) { + return vec3::store_xmm(_mm_min_ps(_mm_max_ps(vec3::load_xmm(left), + vec3::load_xmm(min)), vec3::load_xmm(max))); +} + +inline vec3 vec3::mult_min_max(const vec3& left, const vec3& min, const vec3& max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec3::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec3::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec3::load_xmm(max)); + return vec3::store_xmm(_mm_mul_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec3 vec3::mult_min_max(const vec3& left, const float_t min, const float_t max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec3::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec3::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec3::load_xmm(max)); + return vec3::store_xmm(_mm_mul_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec3 vec3::div_min_max(const vec3& left, const vec3& min, const vec3& max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec3::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec3::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec3::load_xmm(max)); + return vec3::store_xmm(_mm_div_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec3 vec3::div_min_max(const vec3& left, const float_t min, const float_t max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec3::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec3::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec3::load_xmm(max)); + return vec3::store_xmm(_mm_div_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec3 vec3::cross(const vec3& left, const vec3& right) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec3::load_xmm(left); + yt = vec3::load_xmm(right); + zt = _mm_sub_ps( + _mm_mul_ps(xt, _mm_shuffle_ps(yt, yt, 0x09)), + _mm_mul_ps(yt, _mm_shuffle_ps(xt, xt, 0x09)) + ); + return vec3::store_xmm(_mm_shuffle_ps(zt, zt, 0x09)); +} + +inline vec4::vec4() : x(), y(), z(), w() { + +} + +inline vec4::vec4(float_t value) : x(value), y(value), z(value), w(value) { + +} + +inline vec4::vec4(float_t x, float_t y, float_t z, float_t w) : x(x), y(y), z(z), w(w) { + +} + +inline vec4 operator +(const vec4& left, const vec4& right) { + return vec4::store_xmm(_mm_add_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator +(const vec4& left, const float_t right) { + return vec4::store_xmm(_mm_add_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator +(const float_t left, const vec4& right) { + return vec4::store_xmm(_mm_add_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator +=(vec4& left, const vec4& right) { + left = vec4::store_xmm(_mm_add_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator +=(vec4& left, const float_t right) { + left = vec4::store_xmm(_mm_add_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator -(const vec4& left, const vec4& right) { + return vec4::store_xmm(_mm_sub_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator -(const vec4& left, const float_t right) { + return vec4::store_xmm(_mm_sub_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator -(const float_t left, const vec4& right) { + return vec4::store_xmm(_mm_sub_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator -=(vec4& left, const vec4& right) { + left = vec4::store_xmm(_mm_sub_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator -=(vec4& left, const float_t right) { + left = vec4::store_xmm(_mm_sub_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator *(const vec4& left, const vec4& right) { + return vec4::store_xmm(_mm_mul_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator *(const vec4& left, const float_t right) { + return vec4::store_xmm(_mm_mul_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator *(const float_t left, const vec4& right) { + return vec4::store_xmm(_mm_mul_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator *=(vec4& left, const vec4& right) { + left = vec4::store_xmm(_mm_mul_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator *=(vec4& left, const float_t right) { + left = vec4::store_xmm(_mm_mul_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator /(const vec4& left, const vec4& right) { + return vec4::store_xmm(_mm_div_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator /(const vec4& left, const float_t right) { + return vec4::store_xmm(_mm_div_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator /(const float_t left, const vec4& right) { + return vec4::store_xmm(_mm_div_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator /=(vec4& left, const vec4& right) { + left = vec4::store_xmm(_mm_div_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator /=(vec4& left, const float_t right) { + left = vec4::store_xmm(_mm_div_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator &(const vec4& left, const vec4& right) { + return vec4::store_xmm(_mm_and_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator &(const vec4& left, const float_t right) { + return vec4::store_xmm(_mm_and_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator &(const float_t left, const vec4& right) { + return vec4::store_xmm(_mm_and_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator &=(vec4& left, const vec4& right) { + left = vec4::store_xmm(_mm_and_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator &=(vec4& left, const float_t right) { + left = vec4::store_xmm(_mm_and_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator ^(const vec4& left, const vec4& right) { + return vec4::store_xmm(_mm_xor_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator ^(const vec4& left, const float_t right) { + return vec4::store_xmm(_mm_xor_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator ^(const float_t left, const vec4& right) { + return vec4::store_xmm(_mm_xor_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator ^=(vec4& left, const vec4& right) { + left = vec4::store_xmm(_mm_xor_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline void operator ^=(vec4& left, const float_t right) { + left = vec4::store_xmm(_mm_xor_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 operator -(const vec4& left) { + return vec4::store_xmm(_mm_xor_ps(vec4::load_xmm(left), vec4_neg)); +} + +inline float_t vec4::angle(const vec4& left, const vec4& right) { + return acosf(vec4::dot(left, right) / (vec4::length(left) * vec4::length(right))); +} + +inline float_t vec4::dot(const vec4& left, const vec4& right) { + __m128 zt; + zt = _mm_mul_ps(vec4::load_xmm(left), vec4::load_xmm(right)); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline float_t vec4::length(const vec4& left) { + __m128 xt; + __m128 zt; + xt = vec4::load_xmm(left); + zt = _mm_mul_ps(xt, xt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); +} + +inline float_t vec4::length_squared(const vec4& left) { + __m128 xt; + __m128 zt; + xt = vec4::load_xmm(left); + zt = _mm_mul_ps(xt, xt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline float_t vec4::distance(const vec4& left, const vec4& right) { + __m128 zt; + zt = _mm_sub_ps(vec4::load_xmm(left), vec4::load_xmm(right)); + zt = _mm_mul_ps(zt, zt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); +} + +inline float_t vec4::distance_squared(const vec4& left, const vec4& right) { + __m128 zt; + zt = _mm_sub_ps(vec4::load_xmm(left), vec4::load_xmm(right)); + zt = _mm_mul_ps(zt, zt); + zt = _mm_hadd_ps(zt, zt); + return _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); +} + +inline vec4 vec4::lerp(const vec4& left, const vec4& right, const vec4& blend) { + __m128 b1; + __m128 b2; + b1 = vec4::load_xmm(blend); + b2 = vec4::load_xmm(1.0f); + b2 = _mm_sub_ps(b2, b1); + return vec4::store_xmm(_mm_add_ps(_mm_mul_ps(vec4::load_xmm(left), b2), + _mm_mul_ps(vec4::load_xmm(right), b1))); +} + +inline vec4 vec4::lerp(const vec4& left, const vec4& right, const float_t blend) { + __m128 b1; + __m128 b2; + b1 = vec4::load_xmm(blend); + b2 = vec4::load_xmm(1.0f); + b2 = _mm_sub_ps(b2, b1); + return vec4::store_xmm(_mm_add_ps(_mm_mul_ps(vec4::load_xmm(left), b2), + _mm_mul_ps(vec4::load_xmm(right), b1))); +} + +inline vec4 vec4::normalize(const vec4& left) { + __m128 xt; + __m128 zt; + xt = vec4::load_xmm(left); + 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]; + return vec4::store_xmm(_mm_mul_ps(xt, _mm_shuffle_ps(zt, zt, 0))); +} + +inline vec4 vec4::rcp(const vec4& left) { + return vec4::store_xmm(_mm_div_ps(vec4::load_xmm(1.0f), vec4::load_xmm(left))); +} + +inline vec4 vec4::min(const vec4& left, const vec4& right) { + return vec4::store_xmm(_mm_min_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 vec4::max(const vec4& left, const vec4& right) { + return vec4::store_xmm(_mm_max_ps(vec4::load_xmm(left), vec4::load_xmm(right))); +} + +inline vec4 vec4::clamp(const vec4& left, const vec4& min, const vec4& max) { + return vec4::store_xmm(_mm_min_ps(_mm_max_ps(vec4::load_xmm(left), + vec4::load_xmm(min)), vec4::load_xmm(max))); +} + +inline vec4 vec4::clamp(const vec4& left, const float_t min, const float_t max) { + return vec4::store_xmm(_mm_min_ps(_mm_max_ps(vec4::load_xmm(left), + vec4::load_xmm(min)), vec4::load_xmm(max))); +} + +inline vec4 vec4::mult_min_max(const vec4& left, const vec4& min, const vec4& max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec4::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec4::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec4::load_xmm(max)); + return vec4::store_xmm(_mm_mul_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec4 vec4::mult_min_max(const vec4& left, const float_t min, const float_t max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec4::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec4::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec4::load_xmm(max)); + return vec4::store_xmm(_mm_mul_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec4 vec4::div_min_max(const vec4& left, const vec4& min, const vec4& max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec4::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec4::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec4::load_xmm(max)); + return vec4::store_xmm(_mm_div_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec4 vec4::div_min_max(const vec4& left, const float_t min, const float_t max) { + __m128 xt; + __m128 yt; + __m128 zt; + xt = vec4::load_xmm(left); + yt = _mm_and_ps(_mm_cmplt_ps(xt, vec4::load_xmm(vec4_null)), vec4::load_xmm(-min)); + zt = _mm_and_ps(_mm_cmpge_ps(xt, vec4::load_xmm(vec4_null)), vec4::load_xmm(max)); + return vec4::store_xmm(_mm_div_ps(xt, _mm_or_ps(yt, zt))); +} + +inline vec2i::vec2i() : x(), y() { + +} + +inline vec2i::vec2i(int32_t value) : x(value), y(value) { + +} + +inline vec2i::vec2i(int32_t x, int32_t y) : x(x), y(y) { + +} + +inline vec2i operator +(const vec2i& left, const vec2i& right) { + return vec2i::store_xmm(_mm_add_epi32(vec2i::load_xmm(left), vec2i::load_xmm(right))); +} + +inline vec2i operator +(const vec2i& left, const int32_t right) { + return vec2i::store_xmm(_mm_add_epi32(vec2i::load_xmm(left), vec2i::load_xmm(right))); +} + +inline vec2i operator +(const int32_t left, const vec2i& right) { + return vec2i::store_xmm(_mm_add_epi32(vec2i::load_xmm(left), vec2i::load_xmm(right))); +} + +inline vec2i operator -(const vec2i& left, const vec2i& right) { + return vec2i::store_xmm(_mm_sub_epi32(vec2i::load_xmm(left), vec2i::load_xmm(right))); +} + +inline vec2i operator -(const vec2i& left, const int32_t right) { + return vec2i::store_xmm(_mm_sub_epi32(vec2i::load_xmm(left), vec2i::load_xmm(right))); +} + +inline vec2i operator -(const int32_t left, const vec2i& right) { + return vec2i::store_xmm(_mm_sub_epi32(vec2i::load_xmm(left), vec2i::load_xmm(right))); +} + +inline vec2i vec2i::min(const vec2i& left, const vec2i& right) { + return vec2i::store_xmm(_mm_min_epi32(vec2i::load_xmm(left), vec2i::load_xmm(right))); +} + +inline vec2i vec2i::max(const vec2i& left, const vec2i& right) { + return vec2i::store_xmm(_mm_max_epi32(vec2i::load_xmm(left), vec2i::load_xmm(right))); +} + +inline vec2i vec2i::clamp(const vec2i& left, const vec2i& min, const vec2i& max) { + return vec2i::store_xmm(_mm_min_epi32(_mm_max_epi32(vec2i::load_xmm(left), + vec2i::load_xmm(min)), vec2i::load_xmm(max))); +} + +inline vec2i vec2i::clamp(const vec2i& left, const int32_t min, const int32_t max) { + return vec2i::store_xmm(_mm_min_epi32(_mm_max_epi32(vec2i::load_xmm(left), + vec2i::load_xmm(min)), vec2i::load_xmm(max))); +} + +inline vec3i::vec3i() : x(), y(), z() { + +} + +inline vec3i::vec3i(int32_t value) : x(value), y(value), z(value) { + +} + +inline vec3i::vec3i(int32_t x, int32_t y, int32_t z) : x(x), y(y), z(z) { + +} + +inline vec3i operator +(const vec3i& left, const vec3i& right) { + return vec3i::store_xmm(_mm_add_epi32(vec3i::load_xmm(left), vec3i::load_xmm(right))); +} + +inline vec3i operator +(const vec3i& left, const int32_t right) { + return vec3i::store_xmm(_mm_add_epi32(vec3i::load_xmm(left), vec3i::load_xmm(right))); +} + +inline vec3i operator +(const int32_t left, const vec3i& right) { + return vec3i::store_xmm(_mm_add_epi32(vec3i::load_xmm(left), vec3i::load_xmm(right))); +} + +inline vec3i operator -(const vec3i& left, const vec3i& right) { + return vec3i::store_xmm(_mm_sub_epi32(vec3i::load_xmm(left), vec3i::load_xmm(right))); +} + +inline vec3i operator -(const vec3i& left, const int32_t right) { + return vec3i::store_xmm(_mm_sub_epi32(vec3i::load_xmm(left), vec3i::load_xmm(right))); +} + +inline vec3i operator -(const int32_t left, const vec3i& right) { + return vec3i::store_xmm(_mm_sub_epi32(vec3i::load_xmm(left), vec3i::load_xmm(right))); +} + +inline vec3i vec3i::min(const vec3i& left, const vec3i& right) { + return vec3i::store_xmm(_mm_min_epi32(vec3i::load_xmm(left), vec3i::load_xmm(right))); +} + +inline vec3i vec3i::max(const vec3i& left, const vec3i& right) { + return vec3i::store_xmm(_mm_max_epi32(vec3i::load_xmm(left), vec3i::load_xmm(right))); +} + +inline vec3i vec3i::clamp(const vec3i& left, const vec3i& min, const vec3i& max) { + return vec3i::store_xmm(_mm_min_epi32(_mm_max_epi32(vec3i::load_xmm(left), + vec3i::load_xmm(min)), vec3i::load_xmm(max))); +} + +inline vec3i vec3i::clamp(const vec3i& left, const int32_t min, const int32_t max) { + return vec3i::store_xmm(_mm_min_epi32(_mm_max_epi32(vec3i::load_xmm(left), + vec3i::load_xmm(min)), vec3i::load_xmm(max))); +} + +inline vec4i::vec4i() : x(), y(), z(), w() { + +} + +inline vec4i::vec4i(int32_t value) : x(value), y(value), z(value), w(value) { + +} + +inline vec4i::vec4i(int32_t x, int32_t y, int32_t z, int32_t w) : x(x), y(y), z(z), w(w) { + +} + +inline vec4i operator +(const vec4i& left, const vec4i& right) { + return vec4i::store_xmm(_mm_add_epi32(vec4i::load_xmm(left), vec4i::load_xmm(right))); +} + +inline vec4i operator +(const vec4i& left, const int32_t right) { + return vec4i::store_xmm(_mm_add_epi32(vec4i::load_xmm(left), vec4i::load_xmm(right))); +} + +inline vec4i operator +(const int32_t left, const vec4i& right) { + return vec4i::store_xmm(_mm_add_epi32(vec4i::load_xmm(left), vec4i::load_xmm(right))); +} + +inline vec4i operator -(const vec4i& left, const vec4i& right) { + return vec4i::store_xmm(_mm_sub_epi32(vec4i::load_xmm(left), vec4i::load_xmm(right))); +} + +inline vec4i operator -(const vec4i& left, const int32_t right) { + return vec4i::store_xmm(_mm_sub_epi32(vec4i::load_xmm(left), vec4i::load_xmm(right))); +} + +inline vec4i operator -(const int32_t left, const vec4i& right) { + return vec4i::store_xmm(_mm_sub_epi32(vec4i::load_xmm(left), vec4i::load_xmm(right))); +} + +inline vec4i vec4i::min(const vec4i& left, const vec4i& right) { + return vec4i::store_xmm(_mm_min_epi32(vec4i::load_xmm(left), vec4i::load_xmm(right))); +} + +inline vec4i vec4i::max(const vec4i& left, const vec4i& right) { + return vec4i::store_xmm(_mm_max_epi32(vec4i::load_xmm(left), vec4i::load_xmm(right))); +} + +inline vec4i vec4i::clamp(const vec4i& left, const vec4i& min, const vec4i& max) { + return vec4i::store_xmm(_mm_min_epi32(_mm_max_epi32(vec4i::load_xmm(left), + vec4i::load_xmm(min)), vec4i::load_xmm(max))); +} + +inline vec4i vec4i::clamp(const vec4i& left, const int32_t min, const int32_t max) { + return vec4i::store_xmm(_mm_min_epi32(_mm_max_epi32(vec4i::load_xmm(left), + vec4i::load_xmm(min)), vec4i::load_xmm(max))); +} + +inline void vec2i8_to_vec2(vec2i8& src, vec2& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; +} + +inline void vec3i8_to_vec3(vec3i8& src, vec3& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; + dst.z = (float_t)src.z; +} + +inline void vec4i8_to_vec4(vec4i8& src, vec4& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; + dst.z = (float_t)src.z; + dst.w = (float_t)src.w; +} + +inline void vec2_to_vec2i8(vec2& src, vec2i8& dst) { + dst.x = (int8_t)src.x; + dst.y = (int8_t)src.y; +} + +inline void vec3_to_vec3i8(vec3& src, vec3i8& dst) { + dst.x = (int8_t)src.x; + dst.y = (int8_t)src.y; + dst.z = (int8_t)src.z; +} + +inline void vec4_to_vec4i8(vec4& src, vec4i8& dst) { + dst.x = (int8_t)src.x; + dst.y = (int8_t)src.y; + dst.z = (int8_t)src.z; + dst.w = (int8_t)src.w; +} + +inline void vec2u8_to_vec2(vec2u8& src, vec2& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; +} + +inline void vec3u8_to_vec3(vec3u8& src, vec3& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; + dst.z = (float_t)src.z; +} + +inline void vec4u8_to_vec4(vec4u8& src, vec4& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; + dst.z = (float_t)src.z; + dst.w = (float_t)src.w; +} + +inline void vec2_to_vec2u8(vec2& src, vec2u8& dst) { + dst.x = (uint8_t)src.x; + dst.y = (uint8_t)src.y; +} + +inline void vec3_to_vec3u8(vec3& src, vec3u8& dst) { + dst.x = (uint8_t)src.x; + dst.y = (uint8_t)src.y; + dst.z = (uint8_t)src.z; +} + +inline void vec4_to_vec4u8(vec4& src, vec4u8& dst) { + dst.x = (uint8_t)src.x; + dst.y = (uint8_t)src.y; + dst.z = (uint8_t)src.z; + dst.w = (uint8_t)src.w; +} + +inline void vec2i16_to_vec2(vec2i16& src, vec2& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; +} + +inline void vec3i16_to_vec3(vec3i16& src, vec3& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; + dst.z = (float_t)src.z; +} + +inline void vec4i16_to_vec4(vec4i16& src, vec4& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; + dst.z = (float_t)src.z; + dst.w = (float_t)src.w; +} + +inline void vec2_to_vec2i16(vec2& src, vec2i16& dst) { + dst.x = (int16_t)src.x; + dst.y = (int16_t)src.y; +} + +inline void vec3_to_vec3i16(vec3& src, vec3i16& dst) { + dst.x = (int16_t)src.x; + dst.y = (int16_t)src.y; + dst.z = (int16_t)src.z; +} + +inline void vec4_to_vec4i16(vec4& src, vec4i16& dst) { + dst.x = (int16_t)src.x; + dst.y = (int16_t)src.y; + dst.z = (int16_t)src.z; + dst.w = (int16_t)src.w; +} + +inline void vec2u16_to_vec2(vec2u16& src, vec2& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; +} + +inline void vec3u16_to_vec3(vec3u16& src, vec3& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; + dst.z = (float_t)src.z; +} + +inline void vec4u16_to_vec4(vec4u16& src, vec4& dst) { + dst.x = (float_t)src.x; + dst.y = (float_t)src.y; + dst.z = (float_t)src.z; + dst.w = (float_t)src.w; +} + +inline void vec2_to_vec2u16(vec2& src, vec2u16& dst) { + dst.x = (uint16_t)src.x; + dst.y = (uint16_t)src.y; +} + +inline void vec3_to_vec3u16(vec3& src, vec3u16& dst) { + dst.x = (uint16_t)src.x; + dst.y = (uint16_t)src.y; + dst.z = (uint16_t)src.z; +} + +inline void vec4_to_vec4u16(vec4& src, vec4u16& dst) { + dst.x = (uint16_t)src.x; + dst.y = (uint16_t)src.y; + dst.z = (uint16_t)src.z; + dst.w = (uint16_t)src.w; +} + +inline void vec2h_to_vec2(vec2h& src, vec2& dst) { + dst.x = half_to_float(src.x); + dst.y = half_to_float(src.y); +} + +inline void vec3h_to_vec3(vec3h& src, vec3& dst) { + dst.x = half_to_float(src.x); + dst.y = half_to_float(src.y); + dst.z = half_to_float(src.z); +} + +inline void vec4h_to_vec4(vec4h& src, vec4& dst) { + dst.x = half_to_float(src.x); + dst.y = half_to_float(src.y); + dst.z = half_to_float(src.z); + dst.w = half_to_float(src.w); +} + +inline void vec2_to_vec2h(vec2& src, vec2h& dst) { + dst.x = float_to_half(src.x); + dst.y = float_to_half(src.y); +} + +inline void vec3_to_vec3h(vec3& src, vec3h& dst) { + dst.x = float_to_half(src.x); + dst.y = float_to_half(src.y); + dst.z = float_to_half(src.z); +} + +inline void vec4_to_vec4h(vec4& src, vec4h& dst) { + dst.x = float_to_half(src.x); + dst.y = float_to_half(src.y); + dst.z = float_to_half(src.z); + dst.w = float_to_half(src.w); +} + +inline void vec2i8_to_vec2i(vec2i8& src, vec2i& dst) { + dst.x = src.x; + dst.y = src.y; +} + +inline void vec3i8_to_vec3i(vec3i8& src, vec3i& dst) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +inline void vec4i8_to_vec4i(vec4i8& src, vec4i& dst) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; + dst.w = src.w; +} + +inline void vec2i_to_vec2i8(vec2i& src, vec2i8& dst) { + dst.x = (int8_t)src.x; + dst.y = (int8_t)src.y; +} + +inline void vec3i_to_vec3i8(vec3i& src, vec3i8& dst) { + dst.x = (int8_t)src.x; + dst.y = (int8_t)src.y; + dst.z = (int8_t)src.z; +} + +inline void vec4i_to_vec4i8(vec4i& src, vec4i8& dst) { + dst.x = (int8_t)src.x; + dst.y = (int8_t)src.y; + dst.z = (int8_t)src.z; + dst.w = (int8_t)src.w; +} + +inline void vec2u8_to_vec2i(vec2u8& src, vec2i& dst) { + dst.x = src.x; + dst.y = src.y; +} + +inline void vec3u8_to_vec4i(vec3u8& src, vec3i& dst) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +inline void vec4u8_to_vec4i(vec4u8& src, vec4i& dst) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; + dst.w = src.w; +} + +inline void vec2i_to_vec2u8(vec2i& src, vec2u8& dst) { + dst.x = (uint8_t)src.x; + dst.y = (uint8_t)src.y; +} + +inline void vec3i_to_vec3u8(vec3i& src, vec3u8& dst) { + dst.x = (uint8_t)src.x; + dst.y = (uint8_t)src.y; + dst.z = (uint8_t)src.z; +} + +inline void vec4i_to_vec4u8(vec4i& src, vec4u8& dst) { + dst.x = (uint8_t)src.x; + dst.y = (uint8_t)src.y; + dst.z = (uint8_t)src.z; + dst.w = (uint8_t)src.w; +} + +inline void vec2i16_to_vec2i(vec2i16& src, vec2i& dst) { + dst.x = src.x; + dst.y = src.y; +} + +inline void vec3i16_to_vec4i(vec3i16& src, vec3i& dst) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +inline void vec4i16_to_vec4i(vec4i16& src, vec4i& dst) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; + dst.w = src.w; +} + +inline void vec2i_to_vec2i16(vec2i& src, vec2i16& dst) { + dst.x = (int16_t)src.x; + dst.y = (int16_t)src.y; +} + +inline void vec3i_to_vec3i16(vec3i& src, vec3i16& dst) { + dst.x = (int16_t)src.x; + dst.y = (int16_t)src.y; + dst.z = (int16_t)src.z; +} + +inline void vec4i_to_vec4i16(vec4i& src, vec4i16& dst) { + dst.x = (int16_t)src.x; + dst.y = (int16_t)src.y; + dst.z = (int16_t)src.z; + dst.w = (int16_t)src.w; +} + +inline void vec2u16_to_vec2i(vec2u16& src, vec2i& dst) { + dst.x = src.x; + dst.y = src.y; +} + +inline void vec3u16_to_vec4i(vec3u16& src, vec3i& dst) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +inline void vec4u16_to_vec4i(vec4u16& src, vec4i& dst) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; + dst.w = src.w; +} + +inline void vec2i_to_vec2u16(vec2i& src, vec2u16& dst) { + dst.x = (uint16_t)src.x; + dst.y = (uint16_t)src.y; +} + +inline void vec3i_to_vec3u16(vec3i& src, vec3u16& dst) { + dst.x = (uint16_t)src.x; + dst.y = (uint16_t)src.y; + dst.z = (uint16_t)src.z; +} + +inline void vec4i_to_vec4u16(vec4i& src, vec4u16& dst) { + dst.x = (uint16_t)src.x; + dst.y = (uint16_t)src.y; + dst.z = (uint16_t)src.z; + dst.w = (uint16_t)src.w; +} + +inline void vec2_add(const vec2& x, const vec2& y, vec2& z) { + z = x + y; +} + +inline void vec2_add_scalar(const vec2& x, const float_t y, vec2& z) { + z = x + y; +} + +inline void vec2_sub(const vec2& x, const vec2& y, vec2& z) { + z = x - y; +} + +inline void vec2_sub_scalar(const vec2& x, const float_t y, vec2& z) { + z = x - y; +} + +inline void vec2_mult(const vec2& x, const vec2& y, vec2& z) { + z = x * y; +} + +inline void vec2_mult_scalar(const vec2& x, const float_t y, vec2& z) { + z = x * y; +} + +inline void vec2_div(const vec2& x, const vec2& y, vec2& z) { + z = x / y; +} + +inline void vec2_div_scalar(const vec2& x, const float_t y, vec2& z) { + z = x / y; +} + +inline void vec2_and(const vec2& x, const vec2& y, vec2& z) { + z = x & y; +} + +inline void vec2_and_scalar(const vec2& x, const float_t y, vec2& z) { + z = x & y; +} + +inline void vec2_xor(const vec2& x, const vec2& y, vec2& z) { + z = x ^ y; +} + +inline void vec2_xor_scalar(const vec2& x, const float_t y, vec2& z) { + z = x ^ y; +} + +inline void vec2_negate(const vec2& x, vec2& z) { + z = -x; +} + +inline void vec2_dot(const vec2& x, const vec2& y, float_t& z) { + z = vec2::dot(x, y); +} + +inline void vec2_length(const vec2& x, float_t& z) { + z = vec2::length(x); +} + +inline void vec2_length_squared(const vec2& x, float_t& z) { + z = vec2::length_squared(x); +} + +inline void vec2_distance(const vec2& x, const vec2& y, float_t& z) { + z = vec2::distance(x, y); +} + +inline void vec2_distance_squared(const vec2& x, const vec2& y, float_t& z) { + z = vec2::distance_squared(x, y); +} + +inline void vec2_lerp(const vec2& x, const vec2& y, vec2& z, const float_t blend) { + z = vec2::lerp(x, y, blend); +} + +inline void vec2_lerp_scalar(const vec2& x, const vec2& y, vec2& z, const float_t blend) { + z = vec2::lerp(x, y, blend); +} + +inline void vec2_normalize(const vec2& x, vec2& z) { + z = vec2::normalize(x); +} + +inline void vec2_rcp(const vec2& x, vec2& z) { + z = vec2::rcp(x); +} + +inline void vec2_min(const vec2& x, const vec2& y, vec2& z) { + z = vec2::min(x, y); +} + +inline void vec2_max(const vec2& x, const vec2& y, vec2& z) { + z = vec2::max(x, y); +} + +inline void vec2_clamp(const vec2& x, const vec2& y, const vec2& z, vec2& w) { + w = vec2::clamp(x, y, z); +} + +inline void vec2_clamp_scalar(const vec2& x, const float_t y, const float_t z, vec2& w) { + w = vec2::clamp(x, y, z); +} + +inline void vec2_mult_min_max(const vec2& x, const vec2& y, const vec2& z, vec2& w) { + w = vec2::mult_min_max(x, y, z); +} + +inline void vec2_mult_min_max_scalar(const vec2& x, const float_t y, const float_t z, vec2& w) { + w = vec2::mult_min_max(x, y, z); +} + +inline void vec2_div_min_max(const vec2& x, const vec2& y, const vec2& z, vec2& w) { + w = vec2::div_min_max(x, y, z); +} + +inline void vec2_div_min_max_scalar(const vec2& x, const float_t y, const float_t z, vec2& w) { + w = vec2::div_min_max(x, y, z); +} + +inline void vec3_add(const vec3& x, const vec3& y, vec3& z) { + z = x + y; +} + +inline void vec3_add_scalar(const vec3& x, const float_t y, vec3& z) { + z = x + y; +} + +inline void vec3_sub(const vec3& x, const vec3& y, vec3& z) { + z = x - y; +} + +inline void vec3_sub_scalar(const vec3& x, const float_t y, vec3& z) { + z = x - y; +} + +inline void vec3_mult(const vec3& x, const vec3& y, vec3& z) { + z = x * y; +} + +inline void vec3_mult_scalar(const vec3& x, const float_t y, vec3& z) { + z = x * y; +} + +inline void vec3_div(const vec3& x, const vec3& y, vec3& z) { + z = x / y; +} + +inline void vec3_div_scalar(const vec3& x, const float_t y, vec3& z) { + z = x / y; +} + +inline void vec3_and(const vec3& x, const vec3& y, vec3& z) { + z = x & y; +} + +inline void vec3_and_scalar(const vec3& x, const float_t y, vec3& z) { + z = x & y; +} + +inline void vec3_xor(const vec3& x, const vec3& y, vec3& z) { + z = x ^ y; +} + +inline void vec3_xor_scalar(const vec3& x, const float_t y, vec3& z) { + z = x ^ y; +} + +inline void vec3_negate(const vec3& x, vec3& z) { + z = -x; +} + +inline void vec3_dot(const vec3& x, const vec3& y, float_t& z) { + z = vec3::dot(x, y); +} + +inline void vec3_length(const vec3& x, float_t& z) { + z = vec3::length(x); +} + +inline void vec3_length_squared(const vec3& x, float_t& z) { + z = vec3::length_squared(x); +} + +inline void vec3_distance(const vec3& x, const vec3& y, float_t& z) { + z = vec3::distance(x, y); +} + +inline void vec3_distance_squared(const vec3& x, const vec3& y, float_t& z) { + z = vec3::distance_squared(x, y); +} + +inline void vec3_lerp(const vec3& x, const vec3& y, vec3& z, const vec3& blend) { + z = vec3::lerp(x, y, blend); +} + +inline void vec3_lerp_scalar(const vec3& x, const vec3& y, vec3& z, const float_t blend) { + z = vec3::lerp(x, y, blend); +} + +inline void vec3_normalize(const vec3& x, vec3& z) { + z = vec3::normalize(x); +} + +inline void vec3_rcp(const vec3& x, vec3& z) { + z = vec3::rcp(x); +} + +inline void vec3_min(const vec3& x, const vec3& y, vec3& z) { + z = vec3::min(x, y); +} + +inline void vec3_max(const vec3& x, const vec3& y, vec3& z) { + z = vec3::max(x, y); +} + +inline void vec3_clamp(const vec3& x, const vec3& y, const vec3& z, vec3& w) { + w = vec3::clamp(x, y, z); +} + +inline void vec3_clamp_scalar(const vec3& x, const vec3& y, const float_t z, vec3& w) { + w = vec3::clamp(x, y, z); +} + +inline void vec3_mult_min_max(const vec3& x, const vec3& y, const vec3& z, vec3& w) { + w = vec3::mult_min_max(x, y, z); +} + +inline void vec3_mult_min_max_scalar(const vec3& x, const vec3& y, const float_t z, vec3& w) { + w = vec3::mult_min_max(x, y, z); +} + +inline void vec3_div_min_max(const vec3& x, const vec3& y, const vec3& z, vec3& w) { + w = vec3::div_min_max(x, y, z); +} + +inline void vec3_div_min_max_scalar(const vec3& x, const vec3& y, const float_t z, vec3& w) { + w = vec3::div_min_max(x, y, z); +} + +inline void vec3_cross(const vec3& x, const vec3& y, vec3& z) { + z = vec3::cross(x, y); +} + +inline void vec4_add(const vec4& x, const vec4& y, vec4& z) { + z = x + y; +} + +inline void vec4_add_scalar(const vec4& x, const float_t y, vec4& z) { + z = x + y; +} + +inline void vec4_sub(const vec4& x, const vec4& y, vec4& z) { + z = x - y; +} + +inline void vec4_sub_scalar(const vec4& x, const float_t y, vec4& z) { + z = x - y; +} + +inline void vec4_mult(const vec4& x, const vec4& y, vec4& z) { + z = x * y; +} + +inline void vec4_mult_scalar(const vec4& x, const float_t y, vec4& z) { + z = x * y; +} + +inline void vec4_div(const vec4& x, const vec4& y, vec4& z) { + z = x / y; +} + +inline void vec4_div_scalar(const vec4& x, const float_t y, vec4& z) { + z = x / y; +} + +inline void vec4_and(const vec4& x, const vec4& y, vec4& z) { + z = x & y; +} + +inline void vec4_and_scalar(const vec4& x, const float_t y, vec4& z) { + z = x & y; +} + +inline void vec4_xor(const vec4& x, const vec4& y, vec4& z) { + z = x ^ y; +} + +inline void vec4_xor_scalar(const vec4& x, const float_t y, vec4& z) { + z = x ^ y; +} + +inline void vec4_negate(const vec4& x, vec4& z) { + z = -x; +} + +inline void vec4_dot(const vec4& x, const vec4& y, float_t& z) { + z = vec4::dot(x, y); +} + +inline void vec4_length(const vec4& x, float_t& z) { + z = vec4::length(x); +} + +inline void vec4_length_squared(const vec4& x, float_t& z) { + z = vec4::length_squared(x); +} + +inline void vec4_distance(const vec4& x, const vec4& y, float_t& z) { + z = vec4::distance(x, y); +} + +inline void vec4_distance_squared(const vec4& x, const vec4& y, float_t& z) { + z = vec4::distance_squared(x, y); +} + +inline void vec4_lerp(const vec4& x, const vec4& y, vec4& z, const vec4& blend) { + z = vec4::lerp(x, y, blend); +} + +inline void vec4_lerp_scalar(const vec4& x, const vec4& y, vec4& z, const float_t blend) { + z = vec4::lerp(x, y, blend); +} + +inline void vec4_normalize(const vec4& x, vec4& z) { + z = vec4::normalize(x); +} + +inline void vec4_rcp(const vec4& x, vec4& z) { + z = vec4::rcp(x); +} + +inline void vec4_min(const vec4& x, const vec4& y, vec4& z) { + z = vec4::min(x, y); +} + +inline void vec4_max(const vec4& x, const vec4& y, vec4& z) { + z = vec4::max(x, y); +} + +inline void vec4_clamp(const vec4& x, const vec4& y, const vec4& z, vec4& w) { + w = vec4::clamp(x, y, z); +} + +inline void vec4_clamp_scalar(const vec4& x, const float_t y, const float_t z, vec4& w) { + w = vec4::clamp(x, y, z); +} + +inline void vec4_mult_min_max(const vec4& x, const vec4& y, const vec4& z, vec4& w) { + w = vec4::mult_min_max(x, y, z); +} + +inline void vec4_mult_min_max_scalar(const vec4& x, const float_t y, const float_t z, vec4& w) { + w = vec4::mult_min_max(x, y, z); +} + +inline void vec4_div_min_max(const vec4& x, const vec4& y, const vec4& z, vec4& w) { + w = vec4::div_min_max(x, y, z); +} + +inline void vec4_div_min_max_scalar(const vec4& x, const float_t y, const float_t z, vec4& w) { + w = vec4::div_min_max(x, y, z); +} + +inline void vec2i_add(const vec2i& x, const vec2i& y, vec2i& z) { + z = x + y; +} + +inline void vec2i_add_scalar(const vec2i& x, const int32_t y, vec2i& z) { + z = x + y; +} + +inline void vec2i_sub(const vec2i& x, const vec2i& y, vec2i& z) { + z = x - y; +} + +inline void vec2i_sub_scalar(const vec2i& x, const int32_t y, vec2i& z) { + z = x - y; +} + +inline void vec3i_add(const vec3i& x, const vec3i& y, vec3i& z) { + z = x + y; +} + +inline void vec3i_add_scalar(const vec3i& x, const int32_t y, vec3i& z) { + z = x + y; +} + +inline void vec3i_sub(const vec3i& x, const vec3i& y, vec3i& z) { + z = x - y; +} + +inline void vec3i_sub_scalar(const vec3i& x, const int32_t y, vec3i& z) { + z = x - y; +} + +inline void vec4i_add(const vec4i& x, const vec4i& y, vec4i& z) { + z = x + y; +} + +inline void vec4i_add_scalar(const vec4i& x, const int32_t y, vec4i& z) { + z = x + y; } -#define vec4_xor_scalar(x, y, z) \ -{ \ - __m128 yt; \ - yt = _mm_set_ss(y); \ - _mm_storeu_ps((float*)&(z), _mm_xor_ps(_mm_loadu_ps((float*)&(x)), _mm_shuffle_ps(yt, yt, 0))); \ +inline void vec4i_sub(const vec4i& x, const vec4i& y, vec4i& z) { + z = x - y; } -#define vec4_negate(x, z) \ -{ \ - _mm_storeu_ps((float*)&(z), _mm_xor_ps(_mm_loadu_ps((float*)&(x)), vec4_negate)); \ +inline void vec4i_sub_scalar(const vec4i& x, const int32_t y, vec4i& z) { + z = x - y; } -#define vec4_dot(x, y, z) \ -{ \ - __m128 zt; \ - zt = _mm_mul_ps(_mm_loadu_ps((float*)&(x)), _mm_loadu_ps((float*)&(y))); \ - zt = _mm_hadd_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ +inline void vec2_to_vec2i(const vec2& x, vec2i& z) { + z = vec2i::store_xmm(_mm_cvtps_epi32(vec2::load_xmm(x))); } -#define vec4_length(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - xt = _mm_loadu_ps((float*)&(x)); \ - zt = _mm_mul_ps(xt, xt); \ - zt = _mm_hadd_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); \ +inline void vec2i_to_vec2(const vec2i& x, vec2& z) { + z = vec2::store_xmm(_mm_cvtepi32_ps(vec2i::load_xmm(x))); } -#define vec4_length_squared(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - xt = _mm_loadu_ps((float*)&(x)); \ - zt = _mm_mul_ps(xt, xt); \ - zt = _mm_hadd_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ +inline void vec3_to_vec3i(const vec3& x, vec3i& z) { + z = vec3i::store_xmm(_mm_cvtps_epi32(vec3::load_xmm(x))); } -#define vec4_distance(x, y, z) \ -{ \ - __m128 zt; \ - zt = _mm_sub_ps(_mm_loadu_ps((float*)&(x)), _mm_loadu_ps((float*)&(y))); \ - zt = _mm_mul_ps(zt, zt); \ - zt = _mm_hadd_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_sqrt_ss(_mm_hadd_ps(zt, zt))); \ +inline void vec3i_to_vec3(const vec3i& x, vec3& z) { + z = vec3::store_xmm(_mm_cvtepi32_ps(vec3i::load_xmm(x))); } -#define vec4_distance_squared(x, y, z) \ -{ \ - __m128 zt; \ - zt = _mm_sub_ps(_mm_loadu_ps((float*)&(x)), _mm_loadu_ps((float*)&(y))); \ - zt = _mm_mul_ps(zt, zt); \ - zt = _mm_hadd_ps(zt, zt); \ - (z) = _mm_cvtss_f32(_mm_hadd_ps(zt, zt)); \ +inline void vec4_to_vec4i(const vec4& x, vec4i& z) { + z = vec4i::store_xmm(_mm_cvtps_epi32(vec4::load_xmm(x))); } -#define vec4_lerp(x, y, z, blend) \ -{ \ - __m128 b1; \ - __m128 b2; \ - b1 = _mm_loadu_ps((float*)&(blend)); \ - b2 = _mm_sub_ps(_mm_loadu_ps((float*)&(vec4_identity)), b1); \ - _mm_storeu_ps((float*)&(z), _mm_add_ps(_mm_mul_ps(_mm_loadu_ps((float*)&(x)), b2), \ - _mm_mul_ps(_mm_loadu_ps((float*)&(y)), b1))); \ -} - -#define vec4_lerp_scalar(x, y, z, blend) \ -{ \ - __m128 b1; \ - __m128 b2; \ - b1 = _mm_set_ss(blend); \ - b1 = _mm_shuffle_ps(b1, b1, 0); \ - b2 = _mm_sub_ps(_mm_loadu_ps((float*)&(vec4_identity)), b1); \ - _mm_storeu_ps((float*)&(z), _mm_add_ps(_mm_mul_ps(_mm_loadu_ps((float*)&(x)), b2), \ - _mm_mul_ps(_mm_loadu_ps((float*)&(y)), b1))); \ -} - -#define vec4_normalize(x, z) \ -{ \ - __m128 xt; \ - __m128 zt; \ - xt = _mm_loadu_ps((float*)&(x)); \ - 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]; \ - _mm_storeu_ps((float*)&(z), _mm_mul_ps(xt, _mm_shuffle_ps(zt, zt, 0))); \ -} - -#define vec4_rcp(x, z) \ -{ \ - _mm_storeu_ps((float*)&(z), _mm_div_ps(_mm_loadu_ps((float*)&(vec4_identity)), _mm_loadu_ps((float*)&(x)))); \ -} - -#define vec4_min(x, y, z) \ -{ \ - _mm_storeu_ps((float*)&(z), _mm_min_ps(_mm_loadu_ps((float*)&(x)), yt)); \ -} - -#define vec4_max(x, y, z) \ -{ \ - _mm_storeu_ps((float*)&(z), _mm_max_ps(_mm_loadu_ps((float*)&(x)), yt)); \ -} - -#define vec4_clamp(x, y, z, w) \ -{ \ - _mm_storeu_ps((float*)&(w), _mm_min_ps(_mm_max_ps(_mm_loadu_ps((float*)&(x)), yt), zt)); \ -} - -#define vec4_clamp_scalar(x, y, z, w) \ -{ \ - __m128 yt; \ - __m128 zt; \ - yt = _mm_set_ss(y); \ - zt = _mm_set_ss(z); \ - _mm_storeu_ps((float*)&(w), _mm_min_ps(_mm_max_ps(_mm_loadu_ps((float*)&(x)), \ - _mm_shuffle_ps(yt, yt, 0)), _mm_shuffle_ps(zt, zt, 0))); \ -} - -#define vec4_mult_min_max(x, y, z, w) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 wt; \ - xt = _mm_loadu_ps((float*)&(x)); \ - yt = _mm_xor_ps(_mm_loadu_ps((float*)&(y)), vec4_negate); \ - wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(_mm_loadu_ps((float*)&(z)), _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - _mm_storeu_ps((float*)&(w), _mm_mul_ps(xt, wt)); \ -} - -#define vec4_mult_min_max_scalar(x, y, z, w) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - __m128 wt; \ - xt = _mm_loadu_ps((float*)&(xt)); \ - 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(xt, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - _mm_storeu_ps((float*)&(w), _mm_mul_ps(xt, wt)); \ -} - -#define vec4_div_min_max(x, y, z, w) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 wt; \ - xt = _mm_loadu_ps((float*)&(x)); \ - yt = _mm_xor_ps(_mm_loadu_ps((float*)&(y)), vec4_negate); \ - wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(_mm_loadu_ps((float*)&(z)), _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - _mm_storeu_ps((float*)&(w), _mm_div_ps(xt, wt)); \ -} - -#define vec4_div_min_max_scalar(x, y, z, w) \ -{ \ - __m128 xt; \ - __m128 yt; \ - __m128 zt; \ - __m128 wt; \ - xt = _mm_loadu_ps((float*)&(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, vec4_negate); \ - wt = _mm_or_ps(_mm_and_ps(yt, _mm_cmplt_ps(xt, _mm_loadu_ps((float*)&(vec4_null)))), \ - _mm_and_ps(zt, _mm_cmpge_ps(xt, _mm_loadu_ps((float*)&(vec4_null))))); \ - _mm_storeu_ps((float*)&(w), _mm_div_ps(xt, 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) \ -{ \ - __m128i xt; \ - __m128i yt; \ - __m128i zt; \ - *(vec4i*)&xt = (x); \ - *(vec4i*)&yt = (y); \ - zt = _mm_add_epi32(xt, yt); \ - (z) = *(vec4i*)&zt; \ -} - -#define vec4i_add_scalar(x, y, z) \ -{ \ - __m128i xt; \ - __m128i yt; \ - __m128i zt; \ - *(vec4i*)&xt = (x); \ - yt = _mm_set1_epi32(y); \ - zt = _mm_add_epi32(xt, _mm_shuffle_epi32(yt, yt, 0)); \ - (z) = *(vec4i*)&zt; \ -} - -#define vec4i_sub(x, y, z) \ -{ \ - __m128i xt; \ - __m128i yt; \ - __m128i zt; \ - *(vec4i*)&xt = (x); \ - *(vec4i*)&yt = (y); \ - zt = _mm_sub_epi32(xt, yt); \ - (z) = *(vec4i*)&zt; \ -} - -#define vec4i_sub_scalar(x, y, z) \ -{ \ - __m128i xt; \ - __m128i yt; \ - __m128i zt; \ - *(vec4i*)&xt = (x); \ - yt = _mm_set1_epi32(y); \ - zt = _mm_sub_epi32(xt, _mm_shuffle_epi32(yt, yt, 0)); \ - (z) = *(vec4i*)&zt; \ -} - -#define vec4_to_vec4i(x, z) \ -{ \ - __m128i zt; \ - zt = _mm_cvtps_epi32(_mm_loadu_ps((float*)&(x))); \ - (z) = *(vec4i*)&zt; \ -} - -#define vec4i_to_vec4(x, z) \ -{ \ - __m128i xt; \ - *(vec4i*)&xt = (x); \ - _mm_storeu_ps((float*)&(z), _mm_cvtepi32_ps(xt)); \ +inline void vec4i_to_vec4(const vec4i& x, vec4& z) { + z = vec4::store_xmm(_mm_cvtepi32_ps(vec4i::load_xmm(x))); } diff --git a/src/MMPlusDec/MMPlusDec.cpp b/src/MMPlusDec/MMPlusDec.cpp index 22ef33d1..42e48102 100644 --- a/src/MMPlusDec/MMPlusDec.cpp +++ b/src/MMPlusDec/MMPlusDec.cpp @@ -8,8 +8,8 @@ #include #include #include "../KKdLib/default.hpp" +#include "../KKdLib/io/file_stream.hpp" #include "../KKdLib/io/path.hpp" -#include "../KKdLib/io/stream.hpp" #include "../KKdLib/aes.hpp" #include "../KKdLib/str_utils.hpp" #include @@ -71,20 +71,19 @@ int32_t wmain(int32_t argc, wchar_t** argv) { aes256_init_ctx(&ctx, mmplus_key); { - std::vector files; - path_get_files(&files, indir.c_str()); + std::vector files = path_get_files(indir.c_str()); for (std::wstring& i : files) { std::wstring infile = indir + i; std::wstring outfile = outdir + i; - stream in_file; - stream out_file; + file_stream in_file; + file_stream out_file; in_file.open(infile.c_str(), L"rb"); out_file.open(outfile.c_str(), L"wb"); - if (in_file.io.stream && out_file.io.stream) { + if (in_file.check_not_null() && out_file.check_not_null()) { printf(encrypt ? "Encrypting %ls\n" : "Decrypting %ls\n", i.c_str()); aes256_ctx_set_iv(&ctx, mmplus_iv); @@ -124,8 +123,7 @@ int32_t wmain(int32_t argc, wchar_t** argv) { } } - std::vector directories; - path_get_directories_recursive(&directories, indir.c_str(), 0, 0); + std::vector directories = path_get_directories_recursive(indir.c_str(), 0, 0); for (std::wstring& i : directories) { std::wstring _indir = indir + i + L'\\'; std::wstring _outdir = outdir + i + L'\\'; @@ -134,19 +132,18 @@ int32_t wmain(int32_t argc, wchar_t** argv) { && !CreateDirectoryW(_outdir.c_str(), 0)) continue; - std::vector files; - path_get_files(&files, _indir.c_str()); + std::vector files = path_get_files(_indir.c_str()); for (std::wstring& j : files) { std::wstring infile = _indir + j; std::wstring outfile = _outdir + j; - stream in_file; - stream out_file; + file_stream in_file; + file_stream out_file; in_file.open(infile.c_str(), L"rb"); out_file.open(outfile.c_str(), L"wb"); - if (in_file.io.stream && out_file.io.stream) { + if (in_file.check_not_null() && out_file.check_not_null()) { printf(encrypt ? "Encrypting %ls\\%ls\n" : "Decrypting %ls\\%ls\n", i.c_str(), j.c_str()); aes256_ctx_set_iv(&ctx, mmplus_iv); diff --git a/src/ReDIVA/classes.cpp b/src/ReDIVA/classes.cpp index 7ad79169..255bfe24 100644 --- a/src/ReDIVA/classes.cpp +++ b/src/ReDIVA/classes.cpp @@ -13,10 +13,10 @@ void classes_process_init(classes_data* classes, const size_t classes_count, ren for (size_t i = 0; i < classes_count; i++) { classes_data* c = &classes[i]; - lock_init(&c->data.lock); - if (lock_check_init(&c->data.lock) + c->data.lock = new lock; + if (c->data.lock->check_init() && c->flags & (CLASSES_INIT_AT_STARTUP | CLASSES_SHOW_AT_STARTUP) && c->init) { - lock_lock(&c->data.lock); + lock_lock(c->data.lock); if (c->init(&c->data, rctx)) c->data.flags = CLASS_INIT; else @@ -25,16 +25,16 @@ void classes_process_init(classes_data* classes, const size_t classes_count, ren if (~c->flags & CLASSES_SHOW_AT_STARTUP) enum_or(c->data.flags, CLASS_HIDDEN); - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } - if (lock_check_init(&c->data.lock) + if (c->data.lock->check_init() && c->flags & CLASSES_SHOW_AT_STARTUP) { - lock_lock(&c->data.lock); + lock_lock(c->data.lock); if (c->data.flags & CLASS_INIT && ((c->show && c->show(&c->data)) || !c->show)) { enum_and(c->data.flags, ~(CLASS_HIDE | CLASS_HIDDEN)); } - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } if (c->sub_classes && c->sub_classes_count) @@ -48,20 +48,20 @@ void classes_process_ctrl(classes_data* classes, const size_t classes_count) { for (size_t i = 0; i < classes_count; i++) { classes_data* c = &classes[i]; - if (lock_check_init(&c->data.lock)) { + if (c->data.lock->check_init()) { if (c->data.flags & CLASS_HIDE) { - lock_lock(&c->data.lock); + lock_lock(c->data.lock); if (~c->data.flags & CLASS_HIDDEN && ((c->hide && c->hide(&c->data)) || !c->hide)) { enum_and(c->data.flags, ~CLASS_HIDE); enum_or(c->data.flags, CLASS_HIDDEN); enum_and(c->data.flags, ~CLASS_HAS_PARENT); } - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } if ((c->data.flags & CLASS_DISPOSE || (c->data.flags & CLASS_HIDDEN && c->flags & CLASSES_DISPOSE_AT_HIDE))) { - lock_lock(&c->data.lock); + lock_lock(c->data.lock); if (~c->data.flags & CLASS_HIDDEN && ((c->hide && c->hide(&c->data)) || !c->hide)) { enum_and(c->data.flags, ~CLASS_HIDE); enum_or(c->data.flags, CLASS_HIDDEN); @@ -73,14 +73,14 @@ void classes_process_ctrl(classes_data* classes, const size_t classes_count) { enum_or(c->data.flags, CLASS_DISPOSED); c->data.imgui_focus = false; } - lock_unlock(&c->data.lock); - lock_free(&c->data.lock); + lock_unlock(c->data.lock); + delete c->data.lock; } if (c->data.flags & CLASS_INIT && c->ctrl) { - lock_lock(&c->data.lock); + lock_lock(c->data.lock); c->ctrl(&c->data); - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } } @@ -91,11 +91,11 @@ void classes_process_ctrl(classes_data* classes, const size_t classes_count) { void classes_process_disp(classes_data* classes, size_t classes_count) { for (size_t i = 0; i < classes_count; i++) { classes_data* c = &classes[i]; - if (lock_check_init(&c->data.lock) && c->disp) { - lock_lock(&c->data.lock); + if (c->data.lock->check_init() && c->disp) { + lock_lock(c->data.lock); if (c->data.flags & CLASS_INIT) c->disp(&c->data); - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } if (c->sub_classes && c->sub_classes_count) @@ -109,11 +109,11 @@ void classes_process_drop(classes_data* classes, size_t classes_count, size_t co for (size_t i = 0; i < classes_count; i++) { classes_data* c = &classes[i]; - if (lock_check_init(&c->data.lock) && c->drop) { - lock_lock(&c->data.lock); + if (c->data.lock->check_init() && c->drop) { + lock_lock(c->data.lock); if (c->data.flags & CLASS_INIT) c->drop(&c->data, count, paths); - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } if (c->sub_classes && c->sub_classes_count) @@ -127,14 +127,14 @@ void classes_process_imgui(classes_data* classes, const size_t classes_count) { for (size_t i = 0; i < classes_count; i++) { classes_data* c = &classes[i]; - if (lock_check_init(&c->data.lock)) { - lock_lock(&c->data.lock); + if (c->data.lock->check_init()) { + lock_lock(c->data.lock); if (~c->data.flags & CLASS_HIDDEN) { if (c->imgui) c->imgui(&c->data); input_locked |= c->data.imgui_focus; } - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } classes_process_imgui(c->sub_classes, c->sub_classes_count); @@ -147,14 +147,14 @@ void classes_process_input(classes_data* classes, const size_t classes_count) { for (size_t i = 0; i < classes_count; i++) { classes_data* c = &classes[i]; - if (lock_check_init(&c->data.lock)) { - lock_lock(&c->data.lock); + if (c->data.lock->check_init()) { + lock_lock(c->data.lock); if (c->data.flags & CLASS_INIT) { if (c->input) c->input(&c->data); input_locked |= c->data.imgui_focus; } - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } classes_process_input(c->sub_classes, c->sub_classes_count); @@ -167,11 +167,11 @@ void classes_process_sound(classes_data* classes, const size_t classes_count) { for (size_t i = 0; i < classes_count; i++) { classes_data* c = &classes[i]; - if (lock_check_init(&c->data.lock) && c->sound) { - lock_lock(&c->data.lock); + if (c->data.lock->check_init() && c->sound) { + lock_lock(c->data.lock); if (c->data.flags & CLASS_INIT) c->sound(&c->data); - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } classes_process_sound(c->sub_classes, c->sub_classes_count); @@ -184,8 +184,8 @@ void classes_process_dispose(classes_data* classes, const size_t classes_count) for (size_t i = 0; i < classes_count; i++) { classes_data* c = &classes[i]; - if (lock_check_init(&c->data.lock)) { - lock_lock(&c->data.lock); + if (c->data.lock->check_init()) { + lock_lock(c->data.lock); if (~c->data.flags & CLASS_HIDDEN && ((c->hide && c->hide(&c->data)) || !c->hide)) { enum_and(c->data.flags, ~CLASS_HIDE); enum_or(c->data.flags, CLASS_HIDDEN); @@ -197,9 +197,10 @@ void classes_process_dispose(classes_data* classes, const size_t classes_count) enum_or(c->data.flags, CLASS_DISPOSED); c->data.imgui_focus = false; } - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } - lock_free(&c->data.lock); + delete c->data.lock; + c->data.lock = 0; classes_process_dispose(c->sub_classes, c->sub_classes_count); } diff --git a/src/ReDIVA/classes.hpp b/src/ReDIVA/classes.hpp index f96b1832..a42b9720 100644 --- a/src/ReDIVA/classes.hpp +++ b/src/ReDIVA/classes.hpp @@ -30,7 +30,7 @@ enum classes_enum { }; struct class_data { - lock lock; + lock* lock; class_flags flags; bool imgui_focus; void* data; diff --git a/src/ReDIVA/classes/data_view/auth_3d.cpp b/src/ReDIVA/classes/data_view/auth_3d.cpp index 63344647..c4a8d010 100644 --- a/src/ReDIVA/classes/data_view/auth_3d.cpp +++ b/src/ReDIVA/classes/data_view/auth_3d.cpp @@ -4,6 +4,7 @@ */ #include "auth_3d.hpp" +#include "../../../KKdLib/database/item_table.hpp" #include "../../../CRE/auth_3d.hpp" #include "../../imgui_helper.hpp" #include "../../input.hpp" @@ -66,8 +67,8 @@ void data_view_auth_3d_imgui(class_data* data) { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 480.0f); - float_t h = min((float_t)height, 540.0f); + float_t w = min_def((float_t)width, 480.0f); + float_t h = min_def((float_t)height, 540.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Appearing); @@ -98,7 +99,7 @@ void data_view_auth_3d_imgui(class_data* data) { if (auth->id == -1) continue; - size_t str_len = min(sizeof(buf) - 1, auth->file_name.size()); + size_t str_len = min_def(sizeof(buf) - 1, auth->file_name.size()); memcpy(buf, auth->file_name.c_str(), str_len); buf[str_len] = 0; @@ -122,6 +123,16 @@ void data_view_auth_3d_imgui(class_data* data) { tree_node_flags = tree_node_base_flags; tree_node_flags |= ImGuiTreeNodeFlags_DefaultOpen; + if (auth->chara_id != -1) + ImGui::Text("Chara: %d", auth->chara_id); + else + ImGui::Text("Chara: None"); + + if (auth->src_chara != auth->dst_chara) + ImGui::Text("Chara Replace: %s/%s", + chara_index_get_auth_3d_name((chara_index)auth->src_chara), + chara_index_get_auth_3d_name((chara_index)auth->dst_chara)); + if (auth->ambient.size() > 0 && ImGui::TreeNodeEx("Ambient", tree_node_flags)) { for (auth_3d_ambient& l : auth->ambient) diff --git a/src/ReDIVA/classes/data_view/draw_task.cpp b/src/ReDIVA/classes/data_view/draw_task.cpp index b21e96a8..4537f717 100644 --- a/src/ReDIVA/classes/data_view/draw_task.cpp +++ b/src/ReDIVA/classes/data_view/draw_task.cpp @@ -55,11 +55,11 @@ static const char* draw_task_type_name[] = { "Object Translucent", }; -typedef std::pair> draw_task_sort; +typedef std::pair draw_task_sort; struct data_view_draw_task { render_context* rctx; - std::vector>> draw_tasks; + std::vector draw_tasks; data_view_draw_task(); virtual ~data_view_draw_task(); @@ -70,14 +70,13 @@ extern int32_t height; const char* data_view_draw_task_window_title = "Draw Task##Data Viewer"; -static int draw_task_sort_sort(void const* src1, void const* src2); static void data_view_draw_task_imgui_draw_object(draw_object* object); bool data_view_draw_task_init(class_data* data, render_context* rctx) { - data->data = new data_view_draw_task; - data_view_draw_task* data_view = (data_view_draw_task*)data->data; + data_view_draw_task* data_view = new data_view_draw_task; if (data_view) data_view->rctx = rctx; + data->data = data_view; return true; } @@ -86,8 +85,8 @@ void data_view_draw_task_imgui(class_data* data) { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 480.0f); - float_t h = min((float_t)height, 542.0f); + float_t w = min_def((float_t)width, 480.0f); + float_t h = min_def((float_t)height, 542.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Appearing); @@ -113,7 +112,7 @@ void data_view_draw_task_imgui(class_data* data) { render_context* rctx = data_view->rctx; std::vector* draw_task_array = rctx->object_data.draw_task_array; - std::vector>>& draw_tasks_sort = data_view->draw_tasks; + std::vector& draw_tasks_sort = data_view->draw_tasks; ImGuiTreeNodeFlags tree_node_base_flags = 0; tree_node_base_flags |= ImGuiTreeNodeFlags_OpenOnDoubleClick; @@ -142,15 +141,11 @@ void data_view_draw_task_imgui(class_data* data) { for (draw_task*& j : draw_tasks) { draw_task_sort draw_task; draw_task.first = j; - draw_task.second.first = hash_murmurhash(&j, 8, 0, true); - draw_task.second.second = (uint32_t)(&j - draw_tasks.data()); + draw_task.second = hash_murmurhash(&j, 8, 0, true); draw_tasks_sort.push_back(draw_task); } - quicksort_custom(draw_tasks_sort.data(), draw_tasks_sort.size(), - sizeof(draw_task_sort), draw_task_sort_sort); - - ImGui::Text(" Hash; Index; Type"); + ImGui::Text(" Hash; Type"); for (draw_task_sort& j : draw_tasks_sort) { draw_task* task = j.first; @@ -158,8 +153,8 @@ void data_view_draw_task_imgui(class_data* data) { continue; ImGui::PushID(task); - if (!ImGui::TreeNodeEx("", tree_node_flags, "%08x; %8u; %s", - j.second.first, j.second.second, draw_task_type_name[task->type])) { + if (!ImGui::TreeNodeEx("", tree_node_flags, "%08x; %s", + j.second, draw_task_type_name[task->type])) { ImGui::PopID(); continue; } @@ -169,7 +164,7 @@ void data_view_draw_task_imgui(class_data* data) { vec3 rot; mat4_get_rotation(&task->mat, &rot); - vec3_mult_scalar(rot, RAD_TO_DEG_FLOAT, rot); + rot *= RAD_TO_DEG_FLOAT; vec3 scale; mat4_get_scale(&task->mat, &scale); @@ -220,8 +215,10 @@ void data_view_draw_task_imgui(class_data* data) { bool data_view_draw_task_dispose(class_data* data) { data_view_draw_task* data_view = (data_view_draw_task*)data->data; - delete data_view; - data->data = 0; + if (data_view) { + delete data_view; + data->data = 0; + } return true; } @@ -233,12 +230,6 @@ data_view_draw_task::~data_view_draw_task() { } -static int draw_task_sort_sort(void const* src1, void const* src2) { - float_t d1 = ((draw_task_sort*)src1)->first->depth; - float_t d2 = ((draw_task_sort*)src2)->first->depth; - return d1 > d2 ? -1 : (d1 < d2 ? 1 : 0); -} - static void data_view_draw_task_imgui_draw_object(draw_object* object) { ImGui::Text("Mesh Name: %s", object->mesh->name); ImGui::Text("Sub Mesh Index: %lld", object->sub_mesh - object->mesh->submesh_array); diff --git a/src/ReDIVA/classes/data_view/glitter.cpp b/src/ReDIVA/classes/data_view/glitter.cpp index 156aa067..2b08d90b 100644 --- a/src/ReDIVA/classes/data_view/glitter.cpp +++ b/src/ReDIVA/classes/data_view/glitter.cpp @@ -8,21 +8,13 @@ #include "../../../CRE/render_context.hpp" #include "../../imgui_helper.hpp" -struct data_view_glitter { - render_context* rctx; -}; - extern int32_t width; extern int32_t height; const char* data_view_glitter_window_title = "Glitter##Data Viewer"; bool data_view_glitter_init(class_data* data, render_context* rctx) { - data->data = force_malloc(sizeof(data_view_glitter)); - data_view_glitter* data_view = (data_view_glitter*)data->data; - if (data_view) { - data_view->rctx = rctx; - } + data->data = rctx; return true; } @@ -31,8 +23,8 @@ void data_view_glitter_imgui(class_data* data) { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 600.0f); - float_t h = min((float_t)height, 480.0f); + float_t w = min_def((float_t)width, 600.0f); + float_t h = min_def((float_t)height, 480.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Appearing); @@ -50,14 +42,12 @@ void data_view_glitter_imgui(class_data* data) { return; } - data_view_glitter* data_view = (data_view_glitter*)data->data; - if (!data_view) { + render_context* rctx = (render_context*)data->data; + if (!rctx) { ImGui::End(); return; } - render_context* rctx = data_view->rctx; - ImGuiTreeNodeFlags tree_node_base_flags = 0; tree_node_base_flags |= ImGuiTreeNodeFlags_OpenOnDoubleClick; tree_node_base_flags |= ImGuiTreeNodeFlags_OpenOnArrow; @@ -221,9 +211,6 @@ void data_view_glitter_imgui(class_data* data) { } bool data_view_glitter_dispose(class_data* data) { - data_view_glitter* data_view = (data_view_glitter*)data->data; - if (data_view) { - } - free(data->data); + data->data = 0; return true; } diff --git a/src/ReDIVA/classes/data_view/object.cpp b/src/ReDIVA/classes/data_view/object.cpp index 7a529ac7..68672936 100644 --- a/src/ReDIVA/classes/data_view/object.cpp +++ b/src/ReDIVA/classes/data_view/object.cpp @@ -7,21 +7,13 @@ #include "../../../CRE/render_context.hpp" #include "../../imgui_helper.hpp" -struct data_view_object { - render_context* rctx; -}; - extern int32_t width; extern int32_t height; const char* data_view_object_window_title = "Object##Data Viewer"; bool data_view_object_init(class_data* data, render_context* rctx) { - data->data = force_malloc(sizeof(data_view_object)); - data_view_object* data_view = (data_view_object*)data->data; - if (data_view) { - data_view->rctx = rctx; - } + data->data = rctx; return true; } @@ -30,8 +22,8 @@ void data_view_object_imgui(class_data* data) { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 420.0f); - float_t h = min((float_t)height, 480.0f); + float_t w = min_def((float_t)width, 420.0f); + float_t h = min_def((float_t)height, 480.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Appearing); @@ -49,14 +41,12 @@ void data_view_object_imgui(class_data* data) { return; } - data_view_object* data_view = (data_view_object*)data->data; - if (!data_view) { + render_context* rctx = (render_context*)data->data; + if (!rctx) { ImGui::End(); return; } - render_context* rctx = data_view->rctx; - size_t count = object_storage_get_obj_set_count(); for (size_t i = 0; i < count; i++) { obj_set_handler* handler = object_storage_get_obj_set_handler_by_index(i); @@ -78,9 +68,6 @@ void data_view_object_imgui(class_data* data) { } bool data_view_object_dispose(class_data* data) { - data_view_object* data_view = (data_view_object*)data->data; - if (data_view) { - } - free(data->data); + data->data = 0; return true; } diff --git a/src/ReDIVA/classes/data_view/texture.cpp b/src/ReDIVA/classes/data_view/texture.cpp index f59aacf4..b27f0c79 100644 --- a/src/ReDIVA/classes/data_view/texture.cpp +++ b/src/ReDIVA/classes/data_view/texture.cpp @@ -7,21 +7,13 @@ #include "../../../CRE/render_context.hpp" #include "../../imgui_helper.hpp" -struct data_view_texture { - render_context* rctx; -}; - extern int32_t width; extern int32_t height; const char* data_view_texture_window_title = "Texture##Data Viewer"; bool data_view_texture_init(class_data* data, render_context* rctx) { - data->data = force_malloc(sizeof(data_view_texture)); - data_view_texture* data_view = (data_view_texture*)data->data; - if (data_view) { - data_view->rctx = rctx; - } + data->data = rctx; return true; } @@ -30,8 +22,8 @@ void data_view_texture_imgui(class_data* data) { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 580.0f); - float_t h = min((float_t)height, 480.0f); + float_t w = min_def((float_t)width, 580.0f); + float_t h = min_def((float_t)height, 480.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Appearing); @@ -49,14 +41,12 @@ void data_view_texture_imgui(class_data* data) { return; } - data_view_texture* data_view = (data_view_texture*)data->data; - if (!data_view) { + render_context* rctx = (render_context*)data->data; + if (!rctx) { ImGui::End(); return; } - render_context* rctx = data_view->rctx; - size_t count = texture_storage_get_texture_count(); for (size_t i = 0; i < count; i++) { texture* tex = texture_storage_get_texture_by_index(i); @@ -76,9 +66,6 @@ void data_view_texture_imgui(class_data* data) { } bool data_view_texture_dispose(class_data* data) { - data_view_texture* data_view = (data_view_texture*)data->data; - if (data_view) { - } - free(data->data); + data->data = 0; return true; } diff --git a/src/ReDIVA/classes/glitter_editor.cpp b/src/ReDIVA/classes/glitter_editor.cpp index 3634f617..bc018996 100644 --- a/src/ReDIVA/classes/glitter_editor.cpp +++ b/src/ReDIVA/classes/glitter_editor.cpp @@ -7,8 +7,8 @@ #if defined(ReDIVA_DEV) #include "glitter_editor.hpp" +#include "../../KKdLib/io/file_stream.hpp" #include "../../KKdLib/io/path.hpp" -#include "../../KKdLib/io/stream.hpp" #include "../../KKdLib/dds.hpp" #include "../../KKdLib/interpolation.hpp" #include "../../KKdLib/str_utils.hpp" @@ -82,6 +82,11 @@ struct GlitterEditor { bool add_curve; bool del_curve; bool key_edit; + + CurveEditor(); + + void ResetCurves(); + void ResetState(Glitter::CurveType type = (Glitter::CurveType)-1); }; struct GL { @@ -148,8 +153,7 @@ struct GlitterEditor { Glitter::Scene* scene; uint64_t hash; Glitter::SceneCounter scene_counter; - char file[MAX_PATH * 2]; - GLuint vao; + std::string file; glitter_editor_selected_enum selected_type; int32_t selected_resource; @@ -159,6 +163,13 @@ struct GlitterEditor { CurveEditor curve_editor; GlitterEditor::GL* gl_data; + + GlitterEditor(); + virtual ~GlitterEditor(); + + void Reset(); + + static void ResetDisp(); }; static const float_t curve_base_values[] = { @@ -219,8 +230,6 @@ static void glitter_editor_select_particle(GlitterEditor* glt_edt); static void glitter_editor_windows(GlitterEditor* glt_edt, class_data* data); static void glitter_editor_reload(GlitterEditor* glt_edt); -static void glitter_editor_reset(GlitterEditor* glt_edt); -static void glitter_editor_reset_draw(); static void glitter_editor_save(GlitterEditor* glt_edt); static void glitter_editor_open_window(GlitterEditor* glt_edt); static void glitter_editor_save_window(GlitterEditor* glt_edt); @@ -262,10 +271,8 @@ static void glitter_editor_file_load_error_list_popup(GlitterEditor* glt_edt, cl static void glitter_editor_file_save_popup(GlitterEditor* glt_edt, class_data* data, ImGuiIO& io, ImGuiStyle& style, ImFont* font, const float_t title_bar_size); -static void glitter_editor_curve_editor(GlitterEditor* glt_edt); static void glitter_editor_curve_editor_curve_set(GlitterEditor* glt_edt, Glitter::Curve* curve, Glitter::CurveType type); -static void glitter_editor_curve_editor_curves_reset(GlitterEditor* glt_edt); static Glitter::Curve::Key* glitter_editor_curve_editor_get_closest_key( GlitterEditor* glt_edt, Glitter::Curve* curve); static Glitter::Curve::Key* glitter_editor_curve_editor_get_selected_key( @@ -275,16 +282,13 @@ static float_t glitter_editor_curve_editor_get_value(GlitterEditor* glt_edt, static void glitter_editor_curve_editor_key_manager(GlitterEditor* glt_edt, std::vector* keys, bool* add_key, bool* del_key); static void glitter_editor_curve_editor_property_window(GlitterEditor* glt_edt, class_data* data); -static void glitter_editor_curve_editor_reset_state(GlitterEditor* glt_edt, - Glitter::CurveType type); static void glitter_editor_curve_editor_selector(GlitterEditor* glt_edt, class_data* data); +static void glitter_editor_curve_editor_windows(GlitterEditor* glt_edt); static bool glitter_editor_hash_input(GlitterEditor* glt_edt, const char* label, uint64_t* hash); bool glitter_editor_init(class_data* data, render_context* rctx) { - data->data = force_malloc_s(GlitterEditor, 1); - LARGE_INTEGER time; QueryPerformanceCounter(&time); Glitter::glt_particle_manager->random.value = (uint32_t)(time.LowPart * hash_fnv1a64m_empty); @@ -293,20 +297,17 @@ bool glitter_editor_init(class_data* data, render_context* rctx) { QueryPerformanceCounter(&time); Glitter::glt_particle_manager->counter = (uint32_t)(time.LowPart * hash_murmurhash_empty); - GlitterEditor* glt_edt = (GlitterEditor*)data->data; + GlitterEditor* glt_edt = new GlitterEditor; if (glt_edt) { - glt_edt->test = false; - glt_edt->draw_flags = (glitter_editor_draw_flags)0; Glitter::glt_particle_manager->emission = 1.0f; Glitter::glt_particle_manager->draw_all = true; Glitter::glt_particle_manager->draw_all_mesh = true; - glGenVertexArrays(1, &glt_edt->vao); draw_grid_3d = true; - glitter_editor_reset(glt_edt); - GlitterEditor::GL::Load(glt_edt); + glt_edt->Reset(); dtm_stg_load(0); } + data->data = glt_edt; input_reset = true; @@ -344,7 +345,7 @@ bool glitter_editor_init(class_data* data, render_context* rctx) { uint64_t* hashes = force_malloc_s(uint64_t, count); for (size_t i = 0; i < count; i++) { size_t len = utf8_length(lines[i]); - hashes[i] = hash_murmurhash(lines[i], min(len, 0x7F)); + hashes[i] = hash_murmurhash(lines[i], min_def(len, 0x7F)); } for (ssize_t i = 0; i < c; i++) { @@ -382,12 +383,12 @@ bool glitter_editor_init(class_data* data, render_context* rctx) { Glitter::EffectGroup_dispose(fr->effect_group); } - free(file_x); + free_def(file_x); } - free(lines); - free(hashes); + free_def(lines); + free_def(hashes); } - free(data); + free_def(data); } for (string* i = files_x.begin; i != files_x.end; i++) string_free(i); @@ -441,7 +442,7 @@ bool glitter_editor_init(class_data* data, render_context* rctx) { Glitter::EffectGroup_dispose(fr->effect_group); } - free(file_x); + free_def(file_x); } for (string* i = files_x.begin; i != files_x.end; i++) string_free(i); @@ -492,7 +493,7 @@ bool glitter_editor_init(class_data* data, render_context* rctx) { uint64_t* hashes = force_malloc_s(uint64_t, count); for (size_t i = 0; i < count; i++) { size_t len = utf8_length(lines[i]); - hashes[i] = hash_murmurhash(lines[i], min(len, 0x7F)); + hashes[i] = hash_murmurhash(lines[i], min_def(len, 0x7F)); } ssize_t c = vector_old_length(files_f2); @@ -525,7 +526,7 @@ bool glitter_editor_init(class_data* data, render_context* rctx) { break; size_t len = utf8_length(lines[j]); - memcpy(e->name, lines[j], min(len, 0x7F)); + memcpy(e->name, lines[j], min_def(len, 0x7F)); } glt_edt->effect_group = fr->effect_group; @@ -533,14 +534,14 @@ bool glitter_editor_init(class_data* data, render_context* rctx) { //glitter_editor_save_file(path_ft, file_ft); Glitter::EffectGroup_dispose(fr->effect_group); } - free(file_f2); - free(file_ft); + free_def(file_f2); + free_def(file_ft); } glitter_file_reader_dispose(fr); - free(buf); - free(lines); - free(hashes); + free_def(buf); + free_def(lines); + free_def(hashes); } for (string* i = files_f2.begin; i != files_f2.end; i++) string_free(i); @@ -549,7 +550,7 @@ bool glitter_editor_init(class_data* data, render_context* rctx) { for (string* i = files_ft.begin; i != files_ft.end; i++) string_free(i); vector_old_string_free(&files_ft); - free(data); + free_def(data); glt_edt->effect_group = 0;*/ return true; } @@ -567,7 +568,7 @@ void glitter_editor_ctrl(class_data* data) { if (glt_edt->effect_group_add) { Glitter::glt_particle_manager->UnloadEffectGroup(glt_edt->hash); - glitter_editor_reset_draw(); + GlitterEditor::ResetDisp(); LARGE_INTEGER time; QueryPerformanceCounter(&time); @@ -921,8 +922,8 @@ void glitter_editor_ctrl(class_data* data) { glt_edt->particle_flags = (glitter_editor_flags)0; if (glt_edt->load || glt_edt->save) { - char* file = str_utils_get_without_extension(glt_edt->file); - char* path = str_utils_split_right_get_left_include(glt_edt->file, '\\'); + char* file = str_utils_get_without_extension(glt_edt->file.c_str()); + char* path = str_utils_split_right_get_left_include(glt_edt->file.c_str(), '\\'); if (glt_edt->load) glitter_editor_load_file(glt_edt, path, file); @@ -931,8 +932,8 @@ void glitter_editor_ctrl(class_data* data) { glt_edt->save = false; glt_edt->save_compress = false; - free(path); - free(file); + free_def(path); + free_def(file); return; } else if (eg && glt_edt->load_data) { @@ -1050,12 +1051,12 @@ void glitter_editor_ctrl(class_data* data) { Glitter::glt_particle_manager->FreeSceneEffect(glt_edt->scene_counter); Glitter::glt_particle_manager->UnloadEffectGroup(glt_edt->hash); - glitter_editor_reset_draw(); + GlitterEditor::ResetDisp(); glt_edt->effect_group = 0; glt_edt->scene = 0; glt_edt->hash = 0; glt_edt->scene_counter = 0; - memset(glt_edt->file, 0, sizeof(glt_edt->file)); + glt_edt->file.clear(); glt_edt->close = false; return; } @@ -1116,7 +1117,7 @@ void glitter_editor_ctrl(class_data* data) { rob_frame = glt_edt->frame_counter; if (!glt_edt->effect_group) { - glitter_editor_reset_draw(); + GlitterEditor::ResetDisp(); return; } @@ -1136,9 +1137,7 @@ void glitter_editor_drop(class_data* data, size_t count, char** paths) { if (!glt_edt) return; - size_t c = min(utf8_length(paths[0]), sizeof(glt_edt->file) - 1); - memcpy(glt_edt->file, paths[0], c); - glt_edt->file[c] = 0; + glt_edt->file.assign(paths[0]); glt_edt->load_popup = true; } @@ -1194,54 +1193,99 @@ bool glitter_editor_dispose(class_data* data) { GlitterEditor* glt_edt = (GlitterEditor*)data->data; if (glt_edt) { dtm_stg_unload(); - GlitterEditor::GL::Free(glt_edt); Glitter::glt_particle_manager->FreeSceneEffect(glt_edt->scene_counter); Glitter::glt_particle_manager->UnloadEffectGroup(glt_edt->hash); - - glt_edt->test = false; - glt_edt->create_popup = false; - glt_edt->load = false; - glt_edt->load_data = false; - glt_edt->load_data_wait = false; - glt_edt->load_popup = false; - glt_edt->load_data_popup = false; - glt_edt->load_error_list_popup = false; - glt_edt->save = false; - glt_edt->save_popup = false; - glt_edt->save_compress = false; - glt_edt->close = false; - glt_edt->input_play = false; - glt_edt->input_reload = false; - glt_edt->input_pause = true; - glt_edt->input_reset = false; - glt_edt->effect_group_add = false; - glt_edt->draw_flags = (glitter_editor_draw_flags)0; - glt_edt->resource_flags = (glitter_editor_flags)0; - glt_edt->effect_flags = (glitter_editor_flags)0; - glt_edt->emitter_flags = (glitter_editor_flags)0; - glt_edt->particle_flags = (glitter_editor_flags)0; - glt_edt->frame_counter = 0.0f; - glt_edt->old_frame_counter = 0.0f; - glt_edt->start_frame = 0; - glt_edt->end_frame = 0; - glt_edt->random.value = 0; - glt_edt->random.step = 1; - glt_edt->counter = 0; - glt_edt->effect_group = 0; - glt_edt->scene = 0; - glt_edt->hash = 0; - glt_edt->scene_counter = 0; - memset(glt_edt->file, 0, sizeof(glt_edt->file)); - glDeleteVertexArrays(1, &glt_edt->vao); + delete glt_edt; } draw_grid_3d = false; - free(data->data); + data->data = 0; data->flags = (class_flags)(CLASS_HIDDEN | CLASS_DISPOSED); data->imgui_focus = false; return true; } +GlitterEditor::CurveEditor::CurveEditor() : type(), animation(), list(), key(), frame_width(), +zoom_time(), prev_zoom_time(), zoom_value(), key_radius_in(), key_radius_out(), height_offset(), frame(), +draw_list(), io(), timeline_pos(), range(), add_key(), del_key(), add_curve(), del_curve(), key_edit() { + +} + +void GlitterEditor::CurveEditor::ResetCurves() { + memset(&list, 0, sizeof(list)); + animation = 0; + key = {}; +} + +void GlitterEditor::CurveEditor::ResetState(Glitter::CurveType type) { + if (this->type != type) + this->type = type; + + frame_width = 16; + zoom_time = 1.0f; + prev_zoom_time = 1.0f; + zoom_value = 1.0f; + key_radius_in = 6.0f; + key_radius_out = 8.0f; + height_offset = 20.0f; + frame = 0; + + timeline_pos = -curve_editor_timeline_base_pos; + + switch (type) { + case Glitter::CURVE_TRANSLATION_X: + case Glitter::CURVE_TRANSLATION_Y: + case Glitter::CURVE_TRANSLATION_Z: + range = 25.0f; + break; + case Glitter::CURVE_ROTATION_X: + case Glitter::CURVE_ROTATION_Y: + case Glitter::CURVE_ROTATION_Z: + range = 360.0f; + break; + case Glitter::CURVE_SCALE_X: + case Glitter::CURVE_SCALE_Y: + case Glitter::CURVE_SCALE_Z: + case Glitter::CURVE_SCALE_ALL: + 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: + range = 255.0f; + break; + case Glitter::CURVE_EMISSION_INTERVAL: + range = 20.0f; + break; + case Glitter::CURVE_PARTICLES_PER_EMISSION: + 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: + range = 1.0f; + break; + default: + range = 1.0f; + break; + } + + add_key = false; + del_key = false; +} + GlitterEditor::GL::Wireframe::Wireframe() { } @@ -1407,7 +1451,6 @@ void GlitterEditor::GL::Wireframe::Disp(GlitterEditor* glt_edt, gl_state_disable_cull_face(); gl_state_set_polygon_mode(GL_FRONT_AND_BACK, GL_LINE); - gl_state_bind_vertex_array(glt_edt->vao); shader.use(); shader.set("color", 1.0f, 1.0f, 0.0f, 1.0f); for (Glitter::F2RenderGroup*& i : eff->render_scene.groups) { @@ -1426,33 +1469,17 @@ void GlitterEditor::GL::Wireframe::Disp(GlitterEditor* glt_edt, case Glitter::PARTICLE_QUAD: { static const GLsizei buffer_size = sizeof(Glitter::Buffer); - gl_state_bind_array_buffer(rg->vbo); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, buffer_size, - (void*)offsetof(Glitter::Buffer, position)); // Pos - gl_state_bind_array_buffer(0); - - gl_state_bind_element_array_buffer(rg->ebo); + gl_state_bind_vertex_array(rg->vao); glDrawElements(GL_TRIANGLES, (GLsizei)(6 * rg->disp), GL_UNSIGNED_INT, 0); - gl_state_bind_element_array_buffer(0); - - glDisableVertexAttribArray(0); } break; case Glitter::PARTICLE_LINE: case Glitter::PARTICLE_LOCUS: { static const GLsizei buffer_size = sizeof(Glitter::Buffer); - gl_state_bind_array_buffer(rg->vbo); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, buffer_size, - (void*)offsetof(Glitter::Buffer, position)); // Pos - gl_state_bind_array_buffer(0); - + gl_state_bind_vertex_array(rg->vao); const GLenum mode = rg->type == Glitter::PARTICLE_LINE ? GL_LINE_STRIP : GL_TRIANGLE_STRIP; for (std::pair& i : rg->draw_list) glDrawArrays(mode, i.first, i.second); - - glDisableVertexAttribArray(0); } break; } } @@ -1469,7 +1496,6 @@ void GlitterEditor::GL::Wireframe::Disp(GlitterEditor* glt_edt, gl_state_disable_cull_face(); gl_state_set_polygon_mode(GL_FRONT_AND_BACK, GL_LINE); - gl_state_bind_vertex_array(glt_edt->vao); shader.use(); shader.set("color", 1.0f, 1.0f, 0.0f, 1.0f); for (Glitter::XRenderGroup*& i : eff->render_scene.groups) { @@ -1488,33 +1514,17 @@ void GlitterEditor::GL::Wireframe::Disp(GlitterEditor* glt_edt, case Glitter::PARTICLE_QUAD: { static const GLsizei buffer_size = sizeof(Glitter::Buffer); - gl_state_bind_array_buffer(rg->vbo); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, buffer_size, - (void*)offsetof(Glitter::Buffer, position)); // Pos - gl_state_bind_array_buffer(0); - - gl_state_bind_element_array_buffer(rg->ebo); + gl_state_bind_vertex_array(rg->vao); glDrawElements(GL_TRIANGLES, (GLsizei)(6 * rg->disp), GL_UNSIGNED_INT, 0); - gl_state_bind_element_array_buffer(0); - - glDisableVertexAttribArray(0); } break; case Glitter::PARTICLE_LINE: case Glitter::PARTICLE_LOCUS: { static const GLsizei buffer_size = sizeof(Glitter::Buffer); - gl_state_bind_array_buffer(rg->vbo); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, buffer_size, - (void*)offsetof(Glitter::Buffer, position)); // Pos - gl_state_bind_array_buffer(0); - + gl_state_bind_vertex_array(rg->vao); const GLenum mode = rg->type == Glitter::PARTICLE_LINE ? GL_LINE_STRIP : GL_TRIANGLE_STRIP; for (std::pair& i : rg->draw_list) glDrawArrays(mode, i.first, i.second); - - glDisableVertexAttribArray(0); } break; case Glitter::PARTICLE_MESH: GlitterEditor::GL::Wireframe::DispMesh(glt_edt, rg); @@ -1530,7 +1540,7 @@ void GlitterEditor::GL::Wireframe::DispMesh(GlitterEditor* glt_edt, Glitter::XRenderGroup* rg) { Glitter::RenderElement* elem = rg->elements; for (size_t i = rg->ctrl, j_max = 1024; i > 0; i -= j_max) { - j_max = min(i, j_max); + j_max = min_def(i, j_max); for (size_t j = j_max; j > 0; elem++) { if (!elem->alive) continue; @@ -1691,6 +1701,37 @@ void GlitterEditor::GL::Free(GlitterEditor* glt_edt) { } } +GlitterEditor::GlitterEditor() : test(), create_popup(), load(), load_wait(), load_data(), +load_data_wait(), load_popup(), load_data_popup(), load_error_list_popup(), save(), save_popup(), +save_compress(), close(), input_play(), input_reload(), input_pause(), input_pause_temp(), input_reset(), +effect_group_add(), draw_flags(), resource_flags(), effect_flags(), emitter_flags(), particle_flags(), +load_glt_type(), save_glt_type(), load_data_type(), frame_counter(), old_frame_counter(), +start_frame(), end_frame(), counter(), effect_group(), scene(), hash(), selected_type(), +selected_resource(), selected_effect(), selected_emitter(), selected_particle(), gl_data() { + GlitterEditor::GL::Load(this); +} + +GlitterEditor::~GlitterEditor() { + GlitterEditor::GL::Free(this); +} + +void GlitterEditor::Reset() { + selected_type = GLITTER_EDITOR_SELECTED_NONE; + selected_resource = -1; + selected_effect = 0; + selected_emitter = 0; + selected_particle = 0; + curve_editor.ResetState(); + curve_editor.ResetCurves(); +} + +void GlitterEditor::ResetDisp() { + Glitter::glt_particle_manager->selected_scene = 0; + Glitter::glt_particle_manager->selected_effect = 0; + Glitter::glt_particle_manager->selected_emitter = 0; + Glitter::glt_particle_manager->selected_particle = 0; +} + static void glitter_editor_select_particle(GlitterEditor* glt_edt) { Glitter::glt_particle_manager->selected_scene = 0; Glitter::glt_particle_manager->selected_effect = 0; @@ -1875,12 +1916,12 @@ static void glitter_editor_windows(GlitterEditor* glt_edt, class_data* data) { bool selected = glt_edt->selected_effect || glt_edt->selected_emitter || glt_edt->selected_particle ? true : false; - win_x = min((float_t)width / 4.0f, 400.0f); + win_x = min_def((float_t)width / 4.0f, 400.0f); 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); + w = min_def((float_t)width / 4.0f, 400.0f); + h = (float_t)height - y - min_def((float_t)height / 3.0f, 320.0f); window_flags = 0; window_flags |= ImGuiWindowFlags_NoTitleBar; @@ -1922,12 +1963,12 @@ static void glitter_editor_windows(GlitterEditor* glt_edt, class_data* data) { } ImGui::PopID(); - win_x = min((float_t)width / 4.0f, 400.0f); + win_x = min_def((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); + h = (float_t)height - y - min_def((float_t)height / 3.0f, 320.0f); window_flags = 0; window_flags |= ImGuiWindowFlags_NoResize; @@ -1948,8 +1989,8 @@ static void glitter_editor_windows(GlitterEditor* glt_edt, class_data* data) { } ImGui::PopID(); - win_x = min((float_t)width / 4.0f, 400.0f); - win_y = min((float_t)height / 3.0f, 320.0f); + win_x = min_def((float_t)width / 4.0f, 400.0f); + win_y = min_def((float_t)height / 3.0f, 320.0f); x = 0; y = (float_t)height - win_y; @@ -1975,8 +2016,8 @@ static void glitter_editor_windows(GlitterEditor* glt_edt, class_data* data) { } ImGui::PopID(); - win_x = min((float_t)width / 4.0f, 400.0f); - win_y = min((float_t)height / 3.0f, 320.0f); + win_x = min_def((float_t)width / 4.0f, 400.0f); + win_y = min_def((float_t)height / 3.0f, 320.0f); x = (float_t)width - win_x; y = (float_t)height - win_y; @@ -2002,8 +2043,8 @@ static void glitter_editor_windows(GlitterEditor* glt_edt, class_data* data) { } ImGui::PopID(); - win_x = min((float_t)width / 4.0f, 400.0f); - win_y = min((float_t)height / 3.0f, 320.0f); + win_x = min_def((float_t)width / 4.0f, 400.0f); + win_y = min_def((float_t)height / 3.0f, 320.0f); x = win_x; y = (float_t)height - win_y; @@ -2023,7 +2064,7 @@ static void glitter_editor_windows(GlitterEditor* glt_edt, class_data* data) { ImGui::PushID("Glitter Editor Curve Editor Window"); if (ImGui::Begin("Curve Editor", 0, window_flags)) { if (glt_edt->effect_group && selected) - glitter_editor_curve_editor(glt_edt); + glitter_editor_curve_editor_windows(glt_edt); data->imgui_focus |= ImGui::IsWindowFocused(); ImGui::End(); } @@ -2074,24 +2115,6 @@ static void glitter_editor_reload(GlitterEditor* glt_edt) { } } -static void glitter_editor_reset(GlitterEditor* glt_edt) { - glt_edt->selected_type = GLITTER_EDITOR_SELECTED_NONE; - glt_edt->selected_resource = -1; - glt_edt->selected_effect = 0; - glt_edt->selected_emitter = 0; - glt_edt->selected_particle = 0; - glitter_editor_curve_editor_reset_state(glt_edt, (Glitter::CurveType)-1); - glitter_editor_curve_editor_curves_reset(glt_edt); - glitter_editor_reset_draw(); -} - -static void glitter_editor_reset_draw() { - Glitter::glt_particle_manager->selected_scene = 0; - Glitter::glt_particle_manager->selected_effect = 0; - Glitter::glt_particle_manager->selected_emitter = 0; - Glitter::glt_particle_manager->selected_particle = 0; -} - static void glitter_editor_save(GlitterEditor* glt_edt) { glt_edt->save_popup = glt_edt->effect_group && glt_edt->effect_group->type == Glitter::X ? false : true; @@ -2113,8 +2136,8 @@ static void glitter_editor_open_window(GlitterEditor* glt_edt) { ofn.lpstrTitle = L"File to Open"; if (GetOpenFileNameW(&ofn)) { char* file_temp = utf16_to_utf8(file); - memcpy(glt_edt->file, file_temp, utf8_length(file_temp) + 1); - free(file_temp); + glt_edt->file.assign(file_temp); + free_def(file_temp); glt_edt->load_popup = true; } CoUninitialize(); @@ -2155,8 +2178,8 @@ static void glitter_editor_save_as_window(GlitterEditor* glt_edt) { ofn.Flags = OFN_NONETWORKBUTTON; if (GetSaveFileNameW(&ofn)) { char* file_temp = utf16_to_utf8(file); - memcpy(glt_edt->file, file_temp, utf8_length(file_temp) + 1); - free(file_temp); + glt_edt->file.assign(file_temp); + free_def(file_temp); glitter_editor_save(glt_edt); } else @@ -2169,7 +2192,7 @@ static void glitter_editor_load_file(GlitterEditor* glt_edt, const char* path, c Glitter::glt_particle_manager->FreeSceneEffect(glt_edt->scene_counter); Glitter::glt_particle_manager->UnloadEffectGroup(glt_edt->hash); - glitter_editor_reset_draw(); + GlitterEditor::ResetDisp(); glt_edt->effect_group = 0; glt_edt->scene = 0; @@ -2230,7 +2253,7 @@ static void glitter_editor_load_file(GlitterEditor* glt_edt, const char* path, c } } - glitter_editor_reset_draw(); + GlitterEditor::ResetDisp(); Glitter::glt_particle_manager->GetSceneStartEndFrame( &glt_edt->start_frame, &glt_edt->end_frame, glt_edt->scene_counter); @@ -2247,11 +2270,12 @@ static void glitter_editor_load_file(GlitterEditor* glt_edt, const char* path, c glt_edt->load_data_wait = false; } - glitter_editor_reset(glt_edt); + glt_edt->Reset(); } static void glitter_editor_save_file(GlitterEditor* glt_edt, const char* path, const char* file) { - Glitter::FileWriter::Write(glt_edt->save_glt_type, glt_edt->effect_group, path, file, glt_edt->save_compress); + Glitter::FileWriter::Write(glt_edt->save_glt_type, + glt_edt->effect_group, path, file, glt_edt->save_compress); } static bool glitter_editor_list_open_window(Glitter::EffectGroup* eg) { @@ -2271,7 +2295,7 @@ static bool glitter_editor_list_open_window(Glitter::EffectGroup* eg) { ofn.nMaxFile = MAX_PATH; ofn.lpstrTitle = L"File to Open"; if (GetOpenFileNameW(&ofn)) { - stream s; + file_stream s; s.open(file, L"rb"); size_t length = s.length; uint8_t* data = force_malloc_s(uint8_t, length); @@ -2281,7 +2305,7 @@ static bool glitter_editor_list_open_window(Glitter::EffectGroup* eg) { char* buf; char** lines; size_t count; - if (str_utils_text_file_parse(data, length, &buf, &lines, &count)) { + if (str_utils_text_file_parse(data, length, buf, lines, count)) { for (size_t i = 0; i < count; i++) { char* t = strstr(lines[i], "#(?)"); if (t) @@ -2294,12 +2318,12 @@ static bool glitter_editor_list_open_window(Glitter::EffectGroup* eg) { if (eg->type != Glitter::FT) for (size_t i = 0; i < count; i++) { size_t len = utf8_length(lines[i]); - hashes[i] = hash_murmurhash(lines[i], min(len, 0x7F)); + hashes[i] = hash_murmurhash(lines[i], min_def(len, 0x7F)); } else for (size_t i = 0; i < count; i++) { size_t len = utf8_length(lines[i]); - hashes[i] = hash_fnv1a64m(lines[i], min(len, 0x7F)); + hashes[i] = hash_fnv1a64m(lines[i], min_def(len, 0x7F)); } ret = true; @@ -2325,11 +2349,11 @@ static bool glitter_editor_list_open_window(Glitter::EffectGroup* eg) { e->name = lines[j]; } - free(buf); - free(lines); - free(hashes); + free_def(buf); + free_def(lines); + free_def(hashes); } - free(data); + free_def(data); } CoUninitialize(); return ret; @@ -2384,8 +2408,8 @@ static bool glitter_editor_resource_import(GlitterEditor* glt_edt) { do for (uint32_t i = 0; i < tex->mipmaps_count; i++) { txp_mipmap tex_mip; - tex_mip.width = max(d.width >> i, 1); - tex_mip.height = max(d.height >> i, 1); + tex_mip.width = max_def(d.width >> i, 1); + tex_mip.height = max_def(d.height >> i, 1); tex_mip.format = d.format; uint32_t size = txp::get_size(tex_mip.format, tex_mip.width, tex_mip.height); @@ -2405,8 +2429,10 @@ static bool glitter_editor_resource_import(GlitterEditor* glt_edt) { ret = true; } DDSEnd: - free(f); - free(p); + if (f) + free(f); + if (p) + free(p); } CoUninitialize(); return ret; @@ -2451,7 +2477,7 @@ static bool glitter_editor_resource_export(GlitterEditor* glt_edt) { 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)); + uint32_t size = txp::get_size(format, max_def(width >> i, 1), max_def(height >> i, 1)); void* data = force_malloc(size); memcpy(data, tex.mipmaps[index].data.data(), size); d.data.push_back(data); @@ -2460,7 +2486,8 @@ static bool glitter_editor_resource_export(GlitterEditor* glt_edt) { while (index / tex.mipmaps_count < tex.array_size); d.write(p); ret = true; - free(p); + if (p) + free(p); } CoUninitialize(); return ret; @@ -2563,8 +2590,8 @@ static void glitter_editor_test_window(GlitterEditor* glt_edt, class_data* data) data->imgui_focus |= ImGui::IsWindowFocused(); ImGui::End(); - win_x = min((float_t)width, 240.0f); - win_y = min((float_t)height, 96.0f); + win_x = min_def((float_t)width, 240.0f); + win_y = min_def((float_t)height, 96.0f); x = 0.0f; y = (float_t)height - win_y; @@ -2593,7 +2620,7 @@ static void glitter_editor_test_window(GlitterEditor* glt_edt, class_data* data) life_time = 0; frame = Glitter::glt_particle_manager->GetSceneFrameLifeTime(glt_edt->scene_counter, &life_time); - ImGui::Text("%.0f - %.0f/%d", max(glt_edt->frame_counter - glt_edt->start_frame, 0), frame, life_time); + ImGui::Text("%.0f - %.0f/%d", max_def(glt_edt->frame_counter - glt_edt->start_frame, 0), frame, life_time); ctrl = Glitter::glt_particle_manager->GetCtrlCount(Glitter::PARTICLE_QUAD); disp = Glitter::glt_particle_manager->GetDispCount(Glitter::PARTICLE_QUAD); @@ -2993,7 +3020,7 @@ End: case GLITTER_EDITOR_SELECTED_EFFECT: if (glt_edt->selected_type != type || glt_edt->selected_effect != effect) - glitter_editor_reset(glt_edt); + glt_edt->Reset(); glt_edt->selected_effect = effect; glt_edt->selected_emitter = 0; glt_edt->selected_particle = 0; @@ -3001,7 +3028,7 @@ End: case GLITTER_EDITOR_SELECTED_EMITTER: if (glt_edt->selected_type != type || glt_edt->selected_emitter != emitter) - glitter_editor_reset(glt_edt); + glt_edt->Reset(); glt_edt->selected_effect = effect; glt_edt->selected_emitter = emitter; glt_edt->selected_particle = 0; @@ -3009,7 +3036,7 @@ End: case GLITTER_EDITOR_SELECTED_PARTICLE: if (glt_edt->selected_type != type || glt_edt->selected_particle != particle) - glitter_editor_reset(glt_edt); + glt_edt->Reset(); glt_edt->selected_effect = effect; glt_edt->selected_emitter = emitter; glt_edt->selected_particle = particle; @@ -3196,7 +3223,7 @@ static void glitter_editor_play_manager(GlitterEditor* glt_edt) { life_time = 0; frame = Glitter::glt_particle_manager->GetSceneFrameLifeTime(glt_edt->scene_counter, &life_time); - ImGui::Text("%.0f - %.0f/%d", max(glt_edt->frame_counter - glt_edt->start_frame, 0), frame, life_time); + ImGui::Text("%.0f - %.0f/%d", max_def(glt_edt->frame_counter - glt_edt->start_frame, 0), frame, life_time); ctrl = Glitter::glt_particle_manager->GetCtrlCount(Glitter::PARTICLE_QUAD); disp = Glitter::glt_particle_manager->GetDispCount(Glitter::PARTICLE_QUAD); @@ -3299,13 +3326,12 @@ static void glitter_editor_property_effect(GlitterEditor* glt_edt, class_data* d flags & Glitter::CURVE_TYPE_TRANSLATION_XYZ)) changed = true; - vec3 rotation; - vec3_mult_scalar(effect->rotation, RAD_TO_DEG_FLOAT, rotation); + vec3 rotation = effect->rotation * RAD_TO_DEG_FLOAT; if (ImGui::ColumnDragVec3("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); + effect->rotation = rotation * DEG_TO_RAD_FLOAT; changed = true; } @@ -3395,7 +3421,7 @@ static void glitter_editor_property_effect(GlitterEditor* glt_edt, class_data* d 4, &type, 0, false, &data->imgui_focus)) { if (type == 1) { enum_or(effect->data.flags, Glitter::EFFECT_LOCAL); - free(effect->data.ext_anim); + delete effect->data.ext_anim; } else { enum_and(effect->data.flags, ~Glitter::EFFECT_LOCAL); @@ -3408,7 +3434,7 @@ static void glitter_editor_property_effect(GlitterEditor* glt_edt, class_data* d enum_and(effect->data.ext_anim->flags, ~Glitter::EFFECT_EXT_ANIM_CHARA_ANIM); } else - free(effect->data.ext_anim); + delete effect->data.ext_anim; } changed = true; } @@ -3659,12 +3685,12 @@ static void glitter_editor_property_emitter(GlitterEditor* glt_edt, class_data* vec3 rotation = emitter->rotation; if (draw_z_axis) rotation.z -= (float_t)M_PI_2; - vec3_mult_scalar(rotation, RAD_TO_DEG_FLOAT, rotation); + rotation *= RAD_TO_DEG_FLOAT; if (ImGui::ColumnDragVec3("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, rotation); + rotation *= DEG_TO_RAD_FLOAT; if (draw_z_axis) rotation.z += (float_t)M_PI_2; emitter->rotation = rotation; @@ -3672,24 +3698,22 @@ static void glitter_editor_property_emitter(GlitterEditor* glt_edt, class_data* } } else { - vec3 rotation; - vec3_mult_scalar(emitter->rotation, RAD_TO_DEG_FLOAT, rotation); + vec3 rotation = emitter->rotation * RAD_TO_DEG_FLOAT; if (ImGui::ColumnDragVec3("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); + emitter->rotation = rotation * DEG_TO_RAD_FLOAT; changed = true; } } - vec3 rotation_add; - vec3_mult_scalar(emitter->data.rotation_add, RAD_TO_DEG_FLOAT, rotation_add); + vec3 rotation_add = emitter->data.rotation_add * RAD_TO_DEG_FLOAT; if (ImGui::ColumnDragVec3("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); + emitter->data.rotation_add = rotation_add * DEG_TO_RAD_FLOAT; changed = true; } @@ -3730,9 +3754,9 @@ static void glitter_editor_property_emitter(GlitterEditor* glt_edt, class_data* (int32_t*)&emitter->data.timer, 0, true, &data->imgui_focus)) { float_t emission_interval = emitter->data.emission_interval; if (emitter->data.timer == Glitter::EMITTER_TIMER_BY_TIME) - emission_interval = clamp(floorf(emission_interval), 1.0f, FLT_MAX); + emission_interval = clamp_def(floorf(emission_interval), 1.0f, FLT_MAX); else - emission_interval = clamp(emission_interval, 0.0f, FLT_MAX); + emission_interval = clamp_def(emission_interval, 0.0f, FLT_MAX); emitter->data.emission_interval = emission_interval; changed = true; } @@ -4165,12 +4189,12 @@ static void glitter_editor_property_particle(GlitterEditor* glt_edt, class_data* rotation.z -= (float_t)M_PI; else if (draw_z_axis) rotation.z -= (float_t)M_PI_2; - vec3_mult_scalar(rotation, RAD_TO_DEG_FLOAT, rotation); + rotation *= RAD_TO_DEG_FLOAT; if (ImGui::ColumnDragVec3("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, rotation); + rotation *= DEG_TO_RAD_FLOAT; if (draw_prev_pos) rotation.z += (float_t)M_PI; else if (draw_z_axis) @@ -4180,44 +4204,40 @@ static void glitter_editor_property_particle(GlitterEditor* glt_edt, class_data* } } else { - vec3 rotation; - vec3_mult_scalar(particle->data.rotation, RAD_TO_DEG_FLOAT, rotation); + vec3 rotation = particle->data.rotation * RAD_TO_DEG_FLOAT; if (ImGui::ColumnDragVec3("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); + particle->data.rotation = rotation * DEG_TO_RAD_FLOAT; changed = true; } } - vec3 rotation_random; - vec3_mult_scalar(particle->data.rotation_random, RAD_TO_DEG_FLOAT, rotation_random); + vec3 rotation_random = particle->data.rotation_random * RAD_TO_DEG_FLOAT; if (ImGui::ColumnDragVec3("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); + particle->data.rotation_random = rotation_random * DEG_TO_RAD_FLOAT; changed = true; } - vec3 rotation_add; - vec3_mult_scalar(particle->data.rotation_add, RAD_TO_DEG_FLOAT, rotation_add); + vec3 rotation_add = particle->data.rotation_add * RAD_TO_DEG_FLOAT; if (ImGui::ColumnDragVec3("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); + particle->data.rotation_add = rotation_add * DEG_TO_RAD_FLOAT; changed = true; } - vec3 rotation_add_random; - vec3_mult_scalar(particle->data.rotation_add_random, RAD_TO_DEG_FLOAT, rotation_add_random); + vec3 rotation_add_random = particle->data.rotation_add_random * RAD_TO_DEG_FLOAT; if (ImGui::ColumnDragVec3("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); + particle->data.rotation_add_random = rotation_add_random * DEG_TO_RAD_FLOAT; changed = true; } @@ -4386,8 +4406,8 @@ static void glitter_editor_property_particle(GlitterEditor* glt_edt, class_data* 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)); + char** texture_name_list = new char*[rc + 1]; + char* texture_names = new char[0x40 * (rc + 1)]; texture_name_list[0] = texture_names; snprintf(texture_name_list[0], 0x40, "No Texture"); @@ -4414,8 +4434,8 @@ static void glitter_editor_property_particle(GlitterEditor* glt_edt, class_data* idx1, &tex11_anim, &tex1_frame, &tex1_index, &tex1_tex)) changed = true; } - free(texture_names); - free(texture_name_list); + delete[] texture_names; + delete[] texture_name_list; Glitter::ParticleBlendDraw blend_draw = Glitter::particle_blend_draw_default; for (int32_t i = 0; i < Glitter::particle_blend_mask_types_count; i++) @@ -4466,7 +4486,7 @@ static void glitter_editor_property_particle(GlitterEditor* glt_edt, class_data* 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); + particle->data.uv_index = min_def(particle->data.uv_index, uv_max_count); break; } @@ -5386,878 +5406,6 @@ static float_t convert_value_to_height(GlitterEditor* glt_edt, + crv_edt->height_offset; } -static void glitter_editor_curve_editor(GlitterEditor* glt_edt) { - Glitter::Emitter* sel_emit = glt_edt->selected_emitter; - Glitter::Particle* sel_ptcl = glt_edt->selected_particle; - GlitterEditor::CurveEditor* crv_edt = &glt_edt->curve_editor; - - if (crv_edt->type < Glitter::CURVE_TRANSLATION_X - || crv_edt->type > Glitter::CURVE_V_SCROLL_ALPHA_2ND) - return; - - switch (glt_edt->selected_type) { - case GLITTER_EDITOR_SELECTED_EFFECT: - case GLITTER_EDITOR_SELECTED_EMITTER: - case GLITTER_EDITOR_SELECTED_PARTICLE: - break; - default: - return; - } - - Glitter::EffectGroup* eg = glt_edt->effect_group; - Glitter::Curve* curve = crv_edt->list[crv_edt->type]; - std::vector* keys = curve ? &curve->keys_rev : 0; - bool changed = false; - - bool fix_rot_z = eg->type != Glitter::X && curve && curve->type == Glitter::CURVE_ROTATION_Z - && ((glt_edt->selected_type == GLITTER_EDITOR_SELECTED_EMITTER - && sel_emit->data.direction == Glitter::DIRECTION_Z_AXIS) - || (glt_edt->selected_type == GLITTER_EDITOR_SELECTED_PARTICLE - && sel_ptcl->data.draw_type == Glitter::DIRECTION_Z_AXIS)); - - bool add_key = false; - bool del_key = false; - if (curve) - glitter_editor_curve_editor_key_manager(glt_edt, keys, &add_key, &del_key); - - if (ImGui::IsWindowFocused()) { - if (add_key && ImGui::IsKeyPressed(GLFW_KEY_INSERT)) - crv_edt->add_key = true; - else if (del_key && ImGui::IsKeyPressed(GLFW_KEY_DELETE)) - crv_edt->del_key = true; - else if (ImGui::IsKeyPressed(GLFW_KEY_RIGHT)) - crv_edt->frame++; - else if (ImGui::IsKeyPressed(GLFW_KEY_LEFT)) - crv_edt->frame--; - } - - bool exist = true; - if (crv_edt->add_key && add_key) { - if (!crv_edt->list[crv_edt->type] || !keys || !keys->size()) { - if (!crv_edt->list[crv_edt->type]) { - Glitter::Curve* c = new Glitter::Curve(eg->type); - crv_edt->animation->curves.push_back(curve); - crv_edt->list[crv_edt->type] = c; - curve = c; - } - - glitter_editor_curve_editor_curve_set(glt_edt, curve, crv_edt->type); - - if (!keys) - keys = &curve->keys_rev; - - Glitter::Curve::Key key; - key.frame = 0; - key.value = glitter_editor_curve_editor_get_value(glt_edt, curve->type); - keys->push_back(key); - - crv_edt->frame = 0; - changed = true; - } - else { - std::vector::iterator i = keys->begin(); - bool is_before_start = keys->data()[0].frame > crv_edt->frame; - bool has_key_after = false; - if (!is_before_start) - for (i++; i != keys->end(); i++) - if (crv_edt->frame <= i->frame) { - has_key_after = keys->end() - i > 0; - break; - } - - ssize_t pos = i - keys->begin(); - if (!is_before_start) - pos--; - - if (!is_before_start && has_key_after) { - std::vector::iterator c = i - 1; - std::vector::iterator n = i; - - Glitter::Curve::Key key; - key.frame = crv_edt->frame; - 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; - } - keys->insert(keys->begin() + ++pos, key); - } - else if (is_before_start) { - std::vector::iterator n = i; - - Glitter::Curve::Key key; - key.frame = crv_edt->frame; - key.type = n->type; - key.value = n->value; - key.random_range = n->random_range; - keys->insert(keys->begin() + pos, key); - } - else { - std::vector::iterator c = i - 1; - - Glitter::Curve::Key key; - key.frame = crv_edt->frame; - key.type = c->type; - key.value = c->value; - key.random_range = c->random_range; - keys->insert(keys->begin() + ++pos, key); - } - *crv_edt->list[crv_edt->type] = *curve; - changed = true; - } - } - else if (keys && crv_edt->del_key && del_key) { - for (std::vector::iterator i = keys->begin(); i != keys->end(); i++) - if (&i[0] == crv_edt->key) { - bool has_key_before = keys->front().frame < i->frame; - bool has_key_after = keys->back().frame > i->frame; - if (has_key_before && i[-1].type == Glitter::KEY_HERMITE && has_key_after) { - std::vector::iterator c = i - 1; - std::vector::iterator 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); - } - keys->erase(i); - changed = true; - break; - } - } - else if (crv_edt->add_curve) { - Glitter::Curve* c = new Glitter::Curve(eg->type); - crv_edt->animation->curves.push_back(c); - crv_edt->list[crv_edt->type] = c; - curve = c; - - glitter_editor_curve_editor_curve_set(glt_edt, curve, crv_edt->type); - *crv_edt->list[crv_edt->type] = *curve; - crv_edt->frame = curve->start_time; - changed = true; - } - else if (crv_edt->del_curve) { - Glitter::Curve* c = crv_edt->list[crv_edt->type]; - Glitter::Animation* anim = crv_edt->animation; - for (std::vector::iterator i = anim->curves.begin(); i != anim->curves.end(); i++) - if (*i && *i == c) { - delete* i; - anim->curves.erase(i); - break; - } - - crv_edt->list[crv_edt->type] = 0; - crv_edt->frame = 0; - changed = true; - } - crv_edt->add_key = false; - crv_edt->del_key = false; - crv_edt->add_curve = false; - crv_edt->del_curve = false; - - if (!curve || !keys) - return; - - int32_t start_time = curve->start_time; - int32_t end_time = curve->end_time; - - ImGuiIO& io = ImGui::GetIO(); - ImGuiStyle& style = ImGui::GetStyle(); - ImFont* font = ImGui::GetFont(); - - ImVec2 cont_reg_avail = ImGui::GetContentRegionAvail(); - - ImVec2 canvas_size, canvas_pos, canvas_pos_min, canvas_pos_max; - crv_edt->draw_list = ImGui::GetWindowDrawList(); - canvas_size = cont_reg_avail; - canvas_pos = ImGui::GetCursorScreenPos(); - 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; - - 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 (crv_edt->zoom_time != crv_edt->prev_zoom_time) { - float_t timeline_pos = crv_edt->timeline_pos + curve_editor_timeline_base_pos; - timeline_pos *= crv_edt->zoom_time / crv_edt->prev_zoom_time; - crv_edt->timeline_pos = timeline_pos - curve_editor_timeline_base_pos; - } - crv_edt->prev_zoom_time = crv_edt->zoom_time; - - float_t frame_width = crv_edt->frame_width - * crv_edt->zoom_time; - canvas_pos.x -= crv_edt->timeline_pos; - - ImGui::ItemSize(boundaries); - bool hovered = ImGui::IsMouseHoveringRect(boundaries.Min, boundaries.Max); - ImGui::RenderFrame(boundaries.Min, boundaries.Max, ImGui::GetColorU32(ImGuiCol_FrameBg), true, 1.0f); - - static bool can_drag; - if (hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left, false)) - can_drag = true; - - if (can_drag && (ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT) || ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT))) { - crv_edt->key = glitter_editor_curve_editor_get_closest_key(glt_edt, curve); - crv_edt->frame = crv_edt->key->frame; - } - else - crv_edt->key = glitter_editor_curve_editor_get_selected_key(glt_edt, curve); - - if (can_drag && ImGui::IsMouseReleased(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; - - crv_edt->draw_list->PushClipRect(boundaries.Min, boundaries.Max, true); - - int32_t start = (int32_t)(crv_edt->timeline_pos / frame_width) + start_time; - int32_t end = (int32_t)((crv_edt->timeline_pos + canvas_size.x) / frame_width) + start_time; - - ImU32 line_color_valid_bold = ImGui::GetColorU32({ 0.5f, 0.5f, 0.5f, 0.75f }); - ImU32 line_color_valid = ImGui::GetColorU32({ 0.4f, 0.4f, 0.4f, 0.45f }); - ImU32 line_color_not_valid = ImGui::GetColorU32({ 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) || !f || 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; - crv_edt->draw_list->AddLine({ x, y - canvas_size.y }, - { x, y }, line_color, 0.80f); - - if (bold_frame) { - char buf[0x20]; - snprintf(buf, sizeof(buf), "%d", frame); - crv_edt->draw_list->AddText({ x + 3, canvas_pos.y }, line_color, buf); - } - } - - float_t max = crv_edt->range * (1.0f / crv_edt->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 - - crv_edt->height_offset) + crv_edt->height_offset; - - ImU32 line_color = j % 2 == 1 - ? ImGui::GetColorU32({ 0.35f, 0.35f, 0.35f, 0.45f }) - : ImGui::GetColorU32({ 0.45f, 0.45f, 0.45f, 0.75f }); - bool last = j == 4; - if (j && !last) - crv_edt->draw_list->AddLine({ x_pos, y_pos }, - { x_pos + canvas_size.x, y_pos }, line_color, 0.80f); - - float_t val = max - j * 0.25f * (max - min); - char buf[0x20]; - snprintf(buf, sizeof(buf), "%.2f", val); - crv_edt->draw_list->AddText({ x_pos + 2, y_pos + (last ? -16 : -2) }, - ImGui::GetColorU32({ 0.65f, 0.65f, 0.65f, 0.85f }), buf); - } - - 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(glt_edt, 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 + crv_edt->height_offset; - p2.x = p1.x + canvas_size.x; - p2.y = canvas_pos.y + crv_edt->height_offset; - p3.x = canvas_pos_min.x; - p3.y = canvas_pos.y; - crv_edt->draw_list->AddLine(p1, p2, - ImGui::GetColorU32({ 0.5f, 0.5f, 0.5f, 0.85f }), 2.0f); - - ImU32 random_range_color = ImGui::GetColorU32({ 0.5f, 0.5f, 0.0f, 0.25f }); - ImU32 key_random_range_color = ImGui::GetColorU32({ 0.5f, 0.0f, 0.5f, 0.25f }); - ImU32 default_color = ImGui::GetColorU32({ 1.0f, 1.0f, 1.0f, 0.75f }); - ImU32 selected_color = ImGui::GetColorU32({ 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_ft = eg->type == Glitter::FT; - for (std::vector::iterator i = keys->begin(); i != keys->end(); i++) { - if (i->frame >= end_time || keys->end() - i <= 1) - break; - - std::vector::iterator c = i; - std::vector::iterator 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::KeyType 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; - if (fix_rot_z) { - c_value -= (float_t)M_PI_2; - n_value -= (float_t)M_PI_2; - } - float_t c_random_range = c->random_range; - float_t n_random_range = n->random_range; - if (random_range_mult && glt_type_ft) { - 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_ft) - vec3_mult_scalar(random, 0.01f, random); - } - - if (value.x != value.y) { - float_t y1 = convert_value_to_height(glt_edt, value.x + random.x, - canvas_pos.y, canvas_size.y, min, max); - float_t y2 = convert_value_to_height(glt_edt, value.x, - canvas_pos.y, canvas_size.y, min, max); - float_t y3 = convert_value_to_height(glt_edt, value.x, - canvas_pos.y, canvas_size.y, min, max); - float_t y4 = convert_value_to_height(glt_edt, 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) - crv_edt->draw_list->AddRectFilled({ x1, y1 }, - { 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) - crv_edt->draw_list->AddRectFilled({ x1, y3 }, - { x2, y4 }, key_random_range_color, 0.0f, 0); - } - else { - float_t y1 = convert_value_to_height(glt_edt, value.y + random.y, - canvas_pos.y, canvas_size.y, min, max); - float_t y2 = convert_value_to_height(glt_edt, 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) - crv_edt->draw_list->AddRectFilled({ x1, y1 }, - { x2, y2 }, random_range_color, 0.0f, 0); - } - - if (random_range_negate) - if (value.y != value.z) { - float_t y1 = convert_value_to_height(glt_edt, value.y, - canvas_pos.y, canvas_size.y, min, max); - float_t y2 = convert_value_to_height(glt_edt, value.z, - canvas_pos.y, canvas_size.y, min, max); - float_t y3 = convert_value_to_height(glt_edt, value.z, - canvas_pos.y, canvas_size.y, min, max); - float_t y4 = convert_value_to_height(glt_edt, 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) - crv_edt->draw_list->AddRectFilled({ x1, y1 }, - { 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) - crv_edt->draw_list->AddRectFilled({ x1, y3 }, - { x2, y4 }, random_range_color, 0.0f, 0); - } - else { - float_t y1 = convert_value_to_height(glt_edt, value.y, - canvas_pos.y, canvas_size.y, min, max); - float_t y2 = convert_value_to_height(glt_edt, 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) - crv_edt->draw_list->AddRectFilled({ x1, y1 }, - { 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 = { c_value + c_random_range, c_value, c_value - c_random_range }; - vec3 n_value_vec = { n_value + n_random_range, n_value, n_value - n_random_range }; - vec3 random_vec = { random_range, random_range, 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); - - vec3 random; - if (random_range_mult) { - vec3_mult(random_vec, value, random); - if (!glt_type_ft) - vec3_mult_scalar(random, 0.01f, random); - } - else - random = random_vec; - - if (random_range_mult) { - vec3 random = { random_range, random_range, random_range }; - vec3_mult(random, value, random); - if (!glt_type_ft) - 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(glt_edt, value.x + random.x, - canvas_pos.y, canvas_size.y, min, max); - float_t y2 = convert_value_to_height(glt_edt, value.x, - canvas_pos.y, canvas_size.y, min, max); - float_t y3 = convert_value_to_height(glt_edt, value.x, - canvas_pos.y, canvas_size.y, min, max); - float_t y4 = convert_value_to_height(glt_edt, 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) - crv_edt->draw_list->AddLine({ x, y1 }, - { 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) - crv_edt->draw_list->AddLine({ x, y3 }, - { x, y4 }, key_random_range_color, 0.0f); - } - else { - float_t y1 = convert_value_to_height(glt_edt, value.y + random.y, - canvas_pos.y, canvas_size.y, min, max); - float_t y2 = convert_value_to_height(glt_edt, 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) - crv_edt->draw_list->AddLine({ x, y1 }, - { x, y2 }, random_range_color, 0.0f); - } - - if (random_range_negate) - if (value.y != value.z) { - float_t y1 = convert_value_to_height(glt_edt, value.y, - canvas_pos.y, canvas_size.y, min, max); - float_t y2 = convert_value_to_height(glt_edt, value.z, - canvas_pos.y, canvas_size.y, min, max); - float_t y3 = convert_value_to_height(glt_edt, value.z, - canvas_pos.y, canvas_size.y, min, max); - float_t y4 = convert_value_to_height(glt_edt, 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) - crv_edt->draw_list->AddLine({ x, y1 }, - { 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) - crv_edt->draw_list->AddLine({ x, y3 }, - { x, y4 }, random_range_color, 0.0f); - } - else { - float_t y1 = convert_value_to_height(glt_edt, value.y, - canvas_pos.y, canvas_size.y, min, max); - float_t y2 = convert_value_to_height(glt_edt, 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) - crv_edt->draw_list->AddLine({ x, y1 }, - { x, y2 }, random_range_color, 0.0f); - } - } - } - } - } - - for (std::vector::iterator i = keys->begin(); i != keys->end(); i++) { - if (i->frame >= end_time || keys->end() - i <= 1) - break; - - std::vector::iterator c = i; - std::vector::iterator 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 (fix_rot_z) { - c_value -= (float_t)M_PI_2; - n_value -= (float_t)M_PI_2; - } - - if (i->type != Glitter::KEY_HERMITE) { - float_t y1 = convert_value_to_height(glt_edt, c_value, canvas_pos.y, canvas_size.y, min, max); - float_t y2 = convert_value_to_height(glt_edt, n_value, canvas_pos.y, canvas_size.y, min, max); - - if (i->type == Glitter::KEY_CONSTANT) { - int32_t count = 0; - ImVec2 points_temp[3]; - if (x1 != x2) - points_temp[count++] = { x1, y1 }; - points_temp[count++] = { x2, y1 }; - if (y1 != y2) - points_temp[count++] = { x2, y2 }; - - if (count > 1) - crv_edt->draw_list->AddPolyline(points_temp, - count, default_color, 0, 3.0f); - } - else - crv_edt->draw_list->AddLine({ x1, y1 }, { 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(glt_edt, value, - canvas_pos.y, canvas_size.y, min, max); - points[(i - c->frame) * frame_width_int + j] = point; - } - crv_edt->draw_list->AddPolyline(points, - (int32_t)points_count, default_color, 0, 3.0f); - free(points); - } - } - - const ImU32 key_constant_color = ImGui::GetColorU32({ 1.0f, 0.0f, 0.0f, 0.75f }); - const ImU32 key_linear_color = ImGui::GetColorU32({ 0.0f, 1.0f, 0.0f, 0.75f }); - const ImU32 key_hermite_color = ImGui::GetColorU32({ 0.0f, 0.0f, 1.0f, 0.75f }); - - bool dragged = false; - bool holding_tan = false; - for (std::vector::iterator 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 base_value = i->value; - if (fix_rot_z) - base_value -= (float_t)M_PI_2; - float_t x = canvas_pos.x + ((size_t)i->frame - start_time) * frame_width; - float_t y = convert_value_to_height(glt_edt, base_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; - } - - ImGui::PushID(i._Ptr); - ImGui::SetCursorScreenPos({ x - 7.5f, y - 7.5f }); - ImGui::InvisibleButton("val", { 15.0f, 15.0f }, 0); - - if (can_drag && ImGui::IsItemActive() - && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1.0f)) { - float_t old_y = y; - - static int32_t base_frame; - static float_t base_y; - if ((ImGui::IsKeyPressed(GLFW_KEY_LEFT_SHIFT, false) && !ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT)) - || (ImGui::IsKeyPressed(GLFW_KEY_RIGHT_SHIFT, false) && !ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT))) { - base_frame = i->frame; - base_y = base_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; - crv_edt->frame = (int32_t)roundf((io.MousePos.x - canvas_pos.x) / frame_width); - crv_edt->frame = clamp(crv_edt->frame + start_time, start, end); - if (i->frame != crv_edt->frame) { - i->frame = crv_edt->frame; - changed = true; - } - } - - static float_t mouse_delta_history; - if ((ImGui::IsKeyPressed(GLFW_KEY_LEFT_SHIFT, false) && !ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT)) - || (ImGui::IsKeyPressed(GLFW_KEY_RIGHT_SHIFT, false) && !ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT))) - mouse_delta_history = io.MouseDelta.y; - else if ((ImGui::IsKeyReleased(GLFW_KEY_LEFT_SHIFT) && !ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT)) - || ImGui::IsKeyReleased(GLFW_KEY_RIGHT_SHIFT) && !ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT)) { - y += mouse_delta_history; - y += io.MouseDelta.y; - } - else if (ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT) || ImGui::IsKeyDown(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(glt_edt, - y, canvas_pos.y, canvas_size.y, min, max); - dragged = true; - - if (base_value != value) { - if (fix_rot_z) - value += (float_t)M_PI_2; - i->value = value; - changed = true; - } - crv_edt->key = &i[0]; - } - } - - 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(glt_edt, tangent1 = i->tangent1, - canvas_pos.y, canvas_size.y, min, max); - crv_edt->draw_list->AddLine({ 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)) { - ImGui::SetCursorScreenPos({ circle_pos.x - 7.5f, circle_pos.y - 7.5f }); - ImGui::InvisibleButton("tan1", { 15.0f, 15.0f }, 0); - - if (can_drag && ImGui::IsItemActive()) { - if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { - i->tangent1 = convert_height_to_value(glt_edt, - 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; - - crv_edt->draw_list->AddCircleFilled(circle_pos, - crv_edt->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(glt_edt, tangent2 = i->tangent2, - canvas_pos.y, canvas_size.y, min, max); - crv_edt->draw_list->AddLine({ 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)) { - ImGui::SetCursorScreenPos({ circle_pos.x - 7.5f, circle_pos.y - 7.5f }); - ImGui::InvisibleButton("tan2", { 15.0f, 15.0f }, 0); - - if (can_drag && ImGui::IsItemActive()) { - if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { - i->tangent2 = convert_height_to_value(glt_edt, - 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; - - crv_edt->draw_list->AddCircleFilled(circle_pos, - crv_edt->key_radius_in, tangent2_color, 12); - } - } - - crv_edt->draw_list->AddCircleFilled({ x, y }, - crv_edt->key_radius_out, crv_edt->key == &i[0] ? selected_color : default_color, 12); - crv_edt->draw_list->AddCircleFilled({ x, y }, - crv_edt->key_radius_in, value_color, 12); - ImGui::PopID(); - } - - if (!crv_edt->key_edit && can_drag && ImGui::IsMouseDown(ImGuiMouseButton_Left) && (!holding_tan || dragged)) { - int32_t frame = (int32_t)roundf((io.MousePos.x - canvas_pos.x) / frame_width); - crv_edt->frame = clamp(frame + start_time, start_time, end_time); - if (ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT) || ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT)) { - crv_edt->key = glitter_editor_curve_editor_get_closest_key(glt_edt, curve); - crv_edt->frame = crv_edt->key->frame; - } - else - crv_edt->key = glitter_editor_curve_editor_get_selected_key(glt_edt, curve); - } - crv_edt->frame = clamp(crv_edt->frame, start_time, end_time); - - int32_t cursor_frame = crv_edt->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 = ImGui::GetColorU32({ 0.8f, 0.8f, 0.8f, 0.75f }); - p1.x = cursor_pos.x; - p1.y = canvas_pos.y + canvas_size.y; - crv_edt->draw_list->AddLine(cursor_pos, p1, cursor_color, 2.5f); - - p1 = p2 = p3 = cursor_pos; - p1.x -= 10.0f; - p2.y += 10.0f; - p3.x += 10.0f; - crv_edt->draw_list->AddTriangleFilled(p1, p2, p3, cursor_color); - } - crv_edt->draw_list->PopClipRect(); - - if (hovered) - if (ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT) || ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT)) - crv_edt->timeline_pos -= io.MouseWheel * 25.0f * 4.0f; - else - crv_edt->timeline_pos -= io.MouseWheel * 25.0f; - - crv_edt->timeline_pos = clamp(crv_edt->timeline_pos, - -curve_editor_timeline_base_pos, timeline_max_offset); - - if (crv_edt->list[crv_edt->type] && changed) { - curve->Recalculate(eg->type); - *crv_edt->list[crv_edt->type] = *curve; - glt_edt->input_reload = true; - } -} - static void glitter_editor_curve_editor_curve_set(GlitterEditor* glt_edt, Glitter::Curve* curve, Glitter::CurveType type) { Glitter::EffectGroup* eg = glt_edt->effect_group; @@ -6281,14 +5429,6 @@ static void glitter_editor_curve_editor_curve_set(GlitterEditor* glt_edt, } } -static void glitter_editor_curve_editor_curves_reset(GlitterEditor* glt_edt) { - GlitterEditor::CurveEditor* crv_edt = &glt_edt->curve_editor; - memset(&crv_edt->list, 0, sizeof(Glitter::Curve*) - * (Glitter::CURVE_V_SCROLL_ALPHA_2ND - Glitter::CURVE_TRANSLATION_X + 1)); - crv_edt->animation = 0; - crv_edt->key = {}; -} - static Glitter::Curve::Key* glitter_editor_curve_editor_get_closest_key( GlitterEditor* glt_edt, Glitter::Curve* curve) { GlitterEditor::CurveEditor* crv_edt = &glt_edt->curve_editor; @@ -6646,9 +5786,9 @@ static void glitter_editor_curve_editor_property_window(GlitterEditor* glt_edt, ImGui::SetNextItemWidth(60.0f); if (ImGui::InputInt("##C Type:", &c_type, 1, 1)) { if (eg->type == Glitter::X) - c_type = clamp(c_type, 1, 2); + c_type = clamp_def(c_type, 1, 2); else - c_type = clamp(c_type, 0, 1); + c_type = clamp_def(c_type, 0, 1); if (c_type != curve->version) changed = true; @@ -6662,9 +5802,9 @@ static void glitter_editor_curve_editor_property_window(GlitterEditor* glt_edt, ImGui::SetNextItemWidth(60.0f); if (ImGui::InputInt("##K Type:", &k_type, 1, 1)) { if (eg->type == Glitter::X) - k_type = clamp(k_type, 2, 3); + k_type = clamp_def(k_type, 2, 3); else - k_type = clamp(k_type, 0, 2); + k_type = clamp_def(k_type, 0, 2); if (k_type != curve->keys_version) changed = true; @@ -6737,77 +5877,6 @@ static void glitter_editor_curve_editor_property_window(GlitterEditor* glt_edt, } } -static void glitter_editor_curve_editor_reset_state(GlitterEditor* glt_edt, Glitter::CurveType type) { - GlitterEditor::CurveEditor* crv_edt = &glt_edt->curve_editor; - - if (crv_edt->type != type) - crv_edt->type = type; - - crv_edt->frame_width = 16; - crv_edt->zoom_time = 1.0f; - crv_edt->prev_zoom_time = 1.0f; - crv_edt->zoom_value = 1.0f; - crv_edt->key_radius_in = 6.0f; - crv_edt->key_radius_out = 8.0f; - crv_edt->height_offset = 20.0f; - crv_edt->frame = 0; - - crv_edt->timeline_pos = -curve_editor_timeline_base_pos; - - switch (type) { - case Glitter::CURVE_TRANSLATION_X: - case Glitter::CURVE_TRANSLATION_Y: - case Glitter::CURVE_TRANSLATION_Z: - crv_edt->range = 25.0f; - break; - case Glitter::CURVE_ROTATION_X: - case Glitter::CURVE_ROTATION_Y: - case Glitter::CURVE_ROTATION_Z: - crv_edt->range = 360.0f; - break; - case Glitter::CURVE_SCALE_X: - case Glitter::CURVE_SCALE_Y: - case Glitter::CURVE_SCALE_Z: - case Glitter::CURVE_SCALE_ALL: - crv_edt->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: - crv_edt->range = 255.0f; - break; - case Glitter::CURVE_EMISSION_INTERVAL: - crv_edt->range = 20.0f; - break; - case Glitter::CURVE_PARTICLES_PER_EMISSION: - crv_edt->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: - crv_edt->range = 1.0f; - break; - default: - crv_edt->range = 1.0f; - break; - } - - crv_edt->add_key = false; - crv_edt->del_key = false; -} - static void glitter_editor_curve_editor_selector(GlitterEditor* glt_edt, class_data* data) { GlitterEditor::CurveEditor* crv_edt = &glt_edt->curve_editor; int32_t sel_rsrc = glt_edt->selected_resource; @@ -6871,7 +5940,7 @@ if (flags & Glitter::CURVE_TYPE_##curve_type){ \ ImGui::Selectable(_l, crv_edt->type == Glitter::CURVE_##curve_type); \ \ if (ImGui::IsItemFocused() && crv_edt->type != Glitter::CURVE_##curve_type) { \ - glitter_editor_curve_editor_reset_state(glt_edt, Glitter::CURVE_##curve_type); \ + glt_edt->curve_editor.ResetState(Glitter::CURVE_##curve_type); \ reset = true; \ } \ } @@ -7015,6 +6084,865 @@ if (flags & Glitter::CURVE_TYPE_##curve_type){ \ ImGui::EndGroup(); } +static void glitter_editor_curve_editor_windows(GlitterEditor* glt_edt) { + Glitter::Emitter* sel_emit = glt_edt->selected_emitter; + Glitter::Particle* sel_ptcl = glt_edt->selected_particle; + GlitterEditor::CurveEditor* crv_edt = &glt_edt->curve_editor; + + if (crv_edt->type < Glitter::CURVE_TRANSLATION_X + || crv_edt->type > Glitter::CURVE_V_SCROLL_ALPHA_2ND) + return; + + switch (glt_edt->selected_type) { + case GLITTER_EDITOR_SELECTED_EFFECT: + case GLITTER_EDITOR_SELECTED_EMITTER: + case GLITTER_EDITOR_SELECTED_PARTICLE: + break; + default: + return; + } + + Glitter::EffectGroup* eg = glt_edt->effect_group; + Glitter::Curve* curve = crv_edt->list[crv_edt->type]; + std::vector* keys = curve ? &curve->keys_rev : 0; + bool changed = false; + + bool fix_rot_z = eg->type != Glitter::X && curve && curve->type == Glitter::CURVE_ROTATION_Z + && ((glt_edt->selected_type == GLITTER_EDITOR_SELECTED_EMITTER + && sel_emit->data.direction == Glitter::DIRECTION_Z_AXIS) + || (glt_edt->selected_type == GLITTER_EDITOR_SELECTED_PARTICLE + && sel_ptcl->data.draw_type == Glitter::DIRECTION_Z_AXIS)); + + bool add_key = false; + bool del_key = false; + if (curve) + glitter_editor_curve_editor_key_manager(glt_edt, keys, &add_key, &del_key); + + if (ImGui::IsWindowFocused()) { + if (add_key && ImGui::IsKeyPressed(GLFW_KEY_INSERT)) + crv_edt->add_key = true; + else if (del_key && ImGui::IsKeyPressed(GLFW_KEY_DELETE)) + crv_edt->del_key = true; + else if (ImGui::IsKeyPressed(GLFW_KEY_RIGHT)) + crv_edt->frame++; + else if (ImGui::IsKeyPressed(GLFW_KEY_LEFT)) + crv_edt->frame--; + } + + bool exist = true; + if (crv_edt->add_key && add_key) { + if (!crv_edt->list[crv_edt->type] || !keys || !keys->size()) { + if (!crv_edt->list[crv_edt->type]) { + Glitter::Curve* c = new Glitter::Curve(eg->type); + crv_edt->animation->curves.push_back(curve); + crv_edt->list[crv_edt->type] = c; + curve = c; + } + + glitter_editor_curve_editor_curve_set(glt_edt, curve, crv_edt->type); + + if (!keys) + keys = &curve->keys_rev; + + Glitter::Curve::Key key; + key.frame = 0; + key.value = glitter_editor_curve_editor_get_value(glt_edt, curve->type); + keys->push_back(key); + + crv_edt->frame = 0; + changed = true; + } + else { + std::vector::iterator i = keys->begin(); + bool is_before_start = keys->data()[0].frame > crv_edt->frame; + bool has_key_after = false; + if (!is_before_start) + for (i++; i != keys->end(); i++) + if (crv_edt->frame <= i->frame) { + has_key_after = keys->end() - i > 0; + break; + } + + ssize_t pos = i - keys->begin(); + if (!is_before_start) + pos--; + + if (!is_before_start && has_key_after) { + std::vector::iterator c = i - 1; + std::vector::iterator n = i; + + Glitter::Curve::Key key; + key.frame = crv_edt->frame; + 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_def(c->value, n->value, t); + key.random_range = lerp_def(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; + std::vector v_arr = interpolate_chs(c->value, n->value, c->tangent2, n->tangent1, 0, df); + key.value = v_arr[_df]; + key.random_range = lerp_def(c->random_range, n->random_range, (float_t)_df / (float_t)df); + interpolate_chs_reverse(v_arr.data(), v_arr.size(), c->tangent2, key.tangent1, 0, _df); + interpolate_chs_reverse(v_arr.data(), v_arr.size(), key.tangent2, n->tangent1, _df, df); + } break; + } + keys->insert(keys->begin() + ++pos, key); + } + else if (is_before_start) { + std::vector::iterator n = i; + + Glitter::Curve::Key key; + key.frame = crv_edt->frame; + key.type = n->type; + key.value = n->value; + key.random_range = n->random_range; + keys->insert(keys->begin() + pos, key); + } + else { + std::vector::iterator c = i - 1; + + Glitter::Curve::Key key; + key.frame = crv_edt->frame; + key.type = c->type; + key.value = c->value; + key.random_range = c->random_range; + keys->insert(keys->begin() + ++pos, key); + } + *crv_edt->list[crv_edt->type] = *curve; + changed = true; + } + } + else if (keys && crv_edt->del_key && del_key) { + for (std::vector::iterator i = keys->begin(); i != keys->end(); i++) + if (&i[0] == crv_edt->key) { + bool has_key_before = keys->front().frame < i->frame; + bool has_key_after = keys->back().frame > i->frame; + if (has_key_before && i[-1].type == Glitter::KEY_HERMITE && has_key_after) { + std::vector::iterator c = i - 1; + std::vector::iterator n = i + 1; + int32_t df_c = i->frame - c->frame; + int32_t df_n = n->frame - i->frame; + + std::vector v_arr_c = interpolate_chs(c->value, + i->value, c->tangent2, i->tangent1, 0, df_c); + + std::vector v_arr_n = i->type == Glitter::KEY_HERMITE + ? interpolate_chs(i->value, n->value, i->tangent2, n->tangent1, 0, df_n) + : interpolate_linear(i->value, n->value, 0, df_n); + + size_t v_length = v_arr_c.size() + v_arr_n.size() - 1; + float_t* v_arr = new float_t[v_length]; + memmove(v_arr, v_arr_c.data(), (v_arr_c.size() - 1) * sizeof(float_t)); + memmove(v_arr + (v_arr_c.size() - 1), v_arr_n.data(), v_arr_n.size() * sizeof(float_t)); + interpolate_chs_reverse(v_arr, v_length, c->tangent2, + n->tangent1, 0, (size_t)n->frame - c->frame); + delete[] v_arr; + } + keys->erase(i); + changed = true; + break; + } + } + else if (crv_edt->add_curve) { + Glitter::Curve* c = new Glitter::Curve(eg->type); + crv_edt->animation->curves.push_back(c); + crv_edt->list[crv_edt->type] = c; + curve = c; + + glitter_editor_curve_editor_curve_set(glt_edt, curve, crv_edt->type); + *crv_edt->list[crv_edt->type] = *curve; + crv_edt->frame = curve->start_time; + changed = true; + } + else if (crv_edt->del_curve) { + Glitter::Curve* c = crv_edt->list[crv_edt->type]; + Glitter::Animation* anim = crv_edt->animation; + for (std::vector::iterator i = anim->curves.begin(); i != anim->curves.end(); i++) + if (*i && *i == c) { + delete* i; + anim->curves.erase(i); + break; + } + + crv_edt->list[crv_edt->type] = 0; + crv_edt->frame = 0; + changed = true; + } + crv_edt->add_key = false; + crv_edt->del_key = false; + crv_edt->add_curve = false; + crv_edt->del_curve = false; + + if (!curve || !keys) + return; + + int32_t start_time = curve->start_time; + int32_t end_time = curve->end_time; + + ImGuiIO& io = ImGui::GetIO(); + ImGuiStyle& style = ImGui::GetStyle(); + ImFont* font = ImGui::GetFont(); + + ImVec2 cont_reg_avail = ImGui::GetContentRegionAvail(); + + ImVec2 canvas_size, canvas_pos, canvas_pos_min, canvas_pos_max; + crv_edt->draw_list = ImGui::GetWindowDrawList(); + canvas_size = cont_reg_avail; + canvas_pos = ImGui::GetCursorScreenPos(); + 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; + + 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 (crv_edt->zoom_time != crv_edt->prev_zoom_time) { + float_t timeline_pos = crv_edt->timeline_pos + curve_editor_timeline_base_pos; + timeline_pos *= crv_edt->zoom_time / crv_edt->prev_zoom_time; + crv_edt->timeline_pos = timeline_pos - curve_editor_timeline_base_pos; + } + crv_edt->prev_zoom_time = crv_edt->zoom_time; + + float_t frame_width = crv_edt->frame_width + * crv_edt->zoom_time; + canvas_pos.x -= crv_edt->timeline_pos; + + ImGui::ItemSize(boundaries); + bool hovered = ImGui::IsMouseHoveringRect(boundaries.Min, boundaries.Max); + ImGui::RenderFrame(boundaries.Min, boundaries.Max, ImGui::GetColorU32(ImGuiCol_FrameBg), true, 1.0f); + + static bool can_drag; + if (hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left, false)) + can_drag = true; + + if (can_drag && (ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT) || ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT))) { + crv_edt->key = glitter_editor_curve_editor_get_closest_key(glt_edt, curve); + crv_edt->frame = crv_edt->key->frame; + } + else + crv_edt->key = glitter_editor_curve_editor_get_selected_key(glt_edt, curve); + + if (can_drag && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) + can_drag = false; + + float_t timeline_max_offset = (end_time - start_time) * frame_width; + timeline_max_offset = max_def(timeline_max_offset, 0.0f) - curve_editor_timeline_base_pos; + + crv_edt->draw_list->PushClipRect(boundaries.Min, boundaries.Max, true); + + int32_t start = (int32_t)(crv_edt->timeline_pos / frame_width) + start_time; + int32_t end = (int32_t)((crv_edt->timeline_pos + canvas_size.x) / frame_width) + start_time; + + ImU32 line_color_valid_bold = ImGui::GetColorU32({ 0.5f, 0.5f, 0.5f, 0.75f }); + ImU32 line_color_valid = ImGui::GetColorU32({ 0.4f, 0.4f, 0.4f, 0.45f }); + ImU32 line_color_not_valid = ImGui::GetColorU32({ 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) || !f || 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; + crv_edt->draw_list->AddLine({ x, y - canvas_size.y }, + { x, y }, line_color, 0.80f); + + if (bold_frame) { + char buf[0x20]; + snprintf(buf, sizeof(buf), "%d", frame); + crv_edt->draw_list->AddText({ x + 3, canvas_pos.y }, line_color, buf); + } + } + + float_t max = crv_edt->range * (1.0f / crv_edt->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 + - crv_edt->height_offset) + crv_edt->height_offset; + + ImU32 line_color = j % 2 == 1 + ? ImGui::GetColorU32({ 0.35f, 0.35f, 0.35f, 0.45f }) + : ImGui::GetColorU32({ 0.45f, 0.45f, 0.45f, 0.75f }); + bool last = j == 4; + if (j && !last) + crv_edt->draw_list->AddLine({ x_pos, y_pos }, + { x_pos + canvas_size.x, y_pos }, line_color, 0.80f); + + float_t val = max - j * 0.25f * (max - min); + char buf[0x20]; + snprintf(buf, sizeof(buf), "%.2f", val); + crv_edt->draw_list->AddText({ x_pos + 2, y_pos + (last ? -16 : -2) }, + ImGui::GetColorU32({ 0.65f, 0.65f, 0.65f, 0.85f }), buf); + } + + 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(glt_edt, 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 + crv_edt->height_offset; + p2.x = p1.x + canvas_size.x; + p2.y = canvas_pos.y + crv_edt->height_offset; + p3.x = canvas_pos_min.x; + p3.y = canvas_pos.y; + crv_edt->draw_list->AddLine(p1, p2, + ImGui::GetColorU32({ 0.5f, 0.5f, 0.5f, 0.85f }), 2.0f); + + ImU32 random_range_color = ImGui::GetColorU32({ 0.5f, 0.5f, 0.0f, 0.25f }); + ImU32 key_random_range_color = ImGui::GetColorU32({ 0.5f, 0.0f, 0.5f, 0.25f }); + ImU32 default_color = ImGui::GetColorU32({ 1.0f, 1.0f, 1.0f, 0.75f }); + ImU32 selected_color = ImGui::GetColorU32({ 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_ft = eg->type == Glitter::FT; + for (std::vector::iterator i = keys->begin(); i != keys->end(); i++) { + if (i->frame >= end_time || keys->end() - i <= 1) + break; + + std::vector::iterator c = i; + std::vector::iterator 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_def(x1, canvas_pos_min.x); + x2 = min_def(x2, canvas_pos_max.x); + + Glitter::KeyType 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; + if (fix_rot_z) { + c_value -= (float_t)M_PI_2; + n_value -= (float_t)M_PI_2; + } + float_t c_random_range = c->random_range; + float_t n_random_range = n->random_range; + if (random_range_mult && glt_type_ft) { + 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) { + random *= value; + if (!glt_type_ft) + random *= 0.01f; + } + + if (value.x != value.y) { + float_t y1 = convert_value_to_height(glt_edt, value.x + random.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(glt_edt, value.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y3 = convert_value_to_height(glt_edt, value.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y4 = convert_value_to_height(glt_edt, value.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp_def(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp_def(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + crv_edt->draw_list->AddRectFilled({ x1, y1 }, + { x2, y2 }, random_range_color, 0.0f, 0); + + y3 = clamp_def(y3, canvas_pos_min.y, canvas_pos_max.y); + y4 = clamp_def(y4, canvas_pos_min.y, canvas_pos_max.y); + if (y3 != y4) + crv_edt->draw_list->AddRectFilled({ x1, y3 }, + { x2, y4 }, key_random_range_color, 0.0f, 0); + } + else { + float_t y1 = convert_value_to_height(glt_edt, value.y + random.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(glt_edt, value.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp_def(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp_def(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + crv_edt->draw_list->AddRectFilled({ x1, y1 }, + { x2, y2 }, random_range_color, 0.0f, 0); + } + + if (random_range_negate) + if (value.y != value.z) { + float_t y1 = convert_value_to_height(glt_edt, value.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(glt_edt, value.z, + canvas_pos.y, canvas_size.y, min, max); + float_t y3 = convert_value_to_height(glt_edt, value.z, + canvas_pos.y, canvas_size.y, min, max); + float_t y4 = convert_value_to_height(glt_edt, value.z - random.z, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp_def(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp_def(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + crv_edt->draw_list->AddRectFilled({ x1, y1 }, + { x2, y2 }, key_random_range_color, 0.0f, 0); + + y3 = clamp_def(y3, canvas_pos_min.y, canvas_pos_max.y); + y4 = clamp_def(y4, canvas_pos_min.y, canvas_pos_max.y); + if (y3 != y4) + crv_edt->draw_list->AddRectFilled({ x1, y3 }, + { x2, y4 }, random_range_color, 0.0f, 0); + } + else { + float_t y1 = convert_value_to_height(glt_edt, value.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(glt_edt, value.y - random.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp_def(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp_def(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + crv_edt->draw_list->AddRectFilled({ x1, y1 }, + { 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 = { c_value + c_random_range, c_value, c_value - c_random_range }; + vec3 n_value_vec = { n_value + n_random_range, n_value, n_value - n_random_range }; + vec3 random_vec = { random_range, random_range, 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) + value = interpolate_linear_value(c_value_vec, n_value_vec, + c_frame_vec, n_frame_vec, frame_vec); + else + value = interpolate_chs_value(c_value_vec, n_value_vec, + c_tangent2_vec, n_tangent1_vec, c_frame_vec, n_frame_vec, frame_vec); + + vec3 random; + if (random_range_mult) { + random_vec *= value; + if (!glt_type_ft) + random *= 0.01f; + } + else + random = random_vec; + + if (random_range_mult) { + vec3 random = { random_range, random_range, random_range }; + random *= value; + if (!glt_type_ft) + random *= 0.01f; + } + + 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(glt_edt, value.x + random.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(glt_edt, value.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y3 = convert_value_to_height(glt_edt, value.x, + canvas_pos.y, canvas_size.y, min, max); + float_t y4 = convert_value_to_height(glt_edt, value.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp_def(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp_def(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + crv_edt->draw_list->AddLine({ x, y1 }, + { x, y2 }, random_range_color, 0.0f); + + y3 = clamp_def(y3, canvas_pos_min.y, canvas_pos_max.y); + y4 = clamp_def(y4, canvas_pos_min.y, canvas_pos_max.y); + if (y3 != y4) + crv_edt->draw_list->AddLine({ x, y3 }, + { x, y4 }, key_random_range_color, 0.0f); + } + else { + float_t y1 = convert_value_to_height(glt_edt, value.y + random.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(glt_edt, value.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp_def(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp_def(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + crv_edt->draw_list->AddLine({ x, y1 }, + { x, y2 }, random_range_color, 0.0f); + } + + if (random_range_negate) + if (value.y != value.z) { + float_t y1 = convert_value_to_height(glt_edt, value.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(glt_edt, value.z, + canvas_pos.y, canvas_size.y, min, max); + float_t y3 = convert_value_to_height(glt_edt, value.z, + canvas_pos.y, canvas_size.y, min, max); + float_t y4 = convert_value_to_height(glt_edt, value.z - random.z, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp_def(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp_def(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + crv_edt->draw_list->AddLine({ x, y1 }, + { x, y2 }, key_random_range_color, 0.0f); + + y3 = clamp_def(y3, canvas_pos_min.y, canvas_pos_max.y); + y4 = clamp_def(y4, canvas_pos_min.y, canvas_pos_max.y); + if (y3 != y4) + crv_edt->draw_list->AddLine({ x, y3 }, + { x, y4 }, random_range_color, 0.0f); + } + else { + float_t y1 = convert_value_to_height(glt_edt, value.y, + canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(glt_edt, value.y - random.y, + canvas_pos.y, canvas_size.y, min, max); + + y1 = clamp_def(y1, canvas_pos_min.y, canvas_pos_max.y); + y2 = clamp_def(y2, canvas_pos_min.y, canvas_pos_max.y); + if (y1 != y2) + crv_edt->draw_list->AddLine({ x, y1 }, + { x, y2 }, random_range_color, 0.0f); + } + } + } + } + } + + for (std::vector::iterator i = keys->begin(); i != keys->end(); i++) { + if (i->frame >= end_time || keys->end() - i <= 1) + break; + + std::vector::iterator c = i; + std::vector::iterator 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 (fix_rot_z) { + c_value -= (float_t)M_PI_2; + n_value -= (float_t)M_PI_2; + } + + if (i->type != Glitter::KEY_HERMITE) { + float_t y1 = convert_value_to_height(glt_edt, c_value, canvas_pos.y, canvas_size.y, min, max); + float_t y2 = convert_value_to_height(glt_edt, n_value, canvas_pos.y, canvas_size.y, min, max); + + if (i->type == Glitter::KEY_CONSTANT) { + int32_t count = 0; + ImVec2 points_temp[3]; + if (x1 != x2) + points_temp[count++] = { x1, y1 }; + points_temp[count++] = { x2, y1 }; + if (y1 != y2) + points_temp[count++] = { x2, y2 }; + + if (count > 1) + crv_edt->draw_list->AddPolyline(points_temp, + count, default_color, 0, 3.0f); + } + else + crv_edt->draw_list->AddLine({ x1, y1 }, { 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(glt_edt, value, + canvas_pos.y, canvas_size.y, min, max); + points[(i - c->frame) * frame_width_int + j] = point; + } + crv_edt->draw_list->AddPolyline(points, + (int32_t)points_count, default_color, 0, 3.0f); + free_def(points); + } + } + + const ImU32 key_constant_color = ImGui::GetColorU32({ 1.0f, 0.0f, 0.0f, 0.75f }); + const ImU32 key_linear_color = ImGui::GetColorU32({ 0.0f, 1.0f, 0.0f, 0.75f }); + const ImU32 key_hermite_color = ImGui::GetColorU32({ 0.0f, 0.0f, 1.0f, 0.75f }); + + bool dragged = false; + bool holding_tan = false; + for (std::vector::iterator 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 base_value = i->value; + if (fix_rot_z) + base_value -= (float_t)M_PI_2; + float_t x = canvas_pos.x + ((size_t)i->frame - start_time) * frame_width; + float_t y = convert_value_to_height(glt_edt, base_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; + } + + ImGui::PushID(i._Ptr); + ImGui::SetCursorScreenPos({ x - 7.5f, y - 7.5f }); + ImGui::InvisibleButton("val", { 15.0f, 15.0f }, 0); + + if (can_drag && ImGui::IsItemActive() + && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1.0f)) { + float_t old_y = y; + + static int32_t base_frame; + static float_t base_y; + if ((ImGui::IsKeyPressed(GLFW_KEY_LEFT_SHIFT, false) && !ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT)) + || (ImGui::IsKeyPressed(GLFW_KEY_RIGHT_SHIFT, false) && !ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT))) { + base_frame = i->frame; + base_y = base_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; + crv_edt->frame = (int32_t)roundf((io.MousePos.x - canvas_pos.x) / frame_width); + crv_edt->frame = clamp_def(crv_edt->frame + start_time, start, end); + if (i->frame != crv_edt->frame) { + i->frame = crv_edt->frame; + changed = true; + } + } + + static float_t mouse_delta_history; + if ((ImGui::IsKeyPressed(GLFW_KEY_LEFT_SHIFT, false) && !ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT)) + || (ImGui::IsKeyPressed(GLFW_KEY_RIGHT_SHIFT, false) && !ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT))) + mouse_delta_history = io.MouseDelta.y; + else if ((ImGui::IsKeyReleased(GLFW_KEY_LEFT_SHIFT) && !ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT)) + || ImGui::IsKeyReleased(GLFW_KEY_RIGHT_SHIFT) && !ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT)) { + y += mouse_delta_history; + y += io.MouseDelta.y; + } + else if (ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT) || ImGui::IsKeyDown(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(glt_edt, + y, canvas_pos.y, canvas_size.y, min, max); + dragged = true; + + if (base_value != value) { + if (fix_rot_z) + value += (float_t)M_PI_2; + i->value = value; + changed = true; + } + crv_edt->key = &i[0]; + } + } + + 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(glt_edt, tangent1 = i->tangent1, + canvas_pos.y, canvas_size.y, min, max); + crv_edt->draw_list->AddLine({ 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)) { + ImGui::SetCursorScreenPos({ circle_pos.x - 7.5f, circle_pos.y - 7.5f }); + ImGui::InvisibleButton("tan1", { 15.0f, 15.0f }, 0); + + if (can_drag && ImGui::IsItemActive()) { + if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { + i->tangent1 = convert_height_to_value(glt_edt, + 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; + + crv_edt->draw_list->AddCircleFilled(circle_pos, + crv_edt->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(glt_edt, tangent2 = i->tangent2, + canvas_pos.y, canvas_size.y, min, max); + crv_edt->draw_list->AddLine({ 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)) { + ImGui::SetCursorScreenPos({ circle_pos.x - 7.5f, circle_pos.y - 7.5f }); + ImGui::InvisibleButton("tan2", { 15.0f, 15.0f }, 0); + + if (can_drag && ImGui::IsItemActive()) { + if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { + i->tangent2 = convert_height_to_value(glt_edt, + 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; + + crv_edt->draw_list->AddCircleFilled(circle_pos, + crv_edt->key_radius_in, tangent2_color, 12); + } + } + + crv_edt->draw_list->AddCircleFilled({ x, y }, + crv_edt->key_radius_out, crv_edt->key == &i[0] ? selected_color : default_color, 12); + crv_edt->draw_list->AddCircleFilled({ x, y }, + crv_edt->key_radius_in, value_color, 12); + ImGui::PopID(); + } + + if (!crv_edt->key_edit && can_drag && ImGui::IsMouseDown(ImGuiMouseButton_Left) && (!holding_tan || dragged)) { + int32_t frame = (int32_t)roundf((io.MousePos.x - canvas_pos.x) / frame_width); + crv_edt->frame = clamp_def(frame + start_time, start_time, end_time); + if (ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT) || ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT)) { + crv_edt->key = glitter_editor_curve_editor_get_closest_key(glt_edt, curve); + crv_edt->frame = crv_edt->key->frame; + } + else + crv_edt->key = glitter_editor_curve_editor_get_selected_key(glt_edt, curve); + } + crv_edt->frame = clamp_def(crv_edt->frame, start_time, end_time); + + int32_t cursor_frame = crv_edt->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 = ImGui::GetColorU32({ 0.8f, 0.8f, 0.8f, 0.75f }); + p1.x = cursor_pos.x; + p1.y = canvas_pos.y + canvas_size.y; + crv_edt->draw_list->AddLine(cursor_pos, p1, cursor_color, 2.5f); + + p1 = p2 = p3 = cursor_pos; + p1.x -= 10.0f; + p2.y += 10.0f; + p3.x += 10.0f; + crv_edt->draw_list->AddTriangleFilled(p1, p2, p3, cursor_color); + } + crv_edt->draw_list->PopClipRect(); + + if (hovered) + if (ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT) || ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT)) + crv_edt->timeline_pos -= io.MouseWheel * 25.0f * 4.0f; + else + crv_edt->timeline_pos -= io.MouseWheel * 25.0f; + + crv_edt->timeline_pos = clamp_def(crv_edt->timeline_pos, + -curve_editor_timeline_base_pos, timeline_max_offset); + + if (crv_edt->list[crv_edt->type] && changed) { + curve->Recalculate(eg->type); + *crv_edt->list[crv_edt->type] = *curve; + glt_edt->input_reload = true; + } +} + static bool glitter_editor_hash_input(GlitterEditor* glt_edt, const char* label, uint64_t* hash) { uint64_t h = *hash; if (glt_edt->effect_group->type == Glitter::FT) { diff --git a/src/ReDIVA/classes/graphics.cpp b/src/ReDIVA/classes/graphics.cpp index 60a47fac..920551eb 100644 --- a/src/ReDIVA/classes/graphics.cpp +++ b/src/ReDIVA/classes/graphics.cpp @@ -39,7 +39,7 @@ classes_data graphics_classes[] = { "Light##Graphics", CLASSES_IN_CONTEXT_MENU, graphics_light_init, - CLASSES_DATA_NO_FUNC, + graphics_light_ctrl, CLASSES_DATA_NO_FUNC, CLASSES_DATA_NO_FUNC, CLASSES_DATA_NO_FUNC, diff --git a/src/ReDIVA/classes/graphics/background_color.cpp b/src/ReDIVA/classes/graphics/background_color.cpp index 58ceee94..39620181 100644 --- a/src/ReDIVA/classes/graphics/background_color.cpp +++ b/src/ReDIVA/classes/graphics/background_color.cpp @@ -23,8 +23,8 @@ void graphics_background_color_imgui(class_data* data) { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 360.0f); - float_t h = min((float_t)height, 100.0f); + float_t w = min_def((float_t)width, 360.0f); + float_t h = min_def((float_t)height, 100.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always); @@ -53,10 +53,9 @@ void graphics_background_color_imgui(class_data* data) { ImGui::GetContentRegionAvailSetNextItemWidth(); vec4 _clear_color; vec4u8_to_vec4(clear_color, _clear_color); - vec4_mult_scalar(_clear_color, (float_t)(1.0 / 255.0), _clear_color); + _clear_color *= (float_t)(1.0 / 255.0); if (ImGui::ColorEdit4("##Background Color", (float_t*)&_clear_color, color_edit_flags)) { - vec4_clamp_scalar(_clear_color, 0.0f, 1.0f, _clear_color); - vec4_mult_scalar(_clear_color, 255.0f, _clear_color); + _clear_color = vec4::clamp(_clear_color, 0.0f, 1.0f) * 255.0f; vec4_to_vec4u8(_clear_color, clear_color); } ImGui::Checkbox("Set Clear Color", &set_clear_color); diff --git a/src/ReDIVA/classes/graphics/face_light.cpp b/src/ReDIVA/classes/graphics/face_light.cpp index dd932709..2092c202 100644 --- a/src/ReDIVA/classes/graphics/face_light.cpp +++ b/src/ReDIVA/classes/graphics/face_light.cpp @@ -24,8 +24,8 @@ void graphics_face_light_imgui(class_data* data) { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 200.0f); - float_t h = min((float_t)height, 84.0f); + float_t w = min_def((float_t)width, 200.0f); + float_t h = min_def((float_t)height, 84.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always); @@ -47,21 +47,22 @@ void graphics_face_light_imgui(class_data* data) { } render_context* rctx = (render_context*)data->data; - face* face = &rctx->face; + if (!rctx) { + ImGui::End(); + return; + } - ImGuiColorEditFlags color_edit_flags = 0; - color_edit_flags |= ImGuiColorEditFlags_NoLabel; - color_edit_flags |= ImGuiColorEditFlags_NoSidePreview; - color_edit_flags |= ImGuiColorEditFlags_NoDragDrop; + face* face = &rctx->face; w = ImGui::GetContentRegionAvailWidth(); if (ImGui::ButtonEnterKeyPressed("Reset", { w, 0.0f })) - light_param_data_storage_data_set_default_light_param(LIGHT_PARAM_DATA_STORAGE_FACE); + light_param_data_storage_data_set_stage( + light_param_data_storage_data_get_stage_index(), LIGHT_PARAM_DATA_STORAGE_FACE); ImGui::GetContentRegionAvailSetNextItemWidth(); float_t strength = face->get_offset(); if (ImGui::ColumnSliderFloatButton("Strength", - &strength, 0.25f, 0.0f, 10.0f, 1.0f, "%5.2f", color_edit_flags)) + &strength, 0.25f, 0.0f, 10.0f, 1.0f, "%5.2f", 0)) face->set_offset(strength); data->imgui_focus |= ImGui::IsWindowFocused(); @@ -69,5 +70,6 @@ void graphics_face_light_imgui(class_data* data) { } bool graphics_face_light_dispose(class_data* data) { + data->data = 0; return true; } diff --git a/src/ReDIVA/classes/graphics/fog.cpp b/src/ReDIVA/classes/graphics/fog.cpp index 7b0a6423..8549081f 100644 --- a/src/ReDIVA/classes/graphics/fog.cpp +++ b/src/ReDIVA/classes/graphics/fog.cpp @@ -4,10 +4,16 @@ */ #include "fog.hpp" -#include "../../../KKdLib/vec.hpp" -#include "../../../CRE/clear_color.hpp" #include "../../imgui_helper.hpp" +struct data_view_fog { + render_context* rctx; + int32_t group; + + data_view_fog(); + virtual ~data_view_fog(); +}; + extern int32_t width; extern int32_t height; @@ -15,7 +21,10 @@ static const char* graphics_fog_window_title = "Fog##Graphics"; bool graphics_fog_init(class_data* data, render_context* rctx) { graphics_fog_dispose(data); - data->data = rctx; + data_view_fog* fog = new data_view_fog; + if (fog) + fog->rctx = rctx; + data->data = fog; return true; } @@ -24,18 +33,15 @@ void graphics_fog_imgui(class_data* data) { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 200.0f); - float_t h = min((float_t)height, 84.0f); + float_t w = min_def((float_t)width, 300.0f); + float_t h = min_def((float_t)height, 344.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); - ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always); - - ImGuiWindowFlags window_flags = 0; - window_flags |= ImGuiWindowFlags_NoResize; + ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Appearing); data->imgui_focus = false; bool open = data->flags & CLASS_HIDDEN ? false : true; - bool collapsed = !ImGui::Begin(graphics_fog_window_title, &open, window_flags); + bool collapsed = !ImGui::Begin(graphics_fog_window_title, &open, 0); if (!open) { enum_or(data->flags, CLASS_HIDE); ImGui::End(); @@ -46,16 +52,75 @@ void graphics_fog_imgui(class_data* data) { return; } - render_context* rctx = (render_context*)data->data; - fog* fog = rctx->fog; + data_view_fog* fog = (data_view_fog*)data->data; + if (!fog) { + ImGui::End(); + return; + } - ImGuiColorEditFlags color_edit_flags = 0; - color_edit_flags |= ImGuiColorEditFlags_NoLabel; - color_edit_flags |= ImGuiColorEditFlags_NoSidePreview; - color_edit_flags |= ImGuiColorEditFlags_NoDragDrop; + render_context* rctx = fog->rctx; + ::fog* fog_data = &rctx->fog[fog->group]; if (ImGui::ButtonEnterKeyPressed("Reset")) - light_param_data_storage_data_set_default_light_param(LIGHT_PARAM_DATA_STORAGE_FOG); + light_param_data_storage_data_set_stage( + light_param_data_storage_data_get_stage_index(), LIGHT_PARAM_DATA_STORAGE_FOG); + + const char* fog_group_labels[] = { + "0: DEPTH", + "1: HEIGHT", + "2: BUMP", + }; + + ImGui::TextCentered("GROUP"); + ImGui::GetContentRegionAvailSetNextItemWidth(); + ImGui::ComboBox("##Group", fog_group_labels, 3, + &fog->group, 0, false, &data->imgui_focus); + + const char* fog_type_labels[] = { + "NONE", + "LINEAR", + "EXP", + "EXP2", + }; + + ImGui::TextCentered("TYPE"); + + fog_type type = fog_data->get_type(); + ImGui::GetContentRegionAvailSetNextItemWidth(); + ImGui::ComboBox("##Type", fog_type_labels, FOG_EXP2, + (int32_t*)&type, 0, true, &data->imgui_focus); + fog_data->set_type(type); + + ImGui::TextCentered("DENSITY"); + + float_t density = fog_data->get_density(); + ImGui::GetContentRegionAvailSetNextItemWidth(); + ImGui::SliderFloatButton("##Density", &density, 0.01f, 0.0f, 1.0f, 0.1f, "%.3f", 0); + fog_data->set_density(density); + + ImGui::TextCentered("LINEAR"); + + ImGui::PushID("Linear"); + float_t start = fog_data->get_start(); + ImGui::ColumnSliderFloatButton("START", &start, 0.1f, -100.0f, 1000.0f, 1.0f, "%.2f", 0); + fog_data->set_start(start); + + float_t end = fog_data->get_end(); + ImGui::ColumnSliderFloatButton("END", &end, 0.1f, -100.0f, 1000.0f, 1.0f, "%.2f", 0); + fog_data->set_end(end); + ImGui::PopID(); + + ImGui::TextCentered("COLOR"); + + ImGui::PushID("Color"); + vec4 color; + fog_data->get_color(color); + ImGui::GetContentRegionAvailSetNextItemWidth(); + ImGui::ColumnSliderFloatButton("R", &color.x, 0.01f, 0.0f, 8.0f, 0.1f, "%.2f", 0); + ImGui::ColumnSliderFloatButton("G", &color.y, 0.01f, 0.0f, 8.0f, 0.1f, "%.2f", 0); + ImGui::ColumnSliderFloatButton("B", &color.z, 0.01f, 0.0f, 8.0f, 0.1f, "%.2f", 0); + fog_data->set_color(color); + ImGui::PopID(); ImGui::GetContentRegionAvailSetNextItemWidth(); @@ -64,5 +129,17 @@ void graphics_fog_imgui(class_data* data) { } bool graphics_fog_dispose(class_data* data) { + data_view_fog* fog = (data_view_fog*)data->data; + if (fog) + delete fog; + data->data = 0; return true; } + +data_view_fog::data_view_fog() : rctx(), group() { + +} + +data_view_fog::~data_view_fog() { + +} diff --git a/src/ReDIVA/classes/graphics/glitter.cpp b/src/ReDIVA/classes/graphics/glitter.cpp index d564b283..33342163 100644 --- a/src/ReDIVA/classes/graphics/glitter.cpp +++ b/src/ReDIVA/classes/graphics/glitter.cpp @@ -20,8 +20,8 @@ bool graphics_glitter_init(class_data* data, render_context* rctx) { } void graphics_glitter_imgui(class_data* data) { - float_t w = min((float_t)width / 4.0f, 148.0f); - float_t h = min((float_t)height, 204.0f); + float_t w = min_def((float_t)width / 4.0f, 148.0f); + float_t h = min_def((float_t)height, 204.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Appearing); diff --git a/src/ReDIVA/classes/graphics/light.cpp b/src/ReDIVA/classes/graphics/light.cpp index 173459b4..814e6f95 100644 --- a/src/ReDIVA/classes/graphics/light.cpp +++ b/src/ReDIVA/classes/graphics/light.cpp @@ -4,10 +4,23 @@ */ #include "light.hpp" -#include "../../../KKdLib/vec.hpp" -#include "../../../CRE/clear_color.hpp" +#include "../../../CRE/stage.hpp" #include "../../imgui_helper.hpp" +struct data_view_light { + render_context* rctx; + light_id id; + bool sync_pos; + bool light_auth_enable; + int32_t stage_index; + int32_t stage_index_prev; + + data_view_light(); + virtual ~data_view_light(); + + static void column_slider_float_button(const char* label, float_t* val); +}; + extern int32_t width; extern int32_t height; @@ -15,27 +28,49 @@ static const char* graphics_light_window_title = "Light##Graphics"; bool graphics_light_init(class_data* data, render_context* rctx) { graphics_light_dispose(data); - data->data = rctx; + + data_view_light* light = new data_view_light; + if (light) { + light->rctx = rctx; + + int32_t stage_index = task_stage_get_current_stage_index(); + stage_index = max_def(stage_index, 0); + light->stage_index = stage_index; + light->stage_index_prev = stage_index; + } + data->data = light; return true; } +void graphics_light_ctrl(class_data* data) { + if (data->flags & (CLASS_HIDE | CLASS_HIDDEN)) + return; + + data_view_light* light = (data_view_light*)data->data; + if (!light) + return; + + if (light->stage_index != light->stage_index_prev + && !light_param_data_storage_data_load_file()) { + light->stage_index_prev = light->stage_index; + light_param_data_storage_data_set_stage(light->stage_index); + } +} + void graphics_light_imgui(class_data* data) { ImGuiIO& io = ImGui::GetIO(); ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 200.0f); - float_t h = min((float_t)height, 84.0f); + float_t w = min_def((float_t)width, 464.0f); + float_t h = min_def((float_t)height, 604.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); - ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always); - - ImGuiWindowFlags window_flags = 0; - window_flags |= ImGuiWindowFlags_NoResize; + ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Appearing); data->imgui_focus = false; bool open = data->flags & CLASS_HIDDEN ? false : true; - bool collapsed = !ImGui::Begin(graphics_light_window_title, &open, window_flags); + bool collapsed = !ImGui::Begin(graphics_light_window_title, &open, 0); if (!open) { enum_or(data->flags, CLASS_HIDE); ImGui::End(); @@ -46,23 +81,240 @@ void graphics_light_imgui(class_data* data) { return; } - render_context* rctx = (render_context*)data->data; + data_view_light* light = (data_view_light*)data->data; + if (!light) { + ImGui::End(); + return; + } + + render_context* rctx = light->rctx; + + data_struct* aft_data = &data_list[DATA_AFT]; + stage_database* aft_stage_data = &aft_data->data_ft.stage_data; + + std::vector& stg_data = aft_stage_data->stage_data; + light_set* light_set = rctx->light_set; - ImGuiColorEditFlags color_edit_flags = 0; - color_edit_flags |= ImGuiColorEditFlags_NoLabel; - color_edit_flags |= ImGuiColorEditFlags_NoSidePreview; - color_edit_flags |= ImGuiColorEditFlags_NoDragDrop; + int32_t stage_index = light_param_data_storage_data_get_stage_index(); - if (ImGui::ButtonEnterKeyPressed("Reset")) - light_param_data_storage_data_set_default_light_param(LIGHT_PARAM_DATA_STORAGE_LIGHT); + int32_t _stage_index = stage_index < 0 ? light->stage_index : stage_index; + + ImGui::TextCentered("STAGE (Light/Fog/PP)"); ImGui::GetContentRegionAvailSetNextItemWidth(); + if (ImGui::BeginCombo("##Stage Index", _stage_index > -1 + ? stg_data[_stage_index].name.c_str() : "", 0)) { + for (stage_data& i : stg_data) { + int32_t stage_idx = (int32_t)(&i - stg_data.data()); + + ImGui::PushID(&i); + if (ImGui::Selectable(i.name.c_str(), _stage_index == stage_idx) + || ImGui::ItemKeyPressed(GLFW_KEY_ENTER, true) + || (ImGui::IsItemFocused() && _stage_index != stage_idx)) { + stage_index = -1; + _stage_index = stage_idx; + } + ImGui::PopID(); + + if (_stage_index == stage_idx) + ImGui::SetItemDefaultFocus(); + } + + data->imgui_focus |= ImGui::IsWindowFocused(); + ImGui::EndCombo(); + } + + ::light_data* light_data = &light_set->lights[light->id]; + + const char* light_id_labels[] = { + "0:CHARA", + "1:STAGE", + "2:SUN", + "3:REFLECT", + "4:SHADOW", + "5:CHARA COLOR", + "6:CHARA(F)", + "7:PROJECTION", + }; + + ImGui::TextCentered("ID"); + + ImGui::GetContentRegionAvailSetNextItemWidth(); + ImGui::ComboBox("##ID", light_id_labels, LIGHT_MAX, + (int32_t*)&light->id, 0, false, &data->imgui_focus); + + const char* light_type_labels[] = { + "OFF", + "PARALLEL", + "POINT", + "SPOT", + }; + + ImGui::TextCentered("TYPE"); + + light_type type = light_data->get_type(); + ImGui::GetContentRegionAvailSetNextItemWidth(); + ImGui::ComboBox("##Type", light_type_labels, LIGHT_SPOT, + (int32_t*)&type, 0, true, &data->imgui_focus); + light_data->set_type(type); + + if (light->id == LIGHT_CHARA || light->id == LIGHT_TONE_CURVE) { + ::light_data* light_data = &light_set->lights[LIGHT_TONE_CURVE]; + + ImGui::TextCentered("CHARA(F) Tone Curve Adjustment"); + + ImGui::PushID("Tone Curve"); + light_tone_curve tone_curve; + light_data->get_tone_curve(tone_curve); + ImGui::ColumnSliderFloatButton("Start Point", &tone_curve.start_point, 0.01f, 0.0f, 1.0f, 0.1f, "%4.2f", 0); + ImGui::ColumnSliderFloatButton("End Point", &tone_curve.end_point, 0.01f, 0.0f, 1.0f, 0.1f, "%4.2f", 0); + ImGui::ColumnSliderFloatButton("Coefficient", &tone_curve.coefficient, 0.01f, 0.0f, 1.0f, 0.1f, "%4.2f", 0); + light_data->set_tone_curve(tone_curve); + ImGui::PopID(); + + ImGui::Checkbox("Light 0-6 Sync Position", &light->sync_pos); + ImGui::Checkbox("Light Auth Enable", &light->light_auth_enable); + } + + if (light_data->type != LIGHT_OFF) { + ImGui::TextCentered("AMBIENT"); + + ImGui::PushID("Ambient"); + vec4 ambient; + light_data->get_ambient(ambient); + ImGui::ColumnSliderFloatButton("R", &ambient.x, 0.01f, 0.0f, 2.0f, 0.1f, "%4.3f", 0); + ImGui::ColumnSliderFloatButton("G", &ambient.y, 0.01f, 0.0f, 2.0f, 0.1f, "%4.3f", 0); + ImGui::ColumnSliderFloatButton("B", &ambient.z, 0.01f, 0.0f, 2.0f, 0.1f, "%4.3f", 0); + light_data->set_ambient(ambient); + ImGui::PopID(); + + ImGui::TextCentered("DIFFUSE"); + + ImGui::PushID("Diffuse"); + vec4 diffuse; + light_data->get_diffuse(diffuse); + ImGui::ColumnSliderFloatButton("R", &diffuse.x, 0.01f, 0.0f, 2.0f, 0.1f, "%4.3f", 0); + ImGui::ColumnSliderFloatButton("G", &diffuse.y, 0.01f, 0.0f, 2.0f, 0.1f, "%4.3f", 0); + ImGui::ColumnSliderFloatButton("B", &diffuse.z, 0.01f, 0.0f, 2.0f, 0.1f, "%4.3f", 0); + light_data->set_diffuse(diffuse); + ImGui::PopID(); + + ImGui::TextCentered("SPECULAR"); + + ImGui::PushID("Specular"); + vec4 specular; + light_data->get_specular(specular); + ImGui::ColumnSliderFloatButton("R", &specular.x, 0.01f, 0.0f, 2.0f, 0.1f, "%4.3f", 0); + ImGui::ColumnSliderFloatButton("G", &specular.y, 0.01f, 0.0f, 2.0f, 0.1f, "%4.3f", 0); + ImGui::ColumnSliderFloatButton("B", &specular.z, 0.01f, 0.0f, 2.0f, 0.1f, "%4.3f", 0); + ImGui::ColumnSliderFloatButton("A", &specular.z, 0.02f, 0.0f, 4.0f, 0.2f, "%4.3f", 0); + light_data->set_specular(specular); + ImGui::PopID(); + + ImGui::TextCentered("POSITION"); + + ImGui::PushID("Position"); + vec3 position; + light_data->get_position(position); + + float_t rot_y; + if (fabsf(position.x) > 0.000001f || fabsf(position.y) > 0.000001f) + rot_y = atan2f(position.z, position.x) * RAD_TO_DEG_FLOAT; + else + rot_y = 0.0f; + + data_view_light::column_slider_float_button("X", &position.x); + data_view_light::column_slider_float_button("Y", &position.y); + data_view_light::column_slider_float_button("Z", &position.z); + if (ImGui::ColumnSliderFloatButton("ROTY", &rot_y, 0.01f, -180.0f, 180.0f, 0.1f, "%6.2f", 0)) { + vec2 pos = { position.x, position.z }; + float_t len = vec2::length(pos); + position.x = cosf(rot_y * DEG_TO_RAD_FLOAT) * len; + position.z = sinf(rot_y * DEG_TO_RAD_FLOAT) * len; + } + light_data->set_position(position); + ImGui::PopID(); + } + + if (light_data->type == LIGHT_SPOT) { + ImGui::TextCentered("SPOT DIRECTION"); + + ImGui::PushID("Spot Direction"); + vec3 spot_direction; + light_data->get_spot_direction(spot_direction); + ImGui::ColumnSliderFloatButton("X", &spot_direction.x, 0.02f, -1.0f, 1.0f, 0.1f, "%5.2f", 0); + ImGui::ColumnSliderFloatButton("Y", &spot_direction.y, 0.02f, -1.0f, 1.0f, 0.1f, "%5.2f", 0); + ImGui::ColumnSliderFloatButton("Z", &spot_direction.z, 0.02f, -1.0f, 1.0f, 0.1f, "%5.2f", 0); + light_data->set_spot_direction(spot_direction); + ImGui::PopID(); + + if (light->id == LIGHT_REFLECT) { + light_clip_plane clip_plane; + light_data->get_clip_plane(clip_plane); + ImGui::Checkbox("Reflective surface clip(STAGE)", &clip_plane.data[1]); + light_data->set_clip_plane(clip_plane); + } + + ImGui::TextCentered("SPOT EXPONENT"); + + float_t spot_exponent = light_data->get_spot_exponent(); + ImGui::ColumnSliderFloatButton("EXPONENT", &spot_exponent, 1.0f, 0.0f, 128.0f, 10.0f, "%8.4f", 0); + light_data->set_spot_exponent(spot_exponent); + + ImGui::TextCentered("SPOT CUTOFF"); + + float_t spot_cutoff = light_data->get_spot_cutoff(); + ImGui::ColumnSliderFloatButton("CUTOFF", &spot_cutoff, 0.0f, 0.0f, 90.0f, 5.0f, "%8.4f", 0); + light_data->set_spot_cutoff(spot_cutoff); + + ImGui::TextCentered("ATTENUATION"); + + ImGui::PushID("Attenuation"); + light_attenuation attenuation; + light_data->get_attenuation(attenuation); + ImGui::ColumnSliderFloatButton("CONSTANT", &attenuation.constant, 0.01f, 0.0f, 1.0f, 0.1f, "%8.4f", 0); + ImGui::ColumnSliderFloatButton("LINEAR", &attenuation.linear, 0.01f, 0.0f, 1.0f, 0.1f, "%8.4f", 0); + ImGui::ColumnSliderFloatButton("QUADRATIC", &attenuation.quadratic, 0.01f, 0.0f, 1.0f, 0.1f, "%8.4f", 0); + light_data->set_attenuation(attenuation); + } + + if (_stage_index != stage_index && _stage_index != light->stage_index) { + light_param_data_storage_data_load_stage(_stage_index); + light->stage_index = _stage_index; + } data->imgui_focus |= ImGui::IsWindowFocused(); ImGui::End(); } bool graphics_light_dispose(class_data* data) { + data_view_light* light = (data_view_light*)data->data; + if (light) + delete light; + data->data = 0; return true; } + +data_view_light::data_view_light() : rctx(), id(), sync_pos(), +light_auth_enable(), stage_index(), stage_index_prev() { + +} + +data_view_light::~data_view_light() { + +} + +void data_view_light::column_slider_float_button(const char* label, float_t* val) { + float_t val_abs = fabsf(*val); + float_t step; + if (val_abs < 150.0f) + step = 1.0; + else if (val_abs >= 1900.0) + step = 50.0f; + else + step = 10.0f; + + ImGui::ColumnSliderFloatButton(label, val, + step * 0.2f, 1.0f - step * 200.0f, step * 200.0f - 1.0f, step, "%6.2f", 0); +} diff --git a/src/ReDIVA/classes/graphics/light.hpp b/src/ReDIVA/classes/graphics/light.hpp index e37173ff..f9d9806e 100644 --- a/src/ReDIVA/classes/graphics/light.hpp +++ b/src/ReDIVA/classes/graphics/light.hpp @@ -9,5 +9,6 @@ #include "../../classes.hpp" extern bool graphics_light_init(class_data* data, render_context* rctx); +extern void graphics_light_ctrl(class_data* data); extern void graphics_light_imgui(class_data* data); extern bool graphics_light_dispose(class_data* data); diff --git a/src/ReDIVA/classes/graphics/post_process.cpp b/src/ReDIVA/classes/graphics/post_process.cpp index ecd33ab5..473852d1 100644 --- a/src/ReDIVA/classes/graphics/post_process.cpp +++ b/src/ReDIVA/classes/graphics/post_process.cpp @@ -24,8 +24,8 @@ void graphics_post_process_imgui(class_data* data) { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 400.0f); - float_t h = min((float_t)height, 790.0f); + float_t w = min_def((float_t)width, 400.0f); + float_t h = min_def((float_t)height, 790.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Appearing); @@ -44,6 +44,11 @@ void graphics_post_process_imgui(class_data* data) { } render_context* rctx = (render_context*)data->data; + if (!rctx) { + ImGui::End(); + return; + } + post_process* pp = &rctx->post_process; post_process_blur* blur = pp->blur; diff --git a/src/ReDIVA/classes/graphics/render_settings.cpp b/src/ReDIVA/classes/graphics/render_settings.cpp index aa55f23f..d127e20e 100644 --- a/src/ReDIVA/classes/graphics/render_settings.cpp +++ b/src/ReDIVA/classes/graphics/render_settings.cpp @@ -14,7 +14,6 @@ extern int32_t width; extern int32_t height; extern timer* render_timer; -extern timer* sound_timer; const char* graphics_render_settings_window_title = "Render Settings##Graphics"; @@ -41,7 +40,7 @@ void graphics_render_settings_imgui(class_data* data) { float_t w = 280.0f; #if defined(ReDIVA_DEV) - float_t h = 196.0f; + float_t h = 140.0f; #else float_t h = 86.0f; #endif @@ -77,37 +76,21 @@ void graphics_render_settings_imgui(class_data* data) { ImGui::Separator(); double_t render_freq = render_timer->get_freq(); - double_t sound_freq = sound_timer->get_freq(); double_t render_freq_hist = render_timer->get_freq_hist(); - double_t sound_freq_hist = sound_timer->get_freq_hist(); char render_freq_str[0x20]; - char sound_freq_str[0x20]; char render_ms_str[0x20]; - char sound_ms_str[0x20]; render_settings_freq_to_string(render_freq, render_freq_str, sizeof(render_freq_str), render_ms_str, sizeof(render_ms_str)); - render_settings_freq_to_string(sound_freq, sound_freq_str, - sizeof(sound_freq_str), sound_ms_str, sizeof(sound_ms_str)); char render_freq_hist_str[0x20]; - char sound_freq_hist_str[0x20]; char render_ms_hist_str[0x20]; - char sound_ms_hist_str[0x20]; render_settings_freq_to_string(render_freq_hist, render_freq_hist_str, sizeof(render_freq_hist_str), render_ms_hist_str, sizeof(render_ms_hist_str)); - render_settings_freq_to_string(sound_freq_hist, sound_freq_hist_str, - sizeof(sound_freq_hist_str), sound_ms_hist_str, sizeof(sound_ms_hist_str)); - ImGui::Text("Targ: Render / Sound"); - ImGui::Text("freq: %s / %s", render_freq_str, sound_freq_str); - ImGui::Text(" ms: %s / %s", render_ms_str, sound_ms_str); - - ImGui::Separator(); - - ImGui::Text("Curr: Render / Sound"); - ImGui::Text("freq: %s / %s", render_freq_hist_str, sound_freq_hist_str); - ImGui::Text(" ms: %s / %s", render_ms_hist_str, sound_ms_hist_str); + ImGui::Text("Render: Target / Current"); + ImGui::Text(" freq: %s / %s", render_freq_str, render_freq_hist_str); + ImGui::Text(" ms: %s / %s", render_ms_str, render_ms_hist_str); #endif ImGui::Separator(); diff --git a/src/ReDIVA/classes/information/frame_speed.cpp b/src/ReDIVA/classes/information/frame_speed.cpp index 007ac723..7113018e 100644 --- a/src/ReDIVA/classes/information/frame_speed.cpp +++ b/src/ReDIVA/classes/information/frame_speed.cpp @@ -22,8 +22,8 @@ void information_frame_speed_imgui(class_data* data) { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 240.0f); - float_t h = min((float_t)height, 58.0f); + float_t w = min_def((float_t)width, 240.0f); + float_t h = min_def((float_t)height, 58.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always); diff --git a/src/ReDIVA/data_initialize.cpp b/src/ReDIVA/data_initialize.cpp index e5e540c5..404d7afa 100644 --- a/src/ReDIVA/data_initialize.cpp +++ b/src/ReDIVA/data_initialize.cpp @@ -6,6 +6,7 @@ #include "data_initialize.hpp" #include "../CRE/data.hpp" #include "../CRE/object.hpp" +#include "../CRE/sound.hpp" #include "game_state.hpp" extern uint32_t dbg_set_id; @@ -89,14 +90,14 @@ bool TaskDataInit::Ctrl() { object_storage_load_set(aft_data, aft_obj_db, dbg_set_id); //bone_database_read(); //item_table_handler_array_read(); - //sub_14061F7E0("rom/sound/se.farc"); - //sub_14061F7E0("rom/sound/button.farc"); - //sub_14061F7E0("rom/sound/se_cmn.farc"); - //sub_14061F7E0("rom/sound/se_sel.farc"); - //sub_14061F7E0("rom/sound/se_aime.farc"); - //sub_14061F7E0("rom/sound/pvchange.farc"); - //sub_14061F7E0("rom/sound/slide_se.farc"); - //sub_14061F7E0("rom/sound/slide_long.farc"); + sound_work_read_farc("rom/sound/se.farc"); + sound_work_read_farc("rom/sound/button.farc"); + sound_work_read_farc("rom/sound/se_cmn.farc"); + sound_work_read_farc("rom/sound/se_sel.farc"); + sound_work_read_farc("rom/sound/se_aime.farc"); + sound_work_read_farc("rom/sound/pvchange.farc"); + sound_work_read_farc("rom/sound/slide_se.farc"); + sound_work_read_farc("rom/sound/slide_long.farc"); //sub_14037EF30(); //sub_14037F180(); //sub_140377A10(); @@ -124,14 +125,14 @@ bool TaskDataInit::Ctrl() { if (!object_storage_load_obj_set_check_not_read(dbg_set_id) //&& !bone_database_load() //&& !item_table_handler_array_load() - //&& !sub_140620E20("rom/sound/se.farc") - //&& !sub_140620E20("rom/sound/button.farc") - //&& !sub_140620E20("rom/sound/se_cmn.farc") - //&& !sub_140620E20("rom/sound/se_sel.farc") - //&& !sub_140620E20("rom/sound/se_aime.farc") - //&& !sub_140620E20("rom/sound/pvchange.farc") - //&& !sub_140620E20("rom/sound/slide_se.farc") - //&& !sub_140620E20("rom/sound/slide_long.farc") + && !sound_work_load_farc("rom/sound/se.farc") + && !sound_work_load_farc("rom/sound/button.farc") + && !sound_work_load_farc("rom/sound/se_cmn.farc") + && !sound_work_load_farc("rom/sound/se_sel.farc") + && !sound_work_load_farc("rom/sound/se_aime.farc") + && !sound_work_load_farc("rom/sound/pvchange.farc") + && !sound_work_load_farc("rom/sound/slide_se.farc") + && !sound_work_load_farc("rom/sound/slide_long.farc") //&& !sub_14037FE80() //&& !sub_1403785C0() //&& !sub_1403933B0() diff --git a/src/ReDIVA/data_test/auth_3d_test.cpp b/src/ReDIVA/data_test/auth_3d_test.cpp index 9588affd..c9794d26 100644 --- a/src/ReDIVA/data_test/auth_3d_test.cpp +++ b/src/ReDIVA/data_test/auth_3d_test.cpp @@ -137,8 +137,8 @@ void Auth3dTestWindow::Window() { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 280.0f); - float_t h = min((float_t)height, 324.0f); + float_t w = min_def((float_t)width, 280.0f); + float_t h = min_def((float_t)height, 324.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always); @@ -312,8 +312,8 @@ void Auth3dTestWindow::Window() { float_t x = w; float_t y = 0.0f; - w = min((float_t)width, 200.0f); - h = min((float_t)height, 124.0f); + w = min_def((float_t)width, 200.0f); + h = min_def((float_t)height, 124.0f); ImGui::SetNextWindowPos({ x, y }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always); diff --git a/src/ReDIVA/data_test/glitter_test.cpp b/src/ReDIVA/data_test/glitter_test.cpp index be038fad..98c24197 100644 --- a/src/ReDIVA/data_test/glitter_test.cpp +++ b/src/ReDIVA/data_test/glitter_test.cpp @@ -41,8 +41,12 @@ bool TaskDataTestGlitterParticle::Init() { for (std::vector::iterator i = files.begin(); i != files.end();) if (str_utils_check_ends_with(i->name.c_str(), ".farc")) { char* temp = str_utils_get_without_extension(i->name.c_str()); - i->name = temp ? std::string(temp) : std::string(); - free(temp); + if (temp) { + i->name.assign(temp); + free(temp); + } + else + i->name.clear(); i++; } else @@ -196,8 +200,8 @@ void TaskDataTestGlitterParticle::Window() { window_focus |= ImGui::IsWindowFocused(); ImGui::End(); - float_t win_x = min((float_t)width, 240.0f); - float_t win_y = min((float_t)height, 96.0f); + float_t win_x = min_def((float_t)width, 240.0f); + float_t win_y = min_def((float_t)height, 96.0f); float_t x = 0.0f; float_t y = (float_t)height - win_y; diff --git a/src/ReDIVA/data_test/stage_test.cpp b/src/ReDIVA/data_test/stage_test.cpp index 5e98834d..1ae47900 100644 --- a/src/ReDIVA/data_test/stage_test.cpp +++ b/src/ReDIVA/data_test/stage_test.cpp @@ -166,8 +166,8 @@ void DtwStg::Window() { ImGuiStyle& style = ImGui::GetStyle(); ImFont* font = ImGui::GetFont(); - float_t w = min((float_t)width, 240.0f); - float_t h = min((float_t)height, 240.0f); + float_t w = min_def((float_t)width, 240.0f); + float_t h = min_def((float_t)height, 240.0f); ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always); @@ -180,7 +180,7 @@ void DtwStg::Window() { ImGui::End(); return; } - + data_struct* aft_data = &data_list[DATA_AFT]; stage_database* aft_stage_data = &aft_data->data_ft.stage_data; diff --git a/src/ReDIVA/game_state.cpp b/src/ReDIVA/game_state.cpp index 639c108f..95f9ee8d 100644 --- a/src/ReDIVA/game_state.cpp +++ b/src/ReDIVA/game_state.cpp @@ -770,8 +770,7 @@ bool SubGameState::Selector::Init() { bool SubGameState::Selector::Ctrl() { if (x_pv_game_selector.exit) { - if (x_pv_game_selector.start) { - x_pv_game_init(); + if (x_pv_game_selector.start && x_pv_game_init()) { XPVGameSelector& sel = x_pv_game_selector; app::TaskWork::AppendTask(x_pv_game_ptr, "X PVGAME", 0); x_pv_game_ptr->Load(sel.pv_id, sel.stage_id, sel.charas, sel.modules); @@ -800,8 +799,7 @@ bool SubGameState::GameMain::Ctrl() { } bool SubGameState::GameMain::Dest() { - x_pv_game_free(); - return true; + return x_pv_game_free(); } bool SubGameState::GameSel::Init() { diff --git a/src/ReDIVA/imgui_helper.cpp b/src/ReDIVA/imgui_helper.cpp index 64ec3107..c449599c 100644 --- a/src/ReDIVA/imgui_helper.cpp +++ b/src/ReDIVA/imgui_helper.cpp @@ -65,7 +65,8 @@ namespace ImGui { TableNextColumn(); GetContentRegionAvailSetNextItemWidth(); Text(label_temp); - free(label_temp); + if (label_temp) + free(label_temp); TableNextColumn(); GetContentRegionAvailSetNextItemWidth(); @@ -316,7 +317,8 @@ namespace ImGui { DisableElementPush(enable); Text(label_temp); DisableElementPop(enable); - free(label_temp); + if (label_temp) + free(label_temp); TableNextColumn(); GetContentRegionAvailSetNextItemWidth(); @@ -693,7 +695,7 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); + v[0] = clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -711,8 +713,8 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -730,9 +732,9 @@ namespace ImGui { 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[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -750,10 +752,10 @@ namespace ImGui { 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); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); + v[3] = clamp_def(v[3], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) return false; @@ -771,7 +773,7 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); + v[0] = clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -789,8 +791,8 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -808,9 +810,9 @@ namespace ImGui { 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[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -828,10 +830,10 @@ namespace ImGui { 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); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); + v[3] = clamp_def(v[3], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) return false; @@ -861,7 +863,7 @@ namespace ImGui { v[0] = roundf(v[0] / step) * step; - v[0] = clamp(v[0], min, max); + v[0] = clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -884,8 +886,8 @@ namespace ImGui { v[0] = roundf(v[0] / step) * step; v[1] = roundf(v[1] / step) * step; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -909,9 +911,9 @@ namespace ImGui { v[1] = roundf(v[1] / step) * step; v[2] = roundf(v[2] / step) * step; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); - v[2] = clamp(v[2], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -936,10 +938,10 @@ namespace ImGui { v[2] = roundf(v[2] / step) * step; v[3] = roundf(v[3] / step) * step; - 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); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); + v[3] = clamp_def(v[3], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) return false; @@ -959,7 +961,7 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); + v[0] = clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -979,8 +981,8 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -1000,9 +1002,9 @@ namespace ImGui { 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[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -1022,17 +1024,17 @@ namespace ImGui { 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); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); + v[3] = clamp_def(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 ColumnSliderFloatButton(const char* label, float_t* val, float_t button_step, float_t min, float_t max, float_t step, const char* format, ImGuiSliderFlags flags) { float_t v[1]; @@ -1045,9 +1047,9 @@ namespace ImGui { if (!res) return false; - v[0] = roundf(v[0] / step) * step; + v[0] = roundf(v[0] / button_step) * button_step; - v[0] = clamp(v[0], min, max); + v[0] = clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -1075,11 +1077,11 @@ namespace ImGui { if (!res) return false; - v[0] = roundf(v[0] / step) * step; - v[1] = roundf(v[1] / step) * step; + v[0] = roundf(v[0] / button_step) * button_step; + v[1] = roundf(v[1] / button_step) * button_step; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -1110,13 +1112,13 @@ namespace ImGui { if (!res) return false; - v[0] = roundf(v[0] / step) * step; - v[1] = roundf(v[1] / step) * step; - v[2] = roundf(v[2] / step) * step; + v[0] = roundf(v[0] / button_step) * button_step; + v[1] = roundf(v[1] / button_step) * button_step; + v[2] = roundf(v[2] / button_step) * button_step; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); - v[2] = clamp(v[2], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -1150,15 +1152,15 @@ namespace ImGui { if (!res) return false; - v[0] = roundf(v[0] / step) * step; - v[1] = roundf(v[1] / step) * step; - v[2] = roundf(v[2] / step) * step; - v[3] = roundf(v[3] / step) * step; + v[0] = roundf(v[0] / button_step) * button_step; + v[1] = roundf(v[1] / button_step) * button_step; + v[2] = roundf(v[2] / button_step) * button_step; + v[3] = roundf(v[3] / button_step) * button_step; - 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); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); + v[3] = clamp_def(v[3], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) return false; @@ -1178,7 +1180,7 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); + v[0] = clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -1206,8 +1208,8 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -1238,9 +1240,9 @@ namespace ImGui { 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[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -1274,10 +1276,10 @@ namespace ImGui { 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); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); + v[3] = clamp_def(v[3], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) return false; @@ -1310,7 +1312,7 @@ namespace ImGui { if (!res) return false; - v[0] = 1 << clamp(v[0], min, max); + v[0] = 1 << clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -1347,8 +1349,8 @@ namespace ImGui { if (!res) return false; - v[0] = 1 << clamp(v[0], min, max); - v[1] = 1 << clamp(v[1], min, max); + v[0] = 1 << clamp_def(v[0], min, max); + v[1] = 1 << clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -1389,9 +1391,9 @@ namespace ImGui { if (!res) return false; - v[0] = 1 << clamp(v[0], min, max); - v[1] = 1 << clamp(v[1], min, max); - v[2] = 1 << clamp(v[2], min, max); + v[0] = 1 << clamp_def(v[0], min, max); + v[1] = 1 << clamp_def(v[1], min, max); + v[2] = 1 << clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -1436,10 +1438,10 @@ namespace ImGui { if (!res) return false; - v[0] = 1 << clamp(v[0], min, max); - v[1] = 1 << clamp(v[1], min, max); - v[2] = 1 << clamp(v[2], min, max); - v[3] = 1 << clamp(v[3], min, max); + v[0] = 1 << clamp_def(v[0], min, max); + v[1] = 1 << clamp_def(v[1], min, max); + v[2] = 1 << clamp_def(v[2], min, max); + v[3] = 1 << clamp_def(v[3], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) return false; @@ -1470,7 +1472,7 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); + v[0] = clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -1495,8 +1497,8 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -1523,9 +1525,9 @@ namespace ImGui { 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[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -1554,10 +1556,10 @@ namespace ImGui { 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); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); + v[3] = clamp_def(v[3], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) return false; @@ -1580,7 +1582,7 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); + v[0] = clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -1605,8 +1607,8 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -1633,9 +1635,9 @@ namespace ImGui { 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[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -1664,10 +1666,10 @@ namespace ImGui { 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); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); + v[3] = clamp_def(v[3], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) return false; @@ -1690,7 +1692,7 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); + v[0] = clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -1715,8 +1717,8 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -1743,9 +1745,9 @@ namespace ImGui { 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[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -1774,10 +1776,10 @@ namespace ImGui { 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); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); + v[3] = clamp_def(v[3], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) return false; @@ -1800,7 +1802,7 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); + v[0] = clamp_def(v[0], min, max); if (v[0] == *val) return false; @@ -1825,8 +1827,8 @@ namespace ImGui { if (!res) return false; - v[0] = clamp(v[0], min, max); - v[1] = clamp(v[1], min, max); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); if (v[0] == val->x && v[1] == val->y) return false; @@ -1853,9 +1855,9 @@ namespace ImGui { 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[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z) return false; @@ -1884,10 +1886,10 @@ namespace ImGui { 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); + v[0] = clamp_def(v[0], min, max); + v[1] = clamp_def(v[1], min, max); + v[2] = clamp_def(v[2], min, max); + v[3] = clamp_def(v[3], min, max); if (v[0] == val->x && v[1] == val->y && v[2] == val->z && v[3] == val->w) return false; @@ -1895,10 +1897,36 @@ namespace ImGui { return true; } + void TextCentered(const char* fmt, ...) { + ImGuiContext& g = *GImGui; + + va_list args; + va_start(args, fmt); + vsprintf_s(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); + va_end(args); + + std::string tex_buf(g.TempBuffer.Data, g.TempBuffer.Size); + ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::CalcTextSize(tex_buf.c_str()).x) * 0.5f); + ImGui::Text(tex_buf.c_str()); + } + + void TextRight(const char* fmt, ...) { + ImGuiContext& g = *GImGui; + + va_list args; + va_start(args, fmt); + vsprintf_s(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); + va_end(args); + + std::string tex_buf(g.TempBuffer.Data, g.TempBuffer.Size); + ImGui::SetCursorPosX(ImGui::GetWindowWidth() - ImGui::CalcTextSize(tex_buf.c_str()).x); + ImGui::Text(tex_buf.c_str()); + } + // Taken from ImGui src // FIXME: Try to move more of the code into shared SliderBehavior() template - bool SliderBehaviorTA(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, + bool SliderBehaviorStepT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const TYPE v_step, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) { ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; @@ -1932,8 +1960,26 @@ namespace ImGui { zero_deadzone_halfsize = (style.LogSliderDeadzone * 0.5f) / ImMax(slider_usable_sz, 1.0f); } + if (slider_sz < 1.0f) + *out_grab_bb = ImRect(bb.Min, bb.Min); + else { + // Output grab position so it can be displayed by the caller + float_t grab_t = ScaleRatioFromValueT(data_type, + *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + if (axis == ImGuiAxis_Y) + grab_t = 1.0f - grab_t; + const float_t grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); + if (axis == ImGuiAxis_X) + *out_grab_bb = ImRect(grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding, + grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding); + else + *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f, + bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f); + } + // Process interacting with the slider bool value_changed = false; + bool continuos_value_change = false; if (g.ActiveId == id) { bool set_new_value = false; float_t clicked_t = 0.0f; @@ -1960,7 +2006,15 @@ namespace ImGui { - slider_usable_pos_min) / slider_usable_sz); if (axis == ImGuiAxis_Y) clicked_t = 1.0f - clicked_t; - set_new_value = IsMouseClicked(ImGuiMouseButton_Left, true); + + float_t diff1 = g.IO.MousePosPrev[axis] - out_grab_bb->Min[axis]; + float_t diff2 = out_grab_bb->Max[axis] - g.IO.MousePosPrev[axis]; + if (diff1 >= -grab_sz && diff2 >= -grab_sz) { + set_new_value = true; + continuos_value_change = true; + } + else + set_new_value = IsMouseClicked(ImGuiMouseButton_Left, true); } } else if (g.ActiveIdSource == ImGuiInputSource_Nav) { @@ -2038,7 +2092,11 @@ namespace ImGui { v_new = RoundScalarWithFormatT(format, data_type, v_new); // Apply result - if (v_new - *v >= v_step) { + if (continuos_value_change) { + *v = v_new; + value_changed = true; + } + else if (v_new - *v >= v_step) { *v += v_step; value_changed = true; } @@ -2053,23 +2111,6 @@ namespace ImGui { } } - if (slider_sz < 1.0f) - *out_grab_bb = ImRect(bb.Min, bb.Min); - else { - // Output grab position so it can be displayed by the caller - float_t grab_t = ScaleRatioFromValueT(data_type, - *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); - if (axis == ImGuiAxis_Y) - grab_t = 1.0f - grab_t; - const float_t grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); - if (axis == ImGuiAxis_X) - *out_grab_bb = ImRect(grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding, - grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding); - else - *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f, - bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f); - } - return value_changed; } @@ -2093,7 +2134,7 @@ namespace ImGui { const int8_t min = *(const int8_t*)p_min; const int8_t max = *(const int8_t*)p_max; const int8_t step = *(const int8_t*)p_step; - bool r = SliderBehaviorTA(bb, id, ImGuiDataType_S32, + bool r = SliderBehaviorStepT(bb, id, ImGuiDataType_S32, &v32, min, max, step, format, flags, out_grab_bb); if (r) *(int8_t*)p_v = (int8_t)v32; @@ -2104,7 +2145,7 @@ namespace ImGui { const uint8_t min = *(const uint8_t*)p_min; const uint8_t max = *(const uint8_t*)p_max; const uint8_t step = *(const uint8_t*)p_step; - bool r = SliderBehaviorTA(bb, id, ImGuiDataType_U32, + bool r = SliderBehaviorStepT(bb, id, ImGuiDataType_U32, &v32, min, max, step, format, flags, out_grab_bb); if (r) *(uint8_t*)p_v = (uint8_t)v32; @@ -2115,7 +2156,7 @@ namespace ImGui { const int16_t min = *(const int16_t*)p_min; const int16_t max = *(const int16_t*)p_max; const int16_t step = *(const int16_t*)p_step; - bool r = SliderBehaviorTA(bb, id, ImGuiDataType_S32, + bool r = SliderBehaviorStepT(bb, id, ImGuiDataType_S32, &v32, min, max, step, format, flags, out_grab_bb); if (r) *(int16_t*)p_v = (int16_t)v32; @@ -2126,7 +2167,7 @@ namespace ImGui { const uint16_t min = *(const uint16_t*)p_min; const uint16_t max = *(const uint16_t*)p_max; const uint16_t step = *(const uint16_t*)p_step; - bool r = SliderBehaviorTA(bb, id, ImGuiDataType_U32, + bool r = SliderBehaviorStepT(bb, id, ImGuiDataType_U32, &v32, min, max, step, format, flags, out_grab_bb); if (r) *(uint16_t*)p_v = (uint16_t)v32; @@ -2137,7 +2178,7 @@ namespace ImGui { const int32_t max = *(const int32_t*)p_max; const int32_t step = *(const int32_t*)p_step; IM_ASSERT(min >= INT32_MIN / 2 && max <= INT32_MAX / 2); - return SliderBehaviorTA(bb, id, data_type, + return SliderBehaviorStepT(bb, id, data_type, (int32_t*)p_v, min, max, step, format, flags, out_grab_bb); } case ImGuiDataType_U32: { @@ -2145,7 +2186,7 @@ namespace ImGui { const uint32_t max = *(const uint32_t*)p_max; const uint32_t step = *(const uint32_t*)p_step; IM_ASSERT(max <= UINT32_MAX / 2); - return SliderBehaviorTA(bb, id, data_type, + return SliderBehaviorStepT(bb, id, data_type, (uint32_t*)p_v, min, max, step, format, flags, out_grab_bb); } case ImGuiDataType_S64: { @@ -2153,7 +2194,7 @@ namespace ImGui { const int64_t max = *(const int64_t*)p_max; const int64_t step = *(const int64_t*)p_step; IM_ASSERT(min >= INT64_MIN / 2 && max <= INT64_MAX / 2); - return SliderBehaviorTA(bb, id, data_type, + return SliderBehaviorStepT(bb, id, data_type, (int64_t*)p_v, min, max, step, format, flags, out_grab_bb); } case ImGuiDataType_U64: { @@ -2161,7 +2202,7 @@ namespace ImGui { const uint64_t max = *(const uint64_t*)p_max; const uint64_t step = *(const uint64_t*)p_step; IM_ASSERT(max <= UINT64_MAX / 2); - return SliderBehaviorTA(bb, id, data_type, + return SliderBehaviorStepT(bb, id, data_type, (uint64_t*)p_v, min, max, step, format, flags, out_grab_bb); } case ImGuiDataType_Float: { @@ -2169,7 +2210,7 @@ namespace ImGui { const float_t max = *(const float_t*)p_max; const float_t step = *(const float_t*)p_step; IM_ASSERT(min >= -FLT_MAX / 2.0f && max <= FLT_MAX / 2.0f); - return SliderBehaviorTA(bb, id, data_type, + return SliderBehaviorStepT(bb, id, data_type, (float_t*)p_v, min, max, step, format, flags, out_grab_bb); } case ImGuiDataType_Double: { @@ -2177,7 +2218,7 @@ namespace ImGui { const double_t max = *(const double_t*)p_max; const double_t step = *(const double_t*)p_step; IM_ASSERT(min >= -DBL_MAX / 2.0f && max <= DBL_MAX / 2.0f); - return SliderBehaviorTA(bb, id, data_type, + return SliderBehaviorStepT(bb, id, data_type, (double_t*)p_v, min, max, step, format, flags, out_grab_bb); } case ImGuiDataType_COUNT: break; diff --git a/src/ReDIVA/imgui_helper.hpp b/src/ReDIVA/imgui_helper.hpp index 127c8ffe..7d383fa3 100644 --- a/src/ReDIVA/imgui_helper.hpp +++ b/src/ReDIVA/imgui_helper.hpp @@ -88,9 +88,11 @@ namespace ImGui { extern bool ButtonEnterKeyPressed(const char* label, const ImVec2& size = ImVec2(0, 0)); extern bool ButtonExEnterKeyPressed(const char* label, const ImVec2& size = ImVec2(0, 0), ImGuiButtonFlags flags = 0); + extern bool CheckboxEnterKeyPressed(const char* label, bool* v); extern bool CheckboxFlagsEnterKeyPressed(const char* label, int* flags, int flags_value); extern bool CheckboxFlagsEnterKeyPressed(const char* label, unsigned int* flags, unsigned int flags_value); + extern bool ComboBox(const char* label, const char** items, const size_t size, int32_t* selected_idx, ImGuiComboFlags flags, bool include_last, bool* focus); extern bool ComboBox(const char* label, const char** items, const size_t size, @@ -103,8 +105,10 @@ namespace ImGui { int32_t* selected_idx, ImGuiComboFlags flags, bool include_last, bool* focus); extern bool ComboBoxConfigFile(const char* label, void* items, const size_t size, size_t* selected_idx, ImGuiComboFlags flags, bool include_last, bool* focus); + extern bool ColumnColorEdit3(const char* label, vec3* val, ImGuiColorEditFlags flags); extern bool ColumnColorEdit4(const char* label, vec4* val, ImGuiColorEditFlags flags); + extern bool ColumnComboBox(const char* label, const char** items, const size_t size, int32_t* selected_idx, ImGuiComboFlags flags, bool include_last, bool* focus); extern bool ColumnComboBox(const char* label, const char** items, const size_t size, @@ -117,6 +121,7 @@ namespace ImGui { int32_t* selected_idx, ImGuiComboFlags flags, bool include_last, bool* focus); extern bool ColumnComboBoxConfigFile(const char* label, void* items, const size_t size, size_t* selected_idx, ImGuiComboFlags flags, bool include_last, bool* focus); + extern bool ColumnDragFloat(const char* label, float_t* val, float_t speed, float_t min, float_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnDragVec2(const char* label, vec2* val, float_t speed, @@ -125,6 +130,7 @@ namespace ImGui { float_t min, float_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnDragVec4(const char* label, vec4* val, float_t speed, float_t min, float_t max, const char* format, ImGuiSliderFlags flags); + extern bool ColumnDragInt(const char* label, int32_t* val, float_t speed, int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnDragVec2I(const char* label, vec2i* val, float_t speed, @@ -133,8 +139,10 @@ namespace ImGui { int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnDragVec4I(const char* label, vec4i* val, float_t speed, int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); + extern bool ColumnInputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data); + extern bool ColumnSliderFloat(const char* label, float_t* val, float_t step, float_t min, float_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnSliderVec2(const char* label, vec2* val, float_t step, @@ -143,6 +151,7 @@ namespace ImGui { float_t min, float_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnSliderVec4(const char* label, vec4* val, float_t step, float_t min, float_t max, const char* format, ImGuiSliderFlags flags); + extern bool ColumnSliderInt(const char* label, int32_t* val, int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnSliderVec2I(const char* label, vec2i* val, @@ -151,6 +160,7 @@ namespace ImGui { int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnSliderVec4I(const char* label, vec4i* val, int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); + extern bool ColumnSliderFloatButton(const char* label, float_t* val, float_t button_step, float_t min, float_t max, float_t step, const char* format, ImGuiSliderFlags flags); extern bool ColumnSliderVec2Button(const char* label, vec2* val, float_t button_step, @@ -159,6 +169,7 @@ namespace ImGui { float_t min, float_t max, float_t step, const char* format, ImGuiSliderFlags flags); extern bool ColumnSliderVec4Button(const char* label, vec4* val, float_t button_step, float_t min, float_t max, float_t step, const char* format, ImGuiSliderFlags flags); + extern bool ColumnSliderIntButton(const char* label, int32_t* val, int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnSliderVec2IButton(const char* label, vec2i* val, @@ -167,6 +178,7 @@ namespace ImGui { int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnSliderVec4IButton(const char* label, vec4i* val, int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); + extern bool ColumnSliderLogInt(const char* label, int32_t* val, int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnSliderLogVec2I(const char* label, vec2i* val, @@ -175,8 +187,10 @@ namespace ImGui { int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); extern bool ColumnSliderLogVec4I(const char* label, vec4i* val, int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags); + extern bool ColumnInputScalar(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 ColumnDragFloat(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 ColumnDragVec2(const char* label, vec2* val, float_t speed, @@ -185,6 +199,7 @@ namespace ImGui { float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); extern bool ColumnDragVec4(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 ColumnDragInt(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 ColumnDragVec2I(const char* label, vec2i* val, float_t speed, @@ -193,6 +208,7 @@ namespace ImGui { int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); extern bool ColumnDragVec4I(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 ColumnSliderFloat(const char* label, float_t* val, float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); extern bool ColumnSliderVec2(const char* label, vec2* val, @@ -201,6 +217,7 @@ namespace ImGui { float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); extern bool ColumnSliderVec4(const char* label, vec4* val, float_t min, float_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); + extern bool ColumnSliderInt(const char* label, int32_t* val, int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); extern bool ColumnSliderVec2I(const char* label, vec2i* val, @@ -209,4 +226,7 @@ namespace ImGui { int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); extern bool ColumnSliderVec4I(const char* label, vec4i* val, int32_t min, int32_t max, const char* format, ImGuiSliderFlags flags, int32_t bit_flag); -} \ No newline at end of file + + extern void TextCentered(const char* fmt, ...); + extern void TextRight(const char* fmt, ...); +} diff --git a/src/ReDIVA/main.cpp b/src/ReDIVA/main.cpp index 201c3c87..61772219 100644 --- a/src/ReDIVA/main.cpp +++ b/src/ReDIVA/main.cpp @@ -3,6 +3,9 @@ GitHub/GitLab: korenkonder */ +#include "../KKdLib/database/sprite.hpp" +#include "../KKdLib/io/file_stream.hpp" +#include "../KKdLib/io/memory_stream.hpp" #include "../KKdLib/f2/struct.hpp" #include "../KKdLib/a3da.hpp" #include "../KKdLib/dsc.hpp" @@ -86,8 +89,7 @@ static bool a3da_to_dof_data(const char* a3da_path, dft_dsc_data& data) { continue; } - float_t focus; - vec3_distance(cam_a3da.dof.model_transform.translation_value, cr->view_point_value, focus); + float_t focus = vec3::distance(cam_a3da.dof.model_transform.translation_value, cr->view_point_value); dof_data d; d.flags = 0x1F; @@ -118,7 +120,7 @@ static void a3da_to_dft_dsc(int32_t pv_id) { char buf[0x100]; sprintf_s(buf, sizeof(buf), "DOF\\script\\pv_%03d_hard.dsc", pv_id); - stream s_src_dsc; + file_stream s_src_dsc; s_src_dsc.open(buf, "rb"); size_t src_dsc_length = s_src_dsc.get_length(); @@ -128,7 +130,8 @@ static void a3da_to_dft_dsc(int32_t pv_id) { dsc d_src = dsc(); d_src.parse(src_dsc_data, src_dsc_length, DSC_FT); - free(src_dsc_data); + if (src_dsc_data) + free(src_dsc_data); d_src.rebuild(); dsc_get_func_id src_get_func_id = dsc_type_get_dsc_get_func_id(d_src.type); @@ -253,15 +256,17 @@ static void a3da_to_dft_dsc(int32_t pv_id) { d.unparse(&dsc_data, &dsc_length); sprintf_s(buf, sizeof(buf), "DOF\\pv_script\\pv_%03d_dof.dsc", pv_id); - stream s_dsc; + file_stream s_dsc; s_dsc.open(buf, "wb"); s_dsc.write(dsc_data, dsc_length); s_dsc.close(); - free(dsc_data); + if (dsc_data) + free(dsc_data); - stream s_dft; + memory_stream s_dft; s_dft.open(); + uint32_t off; enrs e; enrs_entry ee; @@ -304,11 +309,6 @@ static void a3da_to_dft_dsc(int32_t pv_id) { bool close; -struct thread { - HANDLE handle; - DWORD id; -}; - int32_t wmain(int32_t argc, wchar_t** argv) { //ShowWindow(GetConsoleWindow(), SW_HIDE); timeBeginPeriod(1); @@ -323,26 +323,8 @@ int32_t wmain(int32_t argc, wchar_t** argv) { render_init_struct ris; - thread render, sound; - HANDLE h[2]; - h[0] = render.handle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)render_main, &ris, 0, &render.id); - h[1] = sound.handle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sound_main, 0, 0, &sound.id); + render_main(&ris); - if (render.handle) - SetThreadDescription(render.handle, L"Render Thread"); - if (sound.handle) - SetThreadDescription(sound.handle, L"Sound Thread"); - - lock_init(&state_lock); - state = RENDER_UNINITIALIZED; - if (render.handle && sound.handle) - WaitForMultipleObjects(2, h, true, INFINITE); - lock_free(&state_lock); - - if (render.handle) - CloseHandle(render.handle); - if (sound.handle) - CloseHandle(sound.handle); timeEndPeriod(1); return 0; } diff --git a/src/ReDIVA/main.hpp b/src/ReDIVA/main.hpp index e8543c47..5bbfe06e 100644 --- a/src/ReDIVA/main.hpp +++ b/src/ReDIVA/main.hpp @@ -8,4 +8,3 @@ #include "../KKdLib/default.hpp" #include "input.hpp" #include "render.hpp" -#include "sound.hpp" diff --git a/src/ReDIVA/pv_game.cpp b/src/ReDIVA/pv_game.cpp index e888e393..2a398df8 100644 --- a/src/ReDIVA/pv_game.cpp +++ b/src/ReDIVA/pv_game.cpp @@ -11,6 +11,7 @@ #include "../CRE/Glitter/glitter.hpp" #include "../CRE/light_param/light.hpp" #include "../CRE/light_param.hpp" +#include "../CRE/rob/rob.hpp" #include "../CRE/data.hpp" #include "../CRE/object.hpp" #include "../CRE/pv_param.hpp" @@ -135,10 +136,6 @@ TaskPvGame task_pv_game; extern render_context* rctx_ptr; static float_t dsc_time_to_frame(int64_t time); -static int32_t expression_id_to_mottbl_index(int32_t expression_id); -static int32_t hand_anim_id_to_mottbl_index(int32_t hand_anim_id); -static int32_t look_anim_id_to_mottbl_index(int32_t look_anim_id); -static int32_t mouth_anim_id_to_mottbl_index(int32_t mouth_anim_id); static void pv_game_change_field(pv_game_old* pvgm, int32_t field, int64_t dsc_time, int64_t curr_time); static bool pv_game_dsc_process(pv_game_old* pvgm, int64_t curr_time); static void pv_game_reset_field(pv_game_old* pvgm); @@ -969,67 +966,6 @@ static float_t dsc_time_to_frame(int64_t time) { return (float_t)time / 1000000000.0f * 60.0f; } -static int32_t expression_id_to_mottbl_index(int32_t expression_id) { - static const int32_t expression_id_to_mottbl_index_table[] = { - 11, 15, 57, 19, 23, 25, 29, 33, - 37, 41, 45, 49, 53, 65, 7, 69, - 73, 77, 81, 85, 89, 7, 61, 6, - 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, 93, 95, 97, 99, 101, 103, - 105, 107, 109, 111, 113, 115, 117, 119, - 121, 123, 125, 127, 13, 21, 31, 39, - 43, 47, 51, 55, 67, 71, 79, 83, - 129, 59, 17, 91, 27, 87, 35, 75, - 9, 63, 236, 238, 240, 242, - }; - - if (expression_id >= 0 && expression_id - < sizeof(expression_id_to_mottbl_index_table) / sizeof(int32_t)) - return expression_id_to_mottbl_index_table[expression_id]; - return 6; -} - -static int32_t hand_anim_id_to_mottbl_index(int32_t hand_anim_id) { - static const int32_t hand_anim_id_to_mottbl_index_table[] = { - 195, 196, 194, 197, 201, 198, 199, 202, - 203, 192, 200, 204, 204, 204, 193, - }; - - if (hand_anim_id >= 0 && hand_anim_id - < sizeof(hand_anim_id_to_mottbl_index_table) / sizeof(int32_t)) - return hand_anim_id_to_mottbl_index_table[hand_anim_id]; - return 192; -} - -static int32_t look_anim_id_to_mottbl_index(int32_t look_anim_id) { - static const int32_t look_anim_id_to_mottbl_index_table[] = { - 168, 170, 174, 172, 178, 176, 182, 180, - 166, 165, 224, 169, 171, 175, 173, 179, - 177, 183, 181, 167, - }; - - if (look_anim_id >= 0 && look_anim_id - < sizeof(look_anim_id_to_mottbl_index_table) / sizeof(int32_t)) - return look_anim_id_to_mottbl_index_table[look_anim_id]; - return 165; -} - -static int32_t mouth_anim_id_to_mottbl_index(int32_t mouth_anim_id) { - static const int32_t mouth_anim_id_to_mottbl_index_table[] = { - 134, 140, 142, 146, 144, 148, 150, 152, - 132, 131, 136, 138, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 151, - 135, 143, 147, 145, 133, 137, 139, 141, - 149, 153, 244, 245, 246, 247, 248, 249, - 250, 251, 252, - }; - - if (mouth_anim_id >= 0 && mouth_anim_id - < sizeof(mouth_anim_id_to_mottbl_index_table) / sizeof(int32_t)) - return mouth_anim_id_to_mottbl_index_table[mouth_anim_id]; - return 131; -} - static void sub_140122B60(pv_game_old* a1, int32_t chara_id, int32_t motion_index, int64_t disp_time) { if (chara_id < 0 || chara_id > ROB_CHARA_COUNT || motion_index < 0) return; @@ -1764,7 +1700,7 @@ static bool pv_game_dsc_process(pv_game_old* a1, int64_t curr_time) { if (!rob_chr) break; - rob_chr->item_equip->wet = clamp(value, 0.0f, 1.0f); + rob_chr->item_equip->wet = clamp_def(value, 0.0f, 1.0f); } break; case DSC_FT_LIGHT_ROT: { diff --git a/src/ReDIVA/render.cpp b/src/ReDIVA/render.cpp index 6d58bf6e..03931a25 100644 --- a/src/ReDIVA/render.cpp +++ b/src/ReDIVA/render.cpp @@ -26,7 +26,9 @@ #include "../CRE/lock.hpp" #include "../CRE/mdata_manager.hpp" #include "../CRE/object.hpp" +#include "../CRE/ogg_vorbis.hpp" #include "../CRE/pv_db.hpp" +#include "../CRE/random.hpp" #include "../CRE/shader.hpp" #include "../CRE/shader_ft.hpp" #include "../CRE/shader_glsl.hpp" @@ -150,11 +152,11 @@ static void APIENTRY render_debug_output(GLenum source, GLenum type, uint32_t id extern bool close; bool reload_render; -lock render_lock; +lock* render_lock; HWND window_handle; GLFWwindow* window; ImGuiContext* imgui_context; -lock imgui_context_lock; +lock* imgui_context_lock; bool global_context_menu; extern size_t frame_counter; render_context* rctx_ptr; @@ -164,32 +166,21 @@ render_init_struct::render_init_struct() : scale_index() { } -int32_t render_main(void* arg) { +int32_t render_main(render_init_struct* ris) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); timeBeginPeriod(1); + + render_lock = new lock; + if (!render_lock) + return 0; + render_timer = new timer(60.0); - state = RENDER_UNINITIALIZED; - - lock_init(&render_lock); - if (!lock_check_init(&render_lock)) { - delete render_timer; - return 0; - } - - render_init_struct* ris = (render_init_struct*)arg; window_handle = 0; #pragma region GLFW Init - glfwInit(); - 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); - glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE); -#if defined(DEBUG) && OPENGL_DEBUG - glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true); -#endif + if (!glfwInit()) + return -1; GLFWmonitor* monitor = glfwGetPrimaryMonitor(); const GLFWvidmode* mode = glfwGetVideoMode(monitor); @@ -204,6 +195,16 @@ int32_t render_main(void* arg) { height = 1080; #endif + 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); + glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE); + //glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); +#if defined(DEBUG) && OPENGL_DEBUG + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true); +#endif + glfwWindowHint(GLFW_RED_BITS, mode->redBits); glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); @@ -233,19 +234,21 @@ int32_t render_main(void* arg) { window = glfwCreateWindow(width, height, glfw_titlelabel, maximized ? monitor : 0, 0); if (!window) { glfwTerminate(); - return -1; + return -2; } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { glfwTerminate(); - return -2; + return -3; } + glGetError(); glViewport(0, 0, width, height); window_handle = glfwGetWin32Window(window); + glfwShowWindow(window); glfwFocusWindow(window); glfwSetDropCallback(window, (GLFWdropfun)render_drop_glfw); glfwSetWindowSizeCallback(window, (GLFWwindowsizefun)render_resize_fb_glfw); @@ -284,11 +287,6 @@ int32_t render_main(void* arg) { glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &sv_max_texture_max_anisotropy); glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); - lock_lock(&state_lock); - state = RENDER_INITIALIZING; - enum_or(thread_flags, THREAD_RENDER); - lock_unlock(&state_lock); - #if DRAW_PASS_TIME_DISP for (std::vector& i : draw_pass_cpu_time) i.resize(240, 0.0f); @@ -302,21 +300,24 @@ int32_t render_main(void* arg) { reload_render = false; render_context* rctx = 0; - lock_lock(&render_lock); + lock_lock(render_lock); rctx = render_load(); - lock_unlock(&render_lock); + lock_unlock(render_lock); + + data_struct* aft_data = &data_list[DATA_AFT]; + + //OggFileHandler ofh; + //aft_data->load_file(&ofh, "rom/sound/bgm/", + // "selector_verB_a_lp.ogg", OggFileHandler::LoadFile); - lock_lock(&state_lock); frame_counter = 0; - state = RENDER_INITIALIZED; - lock_unlock(&state_lock); #pragma region GL Init #if !(BAKE_PNG || BAKE_VIDEO) glfwGetFramebufferSize(window, &width, &height); #endif glViewport(0, 0, width, height); - glfwSwapInterval(0); + glfwSwapInterval(1); gl_state_disable_blend(); gl_state_disable_depth_test(); @@ -324,7 +325,6 @@ int32_t render_main(void* arg) { gl_state_disable_cull_face(); gl_state_disable_stencil_test(); #pragma endregion - render_timer->reset(); while (!close && !reload_render) { render_timer->start_of_cycle(); @@ -332,41 +332,25 @@ int32_t render_main(void* arg) { ImGui_ImplGlfw_NewFrame(); ImGui_ImplOpenGL3_NewFrame(); ImGui::NewFrame(); - lock_lock(&render_lock); + Input::NewFrame(); + lock_lock(render_lock); render_ctrl(rctx); - lock_unlock(&render_lock); + lock_unlock(render_lock); render_disp(rctx); - glfwSwapBuffers(window); close |= !!glfwWindowShouldClose(window); frame_counter++; Input::EndFrame(); render_timer->end_of_cycle(); + glfwSwapBuffers(window); } - lock_lock(&state_lock); - state = RENDER_DISPOSING; - lock_unlock(&state_lock); + //ofh.~OggFileHandler(); - bool threads_wait = false; - render_timer->reset(); - do { - render_timer->start_of_cycle(); - lock_lock(&state_lock); - threads_wait = thread_flags & ~THREAD_RENDER; - lock_unlock(&state_lock); - render_timer->end_of_cycle(); - } while (threads_wait); - - lock_lock(&render_lock); + lock_lock(render_lock); render_dispose(rctx); - lock_unlock(&render_lock); + lock_unlock(render_lock); } while (reload_render); - lock_lock(&state_lock); - state = RENDER_DISPOSED; - enum_and(thread_flags, ~THREAD_RENDER); - lock_unlock(&state_lock); - #if DRAW_PASS_TIME_DISP for (std::vector& i : draw_pass_cpu_time) { i.clear(); @@ -383,8 +367,10 @@ int32_t render_main(void* arg) { glfwDestroyWindow(window); glfwTerminate(); #pragma endregion - lock_free(&render_lock); + delete render_lock; + render_lock = 0; delete render_timer; + render_timer = 0; return 0; } @@ -437,8 +423,11 @@ static render_context* render_load() { } render_shaders_load(); + sound_init(); + wave_audio_storage_init(); object_storage_init(aft_obj_db); item_table_array_init(); + rand_state_array_init(); app::task_work_init(); @@ -475,7 +464,7 @@ static render_context* render_load() { sprintf_s(buf, sizeof(buf), i == 815 ? "EFFPV%03d" : "ITMPV%03d", i); object_set_info* effpv_set_info; - if (aft_obj_db->get_object_set_info(buf, &effpv_set_info)){ + if (aft_obj_db->get_object_set_info(buf, &effpv_set_info)) { obj_set_ids.push_back(effpv_set_info->id); obj_set_id_name.insert({ effpv_set_info->id, buf }); } @@ -491,7 +480,7 @@ static render_context* render_load() { sprintf_s(buf, sizeof(buf), "STGPV%03dHRC", i); object_set_info* stgpvhrc_set_info; - if (aft_obj_db->get_object_set_info(buf, &stgpvhrc_set_info)){ + if (aft_obj_db->get_object_set_info(buf, &stgpvhrc_set_info)) { obj_set_ids.push_back(stgpvhrc_set_info->id); obj_set_id_name.insert({ stgpvhrc_set_info->id, buf }); } @@ -780,13 +769,15 @@ static render_context* render_load() { " vec2 uv;\n" "} frg;\n" "\n" - "uniform float dark_border_end;\n" - "uniform float dark_border_start;\n" + "uniform float border_end;\n" + "uniform float border_start;\n" + "uniform vec3 border_color;" + "uniform vec3 center_color;" "\n" "void main() {\n" - " float blend = step(dark_border_end, frg.uv.x) * (1.0 - step(dark_border_start, frg.uv.x))" - " * step(dark_border_end, frg.uv.y) * (1.0 - step(dark_border_start, frg.uv.y));\n" - " result = vec4(blend, blend, blend, 1.0);\n" + " float blend = step(border_end, frg.uv.x) * (1.0 - step(border_start, frg.uv.x))" + " * step(border_end, frg.uv.y) * (1.0 - step(border_start, frg.uv.y));\n" + " result = vec4(mix(border_color, center_color, blend), 1.0);\n" "}\n"; const char* grid_vert_shader = @@ -895,12 +886,13 @@ static render_context* render_load() { render_timer->reset(); for (int32_t i = 0; i < 30; i++) { render_timer->start_of_cycle(); - lock_lock(&render_lock); + lock_lock(render_lock); game_state_ctrl(); app::TaskWork::Ctrl(); + sound_ctrl(); file_handler_storage_ctrl(); app::TaskWork::Basic(); - lock_unlock(&render_lock); + lock_unlock(render_lock); render_timer->end_of_cycle(); } @@ -965,7 +957,8 @@ static render_context* render_load() { camera* cam = rctx->camera; - cam->initialize(aspect, internal_3d_res.x, internal_3d_res.y); + cam->initialize(aspect, internal_3d_res.x, internal_3d_res.y, + internal_2d_res.x, internal_2d_res.y); //cam->set_position(cam, { 1.35542f, 1.41634f, 1.27852f }); //cam->rotate(cam, { -45.0, -32.5 }); //cam->set_position(cam, { -6.67555f, 4.68882f, -3.67537f }); @@ -977,14 +970,14 @@ static render_context* render_load() { cam->set_interest({ 0.0f, 1.375f, 0.0f }); imgui_context = ImGui::CreateContext(); - lock_init(&imgui_context_lock); + imgui_context_lock = new lock; - lock_lock(&imgui_context_lock); + lock_lock(imgui_context_lock); ImGui::SetCurrentContext(imgui_context); ImGuiIO& io = ImGui::GetIO(); io.IniFilename = 0; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - lock_unlock(&imgui_context_lock); + lock_unlock(imgui_context_lock); ImGui::StyleColorsDark(0); ImGui_ImplGlfw_InitForOpenGL(window, true); @@ -1037,15 +1030,15 @@ static void render_ctrl(render_context* rctx) { } global_context_menu = true; - lock_lock(&imgui_context_lock); + lock_lock(imgui_context_lock); ImGui::SetCurrentContext(imgui_context); app::TaskWork_Window(); classes_process_imgui(classes, classes_count); +#if DRAW_PASS_TIME_DISP ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Appearing); ImGui::SetNextWindowSize({ 1280, 636 }, ImGuiCond_Appearing); -#if DRAW_PASS_TIME_DISP if (ImGui::Begin("CPU/GPU Time")) { static const char* draw_pass_names[] = { "Shadow", @@ -1083,7 +1076,7 @@ static void render_ctrl(render_context* rctx) { size_t cpu_time_count = draw_pass_cpu_time[i].size(); if (cpu_time_count) cpu_avg /= (double_t)cpu_time_count; - + for (float_t& j : draw_pass_gpu_time[i]) { if (gpu_min > j) gpu_min = j; @@ -1107,17 +1100,18 @@ static void render_ctrl(render_context* rctx) { } #endif - lock_unlock(&imgui_context_lock); + lock_unlock(imgui_context_lock); if (old_width != width || old_height != height || old_scale_index != scale_index) { render_resize_fb(rctx, true); - cam->set_res(internal_3d_res.x, internal_3d_res.y); + cam->set_res(internal_3d_res.x, internal_3d_res.y, + internal_2d_res.x, internal_2d_res.y); } old_width = width; old_height = height; old_scale_index = scale_index; - lock_lock(&imgui_context_lock); + lock_lock(imgui_context_lock); ImGui::SetCurrentContext(imgui_context); if (global_context_menu && ImGui::IsMouseReleased(ImGuiMouseButton_Right) && !ImGui::IsItemHovered(0) && imgui_context->OpenPopupStack.Size < 1) @@ -1127,7 +1121,7 @@ static void render_ctrl(render_context* rctx) { render_imgui_context_menu(classes, classes_count, rctx); ImGui::EndPopup(); } - lock_unlock(&imgui_context_lock); + lock_unlock(imgui_context_lock); if (window_handle == GetForegroundWindow()) { if (input_reset) { @@ -1212,9 +1206,7 @@ static void cube_line_disp(shader_glsl* shader, camera* cam, vec3* trans, float_ mat4_get_translation(&mat[1], &t[1]); vec3 d; - vec2_sub(*(vec2*)&t[1], *(vec2*)&t[0], *(vec2*)&d); - vec2_normalize(*(vec2*)&d, *(vec2*)&d); - vec2_mult_scalar(*(vec2*)&d, line_size, *(vec2*)&d); + *(vec2*)&d = vec2::normalize(*(vec2*)&t[1] - *(vec2*)&t[0]) * line_size; d.z = 0.0f; vec3 norm[2]; @@ -1224,10 +1216,10 @@ static void cube_line_disp(shader_glsl* shader, camera* cam, vec3* trans, float_ mat4_mult_vec3(&cam->inv_view_rot, &norm[1], &norm[1]); vec3 vert_trans[4]; - vec3_add(trans[0], norm[0], vert_trans[0]); - vec3_add(trans[0], norm[1], vert_trans[1]); - vec3_add(trans[1], norm[0], vert_trans[2]); - vec3_add(trans[1], norm[1], vert_trans[3]); + vert_trans[0] = trans[0] + norm[0]; + vert_trans[1] = trans[0] + norm[1]; + vert_trans[2] = trans[1] + norm[0]; + vert_trans[3] = trans[1] + norm[1]; shader->set("color", *color); @@ -1241,6 +1233,7 @@ static int cube_line_points_sort(void const* src1, void const* src2) { return d1 > d2 ? -1 : (d1 < d2 ? 1 : 0); } +static bool auth_3d_disp = false; static bool rob_disp = false; static void render_disp(render_context* rctx) { @@ -1276,13 +1269,6 @@ static void render_disp(render_context* rctx) { glClearBufferfv(GL_DEPTH, 0, &depth_clear); gl_state_set_depth_mask(GL_FALSE); - if (set_clear_color) { - vec4 _clear_color; - vec4u8_to_vec4(clear_color, _clear_color); - vec4_mult_scalar(_clear_color, (float_t)(1.0 / 255.0), _clear_color); - glClearBufferfv(GL_COLOR, 0, (GLfloat*)&_clear_color); - } - cam->update(); rctx->disp(); @@ -1300,89 +1286,201 @@ static void render_disp(render_context* rctx) { vec4 exp_color = { 0.0f, 1.0f, 0.0f, 1.0f }; vec4 osg_color = { 0.0f, 0.0f, 1.0f, 1.0f }; vec4 osg_node_color = { 1.0f, 0.0f, 1.0f, 1.0f }; - for (int32_t i = 0; i < ROB_CHARA_COUNT && rob_disp; i++) { - if (rob_chara_pv_data_array[i].type == ROB_CHARA_TYPE_NONE) - continue; - - rob_chara* rob_chr = &rob_chara_array[i]; - if (~rob_chr->data.field_0 & 1) - continue; - - gl_state_bind_vertex_array(cube_line_vao); - gl_state_bind_array_buffer(cube_line_vbo); - rob_chara_bone_data* rob_bone_data = rob_chr->bone_data; - size_t object_bone_count = rob_bone_data->object_bone_count; - size_t total_bone_count = rob_bone_data->total_bone_count; - size_t ik_bone_count = rob_bone_data->ik_bone_count; - cube_line_shader->use(); - for (bone_node& j : rob_bone_data->nodes) { - if (!j.parent) + if (rob_disp) + for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) { + if (rob_chara_pv_data_array[i].type == ROB_CHARA_TYPE_NONE) continue; - vec3 trans[2]; - mat4_get_translation(j.parent->mat, &trans[0]); - mat4_get_translation(j.mat, &trans[1]); + rob_chara* rob_chr = &rob_chara_array[i]; + if (~rob_chr->data.field_0 & 1) + continue; - if (memcmp(&trans[0], &trans[1], sizeof(vec3))) - cube_line_disp(cube_line_shader, cam, trans, CUBE_LINE_SIZE, &bone_color); - } - gl_state_bind_array_buffer(0); + gl_state_bind_vertex_array(cube_line_vao); + gl_state_bind_array_buffer(cube_line_vbo); + rob_chara_bone_data* rob_bone_data = rob_chr->bone_data; + size_t object_bone_count = rob_bone_data->object_bone_count; + size_t total_bone_count = rob_bone_data->total_bone_count; + size_t ik_bone_count = rob_bone_data->ik_bone_count; + cube_line_shader->use(); + for (bone_node& j : rob_bone_data->nodes) { + if (!j.parent) + continue; - std::vector> cube_line_points; - for (bone_node& j : rob_bone_data->nodes) { - vec3 trans; - mat4_get_translation(j.mat, &trans); - cube_line_points.push_back({ trans, 0.0f }); + vec3 trans[2]; + mat4_get_translation(j.parent->mat, &trans[0]); + mat4_get_translation(j.mat, &trans[1]); + + if (memcmp(&trans[0], &trans[1], sizeof(vec3))) + cube_line_disp(cube_line_shader, cam, trans, CUBE_LINE_SIZE, &bone_color); + } + gl_state_bind_array_buffer(0); + + std::vector> cube_line_points; + for (bone_node& j : rob_bone_data->nodes) { + vec3 trans; + vec3 vp_trans; + mat4_get_translation(j.mat, &trans); + mat4_mult_vec3(&cam->view_projection, &trans, &vp_trans); + cube_line_points.push_back({ trans, vp_trans.z }); + } + + quicksort_custom(cube_line_points.data(), cube_line_points.size(), + sizeof(std::pair), cube_line_points_sort); + + gl_state_bind_array_buffer(cube_line_point_instance_vbo); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(sizeof(std::pair) + * cube_line_points.size()), cube_line_points.data(), GL_STREAM_DRAW); + gl_state_bind_array_buffer(0); + + vec3 trans[4]; + trans[0] = { -CUBE_LINE_POINT_SIZE, CUBE_LINE_POINT_SIZE, 0.0f }; + trans[1] = { CUBE_LINE_POINT_SIZE, CUBE_LINE_POINT_SIZE, 0.0f }; + trans[2] = { -CUBE_LINE_POINT_SIZE, -CUBE_LINE_POINT_SIZE, 0.0f }; + trans[3] = { CUBE_LINE_POINT_SIZE, -CUBE_LINE_POINT_SIZE, 0.0f }; + + mat4_mult_vec3(&cam->inv_view_rot, &trans[0], &trans[0]); + mat4_mult_vec3(&cam->inv_view_rot, &trans[1], &trans[1]); + mat4_mult_vec3(&cam->inv_view_rot, &trans[2], &trans[2]); + mat4_mult_vec3(&cam->inv_view_rot, &trans[3], &trans[3]); + + gl_state_bind_vertex_array(cube_line_point_vao); + cube_line_point_shader->use(); + cube_line_point_shader->set("trans", 4, trans); + cube_line_point_shader->set("border_end", + ((CUBE_LINE_POINT_SIZE - (CUBE_LINE_SIZE * 1.125f)) / (2.0f * CUBE_LINE_POINT_SIZE))); + cube_line_point_shader->set("border_start", + (1.0f - ((CUBE_LINE_POINT_SIZE - (CUBE_LINE_SIZE * 1.125f)) / (2.0f * CUBE_LINE_POINT_SIZE)))); + cube_line_point_shader->set("border_color", 0.0f, 0.0f, 0.0f); + cube_line_point_shader->set("center_color", 1.0f, 1.0f, 1.0f); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)cube_line_points.size()); + gl_state_bind_vertex_array(0); + cube_line_points.clear(); + cube_line_points.shrink_to_fit(); } - motion_blend_mot* mot = rob_chr->bone_data->motion_loaded.front(); - mot_key_set* key_set = mot->mot_key_data.mot.key_sets; - for (bone_data& j :mot->bone_data.bones) - if (j.type >= BONE_DATABASE_BONE_HEAD_IK_ROTATION - && j.type <= BONE_DATABASE_BONE_LEGS_IK_ROTATION) - cube_line_points.push_back({ j.ik_target, 0.0f }); + if (auth_3d_disp) + for (auth_3d& i : auth_3d_data->data) { + if (i.id == -1 || !i.visible) + continue; - for (std::pair& i : cube_line_points) { - vec3 trans; - mat4_mult_vec3(&cam->view_projection, &i.first, &trans); - i.second = trans.z; + for (auth_3d_object_hrc& j : i.object_hrc) { + if (!j.node[0].model_transform.visible) + continue; + + gl_state_bind_vertex_array(cube_line_vao); + gl_state_bind_array_buffer(cube_line_vbo); + cube_line_shader->use(); + for (auth_3d_object_node& k : j.node) { + if (k.parent == -1 ) + continue; + + vec3 trans[2]; + mat4_get_translation(&j.node[k.parent].model_transform.mat, &trans[0]); + mat4_get_translation(&k.model_transform.mat, &trans[1]); + + if (memcmp(&trans[0], &trans[1], sizeof(vec3))) + cube_line_disp(cube_line_shader, cam, trans, CUBE_LINE_SIZE, &osg_color); + } + gl_state_bind_array_buffer(0); + + std::vector> cube_line_points; + for (auth_3d_object_node& k : j.node) { + vec3 trans; + vec3 vp_trans; + mat4_get_translation(&k.model_transform.mat, &trans); + mat4_mult_vec3(&cam->view_projection, &trans, &vp_trans); + cube_line_points.push_back({ trans, vp_trans.z }); + } + + quicksort_custom(cube_line_points.data(), cube_line_points.size(), + sizeof(std::pair), cube_line_points_sort); + + gl_state_bind_array_buffer(cube_line_point_instance_vbo); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(sizeof(std::pair) + * cube_line_points.size()), cube_line_points.data(), GL_STREAM_DRAW); + gl_state_bind_array_buffer(0); + + vec3 trans[4]; + trans[0] = { -CUBE_LINE_POINT_SIZE, CUBE_LINE_POINT_SIZE, 0.0f }; + trans[1] = { CUBE_LINE_POINT_SIZE, CUBE_LINE_POINT_SIZE, 0.0f }; + trans[2] = { -CUBE_LINE_POINT_SIZE, -CUBE_LINE_POINT_SIZE, 0.0f }; + trans[3] = { CUBE_LINE_POINT_SIZE, -CUBE_LINE_POINT_SIZE, 0.0f }; + + mat4_mult_vec3(&cam->inv_view_rot, &trans[0], &trans[0]); + mat4_mult_vec3(&cam->inv_view_rot, &trans[1], &trans[1]); + mat4_mult_vec3(&cam->inv_view_rot, &trans[2], &trans[2]); + mat4_mult_vec3(&cam->inv_view_rot, &trans[3], &trans[3]); + + gl_state_bind_vertex_array(cube_line_point_vao); + cube_line_point_shader->use(); + cube_line_point_shader->set("trans", 4, trans); + cube_line_point_shader->set("border_end", + ((CUBE_LINE_POINT_SIZE - (CUBE_LINE_SIZE * 1.125f)) / (2.0f * CUBE_LINE_POINT_SIZE))); + cube_line_point_shader->set("border_start", + (1.0f - ((CUBE_LINE_POINT_SIZE - (CUBE_LINE_SIZE * 1.125f)) / (2.0f * CUBE_LINE_POINT_SIZE)))); + cube_line_point_shader->set("border_color", 0.0f, 0.0f, 0.0f); + cube_line_point_shader->set("center_color", 1.0f, 1.0f, 1.0f); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)cube_line_points.size()); + gl_state_bind_vertex_array(0); + cube_line_points.clear(); + cube_line_points.shrink_to_fit(); + } } - quicksort_custom(cube_line_points.data(), cube_line_points.size(), - sizeof(std::pair), cube_line_points_sort); + if (rob_disp) + for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) { + if (rob_chara_pv_data_array[i].type == ROB_CHARA_TYPE_NONE) + continue; - gl_state_bind_array_buffer(cube_line_point_instance_vbo); - glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(sizeof(std::pair) - * cube_line_points.size()), cube_line_points.data(), GL_STREAM_DRAW); - gl_state_bind_array_buffer(0); + rob_chara* rob_chr = &rob_chara_array[i]; + if (~rob_chr->data.field_0 & 1) + continue; - vec3 trans[4]; - trans[0] = { -1.0, 1.0, 0.0 }; - trans[1] = { 1.0, 1.0, 0.0 }; - trans[2] = { -1.0, -1.0, 0.0 }; - trans[3] = { 1.0, -1.0, 0.0 }; + std::vector> cube_line_points; + motion_blend_mot* mot = rob_chr->bone_data->motion_loaded.front(); + mot_key_set* key_set = mot->mot_key_data.mot.key_sets; + for (bone_data& j : mot->bone_data.bones) + if (j.type >= BONE_DATABASE_BONE_HEAD_IK_ROTATION + && j.type <= BONE_DATABASE_BONE_LEGS_IK_ROTATION) { + vec3 trans; + mat4_mult_vec3(&cam->view_projection, &j.ik_target, &trans); + cube_line_points.push_back({ j.ik_target, trans.z }); + } - vec3_mult_scalar(trans[0], CUBE_LINE_POINT_SIZE, trans[0]); - vec3_mult_scalar(trans[1], CUBE_LINE_POINT_SIZE, trans[1]); - vec3_mult_scalar(trans[2], CUBE_LINE_POINT_SIZE, trans[2]); - vec3_mult_scalar(trans[3], CUBE_LINE_POINT_SIZE, trans[3]); + quicksort_custom(cube_line_points.data(), cube_line_points.size(), + sizeof(std::pair), cube_line_points_sort); - mat4_mult_vec3(&cam->inv_view_rot, &trans[0], &trans[0]); - mat4_mult_vec3(&cam->inv_view_rot, &trans[1], &trans[1]); - mat4_mult_vec3(&cam->inv_view_rot, &trans[2], &trans[2]); - mat4_mult_vec3(&cam->inv_view_rot, &trans[3], &trans[3]); + gl_state_bind_array_buffer(cube_line_point_instance_vbo); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(sizeof(std::pair) + * cube_line_points.size()), cube_line_points.data(), GL_STREAM_DRAW); + gl_state_bind_array_buffer(0); + + vec3 trans[4]; + trans[0] = { -CUBE_LINE_POINT_SIZE, CUBE_LINE_POINT_SIZE, 0.0f }; + trans[1] = { CUBE_LINE_POINT_SIZE, CUBE_LINE_POINT_SIZE, 0.0f }; + trans[2] = { -CUBE_LINE_POINT_SIZE, -CUBE_LINE_POINT_SIZE, 0.0f }; + trans[3] = { CUBE_LINE_POINT_SIZE, -CUBE_LINE_POINT_SIZE, 0.0f }; + + mat4_mult_vec3(&cam->inv_view_rot, &trans[0], &trans[0]); + mat4_mult_vec3(&cam->inv_view_rot, &trans[1], &trans[1]); + mat4_mult_vec3(&cam->inv_view_rot, &trans[2], &trans[2]); + mat4_mult_vec3(&cam->inv_view_rot, &trans[3], &trans[3]); + + gl_state_bind_vertex_array(cube_line_point_vao); + cube_line_point_shader->use(); + cube_line_point_shader->set("trans", 4, trans); + cube_line_point_shader->set("border_end", + ((CUBE_LINE_POINT_SIZE - (CUBE_LINE_SIZE * 1.125f)) / (2.0f * CUBE_LINE_POINT_SIZE))); + cube_line_point_shader->set("border_start", + (1.0f - ((CUBE_LINE_POINT_SIZE - (CUBE_LINE_SIZE * 1.125f)) / (2.0f * CUBE_LINE_POINT_SIZE)))); + cube_line_point_shader->set("border_color", 0.0f, 0.0f, 0.0f); + cube_line_point_shader->set("center_color", 0.0f, 1.0f, 0.0f); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)cube_line_points.size()); + gl_state_bind_vertex_array(0); + cube_line_points.clear(); + cube_line_points.shrink_to_fit(); + } - gl_state_bind_vertex_array(cube_line_point_vao); - cube_line_point_shader->use(); - cube_line_point_shader->set("trans", 4, trans); - cube_line_point_shader->set("dark_border_end", - ((CUBE_LINE_POINT_SIZE - (CUBE_LINE_SIZE * 1.125f)) / (2.0f * CUBE_LINE_POINT_SIZE))); - cube_line_point_shader->set("dark_border_start", - (1.0f - ((CUBE_LINE_POINT_SIZE - (CUBE_LINE_SIZE * 1.125f)) / (2.0f * CUBE_LINE_POINT_SIZE)))); - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)cube_line_points.size()); - cube_line_points.clear(); - cube_line_points.shrink_to_fit(); - } gl_state_bind_vertex_array(0); gl_state_enable_cull_face(); gl_state_bind_framebuffer(0); @@ -1420,7 +1518,8 @@ static void render_dispose(render_context* rctx) { ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(imgui_context); - lock_free(&imgui_context_lock); + delete imgui_context_lock; + imgui_context_lock = 0; //pv_game_data.SetDest(); Glitter::glt_particle_manager_free_task(); @@ -1433,12 +1532,13 @@ static void render_dispose(render_context* rctx) { render_timer->reset(); while (app::task_work->tasks.size()) { render_timer->start_of_cycle(); - lock_lock(&render_lock); + lock_lock(render_lock); game_state_ctrl(); app::TaskWork::Ctrl(); + sound_ctrl(); file_handler_storage_ctrl(); app::TaskWork::Basic(); - lock_unlock(&render_lock); + lock_unlock(render_lock); render_timer->end_of_cycle(); } @@ -1459,6 +1559,15 @@ static void render_dispose(render_context* rctx) { cube_line_shader = 0; } + sound_work_unload_farc("rom/sound/se.farc"); + sound_work_unload_farc("rom/sound/button.farc"); + sound_work_unload_farc("rom/sound/se_cmn.farc"); + sound_work_unload_farc("rom/sound/se_sel.farc"); + sound_work_unload_farc("rom/sound/se_aime.farc"); + sound_work_unload_farc("rom/sound/pvchange.farc"); + sound_work_unload_farc("rom/sound/slide_se.farc"); + sound_work_unload_farc("rom/sound/slide_long.farc"); + object_storage_unload_set(dbg_set_id); task_data_test_glitter_particle_free(); @@ -1477,12 +1586,6 @@ static void render_dispose(render_context* rctx) { task_wind_free(); rob_free(); - app::task_work_free(); - - item_table_array_free(); - object_storage_free(); - data_struct_free(); - glDeleteBuffers(1, &common_data_ubo); glDeleteBuffers(1, &grid_vbo); glDeleteBuffers(1, &cube_line_point_instance_vbo); @@ -1490,25 +1593,34 @@ static void render_dispose(render_context* rctx) { glDeleteBuffers(1, &cube_line_vbo); glDeleteVertexArrays(1, &cube_line_vao); - motion_storage_free(); - mothead_storage_free(); + app::task_work_free(); + + rand_state_array_free(); + item_table_array_free(); + object_storage_free(); + wave_audio_storage_free(); + sound_free(); + render_shaders_free(); + osage_setting_data_free(); + data_struct_free(); + + osage_setting_data_free(); + mothead_storage_free(); + motion_storage_free(); + render_texture_data_free(); - delete rctx; file_handler_storage_free(); - - texture_storage_free(); - - render_shaders_free(); + delete rctx; } static void render_imgui(render_context* rctx) { - lock_lock(&imgui_context_lock); + lock_lock(imgui_context_lock); ImGui::SetCurrentContext(imgui_context); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - lock_unlock(&imgui_context_lock); + lock_unlock(imgui_context_lock); } static bool render_load_shaders(void* data, const char* path, const char* file, uint32_t hash) { @@ -1560,8 +1672,8 @@ static void render_resize_fb(render_context* rctx, bool change_fb) { internal_res.x = (int32_t)res_width; internal_res.y = (int32_t)res_height; - internal_2d_res.x = clamp(internal_res.x, 1, sv_max_texture_size); - internal_2d_res.y = clamp(internal_res.y, 1, sv_max_texture_size); + internal_2d_res.x = clamp_def(internal_res.x, 1, sv_max_texture_size); + internal_2d_res.y = clamp_def(internal_res.y, 1, sv_max_texture_size); #if BAKE_PNG || BAKE_VIDEO internal_3d_res.x = (int32_t)roundf((float_t)(internal_res.x * 2)); internal_3d_res.y = (int32_t)roundf((float_t)(internal_res.y * 2)); @@ -1569,8 +1681,8 @@ static void render_resize_fb(render_context* rctx, bool change_fb) { internal_3d_res.x = (int32_t)roundf((float_t)(internal_res.x * render_scale_table[scale_index])); internal_3d_res.y = (int32_t)roundf((float_t)(internal_res.y * render_scale_table[scale_index])); #endif - 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); + internal_3d_res.x = clamp_def(internal_3d_res.x, 1, sv_max_texture_size); + internal_3d_res.y = clamp_def(internal_3d_res.y, 1, sv_max_texture_size); bool fb_changed = old_internal_2d_res.x != internal_2d_res.x || old_internal_2d_res.y != internal_2d_res.y @@ -1580,12 +1692,7 @@ static void render_resize_fb(render_context* rctx, bool change_fb) { old_internal_2d_res = internal_2d_res; old_internal_3d_res = internal_3d_res; - bool st = false; - lock_lock(&state_lock); - st = state == RENDER_INITIALIZED; - lock_unlock(&state_lock); - - if (st && fb_changed && change_fb) { + if (fb_changed && change_fb) { rctx->post_process.init_fbo(internal_3d_res.x, internal_3d_res.y, internal_2d_res.x, internal_2d_res.y, width, height); rctx->litproj->resize(internal_3d_res.x, internal_3d_res.y); @@ -1594,6 +1701,8 @@ static void render_resize_fb(render_context* rctx, bool change_fb) { static void render_imgui_context_menu(classes_data* classes, const size_t classes_count, render_context* rctx) { +#pragma warning(disable:26115) +#pragma warning(disable:26117) for (size_t i = 0; i < classes_count; i++) { classes_data* c = &classes[i]; if (!c->name || ~c->flags & CLASSES_IN_CONTEXT_MENU) @@ -1610,23 +1719,22 @@ static void render_imgui_context_menu(classes_data* classes, ImGui::MenuItem(c->name, 0, false, false); else if (ImGui::MenuItem(c->name, 0)) { if (~c->data.flags & CLASS_INIT) { - lock_init(&c->data.lock); - if (lock_check_init(&c->data.lock) && c->init) { - lock_lock(&c->data.lock); + c->data.lock = new lock; + if (c->data.lock->check_init() && c->init) { + lock_lock(c->data.lock); if (c->init(&c->data, rctx)) c->data.flags = CLASS_INIT; else c->data.flags = (class_flags)(CLASS_DISPOSED | CLASS_HIDDEN); - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } } - if (lock_check_init(&c->data.lock)) { - lock_lock(&c->data.lock); - if (c->data.flags & CLASS_INIT && ((c->show && c->show(&c->data)) || !c->show)) { + if (c->data.lock->check_init()) { + lock_lock(c->data.lock); + if (c->data.flags & CLASS_INIT && ((c->show && c->show(&c->data)) || !c->show)) enum_and(c->data.flags, ~(CLASS_HIDE | CLASS_HIDDEN | CLASS_HIDE_WINDOW)); - } - lock_unlock(&c->data.lock); + lock_unlock(c->data.lock); } } } diff --git a/src/ReDIVA/render.hpp b/src/ReDIVA/render.hpp index 3952c0d1..684532fe 100644 --- a/src/ReDIVA/render.hpp +++ b/src/ReDIVA/render.hpp @@ -36,7 +36,7 @@ struct render_init_struct { extern const double_t render_scale_table[]; -extern int32_t render_main(void* arg); +extern int32_t render_main(render_init_struct* ris); extern double_t render_get_scale(); extern int32_t render_get_scale_index(); extern void render_set_scale_index(int32_t index); diff --git a/src/ReDIVA/shared.cpp b/src/ReDIVA/shared.cpp index 46a8a2f5..998ba57f 100644 --- a/src/ReDIVA/shared.cpp +++ b/src/ReDIVA/shared.cpp @@ -103,7 +103,3 @@ classes_data classes[] = { }; const size_t classes_count = sizeof(classes) / sizeof(classes_data); - -render_state state; -thread_flag thread_flags; -lock state_lock; diff --git a/src/ReDIVA/shared.hpp b/src/ReDIVA/shared.hpp index d80f8f38..ed58300b 100644 --- a/src/ReDIVA/shared.hpp +++ b/src/ReDIVA/shared.hpp @@ -10,22 +10,5 @@ #include #include -enum render_state { - RENDER_UNINITIALIZED = 0, - RENDER_INITIALIZING = 1, - RENDER_INITIALIZED = 2, - RENDER_DISPOSING = 3, - RENDER_DISPOSED = 4, -}; - -enum thread_flag { - THREAD_RENDER = 0x01, - THREAD_SOUND = 0x02, - THREAD_INPUT = 0x04, -}; - extern classes_data classes[]; extern const size_t classes_count; -extern render_state state; -extern thread_flag thread_flags; -extern lock state_lock; diff --git a/src/ReDIVA/sound.cpp b/src/ReDIVA/sound.cpp deleted file mode 100644 index 653bd84a..00000000 --- a/src/ReDIVA/sound.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#include "sound.hpp" -#include "../CRE/timer.hpp" -#include - -timer* sound_timer; - -extern bool close; - -int32_t sound_main(void* arg) { - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - timeBeginPeriod(1); - sound_timer = new timer(60.0); - - bool state_wait = false; - bool state_disposed = false; - do { - lock_lock(&state_lock); - state_wait = state != RENDER_INITIALIZING; - state_disposed = state == RENDER_DISPOSING; - lock_unlock(&state_lock); - if (state_disposed) { - delete sound_timer; - return 0; - } - sound_timer->sleep(0.0625); - } while (state_wait); - - lock_lock(&state_lock); - enum_or(thread_flags, THREAD_SOUND); - lock_unlock(&state_lock); - - bool local_close = false; - sound_timer->reset(); - while (!close && !local_close) { - sound_timer->start_of_cycle(); - lock_lock(&state_lock); - local_close = state == RENDER_DISPOSING; - lock_unlock(&state_lock); - - classes_process_sound(classes, classes_count); - sound_timer->end_of_cycle(); - } - delete sound_timer; - - lock_lock(&state_lock); - enum_and(thread_flags, ~THREAD_SOUND); - lock_unlock(&state_lock); - return 0; -} diff --git a/src/ReDIVA/sound.hpp b/src/ReDIVA/sound.hpp deleted file mode 100644 index c9d727bd..00000000 --- a/src/ReDIVA/sound.hpp +++ /dev/null @@ -1,10 +0,0 @@ -/* - by korenkonder - GitHub/GitLab: korenkonder -*/ - -#pragma once - -#include "shared.hpp" - -extern int32_t sound_main(void* arg); diff --git a/src/ReDIVA/x_pv_game.cpp b/src/ReDIVA/x_pv_game.cpp index e7acb85f..c16090ba 100644 --- a/src/ReDIVA/x_pv_game.cpp +++ b/src/ReDIVA/x_pv_game.cpp @@ -1,4 +1,4 @@ -/* +/* by korenkonder GitHub/GitLab: korenkonder @@ -15,6 +15,7 @@ #include "../CRE/object.hpp" #include "../CRE/pv_expression.hpp" #include "../CRE/pv_param.hpp" +#include "../CRE/sound.hpp" #include "../KKdLib/farc.hpp" #include "../KKdLib/interpolation.hpp" #include "../KKdLib/sort.hpp" @@ -560,6 +561,19 @@ x_pv_play_data::~x_pv_play_data() { } void x_pv_play_data::reset() { + if (rob_chr) { + data_struct* aft_data = &data_list[DATA_AFT]; + bone_database* aft_bone_data = &aft_data->data_ft.bone_data; + motion_database* aft_mot_db = &aft_data->data_ft.mot_db; + + int32_t mottbl_index = hand_anim_id_to_mottbl_index(2); + + rob_chr->reset_data(&rob_chr->pv_data, aft_bone_data, aft_mot_db); + rob_chr->set_hand_l_mottbl_motion(0, mottbl_index, 1.0f, 0, 0.0f, 0.0f, 1.0f, -1, 0.0f, aft_mot_db); + rob_chr->set_hand_r_mottbl_motion(0, mottbl_index, 1.0f, 0, 0.0f, 0.0f, 1.0f, -1, 0.0f, aft_mot_db); + rob_chr->set_visibility(false); + } + motion.clear(); motion.shrink_to_fit(); rob_chr = 0; @@ -713,7 +727,8 @@ x_pv_game_song_effect_glitter::x_pv_game_song_effect_glitter() : scene_counter() void x_pv_game_song_effect_glitter::reset() { name.str.clear(); name.str.shrink_to_fit(); - name.hash = hash_murmurhash_empty; + name.hash_fnv1a64m = hash_fnv1a64m_empty; + name.hash_murmurhash = hash_murmurhash_empty; scene_counter = 0; field_8 = false; for (bool& i : field_9) @@ -749,10 +764,10 @@ x_pv_game_camera::~x_pv_game_camera() { void x_pv_game_camera::ctrl(float_t curr_time) { switch (state) { case 10: { - if (!auth_3d_data_check_category_loaded(category.hash)) + if (!auth_3d_data_check_category_loaded(category.hash_murmurhash)) break; - int32_t id = auth_3d_data_load_hash(file.hash, &data_list[DATA_X], 0, 0); + int32_t id = auth_3d_data_load_hash(file.hash_murmurhash, &data_list[DATA_X], 0, 0); if (auth_3d_data_check_id_not_empty(&id)) { auth_3d_data_read_file_modern(&id); auth_3d_data_set_enable(&id, false); @@ -799,7 +814,7 @@ void x_pv_game_camera::load_data() { if (state || !category.str.size()) return; - auth_3d_data_load_category(&data_list[DATA_X], category.c_str(), category.hash); + auth_3d_data_load_category(&data_list[DATA_X], category.c_str(), category.hash_murmurhash); state = 10; } @@ -807,10 +822,12 @@ void x_pv_game_camera::reset() { state = 0; category.str.clear(); category.str.shrink_to_fit(); - category.hash = hash_murmurhash_empty; + category.hash_fnv1a64m = hash_fnv1a64m_empty; + category.hash_murmurhash = hash_murmurhash_empty; file.str.clear(); file.str.shrink_to_fit(); - file.hash = hash_murmurhash_empty; + file.hash_fnv1a64m = hash_fnv1a64m_empty; + file.hash_murmurhash = hash_murmurhash_empty; auth_3d_id = -1; } @@ -824,7 +841,7 @@ void x_pv_game_camera::unload() { return; auth_3d_data_unload_id(auth_3d_id, rctx_ptr); - auth_3d_data_unload_category(category.hash); + auth_3d_data_unload_category(category.hash_murmurhash); state = 0; } @@ -843,12 +860,12 @@ void x_pv_game_effect::ctrl(object_database* obj_db, texture_database* tex_db) { bool wait_load = false; for (string_hash& i : pv_auth_3d) - if (!auth_3d_data_check_category_loaded(i.hash)) + if (!auth_3d_data_check_category_loaded(i.hash_murmurhash)) wait_load |= true; for (string_hash& i : pv_obj_set) - if (object_storage_get_obj_set_handler(i.hash) - && object_storage_load_obj_set_check_not_read(i.hash, obj_db, tex_db)) + if (object_storage_get_obj_set_handler(i.hash_murmurhash) + && object_storage_load_obj_set_check_not_read(i.hash_murmurhash, obj_db, tex_db)) wait_load |= true; if (wait_load) @@ -863,7 +880,7 @@ void x_pv_game_effect::ctrl(object_database* obj_db, texture_database* tex_db) { x_pv_game_song_effect& song_effect = this->song_effect[i]; pvpp_effect& effect = play_param->effect[i]; for (string_hash& j : effect.auth_3d) { - int32_t id = auth_3d_data_load_hash(j.hash, x_data, obj_db, tex_db); + int32_t id = auth_3d_data_load_hash(j.hash_murmurhash, x_data, obj_db, tex_db); if (!auth_3d_data_check_id_not_empty(&id)) { continue; } @@ -890,7 +907,7 @@ void x_pv_game_effect::ctrl(object_database* obj_db, texture_database* tex_db) { wait_load |= true; for (string_hash& i : pv_glitter) - if (!Glitter::glt_particle_manager->CheckNoFileReaders(i.hash)) + if (!Glitter::glt_particle_manager->CheckNoFileReaders(i.hash_murmurhash)) wait_load |= true; if (wait_load) @@ -917,7 +934,7 @@ void x_pv_game_effect::ctrl(object_database* obj_db, texture_database* tex_db) { if (k < play_param->chara.size()) { pvpp_chara& chara = play_param->chara[k]; for (pvpp_glitter& l : chara.glitter) - if (j.name.hash == l.name.hash) { + if (j.name.hash_murmurhash == l.name.hash_murmurhash) { v121 = true; break; } @@ -931,7 +948,7 @@ void x_pv_game_effect::ctrl(object_database* obj_db, texture_database* tex_db) { data_struct* x_data = &data_list[DATA_X]; for (string_hash& i : pv_glitter) { - Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i.hash); + Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i.hash_murmurhash); if (eff_group && eff_group->CheckModel()) eff_group->LoadModel(x_data); } @@ -943,7 +960,7 @@ void x_pv_game_effect::ctrl(object_database* obj_db, texture_database* tex_db) { bool wait_load = false; for (string_hash& i : pv_glitter) { - Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i.hash); + Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i.hash_murmurhash); if (eff_group && eff_group->CheckLoadModel()) wait_load |= true; } @@ -979,10 +996,10 @@ void x_pv_game_effect::load(int32_t pv_id, pvpp* play_param, FrameRateControl* f char buf[0x100]; size_t len = sprintf_s(buf, sizeof(buf), "A3D_EFFPV%03d", pv_id); - pv_auth_3d.push_back({ std::string(buf, len), hash_murmurhash(buf, len) }); + pv_auth_3d.push_back(std::string(buf, len)); len = sprintf_s(buf, sizeof(buf), "effpv%03d", 800 + (pv_id % 100)); - pv_obj_set.push_back({ std::string(buf, len), hash_murmurhash(buf, len) }); + pv_obj_set.push_back(std::string(buf, len)); break; } } @@ -994,10 +1011,10 @@ void x_pv_game_effect::load_data(int32_t pv_id) { data_struct* x_data = &data_list[DATA_X]; for (string_hash& i : pv_obj_set) - object_storage_load_set_hash(x_data, i.hash); + object_storage_load_set_hash(x_data, i.hash_murmurhash); for (string_hash& i : pv_auth_3d) - auth_3d_data_load_category(x_data, i.c_str(), i.hash); + auth_3d_data_load_category(x_data, i.c_str(), i.hash_murmurhash); size_t effect_count = play_param->effect.size(); for (size_t i = 0; i < effect_count; i++) { @@ -1010,7 +1027,7 @@ void x_pv_game_effect::load_data(int32_t pv_id) { uint32_t hash = (uint32_t)Glitter::glt_particle_manager->LoadFile(Glitter::X, x_data, buf, 0, -1.0f, false, 0); if (hash != hash_murmurhash_empty) - pv_glitter.push_back({ buf, hash }); + pv_glitter.push_back(std::string(buf, len)); break; } @@ -1075,7 +1092,7 @@ void x_pv_game_effect::set_song_effect(int32_t index, int64_t time) { } for (x_pv_game_song_effect_glitter& i : song_effect.glitter) { - i.scene_counter = Glitter::glt_particle_manager->LoadSceneEffect(i.name.hash, i.name.c_str()); + i.scene_counter = Glitter::glt_particle_manager->LoadSceneEffect(i.name.hash_murmurhash, i.name.c_str()); if (!i.scene_counter) continue; @@ -1143,7 +1160,7 @@ void x_pv_game_effect::stop() { stop_song_effect((int32_t)i, false); for (string_hash& i : pv_glitter) - Glitter::glt_particle_manager->FreeScene(i.hash); + Glitter::glt_particle_manager->FreeScene(i.hash_murmurhash); } void x_pv_game_effect::stop_song_effect(int32_t index, bool free_glitter) { @@ -1178,7 +1195,7 @@ void x_pv_game_effect::unload() { stop_song_effect((int32_t)i, false); for (string_hash& i : pv_glitter) - Glitter::glt_particle_manager->FreeScene(i.hash); + Glitter::glt_particle_manager->FreeScene(i.hash_murmurhash); for (x_pv_game_song_effect& i : song_effect) for (x_pv_game_song_effect_auth_3d& j : i.auth_3d) { @@ -1187,17 +1204,17 @@ void x_pv_game_effect::unload() { } for (string_hash& i : pv_auth_3d) - auth_3d_data_unload_category(i.hash); + auth_3d_data_unload_category(i.hash_murmurhash); for (string_hash& i : pv_obj_set) - object_storage_unload_set(i.hash); + object_storage_unload_set(i.hash_murmurhash); for (string_hash& i : pv_glitter) { - Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i.hash); + Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i.hash_murmurhash); if (eff_group) eff_group->FreeModel(); - Glitter::glt_particle_manager->UnloadEffectGroup(i.hash); + Glitter::glt_particle_manager->UnloadEffectGroup(i.hash_murmurhash); } song_effect.clear(); @@ -1221,13 +1238,16 @@ void x_pv_game_chara_effect_auth_3d::reset() { dst_chara = CHARA_MAX; file.str.clear(); file.str.shrink_to_fit(); - file.hash = hash_murmurhash_empty; + file.hash_fnv1a64m = hash_fnv1a64m_empty; + file.hash_murmurhash = hash_murmurhash_empty; category.str.clear(); category.str.shrink_to_fit(); - category.hash = hash_murmurhash_empty; + category.hash_fnv1a64m = hash_fnv1a64m_empty; + category.hash_murmurhash = hash_murmurhash_empty; object_set.str.clear(); object_set.str.shrink_to_fit(); - object_set.hash = hash_murmurhash_empty; + object_set.hash_fnv1a64m = hash_fnv1a64m_empty; + object_set.hash_murmurhash = hash_murmurhash_empty; id = -1; time = -1; } @@ -1250,11 +1270,11 @@ void x_pv_game_chara_effect::ctrl(object_database* obj_db, texture_database* tex if (!j.category.str.size()) continue; - if (!auth_3d_data_check_category_loaded(j.category.hash)) + if (!auth_3d_data_check_category_loaded(j.category.hash_murmurhash)) wait_load |= true; - if (object_storage_get_obj_set_handler(j.object_set.hash) - && object_storage_load_obj_set_check_not_read(j.object_set.hash, obj_db, tex_db)) + if (object_storage_get_obj_set_handler(j.object_set.hash_murmurhash) + && object_storage_load_obj_set_check_not_read(j.object_set.hash_murmurhash, obj_db, tex_db)) wait_load |= true; } @@ -1264,11 +1284,11 @@ void x_pv_game_chara_effect::ctrl(object_database* obj_db, texture_database* tex data_struct* x_data = &data_list[DATA_X]; for (std::vector& i : auth_3d) - for (x_pv_game_chara_effect_auth_3d j : i) { + for (x_pv_game_chara_effect_auth_3d& j : i) { if (!j.category.str.size()) continue; - int32_t id = auth_3d_data_load_hash(j.file.hash, x_data, obj_db, tex_db); + int32_t id = auth_3d_data_load_hash(j.file.hash_murmurhash, x_data, obj_db, tex_db); if (!auth_3d_data_check_id_not_empty(&id)) { j.id = -1; continue; @@ -1352,15 +1372,14 @@ void x_pv_game_chara_effect::load(int32_t pv_id, pvpp* play_param, if (src_chara != dst_chara) { - size_t pos = 0; - pos = object_set.find(src_chara_str); + size_t pos = object_set.find(dst_chara_str); if (pos && pos != -1) - object_set.replace(pos, src_chara_str.size(), dst_chara_str); + object_set.replace(pos, dst_chara_str.size(), src_chara_str); if (!auth_3d.field_0) { - size_t pos = file.find(src_chara_str); + size_t pos = file.find(dst_chara_str); if (pos != -1) - file = file.replace(pos, src_chara_str.size(), dst_chara_str); + file = file.replace(pos, dst_chara_str.size(), src_chara_str); } } @@ -1392,11 +1411,11 @@ void x_pv_game_chara_effect::load_data() { if (!j.category.str.size()) continue; - auth_3d_data_load_category(x_data, j.category.c_str(), j.category.hash); - object_storage_load_set_hash(x_data, j.object_set.hash); + auth_3d_data_load_category(x_data, j.category.c_str(), j.category.hash_murmurhash); + object_storage_load_set_hash(x_data, j.object_set.hash_murmurhash); } - state = 10; + state = 20; } void x_pv_game_chara_effect::reset() { @@ -1501,8 +1520,8 @@ void x_pv_game_chara_effect::unload() { continue; auth_3d_data_unload_id(j.id, rctx_ptr); - auth_3d_data_unload_category(j.category.hash); - object_storage_unload_set(j.object_set.hash); + auth_3d_data_unload_category(j.category.hash_murmurhash); + object_storage_unload_set(j.object_set.hash_murmurhash); } state = 10; } @@ -1626,7 +1645,7 @@ int64_t x_pv_game_dsc_data::find_pv_end() { i = dsc.data.data(); i_end = dsc.data.data() + dsc.data.size(); find(DSC_X_END, &end_time, &pv_branch_mode, i, i_end); - return max(pv_end_time, end_time); + return max_def(pv_end_time, end_time); } void x_pv_game_dsc_data::find_stage_effects(std::vector>& stage_effects) { @@ -1711,7 +1730,7 @@ void x_pv_game_data::ctrl(float_t curr_time, float_t delta_time) { case 20: { effect.load_data(pv_id); chara_effect.load_data(); - pv_expression_file_load(&data_list[DATA_X], "root+/pv_expression/", exp_file.hash); + pv_expression_file_load(&data_list[DATA_X], "root+/pv_expression/", exp_file.hash_murmurhash); state = 21; } break; case 21: { @@ -1725,7 +1744,7 @@ void x_pv_game_data::ctrl(float_t curr_time, float_t delta_time) { case 22: { bool wait_load = false; - wait_load |= pv_expression_file_check_not_ready(exp_file.hash); + wait_load |= pv_expression_file_check_not_ready(exp_file.hash_murmurhash); wait_load |= camera.state && camera.state != 20; wait_load |= effect.state && effect.state != 20; wait_load |= chara_effect.state && chara_effect.state != 10 && chara_effect.state != 30; @@ -1809,8 +1828,8 @@ void x_pv_game_data::load(int32_t pv_id, FrameRateControl* frame_rate_control, c chara_effect.load(pv_id, play_param, frame_rate_control, charas); char buf[0x100]; - sprintf_s(buf, sizeof(buf), "exp_PV%03d", pv_id); - exp_file = { buf, hash_utf8_murmurhash(buf) }; + size_t len = sprintf_s(buf, sizeof(buf), "exp_PV%03d", pv_id); + exp_file = std::string(buf, len); camera.load(pv_id, stage->stage_id, frame_rate_control); @@ -1819,6 +1838,7 @@ void x_pv_game_data::load(int32_t pv_id, FrameRateControl* frame_rate_control, c void x_pv_game_data::reset() { pv_id = 0; + play_param_file_handler.free_data(); if (play_param) { delete play_param; play_param = 0; @@ -1837,11 +1857,14 @@ void x_pv_game_data::reset() { next_stage_effect_bar = 0; stage_effects.clear(); stage_effects.shrink_to_fit(); + camera.reset(); effect.reset(); + chara_effect.reset(); dsc_data.reset(); exp_file.str.clear(); exp_file.str.shrink_to_fit(); - exp_file.hash = hash_murmurhash_empty; + exp_file.hash_fnv1a64m = hash_fnv1a64m_empty; + exp_file.hash_murmurhash = hash_murmurhash_empty; //dof = {}; stage = 0; obj_db.object_set.clear(); @@ -1869,7 +1892,7 @@ void x_pv_game_data::unload() { chara_effect.unload(); //dof = {}; dsc_data.unload(); - pv_expression_file_unload(exp_file.hash); + pv_expression_file_unload(exp_file.hash_murmurhash); obj_db.object_set.clear(); obj_db.object_set.shrink_to_fit(); tex_db.texture.clear(); @@ -1900,7 +1923,8 @@ x_pv_game_stage_effect_glitter::x_pv_game_stage_effect_glitter() : void x_pv_game_stage_effect_glitter::reset() { name.str.clear(); name.str.shrink_to_fit(); - name.hash = hash_murmurhash_empty; + name.hash_fnv1a64m = hash_fnv1a64m_empty; + name.hash_murmurhash = hash_murmurhash_empty; scene_counter = 0; fade_time = 0.0f; fade_time_left = 0.0f; @@ -2174,7 +2198,7 @@ void x_pv_game_stage::ctrl(float_t delta_time) { } for (string_hash& i : stage_auth_3d) - auth_3d_data_load_category(x_data, i.c_str(), i.hash); + auth_3d_data_load_category(x_data, i.c_str(), i.hash_murmurhash); state = 11; } break; @@ -2185,7 +2209,7 @@ void x_pv_game_stage::ctrl(float_t delta_time) { bool wait_load = false; for (string_hash& i : stage_auth_3d) - if (!auth_3d_data_check_category_loaded(i.hash)) + if (!auth_3d_data_check_category_loaded(i.hash_murmurhash)) wait_load |= true; for (uint32_t& i : stage_glitter) @@ -2225,20 +2249,27 @@ void x_pv_game_stage::ctrl(float_t delta_time) { int32_t stage_effect = i + 1; - int32_t id = auth_3d_data_load_hash(stg_eff_auth_3d.name.hash, x_data, &obj_db, &tex_db); - if (!auth_3d_data_check_id_not_empty(&id)) { - eff_auth_3d.id = -1; - continue; + auto elem = auth_3d_ids.find(stg_eff_auth_3d.name.hash_murmurhash); + if (elem == auth_3d_ids.end()) { + int32_t id = auth_3d_data_load_hash(stg_eff_auth_3d.name.hash_murmurhash, x_data, &obj_db, &tex_db); + if (!auth_3d_data_check_id_not_empty(&id)) { + eff_auth_3d.id = -1; + continue; + } + + auth_3d_data_read_file_modern(&id); + auth_3d_data_set_enable(&id, false); + auth_3d_data_set_repeat(&id, true); + auth_3d_data_set_paused(&id, false); + auth_3d_data_set_visibility(&id, false); + auth_3d_data_set_frame_rate(&id, &bpm_frame_rate_control); + eff_auth_3d.id = id; + + auth_3d_ids.insert({ stg_eff_auth_3d.name.hash_murmurhash, id }); } + else + eff_auth_3d.id = elem->second; - auth_3d_data_read_file_modern(&id); - auth_3d_data_set_enable(&id, false); - auth_3d_data_set_repeat(&id, true); - auth_3d_data_set_paused(&id, false); - auth_3d_data_set_visibility(&id, false); - auth_3d_data_set_frame_rate(&id, &bpm_frame_rate_control); - - eff_auth_3d.id = id; if (stage_effect >= 8 && stage_effect <= 9) eff_auth_3d.repeat = false; else if (stage_effect == 7) @@ -2336,10 +2367,12 @@ void x_pv_game_stage::ctrl_inner() { switch (stage_effect_transition_state) { case 0: { if (v6) { - if (set_change_effect_frame(bar_beat->get_bar_current_frame())) { + if (set_change_effect_frame_part_1()) { chg_eff.bars_left = chg_eff.bar_count; stage_effect_transition_state = 1; stop_stage_effect_auth_3d(curr_stage_effect); + + set_change_effect_frame_part_2(bar_beat->get_bar_current_frame()); } else { stop_stage_effect_auth_3d(curr_stage_effect); @@ -2491,24 +2524,31 @@ void x_pv_game_stage::load_change_effect(int32_t curr_stage_effect, int32_t next chg_eff_auth_3d.reset(); - int32_t id = auth_3d_data_load_hash(stg_chg_eff_auth_3d.name.hash, x_data, &obj_db, &tex_db); - if (!auth_3d_data_check_id_not_empty(&id)) { - chg_eff_auth_3d.id = -1; - continue; + auto elem = auth_3d_ids.find(stg_chg_eff_auth_3d.name.hash_murmurhash); + if (elem == auth_3d_ids.end()) { + int32_t id = auth_3d_data_load_hash(stg_chg_eff_auth_3d.name.hash_murmurhash, x_data, &obj_db, &tex_db); + if (!auth_3d_data_check_id_not_empty(&id)) { + chg_eff_auth_3d.id = -1; + continue; + } + + auth_3d_data_read_file_modern(&id); + auth_3d_data_set_enable(&id, false); + auth_3d_data_set_repeat(&id, false); + auth_3d_data_set_paused(&id, false); + auth_3d_data_set_visibility(&id, false); + auth_3d_data_set_frame_rate(&id, &bpm_frame_rate_control); + chg_eff_auth_3d.id = id; + + auth_3d_ids.insert({ stg_chg_eff_auth_3d.name.hash_murmurhash, id }); } + else + chg_eff_auth_3d.id = elem->second; - auth_3d_data_read_file_modern(&id); - auth_3d_data_set_enable(&id, false); - auth_3d_data_set_repeat(&id, false); - auth_3d_data_set_paused(&id, false); - auth_3d_data_set_visibility(&id, false); - auth_3d_data_set_frame_rate(&id, &bpm_frame_rate_control); - - chg_eff_auth_3d.id = id; chg_eff_auth_3d.field_1 = true; chg_eff_auth_3d.repeat = !!(stg_chg_eff_auth_3d.flags & PVSR_AUTH_3D_REPEAT); } - + for (size_t i = 0; i < glitter_count; i++) { pvsr_glitter& stg_chg_eff_glt = stg_chg_eff.glitter[i]; x_pv_game_stage_effect_glitter& chg_eff_glt = chg_eff.glitter[i]; @@ -2524,6 +2564,7 @@ void x_pv_game_stage::reset() { stage_id = 0; field_8 = 0; state = 0; + stage_resource_file_handler.free_data(); if (stage_resource) { delete stage_resource; stage_resource = 0; @@ -2548,6 +2589,7 @@ void x_pv_game_stage::reset() { obj_db.object_set.shrink_to_fit(); tex_db.texture.clear(); tex_db.texture.shrink_to_fit(); + auth_3d_ids.clear(); } void x_pv_game_stage::reset_stage_effect() { @@ -2565,7 +2607,7 @@ void x_pv_game_stage::reset_stage_effect() { Glitter::glt_particle_manager->FreeScene(i); } -bool x_pv_game_stage::set_change_effect_frame(float_t frame) { +bool x_pv_game_stage::set_change_effect_frame_part_1() { if (!curr_stage_effect || !next_stage_effect) return false; @@ -2584,6 +2626,28 @@ bool x_pv_game_stage::set_change_effect_frame(float_t frame) { x_pv_game_stage_change_effect& chg_eff = change_effect[curr_stg_eff][next_sta_eff]; if (!chg_eff.enable) return false; + return true; +} + +void x_pv_game_stage::set_change_effect_frame_part_2(float_t frame) { + if (!curr_stage_effect || !next_stage_effect) + return; + + int32_t curr_stg_eff = curr_stage_effect; + if (curr_stg_eff >= 1 && curr_stg_eff <= 12) + curr_stg_eff--; + else + curr_stg_eff = 0; + + int32_t next_sta_eff = next_stage_effect; + if (next_sta_eff >= 1 && next_sta_eff <= 12) + next_sta_eff--; + else + next_sta_eff = 0; + + x_pv_game_stage_change_effect& chg_eff = change_effect[curr_stg_eff][next_sta_eff]; + if (!chg_eff.enable) + return; for (x_pv_game_stage_effect_auth_3d& i : chg_eff.auth_3d) { int32_t& id = i.id; @@ -2598,17 +2662,16 @@ bool x_pv_game_stage::set_change_effect_frame(float_t frame) { } for (x_pv_game_stage_effect_glitter& i : chg_eff.glitter) { - if (i.name.hash == hash_murmurhash_empty) + if (i.name.hash_murmurhash == hash_murmurhash_empty) continue; - i.scene_counter = Glitter::glt_particle_manager->LoadSceneEffect(i.name.hash, i.name.c_str()); + i.scene_counter = Glitter::glt_particle_manager->LoadSceneEffect(i.name.hash_murmurhash, i.name.c_str()); if (!i.scene_counter) continue; Glitter::glt_particle_manager->SetSceneFrameRate(i.scene_counter, &bpm_frame_rate_control); Glitter::glt_particle_manager->SetSceneEffectReqFrame(i.scene_counter, frame); } - return true; } void x_pv_game_stage::set_stage_effect(int32_t stage_effect) { @@ -2685,7 +2748,7 @@ void x_pv_game_stage::set_stage_effect_glitter_frame(int32_t stage_effect, float std::vector& glitter = effect[stage_effect - 1ULL].glitter; for (x_pv_game_stage_effect_glitter& i : glitter) { - i.scene_counter = Glitter::glt_particle_manager->LoadSceneEffect(i.name.hash, i.name.c_str()); + i.scene_counter = Glitter::glt_particle_manager->LoadSceneEffect(i.name.hash_murmurhash, i.name.c_str()); if (!i.scene_counter) continue; @@ -2797,18 +2860,17 @@ void x_pv_game_stage::unload() { if (!stage_resource || !stage_id) return; - for (x_pv_game_stage_effect& i : effect) { - for (x_pv_game_stage_effect_auth_3d& j : i.auth_3d) { - auth_3d_data_unload_id(j.id, rctx_ptr); - j.id = -1; - } + for (std::pair i : auth_3d_ids) + auth_3d_data_unload_id(i.second, rctx_ptr); + auth_3d_ids.clear(); + + for (x_pv_game_stage_effect& i : effect) for (x_pv_game_stage_effect_glitter& j : i.glitter) if (j.scene_counter) { Glitter::glt_particle_manager->FreeSceneEffect(j.scene_counter, false); j.scene_counter = 0; } - } if (stage_effect_transition_state == 1) stop_stage_change_effect(); @@ -2816,11 +2878,6 @@ void x_pv_game_stage::unload() { for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++) for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++) { x_pv_game_stage_change_effect& chg_eff = change_effect[i][j]; - for (x_pv_game_stage_effect_auth_3d& k : chg_eff.auth_3d) { - auth_3d_data_unload_id(k.id, rctx_ptr); - k.id = -1; - } - for (x_pv_game_stage_effect_glitter& k : chg_eff.glitter) if (k.scene_counter) { Glitter::glt_particle_manager->FreeSceneEffect(k.scene_counter, false); @@ -2843,9 +2900,9 @@ void x_pv_game_stage::unload() { Glitter::glt_particle_manager->UnloadEffectGroup(i); } - + for (string_hash& i : stage_auth_3d) - auth_3d_data_unload_category(i.hash); + auth_3d_data_unload_category(i.hash_murmurhash); delete stage_resource; stage_resource = 0; @@ -2884,6 +2941,31 @@ static bool img_write = false; FILE* pipe; #endif +#if DOF_BAKE +static void a3da_key_rev(a3da_key& k, std::vector& values_src) { + std::vector value; + int32_t type = interpolate_chs_reverse_sequence(values_src, value); + + k = {}; + switch (type) { + case 0: + default: + k.type = A3DA_KEY_NONE; + return; + case 1: + k.value = value[0].value; + k.type = A3DA_KEY_STATIC; + break; + case 2: + break; + } + + k.type = A3DA_KEY_HERMITE; + k.keys = value; + k.max_frame = (float_t)(values_src.size() + 1); +} +#endif + bool x_pv_game::Ctrl() { if (state_old == 20) ctrl((float_t)((frame_float + get_delta_frame()) * (1.0 / 60.0)), get_delta_frame() * (float_t)(1.0 / 60.0)); @@ -2919,6 +3001,8 @@ bool x_pv_game::Ctrl() { if (wait_load) break; + stage_data.load(stage_id, &field_71994, false); + for (int32_t i = 0; i < pv_count; i++) { x_pv_game_data& pv_data = this->pv_data[i]; @@ -2946,8 +3030,6 @@ bool x_pv_game::Ctrl() { } } - stage_data.load(stage_id, &field_71994, false); - state_old = 3; } break; case 3: { @@ -3020,7 +3102,7 @@ bool x_pv_game::Ctrl() { { data_struct* x_data = &data_list[DATA_X]; - dsc dscouth; + dsc dsc_mouth; dsc dsc_scene; dsc dsc_system; dsc dsc_easy; @@ -3034,9 +3116,9 @@ bool x_pv_game::Ctrl() { x_data->load_file(&dsc_common_farc, path_buf, file_buf, farc::load_file); sprintf_s(file_buf, sizeof(file_buf), "pv_%03d_mouth.dsc", pv_data[pv_index].pv_id); - farc_file* dscouth_ff = dsc_common_farc.read_file(file_buf); - if (dscouth_ff) - dscouth.parse(dscouth_ff->data, dscouth_ff->size, DSC_X); + farc_file* dsc_mouth_ff = dsc_common_farc.read_file(file_buf); + if (dsc_mouth_ff) + dsc_mouth.parse(dsc_mouth_ff->data, dsc_mouth_ff->size, DSC_X); sprintf_s(file_buf, sizeof(file_buf), "pv_%03d_scene.dsc", pv_data[pv_index].pv_id); farc_file* dsc_scene_ff = dsc_common_farc.read_file(file_buf); @@ -3052,7 +3134,74 @@ bool x_pv_game::Ctrl() { dsc_easy.type = DSC_X; x_data->load_file(&dsc_easy, path_buf, file_buf, dsc::load_file); - dsc_data.dsc.merge(4, &dscouth, &dsc_scene, &dsc_system, &dsc_easy); + /*if (pv_id == 826) { + dsc dsc_hand_keys[5]; + + char file_buf[0x200]; + for (int32_t i = 2; i <= 6; i++) { + stream s; + sprintf_s(file_buf, sizeof(file_buf), "pv_826_hand_%d.txt", i); + s.open(file_buf, "rb"); + size_t length = s.length; + uint8_t* data = force_malloc_s(uint8_t, length); + s.read(data, length); + s.close(); + + dsc& d = dsc_hand_keys[i - 2]; + d.parse_text(data, length, DSC_X); + d.signature = 0x13120420; + free_def(data); + + { + int32_t hand_l_time = -1; + int32_t hand_l_id = -1; + int32_t hand_l_duration = -1; + ::dsc_data* hand_l_data = 0; + int32_t hand_r_time = -1; + int32_t hand_r_id = -1; + int32_t hand_r_duration = -1; + ::dsc_data* hand_r_data = 0; + int32_t time = -1; + for (::dsc_data& j : d.data) { + if (j.func == DSC_X_END) + break; + + uint32_t* data = d.get_func_data(&j); + switch (j.func) { + case DSC_X_TIME: + time = (int32_t)data[0]; + break; + case DSC_X_HAND_ANIM: { + if (data[1] == 0) { + if (hand_l_time > -1 && hand_l_duration > time - hand_l_time) + data[3] = (time - hand_l_time) / 100; + + hand_l_time = time; + hand_l_id = (int32_t)data[2]; + hand_l_duration = (int32_t)data[3] * 100; + hand_l_data = &j; + } + if (data[1] == 1) { + if (hand_r_time > -1 && hand_r_duration > time - hand_r_time) + data[3] = (time - hand_r_time) / 100; + + hand_r_time = time; + hand_r_id = (int32_t)data[2]; + hand_r_duration = (int32_t)data[3] * 100; + hand_r_data = &j; + } + } break; + } + } + } + } + + dsc_data.dsc.merge(9, &dsc_mouth, &dsc_scene, &dsc_system, &dsc_easy, + &dsc_hand_keys[0], &dsc_hand_keys[1], &dsc_hand_keys[2], &dsc_hand_keys[3], dsc_hand_keys[4]); + } + else + dsc_data.dsc.merge(4, &dsc_mouth, &dsc_scene, &dsc_system, &dsc_easy);*/ + dsc_data.dsc.merge(4, &dsc_mouth, &dsc_scene, &dsc_system, &dsc_easy); struct miku_state { bool disp; @@ -3073,6 +3222,10 @@ bool x_pv_game::Ctrl() { x_pv_bar_beat_data* bar_beat_data = 0; int32_t beat_counter = 0; + /*std::vector> miku_disp; + std::vector> set_motion; + std::vector> set_playdata;*/ + int32_t time = -1; int32_t frame = -1; for (::dsc_data& i : dsc_data.dsc.data) { @@ -3093,16 +3246,21 @@ bool x_pv_game::Ctrl() { state[chara_id].disp = (int32_t)data[1] == 1; if (state[chara_id].disp) state[chara_id].disp_time = time; + //miku_disp.push_back({ time, i.data_offset }); } break; case DSC_X_SET_MOTION: { int32_t chara_id = (int32_t)data[0]; state[chara_id].set_motion_time = time; state[chara_id].set_motion_data_offset = i.data_offset; + //set_motion.push_back({ time, i.data_offset }); } break; + /*case DSC_X_SET_PLAYDATA: { + set_playdata.push_back({ time, i.data_offset }); + } break;*/ } } - if (state_vec.size()) { + if (state_vec.size()/* || miku_disp.size() || set_motion.size() || set_playdata.size()*/) { int32_t time = -1; for (miku_state& i : state_vec) { if (i.disp_time != time) { @@ -3117,6 +3275,61 @@ bool x_pv_game::Ctrl() { uint32_t* data = dsc_data.dsc.data_buffer.data() + i.set_motion_data_offset; memcpy(new_data, data, sizeof(uint32_t) * dsc_x_get_func_length(DSC_X_SET_MOTION)); } + + /*time = -1; + for (std::pair& i : miku_disp) { + if (i.first != time) { + uint32_t* data = dsc_m.add_func(dsc_x_get_func_name(DSC_X_TIME), + DSC_X_TIME, dsc_x_get_func_length(DSC_X_TIME)); + data[0] = i.first; + time = i.first; + } + + for (int32_t j = 1; j < 6; j++) { + uint32_t* new_data = dsc_m.add_func(dsc_x_get_func_name(DSC_X_MIKU_DISP), + DSC_X_MIKU_DISP, dsc_x_get_func_length(DSC_X_MIKU_DISP)); + uint32_t* data = dsc_m.data_buffer.data() + i.second; + memcpy(new_data, data, sizeof(uint32_t) * dsc_x_get_func_length(DSC_X_MIKU_DISP)); + new_data[0] = j; + } + } + + time = -1; + for (std::pair& i : set_motion) { + if (i.first != time) { + uint32_t* data = dsc_m.add_func(dsc_x_get_func_name(DSC_X_TIME), + DSC_X_TIME, dsc_x_get_func_length(DSC_X_TIME)); + data[0] = i.first; + time = i.first; + } + + for (int32_t j = 1; j < 6; j++) { + uint32_t* new_data = dsc_m.add_func(dsc_x_get_func_name(DSC_X_SET_MOTION), + DSC_X_SET_MOTION, dsc_x_get_func_length(DSC_X_SET_MOTION)); + uint32_t* data = dsc_m.data_buffer.data() + i.second; + memcpy(new_data, data, sizeof(uint32_t) * dsc_x_get_func_length(DSC_X_SET_MOTION)); + new_data[0] = j; + } + } + + time = -1; + for (std::pair& i : set_playdata) { + if (i.first != time) { + uint32_t* data = dsc_m.add_func(dsc_x_get_func_name(DSC_X_TIME), + DSC_X_TIME, dsc_x_get_func_length(DSC_X_TIME)); + data[0] = i.first; + time = i.first; + } + + for (int32_t j = 1; j < 6; j++) { + uint32_t* new_data = dsc_m.add_func(dsc_x_get_func_name(DSC_X_SET_PLAYDATA), + DSC_X_SET_PLAYDATA, dsc_x_get_func_length(DSC_X_SET_PLAYDATA)); + uint32_t* data = dsc_m.data_buffer.data() + i.second; + memcpy(new_data, data, sizeof(uint32_t) * dsc_x_get_func_length(DSC_X_SET_PLAYDATA)); + new_data[0] = j; + } + }*/ + dsc_data.dsc.rebuild(); } @@ -3127,7 +3340,7 @@ bool x_pv_game::Ctrl() { stream s; s.open(file_buf, "wb"); s.write(data, size); - free(data);*/ + free_def(data);*/ } pv_expression_array_reset(); @@ -3240,6 +3453,7 @@ bool x_pv_game::Ctrl() { pause = true; state_old = 20; + //sound_work_release_se("load01_2", false); } break; case 20: { float_t delta_frame = get_delta_frame(); @@ -3264,6 +3478,75 @@ bool x_pv_game::Ctrl() { fflush(pipe); _pclose(pipe); #endif + + for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) + pv_expression_array_reset_motion(i); + +#if DOF_BAKE + { + x_pv_game_data& pv_data = this->pv_data[pv_index]; + + data_struct* x_data = &data_list[DATA_X]; + + char buf[0x200]; + sprintf_s(buf, sizeof(buf), "CAMPV%03d", pv_data.pv_id); + + farc* f = new farc; + x_data->load_file(f, "root+/auth_3d/", hash_utf8_murmurhash(buf), ".farc", farc::load_file); + + if ((pv_data.pv_id % 100) >= 25 && (pv_data.pv_id % 100) <= 30 + && stage_data.stage_id >= 25 && stage_data.stage_id <= 30) + sprintf_s(buf, sizeof(buf), "CAMPV%03d_100.a3da", pv_data.pv_id); + else + sprintf_s(buf, sizeof(buf), "CAMPV%03d_BASE.a3da", pv_data.pv_id); + + a3da a; + farc_file* ff = f->read_file(buf); + if (ff) + a.read(ff->data, ff->size); + delete f; + + if ((pv_data.pv_id % 100) >= 25 && (pv_data.pv_id % 100) <= 30 + && stage_data.stage_id >= 25 && stage_data.stage_id <= 30) + sprintf_s(buf, sizeof(buf), "DOF\\auth_3d\\CAMPV%03d_100", pv_data.pv_id); + else + sprintf_s(buf, sizeof(buf), "DOF\\auth_3d\\CAMPV%03d_BASE", pv_data.pv_id); + + a.ready = true; + a.compressed = true; + a.format = A3DA_FORMAT_AFT; + a.dof = {}; + a.dof.has_dof = true; + + a3da_key_rev(a.dof.model_transform.translation.x, dof_cam_data.position_x); + a3da_key_rev(a.dof.model_transform.translation.y, dof_cam_data.position_y); + a3da_key_rev(a.dof.model_transform.translation.z, dof_cam_data.position_z); + a.dof.model_transform.translation.x.raw_data = true; + a.dof.model_transform.translation.y.raw_data = true; + a.dof.model_transform.translation.z.raw_data = true; + a3da_key_rev(a.dof.model_transform.scale.x, dof_cam_data.focus_range); + a3da_key_rev(a.dof.model_transform.rotation.x, dof_cam_data.fuzzing_range); + a3da_key_rev(a.dof.model_transform.rotation.y, dof_cam_data.ratio); + + a3da_key& rot_z = a.dof.model_transform.rotation.z; + if (dof_cam_data.enable_frame.size() > 1) { + rot_z.type = A3DA_KEY_HOLD; + rot_z.keys.reserve(dof_cam_data.enable_frame.size()); + for (std::pair& i : dof_cam_data.enable_frame) + rot_z.keys.push_back({ (float_t)i.first, i.second ? 1.00051f : 0.0f }); + rot_z.max_frame = a.play_control.size; + } + else if (dof_cam_data.enable_frame.size()) { + rot_z.type = A3DA_KEY_STATIC; + rot_z.value = dof_cam_data.enable_frame[0].second ? 1.00051f : 0.0f; + } + else + rot_z.type = A3DA_KEY_NONE; + + a.write(buf); + } +#endif + unload(); state_old = 22; } break; @@ -3278,94 +3561,10 @@ bool x_pv_game::Ctrl() { return false; } -#if DOF_BAKE -static void a3da_key_rev(a3da_key& k, std::vector& values_src) { - std::vector value; - int32_t type = interpolate_chs_reverse_sequence(values_src, value); - - k = {}; - switch (type) { - case 0: - default: - k.type = A3DA_KEY_NONE; - return; - case 1: - k.value = value[0].value; - k.type = A3DA_KEY_STATIC; - break; - case 2: - break; - } - - k.type = A3DA_KEY_HERMITE; - k.keys = value; - k.max_frame = (float_t)(values_src.size() + 1); -} -#endif - bool x_pv_game::Dest() { -#if DOF_BAKE - { - data_struct* x_data = &data_list[DATA_X]; + if (!Unload()) + return false; - char buf[0x200]; - sprintf_s(buf, sizeof(buf), "CAMPV%03d", pv_data.pv_id); - - farc* f = new farc; - x_data->load_file(f, "root+/auth_3d/", hash_utf8_murmurhash(buf), ".farc", farc::load_file); - - if ((pv_data.pv_id % 100) >= 25 && (pv_data.pv_id % 100) <= 30 && stage_data.stage_id >= 25 && stage_data.stage_id <= 30) - sprintf_s(buf, sizeof(buf), "CAMPV%03d_100.a3da", pv_data.pv_id); - else - sprintf_s(buf, sizeof(buf), "CAMPV%03d_BASE.a3da", pv_data.pv_id); - - a3da a; - farc_file* ff = f->read_file(buf); - if (ff) - a.read(ff->data, ff->size); - delete f; - - if ((pv_data.pv_id % 100) >= 25 && (pv_data.pv_id % 100) <= 30 && stage_data.stage_id >= 25 && stage_data.stage_id <= 30) - sprintf_s(buf, sizeof(buf), "DOF\\auth_3d\\CAMPV%03d_100", pv_data.pv_id); - else - sprintf_s(buf, sizeof(buf), "DOF\\auth_3d\\CAMPV%03d_BASE", pv_data.pv_id); - - a.ready = true; - a.compressed = true; - a.format = A3DA_FORMAT_AFT; - a.dof = {}; - a.dof.has_dof = true; - - a3da_key_rev(a.dof.model_transform.translation.x, dof_cam_data.position_x); - a3da_key_rev(a.dof.model_transform.translation.y, dof_cam_data.position_y); - a3da_key_rev(a.dof.model_transform.translation.z, dof_cam_data.position_z); - a.dof.model_transform.translation.x.raw_data = true; - a.dof.model_transform.translation.y.raw_data = true; - a.dof.model_transform.translation.z.raw_data = true; - a3da_key_rev(a.dof.model_transform.scale.x, dof_cam_data.focus_range); - a3da_key_rev(a.dof.model_transform.rotation.x, dof_cam_data.fuzzing_range); - a3da_key_rev(a.dof.model_transform.rotation.y, dof_cam_data.ratio); - - a3da_key& rot_z = a.dof.model_transform.rotation.z; - if (dof_cam_data.enable_frame.size() > 1) { - rot_z.type = A3DA_KEY_HOLD; - rot_z.keys.reserve(dof_cam_data.enable_frame.size()); - for (std::pair& i : dof_cam_data.enable_frame) - rot_z.keys.push_back({ (float_t)i.first, i.second ? 1.00051f : 0.0f }); - rot_z.max_frame = a.play_control.size; - } - else if (dof_cam_data.enable_frame.size()) { - rot_z.type = A3DA_KEY_STATIC; - rot_z.value = dof_cam_data.enable_frame[0].second ? 1.00051f : 0.0f; - } - else - rot_z.type = A3DA_KEY_NONE; - - a.write(buf); - } -#endif - - Unload(); task_rob_manager_free_task(); light_param_data_storage_data_reset(); @@ -3453,6 +3652,45 @@ void x_pv_game::Basic() { extern float_t frame_speed; frame_speed = pause ? 0.0f : 1.0f; + /*if (get_delta_frame() != 0.0f && frame > 0) + for (auto& i : effchrpv_auth_3d_rob_mot_ids) { + rob_chara* rob_chr = rob_chara_array_get(rob_chara_ids[i.first]); + x_pv_game_a3da_to_mot& a2m = i.second; + + rob_chara_bone_data* rob_bone_data = rob_chr->bone_data; + + bone_database_skeleton_type skeleton_type = rob_bone_data->base_skeleton_type; + motion_blend_mot* mot = rob_bone_data->motion_loaded.front(); + std::vector* bones = &mot->bone_data.bones; + std::vector* bone_indices = &mot->bone_data.bone_indices; + + bone_data* bones_data = bones->data(); + for (uint16_t& i : *bone_indices) { + bone_data* data = &bones_data[i]; + ::motion_bone_index motion_bone_index = (::motion_bone_index)data->motion_bone_index; + if (motion_bone_index >= MOTION_BONE_N_HITO_L_EX + && motion_bone_index <= MOTION_BONE_NL_OYA_C_L_WJ) { + auto elem = a2m.bone_keys.find(motion_bone_index); + if (elem == a2m.bone_keys.end()) + elem = a2m.bone_keys.insert({ motion_bone_index, {} }).first; + + elem->second.x.push_back(data->rotation.x); + elem->second.y.push_back(data->rotation.y); + elem->second.z.push_back(data->rotation.z); + } + else if (motion_bone_index >= MOTION_BONE_N_HITO_R_EX + && motion_bone_index <= MOTION_BONE_NL_OYA_C_R_WJ) { + auto elem = a2m.bone_keys.find(motion_bone_index); + if (elem == a2m.bone_keys.end()) + elem = a2m.bone_keys.insert({ motion_bone_index, {} }).first; + + elem->second.x.push_back(data->rotation.x); + elem->second.y.push_back(data->rotation.y); + elem->second.z.push_back(data->rotation.z); + } + } + }*/ + #if BAKE_VIDEO if (img_write && frame_prev != frame) { texture* rend_texture = rctx_ptr->post_process.rend_texture.color_texture; @@ -3678,9 +3916,8 @@ void x_pv_game::Load(int32_t pv_id, int32_t stage_id, ::chara_index charas[6], i i.shrink_to_fit(); } - //pv_auth_3d_chara_count.clear(); - Glitter::glt_particle_manager->draw_all = false; + //sound_work_play_se(1, "load01_2", 1.0f); } mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, @@ -3754,7 +3991,35 @@ mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, } } -/*bool mot_write_motion(void* data, const char* path, const char* file, uint32_t hash) { +/*static void fix_rotation(std::vector& vec) { + if (vec.size() < 2) + return; + + const float_t half_pi = (float_t)(M_PI / 2.0); + + int32_t curr_rot = 0; + float_t rot_fix = 0.0f; + float_t rot_prev = vec.data()[0]; + float_t* i_begin = vec.data() + 1; + float_t* i_end = vec.data() + vec.size(); + for (float_t* i = i_begin; i != i_end; i++) { + float_t rot = *i; + if (rot < -half_pi && rot_prev > half_pi && fabsf(rot - rot_prev) > half_pi) { + curr_rot++; + rot_fix = (float_t)(M_PI * 2.0 * (double_t)curr_rot); + } + else if (rot > half_pi && rot_prev < -half_pi && fabsf(rot - rot_prev) > half_pi) { + curr_rot--; + rot_fix = (float_t)(M_PI * 2.0 * (double_t)curr_rot); + } + + if (curr_rot) + *i = rot + rot_fix; + rot_prev = rot; + } +} + +bool mot_write_motion(void* data, const char* path, const char* file, uint32_t hash) { x_pv_game* xpvgm = (x_pv_game*)data; data_struct* aft_data = &data_list[DATA_AFT]; @@ -3762,7 +4027,7 @@ mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, motion_database* aft_mot_db = &aft_data->data_ft.mot_db; char buf[0x200]; - sprintf_s(buf, sizeof(buf), "PV%03d", xpvgm->pv_data[xpvgm->pv_index].pv_id); + sprintf_s(buf, sizeof(buf), "PV%03d", xpvgm->pv_id); motion_set_info* set_info = aft_mot_db->get_motion_set_by_name(buf); if (!set_info) return true; @@ -3789,7 +4054,7 @@ mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, } for (auto& i : xpvgm->effchrpv_auth_3d_rob_mot_ids) { - char buf[0x200]; + char buf[0x100]; sprintf_s(buf, sizeof(buf), "PV826_OST_P%d_00", i.first + 1); int32_t motion_id = aft_mot_db->get_motion_id(buf); @@ -3832,10 +4097,16 @@ mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, if (elem != a2m.bone_keys.end()) { x_pv_game_a3da_to_mot_keys& keys = elem->second; + if (bone->type == BONE_DATABASE_BONE_ROTATION) { + fix_rotation(keys.x); + fix_rotation(keys.y); + fix_rotation(keys.z); + } + mot_key_set_data& key_set_data_x = mot_data->key_set[key_set_offset]; key_set_data_x.frames.clear(); key_set_data_x.values.clear(); - key_set_data_x.type = mot_fit_keys_into_curve(keys.x, + key_set_data_x.type = mot_set::fit_keys_into_curve(keys.x, key_set_data_x.frames, key_set_data_x.values); key_set_data_x.keys_count = (uint16_t)key_set_data_x.frames.size(); key_set_data_x.data_type = MOT_KEY_SET_DATA_F32; @@ -3843,7 +4114,7 @@ mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, mot_key_set_data& key_set_data_y = mot_data->key_set[key_set_offset + 1]; key_set_data_y.frames.clear(); key_set_data_y.values.clear(); - key_set_data_y.type = mot_fit_keys_into_curve(keys.y, + key_set_data_y.type = mot_set::fit_keys_into_curve(keys.y, key_set_data_y.frames, key_set_data_y.values); key_set_data_y.keys_count = (uint16_t)key_set_data_y.frames.size(); key_set_data_y.data_type = MOT_KEY_SET_DATA_F32; @@ -3851,7 +4122,7 @@ mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, mot_key_set_data& key_set_data_z = mot_data->key_set[key_set_offset + 2]; key_set_data_z.frames.clear(); key_set_data_z.values.clear(); - key_set_data_z.type = mot_fit_keys_into_curve(keys.z, + key_set_data_z.type = mot_set::fit_keys_into_curve(keys.z, key_set_data_z.frames, key_set_data_z.values); key_set_data_z.keys_count = (uint16_t)key_set_data_z.frames.size(); key_set_data_z.data_type = MOT_KEY_SET_DATA_F32; @@ -3861,10 +4132,14 @@ mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, if (elem != a2m.sec_bone_keys.end()) { x_pv_game_a3da_to_mot_keys& keys = elem->second; + fix_rotation(keys.x); + fix_rotation(keys.y); + fix_rotation(keys.z); + mot_key_set_data& key_set_data_x = mot_data->key_set[key_set_offset + 3]; key_set_data_x.frames.clear(); key_set_data_x.values.clear(); - key_set_data_x.type = mot_fit_keys_into_curve(keys.x, + key_set_data_x.type = mot_set::fit_keys_into_curve(keys.x, key_set_data_x.frames, key_set_data_x.values); key_set_data_x.keys_count = (uint16_t)key_set_data_x.frames.size(); key_set_data_x.data_type = MOT_KEY_SET_DATA_F32; @@ -3872,7 +4147,7 @@ mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, mot_key_set_data& key_set_data_y = mot_data->key_set[key_set_offset + 4]; key_set_data_y.frames.clear(); key_set_data_y.values.clear(); - key_set_data_y.type = mot_fit_keys_into_curve(keys.y, + key_set_data_y.type = mot_set::fit_keys_into_curve(keys.y, key_set_data_y.frames, key_set_data_y.values); key_set_data_y.keys_count = (uint16_t)key_set_data_y.frames.size(); key_set_data_y.data_type = MOT_KEY_SET_DATA_F32; @@ -3880,7 +4155,7 @@ mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, mot_key_set_data& key_set_data_z = mot_data->key_set[key_set_offset + 5]; key_set_data_z.frames.clear(); key_set_data_z.values.clear(); - key_set_data_z.type = mot_fit_keys_into_curve(keys.z, + key_set_data_z.type = mot_set::fit_keys_into_curve(keys.z, key_set_data_z.frames, key_set_data_z.values); key_set_data_z.keys_count = (uint16_t)key_set_data_z.frames.size(); key_set_data_z.data_type = MOT_KEY_SET_DATA_F32; @@ -3955,8 +4230,45 @@ mot_key_set_type mot_fit_keys_into_curve(std::vector& values_src, return true; }*/ -void x_pv_game::Unload() { - /*{ +bool x_pv_game::Unload() { + pv_osage_manager_array_set_not_reset_true(); + if (pv_osage_manager_array_get_disp()) + return false; + + /*if (pv_data[pv_index].pv_id == 826) { + for (auto& i : effchrpv_auth_3d_rob_mot_ids) { + rob_chara* rob_chr = rob_chara_array_get(rob_chara_ids[i.first]); + x_pv_game_a3da_to_mot& a2m = i.second; + + bone_node* node = rob_chr->bone_data->nodes.data(); + + for (int32_t j = MOTION_BONE_N_HITO_L_EX; j <= MOTION_BONE_NL_OYA_C_L_WJ; j++) { + ::motion_bone_index motion_bone_index = (::motion_bone_index)j; + + auto elem = a2m.bone_keys.find(motion_bone_index); + if (elem == a2m.bone_keys.end()) + elem = a2m.bone_keys.insert({ motion_bone_index, {} }).first; + + vec3& rotation = node[j - MOTION_BONE_N_HITO_L_EX + ROB_BONE_N_HITO_L_EX].exp_data.rotation; + elem->second.x.push_back(rotation.x); + elem->second.y.push_back(rotation.y); + elem->second.z.push_back(rotation.z); + } + + for (int32_t j = MOTION_BONE_N_HITO_R_EX; j <= MOTION_BONE_NL_OYA_C_R_WJ; j++) { + ::motion_bone_index motion_bone_index = (::motion_bone_index)j; + + auto elem = a2m.bone_keys.find(motion_bone_index); + if (elem == a2m.bone_keys.end()) + elem = a2m.bone_keys.insert({ motion_bone_index, {} }).first; + + vec3& rotation = node[j - MOTION_BONE_N_HITO_R_EX + ROB_BONE_N_HITO_R_EX].exp_data.rotation; + elem->second.x.push_back(rotation.x); + elem->second.y.push_back(rotation.y); + elem->second.z.push_back(rotation.z); + } + } + data_struct* aft_data = &data_list[DATA_AFT]; motion_database* aft_mot_db = &aft_data->data_ft.mot_db; @@ -3972,9 +4284,6 @@ void x_pv_game::Unload() { data_struct* aft_data = &data_list[DATA_AFT]; motion_database* aft_mot_db = &aft_data->data_ft.mot_db; - for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) - pv_expression_array_reset_motion(i); - pv_param::post_process_data_clear_data(); char buf[0x200]; @@ -4003,12 +4312,6 @@ void x_pv_game::Unload() { light_category.clear(); light_category.shrink_to_fit(); - /*for (uint32_t& i : objset_load) - object_storage_unload_set(i);*/ - - /*objset_load.clear(); - objset_load.shrink_to_fit();*/ - for (int32_t i = 0; i < pv_count; i++) pv_data[i].reset(); stage_data.reset(); @@ -4024,8 +4327,6 @@ void x_pv_game::Unload() { pv_data[pv_index].stage_effects.shrink_to_fit(); pv_data[pv_index].stage_effect_index = 0; - //pv_auth_3d_chara_count.clear(); - play = true; success = true; chara_id = 0; @@ -4047,6 +4348,7 @@ void x_pv_game::Unload() { Glitter::glt_particle_manager->draw_all = true; pv_param_task::post_process_task.SetDest(); + return true; } void x_pv_game::ctrl(float_t curr_time, float_t delta_time) { @@ -4151,7 +4453,7 @@ XPVGameSelector::XPVGameSelector() : charas(), modules(), start(), exit() { for (chara_index& i : charas) i = CHARA_MIKU; - + for (int32_t& i : modules) i = 0; } @@ -4185,73 +4487,73 @@ bool XPVGameSelector::Dest() { void XPVGameSelector::Window() { static const char* pv_names[] = { - "801. Strangers", - "802. Ai Dee", - "803. Streaming Heart", - "804. Babylon", - "805. The Lost One's Weeping", - "806. Slow Motion", - "807. Tale of the Deep-sea Lily", - "808. Love Trial", - "809. Love Song", - "810. The First Sound", - "811. LOL - lots of laugh -", - "812. Patchwork Staccato", - "813. Even a Kunoichi Needs Love", - "814. Calc.", - "815. A Single Red Leaf", - "816. Holy Lance Explosion Boy", - "817. Urotander, Underhanded Rangers", - "818. Humorous Dream of Mrs. Pumpkin", - "819. Solitary Envy", - "820. Raspberry * Monster", - "821. Brain Revolution Girl", - "822. Amazing Dolce", - "823. Name of the Sin", - "824. Satisfaction", - "825. Cute Medley - Idol Sounds", - "826. Beginning Medley - Primary Colors", - "827. Cool Medley - Cyber Rock Jam", - "828. Elegant Medley - Glossy Mixture", - "829. Quirky Medley - Giga-Remix", - "830. Ending Medley - Ultimate Exquisite Rampage", - "831. Sharing The World", - "832. Hand in Hand", + u8"801. Strangers", + u8"802. Ai Dee", + u8"803. Streaming Heart", + u8"804. Babylon", + u8"805. The Lost One's Weeping", + u8"806. Slow Motion", + u8"807. Tale of the Deep-sea Lily", + u8"808. Love Trial", + u8"809. Love Song", + u8"810. The First Sound", + u8"811. LOL - lots of laugh -", + u8"812. Patchwork Staccato", + u8"813. Even a Kunoichi Needs Love", + u8"814. Calc.", + u8"815. A Single Red Leaf", + u8"816. Holy Lance Explosion Boy", + u8"817. Urotander, Underhanded Rangers", + u8"818. Humorous Dream of Mrs. Pumpkin", + u8"819. Solitary Envy", + u8"820. Raspberry * Monster", + u8"821. Brain Revolution Girl", + u8"822. Amazing Dolce", + u8"823. Name of the Sin", + u8"824. Satisfaction", + u8"825. Cute Medley - Idol Sounds", + u8"826. Beginning Medley - Primary Colors", + u8"827. Cool Medley - Cyber Rock Jam", + u8"828. Elegant Medley - Glossy Mixture", + u8"829. Quirky Medley - Giga-Remix", + u8"830. Ending Medley - Ultimate Exquisite Rampage", + u8"831. Sharing The World", + u8"832. Hand in Hand", }; static const char* stage_names[] = { - "001. Nighttime Curb Stage", - "002. Digital Concert Stage", - "003. Secret Ruins Stage", - "004. Utopia Stage", - "005. Classroom Concert Stage", - "006. Capsule Room Stage", - "007. Deep Sea Stage", - "008. Verdict Stage", - "009. Sky Garden Stage", - "010. Musical Dawn Stage", - "011. Sweet Dreams Stage", - "012. Heart's Playroom Stage", - "013. Ninja Village Stage", - "014. Park of Promises Stage", - "015. Autumn Sakura Stage", - "016. Classy Lounge Stage", - "017. Secret Base Stage", - "018. Halloween Party Stage", - "019. Twilight Shrine Stage", - "020. Raspberry Stage", - "021. Cabaret Stage", - "022. Witch's House Stage", - "023. Lilies & Shadows Stage", - "024. Techno Club Stage", - "025. Cute Concert Hall", - "026. First Concert Hall", - "027. Cool Concert Hall", - "028. Elegant Concert Hall", - "029. Quirky Concert Hall", - "030. Ultimate Concert Hall", - "031. Highrise Stage", - "032. Mirai Concert Stage", + u8"001. Nighttime Curb Stage", + u8"002. Digital Concert Stage", + u8"003. Secret Ruins Stage", + u8"004. Utopia Stage", + u8"005. Classroom Concert Stage", + u8"006. Capsule Room Stage", + u8"007. Deep Sea Stage", + u8"008. Verdict Stage", + u8"009. Sky Garden Stage", + u8"010. Musical Dawn Stage", + u8"011. Sweet Dreams Stage", + u8"012. Heart's Playroom Stage", + u8"013. Ninja Village Stage", + u8"014. Park of Promises Stage", + u8"015. Autumn Sakura Stage", + u8"016. Classy Lounge Stage", + u8"017. Secret Base Stage", + u8"018. Halloween Party Stage", + u8"019. Twilight Shrine Stage", + u8"020. Raspberry Stage", + u8"021. Cabaret Stage", + u8"022. Witch's House Stage", + u8"023. Lilies & Shadows Stage", + u8"024. Techno Club Stage", + u8"025. Cute Concert Hall", + u8"026. First Concert Hall", + u8"027. Cool Concert Hall", + u8"028. Elegant Concert Hall", + u8"029. Quirky Concert Hall", + u8"030. Ultimate Concert Hall", + u8"031. Highrise Stage", + u8"032. Mirai Concert Stage", }; ImGuiIO& io = ImGui::GetIO(); @@ -4262,7 +4564,7 @@ void XPVGameSelector::Window() { float_t w = 400.0f; float_t h = (float_t)height; - h = min(h, 432.0f); + h = min_def(h, 432.0f); extern int32_t width; ImGui::SetNextWindowPos({ (float_t)width - w, 0.0f }, ImGuiCond_Always); @@ -4285,12 +4587,12 @@ void XPVGameSelector::Window() { } pv_id -= 801; - pv_id = max(pv_id, 0); + pv_id = max_def(pv_id, 0); ImGui::ColumnComboBox("PV", pv_names, 32, &pv_id, 0, false, &window_focus); pv_id += 801; stage_id--; - stage_id = max(stage_id, 0); + stage_id = max_def(stage_id, 0); ImGui::ColumnComboBox("Stage", stage_names, 32, &stage_id, 0, false, &window_focus); stage_id++; @@ -4344,15 +4646,28 @@ void XPVGameSelector::Window() { ImGui::End(); } -extern void x_pv_game_init() { +extern bool x_pv_game_init() { x_pv_game_ptr = new x_pv_game; + return true; } -extern void x_pv_game_free() { +extern bool x_pv_game_free() { if (x_pv_game_ptr) { + switch (x_pv_game_ptr->state_old) { + case 0: + break; + case 21: + case 22: + return false; + default: + x_pv_game_ptr->state_old = 21; + return false; + } + delete x_pv_game_ptr; x_pv_game_ptr = 0; } + return true; } #if DOF_BAKE @@ -4526,7 +4841,7 @@ static bool x_pv_game_dsc_process(x_pv_game* a1, int64_t curr_time) { rob_chr->bone_data->disable_eye_motion = i.disable_eye_motion; rob_chr->data.motion.step_data.step = i.frame_speed; if (v45) - pv_expression_array_set_motion(pv_data.exp_file.hash, a1->chara_id, i.motion_id); + pv_expression_array_set_motion(pv_data.exp_file.hash_murmurhash, a1->chara_id, i.motion_id); //if (!a1->pv_game->data.pv->disable_calc_motfrm_limit) sub_140122B60(a1, a1->chara_id, i.motion_index, i.dsc_time); } @@ -4674,7 +4989,7 @@ static bool x_pv_game_dsc_process(x_pv_game* a1, int64_t curr_time) { rob_chr->bone_data->disable_eye_motion = true; rob_chr->data.motion.step_data.step = set_motion.frame_speed; if (v84) - pv_expression_array_set_motion(pv_data.exp_file.hash, a1->chara_id, motion_id); + pv_expression_array_set_motion(pv_data.exp_file.hash_murmurhash, a1->chara_id, motion_id); //if (!a1->pv_game->data.pv->disable_calc_motfrm_limit) sub_140122B60(a1, a1->chara_id, motion_index, v56 ? v56->time : 0); } @@ -5159,7 +5474,7 @@ static bool x_pv_game_dsc_process(x_pv_game* a1, int64_t curr_time) { if (!rob_chr) break; - rob_chr->item_equip->wet = clamp(value, 0.0f, 1.0f); + rob_chr->item_equip->wet = clamp_def(value, 0.0f, 1.0f); } break; case DSC_X_LIGHT_ROT: { @@ -5784,21 +6099,13 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { auth_3d* auth = auth_3d_data_get_auth_3d(a2m.auth_3d_id); auth_3d_object_hrc* oh = &auth->object_hrc[0]; - - if (rob_chr->data.motion.motion_id == 0xC3) { - data_struct* aft_data = &data_list[DATA_AFT]; - bone_database* aft_bone_data = &aft_data->data_ft.bone_data; - motion_database* aft_mot_db = &aft_data->data_ft.mot_db; - - char buf[0x200]; - sprintf_s(buf, sizeof(buf), "PV826_OST_P%d_00", i.first + 1); - int32_t motion_id = aft_mot_db->get_motion_id(buf); - - rob_chr->set_motion_id(motion_id, 0.0f, - 0.0f, false, false, MOTION_BLEND_CROSS, aft_bone_data, aft_mot_db); - rob_chr->set_motion_reset_data(motion_id, 0.0f); - rob_chr->set_motion_skin_param(motion_id, 0.0f); - } + float_t auth_frame = auth->frame; + bool auth_frame_changed = auth->frame_changed; + bool auth_paused = auth->paused; + auth->frame = (float_t)xpvgm->frame_float; + auth->frame_changed = false; + auth->paused = true; + auth->ctrl(rctx_ptr); rob_chr->set_visibility(oh->node[0].model_transform.visible); @@ -5807,10 +6114,8 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { mot_key_set* key_set = mot->mot_key_data.mot.key_sets; vec3 data[2]; - mat4 mat; - data[0].x = oh->node[a2m.gblctr].model_transform.translation_value.x; + data[0] = oh->node[a2m.gblctr].model_transform.translation_value; data[0].y = oh->node[a2m.n_hara].model_transform.translation_value.y; - data[0].z = oh->node[a2m.gblctr].model_transform.translation_value.z; data[1] = vec3_null; set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_N_HARA_CP, key_set, data, 2); @@ -5827,10 +6132,9 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_N_HARA, key_set, data); - mat = oh->node[a2m.j_mune_wj].model_transform.mat; data[0] = { 0.0f, 0.945f, 0.0f }; - mat4_mult_vec3(&mat, &data[0], &data[1]); - mat4_get_translation(&mat, &data[0]); + mat4_mult_vec3(&oh->node[a2m.j_mune_wj].model_transform.mat, &data[0], &data[1]); + mat4_get_translation(&oh->node[a2m.j_mune_wj].model_transform.mat, &data[0]); vec3_add(data[0], data[1], data[0]); data[1] = vec3_null; set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, @@ -5844,17 +6148,17 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_KL_KUBI, key_set, data); - data[0] = oh->node[a2m.n_kao].model_transform.rotation_value; - data[0].z -= (float_t)M_PI; + data[0] = { (float_t)(M_PI / 2.0), 0.0f, -(float_t)M_PI }; set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_N_KAO, key_set, data); - mat = oh->node[a2m.j_kao_wj].model_transform.mat; data[0] = { 0.0f, 0.40f, 0.0f }; - mat4_mult_vec3(&mat, &data[0], &data[1]); - mat4_get_translation(&mat, &data[0]); + mat4_mult_vec3(&oh->node[a2m.j_kao_wj].model_transform.mat, &data[0], &data[1]); + mat4_get_translation(&oh->node[a2m.j_kao_wj].model_transform.mat, &data[0]); vec3_add(data[0], data[1], data[0]); - data[1] = vec3_null; + data[1] = oh->node[a2m.j_kao_wj].model_transform.rotation_value; + data[1].x = -data[1].x; + data[1].z = -data[1].z; set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_CL_KAO, key_set, data, 2); @@ -5876,10 +6180,7 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_N_WAKI_L, key_set, data); - data[1] = oh->node[a2m.j_waki_l_wj].model_transform.rotation_value; - data[0].x = data[1].x; - data[0].y = data[1].z; - data[0].z = -data[1].y; + data[0] = oh->node[a2m.j_waki_l_wj].model_transform.rotation_value; set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_KL_WAKI_L_WJ, key_set, data); @@ -5900,7 +6201,7 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { float_t pos_middle_dist; vec3_length(tl_up_kata_dir, pos_middle_dist); if (pos_middle_dist == 0.0f) { - mat = oh->node[a2m.j_kata_l_wj].model_transform.mat; + mat4& mat = oh->node[a2m.j_kata_l_wj].model_transform.mat; data[0] = { 0.0f, 0.3f, 0.0f }; mat4_mult_vec3(&mat, &data[0], &tl_up_kata_dir); } @@ -5910,16 +6211,14 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { vec3 tl_up_kata_pos; vec3_add(tl_up_kata_dir, pos_j_ude_l_wj, tl_up_kata_pos); - mat = oh->node[a2m.j_mune_b_wj].model_transform.mat; + mat4& mat = oh->node[a2m.j_mune_b_wj].model_transform.mat; mat4_mult_vec3_inv_trans(&mat, &tl_up_kata_pos, &data[0]); set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_TL_UP_KATA_L, key_set, data); } mat4_get_translation(&oh->node[a2m.j_te_l_wj].model_transform.mat, &data[0]); - data[1].x = -(float_t)(M_PI / 2.0); - data[1].y = -(float_t)(M_PI / 2.0); - data[1].z = -(float_t)(M_PI / 2.0); + data[1] = { -(float_t)(M_PI / 2.0), -(float_t)(M_PI / 2.0), -(float_t)(M_PI / 2.0) }; set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_C_KATA_L, key_set, data, 2); @@ -5931,10 +6230,7 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_N_WAKI_R, key_set, data); - data[1] = oh->node[a2m.j_waki_l_wj].model_transform.rotation_value; - data[0].x = data[1].x; - data[0].y = data[1].z; - data[0].z = data[1].y; + data[0] = oh->node[a2m.j_waki_l_wj].model_transform.rotation_value; set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_KL_WAKI_R_WJ, key_set, data); @@ -5955,7 +6251,7 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { float_t pos_middle_dist; vec3_length(tl_up_kata_dir, pos_middle_dist); if (pos_middle_dist == 0.0f) { - mat = oh->node[a2m.j_kata_r_wj].model_transform.mat; + mat4& mat = oh->node[a2m.j_kata_r_wj].model_transform.mat; data[0] = { 0.0f, 0.3f, 0.0f }; mat4_mult_vec3(&mat, &data[0], &tl_up_kata_dir); } @@ -5965,16 +6261,14 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { vec3 tl_up_kata_pos; vec3_add(tl_up_kata_dir, pos_j_ude_r_wj, tl_up_kata_pos); - mat = oh->node[a2m.j_mune_b_wj].model_transform.mat; + mat4& mat = oh->node[a2m.j_mune_b_wj].model_transform.mat; mat4_mult_vec3_inv_trans(&mat, &tl_up_kata_pos, &data[0]); set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_TL_UP_KATA_R, key_set, data); } mat4_get_translation(&oh->node[a2m.j_te_r_wj].model_transform.mat, &data[0]); - data[1].x = -(float_t)(M_PI / 2.0); - data[1].y = (float_t)(M_PI / 2.0); - data[1].z = (float_t)(M_PI / 2.0); + data[1] = { -(float_t)(M_PI / 2.0), (float_t)(M_PI / 2.0), (float_t)(M_PI / 2.0) }; set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_C_KATA_R, key_set, data, 2); @@ -5983,15 +6277,31 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { MOTION_BONE_KL_TE_R_WJ, key_set, data); mat4_get_translation(&oh->node[a2m.j_asi_l_wj].model_transform.mat, &data[0]); - data[1] = vec3_null; + data[0].y -= 0.033f; + if (data[0].y < 0.103f) + data[0].y = 0.103f; + data[1] = oh->node[a2m.j_momo_l_wj].model_transform.rotation_value; + data[1].z -= (float_t)(M_PI / 2.0); set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_CL_MOMO_L, key_set, data, 2); mat4_get_translation(&oh->node[a2m.j_asi_r_wj].model_transform.mat, &data[0]); - data[1] = vec3_null; + data[0].y -= 0.033f; + if (data[0].y < 0.103f) + data[0].y = 0.103f; + data[1] = oh->node[a2m.j_momo_r_wj].model_transform.rotation_value; + data[1].z -= (float_t)(M_PI / 2.0); set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_CL_MOMO_R, key_set, data, 2); + data[0] = oh->node[a2m.j_asi_l_wj].model_transform.rotation_value; + set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, + MOTION_BONE_KL_ASI_L_WJ_CO, key_set, data); + + data[0] = oh->node[a2m.j_asi_r_wj].model_transform.rotation_value; + set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, + MOTION_BONE_KL_ASI_R_WJ_CO, key_set, data); + data[0] = { 0.0491406508f, 0.0f, 0.0f }; set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_KL_AGO_WJ, key_set, data); @@ -5999,6 +6309,10 @@ static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) { data[0] = { 0.0f, 0.0331281610f, 0.0f }; set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys, MOTION_BONE_N_KUBI_WJ_EX, key_set, data); + + auth->frame = auth_frame; + auth->frame_changed = auth_frame_changed; + auth->paused = auth_paused; } }*/ @@ -6012,7 +6326,7 @@ static void pv_game_dsc_data_find_playdata_item_anim(x_pv_game* xpvgm, int32_t c if (chara_id < 0 || chara_id >= ROB_CHARA_COUNT) return; - x_pv_play_data* playdata = &xpvgm->playdata[chara_id]; + x_pv_play_data* playdata = &xpvgm->playdata[chara_id]; playdata->motion_data.set_item.clear(); int32_t pv_branch_mode = 0; diff --git a/src/ReDIVA/x_pv_game.hpp b/src/ReDIVA/x_pv_game.hpp index 5b08ecbd..21aaf431 100644 --- a/src/ReDIVA/x_pv_game.hpp +++ b/src/ReDIVA/x_pv_game.hpp @@ -493,6 +493,7 @@ struct x_pv_game_stage { object_database obj_db; texture_database tex_db; + std::map auth_3d_ids; x_pv_game_stage(); ~x_pv_game_stage(); @@ -504,7 +505,8 @@ struct x_pv_game_stage { void load_change_effect(int32_t curr_stage_effect, int32_t next_stage_effect); void reset(); void reset_stage_effect(); - bool set_change_effect_frame(float_t frame); + bool set_change_effect_frame_part_1(); + void set_change_effect_frame_part_2(float_t frame); void set_stage_effect(int32_t stage_effect); void set_stage_effect_auth_3d_frame(int32_t stage_effect, float_t frame); void set_stage_effect_glitter_frame(int32_t stage_effect, float_t frame); @@ -525,8 +527,6 @@ public: XPVFrameRateControl field_7198C; XPVFrameRateControl field_71994; - //std::vector objset_load; - int32_t state_old; int32_t frame; double_t frame_float; @@ -544,8 +544,6 @@ public: std::vector set_motion[ROB_CHARA_COUNT]; - //std::map> pv_auth_3d_chara_count; - bool play; bool success; int32_t chara_id; @@ -576,7 +574,7 @@ public: virtual void Window() override; void Load(int32_t pv_id, int32_t stage_id, chara_index charas[6], int32_t modules[6]); - void Unload(); + bool Unload(); void ctrl(float_t curr_time, float_t delta_time); void stop_current_pv(); @@ -604,6 +602,6 @@ public: extern x_pv_game* x_pv_game_ptr; extern XPVGameSelector x_pv_game_selector; -extern void x_pv_game_init(); -extern void x_pv_game_free(); +extern bool x_pv_game_init(); +extern bool x_pv_game_free(); #endif diff --git a/thirdparty.txt b/thirdparty.txt index 7fe73e69..cba936de 100644 --- a/thirdparty.txt +++ b/thirdparty.txt @@ -203,6 +203,8 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- +lodepng + Copyright (c) 2005-2018 Lode Vandevenne This software is provided 'as-is', without any express or implied @@ -223,3 +225,69 @@ freely, subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. + +------------------------------------------------------------------------------- + +libogg + +Copyright (c) 2002, Xiph.org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- + +libvorbis/libvorbisfile + +Copyright (c) 2002-2020 Xiph.org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.