/src/Stage3dGame5.as

https://bitbucket.org/HopeSky/mars_nd2d · ActionScript · 543 lines · 364 code · 60 blank · 119 comment · 23 complexity · 6969721079e752bfd7781139dca6816e MD5 · raw file

  1. //
  2. // Stage3D Game Template - Chapter Five
  3. //
  4. package
  5. {
  6. [SWF(width="640", height="480", frameRate="60",
  7. backgroundColor="#FFFFFF")]
  8. import com.adobe.utils.*;
  9. import flash.display.*;
  10. import flash.display3D.*;
  11. import flash.display3D.textures.*;
  12. import flash.events.*;
  13. import flash.geom.*;
  14. import flash.utils.*;
  15. import flash.text.*;
  16. public class Stage3dGame5 extends Sprite
  17. {
  18. // used by the GUI
  19. private var fpsLast:uint = getTimer();
  20. private var fpsTicks:uint = 0;
  21. private var fpsTf:TextField;
  22. private var scoreTf:TextField;
  23. private var score:uint = 0;
  24. // constants used during inits
  25. private const swfWidth:int = 640;
  26. private const swfHeight:int = 480;
  27. // for this demo, ensure ALL textures are 512x512
  28. private const textureSize:int = 512;
  29. // the 3d graphics window on the stage
  30. private var context3D:Context3D;
  31. // the compiled shaders used to render our mesh
  32. private var shaderProgram1:Program3D;
  33. private var shaderProgram2:Program3D;
  34. private var shaderProgram3:Program3D;
  35. private var shaderProgram4:Program3D;
  36. // matrices that affect the mesh location and camera angles
  37. private var projectionmatrix:PerspectiveMatrix3D =
  38. new PerspectiveMatrix3D();
  39. private var modelmatrix:Matrix3D = new Matrix3D();
  40. private var viewmatrix:Matrix3D = new Matrix3D();
  41. private var terrainviewmatrix:Matrix3D = new Matrix3D();
  42. private var modelViewProjection:Matrix3D = new Matrix3D();
  43. // a simple frame counter used for animation
  44. private var t:Number = 0;
  45. // a reusable loop counter
  46. private var looptemp:int = 0;
  47. /* TEXTURES: Pure AS3 and Flex version:
  48. * if you are using Adobe Flash CS5
  49. * comment out the following: */
  50. [Embed (source = "art/spaceship_texture.jpg")]
  51. private var myTextureBitmap:Class;
  52. private var myTextureData:Bitmap = new myTextureBitmap();
  53. [Embed (source = "art/terrain_texture.jpg")]
  54. private var terrainTextureBitmap:Class;
  55. private var terrainTextureData:Bitmap = new terrainTextureBitmap();
  56. /* TEXTURE: Flash CS5 version:
  57. * add the jpgs to your library (F11)
  58. * right click and edit the advanced properties
  59. * so it is exported for use in Actionscript
  60. * and call them myTextureBitmap and terrainTextureBitmap
  61. * if you are using Flex/FlashBuilder/FlashDevelop/FDT
  62. * comment out the following: */
  63. //private var myBitmapDataObject:myTextureBitmapData =
  64. // new myTextureBitmapData(textureSize, textureSize);
  65. //private var myTextureData:Bitmap =
  66. // new Bitmap(myBitmapDataObject);
  67. //private var terrainBitmapDataObject:terrainTextureBitmapData =
  68. // new terrainTextureBitmapData(textureSize, textureSize);
  69. //private var terrainTextureData:Bitmap =
  70. // new Bitmap(terrainBitmapDataObject);
  71. // The Stage3d Texture that uses the above myTextureData
  72. private var myTexture:Texture;
  73. private var terrainTexture:Texture;
  74. // The spaceship mesh data
  75. [Embed (source = "art/spaceship.obj",
  76. mimeType = "application/octet-stream")]
  77. private var myObjData:Class;
  78. private var myMesh:Stage3dObjParser;
  79. // The terrain mesh data
  80. [Embed (source = "art/terrain.obj",
  81. mimeType = "application/octet-stream")]
  82. private var terrainObjData:Class;
  83. private var terrainMesh:Stage3dObjParser;
  84. public function Stage3dGame5()
  85. {
  86. if (stage != null)
  87. init();
  88. else
  89. addEventListener(Event.ADDED_TO_STAGE, init);
  90. }
  91. private function init(e:Event = null):void
  92. {
  93. if (hasEventListener(Event.ADDED_TO_STAGE))
  94. removeEventListener(Event.ADDED_TO_STAGE, init);
  95. stage.scaleMode = StageScaleMode.NO_SCALE;
  96. stage.align = StageAlign.TOP_LEFT;
  97. // add some text labels
  98. initGUI();
  99. // and request a context3D from Stage3d
  100. stage.stage3Ds[0].addEventListener(
  101. Event.CONTEXT3D_CREATE, onContext3DCreate);
  102. stage.stage3Ds[0].requestContext3D();
  103. }
  104. private function updateScore():void
  105. {
  106. // for now, you earn points over time
  107. score++;
  108. // padded with zeroes
  109. if (score < 10) scoreTf.text = 'Score: 00000' + score;
  110. else if (score < 100) scoreTf.text = 'Score: 0000' + score;
  111. else if (score < 1000) scoreTf.text = 'Score: 000' + score;
  112. else if (score < 10000) scoreTf.text = 'Score: 00' + score;
  113. else if (score < 100000) scoreTf.text = 'Score: 0' + score;
  114. else scoreTf.text = 'Score: ' + score;
  115. }
  116. private function initGUI():void
  117. {
  118. // a text format descriptor used by all gui labels
  119. var myFormat:TextFormat = new TextFormat();
  120. myFormat.color = 0xFFFFFF;
  121. myFormat.size = 13;
  122. // create an FPSCounter that displays the framerate on screen
  123. fpsTf = new TextField();
  124. fpsTf.x = 0;
  125. fpsTf.y = 0;
  126. fpsTf.selectable = false;
  127. fpsTf.autoSize = TextFieldAutoSize.LEFT;
  128. fpsTf.defaultTextFormat = myFormat;
  129. fpsTf.text = "Initializing Stage3d...";
  130. addChild(fpsTf);
  131. // create a score display
  132. scoreTf = new TextField();
  133. scoreTf.x = 560;
  134. scoreTf.y = 0;
  135. scoreTf.selectable = false;
  136. scoreTf.autoSize = TextFieldAutoSize.LEFT;
  137. scoreTf.defaultTextFormat = myFormat;
  138. scoreTf.text = "000000";
  139. addChild(scoreTf);
  140. // add some labels to describe each shader
  141. var label1:TextField = new TextField();
  142. label1.x = 100;
  143. label1.y = 180;
  144. label1.selectable = false;
  145. label1.autoSize = TextFieldAutoSize.LEFT;
  146. label1.defaultTextFormat = myFormat;
  147. label1.text = "Shader 1: Textured";
  148. addChild(label1);
  149. var label2:TextField = new TextField();
  150. label2.x = 400;
  151. label2.y = 180;
  152. label2.selectable = false;
  153. label2.autoSize = TextFieldAutoSize.LEFT;
  154. label2.defaultTextFormat = myFormat;
  155. label2.text = "Shader 2: Vertex RGB";
  156. addChild(label2);
  157. var label3:TextField = new TextField();
  158. label3.x = 80;
  159. label3.y = 440;
  160. label3.selectable = false;
  161. label3.autoSize = TextFieldAutoSize.LEFT;
  162. label3.defaultTextFormat = myFormat;
  163. label3.text = "Shader 3: Vertex RGB + Textured";
  164. addChild(label3);
  165. var label4:TextField = new TextField();
  166. label4.x = 340;
  167. label4.y = 440;
  168. label4.selectable = false;
  169. label4.autoSize = TextFieldAutoSize.LEFT;
  170. label4.defaultTextFormat = myFormat;
  171. label4.text = "Shader 4: Textured + setProgramConstants";
  172. addChild(label4);
  173. }
  174. public function uploadTextureWithMipmaps(
  175. dest:Texture, src:BitmapData):void
  176. {
  177. var ws:int = src.width;
  178. var hs:int = src.height;
  179. var level:int = 0;
  180. var tmp:BitmapData;
  181. var transform:Matrix = new Matrix();
  182. var tmp2:BitmapData;
  183. tmp = new BitmapData( src.width, src.height, true, 0x00000000);
  184. while ( ws >= 1 && hs >= 1 )
  185. {
  186. tmp.draw(src, transform, null, null, null, true);
  187. dest.uploadFromBitmapData(tmp, level);
  188. transform.scale(0.5, 0.5);
  189. level++;
  190. ws >>= 1;
  191. hs >>= 1;
  192. if (hs && ws)
  193. {
  194. tmp.dispose();
  195. tmp = new BitmapData(ws, hs, true, 0x00000000);
  196. }
  197. }
  198. tmp.dispose();
  199. }
  200. private function onContext3DCreate(event:Event):void
  201. {
  202. // Remove existing frame handler. Note that a context
  203. // loss can occur at any time which will force you
  204. // to recreate all objects we create here.
  205. // A context loss occurs for instance if you hit
  206. // CTRL-ALT-DELETE on Windows.
  207. // It takes a while before a new context is available
  208. // hence removing the enterFrame handler is important!
  209. if (hasEventListener(Event.ENTER_FRAME))
  210. removeEventListener(Event.ENTER_FRAME,enterFrame);
  211. // Obtain the current context
  212. var t:Stage3D = event.target as Stage3D;
  213. context3D = t.context3D;
  214. if (context3D == null)
  215. {
  216. // Currently no 3d context is available (error!)
  217. return;
  218. }
  219. // Disabling error checking will drastically improve performance.
  220. // If set to true, Flash sends helpful error messages regarding
  221. // AGAL compilation errors, uninitialized program constants, etc.
  222. context3D.enableErrorChecking = true;
  223. // Initialize our mesh data
  224. initData();
  225. // The 3d back buffer size is in pixels (2=antialiased)
  226. context3D.configureBackBuffer(swfWidth, swfHeight, 2, true);
  227. // assemble all the shaders we need
  228. initShaders();
  229. myTexture = context3D.createTexture(
  230. textureSize, textureSize,
  231. Context3DTextureFormat.BGRA, false);
  232. uploadTextureWithMipmaps(
  233. myTexture, myTextureData.bitmapData);
  234. terrainTexture = context3D.createTexture(
  235. textureSize, textureSize,
  236. Context3DTextureFormat.BGRA, false);
  237. uploadTextureWithMipmaps(
  238. terrainTexture, terrainTextureData.bitmapData);
  239. // create projection matrix for our 3D scene
  240. projectionmatrix.identity();
  241. // 45 degrees FOV, 640/480 aspect ratio, 0.1=near, 100=far
  242. projectionmatrix.perspectiveFieldOfViewRH(
  243. 45.0, swfWidth / swfHeight, 0.01, 5000.0);
  244. // create a matrix that defines the camera location
  245. viewmatrix.identity();
  246. // move the camera back a little so we can see the mesh
  247. viewmatrix.appendTranslation(0,0,-3);
  248. // tilt the terrain a little so it is coming towards us
  249. terrainviewmatrix.identity();
  250. terrainviewmatrix.appendRotation(-60,Vector3D.X_AXIS);
  251. // start the render loop!
  252. addEventListener(Event.ENTER_FRAME,enterFrame);
  253. }
  254. // create four different shaders
  255. private function initShaders():void
  256. {
  257. // A simple vertex shader which does a 3D transformation
  258. // for simplicity, it is used by all four shaders
  259. var vertexShaderAssembler:AGALMiniAssembler =
  260. new AGALMiniAssembler();
  261. vertexShaderAssembler.assemble
  262. (
  263. Context3DProgramType.VERTEX,
  264. // 4x4 matrix multiply to get camera angle
  265. "m44 op, va0, vc0\n" +
  266. // tell fragment shader about XYZ
  267. "mov v0, va0\n" +
  268. // tell fragment shader about UV
  269. "mov v1, va1\n" +
  270. // tell fragment shader about RGBA
  271. "mov v2, va2\n"
  272. );
  273. // textured using UV coordinates
  274. var fragmentShaderAssembler1:AGALMiniAssembler
  275. = new AGALMiniAssembler();
  276. fragmentShaderAssembler1.assemble
  277. (
  278. Context3DProgramType.FRAGMENT,
  279. // grab the texture color from texture 0
  280. // and uv coordinates from varying register 1
  281. // and store the interpolated value in ft0
  282. "tex ft0, v1, fs0 <2d,linear,repeat,miplinear>\n"+
  283. // move this value to the output color
  284. "mov oc, ft0\n"
  285. );
  286. // no texture, RGBA from the vertex buffer data
  287. var fragmentShaderAssembler2:AGALMiniAssembler
  288. = new AGALMiniAssembler();
  289. fragmentShaderAssembler2.assemble
  290. (
  291. Context3DProgramType.FRAGMENT,
  292. // grab the color from the v2 register
  293. // which was set in the vertex program
  294. "sub ft0, v2, fc1\n" +
  295. "mov oc, v2\n"
  296. );
  297. // textured using UV coordinates AND colored by vertex RGB
  298. var fragmentShaderAssembler3:AGALMiniAssembler
  299. = new AGALMiniAssembler();
  300. fragmentShaderAssembler3.assemble
  301. (
  302. Context3DProgramType.FRAGMENT,
  303. // grab the texture color from texture 0
  304. // and uv coordinates from varying register 1
  305. "tex ft0, v1, fs0 <2d,linear,repeat,miplinear>\n" +
  306. // multiply by the value stored in v2 (the vertex rgb)
  307. "mul ft1, v2, ft0\n" +
  308. // move this value to the output color
  309. "mov oc, ft1\n"
  310. );
  311. // textured using UV coordinates and
  312. // tinted using a fragment constant
  313. var fragmentShaderAssembler4:AGALMiniAssembler
  314. = new AGALMiniAssembler();
  315. fragmentShaderAssembler4.assemble
  316. (
  317. Context3DProgramType.FRAGMENT,
  318. // grab the texture color from texture 0
  319. // and uv coordinates from varying register 1
  320. "tex ft0, v1, fs0 <2d,linear,repeat,miplinear>\n" +
  321. // multiply by the value stored in fc0
  322. "mul ft1, fc0, ft0\n" +
  323. // move this value to the output color
  324. "mov oc, ft1\n"
  325. );
  326. // combine shaders into a program which we then upload to the GPU
  327. shaderProgram1 = context3D.createProgram();
  328. shaderProgram1.upload(
  329. vertexShaderAssembler.agalcode,
  330. fragmentShaderAssembler1.agalcode);
  331. shaderProgram2 = context3D.createProgram();
  332. shaderProgram2.upload(
  333. vertexShaderAssembler.agalcode,
  334. fragmentShaderAssembler2.agalcode);
  335. shaderProgram3 = context3D.createProgram();
  336. shaderProgram3.upload(
  337. vertexShaderAssembler.agalcode,
  338. fragmentShaderAssembler3.agalcode);
  339. shaderProgram4 = context3D.createProgram();
  340. shaderProgram4.upload(
  341. vertexShaderAssembler.agalcode,
  342. fragmentShaderAssembler4.agalcode);
  343. }
  344. private function initData():void
  345. {
  346. // parse the OBJ file and create buffers
  347. myMesh = new Stage3dObjParser(
  348. myObjData, context3D, 1, true, true);
  349. // parse the terrain mesh as well
  350. terrainMesh = new Stage3dObjParser(
  351. terrainObjData, context3D, 1, true, true);
  352. }
  353. private function renderTerrain():void
  354. {
  355. context3D.setTextureAt(0, terrainTexture);
  356. // simple textured shader
  357. context3D.setProgram ( shaderProgram1 );
  358. // position
  359. context3D.setVertexBufferAt(0, terrainMesh.positionsBuffer,
  360. 0, Context3DVertexBufferFormat.FLOAT_3);
  361. // tex coord
  362. context3D.setVertexBufferAt(1, terrainMesh.uvBuffer,
  363. 0, Context3DVertexBufferFormat.FLOAT_2);
  364. // vertex rgba
  365. context3D.setVertexBufferAt(2, terrainMesh.colorsBuffer,
  366. 0, Context3DVertexBufferFormat.FLOAT_4);
  367. // set up camera angle
  368. modelmatrix.identity();
  369. // make the terrain face the right way
  370. modelmatrix.appendRotation( -90, Vector3D.Y_AXIS);
  371. // slowly move the terrain around
  372. modelmatrix.appendTranslation(
  373. Math.cos(t/300)*1000,Math.cos(t/200)*1000 + 500,-130);
  374. // clear the matrix and append new angles
  375. modelViewProjection.identity();
  376. modelViewProjection.append(modelmatrix);
  377. modelViewProjection.append(terrainviewmatrix);
  378. modelViewProjection.append(projectionmatrix);
  379. // pass our matrix data to the shader program
  380. context3D.setProgramConstantsFromMatrix(
  381. Context3DProgramType.VERTEX,
  382. 0, modelViewProjection, true );
  383. context3D.drawTriangles(terrainMesh.indexBuffer,
  384. 0, terrainMesh.indexBufferCount);
  385. }
  386. private function enterFrame(e:Event):void
  387. {
  388. // clear scene before rendering is mandatory
  389. context3D.clear(0,0,0);
  390. // move or rotate more each frame
  391. t += 2.0;
  392. // scroll and render the terrain once
  393. renderTerrain();
  394. // how far apart each of the 4 spaceships is
  395. var dist:Number = 0.8;
  396. // loop through each mesh we want to draw
  397. for (looptemp = 0; looptemp < 4; looptemp++)
  398. {
  399. // clear the transformation matrix to 0,0,0
  400. modelmatrix.identity();
  401. // each mesh has a different texture,
  402. // shader, position and spin speed
  403. switch(looptemp)
  404. {
  405. case 0:
  406. context3D.setTextureAt(0, myTexture);
  407. context3D.setProgram ( shaderProgram1 );
  408. modelmatrix.appendRotation(t*0.7, Vector3D.Y_AXIS);
  409. modelmatrix.appendRotation(t*0.6, Vector3D.X_AXIS);
  410. modelmatrix.appendRotation(t*1.0, Vector3D.Y_AXIS);
  411. modelmatrix.appendTranslation(-dist, dist, 0);
  412. break;
  413. case 1:
  414. context3D.setTextureAt(0, null);
  415. context3D.setProgram ( shaderProgram2 );
  416. modelmatrix.appendRotation(t*-0.2, Vector3D.Y_AXIS);
  417. modelmatrix.appendRotation(t*0.4, Vector3D.X_AXIS);
  418. modelmatrix.appendRotation(t*0.7, Vector3D.Y_AXIS);
  419. modelmatrix.appendTranslation(dist, dist, 0);
  420. break;
  421. case 2:
  422. context3D.setTextureAt(0, myTexture);
  423. context3D.setProgram ( shaderProgram3 );
  424. modelmatrix.appendRotation(t*1.0, Vector3D.Y_AXIS);
  425. modelmatrix.appendRotation(t*-0.2, Vector3D.X_AXIS);
  426. modelmatrix.appendRotation(t*0.3, Vector3D.Y_AXIS);
  427. modelmatrix.appendTranslation(-dist, -dist, 0);
  428. break;
  429. case 3:
  430. context3D.setProgramConstantsFromVector(
  431. Context3DProgramType.FRAGMENT, 0, Vector.<Number>
  432. ([ 1, Math.abs(Math.cos(t/50)), 0, 1 ]) );
  433. context3D.setTextureAt(0, myTexture);
  434. context3D.setProgram ( shaderProgram4 );
  435. modelmatrix.appendRotation(t*0.3, Vector3D.Y_AXIS);
  436. modelmatrix.appendRotation(t*0.3, Vector3D.X_AXIS);
  437. modelmatrix.appendRotation(t*-0.3, Vector3D.Y_AXIS);
  438. modelmatrix.appendTranslation(dist, -dist, 0);
  439. break;
  440. }
  441. // clear the matrix and append new angles
  442. modelViewProjection.identity();
  443. modelViewProjection.append(modelmatrix);
  444. modelViewProjection.append(viewmatrix);
  445. modelViewProjection.append(projectionmatrix);
  446. // pass our matrix data to the shader program
  447. context3D.setProgramConstantsFromMatrix(
  448. Context3DProgramType.VERTEX,
  449. 0, modelViewProjection, true );
  450. // draw a spaceship mesh
  451. // position
  452. context3D.setVertexBufferAt(0, myMesh.positionsBuffer,
  453. 0, Context3DVertexBufferFormat.FLOAT_3);
  454. // tex coord
  455. context3D.setVertexBufferAt(1, myMesh.uvBuffer,
  456. 0, Context3DVertexBufferFormat.FLOAT_2);
  457. // vertex rgba
  458. context3D.setVertexBufferAt(2, myMesh.colorsBuffer,
  459. 0, Context3DVertexBufferFormat.FLOAT_4);
  460. // render it
  461. context3D.drawTriangles(myMesh.indexBuffer,
  462. 0, myMesh.indexBufferCount);
  463. }
  464. // present/flip back buffer
  465. // now that all meshes have been drawn
  466. context3D.present();
  467. // update the FPS display
  468. fpsTicks++;
  469. var now:uint = getTimer();
  470. var delta:uint = now - fpsLast;
  471. // only update the display once a second
  472. if (delta >= 1000)
  473. {
  474. var fps:Number = fpsTicks / delta * 1000;
  475. fpsTf.text = fps.toFixed(1) + " fps";
  476. fpsTicks = 0;
  477. fpsLast = now;
  478. }
  479. // update the rest of the GUI
  480. updateScore();
  481. }
  482. } // end of class
  483. } // end of package