[Sandy] [sandy commit] r661 - in trunk/sandy/as3/trunk/src/sandy: parser primitive

codesite-noreply at google.com codesite-noreply at google.com
Tue Jun 3 02:40:48 PDT 2008


Author: makc.the.great
Date: Tue Jun  3 02:39:42 2008
New Revision: 661

Added:
   trunk/sandy/as3/trunk/src/sandy/parser/MD2Parser.as
   trunk/sandy/as3/trunk/src/sandy/primitive/MD2.as
Modified:
   trunk/sandy/as3/trunk/src/sandy/parser/Parser.as

Log:
1st vworking version of MD2 parser and primitive

Added: trunk/sandy/as3/trunk/src/sandy/parser/MD2Parser.as
==============================================================================
--- (empty file)
+++ trunk/sandy/as3/trunk/src/sandy/parser/MD2Parser.as	Tue Jun  3 02:39:42 2008
@@ -0,0 +1,86 @@
+/*
+# ***** 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 *****
+*/
+
+package sandy.parser
+{
+	import flash.events.Event;
+	import flash.net.URLLoaderDataFormat;
+	import flash.utils.ByteArray;
+
+	import sandy.materials.Appearance;
+	import sandy.primitive.MD2;
+
+	/**
+	 * Transforms an MD2 file into Sandy MD2 primitive.
+	 * <p>Creates a Group as rootnode with MD2 primitive as its only child.
+	 *
+	 * @author		makc
+	 * @version		3.0.3
+	 * @date 		03.06.2008
+	 *
+	 * @example To parse an MD2 file at runtime:
+	 *
+	 * <listing version="3.0">
+	 *     var parser:IParser = Parser.create( "/path/to/my/md2file.md2", Parser.MD2 );
+	 * </listing>
+	 *
+	 * @example To parse an embedded MD2 object:
+	 *
+	 * <listing version="3.0">
+	 *     [Embed( source="/path/to/my/md2file.md2", mimeType="application/octet-stream" )]
+	 *     private var MyMD2:Class;
+	 *
+	 *     ...
+	 *
+	 *     var parser:IParser = Parser.create( new MyMD2(), Parser.MD2 );
+	 * </listing>
+	 */
+
+	public final class MD2Parser extends AParser implements IParser
+	{
+		/**
+		 * Creates a new MD2Parser instance
+		 *
+		 * @param p_sUrl		This can be either a String containing an URL or a
+		 * 						an embedded object
+		 * @param p_nScale		The scale factor
+		 */
+		public function MD2Parser( p_sUrl:*, p_nScale:Number )
+		{
+			super( p_sUrl, p_nScale );
+			m_sDataFormat = URLLoaderDataFormat.BINARY;
+		}
+
+		/**
+		 * @private
+		 * Starts the parsing process
+		 *
+		 * @param e				The Event object
+		 */
+		protected override function parseData( e:Event=null ):void
+		{
+			super.parseData( e );
+			// make MD2 object
+			var md2:MD2 = new MD2 ( "animation", ByteArray( m_oFile ), m_nScale );
+			// we are not quite done yet, so we dispatch less than 100% :)
+			var event:ParserEvent = new ParserEvent( ParserEvent.PARSING ); event.percent = 80; dispatchEvent( event );
+			// --
+			md2.appearance = m_oStandardAppearance; m_oGroup.addChild( md2 );
+			// -- Parsing is finished
+			var l_eOnInit:ParserEvent = new ParserEvent( ParserEvent.INIT ); l_eOnInit.group = m_oGroup; dispatchEvent( l_eOnInit );
+		}
+	}
+}

Modified: trunk/sandy/as3/trunk/src/sandy/parser/Parser.as
==============================================================================
--- trunk/sandy/as3/trunk/src/sandy/parser/Parser.as	(original)
+++ trunk/sandy/as3/trunk/src/sandy/parser/Parser.as	Tue Jun  3 02:39:42 2008
@@ -74,6 +74,10 @@
 		 */
 		public static const ASE:String = "ASE";
 		/**
+		 * Specifies that the MD2 (Quake II model) parser should be used.
+		 */
+		public static const MD2:String = "MD2";
+		/**
 		 * Specifies that the 3DS (3D Studio) parser should be used.
 		 */
 		public static const MAX_3DS:String = "3DS";
@@ -116,6 +120,9 @@
 			{
 				case "ASE":
 					l_iParser = new ASEParser( p_sFile, p_nScale );
+					break;
+				case "MD2":
+					l_iParser = new MD2Parser( p_sFile, p_nScale );
 					break;
 				case "OBJ":
 					break;

Added: trunk/sandy/as3/trunk/src/sandy/primitive/MD2.as
==============================================================================
--- (empty file)
+++ trunk/sandy/as3/trunk/src/sandy/primitive/MD2.as	Tue Jun  3 02:39:42 2008
@@ -0,0 +1,217 @@
+package sandy.primitive
+{
+	import flash.utils.ByteArray;
+	import flash.utils.Endian;
+
+	import sandy.core.data.*;
+	import sandy.core.scenegraph.Geometry3D;
+	import sandy.core.scenegraph.Shape3D;
+	import sandy.primitive.Primitive3D;
+
+	/**
+	* MD2 primitive.
+	* 
+	* @author Philippe Ajoux (philippe.ajoux at gmail.com)
+	*/
+	public class MD2 extends Shape3D implements Primitive3D
+	{
+		/**
+		* Creates MD2 primitive.
+		*
+		* @param p_sName Shape instance name.
+		* @param data MD2 binary data.
+		* @param scale Adjusts model scale.
+		*/
+		public function MD2 ( p_sName:String, data:ByteArray, scale:Number = 1 )
+		{
+			super (p_sName); scaling = scale; geometry = generate (data); frame = 0;
+		}
+
+		/**
+		* Generates the geometry for MD2. Sandy never actually calls this method,
+		* but we still implement it according to Primitive3D, just in case :)
+		*
+		* @return The geometry object.
+		*/
+		public function generate (... arguments):Geometry3D
+		{
+			var i:int, j:int;
+			var uvs:Array = [];
+			var mesh:Geometry3D = new Geometry3D ();
+
+			// okay, let's read out header 1st
+			var data:ByteArray = ByteArray (arguments [0]);
+			data.endian = Endian.LITTLE_ENDIAN;
+
+			ident = data.readInt();
+			version = data.readInt();
+
+			if (ident != 844121161 || version != 8)
+				throw new Error("Error loading MD2 file: Not a valid MD2 file/bad version");
+
+			skinwidth = data.readInt();
+			skinheight = data.readInt();
+			framesize = data.readInt();
+			num_skins = data.readInt();
+			num_vertices = data.readInt();
+			num_st = data.readInt();
+			num_tris = data.readInt();
+			num_glcmds = data.readInt();
+			num_frames = data.readInt();
+			offset_skins = data.readInt();
+			offset_st = data.readInt();
+			offset_tris = data.readInt();
+			offset_frames = data.readInt();
+			offset_glcmds = data.readInt();
+			offset_end = data.readInt();
+
+			// UV coordinates
+			data.position = offset_st;
+			for (i = 0; i < num_st; i++)
+				uvs.push (new UVCoord (data.readShort() / skinwidth, data.readShort() / skinheight ));
+
+			// Faces
+			data.position = offset_tris;
+			for (i = 0, j = 0; i < num_tris; i++, j+=3)
+			{
+				var a:int = data.readUnsignedShort();
+				var b:int = data.readUnsignedShort();
+				var c:int = data.readUnsignedShort();
+				var ta:int = data.readUnsignedShort();
+				var tb:int = data.readUnsignedShort();
+				var tc:int = data.readUnsignedShort();
+
+				// create placeholder vertices (actual coordinates are set later)
+				mesh.setVertex (a, 1, 0, 0);
+				mesh.setVertex (b, 0, 1, 0);
+				mesh.setVertex (c, 0, 0, 1);
+
+				mesh.setUVCoords (j, uvs [ta].u, uvs [ta].v);
+				mesh.setUVCoords (j + 1, uvs [tb].u, uvs [tb].v);
+				mesh.setUVCoords (j + 2, uvs [tc].u, uvs [tc].v);
+
+				mesh.setFaceVertexIds (i, a, b, c);
+				mesh.setFaceUVCoordsIds (i, j, j + 1, j + 2);
+			}
+
+			// Frame animation data
+			for (i = 0; i < num_frames; i++)
+			{
+				var sx:Number = data.readFloat();
+				var sy:Number = data.readFloat();
+				var sz:Number = data.readFloat();
+				
+				var tx:Number = data.readFloat();
+				var ty:Number = data.readFloat();
+				var tz:Number = data.readFloat();
+
+				// store frame names as pointers to frame numbers
+				var name:String = "", wasNotZero:Boolean = true;
+				for (j = 0; j < 16; j++)
+				{
+					var char:int = data.readUnsignedByte ();
+					wasNotZero &&= (char != 0);
+					if (wasNotZero)
+						name += String.fromCharCode (char);
+				}
+				frames [name] = i;
+
+				// store vertices for every frame
+				var vi:Array = [];
+				vertices [i] = vi;
+				for (j = 0; j < num_vertices; j++)
+				{
+					var vec:Vector = new Vector ();
+
+					// order of assignment is important here because of data reads...
+					vec.x = ((sx * data.readUnsignedByte()) + tx) * scaling;
+					vec.z = ((sy * data.readUnsignedByte()) + ty) * scaling;
+					vec.y = ((sz * data.readUnsignedByte()) + tz) * scaling;
+
+					vi [j] = vec;
+
+					// ignore "vertex normal index"
+					data.readUnsignedByte ();
+				}
+			}
+
+			return mesh;
+		}
+
+		/**
+		* Frames map. This maps frame names to frame numbers.
+		*/
+		public var frames:Array = [];
+
+		/**
+		* Frame number. You can tween this value to play MD2 animation.
+		*/
+		public function get frame ():Number { return t; }
+
+		/**
+		* @private (setter)
+		*/
+		public function set frame (value:Number):void
+		{
+			t = value;
+
+			// interpolation frames
+			var f1:Array = vertices [int (t) % num_frames];
+			var f2:Array = vertices [(int (t) + 1) % num_frames];
+
+			// interpolation coef-s
+			var c2:Number = t - int (t), c1:Number = 1 - c2;
+
+			// loop through vertices
+			for (var i:int = 0; i < num_vertices; i++)
+			{
+				var v0:Vertex = Vertex (geometry.aVertex [i]);
+				var v1:Vector = Vector (f1 [i]);
+				var v2:Vector = Vector (f2 [i]);
+
+				// interpolate
+				v0.x = v1.x * c1 + v2.x * c2; v0.wx = v0.x;
+				v0.y = v1.y * c1 + v2.y * c2; v0.wy = v0.y;
+				v0.z = v1.z * c1 + v2.z * c2; v0.wz = v0.z;
+			}
+
+			// update face normals
+			for each (var l_oPoly:Polygon in aPolygons)
+			{
+				v.x = l_oPoly.b.x - l_oPoly.a.x; v.y = l_oPoly.b.y - l_oPoly.a.y; v.z = l_oPoly.b.z - l_oPoly.a.z;
+				w.x = l_oPoly.b.x - l_oPoly.c.x; w.y = l_oPoly.b.y - l_oPoly.c.y; w.z = l_oPoly.b.z - l_oPoly.c.z;
+				w.crossWith (v); w.normalize ();
+				l_oPoly.normal.x = w.x; l_oPoly.normal.y = w.y; l_oPoly.normal.z = w.z;
+			}
+		}
+
+		// animation "time" (frame number)
+		private var t:Number;		
+
+		// vertices list for every frame
+		private var vertices:Array = [];
+
+		// vars for quick normal computation
+		private var v:Vector = new Vector (), w:Vector = new Vector ();
+
+		// original Philippe vars
+		private var ident:int;
+		private var version:int;
+		private var skinwidth:int;
+		private var skinheight:int;
+		private var framesize:int;
+		private var num_skins:int;
+		private var num_vertices:int;
+		private var num_st:int;
+		private var num_tris:int;
+		private var num_glcmds:int;
+		private var num_frames:int;
+		private var offset_skins:int;
+		private var offset_st:int;
+		private var offset_tris:int;
+		private var offset_frames:int;
+		private var offset_glcmds:int;
+		private var offset_end:int;
+		private var scaling:Number;
+	}
+}
\ No newline at end of file



More information about the Sandy mailing list