From a5e58add1210258eb7e563b7e088528dc244082e Mon Sep 17 00:00:00 2001 From: Marisa the Magician Date: Sun, 16 Mar 2025 15:50:00 +0100 Subject: [PATCH] Remove Gutamatics, use bespoke projection code from UT99 modding days. --- credits.txt | 3 +- language.def_menu | 2 +- language.es_menu | 2 +- language.version | 4 +- readme.txt | 6 +- zscript.txt | 2 - zscript/handler/swwm_handler_crosshair.zsc | 28 +- zscript/handler/swwm_handler_debugrender.zsc | 36 +- zscript/hud/swwm_hud_target.zsc | 19 +- zscript/menu/swwm_credits.zsc | 2 +- zscript/swwm_Gutamatics/GlobalMaths.zsc | 173 ---------- zscript/swwm_Gutamatics/Include.zsc | 5 - zscript/swwm_Gutamatics/LICENSE.md | 7 - zscript/swwm_Gutamatics/Matrix.zsc | 335 ------------------- zscript/swwm_Gutamatics/Matrix4.zsc | 319 ------------------ zscript/swwm_Gutamatics/Quaternion.zsc | 275 --------------- zscript/swwm_Gutamatics/VectorUtil.zsc | 29 -- zscript/utility/swwm_utility_math.zsc | 68 +++- zscript/weapons/swwm_blazeit.zsc | 2 +- 19 files changed, 102 insertions(+), 1215 deletions(-) delete mode 100644 zscript/swwm_Gutamatics/GlobalMaths.zsc delete mode 100644 zscript/swwm_Gutamatics/Include.zsc delete mode 100644 zscript/swwm_Gutamatics/LICENSE.md delete mode 100644 zscript/swwm_Gutamatics/Matrix.zsc delete mode 100644 zscript/swwm_Gutamatics/Matrix4.zsc delete mode 100644 zscript/swwm_Gutamatics/Quaternion.zsc delete mode 100644 zscript/swwm_Gutamatics/VectorUtil.zsc diff --git a/credits.txt b/credits.txt index 6076459e4..e78c3a0ee 100644 --- a/credits.txt +++ b/credits.txt @@ -17,8 +17,7 @@ Most of the work here is original, but there are some notable exceptions: * Dark Souls 3 - In addition, a whole lot of stock sounds and internet meme sounds have also been used. - Some sprites and sounds are taken from (shareware) Wolfenstein 3D. - - This mod uses Gutamatics, by Gutawer. Big thanks. - - This mod uses Mikolah's ZPolyobject library. Many thanks too. + - This mod uses Mikolah's ZPolyobject library. Many thanks. - Title theme, "Traumatic State", by Teque (which a lot of people just know as "the AS-Golgotha music"). - Intermission theme, "Dragony", also by Teque (very comfy music considering the rest of his repertoire). - Startup/credits theme, "Hidden Tune #242", also by Teque too (super comfy music, ideal for this use). diff --git a/language.def_menu b/language.def_menu index 9adb7842e..eccb567ef 100644 --- a/language.def_menu +++ b/language.def_menu @@ -348,11 +348,11 @@ SWWM_CTHANK = "Special Thanks:"; SWWM_CDRAGON2 = "For being a good pet dragon who cares about me. No matter what, our love will stay strong."; SWWM_CVYOLETTE2 = "For your love and support during my hardest times. I can't thank you enough."; SWWM_CLUCY2 = "For the Tewi font, which I've used for many many years. I hope you're doing well, wherever you are."; -SWWM_CGUTA2 = "For the Gutamatics library."; SWWM_CMIKO2 = "For the VERY useful ZPolyobject library."; SWWM_CKEKS2 = "For assistance with exception handling code, and also for being such a cool Touhou nerd."; SWWM_CZN2 = "For slope alignment code, and to Nash also for being a cool smart cactus dude."; SWWM_CBOUNCY2 = "For lots of help with testing and for letting me rant about lore for hours and being there to listen along. You're a wonderful friend."; +SWWM_CSPY2 = "For your deep love towards the mod and its characters and lore. Oh, and a bit of help with SFX stuff, too. Bless you, friend."; SWWM_CSLEDGE2 = "For being great buds, not just for me but for all of us. Your support and encouragement are something I value a lot, and I can't thank you enough."; SWWM_CINSP1 = "Combine Kegan, HyperUltra64, Yholl and friends"; SWWM_CINSP2 = "For inspiration and also for being really cool people. Bless all of you, keep being amazing."; diff --git a/language.es_menu b/language.es_menu index b328bdbe2..a98178777 100644 --- a/language.es_menu +++ b/language.es_menu @@ -304,11 +304,11 @@ SWWM_CTHANK = "Agradecimientos Especiales:"; SWWM_CDRAGON2 = "Por ser un buen dragón mascota que se preocupa por mí. A pesar de todo, nuestro amor permanecerá fuerte."; SWWM_CVYOLETTE2 = "Por tu cariño y apoyo durante mis peores momentos. No me sobran formas de agradecértelo."; SWWM_CLUCY2 = "Por la fuente Tewi, que he seguido usando todos estos años. Espero que estés donde estés, te encuentres bien."; -SWWM_CGUTA2 = "Por la librería de Gutamatics."; SWWM_CMIKO2 = "Por la MUY útil librería de ZPolyobject."; SWWM_CKEKS2 = "Por asistencia con el código de manejo de excepciones, y también por ser un friki tan guay de Touhou."; SWWM_CZN2 = "Por el código para alineación con superficies inclinadas, y a Nash además por ser un molón tío cactus listo."; SWWM_CBOUNCY2 = "Por tu gran ayuda con el testeo y por dejar que suelte lore durante horas y estar ahí para escuchar. Eres un amigo maravilloso."; +SWWM_CSPY2 = "Por tu profundo amor por el mod y sus personajes y lore. Oh, y por una ayudita con temas de sonido, también. Bendito seas, amigo."; SWWM_CSLEDGE2 = "Por ser grandes colegas, no solo conmigo si no con todos nosotros. Vuestro apoyo y ánimo es algo que valoro muchísimo, y no hay forma de agradecéroslo suficientemente."; SWWM_CINSP1 = "Combine Kegan, HyperUltra64, Yholl y amigos"; SWWM_CINSP2 = "Por servir de inspiración y por ser gente muy molona. Benditos seáis todos, seguid siendo fenomenales."; diff --git a/language.version b/language.version index 1ee013ed6..509e974ab 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r1201 \cu(vie 14 mar 2025 23:57:32 CET)\c-"; -SWWM_SHORTVER="\cw1.3pre r1201 \cu(2025-03-14 23:57:32)\c-"; +SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r1203 \cu(dom 16 mar 2025 15:50:48 CET)\c-"; +SWWM_SHORTVER="\cw1.3pre r1203 \cu(2025-03-16 15:50:48)\c-"; diff --git a/readme.txt b/readme.txt index 7f0b462f6..bf8965fd1 100644 --- a/readme.txt +++ b/readme.txt @@ -443,8 +443,10 @@ CptSledge and Bunray for making me dive deep into the Doom Modiverse™ and its interconnected lore and worldbuilding. You're a very fine pair of cool buds. Bouncy for being one of the few friends who can just stand there and listen to me rant about lore for several hours straight. Many thanks. -Gutawer and Mikolah for the Gutamatics and ZPolyobject libraries, respectively, -which have made certain complicated tasks much easier. +a1337spy for the very enthusiastic fanboyism about the mod, its characters and +lore. Oh, and for a little help with some SFX work, too. +Mikolah for the ZPolyobject library, which has made dealing with those things +far easier of a task. KeksDose for being another ZScript mad genius and teaching me a nifty trick to fuck around with VM aborts (which I then perfected). ZZYZX and Nash for a handy piece of code to align stuff to slopes. The math's diff --git a/zscript.txt b/zscript.txt index df71e1d32..f47a1102d 100644 --- a/zscript.txt +++ b/zscript.txt @@ -7,8 +7,6 @@ version "4.14.1" included from here, with the exception of any third party libraries */ -// Gutamatics -#include "zscript/swwm_Gutamatics/Include.zsc" // ZPolyobject #include "zscript/swwm_Polyobjects/Polyobjects.zs" // utility code diff --git a/zscript/handler/swwm_handler_crosshair.zsc b/zscript/handler/swwm_handler_crosshair.zsc index dacd69251..ebcb6fabe 100644 --- a/zscript/handler/swwm_handler_crosshair.zsc +++ b/zscript/handler/swwm_handler_crosshair.zsc @@ -27,8 +27,8 @@ extend Class SWWMHandler transient ui int numcrosshairs; // how many crosshairs the current weapon has transient ui Vector3 tpos[MAX_CROSSHAIRS]; // current trace positions in world space transient ui Color tcol[MAX_CROSSHAIRS]; // current crosshair colors - transient ui SWWMProjectionData tprojdata; // cached Gutamatics projection data - transient ui Vector3 lagtndc[MAX_CROSSHAIRS]; // "lagged" NDC for crosshairs + transient ui SWWMProjectionData tprojdata; // cached Fast projection data + transient ui Vector2 lagvpos[MAX_CROSSHAIRS]; // "lagged" clip pos for crosshairs transient ui bool tactive[MAX_CROSSHAIRS]; // denotes that the crosshair is "active" for drawing transient ui double prevframe; // previous frame timestamp @@ -128,6 +128,8 @@ extend Class SWWMHandler if ( int(ts.x)%2 ) oddfix.x = -floor(sz/2.)+1.; if ( int(ts.y)%2 ) oddfix.y = -floor(sz/2.)+1.; SWWMUtility.PrepareProjData(tprojdata,e.ViewPos,e.ViewAngle,e.ViewPitch,e.ViewRoll,players[consoleplayer].fov); + int cliptop = tprojdata.viewy, clipbottom = tprojdata.viewy+tprojdata.viewh, + clipleft = tprojdata.viewx, clipright = tprojdata.viewx+tprojdata.vieww; Vector2 actpos[MAX_CROSSHAIRS]; for ( int i=0; i= 1. ) continue; + // invalid or behind view, skip + if ( ndc.z <= 0. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(tprojdata,ndc); - if ( !prevframe ) lagtndc[i] = ndc; - if ( lagtndc[i].z >= 1. ) continue; - Vector2 oldvpos = SWWMUtility.NDCToViewport(tprojdata,lagtndc[i]); - lagtndc[i] = SWWMUtility.LerpVector3(lagtndc[i],ndc,theta); - if ( lagtndc[i].z >= 1. ) continue; - Vector2 lagvpos = SWWMUtility.NDCToViewport(tprojdata,lagtndc[i]); + if ( !prevframe ) lagvpos[i] = vpos; + Vector2 oldvpos = lagvpos[i]; + lagvpos[i] = SWWMUtility.LerpVector2(lagvpos[i],vpos,theta); if ( !tactive[i] ) continue; // draw - int streak = int(max(abs(oldvpos.x-lagvpos.x),abs(oldvpos.y-lagvpos.y))); + int streak = int(max(abs(oldvpos.x-lagvpos[i].x),abs(oldvpos.y-lagvpos[i].y))); double alph = 1.; - if ( i < numcrosshairs ) actpos[i] = lagvpos; + if ( i < numcrosshairs ) actpos[i] = lagvpos[i]; else { // unused crosshairs must "linger" until they merge with the ones that are drawn int j = (i-numcrosshairs)%numcrosshairs; - double dist = (lagvpos-actpos[j]).length(); + double dist = (lagvpos[i]-actpos[j]).length(); if ( (streak <= 0) && (dist < 1.) ) tactive[i] = false; alph = clamp(dist/max(2,streak+2),0.,1.); // this should make the merge less jarring } - for ( int i=0; i 1.) && (b.z > 1.) ) return; - if ( (a.z == -double.infinity) || (b.z == -double.infinity) ) return; // how??? + Vector3 a = SWWMUtility.ProjectPoint(projdata,e.viewpos+level.Vec3Diff(e.viewpos,apos),false), + b = SWWMUtility.ProjectPoint(projdata,e.viewpos+level.Vec3Diff(e.viewpos,bpos),false); + // both points are behind the screen + if ( (a.z <= 0.) && (b.z < 0.) ) return; + // at least one point is invalid + if ( (a.z == 0.) || (b.z == 0.) ) return; double da, db, s; Vector3 p; - da = a dot (0.,0.,-1.)-1.; - db = b dot (0.,0.,-1.)-1.; + da = a dot (0.,0.,1.); + db = b dot (0.,0.,1.); if ( da-db != 0. ) { s = da/(da-db); p = (a.x+s*(b.x-a.x),a.y+s*(b.y-a.y),a.z+s*(b.z-a.z)); - if ( a.z > 1. ) a = p; - if ( b.z > 1. ) b = p; + if ( a.z < 0. ) a = p; + if ( b.z < 0. ) b = p; } Vector2 va = SWWMUtility.NDCToViewport(projdata,a); Vector2 vb = SWWMUtility.NDCToViewport(projdata,b); @@ -33,23 +35,25 @@ extend Class SWWMHandler for ( int i=0; i<64; i++ ) { Vector3 wpos = e.viewpos+level.Vec3Diff(e.viewpos,level.Vec3Offset(pos,SWWMUtility.CircleOffset(y,z,i*5.625,radius))); - ndc[i] = SWWMUtility.ProjectPoint(projdata,wpos); + ndc[i] = SWWMUtility.ProjectPoint(projdata,wpos,false); } for ( int i=0; i<64; i++ ) { Vector3 a = ndc[i], b = ndc[(i+1)%64]; - if ( (a.z > 1.) && (b.z > 1.) ) continue; - if ( (a.z == -double.infinity) || (b.z == -double.infinity) ) continue; // how??? + // both points are behind the screen + if ( (a.z <= 0.) && (b.z < 0.) ) return; + // at least one point is invalid + if ( (a.z == 0.) || (b.z == 0.) ) return; double da, db, s; Vector3 p; - da = a dot (0.,0.,-1.)-1.; - db = b dot (0.,0.,-1.)-1.; + da = a dot (0.,0.,1.); + db = b dot (0.,0.,1.); if ( da-db != 0. ) { s = da/(da-db); p = (a.x+s*(b.x-a.x),a.y+s*(b.y-a.y),a.z+s*(b.z-a.z)); - if ( a.z > 1. ) a = p; - if ( b.z > 1. ) b = p; + if ( a.z < 0. ) a = p; + if ( b.z < 0. ) b = p; } Vector2 va = SWWMUtility.NDCToViewport(projdata,a); Vector2 vb = SWWMUtility.NDCToViewport(projdata,b); @@ -90,7 +94,7 @@ extend Class SWWMHandler double hdiff = a.Height/2; if ( a.bFLOATBOB ) hdiff += a.GetBobOffset(); Vector3 ndc = SWWMUtility.ProjectPoint(projdata,e.viewpos+level.Vec3Diff(e.viewpos,pos+(0,0,hdiff))); - if ( ndc.z > 1. ) return; + if ( ndc.z <= 0. ) return; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc); String tag = a.player?a.player.GetUserName():a.GetTag(); if ( tag == a.GetClassName() ) SWWMUtility.BeautifyClassName(tag); diff --git a/zscript/hud/swwm_hud_target.zsc b/zscript/hud/swwm_hud_target.zsc index 890699148..9fcf02a9a 100644 --- a/zscript/hud/swwm_hud_target.zsc +++ b/zscript/hud/swwm_hud_target.zsc @@ -24,9 +24,8 @@ extend Class SWWMStatusBar Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh); } Vector3 tdir = level.Vec3Diff(ViewPos,poi.pos); - if ( viewvec dot tdir < 0 ) continue; Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir); - if ( ndc.z >= 1. ) continue; + if ( ndc.z <= 0. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs2; if ( poi.type == INT_Key ) tag = String.Format("\cf%s\c-",poi.keytag); else if ( poi.type == INT_Exit ) @@ -161,14 +160,12 @@ extend Class SWWMStatusBar // ignore trackers clearly outside of player view Vector3 smpos = level.Vec3Offset(SWWMUtility.LerpVector3(ct.Owner.prev,ct.Owner.pos,fractic),(0,0,ct.lvheight)); Vector3 tdir = level.Vec3Diff(viewpos,smpos); - if ( viewvec dot tdir < 0 ) continue; // ignore trackers that are too far away double dist = tdir.length(); if ( (fadedist > 0) && (dist > fadedist*1.5) ) continue; Vector3 ndc = SWWMUtility.ProjectPoint(projdata,viewpos+tdir); - if ( ndc.z >= 1. ) continue; + if ( ndc.z <= 0. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1; - if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue; double fin = clamp(ct.fadein+fractic,0.,5.)/5.; double fout = clamp(ct.lifespan-fractic,0.,25.)/25.; double alph = fin*fout; @@ -246,11 +243,9 @@ extend Class SWWMStatusBar // ignore trackers clearly outside of player view Vector3 smpos = level.Vec3Offset(SWWMUtility.LerpVector3(ct.Owner.prev,ct.Owner.pos,fractic),(0,0,ct.lvheight)); Vector3 tdir = level.Vec3Diff(viewpos,smpos); - if ( viewvec dot tdir < 0 ) continue; Vector3 ndc = SWWMUtility.ProjectPoint(projdata,viewpos+tdir); - if ( ndc.z >= 1. ) continue; + if ( ndc.z <= 0. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1; - if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue; double fin = clamp(ct.fadein+fractic,0.,5.)/5.; double fout = clamp(ct.lifespan-fractic,0.,25.)/25.; double alph = fin*fout; @@ -350,9 +345,8 @@ extend Class SWWMStatusBar Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh); } Vector3 tdir = level.Vec3Diff(ViewPos,snum.pos); - if ( viewvec dot tdir < 0 ) continue; - Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir); - if ( ndc.z >= 1. ) continue; + Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir,true); + if ( ndc.z <= 0. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs0; String tag = abs(snum.damage>=Actor.TELEFRAG_DAMAGE)?(snum.damage>0)?"-∞":"+∞":String.Format("%+d",-snum.damage); double alph = clamp((snum.lifespan+fractic)/35.,0.,1.); @@ -380,9 +374,8 @@ extend Class SWWMStatusBar Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh); } Vector3 tdir = level.Vec3Diff(ViewPos,snum.pos); - if ( viewvec dot tdir < 0 ) continue; Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir); - if ( ndc.z >= 1. ) continue; + if ( ndc.z <= 0. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1; String tag = String.Format("%+d",snum.score); double alph = clamp((snum.lifespan+fractic)/double(GameTicRate),0.,1.); diff --git a/zscript/menu/swwm_credits.zsc b/zscript/menu/swwm_credits.zsc index 29ec4b5ad..79b3720fe 100644 --- a/zscript/menu/swwm_credits.zsc +++ b/zscript/menu/swwm_credits.zsc @@ -173,11 +173,11 @@ Class SWWMCreditsMenu : GenericMenu cthanks.Push(new('SWWMCreditsEntry').Init("KynikossDragonn","$SWWM_CDRAGON2")); cthanks.Push(new('SWWMCreditsEntry').Init("Vyolette","$SWWM_CVYOLETTE2")); cthanks.Push(new('SWWMCreditsEntry').Init("Lucy","$SWWM_CLUCY2")); - cthanks.Push(new('SWWMCreditsEntry').Init("Gutawer","$SWWM_CGUTA2")); cthanks.Push(new('SWWMCreditsEntry').Init("Mikolah","$SWWM_CMIKO2")); cthanks.Push(new('SWWMCreditsEntry').Init("KeksDose","$SWWM_CKEKS2")); cthanks.Push(new('SWWMCreditsEntry').Init("ZZYZX & Nash","$SWWM_CZN2")); cthanks.Push(new('SWWMCreditsEntry').Init("BouncyTEM","$SWWM_CBOUNCY2")); + cthanks.Push(new('SWWMCreditsEntry').Init("a1337spy","$SWWM_CSPY2")); cthanks.Push(new('SWWMCreditsEntry').Init("\ctCptSledge\c- & \cdBunray\c-","$SWWM_CSLEDGE2")); cthanks.Push(new('SWWMCreditsEntry').Init("$SWWM_CINSP1","$SWWM_CINSP2")); cthanks.Push(new('SWWMCreditsEntry').Init("$SWWM_CCOMMUNITY1","$SWWM_CCOMMUNITY2")); diff --git a/zscript/swwm_Gutamatics/GlobalMaths.zsc b/zscript/swwm_Gutamatics/GlobalMaths.zsc deleted file mode 100644 index ba4e309bd..000000000 --- a/zscript/swwm_Gutamatics/GlobalMaths.zsc +++ /dev/null @@ -1,173 +0,0 @@ -class swwm_GM_GlobalMaths { - /// Returns the sign of s. - static int sign(double s) { - if (s > 0) return 1; - if (s < 0) return -1; - return 0; - } - - /// Copies the sign from signSource to source. - static int copySignInt(int source, int signSource) { - return abs(source) * sign(signSource); - } - - /// Copies the sign from signSource to source. - static double copySignDouble(double source, double signSource) { - return abs(source) * sign(signSource); - } - - /// Remaps a value in a range to another range. - static double remapRange(double value, double range1L, double range1H, double range2L, double range2H) { - return range2L + (value - range1L) * (range2H - range1H) / (range1H - range1L); - } - - /// Remaps a value in a range to another range. - static int remapRangeInt(int value, int range1L, int range1H, int range2L, int range2H) { - return int(range2L + (value - range1L) * (range2H - range1H) / double(range1H - range1L)); - } - - /// Returns if two values are close enough to be considered equal. - static bool closeEnough(double a, double b, double epsilon = double.epsilon) { - if (a == b) return true; - return abs(a - b) <= epsilon; - } - - // Creates a smoothed transition between edge0 and edge1. - static double smoothStep(double x, double edge0 = 0, double edge1 = 1) { - x = clamp((x - edge0) / (edge1 - edge0), 0, 1); - return x * x * (3 - 2 * x); - } - - // Creates a smoother transition between edge0 and edge1. - static double smootherStep(double x, double edge0 = 0, double edge1 = 1) { - x = clamp((x - edge0) / (edge1 - edge0), 0, 1); - return x * x * x * (x * (x * 6 - 15) + 10); - } - - /// Converts from horizontal FOV to vertical FOV, according to how GZDoom handles it. - static double fovHToY(double fovH) { - // this is how gzdoom does it internally, so i'm using it here - double aspect = Screen.getAspectRatio(); - double fovratio = (aspect >= 1.3) ? 1.333333 : aspect; - return 2 * atan(tan(clamp(fovH, 5, 170) / 2.0) / fovratio); - } - - /// Linearly interpolates between two doubles, clamping the parameters. - static double lerpDouble(double from, double to, double time) { - time = clamp(time, 0, 1); - return lerpUnclampedDouble(from, to, time); - } - - /// Linearly interpolates between two doubles. - static double lerpUnclampedDouble(double from, double to, double time) { - double ret; - double reverseTime = 1 - time; - ret = reverseTime * from + time * to; - return ret; - } - - // Converts from Normalised Device Coordinates to Viewport coordinates. - // This is `ui` scope to safely access `screenblocks`. - static ui Vector2 ndcToViewport(Vector3 ndcCoords, bool useScreenblocks = true) { - if (useScreenblocks) { - int viewwindowx, viewwindowy, viewwidth, viewheight; - [viewwindowx, viewwindowy, viewwidth, viewheight] = Screen.getViewWindow(); - int screenHeight = Screen.getHeight(); - int height = screenHeight; - if (screenblocks < 10) { - height = (screenblocks * screenHeight / 10) & ~7; - } - int bottom = screenHeight - (height + viewwindowy - ((height - viewheight) / 2)); - return (viewwindowx, screenHeight - bottom - height) + (((ndcCoords.x + 1) * viewwidth) / 2, ((-ndcCoords.y + 1) * height) / 2); - } - else { - return (((ndcCoords.x + 1) * Screen.getWidth()) / 2, ((-ndcCoords.y + 1) * Screen.getHeight()) / 2); - } - } - - enum OutCode { - OUT_Inside = 0, - OUT_Left = 1 << 0, - OUT_Right = 1 << 1, - OUT_Bottom = 1 << 2, - OUT_Top = 1 << 3 - } - - /// Computes an outcode for a point in a rectangle. - static OutCode computeOutcode(Vector2 point, Vector2 min, Vector2 max) { - OutCode code = OUT_Inside; - - if (point.x < min.x) { - code |= OUT_Left; - } - else if (point.x > max.x) { - code |= OUT_Right; - } - if (point.y < min.y) { - code |= OUT_Top; - } - else if (point.y > max.y) { - code |= OUT_Bottom; - } - - return code; - } - - /// Clips a line to a rectangle. - static bool, Vector2, Vector2 cohenSutherlandClip(Vector2 point0, Vector2 point1, Vector2 min, Vector2 max) { - OutCode outcode0 = computeOutCode(point0, min, max); - OutCode outcode1 = computeOutCode(point1, min, max); - - while (true) { - // trivial accept - points are both on screen - if ((outcode0 | outcode1) == 0) { - return true, point0, point1; - } - // trivial reject - points are in the same region offscreen - else if ((outcode0 & outcode1) != 0) { - return false, point0, point1; - } - else { - Vector2 new; - OutCode outcodeOut = (outcode0 != 0) ? outcode0 : outcode1; - - if ((outcodeOut & OUT_Bottom) != 0) { - new.x = point0.x + (point1.x - point0.x) * (max.y - point0.y) / (point1.y - point0.y); - new.y = max.y; - } - else if ((outcodeOut & OUT_Top) != 0) { - new.x = point0.x + (point1.x - point0.x) * (min.y - point0.y) / (point1.y - point0.y); - new.y = min.y; - } - else if ((outcodeOut & OUT_Right) != 0) { - new.y = point0.y + (point1.y - point0.y) * (max.x - point0.x) / (point1.x - point0.x); - new.x = max.x; - } - else if ((outcodeOut & OUT_Left) != 0) { - new.y = point0.y + (point1.y - point0.y) * (min.x - point0.x) / (point1.x - point0.x); - new.x = min.x; - } - - if (outcodeOut == outCode0) { - point0.x = new.x; - point0.y = new.y; - outCode0 = computeOutCode(point0, min, max); - } - else { - point1.x = new.x; - point1.y = new.y; - outCode1 = computeOutCode(point1, min, max); - } - } - } - return false, (0, 0), (0, 0); - } - - // Normalizes an angle to (-180, 180]. Like Actor.normalize180, but callable in data scope. - static double normalize180(double ang) { - ang = ang % 360; - ang = (ang + 360) % 360; - if (ang > 180) ang -= 360; - return ang; - } -} diff --git a/zscript/swwm_Gutamatics/Include.zsc b/zscript/swwm_Gutamatics/Include.zsc deleted file mode 100644 index 72515b120..000000000 --- a/zscript/swwm_Gutamatics/Include.zsc +++ /dev/null @@ -1,5 +0,0 @@ -#include "zscript/swwm_Gutamatics/GlobalMaths.zsc" -#include "zscript/swwm_Gutamatics/Matrix.zsc" -#include "zscript/swwm_Gutamatics/Matrix4.zsc" -#include "zscript/swwm_Gutamatics/Quaternion.zsc" -#include "zscript/swwm_Gutamatics/VectorUtil.zsc" diff --git a/zscript/swwm_Gutamatics/LICENSE.md b/zscript/swwm_Gutamatics/LICENSE.md deleted file mode 100644 index cab7d22ba..000000000 --- a/zscript/swwm_Gutamatics/LICENSE.md +++ /dev/null @@ -1,7 +0,0 @@ -Copyright 2020 Jessica Russell - -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. diff --git a/zscript/swwm_Gutamatics/Matrix.zsc b/zscript/swwm_Gutamatics/Matrix.zsc deleted file mode 100644 index 2a6f94d53..000000000 --- a/zscript/swwm_Gutamatics/Matrix.zsc +++ /dev/null @@ -1,335 +0,0 @@ -enum swwm_GM_VectorType { - swwm_GM_Vector_Position, - swwm_GM_Vector_Direction -} - -class swwm_GM_Matrix { - private Array values; - private int columns; - private int rows; - - /// Initialises a new Matrix. - swwm_GM_Matrix init(int columns, int rows) { - if (columns <= 0 || rows <= 0) { - throwAbortException("Error: <%p>.init(%d, %d) - Matrix needs to be at least 1 * 1", self, columns, rows); - } - - self.rows = rows; - self.columns = columns; - values.resize(columns * rows); - for (int i = 0; i < values.size(); i++) { - values[i] = 0; - } - - return self; - } - - /// Initialises a new Matrix in a static context. - static swwm_GM_Matrix create(int columns, int rows) { - return new("swwm_GM_Matrix").init(columns, rows); - } - - /// Returns an identity matrix. - static swwm_GM_Matrix identity(int dimension) { - swwm_GM_Matrix ret = swwm_GM_Matrix.create(dimension, dimension); - for (int i = 0; i < dimension; i++) { - ret.set(i, i, 1); - } - return ret; - } - - /// Returns a rotation matrix from euler angles. - static swwm_GM_Matrix fromEulerAngles(double yaw, double pitch, double roll) { - swwm_GM_Matrix rYaw = swwm_GM_Matrix.identity(4); - double sYaw = sin(yaw); - double cYaw = cos(yaw); - rYaw.set(0, 0, cYaw); - rYaw.set(0, 1, -sYaw); - rYaw.set(1, 0, sYaw); - rYaw.set(1, 1, cYaw); - - swwm_GM_Matrix rPitch = swwm_GM_Matrix.identity(4); - double sPitch = sin(pitch); - double cPitch = cos(pitch); - rPitch.set(0, 0, cPitch); - rPitch.set(2, 0, -sPitch); - rPitch.set(0, 2, sPitch); - rPitch.set(2, 2, cPitch); - - swwm_GM_Matrix rRoll = swwm_GM_Matrix.identity(4); - double sRoll = sin(roll); - double cRoll = cos(roll); - rRoll.set(1, 1, cRoll); - rRoll.set(1, 2, -sRoll); - rRoll.set(2, 1, sRoll); - rRoll.set(2, 2, cRoll); - - // concatenate ypr to get the final matrix - swwm_GM_Matrix ret = rYaw.multiplyMatrix(rPitch); - ret = ret.multiplyMatrix(rRoll); - return ret; - } - - /// Returns a rotation matrix from an axis and an angle. - static swwm_GM_Matrix fromAxisAngle(Vector3 axis, double angle) { - swwm_GM_Matrix ret = swwm_GM_Matrix.identity(4); - double c = cos(angle); - double s = sin(angle); - double x = axis.x; - double y = axis.y; - double z = axis.z; - - ret.set(0, 0, (x * x * (1.0 - c) + c)); - ret.set(0, 1, (x * y * (1.0 - c) - z * s)); - ret.set(0, 2, (x * z * (1.0 - c) + y * s)); - ret.set(1, 0, (y * x * (1.0 - c) + z * s)); - ret.set(1, 1, (y * y * (1.0 - c) + c)); - ret.set(1, 2, (y * z * (1.0 - c) - x * s)); - ret.set(2, 0, (x * z * (1.0 - c) - y * s)); - ret.set(2, 1, (y * z * (1.0 - c) + x * s)); - ret.set(2, 2, (z * z * (1.0 - c) + c)); - - return ret; - } - - /// Converts back from the rotation matrix to euler angles. - double, double, double rotationToEulerAngles() { - if (swwm_GM_GlobalMaths.closeEnough(get(2, 0), -1)) { - double x = 90; - double y = 0; - double z = atan2(get(0, 1), get(0, 2)); - return z, x, y; - } - else if (swwm_GM_GlobalMaths.closeEnough(get(2, 0), 1)) { - double x = -90; - double y = 0; - double z = atan2(-get(0, 1), -get(0, 2)); - return z, x, y; - } - else { - float x1 = -asin(get(2, 0)); - float x2 = 180 - x1; - - float y1 = atan2(get(2, 1) / cos(x1), get(2, 2) / cos(x1)); - float y2 = atan2(get(2, 1) / cos(x2), get(2, 2) / cos(x2)); - - float z1 = atan2(get(1, 0) / cos(x1), get(0, 0) / cos(x1)); - float z2 = atan2(get(1, 0) / cos(x2), get(0, 0) / cos(x2)); - - if ((abs(x1) + abs(y1) + abs(z1)) <= (abs(x2) + abs(y2) + abs(z2))) { - return z1, x1, y1; - } - else { - return z2, x2, y2; - } - } - } - - static swwm_GM_Matrix createTRSEuler(Vector3 translate, double yaw, double pitch, double roll, Vector3 scale) { - swwm_GM_Matrix translateMat = swwm_GM_Matrix.identity(4); - translateMat.set(0, 3, translate.x); - translateMat.set(1, 3, translate.y); - translateMat.set(2, 3, translate.z); - - swwm_GM_Matrix rotateMat = swwm_GM_Matrix.fromEulerAngles(yaw, pitch, roll); - - swwm_GM_Matrix scaleMat = swwm_GM_Matrix.identity(4); - scaleMat.set(0, 0, scale.x); - scaleMat.set(1, 1, scale.y); - scaleMat.set(2, 2, scale.z); - - swwm_GM_Matrix ret = translateMat.multiplyMatrix(rotateMat); - ret = ret.multiplyMatrix(scaleMat); - return ret; - } - - static swwm_GM_Matrix createTRSAxisAngle(Vector3 translate, Vector3 axis, double angle, Vector3 scale) { - swwm_GM_Matrix translateMat = swwm_GM_Matrix.identity(4); - translateMat.set(0, 3, translate.x); - translateMat.set(1, 3, translate.y); - translateMat.set(2, 3, translate.z); - - swwm_GM_Matrix rotateMat = swwm_GM_Matrix.fromAxisAngle(axis, angle); - - swwm_GM_Matrix scaleMat = swwm_GM_Matrix.identity(4); - scaleMat.set(0, 0, scale.x); - scaleMat.set(1, 1, scale.y); - scaleMat.set(2, 2, scale.z); - - swwm_GM_Matrix ret = translateMat.multiplyMatrix(rotateMat); - ret = ret.multiplyMatrix(scaleMat); - return ret; - } - - /// Returns a view matrix. - static swwm_GM_Matrix view(Vector3 camPos, double yaw, double pitch, double roll) { - // all of this is basically lifted and converted from PolyRenderer::SetupPerspectiveMatrix(), - // so credit goes to Graf Zahl/dpJudas/whoever else - // pitch needs to be adjusted by the pixel ratio - float pixelRatio = level.pixelstretch; - double angx = cos(pitch); - double angy = sin(pitch) * pixelRatio; - double alen = sqrt(angx * angx + angy * angy); - double adjustedPitch = asin(angy / alen); - double adjustedYaw = yaw - 90; - - // rotations - swwm_GM_Matrix rotR = swwm_GM_Matrix.fromAxisAngle((0, 0, 1), roll); - swwm_GM_Matrix rotP = swwm_GM_Matrix.fromAxisAngle((1, 0, 0), adjustedPitch); - swwm_GM_Matrix rotY = swwm_GM_Matrix.fromAxisAngle((0, -1, 0), adjustedYaw); - // pixel ratio scaling - swwm_GM_Matrix scale = swwm_GM_Matrix.identity(4); - scale.set(1, 1, pixelRatio); - // swapping y and z - swwm_GM_Matrix swapYZ = swwm_GM_Matrix.create(4, 4); - swapYZ.set(0, 0, 1); - swapYZ.set(1, 2, 1); - swapYZ.set(2, 1, -1); - swapYZ.set(3, 3, 1); - // translation - swwm_GM_Matrix translate = swwm_GM_Matrix.identity(4); - translate.set(0, 3, -camPos.x); - translate.set(1, 3, -camPos.y); - translate.set(2, 3, -camPos.z); - - // concatenate them all to get a final matrix - swwm_GM_Matrix ret = rotR.multiplyMatrix(rotP); - ret = ret.multiplyMatrix(rotY); - ret = ret.multiplyMatrix(scale); - ret = ret.multiplyMatrix(swapYZ); - ret = ret.multiplyMatrix(translate); - - return ret; - } - - /// Returns a perspective matrix (same format as gluPerspective). - static swwm_GM_Matrix perspective(double fovy, double aspect, double zNear, double zFar) { - swwm_GM_Matrix ret = swwm_GM_Matrix.create(4, 4); - double f = 1 / tan(fovy / 2.0); - // x coord - ret.set(0, 0, f / aspect); - // y coord - ret.set(1, 1, f); - // z buffer coord - ret.set(2, 2, (zFar + zNear) / (zNear - zFar)); - ret.set(2, 3, (2 * zFar * zNear) / (zNear - zFar)); - // w (homogeneous coordinates) - ret.set(3, 2, -1); - return ret; - } - - /// Returns a world->clip coords matrix from the passed args. - static swwm_GM_Matrix worldToClip(Vector3 viewPos, double yaw, double pitch, double roll, double FOV) { - double aspect = Screen.getAspectRatio(); - double fovy = swwm_GM_GlobalMaths.fovHToY(FOV); - swwm_GM_Matrix view = swwm_GM_Matrix.view(viewPos, yaw, pitch, roll); - // 5 & 65535 are what are used internally, so they're used here for consistency - swwm_GM_Matrix perp = swwm_GM_Matrix.perspective(fovy, aspect, 5, 65535); - swwm_GM_Matrix worldToClip = perp.multiplyMatrix(view); - return worldToClip; - } - - /// Gets the value at row, col. - double get(int row, int col) const { - return values[columns * row + col]; - } - - /// Sets the value at row, col. - void set(int row, int col, double val) { - values[columns * row + col] = val; - } - - /// Adds two matrices and returns the result. - swwm_GM_Matrix addMatrix(swwm_GM_Matrix other) const { - if (rows != other.rows || columns != other.columns) { - throwAbortException("Error: <%p>.addMatrix(<%p>) - Matrices need to be equal size", self, other); - } - swwm_GM_Matrix ret = swwm_GM_Matrix.create(columns, rows); - for (int row = 0; row < rows; row++) { - for (int col = 0; col < columns; col++) { - ret.set(row, col, get(row, col) + other.get(row, col)); - } - } - return ret; - } - - /// Multiplies the matrix by a scalar and returns the result. - swwm_GM_Matrix multiplyScalar(double scalar) const { - swwm_GM_Matrix ret = swwm_GM_Matrix.create(rows, columns); - for (int row = 0; row < rows; row++) { - for (int col = 0; col < columns; col++) { - ret.set(row, col, get(row, col) * scalar); - } - } - return ret; - } - - /// Multiplies two matrices and returns the result. - swwm_GM_Matrix multiplyMatrix(swwm_GM_Matrix other) const { - if (columns != other.rows) { - throwAbortException("Error: <%p>.multiplyMatrix(<%p>) - Matrix A columns needs to equal Matrix B rows", self, other); - } - swwm_GM_Matrix ret = swwm_GM_Matrix.create(other.columns, rows); - for (int row = 0; row < ret.rows; row++) { - for (int col = 0; col < ret.columns; col++) { - double val = 0; - for (int i = 0; i < columns; i++) { - val += get(row, i) * other.get(i, col); - } - ret.set(row, col, val); - } - } - return ret; - } - - /// Multiplies this Matrix by a 2D vector. - swwm_GM_Matrix multiplyVector2(Vector2 vec, swwm_GM_VectorType type = swwm_GM_Vector_Position) const { - swwm_GM_Matrix vec2Matrix = swwm_GM_Matrix.create(1, 3); - vec2Matrix.set(0, 0, vec.x); - vec2Matrix.set(1, 0, vec.y); - if (type == swwm_GM_Vector_Position) vec2Matrix.set(2, 0, 1); - else if (type == swwm_GM_Vector_Direction) vec2Matrix.set(2, 0, 0); - else throwAbortException("Error: Invalid vector type for multiplyVector2 (%d)", type); - return multiplyMatrix(vec2Matrix); - } - - /// Multiplies this Matrix by a 3D vector. - swwm_GM_Matrix multiplyVector3(Vector3 vec, swwm_GM_VectorType type = swwm_GM_Vector_Position) const { - swwm_GM_Matrix vec3Matrix = swwm_GM_Matrix.create(1, 4); - vec3Matrix.set(0, 0, vec.x); - vec3Matrix.set(1, 0, vec.y); - vec3Matrix.set(2, 0, vec.z); - if (type == swwm_GM_Vector_Position) vec3Matrix.set(3, 0, 1); - else if (type == swwm_GM_Vector_Direction) vec3Matrix.set(3, 0, 0); - else throwAbortException("Error: Invalid vector type for multiplyVector3 (%d)", type); - return multiplyMatrix(vec3Matrix); - } - - /// Returns the Matrix in Vector2 form, optionally dividing by z. - Vector2 asVector2(bool divideZ = true) const { - if (columns != 1 || rows != 3) { - throwAbortException("Error: <%p>.asVector2() - Matrix needs to be 1 * 3", self); - } - if (divideZ) return (get(0, 0), get(1, 0)) / get(2, 0); - else return (get(0, 0), get(1, 0)); - } - - /// Returns the Matrix in Vector3 form, optionally dividing by w. - Vector3 asVector3(bool divideW = true) const { - if (columns != 1 || rows != 4) { - throwAbortException("Error: <%p>.asVector3() - Matrix needs to be 1 * 4", self); - } - if (divideW) return (get(0, 0), get(1, 0), get(2, 0)) / get(3, 0); - else return (get(0, 0), get(1, 0), get(2, 0)); - } - - /// Returns the number of columns. - int getColumns() const { - return columns; - } - - /// Returns the number of rows. - int getRows() const { - return rows; - } -} diff --git a/zscript/swwm_Gutamatics/Matrix4.zsc b/zscript/swwm_Gutamatics/Matrix4.zsc deleted file mode 100644 index 76c1e67c3..000000000 --- a/zscript/swwm_Gutamatics/Matrix4.zsc +++ /dev/null @@ -1,319 +0,0 @@ -class swwm_GM_Matrix4 { - double values[4][4]; - - /// Initialises a new Matrix4 in a static context. - static swwm_GM_Matrix4 create() { - return new("swwm_GM_Matrix4"); - } - - /// Returns an identity matrix. - static swwm_GM_Matrix4 identity() { - let ret = swwm_GM_Matrix4.create(); - ret.values[0][0] = 1; - ret.values[1][1] = 1; - ret.values[2][2] = 1; - ret.values[3][3] = 1; - return ret; - } - - /// Returns a rotation matrix from euler angles. - static swwm_GM_Matrix4 fromEulerAngles(double yaw, double pitch, double roll) { - swwm_GM_Matrix4 rYaw = swwm_GM_Matrix4.identity(); - double sYaw = sin(yaw); - double cYaw = cos(yaw); - rYaw.values[0][0] = cYaw; - rYaw.values[0][1] = -sYaw; - rYaw.values[1][0] = sYaw; - rYaw.values[1][1] = cYaw; - - swwm_GM_Matrix4 rPitch = swwm_GM_Matrix4.identity(); - double sPitch = sin(pitch); - double cPitch = cos(pitch); - rPitch.values[0][0] = cPitch; - rPitch.values[2][0] = -sPitch; - rPitch.values[0][2] = sPitch; - rPitch.values[2][2] = cPitch; - - swwm_GM_Matrix4 rRoll = swwm_GM_Matrix4.identity(); - double sRoll = sin(roll); - double cRoll = cos(roll); - rRoll.values[1][1] = cRoll; - rRoll.values[1][2] = -sRoll; - rRoll.values[2][1] = sRoll; - rRoll.values[2][2] = cRoll; - - // concatenate ypr to get the final matrix - swwm_GM_Matrix4 ret = rYaw.multiplyMatrix(rPitch); - ret = ret.multiplyMatrix(rRoll); - return ret; - } - - /// Returns a rotation matrix from an axis and an angle. - static swwm_GM_Matrix4 fromAxisAngle(Vector3 axis, double angle) { - swwm_GM_Matrix4 ret = swwm_GM_Matrix4.identity(); - double c = cos(angle); - double s = sin(angle); - double x = axis.x; - double y = axis.y; - double z = axis.z; - - ret.values[0][0] = (x * x * (1.0 - c) + c); - ret.values[0][1] = (x * y * (1.0 - c) - z * s); - ret.values[0][2] = (x * z * (1.0 - c) + y * s); - ret.values[1][0] = (y * x * (1.0 - c) + z * s); - ret.values[1][1] = (y * y * (1.0 - c) + c); - ret.values[1][2] = (y * z * (1.0 - c) - x * s); - ret.values[2][0] = (x * z * (1.0 - c) - y * s); - ret.values[2][1] = (y * z * (1.0 - c) + x * s); - ret.values[2][2] = (z * z * (1.0 - c) + c); - - return ret; - } - - /// Converts back from the rotation matrix to euler angles. - double, double, double rotationToEulerAngles() { - if (swwm_GM_GlobalMaths.closeEnough(values[2][0], -1)) { - double x = 90; - double y = 0; - double z = atan2(values[0][1], values[0][2]); - return z, x, y; - } - else if (swwm_GM_GlobalMaths.closeEnough(values[2][0], 1)) { - double x = -90; - double y = 0; - double z = atan2(-values[0][1], -values[0][2]); - return z, x, y; - } - else { - float x1 = -asin(values[2][0]); - float x2 = 180 - x1; - - float y1 = atan2(values[2][1] / cos(x1), values[2][2] / cos(x1)); - float y2 = atan2(values[2][1] / cos(x2), values[2][2] / cos(x2)); - - float z1 = atan2(values[1][0] / cos(x1), values[0][0] / cos(x1)); - float z2 = atan2(values[1][0] / cos(x2), values[0][0] / cos(x2)); - - if ((abs(x1) + abs(y1) + abs(z1)) <= (abs(x2) + abs(y2) + abs(z2))) { - return z1, x1, y1; - } - else { - return z2, x2, y2; - } - } - } - - static swwm_GM_Matrix4 createTRSEuler(Vector3 translate, double yaw, double pitch, double roll, Vector3 scale) { - swwm_GM_Matrix4 translateMat = swwm_GM_Matrix4.identity(); - translateMat.values[0][3] = translate.x; - translateMat.values[1][3] = translate.y; - translateMat.values[2][3] = translate.z; - - swwm_GM_Matrix4 rotateMat = swwm_GM_Matrix4.fromEulerAngles(yaw, pitch, roll); - - swwm_GM_Matrix4 scaleMat = swwm_GM_Matrix4.identity(); - scaleMat.values[0][0] = scale.x; - scaleMat.values[1][1] = scale.y; - scaleMat.values[2][2] = scale.z; - - swwm_GM_Matrix4 ret = translateMat.multiplyMatrix(rotateMat); - ret = ret.multiplyMatrix(scaleMat); - return ret; - } - - static swwm_GM_Matrix4 createTRSAxisAngle(Vector3 translate, Vector3 axis, double angle, Vector3 scale) { - swwm_GM_Matrix4 translateMat = swwm_GM_Matrix4.identity(); - translateMat.values[0][3] = translate.x; - translateMat.values[1][3] = translate.y; - translateMat.values[2][3] = translate.z; - - swwm_GM_Matrix4 rotateMat = swwm_GM_Matrix4.fromAxisAngle(axis, angle); - - swwm_GM_Matrix4 scaleMat = swwm_GM_Matrix4.identity(); - scaleMat.values[0][0] = scale.x; - scaleMat.values[1][1] = scale.y; - scaleMat.values[2][2] = scale.z; - - swwm_GM_Matrix4 ret = translateMat.multiplyMatrix(rotateMat); - ret = ret.multiplyMatrix(scaleMat); - return ret; - } - - /// Returns a view matrix. - static swwm_GM_Matrix4 view(Vector3 camPos, double yaw, double pitch, double roll) { - // all of this is basically lifted and converted from PolyRenderer::SetupPerspectiveMatrix(), - // so credit goes to Graf Zahl/dpJudas/whoever else - // pitch needs to be adjusted by the pixel ratio - float pixelRatio = level.pixelstretch; - double angx = cos(pitch); - double angy = sin(pitch) * pixelRatio; - double alen = sqrt(angx * angx + angy * angy); - double adjustedPitch = asin(angy / alen); - double adjustedYaw = 90 - yaw; - - // rotations - let cz = cos(roll); - let sz = sin(roll); - let cx = cos(adjustedPitch); - let sx = sin(adjustedPitch); - let cy = cos(adjustedYaw); - let sy = sin(adjustedYaw); - - let rot = swwm_GM_Matrix4.create(); - rot.values[0][0] = cz * cy - sz * sx * sy; - rot.values[0][1] = -sz * cx; - rot.values[0][2] = cz * sy + sz * sx * cy; - - rot.values[1][0] = sz * cy + cz * sx * sy; - rot.values[1][1] = cz * cx; - rot.values[1][2] = sz * sy - cz * sx * cy; - - rot.values[2][0] = -cx * sy; - rot.values[2][1] = sx; - rot.values[2][2] = cx * cy; - - rot.values[3][3] = 1.0; - - // pixel ratio scaling - swwm_GM_Matrix4 scale = swwm_GM_Matrix4.identity(); - scale.values[1][1] = pixelRatio; - // swapping y and z - swwm_GM_Matrix4 swapYZ = swwm_GM_Matrix4.create(); - swapYZ.values[0][0] = 1; - swapYZ.values[1][2] = 1; - swapYZ.values[2][1] = -1; - swapYZ.values[3][3] = 1; - // translation - swwm_GM_Matrix4 translate = swwm_GM_Matrix4.identity(); - translate.values[0][3] = -camPos.x; - translate.values[1][3] = -camPos.y; - translate.values[2][3] = -camPos.z; - - // concatenate them all to get a final matrix - swwm_GM_Matrix4 ret = rot.multiplyMatrix(scale); - ret = ret.multiplyMatrix(swapYZ); - ret = ret.multiplyMatrix(translate); - - return ret; - } - - /// Returns a perspective matrix (same format as gluPerspective). - static swwm_GM_Matrix4 perspective(double fovy, double aspect, double zNear, double zFar) { - swwm_GM_Matrix4 ret = swwm_GM_Matrix4.create(); - double f = 1 / tan(fovy / 2.0); - // x coord - ret.values[0][0] = f / aspect; - // y coord - ret.values[1][1] = f; - // z buffer coord - ret.values[2][2] = (zFar + zNear) / (zNear - zFar); - ret.values[2][3] = (2 * zFar * zNear) / (zNear - zFar); - // w (homogeneous coordinates) - ret.values[3][2] = -1; - return ret; - } - - /// Returns a world->clip coords matrix from the passed args. - static swwm_GM_Matrix4 worldToClip(Vector3 viewPos, double yaw, double pitch, double roll, double FOV) { - double aspect = Screen.getAspectRatio(); - double fovy = swwm_GM_GlobalMaths.fovHToY(FOV); - swwm_GM_Matrix4 view = swwm_GM_Matrix4.view(viewPos, yaw, pitch, roll); - // 5 & 65535 are what are used internally, so they're used here for consistency - swwm_GM_Matrix4 perp = swwm_GM_Matrix4.perspective(fovy, aspect, 5, 65535); - swwm_GM_Matrix4 worldToClip = perp.multiplyMatrix(view); - return worldToClip; - } - - /// Adds two matrices and returns the result. - swwm_GM_Matrix4 addMatrix(swwm_GM_Matrix4 other) const { - swwm_GM_Matrix4 ret = swwm_GM_Matrix4.create(); - ret.values[0][0] = values[0][0] + other.values[0][0]; - ret.values[0][1] = values[0][1] + other.values[0][1]; - ret.values[0][2] = values[0][2] + other.values[0][2]; - ret.values[0][3] = values[0][3] + other.values[0][3]; - ret.values[1][0] = values[1][0] + other.values[1][0]; - ret.values[1][1] = values[1][1] + other.values[1][1]; - ret.values[1][2] = values[1][2] + other.values[1][2]; - ret.values[1][3] = values[1][3] + other.values[1][3]; - ret.values[2][0] = values[2][0] + other.values[2][0]; - ret.values[2][1] = values[2][1] + other.values[2][1]; - ret.values[2][2] = values[2][2] + other.values[2][2]; - ret.values[2][3] = values[2][3] + other.values[2][3]; - ret.values[3][0] = values[3][0] + other.values[3][0]; - ret.values[3][1] = values[3][1] + other.values[3][1]; - ret.values[3][2] = values[3][2] + other.values[3][2]; - ret.values[3][3] = values[3][3] + other.values[3][3]; - return ret; - } - - /// Multiplies the matrix by a scalar and returns the result. - swwm_GM_Matrix4 multiplyScalar(double scalar) const { - swwm_GM_Matrix4 ret = swwm_GM_Matrix4.create(); - ret.values[0][0] = values[0][0] * scalar; - ret.values[0][1] = values[0][1] * scalar; - ret.values[0][2] = values[0][2] * scalar; - ret.values[0][3] = values[0][3] * scalar; - ret.values[1][0] = values[1][0] * scalar; - ret.values[1][1] = values[1][1] * scalar; - ret.values[1][2] = values[1][2] * scalar; - ret.values[1][3] = values[1][3] * scalar; - ret.values[2][0] = values[2][0] * scalar; - ret.values[2][1] = values[2][1] * scalar; - ret.values[2][2] = values[2][2] * scalar; - ret.values[2][3] = values[2][3] * scalar; - ret.values[3][0] = values[3][0] * scalar; - ret.values[3][1] = values[3][1] * scalar; - ret.values[3][2] = values[3][2] * scalar; - ret.values[3][3] = values[3][3] * scalar; - return ret; - } - - /// Multiplies two matrices and returns the result. - swwm_GM_Matrix4 multiplyMatrix(swwm_GM_Matrix4 other) const { - swwm_GM_Matrix4 ret = swwm_GM_Matrix4.create(); - for (int row = 0; row < 4; row++) { - ret.values[row][0] = - values[row][0] * other.values[0][0] + - values[row][1] * other.values[1][0] + - values[row][2] * other.values[2][0] + - values[row][3] * other.values[3][0]; - - ret.values[row][1] = - values[row][0] * other.values[0][1] + - values[row][1] * other.values[1][1] + - values[row][2] * other.values[2][1] + - values[row][3] * other.values[3][1]; - - ret.values[row][2] = - values[row][0] * other.values[0][2] + - values[row][1] * other.values[1][2] + - values[row][2] * other.values[2][2] + - values[row][3] * other.values[3][2]; - - ret.values[row][3] = - values[row][0] * other.values[0][3] + - values[row][1] * other.values[1][3] + - values[row][2] * other.values[2][3] + - values[row][3] * other.values[3][3]; - } - return ret; - } - - /// Multiplies this Matrix by a 3D vector. - Vector3 multiplyVector3(Vector3 vec, swwm_GM_VectorType type = swwm_GM_Vector_Position, bool divideW = true) const { - let vecW = (type == swwm_GM_Vector_Position) ? 1.0 : 0.0; - - let ret = ( - values[0][0] * vec.x + values[0][1] * vec.y + values[0][2] * vec.z + values[0][3] * vecW, - values[1][0] * vec.x + values[1][1] * vec.y + values[1][2] * vec.z + values[1][3] * vecW, - values[2][0] * vec.x + values[2][1] * vec.y + values[2][2] * vec.z + values[2][3] * vecW - ); - - if (divideW) { - let retW = values[3][0] * vec.x + values[3][1] * vec.y + values[3][2] * vec.z + values[3][3] * vecW; - ret /= retW; - } - - return ret; - } -} diff --git a/zscript/swwm_Gutamatics/Quaternion.zsc b/zscript/swwm_Gutamatics/Quaternion.zsc deleted file mode 100644 index b19827e2d..000000000 --- a/zscript/swwm_Gutamatics/Quaternion.zsc +++ /dev/null @@ -1,275 +0,0 @@ -class swwm_GM_Quaternion { - double w, x, y, z; - - /// Initialises the Quaternion. - swwm_GM_Quaternion init(double w, double x, double y, double z) { - self.w = w; - self.x = x; - self.y = y; - self.z = z; - - return self; - } - - /// Initialises the Quaternion in a static context. - static swwm_GM_Quaternion create(double w, double x, double y, double z) { - return new("swwm_GM_Quaternion").init(w, x, y, z); - } - - /// Sets up the quaternion using axis and angle. - void setAxisAngle(Vector3 axis, double angle) { - double lengthSquared = axis dot axis; - // avoid a division by 0 and just return the identity - if (swwm_GM_GlobalMaths.closeEnough(lengthSquared, 0)) { - init(1, 0, 0, 0); - return; - } - - angle *= 0.5; - - double sinTheta = sin(angle); - double cosTheta = cos(angle); - double factor = sinTheta / sqrt(lengthSquared); - - w = cosTheta; - x = factor * axis.x; - y = factor * axis.y; - z = factor * axis.z; - } - - /// Initialises the Quaternion using axis and angle. - swwm_GM_Quaternion initFromAxisAngle(Vector3 axis, double angle) { - setAxisAngle(axis, angle); - return self; - } - - /// Initialises the Quaternion using axis and angle in a static context. - static swwm_GM_Quaternion createFromAxisAngle(Vector3 axis, double angle) { - return new("swwm_GM_Quaternion").initFromAxisAngle(axis, angle); - } - - /// Sets up the quaternion using euler angles. - void setAngles(double yaw, double pitch, double roll) { - swwm_GM_Quaternion zRotation = new("swwm_GM_Quaternion").initFromAxisAngle((0, 0, 1), yaw); - swwm_GM_Quaternion yRotation = new("swwm_GM_Quaternion").initFromAxisAngle((0, 1, 0), pitch); - swwm_GM_Quaternion xRotation = new("swwm_GM_Quaternion").initFromAxisAngle((1, 0, 0), roll); - swwm_GM_Quaternion finalRotation = zRotation.multiplyQuat(yRotation); - finalRotation = finalRotation.multiplyQuat(xRotation); - copy(finalRotation); - } - - /// Initialises the quaternion using euler angles. - swwm_GM_Quaternion initFromAngles(double yaw, double pitch, double roll) { - setAngles(yaw, pitch, roll); - return self; - } - - /// Initialises the quaternion using euler angles in a static context. - static swwm_GM_Quaternion createFromAngles(double yaw, double pitch, double roll) { - return new("swwm_GM_Quaternion").initFromAngles(yaw, pitch, roll); - } - - /// Returns the euler angles from the Quaternion. - double, double, double toAngles() { - double singularityTest = z * x - w * y; - double yawY = 2 * (w * z + x * y); - double yawX = (1 - 2 * (y * y + z * z)); - - double singularityThreshold = 0.4999995; - - double yaw = 0; - double pitch = 0; - double roll = 0; - - if (singularityTest < -singularityThreshold) { - pitch = 90; - yaw = atan2(yawY, yawX); - roll = swwm_GM_GlobalMaths.normalize180(yaw + (2 * atan2(x, w))); - } - else if (singularityTest > singularityThreshold) { - pitch = -90; - yaw = atan2(yawY, yawX); - roll = swwm_GM_GlobalMaths.normalize180(yaw + (2 * atan2(x, w))); - } - else { - pitch = -asin(2 * singularityTest); - yaw = atan2(yawY, yawX); - roll = atan2(2 * (w * x + y * z), (1 - 2 * (x * x + y * y))); - } - - return yaw, pitch, roll; - } - - /// Returns the conjugate of the Quaternion. - swwm_GM_Quaternion conjugate() const { - return new("swwm_GM_Quaternion").init(w, -x, -y, -z); - } - - /// Returns the normalised form of the Quaternion. - swwm_GM_Quaternion unit() const { - double lengthSquared = w * w + x * x + y * y + z * z; - if (swwm_GM_GlobalMaths.closeEnough(lengthSquared, 0)) { - return zero(); - } - double factor = 1 / sqrt(lengthSquared); - return new("swwm_GM_Quaternion").init(w * factor, x * factor, y * factor, z * factor); - } - - /// Returns the inverse of the Quaternion (equal to conjugate if normalised). - swwm_GM_Quaternion inverse() { - double norm = w * w + x * x + y * y + z * z; - // if this is a zero quaternion, just return self - if (swwm_GM_GlobalMaths.closeEnough(norm, 0)) { - return self; - } - double inverseNorm = 1/norm; - return new("swwm_GM_Quaternion").init(w * inverseNorm, x * -inverseNorm, y * -inverseNorm, z * -inverseNorm); - } - - /// Adds two Quaternions, returning the result. - swwm_GM_Quaternion add(swwm_GM_Quaternion other) const { - return new("swwm_GM_Quaternion").init(w + other.w, x + other.x, y + other.y, z + other.z); - } - - /// Subtracts two Quaternions, returning the result. - swwm_GM_Quaternion subtract(swwm_GM_Quaternion other) const { - return new("swwm_GM_Quaternion").init(w - other.w, x - other.x, y - other.y, z - other.z); - } - - /// Multiplies the Quaternion by a scalar, returning the result. - swwm_GM_Quaternion multiplyScalar(double scalar) const { - return new("swwm_GM_Quaternion").init(w * scalar, x * scalar, y * scalar, z * scalar); - } - - /// Multiplies two Quaternions, returning the result. - swwm_GM_Quaternion multiplyQuat(swwm_GM_Quaternion other) const { - return new("swwm_GM_Quaternion").init(w * other.w - x * other.x - y * other.y - z * other.z, - w * other.x + x * other.w + y * other.z - z * other.y, - w * other.y + y * other.w + z * other.x - x * other.z, - w * other.z + z * other.w + x * other.y - y * other.x ); - } - - /// Negates the Quaternion. - swwm_GM_Quaternion negate() const { - return new("swwm_GM_Quaternion").init(-w, -x, -y, -z); - } - - /// Sets the values to 0 if they're close enough to 0. - void clean() { - if (swwm_GM_GlobalMaths.closeEnough(w, 0)) w = 0; - if (swwm_GM_GlobalMaths.closeEnough(x, 0)) x = 0; - if (swwm_GM_GlobalMaths.closeEnough(y, 0)) y = 0; - if (swwm_GM_GlobalMaths.closeEnough(z, 0)) z = 0; - } - - /// Returns the length of the Quaternion squared. - double lengthSquared() const { - return (w * w + x * x + y * y + z * z); - } - - /// Returns the length of the Quaternion. - double length() const { - return sqrt(w * w + x * x + y * y + z * z); - } - - /// Returns whether the two Quaternions are equal. - bool equals(swwm_GM_Quaternion other) const { - return swwm_GM_GlobalMaths.closeEnough(w, other.w) && swwm_GM_GlobalMaths.closeEnough(x, other.x) && - swwm_GM_GlobalMaths.closeEnough(y, other.y) && swwm_GM_GlobalMaths.closeEnough(z, other.z) ; - } - - /// Returns if the Quaternion is a 0 Quaternion. - bool isZero() const { - return swwm_GM_GlobalMaths.closeEnough(w * w + x * x + y * y + z * z, 0); - } - - /// Returns if the Quaternion is a unit Quaternion. - bool isUnit() const { - return swwm_GM_GlobalMaths.closeEnough(w * w + x * x + y * y + z * z, 1); - } - - /// Returns if the Quaternion is an identity Quaternion. - bool isIdentity() const { - return swwm_GM_GlobalMaths.closeEnough(w, 1) && swwm_GM_GlobalMaths.closeEnough(x, 0) && - swwm_GM_GlobalMaths.closeEnough(y, 0) && swwm_GM_GlobalMaths.closeEnough(z, 0) ; - } - - /// Returns the dot product of two Quaternions. - double dotProduct(swwm_GM_Quaternion other) const { - return (w * other.w + x * other.x + y * other.y + z * other.z); - } - - /// Copies another Quaternion into this one. - void copy(swwm_GM_Quaternion other) { - w = other.w; - x = other.x; - y = other.y; - z = other.z; - } - - /// Rotates a Vector3 using this Quaternion. - Vector3 rotateVector3(Vector3 vec) const { - swwm_GM_Quaternion q = unit(); - - Vector3 u = (q.x, q.y, q.z); - double s = q.w; - - return 2 * (u dot vec) * u + (s * s - (u dot u)) * vec + 2 * s * u cross vec; - } - - /// Linearly interpolates between two Quaternions, clamping the parameters. - static swwm_GM_Quaternion lerp(swwm_GM_Quaternion from, swwm_GM_Quaternion to, double time) { - time = clamp(time, 0, 1); - return lerpUnclamped(from, to, time); - } - - /// Linearly interpolates between two Quaternions. - static swwm_GM_Quaternion lerpUnclamped(swwm_GM_Quaternion from, swwm_GM_Quaternion to, double time) { - swwm_GM_Quaternion ret = new("swwm_GM_Quaternion"); - double reverseTime = 1 - time; - ret.x = reverseTime * from.x + time * to.x; - ret.y = reverseTime * from.y + time * to.y; - ret.z = reverseTime * from.z + time * to.z; - ret.w = reverseTime * from.w + time * to.w; - ret = ret.unit(); - return ret; - } - - /// Spherically interpolates between two Quaternions, clamping the parameters. - static swwm_GM_Quaternion slerp(swwm_GM_Quaternion from, swwm_GM_Quaternion to, double time) { - time = clamp(time, 0, 1); - return slerpUnclamped(from, to, time); - } - - /// Spherically interpolates between two Quaternions. - static swwm_GM_Quaternion slerpUnclamped(swwm_GM_Quaternion from, swwm_GM_Quaternion to, double time) { - swwm_GM_Quaternion q3; - double fromToDot = from.dotProduct(to); - - if (fromToDot < 0) { - fromToDot = -fromToDot; - q3 = to.negate(); - } - else { - q3 = to; - } - - if (fromToDot < 0.95) { - double angle = acos(fromToDot); - return ((from.multiplyScalar(sin(angle * (1 - time)))).add(q3.multiplyScalar(sin(angle * time)))).multiplyScalar(1 / sin(angle)); - } - else { - return lerp(from, q3, time); - } - } - - /// Returns the 0 Quaternion. - static swwm_GM_Quaternion zero() { - return new("swwm_GM_Quaternion").init(0, 0, 0, 0); - } - - /// Returns the identity Quaternion. - static swwm_GM_Quaternion identity() { - return new("swwm_GM_Quaternion").init(1, 0, 0, 0); - } -} diff --git a/zscript/swwm_Gutamatics/VectorUtil.zsc b/zscript/swwm_Gutamatics/VectorUtil.zsc deleted file mode 100644 index c720cf5ef..000000000 --- a/zscript/swwm_Gutamatics/VectorUtil.zsc +++ /dev/null @@ -1,29 +0,0 @@ -class swwm_GM_VectorUtil { - /// Linearly interpolates between two Vector3s, clamping the parameters. - static Vector3 lerpVec3(Vector3 from, Vector3 to, double time) { - time = clamp(time, 0, 1); - return lerpUnclampedVec3(from, to, time); - } - - /// Linearly interpolates between two Vector3s. - static Vector3 lerpUnclampedVec3(Vector3 from, Vector3 to, double time) { - Vector3 ret; - double reverseTime = 1 - time; - ret = reverseTime * from + time * to; - return ret; - } - - /// Linearly interpolates between two Vector2s, clamping the parameters. - static Vector2 lerpVec2(Vector2 from, Vector2 to, double time) { - time = clamp(time, 0, 1); - return lerpUnclampedVec2(from, to, time); - } - - /// Linearly interpolates between two Vector2s. - static Vector2 lerpUnclampedVec2(Vector2 from, Vector2 to, double time) { - Vector2 ret; - double reverseTime = 1 - time; - ret = reverseTime * from + time * to; - return ret; - } -} diff --git a/zscript/utility/swwm_utility_math.zsc b/zscript/utility/swwm_utility_math.zsc index 902c64185..a8fae274e 100644 --- a/zscript/utility/swwm_utility_math.zsc +++ b/zscript/utility/swwm_utility_math.zsc @@ -1,25 +1,32 @@ -// math stuff + gutamatics caching +// math stuff Struct SWWMProjectionData { - swwm_GM_Matrix wtc; + double tanfovx, tanfovy; + Vector3 viewpos, z, x, y; int viewx, viewy, vieww, viewh; } extend Class SWWMUtility { - // gutamatics caching + // cache some data that requires trig and quat math static void PrepareProjData( SWWMProjectionData &d, Vector3 viewpos, double angle, double pitch, double roll, double fov ) { + // store for internal use + d.viewpos = viewpos; + // precalc vfov/hfov tangents + // (vfov in gzdoom has a small quirk to it) double aspect = Screen.GetAspectRatio(); - // vertical fov double fovratio = (aspect>=1.3)?1.333333:aspect; - double fovy = 2.*atan(tan(clamp(fov,5,170)/2.)/fovratio); - // world→clip matrix - swwm_GM_Matrix view = swwm_GM_Matrix.view(viewpos,angle,pitch,roll); - swwm_GM_Matrix perp = swwm_GM_Matrix.perspective(fovy,aspect,5,65535); - d.wtc = perp.multiplyMatrix(view); - // screen coord data + d.tanfovy = tan(clamp(fov,5,170)/2.)/fovratio; + d.tanfovx = d.tanfovy*aspect; + // precalc view-space axes + // (don't forget pixel stretch, very important) + Quat r = Quat.FromAngles(angle,pitch,roll); + d.z = r*(1.,0.,0.); + d.x = r*(0.,1.,0.); + d.y = r*(0.,0.,level.pixelstretch); + // precalc view origin and clip int sblocks = CVar.FindCVar('screenblocks').GetInt(); let [viewx, viewy, vieww, viewh] = Screen.GetViewWindow(); int sh = Screen.GetHeight(); @@ -32,14 +39,36 @@ extend Class SWWMUtility d.viewh = h; } - static Vector3 ProjectPoint( SWWMProjectionData d, Vector3 worldpos ) + // simple projection without matrices, translated from old UnrealScript work + // bFast: quit early if point is behind screen, for cases where behind-view coords are not really needed + static Vector3 ProjectPoint( SWWMProjectionData d, Vector3 worldpos, bool bFast = true ) { - return d.wtc.multiplyVector3(worldpos).asVector3(); + Vector3 tdir = worldpos-d.viewpos; + // early bail, skip behind-view points + if ( bFast && (d.z dot tdir <= 0.) ) + return (0.,0.,0.); + double dist = tdir.length(); + // points are pretty much equal, skip projection + if ( dist <= double.epsilon ) + return (0.,0.,0.); + tdir /= dist; + Vector3 dir = d.z*(tdir dot d.z); + // I don't understand this math, but it works? + Vector3 xy = tdir-dir; + double dx = xy dot d.x; + double dy = xy dot d.y; + double dlen = dir.length(); + // guard against division by zero here? + if ( dlen <= double.epsilon ) + return (0.,0.,0.); + double tanx = dx/dlen; + double tany = dy/dlen; + return (1.-tanx/d.tanfovx,1.-tany/d.tanfovy,dir dot d.z); } - static Vector2 NDCToViewport( SWWMProjectionData d, Vector3 ndc ) + static Vector2 NDCToViewport( SWWMProjectionData d, Vector3 cpos ) { - return (d.viewx,d.viewy)+(((ndc.x+1)*d.vieww)/2,((-ndc.y+1)*d.viewh)/2); + return (d.viewx+(cpos.x*.5*d.vieww),d.viewy+(cpos.y*.5*d.viewh)); } // checks if a point is inside the viewport @@ -95,7 +124,12 @@ extend Class SWWMUtility return r*(1,0,0), r*(0,-1,0), r*(0,0,1); } - // included here until Gutamatics updates to use native quaternions + static double Normalize180( double angle ) + { + angle = ((angle%360.)+360.)%360.; + return (angle>180.)?(angle-360.):(angle); + } + static double, double, double ToAngles( Quat q ) { double angle = 0., pitch = 0., roll = 0.; @@ -106,13 +140,13 @@ extend Class SWWMUtility { angle = atan2(angY,angX); pitch = 90.; - roll = swwm_GM_GlobalMaths.Normalize180(angle+(2.*atan2(q.x,q.w))); + roll = Normalize180(angle+(2.*atan2(q.x,q.w))); } else if ( stest > .4999995 ) { angle = atan2(angY,angX); pitch = -90.; - roll = swwm_GM_GlobalMaths.Normalize180(angle+(2.*atan2(q.x,q.w))); + roll = Normalize180(angle+(2.*atan2(q.x,q.w))); } else { diff --git a/zscript/weapons/swwm_blazeit.zsc b/zscript/weapons/swwm_blazeit.zsc index b760916c6..e10544f18 100644 --- a/zscript/weapons/swwm_blazeit.zsc +++ b/zscript/weapons/swwm_blazeit.zsc @@ -45,7 +45,7 @@ Class Hellblazer : SWWMWeapon if ( !seektarget[i] ) continue; Vector3 tpos = SWWMUtility.LerpVector3(seektarget[i].prev,seektarget[i].pos,e.FracTic); Vector3 ndc = SWWMUtility.ProjectPoint(projdata,e.viewpos+level.Vec3Diff(e.viewpos,tpos+(0,0,seektarget[i].Height/2))); - if ( ndc.z > 1. ) continue; + if ( ndc.z <= 0. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc); Screen.DrawTexture(LockIcon,false,vpos.x/hs,vpos.y/hs,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_CenterOffset,true,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright); }