Source code of Windows XP (NT5)
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.

634 lines
17 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: nff.c
  3. *
  4. * Parse the Wavefront OBJ format.
  5. *
  6. * Documentation on OBJ available from:
  7. *
  8. * Wavefront Technologies, 530 E. Montecito St., Santa Barbara, CA 93103,
  9. * Phone: 805-962-8117.
  10. *
  11. * Murray, J. D. and van Ryper, W., _Encyclopedia of Graphics File Formats_,
  12. * O'Reilly & Associates, 1994, pp. 727-734.
  13. *
  14. * Created: 15-Mar-1995 23:27:08
  15. * Author: Gilman Wong [gilmanw]
  16. *
  17. * Copyright (c) 1995 Microsoft Corporation
  18. *
  19. \**************************************************************************/
  20. #include <windows.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <ctype.h>
  24. #include <math.h>
  25. #include "global.h"
  26. #include "nff.h"
  27. #define STATIC
  28. typedef struct tagOBJPRIV
  29. {
  30. BOOL bInList; // TRUE while compiling display list
  31. // Vertex arrays
  32. MyXYZ *pxyzGeoVert; // array of geometric vertices
  33. MyXYZ *pxyzTexVert; // array of texture vertices
  34. MyXYZ *pxyzNorm; // array of vertex normals
  35. // Number allocated for each array
  36. GLuint numGeoVert; // total number of geometric vertices
  37. GLuint numTexVert; // total number of texture vertices
  38. GLuint numNorm; // total number of normals
  39. // Number of vertices currently in each array
  40. GLuint curGeoVert; // current number of geometric vertices
  41. GLuint curTexVert; // current number of texture vertices
  42. GLuint curNorm; // current number of normals
  43. GLfloat rMax;
  44. } OBJPRIV;
  45. GLint maxLights;
  46. STATIC void parseObjFile(SCENE *, LPTSTR);
  47. STATIC void DoDisplayList(SCENE *);
  48. STATIC void EndDisplayList(SCENE *);
  49. STATIC void parseObjNormal(SCENE *scene, FILE *file, char *ach, int n);
  50. STATIC void parseObjTextureVertex(SCENE *scene, FILE *file, char *ach, int n);
  51. STATIC void parseObjVertex(SCENE *scene, FILE *file, char *ach, int n);
  52. STATIC void parseObjFace(SCENE *scene, FILE *file, char *ach, int n);
  53. STATIC void fakeObjLight(SCENE *scene, GLfloat x, GLfloat y, GLfloat z);
  54. SCENE *ObjOpenScene(LPTSTR lpstr)
  55. {
  56. SCENE *scene;
  57. scene = (SCENE *) LocalAlloc(LMEM_FIXED, sizeof(SCENE) + sizeof(OBJPRIV));
  58. if (scene)
  59. {
  60. OBJPRIV *objPriv = (OBJPRIV *) (scene + 1);
  61. glGetIntegerv(GL_MAX_LIGHTS, &maxLights);
  62. scene->xyzFrom.x = 0.0;
  63. scene->xyzFrom.y = 0.0;
  64. //scene->xyzFrom.z = 5.0;
  65. scene->xyzAt.x = 0.0;
  66. scene->xyzAt.y = 0.0;
  67. scene->xyzAt.z = 0.0;
  68. scene->xyzUp.x = 0.0;
  69. scene->xyzUp.y = 1.0;
  70. scene->xyzUp.z = 0.0;
  71. scene->ViewAngle = 45.0f;
  72. scene->Hither = 0.1f;
  73. //scene->Yon = 100.0f;
  74. scene->AspectRatio = 1.0f;
  75. scene->szWindow.cx = 400;
  76. scene->szWindow.cy = 400;
  77. scene->rgbaClear.r = (GLfloat) 0.0; // default is black
  78. scene->rgbaClear.g = (GLfloat) 0.0;
  79. scene->rgbaClear.b = (GLfloat) 0.0;
  80. scene->rgbaClear.a = (GLfloat) 1.0;
  81. scene->Lights.count = 0;
  82. scene->Lights.listBase = 1;
  83. scene->Objects.count = 1;
  84. scene->Objects.listBase = maxLights + 1;
  85. scene->pvData = (VOID *) objPriv;
  86. objPriv->bInList = FALSE;
  87. objPriv->pxyzGeoVert = (MyXYZ *) NULL;
  88. objPriv->pxyzTexVert = (MyXYZ *) NULL;
  89. objPriv->pxyzNorm = (MyXYZ *) NULL;
  90. objPriv->numGeoVert = 0;
  91. objPriv->numTexVert = 0;
  92. objPriv->numNorm = 0;
  93. objPriv->curGeoVert = 0;
  94. objPriv->curTexVert = 0;
  95. objPriv->curNorm = 0;
  96. objPriv->rMax = (GLfloat) 0.0;
  97. LBprintf("================================");
  98. LBprintf("Parsing OBJ file, please wait...");
  99. LBprintf("================================");
  100. parseObjFile(scene, lpstr);
  101. LBprintf("Here we go!");
  102. scene->xyzFrom.z = 2.0f * objPriv->rMax * tan(90.0f - scene->ViewAngle);
  103. scene->Yon = (scene->xyzAt.z - scene->xyzFrom.z) * (scene->xyzAt.z - scene->xyzFrom.z);
  104. scene->Yon = sqrt(scene->Yon) * 2.5f;
  105. fakeObjLight(scene, objPriv->rMax, objPriv->rMax, scene->xyzFrom.z);
  106. }
  107. else
  108. {
  109. LBprintf("ObjOpenScene: memory allocation failure");
  110. }
  111. return scene;
  112. }
  113. STATIC void parseObjFile(SCENE *scene, LPTSTR lpstr)
  114. {
  115. FILE *file;
  116. char ach[512];
  117. char *pch;
  118. OBJPRIV *objPriv = (OBJPRIV *) scene->pvData;
  119. file = fopen(lpstr, "rt");
  120. if (file)
  121. {
  122. BOOL bKeepGoing = TRUE;
  123. // Do a quick first pass through the file so we know how big to
  124. // make the arrays.
  125. do
  126. {
  127. if (fgets(ach, sizeof(ach), file) != NULL)
  128. {
  129. // Skip leading whitespace. Some input files have this.
  130. pch = ach;
  131. while (*pch && isspace(*pch)) pch++;
  132. switch(pch[0])
  133. {
  134. case 'V':
  135. case 'v':
  136. switch(pch[1])
  137. {
  138. case 'N':
  139. case 'n':
  140. objPriv->numNorm++;
  141. break;
  142. case 'T':
  143. case 't':
  144. //objPriv->numTexVert++;
  145. break;
  146. case 'P':
  147. case 'p':
  148. break;
  149. default:
  150. objPriv->numGeoVert++;
  151. break;
  152. }
  153. break;
  154. default:
  155. break;
  156. }
  157. }
  158. else
  159. {
  160. bKeepGoing = FALSE;
  161. //LBprintf("possible EOF");
  162. }
  163. } while (bKeepGoing || !feof(file));
  164. rewind(file);
  165. // Allocate the arrays.
  166. objPriv->pxyzGeoVert = (MyXYZ *)
  167. LocalAlloc(LMEM_FIXED, sizeof(MyXYZ) * (objPriv->numNorm +
  168. objPriv->numTexVert +
  169. objPriv->numGeoVert));
  170. objPriv->pxyzTexVert = objPriv->pxyzGeoVert + objPriv->numGeoVert;
  171. objPriv->pxyzNorm = objPriv->pxyzTexVert + objPriv->numTexVert;
  172. // Parse the file for real.
  173. bKeepGoing = TRUE;
  174. do
  175. {
  176. if (fgets(ach, sizeof(ach), file) != NULL)
  177. {
  178. // Skip leading whitespace. Some input files have this.
  179. pch = ach;
  180. while (*pch && isspace(*pch)) pch++;
  181. switch(pch[0])
  182. {
  183. case 'G':
  184. case 'g':
  185. //LBprintf(ach);
  186. break;
  187. case 'V':
  188. case 'v':
  189. switch(pch[1])
  190. {
  191. case 'N':
  192. case 'n':
  193. parseObjNormal(scene, file, pch, sizeof(ach) - (pch - ach));
  194. break;
  195. case 'T':
  196. case 't':
  197. //parseObjTextureVertex(scene, file, pch, sizeof(ach) - (pch - ach));
  198. break;
  199. case 'P':
  200. case 'p':
  201. break;
  202. default:
  203. parseObjVertex(scene, file, pch, sizeof(ach) - (pch - ach));
  204. break;
  205. }
  206. break;
  207. case 'f':
  208. case 'F':
  209. switch(pch[1])
  210. {
  211. case 'O':
  212. case 'o':
  213. parseObjFace(scene, file, &pch[1], sizeof(ach) - (pch - ach) - 1);
  214. break;
  215. default:
  216. parseObjFace(scene, file, pch, sizeof(ach) - (pch - ach));
  217. break;
  218. }
  219. break;
  220. case '#':
  221. LBprintf(pch);
  222. break;
  223. default:
  224. //LBprintf("unknown: %s", ach);
  225. break;
  226. }
  227. }
  228. else
  229. {
  230. bKeepGoing = FALSE;
  231. //LBprintf("possible EOF");
  232. }
  233. } while (bKeepGoing || !feof(file));
  234. fclose(file);
  235. EndDisplayList(scene);
  236. }
  237. else
  238. {
  239. LBprintf("fopen failed %s", lpstr);
  240. LBprintf("USAGE: viewer [OBJ filename].OBJ");
  241. }
  242. }
  243. STATIC void DoDisplayList(SCENE *scene)
  244. {
  245. if (!((OBJPRIV *)scene->pvData)->bInList)
  246. {
  247. ((OBJPRIV *)scene->pvData)->bInList = TRUE;
  248. glNewList(scene->Objects.listBase, GL_COMPILE);
  249. //LBprintf("BEGIN DISPLAY LIST");
  250. }
  251. }
  252. STATIC void EndDisplayList(SCENE *scene)
  253. {
  254. if (((OBJPRIV *)scene->pvData)->bInList)
  255. {
  256. ((OBJPRIV *)scene->pvData)->bInList = FALSE;
  257. glEndList();
  258. //LBprintf("END DISPLAY LIST");
  259. }
  260. }
  261. STATIC void parseObjNormal(SCENE *scene, FILE *file, char *ach, int n)
  262. {
  263. OBJPRIV *objPriv = (OBJPRIV *) scene->pvData;
  264. sscanf(ach, "vn %g %g %g", &objPriv->pxyzNorm[objPriv->curNorm].x,
  265. &objPriv->pxyzNorm[objPriv->curNorm].y,
  266. &objPriv->pxyzNorm[objPriv->curNorm].z);
  267. objPriv->curNorm++;
  268. }
  269. STATIC void parseObjTextureVertex(SCENE *scene, FILE *file, char *ach, int n)
  270. {
  271. OBJPRIV *objPriv = (OBJPRIV *) scene->pvData;
  272. sscanf(ach, "vt %g %g %g", &objPriv->pxyzTexVert[objPriv->curTexVert].x,
  273. &objPriv->pxyzTexVert[objPriv->curTexVert].y,
  274. &objPriv->pxyzTexVert[objPriv->curTexVert].z);
  275. objPriv->curTexVert++;
  276. }
  277. STATIC void parseObjVertex(SCENE *scene, FILE *file, char *ach, int n)
  278. {
  279. OBJPRIV *objPriv = (OBJPRIV *) scene->pvData;
  280. sscanf(ach, "v %g %g %g", &objPriv->pxyzGeoVert[objPriv->curGeoVert].x,
  281. &objPriv->pxyzGeoVert[objPriv->curGeoVert].y,
  282. &objPriv->pxyzGeoVert[objPriv->curGeoVert].z);
  283. objPriv->curGeoVert++;
  284. }
  285. STATIC void parseObjFace(SCENE *scene, FILE *file, char *ach, int n)
  286. {
  287. OBJPRIV *objPriv = (OBJPRIV *) scene->pvData;
  288. char *pch;
  289. GLuint i, numVert = 0;
  290. char achFormat[20];
  291. BOOL bReadTex = FALSE, bReadNorm = FALSE;
  292. GLuint v, vt, vn;
  293. GLfloat rMax;
  294. GLuint vv[3];
  295. MyXYZ faceNorm;
  296. DoDisplayList(scene);
  297. // Determine number of vertices.
  298. // Each vertex is represented by a field of non-whitespace characters
  299. // which are numbers or '/' characters.
  300. pch = &ach[1];
  301. while ( *pch )
  302. {
  303. while (*pch && isspace(*pch))
  304. pch++;
  305. if (*pch)
  306. numVert++;
  307. while (*pch && !isspace(*pch))
  308. pch++;
  309. }
  310. // Bail if there aren't enough vertices to define a face.
  311. if (numVert < 3)
  312. {
  313. LBprintf("bad line: %s", ach);
  314. return;
  315. }
  316. // Determine type of vertex info available. Each vertex has the form
  317. // v[/[vt][/[vn]]]. Some examples include:
  318. //
  319. // f 1/2/3 ...
  320. // f 1//3 ...
  321. // f 1/2 ...
  322. // f 1/2/ ...
  323. // f 1 ...
  324. // f 1// ...
  325. // etc.
  326. pch = &ach[1];
  327. while (*pch && isspace(*pch))
  328. pch++;
  329. if (*pch && isdigit(*pch))
  330. lstrcpy(achFormat, "%ld");
  331. while (*pch && isdigit(*pch))
  332. pch++;
  333. if (*pch == '/')
  334. {
  335. lstrcat(achFormat, "/");
  336. pch++;
  337. }
  338. if (*pch && isdigit(*pch))
  339. {
  340. bReadTex = TRUE;
  341. lstrcat(achFormat, "%ld");
  342. while (*pch && isdigit(*pch))
  343. pch++;
  344. }
  345. if (*pch == '/')
  346. {
  347. lstrcat(achFormat, "/");
  348. pch++;
  349. }
  350. if (*pch && isdigit(*pch))
  351. {
  352. bReadNorm = TRUE;
  353. lstrcat(achFormat, "%ld");
  354. while (*pch && isdigit(*pch))
  355. pch++;
  356. }
  357. // If we need to compute our own normal, let's do it now.
  358. pch = &ach[1];
  359. if (!bReadNorm)
  360. {
  361. for ( i = 0; i < 3; i++ )
  362. {
  363. while (*pch && isspace(*pch))
  364. pch++;
  365. sscanf(pch, "%ld", &vv[i]);
  366. if (vv[i] > 0)
  367. vv[i] = vv[i] - 1;
  368. else
  369. vv[i] = objPriv->curGeoVert + vv[i];
  370. while (*pch && !isspace(*pch))
  371. pch++;
  372. }
  373. calcNorm((GLfloat *) &faceNorm,
  374. (GLfloat *) &objPriv->pxyzGeoVert[vv[0]],
  375. (GLfloat *) &objPriv->pxyzGeoVert[vv[1]],
  376. (GLfloat *) &objPriv->pxyzGeoVert[vv[2]]);
  377. }
  378. // Finally, parse out the vertices.
  379. pch = &ach[1];
  380. glBegin(numVert == 3 ? GL_TRIANGLES :
  381. numVert == 4 ? GL_QUADS :
  382. GL_POLYGON);
  383. if (!bReadTex && !bReadNorm)
  384. {
  385. glNormal3fv((GLfloat *) &faceNorm);
  386. for ( i = 0; i < numVert; i++ )
  387. {
  388. while (*pch && isspace(*pch))
  389. pch++;
  390. sscanf(pch, achFormat, &v);
  391. if (v > 0)
  392. v = v - 1;
  393. else
  394. v = objPriv->curGeoVert + v;
  395. glVertex3fv((GLfloat *)&objPriv->pxyzGeoVert[v]);
  396. if (fabs(objPriv->pxyzGeoVert[v].x) > objPriv->rMax)
  397. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].x);
  398. if (fabs(objPriv->pxyzGeoVert[v].y) > objPriv->rMax)
  399. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].y);
  400. if (fabs(objPriv->pxyzGeoVert[v].z) > objPriv->rMax)
  401. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].z);
  402. while (*pch && !isspace(*pch))
  403. pch++;
  404. }
  405. }
  406. else if (!bReadTex && bReadNorm)
  407. {
  408. for ( i = 0; i < numVert; i++ )
  409. {
  410. while (*pch && isspace(*pch))
  411. pch++;
  412. sscanf(pch, achFormat, &v, &vn);
  413. if (v > 0)
  414. v = v - 1;
  415. else
  416. v = objPriv->curGeoVert + v;
  417. if (vn > 0)
  418. vn = vn - 1;
  419. else
  420. vn = objPriv->curGeoVert + vn;
  421. glNormal3fv((GLfloat *)&objPriv->pxyzNorm[vn]);
  422. glVertex3fv((GLfloat *)&objPriv->pxyzGeoVert[v]);
  423. if (fabs(objPriv->pxyzGeoVert[v].x) > objPriv->rMax)
  424. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].x);
  425. if (fabs(objPriv->pxyzGeoVert[v].y) > objPriv->rMax)
  426. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].y);
  427. if (fabs(objPriv->pxyzGeoVert[v].z) > objPriv->rMax)
  428. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].z);
  429. while (*pch && !isspace(*pch))
  430. pch++;
  431. }
  432. }
  433. else if (bReadTex && !bReadNorm)
  434. {
  435. glNormal3fv((GLfloat *) &faceNorm);
  436. for ( i = 0; i < numVert; i++ )
  437. {
  438. while (*pch && isspace(*pch))
  439. pch++;
  440. sscanf(pch, achFormat, &v, &vt);
  441. if (v > 0)
  442. v = v - 1;
  443. else
  444. v = objPriv->curGeoVert + v;
  445. if (vt > 0)
  446. vt = vt - 1;
  447. else
  448. vt = objPriv->curGeoVert + vt;
  449. //!!! ignore texture vertex for now; just use the geometry
  450. glVertex3fv((GLfloat *)&objPriv->pxyzGeoVert[v]);
  451. if (fabs(objPriv->pxyzGeoVert[v].x) > objPriv->rMax)
  452. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].x);
  453. if (fabs(objPriv->pxyzGeoVert[v].y) > objPriv->rMax)
  454. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].y);
  455. if (fabs(objPriv->pxyzGeoVert[v].z) > objPriv->rMax)
  456. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].z);
  457. while (*pch && !isspace(*pch))
  458. pch++;
  459. }
  460. }
  461. else
  462. {
  463. for ( i = 0; i < numVert; i++ )
  464. {
  465. while (*pch && isspace(*pch))
  466. pch++;
  467. sscanf(pch, achFormat, &v, &vt, &vn);
  468. if (v > 0)
  469. v = v - 1;
  470. else
  471. v = objPriv->curGeoVert + v;
  472. if (vt > 0)
  473. vt = vt - 1;
  474. else
  475. vt = objPriv->curGeoVert + vt;
  476. if (vn > 0)
  477. vn = vn - 1;
  478. else
  479. vn = objPriv->curGeoVert + vn;
  480. //!!! ignore texture vertex for now; just use the geometry
  481. glNormal3fv((GLfloat *)&objPriv->pxyzNorm[vn]);
  482. glVertex3fv((GLfloat *)&objPriv->pxyzGeoVert[v]);
  483. if (fabs(objPriv->pxyzGeoVert[v].x) > objPriv->rMax)
  484. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].x);
  485. if (fabs(objPriv->pxyzGeoVert[v].y) > objPriv->rMax)
  486. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].y);
  487. if (fabs(objPriv->pxyzGeoVert[v].z) > objPriv->rMax)
  488. objPriv->rMax = fabs(objPriv->pxyzGeoVert[v].z);
  489. while (*pch && !isspace(*pch))
  490. pch++;
  491. }
  492. }
  493. glEnd();
  494. }
  495. STATIC void fakeObjLight(SCENE *scene, GLfloat x, GLfloat y, GLfloat z)
  496. {
  497. MyXYZ xyz;
  498. MyRGBA rgb = {1.0f, 1.0f, 1.0f, 1.0f};
  499. xyz.x = x;
  500. xyz.y = y;
  501. xyz.z = z;
  502. if (scene->Lights.count < (maxLights + 1))
  503. {
  504. glNewList(scene->Lights.listBase + scene->Lights.count, GL_COMPILE);
  505. glLightfv(GL_LIGHT0 + scene->Lights.count, GL_POSITION, (GLfloat *) &xyz);
  506. glLightfv(GL_LIGHT0 + scene->Lights.count, GL_DIFFUSE, (GLfloat *) &rgb);
  507. glLightfv(GL_LIGHT0 + scene->Lights.count, GL_SPECULAR, (GLfloat *) &rgb);
  508. glEndList();
  509. scene->Lights.count++;
  510. }
  511. }