Skip to content

Instantly share code, notes, and snippets.

@altunsercan
Created February 5, 2013 11:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save altunsercan/4713987 to your computer and use it in GitHub Desktop.
Save altunsercan/4713987 to your computer and use it in GitHub Desktop.
A simple qubicle constructor parser for as3 - Away3d
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