BinaryConverter.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. using Newtonsoft.Json;
  2. using Newtonsoft.Json.Linq;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. namespace BabylonFileConverter
  11. {
  12. public static class BinaryConverter
  13. {
  14. public enum DataType { Int32, Float };
  15. public static void Convert(string srcFilename, string dstPath, Action<string> onMessage, Action<string> onError)
  16. {
  17. try
  18. {
  19. if (!Directory.Exists(dstPath))
  20. Directory.CreateDirectory(dstPath);
  21. string srcPath = Path.GetDirectoryName(srcFilename);
  22. string dstFilename = Path.Combine(dstPath, Path.GetFileNameWithoutExtension(srcFilename) + ".binary.babylon");
  23. dynamic scene;
  24. // Loading
  25. onMessage("Loading " + srcFilename);
  26. using (var streamReader = new StreamReader(srcFilename))
  27. {
  28. using (var reader = new JsonTextReader(streamReader))
  29. {
  30. scene = JObject.Load(reader);
  31. }
  32. }
  33. // Marking scene
  34. string objName = scene.name;
  35. if (string.IsNullOrEmpty(objName))
  36. objName = Path.GetFileNameWithoutExtension(srcFilename);
  37. var atDot = objName.IndexOf(".incremental");
  38. if (atDot > 0)
  39. objName = objName.Substring(0, atDot);
  40. scene["autoClear"] = true;
  41. scene["useDelayedTextureLoading"] = true;
  42. var doNotDelayLoadingForGeometries = new List<string>();
  43. // Parsing meshes
  44. var meshes = (JArray)scene.meshes;
  45. foreach (dynamic mesh in meshes)
  46. {
  47. if (mesh.checkCollisions.Value) // Do not delay load collisions object
  48. {
  49. if (mesh.geometryId != null)
  50. doNotDelayLoadingForGeometries.Add(mesh.geometryId.Value);
  51. continue;
  52. }
  53. Extract(srcPath, dstPath, objName, mesh, true);
  54. }
  55. // Parsing vertexData
  56. var geometries = scene.geometries;
  57. if (geometries != null)
  58. {
  59. var vertexData = (JArray)geometries.vertexData;
  60. foreach (dynamic geometry in vertexData)
  61. {
  62. var id = geometry.id.Value;
  63. if (doNotDelayLoadingForGeometries.Any(g => g == id))
  64. continue;
  65. Extract(srcPath, dstPath, objName, geometry, false);
  66. }
  67. }
  68. // Saving
  69. onMessage("Saving " + dstFilename);
  70. string json = scene.ToString(Formatting.Indented);
  71. using (var writer = new StreamWriter(WebUtility.UrlDecode(dstFilename)))
  72. {
  73. writer.Write(json);
  74. }
  75. }
  76. catch (Exception ex)
  77. {
  78. onError(ex.Message);
  79. }
  80. }
  81. static void Extract(string srcPath, string dstPath, string objName, dynamic meshObj, bool isMesh)
  82. {
  83. string dstFilename = meshObj.delayLoadingFile;
  84. string dstExt = (isMesh ? ".babylonbinarymeshdata" : ".babylonbinarygeometrydata");
  85. if (!string.IsNullOrEmpty(dstFilename))
  86. {
  87. string filename = WebUtility.UrlDecode(Path.Combine(srcPath, (string)meshObj.delayLoadingFile));
  88. using (var streamReader = new StreamReader(filename))
  89. {
  90. using (var reader = new JsonTextReader(streamReader))
  91. {
  92. var meshData = JObject.Load(reader);
  93. meshObj.positions = meshData["positions"];
  94. meshObj.normals = meshData["normals"];
  95. meshObj.indices = meshData["indices"];
  96. meshObj.uvs = meshData["uvs"];
  97. meshObj.uvs2 = meshData["uvs2"];
  98. meshObj.colors = meshData["colors"];
  99. meshObj.matricesIndices = meshData["matricesIndices"];
  100. meshObj.matricesWeights = meshData["matricesWeights"];
  101. meshObj.subMeshes = meshData["subMeshes"];
  102. }
  103. }
  104. }
  105. if (meshObj.positions == null || meshObj.positions.Count == 0
  106. || meshObj.normals == null || meshObj.normals.Count == 0
  107. || meshObj.indices == null || meshObj.indices.Count == 0)
  108. return;
  109. ComputeBoundingBox(meshObj);
  110. string meshName = meshObj.name.ToString();
  111. meshName = meshName.Trim();
  112. if (meshName.Length > 40)
  113. meshName = meshName.Substring(0, 40);
  114. if (isMesh && !string.IsNullOrEmpty(meshName))
  115. dstFilename = objName + "." + meshName + "." + meshObj.id.ToString() + dstExt;
  116. else
  117. dstFilename = objName + meshObj.id.ToString() + dstExt;
  118. dstFilename = dstFilename.Replace("+", "_").Replace(" ", "_").Replace("/", "_").Replace("\\", "_").Replace(":", "_");
  119. meshObj.delayLoadingFile = WebUtility.UrlEncode(dstFilename);
  120. var binaryInfo = new JObject();
  121. using (var stream = File.Open(WebUtility.UrlDecode(Path.Combine(dstPath, dstFilename)), FileMode.Create))
  122. {
  123. var writer = new BinaryWriter(stream);
  124. if (meshObj.positions != null && meshObj.positions.Count > 0)
  125. {
  126. var attrData = new JObject();
  127. attrData["count"] = meshObj.positions.Count;
  128. attrData["stride"] = 3;
  129. attrData["offset"] = stream.Length;
  130. attrData["dataType"] = (int)DataType.Float;
  131. binaryInfo["positionsAttrDesc"] = attrData;
  132. for (int x = 0; x < meshObj.positions.Count; x++)
  133. writer.Write((float)meshObj.positions[x]);
  134. meshObj.positions = null;
  135. }
  136. if (meshObj.colors != null && meshObj.colors.Count > 0)
  137. {
  138. var attrData = new JObject();
  139. attrData["count"] = meshObj.colors.Count;
  140. attrData["stride"] = 3;
  141. attrData["offset"] = stream.Length;
  142. attrData["dataType"] = (int)DataType.Float;
  143. binaryInfo["colorsAttrDesc"] = attrData;
  144. for (int x = 0; x < meshObj.colors.Count; x++)
  145. writer.Write((float)meshObj.colors[x]);
  146. meshObj["hasColors"] = true;
  147. meshObj.colors = null;
  148. }
  149. if (meshObj.normals != null && meshObj.normals.Count > 0)
  150. {
  151. var attrData = new JObject();
  152. attrData["count"] = meshObj.normals.Count;
  153. attrData["stride"] = 3;
  154. attrData["offset"] = stream.Length;
  155. attrData["dataType"] = (int)DataType.Float;
  156. binaryInfo["normalsAttrDesc"] = attrData;
  157. for (int x = 0; x < meshObj.normals.Count; x++)
  158. writer.Write((float)meshObj.normals[x]);
  159. meshObj.normals = null;
  160. }
  161. if (meshObj.uvs != null && meshObj.uvs.Count > 0)
  162. {
  163. var attrData = new JObject();
  164. attrData["count"] = meshObj.uvs.Count;
  165. attrData["stride"] = 2;
  166. attrData["offset"] = stream.Length;
  167. attrData["dataType"] = (int)DataType.Float;
  168. binaryInfo["uvsAttrDesc"] = attrData;
  169. for (int x = 0; x < meshObj.uvs.Count; x++)
  170. writer.Write((float)meshObj.uvs[x]);
  171. meshObj["hasUVs"] = true;
  172. meshObj.uvs = null;
  173. }
  174. if (meshObj.uvs2 != null && meshObj.uvs2.Count > 0)
  175. {
  176. var attrData = new JObject();
  177. attrData["count"] = meshObj.uvs2.Count;
  178. attrData["stride"] = 2;
  179. attrData["offset"] = stream.Length;
  180. attrData["dataType"] = (int)DataType.Float;
  181. binaryInfo["uvs2AttrDesc"] = attrData;
  182. for (int x = 0; x < meshObj.uvs2.Count; x++)
  183. writer.Write((float)meshObj.uvs2[x]);
  184. meshObj["hasUVs2"] = true;
  185. meshObj.uvs2 = null;
  186. }
  187. if (meshObj.indices != null && meshObj.indices.Count > 0)
  188. {
  189. var attrData = new JObject();
  190. attrData["count"] = meshObj.indices.Count;
  191. attrData["stride"] = 1;
  192. attrData["offset"] = stream.Length;
  193. attrData["dataType"] = (int)DataType.Int32;
  194. binaryInfo["indicesAttrDesc"] = attrData;
  195. for (int x = 0; x < meshObj.indices.Count; x++)
  196. writer.Write((int)meshObj.indices[x]);
  197. meshObj.indices = null;
  198. }
  199. if (meshObj.matricesIndices != null && meshObj.matricesIndices.Count > 0)
  200. {
  201. var attrData = new JObject();
  202. attrData["count"] = meshObj.matricesIndices.Count;
  203. attrData["stride"] = 1;
  204. attrData["offset"] = stream.Length;
  205. attrData["dataType"] = (int)DataType.Int32;
  206. binaryInfo["matricesIndicesAttrDesc"] = attrData;
  207. for (int x = 0; x < meshObj.matricesIndices.Count; x++)
  208. writer.Write((int)meshObj.matricesIndices[x]);
  209. meshObj["hasMatricesIndices"] = true;
  210. meshObj.matricesIndices = null;
  211. }
  212. if (meshObj.matricesWeights != null && meshObj.matricesWeights.Count > 0)
  213. {
  214. var attrData = new JObject();
  215. attrData["count"] = meshObj.matricesWeights.Count;
  216. attrData["stride"] = 2;
  217. attrData["offset"] = stream.Length;
  218. attrData["dataType"] = (int)DataType.Float;
  219. binaryInfo["matricesWeightsAttrDesc"] = attrData;
  220. for (int x = 0; x < meshObj.matricesWeights.Count; x++)
  221. writer.Write((float)meshObj.matricesWeights[x]);
  222. meshObj["hasMatricesWeights"] = true;
  223. meshObj.matricesWeights = null;
  224. }
  225. if (isMesh && meshObj.subMeshes != null && meshObj.subMeshes.Count > 0)
  226. {
  227. var attrData = new JObject();
  228. attrData["count"] = meshObj.subMeshes.Count;
  229. attrData["stride"] = 5;
  230. attrData["offset"] = stream.Length;
  231. attrData["dataType"] = (int)DataType.Int32;
  232. binaryInfo["subMeshesAttrDesc"] = attrData;
  233. var smData = new int[5];
  234. for (int x = 0; x < meshObj.subMeshes.Count; x++)
  235. {
  236. smData[0] = meshObj.subMeshes[x].materialIndex;
  237. smData[1] = meshObj.subMeshes[x].verticesStart;
  238. smData[2] = meshObj.subMeshes[x].verticesCount;
  239. smData[3] = meshObj.subMeshes[x].indexStart;
  240. smData[4] = meshObj.subMeshes[x].indexCount;
  241. for (int y = 0; y < smData.Length; y++)
  242. writer.Write(smData[y]);
  243. }
  244. meshObj.subMeshes = null;
  245. }
  246. }
  247. meshObj["_binaryInfo"] = binaryInfo;
  248. }
  249. static void ComputeBoundingBox(dynamic meshOrGeometry)
  250. {
  251. // Compute bounding boxes
  252. var positions = ((JArray)meshOrGeometry.positions).Select(v => v.Value<float>()).ToArray();
  253. var minimum = new[] { float.MaxValue, float.MaxValue, float.MaxValue };
  254. var maximum = new[] { float.MinValue, float.MinValue, float.MinValue };
  255. for (var index = 0; index < positions.Length; index += 3)
  256. {
  257. var x = positions[index];
  258. var y = positions[index + 1];
  259. var z = positions[index + 2];
  260. if (x < minimum[0])
  261. {
  262. minimum[0] = x;
  263. }
  264. if (x > maximum[0])
  265. {
  266. maximum[0] = x;
  267. }
  268. if (y < minimum[1])
  269. {
  270. minimum[1] = y;
  271. }
  272. if (y > maximum[1])
  273. {
  274. maximum[1] = y;
  275. }
  276. if (z < minimum[2])
  277. {
  278. minimum[2] = z;
  279. }
  280. if (z > maximum[2])
  281. {
  282. maximum[2] = z;
  283. }
  284. }
  285. meshOrGeometry["boundingBoxMinimum"] = new JArray(minimum);
  286. meshOrGeometry["boundingBoxMaximum"] = new JArray(maximum);
  287. }
  288. }
  289. }