Attract-Mode Support Forum
Attract-Mode Support => Themes => Topic started by: verion on December 10, 2015, 01:38:04 AM
-
I'm working on layout that will adapt to screen ratio (responsive) for 16:9 and 16:10 aspects.
Everything is almost finished except that annoying skew/pinch that is somehow related to screen height!
I think the best way to deal with that is to use liquid8d solution - settings table http://forum.attractmode.org/index.php?topic=273.msg1818#msg1818 (http://forum.attractmode.org/index.php?topic=273.msg1818#msg1818)
but... I don't know how to code it properly
Please help me out put it all together into a working code.
Below you'll find a description of what I want to achieve.
==================================
define diffrent coordinate sets for different aspects
==================================
IF (condition #1)
fe.layout.width/fe.layout.height < 1.75 //for 16:10 aspect
THEN DEFINE VARIABLES
local snap_pos_x = 10;
local snap_pos_y = 10;
local snap_width = 400;
local snap_height = 300;
local snap_skew_y = -8;
local snap_skew_x = 42;
local snap_pinch_y = 27;
local snap_pinch_x = 5;
local snap_rotation = 3;
IF (condition #2)
fe.layout.width/fe.layout.height > 1.75 //for 16:9 aspect
THEN DEFINE VARIABLES
local snap_pos_x = 8;
local snap_pos_y = 12;
local snap_width = 420;
local snap_height = 320;
local snap_skew_y = -12;
local snap_skew_x = 32;
local snap_pinch_y = 17;
local snap_pinch_x = 3;
local snap_rotation = 6;
==================================
use that variables sets in layout code
==================================
local snap = fe.add_image( "snap", snap_pos_x, snap_pos_y, snap_width, snap_height);
snap.skew_y = snap_skew_y;
snap.skew_x = snap_skew_x;
snap.pinch_y = snap_pinch_y;
snap.pinch_x = snap_pinch_x;
snap.rotation = snap_rotation;
-
I've been revisiting this with a layout I'm working on now.. it still needs work before I can release an "aspect" module, but here's the idea I'm working with:
local aspect = fe.layout.width / fe.layout.height.tofloat();
switch( aspect )
{
case 1.77778:
aspect = "16x9";
break;
case 1.33333:
aspect = "4x3";
break;
case 0.75:
aspect = "3x4";
break;
}
function Setting( id, name )
{
if ( aspect in settings && id in settings[aspect] && name in settings[aspect][id] )
{
return settings[aspect][id][name];
}
return settings["default"][id][name];
}
local settings = {
"default": {
object1 = { x = 0, y = 0, width = 100, height = 100 }
},
"4x3": {
object1 = { width = 200, height = 200 }
}
}
local this_width = Setting( "object1", "width" );
So define all the default values, and define aspect specific values in the settings table. Then anytime you want a setting for an object, you use the Setting( object_id, attr ) function. You will get the values specific to the current resolution, or the default value if that doesn't exist. This way you can define all settings in defaults, and only ones that change for other aspects in that aspects table.
-
Many thanks - just what I needed!
-
I'm affraid that my cut-and-paste coding skills are not enough to make it work :(
It's not working for me. My code is below:
local aspect = fe.layout.width / fe.layout.height.tofloat();
switch( aspect )
{
case 1.77778:
aspect = "16x9";
break;
case 1.6:
aspect = "16x10";
break;
case 1.33333:
aspect = "4x3";
break;
case 0.75:
aspect = "3x4";
break;
}
function Setting( id, name )
{
if ( aspect in settings && id in settings[aspect] && name in settings[aspect][id] )
{
return settings[aspect][id][name];
}
return settings["default"][id][name];
}
local settings = {
"default": {
cabScreenCoords = { skewY = 42.0, skewY = -8.0, pinchX = 0, pinchY = 29.0, rotate = 0.9 }
},
"16x10": {
cabScreenCoords = { skewY = 62.5, skewY = -12.9, pinchY = 0, pinchY = 40.0, rotate = 1.0 }
}
}
local cabScreen = fe.add_artwork ("snap", flx*0.0615, fly*0.15, flw*0.253, flh*0.221);
cabScreen.skew_x = Setting ( "cabScreenCoords", "skewX" );
cabScreen.skew_y = Setting ( "cabScreenCoords", "skewY" );
cabScreen.pinch_x = Setting ( "cabScreenCoords", "pinchX" );
cabScreen.pinch_y = Setting ( "cabScreenCoords", "pinchY" );
cabScreen.rotation = Setting ( "cabScreenCoords", "rotate" );
-
try using this instead and let me know if you still have issues:
local settings = {
"default": {
cabScreenCoords = { skewY = 42.0, skewY = -8.0, pinchX = 0, pinchY = 29.0, rotate = 0.9 }
},
"16x10": {
cabScreenCoords = { skewY = 62.5, skewY = -12.9, pinchY = 0, pinchY = 40.0, rotate = 1.0 }
}
}
local aspect = fe.layout.width / fe.layout.height.tofloat();
local aspect_name = "";
switch( aspect.tostring() )
{
case "1.77778":
aspect_name = "16x9";
break;
case 1.6:
aspect_name = "16x10";
break;
case "1.33333":
aspect_name = "4x3";
break;
case "0.75":
aspect_name = "3x4";
break;
}
function Setting( id, name )
{
if ( aspect_name in settings && id in settings[aspect_name] && name in settings[aspect_name][id] ) return settings[aspect_name][id][name];
return settings["default"][id][name];
}
-
Thanks, I'll give it a try right away.
-
No, it is not working. :(
I've reduced layout just to that snap and layout screenshot at the background for position check.
It would be great if you could check it out.
It looks that snap skew/pinch is not getting any data (zeros) - it's just straight rectangle.
Maybe it is some kind of a stupid mistake from my side - like missing semicolon or something.
-
//fe.layout.width = 800;
//fe.layout.height = 600;
fe.layout.width = 1280;
fe.layout.height = 720;
local settings = {
"default": {
coords = { x = 0, y = 0, width = 500, height = 30 }
},
"4x3": {
coords = { x = 300, y = 300 }
}
"16x9": {
coords = { x = 300, y = 0 }
},
"16x10": {
coords = { x = 0, y = 300 }
}
}
local aspect = fe.layout.width / fe.layout.height.tofloat();
local aspect_name = "";
switch( aspect.tostring() )
{
case "1.77778":
aspect_name = "16x9";
break;
case 1.6:
aspect_name = "16x10";
break;
case "1.33333":
aspect_name = "4x3";
break;
case "0.75":
aspect_name = "3x4";
break;
}
function Setting( id, name )
{
if ( aspect_name in settings && id in settings[aspect_name] && name in settings[aspect_name][id] )
{
::print("\tusing " + aspect_name + " value for " + id + " : " + name + " : " + settings[aspect_name][id][name] + "\n" );
return settings[aspect_name][id][name];
}
::print("\tusing default value for " + id + " : " + name + " : " + settings["default"][id][name] + "\n" );
return settings["default"][id][name];
}
fe.add_text("[Title]", Setting("coords", "x"), Setting("coords", "y"), Setting("coords", "width"), Setting("coords", "height"));
function on_signal( str )
{
switch( str )
{
case "custom1":
fe.signal("reload");
break;
}
return false;
}
fe.add_signal_handler( this, "on_signal");
This is working for me - I've added print statements so you can see if it is using the aspect values or the default values. You can change the fe.layout.width and fe.layout.height here to get different results. Note with 1.6.2 it looks like there is a glitch if the window isn't focused where the screen isn't getting updated when it reloads, if you are using the custom1 button to reload the layout.
-
strange - it's not working on my side.
I can see only this:
fe.add_text("[Title]", Setting("coords", "x"), Setting("coords", "y"), Setting("coords", "width"), Setting("coords", "height"));
but with X and Y set to 0 (zero) reagrdless of screen aspect - tested with 2 different screens 16:9 and 16:10
=========
OK, I just checked what's going on - I'm ALWAYS getting the "default" value regardless of screen aspect
-
are you possibly overwriting the settings variable - can I see your whole layout code with the new code added?
-
I just copy-pasted your code to an empty file. And changed resolution to 1920x1200.
-
Here's updated debug out...
//fe.layout.width = 800;
//fe.layout.height = 600;
fe.layout.width = 1280;
fe.layout.height = 720;
local settings = {
"default": {
coords = { x = 0, y = 0, width = 500, height = 30 }
},
"4x3": {
coords = { x = 300, y = 300 }
}
"16x9": {
coords = { x = 300, y = 0 }
},
"16x10": {
coords = { x = 0, y = 300 }
}
}
local aspect = fe.layout.width / fe.layout.height.tofloat();
local aspect_name = "";
switch( aspect.tostring() )
{
case "1.77778":
aspect_name = "16x9";
break;
case 1.6:
aspect_name = "16x10";
break;
case "1.33333":
aspect_name = "4x3";
break;
case "0.75":
aspect_name = "3x4";
break;
}
function Setting( id, name )
{
if ( aspect_name in settings && id in settings[aspect_name] && name in settings[aspect_name][id] )
{
::print("\tusing settings[" + aspect_name + "][" + id + "][" + name + "] : " + settings[aspect_name][id][name] + "\n" );
return settings[aspect_name][id][name];
} else if ( aspect_name in settings == false )
{
::print("\tsettings[" + aspect_name + "] does not exist\n");
} else if ( name in settings[aspect_name][id] == false )
{
::print("\tsettings[" + aspect_name + "][" + id + "][" + name + "] does not exist\n");
}
::print("\t\tusing default value: " + settings["default"][id][name] + "\n" );
return settings["default"][id][name];
}
fe.add_text("[Title]", Setting("coords", "x"), Setting("coords", "y"), Setting("coords", "width"), Setting("coords", "height"));
function on_signal( str )
{
switch( str )
{
case "custom1":
fe.signal("reload");
break;
}
return false;
}
fe.add_signal_handler( this, "on_signal");
Here's what I get when I run this layout, with 1280x720 defined for width/height:
using settings[16x9][coords][x] : 300
using settings[16x9][coords][y] : 0
settings[16x9][coords][width] does not exist
using default value: 500
settings[16x9][coords][height] does not exist
using default value: 30
and here's with 800x600 defined:
using settings[4x3][coords][x] : 300
using settings[4x3][coords][y] : 300
settings[4x3][coords][width] does not exist
using default value: 500
settings[4x3][coords][height] does not exist
using default value: 30
-
I've nailed it:
1. my bad (sorry for wasting your time because of this) :'(
------------------------------------------------------------------------
I didnt put " " around my added 1.6 definition - so 16:10 resolution wasn't working (no defined settings)
After that fixed - all golden
//fe.layout.width = 1920;
//fe.layout.height = 1200;
I get [16x10] settings
//fe.layout.width = 1280;
//fe.layout.height = 720;
I get [16x9] settings
//fe.layout.width = 800;
//fe.layout.height = 600;
I get [4x3] settings
2. So I've tested it with deleted //fe.layout.width and //fe.layout.height using real resolutions of 16:10 and 16:9 screens
-----------------------------------------------------------------------------------------------------------------------
It was working... almost :)
Everything was good with 16:10, but I was getting NO SETTINGS for 16:9 - and default settings was used
It turns out that not all 16:9 screens was made equal :)
My screen res is 1366x768
The problem is that
1280/720 = 1.77777777777778
1366/768 = 1.77864583333333
slightly different, but different enough for a cold harted computer to reject my screen as not truly 16:9 :)
---
Is there any solution to have more "fuzzy" logic?
Can we cut 1.7786 to 1.7 when turned into string with aspect.tostring ?
Or maybe round it up to 1.78?
Or make > 1.7?
-
Ah good!
Ah, crap :) Well for now you could just add:
case "1.77778":
case "1.77864583333333":
aspect_name = "16x9";
break;
I'm not great with the resolutions/aspect stuff but if you have a suggestion, I'm happy to implement it - it could be rounded down just using floor( aspect ) but I'm not sure if that's good enough or if that might affect others. It could also be modified by just checking specific resolutions instead of the ratio..
I'm doing some work on a separate 'Settings' module to refine this which will also allow for emu or list name specific settings - once we can refine this, i'll be improving and releasing that.
-
I'm not great with the resolutions/aspect stuff but if you have a suggestion, I'm happy to implement it - it could be rounded down just using floor( aspect ) but I'm not sure if that's good enough or if that might affect others.
resolutions - this is my domain :D
best way is to trim it to #.#
so you'll have 1.3 1.6 1.7
or round up tp #.#
so you'll have 1.3 1.6 1.8
and you'll be covering all resolution variants
-------------
but floor can't be used if I'm not mistaken - because floor(x) returns a float value that is the largest integer that is less than or equal to x
so all numbers will give you 1.0 when "floored"
-
wait... you can use floor...
you just have to multiply aspect value by 10 - so you'll have
13.33333 16 17.77778
and after floor you'll have
13.0 16.0 17.0
and use that values to define
case "17.0":
aspect_name = "16x9";
break;
-
I've checked all popular resolutions and aspects - and it turns out that your workaround for my resolution (additional value) will do the trick.
Because my laptop resolution is THE ONLY resolution that is problematic. All other will give you the same result for width/height - within the same aspect ratio.
1280x720-----16:9 = 1,77777777777778
1366x768-----16:9 = 1,77864583333333
1600x900-----16:9 = 1,77777777777778
1920x1080----16:9 = 1,77777777777778
I can always make 16:9 aspect "default" - but adding another value especially for 1366/768 will tighten the system and make it more (copy-paste) users friendly.
Full resolution list below if you are interested.
Resolution - Aspect ratio
320x240-----4:3
640x480-----4:3
800x600-----4:3
1024x768-----4:3
1152x864-----4:3
1280x960-----4:3
1400x1050-----4:3
1600x1200-----4:3
2048x1536-----4:3
3200x2400-----4:3
4000x3000-----4:3
6400x4800-----4:3
___________________
1280x720-----16:9 = 1,77777777777778
1366x768-----16:9 = 1,77864583333333
1600x900-----16:9 = 1,77777777777778
1920x1080----16:9 = 1,77777777777778
___________________
320x200-----16:10
640x400-----16:10
1280x800-----16:10
1440x900-----16:10
1680x1050-----16:10
1920x1200-----16:10
2560x1600-----16:10
3840x2400-----16:10
7680x4800-----16:10
-
yes i wasn't quite thinking but that should work fine and would solve your lone resolution issue. Although a proper round to tenth function might be nice to include in my utils I am working on :)
What about vertical aspects? What do we want to support, just the same reversed? I don't really use those currently.
-
I think "just the same reversed" is fine. For vertical 3:4 and maybe 10:16 are viable options. You can just throw 9:16 to the mix - but it is very unlikely that someone will use it for vertical (or design layout for 9:16).
---
I think that you could also add the option to define global variables - related to aspect.
like
::moveDown = 120
local screenBottomTitle fe.add_text("[Title]", 0, 1050+moveDown, 500, 30);
in this example
for 16:9 moveDown = 0
for 16:10 moveDown = 120
this way my [title] will be always at the bottom of the screen - regardless of screen aspect 16:9 or 16:10
I know you can do the same with coordinates table - but it could be a simpler solution when only one coordinate change is needed. The easy way to push some elements down/up left/right.
-
latest findings :)
"correct" aspect case for 1366x768 is 1.77865 it looks like it is rounded to #.#####
so it should be
case "1.77865":
-
sounds good - i added the case. And I'll add the vertical cases you mentioned, we can always add others if needed.
In regards to positioning - there's two different methods I have been working on. With animation, I had a positioning function with screen positions like center, left, right, top, bottom. I have also been testing an 'Anchor' function, which can anchor an object inside or against another object ( for example, anchor an image within a surface, or to the right of a surface ). I'm not sure if that should be part of the 'settings' module or something separate. In your case, are you referring to a padding when anchoring to a certain area?
-
positioning function with screen positions like center, left, right, top, bottom.
sounds great if you can stack/combine them - like left-center or top-bottom
But one thing would be really great (and mayby it is that way) If using positioning other that top-left could change insetion point.
example:
placing square image 400x400px in bottom-left corner should change "insert point" to the bottom-left corner of the image (default is top-left)
something like this:
fe.add_image( name, insertPoint, x, y, w, h )
fe.add_image( "square.png", bottom-left, 0, 0, 400, 400 )
should give me visible square in bottom-left corner of the screen
So in this example using bottom-left effectively changes coordinate system for inserted objects (bottom-left corner of the screen is now "locally" point 0.0 and top-right is screenWidth.screenHeight)
'Anchor' function, which can anchor an object inside or against another object
I don't know if I understand your intend correctly. It should work the same way "inside" surface treating surface like new "screen", with top-left being top-left corner of the surface. And padding (moving away from insertion point) should be done with inserted object placement coordinates - but it could work only if coordinate system would change relatively to insertion point.