In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

SimpleObjectController LookAt [Alternativa3D 7.6 TIPS]

SimpleObjectControllerを使用した、ObjectのLookAtです。

直接、座標を指定する lookAtXYZと
Vector3Dを引数とする。lookAtの2種類が用意されています。

Matrixによる変換をしたVector3Dを使用する場合などは。lookAtを使うと良いでしょう

2011/01/12 7.5から7.6仕様に変更
Get Adobe Flash player
by narutohyper 23 Oct 2012
/**
 * Copyright narutohyper ( http://wonderfl.net/user/narutohyper )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/lxBH
 */

// forked from narutohyper's OriginalPrimitive MultiCylinder [Alternativa3D 7.5 TIPS]
// forked from narutohyper's Alternativa3D 7.5 Template
package
{
    import alternativ7.engine3d.core.Object3DContainer;
    import alternativ7.engine3d.materials.FillMaterial;
    import alternativ7.engine3d.controllers.SimpleObjectController;
    import alternativ7.engine3d.loaders.MaterialLoader;
    import alternativ7.engine3d.materials.TextureMaterial;
    import alternativ7.engine3d.core.Sorting;
    import alternativ7.engine3d.primitives.Box;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Matrix3D;
    import flash.geom.Vector3D;

    import flash.system.LoaderContext;
    
    
    /**
     * Alternativa3D 7.6
     *
     * SimpleController LookAt
     *
     * ...
     * @author narutohyper
     */
    [SWF(backgroundColor="#000000", frameRate="100", width="800", height="600")]
    public class Main extends Sprite
    {
        public function Main():void    {
        
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        
        private function init(e:Event=null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
        
            //AlternativaTemplate作成
            var scene:AlternativaTemplate = new AlternativaTemplate(this);

            
            //外部読み込み画像によるmaterial
            var material:FillMaterial = new FillMaterial(0xCCCCFF,1,0,1);

            addChild(scene.camera.diagram);
            
            var RADIAN:Number = Math.PI / 180;
            
            var cylinderContainer:Object3DContainer = new Object3DContainer();
            scene.container.addChild(cylinderContainer);
            
            var cylinder:Cylinder = new Cylinder(200,0,100,1,4,-90,false,false);
            cylinder.setMaterialToAllFaces(material);
            cylinderContainer.addChild(cylinder);
            cylinder.rotationX=90*RADIAN;

            //ObjectControllerの作成
            var objectController:SimpleObjectController = new SimpleObjectController(stage,cylinderContainer,100);
            //デフォルトのキーバインドを無効にする
            objectController.unbindAll();
            //デフォルトで有効になってる、マウス操作を無効にする
            objectController.mouseSensitivity = 0;
            
            
            var box:Box = new Box(200,200,200);
            box.setMaterialToAllFaces(material);
            scene.container.addChild(box);
    
            
            //カメラの調整
            //カメラはControllerに関連付けている為、x,y,zで直接位置を指定できないので
            //SimpleController.setObjectPosXYZを使用
            scene.cameraController.setObjectPosXYZ(0, -1500, 500);
            scene.cameraController.lookAtXYZ(0, 0, 0);

            var angle:Number = 0;
            var point:Vector3D;
            var matrix:Matrix3D;
            
            scene.onPreRender = function():void {
                angle+=1;
                box.x = Math.cos(angle * RADIAN) * 500;
                box.y = Math.sin(angle * RADIAN * 2) * 500;
                box.z = Math.sin(angle * RADIAN) * 500;

                objectController.lookAtXYZ(box.x, box.y, box.z);
                
                objectController.update();
                
            }
            
            //描画開始
            scene.startRendering();

        }


    }
    
}


import alternativ7.engine3d.core.Vertex;
import alternativ7.engine3d.core.Face;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.materials.Material;
import alternativ7.engine3d.objects.Mesh;
/**
 * 汎用性のあるシリンダー&コーンプリミティブクラス
 *
 *
 * @author narutohyper
 */
class Cylinder extends Mesh
{
    /**

     */
    public static const CIRCLE:String = 'circle';

    /**
     * sideのfaceへ筒状にUV設定するタイプ
     */
    public static const LINER:String = 'liner';




    /**
     * 新しい Alternativa3DTemplate インスタンスを作成します。
     *
     * @param        height;
     * @param        topRadius;
     * @param        bottomRadius;
     * @param        heightSegments;
     * @param        radialSegments;
     * @param        startVertexAngle;
     * @param        star;
     * @param        twoSided;
     * @param        reverse;
     * @param        triangulate;
     * @param        sideTextureType;
     * @param        topMaterial;
     * @param        bottomMaterial;
     * @param        sideMaterial;
     * @param        topVisible;
     * @param        bottomVisible;
     */
    public function Cylinder(height:Number = 100,
                             topRadius:Number = 0,bottomRadius:Number = 100,
                             heightSegments:uint = 1, radialSegments:uint = 12,
                             startVertexAngle:Number=-90,star:Boolean = false,
                             twoSided:Boolean = false, reverse:Boolean = false,
                             triangulate:Boolean = false, sideTextureType:String = LINER,
                             topVisible:Boolean = true,bottomVisible:Boolean = true,
                             topMaterial:Material=null,bottomMaterial:Material=null,sideMaterial:Material=null) {

        this.height             = height;
        this.topRadius          = topRadius;
        this.bottomRadius       = bottomRadius;
        this.heightSegments     = heightSegments;
        this.radialSegments     = radialSegments;
        this.startVertexAngle   = startVertexAngle;
        this.star               = star;
        this.twoSided           = twoSided;
        this.reverse            = reverse;
        this.triangulate        = triangulate;
        this.sideTextureType    = sideTextureType;
        this.topMaterial        = topMaterial;
        this.bottomMaterial     = bottomMaterial;
        this.sideMaterial       = sideMaterial;
        this.topVisible         = topVisible;
        this.bottomVisible      = bottomVisible;

        if (this.sideMaterial == null) {
            this.sideMaterial = new FillMaterial(0x666666,1);
        }

        makeMesh(true);
    }


    private function makeMesh(value:Boolean=false):void {
      if (_geometryFlag || value)    {
        _geometryFlag = true;
        makeSide();
                if (topRadius && topVisible) {
                        makePlane(height / 2, topRadius, topMaterial, true, 'top');
                }
                if (bottomRadius && bottomVisible) {
                        makePlane(-height/2,bottomRadius,bottomMaterial,false,'bottom');
                }
                calculateNormals();
      }
    }

    private function makePlane(tz:Number,radius:Number,material:Material,top:Boolean,pre:String):void {

        var vertex:Vector.<Vertex> = new Vector.<Vertex>(radialSegments);
        var RADIAN:Number = Math.PI / 180;
        var sr:Number = startVertexAngle;
        var pitch:Number = 360/radialSegments;
        var angle:Number;
        var i:uint;
        var length:Number = radius;

        var tw:Number = Math.cos(0 * RADIAN) * length * 2;
        var th:Number = Math.sin(90 * RADIAN) * length * 2;

        var tx:Number;
        var ty:Number;
        var tu:Number;
        var tv:Number;
        var v:Vertex;

        for (i = 0; i < radialSegments; i++) {
            angle = (sr + (pitch * i)) * RADIAN;
            if (star) {
                if (i && i % 2) {
                    tx = Math.cos(angle) * length;
                    ty = Math.sin(angle) * length;
                } else {
                    tx = Math.cos(angle) * length/2;
                    ty = Math.sin(angle) * length/2;
                }
            } else {
                tx = Math.cos(angle) * length;
                ty = Math.sin(angle) * length;
            }
            tu = (tx + tw / 2) / tw;
            tv = (ty + th / 2) / th;

            vertex[i] = addVertex(tx, ty, tz, tu, tv, pre+'Vertex'+i);
        }

        //bottom
        //底辺は反転
        var turn:Boolean=reverse;
        if (!top) turn = !turn

        if (!turn) {
                        trace(vertex);
            addFace(vertex,material, pre+'Front');
            if (twoSided) {
                vertex.reverse();
                v = vertex.shift()
                vertex.push(v);
                addFace(vertex,material, pre+'Back');
            }
        } else {
            if (twoSided) {
                            trace(vertex);
              addFace(vertex,material, pre+'Front');
            }
            vertex.reverse();
            v = vertex.shift()
            vertex.push(v);
            addFace(vertex,material, pre+'Back');

        }

    }

    private function makeSide():void {
        var h:Number = height/heightSegments;
        var offsetRadius:Number;
        var iz:int;
        var ir:int;
        var nh:Number;
        var oh:Number;
        var nx:Number;
        var ny:Number;
        var nz:Number;
        var nr:Number;        //半径

        var tu:Number            //U
        var tv:Number            //V
        var uvx:Number;
        var uvy:Number;


        var tuStep:Number = 1/radialSegments;
        var tvStep:Number = 1/heightSegments;

        var sinR:Number = Math.sin((360 / radialSegments) * Math.PI / 180);
        var cosR:Number = Math.cos((360 / radialSegments) * Math.PI / 180);
        var step:Number = 360 / radialSegments;


        var vertex:Vector.<Vertex> = new Vector.<Vertex>;

        var id:uint = 0;
        var v0:Vertex;
        //Vertex(頂点)の登録

        var start:uint;
        var end:uint;
        if (topRadius > bottomRadius) {
            offsetRadius = topRadius - bottomRadius;
            if (bottomRadius == 0) {
                end = 1;
            } else {
                end = 0;
            }
            for (iz = 0; iz <= heightSegments-end; iz++)
            {
                for (ir = 0; ir <= radialSegments;ir++ )
                {
                    nh = (h * iz);
                    oh = (nh) ? (height - nh) / height:1;
                    nr = (bottomRadius + (offsetRadius * oh));
                    if (star) {
                        if (ir && ir % 2) {
                        } else {
                            nr=nr/2;
                        }
                    }
                    nz = (height / 2) - nh;

                    nx = Math.cos((step * ir + startVertexAngle) * Math.PI / 180)*nr;
                    ny = Math.sin((step * ir + startVertexAngle) * Math.PI / 180) * nr;

                    //UV計算
                    //とりあえず、巻きつけ
                    if (sideTextureType == Cylinder.CIRCLE) {
                        //高さ
                        //半径0.5
                        //長さは、(0.5/heightSegments)*iz
                        uvx = Math.cos((step * ir + startVertexAngle) * Math.PI / 180) * (0.5-(0.5 / heightSegments) * iz)+0.5;
                        uvy = Math.sin((step * ir + startVertexAngle) * Math.PI / 180) * (0.5-5(0.5 / heightSegments) * iz)+0.5;
                        v0 = addVertex(nx, ny, nz, uvx, uvy, 'sideVertex' + id);
                    } else {
                        v0 = addVertex(nx, ny, nz, tuStep * ir, tvStep * iz, 'sideVertex' + id);
                    }
                    id++;
                }
            }
            if (bottomRadius == 0) {
                start = 1;
                nz = (height / -2);
                if (sideTextureType == Cylinder.CIRCLE) {
                    v0 = addVertex(0, 0, nz, 0, 0, 'sideVertex' + id);
                } else {
                    v0 = addVertex(0, 0, nz, tuStep * ir, tvStep * iz, 'sideVertex' + id);
                }
                id++;
            }

        } else {
            offsetRadius = bottomRadius - topRadius;

            if (topRadius == 0) {
                nz = (height / 2);
                if (sideTextureType == Cylinder.CIRCLE) {
                    v0 = addVertex(0, 0, nz, 0.5, 0.5, 'sideVertex' + id);
                } else {
                    v0 = addVertex(0, 0, nz, tuStep * ir, tvStep * iz, 'sideVertex' + id);
                }
                id++;
                start = 1;
            } else {
                start = 0;
            }
            for (iz = start; iz <= heightSegments; iz++)
            {
                for (ir = 0; ir <= radialSegments;ir++ )
                {
                    nh = (h * iz);
                    oh = (nh) ? nh / height:0;
                    nr = (topRadius + (offsetRadius * oh));
                    if (star) {
                        if (ir && ir % 2) {
                        } else {
                            nr = nr * starRadius;
                        }
                    }
                    nz = (height / 2) - nh;

                    nx = Math.cos((step * ir + startVertexAngle) * Math.PI / 180) * nr;
                    ny = Math.sin((step * ir + startVertexAngle) * Math.PI / 180) * nr;
                    if (sideTextureType == Cylinder.CIRCLE) {
                        //高さ
                        //半径0.5
                        //長さは、(0.5/heightSegments)*iz
                        uvx = Math.cos((step * ir + startVertexAngle) * Math.PI / 180) * (0.5 / heightSegments) * iz+0.5;
                        uvy = Math.sin((step * ir + startVertexAngle) * Math.PI / 180) * (0.5 / heightSegments) * iz+0.5;
                        v0 = addVertex(nx, ny, nz, uvx, uvy, 'sideVertex' + id);
                    } else {
                        v0 = addVertex(nx, ny, nz, tuStep * ir, tvStep * iz, 'sideVertex' + id);
                    }
                    id++;

                }
            }

        }

        //コーンの場合(topSegment or bottomSegment =0)と、シリンダーでは、SideのUVの割り当てを変える
        //コーンでは、Textureの中心から円状に
        //シリンダーの場合は、巻きつけ


        //Face(面・四角)の登録
        id = 0;
        var n1:uint;
        var n2:uint;
        var n3:int;
        var v1:Vertex;
        var v2:Vertex;
        var v3:Vertex;
        var v4:Vertex;

        for (iz = 0; iz < heightSegments; iz++)
        {
            for (ir = 0; ir < radialSegments;ir++ )
            {

                n1 = ir;
                n2 = ir + 1;

                //n3
                if (topRadius == 0) {
                    //Cone上向き
                    n3 = (iz * (radialSegments + 1) - radialSegments);
                } else {
                    n3 = (iz * (radialSegments+1));
                }

                if (topRadius == 0 && iz == 0) {
                    n3 = 1;
                    v1 = getVertexById('sideVertex' + 0);
                    v2 = getVertexById('sideVertex' + (n3 + n2));
                    v3 = getVertexById('sideVertex' + (n3 + n1));
                    if (!reverse) {
                        addTriFace(v1, v3, v2, sideMaterial, 'sideFront' + id);
                        if (twoSided) {
                            addTriFace(v1, v2, v3, sideMaterial, 'sideBack' + id);
                        }
                    } else {
                        addTriFace(v1, v2, v3, sideMaterial, 'sideBack' + id);
                        if (twoSided) {
                            addTriFace(v1, v3, v2, sideMaterial, 'sideFront' + id);
                        }
                    }
                } else if (bottomRadius == 0 && iz == heightSegments - 1) {
                    v1 = getVertexById('sideVertex' + (n3 + n1));
                    v2 = getVertexById('sideVertex' + (n3 + n2));
                    v3 = getVertexById('sideVertex' + (n3 + radialSegments + 1));
                    if (!reverse) {
                        addTriFace(v1, v3, v2, sideMaterial, 'sideFront' + id);
                        if (twoSided) {
                            addTriFace(v1, v2, v3, sideMaterial, 'sideBack' + id);
                        }
                    } else {
                        addTriFace(v1, v3, v2, sideMaterial, 'sideBack' + id);
                        if (twoSided) {
                            addTriFace(v1, v2, v3, sideMaterial, 'sideFront' + id);
                        }
                    }
                } else {
                    v1 = getVertexById('sideVertex' + (n3 + n1));
                    v2 = getVertexById('sideVertex' + (n3 + n2));
                    v3 = getVertexById('sideVertex' + (n3 + n2 + radialSegments+1));
                    v4 = getVertexById('sideVertex' + (n3 + n1 + radialSegments + 1));
                    if (!reverse) {
                        addQuadFace(v1, v4, v3, v2, sideMaterial, 'sideFront' + id);
                        if (twoSided) {
                            addQuadFace(v1, v2, v3, v4, sideMaterial, 'sideBack' + id);
                        }
                    } else {
                        addQuadFace(v1, v2, v3, v4, sideMaterial, 'sideBack' + id);
                        if (twoSided) {
                            addQuadFace(v1, v4, v3, v2, sideMaterial, 'sideFront' + id);
                        }
                    }
                }
                id++;
            }
        }


    }



    /**
     * シリンダー or コーンの高さ
     * 0以下を指定するとArgumentError
     */
    public function get height():Number { return _height; }

    public function set height(value:Number):void
    {
        _height = value;
        if (height <= 0)
        {
            throw new ArgumentError("height are given below 0");
        }
        makeMesh();

    }

    /**
     * シリンダー or コーンの上面の半径
     * topRadiusとbottomRadius両方に0以下を指定するとArgumentError
     */
    public function get topRadius():Number { return _topRadius; }

    public function set topRadius(value:Number):void
    {
        _topRadius = value;
        if (bottomRadius <= 0 && topRadius <= 0)
        {
                throw new ArgumentError("bottomRadius and topRadius are given below 0");
        }
        makeMesh();
    }

    /**
     * シリンダー or コーンの底面の半径
     * topRadiusとbottomRadius両方に0以下を指定するとArgumentError
     */
    public function get bottomRadius():Number { return _bottomRadius; }

    public function set bottomRadius(value:Number):void
    {
        _bottomRadius = value;
        if (bottomRadius <= 0 && topRadius <= 0)
        {
                throw new ArgumentError("bottomRadius and topRadius are given below 0");
        }
        makeMesh();

    }

    /**
     * シリンダー or コーンの高さの分割数
     * 1未満を指定するとArgumentError
     */
    public function get heightSegments():uint { return _heightSegments; }

    public function set heightSegments(value:uint):void
    {
        _heightSegments = value;
        if (heightSegments < 1)
        {
            throw new ArgumentError("heightSegments are given below 1");
        }
        makeMesh();

    }


    /**
     * シリンダー or コーンの円周の分割数
     * 3未満を指定するとArgumentError
     *
     */
    public function get radialSegments():uint { return _radialSegments; }

    public function set radialSegments(value:uint):void
    {
        _radialSegments = value;
        if (radialSegments < 3)
        {
            throw new ArgumentError("radialSegments are given below 3");
        }
        makeMesh();

    }

    /**
     * シリンダー or コーンの円周のVertexの始まりの角度。
     * UVマップに影響する。
     * 5角形や、星型といった形状作成の時、上部中央に頂点を持ってくる場合、-90を指定する
     *
     */
    public function get startVertexAngle():Number { return _startVertexAngle; }

    public function set startVertexAngle(value:Number):void
    {
        _startVertexAngle = value;
        makeMesh();

    }


    /**
     * 星型にする
     */
    public function get star():Boolean { return _star; }

    public function set star(value:Boolean):void
    {
        _star = value;
        if (_star && radialSegments % 2)
        {
            throw new ArgumentError("if the star is true, the radialSegments is Even");
        }
        makeMesh();

    }

    /**
     * 両面にする
     *
     */
    public function get twoSided():Boolean { return _twoSided; }

    public function set twoSided(value:Boolean):void
    {
        _twoSided = value;
        makeMesh();

    }

    /**
     * 反転する
     * frontFaceとbackFaceを入れ替える
     *
     * twoSidedがfalseの場合
     * sideFront(topFront、bottomFront)が有効になる
     *
     * twoSidedがtrueの場合
     * sideBack(topBack、bottomBack)が有効になる
     *
     */
    public function get reverse():Boolean { return _reverse; }

    public function set reverse(value:Boolean):void
    {
        _reverse = value;
        makeMesh();

    }

    /**
     * Faceの最小単位を三角形にする。(未実装)
     */
    public function get triangulate():Boolean { return _triangulate; }

    public function set triangulate(value:Boolean):void
    {
        _triangulate = value;
        makeMesh();

    }

    /**
     * sideのUV割付タイプを指定
     *
     * Cylinder.CIRCLE : sideのfaceへ円状にUV設定するタイプ
     * Cylinder.LINER : sideのfaceへ筒状にUV設定するタイプ
     *
     */
    public function get sideTextureType():String { return _sideTextureType; }

    public function set sideTextureType(value:String):void
    {
        _sideTextureType = value;
        makeMesh();

    }


    /**
     * top(上面)のMaterialの設定
     */
    public function get topMaterial():Material { return _topMaterial; }

    public function set topMaterial(value:Material):void
    {
        _topMaterial = value;
    }

    /**
     * bottom(底面)のMaterialの設定
     */
    public function get bottomMaterial():Material { return _bottomMaterial }

    public function set bottomMaterial(value:Material):void
    {
        _bottomMaterial = value;
    }

    /**
     * side(横面)のMaterialの設定
     */
    public function get sideMaterial():Material { return _sideMaterial; }

    public function set sideMaterial(value:Material):void
    {
        _sideMaterial = value;
        if (faces.length) {
            for each (var face:Face in faces) {
                face.material = _sideMaterial;
            }
        }
    }

    /**
     * top(上面)の表示・非表示
     */
    public function get topVisible():Boolean { return _topVisible; }

    public function set topVisible(value:Boolean):void
    {
        _topVisible = value;
        makeMesh();
    }

    /**
     * bottom(底面)の表示・非表示
     */
    public function get bottomVisible():Boolean { return _bottomVisible; }

    public function set bottomVisible(value:Boolean):void
    {
        _bottomVisible = value;
        makeMesh();
    }

    /**
     * 星型の内側頂点の割合
     * 0~1
     */
    public function get starRadius():Number { return _starRadius; }

    public function set starRadius(value:Number):void
    {
        _starRadius = value;
    }


    /**
     * private property
     */
    private var _height:Number;
    private var _topRadius:Number=3;
    private var _bottomRadius:Number=3;
    private var _heightSegments:uint;
    private var _radialSegments:uint;
    private var _startVertexAngle:Number;
    private var _star:Boolean;
    private var _twoSided:Boolean;
    private var _reverse:Boolean;
    private var _triangulate:Boolean;
    private var _sideTextureType:String;
    private var _topMaterial:Material;
    private var _bottomMaterial:Material;
    private var _sideMaterial:Material;
    private var _topVisible:Boolean=true;
    private var _bottomVisible:Boolean=true;

    private var _geometryFlag:Boolean = false;

    private var _starRadius:Number=0.5;

}



/**
 * BasicTemplate for Alternativa3D 7.6
 * Alternativa3D 7.6を扱いやすくするためのテンプレートです
 * @author narutohyper & clockmaker
 *
 */
import alternativ7.engine3d.containers.BSPContainer;
import alternativ7.engine3d.containers.ConflictContainer;
import alternativ7.engine3d.containers.DistanceSortContainer;
import alternativ7.engine3d.containers.KDContainer;
import alternativ7.engine3d.containers.LODContainer;
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.core.View;
import flash.display.DisplayObject;

import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;

import flash.events.Event;

class AlternativaTemplate extends Sprite
{
    /**
     * 子オブジェクトを最適な方法でソートするコンテナ
     * (ConflictContainer)
     */
    public static const CONFLICT:String = 'conflict';
    /**
     * 子オブジェクトをBSP(バイナリ空間分割法)によってソートするコンテナ
     * (BSPContainer)
     */
    public static const BSP:String = 'bsp';
    
    /**
     * 子オブジェクトをカメラからのZ値でソートするコンテナ
     * (DistanceSortContainer)
     */
    public static const ZSORT:String = 'zsort';
    /**
     * KDツリー(http://ja.wikipedia.org/wiki/Kd%E6%9C%A8)によってソートするコンテナ
     * (KDContainer)
     */
    public static const KD:String = 'kd';
    /**
     * detalizationと子オブジェクトの距離でソートするコンテナ(詳細は調査中)
     * (LODContainer)
     */
    public static const LOD:String = 'lod';
    
    /**
     * 3dオブジェクト格納するコンテナインスタンス。
     */
    public var container:Object3DContainer;

    /**
     * ビューインスタンスです。
     */
    public var view:View;
    
    /**
     * カメラインスタンスです。
     */
    public var camera:Camera3D;
    
    /**
     * カメラコントローラーです。
     */
    public var cameraController:SimpleObjectController;
    
    private var _mc:DisplayObjectContainer;
    private var _viewWidth:int;
    private var _viewHeight:int;
    private var _scaleToStage:Boolean;
    private var _containerType:String;
    
    /**
     * 新しい Alternativa3DTemplate インスタンスを作成します。
     * @param    mc
     * @param    containerType
     * @param    viewWidth
     * @param    viewHeight
     * @param    scaleToStage
     */
    public function AlternativaTemplate(mc:DisplayObjectContainer,containerType:String=CONFLICT,viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true)
    {
        
        _mc = mc;
        _mc.addChild(this);

        _containerType = containerType;
        _viewWidth = viewWidth;
        _viewHeight = viewHeight;
        _scaleToStage = scaleToStage;
        
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
    }


    /**
     * 初期化されたときに実行されるイベントです。
     * 初期化時に実行したい処理をオーバーライドして記述します。
     */
    protected function atInit():void {}


    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング前に実行したい処理をオーバーライドして記述します。
     */
    protected function atPreRender():void {}
    
    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング前に実行したい処理をオーバーライドして記述します。
     */
    private var _onPreRender:Function = function():void{};
    public function get onPreRender():Function { return _onPreRender; }
    public function set onPreRender(value:Function):void
    {
        _onPreRender = value;
    }
    
    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング後に実行したい処理をオーバーライドして記述します。
     */
    protected function atPostRender():void {}
    
    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング後に実行したい処理を記述します。
     */
    private var _onPostRender:Function = function():void{};
    public function get onPostRender():Function { return _onPostRender; }
    public function set onPostRender(value:Function):void
    {
        _onPostRender = value;
    }
    
    
    /**
     * レンダリングを開始します。
     */
    public function startRendering():void
    {
        addEventListener(Event.ENTER_FRAME, onRenderTick);
    }

    /**
    * レンダリングを停止します。
    */
    public function stopRendering():void
    {
        removeEventListener(Event.ENTER_FRAME, onRenderTick);
    }

    /**
     * シングルレンダリング(レンダリングを一回だけ)を実行します。
     */
    public function singleRender():void
    {
        onRenderTick();
    }

    /**
     * @private
     */
    private function init(e:Event = null):void
    {
        removeEventListener(Event.ADDED_TO_STAGE, init);
        // entry point
        stage.scaleMode = StageScaleMode.NO_SCALE;
        stage.align = StageAlign.TOP_LEFT;
        stage.quality = StageQuality.HIGH;
        
        //Root objectの作成
        if (_containerType == CONFLICT) {
            container = new ConflictContainer();
        } else if (_containerType == BSP) {
            container = new BSPContainer();
        } else if (_containerType == ZSORT) {
            container = new DistanceSortContainer();
        } else if (_containerType == KD) {
            container = new KDContainer();
        } else if (_containerType == LOD) {
            container = new LODContainer();
        }
        //Viewの作成
        view = new View(stage.stageWidth, stage.stageHeight);
        _mc.addChild(view);

        //cameraの作成
        camera = new Camera3D();
        camera.view = view;
        camera.x = 0;
        camera.y = -500;
        camera.z = 0;
        container.addChild(camera);
        
        // Camera controller
        cameraController = new SimpleObjectController(stage, camera, 10);
        cameraController.mouseSensitivity = 0;
        cameraController.unbindAll();
        cameraController.lookAtXYZ(0, 0, 0);
        
        onResize();
        stage.addEventListener(Event.RESIZE, onResize);
        
        atInit();
    }
    
    /**
     * @private
     */    
    private function onResize(e:Event = null):void 
    {
        if (_scaleToStage)
        {
            view.width = stage.stageWidth;
            view.height = stage.stageHeight;
        } 
        else
        {
            view.width = _viewWidth;
            view.height = _viewHeight;
        }
    }
    
    /**
     * @private
     */    
    private function onRenderTick(e:Event = null):void 
    {
        atPreRender();
        _onPreRender();
        cameraController.update();
        camera.render();
        atPostRender();
        _onPostRender();
    }
    
    
}