// =================================================================================================
//
// Starling Framework
// Copyright Gamua GmbH. All Rights Reserved.
//
// This program is free software. You can redistribute and/or modify it
// in accordance with the terms of the accompanying license agreement.
//
// =================================================================================================
package starling.utils
{
import flash.display.Stage3D;
import flash.display3D.Context3D;
import flash.display3D.Context3DMipFilter;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DTextureFilter;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DWrapMode;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.utils.setTimeout;
import starling.core.Starling;
import starling.errors.AbstractClassError;
import starling.textures.Texture;
import starling.textures.TextureSmoothing;
/** A utility class containing methods related to Stage3D and rendering in general. */
public class RenderUtil
{
/** @private */
public function RenderUtil()
{
throw new AbstractClassError();
}
/** Clears the render context with a certain color and alpha value. */
public static function clear(rgb:uint=0, alpha:Number=0.0):void
{
Starling.context.clear(
Color.getRed(rgb) / 255.0,
Color.getGreen(rgb) / 255.0,
Color.getBlue(rgb) / 255.0,
alpha);
}
/** Returns the flags that are required for AGAL texture lookup,
* including the '<' and '>' delimiters. */
public static function getTextureLookupFlags(format:String, mipMapping:Boolean,
repeat:Boolean=false,
smoothing:String="bilinear"):String
{
// TODO this method can probably be removed
var options:Array = ["2d", repeat ? "repeat" : "clamp"];
if (format == Context3DTextureFormat.COMPRESSED)
options.push("dxt1");
else if (format == "compressedAlpha")
options.push("dxt5");
if (smoothing == TextureSmoothing.NONE)
options.push("nearest", mipMapping ? "mipnearest" : "mipnone");
else if (smoothing == TextureSmoothing.BILINEAR)
options.push("linear", mipMapping ? "mipnearest" : "mipnone");
else
options.push("linear", mipMapping ? "miplinear" : "mipnone");
return "<" + options.join() + ">";
}
/** Returns a bit field uniquely describing texture format and premultiplied alpha,
* so that each required AGAL variant will get its unique ID. This method is most
* useful when overriding the programVariantName
method of custom
* effects.
*
* @return a bit field using the 3 least significant bits.
*/
public static function getTextureVariantBits(texture:Texture):uint
{
if (texture == null) return 0;
var bitField:uint = 0;
var formatBits:uint = 0;
switch (texture.format)
{
case Context3DTextureFormat.COMPRESSED_ALPHA:
formatBits = 3; break;
case Context3DTextureFormat.COMPRESSED:
formatBits = 2; break;
default:
formatBits = 1;
}
bitField |= formatBits;
if (!texture.premultipliedAlpha)
bitField |= 1 << 2;
return bitField;
}
/** Calls setSamplerStateAt
at the current context,
* converting the given parameters to their low level counterparts. */
public static function setSamplerStateAt(sampler:int, mipMapping:Boolean,
smoothing:String="bilinear",
repeat:Boolean=false):void
{
var wrap:String = repeat ? Context3DWrapMode.REPEAT : Context3DWrapMode.CLAMP;
var filter:String;
var mipFilter:String;
if (smoothing == TextureSmoothing.NONE)
{
filter = Context3DTextureFilter.NEAREST;
mipFilter = mipMapping ? Context3DMipFilter.MIPNEAREST : Context3DMipFilter.MIPNONE;
}
else if (smoothing == TextureSmoothing.BILINEAR)
{
filter = Context3DTextureFilter.LINEAR;
mipFilter = mipMapping ? Context3DMipFilter.MIPNEAREST : Context3DMipFilter.MIPNONE;
}
else
{
filter = Context3DTextureFilter.LINEAR;
mipFilter = mipMapping ? Context3DMipFilter.MIPLINEAR : Context3DMipFilter.MIPNONE;
}
Starling.context.setSamplerStateAt(sampler, wrap, filter, mipFilter);
}
/** Creates an AGAL source string with a tex
operation, including an options
* list with the appropriate format flag.
*
*
Note that values for repeat/clamp
, filter
and
* mip-filter
are not included in the options list, since it's preferred
* to set those values at runtime via setSamplerStateAt
.
Starling expects every color to have its alpha value premultiplied into
* the RGB channels. Thus, if this method encounters a non-PMA texture, it will
* (per default) convert the color in the result register to PMA mode, resulting
* in an additional mul
-operation.
If you are unsure which profiles are supported on the current * device, you can also pass an Array of profiles; they will be * tried one after the other (starting at index 0), until a working * profile is found. If none of the given profiles is supported, * the Stage3D object will dispatch an ERROR event.
* *You can also pass the String 'auto' to use the best available * profile automatically. This will try all known Stage3D profiles, * beginning with the most powerful.
*/ public static function requestContext3D(stage3D:Stage3D, renderMode:String, profile:*):void { var profiles:Array; var currentProfile:String; if (profile == "auto") profiles = ["standardExtended", "standard", "standardConstrained", "baselineExtended", "baseline", "baselineConstrained"]; else if (profile is String) profiles = [profile as String]; else if (profile is Array) profiles = profile as Array; else throw new ArgumentError("Profile must be of type 'String' or 'Array'"); stage3D.addEventListener(Event.CONTEXT3D_CREATE, onCreated, false, 100); stage3D.addEventListener(ErrorEvent.ERROR, onError, false, 100); requestNextProfile(); function requestNextProfile():void { currentProfile = profiles.shift(); try { execute(stage3D.requestContext3D, renderMode, currentProfile); } catch (error:Error) { if (profiles.length != 0) setTimeout(requestNextProfile, 1); else throw error; } } function onCreated(event:Event):void { var context:Context3D = stage3D.context3D; if (renderMode == Context3DRenderMode.AUTO && profiles.length != 0 && context.driverInfo.indexOf("Software") != -1) { onError(event); } else { onFinished(); } } function onError(event:Event):void { if (profiles.length != 0) { event.stopImmediatePropagation(); setTimeout(requestNextProfile, 1); } else onFinished(); } function onFinished():void { stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onCreated); stage3D.removeEventListener(ErrorEvent.ERROR, onError); } } } }