PolyViewer α1
カメラとか全然判らないので作ってないです。
スケールのアジャストもよく判らないので適当に。
誰か教えて下さい…
注意:
zipはファイル名がutf-8になるようにしてください。
/**
* Copyright zahir ( http://wonderfl.net/user/zahir )
* GNU General Public License, v3 ( http://www.gnu.org/licenses/quick-guide-gplv3.html )
* Downloaded from: http://wonderfl.net/c/q3eY
*/
package{
import com.bit101.components.PushButton;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.*;
import flash.utils.*;
import net.hires.debug.Stats;
[SWF(width="465", height="465",frameRate="30", backgroundColor="0x666666")]
public class PolyViewer_alpha extends Sprite{
private var zip:Zip;
private var imgs:ZIPImages;
private var l:MQOLoader;
private var model:MQO;
private var proj:PerspectiveProjection;
private var m:Matrix3D;
private var g:Graphics;
private var rot:int = 0;
private var fov:int = 45;
private var _path:String = "asset/";
private var s:Shape;
private var btn:PushButton;
private var fr:FileReference;
public function PolyViewer_alpha(){
btn = new PushButton(this, 0,0, "load Zip File");
btn.x = (stage.stageWidth - btn.width) >> 1;
btn.y = (stage.stageHeight - btn.height) >>1;
btn.addEventListener( MouseEvent.MOUSE_DOWN, selectZip);
}
private function selectZip(e:MouseEvent):void{
fr = new FileReference();
fr.addEventListener(Event.SELECT, selectedZip);
fr.browse([new FileFilter("load zip","*.zip")]);
}
private function selectedZip(e:Event):void{
fr.removeEventListener(Event.SELECT, selectedZip);
fr.addEventListener(Event.COMPLETE, loadZip);
fr.load();
}
private function loadZip(e:Event):void{
btn.removeEventListener( MouseEvent.MOUSE_DOWN, selectZip);
fr.removeEventListener(Event.COMPLETE, loadZip);
(zip = new Zip()).setZipData( fr.data );
zip.addEvent( ProgressEvent.PROGRESS, zipProg);
zip.addEvent( Zip.READ_COMP, zipComp );
zip.startReading();
}
private function zipProg( e:ProgressEvent ):void{}
private function zipComp( e:Event ):void{
imgs = zip.images;
imgs.addEvent( ZIPImages.COMP, imgInit);
imgs.startDecode();
}
private function imgInit(e:Event):void{
imgs.removeEvent( ZIPImages.COMP, imgInit);
btn.addEventListener(MouseEvent.MOUSE_DOWN, selectMQO);
btn.label = "load mqo file";
}
private function selectMQO(e:MouseEvent):void{
fr = new FileReference();
fr.addEventListener(Event.SELECT, selectedMQO);
fr.browse([new FileFilter("load mqo","*.mqo")]);
}
private function selectedMQO(e:Event):void{
fr.removeEventListener(Event.SELECT, selectedMQO);
fr.addEventListener(Event.COMPLETE, loadMQO);
fr.load();
}
private function loadMQO(e:Event):void{
btn.removeEventListener( MouseEvent.MOUSE_DOWN, selectMQO);
fr.removeEventListener(Event.COMPLETE, loadMQO);
removeChild(btn);
l = new MQOLoader();
l.addEvent( MQOLoader.PARSE_COMP, modelComp);
l.setData( fr.data, imgs );
}
private function modelComp(e:Event):void{
l.removeEvent( MQOLoader.PARSE_COMP, modelComp);
model = l.modelData;
var pp:PerspectiveProjection = new PerspectiveProjection();
pp.fieldOfView = 60;
proj = transform.perspectiveProjection;
proj.fieldOfView = fov;
m = new Matrix3D();
var bmp:Bitmap = addChild(new Bitmap(model.texture) ) as Bitmap;
bmp.width = bmp.height = 465;
g = (addChild( ( s = new Shape() ) ) as Shape).graphics;
s.x = stage.stageWidth >> 1;
s.y = stage.stageHeight >> 1;
addChild( new Stats() ).alpha = 0.4;
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove );
stage.addEventListener(MouseEvent.MOUSE_WHEEL, onWheel );
render();
}
private function onMove(e:MouseEvent):void{
rot = mouseX * 2;
render();
}
private function onWheel(e:MouseEvent):void{
var d:Number = e.delta;
if(d < 0) fov -= 1;
else fov += 1;
fov = (fov <= 0) ? 1 : (fov >= 180) ? 179 : fov;
proj.fieldOfView = fov;
render();
}
private function render():void{
m.identity();
m.appendRotation( rot, Vector3D.Y_AXIS);
m.appendTranslation( 0,100, 1000 );
m.append( proj.toMatrix3D() );
model.render( g, m);
}
}
}
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.utils.*;
import mx.utils.Base64Decoder;
/* いつかやる
class Camera3D{
}
class Scene{
}
class Viewport{
}//*/
interface IDispatcher{
function addEvent(type:String, listener:Function):void;
function removeEvent(type:String, listener:Function):void;
}
interface IDecoder extends IDispatcher{
function get bitmapData():BitmapData;
function decode():void;
}
class AbstDispacher implements IDispatcher{
private var _d:EventDispatcher;
protected function get d():EventDispatcher{ return _d || ( _d = new EventDispatcher() ); }
public function addEvent( type:String, listener:Function ):void{ d.addEventListener( type, listener); }
public function removeEvent( type:String, listener:Function ):void{ d.removeEventListener( type,listener); }
}
class MQOLoader extends AbstDispacher{
static public const PARSE_COMP:String = "complete_MQO";
static private const READ_COMP:String = "read_complete_MQO";
private var s:String;
private var object_reg:RegExp = /Object \"(.*?)\" \{(.*?}\n)}/sg;
private var last:int = 0;
private var mirror:String;
private var mirror_axis:int;
private var tempV:Vector.<Vertex>;
private var indexCounter:uint = 0;
private var l:URLLoader;
private var _parsed:Boolean = false;
private var model:MQO;
private var material:Material;
private var texture:ZIPImages;
private var scale:Number;
public function MQOLoader(){}
public function load( modelURL:String = null, texture:ZIPImages = null ):void{
this.texture = texture;
if(!modelURL)return;
l = new URLLoader();
l.dataFormat = "binary";
l.addEventListener(Event.COMPLETE, onComp );
l.load( new URLRequest( modelURL) );
}
public function get modelData():MQO{ return _parsed ? model : null; }
private function onComp(e:Event):void{
var b:ByteArray = l.data as ByteArray;
if(!b)return;
setData( b );
}
public function setData( modelData:ByteArray, texture:ZIPImages = null):void{
this.texture = texture;
s = String( modelData.readMultiByte( modelData.length, "shift-jis") ).replace(/\r\n/g,"\n");
s = s.replace(/\t/g,"");
model = new MQO();
last = 0;
tempV = new Vector.<Vertex>();
scale = Number(/zoom2 (.*?)\n/sg.exec(s)[1]) / 5;
addEvent( READ_COMP, readComp);
addEvent( "readMQO_Object", readObjectChunk );
readObjectChunk();
}
private function readComp(e:Event):void{
removeEvent( "readMQO_Object", readObjectChunk );
var ind:Vector.<int> = model.indices;
var len:int = model.vertices.length / 3;
for(var i:int = 0; i<len; i++) ind[i] = i; // indexの初期化
var material_reg:RegExp = /Material (.*?) \{\n(.*?)\n}/sg; // マテリアルデータの抽出
material = new Material();
if( material_reg.test( s ) ){
material_reg.lastIndex = 0;s
var material_data:Array = material_reg.exec( s );
readMaterial(parseInt(material_data[1]), material_data[2]);
}model.texture = material.getData();
d.dispatchEvent( new Event( PARSE_COMP ) );
}
private function readMaterial( num:int, data:String ):void{
var arr:Array = data.split("\n");
if(num != arr.length)return;
for(var i:int = 0; i<num; i++){
var s:String = arr[i] as String;
var name:String = "";
var c:Array = (/col\((.*?)\)/s.exec(s)[1] as String).split(" ");
if(!texture){
material.addSolidMaterial( ((c[3] * 0xFF)<<24 | (c[0]*0xFF)<<16 | (c[1]*0xFF)<<8 | c[2]*0xFF) );
return;
}if(/tex/s.test(s)){
name = (/tex\(\"(.*?)\"\)/s).exec( s )[1];
name = name.match( /[^\\]*$/ )[0];
if( /aplane/s.test(s) ){
var a_name:String = (/aplane\(\"(.*?)\"\)/s).exec( s )[1];
a_name = a_name.match( /[^\\]*$/ )[0];
material.addImageMaterial( texture.getBitmapDataByName( name), texture.getBitmapDataByName( a_name));
}else material.addImageMaterial( texture.getBitmapDataByName( name) );
}else{
material.addSolidMaterial( ((c[3]*0xFF)<<24 | (c[0]*0xFF)<<16 | (c[1]*0xFF)<<8 | c[2]*0xFF) );
}
}
}
private function readObjectChunk( e:Event = null ):void{
tempV.length = 0;
if( object_reg.test( s ) ){
object_reg.lastIndex = last;
var obj_data:Array = object_reg.exec( s );
var str:String = obj_data[2];
last = object_reg.lastIndex;
if( /mirror (\d)/g.test( str ) ){
mirror = /mirror (\d)/s.exec( str )[1];
mirror_axis = parseInt(/mirror_axis (\d)/s.exec( str )[1]);
}else mirror = "";
var vertex:Array = (/vertex (.*?) \{\n(.*?)\n}/sg).exec( str );
var face:Array = (/face (.*?) \{\n(.*?)\n}/sg).exec( str );
if(!vertex || !face){
d.dispatchEvent( new Event( "readMQO_Object" ) );
return;
}
parseVertex( parseInt(vertex[1]), vertex[2] );
parseFace( parseInt(face[1]), face[2] );
}else{
_parsed = true;
d.dispatchEvent( new Event( READ_COMP ) );
return;
}
d.dispatchEvent( new Event( "readMQO_Object" ) );
}
private function parseVertex( num:uint, chunk:String ):void{
var arr:Array = chunk.split("\n");
for(var i:int = 0; i< num; i++){
var v:Array = (arr[i] as String).split(" ");
var x:Number = parseFloat( v[0] ) * scale;
var y:Number = -parseFloat( v[1] ) * scale;
var z:Number = -parseFloat( v[2] ) * scale;
tempV[i] = new Vertex(x,y,z);
}
}
private function parseFace( num:int, chunk:String ):void{
var v:Vector.<Number> = model.vertices;
var uv:Vector.<Number> = model.uvts;
var f:Array = model.faces;
var arr:Array = chunk.split("\n");
for(var i:int = 0; i<num; i++){
var s:String = arr[i] as String;
var vs:Array = (/V\((.*?)\)/sg.exec(s)[1] as String).split(" ");
var uvs:Array;
var m_num:int = 0;
if( /M/sg.test( s ) ){
m_num = parseInt( /M\((.*?)\)/sg.exec(s)[1] );
m_num = (m_num < 0) ? -1 : m_num;
}if( /UV/sg.test(s) ){
uvs = (/UV\((.*?)\)/sg.exec(s)[1] as String).split(" ");
}else uvs = [];
if(!vs) return;
var a:Vertex, b:Vertex, c:Vertex, d:Vertex;
var uvA:UV, uvB:UV, uvC:UV, uvD:UV;
var _uv:UV = new UV(0,0);
if(m_num < 4) _uv.uv( 0.25 * (m_num%4));
else if(m_num < 8) _uv.uv( 0.25 * (m_num%4), 0.25);
else if(m_num < 12) _uv.uv( 0.25 * (m_num%4), 0.5);
else if(m_num < 16) _uv.uv( 0.25 * (m_num%4), 0.75);
if( vs.length == 3){//*
c = tempV[ parseInt( vs[0] ) ];
b = tempV[ parseInt( vs[1] ) ];
a = tempV[ parseInt( vs[2] ) ];
push3();
if(mirror == "1"){
a = mirrorVertex(a, mirror_axis);
b = mirrorVertex(b, mirror_axis);
c = mirrorVertex(c, mirror_axis);
push3(true);
}//*/
}else if( vs.length == 4){//*
d = tempV[ parseInt( vs[0] ) ];
c = tempV[ parseInt( vs[1] ) ];
b = tempV[ parseInt( vs[2] ) ];
a = tempV[ parseInt( vs[3] ) ];
push4();
if(mirror == "1"){
a = mirrorVertex(a, mirror_axis);
b = mirrorVertex(b, mirror_axis);
c = mirrorVertex(c, mirror_axis);
d = mirrorVertex(d, mirror_axis);
push4( true );
}//*/
}
function push3(mirror:Boolean = false):void{
if(!mirror) v.push( c.x, c.y, c.z, b.x, b.y, b.z, a.x, a.y, a.z );
else v.push( a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z );
f.push( new Face() );
if(uvs.length){
uvC = getUV( parseFloat(uvs[0]), parseFloat(uvs[1]), _uv );
uvB = getUV( parseFloat(uvs[2]), parseFloat(uvs[3]), _uv );
uvA = getUV( parseFloat(uvs[4]), parseFloat(uvs[5]), _uv );
if(!mirror) uv.push( uvC.u, uvC.v, 0, uvB.u, uvB.v, 0, uvA.u, uvA.v, 0 );
else uv.push( uvA.u, uvA.v, 0, uvB.u, uvB.v, 0, uvC.u, uvC.v, 0 );
}else uv.push( 0,0,0, 0,0,0, 0,0,0 );
}
function push4( mirror:Boolean = false ):void{
if(!mirror)
v.push( c.x, c.y, c.z, b.x, b.y, b.z, a.x, a.y, a.z,
a.x, a.y, a.z, d.x, d.y, d.z, c.x, c.y, c.z );
else
v.push( a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z,
c.x, c.y, c.z, d.x, d.y, d.z, a.x, a.y, a.z );
f.push( new Face(), new Face() );
if(uvs.length){
uvD = getUV( parseFloat(uvs[0]), parseFloat(uvs[1]), _uv );
uvC = getUV( parseFloat(uvs[2]), parseFloat(uvs[3]), _uv );
uvB = getUV( parseFloat(uvs[4]), parseFloat(uvs[5]), _uv );
uvA = getUV( parseFloat(uvs[6]), parseFloat(uvs[7]), _uv );
if(!mirror)
uv.push( uvC.u, uvC.v, 0, uvB.u, uvB.v, 0, uvA.u, uvA.v, 0,
uvA.u, uvA.v, 0, uvD.u, uvD.v, 0, uvC.u, uvC.v, 0 );
else
uv.push( uvA.u, uvA.v, 0, uvB.u, uvB.v, 0, uvC.u, uvC.v, 0,
uvC.u, uvC.v, 0, uvD.u, uvD.v, 0, uvA.u, uvA.v, 0 );
}else uv.push( 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0 );
}
}
}
private function getUV(u:Number, v:Number, offset:UV):UV{
return new UV( (u/4) + offset.u, (v/4) + offset.v );
}
private function mirrorVertex(v:Vertex, axis:int):Vertex{
return new Vertex( ((axis & 1) != 0) ? -v.x : v.x, ((axis & 2) != 0) ? -v.y : v.y, ((axis & 4) != 0) ? -v.z : v.z);
}
}
class Material{
static private const p:Point = new Point(0,0);
private var bd:BitmapData;
private var solid:BitmapData;
private var m:Matrix;
private var count:int;
public function Material(){
bd = new BitmapData(2048, 2048, true, 0);
solid = new BitmapData(512,512, true, 0);
m = new Matrix();
}
public function getData():BitmapData{ return bd.clone(); }
public function addImageMaterial( src:BitmapData, alpha:BitmapData = null ):void{
if(count >= 16) return;
draw( src, alpha );
}
public function addSolidMaterial(ARGB:uint = 0xFF000000):void{
if(count >= 16) return;
solid.lock();
solid.fillRect( solid.rect, ARGB );
solid.unlock();
draw( solid );
}
private function draw( src:BitmapData, alpha:BitmapData = null):void{
var _src:BitmapData;
if(alpha){
alpha.applyFilter( alpha, src.rect, p, new G2AFilter() );
src.copyPixels( src, src.rect, p, alpha, p);
}if( src.width != src.height ){
var tx:Number = 1, ty:Number = 1;
if(src.width > src.height){
ty = src.width / src.height;
_src = new BitmapData(src.width,src.width, true, 0);
}else{
tx = src.height / src.width;
_src = new BitmapData(src.height,src.height, true, 0);
}m.identity(); m.scale(tx,ty);
_src.lock();
_src.draw(src, m);
_src.unlock();
$( _src.clone() );
_src.dispose();
}else $( src );
}
private function $( src:BitmapData ):void{
var scale:Number = 1;
if( src.width > src.height) scale = 512 / src.width;
else scale = 512 / src.height;
m.identity();
m.scale(scale, scale);
if(count < 4) m.translate( (count%4) * 512, 0);
else if(count < 8) m.translate( (count%4) * 512, 512);
else if(count < 12) m.translate( (count%4) * 512, 1024);
else if(count < 16) m.translate( (count%4) * 512, 1536);
else return;
bd.lock();
bd.draw( src, m );
bd.unlock();
count++;
}
}
class MQO{
public var vertices:Vector.<Number>;
public var indices:Vector.<int>;
public var uvts:Vector.<Number>;
public var faces:Array;
private var pv:Vector.<Number>;
private var sortedIndices:Vector.<int>;
private var bd:BitmapData;
public function MQO(){
vertices = new Vector.<Number>();
indices = new Vector.<int>();
uvts = new Vector.<Number>();
faces = [];
pv = new Vector.<Number>();
sortedIndices = new Vector.<int>();
bd = new BitmapData(256,256);
for(var b:int = 0; b<=256; b++) for(var g:int = 0; g<=256; g++) bd.setPixel( g,b, (0x0000 | (g<<8) | b) );
}
public function get polyNum():int{ return vertices.length / 3; }
public function get texture():BitmapData{ return bd.clone(); }
public function set texture( value:BitmapData ):void{ bd = value.clone(); }
public function render( graphics:Graphics, matrix:Matrix3D ):void{
Utils3D.projectVectors( matrix, vertices, pv, uvts );
var face:Face;
var inc:int = 0, len:int = indices.length;
for (var i:int = 0; i<len; i+=3){
face = faces[inc++] as Face;
face.x = indices[i];
face.y = indices[ i + 1 ];
face.z = indices[ i + 2 ];
var i3:int = i*3;
face.w = uvts[ i3 + 2 ] + uvts[ i3 + 5 ] + uvts[ i3 + 8 ];
}
inc = 0;
faces.sortOn("w", Array.NUMERIC);
for each (face in faces){
sortedIndices[inc++] = face.x;
sortedIndices[inc++] = face.y;
sortedIndices[inc++] = face.z;
}
graphics.clear();
graphics.beginBitmapFill( bd, null, true, true );
graphics.drawTriangles( pv, sortedIndices, uvts, "negative");
graphics.endFill();
}
}
class Zip extends AbstDispacher{
static public const LOAD_COMP:String = "zip_load_complete";
static public const READ:String = "zip_read";
static public const READ_COMP:String = "zip_read_complete";
static private const SIGNATURE:uint = 0x04034b50;
private var url:String;
private var autoStart:Boolean = false;
private var _loaded:Boolean = false;
private var _readed:Boolean = false;
private var _read:Event;
private var _data:ByteArray;
private var imgs:ZIPImages;
public function Zip(autoStart:Boolean = false){
this.autoStart = autoStart;
}
public function setZipData( data:ByteArray ):void{
_data = new ByteArray();
data.position = 0;
data.readBytes( _data );
_data.position = 0;
_data.endian = "littleEndian";
imgs = new ZIPImages();
if(autoStart) startReading();
}
public function startReading():void{
if(!_data)return;
addEvent(READ,read);
_read = new Event( READ );
read( _read );
}
private function read( e:Event = null ):void{
if( _data.bytesAvailable ){
if( _data.readInt() !== SIGNATURE ){
removeEvent(READ, read);
_data.clear();
_readed = true;
d.dispatchEvent( new Event( READ_COMP ) );
return;
}
_data.position += 4;
var compression:int = _data.readUnsignedShort();
_data.position += 8;
var compSize:uint = _data.readUnsignedInt();
var uncompSize:uint = _data.readUnsignedInt();
var fileNameLength:uint = _data.readUnsignedShort();
var exFieldLength:uint = _data.readUnsignedShort();
var fileName:String = _data.readUTFBytes( fileNameLength );
_data.readUTFBytes( exFieldLength );
if(compSize){
var b:ByteArray = new ByteArray();
_data.readBytes( b, 0, compSize );
if(compression == 8) b.inflate();
}
var reg:RegExp = /\.jpg$|\.jpeg$|\.png$|\.tga$|\.bmp$/sig;
if( reg.test( fileName) ) imgs.push( new ZIPImage( b, fileName) ); // image以外を無視
d.dispatchEvent( _read );
}else{
removeEvent(READ, read);
_readed = true;
d.dispatchEvent( new Event( READ_COMP ) );
}
}
private function check(url:String):Boolean { return (/\.zip$/sig.test( url )) ? true : false; }
public function get images():ZIPImages{ return imgs; }
public function get loaded():Boolean{ return _loaded ? true : false; }
}
class ZIPImages extends AbstDispacher{
static public const COMP:String = "zip_image_complete";
private var imgs:Vector.<ZIPImage>;
private var count:int = 1;
private var imgInit:Boolean = false;
public function ZIPImages():void{ imgs = new Vector.<ZIPImage>(); }
public function push( img:ZIPImage ):void{
img.container = this;
imgs.push( img );
}
public function startDecode():void{ for(var i:int = 0; i<imgs.length; i++) imgs[i].start(); }
public function getBitmapDataByName( name:String ):BitmapData{
for(var i:int = 0, len:int = imgs.length; i<len; i++){
var img:ZIPImage = imgs[i] as ZIPImage;
if(new RegExp(name).test(img.name)) return img.bitmapData;
}
return new BitmapData(1,1);
}
public function getBitmapData( num:int ):BitmapData{ return imgs[num].bitmapData; }
public function setComp():void{
if( (count++) >= imgs.length){
imgInit = true;
d.dispatchEvent(new Event(COMP));
}
}
}
class ZIPImage{
private var l:Loader;
private var d:IDecoder;
private var _name:String;
private var bd:BitmapData;
private var decoded:Boolean = false;
public var container:ZIPImages;
public function ZIPImage( data:ByteArray, name:String){
this._name = name.match(/[^\/]*$/)[0];
if(/\.tga$/i.test(name)) d = new TGA( data );
else if(/\.bmp$/i.test(name)) d = new BMP( data );
else d = new BuiltInDecoder( data );
d.addEvent( Decoder.COMP, onDecodeComp);
}
public function start():void{if(decoded) return; d.decode(); }
private function onDecodeComp(e:Event):void{
d.removeEvent( Decoder.COMP, onDecodeComp);
if(container) container.setComp();
decoded = true;
bd = d.bitmapData;
d = null;
}
public function get name():String{ return _name; }
public function get bitmapData():BitmapData{ return bd ? bd : new BitmapData(1,1); }
public function dispose():void{ if(bd) bd.dispose(); }
}
class Decoder extends AbstDispacher implements IDecoder{
public static const COMP:String = "decode_comp";
protected var width:Number, height:Number;
protected var data:ByteArray;
protected var bd:BitmapData;
private var decoded:Boolean = false;
public function Decoder( data:ByteArray ){ this.data = data; }
public function decode():void{}
public function get bitmapData():BitmapData{ return decoded ? bd.clone(): new BitmapData(1,1); }
protected function decodeComp():void{
decoded = true;
d.dispatchEvent( new Event(COMP) );
}
}
class BuiltInDecoder extends Decoder{
private var l:Loader;
public function BuiltInDecoder( data:ByteArray ){
super(data);
(l = new Loader()).contentLoaderInfo.addEventListener(Event.COMPLETE, comp);
}
override public function decode():void{ l.loadBytes( data ); }
private function comp(e:Event):void{
l.contentLoaderInfo.removeEventListener(Event.COMPLETE, comp);
bd = (l.content as Bitmap).bitmapData.clone();
l = null;
decodeComp();
}
}
class TGA extends Decoder{
private const TYPE_NONE:uint = 0x00;
private const TYPE_INDEX_COLOR:uint = 0x01;
private const TYPE_FULL_COLOR:uint = 0x02;
private const TYPE_RLE_BIT:uint = 0x08;
private const DIR_RIGHT_UP:int = 0;
private const DIR_LEFT_UP:int = 1;
private const DIR_RIGHT_DOWN:int = 2;
private const DIR_LEFT_DOWN:int = 3;
private var _idLength:int;
private var _colorMapType:int;
private var _imageType:int;
private var _colorMapIndex:int;
private var _colorMapLength:int;
private var _colorMapSize:int;
private var _originX:int;
private var _originY:int;
private var _bitDepth:int;
private var _descriptor:int;
public function get pixelDirection():int { return (_descriptor >> 4) & 3; }
public function TGA( data:ByteArray ){ super(data); }
override public function decode():void{
data.endian = "littleEndian";
_idLength = data.readByte();
_colorMapType = data.readByte();
_imageType = data.readByte();
_colorMapIndex = data.readShort();
_colorMapLength = data.readShort();
_colorMapSize = data.readByte()
_originX = data.readShort();
_originY = data.readShort();
width = data.readShort();
height = data.readShort();
_bitDepth = data.readByte();
_descriptor = data.readByte();
bd = new BitmapData(width, height);
if ((_imageType & TYPE_FULL_COLOR) == 0|| (_imageType & TYPE_RLE_BIT) != 0) throw new Error("Unsupported tga format.");
bd.lock();
if(_bitDepth == 32) loadBitmap32(data);
if(_bitDepth == 24) loadBitmap24(data);
bd.unlock();
decodeComp();
}
private function loadBitmap32(bytes:ByteArray):void{
var x:int, y:int;
switch (pixelDirection){
case DIR_RIGHT_UP:
for (y = bd.height - 1; y >= 0; --y){
for (x = 0; x < bd.width; ++x) bd.setPixel32(x, y, bytes.readUnsignedInt());
} break;
case DIR_LEFT_UP:
for (y = bd.height - 1; y >= 0; --y){
for (x = bd.width - 1; x >= 0; --x) bd.setPixel32(x, y, bytes.readUnsignedInt());
} break;
case DIR_RIGHT_DOWN:
for (y = 0; y < bd.height; ++y){
for (x = 0; x < bd.width; ++x) bd.setPixel32(x, y, bytes.readUnsignedInt());
} break;
case DIR_LEFT_DOWN:
for (y = 0; y < bd.height; ++y){
for (x = bd.width - 1; x >= 0; --x) bd.setPixel32(x, y, bytes.readUnsignedInt());
} break;
}
}
private function loadBitmap24(bytes:ByteArray):void{
var x:int, y:int;
var r:uint, g:uint, b:uint;
switch (pixelDirection){
case DIR_RIGHT_UP:
for (y = bd.height - 1; y >= 0; --y){
for (x = 0; x < bd.width; ++x) setPixel();
}
break;
case DIR_LEFT_UP:
for (y = bd.height - 1; y >= 0; --y){
for (x = bd.width - 1; x >= 0; --x) setPixel();
}
break;
case DIR_RIGHT_DOWN:
for (y = 0; y < bd.height; ++y){
for (x = 0; x < bd.width; ++x) setPixel();
}
break;
case DIR_LEFT_DOWN:
for (y = 0; y < bd.height; ++y){
for (x = bd.width - 1; x >= 0; --x) setPixel();
}
break;
}
function setPixel():void{
b = bytes.readUnsignedByte();
g = bytes.readUnsignedByte();
r = bytes.readUnsignedByte();
bd.setPixel(x, y, (r << 16) | (g << 8) | b);
}
}
}
class BMP extends Decoder{
private var pos:uint;
private var b:ByteArray;
private var fileSize:uint = 0;
private var offset:uint = 0;
private var infoHeaderSize:int = 0;
private var planes:int = 1;
private var bitCount:uint = 1;
private var compression:int = 0;
private var imageSize:int = 0;
private var usedColor:uint = 0;
private var palleteIndex:uint = 0;
private var rMask:uint = 0, gMask:uint = 0, bMask:uint = 0;
private var rPos:uint = 0,gPos:uint = 0, bPos:uint = 0;
private var rMax:uint = 0, gMax:uint = 0, bMax:uint = 0;
private var pallete:Array;
public function BMP( data:ByteArray ){ super(data); }
private function readFileHeader():Boolean{
if( b.readUTFBytes( 2 ) != "BM" ) return false;
fileSize = b.readUnsignedInt();
b.position += 4;
offset = b.readUnsignedInt();
return true;
}
private function readInfoHeader():void{
infoHeaderSize = b.readUnsignedInt();
if( infoHeaderSize == 40){
width = b.readUnsignedInt();
height = b.readUnsignedInt();
b.position += 2;
bitCount = b.readUnsignedShort();
compression = b.readUnsignedInt();
imageSize = b.readUnsignedInt();
b.position += 8;
usedColor = b.readUnsignedInt();
palleteIndex = b.readUnsignedInt();
}else if( infoHeaderSize == 12){
width = b.readUnsignedShort();
height = b.readUnsignedShort();
b.position += 2;
bitCount = b.readUnsignedShort();
}
}
override public function decode():void{
b = data;
b.endian = "littleEndian";
b.position = 0;
if( !readFileHeader() ) return;
readInfoHeader();
bd = new BitmapData( width, height, true, 0xFF333333);
if( bitCount > 16){
readBitFieald();
checkMask();
}bd.lock();
if( bitCount <= 16) bd.fillRect(bd.rect,0xFFFFFF); // 16bit以下は行数の都合上無視
else if( bitCount == 24) dec24bit();
else if( bitCount == 32) dec32bit();
bd.unlock();
decodeComp();
}
private function dec24bit():void{
var bf:ByteArray = new ByteArray();
var len:int = width * 3;
if( len % 4 > 0) len = ( (len/4|0) + 1 ) * 4;
for( var y:int = height - 1; y >= 0; y--){
bf.length = 0; b.readBytes( bf, 0, len );
for( var x:int = 0; x<width; x++){
var c:uint = (bf.readUnsignedByte() | ( bf.readUnsignedByte() << 8 ) | ( bf.readUnsignedByte() << 16))
bd.setPixel(x,y,c);
}
}
}
private function dec32bit():void{
for(var y:int = height - 1; y >= 0; y--){
for(var x:int = 0; x<width; x++){
var c:uint = b.readUnsignedInt();
c = ( ( ( c & rMask ) >> rPos )*0xff/rMax << 16 ) + ( ( ( c & gMask ) >> gPos )*0xff/gMax << 8 ) + ( ( ( c & bMask ) >> bPos )*0xff/bMax << 0 )
bd.setPixel(x,y,c);
}
}
}
private function readBitFieald():void{
if( compression == 0){
if( bitCount == 16){
rMask = 0x00007c00; gMask = 0x000003e0; bMask = 0x0000001f;
}else{
rMask = 0x00ff0000; gMask = 0x0000ff00; bMask = 0x000000ff;
}
}else if( (compression == 3) && (infoHeaderSize < 52) ){
rMask = b.readUnsignedInt(); gMask = b.readUnsignedInt(); bMask = b.readUnsignedInt();
}
}
private function checkMask():void{
if ( ( rMask & gMask ) | ( gMask & bMask ) | (bMask & rMask ) ) throw new Error();
while( (( rMask >> rPos ) & 0x00000001) == 0 ) rPos++;
while( (( gMask >> gPos ) & 0x00000001) == 0 ) gPos++;
while( (( bMask >> bPos ) & 0x00000001) == 0 ) bPos++;
rMax = rMask >> rPos; gMax = gMask >> gPos; bMax = bMask >> bPos;
}
}
class G2AFilter extends ShaderFilter{
static private var code:ByteArray;
{ static private var dec:Base64Decoder = new Base64Decoder() ;
dec.decode(
"pQEAAACkCQBHMkFGaWx0ZXKgDG5hbWVzcGFjZQBqcC56YWhpcgCgDHZlbmRvcgB6YWhpcgCgCHZl" +
"cnNpb24AAQCgDGRlc2NyaXB0aW9uAGdyYXlTY2FsZSAtPiBhbHBoYQChAQIAAAxfT3V0Q29vcmQA" +
"owAEc3JjAKECBAEAD2RzdAAwAgDxAAAQAB0BAPMCABsAHQEAEAEAAAA=" );
code = dec.toByteArray(); dec = null;
}public function G2AFilter(){ super( new Shader( code) ) }
}
class Vertex{
public var x:Number, y:Number, z:Number;
public function Vertex( x:Number = 0, y:Number = 0, z:Number = 0){ this.x = x; this.y = y; this.z = z; }
}
class UV{
public var u:Number, v:Number;
public function UV( u:Number, v:Number){ uv(u,v) }
public function uv( u:Number = 0, v:Number = 0):void{ this.u = u; this.v = v; }
}
class Face{
public var x:Number, y:Number, z:Number, w:Number;
public function Face( x:Number = 0, y:Number = 0, z:Number = 0, w:Number = 0){
this.x = x; this.y = y; this.z = z; this.w = w;
}
}