ObJS.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /********************************************************************
  2. * Parameters used all along the script. Only for *
  3. * customization. *
  4. ********************************************************************/
  5. var backColor = "rgba(200, 200, 200, 1)";
  6. var vertColor = "rgba(10, 10, 10, 1)";
  7. var edgeColor = "rgba(100, 70, 70, 1)";
  8. var faceColor = "rgba(180, 180, 255, .6)";
  9. var faceAlpha = .6;
  10. var textColor = "rgba(0, 0, 0, 1)";
  11. var vertSize = 4; //Make it even: at small scales will look better
  12. var rotationSpeed = 100; //Smaller = faster. 100 is a good speed
  13. var zoomSpeed = 0.2; //0-1. 0.2 or 0.3 are good speeds
  14. /********************************************************************
  15. * Parameters used to scale the measures in the .obj file. Can be *
  16. * integer or float, greater than 0. 50 is a good default. *
  17. ********************************************************************/
  18. var scale;
  19. /********************************************************************
  20. * Global variable to determine if the mouse button is being holded *
  21. * down. *
  22. ********************************************************************/
  23. var mDown = false;
  24. /********************************************************************
  25. * Global variables containing the canvas and its context. *
  26. ********************************************************************/
  27. var canvas;
  28. var ctx;
  29. /********************************************************************
  30. * Global variables containing the number of elements. *
  31. ********************************************************************/
  32. var totalVert;
  33. var totalEdge;//TODO: I dont know how to calculate. And I dont need it
  34. var totalFace
  35. /********************************************************************
  36. * Arrays containing the vertices, edges and faces. *
  37. ********************************************************************/
  38. var obj; //Unused
  39. var vert;
  40. var face;
  41. /********************************************************************
  42. * Booleans to determine wich elements are to draw. *
  43. ********************************************************************/
  44. var dVerts = true;
  45. var dEdges = true;
  46. var dFaces = true;
  47. var dBackg = true;
  48. /********************************************************************
  49. * Global variables that will contain the position of the mouse in *
  50. * the previous frame to calculate rotation. *
  51. ********************************************************************/
  52. var pX = null;
  53. var pY = null;
  54. /********************************************************************
  55. * Function switching the elements to draw (dVerts, dEdges, dFaces) *
  56. * #parameters: *
  57. * name (string): key to the element to draw. *
  58. * value (boolean): indicating if the element is to be drawn. *
  59. * #return: nothing *
  60. ********************************************************************/
  61. function drawElement(name, value){
  62. switch (name){
  63. case "verts":
  64. dVerts = value;
  65. break;
  66. case "edges":
  67. dEdges = value;
  68. break;
  69. case "faces":
  70. dFaces = value;
  71. break;
  72. case "backg":
  73. dBackg = value;
  74. break;
  75. }
  76. draw();
  77. }
  78. /********************************************************************
  79. * Function that turns a hex color code in RGB. *
  80. * stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb *
  81. * #parameters: *
  82. * hex (string): color code, for example "#33ff99" *
  83. * #return: (Array) r, g, b, with their correspondent color. *
  84. ********************************************************************/
  85. function hexToRgb(hex) {
  86. var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  87. return result ? {
  88. r: parseInt(result[1], 16),
  89. g: parseInt(result[2], 16),
  90. b: parseInt(result[3], 16)
  91. } : null;
  92. }
  93. /********************************************************************
  94. * Function switching the color of the elements. *
  95. * #parameters: *
  96. * name (string): key to the element to colorize. *
  97. * value (boolean): indicating if the element is to be drawn. *
  98. * #return: nothing *
  99. ********************************************************************/
  100. function colorElement(name, value){
  101. var color = hexToRgb(value)
  102. var str = "rgba(" + color.r + ", " + color.g + ", " + color.b + ", 1)"
  103. switch (name){
  104. case "backg":
  105. backColor = "rgba(" + color.r + ", " + color.g + ", " + color.b + ", 1)";
  106. break;
  107. case "verts":
  108. vertColor = "rgba(" + color.r + ", " + color.g + ", " + color.b + ", 1)";
  109. break;
  110. case "edges":
  111. edgeColor = "rgba(" + color.r + ", " + color.g + ", " + color.b + ", 1)";
  112. break;
  113. case "faces":
  114. faceColor = "rgba(" + color.r + ", " + color.g + ", " + color.b + ", " + faceAlpha + ")";
  115. break;
  116. }
  117. draw();
  118. }
  119. /********************************************************************
  120. * Function switching the alpha value of the faces. *
  121. * #parameters: *
  122. * percent (int): Value (0-100) of alpha. Must be processed (0-1) *
  123. * #return: nothing *
  124. ********************************************************************/
  125. function setAlpha(percent){
  126. faceAlpha = percent / 100;
  127. faceColor = faceColor.substring(0, faceColor.lastIndexOf(",") + 2) + faceAlpha + ")";
  128. draw();
  129. }
  130. /********************************************************************
  131. * Main functions, called every time a file is to be loaded. *
  132. * #parameters: *
  133. * val (string): name of the file, without path or extension. *
  134. * canv (canvas): canvas to use (Optional)
  135. * #return: nothing *
  136. ********************************************************************/
  137. function loadModel(val){
  138. loadModel(val, null);
  139. }
  140. function loadModel(file, canv){
  141. //Get file
  142. xmlhttp = new XMLHttpRequest();
  143. xmlhttp.open("GET",file, false);
  144. xmlhttp.send();
  145. var fileContent = xmlhttp.responseText;
  146. initArrays();
  147. if (canvas == null)
  148. initCanvas(canv);
  149. readVerts(fileContent);
  150. readFaces(fileContent);
  151. draw();
  152. }
  153. /********************************************************************
  154. * Function initializing the arrays obj, vert and face as empty *
  155. * arrays. *
  156. * #parameters: none *
  157. * #return: nothing *
  158. ********************************************************************/
  159. function initArrays(){
  160. obj = null;
  161. vert = null;
  162. face = null;
  163. obj = new Array();
  164. vert = new Array();
  165. face = new Array();
  166. }
  167. /********************************************************************
  168. * Function tat populates the vert[] array with and array of three *
  169. * elements, containig the coordinates, with the scale applied. *
  170. * #parameters: *
  171. * text (string): the content of the obj file. *
  172. * #return: nothing *
  173. ********************************************************************/
  174. function readVerts(text){
  175. var line;
  176. var i = 0;
  177. var max = 0;
  178. var dist;
  179. while (text.indexOf("v ") != -1){
  180. line = text.substring(text.indexOf("v "), text.indexOf("\n", text.indexOf("v ")));
  181. vert[i] = new Array(3);
  182. line = line.substring(2);
  183. vert[i][0] = line.substring(0, line.indexOf(" "));
  184. line = line.substring(line.indexOf(" ") + 1);
  185. vert[i][1] = line.substring(0, line.indexOf(" "));
  186. line = line.substring(line.indexOf(" ") + 1);
  187. vert[i][2] = line;
  188. text = text.substring(text.indexOf("v ") + 1)
  189. dist = Math.sqrt(vert[i][0] * vert[i][0] + vert[i][1] * vert[i][1] + vert[i][2] * vert[i][2]);
  190. if (dist > max)
  191. max = dist;
  192. i = i + 1;
  193. }
  194. scale = calculateScale(max);
  195. totalVert = vert.length;
  196. }
  197. /********************************************************************
  198. * Function that automatically calculates the best scale for the *
  199. * modelermined number of elements, containing the verices that *
  200. * form a face, so the bigest dimension from the object can fit in *
  201. * the smallest dimension of the canvas. *
  202. * #parameters: *
  203. * text (int): the farthest vertex, from the center. *
  204. * #return: (int) The scale to be aplied. *
  205. ********************************************************************/
  206. function calculateScale(max){
  207. var dim;
  208. if (canvas.width < canvas.height)
  209. dim = canvas.width;
  210. else
  211. dim = canvas.height;
  212. var sc = Math.round((0.95 * dim) / (2 * max));
  213. return sc;
  214. }
  215. /********************************************************************
  216. * Function that populates the face[] array with and array of an *
  217. * undetermined number of elements, containing the verices that *
  218. * form a face. *
  219. * #parameters: *
  220. * text (string): the content of the obj file. *
  221. * #return: nothing *
  222. ********************************************************************/
  223. function readFaces(text){
  224. var finish = false;
  225. var line;
  226. var i = 0;
  227. var j;
  228. while (text.indexOf("f ") != -1){
  229. line = text.substring(text.indexOf("f "), text.indexOf("\n", text.indexOf("f ")));
  230. line = line.substring(2);
  231. face[i] = new Array();
  232. j = 0;
  233. while(line.indexOf(" ") != -1){
  234. face[i][j] = line.substring(0, line.indexOf(" ")) - 1;
  235. line = line.substring(line.indexOf(" ") + 1);
  236. j = j + 1;
  237. }
  238. face[i][j] = line - 1;
  239. i = i + 1;
  240. text = text.substring(text.indexOf("f ") + 1)
  241. }
  242. totalFace = face.length;
  243. }
  244. /********************************************************************
  245. * Function that compares the average Z coordinate of two faces. *
  246. * Must be used when sorting the face array. *
  247. * #parameters: *
  248. * a (Array): One face. *
  249. * b (Array): The other face. *
  250. * #return: (int) -1, 1 or 0. *
  251. ********************************************************************/
  252. function faceComparator(a,b){
  253. var aZ;
  254. var bZ;
  255. var i = 0;
  256. var sum = 0.0;
  257. while (i < a.length){
  258. sum = sum + parseFloat(vert[a[i]][2]);
  259. i = i + 1;
  260. }
  261. aZ = sum / parseFloat(i);
  262. i = 0;
  263. sum = 0;
  264. while (i < b.length){
  265. sum = sum + parseFloat(1 * vert[b[i]][2]);
  266. i = i + 1;
  267. }
  268. bZ = sum / parseFloat(i);
  269. if (aZ < bZ) return -1;
  270. if (aZ > bZ) return 1;
  271. return 0;
  272. }
  273. /********************************************************************
  274. * Function that writes text in the corner of the canvas. Must be *
  275. * called when everithing has been drawn. *
  276. * #parameters: none *
  277. * #return: nothing *
  278. ********************************************************************/
  279. function writeCredits(){
  280. ctx.fillStyle = textColor;
  281. ctx.font = "12px Arial";
  282. var h = canvas.height / 2 - 14;
  283. var w = 10 - (canvas.height / 2);
  284. ctx.fillText("ObJS " + totalVert + " vertizes " + totalFace + " faces", w, h);
  285. }
  286. /********************************************************************
  287. * Function that draws th vertizes, faces and edges in the canvas. *
  288. * #parameters: none *
  289. * #return: nothing *
  290. ********************************************************************/
  291. function draw(){
  292. face = face.sort(faceComparator).reverse();
  293. clearCanvas();
  294. for (var i = 0; i < face.length; i++){
  295. ctx.strokeStyle = edgeColor;
  296. ctx.fillStyle = vertColor;
  297. ctx.beginPath();
  298. ctx.moveTo(scale * vert[face[i][0]][0], scale * vert[face[i][0]][1]);
  299. for (var j = 1; j < face[i].length; j++) {
  300. ctx.lineTo(scale * vert[face[i][j]][0], scale * vert[face[i][j]][1]);
  301. if(dEdges)
  302. ctx.stroke();
  303. if(dVerts){
  304. var x = scale * vert[face[i][j]][0] - (vertSize / 2);
  305. var w = vertSize;
  306. var y = scale * vert[face[i][j]][1] - (vertSize / 2);
  307. var h = vertSize;
  308. ctx.fillRect(x, y, w, h);
  309. }
  310. }
  311. ctx.closePath();
  312. ctx.fillStyle = faceColor;
  313. if(dFaces)
  314. ctx.fill();
  315. }
  316. writeCredits();
  317. }
  318. /********************************************************************
  319. * Function that rotates elements in the canvas along the Y axis, *
  320. * calculating the new position for each vertex in the vert array. *
  321. * #parameters: *
  322. * des (int): mouse displacement from the last frame. *
  323. * #return: nothing *
  324. ********************************************************************/
  325. function rotateY(des) {
  326. for (var i = 0; i < vert.length; i ++) {
  327. var x = vert[i][0];
  328. var z = vert[i][2];
  329. vert[i][0] = x * Math.cos(des / rotationSpeed) - z * Math.sin(des / rotationSpeed);
  330. vert[i][2] = z * Math.cos(des / rotationSpeed) + x * Math.sin(des / rotationSpeed);
  331. }
  332. };
  333. /********************************************************************
  334. * Function that rotates elements in the canvas along the X axis, *
  335. * calculating the new position for each vertex in the vert array. *
  336. * #parameters: *
  337. * des (int): mouse displacement from the last frame. *
  338. * #return: nothing *
  339. ********************************************************************/
  340. function rotateX(des) {
  341. for (var i = 0; i < vert.length; i ++) {
  342. var y = vert[i][1];
  343. var z = vert[i][2];
  344. vert[i][1] = y * Math.cos(des / rotationSpeed) - z * Math.sin(des / rotationSpeed);
  345. vert[i][2] = z * Math.cos(des / rotationSpeed) + y * Math.sin(des / rotationSpeed);
  346. }
  347. };
  348. /********************************************************************
  349. * Function that initializes the canvas, assignin it to the HTML *
  350. * element, and set the required mouse events. *
  351. * #parameters: none *
  352. * #return: nothing *
  353. ********************************************************************/
  354. function initCanvas(canv){
  355. if (canv!= null)
  356. canvas = canv;
  357. else
  358. canvas = document.getElementById("ObJSCanvas");
  359. ctx = canvas.getContext("2d");
  360. ctx.translate(canvas.width / 2, canvas.height / 2);
  361. canvas.onmousedown = function(e){
  362. pX = e.offsetX==undefined?e.layerX:e.offsetX;
  363. pY = e.offsetY==undefined?e.layerY:e.offsetY;
  364. mDown = true;
  365. }
  366. canvas.onmouseup = function(e){
  367. if(mDown)
  368. mouseClick(e);
  369. pX = null;
  370. pY = null;
  371. mDown = false;
  372. }
  373. canvas.onmousemove = function(e){
  374. if(!mDown)
  375. return;
  376. var x = e.offsetX==undefined?e.layerX:e.offsetX;
  377. var y = e.offsetY==undefined?e.layerY:e.offsetY;
  378. rotateY(x - pX);
  379. rotateX(y - pY);
  380. pX = x;
  381. pY = y;
  382. draw();
  383. return false;
  384. }
  385. canvas.addEventListener('mousewheel',function(event){
  386. if (event.wheelDelta > 0)
  387. zoom("-");
  388. else
  389. zoom("+");
  390. return false;
  391. }, false);
  392. }
  393. /********************************************************************
  394. * Function that changes the scale variable, witch results in a *
  395. * zoom in or zoom out effect. *
  396. * #parameters: none *
  397. * #return: nothing *
  398. ********************************************************************/
  399. function zoom(dir){
  400. if (dir == "+")
  401. scale = Math.round(scale * (1 + zoomSpeed));
  402. if (dir == "-")
  403. scale = Math.round(scale * (1 - zoomSpeed));
  404. draw();
  405. }
  406. /********************************************************************
  407. * Function that clears the canvas and gets it ready to draw on it. *
  408. * #parameters: none *
  409. * #return: nothing *
  410. ********************************************************************/
  411. function clearCanvas(){
  412. ctx.clearRect(0, 0, canvas.width, canvas.height);
  413. if (dBackg)
  414. ctx.fillStyle = backColor;
  415. else
  416. ctx.fillStyle = "#ffffff";
  417. ctx.fillRect(-canvas.width / 2, -canvas.height / 2, canvas.width, canvas.height);
  418. }
  419. /********************************************************************
  420. * TODO: Function used when something in the canvas is clicked. *
  421. * #parameters: none *
  422. * #return: nothing *
  423. ********************************************************************/
  424. function mouseClick(){
  425. }