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 - liquid8d

Pages: 1 2 [3]
31
Scripting / Surface downsides?
« on: March 02, 2015, 03:53:47 PM »
Is there any downsides (performance issues, etc?) in adding objects to surfaces vs adding objects "directly"? I'm guessing fe.add_XXXX draws to it's own surface?

I ask because I put together a Layers module which basically draws the surfaces first, then you only draw to the surfaces. This gives you more flexibility and control with a "layered" effect, meaning you can add objects at a later time and have it drawn to the background or foreground layer.

I was initially including this as part of ExtendedObjects but I'm looking to put it out as a standalone module.

Code: [Select]
layers <- {
    version = 1.4,
    build = 100,
    function add( name )
    {
        this[name] <- fe.add_surface( fe.layout.width, fe.layout.height );
    },
    function init( layers = null )
    {
        //default layers to be used
        if ( layers == null ) layers = [ "Background", "Primary", "Foreground" ];
        //add layers
        foreach ( layer in layers ) { add( layer ); }
    }
}

//now we can draw to the layers instead, in any order we want
layers.init();
layers.Foreground.add_text("I'm on top of title", 0, 0, 400, 30);
layers.Background.add_text("[Title]", 0, 0, 400, 30);


This also means you could manipulate an entire surface (and group of objects) at once. In fact, I thought about using the surface as a holder for a more complex object might be an option. So the surface could be your "object", which includes multiple text or image objects.

32
Scripting / iteration of files in directory?
« on: December 05, 2014, 11:15:17 AM »
Is there a way to iterate through files in a directory?

I know you can use FeConfigDirectory to access specific files in there, but is there a way to get a list of files dynamically and load them with do_nut/load_module?

33
Scripting / SpriteSheets module
« on: November 18, 2014, 10:30:07 PM »
I've seen some use the subimg functionality in some cool ways, but I don't think anyone has put together a simple way to do sprite sheet animation, so I spent some time today making a SpriteSheet module.

You can find the module code and a layout example on my github:
https://github.com/liquid8d/attract-extra/blob/master/modules/spritesheet.nut
https://github.com/liquid8d/attract-extra/tree/master/layouts/SpriteSheet%20Example

Basically, you can have some simple animations using a sprite sheet without having to do your own ontick and subimg coding.

Here's a video of it in action:
http://youtu.be/4WAQuwWIAlk

I also uploaded the joystick and button examples here in my extras folder if you want them. You are of course free to use and modify for whatever:
https://github.com/liquid8d/attract-extra/tree/master/extras





If you want to peruse the code:

Code: [Select]
///////////////////////////////////////////////////
//
// Attract-Mode Frontend - "spritesheet" module
//
// SpriteSheet allows you to create animations from an image with multiple "sprites"
//
// Usage:
//  //create an image object with your spritesheet
//  local joy = fe.add_image("joystick-move.png");
//  //create a SpriteSheet instance with your object and sprite size
//  local sprite = SpriteSheet(joy, 128, 128);
//      //settings
//      sprite.orientation = "vertical";    //orientation of your sprite frames, default is horizontal
//      sprite.repeat = "yoyo";             //a number or either loop or yoyo, default is loop
//      sprite.spf = 1;                     //seconds per frame, default is 1
//      sprite.order = [ 3, 0, 1, 3 ];      //optional array with a custom frame index order
//
//      //control
//      sprite.frame(0);    //set to a specific frame
//      sprite.reset();     //reset the animation
//      sprite.stop();      //stop the animation
//      sprite.start();     //start the animation
//     
//      //info
//      local last = sprite.last_frame();  //will tell you what the last frame index is
//      local next = sprite.next_frame();  //will tell you what the next frame index will be
//      local prev = sprite.prev_frame();  //will tell you what the next frame index will be
//      local played = sprite.playCount();    //will tell you the number of times the animation has played (reset on reset)
///////////////////////////////////////////////////
const SPRITESHEET_VERSION=1;

class SpriteSheet
{
    //TODO
    //single row/column only for now - implement row/columns as frames based on texture size
    //bug - doing last frame again after stop?
    //spf or fps?
   
    //settings you care about
    orientation = "horizontal";     //either horizontal or vertical spritesheet
    width = 0;                      //sprite height
    height = 0;                     //sprite width
    spf = 1;                        //seconds per frame
    order = null;                   //an array with a custom frame order to use from the spritesheet
    repeat = "loop";                //a number or either loop or yoyo
   
    //internal stuff
    mObj = null;                    //object to animate
    mOffset = 0;                    //current texture offset, or array index for a frame array
    mTimer = 0;                     //timer to watch elapsed time
    mRunning = false;               //is animation running?
    mReverse = false;               //whether we are running animation in reverse
    mPlayed = 0;                    //number of times animation has played
   
    constructor( obj, w, h = null )
    {
        mObj = obj;
        width = w;
        height = ( h == null ) ? width : h;
        //set initial sprite size
        mObj.subimg_width = width;
        mObj.subimg_height = height;
        fe.add_ticks_callback( this, "on_tick" );
    }
   
    function start()
    {
        mRunning = true;
    }
   
    function stop()
    {
        mRunning = false;
    }
   
    function reset()
    {
        //reset to first frame
        mPlayed = 0;
        frame( 0 );
    }
   
    function playCount()
    {
        return mPlayed;
    }
   
    function on_tick( ttime )
    {
        if ( mObj != null && mRunning )
        {
            local elapsed = ttime - mTimer;
            if ( elapsed > spf * 1000 )
            {
                mTimer = ttime - ( elapsed - ( spf * 1000 ) );
                //check if we need to reverse the animation for yoyo repeat
                if ( repeat == "yoyo" ) mReverse = (mReverse && prev_frame() == last_frame() || !mReverse && next_frame() == 0) ? mReverse = !mReverse : mReverse;
                //show the next frame
                local playFrame = ( mReverse ) ? prev_frame() : next_frame();
                if ( mReverse && playFrame == last_frame() || !mReverse && playFrame == 0) mPlayed += 1;
                if ( typeof repeat == "integer" && mPlayed > repeat) stop();
                frame( playFrame );
                //print( "frame: " + mTimer + " offset: " + mOffset + " reverse: " + mReverse + " played: " + mPlayed + "\n" );
            }
        }
    }
   
    //shows a specific sprite frame
    function frame(which)
    {
        mOffset = which;
        switch ( orientation ) {
            case "horizontal":
                mObj.subimg_x = ( order == null ) ? mOffset * width : order[mOffset] * width;
                break;
            case "vertical":
                mObj.subimg_y = ( order == null ) ? mOffset * height : order[mOffset] * height;
                break;
        }
    }
   
    function last_frame()
    {
        if ( order == null )
        {
            switch ( orientation ) {
                case "horizontal":
                    return (mObj.texture_width - width) / width;
                case "vertical":
                    return (mObj.texture_height - height) / height;
            }
        } else
        {
            return order.len() - 1;
        }
    }
   
    //finds out which is the previous frame offset based on settings
    function prev_frame()
    {
        if ( order == null )
        {
            //iterate each sprite frame until we reach the beginning
            switch ( orientation ) {
                case "horizontal":
                    if ( mOffset > 0 ) return mOffset - 1; else return (mObj.texture_width - width) / width;
                case "vertical":
                    if ( mOffset > 0 ) return mOffset - 1; else return (mObj.texture_height - height) / height;
            }
        } else
        {
            //get the previous sprite frame in a custom array, or the last if we reach the beginning
            if ( mOffset > 0 ) return mOffset - 1; else return order.len() - 1;
        }
    }
   
    //finds out which is the next frame offset based on settings
    function next_frame()
    {
        if ( order == null )
        {
            //iterate each sprite frame until we reach the end
            switch ( orientation ) {
                case "horizontal":
                    if ( mOffset * width < mObj.texture_width - width ) return mOffset + 1; else return 0;
                case "vertical":
                    if ( mOffset * height < mObj.texture_height - height ) return mOffset + 1; else return 0;
            }
        } else
        {
            //get the next sprite frame in a custom array, or the first if we reach the beginning
            if ( mOffset < order.len() - 1 ) return mOffset + 1; else return 0;
        }
    }

}

and the layout:

Code: [Select]
fe.load_module("spritesheet");
local bg = fe.add_image("bg.png", 0, 0, fe.layout.width, fe.layout.height);
local logo = fe.add_image("logo.png");
logo.set_pos(fe.layout.width / 2 - logo.texture_width / 2, 20);
local list = fe.add_listbox(fe.layout.width / 2, logo.y + logo.texture_height, fe.layout.width / 2, fe.layout.height);
list.charsize = 18;
local joy = fe.add_image("joystick-move.png");
joy.set_pos(logo.x, logo.texture_height + 50);
local sprite = SpriteSheet(joy, 128);
//sprite.orientation = "vertical"; //default is horizontal
sprite.order = [ 0, 3, 0, 3, 0, 4, 0, 4, 0, 1, 0, 2, 0, 1, 0, 2, 0];
sprite.repeat = "loop";
sprite.spf = 0.25;
sprite.frame(0);
sprite.start();
local button = fe.add_image("button-press-white.png");
button.set_pos(logo.x + 128 + 50, joy.y + 10);
local sprite2 = SpriteSheet(button, 128);
sprite2.repeat = "yoyo";
sprite2.order = [ 0, 0, 1, 2, 3, 4, 5, 5 ];
sprite2.spf = 0.2;
sprite2.frame(0);
sprite2.start();
local button2 = fe.add_image("button-press-red.png");
button2.set_pos(button.x + 96, button.y);
local sprite3 = SpriteSheet(button2, 128);
sprite3.frame(0);
sprite3.repeat = "loop";
sprite3.spf = 0.5;
sprite3.order = [ 0, 5, 0, 5, 0, 0, 5 ];
sprite3.start();

34
General / AttractMode logo
« on: November 18, 2014, 05:07:20 AM »
I was bored and.. you have no logo, so ... :) I'm not a graphic designer by any means but here's a couple I came up with:


35
Scripting / Share some Shader info
« on: June 05, 2014, 03:58:20 PM »
The other day, I started to mess with shaders, which was... fun? :) I have done practically no C programming and zero graphics or game development, so this was all new to me. There was only one example I saw in the orbit layout (bloom) so I started looking around..

This has a couple cool things that I was able to implement:
http://www.geeks3d.com/shader-library/

Here is a site where you can play around with stuff:
https://www.shadertoy.com/new#

And here is a site where people have played around (WARNING: no joke, some of these could probably induce an epileptic seizure):
http://glsl.heroku.com/

Here is the ones I thought were pretty cool and maybe useful:

pixelate.frag
Code: [Select]
//http://www.geeks3d.com/20101029/shader-library-pixelation-post-processing-effect-glsl/
uniform sampler2D texture;
void main()
{   
    float rt_w = 480.0;
    float rt_h = 360.0;
    float pixel_w = 4.0;
    float pixel_h = 2.0;
   
    vec2 uv = gl_TexCoord[0].xy;

    vec3 tc = vec3(1.0, 0.0, 0.0);
    float dx = pixel_w*(1./rt_w);
    float dy = pixel_h*(1./rt_h);
    vec2 coord = vec2(dx*floor(uv.x/dx),
                      dy*floor(uv.y/dy));
    tc = texture2D(texture, coord).rgb;
    gl_FragColor = vec4(tc, 1.0);
}

ripple.frag
Code: [Select]
//http://www.geeks3d.com/20110316/shader-library-simple-2d-effects-sphere-and-ripple-in-glsl/
uniform sampler2D texture;
uniform float ttime;

void main()
{   
    float time = ttime / 1000.0;
    vec2 tc = gl_TexCoord[0].xy;
    vec2 p = -1.0 + 2.0 * tc;
    float len = length(p);
    vec2 uv = tc + (p/len)*cos(len*12.0-time*4.0)*0.03;
    vec3 col = texture2D(texture,uv).xyz;
    gl_FragColor = vec4(col,1.0);
}

Ripple requires you to send a parameter, ttime, so your layout.nut would look something like:
Code: [Select]
local fshader = fe.add_shader(Shader.Fragment, "pixelate.frag");
fshader.set_texture_param("texture");

local snap = fe.add_artwork("snap", 50, 50, 480, 360);
snap.shader = fshader;

fe.add_ticks_callback("onTick");

function onTick( ttime ) {
    fshader.set_param("ttime", ttime);
}



scanlines.frag
Code: [Select]
//http://glsl.heroku.com/e#15689.0

uniform sampler2D texture;

void main()
{
    vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
    gl_FragColor = pixel - vec4( step(1.0,mod(gl_FragCoord.y,2.0)) );
}


I tried to convert these as best I could and I only really grasped a little about fragment shaders - vertex is still a bit of a mystery to me. So, I guess.. share your shader info?? :)

36
Scripting / ExtendedObjects and Animate library
« on: June 04, 2014, 08:38:55 PM »
This is a set of extensions I am working on for Attract-Mode:

https://github.com/liquid8d/attract-extra/tree/master/layouts/extended

I say extensions because it's a set of .nut files that can be added to any layout that will extend the capabilities of AM.

ExtendedObjects
Currently, ExtendedObjects is primarily a wrapper around the current Fe.Text, Fe.Image, Fe.ListBox objects with some helper functions to  make it easier to work with your layout objects.

ExtendedObjects has the typical .add_text, .add_image, .add_artwork, and .add_listbox functions, just with an addition of an object id as the first parameter. Returned to you is a new class of that object: ExtendedText, ExtendedImage, ExtendedArtwork and ExtendedListBox. One major difference in these new classes is you don't get or set variables directly:
obj.x becomes obj.getX() or obj.setX(x)
obj.y becomes obj.getY() or obj.setY(y)
...

This is so the extended objects class can do some stuff whenever variables are changed. My initial reason for doing this was to add animation to the objects (modify x and y), but it kind of grew from there.

Benefits

Custom Objects:
You can extend the new classes which not only will take advantage of the additions of ExtendedObjects but allow you to combine multiple objects as one. This would allow someone to create for instance a full marquee wheel that can then be its own object.

Layers:
With the addition of surfaces in 1.3, ExtendedObjects will create a layered system where you can add objects to different layers. This means you don't have to create objects in the order you want them displayed.

Debugging System:
I wrote a debug system that makes use of ExtendedObjects. When enabled, text boxes are overlayed over every object in your layout which can help with debugging.

Positioning:
A full set of functions to help you position objects, you can use something like obj.setPosition("center") instead of having to do something like (fe.layout.width / 2) - (obj.width / 2), (fe.layout.height / 2) - (obj.height / 2)

Animations:
Why I originally wrote this, you can add animation effects to any object.

Animation
As I played with the onTick and onTransition functions and looked at examples, I saw how powerful it could be. I thought it would be a pain to create some animation effects every time I wanted something in a layout, so I began building the animate extension.

I did a lot of research to get animation working, since I know very little about it :) I had to write a custom onTick and onTransition to handle everything and it includes all kinds of neat easing functions. Everything is pretty much done by just telling it which object to animate and providing a config table. It looks like this:

Code: [Select]
local animConfig = {
   which = "translate",
   when = Transition.FromOldSelection,
   duration = 1500,
   from = "offleft",
   to = "left"
}
obj.animate(animConfig);

Benefits

Builtin easing functions:
You can specify the animation "effects" using the easing and tween config options. For examples, you can look at something like:
http://matthewlein.com/experiments/easing.html

Pre-included animations:
I have two currently, property and translate. Property animates a property (like alpha, skew, size or rotation) and translate moves objects.

Custom animations:
I have a boiler-plate template for creating your own animations where all you initialize, then handle start, frame and stop functions. There is an example animations on github to check out.

Animation sets:
I haven't done much with this yet, but intend on creating some already put together configs for common animations, for instance fade out a snapshot on transition, then fade it back in.

Particle animations:
A new animation I am working on which will essentially mirror the particle effects of HyperTheme. It's pretty cool.

Feedback
I'm still trying to figure out what all to do with this thing, but I want it to be user friendly and provide helpful functions to make creating layouts easier. If you get a chance to play around with it, I'd love to hear some feedback. It's fairly well documented on the github page, but as I make changes, some things might not have been updated. Let me know if you have any issues or questions!

37
Scripting / Learning Squirrel
« on: June 04, 2014, 07:22:42 PM »
Here is a great walkthrough to quickly learning squirrel:

http://electricimp.com/docs/resources/squirrelcrib/

Pages: 1 2 [3]