Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - zpaolo11x

Pages: [1] 2
Scripting / Check file existance with relative path
« on: November 27, 2018, 12:34:39 AM »
There are many ways to check if a file exists: one is

Code: [Select]
fe.path_test(fullpathfilename , PathTest.IsFile)

another is

Code: [Select]
try {file(fullpathfilename, "r" );return true;}catch(e){return false;}

Both work well if you have a full pathname but, AFAIK, they don't work on relative paths. You can get the AM working directory with FeConfigDirectory, which is fine, but I want to check if a file exists inside a folder of the current theme, without having to hardcode the theme name or having the user insert a variable with the theme full path.

Is there a way or a workaround to get at least the current theme folder name?

Themes / [RELEASED] Genres/Category artwork for Mame
« on: November 19, 2018, 08:56:25 AM »
I've completed a project to implement in the next version of my theme. The idea is to create genre or category icon for all my games. I had some rules to follow:

1) Being my theme Mame and arcade based I tried to find all the category names that are available, in catlist.ini, category.ini, catver.ini etc, then I parsed the genres/subgenre format so that, for example, Sports / Boxings becomes sportsboxing.png.

2) I wanted some retro look and a stylized vibe so I decided to limit myself to 16x16 pixels artwork with only one "color" (plus transparent background).

I decided to do all the subgenres and not only the main category, you can see a preview of the artwork here:

Overall it's great fun trying to convey a category idea with that reduced resolution, also because if you want to reference a famous game for the genre sometimes you need to reinvent and scale down the sprites :)

In the attached archive you'll find all the PNGs in white on transparent (so you can change the color using set_rgb ), plus a nut to incorporate in your layout. The nut contains two function, one is category_pic() and is used as a magic token, so if you want to add a cat image just use

fe.add_image("[!category_pic]", etc

the other function in the nut is category_list() and you can call it at the beginning of your layout, it will output on the console the whole list of categories that are not present in the PNG folder. If you want me to add some just let me know!

Feel free to incorporate this icons (with credit) in your works and let me know if you like them :)

Themes / Brands monochrome logos
« on: October 22, 2018, 07:52:08 AM »
I'm working on a collection of monochrome logos from arcade brands, I took sources from many places, worked on reducing colors and cleaning up shapes, and adapted every logo to a 800x400 PNG image. The idea is to use them in a theme, so I wrote a routine that gets the brand name and produces an equivalent file name, stripping spaces and unnecessary characters.

So for example if the manufacturer is "Taito Corporation" the file will be taitocorporation.png, or if the manufacturer is "Raizing / Eighting" the file will be raizingeighting.png.

For licensed games I have yet to decide if it's better to strip the license data altogether or, as it is now, parse it so that "Cave (AMI Licens)" becomes caveamilicense.png.

I'm still gathering logos and working on the art, attached a sneak preview of the first 100 logos :D

Scripting / GLSL colorizer and color conversion routines
« on: October 09, 2018, 07:46:44 AM »
I jsut developed a small shader for colorizing, it uses HSL color space which looks much better than HSV. But in the code you can find some useful color conversion functions that you can use for many purposes like desaturation, hue rotation etc.

The shader requires an HSL vector of three values that are used for colorizing, plus a texture mix value if you want to blend (in RGB) the colorized with the default image.

Code: [Select]
uniform sampler2D texture;
uniform vec3 hsl;
uniform float texmix;

vec3 hsl2rgb( in vec3 c )
    vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );
    return c.z + c.y * (rgb-0.5)*(1.0-abs(2.0*c.z-1.0));

vec3 rgb2hsl( in vec3 c ){
  float h = 0.0;
float s = 0.0;
float l = 0.0;
float r = c.r;
float g = c.g;
float b = c.b;
float cMin = min( r, min( g, b ) );
float cMax = max( r, max( g, b ) );

l = ( cMax + cMin ) / 2.0;
if ( cMax > cMin ) {
float cDelta = cMax - cMin;
        //s = l < .05 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); Original
s = l < .0 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) );
if ( r == cMax ) {
h = ( g - b ) / cDelta;
} else if ( g == cMax ) {
h = 2.0 + ( b - r ) / cDelta;
} else {
h = 4.0 + ( r - g ) / cDelta;

if ( h < 0.0) {
h += 6.0;
h = h / 6.0;
return vec3( h, s, l );

vec3 rgb2hsv(vec3 c)
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(, K.wz), vec4(, K.xy), step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));

    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);

vec3 hsv2rgb(vec3 c)
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract( + * 6.0 - K.www);
    return c.z * mix(, clamp(p -, 0.0, 1.0), c.y);

void main()

vec2 uv = gl_TexCoord[0].xy;

vec4 t0 = texture2D(texture, uv);
vec3 hsl0 = rgb2hsl (t0.rgb);

vec3 hsl1 = vec3(hsl.x,hsl.y,hsl0.z);

vec3 tch = hsl2rgb (hsl1);

gl_FragColor = vec4(mix(hsl.z*,,texmix) , gl_Color.a*t0.a);


This is a sample layout

Code: [Select]
local pic1 = fe.add_artwork("snap",0,0,400,400)
pic1.video_flags = Vid.ImagesOnly
pic1.preserve_aspect_ratio = false

local pic2 = fe.add_artwork("snap",400,0,400,400)
pic2.video_flags = Vid.ImagesOnly
pic2.preserve_aspect_ratio = false

local pic3 = fe.add_artwork("snap",800,0,400,400)
pic3.video_flags = Vid.ImagesOnly
pic3.preserve_aspect_ratio = false

local colorshader1 = fe.add_shader(Shader.Fragment,"colorizer.glsl")
pic1.shader = colorshader1

local colorshader2 = fe.add_shader(Shader.Fragment,"colorizer.glsl")
pic2.shader = colorshader2

Scripting / GLSL gaussian blur without nested surfaces
« on: October 08, 2018, 02:19:10 AM »
Inspired by Oomek work with feedback trails, I put together a quick and dirty layout for gaussian blur using a similar trick without need for nested surfaces.

What do you think? It scales down the initial surface so it can work on a lower resolution instance of the picture, but has issues if you turn on aspect ratio (you should then pass the actual resolution to the shader using subimg.x and subimg.y).


Code: [Select]

local picwidth = 64.0
local su0 = fe.add_surface(picwidth,picwidth)
local su1 = fe.add_surface(picwidth,picwidth)

local pic = su0.add_artwork("snap",0,0,picwidth,picwidth)
pic.video_flags = Vid.ImagesOnly
pic.preserve_aspect_ratio = false

local sh0 = fe.add_shader( Shader.Fragment, "gauss_kernsigma_o2.glsl" )
local sh1 = fe.add_shader( Shader.Fragment, "gauss_kernsigma_o2.glsl" )

pic = su0.add_clone (pic)
sh0.set_texture_param( "texture",pic)
sh0.set_param("kernelData", 21.0, 3.0)
sh0.set_param("offsetFactor", 1.0/picwidth, 0.0)
pic.shader = sh0

pic = su1.add_clone (pic)
sh1.set_texture_param( "texture",su0)
sh1.set_param("kernelData", 21.0, 3.0)
sh1.set_param("offsetFactor", 0.0, 1.0/picwidth)
pic.shader = sh1

su0.visible = false
su1.set_pos (0,0,600,600)


Code: [Select]

uniform sampler2D texture;
uniform vec2 kernelData;
uniform vec2 offsetFactor;
uniform float reverse;

void main() {

    vec3 incrementalGaussian;
    incrementalGaussian.x = 1.0 / (sqrt(2.0 * 3.14) * kernelData.y);
    incrementalGaussian.y = exp(-0.5 / (kernelData.y * kernelData.y));
    incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y;

    vec2 uv = gl_TexCoord[0].xy;
    if (reverse == 1.0) {
       uv.y = 1.0 - uv.y;
    vec4 color = vec4(0.0);
    float kersum = 0.0;

    color += texture2D(texture, uv) * incrementalGaussian.x;
    kersum += incrementalGaussian.x;
    incrementalGaussian.xy *= incrementalGaussian.yz;

    for (float i = 1.0 ; i <=   (kernelData.x - 1.0)*0.5 ; i++) {
        color += texture2D(texture, uv - i * offsetFactor ) * incrementalGaussian.x;         
        color += texture2D(texture, uv + i * offsetFactor ) * incrementalGaussian.x;         
        kersum += 2.0 * incrementalGaussian.x;
        incrementalGaussian.xy *= incrementalGaussian.yz;
    gl_FragColor = color/kersum;

Scripting / Frosted glass menu background
« on: October 01, 2018, 01:30:23 AM »
I've worked a bit on this, and it seems I'm very close to have something working, you can see from the screenshots that I managed to make it work both on standard menus (like exit menu called with "esc" button, or filters menu) and on "custom" menus. I jsut need some other trickery to prevent the effect to be "doubled" if you call a standard menu from a custom menu :D

There are still some issues, but most of all I can't find a way to delete the screenshot I generate every time I need to update the background. Any suggestion?

Scripting / Screenshots and how to check if a file exists
« on: September 18, 2018, 01:06:20 AM »
I want to do this: take a screenshot of AM and then load it as an image file.
I can easily write a routine that scans through the AM folder and selects the last screenshot pathname. My idea was to do something like, in a on_signal routine:

generate the screenshot through signal("screenshot")
run through the folder and get the filename
add the filename to the image

The issue is that, as far as I can see, it takes some time to create the screenshot so the routine finds the previous one. Is there a way to wait until the intended file is created?

Scripting / OpenGL versions and Attract Mode
« on: September 14, 2018, 08:37:01 AM »
I'm on a Mac, which of course is a PITA for emulation but I don't want to use Parallels anymore for this :D

My question (maybe a stupid question) is how is OpenGL support implemented in Attract Mode for Mac? I ask this because technically Mac OS supports OpenGL up to a certain level, but for example XQuartz (the X11 display server for Mac OS) only support certain versions of OpenGL, and to add insult to injury in the future Apple is going to deprecate OpenGL in favor of its own Metal framework. I'm not an expert or a programmer, but I'm wondering what would happen of laouts using GLSL filters if Apple removes OpenGL support altogether, and how can I tell what version of GLSL I can use with my setup? Is AttractMode for Mac running on XQuartz?

Scripting / Nested surfaces and speed of update
« on: September 03, 2018, 08:40:23 AM »
I built a simple layout with some examples of nested surfaces. If I run it on my PC I get 60 fps with case 1 (just a single surface), 30 fps with case 2 (two nested surfaces) and about 15 to 20 fps with case 3 (three nested surfaces). You can change the level of "nestyness" in the layout option, I'd like to know how it performs on other machines.

In the past I used some tricks to speed up scrolling in this situations (adding and updating a text item for example) but now I really want to know what is happening and how to speed things up.

Hope someone can help!

Scripting / GLSL shader: how to "downsample" an image?
« on: September 03, 2018, 12:31:46 AM »
Some filters (like blur filters ;) ) work best with a reduced texture size, for example a gaussian blur on a 128x128 pixel image can be smoother with few semples, while the same gaussian blur on a 512 x 512 pixel image requires a lot of samples. In AM I use this trick of adding the 512x512 image on a 128x128 surface, then apply the shader on the surface and rescale it to the desired size.

I'm quite sure that there's a way to write a GLSL shader (vertex?) that downsamples the image before rasterizing it, but I cant' find it, except the use of mipmaps that is so good but doesn't work on my mac :D

Any idea?

Scripting / Shader for sharper pixel upscaler
« on: August 29, 2018, 11:59:46 PM »
I found this site with a neat GLSL fragment shader : it implements a way to enlarge a low resolution, high contrast image obtaining better pixels definition.

It's very clever: when a low resolution image is rendered you usually get linear interpolation between the color values, which looks pretty bad in high contrast pictures (star shaped artifacts). This filter alters the texture coordinate that you are sampling so to reduce and smooth the transition between the color samples. You can apply it to your image using the code below where "texture" is the image, and "resol" is a vector of the picture pixel size (width , height).

To give you an idea I attach a sample with bilinear filtered image on the left, shader filtered image in the middle and original high resolution image on the right (the effect is more visible on low res images so I downsampled the image before)

Code: [Select]
uniform sampler2D texture;
uniform vec2 resol;

void main()

    vec2 uv = gl_TexCoord[0].xy;

    uv = uv*resol + 0.5;

    vec2 i = floor(uv);
    vec2 f = uv - i;
    f = f*f*f*(f*(f*6.0-15.0)+10.0);
    uv = i + f;
    uv = (uv - 0.5)/resol;

    gl_FragColor = texture2D(texture, uv);


By editing the f = f*f*f*(f*(f*6.0-15.0)+10.0); part you can have a sharper effect or a different transition shape.

Scripting / Framerate counter
« on: August 25, 2018, 02:13:23 AM »
There's probably a better way to see if a theme is smooth or not, but this small code allowed me to track the performance of my theme while adding lots and lots of shaders...

Code: [Select]

local monitor = fe.add_text ("",0,0,fe.layout.width,100)
monitor.align = Align.Centre
monitor.set_bg_rgb (255,0,0)
monitor.charsize = 50

local monitor2 = fe.add_text ("",0,0,1,1)
local monitor_tick0 = 0
local monitor_x0 = 0


function monitortick(tick_time){
monitor2.x ++
if (monitor2.x - monitor_x0 == 10) {
monitor.msg = 10000/(tick_time - monitor_tick0)
monitor_tick0 = tick_time
monitor_x0 = monitor2.x

if (monitor2.x >= flw) {
monitor2.x = 0
monitor_x0 = 0

You can add it at the end of your layout, it will create a red banner on the top with a number reporting the current frame rate. It works like this: every tick_callback it moves a text object by one pixel, once the object has moved 10 pixels it calculates the time taken. Ideally if you are on a 60Hz screen you should get a pixel movement every 1/60 of a second and on this basis the framerate is calculated and displayed.

Scripting / mipmap = 1 is a game changer!
« on: August 24, 2018, 01:37:40 AM »
Not only mipmap = 1 improves dramatically the scaling of pictures, but when a GLSL fragment shader is applied to an image with mipmap enabled the fragment shader can sample the desired mipmap level! This is a godsend for smoothnig and blurring filters, and also for averaging and in all those cases where it's better to work with a lower resolution image that is then upscaled. Definitely very cool!

The only issue is what happens on AM 2.3? Is it time to ditch the old good guy and develop only for AM 2.4+? Also, there's probably a way to pass mipmaps to the fragment shader through a vertex shader, but I'm not good enough at GLSL ;D

Scripting / GLSL how to pass an array via set_param
« on: August 20, 2018, 06:38:39 AM »
Is it possible to pass an array of float values with a single "set_param" command? I know I can send a 2D, 3D or 4D vector, but what if I need to send an array of, say, 13 floats? Is it possible?

Scripting / Vertex shader...
« on: August 15, 2018, 09:17:45 AM »
I found this code for a vertex shader, it should be a blur shader AFAIK but there's no example layout so I'm lost at how to call it. Anyone has a clue?

Code: [Select]
/* VBlurVertexShader.glsl */
attribute vec4 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
varying vec2 v_blurTexCoords[14];
void main()
    gl_Position = a_position;
    v_texCoord = a_texCoord;
    v_blurTexCoords[ 0] = v_texCoord + vec2(0.0, -0.028);
    v_blurTexCoords[ 1] = v_texCoord + vec2(0.0, -0.024);
    v_blurTexCoords[ 2] = v_texCoord + vec2(0.0, -0.020);
    v_blurTexCoords[ 3] = v_texCoord + vec2(0.0, -0.016);
    v_blurTexCoords[ 4] = v_texCoord + vec2(0.0, -0.012);
    v_blurTexCoords[ 5] = v_texCoord + vec2(0.0, -0.008);
    v_blurTexCoords[ 6] = v_texCoord + vec2(0.0, -0.004);
    v_blurTexCoords[ 7] = v_texCoord + vec2(0.0,  0.004);
    v_blurTexCoords[ 8] = v_texCoord + vec2(0.0,  0.008);
    v_blurTexCoords[ 9] = v_texCoord + vec2(0.0,  0.012);
    v_blurTexCoords[10] = v_texCoord + vec2(0.0,  0.016);
    v_blurTexCoords[11] = v_texCoord + vec2(0.0,  0.020);
    v_blurTexCoords[12] = v_texCoord + vec2(0.0,  0.024);
    v_blurTexCoords[13] = v_texCoord + vec2(0.0,  0.028);

Pages: [1] 2