ObJS.js 17 KB

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