Stumped getting bitmaps from movieClips in an external Flash SWF library - actionscript-3

My testbed is able to composite a thousand elements into clips on screen, but I can't extract a bitmap on the fly from an external swf for Starling or for export to png.
(I'm a bit of a code butcher, but have tried lot of variations and have looked through spritesheet generating examples))
I have seen the advice "You can't get bitmapData from a Class only displayObjects (MClip, Sprite)", My line: s = new AssetClass() below seems to address that.
Correct usage of addtoStage when loading external swf
I am able to generate a bitmap of an internal vector movieclip, and save it to a .png using as3corelib.PNGEncoder.as, but I end up with a blank png using clips from the external swf, running this in Flash Pro CC..
paraphrased code:
// swf load done handler:
testBitmap = new Bitmap(new BitmapData(w, h , true, 0x0));
var AssetClass:Class = getDefinitionByName("assetNameFromDatabase") as Class;
var s:MovieClip = new AssetClass(); // AddChild(s) functions properly
var m:Matrix = new Matrix(1, 0, 0, 1, 400, 300);
testBitmap.bitmapData.draw(s, m);
// addChild(testBitmap); or send to PNGEncoder rsult is blank
// internal clip test that does convert to bitmap
var b:MovieClip = new testdMovieClip();
var m:Matrix = new Matrix(1, 0, 0, 1, 200, 300);
testBitmap.bitmapData.draw(b, m);
//----------------------------
Thanks Vesper, Couldn't gfix things with your suggestion, I was actually already adding to a movieClip, just left it out of the simplified code sample, I did try some variates of adding an instance ahead of drawing to bitmap, still getting no results.
//--
*** Amendment: Looks like the libs have embedded "display but don't copy" protect code? can someone verify this.
I am using merged movieclip libraries provided in swf format, (I have individual fla source for the hundreds of resources in the library swfs that I hoped to avoid dealing with, their removing swf import from Flash Pro cc is a further agrrevation) This is public domain material from a retired game.
Using a Trillix trial, I examined the embedded Class files, along with the usual individual asset Class they had this code:
public override function get movieClipData():flash.utils.ByteArray
{
if (bytes == null)
{
bytes = flash.utils.ByteArray(new dataClass());
}
return bytes;
}
{
bytes = null;
}
internal static var bytes:flash.utils.ByteArray=null;
// the classes also have
import flash.utils.*;
import mx.core.*; // as well as embedded package mx files, is that for Flex?
I was looking at creating some code-less external library files for Air/iOS down the road, I may have to learn to ways to auto merge FLAs sooner than later.

I have seen weird behavior of width and height properties of shape/sprite objects while they are not added to display list, they return -100 million or something. So you should add, then draw, then remove. This trick helped me when I wrote a dynamically generated sprite.
testBitmap = new Bitmap(new BitmapData(w, h , true, 0x0));
var AssetClass:Class = getDefinitionByName("assetNameFromDatabase") as Class;
var s:MovieClip = new AssetClass(); // AddChild(s) functions properly
addChild(s); // !
var m:Matrix = new Matrix(1, 0, 0, 1, 400, 300);
testBitmap.bitmapData.draw(s, m);
removeChild(s);
addChild(testBitmap); // now should display properly

Related

Using a Numeric Stepper from one Flash file to affect gamespeed in an external Flash file? Actionscript 3.0

Currently I have an intro screen to my flash file which has two objects.
A button which will load an external flash file using:
var myLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("flashgame.swf");
The second thing is a Numeric Stepper, which will be from 1 to 10. If the user selects a number e.g. 3 then the game speed I have set in the flashgame.swf should be changed
Such as:
var gameSpeed:uint = 10 * numericStepper.value;
But I think my problem is coming into place because the stepper and gamespeed are from different files.
Anyone got any idea please?
I have also tried creating a stepper in the game file and used this code:
var gameLevel:NumericStepper = new NumericStepper();
gameLevel.maximum = 10;
gameLevel.minimum = 1;
addChild(gameLevel);
var gameSpeed:uint = 10 * gameLevel.value;
For some reason the stepper just flashes on the stage, no errors come up and the game doesn't work
When you execute you code, the stepper has no chance to wait for user input.
There is no time between theese two instructions.
addChild(gameLevel);
var gameSpeed:uint = 10 * gameLevel.value;
You should wait for user input in your NumericStepper, and then, on user event, set the game speed.
Edit: Yeah I know it's kinda sad to type out all this code (especially since some people wouldn't even be grateful enough to say thanks) but I think this question is important enough to justify the code as it may be helpful to others in future also.
Hi,
You were close. In your game file you could have put a var _setgameSpeed and then from Intro you could adjust it by flashgame._setgameSpeed = gameSpeed; It's a bit more complicated though since you also have to setup a reference to flashgame in the first place. Let me explain...
Ideally you want to put all your code in one place (an .as file would be best but...) if you would rather use timeline then you should create a new empty layer called "actions" and put all your code in the first frame of that.
Also change your button to a movieClip type and remove any code within it since everything will be controlled by the code in "actions" layer. In the example I have that movieclip on the stage with instance name of "btn_load_SWF"
Intro.swf (Parent SWF file)
var my_Game_Swf:MovieClip; //reference name when accessing "flashgame.swf"
var _SWF_is_loaded:Boolean = false; //initial value
var set_gameSpeed:int; //temp value holder for speed
var swf_loader:Loader = new Loader();
btn_load_SWF.buttonMode = true; //instance name of movieclip used as "load" button
btn_load_SWF.addEventListener(MouseEvent.CLICK, load_Game_SWF);
function load_Game_SWF (event:MouseEvent) : void
{
//set_gameSpeed = 10 * numericStepper.value;
set_gameSpeed = 100; //manual set cos I dont have the above numericStepper
if ( _SWF_is_loaded == true)
{
stage.removeChild(swf_loader);
swf_loader.load ( new URLRequest ("flashgame.swf") );
}
else
{ swf_loader.load ( new URLRequest ("flashgame.swf") ); }
swf_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, Game_SWF_ready);
}
function Game_SWF_ready (evt:Event) : void
{
swf_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, Game_SWF_ready);
//Treat the Loader contents (flashgame.swf) as a MovieClip named "my_Game_Swf"
my_Game_Swf = swf_loader.content as MovieClip;
my_Game_Swf.gameSpeed = set_gameSpeed; //update gameSpeed variable in flashgame.swf
//also adjust SWF placement (.x and .y positions etc) here if necessary
stage.addChild(my_Game_Swf);
_SWF_is_loaded = true;
}
Now in you flashgame file make sure the there's also an actions layers and put in code like this below then compile it first before debugging the Intro/Parent file. When your Intro loads the flashgame.swf it should load an swf that already has the code below compiled.
flashgame.swf
var gameSpeed:int;
gameSpeed = 0; //initial value & will be changed by parent
addEventListener(Event.ADDED_TO_STAGE, onAdded_toStage);
function onAdded_toStage (e:Event):void
{
trace("trace gameSpeed is.." + String(gameSpeed)); //confirm speed in Debugger
//*** Example usage ***
var my_shape:Shape = new Shape();
my_shape.graphics.lineStyle(5, 0xFF0000, 5);
my_shape.graphics.moveTo(10, 50);
my_shape.graphics.lineTo(gameSpeed * 10, 50); //this line length is affected by gameSpeed as set in parent SWF
addChild(my_shape);
}
The key line in intro.swf is this: my_Game_Swf.gameSpeed = set_gameSpeed; as it updates a variable in flashgame.swf (referred as my_Game_Swf) with an amount that is taken from a variable in the Parent SWF.
This is just one way you can access information between two separate SWF files. Hope it helps out.

load an external swf (FlashPaper pdf) into a flash project

I have to do a very simple swf application able to show a series of pdf files.
Actually I was able to create on a single layer the menu interface (some buttons on frame 0 which redirect the user to other frames where the pdf should be showed).
Here my question:
I need a way to read the pdf inside the flash frame.
I've found a possible solution converting the pdf into an swf with FlashPaper 2
Now I wish to know how import the swf into the frame.
Reading some actionscript 3 guides I was able to create a container movieclip (a simple rectangle) into which I have loaded the swf with this code:
var swf:MovieClip;
var loader:Loader = new Loader();
var defaultSWF:URLRequest = new URLRequest("test.swf"); //test.swf is my converted pdf
loader.load(defaultSWF);
screen_01.addChild(loader); //screen_01 is the container rectangle converted to movieclip
I've used a container movieclip to mantain the other objects (menu buttons) on the frame, and ecause it helps with the swf positioning.
I seen it is possible also using loader.x and loader.y and it works.
Unfortunately I wasn't able to control width and height of the swf/pdf file (loader.width and loader.height exists but if used cause the swf will not loaded at all)
Solution:
I've found a possible solution at this page. The idea is to change swf scale only after the load process is complete (positioning can be done even before).
Anyway I had to use Actionscript 2 for this project because FlashPaper converted pdf doesn't work properly with AS3, I don't know why...
here the code:
//insert an emplty movieclip to load the swf, I've called it screen_01
var movLoad:MovieClipLoader = new MovieClipLoader();
var myListener:Object = new Object();
myListener.onLoadInit = function(thisMc:MovieClip) {
thisMc._height = 600;
thisMc._width = 900;
thisMc._x = 50;
thisMc._y = 30;
};
movLoad.addListener(myListener);
movLoad.loadClip("folder/flashpaper_converted_pdf.swf.swf",screen_01);
You can modify the size of the loader using scaleX and scaleY properties.
Keep them equals so the swf isn't stretched.
You may also want to listen to the COMPLETE event to do such a thing :
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
function onComplete(e:Event)
{
var loader:Loader = e.currentTarget.loader;
loader.scaleX = loader.scaleY = 2; //Double the size of the loaded swf
}

Actionscript 3 - Import SVG file

Does anyone know of any libraries or tools for importing an SVG file into actionscript on the fly? I need to be able to import an SVG file into flash and convert it to a movieclip or preferably a flat 3d object. The end goal here is to implement a vector file with Augmented reality.
A great library for this can be downloaded here: http://code.google.com/p/as3svgrendererlib/
It is easy to implement and reliable. Note that there are two ways to implement the code. I prefer the following because it gives you more control:
private function loadSVG(url:String):void {
ProcessExecutor.instance.initialize(stage);
ProcessExecutor.instance.percentFrameProcessingTime = 0.9;
loader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.addEventListener(Event.COMPLETE, svgLoaded, false, 0, true);
try {
loader.load(new URLRequest(url));
} catch (error:Error) {
trace(error);
}
}
private function svgLoaded(e:Event):void {
var svgString:String = loader.data as String;
var svgDocument:SVGDocument = new SVGDocument();
svgDocument.parse(svgString);
this.addChild(svgDocument);
}
The other way is shorter and might be the way to go when you only have to load a small SVG or just a few.
public function loadSVG(url:String) {
ProcessExecutor.instance.initialize(stage);
ProcessExecutor.instance.percentFrameProcessingTime = 0.9;
var svgDocument:SVGDocument = new SVGDocument();
svgDocument.load(url);
addChild(svgDocument);
}
Two important notes:
1. I could not seem to be able to capture the width or height of the SVGs and the parent Sprite had a width and height of 0 after loading the SVG. I solved this by making all the SVGs the same size before loading them into AS3. After that I knew the dimensions I used the ScaleX and scaleY to resize the loaded SVGs.
2. The stage has to exist before you can use this code. adding the following code will make sure you won't run into problems:yourDisplayClass.addEventListener(Event.ADDED_TO_STAGE, loadYourSVGs);
Now how you convert this to a flat 3D object depends on your 3D Library. I have worked with Away3D where you can use bitmapmaterial on your Sprite3D. The Sprite3D class would be the object to use. I hope your 3D Library supports the use of MovieClips so that you can add them to your 3D Object. Else you will have to use to extract the bitmapMaterial from the movie clip as i have done in the following example:
public function movieClipToBitmapMaterial(mc:MovieClip):BitmapMaterial {
var bmData:BitmapData = new BitmapData(mc.width, mc.height, true, 0xFFFFFF);
bmData.draw(displayObject);
return new BitmapMaterial(bmData);
}
Your input in the above function will be the movieclip onto wich you have loaded your SVG.
I am not sure of this but I think that by using this function you will loose the ability to scale as much as you like without loosing quality.
I hope my input was of some help!
Good luck
PS: don't forget to add the SWC from the link to your project and to check out the provided examples. Please note as well the excellent comment of shaunhusain on your original question. You might not have to use 3D Library.
Salam,
It is very easy:
Open the "name.svg" file in illustartror.
Save it as "name.ai"
Import it into the stage in flash, that is all.

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

How to set Video Frame Capture Using Bitmap Data

I'm implementing an Augmented Reality application for android using Flash. In order to get the application working on my Android Phone (nexus One) the Phone Camera must be activated as well. So I need 2 layers one for the background which is the feed of my phone camera and an other one on top of it which is the view from away3d in this case.
So setting up a BitmapData object to hold the information of the most recent webcam still-frame I can make this work.
If I use papervision3D library and FLARToolkit we setting up the BitmapData using the following part of the code found from this video tutorial:
//import libraries
import org.libspark.flartoolkit.core.raster.rgb.FLARRgbRaster_BitmapData;
import org.libspark.flartoolkit.detector.FLARSingleMarkerDetector;
private function setupCamera():void
{
vid = new Video(640, 480);
cam = Camera.getCamera();
cam.setMode(320, 240, 10);
vid.attachCamera(cam);
addChild(vid);
}
private function setupBitmap():void
{
bmd = new BitmapData(640, 480);
bmd.draw(vid);
raster = new FLARRgbRaster_BitmapData(bmd);
detector = new FLARSingleMarkerDetector(fparams, mpattern, 80);
}
private function loop(e:Event):void
{
if(detector.detectMarkerLite(raster, 80) && detector.getConfidence() > 0.5)
{
vp.visible = true;
detector.getTransformMatrix(trans);
container.setTransformMatrix(trans);
bre.renderScene(scene, camera, vp);
}
else{
vp.visible = false}
}
catch(e:Error){}}}}
However, to implement my application Im using Away3D engine and FLARManager and the way of doing that is very different as I can understand. I have implement the following code but the only think it does is just show the Flash Camera in the front of the 3D view and I can't check if my application is work or not since it doesn't show me any 3D Object when I place the marker in front of the screen.
My code is:
//Setting Up Away3DLite Camera3D
import com.transmote.flar.camera.FLARCamera_Away3DLite;
private var camera3D:FLARCamera_Away3DLite;
this.camera3D = new FLARCamera_Away3DLite(this.flarManager, new Rectangle(0, 0, this.stage.stageWidth, this.stage.stageHeight));
//Setting Up the bitmapData
private function bitmap():void
{
c = Camera.getCamera();
c.setMode(320,240,10)
this.v.attachCamera(c);
addChild(this.v);
bmd = new BitmapData(640,480);
bmd.draw(this.v);
}
Can you please help me to find out how can I combine those two?
I will really appreciate any advice i can get from you.
Thank you
To isolate your problem, I'd try to break these two things up and make sure each part works first. It's sounds like you've got the camera part working, try doing just some 3D (no AR) draw a cube or something. Then try implementing the AR but have it do something simple like trace something out or making an object visible or invisible. Then start combining them.