From guest  Mon Apr  4 13:33:44 1994
Message-Id: <9404042033.AA29541@merl.com>
Organization: Mitsubishi Electric Research Laboratories, Inc.
	Cambridge, Massachusetts, USA
X-Sender: barrus@mailhost.merl.com
Mime-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Date: Mon, 4 Apr 1994 16:33:38 -0500
To: info-performer@sgi.sgi.com
From: barrus@merl.com (John W. Barrus)
Subject: DXF format specs
Status: OR

I would like to read in some DXF format files and I was wondering where to
get the specs for the format.  Any suggestions?

Of course if I was using Performer 1.2, I could use LoadDxf(), right?  Too
bad we haven't received it yet.

If anyone is willing to part with some code that already reads DXF, I would
be interested and very appreciative.

Thanks,

John B.


                    -------------------------

John Barrus                                     barrus@merl.com

Mitsubishi Electric Research Laboratories       617.621.7535 (VOICE)
201 Broadway                                    617.621.7550 (FAX)
Cambridge, MA  02139





From guest  Mon Apr  4 14:52:23 1994
From: "Michael Jones" <mtj@babar>
Message-Id: <9404041406.ZM5343@babar.asd.sgi.com>
Date: Mon, 4 Apr 1994 14:06:40 -0700
In-Reply-To: barrus@merl.com (John W. Barrus)
        "DXF format specs" (Apr  4,  4:33pm)
References: <9404042033.AA29541@merl.com>
X-Mailer: Z-Mail (3.1.0 22feb94 MediaMail)
To: barrus@merl.com (John W. Barrus), info-performer@sgi.sgi.com
Subject: Re: DXF format specs
Content-Type: text/plain; charset=us-ascii
Mime-Version: 1.0
Status: OR

The DXF format specs ship with IRIS Performer 1.2.

Here's the simple loader from 1.2 -- you'll want the new pfuBuilder()
from 1.2 to compile this.

Hint: upgrade to SC4-PERF-1.2 (the 1..2 release) right away! If you
have support, ask when you'll get your upgrade.

/*
 * Copyright (c) 1993 Silicon Graphics, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that (i) the above copyright notices and this
 * permission notice appear in all copies of the software and related
 * documentation, and (ii) the name of Silicon Graphics may not be
 * used in any advertising or publicity relating to the software
 * without the specific, prior written permission of Silicon Graphics.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
 * INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
 * THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
 * OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

/*
 * pfdxf.c: $Revision: 1.24 $ $Date: 1994/03/16 11:56:18 $
 */

#include <Performer/pf.h>
#include "pfsgi.h"
#include "pfutil.h"

/*
 * This AutoCAD reader was created almost verbatim from the
 * AutoCAD DXF file to DKB data file converter written and
 * placed in the public domain 8/13/90 by Aaron A. Collins.
 *
 * It parses a limited, but useful, subset of the AutoCAD
 * DXF file format. No effort has been made to handle the
 * complete range of possible DXF opcodes and commands.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_SIZE	2048

static int groupcode;
static char linbuf[BUFFER_SIZE];
static char curobj[80];
static int curcolor;
static float curr;
static float curg;
static float curb;
static float xcoords[BUFFER_SIZE];
static float ycoords[BUFFER_SIZE];
static float zcoords[BUFFER_SIZE];
static float floats[10];
static float angles[10];
static int ints[10];
static long numTris;
static long numVoid;

/* function type and argument declarations */
static FILE *openFile(char *fileName);
static pfGeoState* defaultGeoState(void);
static int getLine(FILE *fp);
static void addGeometry(pfuBuilder *);
static void getColor(int ndx, float *red, float *green, float *blue);
static int isDegenerate(int a, int b, int c);
static int findEntity(FILE *fp);
static int readEntity(FILE *fp, pfuBuilder *builder);

/*
 *	LoadDxf -- load DXF format ".dxf" files into IRIS Performer
 */

extern pfNode *
LoadDxf (char *fileName, pfGeoState *geostate)
{
    int		 i;

    FILE	*dxfFile;

    pfuBuilder	*builder	= NULL;
    pfList	*gsetList	= NULL;

    pfGeode	*geode		= NULL;
    pfNode	*node		= NULL;
    pfNode	*hierarchy	= NULL;

    double	 startTime	= pfGetTime();
    double	 elapsedTime	= 0.0;

    /* open DXF file file */
    if ((dxfFile = openFile(fileName)) == NULL)
	return NULL;

    /* give object a default geostate if nothing is passed in */
    if (geostate == NULL)
	geostate = defaultGeoState();

    /* initialize utility library triangle/geoset builder */
    builder = pfuNewBuilder();

    /* initialize current object */
    numTris = 0;
    numVoid = 0;
    curobj[0] = '\0';
    curcolor = 7;
    getColor(curcolor, &curr, &curg, &curb);

    /* read DXF file */
    while (findEntity(dxfFile))
	readEntity(dxfFile, builder);

    /* close DXF file */
    fclose(dxfFile);

    /* signal failure if no geometry loaded */
    if (numTris == 0)
    {
	pfuDelBuilder(builder);
	return NULL;
    }

    /* construct geode */
    geode = pfNewGeode();
    node = (pfNode *)geode;

    /* convert current face list into one or more geosets */
    gsetList = pfuMakeGSets(builder);
    for (i = 0; i < pfGetNum(gsetList); i++)
    {
        pfGeoSet *geoset = (pfGeoSet*)pfGet(gsetList, i);
        pfGSetGState(geoset, geostate);
        pfAddGSet(geode, geoset);
    }
    pfuDelBuilder(builder);

    /* print statistics */
    if(pfGetNotifyLevel() >= PFNFY_INFO)
    {
	elapsedTime = pfGetTime() - startTime;

	fprintf(stderr, "LoadDxf:\n");
	fprintf(stderr, "  file name           = %s\n",  fileName);
	fprintf(stderr, "  triangles           = %8ld\n", numTris);
	fprintf(stderr, "  numVoid             = %8ld\n", numVoid);

	if (elapsedTime > 0.0)
	{
	    fprintf(stderr, "  loading time        = %12.3f sec\n",
		elapsedTime);
	    fprintf(stderr, "  loading rate        = %12.3f tri/sec\n",
		numTris/elapsedTime);
	}
    }

/* #define	BREAKUP_GEODE */
#ifdef	BREAKUP_GEODE
    /* convert geode to recursive spatial hierarchy */
    startTime = pfGetTime();
    hierarchy = pfuBreakup(geode, 10.0f, 24, 8);
    elapsedTime = pfGetTime() - startTime;

    /* replace monolithic geode with recursive spatial hierarchy */
    if (hierarchy != NULL)
    {
	node = hierarchy;
	pfDelete(geode);
    }

    /* print statistics */
    if (pfGetNotifyLevel() >= PFNFY_INFO && elapsedTime > 0.0)
    {
	fprintf(stderr, "  breakup time        = %12.3f sec\n",
	    elapsedTime);
	fprintf(stderr, "  breakup rate        = %12.3f tri/sec\n",
	    numTris/elapsedTime);
    }
#endif

    /* print statistics */
    if (pfGetNotifyLevel() >= PFNFY_INFO)
	fprintf(stderr, "\n");

    return node;
}

static FILE *
openFile (char *fileName)
{
    FILE	*file = NULL;
    char	 filePath[BUFFER_SIZE];

    /* check argument */
    if (fileName == NULL || *fileName == '\0')
	return NULL;

    /* find file in IRIS Performer directory-search path */
    if (!pfFindFile(fileName, filePath, R_OK))
    {
	pfNotify(PFNFY_WARN, PFNFY_RESOURCE,
	    "openFile: Could not find file \"%s\"", fileName);
	return NULL;
    }

    /* open  file */
    if ((file = fopen(filePath, "r")) == NULL)
    {
	pfNotify(PFNFY_WARN, PFNFY_RESOURCE,
	    "openFile: Could not open file \"%s\"", filePath);
	return NULL;
    }

    return file;
}

/*
 * read a group code and the next line from dxfFile
 */
static int
getLine(FILE *fp)
{
    /* get a line from DXF file */
    fgets(linbuf, BUFFER_SIZE, fp);
    if (feof(fp))
	return 1;

    /* scan out group code */
    sscanf(linbuf, "%3d", &groupcode);

    /* get a line from DXF file */
    fgets(linbuf, BUFFER_SIZE, fp);
    if (feof(fp))
	return 1;

    return 0;
}

/*
 * dump out current object we should have all info on
 */
static void
addGeometry(pfuBuilder *builder)
{
    static pfuPoly	 polygon;
    static int state=0;
    static int nb_points;
    static int nb_cotes;
    static int indice_point;

    /* 2 back-to-back triangles */
    if (strstr(curobj, "TRACE"))
    {
	if (isDegenerate(0, 1, 2))
	{
	    numVoid++;
	    return;
	}

	polygon.numVerts = 3;
	polygon.tbind = PFGS_OFF;
	polygon.nbind = PFGS_OFF;
	polygon.cbind = PFGS_OVERALL;
	pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
	pfSetVec3(polygon.coords[1], xcoords[1], ycoords[1], zcoords[1]);
	pfSetVec3(polygon.coords[2], xcoords[2], ycoords[2], zcoords[2]);
	pfSetVec3(polygon.colors[0], curr, curg, curb);
	pfuAddPoly(builder, &polygon);
	numTris += polygon.numVerts - 2;

	if (isDegenerate(0, 3, 2))
	{
	    numVoid++;
	    return;
	}

	polygon.numVerts = 3;
	polygon.tbind = PFGS_OFF;
	polygon.nbind = PFGS_OFF;
	polygon.cbind = PFGS_OVERALL;
	pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
	pfSetVec3(polygon.coords[1], xcoords[2], ycoords[2], zcoords[2]);
	pfSetVec3(polygon.coords[2], xcoords[3], ycoords[3], zcoords[3]);
	pfSetVec3(polygon.colors[0], curr, curg, curb);
	pfuAddPoly(builder, &polygon);
	numTris += polygon.numVerts - 2;

	return;
    }
    /* 1 or 2 triangles */
    else if (strstr(curobj, "SOLID"))
    {
	if (isDegenerate(0, 1, 2))
	{
	    numVoid++;
	    return;
	}

	polygon.numVerts = 3;
	polygon.tbind = PFGS_OFF;
	polygon.nbind = PFGS_OFF;
	polygon.cbind = PFGS_OVERALL;
	pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
	pfSetVec3(polygon.coords[1], xcoords[1], ycoords[1], zcoords[1]);
	pfSetVec3(polygon.coords[2], xcoords[2], ycoords[2], zcoords[2]);
	pfSetVec3(polygon.colors[0], curr, curg, curb);
	pfuAddPoly(builder, &polygon);
	numTris += polygon.numVerts - 2;

	/* is one triangle enough... */
	if (xcoords[2] == xcoords[3] &&
	    ycoords[2] == ycoords[3] &&
	    zcoords[2] == zcoords[3])
	    return;

	if (isDegenerate(0, 3, 2))
	{
	    numVoid++;
	    return;
	}

	polygon.numVerts = 3;
	polygon.tbind = PFGS_OFF;
	polygon.nbind = PFGS_OFF;
	polygon.cbind = PFGS_OVERALL;
	pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
	pfSetVec3(polygon.coords[1], xcoords[2], ycoords[2], zcoords[2]);
	pfSetVec3(polygon.coords[2], xcoords[3], ycoords[3], zcoords[3]);
	pfSetVec3(polygon.colors[0], curr, curg, curb);
	pfuAddPoly(builder, &polygon);
	numTris += polygon.numVerts - 2;

	return;
    }
    /* 1 or 2 triangles */
    else if (strstr(curobj, "3DFACE"))
    {
	if (isDegenerate(0, 1, 2))
	{
	    numVoid++;
	    return;
	}

	polygon.numVerts = 3;
	polygon.tbind = PFGS_OFF;
	polygon.nbind = PFGS_OFF;
	polygon.cbind = PFGS_OVERALL;
	pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
	pfSetVec3(polygon.coords[1], xcoords[1], ycoords[1], zcoords[1]);
	pfSetVec3(polygon.coords[2], xcoords[2], ycoords[2], zcoords[2]);
	pfSetVec3(polygon.colors[0], curr, curg, curb);
	pfuAddPoly(builder, &polygon);
	numTris += polygon.numVerts - 2;

	/* is one triangle enough... */
	if (xcoords[2] == xcoords[3] &&
	    ycoords[2] == ycoords[3] &&
	    zcoords[2] == zcoords[3])
	    return;

	if (isDegenerate(0, 3, 2))
	{
	    numVoid++;
	    return;
	}

	polygon.numVerts = 3;
	polygon.tbind = PFGS_OFF;
	polygon.nbind = PFGS_OFF;
	polygon.cbind = PFGS_OVERALL;
	pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
	pfSetVec3(polygon.coords[1], xcoords[2], ycoords[2], zcoords[2]);
	pfSetVec3(polygon.coords[2], xcoords[3], ycoords[3], zcoords[3]);
	pfSetVec3(polygon.colors[0], curr, curg, curb);
	pfuAddPoly(builder, &polygon);
	numTris += polygon.numVerts - 2;

	return;
    }
    else if (strstr(curobj, "SEQEND"))
    {
	if (state == 1 && polygon.numVerts > 2)
	{
	    pfSetVec3(polygon.colors[0], curr, curg, curb);
	    pfuAddPoly(builder, &polygon);
	    numTris += polygon.numVerts - 2;
	}
	state = 0;	/* end of something */
    }
    else if (strstr(curobj, "POLYLINE"))
    {
	state = 1;	/* begin of a polyline */
	indice_point = 1;
	nb_points = ints[1];
	nb_cotes = ints[2];

	if (nb_points >= (BUFFER_SIZE-1))
	{
	    state = 0;
	    return;
	}

	polygon.numVerts = 0;
	polygon.tbind = PFGS_OFF;
	polygon.nbind = PFGS_OFF;
	polygon.cbind = PFGS_OVERALL;
    }
    /* a new vertex in a polyline */
    else if (strstr(curobj, "VERTEX") && state == 1)
    {
	/* is it a new vertex ? */
	if (indice_point <= nb_points)
	{
	    /* copying point */
	    xcoords[indice_point] = xcoords[0];
	    ycoords[indice_point] = ycoords[0];
	    zcoords[indice_point] = zcoords[0];
	    indice_point++;
	}
	else
	/* creating edges */
	if (nb_cotes > 0)
	{
	    /* closing an older polygon */
	    if ((ints[1] > 0) && (polygon.numVerts > 2))
	    {
		 pfSetVec3(polygon.colors[0], curr, curg, curb);
		 pfuAddPoly(builder, &polygon);
		 numTris += polygon.numVerts - 2;
	    }

	    /* creating a new polygon */
	    if (ints[1] > 0)
	    {
		polygon.numVerts = 0;
		pfSetVec3(polygon.coords[polygon.numVerts++],
		    xcoords[ints[1]], ycoords[ints[1]], zcoords[ints[1]]);
	    }
	    if (ints[2] > 0)
	    {
		pfSetVec3(polygon.coords[polygon.numVerts++],
		    xcoords[ints[2]], ycoords[ints[2]], zcoords[ints[2]]);
	    }
	    if (ints[3] > 0)
	    {
		pfSetVec3(polygon.coords[polygon.numVerts++],
		    xcoords[ints[3]], ycoords[ints[3]], zcoords[ints[3]]);
	    }
	}
    }
    /* not implemented */
    else if (
	strstr(curobj, "LINE")    || strstr(curobj, "POINT")    ||
	strstr(curobj, "CIRCLE")  || strstr(curobj, "ARC")      ||
	strstr(curobj, "TEXT")    || strstr(curobj, "SHAPE")    ||
        strstr(curobj, "BLOCK")   || strstr(curobj, "ENDBLK")   ||
        strstr(curobj, "INSERT")  || strstr(curobj, "ATTDEF")   ||
        strstr(curobj, "ATTRIB")  || strstr(curobj, "3DLINE")   ||
	strstr(curobj, "DIMENSION"))
    {
	return;
    }
    /* no current object defined */
    else
	return;
}

/*
 * colors defined by basic AutoCAD color table
 */
static void
getColor (int ndx, float *red, float *green, float *blue)
{
    /* AutoCAD color table */
    static float colors[][3] =
    {
       {0.0f,  0.0f,  0.0f},	/* 0 == black   */
       {1.0f,  0.0f,  0.0f},	/* 1 == red     */
       {1.0f,  1.0f,  0.0f},	/* 2 == yellow  */
       {0.0f,  1.0f,  0.0f},	/* 3 == green   */
       {0.0f,  1.0f,  1.0f},	/* 4 == cyan    */
       {0.0f,  0.0f,  1.0f},	/* 5 == blue    */
       {1.0f,  0.0f,  1.0f},	/* 6 == magenta */
       {1.0f,  1.0f,  1.0f},	/* 7 == white   */
       {0.5f,  0.5f,  0.5f},	/* 8 == dk grey */
       {0.75f, 0.75f, 0.75f} 	/* 9 == lt grey */
    };

    /* use white (color 7) as default color */
    if (ndx < 0 || ndx > 9)
	ndx = 7;

    /* set colors in reference arguments */
    *red   = colors[ndx][0];
    *green = colors[ndx][1];
    *blue  = colors[ndx][2];

    return;
}

/*
 * check for degenerate triangle structure
 */
static int
isDegenerate(int a, int b, int c)
{
    if ((xcoords[a] == xcoords[b] &&
         ycoords[a] == ycoords[b] &&
	 zcoords[a] == zcoords[b]) ||
	(xcoords[b] == xcoords[c] &&
	 ycoords[b] == ycoords[c] &&
	 zcoords[b] == zcoords[c]) ||
	(xcoords[a] == xcoords[c] &&
	 ycoords[a] == ycoords[c] &&
	 zcoords[a] == zcoords[c]))
	return 1;
    else
	return 0;
}

/*
 * move forward to ENTITIES section
 */
static int
findEntity(FILE *fp)
{
    while (1)
    {
	/* is there more to read */
	if (feof(fp))
	    return 0;

	/* get a group code and a line */
	if (getLine(fp))
	    return 0;

	/* file section mark */
	if (groupcode == 0)
	{
	    if (strstr(linbuf, "EOF"))
		return 0;

	    if (strstr(linbuf, "SECTION"))
	    {
		if (getLine(fp))
		    return 0;
		if (groupcode != 2)
		    continue;
		if (strstr(linbuf, "ENTITIES"))
		    break;
	    }
	}
    }

    return 1;
}

/*
 * read objects from ENTITIES section
 */
static int
readEntity(FILE *fp, pfuBuilder *builder)
{
    while (1)
    {
	/* is there more to read */
	if (feof(fp))
	    break;

	/* get a group code and a line */
	if (getLine(fp))
	    break;

	/* cardinal group codes */
	if (groupcode < 10)
	{
	    switch(groupcode)
	    {
	    /* start of entity, table, file sep */
	    case 0:
		/* add object's polygons to builder */
		addGeometry(builder);

		if (strstr(linbuf, "EOF"))
		    return 0;
		if (strstr(linbuf, "ENDSEC"))
		    continue;

		/* reset object */
		curobj[0] = '\0';
		curcolor = 7;
		getColor(curcolor, &curr, &curg, &curb);

		/* get new */
		strcpy(curobj, linbuf);
		break;

	    /* primary text value for entity (?) */
	    case 1:
		break;

	    /* block name, attribute tag, etc */
	    case 2:
	    case 3:
	    case 4:
		break;

	    /* entity handle (hex string) */
	    case 5:
		break;

	    /* line type name */
	    case 6:
		break;

	    /* text style name */
	    case 7:
		break;

	    /* layer name */
	    case 8:
		break;

	    /* variable name ID (only in header) */
	    case 9:
		break;
	    }
	}
	/* some X coord */
	else if (groupcode >= 10 && groupcode < 19)
	    sscanf(linbuf, "%f", &(xcoords[groupcode-10]));
	/* some Y coord */
	else if (groupcode >= 20 && groupcode < 29)
	    sscanf(linbuf, "%f", &(ycoords[groupcode-20]));
	/* some Z coord */
	else if (groupcode >= 30 && groupcode < 38)
	    sscanf(linbuf, "%f", &(zcoords[groupcode-30]));
	/* entity elevation if nonzero */
	else if (groupcode == 38)
	{
	}
	/* entity thickness if nonzero */
	else if (groupcode == 39)
	{
	}
	/* misc floats */
	else if (groupcode >= 40 && groupcode < 49)
	    sscanf(linbuf, "%f", &(floats[groupcode-40]));
	/* repeated value groups */
	else if (groupcode == 49)
	{
	}
	/* misc angles */
	else if (groupcode >= 50 && groupcode < 59)
	    sscanf(linbuf, "%f", &(angles[groupcode-50]));
	/* color number */
	else if (groupcode == 62)
	{
	    sscanf(linbuf, "%6d", &curcolor);
	    getColor(curcolor, &curr, &curg, &curb);
	}
	/* "entities follow" flag */
	else if (groupcode == 66)
	{
	}
	/* misc ints */
	else if (groupcode >= 70 && groupcode < 79)
	    sscanf(linbuf, "%d", &(ints[groupcode-70]));
	/* X, Y, Z components of extrusion direction */
	else if (groupcode == 210 || groupcode == 220 || groupcode == 230)
	{
	}
    }
    return 0;
}

/*
 * make a reasonable default geostate
 */
static pfGeoState*
defaultGeoState (void)
{
    static void		*arena		= NULL;
    static pfMaterial	*material	= NULL;
    static pfGeoState	*geostate	= NULL;

    if (geostate == NULL)
    {
        arena = pfGetSharedArena();

	material = pfNewMtl(arena);
	pfMtlColor(material, PFMTL_AMBIENT,  0.1, 0.1, 0.1);
	pfMtlColor(material, PFMTL_SPECULAR, 0.8, 0.8, 0.8);
	pfMtlShininess(material, 10.0);
	pfMtlColorMode(material, PFMTL_FRONT, LMC_AD);

	geostate = pfNewGState(arena);
	pfGStateAttr(geostate, PFSTATE_FRONTMTL, material);
    }

    return geostate;
}


-- 

Be seeing you,      mtj@sgi.com  415.390.1455  M/S 7L-590
Michael Jones       Silicon Graphics, Advanced Graphics Division
                    2011 N. Shoreline Blvd., Mtn. View, CA 94039-7311







