- 最后登录
- 2013-12-29
- 注册时间
- 2013-6-7
- 阅读权限
- 30
- 积分
- 630
- 纳金币
- 386
- 精华
- 8
|
/*
# ***** BEGIN LICENSE BLOCK *****
Copyright the original author or authors.
Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# ***** END LICENSE BLOCK *****
*/
import com.bourre.commands.Delegate;
import com.bourre.events.BasicEvent;
import com.bourre.events.EventBroadcaster;
import com.bourre.events.EventType;
import com.bourre.transitions.FpsBeacon;
import sandy.core.data.Vertex;
import sandy.core.data.Vector;
import sandy.core.data.Matrix4;
import sandy.core.group.Group;
import sandy.core.group.Node;
import sandy.core.group.INode;
import sandy.core.buffer.ZBuffer;
import sandy.core.buffer.MatrixBuffer;
import sandy.view.Camera3D;
import sandy.view.IScreen;
import sandy.core.light.Light3D;
import sandy.core.Object3D;
/**
* The 3D world for displaying the Objects.用于显示物体的3维世界
* <p>World3D is a singleton class, it's the central point of Sandy :
* <br/>You can have only one World3D, which contain Groups, Cameras and Lights</p>
* 你只能拥有一个World3D,用于容纳组员,摄影机和灯光。
* @author Thomas Pfeiffer - kiroukou
* @版本 1.0
* @date 16.05.2006
* @see sandy.core.Object3D
*
**/
class sandy.core.World3D
{
/**
* world3d渲染事件,它就是每次渲染场景所播报的事件。The World3D rendering Event. It's the event broadcasted every time the world is rendered
*/
public static var onRenderEVENT:EventType = new EventType( 'onRender' );
/**
* World3D起始事件,当开始渲染场景时播报。The World3D start Event. Broadcasted when the world start to be rendered
*/
public static var onStartEVENT:EventType = new EventType( 'onStart' );
/**
* World3D停止事件,每当停止渲染场景时播报。The World3D stop Event. Broadcasted when the world stop to be rendered
*/
public static var onStopEVENT:EventType = new EventType( 'onStop' );
/**
* World3D灯光更改事件,当灯光改变时播报。The World3D onLightUpdated Event. Broadcasted when the world light is changed
*/
public static var onLightUpdatedEVENT:EventType = new EventType( 'onLightUpdated' );
/**
* The World3D onLightUpdated Event. Broadcasted when the world light is changed
*/
public static var onInitCacheEVENT:EventType = new EventType( 'onInitCache' );
/**
*私有构造函数 Private Constructor.
*
* <p>只能有一个World3D。You can have only one World3D</p>
*
*/
private function World3D ()
{
_eRender = new BasicEvent( World3D.onRenderEVENT );
_eStart = new BasicEvent( World3D.onStartEVENT );
// 初始化事件广播器。init the event broadcaster
_oEB = new EventBroadcaster( this );
//缺省灯光 default light
_light = new Light3D( new Vector( 0, 0, 1 ), 50 );
_isRunning = false;
_aCams = [];
// 添加侦听器we add the listener
FPSBeacon.getInstance().addFrameListener( new Delegate( this, __onEnterFrame ) );
}
/**
*为特定事件添加侦听器。 Add a listener for a specific event.
* @param t 想要注册的EventType类型。 The type of event we want to register
* @param o 监听器对象。The object listener
*/
public function addEventListener( t : EventType, o ) : Void
{
_oEB.addEventListener.apply( _oEB, arguments );
}
/**
* 移除指定事件的监听器。Remove a listener for a specific event.
* @param e 想要移除的事件类型。EventType The type of event we want to register
* @param oL 监听器对象。The object listener
*/
public function removeEventListener( e : EventType, oL ) : Void
{
_oEB.removeEventListener( e, oL );
}
/**
* 得到一个World3D的实例。Get the Singleton instance of World3D.
*
* @return World3D, the only one instance possible返回World3D,唯一的一个实例。
*/
public static function getInstance () : World3D
{
if (_inst === undefined) _inst = new World3D();
return _inst;
}
/**
* 设置场景的摄影机。Set the {@code Camera3D} of the world.
*
* @param cam The new {@link Camera3D}
*/
public function addCamera ( cam:Camera3D ):Number
{
return _aCams.push( cam ) - 1;
}
/**
* 获取场景的摄影机列表。Get the list of {@code Camera3D} of the world.
*
* @return The {@link Camera3D} array返回一个数组。
*/
public function getCameraList ( Void ):Array/*Camera3D*/
{
return _aCams;
}
/**
* Get the a {@code Camera3D} of the world.获取场景中的一个摄影机。
* @param id 标识你想要的摄影机,默认为0。Number The id of the camera you want. default is 0.
* @return 返回Camera3D.The {@link Camera3D}
*/
public function getCamera ( id:Number ):Camera3D
{
if( !id || id < 0 || id >= _aCams.length ) id = 0;
return _aCams[ id ];
}
/**
* 设置3d场景中唯一的灯。We set the unique ligth of the 3D world.
* @param l 灯光实例。Light3D The light instance
* @return Void 无返回直。nothing
*/
public function setLight ( light3D ):Void
{
_oEB.broadcastEvent( new BasicEvent( World3D.onLightUpdatedEVENT ) );
_light = l;
}
/**
* 返回场景中的灯的引用。Returns the world light reference.
* @param Void Nothing
* @return Light3D The light reference
*/
public function getLight ( Void )ight3D
{
return _light;
}
/**
* 为场景添加一个Group.Add a {@code Group} to the world.
*
* @param objGroup 要添加的组。不可以是transformGroup.The group to add. It must not be a transformGroup !
* @return Number The identifier of the object in the list. With that you will be able to use getGroup method.
*/
public function setRootGroup( objGroup:Group ) :Void
{
// check if this node have a parent?!!
_oRoot = objGroup;
}
/**
* 获取场景的根组。 Get the root {@code Group} of the world.
*
* @return Group THe root group of the World3D instance.
*/
public function getRootGroup( Void ):Group
{
return _oRoot;
}
/**
* 计算所有的组,并绘制他们。Compute all groups, and draw them.
* 应该调用一次Should be call only once, or everytime after a Wordl3D.stop call.
*/
public function render ( Void ) : Void
{
if( _isRunning == false )
{
_isRunning = true;
// 播报开始消息。we broadcast the start message
_oEB.broadcastEvent( _eStart );
//开始实时渲染。 we start the real time rendering
FPSBeacon.getInstance().start();
}
}
/**
* 停止渲染。Stop the rendering of the World3D.
* 你可以再次渲染通过调用render方法。You can start again th rendering by calling render method.
*/
public function stop( Void ):Void
{
FPSBeacon.getInstance().stop();
_isRunning = false;
}
/**
* 每次都调用的方法。Method called every time.
*/
private function __onEnterFrame( Void ):Void
{
// 广播事件。we broadcast the event
_oEB.broadcastEvent( _eRender );
//-- we make the active BranchGroup render
__render();
}
/**
* Allows to get the current matrix projection ( usefull since there's several cameras allowed )
* @param Void
* @return Matrix4 The current projection matrix
*/
public function getCurrentProjectionMatrix( Void ):Matrix4
{
return _mProj;
}
/**
* 可以得到当前摄影机。 Allows to get the current camera
* @param Void
* @return Camera3D The current camera
*/
public function getCurrentCamera( Void ):Camera3D
{
return _oCam;
}
////////////////////
//// PRIVATE私有
////////////////////
/**
* Call the recurssive rendering of all the children of this branchGroup.
* This is the most important method in all the engine, because the mojority of the computations are done here.
* This method is making the points transformations and 2D projections.
*/
private function __render( Void ) : Void
{
var l:Number,lc:Number, lp:Number, vx:Number, vy:Number, vz:Number, offx:Number, offy:Number, nbObjects:Number, nbCams:Number;
var mp11:Number,mp21:Number,mp31:Number,mp41:Number,mp12:Number,mp22:Number,mp32:Number,mp42:Number,mp13:Number,mp23:Number,mp33:Number,mp43:Number,mp14:Number,mp24:Number,mp34:Number,mp44:Number;
var mp:Matrix4, aV:Array;
var cam:Camera3D ;
var obj:Object3D;
var v:Vertex;
var crt:Node, crtId:Number;
// we set a variable to remember the number of objects and in the same time we strop if no objects are displayable
if( !( nbCams = _aCams.length ) || _oRoot == null )
return;
//-- we initialize
_bGlbCache = false;
_aObjects = [];
_aMatrix = [];
_aCache = [];
MatrixBuffer.init();
//
__parseTree( _oRoot, _oRoot.isModified() );
// now we check if there are some modifications on that branch
// if true something has changed and we need to compute again
l = nbObjects = _aObjects.length;
while( --l > -1 )
{
obj = _aObjects[ l ];
if( _aCache[ l ] == true )
{
mp = _aMatrix[ l ];
if( mp )
{
aV = obj.aPoints;
//aV.push( obj.getBounds().min, obj.getBounds().max );
mp11 = mp.n11; mp21 = mp.n21; mp31 = mp.n31;
mp12 = mp.n12; mp22 = mp.n22; mp32 = mp.n32;
mp13 = mp.n13; mp23 = mp.n23; mp33 = mp.n33;
mp14 = mp.n14; mp24 = mp.n24; mp34 = mp.n34;
// Now we can transform the objet vertices
lp = aV.length;
while( --lp > -1 )
{
v = aV[lp];
// computations for projection
v.tx = (vx = v.x) * mp11 + (vy = v.y) * mp12 + (vz = v.z) * mp13 + mp14;
v.ty = vx * mp21 + vy * mp22 + vz * mp23 + mp24;
v.tz = vx * mp31 + vy * mp32 + vz * mp33 + mp34;
}
}
else
{
// In this canse we just do a copy of the local position to the transformed
aV = obj.aPoints;
lp = aV.length;
while( --lp > -1 )
{
v = aV[lp];
// computations for projection
v.tx = v.x;
v.ty = v.y;
v.tz = v.z;
}
}
}
else
{
;/* Object cached */
}
}
// -- Now we check if nothing moved on the world and the camera's neither
lc = nbCams;
//
while( --lc > -1 )
{
_oCam = cam = _aCams[ lc ];
// Now we check if nothing moved on the world and the camera's neither
if( _bGlbCache || cam.isModified() )
{
cam.compile();
offx = cam.getXOffset(); offy = cam.getYOffset();
// Camera projection
_mProj = mp = cam.m ;
//
mp11 = mp.n11; mp21 = mp.n21; mp31 = mp.n31; mp41 = mp.n41;
mp12 = mp.n12; mp22 = mp.n22; mp32 = mp.n32; mp42 = mp.n42;
mp13 = mp.n13; mp23 = mp.n23; mp33 = mp.n33; mp43 = mp.n43;
mp14 = mp.n14; mp24 = mp.n24; mp34 = mp.n34; mp44 = mp.n44;
// Object transformations.
l = nbObjects;
while( --l > -1 )
{
obj = Object3D( _aObjects[l] );
aV = obj.aPoints;
//aV.push( obj.getBounds().min, obj.getBounds().max );
lp = aV.length;
while( --lp > -1 )
{
v = aV[lp];
var c:Number = 1 / ( (vx = v.tx) * mp41 + (vy = v.ty) * mp42 + (vz = v.tz) * mp43 + mp44 );
// computations for projection
v.sx = (v.wx = vx * mp11 + vy * mp12 + vz * mp13 + mp14) * c + offx;
v.sy = (v.wy = vx * mp21 + vy * mp22 + vz * mp23 + mp24) * c + offy;
v.wz = vx * mp31 + vy * mp32 + vz * mp33 + mp34;
}
// -- object rendering.
obj.render();
}// end objects loop
// we sort visibles Faces
var aF:Array = ZBuffer.sort();
var s:IScreen = cam.is;
// -- we draw all sorted Faces
s.render( aF );
// -- we clear the ZBuffer
ZBuffer.dispose ();
}
else
{
/* Nothing has moved, so nothing to do exept if an object has a texture which has been updated! Let's see */
l = nbObjects;
while( --l > -1 )
{
obj = Object3D( _aObjects[l] );
if( obj.needRefresh() )
{
obj.refresh();
}
}
// That's all
}
} // end cameras
} // end method
private function __parseTree( n:INode, cache:Boolean ):Void
{
var a:Array = n.getChildList();
var lCache:Boolean = n.isModified();
_bGlbCache = _bGlbCache || lCache;
var l:Number = a.length;
if( !l )
{
_aObjects.push( n );
_aCache.push( cache || lCache );
_aMatrix.push( MatrixBuffer.getCurrentMatrix() );
}
else
{
n.render();
while( --l > -1 )
{
__parseTree( a[l], cache || lCache );
}
n.dispose();
}
n.setModified( false );
return;
}
private var _mProj:Matrix4;
private var _oCam:Camera3D;
private var _oRoot:Group;
/**
* _aGroups : The Array of {@link Group}
*/
private var _aGroups:Array;
/**
* _cam : The {@link Camera3D} of the World3D
*/
private var _aCams:Array/*Camera3D*/;
/**
* _inst : The only one World3D permit
*/
private static var _inst:World3D;
/**
* _oEB : The EventBroadcaster instance which manage the event system of world3D.
*/
private var _oEB:EventBroadcaster;
/**
* the unique light instance of the world
*/
private var _light : Light3D;
private var _eRender:BasicEvent;
private var _eStart:BasicEvent;
private var _isRunning:Boolean;
private var _bGlbCache:Boolean;
private var _aObjects:Array;
private var _aMatrix:Array;
private var _aCache:Array;
}
|
|