Tags – source.

Mobile AIR optimizations.

If you’re interested in optimization of Adobe Flash Platform, mainly AIR for mobile devices, you may be interested in the outline I compiled from several sources yesterday:

Device features

  • Multitouch
  • Accelerometer
  • Orientation
  • Microphone
  • Keyboard
  • GPS
  • Camera

General

  • Don’t write code to constructors, the JIT (Just In Time compiler) won’t optimize it. Code inside the constructor is not optimized by the Just-in-time compiler (JIT). To use JIT optimized code there is the possibility to call a function out of the constructor. The code inside that function is then optimized again. The reason why there are no test results here is that I could not be a real rule when it makes sense to do this or not. Usually you expect a faster code execution but if there is no difference because the JIT is not used at all which could happen you have an even slower code execution because of one extra function call which is your initializing function. (Joa Ebert: ActionScript 3 optimization techniques)

  • If you need to use an Array of Numbers, use ByteArray. It’s much faster.

  • Reuse everything, mainly DisplayObjects and URLLoader objects (Reusing Objects)

  • Use ScrollRect instead of masks.

  • Create DisplayObjects ahead of time to increase perceived speed of transitions.

  • Typing prevents runtime evaluation of method signatures which can slow down the VM

var p:Point = new Point();
p.x = Number(23);

This applies to web service JSON data too:

[
    {
        "_type_" : "RecordClass",
        "name" : "Joe"
    }
]

GPU vs. CPU

  • Flash attempts to keep bitmaps on the GPU allowing them to be quickly composited.
  • Images that don’t change across frames are ideal for GPU caching.
  • If The GPU cannot render an object, it is not displayed at all. There is no fallback to CPU rendering.
  • The following blend modes are not supported: layer, alpha, erase, overlay, hardlight, lighten, and darken.
  • Filters are not supported.
  • PixelBender is not supported.
  • Many GPU units have a maximum texture size of 1024×1024. In ActionScript, this translates to the maximum final rendered size of a display object after all transformations.
  • Adobe does not recommend the use of GPU rendering mode in AIR applications that play video.
  • GPU rendering mode is disabled for some devices on which the mode does not work reliably.
  • Limit the numbers of items visible on stage. Each item takes some time to render and composite with the other items around it.
  • Don’t overdraw. Use the background color as a background. Don’t layer large shapes on top of each other. There is a cost for every pixel that must be drawn.
  • Avoid shapes with long thin spikes, self -intersecting edges, or lots of fine detail along the edges. These shapes take longer to render than display objects with smooth edges.
  • Limit the size of display objects.
  • Enable cacheAsBitMap and cacheAsBitmapMatrix for display objects whose graphics aren’t updated frequently.
  • GPU rendering is more restrictive in mobile AIR apps created with the Packager for iPhone.
  • The GPU is only effective for bitmaps, solid shapes, and display objects that have the cacheAsBitmap property set
  • For objects that have cacheAsBitmap and cacheAsBitmapMatrix set, the GPU can effectively render objects that rotate or scale.
  • The GPU is used in tandem for other display objects and this generally results in poor rendering performance.
  • The Android’s GPU renderer results in far better performance when using copyPixel method, AND, as a bonus, it automatically smooths bitmaps that have been rotated.

Events

  • Don’t use bubbling. A quick way to deal with these issues is to not bubble your events when possible and when you do need to bubble, stop propagation when the events have reached a point that they don’t need to bubble anymore:
event.stopPropagation();

Mouse

  • Don’t use MouseEvent.MOUSE_MOVE. It is simply not there.

  • Check for mouse position in an interval. But no setInterval or Timer, see below.

  • One other thing you can do is prevent mouse events (that are set to bubble by default) from effecting children you weren’t intending. Try setting mouseChildren and mouseEnabled to false.

Filters & Blending Modes

  • Don’t use them.

Visibility

  • visible = false is not enough. Use removeChild().

  • But first stop the MovieClip.

Timers

  • Don’t use Timers: To improve performance avoid high rate timers, this will reduce the amount of events being fired and the quantity of code being executed. The second performance increase is to have one timer for the entire application. Think of it as a heartbeat for your application keeping the internal timing for all your functions. This will reduce the amount of timers you have and the amount of time calculations taken from the Flash Player environment.

  • Event.ENTER_FRAME is better than Timer.

  • Set frame rate to 4 when not animating, increase when needed. Monitoring your frame rate is very important as many flash designers want to ramp up the frame rate to 60 frames per second because it will make the animations “pretty”.

stage.frameRate = 4;

Use deactivation when the app is in background:

this.addEventListener(AIREvent.APPLICATION_DEACTIVATE, appDeactivate);

Grant Skinner wrote a brilliant class on FPS management.

Vectors

  • Draw vector content to Bitmap before it gets rendered to Stage.

  • For simple shapes that are not interactive, use Shape objects. For interactive objects that don’t need a timeline, use Sprite objects. For animation that uses a timeline, use MovieClip objects. Always choose the most efficient type of object for your application.

  • Use the getSize() method to benchmark code and determine the most efficient object for the task.

  • Avoid using the ActionScript drawing API (the Graphics class) to create graphics. When possible, create those objects statically at authoring time instead.

  • Pre-cache Vector animations as a Sprite Sheet for optimal load times. Instead of caching your vectors as bitmaps at runtime, you should convert your vectors into bitmaps before compiling your game. First, store your bitmaps in a tile-based sprite sheet. Then, export this image for action script as bitmap data. Finally, cache positions (parts of the bitmap data) you want to manipulate as rectangles and use the copyPixel method to pull the actual bitmap data off the sprite sheet. 8BitRocket’s website covers how to achieve all of these steps except for converting your MovieClip based animations into a single sprite sheet image. It so happens that I have developed a component that will automatically export a series of MovieClip animations into a PNG with transparency capability; I am willing to share this if I can get some support from other developers on this forum.

Bitmaps

  • Scale bitmap assets to the final size before importing them.

  • One other little used cache method is cacheAsBitmapMatrix. Similar to the cacheAsBitmap this will also cache the x, y, rotation, scale, skew properties. Keeping the Flash Player from having to redraw the object. Again, if you make any changes to alpha/color or the children sprites matrix the object will be redrawn and you will be spending more time and memory to cache an object that is constantly redrawn.

myBall.cacheAsBitmapMatrix = new Matrix();
  • Don’t forget that images split by the power of 2 are going to be more efficient on memory than odd sized images. This can’t always be avoided by it’s good to remember.

  • Make bitmaps in sizes that are close to, but less than, 2n by 2m bits. The dimensions do not have to be power of 2, but they should be close to a power of 2, without being larger. For example, a 31-by-15–pixel image renders faster than a 33-by-17–pixel image. (31 and 15 are just less than powers of 2: 32 and 16.)

  • If possible, set the repeat parameter to false when calling the Graphic.beginBitmapFill() method.

  • Runtime bitmap caching is impractical for mobile. Ideally, I’d like to pre-cache all of my vector based animations as bitmaps such that they are sized to the native resolution of my device at runtime (ex, iPhone has very small resolution, iPad large resolution, and Android, right in the middle). 8BitRocket’s tutorials explain how to achieve this effect by running a timer to loop through a time-line based vector animation to draw each frame as a bitmap and store it within an array as bitmap data for later use. However, I have discovered that attempting to cache a large number of vector frames as bitmaps within an array at runtime on any mobile device is utterly impractical. A single unit model with 300 unique animation frames at 100×100 pixels might take 15-20 seconds for a mobile device to cache. A game with twenty plus models would take 5+ minutes to load, and not even the most diehard players will be willing to wait that long.

Sprites

  • Write some method that splits your bitmap sheet image to single frames with copyPixels and store them to Vector. (and dispose the sheet).

  • Next start extending Bitmap class where you pass your vector and create MovieClip style methods like gotoAndPlay() and gotoAndStop in which you then assign correct BitmapData to your extended Bitmap depending from the function.

  • Also notice that events are extremely slow so you might want to push all your currently used display objects to some array and move/animate them on single Event.ENTER_FRAME outside your extended Bitmap.

  • Since Bitmap can’t use mouse events you also need to add that functionality to your extended bitmap class. Simply use hitTestPoint to determine if mouse was over the bitmap when clicked or dragged.

  • And you may also want to use object pooling (if you’re doing more fast paced games) since creating and removing instances on the fly is also sadly slow.

Text

  • Flash Player 10 and AIR 1.5 introduced a powerful new text engine, the Adobe Flash Text Engine (FTE), that conserves system memory. However, the FTE is a low-level API that requires an additional ActionScript 3.0 layer on top of it, provided in the flash.text.engine package.

  • For read-only text, it’s best to use the Flash Text Engine, which offers low memory usage and better rendering. For input text, TextField objects are a better choice, because less ActionScript code is required to create typical behaviors, such as input handling and word-wrap.

  • In GPU rendering mode, text fields are not always moved to a visible location when the virtual keyboard opens. To ensure that your text field is visible while the user enters text, do one of the following. Place the text field in the top half of the screen or move it to the top half of the screen when it receives focus.

Video

When encoding your video thing of the final endpoint. Most devices have a native codec (usually H.264) that will help improve decompression and playback on the hardware level rather than the software level. Make sure to target these native codecs and see the performance and battery life improvement.

Ant build script to help you compile to iOS AIR 2.6.

Yesterday Adobe announced AIR 2.6, which allows you to compile to iOS and is really fast.

Before you start, I recommend you to read (or at least bookmark) these articles:

John Lidquist wrote a brilliant batch script generator which helped me to start: AIR4AIR. Thanks John!

You definitely should to read John’s article Top 10 AIR 2.6 for iOS Questions.

It is somewhat painful to solve initial compilation steps, so I hope my Ant script will help you get through. Basically it allows you to compile both desktop AIR and an iPhone4 (retina) IPA file. All you need is an iOS developer certificate and provisioning profile. The script then creates the rest (folder structure, desktop AIR certificate). But please take a look at the source and edit it as needed – e.g. there’s only iphone-retina descriptor and settings, but it should be pretty straight-forward to add what you need.

Ant script

<?xml version="1.0" encoding="UTF-8"?>

<!--
  ~ Copyright (c) 2011 Vaclav Vancura (http://vancura.org)
  -->

<project default="1. Create directories" name="Test AIR 2.6 Ant script">
<!-- Edit me: Ant script name -->

    <tstamp>
        <format property="timestamp" pattern="yyyy-MM-dd_HH-mm-ss" />
    </tstamp>

    <!-- FLEX SDK configuration -->
    <property name="flex_sdk_dir" value="/Developer/SDKs/FlexSDK41" />
    <!-- Edit me: path to your Flex SDK with AIR 2.6 overlaid -->
    <property name="mxmlc_path" value="${flex_sdk_dir}/lib/mxmlc.jar" />
    <property name="adt_path" value="${flex_sdk_dir}/lib/adt.jar" />

    <!-- Application configuration -->
    <property name="app_name" value="Test Application" />
    <!-- Edit me: Name of the app -->
    <property name="main_source" value="src/Main.as" />
    <!-- Edit me: Main bootstrap class -->
    <property name="debug_dir" value="bin" />
    <property name="assets_dir" value="assets" />
    <property name="certificates_dir" value="certificates" />
    <property name="deploy_dir" value="deploy" />
    <property name="libs_dir" value="libs" />
    <property name="swf_filename" value="${debug_dir}/test.swf" />
    <!-- Edit me: compiled SWF filename -->

    <!-- Desktop certificate configuration -->
    <property name="desktop_certificate_org_name" value="Your Name" />
    <!-- Edit me: your name, probably not Your Name -->
    <property name="desktop_certicitace_org_unit" value="" />
    <!-- Edit me: organization unit -->
    <property name="desktop_certificate_name" value="your-name" />
    <!-- Edit me: your name (this should be a filename safe name) -->
    <property name="desktop_certificate_password" value="password" />
    <!-- Edit me: your certificate password -->
    <property name="desktop_certificate_country_code" value="CZ" />
    <!-- Edit me: country code -->
    <property name="desktop_certificate_key_type" value="2048-RSA" />

    <!-- Desktop configuration -->
    <property name="desktop_certificate_filename" value="${certificates_dir}/${desktop_certificate_name}.pfx" />
    <property name="desktop_air_filename" value="${deploy_dir}/${app_name}_${timestamp}.air" />
    <property name="desktop_descriptor" value="${assets_dir}/desktop-app.xml" />

    <!-- iOS configuration -->
    <property name="ios_target" value="ipa-test" />
    <!--
        Edit me: choose one from:
            * ipa-test - Quick publishing for device testing
            * ipa-debug - Quick publishing for device debugging
            * ipa-ad-hoc - Deployment - Ad hoc
            * ipa-app-store - Deployment - Apple App Store
    -->

    <property name="ios_provisioning_profile_path" value="/Users/Test/Library/MobileDevice/Provisioning Profiles/your-provisioning-profile.mobileprovision" />
    <!-- Edit me: your provisioning profile path -->
    <property name="ios_certificate_filename" value="/Users/Test/Documents/iphone-developer.p12" />
    <!-- Edit me: your iphone developer certificate, see http://j.mp/convert-profiles -->
    <property name="ios_certificate_password" value="password" /> <!-- Edit me: your certificate password -->
    <property name="ios_ipa_filename" value="${deploy_dir}/${app_name}_${timestamp}.ipa" />
    <property name="ios_iphone_retina_descriptor" value="${assets_dir}/iphone-retina-app.xml" />
    <!-- Add more descriptor files here -->


    <!-- Create required directories -->
    <target name="1. Create directories">
        <mkdir dir="${assets_dir}" />
        <mkdir dir="${deploy_dir}" />
        <mkdir dir="${debug_dir}" />
        <mkdir dir="${libs_dir}" />
        <mkdir dir="${certificates_dir}" />
    </target>


    <!-- Creating a digital ID certificate -->
    <target name="2. Create temporary desktop certificate">
        <java jar="${adt_path}" fork="true">
            <arg line="-certificate" />
            <arg line="-cn ${desktop_certificate_name}" />
            <arg line="-ou '${desktop_certicitace_org_unit}'" />
            <arg line="-o '${desktop_certificate_org_name}'" />
            <arg line="-c '${desktop_certificate_country_code}' ${desktop_certificate_key_type} ${certificates_dir}/${desktop_certificate_name}.pfx ${desktop_certificate_password}" />
        </java>
    </target>


    <!-- Compile SWF to build directory for desktop packaging -->
    <target name="3. Compile" depends="1. Create directories">
        <java jar="${mxmlc_path}" fork="true" failonerror="true">
            <arg value="-debug=false" />
            <arg value="-optimize=true" />
            <arg value="+flexlib=${flex_sdk_dir}/frameworks" />
            <arg value="+configname=air" />
            <arg value="-file-specs=${main_source}" />
            <arg value="-output=${swf_filename}" />
            <arg value="-l+=${libs_dir}" />
        </java>
    </target>


    <!-- Packaging the application to an air-file in the publish directory -->
    <target name="Package for desktop" depends="3. Compile">
        <java jar="${adt_path}" fork="true" failonerror="true">
            <arg line="-package" />
            <arg line="-storetype pkcs12" />
            <arg line="-keystore '${desktop_certificate_filename}'" />
            <arg line="-storepass '${desktop_certificate_password}'" />
            <arg line="'${desktop_air_filename}'" />
            <arg line="'${desktop_descriptor}'" />

            <!-- Add folders to be bundled in the AIR file here -->
            <arg line="'${swf_filename}'" />
            <arg line="'${assets_dir}/icons/icon16.png'" />
            <arg line="'${assets_dir}/icons/icon32.png'" />
            <arg line="'${assets_dir}/icons/icon48.png'" />
            <arg line="'${assets_dir}/icons/icon128.png'" />
        </java>
    </target>


    <!-- Compile SWF to build directory for iOS packaging -->
    <target name="Package for iOS (iPhone retina)" depends="3. Compile">
        <java jar="${adt_path}" fork="true" failonerror="true">
            <arg line="-package" />
            <arg line="-target ${ios_target}" />
            <arg line="-storetype pkcs12" />
            <arg line="-keystore '${ios_certificate_filename}'" />
            <arg line="-storepass '${ios_certificate_password}'" />
            <arg line="-provisioning-profile '${ios_provisioning_profile_path}'" />
            <arg line="'${ios_ipa_filename}'" />
            <arg line="'${ios_iphone_retina_descriptor}'" />

            <!-- Add folders to be bundled in the AIR file here -->
            <arg line="'${swf_filename}'" />
            <arg line="'${assets_dir}/icons/icon29.png'" />
            <arg line="'${assets_dir}/icons/icon48.png'" />
            <arg line="'${assets_dir}/icons/icon57.png'" />
            <arg line="'${assets_dir}/icons/icon72.png'" />
            <arg line="'${assets_dir}/icons/icon512.png'" />
        </java>
    </target>


</project>

Gisted here: https://gist.github.com/882808

Download

You may need to download all files including example descriptors, if you don’t have it yet. Here we go.

Lightweight Unlit Sprite Shaders in Unity.

Yesterday I tweeted about my first two shaders: Sprite and Sprite Additive…

And today Aras Pranckevičius, lead graphics programmer at Unity, wrote me Unity 3.2 will have a couple of unlit shaders. That is perfect for my high performance mobile sprite needs. But until Unity 3.2 is released, I’d stick with my simple shaders.

In more detail: I’ve been looking for the right shader to shade my SpriteManager sprites. The default shader bundled with SM2 has vertex colored features, specularity and so on – but for my scenario it was a bit heavyweight, I just don’t need tinting and so on.

I am no expert in shaders (yet), so all I’ve done was fiddling around Mobile/Background and Mobile/Vertex Colored shaders from the SM bundle. Here’s results of the merge.

Honestly, I am not really sure I got everything right, but it works for me and allows me a bit higher framerate.

Sprite Shader

Shader "Mobile/Sprite" {
    Properties {
        _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    }
    
    Category {
        Tags {
            "Queue" = "Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
        }

        Zwrite Off
        Blend SrcAlpha OneMinusSrcAlpha 
        Lighting Off
        Cull Back
    
        Fog {
            Mode Off
        }
    
        SubShader {
            Pass {
                SetTexture [_MainTex] {
                    Combine texture 
                }
            }
        }
    }
}

Sprite Additive Shader

Shader "Mobile/Sprite Additive" {
    Properties {
        _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    }

    Category {
        Tags {
            "Queue" = "Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
        }

        Blend SrcAlpha One
        Cull Off
        Lighting Off
        ZWrite Off
    
        BindChannels {
            Bind "Color", color
            Bind "Vertex", vertex
            Bind "TexCoord", texcoord
        }
        
        Fog {
            Mode Off
        }
    
        SubShader {
            Pass {
                SetTexture [_MainTex] {
                    combine texture * primary
                }
            }
        }
    }
}

TrazzlePublisher.

If you use as3logger to standardize your AS3 logging needs, I’ve got something for you.

At Falanxia we’ve been using SOS Max Logger by PowerFlasher, but recently I’ve found a great new supplement, which I think is a great leap forward: Trazzle. Let me copy paste few features we love here:

  • Bitmap logging
  • Performance monitoring
  • Multiple Log Levels
  • TextMate support

For us just the Bitmap logging feature was a reason to switch. In case we logged events just via SOS Max, there would be a need to rewrite all logger calls, and it would be a somewhat painful and completely useless experience. Since we use the as3logger approach, it was really easy to add a small Trazzle wrapper. And there was no need to rewrite anything in our sources.

Here’s the source:

/*
 * Falanxia Utilitaris.
 *
 * Copyright (c) 2010 Falanxia (http://falanxia.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.falanxia.utilitaris.logger {
    import com.falanxia.utilitaris.utils.*;
    import com.nesium.logging.*;

    import de.dev_lab.logging.*;
    import de.dev_lab.logging.publisher.*;

    import flash.display.*;



    /**
     * The {@code String} publisher outputs the Log to a Trazzle.
     * See more info about Trazzle here:
     * http://www.nesium.com/products/trazzle
     *
     * @author Vaclav Vancura @ Falanxia a.s. vaclav@falanxia.com
     * @author Falanxia (http://falanxia.com, @falanxia)
     * @since 1.0
     */
    public class TrazzlePublisher implements IPublisher {


        private static var _trazzle:TrazzleLogger;



        /**
         * Constructor.
         */
        public function TrazzlePublisher(stageReference:Stage, appName:String) {
            if(_trazzle == null) {
                _trazzle = new TrazzleLogger();
                _trazzle.setParams(stageReference, appName);
            }
        }



        /**
         * Outputs the message to the {@code String}.
         * @param logLevel Log level
         * @param object Message
         */
        public function publish(logLevel:int, object:*, ...additional):void {
            var prefix:String;

            switch(logLevel) {
                case Logger.DEBUG:
                    prefix = "d ";
                    break;

                case Logger.INFO:
                    prefix = "i ";
                    break;

                case Logger.WARN:
                    prefix = "w ";
                    break;

                case Logger.ERROR:
                    prefix = "e ";
                    break;

                case Logger.FATAL:
                    prefix = "f ";
                    break;

                default:
                    prefix = "";
            }

            if(object == null) object = "[null]";

            _trazzle.log(prefix + String(object), 4);
        }



        /**
         * Clear.
         * Trazzle has no clear method, so it's just a placeholder.
         */
        public function clear():void {
        }



        /**
         * Destructor.
         */
        public function destroy():void {
            clear();
        }



        /* ★ SETTERS & GETTERS ★ */


        /**
         * Get Trazzle reference.
         * @return Reference to Trazzle
         */
        public static function get trazzle():TrazzleLogger {
            return _trazzle;
        }
    }
}

Of course you need as3logger de.dev_lab.logging.Logger class.

All you need now is just an initialization of the logger:

Logger.addPublisher(new TrazzlePublisher(stage, "My application name"));

And you can log as you logged before:

Logger.debug("Debug message");
Logger.info("Info message");
Logger.warn("Warning message");
Logger.error("Error message");
Logger.fatal(Math.random() * 1000);

If you want to call Trazzle for any reason (e.g. to log a Bitmap), you can use:

var myBitmapData = new BitmapData(100, 100);
myBitmapData.noise(Math.random() * 1000);
TrazzlePublisher.trazzle.logBitmapData(myBitmapData);

Or to invoke a beep and show a performance window:

TrazzlePublisher.trazzle.beep();
TrazzlePublisher.trazzle.startPerformanceMonitoring();

You can fork or watch the Gist for this class here on Git.

Dummy Tween Plugin.

A somewhat different approach to periodical calling of a method. This time with TweenLite/TweenMax by Greensock

As I said before, last few months I’ve been working for Falanxia.com, where I help to develop social games in Flash (and more platforms coming). I was not very happy with the way how to periodically call a method:

var timer:Timer = new Timer(10, 100); // call a method 100 times with 10 ms delay)
timer.addEventListener(TimerEvent.TIMER, method);
timer.start();

Is there a shorter approach to do the same thing? While we already use TweenLite/TweenMax a lot, I thought there has to be a plugin which should handle this task (no, I don’t need TweenLite.delayedCall(). Well, nope, there’s not. But sure it can be handled this way:

var tweenObj:Object = {pass:0};
TweenLite.to(tweenObj, 1, {ease:Liner.easeNone, onUpdate:method}); // 100 * 10 ms = 1 second

IMHO this way is a bit cumbersome and you need to create an Object to be tweened. I came up with a simple TweenLite plugin to do the job:

/*
 * Falanxia Utilitaris.
 *
 * Copyright (c) 2010 Falanxia (http://falanxia.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.falanxia.utilitaris.plugins {
    import com.greensock.*;
    import com.greensock.plugins.*;



    /**
     * Dummy tween plugin.
     *
     * @author Vaclav Vancura @ Falanxia a.s. vaclav@falanxia.com
     * @author Falanxia (falanxia.com
     * @since 1.0
     */
    public class DummyTweenPlugin extends TweenPlugin {


        public static const API:Number = 1.0;

        protected var _target:Object;



        /**
         * Constructor.
         */
        public function DummyTweenPlugin() {
            super();
            this.propName = "dummy";
            this.overwriteProps = ["dummy"];
        }



        /**
         * Tween initialization.
         * Gets called when any tween of the special property begins. Store any
         * initial values and/or variables that will be used in the "changeFactor"
         * setter when this method runs.
         * @param target Target object of the TweenLite instance using this plugin
         * @param value The value that is passed in through the special property
         * @param tween The TweenLite or TweenMax instance using this plugin
         * @return If the initialization failed, it returns false. Otherwise true.
         * It may fail if, for example, the plugin requires that the target be a
         * DisplayObject or has some other unmet criteria in which case the plugin
         * is skipped and a normal property tween is used inside TweenLite
         */
        override public function onInitTween(target:Object, value:*,
            tween:TweenLite):Boolean {
            return true;
        }
    }
}

How to use it?

TweenPlugin.activate([DummyTweenPlugin]);
// first you need to activate the plugin, but only once in the whole app

TweenLite.to(this, 1.0, {dummy:{}, onUpdate:method});

This way there’s no need to create an Object variable. I think it’s a bit simpler. Actually this article took much more time to write than to code the DummyTweenPlugin.

Clarion Hotels Panorama Viewer
Clarion Hotel in Prague provides conference rooms for a wide range of events. I was asked to create a panorama viewer where potential clients could see the halls exactly how they look when prepared in several styles and settings.
Year:
2010
Client:
WDF
See it live at cchp.cz

mDocs.

As you saw in my last post, I use autogenerated NaturalDocs documentation.

I was not really happy with skins NaturalDocs provides by default and was not able to find anything usable, so I decided to create my own. If you like it, feel free to use it. Git repo is here.


Click the image to see the full resolution.

Vancura-AS3-Libs.

Finally I was able to take some free time
and open my AS3 libraries.

What does it do? Read the docs here: here and point your browser to the git repo.

Features

Currently these features are covered:

Core functions

Easy Far wrapper:

  • Far
  • FarHelperItem

More features coming soon: skinnable widgets, remoting and more. Watch this space for more information.

How to get the SWC

There are several ways to get the library for use in your project.

Binary distribution

In case you’re lazy or you don’t have all required components to compile it on your machine, you can grab the SWC here.

Compilation from source

You can compile the SWC very easily. In simple words you just need to launch ./compile.sh file. I wrote it on OSX, but it should work fine on a Linux machine as well. The only issue, actually, is the Windows machine. Since I don’t have access to any Windows installation around here, you have to figure out how to compile it. Just take a look at the compile.sh file and you’ll see what’s going on there.

The library uses several 3rd party components: * Greensock Tweening Platform (known as TweenNano, TweenLite and TweenMax) * Printf-AS3, an article here. * Vanrijkom Flashlibs * Uni fonts by miniml.com

All these files are downloaded from internet and not included in the source package. Hence you’ll get the most up-to-date SWC if you compile.

Of course you need Adobe Flex SDK. In my compile.sh script I use FlexSDK4 beta, which is not out yet, but works pretty well for me.