瀏覽代碼

Merge branch 'awdloader' of https://github.com/plepers/three.js into dev

Mr.doob 11 年之前
父節點
當前提交
6fb7a3780c
共有 4 個文件被更改,包括 1378 次插入0 次删除
  1. 1225 0
      examples/js/loaders/AWDLoader.js
  2. 二進制
      examples/models/awd/simple/simple.awd
  3. 二進制
      examples/models/awd/simple/textures/texture.jpg
  4. 153 0
      examples/webgl_loader_awd.html

+ 1225 - 0
examples/js/loaders/AWDLoader.js

@@ -0,0 +1,1225 @@
+/**
+ * Author: Pierre Lepers
+ * Date: 09/12/2013 17:21
+ */
+
+THREE.AWDLoader = (function (){
+
+
+
+  var UNCOMPRESSED  = 0,
+      DEFLATE       = 1,
+      LZMA          = 2,
+
+      AWD_FIELD_INT8      = 1,
+      AWD_FIELD_INT16     = 2,
+      AWD_FIELD_INT32     = 3,
+      AWD_FIELD_UINT8     = 4,
+      AWD_FIELD_UINT16    = 5,
+      AWD_FIELD_UINT32    = 6,
+      AWD_FIELD_FLOAT32   = 7,
+      AWD_FIELD_FLOAT64   = 8,
+      AWD_FIELD_BOOL      = 21,
+      AWD_FIELD_COLOR     = 22,
+      AWD_FIELD_BADDR     = 23,
+      AWD_FIELD_STRING    = 31,
+      AWD_FIELD_BYTEARRAY = 32,
+      AWD_FIELD_VECTOR2x1 = 41,
+      AWD_FIELD_VECTOR3x1 = 42,
+      AWD_FIELD_VECTOR4x1 = 43,
+      AWD_FIELD_MTX3x2    = 44,
+      AWD_FIELD_MTX3x3    = 45,
+      AWD_FIELD_MTX4x3    = 46,
+      AWD_FIELD_MTX4x4    = 47,
+
+      BOOL       = 21,
+      COLOR      = 22,
+      BADDR      = 23,
+
+      INT8    = 1,
+      INT16   = 2,
+      INT32   = 3,
+      UINT8   = 4,
+      UINT16  = 5,
+      UINT32  = 6,
+      FLOAT32 = 7,
+      FLOAT64 = 8;
+
+
+  var littleEndian = true;
+
+  // ResourcesLoader
+  // =============
+  // handle loading for external resources
+  function ResourcesLoader( awdUrl ){
+
+    this._baseDir = awdUrl.substr( 0, awdUrl.lastIndexOf( '/' )+1 );
+
+    this._loadingManager = new THREE.LoadingManager();
+
+  }
+
+  ResourcesLoader.prototype = {
+
+    loadTexture : function( path ){
+      var tex = new THREE.Texture();
+
+      var loader = new THREE.ImageLoader( this._loadingManager );
+
+      loader.load( this._baseDir+path, function( image ) {
+        tex.image = image;
+        tex.needsUpdate = true;
+      });
+
+      return tex;
+
+    }
+  }
+
+
+
+  function Block(){
+    this.id = 0;
+    this.data = null;
+  }
+
+
+
+  function AWDLoader( showStatus ) {
+
+    THREE.Loader.call( this, showStatus );
+
+    this.trunk = new THREE.Object3D();
+
+    this.materialFactory = undefined;
+
+    this._resourceLoader = null;
+    this._url = null;
+
+    this._data;
+    this._ptr = 0;
+
+    this._version =  [];
+    this._streaming = false;
+    this._optimized_for_accuracy = false;
+    this._compression = 0;
+    this._bodylen = 0xFFFFFFFF;
+
+
+    this._blocks = [ new Block() ];
+
+    this._accuracyMatrix  = false;
+    this._accuracyGeo     = false;
+    this._accuracyProps   = false;
+
+
+  };
+
+
+  AWDLoader.prototype = new THREE.Loader();
+
+  AWDLoader.prototype.constructor = AWDLoader;
+
+  AWDLoader.prototype.load = function ( url, callback ) {
+
+    var that = this;
+    this._url = url;
+    var xhr = new XMLHttpRequest();
+    xhr.open( "GET", url, true );
+    xhr.responseType = 'arraybuffer';
+
+    xhr.onreadystatechange = function () {
+
+      if ( xhr.readyState == 4 ) {
+
+        if ( xhr.status == 200 || xhr.status == 0 ) {
+          that.parse( xhr.response );
+          callback( that.trunk );
+
+        } else {
+
+          console.error( 'AWDLoader: Couldn\'t load ' + url + ' (' + xhr.status + ')' );
+
+        }
+
+      }
+
+    };
+
+    xhr.send( null );
+
+  };
+
+  AWDLoader.prototype.parse = function ( data ) {
+
+    var blen = data.byteLength;
+
+    this._ptr = 0;
+    this._data = new DataView( data );
+
+    this._parseHeader( );
+
+    if( this._compression != 0  ) {
+      console.error( 'compressed AWD not supported' );
+    }
+
+    if (!this._streaming && this._bodylen != data.byteLength - this._ptr ) {
+      console.error('AWDLoader: body len does not match file length', this._bodylen ,  blen - this._ptr);
+    }
+
+    while ( this._ptr < blen ) {
+      this.parseNextBlock();
+    }
+
+  }
+
+
+
+  AWDLoader.prototype.parseNextBlock = function ( ) {
+
+    var assetData,
+        ns, type, len, block,
+        blockId = this.readU32(),
+        ns      = this.readU8(),
+        type    = this.readU8(),
+        flags   = this.readU8(),
+        len     = this.readU32();
+
+
+    switch (type) {
+      case 1:
+        assetData = this.parseMeshData(len);
+        break;
+      case 22:
+        assetData = this.parseContainer(len);
+        break;
+      case 23:
+        assetData = this.parseMeshInstance(len);
+        break;
+      case 81:
+        assetData = this.parseMaterial(len);
+        break;
+      case 82:
+        assetData = this.parseTexture(len);
+        break;
+      case 101:
+        assetData = this.parseSkeleton(len);
+        break;
+
+//      case 111:
+//        assetData = this.parseMeshPoseAnimation(len, true);
+//        break;
+      case 112:
+        assetData = this.parseMeshPoseAnimation(len, false);
+        break;
+      case 113:
+        assetData = this.parseVertexAnimationSet(len);
+        break;
+      case 102:
+      	assetData = this.parseSkeletonPose(len);
+      	break;
+      case 103:
+      	assetData = this.parseSkeletonAnimation(len);
+      	break;
+      case 122:
+        assetData = this.parseAnimatorSet(len);
+        break;
+      // case 121:
+      // 	assetData = parseUVAnimation(len);
+      // 	break;
+      default:
+        //debug('Ignoring block!',type, len);
+        this._ptr += len;
+        break;
+    }
+
+
+    // Store block reference for later use
+    this._blocks[blockId] = block = new Block();
+    block.data = assetData;
+    block.id = blockId;
+
+  }
+
+
+  AWDLoader.prototype._parseHeader = function () {
+
+    var version = this._version,
+        awdmagic =
+            ( this.readU8()<<16)
+        |   ( this.readU8()<<8 )
+        |     this.readU8();
+
+    if( awdmagic != 4282180 )
+      throw new Error( "AWDLoader - bad magic" );
+
+    version[0] = this.readU8();
+    version[1] = this.readU8();
+
+    var flags = this.readU16();
+
+    this._streaming = (flags & 0x1) == 0x1;
+
+    if ((version[0] === 2) && (version[1] === 1)) {
+      this._accuracyMatrix =  (flags & 0x2) === 0x2;
+      this._accuracyGeo =     (flags & 0x4) === 0x4;
+      this._accuracyProps =   (flags & 0x8) === 0x8;
+    }
+
+    this._geoNrType     = this._accuracyGeo     ? FLOAT64 : FLOAT32;
+    this._matrixNrType  = this._accuracyMatrix  ? FLOAT64 : FLOAT32;
+    this._propsNrType   = this._accuracyProps   ? FLOAT64 : FLOAT32;
+
+    this._optimized_for_accuracy 	= (flags & 0x2) === 0x2;
+
+    this._compression = this.readU8();
+    this._bodylen = this.readU32();
+
+
+  }
+
+
+  AWDLoader.prototype.parseContainer = function ( len ) {
+    var parent,
+        ctr     = new THREE.Object3D(),
+        par_id  = this.readU32(),
+        mtx     = this.parseMatrix4();
+
+    ctr.name = this.readUTF();
+    ctr.applyMatrix( mtx );
+
+    parent = this._blocks[par_id].data || this.trunk;
+    parent.add(ctr);
+
+    this.parseProperties({
+      1:this._matrixNrType,
+      2:this._matrixNrType,
+      3:this._matrixNrType,
+      4:UINT8
+    });
+
+    ctr.extra = this.parseUserAttributes();
+
+    return ctr;
+  }
+
+
+
+  AWDLoader.prototype.parseMeshInstance = function ( len ) {
+    var name,
+        mesh, geometries, meshLen, meshes,
+        par_id, data_id,
+        mtx,
+        materials, mat, mat_id,
+        num_materials,
+        materials_parsed,
+        parent,
+        i;
+
+    par_id        = this.readU32();
+    mtx           = this.parseMatrix4();
+    name          = this.readUTF();
+    data_id       = this.readU32();
+    num_materials = this.readU16();
+
+    geometries = this.getBlock( data_id );
+
+    materials = [];
+    materials_parsed = 0;
+
+    for ( i = 0; i < num_materials; i++) {
+      mat_id = this.readU32();
+      mat = this.getBlock( mat_id );
+      materials.push( mat );
+    }
+
+
+
+    meshLen = geometries.length
+    meshes = [];
+
+    // TODO : BufferGeometry don't support "geometryGroups" for now.
+    // so we create sub meshes for each groups
+    if( meshLen  > 1 ) {
+      mesh = new THREE.Object3D()
+      for ( i = 0; i < meshLen; i++) {
+        var sm = new THREE.Mesh( geometries[i] );
+        meshes.push( sm );
+        mesh.add( sm );
+      }
+    }
+    else {
+      mesh = new THREE.Mesh( geometries[0] );
+      meshes.push( mesh );
+    }
+
+    mesh.applyMatrix( mtx );
+    mesh.name = name;
+
+
+    parent = this.getBlock( par_id ) || this.trunk;
+    parent.add( mesh );
+
+
+    var matLen = materials.length;
+    var maxLen = Math.max( meshLen, matLen);
+    for( i = 0; i< maxLen; i++ )
+      meshes[ i%meshLen ].material = materials[ i % matLen ];
+
+
+    // Ignore for now
+    this.parseProperties( null );
+    mesh.extra = this.parseUserAttributes();
+
+    return mesh;
+  }
+
+
+
+  AWDLoader.prototype.parseMaterial = function ( len ) {
+    var name,
+        type,
+        props,
+        mat,
+        attributes,
+        finalize,
+        num_methods,
+        methods_parsed;
+
+    name        = this.readUTF();
+    type        = this.readU8();
+    num_methods = this.readU8();
+
+    //log( "AWDLoader parseMaterial ",name )
+
+    // Read material numerical properties
+    // (1=color, 2=bitmap url, 11=alpha_blending, 12=alpha_threshold, 13=repeat)
+    props = this.parseProperties({
+      1:  AWD_FIELD_INT32,
+      2:  AWD_FIELD_BADDR,
+      11: AWD_FIELD_BOOL,
+      12: AWD_FIELD_FLOAT32,
+      13: AWD_FIELD_BOOL
+    });
+
+    methods_parsed = 0;
+
+    while( methods_parsed < num_methods ) {
+      var method_type = this.readU16();
+      this.parseProperties( null );
+      this.parseUserAttributes();
+    }
+
+    attributes = this.parseUserAttributes();
+
+    if( this.materialFactory !== undefined ) {
+      mat = this.materialFactory( name );
+      if( mat ) return mat;
+    }
+
+    mat = new THREE.MeshPhongMaterial();
+
+    if (type === 1) { // Color material
+      mat.color.setHex( props.get(1, 0xcccccc) );
+    }
+    else if (type === 2) { // Bitmap material
+      var tex_addr = props.get(2, 0);
+      mat.map = this.getBlock( tex_addr );
+    }
+
+    mat.extra = attributes;
+    mat.alphaThreshold = props.get(12, 0.0);
+    mat.repeat = props.get(13, false);
+
+
+    return mat;
+  }
+
+
+
+
+  AWDLoader.prototype.parseTexture = function( len ) {
+
+
+    var name = this.readUTF(),
+        type = this.readU8(),
+        asset,
+        data_len;
+
+    // External
+    if (type === 0) {
+      data_len = this.readU32();
+      var url = this.readUTFBytes(data_len);
+      console.log( url );
+
+      asset = this.loadTexture( url );
+    } else {
+      // embed texture not supported
+    }
+    // Ignore for now
+    this.parseProperties( null );
+
+    this.parseUserAttributes();
+    return asset;
+  }
+
+  AWDLoader.prototype.loadTexture = function( url ) {
+
+    if( null === this._resourceLoader )
+      this._resourceLoader = new ResourcesLoader( this._url );
+
+    return this._resourceLoader.loadTexture( url );
+  }
+
+  // broken : skeleton pose format is different than threejs one
+  AWDLoader.prototype.parseSkeleton = function(len) // Array<Bone>
+  {
+    var name          = this.readUTF(),
+        num_joints    = this.readU16(),
+        skeleton      = [],
+        joints_parsed = 0;
+
+    this.parseProperties( null );
+
+    while (joints_parsed < num_joints) {
+      var joint, ibp;
+
+      // Ignore joint id
+      this.readU16();
+
+      joint = new THREE.Bone();
+      joint.parent = this.readU16() - 1; // 0=null in AWD
+      joint.name = this.readUTF();
+
+      ibp = this.parseMatrix4();
+      joint.skinMatrix = ibp;
+
+      // Ignore joint props/attributes for now
+      this.parseProperties(null);
+      this.parseUserAttributes();
+
+      skeleton.push(joint);
+      joints_parsed++;
+    }
+
+    // Discard attributes for now
+    this.parseUserAttributes();
+
+
+    return skeleton;
+  }
+
+
+
+  AWDLoader.prototype.parseSkeletonPose = function(blockID)
+  {
+    var name = this.readUTF();
+
+
+    var num_joints = this.readU16();
+    this.parseProperties(null);
+
+    // debug( 'parse Skeleton Pose. joints : ' + num_joints);
+
+    var pose = [];
+
+    var joints_parsed = 0;
+
+    while (joints_parsed < num_joints) {
+
+      var joint_pose;
+
+      var has_transform; //:uint;
+      var mtx_data;
+
+      has_transform = this.readU8();
+
+      if (has_transform === 1) {
+        mtx_data = this.parseMatrix4();
+      } else
+      {
+        mtx_data = new THREE.Matrix4();
+      }
+      pose[joints_parsed] = mtx_data;
+      joints_parsed++;
+    }
+    // Skip attributes for now
+    this.parseUserAttributes();
+
+    return pose
+  }
+
+  AWDLoader.prototype.parseSkeletonAnimation = function(blockID)
+  {
+    var frame_dur;
+    var pose_addr;
+    var pose;
+
+    var name = this.readUTF();
+
+    var clip = [];
+
+    var num_frames = this.readU16();
+    this.parseProperties(null);
+
+    var frames_parsed = 0;
+    var returnedArray;
+
+
+    // debug( 'parse Skeleton Animation. frames : ' + num_frames);
+
+    while (frames_parsed < num_frames) {
+      pose_addr = this.readU32();
+      frame_dur = this.readU16();
+
+      pose = this._blocks[pose_addr].data
+      // debug( 'pose address ',pose[2].elements[12],pose[2].elements[13],pose[2].elements[14] );
+      clip.push( {
+        pose : pose,
+        duration : frame_dur
+      } );
+
+      frames_parsed++;
+    }
+    if (clip.length == 0) {
+      // debug("Could not this SkeletonClipNode, because no Frames where set.");
+      return;
+    }
+    // Ignore attributes for now
+    this.parseUserAttributes();
+    return clip;
+  }
+
+
+
+  AWDLoader.prototype.parseVertexAnimationSet = function(len)
+  {
+    var poseBlockAdress,
+        name           = this.readUTF(),
+        num_frames     = this.readU16(),
+        props          = this.parseProperties({1:UINT16}),
+        frames_parsed  = 0,
+        skeletonFrames = [];
+
+    while (frames_parsed < num_frames) {
+      poseBlockAdress = this.readU32();
+      skeletonFrames.push(this._blocks[poseBlockAdress].data);
+      frames_parsed++;
+    }
+
+    this.parseUserAttributes();
+
+
+    return skeletonFrames;
+  }
+
+
+  AWDLoader.prototype.parseAnimatorSet = function(len)
+  {
+    var targetMesh;
+
+    var animSetBlockAdress; //:int
+
+    var targetAnimationSet; //:AnimationSetBase;
+    var outputString = ""; //:String = "";
+    var name = this.readUTF();
+    var type = this.readU16();
+
+    var props = this.parseProperties({1:BADDR});
+
+    animSetBlockAdress = this.readU32();
+    var targetMeshLength = this.readU16();
+
+    var meshAdresses = []; //:Vector.<uint> = new Vector.<uint>;
+
+    for (var i = 0; i < targetMeshLength; i++)
+      meshAdresses.push( this.readU32() );
+
+    var activeState = this.readU16();
+    var autoplay = Boolean(this.readU8());
+    this.parseUserAttributes();
+    this.parseUserAttributes();
+
+    var returnedArray;
+    var targetMeshes = []; //:Vector.<Mesh> = new Vector.<Mesh>;
+
+    for (i = 0; i < meshAdresses.length; i++) {
+//      returnedArray = getAssetByID(meshAdresses[i], [AssetType.MESH]);
+//      if (returnedArray[0])
+        targetMeshes.push(this._blocks[meshAdresses[i]].data);
+    }
+
+    targetAnimationSet = this._blocks[animSetBlockAdress].data
+    var thisAnimator;
+
+    if (type == 1) {
+
+
+      thisAnimator = {
+        animationSet : targetAnimationSet,
+        skeleton : this._blocks[props.get(1, 0)].data
+      };
+
+    } else if (type == 2) {
+      // debug( "vertex Anim???");
+    }
+
+
+    for (i = 0; i < targetMeshes.length; i++) {
+        targetMeshes[i].animator = thisAnimator;
+    }
+    // debug("Parsed a Animator: Name = " + name);
+
+    return thisAnimator;
+  }
+
+
+
+
+
+
+
+  AWDLoader.prototype.parseMeshData = function ( len ) {
+
+    var name      = this.readUTF(),
+        num_subs  = this.readU16(),
+        geom,
+        subs_parsed = 0,
+        props,
+        buffer,
+        skinW, skinI,
+        geometries = [];
+
+
+
+
+    props = this.parseProperties({
+      1: this._geoNrType,
+      2: this._geoNrType
+    });
+
+
+
+    // Loop through sub meshes
+    while (subs_parsed < num_subs) {
+
+      var sm_len, sm_end, attrib;
+
+      geom = new THREE.BufferGeometry();
+      geom.name = name;
+      geometries.push( geom );
+
+
+      sm_len = this.readU32();
+      sm_end = this._ptr + sm_len;
+
+
+      // Ignore for now
+      this.parseProperties({1:this._geoNrType, 2:this._geoNrType});
+
+      // Loop through data streams
+      while ( this._ptr < sm_end ) {
+
+
+        var idx = 0,
+            str_type  = this.readU8(),
+            str_ftype = this.readU8(),
+            str_len   = this.readU32(),
+            str_end   = str_len + this._ptr;
+
+
+
+
+
+        // VERTICES
+        // ------------------
+        if ( str_type === 1 ) {
+
+          attrib = new THREE.Float32Attribute( str_len/12, 3 );
+          buffer = attrib.array;
+
+          geom.addAttribute( 'position', attrib );
+          idx = 0;
+
+          while (this._ptr < str_end) {
+            buffer[idx]   = -this.readF32();
+            buffer[idx+1] = this.readF32();
+            buffer[idx+2] = this.readF32();
+            idx+=3;
+          }
+        }
+
+
+        // INDICES
+        // -----------------
+        else if (str_type === 2) {
+
+          attrib = new THREE.Uint16Attribute( str_len/2, 1 );
+          geom.addAttribute( 'index', attrib );
+
+          geom.offsets.push({
+            start: 0,
+            index: 0,
+            count: str_len/2
+          });
+
+          buffer = attrib.array;
+          idx = 0;
+
+          while (this._ptr < str_end) {
+            buffer[idx+1]   = this.readU16();
+            buffer[idx]     = this.readU16();
+            buffer[idx+2]   = this.readU16();
+            idx+=3;
+          }
+        }
+
+        // UVS
+        // -------------------
+        else if (str_type === 3) {
+
+          attrib = new THREE.Float32Attribute( str_len/8, 2 );
+          buffer = attrib.array;
+
+          geom.addAttribute( 'uv', attrib );
+          idx = 0;
+
+          while (this._ptr < str_end) {
+            buffer[idx]   = this.readF32();
+            buffer[idx+1] = 1.0-this.readF32();
+            idx+=2;
+          }
+        }
+
+        // NORMALS
+        else if (str_type === 4) {
+
+          attrib = new THREE.Float32Attribute( str_len/12, 3 );
+          geom.addAttribute( 'normal', attrib );
+          buffer = attrib.array
+          idx = 0
+
+          while (this._ptr < str_end) {
+            buffer[idx]   = -this.readF32();
+            buffer[idx+1] = this.readF32();
+            buffer[idx+2] = this.readF32();
+            idx+=3;
+          }
+
+        }
+
+        // else if (str_type == 6) {
+        //   skinI = new Float32Array( str_len>>1 );
+        //   idx = 0
+
+        //   while (this._ptr < str_end) {
+        //     skinI[idx]   = this.readU16();
+        //     idx++;
+        //   }
+
+        // }
+        // else if (str_type == 7) {
+        //   skinW = new Float32Array( str_len>>2 );
+        //   idx = 0;
+
+        //   while (this._ptr < str_end) {
+        //     skinW[idx]   = this.readF32();
+        //     idx++;
+        //   }
+        // }
+        else {
+          this._ptr = str_end;
+        }
+
+
+
+      }
+
+      this.parseUserAttributes();
+
+
+      geom.computeBoundingSphere();
+      subs_parsed++;
+    }
+
+
+    //geom.computeFaceNormals();
+
+
+    this.parseUserAttributes();
+    //finalizeAsset(geom, name);
+
+    return geometries;
+  }
+
+  AWDLoader.prototype.parseMeshPoseAnimation = function(len, poseOnly)
+  {
+    var num_frames = 1,
+        num_submeshes,
+        frames_parsed,
+        subMeshParsed,
+        frame_dur,
+        x, y, z,
+
+        str_len,
+        str_end,
+        geom,
+        subGeom,
+        idx = 0,
+        clip = {},
+        indices,
+        verts,
+        num_Streams,
+        streamsParsed,
+        streamtypes = [],
+
+        props,
+        thisGeo,
+        name = this.readUTF(),
+        geoAdress = this.readU32();
+
+
+    var mesh = this.getBlock( geoAdress );
+
+    if (mesh == null) {
+      console.log( "parseMeshPoseAnimation target mesh not found at:", geoAdress );
+      return;
+    }
+
+    geom = mesh.geometry;
+    geom.morphTargets = [];
+
+    if (!poseOnly)
+      num_frames = this.readU16();
+
+    num_submeshes = this.readU16();
+    num_Streams = this.readU16();
+
+    // debug("VA num_frames : ", num_frames );
+    // debug("VA num_submeshes : ", num_submeshes );
+    // debug("VA numstreams : ", num_Streams );
+
+    streamsParsed = 0;
+    while (streamsParsed < num_Streams) {
+      streamtypes.push(this.readU16());
+      streamsParsed++;
+    }
+    props = this.parseProperties({1:BOOL, 2:BOOL});
+
+    clip.looping = props.get(1, true);
+    clip.stitchFinalFrame = props.get(2, false);
+
+    frames_parsed = 0;
+
+    while (frames_parsed < num_frames) {
+
+      frame_dur = this.readU16();
+      subMeshParsed = 0;
+
+      while (subMeshParsed < num_submeshes) {
+
+        streamsParsed = 0;
+        str_len = this.readU32();
+        str_end = this._ptr + str_len;
+
+        while (streamsParsed < num_Streams) {
+
+          if (streamtypes[streamsParsed] == 1) {
+
+            //geom.addAttribute( 'morphTarget'+frames_parsed, Float32Array, str_len/12, 3 );
+            var buffer = new Float32Array(str_len/4);
+            geom.morphTargets.push( {
+              array : buffer
+            });
+
+            //buffer = geom.attributes['morphTarget'+frames_parsed].array
+            idx = 0;
+
+            while ( this._ptr < str_end ) {
+              buffer[idx]     = this.readF32();
+              buffer[idx+1]   = this.readF32();
+              buffer[idx+2]   = this.readF32();
+              idx += 3;
+            }
+
+
+            subMeshParsed++;
+          } else
+            this._ptr = str_end;
+          streamsParsed++;
+        }
+      }
+
+
+      frames_parsed++;
+    }
+    this.parseUserAttributes();
+
+    return null;
+  }
+
+
+
+
+
+
+
+
+
+  AWDLoader.prototype.getBlock = function ( id ) {
+    return this._blocks[id].data;
+  },
+
+
+  AWDLoader.prototype.parseMatrix4 = function ( ) {
+    var mtx = new THREE.Matrix4();
+    var e = mtx.elements;
+
+    e[0] = this.readF32();
+    e[1] = this.readF32();
+    e[2] = this.readF32();
+    e[3] = 0.0;
+    //e[3] = 0.0;
+
+    e[4] = this.readF32();
+    e[5] = this.readF32();
+    e[6] = this.readF32();
+    //e[7] = this.readF32();
+    e[7] = 0.0;
+
+    e[8] = this.readF32();
+    e[9] = this.readF32();
+    e[10] = this.readF32();
+    //e[11] = this.readF32();
+    e[11] = 0.0;
+
+    e[12] = -this.readF32();
+    e[13] = this.readF32();
+    e[14] = this.readF32();
+    //e[15] = this.readF32();
+    e[15] = 1.0;
+    return mtx;
+  }
+
+
+  AWDLoader.prototype.parseProperties = function ( expected ) {
+    var list_len = this.readU32();
+    var list_end = this._ptr + list_len;
+
+    var props = new AWDProperties();
+
+    if( expected ) {
+
+      while( this._ptr < list_end ) {
+
+        var key = this.readU16();
+        var len = this.readU32();
+        var type;
+
+        if( expected.hasOwnProperty( key ) ) {
+          type = expected[ key ];
+          props.set( key, this.parseAttrValue( type, len ) );
+        } else {
+          this._ptr += len;
+        }
+      }
+
+    }
+
+    return props;
+
+  };
+
+
+  AWDLoader.prototype.parseUserAttributes = function ( ) {
+    // skip for now
+    this._ptr = this.readU32() + this._ptr;
+    return null;
+  };
+
+
+  AWDLoader.prototype.parseAttrValue = function ( type, len ) {
+
+    var elem_len;
+    var read_func;
+
+    switch (type) {
+      case AWD_FIELD_INT8:
+        elem_len = 1;
+        read_func = this.readI8;
+        break;
+      case AWD_FIELD_INT16:
+        elem_len = 2;
+        read_func = this.readI16;
+        break;
+      case AWD_FIELD_INT32:
+        elem_len = 4;
+        read_func = this.readI32;
+        break;
+      case AWD_FIELD_BOOL:
+      case AWD_FIELD_UINT8:
+        elem_len = 1;
+        read_func = this.readU8;
+        break;
+      case AWD_FIELD_UINT16:
+        elem_len = 2;
+        read_func = this.readU16;
+        break;
+      case AWD_FIELD_UINT32:
+      case AWD_FIELD_BADDR:
+        elem_len = 4;
+        read_func = this.readU32;
+        break;
+      case AWD_FIELD_FLOAT32:
+        elem_len = 4;
+        read_func = this.readF32;
+        break;
+      case AWD_FIELD_FLOAT64:
+        elem_len = 8;
+        read_func = this.readF64;
+        break;
+      case AWD_FIELD_VECTOR2x1:
+      case AWD_FIELD_VECTOR3x1:
+      case AWD_FIELD_VECTOR4x1:
+      case AWD_FIELD_MTX3x2:
+      case AWD_FIELD_MTX3x3:
+      case AWD_FIELD_MTX4x3:
+      case AWD_FIELD_MTX4x4:
+        elem_len = 8;
+        read_func = this.readF64;
+        break;
+    }
+
+    if (elem_len < len) {
+      var list;
+      var num_read;
+      var num_elems;
+
+      list = [];
+      num_read = 0;
+      num_elems = len / elem_len;
+
+      while (num_read < num_elems) {
+        list.push(read_func.call( this ) );
+        num_read++;
+      }
+
+      return list;
+    }
+    else {
+      return read_func.call( this );
+    }
+
+  }
+
+
+  AWDLoader.prototype.readU8 = function () {
+    return this._data.getUint8( this._ptr++ );
+  }
+  AWDLoader.prototype.readI8 = function () {
+    return this._data.getInt8( this._ptr++ );
+  }
+
+  AWDLoader.prototype.readU16 = function () {
+    var a = this._data.getUint16( this._ptr, littleEndian );
+    this._ptr += 2;
+    return a;
+  }
+  AWDLoader.prototype.readI16 = function () {
+    var a = this._data.getInt16( this._ptr, littleEndian );
+    this._ptr += 2;
+    return a;
+  }
+
+  AWDLoader.prototype.readU32 = function () {
+    var a = this._data.getUint32( this._ptr, littleEndian );
+    this._ptr += 4;
+    return a;
+  }
+  AWDLoader.prototype.readI32 = function () {
+    var a = this._data.getInt32( this._ptr, littleEndian );
+    this._ptr += 4;
+    return a;
+  }
+  AWDLoader.prototype.readF32 = function () {
+    var a = this._data.getFloat32( this._ptr, littleEndian );
+    this._ptr += 4;
+    return a;
+  }
+  AWDLoader.prototype.readF64 = function () {
+    var a = this._data.getFloat64( this._ptr, littleEndian );
+    this._ptr += 8;
+    return a;
+  }
+
+
+  /**
+   * Converts a UTF-8 byte array to JavaScript's 16-bit Unicode.
+   * @param {Array.<number>} bytes UTF-8 byte array.
+   * @return {string} 16-bit Unicode string.
+   */
+  AWDLoader.prototype.readUTF = function () {
+    var len = this.readU16();
+
+    return this.readUTFBytes( len );
+  };
+
+  /**
+   * Converts a UTF-8 byte array to JavaScript's 16-bit Unicode.
+   * @param {Array.<number>} bytes UTF-8 byte array.
+   * @return {string} 16-bit Unicode string.
+   */
+  AWDLoader.prototype.readUTFBytes = function ( len ) {
+
+
+    // TODO(user): Use native implementations if/when available
+
+    var out = [], c = 0;
+
+    while ( out.length < len ) {
+      var c1 = this._data.getUint8( this._ptr++, littleEndian );
+      if (c1 < 128) {
+        out[c++] = String.fromCharCode(c1);
+      } else if (c1 > 191 && c1 < 224) {
+        var c2 = this._data.getUint8( this._ptr++, littleEndian );
+        out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
+      } else {
+        var c2 = this._data.getUint8( this._ptr++, littleEndian );
+        var c3 = this._data.getUint8( this._ptr++, littleEndian );
+        out[c++] = String.fromCharCode(
+            (c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63
+        );
+      }
+    }
+    return out.join('');
+  };
+
+
+
+
+
+
+
+
+
+  AWDProperties = function(){}
+
+  AWDProperties.prototype = {
+
+
+    set : function(key, value)
+    {
+      this[key] = value;
+    },
+
+    get : function(key, fallback)
+    {
+      if ( this.hasOwnProperty(key) )
+        return this[key];
+      else return fallback;
+    }
+  }
+
+  return AWDLoader;
+
+})();

二進制
examples/models/awd/simple/simple.awd


二進制
examples/models/awd/simple/textures/texture.jpg


+ 153 - 0
examples/webgl_loader_awd.html

@@ -0,0 +1,153 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - collada</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				font-family: Monospace;
+				background-color: #000000;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#info {
+				color: #fff;
+				position: absolute;
+				top: 10px;
+				width: 100%;
+				text-align: center;
+				z-index: 100;
+				display:block;
+
+			}
+
+			a { color: skyblue }
+		</style>
+	</head>
+	<body>
+		<div id="info">
+			<a href="http://threejs.org" target="_blank">three.js</a> -
+			simple AWD loader
+		</div>
+
+		<script src="../build/three.min.js"></script>
+
+		<script src="js/loaders/AWDLoader.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+
+		<script src="js/Detector.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var container, stats;
+
+			var camera, scene, renderer, objects, controls;
+			var particleLight, pointLight;
+			var trunk;
+
+			var loader = new THREE.AWDLoader();
+
+			loader.materialFactory = createMaterial;
+			loader.load( './models/awd/simple/simple.awd', function ( _trunk ) {
+
+				trunk = _trunk;
+
+				init();
+				render();
+
+			} );
+
+
+			function createMaterial( name ){
+				// console.log( name );
+				// var mat = new THREE.MeshPhongMaterial({
+				// 	color: 0xaaaaaa,
+				// 	shininess: 20
+
+				// });
+				// return mat;
+				return null;
+			}
+
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
+				camera.position.set( 70, 50, -100 );
+
+				controls = new THREE.OrbitControls( camera );
+
+				scene = new THREE.Scene();
+
+
+				// Add the AWD SCENE
+
+				scene.add( trunk );
+
+
+				// Lights
+
+				scene.add( new THREE.AmbientLight( 0x606060 ) );
+
+				var directionalLight = new THREE.DirectionalLight(/*Math.random() * 0xffffff*/0xeeeeee );
+				directionalLight.position.set( .2, -1, .2 );
+				directionalLight.position.normalize();
+				scene.add( directionalLight );
+
+				pointLight = new THREE.PointLight( 0xffffff, .6 );
+				scene.add( pointLight );
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				container.appendChild( renderer.domElement );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+
+
+			function render() {
+
+				requestAnimationFrame( render );
+
+				var timer = Date.now() * 0.0005;
+
+				pointLight.position.x = Math.sin( timer * 4 ) * 3000;
+				pointLight.position.y = 600
+				pointLight.position.z = Math.cos( timer * 4 ) * 3000;
+
+				renderer.render( scene, camera );
+
+				stats.update();
+
+			}
+
+		</script>
+	</body>
+</html>