PageRenderTime 46ms CodeModel.GetById 23ms app.highlight 18ms RepoModel.GetById 0ms app.codeStats 0ms

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