AS3 Blitting is Slower than a Movieclip. Why? - actionscript-3

I tried following a combination of Lee Brimlow's blitting tutorial series and and the technique in Rex Van der spuy's "advanced game design with flash"
I am a developer working on a web online virutal world made in flash. I made a phone application (works similar to the phone in grand theft auto games). Anyway, when a message is sent we want to play this crazy animation of an envelope flying around and transforming with sparkles around it. It was laggy (especially on older computers) so I thought it would be a great chance to use blitting. However, the blitting animation actually plays slower than a regular movieclip!! What the heck is going on here? Is blitting only better for mobile devices and actually slower on computers? Maybe I am doing something wrong. Here is my code:
// THIS PART HAPPENS WHEN PHONE IT INITIALIZED
//**
//---------------- Blitting stuff ----------------------------------
// add this bitmap stage to the display list so we can see it
_bitmapStage = new BitmapData(550, 400, true, 0xD6D6D6);
_phoneItself.addChild(new Bitmap(_bitmapStage));
var _spritesheetClass:Class = getDefinitionByName("ESpritesheet_1") as Class;
_spritesheet = new _spritesheetClass() as BitmapData;
_envelopeBlit = new BlitSprite(_spritesheet, BlitConfig.envelopeAnimAry , _bitmapStage);
_envelopeBlit.x = -100;
_envelopeBlit.y = 0;
_envelopePlayTimer = new Timer(5, 0);
_envelopePlayTimer.addEventListener(TimerEvent.TIMER, onEnterTimerFrame);
_envelopeBlit.addEventListener("ENV_ANIM_DONE", onEnvAnimFinished);
// a "BlitSprite" is a class that I made. It looks like this:
package com.fs.util_j.blit_utils
{
import flash.display.BitmapData;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.geom.Point;
import flash.geom.Rectangle;
public class BlitSprite extends EventDispatcher
{
private var _fullSpriteSheet:BitmapData;
private var _rects:Array;
private var _bitmapStage:BitmapData;
private var pos:Point = new Point ();
public var x:Number = 0;
public var y:Number = 0;
public var _animIndex:
int = 0;
private var _count:int = 0;
public var animate:Boolean = true;
private var _whiteTransparent:BitmapData;
private var _envelopeAnimAry:Array;
private var _model:Object;
public function BlitSprite(fullSpriteSheet:BitmapData, envelopeAnimAry:Array, bitmapStage:BitmapData, model:Object = null)
{
_fullSpriteSheet = fullSpriteSheet;
_envelopeAnimAry = envelopeAnimAry;
_bitmapStage = bitmapStage;
_model= model;
init();
}
private function init():void
{
// _whiteTransparent = new BitmapData(100, 100, true, 0x80FFffFF);
this.addEventListener("ENV_ANIM_DONE", onEvnAnimDone);
}
protected function onEvnAnimDone(event:Event):void
{
}
public function render():void
{
// pos.x = x - _rects[_animIndex].width*.5;
// pos.y = y - _rects[_animIndex].width*.5;
// if (_count % 1 == 0 && animate == true)
// {
// trace("rendering");
if (_animIndex == (_envelopeAnimAry.length - 1) )
{
// _animIndex = 0;
dispatchEvent(new Event("ENV_ANIM_DONE", true));
animate = false;
// trace("!!!!animate over " + _model.animOver);
// if (_model != null)
// {
// _model.animOver = true;
// }
// trace("!!!!animate over " + _model.animOver);
}
else
{
_animIndex++;
}
pos.x = x + _envelopeAnimAry[_animIndex][1];
pos.y = y + _envelopeAnimAry[_animIndex][2];
_bitmapStage.copyPixels(_fullSpriteSheet, _envelopeAnimAry[_animIndex][0], pos, null, null, true);
}
}
}
// THIS PART HAPPENS WHEN PHONE'S SEND BUTTON IS CLICKED
_envelopeBlit.animate = true;
_envelopeBlit._animIndex = 0;
_darkSquare.visible = true;
_envelopePlayTimer.addEventListener(TimerEvent.TIMER, onEnterTimerFrame);
_envelopePlayTimer.start();
it also uses BlitConfig which stores the info about the spritesheet spit out by TexturePacker
package com.fs.pack.phone.configuration
{
import flash.geom.Rectangle;
public final class BlitConfig
{
public static var _sending_message_real_20001:Rectangle = new Rectangle(300,1020,144,102);
public static var _sending_message_real_20002:Rectangle = new Rectangle(452,1012,144,102);
public static var _sending_message_real_20003:Rectangle = new Rectangle(852,852,146,102);
public static var _sending_message_real_20004:Rectangle = new Rectangle(2,1018,146,102);
public static var _sending_message_real_20005:Rectangle = new Rectangle(702,822,148,102);
.
.
.
public static var _sending_message_real_20139:Rectangle = new Rectangle(932,144,1,1);
public static var envelopeAnimAry:Array = [
// rectangle, x offset, y offset
[ _sending_message_real_20001, 184,155],
[ _sending_message_real_20002, 184,155],
[ _sending_message_real_20003, 183,155],
[ _sending_message_real_20004, 183,155],
.
.
.
[ _sending_message_real_20139, 0,0]
]
public function BlitConfig()
{
}
}
}

EDIT:
Knowing that this is not mobile, my answer below is irrelevant. I will leave it there, though, in case someone is having trouble with blitting on mobile in the future.
With regards to this specific question, you are running your timer every 5ms. First off, the lowest range that a Timer is accurate is >15ms so that will never be a viable solution. For any Timer relating to displaying soemthing on the stage, you should never do it less than a single frame. (1000/stage.framerate. ~40ms for a 30fps app)
For blitting, the goal is to reduce calculations and rendering. The way you have this set up right now, it looks like you are blitting every 5ms. That is actually more than 8 times as often as the MovieClip is rendering. You should reduce how often you blit. Only do it when a change has actually been made beyond translation. Doing it any more often than that is overkill and the reason it is so slow (again, creating bitmaps is slow)
In general, you do not want to blit in an AIR for Mobile application (which I assume you are doing since you mentioned the phone being initialized). I'm not sure if it is okay to do it using other/native SDKs, but avoid it in AIR.
Essentially, it comes down to how blitting works. Blitting takes a screen capture and displays that on the stage rather than the actual object. In general, this is great. It means that your display objects, particularly vectors which are slow to render, have to render far less often. It is especially good when animating because an object tends to re-render every time it is translated in any way, but not a bitmap.
On mobile platforms, however, creating that bitmap is incredibly slow. I've never looked into how the SDK creates the Bitmaps, but it doesn't do it efficiently (it often makes me wonder if it does it pixel-by-pixel). On desktops, this is generally fine. There is plenty of CPU and plenty of RAM to make this happen quickly. On mobile, however, that luxury is not there at the moment. So when you blit and create that bitmap, it takes a while to run that process.
The problem is exacerbated on high-resolution screens. An app I developed from January to May of this year selectively used blitting to use filters in a GPU accelerated environment. On an iPad 2, the blitting took my app from 30fps to ~24fps. Not a big deal, not anything the user would notice. On an iPad 3 with retina display, however, it dropped down to 10fps. It makes sense when you think about it, as retina iPads have 4x as many pixels as non-retina iPads do.
If you do want to use blitting on mobile, I recommend a few things:
Use GPU rendering mode. Without it, you stand no chance. Be aware that, at least with pre-AIR 3.7, filters were not supported in GPU mode. I am unsure if that is still the case. You should avoid using filters on mobile regardless, though, as they are very slow to render
Make sure to test a release-mode application. Depending on build settings, the difference between debug mode and a release mode app can be substantial, especially on iOS. An app I just developed went from taking 2-3 seconds to create a new Flex View in debug mode to less than a frame (~40ms) to do it in release mode on an iPhone 4
Use blitting sparingly. Only do it where absolutely necessary
Look for ways to simplify your display list. It is easy to have an object with 40 children to create a button. Instead, look for ways to simplify that into fewer objects and fewer filters (even if removing a filter requires you add another object). I don't believe this will help with the actual blitting process, but it should help with rendering the objects in the first place.
So in general, use blitting sparingly on mobile because bitmap creation is slow.

Related

AS3/ AIR Alternative to PrevFrame() (too slow if big movieclip)

I'm having a problem with prevFrame(). In my previous projects, I never had a trouble with it (usage is pretty straightforward), but this one... I don't understand. Everything does what it needs to do, but when I try to go to the prevFrame of my "main movieclip", it takes ages.
Some context: I'm making a dictionary for an ancient language (non-latin alphabet). There are 6.000 glyphs so I had to find a way to make such a complex "keyboard".
var gArray: Array = [gEmpty, clavierUI.g1, clavierUI.g2, clavierUI.g3, (...)
clavierUI.g50
]; //array contaning the buttons for the keyboard (50 instances of the same
//movieclip. This movieclip is made of 6.000 frames, each containing a
//glyph), the fnClavier function makes each of the fifty instances go to its
//respective frame)
var myXML2: XML = new XML();
var XML_URL2: String = "assets/glyphs.xml";
var myXMLURL2: URLRequest = new URLRequest(XML_URL2);
var myLoader2: URLLoader = new URLLoader(myXMLURL2);
myLoader2.addEventListener("complete", xmlLoaded2);
//import the codename for each glyph
function xmlLoaded2(event: Event): void {
myXML2 = XML(myLoader2.data);
}
var xml2: XMLList = myXML2.glyph.code;
function fnClavier(e: Event): void { //transforms the keyboard
for each(var glyph: MovieClip in gArray) {
glyph.gotoAndStop(gArray.indexOf(glyph) + (50 * (clavierUI.currentFrame - 1)));
//the seconde half (50 * (...) -1))) can be explained like that :
//50 = 50 keys by keyboard "page".
// clavier.currentFrame - 1 = modifier, tells which set of the 6000 glyphs
//needs to appear (and later, correspond with the codename from xml)
}
}
clavierUI.nextPage.addEventListener(MouseEvent.CLICK, fnNextPage);
function fnNextPage(e: Event): void {
clavierUI.nextFrame(); //no problem here, goes fast.
fnClavier(null);
}
clavierUI.prevPage.addEventListener(MouseEvent.CLICK, fnPrevPage);
function fnPrevPage(e: Event): void {
clavierUI.prevFrame(); //takes about 20secondes to go back.
fnClavier(null);
}
My code is probably far from being perfect (i'm still learning), but I don't know why it wouldn't work. Jumping around the frames and going to the next works perfectly, so anyone know why going back one frame takes forever?
Thank you.
You'd better use containers instead of frames. Frames get constructed and deconstructed each time you move between keyframes, while you con construct all the containers once and then display them as needed, one container at a time. I expect that Flash has optimization somewhere that constructs the next frame prior to it being shown via nextFrame() while an abrupt calling of prevFrame() forces Flash to construct it at once, and if it's very complex, it can take a lot of time.
You have 6000 glyphs? That's a lot, but not too much. You can create a set of containers, each holding 120 glyphs, for example. To do that, you create an array of Sprites, each having a grid of glyphs 12x10, there will be 50 of these. Then, when you need another page, display another sprite from the array. Also, if your glyph is a static vector object, you should convert it to vector graphics, and add as library item (Shape descendant, these eat less memory). If it's raster, use Bitmap and underlying BitmapData classes to use them.

AS3 best way to mass crop tiles from a tilesheet?

Okay so I'm trying to create a program that reads a map from a csv file and then draw each tile using a tilesheet. Reading in the map works fine and I could draw certain tiles depending on the value read in but only if I embedded the images. Obviously this is impractical when it comes to having >20 different tiles; embedding them all just wouldn't be smart.
This is my code for drawing the tiles from the tilesheet.
package
{
import flash.display.Graphics;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.geom.Point;
public class Tile extends Sprite
{
[Embed(source="../bin/lib/TileSheet.png")]
private var BitmapClass:Class;
private var tileBitmap:Bitmap = new BitmapClass();
var tileSize = 25;
var tileSheetLength = 20;
var sheetColumns:int = tileBitmap.bitmapData.width / tileSize;
var pt:Point = new Point(0, 0);
var bmp:Bitmap = new Bitmap(new BitmapData(tileSize, tileSize, true, 0));
public function Tile(collide:Boolean, id:int)
{
Draw(id);
}
private function Draw(id:int):void
{
var col:int = id % sheetColumns;
var row:int = Math.floor(id / sheetColumns);
var rect:Rectangle = new Rectangle(col * tileSize, row * tileSize, tileSize, tileSize);
bmp.bitmapData.copyPixels (tileBitmap.bitmapData, rect, pt, null, null, true);
this.addChild(bmp);
}
public function Update():void
{
}
}
}
'
So what I need help with is optimising this code so that I can run it around 1,900 times rather than the 910-911 times it can handle right now before just closing without errors. If there is a better way of doing this please let me know and any constructive criticism is always appreciated!
You have a Tile class which has a BitmapClass instance. Perhaps that should be a static property (belonging to the class, not every instance) to begin with. My guess is you're using the memory for the whole tile sheet every since time you instantiate a single tile which you probably don't want to do.
Another thing I'm noticing is you're creating a new BitmapData for each tile, when in fact you probably just need the tile data (it's id/coordinates) so you can copy pixels into the final BitmapData which gets displayed on stage. Perhaps you need to a class to manage resources(embedded bitmaps) and another to manage the different Tile instance(which should hold render data and references to pixels, but shouldn't store the actual data) and copying to the main buffer.
Also, it's a good idea to use BitmapData's lock() and unlock() functions for performance when doing multiple pixel operations on an image.
Have a look at Lee Brimelow's Sprite Sheet tutorials (part 1,2 and especially 3). They're really easy to follow and useful.
Also, it might be worth having a look at the have a look at the GPU accelerated IsoHill
library.
I've used IsoHill for a project before and it's quite fast, but it's best to get comfortable with the basics first, otherwise this might seem a bit much.

JWPlayer: Trying to bound the video player inside my own container

I am using the JWPlayer source code for 6.0.2813 (http://developer.longtailvideo.com/trac/) and It seems the even though I have a movieclip and I added the jwplayer class as a child, the jwplayer creates itself as a child of the main stage, thus allowing it to expand to the bound of the stage and not my movieclip (which I want to be a resizeable/draggable container) in my flash.
I asked the forums for help but they said they never intended it this way and wasn't much help. I was hoping someone familar with the source code could point my in the right direction.
How can I get the JWPlayer to be contained to a movieclip?
Edit:
I made a little bit of progress.
I found the RootReference class in com/longtailvideo/jwplayer/utils/RootReference.as
public function RootReference(displayObj:DisplayObject) {
if (!RootReference.root) {
RootReference.root = displayObj.root;
RootReference.stage = displayObj.stage;
try {
Security.allowDomain("*");
} catch(e:Error) {
// This may not work in the AIR testing suite
}
}
}
And noticed that the RootReference.stage is where things get added as a child. RootReference.stage = displayObj.stage; where the player class object is sent as displayObj I changed it to be RootReference.stage = MovieClip(root).gui.video_container;
Then throughout the code RootReference.stage.stageHeight and RootReference.stage.stageWidth was used so I switched it to RootReference.stage.height and RootReference.stage.width. This got it to compile and now the video is within the container but the video's top left is center on my video_container's center and the video isn't resized to the size of my container, but rather the size of the video. Also the controls are completely messed up.
But I was able to resize and move the video around
Assuming my testing scenarios are representative of your use-cases, I think I managed to hack up a work around.
The gist of the approach is to replace RootReference.root and RootReference.stage with a fake stage object that you control. Because most of the jwPlayer classes refer to those static variables instead of their own root and stage variables, this seems to work, for the most part. What ended up being the most complicated issue was working with the Stage.stageVideo objects, which I think are the hardware accelerated video objects. These are always attached to the stage and thus weren't compatible with the fake stage object. The main issue with those is positioning, and I have it mostly worked out, but there is still one glitch which I'll describe later but it should be ok, now.
The jwPlayer embed script was causing a lot of problems, so to get started I switched to normal SWFObject-based embedding and added a javascript function to the page called getFlashvars() that returned the configuration settings. Then, I changed the com.longtailvideo.jwplayer.utils.Configger.loadExternal() method to the following:
private function loadExternal():void {
if (ExternalInterface.available) {
try {
//var flashvars:Object = ExternalInterface.call("jwplayer.embed.flash.getVars", ExternalInterface.objectID);
var flashvars:Object = ExternalInterface.call("getFlashvars");
if (flashvars !== null) {
// TODO: add ability to pass in JSON directly instead of going to/from a string
for (var param:String in flashvars) {
setConfigParam(param, flashvars[param]);
}
dispatchEvent(new Event(Event.COMPLETE));
return;
}
} catch (e:Error) {}
}
}
That's something you probably don't have to deal with per not using a webpage.
The fake stage class is called StageInterceptor and is a singleton. To apply it, there were minor changes in the RootReference class:
package com.longtailvideo.jwplayer.utils {
import flash.display.DisplayObject;
import flash.display.Stage;
import flash.system.Security;
// added --------
import somePackage.StageInterceptor;
/**
* Maintains a static reference to the stage and root of the application.
*
* #author Pablo Schklowsky
*/
/* Modified for a stackoverflow question: http://stackoverflow.com/questions/13325318/jwplayer-trying-to-bound-the-video-player-inside-my-own-container */
public class RootReference {
/** The root DisplayObject of the application. **/
public static var root:DisplayObject;
// altered --------
/** A reference to the stage. **/
private static var _stage:StageInterceptor;
// altered --------
public static function get stage():StageInterceptor {
return _stage;
}
public function RootReference(displayObj:DisplayObject) {
if (!RootReference.root) {
// altered --------
RootReference.root = StageInterceptor.singleton;
RootReference._stage = StageInterceptor.singleton;
try {
Security.allowDomain("*");
} catch(e:Error) {
// This may not work in the AIR testing suite
}
}
}
}
}
Also, I removed the set stage() setter method from the class.
In the document class, I have the following code. The MouseEvent.CLICK handler is to test positioning and re-sizing the movie. The only thing you really need are the first few lines:
// add StageInterceptor to the display tree
addChild(StageInterceptor.singleton);
// add the jwPlayer:
var p:Player = new Player();
StageInterceptor.singleton.addChild(p);
// for testing only:
stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
var stg:StageInterceptor = StageInterceptor.singleton;
if (e.altKey) {
// click + alt: ignored (so can play, etc)
return;
} else if (e.shiftKey) {
// click + shift: resizes
stg.width = e.stageX - stg.x;
stg.height = e.stageY - stg.y;
} else {
// click: moves video
stg.x = e.stageX;
stg.y = e.stageY;
}
});
I put StageInterceptor in the package somePackage. It looks like this:
package somePackage
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.InteractiveObject;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.media.StageVideo;
public class StageInterceptor extends Sprite
{
private static var _singleton:StageInterceptor = new StageInterceptor();
public static function get singleton():StageInterceptor {
return _singleton;
}
private var _bg:Bitmap;
public function StageInterceptor()
{
super();
scrollRect = new Rectangle(0, 0, 500, 500);
var bmpData:BitmapData = new BitmapData(500, 500, false, 0);
_bg = new Bitmap(bmpData);
_bg.alpha = 0.1;
_bg.cacheAsBitmap = true;
addChild(_bg);
if (stage) {
initOnStage();
} else {
addEventListener(Event.ADDED_TO_STAGE, initOnStage);
}
}
private function initOnStage(e:Event = null):void {
if (e) {
removeEventListener(Event.ADDED_TO_STAGE, initOnStage);
}
stage.addEventListener(Event.RESIZE, onStageResized);
}
private function onStageResized(e:Event):void {
e.stopImmediatePropagation();
dispatchEvent(new Event(Event.RESIZE));
updateStageVids();
}
public function updateStageVids():void {
if (stage.stageVideos.length > 0) {
for each (var sv:StageVideo in stage.stageVideos) {
if (!sv.videoWidth || !sv.videoHeight) {
continue;
}
var rect:Rectangle = stretch(sv.videoWidth, sv.videoHeight, width, height);
rect.x = Math.max(0, x + 0.5 * (width - rect.width))
rect.y = Math.max(0, y + 0.5 * (height - rect.height));
sv.viewPort = rect;
}
}
}
override public function get width():Number {
return scrollRect.width;
}
override public function set width(value:Number):void {
if (value != width) {
_bg.width = value;
scrollRect = new Rectangle(0, 0, value, scrollRect.height);
dispatchEvent(new Event(Event.RESIZE));
updateStageVids();
}
}
override public function set height(value:Number):void {
if (value != height) {
_bg.height = value;
scrollRect = new Rectangle(0, 0, scrollRect.width, value);
dispatchEvent(new Event(Event.RESIZE));
updateStageVids();
}
}
override public function get height():Number {
return scrollRect.height;
}
public function get stageWidth():Number {
return scrollRect.width;
}
public function get stageHeight():Number {
return scrollRect.height;
}
public function get scaleMode():String {
return stage.scaleMode;
}
public function set scaleMode(value:String):void {
stage.scaleMode = value;
}
public function get displayState():String {
return stage.displayState;
}
public function set displayState(value:String):void {
stage.displayState = value;
}
public function get focus():InteractiveObject {
return stage.focus;
}
public function set focus(value:InteractiveObject):void {
stage.focus = value;
}
public function get stageVideos():* {
return stage.stageVideos;
}
override public function set x(value:Number):void {
if (value != x) {
super.x = value;
updateStageVids();
}
}
override public function set y(value:Number):void {
if (value != y) {
super.y = value;
updateStageVids();
}
}
/**
* Copied from com.longtailvideo.jwplayer.utils.Stretcher, modified to only
* do 'uniform' stretch and to return a Rectangle class.
**/
public static function stretch(elmW:Number, elmH:Number, availW:Number, availH:Number):Rectangle {
var scale:Number = Math.min(availW / elmW, availH / elmH);
elmW = Math.round(elmW * scale);
elmH = Math.round(elmH * scale);
return new Rectangle(0, 0, elmW, elmH);
}
}
}
The issue that remains has to do with the positioning of video instances when they are initialized. I think simply calling StageInterceptor.singleton.updateStageVids(); at the right point will do the trick, but I'm not sure. The edit below covers how this was addressed.
I'm not sure how well this will work if you're not using stageVideo. But, with any luck, this will move things in the right direction.
Edit:
I've updated the StageInterceptor class to do a better job scaling and positioning the video.
Also, it looks like the initial position of videos (at least when it's a stageVideo, is that what you're using?) can be corrected by a small edit in the com.longtailvideo.jwplayer.media.VideoMediaProvider class. Adding import somePackage.StageInterceptor; to the import statements at the top and then replacing this line (link to source):
_stage.viewPort = new Rectangle(_media.x,_media.y,_media.width,_media.height);
To:
StageInterceptor.singleton.updateStageVids();
So the method looks like:
/** Resize the video or stage.**/
override public function resize(width:Number, height:Number):void {
if(_media) {
Stretcher.stretch(_media, width, height, _config.stretching);
if (_stage) {
//_stage.viewPort = new Rectangle(_media.x,_media.y,_media.width,_media.height);
StageInterceptor.singleton.updateStageVids();
}
}
}
This should do the trick, but I haven't tested it for non stageVideos. And, this update also assumes you're playing videos progressively, not using RTMP media.
Edit:
To enable moving and resizing the player with non-StageVideo videos, but still progressively loaded, the contents of the com.longtailvideo.jwplayer.view.View.resizeMasker() method need to be either commented out or deleted:
protected function resizeMasker():void {
/*
if (_displayMasker == null)
setupDisplayMask();
_displayMasker.graphics.clear();
_displayMasker.graphics.beginFill(0, 1);
_displayMasker.graphics.drawRect(_components.display.x, _components.display.y, _player.config.width, _player.config.height);
_displayMasker.graphics.endFill();
*/
}
I also want to mention the open source version of the jwPlayer is governed under the Creative Commons license, as noted on their site:
JW Player 6 — Open Source Edition
The use of the JW Player Open Source edition is governed by a Creative Commons license. In short:
JW Player Open Source - You can use, modify, copy, and distribute this edition as long as it's for non-commercial use, you provide attribution, and share under a similar license.
The license summary and full text can be found here: CC BY-NC-SA 3.0
I'll address the jwPlayer portion of your question since flash is not my forte.
The problem here is jwPlayer is not a simple flash player, but also a HTML5 Multimedia Player as well.
Solution 1: SWFObject embedded in your Flash Object
Since jwPlayer is already compatible with SWFObject, use that (i.e., swfobject.js) as a mediator to load the player.swf file (aka jwPlayer) into your flash stage. To be sure, SWFObject acts as a container and will be the "bounded item" in your stage, as opposed to using jwPlayer directly.
Here is an online demo illustrating this solution except it's using a simple flash video player.
Flash Web Site with embedded SWFObject Logo Playing Music Video
Flash Web Site Documentation on swfObject
Note the HTML source page for that flash website shows RockOnFlashLogo.swf as the file being shown in the browsers entire viewport. Looking deeper, it's written in AS3.
Unlike jwPlayer v4 where many ideas floated on the internet to embed that version into flash websites due to its lax security, I think you'll have issues with current jwPlayer license checking, webpage Ready Event Listeners, and popular plugin integration... not to mention issues that may arise from streaming video content.
IMHO, the newer jwPlayer API and Player are intended to be use via webpage installation.
Solution 2: SWFObject On-Top of your Flash Object
This method treats jwPlayer how it was meant to be used; as a webpage installation. My motivation came from this online demo for Google Chrome Experiment | The Wilderness Downtown.
That demo places strategically synchronized browser windows on-top of the main browser window. Although the main browser window is in charge, all windows make up the entire experience. The same method, but flash flavored, can be done with your current project with excellent results.
Your Flash Object is in charge and contains within an interactive frame that is allocated for the jwPlayer webpage component. To be sure, this interactive frame for jwPlayer can accept relocation (e.g., via dragging frame edges) and resize (e.g, frame has resize-icon bottom-right) which is then relayed to the webpage component (i.e., player.swf) via SWFObject standard embed techniques (i.e., location and size set with jQuery).
Here's a basic cross-section of a webpage for three layered items:
The black layer is the HTML of the webpage. The red layer is your flash object which contains also has the built-in interactive frame shown in aqua. The green top layer is the SWFObject for jwPlayer's player.swf file.
Here's how it would work from jwPlayer to your flash object:
1. Webpage jwPlayer API has event listener active and can accept JavaScript.
2. Then jwPlayer API receives 'play' status from player, updates player event status.
3. Player Event Status is true for Play, and therefore triggers conditional if statement.
4. That if statement then transmits JavaScript to your flash object, indicating play mode is true.
5. Your flash object receives this JavaScript of play event, and dims the stage, less the aqua frame.
Here's how it would work from your flash object to jwPlayer:
1. The aqua frame has user interaction when it's moved to left side of stage.
2. Your AS3 code moves the aqua frame accordingly, while sending out JavaScript of that location.
3. Webpage receives JavaScript and invokes function to position jwPlayer player at new location.
Tip: If using a custom jwPlayer Skin, incorporate that skin theme into your flash object for a uniform look.
The benefit of this scenario is that jwPlayer maintains 100% integrity while both these flash objects work in tandem on your webpage. No hacks, no breakage, no unforeseen consequences, and no headaches... it's standard jwPlayer API and AS3 markup in use.
Hovering over the jwPlayer itself is 100% jwPlayer, while being bound to your flash object indirectly.
Per your written comments that JW Player will not have any access to JavaScript and will be using Firefox Source that is a specialized 3D Game/Chat Engine without access to any DOM elements outside the player, the best solution is to use JW Player Enterprise Edition.
That solution will put you in touch with the Marketing & Engineering department which can provide a turnkey solution to have JW Player integrated into your own product.
Click the image below which includes Licensing information as well:

AS3 SecurityPanel not showing when hardware acceleration is used

If I publish Windows Projector (.exe) with no hardware acceleration, everything works fine, but if I select direct or gpu harware acceleration I will not get the security panel to show up at all. Anyone else have this same issue, or is it just me?
Basically I would like to publish a stand-alone webcam game, but if I try to use getCamera(), the user will not see the security question at all, and I will not get the camera initialized.Does anyone know a workaround for this? I would love to get HW acceleration to my game.
import flash.system.Security;
import flash.system.SecurityPanel;
//import flash.media.Camera;
Security.showSettings(SecurityPanel.CAMERA);
//var camera:Camera=Camera.getCamera();
I got this to work, but I created a projector through the stand alone and the "Create Projector" menu, not through the Flash IDE. I was able to get the panel to show up using the latest flash.
compiler settings: -swf-version=16 -use-gpu=true
// test showing stage3D + panel
final public class Test extends Sprite {
private var cam:Camera;
private var video:Video = new Video();
public function Test():void {
var stage3D:Stage3D = stage.stage3Ds[0];
stage3D.addEventListener(Event.CONTEXT3D_CREATE, handleContext);
stage3D.requestContext3D();
trace(cam.name);
}
/**
* #private
*/
private function handleContext(e:Event):void {
var stage3D:Stage3D = stage.stage3Ds[0];
var context:Context3D = stage3D.context3D;
context.configureBackBuffer(stage.stageWidth, stage.stageHeight, 0, true);
context.clear(0,0,0,1);
context.present();
Security.showSettings(SecurityPanel.CAMERA);
cam = Camera.getCamera();
cam.setMode(640,360,30);
video.attachCamera(cam);
// change to upload via texture instead
addChild(video);
}
In my experience, hardware acceleration gains are only very minimal without using specific gpu apis. Camera in my experience instead accelerated, only specific types of video decompression. If you're not using Stage3D, you probably won't get any visible gains.

How can I load a Papervision/Flex application (SWF) as a material on a Papervision plane?

I am trying to build a portfolio application similar to the used by Whitevoid. I am using Flex 4 and Papervision3D 2. I have everything working except for one issue. When I try to load an external SWF as a material on one of the planes, I can see any native Flex or Flash components in their correct positions, but the papervision objects are not being rendered properly. It looks like the viewport is not being set in the nested swf. I have posted my code for loading the swf below.
private function loadMovie(path:String=""):void
{
loader = new Loader();
request = new URLRequest(path);
loader.contentLoaderInfo.addEventListener(Event.INIT, addMaterial);
loader.load(request);
}
private function addMaterial(e:Event):void
{
movie = new MovieClip();
movie.addChild(e.target.content);
var width:Number = 0;
var height:Number = 0;
width = loader.contentLoaderInfo.width;
height = loader.contentLoaderInfo.height;
//calculate the aspect ratio of the swf
var matAR:Number = width/height;
if (matAR > aspectRatio)
{
plane.scaleY = aspectRatio / matAR;
}
else if (matAR < aspectRatio)
{
plane.scaleX = matAR / aspectRatio;
}
var mat:MovieMaterial = new MovieMaterial(movie, false, true, false, new Rectangle(0, 0, width, height));
mat.interactive = true;
mat.smooth = true;
plane.material = mat;
}
Below I have posted two pictures. The first is a shot of the application running by itself. The second is the application as a MovieMaterial on a Plane. You can see how the button created as a spark object in the mxml stays in the correct position, but papervision sphere (which is rotating) is in the wrong location. Is there something I am missing here?
Man. I haven't seen that site in a while. Still one of the cooler PV projects...
What do you mean by:
I cannot properly see the scene rendered in Papervision
You say you can see the components in their appropriate positions, as in: you have a plane with what looks like the intended file loading up? But I'm guessing that you can't interact with it.
As far as I know, and I've spent a reasonable amount of time trying to make something similar work, the MovieMaterial (which I assume you're using) draws a Bitmap of whatever contents exist in your MovieClip, and if you set it to animated=true, then it will render out a series of bitmaps - equating animation. What it's not doing, is displaying an actual MovieClip (or SWF) on the plane. So you may see your components, but this is how:
MovieMaterial.as line 137
// ______________________________________________________________________ CREATE BITMAP
/**
*
* #param asset
* #return
*/
protected function createBitmapFromSprite( asset:DisplayObject ):BitmapData
{
// Set the new movie reference
movie = asset;
// initialize the bitmap since it's new
initBitmap( movie );
// Draw
drawBitmap();
// Call super.createBitmap to centralize the bitmap specific code.
// Here only MovieClip specific code, all bitmap code (maxUVs, AUTO_MIP_MAP, correctBitmap) in BitmapMaterial.
bitmap = super.createBitmap( bitmap );
return bitmap;
}
Note in the WhiteVoid you never actually interact with a movie until it "lands" = he's very likely swapping in a Movie on top of the bitmap textured plane.
The part that you are interacting with is probably another plane that holds the "button" that simply becomes visible on mouseover.
I think PV1.0 had access to real swfs as a material but this changed in 2.0. Sadly. Hopefully Molehill will.
cheers