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