Files
Alternativa3D/src/alternativa/engine3d/materials/FillMaterial.as
2012-05-16 13:23:07 +06:00

176 lines
6.3 KiB
ActionScript

/**
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
* If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.
* You may add additional accurate notices of copyright ownership.
*
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
* */
package alternativa.engine3d.materials {
import alternativa.engine3d.alternativa3d;
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.DrawUnit;
import alternativa.engine3d.core.Light3D;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Renderer;
import alternativa.engine3d.core.VertexAttributes;
import alternativa.engine3d.materials.compiler.Linker;
import alternativa.engine3d.materials.compiler.Procedure;
import alternativa.engine3d.materials.compiler.VariableType;
import alternativa.engine3d.objects.Surface;
import alternativa.engine3d.resources.Geometry;
import flash.display3D.Context3D;
import flash.display3D.Context3DBlendFactor;
import flash.display3D.Context3DProgramType;
import flash.display3D.VertexBuffer3D;
import flash.utils.Dictionary;
use namespace alternativa3d;
/**
* The materiall fills surface with solid color in light-independent manner. Can draw a Skin with no more than 41 Joints per surface. See Skin.divide() for more details.
*
* @see alternativa.engine3d.objects.Skin#divide()
*/
public class FillMaterial extends Material {
private static var caches:Dictionary = new Dictionary(true);
private var cachedContext3D:Context3D;
private var programsCache:Dictionary;
private static var outColorProcedure:Procedure = new Procedure(["#c0=cColor", "mov o0, c0"], "outColorProcedure");
/**
* Transparency
*/
public var alpha:Number = 1;
private var red:Number;
private var green:Number;
private var blue:Number;
/**
* Color.
*/
public function get color():uint {
return (red*0xFF << 16) + (green*0xFF << 8) + blue*0xFF;
}
/**
* @private
*/
public function set color(value:uint):void {
red = ((value >> 16) & 0xFF)/0xFF;
green = ((value >> 8) & 0xFF)/0xFF;
blue = (value & 0xff)/0xFF;
}
/**
* Creates a new FillMaterial instance.
* @param color Color .
* @param alpha Transparency.
*/
public function FillMaterial(color:uint = 0x7F7F7F, alpha:Number = 1) {
this.color = color;
this.alpha = alpha;
}
private function setupProgram(object:Object3D):FillMaterialProgram {
var vertexLinker:Linker = new Linker(Context3DProgramType.VERTEX);
var positionVar:String = "aPosition";
vertexLinker.declareVariable(positionVar, VariableType.ATTRIBUTE);
if (object.transformProcedure != null) {
positionVar = appendPositionTransformProcedure(object.transformProcedure, vertexLinker);
}
vertexLinker.addProcedure(_projectProcedure);
vertexLinker.setInputParams(_projectProcedure, positionVar);
var fragmentLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
fragmentLinker.addProcedure(outColorProcedure);
fragmentLinker.varyings = vertexLinker.varyings;
return new FillMaterialProgram(vertexLinker, fragmentLinker);
}
/**
* @private
*/
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
var object:Object3D = surface.object;
// Strams
var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
// Check validity
if (positionBuffer == null) return;
// Program
// Renew program cache for this context
if (camera.context3D != cachedContext3D) {
cachedContext3D = camera.context3D;
programsCache = caches[cachedContext3D];
if (programsCache == null) {
programsCache = new Dictionary();
caches[cachedContext3D] = programsCache;
}
}
var program:FillMaterialProgram = programsCache[object.transformProcedure];
if (program == null) {
program = setupProgram(object);
program.upload(camera.context3D);
programsCache[object.transformProcedure] = program;
}
// Drawcall
var drawUnit:DrawUnit = camera.renderer.createDrawUnit(object, program.program, geometry._indexBuffer, surface.indexBegin, surface.numTriangles, program);
// Streams
drawUnit.setVertexBufferAt(program.aPosition, positionBuffer, geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
// Constants
object.setTransformConstants(drawUnit, surface, program.vertexShader, camera);
drawUnit.setProjectionConstants(camera, program.cProjMatrix, object.localToCameraTransform);
drawUnit.setFragmentConstantsFromNumbers(program.cColor, red, green, blue, alpha);
// Send to render
if (alpha < 1) {
drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT);
} else {
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE);
}
}
/**
* @inheritDoc
*/
override public function clone():Material {
var res:FillMaterial = new FillMaterial(color, alpha);
res.clonePropertiesFrom(this);
return res;
}
}
}
import alternativa.engine3d.materials.ShaderProgram;
import alternativa.engine3d.materials.compiler.Linker;
import flash.display3D.Context3D;
class FillMaterialProgram extends ShaderProgram {
public var aPosition:int = -1;
public var cProjMatrix:int = -1;
public var cColor:int = -1;
public function FillMaterialProgram(vertex:Linker, fragment:Linker) {
super(vertex, fragment);
}
override public function upload(context3D:Context3D):void {
super.upload(context3D);
aPosition = vertexShader.findVariable("aPosition");
cProjMatrix = vertexShader.findVariable("cProjMatrix");
cColor = fragmentShader.findVariable("cColor");
}
}