Created
February 5, 2013 11:51
-
-
Save altunsercan/4713987 to your computer and use it in GitHub Desktop.
A simple qubicle constructor parser for as3 - Away3d
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package | |
{ | |
import away3d.cameras.Camera3D; | |
import away3d.containers.Scene3D; | |
import away3d.containers.View3D; | |
import away3d.controllers.HoverController; | |
import away3d.controllers.LookAtController; | |
import away3d.core.base.Geometry; | |
import away3d.debug.AwayStats; | |
import away3d.entities.Mesh; | |
import away3d.lights.DirectionalLight; | |
import away3d.materials.ColorMaterial; | |
import away3d.materials.MaterialBase; | |
import away3d.primitives.CubeGeometry; | |
import away3d.tools.commands.Merge; | |
import flash.display.Sprite; | |
import flash.display.StageAlign; | |
import flash.display.StageScaleMode; | |
import flash.events.Event; | |
import flash.events.KeyboardEvent; | |
import flash.events.MouseEvent; | |
import flash.geom.Vector3D; | |
import flash.ui.Keyboard; | |
import flash.utils.ByteArray; | |
import flash.utils.Dictionary; | |
import flash.utils.Endian; | |
[SWF(frameRate="60")] | |
public class QBAwayTest extends Sprite | |
{ | |
[Embed(source="./resources/guy.qb", mimeType="application/octet-stream")] | |
private var QB_GUY:Class; | |
//engine variables | |
private var scene:Scene3D; | |
private var camera:Camera3D; | |
private var view:View3D; | |
private var awayStats:AwayStats; | |
private var cameraController:HoverController; | |
//QB variables | |
private var qbMatrices:Array; | |
private const CODEFLAG:uint = 2; | |
private const NEXTSLICEFLAG:uint = 6; | |
//navigation variables | |
private var move:Boolean = false; | |
private var lastPanAngle:Number; | |
private var lastTiltAngle:Number; | |
private var lastMouseX:Number; | |
private var lastMouseY:Number; | |
private var tiltSpeed:Number = 2; | |
private var panSpeed:Number = 2; | |
private var distanceSpeed:Number = 2; | |
private var tiltIncrement:Number = 0; | |
private var panIncrement:Number = 0; | |
private var distanceIncrement:Number = 0; | |
public function QBAwayTest() | |
{ | |
initEngine(); | |
parseQB(); | |
createSceneObjects(); | |
changeCameraPosition(); | |
initListeners(); | |
} | |
/** | |
* Initialise the engine | |
*/ | |
private function initEngine() : void | |
{ | |
stage.scaleMode = StageScaleMode.NO_SCALE; | |
stage.align = StageAlign.TOP_LEFT; | |
scene = new Scene3D(); | |
camera = new Camera3D(); | |
camera.lens.far = 2000; | |
camera.lens.near = 20; | |
view = new View3D(); | |
view.antiAlias = 16; | |
view.scene = scene; | |
view.camera = camera; | |
//setup controller to be used on the camera | |
cameraController = new HoverController(camera); | |
cameraController.distance = 100; | |
cameraController.minTiltAngle = 0; | |
cameraController.maxTiltAngle = 90; | |
cameraController.panAngle = 45; | |
cameraController.tiltAngle = 20; | |
//view.addSourceURL("srcview/index.html"); | |
addChild(view); | |
awayStats = new AwayStats(view); | |
addChild(awayStats); | |
} | |
/** | |
* | |
* Parse QB data | |
* | |
*/ | |
private function parseQB():void | |
{ | |
var qbBytes:ByteArray = new QB_GUY(); | |
qbBytes.endian = Endian.LITTLE_ENDIAN; | |
qbBytes.position = 0; | |
var version:uint = qbBytes.readUnsignedInt(); | |
var colorFormat:uint = qbBytes.readUnsignedInt(); | |
var zAxisOrientation:uint = qbBytes.readUnsignedInt(); | |
var compressed:uint = qbBytes.readUnsignedInt(); | |
var visibilityMaskEncoded:uint = qbBytes.readUnsignedInt(); | |
var numMatrices:uint = qbBytes.readUnsignedInt(); | |
qbMatrices = new Array(); | |
for( var i:uint; i < numMatrices; i++ ) | |
{ | |
var qbmatrix:QBMatrix = new QBMatrix(); | |
qbMatrices.push( qbmatrix ); | |
var sizeX:uint = qbmatrix.sizeX = qbBytes.readUnsignedInt() ; | |
var sizeY:uint = qbmatrix.sizeY = qbBytes.readUnsignedInt() ; | |
var sizeZ:uint = qbmatrix.sizeZ = qbBytes.readUnsignedInt() ; | |
var posX:int = qbmatrix.posX = qbBytes.readInt(); | |
var posY:int = qbmatrix.posY = qbBytes.readInt(); | |
var posZ:int = qbmatrix.posZ = qbBytes.readInt(); | |
var matrix:Array = qbmatrix.data; | |
var z:uint; | |
var y:uint; | |
var x:uint; | |
if( compressed == 0 ) | |
{ | |
for(z = 0; z < sizeZ; z++) | |
for(y = 0; y < sizeY; y++) | |
for(x = 0; x < sizeX; x++) | |
matrix[x + y*sizeX + z*sizeX*sizeY] = qbBytes.readUnsignedInt(); | |
}else // if compressed | |
{ | |
/*while (z < sizeZ) | |
{ | |
z++; | |
var index:uint = 0; | |
while (true) | |
{ | |
var data:uint = qbBytes.readUnsignedInt(); | |
if (data == NEXTSLICEFLAG) | |
break; | |
else if (data == CODEFLAG) | |
{ | |
var count:uint = qbBytes.readUnsignedInt(); | |
data = qbBytes.readUnsignedInt(); | |
for(var j:uint = 0; j < count; j++) | |
{ | |
x = index % sizeX + 1; // mod = modulo e.g. 12 mod 8 = 4 | |
y = int(index / sizeX + 1); // div = integer division e.g. 12 div 8 = 1 | |
index++; | |
matrix[x + y*sizeX + z*sizeX*sizeY] = data; | |
} | |
} | |
else | |
{ | |
x = index % sizeX + 1; | |
y = int(index / sizeX + 1); | |
index++; | |
matrix[x + y*sizeX + z*sizeX*sizeY] = data; | |
} | |
} | |
}*/ | |
var index:uint = 0; | |
//var zcounter:uint = 0; | |
//var zskip:uint = qbmatrix.sizeX* qbmatrix.sizeY;*/ | |
while ( qbBytes.bytesAvailable != 0 ) | |
{ | |
var data:uint = qbBytes.readUnsignedInt(); | |
/*if( zcounter == zskip ) | |
{ | |
zcounter = 0; | |
trace(data); | |
continue; | |
}*/ | |
if (data == NEXTSLICEFLAG) | |
continue; // ignore flag | |
else if (data == CODEFLAG) | |
{ | |
var count:uint = qbBytes.readUnsignedInt(); | |
data = qbBytes.readUnsignedInt(); | |
for(var j:uint = 0; j < count; j++) | |
{ | |
matrix[index] = data; | |
index++; | |
//zcounter++; | |
} | |
} | |
else | |
{ | |
matrix[index] = data; | |
index++; | |
//zcounter++; | |
} | |
} | |
} | |
} | |
} | |
private var colorMaterials:Dictionary; | |
private var sameMaterialMeshes:Dictionary; | |
private function createSceneObjects():void | |
{ | |
/// ligths | |
var dirLight:DirectionalLight = new DirectionalLight( ); | |
dirLight.ambient = 0.1; | |
dirLight.diffuse = 0.7; | |
scene.addChild( dirLight ); | |
colorMaterials = new Dictionary(); | |
sameMaterialMeshes = new Dictionary(); | |
var sceneObject:Mesh; | |
var cubeGeometry:CubeGeometry = new CubeGeometry(1, 1, 1); | |
for each( var matrix:QBMatrix in qbMatrices) | |
{ | |
var len:uint = matrix.data.length; | |
var index:uint = 0; | |
while( index< len) | |
{ | |
var voxeldata:uint = matrix.data[ index ]; | |
var mask:uint = (voxeldata & 0x000000FF); | |
var color:uint = (voxeldata & 0xFFFFFF00) >> 8; | |
if (mask == 0) // voxel invisble | |
{ | |
}else{ | |
var material:ColorMaterial = colorMaterials[ ""+color ]; | |
if( material == null ) | |
{ | |
colorMaterials[ ""+color ] = material = new ColorMaterial( color ); | |
} | |
sceneObject = new Mesh( cubeGeometry, material); | |
var x:uint = index % matrix.sizeX ; | |
var y:uint = uint( (index / matrix.sizeX) % matrix.sizeY ); | |
var z:uint = uint( index / ( matrix.sizeX * matrix.sizeY ) ); | |
sceneObject.x = x; | |
sceneObject.y = y; | |
sceneObject.z = z; | |
//scene.addChild( sceneObject); | |
var sameMats:Vector.<Mesh> = sameMaterialMeshes[ ""+color ]; | |
if( sameMats == null ) | |
{ | |
sameMaterialMeshes[ ""+color ] = sameMats = new Vector.<Mesh>(); | |
} | |
sameMats.push( sceneObject ); | |
} | |
index ++; | |
} | |
} | |
/// Merge sameMaterial Objects | |
var merger:Merge = new Merge( ); | |
for ( var key:String in sameMaterialMeshes ) | |
{ | |
var arr:Vector.<Mesh> = sameMaterialMeshes[key]; | |
var mat:MaterialBase = colorMaterials[ key ]; | |
var mesh:Mesh = new Mesh( new Geometry(), mat ); | |
merger.applyToMeshes( mesh, arr ); | |
scene.addChild( mesh ); | |
} | |
} | |
private function changeCameraPosition():void | |
{ | |
/*var cameraX:int = 0; | |
var cameraY:int = 0; | |
var cameraZ:int = 0; | |
for each( var matrix:QBMatrix in qbMatrices) | |
{ | |
cameraX = Math.max( cameraX, matrix.posX + matrix.sizeX ); | |
cameraY = Math.max( cameraY, matrix.posY + matrix.sizeY ); | |
cameraZ = Math.max( cameraZ, matrix.posZ + matrix.sizeZ ); | |
} | |
camera.x = cameraX; | |
camera.y = cameraY; | |
camera.z = cameraZ; | |
*/ | |
} | |
/** | |
* Initialise the listeners | |
*/ | |
private function initListeners():void | |
{ | |
addEventListener(Event.ENTER_FRAME, onEnterFrame); | |
view.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); | |
view.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); | |
stage.addEventListener(Event.RESIZE, onResize); | |
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); | |
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp); | |
onResize(); | |
} | |
/** | |
* Navigation and render loop | |
*/ | |
private function onEnterFrame(event:Event):void | |
{ | |
cameraController.panAngle += panIncrement; | |
cameraController.tiltAngle += tiltIncrement; | |
cameraController.distance += distanceIncrement; | |
view.render(); | |
} | |
/** | |
* Key down listener for camera control | |
*/ | |
private function onKeyDown(event:KeyboardEvent):void | |
{ | |
switch (event.keyCode) { | |
case Keyboard.UP: | |
case Keyboard.W: | |
tiltIncrement = tiltSpeed; | |
break; | |
case Keyboard.DOWN: | |
case Keyboard.S: | |
tiltIncrement = -tiltSpeed; | |
break; | |
case Keyboard.LEFT: | |
case Keyboard.A: | |
panIncrement = panSpeed; | |
break; | |
case Keyboard.RIGHT: | |
case Keyboard.D: | |
panIncrement = -panSpeed; | |
break; | |
case Keyboard.Z: | |
distanceIncrement = distanceSpeed; | |
break; | |
case Keyboard.X: | |
distanceIncrement = -distanceSpeed; | |
break; | |
} | |
} | |
/** | |
* Key up listener for camera control | |
*/ | |
private function onKeyUp(event:KeyboardEvent):void | |
{ | |
switch (event.keyCode) { | |
case Keyboard.UP: | |
case Keyboard.W: | |
case Keyboard.DOWN: | |
case Keyboard.S: | |
tiltIncrement = 0; | |
break; | |
case Keyboard.LEFT: | |
case Keyboard.A: | |
case Keyboard.RIGHT: | |
case Keyboard.D: | |
panIncrement = 0; | |
break; | |
case Keyboard.Z: | |
case Keyboard.X: | |
distanceIncrement = 0; | |
break; | |
} | |
} | |
/** | |
* Mouse down listener for navigation | |
*/ | |
private function onMouseDown(event:MouseEvent):void | |
{ | |
move = true; | |
lastPanAngle = cameraController.panAngle; | |
lastTiltAngle = cameraController.tiltAngle; | |
lastMouseX = stage.mouseX; | |
lastMouseY = stage.mouseY; | |
stage.addEventListener(Event.MOUSE_LEAVE, onStageMouseLeave); | |
} | |
/** | |
* Mouse up listener for navigation | |
*/ | |
private function onMouseUp(event:MouseEvent):void | |
{ | |
move = false; | |
stage.removeEventListener(Event.MOUSE_LEAVE, onStageMouseLeave); | |
} | |
/** | |
* Mouse stage leave listener for navigation | |
*/ | |
private function onStageMouseLeave(event:Event):void | |
{ | |
move = false; | |
stage.removeEventListener(Event.MOUSE_LEAVE, onStageMouseLeave); | |
} | |
/** | |
* stage listener for resize events | |
*/ | |
private function onResize(event:Event = null):void | |
{ | |
view.width = stage.stageWidth; | |
view.height = stage.stageHeight; | |
awayStats.x = stage.stageWidth - awayStats.width; | |
} | |
} | |
} | |
internal class QBMatrix | |
{ | |
public var data:Array; | |
public var sizeX:uint; | |
public var sizeY:uint; | |
public var sizeZ:uint; | |
public var posX:int; | |
public var posY:int; | |
public var posZ:int; | |
public function QBMatrix() | |
{ | |
data = new Array(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment