/**
* Copyright crunchy ( http://wonderfl.net/user/crunchy )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/nWOt
*/
// Gouraud shading using GradientFill
package {
import __AS3__.vec.Vector;
import flash.display.BitmapData;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.GraphicsEndFill;
import flash.display.GraphicsGradientFill;
import flash.display.GraphicsPath;
import flash.display.GraphicsPathCommand;
import flash.display.GraphicsSolidFill;
import flash.display.GraphicsTrianglePath;
import flash.display.IGraphicsData;
import flash.display.Shape;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Point;
import flash.geom.Utils3D;
import flash.geom.Vector3D;
import flash.utils.getTimer;
[SWF(width="800", height="800", frameRate="60", backgroundColor="#0000FF")]
public class GradientTesting extends Sprite {
static private const MAX_X:int = 20;
static private const MAX_Y:int = 20;
static private const MULT:Number = 50;
static private const MOVE_SIN:int = 0;
static private const MOVE_PERLIN:int = 1;
static private const NUM_MOVE:int = 2;
public var shape:Shape = new Shape;
public var movementType_:int = MOVE_SIN;
public var lNW_:Vector3D;
public var vsW_:Vector.<Number> = new Vector.<Number>;
public var vNW_:Vector.<Vector3D> = new Vector.<Vector3D>;
public var light_:Vector.<Number> = new Vector.<Number>;
public var vsS_:Vector.<Number> = new Vector.<Number>;
public var uvt_:Vector.<Number> = new Vector.<Number>;
public var index_:Vector.<int> = new Vector.<int>;
public function GradientTesting() {
addChild(shape);
lNW_ = new Vector3D(1, 1, 1);
lNW_.normalize();
var faces:Vector.<Face> = new Vector.<Face>;
for (var y:Number = 0; y <= MAX_Y; y++) {
for (var x:Number = 0; x <= MAX_X; x++) {
vsW_.push((x - MAX_X / 2) * MULT, (y - MAX_Y / 2) * MULT,
-1000);
uvt_.push(x / MAX_X, y / MAX_Y, 0);
if (x != MAX_X && y != MAX_Y) {
faces.push(new Face(y * (MAX_Y + 1) + x,
y * (MAX_Y + 1) + (x + 1),
(y + 1) * (MAX_Y + 1) + x));
faces.push(new Face(y * (MAX_Y + 1) + (x + 1),
(y + 1) * (MAX_Y + 1) + (x + 1),
(y + 1) * (MAX_Y + 1) + x));
}
}
}
faces.sort(faceCompFunc);
for each (var f:Face in faces) {
index_.push(f.index_[0], f.index_[1], f.index_[2]);
}
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
}
private function onAddedToStage(event:Event):void {
shape.x = stage.stageWidth / 2;
shape.y = stage.stageHeight / 2;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(Event.MOUSE_LEAVE, onMouseLeave);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
private function onRemovedFromStage(event:Event):void {
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.removeEventListener(Event.MOUSE_LEAVE, onMouseLeave);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
private function onMouseDown(event:Event):void {
movementType_ = (movementType_ + 1) % NUM_MOVE;
}
private function onMouseLeave(event:Event):void {
lNW_ = new Vector3D(1, 1, 1);
lNW_.normalize();
}
private function onMouseMove(event:MouseEvent):void {
lNW_ = new Vector3D(-event.stageX / stage.stageWidth * 6 + 3,
-event.stageY / stage.stageHeight * 6 + 3, 1);
lNW_.normalize();
}
private function faceCompFunc(f0:Face, f1:Face):Number {
return minDistSq(f0) - minDistSq(f1);
}
private function minDistSq(f:Face):Number {
var minDist:Number = Number.MAX_VALUE;
for each (var i:int in f.index_) {
var dist:Number = vsW_[i * 3] * vsW_[i * 3] +
vsW_[i * 3 + 1] * vsW_[i * 3 + 1];
if (dist < minDist) {
minDist = dist;
}
}
return minDist;
}
private function onEnterFrame(event:Event):void {
switch(movementType_) {
case MOVE_SIN:
moveSin();
break;
case MOVE_PERLIN:
movePerlin();
break;
}
update();
draw();
}
public function moveSin():void {
var xdiv:Number = 4 + Math.sin(getTimer() / 3000) * 2;
var ydiv:Number = 4 + Math.cos(getTimer() / 3000) * 2;
var h:Number;
for (var y:Number = 0; y <= MAX_Y; y++) {
for (var x:Number = 0; x <= MAX_X; x++) {
h = 1000 +
Math.sin(x/xdiv - getTimer() / 500) * 100 +
Math.sin(y/ydiv - getTimer() / 500) * 100;
vsW_[(y * (MAX_X + 1) + x) * 3 + 2] = h;
}
}
}
private var perlinBitmapData:BitmapData =
new BitmapData(MAX_X + 1, MAX_Y + 1, false);
public function movePerlin():void {
var offsets:Array = [
new Point(-getTimer() / 100, -getTimer() / 100),
new Point(getTimer() / 100, getTimer() / 100),
new Point(-getTimer() / 200, -getTimer() / 200)];
perlinBitmapData.perlinNoise(MAX_X, MAX_Y, 3, 1, false, true, 7,
true, offsets);
for (var y:Number = 0; y <= MAX_Y; y++) {
for (var x:Number = 0; x <= MAX_X; x++) {
var h:Number = perlinBitmapData.getPixel(x, y) & 0xFF;
h = 800 + h * 2;
vsW_[(y * (MAX_X + 1) + x) * 3 + 2] = h;
}
}
}
public function update():void {
vNW_.length = 0;
var n:int;
for (n = 0; n < vsW_.length / 3; n++) {
vNW_.push(new Vector3D(0, 0, 0, 0));
}
var faceNW:Vector3D = new Vector3D;
for (var i:int = 0; i < index_.length; i += 3) {
computeNormal(
vsW_[index_[i] * 3], vsW_[index_[i] * 3 + 1],
vsW_[index_[i] * 3 + 2],
vsW_[index_[i + 1] * 3], vsW_[index_[i + 1] * 3 + 1],
vsW_[index_[i + 1] * 3 + 2],
vsW_[index_[i + 2] * 3], vsW_[index_[i + 2] * 3 + 1],
vsW_[index_[i + 2] * 3 + 2],
faceNW);
vNW_[index_[i]] = vNW_[index_[i]].add(faceNW);
vNW_[index_[i + 1]] = vNW_[index_[i + 1]].add(faceNW);
vNW_[index_[i + 2]] = vNW_[index_[i + 2]].add(faceNW);
}
light_.length = 0;
for (n = 0; n < vNW_.length; n++) {
vNW_[n].normalize();
light_.push(Math.max(0, Math.min(1,
lNW_.dotProduct(vNW_[n]))));
}
}
public function draw():void {
// create matrix
var m:Matrix3D = new Matrix3D();
var pp:PerspectiveProjection = new PerspectiveProjection();
pp.focalLength = 3;
pp.fieldOfView = 48;
m = pp.toMatrix3D();
// compute screen coords
vsS_.length = 0;
Utils3D.projectVectors(m, vsW_, vsS_, uvt_);
// draw triangles
var graphicsData:Vector.<IGraphicsData> =
new Vector.<IGraphicsData>;
//graphicsData.push(new GraphicsTrianglePath(vsS_, index_, uvt_));
for (var i:int = 0; i < index_.length; i += 3) {
drawShadedTriangle(graphicsData,
new Vector3D(vsS_[index_[i] * 2],
vsS_[index_[i] * 2 + 1], 0),
new Vector3D(vsS_[index_[i + 1] * 2],
vsS_[index_[i + 1] * 2 + 1], 0),
new Vector3D(vsS_[index_[i + 2] * 2],
vsS_[index_[i + 2] * 2 + 1], 0),
light_[index_[i]], light_[index_[i + 1]],
light_[index_[i + 2]]);
}
var g:Graphics = shape.graphics;
g.clear();
//g.lineStyle(1, 0x00FF00);
g.drawGraphicsData(graphicsData);
}
static public function computeNormal(
p0x:Number, p0y:Number, p0z:Number,
p1x:Number, p1y:Number, p1z:Number,
p2x:Number, p2y:Number, p2z:Number,
result:Vector3D):void {
result.x = (p1y - p0y) * (p2z - p0z) - (p1z - p0z) * (p2y - p0y);
result.y = (p1z - p0z) * (p2x - p0x) - (p1x - p0x) * (p2z - p0z);
result.z = (p1x - p0x) * (p2y - p0y) - (p1y - p0y) * (p2x - p0x);
}
static private const SHADE_SIZE:Number = 819.2; // 2^13 / 10 = 819.2
static private const fillType:String = GradientType.LINEAR;
static private const colors:Array = [0x000000, 0x000000];
static private const alphas:Array = [1, 0];
static private const ratios:Array = [0x00, 0xFF];
static private const spreadMethod:String = SpreadMethod.PAD;
static private const commands:Vector.<int> = Vector.<int>(
[GraphicsPathCommand.MOVE_TO, GraphicsPathCommand.LINE_TO,
GraphicsPathCommand.LINE_TO, GraphicsPathCommand.LINE_TO]);
private function drawShadedTriangle(
graphicsData:Vector.<IGraphicsData>,
p0S:Vector3D, p1S:Vector3D, p2S:Vector3D,
s0:Number, s1:Number, s2:Number):void {
var s0s1:Boolean = s0 - s1 < .001 && s0 - s1 > -.001;
var s1s2:Boolean = s1 - s2 < .001 && s1 - s2 > -.001;
if (s0s1 && s1s2) {
graphicsData.push(new GraphicsSolidFill(0x000000, 1 - s0));
} else {
if (s0s1) {
var pTempS:Vector3D = p0S;
var sTemp:Number = s0;
p0S = p1S;
s0 = s1;
p1S = p2S;
s1 = s2;
p2S = pTempS;
s2 = sTemp;
}
var tempM:Matrix = new Matrix(
p1S.x - p0S.x, p1S.y - p0S.y,
p2S.x - p0S.x, p2S.y - p0S.y,
p0S.x, p0S.y);
var a11:Number = SHADE_SIZE * 2 * (s1 - s0);
var a21:Number = SHADE_SIZE * 2 * (s2 - s0);
var a31:Number = -SHADE_SIZE + SHADE_SIZE * 2 * s0;
var m:Matrix =
new Matrix(1 / a11, 0, -a21 / a11, 1, -a31 / a11, 0);
m.concat(tempM);
graphicsData.push(new GraphicsGradientFill(fillType, colors,
alphas, ratios, m, spreadMethod));
}
graphicsData.push(new GraphicsPath(commands,
Vector.<Number>([p0S.x, p0S.y, p1S.x, p1S.y,
p2S.x, p2S.y, p0S.x, p0S.y])));
graphicsData.push(new GraphicsEndFill);
}
}
}
import __AS3__.vec.Vector;
class Face {
public var index_:Vector.<int>;
public function Face(i0:int, i1:int, i2:int):void {
index_ = Vector.<int>([i0, i1, i2]);
}
}