From 6d5390a8dfab0527fabb69fc99d978d2323ed621 Mon Sep 17 00:00:00 2001 From: Jay Robson Date: Thu, 29 Feb 2024 15:30:50 +1100 Subject: [PATCH] improved lighting, enabled shadows --- assets/model/monitor_graphics.glb | 3 - assets/model/monitor_graphics.stl | Bin 32884 -> 0 bytes assets/model/monitor_turbine.stl | Bin 6484 -> 0 bytes assets/model/pump_switch_1.glb | 3 - assets/model/pump_switch_2.glb | 3 - assets/model/pump_switch_3.glb | 3 - assets/model/pump_switch_click_1.stl | Bin 584 -> 0 bytes assets/model/pump_switch_click_2.stl | Bin 584 -> 0 bytes assets/model/pump_switch_click_3.stl | Bin 584 -> 0 bytes assets/model/reactor_core_button1.stl | Bin 184 -> 0 bytes assets/model/reactor_core_button2.stl | Bin 184 -> 0 bytes assets/model/reactor_core_button3.stl | Bin 184 -> 0 bytes assets/model/reactor_core_button4.stl | Bin 184 -> 0 bytes assets/model/reactor_core_button5.stl | Bin 184 -> 0 bytes assets/model/reactor_core_button6.stl | Bin 184 -> 0 bytes assets/model/reactor_core_button7.stl | Bin 184 -> 0 bytes assets/model/reactor_core_button8.stl | Bin 184 -> 0 bytes assets/model/reactor_core_button9.stl | Bin 184 -> 0 bytes assets/model/reactor_core_input.stl | Bin 584 -> 0 bytes assets/model/reactor_core_interface_cell.stl | Bin 684 -> 0 bytes .../model/reactor_core_interface_circle.stl | Bin 102484 -> 0 bytes assets/model/reactor_core_joystick.stl | Bin 2384 -> 0 bytes assets/model/reactor_core_scram.stl | Bin 1584 -> 0 bytes assets/model/resistor_bank_switch.glb | 3 - assets/model/resistor_bank_switch_click.stl | Bin 584 -> 0 bytes assets/model/scene_collisions.stl | Bin 26884 -> 0 bytes assets/model/synchroscope_dial.glb | 3 - assets/model/synchroscope_dial.stl | Bin 684 -> 0 bytes assets/model/turbine_breaker_switch.glb | 3 - assets/model/turbine_breaker_switch_click.stl | Bin 584 -> 0 bytes .../model/turbine_valve_bypass_joystick.stl | Bin 2384 -> 0 bytes assets/model/turbine_valve_bypass_switch.glb | 3 - .../turbine_valve_bypass_switch_click.stl | Bin 584 -> 0 bytes assets/model/turbine_valve_inlet_joystick.stl | Bin 2384 -> 0 bytes assets/model/turbine_valve_inlet_switch.glb | 3 - .../turbine_valve_inlet_switch_click.stl | Bin 584 -> 0 bytes assets/scene.blend | 4 +- assets/scene.glb | 4 +- assets/shader/light.fsh | 2 +- assets/shader/light.gsh | 3 +- assets/shader/light.vsh | 3 + assets/shader/main.fsh | 70 ++++------ src/graphics/camera.cpp | 4 +- src/graphics/camera.hpp | 3 +- src/graphics/mesh/gllight.cpp | 4 +- src/graphics/mesh/mesh.hpp | 4 - src/graphics/mesh/model.cpp | 129 ++++++++++++------ src/graphics/mesh/model.hpp | 42 ++++++ src/graphics/monitor/core.cpp | 28 ++-- src/graphics/monitor/core.hpp | 4 +- src/graphics/monitor/primary_loop.cpp | 18 +-- src/graphics/monitor/primary_loop.hpp | 4 +- src/graphics/monitor/secondary_loop.cpp | 14 +- src/graphics/monitor/secondary_loop.hpp | 4 +- src/graphics/monitor/turbine.cpp | 9 +- src/graphics/monitor/turbine.hpp | 3 +- src/graphics/monitor/vessel.cpp | 2 +- src/graphics/monitor/vessel.hpp | 4 +- src/graphics/window.cpp | 76 +++-------- 59 files changed, 234 insertions(+), 231 deletions(-) delete mode 100644 assets/model/monitor_graphics.glb delete mode 100644 assets/model/monitor_graphics.stl delete mode 100644 assets/model/monitor_turbine.stl delete mode 100644 assets/model/pump_switch_1.glb delete mode 100644 assets/model/pump_switch_2.glb delete mode 100644 assets/model/pump_switch_3.glb delete mode 100644 assets/model/pump_switch_click_1.stl delete mode 100644 assets/model/pump_switch_click_2.stl delete mode 100644 assets/model/pump_switch_click_3.stl delete mode 100644 assets/model/reactor_core_button1.stl delete mode 100644 assets/model/reactor_core_button2.stl delete mode 100644 assets/model/reactor_core_button3.stl delete mode 100644 assets/model/reactor_core_button4.stl delete mode 100644 assets/model/reactor_core_button5.stl delete mode 100644 assets/model/reactor_core_button6.stl delete mode 100644 assets/model/reactor_core_button7.stl delete mode 100644 assets/model/reactor_core_button8.stl delete mode 100644 assets/model/reactor_core_button9.stl delete mode 100644 assets/model/reactor_core_input.stl delete mode 100644 assets/model/reactor_core_interface_cell.stl delete mode 100644 assets/model/reactor_core_interface_circle.stl delete mode 100644 assets/model/reactor_core_joystick.stl delete mode 100644 assets/model/reactor_core_scram.stl delete mode 100644 assets/model/resistor_bank_switch.glb delete mode 100644 assets/model/resistor_bank_switch_click.stl delete mode 100644 assets/model/scene_collisions.stl delete mode 100644 assets/model/synchroscope_dial.glb delete mode 100644 assets/model/synchroscope_dial.stl delete mode 100644 assets/model/turbine_breaker_switch.glb delete mode 100644 assets/model/turbine_breaker_switch_click.stl delete mode 100644 assets/model/turbine_valve_bypass_joystick.stl delete mode 100644 assets/model/turbine_valve_bypass_switch.glb delete mode 100644 assets/model/turbine_valve_bypass_switch_click.stl delete mode 100644 assets/model/turbine_valve_inlet_joystick.stl delete mode 100644 assets/model/turbine_valve_inlet_switch.glb delete mode 100644 assets/model/turbine_valve_inlet_switch_click.stl create mode 100644 src/graphics/mesh/model.hpp diff --git a/assets/model/monitor_graphics.glb b/assets/model/monitor_graphics.glb deleted file mode 100644 index b47c924..0000000 --- a/assets/model/monitor_graphics.glb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:17ea9c5be82c4fa4149bc9dd6819a54d71b36048bf737341831f0540c6975ee0 -size 29180 diff --git a/assets/model/monitor_graphics.stl b/assets/model/monitor_graphics.stl deleted file mode 100644 index 530ef42a6e3e4cfe110d663152a0233466ef07a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32884 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 Pbtpqo{7p#rn*;v_cb36q diff --git a/assets/model/monitor_turbine.stl b/assets/model/monitor_turbine.stl deleted file mode 100644 index 1f22efd1222c67a4d85e8dc417a5f39390a5f5bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6484 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 W&_fsI4~Q+G@IrS9vJRL@3=9Azp^Lr% diff --git a/assets/model/pump_switch_click_2.stl b/assets/model/pump_switch_click_2.stl deleted file mode 100644 index 873b920acfb24444ba8081f1736717962cd3c769..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 584 zcmbV|F$%&!5Jj!Mfnbpf7$j@&B6teh-K{i{#lkXo33!e4LGL6p;e|m><5nN$zxg}= zc)vFJ7DJJ8b14qzScjN5yK-Ari+|oyp|*#0uJg{FeBG_~=%HGxem#R1E#7$om(ZeR z6Wd!=c7m3@DLs@RLvy|e>q3(;?ibEZ&}7JcWXuz|gr*)DhdCTzQ8jKmumpqTss diff --git a/assets/model/pump_switch_click_3.stl b/assets/model/pump_switch_click_3.stl deleted file mode 100644 index b632007dad18b96d6154d9821a368eb520de3d63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 584 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIaDg>7?1$-1OIzn)Y#i;7w^-61 z#y({v17@E+li~nkgVf^I0aFFi4Pt{#f|=d`W+BVK*dTLf&fEyr0kZ>a4~7n8RWLTp z4v6_6eaJE}Hp~u?|6q3D)&Wxm(hUm{xIgy8?10I@RDsMz4maF7kX6ChFn_>xfx`sZ TCFr3G^9Obv$e|0f1EK=}4WFhu diff --git a/assets/model/reactor_core_button1.stl b/assets/model/reactor_core_button1.stl deleted file mode 100644 index 7e26a5c17871439f124dc94ecea2fbaf12d503d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 184 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIFrjE_u=lR}Xn)Hg-C>=(BA8t* ak_TpUU4Lv3V*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIFrjE_u)mPW>~PB=-C>=(BA8t* ak_Tod==`*Yv5~c)>OfWnV#7>gU;qF=#U)b! diff --git a/assets/model/reactor_core_button3.stl b/assets/model/reactor_core_button3.stl deleted file mode 100644 index 1cb9d8411646a85ba573fe252fb094fd96f34c34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 184 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIFrjE_u&);3bGYS@?y$~X5zMX@ a$pf=*Ij}px*vMK?bs(z(v0)}LFaQ9cEFw(+ diff --git a/assets/model/reactor_core_button4.stl b/assets/model/reactor_core_button4.stl deleted file mode 100644 index 7b94757f9f16dab1bb282baaf7988940ea52b5f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 184 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIFrjE_u=lR}Xm2nr#$lbiBA9(4 aGa1b0y8hT6#zxkHssmXShz&D|fdK&HVJJrc diff --git a/assets/model/reactor_core_button5.stl b/assets/model/reactor_core_button5.stl deleted file mode 100644 index a3539e2ac1ea6bb5d278faed3bd1b930d3e80360..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 184 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIFrjE_uustWX@4Oz**D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIFrjE_u)pQN?rOfWnV#7>gU;qI0`6CSg diff --git a/assets/model/reactor_core_button7.stl b/assets/model/reactor_core_button7.stl deleted file mode 100644 index d0f5dc501c875186e79b5bebcf150f446611789e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 184 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIFrjE_u;;q|*j{aagu^;_MKHVd abs(7SUH8!*#zxkHssmXShz&D|fdK#si75vF diff --git a/assets/model/reactor_core_button8.stl b/assets/model/reactor_core_button8.stl deleted file mode 100644 index 7ce133016fe31ae38ec8e38532cd9f41d1af882e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 184 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIFrjE_uustWX|J|F!eO1eBADI! aIuOjhkjd--V*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIFrjE_u)pQN?x40m!eO1eBADI! aIuOjR7U6S%v5~c)>OfWnV#7>gU;qFku_Mg@ diff --git a/assets/model/reactor_core_input.stl b/assets/model/reactor_core_input.stl deleted file mode 100644 index 7d86b9999f16c38872d977dcb044beb2e898c7aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 584 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIaDg>7*xN8DYzHx!7#tiJ7#cv> z9>E5QIXIjhzyJW3qH{k0 diff --git a/assets/model/reactor_core_interface_cell.stl b/assets/model/reactor_core_interface_cell.stl deleted file mode 100644 index 3d05d78994b68c767ac640daf795cfb121e84cd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 684 zcmbu5I}XA?3`Dm^^l3RpI)p-tC~}3Qi-05Sttfp4Zp4n`NoJK$VQJ-Ad!F}me~pj6 zyIfDV=P*u(^lu!i0ols-Toy6{Sv7i9>=JY#Q!i9T#n5TqpEk6G_Fm|kKt~Dc4dFKe z>zx>4CG!l|QTMb<=v<|f-=8>KSO_It&*iidIb2Hoeg|C^6vm;Z1U=}j=P2P?ewTDw YUJVp3EQAuS=W>}(2VLAF>+i-HUraPs9{>OV diff --git a/assets/model/reactor_core_interface_circle.stl b/assets/model/reactor_core_interface_circle.stl deleted file mode 100644 index 8193953839cc2c43b6bb452541dc208981b64124..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102484 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 diff --git a/assets/model/reactor_core_joystick.stl b/assets/model/reactor_core_joystick.stl deleted file mode 100644 index f8643ba9e05a61d7a7b9173b1cd83145d33ca493..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2384 zcmbVNJ!n%=7`+ZUIK;tD3erh*Fa)t;3+5G}M#V+wnrcg#9 zNpulR%X|K$Dkz9QgS3--$GSLJzw_=pdFS?ZGD{A8=iGDe_xHxG&(1WjHl_#9HfJsk z9=X`KJl$ySJ5a8a_q+f3l})trzE*uUFc(3;$-R#1?Wxg~Q->nrD~C@+o!@Vw8}+GC zVCSwa)~dY?6v`sTNzTm=m!hM~}n>^&aZtB-xGRiV%bF+94v7A<%5_+*Noy`n-{ z#NOkFDYo}&F+4Ov%y$fJKApYei77fCiVEC{EMo6*&R%|ZxRmf6U?D;l>(Qx9WFD)Q z-Jy}90@)>t*n70C7O$4ZQxA<0!vpod^QfMAys%oFTrMh7E7*PLUG7@+81^yz$i{yw*v_aw74#@7G{PH##f%gc8i9hl z1SfIk!&_;DU5RsbRzihFbZT`=gbI!5zS8{|Dl`HGYmSpxn^2(0HXwste$_dM r(mDH{C;XnPLRrLqKH9cLZMUa=uMuMQRX!iK+hg191%+0S*n9i~5=9-* diff --git a/assets/model/reactor_core_scram.stl b/assets/model/reactor_core_scram.stl deleted file mode 100644 index 35f8899f989bbead8ae260f098eb7766fff649bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1584 zcmbVLJxc>Y6kOEC11lj#q9I=v7M?~$4JmFBf?%yE@mq6(pizQ_m7YJr-x07>e}LFU z#9D0B&i2w6IrHxB?apfFRSUDT^WMx{1ESuept}X?wz+6#x0s zUDC>8Vm9J>PNzR7?a!LLUdTErD=S+iH#`fGkv&U%?lNwffyjrSR*b&(uzCq6^BhDb ztzns~M|xg)NP72svEIRUVvaQsdA&->mcJX`dLB&4um0#PL}fj3#|%WK9+EO??Szc) zW>N;hR;=+>jTk|2;UGeccYjl9^tLx*22Mp9jL=j?E4oF~o|o5S2JcQ9h|uOQS8L%d za^z_+I)`~EcM&0Xix1WK-Hhxs`HTrt9*j_e%%Eho22O>@qn}e#UEb$mkM8EmT}1Nr zg4%riv!EOiVry9^h{$7UM7i6$Gy-{KS2Y6>VsL`=lFl5bLWHK`me91iSG>6po`VQ& z&P~L>K;I{ZiRga*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIaDg>7?1$-1Puu5UY#i;7w^-61 z#y({v17@E+li~nkgVf^I0aFFi4Pt{#f|=d`W+BVK*dTLf%{&O!0kZ>a4~7n8RWLTp z4v6_6eaJE}Hp~u?|6q3D)&Wxm(hUm{xIgy8?10I@RDsMz4maF7kX6ChFn_>xfx`sZ TCFr3G^9Obv$e|0f1EK=}{rIRj diff --git a/assets/model/scene_collisions.stl b/assets/model/scene_collisions.stl deleted file mode 100644 index d91ce4fdc1de60afff9be92e3fa69c1fdbc405c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26884 zcmbW8f6Qe^UB=J0-4%plF;)7*kWHH{P1~))Zeg|QzW4TrxK=U!m1SGCtY&jOCbhH)L@iu5kf_Aw@s~W*Lh~nGxM2u z&OH$CA9tU<@AG`;dG7f!GiUBx^T4m)v+w>p-n@D5zI*Q8eC1p3c-x!r*td22r9W}$ zYr6l>>#S3xT3uMXbNjY{XEXiZc>A_(D+#a8g!Q*6MPgYYwqL7J%fA?_?z{GWbrve; zHl%75WEt1>^*{c_xU@0LZKV3+io{Cl^o`_p;`hbB7?{dczRc1mDS2WU>vO(V z7yf?qX;QDw3a(x0^D#wzG{xd;wff%O-m)B0jw$NzO6sbO#l26yu-Gu1SHd6Izh@@K z&Hs5~@v(Cg?z-#dw;f2j)fFqYZ#%xzEMcpKyY8Aphp%|+XMa1k=D(0X>wyQqzSz9$rdi^>YJS_t2Ss%}%xYbInAbtLnZ>mX81F+h03NiXUHcUYXUp8qSh6=~>rU3aYzqI1?KMS;om#d9RNL zS-KuKe&N-##Jyq3b#7McYPf2nE7moZg6e#oHwvSGs2$cdmV)Yh-)$6R87KGUz0N_F`m3*h;-XpNE*qDa)w&vbwdjgl#Zzb=M6enMOgD@pKNdG@iTh*abt5 z7cCi=nAN%(Mt#v0>l#Zzb=M6e%SJ(#@pKNd)JxpC*EyDr+s$fS4deFcigk^ppgND+ z8wFX$(>cic?ERb~qy4#Aqpl8x`A2lcy2esa9dnE-$TFVJLDtqQU)-1LBb-;G z<94%JSK+)`3$uxsgLRFipt|dRASgl~(kRF>p3XtmWsjcTm-|(?&PV4_X0@))yyd%V zfAqQAqbt@mmV)Xy|5yw2k48b3@pKNdu6ysx`_g}e`|jxRFl)rso#!pW{3E(zU1KSz zj`!VB1zE<^Imp_*II}PPdFTg6uMe|YSD_zVg!xCz!Mes$P#ychQ3YAX(>cg`>c?Ku zm+@5?myG5xt92E|C5tfsh@%YFHI{D$b)=*VxI`hH%c&DATnH)Rfd&g=}v8y z{E}rnorA2Oxqjok^ylYeT*4e?wXXgyWcb%%{eyLlrJ%a&mMO?Gp3Xtmqu<&%FXOA< zSdzo6*44e?4Ee2aZmC7qHI{wpx3B!m8(Rfg#?v{-`u0z6nwRnJ#Tb`_8u|J# zt95m0=n1a*U|RoRU1KSz?z-dubN|X?!}^C=@=KQSbPlri?%kB{V^qc81LPcLwXXgk z+(AEoAgzC}uCWwUcik@s#TlPz6=WIHk#K##B1`R+`C!r2Im}w>D$b)=*VxI+`p1yG zQLqi;;wPax2U$9@Wq!`}kD$!Q!>rcTaF(p89o99Lg6ggt&csGRmT_`l-s>D>>3S^B zOMY+3b#7McYPf2nE7moZg6i-~hjeFX6l58f1PRqS$kP3>JipquB!^k8tKlxXP&=$^ zECtp1zS}6sGM>&smU^P{Jdx`kp+-Kh%xYZ?y;^j|y2esa9qzlS=WG;Y8BgaROXG*~ ze3!q=U=FidSHmbHx?){pDX5O~4~=9R1zE<^ImpsTtvqjEHcm9Fb;b1$)-{%b>O4-2 zIn0t@vW%y5tYgi~`p0EU#_geAWVNn_QFwI4y2esa-F3rAzfshz)ZTOsE5!QL>hrU5 zJVK5AnSJ@e`Z$hSA5P8WI2aftt+m7 zu&%KbRLA+pT9|*t9A?QcS;qRDuQ~@=C;t2CS?NFcoFV9Q4zpTU!*ieLigk^ppgKSI zX%u7`GlOuQgRFaRd1_YrbFLdOhgq$w&<`%c{3E(zU1KSz?z-0;yJm6gh=MHR=^SMJ z)g>opWqieT9Of{qb#)}1AzO#_57sr7g6cRfS%eu&9G93SzhoIt=OF8%eaB~Iyvy|u z<}j;u6-IrFF#m|ISl3tzs^k1)5#}F_f-K|d9As_Vc6^5CL0MRj+s$fSh1tX+%qHR} zoOO+*pt|e!1;wv@x>b;6ob3#tzCOrOdu2XYbaf81mb!|o8LVsU$e zP@RJ;9se>v5A)j5=Wu4VuEP97XNmgkj&+TtpgPV!bS5?mvW%y5kfkfFJTKw;N2rnS zyJoen!fZlUZFI%D#!^t-b;F&ZQIKUkor5ghAItNrH!XS2U{>pDxQni+Mbch}$e=vm4bMgM z`bVgd&nvT9S7H94QATvdy2esaU9W$bCBI}DPv;;@Ben9pec3qCtk%^qPK-HN*H{Xw z^Ek0lkYzlbV;w86A#`0BCytKWL%qBTV6_}}-7pG|uKX9ZZk$*}9s0pE(r*-O!&sI0 zT3wtxd2(^p`&N2=D*TaWw?zESQ=VS@$paTe+;yBsSs^E830s{Ua{q__5}L?utXJpX zk;NQTunl8X;;YU<){nmB$;CVW<5hiP--7;wIm~KZasLPF8cRWSp4Y}4W~p_ujFYSK zUgscd(|aCYY`ONLK5?(z(&h7tIm~KZaW@C+8cRWS{+(saVU}7a%Q(3z?{yBc9y{{S zi;ExJ+9&RrJNnTaX0@(95PE_Q$I@yB>l#Zzb=NIZkY!vFBvj`h>oa%%!{YU~yn4uS z?UM7#tkxBGbFi+l6jbNmA;;rkmRyo$oZOf9ItN+5|JPq${KDbO`oz6;Ne;7GSKQ6P zy2esa-F5E_z0HNgNX9I+PL^?URo?3yWPSMX7Z;y=|4;Ra%kdSj53^cV!>{h+Xo+== zrJ%ar|6!I|C(AgwD(`g;vW^@*n(xPjA7;WU%wbmRin}>j*H{Xw^S+5VZZ}IUlVwat z!gUU^ROw59e0AR_svKsuuC#XkWa!zXXI*0_R~y1zw@kq{j2l-Af4lk%Svs;iZrjy2 ziYkX$tt;;TU|nM=sIK>an5EXqGHzT|ImptLHv8hw_epX2lIz^8*41#;u1U|j#!^sS z@Bc7MYO;*=IbZd8MV9V-zxc81`os>uhg;fzh}F8{{twnQmcnfa=lkwLEt(}vma#tP ztIk1|`m100+Kqi;Z(h<5n$@}*dbQ|^b&aKpAHwXV4S z!Mes$P+jl;FiWkIWt?1<_c{kza{INdd-}xX{txCbt98ZwAFOLE1=V@n9?vVY)H+$l z$yIr;bCC7!7f$QT@!nhAY*24bt=!$iXrJy>`Ya0bw#?v{-dTz(d`f|St*ZJu6VOHxZT(x;O z2kRP3L3Mu45ObI%zhoIt=OF8>bAGrl{YSX(9!T1Hd}UVa>dvqNur;g%&@3e;)e5(Hv&AuDJh$b&aKE5|bu~Pvj;>hOSPH81@AMl5 zS;o^j$lAaE?B36VsH(3Ivszd8h1HBJht&+$HI{x%n7Sl3tzs`GUobC@NsWEnGqaGirJ z-TBJ%tMJ@sbpByh>x%0itZOU<)%E@lv*eL1V|~t7or5g(iRF1>cn&vuUYXUp3iA*3 zYAb4ub&aK_Kk|+dv*eL1 zV|~t7or5fm=gRZ;@SJ+|yfUkG#q|%?HI{(0D=Xy0EMcpK^RL39EB{4xjn}K=%Fh+y_g9UAZ5XQ(Uv&<$K6L9T^Q-n;*e5o} ziOgYE>uQ+SMpvwBECto|`iEI+oh;+zs=U`Z$a>!~PG}HI{N>ngB-m+%xYb6HwWt)OF?!19dbM#X2~yE z#?v{-y6LMM=P%j*+CC|EFUet6>x%n7Sl3tzs_Xq9W~p_ujFYSKUY}QFJ+y7p{QeD> z_lbKk`VXF0X0@)kn}cqy zxc`H7jisQv-v42iS|-bwj)dzRWU11-Ul?2eU=FidSHBc`f^Yn7TK`~OV<%S|!d<82 ze|Df%unpts9AxRpo;WhL{=pn(wXV3EgLRFipgQj>T9Ze!gvm12=X}-2gDhQX&+T|a zpV(agU=FidSKR->y2esaUGM)eORbY-oLrUnItN+0^PP3h^?l-U{=pn(wXV4TgLRFi zpgP}o7i!TgVX}<%IbU@SveXm3a@S3LVsrh2Im~KZ4ZT`)#k$5)P~CMy&)F!*GG+$h zItN)A8614X>mS_z!5n6_u7+_*bj7;HQc#`8C5?hCmRIZECtnhoEUSMrPj$ZPOi#(eLTpL+x`2UBm5q2bX;Oq>ni;IN~7@Tigk^ppgNEA z8wFX$B|$=U4zf1g{QRsOkC0>gps4ymvszc&&B40HQc#_LM;3FKr8dbjPF~7;orA3F zk3Tyr*9U*sr#95n%ZXX7t6^RnU9qn5dUd`2VV0b-4dap^p*jayj~#qwR_<5a|G^w) zwXV4TgLRFipt@fFFiS4UGM>&s*6irhv(kTX{ewBoYF!P_ed6(8U1KSzuGc@zl3%in zr*n{XX!}#M(w~QZaP&Git98ZwAFOLE1=aQXhgtGVmhp5Bvc9wN#H@_3mi6amwXV4T zgLRFipt|1wVV3-oWjvjOthZl#eD=M^yJoenxcRmlVwat!u9=%ELAG=!J?~knAN%(cBRDC z4AwPvaykIuDJfey2esao%_KRdKV_kcsd7J8X1)5 zyWzR$Xb!VlS6u&KU1KSz&f}7p!z}qF%Xm5mSsJO8=k0ebd46S9>x%0itZOU<)p?v4 zbC@N+WEoHAAWK()*AVLcAG|)yYF%+R2kRP3L3O=j#4PzG%a}Rhp1bhDtbcg_Z_d(R z&X~7&b@-clo5UJZh~>|d!tAcwyZ2@DppJD0+^bT--=AVNe6y~U6sn?^b~Vm=wejVn zM?()3ai8!RYJ0$u9N*R}$clKV1Vu=n{*u0IW20W|r@Lh$(={2rcot4kacjb2Caqg2o9<_D&`%{SJO2YpKkDwzc diff --git a/assets/model/synchroscope_dial.glb b/assets/model/synchroscope_dial.glb deleted file mode 100644 index 586cb88..0000000 --- a/assets/model/synchroscope_dial.glb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b2e85c91f5cb6630191ff38473356b5e84704c1bd9dd3035d17c6c5e5216c3d5 -size 4760 diff --git a/assets/model/synchroscope_dial.stl b/assets/model/synchroscope_dial.stl deleted file mode 100644 index 3b8c03eb32459dcd6ceab694459b43b3d6cd0804..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 684 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eI@W3@S><2NqJx@F2?5T0+4>)FT zYz$$iryaA8mPLrev^4Bj^%UBPEVG#(qUw|6F?(As2z$bzqxJ|LAQrL=jD7aZ8he=T z?9w%8I*?^x_MNj^19#y!4Rjqaw}WJ0egf&(90qX}7CVq+G-DvD&H!BnV`KUQSq5e< z$mcNoKw${+`Tzg*`xRJLS|H27`~gx03k8H7ARXvog&YdV{)5=Tz|gSY$wbH$SqA1R hkZ+M)i_o#$Ys(H~8Dtk?x(Z|mx~q`wLpF(l0RX4`=kNdk diff --git a/assets/model/turbine_breaker_switch.glb b/assets/model/turbine_breaker_switch.glb deleted file mode 100644 index fd69f25..0000000 --- a/assets/model/turbine_breaker_switch.glb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:36778a2cafb1baa2ae8447f7cdf117fe03b77ceb7d5082dca6cd1e50c562bb39 -size 5304 diff --git a/assets/model/turbine_breaker_switch_click.stl b/assets/model/turbine_breaker_switch_click.stl deleted file mode 100644 index 525d75ccf8b84d8c54bf714f50abb46c5e116a05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 584 zcmZ>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIaDg>7?1$-{HS?r{v2nCR-eO66 z82glw448fPOo{`D4N{9+2TT=6H;4@~31)f&n1w6@V}r~+d*%#S2h0wzJs3KWRl(RW zJ0RwR^dZZ@*f2Xl{)5?pTL(-PNH;7*;QrVTvjZjrQw1^?IoxpTKvo4~!~6l)1r8Hr Tm!O9(%pcfwAcro@4u}o_@%OcM diff --git a/assets/model/turbine_valve_bypass_joystick.stl b/assets/model/turbine_valve_bypass_joystick.stl deleted file mode 100644 index b793198c495456890cf43ee0a7f831c8e2f683ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2384 zcmbVOF>6y%7`;Wh#zptyDuy6NTB&&tK_cQJ1e{W}G)loVX>gEsFrZR!$!I`Ip#@%qiX(ZO*$-l#9fz|LJV z$Nm`(RS{z)=Xy5^(eP(2%}|CI>#iQI$E$~rvy9i~7@grz6|v9wJg!CO77J;HGQ`N( zsCVLn<40M>(orpXw~%+Jir8oD*s1S)uU2qZ$`B)?-s{9Ojv4nZZbonR^A1%J`-}(X z_%f`Hkf97Q&rzOzn4RN;?W+GR@4&98BK8?i?c{G43JK2v6&R{mkA7(>%h7y`;6c7h2+OkEp;eEjEsJ1ZF1AjUA9^b#(9UTh<%3DJYmh1 zAx6g5ZgbKx&RNY9)|@J=r7B{d@zGBGD(ggLh>*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIaDg>7?1$+suuXC>HjZ}4TP$f0 zW1ljT0khAZNpS$NL27a9fT;rM2C+dV!Ax%evyf$AY>>Iv7H5EU!0Z6qgP{Xi6^sqD z17bc%AF>RL4YLE}KbRf3b-+}Cbi+af?vMR2J76*}RUmVb!wt6%WK}RW%pY)F;4ndU T33}+l{DEBua_GYBfam}K`(B^d diff --git a/assets/model/turbine_valve_inlet_joystick.stl b/assets/model/turbine_valve_inlet_joystick.stl deleted file mode 100644 index 7411f74e22c9c823e3e5569216aef5c3915a4da5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2384 zcmbVOF>6y{6#X1r90Fn;oGh+lC~BpO_B{lN6hVaIBB@%M7C~(d4q^sFlPGlQs3294 z4*mcUQcK<-s6)j;EVNZO!9j2p9qK*rdnY*`FH^JRz`5t1_ucQ_``)>GbFg=t-vo|ZZrz+JW$BRS7qi!d^qKQV|l}6hGwFvr;Yt6X4I2r%CG!hZtIWra=8*9b) z%abv%bB9c^(nq0D#K`2_;;BN^-W*Rolp#jm`B$y@#;5C<$M=y!w6T>}XcV#cn6c=E zlZDhn8De-W{A0XA zmr=;2QN-Tkw<-3l`-xJ9nCIxtxy@k08Dtc4!H-eI-Xp73g!xd0nD^1!S6Quc3RIU- z#NGqB{jVPEKJ+ekEqV<57=Db#e?8dFxPL0>kyj|A=U_$h3T2?+E!uY6J(STZ z==q#`v$T4G9?IyM^l5t@+uIL*D9A4=Nlj5mE6UGRaLP%|OGz!#HPJKBGh!eIaDg>7?1$;)x?b&IY#i;7w^-61 z#y({v17@E+li~nkgVf^I0aFFi4Pt{#f|=d`W+BVK*dTLv$Tfm>!0Z6qgP{Xi6^sqD z17bc%AF>RL4YLE}KbRf3b-+}Cbi+af?vMR2J76*}RUmVb!wt6%WK}RW%pY)F;4ndU T33}+l{DEBua_GYBfam}KLD-x` diff --git a/assets/scene.blend b/assets/scene.blend index b1a4ede..47acb2d 100644 --- a/assets/scene.blend +++ b/assets/scene.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a87cc44b5cf761be0decb7630a2ec95117236ff5e7ad4aded6c0ef70cfc440ae -size 11918805 +oid sha256:f52d92d7183e179115b962150686f0941375e7b1c48e947ab602b8524f92da8a +size 10202465 diff --git a/assets/scene.glb b/assets/scene.glb index 3b115cd..27de43d 100644 --- a/assets/scene.glb +++ b/assets/scene.glb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cabb817503128f7224435427da791afdcb2b2efe33b8ac6c4bc6ea5d8a50cac6 -size 3369184 +oid sha256:2de0ac1e7b1469a499270a6b4df4487e8a6c8d0972fd3152a2bc5a515b6a4ae3 +size 2835508 diff --git a/assets/shader/light.fsh b/assets/shader/light.fsh index 90a7060..464c614 100644 --- a/assets/shader/light.fsh +++ b/assets/shader/light.fsh @@ -8,6 +8,6 @@ uniform float far_plane; void main() { float distance = length(frag_pos); - gl_FragDepth = distance / far_plane + 1e-4f; + gl_FragDepth = distance / far_plane; } diff --git a/assets/shader/light.gsh b/assets/shader/light.gsh index 28101d0..2e66648 100644 --- a/assets/shader/light.gsh +++ b/assets/shader/light.gsh @@ -7,11 +7,12 @@ layout (triangle_strip, max_vertices=18) out; uniform mat4 shadow_mats[6]; in float emissive[]; +in float base_transparency[]; out vec3 frag_pos; void main() { - if(emissive[0] > 0) return; + if(emissive[0] > 0 || base_transparency[0] > 0) return; for(int i = 0; i < 6; i++) { diff --git a/assets/shader/light.vsh b/assets/shader/light.vsh index 4e3357e..f2f3d45 100644 --- a/assets/shader/light.vsh +++ b/assets/shader/light.vsh @@ -2,16 +2,19 @@ #version 460 core layout (location = 2) in vec4 aPos; +layout (location = 4) in vec4 aColour; layout (location = 5) in vec3 aMaterial; uniform mat4 model; uniform mat4 camera; out float emissive; +out float base_transparency; void main() { gl_Position = camera * model * aPos; + base_transparency = 1.f - aColour.a; emissive = aMaterial[2]; } diff --git a/assets/shader/main.fsh b/assets/shader/main.fsh index 72939f2..f4c3056 100644 --- a/assets/shader/main.fsh +++ b/assets/shader/main.fsh @@ -2,23 +2,7 @@ #version 460 core #extension GL_ARB_bindless_texture : require -const float PI = 3.141592; -const float Epsilon = 0.00001; - -// Constant normal incidence Fresnel factor for all dielectrics. -const vec3 Fdielectric = vec3(0.04); - -const int SampleOffsetsLen = 8; -const vec3 SampleOffsets[SampleOffsetsLen] = { - vec3(-1.f,-1.f,-1.f), - vec3(-1.f,-1.f, 1.f), - vec3(-1.f, 1.f,-1.f), - vec3(-1.f, 1.f, 1.f), - vec3( 1.f,-1.f,-1.f), - vec3( 1.f,-1.f, 1.f), - vec3( 1.f, 1.f,-1.f), - vec3( 1.f, 1.f, 1.f), -}; +const float PI = 3.141592f; in VS_OUT { vec3 normal; @@ -55,18 +39,18 @@ uniform bool shadows_enabled; vec3 FresnelSchlick(float cosTheta, vec3 F0) { - return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); + return F0 + (1.f - F0) * pow(clamp(1.f - cosTheta, 0.f, 1.f), 5.f); } float DistributionGGX(vec3 N, vec3 H, float roughness) { float a = roughness*roughness; float a2 = a*a; - float NdotH = max(dot(N, H), 0.0); + float NdotH = max(dot(N, H), 0.f); float NdotH2 = NdotH*NdotH; float num = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); + float denom = (NdotH2 * (a2 - 1.f) + 1.f); denom = PI * denom * denom; return num / denom; @@ -74,19 +58,19 @@ float DistributionGGX(vec3 N, vec3 H, float roughness) float GeometrySchlickGGX(float NdotV, float roughness) { - float r = (roughness + 1.0); - float k = (r*r) / 8.0; + float r = (roughness + 1.f); + float k = (r*r) / 8.f; float num = NdotV; - float denom = NdotV * (1.0 - k) + k; + float denom = NdotV * (1.f - k) + k; return num / denom; } float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { - float NdotV = max(dot(N, V), 0.0); - float NdotL = max(dot(N, L), 0.0); + float NdotV = max(dot(N, V), 0.f); + float NdotL = max(dot(N, L), 0.f); float ggx2 = GeometrySchlickGGX(NdotV, roughness); float ggx1 = GeometrySchlickGGX(NdotL, roughness); @@ -114,6 +98,8 @@ vec3 sRGB_To_LinRGB(vec3 c) void main() { vec4 albedo = texture2D(frag_tex, vin.tex_pos) * vin.colour; + if(albedo.a == 0.f) discard; + vec3 albedo_lin = sRGB_To_LinRGB(albedo.rgb); float roughness = vin.material[0]; @@ -123,10 +109,10 @@ void main() vec3 N = normalize(vin.normal); vec3 V = normalize(camera_pos - vin.pos.xyz); - vec3 F0 = vec3(0.04); + vec3 F0 = vec3(0.04f); F0 = mix(F0, albedo_lin, metalness); - vec3 Lo = vec3(0.0); + vec3 Lo = vec3(0.0f); for(int i = 0; i < lights_count; i++) { Light l = lights[i]; @@ -141,38 +127,35 @@ void main() // cook-torrance brdf float NDF = DistributionGGX(N, H, roughness); float G = GeometrySmith(N, V, L, roughness); - vec3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); + vec3 F = FresnelSchlick(max(dot(H, V), 0.f), F0); vec3 kS = F; - vec3 kD = vec3(1.0) - kS; - kD *= 1.0 - metalness; + vec3 kD = vec3(1.f) - kS; + kD *= 1.f - metalness; vec3 numerator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001; + float denominator = 4.f * max(dot(N, V), 0.f) * max(dot(N, L), 0.f) + 1e-4f; vec3 specular = numerator / denominator; - float amount = 0; + float light_m; + float spec_m; if(shadows_enabled) { - float texel_size = 1.f / textureSize(shadow_maps[i], 0)[0]; - - for(int j = 0; j < SampleOffsetsLen; j++) - { - amount += ((texture(shadow_maps[i], -L + SampleOffsets[j] * texel_size).r * far_plane > d) ? 1.f : 0.5f); - } - - amount /= SampleOffsetsLen; + float max_d = texture(shadow_maps[i], -L).r * far_plane + 1e-2f; + spec_m = max_d > d ? 1.f : 0.f; + light_m = spec_m * 0.25f + 0.75f; } else { - amount = 1.f; + light_m = 1.f; + spec_m = 1.f; } // add to outgoing radiance Lo - float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo_lin / PI + specular) * radiance * NdotL * amount; + float NdotL = max(dot(N, L), 0.f); + Lo += (kD * albedo_lin / PI + specular * spec_m) * radiance * NdotL * light_m; } vec3 ambient = vec3(0.03f) * albedo_lin * brightness; @@ -181,6 +164,5 @@ void main() light = mix(light, albedo.rgb, luminance); frag_colour = vec4(light, albedo.a); - if(frag_colour.a == 0.f) discard; } diff --git a/src/graphics/camera.cpp b/src/graphics/camera.cpp index 02e500c..4595953 100644 --- a/src/graphics/camera.cpp +++ b/src/graphics/camera.cpp @@ -79,9 +79,9 @@ glm::vec<3, double> Camera::get_pos() return pos; } -void Camera::init() +void Camera::init(const Model& model) { - collision_scene.load_model("../assets/model", "scene_collisions.stl"); + collision_scene = model.load("collision"); } void Camera::update(double dt) diff --git a/src/graphics/camera.hpp b/src/graphics/camera.hpp index aab31c0..8da9d6f 100644 --- a/src/graphics/camera.hpp +++ b/src/graphics/camera.hpp @@ -5,6 +5,7 @@ #include #include "../system.hpp" +#include "mesh/model.hpp" namespace Sim::Graphics::Camera { @@ -18,7 +19,7 @@ double get_yaw(); Json::Value serialize(); void load(const Json::Value& node); -void init(); +void init(const Model& model); void rotate(double pitch, double yaw); void move(double x, double y, double z); void update(double dt); diff --git a/src/graphics/mesh/gllight.cpp b/src/graphics/mesh/gllight.cpp index 7e98d5a..38eeae3 100644 --- a/src/graphics/mesh/gllight.cpp +++ b/src/graphics/mesh/gllight.cpp @@ -14,7 +14,7 @@ using namespace Sim::Graphics; static glm::mat4 shadow_mats[6]; -GLLight::GLLight(Light light) : light(light), size(4096) +GLLight::GLLight(Light light) : light(light), size(1024) { glGenTextures(1, &id); glBindTexture(GL_TEXTURE_CUBE_MAP, id); @@ -53,8 +53,6 @@ GLLight::GLLight(GLLight&& o) : light(o.light), size(o.size) GLLight::~GLLight() { - std::cout << "Destructor called for " << fbo << ":" << id << ":" << handle << "\n"; - if(fbo) glDeleteFramebuffers(1, &fbo); if(id) diff --git a/src/graphics/mesh/mesh.hpp b/src/graphics/mesh/mesh.hpp index 0ad861d..50d603f 100644 --- a/src/graphics/mesh/mesh.hpp +++ b/src/graphics/mesh/mesh.hpp @@ -17,17 +17,13 @@ namespace Sim::Graphics struct Mesh { - std::unordered_map mat_nodes; std::vector vertices; std::vector indices; - std::vector lights; Mesh(); void set_vertices(const Arrays::Vertex* data, size_t size); void set_indices(const unsigned int* data, size_t size); - void load_model(std::string base, std::string path); - void load_model(std::string path); void load_text(const char* text, double size); void load_text(const char* text, double size, glm::vec2 align); void add(const Mesh& o, glm::mat4 mat); diff --git a/src/graphics/mesh/model.cpp b/src/graphics/mesh/model.cpp index 66ee752..838b428 100644 --- a/src/graphics/mesh/model.cpp +++ b/src/graphics/mesh/model.cpp @@ -2,10 +2,6 @@ #include #include -#include -#include -#include -#include #include #include @@ -15,6 +11,7 @@ #include "mesh.hpp" #include "arrays.hpp" #include "texture.hpp" +#include "model.hpp" #include "../../util/streams.hpp" using namespace Sim::Graphics; @@ -24,11 +21,9 @@ struct ProcState unsigned int offset = 0; std::string base; - std::vector lights; std::vector vertices; std::vector indices; std::unordered_map handles; - std::unordered_map mat_nodes; }; static unsigned int proc_texture(const ProcState& state, aiMaterial* mat, const aiScene* scene, aiTextureType type, int index) @@ -177,7 +172,7 @@ static void proc_mesh(ProcState& state, glm::mat4 mat, aiMesh* mesh, const aiSce state.offset += mesh->mNumVertices; } -glm::mat4 get_mat(aiMatrix4x4 m) +glm::mat4 convert_mat(aiMatrix4x4 m) { return { m.a1, m.a2, m.a3, m.a4, @@ -187,21 +182,38 @@ glm::mat4 get_mat(aiMatrix4x4 m) }; } -static void proc_node(ProcState& state, glm::mat4 mat, aiNode* node, const aiScene* scene) +bool starts_with(const char* base, const char* check) { - mat = get_mat(node->mTransformation) * mat; - std::string name(node->mName.C_Str()); - state.mat_nodes[name] = mat; - - for(size_t i = 0; i < node->mNumMeshes; i++) + while(base[0] != '\0' && check[0] != '\0') { - aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; - proc_mesh(state, mat, mesh, scene); + if(base[0] != check[0]) + { + return false; + } + + base++; + check++; + } + + return (check[0] == '\0'); +} + +static void proc_node(ProcState& state, glm::mat4 mat, aiNode* node, const aiScene* scene, const char* search) +{ + mat = convert_mat(node->mTransformation) * mat; + + if(starts_with(node->mName.C_Str(), search)) + { + for(size_t i = 0; i < node->mNumMeshes; i++) + { + aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + proc_mesh(state, mat, mesh, scene); + } } for(size_t i = 0; i < node->mNumChildren; i++) { - proc_node(state, mat, node->mChildren[i], scene); + proc_node(state, mat, node->mChildren[i], scene, search); } } @@ -214,65 +226,92 @@ static unsigned int proc_embedded_texture(aiTexture* tex) return Texture::load_mem((unsigned char*)tex->pcData, tex->mWidth); } - // swizzle each pixel to get RGBA + std::vector> pixels; + pixels.reserve(tex->mWidth * tex->mHeight); + + // convert image to get RGBA for(int i = 0; i < tex->mWidth * tex->mHeight; i++) { aiTexel t = tex->pcData[i]; - tex->pcData[i] = {t.r, t.g, t.b, t.a}; + pixels.push_back({t.r, t.g, t.b, t.a}); } - return Texture::load_mem((unsigned char*)tex->pcData, tex->mWidth, tex->mHeight, 4); + return Texture::load_mem(&pixels[0][0], tex->mWidth, tex->mHeight, 4); } -void Mesh::load_model(std::string path) +glm::mat4 get_transforms(const aiNode* node) { - load_model(".", path); -} + glm::mat4 mat(1); -void Mesh::load_model(std::string base, std::string filename) -{ - ProcState state {.base = base}; - std::string path = base + "/" + filename; - Assimp::Importer importer; - - const aiScene *scene = importer.ReadFile(path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs); - - std::cout << "Loaded model: " << path << "\n"; - - if(scene == nullptr) + while(node->mParent != nullptr) { - std::cerr << "AssImp: Error loading model\n"; - return; + mat = mat * convert_mat(node->mTransformation); + node = node->mParent; } + return mat; +} + +glm::mat4 Model::get_matrix(const char* name) const +{ + return get_transforms(scene->mRootNode->FindNode(name)); +} + +Model::Model(std::string base, std::string filename) : base(base) +{ + std::string path = base + "/" + filename; + scene = importer.ReadFile(path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs); + + textures.reserve(scene->mNumTextures); + for(int i = 0; i < scene->mNumTextures; i++) { aiTexture* tex = scene->mTextures[i]; unsigned int handle = proc_embedded_texture(tex); - state.handles[tex] = handle; + textures.push_back(handle); } - proc_node(state, glm::mat4(1), scene->mRootNode, scene); - for(int i = 0; i < scene->mNumLights; i++) { aiLight* light = scene->mLights[i]; - glm::mat4 mat = state.mat_nodes[light->mName.C_Str()]; + glm::mat4 mat = get_matrix(light->mName.C_Str()); auto [x, y, z] = light->mPosition; auto [r, g, b] = light->mColorDiffuse; glm::vec4 pos = glm::vec4(x, y, z, 1) * mat; - state.lights.push_back({ + lights.push_back({ glm::vec3(pos), {r, g, b}, }); } - - mat_nodes = std::move(state.mat_nodes); - vertices = std::move(state.vertices); - indices = std::move(state.indices); - lights = std::move(state.lights); +} + +Mesh Model::load(const char* name, glm::mat4 mat) const +{ + Mesh mesh; + ProcState state {.base = base}; + proc_node(state, mat, scene->mRootNode, scene, name); + + mesh.vertices = std::move(state.vertices); + mesh.indices = std::move(state.indices); + + return mesh; +} + +Mesh Model::load_root(glm::mat4 mat) const +{ + return load("", mat); +} + +Mesh Model::load(const char* name) const +{ + return load(name, glm::mat4(1)); +} + +Mesh Model::load_root() const +{ + return load("", glm::mat4(1)); } diff --git a/src/graphics/mesh/model.hpp b/src/graphics/mesh/model.hpp new file mode 100644 index 0000000..7c8323d --- /dev/null +++ b/src/graphics/mesh/model.hpp @@ -0,0 +1,42 @@ + +#pragma once + +#include "mesh.hpp" +#include "light.hpp" + +#include +#include + +#include + +#include +#include +#include +#include + +namespace Sim::Graphics +{ + +class Model +{ + std::string base; + Assimp::Importer importer; + const aiScene* scene; + +public: + + std::vector textures; + std::vector lights; + + Model(std::string base, std::string filename); + Model(const Model&) = delete; + + Mesh load_root() const; + Mesh load_root(glm::mat4 mat) const; + Mesh load(const char* name) const; + Mesh load(const char* name, glm::mat4 mat) const; + glm::mat4 get_matrix(const char* name) const; +}; + +}; + diff --git a/src/graphics/monitor/core.cpp b/src/graphics/monitor/core.cpp index 6ac1370..fbae7e2 100644 --- a/src/graphics/monitor/core.cpp +++ b/src/graphics/monitor/core.cpp @@ -120,26 +120,26 @@ Core::Core() { } -void Core::init(Mesh& rmesh) +void Core::init(const Model& model, Mesh& rmesh) { - Mesh mesh; + Mesh mesh = model.load("translation_monitor_3"); mat = Locations::monitors[2]; mesh.load_text("Reactor Core", 0.04); rmesh.add(mesh, mat); - m_buttons[0].load_model("../assets/model/", "reactor_core_button1.stl"); - m_buttons[1].load_model("../assets/model/", "reactor_core_button2.stl"); - m_buttons[2].load_model("../assets/model/", "reactor_core_button3.stl"); - m_buttons[3].load_model("../assets/model/", "reactor_core_button4.stl"); - m_buttons[4].load_model("../assets/model/", "reactor_core_button5.stl"); - m_buttons[5].load_model("../assets/model/", "reactor_core_button6.stl"); - m_buttons[6].load_model("../assets/model/", "reactor_core_button7.stl"); - m_buttons[7].load_model("../assets/model/", "reactor_core_button8.stl"); - m_buttons[8].load_model("../assets/model/", "reactor_core_button9.stl"); - m_joystick.load_model("../assets/model/", "reactor_core_joystick.stl"); - m_monitor.load_model("../assets/model/", "reactor_core_input.stl"); - m_scram.load_model("../assets/model/", "reactor_core_scram.stl"); + m_buttons[0] = model.load("click_numpad_1"); + m_buttons[1] = model.load("click_numpad_2"); + m_buttons[2] = model.load("click_numpad_3"); + m_buttons[3] = model.load("click_numpad_4"); + m_buttons[4] = model.load("click_numpad_5"); + m_buttons[5] = model.load("click_numpad_6"); + m_buttons[6] = model.load("click_numpad_7"); + m_buttons[7] = model.load("click_numpad_8"); + m_buttons[8] = model.load("click_numpad_9"); + m_joystick = model.load("click_reactor_joystick"); + m_monitor = model.load("translation_monitor_3"); + m_scram = model.load("click_scram"); } static Mesh add_dot(glm::mat4 model_mat, glm::vec4 colour) diff --git a/src/graphics/monitor/core.hpp b/src/graphics/monitor/core.hpp index bd83e52..61a7993 100644 --- a/src/graphics/monitor/core.hpp +++ b/src/graphics/monitor/core.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../mesh/glmesh.hpp" +#include "../mesh/model.hpp" namespace Sim::Graphics::Monitor { @@ -17,7 +17,7 @@ class Core public: Core(); - void init(Mesh& rmesh); + void init(const Model& model, Mesh& rmesh); void update(double dt); void remesh_slow(Mesh& rmesh); void remesh_fast(Mesh& rmesh); diff --git a/src/graphics/monitor/primary_loop.cpp b/src/graphics/monitor/primary_loop.cpp index 8d9822b..8c6dd62 100644 --- a/src/graphics/monitor/primary_loop.cpp +++ b/src/graphics/monitor/primary_loop.cpp @@ -55,7 +55,7 @@ PrimaryLoop::PrimaryLoop() } -void PrimaryLoop::init(Mesh& rmesh) +void PrimaryLoop::init(const Model& model, Mesh& rmesh) { mat = Locations::monitors[3]; @@ -77,15 +77,15 @@ void PrimaryLoop::init(Mesh& rmesh) mesh.load_text(ss.str().c_str(), 0.04); rmesh.add(mesh, mat); - g_switch_pump.load_model("../assets/model", "pump_switch_1.glb"); - g_switch_bypass.load_model("../assets/model", "turbine_valve_bypass_switch.glb"); - g_switch_inlet.load_model("../assets/model", "turbine_valve_inlet_switch.glb"); + g_switch_pump = model.load("visual_pump_switch_1"); + g_switch_bypass = model.load("visual_bypass_switch"); + g_switch_inlet = model.load("visual_inlet_switch"); - m_joystick_turbine_bypass.load_model("../assets/model", "turbine_valve_bypass_joystick.stl"); - m_joystick_turbine_inlet.load_model("../assets/model", "turbine_valve_inlet_joystick.stl"); - m_switch_pump.load_model("../assets/model", "pump_switch_click_1.stl"); - m_switch_bypass.load_model("../assets/model", "turbine_valve_bypass_switch_click.stl"); - m_switch_inlet.load_model("../assets/model", "turbine_valve_inlet_switch_click.stl"); + m_joystick_turbine_bypass = model.load("click_bypass_joystick"); + m_joystick_turbine_inlet = model.load("click_inlet_joystick"); + m_switch_pump = model.load("click_pump_switch_1"); + m_switch_bypass = model.load("click_bypass_switch"); + m_switch_inlet = model.load("click_inlet_switch"); } void PrimaryLoop::update(double dt) diff --git a/src/graphics/monitor/primary_loop.hpp b/src/graphics/monitor/primary_loop.hpp index d9d19e1..f9464a7 100644 --- a/src/graphics/monitor/primary_loop.hpp +++ b/src/graphics/monitor/primary_loop.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../mesh/glmesh.hpp" +#include "../mesh/model.hpp" namespace Sim::Graphics::Monitor { @@ -24,7 +24,7 @@ class PrimaryLoop public: PrimaryLoop(); - void init(Mesh& rmesh); + void init(const Model& model, Mesh& rmesh); void update(double dt); void remesh_slow(Mesh& rmesh); void remesh_fast(Mesh& rmesh); diff --git a/src/graphics/monitor/secondary_loop.cpp b/src/graphics/monitor/secondary_loop.cpp index c2b0d12..78082d5 100644 --- a/src/graphics/monitor/secondary_loop.cpp +++ b/src/graphics/monitor/secondary_loop.cpp @@ -21,7 +21,7 @@ SecondaryLoop::SecondaryLoop() } -void SecondaryLoop::init(Mesh& rmesh) +void SecondaryLoop::init(const Model& model, Mesh& rmesh) { mat = Locations::monitors[5]; @@ -38,13 +38,13 @@ void SecondaryLoop::init(Mesh& rmesh) mesh.load_text(ss.str().c_str(), 0.04); rmesh.add(mesh, mat); - g_switch_2.load_model("../assets/model", "pump_switch_2.glb"); - g_switch_3.load_model("../assets/model", "pump_switch_3.glb"); + g_switch_2 = model.load("visual_pump_switch_2"); + g_switch_3 = model.load("visual_pump_switch_3"); - m_joystick_turbine_bypass.load_model("../assets/model", "turbine_valve_bypass_joystick.stl"); - m_joystick_turbine_inlet.load_model("../assets/model", "turbine_valve_inlet_joystick.stl"); - m_switch_2.load_model("../assets/model", "pump_switch_click_2.stl"); - m_switch_3.load_model("../assets/model", "pump_switch_click_3.stl"); + m_joystick_turbine_bypass = model.load("click_bypass_joystick"); + m_joystick_turbine_inlet = model.load("click_inlet_joystick"); + m_switch_2 = model.load("click_pump_switch_2"); + m_switch_3 = model.load("click_pump_switch_3"); } void SecondaryLoop::update(double dt) diff --git a/src/graphics/monitor/secondary_loop.hpp b/src/graphics/monitor/secondary_loop.hpp index 9f1e3df..c1c7d72 100644 --- a/src/graphics/monitor/secondary_loop.hpp +++ b/src/graphics/monitor/secondary_loop.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../mesh/glmesh.hpp" +#include "../mesh/model.hpp" namespace Sim::Graphics::Monitor { @@ -21,7 +21,7 @@ class SecondaryLoop public: SecondaryLoop(); - void init(Mesh& rmesh); + void init(const Model& model, Mesh& rmesh); void update(double dt); void remesh_slow(Mesh& rmesh); void remesh_fast(Mesh& rmesh); diff --git a/src/graphics/monitor/turbine.cpp b/src/graphics/monitor/turbine.cpp index 8621949..c8e0eeb 100644 --- a/src/graphics/monitor/turbine.cpp +++ b/src/graphics/monitor/turbine.cpp @@ -21,7 +21,7 @@ Turbine::Turbine() } -void Turbine::init(Mesh& rmesh) +void Turbine::init(const Model& model, Mesh& rmesh) { mat = Locations::monitors[4]; @@ -37,12 +37,12 @@ void Turbine::init(Mesh& rmesh) mesh.load_text("Synchroscope", 0.04); rmesh.add(mesh, glm::translate(mat, glm::vec3(0, 0.6, 0))); - mesh.load_model("../assets/model", "synchroscope_dial.glb"); + mesh = model.load("visual_synchroscope_dial"); gm_synchroscope_dial.bind(); gm_synchroscope_dial.set(mesh, GL_STATIC_DRAW); - g_switch_breaker.load_model("../assets/model", "turbine_breaker_switch.glb"); - m_switch_breaker.load_model("../assets/model", "turbine_breaker_switch_click.stl"); + g_switch_breaker = model.load("visual_breaker_switch"); + m_switch_breaker = model.load("click_breaker_switch"); } void Turbine::update(double dt) @@ -61,7 +61,6 @@ void Turbine::update(double dt) if(m_switch_breaker.check_focus()) sys.loop.generator.breaker_closed = !sys.loop.generator.breaker_closed; - } void Turbine::remesh_slow(Mesh& rmesh) diff --git a/src/graphics/monitor/turbine.hpp b/src/graphics/monitor/turbine.hpp index 436249a..659d1f3 100644 --- a/src/graphics/monitor/turbine.hpp +++ b/src/graphics/monitor/turbine.hpp @@ -1,6 +1,7 @@ #pragma once +#include "../mesh/model.hpp" #include "../mesh/glmesh.hpp" namespace Sim::Graphics::Monitor @@ -17,7 +18,7 @@ class Turbine public: Turbine(); - void init(Mesh& rmesh); + void init(const Model& model, Mesh& rmesh); void update(double dt); void remesh_slow(Mesh& rmesh); void remesh_fast(Mesh& rmesh); diff --git a/src/graphics/monitor/vessel.cpp b/src/graphics/monitor/vessel.cpp index 18a6208..8ffea21 100644 --- a/src/graphics/monitor/vessel.cpp +++ b/src/graphics/monitor/vessel.cpp @@ -20,7 +20,7 @@ Vessel::Vessel() } -void Vessel::init(Mesh& rmesh) +void Vessel::init(const Model& model, Mesh& rmesh) { mat = Locations::monitors[1]; diff --git a/src/graphics/monitor/vessel.hpp b/src/graphics/monitor/vessel.hpp index 6254d68..c8e078f 100644 --- a/src/graphics/monitor/vessel.hpp +++ b/src/graphics/monitor/vessel.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../mesh/glmesh.hpp" +#include "../mesh/model.hpp" namespace Sim::Graphics::Monitor { @@ -13,7 +13,7 @@ class Vessel public: Vessel(); - void init(Mesh& rmesh); + void init(const Model& model, Mesh& rmesh); void update(double dt); void remesh_slow(Mesh& rmesh); void remesh_fast(Mesh& rmesh); diff --git a/src/graphics/window.cpp b/src/graphics/window.cpp index c444cab..3dce591 100644 --- a/src/graphics/window.cpp +++ b/src/graphics/window.cpp @@ -25,6 +25,7 @@ #include "monitor/secondary_loop.hpp" #include "monitor/turbine.hpp" #include "mesh/texture.hpp" +#include "mesh/model.hpp" #include "mesh/gllight.hpp" #include "../system.hpp" #include "../util/streams.hpp" @@ -124,7 +125,6 @@ void Window::create() Mouse::init(); Resize::init(); Texture::init(); - Camera::init(); Font::init(); UI::init(); @@ -134,45 +134,30 @@ void Window::create() Sim::System& sys = *System::active; Mesh m_scene; - m_scene.load_model("../assets", "scene.glb"); - - m_scene.lights[0].pos.x = 6; - m_scene.lights[1].pos.x = 0; - - // find the floor parts of the model and set them slightly transparent - for(int i = 0; i < m_scene.indices.size(); i += 3) - { - Arrays::Vertex& v1 = m_scene.vertices[m_scene.indices[i]]; - Arrays::Vertex& v2 = m_scene.vertices[m_scene.indices[i + 1]]; - Arrays::Vertex& v3 = m_scene.vertices[m_scene.indices[i + 2]]; - - if(v1.pos.z <= 0 && v2.pos.z <= 0 && v3.pos.z <= 0) - { - v1.colour.w = 0.95; - v2.colour.w = 0.95; - v3.colour.w = 0.95; - } - } + Model model("../assets", "scene.glb"); + m_scene = model.load("scene"); + + Camera::init(model); // send all the light data glGenBuffers(1, &ssbo_lights); glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_lights); - glBufferData(GL_SHADER_STORAGE_BUFFER, m_scene.lights.size() * sizeof(m_scene.lights[0]), &m_scene.lights[0], GL_STATIC_DRAW); + glBufferData(GL_SHADER_STORAGE_BUFFER, model.lights.size() * sizeof(model.lights[0]), &model.lights[0], GL_STATIC_DRAW); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo_lights); - glUniform1i(Shader::MAIN["lights_count"], m_scene.lights.size()); + glUniform1i(Shader::MAIN["lights_count"], model.lights.size()); - monitor_core.init(m_scene); - monitor_vessel.init(m_scene); - monitor_primary_loop.init(m_scene); - monitor_secondary_loop.init(m_scene); - monitor_turbine.init(m_scene); + monitor_core.init(model, m_scene); + monitor_vessel.init(model, m_scene); + monitor_primary_loop.init(model, m_scene); + monitor_secondary_loop.init(model, m_scene); + monitor_turbine.init(model, m_scene); gm_scene.bind(); gm_scene.set(m_scene, GL_STATIC_DRAW); glfwShowWindow(win); -/* + // setup lighting and prerender shadows Shader::LIGHT.load("../assets/shader", "light.vsh", "light.gsh", "light.fsh"); glUniform1f(Shader::LIGHT["far_plane"], 100.0f); @@ -180,28 +165,24 @@ void Window::create() std::vector light_handles; - for(int i = 0; i < m_scene.lights.size(); i++) + for(int i = 0; i < model.lights.size(); i++) { - GLLight light(m_scene.lights[i]); + GLLight light(model.lights[i]); light.render(); light_handles.push_back(light.handle); lights.push_back(std::move(light)); } - for(int i = 0; i < lights.size(); i++) - { - std::cout << "handle " << i << ": " << light_handles[i] << "\n"; - } - - Shader::MAIN.use();*/ + Shader::MAIN.use(); glUniform1f(Shader::MAIN["far_plane"], 100.0f); + glUniform1i(Shader::MAIN["shadows_enabled"], 1); -/* // send all the light shadow map handles + // send all the light shadow map handles glGenBuffers(1, &ssbo_shadow_maps); glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_shadow_maps); glBufferData(GL_SHADER_STORAGE_BUFFER, light_handles.size() * sizeof(light_handles[0]), &light_handles[0], GL_STATIC_DRAW); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssbo_shadow_maps);*/ + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssbo_shadow_maps); } void update_slow() @@ -287,32 +268,19 @@ void Window::render() glm::vec3 camera_pos = Camera::get_pos(); glm::mat4 mat_camera = Camera::get_matrix(); - mat_camera = glm::scale(mat_camera, {1, 1, -1}); - camera_pos.z *= -1; Shader::MAIN.use(); glm::vec3 brightness = glm::vec3(System::active->grid.get_light_intensity()); - glm::mat4 mat_projection = glm::perspective(glm::radians(90.0f), Resize::get_aspect(), 0.01f, 20.f); + glm::mat4 mat_projection = glm::perspective(glm::radians(90.0f), Resize::get_aspect(), 0.01f, 50.f); glUniformMatrix4fv(Shader::MAIN["projection"], 1, false, &mat_projection[0][0]); glUniformMatrix4fv(Shader::MAIN["camera"], 1, false, &mat_camera[0][0]); - glUniform3fv(Shader::MAIN["brightness"], 1, &brightness[0]); glUniform3fv(Shader::MAIN["camera_pos"], 1, &camera_pos[0]); - projection_matrix = mat_projection; + glUniform3fv(Shader::MAIN["brightness"], 1, &brightness[0]); + glFrontFace(GL_CCW); glClearColor(0, 0, 0, 1.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - glCullFace(GL_BACK); - glFrontFace(GL_CW); - - render_scene(); - - camera_pos.z *= -1; - mat_camera = Camera::get_matrix(); - glUniformMatrix4fv(Shader::MAIN["camera"], 1, false, &mat_camera[0][0]); - glUniform3fv(Shader::MAIN["camera_pos"], 1, &camera_pos[0]); - glClear(GL_DEPTH_BUFFER_BIT); - glFrontFace(GL_CCW); render_scene();