From 632300740d5d5930460dae7610614bbe8883277f Mon Sep 17 00:00:00 2001 From: saxonschmauderer Date: Sun, 30 Apr 2017 16:39:05 -0400 Subject: [PATCH 01/75] Fix for bug #1975 The change was made to the function that is executed when entering the world editor. The boolean variable for first person shooter was set to true, since the camera always defaults to first person on entering the world editor. On setting this boolean variable to be true, the correct camera setting will always be displayed on entering the world editor. This does not affect other camera labels. --- Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs index bc1905292..d1f93503a 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -1919,6 +1919,7 @@ function Editor::open(%this) %this.editorEnabled(); Canvas.setContent(EditorGui); + $isFirstPersonVar = true; EditorGui.syncCameraGui(); } @@ -2829,4 +2830,4 @@ function EditorDropdownSliderContainer::onMouseDown(%this) function EditorDropdownSliderContainer::onRightMouseDown(%this) { Canvas.popDialog(%this); -} \ No newline at end of file +} From 27347d9a5223d1485d7b474d4ab5cc67cbdda026 Mon Sep 17 00:00:00 2001 From: Johxz Date: Fri, 23 Jun 2017 19:19:48 -0500 Subject: [PATCH 02/75] snapTo Menu by Paul Weston --- .../worldEditor/scripts/menuHandlers.ed.cs | 58 +++++++++++++++++++ .../tools/worldEditor/scripts/menus.ed.cs | 25 +++++++- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.cs index f476ccaeb..90295db13 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.cs @@ -875,6 +875,64 @@ function EditorDropTypeMenu::setupDefaultState(%this) ////////////////////////////////////////////////////////////////////////// +function EditorSnapToMenu::onSelectItem(%this, %id, %text) +{ + EWorldEditor.SnapTo(%id); +} + +function EditorSnapToMenu::setupDefaultState(%this) +{ + Parent::setupDefaultState(%this); +} + +function WorldEditor::snapTo(%this, %id) +{ + if(%this.getSelectionSize() > 2) + { + error("Please select two objects before selecting a Snap To function."); + return; + } + + %objTarget = %this.getSelectedObject(0); + %objToSnap = %this.getSelectedObject(%this.getSelectionSize()-1); + + switch$(%id) + { + case 0: + %objToSnap.setTransform(setWord(%objToSnap.getTransform(), 0, getWord(%objTarget.getTransform(), 0))); + case 1: + %objTargetXEdge = getWord(%objTarget.getTransform(), 0) + getWord(%objTarget.getObjectBox(), 0); + %objToSnapXEdge = %objTargetXEdge - getWord(%objToSnap.getObjectBox(), 3); + %objToSnap.setTransform(setWord(%objToSnap.getTransform(), 0, %objToSnapXEdge)); + case 2: + %objTargetXEdge = getWord(%objTarget.getTransform(), 0) + getWord(%objTarget.getObjectBox(), 3); + %objToSnapXEdge = %objTargetXEdge - getWord(%objToSnap.getObjectBox(), 0); + %objToSnap.setTransform(setWord(%objToSnap.getTransform(), 0, %objToSnapXEdge)); + case 3: + %objToSnap.setTransform(setWord(%objToSnap.getTransform(), 1, getWord(%objTarget.getTransform(), 1))); + case 4: + %objTargetXEdge = getWord(%objTarget.getTransform(), 1) + getWord(%objTarget.getObjectBox(), 1); + %objToSnapXEdge = %objTargetXEdge - getWord(%objToSnap.getObjectBox(), 4); + %objToSnap.setTransform(setWord(%objToSnap.getTransform(), 1, %objToSnapXEdge)); + case 5: + %objTargetXEdge = getWord(%objTarget.getTransform(), 1) + getWord(%objTarget.getObjectBox(), 4); + %objToSnapXEdge = %objTargetXEdge - getWord(%objToSnap.getObjectBox(), 1); + %objToSnap.setTransform(setWord(%objToSnap.getTransform(), 1, %objToSnapXEdge)); + case 6: + %objToSnap.setTransform(setWord(%objToSnap.getTransform(), 2, getWord(%objTarget.getTransform(), 2))); + case 7: + %objTargetXEdge = getWord(%objTarget.getTransform(), 2) + getWord(%objTarget.getObjectBox(), 2); + %objToSnapXEdge = %objTargetXEdge - getWord(%objToSnap.getObjectBox(), 5); + %objToSnap.setTransform(setWord(%objToSnap.getTransform(), 2, %objToSnapXEdge)); + case 8: + %objTargetXEdge = getWord(%objTarget.getTransform(), 2) + getWord(%objTarget.getObjectBox(), 5); + %objToSnapXEdge = %objTargetXEdge - getWord(%objToSnap.getObjectBox(), 2); + %objToSnap.setTransform(setWord(%objToSnap.getTransform(), 2, %objToSnapXEdge)); + } +} + +////////////////////////////////////////////////////////////////////////// + function EditorAlignBoundsMenu::onSelectItem(%this, %id, %text) { // Have the editor align all selected objects by the selected bounds. diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs index dbe978cab..6ea188239 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs @@ -230,7 +230,30 @@ function EditorGui::buildMenus(%this) item[16] = "Jump to Bookmark" TAB %this.cameraBookmarksMenu; }; %this.menuBar.insert(%cameraMenu, %this.menuBar.getCount()); - + + // Snap Menu + %snapToMenu = new PopupMenu() + { + superClass = "MenuBuilder"; + class = "EditorSnapToMenu"; + + barTitle = "SnapTo"; + + // The onSelectItem() callback for this menu re-purposes the command field + // as the MenuBuilder version is not used. + item[0] = "Snap 2nd Object To 1st X" TAB "" TAB "X"; + item[1] = "Snap 2nd Object To 1st X+" TAB "" TAB "X+"; + item[2] = "Snap 2nd Object To 1st X-" TAB "" TAB "X-"; + item[3] = "Snap 2nd Object To 1st Y" TAB "" TAB "Y"; + item[4] = "Snap 2nd Object to 1st Y+" TAB "" TAB "Y+"; + item[5] = "Snap 2nd Object to 1st Y-" TAB "" TAB "Y-"; + item[6] = "Snap 2nd Object To 1st Z" TAB "" TAB "Z"; + item[7] = "Snap 2nd Object to 1st Z+" TAB "" TAB "Z+"; + item[8] = "Snap 2nd Object to 1st Z-" TAB "" TAB "Z-"; + + }; + %this.menuBar.insert(%snapToMenu, %this.menuBar.getCount()); + // Editors Menu %editorsMenu = new PopupMenu() { From 8a8300b231b68560f9a6980efdf6e531b1600179 Mon Sep 17 00:00:00 2001 From: Johxz Date: Mon, 10 Jul 2017 19:24:00 -0500 Subject: [PATCH 03/75] removed unnecessary shapes from fps module --- .../Modules/FPSGameplay/art/shapes/noshape.dts | Bin 18389 -> 0 bytes .../Modules/FPSGameplay/art/shapes/noshape.mb | Bin 61648 -> 0 bytes .../FPSGameplay/art/shapes/unit_capsule.dts | Bin 2709 -> 0 bytes .../FPSGameplay/art/shapes/unit_cube.dts | Bin 1881 -> 0 bytes .../FPSGameplay/art/shapes/unit_sphere.dts | Bin 5345 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Templates/Modules/FPSGameplay/art/shapes/noshape.dts delete mode 100644 Templates/Modules/FPSGameplay/art/shapes/noshape.mb delete mode 100644 Templates/Modules/FPSGameplay/art/shapes/unit_capsule.dts delete mode 100644 Templates/Modules/FPSGameplay/art/shapes/unit_cube.dts delete mode 100644 Templates/Modules/FPSGameplay/art/shapes/unit_sphere.dts diff --git a/Templates/Modules/FPSGameplay/art/shapes/noshape.dts b/Templates/Modules/FPSGameplay/art/shapes/noshape.dts deleted file mode 100644 index a7a64cf1099e4247aecded23bec3923eb6e3a198..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18389 zcmeI43Aj~N6~`|EB8Z4)l3IwMQi?e|3#|+9na!G7QVtbG!4n)Iu|O>^R+f!4rJ)c^|L2G&Gu%CY#LW$+9f9-+!OI?)~rAJNoSV$i6Sn=a0S4UjMbu-us-r?s*R{ zyEblK@rxZAjpJYuY}IHqMuCoKtFwRq)BUo=Xi$zgF5mI`IfCKu;3s4D zY)`m-^}x(KSI@z2j=z2NoXB@)K6EZK`V}9(7-#rG+i0`~HHI-TRsnWwjU9379%sIx z<~DSUhY88i>J9(47!zST@Og6Dr)!JLIH@}(Wykik8gq~U^e+JkO8VnDtjcGLQsrgyu2(%8KQW?lRHl*cq}vt8dbz1wYF z|6s2+pce#-tG46+m6saO843{p5OIN)4Lt|rp99$w_P7O zrFT1xzlXI}o;;qRw(HXzv)=7=e>D!}(LGhJA$Gc7xj#JvS?{)D+vnt1tyAPQ+x5yB zdbit*v3)xCGLIoNp5OIN)4Q!41F=4)@%*lDn%-?)e?aS^@tDSK*Edb?c2O%#GnxCT{v*fp;xxm@3qD2Nzre5kKOi?lLz)&zK`~`*PnDx zPN&Xq@TI%Mm4$hE8JcfH%1(_+RtTx_m~MNZedt?TF7pRQ}MQM-!%q56m= zXVb>hiM86L@pSrK?>2LsGbyi+$6DYnS}CdVADm)6H)t#%dtu6KLMO&8A5dMS^` zTJ0+OUGKI&Q?+)=Gfb@ZSJCf!x0UmH*4oCCY|Sz6_ZUy=cfH%1)lokol9RucAn>`rA5E%-PW8mKIPGKGF-j&e%HILG1&V{)Zw%ja(zzY@fz;>u*umz zr8^$gsWdjLrA1EHyUiR2Cg=6>SgWN)9d^CjaA%!zw6tkce|+?5cSP8p5OIt z)4QFXJ*%0WoHhEkp67TsH(TTB)LZX2yNETt#?y&qE}eSo{bsvfa}2%PP1OLci=Hdf zxb6D3>D^8>fNQsv$24xczO9;(^=>zZ*38IRqfbBgXzjSJ+i5(pUp%MTu1{mgdbiW~ zWB+;`Hrw@Sj#=+^Q+-iy)kaRUUEemn+f9v8*Va0l#%qfa@Oe6Gnw^n zYdoELtNRc+&33)U5PG*Y{!YC$jpuj0<`{ann_e?b)qD#phIKuSdA;!=c2z-5BogFJG1Ir zCsz8Xx8AR3M)T2i-IhMT8`sub&pA{dvE+<*=GuD8cvQ1u3?044+Bzn!=^mQALOg~GbInj5<7Hf~J%?z!T_uU7tOm8HssKIN?1q~}~dr_s3hqKi7$jxo5V^0(%OuBYe9 zq>uB`-XR z@plr|hF{l_KU%HNE=d=0rC;kJf3#Y`zNGKz>9JPpp>thF{%F(lkaQ7O`ZbOtlfG&- zo)eNj&P%_>A%C=uMt^^Q(nnnB*E-4{ZKKiCb7s; z#+7t=F1j!2ylT6;%CGsPIp=*-+0m!#hc53U#-n{0`$qGq&P#uzH}9j|rg;`|r9Z6; z{%B+0bmQ_q)A}S`-bcN$k7BHGUi#C0)4j_mZ?%6SuIsBbc^`4TO2>MqwTSc5pYBu2 z9lHMhy^}u9tG27F{0+um>0;l-dFj`BrhS@Q-KV~kKjKQi<{*Ex>G?_eh%5c+xk!4R zlcbCN7w1*m)#ZK4^HA;M*ne?e`ZdqAzjGV=GWK({U0vR%%(vRdJacJWabEg0Px+%w z^G*AWJ{|IL^mSV1gTIga8~Zf&XPmoVI{BlGeW~?`IQRGEeH*QG+K1gZo`-Y~qpkeP zU+H4s#d+!1Ji5<7l~?;P&EMLtuG*g(Po<0f7w4tFFYnuE(>zn&h^yN0YuwtG(ds^? z&&S*!@!{{w{%AGsiioS)@M|9ON2`3=msL!+4Zp4DN5vk5=)*B;csPsv?*_Tz9X(`!>>5)+i24~@_tZ%#D`z=NT0R2)p)co zyK$vo*O5P3t*hQ|yK$wzmHpA``qlo7xT+1m#wCBWy3g9b-MG@<%Km6I?gn(@s`&70 zzVb(_yw(1UxYDn2$RDldsn6eTTDN4^iB{vT_Gi@}@!{7z<&Re5uJ&idm43}r{%AGdYJWyt>DN5vk5=QZ_GiSE ze$7+s{zU+3Xd8;AErf3%@d8-4dw-)O8{ac1w? zvoB>YRCxwwU+}QIvR&`?_+1wEE?9PR%H#cYw(H&I+O3#R^MGk{cfaA>v>tV~>)mEf z8x}J+`gF7+XPxbOw|82(^Wea4N2fgAUuV1CZE_59p7MBqo$Y$JnbRQGPV4Obb++r> zW<3VAFgm=y&UU@qS-+vm)XnJ{w_Wcx&%hwhPs-!{b++r>W*n`!-gyU1+raaa=2>UE z-fgY1u1%kgR^+U+UGKK;x$cdUcz>Pkdbi2Zt7k=dyuZ$Nz1!N4$Fnz-$NTGS*SpPn z^hT}l{yN+BrLDEqk!n~gng6*>{5{I!`ul7auaW4i;eBgz@2-h%M{jjcQVqI0+x1(* zZrON7lHc`P!uBzYB){wLv#V$OF4uv2uJ?`3=Q}n3Dh2T0;BdC<-RAQ}??37D%lqqW z*SoD8I%f>}{OaVavt94D<`kdr-d|_C-ffLTYoR~Azs{B}^lqc~_l;pSb$X9w{Qpz$ z8?3Q@z8LZQhU?vC&7$_{eYKOb&UU@qSwAulG%ou7e}$NTGS*Sl@&67Q=ir)%7Hz1wK~=Pz98{#BA;Y}dQZ`2VMV{!+c- z{aN?A#XVB}iF-G!?RvKf@6=E4ud`iW+MW03L5-cz8#d07 zT+8)a!uBzYB){w3_E_()vt94D>%G6ucK!c@?dvd-`MQ2f*gl4lf{Y0NRBlJiq_n`GXW_`C=-*MJ=lJ$LNeXp6XfHx+C zzMs4k+z)nyDX=r#A9jUZ-~sR;cp&Ts(_nX)3Nv6j>;ZejUa%)T1Re}CVHWHQ`@sJ2 zP}mRjMR9%M`2f%_(+`FoI0RND)<e>fO=;2@X{4~K`rBj8Xt1oV$aG~toZ2fZ*C4u?m2M;P0Q2FQ@C;Z0&xU8gLU=Ab2Tp>1SOh1- z5?BnU!KrWxEQK@RbT|{92g~63a270wm9PR{0O!Iva5kI=FM=1s`LGIF@KSgQyck{% zFM|u4J3-5$? zzhEKsKVFL_68$JV{ zhC%o|d=5SfUxF{f7vNgB2EGi}!AAHBY=W=C_3#b&I(!Yj4c~%q!VU0U_zrv@z6YD( zNAN@V0qD3fx0A7VfF0G@7{zDvXg-g}@) z$wa2OQCp23Gj{87+l-&E?ZoXSZ9jG1ym?cnuA2($TIra{pEGAJn+ePMmOctm<6_y|?zlt($IzP4hOvyi@O`qZ;RC#<_X(l+7?@ z%@kNOYYp7Zn0-yAuUofn`t%voVMc2PwC;L+_Ptk+YO%Rp9NYws$vZ4O>$KBWHkKZ< qWa**<8w(dLU$ErVgYu)G=W5(hXB@kD!O}&e;}OdLDh^w|SNsbiRi_95 diff --git a/Templates/Modules/FPSGameplay/art/shapes/noshape.mb b/Templates/Modules/FPSGameplay/art/shapes/noshape.mb deleted file mode 100644 index 24330c1dbf43dd76c8a82d87d4d398e6393c7922..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61648 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 diff --git a/Templates/Modules/FPSGameplay/art/shapes/unit_capsule.dts b/Templates/Modules/FPSGameplay/art/shapes/unit_capsule.dts deleted file mode 100644 index bc9483fac22763bc20aacffa4573ce44e04499a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2709 zcmZ{mPiT}^6vdy(Of<$Alcs-+e=@dO+hD~6imS}~s-V_|E))c@ML`$R=t8?`#deH} zi)N#cjZg~huB+_2Y3B`!%fXE`E33i8{sN=@afVQC?Z}psOVMC03K@3`)X)z#54`iE=+lE737;67t$-t#yV3eSgl7 z*Xnukh;nub@Wq3ELQ}1$zmByROcUWtwU5y!(759MuRju9P(R~|b)pem*28Tb=LqU4 zI@OrJ>yxcjkHS9{{%E54J6C-q4eYQm{!tYW)8qWz52^?P7g#cQ*Rs?A8hj4H1GZ+;rDjJjSd9NCND zIT;`SJ3q}FAoYw5MfT6RukAF++1KkCgXZj)b3KoqZ(7fKGG?p{8;bbny3ViX%6X^h z^^8Gt{4Lk%|L(gK>%Sjpll;`Z9IHR-d`97JYf|grXZLo-BPXsm!7Uf(rqH0h`OVxE zYw-|Wf}1|MUUbPlMW-6`cYP9H*Qdfi75=H12ffde%9+cv{Jd{&Qr?%oqkFZd&2wYB zBiMWSV7&3;My(&7?M%X{Nv~aK5_S5o__(GmYnC;KXR9gmNyT1hmiIEB#M!N`-1NH6 z=1IjoTDQGYF^~H&gVt?+^lh65AD>6-<-Yzuyu&~t?CQuL?h~*3-7;=e`{YH-(cOx~{G7mYNJCZ&83(lQe z-oNy=S)Kcr9yn(FeL>csfrDEm(5#n0N5J2a*e-z%4V<;)^fySL0m<=zZc?V>^LGd1vHN&Fs zcEgIE-deqH<*NSG18WA?4jmnRbaiI@;nvUpdHUyr`~Tk=J=%J*@aq><>-(yHYhlOI pZ-*upcP#Gz^p~Y|!+XD)IeY%}nG50cnJ-VBotX+F;-?eHpXdCcKQjOT diff --git a/Templates/Modules/FPSGameplay/art/shapes/unit_cube.dts b/Templates/Modules/FPSGameplay/art/shapes/unit_cube.dts deleted file mode 100644 index feee7cf94be34c173bcd5d2e91afe3168dccfc44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1881 zcmd5-NlpS$5dA~vwg0483+ttJ{-n6T8feJ2jkCm?a>ap1k`Urpr)G{VLg zAN6YZ^^2BN_uX{*m2++aCLsQVFqx%Z2G%O{Tpj^Z@jZDQlInY#z$%#&YQGu4I$A>e zXd;SoKaJC;R$p~!6H})-8w+*l^9*AexArF;=IDnU zn!c;_vNNo;)EdTCX-PsOrT%xezSbQ$U<>DNXt|Fy&b=Ff z+{4_d+_T)h+@svB+_Bt=+^5`|U9bakKW>9tU=Q2_cflR74<3N~;4ydv9)f4!DR=^2 zf*0U9Ncj1rH}7CiPMODK5#A1^>91y6!l(COZPyo}uI=>7R^e4Ab?&t?u<*~FFr diff --git a/Templates/Modules/FPSGameplay/art/shapes/unit_sphere.dts b/Templates/Modules/FPSGameplay/art/shapes/unit_sphere.dts deleted file mode 100644 index 4d435438e87ac499a1a5171f3fb5e7077b735a08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5345 zcma)AO>9(E6uv+yr7cjPqWn0HwJ5@1DAhqxtKiR|RQVGqpaO}>BTWj4 z3*%Cg8k0s7-4NJm!n{e-g^6v_7&LL`#$7i?Hw_E?zWdI3oEaGDO+L=g{m!}foO^G{ zyj5;;vU|RB*BhK`ft=$KKzN<9-XK?p#?6I;(DB9j-$O!e$^)lQ#%BQMq8NGz9rIDB z`L1J-N6Df2bYABsG3LR*)*ZH9H5y^*o;b0fYSy_X*b9MX?~l^`wZLu#76EoWn0fA( zfKqoXmYF4xx;|@Q&5UK;tQor0eIph5XH%1FIoEz>MR;X((d%uKR|D#l2`$;T_(MwJ zBfpL$4=u)WKAE{uGyEa_Hji+0-Ey6E>GyGx-{-Nh$Qv`Z=i0ZOc3ts@^kdzsJV~FO z6F=)M+gQUd+dOt%>RgxeHdg%Hr_U?<*Zf+q_F4VDXIPhh*6aP$O@1E>J3TMEuJ~`t z!@F>H^VdG#)pa?q{{_id`uR5CkEzqodqh3Aqj9bA`?ZB1n>_xm(a(IcR#2-8KcKWa zd58^?`+9pFvD};HNp;zCz&+1KH+fi#=Fu9tpIPaq7VQc5raif-53G~>XWezq%lAS# z=05nEP3=Ap*S8$o&sx9SB|Z0B_FOr5&#Br+1|+{DC$?}144%iAK^H`?_i`^9;c4*T@+b!1ljD)VC3lO>r~ z8HugZ?!S+9U_V}JU24ldIq&x;{^%AqQ z#d_sB>y~w0o5#jty_oA_{Y!RTtQYG(v2L2j#+r4@HrDXVHjj<%KDJfs^}S>7*(P!c*Ew(e zzDD84Rn;RtK*Oc>;20qa&7k(>$q;c(2R4x7AG^)}nc0vxiyf zrWWl9_oh9$sSma%bh{@k%)RA4(lfGt(>I=} z_K@qQZ_S>I_1iaPIaaqE6U+OWp0D+rJye~k<(OKk-lnO&?zvkIa;ERJCTHr$e)Np0 z?uLy;EuMoM_N@6gC;c01IrMc_r?1>j}iC14luD)0)h8+aY) z2VMjA0(*crfVY9SfH#4CKnZvU*blr1ybF8)yblZjhk%2?0pLU62yhrU4jcoH0w;kJ zz##B3@DXqdI0KvpJ^|JPJ-{ZQ7kCt)kLU&-6rGa&<@XuwGj;N4^P3B8ev6?_KkW^` zX0hp~%{hK|q1^)H0QzauPn$aB7Jzfq9|N`mPXLbt^eqKifi}_Uqx}%@B%mDH)K>tE zxdV6@pr1DVw5d}D0OzRZ0se>ZH1HHa-)ev{t3;=d_9H+6P!4VCS%5M302=}NX=ef2 z)G4j6*bdOQ7RUnpz(SqAtms{0Q$8m;MEaen4La-NJ?E*-#j9w*3u*M- zKDXx_E@Km3NHb2Q6)$5kUP&7wmf^dhn=^M_!~DhtO$(b_S{E%|lDlvvn(4@WAN9}V zvQeQw*AopEa@(Vk!Q5w2??`TWRP4=Nh&qZ>fBgB|zdtRyHkHW?4NYToc8+3Kj+xBN(9q2EO#k$Be_^`N*;yDZ433Ttj*O0skB4p8x;= From ae56edd0135519e0fe3331a7e46eca345223ac7e Mon Sep 17 00:00:00 2001 From: Johxz Date: Mon, 10 Jul 2017 19:24:21 -0500 Subject: [PATCH 04/75] removed unnecessary shapes from spectator module --- .../spectatorGameplay/art/shapes/noshape.dts | Bin 18389 -> 0 bytes .../spectatorGameplay/art/shapes/noshape.mb | Bin 61648 -> 0 bytes .../art/shapes/unit_capsule.dts | Bin 2709 -> 0 bytes .../spectatorGameplay/art/shapes/unit_cube.dts | Bin 1881 -> 0 bytes .../art/shapes/unit_sphere.dts | Bin 5345 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/noshape.dts delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/noshape.mb delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/unit_capsule.dts delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/unit_cube.dts delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/unit_sphere.dts diff --git a/Templates/Modules/spectatorGameplay/art/shapes/noshape.dts b/Templates/Modules/spectatorGameplay/art/shapes/noshape.dts deleted file mode 100644 index a7a64cf1099e4247aecded23bec3923eb6e3a198..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18389 zcmeI43Aj~N6~`|EB8Z4)l3IwMQi?e|3#|+9na!G7QVtbG!4n)Iu|O>^R+f!4rJ)c^|L2G&Gu%CY#LW$+9f9-+!OI?)~rAJNoSV$i6Sn=a0S4UjMbu-us-r?s*R{ zyEblK@rxZAjpJYuY}IHqMuCoKtFwRq)BUo=Xi$zgF5mI`IfCKu;3s4D zY)`m-^}x(KSI@z2j=z2NoXB@)K6EZK`V}9(7-#rG+i0`~HHI-TRsnWwjU9379%sIx z<~DSUhY88i>J9(47!zST@Og6Dr)!JLIH@}(Wykik8gq~U^e+JkO8VnDtjcGLQsrgyu2(%8KQW?lRHl*cq}vt8dbz1wYF z|6s2+pce#-tG46+m6saO843{p5OIN)4Lt|rp99$w_P7O zrFT1xzlXI}o;;qRw(HXzv)=7=e>D!}(LGhJA$Gc7xj#JvS?{)D+vnt1tyAPQ+x5yB zdbit*v3)xCGLIoNp5OIN)4Q!41F=4)@%*lDn%-?)e?aS^@tDSK*Edb?c2O%#GnxCT{v*fp;xxm@3qD2Nzre5kKOi?lLz)&zK`~`*PnDx zPN&Xq@TI%Mm4$hE8JcfH%1(_+RtTx_m~MNZedt?TF7pRQ}MQM-!%q56m= zXVb>hiM86L@pSrK?>2LsGbyi+$6DYnS}CdVADm)6H)t#%dtu6KLMO&8A5dMS^` zTJ0+OUGKI&Q?+)=Gfb@ZSJCf!x0UmH*4oCCY|Sz6_ZUy=cfH%1)lokol9RucAn>`rA5E%-PW8mKIPGKGF-j&e%HILG1&V{)Zw%ja(zzY@fz;>u*umz zr8^$gsWdjLrA1EHyUiR2Cg=6>SgWN)9d^CjaA%!zw6tkce|+?5cSP8p5OIt z)4QFXJ*%0WoHhEkp67TsH(TTB)LZX2yNETt#?y&qE}eSo{bsvfa}2%PP1OLci=Hdf zxb6D3>D^8>fNQsv$24xczO9;(^=>zZ*38IRqfbBgXzjSJ+i5(pUp%MTu1{mgdbiW~ zWB+;`Hrw@Sj#=+^Q+-iy)kaRUUEemn+f9v8*Va0l#%qfa@Oe6Gnw^n zYdoELtNRc+&33)U5PG*Y{!YC$jpuj0<`{ann_e?b)qD#phIKuSdA;!=c2z-5BogFJG1Ir zCsz8Xx8AR3M)T2i-IhMT8`sub&pA{dvE+<*=GuD8cvQ1u3?044+Bzn!=^mQALOg~GbInj5<7Hf~J%?z!T_uU7tOm8HssKIN?1q~}~dr_s3hqKi7$jxo5V^0(%OuBYe9 zq>uB`-XR z@plr|hF{l_KU%HNE=d=0rC;kJf3#Y`zNGKz>9JPpp>thF{%F(lkaQ7O`ZbOtlfG&- zo)eNj&P%_>A%C=uMt^^Q(nnnB*E-4{ZKKiCb7s; z#+7t=F1j!2ylT6;%CGsPIp=*-+0m!#hc53U#-n{0`$qGq&P#uzH}9j|rg;`|r9Z6; z{%B+0bmQ_q)A}S`-bcN$k7BHGUi#C0)4j_mZ?%6SuIsBbc^`4TO2>MqwTSc5pYBu2 z9lHMhy^}u9tG27F{0+um>0;l-dFj`BrhS@Q-KV~kKjKQi<{*Ex>G?_eh%5c+xk!4R zlcbCN7w1*m)#ZK4^HA;M*ne?e`ZdqAzjGV=GWK({U0vR%%(vRdJacJWabEg0Px+%w z^G*AWJ{|IL^mSV1gTIga8~Zf&XPmoVI{BlGeW~?`IQRGEeH*QG+K1gZo`-Y~qpkeP zU+H4s#d+!1Ji5<7l~?;P&EMLtuG*g(Po<0f7w4tFFYnuE(>zn&h^yN0YuwtG(ds^? z&&S*!@!{{w{%AGsiioS)@M|9ON2`3=msL!+4Zp4DN5vk5=)*B;csPsv?*_Tz9X(`!>>5)+i24~@_tZ%#D`z=NT0R2)p)co zyK$vo*O5P3t*hQ|yK$wzmHpA``qlo7xT+1m#wCBWy3g9b-MG@<%Km6I?gn(@s`&70 zzVb(_yw(1UxYDn2$RDldsn6eTTDN4^iB{vT_Gi@}@!{7z<&Re5uJ&idm43}r{%AGdYJWyt>DN5vk5=QZ_GiSE ze$7+s{zU+3Xd8;AErf3%@d8-4dw-)O8{ac1w? zvoB>YRCxwwU+}QIvR&`?_+1wEE?9PR%H#cYw(H&I+O3#R^MGk{cfaA>v>tV~>)mEf z8x}J+`gF7+XPxbOw|82(^Wea4N2fgAUuV1CZE_59p7MBqo$Y$JnbRQGPV4Obb++r> zW<3VAFgm=y&UU@qS-+vm)XnJ{w_Wcx&%hwhPs-!{b++r>W*n`!-gyU1+raaa=2>UE z-fgY1u1%kgR^+U+UGKK;x$cdUcz>Pkdbi2Zt7k=dyuZ$Nz1!N4$Fnz-$NTGS*SpPn z^hT}l{yN+BrLDEqk!n~gng6*>{5{I!`ul7auaW4i;eBgz@2-h%M{jjcQVqI0+x1(* zZrON7lHc`P!uBzYB){wLv#V$OF4uv2uJ?`3=Q}n3Dh2T0;BdC<-RAQ}??37D%lqqW z*SoD8I%f>}{OaVavt94D<`kdr-d|_C-ffLTYoR~Azs{B}^lqc~_l;pSb$X9w{Qpz$ z8?3Q@z8LZQhU?vC&7$_{eYKOb&UU@qSwAulG%ou7e}$NTGS*Sl@&67Q=ir)%7Hz1wK~=Pz98{#BA;Y}dQZ`2VMV{!+c- z{aN?A#XVB}iF-G!?RvKf@6=E4ud`iW+MW03L5-cz8#d07 zT+8)a!uBzYB){w3_E_()vt94D>%G6ucK!c@?dvd-`MQ2f*gl4lf{Y0NRBlJiq_n`GXW_`C=-*MJ=lJ$LNeXp6XfHx+C zzMs4k+z)nyDX=r#A9jUZ-~sR;cp&Ts(_nX)3Nv6j>;ZejUa%)T1Re}CVHWHQ`@sJ2 zP}mRjMR9%M`2f%_(+`FoI0RND)<e>fO=;2@X{4~K`rBj8Xt1oV$aG~toZ2fZ*C4u?m2M;P0Q2FQ@C;Z0&xU8gLU=Ab2Tp>1SOh1- z5?BnU!KrWxEQK@RbT|{92g~63a270wm9PR{0O!Iva5kI=FM=1s`LGIF@KSgQyck{% zFM|u4J3-5$? zzhEKsKVFL_68$JV{ zhC%o|d=5SfUxF{f7vNgB2EGi}!AAHBY=W=C_3#b&I(!Yj4c~%q!VU0U_zrv@z6YD( zNAN@V0qD3fx0A7VfF0G@7{zDvXg-g}@) z$wa2OQCp23Gj{87+l-&E?ZoXSZ9jG1ym?cnuA2($TIra{pEGAJn+ePMmOctm<6_y|?zlt($IzP4hOvyi@O`qZ;RC#<_X(l+7?@ z%@kNOYYp7Zn0-yAuUofn`t%voVMc2PwC;L+_Ptk+YO%Rp9NYws$vZ4O>$KBWHkKZ< qWa**<8w(dLU$ErVgYu)G=W5(hXB@kD!O}&e;}OdLDh^w|SNsbiRi_95 diff --git a/Templates/Modules/spectatorGameplay/art/shapes/noshape.mb b/Templates/Modules/spectatorGameplay/art/shapes/noshape.mb deleted file mode 100644 index 24330c1dbf43dd76c8a82d87d4d398e6393c7922..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61648 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 diff --git a/Templates/Modules/spectatorGameplay/art/shapes/unit_capsule.dts b/Templates/Modules/spectatorGameplay/art/shapes/unit_capsule.dts deleted file mode 100644 index bc9483fac22763bc20aacffa4573ce44e04499a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2709 zcmZ{mPiT}^6vdy(Of<$Alcs-+e=@dO+hD~6imS}~s-V_|E))c@ML`$R=t8?`#deH} zi)N#cjZg~huB+_2Y3B`!%fXE`E33i8{sN=@afVQC?Z}psOVMC03K@3`)X)z#54`iE=+lE737;67t$-t#yV3eSgl7 z*Xnukh;nub@Wq3ELQ}1$zmByROcUWtwU5y!(759MuRju9P(R~|b)pem*28Tb=LqU4 zI@OrJ>yxcjkHS9{{%E54J6C-q4eYQm{!tYW)8qWz52^?P7g#cQ*Rs?A8hj4H1GZ+;rDjJjSd9NCND zIT;`SJ3q}FAoYw5MfT6RukAF++1KkCgXZj)b3KoqZ(7fKGG?p{8;bbny3ViX%6X^h z^^8Gt{4Lk%|L(gK>%Sjpll;`Z9IHR-d`97JYf|grXZLo-BPXsm!7Uf(rqH0h`OVxE zYw-|Wf}1|MUUbPlMW-6`cYP9H*Qdfi75=H12ffde%9+cv{Jd{&Qr?%oqkFZd&2wYB zBiMWSV7&3;My(&7?M%X{Nv~aK5_S5o__(GmYnC;KXR9gmNyT1hmiIEB#M!N`-1NH6 z=1IjoTDQGYF^~H&gVt?+^lh65AD>6-<-Yzuyu&~t?CQuL?h~*3-7;=e`{YH-(cOx~{G7mYNJCZ&83(lQe z-oNy=S)Kcr9yn(FeL>csfrDEm(5#n0N5J2a*e-z%4V<;)^fySL0m<=zZc?V>^LGd1vHN&Fs zcEgIE-deqH<*NSG18WA?4jmnRbaiI@;nvUpdHUyr`~Tk=J=%J*@aq><>-(yHYhlOI pZ-*upcP#Gz^p~Y|!+XD)IeY%}nG50cnJ-VBotX+F;-?eHpXdCcKQjOT diff --git a/Templates/Modules/spectatorGameplay/art/shapes/unit_cube.dts b/Templates/Modules/spectatorGameplay/art/shapes/unit_cube.dts deleted file mode 100644 index feee7cf94be34c173bcd5d2e91afe3168dccfc44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1881 zcmd5-NlpS$5dA~vwg0483+ttJ{-n6T8feJ2jkCm?a>ap1k`Urpr)G{VLg zAN6YZ^^2BN_uX{*m2++aCLsQVFqx%Z2G%O{Tpj^Z@jZDQlInY#z$%#&YQGu4I$A>e zXd;SoKaJC;R$p~!6H})-8w+*l^9*AexArF;=IDnU zn!c;_vNNo;)EdTCX-PsOrT%xezSbQ$U<>DNXt|Fy&b=Ff z+{4_d+_T)h+@svB+_Bt=+^5`|U9bakKW>9tU=Q2_cflR74<3N~;4ydv9)f4!DR=^2 zf*0U9Ncj1rH}7CiPMODK5#A1^>91y6!l(COZPyo}uI=>7R^e4Ab?&t?u<*~FFr diff --git a/Templates/Modules/spectatorGameplay/art/shapes/unit_sphere.dts b/Templates/Modules/spectatorGameplay/art/shapes/unit_sphere.dts deleted file mode 100644 index 4d435438e87ac499a1a5171f3fb5e7077b735a08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5345 zcma)AO>9(E6uv+yr7cjPqWn0HwJ5@1DAhqxtKiR|RQVGqpaO}>BTWj4 z3*%Cg8k0s7-4NJm!n{e-g^6v_7&LL`#$7i?Hw_E?zWdI3oEaGDO+L=g{m!}foO^G{ zyj5;;vU|RB*BhK`ft=$KKzN<9-XK?p#?6I;(DB9j-$O!e$^)lQ#%BQMq8NGz9rIDB z`L1J-N6Df2bYABsG3LR*)*ZH9H5y^*o;b0fYSy_X*b9MX?~l^`wZLu#76EoWn0fA( zfKqoXmYF4xx;|@Q&5UK;tQor0eIph5XH%1FIoEz>MR;X((d%uKR|D#l2`$;T_(MwJ zBfpL$4=u)WKAE{uGyEa_Hji+0-Ey6E>GyGx-{-Nh$Qv`Z=i0ZOc3ts@^kdzsJV~FO z6F=)M+gQUd+dOt%>RgxeHdg%Hr_U?<*Zf+q_F4VDXIPhh*6aP$O@1E>J3TMEuJ~`t z!@F>H^VdG#)pa?q{{_id`uR5CkEzqodqh3Aqj9bA`?ZB1n>_xm(a(IcR#2-8KcKWa zd58^?`+9pFvD};HNp;zCz&+1KH+fi#=Fu9tpIPaq7VQc5raif-53G~>XWezq%lAS# z=05nEP3=Ap*S8$o&sx9SB|Z0B_FOr5&#Br+1|+{DC$?}144%iAK^H`?_i`^9;c4*T@+b!1ljD)VC3lO>r~ z8HugZ?!S+9U_V}JU24ldIq&x;{^%AqQ z#d_sB>y~w0o5#jty_oA_{Y!RTtQYG(v2L2j#+r4@HrDXVHjj<%KDJfs^}S>7*(P!c*Ew(e zzDD84Rn;RtK*Oc>;20qa&7k(>$q;c(2R4x7AG^)}nc0vxiyf zrWWl9_oh9$sSma%bh{@k%)RA4(lfGt(>I=} z_K@qQZ_S>I_1iaPIaaqE6U+OWp0D+rJye~k<(OKk-lnO&?zvkIa;ERJCTHr$e)Np0 z?uLy;EuMoM_N@6gC;c01IrMc_r?1>j}iC14luD)0)h8+aY) z2VMjA0(*crfVY9SfH#4CKnZvU*blr1ybF8)yblZjhk%2?0pLU62yhrU4jcoH0w;kJ zz##B3@DXqdI0KvpJ^|JPJ-{ZQ7kCt)kLU&-6rGa&<@XuwGj;N4^P3B8ev6?_KkW^` zX0hp~%{hK|q1^)H0QzauPn$aB7Jzfq9|N`mPXLbt^eqKifi}_Uqx}%@B%mDH)K>tE zxdV6@pr1DVw5d}D0OzRZ0se>ZH1HHa-)ev{t3;=d_9H+6P!4VCS%5M302=}NX=ef2 z)G4j6*bdOQ7RUnpz(SqAtms{0Q$8m;MEaen4La-NJ?E*-#j9w*3u*M- zKDXx_E@Km3NHb2Q6)$5kUP&7wmf^dhn=^M_!~DhtO$(b_S{E%|lDlvvn(4@WAN9}V zvQeQw*AopEa@(Vk!Q5w2??`TWRP4=Nh&qZ>fBgB|zdtRyHkHW?4NYToc8+3Kj+xBN(9q2EO#k$Be_^`N*;yDZ433Ttj*O0skB4p8x;= From 9608379ac821b48ac34f3c15147d962f672b736a Mon Sep 17 00:00:00 2001 From: Johxz Date: Mon, 10 Jul 2017 19:44:00 -0500 Subject: [PATCH 05/75] moving editor shapes into tools folder --- .../BaseGame/game/tools/shapes/noshape.dts | Bin 0 -> 18389 bytes Templates/BaseGame/game/tools/shapes/noshape.mb | Bin 0 -> 61648 bytes .../BaseGame/game/tools/shapes/unit_capsule.dts | Bin 0 -> 2709 bytes .../BaseGame/game/tools/shapes/unit_cube.dts | Bin 0 -> 1881 bytes .../BaseGame/game/tools/shapes/unit_sphere.dts | Bin 0 -> 5345 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Templates/BaseGame/game/tools/shapes/noshape.dts create mode 100644 Templates/BaseGame/game/tools/shapes/noshape.mb create mode 100644 Templates/BaseGame/game/tools/shapes/unit_capsule.dts create mode 100644 Templates/BaseGame/game/tools/shapes/unit_cube.dts create mode 100644 Templates/BaseGame/game/tools/shapes/unit_sphere.dts diff --git a/Templates/BaseGame/game/tools/shapes/noshape.dts b/Templates/BaseGame/game/tools/shapes/noshape.dts new file mode 100644 index 0000000000000000000000000000000000000000..a7a64cf1099e4247aecded23bec3923eb6e3a198 GIT binary patch literal 18389 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 literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/tools/shapes/noshape.mb b/Templates/BaseGame/game/tools/shapes/noshape.mb new file mode 100644 index 0000000000000000000000000000000000000000..24330c1dbf43dd76c8a82d87d4d398e6393c7922 GIT binary patch literal 61648 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 literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/tools/shapes/unit_capsule.dts b/Templates/BaseGame/game/tools/shapes/unit_capsule.dts new file mode 100644 index 0000000000000000000000000000000000000000..bc9483fac22763bc20aacffa4573ce44e04499a7 GIT binary patch literal 2709 zcmZ{mPiT}^6vdy(Of<$Alcs-+e=@dO+hD~6imS}~s-V_|E))c@ML`$R=t8?`#deH} zi)N#cjZg~huB+_2Y3B`!%fXE`E33i8{sN=@afVQC?Z}psOVMC03K@3`)X)z#54`iE=+lE737;67t$-t#yV3eSgl7 z*Xnukh;nub@Wq3ELQ}1$zmByROcUWtwU5y!(759MuRju9P(R~|b)pem*28Tb=LqU4 zI@OrJ>yxcjkHS9{{%E54J6C-q4eYQm{!tYW)8qWz52^?P7g#cQ*Rs?A8hj4H1GZ+;rDjJjSd9NCND zIT;`SJ3q}FAoYw5MfT6RukAF++1KkCgXZj)b3KoqZ(7fKGG?p{8;bbny3ViX%6X^h z^^8Gt{4Lk%|L(gK>%Sjpll;`Z9IHR-d`97JYf|grXZLo-BPXsm!7Uf(rqH0h`OVxE zYw-|Wf}1|MUUbPlMW-6`cYP9H*Qdfi75=H12ffde%9+cv{Jd{&Qr?%oqkFZd&2wYB zBiMWSV7&3;My(&7?M%X{Nv~aK5_S5o__(GmYnC;KXR9gmNyT1hmiIEB#M!N`-1NH6 z=1IjoTDQGYF^~H&gVt?+^lh65AD>6-<-Yzuyu&~t?CQuL?h~*3-7;=e`{YH-(cOx~{G7mYNJCZ&83(lQe z-oNy=S)Kcr9yn(FeL>csfrDEm(5#n0N5J2a*e-z%4V<;)^fySL0m<=zZc?V>^LGd1vHN&Fs zcEgIE-deqH<*NSG18WA?4jmnRbaiI@;nvUpdHUyr`~Tk=J=%J*@aq><>-(yHYhlOI pZ-*upcP#Gz^p~Y|!+XD)IeY%}nG50cnJ-VBotX+F;-?eHpXdCcKQjOT literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/tools/shapes/unit_cube.dts b/Templates/BaseGame/game/tools/shapes/unit_cube.dts new file mode 100644 index 0000000000000000000000000000000000000000..feee7cf94be34c173bcd5d2e91afe3168dccfc44 GIT binary patch literal 1881 zcmd5-NlpS$5dA~vwg0483+ttJ{-n6T8feJ2jkCm?a>ap1k`Urpr)G{VLg zAN6YZ^^2BN_uX{*m2++aCLsQVFqx%Z2G%O{Tpj^Z@jZDQlInY#z$%#&YQGu4I$A>e zXd;SoKaJC;R$p~!6H})-8w+*l^9*AexArF;=IDnU zn!c;_vNNo;)EdTCX-PsOrT%xezSbQ$U<>DNXt|Fy&b=Ff z+{4_d+_T)h+@svB+_Bt=+^5`|U9bakKW>9tU=Q2_cflR74<3N~;4ydv9)f4!DR=^2 zf*0U9Ncj1rH}7CiPMODK5#A1^>91y6!l(COZPyo}uI=>7R^e4Ab?&t?u<*~FFr literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/tools/shapes/unit_sphere.dts b/Templates/BaseGame/game/tools/shapes/unit_sphere.dts new file mode 100644 index 0000000000000000000000000000000000000000..4d435438e87ac499a1a5171f3fb5e7077b735a08 GIT binary patch literal 5345 zcma)AO>9(E6uv+yr7cjPqWn0HwJ5@1DAhqxtKiR|RQVGqpaO}>BTWj4 z3*%Cg8k0s7-4NJm!n{e-g^6v_7&LL`#$7i?Hw_E?zWdI3oEaGDO+L=g{m!}foO^G{ zyj5;;vU|RB*BhK`ft=$KKzN<9-XK?p#?6I;(DB9j-$O!e$^)lQ#%BQMq8NGz9rIDB z`L1J-N6Df2bYABsG3LR*)*ZH9H5y^*o;b0fYSy_X*b9MX?~l^`wZLu#76EoWn0fA( zfKqoXmYF4xx;|@Q&5UK;tQor0eIph5XH%1FIoEz>MR;X((d%uKR|D#l2`$;T_(MwJ zBfpL$4=u)WKAE{uGyEa_Hji+0-Ey6E>GyGx-{-Nh$Qv`Z=i0ZOc3ts@^kdzsJV~FO z6F=)M+gQUd+dOt%>RgxeHdg%Hr_U?<*Zf+q_F4VDXIPhh*6aP$O@1E>J3TMEuJ~`t z!@F>H^VdG#)pa?q{{_id`uR5CkEzqodqh3Aqj9bA`?ZB1n>_xm(a(IcR#2-8KcKWa zd58^?`+9pFvD};HNp;zCz&+1KH+fi#=Fu9tpIPaq7VQc5raif-53G~>XWezq%lAS# z=05nEP3=Ap*S8$o&sx9SB|Z0B_FOr5&#Br+1|+{DC$?}144%iAK^H`?_i`^9;c4*T@+b!1ljD)VC3lO>r~ z8HugZ?!S+9U_V}JU24ldIq&x;{^%AqQ z#d_sB>y~w0o5#jty_oA_{Y!RTtQYG(v2L2j#+r4@HrDXVHjj<%KDJfs^}S>7*(P!c*Ew(e zzDD84Rn;RtK*Oc>;20qa&7k(>$q;c(2R4x7AG^)}nc0vxiyf zrWWl9_oh9$sSma%bh{@k%)RA4(lfGt(>I=} z_K@qQZ_S>I_1iaPIaaqE6U+OWp0D+rJye~k<(OKk-lnO&?zvkIa;ERJCTHr$e)Np0 z?uLy;EuMoM_N@6gC;c01IrMc_r?1>j}iC14luD)0)h8+aY) z2VMjA0(*crfVY9SfH#4CKnZvU*blr1ybF8)yblZjhk%2?0pLU62yhrU4jcoH0w;kJ zz##B3@DXqdI0KvpJ^|JPJ-{ZQ7kCt)kLU&-6rGa&<@XuwGj;N4^P3B8ev6?_KkW^` zX0hp~%{hK|q1^)H0QzauPn$aB7Jzfq9|N`mPXLbt^eqKifi}_Uqx}%@B%mDH)K>tE zxdV6@pr1DVw5d}D0OzRZ0se>ZH1HHa-)ev{t3;=d_9H+6P!4VCS%5M302=}NX=ef2 z)G4j6*bdOQ7RUnpz(SqAtms{0Q$8m;MEaen4La-NJ?E*-#j9w*3u*M- zKDXx_E@Km3NHb2Q6)$5kUP&7wmf^dhn=^M_!~DhtO$(b_S{E%|lDlvvn(4@WAN9}V zvQeQw*AopEa@(Vk!Q5w2??`TWRP4=Nh&qZ>fBgB|zdtRyHkHW?4NYToc8+3Kj+xBN(9q2EO#k$Be_^`N*;yDZ433Ttj*O0skB4p8x;= literal 0 HcmV?d00001 From 9854aaffa21333d4a53f5ed2ecf64c71ce0e9fcc Mon Sep 17 00:00:00 2001 From: Johxz Date: Mon, 10 Jul 2017 19:52:20 -0500 Subject: [PATCH 06/75] correct materials.cs --- .../BaseGame/game/tools/shapes/materials.cs | 16 ++++ .../FPSGameplay/art/shapes/materials.cs | 54 ----------- .../spectatorGameplay/art/shapes/materials.cs | 94 ------------------- 3 files changed, 16 insertions(+), 148 deletions(-) create mode 100644 Templates/BaseGame/game/tools/shapes/materials.cs diff --git a/Templates/BaseGame/game/tools/shapes/materials.cs b/Templates/BaseGame/game/tools/shapes/materials.cs new file mode 100644 index 000000000..2911ca4d2 --- /dev/null +++ b/Templates/BaseGame/game/tools/shapes/materials.cs @@ -0,0 +1,16 @@ +//--- noshape.dts MATERIALS BEGIN --- +singleton Material(noshape_NoShape) +{ + mapTo = "NoShape"; + + diffuseMap[0] = ""; + diffuseColor[0] = "0.8 0.003067 0 .8"; + emissive[0] = 0; + doubleSided = false; + translucent = 1; + translucentBlendOp = "LerpAlpha"; + castShadows = false; + materialTag0 = "WorldEditor"; +}; + +//--- noshape.dts MATERIALS END --- diff --git a/Templates/Modules/FPSGameplay/art/shapes/materials.cs b/Templates/Modules/FPSGameplay/art/shapes/materials.cs index 3e48872a7..c3620b36d 100644 --- a/Templates/Modules/FPSGameplay/art/shapes/materials.cs +++ b/Templates/Modules/FPSGameplay/art/shapes/materials.cs @@ -65,57 +65,3 @@ singleton Material(CameraMat) }; //--- camera.dts MATERIALS END --- -//--- noshape.dts MATERIALS BEGIN --- -singleton Material(noshape_NoShape) -{ - mapTo = "NoShape"; - - diffuseMap[0] = ""; - - diffuseColor[0] = "0.8 0.003067 0 .8"; - emissive[0] = 0; - - doubleSided = false; - translucent = 1; - translucentBlendOp = "LerpAlpha"; - castShadows = false; -}; - -//--- noshape.dts MATERIALS END --- - -//--- noshapetext.dae MATERIALS BEGIN --- -singleton Material(noshapetext_lambert1) -{ - mapTo = "lambert1"; - - diffuseMap[0] = ""; - - diffuseColor[0] = "0.4 0.4 0.4 1"; - specular[0] = "1 1 1 1"; - specularPower[0] = 8; - pixelSpecular[0] = false; - emissive[0] = true; - - doubleSided = false; - translucent = false; - translucentBlendOp = "None"; -}; - -singleton Material(noshapetext_noshape_mat) -{ - mapTo = "noshape_mat"; - - diffuseMap[0] = ""; - - diffuseColor[0] = "0.4 0.3504 0.363784 0.33058"; - specular[0] = "1 1 1 1"; - specularPower[0] = 8; - pixelSpecular[0] = false; - emissive[0] = true; - - doubleSided = false; - translucent = true; - translucentBlendOp = "None"; -}; - -//--- noshapetext.dae MATERIALS END --- \ No newline at end of file diff --git a/Templates/Modules/spectatorGameplay/art/shapes/materials.cs b/Templates/Modules/spectatorGameplay/art/shapes/materials.cs index f413f54b0..c3620b36d 100644 --- a/Templates/Modules/spectatorGameplay/art/shapes/materials.cs +++ b/Templates/Modules/spectatorGameplay/art/shapes/materials.cs @@ -65,97 +65,3 @@ singleton Material(CameraMat) }; //--- camera.dts MATERIALS END --- -//--- noshape.dts MATERIALS BEGIN --- -singleton Material(noshape_NoShape) -{ - mapTo = "NoShape"; - - diffuseMap[0] = ""; - - diffuseColor[0] = "0.8 0.003067 0 .8"; - emissive[0] = 0; - - doubleSided = false; - translucent = 1; - translucentBlendOp = "LerpAlpha"; - castShadows = false; -}; - -//--- noshape.dts MATERIALS END --- - -//--- noshapetext.dae MATERIALS BEGIN --- -singleton Material(noshapetext_lambert1) -{ - mapTo = "lambert1"; - - diffuseMap[0] = ""; - - diffuseColor[0] = "0.4 0.4 0.4 1"; - specular[0] = "1 1 1 1"; - specularPower[0] = 8; - pixelSpecular[0] = false; - emissive[0] = true; - - doubleSided = false; - translucent = false; - translucentBlendOp = "None"; -}; - -singleton Material(noshapetext_noshape_mat) -{ - mapTo = "noshape_mat"; - - diffuseMap[0] = ""; - - diffuseColor[0] = "0.4 0.3504 0.363784 0.33058"; - specular[0] = "1 1 1 1"; - specularPower[0] = 8; - pixelSpecular[0] = false; - emissive[0] = true; - - doubleSided = false; - translucent = true; - translucentBlendOp = "None"; -}; - -//--- noshapetext.dae MATERIALS END --- - -//--- portal MATERIALS BEGIN --- - -singleton Material(portal5_portal_top) -{ - mapTo = "portal_top"; - - diffuseMap[0] = "top"; - normalMap[0] = "top-normal"; - - diffuseColor[0] = "0.4 0.4 0.4 1"; - specular[0] = "0.5 0.5 0.5 1"; - specularPower[0] = 2; - pixelSpecular[0] = false; - emissive[0] = true; - - doubleSided = false; - translucent = false; - translucentBlendOp = "None"; -}; - -singleton Material(portal5_portal_lightray) -{ - mapTo = "portal_lightray"; - - diffuseMap[0] = "lightray"; - - diffuseColor[0] = "0.4 0.4 0.4 0.64462"; - specular[0] = "0.5 0.5 0.5 1"; - specularPower[0] = 2; - pixelSpecular[0] = false; - emissive[0] = true; - - doubleSided = 1; - translucent = true; - translucentBlendOp = "AddAlpha"; - castShadows = "0"; -}; -//--- portal MATERIALS END --- - From 0878327304e690f0ae15681ad0b39694416f5c8d Mon Sep 17 00:00:00 2001 From: Johxz Date: Mon, 10 Jul 2017 19:53:37 -0500 Subject: [PATCH 07/75] remove unused portal shape from spectator module --- .../art/shapes/base-normal.png | Bin 112442 -> 0 bytes .../spectatorGameplay/art/shapes/base.png | Bin 117311 -> 0 bytes .../spectatorGameplay/art/shapes/lightray.png | Bin 2135 -> 0 bytes .../spectatorGameplay/art/shapes/portal.dts | Bin 71396 -> 0 bytes .../art/shapes/top-normal.png | Bin 125538 -> 0 bytes .../spectatorGameplay/art/shapes/top.png | Bin 105137 -> 0 bytes 6 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/base-normal.png delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/base.png delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/lightray.png delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/portal.dts delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/top-normal.png delete mode 100644 Templates/Modules/spectatorGameplay/art/shapes/top.png diff --git a/Templates/Modules/spectatorGameplay/art/shapes/base-normal.png b/Templates/Modules/spectatorGameplay/art/shapes/base-normal.png deleted file mode 100644 index 27ed35fcd7a0b066d92e6eb002f5047562c17fe5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112442 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�nhP}dK|!g{%c4RH;eauSKnrV22dy+5BH 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

iL^BxT4kkJ|I!|*c3MweG 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≠&`&OhOp2?ME~ld~I4QFziurTj}c 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 s)#_>`i{()fnyh`Z-E<Mrg6#xJL diff --git a/Templates/Modules/spectatorGameplay/art/shapes/lightray.png b/Templates/Modules/spectatorGameplay/art/shapes/lightray.png deleted file mode 100644 index 1f3ed83ba0fa251c659afe782ffb22b170c08c77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2135 zcmV-d2&ngoP)f$MMFUvYgL z#>2fI-}(2iLNBUk(#jl5qX zln|_0hai6@FS&&ReyyXp<|4{V4iv36D7-WN{xXi^_1RNt-wVzTc_?6v(}z^+E?t0P zQuuz_sjb@@GKHboaQc~ZfiRY}mz-)CM=Iket5A!}JjZ#(qxQqG>8HT+3@{&5xKt+K znoehWvT!q&_PKEOgYf_ko6z}viQ(Ef-J$7nSSbL%><;IH?vGKNoB}1p$LD5-?{g`K z^4*-H3X#t!T0^1mupGvH$efJ}oTj!c;Q1Q^6JU_EHU($ur_^JC)APNzfa$l>OgK-U zvOp#wotuaPSPQ$YqHuvjC*O*=-9Q(|O~@e&-|(SG$2Dw(@9Amxgax0E~07=Nz;lx9y|A6Y#_Z&i8#DxdANLwHdSX z=-+JY_s?ia2)q6{ESho&SVX8>qUJz%a)M(W;P>Rc3tSH$rjN-8NVgdYH9qt}2o95Q z=Xs7IxV2+l2MxewVQ|PaUP=qhr3Fka9k8O|ze_uz@ONOR~0u#UBP2Tf`< zWDnL9LNNl*C|uxJ1Ze5-atU(p(pxw839)ZRr7hsF0!*`M)9&Muk zdHNFvijA;feF_}>5hsZ-;w3sWqj2m^|90+Y^xMn?3& z`Ln#E*=SXOp!gp>3MYuJDd!+S0sY4qnkY8Oo{qEO3@bE`Pe_|Sw`Boz=nR)3!s1L# zg=hG~b@Hu!egEApYfEx~z)!^g$9t0}z-56Mh<(d8gC!a*r2kq(hc@YI@?2VztubKn z^KtSw4~Vfe#`r7((1xUGzK3)D5N08MjmR73^AXZubw4FYTtNHS#;m#VnG|&o-i=Ah zTP5^_C0Xqq#hw55^B`<48k3=reltnO--!Z?gbeiWiwtFe&EFvdFKU2gJt;;5LvzR4 z-dPJ?BtxLjwp~#Kj`F&M+}HM4)eu_Z?-anC`OR=Ym;xdsF#~OppiIQ9g}mni5IU?J zn^|g`2*svc#=!H8kDisDOSV>}AR8Y_=z;DU87@NYiBPkef4aaG0eT3RS(ev|qAoP% z>v*l-A*uG>C$Ci{9JVZe<^mD{M%BoKN>`2LHVjVge_O%%zOM}?R1?`|TP%<1oKf~t z9$}TzZ!3_sFdo9NfGivJBuHHCQDV}7)Qb`JbMqG(=OzxuG~UX?ca*%W zm)RgYZnlT>J#P#+c|dpJ3eqQVAjaKEi%WyMK7PN89k>ob$(R17bcegkKzmY!U-Xw;EF=E3-E4@FSNm| z5c%67Xo(NIOBB9N4}YnHE>=$fl|*bLM9p2mkg(&MM}U<_YLwf6U~jj{ofPwFLtkfQ zrfW}7H-&v}kK(oj(psgC?S>Aw>~_kjs4t^TwEU`$leYsw0hiel!{SB)IOd8DEde2u z=0pj`}VsU8PcO!$DT zt#E-aUkwr}%mlm~DKS9luGM7}*d$H?+-})}gSh@A9TRMD>uNT|hArdoEWj2;D64~C zJgg6Q7HzS*ln@l99iJKcgmCCaF8K%?0@+nPD`OW1;Tj@+=G=ZKbTL1x`7=?%tGele zwQeSByNtsqg$M;ck<=Nt^#Emdyn%24qTbpt)f*(87|kt`Hh6WF&emM?ZW1E*a01gi zgb=K;w7X`4vmlDW2e5pjxg^MEVJ)8iBv-Gl%fh=vzl)*QI?mr+OJPH9Z{;FDO|BDs?X9a)sFduIS zZ!b*mzfi!R9QSd7-*o}}4=muFHT`BMM@ diff --git a/Templates/Modules/spectatorGameplay/art/shapes/portal.dts b/Templates/Modules/spectatorGameplay/art/shapes/portal.dts deleted file mode 100644 index edbd851c70c4130466032e1482d36284d0e29db2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71396 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 TM*rJ7cHM^(TWkEc_0Qu^Ch=c( diff --git a/Templates/Modules/spectatorGameplay/art/shapes/top-normal.png b/Templates/Modules/spectatorGameplay/art/shapes/top-normal.png deleted file mode 100644 index 30e35fedb88bf5db92cdbbce52dac1111d1069d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125538 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 DTHC*P diff --git a/Templates/Modules/spectatorGameplay/art/shapes/top.png b/Templates/Modules/spectatorGameplay/art/shapes/top.png deleted file mode 100644 index 0ceb304da4bd55de13ce3f516d2249daf1b19dae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105137 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≺c3LwQNki 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 Date: Mon, 10 Jul 2017 20:00:23 -0500 Subject: [PATCH 08/75] noshape.dae should go inside core --- .../game/{tools => core}/shapes/materials.cs | 0 .../game/{tools => core}/shapes/noshape.dts | Bin .../BaseGame/game/{tools => core}/shapes/noshape.mb | Bin 3 files changed, 0 insertions(+), 0 deletions(-) rename Templates/BaseGame/game/{tools => core}/shapes/materials.cs (100%) rename Templates/BaseGame/game/{tools => core}/shapes/noshape.dts (100%) rename Templates/BaseGame/game/{tools => core}/shapes/noshape.mb (100%) diff --git a/Templates/BaseGame/game/tools/shapes/materials.cs b/Templates/BaseGame/game/core/shapes/materials.cs similarity index 100% rename from Templates/BaseGame/game/tools/shapes/materials.cs rename to Templates/BaseGame/game/core/shapes/materials.cs diff --git a/Templates/BaseGame/game/tools/shapes/noshape.dts b/Templates/BaseGame/game/core/shapes/noshape.dts similarity index 100% rename from Templates/BaseGame/game/tools/shapes/noshape.dts rename to Templates/BaseGame/game/core/shapes/noshape.dts diff --git a/Templates/BaseGame/game/tools/shapes/noshape.mb b/Templates/BaseGame/game/core/shapes/noshape.mb similarity index 100% rename from Templates/BaseGame/game/tools/shapes/noshape.mb rename to Templates/BaseGame/game/core/shapes/noshape.mb From e7c98e504b747872116d53cdf2164b6a14f8f774 Mon Sep 17 00:00:00 2001 From: Johxz Date: Mon, 10 Jul 2017 20:02:06 -0500 Subject: [PATCH 09/75] corrected shape path --- Engine/source/T3D/shapeImage.cpp | 2 +- Engine/source/ts/tsShapeConstruct.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine/source/T3D/shapeImage.cpp b/Engine/source/T3D/shapeImage.cpp index 627e8e433..61c03785a 100644 --- a/Engine/source/T3D/shapeImage.cpp +++ b/Engine/source/T3D/shapeImage.cpp @@ -189,7 +189,7 @@ ShapeBaseImageData::ShapeBaseImageData() lightRadius = 10.f; lightBrightness = 1.0f; - shapeName = "core/art/shapes/noshape.dts"; + shapeName = "core/shapes/noshape.dts"; shapeNameFP = ""; imageAnimPrefix = ""; imageAnimPrefixFP = ""; diff --git a/Engine/source/ts/tsShapeConstruct.cpp b/Engine/source/ts/tsShapeConstruct.cpp index dd2a67644..6082472d7 100644 --- a/Engine/source/ts/tsShapeConstruct.cpp +++ b/Engine/source/ts/tsShapeConstruct.cpp @@ -74,9 +74,9 @@ EndImplementEnumType; //----------------------------------------------------------------------------- -String TSShapeConstructor::smCapsuleShapePath("core/art/shapes/unit_capsule.dts"); -String TSShapeConstructor::smCubeShapePath("core/art/shapes/unit_cube.dts"); -String TSShapeConstructor::smSphereShapePath("core/art/shapes/unit_sphere.dts"); +String TSShapeConstructor::smCapsuleShapePath("tools/shapes/unit_capsule.dts"); +String TSShapeConstructor::smCubeShapePath("tools/shapes/unit_cube.dts"); +String TSShapeConstructor::smSphereShapePath("tools/shapes/unit_sphere.dts"); ResourceRegisterPostLoadSignal< TSShape > TSShapeConstructor::_smAutoLoad( &TSShapeConstructor::_onTSShapeLoaded ); ResourceRegisterUnloadSignal< TSShape > TSShapeConstructor::_smAutoUnload( &TSShapeConstructor::_onTSShapeUnloaded ); From 0a407865ac12c410129bedbc1c3a25a7a399949b Mon Sep 17 00:00:00 2001 From: Richard Marrevee Date: Fri, 22 Dec 2017 17:11:31 +0100 Subject: [PATCH 10/75] Update gfxD3D11Device.cpp --- Engine/source/gfx/D3D11/gfxD3D11Device.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/gfx/D3D11/gfxD3D11Device.cpp b/Engine/source/gfx/D3D11/gfxD3D11Device.cpp index 2be8d2a15..bf2f3b39f 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Device.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Device.cpp @@ -238,7 +238,7 @@ DXGI_SWAP_CHAIN_DESC GFXD3D11Device::setupPresentParams(const GFXVideoMode &mode if (mode.fullScreen) { - d3dpp.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + d3dpp.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED; d3dpp.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; d3dpp.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; } @@ -1865,4 +1865,4 @@ void GFXD3D11Device::setDebugMarker(ColorI color, const char *name) MultiByteToWideChar(CP_ACP, 0, name, -1, eventName, 260); mUserAnnotation->SetMarker(eventName); } -} \ No newline at end of file +} From 0380b95492b75191ac024e2a20042a5428a32ccd Mon Sep 17 00:00:00 2001 From: irei1as Date: Sun, 11 Mar 2018 17:20:59 +0100 Subject: [PATCH 11/75] Update sfxSound.cpp --- Engine/source/sfx/sfxSound.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Engine/source/sfx/sfxSound.cpp b/Engine/source/sfx/sfxSound.cpp index 683f70cda..df856ae8f 100644 --- a/Engine/source/sfx/sfxSound.cpp +++ b/Engine/source/sfx/sfxSound.cpp @@ -693,8 +693,9 @@ DefineEngineMethod( SFXSound, setPosition, void, ( F32 position ),, "playback will resume at the given position when play() is called.\n\n" "@param position The new position of the play cursor (in seconds).\n" ) { - if( position >= 0 && position <= object->getDuration() ) - object->setPosition( position * 1000.0f ); + position *= 1000.0f; + if( position >= 0 && position < object->getDuration() ) + object->setPosition( position ); } //----------------------------------------------------------------------------- From ae82c93ad0ae2e054a0f64b608482453d823dd1a Mon Sep 17 00:00:00 2001 From: irei1as Date: Sun, 11 Mar 2018 17:23:59 +0100 Subject: [PATCH 12/75] Update asyncPacketStream.h --- Engine/source/platform/async/asyncPacketStream.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Engine/source/platform/async/asyncPacketStream.h b/Engine/source/platform/async/asyncPacketStream.h index a5ed13daf..9cc33d4dc 100644 --- a/Engine/source/platform/async/asyncPacketStream.h +++ b/Engine/source/platform/async/asyncPacketStream.h @@ -281,9 +281,22 @@ void AsyncPacketBufferedInputStream< Stream, Packet >::_requestNext() IResettable* resettable = dynamic_cast< IResettable* >( s ); if( resettable ) { + IPositionable< U32 >* positionable = dynamic_cast< IPositionable< U32 >* >( &Deref( stream ) ); + U32 pos; + if(positionable) + pos = positionable->getPosition(); + resettable->reset(); isEOS = false; this->mNumRemainingSourceElements = mNumTotalSourceElements; + + if( positionable ) + { + positionable->setPosition(pos); + U32 dur = stream->getDuration(); + if(dur != 0) //avoiding division by zero? not needed, probably + this->mNumRemainingSourceElements -= (U32)(mNumTotalSourceElements*(F32)pos/dur); + } } } else if( isEOS ) From a21c5a7677460f8fe86f2c06b20039645660ea73 Mon Sep 17 00:00:00 2001 From: irei1as Date: Sun, 11 Mar 2018 17:25:30 +0100 Subject: [PATCH 13/75] Update sfxSound.h --- Engine/source/sfx/sfxSound.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Engine/source/sfx/sfxSound.h b/Engine/source/sfx/sfxSound.h index 16c8b0b28..364f2ed59 100644 --- a/Engine/source/sfx/sfxSound.h +++ b/Engine/source/sfx/sfxSound.h @@ -81,6 +81,9 @@ class SFXSound : public SFXSource, /// _initBuffer() used for managing virtual sources. U32 mDuration; + ///Used for setPosition (time in miliseconds) + U32 mSetPositionValue; + /// Create a new voice for this source. bool _allocVoice( SFXDevice* device ); From 932ba0aed8644cd4315f4e9199bcd65a973868e2 Mon Sep 17 00:00:00 2001 From: irei1as Date: Sun, 11 Mar 2018 17:29:30 +0100 Subject: [PATCH 14/75] Update sfxSound.cpp --- Engine/source/sfx/sfxSound.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Engine/source/sfx/sfxSound.cpp b/Engine/source/sfx/sfxSound.cpp index df856ae8f..6b4895f80 100644 --- a/Engine/source/sfx/sfxSound.cpp +++ b/Engine/source/sfx/sfxSound.cpp @@ -81,6 +81,7 @@ SFXSound::SFXSound( SFXProfile *profile, SFXDescription* desc ) : Parent( profile, desc ), mVoice( NULL ) { + mSetPositionValue = 0; } //----------------------------------------------------------------------------- @@ -411,6 +412,9 @@ void SFXSound::_play() Platform::outputDebugString( "[SFXSound] virtualizing playback of source '%i'", getId() ); #endif } + if(getPosition() != mSetPositionValue) + setPosition(mSetPositionValue); + mSetPositionValue = 0; //Non looping sounds need this to reset. } //----------------------------------------------------------------------------- @@ -421,6 +425,7 @@ void SFXSound::_stop() if( mVoice ) mVoice->stop(); + mSetPositionValue = 0; } //----------------------------------------------------------------------------- @@ -431,6 +436,7 @@ void SFXSound::_pause() if( mVoice ) mVoice->pause(); + mSetPositionValue = getPosition(); } //----------------------------------------------------------------------------- @@ -511,6 +517,8 @@ void SFXSound::_updatePriority() U32 SFXSound::getPosition() const { + if( getLastStatus() == SFXStatusStopped) + return mSetPositionValue; if( mVoice ) return mVoice->getFormat().getDuration( mVoice->getPosition() ); else @@ -522,6 +530,8 @@ U32 SFXSound::getPosition() const void SFXSound::setPosition( U32 ms ) { AssertFatal( ms < getDuration(), "SFXSound::setPosition() - position out of range" ); + mSetPositionValue = ms; + if( mVoice ) mVoice->setPosition( mVoice->getFormat().getSampleCount( ms ) ); else From 8b14790c93eadfe51424dcf7c06de0082be7cbb7 Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Wed, 18 Jul 2018 20:35:59 -0400 Subject: [PATCH 15/75] =?UTF-8?q?Adds=20features=20to=20GuiInputCtrl=20Thi?= =?UTF-8?q?s=20commit=20adds=20three=20new=20features=20to=20the=20GuiInpu?= =?UTF-8?q?tCtrl.=20All=20three=20default=20to=20off,=20so=20it=20is=20ful?= =?UTF-8?q?ly=20backward=20compatible=20with=20existing=20scripts.=20The?= =?UTF-8?q?=20new=20options=20are:=20sendAxisEvents=20=E2=80=93=20If=20tru?= =?UTF-8?q?e,=20the=20control=20will=20generate=20onAxisEvent()=20callback?= =?UTF-8?q?s=20for=20all=20axis=20events.=20This=20is=20useful=20for=20bin?= =?UTF-8?q?ding=20joystick/controller=20axes=20to=20game=20actions.=20send?= =?UTF-8?q?BreakEvents=20=E2=80=93=20If=20true,=20the=20control=20will=20g?= =?UTF-8?q?enerate=20onInputEvent()=20callbacks=20for=20SI=5FBREAK=20event?= =?UTF-8?q?s=20for=20all=20keys=20and=20buttons.=20By=20default=20the=20ca?= =?UTF-8?q?llback=20is=20only=20triggered=20for=20break=20events=20on=20mo?= =?UTF-8?q?difier=20keys.=20SendModifierEvents=20=E2=80=93=20If=20true=20S?= =?UTF-8?q?I=5FMAKE=20events=20for=20modifier=20keys=20will=20generate=20c?= =?UTF-8?q?allbacks.=20By=20default,=20only=20the=20break=20events=20are?= =?UTF-8?q?=20sent=20for=20modifier=20keys.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Engine/source/gui/utility/guiInputCtrl.cpp | 95 +++++++++++++++++----- Engine/source/gui/utility/guiInputCtrl.h | 34 +++++--- 2 files changed, 95 insertions(+), 34 deletions(-) diff --git a/Engine/source/gui/utility/guiInputCtrl.cpp b/Engine/source/gui/utility/guiInputCtrl.cpp index c1799b43f..ba4eec0aa 100644 --- a/Engine/source/gui/utility/guiInputCtrl.cpp +++ b/Engine/source/gui/utility/guiInputCtrl.cpp @@ -58,9 +58,25 @@ ConsoleDocClass( GuiInputCtrl, //------------------------------------------------------------------------------ +GuiInputCtrl::GuiInputCtrl() + : mSendAxisEvents(false), + mSendBreakEvents(false), + mSendModifierEvents(false) +{ +} + +//------------------------------------------------------------------------------ + void GuiInputCtrl::initPersistFields() { - + addGroup("GuiInputCtrl"); + addField("sendAxisEvents", TypeBool, Offset(mSendAxisEvents, GuiInputCtrl), + "If true, onAxisEvent callbacks will be sent for SI_AXIS Move events (Default false)."); + addField("sendBreakEvents", TypeBool, Offset(mSendBreakEvents, GuiInputCtrl), + "If true, break events for all devices will generate callbacks (Default false)."); + addField("sendModifierEvents", TypeBool, Offset(mSendModifierEvents, GuiInputCtrl), + "If true, Make events will be sent for modifier keys (Default false)."); + endGroup("GuiInputCtrl"); Parent::initPersistFields(); } @@ -110,6 +126,8 @@ static bool isModifierKey( U16 keyCode ) case KEY_RALT: case KEY_LSHIFT: case KEY_RSHIFT: + case KEY_MAC_LOPT: + case KEY_MAC_ROPT: return( true ); } @@ -117,33 +135,46 @@ static bool isModifierKey( U16 keyCode ) } IMPLEMENT_CALLBACK( GuiInputCtrl, onInputEvent, void, (const char* device, const char* action, bool state ), - ( device, action, state), - "@brief Callback that occurs when an input is triggered on this control\n\n" - "@param device The device type triggering the input, such as keyboard, mouse, etc\n" - "@param action The actual event occuring, such as a key or button\n" - "@param state True if the action is being pressed, false if it is being release\n\n" -); + ( device, action, state), + "@brief Callback that occurs when an input is triggered on this control\n\n" + "@param device The device type triggering the input, such as keyboard, mouse, etc\n" + "@param action The actual event occuring, such as a key or button\n" + "@param state True if the action is being pressed, false if it is being release\n\n"); + +IMPLEMENT_CALLBACK(GuiInputCtrl, onAxisEvent, void, (const char* device, const char* action, F32 axisValue), + (device, action, axisValue), + "@brief Callback that occurs when an axis event is triggered on this control\n\n" + "@param device The device type triggering the input, such as mouse, joystick, gamepad, etc\n" + "@param action The ActionMap code for the axis\n" + "@param axisValue The current value of the axis\n\n"); //------------------------------------------------------------------------------ bool GuiInputCtrl::onInputEvent( const InputEventInfo &event ) { - // TODO - add POV support... + char deviceString[32]; if ( event.action == SI_MAKE ) { if ( event.objType == SI_BUTTON || event.objType == SI_POV - || ( ( event.objType == SI_KEY ) && !isModifierKey( event.objInst ) ) ) + || event.objType == SI_KEY ) { - char deviceString[32]; if ( !ActionMap::getDeviceName( event.deviceType, event.deviceInst, deviceString ) ) - return( false ); + return false; - const char* actionString = ActionMap::buildActionString( &event ); + if ((event.objType == SI_KEY) && isModifierKey(event.objInst)) + { + if (!mSendModifierEvents) + return false; - //Con::executef( this, "onInputEvent", deviceString, actionString, "1" ); - onInputEvent_callback(deviceString, actionString, 1); - - return( true ); + const char* actionString = INPUTMGR->findKeyboardMapDescFromCode(event.objInst); + onInputEvent_callback(deviceString, actionString, 1); + } + else + { + const char* actionString = ActionMap::buildActionString(&event); + onInputEvent_callback(deviceString, actionString, 1); + } + return true; } } else if ( event.action == SI_BREAK ) @@ -152,14 +183,36 @@ bool GuiInputCtrl::onInputEvent( const InputEventInfo &event ) { char keyString[32]; if ( !ActionMap::getKeyString( event.objInst, keyString ) ) - return( false ); + return false; - //Con::executef( this, "onInputEvent", "keyboard", keyString, "0" ); - onInputEvent_callback("keyboard", keyString, 0); + onInputEvent_callback("keyboard", keyString, 0); + return true; + } + else if (mSendBreakEvents) + { + if (!ActionMap::getDeviceName(event.deviceType, event.deviceInst, deviceString)) + return false; - return( true ); + const char* actionString = ActionMap::buildActionString(&event); + + onInputEvent_callback(deviceString, actionString, 0); + return true; } } + else if (mSendAxisEvents && ((event.objType == SI_AXIS) || (event.objType == SI_INT) || (event.objType == SI_FLOAT))) + { + F32 fValue = event.fValue; + if (event.objType == SI_INT) + fValue = (F32)event.iValue; - return( false ); + if (!ActionMap::getDeviceName(event.deviceType, event.deviceInst, deviceString)) + return false; + + const char* actionString = ActionMap::buildActionString(&event); + + onAxisEvent_callback(deviceString, actionString, fValue); + return (event.deviceType != MouseDeviceType); // Don't consume mouse move events + } + + return false; } diff --git a/Engine/source/gui/utility/guiInputCtrl.h b/Engine/source/gui/utility/guiInputCtrl.h index e5769740c..be60371f3 100644 --- a/Engine/source/gui/utility/guiInputCtrl.h +++ b/Engine/source/gui/utility/guiInputCtrl.h @@ -32,23 +32,31 @@ /// to script. This is useful for implementing custom keyboard handling code. class GuiInputCtrl : public GuiMouseEventCtrl { - public: +protected: + bool mSendAxisEvents; + bool mSendBreakEvents; + bool mSendModifierEvents; - typedef GuiMouseEventCtrl Parent; - - // GuiControl. - virtual bool onWake(); - virtual void onSleep(); +public: - virtual bool onInputEvent( const InputEventInfo &event ); - - static void initPersistFields(); + typedef GuiMouseEventCtrl Parent; - DECLARE_CONOBJECT(GuiInputCtrl); - DECLARE_CATEGORY( "Gui Other Script" ); - DECLARE_DESCRIPTION( "A control that locks the mouse and reports all keyboard input events to script." ); + GuiInputCtrl(); - DECLARE_CALLBACK( void, onInputEvent, ( const char* device, const char* action, bool state )); + // GuiControl. + virtual bool onWake(); + virtual void onSleep(); + + virtual bool onInputEvent( const InputEventInfo &event ); + + static void initPersistFields(); + + DECLARE_CONOBJECT(GuiInputCtrl); + DECLARE_CATEGORY( "Gui Other Script" ); + DECLARE_DESCRIPTION( "A control that locks the mouse and reports all input events to script." ); + + DECLARE_CALLBACK( void, onInputEvent, ( const char* device, const char* action, bool state )); + DECLARE_CALLBACK(void, onAxisEvent, (const char* device, const char* action, F32 axisValue)); }; #endif // _GUI_INPUTCTRL_H From ef9a9da83f7227ed9190e930ad1d03f2bf8e0020 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 29 Oct 2018 18:01:56 +0000 Subject: [PATCH 16/75] OpenALEffects Ground work, this commit enables reverb zones and opens the slots for other effects to be added later. Tested using the full template. Build your openal dll and your full.exe use one of the environment presets and it will work --- Engine/source/sfx/openal/LoadOAL.h | 51 + Engine/source/sfx/openal/sfxALDevice.cpp | 131 +- Engine/source/sfx/openal/sfxALDevice.h | 9 + Engine/source/sfx/openal/sfxALVoice.cpp | 3 +- Engine/source/sfx/openal/win32/LoadOAL.cpp | 111 + Engine/source/sfx/sfxCommon.h | 343 +-- Engine/source/sfx/sfxDescription.cpp | 212 +- Engine/source/sfx/sfxDevice.h | 3 + Engine/source/sfx/sfxEnvironment.cpp | 211 +- Engine/source/sfx/sfxSystem.cpp | 6 + .../core/scripts/client/audioEnvironments.cs | 2093 ++++++++++------- 11 files changed, 1961 insertions(+), 1212 deletions(-) diff --git a/Engine/source/sfx/openal/LoadOAL.h b/Engine/source/sfx/openal/LoadOAL.h index 0a58e074b..b52047cca 100644 --- a/Engine/source/sfx/openal/LoadOAL.h +++ b/Engine/source/sfx/openal/LoadOAL.h @@ -36,6 +36,8 @@ #else # include # include +# include +# include #endif #ifndef ALAPIENTRY @@ -134,6 +136,31 @@ typedef void * (ALCAPIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, con typedef ALCenum (ALCAPIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname ); typedef const ALCchar* (ALCAPIENTRY *LPALCGETSTRING)( ALCdevice *device, ALCenum param ); typedef void (ALCAPIENTRY *LPALCGETINTEGERV)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *dest ); +///Changes for effects +typedef void (ALAPIENTRY *LPALGENEFFECTS)(ALsizei n, ALuint *effects); +typedef void (ALAPIENTRY *LPALDELETEEFFECTS)(ALsizei n, const ALuint *effects); +typedef ALboolean (ALAPIENTRY *LPALISEFFECT)(ALuint effect); +typedef void (ALAPIENTRY *LPALEFFECTI)(ALuint effect, ALenum param, ALint value); +typedef void (ALAPIENTRY *LPALEFFECTIV)(ALuint effect, ALenum param, const ALint *values); +typedef void (ALAPIENTRY *LPALEFFECTF)(ALuint effect, ALenum param, ALfloat value); +typedef void (ALAPIENTRY *LPALEFFECTFV)(ALuint effect, ALenum param, const ALfloat *values); +typedef void (ALAPIENTRY *LPALGETEFFECTI)(ALuint effect, ALenum param, ALint *value); +typedef void (ALAPIENTRY *LPALGETEFFECTIV)(ALuint effect, ALenum param, ALint *values); +typedef void (ALAPIENTRY *LPALGETEFFECTF)(ALuint effect, ALenum param, ALfloat *value); +typedef void (ALAPIENTRY *LPALGETEFFECTFV)(ALuint effect, ALenum param, ALfloat *values); +typedef void (ALAPIENTRY *LPALRELEASEALEFFECTS)(ALCdevice *device); +typedef void (ALAPIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei n, ALuint *effectslots); +typedef void (ALAPIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei n, const ALuint *effectslots); +typedef ALboolean (ALAPIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint effectslot); +typedef void (ALAPIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint effectslot, ALenum param, ALint value); +typedef void (ALAPIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint effectslot, ALenum param, const ALint *values); +typedef void (ALAPIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint effectslot, ALenum param, ALfloat value); +typedef void (ALAPIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint effectslot, ALenum param, const ALfloat *values); +typedef void (ALAPIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint effectslot, ALenum param, ALint *value); +typedef void (ALAPIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint effectslot, ALenum param, ALint *values); +typedef void (ALAPIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint effectslot, ALenum param, ALfloat *value); +typedef void (ALAPIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint effectslot, ALenum param, ALfloat *values); +typedef void (ALAPIENTRY *LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); typedef struct { @@ -166,6 +193,7 @@ typedef struct LPALISSOURCE alIsSource; LPALSOURCEI alSourcei; LPALSOURCEF alSourcef; + LPALSOURCE3I alSource3i; LPALSOURCE3F alSource3f; LPALSOURCEFV alSourcefv; LPALGETSOURCEI alGetSourcei; @@ -203,6 +231,29 @@ typedef struct LPALCISEXTENSIONPRESENT alcIsExtensionPresent; LPALCGETPROCADDRESS alcGetProcAddress; LPALCGETENUMVALUE alcGetEnumValue; + LPALGENEFFECTS alGenEffects; + LPALDELETEEFFECTS alDeleteEffects; + LPALISEFFECT alIsEffect; + LPALEFFECTI alEffecti; + LPALEFFECTIV alEffectiv; + LPALEFFECTF alEffectf; + LPALEFFECTFV alEffectfv; + LPALGETEFFECTI alGetEffecti; + LPALGETEFFECTIV alGetEffectiv; + LPALGETEFFECTF alGetEffectf; + LPALGETEFFECTFV alGetEffectfv; + LPALRELEASEALEFFECTS alReleaseEffects; + LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots; + LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots; + LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot; + LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti; + LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv; + LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf; + LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv; + LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti; + LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv; + LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf; + LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; } OPENALFNTABLE, *LPOPENALFNTABLE; #endif diff --git a/Engine/source/sfx/openal/sfxALDevice.cpp b/Engine/source/sfx/openal/sfxALDevice.cpp index 13e891ece..e620a483c 100644 --- a/Engine/source/sfx/openal/sfxALDevice.cpp +++ b/Engine/source/sfx/openal/sfxALDevice.cpp @@ -42,16 +42,21 @@ SFXALDevice::SFXALDevice( SFXProvider *provider, // TODO: The OpenAL device doesn't set the primary buffer // $pref::SFX::frequency or $pref::SFX::bitrate! + //check auxiliary device sends 4 and add them to the device + ALint attribs[4] = { 0 }; + ALCint iSends = 0; + attribs[0] = ALC_MAX_AUXILIARY_SENDS; + attribs[1] = 4; mDevice = mOpenAL.alcOpenDevice( name ); mOpenAL.alcGetError( mDevice ); if( mDevice ) { - mContext = mOpenAL.alcCreateContext( mDevice, NULL ); + mContext = mOpenAL.alcCreateContext( mDevice, attribs ); if( mContext ) mOpenAL.alcMakeContextCurrent( mContext ); - + mOpenAL.alcGetIntegerv(mDevice, ALC_MAX_AUXILIARY_SENDS, 1, &iSends); U32 err = mOpenAL.alcGetError( mDevice ); if( err != ALC_NO_ERROR ) @@ -78,7 +83,10 @@ SFXALDevice::SFXALDevice( SFXProvider *provider, SFXALDevice::~SFXALDevice() { _releaseAllResources(); - + ///cleanup our effects + mOpenAL.alDeleteAuxiliaryEffectSlots(4, effectSlot); + mOpenAL.alDeleteEffects(2, effect); + ///cleanup of effects ends mOpenAL.alcMakeContextCurrent( NULL ); mOpenAL.alcDestroyContext( mContext ); mOpenAL.alcCloseDevice( mDevice ); @@ -145,6 +153,9 @@ void SFXALDevice::setListener( U32 index, const SFXListenerProperties& listener mOpenAL.alListenerfv( AL_POSITION, pos ); mOpenAL.alListenerfv( AL_VELOCITY, velocity ); mOpenAL.alListenerfv( AL_ORIENTATION, (const F32 *)&tupple[0] ); + ///Pass a unit size to openal, 1.0 assumes 1 meter to 1 game unit. + ///Crucial for air absorbtion calculations. + mOpenAL.alListenerf(AL_METERS_PER_UNIT, 1.0f); } //----------------------------------------------------------------------------- @@ -164,7 +175,13 @@ void SFXALDevice::setDistanceModel( SFXDistanceModel model ) if( mUserRolloffFactor != mRolloffFactor ) _setRolloffFactor( mUserRolloffFactor ); break; - + /// create a case for our exponential distance model + case SFXDistanceModelExponent: + mOpenAL.alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED); + if (mUserRolloffFactor != mRolloffFactor) + _setRolloffFactor(mUserRolloffFactor); + break; + default: AssertWarn( false, "SFXALDevice::setDistanceModel - distance model not implemented" ); } @@ -200,3 +217,109 @@ void SFXALDevice::setRolloffFactor( F32 factor ) mUserRolloffFactor = factor; } + +void SFXALDevice::openSlots() +{ + for (uLoop = 0; uLoop < 4; uLoop++) + { + mOpenAL.alGenAuxiliaryEffectSlots(1, &effectSlot[uLoop]); + } + + for (uLoop = 0; uLoop < 2; uLoop++) + { + mOpenAL.alGenEffects(1, &effect[uLoop]); + } + ///debug string output so we know our slots are open + Platform::outputDebugString("Slots Open"); +} + +///create reverb effect +void SFXALDevice::setReverb(const SFXReverbProperties& reverb) +{ + ///output a debug string so we know each time the reverb changes + Platform::outputDebugString("Updated"); + + ///load an efxeaxreverb default and add our values from + ///sfxreverbproperties to it + EFXEAXREVERBPROPERTIES prop = EFX_REVERB_PRESET_GENERIC; + + prop.flDensity = reverb.flDensity; + prop.flDiffusion = reverb.flDiffusion; + prop.flGain = reverb.flGain; + prop.flGainHF = reverb.flGainHF; + prop.flGainLF = reverb.flGainLF; + prop.flDecayTime = reverb.flDecayTime; + prop.flDecayHFRatio = reverb.flDecayHFRatio; + prop.flDecayLFRatio = reverb.flDecayLFRatio; + prop.flReflectionsGain = reverb.flReflectionsGain; + prop.flReflectionsDelay = reverb.flReflectionsDelay; + prop.flLateReverbGain = reverb.flLateReverbGain; + prop.flLateReverbDelay = reverb.flLateReverbDelay; + prop.flEchoTime = reverb.flEchoTime; + prop.flEchoDepth = reverb.flEchoDepth; + prop.flModulationTime = reverb.flModulationTime; + prop.flModulationDepth = reverb.flModulationDepth; + prop.flAirAbsorptionGainHF = reverb.flAirAbsorptionGainHF; + prop.flHFReference = reverb.flHFReference; + prop.flLFReference = reverb.flLFReference; + prop.flRoomRolloffFactor = reverb.flRoomRolloffFactor; + prop.iDecayHFLimit = reverb.iDecayHFLimit; + + if (mOpenAL.alGetEnumValue("AL_EFFECT_EAXREVERB") != 0) + { + + /// EAX Reverb is available. Set the EAX effect type + + mOpenAL.alEffecti(effect[0], AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + + ///add our values to the setup of the reverb + + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DENSITY, prop.flDensity); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DIFFUSION, prop.flDiffusion); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAIN, prop.flGain); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAINHF, prop.flGainHF); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAINLF, prop.flGainLF); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_TIME, prop.flDecayTime); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_HFRATIO, prop.flDecayHFRatio); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_LFRATIO, prop.flDecayLFRatio); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_REFLECTIONS_GAIN, prop.flReflectionsGain); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_REFLECTIONS_DELAY, prop.flReflectionsDelay); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LATE_REVERB_GAIN, prop.flLateReverbGain); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LATE_REVERB_DELAY, prop.flLateReverbDelay); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ECHO_TIME, prop.flEchoTime); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ECHO_DEPTH, prop.flEchoDepth); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_MODULATION_TIME, prop.flModulationTime); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_MODULATION_DEPTH, prop.flModulationDepth); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_AIR_ABSORPTION_GAINHF, prop.flAirAbsorptionGainHF); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_HFREFERENCE, prop.flHFReference); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LFREFERENCE, prop.flLFReference); + mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, prop.flRoomRolloffFactor); + mOpenAL.alEffecti(effect[0], AL_EAXREVERB_DECAY_HFLIMIT, prop.iDecayHFLimit); + mOpenAL.alAuxiliaryEffectSloti(1, AL_EFFECTSLOT_EFFECT, effect[0]); + Platform::outputDebugString("eax reverb properties set"); + + } + else + { + + /// No EAX Reverb. Set the standard reverb effect + mOpenAL.alEffecti(effect[0], AL_EFFECT_TYPE, AL_EFFECT_REVERB); + + mOpenAL.alEffectf(effect[0], AL_REVERB_DENSITY, prop.flDensity); + mOpenAL.alEffectf(effect[0], AL_REVERB_DIFFUSION, prop.flDiffusion); + mOpenAL.alEffectf(effect[0], AL_REVERB_GAIN, prop.flGain); + mOpenAL.alEffectf(effect[0], AL_REVERB_GAINHF, prop.flGainHF); + mOpenAL.alEffectf(effect[0], AL_REVERB_DECAY_TIME, prop.flDecayTime); + mOpenAL.alEffectf(effect[0], AL_REVERB_DECAY_HFRATIO, prop.flDecayHFRatio); + mOpenAL.alEffectf(effect[0], AL_REVERB_REFLECTIONS_GAIN, prop.flReflectionsGain); + mOpenAL.alEffectf(effect[0], AL_REVERB_REFLECTIONS_DELAY, prop.flReflectionsDelay); + mOpenAL.alEffectf(effect[0], AL_REVERB_LATE_REVERB_GAIN, prop.flLateReverbGain); + mOpenAL.alEffectf(effect[0], AL_REVERB_LATE_REVERB_DELAY, prop.flLateReverbDelay); + mOpenAL.alEffectf(effect[0], AL_REVERB_AIR_ABSORPTION_GAINHF, prop.flAirAbsorptionGainHF); + mOpenAL.alEffectf(effect[0], AL_REVERB_ROOM_ROLLOFF_FACTOR, prop.flRoomRolloffFactor); + mOpenAL.alEffecti(effect[0], AL_REVERB_DECAY_HFLIMIT, prop.iDecayHFLimit); + mOpenAL.alAuxiliaryEffectSloti(1, AL_EFFECTSLOT_EFFECT, effect[0]); + + } + +} \ No newline at end of file diff --git a/Engine/source/sfx/openal/sfxALDevice.h b/Engine/source/sfx/openal/sfxALDevice.h index ee6f1ccdb..277b2496a 100644 --- a/Engine/source/sfx/openal/sfxALDevice.h +++ b/Engine/source/sfx/openal/sfxALDevice.h @@ -85,6 +85,15 @@ class SFXALDevice : public SFXDevice virtual void setDistanceModel( SFXDistanceModel model ); virtual void setDopplerFactor( F32 factor ); virtual void setRolloffFactor( F32 factor ); + //function for openAL to open slots + virtual void openSlots(); + //slots + ALuint effectSlot[4] = { 0 }; + ALuint effect[2] = { 0 }; + ALuint uLoop; + //get values from sfxreverbproperties and pass it to openal device + virtual void setReverb(const SFXReverbProperties& reverb); + virtual void resetReverb() {} }; #endif // _SFXALDEVICE_H_ \ No newline at end of file diff --git a/Engine/source/sfx/openal/sfxALVoice.cpp b/Engine/source/sfx/openal/sfxALVoice.cpp index 21fc51700..ccba74143 100644 --- a/Engine/source/sfx/openal/sfxALVoice.cpp +++ b/Engine/source/sfx/openal/sfxALVoice.cpp @@ -118,7 +118,8 @@ void SFXALVoice::_play() #ifdef DEBUG_SPEW Platform::outputDebugString( "[SFXALVoice] Starting playback" ); #endif - + //send every voice that plays to the alauxiliary slot that has the reverb + mOpenAL.alSource3i(mSourceName, AL_AUXILIARY_SEND_FILTER, 1, 0, AL_FILTER_NULL); mOpenAL.alSourcePlay( mSourceName ); //WORKAROUND: Adjust play cursor for buggy OAL when resuming playback. Do this after alSourcePlay diff --git a/Engine/source/sfx/openal/win32/LoadOAL.cpp b/Engine/source/sfx/openal/win32/LoadOAL.cpp index a3a31a0f7..df28cd440 100644 --- a/Engine/source/sfx/openal/win32/LoadOAL.cpp +++ b/Engine/source/sfx/openal/win32/LoadOAL.cpp @@ -439,7 +439,118 @@ ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE lpOALFnTable OutputDebugStringA("Failed to retrieve 'alcGetEnumValue' function address\n"); return AL_FALSE; } + lpOALFnTable->alGenEffects = (LPALGENEFFECTS)GetProcAddress(g_hOpenALDLL, "alGenEffects"); + if (lpOALFnTable->alGenEffects == NULL) + { + OutputDebugStringA("Failed to retrieve 'alGenEffects' function address\n"); + } + lpOALFnTable->alEffecti = (LPALEFFECTI)GetProcAddress(g_hOpenALDLL, "alEffecti"); + if (lpOALFnTable->alEffecti == NULL) + { + OutputDebugStringA("Failed to retrieve 'alEffecti' function address\n"); + } + lpOALFnTable->alEffectiv = (LPALEFFECTIV)GetProcAddress(g_hOpenALDLL, "alEffectiv"); + if (lpOALFnTable->alEffectiv == NULL) + { + OutputDebugStringA("Failed to retrieve 'alEffectiv' function address\n"); + } + lpOALFnTable->alEffectf = (LPALEFFECTF)GetProcAddress(g_hOpenALDLL, "alEffectf"); + if (lpOALFnTable->alEffectf == NULL) + { + OutputDebugStringA("Failed to retrieve 'alEffectf' function address\n"); + } + lpOALFnTable->alEffectfv = (LPALEFFECTFV)GetProcAddress(g_hOpenALDLL, "alEffectfv"); + if (lpOALFnTable->alEffectfv == NULL) + { + OutputDebugStringA("Failed to retrieve 'alEffectfv' function address\n"); + } + lpOALFnTable->alGetEffecti = (LPALGETEFFECTI)GetProcAddress(g_hOpenALDLL, "alGetEffecti"); + if (lpOALFnTable->alGetEffecti == NULL) + { + OutputDebugStringA("Failed to retrieve 'alGetEffecti' function address\n"); + } + lpOALFnTable->alGetEffectiv = (LPALGETEFFECTIV)GetProcAddress(g_hOpenALDLL, "alGetEffectiv"); + if (lpOALFnTable->alGetEffectiv == NULL) + { + OutputDebugStringA("Failed to retrieve 'alGetEffectiv' function address\n"); + } + lpOALFnTable->alGetEffectf = (LPALGETEFFECTF)GetProcAddress(g_hOpenALDLL, "alGetEffectf"); + if (lpOALFnTable->alGetEffectf == NULL) + { + OutputDebugStringA("Failed to retrieve 'alGetEffectf' function address\n"); + } + lpOALFnTable->alGetEffectfv = (LPALGETEFFECTFV)GetProcAddress(g_hOpenALDLL, "alGetEffectfv"); + if (lpOALFnTable->alGetEffectfv == NULL) + { + OutputDebugStringA("Failed to retrieve 'alGetEffectfv' function address\n"); + } + lpOALFnTable->alDeleteEffects = (LPALDELETEEFFECTS)GetProcAddress(g_hOpenALDLL, "alDeleteEffects"); + if (lpOALFnTable->alDeleteEffects == NULL) + { + OutputDebugStringA("Failed to retrieve 'alDeleteEffects' function address\n"); + } + lpOALFnTable->alIsEffect = (LPALISEFFECT)GetProcAddress(g_hOpenALDLL, "alIsEffect"); + if (lpOALFnTable->alIsEffect == NULL) + { + OutputDebugStringA("Failed to retrieve 'alIsEffect' function address\n"); + } + lpOALFnTable->alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSlotf"); + if (lpOALFnTable->alAuxiliaryEffectSlotf == NULL) + { + OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSlotf' function address\n"); + } + lpOALFnTable->alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSlotfv"); + if (lpOALFnTable->alAuxiliaryEffectSlotfv == NULL) + { + OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSlotfv' function address\n"); + } + lpOALFnTable->alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSloti"); + if (lpOALFnTable->alAuxiliaryEffectSloti == NULL) + { + OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSloti' function address\n"); + } + lpOALFnTable->alAuxiliaryEffectSlotiv = (LPALAUXILIARYEFFECTSLOTIV)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSlotiv"); + if (lpOALFnTable->alAuxiliaryEffectSlotiv == NULL) + { + OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSlotiv' function address\n"); + } + lpOALFnTable->alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT)GetProcAddress(g_hOpenALDLL, "alIsAuxiliaryEffectSlot"); + if (lpOALFnTable->alIsAuxiliaryEffectSlot == NULL) + { + OutputDebugStringA("Failed to retrieve 'alIsAuxiliaryEffectSlot' function address\n"); + } + lpOALFnTable->alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)GetProcAddress(g_hOpenALDLL, "alGenAuxiliaryEffectSlots"); + if (lpOALFnTable->alGenAuxiliaryEffectSlots == NULL) + { + OutputDebugStringA("Failed to retrieve 'alGenAuxiliaryEffectSlots' function address\n"); + } + lpOALFnTable->alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS)GetProcAddress(g_hOpenALDLL, "alDeleteAuxiliaryEffectSlots"); + if (lpOALFnTable->alDeleteAuxiliaryEffectSlots == NULL) + { + OutputDebugStringA("Failed to retrieve 'alDeleteAuxiliaryEffectSlots' function address\n"); + } + lpOALFnTable->alGetAuxiliaryEffectSlotf = (LPALGETAUXILIARYEFFECTSLOTF)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSlotf"); + if (lpOALFnTable->alGetAuxiliaryEffectSlotf == NULL) + { + OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSlotf' function address\n"); + } + lpOALFnTable->alGetAuxiliaryEffectSlotfv = (LPALGETAUXILIARYEFFECTSLOTFV)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSlotfv"); + if (lpOALFnTable->alGetAuxiliaryEffectSlotfv == NULL) + { + OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSlotfv' function address\n"); + } + lpOALFnTable->alGetAuxiliaryEffectSloti = (LPALGETAUXILIARYEFFECTSLOTI)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSloti"); + if (lpOALFnTable->alGetAuxiliaryEffectSloti == NULL) + { + OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSloti' function address\n"); + } + lpOALFnTable->alGetAuxiliaryEffectSlotiv = (LPALGETAUXILIARYEFFECTSLOTIV)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSlotiv"); + if (lpOALFnTable->alGetAuxiliaryEffectSlotiv == NULL) + { + OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSlotiv' function address\n"); + } + lpOALFnTable->alSource3i = (LPALSOURCE3I)GetProcAddress(g_hOpenALDLL, "alSource3i"); return AL_TRUE; } diff --git a/Engine/source/sfx/sfxCommon.h b/Engine/source/sfx/sfxCommon.h index 7b69b2506..a6c764ab9 100644 --- a/Engine/source/sfx/sfxCommon.h +++ b/Engine/source/sfx/sfxCommon.h @@ -153,6 +153,7 @@ enum SFXDistanceModel { SFXDistanceModelLinear, ///< Volume decreases linearly from min to max where it reaches zero. SFXDistanceModelLogarithmic, ///< Volume halves every min distance steps starting from min distance; attenuation stops at max distance. + SFXDistanceModelExponent, /// exponential falloff for distance attenuation. }; DefineEnumType( SFXDistanceModel ); @@ -187,6 +188,14 @@ inline F32 SFXDistanceAttenuation( SFXDistanceModel model, F32 minDistance, F32 gain = minDistance / ( minDistance + rolloffFactor * ( distance - minDistance ) ); break; + + ///create exponential distance model + case SFXDistanceModelExponent: + distance = getMax(distance, minDistance); + distance = getMin(distance, maxDistance); + + gain = pow((distance / minDistance), (-rolloffFactor)); + break; } @@ -313,97 +322,97 @@ class SFXFormat /// Reverb environment properties. /// /// @note A given device may not implement all properties. +///restructure our reverbproperties to match openal + class SFXReverbProperties { - public: - - typedef void Parent; - - F32 mEnvSize; - F32 mEnvDiffusion; - S32 mRoom; - S32 mRoomHF; - S32 mRoomLF; - F32 mDecayTime; - F32 mDecayHFRatio; - F32 mDecayLFRatio; - S32 mReflections; - F32 mReflectionsDelay; - F32 mReflectionsPan[ 3 ]; - S32 mReverb; - F32 mReverbDelay; - F32 mReverbPan[ 3 ]; - F32 mEchoTime; - F32 mEchoDepth; - F32 mModulationTime; - F32 mModulationDepth; - F32 mAirAbsorptionHF; - F32 mHFReference; - F32 mLFReference; - F32 mRoomRolloffFactor; - F32 mDiffusion; - F32 mDensity; - S32 mFlags; - - SFXReverbProperties() - : mEnvSize( 7.5f ), - mEnvDiffusion( 1.0f ), - mRoom( -1000 ), - mRoomHF( -100 ), - mRoomLF( 0 ), - mDecayTime( 1.49f ), - mDecayHFRatio( 0.83f ), - mDecayLFRatio( 1.0f ), - mReflections( -2602 ), - mReflectionsDelay( 0.007f ), - mReverb( 200 ), - mReverbDelay( 0.011f ), - mEchoTime( 0.25f ), - mEchoDepth( 0.0f ), - mModulationTime( 0.25f ), - mModulationDepth( 0.0f ), - mAirAbsorptionHF( -5.0f ), - mHFReference( 5000.0f ), - mLFReference( 250.0f ), - mRoomRolloffFactor( 0.0f ), - mDiffusion( 100.0f ), - mDensity( 100.0f ), - mFlags( 0 ) - { - mReflectionsPan[ 0 ] = 0.0f; - mReflectionsPan[ 1 ] = 0.0f; - mReflectionsPan[ 2 ] = 0.0f; - - mReverbPan[ 0 ] = 0.0f; - mReverbPan[ 1 ] = 0.0f; - mReverbPan[ 2 ] = 0.0f; - } - - void validate() - { - mEnvSize = mClampF( mEnvSize, 1.0f, 100.0f ); - mEnvDiffusion = mClampF( mEnvDiffusion, 0.0f, 1.0f ); - mRoom = mClamp( mRoom, -10000, 0 ); - mRoomHF = mClamp( mRoomHF, -10000, 0 ); - mRoomLF = mClamp( mRoomLF, -10000, 0 ); - mDecayTime = mClampF( mDecayTime, 0.1f, 20.0f ); - mDecayHFRatio = mClampF( mDecayHFRatio, 0.1f, 2.0f ); - mDecayLFRatio = mClampF( mDecayLFRatio, 0.1f, 2.0f ); - mReflections = mClamp( mReflections, -10000, 1000 ); - mReflectionsDelay = mClampF( mReflectionsDelay, 0.0f, 0.3f ); - mReverb = mClamp( mReverb, -10000, 2000 ); - mReverbDelay = mClampF( mReverbDelay, 0.0f, 0.1f ); - mEchoTime = mClampF( mEchoTime, 0.075f, 0.25f ); - mEchoDepth = mClampF( mEchoDepth, 0.0f, 1.0f ); - mModulationTime = mClampF( mModulationTime, 0.04f, 4.0f ); - mModulationDepth = mClampF( mModulationDepth, 0.0f, 1.0f ); - mAirAbsorptionHF = mClampF( mAirAbsorptionHF, -100.0f, 0.0f ); - mHFReference = mClampF( mHFReference, 1000.0f, 20000.0f ); - mLFReference = mClampF( mLFReference, 20.0f, 1000.0f ); - mRoomRolloffFactor = mClampF( mRoomRolloffFactor, 0.0f, 10.0f ); - mDiffusion = mClampF( mDiffusion, 0.0f, 100.0f ); - mDensity = mClampF( mDensity, 0.0f, 100.0f ); - } +public: + + struct Parent; + + float flDensity; + float flDiffusion; + float flGain; + float flGainHF; + float flGainLF; + float flDecayTime; + float flDecayHFRatio; + float flDecayLFRatio; + float flReflectionsGain; + float flReflectionsDelay; + float flReflectionsPan[3]; + float flLateReverbGain; + float flLateReverbDelay; + float flLateReverbPan[3]; + float flEchoTime; + float flEchoDepth; + float flModulationTime; + float flModulationDepth; + float flAirAbsorptionGainHF; + float flHFReference; + float flLFReference; + float flRoomRolloffFactor; + int iDecayHFLimit; + + ///set our defaults to be the same as no reverb otherwise our reverb + ///effects menu sounds + SFXReverbProperties() + { + flDensity = 0.0f; + flDiffusion = 0.0f; + flGain = 0.0f; + flGainHF = 0.0f; + flGainLF = 0.0000f; + flDecayTime = 0.0f; + flDecayHFRatio = 0.0f; + flDecayLFRatio = 0.0f; + flReflectionsGain = 0.0f; + flReflectionsDelay = 0.0f; + flReflectionsPan[3] = 0.0f; + flLateReverbGain = 0.0f; + flLateReverbDelay = 0.0f; + flLateReverbPan[3] = 0.0f; + flEchoTime = 0.0f; + flEchoDepth = 0.0f; + flModulationTime = 0.0f; + flModulationDepth = 0.0f; + flAirAbsorptionGainHF = 0.0f; + flHFReference = 0.0f; + flLFReference = 0.0f; + flRoomRolloffFactor = 0.0f; + iDecayHFLimit = 0; + } + + void validate() + { + flDensity = mClampF(flDensity, 0.0f, 1.0f); + flDiffusion = mClampF(flDiffusion, 0.0f, 1.0f); + flGain = mClampF(flGain, 0.0f, 1.0f); + flGainHF = mClampF(flGainHF, 0.0f, 1.0f); + flGainLF = mClampF(flGainLF, 0.0f, 1.0f); + flDecayTime = mClampF(flDecayTime, 0.1f, 20.0f); + flDecayHFRatio = mClampF(flDecayHFRatio, 0.1f, 2.0f); + flDecayLFRatio = mClampF(flDecayLFRatio, 0.1f, 2.0f); + flReflectionsGain = mClampF(flReflectionsGain, 0.0f, 3.16f); + flReflectionsDelay = mClampF(flReflectionsDelay, 0.0f, 0.3f); + flReflectionsPan[0] = mClampF(flReflectionsPan[0], -1.0f, 1.0f); + flReflectionsPan[1] = mClampF(flReflectionsPan[1], -1.0f, 1.0f); + flReflectionsPan[2] = mClampF(flReflectionsPan[2], -1.0f, 1.0f); + flLateReverbGain = mClampF(flLateReverbGain, 0.0f, 10.0f); + flLateReverbDelay = mClampF(flLateReverbDelay, 0.0f, 0.1f); + flLateReverbPan[0] = mClampF(flLateReverbPan[0], -1.0f, 1.0f); + flLateReverbPan[1] = mClampF(flLateReverbPan[1], -1.0f, 1.0f); + flLateReverbPan[2] = mClampF(flLateReverbPan[2], -1.0f, 1.0f); + flEchoTime = mClampF(flEchoTime, 0.075f, 0.25f); + flEchoDepth = mClampF(flEchoDepth, 0.0f, 1.0f); + flModulationTime = mClampF(flModulationTime, 0.04f, 4.0f); + flModulationDepth = mClampF(flModulationDepth, 0.0f, 1.0f); + flAirAbsorptionGainHF = mClampF(flAirAbsorptionGainHF, 0.892f, 1.0f); + flHFReference = mClampF(flHFReference, 1000.0f, 20000.0f); + flLFReference = mClampF(flLFReference, 20.0f, 1000.0f); + flRoomRolloffFactor = mClampF(flRoomRolloffFactor, 0.0f, 10.0f); + iDecayHFLimit = mClampF(iDecayHFLimit, 0, 1); + } }; @@ -415,73 +424,99 @@ class SFXReverbProperties /// Sound reverb properties. /// /// @note A given SFX device may not implement all properties. +///not in use by openal yet if u are going to use ambient reverb zones its +///probably best to not have reverb on the sound effect itself. class SFXSoundReverbProperties { - public: - - typedef void Parent; - - S32 mDirect; - S32 mDirectHF; - S32 mRoom; - S32 mRoomHF; - S32 mObstruction; - F32 mObstructionLFRatio; - S32 mOcclusion; - F32 mOcclusionLFRatio; - F32 mOcclusionRoomRatio; - F32 mOcclusionDirectRatio; - S32 mExclusion; - F32 mExclusionLFRatio; - S32 mOutsideVolumeHF; - F32 mDopplerFactor; - F32 mRolloffFactor; - F32 mRoomRolloffFactor; - F32 mAirAbsorptionFactor; - S32 mFlags; - - SFXSoundReverbProperties() - : mDirect( 0 ), - mDirectHF( 0 ), - mRoom( 0 ), - mRoomHF( 0 ), - mObstruction( 0 ), - mObstructionLFRatio( 0.0f ), - mOcclusion( 0 ), - mOcclusionLFRatio( 0.25f ), - mOcclusionRoomRatio( 1.5f ), - mOcclusionDirectRatio( 1.0f ), - mExclusion( 0 ), - mExclusionLFRatio( 1.0f ), - mOutsideVolumeHF( 0 ), - mDopplerFactor( 0.0f ), - mRolloffFactor( 0.0f ), - mRoomRolloffFactor( 0.0f ), - mAirAbsorptionFactor( 1.0f ), - mFlags( 0 ) - { - } - - void validate() - { - mDirect = mClamp( mDirect, -10000, 1000 ); - mDirectHF = mClamp( mDirectHF, -10000, 0 ); - mRoom = mClamp( mRoom, -10000, 1000 ); - mRoomHF = mClamp( mRoomHF, -10000, 0 ); - mObstruction = mClamp( mObstruction, -10000, 0 ); - mObstructionLFRatio = mClampF( mObstructionLFRatio, 0.0f, 1.0f ); - mOcclusion = mClamp( mOcclusion, -10000, 0 ); - mOcclusionLFRatio = mClampF( mOcclusionLFRatio, 0.0f, 1.0f ); - mOcclusionRoomRatio = mClampF( mOcclusionRoomRatio, 0.0f, 10.0f ); - mOcclusionDirectRatio= mClampF( mOcclusionDirectRatio, 0.0f, 10.0f ); - mExclusion = mClamp( mExclusion, -10000, 0 ); - mExclusionLFRatio = mClampF( mExclusionLFRatio, 0.0f, 1.0f ); - mOutsideVolumeHF = mClamp( mOutsideVolumeHF, -10000, 0 ); - mDopplerFactor = mClampF( mDopplerFactor, 0.0f, 10.0f ); - mRolloffFactor = mClampF( mRolloffFactor, 0.0f, 10.0f ); - mRoomRolloffFactor = mClampF( mRoomRolloffFactor, 0.0f, 10.0f ); - mAirAbsorptionFactor = mClampF( mAirAbsorptionFactor, 0.0f, 10.0f ); - } +public: + + typedef void Parent; + + float flDensity; + float flDiffusion; + float flGain; + float flGainHF; + float flGainLF; + float flDecayTime; + float flDecayHFRatio; + float flDecayLFRatio; + float flReflectionsGain; + float flReflectionsDelay; + float flReflectionsPan[3]; + float flLateReverbGain; + float flLateReverbDelay; + float flLateReverbPan[3]; + float flEchoTime; + float flEchoDepth; + float flModulationTime; + float flModulationDepth; + float flAirAbsorptionGainHF; + float flHFReference; + float flLFReference; + float flRoomRolloffFactor; + int iDecayHFLimit; + + + ///Set our defaults to have no reverb + ///if you are going to use zone reverbs its + ///probably best not to use per-voice reverb + SFXSoundReverbProperties() + { + flDensity = 0.0f; + flDiffusion = 0.0f; + flGain = 0.0f; + flGainHF = 0.0f; + flGainLF = 0.0000f; + flDecayTime = 0.0f; + flDecayHFRatio = 0.0f; + flDecayLFRatio = 0.0f; + flReflectionsGain = 0.0f; + flReflectionsDelay = 0.0f; + flReflectionsPan[3] = 0.0f; + flLateReverbGain = 0.0f; + flLateReverbDelay = 0.0f; + flLateReverbPan[3] = 0.0f; + flEchoTime = 0.0f; + flEchoDepth = 0.0f; + flModulationTime = 0.0f; + flModulationDepth = 0.0f; + flAirAbsorptionGainHF = 0.0f; + flHFReference = 0.0f; + flLFReference = 0.0f; + flRoomRolloffFactor = 0.0f; + iDecayHFLimit = 0; + } + + void validate() + { + flDensity = mClampF(flDensity, 0.0f, 1.0f); + flDiffusion = mClampF(flDiffusion, 0.0f, 1.0f); + flGain = mClampF(flGain, 0.0f, 1.0f); + flGainHF = mClampF(flGainHF, 0.0f, 1.0f); + flGainLF = mClampF(flGainLF, 0.0f, 1.0f); + flDecayTime = mClampF(flDecayTime, 0.1f, 20.0f); + flDecayHFRatio = mClampF(flDecayHFRatio, 0.1f, 2.0f); + flDecayLFRatio = mClampF(flDecayLFRatio, 0.1f, 2.0f); + flReflectionsGain = mClampF(flReflectionsGain, 0.0f, 3.16f); + flReflectionsDelay = mClampF(flReflectionsDelay, 0.0f, 0.3f); + flReflectionsPan[0] = mClampF(flReflectionsPan[0], -1.0f, 1.0f); + flReflectionsPan[1] = mClampF(flReflectionsPan[1], -1.0f, 1.0f); + flReflectionsPan[2] = mClampF(flReflectionsPan[2], -1.0f, 1.0f); + flLateReverbGain = mClampF(flLateReverbGain, 0.0f, 10.0f); + flLateReverbDelay = mClampF(flLateReverbDelay, 0.0f, 0.1f); + flLateReverbPan[0] = mClampF(flLateReverbPan[0], -1.0f, 1.0f); + flLateReverbPan[1] = mClampF(flLateReverbPan[1], -1.0f, 1.0f); + flLateReverbPan[2] = mClampF(flLateReverbPan[2], -1.0f, 1.0f); + flEchoTime = mClampF(flEchoTime, 0.075f, 0.25f); + flEchoDepth = mClampF(flEchoDepth, 0.0f, 1.0f); + flModulationTime = mClampF(flModulationTime, 0.04f, 4.0f); + flModulationDepth = mClampF(flModulationDepth, 0.0f, 1.0f); + flAirAbsorptionGainHF = mClampF(flAirAbsorptionGainHF, 0.892f, 1.0f); + flHFReference = mClampF(flHFReference, 1000.0f, 20000.0f); + flLFReference = mClampF(flLFReference, 20.0f, 1000.0f); + flRoomRolloffFactor = mClampF(flRoomRolloffFactor, 0.0f, 10.0f); + iDecayHFLimit = mClampF(iDecayHFLimit, 0, 1); + } }; diff --git a/Engine/source/sfx/sfxDescription.cpp b/Engine/source/sfx/sfxDescription.cpp index 1c82ba6a5..3b41b9b80 100644 --- a/Engine/source/sfx/sfxDescription.cpp +++ b/Engine/source/sfx/sfxDescription.cpp @@ -389,91 +389,55 @@ void SFXDescription::initPersistFields() addGroup( "Reverb" ); - addField( "useCustomReverb", TypeBool, Offset( mUseReverb, SFXDescription ), - "If true, use the reverb properties defined here on sounds.\n" - "By default, sounds will be assigned a generic reverb profile. By setting this flag to true, " - "a custom reverb setup can be defined using the \"Reverb\" properties that will then be assigned " - "to sounds playing with the description.\n\n" - "@ref SFX_reverb" ); - addField( "reverbDirect", TypeS32, Offset( mReverb.mDirect, SFXDescription ), - "Direct path level (at low and mid frequencies).\n" - "@note SUPPORTED: EAX/I3DL2/FMODSFX\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbDirectHF", TypeS32, Offset( mReverb.mDirectHF, SFXDescription ), - "Relative direct path level at high frequencies.\n" - "@note SUPPORTED: EAX/I3DL2\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbRoom", TypeS32, Offset( mReverb.mRoom, SFXDescription ), - "Room effect level (at low and mid frequencies).\n" - "@note SUPPORTED: EAX/I3DL2/FMODSFX\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbRoomHF", TypeS32, Offset( mReverb.mRoomHF, SFXDescription ), - "Relative room effect level at high frequencies.\n" - "@note SUPPORTED: EAX/I3DL2\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbObstruction", TypeS32, Offset( mReverb.mObstruction, SFXDescription ), - "Main obstruction control (attenuation at high frequencies).\n" - "@note SUPPORTED: EAX/I3DL2\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbObstructionLFRatio", TypeF32, Offset( mReverb.mObstructionLFRatio, SFXDescription ), - "Obstruction low-frequency level re. main control.\n" - "@note SUPPORTED: EAX/I3DL2\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbOcclusion", TypeS32, Offset( mReverb.mOcclusion, SFXDescription ), - "Main occlusion control (attenuation at high frequencies)." - "@note SUPPORTED: EAX/I3DL2\n\n" - "\n@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbOcclusionLFRatio", TypeF32, Offset( mReverb.mOcclusionLFRatio, SFXDescription ), - "Occlusion low-frequency level re. main control.\n" - "@note SUPPORTED: EAX/I3DL2\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbOcclusionRoomRatio", TypeF32, Offset( mReverb.mOcclusionRoomRatio, SFXDescription ), - "Relative occlusion control for room effect.\n" - "@note SUPPORTED: EAX Only\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbOcclusionDirectRatio",TypeF32, Offset( mReverb.mOcclusionDirectRatio, SFXDescription ), - "Relative occlusion control for direct path.\n" - "@note SUPPORTED: EAX Only\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbExclusion", TypeS32, Offset( mReverb.mExclusion, SFXDescription ), - "Main exclusion control (attenuation at high frequencies).\n" - "@note SUPPORTED: EAX Only\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbExclusionLFRatio", TypeF32, Offset( mReverb.mExclusionLFRatio, SFXDescription ), - "Exclusion low-frequency level re. main control.\n" - "@note SUPPORTED: EAX Only\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbOutsideVolumeHF", TypeS32, Offset( mReverb.mOutsideVolumeHF, SFXDescription ), - "Outside sound cone level at high frequencies.\n" - "@note SUPPORTED: EAX Only\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbDopplerFactor", TypeF32, Offset( mReverb.mDopplerFactor, SFXDescription ), - "Per-source doppler factor.\n" - "@note SUPPORTED: EAX Only\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbReverbRolloffFactor", TypeF32, Offset( mReverb.mRolloffFactor, SFXDescription ), - "Per-source logarithmic falloff factor.\n" - "@note SUPPORTED: EAX Only\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbRoomRolloffFactor", TypeF32, Offset( mReverb.mRoomRolloffFactor, SFXDescription ), - "Room effect falloff factor.\n" - "@note SUPPORTED: EAX/I3DL2\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbAirAbsorptionFactor", TypeF32, Offset( mReverb.mAirAbsorptionFactor, SFXDescription ), - "Multiplies SFXEnvironment::airAbsorptionHR.\n" - "@note SUPPORTED: EAX Only\n\n" - "@see http://www.atc.creative.com/algorithms/eax20.pdf" ); - addField( "reverbFlags", TypeS32, Offset( mReverb.mFlags, SFXDescription ), - "Bitfield combination of per-sound reverb flags.\n" - "@see REVERB_DIRECTHFAUTO\n" - "@see REVERB_ROOMAUTO\n" - "@see REVERB_ROOMHFAUTO\n" - "@see REVERB_INSTANCE0\n" - "@see REVERB_INSTANCE1\n" - "@see REVERB_INSTANCE2\n" - "@see REVERB_INSTANCE3\n" ); - - endGroup( "Reverb" ); + addField("useCustomReverb", TypeBool, Offset(mUseReverb, SFXDescription), + "If true, use the reverb properties defined here on sounds.\n" + "By default, sounds will be assigned a generic reverb profile. By setting this flag to true, " + "a custom reverb setup can be defined using the \"Reverb\" properties that will then be assigned " + "to sounds playing with the description.\n\n" + "@ref SFX_reverb"); + addField("reverbDensity", TypeF32, Offset(mReverb.flDensity, SFXDescription), + "Density of reverb environment."); + addField("reverbDiffusion", TypeF32, Offset(mReverb.flDiffusion, SFXDescription), + "Environment diffusion."); + addField("reverbGain", TypeF32, Offset(mReverb.flGain, SFXDescription), + "Reverb Gain Level."); + addField("reverbGainHF", TypeF32, Offset(mReverb.flGainHF, SFXDescription), + "Reverb Gain to high frequencies"); + addField("reverbGainLF", TypeF32, Offset(mReverb.flGainLF, SFXDescription), + "Reverb Gain to high frequencies"); + addField("reverbDecayTime", TypeF32, Offset(mReverb.flDecayTime, SFXDescription), + "Decay time for the reverb."); + addField("reverbDecayHFRatio", TypeF32, Offset(mReverb.flDecayHFRatio, SFXDescription), + "High frequency decay time ratio."); + addField("reverbDecayLFRatio", TypeF32, Offset(mReverb.flDecayLFRatio, SFXDescription), + "High frequency decay time ratio."); + addField("reflectionsGain", TypeF32, Offset(mReverb.flReflectionsGain, SFXDescription), + "Reflection Gain."); + addField("reflectionDelay", TypeF32, Offset(mReverb.flReflectionsDelay, SFXDescription), + "How long to delay reflections."); + addField("lateReverbGain", TypeF32, Offset(mReverb.flLateReverbGain, SFXDescription), + "Late reverb gain amount."); + addField("lateReverbDelay", TypeF32, Offset(mReverb.flLateReverbDelay, SFXDescription), + "Late reverb delay time."); + addField("reverbEchoTime", TypeF32, Offset(mReverb.flEchoTime, SFXDescription), + "Reverb echo time."); + addField("reverbEchoDepth", TypeF32, Offset(mReverb.flEchoDepth, SFXDescription), + "Reverb echo depth."); + addField("reverbModTime", TypeF32, Offset(mReverb.flModulationTime, SFXDescription), + "Reverb Modulation time."); + addField("reverbModTime", TypeF32, Offset(mReverb.flModulationDepth, SFXDescription), + "Reverb Modulation time."); + addField("airAbsorbtionGainHF", TypeF32, Offset(mReverb.flAirAbsorptionGainHF, SFXDescription), + "High Frequency air absorbtion"); + addField("reverbHFRef", TypeF32, Offset(mReverb.flHFReference, SFXDescription), + "Reverb High Frequency Reference."); + addField("reverbLFRef", TypeF32, Offset(mReverb.flLFReference, SFXDescription), + "Reverb Low Frequency Reference."); + addField("roomRolloffFactor", TypeF32, Offset(mReverb.flRoomRolloffFactor, SFXDescription), + "Rolloff factor for reverb."); + addField("decayHFLimit", TypeS32, Offset(mReverb.iDecayHFLimit, SFXDescription), + "High Frequency decay limit."); + endGroup("Reverb"); Parent::initPersistFields(); } @@ -570,24 +534,27 @@ void SFXDescription::packData( BitStream *stream ) if( mUseReverb ) { - stream->writeRangedS32( mReverb.mDirect, -10000, 1000 ); - stream->writeRangedS32( mReverb.mDirectHF, -10000, 0 ); - stream->writeRangedS32( mReverb.mRoom, -10000, 1000 ); - stream->writeRangedS32( mReverb.mRoomHF, -10000, 0 ); - stream->writeRangedS32( mReverb.mObstruction, -10000, 0 ); - stream->writeRangedF32( mReverb.mObstructionLFRatio, 0.0, 1.0, 7 ); - stream->writeRangedS32( mReverb.mOcclusion, -10000, 0 ); - stream->writeRangedF32( mReverb.mOcclusionLFRatio, 0.0, 1.0, 7 ); - stream->writeRangedF32( mReverb.mOcclusionRoomRatio, 0.0, 10.0, 7 ); - stream->writeRangedF32( mReverb.mOcclusionDirectRatio, 0.0, 10.0, 7 ); - stream->writeRangedS32( mReverb.mExclusion, -10000, 0 ); - stream->writeRangedF32( mReverb.mExclusionLFRatio, 0.0, 1.0, 7 ); - stream->writeRangedS32( mReverb.mOutsideVolumeHF, -10000, 0 ); - stream->writeRangedF32( mReverb.mDopplerFactor, 0.0, 10.0, 7 ); - stream->writeRangedF32( mReverb.mRolloffFactor, 0.0, 10.0, 7 ); - stream->writeRangedF32( mReverb.mRoomRolloffFactor, 0.0, 10.0, 7 ); - stream->writeRangedF32( mReverb.mAirAbsorptionFactor, 0.0, 10.0, 7 ); - stream->writeInt( mReverb.mFlags, 6 ); + stream->write(mReverb.flDensity); + stream->write(mReverb.flDiffusion); + stream->write(mReverb.flGain); + stream->write(mReverb.flGainHF); + stream->write(mReverb.flGainLF); + stream->write(mReverb.flDecayTime); + stream->write(mReverb.flDecayHFRatio); + stream->write(mReverb.flDecayLFRatio); + stream->write(mReverb.flReflectionsGain); + stream->write(mReverb.flReflectionsDelay); + stream->write(mReverb.flLateReverbGain); + stream->write(mReverb.flLateReverbDelay); + stream->write(mReverb.flEchoTime); + stream->write(mReverb.flEchoDepth); + stream->write(mReverb.flModulationTime); + stream->write(mReverb.flModulationDepth); + stream->write(mReverb.flAirAbsorptionGainHF); + stream->write(mReverb.flHFReference); + stream->write(mReverb.flLFReference); + stream->write(mReverb.flRoomRolloffFactor); + stream->write(mReverb.iDecayHFLimit); } } @@ -640,24 +607,27 @@ void SFXDescription::unpackData( BitStream *stream ) if( mUseReverb ) { - mReverb.mDirect = stream->readRangedS32( -10000, 1000 ); - mReverb.mDirectHF = stream->readRangedS32( -10000, 0 ); - mReverb.mRoom = stream->readRangedS32( -10000, 1000 ); - mReverb.mRoomHF = stream->readRangedS32( -10000, 0 ); - mReverb.mObstruction = stream->readRangedS32( -10000, 0 ); - mReverb.mObstructionLFRatio = stream->readRangedF32( 0.0, 1.0, 7 ); - mReverb.mOcclusion = stream->readRangedS32( -10000, 0 ); - mReverb.mOcclusionLFRatio = stream->readRangedF32( 0.0, 1.0, 7 ); - mReverb.mOcclusionRoomRatio = stream->readRangedF32( 0.0, 10.0, 7 ); - mReverb.mOcclusionDirectRatio = stream->readRangedF32( 0.0, 10.0, 7 ); - mReverb.mExclusion = stream->readRangedS32( -10000, 0 ); - mReverb.mExclusionLFRatio = stream->readRangedF32( 0.0, 1.0, 7 ); - mReverb.mOutsideVolumeHF = stream->readRangedS32( -10000, 0 ); - mReverb.mDopplerFactor = stream->readRangedF32( 0.0, 10.0, 7 ); - mReverb.mRolloffFactor = stream->readRangedF32( 0.0, 10.0, 7 ); - mReverb.mRoomRolloffFactor = stream->readRangedF32( 0.0, 10.0, 7 ); - mReverb.mAirAbsorptionFactor = stream->readRangedF32( 0.0, 10.0, 7 ); - mReverb.mFlags = stream->readInt( 6 ); + stream->read(&mReverb.flDensity); + stream->read(&mReverb.flDiffusion); + stream->read(&mReverb.flGain); + stream->read(&mReverb.flGainHF); + stream->read(&mReverb.flGainLF); + stream->read(&mReverb.flDecayTime); + stream->read(&mReverb.flDecayHFRatio); + stream->read(&mReverb.flDecayLFRatio); + stream->read(&mReverb.flReflectionsGain); + stream->read(&mReverb.flReflectionsDelay); + stream->read(&mReverb.flLateReverbGain); + stream->read(&mReverb.flLateReverbDelay); + stream->read(&mReverb.flEchoTime); + stream->read(&mReverb.flEchoDepth); + stream->read(&mReverb.flModulationTime); + stream->read(&mReverb.flModulationDepth); + stream->read(&mReverb.flAirAbsorptionGainHF); + stream->read(&mReverb.flHFReference); + stream->read(&mReverb.flLFReference); + stream->read(&mReverb.flRoomRolloffFactor); + stream->read(&mReverb.iDecayHFLimit); } } diff --git a/Engine/source/sfx/sfxDevice.h b/Engine/source/sfx/sfxDevice.h index b4d6485e3..f7dc66b77 100644 --- a/Engine/source/sfx/sfxDevice.h +++ b/Engine/source/sfx/sfxDevice.h @@ -178,6 +178,9 @@ public: /// Set the rolloff scale factor for distance attenuation of 3D sounds. virtual void setRolloffFactor( F32 factor ) {} + + /// send empty function to all sfxdevices + virtual void openSlots() {} /// Set the global reverb environment. virtual void setReverb( const SFXReverbProperties& reverb ) {} diff --git a/Engine/source/sfx/sfxEnvironment.cpp b/Engine/source/sfx/sfxEnvironment.cpp index 54bfc7d7d..780821719 100644 --- a/Engine/source/sfx/sfxEnvironment.cpp +++ b/Engine/source/sfx/sfxEnvironment.cpp @@ -144,70 +144,53 @@ void SFXEnvironment::initPersistFields() { addGroup( "Reverb" ); - addField( "envSize", TypeF32, Offset( mReverb.mEnvSize, SFXEnvironment ), - "Environment size in meters." ); - addField( "envDiffusion", TypeF32, Offset( mReverb.mEnvDiffusion, SFXEnvironment ), - "Environment diffusion." ); - addField( "room", TypeS32, Offset( mReverb.mRoom, SFXEnvironment ), - "Room effect level at mid-frequencies." ); - addField( "roomHF", TypeS32, Offset( mReverb.mRoomHF, SFXEnvironment ), - "Relative room effect level at high frequencies." ); - addField( "roomLF", TypeS32, Offset( mReverb.mRoomLF, SFXEnvironment ), - "Relative room effect level at low frequencies." ); - addField( "decayTime", TypeF32, Offset( mReverb.mDecayTime, SFXEnvironment ), - "Reverberation decay time at mid frequencies." ); - addField( "decayHFRatio", TypeF32, Offset( mReverb.mDecayHFRatio, SFXEnvironment ), - "High-frequency to mid-frequency decay time ratio." ); - addField( "decayLFRatio", TypeF32, Offset( mReverb.mDecayLFRatio, SFXEnvironment ), - "Low-frequency to mid-frequency decay time ratio." ); - addField( "reflections", TypeS32, Offset( mReverb.mReflections, SFXEnvironment ), - "Early reflections level relative to room effect." ); - addField( "reflectionsDelay", TypeF32, Offset( mReverb.mReflectionsDelay, SFXEnvironment ), - "Initial reflection delay time." ); - addField( "reflectionsPan", TypeF32, Offset( mReverb.mReflectionsPan, SFXEnvironment ), 3, - "Early reflections panning vector." ); - addField( "reverb", TypeS32, Offset( mReverb.mReverb, SFXEnvironment ), - "Late reverberation level relative to room effect." ); - addField( "reverbDelay", TypeF32, Offset( mReverb.mReverbDelay, SFXEnvironment ), - "Late reverberation delay time relative to initial reflection." ); - addField( "reverbPan", TypeF32, Offset( mReverb.mReverbPan, SFXEnvironment ), 3, - "Late reverberation panning vector." ); - addField( "echoTime", TypeF32, Offset( mReverb.mEchoTime, SFXEnvironment ), - "Echo time." ); - addField( "echoDepth", TypeF32, Offset( mReverb.mEchoDepth, SFXEnvironment ), - "Echo depth." ); - addField( "modulationTime", TypeF32, Offset( mReverb.mModulationTime, SFXEnvironment ), - "Modulation time." ); - addField( "modulationDepth", TypeF32, Offset( mReverb.mModulationDepth, SFXEnvironment ), - "Modulation depth." ); - addField( "airAbsorptionHF", TypeF32, Offset( mReverb.mAirAbsorptionHF, SFXEnvironment ), - "Change in level per meter at high frequencies." ); - addField( "HFReference", TypeF32, Offset( mReverb.mHFReference, SFXEnvironment ), - "Reference high frequency in Hertz." ); - addField( "LFReference", TypeF32, Offset( mReverb.mLFReference, SFXEnvironment ), - "Reference low frequency in Hertz." ); - addField( "roomRolloffFactor", TypeF32, Offset( mReverb.mRoomRolloffFactor, SFXEnvironment ), - "Logarithmic distance attenuation rolloff scale factor for reverb room size effect." ); - addField( "diffusion", TypeF32, Offset( mReverb.mDiffusion, SFXEnvironment ), - "Value that controls the echo density in the late reverberation decay." ); - addField( "density", TypeF32, Offset( mReverb.mDensity, SFXEnvironment ), - "Value that controls the modal density in the late reverberation decay." ); - addField( "flags", TypeS32, Offset( mReverb.mFlags, SFXEnvironment ), - "A bitfield of reverb flags.\n" - "@see REVERB_DECAYTIMESCALE\n" - "@see REVERB_REFLECTIONSSCALE\n" - "@see REVERB_REFLECTIONSDELAYSCALE\n" - "@see REVERB_REVERBSCALE\n" - "@see REVERB_REVERBDELAYSCALE\n" - "@see REVERB_DECAYHFLIMIT\n" - "@see REVERB_ECHOTIMESCALE\n" - "@see REVERB_MODULATIONTIMESCALE\n" - "@see REVERB_CORE0\n" - "@see REVERB_CORE1\n" - "@see REVERB_HIGHQUALITYREVERB\n" - "@see REVERB_HIGHQUALITYDPL2REVERB\n" ); - - endGroup( "Reverb" ); + addField("reverbDensity", TypeF32, Offset(mReverb.flDensity, SFXEnvironment), + "Density of reverb environment."); + addField("reverbDiffusion", TypeF32, Offset(mReverb.flDiffusion, SFXEnvironment), + "Environment diffusion."); + addField("reverbGain", TypeF32, Offset(mReverb.flGain, SFXEnvironment), + "Reverb Gain Level."); + addField("reverbGainHF", TypeF32, Offset(mReverb.flGainHF, SFXEnvironment), + "Reverb Gain to high frequencies"); + addField("reverbGainLF", TypeF32, Offset(mReverb.flGainLF, SFXEnvironment), + "Reverb Gain to high frequencies"); + addField("reverbDecayTime", TypeF32, Offset(mReverb.flDecayTime, SFXEnvironment), + "Decay time for the reverb."); + addField("reverbDecayHFRatio", TypeF32, Offset(mReverb.flDecayHFRatio, SFXEnvironment), + "High frequency decay time ratio."); + addField("reverbDecayLFRatio", TypeF32, Offset(mReverb.flDecayLFRatio, SFXEnvironment), + "High frequency decay time ratio."); + addField("reflectionsGain", TypeF32, Offset(mReverb.flReflectionsGain, SFXEnvironment), + "Reflection Gain."); + addField("reflectionDelay", TypeF32, Offset(mReverb.flReflectionsDelay, SFXEnvironment), + "How long to delay reflections."); + addField("reflectionsPan", TypeF32, Offset(mReverb.flReflectionsPan, SFXEnvironment), 3, + "Reflection reverberation panning vector."); + addField("lateReverbGain", TypeF32, Offset(mReverb.flLateReverbGain, SFXEnvironment), + "Late reverb gain amount."); + addField("lateReverbDelay", TypeF32, Offset(mReverb.flLateReverbDelay, SFXEnvironment), + "Late reverb delay time."); + addField("lateReverbPan", TypeF32, Offset(mReverb.flLateReverbPan, SFXEnvironment), 3, + "Late reverberation panning vector."); + addField("reverbEchoTime", TypeF32, Offset(mReverb.flEchoTime, SFXEnvironment), + "Reverb echo time."); + addField("reverbEchoDepth", TypeF32, Offset(mReverb.flEchoDepth, SFXEnvironment), + "Reverb echo depth."); + addField("reverbModTime", TypeF32, Offset(mReverb.flModulationTime, SFXEnvironment), + "Reverb Modulation time."); + addField("reverbModDepth", TypeF32, Offset(mReverb.flModulationDepth, SFXEnvironment), + "Reverb Modulation time."); + addField("airAbsorbtionGainHF", TypeF32, Offset(mReverb.flAirAbsorptionGainHF, SFXEnvironment), + "High Frequency air absorbtion"); + addField("reverbHFRef", TypeF32, Offset(mReverb.flHFReference, SFXEnvironment), + "Reverb High Frequency Reference."); + addField("reverbLFRef", TypeF32, Offset(mReverb.flLFReference, SFXEnvironment), + "Reverb Low Frequency Reference."); + addField("roomRolloffFactor", TypeF32, Offset(mReverb.flRoomRolloffFactor, SFXEnvironment), + "Rolloff factor for reverb."); + addField("decayHFLimit", TypeS32, Offset(mReverb.iDecayHFLimit, SFXEnvironment), + "High Frequency decay limit."); + endGroup("Reverb"); Parent::initPersistFields(); } @@ -257,35 +240,27 @@ void SFXEnvironment::packData( BitStream* stream ) { Parent::packData( stream ); - stream->write( mReverb.mEnvSize ); - stream->write( mReverb.mEnvDiffusion ); - stream->write( mReverb.mRoom ); - stream->write( mReverb.mRoomHF ); - stream->write( mReverb.mRoomLF ); - stream->write( mReverb.mDecayTime ); - stream->write( mReverb.mDecayHFRatio ); - stream->write( mReverb.mDecayLFRatio ); - stream->write( mReverb.mReflections ); - stream->write( mReverb.mReflectionsDelay ); - stream->write( mReverb.mReflectionsPan[ 0 ] ); - stream->write( mReverb.mReflectionsPan[ 1 ] ); - stream->write( mReverb.mReflectionsPan[ 2 ] ); - stream->write( mReverb.mReverb ); - stream->write( mReverb.mReverbDelay ); - stream->write( mReverb.mReverbPan[ 0 ] ); - stream->write( mReverb.mReverbPan[ 1 ] ); - stream->write( mReverb.mReverbPan[ 2 ] ); - stream->write( mReverb.mEchoTime ); - stream->write( mReverb.mEchoDepth ); - stream->write( mReverb.mModulationTime ); - stream->write( mReverb.mModulationDepth ); - stream->write( mReverb.mAirAbsorptionHF ); - stream->write( mReverb.mHFReference ); - stream->write( mReverb.mLFReference ); - stream->write( mReverb.mRoomRolloffFactor ); - stream->write( mReverb.mDiffusion ); - stream->write( mReverb.mDensity ); - stream->write( mReverb.mFlags ); + stream->write(mReverb.flDensity); + stream->write(mReverb.flDiffusion); + stream->write(mReverb.flGain); + stream->write(mReverb.flGainHF); + stream->write(mReverb.flGainLF); + stream->write(mReverb.flDecayTime); + stream->write(mReverb.flDecayHFRatio); + stream->write(mReverb.flDecayLFRatio); + stream->write(mReverb.flReflectionsGain); + stream->write(mReverb.flReflectionsDelay); + stream->write(mReverb.flLateReverbGain); + stream->write(mReverb.flLateReverbDelay); + stream->write(mReverb.flEchoTime); + stream->write(mReverb.flEchoDepth); + stream->write(mReverb.flModulationTime); + stream->write(mReverb.flModulationDepth); + stream->write(mReverb.flAirAbsorptionGainHF); + stream->write(mReverb.flHFReference); + stream->write(mReverb.flLFReference); + stream->write(mReverb.flRoomRolloffFactor); + stream->write(mReverb.iDecayHFLimit); } //----------------------------------------------------------------------------- @@ -294,33 +269,25 @@ void SFXEnvironment::unpackData( BitStream* stream ) { Parent::unpackData( stream ); - stream->read( &mReverb.mEnvSize ); - stream->read( &mReverb.mEnvDiffusion ); - stream->read( &mReverb.mRoom ); - stream->read( &mReverb.mRoomHF ); - stream->read( &mReverb.mRoomLF ); - stream->read( &mReverb.mDecayTime ); - stream->read( &mReverb.mDecayHFRatio ); - stream->read( &mReverb.mDecayLFRatio ); - stream->read( &mReverb.mReflections ); - stream->read( &mReverb.mReflectionsDelay ); - stream->read( &mReverb.mReflectionsPan[ 0 ] ); - stream->read( &mReverb.mReflectionsPan[ 1 ] ); - stream->read( &mReverb.mReflectionsPan[ 2 ] ); - stream->read( &mReverb.mReverb ); - stream->read( &mReverb.mReverbDelay ); - stream->read( &mReverb.mReverbPan[ 0 ] ); - stream->read( &mReverb.mReverbPan[ 1 ] ); - stream->read( &mReverb.mReverbPan[ 2 ] ); - stream->read( &mReverb.mEchoTime ); - stream->read( &mReverb.mEchoDepth ); - stream->read( &mReverb.mModulationTime ); - stream->read( &mReverb.mModulationDepth ); - stream->read( &mReverb.mAirAbsorptionHF ); - stream->read( &mReverb.mHFReference ); - stream->read( &mReverb.mLFReference ); - stream->read( &mReverb.mRoomRolloffFactor ); - stream->read( &mReverb.mDiffusion ); - stream->read( &mReverb.mDensity ); - stream->read( &mReverb.mFlags ); + stream->read(&mReverb.flDensity); + stream->read(&mReverb.flDiffusion); + stream->read(&mReverb.flGain); + stream->read(&mReverb.flGainHF); + stream->read(&mReverb.flGainLF); + stream->read(&mReverb.flDecayTime); + stream->read(&mReverb.flDecayHFRatio); + stream->read(&mReverb.flDecayLFRatio); + stream->read(&mReverb.flReflectionsGain); + stream->read(&mReverb.flReflectionsDelay); + stream->read(&mReverb.flLateReverbGain); + stream->read(&mReverb.flLateReverbDelay); + stream->read(&mReverb.flEchoTime); + stream->read(&mReverb.flEchoDepth); + stream->read(&mReverb.flModulationTime); + stream->read(&mReverb.flModulationDepth); + stream->read(&mReverb.flAirAbsorptionGainHF); + stream->read(&mReverb.flHFReference); + stream->read(&mReverb.flLFReference); + stream->read(&mReverb.flRoomRolloffFactor); + stream->read(&mReverb.iDecayHFLimit); } diff --git a/Engine/source/sfx/sfxSystem.cpp b/Engine/source/sfx/sfxSystem.cpp index 5cf340cf2..d586e921c 100644 --- a/Engine/source/sfx/sfxSystem.cpp +++ b/Engine/source/sfx/sfxSystem.cpp @@ -94,6 +94,9 @@ ImplementEnumType( SFXDistanceModel, { SFXDistanceModelLogarithmic, "Logarithmic", "Volume attenuates logarithmically starting from the reference distance and halving every reference distance step from there on. " "Attenuation stops at max distance but volume won't reach zero." }, + { SFXDistanceModelExponent, "Exponential", + "Volume attenuates exponentially starting from the reference distance and attenuating every reference distance step by the rolloff factor. " + "Attenuation stops at max distance but volume won't reach zero." }, EndImplementEnumType; ImplementEnumType( SFXChannel, @@ -473,6 +476,9 @@ bool SFXSystem::createDevice( const String& providerName, const String& deviceNa mDevice->setDistanceModel( mDistanceModel ); mDevice->setDopplerFactor( mDopplerFactor ); mDevice->setRolloffFactor( mRolloffFactor ); + //OpenAL requires slots for effects, this creates an empty function + //that will run when a sfxdevice is created. + mDevice->openSlots(); mDevice->setReverb( mReverb ); // Signal system. diff --git a/Templates/Full/game/core/scripts/client/audioEnvironments.cs b/Templates/Full/game/core/scripts/client/audioEnvironments.cs index 09fc4de1a..71050d8c4 100644 --- a/Templates/Full/game/core/scripts/client/audioEnvironments.cs +++ b/Templates/Full/game/core/scripts/client/audioEnvironments.cs @@ -24,893 +24,1366 @@ // // For customized presets, best derive from one of these presets. -singleton SFXEnvironment( AudioEnvOff ) +singleton SFXEnvironment(Generic) { - envSize = "7.5"; - envDiffusion = "1.0"; - room = "-10000"; - roomHF = "-10000"; - roomLF = "0"; - decayTime = "1.0"; - decayHFRatio = "1.0"; - decayLFRatio = "1.0"; - reflections = "-2602"; - reflectionsDelay = "0.007"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "200"; - reverbDelay = "0.011"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "0.0"; - density = "0.0"; - flags = 0x33; +reverbDensity = "1.000"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.8913"; +reverbGainLF = "1.000"; +reverbDecayTime = "1.4900"; +reverbDecayHFRatio = "0.8300"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.0500"; +reflectionDelay = "0.0070"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.2589"; +lateReverbDelay = "0.0110"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvGeneric ) +singleton SFXEnvironment(PaddedCell) { - envSize = "7.5"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-100"; - roomLF = "0"; - decayTime = "1.49"; - decayHFRatio = "0.83"; - decayLFRatio = "1.0"; - reflections = "-2602"; - reflectionsDelay = "0.007"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "200"; - reverbDelay = "0.011"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "0.1715"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.0010"; +reverbGainLF = "1.000"; +reverbDecayTime = "0.1700"; +reverbDecayHFRatio = "0.1000"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.2500"; +reflectionDelay = "0.0010"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.2691"; +lateReverbDelay = "0.0020"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvRoom ) +singleton SFXEnvironment(PresetRoom) { - envSize = "1.9"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-454"; - roomLF = "0"; - decayTime = "0.4"; - decayHFRatio = "0.83"; - decayLFRatio = "1.0"; - reflections = "-1646"; - reflectionsDelay = "0.002"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "53"; - reverbDelay = "0.003"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "0.4287"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.5929"; +reverbGainLF = "1.000"; +reverbDecayTime = "0.4000"; +reverbDecayHFRatio = "0.8300"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.1503"; +reflectionDelay = "0.0020"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.0629"; +lateReverbDelay = "0.0030"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvPaddedCell ) +singleton SFXEnvironment(PresetBathroom) { - envSize = "1.4"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-6000"; - roomLF = "0"; - decayTime = "0.17"; - decayHFRatio = "0.1"; - decayLFRatio = "1.0"; - reflections = "-1204"; - reflectionsDelay = "0.001"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "207"; - reverbDelay = "0.002"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "0.1715"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.2512"; +reverbGainLF = "1.000"; +reverbDecayTime = "1.4900"; +reverbDecayHFRatio = "0.5400"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.6531"; +reflectionDelay = "0.0070"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "3.2734"; +lateReverbDelay = "0.0110"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvBathroom ) +singleton SFXEnvironment(PresetLivingroom) { - envSize = "1.4"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-1200"; - roomLF = "0"; - decayTime = "1.49"; - decayHFRatio = "0.54"; - decayLFRatio = "1.0"; - reflections = "-370"; - reflectionsDelay = "0.007"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "1030"; - reverbDelay = "0.011"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "60.0"; - flags = 0x3f; +reverbDensity = "0.9766"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.0010"; +reverbGainLF = "1.0000"; +reverbDecayTime = "0.0900"; +reverbDecayHFRatio = "0.5000"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.2051"; +reflectionDelay = "0.0030"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.2805"; +lateReverbDelay = "0.0040"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvLivingRoom ) +singleton SFXEnvironment(PresetStoneroom) { - envSize = "2.5"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-6000"; - roomLF = "0"; - decayTime = "0.5"; - decayHFRatio = "0.1"; - decayLFRatio = "1.0"; - reflections = "-1376"; - reflectionsDelay = "0.003"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-1104"; - reverbDelay = "0.004"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.7079"; +reverbGainLF = "1.0000"; +reverbDecayTime = "2.3100"; +reverbDecayHFRatio = "0.6400"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.4411"; +reflectionDelay = "0.0120"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.1003"; +lateReverbDelay = "0.0170"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvStoneRoom ) +singleton SFXEnvironment(PresetAuditorium) { - envSize = "11.6"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "300"; - roomLF = "0"; - decayTime = "2.31"; - decayHFRatio = "0.64"; - decayLFRatio = "1.0"; - reflections = "-711"; - reflectionsDelay = "0.012"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "83"; - reverbDelay = "0.017"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "-5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.5781"; +reverbGainLF = "1.0000"; +reverbDecayTime = "4.3200"; +reverbDecayHFRatio = "0.5900"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.4032"; +reflectionDelay = "0.0200"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.7170"; +lateReverbDelay = "0.0300"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvAuditorium ) +singleton SFXEnvironment(PresetConcerthall) { - envSize = "21.6"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-476"; - roomLF = "0"; - decayTime = "4.32"; - decayHFRatio = "0.59"; - decayLFRatio = "1.0"; - reflections = "0.789"; - reflectionsDelay = "0.02"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-289"; - reverbDelay = "0.03"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.5632"; +reverbGainLF = "1.0000"; +reverbDecayTime = "3.9200"; +reverbDecayHFRatio = "0.7000"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.2427"; +reflectionDelay = "0.0200"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.9977"; +lateReverbDelay = "0.0290"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvConcertHall ) +singleton SFXEnvironment(PresetCave) { - envSize = "19.6"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-500"; - roomLF = "0"; - decayTime = "3.92"; - decayHFRatio = "0.7"; - decayLFRatio = "1.0"; - reflections = "-1230"; - reflectionsDelay = "0.02"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-2"; - reverbDelay = "0.029"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "1.000"; +reverbGainLF = "1.0000"; +reverbDecayTime = "2.9100"; +reverbDecayHFRatio = "1.3000"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.5000"; +reflectionDelay = "0.0250"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.7063"; +lateReverbDelay = "0.0220"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "0"; }; -singleton SFXEnvironment( AudioEnvCave ) +singleton SFXEnvironment(PresetArena) { - envSize = "14.6"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "0"; - roomLF = "0"; - decayTime = "2.91"; - decayHFRatio = "1.3"; - decayLFRatio = "1.0"; - reflections = "-602"; - reflectionsDelay = "0.015"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-302"; - reverbDelay = "0.022"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x1f; +reverbDensity = "1.000"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.4477"; +reverbGainLF = "1.0000"; +reverbDecayTime = "7.2400"; +reverbDecayHFRatio = "0.3300"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.2612"; +reflectionDelay = "0.0200"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.0186"; +lateReverbDelay = "0.0300"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvArena ) +singleton SFXEnvironment(PresetHangar) { - envSize = "36.2f"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-698"; - roomLF = "0"; - decayTime = "7.24"; - decayHFRatio = "0.33"; - decayLFRatio = "1.0"; - reflections = "-1166"; - reflectionsDelay = "0.02"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "16"; - reverbDelay = "0.03"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.3162"; +reverbGainLF = "1.0000"; +reverbDecayTime = "10.0500"; +reverbDecayHFRatio = "0.2300"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.5000"; +reflectionDelay = "0.0200"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.2560"; +lateReverbDelay = "0.0300"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvHangar ) +singleton SFXEnvironment(PresetCarpetedHall) { - envSize = "50.3"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-1000"; - roomLF = "0"; - decayTime = "10.05"; - decayHFRatio = "0.23"; - decayLFRatio = "1.0"; - reflections = "-602"; - reflectionsDelay = "0.02"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "198"; - reverbDelay = "0.03"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "0.4287"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.0100"; +reverbGainLF = "1.0000"; +reverbDecayTime = "0.3000"; +reverbDecayHFRatio = "0.1000"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.1215"; +reflectionDelay = "0.0020"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.1531"; +lateReverbDelay = "0.0300"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvCarpettedHallway ) +singleton SFXEnvironment(PresetHallway) { - envSize = "1.9"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-4000"; - roomLF = "0"; - decayTime = "0.3"; - decayHFRatio = "0.1"; - decayLFRatio = "1.0"; - reflections = "-1831"; - reflectionsDelay = "0.002"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-1630"; - reverbDelay = "0.03"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "0.3645"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.7079"; +reverbGainLF = "1.0000"; +reverbDecayTime = "1.4900"; +reverbDecayHFRatio = "0.5900"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.2458"; +reflectionDelay = "0.0070"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.6615"; +lateReverbDelay = "0.0110"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvHallway ) +singleton SFXEnvironment(PresetStoneCorridor) { - envSize = "1.8"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-300"; - roomLF = "0"; - decayTime = "1.49"; - decayHFRatio = "0.59"; - decayLFRatio = "1.0"; - reflections = "-1219"; - reflectionsDelay = "0.007"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "441"; - reverbDelay = "0.011"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "1.000"; +reverbGain = "0.3162"; +reverbGainHF = "0.7612"; +reverbGainLF = "1.0000"; +reverbDecayTime = "2.7000"; +reverbDecayHFRatio = "0.7900"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.2472"; +reflectionDelay = "0.0130"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.5758"; +lateReverbDelay = "0.0200"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvStoneCorridor ) +singleton SFXEnvironment(PresetStoneAlley) { - envSize = "13.5"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-237"; - roomLF = "0"; - decayTime = "2.7"; - decayHFRatio = "0.79"; - decayLFRatio = "1.0"; - reflections = "-1214"; - reflectionsDelay = "0.013"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "395"; - reverbDelay = "0.02"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "0.300"; +reverbGain = "0.3162"; +reverbGainHF = "0.7328"; +reverbGainLF = "1.0000"; +reverbDecayTime = "1.4900"; +reverbDecayHFRatio = "0.8600"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.2500"; +reflectionDelay = "0.0070"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.9954"; +lateReverbDelay = "0.0110"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1250"; +reverbEchoDepth = "0.9500"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvAlley ) +singleton SFXEnvironment(PresetFroest) { - envSize = "7.5"; - envDiffusion = "0.3"; - room = "-1000"; - roomHF = "-270"; - roomLF = "0"; - decayTime = "1.49"; - decayHFRatio = "0.86"; - decayLFRatio = "1.0"; - reflections = "-1204"; - reflectionsDelay = "0.007"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-4"; - reverbDelay = "0.011"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.125"; - echoDepth = "0.95"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "0.300"; +reverbGain = "0.3162"; +reverbGainHF = "0.0224"; +reverbGainLF = "1.0000"; +reverbDecayTime = "1.4900"; +reverbDecayHFRatio = "0.5400"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.0525"; +reflectionDelay = "0.1620"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.7682"; +lateReverbDelay = "0.0880"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1250"; +reverbEchoDepth = "1.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvForest ) +singleton SFXEnvironment(PresetCity) { - envSize = "38.0"; - envDiffusion = "0.3"; - room = "-1000"; - roomHF = "-3300"; - roomLF = "0"; - decayTime = "1.49"; - decayHFRatio = "0.54"; - decayLFRatio = "1.0"; - reflections = "-2560"; - reflectionsDelay = "0.162"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-229"; - reverbDelay = "0.088"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.125"; - echoDepth = "1.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "79.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "0.500"; +reverbGain = "0.3162"; +reverbGainHF = "0.3981"; +reverbGainLF = "1.0000"; +reverbDecayTime = "1.4900"; +reverbDecayHFRatio = "0.6700"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.0730"; +reflectionDelay = "0.0070"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.1427"; +lateReverbDelay = "0.0110"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1250"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvCity ) +singleton SFXEnvironment(PresetMountains) { - envSize = "7.5"; - envDiffusion = "0.5"; - room = "-1000"; - roomHF = "-800"; - roomLF = "0"; - decayTime = "1.49"; - decayHFRatio = "0.67"; - decayLFRatio = "1.0"; - reflections = "-2273"; - reflectionsDelay = "0.007"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-1691"; - reverbDelay = "0.011"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "50.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "0.2700"; +reverbGain = "0.3162"; +reverbGainHF = "0.0562"; +reverbGainLF = "1.0000"; +reverbDecayTime = "1.4900"; +reverbDecayHFRatio = "0.2100"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.0407"; +reflectionDelay = "0.3000"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.1919"; +lateReverbDelay = "0.1000"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1250"; +reverbEchoDepth = "1.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "0"; }; -singleton SFXEnvironment( AudioEnvMountains ) +singleton SFXEnvironment(PresetQuarry) { - envSize = "100.0"; - envDiffusion = "0.27"; - room = "-1000"; - roomHF = "-2500"; - roomLF = "0"; - decayTime = "1.49"; - decayHFRatio = "0.21"; - decayLFRatio = "1.0"; - reflections = "-2780"; - reflectionsDelay = "0.3"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-1434"; - reverbDelay = "0.1"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "1.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "27.0"; - density = "100.0"; - flags = 0x1f; +reverbDensity = "1.000"; +reverbDiffusion = "1.0000"; +reverbGain = "0.3162"; +reverbGainHF = "0.3162"; +reverbGainLF = "1.0000"; +reverbDecayTime = "1.4900"; +reverbDecayHFRatio = "0.8300"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.0000"; +reflectionDelay = "0.0610"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.7783"; +lateReverbDelay = "0.0250"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1250"; +reverbEchoDepth = "0.7000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvQuary ) +singleton SFXEnvironment(PresetPlain) { - envSize = "17.5"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-1000"; - roomLF = "0"; - decayTime = "1.49"; - decayHFRatio = "0.83"; - decayLFRatio = "1.0"; - reflections = "-10000"; - reflectionsDelay = "0.061"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "500"; - reverbDelay = "0.025"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.125"; - echoDepth = "0.7"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "0.2100"; +reverbGain = "0.3162"; +reverbGainHF = "0.1000"; +reverbGainLF = "1.0000"; +reverbDecayTime = "1.4900"; +reverbDecayHFRatio = "0.5000"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.0585"; +reflectionDelay = "0.1790"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.1089"; +lateReverbDelay = "0.1000"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "1.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvPlain ) +singleton SFXEnvironment(PresetParkinglot) { - envSize = "42.5"; - envDiffusion = "0.21"; - room = "-1000"; - roomHF = "-2000"; - roomLF = "0"; - decayTime = "1.49"; - decayHFRatio = "0.5"; - decayLFRatio = "1.0"; - reflections = "-2466"; - reflectionsDelay = "0.179"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-1926"; - reverbDelay = "0.1"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "1.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "21.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "1.000"; +reverbDiffusion = "1.0000"; +reverbGain = "0.3162"; +reverbGainHF = "1.0000"; +reverbGainLF = "1.0000"; +reverbDecayTime = "1.6500"; +reverbDecayHFRatio = "1.5000"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.2082"; +reflectionDelay = "0.0080"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.2652"; +lateReverbDelay = "0.0120"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "0"; }; -singleton SFXEnvironment( AudioEnvParkingLot ) +singleton SFXEnvironment(PresetSewerpipe) { - envSize = "8.3"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "0"; - roomLF = "0"; - decayTime = "1.65"; - decayHFRatio = "1.5"; - decayLFRatio = "1.0"; - reflections = "-1363"; - reflectionsDelay = "0.008"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-1153"; - reverbDelay = "0.012"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x1f; +reverbDensity = "0.3071"; +reverbDiffusion = "0.8000"; +reverbGain = "0.3162"; +reverbGainHF = "0.3162"; +reverbGainLF = "1.0000"; +reverbDecayTime = "2.8100"; +reverbDecayHFRatio = "0.1400"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "1.6387"; +reflectionDelay = "0.0140"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "3.2471"; +lateReverbDelay = "0.0210"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvSewerPipe ) +singleton SFXEnvironment(PresetUnderwater) { - envSize = "1.7"; - envDiffusion = "0.8"; - room = "-1000"; - roomHF = "-1000"; - roomLF = "0"; - decayTime = "2.81"; - decayHFRatio = "0.14"; - decayLFRatio = "1.0"; - reflections = "429"; - reflectionsDelay = "0.014"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "1023"; - reverbDelay = "0.21"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "0.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "80.0"; - density = "60.0"; - flags = 0x3f; +reverbDensity = "0.3645"; +reverbDiffusion = "1.0000"; +reverbGain = "0.3162"; +reverbGainHF = "0.0100"; +reverbGainLF = "1.0000"; +reverbDecayTime = "1.4900"; +reverbDecayHFRatio = "0.1000"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.5963"; +reflectionDelay = "0.0070"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "7.0795"; +lateReverbDelay = "0.0110"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "1.1800"; +reverbModDepth = "0.3480"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; -singleton SFXEnvironment( AudioEnvUnderwater ) +singleton SFXEnvironment(PresetDrugged) { - envSize = "1.8"; - envDiffusion = "1.0"; - room = "-1000"; - roomHF = "-4000"; - roomLF = "0"; - decayTime = "1.49"; - decayHFRatio = "0.1"; - decayLFRatio = "1.0"; - reflections = "-449"; - reflectionsDelay = "0.007"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "1700"; - reverbDelay = "0.011"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "1.18"; - modulationDepth = "0.348"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x3f; +reverbDensity = "0.4287"; +reverbDiffusion = "0.5000"; +reverbGain = "0.3162"; +reverbGainHF = "1.0000"; +reverbGainLF = "1.0000"; +reverbDecayTime = "8.3900"; +reverbDecayHFRatio = "1.3900"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.8760"; +reflectionDelay = "0.0020"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "3.1081"; +lateReverbDelay = "0.0300"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "1.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "0"; }; -singleton SFXEnvironment( AudioEnvDrugged ) +singleton SFXEnvironment(PresetDizzy) { - envSize = "1.9"; - envDiffusion = "0.5"; - room = "-1000"; - roomHF = "0"; - roomLF = "0"; - decayTime = "8.39"; - decayHFRatio = "1.39"; - decayLFRatio = "1.0"; - reflections = "-115"; - reflectionsDelay = "0.002"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "985"; - reverbDelay = "0.03"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "0.25"; - modulationDepth = "1.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x1f; +reverbDensity = "0.3645"; +reverbDiffusion = "0.6000"; +reverbGain = "0.3162"; +reverbGainHF = "0.6310"; +reverbGainLF = "1.0000"; +reverbDecayTime = "17.2300"; +reverbDecayHFRatio = "0.5600"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.1392"; +reflectionDelay = "0.0200"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.4937"; +lateReverbDelay = "0.0300"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "1.0000"; +reverbModTime = "0.8100"; +reverbModDepth = "0.3100"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "0"; }; -singleton SFXEnvironment( AudioEnvDizzy ) +singleton SFXEnvironment(PresetPsychotic) { - envSize = "1.8"; - envDiffusion = "0.6"; - room = "-1000.0"; - roomHF = "-400"; - roomLF = "0"; - decayTime = "17.23"; - decayHFRatio = "0.56"; - decayLFRatio = "1.0"; - reflections = "-1713"; - reflectionsDelay = "0.02"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "-613"; - reverbDelay = "0.03"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "1.0"; - modulationTime = "0.81"; - modulationDepth = "0.31"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x1f; +reverbDensity = "0.0625"; +reverbDiffusion = "0.5000"; +reverbGain = "0.3162"; +reverbGainHF = "0.8404"; +reverbGainLF = "1.0000"; +reverbDecayTime = "7.5600"; +reverbDecayHFRatio = "0.9100"; +reverbDecayLFRatio = "1.0000"; +reflectionsGain = "0.4864"; +reflectionDelay = "0.0200"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "2.4378"; +lateReverbDelay = "0.0300"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "4.0000"; +reverbModDepth = "1.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "0"; }; -singleton SFXEnvironment( AudioEnvPsychotic ) +singleton SFXEnvironment(CastleSmallroom) { - envSize = "1.0"; - envDiffusion = "0.5"; - room = "-1000"; - roomHF = "-151"; - roomLF = "0"; - decayTime = "7.56"; - decayHFRatio = "0.91"; - decayLFRatio = "1.0"; - reflections = "-626"; - reflectionsDelay = "0.02"; - reflectionsPan[ 0 ] = "0.0"; - reflectionsPan[ 1 ] = "0.0"; - reflectionsPan[ 2 ] = "0.0"; - reverb = "774"; - reverbDelay = "0.03"; - reverbPan[ 0 ] = "0.0"; - reverbPan[ 1 ] = "0.0"; - reverbPan[ 2 ] = "0.0"; - echoTime = "0.25"; - echoDepth = "0.0"; - modulationTime = "4.0"; - modulationDepth = "1.0"; - airAbsorptionHF = "-5.0"; - HFReference = "5000.0"; - LFReference = "250.0"; - roomRolloffFactor = "0.0"; - diffusion = "100.0"; - density = "100.0"; - flags = 0x1f; +reverbDensity = "1.0000"; +reverbDiffusion = "0.8900"; +reverbGain = "0.3162"; +reverbGainHF = "0.3981"; +reverbGainLF = "0.1000"; +reverbDecayTime = "1.2200"; +reverbDecayHFRatio = "0.8300"; +reverbDecayLFRatio = "0.3100"; +reflectionsGain = "0.8913"; +reflectionDelay = "0.0220"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.9953"; +lateReverbDelay = "0.0110"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1380"; +reverbEchoDepth = "0.0800"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; }; + +singleton SFXEnvironment(CastleShortPassage) +{ +reverbDensity = "1.0000"; +reverbDiffusion = "0.8900"; +reverbGain = "0.3162"; +reverbGainHF = "0.3162"; +reverbGainLF = "0.1000"; +reverbDecayTime = "2.3200"; +reverbDecayHFRatio = "0.8300"; +reverbDecayLFRatio = "0.3100"; +reflectionsGain = "0.8913"; +reflectionDelay = "0.0070"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.2589"; +lateReverbDelay = "0.0230"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1380"; +reverbEchoDepth = "0.0800"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5168.0001"; +reverbLFRef = "139.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(CastleMediumRoom) +{ +reverbDensity = "1.0000"; +reverbDiffusion = "0.9300"; +reverbGain = "0.3162"; +reverbGainHF = "0.2818"; +reverbGainLF = "0.1000"; +reverbDecayTime = "2.0400"; +reverbDecayHFRatio = "0.8300"; +reverbDecayLFRatio = "0.4600"; +reflectionsGain = "0.6310"; +reflectionDelay = "0.0220"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.5849"; +lateReverbDelay = "0.0110"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1550"; +reverbEchoDepth = "0.0300"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5168.0001"; +reverbLFRef = "139.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(CastleLargeRoom) +{ +reverbDensity = "1.0000"; +reverbDiffusion = "0.8200"; +reverbGain = "0.3162"; +reverbGainHF = "0.2818"; +reverbGainLF = "0.1259"; +reverbDecayTime = "2.5300"; +reverbDecayHFRatio = "0.8300"; +reverbDecayLFRatio = "0.5000"; +reflectionsGain = "0.4467"; +reflectionDelay = "0.0340"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.2589"; +lateReverbDelay = "0.0160"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1850"; +reverbEchoDepth = "0.0700"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5168.0001"; +reverbLFRef = "139.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(CastleLongPassage) +{ +reverbDensity = "1.0000"; +reverbDiffusion = "0.8900"; +reverbGain = "0.3162"; +reverbGainHF = "0.3981"; +reverbGainLF = "0.1000"; +reverbDecayTime = "3.4200"; +reverbDecayHFRatio = "0.8300"; +reverbDecayLFRatio = "0.3100"; +reflectionsGain = "0.8913"; +reflectionDelay = "0.0070"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.4125"; +lateReverbDelay = "0.0230"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1380"; +reverbEchoDepth = "0.0800"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5168.0001"; +reverbLFRef = "139.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(CastleHall) +{ +reverbDensity = "1.0000"; +reverbDiffusion = "0.8100"; +reverbGain = "0.3162"; +reverbGainHF = "0.2818"; +reverbGainLF = "0.1778"; +reverbDecayTime = "3.1400"; +reverbDecayHFRatio = "0.7900"; +reverbDecayLFRatio = "0.6200"; +reflectionsGain = "0.1778"; +reflectionDelay = "0.0560"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.1220"; +lateReverbDelay = "0.0240"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5168.0001"; +reverbLFRef = "139.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(CastleCupboard) +{ +reverbDensity = "1.0000"; +reverbDiffusion = "0.8900"; +reverbGain = "0.3162"; +reverbGainHF = "0.2818"; +reverbGainLF = "0.1000"; +reverbDecayTime = "0.6700"; +reverbDecayHFRatio = "0.8700"; +reverbDecayLFRatio = "0.3100"; +reflectionsGain = "1.4125"; +reflectionDelay = "0.0100"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "3.5481"; +lateReverbDelay = "0.0070"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1380"; +reverbEchoDepth = "0.0800"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5168.0001"; +reverbLFRef = "139.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(CastleCourtyard) +{ +reverbDensity = "1.0000"; +reverbDiffusion = "0.4200"; +reverbGain = "0.3162"; +reverbGainHF = "0.4467"; +reverbGainLF = "0.1995"; +reverbDecayTime = "2.1300"; +reverbDecayHFRatio = "0.6100"; +reverbDecayLFRatio = "0.2300"; +reflectionsGain = "0.2239"; +reflectionDelay = "0.1600"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.7079"; +lateReverbDelay = "0.0360"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.3700"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5000.0000"; +reverbLFRef = "250.0000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "0"; +}; + +singleton SFXEnvironment(CastleAlcove) +{ +reverbDensity = "1.0000"; +reverbDiffusion = "0.8900"; +reverbGain = "0.3162"; +reverbGainHF = "0.5012"; +reverbGainLF = "0.1000"; +reverbDecayTime = "1.6400"; +reverbDecayHFRatio = "0.8700"; +reverbDecayLFRatio = "0.3100"; +reflectionsGain = "1.0000"; +reflectionDelay = "0.0070"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.4125"; +lateReverbDelay = "0.0340"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1380"; +reverbEchoDepth = "0.0800"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "5168.0001"; +reverbLFRef = "139.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(FactorySmallRoom) +{ +reverbDensity = "0.3645"; +reverbDiffusion = "0.8200"; +reverbGain = "0.3162"; +reverbGainHF = "0.7943"; +reverbGainLF = "0.5012"; +reverbDecayTime = "1.7200"; +reverbDecayHFRatio = "0.6500"; +reverbDecayLFRatio = "1.3100"; +reflectionsGain = "0.7079"; +reflectionDelay = "0.0100"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.7783"; +lateReverbDelay = "0.0240"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1190"; +reverbEchoDepth = "0.0700"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "3762.6001"; +reverbLFRef = "362.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(FactoryShortPassage) +{ +reverbDensity = "0.3645"; +reverbDiffusion = "0.6400"; +reverbGain = "0.2512"; +reverbGainHF = "0.7943"; +reverbGainLF = "0.5012"; +reverbDecayTime = "2.5300"; +reverbDecayHFRatio = "0.6500"; +reverbDecayLFRatio = "1.3100"; +reflectionsGain = "1.0000"; +reflectionDelay = "0.0100"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.2589"; +lateReverbDelay = "0.0380"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1350"; +reverbEchoDepth = "0.2300"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "3762.6001"; +reverbLFRef = "362.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(FactoryMediumRoom) +{ +reverbDensity = "0.4287"; +reverbDiffusion = "0.8200"; +reverbGain = "0.2512"; +reverbGainHF = "0.7943"; +reverbGainLF = "0.5012"; +reverbDecayTime = "2.7600"; +reverbDecayHFRatio = "0.6500"; +reverbDecayLFRatio = "1.3100"; +reflectionsGain = "0.2818"; +reflectionDelay = "0.0220"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.4125"; +lateReverbDelay = "0.0230"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1740"; +reverbEchoDepth = "0.0700"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "3762.6001"; +reverbLFRef = "362.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(FactoryLargeRoom) +{ +reverbDensity = "0.4287"; +reverbDiffusion = "0.7500"; +reverbGain = "0.2512"; +reverbGainHF = "0.7079"; +reverbGainLF = "0.6310"; +reverbDecayTime = "4.2400"; +reverbDecayHFRatio = "0.5100"; +reverbDecayLFRatio = "1.3100"; +reflectionsGain = "0.1778"; +reflectionDelay = "0.0390"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.1220"; +lateReverbDelay = "0.0230"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2310"; +reverbEchoDepth = "0.0700"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "3762.6001"; +reverbLFRef = "362.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(FactoryLongPassage) +{ +reverbDensity = "0.3645"; +reverbDiffusion = "0.6400"; +reverbGain = "0.2512"; +reverbGainHF = "0.7943"; +reverbGainLF = "0.5012"; +reverbDecayTime = "4.0000"; +reverbDecayHFRatio = "0.6500"; +reverbDecayLFRatio = "1.3100"; +reflectionsGain = "1.0000"; +reflectionDelay = "0.0200"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.2589"; +lateReverbDelay = "0.0370"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1350"; +reverbEchoDepth = "0.2300"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "3762.6001"; +reverbLFRef = "362.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(FactoryHall) +{ +reverbDensity = "0.4287"; +reverbDiffusion = "0.7500"; +reverbGain = "0.3162"; +reverbGainHF = "0.7079"; +reverbGainLF = "0.6310"; +reverbDecayTime = "7.4300"; +reverbDecayHFRatio = "0.5100"; +reverbDecayLFRatio = "1.3100"; +reflectionsGain = "0.0631"; +reflectionDelay = "0.0730"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.8913"; +lateReverbDelay = "0.0270"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.0700"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "3762.6001"; +reverbLFRef = "362.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(FactoryCupboard) +{ +reverbDensity = "0.3071"; +reverbDiffusion = "0.6300"; +reverbGain = "0.2512"; +reverbGainHF = "0.7943"; +reverbGainLF = "0.5012"; +reverbDecayTime = "0.4900"; +reverbDecayHFRatio = "0.6500"; +reverbDecayLFRatio = "1.3100"; +reflectionsGain = "1.2589"; +reflectionDelay = "0.0100"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.9953"; +lateReverbDelay = "0.0320"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1070"; +reverbEchoDepth = "0.0700"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "3762.6001"; +reverbLFRef = "362.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(FactoryCourtyard) +{ +reverbDensity = "0.3071"; +reverbDiffusion = "0.5700"; +reverbGain = "0.3162"; +reverbGainHF = "0.3162"; +reverbGainLF = "0.6310"; +reverbDecayTime = "2.3200"; +reverbDecayHFRatio = "0.2900"; +reverbDecayLFRatio = "0.5600"; +reflectionsGain = "0.2239"; +reflectionDelay = "0.1400"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "0.3981"; +lateReverbDelay = "0.0390"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.2500"; +reverbEchoDepth = "0.2900"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "3762.6001"; +reverbLFRef = "362.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; + +singleton SFXEnvironment(FactoryAlcove) +{ +reverbDensity = "0.3645"; +reverbDiffusion = "0.5900"; +reverbGain = "0.2512"; +reverbGainHF = "0.7943"; +reverbGainLF = "0.5012"; +reverbDecayTime = "3.1400"; +reverbDecayHFRatio = "0.6500"; +reverbDecayLFRatio = "1.3100"; +reflectionsGain = "1.4125"; +reflectionDelay = "0.0100"; +reflectionsPan[ 0 ] = "0.0"; +reflectionsPan[ 1 ] = "0.0"; +reflectionsPan[ 2 ] = "0.0"; +lateReverbGain = "1.0000"; +lateReverbDelay = "0.0380"; +lateReverbPan[ 0 ] = "0.0"; +lateReverbPan[ 1 ] = "0.0"; +lateReverbPan[ 2 ] = "0.0"; +reverbEchoTime = "0.1140"; +reverbEchoDepth = "0.1000"; +reverbModTime = "0.2500"; +reverbModDepth = "0.0000"; +airAbsorbtionGainHF = "0.9943"; +reverbHFRef = "3762.6001"; +reverbLFRef = "362.5000"; +roomRolloffFactor = "0.0000"; +decayHFLimit = "1"; +}; \ No newline at end of file From 580ab01766c25d15fb7ffed5c75192acdd56a3b0 Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Sat, 17 Nov 2018 05:51:47 -0500 Subject: [PATCH 17/75] Fix CanvasSizeChangeSignal and Canvas::onResize() callback for SDL Window. --- Engine/source/windowManager/sdl/sdlWindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Engine/source/windowManager/sdl/sdlWindow.cpp b/Engine/source/windowManager/sdl/sdlWindow.cpp index 149825b98..06b0c81b8 100644 --- a/Engine/source/windowManager/sdl/sdlWindow.cpp +++ b/Engine/source/windowManager/sdl/sdlWindow.cpp @@ -594,6 +594,7 @@ void PlatformWindowSDL::_processSDLEvent(SDL_Event &evt) SDL_GetWindowSize( mWindowHandle, &width, &height ); mVideoMode.resolution.set( width, height ); getGFXTarget()->resetMode(); + resizeEvent.trigger(getWindowId(), width, height); break; } From b5815bde22b83a6a148175eaa89cc916ad850563 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Tue, 1 Jan 2019 10:58:53 -0600 Subject: [PATCH 18/75] NFD updated to 1.1.4 --- Engine/lib/nativeFileDialogs/README.md | 80 ++++-- Engine/lib/nativeFileDialogs/nfd_cocoa.m | 16 +- Engine/lib/nativeFileDialogs/nfd_gtk.c | 2 +- Engine/lib/nativeFileDialogs/nfd_win.cpp | 103 ++++--- Engine/lib/nativeFileDialogs/nfd_zenity.c | 311 +++++++++++++++++++++ Engine/lib/nativeFileDialogs/simple_exec.h | 214 ++++++++++++++ 6 files changed, 658 insertions(+), 68 deletions(-) create mode 100644 Engine/lib/nativeFileDialogs/nfd_zenity.c create mode 100644 Engine/lib/nativeFileDialogs/simple_exec.h diff --git a/Engine/lib/nativeFileDialogs/README.md b/Engine/lib/nativeFileDialogs/README.md index 7ff1008a3..83238e133 100644 --- a/Engine/lib/nativeFileDialogs/README.md +++ b/Engine/lib/nativeFileDialogs/README.md @@ -1,6 +1,6 @@ # Native File Dialog # -A tiny, neat C library that portably invokes native file open and save dialogs. Write dialog code once and have it pop up native dialogs on all supported platforms. Avoid linking large dependencies like wxWidgets and qt. +A tiny, neat C library that portably invokes native file open, folder select and save dialogs. Write dialog code once and have it pop up native dialogs on all supported platforms. Avoid linking large dependencies like wxWidgets and qt. Features: @@ -11,11 +11,12 @@ Features: - Paid support available. - Multiple file selection support. - 64-bit and 32-bit friendly. - - GCC, Clang and Visual Studio supported. - - No third party dependencies. + - GCC, Clang, Xcode, Mingw and Visual Studio supported. + - No third party dependencies for building or linking. - Support for Vista's modern `IFileDialog` on Windows. - Support for non-deprecated Cocoa APIs on OS X. - - GTK+3 dialog on Linux. + - GTK3 dialog on Linux. + - Optional Zenity support on Linux to avoid linking GTK. - Tested, works alongside [http://www.libsdl.org](SDL2) on all platforms, for the game developers out there. # Example Usage # @@ -50,47 +51,74 @@ See [NFD.h](src/include/nfd.h) for more options. # Screenshots # -![Windows 8 rendering an IFileOpenDialog](screens/open_win8.png?raw=true) +![Windows 8 rendering an IFileOpenDialog](screens/open_win.png?raw=true) ![GTK3 on Linux](screens/open_gtk3.png?raw=true) ![Cocoa on Yosemite](screens/open_cocoa.png?raw=true) +## Changelog ## + +release | what's new | date +--------|-----------------------------|--------- +1.0.0 | initial | oct 2014 +1.1.0 | premake5; scons deprecated | aug 2016 +1.1.1 | mingw support, build fixes | aug 2016 +1.1.2 | test_pickfolder() added | aug 2016 +1.1.3 | zenity linux backend added | nov 2017 +1.1.3 | fix char type in decls | nov 2017 +1.1.4 | fix win32 memleaks | dec 2018 +1.1.4 | improve win32 errorhandling | dec 2018 +1.1.4 | macos fix focus bug | dec 2018 + ## Building ## -NFD uses [SCons](http://www.scons.org) for cross-platform builds. After installing SCons, build it with: +NFD uses [Premake5](https://premake.github.io/download.html) generated Makefiles and IDE project files. The generated project files are checked in under `build/` so you don't have to download and use Premake in most cases. - cd src - scons debug=[0,1] +If you need to run Premake5 directly, further [build documentation](docs/build.md) is available. -Alternatively, you can avoid Scons by just including NFD files to your existing project: +Previously, NFD used SCons to build. It still works, but is now deprecated; updates to it are discouraged. Opt to use the native build system where possible. - 1. Add all header files in `src/` and `src/include` to your project. - 2. Add `src/include` to your include search path or copy it into your existing search path. - 3. Add `src/nfd_common.c` to your project. - 4. Add `src/nfd_` to your project, where `` is the NFD backend for the platform you are fixing to build. - 5. On Visual Studio, define `_CRT_SECURE_NO_WARNINGS` to avoid warnings. +`nfd.a` will be built for release builds, and `nfd_d.a` will be built for debug builds. + +### Makefiles ### + +The makefile offers five options, with `release_x64` as the default. + + make config=release_x86 + make config=release_x64 + make config=debug_x86 + make config=debug_x64 ### Compiling Your Programs ### 1. Add `src/include` to your include search path. - 2. Add `nfd.lib` to the list of list of static libraries to link against. - 3. Add `src/` to the library search path. + 2. Add `nfd.lib` or `nfd_d.lib` to the list of list of static libraries to link against (for release or debug, respectively). + 3. Add `build//` to the library search path. -On Linux, you must compile and link against GTK+. Recommend use of `pkg-config --cflags --libs gtk+-3.0`. +#### Linux GTK #### +`apt-get libgtk-3-dev` installs the gtk dependency for library compilation. -On Mac OS X, add `AppKit` to the list of frameworks. +On Linux, you have the option of compiling and linking against GTK. If you use it, the recommended way to compile is to include the arguments of `pkg-config --cflags --libs gtk+-3.0`. +#### Linux Zenity #### + +Alternatively, you can use the Zenity backend by running the Makefile in `build/gmake_linux_zenity`. Zenity runs the dialog in its own address space, but requires the user to have Zenity correctly installed and configured on their system. + +#### MacOS #### +On Mac OS, add `AppKit` to the list of frameworks. + +#### Windows #### On Windows, ensure you are building against `comctl32.lib`. ## Usage ## See `NFD.h` for API calls. See `tests/*.c` for example code. -See `tests/SConstruct` for a working build script that compiles on all platforms. +After compiling, `build/bin` contains compiled test programs. ## File Filter Syntax ## -There is a form of file filtering in every file dialog, but no consistent means of supporting it. NFD provides support for filtering files by groups of extensions, providing its own descriptions (where applicable) for the extensions. +There is a form of file filtering in every file dialog API, but no consistent means of supporting it. NFD provides support for filtering files by groups of extensions, providing its own descriptions (where applicable) for the extensions. A wildcard filter is always added to every dialog. @@ -113,16 +141,14 @@ See [test_opendialogmultiple.c](test/test_opendialogmultiple.c). # Known Limitations # -I accept quality code patches, or will resolve these and other matters through support. +I accept quality code patches, or will resolve these and other matters through support. See [submitting pull requests](docs/submitting_pull_requests.md) for details. - No support for Windows XP's legacy dialogs such as `GetOpenFileName`. - - No support for file filter names -- ex: "Image Files" (*.png, *.jpg). Nameless filters are supported, though. - - No support for selecting folders instead of files. - - On Linux, GTK+ cannot be uninitialized to save memory. Launching a file dialog costs memory. I am open to accepting an alternative `nfd_zenity.c` implementation which uses Zenity and pipes. + - No support for file filter names -- ex: "Image Files" (*.png, *.jpg). Nameless filters are supported, however. # Copyright and Credit # -Copyright © 2014 [Frogtoss Games](http://www.frogtoss.com), Inc. +Copyright © 2014-2017 [Frogtoss Games](http://www.frogtoss.com), Inc. File [LICENSE](LICENSE) covers all files in this repo. Native File Dialog by Michael Labbe @@ -130,6 +156,10 @@ Native File Dialog by Michael Labbe Tomasz Konojacki for [microutf8](http://puszcza.gnu.org.ua/software/microutf8/) +[Denis Kolodin](https://github.com/DenisKolodin) for mingw support. + +[Tom Mason](https://github.com/wheybags) for Zenity support. + ## Support ## Directed support for this work is available from the original author under a paid agreement. diff --git a/Engine/lib/nativeFileDialogs/nfd_cocoa.m b/Engine/lib/nativeFileDialogs/nfd_cocoa.m index d3fb48347..39a0931de 100644 --- a/Engine/lib/nativeFileDialogs/nfd_cocoa.m +++ b/Engine/lib/nativeFileDialogs/nfd_cocoa.m @@ -117,7 +117,7 @@ static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset ) /* public */ -nfdresult_t NFD_OpenDialog( const char *filterList, +nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, nfdchar_t **outPath ) { @@ -146,6 +146,7 @@ nfdresult_t NFD_OpenDialog( const char *filterList, if ( !*outPath ) { [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; return NFD_ERROR; } memcpy( *outPath, utf8Path, len+1 ); /* copy null term */ @@ -163,6 +164,7 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, nfdpathset_t *outPaths ) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; NSOpenPanel *dialog = [NSOpenPanel openPanel]; [dialog setAllowsMultipleSelection:YES]; @@ -181,12 +183,14 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, if ( [urls count] == 0 ) { [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; return NFD_CANCEL; } if ( AllocPathSet( urls, outPaths ) == NFD_ERROR ) { [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; return NFD_ERROR; } @@ -194,6 +198,7 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, } [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; return nfdResult; } @@ -203,7 +208,8 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, nfdchar_t **outPath ) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - + NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; + NSSavePanel *dialog = [NSSavePanel savePanel]; [dialog setExtensionHidden:NO]; @@ -225,6 +231,7 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, if ( !*outPath ) { [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; return NFD_ERROR; } memcpy( *outPath, utf8Path, byteLen ); @@ -232,7 +239,7 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, } [pool release]; - + [keyWindow makeKeyAndOrderFront:nil]; return nfdResult; } @@ -241,7 +248,7 @@ nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; + NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; NSOpenPanel *dialog = [NSOpenPanel openPanel]; [dialog setAllowsMultipleSelection:NO]; [dialog setCanChooseDirectories:YES]; @@ -264,6 +271,7 @@ nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, if ( !*outPath ) { [pool release]; + [keyWindow makeKeyAndOrderFront:nil]; return NFD_ERROR; } memcpy( *outPath, utf8Path, len+1 ); /* copy null term */ diff --git a/Engine/lib/nativeFileDialogs/nfd_gtk.c b/Engine/lib/nativeFileDialogs/nfd_gtk.c index 65bc41dad..7a9958ed1 100644 --- a/Engine/lib/nativeFileDialogs/nfd_gtk.c +++ b/Engine/lib/nativeFileDialogs/nfd_gtk.c @@ -165,7 +165,7 @@ static void WaitForCleanup(void) /* public */ -nfdresult_t NFD_OpenDialog( const char *filterList, +nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, nfdchar_t **outPath ) { diff --git a/Engine/lib/nativeFileDialogs/nfd_win.cpp b/Engine/lib/nativeFileDialogs/nfd_win.cpp index 1187fc84b..9e94d9d58 100644 --- a/Engine/lib/nativeFileDialogs/nfd_win.cpp +++ b/Engine/lib/nativeFileDialogs/nfd_win.cpp @@ -4,6 +4,10 @@ http://www.frogtoss.com/labs */ +#define _CRTDBG_MAP_ALLOC +#include +#include + /* only locally define UNICODE in this compilation unit */ #ifndef UNICODE #define UNICODE @@ -19,7 +23,7 @@ #include #include #include -#include +#include #include "nfd_common.h" @@ -47,9 +51,9 @@ static void CopyWCharToNFDChar( const wchar_t *inStr, nfdchar_t **outStr ) /* includes NULL terminator byte in return */ static size_t GetUTF8ByteCountForWChar( const wchar_t *str ) { - int bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, - str, -1, - NULL, 0, NULL, NULL ); + size_t bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, + str, -1, + NULL, 0, NULL, NULL ); assert( bytesNeeded ); return bytesNeeded+1; } @@ -148,12 +152,12 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char } /* filterCount plus 1 because we hardcode the *.* wildcard after the while loop */ - COMDLG_FILTERSPEC *specList = (COMDLG_FILTERSPEC*)NFDi_Malloc( sizeof(COMDLG_FILTERSPEC) * (filterCount + 1) ); + COMDLG_FILTERSPEC *specList = (COMDLG_FILTERSPEC*)NFDi_Malloc( sizeof(COMDLG_FILTERSPEC) * ((size_t)filterCount + 1) ); if ( !specList ) { return NFD_ERROR; } - for (size_t i = 0; i < filterCount+1; ++i ) + for (UINT i = 0; i < filterCount+1; ++i ) { specList[i].pszName = NULL; specList[i].pszSpec = NULL; @@ -181,9 +185,8 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char if ( *p_filterList == ';' || *p_filterList == '\0' ) { /* end of filter -- add it to specList */ - - // Empty filter name -- Windows describes them by extension. - CopyNFDCharToWChar(specbuf, (wchar_t**)&specList[specIdx].pszName); + + CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszName ); CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszSpec ); memset( specbuf, 0, sizeof(char)*NFD_MAX_STRLEN ); @@ -270,6 +273,8 @@ static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *path // Calculate length of name with UTF-8 encoding bufSize += GetUTF8ByteCountForWChar( name ); + + CoTaskMemFree(name); } assert(bufSize); @@ -304,6 +309,7 @@ static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *path shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name); int bytesWritten = CopyWCharToExistingNFDCharBuffer(name, p_buf); + CoTaskMemFree(name); ptrdiff_t index = p_buf - pathSet->buf; assert( index >= 0 ); @@ -353,29 +359,30 @@ static nfdresult_t SetDefaultPath( IFileDialog *dialog, const char *defaultPath /* public */ -nfdresult_t NFD_OpenDialog( const char *filterList, +nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, nfdchar_t **outPath ) { nfdresult_t nfdResult = NFD_ERROR; // Init COM library. - HRESULT result = ::CoInitializeEx(NULL, - ::COINIT_APARTMENTTHREADED | - ::COINIT_DISABLE_OLE1DDE ); + HRESULT coResult = ::CoInitializeEx(NULL, + ::COINIT_APARTMENTTHREADED | + ::COINIT_DISABLE_OLE1DDE ); ::IFileOpenDialog *fileOpenDialog(NULL); - if ( !SUCCEEDED(result)) + if ( !SUCCEEDED(coResult)) { + fileOpenDialog = NULL; NFDi_SetError("Could not initialize COM."); goto end; } // Create dialog - result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, - CLSCTX_ALL, ::IID_IFileOpenDialog, - reinterpret_cast(&fileOpenDialog) ); + HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, + CLSCTX_ALL, ::IID_IFileOpenDialog, + reinterpret_cast(&fileOpenDialog) ); if ( !SUCCEEDED(result) ) { @@ -412,6 +419,7 @@ nfdresult_t NFD_OpenDialog( const char *filterList, if ( !SUCCEEDED(result) ) { NFDi_SetError("Could not get file path for selected."); + shellItem->Release(); goto end; } @@ -420,6 +428,7 @@ nfdresult_t NFD_OpenDialog( const char *filterList, if ( !*outPath ) { /* error is malloc-based, error message would be redundant */ + shellItem->Release(); goto end; } @@ -436,8 +445,12 @@ nfdresult_t NFD_OpenDialog( const char *filterList, nfdResult = NFD_ERROR; } - end: - ::CoUninitialize(); +end: + if (fileOpenDialog) + fileOpenDialog->Release(); + + if (SUCCEEDED(coResult)) + ::CoUninitialize(); return nfdResult; } @@ -449,10 +462,10 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, nfdresult_t nfdResult = NFD_ERROR; // Init COM library. - HRESULT result = ::CoInitializeEx(NULL, - ::COINIT_APARTMENTTHREADED | - ::COINIT_DISABLE_OLE1DDE ); - if ( !SUCCEEDED(result)) + HRESULT coResult = ::CoInitializeEx(NULL, + ::COINIT_APARTMENTTHREADED | + ::COINIT_DISABLE_OLE1DDE ); + if ( !SUCCEEDED(coResult)) { NFDi_SetError("Could not initialize COM."); return NFD_ERROR; @@ -461,12 +474,13 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, ::IFileOpenDialog *fileOpenDialog(NULL); // Create dialog - result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, - CLSCTX_ALL, ::IID_IFileOpenDialog, - reinterpret_cast(&fileOpenDialog) ); + HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, + CLSCTX_ALL, ::IID_IFileOpenDialog, + reinterpret_cast(&fileOpenDialog) ); if ( !SUCCEEDED(result) ) { + fileOpenDialog = NULL; NFDi_SetError("Could not create dialog."); goto end; } @@ -512,6 +526,7 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, if ( AllocPathSet( shellItems, outPaths ) == NFD_ERROR ) { + shellItems->Release(); goto end; } @@ -528,8 +543,12 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, nfdResult = NFD_ERROR; } - end: - ::CoUninitialize(); +end: + if ( fileOpenDialog ) + fileOpenDialog->Release(); + + if (SUCCEEDED(coResult)) + ::CoUninitialize(); return nfdResult; } @@ -541,10 +560,10 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, nfdresult_t nfdResult = NFD_ERROR; // Init COM library. - HRESULT result = ::CoInitializeEx(NULL, - ::COINIT_APARTMENTTHREADED | - ::COINIT_DISABLE_OLE1DDE ); - if ( !SUCCEEDED(result)) + HRESULT coResult = ::CoInitializeEx(NULL, + ::COINIT_APARTMENTTHREADED | + ::COINIT_DISABLE_OLE1DDE ); + if ( !SUCCEEDED(coResult)) { NFDi_SetError("Could not initialize COM."); return NFD_ERROR; @@ -553,12 +572,13 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, ::IFileSaveDialog *fileSaveDialog(NULL); // Create dialog - result = ::CoCreateInstance(::CLSID_FileSaveDialog, NULL, - CLSCTX_ALL, ::IID_IFileSaveDialog, - reinterpret_cast(&fileSaveDialog) ); + HRESULT result = ::CoCreateInstance(::CLSID_FileSaveDialog, NULL, + CLSCTX_ALL, ::IID_IFileSaveDialog, + reinterpret_cast(&fileSaveDialog) ); if ( !SUCCEEDED(result) ) { + fileSaveDialog = NULL; NFDi_SetError("Could not create dialog."); goto end; } @@ -591,6 +611,7 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, result = shellItem->GetDisplayName(::SIGDN_FILESYSPATH, &filePath); if ( !SUCCEEDED(result) ) { + shellItem->Release(); NFDi_SetError("Could not get file path for selected."); goto end; } @@ -600,6 +621,7 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, if ( !*outPath ) { /* error is malloc-based, error message would be redundant */ + shellItem->Release(); goto end; } @@ -616,8 +638,12 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, nfdResult = NFD_ERROR; } - end: - ::CoUninitialize(); +end: + if ( fileSaveDialog ) + fileSaveDialog->Release(); + + if (SUCCEEDED(coResult)) + ::CoUninitialize(); return nfdResult; } @@ -729,7 +755,8 @@ nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, ComPtr pShellItem; if (!SUCCEEDED(pFileDialog->GetResult(&pShellItem))) { - return NFD_OKAY; + NFDi_SetError("Could not get shell item from dialog."); + return NFD_ERROR; } // Finally get the path diff --git a/Engine/lib/nativeFileDialogs/nfd_zenity.c b/Engine/lib/nativeFileDialogs/nfd_zenity.c new file mode 100644 index 000000000..1890eec9e --- /dev/null +++ b/Engine/lib/nativeFileDialogs/nfd_zenity.c @@ -0,0 +1,311 @@ +/* + Native File Dialog + + http://www.frogtoss.com/labs +*/ + +#include +#include +#include +#include "nfd.h" +#include "nfd_common.h" + +#define SIMPLE_EXEC_IMPLEMENTATION +#include "simple_exec.h" + + +const char NO_ZENITY_MSG[] = "zenity not installed"; + + +static void AddTypeToFilterName( const char *typebuf, char *filterName, size_t bufsize ) +{ + size_t len = strlen(filterName); + if( len > 0 ) + strncat( filterName, " *.", bufsize - len - 1 ); + else + strncat( filterName, "--file-filter=*.", bufsize - len - 1 ); + + len = strlen(filterName); + strncat( filterName, typebuf, bufsize - len - 1 ); +} + +static void AddFiltersToCommandArgs(char** commandArgs, int commandArgsLen, const char *filterList ) +{ + char typebuf[NFD_MAX_STRLEN] = {0}; + const char *p_filterList = filterList; + char *p_typebuf = typebuf; + char filterName[NFD_MAX_STRLEN] = {0}; + int i; + + if ( !filterList || strlen(filterList) == 0 ) + return; + + while ( 1 ) + { + + if ( NFDi_IsFilterSegmentChar(*p_filterList) ) + { + char typebufWildcard[NFD_MAX_STRLEN]; + /* add another type to the filter */ + assert( strlen(typebuf) > 0 ); + assert( strlen(typebuf) < NFD_MAX_STRLEN-1 ); + + snprintf( typebufWildcard, NFD_MAX_STRLEN, "*.%s", typebuf ); + + AddTypeToFilterName( typebuf, filterName, NFD_MAX_STRLEN ); + + p_typebuf = typebuf; + memset( typebuf, 0, sizeof(char) * NFD_MAX_STRLEN ); + } + + if ( *p_filterList == ';' || *p_filterList == '\0' ) + { + /* end of filter -- add it to the dialog */ + + for(i = 0; commandArgs[i] != NULL && i < commandArgsLen; i++); + + commandArgs[i] = strdup(filterName); + + filterName[0] = '\0'; + + if ( *p_filterList == '\0' ) + break; + } + + if ( !NFDi_IsFilterSegmentChar( *p_filterList ) ) + { + *p_typebuf = *p_filterList; + p_typebuf++; + } + + p_filterList++; + } + + /* always append a wildcard option to the end*/ + + for(i = 0; commandArgs[i] != NULL && i < commandArgsLen; i++); + + commandArgs[i] = strdup("--file-filter=*.*"); +} + +static nfdresult_t ZenityCommon(char** command, int commandLen, const char* defaultPath, const char* filterList, char** stdOut) +{ + if(defaultPath != NULL) + { + char* prefix = "--filename"; + int len = strlen(prefix) + strlen(defaultPath) + 1; + + char* tmp = (char*) calloc(len, 1); + strcat(tmp, prefix); + strcat(tmp, defaultPath); + + int i; + for(i = 0; command[i] != NULL && i < commandLen; i++); + + command[i] = tmp; + } + + AddFiltersToCommandArgs(command, commandLen, filterList); + + int byteCount = 0; + int exitCode = 0; + int processInvokeError = runCommandArray(stdOut, &byteCount, &exitCode, 0, command); + + for(int i = 0; command[i] != NULL && i < commandLen; i++) + free(command[i]); + + nfdresult_t result = NFD_OKAY; + + if(processInvokeError == COMMAND_NOT_FOUND) + { + NFDi_SetError(NO_ZENITY_MSG); + result = NFD_ERROR; + } + else + { + if(exitCode == 1) + result = NFD_CANCEL; + } + + return result; +} + + +static nfdresult_t AllocPathSet(char* zenityList, nfdpathset_t *pathSet ) +{ + size_t bufSize = 0; + nfdchar_t *p_buf; + size_t count = 0; + + assert(zenityList); + assert(pathSet); + + size_t len = strlen(zenityList) + 1; + pathSet->buf = NFDi_Malloc(len); + + int numEntries = 1; + + for(size_t i = 0; i < len; i++) + { + char ch = zenityList[i]; + + if(ch == '|') + { + numEntries++; + ch = '\0'; + } + + pathSet->buf[i] = ch; + } + + pathSet->count = numEntries; + assert( pathSet->count > 0 ); + + pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count ); + + int entry = 0; + pathSet->indices[0] = 0; + for(size_t i = 0; i < len; i++) + { + char ch = zenityList[i]; + + if(ch == '|') + { + entry++; + pathSet->indices[entry] = i + 1; + } + } + + return NFD_OKAY; +} + +/* public */ + +nfdresult_t NFD_OpenDialog( const char *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + int commandLen = 100; + char* command[commandLen]; + memset(command, 0, commandLen * sizeof(char*)); + + command[0] = strdup("zenity"); + command[1] = strdup("--file-selection"); + command[2] = strdup("--title=Open File"); + + char* stdOut = NULL; + nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut); + + if(stdOut != NULL) + { + size_t len = strlen(stdOut); + *outPath = NFDi_Malloc(len); + memcpy(*outPath, stdOut, len); + (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator + free(stdOut); + } + else + { + *outPath = NULL; + } + + return result; +} + + +nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdpathset_t *outPaths ) +{ + int commandLen = 100; + char* command[commandLen]; + memset(command, 0, commandLen * sizeof(char*)); + + command[0] = strdup("zenity"); + command[1] = strdup("--file-selection"); + command[2] = strdup("--title=Open Files"); + command[3] = strdup("--multiple"); + + char* stdOut = NULL; + nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut); + + if(stdOut != NULL) + { + size_t len = strlen(stdOut); + stdOut[len-1] = '\0'; // remove trailing newline + + if ( AllocPathSet( stdOut, outPaths ) == NFD_ERROR ) + result = NFD_ERROR; + + free(stdOut); + } + else + { + result = NFD_ERROR; + } + + return result; +} + +nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + int commandLen = 100; + char* command[commandLen]; + memset(command, 0, commandLen * sizeof(char*)); + + command[0] = strdup("zenity"); + command[1] = strdup("--file-selection"); + command[2] = strdup("--title=Save File"); + command[3] = strdup("--save"); + + char* stdOut = NULL; + nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut); + + if(stdOut != NULL) + { + size_t len = strlen(stdOut); + *outPath = NFDi_Malloc(len); + memcpy(*outPath, stdOut, len); + (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator + free(stdOut); + } + else + { + *outPath = NULL; + } + + return result; +} + +nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, + nfdchar_t **outPath) +{ + int commandLen = 100; + char* command[commandLen]; + memset(command, 0, commandLen * sizeof(char*)); + + command[0] = strdup("zenity"); + command[1] = strdup("--file-selection"); + command[2] = strdup("--directory"); + command[3] = strdup("--title=Select folder"); + + char* stdOut = NULL; + nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, "", &stdOut); + + if(stdOut != NULL) + { + size_t len = strlen(stdOut); + *outPath = NFDi_Malloc(len); + memcpy(*outPath, stdOut, len); + (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator + free(stdOut); + } + else + { + *outPath = NULL; + } + + return result; +} diff --git a/Engine/lib/nativeFileDialogs/simple_exec.h b/Engine/lib/nativeFileDialogs/simple_exec.h new file mode 100644 index 000000000..b85327b55 --- /dev/null +++ b/Engine/lib/nativeFileDialogs/simple_exec.h @@ -0,0 +1,214 @@ +// copied from: https://github.com/wheybags/simple_exec/blob/5a74c507c4ce1b2bb166177ead4cca7cfa23cb35/simple_exec.h + +// simple_exec.h, single header library to run external programs + retrieve their status code and output (unix only for now) +// +// do this: +// #define SIMPLE_EXEC_IMPLEMENTATION +// before you include this file in *one* C or C++ file to create the implementation. +// i.e. it should look like this: +// #define SIMPLE_EXEC_IMPLEMENTATION +// #include "simple_exec.h" + +#ifndef SIMPLE_EXEC_H +#define SIMPLE_EXEC_H + +int runCommand(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* command, ...); +int runCommandArray(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* const* allArgs); + +#endif // SIMPLE_EXEC_H + +#ifdef SIMPLE_EXEC_IMPLEMENTATION + +#include +#include +#include +#include +#include +#include +#include +#include + +#define release_assert(x) do { int __release_assert_tmp__ = (x); assert(__release_assert_tmp__); } while(0) + +enum PIPE_FILE_DESCRIPTORS +{ + READ_FD = 0, + WRITE_FD = 1 +}; + +enum RUN_COMMAND_ERROR +{ + COMMAND_RAN_OK = 0, + COMMAND_NOT_FOUND = 1 +}; + +int runCommandArray(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* const* allArgs) +{ + // adapted from: https://stackoverflow.com/a/479103 + + int bufferSize = 256; + char buffer[bufferSize + 1]; + + int dataReadFromChildDefaultSize = bufferSize * 5; + int dataReadFromChildSize = dataReadFromChildDefaultSize; + int dataReadFromChildUsed = 0; + char* dataReadFromChild = (char*)malloc(dataReadFromChildSize); + + + int parentToChild[2]; + release_assert(pipe(parentToChild) == 0); + + int childToParent[2]; + release_assert(pipe(childToParent) == 0); + + int errPipe[2]; + release_assert(pipe(errPipe) == 0); + + pid_t pid; + switch( pid = fork() ) + { + case -1: + { + release_assert(0 && "Fork failed"); + } + + case 0: // child + { + release_assert(dup2(parentToChild[READ_FD ], STDIN_FILENO ) != -1); + release_assert(dup2(childToParent[WRITE_FD], STDOUT_FILENO) != -1); + + if(includeStdErr) + { + release_assert(dup2(childToParent[WRITE_FD], STDERR_FILENO) != -1); + } + else + { + int devNull = open("/dev/null", O_WRONLY); + release_assert(dup2(devNull, STDERR_FILENO) != -1); + } + + // unused + release_assert(close(parentToChild[WRITE_FD]) == 0); + release_assert(close(childToParent[READ_FD ]) == 0); + release_assert(close(errPipe[READ_FD]) == 0); + + const char* command = allArgs[0]; + execvp(command, allArgs); + + char err = 1; + write(errPipe[WRITE_FD], &err, 1); + + close(errPipe[WRITE_FD]); + close(parentToChild[READ_FD]); + close(childToParent[WRITE_FD]); + + exit(0); + } + + + default: // parent + { + // unused + release_assert(close(parentToChild[READ_FD]) == 0); + release_assert(close(childToParent[WRITE_FD]) == 0); + release_assert(close(errPipe[WRITE_FD]) == 0); + + while(1) + { + ssize_t bytesRead = 0; + switch(bytesRead = read(childToParent[READ_FD], buffer, bufferSize)) + { + case 0: // End-of-File, or non-blocking read. + { + int status = 0; + release_assert(waitpid(pid, &status, 0) == pid); + + // done with these now + release_assert(close(parentToChild[WRITE_FD]) == 0); + release_assert(close(childToParent[READ_FD]) == 0); + + char errChar = 0; + read(errPipe[READ_FD], &errChar, 1); + close(errPipe[READ_FD]); + + if(errChar) + { + free(dataReadFromChild); + return COMMAND_NOT_FOUND; + } + + // free any un-needed memory with realloc + add a null terminator for convenience + dataReadFromChild = (char*)realloc(dataReadFromChild, dataReadFromChildUsed + 1); + dataReadFromChild[dataReadFromChildUsed] = '\0'; + + if(stdOut != NULL) + *stdOut = dataReadFromChild; + else + free(dataReadFromChild); + + if(stdOutByteCount != NULL) + *stdOutByteCount = dataReadFromChildUsed; + if(returnCode != NULL) + *returnCode = WEXITSTATUS(status); + + return COMMAND_RAN_OK; + } + case -1: + { + release_assert(0 && "read() failed"); + } + + default: + { + if(dataReadFromChildUsed + bytesRead + 1 >= dataReadFromChildSize) + { + dataReadFromChildSize += dataReadFromChildDefaultSize; + dataReadFromChild = (char*)realloc(dataReadFromChild, dataReadFromChildSize); + } + + memcpy(dataReadFromChild + dataReadFromChildUsed, buffer, bytesRead); + dataReadFromChildUsed += bytesRead; + break; + } + } + } + } + } +} + +int runCommand(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* command, ...) +{ + va_list vl; + va_start(vl, command); + + char* currArg = NULL; + + int allArgsInitialSize = 16; + int allArgsSize = allArgsInitialSize; + char** allArgs = (char**)malloc(sizeof(char*) * allArgsSize); + allArgs[0] = command; + + int i = 1; + do + { + currArg = va_arg(vl, char*); + allArgs[i] = currArg; + + i++; + + if(i >= allArgsSize) + { + allArgsSize += allArgsInitialSize; + allArgs = (char**)realloc(allArgs, sizeof(char*) * allArgsSize); + } + + } while(currArg != NULL); + + va_end(vl); + + int retval = runCommandArray(stdOut, stdOutByteCount, returnCode, includeStdErr, allArgs); + free(allArgs); + return retval; +} + +#endif //SIMPLE_EXEC_IMPLEMENTATION From 989662774e16964c01d56c5bfbd7df0fffa7a78f Mon Sep 17 00:00:00 2001 From: Azaezel Date: Tue, 1 Jan 2019 11:00:05 -0600 Subject: [PATCH 19/75] blacklist updated to filter out the new zenity backend when on windows. likely need to do the same on mac and potentially resolve conflicts on linux --- Tools/CMake/torque3d.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index 751c908d8..ec3eb110e 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -470,7 +470,7 @@ if(TORQUE_SDL) addLib(nativeFileDialogs) set(BLACKLIST "" ) else() - set(BLACKLIST "nfd_gtk.c" "nfd_cocoa.m" ) + set(BLACKLIST "nfd_gtk.c" "nfd_cocoa.m" "simple_exec.h" "nfd_zenity.c") addLib(nativeFileDialogs) set(BLACKLIST "" ) addLib(comctl32) From a5bdbd47a202507794db55039193df49bebdfed7 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Tue, 1 Jan 2019 13:11:46 -0600 Subject: [PATCH 20/75] corrects compilation errors on mac --- .../worldEditor/guiConvexShapeEditorCtrl.cpp | 4 +-- Engine/source/platformMac/macFileIO.mm | 28 ++++++++----------- Engine/source/platformMac/macMath.mm | 9 +++++- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp b/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp index ecae9f76d..24e6ea8c8 100644 --- a/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp +++ b/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp @@ -178,7 +178,7 @@ void GuiConvexEditorCtrl::setVisible( bool val ) AbstractClassRep* classRep = AbstractClassRep::findClassRep(mProxyObjects[i].targetObjectClass); if (!classRep) { - Con::errorf("WorldEditor::createPolyhedralObject - No such class: %s", mProxyObjects[i].targetObjectClass); + Con::errorf("WorldEditor::createPolyhedralObject - No such class: %s", mProxyObjects[i].targetObjectClass.c_str()); continue; } @@ -2513,4 +2513,4 @@ if (convex) DefineEngineMethod( GuiConvexEditorCtrl, splitSelectedFace, void, (), , "" ) { object->splitSelectedFace(); -} \ No newline at end of file +} diff --git a/Engine/source/platformMac/macFileIO.mm b/Engine/source/platformMac/macFileIO.mm index e4d182dc1..b2549e0f7 100644 --- a/Engine/source/platformMac/macFileIO.mm +++ b/Engine/source/platformMac/macFileIO.mm @@ -39,7 +39,7 @@ #import "platform/profiler.h" #import "cinterface/c_controlInterface.h" #import "core/volume.h" - +#include "console/engineAPI.h" //TODO: file io still needs some work... #define MAX_MAC_PATH_LONG 2048 @@ -992,25 +992,22 @@ bool Platform::fileTimeToString(FileTime * time, char * string, U32 strLen) { re //----------------------------------------------------------------------------- #if defined(TORQUE_DEBUG) -ConsoleFunction(testHasSubdir,void,2,2,"tests platform::hasSubDirectory") { - Con::printf("testing %s",(const char*)argv[1]); +DefineEngineFunction(testHasSubdir,void, (String _dir),,"tests platform::hasSubDirectory") { Platform::addExcludedDirectory(".svn"); - if(Platform::hasSubDirectory(argv[1])) + if(Platform::hasSubDirectory(_dir.c_str())) Con::printf(" has subdir"); else Con::printf(" does not have subdir"); } -ConsoleFunction(testDumpDirectories,void,4,4,"testDumpDirectories('path', int depth, bool noBasePath)") { +DefineEngineFunction(testDumpDirectories,void,(String _path, S32 _depth, bool _noBasePath),,"testDumpDirectories('path', int depth, bool noBasePath)") { Vector paths; - const S32 depth = dAtoi(argv[2]); - const bool noBasePath = dAtob(argv[3]); Platform::addExcludedDirectory(".svn"); - Platform::dumpDirectories(argv[1], paths, depth, noBasePath); + Platform::dumpDirectories(_path.c_str(), paths, _depth, _noBasePath); - Con::printf("Dumping directories starting from %s with depth %i", (const char*)argv[1],depth); + Con::printf("Dumping directories starting from %s with depth %i", _path.c_str(), _depth); for(Vector::iterator itr = paths.begin(); itr != paths.end(); itr++) { Con::printf(*itr); @@ -1018,14 +1015,13 @@ ConsoleFunction(testDumpDirectories,void,4,4,"testDumpDirectories('path', int de } -ConsoleFunction(testDumpPaths, void, 3, 3, "testDumpPaths('path', int depth)") +DefineEngineFunction(testDumpPaths, void, (String _path, S32 _depth),, "testDumpPaths('path', int depth)") { Vector files; - S32 depth = dAtoi(argv[2]); Platform::addExcludedDirectory(".svn"); - Platform::dumpPath(argv[1], files, depth); + Platform::dumpPath(_path.c_str(), files, _depth); for(Vector::iterator itr = files.begin(); itr != files.end(); itr++) { Con::printf("%s/%s",itr->pFullPath, itr->pFileName); @@ -1033,15 +1029,15 @@ ConsoleFunction(testDumpPaths, void, 3, 3, "testDumpPaths('path', int depth)") } //----------------------------------------------------------------------------- -ConsoleFunction(testFileTouch, bool , 2,2, "testFileTouch('path')") +DefineEngineFunction(testFileTouch, bool , (String _path),, "testFileTouch('path')") { - return dFileTouch(argv[1]); + return dFileTouch(_path.c_str()); } -ConsoleFunction(testGetFileTimes, bool, 2,2, "testGetFileTimes('path')") +DefineEngineFunction(testGetFileTimes, bool, (String _path),, "testGetFileTimes('path')") { FileTime create, modify; - bool ok = Platform::getFileTimes(argv[1], &create, &modify); + bool ok = Platform::getFileTimes(_path.c_str(), &create, &modify); Con::printf("%s Platform::getFileTimes %i, %i", ok ? "+OK" : "-FAIL", create, modify); return ok; } diff --git a/Engine/source/platformMac/macMath.mm b/Engine/source/platformMac/macMath.mm index c27375ee4..a59bf6609 100644 --- a/Engine/source/platformMac/macMath.mm +++ b/Engine/source/platformMac/macMath.mm @@ -24,6 +24,7 @@ #import "console/console.h" #import "math/mMath.h" #import "core/strings/stringFunctions.h" +#include "console/engineAPI.h" extern void mInstallLibrary_C(); extern void mInstallLibrary_Vec(); @@ -51,7 +52,13 @@ void Platform::setMathControlStateKnown() } //-------------------------------------- -ConsoleFunction( MathInit, void, 1, 10, "(DETECT|C|SSE)") +DefineEngineStringlyVariadicFunction( mathInit, void, 1, 10, "( ... )" + "@brief Install the math library with specified extensions.\n\n" + "Possible parameters are:\n\n" + " - 'DETECT' Autodetect math lib settings.\n\n" + " - 'C' Enable the C math routines. C routines are always enabled.\n\n" + " - 'SSE' Enable SSE math routines.\n\n" + "@ingroup Math") { U32 properties = CPU_PROP_C; // C entensions are always used From 8304168365138c4d70d1f2a0c0ae1accfa945554 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Tue, 1 Jan 2019 15:40:44 -0600 Subject: [PATCH 21/75] linux compilation, defaults to using the older gtk solution till more folks have a chance to beat up the zenity one. --- Tools/CMake/torque3d.cmake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index ec3eb110e..0bb20f6f1 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -204,6 +204,9 @@ mark_as_advanced(TORQUE_DEBUG_GFX_MODE) #option(DEBUG_SPEW "more debug" OFF) set(TORQUE_NO_DSO_GENERATION ON) +option(TORQUE_UseZenity "use the Zenity backend for NFD" OFF) +mark_as_advanced(TORQUE_UseZenity) + if(WIN32) # warning C4800: 'XXX' : forcing value to bool 'true' or 'false' (performance warning) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4800") @@ -460,7 +463,11 @@ if(TORQUE_SDL) # Add other flags to the compiler add_definitions(${GTK3_CFLAGS_OTHER}) - set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" ) + if(TORQUE_UseZenity) + set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" ) + else() + set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" "simple_exec.h" "nfd_zenity.c") + endif() addLib(nativeFileDialogs) set(BLACKLIST "" ) From 9d59caae35c5a47d1cfc1411376c58a82254a989 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Tue, 1 Jan 2019 15:41:59 -0600 Subject: [PATCH 22/75] corrects compilation errors on non-mac unix derivatives --- Engine/source/platformX86UNIX/x86UNIXConsole.cpp | 7 ++++--- Engine/source/platformX86UNIX/x86UNIXMath.cpp | 10 ++++++++-- .../source/platformX86UNIX/x86UNIXProcessControl.cpp | 7 ++----- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Engine/source/platformX86UNIX/x86UNIXConsole.cpp b/Engine/source/platformX86UNIX/x86UNIXConsole.cpp index 9dee9d263..88e17f38e 100644 --- a/Engine/source/platformX86UNIX/x86UNIXConsole.cpp +++ b/Engine/source/platformX86UNIX/x86UNIXConsole.cpp @@ -34,13 +34,14 @@ #include #include +#include "console/engineAPI.h" + StdConsole *stdConsole = NULL; -ConsoleFunction(enableWinConsole, void, 2, 2, "enableWinConsole(bool);") +DefineEngineFunction(enableWinConsole, void, (bool _enable),, "enableWinConsole(bool);") { - argc; if (stdConsole) - stdConsole->enable(dAtob(argv[1])); + stdConsole->enable(_enable); } void StdConsole::create() diff --git a/Engine/source/platformX86UNIX/x86UNIXMath.cpp b/Engine/source/platformX86UNIX/x86UNIXMath.cpp index 6d3d141c3..ada90c5f5 100644 --- a/Engine/source/platformX86UNIX/x86UNIXMath.cpp +++ b/Engine/source/platformX86UNIX/x86UNIXMath.cpp @@ -24,7 +24,7 @@ #include "console/console.h" #include "math/mMath.h" #include "core/strings/stringFunctions.h" - +#include "console/engineAPI.h" extern void mInstallLibrary_C(); extern void mInstallLibrary_ASM(); @@ -35,7 +35,13 @@ extern void mInstall_Library_SSE(); //-------------------------------------- -ConsoleFunction( MathInit, void, 1, 10, "(detect|C|FPU|MMX|3DNOW|SSE|...)") +DefineEngineStringlyVariadicFunction( mathInit, void, 1, 10, "( ... )" + "@brief Install the math library with specified extensions.\n\n" + "Possible parameters are:\n\n" + " - 'DETECT' Autodetect math lib settings.\n\n" + " - 'C' Enable the C math routines. C routines are always enabled.\n\n" + " - 'SSE' Enable SSE math routines.\n\n" + "@ingroup Math") { U32 properties = CPU_PROP_C; // C entensions are always used diff --git a/Engine/source/platformX86UNIX/x86UNIXProcessControl.cpp b/Engine/source/platformX86UNIX/x86UNIXProcessControl.cpp index bf246d132..09c59af4d 100644 --- a/Engine/source/platformX86UNIX/x86UNIXProcessControl.cpp +++ b/Engine/source/platformX86UNIX/x86UNIXProcessControl.cpp @@ -29,7 +29,7 @@ #include #include #include - +#include "console/engineAPI.h" #ifndef TORQUE_DEDICATED #include #endif @@ -203,10 +203,7 @@ void Platform::outputDebugString(const char *string, ...) //----------------------------------------------------------------------------- // testing function -ConsoleFunction(debug_debugbreak, void, 1, 1, "debug_debugbreak()") -{ - Platform::debugBreak(); -} +//DefineEngineFunction(debug_debugbreak, void, () , , "debug_debugbreak();"); //----------------------------------------------------------------------------- void Platform::restartInstance() From 7695c56f0878947e5716a4891376b6aba9d72e83 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Wed, 2 Jan 2019 17:52:20 -0600 Subject: [PATCH 23/75] use the newer c_controlInterface file --- Engine/source/platformX86UNIX/x86UNIXFileio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/source/platformX86UNIX/x86UNIXFileio.cpp b/Engine/source/platformX86UNIX/x86UNIXFileio.cpp index 40f5fedae..ec74dcce8 100644 --- a/Engine/source/platformX86UNIX/x86UNIXFileio.cpp +++ b/Engine/source/platformX86UNIX/x86UNIXFileio.cpp @@ -55,7 +55,7 @@ #include "console/console.h" #include "core/strings/stringFunctions.h" #include "util/tempAlloc.h" - #include "cinterface/cinterface.h" + #import "cinterface/c_controlInterface.h" #include "core/volume.h" #if defined(__FreeBSD__) From e4206c4ae37f46c0f429f12b2f00731595f91ced Mon Sep 17 00:00:00 2001 From: Azaezel Date: Wed, 2 Jan 2019 17:53:17 -0600 Subject: [PATCH 24/75] no message --- Engine/source/platformX86UNIX/x86UNIXFileio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/source/platformX86UNIX/x86UNIXFileio.cpp b/Engine/source/platformX86UNIX/x86UNIXFileio.cpp index ec74dcce8..690bae1f0 100644 --- a/Engine/source/platformX86UNIX/x86UNIXFileio.cpp +++ b/Engine/source/platformX86UNIX/x86UNIXFileio.cpp @@ -55,7 +55,7 @@ #include "console/console.h" #include "core/strings/stringFunctions.h" #include "util/tempAlloc.h" - #import "cinterface/c_controlInterface.h" + #include "cinterface/c_controlInterface.h" #include "core/volume.h" #if defined(__FreeBSD__) From 95eb2fc626bc7b64b056b5ffa788614d635d70d1 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Sun, 6 Jan 2019 14:24:33 -0600 Subject: [PATCH 25/75] zenity backend file filter fix --- Tools/CMake/torque3d.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index 0bb20f6f1..37f1f4b52 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -464,7 +464,7 @@ if(TORQUE_SDL) add_definitions(${GTK3_CFLAGS_OTHER}) if(TORQUE_UseZenity) - set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" ) + set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" "nfd_gtk.c" ) else() set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" "simple_exec.h" "nfd_zenity.c") endif() From 831e9db5a57e29c1fc2dce1c589de8e8ef1cea66 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Sun, 6 Jan 2019 15:42:18 -0600 Subject: [PATCH 26/75] constant consistency creates continuums --- Tools/CMake/torque3d.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index 37f1f4b52..53d503c50 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -204,8 +204,8 @@ mark_as_advanced(TORQUE_DEBUG_GFX_MODE) #option(DEBUG_SPEW "more debug" OFF) set(TORQUE_NO_DSO_GENERATION ON) -option(TORQUE_UseZenity "use the Zenity backend for NFD" OFF) -mark_as_advanced(TORQUE_UseZenity) +option(TORQUE_USE_ZENITY "use the Zenity backend for NFD" OFF) +mark_as_advanced(TORQUE_USE_ZENITY) if(WIN32) # warning C4800: 'XXX' : forcing value to bool 'true' or 'false' (performance warning) @@ -463,7 +463,7 @@ if(TORQUE_SDL) # Add other flags to the compiler add_definitions(${GTK3_CFLAGS_OTHER}) - if(TORQUE_UseZenity) + if(TORQUE_USE_ZENITY) set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" "nfd_gtk.c" ) else() set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" "simple_exec.h" "nfd_zenity.c") From aebbb1e3d8790c2f1f6edfea17d6102e97754e3f Mon Sep 17 00:00:00 2001 From: Azaezel Date: Sun, 6 Jan 2019 15:50:19 -0600 Subject: [PATCH 27/75] tabspace --- Tools/CMake/torque3d.cmake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index 53d503c50..d827663f5 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -463,11 +463,11 @@ if(TORQUE_SDL) # Add other flags to the compiler add_definitions(${GTK3_CFLAGS_OTHER}) - if(TORQUE_USE_ZENITY) - set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" "nfd_gtk.c" ) - else() - set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" "simple_exec.h" "nfd_zenity.c") - endif() + if(TORQUE_USE_ZENITY) + set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" "nfd_gtk.c" ) + else() + set(BLACKLIST "nfd_win.cpp" "nfd_cocoa.m" "simple_exec.h" "nfd_zenity.c") + endif() addLib(nativeFileDialogs) set(BLACKLIST "" ) From 8d770c56099bbaaebc00b2e7ecc43c5aa2ad42e2 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Mon, 7 Jan 2019 06:22:24 -0600 Subject: [PATCH 28/75] afxRenderHighlightMgr: account for hardware skinning --- Engine/source/afx/afxRenderHighlightMgr.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Engine/source/afx/afxRenderHighlightMgr.cpp b/Engine/source/afx/afxRenderHighlightMgr.cpp index 28e875eb9..0727f9d9b 100644 --- a/Engine/source/afx/afxRenderHighlightMgr.cpp +++ b/Engine/source/afx/afxRenderHighlightMgr.cpp @@ -151,7 +151,13 @@ void afxRenderHighlightMgr::render( SceneRenderState *state ) matrixSet.setProjection(*passRI->projection); mat->setTransforms(matrixSet, state); - mat->setSceneInfo(state, sgData); + // Setup HW skinning transforms if applicable + if (mat->usesHardwareSkinning()) + { + mat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount); + } + + mat->setSceneInfo(state, sgData); mat->setBuffers(passRI->vertBuff, passRI->primBuff); if ( passRI->prim ) From d640eeb228dfe572796355b578abcbce8a33cec5 Mon Sep 17 00:00:00 2001 From: Brian Roberts Date: Mon, 7 Jan 2019 11:41:17 -0600 Subject: [PATCH 29/75] Update afxRenderHighlightMgr.cpp --- Engine/source/afx/afxRenderHighlightMgr.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Engine/source/afx/afxRenderHighlightMgr.cpp b/Engine/source/afx/afxRenderHighlightMgr.cpp index 0727f9d9b..22632b1ef 100644 --- a/Engine/source/afx/afxRenderHighlightMgr.cpp +++ b/Engine/source/afx/afxRenderHighlightMgr.cpp @@ -151,13 +151,13 @@ void afxRenderHighlightMgr::render( SceneRenderState *state ) matrixSet.setProjection(*passRI->projection); mat->setTransforms(matrixSet, state); - // Setup HW skinning transforms if applicable - if (mat->usesHardwareSkinning()) - { - mat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount); - } + // Setup HW skinning transforms if applicable + if (mat->usesHardwareSkinning()) + { + mat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount); + } - mat->setSceneInfo(state, sgData); + mat->setSceneInfo(state, sgData); mat->setBuffers(passRI->vertBuff, passRI->primBuff); if ( passRI->prim ) @@ -179,4 +179,4 @@ void afxRenderHighlightMgr::render( SceneRenderState *state ) // Make sure the effect is gonna render. getSelectionEffect()->setSkip( false ); -} \ No newline at end of file +} From e2348f3d98bc58f091d8764363f7f6660acb77c3 Mon Sep 17 00:00:00 2001 From: Marc Chapman Date: Tue, 8 Jan 2019 19:35:02 +0000 Subject: [PATCH 30/75] Add a .editorconfig file --- .editorconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..a4cf70872 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# https://editorconfig.org/ + +root = true + +[*] +tab_width = 3 +indent_style = space +indent_size = 3 + +insert_final_newline = true +trim_trailing_whitespace = true +end_of_line = lf +charset = utf-8 From c256ebdb5cde5d34665927b8d3af23dcec343bfc Mon Sep 17 00:00:00 2001 From: Glenn Smith Date: Thu, 10 Jan 2019 04:15:22 -0500 Subject: [PATCH 31/75] Fix Input::getKeyCode on software keyboard layouts Input::getAscii goes Torque keyCode -> SDL Scancode -> SDL Keycode -> SDL ascii key name Input::getKeycode used to be SDL ascii key name -> SDL Scancode -> Torque keyCode This mismatch made software keyboard layouts behave incorrectly in different places. For example, you would bind a key to an ActionMap and it would activate with a different button than specified. --- Engine/source/platformSDL/sdlInput.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/platformSDL/sdlInput.cpp b/Engine/source/platformSDL/sdlInput.cpp index eb9e3dd8e..99793609b 100644 --- a/Engine/source/platformSDL/sdlInput.cpp +++ b/Engine/source/platformSDL/sdlInput.cpp @@ -118,7 +118,7 @@ U16 Input::getKeyCode( U16 asciiCode ) char c[2]; c[0]= asciiCode; c[1] = NULL; - return KeyMapSDL::getTorqueScanCodeFromSDL( SDL_GetScancodeFromName( c ) ); + return KeyMapSDL::getTorqueScanCodeFromSDL( SDL_GetScancodeFromKey( SDL_GetKeyFromName(c) ) ); } //------------------------------------------------------------------------------ @@ -435,4 +435,4 @@ U32 KeyMapSDL::getSDLScanCodeFromTorque(U32 torque) buildScanCodeArray(); return T3D_SDL[torque]; -} \ No newline at end of file +} From 2739d8713a3f39b01da1852137c527ebe1efc343 Mon Sep 17 00:00:00 2001 From: Glenn Smith Date: Thu, 10 Jan 2019 04:18:35 -0500 Subject: [PATCH 32/75] Really, github? From 30d236cfb22ca519a8a1f092cf42ab1fbf6f1e02 Mon Sep 17 00:00:00 2001 From: troido Date: Tue, 8 Jan 2019 14:12:25 +0100 Subject: [PATCH 33/75] travis test whether compilation works on mac and linux This checks both gcc and clang on linux, but only clang on mac Becuse there are so many debug warnings they are supressed in a very hacky way: Make is run first with error output ignored. Then an incremental build is run which has the error output, but will only build the files that errored the first time (and will error again). If anyone knows a better way to ignore the warnings that would be great. --- .travis.yml | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8e5970686..72177bad3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,42 @@ language: cpp -compiler: - - clang - - gcc + +dist: xenial + +matrix: + include: + - os: osx + compiler: clang + env: if CXXFLAGS="-fgnu-inline-asm -fasm-blocks" + - os: linux + compiler: gcc + - os: linux + compiler: clang + +addons: + apt: + packages: + - build-essential + - nasm + - libogg-dev + - libxft-dev + - libx11-dev + - libxxf86vm-dev + - libopenal-dev + - libfreetype6-dev + - libxcursor-dev + - libxinerama-dev + - libxi-dev + - libxrandr-dev + - libxss-dev + - libglu1-mesa-dev + - libgtk-3-dev + +script: + - mkdir -p My\ Projects/TestProject/buildFiles/travis/ + - cd My\ Projects/TestProject/buildFiles/travis/ + - cmake ../../../.. -DTORQUE_APP_NAME=TestProject -DCMAKE_BUILD_TYPE=Debug + - make 2>/dev/null # Do the actual build, but ignore all the warnings + - make # build again. This time all output is printed but the warnings that happened earlier do not happen again + - make install + - cd ../../game/ + - ls From 9291bc610599521c17c1afbc114c68041acb7b52 Mon Sep 17 00:00:00 2001 From: Marc Chapman Date: Thu, 10 Jan 2019 21:31:17 +0000 Subject: [PATCH 34/75] Sqlite Console refactor, also rename param to make tooltip function more helpful --- Engine/source/console/engineAPI.h | 2 +- Engine/source/sqlite/SQLiteObject.cpp | 244 +++++++++++++------------- 2 files changed, 125 insertions(+), 121 deletions(-) diff --git a/Engine/source/console/engineAPI.h b/Engine/source/console/engineAPI.h index 5fa20a82c..78a469522 100644 --- a/Engine/source/console/engineAPI.h +++ b/Engine/source/console/engineAPI.h @@ -836,7 +836,7 @@ public: /// Define a call-in point for calling into the engine. Unlike with DefineEngineFunction, the statically /// callable function will be confined to the namespace of the given class. /// -/// @param name The name of the C++ class (or a registered export scope). +/// @param classname The name of the C++ class (or a registered export scope). /// @param name The name of the method as it should be seen by the control layer. /// @param returnType The value type returned to the control layer. /// @param args The argument list as it would appear on the function definition diff --git a/Engine/source/sqlite/SQLiteObject.cpp b/Engine/source/sqlite/SQLiteObject.cpp index 4cba76720..7153e8740 100644 --- a/Engine/source/sqlite/SQLiteObject.cpp +++ b/Engine/source/sqlite/SQLiteObject.cpp @@ -519,30 +519,33 @@ void SQLiteObject::escapeSingleQuotes(const char* source, char *dest) // calls the C++ class function. // FIX: change all these to DefineEngineMethod! -ConsoleMethod(SQLiteObject, openDatabase, bool, 3, 3, "(const char* filename) Opens the database specifed by filename. Returns true or false.") +DefineEngineMethod(SQLiteObject, openDatabase, bool, (const char* filename),, "(const char* filename) Opens the database specifed by filename. Returns true or false.") { - return object->OpenDatabase(argv[2]); + return object->OpenDatabase(filename); } -DefineEngineMethod(SQLiteObject, loadOrSaveDb, bool, (const char* filename, bool isSave), , +DefineEngineMethod(SQLiteObject, loadOrSaveDb, bool, (const char* filename, bool isSave),, "Loads or saves a cached database from the disk db specifed by filename. Second argument determines loading (false) or saving (true). Returns true or false.") { return object->loadOrSaveDb(filename, isSave); } -ConsoleMethod(SQLiteObject, closeDatabase, void, 2, 2, "Closes the active database.") +DefineEngineMethod(SQLiteObject, closeDatabase, void, (),, "Closes the active database.") { object->CloseDatabase(); } -ConsoleMethod(SQLiteObject, query, S32, 4, 0, "(const char* sql, S32 mode) Performs an SQL query on the open database and returns an identifier to a valid result set. mode is currently unused, and is reserved for future use.") + + +DefineEngineStringlyVariadicMethod(SQLiteObject, query, S32, 1, 5, + "(const char* sql, S32 mode) Performs an SQL query on the open database and returns an identifier to a valid result set. mode is currently unused, and is reserved for future use.") { S32 iCount; S32 iIndex, iLen, iNewIndex, iArg, iArgLen, i; char* szNew; if (argc == 4) - return object->ExecuteSQL(argv[2]); + return object->ExecuteSQL(argv[1]); else if (argc > 4) { // Support for printf type querys, as per Ben Garney's suggestion @@ -552,10 +555,10 @@ ConsoleMethod(SQLiteObject, query, S32, 4, 0, "(const char* sql, S32 mode) Perfo // scan the query and count the question marks iCount = 0; - iLen = dStrlen(argv[2]); + iLen = dStrlen(argv[1]); for (iIndex = 0; iIndex < iLen; iIndex++) { - if (argv[2][iIndex] == '?') + if (argv[1][iIndex] == '?') iCount++; } @@ -567,7 +570,7 @@ ConsoleMethod(SQLiteObject, query, S32, 4, 0, "(const char* sql, S32 mode) Perfo // so now we need to calc the length of the new query string. This is easily achieved. // We simply take our base string length, subtract the question marks, then add in // the number of total characters used by our arguments. - iLen = dStrlen(argv[2]) - iCount; + iLen = dStrlen(argv[1]) - iCount; for (iIndex = 1; iIndex <= iCount; iIndex++) { iLen = iLen + dStrlen(argv[iIndex + 3]); @@ -576,12 +579,12 @@ ConsoleMethod(SQLiteObject, query, S32, 4, 0, "(const char* sql, S32 mode) Perfo szNew = new char[iLen]; // now we need to replace all the question marks with the actual arguments - iLen = dStrlen(argv[2]); + iLen = dStrlen(argv[1]); iNewIndex = 0; iArg = 1; for (iIndex = 0; iIndex <= iLen; iIndex++) { - if (argv[2][iIndex] == '?') + if (argv[1][iIndex] == '?') { // ok we need to replace this question mark with the actual argument // and iterate our pointers and everything as needed. This is no doubt @@ -600,79 +603,79 @@ ConsoleMethod(SQLiteObject, query, S32, 4, 0, "(const char* sql, S32 mode) Perfo } else - szNew[iNewIndex] = argv[2][iIndex]; + szNew[iNewIndex] = argv[1][iIndex]; iNewIndex++; } } else return 0; // incorrect number of question marks vs arguments - Con::printf("Old SQL: %s\nNew SQL: %s", argv[2].getStringValue(), szNew); + Con::printf("Old SQL: %s\nNew SQL: %s", argv[1].getStringValue(), szNew); return object->ExecuteSQL(szNew); } return 0; } -ConsoleMethod(SQLiteObject, clearResult, void, 3, 3, "(S32 resultSet) Clears memory used by the specified result set, and deletes the result set.") +DefineEngineMethod(SQLiteObject, clearResult, void, (S32 resultSet),, "(S32 resultSet) Clears memory used by the specified result set, and deletes the result set.") { - object->ClearResultSet(dAtoi(argv[2])); + object->ClearResultSet(resultSet); } -ConsoleMethod(SQLiteObject, nextRow, void, 3, 3, "(S32 resultSet) Moves the result set's row pointer to the next row.") +DefineEngineMethod(SQLiteObject, nextRow, void, (S32 resultSet),, "(S32 resultSet) Moves the result set's row pointer to the next row.") { sqlite_resultset* pResultSet; - pResultSet = object->GetResultSet(dAtoi(argv[2])); + pResultSet = object->GetResultSet(resultSet); if (pResultSet) { pResultSet->iCurrentRow++; } } -ConsoleMethod(SQLiteObject, previousRow, void, 3, 3, "(S32 resultSet) Moves the result set's row pointer to the previous row") +DefineEngineMethod(SQLiteObject, previousRow, void, (S32 resultSet),, "(S32 resultSet) Moves the result set's row pointer to the previous row") { sqlite_resultset* pResultSet; - pResultSet = object->GetResultSet(dAtoi(argv[2])); + pResultSet = object->GetResultSet(resultSet); if (pResultSet) { pResultSet->iCurrentRow--; } } -ConsoleMethod(SQLiteObject, firstRow, void, 3, 3, "(S32 resultSet) Moves the result set's row pointer to the very first row in the result set.") +DefineEngineMethod(SQLiteObject, firstRow, void, (S32 resultSet),, "(S32 resultSet) Moves the result set's row pointer to the very first row in the result set.") { sqlite_resultset* pResultSet; - pResultSet = object->GetResultSet(dAtoi(argv[2])); + pResultSet = object->GetResultSet(resultSet); if (pResultSet) { pResultSet->iCurrentRow = 0; } } -ConsoleMethod(SQLiteObject, lastRow, void, 3, 3, "(S32 resultSet) Moves the result set's row pointer to the very last row in the result set.") +DefineEngineMethod(SQLiteObject, lastRow, void, (S32 resultSet),, "(S32 resultSet) Moves the result set's row pointer to the very last row in the result set.") { sqlite_resultset* pResultSet; - pResultSet = object->GetResultSet(dAtoi(argv[2])); + pResultSet = object->GetResultSet(resultSet); if (pResultSet) { pResultSet->iCurrentRow = pResultSet->iNumRows - 1; } } -ConsoleMethod(SQLiteObject, setRow, void, 4, 4, "(S32 resultSet S32 row) Moves the result set's row pointer to the row specified. Row indices start at 1 not 0.") +DefineEngineMethod(SQLiteObject, setRow, void, (S32 resultSet, S32 row),, "(S32 resultSet S32 row) Moves the result set's row pointer to the row specified. Row indices start at 1 not 0.") { sqlite_resultset* pResultSet; - pResultSet = object->GetResultSet(dAtoi(argv[2])); + pResultSet = object->GetResultSet(resultSet); if (pResultSet) { - pResultSet->iCurrentRow = dAtoi(argv[3]) - 1; + pResultSet->iCurrentRow = row - 1; } } -ConsoleMethod(SQLiteObject, getRow, S32, 3, 3, "(S32 resultSet) Returns what row the result set's row pointer is currently on.") +DefineEngineMethod(SQLiteObject, getRow, S32, (S32 resultSet),, "(S32 resultSet) Returns what row the result set's row pointer is currently on.") { sqlite_resultset* pResultSet; - pResultSet = object->GetResultSet(dAtoi(argv[2])); + pResultSet = object->GetResultSet(resultSet); if (pResultSet) { return pResultSet->iCurrentRow + 1; @@ -681,10 +684,10 @@ ConsoleMethod(SQLiteObject, getRow, S32, 3, 3, "(S32 resultSet) Returns what row return 0; } -ConsoleMethod(SQLiteObject, numRows, S32, 3, 3, "(S32 resultSet) Returns the number of rows in the result set.") +DefineEngineMethod(SQLiteObject, numRows, S32, (S32 resultSet),, "(S32 resultSet) Returns the number of rows in the result set.") { sqlite_resultset* pResultSet; - pResultSet = object->GetResultSet(dAtoi(argv[2])); + pResultSet = object->GetResultSet(resultSet); if (pResultSet) { return pResultSet->iNumRows; @@ -693,10 +696,10 @@ ConsoleMethod(SQLiteObject, numRows, S32, 3, 3, "(S32 resultSet) Returns the num return 0; } -ConsoleMethod(SQLiteObject, numColumns, S32, 3, 3, "(S32 resultSet) Returns the number of columns in the result set.") +DefineEngineMethod(SQLiteObject, numColumns, S32, (S32 resultSet),, "(S32 resultSet) Returns the number of columns in the result set.") { sqlite_resultset* pResultSet; - pResultSet = object->GetResultSet(dAtoi(argv[2])); + pResultSet = object->GetResultSet(resultSet); if (pResultSet) { return pResultSet->iNumCols; @@ -705,33 +708,33 @@ ConsoleMethod(SQLiteObject, numColumns, S32, 3, 3, "(S32 resultSet) Returns the return 0; } -ConsoleMethod(SQLiteObject, endOfResult, bool, 3, 3, "(S32 resultSet) Checks to see if the internal pointer for the specified result set is at the end, indicating there are no more rows left to read.") +DefineEngineMethod(SQLiteObject, endOfResult, bool, (S32 resultSet),, "(S32 resultSet) Checks to see if the internal pointer for the specified result set is at the end, indicating there are no more rows left to read.") { - return object->EndOfResult(dAtoi(argv[2])); + return object->EndOfResult(resultSet); } -ConsoleMethod(SQLiteObject, EOR, bool, 3, 3, "(S32 resultSet) Same as endOfResult().") +DefineEngineMethod(SQLiteObject, EOR, bool, (S32 resultSet),, "(S32 resultSet) Same as endOfResult().") { - return object->EndOfResult(dAtoi(argv[2])); + return object->EndOfResult(resultSet); } -ConsoleMethod(SQLiteObject, EOF, bool, 3, 3, "(S32 resultSet) Same as endOfResult().") +DefineEngineMethod(SQLiteObject, EOFile, bool, (S32 resultSet),, "(S32 resultSet) Same as endOfResult().") { - return object->EndOfResult(dAtoi(argv[2])); + return object->EndOfResult(resultSet); } -ConsoleMethod(SQLiteObject, getColumnIndex, S32, 4, 4, "(resultSet columnName) Looks up the specified column name in the specified result set, and returns the columns index number. A return value of 0 indicates the lookup failed for some reason (usually this indicates you specified a column name that doesn't exist or is spelled wrong).") +DefineEngineMethod(SQLiteObject, getColumnIndex, S32, (S32 resultSet, String columnName),, "(resultSet columnName) Looks up the specified column name in the specified result set, and returns the columns index number. A return value of 0 indicates the lookup failed for some reason (usually this indicates you specified a column name that doesn't exist or is spelled wrong).") { - return object->GetColumnIndex(dAtoi(argv[2]), argv[3]); + return object->GetColumnIndex(resultSet, columnName); } -ConsoleMethod(SQLiteObject, getColumnName, const char *, 4, 4, "(resultSet columnIndex) Looks up the specified column index in the specified result set, and returns the column's name. A return value of an empty string indicates the lookup failed for some reason (usually this indicates you specified a column index that is invalid or exceeds the number of columns in the result set). Columns are index starting with 1 not 0") +DefineEngineMethod(SQLiteObject, getColumnName, const char *, (S32 resultSet, S32 columnIndex), , "(resultSet columnIndex) Looks up the specified column index in the specified result set, and returns the column's name. A return value of an empty string indicates the lookup failed for some reason (usually this indicates you specified a column index that is invalid or exceeds the number of columns in the result set). Columns are index starting with 1 not 0") { sqlite_resultset* pResultSet; sqlite_resultrow* pRow; S32 iColumn; - pResultSet = object->GetResultSet(dAtoi(argv[2])); + pResultSet = object->GetResultSet(resultSet); if (pResultSet) { pRow = pResultSet->vRows[pResultSet->iCurrentRow]; @@ -739,7 +742,7 @@ ConsoleMethod(SQLiteObject, getColumnName, const char *, 4, 4, "(resultSet colum return ""; // We assume they specified column by index. If they know the column name they wouldn't be calling this function :) - iColumn = dAtoi(argv[3]); + iColumn = columnIndex; if (iColumn == 0) return ""; // column indices start at 1, not 0 @@ -753,90 +756,91 @@ ConsoleMethod(SQLiteObject, getColumnName, const char *, 4, 4, "(resultSet colum return ""; } -ConsoleMethod(SQLiteObject, getColumn, const char *, 4, 4, "(resultSet column) Returns the value of the specified column (Column can be specified by name or index) in the current row of the specified result set. If the call fails, the returned string will indicate the error.") +DefineEngineStringlyVariadicMethod(SQLiteObject, getColumn, const char *, 4, 4, "(resultSet column) Returns the value of the specified column (Column can be specified by name or index) in the current row of the specified result set. If the call fails, the returned string will indicate the error.") { - sqlite_resultset* pResultSet; - sqlite_resultrow* pRow; - S32 iColumn; + sqlite_resultset* pResultSet; + sqlite_resultrow* pRow; + S32 iColumn; - pResultSet = object->GetResultSet(dAtoi(argv[2])); - if (pResultSet) - { - if (pResultSet->vRows.size() == 0) - return "NULL"; + pResultSet = object->GetResultSet(dAtoi(argv[2])); + if (pResultSet) + { + if (pResultSet->vRows.size() == 0) + return "NULL"; - pRow = pResultSet->vRows[pResultSet->iCurrentRow]; - if (!pRow) - return "invalid_row"; + pRow = pResultSet->vRows[pResultSet->iCurrentRow]; + if (!pRow) + return "invalid_row"; - // Is column specified by a name or an index? - iColumn = dAtoi(argv[3]); - if (iColumn == 0) - { - // column was specified by a name - iColumn = object->GetColumnIndex(dAtoi(argv[2]), argv[3]); - // if this is still 0 then we have some error - if (iColumn == 0) - return "invalid_column"; - } + // Is column specified by a name or an index? + iColumn = dAtoi(argv[3]); + if (iColumn == 0) + { + // column was specified by a name + iColumn = object->GetColumnIndex(dAtoi(argv[2]), argv[3]); + // if this is still 0 then we have some error + if (iColumn == 0) + return "invalid_column"; + } - // We temporarily padded the index in GetColumnIndex() so we could return a - // 0 for error. So now we need to drop it back down. - iColumn--; + // We temporarily padded the index in GetColumnIndex() so we could return a + // 0 for error. So now we need to drop it back down. + iColumn--; - // now we should have an index for our column data - if (pRow->vColumnValues[iColumn]) - return pRow->vColumnValues[iColumn]; - else - return "NULL"; - } - else - return "invalid_result_set"; + // now we should have an index for our column data + if (pRow->vColumnValues[iColumn]) + return pRow->vColumnValues[iColumn]; + else + return "NULL"; + } + else + return "invalid_result_set"; } -ConsoleMethod(SQLiteObject, getColumnNumeric, F32, 4, 4, "(resultSet column) Returns the value of the specified column (Column can be specified by name or index) in the current row of the specified result set. If the call fails, the returned string will indicate the error.") +DefineEngineStringlyVariadicMethod(SQLiteObject, getColumnNumeric, F32, 4, 4, "(resultSet column) Returns the value of the specified column (Column can be specified by name or index) in the current row of the specified result set. If the call fails, the returned string will indicate the error.") { - sqlite_resultset* pResultSet; - sqlite_resultrow* pRow; - S32 iColumn; + sqlite_resultset* pResultSet; + sqlite_resultrow* pRow; + S32 iColumn; - pResultSet = object->GetResultSet(dAtoi(argv[2])); - if (pResultSet) - { + pResultSet = object->GetResultSet(dAtoi(argv[2])); + if (pResultSet) + { - if (pResultSet->vRows.size() == 0) - return -1; + if (pResultSet->vRows.size() == 0) + return -1; - pRow = pResultSet->vRows[pResultSet->iCurrentRow]; - if (!pRow) - return -1;//"invalid_row"; + pRow = pResultSet->vRows[pResultSet->iCurrentRow]; + if (!pRow) + return -1;//"invalid_row"; - // Is column specified by a name or an index? - iColumn = dAtoi(argv[3]); - if (iColumn == 0) - { - // column was specified by a name - iColumn = object->GetColumnIndex(dAtoi(argv[2]), argv[3]); - // if this is still 0 then we have some error - if (iColumn == 0) - return -1;//"invalid_column"; - } + // Is column specified by a name or an index? + iColumn = dAtoi(argv[3]); + if (iColumn == 0) + { + // column was specified by a name + iColumn = object->GetColumnIndex(dAtoi(argv[2]), argv[3]); + // if this is still 0 then we have some error + if (iColumn == 0) + return -1;//"invalid_column"; + } - // We temporarily padded the index in GetColumnIndex() so we could return a - // 0 for error. So now we need to drop it back down. - iColumn--; + // We temporarily padded the index in GetColumnIndex() so we could return a + // 0 for error. So now we need to drop it back down. + iColumn--; - // now we should have an index for our column data - if (pRow->vColumnValues[iColumn]) - return dAtof(pRow->vColumnValues[iColumn]); - else - return 0; - } - else - return -1;//"invalid_result_set"; + // now we should have an index for our column data + if (pRow->vColumnValues[iColumn]) + return dAtof(pRow->vColumnValues[iColumn]); + else + return 0; + } + else + return -1;//"invalid_result_set"; } -ConsoleMethod(SQLiteObject, escapeString, const char *, 3, 3, "(string) Escapes the given string, making it safer to pass into a query.") + +DefineEngineMethod(SQLiteObject, escapeString, const char *, (String string),, "(string) Escapes the given string, making it safer to pass into a query.") { // essentially what we need to do here is scan the string for any occurrences of: ', ", and \ // and prepend them with a slash: \', \", \\ @@ -848,14 +852,14 @@ ConsoleMethod(SQLiteObject, escapeString, const char *, 3, 3, "(string) Escapes char* szNew; iCount = 0; - iLen = dStrlen(argv[2]); + iLen = dStrlen(string); for (iIndex = 0; iIndex < iLen; iIndex++) { - if (argv[2][iIndex] == '\'') + if (string[iIndex] == '\'') iCount++; - else if (argv[2][iIndex] == '\"') + else if (string[iIndex] == '\"') iCount++; - else if (argv[2][iIndex] == '\\') + else if (string[iIndex] == '\\') iCount++; } @@ -864,26 +868,26 @@ ConsoleMethod(SQLiteObject, escapeString, const char *, 3, 3, "(string) Escapes iNewIndex = 0; for (iIndex = 0; iIndex <= iLen; iIndex++) { - if (argv[2][iIndex] == '\'') + if (string[iIndex] == '\'') { szNew[iNewIndex] = '\\'; iNewIndex++; szNew[iNewIndex] = '\''; } - else if (argv[2][iIndex] == '\"') + else if (string[iIndex] == '\"') { szNew[iNewIndex] = '\\'; iNewIndex++; szNew[iNewIndex] = '\"'; } - else if (argv[2][iIndex] == '\\') + else if (string[iIndex] == '\\') { szNew[iNewIndex] = '\\'; iNewIndex++; szNew[iNewIndex] = '\\'; } else - szNew[iNewIndex] = argv[2][iIndex]; + szNew[iNewIndex] = string[iIndex]; iNewIndex++; } @@ -894,12 +898,12 @@ ConsoleMethod(SQLiteObject, escapeString, const char *, 3, 3, "(string) Escapes } -ConsoleMethod(SQLiteObject, numResultSets, S32, 2, 2, "numResultSets()") +DefineEngineMethod(SQLiteObject, numResultSets, S32, (),, "numResultSets()") { return object->numResultSets(); } -ConsoleMethod(SQLiteObject, getLastRowId, S32, 2, 2, "getLastRowId()") +DefineEngineMethod(SQLiteObject, getLastRowId, S32, (), , "getLastRowId()") { return object->getLastRowId(); } \ No newline at end of file From 2f3b3e87c26d4488320b6156c4d991debf75f1fa Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Thu, 10 Jan 2019 17:44:30 -0500 Subject: [PATCH 35/75] Updated to work without keyboard event refactor. --- Engine/source/gui/utility/guiInputCtrl.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Engine/source/gui/utility/guiInputCtrl.cpp b/Engine/source/gui/utility/guiInputCtrl.cpp index ba4eec0aa..907d861a9 100644 --- a/Engine/source/gui/utility/guiInputCtrl.cpp +++ b/Engine/source/gui/utility/guiInputCtrl.cpp @@ -166,8 +166,11 @@ bool GuiInputCtrl::onInputEvent( const InputEventInfo &event ) if (!mSendModifierEvents) return false; - const char* actionString = INPUTMGR->findKeyboardMapDescFromCode(event.objInst); - onInputEvent_callback(deviceString, actionString, 1); + char keyString[32]; + if (!ActionMap::getKeyString(event.objInst, keyString)) + return false; + + onInputEvent_callback(deviceString, keyString, 1); } else { From bc8796773c80203bf141f9075b80f006bbd0bdce Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Thu, 10 Jan 2019 20:06:54 -0500 Subject: [PATCH 36/75] Adds event codes for 2 POV hat masks, 2 trackballs and the guide button. --- Engine/source/platform/input/event.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Engine/source/platform/input/event.h b/Engine/source/platform/input/event.h index 1c6d1f1dc..a63d0d62c 100644 --- a/Engine/source/platform/input/event.h +++ b/Engine/source/platform/input/event.h @@ -249,6 +249,14 @@ enum InputObjectInstancesEnum SI_DPOV2 = 0x215, SI_LPOV2 = 0x216, SI_RPOV2 = 0x217, + SI_POVMASK = 0x218, + SI_POVMASK2 = 0x219, + + /// Trackball event codes. + SI_XBALL = 0x21A, + SI_YBALL = 0x21B, + SI_XBALL2 = 0x21C, + SI_YBALL2 = 0x21D, XI_CONNECT = 0x300, XI_THUMBLX = 0x301, @@ -262,7 +270,7 @@ enum InputObjectInstancesEnum XI_DPAD_DOWN = 0x308, XI_DPAD_LEFT = 0x309, XI_DPAD_RIGHT = 0x310,*/ - + XI_START = 0x311, XI_BACK = 0x312, XI_LEFT_THUMB = 0x313, @@ -273,7 +281,8 @@ enum InputObjectInstancesEnum XI_A = 0x317, XI_B = 0x318, XI_X = 0x319, - XI_Y = 0x320, + XI_Y = 0x31A, + XI_GUIDE = 0x31B, INPUT_DEVICE_PLUGIN_CODES_START = 0x400, }; From 4fd6dfeaf06ac3a1c5f53fa075ec9f3f8a87f6a3 Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Thu, 10 Jan 2019 20:09:05 -0500 Subject: [PATCH 37/75] Adds support for SDL joystick and game controllers. --- Engine/source/platformSDL/sdlInput.cpp | 47 +- Engine/source/platformSDL/sdlInputManager.cpp | 1381 +++++++++++++++++ Engine/source/platformSDL/sdlInputManager.h | 114 ++ .../source/windowManager/sdl/sdlWindowMgr.cpp | 19 +- 4 files changed, 1530 insertions(+), 31 deletions(-) create mode 100644 Engine/source/platformSDL/sdlInputManager.cpp create mode 100644 Engine/source/platformSDL/sdlInputManager.h diff --git a/Engine/source/platformSDL/sdlInput.cpp b/Engine/source/platformSDL/sdlInput.cpp index eb9e3dd8e..cbb6985f6 100644 --- a/Engine/source/platformSDL/sdlInput.cpp +++ b/Engine/source/platformSDL/sdlInput.cpp @@ -27,15 +27,11 @@ #include "sdlInput.h" #include "platform/platformInput.h" +#include "sdlInputManager.h" #include "SDL.h" -#ifdef LOG_INPUT -#include -#include -#endif - // Static class variables: -InputManager* Input::smManager; +InputManager* Input::smManager = NULL; bool Input::smActive; U8 Input::smModifierKeys; bool Input::smLastKeyboardActivated; @@ -43,10 +39,6 @@ bool Input::smLastMouseActivated; bool Input::smLastJoystickActivated; InputEvent Input::smInputEvent; -#ifdef LOG_INPUT -static HANDLE gInputLog; -#endif - static void fillAsciiTable() {} //------------------------------------------------------------------------------ @@ -91,24 +83,17 @@ void Input::init() fillAsciiTable(); Con::printf( "" ); + smManager = new SDLInputManager; + if (smManager) + { + SDLInputManager::init(); + } + // Set ourselves to participate in per-frame processing. Process::notify(Input::process, PROCESS_INPUT_ORDER); } -//------------------------------------------------------------------------------ -DefineEngineFunction(isJoystickDetected, bool, (),, "") -{ - return(SDL_NumJoysticks() > 0); -} - -//------------------------------------------------------------------------------ -DefineEngineFunction(getJoystickAxes, const char*, (const char* instance), , "") -{ - // TODO SDL - return(""); -} - //------------------------------------------------------------------------------ U16 Input::getKeyCode( U16 asciiCode ) { @@ -159,6 +144,13 @@ void Input::destroy() SDL_QuitSubSystem( SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER ); + if (smManager) + { + if (smManager->isEnabled()) + smManager->disable(); + delete smManager; + smManager = NULL; + } } //------------------------------------------------------------------------------ @@ -186,8 +178,8 @@ void Input::activate() //ImmReleaseContext( getWin32WindowHandle(), winState.imeHandle ); #endif - if ( !Con::getBoolVariable( "$enableDirectInput" ) ) - return; + if (smManager && !smManager->isEnabled()) + smManager->enable(); if ( smManager && smManager->isEnabled() && !smActive ) { @@ -199,7 +191,10 @@ void Input::activate() //------------------------------------------------------------------------------ void Input::deactivate() { - if ( smManager && smManager->isEnabled() && smActive ) + if (smManager && smManager->isEnabled()) + smManager->disable(); + + if (smActive) { smActive = false; Con::printf( "Input deactivated." ); diff --git a/Engine/source/platformSDL/sdlInputManager.cpp b/Engine/source/platformSDL/sdlInputManager.cpp new file mode 100644 index 000000000..5c5d5ec72 --- /dev/null +++ b/Engine/source/platformSDL/sdlInputManager.cpp @@ -0,0 +1,1381 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "console/console.h" +#include "console/consoleTypes.h" +#include "console/engineAPI.h" +#include "sim/actionMap.h" + +#include "sdlInputManager.h" + +typedef SDL_JoystickType SDLJoystickType; +DefineEnumType(SDLJoystickType); +ImplementEnumType(SDLJoystickType, + "The type of device connected.\n\n" + "@ingroup Input") +{ SDL_JOYSTICK_TYPE_UNKNOWN, "Unknown"}, +{ SDL_JOYSTICK_TYPE_GAMECONTROLLER, "Game Controller" }, +{ SDL_JOYSTICK_TYPE_WHEEL, "Wheel" }, +{ SDL_JOYSTICK_TYPE_ARCADE_STICK, "Arcade Stick" }, +{ SDL_JOYSTICK_TYPE_FLIGHT_STICK, "Flight Stick" }, +{ SDL_JOYSTICK_TYPE_DANCE_PAD, "Dance Pad" }, +{ SDL_JOYSTICK_TYPE_GUITAR, "Guitar" }, +{ SDL_JOYSTICK_TYPE_DRUM_KIT, "Drum Kit" }, +{ SDL_JOYSTICK_TYPE_ARCADE_PAD, "Arcade Pad" }, +{ SDL_JOYSTICK_TYPE_THROTTLE, "Throttle" }, +EndImplementEnumType; + +typedef SDL_JoystickPowerLevel SDLPowerEnum; +DefineEnumType(SDLPowerEnum); +ImplementEnumType(SDLPowerEnum, + "An enumeration of battery levels of a joystick.\n\n" + "@ingroup Input") +{ SDL_JOYSTICK_POWER_UNKNOWN, "Unknown" }, +{ SDL_JOYSTICK_POWER_EMPTY, "Empty" }, +{ SDL_JOYSTICK_POWER_LOW, "Low" }, +{ SDL_JOYSTICK_POWER_MEDIUM, "Medium" }, +{ SDL_JOYSTICK_POWER_FULL, "Full" }, +{ SDL_JOYSTICK_POWER_WIRED, "Wired" }, +{ SDL_JOYSTICK_POWER_MAX, "Max" }, +EndImplementEnumType; + +IMPLEMENT_STATIC_CLASS(SDLInputManager, , + "@brief Static class exposing the SDL_Joystick and SDL_GameController APIs to Torque Script.\n" + "SDLInputManager provides access to the functions of these APIs through static class " + "functions.These functions are not required to bind or process events.By setting " + "pref::Input::JoystickEnabled or pref::Input::sdlControllerEnabled to true, all connected " + "devices will automatically be opened.All of the joystick and controller events defined " + "in event.h can then be bound. For complete API documentation see the Joystick and Game " + "Controller section of https ://wiki.libsdl.org/APIByCategory#Input_Events.\n\n" + + "@tsexample\n" + "// Get the name and device type for all connected devices\n" + "%sdlDevices = SDLInputManager::numJoysticks();\n" + "for (%i = 0; %i < %sdlDevices; %i++)\n" + "{\n" + " %deviceName = SDLInputManager::JoystickNameForIndex(%i);\n" + " %deviceType = SDLInputManager::GetDeviceType(%i);\n" + "}\n" + "\n" + "// List all installed controller mappings\n" + "%numMappings = SDLInputManager::GameControllerNumMappings();\n" + "for (%i = 0; %i < %numMappings; %i++)\n" + " echo(SDLInputManager::GameControllerMappingForIndex(%i));\n" + "@endtsexample\n\n"); + +IMPLEMENT_GLOBAL_CALLBACK(onSDLDeviceConnected, void, (S32 sdlIndex, const char* deviceName, const char* deviceType), +(sdlIndex, deviceName, deviceType), +"Callback that occurs when an input device is connected to the system.\n\n" +"@param sdlIndex The index that will be used by sdl to refer to the device.\n" +"@param deviceName The name that the device reports. This will be the return " +"value of SDL_JoystickNameForIndex or SDL_GameControllerNameForIndex depending on the device type.\n" +"@param deviceType The type of device connected. See SDLInputManager::getDeviceType() " +"for possible string values.\n\n"); + +IMPLEMENT_GLOBAL_CALLBACK(onSDLDeviceDisconnected, void, (S32 sdlIndex), (sdlIndex), +"Callback that occurs when an input device is disconnected from the system.\n\n" +"@param sdlIndex The index of the device that was removed.\n"); + +//------------------------------------------------------------------------------ +// Static class variables: +bool SDLInputManager::smJoystickEnabled = true; +bool SDLInputManager::smJoystickSplitAxesLR = true; +bool SDLInputManager::smControllerEnabled = true; +bool SDLInputManager::smPOVButtonEvents = true; +bool SDLInputManager::smPOVMaskEvents = false; + +// Map SDL controller Axis to torque input event +// Commented text from map_StringForControllerAxis[] in SDL_gamecontroller.c +S32 SDLInputManager::map_EventForControllerAxis[] = { + SI_XAXIS, //"leftx", + SI_YAXIS, //"lefty", + SI_RXAXIS, //"rightx", + SI_RYAXIS, //"righty", + SI_ZAXIS, //"lefttrigger", + SI_RZAXIS, //"righttrigger", + -1 // NULL +}; + +// Map SDL controller button ID to torque input event +// Commented text from map_StringForControllerButton[] in SDL_gamecontroller.c +S32 SDLInputManager::map_EventForControllerButton[] = { + XI_A, //"a", + XI_B, //"b", + XI_X, //"x", + XI_Y, //"y", + XI_BACK, //"back", + XI_GUIDE, //"guide", + XI_START, //"start", + XI_LEFT_THUMB, //"leftstick", + XI_RIGHT_THUMB, //"rightstick", + XI_LEFT_SHOULDER, //"leftshoulder", + XI_RIGHT_SHOULDER, //"rightshoulder", + SI_UPOV, //"dpup", + SI_DPOV, //"dpdown", + SI_LPOV, //"dpleft", + SI_RPOV, //"dpright", + -1 // NULL +}; + +//------------------------------------------------------------------------------ +void SDLInputManager::joystickState::reset() +{ + sdlInstID = -1; + inputDevice = NULL; + numAxes = 0; + lastHatState[0] = 0; + lastHatState[1] = 0; +} + +//------------------------------------------------------------------------------ +SDLInputManager::SDLInputManager() +{ + mEnabled = true; + mJoystickActive = true; + + for (S32 i = 0; i < MaxJoysticks; ++i) + { + mJoysticks[i].reset(); + mJoysticks[i].torqueInstID = i; + } + + for (S32 i = 0; i < MaxControllers; ++i) + { + mControllers[i].sdlInstID = -1; + mControllers[i].torqueInstID = i; + mControllers[i].inputDevice = NULL; + } +} + +//------------------------------------------------------------------------------ +void SDLInputManager::init() +{ + Con::addVariable( "pref::Input::JoystickEnabled", TypeBool, &smJoystickEnabled, + "If true, Joystick devices will be automatically opened.\n\n" + "@ingroup Input"); + Con::addVariable("pref::Input::JoystickSplitAxesLR", TypeBool, &smJoystickSplitAxesLR, + "Split axis inputs on 4 axis joysticks. This has no effect on any other device.\n\n" + "4 Axis joysticks use IDs 0-3 which get mapped to xaxis, yaxis, zaxis and rxaxis. " + "When true, this will increment IDs 2 and 3 so the inputs map to xaxis, yaxis, rxaxis and ryaxis.\n" + "@ingroup Input"); + Con::addVariable("pref::Input::sdlControllerEnabled", TypeBool, &smControllerEnabled, + "If true, any Joystick device that SDL recognizes as a Game Controller will be automatically opened as a game controller.\n\n" + "@ingroup Input"); + Con::addVariable("pref::Input::JoystickPOVButtons", TypeBool, &smPOVButtonEvents, + "If true, the pov hat will be treated as 4 buttons and make/break events will be generated for " + "upov, dpov, lpov and rpov.\n" + "@ingroup Input"); + Con::addVariable("pref::Input::JoystickPOVMask", TypeBool, &smPOVMaskEvents, + "If true, the pov hat will be treated as a single input with a 4 bit mask value. The povmask " + "event will be generated with the current mask every time the mask value changes.\n" + "@ingroup Input"); + + // POV Hat mask bits + Con::setIntVariable("$SDLMask::HatUp", SDL_HAT_UP); + Con::setIntVariable("$SDLMask::HatRight", SDL_HAT_RIGHT); + Con::setIntVariable("$SDLMask::HatDown", SDL_HAT_DOWN); + Con::setIntVariable("$SDLMask::HatLeft", SDL_HAT_LEFT); +} + +//------------------------------------------------------------------------------ +bool SDLInputManager::enable() +{ + disable(); + + if (smControllerEnabled || smJoystickEnabled) + { + for (S32 i = 0; i < SDL_NumJoysticks(); ++i) + { + if (smControllerEnabled && SDL_IsGameController(i)) + openController(i, 0); + else if (smJoystickEnabled) + openJoystick(i, 0); + } + } + mEnabled = true; + return true; +} + +//------------------------------------------------------------------------------ +void SDLInputManager::disable() +{ + // Close any open devices + for (S32 i = 0; i < MaxControllers; ++i) + closeControllerByIndex(i); + for (S32 i = 0; i < MaxJoysticks; ++i) + closeJoystickByIndex(i); + + mEnabled = false; +} + +//------------------------------------------------------------------------------ +void SDLInputManager::process() +{ +} + +//------------------------------------------------------------------------------ +void SDLInputManager::processEvent(SDL_Event &evt) +{ + switch (evt.type) + { + case SDL_JOYAXISMOTION: + { + joystickState* torqueMapping; + if (mJoystickMap.isEmpty() || !mJoystickMap.find(evt.jaxis.which, torqueMapping)) + break; + // SDL axis value inputs are in (range: -32768 to 32767) + // Torque axis values are -1.0 to 1.0 + F32 value = ((F32)evt.jaxis.value) / (F32) (evt.jaxis.value > 0 ? SDL_JOYSTICK_AXIS_MAX : -SDL_JOYSTICK_AXIS_MIN); + S32 mapAxis = SI_XAXIS + evt.jaxis.axis; + if (evt.jaxis.axis > 1 && torqueMapping->numAxes == 4 && smJoystickSplitAxesLR) + mapAxis += 1; // On a 4 axis, we'll shift the second two so we use LX LY RX RY instead of LX LY LZ RX + buildInputEvent(JoystickDeviceType, torqueMapping->torqueInstID, SI_AXIS, mapAxis, SI_MOVE, value); + break; + } + + case SDL_JOYBALLMOTION: + { + joystickState* torqueMapping; + if (mJoystickMap.isEmpty() || !mJoystickMap.find(evt.jball.which, torqueMapping) || evt.jball.ball >= MaxBalls) + break; + if (evt.jball.xrel != 0) + buildInputEvent(JoystickDeviceType, torqueMapping->torqueInstID, SI_INT, evt.jball.ball ? SI_XBALL2 : SI_XBALL, SI_MOVE, (S32) evt.jball.xrel); + if (evt.jball.yrel != 0) + buildInputEvent(JoystickDeviceType, torqueMapping->torqueInstID, SI_INT, evt.jball.ball ? SI_YBALL2 : SI_YBALL, SI_MOVE, (S32) evt.jball.yrel); + break; + } + + case SDL_JOYHATMOTION: + { + joystickState* torqueMapping; + if (mJoystickMap.isEmpty() || !mJoystickMap.find(evt.jball.which, torqueMapping) || evt.jhat.hat >= MaxHats) + break; + if (torqueMapping->lastHatState[evt.jhat.hat] != evt.jhat.value) + { + buildHatEvents(JoystickDeviceType, torqueMapping->torqueInstID, torqueMapping->lastHatState[evt.jhat.hat], evt.jhat.value, evt.jhat.hat); + torqueMapping->lastHatState[evt.jhat.hat] = evt.jhat.value; + } + break; + } + + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + { + joystickState* torqueMapping; + if (mJoystickMap.isEmpty() || !mJoystickMap.find(evt.jbutton.which, torqueMapping)) + break; + buildInputEvent(JoystickDeviceType, torqueMapping->torqueInstID, SI_BUTTON, KEY_BUTTON0 + evt.jbutton.button, + evt.cbutton.state == SDL_PRESSED ? SI_MAKE : SI_BREAK, evt.cbutton.state == SDL_PRESSED ? 1.0f : 0.0f); + break; + } + + case SDL_JOYDEVICEADDED: + { + deviceConnectedCallback(evt.jdevice.which); + if (smControllerEnabled && SDL_IsGameController(evt.jdevice.which)) + break; // This device will be added as a controller + + if (smJoystickEnabled) + openJoystick(evt.jdevice.which, 0); + break; + } + + case SDL_JOYDEVICEREMOVED: + { + onSDLDeviceDisconnected_callback(evt.jdevice.which); + closeJoystick(evt.jdevice.which); + } + + case SDL_CONTROLLERAXISMOTION: + { + controllerState* torqueMapping; + if (mControllerMap.isEmpty() || !mControllerMap.find(evt.caxis.which, torqueMapping)) + break; + // SDL axis value inputs are in (range: -32768 to 32767) + // Torque axis values are -1.0 to 1.0 + F32 value = ((F32)evt.caxis.value) / (F32) (evt.caxis.value > 0 ? SDL_JOYSTICK_AXIS_MAX : -SDL_JOYSTICK_AXIS_MIN); + buildInputEvent(GamepadDeviceType, torqueMapping->torqueInstID, SI_AXIS, map_EventForControllerAxis[evt.caxis.axis], SI_MOVE, value); + break; + } + + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERBUTTONUP: + { + controllerState* torqueMapping; + if (mControllerMap.isEmpty() || !mControllerMap.find(evt.cbutton.which, torqueMapping)) + break; + buildInputEvent(GamepadDeviceType, torqueMapping->torqueInstID, SI_BUTTON, map_EventForControllerButton[evt.cbutton.button], + evt.cbutton.state == SDL_PRESSED ? SI_MAKE : SI_BREAK, evt.cbutton.state == SDL_PRESSED ? 1.0f : 0.0f); + break; + } + + case SDL_CONTROLLERDEVICEADDED: + { + if (smControllerEnabled) + openController(evt.cdevice.which, 0); + break; + } + + case SDL_CONTROLLERDEVICEREMOVED: + { + closeController(evt.cdevice.which); + break; + } + + case SDL_CONTROLLERDEVICEREMAPPED: + break; + + default: +#ifdef TORQUE_DEBUG + Con::warnf("Unhandled SDL input event: 0x%04x", evt.type); +#endif + break; + } +} + +//------------------------------------------------------------------------------ +void SDLInputManager::buildInputEvent(U32 deviceType, U32 deviceInst, InputEventType objType, InputObjectInstances objInst, InputActionType action, S32 iValue) +{ + InputEventInfo newEvent; + + newEvent.deviceType = deviceType; + newEvent.deviceInst = deviceInst; + newEvent.objType = objType; + newEvent.objInst = objInst; + newEvent.action = action; + newEvent.iValue = iValue; + + newEvent.postToSignal(Input::smInputEvent); +} + +//------------------------------------------------------------------------------ +void SDLInputManager::buildInputEvent(U32 deviceType, U32 deviceInst, InputEventType objType, InputObjectInstances objInst, InputActionType action, F32 fValue) +{ + InputEventInfo newEvent; + + newEvent.deviceType = deviceType; + newEvent.deviceInst = deviceInst; + newEvent.objType = objType; + newEvent.objInst = objInst; + newEvent.action = action; + newEvent.fValue = fValue; + + newEvent.postToSignal(Input::smInputEvent); +} + +//------------------------------------------------------------------------------ +void SDLInputManager::buildHatEvents(U32 deviceType, U32 deviceInst, U8 lastState, U8 currentState, S32 hatIndex) +{ + if (smPOVButtonEvents) + { + if ((lastState & SDL_HAT_UP) != (currentState & SDL_HAT_UP)) + { + buildInputEvent(deviceType, deviceInst, SI_POV, hatIndex ? SI_UPOV2 : SI_UPOV, + (currentState & SDL_HAT_UP) ? SI_MAKE : SI_BREAK, (currentState & SDL_HAT_UP) ? 1.0f : 0.0f); + } + + if ((lastState & SDL_HAT_DOWN) != (currentState & SDL_HAT_DOWN)) + { + buildInputEvent(deviceType, deviceInst, SI_POV, hatIndex ? SI_DPOV2 : SI_DPOV, + (currentState & SDL_HAT_DOWN) ? SI_MAKE : SI_BREAK, (currentState & SDL_HAT_DOWN) ? 1.0f : 0.0f); + } + + if ((lastState & SDL_HAT_LEFT) != (currentState & SDL_HAT_LEFT)) + { + buildInputEvent(deviceType, deviceInst, SI_POV, hatIndex ? SI_LPOV2 : SI_LPOV, + (currentState & SDL_HAT_LEFT) ? SI_MAKE : SI_BREAK, (currentState & SDL_HAT_LEFT) ? 1.0f : 0.0f); + } + + if ((lastState & SDL_HAT_RIGHT) != (currentState & SDL_HAT_RIGHT)) + { + buildInputEvent(deviceType, deviceInst, SI_POV, hatIndex ? SI_RPOV2 : SI_RPOV, + (currentState & SDL_HAT_RIGHT) ? SI_MAKE : SI_BREAK, (currentState & SDL_HAT_RIGHT) ? 1.0f : 0.0f); + } + } + + if (smPOVMaskEvents) + { + buildInputEvent(deviceType, deviceInst, SI_INT, hatIndex ? SI_POVMASK2 : SI_POVMASK, SI_VALUE, (S32) currentState); + } +} + +//------------------------------------------------------------------------------ +S32 SDLInputManager::openController(S32 sdlIndex, S32 requestedTID) +{ + if ((sdlIndex < 0) || (sdlIndex >= SDL_NumJoysticks()) || (requestedTID < 0) || (requestedTID >= MaxControllers)) + return -1; + + if (SDL_IsGameController(sdlIndex)) + { + SDL_GameController *inputDevice = SDL_GameControllerOpen(sdlIndex); + if (inputDevice) + { + SDL_JoystickID sdlId = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(inputDevice)); + + // See if the device is already open as a joystick + for (S32 i = 0; i < MaxJoysticks; ++i) + { + if (mJoysticks[i].sdlInstID == sdlId) + { + if (!closeJoystickByIndex(i)) + { + SDL_GameControllerClose(inputDevice); + return -1; + } + } + } + + controllerState* torqueMapping = NULL; + if (mControllerMap.find(sdlId, torqueMapping)) + { + if (torqueMapping->torqueInstID == (U32) requestedTID) + { + SDL_GameControllerClose(inputDevice); + return requestedTID; // Already open at the requested ID + } + closeControllerByIndex(torqueMapping->torqueInstID); + } + + S32 gamepadSlot = -1; + if (!mControllers[requestedTID].inputDevice) + gamepadSlot = requestedTID; + else + { + // Find the first available gamepad device slot + for (S32 i = 0; i < MaxControllers; ++i) + { + if (!mControllers[i].inputDevice) + { + gamepadSlot = i; + break; + } + } + } + + if (gamepadSlot == -1) + { + Con::errorf("Unable to open Game Controller %s. Too many devices present.", SDL_GameControllerName(inputDevice)); + SDL_GameControllerClose(inputDevice); + return -1; + } + + mControllers[gamepadSlot].inputDevice = inputDevice; + mControllers[gamepadSlot].sdlInstID = sdlId; + mControllerMap.insertUnique(sdlId, &mControllers[gamepadSlot]); + + return gamepadSlot; + } + } + return -1; +} + +//------------------------------------------------------------------------------ +void SDLInputManager::closeController(SDL_JoystickID sdlId) +{ + controllerState* torqueMapping = NULL; + if (mControllerMap.find(sdlId, torqueMapping)) + closeControllerByIndex(torqueMapping->torqueInstID); +} + +//------------------------------------------------------------------------------ +bool SDLInputManager::closeControllerByIndex(S32 index) +{ + if (index < 0 || index >= MaxControllers) + return false; + + if (mControllers[index].inputDevice && mControllers[index].sdlInstID != -1) + { + SDL_GameControllerClose(mControllers[index].inputDevice); + mControllerMap.erase(mControllers[index].sdlInstID); + mControllers[index].sdlInstID = -1; + mControllers[index].inputDevice = NULL; + return true; + } + + return false; +} + +//------------------------------------------------------------------------------ +S32 SDLInputManager::openJoystick(S32 sdlIndex, S32 requestedTID) +{ + if ((sdlIndex < 0) || (sdlIndex >= SDL_NumJoysticks()) || (requestedTID < 0) || (requestedTID >= MaxJoysticks)) + return -1; + + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + SDL_JoystickID sdlId = SDL_JoystickInstanceID(inputDevice); + + // See if the device is already open as a controller + for (S32 i = 0; i < MaxControllers; ++i) + { + if (mControllers[i].sdlInstID == sdlId) + { + if (!closeControllerByIndex(i)) + { + SDL_JoystickClose(inputDevice); + return -1; + } + } + } + + joystickState* torqueMapping = NULL; + if (mJoystickMap.find(sdlId, torqueMapping)) + { + if (torqueMapping->torqueInstID == (U32) requestedTID) + { + SDL_JoystickClose(inputDevice); + return requestedTID; // Already open at the requested ID + } + closeJoystickByIndex(torqueMapping->torqueInstID); + } + + S32 joystickSlot = -1; + if (!mJoysticks[requestedTID].inputDevice) + joystickSlot = requestedTID; + else + { + // Find the first available joystick device slot + for (S32 i = 0; i < MaxJoysticks; ++i) + { + if (!mJoysticks[i].inputDevice) + { + joystickSlot = i; + break; + } + } + } + + if (joystickSlot == -1) + { + Con::errorf("Unable to open Joystick %s. Too many devices present.", SDL_JoystickName(inputDevice)); + SDL_JoystickClose(inputDevice); + return -1; + } + + mJoysticks[joystickSlot].inputDevice = inputDevice; + mJoysticks[joystickSlot].sdlInstID = sdlId; + mJoysticks[joystickSlot].numAxes = SDL_JoystickNumAxes(inputDevice); + mJoystickMap.insertUnique(sdlId, &mJoysticks[joystickSlot]); + + return joystickSlot; + } + return -1; +} + +//------------------------------------------------------------------------------ +void SDLInputManager::closeJoystick(SDL_JoystickID sdlId) +{ + joystickState* torqueMapping = NULL; + if (mJoystickMap.find(sdlId, torqueMapping)) + closeJoystickByIndex(torqueMapping->torqueInstID); +} + +//------------------------------------------------------------------------------ +bool SDLInputManager::closeJoystickByIndex(S32 index) +{ + if (index < 0 || index >= MaxJoysticks) + return false; + + if (mJoysticks[index].inputDevice && mJoysticks[index].sdlInstID != -1) + { + SDL_JoystickClose(mJoysticks[index].inputDevice); + mJoystickMap.erase(mJoysticks[index].sdlInstID); + mJoysticks[index].reset(); + return true; + } + + return false; +} + +//------------------------------------------------------------------------------ +void SDLInputManager::closeDevice(S32 sdlIndex) +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return; + + SDL_JoystickID sdlId = -1; + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + sdlId = SDL_JoystickInstanceID(inputDevice); + SDL_JoystickClose(inputDevice); + } + + if (sdlId < 0) + return; + + for (S32 i = 0; i < MaxControllers; ++i) + { + if (mControllers[i].sdlInstID == sdlId) + { + closeControllerByIndex(i); + return; + } + } + + for (S32 i = 0; i < MaxJoysticks; ++i) + { + if (mJoysticks[i].sdlInstID == sdlId) + { + closeJoystickByIndex(i); + return; + } + } +} + +//------------------------------------------------------------------------------ +void SDLInputManager::deviceConnectedCallback(S32 index) +{ + // This will generate the script callback: + // onSDLDeviceConnected(%sdlIndex, %isController, %deviceName) + bool isController = SDL_IsGameController(index); + const char *deviceName = isController ? SDL_GameControllerNameForIndex(index) : SDL_JoystickNameForIndex(index); + SDL_JoystickType deviceType = SDL_JoystickGetDeviceType(index); + onSDLDeviceConnected_callback(index, deviceName, castConsoleTypeToString(deviceType)); +} + +//------------------------------------------------------------------------------ +// Console interface + +//------------------------------------------------------------------------------ +// Get the N'th SDL device state -1=doesn't exist, 0=closed, 1=open joystick, 2=open controller +S32 SDLInputManager::getJoystickOpenState(S32 sdlIndex) +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return -1; + + S32 currentState = 0; + // We need to open the joystick to get the sdl instanceID + // This will increase the refcount on the joystick if it was already open. + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + SDL_JoystickID sdlId = SDL_JoystickInstanceID(inputDevice); + controllerState* controllerMapping = NULL; + joystickState* joystickMapping = NULL; + if (!mControllerMap.isEmpty() && mControllerMap.find(sdlId, controllerMapping)) + currentState = 2; + else if (!mJoystickMap.isEmpty() && mJoystickMap.find(sdlId, joystickMapping)) + currentState = 1; + + // Close the joystick to return the refcount to the previouse state + SDL_JoystickClose(inputDevice); + } + + return currentState; +} + +//------------------------------------------------------------------------------ +// Fills in the torque device instance string from an sdl joystick index number +void SDLInputManager::getJoystickTorqueInst(S32 sdlIndex, char* instBuffer) +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return; + + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + SDL_JoystickID sdlId = SDL_JoystickInstanceID(inputDevice); + controllerState* controllerMapping = NULL; + joystickState* joystickMapping = NULL; + if (!mControllerMap.isEmpty() && mControllerMap.find(sdlId, controllerMapping)) + ActionMap::getDeviceName(GamepadDeviceType, controllerMapping->torqueInstID, instBuffer); + else if (!mJoystickMap.isEmpty() && mJoystickMap.find(sdlId, joystickMapping)) + ActionMap::getDeviceName(JoystickDeviceType, joystickMapping->torqueInstID, instBuffer); + + SDL_JoystickClose(inputDevice); + } +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, numJoysticks, S32, (), , + "@brief Returns the number of currently connected joystick devices.\n\n" + "Game Controllers are a sub-set of joysticks and are included in the joystick count. " + "See https://wiki.libsdl.org/SDL_NumJoysticks for more details.\n" + "@ingroup Input") +{ + return SDL_NumJoysticks(); +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, getDeviceOpenState, S32, ( S32 sdlIndex ), ( 0 ), + "@brief Used to determine the current state of the N'th item in the SDL device list.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return values:\n" + "-1 if the device does not exist (invalid sdlIndex passed)\n" + "0 The device is closed\n" + "1 The device is open as a Joystick\n" + "2 The device is open as a Game Controller\n" + "@ingroup Input") +{ + SDLInputManager* mgr = dynamic_cast(Input::getManager()); + if (mgr && mgr->isEnabled()) + return mgr->getJoystickOpenState(sdlIndex); + return -1; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, openAsJoystick, S32, ( S32 sdlIndex, S32 torqueInstId ), ( 0, 0 ), + "@brief Used to open the device as a Joystick.\n\n" + "If the device is currently open as a Game Controller, it will be closed and opened as " + "a Joystick. If it is currently opened as a Joystick with a different T3D instance ID, " + "it will be changed to the requested ID if that ID is available.\n" + "@param sdlIndex The SDL index for this device.\n" + "@param torqueInstId Is the requested T3D device instance ID. If there is already an open Joystick with " + "the requested ID, The first available ID will be assigned.\n" + "@return The T3D device instance ID assigned, or -1 if the device could not be opened.") +{ + SDLInputManager* mgr = dynamic_cast(Input::getManager()); + if (mgr && mgr->isEnabled()) + return mgr->openJoystick(sdlIndex, torqueInstId); + return -1; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, openAsController, S32, (S32 sdlIndex, S32 torqueInstId), (0, 0), + "@brief Used to open the device as a Game Controller.\n\n" + "If the device is currently open as a Joystick, it will be closed and opened as " + "a Game Controller. If it is currently opened as a Game Controller with a different " + "T3D instance ID, it will be changed to the requested ID if that ID is available.\n" + "@param sdlIndex The SDL index for this device.\n" + "@param torqueInstId Is the requested T3D device instance ID. If there is already an " + "open Game Controller with the requested ID, The first available ID will be assigned.\n" + "@return The T3D device instance ID assigned, or -1 if the device could not be opened.") +{ + SDLInputManager* mgr = dynamic_cast(Input::getManager()); + if (mgr && mgr->isEnabled()) + return mgr->openController(sdlIndex, torqueInstId); + return -1; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, closeDevice, void, (S32 sdlIndex), (0), + "@brief Used to close the N'th item in the SDL device list.\n\n" + "This will close a Joystick or Game Controller.\n" + "@param sdlIndex The SDL index for this device.\n") +{ + SDLInputManager* mgr = dynamic_cast(Input::getManager()); + if (mgr && mgr->isEnabled()) + mgr->closeDevice(sdlIndex); + return; +} + + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, getTorqueInstFromDevice, const char *, (S32 sdlIndex), (0), + "@brief Gets the T3D instance identifier for an open SDL joystick.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns the T3D instance ID used for mapping this device or Null if it does not exist.\n" + "@ingroup Input") +{ + SDLInputManager* mgr = dynamic_cast(Input::getManager()); + if (mgr && mgr->isEnabled()) + { + char* deviceInst = Con::getReturnBuffer(32); + deviceInst[0] = '\0'; + mgr->getJoystickTorqueInst(sdlIndex, deviceInst); + return deviceInst; + } + return NULL; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickNameForIndex, const char *, (S32 sdlIndex), (0), + "@brief Exposes SDL_JoystickNameForIndex() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns the name of the selected joystick or Null if it does not exist.\n" + "@see https://wiki.libsdl.org/SDL_JoystickNameForIndex \n" + "@ingroup Input") +{ + if (sdlIndex >= 0 && sdlIndex < SDL_NumJoysticks()) + return SDL_JoystickNameForIndex(sdlIndex); + return NULL; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, ControllerNameForIndex, const char *, (S32 sdlIndex), (0), + "@brief Exposes SDL_GameControllerNameForIndex() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns the implementation dependent name for the game controller, " + "or NULL if there is no name or the index is invalid.\n" + "@see https://wiki.libsdl.org/SDL_GameControllerNameForIndex \n" + "@ingroup Input") +{ + if (sdlIndex >= 0 && sdlIndex < SDL_NumJoysticks() || !SDL_IsGameController(sdlIndex)) + return SDL_GameControllerNameForIndex(sdlIndex); + return NULL; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickGetGUID, const char *, (S32 sdlIndex), (0), + "@brief Exposes SDL_JoystickGetDeviceGUID() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return GUID for the indexed device or Null if it does not exist.\n" + "@see https://wiki.libsdl.org/SDL_JoystickGetDeviceGUID \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return NULL; + + SDL_JoystickGUID guidVal = SDL_JoystickGetDeviceGUID(sdlIndex); + char *guidStr = Con::getReturnBuffer(64); + SDL_JoystickGetGUIDString(guidVal, guidStr, 64); + + return guidStr; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, GetVendor, S32, (S32 sdlIndex), (0), + "Gets the USB vendor ID of a joystick device, if available.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return The USB vendor ID. If the vendor ID isn't available this function returns 0.\n" + "@see https://wiki.libsdl.org/SDL_JoystickGetDeviceVendor \n" + "@see https://wiki.libsdl.org/SDL_JoystickGetVendor \n" + "@see https://wiki.libsdl.org/SDL_GameControllerGetVendor \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return 0; + + return (S32) SDL_JoystickGetDeviceVendor(sdlIndex); +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, GetProduct, S32, (S32 sdlIndex), (0), + "Gets the USB product ID of a joystick device, if available.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return The USB product ID. If the product ID isn't available this function returns 0.\n" + "@see https://wiki.libsdl.org/SDL_JoystickGetDeviceProduct \n" + "@see https://wiki.libsdl.org/SDL_JoystickGetProduct \n" + "@see https://wiki.libsdl.org/SDL_GameControllerGetProduct \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return 0; + + return (S32)SDL_JoystickGetDeviceProduct(sdlIndex); +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, GetProductVersion, S32, (S32 sdlIndex), (0), + "Gets the product version of a joystick device, if available.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return The product version. If the product version isn't available this function returns 0.\n" + "@see https://wiki.libsdl.org/SDL_JoystickGetDeviceProductVersion \n" + "@see https://wiki.libsdl.org/SDL_JoystickGetProductVersion \n" + "@see https://wiki.libsdl.org/SDL_GameControllerGetProductVersion \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return 0; + + return (S32)SDL_JoystickGetDeviceProductVersion(sdlIndex); +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, GetDeviceType, SDLJoystickType, (S32 sdlIndex), (0), + "@brief Exposes SDL_JoystickGetDeviceType() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return The type of device connected. Possible return strings are: \"Unknown\", " + "\"Game Controller\", \"Wheel\", \"Arcade Stick\", \"Flight Stick\", \"Dance Pad\", " + "\"Guitar\", \"Drum Kit\", \"Arcade Pad\" and \"Throttle\"\n" + "@see https://wiki.libsdl.org/SDL_JoystickGetDeviceType \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return SDL_JOYSTICK_TYPE_UNKNOWN; + + return SDL_JoystickGetDeviceType(sdlIndex); +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickNumAxes, S32, (S32 sdlIndex), (0), + "@brief Exposes SDL_JoystickNumAxes() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns the number of axis controls/number of axes on success or zero on failure.\n" + "@see https://wiki.libsdl.org/SDL_JoystickNumAxes \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return 0; + + S32 numAxes = 0; + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + numAxes = SDL_JoystickNumAxes(inputDevice); + if (numAxes < 0) + { + Con::errorf("SDL Joystick error: %s", SDL_GetError()); + numAxes = 0; + } + + SDL_JoystickClose(inputDevice); + } + + return numAxes; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickNumBalls, S32, (S32 sdlIndex), (0), + "@brief Exposes SDL_JoystickNumBalls() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns the number of trackballs on success or zero on failure.\n" + "@see https://wiki.libsdl.org/SDL_JoystickNumBalls \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return 0; + + S32 numBalls = 0; + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + numBalls = SDL_JoystickNumBalls(inputDevice); + if (numBalls < 0) + { + Con::errorf("SDL Joystick error: %s", SDL_GetError()); + numBalls = 0; + } + + SDL_JoystickClose(inputDevice); + } + + return numBalls; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickNumButtons, S32, (S32 sdlIndex), (0), + "@brief Exposes SDL_JoystickNumButtons() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns the number of buttons on success or zero on failure.\n" + "@see https://wiki.libsdl.org/SDL_JoystickNumButtons \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return 0; + + S32 numButtons = 0; + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + numButtons = SDL_JoystickNumButtons(inputDevice); + if (numButtons < 0) + { + Con::errorf("SDL Joystick error: %s", SDL_GetError()); + numButtons = 0; + } + + SDL_JoystickClose(inputDevice); + } + + return numButtons; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickNumHats, S32, (S32 sdlIndex), (0), + "@brief Exposes SDL_JoystickNumHats() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns the number of POV hats on success or zero on failure.\n" + "@see https://wiki.libsdl.org/SDL_JoystickNumHats \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return 0; + + S32 numHats = 0; + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + numHats = SDL_JoystickNumHats(inputDevice); + if (numHats < 0) + { + Con::errorf("SDL Joystick error: %s", SDL_GetError()); + numHats = 0; + } + + SDL_JoystickClose(inputDevice); + } + + return numHats; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, IsGameController, bool, (S32 sdlIndex), (0), + "@brief Exposes SDL_IsGameController() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns true if the given joystick is supported by the game controller " + "interface, false if it isn't or it's an invalid index.\n" + "@see https://wiki.libsdl.org/SDL_IsGameController \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks() || !SDL_IsGameController(sdlIndex)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickIsHaptic, bool, (S32 sdlIndex), (0), + "@brief Exposes SDL_JoystickIsHaptic() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns true if the joystick is haptic.\n" + "@see https://wiki.libsdl.org/SDL_JoystickIsHaptic \n" + "@ingroup Input") +{ + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return false; + + bool isHaptic = false; + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + isHaptic = (SDL_JoystickIsHaptic(inputDevice) == SDL_TRUE); + SDL_JoystickClose(inputDevice); + } + + return isHaptic; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickPowerLevel, SDLPowerEnum, (S32 sdlIndex), (0), + "@brief Exposes SDL_JoystickCurrentPowerLevel() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns the current battery level or \"Wired\" if it's a connected device.\n" + "@see https://wiki.libsdl.org/SDL_JoystickCurrentPowerLevel \n" + "@ingroup Input") +{ + SDL_JoystickPowerLevel powerLevel = SDL_JOYSTICK_POWER_UNKNOWN; + if (sdlIndex >= 0 && sdlIndex < SDL_NumJoysticks()) + { + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + powerLevel = SDL_JoystickCurrentPowerLevel(inputDevice); + SDL_JoystickClose(inputDevice); + } + } + return powerLevel; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickGetSpecs, String, (S32 sdlIndex), (0), + "@brief A convenience function to reurn all of the data for a Joystick/Game Controller " + " packed as fields in a tab separated string.\n\n" + "There is overhead involved in querying joystick data, especially if the device is not open. " + "If more than one field is required, it is more efficient to call JoystickGetSpecs() and " + "parse the data out of the return string than to call the console method for each.\n" + "@param sdlIndex The SDL index for this device.\n" + "@return A tab separated string that can be parsed from script with getField()/getFields().\n\n" + "Field 0: Number of Axes\n" + " 1: Number of Buttons\n" + " 2: Number of POV Hats\n" + " 3: Number of Trackballs\n" + " 4: SDL_IsGameController() (Boolean)\n" + " 5: SDL_JoystickIsHaptic() (Boolean)\n" + " 6: Power Level (String)\n" + " 7: Device Type (String)\n" + "@ingroup Input") +{ + String specStr; + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return specStr; + + bool isController = SDL_IsGameController(sdlIndex); + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + SDL_JoystickPowerLevel powerLevel = SDL_JoystickCurrentPowerLevel(inputDevice); + SDL_JoystickType deviceType = SDL_JoystickGetDeviceType(sdlIndex); + + specStr = String::ToString("%d\t%d\t%d\t%d\t%d\t%d\t%s\t%s\t", + SDL_JoystickNumAxes(inputDevice), SDL_JoystickNumButtons(inputDevice), + SDL_JoystickNumHats(inputDevice), SDL_JoystickNumBalls(inputDevice), + isController ? 1 : 0, (SDL_JoystickIsHaptic(inputDevice) == SDL_TRUE) ? 1 : 0, + castConsoleTypeToString(powerLevel), castConsoleTypeToString(deviceType)); + SDL_JoystickClose(inputDevice); + } + + return specStr; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickGetAxes, String, (S32 sdlIndex), (0), + "@brief Gets the current value for all joystick axes.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return A tab separated string that can be parsed from script with getField()/getFields(). " + "Each axis is one field, so a 4 axis device will have 4 fields.\n\n" + "@ingroup Input") +{ + String axesStr; + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return axesStr; + + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + S32 numAxes = SDL_JoystickNumAxes(inputDevice); + for (S32 i = 0; i < numAxes; i++) + { + F32 axisVal = (F32) SDL_JoystickGetAxis(inputDevice, i); + F32 value = axisVal / (F32)(axisVal > 0.0f ? SDL_JOYSTICK_AXIS_MAX : -SDL_JOYSTICK_AXIS_MIN); + axesStr += String::ToString("%0.3f\t", value); + } + SDL_JoystickClose(inputDevice); + } + + return axesStr; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickGetButtons, String, (S32 sdlIndex), (0), + "@brief Gets the current value for all joystick buttons.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return A tab separated string that can be parsed from script with getField()/getFields(). " + "Each button is one field. 0 - SDL_JoystickNumButtons() fields.\n\n" + "@ingroup Input") +{ + String buttonStr; + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return buttonStr; + + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + S32 numbuttons = SDL_JoystickNumButtons(inputDevice); + for (S32 i = 0; i < numbuttons; i++) + { + buttonStr += String::ToString("%d\t", (S32) SDL_JoystickGetButton(inputDevice, i)); + } + SDL_JoystickClose(inputDevice); + } + + return buttonStr; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, JoystickGetHats, String, (S32 sdlIndex), (0), + "@brief Gets the current value for all POV hats.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return A tab separated string that can be parsed from script with getField()/getFields(). " + "Each hat is one field. 0 - SDL_JoystickNumHats() fields. The value is a 4 bit bitmask. " + "If no bits are set, the hat is centered. Bit 0 is up, 1 is right, 2 is down and 3 is left.\n\n" + "@ingroup Input") +{ + String hatStr; + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return hatStr; + + SDL_Joystick *inputDevice = SDL_JoystickOpen(sdlIndex); + if (inputDevice) + { + S32 numHats = SDL_JoystickNumHats(inputDevice); + for (S32 i = 0; i < numHats; i++) + { + hatStr += String::ToString("%d\t", (S32)SDL_JoystickGetHat(inputDevice, i)); + } + SDL_JoystickClose(inputDevice); + } + + return hatStr; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, ControllerGetAxes, String, (S32 sdlIndex), (0), + "@brief Gets the current value for all controller axes.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return A tab separated string that can be parsed from script with getField()/getFields(). " + "Game controllers always have 6 axes in the following order: 0-LX, 1-LY, 2-RX, 3-RY, 4-LT, 5-RT.\n\n" + "@ingroup Input") +{ + String axesStr; + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return axesStr; + + bool isController = SDL_IsGameController(sdlIndex); + if (!isController) + return axesStr; + + SDL_GameController *inputDevice = SDL_GameControllerOpen(sdlIndex); + if (inputDevice) + { + for (S32 i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) + { + F32 axisVal = (F32)SDL_GameControllerGetAxis(inputDevice, (SDL_GameControllerAxis) i); + F32 value = axisVal / (F32)(axisVal > 0.0f ? SDL_JOYSTICK_AXIS_MAX : -SDL_JOYSTICK_AXIS_MIN); + axesStr += String::ToString("%0.3f\t", value); + } + SDL_GameControllerClose(inputDevice); + } + + return axesStr; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, ControllerGetButtons, String, (S32 sdlIndex), (0), + "@brief Gets the current value for all controller buttons.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return A tab separated string that can be parsed from script with getField()/getFields(). " + "Game controllers always have 15 buttons in the following order: 0-A, 1-B, 2-X, 3-Y, 4-Back, " + "5-Guide, 6-Start, 7-Left Stick, 8-Right Stick, 9-Left Shoulder, 10-Right Shoulder, " + "11-DPad Up, 12-DPad Down, 13-DPad Left, 14-DPad Right.\n\n" + "@ingroup Input") +{ + String buttonStr; + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return buttonStr; + + bool isController = SDL_IsGameController(sdlIndex); + if (!isController) + return buttonStr; + + SDL_GameController *inputDevice = SDL_GameControllerOpen(sdlIndex); + if (inputDevice) + { + for (S32 i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) + { + buttonStr += String::ToString("%d\t", (S32)SDL_GameControllerGetButton(inputDevice, (SDL_GameControllerButton) i)); + } + SDL_GameControllerClose(inputDevice); + } + + return buttonStr; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, GameControllerMapping, String, (S32 sdlIndex), (0), + "@brief Exposes SDL_GameControllerMapping() to script.\n\n" + "@param sdlIndex The SDL index for this device.\n" + "@return Returns a string that has the controller's mapping or NULL if no mapping " + "is available or it does not exist.\n" + "@see https://wiki.libsdl.org/SDL_JoystickNameForIndex \n" + "@ingroup Input") +{ + String mapping; + if (sdlIndex < 0 || sdlIndex >= SDL_NumJoysticks()) + return mapping; + + SDL_GameController *inputDevice = SDL_GameControllerOpen(sdlIndex); + if (inputDevice) + { + char* sdlStr = SDL_GameControllerMapping(inputDevice); + if (sdlStr) + { + mapping = sdlStr; + SDL_free(sdlStr); + } + else + Con::errorf("SDL Joystick error: %s", SDL_GetError()); + + SDL_GameControllerClose(inputDevice); + } + + return mapping; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, GameControllerMappingForGUID, String, (const char* guidStr), , + "@brief Exposes SDL_GameControllerMappingForGUID() to script.\n\n" + "@param guidStr The GUID for which a mapping is desired.\n" + "@return Returns a mapping string or NULL on error.\n" + "@see https://wiki.libsdl.org/SDL_GameControllerMappingForGUID \n" + "@ingroup Input") +{ + String mapping; + SDL_JoystickGUID guid = SDL_JoystickGetGUIDFromString(guidStr); + + char* sdlStr = SDL_GameControllerMappingForGUID(guid); + if (sdlStr) + { + mapping = sdlStr; + SDL_free(sdlStr); + } + + return mapping; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, GameControllerAddMapping, S32, (const char* mappingString), , + "@brief Exposes SDL_GameControllerAddMapping() to script.\n\n" + "Use this function to add support for controllers that SDL is unaware of or " + "to cause an existing controller to have a different binding.\n" + "@param mappingString The new mapping string to apply. Full details on the format of this " + "string are available at the linked SDL wiki page.\n" + "@return Returns 1 if a new mapping is added, 0 if an existing mapping is updated, -1 on error.\n" + "@see https://wiki.libsdl.org/SDL_GameControllerAddMapping \n" + "@ingroup Input") +{ + S32 retVal = SDL_GameControllerAddMapping(mappingString); + if (retVal == -1) + Con::errorf("SDL Joystick error: %s", SDL_GetError()); + + return retVal; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, GameControllerAddMappingsFromFile, S32, (const char* fileName), , + "@brief Exposes SDL_GameControllerAddMappingsFromFile() to script.\n\n" + "Use this function to load a set of Game Controller mappings from a file, filtered by the " + "current SDL_GetPlatform(). A community sourced database of controllers is available at " + "https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt \n" + "@param fileName The file to load mappings from.\n" + "@return Returns the number of mappings added or -1 on error.\n" + "@see https://wiki.libsdl.org/SDL_GameControllerAddMappingsFromFile \n" + "@ingroup Input") +{ + char torquePath[1024]; + Con::expandScriptFilename(torquePath, sizeof(torquePath), fileName); + S32 retVal = SDL_GameControllerAddMappingsFromFile(torquePath); + if (retVal == -1) + Con::errorf("SDL Joystick error: %s", SDL_GetError()); + + return retVal; +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, GameControllerNumMappings, S32, (), , + "Get the number of mappings installed. Used with GameControllerMappingForIndex " + "to iterate through all installed mappings.\n\n" + "@ingroup Input") +{ + return SDL_GameControllerNumMappings(); +} + +//------------------------------------------------------------------------------ +DefineEngineStaticMethod(SDLInputManager, GameControllerMappingForIndex, String, (S32 mappingIndex), , + "Get the mapping at a particular index.\n\n" + "@param mappingIndex The index for which a mapping is desired.\n" + "@return Returns a mapping string or NULL if the index is out of range.\n" + "@ingroup Input") +{ + String mapping; + char* sdlStr = SDL_GameControllerMappingForIndex(mappingIndex); + + if (sdlStr) + { + mapping = sdlStr; + SDL_free(sdlStr); + } + + return mapping; +} diff --git a/Engine/source/platformSDL/sdlInputManager.h b/Engine/source/platformSDL/sdlInputManager.h new file mode 100644 index 000000000..b9c9f057d --- /dev/null +++ b/Engine/source/platformSDL/sdlInputManager.h @@ -0,0 +1,114 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _SDLINPUTMANAGER_H_ +#define _SDLINPUTMANAGER_H_ + +#ifndef _PLATFORMINPUT_H_ +#include "platform/platformInput.h" +#endif +#include "SDL.h" + +//------------------------------------------------------------------------------ +class SDLInputManager : public InputManager +{ + enum Constants { + MaxJoysticks = 4, // Up to 4 simultaneous joysticks + MaxControllers = 4, // Up to 4 simultaneous controllers + MaxHats = 2, // Maximum 2 hats per device + MaxBalls = 2, // Maximum 2 trackballs per device + MaxControllerAxes = 7, // From map_StringForControllerAxis[] in SDL_gamecontroller.c + MaxControllerButtons = 16 // From map_StringForControllerButton[] in SDL_gamecontroller.c + }; + + struct controllerState + { + S32 sdlInstID; // SDL device instance id + U32 torqueInstID; // Torque device instance id + SDL_GameController *inputDevice; + }; + + struct joystickState + { + S32 sdlInstID; // SDL device instance id + U32 torqueInstID; // Torque device instance id + SDL_Joystick *inputDevice; + U32 numAxes; + U8 lastHatState[MaxHats]; + + void reset(); + }; + +private: + typedef InputManager Parent; + + static S32 map_EventForControllerAxis[MaxControllerAxes]; + static S32 map_EventForControllerButton[MaxControllerButtons]; + + static bool smJoystickEnabled; + static bool smJoystickSplitAxesLR; + static bool smControllerEnabled; + static bool smPOVButtonEvents; + static bool smPOVMaskEvents; + + joystickState mJoysticks[MaxJoysticks]; + controllerState mControllers[MaxControllers]; + + // Used to look up a torque instance based on a device inst + HashTable mJoystickMap; + HashTable mControllerMap; + + bool mJoystickActive; + + void deviceConnectedCallback(S32 index); + bool closeControllerByIndex(S32 index); + void closeController(SDL_JoystickID sdlId); + bool closeJoystickByIndex(S32 index); + void closeJoystick(SDL_JoystickID sdlId); + + void buildInputEvent(U32 deviceType, U32 deviceInst, InputEventType objType, InputObjectInstances objInst, InputActionType action, S32 iValue); + void buildInputEvent(U32 deviceType, U32 deviceInst, InputEventType objType, InputObjectInstances objInst, InputActionType action, F32 fValue); + void buildHatEvents(U32 deviceType, U32 deviceInst, U8 lastState, U8 currentState, S32 hatIndex); + +public: + DECLARE_STATIC_CLASS(SDLInputManager); + +public: + SDLInputManager(); + + bool enable(); + void disable(); + void process(); + + void processEvent(SDL_Event &evt); + + static void init(); + + // Console interface: + S32 openJoystick(S32 sdlIndex, S32 requestedTID); + S32 openController(S32 sdlIndex, S32 requestedTID); + void closeDevice(S32 sdlIndex); + S32 getJoystickOpenState(S32 sdlIndex); + void getJoystickTorqueInst(S32 sdlIndex, char* instBuffer); +}; + +#endif // _SDLINPUTMANAGER_H_ diff --git a/Engine/source/windowManager/sdl/sdlWindowMgr.cpp b/Engine/source/windowManager/sdl/sdlWindowMgr.cpp index f503c4fb1..dd3f13825 100644 --- a/Engine/source/windowManager/sdl/sdlWindowMgr.cpp +++ b/Engine/source/windowManager/sdl/sdlWindowMgr.cpp @@ -21,6 +21,7 @@ //----------------------------------------------------------------------------- #include "windowManager/sdl/sdlWindowMgr.h" +#include "platformSDL/sdlInputManager.h" #include "gfx/gfxDevice.h" #include "core/util/journal/process.h" #include "core/strings/unicode.h" @@ -269,6 +270,13 @@ void PlatformWindowManagerSDL::_process() SDL_Event evt; while( SDL_PollEvent(&evt) ) { + if (evt.type >= SDL_JOYAXISMOTION && evt.type <= SDL_CONTROLLERDEVICEREMAPPED) + { + SDLInputManager* mgr = static_cast(Input::getManager()); + if (mgr) + mgr->processEvent(evt); + continue; + } switch(evt.type) { case SDL_QUIT: @@ -356,15 +364,16 @@ void PlatformWindowManagerSDL::_process() case(SDL_DROPCOMPLETE): { - if (!Con::isFunction("onDropEnd")) - break; - - Con::executef("onDropEnd"); + if (Con::isFunction("onDropEnd")) + Con::executef("onDropEnd"); + break; } default: { - //Con::printf("Event: %d", evt.type); +#ifdef TORQUE_DEBUG + Con::warnf("Unhandled SDL input event: 0x%04x", evt.type); +#endif } } } From 951e302cb1c974cbb4c83de477ab5919bf3428d8 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Mon, 28 Jan 2019 21:04:51 -0600 Subject: [PATCH 38/75] corrects a copy-corruption flaw with GuiSwatchButtonCtrl::onMouseDragged pretty sure the offending leak-line creeps in with https://github.com/GarageGames/Torque3D/blob/561f010f2e6411d8253d23f0cfcff794e81f60bf/Templates/BaseGame/game/tools/base/utils/swatchButtons.ed.cs#L34 comparative release/debug results in string gridBitmap = "\c0" vs string gridBitmap = "ic\c1Gl\c0" and the relavent initpersistfields entry of TypeString points to https://github.com/GarageGames/Torque3D/blob/561f010f2e6411d8253d23f0cfcff794e81f60bf/Engine/source/console/consoleTypes.h#L71 which is likely causing malformation --- Engine/source/gui/buttons/guiSwatchButtonCtrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/source/gui/buttons/guiSwatchButtonCtrl.cpp b/Engine/source/gui/buttons/guiSwatchButtonCtrl.cpp index 686ba0b04..7db73a05e 100644 --- a/Engine/source/gui/buttons/guiSwatchButtonCtrl.cpp +++ b/Engine/source/gui/buttons/guiSwatchButtonCtrl.cpp @@ -72,7 +72,7 @@ GuiSwatchButtonCtrl::GuiSwatchButtonCtrl() void GuiSwatchButtonCtrl::initPersistFields() { addField("color", TypeColorF, Offset(mSwatchColor, GuiSwatchButtonCtrl), "The foreground color of GuiSwatchButtonCtrl"); - addField( "gridBitmap", TypeString, Offset( mGridBitmap, GuiSwatchButtonCtrl ), "The bitmap used for the transparent grid" ); + addField( "gridBitmap", TypeRealString, Offset( mGridBitmap, GuiSwatchButtonCtrl ), "The bitmap used for the transparent grid" ); Parent::initPersistFields(); } From 86947228d56c1d3e24f27352c0b029b2363a2aab Mon Sep 17 00:00:00 2001 From: Azaezel Date: Thu, 31 Jan 2019 06:45:10 -0600 Subject: [PATCH 39/75] nextfreemask does nothing for proximity mines as there are no subclasses on this chain, but does bump it's enum value over the limit with the new addition to sceneobject. so killed it. --- Engine/source/T3D/proximityMine.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Engine/source/T3D/proximityMine.h b/Engine/source/T3D/proximityMine.h index b14f5051a..7b448e628 100644 --- a/Engine/source/T3D/proximityMine.h +++ b/Engine/source/T3D/proximityMine.h @@ -72,8 +72,7 @@ class ProximityMine: public Item protected: enum MaskBits { DeployedMask = Parent::NextFreeMask, - ExplosionMask = Parent::NextFreeMask << 1, - NextFreeMask = Parent::NextFreeMask << 2 + ExplosionMask = Parent::NextFreeMask << 1 }; enum State From e6ffe181f399fde363641eac7ff4cf4fdc921cab Mon Sep 17 00:00:00 2001 From: Areloch Date: Fri, 1 Feb 2019 23:32:28 -0600 Subject: [PATCH 40/75] Update audioEnvironments.cs Fixed a typo and spacing issues(as much as github allows) --- .../core/scripts/client/audioEnvironments.cs | 2380 ++++++++--------- 1 file changed, 1190 insertions(+), 1190 deletions(-) diff --git a/Templates/Full/game/core/scripts/client/audioEnvironments.cs b/Templates/Full/game/core/scripts/client/audioEnvironments.cs index 71050d8c4..b2c70d589 100644 --- a/Templates/Full/game/core/scripts/client/audioEnvironments.cs +++ b/Templates/Full/game/core/scripts/client/audioEnvironments.cs @@ -26,1364 +26,1364 @@ singleton SFXEnvironment(Generic) { -reverbDensity = "1.000"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.8913"; -reverbGainLF = "1.000"; -reverbDecayTime = "1.4900"; -reverbDecayHFRatio = "0.8300"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.0500"; -reflectionDelay = "0.0070"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.2589"; -lateReverbDelay = "0.0110"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.8913"; + reverbGainLF = "1.000"; + reverbDecayTime = "1.4900"; + reverbDecayHFRatio = "0.8300"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.0500"; + reflectionDelay = "0.0070"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.2589"; + lateReverbDelay = "0.0110"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PaddedCell) { -reverbDensity = "0.1715"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.0010"; -reverbGainLF = "1.000"; -reverbDecayTime = "0.1700"; -reverbDecayHFRatio = "0.1000"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.2500"; -reflectionDelay = "0.0010"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.2691"; -lateReverbDelay = "0.0020"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.1715"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.0010"; + reverbGainLF = "1.000"; + reverbDecayTime = "0.1700"; + reverbDecayHFRatio = "0.1000"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.2500"; + reflectionDelay = "0.0010"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.2691"; + lateReverbDelay = "0.0020"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetRoom) { -reverbDensity = "0.4287"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.5929"; -reverbGainLF = "1.000"; -reverbDecayTime = "0.4000"; -reverbDecayHFRatio = "0.8300"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.1503"; -reflectionDelay = "0.0020"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.0629"; -lateReverbDelay = "0.0030"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.4287"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.5929"; + reverbGainLF = "1.000"; + reverbDecayTime = "0.4000"; + reverbDecayHFRatio = "0.8300"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.1503"; + reflectionDelay = "0.0020"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.0629"; + lateReverbDelay = "0.0030"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetBathroom) { -reverbDensity = "0.1715"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.2512"; -reverbGainLF = "1.000"; -reverbDecayTime = "1.4900"; -reverbDecayHFRatio = "0.5400"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.6531"; -reflectionDelay = "0.0070"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "3.2734"; -lateReverbDelay = "0.0110"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.1715"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.2512"; + reverbGainLF = "1.000"; + reverbDecayTime = "1.4900"; + reverbDecayHFRatio = "0.5400"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.6531"; + reflectionDelay = "0.0070"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "3.2734"; + lateReverbDelay = "0.0110"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetLivingroom) { -reverbDensity = "0.9766"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.0010"; -reverbGainLF = "1.0000"; -reverbDecayTime = "0.0900"; -reverbDecayHFRatio = "0.5000"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.2051"; -reflectionDelay = "0.0030"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.2805"; -lateReverbDelay = "0.0040"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.9766"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.0010"; + reverbGainLF = "1.0000"; + reverbDecayTime = "0.0900"; + reverbDecayHFRatio = "0.5000"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.2051"; + reflectionDelay = "0.0030"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.2805"; + lateReverbDelay = "0.0040"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetStoneroom) { -reverbDensity = "1.000"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.7079"; -reverbGainLF = "1.0000"; -reverbDecayTime = "2.3100"; -reverbDecayHFRatio = "0.6400"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.4411"; -reflectionDelay = "0.0120"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.1003"; -lateReverbDelay = "0.0170"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.7079"; + reverbGainLF = "1.0000"; + reverbDecayTime = "2.3100"; + reverbDecayHFRatio = "0.6400"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.4411"; + reflectionDelay = "0.0120"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.1003"; + lateReverbDelay = "0.0170"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetAuditorium) { -reverbDensity = "1.000"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.5781"; -reverbGainLF = "1.0000"; -reverbDecayTime = "4.3200"; -reverbDecayHFRatio = "0.5900"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.4032"; -reflectionDelay = "0.0200"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.7170"; -lateReverbDelay = "0.0300"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.5781"; + reverbGainLF = "1.0000"; + reverbDecayTime = "4.3200"; + reverbDecayHFRatio = "0.5900"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.4032"; + reflectionDelay = "0.0200"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.7170"; + lateReverbDelay = "0.0300"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetConcerthall) { -reverbDensity = "1.000"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.5632"; -reverbGainLF = "1.0000"; -reverbDecayTime = "3.9200"; -reverbDecayHFRatio = "0.7000"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.2427"; -reflectionDelay = "0.0200"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.9977"; -lateReverbDelay = "0.0290"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.5632"; + reverbGainLF = "1.0000"; + reverbDecayTime = "3.9200"; + reverbDecayHFRatio = "0.7000"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.2427"; + reflectionDelay = "0.0200"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.9977"; + lateReverbDelay = "0.0290"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetCave) { -reverbDensity = "1.000"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "1.000"; -reverbGainLF = "1.0000"; -reverbDecayTime = "2.9100"; -reverbDecayHFRatio = "1.3000"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.5000"; -reflectionDelay = "0.0250"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.7063"; -lateReverbDelay = "0.0220"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "0"; + reverbDensity = "1.000"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "1.000"; + reverbGainLF = "1.0000"; + reverbDecayTime = "2.9100"; + reverbDecayHFRatio = "1.3000"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.5000"; + reflectionDelay = "0.0250"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.7063"; + lateReverbDelay = "0.0220"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "0"; }; singleton SFXEnvironment(PresetArena) { -reverbDensity = "1.000"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.4477"; -reverbGainLF = "1.0000"; -reverbDecayTime = "7.2400"; -reverbDecayHFRatio = "0.3300"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.2612"; -reflectionDelay = "0.0200"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.0186"; -lateReverbDelay = "0.0300"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.4477"; + reverbGainLF = "1.0000"; + reverbDecayTime = "7.2400"; + reverbDecayHFRatio = "0.3300"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.2612"; + reflectionDelay = "0.0200"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.0186"; + lateReverbDelay = "0.0300"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetHangar) { -reverbDensity = "1.000"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.3162"; -reverbGainLF = "1.0000"; -reverbDecayTime = "10.0500"; -reverbDecayHFRatio = "0.2300"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.5000"; -reflectionDelay = "0.0200"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.2560"; -lateReverbDelay = "0.0300"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.3162"; + reverbGainLF = "1.0000"; + reverbDecayTime = "10.0500"; + reverbDecayHFRatio = "0.2300"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.5000"; + reflectionDelay = "0.0200"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.2560"; + lateReverbDelay = "0.0300"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetCarpetedHall) { -reverbDensity = "0.4287"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.0100"; -reverbGainLF = "1.0000"; -reverbDecayTime = "0.3000"; -reverbDecayHFRatio = "0.1000"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.1215"; -reflectionDelay = "0.0020"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.1531"; -lateReverbDelay = "0.0300"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.4287"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.0100"; + reverbGainLF = "1.0000"; + reverbDecayTime = "0.3000"; + reverbDecayHFRatio = "0.1000"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.1215"; + reflectionDelay = "0.0020"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.1531"; + lateReverbDelay = "0.0300"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetHallway) { -reverbDensity = "0.3645"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.7079"; -reverbGainLF = "1.0000"; -reverbDecayTime = "1.4900"; -reverbDecayHFRatio = "0.5900"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.2458"; -reflectionDelay = "0.0070"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.6615"; -lateReverbDelay = "0.0110"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.3645"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.7079"; + reverbGainLF = "1.0000"; + reverbDecayTime = "1.4900"; + reverbDecayHFRatio = "0.5900"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.2458"; + reflectionDelay = "0.0070"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.6615"; + lateReverbDelay = "0.0110"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetStoneCorridor) { -reverbDensity = "1.000"; -reverbDiffusion = "1.000"; -reverbGain = "0.3162"; -reverbGainHF = "0.7612"; -reverbGainLF = "1.0000"; -reverbDecayTime = "2.7000"; -reverbDecayHFRatio = "0.7900"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.2472"; -reflectionDelay = "0.0130"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.5758"; -lateReverbDelay = "0.0200"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "1.000"; + reverbGain = "0.3162"; + reverbGainHF = "0.7612"; + reverbGainLF = "1.0000"; + reverbDecayTime = "2.7000"; + reverbDecayHFRatio = "0.7900"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.2472"; + reflectionDelay = "0.0130"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.5758"; + lateReverbDelay = "0.0200"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetStoneAlley) { -reverbDensity = "1.000"; -reverbDiffusion = "0.300"; -reverbGain = "0.3162"; -reverbGainHF = "0.7328"; -reverbGainLF = "1.0000"; -reverbDecayTime = "1.4900"; -reverbDecayHFRatio = "0.8600"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.2500"; -reflectionDelay = "0.0070"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.9954"; -lateReverbDelay = "0.0110"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1250"; -reverbEchoDepth = "0.9500"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "0.300"; + reverbGain = "0.3162"; + reverbGainHF = "0.7328"; + reverbGainLF = "1.0000"; + reverbDecayTime = "1.4900"; + reverbDecayHFRatio = "0.8600"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.2500"; + reflectionDelay = "0.0070"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.9954"; + lateReverbDelay = "0.0110"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1250"; + reverbEchoDepth = "0.9500"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; -singleton SFXEnvironment(PresetFroest) +singleton SFXEnvironment(PresetForest) { -reverbDensity = "1.000"; -reverbDiffusion = "0.300"; -reverbGain = "0.3162"; -reverbGainHF = "0.0224"; -reverbGainLF = "1.0000"; -reverbDecayTime = "1.4900"; -reverbDecayHFRatio = "0.5400"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.0525"; -reflectionDelay = "0.1620"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.7682"; -lateReverbDelay = "0.0880"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1250"; -reverbEchoDepth = "1.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "0.300"; + reverbGain = "0.3162"; + reverbGainHF = "0.0224"; + reverbGainLF = "1.0000"; + reverbDecayTime = "1.4900"; + reverbDecayHFRatio = "0.5400"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.0525"; + reflectionDelay = "0.1620"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.7682"; + lateReverbDelay = "0.0880"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1250"; + reverbEchoDepth = "1.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetCity) { -reverbDensity = "1.000"; -reverbDiffusion = "0.500"; -reverbGain = "0.3162"; -reverbGainHF = "0.3981"; -reverbGainLF = "1.0000"; -reverbDecayTime = "1.4900"; -reverbDecayHFRatio = "0.6700"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.0730"; -reflectionDelay = "0.0070"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.1427"; -lateReverbDelay = "0.0110"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1250"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "0.500"; + reverbGain = "0.3162"; + reverbGainHF = "0.3981"; + reverbGainLF = "1.0000"; + reverbDecayTime = "1.4900"; + reverbDecayHFRatio = "0.6700"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.0730"; + reflectionDelay = "0.0070"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.1427"; + lateReverbDelay = "0.0110"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1250"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetMountains) { -reverbDensity = "1.000"; -reverbDiffusion = "0.2700"; -reverbGain = "0.3162"; -reverbGainHF = "0.0562"; -reverbGainLF = "1.0000"; -reverbDecayTime = "1.4900"; -reverbDecayHFRatio = "0.2100"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.0407"; -reflectionDelay = "0.3000"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.1919"; -lateReverbDelay = "0.1000"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1250"; -reverbEchoDepth = "1.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "0"; + reverbDensity = "1.000"; + reverbDiffusion = "0.2700"; + reverbGain = "0.3162"; + reverbGainHF = "0.0562"; + reverbGainLF = "1.0000"; + reverbDecayTime = "1.4900"; + reverbDecayHFRatio = "0.2100"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.0407"; + reflectionDelay = "0.3000"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.1919"; + lateReverbDelay = "0.1000"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1250"; + reverbEchoDepth = "1.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "0"; }; singleton SFXEnvironment(PresetQuarry) { -reverbDensity = "1.000"; -reverbDiffusion = "1.0000"; -reverbGain = "0.3162"; -reverbGainHF = "0.3162"; -reverbGainLF = "1.0000"; -reverbDecayTime = "1.4900"; -reverbDecayHFRatio = "0.8300"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.0000"; -reflectionDelay = "0.0610"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.7783"; -lateReverbDelay = "0.0250"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1250"; -reverbEchoDepth = "0.7000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "1.0000"; + reverbGain = "0.3162"; + reverbGainHF = "0.3162"; + reverbGainLF = "1.0000"; + reverbDecayTime = "1.4900"; + reverbDecayHFRatio = "0.8300"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.0000"; + reflectionDelay = "0.0610"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.7783"; + lateReverbDelay = "0.0250"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1250"; + reverbEchoDepth = "0.7000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetPlain) { -reverbDensity = "1.000"; -reverbDiffusion = "0.2100"; -reverbGain = "0.3162"; -reverbGainHF = "0.1000"; -reverbGainLF = "1.0000"; -reverbDecayTime = "1.4900"; -reverbDecayHFRatio = "0.5000"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.0585"; -reflectionDelay = "0.1790"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.1089"; -lateReverbDelay = "0.1000"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "1.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.000"; + reverbDiffusion = "0.2100"; + reverbGain = "0.3162"; + reverbGainHF = "0.1000"; + reverbGainLF = "1.0000"; + reverbDecayTime = "1.4900"; + reverbDecayHFRatio = "0.5000"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.0585"; + reflectionDelay = "0.1790"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.1089"; + lateReverbDelay = "0.1000"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "1.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetParkinglot) { -reverbDensity = "1.000"; -reverbDiffusion = "1.0000"; -reverbGain = "0.3162"; -reverbGainHF = "1.0000"; -reverbGainLF = "1.0000"; -reverbDecayTime = "1.6500"; -reverbDecayHFRatio = "1.5000"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.2082"; -reflectionDelay = "0.0080"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.2652"; -lateReverbDelay = "0.0120"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "0"; + reverbDensity = "1.000"; + reverbDiffusion = "1.0000"; + reverbGain = "0.3162"; + reverbGainHF = "1.0000"; + reverbGainLF = "1.0000"; + reverbDecayTime = "1.6500"; + reverbDecayHFRatio = "1.5000"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.2082"; + reflectionDelay = "0.0080"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.2652"; + lateReverbDelay = "0.0120"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "0"; }; singleton SFXEnvironment(PresetSewerpipe) { -reverbDensity = "0.3071"; -reverbDiffusion = "0.8000"; -reverbGain = "0.3162"; -reverbGainHF = "0.3162"; -reverbGainLF = "1.0000"; -reverbDecayTime = "2.8100"; -reverbDecayHFRatio = "0.1400"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "1.6387"; -reflectionDelay = "0.0140"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "3.2471"; -lateReverbDelay = "0.0210"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.3071"; + reverbDiffusion = "0.8000"; + reverbGain = "0.3162"; + reverbGainHF = "0.3162"; + reverbGainLF = "1.0000"; + reverbDecayTime = "2.8100"; + reverbDecayHFRatio = "0.1400"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "1.6387"; + reflectionDelay = "0.0140"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "3.2471"; + lateReverbDelay = "0.0210"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetUnderwater) { -reverbDensity = "0.3645"; -reverbDiffusion = "1.0000"; -reverbGain = "0.3162"; -reverbGainHF = "0.0100"; -reverbGainLF = "1.0000"; -reverbDecayTime = "1.4900"; -reverbDecayHFRatio = "0.1000"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.5963"; -reflectionDelay = "0.0070"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "7.0795"; -lateReverbDelay = "0.0110"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "1.1800"; -reverbModDepth = "0.3480"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.3645"; + reverbDiffusion = "1.0000"; + reverbGain = "0.3162"; + reverbGainHF = "0.0100"; + reverbGainLF = "1.0000"; + reverbDecayTime = "1.4900"; + reverbDecayHFRatio = "0.1000"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.5963"; + reflectionDelay = "0.0070"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "7.0795"; + lateReverbDelay = "0.0110"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "1.1800"; + reverbModDepth = "0.3480"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(PresetDrugged) { -reverbDensity = "0.4287"; -reverbDiffusion = "0.5000"; -reverbGain = "0.3162"; -reverbGainHF = "1.0000"; -reverbGainLF = "1.0000"; -reverbDecayTime = "8.3900"; -reverbDecayHFRatio = "1.3900"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.8760"; -reflectionDelay = "0.0020"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "3.1081"; -lateReverbDelay = "0.0300"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "1.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "0"; + reverbDensity = "0.4287"; + reverbDiffusion = "0.5000"; + reverbGain = "0.3162"; + reverbGainHF = "1.0000"; + reverbGainLF = "1.0000"; + reverbDecayTime = "8.3900"; + reverbDecayHFRatio = "1.3900"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.8760"; + reflectionDelay = "0.0020"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "3.1081"; + lateReverbDelay = "0.0300"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "1.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "0"; }; singleton SFXEnvironment(PresetDizzy) { -reverbDensity = "0.3645"; -reverbDiffusion = "0.6000"; -reverbGain = "0.3162"; -reverbGainHF = "0.6310"; -reverbGainLF = "1.0000"; -reverbDecayTime = "17.2300"; -reverbDecayHFRatio = "0.5600"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.1392"; -reflectionDelay = "0.0200"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.4937"; -lateReverbDelay = "0.0300"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "1.0000"; -reverbModTime = "0.8100"; -reverbModDepth = "0.3100"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "0"; + reverbDensity = "0.3645"; + reverbDiffusion = "0.6000"; + reverbGain = "0.3162"; + reverbGainHF = "0.6310"; + reverbGainLF = "1.0000"; + reverbDecayTime = "17.2300"; + reverbDecayHFRatio = "0.5600"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.1392"; + reflectionDelay = "0.0200"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.4937"; + lateReverbDelay = "0.0300"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "1.0000"; + reverbModTime = "0.8100"; + reverbModDepth = "0.3100"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "0"; }; singleton SFXEnvironment(PresetPsychotic) { -reverbDensity = "0.0625"; -reverbDiffusion = "0.5000"; -reverbGain = "0.3162"; -reverbGainHF = "0.8404"; -reverbGainLF = "1.0000"; -reverbDecayTime = "7.5600"; -reverbDecayHFRatio = "0.9100"; -reverbDecayLFRatio = "1.0000"; -reflectionsGain = "0.4864"; -reflectionDelay = "0.0200"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "2.4378"; -lateReverbDelay = "0.0300"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "4.0000"; -reverbModDepth = "1.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "0"; + reverbDensity = "0.0625"; + reverbDiffusion = "0.5000"; + reverbGain = "0.3162"; + reverbGainHF = "0.8404"; + reverbGainLF = "1.0000"; + reverbDecayTime = "7.5600"; + reverbDecayHFRatio = "0.9100"; + reverbDecayLFRatio = "1.0000"; + reflectionsGain = "0.4864"; + reflectionDelay = "0.0200"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "2.4378"; + lateReverbDelay = "0.0300"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "4.0000"; + reverbModDepth = "1.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "0"; }; singleton SFXEnvironment(CastleSmallroom) { -reverbDensity = "1.0000"; -reverbDiffusion = "0.8900"; -reverbGain = "0.3162"; -reverbGainHF = "0.3981"; -reverbGainLF = "0.1000"; -reverbDecayTime = "1.2200"; -reverbDecayHFRatio = "0.8300"; -reverbDecayLFRatio = "0.3100"; -reflectionsGain = "0.8913"; -reflectionDelay = "0.0220"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.9953"; -lateReverbDelay = "0.0110"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1380"; -reverbEchoDepth = "0.0800"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.0000"; + reverbDiffusion = "0.8900"; + reverbGain = "0.3162"; + reverbGainHF = "0.3981"; + reverbGainLF = "0.1000"; + reverbDecayTime = "1.2200"; + reverbDecayHFRatio = "0.8300"; + reverbDecayLFRatio = "0.3100"; + reflectionsGain = "0.8913"; + reflectionDelay = "0.0220"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.9953"; + lateReverbDelay = "0.0110"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1380"; + reverbEchoDepth = "0.0800"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(CastleShortPassage) { -reverbDensity = "1.0000"; -reverbDiffusion = "0.8900"; -reverbGain = "0.3162"; -reverbGainHF = "0.3162"; -reverbGainLF = "0.1000"; -reverbDecayTime = "2.3200"; -reverbDecayHFRatio = "0.8300"; -reverbDecayLFRatio = "0.3100"; -reflectionsGain = "0.8913"; -reflectionDelay = "0.0070"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.2589"; -lateReverbDelay = "0.0230"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1380"; -reverbEchoDepth = "0.0800"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5168.0001"; -reverbLFRef = "139.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.0000"; + reverbDiffusion = "0.8900"; + reverbGain = "0.3162"; + reverbGainHF = "0.3162"; + reverbGainLF = "0.1000"; + reverbDecayTime = "2.3200"; + reverbDecayHFRatio = "0.8300"; + reverbDecayLFRatio = "0.3100"; + reflectionsGain = "0.8913"; + reflectionDelay = "0.0070"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.2589"; + lateReverbDelay = "0.0230"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1380"; + reverbEchoDepth = "0.0800"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5168.0001"; + reverbLFRef = "139.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(CastleMediumRoom) { -reverbDensity = "1.0000"; -reverbDiffusion = "0.9300"; -reverbGain = "0.3162"; -reverbGainHF = "0.2818"; -reverbGainLF = "0.1000"; -reverbDecayTime = "2.0400"; -reverbDecayHFRatio = "0.8300"; -reverbDecayLFRatio = "0.4600"; -reflectionsGain = "0.6310"; -reflectionDelay = "0.0220"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.5849"; -lateReverbDelay = "0.0110"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1550"; -reverbEchoDepth = "0.0300"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5168.0001"; -reverbLFRef = "139.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.0000"; + reverbDiffusion = "0.9300"; + reverbGain = "0.3162"; + reverbGainHF = "0.2818"; + reverbGainLF = "0.1000"; + reverbDecayTime = "2.0400"; + reverbDecayHFRatio = "0.8300"; + reverbDecayLFRatio = "0.4600"; + reflectionsGain = "0.6310"; + reflectionDelay = "0.0220"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.5849"; + lateReverbDelay = "0.0110"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1550"; + reverbEchoDepth = "0.0300"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5168.0001"; + reverbLFRef = "139.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(CastleLargeRoom) { -reverbDensity = "1.0000"; -reverbDiffusion = "0.8200"; -reverbGain = "0.3162"; -reverbGainHF = "0.2818"; -reverbGainLF = "0.1259"; -reverbDecayTime = "2.5300"; -reverbDecayHFRatio = "0.8300"; -reverbDecayLFRatio = "0.5000"; -reflectionsGain = "0.4467"; -reflectionDelay = "0.0340"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.2589"; -lateReverbDelay = "0.0160"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1850"; -reverbEchoDepth = "0.0700"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5168.0001"; -reverbLFRef = "139.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.0000"; + reverbDiffusion = "0.8200"; + reverbGain = "0.3162"; + reverbGainHF = "0.2818"; + reverbGainLF = "0.1259"; + reverbDecayTime = "2.5300"; + reverbDecayHFRatio = "0.8300"; + reverbDecayLFRatio = "0.5000"; + reflectionsGain = "0.4467"; + reflectionDelay = "0.0340"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.2589"; + lateReverbDelay = "0.0160"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1850"; + reverbEchoDepth = "0.0700"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5168.0001"; + reverbLFRef = "139.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(CastleLongPassage) { -reverbDensity = "1.0000"; -reverbDiffusion = "0.8900"; -reverbGain = "0.3162"; -reverbGainHF = "0.3981"; -reverbGainLF = "0.1000"; -reverbDecayTime = "3.4200"; -reverbDecayHFRatio = "0.8300"; -reverbDecayLFRatio = "0.3100"; -reflectionsGain = "0.8913"; -reflectionDelay = "0.0070"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.4125"; -lateReverbDelay = "0.0230"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1380"; -reverbEchoDepth = "0.0800"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5168.0001"; -reverbLFRef = "139.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.0000"; + reverbDiffusion = "0.8900"; + reverbGain = "0.3162"; + reverbGainHF = "0.3981"; + reverbGainLF = "0.1000"; + reverbDecayTime = "3.4200"; + reverbDecayHFRatio = "0.8300"; + reverbDecayLFRatio = "0.3100"; + reflectionsGain = "0.8913"; + reflectionDelay = "0.0070"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.4125"; + lateReverbDelay = "0.0230"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1380"; + reverbEchoDepth = "0.0800"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5168.0001"; + reverbLFRef = "139.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(CastleHall) { -reverbDensity = "1.0000"; -reverbDiffusion = "0.8100"; -reverbGain = "0.3162"; -reverbGainHF = "0.2818"; -reverbGainLF = "0.1778"; -reverbDecayTime = "3.1400"; -reverbDecayHFRatio = "0.7900"; -reverbDecayLFRatio = "0.6200"; -reflectionsGain = "0.1778"; -reflectionDelay = "0.0560"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.1220"; -lateReverbDelay = "0.0240"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5168.0001"; -reverbLFRef = "139.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.0000"; + reverbDiffusion = "0.8100"; + reverbGain = "0.3162"; + reverbGainHF = "0.2818"; + reverbGainLF = "0.1778"; + reverbDecayTime = "3.1400"; + reverbDecayHFRatio = "0.7900"; + reverbDecayLFRatio = "0.6200"; + reflectionsGain = "0.1778"; + reflectionDelay = "0.0560"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.1220"; + lateReverbDelay = "0.0240"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5168.0001"; + reverbLFRef = "139.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(CastleCupboard) { -reverbDensity = "1.0000"; -reverbDiffusion = "0.8900"; -reverbGain = "0.3162"; -reverbGainHF = "0.2818"; -reverbGainLF = "0.1000"; -reverbDecayTime = "0.6700"; -reverbDecayHFRatio = "0.8700"; -reverbDecayLFRatio = "0.3100"; -reflectionsGain = "1.4125"; -reflectionDelay = "0.0100"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "3.5481"; -lateReverbDelay = "0.0070"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1380"; -reverbEchoDepth = "0.0800"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5168.0001"; -reverbLFRef = "139.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.0000"; + reverbDiffusion = "0.8900"; + reverbGain = "0.3162"; + reverbGainHF = "0.2818"; + reverbGainLF = "0.1000"; + reverbDecayTime = "0.6700"; + reverbDecayHFRatio = "0.8700"; + reverbDecayLFRatio = "0.3100"; + reflectionsGain = "1.4125"; + reflectionDelay = "0.0100"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "3.5481"; + lateReverbDelay = "0.0070"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1380"; + reverbEchoDepth = "0.0800"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5168.0001"; + reverbLFRef = "139.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(CastleCourtyard) { -reverbDensity = "1.0000"; -reverbDiffusion = "0.4200"; -reverbGain = "0.3162"; -reverbGainHF = "0.4467"; -reverbGainLF = "0.1995"; -reverbDecayTime = "2.1300"; -reverbDecayHFRatio = "0.6100"; -reverbDecayLFRatio = "0.2300"; -reflectionsGain = "0.2239"; -reflectionDelay = "0.1600"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.7079"; -lateReverbDelay = "0.0360"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.3700"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5000.0000"; -reverbLFRef = "250.0000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "0"; + reverbDensity = "1.0000"; + reverbDiffusion = "0.4200"; + reverbGain = "0.3162"; + reverbGainHF = "0.4467"; + reverbGainLF = "0.1995"; + reverbDecayTime = "2.1300"; + reverbDecayHFRatio = "0.6100"; + reverbDecayLFRatio = "0.2300"; + reflectionsGain = "0.2239"; + reflectionDelay = "0.1600"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.7079"; + lateReverbDelay = "0.0360"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.3700"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5000.0000"; + reverbLFRef = "250.0000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "0"; }; singleton SFXEnvironment(CastleAlcove) { -reverbDensity = "1.0000"; -reverbDiffusion = "0.8900"; -reverbGain = "0.3162"; -reverbGainHF = "0.5012"; -reverbGainLF = "0.1000"; -reverbDecayTime = "1.6400"; -reverbDecayHFRatio = "0.8700"; -reverbDecayLFRatio = "0.3100"; -reflectionsGain = "1.0000"; -reflectionDelay = "0.0070"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.4125"; -lateReverbDelay = "0.0340"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1380"; -reverbEchoDepth = "0.0800"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "5168.0001"; -reverbLFRef = "139.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "1.0000"; + reverbDiffusion = "0.8900"; + reverbGain = "0.3162"; + reverbGainHF = "0.5012"; + reverbGainLF = "0.1000"; + reverbDecayTime = "1.6400"; + reverbDecayHFRatio = "0.8700"; + reverbDecayLFRatio = "0.3100"; + reflectionsGain = "1.0000"; + reflectionDelay = "0.0070"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.4125"; + lateReverbDelay = "0.0340"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1380"; + reverbEchoDepth = "0.0800"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "5168.0001"; + reverbLFRef = "139.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(FactorySmallRoom) { -reverbDensity = "0.3645"; -reverbDiffusion = "0.8200"; -reverbGain = "0.3162"; -reverbGainHF = "0.7943"; -reverbGainLF = "0.5012"; -reverbDecayTime = "1.7200"; -reverbDecayHFRatio = "0.6500"; -reverbDecayLFRatio = "1.3100"; -reflectionsGain = "0.7079"; -reflectionDelay = "0.0100"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.7783"; -lateReverbDelay = "0.0240"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1190"; -reverbEchoDepth = "0.0700"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "3762.6001"; -reverbLFRef = "362.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.3645"; + reverbDiffusion = "0.8200"; + reverbGain = "0.3162"; + reverbGainHF = "0.7943"; + reverbGainLF = "0.5012"; + reverbDecayTime = "1.7200"; + reverbDecayHFRatio = "0.6500"; + reverbDecayLFRatio = "1.3100"; + reflectionsGain = "0.7079"; + reflectionDelay = "0.0100"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.7783"; + lateReverbDelay = "0.0240"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1190"; + reverbEchoDepth = "0.0700"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "3762.6001"; + reverbLFRef = "362.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(FactoryShortPassage) { -reverbDensity = "0.3645"; -reverbDiffusion = "0.6400"; -reverbGain = "0.2512"; -reverbGainHF = "0.7943"; -reverbGainLF = "0.5012"; -reverbDecayTime = "2.5300"; -reverbDecayHFRatio = "0.6500"; -reverbDecayLFRatio = "1.3100"; -reflectionsGain = "1.0000"; -reflectionDelay = "0.0100"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.2589"; -lateReverbDelay = "0.0380"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1350"; -reverbEchoDepth = "0.2300"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "3762.6001"; -reverbLFRef = "362.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.3645"; + reverbDiffusion = "0.6400"; + reverbGain = "0.2512"; + reverbGainHF = "0.7943"; + reverbGainLF = "0.5012"; + reverbDecayTime = "2.5300"; + reverbDecayHFRatio = "0.6500"; + reverbDecayLFRatio = "1.3100"; + reflectionsGain = "1.0000"; + reflectionDelay = "0.0100"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.2589"; + lateReverbDelay = "0.0380"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1350"; + reverbEchoDepth = "0.2300"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "3762.6001"; + reverbLFRef = "362.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(FactoryMediumRoom) { -reverbDensity = "0.4287"; -reverbDiffusion = "0.8200"; -reverbGain = "0.2512"; -reverbGainHF = "0.7943"; -reverbGainLF = "0.5012"; -reverbDecayTime = "2.7600"; -reverbDecayHFRatio = "0.6500"; -reverbDecayLFRatio = "1.3100"; -reflectionsGain = "0.2818"; -reflectionDelay = "0.0220"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.4125"; -lateReverbDelay = "0.0230"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1740"; -reverbEchoDepth = "0.0700"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "3762.6001"; -reverbLFRef = "362.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.4287"; + reverbDiffusion = "0.8200"; + reverbGain = "0.2512"; + reverbGainHF = "0.7943"; + reverbGainLF = "0.5012"; + reverbDecayTime = "2.7600"; + reverbDecayHFRatio = "0.6500"; + reverbDecayLFRatio = "1.3100"; + reflectionsGain = "0.2818"; + reflectionDelay = "0.0220"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.4125"; + lateReverbDelay = "0.0230"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1740"; + reverbEchoDepth = "0.0700"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "3762.6001"; + reverbLFRef = "362.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(FactoryLargeRoom) { -reverbDensity = "0.4287"; -reverbDiffusion = "0.7500"; -reverbGain = "0.2512"; -reverbGainHF = "0.7079"; -reverbGainLF = "0.6310"; -reverbDecayTime = "4.2400"; -reverbDecayHFRatio = "0.5100"; -reverbDecayLFRatio = "1.3100"; -reflectionsGain = "0.1778"; -reflectionDelay = "0.0390"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.1220"; -lateReverbDelay = "0.0230"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2310"; -reverbEchoDepth = "0.0700"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "3762.6001"; -reverbLFRef = "362.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.4287"; + reverbDiffusion = "0.7500"; + reverbGain = "0.2512"; + reverbGainHF = "0.7079"; + reverbGainLF = "0.6310"; + reverbDecayTime = "4.2400"; + reverbDecayHFRatio = "0.5100"; + reverbDecayLFRatio = "1.3100"; + reflectionsGain = "0.1778"; + reflectionDelay = "0.0390"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.1220"; + lateReverbDelay = "0.0230"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2310"; + reverbEchoDepth = "0.0700"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "3762.6001"; + reverbLFRef = "362.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(FactoryLongPassage) { -reverbDensity = "0.3645"; -reverbDiffusion = "0.6400"; -reverbGain = "0.2512"; -reverbGainHF = "0.7943"; -reverbGainLF = "0.5012"; -reverbDecayTime = "4.0000"; -reverbDecayHFRatio = "0.6500"; -reverbDecayLFRatio = "1.3100"; -reflectionsGain = "1.0000"; -reflectionDelay = "0.0200"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.2589"; -lateReverbDelay = "0.0370"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1350"; -reverbEchoDepth = "0.2300"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "3762.6001"; -reverbLFRef = "362.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.3645"; + reverbDiffusion = "0.6400"; + reverbGain = "0.2512"; + reverbGainHF = "0.7943"; + reverbGainLF = "0.5012"; + reverbDecayTime = "4.0000"; + reverbDecayHFRatio = "0.6500"; + reverbDecayLFRatio = "1.3100"; + reflectionsGain = "1.0000"; + reflectionDelay = "0.0200"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.2589"; + lateReverbDelay = "0.0370"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1350"; + reverbEchoDepth = "0.2300"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "3762.6001"; + reverbLFRef = "362.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(FactoryHall) { -reverbDensity = "0.4287"; -reverbDiffusion = "0.7500"; -reverbGain = "0.3162"; -reverbGainHF = "0.7079"; -reverbGainLF = "0.6310"; -reverbDecayTime = "7.4300"; -reverbDecayHFRatio = "0.5100"; -reverbDecayLFRatio = "1.3100"; -reflectionsGain = "0.0631"; -reflectionDelay = "0.0730"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.8913"; -lateReverbDelay = "0.0270"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.0700"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "3762.6001"; -reverbLFRef = "362.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.4287"; + reverbDiffusion = "0.7500"; + reverbGain = "0.3162"; + reverbGainHF = "0.7079"; + reverbGainLF = "0.6310"; + reverbDecayTime = "7.4300"; + reverbDecayHFRatio = "0.5100"; + reverbDecayLFRatio = "1.3100"; + reflectionsGain = "0.0631"; + reflectionDelay = "0.0730"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.8913"; + lateReverbDelay = "0.0270"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.0700"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "3762.6001"; + reverbLFRef = "362.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(FactoryCupboard) { -reverbDensity = "0.3071"; -reverbDiffusion = "0.6300"; -reverbGain = "0.2512"; -reverbGainHF = "0.7943"; -reverbGainLF = "0.5012"; -reverbDecayTime = "0.4900"; -reverbDecayHFRatio = "0.6500"; -reverbDecayLFRatio = "1.3100"; -reflectionsGain = "1.2589"; -reflectionDelay = "0.0100"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.9953"; -lateReverbDelay = "0.0320"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1070"; -reverbEchoDepth = "0.0700"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "3762.6001"; -reverbLFRef = "362.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.3071"; + reverbDiffusion = "0.6300"; + reverbGain = "0.2512"; + reverbGainHF = "0.7943"; + reverbGainLF = "0.5012"; + reverbDecayTime = "0.4900"; + reverbDecayHFRatio = "0.6500"; + reverbDecayLFRatio = "1.3100"; + reflectionsGain = "1.2589"; + reflectionDelay = "0.0100"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.9953"; + lateReverbDelay = "0.0320"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1070"; + reverbEchoDepth = "0.0700"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "3762.6001"; + reverbLFRef = "362.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(FactoryCourtyard) { -reverbDensity = "0.3071"; -reverbDiffusion = "0.5700"; -reverbGain = "0.3162"; -reverbGainHF = "0.3162"; -reverbGainLF = "0.6310"; -reverbDecayTime = "2.3200"; -reverbDecayHFRatio = "0.2900"; -reverbDecayLFRatio = "0.5600"; -reflectionsGain = "0.2239"; -reflectionDelay = "0.1400"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "0.3981"; -lateReverbDelay = "0.0390"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.2500"; -reverbEchoDepth = "0.2900"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "3762.6001"; -reverbLFRef = "362.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; + reverbDensity = "0.3071"; + reverbDiffusion = "0.5700"; + reverbGain = "0.3162"; + reverbGainHF = "0.3162"; + reverbGainLF = "0.6310"; + reverbDecayTime = "2.3200"; + reverbDecayHFRatio = "0.2900"; + reverbDecayLFRatio = "0.5600"; + reflectionsGain = "0.2239"; + reflectionDelay = "0.1400"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "0.3981"; + lateReverbDelay = "0.0390"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.2500"; + reverbEchoDepth = "0.2900"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "3762.6001"; + reverbLFRef = "362.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; }; singleton SFXEnvironment(FactoryAlcove) { -reverbDensity = "0.3645"; -reverbDiffusion = "0.5900"; -reverbGain = "0.2512"; -reverbGainHF = "0.7943"; -reverbGainLF = "0.5012"; -reverbDecayTime = "3.1400"; -reverbDecayHFRatio = "0.6500"; -reverbDecayLFRatio = "1.3100"; -reflectionsGain = "1.4125"; -reflectionDelay = "0.0100"; -reflectionsPan[ 0 ] = "0.0"; -reflectionsPan[ 1 ] = "0.0"; -reflectionsPan[ 2 ] = "0.0"; -lateReverbGain = "1.0000"; -lateReverbDelay = "0.0380"; -lateReverbPan[ 0 ] = "0.0"; -lateReverbPan[ 1 ] = "0.0"; -lateReverbPan[ 2 ] = "0.0"; -reverbEchoTime = "0.1140"; -reverbEchoDepth = "0.1000"; -reverbModTime = "0.2500"; -reverbModDepth = "0.0000"; -airAbsorbtionGainHF = "0.9943"; -reverbHFRef = "3762.6001"; -reverbLFRef = "362.5000"; -roomRolloffFactor = "0.0000"; -decayHFLimit = "1"; -}; \ No newline at end of file + reverbDensity = "0.3645"; + reverbDiffusion = "0.5900"; + reverbGain = "0.2512"; + reverbGainHF = "0.7943"; + reverbGainLF = "0.5012"; + reverbDecayTime = "3.1400"; + reverbDecayHFRatio = "0.6500"; + reverbDecayLFRatio = "1.3100"; + reflectionsGain = "1.4125"; + reflectionDelay = "0.0100"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + lateReverbGain = "1.0000"; + lateReverbDelay = "0.0380"; + lateReverbPan[ 0 ] = "0.0"; + lateReverbPan[ 1 ] = "0.0"; + lateReverbPan[ 2 ] = "0.0"; + reverbEchoTime = "0.1140"; + reverbEchoDepth = "0.1000"; + reverbModTime = "0.2500"; + reverbModDepth = "0.0000"; + airAbsorbtionGainHF = "0.9943"; + reverbHFRef = "3762.6001"; + reverbLFRef = "362.5000"; + roomRolloffFactor = "0.0000"; + decayHFLimit = "1"; +}; From fcb906d59855de15258415bdc6ab39ef8b557b67 Mon Sep 17 00:00:00 2001 From: suncaller Date: Sat, 2 Feb 2019 23:07:44 -0500 Subject: [PATCH 41/75] Clean up MSVC warning [C4305]: truncation from 'double' to 'F32' --- Engine/source/math/mConstants.h | 2 +- Engine/source/math/util/frustum.cpp | 2 +- Engine/source/scene/sceneContainer.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Engine/source/math/mConstants.h b/Engine/source/math/mConstants.h index 42b071d1e..6218e4040 100644 --- a/Engine/source/math/mConstants.h +++ b/Engine/source/math/mConstants.h @@ -44,7 +44,7 @@ #define M_CONST_E_F 2.7182818284590452353602874f -#define POINT_EPSILON (1e-4) ///< Epsilon for point types. +#define POINT_EPSILON (0.0001f) ///< Epsilon for point types. /// Result of an overlap test. diff --git a/Engine/source/math/util/frustum.cpp b/Engine/source/math/util/frustum.cpp index bfb42a6bf..2ac1824b7 100644 --- a/Engine/source/math/util/frustum.cpp +++ b/Engine/source/math/util/frustum.cpp @@ -216,7 +216,7 @@ void Frustum::setNearFarDist( F32 nearDist, F32 farDist ) // Recalculate the frustum. MatrixF xfm( mTransform ); - const F32 CENTER_EPSILON = 0.001; + const F32 CENTER_EPSILON = 0.001f; F32 centerX = mNearLeft + (mNearRight - mNearLeft) * 0.5; F32 centerY = mNearBottom + (mNearTop - mNearBottom) * 0.5; if ((centerX > CENTER_EPSILON || centerX < -CENTER_EPSILON) || (centerY > CENTER_EPSILON || centerY < -CENTER_EPSILON) ) diff --git a/Engine/source/scene/sceneContainer.cpp b/Engine/source/scene/sceneContainer.cpp index 128ef3edd..b08456b15 100644 --- a/Engine/source/scene/sceneContainer.cpp +++ b/Engine/source/scene/sceneContainer.cpp @@ -1392,7 +1392,7 @@ void SceneContainer::getBinRange( const F32 min, const F32 max, U32& minBin, U32 // This is truly lame, but it can happen. There must be a better way to // deal with this. if (minCoord == SceneContainer::csmTotalBinSize) - minCoord = SceneContainer::csmTotalBinSize - 0.01; + minCoord = SceneContainer::csmTotalBinSize - 0.01f; } AssertFatal(minCoord >= 0.0 && minCoord < SceneContainer::csmTotalBinSize, "Bad minCoord"); @@ -1415,7 +1415,7 @@ void SceneContainer::getBinRange( const F32 min, const F32 max, U32& minBin, U32 // This is truly lame, but it can happen. There must be a better way to // deal with this. if (minCoord == SceneContainer::csmTotalBinSize) - minCoord = SceneContainer::csmTotalBinSize - 0.01; + minCoord = SceneContainer::csmTotalBinSize - 0.01f; } AssertFatal(minCoord >= 0.0 && minCoord < SceneContainer::csmTotalBinSize, "Bad minCoord"); @@ -1426,7 +1426,7 @@ void SceneContainer::getBinRange( const F32 min, const F32 max, U32& minBin, U32 // This is truly lame, but it can happen. There must be a better way to // deal with this. if (maxCoord == SceneContainer::csmTotalBinSize) - maxCoord = SceneContainer::csmTotalBinSize - 0.01; + maxCoord = SceneContainer::csmTotalBinSize - 0.01f; } AssertFatal(maxCoord >= 0.0 && maxCoord < SceneContainer::csmTotalBinSize, "Bad maxCoord"); From 7f7e402c42000d577127630c9726ab39cab7fa85 Mon Sep 17 00:00:00 2001 From: suncaller Date: Sat, 2 Feb 2019 23:09:55 -0500 Subject: [PATCH 42/75] Clean up MSVC warning [C4312] conversion from type to type * of greater size --- Engine/source/T3D/fx/particleEmitter.cpp | 2 +- Engine/source/T3D/shapeBase.cpp | 2 +- Engine/source/T3D/shapeImage.cpp | 4 ++-- Engine/source/T3D/vehicles/flyingVehicle.cpp | 4 ++-- Engine/source/T3D/vehicles/hoverVehicle.cpp | 4 ++-- Engine/source/T3D/vehicles/vehicle.cpp | 2 +- Engine/source/T3D/vehicles/wheeledVehicle.cpp | 2 +- Engine/source/afx/afxEffectGroup.cpp | 2 +- Engine/source/afx/afxEffectWrapper.cpp | 2 +- Engine/source/afx/afxEffectron.cpp | 2 +- Engine/source/afx/afxMagicSpell.cpp | 4 ++-- Engine/source/afx/afxSelectron.cpp | 2 +- Engine/source/afx/afxSpellBook.cpp | 2 +- Engine/source/afx/ce/afxLightBase_T3D.cpp | 4 ++-- Engine/source/afx/ce/afxPhraseEffect.cpp | 2 +- Engine/source/forest/editor/forestUndo.cpp | 8 ++++---- Engine/source/gfx/gfxStringEnumTranslate.cpp | 4 ++-- Engine/source/gfx/gl/gfxGLPrimitiveBuffer.cpp | 2 +- Engine/source/gfx/gl/gfxGLVertexDecl.cpp | 18 +++++++++--------- Engine/source/gui/controls/guiListBoxCtrl.cpp | 4 ++-- Engine/source/ts/loader/tsShapeLoader.cpp | 2 +- 21 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Engine/source/T3D/fx/particleEmitter.cpp b/Engine/source/T3D/fx/particleEmitter.cpp index b10d88f8a..bd2256e7d 100644 --- a/Engine/source/T3D/fx/particleEmitter.cpp +++ b/Engine/source/T3D/fx/particleEmitter.cpp @@ -490,7 +490,7 @@ void ParticleEmitterData::unpackData(BitStream* stream) #if defined(AFX_CAP_PARTICLE_POOLS) if (stream->readFlag()) { - pool_datablock = (afxParticlePoolData*)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); + pool_datablock = (afxParticlePoolData*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); stream->read(&pool_index); pool_depth_fade = stream->readFlag(); pool_radial_fade = stream->readFlag(); diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index 3e88c482f..a3d6a3c66 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -3259,7 +3259,7 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream) st.play = stream->readFlag(); if ( st.play ) { - st.profile = (SFXTrack*) stream->readRangedU32( DataBlockObjectIdFirst, + st.profile = (SFXTrack*)(uintptr_t)stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); } diff --git a/Engine/source/T3D/shapeImage.cpp b/Engine/source/T3D/shapeImage.cpp index 56d413a2b..e616d6fae 100644 --- a/Engine/source/T3D/shapeImage.cpp +++ b/Engine/source/T3D/shapeImage.cpp @@ -1202,7 +1202,7 @@ void ShapeBaseImageData::unpackData(BitStream* stream) } projectile = (stream->readFlag() ? - (ProjectileData*)stream->readRangedU32(DataBlockObjectIdFirst, + (ProjectileData*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast) : 0); cloakable = stream->readFlag(); @@ -1340,7 +1340,7 @@ void ShapeBaseImageData::unpackData(BitStream* stream) if (stream->readFlag()) { - s.emitter = (ParticleEmitterData*) stream->readRangedU32(DataBlockObjectIdFirst, + s.emitter = (ParticleEmitterData*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); stream->read(&s.emitterTime); diff --git a/Engine/source/T3D/vehicles/flyingVehicle.cpp b/Engine/source/T3D/vehicles/flyingVehicle.cpp index 2ee5bc375..bb50243b2 100644 --- a/Engine/source/T3D/vehicles/flyingVehicle.cpp +++ b/Engine/source/T3D/vehicles/flyingVehicle.cpp @@ -282,14 +282,14 @@ void FlyingVehicleData::unpackData(BitStream* stream) for (S32 i = 0; i < MaxSounds; i++) { sound[i] = NULL; if (stream->readFlag()) - sound[i] = (SFXProfile*)stream->readRangedU32(DataBlockObjectIdFirst, + sound[i] = (SFXProfile*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); } for (S32 j = 0; j < MaxJetEmitters; j++) { jetEmitter[j] = NULL; if (stream->readFlag()) - jetEmitter[j] = (ParticleEmitterData*)stream->readRangedU32(DataBlockObjectIdFirst, + jetEmitter[j] = (ParticleEmitterData*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); } diff --git a/Engine/source/T3D/vehicles/hoverVehicle.cpp b/Engine/source/T3D/vehicles/hoverVehicle.cpp index 1f1d259b5..7cc204046 100644 --- a/Engine/source/T3D/vehicles/hoverVehicle.cpp +++ b/Engine/source/T3D/vehicles/hoverVehicle.cpp @@ -411,13 +411,13 @@ void HoverVehicleData::unpackData(BitStream* stream) for (S32 i = 0; i < MaxSounds; i++) sound[i] = stream->readFlag()? - (SFXProfile*) stream->readRangedU32(DataBlockObjectIdFirst, + (SFXProfile*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast): 0; for (S32 j = 0; j < MaxJetEmitters; j++) { jetEmitter[j] = NULL; if (stream->readFlag()) - jetEmitter[j] = (ParticleEmitterData*)stream->readRangedU32(DataBlockObjectIdFirst, + jetEmitter[j] = (ParticleEmitterData*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); } diff --git a/Engine/source/T3D/vehicles/vehicle.cpp b/Engine/source/T3D/vehicles/vehicle.cpp index 18a7c4466..739fd2671 100644 --- a/Engine/source/T3D/vehicles/vehicle.cpp +++ b/Engine/source/T3D/vehicles/vehicle.cpp @@ -374,7 +374,7 @@ void VehicleData::unpackData(BitStream* stream) for (i = 0; i < Body::MaxSounds; i++) { body.sound[i] = NULL; if (stream->readFlag()) - body.sound[i] = (SFXProfile*)stream->readRangedU32(DataBlockObjectIdFirst, + body.sound[i] = (SFXProfile*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); } diff --git a/Engine/source/T3D/vehicles/wheeledVehicle.cpp b/Engine/source/T3D/vehicles/wheeledVehicle.cpp index f4f272fd3..e4e7885ea 100644 --- a/Engine/source/T3D/vehicles/wheeledVehicle.cpp +++ b/Engine/source/T3D/vehicles/wheeledVehicle.cpp @@ -494,7 +494,7 @@ void WheeledVehicleData::unpackData(BitStream* stream) Parent::unpackData(stream); tireEmitter = stream->readFlag()? - (ParticleEmitterData*) stream->readRangedU32(DataBlockObjectIdFirst, + (ParticleEmitterData*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast): 0; for (S32 i = 0; i < MaxSounds; i++) diff --git a/Engine/source/afx/afxEffectGroup.cpp b/Engine/source/afx/afxEffectGroup.cpp index 749dbbddb..71c6a89b6 100644 --- a/Engine/source/afx/afxEffectGroup.cpp +++ b/Engine/source/afx/afxEffectGroup.cpp @@ -133,7 +133,7 @@ void afxEffectGroupData::unpack_fx(BitStream* stream, afxEffectList& fx) fx.clear(); S32 n_fx = stream->readInt(EFFECTS_PER_PHRASE_BITS); for (int i = 0; i < n_fx; i++) - fx.push_back((afxEffectWrapperData*)readDatablockID(stream)); + fx.push_back((afxEffectWrapperData*)(uintptr_t)readDatablockID(stream)); } #define myOffset(field) Offset(field, afxEffectGroupData) diff --git a/Engine/source/afx/afxEffectWrapper.cpp b/Engine/source/afx/afxEffectWrapper.cpp index 5906947ee..3ec9d855f 100644 --- a/Engine/source/afx/afxEffectWrapper.cpp +++ b/Engine/source/afx/afxEffectWrapper.cpp @@ -608,7 +608,7 @@ void afxEffectWrapperData::unpack_mods(BitStream* stream, afxXM_BaseData* mods[] { S32 n_mods = stream->readInt(6); for (int i = 0; i < n_mods; i++) - mods[i] = (afxXM_BaseData*) readDatablockID(stream); + mods[i] = (afxXM_BaseData*)(uintptr_t)readDatablockID(stream); } bool afxEffectWrapperData::preload(bool server, String &errorStr) diff --git a/Engine/source/afx/afxEffectron.cpp b/Engine/source/afx/afxEffectron.cpp index b1b7f7eff..cf60ede4b 100644 --- a/Engine/source/afx/afxEffectron.cpp +++ b/Engine/source/afx/afxEffectron.cpp @@ -147,7 +147,7 @@ void afxEffectronData::unpack_fx(BitStream* stream, afxEffectList& fx) fx.clear(); S32 n_fx = stream->readInt(EFFECTS_PER_PHRASE_BITS); for (int i = 0; i < n_fx; i++) - fx.push_back((afxEffectWrapperData*)readDatablockID(stream)); + fx.push_back((afxEffectWrapperData*)(uintptr_t)readDatablockID(stream)); } void afxEffectronData::packData(BitStream* stream) diff --git a/Engine/source/afx/afxMagicSpell.cpp b/Engine/source/afx/afxMagicSpell.cpp index 029e88e62..e169d70d7 100644 --- a/Engine/source/afx/afxMagicSpell.cpp +++ b/Engine/source/afx/afxMagicSpell.cpp @@ -304,7 +304,7 @@ void afxMagicSpellData::unpack_fx(BitStream* stream, afxEffectList& fx) fx.clear(); S32 n_fx = stream->readInt(EFFECTS_PER_PHRASE_BITS); for (int i = 0; i < n_fx; i++) - fx.push_back((afxEffectWrapperData*)readDatablockID(stream)); + fx.push_back((afxEffectWrapperData*)(uintptr_t)readDatablockID(stream)); } void afxMagicSpellData::packData(BitStream* stream) @@ -356,7 +356,7 @@ void afxMagicSpellData::unpackData(BitStream* stream) mDo_move_interrupts = stream->readFlag(); stream->read(&mMove_interrupt_speed); - mMissile_db = (afxMagicMissileData*) readDatablockID(stream); + mMissile_db = (afxMagicMissileData*)(uintptr_t)readDatablockID(stream); stream->read(&mLaunch_on_server_signal); stream->read(&mPrimary_target_types); diff --git a/Engine/source/afx/afxSelectron.cpp b/Engine/source/afx/afxSelectron.cpp index 81b60c836..67cd32849 100644 --- a/Engine/source/afx/afxSelectron.cpp +++ b/Engine/source/afx/afxSelectron.cpp @@ -214,7 +214,7 @@ void afxSelectronData::unpack_fx(BitStream* stream, afxEffectList& fx) fx.clear(); S32 n_fx = stream->readInt(EFFECTS_PER_PHRASE_BITS); for (int i = 0; i < n_fx; i++) - fx.push_back((afxEffectWrapperData*)readDatablockID(stream)); + fx.push_back((afxEffectWrapperData*)(uintptr_t)readDatablockID(stream)); } void afxSelectronData::packData(BitStream* stream) diff --git a/Engine/source/afx/afxSpellBook.cpp b/Engine/source/afx/afxSpellBook.cpp index cce22129b..15581ab32 100644 --- a/Engine/source/afx/afxSpellBook.cpp +++ b/Engine/source/afx/afxSpellBook.cpp @@ -128,7 +128,7 @@ void afxSpellBookData::unpackData(BitStream* stream) do_id_convert = true; for (S32 i = 0; i < pages_per_book*spells_per_page; i++) - rpg_spells[i] = (afxRPGMagicSpellData*) readDatablockID(stream); + rpg_spells[i] = (afxRPGMagicSpellData*)(uintptr_t)readDatablockID(stream); } DefineEngineMethod(afxSpellBookData, getPageSlotIndex, S32, (Point2I bookSlot),, diff --git a/Engine/source/afx/ce/afxLightBase_T3D.cpp b/Engine/source/afx/ce/afxLightBase_T3D.cpp index 56b76ccca..a6b8da051 100644 --- a/Engine/source/afx/ce/afxLightBase_T3D.cpp +++ b/Engine/source/afx/ce/afxLightBase_T3D.cpp @@ -195,8 +195,8 @@ void afxT3DLightBaseData::unpackData(BitStream* stream) stream->read( &mAnimState.animationPhase ); stream->read( &mFlareScale ); - mAnimationData = (LightAnimData*) readDatablockID(stream); - mFlareData = (LightFlareData*) readDatablockID(stream); + mAnimationData = (LightAnimData*)(uintptr_t)readDatablockID(stream); + mFlareData = (LightFlareData*)(uintptr_t)readDatablockID(stream); do_id_convert = true; } diff --git a/Engine/source/afx/ce/afxPhraseEffect.cpp b/Engine/source/afx/ce/afxPhraseEffect.cpp index 5df7dfc26..b574afbed 100644 --- a/Engine/source/afx/ce/afxPhraseEffect.cpp +++ b/Engine/source/afx/ce/afxPhraseEffect.cpp @@ -215,7 +215,7 @@ void afxPhraseEffectData::unpack_fx(BitStream* stream, afxEffectList& fx) fx.clear(); S32 n_fx = stream->readInt(EFFECTS_PER_PHRASE_BITS); for (int i = 0; i < n_fx; i++) - fx.push_back((afxEffectWrapperData*)readDatablockID(stream)); + fx.push_back((afxEffectWrapperData*)(uintptr_t)readDatablockID(stream)); } void afxPhraseEffectData::packData(BitStream* stream) diff --git a/Engine/source/forest/editor/forestUndo.cpp b/Engine/source/forest/editor/forestUndo.cpp index 60be8d2b1..603986700 100644 --- a/Engine/source/forest/editor/forestUndo.cpp +++ b/Engine/source/forest/editor/forestUndo.cpp @@ -55,7 +55,7 @@ void ForestCreateUndoAction::addItem( ForestItemData *data, // We store the datablock ID rather than the actual pointer // since the pointer could go bad. SimObjectId dataId = item.getData()->getId(); - mItems.last().setData( (ForestItemData*)dataId ); + mItems.last().setData( (ForestItemData*)(uintptr_t)dataId ); } void ForestCreateUndoAction::redo() @@ -110,7 +110,7 @@ void ForestDeleteUndoAction::removeItem( const ForestItem &item ) SimObjectId dataId = item.getData()->getId(); mItems.push_back( item ); - mItems.last().setData( (ForestItemData*)dataId ); + mItems.last().setData( (ForestItemData*)(uintptr_t)dataId ); mData->removeItem( item.getKey(), item.getPosition() ); } @@ -171,7 +171,7 @@ void ForestUpdateAction::saveItem( const ForestItem &item ) // We store the datablock ID rather than the actual pointer // since the pointer could go bad. SimObjectId dataId = item.getData()->getId(); - mItems.last().setData( (ForestItemData*)dataId ); + mItems.last().setData( (ForestItemData*)(uintptr_t)dataId ); } void ForestUpdateAction::_swapState() @@ -215,7 +215,7 @@ void ForestUpdateAction::_swapState() item.getScale() ); // Save the state before this swap for the next swap. - newItem.setData( (ForestItemData*)data->getId() ); + newItem.setData( (ForestItemData*)(uintptr_t)data->getId() ); mItems.push_back( newItem ); } diff --git a/Engine/source/gfx/gfxStringEnumTranslate.cpp b/Engine/source/gfx/gfxStringEnumTranslate.cpp index 8a3db347c..8c08c939e 100644 --- a/Engine/source/gfx/gfxStringEnumTranslate.cpp +++ b/Engine/source/gfx/gfxStringEnumTranslate.cpp @@ -77,11 +77,11 @@ _STRING_VALUE_LOOKUP_FXN(GFXStringBlendOp); #define INIT_LOOKUPTABLE( tablearray, enumprefix, type ) \ for( S32 i = enumprefix##_FIRST; i < enumprefix##_COUNT; i++ ) \ - tablearray[i] = (type)GFX_UNINIT_VAL; + tablearray[i] = (type)(uintptr_t)GFX_UNINIT_VAL; #define INIT_LOOKUPTABLE_EX( tablearray, enumprefix, type, typeTable ) \ for( S32 i = enumprefix##_FIRST; i < enumprefix##_COUNT; i++ ) \ {\ - tablearray[i] = (type)GFX_UNINIT_VAL;\ + tablearray[i] = (type)(uintptr_t)GFX_UNINIT_VAL;\ typeTable[i] = &defaultStringValueLookup;\ } diff --git a/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.cpp b/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.cpp index 385e0ed50..3df694de9 100644 --- a/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.cpp +++ b/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.cpp @@ -131,7 +131,7 @@ void GFXGLPrimitiveBuffer::finish() GLvoid* GFXGLPrimitiveBuffer::getBuffer() { // NULL specifies no offset into the hardware buffer - return (GLvoid*)mBufferOffset; + return (GLvoid*)(uintptr_t)mBufferOffset; } void GFXGLPrimitiveBuffer::zombify() diff --git a/Engine/source/gfx/gl/gfxGLVertexDecl.cpp b/Engine/source/gfx/gl/gfxGLVertexDecl.cpp index 64195164e..bfe6b6f93 100644 --- a/Engine/source/gfx/gl/gfxGLVertexDecl.cpp +++ b/Engine/source/gfx/gl/gfxGLVertexDecl.cpp @@ -130,7 +130,7 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream) glElement.normalized = false; glElement.type = GL_FLOAT; glElement.stride = vertexSize; - glElement.pointerFirst = (void*)buffer; + glElement.pointerFirst = (void*)(uintptr_t)buffer; buffer += element.getSizeInBytes(); } @@ -141,7 +141,7 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream) glElement.normalized = false; glElement.type = GL_FLOAT; glElement.stride = vertexSize; - glElement.pointerFirst = (void*)buffer; + glElement.pointerFirst = (void*)(uintptr_t)buffer; buffer += element.getSizeInBytes(); } @@ -152,7 +152,7 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream) glElement.normalized = false; glElement.type = GL_FLOAT; glElement.stride = vertexSize; - glElement.pointerFirst = (void*)buffer; + glElement.pointerFirst = (void*)(uintptr_t)buffer; buffer += element.getSizeInBytes(); } @@ -163,7 +163,7 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream) glElement.normalized = false; glElement.type = GL_FLOAT; glElement.stride = vertexSize; - glElement.pointerFirst = (void*)buffer; + glElement.pointerFirst = (void*)(uintptr_t)buffer; buffer += element.getSizeInBytes(); } @@ -174,7 +174,7 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream) glElement.normalized = false; glElement.type = GL_FLOAT; glElement.stride = vertexSize; - glElement.pointerFirst = (void*)buffer; + glElement.pointerFirst = (void*)(uintptr_t)buffer; buffer += element.getSizeInBytes(); } @@ -185,7 +185,7 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream) glElement.normalized = true; glElement.type = GL_UNSIGNED_BYTE; glElement.stride = vertexSize; - glElement.pointerFirst = (void*)buffer; + glElement.pointerFirst = (void*)(uintptr_t)buffer; buffer += element.getSizeInBytes(); } @@ -196,7 +196,7 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream) glElement.normalized = false; glElement.type = GL_FLOAT; glElement.stride = vertexSize; - glElement.pointerFirst = (void*)buffer; + glElement.pointerFirst = (void*)(uintptr_t)buffer; buffer += element.getSizeInBytes(); } @@ -207,7 +207,7 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream) glElement.normalized = false; glElement.type = GL_UNSIGNED_BYTE; glElement.stride = vertexSize; - glElement.pointerFirst = (void*)buffer; + glElement.pointerFirst = (void*)(uintptr_t)buffer; buffer += element.getSizeInBytes(); } @@ -221,7 +221,7 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream) glElement.normalized = false; glElement.type = GL_FLOAT; glElement.stride = vertexSize; - glElement.pointerFirst = (void*)buffer; + glElement.pointerFirst = (void*)(uintptr_t)buffer; buffer += element.getSizeInBytes(); ++texCoordIndex; diff --git a/Engine/source/gui/controls/guiListBoxCtrl.cpp b/Engine/source/gui/controls/guiListBoxCtrl.cpp index d47914d3d..cab79e1b0 100644 --- a/Engine/source/gui/controls/guiListBoxCtrl.cpp +++ b/Engine/source/gui/controls/guiListBoxCtrl.cpp @@ -631,7 +631,7 @@ DefineEngineMethod( GuiListBoxCtrl, addItem, S32, (const char* newItem, const ch else if(elementCount == 1) { U32 objId = dAtoi( color ); - return object->addItem( newItem, (void*)objId ); + return object->addItem( newItem, (void*)(uintptr_t)objId ); } else { @@ -1523,7 +1523,7 @@ void GuiListBoxCtrl::_mirror() if ( !found ) { - addItem( _makeMirrorItemName( curObj ), (void*)curId ); + addItem( _makeMirrorItemName( curObj ), (void*)(uintptr_t)curId ); } } } diff --git a/Engine/source/ts/loader/tsShapeLoader.cpp b/Engine/source/ts/loader/tsShapeLoader.cpp index 581f2a384..6cebbc7e0 100644 --- a/Engine/source/ts/loader/tsShapeLoader.cpp +++ b/Engine/source/ts/loader/tsShapeLoader.cpp @@ -412,7 +412,7 @@ void TSShapeLoader::generateObjects() AppMesh* mesh = subshape->objMeshes[iMesh]; mesh->detailSize = 2; String name = String::GetTrailingNumber( mesh->getName(), mesh->detailSize ); - name = getUniqueName( name, cmpMeshNameAndSize, meshNames, &(subshape->objMeshes), (void*)mesh->detailSize ); + name = getUniqueName( name, cmpMeshNameAndSize, meshNames, &(subshape->objMeshes), (void*)(uintptr_t)mesh->detailSize ); meshNames.push_back( name ); // Fix up any collision details that don't have a negative detail level. From 5e8e7e7bf88f5f0e85af50ad33536f901d4d2a54 Mon Sep 17 00:00:00 2001 From: suncaller Date: Wed, 6 Feb 2019 15:03:06 -0500 Subject: [PATCH 43/75] Clean up redundant variables --- .../T3D/components/animation/animationComponent.cpp | 2 -- Engine/source/T3D/components/camera/cameraComponent.cpp | 3 --- .../T3D/components/collision/collisionComponent.cpp | 1 - Engine/source/T3D/components/game/stateMachine.cpp | 1 - Engine/source/T3D/components/game/triggerComponent.cpp | 2 -- .../T3D/components/physics/playerControllerComponent.cpp | 5 ----- Engine/source/T3D/convexShape.cpp | 2 -- Engine/source/T3D/entity.cpp | 9 --------- Engine/source/T3D/entity.h | 1 - Engine/source/T3D/gameFunctions.cpp | 1 - Engine/source/T3D/systems/render/meshRenderSystem.cpp | 2 -- Engine/source/T3D/tsStatic.cpp | 1 - Engine/source/app/net/serverQuery.cpp | 4 +--- Engine/source/gui/controls/guiConsole.cpp | 9 --------- Engine/source/gui/editor/inspector/mountingGroup.cpp | 4 ---- Engine/source/gui/worldEditor/worldEditor.cpp | 2 -- Engine/source/platform/platformNet.cpp | 2 -- 17 files changed, 1 insertion(+), 50 deletions(-) diff --git a/Engine/source/T3D/components/animation/animationComponent.cpp b/Engine/source/T3D/components/animation/animationComponent.cpp index cb7808b8b..59ff1fbf8 100644 --- a/Engine/source/T3D/components/animation/animationComponent.cpp +++ b/Engine/source/T3D/components/animation/animationComponent.cpp @@ -621,8 +621,6 @@ void AnimationComponent::advanceThreads(F32 dt) Thread& st = mAnimationThreads[i]; if (st.thread && st.sequence != -1) { - bool cyclic = getShape()->sequences[st.sequence].isCyclic(); - if (!getShape()->sequences[st.sequence].isCyclic() && !st.atEnd && ((st.timescale > 0.f) ? mOwnerShapeInstance->getPos(st.thread) >= 1.0 : mOwnerShapeInstance->getPos(st.thread) <= 0)) diff --git a/Engine/source/T3D/components/camera/cameraComponent.cpp b/Engine/source/T3D/components/camera/cameraComponent.cpp index 2cd1b7d08..4e566bba7 100644 --- a/Engine/source/T3D/components/camera/cameraComponent.cpp +++ b/Engine/source/T3D/components/camera/cameraComponent.cpp @@ -237,8 +237,6 @@ bool CameraComponent::getCameraTransform(F32* pos,MatrixF* mat) { // Returns camera to world space transform // Handles first person / third person camera position - bool isServer = isServerObject(); - if (mTargetNodeIdx == -1) { if (mUseParentTransform) @@ -479,7 +477,6 @@ void CameraComponent::setRotation(RotationF newRot) Frustum CameraComponent::getFrustum() { Frustum visFrustum; - F32 left, right, top, bottom; F32 aspectRatio = mClientScreen.x / mClientScreen.y; visFrustum.set(false, mDegToRad(mCameraFov), aspectRatio, 0.1f, 1000, mOwner->getTransform()); diff --git a/Engine/source/T3D/components/collision/collisionComponent.cpp b/Engine/source/T3D/components/collision/collisionComponent.cpp index 3736fbe04..5eee24a9e 100644 --- a/Engine/source/T3D/components/collision/collisionComponent.cpp +++ b/Engine/source/T3D/components/collision/collisionComponent.cpp @@ -538,7 +538,6 @@ PhysicsCollision* CollisionComponent::buildColShapes() for (S32 o = start; o < end; o++) { const TSShape::Object &object = shape->objects[o]; - const String &meshName = shape->names[object.nameIndex]; if (object.numMeshes <= detail.objectDetailNum) continue; diff --git a/Engine/source/T3D/components/game/stateMachine.cpp b/Engine/source/T3D/components/game/stateMachine.cpp index fd1ef8505..8c9f8b4f9 100644 --- a/Engine/source/T3D/components/game/stateMachine.cpp +++ b/Engine/source/T3D/components/game/stateMachine.cpp @@ -152,7 +152,6 @@ void StateMachine::readConditions(StateTransition ¤tTransition) //get our first state StateTransition::Condition firstCondition; StateField firstField; - bool fieldRead = false; readFieldName(&firstField, reader); firstCondition.field = firstField; diff --git a/Engine/source/T3D/components/game/triggerComponent.cpp b/Engine/source/T3D/components/game/triggerComponent.cpp index 290fab437..873c1307d 100644 --- a/Engine/source/T3D/components/game/triggerComponent.cpp +++ b/Engine/source/T3D/components/game/triggerComponent.cpp @@ -239,8 +239,6 @@ bool TriggerComponent::testObject(SceneObject* enter) myList.setObject(mOwner); myCI->buildPolyList(PLC_Collision, &myList, enterBox, sphere); - - bool test = true; } } } diff --git a/Engine/source/T3D/components/physics/playerControllerComponent.cpp b/Engine/source/T3D/components/physics/playerControllerComponent.cpp index 5b7455bfc..d321f7904 100644 --- a/Engine/source/T3D/components/physics/playerControllerComponent.cpp +++ b/Engine/source/T3D/components/physics/playerControllerComponent.cpp @@ -330,9 +330,6 @@ void PlayerControllerComponent::updateMove() } // Update current orientation - bool doStandardMove = true; - GameConnection* con = mOwner->getControllingClient(); - MatrixF zRot; zRot.set(EulerF(0.0f, 0.0f, mOwner->getRotation().asEulerF().z)); @@ -355,7 +352,6 @@ void PlayerControllerComponent::updateMove() mContactInfo.jump = false; mContactInfo.run = false; - bool jumpSurface = false, runSurface = false; if (!mOwner->isMounted()) findContact(&mContactInfo.run, &mContactInfo.jump, &mContactInfo.contactNormal); if (mContactInfo.jump) @@ -577,7 +573,6 @@ void PlayerControllerComponent::updatePos(const F32 travelTime) newPos = mPhysicsRep->move(mVelocity * travelTime, collisionList); bool haveCollisions = false; - bool wasFalling = mFalling; if (collisionList.getCount() > 0) { mFalling = false; diff --git a/Engine/source/T3D/convexShape.cpp b/Engine/source/T3D/convexShape.cpp index 33e2bc65c..f179ad25a 100644 --- a/Engine/source/T3D/convexShape.cpp +++ b/Engine/source/T3D/convexShape.cpp @@ -719,8 +719,6 @@ bool ConvexShape::buildExportPolyList(ColladaUtils::ExportData* exportData, cons //Convex shapes only have the one 'level', so we'll just rely on the export post-process to back-fill if (isServerObject() && getClientObject()) { - ConvexShape* clientShape = dynamic_cast(getClientObject()); - exportData->meshData.increment(); //Prep a meshData for this shape in particular diff --git a/Engine/source/T3D/entity.cpp b/Engine/source/T3D/entity.cpp index ffe724406..bb8f7becf 100644 --- a/Engine/source/T3D/entity.cpp +++ b/Engine/source/T3D/entity.cpp @@ -306,8 +306,6 @@ void Entity::onPostAdd() bool Entity::_setGameObject(void *object, const char *index, const char *data) { - Entity *e = static_cast(object); - // Sanity! AssertFatal(data != NULL, "Cannot use a NULL asset Id."); @@ -513,8 +511,6 @@ U32 Entity::packUpdate(NetConnection *con, U32 mask, BitStream *stream) for (U32 i = 0; i < mNetworkedComponents.size(); i++) { - NetworkedComponent::UpdateState state = mNetworkedComponents[i].updateState; - if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding) { const char* className = mComponents[mNetworkedComponents[i].componentIndex]->getClassName(); @@ -1381,7 +1377,6 @@ bool Entity::removeComponent(Component *comp, bool deleteComponent) //to re-add them. Need to implement a clean clear function that will clear the local list, and only delete unused behaviors during an update. void Entity::clearComponents(bool deleteComponents) { - bool srv = isServerObject(); if (!deleteComponents) { while (mComponents.size() > 0) @@ -1399,8 +1394,6 @@ void Entity::clearComponents(bool deleteComponents) { comp->onComponentRemove(); //in case the behavior needs to do cleanup on the owner - bool removed = mComponents.remove(comp); - //we only need to delete them on the server side. they'll be cleaned up on the client side //via the ghosting system for us if (isServerObject()) @@ -1663,7 +1656,6 @@ void Entity::notifyComponents(String signalFunction, String argA, String argB, S void Entity::setComponentsDirty() { - bool tmp = true; /*if (mToLoadComponents.empty()) mStartComponentUpdate = true; @@ -1694,7 +1686,6 @@ void Entity::setComponentsDirty() void Entity::setComponentDirty(Component *comp, bool forceUpdate) { - bool found = false; for (U32 i = 0; i < mComponents.size(); i++) { if (mComponents[i]->getId() == comp->getId()) diff --git a/Engine/source/T3D/entity.h b/Engine/source/T3D/entity.h index 5bf9898ea..b7e325ce5 100644 --- a/Engine/source/T3D/entity.h +++ b/Engine/source/T3D/entity.h @@ -309,7 +309,6 @@ Vector Entity::getComponents() Vector foundObjects; T *curObj; - Component* comp; // Loop through our child objects. for (U32 i = 0; i < mComponents.size(); i++) diff --git a/Engine/source/T3D/gameFunctions.cpp b/Engine/source/T3D/gameFunctions.cpp index c49c75cb3..db2ac5a27 100644 --- a/Engine/source/T3D/gameFunctions.cpp +++ b/Engine/source/T3D/gameFunctions.cpp @@ -553,7 +553,6 @@ void renderFrame(GFXTextureTargetRef* target, MatrixF transform, Frustum frustum GFX->setStateBlock(mDefaultGuiSB); GFXTargetRef origTarget = GFX->getActiveRenderTarget(); - U32 origStyle = GFX->getCurrentRenderStyle(); // Clear the zBuffer so GUI doesn't hose object rendering accidentally GFX->clear(GFXClearZBuffer, ColorI(20, 20, 20), 1.0f, 0); diff --git a/Engine/source/T3D/systems/render/meshRenderSystem.cpp b/Engine/source/T3D/systems/render/meshRenderSystem.cpp index 39b163601..6faf2a74c 100644 --- a/Engine/source/T3D/systems/render/meshRenderSystem.cpp +++ b/Engine/source/T3D/systems/render/meshRenderSystem.cpp @@ -21,11 +21,9 @@ void MeshRenderSystem::render(SceneManager *sceneManager, SceneRenderState* stat for (U32 i = 0; i < count; i++) { //Server side items exist for data, but we don't actually render them - bool isClient = MeshRenderSystemInterface::all[i]->mIsClient; if (!MeshRenderSystemInterface::all[i]->mIsClient) continue; - bool isStatic = MeshRenderSystemInterface::all[i]->mStatic; if (MeshRenderSystemInterface::all[i]->mStatic) continue; diff --git a/Engine/source/T3D/tsStatic.cpp b/Engine/source/T3D/tsStatic.cpp index 58925b29e..3e48154e7 100644 --- a/Engine/source/T3D/tsStatic.cpp +++ b/Engine/source/T3D/tsStatic.cpp @@ -1131,7 +1131,6 @@ bool TSStatic::buildExportPolyList(ColladaUtils::ExportData* exportData, const B if (isServerObject() && getClientObject()) { TSStatic* clientShape = dynamic_cast(getClientObject()); - U32 numDetails = clientShape->mShapeInstance->getNumDetails() - 1; exportData->meshData.increment(); diff --git a/Engine/source/app/net/serverQuery.cpp b/Engine/source/app/net/serverQuery.cpp index 17caac478..a1f60cd74 100644 --- a/Engine/source/app/net/serverQuery.cpp +++ b/Engine/source/app/net/serverQuery.cpp @@ -1611,9 +1611,7 @@ static void handleExtendedMasterServerListResponse(BitStream* stream, U32 key, U { U16 packetIndex, packetTotal; U32 i; - U16 serverCount, port; - U8 netNum[16]; - char addressBuffer[256]; + U16 serverCount; NetAddress addr; stream->read(&packetIndex); diff --git a/Engine/source/gui/controls/guiConsole.cpp b/Engine/source/gui/controls/guiConsole.cpp index d063272bf..3eb81e7e8 100644 --- a/Engine/source/gui/controls/guiConsole.cpp +++ b/Engine/source/gui/controls/guiConsole.cpp @@ -89,9 +89,6 @@ bool GuiConsole::onWake() S32 GuiConsole::getMaxWidth(S32 startIndex, S32 endIndex) { //sanity check - U32 size; - ConsoleLogEntry *log; - if (startIndex < 0 || (U32)endIndex >= mFilteredLog.size() || startIndex > endIndex) return 0; @@ -190,9 +187,6 @@ void GuiConsole::onPreRender() void GuiConsole::onRenderCell(Point2I offset, Point2I cell, bool /*selected*/, bool /*mouseOver*/) { - U32 size; - ConsoleLogEntry *log; - ConsoleLogEntry &entry = mFilteredLog[cell.y]; switch (entry.mLevel) { @@ -210,9 +204,6 @@ void GuiConsole::onCellSelected( Point2I cell ) { Parent::onCellSelected( cell ); - U32 size; - ConsoleLogEntry* log; - ConsoleLogEntry& entry = mFilteredLog[cell.y]; onMessageSelected_callback( entry.mLevel, entry.mString ); } diff --git a/Engine/source/gui/editor/inspector/mountingGroup.cpp b/Engine/source/gui/editor/inspector/mountingGroup.cpp index 759139658..158461902 100644 --- a/Engine/source/gui/editor/inspector/mountingGroup.cpp +++ b/Engine/source/gui/editor/inspector/mountingGroup.cpp @@ -133,9 +133,6 @@ bool GuiInspectorMountingGroup::inspectGroup() clearFields(); bool bNewItems = false; - bool bMakingArray = false; - GuiStackControl *pArrayStack = NULL; - GuiRolloutCtrl *pArrayRollout = NULL; bool bGrabItems = false; AbstractClassRep* commonAncestorClass = findCommonAncestorClass(); @@ -240,7 +237,6 @@ void GuiInspectorMountingGroup::updateAllFields() void GuiInspectorMountingGroup::onMouseMove(const GuiEvent &event) { //mParent->mOverDivider = false; - bool test = false; } DefineEngineMethod(GuiInspectorMountingGroup, inspectGroup, bool, (),, "Refreshes the dynamic fields in the inspector.") diff --git a/Engine/source/gui/worldEditor/worldEditor.cpp b/Engine/source/gui/worldEditor/worldEditor.cpp index 27c9dc473..478cc2e3d 100644 --- a/Engine/source/gui/worldEditor/worldEditor.cpp +++ b/Engine/source/gui/worldEditor/worldEditor.cpp @@ -3877,8 +3877,6 @@ void WorldEditor::makeSelectionAMesh(const char *filename) fabMat.inverse(); MatrixF objMat; - SimObject *obj = NULL; - SceneObject *sObj = NULL; Vector< SceneObject* > objectList; diff --git a/Engine/source/platform/platformNet.cpp b/Engine/source/platform/platformNet.cpp index 2a22499c4..1e5cb0a5a 100644 --- a/Engine/source/platform/platformNet.cpp +++ b/Engine/source/platform/platformNet.cpp @@ -230,7 +230,6 @@ namespace PlatformNetState // which are required for LAN queries (PC->Xbox connectivity). The wire protocol still // uses the VDP packet structure, though. S32 protocol = IPPROTO_UDP; - bool useVDP = false; #ifdef TORQUE_DISABLE_PC_CONNECTIVITY // Xbox uses a VDP (voice/data protocol) socket for networking protocol = IPPROTO_VDP; @@ -1956,7 +1955,6 @@ void Net::enableMulticast() if (error == NoError) { - NetAddress listenAddress; char listenAddressStr[256]; Net::addressToString(&multicastAddress, listenAddressStr); Con::printf("Multicast initialized on %s", listenAddressStr); From 008423bf323fce80209280bfb7e8e76a37a33207 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Mon, 11 Feb 2019 07:41:09 -0600 Subject: [PATCH 44/75] add vertex colors to standard cube sample mesh as a validation tool --- Templates/Full/game/art/shapes/cube/cube.dae | 156 +++++++------------ 1 file changed, 54 insertions(+), 102 deletions(-) diff --git a/Templates/Full/game/art/shapes/cube/cube.dae b/Templates/Full/game/art/shapes/cube/cube.dae index 720fdc14c..d6c1d4bcc 100644 --- a/Templates/Full/game/art/shapes/cube/cube.dae +++ b/Templates/Full/game/art/shapes/cube/cube.dae @@ -1,119 +1,73 @@ - + - Matt - 3dsMax 10 - Feeling ColladaMax v3.05B. - ColladaMax Export Options: ExportNormals=1;ExportEPolyAsTriangles=1;ExportXRefs=1;ExportSelected=0;ExportTangents=0;ExportAnimations=0;SampleAnim=1;ExportAnimClip=1;BakeMatrices=1;ExportRelativePaths=1;AnimStart=0;AnimEnd=3.33333; - cube.max + Blender User + Blender 2.79.0 commit date:2017-09-11, commit time:10:43, hash:5bd8ac9 - 2009-09-09T07:28:49Z - 2009-09-09T07:28:53Z - + 2019-02-11T07:13:36 + 2019-02-11T07:13:36 + Z_UP - - ./grid.dds + + grid.dds - - - - - - + - grid.dds - A8R8G8B8 + grid_dds grid_dds-surface - WRAP - WRAP - NONE - NONE - NONE + + 0 0 0 1 + - 0.588235 0.588235 0.588235 1 + 0 0 0 1 - - - - 0 - 0 - 1 - 1 - 1 - 1 - 0 - 0 - 0 - - - 1 - - - + - 0.9 0.9 0.9 1 + 0.3743451 0.3743451 0.3743451 1 - 0.415939 + 50 - - 0 0 0 1 - - - 1 - 1 1 1 1 - - 1 - + + 1 + - - - - 0 - - - 0 - - - - - - 0 - 0 - 0 - 0 - - + + + + + - -0.5 -0.5 0 0.5 -0.5 0 -0.5 0.5 0 0.5 0.5 0 -0.5 -0.5 1 0.5 -0.5 1 -0.5 0.5 1 0.5 0.5 1 + -0.5 -0.5 0 0.5 -0.5 0 -0.5 0.5 0 0.5 0.5 0 -0.5 -0.5 1 0.5 -0.5 1 -0.5 0.5 1 0.5 0.5 1 0.1666666 0.5 0.3333333 -0.1666666 0.5 0.6666666 -0.5 0.1666666 0.3333333 -0.5 -0.1666666 0.6666666 -0.5 0.5 0.3333333 -0.5 0.5 0.6666666 -0.1666666 -0.5 0.3333333 0.1666666 -0.5 0.6666666 -0.5 -0.5 0.3333333 -0.5 -0.5 0.6666666 -0.1666666 0.5 0 0.1666666 0.5 0 0.5 0.5 0.3333333 0.5 0.5 0.6666666 -0.1666666 -0.1666666 1 0.1666666 0.1666666 1 0.5 -0.1666666 1 0.5 0.1666666 1 -0.1666666 -0.1666666 0 0.1666666 0.1666666 0 -0.5 -0.1666666 1 -0.5 0.1666666 1 0.5 -0.1666666 0 0.5 0.1666666 0 -0.5 -0.1666666 0 -0.5 0.1666666 0 -0.1666666 -0.5 1 0.1666666 -0.5 1 0.5 -0.1666666 0.3333333 0.5 0.1666666 0.6666666 0.5 -0.5 0.3333333 0.5 -0.5 0.6666666 -0.1666666 -0.5 0 0.1666666 -0.5 0 -0.1666666 0.5 1 0.1666666 0.5 1 -0.5 0.1666666 0.6666666 -0.5 -0.1666666 0.3333333 0.1666666 0.5 0.6666666 -0.1666666 0.5 0.3333333 0.5 -0.1666666 0.6666666 0.5 0.1666666 0.3333333 -0.1666666 -0.5 0.6666666 0.1666666 -0.5 0.3333333 -0.1666666 0.1666666 1 0.1666666 -0.1666666 1 0.1666666 -0.1666666 0 -0.1666666 0.1666666 0 - + @@ -121,65 +75,63 @@ - 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 1 0 0 1 0 0 1 0 0 1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 1 0 0 1 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 1 0 0 1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 + 0 0 -1 0 0 1 0 -1 0 1 0 0 0 1 0 -1 0 0 - + - - 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0 1 1 0 + + 1 0 1 0.3333333 0.6666666 0.3333333 0 1 0 0.6666667 0.3333333 0.6666667 0 0 0.3333333 0 0.3333333 0.3333333 1 1 0.6666667 1 0.6666667 0.6666667 0 0 0.3333333 0 0.3333333 0.3333333 1 1 0.6666667 1 0.6666667 0.6666667 0 0 0.3333333 0 0.3333333 0.3333333 1 1 0.6666667 1 0.6666667 0.6666667 0 0 0.3333333 0 0.3333333 0.3333333 1 1 0.6666666 1 0.6666667 0.6666667 0 0 0.3333333 0 0.3333333 0.3333333 1 1 0.6666666 1 0.6666667 0.6666667 0.3333333 0.3333333 0 0.3333333 0 0 0.6666667 0.6666667 0.3333333 0.6666667 0.3333333 0.3333333 0.3333333 0.3333333 0.3333333 0.6666667 0 0.3333333 0.3333333 0.6666667 0 0.6666667 0 0.3333333 0.6666667 0.6666667 0.6666666 1 0.3333333 0.6666667 0.6666666 1 0.3333333 1 0.3333333 0.6666667 0.3333333 0.6666667 0.3333333 1 0 0.6666667 0.3333333 1 0 1 0 0.6666667 0.6666667 0.6666667 1 0.6666667 1 1 0.3333333 0.3333333 0.6666667 0.3333333 0.6666667 0.6666667 0.6666667 0.6666667 0.6666667 0.3333333 1 0.6666667 0.6666667 0.3333333 1 0.3333333 1 0.6666667 0.3333333 0.3333333 0.3333333 0 0.6666667 0.3333333 0.3333333 0 0.6666666 0 0.6666667 0.3333333 0.6666667 0.3333333 0.6666666 0 1 0.3333333 0.6666666 0 1 0 1 0.3333333 0.3333333 0.3333333 0 0.3333333 0 0 0.6666667 0.6666667 0.3333333 0.6666667 0.3333333 0.3333333 0.3333333 0.3333333 0.3333333 0.6666667 0 0.3333333 0.3333333 0.6666667 0 0.6666667 0 0.3333333 0.6666667 0.6666667 0.6666666 1 0.3333333 0.6666667 0.6666666 1 0.3333333 1 0.3333333 0.6666667 0.3333333 0.6666667 0.3333333 1 0 0.6666667 0.3333333 1 0 1 0 0.6666667 0.6666667 0.6666667 1 0.6666667 1 1 0.3333333 0.3333333 0.6666667 0.3333333 0.6666667 0.6666667 0.6666667 0.6666667 0.6666667 0.3333333 1 0.6666667 0.6666667 0.3333333 1 0.3333333 1 0.6666667 0.3333333 0.3333333 0.3333333 0 0.6666667 0.3333333 0.3333333 0 0.6666666 0 0.6666667 0.3333333 0.6666667 0.3333333 0.6666666 0 1 0.3333333 0.6666666 0 1 0 1 0.3333333 0.3333333 0.3333333 0 0.3333333 0 0 0.6666667 0.6666667 0.3333333 0.6666667 0.3333333 0.3333333 0.3333333 0.3333333 0.3333333 0.6666667 0 0.3333333 0.3333333 0.6666667 0 0.6666667 0 0.3333333 0.6666667 0.6666667 0.6666667 1 0.3333333 0.6666667 0.6666667 1 0.3333333 1 0.3333333 0.6666667 0.3333333 0.6666667 0.3333333 1 0 0.6666667 0.3333333 1 0 1 0 0.6666667 0.6666667 0.6666667 1 0.6666667 1 1 0.3333333 0.3333333 0.6666667 0.3333333 0.6666667 0.6666667 0.6666667 0.6666667 0.6666667 0.3333333 1 0.6666667 0.6666667 0.3333333 1 0.3333333 1 0.6666667 0.3333333 0.3333333 0.3333333 0 0.6666667 0.3333333 0.3333333 0 0.6666667 0 0.6666667 0.3333333 0.6666667 0.3333333 0.6666667 0 1 0.3333333 0.6666667 0 1 0 1 0.3333333 0.3333333 0.3333333 0 0.3333333 0 0 0.6666667 0.6666667 0.3333333 0.6666667 0.3333333 0.3333333 0.3333333 0.3333333 0.3333333 0.6666667 0 0.3333333 0.3333333 0.6666667 0 0.6666667 0 0.3333333 0.6666667 0.6666667 0.6666667 1 0.3333333 0.6666667 0.6666667 1 0.3333333 1 0.3333333 0.6666667 0.3333333 0.6666667 0.3333333 1 0 0.6666667 0.3333333 1 0 1 0 0.6666667 0.6666667 0.6666667 1 0.6666667 1 1 0.3333333 0.3333333 0.6666667 0.3333333 0.6666667 0.6666667 0.6666667 0.6666667 0.6666667 0.3333333 1 0.6666667 0.6666667 0.3333333 1 0.3333333 1 0.6666667 0.3333333 0.3333333 0.3333333 0 0.6666667 0.3333333 0.3333333 0 0.6666667 0 0.6666667 0.3333333 0.6666667 0.3333333 0.6666667 0 1 0.3333333 0.6666667 0 1 0 1 0.3333333 0.3333333 0.3333333 0 0.3333333 0 0 0.6666667 0.6666667 0.3333333 0.6666667 0.3333333 0.3333333 0.3333333 0.3333333 0.3333333 0.6666667 0 0.3333333 0.3333333 0.6666667 0 0.6666667 0 0.3333333 0.6666667 0.6666667 0.6666667 1 0.3333333 0.6666667 0.6666667 1 0.3333333 1 0.3333333 0.6666667 0.3333333 0.6666667 0.3333333 1 0 0.6666667 0.3333333 1 0 1 0 0.6666667 0.6666667 0.6666667 1 0.6666667 1 1 0.3333333 0.3333333 0.6666667 0.3333333 0.6666667 0.6666667 0.6666667 0.6666667 0.6666667 0.3333333 1 0.6666667 0.6666667 0.3333333 1 0.3333333 1 0.6666667 0.3333333 0.3333333 0.3333333 0 0.6666667 0.3333333 0.3333333 0 0.6666667 0 0.6666667 0.3333333 0.6666667 0.3333333 0.6666667 0 1 0.3333333 0.6666667 0 1 0 1 0.3333333 0.6666666 0.3333333 0.6666666 0 1 0 0.3333333 0.6666667 0.3333333 0.3333333 0.6666666 0.3333333 0.6666666 0.3333333 0.3333333 0.3333333 0.6666666 0 0.3333333 0.3333333 0.3333333 0 0.6666666 0 0.3333333 0.6666667 0 0.6666667 0.3333333 0.3333333 0 0.6666667 0 0.3333333 0.3333333 0.3333333 0.3333333 0.3333333 0 0.3333333 0.3333333 0 0 0.3333333 0 0 0.3333333 0 0.3333333 0.6666667 0.3333333 1 0 1 0.6666666 0.3333333 0.6666666 0.6666667 0.3333333 0.6666667 0.3333333 0.6666667 0.6666666 0.6666667 0.3333333 1 0.6666666 0.6666667 0.6666666 1 0.3333333 1 0.6666666 0.3333333 1 0.3333333 0.6666666 0.6666667 1 0.3333333 1 0.6666667 0.6666666 0.6666667 0.6666666 0.6666667 1 0.6666667 0.6666666 1 1 0.6666667 1 1 0.6666666 1 - + - + + + + + 0.02745097 0.02745097 1 0 0 1 0 0 1 0.02352941 0.02352941 1 0 0 1 0 0 1 1 0.1176471 0.1176471 1 0.003921568 0.003921568 1 0.02352941 0.02352941 1 0.003921568 0.003921568 1 0.09019607 0.09019607 1 0.0862745 0.0862745 0.003921568 0.003921568 1 0 0 1 0.007843136 0.007843136 1 0.9411765 0.0980392 0.1529412 0.854902 0.0117647 0.1529412 0.6313726 0.01568627 0.3843137 0.07058823 0.07058823 1 0.003921568 0.003921568 1 0.07058823 0.07058823 1 1 0.07450979 0.07450979 1 0.04313725 0.04313725 1 0.0980392 0.0980392 0.1372549 0.1372549 1 0.09411764 0.09411764 1 0.2431373 0.2431373 1 1 0.05098038 0.05098038 1 0.172549 0.172549 1 0.0117647 0.0117647 0.1647059 0.1647059 1 0 0 1 0.003921568 0.003921568 1 1 0 0 1 0 0 1 0 0 0.003921568 0.003921568 1 0 0 1 0.1647059 0.1647059 1 1 0 0 1 0.003921568 0.003921568 0.003921568 0.003921568 1 0.003921568 0.003921568 1 1 0.003921568 0.003921568 0 0 1 1 0.003921568 0.003921568 1 0 0 0 0 1 1 0 0 1 0 0 1 0.003921568 0.003921568 1 0 0 1 0.007843136 0.007843136 1 0.003921568 0.003921568 1 0.003921568 0.003921568 1 0.007843136 0.007843136 1 0 0 1 0.007843136 0.007843136 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0.003921568 0.003921568 1 0 0 1 1 0 0 1 0 0 0 0 1 1 0 0 0 0 1 0 0 1 1 0 0 0.003921568 0.003921568 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0.2431373 0.2431373 1 0.003921568 0.003921568 1 0.1372549 0.1372549 1 1 0.0117647 0.0117647 1 0.04313725 0.04313725 0.2431373 0.2431373 1 0.2431373 0.2431373 1 1 0.04313725 0.04313725 0.003921568 0.003921568 1 1 0.04313725 0.04313725 1 0.1019608 0.1019608 0.003921568 0.003921568 1 1 0.0117647 0.0117647 1 0.172549 0.172549 1 0.04313725 0.04313725 1 0.172549 0.172549 1 0.1254902 0.1254902 1 0.04313725 0.04313725 1 0.04313725 0.04313725 1 0.1254902 0.1254902 1 0.1019608 0.1019608 1 0.1254902 0.1254902 1 0.03137254 0.03137254 1 0.1019608 0.1019608 1 0.0117647 0.0117647 1 0.007843136 0.007843136 1 0.05098038 0.05098038 0.2431373 0.2431373 1 0.0117647 0.0117647 1 1 0.0117647 0.0117647 1 0.0117647 0.0117647 0.0117647 0.0117647 1 1 0.007843136 0.007843136 0.0117647 0.0117647 1 0 0 1 1 0.007843136 0.007843136 0.2431373 0.2431373 1 0.09411764 0.09411764 1 0.0117647 0.0117647 1 0.09411764 0.09411764 1 0.02352941 0.02352941 1 0.0117647 0.0117647 1 0.0117647 0.0117647 1 0.02352941 0.02352941 1 0 0 1 0.02352941 0.02352941 1 0 0 1 0 0 1 0.07058823 0.07058823 1 0.0117647 0.0117647 1 0.07058823 0.07058823 1 1 0.0980392 0.0980392 1 0.1960784 0.1960784 0.07058823 0.07058823 1 0.07058823 0.07058823 1 1 0.1960784 0.1960784 0.0117647 0.0117647 1 1 0.1960784 0.1960784 1 0 0 0.0117647 0.0117647 1 1 0.0980392 0.0980392 1 0.04313725 0.04313725 1 0.1960784 0.1960784 1 0.04313725 0.04313725 1 0.007843136 0.007843136 1 0.1960784 0.1960784 1 0.1960784 0.1960784 1 0.007843136 0.007843136 1 0 0 1 0.007843136 0.007843136 1 0.0117647 0.0117647 1 0 0 1 0.0980392 0.0980392 1 0.09019607 0.09019607 1 0.07450979 0.07450979 0.07058823 0.07058823 1 0.04705882 0.04705882 1 1 0.0980392 0.0980392 1 0.0980392 0.0980392 0.04705882 0.04705882 1 1 0.09019607 0.09019607 0.04705882 0.04705882 1 0 0 1 1 0.09019607 0.09019607 0.07058823 0.07058823 1 0.003921568 0.003921568 1 0.04705882 0.04705882 1 0.003921568 0.003921568 1 0.05490195 0.05490195 1 0.04705882 0.04705882 1 0.04705882 0.04705882 1 0.05490195 0.05490195 1 0 0 1 0.05490195 0.05490195 1 0.0117647 0.0117647 1 0 0 1 0.007843136 0.007843136 1 0.0117647 0.0117647 1 0.003921568 0.003921568 1 0.6313726 0.01568627 0.3843137 0.8313726 0.09019607 0.2588235 0.007843136 0.007843136 1 0.007843136 0.007843136 1 0.8313726 0.09019607 0.2588235 0.0117647 0.0117647 1 0.8313726 0.09019607 0.2588235 0.6901961 0 0.3098039 0.0117647 0.0117647 1 0.6313726 0.01568627 0.3843137 0.854902 0.0117647 0.1529412 0.8313726 0.09019607 0.2588235 0.854902 0.0117647 0.1529412 0.9607843 0.1137255 0.1529412 0.8313726 0.09019607 0.2588235 0.8313726 0.09019607 0.2588235 0.9607843 0.1137255 0.1529412 0.6901961 0 0.3098039 0.9607843 0.1137255 0.1529412 0.9490196 0.1882353 0.2392157 0.6901961 0 0.3098039 0.6313726 0.01568627 0.3843137 0.8470588 0.003921568 0.1568627 0.9411765 0.0980392 0.1529412 0.007843136 0.007843136 1 0.01568627 0.0117647 0.9960784 0.6313726 0.01568627 0.3843137 0.6313726 0.01568627 0.3843137 0.01568627 0.0117647 0.9960784 0.8470588 0.003921568 0.1568627 0.01568627 0.0117647 0.9960784 0.05490195 0.003921568 0.9450981 0.8470588 0.003921568 0.1568627 0.007843136 0.007843136 1 0 0 1 0.01568627 0.0117647 0.9960784 0 0 1 0 0 1 0.01568627 0.01568627 1 0.01568627 0.0117647 0.9960784 0 0 1 0.05490195 0.003921568 0.9450981 0 0 1 0.1333333 0.1333333 1 0.05490195 0.003921568 0.9450981 1 0.02352941 0.02352941 1 0.0117647 0.0117647 1 0.1176471 0.1176471 1 0.0862745 0.0862745 1 0.0117647 0.0117647 1 0.02352941 0.02352941 1 0.02352941 0.02352941 1 0.0117647 0.0117647 1 0.0117647 0.0117647 1 0.0117647 0.0117647 1 0.03529411 0.03529411 1 0.0117647 0.0117647 1 0.0862745 0.0862745 1 0.09019607 0.09019607 1 0.0117647 0.0117647 1 0.09019607 0.09019607 1 0.05098038 0.05098038 1 0.0117647 0.0117647 1 0.0117647 0.0117647 1 0.05098038 0.05098038 1 0.03529411 0.03529411 1 0.05098038 0.05098038 1 0.03137254 0.03137254 1 0.03529411 0.03529411 1 0.0862745 0.0862745 1 0.07450979 0.07450979 1 0.003921568 0.003921568 1 0.02352941 0.02352941 1 0.1843137 0.1843137 1 0.0862745 0.0862745 1 0.0862745 0.0862745 1 0.1843137 0.1843137 1 0.07450979 0.07450979 1 0.1843137 0.1843137 1 0.07843136 0.07843136 1 0.07450979 0.07450979 1 0.02352941 0.02352941 1 0.003921568 0.003921568 1 0.1843137 0.1843137 1 0.003921568 0.003921568 1 0.04705882 0.04705882 1 0.1843137 0.1843137 1 0.1843137 0.1843137 1 0.04705882 0.04705882 1 0.07843136 0.07843136 1 0.04705882 0.04705882 1 0.07843136 0.07843136 1 0.07843136 0.07843136 0 0 1 0.03921568 0.03921568 1 0.02745097 0.02745097 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0.03921568 0.03921568 1 0 0 1 0.01568627 0.01568627 1 0.03921568 0.03921568 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0.01568627 0.01568627 1 0 0 1 0.06274509 0.06274509 1 0.01568627 0.01568627 1 0 0 1 0 0 1 0.02352941 0.02352941 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0.003921568 0.003921568 1 0 0 1 + + + + + - + - -

0 0 9 2 1 11 3 2 10 3 2 10 1 3 8 0 0 9 4 4 8 5 5 9 7 6 11 7 6 11 6 7 10 4 4 8 0 8 4 1 9 5 5 10 7 5 10 7 4 11 6 0 8 4 1 12 0 3 13 1 7 14 3 7 14 3 5 15 2 1 12 0 3 16 4 2 17 5 6 18 7 6 18 7 7 19 6 3 16 4 2 20 0 0 21 1 4 22 3 4 22 3 6 23 2 2 20 0

+ + +

0 0 0 0 32 0 1 1 26 0 2 2 3 0 3 3 31 0 4 4 27 0 5 5 4 1 6 6 34 1 7 7 22 1 8 8 7 1 9 9 43 1 10 10 23 1 11 11 0 2 12 12 40 2 13 13 14 2 14 14 5 2 15 15 35 2 16 16 15 2 17 17 1 3 18 18 30 3 19 19 36 3 20 20 7 3 21 21 25 3 22 22 37 3 23 23 3 4 24 24 19 4 25 25 8 4 26 26 6 4 27 27 42 4 28 28 9 4 29 29 2 5 30 30 33 5 31 31 10 5 32 32 4 5 33 33 28 5 34 34 11 5 35 35 10 5 36 36 12 5 37 37 2 5 38 38 11 5 39 39 44 5 40 40 10 5 41 41 10 5 42 42 44 5 43 43 12 5 44 44 44 5 45 45 13 5 46 46 12 5 47 47 11 5 48 48 28 5 49 49 44 5 50 50 28 5 51 51 29 5 52 52 44 5 53 53 44 5 54 54 29 5 55 55 13 5 56 56 29 5 57 57 6 5 58 58 13 5 59 59 11 5 60 60 17 5 61 61 4 5 62 62 10 5 63 63 45 5 64 64 11 5 65 65 11 5 66 66 45 5 67 67 17 5 68 68 45 5 69 69 16 5 70 70 17 5 71 71 10 5 72 72 33 5 73 73 45 5 74 74 33 5 75 75 32 5 76 76 45 5 77 77 45 5 78 78 32 5 79 79 16 5 80 80 32 5 81 81 0 5 82 82 16 5 83 83 8 4 84 84 20 4 85 85 3 4 86 86 9 4 87 87 46 4 88 88 8 4 89 89 8 4 90 90 46 4 91 91 20 4 92 92 46 4 93 93 21 4 94 94 20 4 95 95 9 4 96 96 42 4 97 97 46 4 98 98 42 4 99 99 43 4 100 100 46 4 101 101 46 4 102 102 43 4 103 103 21 4 104 104 43 4 105 105 7 4 106 106 21 4 107 107 9 4 108 108 13 4 109 109 6 4 110 110 8 4 111 111 47 4 112 112 9 4 113 113 9 4 114 114 47 4 115 115 13 4 116 116 47 4 117 117 12 4 118 118 13 4 119 119 8 4 120 120 19 4 121 121 47 4 122 122 19 4 123 123 18 4 124 124 47 4 125 125 47 4 126 126 18 4 127 127 12 4 128 128 18 4 129 129 2 4 130 130 12 4 131 131 36 3 132 132 38 3 133 133 1 3 134 134 37 3 135 135 48 3 136 136 36 3 137 137 36 3 138 138 48 3 139 139 38 3 140 140 48 3 141 141 39 3 142 142 38 3 143 143 37 3 144 144 25 3 145 145 48 3 146 146 25 3 147 147 24 3 148 148 48 3 149 149 48 3 150 150 24 3 151 151 39 3 152 152 24 3 153 153 5 3 154 154 39 3 155 155 37 3 156 156 21 3 157 157 7 3 158 158 36 3 159 159 49 3 160 160 37 3 161 161 37 3 162 162 49 3 163 163 21 3 164 164 49 3 165 165 20 3 166 166 21 3 167 167 36 3 168 168 30 3 169 169 49 3 170 170 30 3 171 171 31 3 172 172 49 3 173 173 49 3 174 174 31 3 175 175 20 3 176 176 31 3 177 177 3 3 178 178 20 3 179 179 14 2 180 180 16 2 181 181 0 2 182 182 15 2 183 183 50 2 184 184 14 2 185 185 14 2 186 186 50 2 187 187 16 2 188 188 50 2 189 189 17 2 190 190 16 2 191 191 15 2 192 192 35 2 193 193 50 2 194 194 35 2 195 195 34 2 196 196 50 2 197 197 50 2 198 198 34 2 199 199 17 2 200 200 34 2 201 201 4 2 202 202 17 2 203 203 15 2 204 204 39 2 205 205 5 2 206 206 14 2 207 207 51 2 208 208 15 2 209 209 15 2 210 210 51 2 211 211 39 2 212 212 51 2 213 213 38 2 214 214 39 2 215 215 14 2 216 216 40 2 217 217 51 2 218 218 40 2 219 219 41 2 220 220 51 2 221 221 51 2 222 222 41 2 223 223 38 2 224 224 41 2 225 225 1 2 226 226 38 2 227 227 22 1 228 228 28 1 229 229 4 1 230 230 23 1 231 231 52 1 232 232 22 1 233 233 22 1 234 234 52 1 235 235 28 1 236 236 52 1 237 237 29 1 238 238 28 1 239 239 23 1 240 240 43 1 241 241 52 1 242 242 43 1 243 243 42 1 244 244 52 1 245 245 52 1 246 246 42 1 247 247 29 1 248 248 42 1 249 249 6 1 250 250 29 1 251 251 23 1 252 252 25 1 253 253 7 1 254 254 22 1 255 255 53 1 256 256 23 1 257 257 23 1 258 258 53 1 259 259 25 1 260 260 53 1 261 261 24 1 262 262 25 1 263 263 22 1 264 264 34 1 265 265 53 1 266 266 34 1 267 267 35 1 268 268 53 1 269 269 53 1 270 270 35 1 271 271 24 1 272 272 35 1 273 273 5 1 274 274 24 1 275 275 26 0 276 276 40 0 277 277 0 0 278 278 27 0 279 279 54 0 280 280 26 0 281 281 26 0 282 282 54 0 283 283 40 0 284 284 54 0 285 285 41 0 286 286 40 0 287 287 27 0 288 288 31 0 289 289 54 0 290 290 31 0 291 291 30 0 292 292 54 0 293 293 54 0 294 294 30 0 295 295 41 0 296 296 30 0 297 297 1 0 298 298 41 0 299 299 27 0 300 300 19 0 301 301 3 0 302 302 26 0 303 303 55 0 304 304 27 0 305 305 27 0 306 306 55 0 307 307 19 0 308 308 55 0 309 309 18 0 310 310 19 0 311 311 26 0 312 312 32 0 313 313 55 0 314 314 32 0 315 315 33 0 316 316 55 0 317 317 55 0 318 318 33 0 319 319 18 0 320 320 33 0 321 321 2 0 322 322 18 0 323 323

+ - - - 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 - + + + 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 + - - - + - - - 0 - 3.33333 - - - - - 30 - - - + - + \ No newline at end of file From aeb43432fa3588919b122d23e3302e21e2e7f660 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Mon, 11 Feb 2019 07:42:31 -0600 Subject: [PATCH 45/75] set gl vertcolor mapping to bgra format, the same as we do for stateblocks --- Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp index ab9bdb25b..ffb5c409a 100644 --- a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp +++ b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp @@ -1159,7 +1159,7 @@ void DiffuseVertColorFeatureGLSL::processVert( Vector< ShaderComponent* >& comp outColor->setStructName( "OUT" ); outColor->setType( "vec4" ); - output = new GenOp( " @ = @;\r\n", outColor, inColor ); + output = new GenOp( " @ = @.bgra;\r\n", outColor, inColor ); } else output = NULL; // Nothing we need to do. From ee6cabb76a3245c043d7ef5be6c0673beffd63b8 Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Wed, 13 Feb 2019 14:12:12 -0500 Subject: [PATCH 46/75] Switches to absolute position for mouse tracking when the platform cursor is visible. --- .../windowManager/windowInputGenerator.cpp | 34 ++++++------------- .../windowManager/windowInputGenerator.h | 2 -- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/Engine/source/windowManager/windowInputGenerator.cpp b/Engine/source/windowManager/windowInputGenerator.cpp index 435f88e7b..f2391d553 100644 --- a/Engine/source/windowManager/windowInputGenerator.cpp +++ b/Engine/source/windowManager/windowInputGenerator.cpp @@ -33,7 +33,6 @@ extern InputModifiers convertModifierBits(const U32 in); // Constructor/Destructor //----------------------------------------------------------------------------- WindowInputGenerator::WindowInputGenerator( PlatformWindow *window ) : - mNotifyPosition(true), mWindow(window), mInputController(NULL), mLastCursorPos(0,0), @@ -135,6 +134,7 @@ void WindowInputGenerator::handleMouseMove( WindowId did, U32 modifier, S32 x, S // Because of this we always have to generate and send off for processing // relative events, even if the mouse is not locked. // I'm considering removing this in the Canvas refactor, thoughts? [7/6/2007 justind] + // Now sends the absolute position event whenever an absolute position is received from the OS. [2/13/2019 mar] // Generate a base Movement along and Axis event InputEventInfo event; @@ -192,33 +192,23 @@ void WindowInputGenerator::handleMouseMove( WindowId did, U32 modifier, S32 x, S } - // When the window gains focus, we send a cursor position event - if( mNotifyPosition ) - { - mNotifyPosition = false; + // We use SI_MAKE to signify that the position is being set, not relatively moved. + event.action = SI_MAKE; - // We use SI_MAKE to signify that the position is being set, not relatively moved. - event.action = SI_MAKE; + // X Axis + event.objInst = SI_XAXIS; + event.fValue = (F32)x; + generateInputEvent(event); - // X Axis - event.objInst = SI_XAXIS; - event.fValue = (F32)x; - generateInputEvent(event); - - // Y Axis - event.objInst = SI_YAXIS; - event.fValue = (F32)y; - generateInputEvent(event); - } + // Y Axis + event.objInst = SI_YAXIS; + event.fValue = (F32)y; + generateInputEvent(event); mLastCursorPos = Point2I(x,y); - } else - { mLastCursorPos += Point2I(x,y); - mNotifyPosition = true; - } } void WindowInputGenerator::handleMouseButton( WindowId did, U32 modifiers, U32 action, U16 button ) @@ -388,8 +378,6 @@ void WindowInputGenerator::handleAppEvent( WindowId did, S32 event ) } else if(event == GainFocus) { - // Set an update flag to notify the consumer of the absolute mouse position next move - mNotifyPosition = true; mFocused = true; } diff --git a/Engine/source/windowManager/windowInputGenerator.h b/Engine/source/windowManager/windowInputGenerator.h index a5e9175c3..f4c3d2a76 100644 --- a/Engine/source/windowManager/windowInputGenerator.h +++ b/Engine/source/windowManager/windowInputGenerator.h @@ -37,8 +37,6 @@ class PlatformWindow; class WindowInputGenerator { - bool mNotifyPosition; - protected: PlatformWindow *mWindow; From 0bc332374f7441bddd5456ba1e66ed111b3bde77 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Tue, 19 Feb 2019 13:13:23 -0600 Subject: [PATCH 47/75] corrects a parity flaw between wireframe and non wireframe box display --- Engine/source/gfx/gfxDrawUtil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/source/gfx/gfxDrawUtil.cpp b/Engine/source/gfx/gfxDrawUtil.cpp index 9796e30fa..688de6bcf 100644 --- a/Engine/source/gfx/gfxDrawUtil.cpp +++ b/Engine/source/gfx/gfxDrawUtil.cpp @@ -845,7 +845,7 @@ void GFXDrawUtil::_drawWireCube( const GFXStateBlockDesc &desc, const Point3F &s if ( xfm != NULL ) { for ( U32 i = 0; i < 30; i++ ) - xfm->mulP( verts[i].point ); + xfm->mulV( verts[i].point ); } // Apply position offset From 2ac7d55be09ca1c546c20f88e45546b280466929 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Tue, 19 Feb 2019 16:10:33 -0600 Subject: [PATCH 48/75] solid capsule renderfix. +/- halfhieght, not full, and need to do vector, not point-multiplication for the verts --- Engine/source/gfx/gfxDrawUtil.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Engine/source/gfx/gfxDrawUtil.cpp b/Engine/source/gfx/gfxDrawUtil.cpp index 688de6bcf..f6d0d0a43 100644 --- a/Engine/source/gfx/gfxDrawUtil.cpp +++ b/Engine/source/gfx/gfxDrawUtil.cpp @@ -1153,9 +1153,9 @@ void GFXDrawUtil::_drawSolidCapsule( const GFXStateBlockDesc &desc, const Point3 for (S32 i=0; i Date: Tue, 19 Feb 2019 16:30:39 -0600 Subject: [PATCH 49/75] wireframe capsule set to the contents of the solid capsule for corrections and backwards compatibility --- Engine/source/gfx/gfxDrawUtil.cpp | 64 ++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/Engine/source/gfx/gfxDrawUtil.cpp b/Engine/source/gfx/gfxDrawUtil.cpp index f6d0d0a43..357e48a5e 100644 --- a/Engine/source/gfx/gfxDrawUtil.cpp +++ b/Engine/source/gfx/gfxDrawUtil.cpp @@ -1202,43 +1202,61 @@ void GFXDrawUtil::_drawSolidCapsule( const GFXStateBlockDesc &desc, const Point3 void GFXDrawUtil::_drawWireCapsule( const GFXStateBlockDesc &desc, const Point3F ¢er, F32 radius, F32 height, const ColorI &color, const MatrixF *xfm ) { MatrixF mat; - if ( xfm ) + if (xfm) mat = *xfm; else mat = MatrixF::Identity; - mat.scale( Point3F(radius,radius,height*0.5f) ); - mat.setPosition(center); - mDevice->pushWorldMatrix(); - mDevice->multWorld(mat); - - S32 numPoints = sizeof(circlePoints)/sizeof(Point2F); - GFXVertexBufferHandle verts(mDevice, numPoints, GFXBufferTypeVolatile); + S32 numPoints = sizeof(circlePoints) / sizeof(Point2F); + GFXVertexBufferHandle verts(mDevice, numPoints * 2 + 2, GFXBufferTypeVolatile); verts.lock(); - for (S32 i=0; i< numPoints; i++) + for (S32 i = 0; i < numPoints + 1; i++) { - S32 idx = i & (~1); // just draw the even ones - F32 z = i & 1 ? 1.0f : -1.0f; - verts[i].point = Point3F(circlePoints[idx].x,circlePoints[idx].y, z); - verts[i].color = color; + S32 imod = i % numPoints; + verts[2 * i].point = Point3F(circlePoints[imod].x * radius, circlePoints[imod].y * radius, height / 2); + verts[2 * i].color = color; + verts[2 * i + 1].point = Point3F(circlePoints[imod].x * radius, circlePoints[imod].y * radius, -height / 2); + verts[2 * i + 1].color = color; } + + S32 totalNumPnts = numPoints * 2 + 2; + + // Apply xfm if we were passed one. + for (U32 i = 0; i < totalNumPnts; i++) + mat.mulV(verts[i].point); + + // Apply position offset + for (U32 i = 0; i < totalNumPnts; i++) + verts[i].point += center; + verts.unlock(); - mDevice->setStateBlockByDesc( desc ); + mDevice->setStateBlockByDesc(desc); - mDevice->setVertexBuffer( verts ); + mDevice->setVertexBuffer(verts); mDevice->setupGenericShaders(); - for (S32 i=0; idrawPrimitive(GFXLineStrip, i, 1); - - mDevice->popWorldMatrix(); + mDevice->drawPrimitive(GFXTriangleStrip, 0, 2 * numPoints); Point3F sphereCenter; - sphereCenter.z = center.z + 0.5f * height; - drawSphere( desc, radius,sphereCenter,color,true,false); - sphereCenter.z = center.z - 0.5f * height; - drawSphere( desc, radius,sphereCenter,color,false,true); + MatrixF sphereMat; + + if (xfm) + sphereMat = *xfm; + else + sphereMat = MatrixF::Identity; + + sphereCenter.set(0, 0, 0.5f * height); + mat.mulV(sphereCenter); + sphereCenter += center; + + drawSphere(desc, radius, sphereCenter, color, true, false, &sphereMat); + + sphereCenter.set(0, 0, -0.5f * height); + mat.mulV(sphereCenter); + sphereCenter += center; + + drawSphere(desc, radius, sphereCenter, color, false, true, &sphereMat); } void GFXDrawUtil::drawCone( const GFXStateBlockDesc &desc, const Point3F &basePnt, const Point3F &tipPnt, F32 baseRadius, const ColorI &color ) From 21aa13e0f039744bbcae171d060a377892985ae9 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 13:55:29 -0600 Subject: [PATCH 50/75] Adds ability to set the split point of a guiSplitContainer --- .../gui/containers/guiSplitContainer.cpp | 22 +++++++++++++++++++ .../source/gui/containers/guiSplitContainer.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/Engine/source/gui/containers/guiSplitContainer.cpp b/Engine/source/gui/containers/guiSplitContainer.cpp index df52829dc..971dd262f 100644 --- a/Engine/source/gui/containers/guiSplitContainer.cpp +++ b/Engine/source/gui/containers/guiSplitContainer.cpp @@ -613,3 +613,25 @@ void GuiSplitContainer::onMouseDragged( const GuiEvent &event ) solvePanelConstraints(newDragPos, firstPanel, secondPanel, clientRect); } } + +void GuiSplitContainer::setSplitPoint(Point2I splitPoint) +{ + GuiContainer *firstPanel = dynamic_cast(at(0)); + GuiContainer *secondPanel = dynamic_cast(at(1)); + + // This function will constrain the panels to their minExtents and update the mSplitPoint + if (firstPanel && secondPanel) + { + RectI clientRect = getClientRect(); + + solvePanelConstraints(splitPoint, firstPanel, secondPanel, clientRect); + + layoutControls(clientRect); + } +} + +DefineEngineMethod(GuiSplitContainer, setSplitPoint, void, (Point2I splitPoint), , + "Set the positin of the split handler.") +{ + object->setSplitPoint(splitPoint); +} \ No newline at end of file diff --git a/Engine/source/gui/containers/guiSplitContainer.h b/Engine/source/gui/containers/guiSplitContainer.h index f3d853fe4..ab78fb0ff 100644 --- a/Engine/source/gui/containers/guiSplitContainer.h +++ b/Engine/source/gui/containers/guiSplitContainer.h @@ -87,6 +87,9 @@ public: virtual void solvePanelConstraints(Point2I newDragPos, GuiContainer * firstPanel, GuiContainer * secondPanel, const RectI& clientRect); virtual Point2I getMinExtent() const; + //Set the positin of the split handler + void setSplitPoint(Point2I splitPoint); + protected: S32 mFixedPanel; From 41caeedb0549ccc4e60f010ecfe1cb480628b611 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 14:20:57 -0600 Subject: [PATCH 51/75] Tweaks to the Asset/Module info echo behavior to spam the console less. --- Engine/source/assets/assetManager.cpp | 6 +++--- Engine/source/module/moduleManager.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine/source/assets/assetManager.cpp b/Engine/source/assets/assetManager.cpp index c2591a84f..2018dd57c 100644 --- a/Engine/source/assets/assetManager.cpp +++ b/Engine/source/assets/assetManager.cpp @@ -130,8 +130,8 @@ void AssetManager::initPersistFields() // Call parent. Parent::initPersistFields(); - addField( "EchoInfo", TypeBool, Offset(mEchoInfo, AssetManager), "Whether the asset manager echos extra information to the console or not." ); - addField( "IgnoreAutoUnload", TypeBool, Offset(mIgnoreAutoUnload, AssetManager), "Whether the asset manager should ignore unloading of auto-unload assets or not." ); + addField( "EchoInfo", TypeBool, false, Offset(mEchoInfo, AssetManager), "Whether the asset manager echos extra information to the console or not." ); + addField( "IgnoreAutoUnload", TypeBool, true, Offset(mIgnoreAutoUnload, AssetManager), "Whether the asset manager should ignore unloading of auto-unload assets or not." ); } //----------------------------------------------------------------------------- @@ -228,7 +228,7 @@ bool AssetManager::loadModuleAutoLoadAssets(ModuleDefinition* pModuleDefinition) AssertFatal(pModuleDefinition != NULL, "Cannot auto load assets using a NULL module definition"); // Does the module have any assets associated with it? - if (pModuleDefinition->getModuleAssets().empty()) + if (pModuleDefinition->getModuleAssets().empty() && mEchoInfo) { // Yes, so warn. Con::warnf("Asset Manager: Cannot auto load assets to module '%s' as it has no existing assets.", pModuleDefinition->getSignature()); diff --git a/Engine/source/module/moduleManager.cpp b/Engine/source/module/moduleManager.cpp index c5d3b42f6..e122177e8 100644 --- a/Engine/source/module/moduleManager.cpp +++ b/Engine/source/module/moduleManager.cpp @@ -69,7 +69,7 @@ S32 QSORT_CALLBACK moduleDefinitionVersionIdSort( const void* a, const void* b ) ModuleManager::ModuleManager() : mEnforceDependencies(true), - mEchoInfo(true), + mEchoInfo(false), mDatabaseLocks( 0 ), mIgnoreLoadedGroups(false) { From 1c2f90a190054c8caa054da20a7ba89fd7669772 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 15:55:28 -0600 Subject: [PATCH 52/75] Initial implementation of the Scene object for handling scenes/levels in a more consistent and deliberate way. --- Engine/source/T3D/Scene.cpp | 236 ++++++++++++++++++ Engine/source/T3D/Scene.h | 79 ++++++ Engine/source/T3D/prefab.cpp | 14 +- Engine/source/T3D/prefab.h | 2 +- .../editors/guiMeshRoadEditorCtrl.cpp | 14 +- .../editors/guiRiverEditorCtrl.cpp | 12 +- .../environment/editors/guiRoadEditorCtrl.cpp | 14 +- Engine/source/gui/worldEditor/editTSCtrl.cpp | 7 +- .../worldEditor/guiConvexShapeEditorCtrl.cpp | 50 ++-- .../source/gui/worldEditor/terrainEditor.cpp | 10 +- Engine/source/gui/worldEditor/worldEditor.cpp | 39 +-- Engine/source/scene/simPath.cpp | 8 +- Engine/source/terrain/terrImport.cpp | 16 +- Engine/source/ts/collada/colladaLights.cpp | 15 +- .../core/clientServer/Core_ClientServer.cs | 2 +- .../clientServer/scripts/server/levelInfo.cs | 4 +- .../clientServer/scripts/server/levelLoad.cs | 8 +- .../clientServer/scripts/server/server.cs | 4 +- .../BaseGame/game/tools/convexEditor/main.cs | 2 +- .../game/tools/gui/colladaImport.ed.gui | 4 +- .../BaseGame/game/tools/levels/BlankRoom.mis | 2 +- .../scripts/materialEditor.ed.cs | 2 +- .../scripts/materialEditorUndo.ed.cs | 4 +- .../game/tools/meshRoadEditor/main.cs | 2 +- .../game/tools/missionAreaEditor/main.cs | 2 +- .../tools/navEditor/CreateNewNavMeshDlg.gui | 8 +- .../BaseGame/game/tools/navEditor/main.cs | 2 +- .../BaseGame/game/tools/riverEditor/main.cs | 4 +- .../BaseGame/game/tools/roadEditor/main.cs | 2 +- .../BaseGame/game/tools/shapeEditor/main.cs | 2 +- .../worldEditor/gui/TimeAdjustGui.ed.gui | 6 +- .../worldEditor/gui/objectBuilderGui.ed.gui | 8 +- .../tools/worldEditor/scripts/EditorGui.ed.cs | 32 ++- .../scripts/SelectObjectsWindow.ed.cs | 2 +- .../worldEditor/scripts/editors/creator.ed.cs | 6 +- .../scripts/editors/worldEditor.ed.cs | 8 +- .../worldEditor/scripts/menuHandlers.ed.cs | 17 +- 37 files changed, 509 insertions(+), 140 deletions(-) create mode 100644 Engine/source/T3D/Scene.cpp create mode 100644 Engine/source/T3D/Scene.h diff --git a/Engine/source/T3D/Scene.cpp b/Engine/source/T3D/Scene.cpp new file mode 100644 index 000000000..aeed7399b --- /dev/null +++ b/Engine/source/T3D/Scene.cpp @@ -0,0 +1,236 @@ +#include "Scene.h" + +Scene * Scene::smRootScene = nullptr; +Vector Scene::smSceneList; + +IMPLEMENT_CO_NETOBJECT_V1(Scene); + +Scene::Scene() : + mIsSubScene(false), + mParentScene(nullptr), + mSceneId(-1), + mIsEditing(false), + mIsDirty(false) +{ + +} + +Scene::~Scene() +{ + +} + +void Scene::initPersistFields() +{ + Parent::initPersistFields(); + + addGroup("Internal"); + addField("isSubscene", TypeBool, Offset(mIsSubScene, Scene), "", AbstractClassRep::FIELD_HideInInspectors); + addField("isEditing", TypeBool, Offset(mIsEditing, Scene), "", AbstractClassRep::FIELD_HideInInspectors); + addField("isDirty", TypeBool, Offset(mIsDirty, Scene), "", AbstractClassRep::FIELD_HideInInspectors); + endGroup("Internal"); +} + +bool Scene::onAdd() +{ + if (!Parent::onAdd()) + return false; + + smSceneList.push_back(this); + mSceneId = smSceneList.size() - 1; + + /*if (smRootScene == nullptr) + { + //we're the first scene, so we're the root. woo! + smRootScene = this; + } + else + { + mIsSubScene = true; + smRootScene->mSubScenes.push_back(this); + }*/ + + return true; +} + +void Scene::onRemove() +{ + Parent::onRemove(); + + smSceneList.remove(this); + mSceneId = -1; + + /*if (smRootScene == this) + { + for (U32 i = 0; i < mSubScenes.size(); i++) + { + mSubScenes[i]->deleteObject(); + } + } + else if (smRootScene != nullptr) + { + for (U32 i = 0; i < mSubScenes.size(); i++) + { + if(mSubScenes[i]->getId() == getId()) + smRootScene->mSubScenes.erase(i); + } + }*/ +} + +void Scene::addObject(SimObject* object) +{ + //Child scene + Scene* scene = dynamic_cast(object); + if (scene) + { + //We'll keep these principly separate so they don't get saved into each other + mSubScenes.push_back(scene); + return; + } + + SceneObject* sceneObj = dynamic_cast(object); + if (sceneObj) + { + //We'll operate on the presumption that if it's being added via regular parantage means, it's considered permanent + mPermanentObjects.push_back(sceneObj); + Parent::addObject(object); + + return; + } + + //Do it like regular, though we should probably bail if we're trying to add non-scene objects to the scene? + Parent::addObject(object); +} + +void Scene::removeObject(SimObject* object) +{ + //Child scene + Scene* scene = dynamic_cast(object); + if (scene) + { + //We'll keep these principly separate so they don't get saved into each other + mSubScenes.remove(scene); + return; + } + + SceneObject* sceneObj = dynamic_cast(object); + if (sceneObj) + { + //We'll operate on the presumption that if it's being added via regular parantage means, it's considered permanent + + mPermanentObjects.remove(sceneObj); + Parent::removeObject(object); + + return; + } + + Parent::removeObject(object); +} + +void Scene::addDynamicObject(SceneObject* object) +{ + mDynamicObjects.push_back(object); + + //Do it like regular, though we should probably bail if we're trying to add non-scene objects to the scene? + Parent::addObject(object); +} + +void Scene::removeDynamicObject(SceneObject* object) +{ + mDynamicObjects.remove(object); + + //Do it like regular, though we should probably bail if we're trying to add non-scene objects to the scene? + Parent::removeObject(object); +} + +void Scene::interpolateTick(F32 delta) +{ + +} + +void Scene::processTick() +{ + +} + +void Scene::advanceTime(F32 timeDelta) +{ + +} + +U32 Scene::packUpdate(NetConnection *conn, U32 mask, BitStream *stream) +{ + bool ret = Parent::packUpdate(conn, mask, stream); + + return ret; +} + +void Scene::unpackUpdate(NetConnection *conn, BitStream *stream) +{ + +} + +// +Vector Scene::getObjectsByClass(String className) +{ + return Vector(); +} + +DefineEngineFunction(getScene, Scene*, (U32 sceneId), (0), + "Get the root Scene object that is loaded.\n" + "@return The id of the Root Scene. Will be 0 if no root scene is loaded") +{ + if (Scene::smSceneList.empty() || sceneId >= Scene::smSceneList.size()) + return nullptr; + + return Scene::smSceneList[sceneId]; +} + +DefineEngineFunction(getRootScene, S32, (), , + "Get the root Scene object that is loaded.\n" + "@return The id of the Root Scene. Will be 0 if no root scene is loaded") +{ + Scene* root = Scene::getRootScene(); + + if (root) + return root->getId(); + + return 0; +} + +DefineEngineMethod(Scene, getRootScene, S32, (),, + "Get the root Scene object that is loaded.\n" + "@return The id of the Root Scene. Will be 0 if no root scene is loaded") +{ + Scene* root = Scene::getRootScene(); + + if (root) + return root->getId(); + + return 0; +} + +DefineEngineMethod(Scene, addDynamicObject, void, (SceneObject* sceneObj), (nullAsType()), + "Get the root Scene object that is loaded.\n" + "@return The id of the Root Scene. Will be 0 if no root scene is loaded") +{ + object->addDynamicObject(sceneObj); +} + +DefineEngineMethod(Scene, removeDynamicObject, void, (SceneObject* sceneObj), (nullAsType()), + "Get the root Scene object that is loaded.\n" + "@return The id of the Root Scene. Will be 0 if no root scene is loaded") +{ + object->removeDynamicObject(sceneObj); +} + +DefineEngineMethod(Scene, getObjectsByClass, String, (String className), (""), + "Get the root Scene object that is loaded.\n" + "@return The id of the Root Scene. Will be 0 if no root scene is loaded") +{ + if (className == String::EmptyString) + return ""; + + //return object->getObjectsByClass(className); + return ""; +} diff --git a/Engine/source/T3D/Scene.h b/Engine/source/T3D/Scene.h new file mode 100644 index 000000000..111044247 --- /dev/null +++ b/Engine/source/T3D/Scene.h @@ -0,0 +1,79 @@ +#pragma once + +#include "console/engineAPI.h" + +#ifndef _NETOBJECT_H_ +#include "sim/netObject.h" +#endif + +#ifndef _ITICKABLE_H_ +#include "core/iTickable.h" +#endif + +#include "scene/sceneObject.h" + +/// Scene +/// This object is effectively a smart container to hold and manage any relevent scene objects and data +/// used to run things. +class Scene : public NetObject, public virtual ITickable +{ + typedef NetObject Parent; + + bool mIsSubScene; + + Scene* mParentScene; + + Vector mSubScenes; + + Vector mPermanentObjects; + + Vector mDynamicObjects; + + S32 mSceneId; + + bool mIsEditing; + + bool mIsDirty; + +protected: + static Scene * smRootScene; + + DECLARE_CONOBJECT(Scene); + +public: + Scene(); + ~Scene(); + + static void initPersistFields(); + + virtual bool onAdd(); + virtual void onRemove(); + + virtual void interpolateTick(F32 delta); + virtual void processTick(); + virtual void advanceTime(F32 timeDelta); + + virtual void addObject(SimObject* object); + virtual void removeObject(SimObject* object); + + void addDynamicObject(SceneObject* object); + void removeDynamicObject(SceneObject* object); + + // + //Networking + U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream); + void unpackUpdate(NetConnection *conn, BitStream *stream); + + // + Vector getObjectsByClass(String className); + + static Scene *getRootScene() + { + if (Scene::smSceneList.empty()) + return nullptr; + + return Scene::smSceneList[0]; + } + + static Vector smSceneList; +}; \ No newline at end of file diff --git a/Engine/source/T3D/prefab.cpp b/Engine/source/T3D/prefab.cpp index 32e209c31..54080c8a0 100644 --- a/Engine/source/T3D/prefab.cpp +++ b/Engine/source/T3D/prefab.cpp @@ -34,6 +34,8 @@ #include "T3D/physics/physicsShape.h" #include "core/util/path.h" +#include "T3D/Scene.h" + // We use this locally ( within this file ) to prevent infinite recursion // while loading prefab files that contain other prefabs. static Vector sPrefabFileStack; @@ -269,11 +271,11 @@ void Prefab::setFile( String file ) SimGroup* Prefab::explode() { - SimGroup *missionGroup; + Scene* scene = Scene::getRootScene(); - if ( !Sim::findObject( "MissionGroup", missionGroup ) ) + if ( !scene) { - Con::errorf( "Prefab::explode, MissionGroup was not found." ); + Con::errorf( "Prefab::explode, Scene was not found." ); return NULL; } @@ -295,7 +297,7 @@ SimGroup* Prefab::explode() smChildToPrefabMap.erase( child->getId() ); } - missionGroup->addObject(group); + scene->addObject(group); mChildGroup = NULL; mChildMap.clear(); @@ -468,10 +470,10 @@ Prefab* Prefab::getPrefabByChild( SimObject *child ) bool Prefab::isValidChild( SimObject *simobj, bool logWarnings ) { - if ( simobj->getName() && dStricmp(simobj->getName(),"MissionGroup") == 0 ) + if ( simobj->getName() && simobj == Scene::getRootScene() ) { if ( logWarnings ) - Con::warnf( "MissionGroup is not valid within a Prefab." ); + Con::warnf( "root Scene is not valid within a Prefab." ); return false; } diff --git a/Engine/source/T3D/prefab.h b/Engine/source/T3D/prefab.h index fd1ebc2a4..36e5d12f3 100644 --- a/Engine/source/T3D/prefab.h +++ b/Engine/source/T3D/prefab.h @@ -93,7 +93,7 @@ public: void setFile( String file ); /// Removes all children from this Prefab and puts them into a SimGroup - /// which is added to the MissionGroup and returned to the caller. + /// which is added to the Scene and returned to the caller. SimGroup* explode(); bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF& sphere); diff --git a/Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp b/Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp index bb78ba61e..95dfe4ad9 100644 --- a/Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp +++ b/Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp @@ -45,6 +45,8 @@ #include "materials/materialDefinition.h" #include "T3D/prefab.h" +#include "T3D/Scene.h" + IMPLEMENT_CONOBJECT(GuiMeshRoadEditorCtrl); ConsoleDocClass( GuiMeshRoadEditorCtrl, @@ -420,12 +422,14 @@ void GuiMeshRoadEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event) newRoad->registerObject(); - // Add to MissionGroup - SimGroup *missionGroup; - if ( !Sim::findObject( "MissionGroup", missionGroup ) ) - Con::errorf( "GuiMeshRoadEditorCtrl - could not find MissionGroup to add new MeshRoad" ); + // Add to scene + Scene *scene; + + scene = Scene::getRootScene(); + if ( !scene) + Con::errorf( "GuiMeshRoadEditorCtrl - could not find Scene to add new MeshRoad" ); else - missionGroup->addObject( newRoad ); + scene->addObject( newRoad ); Point3F pos( endPnt ); pos.z += mDefaultDepth * 0.5f; diff --git a/Engine/source/environment/editors/guiRiverEditorCtrl.cpp b/Engine/source/environment/editors/guiRiverEditorCtrl.cpp index 50abb45df..23df5900d 100644 --- a/Engine/source/environment/editors/guiRiverEditorCtrl.cpp +++ b/Engine/source/environment/editors/guiRiverEditorCtrl.cpp @@ -43,6 +43,8 @@ #include "T3D/gameBase/gameConnection.h" #include "T3D/prefab.h" +#include "T3D/Scene.h" + IMPLEMENT_CONOBJECT(GuiRiverEditorCtrl); ConsoleDocClass( GuiRiverEditorCtrl, @@ -444,12 +446,12 @@ void GuiRiverEditorCtrl::_process3DMouseDown( const Gui3DMouseEvent& event ) return; } - // Add to MissionGroup - SimGroup *missionGroup; - if ( !Sim::findObject( "MissionGroup", missionGroup ) ) - Con::errorf( "GuiRiverEditorCtrl - could not find MissionGroup to add new River" ); + // Add to Scene + Scene* scene = Scene::getRootScene(); + if ( !scene ) + Con::errorf( "GuiRiverEditorCtrl - could not find root Scene to add new River" ); else - missionGroup->addObject( newRiver ); + scene->addObject( newRiver ); Point3F pos( endPnt ); pos.z += mDefaultDepth * 0.5f; diff --git a/Engine/source/environment/editors/guiRoadEditorCtrl.cpp b/Engine/source/environment/editors/guiRoadEditorCtrl.cpp index 7a2ec8a96..c3b3f0e99 100644 --- a/Engine/source/environment/editors/guiRoadEditorCtrl.cpp +++ b/Engine/source/environment/editors/guiRoadEditorCtrl.cpp @@ -39,6 +39,8 @@ #include "gui/worldEditor/undoActions.h" #include "materials/materialDefinition.h" +#include "T3D/Scene.h" + IMPLEMENT_CONOBJECT(GuiRoadEditorCtrl); ConsoleDocClass( GuiRoadEditorCtrl, @@ -407,12 +409,12 @@ void GuiRoadEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event) newRoad->registerObject(); - // Add to MissionGroup - SimGroup *missionGroup; - if ( !Sim::findObject( "MissionGroup", missionGroup ) ) - Con::errorf( "GuiDecalRoadEditorCtrl - could not find MissionGroup to add new DecalRoad" ); + // Add to scene + Scene* scene = Scene::getRootScene(); + if ( !scene ) + Con::errorf( "GuiDecalRoadEditorCtrl - could not find scene to add new DecalRoad" ); else - missionGroup->addObject( newRoad ); + scene->addObject( newRoad ); newRoad->insertNode( tPos, mDefaultWidth, 0 ); U32 newNode = newRoad->insertNode( tPos, mDefaultWidth, 1 ); @@ -722,7 +724,7 @@ void GuiRoadEditorCtrl::renderScene(const RectI & updateRect) // Draw the spline based from the client-side road // because the serverside spline is not actually reliable... // Can be incorrect if the DecalRoad is before the TerrainBlock - // in the MissionGroup. + // in the scene. if ( mHoverRoad && mHoverRoad != mSelRoad ) { diff --git a/Engine/source/gui/worldEditor/editTSCtrl.cpp b/Engine/source/gui/worldEditor/editTSCtrl.cpp index 4b5104cc9..032e29a1f 100644 --- a/Engine/source/gui/worldEditor/editTSCtrl.cpp +++ b/Engine/source/gui/worldEditor/editTSCtrl.cpp @@ -38,6 +38,7 @@ #include "scene/sceneRenderState.h" #include "renderInstance/renderBinManager.h" +#include "T3D/Scene.h" IMPLEMENT_CONOBJECT(EditTSCtrl); ConsoleDocClass( EditTSCtrl, @@ -795,15 +796,15 @@ void EditTSCtrl::_renderScene( ObjectRenderInst*, SceneRenderState *state, BaseM GFXTransformSaver saver; // render through console callbacks - SimSet * missionGroup = static_cast(Sim::findObject("MissionGroup")); - if(missionGroup) + Scene* scene = Scene::getRootScene(); + if(scene) { mConsoleRendering = true; // [ rene, 27-Jan-10 ] This calls onEditorRender on the server objects instead // of on the client objects which seems a bit questionable to me. - for(SimSetIterator itr(missionGroup); *itr; ++itr) + for(SimSetIterator itr(scene); *itr; ++itr) { SceneObject* object = dynamic_cast< SceneObject* >( *itr ); if( object && object->isRenderEnabled() && !object->isHidden() ) diff --git a/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp b/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp index 24e6ea8c8..bcb53df80 100644 --- a/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp +++ b/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp @@ -51,6 +51,8 @@ #include "T3D/portal.h" #include "math/mPolyhedron.impl.h" +#include "T3D/Scene.h" + IMPLEMENT_CONOBJECT( GuiConvexEditorCtrl ); ConsoleDocClass( GuiConvexEditorCtrl, @@ -121,12 +123,12 @@ bool GuiConvexEditorCtrl::onWake() if ( !Parent::onWake() ) return false; - SimGroup *missionGroup; - if ( !Sim::findObject( "MissionGroup", missionGroup ) ) + Scene* scene = Scene::getRootScene(); + if ( !scene ) return true; - SimGroup::iterator itr = missionGroup->begin(); - for ( ; itr != missionGroup->end(); itr++ ) + SimGroup::iterator itr = scene->begin(); + for ( ; itr != scene->end(); itr++ ) { if ( dStrcmp( (*itr)->getClassName(), "ConvexShape" ) == 0 ) { @@ -166,8 +168,8 @@ void GuiConvexEditorCtrl::setVisible( bool val ) mSavedGizmoFlags = -1; } - SimGroup* misGroup; - if (Sim::findObject("MissionGroup", misGroup)) + Scene* scene = Scene::getRootScene(); + if (scene != nullptr) { //Make our proxy objects "real" again for (U32 i = 0; i < mProxyObjects.size(); ++i) @@ -184,7 +186,7 @@ void GuiConvexEditorCtrl::setVisible( bool val ) SceneObject* polyObj = createPolyhedralObject(mProxyObjects[i].targetObjectClass.c_str(), mProxyObjects[i].shapeProxy); - misGroup->addObject(polyObj); + scene->addObject(polyObj); //Now, remove the convex proxy mProxyObjects[i].shapeProxy->deleteObject(); @@ -222,19 +224,19 @@ void GuiConvexEditorCtrl::setVisible( bool val ) updateGizmoPos(); mSavedGizmoFlags = mGizmoProfile->flags; - SimGroup* misGroup; - if (Sim::findObject("MissionGroup", misGroup)) + Scene* scene = Scene::getRootScene(); + if (scene != nullptr) { - for (U32 c = 0; c < misGroup->size(); ++c) + for (U32 c = 0; c < scene->size(); ++c) { - bool isTrigger = (misGroup->at(c)->getClassName() == StringTable->insert("Trigger")); - bool isZone = (misGroup->at(c)->getClassName() == StringTable->insert("Zone")); - bool isPortal = (misGroup->at(c)->getClassName() == StringTable->insert("Portal")); - bool isOccluder = (misGroup->at(c)->getClassName() == StringTable->insert("OcclusionVolume")); + bool isTrigger = (scene->at(c)->getClassName() == StringTable->insert("Trigger")); + bool isZone = (scene->at(c)->getClassName() == StringTable->insert("Zone")); + bool isPortal = (scene->at(c)->getClassName() == StringTable->insert("Portal")); + bool isOccluder = (scene->at(c)->getClassName() == StringTable->insert("OcclusionVolume")); if (isZone || isPortal || isOccluder) { - SceneObject* sceneObj = static_cast(misGroup->at(c)); + SceneObject* sceneObj = static_cast(scene->at(c)); if (!sceneObj) { Con::errorf("WorldEditor::createConvexShapeFrom - Invalid object"); @@ -1350,9 +1352,9 @@ void GuiConvexEditorCtrl::setupShape( ConvexShape *shape ) shape->registerObject(); updateShape( shape ); - SimGroup *group; - if ( Sim::findObject( "missionGroup", group ) ) - group->addObject( shape ); + Scene* scene = Scene::getRootScene(); + if ( scene ) + scene->addObject( shape ); } void GuiConvexEditorCtrl::updateShape( ConvexShape *shape, S32 offsetFace ) @@ -1929,10 +1931,8 @@ ConvexEditorTool::EventResult ConvexEditorCreateTool::on3DMouseUp( const Gui3DMo } else if ( mStage == 0 ) { - SimGroup *mg; - Sim::findObject( "MissionGroup", mg ); - - mg->addObject( mNewConvex ); + SimGroup *scene = Scene::getRootScene(); + scene->addObject( mNewConvex ); mStage = -1; @@ -2128,9 +2128,9 @@ ConvexShape* ConvexEditorCreateTool::extrudeShapeFromFace( ConvexShape *inShape, newShape->registerObject(); mEditor->updateShape( newShape ); - SimGroup *group; - if ( Sim::findObject( "missionGroup", group ) ) - group->addObject( newShape ); + Scene* scene = Scene::getRootScene(); + if ( scene ) + scene->addObject( newShape ); return newShape; } diff --git a/Engine/source/gui/worldEditor/terrainEditor.cpp b/Engine/source/gui/worldEditor/terrainEditor.cpp index f1bf5fd58..41ba690d2 100644 --- a/Engine/source/gui/worldEditor/terrainEditor.cpp +++ b/Engine/source/gui/worldEditor/terrainEditor.cpp @@ -36,7 +36,7 @@ #include "gui/worldEditor/terrainActions.h" #include "terrain/terrMaterial.h" - +#include "T3D/Scene.h" IMPLEMENT_CONOBJECT(TerrainEditor); @@ -2405,10 +2405,10 @@ void TerrainEditor::reorderMaterial( S32 index, S32 orderPos ) DefineEngineMethod( TerrainEditor, attachTerrain, void, (const char * terrain), (""), "(TerrainBlock terrain)") { - SimSet * missionGroup = dynamic_cast(Sim::findObject("MissionGroup")); - if (!missionGroup) + Scene* scene = Scene::getRootScene(); + if (!scene) { - Con::errorf(ConsoleLogEntry::Script, "TerrainEditor::attach: no mission group found"); + Con::errorf(ConsoleLogEntry::Script, "TerrainEditor::attach: no scene found"); return; } @@ -2417,7 +2417,7 @@ DefineEngineMethod( TerrainEditor, attachTerrain, void, (const char * terrain), // attach to first found terrainBlock if (dStrcmp (terrain,"")==0) { - for(SimSetIterator itr(missionGroup); *itr; ++itr) + for(SimSetIterator itr(scene); *itr; ++itr) { TerrainBlock* terrBlock = dynamic_cast(*itr); diff --git a/Engine/source/gui/worldEditor/worldEditor.cpp b/Engine/source/gui/worldEditor/worldEditor.cpp index 478cc2e3d..2581cee72 100644 --- a/Engine/source/gui/worldEditor/worldEditor.cpp +++ b/Engine/source/gui/worldEditor/worldEditor.cpp @@ -51,6 +51,8 @@ #include "tools/editorTool.h" +#include "T3D/Scene.h" + IMPLEMENT_CONOBJECT( WorldEditor ); ConsoleDocClass( WorldEditor, @@ -455,19 +457,20 @@ bool WorldEditor::pasteSelection( bool dropSel ) return false; } - SimGroup *missionGroup = NULL; + SimGroup *targetGroup = NULL; if( isMethod( "getNewObjectGroup" ) ) { const char* targetGroupName = Con::executef( this, "getNewObjectGroup" ); - if( targetGroupName && targetGroupName[ 0 ] && !Sim::findObject( targetGroupName, missionGroup ) ) + if( targetGroupName && targetGroupName[ 0 ] && !Sim::findObject( targetGroupName, targetGroup) ) Con::errorf( "WorldEditor::pasteSelection() - no SimGroup called '%s'", targetGroupName ); } - if( !missionGroup ) + if( !targetGroup) { - if( !Sim::findObject( "MissionGroup", missionGroup ) ) + targetGroup = Scene::getRootScene(); + if( !targetGroup) { - Con::errorf( "WorldEditor::pasteSelection() - MissionGroup not found" ); + Con::errorf( "WorldEditor::pasteSelection() - Scene not found" ); return false; } } @@ -481,8 +484,8 @@ bool WorldEditor::pasteSelection( bool dropSel ) if ( !obj ) continue; - if ( missionGroup ) - missionGroup->addObject( obj ); + if (targetGroup) + targetGroup->addObject( obj ); action->addObject( obj ); @@ -594,7 +597,7 @@ void WorldEditor::hideObject(SceneObject* serverObj, bool hide) void WorldEditor::hideSelection(bool hide) { - SimGroup* pGroup = dynamic_cast(Sim::findObject("MissionGroup")); + Scene* scene = Scene::getRootScene(); // set server/client objects hide field for(U32 i = 0; i < mSelected->size(); i++) @@ -605,7 +608,7 @@ void WorldEditor::hideSelection(bool hide) // Prevent non-mission group objects (i.e. Player) from being hidden. // Otherwise it is difficult to show them again. - if(!serverObj->isChildOfGroup(pGroup)) + if(!serverObj->isChildOfGroup(scene)) continue; hideObject(serverObj, hide); @@ -2437,7 +2440,7 @@ void WorldEditor::renderScene( const RectI &updateRect ) } // Render the paths - renderPaths(Sim::findObject("MissionGroup")); + renderPaths(Scene::getRootScene()); // walk selected Selection* selection = getActiveSelectionSet(); @@ -3653,10 +3656,10 @@ void WorldEditor::makeSelectionPrefab( const char *filename ) return; } - SimGroup *missionGroup; - if ( !Sim::findObject( "MissionGroup", missionGroup ) ) + Scene* scene = Scene::getRootScene(); + if ( !scene) { - Con::errorf( "WorldEditor::makeSelectionPrefab - Could not find MissionGroup." ); + Con::errorf( "WorldEditor::makeSelectionPrefab - Could not find root Scene." ); return; } @@ -3746,7 +3749,7 @@ void WorldEditor::makeSelectionPrefab( const char *filename ) fabMat.inverse(); fab->setTransform( fabMat ); fab->registerObject(); - missionGroup->addObject( fab ); + scene->addObject( fab ); // Select it, mark level as dirty. clearSelection(); @@ -3812,10 +3815,10 @@ void WorldEditor::makeSelectionAMesh(const char *filename) return; } - SimGroup *missionGroup; - if (!Sim::findObject("MissionGroup", missionGroup)) + Scene* scene = Scene::getRootScene(); + if (!scene) { - Con::errorf("WorldEditor::makeSelectionAMesh - Could not find MissionGroup."); + Con::errorf("WorldEditor::makeSelectionAMesh - Could not find root Scene."); return; } @@ -3965,7 +3968,7 @@ void WorldEditor::makeSelectionAMesh(const char *filename) fabMat.inverse(); ts->setTransform(fabMat); ts->registerObject(); - missionGroup->addObject(ts); + scene->addObject(ts); // Select it, mark level as dirty. clearSelection(); diff --git a/Engine/source/scene/simPath.cpp b/Engine/source/scene/simPath.cpp index 2145af3cc..efa8f05f0 100644 --- a/Engine/source/scene/simPath.cpp +++ b/Engine/source/scene/simPath.cpp @@ -35,6 +35,8 @@ #include "renderInstance/renderPassManager.h" #include "console/engineAPI.h" +#include "T3D/Scene.h" + extern bool gEditingMission; //-------------------------------------------------------------------------- @@ -59,13 +61,13 @@ DefineEngineFunction(pathOnMissionLoadDone, void, (),, "@ingroup Networking") { // Need to load subobjects for all loaded interiors... - SimGroup* pMissionGroup = dynamic_cast(Sim::findObject("MissionGroup")); - AssertFatal(pMissionGroup != NULL, "Error, mission done loading and no mission group?"); + Scene* scene = Scene::getRootScene(); + AssertFatal(scene != NULL, "Error, mission done loading and no scene?"); U32 currStart = 0; U32 currEnd = 1; Vector groups; - groups.push_back(pMissionGroup); + groups.push_back(scene); while (true) { for (U32 i = currStart; i < currEnd; i++) { diff --git a/Engine/source/terrain/terrImport.cpp b/Engine/source/terrain/terrImport.cpp index 063a80c93..abdb1a6c2 100644 --- a/Engine/source/terrain/terrImport.cpp +++ b/Engine/source/terrain/terrImport.cpp @@ -31,6 +31,8 @@ #include "util/noise2d.h" #include "core/volume.h" +#include "T3D/Scene.h" + using namespace Torque; DefineEngineStaticMethod( TerrainBlock, createNew, S32, (String terrainName, U32 resolution, String materialName, bool genNoise),, @@ -108,9 +110,9 @@ DefineEngineStaticMethod( TerrainBlock, createNew, S32, (String terrainName, U32 terrain->registerObject( terrainName.c_str() ); // Add to mission group! - SimGroup *missionGroup; - if( Sim::findObject( "MissionGroup", missionGroup ) ) - missionGroup->addObject( terrain ); + Scene* scene = Scene::getRootScene(); + if(scene) + scene->addObject( terrain ); return terrain->getId(); } @@ -245,10 +247,10 @@ DefineEngineStaticMethod( TerrainBlock, import, S32, (String terrainName, String terrain->import( (*heightmap), heightScale, metersPerPixel, layerMap, materials, flipYAxis ); terrain->registerObject(); - // Add to mission group! - SimGroup *missionGroup; - if ( Sim::findObject( "MissionGroup", missionGroup ) ) - missionGroup->addObject( terrain ); + // Add to scene! + Scene* scene = Scene::getRootScene(); + if (scene) + scene->addObject( terrain ); } return terrain->getId(); diff --git a/Engine/source/ts/collada/colladaLights.cpp b/Engine/source/ts/collada/colladaLights.cpp index fcc4bb67d..574478cab 100644 --- a/Engine/source/ts/collada/colladaLights.cpp +++ b/Engine/source/ts/collada/colladaLights.cpp @@ -30,6 +30,7 @@ #include "T3D/pointLight.h" #include "T3D/spotLight.h" +#include "T3D/Scene.h" //----------------------------------------------------------------------------- // Collada elements are very similar, but are arranged as separate, unrelated @@ -140,11 +141,11 @@ static void processNodeLights(AppNode* appNode, const MatrixF& offset, SimGroup* // Load lights from a collada file and add to the scene. DefineEngineFunction( loadColladaLights, bool, (const char * filename, const char * parentGroup, const char * baseObject), ("", ""), - "(string filename, SimGroup parentGroup=MissionGroup, SimObject baseObject=-1)" + "(string filename, SimGroup parentGroup=Scene, SimObject baseObject=-1)" "Load all light instances from a COLLADA (.dae) file and add to the scene.\n" "@param filename COLLADA filename to load lights from\n" "@param parentGroup (optional) name of an existing simgroup to add the new " - "lights to (defaults to MissionGroup)\n" + "lights to (defaults to root Scene)\n" "@param baseObject (optional) name of an object to use as the origin (useful " "if you are loading the lights for a collada scene and have moved or rotated " "the geometry)\n" @@ -165,16 +166,16 @@ DefineEngineFunction( loadColladaLights, bool, (const char * filename, const cha Torque::Path path(filename); // Optional group to add the lights to. Create if it does not exist, and use - // the MissionGroup if not specified. - SimGroup* missionGroup = dynamic_cast(Sim::findObject("MissionGroup")); + // the root Scene if not specified. + Scene* scene = Scene::getRootScene(); SimGroup* group = 0; if (!String::isEmpty(parentGroup)){ if (!Sim::findObject(parentGroup, group)) { // Create the group if it could not be found group = new SimGroup; if (group->registerObject(parentGroup)) { - if (missionGroup) - missionGroup->addObject(group); + if (scene) + scene->addObject(group); } else { delete group; @@ -183,7 +184,7 @@ DefineEngineFunction( loadColladaLights, bool, (const char * filename, const cha } } if (!group) - group = missionGroup; + group = scene; // Optional object to provide the base transform MatrixF offset(true); diff --git a/Templates/BaseGame/game/core/clientServer/Core_ClientServer.cs b/Templates/BaseGame/game/core/clientServer/Core_ClientServer.cs index 51a7fbe76..1866adc12 100644 --- a/Templates/BaseGame/game/core/clientServer/Core_ClientServer.cs +++ b/Templates/BaseGame/game/core/clientServer/Core_ClientServer.cs @@ -18,7 +18,7 @@ function Core_ClientServer::create( %this ) exec( "./scripts/client/client.cs" ); exec( "./scripts/server/server.cs" ); - $Game::MissionGroup = "MissionGroup"; + $Game::MainScene = getScene(0); initServer(); diff --git a/Templates/BaseGame/game/core/clientServer/scripts/server/levelInfo.cs b/Templates/BaseGame/game/core/clientServer/scripts/server/levelInfo.cs index 51df91204..7da9a992e 100644 --- a/Templates/BaseGame/game/core/clientServer/scripts/server/levelInfo.cs +++ b/Templates/BaseGame/game/core/clientServer/scripts/server/levelInfo.cs @@ -115,7 +115,7 @@ function sendLoadInfoToClient( %client ) function parseMissionGroup( %className, %childGroup ) { if( getWordCount( %childGroup ) == 0) - %currentGroup = "MissionGroup"; + %currentGroup = getScene(0); else %currentGroup = %childGroup; @@ -136,7 +136,7 @@ function parseMissionGroup( %className, %childGroup ) function parseMissionGroupForIds( %className, %childGroup ) { if( getWordCount( %childGroup ) == 0) - %currentGroup = $Game::MissionGroup; + %currentGroup = getScene(0); else %currentGroup = %childGroup; diff --git a/Templates/BaseGame/game/core/clientServer/scripts/server/levelLoad.cs b/Templates/BaseGame/game/core/clientServer/scripts/server/levelLoad.cs index 92801318d..32da4e9dd 100644 --- a/Templates/BaseGame/game/core/clientServer/scripts/server/levelLoad.cs +++ b/Templates/BaseGame/game/core/clientServer/scripts/server/levelLoad.cs @@ -98,9 +98,9 @@ function loadMissionStage2() // Exec the mission. The MissionGroup (loaded components) is added to the ServerGroup exec(%file); - if( !isObject(MissionGroup) ) + if( !isObject(getScene(0)) ) { - $Server::LoadFailMsg = "No 'MissionGroup' found in mission \"" @ %file @ "\"."; + $Server::LoadFailMsg = "No Scene found in level \"" @ %file @ "\"."; } } @@ -141,7 +141,7 @@ function loadMissionStage2() function endMission() { - if (!isObject( MissionGroup )) + if (!isObject( getScene(0) )) return; echo("*** ENDING MISSION"); @@ -159,7 +159,7 @@ function endMission() } // Delete everything - MissionGroup.delete(); + getScene(0).delete(); MissionCleanup.delete(); clearServerPaths(); diff --git a/Templates/BaseGame/game/core/clientServer/scripts/server/server.cs b/Templates/BaseGame/game/core/clientServer/scripts/server/server.cs index 17f127314..47be979db 100644 --- a/Templates/BaseGame/game/core/clientServer/scripts/server/server.cs +++ b/Templates/BaseGame/game/core/clientServer/scripts/server/server.cs @@ -243,7 +243,7 @@ function onServerDestroyed() { physicsStopSimulation("server"); - if (!isObject( MissionGroup )) + if (!isObject( getScene(0) )) return; echo("*** ENDING MISSION"); @@ -262,7 +262,7 @@ function onServerDestroyed() } // Delete everything - MissionGroup.delete(); + getScene(0).delete(); MissionCleanup.delete(); clearServerPaths(); diff --git a/Templates/BaseGame/game/tools/convexEditor/main.cs b/Templates/BaseGame/game/tools/convexEditor/main.cs index 71e6b3090..4577f20e2 100644 --- a/Templates/BaseGame/game/tools/convexEditor/main.cs +++ b/Templates/BaseGame/game/tools/convexEditor/main.cs @@ -189,7 +189,7 @@ function ConvexEditorPlugin::onSaveMission( %this, %missionFile ) { if( ConvexEditorGui.isDirty ) { - MissionGroup.save( %missionFile ); + getScene(0).save( %missionFile ); ConvexEditorGui.isDirty = false; } } diff --git a/Templates/BaseGame/game/tools/gui/colladaImport.ed.gui b/Templates/BaseGame/game/tools/gui/colladaImport.ed.gui index 30838c76d..4c0f60316 100644 --- a/Templates/BaseGame/game/tools/gui/colladaImport.ed.gui +++ b/Templates/BaseGame/game/tools/gui/colladaImport.ed.gui @@ -1584,7 +1584,7 @@ function ColladaImportDlg::onOK(%this) function ColladaImportDlg::loadLights(%this) { // Get the ID of the last object added - %obj = MissionGroup.getObject(MissionGroup.getCount()-1); + %obj = getScene(0).getObject(getScene(0).getCount()-1); // Create a new SimGroup to hold the model and lights %group = new SimGroup(); @@ -1596,7 +1596,7 @@ function ColladaImportDlg::loadLights(%this) { %group.add(%obj); %group.bringToFront(%obj); - MissionGroup.add(%group); + getScene(0).add(%group); if (EditorTree.isVisible()) { EditorTree.removeItem(EditorTree.findItemByObjectId(%obj)); diff --git a/Templates/BaseGame/game/tools/levels/BlankRoom.mis b/Templates/BaseGame/game/tools/levels/BlankRoom.mis index 3d43918be..7e1243a8d 100644 --- a/Templates/BaseGame/game/tools/levels/BlankRoom.mis +++ b/Templates/BaseGame/game/tools/levels/BlankRoom.mis @@ -1,5 +1,5 @@ //--- OBJECT WRITE BEGIN --- -new SimGroup(MissionGroup) { +new Scene(EditorTemplateLevel) { canSave = "1"; canSaveDynamicFields = "1"; cdTrack = "2"; diff --git a/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.cs b/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.cs index 6564362e4..30c5dac26 100644 --- a/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.cs +++ b/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.cs @@ -1051,7 +1051,7 @@ function MaterialEditorGui::updateActiveMaterialName(%this, %name) // Some objects (ConvexShape, DecalRoad etc) reference Materials by name => need // to find and update all these references so they don't break when we rename the // Material. - MaterialEditorGui.updateMaterialReferences( MissionGroup, %action.oldName, %action.newName ); + MaterialEditorGui.updateMaterialReferences( getScene(0), %action.oldName, %action.newName ); } function MaterialEditorGui::updateMaterialReferences( %this, %obj, %oldName, %newName ) diff --git a/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditorUndo.ed.cs b/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditorUndo.ed.cs index 184f02ce4..c00d8f70f 100644 --- a/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditorUndo.ed.cs +++ b/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditorUndo.ed.cs @@ -187,7 +187,7 @@ function ActionUpdateActiveMaterialAnimationFlags::undo(%this) function ActionUpdateActiveMaterialName::redo(%this) { %this.material.setName(%this.newName); - MaterialEditorGui.updateMaterialReferences( MissionGroup, %this.oldName, %this.newName ); + MaterialEditorGui.updateMaterialReferences( getScene(0), %this.oldName, %this.newName ); if( MaterialEditorPreviewWindow.isVisible() && MaterialEditorGui.currentMaterial == %this.material ) { @@ -199,7 +199,7 @@ function ActionUpdateActiveMaterialName::redo(%this) function ActionUpdateActiveMaterialName::undo(%this) { %this.material.setName(%this.oldName); - MaterialEditorGui.updateMaterialReferences( MissionGroup, %this.newName, %this.oldName ); + MaterialEditorGui.updateMaterialReferences( getScene(0), %this.newName, %this.oldName ); if( MaterialEditorPreviewWindow.isVisible() && MaterialEditorGui.currentMaterial == %this.material ) { diff --git a/Templates/BaseGame/game/tools/meshRoadEditor/main.cs b/Templates/BaseGame/game/tools/meshRoadEditor/main.cs index d101e50b0..a6ccbc507 100644 --- a/Templates/BaseGame/game/tools/meshRoadEditor/main.cs +++ b/Templates/BaseGame/game/tools/meshRoadEditor/main.cs @@ -164,7 +164,7 @@ function MeshRoadEditorPlugin::onSaveMission( %this, %missionFile ) { if( MeshRoadEditorGui.isDirty ) { - MissionGroup.save( %missionFile ); + getScene(0).save( %missionFile ); MeshRoadEditorGui.isDirty = false; } } diff --git a/Templates/BaseGame/game/tools/missionAreaEditor/main.cs b/Templates/BaseGame/game/tools/missionAreaEditor/main.cs index 000197bc6..946d9ab1f 100644 --- a/Templates/BaseGame/game/tools/missionAreaEditor/main.cs +++ b/Templates/BaseGame/game/tools/missionAreaEditor/main.cs @@ -114,7 +114,7 @@ function MissionAreaEditorPlugin::createNewMissionArea(%this) %newMissionArea = new MissionArea(); %newMissionArea.area = "-256 -256 512 512"; - MissionGroup.add(%newMissionArea); + getScene(0).add(%newMissionArea); EditorGui.setEditor(MissionAreaEditorPlugin); diff --git a/Templates/BaseGame/game/tools/navEditor/CreateNewNavMeshDlg.gui b/Templates/BaseGame/game/tools/navEditor/CreateNewNavMeshDlg.gui index 755bce30a..0ea3f0d02 100644 --- a/Templates/BaseGame/game/tools/navEditor/CreateNewNavMeshDlg.gui +++ b/Templates/BaseGame/game/tools/navEditor/CreateNewNavMeshDlg.gui @@ -354,13 +354,13 @@ function CreateNewNavMeshDlg::create(%this) if(MeshMissionBounds.isStateOn()) { - if(!isObject(MissionGroup)) + if(!isObject(getScene(0))) { - MessageBoxOk("Error", "You must have a MissionGroup to use the mission bounds function."); + MessageBoxOk("Error", "You must have a Scene to use the mission bounds function."); return; } // Get maximum extents of all objects. - %box = MissionBoundsExtents(MissionGroup); + %box = MissionBoundsExtents(getScene(0)); %pos = GetBoxCenter(%box); %scale = (GetWord(%box, 3) - GetWord(%box, 0)) / 2 + 5 SPC (GetWord(%box, 4) - GetWord(%box, 1)) / 2 + 5 @@ -380,7 +380,7 @@ function CreateNewNavMeshDlg::create(%this) scale = %this-->MeshScale.getText(); }; } - MissionGroup.add(%mesh); + getScene(0).add(%mesh); NavEditorGui.selectObject(%mesh); Canvas.popDialog(CreateNewNavMeshDlg); diff --git a/Templates/BaseGame/game/tools/navEditor/main.cs b/Templates/BaseGame/game/tools/navEditor/main.cs index 6af3abf19..dd6f15772 100644 --- a/Templates/BaseGame/game/tools/navEditor/main.cs +++ b/Templates/BaseGame/game/tools/navEditor/main.cs @@ -205,7 +205,7 @@ function NavEditorPlugin::onSaveMission(%this, %missionFile) { if(NavEditorGui.isDirty) { - MissionGroup.save(%missionFile); + getScene(0).save(%missionFile); NavEditorGui.isDirty = false; } } diff --git a/Templates/BaseGame/game/tools/riverEditor/main.cs b/Templates/BaseGame/game/tools/riverEditor/main.cs index eafb3c3c8..5c082bd6d 100644 --- a/Templates/BaseGame/game/tools/riverEditor/main.cs +++ b/Templates/BaseGame/game/tools/riverEditor/main.cs @@ -178,7 +178,9 @@ function RiverEditorPlugin::onSaveMission( %this, %missionFile ) { if( RiverEditorGui.isDirty ) { - MissionGroup.save( %missionFile ); + //Get our root scene, which would be the level + getScene(0).save( %missionFile ); + RiverEditorGui.isDirty = false; } } diff --git a/Templates/BaseGame/game/tools/roadEditor/main.cs b/Templates/BaseGame/game/tools/roadEditor/main.cs index f45823670..25757a965 100644 --- a/Templates/BaseGame/game/tools/roadEditor/main.cs +++ b/Templates/BaseGame/game/tools/roadEditor/main.cs @@ -156,7 +156,7 @@ function RoadEditorPlugin::onSaveMission( %this, %missionFile ) { if( RoadEditorGui.isDirty ) { - MissionGroup.save( %missionFile ); + getScene(0).save( %missionFile ); RoadEditorGui.isDirty = false; } } diff --git a/Templates/BaseGame/game/tools/shapeEditor/main.cs b/Templates/BaseGame/game/tools/shapeEditor/main.cs index efbc1c538..40b6af6e0 100644 --- a/Templates/BaseGame/game/tools/shapeEditor/main.cs +++ b/Templates/BaseGame/game/tools/shapeEditor/main.cs @@ -175,7 +175,7 @@ function ShapeEditorPlugin::open(%this, %filename) ShapeEdNodes-->worldTransform.setStateOn(1); // Initialise and show the shape editor - ShapeEdShapeTreeView.open(MissionGroup); + ShapeEdShapeTreeView.open(getScene(0)); ShapeEdShapeTreeView.buildVisibleTree(true); ShapeEdPreviewGui.setVisible(true); diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/TimeAdjustGui.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/TimeAdjustGui.ed.gui index 8eaf11d4c..4b7b8a26e 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/TimeAdjustGui.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/TimeAdjustGui.ed.gui @@ -184,11 +184,11 @@ function TimeAdjustSliderCtrl::onAction(%this) if ( !isObject( %this.tod ) ) { - if ( isObject( MissionGroup ) ) + if ( isObject( getScene(0) ) ) { - for ( %i = 0; %i < MissionGroup.getCount(); %i++ ) + for ( %i = 0; %i < getScene(0).getCount(); %i++ ) { - %obj = MissionGroup.getObject( %i ); + %obj = getScene(0).getObject( %i ); if ( %obj.getClassName() $= "TimeOfDay" ) { diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui index 74f1200c6..fce36e940 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui @@ -947,10 +947,10 @@ function ObjectBuilderGui::buildPlayerDropPoint(%this) %this.addField("spawnClass", "TypeString", "Spawn Class", "Player"); %this.addField("spawnDatablock", "TypeDataBlock", "Spawn Data", "PlayerData DefaultPlayerData"); - if( EWCreatorWindow.objectGroup.getID() == MissionGroup.getID() ) + if( EWCreatorWindow.objectGroup.getID() == getScene(0).getID() ) { if( !isObject("PlayerDropPoints") ) - MissionGroup.add( new SimGroup("PlayerDropPoints") ); + getScene(0).add( new SimGroup("PlayerDropPoints") ); %this.objectGroup = "PlayerDropPoints"; } @@ -967,10 +967,10 @@ function ObjectBuilderGui::buildObserverDropPoint(%this) %this.addField("spawnClass", "TypeString", "Spawn Class", "Camera"); %this.addField("spawnDatablock", "TypeDataBlock", "Spawn Data", "CameraData Observer"); - if( EWCreatorWindow.objectGroup.getID() == MissionGroup.getID() ) + if( EWCreatorWindow.objectGroup.getID() == getScene(0).getID() ) { if( !isObject("ObserverDropPoints") ) - MissionGroup.add( new SimGroup("ObserverDropPoints") ); + getScene(0).add( new SimGroup("ObserverDropPoints") ); %this.objectGroup = "ObserverDropPoints"; } diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs index 50aac111b..47ac61e0d 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -637,7 +637,7 @@ function EditorGui::addCameraBookmark( %this, %name ) if( !isObject(CameraBookmarks) ) { %grp = new SimGroup(CameraBookmarks); - MissionGroup.add(%grp); + getScene(0).add(%grp); } CameraBookmarks.add( %obj ); @@ -835,12 +835,17 @@ function EditorGui::syncCameraGui( %this ) function WorldEditorPlugin::onActivated( %this ) { + if(!isObject(Scenes)) + $scenesRootGroup = new SimGroup(Scenes); + + $scenesRootGroup.add(getScene(0)); + EditorGui.bringToFront( EWorldEditor ); EWorldEditor.setVisible(true); EditorGui.menuBar.insert( EditorGui.worldMenu, EditorGui.menuBar.dynamicItemInsertPos ); EWorldEditor.makeFirstResponder(true); - EditorTree.open(MissionGroup,true); - EWCreatorWindow.setNewObjectGroup(MissionGroup); + EditorTree.open($scenesRootGroup,true); + EWCreatorWindow.setNewObjectGroup(getScene(0)); EWorldEditor.syncGui(); @@ -1464,7 +1469,7 @@ function EditorTree::onDeleteObject( %this, %object ) return true; if( %object == EWCreatorWindow.objectGroup ) - EWCreatorWindow.setNewObjectGroup( MissionGroup ); + EWCreatorWindow.setNewObjectGroup( getScene(0) ); // Append it to our list. %this.undoDeleteList = %this.undoDeleteList TAB %object; @@ -1596,6 +1601,13 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj ) { %popup.item[ 0 ] = "Add Camera Bookmark" TAB "" TAB "EditorGui.addCameraBookmarkByGui();"; } + else if( %obj.isMemberOfClass( "Scene" )) + { + %popup.item[ 0 ] = "Set as Active Scene" TAB "" TAB "EditorTree.showItemRenameCtrl( EditorTree.findItemByObjectId(" @ %popup.object @ ") );"; + %popup.item[ 1 ] = "Delete" TAB "" TAB "EWorldEditor.deleteMissionObject(" @ %popup.object @ ");"; + %popup.item[ 2 ] = "Inspect" TAB "" TAB "inspectObject(" @ %popup.object @ ");"; + %popup.item[ 3 ] = "-"; + } else { %popup.object = %obj; @@ -1673,8 +1685,8 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj ) if( %haveObjectEntries ) { - %popup.enableItem( 0, %obj.isNameChangeAllowed() && %obj.getName() !$= "MissionGroup" ); - %popup.enableItem( 1, %obj.getName() !$= "MissionGroup" ); + %popup.enableItem( 0, %obj.isNameChangeAllowed() && %obj !$= getScene(0) ); + %popup.enableItem( 1, %obj !$= getScene(0) ); if( %haveLockAndHideEntries ) { @@ -2025,21 +2037,21 @@ function EWorldEditor::syncToolPalette( %this ) function EWorldEditor::addSimGroup( %this, %groupCurrentSelection ) { %activeSelection = %this.getActiveSelection(); - if ( %activeSelection.getObjectIndex( MissionGroup ) != -1 ) + if ( %activeSelection.getObjectIndex( getScene(0) ) != -1 ) { - MessageBoxOK( "Error", "Cannot add MissionGroup to a new SimGroup" ); + MessageBoxOK( "Error", "Cannot add Scene to a new SimGroup" ); return; } // Find our parent. - %parent = MissionGroup; + %parent = getScene(0); if( !%groupCurrentSelection && isObject( %activeSelection ) && %activeSelection.getCount() > 0 ) { %firstSelectedObject = %activeSelection.getObject( 0 ); if( %firstSelectedObject.isMemberOfClass( "SimGroup" ) ) %parent = %firstSelectedObject; - else if( %firstSelectedObject.getId() != MissionGroup.getId() ) + else if( %firstSelectedObject.getId() != getScene(0).getId() ) %parent = %firstSelectedObject.parentGroup; } diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/SelectObjectsWindow.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/SelectObjectsWindow.ed.cs index 2c436f74f..65fae1760 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/SelectObjectsWindow.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/SelectObjectsWindow.ed.cs @@ -40,7 +40,7 @@ function ESelectObjectsWindow::toggleVisibility( %this ) /// to start searching for objects. function ESelectObjectsWindow::getRootGroup( %this ) { - return MissionGroup; + return getScene(0); } //--------------------------------------------------------------------------------------------- diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.cs index 006031668..a2841d977 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.cs @@ -179,7 +179,7 @@ function EWCreatorWindow::createStatic( %this, %file ) return; if( !isObject(%this.objectGroup) ) - %this.setNewObjectGroup( MissionGroup ); + %this.setNewObjectGroup( getScene(0) ); %objId = new TSStatic() { @@ -197,7 +197,7 @@ function EWCreatorWindow::createPrefab( %this, %file ) return; if( !isObject(%this.objectGroup) ) - %this.setNewObjectGroup( MissionGroup ); + %this.setNewObjectGroup( getScene(0) ); %objId = new Prefab() { @@ -215,7 +215,7 @@ function EWCreatorWindow::createObject( %this, %cmd ) return; if( !isObject(%this.objectGroup) ) - %this.setNewObjectGroup( MissionGroup ); + %this.setNewObjectGroup( getScene(0) ); pushInstantGroup(); %objId = eval(%cmd); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/editors/worldEditor.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/editors/worldEditor.ed.cs index eb89d1a30..2a4853e62 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/editors/worldEditor.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/editors/worldEditor.ed.cs @@ -124,6 +124,12 @@ function WorldEditor::onSelectionCentroidChanged( %this ) Inspector.refresh(); } +function WorldEditor::setSceneAsDirty(%this) +{ + EWorldEditor.isDirty = true; + +} + ////////////////////////////////////////////////////////////////////////// function WorldEditor::init(%this) @@ -198,7 +204,7 @@ function WorldEditor::export(%this) function WorldEditor::doExport(%this, %file) { - missionGroup.save("~/editor/" @ %file, true); + getScene(0).save("~/editor/" @ %file, true); } function WorldEditor::import(%this) diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.cs index 8c558bfef..c6ca23e46 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.cs @@ -272,7 +272,7 @@ function EditorSaveMission() // now write the terrain and mission files out: if(EWorldEditor.isDirty || ETerrainEditor.isMissionDirty) - MissionGroup.save($Server::MissionFile); + getScene(0).save($Server::MissionFile); if(ETerrainEditor.isDirty) { // Find all of the terrain files @@ -483,6 +483,21 @@ function EditorOpenMission(%filename) } } +function EditorOpenSceneAppend(%levelAsset) +{ + //Load the asset's level file + exec(%levelAsset.levelFile); + + //We'll assume the scene name and assetname are the same for now + %sceneName = %levelAsset.AssetName; + %scene = nameToID(%sceneName); + if(isObject(%scene)) + { + //Append it to our scene heirarchy + $scenesRootGroup.add(%scene); + } +} + function EditorExportToCollada() { From 837b936bae743589681c04833f88f29fa8730141 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 16:08:47 -0600 Subject: [PATCH 53/75] Allows special inspectorFields to override the height they use in the rollouts --- Engine/source/gui/editor/inspector/field.cpp | 15 ++++++++++++--- Engine/source/gui/editor/inspector/field.h | 4 ++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Engine/source/gui/editor/inspector/field.cpp b/Engine/source/gui/editor/inspector/field.cpp index 2808ee140..02046f7a9 100644 --- a/Engine/source/gui/editor/inspector/field.cpp +++ b/Engine/source/gui/editor/inspector/field.cpp @@ -50,7 +50,9 @@ GuiInspectorField::GuiInspectorField( GuiInspector* inspector, mField( field ), mFieldArrayIndex( NULL ), mEdit( NULL ), - mTargetObject(NULL) + mTargetObject(NULL), + mUseHeightOverride(false), + mHeightOverride(18) { if( field != NULL ) mCaption = field->pFieldname; @@ -77,7 +79,9 @@ GuiInspectorField::GuiInspectorField() mTargetObject(NULL), mVariableName(StringTable->EmptyString()), mCallbackName(StringTable->EmptyString()), - mSpecialEditField(false) + mSpecialEditField(false), + mUseHeightOverride(false), + mHeightOverride(18) { setCanSave( false ); } @@ -112,7 +116,12 @@ bool GuiInspectorField::onAdd() if ( mEdit == NULL ) return false; - setBounds(0,0,100,18); + S32 fieldHeight = 18; + + if (mUseHeightOverride) + fieldHeight = mHeightOverride; + + setBounds(0,0,100, fieldHeight); // Add our edit as a child addObject( mEdit ); diff --git a/Engine/source/gui/editor/inspector/field.h b/Engine/source/gui/editor/inspector/field.h index cb1210b53..3df9f5ece 100644 --- a/Engine/source/gui/editor/inspector/field.h +++ b/Engine/source/gui/editor/inspector/field.h @@ -84,6 +84,10 @@ class GuiInspectorField : public GuiControl /// bool mHighlighted; + //These are so we can special-case our height for additional room on certain field-types + bool mUseHeightOverride; + U32 mHeightOverride; + //An override that lets us bypass inspector-dependent logic for setting/getting variables/fields bool mSpecialEditField; //An override to make sure this field is associated to an object that isn't expressly From b865e1d1816f79699f63ceb6774d790679bb40e2 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 16:18:03 -0600 Subject: [PATCH 54/75] Updates TextEdit value when focus is lost. --- Engine/source/gui/controls/guiTextEditCtrl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Engine/source/gui/controls/guiTextEditCtrl.cpp b/Engine/source/gui/controls/guiTextEditCtrl.cpp index 968fe17a6..65bb331a6 100644 --- a/Engine/source/gui/controls/guiTextEditCtrl.cpp +++ b/Engine/source/gui/controls/guiTextEditCtrl.cpp @@ -1241,6 +1241,9 @@ void GuiTextEditCtrl::onLoseFirstResponder() root->disableKeyboardTranslation(); } + updateHistory(&mTextBuffer, true); + mHistoryDirty = false; + //execute the validate command if( mValidateCommand.isNotEmpty() ) evaluate( mValidateCommand ); From a949326cabe3af9286e97799a89f5260399408ca Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 16:36:40 -0600 Subject: [PATCH 55/75] Adds gui3DProjectionCtrl so a gui control can be tracked to a point in 3d space --- .../gui/controls/gui3DProjectionCtrl.cpp | 298 ++++++++++++++++++ .../source/gui/controls/gui3DProjectionCtrl.h | 77 +++++ 2 files changed, 375 insertions(+) create mode 100644 Engine/source/gui/controls/gui3DProjectionCtrl.cpp create mode 100644 Engine/source/gui/controls/gui3DProjectionCtrl.h diff --git a/Engine/source/gui/controls/gui3DProjectionCtrl.cpp b/Engine/source/gui/controls/gui3DProjectionCtrl.cpp new file mode 100644 index 000000000..340cfc186 --- /dev/null +++ b/Engine/source/gui/controls/gui3DProjectionCtrl.cpp @@ -0,0 +1,298 @@ +//----------------------------------------------------------------------------- +// Gui3DProjectionCtrl +// Doppelganger Inc +// Orion Elenzil 200701 +// +// This control is meant to be merely a container for other controls. +// What's neat is that it's easy to 'attach' this control to a point in world-space +// or, more interestingly, to an object such as a player. +// +// Usage: +// * Create the Gui3DProjectionControl - by default it will be at 0, 0, 0. +// * You can change where it's located by setting the field "offsetWorld". +// - note you can specify that right in the .gui file +// * You can attach it to any SceneObject by calling "setAttachedTo()". +// +// Behaviour: +// * If you're attaching it to a player, by default it will center on the player's head. +// * If you attach it to an object, by default it will delete itself if the object is deleted. +// * Doesn't occlude w/r/t 3D objects. +// +// Console Methods: +// * SetAttachedTo(SceneObject) +// * GetAttachedTo() +// +// Params: +// * pointWorld - read/write point in worldspace. read-only if attached to an object. +// * offsetObject - an offset in objectspace. default 0, 0, 0. +// * offsetWorld - an offset in worldspace. default 0, 0, 0. +// * offsetScreen - an offset in screenspace. default 0, 0. +// * hAlign - horizontal alignment. 0 = left, 1 = center, 2 = right. default center. +// * vAlign - vertical alignment. 0 = top, 1 = center, 2 = bottomt. default center. +// * useEyePoint - H & V usage of the eyePoint, if player object. default 0, 1. (ie - use only the vertical component) +// * autoDelete - self-delete when attachedTo object is deleted. default true. +// +// Todo: +// * occlusion - hide the control when its anchor point is occluded. +// * integrate w/ zbuffer - this would actually be a change to the whole GuiControl system. +// * allow attaching to arbitrary nodes in a skeleton. +// * avoid projection when the object is out of the frustum. +// +// oxe 20070111 +//----------------------------------------------------------------------------- + +#include "console/console.h" +#include "console/consoleTypes.h" +#include "scene/SceneObject.h" +#include "T3D/player.h" +#include "gui/controls/Gui3DProjectionCtrl.h" + +IMPLEMENT_CONOBJECT(Gui3DProjectionCtrl); + +//----------------------------------------------------------------------------- + +Gui3DProjectionCtrl::Gui3DProjectionCtrl() +{ + mTSCtrl = NULL; + mAttachedTo = NULL; + mAttachedToPlayer = NULL; + mAutoDelete = true; + mHAlign = center; + mVAlign = center; + mUseEyePoint.x = 0; + mUseEyePoint.y = 1; + + mPtWorld .set(0, 0, 0); + mPtProj .set(0, 0); + mOffsetObject.set(0, 0, 0); + mOffsetWorld .set(0, 0, 0); + mOffsetScreen.set(0, 0); +} + +void Gui3DProjectionCtrl::initPersistFields() +{ + Parent::initPersistFields(); + addGroup("3DProjection"); + addField("pointWorld" , TypePoint3F , Offset(mPtWorld , Gui3DProjectionCtrl)); + addField("offsetObject" , TypePoint3F , Offset(mOffsetObject , Gui3DProjectionCtrl)); + addField("offsetWorld" , TypePoint3F , Offset(mOffsetWorld , Gui3DProjectionCtrl)); + addField("offsetScreen" , TypePoint2I , Offset(mOffsetScreen , Gui3DProjectionCtrl)); + addField("hAlign" , TypeS32 , Offset(mHAlign , Gui3DProjectionCtrl)); + addField("vAlign" , TypeS32 , Offset(mVAlign , Gui3DProjectionCtrl)); + addField("useEyePoint" , TypePoint2I , Offset(mUseEyePoint , Gui3DProjectionCtrl)); + addField("autoDelete" , TypeBool , Offset(mAutoDelete , Gui3DProjectionCtrl)); + endGroup("3DProjection"); +} + +void Gui3DProjectionCtrl::onRender(Point2I offset, const RectI &updateRect) +{ + doPositioning(); + doProjection(); + doAlignment(); + + Parent::onRender(offset, updateRect); +} + +void Gui3DProjectionCtrl::resizeDuringRender() +{ + doPositioning(); + doProjection (); + doAlignment (); +} + + + +bool Gui3DProjectionCtrl::onWake() +{ + // walk up the GUI tree until we find a GuiTSCtrl. + + mTSCtrl = NULL; + GuiControl* walkCtrl = getParent(); + AssertFatal(walkCtrl != NULL, "Gui3DProjectionCtrl::onWake() - NULL parent"); + bool doMore = true; + + while (doMore) + { + mTSCtrl = dynamic_cast(walkCtrl); + walkCtrl = walkCtrl->getParent(); + doMore = (mTSCtrl == NULL) && (walkCtrl != NULL); + } + + if (!mTSCtrl) + Con::errorf("Gui3DProjectionCtrl::onWake() - no TSCtrl parent"); + + return Parent::onWake(); +} + +void Gui3DProjectionCtrl::onSleep() +{ + mTSCtrl = NULL; + return Parent::onSleep(); +} + +void Gui3DProjectionCtrl::onDeleteNotify(SimObject* obj) +{ + // - SimSet assumes that obj is a member of THIS, which in our case ain't true. + // oxe 20070116 - the following doesn't compile on GCC. + // SimSet::Parent::onDeleteNotify(obj); + + if (!obj) + { + Con::warnf("Gui3DProjectionCtrl::onDeleteNotify - got NULL"); + return; + } + + if (obj != mAttachedTo) + { + if (mAttachedTo != NULL) + Con::warnf("Gui3DProjectionCtrl::onDeleteNotify - got unexpected object: %d vs. %d", obj->getId(), mAttachedTo->getId()); + return; + } + + if (mAutoDelete) + this->deleteObject(); +} + +//----------------------------------------------------------------------------- + +void Gui3DProjectionCtrl::doPositioning() +{ + if (mAttachedTo == NULL) + return; + + Point3F ptBase; // the regular position of the object. + Point3F ptEye; // the render position of the eye node, if a player object. + Point3F pt; // combination of ptBase and ptEye. + + MatrixF mat; // utility + + mAttachedTo->getRenderTransform().getColumn(3, &ptBase); + + if (mAttachedToPlayer != NULL) + { + mAttachedToPlayer->getRenderEyeTransform(&mat); + mat.getColumn(3, &ptEye); + } + else + { + ptEye = ptBase; + } + + // use some components from ptEye but other position from ptBase + pt = ptBase; + if (mUseEyePoint.x != 0) + { + pt.x = ptEye.x; + pt.y = ptEye.y; + } + if (mUseEyePoint.y != 0) + { + pt.z = ptEye.z; + } + + // object-space offset + Point3F offsetObj; + QuatF quat(mAttachedTo->getRenderTransform()); + quat.mulP(mOffsetObject, &offsetObj); + pt += offsetObj; + + + // world-space offset + pt += mOffsetWorld; + + mPtWorld = pt; +} + + +void Gui3DProjectionCtrl::doProjection() +{ + if (!mTSCtrl) + return; + + Point3F pt; + + if (!mTSCtrl->project(mPtWorld, &pt)) + return; + + mPtProj.x = (S32)(pt.x + 0.5f); + mPtProj.y = (S32)(pt.y + 0.5f); +} + +void Gui3DProjectionCtrl::doAlignment() +{ + // alignment + Point2I offsetAlign; + switch(mHAlign) + { + default: + case center: + offsetAlign.x = -getBounds().extent.x / 2; + break; + case min: + offsetAlign.x = 0; + break; + case max: + offsetAlign.x = -getBounds().extent.x; + break; + } + + switch(mVAlign) + { + default: + case center: + offsetAlign.y = -getBounds().extent.y / 2; + break; + case min: + offsetAlign.y = 0; + break; + case max: + offsetAlign.y = -getBounds().extent.y; + break; + } + + // projected point + mPtScreen = mPtProj; + + // alignment offset + mPtScreen += offsetAlign; + + // screen offset + mPtScreen += mOffsetScreen; + +// setTrgPosition(mPtScreen); + RectI bounds = getBounds(); + bounds.point = mPtScreen; + setBounds(bounds); +} + +//----------------------------------------------------------------------------- + +void Gui3DProjectionCtrl::setAttachedTo(SceneObject* obj) +{ + if (obj == mAttachedTo) + return; + + if (mAttachedTo) + clearNotify(mAttachedTo); + + mAttachedTo = obj; + mAttachedToPlayer = dynamic_cast(obj); + + if (mAttachedTo) + deleteNotify(mAttachedTo); +} + +DefineEngineMethod(Gui3DProjectionCtrl, setAttachedTo, void, (SceneObject* target), (nullAsType()), "(object)") +{ + if(target) + object->setAttachedTo(target); +} + +DefineEngineMethod(Gui3DProjectionCtrl, getAttachedTo, S32, (),, "()") +{ + SceneObject* obj = object->getAttachedTo(); + if (!obj) + return 0; + else + return obj->getId(); +} diff --git a/Engine/source/gui/controls/gui3DProjectionCtrl.h b/Engine/source/gui/controls/gui3DProjectionCtrl.h new file mode 100644 index 000000000..b2d1949b0 --- /dev/null +++ b/Engine/source/gui/controls/gui3DProjectionCtrl.h @@ -0,0 +1,77 @@ +//----------------------------------------------------------------------------- +// Gui3DProjectionCtrl +// Doppelganger Inc +// Orion Elenzil 200701 +// +// +//----------------------------------------------------------------------------- + +#ifndef _GUI3DPROJECTIONCTRL_H_ +#define _GUI3DPROJECTIONCTRL_H_ + +#include "gui/core/guiTypes.h" +#include "gui/core/guiControl.h" +#include "gui/3d/guiTSControl.h" +#include "scene/sceneObject.h" +#include "T3D/player.h" + +class Gui3DProjectionCtrl : public GuiControl +{ + +//----------------------------------------------------------------------------- +// stock stuff +public: + Gui3DProjectionCtrl(); + typedef GuiControl Parent; + + DECLARE_CONOBJECT(Gui3DProjectionCtrl); + + static void initPersistFields (); + +//----------------------------------------------------------------------------- +// more interesting stuff + + GuiTSCtrl* mTSCtrl; /// must be a child of one of these. + SimObjectPtr mAttachedTo; /// optional object we're attached to. + SimObjectPtr mAttachedToPlayer; /// same pointer as mAttachedTo, but conveniently casted to player. + + Point3F mPtWorld; /// the worldspace point which we're projecting + Point2I mPtProj; /// the screenspace projected point. - note there are further modifiers before + Point2I mPtScreen; + + Point3F mOffsetObject; /// object-space offset applied first to the attached point to obtain mPtWorld. + Point3F mOffsetWorld; /// world-space offset applied second to the attached point to obtain mPtWorld. + Point2I mOffsetScreen; /// screen-space offset applied to mPtProj. note we still have centering, etc. + + enum alignment + { + min = 0, + center = 1, + max = 2 + }; + + alignment mHAlign; /// horizontal alignment + alignment mVAlign; /// horizontal alignment + + bool mAutoDelete; /// optionally self-delete when mAttachedTo is deleted. + Point2I mUseEyePoint; /// optionally use the eye point. x != 0 -> horiz. y != 0 -> vert. + + + virtual void onRender (Point2I offset, const RectI &updateRect); + virtual void resizeDuringRender (); + + virtual bool onWake (); + virtual void onSleep (); + virtual void onDeleteNotify (SimObject *object); + + void doPositioning (); + void doProjection (); + void doAlignment (); + + void setAttachedTo (SceneObject* obj); + SceneObject* getAttachedTo () { return mAttachedTo; } + void setWorldPt (Point3F& pt) { mPtWorld = pt; } + Point3F getWorldPt () { return mPtWorld; } +}; + +#endif //_GUI3DPROJECTIONCTRL_H_ \ No newline at end of file From 6f418cc1832753669907641ccc1299a71a99aa76 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 16:50:05 -0600 Subject: [PATCH 56/75] Sanity check so calling getFieldValue on a blank fieldName doesn't cause a crash. --- Engine/source/console/simObject.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Engine/source/console/simObject.cpp b/Engine/source/console/simObject.cpp index 447d96ce4..28cbf1007 100644 --- a/Engine/source/console/simObject.cpp +++ b/Engine/source/console/simObject.cpp @@ -2834,6 +2834,9 @@ DefineEngineMethod( SimObject, getFieldValue, const char*, ( const char* fieldNa "@param index Optional parameter to specify the index of an array field separately.\n" "@return The value of the given field or \"\" if undefined." ) { + if (fieldName == "") + return ""; + char fieldNameBuffer[ 1024 ]; char arrayIndexBuffer[ 64 ]; From 282333538a7af8280bced26b1e78b589b16055f5 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 18:11:54 -0600 Subject: [PATCH 57/75] Moves the path return from fileDialog through the returnBuffer so it doesn't get mangled or corrupted in memory inadvertently. --- Engine/source/platform/nativeDialogs/fileDialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/platform/nativeDialogs/fileDialog.cpp b/Engine/source/platform/nativeDialogs/fileDialog.cpp index 21bdfefa3..067458e9f 100644 --- a/Engine/source/platform/nativeDialogs/fileDialog.cpp +++ b/Engine/source/platform/nativeDialogs/fileDialog.cpp @@ -285,9 +285,9 @@ bool FileDialog::Execute() { // Single file selection, do it the easy way if(mForceRelativePath) - mData.mFile = Platform::makeRelativePathName(resultPath.c_str(), NULL); + mData.mFile = Con::getReturnBuffer(Platform::makeRelativePathName(resultPath.c_str(), NULL)); else - mData.mFile = resultPath.c_str(); + mData.mFile = Con::getReturnBuffer(resultPath.c_str()); } else if (mData.mStyle & FileDialogData::FDS_MULTIPLEFILES) { From d18ab265be48a8c09f4fae3c6172cbb04cf8229e Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 20:12:17 -0600 Subject: [PATCH 58/75] Update gui3DProjectionCtrl.cpp Corrected file capitalizations for linux --- Engine/source/gui/controls/gui3DProjectionCtrl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/gui/controls/gui3DProjectionCtrl.cpp b/Engine/source/gui/controls/gui3DProjectionCtrl.cpp index 340cfc186..765b3f1f8 100644 --- a/Engine/source/gui/controls/gui3DProjectionCtrl.cpp +++ b/Engine/source/gui/controls/gui3DProjectionCtrl.cpp @@ -43,9 +43,9 @@ #include "console/console.h" #include "console/consoleTypes.h" -#include "scene/SceneObject.h" +#include "scene/sceneObject.h" #include "T3D/player.h" -#include "gui/controls/Gui3DProjectionCtrl.h" +#include "gui/controls/gui3DProjectionCtrl.h" IMPLEMENT_CONOBJECT(Gui3DProjectionCtrl); From a4fde427b72f28b4bf07e064c8cfa508239fe85c Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 20:14:10 -0600 Subject: [PATCH 59/75] Update simObject.cpp better way to handle the validity check for const char* --- Engine/source/console/simObject.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Engine/source/console/simObject.cpp b/Engine/source/console/simObject.cpp index 28cbf1007..7374919f5 100644 --- a/Engine/source/console/simObject.cpp +++ b/Engine/source/console/simObject.cpp @@ -2834,7 +2834,8 @@ DefineEngineMethod( SimObject, getFieldValue, const char*, ( const char* fieldNa "@param index Optional parameter to specify the index of an array field separately.\n" "@return The value of the given field or \"\" if undefined." ) { - if (fieldName == "") + const U32 nameLen = dStrlen( fieldName ); + if (nameLen == 0) return ""; char fieldNameBuffer[ 1024 ]; From 11fd2989b533759c55a685c986ba94517c1b342e Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 20:28:59 -0600 Subject: [PATCH 60/75] Adds visualizers for various types of colorblindness to help calibrate scene's visual clarity given certain vision impairments. (Also corrects some erroneous pathing in the other render visualizers to match) --- Templates/BaseGame/game/tools/settings.xml | 136 +++++++++--------- .../BaseGame/game/tools/worldEditor/main.cs | 9 ++ .../tools/worldEditor/scripts/lightViz.cs | 78 ++++++++++ .../shaders/dbgColorBlindnessVisualizeP.glsl | 121 ++++++++++++++++ .../shaders/dbgColorBlindnessVisualizeP.hlsl | 118 +++++++++++++++ .../scripts/shaders/dbgColorBufferP.glsl | 2 +- .../scripts/shaders/dbgColorBufferP.hlsl | 2 +- .../scripts/shaders/dbgDepthVisualizeP.glsl | 2 +- .../scripts/shaders/dbgDepthVisualizeP.hlsl | 4 +- .../scripts/shaders/dbgGlowVisualizeP.glsl | 2 +- .../scripts/shaders/dbgGlowVisualizeP.hlsl | 2 +- .../shaders/dbgLightColorVisualizeP.glsl | 2 +- .../shaders/dbgLightColorVisualizeP.hlsl | 4 +- .../shaders/dbgLightSpecularVisualizeP.glsl | 2 +- .../shaders/dbgLightSpecularVisualizeP.hlsl | 2 +- .../scripts/shaders/dbgNormalVisualizeP.glsl | 2 +- .../scripts/shaders/dbgNormalVisualizeP.hlsl | 4 +- .../scripts/shaders/dbgShadowVisualizeP.glsl | 2 +- .../scripts/shaders/dbgShadowVisualizeP.hlsl | 2 +- .../scripts/shaders/dbgSpecMapVisualizeP.glsl | 2 +- .../scripts/shaders/dbgSpecMapVisualizeP.hlsl | 2 +- 21 files changed, 413 insertions(+), 87 deletions(-) create mode 100644 Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBlindnessVisualizeP.glsl create mode 100644 Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBlindnessVisualizeP.hlsl diff --git a/Templates/BaseGame/game/tools/settings.xml b/Templates/BaseGame/game/tools/settings.xml index 761b16978..d01241a25 100644 --- a/Templates/BaseGame/game/tools/settings.xml +++ b/Templates/BaseGame/game/tools/settings.xml @@ -1,80 +1,83 @@ - - 100 - 0 - 0.8 - 1 - 15 - 0.8 - 0 - - 500 - 255 255 255 20 - 0 - 0 - 10 10 10 - 0 - - - screenCenter - 0 - 50 - WorldEditorInspectorPlugin - 40 - 6 1 - - 0 - 0 - 0 - 100 - 2 - 1 - 1 - - - http://www.garagegames.com/products/torque-3d/documentation/user - ../../../Documentation/Official Documentation.html - http://www.garagegames.com/products/torque-3d/forums - ../../../Documentation/Torque 3D - Script Manual.chm - - - 255 255 255 100 - 1 - 102 102 102 100 - 51 51 51 100 - 0 - - - tools/worldEditor/images/LockedHandle - tools/worldEditor/images/DefaultHandle - tools/worldEditor/images/SelectHandle - - - 1 - 1 - 1 - 1 - 1 - + 0 + WorldEditorInspectorPlugin + 6 + screenCenter + 50 + 40 - 0 255 0 255 - 100 100 100 255 - 255 255 255 255 - 255 0 0 255 255 255 0 255 - 0 0 255 255 + 0 255 0 255 + 255 0 0 255 255 255 0 255 + 255 255 255 255 + 0 0 255 255 + 100 100 100 255 8 - 1 - 0 - 255 20 + 255 + 0 + 1 + + 1 + 1 + 1 + 1 + 1 + + + 255 255 255 100 + 102 102 102 100 + 0 + 1 + 51 51 51 100 + + + ../../../Documentation/Official Documentation.html + ../../../Documentation/Torque 3D - Script Manual.chm + http://www.garagegames.com/products/torque-3d/documentation/user + http://www.garagegames.com/products/torque-3d/forums + + + tools/worldEditor/images/LockedHandle + tools/worldEditor/images/SelectHandle + tools/worldEditor/images/DefaultHandle + + + 0 + 2 + 100 + 0 + 1 + 1 + 0 + + + + 1 + 0.8 + 100 + 0.8 + 15 + 0 + 0 + + 0 + 500 + 0 + 10 10 10 + 255 255 255 20 + 0 + + + + AIPlayer data/FPSGameplay/levels @@ -84,7 +87,4 @@ - - AIPlayer - diff --git a/Templates/BaseGame/game/tools/worldEditor/main.cs b/Templates/BaseGame/game/tools/worldEditor/main.cs index 8102438c6..5d337cdf1 100644 --- a/Templates/BaseGame/game/tools/worldEditor/main.cs +++ b/Templates/BaseGame/game/tools/worldEditor/main.cs @@ -133,6 +133,15 @@ function initializeWorldEditor() EVisibility.addOption( "Frustum Lock", "$Scene::lockCull", "" ); EVisibility.addOption( "Disable Zone Culling", "$Scene::disableZoneCulling", "" ); EVisibility.addOption( "Disable Terrain Occlusion", "$Scene::disableTerrainOcclusion", "" ); + + EVisibility.addOption( "Colorblindness: Protanopia", "$CBV_Protanopia", "toggleColorBlindnessViz" ); + EVisibility.addOption( "Colorblindness: Protanomaly", "$CBV_Protanomaly", "toggleColorBlindnessViz" ); + EVisibility.addOption( "Colorblindness: Deuteranopia", "$CBV_Deuteranopia", "toggleColorBlindnessViz" ); + EVisibility.addOption( "Colorblindness: Deuteranomaly", "$CBV_Deuteranomaly", "toggleColorBlindnessViz" ); + EVisibility.addOption( "Colorblindness: Tritanopia", "$CBV_Tritanopia", "toggleColorBlindnessViz" ); + EVisibility.addOption( "Colorblindness: Tritanomaly", "$CBV_Tritanomaly", "toggleColorBlindnessViz" ); + EVisibility.addOption( "Colorblindness: Achromatopsia", "$CBV_Achromatopsia", "toggleColorBlindnessViz" ); + EVisibility.addOption( "Colorblindness: Achromatomaly", "$CBV_Achromatomaly", "toggleColorBlindnessViz" ); } function destroyWorldEditor() diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/lightViz.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/lightViz.cs index 905b826c6..574063460 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/lightViz.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/lightViz.cs @@ -367,3 +367,81 @@ function toggleBackbufferViz( %enable ) else if ( !%enable ) AL_DeferredShading.enable(); } + +function toggleColorBlindnessViz( %enable ) +{ + if ( %enable $= "" ) + { + $CBV_Protanopia = ColorBlindnessVisualize.isEnabled() ? false : true; + ColorBlindnessVisualize.toggle(); + } + else if ( %enable ) + ColorBlindnessVisualize.enable(); + else if ( !%enable ) + ColorBlindnessVisualize.disable(); +} + +new ShaderData( ColorBlindnessVisualizeShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = "tools/worldEditor/scripts/shaders/dbgColorBlindnessVisualizeP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = "tools/worldEditor/scripts/shaders/dbgColorBlindnessVisualizeP.glsl"; + + samplerNames[0] = "$backBuffer"; + + pixVersion = 2.0; +}; + +singleton PostEffect( ColorBlindnessVisualize ) +{ + isEnabled = false; + allowReflectPass = false; + renderTime = "PFXAfterBin"; + renderBin = "GlowBin"; + + shader = ColorBlindnessVisualizeShader; + stateBlock = PFX_DefaultStateBlock; + texture[0] = "$backBuffer"; + target = "$backBuffer"; + renderPriority = 10; +}; + +function ColorBlindnessVisualize::setShaderConsts(%this) +{ + %mode = 0; + + if($CBV_Protanopia) + %mode = 1; + else if($CBV_Protanomaly) + %mode = 2; + else if($CBV_Deuteranopia) + %mode = 3; + else if($CBV_Deuteranomaly) + %mode = 4; + else if($CBV_Tritanopia) + %mode = 5; + else if($CBV_Tritanomaly) + %mode = 6; + else if($CBV_Achromatopsia) + %mode = 7; + else if($CBV_Achromatomaly) + %mode = 8; + + %this.setShaderConst("$mode", %mode); +} + +function ColorBlindnessVisualize::onEnabled( %this ) +{ + AL_NormalsVisualize.disable(); + AL_DepthVisualize.disable(); + AL_LightSpecularVisualize.disable(); + AL_LightColorVisualize.disable(); + $AL_NormalsVisualizeVar = false; + $AL_DepthVisualizeVar = false; + $AL_LightSpecularVisualizeVar = false; + $AL_LightColorVisualizeVar = false; + + return true; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBlindnessVisualizeP.glsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBlindnessVisualizeP.glsl new file mode 100644 index 000000000..6dff4aba4 --- /dev/null +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBlindnessVisualizeP.glsl @@ -0,0 +1,121 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//Using calculations and values provided by Alan Zucconi +// www.alanzucconi.com + +#include "../../../../core/rendering/shaders/gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +in vec2 uv0; +uniform sampler2D backBufferTex; + +in float mode; + +out vec4 OUT_col; + +void main() +{ + vec4 imageColor = texture( backBufferTex, uv0 ); + + if(mode == 0) + { + OUT_col = imageColor; + } + else + { + vec3 R = imageColor.r; + vec3 G = imageColor.g; + vec3 B = imageColor.b; + + if(mode == 1) // Protanopia + { + R = vec3(0.56667, 0.43333, 0); + G = vec3(0.55833, 0.44167, 0); + B = vec3(0, 0.24167, 0.75833); + } + else if(mode == 2) // Protanomaly + { + R = vec3(0.81667, 0.18333, 0); + G = vec3(0.33333, 0.66667, 0); + B = vec3(0, 0.125, 0.875); + } + else if(mode == 3) // Deuteranopia + { + R = vec3(0.625, 0.375, 0); + G = vec3(0.70, 0.30, 0); + B = vec3(0, 0.30, 0.70); + } + else if(mode == 4) // Deuteranomaly + { + R = vec3(0.80, 0.20, 0); + G = vec3(0.25833, 0.74167, 0); + B = vec3(0, 0.14167, 0.85833); + } + else if(mode == 5) // Tritanopia + { + R = vec3(0.95, 0.05, 0); + G = vec3(0, 0.43333, 0.56667); + B = vec3(0, 0.475, 0.525); + } + else if(mode == 6) // Tritanomaly + { + R = vec3(0.96667, 0.03333, 0); + G = vec3(0, 0.73333, 0.26667); + B = vec3(0, 0.18333, 0.81667); + } + else if(mode == 7) // Achromatopsia + { + R = vec3(0.299, 0.587, 0.114); + G = vec3(0.299, 0.587, 0.114); + B = vec3(0.299, 0.587, 0.114); + } + else if(mode == 8) // Achromatomaly + { + R = vec3(0.618, 0.32, 0.062); + G = vec3(0.163, 0.775, 0.062); + B = vec3(0.163, 0.320, 0.516); + } + + //First set + vec4 c = imageColor; + + c.r = c.r * R[0] + c.g * R[1] + c.b * R[2]; + c.g = c.r * G[0] + c.g * G[1] + c.b * G[2]; + c.b = c.r * B[0] + c.g * B[1] + c.b * B[2]; + + vec3 cb = c.rgb; + + cb.r = c.r * R[0] + c.g * R[1] + c.b * R[2]; + cb.g = c.r * G[0] + c.g * G[1] + c.b * G[2]; + cb.b = c.r * B[0] + c.g * B[1] + c.b * B[2]; + + // Difference + vec3 diff = abs(c.rgb - cb); + + float lum = c.r*.3 + c.g*.59 + c.b*.11; + vec3 bw = vec3(lum, lum, lum); + + // return vec4(lerp(bw, vec3(1, 0, 0), saturate((diff.r + diff.g + diff.b) / 3)), c.a); + OUT_col = vec4(c.rgb,1); + } +} diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBlindnessVisualizeP.hlsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBlindnessVisualizeP.hlsl new file mode 100644 index 000000000..fcb4ff41c --- /dev/null +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBlindnessVisualizeP.hlsl @@ -0,0 +1,118 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//Using calculations and values provided by Alan Zucconi +// www.alanzucconi.com + +#include "../../../../core/rendering/shaders/shaderModelAutoGen.hlsl" +#include "../../../../core/rendering/shaders/postFX/postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(backBufferTex,0); + +uniform float mode; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float4 imageColor = TORQUE_TEX2D( backBufferTex, IN.uv0 ); + + if(mode == 0) + { + return imageColor; + } + else + { + float3 R = imageColor.r; + float3 G = imageColor.g; + float3 B = imageColor.b; + + if(mode == 1) // Protanopia + { + R = float3(0.56667, 0.43333, 0); + G = float3(0.55833, 0.44167, 0); + B = float3(0, 0.24167, 0.75833); + } + else if(mode == 2) // Protanomaly + { + R = float3(0.81667, 0.18333, 0); + G = float3(0.33333, 0.66667, 0); + B = float3(0, 0.125, 0.875); + } + else if(mode == 3) // Deuteranopia + { + R = float3(0.625, 0.375, 0); + G = float3(0.70, 0.30, 0); + B = float3(0, 0.30, 0.70); + } + else if(mode == 4) // Deuteranomaly + { + R = float3(0.80, 0.20, 0); + G = float3(0.25833, 0.74167, 0); + B = float3(0, 0.14167, 0.85833); + } + else if(mode == 5) // Tritanopia + { + R = float3(0.95, 0.05, 0); + G = float3(0, 0.43333, 0.56667); + B = float3(0, 0.475, 0.525); + } + else if(mode == 6) // Tritanomaly + { + R = float3(0.96667, 0.03333, 0); + G = float3(0, 0.73333, 0.26667); + B = float3(0, 0.18333, 0.81667); + } + else if(mode == 7) // Achromatopsia + { + R = float3(0.299, 0.587, 0.114); + G = float3(0.299, 0.587, 0.114); + B = float3(0.299, 0.587, 0.114); + } + else if(mode == 8) // Achromatomaly + { + R = float3(0.618, 0.32, 0.062); + G = float3(0.163, 0.775, 0.062); + B = float3(0.163, 0.320, 0.516); + } + + //First set + float4 c = imageColor; + + c.r = c.r * R[0] + c.g * R[1] + c.b * R[2]; + c.g = c.r * G[0] + c.g * G[1] + c.b * G[2]; + c.b = c.r * B[0] + c.g * B[1] + c.b * B[2]; + + float3 cb = c.rgb; + + cb.r = c.r * R[0] + c.g * R[1] + c.b * R[2]; + cb.g = c.r * G[0] + c.g * G[1] + c.b * G[2]; + cb.b = c.r * B[0] + c.g * B[1] + c.b * B[2]; + + // Difference + float3 diff = abs(c.rgb - cb); + + float lum = c.r*.3 + c.g*.59 + c.b*.11; + float3 bw = float3(lum, lum, lum); + + // return float4(lerp(bw, float3(1, 0, 0), saturate((diff.r + diff.g + diff.b) / 3)), c.a); + return float4(c.rgb,1); + } +} diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBufferP.glsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBufferP.glsl index 0b7e370bf..01b2d737b 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBufferP.glsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBufferP.glsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/gl/hlslCompat.glsl" +#include "../../../../core/rendering/shaders/gl/hlslCompat.glsl" in vec2 uv0; uniform sampler2D colorBufferTex; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBufferP.hlsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBufferP.hlsl index e996f840a..e7bf0e5e9 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBufferP.hlsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgColorBufferP.hlsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/postfx/postFx.hlsl" +#include "../../../../core/rendering/shaders/postFX/postFx.hlsl" TORQUE_UNIFORM_SAMPLER2D(colorBufferTex,0); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgDepthVisualizeP.glsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgDepthVisualizeP.glsl index 8ada46462..8e034a55f 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgDepthVisualizeP.glsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgDepthVisualizeP.glsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/gl/hlslCompat.glsl" +#include "../../../../core/rendering/shaders/gl/hlslCompat.glsl" #include "shadergen:/autogenConditioners.h" in vec2 uv0; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgDepthVisualizeP.hlsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgDepthVisualizeP.hlsl index 83547571a..26147b5be 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgDepthVisualizeP.hlsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgDepthVisualizeP.hlsl @@ -20,8 +20,8 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/postfx/postFx.hlsl" -#include "core/shaders/shaderModelAutoGen.hlsl" +#include "../../../../core/rendering/shaders/postFX/postFx.hlsl" +#include "../../../../core/rendering/shaders/shaderModelAutoGen.hlsl" TORQUE_UNIFORM_SAMPLER2D(deferredTex, 0); TORQUE_UNIFORM_SAMPLER1D(depthViz, 1); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgGlowVisualizeP.glsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgGlowVisualizeP.glsl index cdc58d7c6..85afcf4c8 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgGlowVisualizeP.glsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgGlowVisualizeP.glsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/gl/hlslCompat.glsl" +#include "../../../../core/rendering/shaders/gl/hlslCompat.glsl" in vec2 uv0; uniform sampler2D glowBuffer; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgGlowVisualizeP.hlsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgGlowVisualizeP.hlsl index b78d29d67..d4b3028f8 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgGlowVisualizeP.hlsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgGlowVisualizeP.hlsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/postfx/postFx.hlsl" +#include "../../../../core/rendering/shaders/postFX/postFx.hlsl" TORQUE_UNIFORM_SAMPLER2D(glowBuffer, 0); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightColorVisualizeP.glsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightColorVisualizeP.glsl index 86fb67268..d354adc0d 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightColorVisualizeP.glsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightColorVisualizeP.glsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/gl/hlslCompat.glsl" +#include "../../../../core/rendering/shaders/gl/hlslCompat.glsl" in vec2 uv0; uniform sampler2D lightDeferredTex; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightColorVisualizeP.hlsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightColorVisualizeP.hlsl index 38e5832f5..f178e66c0 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightColorVisualizeP.hlsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightColorVisualizeP.hlsl @@ -20,8 +20,8 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/shaderModelAutoGen.hlsl" -#include "core/shaders/postfx/postFx.hlsl" +#include "../../../../core/rendering/shaders/shaderModelAutoGen.hlsl" +#include "../../../../core/rendering/shaders/postFX/postFx.hlsl" TORQUE_UNIFORM_SAMPLER2D(lightDeferredTex,0); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightSpecularVisualizeP.glsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightSpecularVisualizeP.glsl index e8a037d2b..51fe2f8eb 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightSpecularVisualizeP.glsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightSpecularVisualizeP.glsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/gl/hlslCompat.glsl" +#include "../../../../core/rendering/shaders/gl/hlslCompat.glsl" in vec2 uv0; uniform sampler2D lightDeferredTex; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightSpecularVisualizeP.hlsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightSpecularVisualizeP.hlsl index 66424a11f..7c45e4115 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightSpecularVisualizeP.hlsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgLightSpecularVisualizeP.hlsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/postfx/postFx.hlsl" +#include "../../../../core/rendering/shaders/postFX/postFx.hlsl" TORQUE_UNIFORM_SAMPLER2D(lightDeferredTex,0); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgNormalVisualizeP.glsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgNormalVisualizeP.glsl index ab3323360..274dc0369 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgNormalVisualizeP.glsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgNormalVisualizeP.glsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/gl/hlslCompat.glsl" +#include "../../../../core/rendering/shaders/gl/hlslCompat.glsl" #include "shadergen:/autogenConditioners.h" in vec2 uv0; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgNormalVisualizeP.hlsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgNormalVisualizeP.hlsl index 913745bb5..2d813a0eb 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgNormalVisualizeP.hlsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgNormalVisualizeP.hlsl @@ -20,8 +20,8 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/postfx/postFx.hlsl" -#include "core/shaders/shaderModelAutoGen.hlsl" +#include "../../../../core/rendering/shaders/postFX/postFx.hlsl" +#include "../../../../core/rendering/shaders/shaderModelAutoGen.hlsl" TORQUE_UNIFORM_SAMPLER2D(deferredTex, 0); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgShadowVisualizeP.glsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgShadowVisualizeP.glsl index f73f7812d..3f6f775b6 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgShadowVisualizeP.glsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgShadowVisualizeP.glsl @@ -19,7 +19,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/gl/hlslCompat.glsl" +#include "../../../../core/rendering/shaders/gl/hlslCompat.glsl" in vec2 uv0; uniform sampler2D shadowMap; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgShadowVisualizeP.hlsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgShadowVisualizeP.hlsl index 3c56c2abd..a4978a49f 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgShadowVisualizeP.hlsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgShadowVisualizeP.hlsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/shaderModel.hlsl" +#include "../../../../core/rendering/shaders/shaderModel.hlsl" struct MaterialDecoratorConnectV { diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgSpecMapVisualizeP.glsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgSpecMapVisualizeP.glsl index d391a1963..6342ed973 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgSpecMapVisualizeP.glsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgSpecMapVisualizeP.glsl @@ -19,7 +19,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/gl/hlslCompat.glsl" +#include "../../../../core/rendering/shaders/gl/hlslCompat.glsl" in vec2 uv0; uniform sampler2D matinfoTex; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgSpecMapVisualizeP.hlsl b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgSpecMapVisualizeP.hlsl index 59252cd7b..6dd32a480 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgSpecMapVisualizeP.hlsl +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/shaders/dbgSpecMapVisualizeP.hlsl @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "core/shaders/postfx/postFx.hlsl" +#include "../../../../core/rendering/shaders/postFX/postFx.hlsl" TORQUE_UNIFORM_SAMPLER2D(matinfoTex,0); From 892077973b5c0bb74eaa51d9f4f67d9d0b553c2a Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 21:34:11 -0600 Subject: [PATCH 61/75] Adds ability to skip loading of cached dts in enumColladaForImport --- Engine/source/ts/collada/colladaImport.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Engine/source/ts/collada/colladaImport.cpp b/Engine/source/ts/collada/colladaImport.cpp index cab5311ff..8206bb0a5 100644 --- a/Engine/source/ts/collada/colladaImport.cpp +++ b/Engine/source/ts/collada/colladaImport.cpp @@ -126,13 +126,14 @@ static void processNode(GuiTreeViewCtrl* tree, domNode* node, S32 parentID, Scen } } -DefineEngineFunction( enumColladaForImport, bool, (const char * shapePath, const char * ctrl), , +DefineEngineFunction( enumColladaForImport, bool, (const char * shapePath, const char * ctrl, bool loadCachedDts), ("", "", true), "(string shapePath, GuiTreeViewCtrl ctrl) Collect scene information from " "a COLLADA file and store it in a GuiTreeView control. This function is " "used by the COLLADA import gui to show a preview of the scene contents " "prior to import, and is probably not much use for anything else.\n" "@param shapePath COLLADA filename\n" "@param ctrl GuiTreeView control to add elements to\n" + "@param loadCachedDts dictates if it should try and load the cached dts file if it exists" "@return true if successful, false otherwise\n" "@ingroup Editors\n" "@internal") @@ -147,7 +148,7 @@ DefineEngineFunction( enumColladaForImport, bool, (const char * shapePath, const // Check if a cached DTS is available => no need to import the collada file // if we can load the DTS instead Torque::Path path(shapePath); - if (ColladaShapeLoader::canLoadCachedDTS(path)) + if (loadCachedDts && ColladaShapeLoader::canLoadCachedDTS(path)) return false; // Check if this is a Sketchup file (.kmz) and if so, mount the zip filesystem From cf21bf7dfd91ab445655e8d65af91b43eb17da85 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 23 Feb 2019 21:41:22 -0600 Subject: [PATCH 62/75] Update simObject.cpp Accidental redefine --- Engine/source/console/simObject.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Engine/source/console/simObject.cpp b/Engine/source/console/simObject.cpp index 7374919f5..6cf6fd029 100644 --- a/Engine/source/console/simObject.cpp +++ b/Engine/source/console/simObject.cpp @@ -2844,7 +2844,6 @@ DefineEngineMethod( SimObject, getFieldValue, const char*, ( const char* fieldNa // Parse out index if the field is given in the form of 'name[index]'. const char* arrayIndex = NULL; - const U32 nameLen = dStrlen( fieldName ); if( fieldName[ nameLen - 1 ] == ']' ) { const char* leftBracket = dStrchr( fieldName, '[' ); From 461e2b65342a268da02e445408a38eff252eb678 Mon Sep 17 00:00:00 2001 From: Marc Chapman Date: Tue, 26 Feb 2019 14:42:09 +0000 Subject: [PATCH 63/75] Set contrsaints for Player Z rotation --- Engine/source/T3D/player.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Engine/source/T3D/player.cpp b/Engine/source/T3D/player.cpp index 9a2c072a6..ced012299 100644 --- a/Engine/source/T3D/player.cpp +++ b/Engine/source/T3D/player.cpp @@ -6345,6 +6345,14 @@ U32 Player::packUpdate(NetConnection *con, U32 mask, BitStream *stream) if(len > 8191) len = 8191; stream->writeInt((S32)len, 13); + + // constrain the range of mRot.z + while (mRot.z < 0.0f) + mRot.z += M_2PI_F; + while (mRot.z > M_2PI_F) + mRot.z -= M_2PI_F; + + } stream->writeFloat(mRot.z / M_2PI_F, 7); stream->writeSignedFloat(mHead.x / (mDataBlock->maxLookAngle - mDataBlock->minLookAngle), 6); From 9820780d1cce2b8e3ce57d229fdfc564ed2671f7 Mon Sep 17 00:00:00 2001 From: Marc Chapman Date: Tue, 26 Feb 2019 14:47:02 +0000 Subject: [PATCH 64/75] Fixes a crash that occurs on linux headless servers --- Engine/source/windowManager/sdl/sdlWindowMgr.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Engine/source/windowManager/sdl/sdlWindowMgr.cpp b/Engine/source/windowManager/sdl/sdlWindowMgr.cpp index dd3f13825..5be1ae53d 100644 --- a/Engine/source/windowManager/sdl/sdlWindowMgr.cpp +++ b/Engine/source/windowManager/sdl/sdlWindowMgr.cpp @@ -504,10 +504,12 @@ void InitWindowingSystem() AFTER_MODULE_INIT(gfx) { +#if !defined(TORQUE_DEDICATED) int res = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE); AssertFatal(res != -1, avar("SDL error:%s", SDL_GetError())); // By default, SDL enables text input. We disable it on initialization, and // we will enable it whenever the time is right. SDL_StopTextInput(); +#endif } From f04d4c03d9afa41d9670fcfd58e7e50e9fed12d6 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 4 Mar 2019 22:07:55 -0600 Subject: [PATCH 65/75] Cleanup and minor tweaks to the core dir structure. --- Templates/BaseGame/game/core/Core.cs | 60 +-- Templates/BaseGame/game/core/Core.module | 13 +- .../scripts/client/connectionToServer.cs | 2 +- .../actionAnimationComponent.asset.taml | 8 + .../aiControllerComponent.asset.taml | 8 + .../armAnimationComponent.asset.taml | 8 + .../components/game/controlObject.cs | 89 --- .../game/core/utility/Core_Utility.cs | 2 + .../utility/scripts/gameObjectManagement.cs | 181 +++++++ .../game/core/utility/scripts/globals.cs | 3 - .../core/utility/scripts/helperFunctions.cs | 510 +----------------- .../utility/scripts/persistanceManagement.cs | 315 +++++++++++ 12 files changed, 539 insertions(+), 660 deletions(-) create mode 100644 Templates/BaseGame/game/core/components/components/actionAnimationComponent.asset.taml create mode 100644 Templates/BaseGame/game/core/components/components/aiControllerComponent.asset.taml create mode 100644 Templates/BaseGame/game/core/components/components/armAnimationComponent.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/components/game/controlObject.cs create mode 100644 Templates/BaseGame/game/core/utility/scripts/gameObjectManagement.cs create mode 100644 Templates/BaseGame/game/core/utility/scripts/persistanceManagement.cs diff --git a/Templates/BaseGame/game/core/Core.cs b/Templates/BaseGame/game/core/Core.cs index 5559760ae..99efdd706 100644 --- a/Templates/BaseGame/game/core/Core.cs +++ b/Templates/BaseGame/game/core/Core.cs @@ -20,10 +20,11 @@ function CoreModule::onCreate(%this) ModuleDatabase.LoadExplicit( "Core_Rendering" ); ModuleDatabase.LoadExplicit( "Core_Utility" ); ModuleDatabase.LoadExplicit( "Core_GUI" ); - ModuleDatabase.LoadExplicit( "CoreModule" ); ModuleDatabase.LoadExplicit( "Core_Lighting" ); ModuleDatabase.LoadExplicit( "Core_SFX" ); ModuleDatabase.LoadExplicit( "Core_PostFX" ); + ModuleDatabase.LoadExplicit( "Core_Components" ); + ModuleDatabase.LoadExplicit( "Core_GameObjects" ); ModuleDatabase.LoadExplicit( "Core_ClientServer" ); %prefPath = getPrefpath(); @@ -32,63 +33,6 @@ function CoreModule::onCreate(%this) else exec("data/defaults.cs"); - %der = $pref::Video::displayDevice; - - //We need to hook the missing/warn material stuff early, so do it here - /*$Core::MissingTexturePath = "core/images/missingTexture"; - $Core::UnAvailableTexturePath = "core/images/unavailable"; - $Core::WarningTexturePath = "core/images/warnMat"; - $Core::CommonShaderPath = "core/shaders"; - - /*%classList = enumerateConsoleClasses( "Component" ); - - foreach$( %componentClass in %classList ) - { - echo("Native Component of type: " @ %componentClass); - }*/ - - //exec("./helperFunctions.cs"); - - // We need some of the default GUI profiles in order to get the canvas and - // other aspects of the GUI system ready. - //exec("./profiles.cs"); - - //This is a bit of a shortcut, but we'll load the client's default settings to ensure all the prefs get initialized correctly - - - // Initialization of the various subsystems requires some of the preferences - // to be loaded... so do that first. - /*exec("./globals.cs"); - - exec("./canvas.cs"); - exec("./cursor.cs"); - - exec("./renderManager.cs"); - exec("./lighting.cs"); - - exec("./audio.cs"); - exec("./sfx/audioAmbience.cs"); - exec("./sfx/audioData.cs"); - exec("./sfx/audioDescriptions.cs"); - exec("./sfx/audioEnvironments.cs"); - exec("./sfx/audioStates.cs"); - - exec("./parseArgs.cs"); - - // Materials and Shaders for rendering various object types - exec("./gfxData/commonMaterialData.cs"); - exec("./gfxData/shaders.cs"); - exec("./gfxData/terrainBlock.cs"); - exec("./gfxData/water.cs"); - exec("./gfxData/scatterSky.cs"); - exec("./gfxData/clouds.cs"); - - // Initialize all core post effects. - exec("./postFx.cs"); - - //VR stuff - exec("./oculusVR.cs");*/ - // Seed the random number generator. setRandomSeed(); diff --git a/Templates/BaseGame/game/core/Core.module b/Templates/BaseGame/game/core/Core.module index c7ab7b64b..b9a2490e3 100644 --- a/Templates/BaseGame/game/core/Core.module +++ b/Templates/BaseGame/game/core/Core.module @@ -5,15 +5,4 @@ ScriptFile="Core.cs" CreateFunction="onCreate" DestroyFunction="onDestroy" - Group="Core"> - - - \ No newline at end of file + Group="Core"/> \ No newline at end of file diff --git a/Templates/BaseGame/game/core/clientServer/scripts/client/connectionToServer.cs b/Templates/BaseGame/game/core/clientServer/scripts/client/connectionToServer.cs index 693c7fff7..11df6afd6 100644 --- a/Templates/BaseGame/game/core/clientServer/scripts/client/connectionToServer.cs +++ b/Templates/BaseGame/game/core/clientServer/scripts/client/connectionToServer.cs @@ -43,7 +43,7 @@ function GameConnection::initialControlSet(%this) // first check if the editor is active if (!isToolBuild() || !isMethod("Editor", "checkActiveLoadDone") || !Editor::checkActiveLoadDone()) { - if (Canvas.getContent() != PlayGui.getId()) + if (isObject(PlayGui) && Canvas.getContent() != PlayGui.getId()) Canvas.setContent(PlayGui); } } diff --git a/Templates/BaseGame/game/core/components/components/actionAnimationComponent.asset.taml b/Templates/BaseGame/game/core/components/components/actionAnimationComponent.asset.taml new file mode 100644 index 000000000..36d5b9a90 --- /dev/null +++ b/Templates/BaseGame/game/core/components/components/actionAnimationComponent.asset.taml @@ -0,0 +1,8 @@ + diff --git a/Templates/BaseGame/game/core/components/components/aiControllerComponent.asset.taml b/Templates/BaseGame/game/core/components/components/aiControllerComponent.asset.taml new file mode 100644 index 000000000..0111cd999 --- /dev/null +++ b/Templates/BaseGame/game/core/components/components/aiControllerComponent.asset.taml @@ -0,0 +1,8 @@ + diff --git a/Templates/BaseGame/game/core/components/components/armAnimationComponent.asset.taml b/Templates/BaseGame/game/core/components/components/armAnimationComponent.asset.taml new file mode 100644 index 000000000..d9fd4ef80 --- /dev/null +++ b/Templates/BaseGame/game/core/components/components/armAnimationComponent.asset.taml @@ -0,0 +1,8 @@ + diff --git a/Templates/BaseGame/game/core/components/components/game/controlObject.cs b/Templates/BaseGame/game/core/components/components/game/controlObject.cs deleted file mode 100644 index 7f477ecca..000000000 --- a/Templates/BaseGame/game/core/components/components/game/controlObject.cs +++ /dev/null @@ -1,89 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -//registerComponent("ControlObjectComponent", "Component", "Control Object", "Game", false, "Allows the behavior owner to operate as a camera."); - -function ControlObjectComponent::onAdd(%this) -{ - %this.addComponentField(clientOwner, "The shape to use for rendering", "int", "1", ""); - - %clientID = %this.getClientID(); - - if(%clientID && !isObject(%clientID.getControlObject())) - %clientID.setControlObject(%this.owner); -} - -function ControlObjectComponent::onRemove(%this) -{ - %clientID = %this.getClientID(); - - if(%clientID) - %clientID.setControlObject(0); -} - -function ControlObjectComponent::onClientConnect(%this, %client) -{ - if(%this.isControlClient(%client) && !isObject(%client.getControlObject())) - %client.setControlObject(%this.owner); -} - -function ControlObjectComponent::onClientDisconnect(%this, %client) -{ - if(%this.isControlClient(%client)) - %client.setControlObject(0); -} - -function ControlObjectComponent::getClientID(%this) -{ - return ClientGroup.getObject(%this.clientOwner-1); -} - -function ControlObjectComponent::isControlClient(%this, %client) -{ - %clientID = ClientGroup.getObject(%this.clientOwner-1); - - if(%client.getID() == %clientID) - return true; - else - return false; -} - -function ControlObjectComponent::onInspectorUpdate(%this, %field) -{ - %clientID = %this.getClientID(); - - if(%clientID && !isObject(%clientID.getControlObject())) - %clientID.setControlObject(%this.owner); -} - -function switchControlObject(%client, %newControlEntity) -{ - if(!isObject(%client) || !isObject(%newControlEntity)) - return error("SwitchControlObject: No client or target controller!"); - - %control = %newControlEntity.getComponent(ControlObjectComponent); - - if(!isObject(%control)) - return error("SwitchControlObject: Target controller has no conrol object behavior!"); - - %client.setControlObject(%newControlEntity); -} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/utility/Core_Utility.cs b/Templates/BaseGame/game/core/utility/Core_Utility.cs index d412f3544..e38d474d5 100644 --- a/Templates/BaseGame/game/core/utility/Core_Utility.cs +++ b/Templates/BaseGame/game/core/utility/Core_Utility.cs @@ -4,6 +4,8 @@ function Core_Utility::onCreate(%this) exec("./scripts/parseArgs.cs"); exec("./scripts/globals.cs"); exec("./scripts/helperFunctions.cs"); + exec("./scripts/gameObjectManagement.cs"); + exec("./scripts/persistanceManagement.cs"); } function Core_Utility::onDestroy(%this) diff --git a/Templates/BaseGame/game/core/utility/scripts/gameObjectManagement.cs b/Templates/BaseGame/game/core/utility/scripts/gameObjectManagement.cs new file mode 100644 index 000000000..f496111eb --- /dev/null +++ b/Templates/BaseGame/game/core/utility/scripts/gameObjectManagement.cs @@ -0,0 +1,181 @@ + +//Game Object management +function findGameObject(%name) +{ + //find all GameObjectAssets + %assetQuery = new AssetQuery(); + if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset")) + return 0; //if we didn't find ANY, just exit + + %count = %assetQuery.getCount(); + + for(%i=0; %i < %count; %i++) + { + %assetId = %assetQuery.getAsset(%i); + + //%assetName = AssetDatabase.getAssetName(%assetId); + + if(%assetId $= %name) + { + %gameObjectAsset = AssetDatabase.acquireAsset(%assetId); + + %assetQuery.delete(); + return %gameObjectAsset; + } + } + + %assetQuery.delete(); + return 0; +} + +function spawnGameObject(%name, %addToScene) +{ + if(%addToScene $= "") + %addToScene = true; + + //First, check if this already exists in our GameObjectPool + if(isObject(GameObjectPool)) + { + %goCount = GameObjectPool.countKey(%name); + + //if we have some already in the pool, pull it out and use that + if(%goCount != 0) + { + %goIdx = GameObjectPool.getIndexFromKey(%name); + %go = GameObjectPool.getValue(%goIdx); + + %go.setHidden(false); + %go.setScopeAlways(); + + if(%addToMissionGroup == true) //save instance when saving level + getScene(0).add(%go); + else // clear instance on level exit + MissionCleanup.add(%go); + + //remove from the object pool's list + GameObjectPool.erase(%goIdx); + + return %go; + } + } + + //We have no existing pool, or no existing game objects of this type, so spawn a new one + + %gameObjectAsset = findGameObject(%name); + + if(isObject(%gameObjectAsset)) + { + %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath); + + if(%addToScene == true) //save instance when saving level + getScene(0).add(%newSGOObject); + else // clear instance on level exit + MissionCleanup.add(%newSGOObject); + + return %newSGOObject; + } + + return 0; +} + +function saveGameObject(%name, %tamlPath, %scriptPath) +{ + %gameObjectAsset = findGameObject(%name); + + //find if it already exists. If it does, we'll update it, if it does not, we'll make a new asset + if(isObject(%gameObjectAsset)) + { + %assetID = %gameObjectAsset.getAssetId(); + + %gameObjectAsset.TAMLFilePath = %tamlPath; + %gameObjectAsset.scriptFilePath = %scriptPath; + + TAMLWrite(%gameObjectAsset, AssetDatabase.getAssetFilePath(%assetID)); + AssetDatabase.refreshAsset(%assetID); + } + else + { + //Doesn't exist, so make a new one + %gameObjectAsset = new GameObjectAsset() + { + assetName = %name @ "Asset"; + gameObjectName = %name; + TAMLFilePath = %tamlPath; + scriptFilePath = %scriptPath; + }; + + //Save it alongside the taml file + %path = filePath(%tamlPath); + + TAMLWrite(%gameObjectAsset, %path @ "/" @ %name @ ".asset.taml"); + AssetDatabase.refreshAllAssets(true); + } +} + +//Allocates a number of a game object into a pool to be pulled from as needed +function allocateGameObjects(%name, %amount) +{ + //First, we need to make sure our pool exists + if(!isObject(GameObjectPool)) + { + new ArrayObject(GameObjectPool); + } + + //Next, we loop and generate our game objects, and add them to the pool + for(%i=0; %i < %amount; %i++) + { + %go = spawnGameObject(%name, false); + + //When our object is in the pool, it's not "real", so we need to make sure + //that we don't ghost it to clients untill we actually spawn it. + %go.clearScopeAlways(); + + //We also hide it, so that we don't 'exist' in the scene until we spawn + %go.hidden = true; + + //Lastly, add us to the pool, with the key being our game object type + GameObjectPool.add(%name, %go); + } +} + +function Entity::delete(%this) +{ + //we want to intercept the delete call, and add it to our GameObjectPool + //if it's a game object + if(%this.gameObjectAsset !$= "") + { + %this.setHidden(true); + %this.clearScopeAlways(); + + if(!isObject(GameObjectPool)) + { + new ArrayObject(GameObjectPool); + } + + GameObjectPool.add(%this.gameObjectAsset, %this); + + %missionSet = %this.getGroup(); + %missionSet.remove(%this); + } + else + { + %this.superClass.delete(); + } +} + +function clearGameObjectPool() +{ + if(isObject(GameObjectPool)) + { + %count = GameObjectPool.count(); + + for(%i=0; %i < %count; %i++) + { + %go = GameObjectPool.getValue(%i); + + %go.superClass.delete(); + } + + GameObjectPool.empty(); + } +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/utility/scripts/globals.cs b/Templates/BaseGame/game/core/utility/scripts/globals.cs index fcf52390a..adb035fdc 100644 --- a/Templates/BaseGame/game/core/utility/scripts/globals.cs +++ b/Templates/BaseGame/game/core/utility/scripts/globals.cs @@ -36,9 +36,6 @@ $pref::Input::JoystickEnabled = 0; // Set directory paths for various data or default images. $pref::Video::ProfilePath = "core/rendering/scripts/gfxprofile"; -/*$pref::Video::missingTexturePath = "core/images/missingTexture.png"; -$pref::Video::unavailableTexturePath = "core/images/unavailable.png"; -$pref::Video::warningTexturePath = "core/images/warnMat.dds";*/ $pref::Video::disableVerticalSync = 1; $pref::Video::mode = "800 600 false 32 60 4"; diff --git a/Templates/BaseGame/game/core/utility/scripts/helperFunctions.cs b/Templates/BaseGame/game/core/utility/scripts/helperFunctions.cs index 8abe3e6e6..d620d08b1 100644 --- a/Templates/BaseGame/game/core/utility/scripts/helperFunctions.cs +++ b/Templates/BaseGame/game/core/utility/scripts/helperFunctions.cs @@ -636,503 +636,6 @@ function mvReset() // There are others. } -//Persistance Manager tests - -new PersistenceManager(TestPManager); - -function runPManTest(%test) -{ - if (!isObject(TestPManager)) - return; - - if (%test $= "") - %test = 100; - - switch(%test) - { - case 0: - TestPManager.testFieldUpdates(); - case 1: - TestPManager.testObjectRename(); - case 2: - TestPManager.testNewObject(); - case 3: - TestPManager.testNewGroup(); - case 4: - TestPManager.testMoveObject(); - case 5: - TestPManager.testObjectRemove(); - case 100: - TestPManager.testFieldUpdates(); - TestPManager.testObjectRename(); - TestPManager.testNewObject(); - TestPManager.testNewGroup(); - TestPManager.testMoveObject(); - TestPManager.testObjectRemove(); - } -} - -function TestPManager::testFieldUpdates(%doNotSave) -{ - // Set some objects as dirty - TestPManager.setDirty(AudioGui); - TestPManager.setDirty(AudioSim); - TestPManager.setDirty(AudioMessage); - - // Alter some of the existing fields - AudioEffect.isLooping = true; - AudioMessage.isLooping = true; - AudioEffect.is3D = true; - - // Test removing a field - TestPManager.removeField(AudioGui, "isLooping"); - - // Alter some of the persistent fields - AudioGui.referenceDistance = 0.8; - AudioMessage.referenceDistance = 0.8; - - // Add some new dynamic fields - AudioGui.foo = "bar"; - AudioEffect.foo = "bar"; - - // Remove an object from the dirty list - // It shouldn't get updated in the file - TestPManager.removeDirty(AudioEffect); - - // Dirty an object in another file as well - TestPManager.setDirty(WarningMaterial); - - // Update a field that doesn't exist - WarningMaterial.glow[0] = true; - - // Drity another object to test for crashes - // when a dirty object is deleted - TestPManager.setDirty(SFXPausedSet); - - // Delete the object - SFXPausedSet.delete(); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); -} - -function TestPManager::testObjectRename(%doNotSave) -{ - // Flag an object as dirty - if (isObject(AudioGui)) - TestPManager.setDirty(AudioGui); - else if (isObject(AudioGuiFoo)) - TestPManager.setDirty(AudioGuiFoo); - - // Rename it - if (isObject(AudioGui)) - AudioGui.setName(AudioGuiFoo); - else if (isObject(AudioGuiFoo)) - AudioGuiFoo.setName(AudioGui); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); -} - -function TestPManager::testNewObject(%doNotSave) -{ - // Test adding a new named object - new SFXDescription(AudioNew) - { - volume = 0.5; - isLooping = true; - channel = $GuiAudioType; - foo = 2; - }; - - // Flag it as dirty - TestPManager.setDirty(AudioNew, "core/scripts/client/audio.cs"); - - // Test adding a new unnamed object - %obj = new SFXDescription() - { - volume = 0.75; - isLooping = true; - bar = 3; - }; - - // Flag it as dirty - TestPManager.setDirty(%obj, "core/scripts/client/audio.cs"); - - // Test adding an "empty" object - new SFXDescription(AudioEmpty); - - TestPManager.setDirty(AudioEmpty, "core/scripts/client/audio.cs"); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); -} - -function TestPManager::testNewGroup(%doNotSave) -{ - // Test adding a new named SimGroup - new SimGroup(TestGroup) - { - foo = "bar"; - - new SFXDescription(TestObject) - { - volume = 0.5; - isLooping = true; - channel = $GuiAudioType; - foo = 1; - }; - new SimGroup(SubGroup) - { - foo = 2; - - new SFXDescription(SubObject) - { - volume = 0.5; - isLooping = true; - channel = $GuiAudioType; - foo = 3; - }; - }; - }; - - // Flag this as dirty - TestPManager.setDirty(TestGroup, "core/scripts/client/audio.cs"); - - // Test adding a new unnamed SimGroup - %group = new SimGroup() - { - foo = "bar"; - - new SFXDescription() - { - volume = 0.75; - channel = $GuiAudioType; - foo = 4; - }; - new SimGroup() - { - foo = 5; - - new SFXDescription() - { - volume = 0.75; - isLooping = true; - channel = $GuiAudioType; - foo = 6; - }; - }; - }; - - // Flag this as dirty - TestPManager.setDirty(%group, "core/scripts/client/audio.cs"); - - // Test adding a new unnamed SimSet - %set = new SimSet() - { - foo = "bar"; - - new SFXDescription() - { - volume = 0.75; - channel = $GuiAudioType; - foo = 7; - }; - new SimGroup() - { - foo = 8; - - new SFXDescription() - { - volume = 0.75; - isLooping = true; - channel = $GuiAudioType; - foo = 9; - }; - }; - }; - - // Flag this as dirty - TestPManager.setDirty(%set, "core/scripts/client/audio.cs"); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); -} - -function TestPManager::testMoveObject(%doNotSave) -{ - // First add a couple of groups to the file - new SimGroup(MoveGroup1) - { - foo = "bar"; - - new SFXDescription(MoveObject1) - { - volume = 0.5; - isLooping = true; - channel = $GuiAudioType; - foo = 1; - }; - - new SimSet(SubGroup1) - { - new SFXDescription(SubObject1) - { - volume = 0.75; - isLooping = true; - channel = $GuiAudioType; - foo = 2; - }; - }; - }; - - // Flag this as dirty - TestPManager.setDirty(MoveGroup1, "core/scripts/client/audio.cs"); - - new SimGroup(MoveGroup2) - { - foo = "bar"; - - new SFXDescription(MoveObject2) - { - volume = 0.5; - isLooping = true; - channel = $GuiAudioType; - foo = 3; - }; - }; - - // Flag this as dirty - TestPManager.setDirty(MoveGroup2, "core/scripts/client/audio.cs"); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); - - // Set them as dirty again - TestPManager.setDirty(MoveGroup1); - TestPManager.setDirty(MoveGroup2); - - // Give the subobject an new value - MoveObject1.foo = 4; - - // Move it into the other group - MoveGroup1.add(MoveObject2); - - // Switch the other subobject - MoveGroup2.add(MoveObject1); - - // Also add a new unnamed object to one of the groups - %obj = new SFXDescription() - { - volume = 0.75; - isLooping = true; - bar = 5; - }; - - MoveGroup1.add(%obj); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); -} - -function TestPManager::testObjectRemove(%doNotSave) -{ - TestPManager.removeObjectFromFile(AudioSim); -} - -//Game Object management -function findGameObject(%name) -{ - //find all GameObjectAssets - %assetQuery = new AssetQuery(); - if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset")) - return 0; //if we didn't find ANY, just exit - - %count = %assetQuery.getCount(); - - for(%i=0; %i < %count; %i++) - { - %assetId = %assetQuery.getAsset(%i); - - //%assetName = AssetDatabase.getAssetName(%assetId); - - if(%assetId $= %name) - { - %gameObjectAsset = AssetDatabase.acquireAsset(%assetId); - - %assetQuery.delete(); - return %gameObjectAsset; - } - } - - %assetQuery.delete(); - return 0; -} - -function spawnGameObject(%name, %addToMissionGroup) -{ - if(%addToMissionGroup $= "") - %addToMissionGroup = true; - - //First, check if this already exists in our GameObjectPool - if(isObject(GameObjectPool)) - { - %goCount = GameObjectPool.countKey(%name); - - //if we have some already in the pool, pull it out and use that - if(%goCount != 0) - { - %goIdx = GameObjectPool.getIndexFromKey(%name); - %go = GameObjectPool.getValue(%goIdx); - - %go.setHidden(false); - %go.setScopeAlways(); - - if(%addToMissionGroup == true) //save instance when saving level - MissionGroup.add(%go); - else // clear instance on level exit - MissionCleanup.add(%go); - - //remove from the object pool's list - GameObjectPool.erase(%goIdx); - - return %go; - } - } - - //We have no existing pool, or no existing game objects of this type, so spawn a new one - - %gameObjectAsset = findGameObject(%name); - - if(isObject(%gameObjectAsset)) - { - %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath); - - if(%addToMissionGroup == true) //save instance when saving level - MissionGroup.add(%newSGOObject); - else // clear instance on level exit - MissionCleanup.add(%newSGOObject); - - return %newSGOObject; - } - - return 0; -} - -function saveGameObject(%name, %tamlPath, %scriptPath) -{ - %gameObjectAsset = findGameObject(%name); - - //find if it already exists. If it does, we'll update it, if it does not, we'll make a new asset - if(isObject(%gameObjectAsset)) - { - %assetID = %gameObjectAsset.getAssetId(); - - %gameObjectAsset.TAMLFilePath = %tamlPath; - %gameObjectAsset.scriptFilePath = %scriptPath; - - TAMLWrite(%gameObjectAsset, AssetDatabase.getAssetFilePath(%assetID)); - AssetDatabase.refreshAsset(%assetID); - } - else - { - //Doesn't exist, so make a new one - %gameObjectAsset = new GameObjectAsset() - { - assetName = %name @ "Asset"; - gameObjectName = %name; - TAMLFilePath = %tamlPath; - scriptFilePath = %scriptPath; - }; - - //Save it alongside the taml file - %path = filePath(%tamlPath); - - TAMLWrite(%gameObjectAsset, %path @ "/" @ %name @ ".asset.taml"); - AssetDatabase.refreshAllAssets(true); - } -} - -//Allocates a number of a game object into a pool to be pulled from as needed -function allocateGameObjects(%name, %amount) -{ - //First, we need to make sure our pool exists - if(!isObject(GameObjectPool)) - { - new ArrayObject(GameObjectPool); - } - - //Next, we loop and generate our game objects, and add them to the pool - for(%i=0; %i < %amount; %i++) - { - %go = spawnGameObject(%name, false); - - //When our object is in the pool, it's not "real", so we need to make sure - //that we don't ghost it to clients untill we actually spawn it. - %go.clearScopeAlways(); - - //We also hide it, so that we don't 'exist' in the scene until we spawn - %go.hidden = true; - - //Lastly, add us to the pool, with the key being our game object type - GameObjectPool.add(%name, %go); - } -} - -function Entity::delete(%this) -{ - //we want to intercept the delete call, and add it to our GameObjectPool - //if it's a game object - if(%this.gameObjectAsset !$= "") - { - %this.setHidden(true); - %this.clearScopeAlways(); - - if(!isObject(GameObjectPool)) - { - new ArrayObject(GameObjectPool); - } - - GameObjectPool.add(%this.gameObjectAsset, %this); - - %missionSet = %this.getGroup(); - %missionSet.remove(%this); - } - else - { - %this.superClass.delete(); - } -} - -function clearGameObjectPool() -{ - if(isObject(GameObjectPool)) - { - %count = GameObjectPool.count(); - - for(%i=0; %i < %count; %i++) - { - %go = GameObjectPool.getValue(%i); - - %go.superClass.delete(); - } - - GameObjectPool.empty(); - } -} - // function switchCamera(%client, %newCamEntity) { @@ -1155,4 +658,17 @@ function switchCamera(%client, %newCamEntity) %client.setControlCameraFov(%cam.FOV); %client.camera = %newCamEntity; +} + +function switchControlObject(%client, %newControlEntity) +{ + if(!isObject(%client) || !isObject(%newControlEntity)) + return error("SwitchControlObject: No client or target controller!"); + + %control = %newControlEntity.getComponent(ControlObjectComponent); + + if(!isObject(%control)) + return error("SwitchControlObject: Target controller has no conrol object behavior!"); + + %control.setConnectionControlObject(%client); } \ No newline at end of file diff --git a/Templates/BaseGame/game/core/utility/scripts/persistanceManagement.cs b/Templates/BaseGame/game/core/utility/scripts/persistanceManagement.cs new file mode 100644 index 000000000..aab054161 --- /dev/null +++ b/Templates/BaseGame/game/core/utility/scripts/persistanceManagement.cs @@ -0,0 +1,315 @@ +//Persistance Manager tests + +new PersistenceManager(TestPManager); + +function runPManTest(%test) +{ + if (!isObject(TestPManager)) + return; + + if (%test $= "") + %test = 100; + + switch(%test) + { + case 0: + TestPManager.testFieldUpdates(); + case 1: + TestPManager.testObjectRename(); + case 2: + TestPManager.testNewObject(); + case 3: + TestPManager.testNewGroup(); + case 4: + TestPManager.testMoveObject(); + case 5: + TestPManager.testObjectRemove(); + case 100: + TestPManager.testFieldUpdates(); + TestPManager.testObjectRename(); + TestPManager.testNewObject(); + TestPManager.testNewGroup(); + TestPManager.testMoveObject(); + TestPManager.testObjectRemove(); + } +} + +function TestPManager::testFieldUpdates(%doNotSave) +{ + // Set some objects as dirty + TestPManager.setDirty(AudioGui); + TestPManager.setDirty(AudioSim); + TestPManager.setDirty(AudioMessage); + + // Alter some of the existing fields + AudioEffect.isLooping = true; + AudioMessage.isLooping = true; + AudioEffect.is3D = true; + + // Test removing a field + TestPManager.removeField(AudioGui, "isLooping"); + + // Alter some of the persistent fields + AudioGui.referenceDistance = 0.8; + AudioMessage.referenceDistance = 0.8; + + // Add some new dynamic fields + AudioGui.foo = "bar"; + AudioEffect.foo = "bar"; + + // Remove an object from the dirty list + // It shouldn't get updated in the file + TestPManager.removeDirty(AudioEffect); + + // Dirty an object in another file as well + TestPManager.setDirty(WarningMaterial); + + // Update a field that doesn't exist + WarningMaterial.glow[0] = true; + + // Drity another object to test for crashes + // when a dirty object is deleted + TestPManager.setDirty(SFXPausedSet); + + // Delete the object + SFXPausedSet.delete(); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); +} + +function TestPManager::testObjectRename(%doNotSave) +{ + // Flag an object as dirty + if (isObject(AudioGui)) + TestPManager.setDirty(AudioGui); + else if (isObject(AudioGuiFoo)) + TestPManager.setDirty(AudioGuiFoo); + + // Rename it + if (isObject(AudioGui)) + AudioGui.setName(AudioGuiFoo); + else if (isObject(AudioGuiFoo)) + AudioGuiFoo.setName(AudioGui); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); +} + +function TestPManager::testNewObject(%doNotSave) +{ + // Test adding a new named object + new SFXDescription(AudioNew) + { + volume = 0.5; + isLooping = true; + channel = $GuiAudioType; + foo = 2; + }; + + // Flag it as dirty + TestPManager.setDirty(AudioNew, "core/scripts/client/audio.cs"); + + // Test adding a new unnamed object + %obj = new SFXDescription() + { + volume = 0.75; + isLooping = true; + bar = 3; + }; + + // Flag it as dirty + TestPManager.setDirty(%obj, "core/scripts/client/audio.cs"); + + // Test adding an "empty" object + new SFXDescription(AudioEmpty); + + TestPManager.setDirty(AudioEmpty, "core/scripts/client/audio.cs"); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); +} + +function TestPManager::testNewGroup(%doNotSave) +{ + // Test adding a new named SimGroup + new SimGroup(TestGroup) + { + foo = "bar"; + + new SFXDescription(TestObject) + { + volume = 0.5; + isLooping = true; + channel = $GuiAudioType; + foo = 1; + }; + new SimGroup(SubGroup) + { + foo = 2; + + new SFXDescription(SubObject) + { + volume = 0.5; + isLooping = true; + channel = $GuiAudioType; + foo = 3; + }; + }; + }; + + // Flag this as dirty + TestPManager.setDirty(TestGroup, "core/scripts/client/audio.cs"); + + // Test adding a new unnamed SimGroup + %group = new SimGroup() + { + foo = "bar"; + + new SFXDescription() + { + volume = 0.75; + channel = $GuiAudioType; + foo = 4; + }; + new SimGroup() + { + foo = 5; + + new SFXDescription() + { + volume = 0.75; + isLooping = true; + channel = $GuiAudioType; + foo = 6; + }; + }; + }; + + // Flag this as dirty + TestPManager.setDirty(%group, "core/scripts/client/audio.cs"); + + // Test adding a new unnamed SimSet + %set = new SimSet() + { + foo = "bar"; + + new SFXDescription() + { + volume = 0.75; + channel = $GuiAudioType; + foo = 7; + }; + new SimGroup() + { + foo = 8; + + new SFXDescription() + { + volume = 0.75; + isLooping = true; + channel = $GuiAudioType; + foo = 9; + }; + }; + }; + + // Flag this as dirty + TestPManager.setDirty(%set, "core/scripts/client/audio.cs"); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); +} + +function TestPManager::testMoveObject(%doNotSave) +{ + // First add a couple of groups to the file + new SimGroup(MoveGroup1) + { + foo = "bar"; + + new SFXDescription(MoveObject1) + { + volume = 0.5; + isLooping = true; + channel = $GuiAudioType; + foo = 1; + }; + + new SimSet(SubGroup1) + { + new SFXDescription(SubObject1) + { + volume = 0.75; + isLooping = true; + channel = $GuiAudioType; + foo = 2; + }; + }; + }; + + // Flag this as dirty + TestPManager.setDirty(MoveGroup1, "core/scripts/client/audio.cs"); + + new SimGroup(MoveGroup2) + { + foo = "bar"; + + new SFXDescription(MoveObject2) + { + volume = 0.5; + isLooping = true; + channel = $GuiAudioType; + foo = 3; + }; + }; + + // Flag this as dirty + TestPManager.setDirty(MoveGroup2, "core/scripts/client/audio.cs"); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); + + // Set them as dirty again + TestPManager.setDirty(MoveGroup1); + TestPManager.setDirty(MoveGroup2); + + // Give the subobject an new value + MoveObject1.foo = 4; + + // Move it into the other group + MoveGroup1.add(MoveObject2); + + // Switch the other subobject + MoveGroup2.add(MoveObject1); + + // Also add a new unnamed object to one of the groups + %obj = new SFXDescription() + { + volume = 0.75; + isLooping = true; + bar = 5; + }; + + MoveGroup1.add(%obj); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); +} + +function TestPManager::testObjectRemove(%doNotSave) +{ + TestPManager.removeObjectFromFile(AudioSim); +} \ No newline at end of file From ce18d46b82c5dbeab3ca515f815b96802fb25cb9 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Wed, 6 Mar 2019 18:14:36 -0600 Subject: [PATCH 66/75] the buildtiles method does not in fact build tiles right then and there, but instead queues tiles to update themselves over time. as such, simply disabling then enabling collision no longer functions (and how it did before so before is frankly likely due to exploiting a bug someplace upstream). as such, we set the same flag for NavMeshUpdateAll as we do for NavMeshIgnore to filter something as hidden from navmesh generation or not on a permanent, instead of a temporary basis via removing from the physics sim since it's likely to still be generating by the time it's put back. --- Engine/source/navigation/navMesh.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Engine/source/navigation/navMesh.cpp b/Engine/source/navigation/navMesh.cpp index 20b1bfa2c..c6189c366 100644 --- a/Engine/source/navigation/navMesh.cpp +++ b/Engine/source/navigation/navMesh.cpp @@ -107,8 +107,7 @@ DefineEngineFunction(NavMeshUpdateAll, void, (S32 objid, bool remove), (0, false SceneObject *obj; if(!Sim::findObject(objid, obj)) return; - if(remove) - obj->disableCollision(); + obj->mPathfindingIgnore = remove; SimSet *set = NavMesh::getServerSet(); for(U32 i = 0; i < set->size(); i++) { @@ -119,8 +118,6 @@ DefineEngineFunction(NavMeshUpdateAll, void, (S32 objid, bool remove), (0, false m->buildTiles(obj->getWorldBox()); } } - if(remove) - obj->enableCollision(); } DefineEngineFunction(NavMeshUpdateAroundObject, void, (S32 objid, bool remove), (0, false), @@ -129,8 +126,7 @@ DefineEngineFunction(NavMeshUpdateAroundObject, void, (S32 objid, bool remove), SceneObject *obj; if (!Sim::findObject(objid, obj)) return; - if (remove) - obj->disableCollision(); + obj->mPathfindingIgnore = remove; SimSet *set = NavMesh::getServerSet(); for (U32 i = 0; i < set->size(); i++) { @@ -141,8 +137,6 @@ DefineEngineFunction(NavMeshUpdateAroundObject, void, (S32 objid, bool remove), m->buildTiles(obj->getWorldBox()); } } - if (remove) - obj->enableCollision(); } From 028c9a40ac234eaf161eb33b55500751345b2f59 Mon Sep 17 00:00:00 2001 From: wcbx <44142101+wcbx@users.noreply.github.com> Date: Sun, 10 Mar 2019 23:08:50 -0400 Subject: [PATCH 67/75] Fixes artifacts in Cloud Layer. Cloud Layer uses normal. This applies appropriate profile for normal texture. --- Engine/source/environment/cloudLayer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Engine/source/environment/cloudLayer.cpp b/Engine/source/environment/cloudLayer.cpp index e30f1ecd1..08cb6ce00 100644 --- a/Engine/source/environment/cloudLayer.cpp +++ b/Engine/source/environment/cloudLayer.cpp @@ -398,10 +398,10 @@ void CloudLayer::_initTexture() } if ( mTextureName.isNotEmpty() ) - mTexture.set( mTextureName, &GFXStaticTextureSRGBProfile, "CloudLayer" ); + mTexture.set( mTextureName, &GFXNormalMapProfile, "CloudLayer" ); if ( mTexture.isNull() ) - mTexture.set( GFXTextureManager::getWarningTexturePath(), &GFXStaticTextureSRGBProfile, "CloudLayer" ); + mTexture.set( GFXTextureManager::getWarningTexturePath(), &GFXNormalMapProfile, "CloudLayer" ); } void CloudLayer::_initBuffers() @@ -501,4 +501,4 @@ void CloudLayer::_initBuffers() } mPB.unlock(); -} \ No newline at end of file +} From 7b01b42e155e5e60afca7e0b3899ccc706978b5c Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 16 Mar 2019 02:38:40 -0500 Subject: [PATCH 68/75] Fixes a crash that comes from toggling the editors on and off, then clicking a menubar item Fixes the menubar not resizing with the Window Fixes the Editors Menubar item not being repopulated if the editor was closed/reopened Fixes the Physics menubar item not appearing if the editor was closed/reopened Fixes issue where findMenu could fail if the StringTableEntry happened to trip against a different capitalization. --- Engine/source/gui/editor/guiMenuBar.cpp | 15 +++++-- Engine/source/gui/editor/guiMenuBar.h | 2 +- .../BaseGame/game/tools/physicsTools/main.cs | 22 ---------- .../tools/worldEditor/scripts/EditorGui.ed.cs | 10 ++++- .../tools/worldEditor/scripts/menus.ed.cs | 42 ++++++++++++++++++- .../Full/game/tools/physicsTools/main.cs | 22 ---------- .../tools/worldEditor/scripts/EditorGui.ed.cs | 12 +++++- .../tools/worldEditor/scripts/menus.ed.cs | 42 ++++++++++++++++++- 8 files changed, 113 insertions(+), 54 deletions(-) diff --git a/Engine/source/gui/editor/guiMenuBar.cpp b/Engine/source/gui/editor/guiMenuBar.cpp index 7a0f10ce3..ec75520c9 100644 --- a/Engine/source/gui/editor/guiMenuBar.cpp +++ b/Engine/source/gui/editor/guiMenuBar.cpp @@ -33,6 +33,7 @@ #include "gfx/gfxDrawUtil.h" #include "gfx/primBuilder.h" #include "console/engineAPI.h" +#include "gui/editor/guiPopupMenuCtrl.h" // menu bar: // basic idea - fixed height control bar at the top of a window, placed and sized in gui editor @@ -1113,6 +1114,13 @@ GuiMenuBar::GuiMenuBar() void GuiMenuBar::onRemove() { + GuiPopupMenuBackgroundCtrl* backgroundCtrl; + if (Sim::findObject("PopUpMenuControl", backgroundCtrl)) + { + if (backgroundCtrl->mMenuBarCtrl == this) + backgroundCtrl->mMenuBarCtrl = nullptr; + } + Parent::onRemove(); } @@ -1472,11 +1480,11 @@ PopupMenu* GuiMenuBar::getMenu(U32 index) return mMenuList[index].popupMenu; } -PopupMenu* GuiMenuBar::findMenu(StringTableEntry barTitle) +PopupMenu* GuiMenuBar::findMenu(String barTitle) { for (U32 i = 0; i < mMenuList.size(); i++) { - if (mMenuList[i].text == barTitle) + if (String::ToLower(mMenuList[i].text) == String::ToLower(barTitle)) return mMenuList[i].popupMenu; } @@ -1521,8 +1529,7 @@ DefineEngineMethod(GuiMenuBar, insert, void, (SimObject* pObject, S32 pos), (nul DefineEngineMethod(GuiMenuBar, findMenu, S32, (const char* barTitle), (""), "(barTitle)") { - StringTableEntry barTitleStr = StringTable->insert(barTitle); - PopupMenu* menu = object->findMenu(barTitleStr); + PopupMenu* menu = object->findMenu(barTitle); if (menu) return menu->getId(); diff --git a/Engine/source/gui/editor/guiMenuBar.h b/Engine/source/gui/editor/guiMenuBar.h index 054be37cc..985df8de6 100644 --- a/Engine/source/gui/editor/guiMenuBar.h +++ b/Engine/source/gui/editor/guiMenuBar.h @@ -116,7 +116,7 @@ public: U32 getMenuListCount() { return mMenuList.size(); } PopupMenu* getMenu(U32 index); - PopupMenu* findMenu(StringTableEntry barTitle); + PopupMenu* findMenu(String barTitle); DECLARE_CONOBJECT(GuiMenuBar); DECLARE_CALLBACK( void, onMouseInMenu, ( bool hasLeftMenu )); diff --git a/Templates/BaseGame/game/tools/physicsTools/main.cs b/Templates/BaseGame/game/tools/physicsTools/main.cs index 8da40844e..4fbf44bdb 100644 --- a/Templates/BaseGame/game/tools/physicsTools/main.cs +++ b/Templates/BaseGame/game/tools/physicsTools/main.cs @@ -64,28 +64,6 @@ function destroyPhysicsTools() function PhysicsEditorPlugin::onWorldEditorStartup( %this ) { - new PopupMenu( PhysicsToolsMenu ) - { - superClass = "MenuBuilder"; - //class = "PhysXToolsMenu"; - - barTitle = "Physics"; - - item[0] = "Start Simulation" TAB "Ctrl-Alt P" TAB "physicsStartSimulation( \"client\" );physicsStartSimulation( \"server\" );"; - //item[1] = "Stop Simulation" TAB "" TAB "physicsSetTimeScale( 0 );"; - item[1] = "-"; - item[2] = "Speed 25%" TAB "" TAB "physicsSetTimeScale( 0.25 );"; - item[3] = "Speed 50%" TAB "" TAB "physicsSetTimeScale( 0.5 );"; - item[4] = "Speed 100%" TAB "" TAB "physicsSetTimeScale( 1.0 );"; - item[5] = "-"; - item[6] = "Reload NXBs" TAB "" TAB ""; - }; - - // Add our menu. - EditorGui.menuBar.insert( PhysicsToolsMenu, EditorGui.menuBar.dynamicItemInsertPos ); - - // Add ourselves to the window menu. - //EditorGui.addToWindowMenu( "Road and Path Editor", "", "RoadEditor" ); } function PhysicsToolsMenu::onMenuSelect(%this) diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs index 50aac111b..8b24e2496 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -317,10 +317,15 @@ function EditorGui::shutdown( %this ) /// will take over the default world editor window. function EditorGui::addToEditorsMenu( %this, %displayName, %accel, %newPlugin ) { + //We need to cache the editors list. So first see if we have our list we cache the entries into + if(!isObject(EditorsMenuList)) + { + new ArrayObject(EditorsMenuList); + } + %windowMenu = %this.findMenu( "Editors" ); %count = %windowMenu.getItemCount(); - %alreadyExists = false; for ( %i = 0; %i < %count; %i++ ) { @@ -336,7 +341,10 @@ function EditorGui::addToEditorsMenu( %this, %displayName, %accel, %newPlugin ) %accel = ""; if(!%alreadyExists) + { + EditorsMenuList.add(%displayName TAB %accel TAB %newPlugin); %windowMenu.addItem( %count, %displayName TAB %accel TAB %newPlugin ); + } return %accel; } diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs index e0d53a76d..69ed628c9 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs @@ -113,7 +113,7 @@ function EditorGui::buildMenus(%this) %this.menuBar = new GuiMenuBar(WorldEditorMenubar) { dynamicItemInsertPos = 3; - extent = "1024 20"; + extent = Canvas.extent.x SPC "20"; minExtent = "320 20"; horizSizing = "width"; profile = "GuiMenuBarProfile"; @@ -251,6 +251,41 @@ function EditorGui::buildMenus(%this) //item[5] = "-"; }; %this.menuBar.insert(%editorsMenu); + + //if we're just refreshing the menus, we probably have a list of editors we want added to the Editors menu there, so check and if so, add them now + if(isObject(EditorsMenuList)) + { + %editorsListCount = EditorsMenuList.count(); + + for(%e = 0; %e < %editorsListCount; %e++) + { + %menuEntry = EditorsMenuList.getKey(%e); + %editorsMenu.addItem(%e, %menuEntry); + } + } + + if(isObject(PhysicsEditorPlugin)) + { + %physicsToolsMenu = new PopupMenu() + { + superClass = "MenuBuilder"; + //class = "PhysXToolsMenu"; + + barTitle = "Physics"; + + item[0] = "Start Simulation" TAB "Ctrl-Alt P" TAB "physicsStartSimulation( \"client\" );physicsStartSimulation( \"server\" );"; + //item[1] = "Stop Simulation" TAB "" TAB "physicsSetTimeScale( 0 );"; + item[1] = "-"; + item[2] = "Speed 25%" TAB "" TAB "physicsSetTimeScale( 0.25 );"; + item[3] = "Speed 50%" TAB "" TAB "physicsSetTimeScale( 0.5 );"; + item[4] = "Speed 100%" TAB "" TAB "physicsSetTimeScale( 1.0 );"; + item[5] = "-"; + item[6] = "Reload NXBs" TAB "" TAB ""; + }; + + // Add our menu. + %this.menuBar.insert( %physicsToolsMenu, EditorGui.menuBar.dynamicItemInsertPos ); + } // Lighting Menu %lightingMenu = new PopupMenu() @@ -389,6 +424,11 @@ function EditorGui::buildMenus(%this) ////////////////////////////////////////////////////////////////////////// +function WorldEditorMenubar::onResize(%this) +{ + %this.extent.x = Canvas.extent.x; +} + function EditorGui::attachMenus(%this) { %this.menuBar.attachToCanvas(Canvas, 0); diff --git a/Templates/Full/game/tools/physicsTools/main.cs b/Templates/Full/game/tools/physicsTools/main.cs index 8da40844e..4fbf44bdb 100644 --- a/Templates/Full/game/tools/physicsTools/main.cs +++ b/Templates/Full/game/tools/physicsTools/main.cs @@ -64,28 +64,6 @@ function destroyPhysicsTools() function PhysicsEditorPlugin::onWorldEditorStartup( %this ) { - new PopupMenu( PhysicsToolsMenu ) - { - superClass = "MenuBuilder"; - //class = "PhysXToolsMenu"; - - barTitle = "Physics"; - - item[0] = "Start Simulation" TAB "Ctrl-Alt P" TAB "physicsStartSimulation( \"client\" );physicsStartSimulation( \"server\" );"; - //item[1] = "Stop Simulation" TAB "" TAB "physicsSetTimeScale( 0 );"; - item[1] = "-"; - item[2] = "Speed 25%" TAB "" TAB "physicsSetTimeScale( 0.25 );"; - item[3] = "Speed 50%" TAB "" TAB "physicsSetTimeScale( 0.5 );"; - item[4] = "Speed 100%" TAB "" TAB "physicsSetTimeScale( 1.0 );"; - item[5] = "-"; - item[6] = "Reload NXBs" TAB "" TAB ""; - }; - - // Add our menu. - EditorGui.menuBar.insert( PhysicsToolsMenu, EditorGui.menuBar.dynamicItemInsertPos ); - - // Add ourselves to the window menu. - //EditorGui.addToWindowMenu( "Road and Path Editor", "", "RoadEditor" ); } function PhysicsToolsMenu::onMenuSelect(%this) diff --git a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs index 50aac111b..4341653f8 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -317,10 +317,15 @@ function EditorGui::shutdown( %this ) /// will take over the default world editor window. function EditorGui::addToEditorsMenu( %this, %displayName, %accel, %newPlugin ) { + //We need to cache the editors list. So first see if we have our list we cache the entries into + if(!isObject(EditorsMenuList)) + { + new ArrayObject(EditorsMenuList); + } + %windowMenu = %this.findMenu( "Editors" ); %count = %windowMenu.getItemCount(); - - + %alreadyExists = false; for ( %i = 0; %i < %count; %i++ ) { @@ -336,7 +341,10 @@ function EditorGui::addToEditorsMenu( %this, %displayName, %accel, %newPlugin ) %accel = ""; if(!%alreadyExists) + { + EditorsMenuList.add(%displayName TAB %accel TAB %newPlugin); %windowMenu.addItem( %count, %displayName TAB %accel TAB %newPlugin ); + } return %accel; } diff --git a/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs index b225d3534..4e8052685 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs @@ -113,7 +113,7 @@ function EditorGui::buildMenus(%this) %this.menuBar = new GuiMenuBar(WorldEditorMenubar) { dynamicItemInsertPos = 3; - extent = "1024 20"; + extent = Canvas.extent.x SPC "20"; minExtent = "320 20"; horizSizing = "width"; profile = "GuiMenuBarProfile"; @@ -251,6 +251,41 @@ function EditorGui::buildMenus(%this) //item[5] = "-"; }; %this.menuBar.insert(%editorsMenu); + + //if we're just refreshing the menus, we probably have a list of editors we want added to the Editors menu there, so check and if so, add them now + if(isObject(EditorsMenuList)) + { + %editorsListCount = EditorsMenuList.count(); + + for(%e = 0; %e < %editorsListCount; %e++) + { + %menuEntry = EditorsMenuList.getKey(%e); + %editorsMenu.addItem(%e, %menuEntry); + } + } + + if(isObject(PhysicsEditorPlugin)) + { + %physicsToolsMenu = new PopupMenu() + { + superClass = "MenuBuilder"; + //class = "PhysXToolsMenu"; + + barTitle = "Physics"; + + item[0] = "Start Simulation" TAB "Ctrl-Alt P" TAB "physicsStartSimulation( \"client\" );physicsStartSimulation( \"server\" );"; + //item[1] = "Stop Simulation" TAB "" TAB "physicsSetTimeScale( 0 );"; + item[1] = "-"; + item[2] = "Speed 25%" TAB "" TAB "physicsSetTimeScale( 0.25 );"; + item[3] = "Speed 50%" TAB "" TAB "physicsSetTimeScale( 0.5 );"; + item[4] = "Speed 100%" TAB "" TAB "physicsSetTimeScale( 1.0 );"; + item[5] = "-"; + item[6] = "Reload NXBs" TAB "" TAB ""; + }; + + // Add our menu. + %this.menuBar.insert( %physicsToolsMenu, EditorGui.menuBar.dynamicItemInsertPos ); + } // Lighting Menu %lightingMenu = new PopupMenu() @@ -387,6 +422,11 @@ function EditorGui::buildMenus(%this) ////////////////////////////////////////////////////////////////////////// +function WorldEditorMenubar::onResize(%this) +{ + %this.extent.x = Canvas.extent.x; +} + function EditorGui::attachMenus(%this) { %this.menuBar.attachToCanvas(Canvas, 0); From 7b4fdd8b81f8606cf3f4dc82a01cb33bc0111533 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 16 Mar 2019 03:13:47 -0500 Subject: [PATCH 69/75] Properly converted Spectator and FPS Gameplay modules' levels to utilize Scene --- Templates/Modules/FPSGameplay/levels/Empty Terrain.mis | 2 +- Templates/Modules/FPSGameplay/levels/EmptyLevel.mis | 2 +- Templates/Modules/FPSGameplay/levels/Outpost.mis | 2 +- Templates/Modules/spectatorGameplay/levels/Empty_Room.mis | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Templates/Modules/FPSGameplay/levels/Empty Terrain.mis b/Templates/Modules/FPSGameplay/levels/Empty Terrain.mis index 894164049..72a136c3c 100644 --- a/Templates/Modules/FPSGameplay/levels/Empty Terrain.mis +++ b/Templates/Modules/FPSGameplay/levels/Empty Terrain.mis @@ -1,5 +1,5 @@ //--- OBJECT WRITE BEGIN --- -new SimGroup(MissionGroup) { +new Scene(EmptyTerrainLevel) { canSaveDynamicFields = "1"; enabled = "1"; diff --git a/Templates/Modules/FPSGameplay/levels/EmptyLevel.mis b/Templates/Modules/FPSGameplay/levels/EmptyLevel.mis index 9d5eddd95..db7b8dc56 100644 --- a/Templates/Modules/FPSGameplay/levels/EmptyLevel.mis +++ b/Templates/Modules/FPSGameplay/levels/EmptyLevel.mis @@ -1,5 +1,5 @@ //--- OBJECT WRITE BEGIN --- -new SimGroup(MissionGroup) { +new Scene(EmptyLevel) { canSave = "1"; canSaveDynamicFields = "1"; cdTrack = "2"; diff --git a/Templates/Modules/FPSGameplay/levels/Outpost.mis b/Templates/Modules/FPSGameplay/levels/Outpost.mis index be3f48652..c9d28b2c9 100644 --- a/Templates/Modules/FPSGameplay/levels/Outpost.mis +++ b/Templates/Modules/FPSGameplay/levels/Outpost.mis @@ -1,5 +1,5 @@ //--- OBJECT WRITE BEGIN --- -new SimGroup(MissionGroup) { +new Scene(OutpostLevel) { canSave = "1"; canSaveDynamicFields = "1"; enabled = "1"; diff --git a/Templates/Modules/spectatorGameplay/levels/Empty_Room.mis b/Templates/Modules/spectatorGameplay/levels/Empty_Room.mis index 2ac402388..de98a2e7a 100644 --- a/Templates/Modules/spectatorGameplay/levels/Empty_Room.mis +++ b/Templates/Modules/spectatorGameplay/levels/Empty_Room.mis @@ -1,5 +1,5 @@ //--- OBJECT WRITE BEGIN --- -new SimGroup(MissionGroup) { +new Scene(Empty_RoomLevel) { canSave = "1"; canSaveDynamicFields = "1"; Enabled = "1"; From 6f5c215d9efab40e0d4c82b4fc5d3ab3ba179a1b Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 16 Mar 2019 10:48:00 -0500 Subject: [PATCH 70/75] Adds logic to temporarily disable collisions of mounted objects on Players so you don't try colliding with things that are mounted to you when moving. --- Engine/source/T3D/player.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Engine/source/T3D/player.cpp b/Engine/source/T3D/player.cpp index 9a2c072a6..f1feaf833 100644 --- a/Engine/source/T3D/player.cpp +++ b/Engine/source/T3D/player.cpp @@ -6150,8 +6150,22 @@ void Player::updateWorkingCollisionSet() mWorkingQueryBox.maxExtents += twolPoint; disableCollision(); + + //We temporarily disable the collisions of anything mounted to us so we don't accidentally walk into things we've attached to us + for (SceneObject *ptr = mMount.list; ptr; ptr = ptr->getMountLink()) + { + ptr->disableCollision(); + } + mConvex.updateWorkingList(mWorkingQueryBox, isGhost() ? sClientCollisionContactMask : sServerCollisionContactMask); + + //And now re-enable the collisions of the mounted things + for (SceneObject *ptr = mMount.list; ptr; ptr = ptr->getMountLink()) + { + ptr->enableCollision(); + } + enableCollision(); } } From a438cda47f3e4783ebde334aee0269a248c61ad5 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 17 Mar 2019 02:33:54 -0500 Subject: [PATCH 71/75] Makes the popups correctly operate anywhere in the space of the canvas Also corrects a notional issue where if a poup extends past the bottom of the screen, it'll instead appear above the mouse so it doesn't ever get cut off. --- Engine/source/gui/editor/popupMenu.cpp | 295 +++++++++++++------------ 1 file changed, 149 insertions(+), 146 deletions(-) diff --git a/Engine/source/gui/editor/popupMenu.cpp b/Engine/source/gui/editor/popupMenu.cpp index 308fb4e67..9aef352ca 100644 --- a/Engine/source/gui/editor/popupMenu.cpp +++ b/Engine/source/gui/editor/popupMenu.cpp @@ -282,156 +282,159 @@ void PopupMenu::showPopup(GuiCanvas *owner, S32 x /* = -1 */, S32 y /* = -1 */) if (owner == NULL) return; - GuiControl* editorGui; - Sim::findObject("EditorGui", editorGui); + GuiPopupMenuBackgroundCtrl* backgroundCtrl; + Sim::findObject("PopUpMenuControl", backgroundCtrl); - if (editorGui) + GuiControlProfile* profile; + Sim::findObject("GuiMenubarProfile", profile); + + if (!profile) + return; + + if (mTextList == nullptr) { - GuiPopupMenuBackgroundCtrl* backgroundCtrl; - Sim::findObject("PopUpMenuControl", backgroundCtrl); + mTextList = new GuiPopupMenuTextListCtrl(); + mTextList->registerObject(); + mTextList->setControlProfile(profile); - GuiControlProfile* profile; - Sim::findObject("GuiMenubarProfile", profile); - - if (!profile) - return; - - if (mTextList == nullptr) - { - mTextList = new GuiPopupMenuTextListCtrl(); - mTextList->registerObject(); - mTextList->setControlProfile(profile); - - mTextList->mPopup = this; - mTextList->mMenuBar = getMenuBarCtrl(); - } - - if (!backgroundCtrl) - { - backgroundCtrl = new GuiPopupMenuBackgroundCtrl(); - - backgroundCtrl->registerObject("PopUpMenuControl"); - } - - if (!backgroundCtrl || !mTextList) - return; - - if (!mIsSubmenu) - { - //if we're a 'parent' menu, then tell the background to clear out all existing other popups - - backgroundCtrl->clearPopups(); - } - - //find out if we're doing a first-time add - S32 popupIndex = backgroundCtrl->findPopupMenu(this); - - if (popupIndex == -1) - { - backgroundCtrl->addObject(mTextList); - backgroundCtrl->mPopups.push_back(this); - } - - mTextList->mBackground = backgroundCtrl; - - owner->pushDialogControl(backgroundCtrl, 10); - - //Set the background control's menubar, if any, and if it's not already set - if(backgroundCtrl->mMenuBarCtrl == nullptr) - backgroundCtrl->mMenuBarCtrl = getMenuBarCtrl(); - - backgroundCtrl->setExtent(editorGui->getExtent()); - - mTextList->clear(); - - S32 textWidth = 0, width = 0; - S32 acceleratorWidth = 0; - GFont *font = profile->mFont; - - Point2I maxBitmapSize = Point2I(0, 0); - - S32 numBitmaps = profile->mBitmapArrayRects.size(); - if (numBitmaps) - { - RectI *bitmapBounds = profile->mBitmapArrayRects.address(); - for (S32 i = 0; i < numBitmaps; i++) - { - if (bitmapBounds[i].extent.x > maxBitmapSize.x) - maxBitmapSize.x = bitmapBounds[i].extent.x; - if (bitmapBounds[i].extent.y > maxBitmapSize.y) - maxBitmapSize.y = bitmapBounds[i].extent.y; - } - } - - for (U32 i = 0; i < mMenuItems.size(); i++) - { - if (!mMenuItems[i].mVisible) - continue; - - S32 iTextWidth = font->getStrWidth(mMenuItems[i].mText.c_str()); - S32 iAcceleratorWidth = mMenuItems[i].mAccelerator ? font->getStrWidth(mMenuItems[i].mAccelerator) : 0; - - if (iTextWidth > textWidth) - textWidth = iTextWidth; - if (iAcceleratorWidth > acceleratorWidth) - acceleratorWidth = iAcceleratorWidth; - } - - width = textWidth + acceleratorWidth + maxBitmapSize.x * 2 + 2 + 4; - - mTextList->setCellSize(Point2I(width, font->getHeight() + 2)); - mTextList->clearColumnOffsets(); - mTextList->addColumnOffset(-1); // add an empty column in for the bitmap index. - mTextList->addColumnOffset(maxBitmapSize.x + 1); - mTextList->addColumnOffset(maxBitmapSize.x + 1 + textWidth + 4); - - U32 entryCount = 0; - - for (U32 i = 0; i < mMenuItems.size(); i++) - { - if (!mMenuItems[i].mVisible) - continue; - - char buf[512]; - - // If this menu item is a submenu, then set the isSubmenu to 2 to indicate - // an arrow should be drawn. Otherwise set the isSubmenu normally. - char isSubmenu = 1; - if (mMenuItems[i].mIsSubmenu) - isSubmenu = 2; - - char bitmapIndex = 1; - if (mMenuItems[i].mBitmapIndex >= 0 && (mMenuItems[i].mBitmapIndex * 3 <= profile->mBitmapArrayRects.size())) - bitmapIndex = mMenuItems[i].mBitmapIndex + 2; - - dSprintf(buf, sizeof(buf), "%c%c\t%s\t%s", bitmapIndex, isSubmenu, mMenuItems[i].mText.c_str(), mMenuItems[i].mAccelerator ? mMenuItems[i].mAccelerator : ""); - mTextList->addEntry(entryCount, buf); - - if (!mMenuItems[i].mEnabled) - mTextList->setEntryActive(entryCount, false); - - entryCount++; - } - - Point2I pos = Point2I::Zero; - - if (x == -1 && y == -1) - pos = owner->getCursorPos(); - else - pos = Point2I(x, y); - - mTextList->setPosition(pos); - - //nudge in if we'd overshoot the screen - S32 widthDiff = (mTextList->getPosition().x + mTextList->getExtent().x) - backgroundCtrl->getWidth(); - if (widthDiff > 0) - { - Point2I popupPos = mTextList->getPosition(); - mTextList->setPosition(popupPos.x - widthDiff, popupPos.y); - } - - mTextList->setHidden(false); + mTextList->mPopup = this; + mTextList->mMenuBar = getMenuBarCtrl(); } + + if (!backgroundCtrl) + { + backgroundCtrl = new GuiPopupMenuBackgroundCtrl(); + + backgroundCtrl->registerObject("PopUpMenuControl"); + } + + if (!backgroundCtrl || !mTextList) + return; + + if (!mIsSubmenu) + { + //if we're a 'parent' menu, then tell the background to clear out all existing other popups + + backgroundCtrl->clearPopups(); + } + + //find out if we're doing a first-time add + S32 popupIndex = backgroundCtrl->findPopupMenu(this); + + if (popupIndex == -1) + { + backgroundCtrl->addObject(mTextList); + backgroundCtrl->mPopups.push_back(this); + } + + mTextList->mBackground = backgroundCtrl; + + owner->pushDialogControl(backgroundCtrl, 10); + + //Set the background control's menubar, if any, and if it's not already set + if(backgroundCtrl->mMenuBarCtrl == nullptr) + backgroundCtrl->mMenuBarCtrl = getMenuBarCtrl(); + + backgroundCtrl->setExtent(owner->getExtent()); + + mTextList->clear(); + + S32 textWidth = 0, width = 0; + S32 acceleratorWidth = 0; + GFont *font = profile->mFont; + + Point2I maxBitmapSize = Point2I(0, 0); + + S32 numBitmaps = profile->mBitmapArrayRects.size(); + if (numBitmaps) + { + RectI *bitmapBounds = profile->mBitmapArrayRects.address(); + for (S32 i = 0; i < numBitmaps; i++) + { + if (bitmapBounds[i].extent.x > maxBitmapSize.x) + maxBitmapSize.x = bitmapBounds[i].extent.x; + if (bitmapBounds[i].extent.y > maxBitmapSize.y) + maxBitmapSize.y = bitmapBounds[i].extent.y; + } + } + + for (U32 i = 0; i < mMenuItems.size(); i++) + { + if (!mMenuItems[i].mVisible) + continue; + + S32 iTextWidth = font->getStrWidth(mMenuItems[i].mText.c_str()); + S32 iAcceleratorWidth = mMenuItems[i].mAccelerator ? font->getStrWidth(mMenuItems[i].mAccelerator) : 0; + + if (iTextWidth > textWidth) + textWidth = iTextWidth; + if (iAcceleratorWidth > acceleratorWidth) + acceleratorWidth = iAcceleratorWidth; + } + + width = textWidth + acceleratorWidth + maxBitmapSize.x * 2 + 2 + 4; + + mTextList->setCellSize(Point2I(width, font->getHeight() + 2)); + mTextList->clearColumnOffsets(); + mTextList->addColumnOffset(-1); // add an empty column in for the bitmap index. + mTextList->addColumnOffset(maxBitmapSize.x + 1); + mTextList->addColumnOffset(maxBitmapSize.x + 1 + textWidth + 4); + + U32 entryCount = 0; + + for (U32 i = 0; i < mMenuItems.size(); i++) + { + if (!mMenuItems[i].mVisible) + continue; + + char buf[512]; + + // If this menu item is a submenu, then set the isSubmenu to 2 to indicate + // an arrow should be drawn. Otherwise set the isSubmenu normally. + char isSubmenu = 1; + if (mMenuItems[i].mIsSubmenu) + isSubmenu = 2; + + char bitmapIndex = 1; + if (mMenuItems[i].mBitmapIndex >= 0 && (mMenuItems[i].mBitmapIndex * 3 <= profile->mBitmapArrayRects.size())) + bitmapIndex = mMenuItems[i].mBitmapIndex + 2; + + dSprintf(buf, sizeof(buf), "%c%c\t%s\t%s", bitmapIndex, isSubmenu, mMenuItems[i].mText.c_str(), mMenuItems[i].mAccelerator ? mMenuItems[i].mAccelerator : ""); + mTextList->addEntry(entryCount, buf); + + if (!mMenuItems[i].mEnabled) + mTextList->setEntryActive(entryCount, false); + + entryCount++; + } + + Point2I pos = Point2I::Zero; + + if (x == -1 && y == -1) + pos = owner->getCursorPos(); + else + pos = Point2I(x, y); + + mTextList->setPosition(pos); + + //nudge in if we'd overshoot the screen + S32 widthDiff = (mTextList->getPosition().x + mTextList->getExtent().x) - backgroundCtrl->getWidth(); + if (widthDiff > 0) + { + Point2I popupPos = mTextList->getPosition(); + mTextList->setPosition(popupPos.x - widthDiff, popupPos.y); + } + + //If we'd overshoot the screen vertically, just mirror the axis so we're above the mouse + S32 heightDiff = (mTextList->getPosition().y + mTextList->getExtent().y) - backgroundCtrl->getHeight(); + if (heightDiff > 0) + { + Point2I popupPos = mTextList->getPosition(); + mTextList->setPosition(popupPos.x, popupPos.y - mTextList->getExtent().y); + } + + + mTextList->setHidden(false); } void PopupMenu::hidePopup() From 2311120cbcc6743437c78ae51f4302429ec75977 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 30 Mar 2019 14:40:58 -0500 Subject: [PATCH 72/75] Update guiSplitContainer.cpp Corrected typo. --- Engine/source/gui/containers/guiSplitContainer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/gui/containers/guiSplitContainer.cpp b/Engine/source/gui/containers/guiSplitContainer.cpp index 971dd262f..59b2bb75f 100644 --- a/Engine/source/gui/containers/guiSplitContainer.cpp +++ b/Engine/source/gui/containers/guiSplitContainer.cpp @@ -631,7 +631,7 @@ void GuiSplitContainer::setSplitPoint(Point2I splitPoint) } DefineEngineMethod(GuiSplitContainer, setSplitPoint, void, (Point2I splitPoint), , - "Set the positin of the split handler.") + "Set the position of the split handle.") { object->setSplitPoint(splitPoint); -} \ No newline at end of file +} From 8d85a56095bf88258401c5f065ea18139b15fb62 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 31 Mar 2019 22:12:38 -0500 Subject: [PATCH 73/75] Failed to get the Scene changes for the Full template rolled up. This corrects that. --- .../tools/worldEditor/scripts/EditorGui.ed.cs | 1 + .../game/core/scripts/client/helperfuncs.cs | 4 +- .../core/scripts/server/missionDownload.cs | 2 +- .../game/core/scripts/server/missionLoad.cs | 10 +-- Templates/Full/game/levels/Empty Room.mis | 2 +- Templates/Full/game/levels/Empty Terrain.mis | 82 +++++++++++++++++-- Templates/Full/game/levels/Outpost.mis | 2 +- .../Full/game/scripts/server/gameCore.cs | 6 +- Templates/Full/game/scripts/server/item.cs | 2 +- Templates/Full/game/scripts/server/turret.cs | 8 +- Templates/Full/game/shaders/.gitignore | 1 - .../Full/game/shaders/procedural/.gitignore | 2 + .../Full/game/tools/convexEditor/main.cs | 2 +- .../Full/game/tools/gui/colladaImport.ed.gui | 4 +- .../Full/game/tools/levels/BlankRoom.mis | 2 +- .../scripts/materialEditor.ed.cs | 2 +- .../scripts/materialEditorUndo.ed.cs | 4 +- .../Full/game/tools/meshRoadEditor/main.cs | 2 +- .../Full/game/tools/missionAreaEditor/main.cs | 2 +- .../tools/navEditor/CreateNewNavMeshDlg.gui | 8 +- Templates/Full/game/tools/navEditor/main.cs | 2 +- Templates/Full/game/tools/riverEditor/main.cs | 2 +- Templates/Full/game/tools/roadEditor/main.cs | 2 +- Templates/Full/game/tools/shapeEditor/main.cs | 2 +- .../worldEditor/gui/TimeAdjustGui.ed.gui | 6 +- .../worldEditor/gui/objectBuilderGui.ed.gui | 8 +- .../tools/worldEditor/scripts/EditorGui.ed.cs | 32 +++++--- .../scripts/SelectObjectsWindow.ed.cs | 2 +- .../worldEditor/scripts/editors/creator.ed.cs | 6 +- .../scripts/editors/worldEditor.ed.cs | 8 +- .../worldEditor/scripts/menuHandlers.ed.cs | 17 +++- 31 files changed, 167 insertions(+), 68 deletions(-) delete mode 100644 Templates/Full/game/shaders/.gitignore create mode 100644 Templates/Full/game/shaders/procedural/.gitignore diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs index d75728978..8cc951a99 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -1884,6 +1884,7 @@ function Editor::open(%this) %this.editorEnabled(); Canvas.setContent(EditorGui); + $isFirstPersonVar = true; EditorGui.syncCameraGui(); } diff --git a/Templates/Full/game/core/scripts/client/helperfuncs.cs b/Templates/Full/game/core/scripts/client/helperfuncs.cs index f8988a270..511a47d4a 100644 --- a/Templates/Full/game/core/scripts/client/helperfuncs.cs +++ b/Templates/Full/game/core/scripts/client/helperfuncs.cs @@ -219,7 +219,7 @@ function AggregateControl::callMethod(%this, %method, %args) function parseMissionGroup( %className, %childGroup ) { if( getWordCount( %childGroup ) == 0) - %currentGroup = "MissionGroup"; + %currentGroup = getRootScene(); else %currentGroup = %childGroup; @@ -240,7 +240,7 @@ function parseMissionGroup( %className, %childGroup ) function parseMissionGroupForIds( %className, %childGroup ) { if( getWordCount( %childGroup ) == 0) - %currentGroup = "MissionGroup"; + %currentGroup = getRootScene(); else %currentGroup = %childGroup; diff --git a/Templates/Full/game/core/scripts/server/missionDownload.cs b/Templates/Full/game/core/scripts/server/missionDownload.cs index 2b1168b39..b3bf07ef2 100644 --- a/Templates/Full/game/core/scripts/server/missionDownload.cs +++ b/Templates/Full/game/core/scripts/server/missionDownload.cs @@ -49,7 +49,7 @@ function GameConnection::loadMission(%this) else { commandToClient(%this, 'MissionStartPhase1', $missionSequence, - $Server::MissionFile, MissionGroup.musicTrack); + $Server::MissionFile, getRootScene().musicTrack); echo("*** Sending mission load to client: " @ $Server::MissionFile); } } diff --git a/Templates/Full/game/core/scripts/server/missionLoad.cs b/Templates/Full/game/core/scripts/server/missionLoad.cs index d85b15516..f5acb588b 100644 --- a/Templates/Full/game/core/scripts/server/missionLoad.cs +++ b/Templates/Full/game/core/scripts/server/missionLoad.cs @@ -96,12 +96,12 @@ function loadMissionStage2() // to caching mission lighting. $missionCRC = getFileCRC( %file ); - // Exec the mission. The MissionGroup (loaded components) is added to the ServerGroup + // Exec the mission. The Scene (loaded components) is added to the ServerGroup exec(%file); - if( !isObject(MissionGroup) ) + if( !isObject(getRootScene()) ) { - $Server::LoadFailMsg = "No 'MissionGroup' found in mission \"" @ %file @ "\"."; + $Server::LoadFailMsg = "No 'Scene' found in mission \"" @ %file @ "\"."; } } @@ -145,7 +145,7 @@ function loadMissionStage2() function endMission() { - if (!isObject( MissionGroup )) + if (!isObject( getRootScene() )) return; echo("*** ENDING MISSION"); @@ -163,7 +163,7 @@ function endMission() } // Delete everything - MissionGroup.delete(); + getRootScene().delete(); MissionCleanup.delete(); clearServerPaths(); diff --git a/Templates/Full/game/levels/Empty Room.mis b/Templates/Full/game/levels/Empty Room.mis index c3ba059a4..fdb4665ba 100644 --- a/Templates/Full/game/levels/Empty Room.mis +++ b/Templates/Full/game/levels/Empty Room.mis @@ -1,5 +1,5 @@ //--- OBJECT WRITE BEGIN --- -new SimGroup(MissionGroup) { +new Scene(EmptyLevel) { canSaveDynamicFields = "1"; Enabled = "1"; diff --git a/Templates/Full/game/levels/Empty Terrain.mis b/Templates/Full/game/levels/Empty Terrain.mis index 0428ece36..aa77b6c6b 100644 --- a/Templates/Full/game/levels/Empty Terrain.mis +++ b/Templates/Full/game/levels/Empty Terrain.mis @@ -1,39 +1,57 @@ //--- OBJECT WRITE BEGIN --- -new SimGroup(MissionGroup) { +new Scene(EmptyTerrainLevel) { + canSave = "1"; canSaveDynamicFields = "1"; + isSubscene = "0"; + isEditing = "0"; + isDirty = "0"; enabled = "1"; new LevelInfo(theLevelInfo) { nearClip = "0.1"; visibleDistance = "2000"; + visibleGhostDistance = "0"; decalBias = "0.0015"; fogColor = "1 1 0.6 1"; fogDensity = "0.001"; fogDensityOffset = "10"; fogAtmosphereHeight = "100"; canvasClearColor = "233 220 143 255"; + ambientLightBlendPhase = "1"; + ambientLightBlendCurve = "0 0 -1 -1"; advancedLightmapSupport = "0"; + soundAmbience = "AudioAmbienceDefault"; + soundDistanceModel = "Linear"; + canSave = "1"; + canSaveDynamicFields = "1"; desc0 = "An empty terrain ready to be populated with Torque objects."; - LevelName = "Empty Terrain"; + levelName = "Empty Terrain"; }; new ScatterSky() { skyBrightness = "30"; - mieScattering = "0.0015"; + sunSize = "1"; + colorizeAmount = "0"; + colorize = "0 0 0 1"; rayleighScattering = "0.0035"; sunScale = "1 1 0.8 1"; ambientScale = "0.5 0.5 0.4 1"; + fogScale = "1 1 1 1"; exposure = "0.85"; + zOffset = "0"; azimuth = "84"; elevation = "54"; + moonAzimuth = "0"; + moonElevation = "45"; castShadows = "1"; + staticRefreshFreq = "8"; + dynamicRefreshFreq = "8"; brightness = "1"; - flareType = "SunFlareExample1"; flareScale = "1"; nightColor = "0.0196078 0.0117647 0.109804 1"; + nightFogColor = "0.0196078 0.0117647 0.109804 1"; moonEnabled = "1"; - moonTexture = "core/art/skies/night/moon_wglow"; moonScale = "0.3"; - moonTint = "0.192157 0.192157 0.192157 1"; + moonLightColor = "0.192157 0.192157 0.192157 1"; useNightCubemap = "0"; attenuationRatio = "0 1 1"; shadowType = "PSSM"; @@ -51,40 +69,86 @@ new SimGroup(MissionGroup) { position = "0 0 0"; rotation = "1 0 0 0"; scale = "1 1 1"; + canSave = "1"; canSaveDynamicFields = "1"; + mieScattering = "0.0015"; + moonTexture = "core/art/skies/night/moon_wglow"; + moonTint = "0.192157 0.192157 0.192157 1"; sunBrightness = "50"; }; new TerrainBlock(theTerrain) { terrainFile = "art/terrains/Empty Terrain_0.ter"; + castShadows = "1"; squareSize = "2"; - tile = "0"; baseTexSize = "1024"; + baseTexFormat = "DDS"; + lightMapSize = "256"; screenError = "16"; + ignoreZodiacs = "0"; position = "-1024 -1024 179.978"; rotation = "1 0 0 0"; - scale = "1 1 1"; + canSave = "1"; canSaveDynamicFields = "1"; + scale = "1 1 1"; + tile = "0"; }; new SimGroup(PlayerDropPoints) { + canSave = "1"; canSaveDynamicFields = "1"; enabled = "1"; new SpawnSphere() { autoSpawn = "0"; + spawnTransform = "0"; radius = "1"; sphereWeight = "1"; indoorWeight = "1"; outdoorWeight = "1"; + isAIControlled = "0"; dataBlock = "SpawnSphereMarker"; position = "0 0 241.772"; rotation = "1 0 0 0"; scale = "1 1 1"; + canSave = "1"; canSaveDynamicFields = "1"; enabled = "1"; homingCount = "0"; lockCount = "0"; - TypeBool locked = "False"; }; }; + new ConvexShape() { + Material = "Grid512_OrangeLines_Mat"; + position = "6.31688 13.7911 241.9"; + rotation = "0.475487 0.209976 -0.854296 13.8377"; + scale = "1 1 1"; + canSave = "1"; + canSaveDynamicFields = "1"; + + surface = "0 0 0 1 0 0 1.58549"; + surface = "0 1 0 0 0 0 -1.58549"; + surface = "0.707107 0 0 0.707107 0 4.99426 0"; + surface = "0 0.707107 -0.707107 0 0 -4.99426 0"; + surface = "0.5 0.5 -0.5 0.5 -4.01359 0 0"; + surface = "0.5 -0.5 0.5 0.5 4.01359 0 0"; + }; + new MeshRoad() { + topMaterial = "DefaultRoadMaterialTop"; + bottomMaterial = "DefaultRoadMaterialOther"; + sideMaterial = "DefaultRoadMaterialOther"; + textureLength = "5"; + breakAngle = "3"; + widthSubdivisions = "0"; + position = "46.4415 52.221 236.031"; + rotation = "1 0 0 0"; + scale = "1 1 1"; + canSave = "1"; + canSaveDynamicFields = "1"; + + Node = "46.4415 52.221 236.031 10 5 0 0 1"; + Node = "21.9538 4.57701 242.652 10 5 0 0 1"; + Node = "1.52535 -12.3952 243.532 10 5 0 0 1"; + Node = "-47.4526 30.2515 249.092 10 5 0 0 1"; + Node = "-26.0405 51.9559 255.77 10 5 0 0 1"; + }; }; //--- OBJECT WRITE END --- diff --git a/Templates/Full/game/levels/Outpost.mis b/Templates/Full/game/levels/Outpost.mis index 6a7045e30..8b1cda54b 100644 --- a/Templates/Full/game/levels/Outpost.mis +++ b/Templates/Full/game/levels/Outpost.mis @@ -1,5 +1,5 @@ //--- OBJECT WRITE BEGIN --- -new SimGroup(MissionGroup) { +new Scene(OutpostLevel) { canSave = "1"; canSaveDynamicFields = "1"; enabled = "1"; diff --git a/Templates/Full/game/scripts/server/gameCore.cs b/Templates/Full/game/scripts/server/gameCore.cs index bb7aed714..9917d1048 100644 --- a/Templates/Full/game/scripts/server/gameCore.cs +++ b/Templates/Full/game/scripts/server/gameCore.cs @@ -134,12 +134,12 @@ package GameCore // to caching mission lighting. $missionCRC = getFileCRC( %file ); - // Exec the mission. The MissionGroup (loaded components) is added to the ServerGroup + // Exec the mission. The Scene (loaded components) is added to the ServerGroup exec(%file); - if( !isObject(MissionGroup) ) + if( !isObject(getRootScene()) ) { - $Server::LoadFailMsg = "No 'MissionGroup' found in mission \"" @ %file @ "\"."; + $Server::LoadFailMsg = "No Scene found in mission \"" @ %file @ "\"."; } } diff --git a/Templates/Full/game/scripts/server/item.cs b/Templates/Full/game/scripts/server/item.cs index f4f355386..ad6859b9e 100644 --- a/Templates/Full/game/scripts/server/item.cs +++ b/Templates/Full/game/scripts/server/item.cs @@ -92,7 +92,7 @@ function ItemData::onThrow(%this, %user, %amount) rotation = "0 0 1 "@ (getRandom() * 360); count = %amount; }; - MissionGroup.add(%obj); + getRootScene().add(%obj); %obj.schedulePop(); return %obj; } diff --git a/Templates/Full/game/scripts/server/turret.cs b/Templates/Full/game/scripts/server/turret.cs index 19b19ed22..be43d7043 100644 --- a/Templates/Full/game/scripts/server/turret.cs +++ b/Templates/Full/game/scripts/server/turret.cs @@ -87,7 +87,7 @@ function TurretShapeData::onRemove(%this, %obj) } // This is on MissionGroup so it doesn't happen when the mission has ended -function MissionGroup::respawnTurret(%this, %datablock, %className, %transform, %static, %respawn) +function Scene::respawnTurret(%this, %datablock, %className, %transform, %static, %respawn) { %turret = new (%className)() { @@ -97,7 +97,7 @@ function MissionGroup::respawnTurret(%this, %datablock, %className, %transform, }; %turret.setTransform(%transform); - MissionGroup.add(%turret); + getRootScene().add(%turret); return %turret; } @@ -149,7 +149,7 @@ function TurretShapeData::onDestroyed(%this, %obj, %lastState) if (%obj.doRespawn()) { - MissionGroup.schedule($TurretShape::RespawnTime, "respawnTurret", %this, %obj.getClassName(), %obj.getTransform(), true, true); + getRootScene().schedule($TurretShape::RespawnTime, "respawnTurret", %this, %obj.getClassName(), %obj.getTransform(), true, true); } } @@ -331,7 +331,7 @@ function AITurretShapeData::onThrow(%this, %user, %amount) client = %user.client; isAiControlled = true; }; - MissionGroup.add(%obj); + getRootScene().add(%obj); // Let the turret know that we're a firend %obj.addToIgnoreList(%user); diff --git a/Templates/Full/game/shaders/.gitignore b/Templates/Full/game/shaders/.gitignore deleted file mode 100644 index 5baa4d384..000000000 --- a/Templates/Full/game/shaders/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/procedural/ diff --git a/Templates/Full/game/shaders/procedural/.gitignore b/Templates/Full/game/shaders/procedural/.gitignore new file mode 100644 index 000000000..013488d4e --- /dev/null +++ b/Templates/Full/game/shaders/procedural/.gitignore @@ -0,0 +1,2 @@ +*.hlsl +*.glsl \ No newline at end of file diff --git a/Templates/Full/game/tools/convexEditor/main.cs b/Templates/Full/game/tools/convexEditor/main.cs index 496140cd4..54de25d02 100644 --- a/Templates/Full/game/tools/convexEditor/main.cs +++ b/Templates/Full/game/tools/convexEditor/main.cs @@ -189,7 +189,7 @@ function ConvexEditorPlugin::onSaveMission( %this, %missionFile ) { if( ConvexEditorGui.isDirty ) { - MissionGroup.save( %missionFile ); + getRootScene().save( %missionFile ); ConvexEditorGui.isDirty = false; } } diff --git a/Templates/Full/game/tools/gui/colladaImport.ed.gui b/Templates/Full/game/tools/gui/colladaImport.ed.gui index 30838c76d..b83c1e477 100644 --- a/Templates/Full/game/tools/gui/colladaImport.ed.gui +++ b/Templates/Full/game/tools/gui/colladaImport.ed.gui @@ -1584,7 +1584,7 @@ function ColladaImportDlg::onOK(%this) function ColladaImportDlg::loadLights(%this) { // Get the ID of the last object added - %obj = MissionGroup.getObject(MissionGroup.getCount()-1); + %obj = getRootScene().getObject(getRootScene().getCount()-1); // Create a new SimGroup to hold the model and lights %group = new SimGroup(); @@ -1596,7 +1596,7 @@ function ColladaImportDlg::loadLights(%this) { %group.add(%obj); %group.bringToFront(%obj); - MissionGroup.add(%group); + getRootScene().add(%group); if (EditorTree.isVisible()) { EditorTree.removeItem(EditorTree.findItemByObjectId(%obj)); diff --git a/Templates/Full/game/tools/levels/BlankRoom.mis b/Templates/Full/game/tools/levels/BlankRoom.mis index 5ca65ed5a..bbef5d24f 100644 --- a/Templates/Full/game/tools/levels/BlankRoom.mis +++ b/Templates/Full/game/tools/levels/BlankRoom.mis @@ -1,5 +1,5 @@ //--- OBJECT WRITE BEGIN --- -new SimGroup(MissionGroup) { +new Scene(EditorTemplateLevel) { canSaveDynamicFields = "1"; cdTrack = "2"; CTF_scoreLimit = "5"; diff --git a/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs b/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs index b4e85229f..5d4a9a7ba 100644 --- a/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs +++ b/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs @@ -1051,7 +1051,7 @@ function MaterialEditorGui::updateActiveMaterialName(%this, %name) // Some objects (ConvexShape, DecalRoad etc) reference Materials by name => need // to find and update all these references so they don't break when we rename the // Material. - MaterialEditorGui.updateMaterialReferences( MissionGroup, %action.oldName, %action.newName ); + MaterialEditorGui.updateMaterialReferences( getRootScene(), %action.oldName, %action.newName ); } function MaterialEditorGui::updateMaterialReferences( %this, %obj, %oldName, %newName ) diff --git a/Templates/Full/game/tools/materialEditor/scripts/materialEditorUndo.ed.cs b/Templates/Full/game/tools/materialEditor/scripts/materialEditorUndo.ed.cs index 184f02ce4..2adf419ca 100644 --- a/Templates/Full/game/tools/materialEditor/scripts/materialEditorUndo.ed.cs +++ b/Templates/Full/game/tools/materialEditor/scripts/materialEditorUndo.ed.cs @@ -187,7 +187,7 @@ function ActionUpdateActiveMaterialAnimationFlags::undo(%this) function ActionUpdateActiveMaterialName::redo(%this) { %this.material.setName(%this.newName); - MaterialEditorGui.updateMaterialReferences( MissionGroup, %this.oldName, %this.newName ); + MaterialEditorGui.updateMaterialReferences( getRootScene(), %this.oldName, %this.newName ); if( MaterialEditorPreviewWindow.isVisible() && MaterialEditorGui.currentMaterial == %this.material ) { @@ -199,7 +199,7 @@ function ActionUpdateActiveMaterialName::redo(%this) function ActionUpdateActiveMaterialName::undo(%this) { %this.material.setName(%this.oldName); - MaterialEditorGui.updateMaterialReferences( MissionGroup, %this.newName, %this.oldName ); + MaterialEditorGui.updateMaterialReferences( getRootScene(), %this.newName, %this.oldName ); if( MaterialEditorPreviewWindow.isVisible() && MaterialEditorGui.currentMaterial == %this.material ) { diff --git a/Templates/Full/game/tools/meshRoadEditor/main.cs b/Templates/Full/game/tools/meshRoadEditor/main.cs index d101e50b0..5b76bcd63 100644 --- a/Templates/Full/game/tools/meshRoadEditor/main.cs +++ b/Templates/Full/game/tools/meshRoadEditor/main.cs @@ -164,7 +164,7 @@ function MeshRoadEditorPlugin::onSaveMission( %this, %missionFile ) { if( MeshRoadEditorGui.isDirty ) { - MissionGroup.save( %missionFile ); + getRootScene().save( %missionFile ); MeshRoadEditorGui.isDirty = false; } } diff --git a/Templates/Full/game/tools/missionAreaEditor/main.cs b/Templates/Full/game/tools/missionAreaEditor/main.cs index 000197bc6..ebb62bb9c 100644 --- a/Templates/Full/game/tools/missionAreaEditor/main.cs +++ b/Templates/Full/game/tools/missionAreaEditor/main.cs @@ -114,7 +114,7 @@ function MissionAreaEditorPlugin::createNewMissionArea(%this) %newMissionArea = new MissionArea(); %newMissionArea.area = "-256 -256 512 512"; - MissionGroup.add(%newMissionArea); + getRootScene().add(%newMissionArea); EditorGui.setEditor(MissionAreaEditorPlugin); diff --git a/Templates/Full/game/tools/navEditor/CreateNewNavMeshDlg.gui b/Templates/Full/game/tools/navEditor/CreateNewNavMeshDlg.gui index 755bce30a..af39140c9 100644 --- a/Templates/Full/game/tools/navEditor/CreateNewNavMeshDlg.gui +++ b/Templates/Full/game/tools/navEditor/CreateNewNavMeshDlg.gui @@ -354,13 +354,13 @@ function CreateNewNavMeshDlg::create(%this) if(MeshMissionBounds.isStateOn()) { - if(!isObject(MissionGroup)) + if(!isObject(getRootScene())) { - MessageBoxOk("Error", "You must have a MissionGroup to use the mission bounds function."); + MessageBoxOk("Error", "You must have a Scene to use the mission bounds function."); return; } // Get maximum extents of all objects. - %box = MissionBoundsExtents(MissionGroup); + %box = MissionBoundsExtents(getRootScene()); %pos = GetBoxCenter(%box); %scale = (GetWord(%box, 3) - GetWord(%box, 0)) / 2 + 5 SPC (GetWord(%box, 4) - GetWord(%box, 1)) / 2 + 5 @@ -380,7 +380,7 @@ function CreateNewNavMeshDlg::create(%this) scale = %this-->MeshScale.getText(); }; } - MissionGroup.add(%mesh); + getRootScene().add(%mesh); NavEditorGui.selectObject(%mesh); Canvas.popDialog(CreateNewNavMeshDlg); diff --git a/Templates/Full/game/tools/navEditor/main.cs b/Templates/Full/game/tools/navEditor/main.cs index 6af3abf19..2a742bf51 100644 --- a/Templates/Full/game/tools/navEditor/main.cs +++ b/Templates/Full/game/tools/navEditor/main.cs @@ -205,7 +205,7 @@ function NavEditorPlugin::onSaveMission(%this, %missionFile) { if(NavEditorGui.isDirty) { - MissionGroup.save(%missionFile); + getRootScene().save(%missionFile); NavEditorGui.isDirty = false; } } diff --git a/Templates/Full/game/tools/riverEditor/main.cs b/Templates/Full/game/tools/riverEditor/main.cs index eafb3c3c8..1c6ce72ed 100644 --- a/Templates/Full/game/tools/riverEditor/main.cs +++ b/Templates/Full/game/tools/riverEditor/main.cs @@ -178,7 +178,7 @@ function RiverEditorPlugin::onSaveMission( %this, %missionFile ) { if( RiverEditorGui.isDirty ) { - MissionGroup.save( %missionFile ); + getRootScene().save( %missionFile ); RiverEditorGui.isDirty = false; } } diff --git a/Templates/Full/game/tools/roadEditor/main.cs b/Templates/Full/game/tools/roadEditor/main.cs index f45823670..9b2f70f56 100644 --- a/Templates/Full/game/tools/roadEditor/main.cs +++ b/Templates/Full/game/tools/roadEditor/main.cs @@ -156,7 +156,7 @@ function RoadEditorPlugin::onSaveMission( %this, %missionFile ) { if( RoadEditorGui.isDirty ) { - MissionGroup.save( %missionFile ); + getRootScene().save( %missionFile ); RoadEditorGui.isDirty = false; } } diff --git a/Templates/Full/game/tools/shapeEditor/main.cs b/Templates/Full/game/tools/shapeEditor/main.cs index 721313e95..1c021cb01 100644 --- a/Templates/Full/game/tools/shapeEditor/main.cs +++ b/Templates/Full/game/tools/shapeEditor/main.cs @@ -168,7 +168,7 @@ function ShapeEditorPlugin::open(%this, %filename) ShapeEdNodes-->worldTransform.setStateOn(1); // Initialise and show the shape editor - ShapeEdShapeTreeView.open(MissionGroup); + ShapeEdShapeTreeView.open(getRootScene()); ShapeEdShapeTreeView.buildVisibleTree(true); ShapeEdPreviewGui.setVisible(true); diff --git a/Templates/Full/game/tools/worldEditor/gui/TimeAdjustGui.ed.gui b/Templates/Full/game/tools/worldEditor/gui/TimeAdjustGui.ed.gui index 8eaf11d4c..9f36921ad 100644 --- a/Templates/Full/game/tools/worldEditor/gui/TimeAdjustGui.ed.gui +++ b/Templates/Full/game/tools/worldEditor/gui/TimeAdjustGui.ed.gui @@ -184,11 +184,11 @@ function TimeAdjustSliderCtrl::onAction(%this) if ( !isObject( %this.tod ) ) { - if ( isObject( MissionGroup ) ) + if ( isObject( getRootScene() ) ) { - for ( %i = 0; %i < MissionGroup.getCount(); %i++ ) + for ( %i = 0; %i < getRootScene().getCount(); %i++ ) { - %obj = MissionGroup.getObject( %i ); + %obj = getRootScene().getObject( %i ); if ( %obj.getClassName() $= "TimeOfDay" ) { diff --git a/Templates/Full/game/tools/worldEditor/gui/objectBuilderGui.ed.gui b/Templates/Full/game/tools/worldEditor/gui/objectBuilderGui.ed.gui index 74f1200c6..a1bc87507 100644 --- a/Templates/Full/game/tools/worldEditor/gui/objectBuilderGui.ed.gui +++ b/Templates/Full/game/tools/worldEditor/gui/objectBuilderGui.ed.gui @@ -947,10 +947,10 @@ function ObjectBuilderGui::buildPlayerDropPoint(%this) %this.addField("spawnClass", "TypeString", "Spawn Class", "Player"); %this.addField("spawnDatablock", "TypeDataBlock", "Spawn Data", "PlayerData DefaultPlayerData"); - if( EWCreatorWindow.objectGroup.getID() == MissionGroup.getID() ) + if( EWCreatorWindow.objectGroup.getID() == getRootScene().getID() ) { if( !isObject("PlayerDropPoints") ) - MissionGroup.add( new SimGroup("PlayerDropPoints") ); + getRootScene().add( new SimGroup("PlayerDropPoints") ); %this.objectGroup = "PlayerDropPoints"; } @@ -967,10 +967,10 @@ function ObjectBuilderGui::buildObserverDropPoint(%this) %this.addField("spawnClass", "TypeString", "Spawn Class", "Camera"); %this.addField("spawnDatablock", "TypeDataBlock", "Spawn Data", "CameraData Observer"); - if( EWCreatorWindow.objectGroup.getID() == MissionGroup.getID() ) + if( EWCreatorWindow.objectGroup.getID() == getRootScene().getID() ) { if( !isObject("ObserverDropPoints") ) - MissionGroup.add( new SimGroup("ObserverDropPoints") ); + getRootScene().add( new SimGroup("ObserverDropPoints") ); %this.objectGroup = "ObserverDropPoints"; } diff --git a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs index 329846cb5..f8bb433ff 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -645,7 +645,7 @@ function EditorGui::addCameraBookmark( %this, %name ) if( !isObject(CameraBookmarks) ) { %grp = new SimGroup(CameraBookmarks); - MissionGroup.add(%grp); + getRootScene().add(%grp); } CameraBookmarks.add( %obj ); @@ -843,12 +843,17 @@ function EditorGui::syncCameraGui( %this ) function WorldEditorPlugin::onActivated( %this ) { + if(!isObject(Scenes)) + $scenesRootGroup = new SimGroup(Scenes); + + $scenesRootGroup.add(getRootScene()); + EditorGui.bringToFront( EWorldEditor ); EWorldEditor.setVisible(true); EditorGui.menuBar.insert( EditorGui.worldMenu, EditorGui.menuBar.dynamicItemInsertPos ); EWorldEditor.makeFirstResponder(true); - EditorTree.open(MissionGroup,true); - EWCreatorWindow.setNewObjectGroup(MissionGroup); + EditorTree.open($scenesRootGroup,true); + EWCreatorWindow.setNewObjectGroup(getRootScene()); EWorldEditor.syncGui(); @@ -1472,7 +1477,7 @@ function EditorTree::onDeleteObject( %this, %object ) return true; if( %object == EWCreatorWindow.objectGroup ) - EWCreatorWindow.setNewObjectGroup( MissionGroup ); + EWCreatorWindow.setNewObjectGroup( getRootScene() ); // Append it to our list. %this.undoDeleteList = %this.undoDeleteList TAB %object; @@ -1604,6 +1609,13 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj ) { %popup.item[ 0 ] = "Add Camera Bookmark" TAB "" TAB "EditorGui.addCameraBookmarkByGui();"; } + else if( %obj.isMemberOfClass( "Scene" )) + { + %popup.item[ 0 ] = "Set as Active Scene" TAB "" TAB "EditorTree.showItemRenameCtrl( EditorTree.findItemByObjectId(" @ %popup.object @ ") );"; + %popup.item[ 1 ] = "Delete" TAB "" TAB "EWorldEditor.deleteMissionObject(" @ %popup.object @ ");"; + %popup.item[ 2 ] = "Inspect" TAB "" TAB "inspectObject(" @ %popup.object @ ");"; + %popup.item[ 3 ] = "-"; + } else { %popup.object = %obj; @@ -1681,8 +1693,8 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj ) if( %haveObjectEntries ) { - %popup.enableItem( 0, %obj.isNameChangeAllowed() && %obj.getName() !$= "MissionGroup" ); - %popup.enableItem( 1, %obj.getName() !$= "MissionGroup" ); + %popup.enableItem( 0, %obj.isNameChangeAllowed() && %obj.getName() !$= getRootScene() ); + %popup.enableItem( 1, %obj.getName() !$= getRootScene() ); if( %haveLockAndHideEntries ) { @@ -2034,21 +2046,21 @@ function EWorldEditor::syncToolPalette( %this ) function EWorldEditor::addSimGroup( %this, %groupCurrentSelection ) { %activeSelection = %this.getActiveSelection(); - if ( %activeSelection.getObjectIndex( MissionGroup ) != -1 ) + if ( %activeSelection.getObjectIndex( getRootScene() ) != -1 ) { - MessageBoxOK( "Error", "Cannot add MissionGroup to a new SimGroup" ); + MessageBoxOK( "Error", "Cannot add Scene to a new SimGroup" ); return; } // Find our parent. - %parent = MissionGroup; + %parent = getRootScene(); if( !%groupCurrentSelection && isObject( %activeSelection ) && %activeSelection.getCount() > 0 ) { %firstSelectedObject = %activeSelection.getObject( 0 ); if( %firstSelectedObject.isMemberOfClass( "SimGroup" ) ) %parent = %firstSelectedObject; - else if( %firstSelectedObject.getId() != MissionGroup.getId() ) + else if( %firstSelectedObject.getId() != getRootScene().getId() ) %parent = %firstSelectedObject.parentGroup; } diff --git a/Templates/Full/game/tools/worldEditor/scripts/SelectObjectsWindow.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/SelectObjectsWindow.ed.cs index 2c436f74f..f6c11b41b 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/SelectObjectsWindow.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/SelectObjectsWindow.ed.cs @@ -40,7 +40,7 @@ function ESelectObjectsWindow::toggleVisibility( %this ) /// to start searching for objects. function ESelectObjectsWindow::getRootGroup( %this ) { - return MissionGroup; + return getRootScene(); } //--------------------------------------------------------------------------------------------- diff --git a/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs index 006031668..1271bf33d 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs @@ -179,7 +179,7 @@ function EWCreatorWindow::createStatic( %this, %file ) return; if( !isObject(%this.objectGroup) ) - %this.setNewObjectGroup( MissionGroup ); + %this.setNewObjectGroup( getRootScene() ); %objId = new TSStatic() { @@ -197,7 +197,7 @@ function EWCreatorWindow::createPrefab( %this, %file ) return; if( !isObject(%this.objectGroup) ) - %this.setNewObjectGroup( MissionGroup ); + %this.setNewObjectGroup( getRootScene() ); %objId = new Prefab() { @@ -215,7 +215,7 @@ function EWCreatorWindow::createObject( %this, %cmd ) return; if( !isObject(%this.objectGroup) ) - %this.setNewObjectGroup( MissionGroup ); + %this.setNewObjectGroup( getRootScene() ); pushInstantGroup(); %objId = eval(%cmd); diff --git a/Templates/Full/game/tools/worldEditor/scripts/editors/worldEditor.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/editors/worldEditor.ed.cs index eb89d1a30..1258fe8fa 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/editors/worldEditor.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/editors/worldEditor.ed.cs @@ -124,6 +124,12 @@ function WorldEditor::onSelectionCentroidChanged( %this ) Inspector.refresh(); } +function WorldEditor::setSceneAsDirty(%this) +{ + EWorldEditor.isDirty = true; + +} + ////////////////////////////////////////////////////////////////////////// function WorldEditor::init(%this) @@ -198,7 +204,7 @@ function WorldEditor::export(%this) function WorldEditor::doExport(%this, %file) { - missionGroup.save("~/editor/" @ %file, true); + getRootScene().save("~/editor/" @ %file, true); } function WorldEditor::import(%this) diff --git a/Templates/Full/game/tools/worldEditor/scripts/menuHandlers.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/menuHandlers.ed.cs index f476ccaeb..9b3518469 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/menuHandlers.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/menuHandlers.ed.cs @@ -272,7 +272,7 @@ function EditorSaveMission() // now write the terrain and mission files out: if(EWorldEditor.isDirty || ETerrainEditor.isMissionDirty) - MissionGroup.save($Server::MissionFile); + getRootScene().save($Server::MissionFile); if(ETerrainEditor.isDirty) { // Find all of the terrain files @@ -483,6 +483,21 @@ function EditorOpenMission(%filename) } } +function EditorOpenSceneAppend(%levelAsset) +{ + //Load the asset's level file + exec(%levelAsset.levelFile); + + //We'll assume the scene name and assetname are the same for now + %sceneName = %levelAsset.AssetName; + %scene = nameToID(%sceneName); + if(isObject(%scene)) + { + //Append it to our scene heirarchy + $scenesRootGroup.add(%scene); + } +} + function EditorExportToCollada() { From ae8bc232a25257576fcdfe650a9b63101dd8f76a Mon Sep 17 00:00:00 2001 From: Azaezel Date: Thu, 4 Apr 2019 20:56:57 -0500 Subject: [PATCH 74/75] surpress nonrendered lights killoff method till we've time to revisit that --- Engine/source/lighting/lightManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/lighting/lightManager.cpp b/Engine/source/lighting/lightManager.cpp index 3bb71fd97..58081dae9 100644 --- a/Engine/source/lighting/lightManager.cpp +++ b/Engine/source/lighting/lightManager.cpp @@ -226,7 +226,7 @@ void LightManager::registerGlobalLights( const Frustum *frustum, bool staticLigh { // Cull the lights using the frustum. getSceneManager()->getContainer()->findObjectList( *frustum, lightMask, &activeLights ); - + /* for (U32 i = 0; i < activeLights.size(); ++i) { if (!getSceneManager()->mRenderedObjectsList.contains(activeLights[i])) @@ -235,7 +235,7 @@ void LightManager::registerGlobalLights( const Frustum *frustum, bool staticLigh --i; } } - + */ // Store the culling position for sun placement // later... see setSpecialLight. mCullPos = frustum->getPosition(); From 2d2f66f3882395652756b8f34d807324795fa5b1 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 8 Apr 2019 10:20:13 -0500 Subject: [PATCH 75/75] Modification of #2145 Original PR broke class-type visibility toggles in the editor, so this adjustment on the same setup keeps the optimized path, but also enables the original class-based render toggle if the editor is open. (Also adds TORQUE_TOOLS check to have it be even leaner if the project doesn't have tool support at all) --- Engine/source/scene/sceneObject.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Engine/source/scene/sceneObject.cpp b/Engine/source/scene/sceneObject.cpp index ff7b6496c..354440fd2 100644 --- a/Engine/source/scene/sceneObject.cpp +++ b/Engine/source/scene/sceneObject.cpp @@ -93,6 +93,9 @@ ConsoleDocClass( SceneObject, "@ingroup gameObjects\n" ); +#ifdef TORQUE_TOOLS +extern bool gEditingMission; +#endif Signal< void( SceneObject* ) > SceneObject::smSceneObjectAdd; Signal< void( SceneObject* ) > SceneObject::smSceneObjectRemove; @@ -763,8 +766,14 @@ void SceneObject::onCameraScopeQuery( NetConnection* connection, CameraScopeQuer bool SceneObject::isRenderEnabled() const { - AbstractClassRep *classRep = getClassRep(); - return ( mObjectFlags.test( RenderEnabledFlag ) && classRep->isRenderEnabled() ); +#ifdef TORQUE_TOOLS + if (gEditingMission) + { + AbstractClassRep *classRep = getClassRep(); + return (mObjectFlags.test(RenderEnabledFlag) && classRep->isRenderEnabled()); + } +#endif + return (mObjectFlags.test(RenderEnabledFlag)); } //-----------------------------------------------------------------------------