Full source code for the example project is on gitHub.

What is DMT?

In short, DMT will lets create texture atlases from vector based assets at run-time.
I'll show you a very simple example on how to do that, and what are the benefits of DMT.
Next time we'll talk about Dimethyltryptamine, for now let's do some code :-)


Creating a project

For this example we'll use Flash-Builder 4.7, but this can be done with any other IDE.

Create an ActionScript Mobile AIR Project, name it HelloDMT. You can also use Desktop AIR, it doesn't really matters, as long as you use AIR. AIR is important here because the basic DMT API uses the file-system to save the texture atlases and some more data. To use DMT on pure Flash projects you'll have to use a more advance DMT API.


Basic Starling setup

Lets create a very basic Starling app.
  • First include Starling.swc in your project (Download from here)
  • Edit the HelloDMT.xml, and set the renderMode to direct. To be able to use the Stage3D.
  • Create your Starling main class, Main.as (Inherit from starling.display.Sprite)
  • And on HelloDMT.as use this code:
package
{
 import flash.display.Sprite;
 import flash.display.StageAlign;
 import flash.display.StageScaleMode;
 
 import starling.core.Starling;
 
 public class HelloDMT extends Sprite
 {
  private var m_starling:Starling;
  
  public function HelloDMT()
  {
   super();
   
   stage.align = StageAlign.TOP_LEFT;
   stage.scaleMode = StageScaleMode.NO_SCALE;
   
   Starling.multitouchEnabled = true;
   Starling.handleLostContext = true;
   
   // initialize Starling
   m_starling = new Starling(Main, stage);
   m_starling.simulateMultitouch  = false;
   m_starling.start();
  }
 }
}

Vector Assets

Most artists create their vector game/app assets in Flash or Illustrator. To be able to use these assets, you must give it a linkage name, so we will be able to create it on run-time.
In our example we will use a simple Square, Triangle, and Circle assets that I've created, as you can see they all share the same LeftEye and RightEye assets (Download swf or fla).
The library looks like this:


Create assets folder under the main project and put the HelloDMT-Assets.swf in that folder, so we can embed it in our project.


The DMT library

Clone the code from gitHub, or just download it.
On the main directory you can see 4 folders:
  1. libs: This contains the Starling.swc, and XTDCommon.swc. Starling you should know, and XTDCommon is another open-source library (gitHub) with some useful utilities (You'll see soon)
  2. Samples: This folder contains an example project with the examples of the DMT library.
  3. DMT: This is the full source-code of the library.
  4. swc: Contains the compiled swc, in case you don't want to include the code in your project.
Copy the DMT.swc & XTDCommon.swc to your project, and include it just like you did with Starling.swc.
Your project tree should look like this:



Loading the assets

Before we can start using our assets, we must load them into our Application Domain.
There are few ways to load swf assets into your application domain. You can load from external file, remote url, or embed the swf. In our example we'll embed the swf and load it into our application domain, so we can create our three assets.
  [Embed(source="/../assets/HelloDMT-Assets.swf", mimeType="application/octet-stream")] 
  private var AllAssetsClass:Class;


To load the embedded assets into our application domain we'll use a utility class named AssetsLoaderFromByteArray, available on XTDCommon library (Told you we'll use it).
Using this class we can shorten our code of loading the assets and registering them on the application domain.

private var _assetsLoader  : AssetsLoaderFromByteArray;

private function loadAssets():void
{
  var assetsByteArrays : Vector.<bytearray> = new Vector.<bytearray>;
  assetsByteArrays.push(new AllAssetsClass());
  _assetsLoader = new AssetsLoaderFromByteArray(assetsByteArrays);
  _assetsLoader.addEventListener(Event.COMPLETE, onAssetsReady);
  _assetsLoader.initializeAllAssets();
}

protected function onAssetsReady(event:Event):void
{
  sendVectorAssetsToDMT();
}  


Lets examine the code:
I've defined a private variable _assetsLoader in the type of AssetsLoaderFromByteArray.
Created a function loadAssets, which will handle the loading process.
The AssetsLoaderFromByteArray class excepts a Vector of ByteArrays (SWFs that you embedded) and loads them all into the current ApplicationDomain. Once the assets are loaded and ready (Listening to Event.COMPLETE), we can start working on the DMT side, and start the rasterization process (Converting Vectors to Textures).


Initialize DMT

To use DMT we will create an instance of DMTBasic, and listen to Event.COMPLETE (We can also listen to Event.PROGRESS to get processing/loading progress) Now, if we have cache, we can start the processing right away. if we don't have cache we should first load the assets and rasterize them.
private var _dmtBasic   : DMTBasic;

private function initDMT():void 
{
  _dmtBasic = new DMTBasic("HelloDMT", true);
  _dmtBasic.addEventListener(flash.events.Event.COMPLETE, dmtComplete);
  if (_dmtBasic.cacheExist() == true)
    _dmtBasic.process(); // will use the existing cache
  else
    loadAssets();
}


Get ready for the Rasterization

In the case that we don't have cache, we will create the three vector assets, add them to DMT, and start the processing.
private function addVectorsToDMT():void 
{
  var square : DisplayObject = new (ApplicationDomain.currentDomain.getDefinition("Square"))
  square.name = "square";   
 
  var circle : DisplayObject = new (ApplicationDomain.currentDomain.getDefinition("Circle"))
  circle.name = "circle";

  var triangle : DisplayObject = new (ApplicationDomain.currentDomain.getDefinition("Triangle"))
  triangle.name = "triangle";

  _dmtBasic.addItemToRaster(square);
  _dmtBasic.addItemToRaster(circle);
  _dmtBasic.addItemToRaster(triangle);
  _dmtBasic.process(); // will rasterize the given assets  
}
I've given each asset a name, so later we will be able to ask DMT for these specific assets by name.



Game on!

After the cache was loaded, or after the rasterization is complete, DMT will fire the Event.COMPLETE, in this event listener we can be sure that we have our Starling assets ready to use.
In this example I've created all three assets, and put them on the stage, I've also rotated the eyes of the Triangle to show that the eyes are not baked into the texture.
Pay attention that we used the names that we gave the assets.
protected function dmtComplete(event:Event):void
{
  var starlingSquare : Sprite = _dmtBasic.getAssetByUniqueAlias("square") as starling.display.Sprite;
  starlingSquare.x = 100;
  starlingSquare.y = 100;
  addChild(starlingSquare);

  var starlingCirlce : Sprite = _dmtBasic.getAssetByUniqueAlias("circle") as starling.display.Sprite;
  starlingCirlce.x = 100;
  starlingCirlce.y = 300;
  addChild(starlingCirlce);

  var starlingTriangle : Sprite = _dmtBasic.getAssetByUniqueAlias("triangle") as starling.display.Sprite;
  starlingTriangle.x = 100;
  starlingTriangle.y = 500;
  addChild(starlingTriangle);
   
  starlingTriangle.getChildByName("right_eye_instance").rotation = Math.PI/2;
  starlingTriangle.getChildByName("left_eye_instance").rotation = -Math.PI/2;
}

This is how the Texture will look like, as you can see the left and right eyes were created once because they are actually the same assets with the same linkage.


Best practices

  • Instead of doing what I did in this example, created and added items one by one. You can do this:
    • Design your level/screen in Flash-Pro into one asset.
    • Make sure that all the children are with instance names (So you'll be able to access them).
    • Give it a linkage name, say "Level1".
    • Load this asset the same as we did in this example.
    • Re-position and re-scale the children to best fit the screen-resolution.
    • Call the DMT process() function.
    • Your level is ready as Starling objects with all the inner children positioned/scaled and accessible.
    • Because we use cache, this process will be done once, and DMT will load the textures and data next time.
  • Listen to DMT Event.PROGRESS, and show the user a "Loading..." message. if DMT doesn't have cache show the user "First time Loading, please wait..."
  • The third parameter of the DMT constructor is the cache version. In case that you've updated your game, and your game has changed assets. You want DMT to clear the previous cache, and create a new one, just increase the version.
  • Don't use huge vector assets, remember that the current limit is 2048x2048.
  • DMT will rasterize each frame in a MovieClip, so be smart about it.
  • You can checkout our game (Android, iOS, Amazon), and see for yourself, everything there was done with DMT, and it fits perfectly on ALL possible resolutions with crisp graphics!



Conclusion

DMT is quite easy after few minutes, and it gives you fast and powerful technique in just few lines of code.
You can animate the inner children, just like you would in the flash timeline, but in code.
No more stretched/squashed textures!


Troubles, Solutions, and some notes

  • Most of the first time users of DMT forget about the cache, they add assets, ask DMT to process them, and get an error when asking DMT to create these new assets... DMT will use the old cache if exists. So while in development don't use cache, until the late stages of your game/app.
  • Where is the Cache saved? The answer to that is "Depends on what device", on Windows it's under C:\Users\USER_NAME\AppData\Roaming\DATA_NAME, on Android and iPhone it's on a temp folder that will not get saved to the app cloud data (As noted by Apple)
  • If you want DMT to stop "digging" into your assets display-tree and stop rasteraizing. you can do two things:
    • When you call dmtInstance.process, the second parameter is the maxDepth, use that as an overall limit. DMT will not rasterize deeper children.
    • To stop "digging" into a specific instance, name it "stop_raster", and DMT will raster this instance as it is, and not its children.
  • dmtInstance.getAssetByUniqueAlias is returning starling.display.DisplayObject, but you want MovieClip? If you are sure that your assets was a movieClip, just cast it to MovieClip.
  • MovieClips are rasterized as is, DMT will lot try to rasterize each frame's children.
  • Make sure that you use linkage name to your assets that you re-use, DMT will detect the same assets (As you saw in this example) as will not re-rasterize them.
  • Be sure to checkout the DMT source code, there are some example projects there.
Powered by Blogger.