From b56d85f95da7824065af520c27b879fff77960da Mon Sep 17 00:00:00 2001 From: kotofyt Date: Wed, 18 Mar 2026 18:41:28 +0200 Subject: [PATCH] improve rendering and physics --- external/GameNetworkingSockets | 2 +- external/SDL | 2 +- external/Vulkan-Headers | 2 +- external/Vulkan-Utility-Libraries | 2 +- external/VulkanMemoryAllocator | 2 +- external/cglm | 2 +- external/slang | 2 +- external/stb | 2 +- external/volk | 2 +- external/xtool | 2 +- funnyassets/maps/test/test.fmap | 7 ++-- funnyassets/maps/test/test0.fmesh_c | Bin 23808 -> 23808 bytes funnyassets/meshes/sphere.fmesh_c | Bin 0 -> 122880 bytes funnyassets/models/sphere.fmdl | 5 +++ funnyassets/physics/sphere.fpx | 4 ++ funnyassets/shaders/mesh_raster.shader | 10 +++-- game/client/assetmgr.cpp | 4 +- game/client/basemodelentity.cpp | 2 + game/client/game.cpp | 4 +- game/client/milmoba/player.cpp | 1 - game/client/worldrender.cpp | 54 +++++++++++++++---------- game/server/assetmgr.cpp | 18 ++++----- game/server/baseentity.cpp | 3 -- game/server/baseentity.h | 4 +- game/server/basemodelentity.h | 2 +- game/server/milmoba/player.cpp | 8 +++- game/server/milmoba/player.h | 4 +- game/server/physicsprop.cpp | 38 +++++++++++++---- game/server/physicsprop.h | 6 ++- game/server/worldsystem.cpp | 2 - rapier/build.cpp | 4 +- rapier/physics.cpp | 5 +++ rapier/physics.rs | 18 +++++---- 33 files changed, 141 insertions(+), 82 deletions(-) create mode 100644 funnyassets/meshes/sphere.fmesh_c create mode 100644 funnyassets/models/sphere.fmdl create mode 100644 funnyassets/physics/sphere.fpx diff --git a/external/GameNetworkingSockets b/external/GameNetworkingSockets index 517fff0..725e273 160000 --- a/external/GameNetworkingSockets +++ b/external/GameNetworkingSockets @@ -1 +1 @@ -Subproject commit 517fff0cf6866ba163f4f016b0ef28f365c06c05 +Subproject commit 725e273c7442bac7a8bc903c0b210b1c15c34d92 diff --git a/external/SDL b/external/SDL index 1d08131..7c11a8c 160000 --- a/external/SDL +++ b/external/SDL @@ -1 +1 @@ -Subproject commit 1d081314a89eb6bfd22bbc0224b604533ae6156b +Subproject commit 7c11a8cb9f66a2cac63f9a24ab2f49f6d4bf12a0 diff --git a/external/Vulkan-Headers b/external/Vulkan-Headers index 29184b9..2e0a6e6 160000 --- a/external/Vulkan-Headers +++ b/external/Vulkan-Headers @@ -1 +1 @@ -Subproject commit 29184b98984f6169a5e83e97557a77cff1e5b0ca +Subproject commit 2e0a6e699e35c9609bde2ca4abb0d380c0378639 diff --git a/external/Vulkan-Utility-Libraries b/external/Vulkan-Utility-Libraries index c15a1ac..4f4c0b6 160000 --- a/external/Vulkan-Utility-Libraries +++ b/external/Vulkan-Utility-Libraries @@ -1 +1 @@ -Subproject commit c15a1ac31670cb2ce61c235f070fb40ec6e42612 +Subproject commit 4f4c0b6c61223b703f1c753a404578d7d63932ad diff --git a/external/VulkanMemoryAllocator b/external/VulkanMemoryAllocator index b3cbbb4..f0969e9 160000 --- a/external/VulkanMemoryAllocator +++ b/external/VulkanMemoryAllocator @@ -1 +1 @@ -Subproject commit b3cbbb43ea3a506dffe10759e205a41c27c35ae2 +Subproject commit f0969e908b01104f66bec2f203103de2012354c9 diff --git a/external/cglm b/external/cglm index 83d5b2c..a886d6e 160000 --- a/external/cglm +++ b/external/cglm @@ -1 +1 @@ -Subproject commit 83d5b2c97378e61a4666825fd3a5548955c83add +Subproject commit a886d6e170292a1d534a7a2c0471be5953b16455 diff --git a/external/slang b/external/slang index f267cb7..5d775e2 160000 --- a/external/slang +++ b/external/slang @@ -1 +1 @@ -Subproject commit f267cb77a09b0f4cf083a9585bc1ddb3744c310a +Subproject commit 5d775e2829ceef5bd34ec89aa3eafa4968a74c8e diff --git a/external/stb b/external/stb index e6cd956..802cd45 160000 --- a/external/stb +++ b/external/stb @@ -1 +1 @@ -Subproject commit e6cd9561ea6dae43d41633797745789d142b691e +Subproject commit 802cd454f25469d3123e678af41364153c132c2a diff --git a/external/volk b/external/volk index e91ceff..d64d20b 160000 --- a/external/volk +++ b/external/volk @@ -1 +1 @@ -Subproject commit e91ceff7db05f92ac8b498c9631235a6a73566e2 +Subproject commit d64d20b4eaf2698296e085d9d9638c69af280e3e diff --git a/external/xtool b/external/xtool index f12a84e..22655f3 160000 --- a/external/xtool +++ b/external/xtool @@ -1 +1 @@ -Subproject commit f12a84e960fa9bced1249a8d233ab8eafca28f6f +Subproject commit 22655f3e70b87bef9be736e9625984e21bf8c697 diff --git a/funnyassets/maps/test/test.fmap b/funnyassets/maps/test/test.fmap index c965de8..151242e 100644 --- a/funnyassets/maps/test/test.fmap +++ b/funnyassets/maps/test/test.fmap @@ -2,13 +2,14 @@ { "classname": "prop_physics", "model": "game/core/maps/test/test0.fmdl", - "physics": "static" + "physics": "static", + "origin": [ 0, -10, 0 ] }, { "classname": "prop_physics", - "model": "game/core/models/cube.fmdl", + "model": "game/core/models/sphere.fmdl", "physics": "dynamic", - "origin": [ 0, 3, 0 ] + "origin": [ 0, -5, 0 ] } ] diff --git a/funnyassets/maps/test/test0.fmesh_c b/funnyassets/maps/test/test0.fmesh_c index ee7216bbda74df39a07c133b0813ebae19f48493..4db10977c4035387fae85d57171ed4550a79b584 100644 GIT binary patch literal 23808 zcmb7MU8ts28T}yeXX;`IMaN18BF3v>!l;Q}=e$R<=+3!mE($zRd0`+Eb!;kaKJstW z%%i4un$gZpP!JU&q0WcrJBM&Cg0LSG%Ics|7nUhF1a;G1&+|Qd?Pu?O-u)KL)jDgv z>sim*`};X3FaOE8t?#d|&u@6(o6D2Qsqk-OzWM6?vw8UU+^hF@mj`@3;9t7t-mS@G zE&NkFVDdA-k6&|dg0C6B!_NS3>9_c|1bzBbeRvBVyWnd%;RpYM3uezJ{sLww{Bb_u ze!emKEk5zJ;7{}=8)OW9kFRZo{3Gu37yrPqo0vcI1%7Hd-QO7f7N0o$i$3y&2g#rN zA#VGDf8z9);@N&=KI|4V!aw_>{zpX^8aW%I#*OTWb@ zF8-m9Y-0b3Q#_eJ^uwQztRDd{``OY@`dj65{&>H{{`~0pZCk71d_RBws^I-l z_!rNo^b7cx<$l={u)PsSH?RZXk8Q7p`^WI9JKtmUTYTX3r}~!fwR?^w&tKV^OazzR zz@ztfhvD!p{r2+#*ZFO}G5XA>&L<9ku^*Bj^gX^8_lJ11e2GI}aO@`L&;0>EAI@j{8LQvoD-M5}Z>sO-i|143^ZkXt@_ewL zz{`HN^jm!5@UQ*0{Cqw*zjZu2pV*&t%=aUnZ^5wRG5YLhozMB<&*wY4^2HwfhqqVz z;642F`2r7j2v>eK5_UL{p9}9d~`p=@oZ#l`72KS9M}GEKHHDw-_mdK6^B2~H`Vv^4V@48E6)e} z34BHJxB1||rQhNchkwyWKO|qD&vaKjJD{ThErzs2vv{qsijSMHbm9eaMv*ZcdE z;qWdQn?Icoxc1BD^ZD2HnQxs>9DL0`)%W<+-9M#2!Lgf|Klqw2o_Y`}sd~^=}vV^Z9^H z?ETTq@;6-bi~QJs;1z%1Bcqw|AKuv{m}iG4D z?=S8j;1z!CKXB#~=ZAM>G#jJe;xC2!hyKRxCw)Hk|7iPj{x~1-`u)TH>wZ)H7N0o# zo$lA;dcFJeExNP_P5UG{NVe1pZxf*<^K8C(Zd1j4afPEd=2OM_vaIMWq$DG{xSZLev5x3 z+&|=(`z4?INuN*r54OL;pUwx|&*$^6>oeavpE&sCem$<|+xBny(VyVhjqJ#9%?Ho# zi~DDcev7X-{EL2P{Xjn45Aom+Khwb$^%;uDvA?en?h>+`|+E$<)j zb$*=R`u#(^>?faJ*Jr=u{UB!_8Tt9a_w%26?ZM>t@88`5{>0&5b#H#^y=UKg_Z{8Y zD}RvSKNfuP`z`4oaQ=P}_;h~oy6Nn-Th4Ts+Ef5R~!`Ox>j zfA{kP_rHH1qmTaR@5k$W;_!b+{H6V1e#+1H@AKQc4BYY?<8Mg6#Rop*zvQpYFZ=K> zyIa3?=Ij;sYX5!y+RwDV*X=pB=ojW+nXg{|x!L<3|6$jkzDN2`{@!JKeM|Ykm&5z8 z$t2!?I2*D59}W7%RsTTHKXUpW>3>VV#ixJxEB%wt`SRzhKj8lSTE2>F|B>%4ns4ks z@tr=!t^d^DvG3PnKAa!V*Yjcdmd~&2>;14hUvc=~yPWrf`6)l&zt3-{2X6U|@i(O3 z;v2r3f5Vyo+Wdw~&vl=E=;gDU`|phXW&UOV-#mIay#GOeF@Hb*{9~V(9l7Ai?(u`C zGCuol`?39=USALV4SRp)`Vajx5m)^_=$}4#D)wLf)%9C^`Uk)CPd?|%pRfLb*ZZ%y z_8<9vQuB@dC%)0AxX%ar8`b`EKYBhaU)yg>zr|M^{&&P*+7IRje>;7?f1lrm;FjMQ ze?$5$zTvz1H=Oyb&0o4_ySwb`7tMb5Jo~RW_iOoLKToXhTl5q7{`r9y-#`1zmCt^seEj{u>qifxd)59w9`uQ;{%3>!!2@^4{txN5`1B8drGN4{U;2FdXFm4& zg?x!?|B>&dny>WV<9(mv$d@?u`)dEWA3YzIZ~6REAFm%neB$uGA^y^SFhBU)==1&i z{CdGHzcK!X^jm!3L;n5WpO)`W4A=96`_bQT!1?+Hd}W^g{hRUm{@cHPjN$Y3Pv4(F zKlG~$I}V?Jk0sB?-zUoR1w#kD{vC$ny+da>^3nN#`}xM`xA?^2PxR&4=qU6(F86oD zEkF9x``yl$;hHb}`}aR%^;>+!-QTau4xrEd5V!rnA94CiarOte&S(1>qu=5ahd<3X z)kprEPxph}z+;(j*yRL(~{pYeQ{zwCU+{`vgt z`s{DK9~__g#`^`&mwe0nYi)kvrO$QmI`N*_Z8zN|ub=+@_xa=XA^dIMroKMn{+-OP z2;2*T#y1LnAMY=FzP-LYu)VqzKKqA%svq*h9U-r;;dif_4@F${FADm%-gKAX^jFt! z@#!D@(m(l}FMq!J2k!k_zKZMXFY?`|`Nr2@;?t!R_xV77y0o}|V?LZ8crUNdmT&p| zx<2<;=PM5XeV_M(`RViX{rmi;OTaC^G5&`1TYSTJ^KUrwUz=b2?`OKdU43x&!MExA zN93FD*Yd@F!ryi*`ic4Hn{QqJj@i@awz{vrqVHeHXTMWE@b&H0&9K|>&-VxV;ct&N zAC0)`KO6MF^2(jD|LU)<-{R9h_@#gHIbZ&K^$*R{#wuu-_I{_)&E-1zxX8kKcwH{(?9%`{>kTj`SaEP?)_I>`;UD8q4~!C z6YnK|!>#|+@8$h{`ufQGL;Wq@|GU@smOl5Z=gam}_G7x4_hWp1*stH8>8n58f0~c) zSGk`S-|(~_segNanZ5s#*H*lTGd%x%Z}|h~_bVGcI=skV-h&x`NWaDB_b)q9AKt=_ z%RgUZTtH5=rXx{>tB7zr|Oa z`KJ2(`~Y0{WAl~yYClq(^Rr(zpXJZ|O8pj}IQ(h9Q+?v`d?35Z`H1H;o)7b<{QzF} zv!%~|*ZIsB{>u3)eCal3K>oPj_5EvaeAj<|zXg1M_5R7`bNVelzyHE~s-NadKK3Jc z%oqNNqaUR|&Ierk74*d;_CtPMzr`ocey92#?~D6~xbz#i%b)uL9?vg+M($_wrN4!K zi%%SU(MP^fpZg(h`$7K1=`Y2ZFXv0|2lDIsEk1G1pX&ShhRz54X+LcKa=x;kEq%@h z{gO`{{KegN0`13&h^rQhOne)uc%t?=d9n8EI!^z%dB ze}2Bl=f_EL|Fra5e185%KB}MQOFs4^c+406iDSQYe>xxgmF7==T_5ue@ri?9?$_h; z`4#<<9r*m=&wu}8xV}CBm-{R3&-$hQ@cg=di?2BNdOzCvgFg2|-1Y;1#OW`^nJ?!{ z?+5bh`Yk?j&Y$YDpTLLC2mA>h^DXBq``Oaxe9$lX#Nki-ZTb29B`YnF`{mbI{k|FXT zAN!H#$9(a8;@EH9pU%gA+4&!%k9>#t#M$pu-{bQ6Kknc1qrTuX;~UQV&wu}B{Zc-j zU)OK(^ZU#C0e$XA^zr?8>_7YwN51j?lpU4((fO=DWAy!gOFnVVpXwuj&R4&Gm`{2C z`1$7c{b=lGOTWb@4*#Mb^Y!`Q{FgZAkLNR<58n^qI=}U6j6VBY=W~AEPu3snul6(Y zXE~mJKb7A<{C-fs-vVy?9i!jk=ijg8_Ye7HzwmtG(*NrHsPonDAM)$^$ajcO9Q<;> z9`Et~vABPzFL-hP9&-$f&Jio5r;^+5Qs?Yr}pU_|FIPxdX{8OCy0@wMhKk!d} zUBAUA&iPY)v#$$o~sB-WYa&+|CE?4~L(;fD=eNW;KhCe>`TRV; zWk31+x<30G?*}>i$k6)7^Q-!n@5xJk-{XGD|NDA5{_?(`J{7!&|7rf#fAGT{*?;@c zsShZ=BHxeNd}H)meEj!&!e`*{-V*&)eaj!e7a@PgaGVdx!2A1);W(cW$NV}Ua6jJ| z{T81%{Q3Pt-{av0Y~c+%u>9yx@Ob|iuKR=kiRF)<3Ew}D({J$=hkwzJ_Yd^BAL6zj z_#;k#DbD=~j``z$#^|^B#KoWFYx}o+IN#9uU_Y=M%uvo(_7nRZ()an4eB$sgIJzqx g_xVh!IOh-BtNi~T*+1ZAKl%K+ev8lf!T0(855T3;djJ3c literal 23808 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 x?pIyE#U~EF=p(zBfy|e9SH;i-k diff --git a/funnyassets/meshes/sphere.fmesh_c b/funnyassets/meshes/sphere.fmesh_c new file mode 100644 index 0000000000000000000000000000000000000000..5da3c38121b633be8d2cca5b6885433e46247064 GIT binary patch literal 122880 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 K@btot@c$nTClYf2 literal 0 HcmV?d00001 diff --git a/funnyassets/models/sphere.fmdl b/funnyassets/models/sphere.fmdl new file mode 100644 index 0000000..f708ebb --- /dev/null +++ b/funnyassets/models/sphere.fmdl @@ -0,0 +1,5 @@ +{ + "Mesh": "game/core/meshes/sphere.fmesh_c", + "Material": "game/core/materials/cube.fmat", + "Physics": "game/core/physics/sphere.fpx" +} diff --git a/funnyassets/physics/sphere.fpx b/funnyassets/physics/sphere.fpx new file mode 100644 index 0000000..cd28979 --- /dev/null +++ b/funnyassets/physics/sphere.fpx @@ -0,0 +1,4 @@ +{ + "Type": "Sphere", + "Radius": "1.0" +} diff --git a/funnyassets/shaders/mesh_raster.shader b/funnyassets/shaders/mesh_raster.shader index 6eed28c..6ec5759 100644 --- a/funnyassets/shaders/mesh_raster.shader +++ b/funnyassets/shaders/mesh_raster.shader @@ -19,6 +19,7 @@ COMMON { float4 m_vWorldPosition: POSITION; float4 m_vTexCoord: TEXCOORD0; float4 m_vNormal: NORMAL0; + uint m_uInstance: SV_InstanceID; } } VS @@ -31,8 +32,10 @@ VS float3 m_vNormal: NORMAL0; } - PS_INPUT vsMain( VS_INPUT input, uint uInstance: SV_InstanceID ) + PS_INPUT vsMain( VS_INPUT input, uint uInstance: SV_InstanceID, uint uBaseInstance: SV_StartInstanceLocation ) { + uint uInstance = uBaseInstance + uInstance; + PS_INPUT output = {}; output.m_vScreenPosition = float4(input.m_vPosition, 1); output.m_vScreenPosition = mul( @@ -53,6 +56,7 @@ VS g_modelData[uInstance].m_matRotation ); output.m_vTexCoord = float4(input.m_vTexCoord, 0, 0); + output.m_uInstance = uInstance; return output; } } @@ -69,10 +73,10 @@ PS float4 m_vWorldPosition: SV_Target2; } - PS_OUTPUT psMain( PS_INPUT input, uint uInstance: SV_InstanceID ) + PS_OUTPUT psMain( PS_INPUT input ) { PS_OUTPUT output = {}; - PerModelData data = g_modelData[uInstance]; + PerModelData data = g_modelData[input.m_uInstance]; output.m_vAlbedo = g_textures[data.m_uAlbedo].Sample(g_textureSampler, input.m_vTexCoord.xy); output.m_vWorldPosition = input.m_vWorldPosition; output.m_vNormal = input.m_vNormal; diff --git a/game/client/assetmgr.cpp b/game/client/assetmgr.cpp index f3a8276..8af6094 100644 --- a/game/client/assetmgr.cpp +++ b/game/client/assetmgr.cpp @@ -317,7 +317,6 @@ HFunnyPhysics CAssetManager::LoadPhysics( const char *szName ) IJSONValue *pRoot = JSONManager()->ReadString(szProperties); if (!pRoot) return 0; - V_printf("PHYSICS %s\n", szName); IJSONObject *pMainObject; switch (pRoot->GetType()) @@ -340,10 +339,9 @@ HFunnyPhysics CAssetManager::LoadPhysics( const char *szName ) return 0; } CUtlString szType = pTypeValue->GetStringValue(); - V_printf("szType\n"); if (szType == "Sphere") { - pPhysics->m_hShape = g_pPhysics->CreateBall({1.0}); + pPhysics->m_hShape = g_pPhysics->CreateBall({0.1}); } return hPhysics; diff --git a/game/client/basemodelentity.cpp b/game/client/basemodelentity.cpp index 9940658..1c3394c 100644 --- a/game/client/basemodelentity.cpp +++ b/game/client/basemodelentity.cpp @@ -54,6 +54,8 @@ void C_BaseModelEntity::UpdateModel() FunnyMesh_t *pMesh = g_pAssetManager->GetMeshByIndex(m_pModel->m_hMesh); m_pInstance = g_pWorldRenderer->CreateInstance(pMesh->m_pMesh); + m_pInstance->SetPosition({0,0,0}); + m_pInstance->SetRotation({0,0,0,1}); } diff --git a/game/client/game.cpp b/game/client/game.cpp index f3ee677..42c8b63 100644 --- a/game/client/game.cpp +++ b/game/client/game.cpp @@ -8,6 +8,7 @@ #include "game.h" #include "netprotocol.h" #include "userinput.h" +#include "math.h" #ifdef STEAM #include "steam/isteamgameserver.h" #include "steam/steam_gameserver.h" @@ -157,9 +158,10 @@ void CFunnyGameBridge::Frame( float fDelta ) m_fNetUpdateTimer += fDelta; if (m_fNetUpdateTimer >= fTickRate) m_fNetUpdateTimer = fTickRate; - while (m_fNetUpdateTimer >= fTickRate) + if (m_fNetUpdateTimer >= fTickRate) { m_fNetUpdateTimer-=fTickRate; + m_fNetUpdateTimer = fmod(m_fNetUpdateTimer, fTickRate); if (pCurrentServer) EntitySystem()->NetSendThink(pCurrentServer); } diff --git a/game/client/milmoba/player.cpp b/game/client/milmoba/player.cpp index a3addee..0223b3f 100644 --- a/game/client/milmoba/player.cpp +++ b/game/client/milmoba/player.cpp @@ -21,7 +21,6 @@ void C_MOBAPlayer::Think( float fDelta ) C_MOBAPlayer *pEntity = (C_MOBAPlayer*)UTIL_GetLocalPlayer(); - m_vMovementVector.z = m_bIsForward - m_bIsBack; m_vMovementVector.x = m_bIsLeft - m_bIsRight; diff --git a/game/client/worldrender.cpp b/game/client/worldrender.cpp index 4e98dcf..4f1236d 100644 --- a/game/client/worldrender.cpp +++ b/game/client/worldrender.cpp @@ -59,8 +59,8 @@ public: virtual void Frame(); PerMeshData_t m_data = {}; - Quat m_vRotation = {}; - Vector m_vPosition = {}; + Quat m_vRotation = { 0, 0, 0, 1 }; + Vector m_vPosition = { 0, 0, 0}; Vector m_vScale = { 1, 1, 1 }; }; @@ -105,6 +105,12 @@ void CFunnyMeshInstance::Frame() glm_mat4_mul(m_data.m_matTranslation, m, m_data.m_matTranslation); m_data.m_uAlbedo = 1; + /* + V_printf("AAAAA %f %f %f %f\n", m_data.m_matTranslation[0][0], m_data.m_matTranslation[0][1], m_data.m_matTranslation[0][2], m_data.m_matTranslation[0][3]); + V_printf("AAAAA %f %f %f %f\n", m_data.m_matTranslation[1][0], m_data.m_matTranslation[1][1], m_data.m_matTranslation[1][2], m_data.m_matTranslation[1][3]); + V_printf("AAAAA %f %f %f %f\n", m_data.m_matTranslation[2][0], m_data.m_matTranslation[2][1], m_data.m_matTranslation[2][2], m_data.m_matTranslation[2][3]); + V_printf("AAAAA %f %f %f %f\n", m_data.m_matTranslation[3][0], m_data.m_matTranslation[3][1], m_data.m_matTranslation[3][2], m_data.m_matTranslation[3][3]); + */ } @@ -222,7 +228,7 @@ void CFunnyWorldRenderer::Frame( float fDelta ) glm_mat4_identity(matCamera); glm_mat4_identity(matCamera2); glm_translate(matCamera2, m_vPos); - glm_perspective(glm_rad(60), uWidth/(float)uHeight, 0.01, 10000, matCamera); + glm_perspective(glm_rad(75), uWidth/(float)uHeight, 0.01, 10000, matCamera); glm_mul(matCamera, matCamera2, matCamera); m_pViewBufferData = (ViewBuffer_t*)m_pViewBuffer->Map(); m_pViewBuffer->Lock(); @@ -278,38 +284,44 @@ void CFunnyWorldRenderer::Frame( float fDelta ) m_pRasterCommandList->SetScissors(0, 0, uWidth, uHeight); m_pRasterCommandList->SetClearColor(0, 0, 0, 0, 0); m_pRasterCommandList->SetClearDepth(1); + uint32_t uTotalMeshes = 0; + uint32_t u = 0; + for ( auto mesh: m_pMeshes) + { + uTotalMeshes+=mesh->m_instances.GetSize(); + } + if (!uTotalMeshes) + return; + IBuffer *pDataBuffer = g_pRenderContext->CreateStorageBuffer(uTotalMeshes*sizeof(PerMeshData_t)); + pDataBuffer->Lock(); + void *pData = pDataBuffer->Map(); for ( auto mesh: m_pMeshes) { if (mesh->m_instances.GetSize()==0) continue; - CUtlVector data = {}; - data.Reserve(mesh->m_instances.GetSize()); - for ( auto instance: mesh->m_instances ) - { - instance->Frame(); - data.AppendTail(instance->m_data); - } - IBuffer *pDataBuffer = g_pRenderContext->CreateStorageBuffer(data.GetSize()*sizeof(PerMeshData_t)); - pDataBuffer->Lock(); - void *pData = pDataBuffer->Map(); for ( uint32_t i = 0; i < mesh->m_instances.GetSize(); i++ ) { - V_memcpy(&((PerMeshData_t*)pData)[i], &mesh->m_instances[i]->m_data, sizeof(PerMeshData_t)); + mesh->m_instances[i]->Frame(); + V_memcpy(&((PerMeshData_t*)pData)[i+u], &mesh->m_instances[i]->m_data, sizeof(PerMeshData_t)); } - pDataBuffer->Unmap(); - pDataBuffer->Unlock(); - m_pRasterMaterial->VSSetConstantsBuffer(0, m_pViewBuffer); - m_pRasterMaterial->VSSetConstantsBuffer(1, pDataBuffer); - m_pRasterMaterial->PSSetTextureArray(1, m_pTextures); - g_pRenderContext->DestroyBuffer(pDataBuffer); + u+=mesh->m_instances.GetSize(); } + pDataBuffer->Unmap(); + pDataBuffer->Unlock(); + g_pRenderContext->DestroyBuffer(pDataBuffer); + m_pRasterMaterial->VSSetConstantsBuffer(0, m_pViewBuffer); + m_pRasterMaterial->VSSetConstantsBuffer(1, pDataBuffer); + m_pRasterMaterial->PSSetTextureArray(1, m_pTextures); + m_pRasterCommandList->SetMaterial(m_pRasterMaterial); + u = 0; for ( auto mesh: m_pMeshes) { if (mesh->m_instances.GetSize()==0) continue; m_pRasterCommandList->SetVertexBuffer(0, mesh->m_pVertexBuffer); - m_pRasterCommandList->DrawPrimitives(mesh->m_pVertexBuffer->GetSize()/32, 0, mesh->m_instances.GetSize(), 0); + m_pRasterCommandList->DrawPrimitives(mesh->m_pVertexBuffer->GetSize()/32, 0, mesh->m_instances.GetSize(), u); + u += mesh->m_instances.GetSize(); } m_pRasterCommandList->ResolveImage(m_pOutputImage, m_pResolvedOutputImage); diff --git a/game/server/assetmgr.cpp b/game/server/assetmgr.cpp index 94738a4..8a79117 100644 --- a/game/server/assetmgr.cpp +++ b/game/server/assetmgr.cpp @@ -197,11 +197,14 @@ HFunnyMesh CAssetManager::LoadMesh( const char *szName ) } - pMesh->m_nPositionCount = filesystem->Size(hMesh)/4; + *pMesh = {}; + pMesh->m_nPositionCount = filesystem->Size(hMesh)/32*3; pMesh->m_pfPositions = new float[pMesh->m_nPositionCount]; - filesystem->Read( hMesh, pMesh->m_pfPositions, filesystem->Size(hMesh)); - pMesh->m_nIndiciesCount = 0; - pMesh->m_puIndicies = 0; + for ( int i = 0; i < filesystem->Size(hMesh) / 32; i++) + { + filesystem->Seek( hMesh, SEEKMODE_RELATIVE_START, 32*i); + filesystem->Read( hMesh, &pMesh->m_pfPositions[i*3], 12); + } return hAsset; @@ -251,16 +254,13 @@ HFunnyPhysics CAssetManager::LoadPhysics( const char *szName ) return 0; } CUtlString szType = pTypeValue->GetStringValue(); - V_printf("%s\n", szType.GetString()); if (szType == "Sphere") { pPhysics->m_hShape = g_pPhysics->CreateBall({1.0}); } if (szType == "TriangleMesh") { - V_printf("hi\n"); IJSONValue *pMeshValue = pMainObject->GetValue("Mesh"); - V_printf("hi\n"); if (!pMeshValue) { @@ -269,11 +269,9 @@ HFunnyPhysics CAssetManager::LoadPhysics( const char *szName ) return 0; } CUtlString szMesh = pMeshValue->GetStringValue(); - V_printf("%s\n", szMesh.GetString()); HFunnyMesh hMesh = LoadMesh(szMesh); FunnyMesh_t *pMesh = GetMeshByIndex(hMesh); - pPhysics->m_hShape = g_pPhysics->CreateTriangleMesh({pMesh->m_pfPositions, pMesh->m_nPositionCount}); - V_printf("%p\n", pPhysics->m_hShape); + pPhysics->m_hShape = g_pPhysics->CreateTriangleMesh({pMesh->m_pfPositions, pMesh->m_nPositionCount, pMesh->m_puIndicies, pMesh->m_nIndiciesCount}); pPhysics->m_hMesh = hMesh; } diff --git a/game/server/baseentity.cpp b/game/server/baseentity.cpp index 185c309..0bf2e12 100644 --- a/game/server/baseentity.cpp +++ b/game/server/baseentity.cpp @@ -21,9 +21,6 @@ void CBaseEntity::Precache() void CBaseEntity::Spawn() { Precache(); - SetAbsOrigin({0, 0, 0}); - SetAbsQAngles(0, 0, 0); - SetScale(1); } void CBaseEntity::SetAbsAngles( Quat vQuat ) diff --git a/game/server/baseentity.h b/game/server/baseentity.h index 8069055..81b65a2 100644 --- a/game/server/baseentity.h +++ b/game/server/baseentity.h @@ -78,8 +78,8 @@ public: virtual void SetNextThink( float fThink ); fnThink m_pfnThink = NULL; - const char *m_szClassName; - uint64_t m_ullOwner; + const char *m_szClassName = NULL; + uint64_t m_ullOwner = 0; private: Vector m_vPosition = {}; Quat m_vRotation = {}; diff --git a/game/server/basemodelentity.h b/game/server/basemodelentity.h index 3f90464..cdbb030 100644 --- a/game/server/basemodelentity.h +++ b/game/server/basemodelentity.h @@ -16,9 +16,9 @@ public: virtual void SetModel( const char *szName ); virtual void OnModelChanged( const char *szName ); virtual void Think( float fDelta ); + char m_szModel[256] = {}; private: char m_szCurrentModel[256] = {}; - char m_szModel[256] = {}; }; #endif diff --git a/game/server/milmoba/player.cpp b/game/server/milmoba/player.cpp index da2fb21..0ed6cf4 100644 --- a/game/server/milmoba/player.cpp +++ b/game/server/milmoba/player.cpp @@ -7,13 +7,18 @@ void CMOBAPlayer::Spawn() { CBaseEntity::Spawn(); - SetModel("game/core/models/cube.fmdl"); + SetPhysics(k_EPhysics_Static); + SetModel("game/core/models/sphere.fmdl"); SetScale(1); + SetAbsOrigin({0,-14.5, 0}); SetThink(Think); }; void CMOBAPlayer::Think( float fDelta ) { + BaseClass::Think(fDelta); + + Vector vPosition = GetAbsOrigin(); // player might lie to us m_vMovementVector.x = glm_clamp(m_vMovementVector.x, -1, 1); @@ -22,7 +27,6 @@ void CMOBAPlayer::Think( float fDelta ) vPosition.x += m_vMovementVector.x*fDelta*5; vPosition.z += m_vMovementVector.z*fDelta*5; SetAbsOrigin(vPosition); - V_printf("player: %f %f %f\n", vPosition.x, vPosition.y, vPosition.z); }; LINK_ENTITY_TO_CLASS(player, CMOBAPlayer) diff --git a/game/server/milmoba/player.h b/game/server/milmoba/player.h index cc6a44e..f578bc9 100644 --- a/game/server/milmoba/player.h +++ b/game/server/milmoba/player.h @@ -3,10 +3,10 @@ #include "physicsprop.h" -class CMOBAPlayer: public CBaseModelEntity +class CMOBAPlayer: public CPhysicsProp { public: - DECLARE_CLASS(CMOBAPlayer, CBaseModelEntity); + DECLARE_CLASS(CMOBAPlayer, CPhysicsProp); DECLARE_DATADESC(); DECLARE_SERVERCLASS() diff --git a/game/server/physicsprop.cpp b/game/server/physicsprop.cpp index e59d437..4b8a9c0 100644 --- a/game/server/physicsprop.cpp +++ b/game/server/physicsprop.cpp @@ -1,6 +1,11 @@ #include "physicsprop.h" #include "game.h" +CPhysicsProp::CPhysicsProp() +{ + SetAbsOrigin({0,0,0}); + SetAbsQAngles(0,0,0); +} void CPhysicsProp::Precache() { @@ -16,12 +21,17 @@ void CPhysicsProp::Spawn() void CPhysicsProp::Think( float fDelta ) { BaseClass::Think(fDelta); + if (m_pBody) { + if (m_ePhysicsType != m_eCurrentPhysicsType) + { + m_ePhysicsType = m_eCurrentPhysicsType; + m_pBody->SetType(m_eCurrentPhysicsType); + } BaseClass::SetAbsOrigin(m_pBody->GetPosition()); BaseClass::SetAbsAngles(m_pBody->GetRotation()); } - V_printf("%f %f %f\n", GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z); } void CPhysicsProp::SetAbsAngles( Quat vQuat ) @@ -29,7 +39,7 @@ void CPhysicsProp::SetAbsAngles( Quat vQuat ) BaseClass::SetAbsAngles( vQuat ); if (m_pBody) - m_pBody->SetRotation(m_pBody->GetRotation()); + m_pBody->SetRotation(GetAbsAngles()); } void CPhysicsProp::SetAbsQAngles( float fPitch, float fYaw, float fRoll ) @@ -37,14 +47,14 @@ void CPhysicsProp::SetAbsQAngles( float fPitch, float fYaw, float fRoll ) BaseClass::SetAbsQAngles( fPitch, fYaw, fRoll); if (m_pBody) - m_pBody->SetRotation(m_pBody->GetRotation()); + m_pBody->SetRotation(GetAbsAngles()); } void CPhysicsProp::SetAbsOrigin( Vector origin ) { BaseClass::SetAbsOrigin( origin ); if (m_pBody) - m_pBody->SetPosition(m_pBody->GetPosition()); + m_pBody->SetPosition(GetAbsOrigin()); } void CPhysicsProp::OnModelChanged( const char *szName ) @@ -57,9 +67,16 @@ void CPhysicsProp::OnModelChanged( const char *szName ) m_pModel = g_pAssetManager->GetModelByIndex(m_hModel); m_pPhysics = g_pAssetManager->GetPhysicsByIndex(m_pModel->m_hPhysics); m_hCollider = g_pPhysics->CreateCollider(m_pPhysics->m_hShape); - m_pBody = g_pPhysicsWorld->CreateRigidBody(m_hCollider, k_EPhysics_Dynamic); - m_pBody->SetPosition({0,0,0}); - m_pBody->SetRotation({0,0,0}); + m_pBody = g_pPhysicsWorld->CreateRigidBody(m_hCollider, m_eCurrentPhysicsType); + m_pBody->SetPosition(GetAbsOrigin()); + m_pBody->SetRotation(GetAbsAngles()); + m_ePhysicsType = m_eCurrentPhysicsType; + if (!V_strcmp(szName, "game/core/maps/test/test0.fmdl")) + { + m_pBody->SetType(k_EPhysics_Static); + SetScale(1); + + } } void CPhysicsProp::EnableMovement() @@ -71,6 +88,13 @@ void CPhysicsProp::DisableMovement() { } + + +void CPhysicsProp::SetPhysics( EPhysicsBodyType eType ) +{ + m_eCurrentPhysicsType = eType; +} + BEGIN_DATADESC(CPhysicsProp) DEFINE_KEYFIELD(m_ePhysicsType, FIELD_INTEGER, "physics_type") END_DATADESC() diff --git a/game/server/physicsprop.h b/game/server/physicsprop.h index 8f98d19..637cb33 100644 --- a/game/server/physicsprop.h +++ b/game/server/physicsprop.h @@ -8,8 +8,10 @@ class CPhysicsProp: public CBaseModelEntity friend CBaseEntity; friend CBaseModelEntity; public: + DECLARE_CLASS(CPhysicsProp, CBaseModelEntity) DECLARE_DATADESC() + CPhysicsProp(); virtual void Spawn() override; virtual void Precache() override; @@ -25,8 +27,8 @@ public: void Think( float fDelta ); private: - EPhysicsBodyType m_ePhysicsType; - EPhysicsBodyType m_eCurrentPhysicsType; + EPhysicsBodyType m_ePhysicsType = k_EPhysics_Dynamic; + EPhysicsBodyType m_eCurrentPhysicsType = k_EPhysics_Dynamic; HFunnyModel m_hModel = 0; FunnyModel_t *m_pModel = NULL; FunnyPhysics_t *m_pPhysics = NULL; diff --git a/game/server/worldsystem.cpp b/game/server/worldsystem.cpp index 67117dc..2ec49bc 100644 --- a/game/server/worldsystem.cpp +++ b/game/server/worldsystem.cpp @@ -54,7 +54,6 @@ void CWorldSystem::LoadEntity( IJSONValue *pObject ) if (pValue->GetType() != JSON_PARAMETER_STRING) continue; V_strncpy(pcData, pValue->GetStringValue(), pDataMap->m_uFieldSize); - V_printf("loading %s %u\n", pValue->GetStringValue(), pDataMap->m_uFieldSize); continue; case FIELD_FLOAT3: if (pValue->GetType() != JSON_PARAMETER_ARRAY) @@ -83,7 +82,6 @@ void CWorldSystem::LoadEntity( IJSONValue *pObject ) bool CWorldSystem::LoadMap( const char *szName ) { - V_printf("Loading %s\n", szName); // unload the map IFileHandle *pHandle = filesystem->Open(szName, FILEMODE_READ); diff --git a/rapier/build.cpp b/rapier/build.cpp index 7951095..40b7a45 100644 --- a/rapier/build.cpp +++ b/rapier/build.cpp @@ -17,10 +17,10 @@ DECLARE_BUILD_STAGE(rapier) CUtlString szTarget = target.GetTriplet(); if (CommandLine()->CheckParam("-norust")) return 0; - rapier_lib = CUtlString("target/%s/debug/librapier_rtt.a",szTarget.GetString()); - V_printf("%s\n",rapier_lib.GetString()); + rapier_lib = CUtlString("target/%s/release/librapier_rtt.a",szTarget.GetString()); CUtlVector cargo_args = { "build", + "--release", "--target", szTarget }; diff --git a/rapier/physics.cpp b/rapier/physics.cpp index 0941d9b..5949dfc 100644 --- a/rapier/physics.cpp +++ b/rapier/physics.cpp @@ -42,6 +42,11 @@ public: return CRapierPhysicsBody_GetRotation(m_pBody); } + virtual void SetType( EPhysicsBodyType eType ) override + { + CRapierPhysicsBody_SetType(m_pBody, eType); + } + RapierPhysicsBody_t *m_pBody = NULL; diff --git a/rapier/physics.rs b/rapier/physics.rs index 6f05ae5..0cad87b 100644 --- a/rapier/physics.rs +++ b/rapier/physics.rs @@ -16,7 +16,7 @@ macro_rules! V_malloc { use std::{default, ops::Index, ptr::{self, null, null_mut}, slice::from_raw_parts, sync::Arc}; use parry3d::{glamx::vec3, shape::{Shape, ShapeType, SharedShape}}; -use rapier3d::{geometry::Ball, na::{UnitQuaternion, Vector4}}; +use rapier3d::{geometry::Ball, na::{UnitQuaternion, Vector4, coordinates::XYZ}}; use rapier3d::prelude::*; use libc::{malloc, free}; @@ -56,6 +56,7 @@ pub struct RapierShape_t } #[repr(C)] +#[derive(Debug)] pub enum EPhysicsBodyType { k_EPhysics_Static, @@ -119,7 +120,8 @@ pub unsafe extern "C" fn CRapierPhysicsBody_SetRotation( this: *mut RapierPhysic { let world: &mut RapierWorld_t = &mut *(*this).m_pWorld; world.m_rigidBodies[(*this).m_hRigidBodyHandle] - .set_translation(vec3(fX, fY, fZ), true); + .set_rotation(parry3d::glamx::Quat::from_xyzw(fX, fY, fZ, fW), true); + } #[repr(C)] @@ -256,7 +258,7 @@ pub unsafe extern "C" fn CRapierPhysics_CreateCube( this: *mut RapierPhysics_t, pub unsafe extern "C" fn CRapierPhysics_CreateTriangleMesh( this: *mut RapierPhysics_t, triangle: TriangleMeshShape_t ) -> *mut RapierShape_t { let pShapeMemory: *mut RapierShape_t = V_malloc!(RapierShape_t, 1); - let positions = Vec::from_raw_parts(triangle.m_pfPositions as *mut Vec3, triangle.m_nPositionCount as usize, triangle.m_nPositionCount as usize); + let positions = Vec::from_raw_parts(triangle.m_pfPositions as *mut Vec3, (triangle.m_nPositionCount/3) as usize, (triangle.m_nPositionCount/3) as usize); let mut indices: Vec<[u32; 3]>; if ( triangle.m_nIndiciesCount == 0 ) @@ -265,8 +267,8 @@ pub unsafe extern "C" fn CRapierPhysics_CreateTriangleMesh( this: *mut RapierPhy { return null_mut(); } - indices = vec![[0,0,0]; (triangle.m_nPositionCount/3) as usize]; - for i in 0..indices.len()/3 + indices = vec![[0,0,0]; (triangle.m_nPositionCount/9) as usize]; + for i in 0..indices.len() { let u = i as u32; indices[i][0] = u*3; @@ -281,7 +283,7 @@ pub unsafe extern "C" fn CRapierPhysics_CreateTriangleMesh( this: *mut RapierPhy { return null_mut(); } - indices = Vec::from_raw_parts(triangle.m_puIndicies as *mut [u32; 3], triangle.m_nIndiciesCount as usize, triangle.m_nIndiciesCount as usize); + indices = Vec::from_raw_parts(triangle.m_puIndicies as *mut [u32; 3], (triangle.m_nIndiciesCount / 3) as usize, (triangle.m_nIndiciesCount / 3) as usize); } let mesh = TriMesh::new(positions, indices); @@ -291,7 +293,9 @@ pub unsafe extern "C" fn CRapierPhysics_CreateTriangleMesh( this: *mut RapierPhy { std::ptr::write(&mut (*pShapeMemory).m_sharedShape, SharedShape::new(m)); } - default => {} + default => { + return null_mut(); + } } pShapeMemory }