Scaleform GFx FAQ: GFx Integration and Flash-to-C++ Interfacing

This section covers issues including how to get GFx to run in your game, handling events, ActionScript-to-C++ communication, and other integration topics.

How does the game application control and interact with the playing Flash content?

There are several methods of communication between C++ and Flash/ActionScript:

Our Scaleform Integration Tutorial demonstrates the above methods.

Can Scaleform stream SWF content from a Web server?

Scaleform does not perform any network communication, so the built-in API does not support direct downloads from a Web server. However, users can implement and install a custom GFxFileOpener class to stream content from a Web server or through their game’s network layer. If progressive loading is used in combination with such streaming, Scaleform will allow for a preloader progress button to be displayed within the Flash file.

Is it possible to download new game resources through a network or HTTP server?

By implementing and installing your own custom GFxFileOpener class, it is possible to dynamically add new images, dialog boxes, and even ActionScript logic to a game through a network or HTTP server. This functionality is particularly valuable for MMO games where the storyline and UI assets evolve over time. Typically this communication occurs through a non-HTTP protocol, and content would be downloaded through the game’s network layer and then passed to the movie through Scaleform's C++ API. Please note that the Flash Web API is not supported by design.

Can I use my own file streaming system, such as from my own pack file system and such?

Yes. Implement GFxFileOpener, and override its OpenFile virtual function, which returns a GFile interface that implements your file. When Flash needs to open any type of resource file, it will rely on GFxFileOpener to access your resource system. See GFxFileOpener documentation for details.

Do you support loading Flash content on a background thread while you are already playing the content? Do you support streaming data in, so you can start playing back files before they finish loading?

Yes, we support background threading and background loading as of GFx 2.1. To enable threaded loading, install GFxTaskManager state on GFxLoader and configure the number of threads it will use. After GFxTaskManager is installed, all file loading requests will be handled progressively. (In other words, the content will start playing back before it finishes loading.)

Is it possible to seek within a Flash file?

The GFx Player supports dynamic advancement based on a specified time interval. It is possible to seek in the Flash file, moving directly to a specified frame; however, depending on the Flash file implementation, the seeking behavior can be unpredictable due to ActionScript logic that is attached to frames and can be potentially bypassed.

How does data serialization work (saving the state of the UI)?

There is no explicit serialization support. It is possible to query the state of ActionScript variables and UI components and serialize them manually. In GFx 2.2 we have introduced XML support, which allows your components to serialize and receive data through XML. In general, we do not recommend heavy XML use for consoles; it is best to maintain and serialize data externally on the C++ side.

Is it possible to draw something only by code, without a Flash file?

In Scaleform it is not possible to draw directly from C++, but you can use the ActionScript drawing API, which allows you to do fields and arbitrary shapes. You can also create text fields and reposition them using invokes. In GFx 2.2, GFxDrawText API has been introduced for the rendering and formatting of text outside of ActionScript sandbox.

How can C++ dynamically create new buttons and change Flash content (e.g., create a button with the label "click me" dynamically during game play)?

It is possible to implement a Flash movie that will create new buttons internally based on an ActionScript routine which is callable from C++. To implement this, a developer can create a single button with a dynamic text field, turn it into a movie clip (F8) and give it a linkage identifier in the Flash library. After the button is in the library, MovieClip.attachMovie API can be used to create multiple instances of it. Developers can also use SetVariable to change the content of the dynamic text field within the button by accessing its ‘text’ property. Most dynamic UI effects can be achieved with a combination of C++ and ActionScript.

Our MMOG has many separate interfaces, each in its own SWF file. What is a good way to enable the separate interfaces to exchange and synchronize shared data?

GFx supports ActionScript’s loadMovie method, which enables Flash SWF content to be loaded into a running SWF file. By creating a single-shell SWF file and a single GFxMovieView for the entire game, individual interfaces can be loaded and unloaded from memory but share the same variable namespace. Each interface can change variables and other ActionScript state and the changes are visible to the other screens because they are all part of the same GFxMovieView instance. Additionally, this shared state can be accessed from C++ through GFxMovieView.

I'm receiving Flash Tween class errors at runtime. Is this normal?

This is a fairly typical occurrence. Tween class is somewhat inaccurately designed, and GFx is designed to show all runtime errors (in contrast to Flash Player, which is completely silent about runtime errors). Displaying these error messages helps to design clean SWF files with correct ActionScript. If you don't want see these messages just specify the command-line option "-qae" for GFxPlayer. To turn off these messages in your application use the following code:

Code:

GPtr<GFxActionControl> pactionControl = *new GFxActionControl()
pactionControl->SetActionErrorSuppress(true);
pMovie->SetActionControl(pactionControl);

where pmovie is the instance of GFxMovieView.

We are using MSVS 2005, and get a manifest error when we compile in debug mode. Which version of MSVS 2005 is required for Scaleform

Scaleform requires MSVS2005 SP1. MSVS2005 without Service Pack 1 is not supported. You can download the Service Pack here: http://www.microsoft.com/downloads/details.aspx?FamilyID=bb4a75ab-e2d4-4c96-b39d-37baf6b5b1dc&DisplayLang=en

Is there any way to determine platform, player version and which player is playing the SWF?

Platform and Flash Version: $version or getVersion()

To determine which platform a SWF is running on, trace($version) or getVersion() may be used.

The output of either function will be in the following format: [PLATFORM] [FLASH VERSION]. For example, if the SWF is running on the PC platform, the output will be: "WIN 8,0,0,0".

The first set of letters will indicate the platform: WIN, MAC, LINUX, XBOX, XBOX360, PSP, PS2, PS3, or GFX.The second set of numbers will indicate the Flash version, which is always "8,0,0,0" in the current version of Scaleform GFx.

Scaleform GFx Version: _global.gfxVersion

To determine whether a SWF file is running in Scaleform GFx or in Flash Player/Studio,_global.gfxVersion may be used.

Code:

  _global.gfxExtensions = 1;
  Trace(_global.gfxVersion);

In the standard Flash Player _global.gfxVersion is "undefined". However, in Scaleform, it will indicate the version of GFx such, as "2.1.56".

Scaleform GFx Player: _global.gfxPlayer

To determine if a SWF file is being played by GFxPlayer, _global.gfxPlayer may be used.

      Code:
                  if (_global.gfxPlayer)
       {
        ...
       }

If the SWF file is playing in GFxPlayer, then _global.gfxPlayer is set to 1, otherwise it is "undefined" in both the Flash Player and the game engine. Thus, custom debugging code may be added, like buttons, or traces, that will be executed only if a SWF file is dropped into GFxPlayer.

We get a linker error saying that 'GFx_Compile_with_GFC_BUILD_DEBUG' is undefined. How do we fix it?

This issue will occur if you linked the debug build to release libraries (or the other way around), or misused the GFC_BUILD_DEBUG definition. You must compile your application that includes GFx headers with GFC_BUILD_DEBUG defined for debug builds, and not defined for release ones.

How can I use Advance and Display from different threads?

Many developers have requested the ability to do GFx rendering and processing in separate threads, i.e. calling Advance and Display methods of GFxMovieView asynchronously. While asynchronous execution of these methods is currently not possible, developers can free up processing time in the rendering thread by moving the Advance into a different thread and using proper synchronization techniques. Such setup can improve performance on multi-core systems and consoles such as Xbox 360.

In order for Advance and Display to be called from separate threads, their access needs to be synchronized with an external user lock. Below is an example of how this can be done with separate processing and rendering threads.

Suppose we have two threads: Thread1 is executing input processing and Advance, while Thread2 is a renderer thread performing both game engine rendering and GFx rendering - i.e. Display. What we need to do is ensure that Advance and Display are never executed simultaneously. In other words, Thread2 can be rendering 3D game content while GFxMovieView::Advance is being executed in Thread1. Once Thread2 gets to rendering of the GFx movie, it needs to wait for Thread1 to complete. In other words, this requires synchronization once per frame. Users can mediate this limitation by issuing Advance in Thread1 right after Display in Thread2 has completed; this will ensure that the Advance will most likely be completed by the time Display is called again.

Below is the pseudo-code that can be used to achieve such synchronization. The benefit of this pseudo-code is that the user RenderGameScene() method can execute simultaneously with Advance, yielding better overall throughput.

Code:

Thread 1: Processing 

while(running) 
{ 
       ProcessInput(); 
  
       movieLock.Lock(); 
       pmovie->Advance(1.0f / FPS); 
      // Unlock and wait until display has completed 
       movieWaitCondition.Wait(&movieLock); 
       movieLock.Unlock(); 
} 


Thread 2: Rendering 

while(running) 
{ 
       RenderGameScane(); 

       movieLock.Lock(); 
       pmovie->Display(); 
       movieLock.Unlock(); 

       movieWaitCondition.Notify();  // Release Thread 1 for processing 

       PresentScene(); 
}

Please note that there is only one exception which will cause the Advance method to affect DirectX data or rendering data. That exception is the function GRenderer::ReleaseCachedData, which can be called from Advance when internal objects die. However, if you are using our renderer implementations, that function will not perform any DirectX/GL calls.

If you have implemented your own renderer where ReleaseCachedData is used to release buffer data, you can make it DirectX thread-safe by simply delaying the buffer destruction (i.e. putting it in a queue) until the next BeginDisplay call or video mode reset. If you are already in the {BeginDisplay, EndDisplay} bracket then you don't need to do such queuing.