Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

glm.c 53KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917
  1. /*
  2. * GLM library. Wavefront .obj file format reader/writer/manipulator.
  3. *
  4. * Written by Nate Robins, 1997.
  5. * email: ndr@pobox.com
  6. * www: http://www.pobox.com/~ndr
  7. */
  8. /* includes */
  9. #include <math.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <assert.h>
  14. #include "glm.h"
  15. #include "readtex.h"
  16. typedef unsigned char boolean;
  17. #define TRUE 1
  18. #define FALSE 0
  19. /* Some <math.h> files do not define M_PI... */
  20. #ifndef M_PI
  21. #define M_PI 3.14159265358979323846
  22. #endif
  23. /* defines */
  24. #define T(x) model->triangles[(x)]
  25. /* enums */
  26. enum { X, Y, Z, W }; /* elements of a vertex */
  27. /* typedefs */
  28. /* _GLMnode: general purpose node
  29. */
  30. typedef struct _GLMnode {
  31. uint index;
  32. boolean averaged;
  33. struct _GLMnode* next;
  34. } GLMnode;
  35. /* strdup is actually not a standard ANSI C or POSIX routine
  36. so implement a private one. OpenVMS does not have a strdup; Linux's
  37. standard libc doesn't declare strdup by default (unless BSD or SVID
  38. interfaces are requested). */
  39. static char *
  40. stralloc(const char *string)
  41. {
  42. char *copy;
  43. copy = malloc(strlen(string) + 1);
  44. if (copy == NULL)
  45. return NULL;
  46. strcpy(copy, string);
  47. return copy;
  48. }
  49. /* private functions */
  50. /* _glmMax: returns the maximum of two floats */
  51. static float
  52. _glmMax(float a, float b)
  53. {
  54. if (a > b)
  55. return a;
  56. return b;
  57. }
  58. /* _glmAbs: returns the absolute value of a float */
  59. static float
  60. _glmAbs(float f)
  61. {
  62. if (f < 0)
  63. return -f;
  64. return f;
  65. }
  66. /* _glmDot: compute the dot product of two vectors
  67. *
  68. * u - array of 3 floats (float u[3])
  69. * v - array of 3 floats (float v[3])
  70. */
  71. static float
  72. _glmDot(float* u, float* v)
  73. {
  74. assert(u);
  75. assert(v);
  76. /* compute the dot product */
  77. return u[X] * v[X] + u[Y] * v[Y] + u[Z] * v[Z];
  78. }
  79. /* _glmCross: compute the cross product of two vectors
  80. *
  81. * u - array of 3 floats (float u[3])
  82. * v - array of 3 floats (float v[3])
  83. * n - array of 3 floats (float n[3]) to return the cross product in
  84. */
  85. static void
  86. _glmCross(float* u, float* v, float* n)
  87. {
  88. assert(u);
  89. assert(v);
  90. assert(n);
  91. /* compute the cross product (u x v for right-handed [ccw]) */
  92. n[X] = u[Y] * v[Z] - u[Z] * v[Y];
  93. n[Y] = u[Z] * v[X] - u[X] * v[Z];
  94. n[Z] = u[X] * v[Y] - u[Y] * v[X];
  95. }
  96. /* _glmNormalize: normalize a vector
  97. *
  98. * n - array of 3 floats (float n[3]) to be normalized
  99. */
  100. static void
  101. _glmNormalize(float* n)
  102. {
  103. float l;
  104. assert(n);
  105. /* normalize */
  106. l = (float)sqrt(n[X] * n[X] + n[Y] * n[Y] + n[Z] * n[Z]);
  107. n[0] /= l;
  108. n[1] /= l;
  109. n[2] /= l;
  110. }
  111. /* _glmEqual: compares two vectors and returns TRUE if they are
  112. * equal (within a certain threshold) or FALSE if not. An epsilon
  113. * that works fairly well is 0.000001.
  114. *
  115. * u - array of 3 floats (float u[3])
  116. * v - array of 3 floats (float v[3])
  117. */
  118. static boolean
  119. _glmEqual(float* u, float* v, float epsilon)
  120. {
  121. if (_glmAbs(u[0] - v[0]) < epsilon &&
  122. _glmAbs(u[1] - v[1]) < epsilon &&
  123. _glmAbs(u[2] - v[2]) < epsilon)
  124. {
  125. return TRUE;
  126. }
  127. return FALSE;
  128. }
  129. /* _glmWeldVectors: eliminate (weld) vectors that are within an
  130. * epsilon of each other.
  131. *
  132. * vectors - array of float[3]'s to be welded
  133. * numvectors - number of float[3]'s in vectors
  134. * epsilon - maximum difference between vectors
  135. *
  136. */
  137. static float*
  138. _glmWeldVectors(float* vectors, uint* numvectors, float epsilon)
  139. {
  140. float* copies;
  141. uint copied;
  142. uint i, j;
  143. copies = (float*)malloc(sizeof(float) * 3 * (*numvectors + 1));
  144. memcpy(copies, vectors, (sizeof(float) * 3 * (*numvectors + 1)));
  145. copied = 1;
  146. for (i = 1; i <= *numvectors; i++) {
  147. for (j = 1; j <= copied; j++) {
  148. if (_glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) {
  149. goto duplicate;
  150. }
  151. }
  152. /* must not be any duplicates -- add to the copies array */
  153. copies[3 * copied + 0] = vectors[3 * i + 0];
  154. copies[3 * copied + 1] = vectors[3 * i + 1];
  155. copies[3 * copied + 2] = vectors[3 * i + 2];
  156. j = copied; /* pass this along for below */
  157. copied++;
  158. duplicate:
  159. /* set the first component of this vector to point at the correct
  160. index into the new copies array */
  161. vectors[3 * i + 0] = (float)j;
  162. }
  163. *numvectors = copied-1;
  164. return copies;
  165. }
  166. /* _glmFindGroup: Find a group in the model
  167. */
  168. static GLMgroup*
  169. _glmFindGroup(GLMmodel* model, char* name)
  170. {
  171. GLMgroup* group;
  172. assert(model);
  173. group = model->groups;
  174. while(group) {
  175. if (!strcmp(name, group->name))
  176. break;
  177. group = group->next;
  178. }
  179. return group;
  180. }
  181. /* _glmAddGroup: Add a group to the model
  182. */
  183. static GLMgroup*
  184. _glmAddGroup(GLMmodel* model, char* name)
  185. {
  186. GLMgroup* group;
  187. group = _glmFindGroup(model, name);
  188. if (!group) {
  189. group = (GLMgroup*)malloc(sizeof(GLMgroup));
  190. group->name = stralloc(name);
  191. group->material = 0;
  192. group->numtriangles = 0;
  193. group->triangles = NULL;
  194. group->next = model->groups;
  195. model->groups = group;
  196. model->numgroups++;
  197. }
  198. return group;
  199. }
  200. /* _glmFindGroup: Find a material in the model
  201. */
  202. static uint
  203. _glmFindMaterial(GLMmodel* model, char* name)
  204. {
  205. uint i;
  206. for (i = 0; i < model->nummaterials; i++) {
  207. if (!strcmp(model->materials[i].name, name))
  208. goto found;
  209. }
  210. /* didn't find the name, so set it as the default material */
  211. printf("_glmFindMaterial(): can't find material \"%s\".\n", name);
  212. i = 0;
  213. found:
  214. return i;
  215. }
  216. /* _glmDirName: return the directory given a path
  217. *
  218. * path - filesystem path
  219. *
  220. * The return value should be free'd.
  221. */
  222. static char*
  223. _glmDirName(char* path)
  224. {
  225. char* dir;
  226. char* s;
  227. dir = stralloc(path);
  228. s = strrchr(dir, '/');
  229. if (s)
  230. s[1] = '\0';
  231. else
  232. dir[0] = '\0';
  233. return dir;
  234. }
  235. /* _glmReadMTL: read a wavefront material library file
  236. *
  237. * model - properly initialized GLMmodel structure
  238. * name - name of the material library
  239. */
  240. static void
  241. _glmReadMTL(GLMmodel* model, char* name)
  242. {
  243. FILE* file;
  244. char* dir;
  245. char* filename;
  246. char buf[128], buf2[128];
  247. uint nummaterials, i;
  248. GLMmaterial *mat;
  249. dir = _glmDirName(model->pathname);
  250. filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1));
  251. strcpy(filename, dir);
  252. strcat(filename, name);
  253. free(dir);
  254. /* open the file */
  255. file = fopen(filename, "r");
  256. if (!file) {
  257. fprintf(stderr, "_glmReadMTL() failed: can't open material file \"%s\".\n",
  258. filename);
  259. exit(1);
  260. }
  261. free(filename);
  262. /* count the number of materials in the file */
  263. nummaterials = 1;
  264. while(fscanf(file, "%s", buf) != EOF) {
  265. switch(buf[0]) {
  266. case '#': /* comment */
  267. /* eat up rest of line */
  268. fgets(buf, sizeof(buf), file);
  269. break;
  270. case 'n': /* newmtl */
  271. fgets(buf, sizeof(buf), file);
  272. nummaterials++;
  273. sscanf(buf, "%s %s", buf, buf);
  274. break;
  275. default:
  276. /* eat up rest of line */
  277. fgets(buf, sizeof(buf), file);
  278. break;
  279. }
  280. }
  281. rewind(file);
  282. /* allocate memory for the materials */
  283. model->materials = (GLMmaterial*)calloc(nummaterials, sizeof(GLMmaterial));
  284. model->nummaterials = nummaterials;
  285. /* set the default material */
  286. for (i = 0; i < nummaterials; i++) {
  287. model->materials[i].name = NULL;
  288. model->materials[i].shininess = 0;
  289. model->materials[i].diffuse[0] = 0.8;
  290. model->materials[i].diffuse[1] = 0.8;
  291. model->materials[i].diffuse[2] = 0.8;
  292. model->materials[i].diffuse[3] = 1.0;
  293. model->materials[i].ambient[0] = 0.2;
  294. model->materials[i].ambient[1] = 0.2;
  295. model->materials[i].ambient[2] = 0.2;
  296. model->materials[i].ambient[3] = 0.0;
  297. model->materials[i].specular[0] = 0.0;
  298. model->materials[i].specular[1] = 0.0;
  299. model->materials[i].specular[2] = 0.0;
  300. model->materials[i].specular[3] = 0.0;
  301. }
  302. model->materials[0].name = stralloc("default");
  303. /* now, read in the data */
  304. nummaterials = 0;
  305. mat = &model->materials[nummaterials];
  306. while(fscanf(file, "%s", buf) != EOF) {
  307. switch(buf[0]) {
  308. case '#': /* comment */
  309. /* eat up rest of line */
  310. fgets(buf, sizeof(buf), file);
  311. break;
  312. case 'n': /* newmtl */
  313. fgets(buf, sizeof(buf), file);
  314. sscanf(buf, "%s %s", buf, buf);
  315. nummaterials++;
  316. model->materials[nummaterials].name = stralloc(buf);
  317. break;
  318. case 'N':
  319. fscanf(file, "%f", &model->materials[nummaterials].shininess);
  320. /* wavefront shininess is from [0, 1000], so scale for OpenGL */
  321. model->materials[nummaterials].shininess /= 1000.0;
  322. model->materials[nummaterials].shininess *= 128.0;
  323. mat = &model->materials[nummaterials];
  324. break;
  325. case 'K':
  326. switch(buf[1]) {
  327. case 'd':
  328. fscanf(file, "%f %f %f",
  329. &model->materials[nummaterials].diffuse[0],
  330. &model->materials[nummaterials].diffuse[1],
  331. &model->materials[nummaterials].diffuse[2]);
  332. break;
  333. case 's':
  334. fscanf(file, "%f %f %f",
  335. &model->materials[nummaterials].specular[0],
  336. &model->materials[nummaterials].specular[1],
  337. &model->materials[nummaterials].specular[2]);
  338. break;
  339. case 'a':
  340. fscanf(file, "%f %f %f",
  341. &model->materials[nummaterials].ambient[0],
  342. &model->materials[nummaterials].ambient[1],
  343. &model->materials[nummaterials].ambient[2]);
  344. break;
  345. default:
  346. /* eat up rest of line */
  347. fgets(buf, sizeof(buf), file);
  348. break;
  349. }
  350. break;
  351. case 'd': /* alpha? */
  352. fscanf(file, "%f",
  353. &model->materials[nummaterials].diffuse[3]);
  354. break;
  355. case 'm': /* texture map */
  356. fscanf(file, "%s", buf2);
  357. /*printf("map %s\n", buf2);*/
  358. mat->map_kd = strdup(buf2);
  359. break;
  360. default:
  361. /* eat up rest of line */
  362. fgets(buf, sizeof(buf), file);
  363. break;
  364. }
  365. }
  366. }
  367. /* _glmWriteMTL: write a wavefront material library file
  368. *
  369. * model - properly initialized GLMmodel structure
  370. * modelpath - pathname of the model being written
  371. * mtllibname - name of the material library to be written
  372. */
  373. static void
  374. _glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname)
  375. {
  376. FILE* file;
  377. char* dir;
  378. char* filename;
  379. GLMmaterial* material;
  380. uint i;
  381. dir = _glmDirName(modelpath);
  382. filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(mtllibname)));
  383. strcpy(filename, dir);
  384. strcat(filename, mtllibname);
  385. free(dir);
  386. /* open the file */
  387. file = fopen(filename, "w");
  388. if (!file) {
  389. fprintf(stderr, "_glmWriteMTL() failed: can't open file \"%s\".\n",
  390. filename);
  391. exit(1);
  392. }
  393. free(filename);
  394. /* spit out a header */
  395. fprintf(file, "# \n");
  396. fprintf(file, "# Wavefront MTL generated by GLM library\n");
  397. fprintf(file, "# \n");
  398. fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n");
  399. fprintf(file, "# email: ndr@pobox.com\n");
  400. fprintf(file, "# www: http://www.pobox.com/~ndr\n");
  401. fprintf(file, "# \n\n");
  402. for (i = 0; i < model->nummaterials; i++) {
  403. material = &model->materials[i];
  404. fprintf(file, "newmtl %s\n", material->name);
  405. fprintf(file, "Ka %f %f %f\n",
  406. material->ambient[0], material->ambient[1], material->ambient[2]);
  407. fprintf(file, "Kd %f %f %f\n",
  408. material->diffuse[0], material->diffuse[1], material->diffuse[2]);
  409. fprintf(file, "Ks %f %f %f\n",
  410. material->specular[0],material->specular[1],material->specular[2]);
  411. fprintf(file, "Ns %f\n", material->shininess);
  412. fprintf(file, "\n");
  413. }
  414. }
  415. /* _glmFirstPass: first pass at a Wavefront OBJ file that gets all the
  416. * statistics of the model (such as #vertices, #normals, etc)
  417. *
  418. * model - properly initialized GLMmodel structure
  419. * file - (fopen'd) file descriptor
  420. */
  421. static void
  422. _glmFirstPass(GLMmodel* model, FILE* file)
  423. {
  424. uint numvertices; /* number of vertices in model */
  425. uint numnormals; /* number of normals in model */
  426. uint numtexcoords; /* number of texcoords in model */
  427. uint numtriangles; /* number of triangles in model */
  428. GLMgroup* group; /* current group */
  429. unsigned v, n, t;
  430. char buf[128];
  431. /* make a default group */
  432. group = _glmAddGroup(model, "default");
  433. numvertices = numnormals = numtexcoords = numtriangles = 0;
  434. while(fscanf(file, "%s", buf) != EOF) {
  435. switch(buf[0]) {
  436. case '#': /* comment */
  437. /* eat up rest of line */
  438. fgets(buf, sizeof(buf), file);
  439. break;
  440. case 'v': /* v, vn, vt */
  441. switch(buf[1]) {
  442. case '\0': /* vertex */
  443. /* eat up rest of line */
  444. fgets(buf, sizeof(buf), file);
  445. numvertices++;
  446. break;
  447. case 'n': /* normal */
  448. /* eat up rest of line */
  449. fgets(buf, sizeof(buf), file);
  450. numnormals++;
  451. break;
  452. case 't': /* texcoord */
  453. /* eat up rest of line */
  454. fgets(buf, sizeof(buf), file);
  455. numtexcoords++;
  456. break;
  457. default:
  458. printf("_glmFirstPass(): Unknown token \"%s\".\n", buf);
  459. exit(1);
  460. break;
  461. }
  462. break;
  463. case 'm':
  464. fgets(buf, sizeof(buf), file);
  465. sscanf(buf, "%s %s", buf, buf);
  466. model->mtllibname = stralloc(buf);
  467. _glmReadMTL(model, buf);
  468. break;
  469. case 'u':
  470. /* eat up rest of line */
  471. fgets(buf, sizeof(buf), file);
  472. break;
  473. case 'g': /* group */
  474. /* eat up rest of line */
  475. fgets(buf, sizeof(buf), file);
  476. sscanf(buf, "%s", buf);
  477. group = _glmAddGroup(model, buf);
  478. break;
  479. case 'f': /* face */
  480. v = n = t = 0;
  481. fscanf(file, "%s", buf);
  482. /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
  483. if (strstr(buf, "//")) {
  484. /* v//n */
  485. sscanf(buf, "%u//%u", &v, &n);
  486. fscanf(file, "%u//%u", &v, &n);
  487. fscanf(file, "%u//%u", &v, &n);
  488. numtriangles++;
  489. group->numtriangles++;
  490. while(fscanf(file, "%u//%u", &v, &n) > 0) {
  491. numtriangles++;
  492. group->numtriangles++;
  493. }
  494. } else if (sscanf(buf, "%u/%u/%u", &v, &t, &n) == 3) {
  495. /* v/t/n */
  496. fscanf(file, "%u/%u/%u", &v, &t, &n);
  497. fscanf(file, "%u/%u/%u", &v, &t, &n);
  498. numtriangles++;
  499. group->numtriangles++;
  500. while(fscanf(file, "%u/%u/%u", &v, &t, &n) > 0) {
  501. numtriangles++;
  502. group->numtriangles++;
  503. }
  504. } else if (sscanf(buf, "%u/%u", &v, &t) == 2) {
  505. /* v/t */
  506. fscanf(file, "%u/%u", &v, &t);
  507. fscanf(file, "%u/%u", &v, &t);
  508. numtriangles++;
  509. group->numtriangles++;
  510. while(fscanf(file, "%u/%u", &v, &t) > 0) {
  511. numtriangles++;
  512. group->numtriangles++;
  513. }
  514. } else {
  515. /* v */
  516. fscanf(file, "%u", &v);
  517. fscanf(file, "%u", &v);
  518. numtriangles++;
  519. group->numtriangles++;
  520. while(fscanf(file, "%u", &v) > 0) {
  521. numtriangles++;
  522. group->numtriangles++;
  523. }
  524. }
  525. break;
  526. default:
  527. /* eat up rest of line */
  528. fgets(buf, sizeof(buf), file);
  529. break;
  530. }
  531. }
  532. #if 0
  533. /* announce the model statistics */
  534. printf(" Vertices: %d\n", numvertices);
  535. printf(" Normals: %d\n", numnormals);
  536. printf(" Texcoords: %d\n", numtexcoords);
  537. printf(" Triangles: %d\n", numtriangles);
  538. printf(" Groups: %d\n", model->numgroups);
  539. #endif
  540. /* set the stats in the model structure */
  541. model->numvertices = numvertices;
  542. model->numnormals = numnormals;
  543. model->numtexcoords = numtexcoords;
  544. model->numtriangles = numtriangles;
  545. /* allocate memory for the triangles in each group */
  546. group = model->groups;
  547. while(group) {
  548. group->triangles = (uint*)malloc(sizeof(uint) * group->numtriangles);
  549. group->numtriangles = 0;
  550. group = group->next;
  551. }
  552. }
  553. /* _glmSecondPass: second pass at a Wavefront OBJ file that gets all
  554. * the data.
  555. *
  556. * model - properly initialized GLMmodel structure
  557. * file - (fopen'd) file descriptor
  558. */
  559. static void
  560. _glmSecondPass(GLMmodel* model, FILE* file)
  561. {
  562. uint numvertices; /* number of vertices in model */
  563. uint numnormals; /* number of normals in model */
  564. uint numtexcoords; /* number of texcoords in model */
  565. uint numtriangles; /* number of triangles in model */
  566. float* vertices; /* array of vertices */
  567. float* normals; /* array of normals */
  568. float* texcoords; /* array of texture coordinates */
  569. GLMgroup* group; /* current group pointer */
  570. uint material; /* current material */
  571. uint v, n, t;
  572. char buf[128];
  573. /* set the pointer shortcuts */
  574. vertices = model->vertices;
  575. normals = model->normals;
  576. texcoords = model->texcoords;
  577. group = model->groups;
  578. /* on the second pass through the file, read all the data into the
  579. allocated arrays */
  580. numvertices = numnormals = numtexcoords = 1;
  581. numtriangles = 0;
  582. material = 0;
  583. while(fscanf(file, "%s", buf) != EOF) {
  584. switch(buf[0]) {
  585. case '#': /* comment */
  586. /* eat up rest of line */
  587. fgets(buf, sizeof(buf), file);
  588. break;
  589. case 'v': /* v, vn, vt */
  590. switch(buf[1]) {
  591. case '\0': /* vertex */
  592. fscanf(file, "%f %f %f",
  593. &vertices[3 * numvertices + X],
  594. &vertices[3 * numvertices + Y],
  595. &vertices[3 * numvertices + Z]);
  596. numvertices++;
  597. break;
  598. case 'n': /* normal */
  599. fscanf(file, "%f %f %f",
  600. &normals[3 * numnormals + X],
  601. &normals[3 * numnormals + Y],
  602. &normals[3 * numnormals + Z]);
  603. numnormals++;
  604. break;
  605. case 't': /* texcoord */
  606. fscanf(file, "%f %f",
  607. &texcoords[2 * numtexcoords + X],
  608. &texcoords[2 * numtexcoords + Y]);
  609. numtexcoords++;
  610. break;
  611. }
  612. break;
  613. case 'u':
  614. fgets(buf, sizeof(buf), file);
  615. sscanf(buf, "%s %s", buf, buf);
  616. material = _glmFindMaterial(model, buf);
  617. if (!group->material)
  618. group->material = material;
  619. /*printf("material %s = %u\n", buf, material);*/
  620. break;
  621. case 'g': /* group */
  622. /* eat up rest of line */
  623. fgets(buf, sizeof(buf), file);
  624. sscanf(buf, "%s", buf);
  625. group = _glmFindGroup(model, buf);
  626. group->material = material;
  627. /*printf("GROUP %s material %u\n", buf, material);*/
  628. break;
  629. case 'f': /* face */
  630. v = n = t = 0;
  631. fscanf(file, "%s", buf);
  632. /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
  633. if (strstr(buf, "//")) {
  634. /* v//n */
  635. sscanf(buf, "%u//%u", &v, &n);
  636. T(numtriangles).vindices[0] = v;
  637. T(numtriangles).nindices[0] = n;
  638. fscanf(file, "%u//%u", &v, &n);
  639. T(numtriangles).vindices[1] = v;
  640. T(numtriangles).nindices[1] = n;
  641. fscanf(file, "%u//%u", &v, &n);
  642. T(numtriangles).vindices[2] = v;
  643. T(numtriangles).nindices[2] = n;
  644. group->triangles[group->numtriangles++] = numtriangles;
  645. numtriangles++;
  646. while(fscanf(file, "%u//%u", &v, &n) > 0) {
  647. T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
  648. T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
  649. T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
  650. T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
  651. T(numtriangles).vindices[2] = v;
  652. T(numtriangles).nindices[2] = n;
  653. group->triangles[group->numtriangles++] = numtriangles;
  654. numtriangles++;
  655. }
  656. } else if (sscanf(buf, "%u/%u/%u", &v, &t, &n) == 3) {
  657. /* v/t/n */
  658. T(numtriangles).vindices[0] = v;
  659. T(numtriangles).tindices[0] = t;
  660. T(numtriangles).nindices[0] = n;
  661. fscanf(file, "%u/%u/%u", &v, &t, &n);
  662. T(numtriangles).vindices[1] = v;
  663. T(numtriangles).tindices[1] = t;
  664. T(numtriangles).nindices[1] = n;
  665. fscanf(file, "%u/%u/%u", &v, &t, &n);
  666. T(numtriangles).vindices[2] = v;
  667. T(numtriangles).tindices[2] = t;
  668. T(numtriangles).nindices[2] = n;
  669. group->triangles[group->numtriangles++] = numtriangles;
  670. numtriangles++;
  671. while(fscanf(file, "%u/%u/%u", &v, &t, &n) > 0) {
  672. T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
  673. T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
  674. T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
  675. T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
  676. T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
  677. T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
  678. T(numtriangles).vindices[2] = v;
  679. T(numtriangles).tindices[2] = t;
  680. T(numtriangles).nindices[2] = n;
  681. group->triangles[group->numtriangles++] = numtriangles;
  682. numtriangles++;
  683. }
  684. } else if (sscanf(buf, "%u/%u", &v, &t) == 2) {
  685. /* v/t */
  686. T(numtriangles).vindices[0] = v;
  687. T(numtriangles).tindices[0] = t;
  688. fscanf(file, "%u/%u", &v, &t);
  689. T(numtriangles).vindices[1] = v;
  690. T(numtriangles).tindices[1] = t;
  691. fscanf(file, "%u/%u", &v, &t);
  692. T(numtriangles).vindices[2] = v;
  693. T(numtriangles).tindices[2] = t;
  694. group->triangles[group->numtriangles++] = numtriangles;
  695. numtriangles++;
  696. while(fscanf(file, "%u/%u", &v, &t) > 0) {
  697. T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
  698. T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
  699. T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
  700. T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
  701. T(numtriangles).vindices[2] = v;
  702. T(numtriangles).tindices[2] = t;
  703. group->triangles[group->numtriangles++] = numtriangles;
  704. numtriangles++;
  705. }
  706. } else {
  707. /* v */
  708. sscanf(buf, "%u", &v);
  709. T(numtriangles).vindices[0] = v;
  710. fscanf(file, "%u", &v);
  711. T(numtriangles).vindices[1] = v;
  712. fscanf(file, "%u", &v);
  713. T(numtriangles).vindices[2] = v;
  714. group->triangles[group->numtriangles++] = numtriangles;
  715. numtriangles++;
  716. while(fscanf(file, "%u", &v) > 0) {
  717. T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
  718. T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
  719. T(numtriangles).vindices[2] = v;
  720. group->triangles[group->numtriangles++] = numtriangles;
  721. numtriangles++;
  722. }
  723. }
  724. break;
  725. default:
  726. /* eat up rest of line */
  727. fgets(buf, sizeof(buf), file);
  728. break;
  729. }
  730. }
  731. #if 0
  732. /* announce the memory requirements */
  733. printf(" Memory: %d bytes\n",
  734. numvertices * 3*sizeof(float) +
  735. numnormals * 3*sizeof(float) * (numnormals ? 1 : 0) +
  736. numtexcoords * 3*sizeof(float) * (numtexcoords ? 1 : 0) +
  737. numtriangles * sizeof(GLMtriangle));
  738. #endif
  739. }
  740. /* public functions */
  741. /* glmUnitize: "unitize" a model by translating it to the origin and
  742. * scaling it to fit in a unit cube around the origin. Returns the
  743. * scalefactor used.
  744. *
  745. * model - properly initialized GLMmodel structure
  746. */
  747. float
  748. glmUnitize(GLMmodel* model)
  749. {
  750. uint i;
  751. float maxx, minx, maxy, miny, maxz, minz;
  752. float cx, cy, cz, w, h, d;
  753. float scale;
  754. assert(model);
  755. assert(model->vertices);
  756. /* get the max/mins */
  757. maxx = minx = model->vertices[3 + X];
  758. maxy = miny = model->vertices[3 + Y];
  759. maxz = minz = model->vertices[3 + Z];
  760. for (i = 1; i <= model->numvertices; i++) {
  761. if (maxx < model->vertices[3 * i + X])
  762. maxx = model->vertices[3 * i + X];
  763. if (minx > model->vertices[3 * i + X])
  764. minx = model->vertices[3 * i + X];
  765. if (maxy < model->vertices[3 * i + Y])
  766. maxy = model->vertices[3 * i + Y];
  767. if (miny > model->vertices[3 * i + Y])
  768. miny = model->vertices[3 * i + Y];
  769. if (maxz < model->vertices[3 * i + Z])
  770. maxz = model->vertices[3 * i + Z];
  771. if (minz > model->vertices[3 * i + Z])
  772. minz = model->vertices[3 * i + Z];
  773. }
  774. /* calculate model width, height, and depth */
  775. w = _glmAbs(maxx) + _glmAbs(minx);
  776. h = _glmAbs(maxy) + _glmAbs(miny);
  777. d = _glmAbs(maxz) + _glmAbs(minz);
  778. /* calculate center of the model */
  779. cx = (maxx + minx) / 2.0;
  780. cy = (maxy + miny) / 2.0;
  781. cz = (maxz + minz) / 2.0;
  782. /* calculate unitizing scale factor */
  783. scale = 2.0 / _glmMax(_glmMax(w, h), d);
  784. /* translate around center then scale */
  785. for (i = 1; i <= model->numvertices; i++) {
  786. model->vertices[3 * i + X] -= cx;
  787. model->vertices[3 * i + Y] -= cy;
  788. model->vertices[3 * i + Z] -= cz;
  789. model->vertices[3 * i + X] *= scale;
  790. model->vertices[3 * i + Y] *= scale;
  791. model->vertices[3 * i + Z] *= scale;
  792. }
  793. return scale;
  794. }
  795. /* glmDimensions: Calculates the dimensions (width, height, depth) of
  796. * a model.
  797. *
  798. * model - initialized GLMmodel structure
  799. * dimensions - array of 3 floats (float dimensions[3])
  800. */
  801. void
  802. glmDimensions(GLMmodel* model, float* dimensions)
  803. {
  804. uint i;
  805. float maxx, minx, maxy, miny, maxz, minz;
  806. assert(model);
  807. assert(model->vertices);
  808. assert(dimensions);
  809. /* get the max/mins */
  810. maxx = minx = model->vertices[3 + X];
  811. maxy = miny = model->vertices[3 + Y];
  812. maxz = minz = model->vertices[3 + Z];
  813. for (i = 1; i <= model->numvertices; i++) {
  814. if (maxx < model->vertices[3 * i + X])
  815. maxx = model->vertices[3 * i + X];
  816. if (minx > model->vertices[3 * i + X])
  817. minx = model->vertices[3 * i + X];
  818. if (maxy < model->vertices[3 * i + Y])
  819. maxy = model->vertices[3 * i + Y];
  820. if (miny > model->vertices[3 * i + Y])
  821. miny = model->vertices[3 * i + Y];
  822. if (maxz < model->vertices[3 * i + Z])
  823. maxz = model->vertices[3 * i + Z];
  824. if (minz > model->vertices[3 * i + Z])
  825. minz = model->vertices[3 * i + Z];
  826. }
  827. /* calculate model width, height, and depth */
  828. dimensions[X] = _glmAbs(maxx) + _glmAbs(minx);
  829. dimensions[Y] = _glmAbs(maxy) + _glmAbs(miny);
  830. dimensions[Z] = _glmAbs(maxz) + _glmAbs(minz);
  831. }
  832. /* glmScale: Scales a model by a given amount.
  833. *
  834. * model - properly initialized GLMmodel structure
  835. * scale - scalefactor (0.5 = half as large, 2.0 = twice as large)
  836. */
  837. void
  838. glmScale(GLMmodel* model, float scale)
  839. {
  840. uint i;
  841. for (i = 1; i <= model->numvertices; i++) {
  842. model->vertices[3 * i + X] *= scale;
  843. model->vertices[3 * i + Y] *= scale;
  844. model->vertices[3 * i + Z] *= scale;
  845. }
  846. }
  847. /* glmReverseWinding: Reverse the polygon winding for all polygons in
  848. * this model. Default winding is counter-clockwise. Also changes
  849. * the direction of the normals.
  850. *
  851. * model - properly initialized GLMmodel structure
  852. */
  853. void
  854. glmReverseWinding(GLMmodel* model)
  855. {
  856. uint i, swap;
  857. assert(model);
  858. for (i = 0; i < model->numtriangles; i++) {
  859. swap = T(i).vindices[0];
  860. T(i).vindices[0] = T(i).vindices[2];
  861. T(i).vindices[2] = swap;
  862. if (model->numnormals) {
  863. swap = T(i).nindices[0];
  864. T(i).nindices[0] = T(i).nindices[2];
  865. T(i).nindices[2] = swap;
  866. }
  867. if (model->numtexcoords) {
  868. swap = T(i).tindices[0];
  869. T(i).tindices[0] = T(i).tindices[2];
  870. T(i).tindices[2] = swap;
  871. }
  872. }
  873. /* reverse facet normals */
  874. for (i = 1; i <= model->numfacetnorms; i++) {
  875. model->facetnorms[3 * i + X] = -model->facetnorms[3 * i + X];
  876. model->facetnorms[3 * i + Y] = -model->facetnorms[3 * i + Y];
  877. model->facetnorms[3 * i + Z] = -model->facetnorms[3 * i + Z];
  878. }
  879. /* reverse vertex normals */
  880. for (i = 1; i <= model->numnormals; i++) {
  881. model->normals[3 * i + X] = -model->normals[3 * i + X];
  882. model->normals[3 * i + Y] = -model->normals[3 * i + Y];
  883. model->normals[3 * i + Z] = -model->normals[3 * i + Z];
  884. }
  885. }
  886. /* glmFacetNormals: Generates facet normals for a model (by taking the
  887. * cross product of the two vectors derived from the sides of each
  888. * triangle). Assumes a counter-clockwise winding.
  889. *
  890. * model - initialized GLMmodel structure
  891. */
  892. void
  893. glmFacetNormals(GLMmodel* model)
  894. {
  895. uint i;
  896. float u[3];
  897. float v[3];
  898. assert(model);
  899. assert(model->vertices);
  900. /* clobber any old facetnormals */
  901. if (model->facetnorms)
  902. free(model->facetnorms);
  903. /* allocate memory for the new facet normals */
  904. model->numfacetnorms = model->numtriangles;
  905. model->facetnorms = (float*)malloc(sizeof(float) *
  906. 3 * (model->numfacetnorms + 1));
  907. for (i = 0; i < model->numtriangles; i++) {
  908. model->triangles[i].findex = i+1;
  909. u[X] = model->vertices[3 * T(i).vindices[1] + X] -
  910. model->vertices[3 * T(i).vindices[0] + X];
  911. u[Y] = model->vertices[3 * T(i).vindices[1] + Y] -
  912. model->vertices[3 * T(i).vindices[0] + Y];
  913. u[Z] = model->vertices[3 * T(i).vindices[1] + Z] -
  914. model->vertices[3 * T(i).vindices[0] + Z];
  915. v[X] = model->vertices[3 * T(i).vindices[2] + X] -
  916. model->vertices[3 * T(i).vindices[0] + X];
  917. v[Y] = model->vertices[3 * T(i).vindices[2] + Y] -
  918. model->vertices[3 * T(i).vindices[0] + Y];
  919. v[Z] = model->vertices[3 * T(i).vindices[2] + Z] -
  920. model->vertices[3 * T(i).vindices[0] + Z];
  921. _glmCross(u, v, &model->facetnorms[3 * (i+1)]);
  922. _glmNormalize(&model->facetnorms[3 * (i+1)]);
  923. }
  924. }
  925. /* glmVertexNormals: Generates smooth vertex normals for a model.
  926. * First builds a list of all the triangles each vertex is in. Then
  927. * loops through each vertex in the the list averaging all the facet
  928. * normals of the triangles each vertex is in. Finally, sets the
  929. * normal index in the triangle for the vertex to the generated smooth
  930. * normal. If the dot product of a facet normal and the facet normal
  931. * associated with the first triangle in the list of triangles the
  932. * current vertex is in is greater than the cosine of the angle
  933. * parameter to the function, that facet normal is not added into the
  934. * average normal calculation and the corresponding vertex is given
  935. * the facet normal. This tends to preserve hard edges. The angle to
  936. * use depends on the model, but 90 degrees is usually a good start.
  937. *
  938. * model - initialized GLMmodel structure
  939. * angle - maximum angle (in degrees) to smooth across
  940. */
  941. void
  942. glmVertexNormals(GLMmodel* model, float angle)
  943. {
  944. GLMnode* node;
  945. GLMnode* tail;
  946. GLMnode** members;
  947. float* normals;
  948. uint numnormals;
  949. float average[3];
  950. float dot, cos_angle;
  951. uint i, avg;
  952. assert(model);
  953. assert(model->facetnorms);
  954. /* calculate the cosine of the angle (in degrees) */
  955. cos_angle = cos(angle * M_PI / 180.0);
  956. /* nuke any previous normals */
  957. if (model->normals)
  958. free(model->normals);
  959. /* allocate space for new normals */
  960. model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */
  961. model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1));
  962. /* allocate a structure that will hold a linked list of triangle
  963. indices for each vertex */
  964. members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1));
  965. for (i = 1; i <= model->numvertices; i++)
  966. members[i] = NULL;
  967. /* for every triangle, create a node for each vertex in it */
  968. for (i = 0; i < model->numtriangles; i++) {
  969. node = (GLMnode*)malloc(sizeof(GLMnode));
  970. node->index = i;
  971. node->next = members[T(i).vindices[0]];
  972. members[T(i).vindices[0]] = node;
  973. node = (GLMnode*)malloc(sizeof(GLMnode));
  974. node->index = i;
  975. node->next = members[T(i).vindices[1]];
  976. members[T(i).vindices[1]] = node;
  977. node = (GLMnode*)malloc(sizeof(GLMnode));
  978. node->index = i;
  979. node->next = members[T(i).vindices[2]];
  980. members[T(i).vindices[2]] = node;
  981. }
  982. /* calculate the average normal for each vertex */
  983. numnormals = 1;
  984. for (i = 1; i <= model->numvertices; i++) {
  985. /* calculate an average normal for this vertex by averaging the
  986. facet normal of every triangle this vertex is in */
  987. node = members[i];
  988. if (!node)
  989. fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n");
  990. average[0] = 0.0; average[1] = 0.0; average[2] = 0.0;
  991. avg = 0;
  992. while (node) {
  993. /* only average if the dot product of the angle between the two
  994. facet normals is greater than the cosine of the threshold
  995. angle -- or, said another way, the angle between the two
  996. facet normals is less than (or equal to) the threshold angle */
  997. dot = _glmDot(&model->facetnorms[3 * T(node->index).findex],
  998. &model->facetnorms[3 * T(members[i]->index).findex]);
  999. if (dot > cos_angle) {
  1000. node->averaged = TRUE;
  1001. average[0] += model->facetnorms[3 * T(node->index).findex + 0];
  1002. average[1] += model->facetnorms[3 * T(node->index).findex + 1];
  1003. average[2] += model->facetnorms[3 * T(node->index).findex + 2];
  1004. avg = 1; /* we averaged at least one normal! */
  1005. } else {
  1006. node->averaged = FALSE;
  1007. }
  1008. node = node->next;
  1009. }
  1010. if (avg) {
  1011. /* normalize the averaged normal */
  1012. _glmNormalize(average);
  1013. /* add the normal to the vertex normals list */
  1014. model->normals[3 * numnormals + 0] = average[0];
  1015. model->normals[3 * numnormals + 1] = average[1];
  1016. model->normals[3 * numnormals + 2] = average[2];
  1017. avg = numnormals;
  1018. numnormals++;
  1019. }
  1020. /* set the normal of this vertex in each triangle it is in */
  1021. node = members[i];
  1022. while (node) {
  1023. if (node->averaged) {
  1024. /* if this node was averaged, use the average normal */
  1025. if (T(node->index).vindices[0] == i)
  1026. T(node->index).nindices[0] = avg;
  1027. else if (T(node->index).vindices[1] == i)
  1028. T(node->index).nindices[1] = avg;
  1029. else if (T(node->index).vindices[2] == i)
  1030. T(node->index).nindices[2] = avg;
  1031. } else {
  1032. /* if this node wasn't averaged, use the facet normal */
  1033. model->normals[3 * numnormals + 0] =
  1034. model->facetnorms[3 * T(node->index).findex + 0];
  1035. model->normals[3 * numnormals + 1] =
  1036. model->facetnorms[3 * T(node->index).findex + 1];
  1037. model->normals[3 * numnormals + 2] =
  1038. model->facetnorms[3 * T(node->index).findex + 2];
  1039. if (T(node->index).vindices[0] == i)
  1040. T(node->index).nindices[0] = numnormals;
  1041. else if (T(node->index).vindices[1] == i)
  1042. T(node->index).nindices[1] = numnormals;
  1043. else if (T(node->index).vindices[2] == i)
  1044. T(node->index).nindices[2] = numnormals;
  1045. numnormals++;
  1046. }
  1047. node = node->next;
  1048. }
  1049. }
  1050. model->numnormals = numnormals - 1;
  1051. /* free the member information */
  1052. for (i = 1; i <= model->numvertices; i++) {
  1053. node = members[i];
  1054. while (node) {
  1055. tail = node;
  1056. node = node->next;
  1057. free(tail);
  1058. }
  1059. }
  1060. free(members);
  1061. /* pack the normals array (we previously allocated the maximum
  1062. number of normals that could possibly be created (numtriangles *
  1063. 3), so get rid of some of them (usually alot unless none of the
  1064. facet normals were averaged)) */
  1065. normals = model->normals;
  1066. model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1));
  1067. for (i = 1; i <= model->numnormals; i++) {
  1068. model->normals[3 * i + 0] = normals[3 * i + 0];
  1069. model->normals[3 * i + 1] = normals[3 * i + 1];
  1070. model->normals[3 * i + 2] = normals[3 * i + 2];
  1071. }
  1072. free(normals);
  1073. printf("glmVertexNormals(): %d normals generated\n", model->numnormals);
  1074. }
  1075. /* glmLinearTexture: Generates texture coordinates according to a
  1076. * linear projection of the texture map. It generates these by
  1077. * linearly mapping the vertices onto a square.
  1078. *
  1079. * model - pointer to initialized GLMmodel structure
  1080. */
  1081. void
  1082. glmLinearTexture(GLMmodel* model)
  1083. {
  1084. GLMgroup *group;
  1085. float dimensions[3];
  1086. float x, y, scalefactor;
  1087. uint i;
  1088. assert(model);
  1089. if (model->texcoords)
  1090. free(model->texcoords);
  1091. model->numtexcoords = model->numvertices;
  1092. model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1));
  1093. glmDimensions(model, dimensions);
  1094. scalefactor = 2.0 /
  1095. _glmAbs(_glmMax(_glmMax(dimensions[0], dimensions[1]), dimensions[2]));
  1096. /* do the calculations */
  1097. for(i = 1; i <= model->numvertices; i++) {
  1098. x = model->vertices[3 * i + 0] * scalefactor;
  1099. y = model->vertices[3 * i + 2] * scalefactor;
  1100. model->texcoords[2 * i + 0] = (x + 1.0) / 2.0;
  1101. model->texcoords[2 * i + 1] = (y + 1.0) / 2.0;
  1102. }
  1103. /* go through and put texture coordinate indices in all the triangles */
  1104. group = model->groups;
  1105. while(group) {
  1106. for(i = 0; i < group->numtriangles; i++) {
  1107. T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0];
  1108. T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1];
  1109. T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2];
  1110. }
  1111. group = group->next;
  1112. }
  1113. #if 0
  1114. printf("glmLinearTexture(): generated %d linear texture coordinates\n",
  1115. model->numtexcoords);
  1116. #endif
  1117. }
  1118. /* glmSpheremapTexture: Generates texture coordinates according to a
  1119. * spherical projection of the texture map. Sometimes referred to as
  1120. * spheremap, or reflection map texture coordinates. It generates
  1121. * these by using the normal to calculate where that vertex would map
  1122. * onto a sphere. Since it is impossible to map something flat
  1123. * perfectly onto something spherical, there is distortion at the
  1124. * poles. This particular implementation causes the poles along the X
  1125. * axis to be distorted.
  1126. *
  1127. * model - pointer to initialized GLMmodel structure
  1128. */
  1129. void
  1130. glmSpheremapTexture(GLMmodel* model)
  1131. {
  1132. GLMgroup* group;
  1133. float theta, phi, rho, x, y, z, r;
  1134. uint i;
  1135. assert(model);
  1136. assert(model->normals);
  1137. if (model->texcoords)
  1138. free(model->texcoords);
  1139. model->numtexcoords = model->numnormals;
  1140. model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1));
  1141. /* do the calculations */
  1142. for (i = 1; i <= model->numnormals; i++) {
  1143. z = model->normals[3 * i + 0]; /* re-arrange for pole distortion */
  1144. y = model->normals[3 * i + 1];
  1145. x = model->normals[3 * i + 2];
  1146. r = sqrt((x * x) + (y * y));
  1147. rho = sqrt((r * r) + (z * z));
  1148. if(r == 0.0) {
  1149. theta = 0.0;
  1150. phi = 0.0;
  1151. } else {
  1152. if(z == 0.0)
  1153. phi = M_PI / 2.0;
  1154. else
  1155. phi = acos(z / rho);
  1156. #if WE_DONT_NEED_THIS_CODE
  1157. if(x == 0.0)
  1158. theta = M_PI / 2.0; /* asin(y / r); */
  1159. else
  1160. theta = acos(x / r);
  1161. #endif
  1162. if(y == 0.0)
  1163. theta = M_PI / 2.0; /* acos(x / r); */
  1164. else
  1165. theta = asin(y / r) + (M_PI / 2.0);
  1166. }
  1167. model->texcoords[2 * i + 0] = theta / M_PI;
  1168. model->texcoords[2 * i + 1] = phi / M_PI;
  1169. }
  1170. /* go through and put texcoord indices in all the triangles */
  1171. group = model->groups;
  1172. while(group) {
  1173. for (i = 0; i < group->numtriangles; i++) {
  1174. T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0];
  1175. T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1];
  1176. T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2];
  1177. }
  1178. group = group->next;
  1179. }
  1180. #if 0
  1181. printf("glmSpheremapTexture(): generated %d spheremap texture coordinates\n",
  1182. model->numtexcoords);
  1183. #endif
  1184. }
  1185. /* glmDelete: Deletes a GLMmodel structure.
  1186. *
  1187. * model - initialized GLMmodel structure
  1188. */
  1189. void
  1190. glmDelete(GLMmodel* model)
  1191. {
  1192. GLMgroup* group;
  1193. uint i;
  1194. assert(model);
  1195. if (model->pathname) free(model->pathname);
  1196. if (model->mtllibname) free(model->mtllibname);
  1197. if (model->vertices) free(model->vertices);
  1198. if (model->normals) free(model->normals);
  1199. if (model->texcoords) free(model->texcoords);
  1200. if (model->facetnorms) free(model->facetnorms);
  1201. if (model->triangles) free(model->triangles);
  1202. if (model->materials) {
  1203. for (i = 0; i < model->nummaterials; i++)
  1204. free(model->materials[i].name);
  1205. }
  1206. free(model->materials);
  1207. while(model->groups) {
  1208. group = model->groups;
  1209. model->groups = model->groups->next;
  1210. free(group->name);
  1211. free(group->triangles);
  1212. free(group);
  1213. }
  1214. free(model);
  1215. }
  1216. static GLMmaterial *
  1217. glmDefaultMaterial(void)
  1218. {
  1219. GLMmaterial *m = (GLMmaterial *) calloc(1, sizeof(GLMmaterial));
  1220. m->diffuse[0] = 0.75;
  1221. m->diffuse[1] = 0.75;
  1222. m->diffuse[2] = 0.75;
  1223. m->diffuse[3] = 1.0;
  1224. m->specular[0] = 1.0;
  1225. m->specular[1] = 1.0;
  1226. m->specular[2] = 1.0;
  1227. m->specular[3] = 1.0;
  1228. m->shininess = 5;
  1229. return m;
  1230. }
  1231. /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file.
  1232. * Returns a pointer to the created object which should be free'd with
  1233. * glmDelete().
  1234. *
  1235. * filename - name of the file containing the Wavefront .OBJ format data.
  1236. */
  1237. GLMmodel*
  1238. glmReadOBJ(char* filename)
  1239. {
  1240. GLMmodel* model;
  1241. FILE* file;
  1242. /* open the file */
  1243. file = fopen(filename, "r");
  1244. if (!file) {
  1245. fprintf(stderr, "glmReadOBJ() failed: can't open data file \"%s\".\n",
  1246. filename);
  1247. exit(1);
  1248. }
  1249. #if 0
  1250. /* announce the model name */
  1251. printf("Model: %s\n", filename);
  1252. #endif
  1253. /* allocate a new model */
  1254. model = (GLMmodel*)malloc(sizeof(GLMmodel));
  1255. model->pathname = stralloc(filename);
  1256. model->mtllibname = NULL;
  1257. model->numvertices = 0;
  1258. model->vertices = NULL;
  1259. model->numnormals = 0;
  1260. model->normals = NULL;
  1261. model->numtexcoords = 0;
  1262. model->texcoords = NULL;
  1263. model->numfacetnorms = 0;
  1264. model->facetnorms = NULL;
  1265. model->numtriangles = 0;
  1266. model->triangles = NULL;
  1267. model->nummaterials = 0;
  1268. model->materials = NULL;
  1269. model->numgroups = 0;
  1270. model->groups = NULL;
  1271. model->position[0] = 0.0;
  1272. model->position[1] = 0.0;
  1273. model->position[2] = 0.0;
  1274. model->scale = 1.0;
  1275. /* make a first pass through the file to get a count of the number
  1276. of vertices, normals, texcoords & triangles */
  1277. _glmFirstPass(model, file);
  1278. /* allocate memory */
  1279. model->vertices = (float*)malloc(sizeof(float) *
  1280. 3 * (model->numvertices + 1));
  1281. model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) *
  1282. model->numtriangles);
  1283. if (model->numnormals) {
  1284. model->normals = (float*)malloc(sizeof(float) *
  1285. 3 * (model->numnormals + 1));
  1286. }
  1287. if (model->numtexcoords) {
  1288. model->texcoords = (float*)malloc(sizeof(float) *
  1289. 2 * (model->numtexcoords + 1));
  1290. }
  1291. /* rewind to beginning of file and read in the data this pass */
  1292. rewind(file);
  1293. _glmSecondPass(model, file);
  1294. /* close the file */
  1295. fclose(file);
  1296. if (!model->materials) {
  1297. model->materials = glmDefaultMaterial();
  1298. model->nummaterials = 1;
  1299. }
  1300. return model;
  1301. }
  1302. /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to
  1303. * a file.
  1304. *
  1305. * model - initialized GLMmodel structure
  1306. * filename - name of the file to write the Wavefront .OBJ format data to
  1307. * mode - a bitwise or of values describing what is written to the file
  1308. * GLM_NONE - render with only vertices
  1309. * GLM_FLAT - render with facet normals
  1310. * GLM_SMOOTH - render with vertex normals
  1311. * GLM_TEXTURE - render with texture coords
  1312. * GLM_COLOR - render with colors (color material)
  1313. * GLM_MATERIAL - render with materials
  1314. * GLM_COLOR and GLM_MATERIAL should not both be specified.
  1315. * GLM_FLAT and GLM_SMOOTH should not both be specified.
  1316. */
  1317. void
  1318. glmWriteOBJ(GLMmodel* model, char* filename, uint mode)
  1319. {
  1320. uint i;
  1321. FILE* file;
  1322. GLMgroup* group;
  1323. assert(model);
  1324. /* do a bit of warning */
  1325. if (mode & GLM_FLAT && !model->facetnorms) {
  1326. printf("glmWriteOBJ() warning: flat normal output requested "
  1327. "with no facet normals defined.\n");
  1328. mode &= ~GLM_FLAT;
  1329. }
  1330. if (mode & GLM_SMOOTH && !model->normals) {
  1331. printf("glmWriteOBJ() warning: smooth normal output requested "
  1332. "with no normals defined.\n");
  1333. mode &= ~GLM_SMOOTH;
  1334. }
  1335. if (mode & GLM_TEXTURE && !model->texcoords) {
  1336. printf("glmWriteOBJ() warning: texture coordinate output requested "
  1337. "with no texture coordinates defined.\n");
  1338. mode &= ~GLM_TEXTURE;
  1339. }
  1340. if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
  1341. printf("glmWriteOBJ() warning: flat normal output requested "
  1342. "and smooth normal output requested (using smooth).\n");
  1343. mode &= ~GLM_FLAT;
  1344. }
  1345. /* open the file */
  1346. file = fopen(filename, "w");
  1347. if (!file) {
  1348. fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n",
  1349. filename);
  1350. exit(1);
  1351. }
  1352. /* spit out a header */
  1353. fprintf(file, "# \n");
  1354. fprintf(file, "# Wavefront OBJ generated by GLM library\n");
  1355. fprintf(file, "# \n");
  1356. fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n");
  1357. fprintf(file, "# email: ndr@pobox.com\n");
  1358. fprintf(file, "# www: http://www.pobox.com/~ndr\n");
  1359. fprintf(file, "# \n");
  1360. if (mode & GLM_MATERIAL && model->mtllibname) {
  1361. fprintf(file, "\nmtllib %s\n\n", model->mtllibname);
  1362. _glmWriteMTL(model, filename, model->mtllibname);
  1363. }
  1364. /* spit out the vertices */
  1365. fprintf(file, "\n");
  1366. fprintf(file, "# %d vertices\n", model->numvertices);
  1367. for (i = 1; i <= model->numvertices; i++) {
  1368. fprintf(file, "v %f %f %f\n",
  1369. model->vertices[3 * i + 0],
  1370. model->vertices[3 * i + 1],
  1371. model->vertices[3 * i + 2]);
  1372. }
  1373. /* spit out the smooth/flat normals */
  1374. if (mode & GLM_SMOOTH) {
  1375. fprintf(file, "\n");
  1376. fprintf(file, "# %d normals\n", model->numnormals);
  1377. for (i = 1; i <= model->numnormals; i++) {
  1378. fprintf(file, "vn %f %f %f\n",
  1379. model->normals[3 * i + 0],
  1380. model->normals[3 * i + 1],
  1381. model->normals[3 * i + 2]);
  1382. }
  1383. } else if (mode & GLM_FLAT) {
  1384. fprintf(file, "\n");
  1385. fprintf(file, "# %d normals\n", model->numfacetnorms);
  1386. for (i = 1; i <= model->numnormals; i++) {
  1387. fprintf(file, "vn %f %f %f\n",
  1388. model->facetnorms[3 * i + 0],
  1389. model->facetnorms[3 * i + 1],
  1390. model->facetnorms[3 * i + 2]);
  1391. }
  1392. }
  1393. /* spit out the texture coordinates */
  1394. if (mode & GLM_TEXTURE) {
  1395. fprintf(file, "\n");
  1396. fprintf(file, "# %d texcoords\n", model->numtexcoords);
  1397. for (i = 1; i <= model->numtexcoords; i++) {
  1398. fprintf(file, "vt %f %f\n",
  1399. model->texcoords[2 * i + 0],
  1400. model->texcoords[2 * i + 1]);
  1401. }
  1402. }
  1403. fprintf(file, "\n");
  1404. fprintf(file, "# %d groups\n", model->numgroups);
  1405. fprintf(file, "# %d faces (triangles)\n", model->numtriangles);
  1406. fprintf(file, "\n");
  1407. group = model->groups;
  1408. while(group) {
  1409. fprintf(file, "g %s\n", group->name);
  1410. if (mode & GLM_MATERIAL)
  1411. fprintf(file, "usemtl %s\n", model->materials[group->material].name);
  1412. for (i = 0; i < group->numtriangles; i++) {
  1413. if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) {
  1414. fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
  1415. T(group->triangles[i]).vindices[0],
  1416. T(group->triangles[i]).nindices[0],
  1417. T(group->triangles[i]).tindices[0],
  1418. T(group->triangles[i]).vindices[1],
  1419. T(group->triangles[i]).nindices[1],
  1420. T(group->triangles[i]).tindices[1],
  1421. T(group->triangles[i]).vindices[2],
  1422. T(group->triangles[i]).nindices[2],
  1423. T(group->triangles[i]).tindices[2]);
  1424. } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) {
  1425. fprintf(file, "f %d/%d %d/%d %d/%d\n",
  1426. T(group->triangles[i]).vindices[0],
  1427. T(group->triangles[i]).findex,
  1428. T(group->triangles[i]).vindices[1],
  1429. T(group->triangles[i]).findex,
  1430. T(group->triangles[i]).vindices[2],
  1431. T(group->triangles[i]).findex);
  1432. } else if (mode & GLM_TEXTURE) {
  1433. fprintf(file, "f %d/%d %d/%d %d/%d\n",
  1434. T(group->triangles[i]).vindices[0],
  1435. T(group->triangles[i]).tindices[0],
  1436. T(group->triangles[i]).vindices[1],
  1437. T(group->triangles[i]).tindices[1],
  1438. T(group->triangles[i]).vindices[2],
  1439. T(group->triangles[i]).tindices[2]);
  1440. } else if (mode & GLM_SMOOTH) {
  1441. fprintf(file, "f %d//%d %d//%d %d//%d\n",
  1442. T(group->triangles[i]).vindices[0],
  1443. T(group->triangles[i]).nindices[0],
  1444. T(group->triangles[i]).vindices[1],
  1445. T(group->triangles[i]).nindices[1],
  1446. T(group->triangles[i]).vindices[2],
  1447. T(group->triangles[i]).nindices[2]);
  1448. } else if (mode & GLM_FLAT) {
  1449. fprintf(file, "f %d//%d %d//%d %d//%d\n",
  1450. T(group->triangles[i]).vindices[0],
  1451. T(group->triangles[i]).findex,
  1452. T(group->triangles[i]).vindices[1],
  1453. T(group->triangles[i]).findex,
  1454. T(group->triangles[i]).vindices[2],
  1455. T(group->triangles[i]).findex);
  1456. } else {
  1457. fprintf(file, "f %d %d %d\n",
  1458. T(group->triangles[i]).vindices[0],
  1459. T(group->triangles[i]).vindices[1],
  1460. T(group->triangles[i]).vindices[2]);
  1461. }
  1462. }
  1463. fprintf(file, "\n");
  1464. group = group->next;
  1465. }
  1466. fclose(file);
  1467. }
  1468. /* glmWeld: eliminate (weld) vectors that are within an epsilon of
  1469. * each other.
  1470. *
  1471. * model - initialized GLMmodel structure
  1472. * epsilon - maximum difference between vertices
  1473. * ( 0.00001 is a good start for a unitized model)
  1474. *
  1475. */
  1476. void
  1477. glmWeld(GLMmodel* model, float epsilon)
  1478. {
  1479. float* vectors;
  1480. float* copies;
  1481. uint numvectors;
  1482. uint i;
  1483. /* vertices */
  1484. numvectors = model->numvertices;
  1485. vectors = model->vertices;
  1486. copies = _glmWeldVectors(vectors, &numvectors, epsilon);
  1487. printf("glmWeld(): %d redundant vertices.\n",
  1488. model->numvertices - numvectors - 1);
  1489. for (i = 0; i < model->numtriangles; i++) {
  1490. T(i).vindices[0] = (uint)vectors[3 * T(i).vindices[0] + 0];
  1491. T(i).vindices[1] = (uint)vectors[3 * T(i).vindices[1] + 0];
  1492. T(i).vindices[2] = (uint)vectors[3 * T(i).vindices[2] + 0];
  1493. }
  1494. /* free space for old vertices */
  1495. free(vectors);
  1496. /* allocate space for the new vertices */
  1497. model->numvertices = numvectors;
  1498. model->vertices = (float*)malloc(sizeof(float) *
  1499. 3 * (model->numvertices + 1));
  1500. /* copy the optimized vertices into the actual vertex list */
  1501. for (i = 1; i <= model->numvertices; i++) {
  1502. model->vertices[3 * i + 0] = copies[3 * i + 0];
  1503. model->vertices[3 * i + 1] = copies[3 * i + 1];
  1504. model->vertices[3 * i + 2] = copies[3 * i + 2];
  1505. }
  1506. free(copies);
  1507. }
  1508. void
  1509. glmReIndex(GLMmodel *model)
  1510. {
  1511. uint i, j, n;
  1512. GLMgroup* group;
  1513. float *newNormals = NULL;
  1514. float *newTexcoords = NULL;
  1515. const uint numv = model->numvertices;
  1516. if (model->numnormals > 0)
  1517. newNormals = (float *) malloc((numv + 1) * 3 * sizeof(float));
  1518. if (model->numtexcoords > 0)
  1519. newTexcoords = (float *) malloc((numv + 1) * 2 * sizeof(float));
  1520. for (group = model->groups; group; group = group->next) {
  1521. n = group->numtriangles;
  1522. group->triIndexes = (uint *) malloc(n * 3 * sizeof(uint));
  1523. group->minIndex = 10000000;
  1524. group->maxIndex = 0;
  1525. for (i = 0; i < n; i++) {
  1526. for (j = 0; j < 3; j++) {
  1527. uint vindex = T(group->triangles[i]).vindices[j];
  1528. uint nindex = T(group->triangles[i]).nindices[j];
  1529. uint tindex = T(group->triangles[i]).tindices[j];
  1530. float *nrm = &model->normals[nindex * 3];
  1531. float *tex = &model->texcoords[tindex * 2];
  1532. if (newNormals) {
  1533. assert(vindex * 3 + 2 < (numv + 1) * 3);
  1534. newNormals[vindex * 3 + 0] = nrm[0];
  1535. newNormals[vindex * 3 + 1] = nrm[1];
  1536. newNormals[vindex * 3 + 2] = nrm[2];
  1537. }
  1538. if (newTexcoords) {
  1539. newTexcoords[vindex * 2 + 0] = tex[0];
  1540. newTexcoords[vindex * 2 + 1] = tex[1];
  1541. }
  1542. T(group->triangles[i]).nindices[j] = vindex;
  1543. T(group->triangles[i]).tindices[j] = vindex;
  1544. group->triIndexes[i * 3 + j] = vindex;
  1545. if (vindex > group->maxIndex)
  1546. group->maxIndex = vindex;
  1547. if (vindex < group->minIndex)
  1548. group->minIndex = vindex;
  1549. }
  1550. }
  1551. }
  1552. if (newNormals) {
  1553. free(model->normals);
  1554. model->normals = newNormals;
  1555. model->numnormals = model->numvertices;
  1556. }
  1557. if (newTexcoords) {
  1558. free(model->texcoords);
  1559. model->texcoords = newTexcoords;
  1560. model->numtexcoords = model->numvertices;
  1561. }
  1562. }
  1563. void
  1564. glmPrint(const GLMmodel *model)
  1565. {
  1566. uint i, j, grp, n;
  1567. GLMgroup* group;
  1568. uint totalTris = 0;
  1569. grp = 0;
  1570. printf("%u vertices\n", model->numvertices);
  1571. printf("%u normals\n", model->numnormals);
  1572. printf("%u texcoords\n", model->numtexcoords);
  1573. for (group = model->groups; group; group = group->next, grp++) {
  1574. printf("Group %u:\n", grp);
  1575. printf(" Min index %u, max index %u\n", group->minIndex, group->maxIndex);
  1576. #if 0
  1577. if (mode & GLM_MATERIAL) {
  1578. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,
  1579. model->materials[group->material].ambient);
  1580. glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
  1581. model->materials[group->material].diffuse);
  1582. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,
  1583. model->materials[group->material].specular);
  1584. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS,
  1585. model->materials[group->material].shininess);
  1586. }
  1587. if (mode & GLM_COLOR) {
  1588. glColor3fv(model->materials[group->material].diffuse);
  1589. }
  1590. #endif
  1591. totalTris += group->numtriangles;
  1592. printf(" %u triangles\n", group->numtriangles);
  1593. n = group->numtriangles;
  1594. if (n > 10)
  1595. n = 10;
  1596. for (i = 0; i < n; i++) {
  1597. printf(" %u: vert ", i);
  1598. for (j = 0; j < 3; j++) {
  1599. printf("%u ", T(group->triangles[i]).vindices[j]);
  1600. }
  1601. printf(" normal ");
  1602. for (j = 0; j < 3; j++) {
  1603. printf("%u ", T(group->triangles[i]).nindices[j]);
  1604. }
  1605. printf(" tex ");
  1606. for (j = 0; j < 3; j++) {
  1607. printf("%u ", T(group->triangles[i]).tindices[j]);
  1608. }
  1609. printf("\n");
  1610. }
  1611. }
  1612. printf("Total tris: %u\n", totalTris);
  1613. }
  1614. #if 0
  1615. /* normals */
  1616. if (model->numnormals) {
  1617. numvectors = model->numnormals;
  1618. vectors = model->normals;
  1619. copies = _glmOptimizeVectors(vectors, &numvectors);
  1620. printf("glmOptimize(): %d redundant normals.\n",
  1621. model->numnormals - numvectors);
  1622. for (i = 0; i < model->numtriangles; i++) {
  1623. T(i).nindices[0] = (uint)vectors[3 * T(i).nindices[0] + 0];
  1624. T(i).nindices[1] = (uint)vectors[3 * T(i).nindices[1] + 0];
  1625. T(i).nindices[2] = (uint)vectors[3 * T(i).nindices[2] + 0];
  1626. }
  1627. /* free space for old normals */
  1628. free(vectors);
  1629. /* allocate space for the new normals */
  1630. model->numnormals = numvectors;
  1631. model->normals = (float*)malloc(sizeof(float) *
  1632. 3 * (model->numnormals + 1));
  1633. /* copy the optimized vertices into the actual vertex list */
  1634. for (i = 1; i <= model->numnormals; i++) {
  1635. model->normals[3 * i + 0] = copies[3 * i + 0];
  1636. model->normals[3 * i + 1] = copies[3 * i + 1];
  1637. model->normals[3 * i + 2] = copies[3 * i + 2];
  1638. }
  1639. free(copies);
  1640. }
  1641. /* texcoords */
  1642. if (model->numtexcoords) {
  1643. numvectors = model->numtexcoords;
  1644. vectors = model->texcoords;
  1645. copies = _glmOptimizeVectors(vectors, &numvectors);
  1646. printf("glmOptimize(): %d redundant texcoords.\n",
  1647. model->numtexcoords - numvectors);
  1648. for (i = 0; i < model->numtriangles; i++) {
  1649. for (j = 0; j < 3; j++) {
  1650. T(i).tindices[j] = (uint)vectors[3 * T(i).tindices[j] + 0];
  1651. }
  1652. }
  1653. /* free space for old texcoords */
  1654. free(vectors);
  1655. /* allocate space for the new texcoords */
  1656. model->numtexcoords = numvectors;
  1657. model->texcoords = (float*)malloc(sizeof(float) *
  1658. 2 * (model->numtexcoords + 1));
  1659. /* copy the optimized vertices into the actual vertex list */
  1660. for (i = 1; i <= model->numtexcoords; i++) {
  1661. model->texcoords[2 * i + 0] = copies[2 * i + 0];
  1662. model->texcoords[2 * i + 1] = copies[2 * i + 1];
  1663. }
  1664. free(copies);
  1665. }
  1666. #endif
  1667. #if 0
  1668. /* look for unused vertices */
  1669. /* look for unused normals */
  1670. /* look for unused texcoords */
  1671. for (i = 1; i <= model->numvertices; i++) {
  1672. for (j = 0; j < model->numtriangles; i++) {
  1673. if (T(j).vindices[0] == i ||
  1674. T(j).vindices[1] == i ||
  1675. T(j).vindices[1] == i)
  1676. break;
  1677. }
  1678. }
  1679. #endif