Just tested a proof of concept implementation.
Here is the code in case someone wants to play with it or improve :
package away3d.textures
{
import flash.display.BitmapData;
import flash.display3D.Context3D;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.textures.RectangleTexture;
import flash.display3D.textures.Texture;
import flash.display3D.textures.TextureBase;
import away3d.tools.utils.TextureUtils;
/**
* NPOT : non power of two bitmap texture
* uses a RectangleTexture instance internally if supported
* Flash Player 11.8, AIR 3.8
*
* @see http://help.adobe.com/fr_FR/FlashPlatform/reference/actionscript/3/flash/display3D/textures/RectangleTexture.html
* @see http://away3d.com/forum/viewthread/3733/
* @see https://github.com/shin10/Starling-WebcamVideo
*/
public class NPOTBitmapTexture extends Texture2DBase
{
private var _bitmapData : BitmapData;
private var _bitmapDataPOT:Boolean = false;
private var _npotSupported:Boolean = false;
public function NPOTBitmapTexture(bitmapData:BitmapData)
{
super();
this.bitmapData = bitmapData;
}
public function get bitmapData() : BitmapData
{
return _bitmapData;
}
public function set bitmapData(value : BitmapData) : void
{
if (value == _bitmapData) return;
invalidateContent();
setSize(value.width, value.height);
_bitmapData = value;
_bitmapDataPOT = (TextureUtils.isPowerOfTwo (_width) && TextureUtils.isPowerOfTwo (_height));
}
override protected function createTexture(context:Context3D):TextureBase
{
// FIXME fallback to normal texture if POT ?
if (_bitmapDataPOT) return super.createTexture (context);
else {
_npotSupported = ("createRectangleTexture" in context);
if (!_npotSupported) throw new Error("Non power of two textures not supported : requires swfversion 21+");
return context["createRectangleTexture"] (_width, _height, Context3DTextureFormat.BGRA, false);
}
}
override protected function uploadContent(texture : TextureBase) : void
{
if (!_npotSupported) Texture(texture).uploadFromBitmapData (_bitmapData, 0);
else RectangleTexture(texture).uploadFromBitmapData (_bitmapData);
}
}
}
A simple class with camera streaming using NPOTBitmapTexture :
package
{
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.media.Camera;
import flash.media.Video;
import flash.text.TextField;
import flash.utils.getTimer;
import away3d.containers.View3D;
import away3d.textures.NPOTBitmapTexture;
import away3d.textures.Texture2DBase;
public class Away3DWebcamVideo extends Sprite
{
private var _view:View3D;
private var _backgroundTexture:Texture2DBase;
private var _camWidth:int;
private var _camHeight:int;
private var _camera:Camera;
private var _video:Video;
private var _backgroundFrame:BitmapData;
private var _stats:TextField;
public function Away3DWebcamVideo(camWidth:int, camHeight:int)
{
_camWidth = camWidth;
_camHeight = camHeight;
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage (evt:Event) : void
{
_view = addChild (new View3D ()) as View3D;
_view.width = stage.stageWidth;
_view.height = stage.stageHeight;
_camera = Camera.getCamera();
_camera.setLoopback(false);
_camera.setMode(_camWidth, _camHeight, 30);
_video = new Video ();
_video.attachCamera (_camera);
_backgroundFrame = new BitmapData (_camWidth, _camHeight, false, 0);
_backgroundTexture = new NPOTBitmapTexture (_backgroundFrame);
_view.background = _backgroundTexture;
_stats = addChild (new TextField()) as TextField;
_stats.width = 200;
_stats.height = 200;
_stats.multiline = _stats.wordWrap = true;
_stats.textColor = 0;
_camera.addEventListener (Event.VIDEO_FRAME, onCameraVideoFrame);
_view.addEventListener (Event.ENTER_FRAME, render);
}
private function onCameraVideoFrame (evt:Event) : void
{
drawFrame ();
}
private var _drawFrameCount:int = 0;
private var _drawFrameTotal:int = 0;
private function drawFrame () : void
{
var start:int = getTimer();
_camera.drawToBitmapData (_backgroundFrame);
_backgroundTexture.invalidateContent ();
_drawFrameTotal += (getTimer() - start);
_drawFrameCount++;
}
private var _renderCount:int = 0;
private var _renderTotal:int = 0;
private function render (evt:Event) : void
{
var start:int = getTimer();
_view.render();
_renderTotal += (getTimer() - start);
_renderCount++;
var output:String = "CAM : " + _camWidth + "x" + _camHeight + "\n";
output += "DRAW : " + (_drawFrameTotal/_drawFrameCount).toFixed(2) + " (" + _drawFrameCount + ")\n";
output += "RENDER : " + (_renderTotal/_renderCount).toFixed(2) + " (" + _renderCount + ")";
_stats.text = output;
}
}
}
And the main :
package
{
import flash.display.Sprite;
[SWF(width="800", height="600", frameRate="60", backgroundColor="#ffffff")]
public class Main extends Sprite
{
public function Main()
{
// away3d version : http://away3d.com/forum/viewthread/3733/
addChild (new Away3DWebcamVideo (640, 480));
}
}
}