Page 6 of 8

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sat Mar 04, 2017 8:03 am
by Major Cooke
Not trying to rain on your parade but:

  1. Consider using a regular zip file instead of .7z so people can open it up with SLADE.
  2. I don't really see what purpose this may serve, honestly.

Maybe I'm just blind to what it could be for, but one could easily replace it with something like this:

Code: Select allExpand view
if (!master) return Destroy();
double mpitch = master.pitch;
double mang = master.angle;
Vector3 StickerPos = master.Vec3Angle(cos(mpitch) * 20, mang, -sin(mpitch) * 20);
SetOrigin(StickerPos);


And if you just want the roughest degree to be a whole number, turn mpitch and mang into ints.

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sat Mar 04, 2017 12:13 pm
by Matt
You're also the guy who told me it wouldn't make any difference making the same calculation 6 times in a row as opposed to storing a variable.

However, I did finally get around to benchmarking it:
Code: Select allExpand view
class CrudeSiner:IdleDummy{
   states{
   spawn:
      BAL1 A 1 nodelay{
         for(int i=0;i<10000000;i++){
            speed=(HDLib.CrudeSine(self,24));
         }
         A_LogInt(speed*1000);
      }wait;
   }
}
class FineSiner:IdleDummy{
   states{
   spawn:
      BAL1 A 1 nodelay{
         for(int i=0;i<10000000;i++){
            speed=(sin(24));
         }
         A_LogInt(speed*1000);
      }wait;
   }
}
and while the native sin function on the bottom got me around 1300ms per frame, that number went up to over 27000ms with the lookup table, so unfortunately it is useless.

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sat Mar 04, 2017 12:30 pm
by Major Cooke
I was in a rush, didn't read it properly, that's all. I thought it was an organization thing you were asking, not what you had originally asked.

Anyway, yes. I figured the sine table would've been problematic, and that's why I suggested the other thing.

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sat Mar 04, 2017 12:38 pm
by Gez
Vaecrius wrote:while the native sin function on the bottom got me around 1300ms per frame, that number went up to over 27000ms with the lookup table, so unfortunately it is useless.

Yeah, the overhead from calling a VM function is so great that the gain from using a precomputed table is irrelevant.

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sat Mar 04, 2017 1:07 pm
by ZZYZX
What happens if you use an array without a function, like sintab[int(angle)%360]? Does it give any performance boost?

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sat Mar 04, 2017 3:12 pm
by Matt
How do you do that, though? Please don't tell me we need to do sintab[0]=0 all the way through 360...

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sat Mar 04, 2017 3:19 pm
by ZZYZX
Fill it somehow. For example, on BeginPlay of a persistent thinker. for (int i = 0; i < 360; i++) sintab[i] = sin(i);

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sat Mar 04, 2017 3:50 pm
by Matt
> asks how to process a large group of numbers on a computer
> use the computer

:oops:

Anyway:
Code: Select allExpand view
/*
vid_fps 1;summon cs;
vid_fps 1;summon fs;
*/

class cs:Actor{
   double sintab[360];
   states{
   spawn:
      BAL1 A 10 nodelay{
         for(int i=0;i<360;i++){
            sintab[i]=sin(i);
         }
      }
      BAL1 A 1{
         for(int i=0;i<10000000;i++){
            speed=sintab[24];
         }
         A_LogInt(speed*1000);
      }wait;
   }
}
class fs:Actor{
   states{
   spawn:
      BAL1 A 10;
      BAL1 A 1{
         for(int i=0;i<10000000;i++){
            speed=sin(24);
         }
         A_LogInt(speed*1000);
      }wait;
   }
}


cs:~1550 ms/frame

fs: ~1440 ms/frame

So the native sine calculation is still faster.

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sun Mar 05, 2017 12:32 am
by Nash
Vaecrius wrote:How do you do that, though? Please don't tell me we need to do sintab[0]=0 all the way through 360...


Make a Console.Printf that writes code for you, and use Logfile before you execute it.

This was what I did to pre-generate array assignments for ~379,000 x 3 variables. It generated a 112 MB ZScript source file. >8D Of course, as I found out, the program actually froze at startup as it tried to compile...

So to answer the question, no, pre-generating your arrays probably won't help either.

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sun Mar 05, 2017 1:25 am
by Matt
Could your situation have been helped if you somehow broke it up so you only did like a few dozen lines per tic or something?

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sun Mar 05, 2017 1:32 am
by Nash
Hmm actually my situation is a little different. There were 379k things placed in the map. The map editor would crash if I attempted to add more.

So I had the idea that, instead of pre-placing the things and then at World Load, do a 379-thousand-step for loop to fill in the array (like what you did above)... what if I pre-generate the coordinates and classes into an array list. So I can delete all the things in the map, and the trees would have been "placed" via array definitions instead.

There's no way I'm going to type 379,000 times tree[0].x, tree[0].y, tree[0].class "blah"... so I used a Console.Printf and +logfile to help write code for me. x3

That wasn't a good idea at all, because the program won't even start.

The for loop on map load was actually faster, MUCH faster!

Anyway it wasn't a serious project, just wanted to mess around with ZScript and see what works and what doesn't.

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sun Mar 05, 2017 11:10 am
by ZZYZX
Nash wrote:Make a Console.Printf that writes code for you, and use Logfile before you execute it.

This was what I did to pre-generate array assignments for ~379,000 x 3 variables. It generated a 112 MB ZScript source file. >8D Of course, as I found out, the program actually froze at startup as it tried to compile...

So to answer the question, no, pre-generating your arrays probably won't help either.

Or write a Python script already and stop trying to use ZScript as a general purpose language :P
At least not until file(lump) reading/writing is done properly, lol.

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Sun Mar 05, 2017 12:51 pm
by Graf Zahl
Vaecrius wrote:and while the native sin function on the bottom got me around 1300ms per frame, that number went up to over 27000ms with the lookup table, so unfortunately it is useless.


The native sine function already uses a table, so you'll have a very hard time beating that. I optimized the hell out of it and it's possibly the most precise fast sine function you'll ever get.
And that doesn't even factor in the VM overhead for calling a script function, which alone is a lot more than the sine function requires to do its job.

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Tue Mar 07, 2017 6:59 pm
by Matt
Good to know! I did notice in my subsequent attempts to benchmark stuff that sine functions were abnormally fast compared to what I had been expecting relative to everything else.

(Though I suppose given how relevant these calculations are to projectiles, movement, weapon bobbing, etc. etc. etc. I guess I shouldn't have expected anything less!)

Re: ZScript "Standard Library" - Brainstorming

PostPosted: Fri Mar 24, 2017 1:37 pm
by ZZYZX
Hello so I made this https://github.com/jewalky/zgui

You can use it like so:
Code: Select allExpand view
class Doom3Element : Element
{
   TextureID mMouseCursor;
   
   override void OnCreate()
   {
      mRect = Rect.FromXYWH(0, 0, Screen.GetWidth(), Screen.GetHeight());
      mScale = 2;
   
      mMouseCursor = TexMan.CheckForTexture("graphics/D3Mouse.png", TexMan.Type_Any);
      AddChild(new('Doom3Doom').Init());
   }

   override void Draw()
   {
      Drawer d = GetDrawer();
      vector2 mouse = GetMouseXY();
      d.DrawTexture(mMouseCursor, false, mouse.x, mouse.y);
   }
}

class Doom3Menu : ListMenu
{
   Element e;

   override void Init(Menu parent, ListMenuDescriptor desc)
   {
      Super.Init(parent, desc);
      DontDim = true;
      
      e = new('Doom3Element').Init();
      e.OnCreate();
   }

   override bool OnUIEvent(UiEvent ev)
   {
      if (e) return e.OnProcessUi(ev);
      return false;
   }
   
   override bool OnInputEvent(InputEvent ev)
   {
      if (e) return e.OnProcessInput(ev);
      return false;
   }

   override void Drawer()
   {
      if (e) e.OnDraw();
   }

   override void Ticker()
   {
      if (e) e.OnTick();
   }
}

What it does: it allows you to have a WM-style hierarchy of Elements with automatic scaling, clipping, text align and wrapping.
Each Element can have a position inside the parent Element (mRect field), and scale of child elements (mScale field). The scale also affects perceived width/height of the Element (the client rect).
Topmost Element has mParent=null which means that it's using the real screen coordinates and scale of 1.0.

Functions exposed to the user are these:
Code: Select allExpand view
   virtual void OnCreate()
   {
      
   }
   
   virtual bool Process(ElementEvent ev)
   {
      return false;
   }
   
   virtual void Tick()
   {
      //
   }
   
   virtual void Draw()
   {
      //
   }

The preferred way of constructing Elements is calling "new ('Element').Init()", for example. That automatically sets certain fields to the initial values, otherwise you might end up with a wild null pointer error.
Unobviously enough, OnCreate is actually called when you add a child element, on the child. For a root element, you have to call OnCreate manually or it won't get a chance to initialize.

You can draw things by receiving an instance of Drawer class:
Code: Select allExpand view
Drawer d = GetDrawer();
And then using it's methods to draw things as opposed to directly using Screen.
Alternatively, you can instantiate a drawer by using
Code: Select allExpand view
Drawer d = Drawer.Create(self);
or even
Code: Select allExpand view
Drawer d = Drawer.CreateMod('Drawer', self);
The latter option is for custom Drawer classes if you want to do some fancy stuff.

Also, the system doesn't care about your input/rendering backend — you can provide OnProcessUi/OnProcessInput/OnTick by an event handler, and OnDraw by DrawPowerup (I blame Graf for consistently removing any ways to draw anything while playing the game and providing no alternative), or you can do all this in a menu.
The system is able to receive mouse input both from UiEvent and InputEvent — the elements will receive an uniform ElementEvent anyway. This means that it transparently supports both enabled and disabled mouse in menus.
ElementEvent is the same as UiEvent, except there is no information about pressed modifier keys (yet?)
Also, you can receive the current mouse coordinates relative to the current element (including all scaling) by using GetMouseXY() — which returns a vector2, see the example.

What it doesn't have yet is setting arbitrary clipping values in a Drawer. That'll be added eventually.
Added, actually.

The system is kinda new and untested, pls report bugs if anyone is actually going to use this.