416 lines
12 KiB
C
416 lines
12 KiB
C
|
/******************************Module*Header*******************************\
|
||
|
* Module Name: nff.c
|
||
|
*
|
||
|
* Parse the Neutral File Format (.NFF) by Eric Haines of 3D/Eye Inc.
|
||
|
*
|
||
|
* Documentation on NFF available from a varity of sources including:
|
||
|
*
|
||
|
* Eric Haines, 3D/Eye Inc., 2359 N. Triphammer Rd., Ithaca, NY, 14850,
|
||
|
* erich@eye.com.
|
||
|
*
|
||
|
* Murray, J. D. and van Ryper, W., _Encyclopedia of Graphics File Formats_,
|
||
|
* O'Reilly & Associates, 1994, pp. 471-478.
|
||
|
*
|
||
|
* Created: 14-Mar-1995 23:26:34
|
||
|
* Author: Gilman Wong [gilmanw]
|
||
|
*
|
||
|
* Copyright (c) 1995 Microsoft Corporation
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <ctype.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
#include "global.h"
|
||
|
#include "nff.h"
|
||
|
|
||
|
#define STATIC
|
||
|
|
||
|
typedef struct tagNFFPRIV
|
||
|
{
|
||
|
BOOL bInList; // TRUE while compiling display list
|
||
|
BOOL bKayHack; // support for the 'k' backface color hack
|
||
|
} NFFPRIV;
|
||
|
|
||
|
GLint maxLights;
|
||
|
|
||
|
STATIC void parseNffFile(SCENE *, LPTSTR);
|
||
|
STATIC void DoDisplayList(SCENE *);
|
||
|
STATIC void EndDisplayList(SCENE *);
|
||
|
STATIC void parseNffViewpoint(SCENE *scene, FILE *file, char *ach, int n);
|
||
|
STATIC void parseNffBackground(SCENE *scene, FILE *file, char *ach, int n);
|
||
|
STATIC void parseNffLight(SCENE *scene, FILE *file, char *ach, int n);
|
||
|
STATIC void parseNffColor(SCENE *scene, FILE *file, char *ach, int n, GLenum matSide);
|
||
|
STATIC void parseNffCone(SCENE *scene, FILE *file, char *ach, int n);
|
||
|
STATIC void parseNffSphere(SCENE *scene, FILE *file, char *ach, int n);
|
||
|
STATIC void parseNffPolygon(SCENE *scene, FILE *file, char *ach, int n);
|
||
|
STATIC void parseNffPolygonPatch(SCENE *scene, FILE *file, char *ach, int n);
|
||
|
|
||
|
SCENE *NffOpenScene(LPTSTR lpstr)
|
||
|
{
|
||
|
SCENE *scene;
|
||
|
|
||
|
scene = (SCENE *) LocalAlloc(LMEM_FIXED, sizeof(SCENE) + sizeof(NFFPRIV));
|
||
|
if (scene)
|
||
|
{
|
||
|
NFFPRIV *nffPriv = (NFFPRIV *) (scene + 1);
|
||
|
|
||
|
glGetIntegerv(GL_MAX_LIGHTS, &maxLights);
|
||
|
|
||
|
scene->xyzFrom.x = 0.0;
|
||
|
scene->xyzFrom.y = 0.0;
|
||
|
scene->xyzFrom.z = 5.0;
|
||
|
|
||
|
scene->xyzAt.x = 0.0;
|
||
|
scene->xyzAt.y = 0.0;
|
||
|
scene->xyzAt.z = 0.0;
|
||
|
|
||
|
scene->xyzUp.x = 0.0;
|
||
|
scene->xyzUp.y = 1.0;
|
||
|
scene->xyzUp.z = 0.0;
|
||
|
|
||
|
scene->ViewAngle = 45.0f;
|
||
|
scene->Hither = 0.1f;
|
||
|
scene->Yon = 1000000000.0f; // always "infinity" for NFF
|
||
|
scene->AspectRatio = 1.0f; // always 1.0 for NFF
|
||
|
|
||
|
scene->szWindow.cx = 300;
|
||
|
scene->szWindow.cy = 300;
|
||
|
|
||
|
scene->rgbaClear.r = (GLfloat) 0.0; // default is black
|
||
|
scene->rgbaClear.g = (GLfloat) 0.0;
|
||
|
scene->rgbaClear.b = (GLfloat) 0.0;
|
||
|
scene->rgbaClear.a = (GLfloat) 1.0;
|
||
|
|
||
|
scene->Lights.count = 0;
|
||
|
scene->Lights.listBase = 1;
|
||
|
|
||
|
scene->Objects.count = 1;
|
||
|
scene->Objects.listBase = maxLights + 1;
|
||
|
|
||
|
scene->pvData = (VOID *) nffPriv;
|
||
|
nffPriv->bInList = FALSE;
|
||
|
nffPriv->bKayHack = FALSE;
|
||
|
|
||
|
LBprintf("================================");
|
||
|
LBprintf("Parsing NFF file, please wait...");
|
||
|
LBprintf("================================");
|
||
|
parseNffFile(scene, lpstr);
|
||
|
LBprintf("Here we go!");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LBprintf("NffOpenScene: memory allocation failure");
|
||
|
}
|
||
|
|
||
|
return scene;
|
||
|
}
|
||
|
|
||
|
STATIC void parseNffFile(SCENE *scene, LPTSTR lpstr)
|
||
|
{
|
||
|
FILE *file;
|
||
|
char ach[512];
|
||
|
char achToken[5];
|
||
|
|
||
|
file = fopen(lpstr, "r");
|
||
|
|
||
|
if (file)
|
||
|
{
|
||
|
BOOL bKeepGoing = TRUE;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (fgets(ach, 512, file) != NULL)
|
||
|
{
|
||
|
switch(ach[0])
|
||
|
{
|
||
|
case 'v':
|
||
|
case 'V':
|
||
|
parseNffViewpoint(scene, file, ach, 512);
|
||
|
break;
|
||
|
|
||
|
case 'b':
|
||
|
case 'B':
|
||
|
parseNffBackground(scene, file, ach, 512);
|
||
|
break;
|
||
|
|
||
|
case 'l':
|
||
|
case 'L':
|
||
|
parseNffLight(scene, file, ach, 512);
|
||
|
break;
|
||
|
|
||
|
case 'f':
|
||
|
case 'F':
|
||
|
if (((NFFPRIV *)scene->pvData)->bKayHack)
|
||
|
parseNffColor(scene, file, ach, 512, GL_FRONT);
|
||
|
else
|
||
|
parseNffColor(scene, file, ach, 512, GL_FRONT_AND_BACK);
|
||
|
break;
|
||
|
|
||
|
case 'k':
|
||
|
case 'K':
|
||
|
parseNffColor(scene, file, ach, 512, GL_BACK);
|
||
|
((NFFPRIV *)scene->pvData)->bKayHack = TRUE;
|
||
|
break;
|
||
|
|
||
|
case 'c':
|
||
|
case 'C':
|
||
|
parseNffCone(scene, file, ach, 512);
|
||
|
break;
|
||
|
|
||
|
case 's':
|
||
|
case 'S':
|
||
|
parseNffSphere(scene, file, ach, 512);
|
||
|
break;
|
||
|
|
||
|
case 'p':
|
||
|
case 'P':
|
||
|
if ((ach[1] == 'p') || (ach[1] == 'P'))
|
||
|
parseNffPolygonPatch(scene, file, ach, 512);
|
||
|
else
|
||
|
parseNffPolygon(scene, file, ach, 512);
|
||
|
break;
|
||
|
|
||
|
case '#':
|
||
|
LBprintf(ach);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
LBprintf("unknown: %s", ach);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bKeepGoing = FALSE;
|
||
|
//LBprintf("possible EOF");
|
||
|
}
|
||
|
|
||
|
} while (bKeepGoing || !feof(file));
|
||
|
fclose(file);
|
||
|
|
||
|
EndDisplayList(scene);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LBprintf("fopen failed %s", lpstr);
|
||
|
LBprintf("USAGE: viewer [NFF filename].NFF");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STATIC void DoDisplayList(SCENE *scene)
|
||
|
{
|
||
|
if (!((NFFPRIV *)scene->pvData)->bInList)
|
||
|
{
|
||
|
((NFFPRIV *)scene->pvData)->bInList = TRUE;
|
||
|
|
||
|
glNewList(scene->Objects.listBase, GL_COMPILE);
|
||
|
|
||
|
//LBprintf("BEGIN DISPLAY LIST");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STATIC void EndDisplayList(SCENE *scene)
|
||
|
{
|
||
|
if (((NFFPRIV *)scene->pvData)->bInList)
|
||
|
{
|
||
|
((NFFPRIV *)scene->pvData)->bInList = FALSE;
|
||
|
|
||
|
glEndList();
|
||
|
|
||
|
//LBprintf("END DISPLAY LIST");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STATIC void parseNffViewpoint(SCENE *scene, FILE *file, char *ach, int n)
|
||
|
{
|
||
|
if (((NFFPRIV *)scene->pvData)->bInList)
|
||
|
LBprintf("NFF error: setting viewpoint too late");
|
||
|
|
||
|
fgets(ach, n, file);
|
||
|
sscanf(ach, "from %g %g %g", &scene->xyzFrom.x, &scene->xyzFrom.y, &scene->xyzFrom.z);
|
||
|
fgets(ach, n, file);
|
||
|
sscanf(ach, "at %g %g %g", &scene->xyzAt.x, &scene->xyzAt.y, &scene->xyzAt.z);
|
||
|
fgets(ach, n, file);
|
||
|
sscanf(ach, "up %g %g %g", &scene->xyzUp.x, &scene->xyzUp.y, &scene->xyzUp.z);
|
||
|
fgets(ach, n, file);
|
||
|
sscanf(ach, "angle %g", &scene->ViewAngle);
|
||
|
fgets(ach, n, file);
|
||
|
//!!!dbug -- possible front plane clipping problem; should calculate the
|
||
|
//!!! bounding sphere and use this to set near plane, but for now
|
||
|
//!!! set it to zero
|
||
|
//sscanf(ach, "hither %g", &scene->Hither);
|
||
|
scene->Hither = 0.001f;
|
||
|
fgets(ach, n, file);
|
||
|
sscanf(ach, "resolution %ld %ld", &scene->szWindow.cx, &scene->szWindow.cy);
|
||
|
|
||
|
// Estimate the yon plane as 2.5 times the distance from eye to object.
|
||
|
|
||
|
scene->Yon = ((scene->xyzAt.x - scene->xyzFrom.x) * (scene->xyzAt.x - scene->xyzFrom.x)) +
|
||
|
((scene->xyzAt.y - scene->xyzFrom.y) * (scene->xyzAt.y - scene->xyzFrom.y)) +
|
||
|
((scene->xyzAt.z - scene->xyzFrom.z) * (scene->xyzAt.z - scene->xyzFrom.z));
|
||
|
scene->Yon = sqrt(scene->Yon) * 2.5f;
|
||
|
|
||
|
#if 0
|
||
|
LBprintf("Viewpoint");
|
||
|
LBprintf("from %g %g %g", scene->xyzFrom.x, scene->xyzFrom.y, scene->xyzFrom.z);
|
||
|
LBprintf("at %g %g %g", scene->xyzAt.x, scene->xyzAt.y, scene->xyzAt.z);
|
||
|
LBprintf("up %g %g %g", scene->xyzUp.x, scene->xyzUp.y, scene->xyzUp.z);
|
||
|
LBprintf("angle %g", scene->ViewAngle);
|
||
|
LBprintf("hither %g", scene->Hither);
|
||
|
LBprintf("resolution %ld %ld", scene->szWindow.cx, scene->szWindow.cy);
|
||
|
LBprintf("yon (estimate) %g", scene->Yon);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
STATIC void parseNffBackground(SCENE *scene, FILE *file, char *ach, int n)
|
||
|
{
|
||
|
if (((NFFPRIV *)scene->pvData)->bInList)
|
||
|
LBprintf("NFF error: setting background color too late");
|
||
|
|
||
|
//LBprintf(ach);
|
||
|
|
||
|
sscanf(ach, "b %g %g %g", &scene->rgbaClear.r, &scene->rgbaClear.g, &scene->rgbaClear.b);
|
||
|
}
|
||
|
|
||
|
STATIC void parseNffLight(SCENE *scene, FILE *file, char *ach, int n)
|
||
|
{
|
||
|
GLfloat xyz[3];
|
||
|
GLfloat rgb[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||
|
//!!! specular light should be the same as diffuse
|
||
|
//static GLfloat lightSpecular[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||
|
|
||
|
if (((NFFPRIV *)scene->pvData)->bInList)
|
||
|
LBprintf("NFF error: setting lights too late");
|
||
|
|
||
|
sscanf(ach, "l %g %g %g %g %g %g", &xyz[0], &xyz[1], &xyz[2]
|
||
|
, &rgb[0], &rgb[1], &rgb[2]);
|
||
|
|
||
|
if (scene->Lights.count < (maxLights + 1))
|
||
|
{
|
||
|
glNewList(scene->Lights.listBase + scene->Lights.count, GL_COMPILE);
|
||
|
|
||
|
glLightfv(GL_LIGHT0 + scene->Lights.count, GL_POSITION, xyz);
|
||
|
glLightfv(GL_LIGHT0 + scene->Lights.count, GL_DIFFUSE, rgb);
|
||
|
glLightfv(GL_LIGHT0 + scene->Lights.count, GL_SPECULAR, rgb);
|
||
|
|
||
|
glEndList();
|
||
|
|
||
|
scene->Lights.count++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STATIC void parseNffColor(SCENE *scene, FILE *file, char *ach, int n, GLenum matSide)
|
||
|
{
|
||
|
GLfloat rgb[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||
|
GLfloat Kd, Ks, Shine, Trans, Refract;
|
||
|
GLfloat lightSpecular[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||
|
|
||
|
DoDisplayList(scene);
|
||
|
|
||
|
if (matSide == GL_BACK)
|
||
|
sscanf(ach, "k %g %g %g %g %g %g %g %g", &rgb[0], &rgb[1], &rgb[2],
|
||
|
&Kd, &Ks, &Shine,
|
||
|
&Trans, &Refract);
|
||
|
else
|
||
|
sscanf(ach, "f %g %g %g %g %g %g %g %g", &rgb[0], &rgb[1], &rgb[2],
|
||
|
&Kd, &Ks, &Shine,
|
||
|
&Trans, &Refract);
|
||
|
|
||
|
rgb[0] *= Kd; rgb[1] *= Kd; rgb[2] *= Kd;
|
||
|
lightSpecular[0] *= Ks; lightSpecular[1] *= Ks; lightSpecular[2] *= Ks;
|
||
|
|
||
|
glMaterialfv(matSide, GL_SPECULAR, lightSpecular);
|
||
|
glMaterialfv(matSide, GL_AMBIENT_AND_DIFFUSE, rgb);
|
||
|
glMaterialfv(matSide, GL_SHININESS, (GLfloat *) &Shine);
|
||
|
}
|
||
|
|
||
|
STATIC void parseNffCone(SCENE *scene, FILE *file, char *ach, int n)
|
||
|
{
|
||
|
GLfloat xBase, yBase, zBase, rBase;
|
||
|
GLfloat xApex, yApex, zApex, rApex;
|
||
|
DoDisplayList(scene);
|
||
|
|
||
|
LBprintf("*** Cylinder not implemented yet!");
|
||
|
fgets(ach, n, file);
|
||
|
sscanf(ach, "%g %g %g %g", &xBase, &yBase, &zBase, &rBase);
|
||
|
fgets(ach, n, file);
|
||
|
sscanf(ach, "%g %g %g %g", &xApex, &yApex, &zApex, &rApex);
|
||
|
|
||
|
LBprintf(" base %g %g %g %g", xBase, yBase, zBase, rBase);
|
||
|
LBprintf(" apex %g %g %g %g", xApex, yApex, zApex, rApex);
|
||
|
}
|
||
|
|
||
|
STATIC void parseNffSphere(SCENE *scene, FILE *file, char *ach, int n)
|
||
|
{
|
||
|
GLfloat x, y, z, r;
|
||
|
DoDisplayList(scene);
|
||
|
|
||
|
LBprintf("*** Sphere not implemented yet!");
|
||
|
sscanf(ach, "%g %g %g %g", &x, &y, &z, &r);
|
||
|
|
||
|
LBprintf(" %g %g %g %g", x, y, z, r);
|
||
|
}
|
||
|
|
||
|
STATIC void parseNffPolygon(SCENE *scene, FILE *file, char *ach, int n)
|
||
|
{
|
||
|
GLuint i, numVert;
|
||
|
GLfloat *aVerts, *pVert;
|
||
|
GLfloat aNorm[3];
|
||
|
|
||
|
DoDisplayList(scene);
|
||
|
|
||
|
sscanf(ach, "p %ld", &numVert);
|
||
|
|
||
|
aVerts = (GLfloat *) LocalAlloc(LMEM_FIXED, sizeof(GLfloat) * numVert * 3);
|
||
|
if (aVerts)
|
||
|
{
|
||
|
for ( i = 0, pVert = aVerts; i < numVert; i++, pVert+=3 )
|
||
|
{
|
||
|
fgets(ach, n, file);
|
||
|
sscanf(ach, "%g %g %g", &pVert[0], &pVert[1], &pVert[2]);
|
||
|
}
|
||
|
|
||
|
calcNorm(aNorm, &aVerts[0], &aVerts[3], &aVerts[6]);
|
||
|
|
||
|
glBegin(numVert == 3 ? GL_TRIANGLES :
|
||
|
numVert == 4 ? GL_QUADS :
|
||
|
GL_POLYGON);
|
||
|
{
|
||
|
glNormal3fv(aNorm);
|
||
|
for ( i = 0, pVert = aVerts; i < numVert; i++, pVert+=3 )
|
||
|
glVertex3fv(pVert);
|
||
|
}
|
||
|
glEnd();
|
||
|
|
||
|
LocalFree(pVert);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STATIC void parseNffPolygonPatch(SCENE *scene, FILE *file, char *ach, int n)
|
||
|
{
|
||
|
GLfloat x, y, z;
|
||
|
GLfloat nx, ny, nz;
|
||
|
GLuint count;
|
||
|
|
||
|
DoDisplayList(scene);
|
||
|
|
||
|
sscanf(ach, "pp %ld", &count);
|
||
|
|
||
|
glBegin(count == 3 ? GL_TRIANGLES :
|
||
|
count == 4 ? GL_QUADS :
|
||
|
GL_POLYGON);
|
||
|
for ( ; count; count--)
|
||
|
{
|
||
|
fgets(ach, n, file);
|
||
|
sscanf(ach, "%g %g %g %g %g %g", &x, &y, &z, &nx, &ny, &nz);
|
||
|
|
||
|
glNormal3f(nx, ny, nz);
|
||
|
glVertex3f(x, y, z);
|
||
|
}
|
||
|
glEnd();
|
||
|
}
|