Program.cs 16 KB

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