Expression Lab - interactive expression display

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
misol101
Posts: 448
Joined: 02 May 2016 18:20

Expression Lab - interactive expression display

#1 Post by misol101 » 20 Jun 2020 09:54

Image
A tunnel (66 FPS captured at 8 FPS)
Image
Still images of four expressions

What is it?
Expression Lab is a small batch script layer on top of Cmdgfx_RGB (1.6, unreleased) which allows to write (RGB color) expressions and see them animate immediately in real time.
As well as making my own, I thought it would be fun to see if some DosTips users could come up with interesting animations. I know many of you would have no problem of doing so (if interested).

How does it work?
After running ExpressionLab.bat, you can either:
1. Browse the 48 examples with cursor left/right. The examples are divided into 2 sets of ~20 examples each, press 'm' to switch between sets.
2. Press 'Enter' to open the interactive expression lab, which is just a prompt. (It's possible to have several such windows open at the same time). Write an expression in the window, press Enter, see results (or errors). Note that after pressing Enter, the script tries to restore both your previous input as well as the previous cursor position (the latter may take ~1s). Also note that since it is a prompt, you have command history available in the window.

But how do the expressions work?
So basically, like a fragment shader, the expression runs for every character in the window, and the only real input you get is the x and y position of the current character. From this, all kinds of colors and animations blooms through the use of math. Everything has to be composed in a single line, no spaces, and the result should be a 24-bit RGB (red/green/blue) value.
Apart from the x and y position, ExpressionLab also injects the following data that can be used in expressions:

Code: Select all

x: current x position (column)
y: current y position (row)
A1 : a counter increasing by 1 every frame
A2: a counter decreasing by 2 every frame
C1: sin(A1 degrees)*367 (stupid decision, *255 would have been better but too annoying to change now)
C2: sin(A2 degrees)*342 (as above)
L1: a counter that goes from 0 to 255 and then restarts 
SCRW: the width in characters of the current window
SCRH: the height in characters of the current window
s0-s9: Not filled in by the script, these are the variables used for (temporary) storage inside expressions
Which math or other functions are available?
Currently, these (I skipped some that are useless in this context):

Code: Select all

Standard math:  abs, acos, asin, atan, atan2, ceil, cos, cosh, e, exp, floor, ln, log, log10, pi, pow, sin, sinh, sqrt, tan, tanh

Add-on math:  random, or, and, xor, neg, shl, shr, max, min, mod, clamp, sign, clamp255, length, frac, perlin

Conditional (these return 1 if true, otherwise 0): eq, neq, gtr, lss, geq, leq

Sampling functions (returns color at given position): col (fgcol, bgcol)

Storing temporary values: store (always returns 0. 2 parameters, first is the value, second is index of storage 0-9. So store(5+9,1) would store 14 in s1 )

Getting color components (red/green/blue) of color: fgr, fgg, fgb

Composing colors: makecol, makecol255, shade, blend (plus several more I left out)
Limitations?
As mentioned, everything must be on a single line, no spaces. No looping is possible (though you could unroll loops like I did for the Julia fractal). An expression must be minimum 2 characters. No self-defined functions. Also as mentioned, there are only 10 variables for temp storage.

Examples?
Yes, very much needed I think...

Let's start super simple:

Code: Select all

y+0
This results in a nice, blue shade, black at the top and getting more blue every row. Why blue? Because the first byte of the 24-bit output is the blue component.

Next up:

Code: Select all

y*5
This also results in a blue shade, but it restarts from 0 halfway down. That's because it overflows and becomes larger than 255, the biggest possible red, green or blue value.
To help this, we could use e.g. the clamp255 function, which clamps the value between 0-255. But it's better to get acquainted with the makecol255 function:

Code: Select all

makecol255(y*5,y,y*2)
Now we get a pinkish shade, which is clamped from 0-255 for each color component. First is y*5, the red channel, then y for green, then y*2 for blue.

But what if the expression was complex and we just wanted to adjust it a bit for each color component? That's where store comes in:

Code: Select all

store(x/1.6+max(x/2,y)*2,0)+makecol255(s0,s0/1.5,s0*1.4)
Ok, but the picture is static? How to animate it?
Use A1/A2,C1/C2/L1 in the math expression. C1 and C2 (the sinus values) are good for quickly getting something running, e.g.:

Code: Select all

store(x/1.6+max(x/2,y+C2/6)*2,0)+makecol255(s0,s0/4.5+C1/5,s0*1.4)
Here C2 is used to animate movement, and C1 to animate the (green component) color.

Finally you might end up with something like the colorized tunnel from the first still image above:

Code: Select all

store(A1/20,4)+store(x/SCRW-0.5+sin(s4/2.7)*0.2,0)+store(y/1.6/SCRH-0.3+cos(s4/3)*0.11,1)+store(length(s0,s1),2)+store(atan2(s0,s1)+s4*0.3,0)+store(0.3/s2+s4*0.5,1)+store(perlin(sin(s0)*(2+sin(A1/150)*3)*1+s1*2,s1*2)*s2*s2*2.8,3)+makecol255(s3*10000+sin(s0)*s2*1000,10+abs(s3)*1500+sin(s0*3)*s2*250,abs(s3)*4600+sin(s0*2)*750*s2)
Attachments
ExpressionLab.zip
(400.86 KiB) Downloaded 7 times
Last edited by misol101 on 06 Jul 2020 14:44, edited 14 times in total.

T3RRY
Posts: 40
Joined: 06 May 2020 10:14

Re: Expression Lab - interactive expression display

#2 Post by T3RRY » 20 Jun 2020 11:18

I'm going to spend a few nights without sleep trying this out I think... Cant wait!

misol101
Posts: 448
Joined: 02 May 2016 18:20

Re: Expression Lab - interactive expression display

#3 Post by misol101 » 20 Jun 2020 11:24

Of course, not everything about the functions available, quirks, implementation etc can be captured in so few words. But there are many examples available to look at, or just ask if interested :)

When browsing the examples, the index of the effect is written in the title, last part. It is easy to go into the script and copy/paste the corresponding index expression into the expression popup window, and play around with it.

There are also a bunch of keys that can be used in the main window:

Code: Select all

Documented (mentioned in the help text in the title):

Enter: expression popup window
Left: Previous expression
Right: Next expression
m: switch set
t: switch character set (basically)
c: use standard 16 color palette only
d: toggle show current running expression
p: pause
1-9: change font (1-5 regular, 6-9 pixel fonts)

"Undocumented":

Alt-Enter or Ctrl-Enter: toggle fullscreen
w: change wrapping mode (ignore/clamp/repeat). Changes behaviour of sampling, used in expression 1-5 of set 2.
W: remove/restore FPS limit
T: switch threading use off/on
f: show FPS on/off
S: save current LAB expression to outExpr.txt (useful if you accidentally closed the popup and didn't copy the expression first)
i: toggle use of background image (only visible if you use "col" in your expression)
Last edited by misol101 on 06 Jul 2020 14:42, edited 4 times in total.

misol101
Posts: 448
Joined: 02 May 2016 18:20

Re: Expression Lab - interactive expression display

#4 Post by misol101 » 20 Jun 2020 11:26

T3RRY wrote:
20 Jun 2020 11:18
I'm going to spend a few nights without sleep trying this out I think... Cant wait!
Awesome! :D (except I forgot to add the attachment file... :oops: fixed now :) )

T3RRY
Posts: 40
Joined: 06 May 2020 10:14

Re: Expression Lab - interactive expression display

#5 Post by T3RRY » 20 Jun 2020 11:42

Working well for the most part, Still an issue with scaling over 100% though. Still going to have plenty of fun with this.

misol101
Posts: 448
Joined: 02 May 2016 18:20

Re: Expression Lab - interactive expression display

#6 Post by misol101 » 20 Jun 2020 11:48

T3RRY wrote:
20 Jun 2020 11:42
Working well for the most part, Still an issue with scaling over 100% though. Still going to have plenty of fun with this.
Hmm, annoying, thought it would be fixed now with latest CmdWiz... anyway, better for another thread maybe or I'll PM you later

EDIT: archive above replaced, should be ok also for scaled screens now (though properly supporting this fully is more complicated than I thought... not completely trusting my estimation of the window height atm, so moved help text into the title :) )

misol101
Posts: 448
Joined: 02 May 2016 18:20

Re: Expression Lab - interactive expression display

#7 Post by misol101 » 21 Jun 2020 00:56

While on the subject of scaling:

The rendering window can be resized freely without problems, and you can enter Fullscreen with Alt-Enter or Ctrl-Enter (pray for a strong CPU...). To make the output scale with screen size (if wanted), you should scale x and y to lie within 0...1 in the beginning of the expression, like so (after this, scaled x and y are in s0 and s1):

Code: Select all

store(x/SCRW,0)+store(y/SCRH,1)

T3RRY
Posts: 40
Joined: 06 May 2020 10:14

Re: Expression Lab - interactive expression display

#8 Post by T3RRY » 21 Jun 2020 02:04

The scaling issue I was experiencing is when screen display is set to factors other than 100%. Different resolutions work fine so long as the scale is 100%, and when at factors over 100% the fullscreen mode kicks in though with the animation at a reduced size within the console.

I've developed my own formula for dealing with screen positioning in my scripts that accounts for scaling, however it's not foolproof - If the registry value containing the screen scale has not been updated, the scripts calculations return incorrect values. (It was very annoying having to restart every time I changed scale to test the formula.)

In my efforts I've found (with a fair degree of trial and error) Determining the available scaled console dimension requires the Following values and Calculations:

Code: Select all

::: { Get screen Dimensions
	For /f "delims=" %%# in  ('"wmic path Win32_VideoController get CurrentHorizontalResolution,CurrentVerticalResolution /format:value"') do (
		Set "%%#">nul
	)
::: - Calculate scale Factor in effect. Registry value requires restart to update if scale has changed.
	For /F "Tokens=3 Delims= " %%A in ('REG QUERY "HKCU\Control Panel\Desktop\WindowMetrics" /V AppliedDPI') Do Set /A SF=%%A / 100 + 1
::: - Get Font Size
	(For /F "Delims=" %%S in ('dir GetFontSize.exe /B /S') Do (%%S)) 2> Nul
	Set /A "Font.H=%errorlevel% >> 16, Font.W=%errorlevel% & 0xFF"
	Set /A Max.Width= ( CurrentHorizontalResolution / ( Font.W * SF ) )
	Set /A Max.hieght= ( ( CurrentVerticalResolution / Font.H ) / SF ) - 4
::: }
The above determines the maximum lines and columns based on the relationship between resolution, Fontsize and Scale Factor, with 4 lines being trimmed from the hieght value to allow for the Title Bar and Windows Start Bar.

I then use the Following Subroutine to relaunch the batch using a vbs script at the coordinates required to centre it.

Code: Select all

:ChangeConsole <Lines> <Columns> <Label to Resume From> <If a 4th parameter is Defined, Aligns screen at top left>
::: - Calculation of X axis relative to screen resolution and console size. Resolution scales to Max Columns.
	Set /A XresScale= CurrentHorizontalResolution / Max.Width
	Set /A HorzCentre= CurrentHorizontalResolution / 2
	Set /A CentreX= HorzCentre - ( ( %~2 * XresScale ) / 2 )
::: - Calculation of Y axis relative to screen resolution and console size. Resolution scales to Max Lines.
	Set /A YresScale= CurrentVerticalResolution / Max.hieght
	Set /A VertCentre= CurrentVerticalResolution / 2
	Set /A CentreY= VertCentre - ( ( %~1 * YresScale ) / 2 )
::: - Optional 4th parameter can be used to align console at top left of screen instead of screen centre
	If Not "%~4"=="" (Set /A CentreY=0,CentreX=-8)
	>"%TEMP%\paintMH.sav" ECHO/%~1
	>"%TEMP%\paintMW.sav" ECHO/%~2
::: - Creates a batch file to reopen the main script using Call with parameters to define properties for console change and the label to resume from.
	(
	Echo.@Mode Con: lines=%~1 cols=%~2
	Echo.@Title %ProgName%
	Echo.@Call "%ThisFile%" "%~1" "%~2" "%~3" "%ThisFile%" 
	)>"%temp%\ChangeConsole.bat"
::: - .Vbs script creation
	(
	Echo.Set objWMIService = GetObject^("winmgmts:\\.\root\cimv2"^)
	Echo.Set objConfig = objWMIService.Get^("Win32_ProcessStartup"^)
	Echo.objConfig.SpawnInstance_
	Echo.objConfig.X = %CentreX%
	Echo.objConfig.Y = %CentreY%
	Echo.Set objNewProcess = objWMIService.Get^("Win32_Process"^)
	Echo.intReturn = objNewProcess.Create^("%temp%\ChangeConsole.bat", Null, objConfig, intProcessID^)
	)>"%temp%\Consolepos.vbs"
::: - .Vbs Starts the companion batch script to Change Console properties, ends the parent.
	Start "" "%temp%\Consolepos.vbs" & Exit
::: }
Edit:
Have updated the archive and window size is greatly improved and position is perfectly centered.
Edit 2:
Spoke too soon, Positioning works for Scales of 100% and 300 %, failed for 200% (Winds up in Far Low right corner of screen)

misol101
Posts: 448
Joined: 02 May 2016 18:20

Re: Expression Lab - interactive expression display

#9 Post by misol101 » 21 Jun 2020 08:12

Thanks T3rry! Seems almost absurd that it would work for 300% scale but not 200%, but obviously there is some reason. I can only test it for 125,150 and 175% here it seems (and it works), Windows settings won't allow me to go higher. Anyway, let's continue the scaling issue discussion in PM as it is a bit off-topic here.

Your solution seems good but a bit too complicated for what I would like... but helpful for sure

misol101
Posts: 448
Joined: 02 May 2016 18:20

Re: Expression Lab - interactive expression display

#10 Post by misol101 » 23 Jun 2020 09:18

Replaced the archive because:

1. It wasn't writing the effect index in the title (which it does now)

2. Added support for using a background image in the expression, either for an image effect or as a texture. This has to be enabled with the 'i' key if using it for your own expressions. Also, even if enabled, the image will only be visible if the "col" function is used in the expression to sample the image. It can be seen in set 0:index 20-22, (and, if user enabled, in set 1:index 0-4). (Simple way to see the image in your own expression: press 'i', then return, then write expression: col(x,y)

Not many takers so far, but I still have hope :) Here are a few "base expressions" for the lab that might be useful as a starting point:

Xor:

Code: Select all

xor(x,y)
Image

Pink shade:

Code: Select all

makecol255(y*5,y,y*2)
Image

Perlin noise:

Code: Select all

abs(perlin(x/40,y/40))*500
Image

Chess board:

Code: Select all

mod(floor(x/20)+floor(y/15),2)*255
Image

(Moving) strobes:

Code: Select all

clamp255(sin(atan2(x/SCRW-0.5,y/SCRH-0.5)*4+A1/10)*250)
Image

Sphere that scales to window size:

Code: Select all

store(x/SCRW-0.5,0)+store(y/SCRH-0.5,1)+store(255-pow(length(s0,s1)*35,2),2)+makecol255(s2,s2,s2)
Image

misol101
Posts: 448
Joined: 02 May 2016 18:20

Re: Expression Lab - interactive expression display

#11 Post by misol101 » 30 Jun 2020 06:41

Replaced archive one more time due to:

1. Fixed bugs in Cmdgfx in "mod" function, and negative wrapping.
2. Added 6 new expressions, removed 2 boring ones
3. Added a second texture, 'i' button now selects no texture or texture 1-2.
4. Upped the number of temporary storage variables to 10 (s0-s9)
5. Improved (hopefully) scaling support

Image
ring twister, kaleidoscope, bump mapping, twister, lens distortion, bouncing rectangles (all in latest version)

Last version (I suppose). Now I'll wait for T3RRY (and others?) to revive the thread with some neat expressions :mrgreen: It is fun to play with, promise!

misol101
Posts: 448
Joined: 02 May 2016 18:20

Re: Expression Lab - interactive expression display

#12 Post by misol101 » 06 Jul 2020 06:07

Image

Alright, not quite done... I decided to go full circle :mrgreen:

With threading support, block expressions were getting fairly fast, but still... obviously you cannot get close to native code without using native code.

So, I decided to add to cmdgfx the ability to use small, custom-written C DLL "hooks" as color expressions.
Obviously this is not for the casual user since you actually have to write and compile C code, but you do get very high efficiency while writing very little code.

The last 3 examples (first set, index 26,27,28) of the updated archive above now use Dll hooks, making their expressions look something like: "DLL:eextern:julia:A1,A2,C1,C2", which means: try to load eextern.dll, then attempt to run the function "julia".

For example, converting this expression: store(C1/20*sin(x/7)+cos(y/34)*C2/8,1)+makecol(sin(s1/10)+cos(s1/24)*127+127,cos(s1/4)*127+127,0)
to Dll C code:

Code: Select all

int GRY(int w, int h, int yStart, int fullH, DWORD tickCount, int v1, int v2, int v3, int v4, int v5,  unsigned long long *outArray,  unsigned long long *sampleArray) {
	float C1=(float)v3/20, C2=(float)v4/8;

 	for (int y = yStart; y < yStart + h; y++)
	{
		float fxy=cos((float)y/34)*C2;
		for (int x = 0; x < w; x++)
		{
			float s1 = C1*sin((float)x/7) + fxy;
			*outArray++ = ((int)(sin(s1/10)+cos(s1/24)*127+127)<<16) | ((int)(cos(s1/4)*127+127)<<8); 
		}
	}
}
This function will be called as many times per frame as there are threads active, each completing a part of the block. Depending on if cmdgfx_RGB/VT or cmdgfx/_gdi is running, the last two arguments should be either unsigned long long * or unsigned char *.

As expected, using native code instead of interpreted expressions boost speed hugely. It also allows using loops etc. The downside, besides having to compile, is that the helper functions like perlin,makecol255 etc are not available to call, so you would have to roll your own.

As a proof of concept I also included ScreenSaver-GameOfLife-External.bat, which runs Game of Life in fullscreen, using pixel font. At 1920x1080, the expression version ran at ~3 FPS, while the native one ran at ~130 FPS, thus around 40+ times faster.

C code for eextern.dll (5 functions) is included in the archive.


EDIT: re-uploaded again because I added keys 1-9 to switch between fonts (1-5 regular, 6-9 pixel fonts)

Post Reply