/src/away3d/loaders/parsers/MD5MeshParser.as

http://github.com/away3d/away3d-core-fp11 · ActionScript · 683 lines · 482 code · 97 blank · 104 comment · 89 complexity · dfa77fa04079390fd23c3bb2dc50431e MD5 · raw file

  1. package away3d.loaders.parsers
  2. {
  3. import away3d.animators.SkeletonAnimationSet;
  4. import away3d.animators.data.Skeleton;
  5. import away3d.animators.data.SkeletonJoint;
  6. import away3d.arcane;
  7. import away3d.core.base.Geometry;
  8. import away3d.core.base.SkinnedSubGeometry;
  9. import away3d.core.math.Quaternion;
  10. import away3d.entities.Mesh;
  11. import flash.geom.Matrix3D;
  12. import flash.geom.Vector3D;
  13. use namespace arcane;
  14. // todo: create animation system, parse skeleton
  15. /**
  16. * MD5MeshParser provides a parser for the md5mesh data type, providing the geometry of the md5 format.
  17. *
  18. * todo: optimize
  19. */
  20. public class MD5MeshParser extends ParserBase
  21. {
  22. private var _textData:String;
  23. private var _startedParsing:Boolean;
  24. private static const VERSION_TOKEN:String = "MD5Version";
  25. private static const COMMAND_LINE_TOKEN:String = "commandline";
  26. private static const NUM_JOINTS_TOKEN:String = "numJoints";
  27. private static const NUM_MESHES_TOKEN:String = "numMeshes";
  28. private static const COMMENT_TOKEN:String = "//";
  29. private static const JOINTS_TOKEN:String = "joints";
  30. private static const MESH_TOKEN:String = "mesh";
  31. private static const MESH_SHADER_TOKEN:String = "shader";
  32. private static const MESH_NUM_VERTS_TOKEN:String = "numverts";
  33. private static const MESH_VERT_TOKEN:String = "vert";
  34. private static const MESH_NUM_TRIS_TOKEN:String = "numtris";
  35. private static const MESH_TRI_TOKEN:String = "tri";
  36. private static const MESH_NUM_WEIGHTS_TOKEN:String = "numweights";
  37. private static const MESH_WEIGHT_TOKEN:String = "weight";
  38. private var _parseIndex:int;
  39. private var _reachedEOF:Boolean;
  40. private var _line:int;
  41. private var _charLineIndex:int;
  42. private var _version:int;
  43. private var _numJoints:int;
  44. private var _numMeshes:int;
  45. private var _mesh:Mesh;
  46. private var _shaders:Vector.<String>;
  47. private var _maxJointCount:int;
  48. private var _meshData:Vector.<MeshData>;
  49. private var _bindPoses:Vector.<Matrix3D>;
  50. private var _geometry:Geometry;
  51. private var _skeleton:Skeleton;
  52. private var _animationSet:SkeletonAnimationSet;
  53. private var _rotationQuat:Quaternion;
  54. /**
  55. * Creates a new MD5MeshParser object.
  56. */
  57. public function MD5MeshParser(additionalRotationAxis:Vector3D = null, additionalRotationRadians:Number = 0)
  58. {
  59. super(ParserDataFormat.PLAIN_TEXT);
  60. _rotationQuat = new Quaternion();
  61. _rotationQuat.fromAxisAngle(Vector3D.X_AXIS, -Math.PI*.5);
  62. if (additionalRotationAxis) {
  63. var quat:Quaternion = new Quaternion();
  64. quat.fromAxisAngle(additionalRotationAxis, additionalRotationRadians);
  65. _rotationQuat.multiply(_rotationQuat, quat);
  66. }
  67. }
  68. /**
  69. * Indicates whether or not a given file extension is supported by the parser.
  70. * @param extension The file extension of a potential file to be parsed.
  71. * @return Whether or not the given file type is supported.
  72. */
  73. public static function supportsType(extension:String):Boolean
  74. {
  75. extension = extension.toLowerCase();
  76. return extension == "md5mesh";
  77. }
  78. /**
  79. * Tests whether a data block can be parsed by the parser.
  80. * @param data The data block to potentially be parsed.
  81. * @return Whether or not the given data is supported.
  82. */
  83. public static function supportsData(data:*):Boolean
  84. {
  85. data = data;
  86. return false;
  87. }
  88. /**
  89. * @inheritDoc
  90. */
  91. protected override function proceedParsing():Boolean
  92. {
  93. var token:String;
  94. if (!_startedParsing) {
  95. _textData = getTextData();
  96. _startedParsing = true;
  97. }
  98. while (hasTime()) {
  99. token = getNextToken();
  100. switch (token) {
  101. case COMMENT_TOKEN:
  102. ignoreLine();
  103. break;
  104. case VERSION_TOKEN:
  105. _version = getNextInt();
  106. if (_version != 10)
  107. throw new Error("Unknown version number encountered!");
  108. break;
  109. case COMMAND_LINE_TOKEN:
  110. parseCMD();
  111. break;
  112. case NUM_JOINTS_TOKEN:
  113. _numJoints = getNextInt();
  114. _bindPoses = new Vector.<Matrix3D>(_numJoints, true);
  115. break;
  116. case NUM_MESHES_TOKEN:
  117. _numMeshes = getNextInt();
  118. break;
  119. case JOINTS_TOKEN:
  120. parseJoints();
  121. break;
  122. case MESH_TOKEN:
  123. parseMesh();
  124. break;
  125. default:
  126. if (!_reachedEOF)
  127. sendUnknownKeywordError();
  128. }
  129. if (_reachedEOF) {
  130. calculateMaxJointCount();
  131. _animationSet = new SkeletonAnimationSet(_maxJointCount);
  132. _mesh = new Mesh(new Geometry(), null);
  133. _geometry = _mesh.geometry;
  134. for (var i:int = 0; i < _meshData.length; ++i)
  135. _geometry.addSubGeometry(translateGeom(_meshData[i].vertexData, _meshData[i].weightData, _meshData[i].indices));
  136. //_geometry.animation = _animation;
  137. // _mesh.animationController = _animationController;
  138. finalizeAsset(_geometry);
  139. finalizeAsset(_mesh);
  140. finalizeAsset(_skeleton);
  141. finalizeAsset(_animationSet);
  142. return ParserBase.PARSING_DONE;
  143. }
  144. }
  145. return ParserBase.MORE_TO_PARSE;
  146. }
  147. private function calculateMaxJointCount():void
  148. {
  149. _maxJointCount = 0;
  150. var numMeshData:int = _meshData.length;
  151. for (var i:int = 0; i < numMeshData; ++i) {
  152. var meshData:MeshData = _meshData[i];
  153. var vertexData:Vector.<VertexData> = meshData.vertexData;
  154. var numVerts:int = vertexData.length;
  155. for (var j:int = 0; j < numVerts; ++j) {
  156. var zeroWeights:int = countZeroWeightJoints(vertexData[j], meshData.weightData);
  157. var totalJoints:int = vertexData[j].countWeight - zeroWeights;
  158. if (totalJoints > _maxJointCount)
  159. _maxJointCount = totalJoints;
  160. }
  161. }
  162. }
  163. private function countZeroWeightJoints(vertex:VertexData, weights:Vector.<JointData>):int
  164. {
  165. var start:int = vertex.startWeight;
  166. var end:int = vertex.startWeight + vertex.countWeight;
  167. var count:int = 0;
  168. var weight:Number;
  169. for (var i:int = start; i < end; ++i) {
  170. weight = weights[i].bias;
  171. if (weight == 0)
  172. ++count;
  173. }
  174. return count;
  175. }
  176. /**
  177. * Parses the skeleton's joints.
  178. */
  179. private function parseJoints():void
  180. {
  181. var ch:String;
  182. var joint:SkeletonJoint;
  183. var pos:Vector3D;
  184. var quat:Quaternion;
  185. var i:int = 0;
  186. var token:String = getNextToken();
  187. if (token != "{")
  188. sendUnknownKeywordError();
  189. _skeleton = new Skeleton();
  190. do {
  191. if (_reachedEOF)
  192. sendEOFError();
  193. joint = new SkeletonJoint();
  194. joint.name = parseLiteralString();
  195. joint.parentIndex = getNextInt();
  196. pos = parseVector3D();
  197. pos = _rotationQuat.rotatePoint(pos);
  198. quat = parseQuaternion();
  199. // todo: check if this is correct, or maybe we want to actually store it as quats?
  200. _bindPoses[i] = quat.toMatrix3D();
  201. _bindPoses[i].appendTranslation(pos.x, pos.y, pos.z);
  202. var inv:Matrix3D = _bindPoses[i].clone();
  203. inv.invert();
  204. joint.inverseBindPose = inv.rawData;
  205. _skeleton.joints[i++] = joint;
  206. ch = getNextChar();
  207. if (ch == "/") {
  208. putBack();
  209. ch = getNextToken();
  210. if (ch == COMMENT_TOKEN)
  211. ignoreLine();
  212. ch = getNextChar();
  213. }
  214. if (ch != "}")
  215. putBack();
  216. } while (ch != "}");
  217. }
  218. /**
  219. * Puts back the last read character into the data stream.
  220. */
  221. private function putBack():void
  222. {
  223. _parseIndex--;
  224. _charLineIndex--;
  225. _reachedEOF = _parseIndex >= _textData.length;
  226. }
  227. /**
  228. * Parses the mesh geometry.
  229. */
  230. private function parseMesh():void
  231. {
  232. var token:String = getNextToken();
  233. var ch:String;
  234. var vertexData:Vector.<VertexData>;
  235. var weights:Vector.<JointData>;
  236. var indices:Vector.<uint>;
  237. if (token != "{")
  238. sendUnknownKeywordError();
  239. _shaders ||= new Vector.<String>();
  240. while (ch != "}") {
  241. ch = getNextToken();
  242. switch (ch) {
  243. case COMMENT_TOKEN:
  244. ignoreLine();
  245. break;
  246. case MESH_SHADER_TOKEN:
  247. _shaders.push(parseLiteralString());
  248. break;
  249. case MESH_NUM_VERTS_TOKEN:
  250. vertexData = new Vector.<VertexData>(getNextInt(), true);
  251. break;
  252. case MESH_NUM_TRIS_TOKEN:
  253. indices = new Vector.<uint>(getNextInt()*3, true);
  254. break;
  255. case MESH_NUM_WEIGHTS_TOKEN:
  256. weights = new Vector.<JointData>(getNextInt(), true);
  257. break;
  258. case MESH_VERT_TOKEN:
  259. parseVertex(vertexData);
  260. break;
  261. case MESH_TRI_TOKEN:
  262. parseTri(indices);
  263. break;
  264. case MESH_WEIGHT_TOKEN:
  265. parseJoint(weights);
  266. break;
  267. }
  268. }
  269. _meshData ||= new Vector.<MeshData>();
  270. var i:uint = _meshData.length;
  271. _meshData[i] = new MeshData();
  272. _meshData[i].vertexData = vertexData;
  273. _meshData[i].weightData = weights;
  274. _meshData[i].indices = indices;
  275. }
  276. /**
  277. * Converts the mesh data to a SkinnedSub instance.
  278. * @param vertexData The mesh's vertices.
  279. * @param weights The joint weights per vertex.
  280. * @param indices The indices for the faces.
  281. * @return A SkinnedSubGeometry instance containing all geometrical data for the current mesh.
  282. */
  283. private function translateGeom(vertexData:Vector.<VertexData>, weights:Vector.<JointData>, indices:Vector.<uint>):SkinnedSubGeometry
  284. {
  285. var len:int = vertexData.length;
  286. var v1:int, v2:int, v3:int;
  287. var vertex:VertexData;
  288. var weight:JointData;
  289. var bindPose:Matrix3D;
  290. var pos:Vector3D;
  291. var subGeom:SkinnedSubGeometry = new SkinnedSubGeometry(_maxJointCount);
  292. var uvs:Vector.<Number> = new Vector.<Number>(len*2, true);
  293. var vertices:Vector.<Number> = new Vector.<Number>(len*3, true);
  294. var jointIndices:Vector.<Number> = new Vector.<Number>(len*_maxJointCount, true);
  295. var jointWeights:Vector.<Number> = new Vector.<Number>(len*_maxJointCount, true);
  296. var l:int;
  297. var nonZeroWeights:int;
  298. for (var i:int = 0; i < len; ++i) {
  299. vertex = vertexData[i];
  300. v1 = vertex.index*3;
  301. v2 = v1 + 1;
  302. v3 = v1 + 2;
  303. vertices[v1] = vertices[v2] = vertices[v3] = 0;
  304. nonZeroWeights = 0;
  305. for (var j:int = 0; j < vertex.countWeight; ++j) {
  306. weight = weights[vertex.startWeight + j];
  307. if (weight.bias > 0) {
  308. bindPose = _bindPoses[weight.joint];
  309. pos = bindPose.transformVector(weight.pos);
  310. vertices[v1] += pos.x*weight.bias;
  311. vertices[v2] += pos.y*weight.bias;
  312. vertices[v3] += pos.z*weight.bias;
  313. // indices need to be multiplied by 3 (amount of matrix registers)
  314. jointIndices[l] = weight.joint*3;
  315. jointWeights[l++] = weight.bias;
  316. ++nonZeroWeights;
  317. }
  318. }
  319. for (j = nonZeroWeights; j < _maxJointCount; ++j) {
  320. jointIndices[l] = 0;
  321. jointWeights[l++] = 0;
  322. }
  323. v1 = vertex.index << 1;
  324. uvs[v1++] = vertex.s;
  325. uvs[v1] = vertex.t;
  326. }
  327. subGeom.updateIndexData(indices);
  328. subGeom.fromVectors(vertices, uvs, null, null);
  329. // cause explicit updates
  330. subGeom.vertexNormalData;
  331. subGeom.vertexTangentData;
  332. // turn auto updates off because they may be animated and set explicitly
  333. subGeom.autoDeriveVertexTangents = false;
  334. subGeom.autoDeriveVertexNormals = false;
  335. subGeom.updateJointIndexData(jointIndices);
  336. subGeom.updateJointWeightsData(jointWeights);
  337. return subGeom;
  338. }
  339. /**
  340. * Retrieve the next triplet of vertex indices that form a face.
  341. * @param indices The index list in which to store the read data.
  342. */
  343. private function parseTri(indices:Vector.<uint>):void
  344. {
  345. var index:int = getNextInt()*3;
  346. indices[index] = getNextInt();
  347. indices[index + 1] = getNextInt();
  348. indices[index + 2] = getNextInt();
  349. }
  350. /**
  351. * Reads a new joint data set for a single joint.
  352. * @param weights the target list to contain the weight data.
  353. */
  354. private function parseJoint(weights:Vector.<JointData>):void
  355. {
  356. var weight:JointData = new JointData();
  357. weight.index = getNextInt();
  358. weight.joint = getNextInt();
  359. weight.bias = getNextNumber();
  360. weight.pos = parseVector3D();
  361. weights[weight.index] = weight;
  362. }
  363. /**
  364. * Reads the data for a single vertex.
  365. * @param vertexData The list to contain the vertex data.
  366. */
  367. private function parseVertex(vertexData:Vector.<VertexData>):void
  368. {
  369. var vertex:VertexData = new VertexData();
  370. vertex.index = getNextInt();
  371. parseUV(vertex);
  372. vertex.startWeight = getNextInt();
  373. vertex.countWeight = getNextInt();
  374. // if (vertex.countWeight > _maxJointCount) _maxJointCount = vertex.countWeight;
  375. vertexData[vertex.index] = vertex;
  376. }
  377. /**
  378. * Reads the next uv coordinate.
  379. * @param vertexData The vertexData to contain the UV coordinates.
  380. */
  381. private function parseUV(vertexData:VertexData):void
  382. {
  383. var ch:String = getNextToken();
  384. if (ch != "(")
  385. sendParseError("(");
  386. vertexData.s = getNextNumber();
  387. vertexData.t = getNextNumber();
  388. if (getNextToken() != ")")
  389. sendParseError(")");
  390. }
  391. /**
  392. * Gets the next token in the data stream.
  393. */
  394. private function getNextToken():String
  395. {
  396. var ch:String;
  397. var token:String = "";
  398. while (!_reachedEOF) {
  399. ch = getNextChar();
  400. if (ch == " " || ch == "\r" || ch == "\n" || ch == "\t") {
  401. if (token != COMMENT_TOKEN)
  402. skipWhiteSpace();
  403. if (token != "")
  404. return token;
  405. } else
  406. token += ch;
  407. if (token == COMMENT_TOKEN)
  408. return token;
  409. }
  410. return token;
  411. }
  412. /**
  413. * Skips all whitespace in the data stream.
  414. */
  415. private function skipWhiteSpace():void
  416. {
  417. var ch:String;
  418. do
  419. ch = getNextChar();
  420. while (ch == "\n" || ch == " " || ch == "\r" || ch == "\t");
  421. putBack();
  422. }
  423. /**
  424. * Skips to the next line.
  425. */
  426. private function ignoreLine():void
  427. {
  428. var ch:String;
  429. while (!_reachedEOF && ch != "\n")
  430. ch = getNextChar();
  431. }
  432. /**
  433. * Retrieves the next single character in the data stream.
  434. */
  435. private function getNextChar():String
  436. {
  437. var ch:String = _textData.charAt(_parseIndex++);
  438. if (ch == "\n") {
  439. ++_line;
  440. _charLineIndex = 0;
  441. } else if (ch != "\r")
  442. ++_charLineIndex;
  443. if (_parseIndex >= _textData.length)
  444. _reachedEOF = true;
  445. return ch;
  446. }
  447. /**
  448. * Retrieves the next integer in the data stream.
  449. */
  450. private function getNextInt():int
  451. {
  452. var i:Number = parseInt(getNextToken());
  453. if (isNaN(i))
  454. sendParseError("int type");
  455. return i;
  456. }
  457. /**
  458. * Retrieves the next floating point number in the data stream.
  459. */
  460. private function getNextNumber():Number
  461. {
  462. var f:Number = parseFloat(getNextToken());
  463. if (isNaN(f))
  464. sendParseError("float type");
  465. return f;
  466. }
  467. /**
  468. * Retrieves the next 3d vector in the data stream.
  469. */
  470. private function parseVector3D():Vector3D
  471. {
  472. var vec:Vector3D = new Vector3D();
  473. var ch:String = getNextToken();
  474. if (ch != "(")
  475. sendParseError("(");
  476. vec.x = -getNextNumber();
  477. vec.y = getNextNumber();
  478. vec.z = getNextNumber();
  479. if (getNextToken() != ")")
  480. sendParseError(")");
  481. return vec;
  482. }
  483. /**
  484. * Retrieves the next quaternion in the data stream.
  485. */
  486. private function parseQuaternion():Quaternion
  487. {
  488. var quat:Quaternion = new Quaternion();
  489. var ch:String = getNextToken();
  490. if (ch != "(")
  491. sendParseError("(");
  492. quat.x = getNextNumber();
  493. quat.y = -getNextNumber();
  494. quat.z = -getNextNumber();
  495. // quat supposed to be unit length
  496. var t:Number = 1 - quat.x*quat.x - quat.y*quat.y - quat.z*quat.z;
  497. quat.w = t < 0? 0 : -Math.sqrt(t);
  498. if (getNextToken() != ")")
  499. sendParseError(")");
  500. var rotQuat:Quaternion = new Quaternion();
  501. rotQuat.multiply(_rotationQuat, quat);
  502. return rotQuat;
  503. }
  504. /**
  505. * Parses the command line data.
  506. */
  507. private function parseCMD():void
  508. {
  509. // just ignore the command line property
  510. parseLiteralString();
  511. }
  512. /**
  513. * Retrieves the next literal string in the data stream. A literal string is a sequence of characters bounded
  514. * by double quotes.
  515. */
  516. private function parseLiteralString():String
  517. {
  518. skipWhiteSpace();
  519. var ch:String = getNextChar();
  520. var str:String = "";
  521. if (ch != "\"")
  522. sendParseError("\"");
  523. do {
  524. if (_reachedEOF)
  525. sendEOFError();
  526. ch = getNextChar();
  527. if (ch != "\"")
  528. str += ch;
  529. } while (ch != "\"");
  530. return str;
  531. }
  532. /**
  533. * Throws an end-of-file error when a premature end of file was encountered.
  534. */
  535. private function sendEOFError():void
  536. {
  537. throw new Error("Unexpected end of file");
  538. }
  539. /**
  540. * Throws an error when an unexpected token was encountered.
  541. * @param expected The token type that was actually expected.
  542. */
  543. private function sendParseError(expected:String):void
  544. {
  545. throw new Error("Unexpected token at line " + (_line + 1) + ", character " + _charLineIndex + ". " + expected + " expected, but " + _textData.charAt(_parseIndex - 1) + " encountered");
  546. }
  547. /**
  548. * Throws an error when an unknown keyword was encountered.
  549. */
  550. private function sendUnknownKeywordError():void
  551. {
  552. throw new Error("Unknown keyword at line " + (_line + 1) + ", character " + _charLineIndex + ". ");
  553. }
  554. }
  555. }
  556. import flash.geom.Vector3D;
  557. class VertexData
  558. {
  559. public var index:int;
  560. public var s:Number;
  561. public var t:Number;
  562. public var startWeight:int;
  563. public var countWeight:int;
  564. public function VertexData()
  565. {
  566. }
  567. }
  568. class JointData
  569. {
  570. public var index:int;
  571. public var joint:int;
  572. public var bias:Number;
  573. public var pos:Vector3D;
  574. public function JointData()
  575. {
  576. }
  577. }
  578. class MeshData
  579. {
  580. public var vertexData:Vector.<VertexData>;
  581. public var weightData:Vector.<JointData>;
  582. public var indices:Vector.<uint>;
  583. public function MeshData()
  584. {
  585. }
  586. }