PageRenderTime 59ms CodeModel.GetById 14ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 1ms

/src/Stage3dEntity.as

https://bitbucket.org/HopeSky/mars_nd2d
ActionScript | 596 lines | 483 code | 70 blank | 43 comment | 48 complexity | 1bfa201be10495496d35b1950589181f MD5 | raw file
  1// Stage3d game entity class version 1.3
  2//
  3package
  4{
  5import com.adobe.utils.*;
  6import flash.display.Stage3D;
  7import flash.display3D.Context3D;
  8import flash.display3D.Context3DProgramType;
  9import flash.display3D.Context3DTriangleFace;
 10import flash.display3D.Context3DVertexBufferFormat;
 11import flash.display3D.IndexBuffer3D;
 12import flash.display3D.Program3D;
 13import flash.display3D.VertexBuffer3D;
 14import flash.display3D.*;
 15import flash.display3D.textures.*;
 16import flash.geom.Matrix;
 17import flash.geom.Matrix3D;
 18import flash.geom.Vector3D;
 19
 20public class Stage3dEntity
 21{
 22	// Matrix variables (position, rotation, etc.)
 23	private var _transform:Matrix3D;
 24	private var _inverseTransform:Matrix3D;
 25	private var _transformNeedsUpdate:Boolean;
 26	private var _valuesNeedUpdate:Boolean;
 27	private var _x:Number = 0;
 28	private var _y:Number = 0;
 29	private var _z:Number = 0;
 30	private var _rotationDegreesX:Number = 0;
 31	private var _rotationDegreesY:Number = 0;
 32	private var _rotationDegreesZ:Number = 0;
 33	private var _scaleX:Number = 1;
 34	private var _scaleY:Number = 1;
 35	private var _scaleZ:Number = 1;
 36	private const RAD_TO_DEG:Number = 180/Math.PI;
 37	
 38	// Stage3d objects (public so they can be inherited)
 39	public var context:Context3D;
 40	public var vertexBuffer:VertexBuffer3D;
 41	public var indexBuffer:IndexBuffer3D;
 42	public var shader:Program3D;
 43	public var texture:Texture;
 44	public var mesh:Stage3dObjParser;
 45	// Render modes:
 46	public var cullingMode:String = Context3DTriangleFace.FRONT;
 47	public var blendSrc:String = Context3DBlendFactor.ONE;
 48	public var blendDst:String = Context3DBlendFactor.ZERO;
 49	public var depthTestMode:String = Context3DCompareMode.LESS;
 50	public var depthTest:Boolean = true;
 51	public var depthDraw:Boolean = true;
 52
 53	// used only for stats
 54	public var polycount:uint = 0;
 55
 56	// if this is set entity is "stuck" to another
 57	public var following:Stage3dEntity;
 58	
 59	// optimize what data we need to send to Stage3D
 60	// this depends on what the shaders require
 61	public var shaderUsesUV:Boolean = true;
 62	public var shaderUsesRgba:Boolean = true;
 63	public var shaderUsesNormals:Boolean = true; // false;
 64	
 65	// Class Constructor
 66	public function Stage3dEntity(
 67		mydata:Class = null,
 68		mycontext:Context3D = null,
 69		myshader:Program3D = null,
 70		mytexture:Texture = null,
 71		modelscale:Number = 1,
 72		flipAxis:Boolean = true,
 73		flipTexture: Boolean = true)
 74	{
 75		_transform = new Matrix3D();
 76		context = mycontext;
 77		shader = myshader;
 78		texture = mytexture;
 79		if (mydata && context) 
 80		{
 81			mesh = new Stage3dObjParser(
 82				mydata, context, modelscale, flipAxis, flipTexture);
 83			polycount = mesh.indexBufferCount;
 84			trace("Mesh has " + polycount + " polygons.");
 85		}
 86	}
 87
 88    public function get transform():Matrix3D
 89    {
 90        if(_transformNeedsUpdate)
 91            updateTransformFromValues();
 92        return _transform;
 93    }
 94
 95    public function set transform(value:Matrix3D):void
 96    {
 97        _transform = value;
 98        _transformNeedsUpdate = false;
 99        _valuesNeedUpdate = true;
100    }
101
102    // Position:
103
104    public function set position(value:Vector3D):void
105    {
106        _x = value.x;
107        _y = value.y;
108        _z = value.z;
109        _transformNeedsUpdate = true;
110    }
111
112    private var _posvec:Vector3D = new Vector3D();
113	public function get position():Vector3D
114    {
115        if(_valuesNeedUpdate)
116            updateValuesFromTransform();
117		// optimization: avoid creating temporary variable
118        // e.g. return new Vector3D(_x, _y, _z);
119		_posvec.setTo(_x, _y, _z);
120		return _posvec;
121    }
122
123    public function set x(value:Number):void
124    {
125        _x = value;
126        _transformNeedsUpdate = true;
127    }
128    public function get x():Number
129    {
130        if(_valuesNeedUpdate)
131            updateValuesFromTransform();
132        return _x;
133    }
134
135    public function set y(value:Number):void
136    {
137        _y = value;
138        _transformNeedsUpdate = true;
139    }
140    public function get y():Number
141    {
142        if(_valuesNeedUpdate)
143            updateValuesFromTransform();
144        return _y;
145    }
146
147    public function set z(value:Number):void
148    {
149        _z = value;
150        _transformNeedsUpdate = true;
151    }
152    public function get z():Number
153    {
154        if(_valuesNeedUpdate)
155            updateValuesFromTransform();
156        return _z;
157    }
158
159    // Rotation:
160
161    public function set rotationDegreesX(value:Number):void
162    {
163        _rotationDegreesX = value;
164        _transformNeedsUpdate = true;
165    }
166    public function get rotationDegreesX():Number
167    {
168        if(_valuesNeedUpdate)
169            updateValuesFromTransform();
170        return _rotationDegreesX;
171    }
172
173    public function set rotationDegreesY(value:Number):void
174    {
175        _rotationDegreesY = value;
176        _transformNeedsUpdate = true;
177    }
178    public function get rotationDegreesY():Number
179    {
180        if(_valuesNeedUpdate)
181            updateValuesFromTransform();
182        return _rotationDegreesY;
183    }
184
185    public function set rotationDegreesZ(value:Number):void
186    {
187        _rotationDegreesZ = value;
188        _transformNeedsUpdate = true;
189    }
190    public function get rotationDegreesZ():Number
191    {
192        if(_valuesNeedUpdate)
193            updateValuesFromTransform();
194        return _rotationDegreesZ;
195    }
196
197    // Scale:
198
199    public function set scale(vec:Vector3D):void
200    {
201        _scaleX = vec.x;
202        _scaleY = vec.y;
203        _scaleZ = vec.z;
204        _transformNeedsUpdate = true;
205    }
206    private var _scalevec:Vector3D = new Vector3D();
207	public function get scale():Vector3D
208    {
209        if(_valuesNeedUpdate)
210            updateValuesFromTransform();
211        //return new Vector3D(_scaleX, _scaleY, _scaleZ, 1.0);
212		
213		// optimization: avoid creating a temporary variable
214		_scalevec.setTo(_scaleX, _scaleX, _scaleZ);
215		_scalevec.w = 1.0;
216		return _scalevec;
217    }
218    public function set scaleXYZ(value:Number):void
219    {
220        _scaleX = value;
221        _scaleY = value;
222        _scaleZ = value;
223        _transformNeedsUpdate = true;
224    }
225    public function get scaleXYZ():Number
226    {
227        if(_valuesNeedUpdate)
228            updateValuesFromTransform();
229        return _scaleX; // impossible to determine
230        _transformNeedsUpdate = true;
231    }
232    public function set scaleX(value:Number):void
233    {
234        _scaleX = value;
235        _transformNeedsUpdate = true;
236    }
237    public function get scaleX():Number
238    {
239        if(_valuesNeedUpdate)
240            updateValuesFromTransform();
241        return _scaleX;
242    }
243
244    public function set scaleY(value:Number):void
245    {
246        _scaleY = value;
247        _transformNeedsUpdate = true;
248    }
249    public function get scaleY():Number
250    {
251        if(_valuesNeedUpdate)
252            updateValuesFromTransform();
253        return _scaleY;
254    }
255
256    public function set scaleZ(value:Number):void
257    {
258        _scaleZ = value;
259        _transformNeedsUpdate = true;
260    }
261    public function get scaleZ():Number
262    {
263        if(_valuesNeedUpdate)
264            updateValuesFromTransform();
265        return _scaleZ;
266    }
267
268    // Update:
269
270    public function updateTransformFromValues():void
271    {
272        _transform.identity();
273
274        _transform.appendRotation(
275			_rotationDegreesX, Vector3D.X_AXIS);
276        _transform.appendRotation(
277			_rotationDegreesY, Vector3D.Y_AXIS);
278        _transform.appendRotation(
279			_rotationDegreesZ, Vector3D.Z_AXIS);
280
281        // avoid matrix error #2183: 
282		// scale values must not be zero
283		if (_scaleX == 0) _scaleX = 0.0000001;
284		if (_scaleY == 0) _scaleY = 0.0000001;
285		if (_scaleZ == 0) _scaleZ = 0.0000001;
286		_transform.appendScale(_scaleX, _scaleY, _scaleZ);
287
288        _transform.appendTranslation(_x, _y, _z);
289
290        _transformNeedsUpdate = false;
291    }
292
293    public function updateValuesFromTransform():void
294    {
295        var d:Vector.<Vector3D> = _transform.decompose();
296
297        var position:Vector3D = d[0];
298        _x = position.x;
299        _y = position.y;
300        _z = position.z;
301
302        var rotation:Vector3D = d[1];
303        _rotationDegreesX = rotation.x*RAD_TO_DEG;
304        _rotationDegreesY = rotation.y*RAD_TO_DEG;
305        _rotationDegreesZ = rotation.z*RAD_TO_DEG;
306
307        var scale:Vector3D = d[2];
308        _scaleX = scale.x;
309        _scaleY = scale.y;
310        _scaleZ = scale.z;
311
312        _valuesNeedUpdate = false;
313    }
314
315    // Movement Utils:
316
317    // move according to the direction we are facing
318	public function moveForward(amt:Number):void
319    {
320		if (_transformNeedsUpdate) 
321			updateTransformFromValues();
322		var v:Vector3D = frontvector;
323		v.scaleBy(-amt)
324		transform.appendTranslation(v.x, v.y, v.z);
325		_valuesNeedUpdate = true;
326    }
327    public function moveBackward(amt:Number):void
328    {
329		if (_transformNeedsUpdate) 
330			updateTransformFromValues();
331		var v:Vector3D = backvector;
332		v.scaleBy(-amt)
333		transform.appendTranslation(v.x, v.y, v.z);
334		_valuesNeedUpdate = true;
335    }
336    public function moveUp(amt:Number):void
337    {
338		if (_transformNeedsUpdate) 
339			updateTransformFromValues();
340		var v:Vector3D = upvector;
341		v.scaleBy(amt)
342		transform.appendTranslation(v.x, v.y, v.z);
343		_valuesNeedUpdate = true;
344    }
345    public function moveDown(amt:Number):void
346    {
347		if (_transformNeedsUpdate) 
348			updateTransformFromValues();
349		var v:Vector3D = downvector;
350		v.scaleBy(amt)
351		transform.appendTranslation(v.x, v.y, v.z);
352		_valuesNeedUpdate = true;
353    }
354	public function moveLeft(amt:Number):void
355    {
356		if (_transformNeedsUpdate) 
357			updateTransformFromValues();
358		var v:Vector3D = leftvector;
359		v.scaleBy(amt)
360		transform.appendTranslation(v.x, v.y, v.z);
361		_valuesNeedUpdate = true;
362    }
363    public function moveRight(amt:Number):void
364    {
365		if (_transformNeedsUpdate) 
366			updateTransformFromValues();
367		var v:Vector3D = rightvector;
368		v.scaleBy(amt)
369		transform.appendTranslation(v.x, v.y, v.z);
370		_valuesNeedUpdate = true;
371    }
372	
373    // optimization: these vectors are defined as constants
374	// to avoid creation of temporary variables each frame
375	private static const vecft:Vector3D = new Vector3D(0, 0, 1);
376    private static const vecbk:Vector3D = new Vector3D(0, 0, -1);
377    private static const veclf:Vector3D = new Vector3D(-1, 0, 0);
378    private static const vecrt:Vector3D = new Vector3D(1, 0, 0);
379    private static const vecup:Vector3D = new Vector3D(0, 1, 0);
380    private static const vecdn:Vector3D = new Vector3D(0, -1, 0);
381
382    public function get frontvector():Vector3D
383    {
384        if(_transformNeedsUpdate)
385            updateTransformFromValues();
386        return transform.deltaTransformVector(vecft);
387    }
388
389    public function get backvector():Vector3D
390    {
391        if(_transformNeedsUpdate)
392            updateTransformFromValues();
393        return transform.deltaTransformVector(vecbk);
394    }
395
396    public function get leftvector():Vector3D
397    {
398        if(_transformNeedsUpdate)
399            updateTransformFromValues();
400        return transform.deltaTransformVector(veclf);
401    }
402
403    public function get rightvector():Vector3D
404    {
405        if(_transformNeedsUpdate)
406            updateTransformFromValues();
407        return transform.deltaTransformVector(vecrt);
408    }
409
410    public function get upvector():Vector3D
411    {
412        if(_transformNeedsUpdate)
413            updateTransformFromValues();
414        return transform.deltaTransformVector(vecup);
415    }
416
417    public function get downvector():Vector3D
418    {
419        if(_transformNeedsUpdate)
420            updateTransformFromValues();
421        return transform.deltaTransformVector(vecdn);
422    }
423
424    // Handy Utils:
425
426    public function get rotationTransform():Matrix3D
427    {
428        var d:Vector.<Vector3D> = transform.decompose();
429        d[0] = new Vector3D();
430        d[1] = new Vector3D(1, 1, 1);
431        var t:Matrix3D = new Matrix3D();
432        t.recompose(d);
433        return t;
434    }
435
436    public function get reducedTransform():Matrix3D
437    {
438        var raw:Vector.<Number> = transform.rawData;
439        raw[3] = 0; // Remove translation.
440        raw[7] = 0;
441        raw[11] = 0;
442        raw[15] = 1;
443        raw[12] = 0;
444        raw[13] = 0;
445        raw[14] = 0;
446        var reducedTransform:Matrix3D = new Matrix3D();
447        reducedTransform.copyRawDataFrom(raw);
448        return reducedTransform;
449    }
450
451    public function get invRotationTransform():Matrix3D
452    {
453        var t:Matrix3D = rotationTransform;
454        t.invert();
455        return t;
456    }
457
458    public function get positionVector():Vector.<Number>
459    {
460        return Vector.<Number>([_x, _y, _z, 1.0]);
461    }
462
463    public function get inverseTransform():Matrix3D
464    {
465        _inverseTransform = transform.clone();
466        _inverseTransform.invert();
467
468        return _inverseTransform;
469    }
470
471	public function posString():String
472	{
473		if (_valuesNeedUpdate)
474			updateValuesFromTransform();
475		
476		return _x.toFixed(2) + ',' 
477			+ _y.toFixed(2) + ',' 
478			+ _z.toFixed(2);
479	}
480	
481	public function rotString():String
482	{
483		if (_valuesNeedUpdate)
484			updateValuesFromTransform();
485		
486		return _rotationDegreesX.toFixed(2) + ',' 
487			+ _rotationDegreesY.toFixed(2) + ',' 
488			+ _rotationDegreesZ.toFixed(2);
489	}
490	
491	public function follow(thisentity:Stage3dEntity):void
492	{
493		following = thisentity;
494	}
495	
496	// create an exact duplicate in the game world
497	// whle re-using all Stage3d objects
498	public function clone():Stage3dEntity
499	{
500        if(_transformNeedsUpdate)
501            updateTransformFromValues();
502		var myclone:Stage3dEntity = new Stage3dEntity();
503		myclone.transform = this.transform.clone();
504		myclone.mesh = this.mesh;
505		myclone.texture = this.texture;
506		myclone.shader = this.shader;
507		myclone.vertexBuffer = this.vertexBuffer;
508		myclone.indexBuffer = this.indexBuffer;
509		myclone.context = this.context;
510		myclone.polycount = this.polycount;
511		myclone.shaderUsesNormals = this.shaderUsesNormals;
512		myclone.shaderUsesRgba = this.shaderUsesRgba;
513		myclone.shaderUsesUV = this.shaderUsesUV;
514		myclone.updateValuesFromTransform();
515		return myclone;
516	}
517	
518	// optimization: reuse the same temporary matrix
519	private var _rendermatrix:Matrix3D = new Matrix3D();
520	// renders the entity, changing states only if required
521	public function render(
522		view:Matrix3D,
523		projection:Matrix3D,
524		statechanged:Boolean = true):void
525	{
526		// used only for debugging:
527		if (!mesh) trace("Missing mesh!");
528		if (!context) trace("Missing context!");
529		if (!shader) trace("Missing shader!");
530		
531		// only render if these are set
532		if (!mesh) return;
533		if (!context) return;
534		if (!shader) return;
535
536		_rendermatrix.identity();
537		_rendermatrix.append(transform);
538		if (following) _rendermatrix.append(following.transform);
539		_rendermatrix.append(view);
540		_rendermatrix.append(projection);
541		
542		// Set the vertex program register vc0 to our
543		// model view projection matrix = vc0
544		context.setProgramConstantsFromMatrix(
545			Context3DProgramType.VERTEX, 0, _rendermatrix, true);
546			
547		// optimization: only change render state
548		// if the previously rendered actor is not
549		// using an identical mesh/shader as the current one
550		if (statechanged)
551		{
552			// Set the AGAL program
553			context.setProgram(shader);
554			
555			// Set the fragment program register ts0 to a texture
556			if (texture) context.setTextureAt(0,texture);
557
558			// position (va0)
559			context.setVertexBufferAt(0, mesh.positionsBuffer, 
560				0, Context3DVertexBufferFormat.FLOAT_3);
561			
562			// tex coord (va1)
563			if (shaderUsesUV)
564				context.setVertexBufferAt(1, mesh.uvBuffer, 
565				0, Context3DVertexBufferFormat.FLOAT_2);
566			else
567				context.setVertexBufferAt(1, null);
568			
569			// vertex rgba (va2)
570			if (shaderUsesRgba)
571				context.setVertexBufferAt(2, mesh.colorsBuffer, 
572				0, Context3DVertexBufferFormat.FLOAT_4);
573			else
574				context.setVertexBufferAt(2, null);
575		
576			// vertex normal (va3)
577			if (shaderUsesNormals)
578				context.setVertexBufferAt(3, mesh.normalsBuffer, 
579				0, Context3DVertexBufferFormat.FLOAT_3);
580			else
581				context.setVertexBufferAt(3, null);
582			
583			context.setBlendFactors(blendSrc, blendDst);
584			context.setDepthTest(depthTest,depthTestMode);
585			context.setCulling(cullingMode);
586			context.setColorMask(true, true, true, depthDraw);
587		}
588		
589		// render it
590		context.drawTriangles(mesh.indexBuffer, 
591			0, mesh.indexBufferCount);		
592
593	}
594	
595} // end class
596} // end package