ObJS.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. /********************************************************************
  2. * The ObJS objectnitializes the canvas, assignin it to the HTML *
  3. * element, and set the required mouse events. *
  4. * #parameters: none *
  5. * #return: nothing *
  6. ********************************************************************/
  7. function ObJS(){
  8. /********************************************************************
  9. * Parameters for costumization. *
  10. ********************************************************************/
  11. var backColor = "rgba(200, 200, 200, 1)";
  12. var vertColor = "rgba(10, 10, 10, 1)";
  13. var edgeColor = "rgba(100, 70, 70, 1)";
  14. var faceColor = "rgba(180, 180, 255, .6)";
  15. var faceAlpha = .6;
  16. var textColor = "rgba(0, 0, 0, 1)";
  17. var vertSize = 4; //Make it even: at small scales will look better
  18. var rotationSpeed = 90; //Smaller = faster. 100 is a good speed
  19. var zoomSpeed = 0.161; //0-1. 0.2 or 0.3 are good speeds
  20. var moveSpeed = .5;
  21. /********************************************************************
  22. * Variable containing this object, to be refered from nested *
  23. * functions. *
  24. ********************************************************************/
  25. var thisObJS;
  26. /********************************************************************
  27. * Parameter used to scale the measures in the .obj file. Can be *
  28. * integer or float, greater than 0. 50 is a good default. *
  29. ********************************************************************/
  30. var scale;
  31. /********************************************************************
  32. * Variable to determine if the canvas has been initialized. *
  33. ********************************************************************/
  34. var canvasInitialized = false;
  35. /********************************************************************
  36. * Variable to determine if the mouse button is being holded down. *
  37. ********************************************************************/
  38. var mDown = false;
  39. var pinch = false;
  40. var pinchScale = 0;
  41. /********************************************************************
  42. * Variables containing the canvas and its context. *
  43. ********************************************************************/
  44. var canvas;
  45. var ctx;
  46. /********************************************************************
  47. * Variables containing the number of elements. *
  48. ********************************************************************/
  49. var totalVert;
  50. var totalMaterial = 0;
  51. var totalFace
  52. /********************************************************************
  53. * Arrays containing the vertices, faces and materials. *
  54. ********************************************************************/
  55. var material;
  56. var vert;
  57. var face;
  58. /********************************************************************
  59. * Booleans to determine wich elements are to draw. *
  60. ********************************************************************/
  61. var dVerts = true;
  62. var dEdges = true;
  63. var dFaces = true;
  64. var dBackg = true;
  65. /********************************************************************
  66. * Booleans to indicate if mtl file should be used. *
  67. ********************************************************************/
  68. var hasMtl = true;
  69. var useMtl = true;
  70. /********************************************************************
  71. * Global variables that will contain the position of the mouse in *
  72. * the previous frame to calculate rotation. *
  73. ********************************************************************/
  74. var pX = null;
  75. var pY = null;
  76. /********************************************************************
  77. * Function that initializes the canvas, assignin it to the HTML *
  78. * element, and set the required mouse events. *
  79. * #parameters: *
  80. * canv (canvas): canvas to use. If omited, the one named *
  81. * named "ObJSCanvas" will be used. *
  82. * #return: nothing *
  83. * #scope: public *
  84. ********************************************************************/
  85. this.initCanvas = function(canv){
  86. if (!canvasInitialized){
  87. if (canv!= null)
  88. canvas = canv;
  89. else
  90. canvas = document.getElementById("ObJSCanvas");
  91. ctx = canvas.getContext("2d");
  92. ctx.translate(canvas.width / 2, canvas.height / 2);
  93. canvas.onmousedown = function(e){
  94. pX = e.offsetX==undefined?e.layerX:e.offsetX;
  95. pY = e.offsetY==undefined?e.layerY:e.offsetY;
  96. mDown = true;
  97. };
  98. canvas.onmouseup = function(e){
  99. if(mDown)
  100. mouseClick(e);
  101. pX = null;
  102. pY = null;
  103. mDown = false;
  104. };
  105. canvas.onmousemove = function(e){
  106. if(!mDown)
  107. return;
  108. var x = e.offsetX==undefined?e.layerX:e.offsetX;
  109. var y = e.offsetY==undefined?e.layerY:e.offsetY;
  110. if (e.shiftKey){
  111. thisObJS.moveHorizontal(x - pX);
  112. thisObJS.moveVertical(y - pY);
  113. }
  114. else{
  115. thisObJS.rotateY(x - pX);
  116. thisObJS.rotateX(y - pY);
  117. }
  118. pX = x;
  119. pY = y;
  120. return false;
  121. };
  122. canvas.onmouseout = function(e){
  123. if(mDown)
  124. mDown = false;
  125. }
  126. canvas.addEventListener('mousewheel',function(e){
  127. e.preventDefault();
  128. if (event.wheelDelta > 0)
  129. thisObJS.zoom(1);
  130. else
  131. thisObJS.zoom(-1);
  132. return false;
  133. }, false);
  134. canvas.addEventListener('touchstart',function(e){
  135. if(e.touches.length == 2) {
  136. pinch = true;
  137. pinchScale = Math.sqrt((e.touches[0].clientX-e.touches[1].clientX) * (e.touches[0].clientX-e.touches[1].clientX) + (e.touches[0].clientY-e.touches[1].clientY) * (e.touches[0].clientY-e.touches[1].clientY));
  138. }
  139. return false;
  140. }, false);
  141. canvas.addEventListener('touchend',function(e){
  142. if(pinch)
  143. pinch = false;
  144. return false;
  145. }, false);
  146. canvas.addEventListener('touchcancel',function(e){
  147. if(pinch)
  148. pinch = false;
  149. return false;
  150. }, false);
  151. canvas.addEventListener('touchleave',function(e){
  152. if(pinch)
  153. pinch = false;
  154. return false;
  155. }, false);
  156. canvas.addEventListener('touchmove',function(e){
  157. e.preventDefault();
  158. if(pinch){
  159. var dist = Math.sqrt((e.touches[0].clientX-e.touches[1].clientX) * (e.touches[0].clientX-e.touches[1].clientX) + (e.touches[0].clientY-e.touches[1].clientY) * (e.touches[0].clientY-e.touches[1].clientY));
  160. if (dist > pinchScale)
  161. thisObJS.zoom(1);
  162. else if (dist < pinchScale)
  163. thisObJS.zoom(-1);
  164. pinchScale = dist;
  165. }
  166. else{
  167. var x = e.touches[0].clientX
  168. var y = e.touches[0].clientY;
  169. thisObJS.rotateY(x - pX);
  170. thisObJS.rotateX(y - pY);
  171. pX = x;
  172. pY = y;
  173. }
  174. return false;
  175. }, false);
  176. canvasInitialized = true;
  177. }
  178. };
  179. /********************************************************************
  180. * Main function, called every time a file is to be loaded. *
  181. * #parameters: *
  182. * file (string): name of the file, without path or extension. *
  183. * #return: nothing *
  184. * #scope: public *
  185. ********************************************************************/
  186. this.load = function(file){
  187. if(!canvasInitialized)
  188. initCanvas();
  189. //Get obj file
  190. var xmlhttp = new XMLHttpRequest();
  191. xmlhttp.open("GET", file, false);
  192. xmlhttp.send();
  193. var fileContent = xmlhttp.responseText;
  194. //Get mtl file
  195. xmlhttp = new XMLHttpRequest();
  196. xmlhttp.open("GET",file.substring(0, file.lastIndexOf(".")) + ".mtl", false);
  197. xmlhttp.send();
  198. var mtlContent = xmlhttp.responseText;
  199. initArrays();
  200. readFile(fileContent);
  201. readMtlFile(mtlContent);
  202. draw();
  203. };
  204. /********************************************************************
  205. * Getters that determine if an element is being drawn. *
  206. ********************************************************************/
  207. this.isBackgroundDrawn = function(){
  208. return dBackg;
  209. };
  210. this.isVertexDrawn = function(){
  211. return dVerts;
  212. };
  213. this.isEdgeDrawn = function(){
  214. return dEdges;
  215. };
  216. this.isFaceDrawn = function(){
  217. return dFaces;
  218. };
  219. this.isMaterialUsed = function(){
  220. return useMtl;
  221. };
  222. /********************************************************************
  223. * Getters that determine if the model has associated materials. *
  224. ********************************************************************/
  225. this.hasMaterial = function(){
  226. return hasMtl;
  227. };
  228. /********************************************************************
  229. * Getters for the color of the elements. *
  230. ********************************************************************/
  231. this.getBackgroundColor = function (){
  232. var str = backColor;
  233. var r = str.substring(5, str.indexOf(', '));
  234. str = str.substring(str.indexOf(', ') + 2);
  235. var g = str.substring(0, str.indexOf(', '));
  236. str = str.substring(str.indexOf(', ') + 2);
  237. var b = str.substring(0, str.indexOf(', '));
  238. var a = 1;
  239. return {red: r, green: g, blue: b, alpha: a};
  240. };
  241. this.getVertexColor = function (){
  242. var str = vertColor;
  243. var r = str.substring(5, str.indexOf(', '));
  244. str = str.substring(str.indexOf(', ') + 2);
  245. var g = str.substring(0, str.indexOf(', '));
  246. str = str.substring(str.indexOf(', ') + 2);
  247. var b = str.substring(0, str.indexOf(', '));
  248. var a = 1;
  249. return {red: r, green: g, blue: b, alpha: a};
  250. };
  251. this.getEdgeColor = function (){
  252. var str = edgeColor;
  253. var r = str.substring(5, str.indexOf(', '));
  254. str = str.substring(str.indexOf(', ') + 2);
  255. var g = str.substring(0, str.indexOf(', '));
  256. str = str.substring(str.indexOf(', ') + 2);
  257. var b = str.substring(0, str.indexOf(', '));
  258. var a = 1;
  259. return {red: r, green: g, blue: b, alpha: a};
  260. };
  261. this.getFaceColor = function (){
  262. var str = faceColor;
  263. var r = str.substring(5, str.indexOf(', '));
  264. str = str.substring(str.indexOf(', ') + 2);
  265. var g = str.substring(0, str.indexOf(', '));
  266. str = str.substring(str.indexOf(', ') + 2);
  267. var b = str.substring(0, str.indexOf(', '));
  268. str = str.substring(str.indexOf(', ') + 2);
  269. var a = str.substring(0, str.indexOf(')'));
  270. return {red: r, green: g, blue: b, alpha: a};
  271. };
  272. /********************************************************************
  273. * Functions switching the elements drawn (dVerts, dEdges, dFaces). *
  274. * #parameters: *
  275. * on (boolean): indicating if the element is to be drawn. *
  276. * #return: nothing *
  277. * #scope: public *
  278. ********************************************************************/
  279. this.drawVertices = function(on){
  280. if (on == true || on == false){
  281. dVerts = on;
  282. draw();
  283. }
  284. };
  285. this.drawEdges = function(on){
  286. if (on == true || on == false){
  287. dEdges = on;
  288. draw();
  289. }
  290. };
  291. this.drawFaces = function(on){
  292. if (on == true || on == false){
  293. dFaces = on;
  294. draw();
  295. }
  296. };
  297. this.drawBackground = function(on){
  298. if (on == true || on == false){
  299. dBackg = on;
  300. draw();
  301. }
  302. };
  303. /********************************************************************
  304. * Functions switching the color of the elements. *
  305. * #parameters: *
  306. * code (string): hex color value, in #fff or #ffffff form. If *
  307. * wrong, a message will be printed to console, *
  308. * and nothing will be changed. *
  309. * #return: nothing *
  310. * #scope: public *
  311. ********************************************************************/
  312. this.setVerticesColor = function(code){
  313. if (isColor(code)){
  314. var color = hexToRgb(code);
  315. vertColor = "rgba(" + color.r + ", " + color.g + ", " + color.b + ", 1)";
  316. draw();
  317. }
  318. else
  319. console.log("setVerticesColor(" + code + ") ERROR: " + code + " not a valid hex color");
  320. };
  321. this.setEdgesColor = function(code){
  322. if (isColor(code)){
  323. var color = hexToRgb(code);
  324. edgeColor = "rgba(" + color.r + ", " + color.g + ", " + color.b + ", 1)";
  325. draw();
  326. }
  327. else
  328. console.log("setEdgesColor(" + code + ") ERROR: " + code + " not a valid hex color");
  329. };
  330. this.setFacesColor = function(code){
  331. if (isColor(code)){
  332. var color = hexToRgb(code);
  333. faceColor = "rgba(" + color.r + ", " + color.g + ", " + color.b + ", 1)";
  334. draw();
  335. }
  336. else
  337. console.log("setFacesColor(" + code + ") ERROR: " + code + " not a valid hex color");
  338. };
  339. this.setBackgroundColor = function(code){
  340. if (isColor(code)){
  341. var color = hexToRgb(code);
  342. backColor = "rgba(" + color.r + ", " + color.g + ", " + color.b + ", 1)";
  343. draw();
  344. }
  345. else
  346. console.log("setBackgroundColor(" + code + ") ERROR: " + code + " not a valid hex color");
  347. };
  348. /********************************************************************
  349. * Function switching the use of mtl file for color. *
  350. * #parameters: *
  351. * value (boolean): indicating if the element is to be drawn. *
  352. * #return: nothing *
  353. * #scope: public *
  354. ********************************************************************/
  355. this.linkMaterial = function(value){
  356. useMtl = value;
  357. draw();
  358. }
  359. /********************************************************************
  360. * Function switching the alpha value of the faces. *
  361. * #parameters: *
  362. * percent (int): Value (0-100) of alpha. Must be processed (0-1) *
  363. * #return: nothing *
  364. * #scope: public *
  365. ********************************************************************/
  366. this.setAlpha = function(percent){
  367. if (percent >= 0 && percent <= 100){
  368. faceAlpha = percent / 100;
  369. faceColor = faceColor.substring(0, faceColor.lastIndexOf(",") + 2) + faceAlpha + ")";
  370. draw();
  371. }
  372. else
  373. console.log("setAlpha(" + percent + "); ERROR: Only values between 0 and 100 are allowed");
  374. };
  375. /********************************************************************
  376. * Function switching the rotation speed. *
  377. * #parameters: *
  378. * percent (int): Value (0-10) of speed. *
  379. * #return: nothing *
  380. * #scope: public *
  381. ********************************************************************/
  382. this.setRotationSpeed = function(percent){
  383. if (percent >= 0 && percent <= 10){
  384. rotationSpeed = Math.round((10 - percent) * 30);
  385. if (rotationSpeed == 0)
  386. rotationSpeed = 1;
  387. }
  388. else
  389. console.log("setRotationSpeed(" + percent + "); ERROR: Only values between 0 and 10 are allowed");
  390. }
  391. /********************************************************************
  392. * Functions that rotate elements in the canvas along the *
  393. * correspondent axys, calculating the new position for each vertex *
  394. * in the vert array. *
  395. * #parameters: *
  396. * des (int): distance to rotate. *
  397. * #return: nothing *
  398. * #scope: public *
  399. ********************************************************************/
  400. this.rotateY = function(des){
  401. for (var i = 0; i < vert.length; i ++) {
  402. var x = vert[i][0];
  403. var z = vert[i][2];
  404. vert[i][0] = x * Math.cos(des / rotationSpeed) - z * Math.sin(des / rotationSpeed);
  405. vert[i][2] = z * Math.cos(des / rotationSpeed) + x * Math.sin(des / rotationSpeed);
  406. }
  407. draw();
  408. };
  409. this.rotateX = function(des){
  410. for (var i = 0; i < vert.length; i ++) {
  411. var y = vert[i][1];
  412. var z = vert[i][2];
  413. vert[i][1] = y * Math.cos(des / rotationSpeed) - z * Math.sin(des / rotationSpeed);
  414. vert[i][2] = z * Math.cos(des / rotationSpeed) + y * Math.sin(des / rotationSpeed);
  415. }
  416. draw();
  417. };
  418. /********************************************************************
  419. * Function switching the movement speed of the model. *
  420. * #parameters: *
  421. * percent (int): Value (0-10) of speed. *
  422. * #return: nothing *
  423. * #scope: public *
  424. ********************************************************************/
  425. this.setMovementSpeed = function(percent){
  426. if (percent >= 0 && percent <= 10)
  427. moveSpeed = ((percent * 0.8) / 10) + 0.01;
  428. else
  429. console.log("setMoveSpeed(" + percent + "); ERROR: Only values between 0 and 10 are allowed");
  430. }
  431. /********************************************************************
  432. * Functions that move elements in the canvas along the selected *
  433. * direction, calculating the new position for each vertex in the *
  434. * vert array. *
  435. * #parameters: *
  436. * des (int): distance to move. *
  437. * #return: nothing *
  438. * #scope: public *
  439. ********************************************************************/
  440. this.moveVertical = function(des){
  441. for (var i = 0; i < vert.length; i ++)
  442. vert[i][1] = (vert[i][1] * 1) + des * (moveSpeed / 50);
  443. draw();
  444. };
  445. this.moveHorizontal = function(des){
  446. for (var i = 0; i < vert.length; i ++)
  447. vert[i][0] = (vert[i][0] * 1) + des * (moveSpeed / 50);
  448. draw();
  449. };
  450. /********************************************************************
  451. * Function switching the zoom speede of the faces. *
  452. * #parameters: *
  453. * percent (int): Value (0-100) of speed. *
  454. * #return: nothing *
  455. * #scope: public *
  456. ********************************************************************/
  457. this.setZoomSpeed = function(percent){
  458. if (percent >= 0 && percent <= 10)
  459. zoomSpeed = ((percent * 0.8) / 10) + 0.01;
  460. else
  461. console.log("setZoomSpeed(" + percent + "); ERROR: Only values between 0 and 10 are allowed");
  462. }
  463. /********************************************************************
  464. * Function that changes the scale variable, witch results in a *
  465. * zoom in or zoom out effect. *
  466. * #parameters: none *
  467. * #return: nothing *
  468. * #scope: public *
  469. ********************************************************************/
  470. this.zoom = function(val){
  471. scale = scale + val * scale * zoomSpeed;
  472. draw();
  473. };
  474. /********************************************************************
  475. * Function that clears the arrays and the canvas. Use to unload a *
  476. * model. *
  477. * #parameters: none *
  478. * #return: nothing *
  479. * #scope: public *
  480. ********************************************************************/
  481. this.clear = function(){
  482. initArrays();
  483. clearCanvas();
  484. };
  485. /********************************************************************
  486. * Function that turns a hex color code in RGB. *
  487. * stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb *
  488. * #parameters: *
  489. * hex (string): color code, for example "#33ff99" *
  490. * #return: (Array) r, g, b, with their correspondent color. *
  491. * #scope: private *
  492. ********************************************************************/
  493. var hexToRgb = function(hex) {
  494. var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  495. return result ? {
  496. r: parseInt(result[1], 16),
  497. g: parseInt(result[2], 16),
  498. b: parseInt(result[3], 16)
  499. } : null;
  500. };
  501. /********************************************************************
  502. * Function that checks if a string is a valid hexadecimal color *
  503. * code, in the format '#ffffff' or '#fff' *
  504. * #parameters: *
  505. * code (string): Code to check. *
  506. * #return: (Boolean) True if valid color code, false otherwise. *
  507. * #scope: private *
  508. ********************************************************************/
  509. var isColor = function(code){
  510. if (code[0] != '#')
  511. return false;
  512. if (code.length != 4 && code.length != 7)
  513. return false
  514. for (var i = 1; i < code.length; i ++)
  515. if (code[i] < '0' || (code[i] > 9 && code[i] < 'A') || (code[i] > 'Z' && code[i] < 'a') || code[i] > 'z')
  516. return false;
  517. return true;
  518. };
  519. /********************************************************************
  520. * Function that clears the canvas and gets it ready to draw on it. *
  521. * #parameters: none *
  522. * #return: nothing *
  523. * #scope: private *
  524. ********************************************************************/
  525. var clearCanvas = function(){
  526. ctx.clearRect(0, 0, canvas.width, canvas.height);
  527. if (dBackg)
  528. ctx.fillStyle = backColor;
  529. else
  530. ctx.fillStyle = "#ffffff";
  531. ctx.fillRect(-canvas.width / 2, -canvas.height / 2, canvas.width, canvas.height);
  532. };
  533. /********************************************************************
  534. * Function initializing the arrays obj, vert and face as empty *
  535. * arrays. *
  536. * #parameters: none *
  537. * #return: nothing *
  538. * #scope: private *
  539. ********************************************************************/
  540. var initArrays = function(){
  541. material = null;
  542. vert = null;
  543. face = null;
  544. material = new Array();
  545. vert = new Array();
  546. face = new Array();
  547. };
  548. /********************************************************************
  549. * Function tat populates the vert[] array with and array of three *
  550. * elements, containig the coordinates, and the face[] array with *
  551. * the vertices forming the face, plus one element indicating the *
  552. * codename of the material. *
  553. * #parameters: *
  554. * text (string): the content of the obj file. *
  555. * #return: nothing *
  556. * #scope: private *
  557. ********************************************************************/
  558. var readFile = function(text){
  559. var line;
  560. var v = 0;
  561. var f = 0;
  562. var m = 0;
  563. var max = 0;
  564. var j;
  565. var dist;
  566. var fac;
  567. var mat = "null";
  568. text = text + "\n";
  569. while (text.indexOf("\n") != -1){
  570. line = text.substring(0, text.indexOf("\n"));
  571. if (line.substring(0, 2) == "v "){
  572. vert[v] = new Array(3);
  573. line = line.substring(2);
  574. vert[v][0] = line.substring(0, line.indexOf(" "));
  575. line = line.substring(line.indexOf(" ") + 1);
  576. vert[v][1] = line.substring(0, line.indexOf(" "));
  577. line = line.substring(line.indexOf(" ") + 1);
  578. vert[v][2] = line;
  579. dist = Math.sqrt(vert[v][0] * vert[v][0] + vert[v][1] * vert[v][1] + vert[v][2] * vert[v][2]);
  580. if (dist > max)
  581. max = dist;
  582. v = v + 1;
  583. }
  584. else if (line.substring(0,2) == "f "){
  585. line = line.substring(2);
  586. face[f] = new Array();
  587. j = 0;
  588. while(line.indexOf(" ") != -1){
  589. face[f][j] = line.substring(0, line.indexOf(" "));
  590. if (face[f][j].indexOf('/') != -1)
  591. face[f][j] = face[f][j].substring(0, face[f][j].indexOf('/'));
  592. face[f][j] = face[f][j] - 1;
  593. line = line.substring(line.indexOf(" ") + 1);
  594. j = j + 1;
  595. }
  596. face[f][j] = line;
  597. if (face[f][j].indexOf('/') != -1)
  598. face[f][j] = face[f][j].substring(0, face[f][j].indexOf('/'));
  599. face[f][j] = face[f][j] - 1;
  600. face[f][j + 1] = mat;
  601. f = f + 1;
  602. }
  603. else if (line.substring(0, 6) == "usemtl"){
  604. mat = line.substring(7);
  605. }
  606. text = text.substring(text.indexOf("\n") + 1);
  607. }
  608. scale = calculateScale(max);
  609. totalVert = vert.length;
  610. totalFace = face.length;
  611. };
  612. /********************************************************************
  613. * Function tat populates the material[] array with an array *
  614. * containig, four values: the material name, and the three RGB *
  615. * values. *
  616. * #parameters: *
  617. * text (string): the content of the mtl file. *
  618. * #return: nothing *
  619. * #scope: private *
  620. ********************************************************************/
  621. var readMtlFile = function(text){
  622. text = text + "\n";
  623. i = -1;
  624. while (text.indexOf("\n") != -1){
  625. line = text.substring(0, text.indexOf("\n"));
  626. if (line.substring(0, 6) == "newmtl"){
  627. i = i + 1;
  628. material[i] = new Array(4);
  629. material[i][0] = line.substring(line.indexOf(" ") + 1);
  630. }
  631. //Kd, ddifuse color, usefull
  632. //Ka, ambient color, not now
  633. //Ks, specular color, not now
  634. //d or TR, transparency, not now
  635. else if (line.substring(0, 3) == "Kd "){
  636. line = line.substring(3);
  637. material[i][1] = line.substring(0, line.indexOf(" "));
  638. line = line.substring(line.indexOf(" ") + 1);
  639. material[i][2] = line.substring(0, line.indexOf(" "));
  640. line = line.substring(line.indexOf(" ") + 1);
  641. material[i][3] = line;
  642. }
  643. text = text.substring(text.indexOf("\n") + 1);
  644. }
  645. totalMaterial = material.length;
  646. if (totalMaterial == 0)
  647. hasMtl = false;
  648. };
  649. /********************************************************************
  650. * Function that automatically calculates the best scale for the *
  651. * modelermined number of elements, containing the verices that *
  652. * form a face, so the bigest dimension from the object can fit in *
  653. * the smallest dimension of the canvas. *
  654. * #parameters: *
  655. * text (int): the farthest vertex, from the center. *
  656. * #return: (int) The scale to be aplied. *
  657. * #scope: private *
  658. ********************************************************************/
  659. var calculateScale = function(max){
  660. var dim;
  661. if (canvas.width < canvas.height)
  662. dim = canvas.width;
  663. else
  664. dim = canvas.height;
  665. var sc = Math.round((0.95 * dim) / (2 * max));
  666. return sc;
  667. };
  668. /********************************************************************
  669. * Function that compares the average Z coordinate of two faces. *
  670. * Must be used when sorting the face array. *
  671. * #parameters: *
  672. * a (Array): One face. *
  673. * b (Array): The other face. *
  674. * #return: (int) -1, 1 or 0. *
  675. * #scope: private *
  676. ********************************************************************/
  677. var faceComparator = function(a,b){
  678. var aZ;
  679. var bZ;
  680. var i = 0;
  681. var sum = 0.0;
  682. while (i < a.length - 1){
  683. sum = sum + parseFloat(vert[a[i]][2]);
  684. i = i + 1;
  685. }
  686. aZ = sum / parseFloat(i);
  687. i = 0;
  688. sum = 0;
  689. while (i < b.length - 1){
  690. sum = sum + parseFloat(1 * vert[b[i]][2]);
  691. i = i + 1;
  692. }
  693. bZ = sum / parseFloat(i);
  694. if (aZ < bZ) return -1;
  695. if (aZ > bZ) return 1;
  696. return 0;
  697. };
  698. /********************************************************************
  699. * Function that writes text in the corner of the canvas. Must be *
  700. * called when everithing has been drawn. *
  701. * #parameters: none *
  702. * #return: nothing *
  703. * #scope: private *
  704. ********************************************************************/
  705. var writeCredits = function(){
  706. ctx.fillStyle = textColor;
  707. ctx.font = "12px Arial";
  708. var h = canvas.height / 2 - 14;
  709. var w = 10 - (canvas.width / 2);
  710. ctx.fillText("ObJS: " + totalVert + " vertices " + totalFace + " faces " + totalMaterial + " materials", w, h);
  711. };
  712. /********************************************************************
  713. * Function that draws th vertices, faces and edges in the canvas. *
  714. * #parameters: none *
  715. * #return: nothing *
  716. * #scope: private *
  717. ********************************************************************/
  718. var draw = function(){
  719. face = face.sort(faceComparator).reverse();
  720. clearCanvas();
  721. for (var i = 0; i < face.length; i++){
  722. ctx.strokeStyle = edgeColor;
  723. ctx.fillStyle = vertColor;
  724. ctx.beginPath();
  725. ctx.moveTo(scale * vert[face[i][0]][0], scale * vert[face[i][0]][1]);
  726. for (var j = 1; j < face[i].length - 1; j++) {
  727. ctx.lineTo(scale * vert[face[i][j]][0], scale * vert[face[i][j]][1]);
  728. if(dEdges)
  729. ctx.stroke();
  730. if(dVerts){
  731. var x = scale * vert[face[i][j]][0] - (vertSize / 2);
  732. var w = vertSize;
  733. var y = scale * vert[face[i][j]][1] - (vertSize / 2);
  734. var h = vertSize;
  735. ctx.fillRect(x, y, w, h);
  736. }
  737. }
  738. ctx.closePath();
  739. if (useMtl){
  740. //Get material with the same name as the one in the last element of the face
  741. j = 0;
  742. while (material[j][0] != face[i][face[i].length - 1] && j < material.length)
  743. j = j + 1;
  744. if (material[j][0] == face[i][face[i].length - 1])
  745. ctx.fillStyle = "rgba(" + Math.round(255 * material[j][1]) + ", " + Math.round(255 * material[j][2]) + ", " + Math.round(255 * material[j][3]) + ", " + faceAlpha + ")";
  746. else
  747. ctx.fillStyle = faceColor;
  748. }
  749. else
  750. ctx.fillStyle = faceColor;
  751. if(dFaces)
  752. ctx.fill();
  753. }
  754. writeCredits();
  755. };
  756. /********************************************************************
  757. * TODO: Function used when something in the canvas is clicked. *
  758. * #parameters: none *
  759. * #return: nothing *
  760. * #scope: private *
  761. ********************************************************************/
  762. var mouseClick = function(){
  763. };
  764. thisObJS = this;
  765. return this;
  766. }