#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 07/31/1992 19:19 UTC by glewis@fws204
# Source directory /nfs/mcfgpe/mcfg/src/.urt/ttdddlib
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#  11690 -rw-r--r-- README.R36
#   4763 -rw-r--r-- CHANGES
#   1781 -rw-r--r-- Makefile
#   3190 -rw-r--r-- Makefile.Amiga
#   3322 -rw-r--r-- freeworld.c
#   4749 -rw-r--r-- merge.c
#  37860 -rw-r--r-- read.c
#  20014 -rw-r--r-- readtddd.c
#   1543 -rw-r--r-- readwrite.c
#   1101 -rw-r--r-- sort.c
#   1174 -rw-r--r-- tddd2dxf.c
#    362 -rw-r--r-- tddd2mif.c
#   1174 -rw-r--r-- tddd2nff.c
#   1246 -rw-r--r-- tddd2off.c
#    356 -rw-r--r-- tddd2pov.c
#    376 -rw-r--r-- tddd2ps.c
#    360 -rw-r--r-- tddd2ray.c
#    352 -rw-r--r-- tddd2vort.c
#   4938 -rw-r--r-- ttdddlib.h
#  12386 -rw-r--r-- write.c
#   2720 -rw-r--r-- writedxf.c
#   6829 -rw-r--r-- writemif.c
#   2395 -rw-r--r-- writenff.c
#   5366 -rw-r--r-- writeoff.c
#  15760 -rw-r--r-- writepov.c
#   8813 -rw-r--r-- writeps.c
#  13541 -rw-r--r-- writeray.c
#  14117 -rw-r--r-- writevort.c
#  10283 -rw-r--r-- writeim.c
#
# ============= README.R36 ==============
if test -f 'README.R36' -a X"$1" != X"-c"; then
	echo 'x - skipping README.R36 (File already exists)'
else
echo 'x - extracting README.R36 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README.R36' &&
X
This is an lzh file containing a set of programs called T3DLIB (previously
known as TTDDDLIB).  These programs convert 3D objects in the binary TDDD
format into the Textual TDDD (TTDDD) format and back again, and also
provide a number of other conversion filters.
X
-----------------------------------
X
These programs are provided as SHAREWARE. If you choose to use these programs,
you are obligated to send in a $25 (US) to the author, Glenn Lewis.
His address:
X
X   Glenn M. Lewis
X   8341 Olive Hill Court
X   Fair Oaks, CA  95628
X   (USA)
X
Glenn is also reachable via email at glewis@pcocd2.intel.com.
X
----------------
X
Enjoy these programs and the objects, and send in your Shareware fee to Glenn!
X
[condensed message from...]
-Steve
X
--------------------------------------------------------------------------
Steve Worley                                         Worley@cup.portal.com
--------------------------------------------------------------------------
X
X
X    As of March 31, 1992, I have included the Amiga executables of the latest
revision of T3DLIB in the files:
X
X  T3DLIB*_68000exe.lha  (68000, non-FPU version)
X  T3DLIB*_68030exe.lha  (68030, FPU version)
X
X    Note that these were compiled with SAS/C, and so they do not have that bogus
restriction of running only under version 2.04 of the operating system like the
R33 version of the executables had!
Yahoo!  Thanks, Scott!
X
X    You will find several filters in there, all of which support Imagine
objects (and, of course, Turbo Silver objects).  The most important filter you
will use is called "readwrite", which basically replaces the old ReadTDDD and
WriteTDDD programs.
X
X    "ReadWrite" will read from its standard input, *EITHER* an Imagine object
file *OR* a TTDDD file, and it is smart enough to know which is which without
you telling it.  (In fact, all of the executables from T3DLIB now read
either type of file!)  It will also read old Turbo Silver files, and make all
external objects internal.
X
X    "readwrite" will, by default, output TTDDD files to its standard output.
But if you give it the "-tddd" flag (or "-t" for short), it will output
Imagine object files directly!
X
X    Remember that all of these programs are filters, so you must redirect
their input and output from/to files.
X
X    readwrite   - reads and writes both TDDD and TTDDD files
X    tddd2mif    - reads TDDD or TTDDD files and outputs FrameMaker MIF files
X    tddd2ps     - reads TDDD or TTDDD files and outputs isometric wireframes
X                  with Top, Front, Right, and Isometric views in PostScript
X    tddd2nff    - reads TDDD or TTDDD files and outputs NFF files
X    tddd2off    - reads TDDD or TTDDD files and outputs OFF files
X    tddd2ray    - reads TDDD or TTDDD files and outputs Rayshade 4.0 files
X    tddd2vort   - reads TDDD or TTDDD files and outputs VORT files
X
Two new filters as of release 34 are:
X    tddd2dxf    - reads TDDD or TTDDD files and outputs DXF (AutoCAD) files
X    tddd2pov    - reads TDDD or TTDDD files and outputs POV-Ray 1.0 files
X
Here is some documentation on the OFF and NFF versions:
X
TDDD is a complex format that allows heirarchical structure to be
defined. Thus, a car might be defined as different parts, such as the
frame, the doors, the tires, and the windows. When you are converting
from TDDD, sometimes you will want to merge all of the sub-parts together
to form one single object, but other times it is convienient to have the
different parts saved as seperate objects so you can manipulate them 
easier. T3DLIB supports both conversion methods by a flag, -split. 
X
The programs included:
X
1) tddd2off
X
Usage: tddd2off [-geom_only] [-split] [infile] [outfile]
X
X   Converts an input TDDD or TTDDD file to an OFF format file. It defaults
X   to outputting both a .geom and a .ipcol file, but if you are only
X   interested in the structure of the object, the flag -geom_only
X   (or -g) will ouput only the point, edge, and face information.
X   -split will split heirarchical objects into individual objects.
X   In this case, if the outfile name is "model", the output names
X   would be "model001.geom", "model002,geom", etc. 
X
2) tddd2nff
X
Usage: tddd2nff [infile] [outfile]
X
X   Converts an input TDDD or TTDDD file and saves an NFF format file.
X
-------------------------------------------------------------------------
X
X    Althought the following does not cut it for documentation (hopefully
I will have some real docs by the next release...), I thought this might
be helpful to some people:
X
>>>>> On Wed, 24 Jun 92 13:23:29 -0400, kelly@ll.mit.edu said:
X
Dave> Greetings;
X
Dave>         Can anyone out there tell me a little about the program
Dave> TTDDD?  Specifically what kinds of things can be done with it
Dave> (especially by none programmers such as myself). I downloaded some
Dave> nice 3D fonts from hubcap that were converted from TeX with TTDDD.
Dave> Is this the kind of thing that I could do with little or no
Dave> programming? Also what other programs/excessories would be useful
Dave> with TTDDD? Thanks for the help!
X
X        Hi!  I am Glenn Lewis, the author of TTDDD and T3DLIB (previously
known as "TTDDDLIB").  I thought I would post to the list so that
everybody would be up-to-date.
X
X        Basically, the old TTDDD programs, called "ReadTDDD" and
"WriteTDDD" are obsolete, and do not support any of the new Imagine
sub-chunks.  Let me give you a summary of what T3DLIB can do for you
from my point of view, which is obviously quite biased.
X
X        First, T3DLIB consists of two things: a linkable library of
routines that allow programmers to manipulate 3D objects and scenes
easily from within their own applications.  (Of course if you wish to
use my code in a commercial product, you must check with me first, as
one author failed to do.)  The second part of T3DLIB is a collection of
filters that are built using the linkable library.  T3DLIB supports
(reads/writes) most all "chunks" in the Imagine TDDD file format.
X
X        The source code (and executables that run under *BOTH* 2.04 and 1.3
of the Amiga operating system without any special libraries) are available on
hubcap.clemson.edu [130.127.8.1] in the directory:
pub/amiga/incoming/imagine/TTDDDLIB.
X
X        The main program included in T3DLIB is called "ReadWrite".  This
is the one that makes the previous two programs obsolete, as mentioned
above.  "ReadWrite" is simply a filter, but a powerful one.  First off,
I better describe what the TTDDD format is: TTDDD is "Textual TDDD", and
"TDDD" is an IFF (Interchange File Format [?]) that has many "chunks"
and "sub-chunks" that describe objects and scene for Imagine (and
previously Turbo Silver).  "TDDD" was created by Impulse, Inc.  TTDDD
was created by me, and allows any text file to describe in full detail,
all that a TDDD file can describe, but is editable and can be
algorithmically generated.
X
X        Back to "ReadWrite"...  ReadWrite reads a file from its standard
input, and writes a file to its standard output.  The input file can be
*either* a TTDDD *or* a TDDD file, and the output, by default, is a
TTDDD file.  If "ReadWrite" is given the "-tddd" (or "-t" for short)
flag on its command line, it will write a TDDD file that is directly
loadable by Imagine.  Since Imagine does not support "external" objects
like Turbo Silver did, "ReadWrite" will load any "external" objects at
that time and make them internal to make Imagine happy.  Also, if one
wishes to "optimize" points and edges (by simply removing redundancies),
the "-m" (for "merge") flag will accomplish this.  This does, however,
take much longer processing time, so sit back and let it crunch on the
object(s).
X
X        This, obviously, is the most useful (and necessary) program for
dealing with TTDDD and TDDD files.  Here is a list of other utilities
that are included:
X
tddd2off tddd2nff tddd2vort tddd2ray tddd2ps tddd2mif tddd2dxf tddd2pov
X
X        All of the above are also filters, and perform the following
conversions:
X
tddd2off  - converts TDDD (or TTDDD automatically) to OFF format
tddd2nff  - converts TDDD (or TTDDD automatically) to NFF format
tddd2vort - converts TDDD (or TTDDD automatically) to VORT format
tddd2ray  - converts TDDD (or TTDDD automatically) to Rayshade 4.0 format
tddd2ps   - converts TDDD (or TTDDD automatically) to PostScript format
tddd2mif  - converts TDDD (or TTDDD automatically) to MIF format
tddd2dxf  - converts TDDD (or TTDDD automatically) to DXF (AutoCAD) format
tddd2pov  - converts TDDD (or TTDDD automatically) to POV-Ray format
X
OFF is DEC's Object File Format.
NFF is Eric Haines' (SP?) Neutral File Format.
VORT is the "Very Ordinary Ray Tracer", I believe.
Rayshade is that awesome program by Craig Kolb.
PostScript output has 4 views: Top, front, right, and isometric.
MIF is "Maker Interchange Format" for FrameMaker, and looks like the
X    PostScript output, but is editable from within FrameMaker.
DXF is AutoCAD's interchange file format.
POV is POV-Ray's file format.
X
X        The entire T3DLIB package is shareware, and costs $25 to
register.  Details are in the sources archive on hubcap.  As a "Thank You" 
for registering, I will send you a disk with the two utilities: TSTeX
(which created the font you viewed on hubcap from public domain TeX
fonts [in PK format]) and SQuad, which generates superquadric surfaces
based upon parameters that you supply it.  Examples of superquadrics are
torii, cubes (with rounded edges), diamonds, and a sphere is a
degenerate superquadric.  I will also send you a copy of the TDDD file
format, which is basically the documentation for the TTDDD file format,
as it uses the same names, but is editable.  I also provide some
examples on the diskette.
X
X        But back to your original question: What can this do for
non-programmers?  Well, you will probably find the utilities useful, and
you may be interested in looking at the geometric details of an object
(OK, maybe not :-).
X
X        Most definitely, though, the power of the package comes from
being able to algorithmically generate or modify objects and scenes for
animating or for simply creating/modifying complex objects.
X
X        Helge Rasmussen, for example, created a program called
"igensurf" that uses the TTDDD format and filters to generate basically
any surface that you can describe mathematically in closed form.
X
X        Steve Worley, for another example, created an animation of a
waterfall by algorithmically controlling the positions of thousands of
little spheres.
X
X        I, for a third example, created the steam locomotive object on
hubcap with the help of TTDDD, and animated the pistons and wheels.
X
X        One of my registered shareware users has a cabinetry business
and models all cabinets and drawers using TTDDD first, and presents a
video of his plans to the customer before he ever starts, making each
presentation expressly unique for that person's kitchen or room.
X
X        Feel free, if you have any questions, to send me e-mail.  I hope
I have answered any questions you have, without attempting to make this
a commercial.
X
X        Future work includes general object morphing for Imagine such
that *any* two objects can be morphed from one to the other, with T3DLIB
creating all the in-betweens, since Imagine currently can only morph two
objects with the same topology (points/edges/faces).
X
X        Of course, work on this will not continue until Steve Worley and
I finish up Essence and ship it.  :-)  [Hmmm... as of release 34, that is
not longer an excuse, so I will have to think of another good one.  :-) ]
X
X                                                        -- Glenn
X
Glenn Lewis | glewis@pcocd2.intel.com | These are my opinions...not Intel's
SHAR_EOF
chmod 0644 README.R36 ||
echo 'restore of README.R36 failed'
Wc_c="`wc -c < 'README.R36'`"
test 11690 -eq "$Wc_c" ||
	echo 'README.R36: original size 11690, current size' "$Wc_c"
fi
# ============= CHANGES ==============
if test -f 'CHANGES' -a X"$1" != X"-c"; then
	echo 'x - skipping CHANGES (File already exists)'
else
echo 'x - extracting CHANGES (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'CHANGES' &&
X
X        The purpose of this file is to attempt to describe the changes
made since the last release.  I should have started this from the beginning,
and I am sorry that I didn't.  I also apologize for the lack of documentation.
Make sure to look at the README file, though, for information.
X
X        With that, here is the list of changes:
X
Changes from T3DLIB35 to T3DLIB36
---------------------------------
o Minor update that fixes a T3DLIB bug that was tickled by "igensurf"...
X  If the first line had a valid TTDDD command on it, readwrite croaked.
X  Two lines fixed it.  Sorry about that.
X
Changes from T3DLIB34 to T3DLIB35
---------------------------------
o Thanks to Scott Ellis, Amiga executables are provided in the files:
X  T3DLIB35_68000exe.lha  (68000, non-FPU version)
X  T3DLIB35_68030exe.lha  (68030, FPU version)
X  Note that these were compiled with SAS/C, and so they do not have that bogus
X  restriction of running only under version 2.04 of the operating system like
X  the R33 version of the executables had!
X  Yahoo!  Thanks, Scott!
o So as to reduce the amount of confusion, I went ahead and bumped the revision
X  number, because the README file changed, as did the Makefile.Amiga.
X
Changes from TTDDDLIB33 to T3DLIB34
-------------------------------------
o Added support for AutoCAD's DXF files (without having AutoCAD).  If someone
X  wishes to send me DXF examples that include "Layers" for use in assigning
X  different levels in an object's hierarchy, I will attempt to implement that
X  too.
o Added support for POV-Ray 1.0.  The input file format is rather restrictive,
X  in my humble opinion (specifically regarding describing complex object
X  hierarchies and applying textures to unions of shapes), which forced me to
X  color ("texture") each triangle individually instead of applying a texture
X  to a child object and overriding it on a triangle-basis if need be.
X  Drew Wells, leader of the POV-Ray project, says that a future version will
X  address my concerns.  Anyway, all this means that the POV files will be
X  quite large for a medium- to high-complexity object.
o I added more documentation to the README.R34 file, describing uses of this
X  package.  Yes, better and more complete documentation must still be written.
o Essence 1.0 has already shipped.  :-)  (Just thought I would throw this in
X  here even though it has nothing to do with T3DLIB.  :-)
o I changed the names of the archives to T3DLIB, which is much easier to say. :-)
o I removed the "ext2int" program, which was simply a link to "readwrite" anyway.
X
Changes from TTDDDLIB31 to TTDDDLIB33 (ooops, forgot to update this at 32)
-------------------------------------
o First, the "readwrite" filter (aka ext2int) can now output Imagine object
X  files directly (in the TDDD format) when given the "-tddd" option (or "-t" for
X  short).  Also, for some time now it has already had the ability to read either
X  TDDD *or* TTDDD files without you having to specify which is which.
X
o This release supports a number of new Imagine 2.0 TDDD "chunks", including
X  the following:
X
X        SPC1 - Specular default
X        PRP1 - Object properties
X        EFLG - Edge flag
X        FGRP - Face subgrouping
X
Changes from TTDDDLIB29 to TTDDDLIB31 (yep, no release 30)
-------------------------------------
o Fixed a bug in writetddd that caused incorrect reading of real numbers
X  such as "-.5" with no digits before the decimal point.  Thanks, Paul,
X  for pointing this out!  Also added exponential notation support in case
X  some program decided to generate them.
X
Changes from TTDDDLIB28 to TTDDDLIB29
-------------------------------------
o I have decided to include "writetddd" with the distribution so that it
X  will be much more useful to even those people who do not register for
X  this shareware (the majority, I'm afraid).  Now you can pipe the output
X  of any of the programs that create TTDDD file through "writetddd" and
X  get Imagine-compatible objects.
X
Changes from TTDDDLIB27 to TTDDDLIB28
-------------------------------------
o Ooops.  I forgot to include "merge.c" in the archive.
X
Changes from TTDDDLIB26 to TTDDDLIB27
-------------------------------------
o Speed-up and bug fix (which caused it to hang) in "merge.c"
X
Changes from TTDDDLIB25 to TTDDDLIB26
-------------------------------------
o Added "merge_World()" function in "merge.c"
X  This routine optimizes points and edges in an object hierarchy
X  by removing duplicates.
o Added the "-m" flag to "ext2int" to optionally "merge" the object
X  before outputing.
X
Changes from TTDDDLIB24 to TTDDDLIB25
-------------------------------------
o Bug fix in read.c and readtddd.c
X  read.c was calling an external "malloc_arrays()" such that its static
X  variables "defclst", etc. were not being used.
X
SHAR_EOF
chmod 0644 CHANGES ||
echo 'restore of CHANGES failed'
Wc_c="`wc -c < 'CHANGES'`"
test 4763 -eq "$Wc_c" ||
	echo 'CHANGES: original size 4763, current size' "$Wc_c"
fi
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping Makefile (File already exists)'
else
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
# Makefile for TTDDDLIB
# $Id: Makefile,v 1.20 1992/07/29 20:46:07 glewis Exp $
X
C_SRCS=read.c write.c readtddd.c writeray.c writeps.c writemif.c writevort.c \
X	   writenff.c writeoff.c writedxf.c sort.c freeworld.c merge.c writeim.c \
X	   writepov.c
OBJS=${C_SRCS:.c=.o}
CFLAGS=-g
RANLIB=ranlib
X
.c.o:
X	$(CC) $(CFLAGS) -c $*.c
X
all: libttddd.a tddd2off tddd2nff tddd2vort tddd2ray tddd2ps tddd2mif tddd2dxf \
X	writetddd readwrite tddd2pov
X	@echo " "
X	@echo 'Thank you for supporting this Shareware by sending your 25 (US) dollars to:'
X	@echo " "
X	@echo "Glenn M. Lewis"
X	@echo "8341 Olive Hill Court"
X	@echo "Fair Oaks, CA  95628"
X	@echo "(USA)"
X	@echo " "
X
$(OBJS): ttdddlib.h
X
libttddd.a: $(OBJS)
X	$(AR) rcu libttddd.a $(OBJS)
X	$(RANLIB) libttddd.a
X
# morph: libttddd.a morph.o morphlib.o
# 	$(CC) $(CFLAGS) -o morph morph.o morphlib.o libttddd.a -lm
X
tddd2pov: libttddd.a tddd2pov.o
X	$(CC) $(CFLAGS) -o tddd2pov tddd2pov.o libttddd.a -lm
X
tddd2dxf: libttddd.a tddd2dxf.o
X	$(CC) $(CFLAGS) -o tddd2dxf tddd2dxf.o libttddd.a
X
tddd2nff: libttddd.a tddd2nff.o
X	$(CC) $(CFLAGS) -o tddd2nff tddd2nff.o libttddd.a
X
tddd2off: libttddd.a tddd2off.o
X	$(CC) $(CFLAGS) -o tddd2off tddd2off.o libttddd.a
X
tddd2vort: libttddd.a tddd2vort.o
X	$(CC) $(CFLAGS) -o tddd2vort tddd2vort.o libttddd.a
X
tddd2ray: libttddd.a tddd2ray.o
X	$(CC) $(CFLAGS) -o tddd2ray tddd2ray.o libttddd.a
X
tddd2ps: libttddd.a tddd2ps.o
X	$(CC) $(CFLAGS) -o tddd2ps tddd2ps.o libttddd.a
X
tddd2mif: libttddd.a tddd2mif.o
X	$(CC) $(CFLAGS) -o tddd2mif tddd2mif.o libttddd.a
X
readwrite: libttddd.a readwrite.o
X	$(CC) $(CFLAGS) -o readwrite readwrite.o libttddd.a
X
writetddd: writetddd.o
X	$(CC) $(CFLAGS) -o writetddd writetddd.o
X
clean:
X	rm -f *.o libttddd.a tddd2off tddd2nff tddd2vort tddd2ray tddd2ps tddd2mif \
X	tddd2dxf
X
SHAR_EOF
chmod 0644 Makefile ||
echo 'restore of Makefile failed'
Wc_c="`wc -c < 'Makefile'`"
test 1781 -eq "$Wc_c" ||
	echo 'Makefile: original size 1781, current size' "$Wc_c"
fi
# ============= Makefile.Amiga ==============
if test -f 'Makefile.Amiga' -a X"$1" != X"-c"; then
	echo 'x - skipping Makefile.Amiga (File already exists)'
else
echo 'x - extracting Makefile.Amiga (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile.Amiga' &&
#########################################################################
#
# Makefile for Lattice C on the Amiga
#
# $Id: Makefile.Amiga,v 1.10 1992/07/31 06:58:24 glewis Exp $
#
#########################################################################
X
#
# Rules:
#
CC	= lc:lc
X
.c.o:
X	$(CC) $(CFLAGS) $*
X
.DEFAULT:
X
#
# Lattice C compile options:
#
# -b0 	: 32 bit addressing
# -fi	: ieee math 
# -f8	: Inline M68881 math
# -m3   : Code optimized for 68030
# -cw	: No warning for missing return in int functions
#
LCFLAGS = -cw -b0 -fi
X
# Other options:
#
# -d3	: Debug on 
# -O	: Optimize
#
OPT = -d3
X
#
# Machine specific defines:
#
MACH = -DAMIGA
X
#
# Other defines:
#
DEFS =
X
X
CFLAGS = $(LCFLAGS) $(OPT) $(MACH) $(DEFS)
X
#
# Installation directory for binaries:
#
X
OBJS=read.o write.o readtddd.o writeray.o writemif.o writeps.o writedxf.o \
X	writeoff.o writenff.o writevort.o writepov.o sort.o freeworld.o merge.o \
X	writeim.o
LIB=ttddd.lib
X
all: readwrite tddd2ray tddd2ps tddd2mif tddd2vort tddd2off tddd2nff \
X	tddd2pov tddd2dxf
X
X
$(LIB): $(OBJS)
X	oml $(LIB) r $(OBJS)
X
readwrite: readwrite.o $(LIB)
X	BLINK FROM lib:c.o readwrite.o \
X		  TO readwrite \
X		  LIB $(LIB) lib:lcmieee.lib lib:lc.lib lib:amiga.lib
X
tddd2ray: tddd2ray.o $(LIB)
X	BLINK FROM lib:c.o tddd2ray.o \
X		  TO tddd2ray \
X		  LIB $(LIB) lib:lcmieee.lib lib:lc.lib lib:amiga.lib
X
tddd2ps: tddd2ps.o $(LIB)
X	BLINK FROM lib:c.o tddd2ps.o \
X		  TO tddd2ps \
X		  LIB $(LIB) lib:lcmieee.lib lib:lc.lib lib:amiga.lib
X
tddd2mif: tddd2mif.o $(LIB)
X	BLINK FROM lib:c.o tddd2mif.o \
X		  TO tddd2mif \
X		  LIB $(LIB) lib:lcmieee.lib lib:lc.lib lib:amiga.lib
X
tddd2off: tddd2off.o $(LIB)
X	BLINK FROM lib:c.o tddd2off.o \
X		  TO tddd2off \
X		  LIB $(LIB) lib:lcmieee.lib lib:lc.lib lib:amiga.lib
X
tddd2nff: tddd2nff.o $(LIB)
X	BLINK FROM lib:c.o tddd2nff.o \
X		  TO tddd2nff \
X		  LIB $(LIB) lib:lcmieee.lib lib:lc.lib lib:amiga.lib
X
tddd2vort: tddd2vort.o $(LIB)
X	BLINK FROM lib:c.o tddd2vort.o \
X		  TO tddd2vort \
X		  LIB $(LIB) lib:lcmieee.lib lib:lc.lib lib:amiga.lib
X
tddd2pov: tddd2pov.o $(LIB)
X	BLINK FROM lib:c.o tddd2pov.o \
X		  TO tddd2pov \
X		  LIB $(LIB) lib:lcmieee.lib lib:lc.lib lib:amiga.lib
X
tddd2dxf: tddd2dxf.o $(LIB)
X	BLINK FROM lib:c.o tddd2dxf.o \
X		  TO tddd2dxf \
X		  LIB $(LIB) lib:lcmieee.lib lib:lc.lib lib:amiga.lib
X
X
# $(OBJS): ttdddlib.h
# lmk doesn't understand the above rule, so we have to spell it out!
# 
read.o:		read.c ttdddlib.h
write.o:	write.c ttdddlib.h
readtddd.o:	readtddd.c ttdddlib.h
writeray.o:	writeray.c ttdddlib.h
writevort.o: writevort.c ttdddlib.h
writeoff.o: writeoff.c ttdddlib.h
writenff.o: writenff.c ttdddlib.h
writeim.o:	writeim.c ttdddlib.h
writeps.o:	writeps.c ttdddlib.h
writemif.o:	writemif.c ttdddlib.h
writepov.o:	writepov.c ttdddlib.h
writedxf.o:	writedxf.c ttdddlib.h
sort.o:		sort.c ttdddlib.h
freeworld.o: freeworld.c ttdddlib.h
merge.o: merge.c ttdddlib.h
X
clean:
X	-delete $(OBJS)
X	-delete $(LIB)
X	-delete readwrite readwrite.o
X	-delete tddd2ray tddd2ray.o
X	-delete tddd2ps tddd2ps.o
X	-delete tddd2mif tddd2mif.o
X	-delete tddd2off tddd2off.o
X	-delete tddd2nff tddd2nff.o
X	-delete tddd2vort tddd2vort.o
X	-delete tddd2pov tddd2pov.o
X	-delete tddd2dxf tddd2dxf.o
SHAR_EOF
chmod 0644 Makefile.Amiga ||
echo 'restore of Makefile.Amiga failed'
Wc_c="`wc -c < 'Makefile.Amiga'`"
test 3190 -eq "$Wc_c" ||
	echo 'Makefile.Amiga: original size 3190, current size' "$Wc_c"
fi
# ============= freeworld.c ==============
if test -f 'freeworld.c' -a X"$1" != X"-c"; then
	echo 'x - skipping freeworld.c (File already exists)'
else
echo 'x - extracting freeworld.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'freeworld.c' &&
/* freeworld.c - free a TTDDDLIB WORLD * object
X *             - written by John T. Grieggs - 12-3-91
X *             - Thanks, John!  [--Glenn]
X */
X
static char rcs_id[] = "$Id: freeworld.c,v 1.3 1992/03/27 17:39:56 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
#define myfree(x) {free((char *)x);x=NULL;}
X
/* free an OBJECT struct - recursive */
static OBJECT *free_object(object)
OBJECT *object;
{
X	FGRP *fgrp;
X
X	/* I follow the next chain, then the child chain.  Glenn? */
X	if (object->next)
X		object->next = free_object(object->next);
X	if (object->child)
X		object->child = free_object(object->child);
X
X	/* free the easy parts */
X	if (object->extr)
X		myfree(object->extr);
X	if (object->user)
X		myfree(object->user);
X
X	/* free the DESC */
X	if (object->desc) {
X		if (object->desc->shap)
X			myfree(object->desc->shap);
X		if (object->desc->posi)
X			myfree(object->desc->posi);
X		if (object->desc->axis)
X			myfree(object->desc->axis);
X		if (object->desc->size)
X			myfree(object->desc->size);
X		if (object->desc->pnts)
X			myfree(object->desc->pnts);
X		if (object->desc->colr)
X			myfree(object->desc->colr);
X		if (object->desc->refl)
X			myfree(object->desc->refl);
X		if (object->desc->tran)
X			myfree(object->desc->tran);
X		if (object->desc->spc1)
X			myfree(object->desc->spc1);
X		if (object->desc->edge)
X			myfree(object->desc->edge);
X		if (object->desc->face)
X			myfree(object->desc->face);
X		if (object->desc->clst)
X			myfree(object->desc->clst);
X		if (object->desc->rlst)
X			myfree(object->desc->rlst);
X		if (object->desc->tlst)
X			myfree(object->desc->tlst);
X		if (object->desc->tpar)
X			myfree(object->desc->tpar);
X		if (object->desc->surf)
X			myfree(object->desc->surf);
X		if (object->desc->mttr)
X			myfree(object->desc->mttr);
X		if (object->desc->spec)
X			myfree(object->desc->spec);
X		if (object->desc->prp0)
X			myfree(object->desc->prp0);
X		if (object->desc->prp1)
X			myfree(object->desc->prp1);
X		if (object->desc->ints)
X			myfree(object->desc->ints);
X		if (object->desc->int1)
X			myfree(object->desc->int1);
X		if (object->desc->stry)
X			myfree(object->desc->stry);
X		if (object->desc->eflg) {
X			if (object->desc->eflg->eflg)
X				myfree(object->desc->eflg->eflg);
X			myfree(object->desc->eflg);
X		}
X		while (object->desc->fgrp) {
X			if (object->desc->fgrp->face)
X				myfree(object->desc->fgrp->face);
X			fgrp = object->desc->fgrp;
X			object->desc->fgrp = object->desc->fgrp->next;
X			myfree(fgrp);
X		}
X		myfree(object->desc);
X	}
X
X	/* finally, free yourself */
X	free((char *)object);
X	return NULL;
}
X
/* free the WORLD - always returns NULL, for "World = free_World(World);" */
WORLD *free_World(World)
WORLD *World;
{
X	/* really have an object? */
X	if (!World)
X		return NULL;
X
X	/* free the substructures */
X	if (World->info) {
X		if (World->info->obsv)
X			myfree(World->info->obsv);
X		if (World->info->ostr)
X			myfree(World->info->ostr);
X		if (World->info->fade)
X			myfree(World->info->fade);
X		if (World->info->skyc)
X			myfree(World->info->skyc);
X		if (World->info->ambi)
X			myfree(World->info->ambi);
X		if (World->info->glb0)
X			myfree(World->info->glb0);
X		myfree(World->info);
X	}
X	if (World->object)
X		World->object = free_object(World->object);
X	if (World->user)
X		myfree(World->user);
X
X	/* I don't touch FILE *inp or OBJECT *curobj */
X
X	/* free the World */
X	free((char *)World);
X	return NULL;
}
X
SHAR_EOF
chmod 0644 freeworld.c ||
echo 'restore of freeworld.c failed'
Wc_c="`wc -c < 'freeworld.c'`"
test 3322 -eq "$Wc_c" ||
	echo 'freeworld.c: original size 3322, current size' "$Wc_c"
fi
# ============= merge.c ==============
if test -f 'merge.c' -a X"$1" != X"-c"; then
	echo 'x - skipping merge.c (File already exists)'
else
echo 'x - extracting merge.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'merge.c' &&
/* merge.c - optimize an object by removing common points and edges
X *         - Written by Glenn M. Lewis - 3/10/92
X */
X
#include <stdio.h>
#include "ttdddlib.h"
X
static char rcs_id[] = "$Id: merge.c,v 1.8 1992/07/29 20:46:07 glewis Exp $";
X
void merge_object();
X
void merge_World(world)
WORLD *world;
{
X	OBJECT *o;
X
X	for (o=world->object; o; o=o->next)
X		merge_object(o);
}
X
void remove_point(desc, p)
register DESC *desc;
int p;
{
X	register UWORD *e;
X	register int i;
X
X	if (p >= desc->pcount-1) {		/* No need to do anything */
X		desc->pcount--;
X		return;
X	}
X
X	/* First, move all the points closer to the front of the list */
X	bcopy((char*)&desc->pnts[p+1], (char*)&desc->pnts[p],
X		(unsigned)(desc->pcount-p-1)*sizeof(XYZ_st));
X	desc->pcount--;
X	/* Next, decrement all Point indices that are equal to or greater than "p" */
X	for (i=desc->ecount,e=desc->edge; i--; e+=2) {
X		if (e[0] >= p) e[0]--;
X		if (e[1] >= p) e[1]--;
X	}
}
X
void remove_edge(desc, e)
register DESC *desc;
int e;
{
X	register UWORD *f;
X	register int i;
X
X	if (e >= desc->ecount-1) {		/* No need to do anything */
X		desc->ecount--;
X		return;
X	}
X	/* First, move all the edges closer to the front of the list */
X	bcopy((char*)&desc->edge[(e+1)<<1], (char*)&desc->edge[e<<1],
X		(unsigned)(desc->ecount-e-1)*2*sizeof(UWORD));
X	desc->ecount--;
X	/* Next, decrement all Edge indices that are equal to or greater than "e" */
X	for (i=desc->fcount,f=desc->face; i--; f+=3) {
X		if (f[0] >= e) f[0]--;
X		if (f[1] >= e) f[1]--;
X		if (f[2] >= e) f[2]--;
X	}
}
X
void merge_points(desc, p1, p2)
register DESC *desc;
int p1, p2;
{
X	register UWORD *e;
X	register int i;
X
X	/* First, check all edges, and those that point to "p2" make point to "p1" */
X	for (e=desc->edge,i=0; i<desc->ecount; i++,e+=2) {
X		if (e[0] == p2) e[0] = p1;
X		if (e[1] == p2) e[1] = p1;
X		/* If the two points in the edge are the same point, remove the edge! */
X		if (e[0] == e[1]) { remove_edge(desc, i); i--; e-=2; }
X	}
X	/* Next, remove the duplicate point and adjust *all* the pointers */
X	remove_point(desc, p2);
}
X
void merge_edges(desc, e1, e2)
register DESC *desc;
int e1, e2;
{
X	register UWORD *f;
X	register int i;
X
X	/* First, check all faces, and those that point to "e2" make point to "e1" */
X	for (f=desc->face,i=0; i<desc->fcount; i++,f+=3) {
X		if (f[0] == e2) f[0] = e1;
X		if (f[1] == e2) f[1] = e1;
X		if (f[2] == e2) f[2] = e1;
X	}
X	/* Next, remove the duplicate edge and adjust *all* the pointers */
X	remove_edge(desc, e2);
}
X
void merge_object(obj)
OBJECT *obj;
{
X	register DESC *desc;
X	XYZ_st *p1, *p2;
X	UWORD *e1, *e2;
X	register int i, j;
X
X	if (obj->child) merge_object(obj->child);
X
X	if (!(desc = obj->desc) || !desc->pcount || !desc->ecount) return;
X	/* Merge duplicate points */
X	/* DO NOT ATTEMPT TO OPTIMIZE THE LOOPS, AS THE VARIABLE REFERENCES *MUST*
X	 * BE PERFORMED EACH TIME THROUGH THE LOOP SINCE THE STRUCTURE IS CHANGING!
X	 */
X	/* Start at end and work back */
X
#ifdef DEBUG
fprintf(stderr, "Removing unused edges...\n");
#endif
X
X	/* Remove unused edges */
X	/* Start at end and work back */
X	for (i=desc->ecount; i--; ) {
#ifdef DEBUG
fprintf(stderr, "i:%4d:%4d\n", i, desc->ecount);
#endif
X		for (j=desc->fcount; j--; ) {
X			if (desc->face[3*j]==i ||
X				desc->face[3*j+1]==i ||
X				desc->face[3*j+2]==i) break;	/* Yup, it is used. */
X		}
X		if (j<0)	/* Edge is not referenced in any face.  Delete. */
X			remove_edge(desc, i);
X	}
X
#ifdef DEBUG
fprintf(stderr, "Removing unused points...\n");
#endif
X
X	for (i=desc->pcount; i--; ) {
#ifdef DEBUG
fprintf(stderr, "i:%4d:%4d\n", i, desc->pcount);
#endif
X		for (j=desc->ecount; j--; ) {
X			if (desc->edge[j<<1]==i ||
X				desc->edge[(j<<1)+1]==i) break;	/* Yup, it is used. */
X		}
X		if (j<0)	/* Point is not referenced in any edge.  Delete. */
X			remove_point(desc, i);
X	}
X
#ifdef DEBUG
fprintf(stderr, "Merging duplicate edges...\n");
#endif
X
X	/* Merge duplicate edges */
X	/* Start at end and work back */
X	for (i=desc->ecount-1; i--; ) {
X		e1 = &desc->edge[i<<1];
#ifdef DEBUG
fprintf(stderr, "i:%4d:%4d\n", i, desc->ecount);
#endif
X		for (j=i+1; j<desc->ecount; j++) {
X			e2 = &desc->edge[j<<1];
X			if ((e1[0] == e2[0] && e1[1] == e2[1]) ||
X				(e1[0] == e2[1] && e1[1] == e2[0])) {
X				/* Yep, the edges are identical.  Merge them. */
X				merge_edges(desc, i, j);
X				j--;
X			}
X		}
X	}
X
#ifdef DEBUG
fprintf(stderr, "Merging duplicate points...\n");
#endif
X
X	for (i=desc->pcount-1; i--; ) {
X		p1 = &desc->pnts[i];
#ifdef DEBUG
fprintf(stderr, "i:%4d:%4d\n", i, desc->pcount);
#endif
X		for (j=i+1; j<desc->pcount; j++) {
X			p2 = &desc->pnts[j];
X			if (p1->val[0] == p2->val[0] &&
X				p1->val[1] == p2->val[1] &&
X				p1->val[2] == p2->val[2]) {
X				/* Yep, the points are identical.  Merge them. */
X				merge_points(desc, i, j);
X				j--;
X			}
X		}
X	}
}
SHAR_EOF
chmod 0644 merge.c ||
echo 'restore of merge.c failed'
Wc_c="`wc -c < 'merge.c'`"
test 4749 -eq "$Wc_c" ||
	echo 'merge.c: original size 4749, current size' "$Wc_c"
fi
# ============= read.c ==============
if test -f 'read.c' -a X"$1" != X"-c"; then
	echo 'x - skipping read.c (File already exists)'
else
echo 'x - extracting read.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'read.c' &&
/* read.c - read a TTDDD file and fill the structures
X *        - written by Glenn M. Lewis - 7/19/91
X */
X
static char rcs_id[] = "$Id: read.c,v 1.20 1992/07/31 18:48:40 glewis Exp glewis $";
X
#include <stdio.h>
#include <ctype.h>
#include "ttdddlib.h"
X
static void process_INFO();
static void process_OBJ();
static OBJECT *process_EXTR();
static void process_DESC();
X
#define MAXLINE 132
#define get_UBYTE	(UBYTE)get_num
#define get_UWORD	(UWORD)get_num
#define get_ULONG	(ULONG)get_num
X
static char strin[MAXLINE+1], ps[MAXLINE+1];
X
/* Here are a few necessary utilities */
X
static void warn(curline)
int curline;
{
X	fprintf(stderr, "WARNING: Line %d: ", curline);
}
X
static void parse_word(name, lim, up)	/* Get next word, optionally limit # of chars */
register char *name;
int lim, up;
{
X	register char *c = &strin[0];
X	register int i;
X	int quote = 0;
X
X	while (*c==' ') c++;		/* Skip over leading spaces */
X	for (i=0; *c; i++,c++) {
X		if (lim && i>=lim) break;	/* No more characters desired */
X		if (*c == '\"') {			/* Chop off quotes, ignore spaces */
X			if (quote) break;		/* Second quote.  Stop reading string */
X			quote=1;
X			i--;					/* Don't want i to increment */
X			continue;
X		}
X		if (up && !quote && islower(*c)) *name++ = toupper(*c);
X		else {
X			if (!quote && *c==' ') break;	/* End of the line */
X			*name++ = *c;			/* Don't modify original case */
X		}
X	}
X	*name = '\0';	/* Truncate the puppy */
X	/* Now, delete the command from 'strin' */
X	while (*c && *c!=' ') c++;	/* Skip the end of the command */
X	while (*c==' ') c++;		/* Skip mid-word spacing */
X	strcpy(strin, c);			/* Chop off front of line */
}
X
static int get_line(strin, w)
register char *strin;
WORLD *w;
{
X	static int comment = 0;
X	int quote = 0, start;
X	register char *c;
X	extern int already_read_header;			/* A hack to include characters */
X	extern unsigned char header_storage[];	/* that were already read from in */
X
GET_MORE:
X	if (comment) start = 0; else start = -1;
X	if (fgets(&strin[already_read_header], MAXLINE, w->inp) == NULL) {
X		already_read_header = 0;
X		if (comment)
X		fprintf(stderr, "WARNING: Line %d: Unterminated comment.\n",w->cur_line);
X		return(0);	/* EOF */
X	}
X	already_read_header = 0;
X	w->cur_line++;
X	for (c=strin; *c; c++) {
X		if (*c=='/' && c[1]=='*') {			/* Begin of comment */
X			if (!quote) {
X				if (!comment++) {			/* First comment */
X					start = (int)(c-strin);
X				}
X			}
X		} else
X		if (*c=='*' && c[1]=='/') {			/* End of comment */
X			if (!quote) {
X				comment--;
X				if (comment<0) {
X					fprintf(stderr, "ERROR!  '*/' before '/*'\n*** ABORT ***\n");
X					exit(20);
X				}
X				if (!comment) {				/* Chop off front of line */
X					strcpy(strin, c+2);
X					c = strin-1;			/* Pointer will increment */
X				}
X			}
X		} else
X		if (*c=='%') {						/* Line comment */
X			if (!(quote || comment)) {
X				*c = '\0';					/* Terminate line */
X				break;
X			}
X		} else
X		if (*c =='\"') {					/* Quote */
X			if (!comment) quote=1-quote;	/* Toggle flag */
X		} else
X		if (*c == '\t') *c = ' ';			/* Change tabs to spaces */
X		else
X		if (!quote && (*c=='[' || *c==']' || *c=='=')) *c = ' ';
X		if (*c == '\n') { *c = '\0'; break; }
X	}
X	if (comment) strin[start] = '\0';		/* Chop off comment */
/* Skip leading white space to see if this line contains anything */
X	for (c=strin; *c==' '; c++) ;
X	if (!*c) goto GET_MORE;
X	return(1);
}
X
static int valid_num;
X
static long get_num()
{
X	long val = 0;
X	char neg = ' ';
X	register char *c = &strin[0];
X
X	valid_num = 0;
X	while (*c == ' ') c++;		/* Skip leading space */
X	if (*c == '-') neg = *c++;	/* Save the negation  */
X	if (!isdigit(*c)) return(0L);
X	while (*c && isdigit(*c))
X		val = (val*10) + (*c++ - '0');
X	while (*c == ' ') c++;		/* Skip trailing space */
X	strcpy(strin, c);			/* Chop off number */
X	valid_num = 1;
X	return((neg=='-' ? -val : val));
}
X
static int valid_FRACT;
X
static double get_FRACT()
{
X	register long whole, frac, place, expo;
X	register char *s = &strin[0];
X	char neg=' ', negexp=' ';
X	double f;
X
X	valid_FRACT = 0;
X	whole = expo = 0;
X	while (*s == ' ') s++;
X	if (*s == '-') neg = *s++;
X	if (!isdigit(*s) && *s!='.') return(0L);	/* Invalid FRACT */
X	while (*s && isdigit(*s))		/* Handle float before decimal point */
X		whole = (whole * 10) + (*s++ - '0');
X	if (*s == '.') {		/* Handle float after decimal point */
X		s++;
X		frac = 0;
X		for (place=1; *s && isdigit(*s); place*=10)
X			frac = (frac * 10) + (*s++ - '0');
X		f = (double)whole + ((double)frac/(double)place);
X	} else f = (double)whole;
X	if (*s == 'e' || *s == 'E') {	/* Support exponential notation */
X		s++;
X		if (*s=='-' || *s=='+') negexp = *s++;
X		while (*s && isdigit(*s)) expo = (expo*10) + (*s++ - '0');
X		if (negexp=='-')	while (expo--) f/=10.0;
X		else				while (expo--) f*=10.0;
X	}
X	while (*s == ' ') s++;
X	strcpy(strin, s);
X	valid_FRACT = 1;
X	return((neg=='-' ? -f : f));
}
X
static void stuff_XYZ(st)
XXYZ_st *st;
{
X	register char *c = &strin[0];
X	register int i, flag, cnt;
X
X	flag = 0;	/* If they use 'X','Y', or 'Z', they must continue to use it */
X	/* On the other hand, if they give only a single parameter, then it applies to all */
X	cnt = 0;
X	for (i=0; i<3; i++) {
X		if (*c=='x' || *c=='X')		/* If !valid, it's an ERROR! */
X		{ *c=' '; st->val[0] = get_FRACT(); if (valid_FRACT) flag=1; }
X		else
X		if (*c=='y' || *c=='Y')
X		{ *c=' '; st->val[1] = get_FRACT(); if (valid_FRACT) flag=1; }
X		else
X		if (*c=='z' || *c=='Z')
X		{ *c=' '; st->val[2] = get_FRACT(); if (valid_FRACT) flag=1; }
X		else if (!flag) {
X			st->val[i] = get_FRACT();
X			if (valid_FRACT) cnt++;
X		}
X	}
X	if (!flag && cnt==1) { 	/* Copy value into other two elements */
X		st->val[1] = st->val[2] = st->val[0];
X	}
}
X
static void stuff_RGB(st)
RGB_st *st;
{
X	register char *c = &strin[0];
X	register int i, flag, cnt;
X
X	flag = 0;	/* If they use 'R','G', or 'B', they must continue to use it */
X	/* On the other hand, if they give only a single parameter, then it applies to all */
X	cnt = 0;
X	for (i=0; i<3; i++) {
X		if (*c=='r' || *c=='R')		/* If !valid, it's an ERROR! */
X		{ *c=' '; st->val[0] = get_UBYTE(); if (valid_num) flag=1; }
X		else
X		if (*c=='g' || *c=='G')
X		{ *c=' '; st->val[1] = get_UBYTE(); if (valid_num) flag=1; }
X		else
X		if (*c=='b' || *c=='B')
X		{ *c=' '; st->val[2] = get_UBYTE(); if (valid_num) flag=1; }
X		else if (!flag) {
X			st->val[i] = get_UBYTE();
X			if (valid_num) cnt++;
X		}
X	}
X	if (!flag && cnt==1) { 	/* Copy value into other two elements */
X		st->val[1] = st->val[2] = st->val[0];
X	}
}
X
/********************/
/* The MAIN section */
/********************/
X
WORLD *read_TTDDD(file)
FILE *file;
{
X	char name[5];
X	WORLD *world;
X
X	if (!file) return(0L); /* File not open */
X
X	if (!(world = (WORLD*)malloc(sizeof(WORLD)))) { OUT_MEM("WORLD"); }
X	bzero((char*)world, sizeof(WORLD));
X	world->inp = file;
X
X	if (already_read_header)	/* Copy the data into the "strin" */
X		strncpy(strin, header_storage, already_read_header);
X
/* Here is the main loop: */
X	while (get_line(strin, world)) {
X		parse_word(name, 4, 1);		/* And chop it out of the string */
X
X		if		(strcmp(name, "INFO")==0) process_INFO(world);
X		else if (strcmp(name, "OBJ") ==0) process_OBJ(world);
X		else {
X			fprintf(stderr, "Invalid chunk on line %d: '%s' (skipped)\n",
X				world->cur_line, name);
X			continue;
X		}
X	}
X
/* All done.  Close up shop. */
X	return(world);
}
X
static void process_INFO(world)
WORLD *world;
{
X	register INFO *info;
X	register ULONG i;
X	char this_level[MAXLINE], name[5];
X
X	if (world->info) {
X		fprintf(stderr, "Parse error: More than one INFO chunk!\n"); exit(-1); }
X	if (!(info = world->info = (INFO*)malloc(sizeof(INFO)))) { OUT_MEM("INFO"); }
X	bzero((char *)world->info, sizeof(INFO));
X
X	parse_word(this_level, 0, 1);	/* No limit, uppercase. */
X	if (strcmp(this_level, "BEGIN") != 0) {
X		fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'INFO'\n",
X			world->cur_line);
X	}
X	parse_word(this_level, 0, 0);	/* No limit, original case */
X
X	while (get_line(strin, world)) {
X		parse_word(name, 4, 1);		/* Get command */
X		if (strcmp(name, "BRSH")==0) {
X			i = get_UWORD();
X			if (i<0 || i>7) fputs("BRSH error.\n", stderr);
X			parse_word(ps, 0, 0);
X			strncpy(info->brsh[i], ps, 80);
X			info->brsh[i][80]='\0';
X		} else
X		if (strcmp(name, "STNC")==0) {
X			i = get_UWORD();
X			if (i<0 || i>7) fputs("STNC error.\n", stderr);
X			parse_word(ps, 0, 0);
X			strncpy(info->stnc[i], ps, 80);
X			info->stnc[i][80]='\0';
X		} else
X		if (strcmp(name, "TXTR")==0) {
X			i = get_UWORD();
X			if (i<0 || i>7) fputs("TXTR error.\n", stderr);
X			parse_word(ps, 0, 0);
X			strncpy(info->txtr[i], ps, 80);
X			info->txtr[i][80]='\0';
X		} else
X		if (strcmp(name, "OBSV")==0) {
X			if (!info->obsv) info->obsv=(OBSV*)malloc(sizeof(OBSV));
X			if (!info->obsv) { OUT_MEM("OBSV"); }
X			parse_word(name, 4, 1);		/* Get field */
X			if		(strcmp(name, "CAME")==0) stuff_XYZ(&info->obsv->came);
X			else if (strcmp(name, "ROTA")==0) stuff_XYZ(&info->obsv->rota);
X			else if (strcmp(name, "FOCA")==0) info->obsv->foca = get_FRACT();
X			else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown OBSV field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "OTRK")==0) {
X			parse_word(ps, 0, 0);
X			strncpy(info->otrk, ps, 18);
X			info->otrk[18]='\0';
X		} else
X		if (strcmp(name, "OSTR")==0) {
X			if (!info->ostr) info->ostr=(STRY*)malloc(sizeof(STRY));
X			if (!info->ostr) { OUT_MEM("OSTR"); }
X			parse_word(name, 4, 1);		/* Get field */
X			if (strcmp(name, "PATH")==0) parse_word(info->ostr->path, 18, 0);
X			else if (strcmp(name, "TRAN")==0) stuff_XYZ(&info->ostr->tran);
X			else if (strcmp(name, "ROTA")==0) stuff_XYZ(&info->ostr->rota);
X			else if (strcmp(name, "SCAL")==0) stuff_XYZ(&info->ostr->scal);
X			else
X			if (strcmp(name, "INFO")==0) {
X				info->ostr->info = 0;
X				while (strin[0]) {
X					parse_word(ps, 7, 1);
X					if		(strcmp(ps, "ABS_TRA")==0) info->ostr->info|=(1<<0);
X					else if (strcmp(ps, "ABS_ROT")==0) info->ostr->info|=(1<<1);
X					else if (strcmp(ps, "ABS_SCL")==0) info->ostr->info|=(1<<2);
X					else if (strcmp(ps, "LOC_TRA")==0) info->ostr->info|=(1<<4);
X					else if (strcmp(ps, "LOC_ROT")==0) info->ostr->info|=(1<<5);
X					else if (strcmp(ps, "LOC_SCL")==0) info->ostr->info|=(1<<6);
X					else if (strcmp(ps, "X_ALIGN")==0) info->ostr->info|=(1<<8);
X					else if (strcmp(ps, "Y_ALIGN")==0) info->ostr->info|=(1<<9);
X					else if (strcmp(ps, "Z_ALIGN")==0) info->ostr->info|=(1<<10);
X					else if (strcmp(ps, "FOLLOW_")==0) info->ostr->info|=(1<<12);
X					else {
#ifdef WARNING
X						fprintf(stderr, "WARNING: Line %d: Unknown OSTR INFO flag: '%s'\n", world->cur_line, ps);
#endif
X						continue;
X					}
X				}
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown OSTR field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "FADE")==0) {
X			if (!info->fade) info->fade=(FADE*)malloc(sizeof(FADE));
X			if (!info->fade) { OUT_MEM("FADE"); }
X			parse_word(ps, 6, 1);		/* Get field */
X			if		(strcmp(ps, "FADEAT")==0) info->fade->at = get_FRACT();
X			else if (strcmp(ps, "FADEBY")==0) info->fade->by = get_FRACT();
X			else if (strcmp(ps, "FADETO")==0) stuff_RGB(&info->fade->to);
X			else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown FADE field: '%s'\n", world->cur_line, ps);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "SKYC")==0) {
X			if (!info->skyc) info->skyc=(SKYC*)malloc(sizeof(SKYC));
X			if (!info->skyc) { OUT_MEM("SKYC"); }
X			parse_word(name, 4, 1);		/* Get field */
X			if		(strcmp(name, "HORI")==0) stuff_RGB(&info->skyc->hori);
X			else if (strcmp(name, "ZENI")==0) stuff_RGB(&info->skyc->zeni);
X			else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown SKYC field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "AMBI")==0) {
X			if (!info->ambi) info->ambi=(RGB_st*)malloc(sizeof(RGB_st));
X			if (!info->ambi) { OUT_MEM("AMBI"); }
X			stuff_RGB(info->ambi);
X		} else
X		if (strcmp(name, "GLB0")==0) {
X			if (!info->glb0) info->glb0=(BYTE*)malloc(8*sizeof(BYTE));
X			if (!info->glb0) { OUT_MEM("GLB0"); }
X			i = get_ULONG();	/* Index into array */
X			if (i>=0 && i<8) {
X				info->glb0[i] = (BYTE) get_ULONG();
X			} else
X				fprintf(stderr, "WARNING: Line %d: Bad index: GLB0[%d] should be [0..7]\n", world->cur_line, i);
X		} else if (strcmp(name, "END")==0) {
X			parse_word(name, 4, 1);
X			if (strcmp(name, "INFO")!=0)
X				fprintf(stderr, "WARNING: Line %d: Expected 'END INFO' but got: 'END %s'\n", world->cur_line, name);
X			parse_word(ps, 0, 0);	/* Get the quote, if any */
X			if (strcmp(this_level, ps)!=0)
X				fprintf(stderr, "WARNING: Line %d: 'INFO Begin' and 'End INFO' quoted comments do not match\n", world->cur_line);
X			break;
X		}
#ifdef WARNING
X		else fprintf(stderr, "WARNING: Line %d: Unknown INFO sub-sub-chunk: '%s'\n", world->cur_line, name);
#endif
X	}
}
X
OBJECT *create_object()
{
X	OBJECT *p;
X	p = (OBJECT*)malloc(sizeof(OBJECT));
X	if (!p) { OUT_MEM("Create"); }
X	bzero((char*)p,sizeof(OBJECT));
X	return(p);
}
X
static void process_OBJ(world)
WORLD *world;
{
X	char this_level[MAXLINE], name[5];
X	register OBJECT *p;
X	int depth;
X
X	parse_word(this_level, 0, 1);	/* No limit, uppercase. */
X	if (strcmp(this_level, "BEGIN") != 0) {
X		fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'OBJ'\n",
X			world->cur_line);
X	}
X	parse_word(this_level, 0, 0);	/* No limit, original case */
X
X	depth=0;
X	while (get_line(strin, world)) {
X		parse_word(name, 4, 1);		/* Get command */
X		if		(strcmp(name, "EXTR")==0) {
X			p = process_EXTR(create_object(), world);
X			if (world->curobj) {
X				world->curobj->next = p;
X				p->parent = world->curobj->parent;
X			} else {
X				world->object = p;
X				p->parent = 0;
X			}
X			world->curobj = p;
X		} else if (strcmp(name, "DESC")==0) {
X			p = create_object();
X			if (world->num_DESC > world->num_TOBJ+depth) {	/* This is a child */
X				depth++;	/* Down one in the hierarchy */
X				world->curobj->child = p;
X				p->parent = world->curobj;
X			} else {
X				if (world->curobj) {
X					world->curobj->next = p;
X					p->parent = world->curobj->parent;
X				} else {
X					world->object = p;
X					p->parent = 0;
X				}
X			}
X			world->curobj = p;
X			process_DESC(&p->desc, world);
X		} else if (strcmp(name, "TOBJ")==0) {
X			world->num_TOBJ++;
X			if (world->num_TOBJ > world->num_DESC) {
X				warn(world->cur_line);
X				fprintf(stderr, "TOBJ without DESC.  Ignored.\n");
X			}
X			if (world->num_TOBJ+depth > world->num_DESC) {	/* Go back up a level */
X				depth--;
X				world->curobj=world->curobj->parent;
X			}
X		} else if (strcmp(name, "END" )==0) {
X			if (world->num_DESC > world->num_TOBJ) {
X				int i;
X				warn(world->cur_line);
X				i = world->num_DESC - world->num_TOBJ;
X				fprintf(stderr, "Missing %d 'TOBJ'.  Inserted.\n", i);
X			}
X			parse_word(name, 4, 1);
X			if (strcmp(name, "OBJ")!=0)
X				fprintf(stderr, "WARNING: Line %d: Expected 'END OBJ' but got: 'END %s'\n", world->cur_line, name);
X			parse_word(ps, 0, 0);	/* Get the quote, if any */
X			if (strcmp(this_level, ps)!=0)
X				fprintf(stderr, "WARNING: Line %d: 'OBJ Begin' and 'End OBJ' quoted comments do not match\n", world->cur_line);
X			break;
X		}
#ifdef WARNING
X		else
X		fprintf(stderr, "WARNING: Line %d: Unknown OBJ sub-sub-chunk: '%s'\n",
X			world->cur_line, name);
#endif
X	}
}
X
static OBJECT *process_EXTR(obj, world)
OBJECT *obj;
WORLD *world;
{
X	register EXTR *extr;
X	register OBJECT *p;
X	char this_level[MAXLINE], name[5];
X	MTRX *mtrx;
X	WORLD *new;
X	FILE *newinp;
X
X	if (!(extr = obj->extr = (EXTR*)malloc(sizeof(EXTR)))) { OUT_MEM("EXTR"); }
X	bzero((char*)extr, sizeof(EXTR));
X	mtrx = &extr->mtrx;
X	/* Initialize structure */
X	mtrx->tran.val[0]  = mtrx->tran.val[1]  = mtrx->tran.val[2]  = 0.0;
X	mtrx->scal.val[0]  = mtrx->scal.val[1]  = mtrx->scal.val[2]  = 1.0;
X	mtrx->rota1.val[1] = mtrx->rota1.val[2] = 0.0;
X	mtrx->rota2.val[0] = mtrx->rota2.val[2] = 0.0;
X	mtrx->rota3.val[0] = mtrx->rota3.val[1] = 0.0;
X	mtrx->rota1.val[0] = mtrx->rota2.val[1] = mtrx->rota3.val[2] = 1.0;
X
X	parse_word(this_level, 0, 1);	/* No limit, uppercase. */
X	if (strcmp(this_level, "BEGIN") != 0) {
X		fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'EXTR'\n",
X			world->cur_line);
X	}
X	parse_word(this_level, 0, 0);	/* No limit, original case */
X
X	while (get_line(strin, world)) {
X		parse_word(name, 4, 1);		/* Get command */
X		if		(strcmp(name, "MTRX")==0) {
X			parse_word(name, 4, 1);		/* Get field */
X			if      (strcmp(name, "TRAN")==0) stuff_XYZ(&mtrx->tran);
X			else if (strcmp(name, "SCAL")==0) stuff_XYZ(&mtrx->scal);
X			else if (strcmp(name, "ROTA")==0) {
X				stuff_XYZ(&mtrx->rota1);
X				stuff_XYZ(&mtrx->rota2);
X				stuff_XYZ(&mtrx->rota3);
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown MTRX field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else if (strcmp(name, "LOAD")==0) {
X			parse_word(extr->filename, 80, 0);
X		} else if (strcmp(name, "END" )==0) {
X			parse_word(name, 4, 1);
X			if (strcmp(name, "EXTR")!=0)
X				fprintf(stderr, "WARNING: Line %d: Expected 'END EXTR' but got: 'END %s'\n", world->cur_line, name);
X			parse_word(ps, 0, 0);	/* Get the quote, if any */
X			if (strcmp(this_level, ps)!=0)
X				fprintf(stderr, "WARNING: Line %d: 'EXTR Begin' and 'End EXTR' quoted comments do not match\n", world->cur_line);
X			break;
X		}
#ifdef WARNING
X		else fprintf(stderr, "WARNING: Line %d: Unknown EXTR sub-sub-chunk: '%s'\n", world->cur_line, name);
#endif
X	}
X	/* Now, load in the external object */
X	if (!(newinp=fopen(extr->filename, "r"))) {
X		fprintf(stderr, "Can't load in EXTR object: '%s'... ignored.\n",
X			extr->filename);
X		return(obj);
X	}
X	new = read_World(newinp);
X	fclose(newinp);
X	/* scale, rotate, and translate new object hierarchy */
X	for (p=new->object; p; p=p->next)
X		move_extr(p, mtrx);
X	/* Free up unused memory */
X	free((char*)obj->extr);
X	free((char*)obj);
X	obj = new->object;
X	free((char*)new);
X	return(obj);
}
X
void move_extr(obj, mtrx)
register OBJECT *obj;
register MTRX *mtrx;
{
X	register XYZ_st *p;
X	register int i;
X	register double x, y, z;
X	if (obj->desc)
X		for (p=obj->desc->pnts,i=obj->desc->pcount; i--; p++) {
X			x = (p->val[0]*mtrx->scal.val[0]);
X			y = (p->val[1]*mtrx->scal.val[1]);
X			z = (p->val[2]*mtrx->scal.val[2]);
X			p->val[0] = x*mtrx->rota1.val[0] +
X						y*mtrx->rota1.val[1] +
X						z*mtrx->rota1.val[2] +
X						mtrx->tran.val[0];
X			p->val[1] = x*mtrx->rota2.val[0] +
X						y*mtrx->rota2.val[1] +
X						z*mtrx->rota2.val[2] +
X						mtrx->tran.val[1];
X			p->val[2] = x*mtrx->rota3.val[0] +
X						y*mtrx->rota3.val[1] +
X						z*mtrx->rota3.val[2] +
X						mtrx->tran.val[2];
X		}
X	for (obj=obj->child; obj; obj=obj->next)
X		move_extr(obj, mtrx);	/* Process all children */
}
X
void OUT_MEM(s)
char *s;
{
X	if (s)
X	fprintf(stderr, "Ran out of memory while processing '%s'.  Sorry.\n", s);
X	exit(-1);
}
X
static UBYTE defclst[3], defrlst[3], deftlst[3], defspc1[3];
X
static void malloc_arrays(i, desc)
register int i;
register DESC *desc;
{
X	if (!desc->fcount) {
X		desc->fcount = i;
if (!(desc->face=(UWORD*)malloc(3*desc->fcount*sizeof(UWORD))))OUT_MEM((char*)0);
if (!(desc->clst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
if (!(desc->rlst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
if (!(desc->tlst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
X		/* Initialize arrays */
X		for (i=0; i<3*desc->fcount; i+=3) {
X			desc->face[i]   = desc->face[i+1] = desc->face[i+2] = 0;
X			desc->clst[i]   = defclst[0];
X			desc->clst[i+1] = defclst[1];
X			desc->clst[i+2] = defclst[2];
X			desc->rlst[i]   = defrlst[0];
X			desc->rlst[i+1] = defrlst[1];
X			desc->rlst[i+2] = defrlst[2];
X			desc->tlst[i]   = deftlst[0];
X			desc->tlst[i+1] = deftlst[1];
X			desc->tlst[i+2] = deftlst[2];
X		}
X	} else if (i != desc->fcount) {
X		fprintf(stderr, "ERROR: FACE and [C|R|T]LST 'Count' values inconsistant.\n");
X		OUT_MEM((char*)0);
X	}
}
X
static void process_DESC(orig, world)
DESC **orig;
WORLD *world;
{
X	register DESC *desc;
X	register int i;
X	char this_level[MAXLINE], name[5];
X	FGRP *fgrp;
X
X	if (!(desc = *orig = (DESC*)malloc(sizeof(DESC)))) { OUT_MEM("DESC"); }
X	bzero((char*)desc, sizeof(DESC));
X
X	/* Set up defaults: */
X	defclst[0] = defclst[1] = defclst[2] = 240;	/* TS default */
X	defrlst[0] = defrlst[1] = defrlst[2] = 0;
X	deftlst[0] = deftlst[1] = deftlst[2] = 0;
X	defspc1[0] = defspc1[1] = defspc1[2] = 0;
X
X	parse_word(this_level, 0, 1);	/* No limit, uppercase. */
X	if (strcmp(this_level, "BEGIN") != 0) {
X		fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'DESC'\n",
X			world->cur_line);
X	}
X	parse_word(this_level, 0, 0);	/* No limit, original case */
X
X	world->num_DESC++;
X
X	while (get_line(strin, world)) {
X		parse_word(name, 4, 1);		/* Get command */
X		/* Put most-frequent commands near the front of this list */
X		if (strcmp(name, "PNTS")==0) {
X			parse_word(name, 4, 1);		/* Get field */
X			if		  (strcmp(name, "POIN")==0) {
X				if (!desc->pcount) {
X					fprintf(stderr, "ERROR: Line %d: 'PNTS Point' encountered before 'PNTS PCount'\n", world->cur_line);
X					OUT_MEM((char*)0);
X				}
X				i = get_UWORD();
X				if (i<0 || i>=desc->pcount) {
X					fprintf(stderr, "WARNING: Line %d: Bad index: PNTS Point[%d] should be [0..%d]\n", world->cur_line, i, desc->pcount-1);
X					continue;
X				}
X				stuff_XYZ(&desc->pnts[i]);
X			} else if (strcmp(name, "PCOU")==0) {
X				if (!desc->pcount) {
X					desc->pcount = get_UWORD();
X					if (!(desc->pnts = (XYZ_st*)malloc(desc->pcount*sizeof(XYZ_st))))
X						OUT_MEM("PNTS");
X					/* Initialize array */
X					for (i=0; i<desc->pcount; i++) {
X						desc->pnts[i].val[0] = 0;
X						desc->pnts[i].val[1] = 0;
X						desc->pnts[i].val[2] = 0;
X					}
X				} else {
X					fprintf(stderr, "WARNING: Line %d: PNTS Pcount defined more than once.\n", world->cur_line);
X				}
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown PNTS field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "EDGE")==0) {
X			parse_word(name, 4, 1);		/* Get field */
X			if		  (strcmp(name, "EDGE")==0) {
X				if (!desc->ecount) {
X					fprintf(stderr, "ERROR: Line %d: 'EDGE Edge' encountered before 'EDGE ECount'\n", world->cur_line);
X					OUT_MEM((char*)0);
X				}
X				i = get_UWORD();
X				if (i<0 || i>=desc->ecount) {
X					fprintf(stderr, "WARNING: Line %d: Bad index: EDGE Edge[%d] should be [0..%d]\n", world->cur_line, i, desc->ecount-1);
X					continue;
X				}
X				desc->edge[2*i]   = get_UWORD();
X				desc->edge[2*i+1] = get_UWORD();
X			} else if (strcmp(name, "ECOU")==0) {
X				if (!desc->ecount) {
X					desc->ecount = get_UWORD();
X					if (!(desc->edge = (UWORD*)malloc(2*desc->ecount*sizeof(UWORD))))
X						OUT_MEM("EDGE");
X					/* Initialize array */
X					for (i=0; i<2*desc->ecount; i++)
X						desc->edge[i] = 0;
X				} else {
X					fprintf(stderr, "WARNING: Line %d: EDGE Ecount defined more than once.\n", world->cur_line);
X				}
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown EDGE field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "EFLG")==0) {
X			parse_word(name, 4, 1);		/* Get field */
X			if (strcmp(name, "COUN")==0) {
X				if (!desc->eflg) {
X					if (!(desc->eflg = (EFLG*)malloc(sizeof(EFLG))))
X						OUT_MEM("EFLG");
X					desc->eflg->num = get_UWORD();
X					if (!(desc->eflg->eflg = (UBYTE*)malloc(desc->eflg->num*sizeof(UBYTE))))
X						OUT_MEM("EFLG");
X					/* Initialize array */
X					for (i=0; i<desc->eflg->num; i++)
X						desc->eflg->eflg[i] = 0;
X				} else {
X					fprintf(stderr, "WARNING: Line %d: EFLG Count defined more than once.\n", world->cur_line);
X				}
X			} else if (strcmp(name, "EFLG")==0) {
X				if (!desc->eflg) {
X					fprintf(stderr, "ERROR: Line %d: 'EFLG Eflg' encountered before 'EFLG Count'\n", world->cur_line);
X					OUT_MEM((char*)0);
X				}
X				i = get_UWORD();
X				if (i<0 || i>=desc->eflg->num) {
X					fprintf(stderr, "WARNING: Line %d: Bad index: EFLG Eflg[%d] should be [0..%d]\n", world->cur_line, i, desc->eflg->num-1);
X					continue;
X				}
X				desc->eflg->eflg[i]   = get_UWORD();
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown EFLG field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "FACE")==0) {
X			parse_word(name, 4, 1);		/* Get field */
X			if		  (strcmp(name, "CONN")==0) {
X				if (!desc->fcount) {
X					fprintf(stderr, "ERROR: Line %d: 'FACE Connects' encountered before 'FACE TCount'\n", world->cur_line);
X					OUT_MEM((char*)0);
X				}
X				i = get_UWORD();
X				if (i<0 || i>=desc->fcount) {
X					fprintf(stderr, "WARNING: Line %d: Bad index: FACE Connects[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
X					continue;
X				}
X				desc->face[3*i]   = get_UWORD();
X				desc->face[3*i+1] = get_UWORD();
X				desc->face[3*i+2] = get_UWORD();
X			} else if (strcmp(name, "TCOU")==0) {
X				i = get_UWORD();
X				malloc_arrays(i, desc);
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown FACE field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "FGRP")==0) {
X			parse_word(name, 4, 1);
X			if (strcmp(name, "NAME")==0) {
X				if (!(fgrp = (FGRP*)malloc(sizeof(FGRP))))
X					OUT_MEM("FGRP");
X				bzero((char*)fgrp, sizeof(FGRP));
X				parse_word(ps, 0, 0);
X				strncpy(fgrp->name, ps, 18);
X				fgrp->name[18]='\0';
X				fgrp->next = desc->fgrp;
X				desc->fgrp = fgrp;
X			} else if (strcmp(name, "COUN")==0) {
X				i = get_UWORD();
X				if (!desc->fgrp) {
X					fprintf(stderr, "ERROR: Line %d: 'FGRP Count' encountered before 'FGRP Name'\n", world->cur_line);
X					OUT_MEM((char*)0);
X				}
X				if (desc->fgrp->face) {
X					fprintf(stderr, "ERROR: Line %d: 'FGRP Count' encountered twice\n", world->cur_line);
X					OUT_MEM((char*)0);
X				}
X				desc->fgrp->num = i;
X				if (!(desc->fgrp->face = (UWORD*)malloc(i*sizeof(UWORD))))
X					OUT_MEM("FGRP");
X				while (i--) desc->fgrp->face[i] = 0;
X			} else if (strcmp(name, "FACE")==0) {
X				i = get_UWORD();
X				if (i<0 || i>=desc->fgrp->num) {
X					fprintf(stderr, "WARNING: Line %d: Bad index: FGRP Face[%d] should be [0..%d]\n", world->cur_line, i, desc->fgrp->num-1);
X					continue;
X				}
X				desc->fgrp->face[i] = get_UWORD();
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown FGRP field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "CLST")==0) {
X			parse_word(name, 4, 1);		/* Get field */
X			if		  (strcmp(name, "COLO")==0) {
X				if (!desc->fcount) {
X					fprintf(stderr, "ERROR: Line %d: 'CLST Color' encountered before 'CLST Count'\n", world->cur_line);
X					OUT_MEM((char*)0);
X				}
X				i = get_UWORD();
X				if (i<0 || i>=desc->fcount) {
X					fprintf(stderr, "WARNING: Line %d: Bad index: CLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
X					continue;
X				}
X				stuff_RGB((RGB_st*)&desc->clst[3*i]);	/* Place 3 UBYTE's into array */
X			} else if (strcmp(name, "COUN")==0) {
X				i = get_UWORD();
X				malloc_arrays(i, desc);
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown CLST field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "RLST")==0) {
X			parse_word(name, 4, 1);		/* Get field */
X			if		  (strcmp(name, "COLO")==0) {
X				if (!desc->fcount) {
X					fprintf(stderr, "ERROR: Line %d: 'RLST Color' encountered before 'RLST Count'\n", world->cur_line);
X					OUT_MEM((char*)0);
X				}
X				i = get_UWORD();
X				if (i<0 || i>=desc->fcount) {
X					fprintf(stderr, "WARNING: Line %d: Bad index: RLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
X					continue;
X				}
X				stuff_RGB((RGB_st*)&desc->rlst[3*i]);	/* Place three UBYTE's into array */
X			} else if (strcmp(name, "COUN")==0) {
X				i = get_UWORD();
X				malloc_arrays(i, desc);
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown RLST field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "TLST")==0) {
X			parse_word(name, 4, 1);		/* Get field */
X			if		  (strcmp(name, "COLO")==0) {
X				if (!desc->fcount) {
X					fprintf(stderr, "ERROR: Line %d: 'TLST Color' encountered before 'TLST Count'\n", world->cur_line);
X					OUT_MEM((char*)0);
X				}
X				i = get_UWORD();
X				if (i<0 || i>=desc->fcount) {
X					fprintf(stderr, "WARNING: Line %d: Bad index: TLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
X					continue;
X				}
X				stuff_RGB((RGB_st*)&desc->tlst[3*i]);	/* Place three UBYTE's into array */
X			} else if (strcmp(name, "COUN")==0) {
X				i = get_UWORD();
X				malloc_arrays(i, desc);
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown TLST field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "NAME")==0) {
X			parse_word(ps, 0, 0);
X			strncpy(desc->name, ps, 18);
X			desc->name[18]='\0';
X		} else
X		if (strcmp(name, "SHAP")==0) {
X			if (!desc->shap) {
X				if (!(desc->shap=(WORD*)malloc(2*sizeof(WORD))))
X					{ OUT_MEM("SHAP"); }
X				desc->shap[0] = 1;	/* TS defaults */
X				desc->shap[1] = 0;
X			}
X			parse_word(name, 4, 1);		/* Get field */
X			if		(strcmp(name, "SHAP")==0) desc->shap[0] = get_UWORD();
X			else if (strcmp(name, "LAMP")==0) desc->shap[1] = get_UWORD();
X			else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown SHAP field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "POSI")==0) {
X			if (!desc->posi) {
X				if (!(desc->posi=(XYZ_st*)malloc(sizeof(XYZ_st))))
X					{ OUT_MEM("POSI"); }
X			}
X			stuff_XYZ(desc->posi);
X		} else
X		if (strcmp(name, "AXIS")==0) {
X			if (!desc->axis) {
X				if (!(desc->axis=(AXIS*)malloc(sizeof(AXIS))))
X					{ OUT_MEM("AXIS"); }
X				bzero((char*)desc->axis, sizeof(AXIS));
X				desc->axis->xaxi.val[0] = 1;
X				desc->axis->yaxi.val[1] = 1;
X				desc->axis->zaxi.val[2] = 1;
X			}
X			parse_word(name, 4, 1);		/* Get field */
X			if		(strcmp(name, "XAXI")==0) stuff_XYZ(&desc->axis->xaxi);
X			else if (strcmp(name, "YAXI")==0) stuff_XYZ(&desc->axis->yaxi);
X			else if (strcmp(name, "ZAXI")==0) stuff_XYZ(&desc->axis->zaxi);
X			else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown AXIS field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "SIZE")==0) {
X			if (!desc->size) {
X				if (!(desc->size=(XYZ_st*)malloc(sizeof(XYZ_st))))
X					{ OUT_MEM("SIZE"); }
X			}
X			stuff_XYZ(desc->size);
X		} else
X		if (strcmp(name, "COLR")==0) {
X			if (!desc->colr) {
X				if (!(desc->colr = (RGB_st*)malloc(sizeof(RGB_st))))
X					{ OUT_MEM("COLR"); }
X			}
X			stuff_RGB((RGB_st*)&defclst[0]);
X			desc->colr->val[0] = defclst[0];
X			desc->colr->val[1] = defclst[1];
X			desc->colr->val[2] = defclst[2];
#ifdef DO_I_REALLY_WANT_TO_DO_THIS
X			if (desc->fcount) {	/* Already initialized... rewrite */
X				for (i=3*desc->fcount; i; ) {		/* Reverse - efficiency */
X					desc->clst[--i] = defclst[2];
X					desc->clst[--i] = defclst[1];
X					desc->clst[--i] = defclst[0];
X				}
X			}
#endif
X		} else
X		if (strcmp(name, "REFL")==0) {
X			if (!desc->refl) {
X				if (!(desc->refl = (RGB_st*)malloc(sizeof(RGB_st))))
X					{ OUT_MEM("REFL"); }
X			}
X			stuff_RGB((RGB_st*)&defrlst[0]);
X			desc->refl->val[0] = defrlst[0];
X			desc->refl->val[1] = defrlst[1];
X			desc->refl->val[2] = defrlst[2];
#ifdef DO_I_REALLY_WANT_TO_DO_THIS
X			if (desc->fcount) {	/* Already initialized... rewrite */
X				for (i=3*desc->fcount; i; ) {		/* Reverse - efficiency */
X					desc->rlst[--i] = defrlst[2];
X					desc->rlst[--i] = defrlst[1];
X					desc->rlst[--i] = defrlst[0];
X				}
X			}
#endif
X		} else
X		if (strcmp(name, "TRAN")==0) {
X			if (!desc->tran) {
X				if (!(desc->tran = (RGB_st*)malloc(sizeof(RGB_st))))
X					{ OUT_MEM("TRAN"); }
X			}
X			stuff_RGB((RGB_st*)&deftlst[0]);
X			desc->tran->val[0] = deftlst[0];
X			desc->tran->val[1] = deftlst[1];
X			desc->tran->val[2] = deftlst[2];
#ifdef DO_I_REALLY_WANT_TO_DO_THIS
X			if (desc->fcount) {	/* Already initialized... rewrite */
X				for (i=3*desc->fcount; i; ) {		/* Reverse - efficiency */
X					desc->tlst[--i] = deftlst[2];
X					desc->tlst[--i] = deftlst[1];
X					desc->tlst[--i] = deftlst[0];
X				}
X			}
#endif
X		} else
X		if (strcmp(name, "SPC1")==0) {
X			if (!desc->spc1) {
X				if (!(desc->spc1 = (RGB_st*)malloc(sizeof(RGB_st))))
X					{ OUT_MEM("SPC1"); }
X			}
X			stuff_RGB((RGB_st*)&defspc1[0]);
X			desc->spc1->val[0] = defspc1[0];
X			desc->spc1->val[1] = defspc1[1];
X			desc->spc1->val[2] = defspc1[2];
X		} else
X		if (strcmp(name, "TPAR")==0) {
X			if (!desc->tpar) {
X				if (!(desc->tpar=(double*)malloc(16*sizeof(double))))
X					{ OUT_MEM("TPAR"); }
X				bzero((char*)desc->tpar, 16*sizeof(double));
X			}
X			i = get_UWORD();
X			if (i<0 || i>15) {
X				fprintf(stderr, "WARNING: Line %d: Bad index: TPAR[%d] should be [0..15]\n", world->cur_line, i);
X				continue;
X			}
X			desc->tpar[i] = get_FRACT();
X		} else
X		if (strcmp(name, "SURF")==0) {
X			if (!desc->surf) {
X				if (!(desc->surf=(UBYTE*)malloc(5*sizeof(UBYTE))))
X					{ OUT_MEM("SURF"); }
X				bzero((char*)desc->surf, 5*sizeof(UBYTE));
X			}
X			i = get_UWORD();
X			if (i<0 || i>4) {
X				fprintf(stderr, "WARNING: Line %d: Bad index: SURF[%d] should be [0..4]\n", world->cur_line, i);
X				continue;
X			}
X			desc->surf[i] = get_UBYTE();
X		} else
X		if (strcmp(name, "MTTR")==0) {
X			if (!desc->mttr) {
X				if (!(desc->mttr=(MTTR*)malloc(sizeof(MTTR))))
X					{ OUT_MEM("MTTR"); }
X				bzero((char*)desc->mttr, sizeof(MTTR));
X			}
X			parse_word(name, 4, 1);		/* Get field */
X			if		(strcmp(name, "TYPE")==0) {
X				desc->mttr->type = get_UBYTE();
X				if (desc->mttr->type>4) {
X					fprintf(stderr, "WARNING: Line %d: Invalid MTTR refraction Type %d.  Must be [0..4]\n", world->cur_line, desc->mttr->type);
X					desc->mttr->type = 0;
X					continue;
X				}
X			} else if (strcmp(name, "INDE")==0) {	/* Must be between 1.0 and 3.55 inclusive */
X				desc->mttr->indx = get_FRACT();
X				if (desc->mttr->indx<1.0 || desc->mttr->indx>3.55) {
X					fprintf(stderr, "WARNING: Line %d: Invalid MTTR Index of refraction.  Must be (1.0 - 3.55)\n", world->cur_line);
X					desc->mttr->indx = 1.0;
X					continue;
X				}
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown MTTR field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "SPEC")==0) {
X			if (!desc->spec) {
X				if (!(desc->spec=(UBYTE*)malloc(2*sizeof(UBYTE))))
X					{ OUT_MEM("SPEC"); }
X				bzero((char*)desc->spec, 2*sizeof(UBYTE));
X			}
X			parse_word(name, 4, 1);		/* Get field */
X			if		(strcmp(name, "SPEC")==0) desc->spec[0] = get_UBYTE();
X			else if (strcmp(name, "HARD")==0) desc->spec[1] = get_UBYTE();
X			else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown SPEC field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "PRP0")==0) {
X			if (!desc->prp0) {
X				if (!(desc->prp0=(UBYTE*)malloc(6*sizeof(UBYTE))))
X					{ OUT_MEM("PRP0"); }
X				bzero((char*)desc->prp0, 6*sizeof(UBYTE));
X				desc->prp0[0] = 255;	/* TS defaults */
X				desc->prp0[3] = 1;
X			}
X			i = get_UWORD();
X			if (i<0 || i>5) {
X				fprintf(stderr, "WARNING: Line %d: Bad index: PRP0[%d] should be [0..5]\n", world->cur_line, i);
X				continue;
X			}
X			desc->prp0[i] = get_UBYTE();
X		} else
X		if (strcmp(name, "PRP1")==0) {
X			if (!desc->prp1) {
X				if (!(desc->prp1=(UBYTE*)malloc(8*sizeof(UBYTE))))
X					{ OUT_MEM("PRP1"); }
X				bzero((char*)desc->prp1, 8*sizeof(UBYTE));
X			}
X			i = get_UWORD();
X			if (i<0 || i>7) {
X				fprintf(stderr, "WARNING: Line %d: Bad index: PRP1[%d] should be [0..7]\n", world->cur_line, i);
X				continue;
X			}
X			desc->prp1[i] = get_UBYTE();
X		} else
X		if (strcmp(name, "INTS")==0) {
X			if (!desc->ints) {
X				if (!(desc->ints=(double*)malloc(sizeof(double))))
X					{ OUT_MEM("INTS"); }
X			}
X			*desc->ints = get_FRACT();
X		} else
X		if (strcmp(name, "INT1")==0) {
X			if (!desc->int1) desc->int1=(XYZ_st*)malloc(sizeof(XYZ_st));
X			if (!desc->int1) { OUT_MEM("INT1"); }
X			stuff_XYZ(desc->int1);
X		} else
X		if (strcmp(name, "STRY")==0) {
X			parse_word(name, 4, 1);		/* Get field */
X			if		(strcmp(name, "PATH")==0) parse_word(desc->stry->path,18,0);
X			else if (strcmp(name, "TRAN")==0) stuff_XYZ(&desc->stry->tran);
X			else if (strcmp(name, "ROTA")==0) stuff_XYZ(&desc->stry->rota);
X			else if (strcmp(name, "SCAL")==0) stuff_XYZ(&desc->stry->scal);
X			else
X			if (strcmp(name, "INFO")==0) {
X				desc->stry->info = 0;
X				while (strin[0]) {
X					parse_word(ps, 7, 1);
X					if		(strcmp(ps, "ABS_TRA")==0) desc->stry->info|=(1<<0);
X					else if (strcmp(ps, "ABS_ROT")==0) desc->stry->info|=(1<<1);
X					else if (strcmp(ps, "ABS_SCL")==0) desc->stry->info|=(1<<2);
X					else if (strcmp(ps, "LOC_TRA")==0) desc->stry->info|=(1<<4);
X					else if (strcmp(ps, "LOC_ROT")==0) desc->stry->info|=(1<<5);
X					else if (strcmp(ps, "LOC_SCL")==0) desc->stry->info|=(1<<6);
X					else if (strcmp(ps, "X_ALIGN")==0) desc->stry->info|=(1<<8);
X					else if (strcmp(ps, "Y_ALIGN")==0) desc->stry->info|=(1<<9);
X					else if (strcmp(ps, "Z_ALIGN")==0) desc->stry->info|=(1<<10);
X					else if (strcmp(ps, "FOLLOW_")==0) desc->stry->info|=(1<<12);
X					else {
#ifdef WARNING
X						fprintf(stderr, "WARNING: Line %d: Unknown STRY INFO flag: '%s'\n", world->cur_line, ps);
#endif
X						continue;
X					}
X				}
X			} else {
#ifdef WARNING
X				fprintf(stderr, "WARNING: Line %d: Unknown STRY field: '%s'\n", world->cur_line, name);
#endif
X				continue;
X			}
X		} else
X		if (strcmp(name, "END")==0) {
X			parse_word(name, 4, 1);
X			if (strcmp(name, "DESC")!=0)
X				fprintf(stderr, "WARNING: Line %d: Expected 'END DESC' but got: 'END %s'\n", world->cur_line, name);
X			parse_word(ps, 0, 0);	/* Get the quote, if any */
X			if (strcmp(this_level, ps)!=0)
X				fprintf(stderr, "WARNING: Line %d: 'DESC Begin' and 'End DESC' quoted comments do not match\n", world->cur_line);
X			break;
X		}
#ifdef WARNING
X		else fprintf(stderr, "WARNING: Line %d: Unknown DESC sub-sub-chunk: '%s'\n", world->cur_line, name);
#endif
X	}
}
X
SHAR_EOF
chmod 0644 read.c ||
echo 'restore of read.c failed'
Wc_c="`wc -c < 'read.c'`"
test 37860 -eq "$Wc_c" ||
	echo 'read.c: original size 37860, current size' "$Wc_c"
fi
# ============= readtddd.c ==============
if test -f 'readtddd.c' -a X"$1" != X"-c"; then
	echo 'x - skipping readtddd.c (File already exists)'
else
echo 'x - extracting readtddd.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'readtddd.c' &&
/* ReadTDDD.c - read a TDDD (Three Dimension Data Decription) file
X *            - and write a TTDDD text file with its contents
X *            - written by Glenn M. Lewis - 9/4/91
X */
X
static char rcs_id[] = "$Id: readtddd.c,v 1.18 1992/03/27 17:34:46 glewis Exp $";
X
#include <stdio.h>
#include <ctype.h>
#include "ttdddlib.h"
#define MAXLINE 132
X
int verbose_flag=0;
X
static void process_DESC();
static OBJECT *process_EXTR();
static void process_INFO();
static void process_OBJ();
X
/* Here are a few necessary utilities */
X
static void get_name(name, size, world)
register char  *name;
register int size;
WORLD *world;
{
X	while (size--) *name++ = fgetc(world->inp);
X	*name = '\0';
}
X
static BYTE get_BYTE(world)
WORLD *world;
{
X	return((BYTE)fgetc(world->inp));
}
X
static UBYTE get_UBYTE(world)
WORLD *world;
{
X	return((UBYTE)fgetc(world->inp));
}
X
static WORD get_WORD(world)
WORLD *world;
{
X	WORD tmp = (WORD)get_UBYTE(world)<<8;
X	return(tmp|get_UBYTE(world));
}
X
static UWORD get_UWORD(world)
WORLD *world;
{
X	UWORD tmp = (UWORD)get_UBYTE(world)<<8;
X	return(tmp|get_UBYTE(world));
}
X
static ULONG get_ULONG(world)
WORLD *world;
{
X	ULONG tmp = (ULONG)get_UWORD(world)<<16;
X	return(tmp|get_UWORD(world));
}
X
static float get_FRACT(world)	/* This sets the precision to 10^(-3) */
WORLD *world;
{
X	register float whole, fract;
X
X	whole =  (float)get_WORD(world);
X	fract = ((float)get_UWORD(world))/65536.0;
X	return((float)(whole+fract));
}
X
static void stuff_XYZ(st, world)
XXYZ_st *st;
WORLD *world;
{
X	st->val[0] = get_FRACT(world);
X	st->val[1] = get_FRACT(world);
X	st->val[2] = get_FRACT(world);
}
X
static void stuff_RGB(st, world)
RGB_st *st;
WORLD *world;
{
X	st->val[0] = get_UBYTE(world);
X	st->val[1] = get_UBYTE(world);
X	st->val[2] = get_UBYTE(world);
}
X
output_warning(world, area, name, size)
WORLD *world;
char *area, *name;
ULONG size;
{
X	ULONG i;
X	int j;
X	unsigned char tmpstr[20];
X
X	fprintf(stderr, "WARNING: Unknown %ssub-chunk: '%s', size %lu...\n",
X		area, name, size);
X	for (i=0; i<size; i+=16) {
X		fprintf(stderr, "%04lx:", i);
X		for (j=0; j<16 && i+j<size; j++)
X			fprintf(stderr, " %02x", tmpstr[j] = (fgetc(world->inp)&0xff));
X		while (j++ < 16) fputs("   ", stderr);
X		fputs("    ", stderr);
X		/* Print out the ASCII equivalent */
X		for (j=0; j<16 && i+j<size; j++) {
X			tmpstr[j] &= 0x7F;   /* Strip off upper bit */
X			if (isprint(tmpstr[j]))
X				fputc(tmpstr[j], stderr);
X			else fputc('.', stderr);
X		}
X		fputs("\n", stderr);
X	}
}
X
/********************/
/* The MAIN section */
/********************/
X
int already_read_header = 0;
unsigned char header_storage[13];
X
WORLD *read_World(file)
FILE *file;
{
X	int i;
X	for (i=0; i<4; i++) header_storage[i] = fgetc(file);
X	already_read_header = 4;
X	if (strncmp(header_storage, "FORM", 4)==0) {
X		while (i<12) header_storage[i++] = fgetc(file);
X		already_read_header = 12;
X		if (strncmp(&header_storage[8], "TDDD", 4)==0) return(read_TDDD(file));
X		/* BAD IFF */
X		header_storage[12] = 0;
X		fprintf(stderr, "ERROR! Unknown FORM: '%s'\n", &header_storage[8]);
X		return(0);
X	} else {
X		return(read_TTDDD(file));
X	}
}
X
WORLD *read_TDDD(file)
FILE *file;
{
X	register ULONG i, len, size;
X	WORLD *world;
X	char name[5];
X
X	if (!file) return(0L);	/* File not open */
X
X	if (!(world = (WORLD*)malloc(sizeof(WORLD)))) { OUT_MEM("WORLD"); }
X	bzero((char*)world, sizeof(WORLD));
X	world->inp = file;
X
X	if (!already_read_header) {
X		/* Parse the IFF TDDD file */
X		get_name(name, 4, world);
X		if (strcmp(name, "FORM") != 0) {
X			fprintf(stderr, "ERROR: Input is not an IFF file.\n"); exit(-1); }
X		if (!(len = get_ULONG(world))) {
X			fprintf(stderr, "ERROR: Bad FORM length in IFF file.\n"); exit(-1); }
X		get_name(name, 4, world);
X		if (strcmp(name, "TDDD") != 0) {
X			fprintf(stderr, "ERROR: IFF file is not a TDDD file.\n"); exit(-1); }
X	} else {
X		len =	(header_storage[4]<<24) | (header_storage[5]<<16) |
X				(header_storage[6]<< 8) | (header_storage[7]    );
X		already_read_header = 0;
X	}
X	len -= 4;
X
/* Here is the main loop: */
X	while (len>0) {
X		get_name(name, 4, world);
X		size = get_ULONG(world);
X		len -= 8;
X		if (strcmp(name, "INFO")==0) process_INFO(size, world);
X		else
X		if (strcmp(name, "OBJ ")==0) process_OBJ(size, world);
X		else {
X			if (verbose_flag) output_warning(world, "", name, size);
X			else {
X				for (i=size; i--; ) fgetc(world->inp);	/* Skip this section */
X			}
X		}
X		if ((size % 2) == 1) { fgetc(world->inp); len--; }	/* Skip odd byte */
X		len -= size;
X	}
X
/* All done. */
X	return(world);
}
X
static void process_INFO(len, world)
register ULONG len;
WORLD *world;
{
X	register INFO *info;
X	register ULONG i, size;
X	char name[5];
X
X	if (world->info) {
X		fputs("ERROR: More than one INFO chunk!\n", stderr); exit(-1); }
X	if (!(info = world->info = (INFO*)malloc(sizeof(INFO)))) { OUT_MEM("INFO"); }
X	bzero((char*)world->info, sizeof(INFO));
X
X	if (verbose_flag>1) fprintf(stderr, "INFO chunk.\n");
X	while (len>0) {
X		get_name(name, 4, world);
X		size = get_ULONG(world);
X		len -= 8;
X		if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
X		if (strcmp(name, "BRSH")==0) {
X			i = get_UWORD(world);
X			if (i<0 || i>7) { i=0; fputs("BRSH error.\n", stderr); }
X			get_name(info->brsh[i], 80, world);
X		} else
X		if (strcmp(name, "STNC")==0) {
X			i = get_UWORD(world);
X			if (i<0 || i>7) { i=0; fputs("STNC error.\n", stderr); }
X			get_name(info->stnc[i], 80, world);
X		} else
X		if (strcmp(name, "TXTR")==0) {
X			i = get_UWORD(world);
X			if (i<0 || i>7) { i=0; fputs("TXTR error.\n", stderr); }
X			get_name(info->txtr[i], 80, world);
X		} else
X		if (strcmp(name, "OBSV")==0) {
X			if (!info->obsv) info->obsv=(OBSV*)malloc(sizeof(OBSV));
X			if (!info->obsv) { OUT_MEM("OBSV"); }
X			stuff_XYZ(&info->obsv->came, world);
X			stuff_XYZ(&info->obsv->rota, world);
X			info->obsv->foca = get_FRACT(world);
X		} else
X		if (strcmp(name, "OTRK")==0) {
X			get_name(info->otrk, 18, world);
X		} else
X		if (strcmp(name, "OSTR")==0) {
X			if (!info->ostr) info->ostr=(STRY*)malloc(sizeof(STRY));
X			if (!info->ostr) { OUT_MEM("OSTR"); }
X			get_name(info->ostr->path, 18, world);
X			stuff_XYZ(&info->ostr->tran, world);
X			stuff_XYZ(&info->ostr->rota, world);
X			stuff_XYZ(&info->ostr->scal, world);
X			info->ostr->info = get_UWORD(world);
X		} else
X		if (strcmp(name, "FADE")==0) {
X			if (!info->fade) info->fade=(FADE*)malloc(sizeof(FADE));
X			if (!info->fade) { OUT_MEM("FADE"); }
X			info->fade->at = get_FRACT(world);
X			info->fade->by = get_FRACT(world);
X			fgetc(world->inp);		/* Skip a byte */
X			stuff_RGB(&info->fade->to, world);
X		} else
X		if (strcmp(name, "SKYC")==0) {
X			if (!info->skyc) info->skyc=(SKYC*)malloc(sizeof(SKYC));
X			if (!info->skyc) { OUT_MEM("SKYC"); }
X			fgetc(world->inp);		/* Skip a byte */
X			stuff_RGB(&info->skyc->hori, world);
X			fgetc(world->inp);		/* Skip a byte */
X			stuff_RGB(&info->skyc->zeni, world);
X		} else
X		if (strcmp(name, "AMBI")==0) {
X			if (!info->ambi) info->ambi=(RGB_st*)malloc(sizeof(RGB_st));
X			if (!info->ambi) { OUT_MEM("AMBI"); }
X			fgetc(world->inp);		/* Skip a byte */
X			stuff_RGB(info->ambi, world);
X		} else
X		if (strcmp(name, "GLB0")==0) {
X			if (!info->glb0) info->glb0=(BYTE*)malloc(8*sizeof(BYTE));
X			if (!info->glb0) { OUT_MEM("GLB0"); }
X			for (i=0; i<8; i++)
X				info->glb0[i] = get_UBYTE(world);
X		} else {
X			if (verbose_flag) output_warning(world, "INFO ", name, size);
X			else {
X				for (i=size; i--; ) fgetc(world->inp);	/* Skip this section */
X			}
X		}
X		if ((size % 2) == 1) { fgetc(world->inp); len--; }	/* Skip odd byte */
X		len -= size;
X	}
}
X
static void process_OBJ(len, world)
register ULONG len;
WORLD *world;
{
X	register ULONG i, size;
X	register OBJECT *p;
X	char name[5];
X	int depth=0;
X
X	if (verbose_flag>1) fprintf(stderr, "OBJ chunk.\n");
X	while (len>0) {
X		get_name(name, 4, world);
X		size = get_ULONG(world);
X		len -= 8;
X		if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
X		if (strcmp(name, "EXTR")==0) {
X			p = process_EXTR(size, create_object(), world);
X			if (world->curobj) {
X				world->curobj->next = p;
X				p->parent = world->curobj->parent;
X			} else {
X				world->object = p;
X				p->parent = 0;
X			}
X			world->curobj = p;
X		} else if (strcmp(name, "DESC")==0) {
X			p = create_object();
X			if (world->num_DESC > world->num_TOBJ+depth) {  /* This is a child */
X				depth++;    /* Down one in the hierarchy */
X				world->curobj->child = p;
X				p->parent = world->curobj;
X			} else {
X				if (world->curobj) {
X					world->curobj->next = p;
X					p->parent = world->curobj->parent;
X				} else {
X					world->object = p;
X					p->parent = 0;
X				}
X			}
X			world->curobj = p;
X			process_DESC(size, &p->desc, world);
X		} else if (strcmp(name, "TOBJ")==0) {
X			world->num_TOBJ++;
X			if (world->num_TOBJ > world->num_DESC) {
X				fprintf(stderr, "Warning: TOBJ without DESC.  Ignored.\n");
X			}
X			if (world->num_TOBJ+depth > world->num_DESC) {  /* Up a level */
X				depth--;
X				world->curobj=world->curobj->parent;
X			}
X		} else {
X			if (verbose_flag) output_warning(world, "OBJ ", name, size);
X			else {
X				for (i=size; i--; ) fgetc(world->inp);	/* Skip this section */
X			}
X		}
X		if ((size % 2) == 1) { fgetc(world->inp); len--; }	/* Skip odd byte */
X		len -= size;
X	}
}
X
static OBJECT *process_EXTR(len, obj, world)
register ULONG len;
OBJECT *obj;
WORLD *world;
{
X	register ULONG i, size;
X	register EXTR *extr;
X	register OBJECT *p;
X	char name[5];
X	MTRX *mtrx;
X	WORLD *new;
X	FILE *newinp;
X
X	if (!(extr = obj->extr = (EXTR*)malloc(sizeof(EXTR))))
X		{ OUT_MEM("EXTR"); }
X	bzero((char*)extr, sizeof(EXTR));
X	mtrx = &extr->mtrx;
X	/* Initialize structure */
X	mtrx->tran.val[0]  = mtrx->tran.val[1]  = mtrx->tran.val[2]  = 0.0;
X	mtrx->scal.val[0]  = mtrx->scal.val[1]  = mtrx->scal.val[2]  = 1.0;
X	mtrx->rota1.val[1] = mtrx->rota1.val[2] = 0.0;
X	mtrx->rota2.val[0] = mtrx->rota2.val[2] = 0.0;
X	mtrx->rota3.val[0] = mtrx->rota3.val[1] = 0.0;
X	mtrx->rota1.val[0] = mtrx->rota2.val[1] = mtrx->rota3.val[2] = 1.0;
X
X	if (verbose_flag>1) fprintf(stderr, "EXTR chunk.\n");
X	while (len>0) {
X		get_name(name, 4, world);
X		size = get_ULONG(world);
X		len -= 8;
X		if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
X		if (strcmp(name, "MTRX")==0) {
X			stuff_XYZ(&mtrx->tran, world);
X			stuff_XYZ(&mtrx->scal, world);
X			stuff_XYZ(&mtrx->rota1, world);
X			stuff_XYZ(&mtrx->rota2, world);
X			stuff_XYZ(&mtrx->rota3, world);
X		} else
X		if (strcmp(name, "LOAD")==0) {
X			get_name(extr->filename, 80, world);
X		} else {
X			if (verbose_flag) output_warning(world, "EXTR ", name, size);
X			else {
X				for (i=size; i--; ) fgetc(world->inp);	/* Skip this section */
X			}
X		}
X		if ((size % 2) == 1) { fgetc(world->inp); len--; }	/* Skip odd byte */
X		len -= size;
X	}
X	/* Now, load in the external object */
X	if (!(newinp=fopen(extr->filename, "r"))) {
X		fprintf(stderr, "Can't load in EXTR object: '%s'... ignored.\n",
X			extr->filename);
X		return(obj);
X	}
X	new = read_World(newinp);
X	fclose(newinp);
X	/* scale, rotate, and translate new object hierarchy */
X	for (p=new->object; p; p=p->next)
X		move_extr(p, mtrx);
X	/* Free up unused memory */
X	free((char*)obj->extr);
X	free((char*)obj);
X	obj = new->object;
X	free((char*)new);
X	return(obj);
}
X
static UBYTE defclst[3], defrlst[3], deftlst[3], defspc1[3];
X
static void malloc_arrays(i, desc)
register int i;
register DESC *desc;
{
X	if (!desc->fcount) {
X		desc->fcount = i;
if (!(desc->face=(UWORD*)malloc(3*desc->fcount*sizeof(UWORD))))OUT_MEM((char*)0);
if (!(desc->clst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
if (!(desc->rlst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
if (!(desc->tlst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
X		/* Initialize arrays */
X		for (i=0; i<3*desc->fcount; i+=3) {
X			desc->face[i]   = desc->face[i+1] = desc->face[i+2] = 0;
X			desc->clst[i]   = defclst[0];
X			desc->clst[i+1] = defclst[1];
X			desc->clst[i+2] = defclst[2];
X			desc->rlst[i]   = defrlst[0];
X			desc->rlst[i+1] = defrlst[1];
X			desc->rlst[i+2] = defrlst[2];
X			desc->tlst[i]   = deftlst[0];
X			desc->tlst[i+1] = deftlst[1];
X			desc->tlst[i+2] = deftlst[2];
X		}
X	} else if (i != desc->fcount) {
X		fprintf(stderr, "ERROR: FACE and [C|R|T]LST 'Count' values inconsistant.\n");
X		OUT_MEM((char*)0);
X	}
}
X
static void process_DESC(len, orig, world)
register ULONG len;
DESC **orig;
WORLD *world;
{
X	register ULONG size;
X	register DESC *desc;
X	register int i, j;
X	FGRP *fgrp;
X	char name[5];
X
X	if (!(desc = *orig = (DESC*)malloc(sizeof(DESC))))
X		{ OUT_MEM("DESC"); }
X	bzero((char*)desc, sizeof(DESC));
X
X	/* Set up defaults: */
X	defclst[0] = defclst[1] = defclst[2] = 240; /* TS default */
X	defrlst[0] = defrlst[1] = defrlst[2] = 0;
X	deftlst[0] = deftlst[1] = deftlst[2] = 0;
X	defspc1[0] = defspc1[1] = defspc1[2] = 0;
X
X	world->num_DESC++;
X
X	if (verbose_flag>1) fprintf(stderr, "DESC chunk.\n");
X	while (len>0) {
X		get_name(name, 4, world);
X		size = get_ULONG(world);
X		len -= 8;
X		if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
X		if (strcmp(name, "NAME")==0) {
X			get_name(desc->name, 18, world);
X		} else
X		if (strcmp(name, "SHAP")==0) {
X			if (!desc->shap) {
X				if (!(desc->shap=(WORD*)malloc(2*sizeof(WORD))))
X					{ OUT_MEM("SHAP"); }
X				desc->shap[0] = 1;  /* TS defaults */
X				desc->shap[1] = 0;
X			}
X			desc->shap[0] = get_UWORD(world);
X			desc->shap[1] = get_UWORD(world);
X		} else
X		if (strcmp(name, "POSI")==0) {
X			if (!desc->posi) {
X				if (!(desc->posi=(XYZ_st*)malloc(sizeof(XYZ_st))))
X					{ OUT_MEM("POSI"); }
X			}
X			stuff_XYZ(desc->posi, world);
X		} else
X		if (strcmp(name, "AXIS")==0) {
X			if (!desc->axis) {
X				if (!(desc->axis=(AXIS*)malloc(sizeof(AXIS))))
X					{ OUT_MEM("AXIS"); }
X				bzero((char*)desc->axis, sizeof(AXIS));
X				desc->axis->xaxi.val[0] = 1;
X				desc->axis->yaxi.val[1] = 1;
X				desc->axis->zaxi.val[2] = 1;
X			}
X			stuff_XYZ(&desc->axis->xaxi, world);
X			stuff_XYZ(&desc->axis->yaxi, world);
X			stuff_XYZ(&desc->axis->zaxi, world);
X		} else
X		if (strcmp(name, "SIZE")==0) {
X			if (!desc->size) {
X				if (!(desc->size=(XYZ_st*)malloc(sizeof(XYZ_st))))
X					{ OUT_MEM("SIZE"); }
X			}
X			stuff_XYZ(desc->size, world);
X		} else
X		if (strcmp(name, "PNTS")==0) {
X			i = desc->pcount = get_UWORD(world);	/* Number of points */
X			if (!(desc->pnts = (XYZ_st*)malloc(desc->pcount*sizeof(XYZ_st))))
X				OUT_MEM("PNTS");
X			for (j=0; j<i; j++)
X				{ stuff_XYZ(&desc->pnts[j], world); }
X		} else
X		if (strcmp(name, "EDGE")==0) {
X			i = desc->ecount = get_UWORD(world);	/* Number of edges */
X			if (!(desc->edge = (UWORD*)malloc(2*desc->ecount*sizeof(UWORD))))
X				OUT_MEM("EDGE");
X			for (j=0; j<2*i; j++)
X				{ desc->edge[j] = get_UWORD(world); }
X		} else
X		if (strcmp(name, "EFLG")==0) {
X			if (!(desc->eflg = (EFLG*)malloc(sizeof(EFLG))))
X				OUT_MEM("EFLG");
X			i = desc->eflg->num = get_UWORD(world);	/* Number of edge flags */
X			if (!(desc->eflg->eflg=(UBYTE*)malloc(desc->eflg->num*sizeof(UBYTE))))
X				OUT_MEM("EFLG");
X			for (j=0; j<i; j++)
X				{ desc->eflg->eflg[j] = get_UBYTE(world); }
X		} else
X		if (strcmp(name, "FACE")==0) {
X			i = get_UWORD(world);				/* Number of faces */
X			malloc_arrays(i, desc);
X			for (j=0; j<i; j++) {
X				desc->face[3*j]   = get_UWORD(world);
X				desc->face[3*j+1] = get_UWORD(world);
X				desc->face[3*j+2] = get_UWORD(world);
X			}
X		} else
X		if (strcmp(name, "FGRP")==0) {
X			if (!(fgrp = (FGRP*)malloc(sizeof(FGRP))))
X				OUT_MEM("FGRP");
X			i = fgrp->num = get_UWORD(world);	/* Number of faces in group */
X			if (!(fgrp->face = (UWORD*)malloc(i*sizeof(UWORD))))
X				OUT_MEM("FGRP");
X			get_name(fgrp->name, 18, world);
X			for (j=0; j<i; j++)
X				fgrp->face[j] = get_UWORD(world);
X			/* Link this new FGRP into list */
X			fgrp->next = desc->fgrp;
X			desc->fgrp = fgrp;
X		} else
X		if (strcmp(name, "COLR")==0) {
X			if (!desc->colr) {
X				if (!(desc->colr = (RGB_st*)malloc(sizeof(RGB_st))))
X					{ OUT_MEM("COLR"); }
X			}
X			fgetc(world->inp);			/* Must be zero */
X			stuff_RGB((RGB_st*)&defclst[0], world);
X			desc->colr->val[0] = defclst[0];
X			desc->colr->val[1] = defclst[1];
X			desc->colr->val[2] = defclst[2];
X		} else
X		if (strcmp(name, "REFL")==0) {
X			if (!desc->refl) {
X				if (!(desc->refl = (RGB_st*)malloc(sizeof(RGB_st))))
X					{ OUT_MEM("REFL"); }
X			}
X			fgetc(world->inp);			/* Must be zero */
X			stuff_RGB((RGB_st*)&defrlst[0], world);
X			desc->refl->val[0] = defrlst[0];
X			desc->refl->val[1] = defrlst[1];
X			desc->refl->val[2] = defrlst[2];
X		} else
X		if (strcmp(name, "TRAN")==0) {
X			if (!desc->tran) {
X				if (!(desc->tran = (RGB_st*)malloc(sizeof(RGB_st))))
X					{ OUT_MEM("TRAN"); }
X			}
X			fgetc(world->inp);			/* Must be zero */
X			stuff_RGB((RGB_st*)&deftlst[0], world);
X			desc->tran->val[0] = deftlst[0];
X			desc->tran->val[1] = deftlst[1];
X			desc->tran->val[2] = deftlst[2];
X		} else
X		if (strcmp(name, "SPC1")==0) {
X			if (!desc->spc1) {
X				if (!(desc->spc1 = (RGB_st*)malloc(sizeof(RGB_st))))
X					{ OUT_MEM("SPC1"); }
X			}
X			fgetc(world->inp);			/* Must be zero */
X			stuff_RGB((RGB_st*)&defspc1[0], world);
X			desc->spc1->val[0] = defspc1[0];
X			desc->spc1->val[1] = defspc1[1];
X			desc->spc1->val[2] = defspc1[2];
X		} else
X		if (strcmp(name, "CLST")==0) {
X			i = get_UWORD(world);		/* Number of faces */
X			malloc_arrays(i, desc);
X			for (j=0; j<i; j++)
X				{ stuff_RGB((RGB_st*)&desc->clst[3*j], world); }
X		} else
X		if (strcmp(name, "RLST")==0) {
X			i = get_UWORD(world);		/* Number of faces */
X			malloc_arrays(i, desc);
X			for (j=0; j<i; j++)
X				{ stuff_RGB((RGB_st*)&desc->rlst[3*j], world); }
X		} else
X		if (strcmp(name, "TLST")==0) {
X			i = get_UWORD(world);		/* Number of faces */
X			malloc_arrays(i, desc);
X			for (j=0; j<i; j++)
X				{ stuff_RGB((RGB_st*)&desc->tlst[3*j], world); }
X		} else
X		if (strcmp(name, "TPAR")==0) {
X			if (!desc->tpar) {
X				if (!(desc->tpar=(double*)malloc(16*sizeof(double))))
X					{ OUT_MEM("TPAR"); }
X				bzero((char*)desc->tpar, 16*sizeof(double));
X			}
X			for (i=0; i<16; i++)
X				desc->tpar[i] = get_FRACT(world);
X		} else
X		if (strcmp(name, "SURF")==0) {
X			if (!desc->surf) {
X				if (!(desc->surf=(UBYTE*)malloc(5*sizeof(UBYTE))))
X					{ OUT_MEM("SURF"); }
X				bzero((char*)desc->surf, 5*sizeof(UBYTE));
X			}
X			for (i=0; i<5; i++)
X				desc->surf[i] = get_BYTE(world);
X		} else
X		if (strcmp(name, "MTTR")==0) {
X			if (!desc->mttr) {
X				if (!(desc->mttr=(MTTR*)malloc(sizeof(MTTR))))
X					{ OUT_MEM("MTTR"); }
X				bzero((char*)desc->mttr, sizeof(MTTR));
X			}
X			desc->mttr->type = get_UBYTE(world);
X			desc->mttr->indx = (get_UBYTE(world)/100.0)+1.0;
X		} else
X		if (strcmp(name, "SPEC")==0) {
X			if (!desc->spec) {
X				if (!(desc->spec=(UBYTE*)malloc(2*sizeof(UBYTE))))
X					{ OUT_MEM("SPEC"); }
X				bzero((char*)desc->spec, 2*sizeof(UBYTE));
X			}
X			desc->spec[0] = get_UBYTE(world);
X			desc->spec[1] = get_UBYTE(world);
X		} else
X		if (strcmp(name, "PRP0")==0) {
X			if (!desc->prp0) {
X				if (!(desc->prp0=(UBYTE*)malloc(6*sizeof(UBYTE))))
X					{ OUT_MEM("PRP0"); }
X				bzero((char*)desc->prp0, 6*sizeof(UBYTE));
X			}
X			for (i=0; i<6; i++)
X				desc->prp0[i] = get_UBYTE(world);
X		} else
X		if (strcmp(name, "PRP1")==0) {
X			if (!desc->prp1) {
X				if (!(desc->prp1=(UBYTE*)malloc(8*sizeof(UBYTE))))
X					{ OUT_MEM("PRP1"); }
X				bzero((char*)desc->prp1, 8*sizeof(UBYTE));
X			}
X			for (i=0; i<8; i++)
X				desc->prp1[i] = get_UBYTE(world);
X		} else
X		if (strcmp(name, "INTS")==0) {
X			if (!desc->ints) {
X				if (!(desc->ints=(double*)malloc(sizeof(double))))
X					{ OUT_MEM("INTS"); }
X			}
X			*desc->ints = get_FRACT(world);
X		} else
X		if (strcmp(name, "INT1")==0) {
X			if (!desc->int1) desc->int1=(XYZ_st*)malloc(sizeof(XYZ_st));
X			if (!desc->int1) { OUT_MEM("INT1"); }
X			stuff_XYZ(desc->int1, world);
X		} else
X		if (strcmp(name, "STRY")==0) {
X			get_name(desc->stry->path, 18, world);
X			stuff_XYZ(&desc->stry->tran, world);
X			stuff_XYZ(&desc->stry->rota, world);
X			stuff_XYZ(&desc->stry->scal, world);
X			desc->stry->info = get_UWORD(world);
X		} else {
X			if (verbose_flag) output_warning(world, "DESC ", name, size);
X			else {
X				for (i=size; i--; ) fgetc(world->inp);	/* Skip this section */
X			}
X		}
X		if ((size % 2) == 1) { fgetc(world->inp); len--; }	/* Skip odd byte */
X		len -= size;
X	}
}
X
SHAR_EOF
chmod 0644 readtddd.c ||
echo 'restore of readtddd.c failed'
Wc_c="`wc -c < 'readtddd.c'`"
test 20014 -eq "$Wc_c" ||
	echo 'readtddd.c: original size 20014, current size' "$Wc_c"
fi
# ============= readwrite.c ==============
if test -f 'readwrite.c' -a X"$1" != X"-c"; then
	echo 'x - skipping readwrite.c (File already exists)'
else
echo 'x - extracting readwrite.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'readwrite.c' &&
/* readwrite.c - written by Glenn M. Lewis - 10/91
X * convert external Turbo Silver objects into "internal" Imagine objects
X * with optional "merge" feature
X */
X
static char rcs_id[] = "$Id: readwrite.c,v 1.1 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
WORLD *world;
extern int verbose_flag;
char infile[128], outfile[128];
X
main(argc, argv)
int argc;
char *argv[];
{
X	int i, merge_flag, tddd_flag;
X	FILE *inp, *out, *fopen();
X
X	merge_flag = 0;
X	verbose_flag = 0;
X	tddd_flag = 0;
X	infile[0] = outfile[0] = '\0';
X	inp = stdin;
X	out = stdout;
X	for (i=1; i<argc; i++) {
X		if (argv[i][0] == '-') {
X			switch(argv[i][1]) {
X				case 'm': merge_flag = 1; break;
X				case 'v': verbose_flag = 1; break;
X				case 'V': verbose_flag = 2; break;
X				case 't': tddd_flag = 1; break;
X				default: 
USAGE:
X					fprintf(stderr,"Usage: %s [-tddd] [-m] [obj_in] [obj_out]\n",
X						argv[0]);
X					exit(-1);
X			}
X		} else if (!infile[0]) {
X			strcpy(infile, argv[i]);
X			if (!(inp = fopen(infile, "r"))) {
X				fprintf(stderr, "Can't open '%s' for input.\n", infile);
X				exit(-1);
X			}
X		} else if (!outfile[0]) {
X			strcpy(outfile, argv[i]);
X			if (!(out = fopen(outfile, "w"))) {
X				fprintf(stderr, "Can't open '%s' for output.\n", outfile);
X				exit(-1);
X			}
X		} else goto USAGE;
X	}
X	if (!(world = read_World(inp))) {
X		fprintf(stderr, "No object to process.\n");
X		exit(-1);
X	}
X	if (merge_flag) merge_World(world);
X	if (tddd_flag)
X		write_TDDD(world, out);
X	else
X		write_TTDDD(world, out);
X	free_World(world);
X	exit(0);
}
X
SHAR_EOF
chmod 0644 readwrite.c ||
echo 'restore of readwrite.c failed'
Wc_c="`wc -c < 'readwrite.c'`"
test 1543 -eq "$Wc_c" ||
	echo 'readwrite.c: original size 1543, current size' "$Wc_c"
fi
# ============= sort.c ==============
if test -f 'sort.c' -a X"$1" != X"-c"; then
	echo 'x - skipping sort.c (File already exists)'
else
echo 'x - extracting sort.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'sort.c' &&
/* sort.c - Shell-Metzner sort algorithm implemented by Glenn M. Lewis - 7/26/91
X */
X
#include <stdio.h>
#include "ttdddlib.h"
X
static char rcs_id[] = "$Id: sort.c,v 1.3 1991/09/05 17:51:13 glewis Exp $";
X
void swap_points(desc, p1, p2)
register DESC *desc;
register int p1, p2;
{
X	register UWORD *edge;
X	register int i;
X	XYZ_st tmp;
X	if (p1==p2) return;
X	for (edge=desc->edge,i=2*desc->ecount; i--; edge++) {
X		if (*edge==p1) *edge=p2;
X		else if (*edge==p2) *edge=p1;
X	}
X	bcopy((char*)&desc->pnts[p1], (char*)&tmp, sizeof(XYZ_st));
X	bcopy((char*)&desc->pnts[p2], (char*)&desc->pnts[p1], sizeof(XYZ_st));
X	bcopy((char*)&tmp, (char*)&desc->pnts[p2], sizeof(XYZ_st));
}
X
void sort_points(desc, cmp)	/* Sort the boxes w/ Shell-Metzner algorithm */
register DESC *desc;
int (*cmp)();
{
X	register int i, j, gap;
X
/* Sort the puppies! */
X
X	if (desc->pcount <= 1) return;
X	for (gap = desc->pcount/2; gap>0; gap/=2)
X		for (i=gap; i<desc->pcount; i++)
X			for (j=i-gap; j>=0; j-=gap) {
X				if (cmp(&desc->pnts[j], &desc->pnts[j+gap])<0) break;
X				/* Swap the points */
X				swap_points(desc, j, j+gap);
X			}
}
X
SHAR_EOF
chmod 0644 sort.c ||
echo 'restore of sort.c failed'
Wc_c="`wc -c < 'sort.c'`"
test 1101 -eq "$Wc_c" ||
	echo 'sort.c: original size 1101, current size' "$Wc_c"
fi
# ============= tddd2dxf.c ==============
if test -f 'tddd2dxf.c' -a X"$1" != X"-c"; then
	echo 'x - skipping tddd2dxf.c (File already exists)'
else
echo 'x - extracting tddd2dxf.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tddd2dxf.c' &&
/* tddd2dxf.c - convert TDDD (or TTDDD) file to DXF file
X *            - written by Glenn M. Lewis - 10/29/91
X */
X
static char rcs_id[] = "$Id: tddd2dxf.c,v 1.1 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
main(argc, argv)
int argc;
char *argv[];
{
X	char filename[256], rootname[256], *c1, *c2;
X	int i;
X	WORLD *world;
X	FILE *inp, *out;
X
X	filename[0] = '\0';
X	rootname[0] = '\0';
X	for (i=1; i<argc; i++) {
X		if (argv[i][0] == '-') {
X			fprintf(stderr, "Unknown option '%s' ignored.\n", argv[i]);
X		} else if (filename[0]) {
X			strcpy(rootname, argv[i]);
X		} else {
X			strcpy(filename, argv[i]);	/* Make root of filename the default */
X			for (c1=rootname,c2=argv[i]; (*c1 = *c2++) && *c1!='.'; c1++) ;
X			*c1 = '\0';
X			strcat(rootname, ".dxf");
X		}
X	}
X
X	if (!filename[0]) inp = stdin;
X	else if (!(inp = fopen(filename, "r"))) {
X		fprintf(stderr, "Can't open '%s' for input.\n", filename);
X		exit(-1);
X	}
X	if (!rootname[0]) out = stdout;
X	else if (!(out = fopen(rootname, "w"))) {
X		fprintf(stderr, "Can't open '%s' for output.\n", rootname);
X		exit(-1);
X	}
X
X	world = read_World(inp);
X	write_DXF(world, out);
X	free_World(world);
X	exit(0);
}
X
SHAR_EOF
chmod 0644 tddd2dxf.c ||
echo 'restore of tddd2dxf.c failed'
Wc_c="`wc -c < 'tddd2dxf.c'`"
test 1174 -eq "$Wc_c" ||
	echo 'tddd2dxf.c: original size 1174, current size' "$Wc_c"
fi
# ============= tddd2mif.c ==============
if test -f 'tddd2mif.c' -a X"$1" != X"-c"; then
	echo 'x - skipping tddd2mif.c (File already exists)'
else
echo 'x - extracting tddd2mif.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tddd2mif.c' &&
/* tomif.c - convert TTDDD file to FrameMaker MIF format
X *         - written by Glenn M. Lewis - 7/24/91
X */
X
static char rcs_id[] = "$Id: tddd2mif.c,v 1.2 1991/12/04 07:03:28 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
WORLD *world;
X
main()
{
X	world = read_World(stdin);
X	write_MIF(world, stdout, VIEW_ALL_FOUR);
X	free_World(world);
X	exit(0);
}
X
SHAR_EOF
chmod 0644 tddd2mif.c ||
echo 'restore of tddd2mif.c failed'
Wc_c="`wc -c < 'tddd2mif.c'`"
test 362 -eq "$Wc_c" ||
	echo 'tddd2mif.c: original size 362, current size' "$Wc_c"
fi
# ============= tddd2nff.c ==============
if test -f 'tddd2nff.c' -a X"$1" != X"-c"; then
	echo 'x - skipping tddd2nff.c (File already exists)'
else
echo 'x - extracting tddd2nff.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tddd2nff.c' &&
/* tddd2nff.c - convert TDDD (or TTDDD) file to NFF file
X *            - written by Glenn M. Lewis - 10/29/91
X */
X
static char rcs_id[] = "$Id: tddd2nff.c,v 1.4 1991/12/04 07:03:28 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
main(argc, argv)
int argc;
char *argv[];
{
X	char filename[256], rootname[256], *c1, *c2;
X	int i;
X	WORLD *world;
X	FILE *inp, *out;
X
X	filename[0] = '\0';
X	rootname[0] = '\0';
X	for (i=1; i<argc; i++) {
X		if (argv[i][0] == '-') {
X			fprintf(stderr, "Unknown option '%s' ignored.\n", argv[i]);
X		} else if (filename[0]) {
X			strcpy(rootname, argv[i]);
X		} else {
X			strcpy(filename, argv[i]);	/* Make root of filename the default */
X			for (c1=rootname,c2=argv[i]; (*c1 = *c2++) && *c1!='.'; c1++) ;
X			*c1 = '\0';
X			strcat(rootname, ".nff");
X		}
X	}
X
X	if (!filename[0]) inp = stdin;
X	else if (!(inp = fopen(filename, "r"))) {
X		fprintf(stderr, "Can't open '%s' for input.\n", filename);
X		exit(-1);
X	}
X	if (!rootname[0]) out = stdout;
X	else if (!(out = fopen(rootname, "w"))) {
X		fprintf(stderr, "Can't open '%s' for output.\n", rootname);
X		exit(-1);
X	}
X
X	world = read_World(inp);
X	write_NFF(world, out);
X	free_World(world);
X	exit(0);
}
X
SHAR_EOF
chmod 0644 tddd2nff.c ||
echo 'restore of tddd2nff.c failed'
Wc_c="`wc -c < 'tddd2nff.c'`"
test 1174 -eq "$Wc_c" ||
	echo 'tddd2nff.c: original size 1174, current size' "$Wc_c"
fi
# ============= tddd2off.c ==============
if test -f 'tddd2off.c' -a X"$1" != X"-c"; then
	echo 'x - skipping tddd2off.c (File already exists)'
else
echo 'x - extracting tddd2off.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tddd2off.c' &&
/* tddd2off.c - convert TDDD (or TTDDD) file to OFF file
X *            - written by Glenn M. Lewis - 10/29/91
X */
X
static char rcs_id[] = "$Id: tddd2off.c,v 1.3 1991/12/04 07:03:28 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
main(argc, argv)
int argc;
char *argv[];
{
X	char filename[256], rootname[256], *c1, *c2;
X	int i;
X	WORLD *world;
X	FILE *inp;
X	int split = 0, geom_only = 0;
X
X	filename[0] = '\0';
X	strcpy(rootname, "model");	/* The default for reading stdin */
X	for (i=1; i<argc; i++) {
X		if (argv[i][0] == '-') {
X			switch(argv[i][1]) {
X				case 's':	split = 1; break;
X				case 'g':	geom_only = 1; break;
X				case 'h':
X				default:
X		fprintf(stderr, "Usage: %s [-geom_only] [-split] [infile] [outfile]\n",
X				argv[0]);
X				exit(-1);
X			}
X		} else if (filename[0]) {
X			strcpy(rootname, argv[i]);
X		} else {
X			strcpy(filename, argv[i]);	/* Make root of filename the default */
X			for (c1=rootname,c2=argv[i]; (*c1 = *c2++) && *c1!='.'; c1++) ;
X			*c1 = '\0';
X		}
X	}
X
X	if (!filename[0]) inp = stdin;
X	else if (!(inp = fopen(filename, "r"))) {
X		fprintf(stderr, "Can't open '%s' for input.\n", filename);
X		exit(-1);
X	}
X
X	world = read_World(inp);
X	write_OFF(world, rootname, split, geom_only);
X	free_World(world);
X	exit(0);
}
X
SHAR_EOF
chmod 0644 tddd2off.c ||
echo 'restore of tddd2off.c failed'
Wc_c="`wc -c < 'tddd2off.c'`"
test 1246 -eq "$Wc_c" ||
	echo 'tddd2off.c: original size 1246, current size' "$Wc_c"
fi
# ============= tddd2pov.c ==============
if test -f 'tddd2pov.c' -a X"$1" != X"-c"; then
	echo 'x - skipping tddd2pov.c (File already exists)'
else
echo 'x - extracting tddd2pov.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tddd2pov.c' &&
/* tddd2pov.c - convert TTDDD file to POVRay 1.0 input file
X *            - written by Glenn M. Lewis - 7/27/92
X */
X
static char rcs_id[] = "$Id: tddd2pov.c,v 1.1 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
WORLD *world;
X
main()
{
X	world = read_World(stdin);
X	write_POVRay(world, stdout);
X	free_World(world);
X	exit(0);
}
X
SHAR_EOF
chmod 0644 tddd2pov.c ||
echo 'restore of tddd2pov.c failed'
Wc_c="`wc -c < 'tddd2pov.c'`"
test 356 -eq "$Wc_c" ||
	echo 'tddd2pov.c: original size 356, current size' "$Wc_c"
fi
# ============= tddd2ps.c ==============
if test -f 'tddd2ps.c' -a X"$1" != X"-c"; then
	echo 'x - skipping tddd2ps.c (File already exists)'
else
echo 'x - extracting tddd2ps.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tddd2ps.c' &&
/* tddd2ps.c - convert TTDDD file to PostScript viewing format
X *           - written by Glenn M. Lewis - 7/22/91
X */
X
static char rcs_id[] = "$Id: tddd2ps.c,v 1.2 1991/12/04 07:03:28 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
WORLD *world;
X
main()
{
X	world = read_World(stdin);
X	write_PostScript(world, stdout, VIEW_ALL_FOUR);
X	free_World(world);
X	exit(0);
}
X
SHAR_EOF
chmod 0644 tddd2ps.c ||
echo 'restore of tddd2ps.c failed'
Wc_c="`wc -c < 'tddd2ps.c'`"
test 376 -eq "$Wc_c" ||
	echo 'tddd2ps.c: original size 376, current size' "$Wc_c"
fi
# ============= tddd2ray.c ==============
if test -f 'tddd2ray.c' -a X"$1" != X"-c"; then
	echo 'x - skipping tddd2ray.c (File already exists)'
else
echo 'x - extracting tddd2ray.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tddd2ray.c' &&
/* tddd2ray.c - convert TTDDD file to Rayshade 4.0 input file
X *            - written by Glenn M. Lewis - 7/22/91
X */
X
static char rcs_id[] = "$Id: tddd2ray.c,v 1.2 1991/12/04 07:03:28 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
WORLD *world;
X
main()
{
X	world = read_World(stdin);
X	write_Rayshade(world, stdout);
X	free_World(world);
X	exit(0);
}
X
SHAR_EOF
chmod 0644 tddd2ray.c ||
echo 'restore of tddd2ray.c failed'
Wc_c="`wc -c < 'tddd2ray.c'`"
test 360 -eq "$Wc_c" ||
	echo 'tddd2ray.c: original size 360, current size' "$Wc_c"
fi
# ============= tddd2vort.c ==============
if test -f 'tddd2vort.c' -a X"$1" != X"-c"; then
	echo 'x - skipping tddd2vort.c (File already exists)'
else
echo 'x - extracting tddd2vort.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tddd2vort.c' &&
/* tddd2vort.c - convert TTDDD file to Vort input file
X *             - written by Glenn M. Lewis - 10/11/91
X */
X
static char rcs_id[] = "$Id: tddd2vort.c,v 1.2 1991/12/04 07:03:28 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
WORLD *world;
X
main()
{
X	world = read_World(stdin);
X	write_Vort(world, stdout);
X	free_World(world);
X	exit(0);
}
X
SHAR_EOF
chmod 0644 tddd2vort.c ||
echo 'restore of tddd2vort.c failed'
Wc_c="`wc -c < 'tddd2vort.c'`"
test 352 -eq "$Wc_c" ||
	echo 'tddd2vort.c: original size 352, current size' "$Wc_c"
fi
# ============= ttdddlib.h ==============
if test -f 'ttdddlib.h' -a X"$1" != X"-c"; then
	echo 'x - skipping ttdddlib.h (File already exists)'
else
echo 'x - extracting ttdddlib.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'ttdddlib.h' &&
/* ttdddlib.h - definitions needed to interface to TTDDD library
X *            - written by Glenn M. Lewis - 7/19/91
X * $Id: ttdddlib.h,v 1.16 1992/03/27 17:28:31 glewis Exp $
X */
X
#ifdef AMIGA
X
/* The following has been tested using SAS/C on an Amiga by Helge Rasmussen */
#include <string.h>
#include <stdlib.h>
#define  bcopy(s,d,n)	(void)memcpy((d),(s),(n))
#define  bzero(d,n)		(void)memset((d),0,(n))
#define  bcmp(b1,b2,n)	memcmp((b1),(b2),(n))
#define  index			strchr
#define  rindex			strrchr
X
#else
X
#include <strings.h>
#include <malloc.h>
char *calloc();
X
#endif
X
#ifdef SYSV
extern char *memcpy(), *memset();
#define bcopy(s,d,n)	(void)memcpy((d),(s),(n))
#define bzero(d,n)		(void)memset((d),0,(n))
#define bcmp(b1,b2,n)	memcmp((b1),(b2),(n))
#define index			strchr
#define rindex			strrchr
#endif
X
#ifndef UBYTE
#define UBYTE unsigned char
#endif
#ifndef BYTE
#define BYTE char
#endif
X
#ifndef UWORD
#define UWORD unsigned short
#endif
#ifndef WORD
#define WORD short
#endif
X
#ifndef ULONG
#define ULONG unsigned long
#endif
#ifndef LONG
#define LONG long
#endif
X
typedef struct { double val[3]; } XYZ_st;
typedef struct { UBYTE val[3];  } RGB_st;
typedef struct { XYZ_st came, rota; double foca; } OBSV;
typedef struct { double at, by; RGB_st to; } FADE;
typedef struct { RGB_st hori, zeni; } SKYC;
typedef char BRSH[81];
typedef struct { XYZ_st tran, scal, rota1, rota2, rota3; } MTRX;
typedef struct { XYZ_st xaxi, yaxi, zaxi; } AXIS;
typedef struct { char path[19]; XYZ_st tran, rota, scal; UWORD info; } STRY;
typedef struct {
X	MTRX mtrx;
X	char filename[81];
} EXTR;
typedef struct {
X	UBYTE type;
X	float indx;
} MTTR;
struct OBJECT {
X	EXTR *extr;	/* Either EXTR or DESC */
X	struct DESC *desc;
X	struct OBJECT *parent;	/* whose child this OBJECT is */
X	struct OBJECT *child;	/* children of this OBJECT - not for EXTR */
X	struct OBJECT *next;	/* At this level in the hierarchy */
X	void *user;		/* User-defined data for any purpose */
};
typedef struct OBJECT OBJECT;
typedef struct {
X	UWORD num;
X	UBYTE *eflg;
} EFLG;
struct FGRP {
X	struct FGRP *next;	/* Linked list */
X	UWORD num;
X	char name[19];	/* 18 allowed in file */
X	UWORD *face;
};
typedef struct FGRP FGRP;
typedef struct DESC {
X	char name[19];
X	WORD *shap;
X	XYZ_st *posi;
X	AXIS *axis;
X	XYZ_st *size;
X	XYZ_st *pnts;
X	RGB_st *colr, *refl, *tran, *spc1;
X	UWORD *edge, *face, pcount, ecount, fcount; 
X	UBYTE *clst, *rlst, *tlst;
X	double *tpar;
X	UBYTE *surf;
X	MTTR  *mttr;
X	UBYTE *spec;
X	UBYTE *prp0, *prp1;
X	double *ints;
X	XYZ_st *int1;
X	STRY *stry;
X	FGRP *fgrp;
X	EFLG *eflg;
} DESC;
X
extern UBYTE defclst[3], defrlst[3], deftlst[3], defspc1[3];
X
#define STNC BRSH
#define TXTR BRSH
typedef struct {
X	BRSH brsh[8];
X	STNC stnc[8];
X	TXTR txtr[8];
X	OBSV *obsv;
X	BYTE otrk[19];
X	STRY *ostr;
X	FADE *fade;
X	SKYC *skyc;
X	RGB_st *ambi;
X	BYTE *glb0;
} INFO;
X
typedef struct {
X	INFO *info;			/* The INFO description in the file */
X	OBJECT *object;		/* The first object in the world */
X	void *user;		/* User-defined data for any purpose */
X	/* Some private variables needed to parse input file - don't touch! */
X	int num_OBJ, num_DESC, num_TOBJ, cur_line;
X	FILE *inp;
X	OBJECT *curobj;
} WORLD;
X
typedef struct {
X	double minx, maxx, miny, maxy, minz, maxz;
} MBB;
X
WORLD *read_World();	/* world = read_World(FILE *); ..figures out format */
WORLD *free_World();	/* world = free_World(world *);   ...frees a WORLD* */
void merge_World();		/* merge_World(world *); ..optimizes points & edges */
WORLD *read_TTDDD();	/* world = read_TTDDD(FILE *);      ...0 on failure */
WORLD *read_TDDD();		/* world = read_TDDD(FILE *);       ...0 on failure */
int write_TTDDD();		/* write_TTDDD(world *, FILE *);    ...0 on failure */
int write_TDDD();		/* write_TDDD(world *, FILE *);     ...0 on failure */
int write_Rayshade();	/* write_Rayshade(world *, FILE *); ...0 on failure */
int write_PostScript();	/* write_PostScript(world *, FILE *, view); ..ditto */
int write_MIF();		/* write_MIF(world *, FILE *, view); ..0 on failure */
void calculate_MBB_world();	/* calculate_MBB_world(WORLD *); */
void calculate_MBB();	/* calculate_MBB(OBJECT *); */
OBJECT *linear_morph();	/* linear_morph(obj1, obj2, time); /* 0.0<=time<=1.0 */
OBJECT *create_object();/* p = create_object(); */
int count_objects();	/* Used by "morph()" */
int morph();			/* morph(world1, world2, num, name, morph_function); */
void free_desc();		/* free_desc(DESC *); */
void match_points();	/* match_points(numpoints, obj1, obj2); */
void sort_points();		/* sort_points(obj1); */
int cmpXYZ();			/* comparison for sort_points */
void move_extr();
void OUT_MEM();
X
/* Some stuff for PostScript and MIF output */
extern double XSIZE, YSIZE;	/* (in inches) Default: 8.5x11.0 */
X
#define VIEW_TOP	0	/* eye at (0,0,+inf) */
#define VIEW_FRONT	1	/* eye at (0,-inf,0) */
#define VIEW_ISO	2	/* eye at (+inf,-inf,+inf) */
#define VIEW_RIGHT	3	/* eye at (+inf,0,0) */
#define VIEW_ALL_FOUR 4	/* Place all on the same page */
X
SHAR_EOF
chmod 0644 ttdddlib.h ||
echo 'restore of ttdddlib.h failed'
Wc_c="`wc -c < 'ttdddlib.h'`"
test 4938 -eq "$Wc_c" ||
	echo 'ttdddlib.h: original size 4938, current size' "$Wc_c"
fi
# ============= write.c ==============
if test -f 'write.c' -a X"$1" != X"-c"; then
	echo 'x - skipping write.c (File already exists)'
else
echo 'x - extracting write.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'write.c' &&
/* write.c - dump the internal database to a TTDDD file
X *         - written by Glenn M. Lewis - 7/19/91
X */
X
static char rcs_id[] = "$Id: write.c,v 1.11 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include <ctype.h>
#include "ttdddlib.h"
X
static void process_DESC();
static void process_EXTR();
static void process_INFO();
static void process_OBJ();
X
/* Two-space tabs */
#define TABSTOP "  "
X
static FILE *out;
static char tab[133], strin[133];
static int num_OBJ, num_DESC, num_TOBJ;
static int cur_level, cur_objnum;
static int prntline;
X
static struct save_hier {
X	int objnum;
X	struct save_hier *next;
} *root = 0;
typedef struct save_hier HIER;
X
/* Here are a few necessary utilities */
X
static void indent()
{
X	strcat(tab, TABSTOP);
}
X
static void outdent()
{
X	register int i = strlen(tab) - strlen(TABSTOP);
X	if (i<0) {
X		fprintf(stderr, "Whoa, Glenn!  You blew it!\n");
X		tab[0] = '\0';
X		return;
X	}
X	tab[i] = '\0';
}
X
static void send_XYZ(f)			/* Print a common string */
XXYZ_st *f;
{
/* I noticed that with a Ultrix C compiler, these in-line function calls were
X * not executed in the order specified.  Since I want this code to be portable,
X * and since some C compilers are broken, I seperated the following lines.
X * This goes for *all* in-line function calls in this source code.
X */
X	fprintf(out, " X=%g",   f->val[0]);
X	fprintf(out, " Y=%g",   f->val[1]);
X	fprintf(out, " Z=%g\n", f->val[2]);
}
X
static void send_RGB(rgb)			/* Print a common string */
RGB_st *rgb;
{
X	fprintf(out, " R=%u",   rgb->val[0]);
X	fprintf(out, " G=%u",   rgb->val[1]);
X	fprintf(out, " B=%u\n", rgb->val[2]);
}
X
/********************/
/* The MAIN section */
/********************/
X
int write_TTDDD(world, file)
WORLD *world;
FILE *file;
{
X	register OBJECT *o;
X
X	if (!(out=file) || !world) return(0);	/* File not open */
X
X	tab[0] = '\0';
X	num_OBJ = num_DESC = num_TOBJ = 0;
X
X	fputs("% TTDDD library - Written by Glenn M. Lewis - 7/19/91\n\n", out);
X	if (world->info) process_INFO(world->info);
X	for (o=world->object; o; o=o->next)
X		process_OBJ(o);
X	return(1);
}
X
static void process_INFO(info)
INFO *info;
{
X	register int i;
X
X	fprintf(out, "%sINFO Begin\n", tab);
X	indent();
X	for (i=0; i<8; i++)
X		if (info->brsh[i][0])
X			fprintf(out, "%sBRSH[%d]=\"%s\"\n", tab, i, info->brsh[i]);
X
X	for (i=0; i<8; i++)
X		if (info->stnc[i][0])
X			fprintf(out, "%sSTNC[%d]=\"%s\"\n", tab, i, info->stnc[i]);
X
X	for (i=0; i<8; i++)
X		if (info->txtr[i][0])
X			fprintf(out, "%sTXTR[%d]=\"%s\"\n", tab, i, info->txtr[i]);
X
X	if (info->obsv) {
X		fprintf(out, "%sOBSV Camera", tab); send_XYZ(&info->obsv->came);
X		fprintf(out, "%sOBSV Rotate", tab); send_XYZ(&info->obsv->rota);
X		fprintf(out, "%sOBSV Focal  %g\n", tab, info->obsv->foca);
X	}
X
X	if (info->otrk[0]) fprintf(out, "%sOTRK \"%s\"\n", tab, info->otrk);
X
X	if (info->ostr) {
X		if (info->ostr->path[0])
X			fprintf(out, "%sOSTR Path \"%s\"\n", tab, info->ostr->path);
X		fprintf(out, "%sOSTR Translate", tab); send_XYZ(&info->ostr->tran);
X		fprintf(out, "%sOSTR Rotate   ", tab); send_XYZ(&info->ostr->rota);
X		fprintf(out, "%sOSTR Scale    ", tab); send_XYZ(&info->ostr->scal);
X		i = info->ostr->info;
X		strin[0] = '\0';
X		if (i&(1<<0))  strcat(strin, " ABS_TRA");
X		if (i&(1<<1))  strcat(strin, " ABS_ROT");
X		if (i&(1<<2))  strcat(strin, " ABS_SCL");
X		if (i&(1<<4))  strcat(strin, " LOC_TRA");
X		if (i&(1<<5))  strcat(strin, " LOC_ROT");
X		if (i&(1<<6))  strcat(strin, " LOC_SCL");
X		if (i&(1<<8))  strcat(strin, " X_ALIGN");
X		if (i&(1<<9))  strcat(strin, " Y_ALIGN");
X		if (i&(1<<10)) strcat(strin, " Z_ALIGN");
X		if (i&(1<<12)) strcat(strin, " FOLLOW_ME");
X		fprintf(out, "%sOSTR Info%s\n", tab, strin);
X	}
X
X	if (info->fade) {
X		fprintf(out, "%sFADE FadeAt %g\n", tab, info->fade->at);
X		fprintf(out, "%sFADE FadeBy %g\n", tab, info->fade->by);
X		fprintf(out, "%sFADE FadeTo", tab); send_RGB(&info->fade->to);
X	}
X
X	if (info->skyc) {
X		fprintf(out, "%sSKYC Horizon", tab); send_RGB(&info->skyc->hori);
X		fprintf(out, "%sSKYC Zenith ", tab); send_RGB(&info->skyc->zeni);
X	}
X
X	if (info->ambi)
X		{ fprintf(out, "%sAMBI", tab); send_RGB(info->ambi); }
X
X	if (info->glb0)
X		for (i=0; i<8; i++)
X			fprintf(out, "%sGLB0[%d]=%u\n", tab, i, info->glb0[i]);
X
X	outdent();
X	fprintf(out, "%sEnd INFO\n", tab);
}
X
static void process_OBJ(obj)
register OBJECT *obj;
{
X	register HIER *p;
X	num_OBJ++;
X	fprintf(out, "%sOBJ Begin \"Hierarchy %d\"\n", tab, num_OBJ);
X	num_DESC = num_TOBJ = 0;		/* Reset counters */
X	cur_level = 0;
X	cur_objnum = 1;
X	prntline = 1;
X
X	if (obj->extr) process_EXTR(obj->extr);
X	else process_DESC(obj);
X
X	while (root) {				/* This should happen at most once. */
X		p = root->next;
X		free((char *)root);		/* Delete this from list */
X		root = p;
X		outdent();
X	}
X
X	fprintf(out, "%sEnd OBJ   \"Hierarchy %d\"\n", tab, num_OBJ);
}
X
static int process_TOBJ()
{
X	register HIER *p;
X	if (num_DESC-num_TOBJ < cur_level) {	/* Pop old level off HIER */
X		cur_level--;
X		cur_objnum = root->objnum;
X		p = root->next;
X		free((char *)root);	/* Delete from list */
X		root = p;
X		outdent();	/* Pretty file formatting */
X	}
X	fprintf(out, "%sTOBJ       \"Object %d at level %d of hierarchy %d\"\n",
X		tab, cur_objnum-1, num_DESC-num_TOBJ, num_OBJ);
X	num_TOBJ++;
X	prntline = 1;
}
X
static void process_EXTR(extr)
EXTR *extr;
{
X	register int i;
X
X	if (!prntline) fprintf(out, "\n");	/* Print one anyway */
X	indent();
X	num_DESC++;
X
X	fprintf(out, "%sEXTR Begin \"Object %d at level %d of hierarchy %d\"\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X	indent();
X	fprintf(out, "%sMTRX Translate", tab); send_XYZ(&extr->mtrx.tran);
X	fprintf(out, "%sMTRX Scale    ", tab); send_XYZ(&extr->mtrx.scal);
X	fprintf(out, "%sMTRX Rotate", tab);
X	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota1.val[i]);
X	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota2.val[i]);
X	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota3.val[i]);
X	fprintf(out, "\n");
X
X	fprintf(out, "%sLOAD \"%s\"\n", tab, extr->filename);
X	outdent();
X	fprintf(out, "%sEnd EXTR   \"Object %d at level %d of hierarchy %d\"\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X
X	num_TOBJ++;
X	cur_objnum++;
X	outdent();
X	prntline = 1;
}
X
static void process_DESC(object)
OBJECT *object;
{
X	register int i;
X	register HIER *p;
X	register OBJECT *obj;
X	register DESC *desc = object->desc;
X	FGRP *fgrp;
X
X	num_DESC++;
X	if (num_DESC-num_TOBJ > cur_level) {	/* Push new level in HIER */
X		if (!prntline) fprintf(out, "\n");	/* Print one anyway */
X		if (!(p = (HIER*)malloc(sizeof(HIER)))) {
X			fprintf(stderr, "ERROR!  Out of memory.\n*** ABORT ***\n");
X			exit(20);
X		}
X		p->next = root;		/* Insert into list */
X		root = p;
X		root->objnum = cur_objnum;
X		cur_level++;
X		cur_objnum = 1;
X		indent();	/* Pretty file formatting */
X	}
X
X	fprintf(out, "%sDESC Begin \"Object %d at level %d of hierarchy %d\"\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X	indent();
X
X	if (desc->name[0]) fprintf(out, "%sNAME \"%s\"\n", tab, desc->name);
X
X	if (desc->shap) {
X		fprintf(out, "%sSHAP Shape = %u\n", tab, desc->shap[0]);
X		fprintf(out, "%sSHAP Lamp  = %u\n", tab, desc->shap[1]);
X	}
X
X	if (desc->posi)
X		{ fprintf(out, "%sPOSI", tab); send_XYZ(desc->posi); }
X
X	if (desc->axis) {
X		fprintf(out, "%sAXIS XAxis", tab); send_XYZ(&desc->axis->xaxi);
X		fprintf(out, "%sAXIS YAxis", tab); send_XYZ(&desc->axis->yaxi);
X		fprintf(out, "%sAXIS ZAxis", tab); send_XYZ(&desc->axis->zaxi);
X	}
X
X	if (desc->size)
X		{ fprintf(out, "%sSIZE", tab); send_XYZ(desc->size); }
X
X	if (desc->pcount) {
X		fprintf(out, "%sPNTS PCount %u\n", tab, desc->pcount);
X		for (i=0; i<desc->pcount; i++) {
X			fprintf(out, "%sPNTS Point[%d]", tab, i);
X			send_XYZ(&desc->pnts[i]);
X		}
X	}
X
X	if (desc->ecount) {
X		fprintf(out, "%sEDGE ECount %u\n", tab, desc->ecount);
X		for (i=0; i<desc->ecount; i++) {
X			fprintf(out, "%sEDGE Edge[%d] %u %u\n", tab, i,
X				desc->edge[i<<1], desc->edge[(i<<1)+1]);
X		}
X	}
X
X	if (desc->eflg) {
X		fprintf(out, "%sEFLG Count %u\n", tab, desc->eflg->num);
X		for (i=0; i<desc->eflg->num; i++) {
X			fprintf(out, "%sEFLG Eflg[%d]=%u\n", tab, i, desc->eflg->eflg[i]);
X		}
X	}
X
X	if (desc->fcount) {
X		fprintf(out, "%sFACE TCount %u\n", tab, desc->fcount);
X		for (i=0; i<desc->fcount; i++) {
X			fprintf(out, "%sFACE Connect[%u] %u %u %u\n", tab, i,
X				desc->face[i*3], desc->face[i*3+1], desc->face[i*3+2]);
X		}
X	}
X
X	for (fgrp=desc->fgrp; fgrp; fgrp=fgrp->next) {
X		fprintf(out, "%sFGRP Name \"%s\"\n", tab, fgrp->name);
X		fprintf(out, "%sFGRP Count %u\n", tab, fgrp->num);
X		for (i=0; i<fgrp->num; i++)
X			fprintf(out, "%sFGRP Face[%u]=%u\n", tab, i, fgrp->face[i]);
X	}
X
X	if (desc->colr) { fprintf(out, "%sCOLR", tab); send_RGB(desc->colr); }
X
X	if (desc->refl) { fprintf(out, "%sREFL", tab); send_RGB(desc->refl); }
X
X	if (desc->tran) { fprintf(out, "%sTRAN", tab); send_RGB(desc->tran); }
X
X	if (desc->spc1) { fprintf(out, "%sSPC1", tab); send_RGB(desc->spc1); }
X
X	if (desc->fcount) {
X		fprintf(out, "%sCLST Count %u\n", tab, desc->fcount);
X		for (i=0; i<desc->fcount; i++) {
#if 0
/* Never skip printing a CLST value - GML - 3/27/92 */
X			if (desc->colr) {
X				if (desc->clst[i*3  ]==desc->colr->val[0] &&
X					desc->clst[i*3+1]==desc->colr->val[1] &&
X					desc->clst[i*3+2]==desc->colr->val[2]) continue; /* Skip */
X			} else {
X				if (desc->clst[i*3  ]==240 &&
X					desc->clst[i*3+1]==240 &&
X					desc->clst[i*3+2]==240) continue;	/* Skip this one */
X			}
#endif
X			fprintf(out, "%sCLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->clst[i*3]);
X		}
X		fprintf(out, "%sRLST Count %u\n", tab, desc->fcount);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->refl) {
X				if (desc->rlst[i*3  ]==desc->refl->val[0] &&
X					desc->rlst[i*3+1]==desc->refl->val[1] &&
X					desc->rlst[i*3+2]==desc->refl->val[2]) continue; /* Skip */
X			} else {
X				if (desc->rlst[i*3  ]==0 &&
X					desc->rlst[i*3+1]==0 &&
X					desc->rlst[i*3+2]==0) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sRLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->rlst[i*3]);
X		}
X		fprintf(out, "%sTLST Count %u\n", tab, desc->fcount);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->tran) {
X				if (desc->tlst[i*3  ]==desc->tran->val[0] &&
X					desc->tlst[i*3+1]==desc->tran->val[1] &&
X					desc->tlst[i*3+2]==desc->tran->val[2]) continue; /* Skip */
X			} else {
X				if (desc->tlst[i*3  ]==0 &&
X					desc->tlst[i*3+1]==0 &&
X					desc->tlst[i*3+2]==0) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sTLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->tlst[i*3]);
X		}
X	}
X
X	if (desc->tpar) {
X		for (i=0; i<16; i++)
X			fprintf(out, "%sTPAR[%u]=%g\n", tab, i, desc->tpar[i]);
X	}
X
X	if (desc->surf) {
X		for (i=0; i<5; i++)
X			fprintf(out, "%sSURF[%u]=%d\n", tab, i, desc->surf[i]);
X	}
X
X	if (desc->mttr) {
X		fprintf(out, "%sMTTR Type =%u\n", tab, desc->mttr->type);
X		fprintf(out, "%sMTTR Index=%g\n", tab, (double)desc->mttr->indx);
X	}
X
X	if (desc->spec) {
X		fprintf(out, "%sSPEC Spec=%u\n", tab, desc->spec[0]);
X		fprintf(out, "%sSPEC Hard=%u\n", tab, desc->spec[1]);
X	}
X
X	if (desc->prp0) {
X		for (i=0; i<6; i++)
X			fprintf(out, "%sPRP0[%u]=%u\n", tab, i, desc->prp0[i]);
X	}
X
X	if (desc->prp1) {
X		for (i=0; i<8; i++)
X			fprintf(out, "%sPRP1[%u]=%u\n", tab, i, desc->prp1[i]);
X	}
X
X	if (desc->ints)
X		fprintf(out, "%sINTS=%g\n", tab, desc->ints);
X
X	if (desc->int1) { fprintf(out, "%sINT1", tab); send_XYZ(desc->int1); }
X
X	if (desc->stry) {
X		fprintf(out, "%sSTRY Path \"%s\"\n", tab, desc->stry->path);
X		fprintf(out, "%sSTRY Translate", tab); send_XYZ(&desc->stry->tran);
X		fprintf(out, "%sSTRY Rotate   ", tab); send_XYZ(&desc->stry->rota);
X		fprintf(out, "%sSTRY Scale    ", tab); send_XYZ(&desc->stry->scal);
X		i = desc->stry->info;
X		strin[0] = '\0';
X		if (i&(1<<0))  strcat(strin, " ABS_TRA");
X		if (i&(1<<1))  strcat(strin, " ABS_ROT");
X		if (i&(1<<2))  strcat(strin, " ABS_SCL");
X		if (i&(1<<4))  strcat(strin, " LOC_TRA");
X		if (i&(1<<5))  strcat(strin, " LOC_ROT");
X		if (i&(1<<6))  strcat(strin, " LOC_SCL");
X		if (i&(1<<8))  strcat(strin, " X_ALIGN");
X		if (i&(1<<9))  strcat(strin, " Y_ALIGN");
X		if (i&(1<<10)) strcat(strin, " Z_ALIGN");
X		if (i&(1<<12)) strcat(strin, " FOLLOW_ME");
X		fprintf(out, "%sSTRY Info%s\n", tab, strin);
X	}
X
X	outdent();
X	fprintf(out, "%sEnd DESC   \"Object %d at level %d of hierarchy %d\"\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X
X	for (obj=object->child; obj; obj=obj->next) {
X		if (obj->extr) process_EXTR(obj->extr);
X		else process_DESC(obj);
X	}
X
X	cur_objnum++;
X	prntline = 0;
X	process_TOBJ();
}
X
SHAR_EOF
chmod 0644 write.c ||
echo 'restore of write.c failed'
Wc_c="`wc -c < 'write.c'`"
test 12386 -eq "$Wc_c" ||
	echo 'write.c: original size 12386, current size' "$Wc_c"
fi
# ============= writedxf.c ==============
if test -f 'writedxf.c' -a X"$1" != X"-c"; then
	echo 'x - skipping writedxf.c (File already exists)'
else
echo 'x - extracting writedxf.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'writedxf.c' &&
/* writedxf.c - dump the internal database to a DXF file
X *            - written by Glenn M. Lewis - 07/07/92
X */
X
static char rcs_id[] = "$Id: writedxf.c,v 1.1 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include <ctype.h>
#include "ttdddlib.h"
X
static void process_DESC();
static void process_INFO();
static FILE *out;
X
/* Here are a few necessary utilities */
X
static void send_XYZ(i, f)			/* Print a common string */
int i;
XXYZ_st *f;
{
X	fprintf(out, " %d\n%g\n", 10+i, f->val[0]);
X	fprintf(out, " %d\n%g\n", 20+i, f->val[1]);
X	fprintf(out, " %d\n%g\n", 30+i, f->val[2]);
}
X
static void send_RGB(rgb)			/* Print a common string */
RGB_st *rgb;
{
X	fprintf(out, "%g\t%g\t%g\n", ((double)rgb->val[0])/255.0,
X		((double)rgb->val[1])/255.0,
X		((double)rgb->val[2])/255.0);
}
X
/********************/
/* The MAIN section */
/********************/
X
int write_DXF(world, file)
WORLD *world;
FILE *file;
{
X	register OBJECT *o;
X
X	if (!(out = file) || !world) return(0);
X
X	/* Write header to DXF file: */
X	fprintf(out, "  0\nSECTION\n  2\nENTITIES\n");
X
X	if (world->info) process_INFO(world->info);
X
X	for (o=world->object; o; o=o->next)
X		if (!o->extr) process_DESC(o);
X
X	fprintf(out, "  0\nENDSEC\n  0\nEOF\n");
X
X	return(1);
}
X
static void process_DESC(object)
OBJECT *object;
{
X	register int i;
X	register OBJECT *obj;
X	register DESC *desc = object->desc;
X	register int p1, p2, p3;
X
X	/* Process children first */
X	for (obj=object->child; obj; obj=obj->next) {
X		if (!obj->extr) process_DESC(obj);
X	}
X
X	if (!desc->pcount || !desc->fcount) return;
X
/*	fprintf(out, "\n# Start of new object\n");	*/
X
X	for (i=0; i<desc->fcount; i++) {
X	/* First check to make sure that this triangle is real */
X		p1 = desc->edge[(desc->face[i*3])<<1];
X		p2 = desc->edge[((desc->face[i*3])<<1)+1];
X		if (p1 == p2) continue;	/* How did *this* happen? */
X		p3 = desc->edge[(desc->face[i*3+2])<<1];
X		if (p1 == p3 || p2 == p3)
X			p3 = desc->edge[((desc->face[i*3+2])<<1)+1];
X		if (p1 == p3 || p2 == p3) continue; /* How did *this* happen? */
X		/* Now check the actual points for equality */
X		if (bcmp(&desc->pnts[p1], &desc->pnts[p2], sizeof(XYZ_st))==0 ||
X			bcmp(&desc->pnts[p1], &desc->pnts[p3], sizeof(XYZ_st))==0 ||
X			bcmp(&desc->pnts[p2], &desc->pnts[p3], sizeof(XYZ_st))==0)
X			continue;
X
X		fprintf(out, "  0\n3DFACE\n  8\n0\n  6\nCONTINUOUS\n 62\n     4\n");
X
X		send_XYZ(0, &desc->pnts[p1]);
X		send_XYZ(1, &desc->pnts[p2]);
X		send_XYZ(2, &desc->pnts[p3]);
X		send_XYZ(3, &desc->pnts[p3]);
X	}
}
X
static void process_INFO(info)
INFO *info;
{
#ifdef OLD_NFF_CODE
X	fprintf(out, "v\n");
X	if (info->obsv) {
X		fprintf(out, "from "); send_XYZ(&info->obsv->came);
X	}
X	if (info->ambi)
X		{ fprintf(out, "b "); send_RGB(info->ambi); }
#endif
}
SHAR_EOF
chmod 0644 writedxf.c ||
echo 'restore of writedxf.c failed'
Wc_c="`wc -c < 'writedxf.c'`"
test 2720 -eq "$Wc_c" ||
	echo 'writedxf.c: original size 2720, current size' "$Wc_c"
fi
# ============= writemif.c ==============
if test -f 'writemif.c' -a X"$1" != X"-c"; then
	echo 'x - skipping writemif.c (File already exists)'
else
echo 'x - extracting writemif.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'writemif.c' &&
/* writemif.c - routines to output FrameMaker MIF format
X *            - using TTDDDLIB by Glenn M. Lewis - 7/24/91
X */
X
static char rcs_id[] = "$Id: writemif.c,v 1.6 1991/12/09 23:49:21 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
/* double XSIZE = 8.5;	- in the PostScript module */
/* double YSIZE = 11.0;	- in the PostScript module */
#define MARGIN	(0.25)	/* On each side of the page */
#define PPI	(72.0)
#define COS60	(0.5)
#define COS30	(0.8660)
X
static void write_MIF_header();
static void draw_MIF_view();
static void render_MIF_object();
X
static FILE *out;
static WORLD *world;
static MBB mbb;
static double xsize, ysize;
static int view;
static double xoffset, yoffset, scale, ybottom;
X
static int tab;
static void dotab() { register int i=tab; while (i--) fputc(' ',out); }
#define TAB(a) {dotab();fputs(a,out);}
#define TABr(a) {dotab();fputs(a,out);tab++;}
#define TABl(a) {tab--;dotab();fputs(a,out);}
#define PTAB dotab();fprintf
X
int write_MIF(object, file, selected_view)
WORLD *object;
FILE *file;
int selected_view;
{
X	double llx, lly;
X	register OBJECT *obj;
X	if (!(out = file)) return(0);		/* File not open */
X	if (!(world = object)) return(0);	/* No object */
X
X	/* Determine the extent of the world object */
X	mbb.minx = mbb.miny = mbb.minz =  1.0e10;
X	mbb.maxx = mbb.maxy = mbb.maxz = -1.0e10;
X	for (obj=world->object; obj; obj=obj->next) {
X		calculate_MBB(obj);
X		if (!obj->user) continue;
X		if (((MBB*)obj->user)->minx<mbb.minx) mbb.minx = ((MBB*)obj->user)->minx;
X		if (((MBB*)obj->user)->miny<mbb.miny) mbb.miny = ((MBB*)obj->user)->miny;
X		if (((MBB*)obj->user)->minz<mbb.minz) mbb.minz = ((MBB*)obj->user)->minz;
X		if (((MBB*)obj->user)->maxx>mbb.maxx) mbb.maxx = ((MBB*)obj->user)->maxx;
X		if (((MBB*)obj->user)->maxy>mbb.maxy) mbb.maxy = ((MBB*)obj->user)->maxy;
X		if (((MBB*)obj->user)->maxz>mbb.maxz) mbb.maxz = ((MBB*)obj->user)->maxz;
X	}
#ifdef DEBUG
X	fprintf(stderr, "MBB: (%g,%g,%g)-(%g,%g,%g)\n",
X		mbb.minx, mbb.miny, mbb.minz,
X		mbb.maxx, mbb.maxy, mbb.maxz);
#endif
X
X	write_MIF_header();
X	if (selected_view==VIEW_ALL_FOUR) {
X		for (view=0; view<4; view++) {
X			llx = ((view&0x02) ? XSIZE/2.0 : MARGIN) * PPI;
X			lly = ((view&0x01) ? YSIZE/2.0 : MARGIN) * PPI;
X			xsize = PPI*(XSIZE/2.0 - MARGIN);
X			ysize = PPI*(YSIZE/2.0 - MARGIN);
X			TABr("<Frame\n");
X			TAB("<Pen 0>\n");
X			TAB("<Fill 15>\n");
X			TAB("<PenWidth  0.1 pt>\n");
X			TAB("<Separation 0>\n");
X			PTAB(out, "<BRect %g %g %g %g>\n", llx, lly, xsize, ysize);
X			draw_MIF_view();
X			TABl("> # end of Frame\n");
X		}
X	} else {
X		xsize = PPI*(XSIZE - 2.0*MARGIN);
X		ysize = PPI*(YSIZE - 2.0*MARGIN);
X		view=selected_view;
X		TABr("<Frame\n");
X		TAB("<Pen 0>\n");
X		TAB("<Fill 15>\n");
X		TAB("<PenWidth  0.1 pt>\n");
X		TAB("<Separation 0>\n");
X		PTAB(out, "<BRect %g %g %g %g>\n", PPI*MARGIN, PPI*MARGIN, xsize, ysize);
X		draw_MIF_view();
X		TABl("> # end of Frame\n");
X	}
X	return(1);
}
X
static void write_MIF_header()
{
X	tab=0;
X	fputs("<MIFFile 2.00>\t# Created by TTDDDLIB by Glenn M. Lewis\n", out);
X	fprintf(out, "# %s\n", rcs_id);
X	fputs("\n<Document\n <DPageRounding DeleteEmptyPages>\n", out);
X	fputs(" <DSmartQuotesOn Yes>\n <DBordersOn Yes>\n <DGridOn Yes>\n", out);
X	fputs(" <DRulersOn Yes>\n <DSymbolsOn No>\n> # end of Document\n", out);
X	fputs("<Units Upt>\n", out);
}
X
static void draw_MIF_view()
{
X	double xratio, yratio, zratio, ratio;
X	OBJECT *obj;
X
X	if (mbb.maxx-mbb.minx>0.0) xratio=1.0/(mbb.maxx-mbb.minx); else xratio=1.0;
X	if (mbb.maxy-mbb.miny>0.0) yratio=1.0/(mbb.maxy-mbb.miny); else yratio=1.0;
X	if (mbb.maxz-mbb.minz>0.0) zratio=1.0/(mbb.maxz-mbb.minz); else zratio=1.0;
X	ratio = (xratio < yratio ? xratio : yratio);	/* Get minimum ratio */
X	ratio = (ratio  < zratio ? ratio  : zratio);
X
X	scale = (xsize < ysize ? xsize : ysize)*ratio;	/* Keep aspect ratio same */
X
X	switch(view) {
X		case VIEW_TOP:
X			xoffset = (xsize-scale/xratio)/2.0;
X			yoffset = (ysize-scale/yratio)/2.0;
X			break;
X		case VIEW_FRONT:
X			xoffset = (xsize-scale/xratio)/2.0;
X			yoffset = (ysize-scale/zratio)/2.0;
X			break;
X		case VIEW_ISO:
X			xratio = (mbb.maxx-mbb.minx)*COS30+(mbb.maxy-mbb.miny)*COS30;
X			if (xratio>0.0) xratio = 1.0/xratio; else xratio=1.0;
X			ybottom = -(mbb.maxx-mbb.minx)*COS60;
X			yratio = (mbb.maxz-mbb.minz)+(mbb.maxy-mbb.miny)*COS60	/* Top */
X					 - ybottom;
X			if (yratio>0.0) yratio = 1.0/yratio; else yratio=1.0;
X			ratio = (xratio < yratio ? xratio : yratio);
X			scale = (xsize < ysize ? xsize : ysize)*ratio;
X			xoffset = (xsize-scale/xratio)/2.0;
X			yoffset = (ysize-scale/yratio)/2.0;
X			break;
X		case VIEW_RIGHT:
X			xoffset = (xsize-scale/yratio)/2.0;
X			yoffset = (ysize-scale/zratio)/2.0;
X			break;
X	}
X	for (obj=world->object; obj; obj=obj->next)
X		render_MIF_object(obj);
}
X
static void render_MIF_object(obj)
register OBJECT *obj;
{
X	register UWORD *f;
X	register OBJECT *op;
X	register int i, j;
X	int p[3];
X	double x[3], y[3];
X
X	if (!obj->desc) return;
X	for (op=obj->child; op; op=op->next)	/* render children first */
X		render_MIF_object(op);
X	
X	/* Now, the meat... */
X	if (obj->desc->shap && obj->desc->shap[1]!=0) return;	/* A lamp */
X	if (!obj->desc->edge || !obj->desc->pnts || !obj->desc->face) return;
X	for (f=obj->desc->face,i=obj->desc->fcount; i--; f+=3) {
X		p[0] = obj->desc->edge[((*f)<<1)];
X		p[1] = obj->desc->edge[((*f)<<1)+1];
X		if (obj->desc->edge[((f[1])<<1)] == p[0] ||
X			obj->desc->edge[((f[1])<<1)] == p[1])
X			p[2] = obj->desc->edge[((f[1])<<1)+1];
X		else
X			p[2] = obj->desc->edge[((f[1])<<1)];
X		switch(view) {
X			case VIEW_TOP:
X				for (j=3; j--; ) {
X					x[j] = obj->desc->pnts[p[j]].val[0]-mbb.minx;
X					y[j] = obj->desc->pnts[p[j]].val[1]-mbb.miny;
X				}
X				break;
X			case VIEW_FRONT:
X				for (j=3; j--; ) {
X					x[j] = obj->desc->pnts[p[j]].val[0]-mbb.minx;
X					y[j] = obj->desc->pnts[p[j]].val[2]-mbb.minz;
X				}
X				break;
X			case VIEW_ISO:
X				for (j=3; j--; ) {
X					x[j] = (obj->desc->pnts[p[j]].val[0]-mbb.minx)*COS30
X						  +(obj->desc->pnts[p[j]].val[1]-mbb.miny)*COS30;
X					y[j] = (obj->desc->pnts[p[j]].val[2]-mbb.minz)
X						  -(obj->desc->pnts[p[j]].val[0]-mbb.minx)*COS60
X						  +(obj->desc->pnts[p[j]].val[1]-mbb.miny)*COS60
X						  - ybottom;
X				}
X				break;
X			case VIEW_RIGHT:
X				for (j=3; j--; ) {
X					x[j] = obj->desc->pnts[p[j]].val[1]-mbb.miny;
X					y[j] = obj->desc->pnts[p[j]].val[2]-mbb.minz;
X				}
X				break;
X		}
X		if (x[0]==x[1] && x[1]==x[2] && y[0]==y[1] && y[1]==y[2]) continue;
X		TABr("<Polygon\n");
X		PTAB(out, "<Point %0.2lf %0.2lf>\n", xoffset+scale*x[0],
X			ysize-(yoffset+scale*y[0]));
X		if (!(x[0]==x[1] && y[0]==y[1])) {
X			PTAB(out, "<Point %0.2lf %0.2lf>\n", xoffset+scale*x[1],
X				ysize-(yoffset+scale*y[1]));
X		}
X		if (!(x[0]==x[2] && y[0]==y[2]) && !(x[1]==x[2] && y[1]==y[2])) {
X			PTAB(out, "<Point %0.2lf %0.2lf>\n", xoffset+scale*x[2],
X				ysize-(yoffset+scale*y[2]));
X		}
X		TABl(">\n");
X	}
}
X
SHAR_EOF
chmod 0644 writemif.c ||
echo 'restore of writemif.c failed'
Wc_c="`wc -c < 'writemif.c'`"
test 6829 -eq "$Wc_c" ||
	echo 'writemif.c: original size 6829, current size' "$Wc_c"
fi
# ============= writenff.c ==============
if test -f 'writenff.c' -a X"$1" != X"-c"; then
	echo 'x - skipping writenff.c (File already exists)'
else
echo 'x - extracting writenff.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'writenff.c' &&
/* writenff.c - dump the internal database to an NFF file
X *            - written by Glenn M. Lewis - 10/29/91
X */
X
static char rcs_id[] = "$Id: writenff.c,v 1.6 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include <ctype.h>
#include "ttdddlib.h"
X
static void process_DESC();
static void process_INFO();
static FILE *out;
X
/* Here are a few necessary utilities */
X
static void send_XYZ(f)			/* Print a common string */
XXYZ_st *f;
{
X	fprintf(out, "%g\t%g\t%g\n", f->val[0], f->val[1], f->val[2]);
}
X
static void send_RGB(rgb)			/* Print a common string */
RGB_st *rgb;
{
X	fprintf(out, "%g\t%g\t%g\n", ((double)rgb->val[0])/255.0,
X		((double)rgb->val[1])/255.0,
X		((double)rgb->val[2])/255.0);
}
X
/********************/
/* The MAIN section */
/********************/
X
int write_NFF(world, file)
WORLD *world;
FILE *file;
{
X	register OBJECT *o;
X
X	if (!(out = file) || !world) return(0);
X
X	if (world->info) process_INFO(world->info);
X
X	for (o=world->object; o; o=o->next)
X		if (!o->extr) process_DESC(o);
X
X	return(1);
}
X
static void process_DESC(object)
OBJECT *object;
{
X	register int i;
X	register OBJECT *obj;
X	register DESC *desc = object->desc;
X	register int p1, p2, p3;
X
X	/* Process children first */
X	for (obj=object->child; obj; obj=obj->next) {
X		if (!obj->extr) process_DESC(obj);
X	}
X
X	if (!desc->pcount || !desc->fcount) return;
X
X	fprintf(out, "\n# Start of new object\n");
X
X	for (i=0; i<desc->fcount; i++) {
X	/* First check to make sure that this triangle is real */
X		p1 = desc->edge[(desc->face[i*3])<<1];
X		p2 = desc->edge[((desc->face[i*3])<<1)+1];
X		if (p1 == p2) continue;	/* How did *this* happen? */
X		p3 = desc->edge[(desc->face[i*3+2])<<1];
X		if (p1 == p3 || p2 == p3)
X			p3 = desc->edge[((desc->face[i*3+2])<<1)+1];
X		if (p1 == p3 || p2 == p3) continue; /* How did *this* happen? */
X		/* Now check the actual points for equality */
X		if (bcmp(&desc->pnts[p1], &desc->pnts[p2], sizeof(XYZ_st))==0 ||
X			bcmp(&desc->pnts[p1], &desc->pnts[p3], sizeof(XYZ_st))==0 ||
X			bcmp(&desc->pnts[p2], &desc->pnts[p3], sizeof(XYZ_st))==0)
X			continue;
X
X		fprintf(out, "p 3\n");
X		send_XYZ(&desc->pnts[p1]);
X		send_XYZ(&desc->pnts[p2]);
X		send_XYZ(&desc->pnts[p3]);
X	}
}
X
static void process_INFO(info)
INFO *info;
{
X	fprintf(out, "v\n");
X	if (info->obsv) {
X		fprintf(out, "from "); send_XYZ(&info->obsv->came);
X	}
X	if (info->ambi)
X		{ fprintf(out, "b "); send_RGB(info->ambi); }
}
SHAR_EOF
chmod 0644 writenff.c ||
echo 'restore of writenff.c failed'
Wc_c="`wc -c < 'writenff.c'`"
test 2395 -eq "$Wc_c" ||
	echo 'writenff.c: original size 2395, current size' "$Wc_c"
fi
# ============= writeoff.c ==============
if test -f 'writeoff.c' -a X"$1" != X"-c"; then
	echo 'x - skipping writeoff.c (File already exists)'
else
echo 'x - extracting writeoff.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'writeoff.c' &&
/* writeoff.c - dump the internal database to an OFF file
X *            - written by Glenn M. Lewis - 10/29/91
X */
X
static char rcs_id[] = "$Id: writeoff.c,v 1.6 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include <ctype.h>
#include "ttdddlib.h"
X
static void process_DESC();
static void process_points_DESC();
static void process_faces_DESC();
static void count_points_faces();
X
static int geom_count;
static char filename[256];
static char *rootname;
static FILE *out, *outcol;
static unsigned long poff;	/* Point index offset */
X
/* Here are a few necessary utilities */
X
static void send_XYZ(f)			/* Print a common string */
XXYZ_st *f;
{
X	fprintf(out, "%g\t%g\t%g\n", f->val[0], f->val[1], f->val[2]);
}
X
static void send_RGB(rgb)			/* Print a common string */
RGB_st *rgb;
{
X	fprintf(outcol, "%g\t%g\t%g\n", ((double)rgb->val[0])/255.0,
X		((double)rgb->val[1])/255.0,
X		((double)rgb->val[2])/255.0);
}
X
/********************/
/* The MAIN section */
/********************/
X
int geom_flag;
X
int write_OFF(world, name, splitflag, geom_only)
WORLD *world;
char *name;
int splitflag, geom_only;
{
X	register OBJECT *o;
X	unsigned long total_points, total_faces;
X
X	if (!world) return(0);
X
X	geom_flag = geom_only;
X	geom_count = 0;
X	rootname = name;
X	if (splitflag) {
X		for (o=world->object; o; o=o->next)
X			if (!o->extr) process_DESC(o);
X		return(1);
X	}
X
X	strcpy(filename, rootname);
X	strcat(filename, ".geom");
X	if (!(out=fopen(filename, "w"))) {
X		fprintf(stderr, "Can't open '%s' for output.\n", filename);
X		return(0);
X	}
X	if (!geom_flag) {
X		strcpy(filename, rootname);
X		strcat(filename, ".ipcol");
X		if (!(outcol=fopen(filename, "w"))) {
X			fprintf(stderr, "Can't open '%s' for output.\n", filename);
X			fclose(out);
X			return(0);
X		}
X	}
X
X	poff = total_points = total_faces = 0;
X
X	for (o=world->object; o; o=o->next)
X		count_points_faces(o, &total_points, &total_faces);
X	fprintf(out, "%lu\t%lu\t%lu\n", total_points, total_faces, total_points*3L);
X	if (!geom_flag) fprintf(outcol, "%lu\n", total_faces);
X
X	for (o=world->object; o; o=o->next)
X		process_points_DESC(o);
X	for (o=world->object; o; o=o->next)
X		process_faces_DESC(o);
X	
X	fclose(out);
X	if (!geom_flag) fclose(outcol);
X	return(1);
}
X
static void count_points_faces(object, points, faces)
register OBJECT *object;
unsigned long *points, *faces;
{
X	register OBJECT *obj;
X
X	if (object->extr) return;
X	*points += object->desc->pcount;
X	*faces  += object->desc->fcount;
X
X	for (obj=object->child; obj; obj=obj->next) {
X		if (!obj->extr) count_points_faces(obj, points, faces);
X	}
}
X
static void process_points_DESC(object)
OBJECT *object;
{
X	register int i;
X	register OBJECT *obj;
X	register DESC *desc = object->desc;
X
/*	if (!desc->pcount || !desc->fcount) return;	*/
X
X	if (desc)
X	for (i=0; i<desc->pcount; i++) {
X		send_XYZ(&desc->pnts[i]);
X	}
X
X	for (obj=object->child; obj; obj=obj->next) {
X		if (!obj->extr) process_points_DESC(obj);
X	}
}
X
static void process_faces_DESC(object)
OBJECT *object;
{
X	register int i;
X	register OBJECT *obj;
X	register DESC *desc = object->desc;
X	register int p1, p2, p3;
X
/*	if (!desc->pcount || !desc->fcount) return;	*/
X
X	if (desc) {
X		for (i=0; i<desc->fcount; i++) {
X		/* First check to make sure that this triangle is real */
X			p1 = desc->edge[(desc->face[i*3])<<1];
X			p2 = desc->edge[((desc->face[i*3])<<1)+1];
X			/* if (p1 == p2) continue;	/* How did *this* happen? */
X			p3 = desc->edge[(desc->face[i*3+2])<<1];
X			if (p1 == p3 || p2 == p3)
X				p3 = desc->edge[((desc->face[i*3+2])<<1)+1];
X			/* if (p1 == p3 || p2 == p3) continue; /* How did *this* happen? */
X
X			fprintf(out, "3\t%lu\t%lu\t%lu\n", poff+p1+1, poff+p2+1, poff+p3+1);
X			if (!geom_flag) send_RGB(&desc->clst[i*3]);
X		}
X		poff += desc->pcount;
X	}
X
X	for (obj=object->child; obj; obj=obj->next) {
X		if (!obj->extr) process_faces_DESC(obj);
X	}
}
X
static void process_DESC(object)
OBJECT *object;
{
X	register int i;
X	register OBJECT *obj;
X	register DESC *desc = object->desc;
X	register int p1, p2, p3;
X
X	/* Process children first */
X	for (obj=object->child; obj; obj=obj->next) {
X		if (!obj->extr) process_DESC(obj);
X	}
X
X	if (!desc->pcount || !desc->fcount) return;
X
X	geom_count++;
X	sprintf(filename, "%s%03d.geom", rootname, geom_count);
X	if (!(out = fopen(filename, "w"))) {
X		fprintf(stderr, "Can't open '%s' for output.\n", filename);
X		return;
X	}
X	fprintf(out, "; %s\n", filename);
X	fprintf(out, "%u\t%u\t%u\n",
X		desc->pcount, desc->fcount, desc->pcount*3);
X	if (!geom_flag) {
X		sprintf(filename, "%s%03d.ipcol", rootname, geom_count);
X		if (!(outcol = fopen(filename, "w"))) {
X			fprintf(stderr, "Can't open '%s' for output.\n", filename);
X			return;
X		}
X		fprintf(outcol, "; %s\n", filename);
X		fprintf(outcol, "%u\n", desc->fcount);
X	}
X
X	for (i=0; i<desc->pcount; i++) {
X		send_XYZ(&desc->pnts[i]);
X	}
X
X	for (i=0; i<desc->fcount; i++) {
X	/* First check to make sure that this triangle is real */
X		p1 = desc->edge[(desc->face[i*3])<<1];
X		p2 = desc->edge[((desc->face[i*3])<<1)+1];
X		/* if (p1 == p2) continue;	/* How did *this* happen? */
X		p3 = desc->edge[(desc->face[i*3+2])<<1];
X		if (p1 == p3 || p2 == p3)
X			p3 = desc->edge[((desc->face[i*3+2])<<1)+1];
X		/* if (p1 == p3 || p2 == p3) continue; /* How did *this* happen? */
X
X		fprintf(out, "3\t%u\t%u\t%u\n", p1+1, p2+1, p3+1);
X		if (!geom_flag) send_RGB(&desc->clst[i*3]);
X	}
X
X	fclose(out);
X	if (!geom_flag) fclose(outcol);
}
X
SHAR_EOF
chmod 0644 writeoff.c ||
echo 'restore of writeoff.c failed'
Wc_c="`wc -c < 'writeoff.c'`"
test 5366 -eq "$Wc_c" ||
	echo 'writeoff.c: original size 5366, current size' "$Wc_c"
fi
# ============= writepov.c ==============
if test -f 'writepov.c' -a X"$1" != X"-c"; then
	echo 'x - skipping writepov.c (File already exists)'
else
echo 'x - extracting writepov.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'writepov.c' &&
/* writepov.c - dump the internal database to a POV-Ray 1.0 input file
X *            - written by Glenn M. Lewis - 7/27/92
X */
X
static char rcs_id[] = "$Id: writepov.c,v 1.2 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include <ctype.h>
#include <math.h>
extern double sqrt();
#include "ttdddlib.h"
X
static void process_DESC();
static void process_EXTR();
static void process_INFO();
static void process_OBJ();
X
/* Two-space tabs */
#define TABSTOP "  "
X
static FILE *out;
static char tab[133];
static int num_OBJ, num_DESC, num_TOBJ;
static int cur_level, cur_objnum;
static int prntline;
X
static struct save_hier {
X	int objnum;
X	struct save_hier *next;
} *root = 0;
typedef struct save_hier HIER;
X
/* Here are a few necessary utilities */
X
static void indent()
{
X	strcat(tab, TABSTOP);
}
X
static void outdent()
{
X	register int i = strlen(tab) - strlen(TABSTOP);
X	if (i<0) {
X		fprintf(stderr, "Whoa, Glenn!  You blew it!\n");
X		tab[0] = '\0';
X		return;
X	}
X	tab[i] = '\0';
}
X
static void send_XYZ(f)			/* Print a common string */
XXYZ_st *f;
{
/* I noticed that with a Ultrix C compiler, these in-line function calls were
X * not executed in the order specified.  Since I want this code to be portable,
X * and since some C compilers are broken, I seperated the following lines.
X * This goes for *all* in-line function calls in this source code.
X */
X	fprintf(out, " <%g",   f->val[0]);
X	fprintf(out, " %g",   f->val[1]);
X	fprintf(out, " %g>\n", f->val[2]);
}
X
static void send_RGB(rgb)			/* Print a common string */
RGB_st *rgb;
{
X	fprintf(out, " color red %g",   ((double)rgb->val[0])*(1.0/255.0));
X	fprintf(out, " green %g",   ((double)rgb->val[1])*(1.0/255.0));
X	fprintf(out, " blue %g ", ((double)rgb->val[2])*(1.0/255.0));
}
X
/********************/
/* The MAIN section */
/********************/
X
int write_POVRay(world, file)
WORLD *world;
FILE *file;
{
X	register OBJECT *o;
X
X	if (!(out=file) || !world) return(0);	/* File not open */
X
X	tab[0] = '\0';
X	num_OBJ = num_DESC = num_TOBJ = 0;
X
X	fputs("/* TTDDD library - Written by Glenn M. Lewis - 7/27/92 */\n\n", out);
X	if (world->info) process_INFO(world->info);
X	for (o=world->object; o; o=o->next)
X		process_OBJ(o);
X	return(1);
}
X
static void process_INFO(info)
INFO *info;
{
X	fprintf(out, "%s/* INFO Begin */\n", tab);
X	indent();
#ifdef OLD_STUFF
X	for (i=0; i<8; i++)
X		if (info->brsh[i][0])
X			fprintf(out, "%sBRSH[%d]=\"%s\"\n", tab, i, info->brsh[i]);
X
X	for (i=0; i<8; i++)
X		if (info->stnc[i][0])
X			fprintf(out, "%sSTNC[%d]=\"%s\"\n", tab, i, info->stnc[i]);
X
X	for (i=0; i<8; i++)
X		if (info->txtr[i][0])
X			fprintf(out, "%sTXTR[%d]=\"%s\"\n", tab, i, info->txtr[i]);
X
X	if (info->obsv) {
X		fprintf(out, "%seyep", tab); send_XYZ(&info->obsv->came);
X		fprintf(out, "%s/* OBSV Rotate", tab); send_XYZ(&info->obsv->rota);
X		fprintf(out, "*/%sfocaldist  %g\n", tab, info->obsv->foca);
X	}
*
X
/*	if (info->otrk[0]) fprintf(out, "%sOTRK \"%s\"\n", tab, info->otrk);	*/
X
X
X	if (info->ostr) {
X		if (info->ostr->path[0])
X			fprintf(out, "%sOSTR Path \"%s\"\n", tab, info->ostr->path);
X		fprintf(out, "%sOSTR Translate", tab); send_XYZ(&info->ostr->tran);
X		fprintf(out, "%sOSTR Rotate   ", tab); send_XYZ(&info->ostr->rota);
X		fprintf(out, "%sOSTR Scale    ", tab); send_XYZ(&info->ostr->scal);
X		i = info->ostr->info;
X		strin[0] = '\0';
X		if (i&(1<<0))  strcat(strin, " ABS_TRA");
X		if (i&(1<<1))  strcat(strin, " ABS_ROT");
X		if (i&(1<<2))  strcat(strin, " ABS_SCL");
X		if (i&(1<<4))  strcat(strin, " LOC_TRA");
X		if (i&(1<<5))  strcat(strin, " LOC_ROT");
X		if (i&(1<<6))  strcat(strin, " LOC_SCL");
X		if (i&(1<<8))  strcat(strin, " X_ALIGN");
X		if (i&(1<<9))  strcat(strin, " Y_ALIGN");
X		if (i&(1<<10)) strcat(strin, " Z_ALIGN");
X		if (i&(1<<12)) strcat(strin, " FOLLOW_ME");
X		fprintf(out, "%sOSTR Info%s\n", tab, strin);
X	}
X
X	if (info->fade) {
X		fprintf(out, "%s/* FADE FadeAt %g*/\n", tab, info->fade->at);
X		fprintf(out, "%s/* FADE FadeBy %g*/\n", tab, info->fade->by);
X		fprintf(out, "%s/* FADE FadeTo", tab); send_RGB(&info->fade->to);
X		fprintf(out, "*/\n");
X	}
X
X	if (info->skyc) {
X		fprintf(out, "%s/* SKYX Horizon", tab); send_RGB(&info->skyc->hori);
X		fprintf(out, "*/\n");
X		fprintf(out, "%s/* SKYC Zenith ", tab); send_RGB(&info->skyc->zeni);
X		fprintf(out, "*/\n");
X	}
X
X	if (info->ambi)
X		{ fprintf(out, "%sbackground", tab); send_RGB(info->ambi); }
X
X
X	if (info->glb0)
X		for (i=0; i<8; i++)
X			fprintf(out, "%sGLB0[%d]=%u\n", tab, i, info->glb0[i]);
#endif
X
X	outdent();
X	fprintf(out, "%s/* End INFO */\n", tab);
}
X
static void process_OBJ(obj)
register OBJECT *obj;
{
X	register HIER *p;
X	num_OBJ++;
X	fprintf(out, "%s/* OBJ Begin \"Hierarchy %d\" */\n", tab, num_OBJ);
X	fprintf(out, "%sobject {\n", tab);
X	num_DESC = num_TOBJ = 0;		/* Reset counters */
X	cur_level = 0;
X	cur_objnum = 1;
X	prntline = 1;
X
X	if (obj->extr) process_EXTR(obj->extr);
X	else process_DESC(obj);
X
X	while (root) {				/* This should happen at most once. */
X		p = root->next;
X		free((char *)root);		/* Delete this from list */
X		root = p;
X		outdent();
X	}
X
X	fprintf(out, "%s/* End OBJ   \"Hierarchy %d\" */\n", tab, num_OBJ);
X	fprintf(out, "%s}\n", tab);
}
X
static int process_TOBJ()
{
X	register HIER *p;
X	if (num_DESC-num_TOBJ < cur_level) {	/* Pop old level off HIER */
X		cur_level--;
X		cur_objnum = root->objnum;
X		p = root->next;
X		free((char *)root);	/* Delete from list */
X		root = p;
X		outdent();	/* Pretty file formatting */
X	}
X	fprintf(out, "%s/* TOBJ       \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum-1, num_DESC-num_TOBJ, num_OBJ);
X	fprintf(out, "%s}\n", tab);
X	num_TOBJ++;
X	prntline = 1;
}
X
static void process_EXTR(extr)
EXTR *extr;
{
X	register int i;
X
X	if (!prntline) fprintf(out, "\n");	/* Print one anyway */
X	indent();
X	num_DESC++;
X
X	fprintf(out, "%s/* EXTR Begin \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X	fprintf(out, "%sunion {\n", tab);
X	indent();
X	fprintf(out, "%s/* LOAD \"%s\" */\n", tab, extr->filename);
X	fprintf(out, "#include \"%s\"\n", extr->filename);
X	fprintf(out, "%stranslate", tab); send_XYZ(&extr->mtrx.tran);
X	fprintf(out, "%sscale    ", tab); send_XYZ(&extr->mtrx.scal);
X	fprintf(out, "%s/* transform", tab);
X	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota1.val[i]);
X	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota2.val[i]);
X	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota3.val[i]);
X	fprintf(out, "*/\n");
X
X	outdent();
X	fprintf(out, "%s/* End EXTR   \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X	fprintf(out, "%s}\n", tab);
X
X	num_TOBJ++;
X	cur_objnum++;
X	outdent();
X	prntline = 1;
}
X
static void process_DESC(object)
OBJECT *object;
{
X	register int i;
X	register XYZ_st *p1, *p2, *p3;
X	register HIER *p;
X	register OBJECT *obj;
X	register DESC *desc = object->desc;
X
X	num_DESC++;
X	if (num_DESC-num_TOBJ > cur_level) {	/* Push new level in HIER */
X		if (!prntline) fprintf(out, "\n");	/* Print one anyway */
X		if (!(p = (HIER*)malloc(sizeof(HIER)))) {
X			fprintf(stderr, "ERROR!  Out of memory.\n*** ABORT ***\n");
X			exit(20);
X		}
X		p->next = root;		/* Insert into list */
X		root = p;
X		root->objnum = cur_objnum;
X		cur_level++;
X		cur_objnum = 1;
X		indent();	/* Pretty file formatting */
X	}
X
X	if (desc->shap && desc->shap[1]) {
X		fprintf(out, "%slight_source", tab);
X		if (desc->colr) send_RGB(desc->colr); /* else fprintf(out, " 1.0 "); */
X		if (desc->shap[1]==1)	/* Sunlight */
X			fprintf(out, "point_at < %g %g %g >\n",
X				-(desc->posi->val[0]),
X				-(desc->posi->val[1]),
X				-(desc->posi->val[2]));
X		else	/* Like a lamp */
X			fprintf(out, "point < %g %g %g >\n",
X				desc->posi->val[0],
X				desc->posi->val[1],
X				desc->posi->val[2]);
X		goto SKIP_REST_LIGHT;
X	}
X
X	fprintf(out,"%s/* DESC Begin \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X	fprintf(out, "%sunion {\n", tab);
X	indent();
X
X	if (desc->name[0]) fprintf(out, "%s/* name \"%s\" */\n", tab, desc->name);
X
X	if (desc->shap) {
X		fprintf(out, "%s/* SHAP Shape = %u */\n", tab, desc->shap[0]);
X		if (desc->shap==0 && !desc->shap[1]) {	/* Sphere */
X			fprintf(out, "%ssphere {", tab);
X			send_XYZ(desc->posi);
X			fprintf(out, "%s%g }\n", tab, desc->size->val[0]);
X			goto SKIP_REST;
X		}
X		fprintf(out, "%s/* SHAP Lamp  = %u */\n", tab, desc->shap[1]);
X	}
X
/*
X	if (desc->axis) {
X		fprintf(out, "%sAXIS XAxis", tab); send_XYZ(&desc->axis->xaxi);
X		fprintf(out, "%sAXIS YAxis", tab); send_XYZ(&desc->axis->yaxi);
X		fprintf(out, "%sAXIS ZAxis", tab); send_XYZ(&desc->axis->zaxi);
X	}
X
X	if (desc->size)
X		{ fprintf(out, "%sSIZE", tab); send_XYZ(desc->size); }
X
X	if (desc->pcount) {
X		fprintf(out, "%sPNTS PCount %u\n", tab, desc->pcount);
X		for (i=0; i<desc->pcount; i++) {
X			fprintf(out, "%sPNTS Point[%d]", tab, i);
X			send_XYZ(&desc->pnts[i]);
X		}
X	}
X
X	if (desc->ecount) {
X		fprintf(out, "%sEDGE ECount %u\n", tab, desc->ecount);
X		for (i=0; i<desc->ecount; i++) {
X			fprintf(out, "%sEDGE Edge[%d] %u %u\n", tab, i,
X				desc->edge[i<<1], desc->edge[(i<<1)+1]);
X		}
X	}
*/
X
X	if (desc->fcount && desc->ecount && desc->pcount) {
X		fprintf(out, "%s/* FACE TCount %u */\n", tab, desc->fcount);
X		for (i=0; i<desc->fcount; i++) {
/*			fprintf(out, "%sFACE Connect[%u] %u %u %u\n", tab, i,
X				desc->face[i*3], desc->face[i*3+1], desc->face[i*3+2]);
*/
X			/* First check and see if the triangle is degenerate */
X			p1 = &desc->pnts[desc->edge[(desc->face[i*3])<<1]];
X			p2 = &desc->pnts[desc->edge[((desc->face[i*3])<<1)+1]];
X			if (desc->edge[(desc->face[i*3+2])<<1] ==
X				desc->edge[(desc->face[i*3])<<1] ||
X				desc->edge[(desc->face[i*3+2])<<1] ==
X				desc->edge[((desc->face[i*3])<<1)+1])
X				p3 = &desc->pnts[desc->edge[((desc->face[i*3+2])<<1)+1]];
X			else
X				p3 = &desc->pnts[desc->edge[(desc->face[i*3+2])<<1]];
#define X val[0]
#define Y val[1]
#define Z val[2]
X			if (!((p1->X==p2->X && p1->Y==p2->Y && p1->Z==p2->Z) ||
X				  (p1->X==p3->X && p1->Y==p3->Y && p1->Z==p3->Z) ||
X				  (p2->X==p3->X && p2->Y==p3->Y && p2->Z==p3->Z))) {
X				fprintf(out, "%striangle {\n", tab);
X				send_XYZ(p1);
X				send_XYZ(p2);
X				send_XYZ(p3);
X	/* Print texture properties for each triangle because POV-Ray does
X	 * not yet support object hierarchies very cleanly, IMHO.
X	 */
X	if (desc->colr || desc->refl || desc->tran ||
X		desc->clst || desc->rlst || desc->tlst) {
X		fprintf(out, "%stexture {", tab);
X		if (desc->clst) { send_RGB((RGB_st*)&desc->clst[i*3]); fputc('\n', out);
X		} else if (desc->colr) { send_RGB(desc->colr); fputc('\n', out); }
X		if (desc->rlst) {
X			fprintf(out, "%sspecular %g\n", tab,
X				(1.0/255.0) *
X				sqrt((double)desc->rlst[i*3+0] * desc->rlst[i*3+0] +
X					 (double)desc->rlst[i*3+1] * desc->rlst[i*3+1] +
X					 (double)desc->rlst[i*3+2] * desc->rlst[i*3+2]));
X		} else if (desc->refl) {
X			fprintf(out, "%sspecular %g\n", tab,
X				(1.0/255.0) *
X				sqrt((double)desc->refl->val[0] * desc->refl->val[0] +
X					 (double)desc->refl->val[1] * desc->refl->val[1] +
X					 (double)desc->refl->val[2] * desc->refl->val[2]));
X		}
X		if (desc->tlst) {
X			fprintf(out, "%srefraction %g\n", tab,
X				(1.0/255.0) *
X				sqrt((double)desc->tlst[i*3+0] * desc->tlst[i*3+0] +
X					 (double)desc->tlst[i*3+1] * desc->tlst[i*3+1] +
X					 (double)desc->tlst[i*3+2] * desc->tlst[i*3+2]));
X		} else if (desc->tran) {
X			fprintf(out, "%srefraction %g\n", tab,
X				(1.0/255.0) *
X				sqrt((double)desc->tran->val[0] * desc->tran->val[0] +
X					 (double)desc->tran->val[1] * desc->tran->val[1] +
X					 (double)desc->tran->val[2] * desc->tran->val[2]));
X		}
X		fprintf(out, "%s}\n", tab);
X	}
X				fprintf(out, "%s}\n", tab);
X			}
X		}
X	}
X
SKIP_REST:
X
X	for (obj=object->child; obj; obj=obj->next) {
X		if (obj->extr) process_EXTR(obj->extr);
X		else process_DESC(obj);
X	}
X
X	outdent();
X	fprintf(out, "%s/* End DESC   \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X
X	if (desc->posi)
X		{ fprintf(out, "%stranslate", tab); send_XYZ(desc->posi); }
X
/*
X	if (desc->colr || desc->refl || desc->tran) {
X		fprintf(out, "%stexture {", tab);
X		if (desc->colr) { send_RGB(desc->colr); fputc('\n', out); }
X		if (desc->refl) {
X			fprintf(out, "%sspecular %g\n", tab,
X				(1.0/255.0) *
X				sqrt((double)desc->refl->val[0] * desc->refl->val[0] +
X					 (double)desc->refl->val[1] * desc->refl->val[1] +
X					 (double)desc->refl->val[2] * desc->refl->val[2]));
X		}
X		if (desc->tran) {
X			fprintf(out, "%srefraction %g\n", tab,
X				(1.0/255.0) *
X				sqrt((double)desc->tran->val[0] * desc->tran->val[0] +
X					 (double)desc->tran->val[1] * desc->tran->val[1] +
X					 (double)desc->tran->val[2] * desc->tran->val[2]));
X		}
X		fprintf(out, "%s}\n", tab);
X	}
*/
X
#ifdef WRITETTDDD
X	if (desc->fcount) {
X		fprintf(out, "%sCLST Count %u\n", tab, i);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->colr) {
X				if (desc->clst[i*3  ]==desc->colr->val[0] &&
X					desc->clst[i*3+1]==desc->colr->val[1] &&
X					desc->clst[i*3+2]==desc->colr->val[2]) continue; /* Skip */
X			} else {
X				if (desc->clst[i*3  ]==255 &&
X					desc->clst[i*3+1]==255 &&
X					desc->clst[i*3+2]==255) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sCLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->clst[i*3]);
X		}
X		fprintf(out, "%sRLST Count %u\n", tab, i);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->refl) {
X				if (desc->rlst[i*3  ]==desc->refl->val[0] &&
X					desc->rlst[i*3+1]==desc->refl->val[1] &&
X					desc->rlst[i*3+2]==desc->refl->val[2]) continue; /* Skip */
X			} else {
X				if (desc->rlst[i*3  ]==0 &&
X					desc->rlst[i*3+1]==0 &&
X					desc->rlst[i*3+2]==0) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sRLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->rlst[i*3]);
X		}
X		fprintf(out, "%sTLST Count %u\n", tab, i);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->tran) {
X				if (desc->tlst[i*3  ]==desc->tran->val[0] &&
X					desc->tlst[i*3+1]==desc->tran->val[1] &&
X					desc->tlst[i*3+2]==desc->tran->val[2]) continue; /* Skip */
X			} else {
X				if (desc->tlst[i*3  ]==0 &&
X					desc->tlst[i*3+1]==0 &&
X					desc->tlst[i*3+2]==0) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sTLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->tlst[i*3]);
X		}
X	}
#endif
X
X	if (desc->tpar) {
X		for (i=0; i<16; i++)
X			fprintf(out, "%s/* TPAR[%u]=%g */\n", tab, i, desc->tpar[i]);
X	}
X
X	if (desc->surf) {
X		for (i=0; i<5; i++)
X			fprintf(out, "%s/* SURF[%u]=%d */\n", tab, i, desc->surf[i]);
X	}
X
X	if (desc->mttr) {
X		fprintf(out, "%s/* MTTR Type =%u */\n", tab, desc->mttr->type);
X		fprintf(out, "%s/* MTTR Index=%g */\n", tab, (double)desc->mttr->indx);
X	}
X
X	if (desc->spec) {
X		fprintf(out, "%s/* SPEC Spec=%u */\n", tab, desc->spec[0]);
X		fprintf(out, "%s/* SPEC Hard=%u */\n", tab, desc->spec[1]);
X	}
X
X	if (desc->prp0) {
X		for (i=0; i<6; i++)
X			fprintf(out, "%s/* PRP0[%u]=%u */\n", tab, i, desc->prp0[i]);
X	}
X
X	if (desc->ints)
X		fprintf(out, "%s/* INTS=%g */\n", tab, desc->ints);
X
#ifdef WRITETDDD
X	if (desc->stry) {
X		fprintf(out, "%sSTRY Path \"%s\"\n", tab, desc->stry->path);
X		fprintf(out, "%sSTRY Translate", tab); send_XYZ(&desc->stry->tran);
X		fprintf(out, "%sSTRY Rotate   ", tab); send_XYZ(&desc->stry->rota);
X		fprintf(out, "%sSTRY Scale    ", tab); send_XYZ(&desc->stry->scal);
X		i = desc->stry->info;
X		strin[0] = '\0';
X		if (i&(1<<0))  strcat(strin, " ABS_TRA");
X		if (i&(1<<1))  strcat(strin, " ABS_ROT");
X		if (i&(1<<2))  strcat(strin, " ABS_SCL");
X		if (i&(1<<4))  strcat(strin, " LOC_TRA");
X		if (i&(1<<5))  strcat(strin, " LOC_ROT");
X		if (i&(1<<6))  strcat(strin, " LOC_SCL");
X		if (i&(1<<8))  strcat(strin, " X_ALIGN");
X		if (i&(1<<9))  strcat(strin, " Y_ALIGN");
X		if (i&(1<<10)) strcat(strin, " Z_ALIGN");
X		if (i&(1<<12)) strcat(strin, " FOLLOW_ME");
X		fprintf(out, "%sSTRY Info%s\n", tab, strin);
X	}
#endif
X
SKIP_REST_LIGHT:
X
X	cur_objnum++;
X	prntline = 0;
X	process_TOBJ();
}
X
SHAR_EOF
chmod 0644 writepov.c ||
echo 'restore of writepov.c failed'
Wc_c="`wc -c < 'writepov.c'`"
test 15760 -eq "$Wc_c" ||
	echo 'writepov.c: original size 15760, current size' "$Wc_c"
fi
# ============= writeps.c ==============
if test -f 'writeps.c' -a X"$1" != X"-c"; then
	echo 'x - skipping writeps.c (File already exists)'
else
echo 'x - extracting writeps.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'writeps.c' &&
/* writeps.c - routines to output PostScript representation of object
X *           - using TTDDDLIB by Glenn M. Lewis - 7/23/91
X */
X
static char rcs_id[] = "$Id: writeps.c,v 1.15 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include "ttdddlib.h"
X
double XSIZE = 8.5;
double YSIZE = 11.0;
#define EXTRASPACE 0.95
#define MARGIN	(0.25)	/* On each side of the page */
#define PPI	(72.0)
#define COS60	(0.5)
#define COS30	(0.8660)
X
static void write_PS_header();
static void draw_PS_view();
static void render_PS_object();
X
static FILE *out;
static WORLD *world;
static MBB mbb;
static double xsize, ysize;
static int view;
static double xoffset, yoffset, scale, ybottom;
X
void calculate_MBB_world(world)
WORLD *world;
{
X	register OBJECT *obj;
X
X	if (!world) return;
X
X	/* Determine the extent of the world object */
X	mbb.minx = mbb.miny = mbb.minz =  1.0e10;
X	mbb.maxx = mbb.maxy = mbb.maxz = -1.0e10;
X	for (obj=world->object; obj; obj=obj->next) {
X		calculate_MBB(obj);
X		if (!obj->user) continue;
X		if (((MBB*)obj->user)->minx<mbb.minx) mbb.minx=((MBB*)obj->user)->minx;
X		if (((MBB*)obj->user)->miny<mbb.miny) mbb.miny=((MBB*)obj->user)->miny;
X		if (((MBB*)obj->user)->minz<mbb.minz) mbb.minz=((MBB*)obj->user)->minz;
X		if (((MBB*)obj->user)->maxx>mbb.maxx) mbb.maxx=((MBB*)obj->user)->maxx;
X		if (((MBB*)obj->user)->maxy>mbb.maxy) mbb.maxy=((MBB*)obj->user)->maxy;
X		if (((MBB*)obj->user)->maxz>mbb.maxz) mbb.maxz=((MBB*)obj->user)->maxz;
X	}
X	world->user = (void*)&mbb;
}
X
int write_PostScript(object, file, selected_view)
WORLD *object;
FILE *file;
int selected_view;
{
X	double llx, lly;
X	register OBJECT *obj;
X	if (!(out = file)) return(0);		/* File not open */
X	if (!(world = object)) return(0);	/* No object */
X
X	calculate_MBB_world(world);
X
#ifdef DEBUG
X	fprintf(stderr, "MBB: (%g,%g,%g)-(%g,%g,%g)\n",
X		mbb.minx, mbb.miny, mbb.minz,
X		mbb.maxx, mbb.maxy, mbb.maxz);
#endif
X
X	write_PS_header();
X	if (selected_view==VIEW_ALL_FOUR) {
X		for (view=0; view<4; view++) {
X			llx = ((view&0x02) ? XSIZE/2.0 : MARGIN) * PPI;
X			lly = ((view&0x01) ? MARGIN : YSIZE/2.0) * PPI;
X			xsize = PPI*(XSIZE/2.0 - MARGIN);
X			ysize = PPI*(YSIZE/2.0 - MARGIN);
X			fprintf(out, "gsave\n0.1 setlinewidth\n%g %g translate\n", llx, lly);
X			draw_PS_view();
X			fprintf(out, "grestore\n");
X		}
X	} else {
X		xsize = PPI*(XSIZE - 2.0*MARGIN);
X		ysize = PPI*(YSIZE - 2.0*MARGIN);
X		fprintf(out,"0.1 setlinewidth\n%g %g translate\n",PPI*MARGIN,PPI*MARGIN);
X		view=selected_view;
X		draw_PS_view();
X	}
X	fprintf(out, "showpage\n");
X	return(1);
}
X
void calculate_MBB(obj)
OBJECT *obj;
{
X	OBJECT *child;
X	register XYZ_st *p;
X	register int i;
X	MBB *mbb;
X	double x, y, z;
X
X	if (!obj) return;
X	if (!obj->desc && !obj->child) return;	/* Not an object */
X	if (obj->user) { free((char*)obj->user); obj->user=0; }
X
X	if (!(mbb = (MBB*)malloc(sizeof(MBB)))) {
X		fputs("Out of memory", out); exit(-1); }
X	mbb->minx = mbb->miny = mbb->minz =  1.0e10;
X	mbb->maxx = mbb->maxy = mbb->maxz = -1.0e10;
X
X	/* Account for children... */
X	for (child=obj->child; child; child=child->next) {
X		calculate_MBB(child);
X		if (!child->user) continue;
X		if (((MBB*)child->user)->minx < mbb->minx)
X			mbb->minx = ((MBB*)child->user)->minx;
X		if (((MBB*)child->user)->miny < mbb->miny)
X			mbb->miny = ((MBB*)child->user)->miny;
X		if (((MBB*)child->user)->minz < mbb->minz)
X			mbb->minz = ((MBB*)child->user)->minz;
X		if (((MBB*)child->user)->maxx > mbb->maxx)
X			mbb->maxx = ((MBB*)child->user)->maxx;
X		if (((MBB*)child->user)->maxy > mbb->maxy)
X			mbb->maxy = ((MBB*)child->user)->maxy;
X		if (((MBB*)child->user)->maxz > mbb->maxz)
X			mbb->maxz = ((MBB*)child->user)->maxz;
X	}
X
X	x = y = z = 0.0;
/*
X	if (obj->desc->posi) {
X		x = obj->desc->posi->val[0];
X		y = obj->desc->posi->val[1];
X		z = obj->desc->posi->val[2];
X		fprintf(out, "position: %lx (%g,%g,%g)\n", (unsigned long)obj,x,y,z);
X	}
*/
X	for (p=obj->desc->pnts,i=obj->desc->pcount; i--; p++) {
X		if (p->val[0]-x < mbb->minx) mbb->minx = p->val[0]-x;
X		if (p->val[1]-y < mbb->miny) mbb->miny = p->val[1]-y;
X		if (p->val[2]-z < mbb->minz) mbb->minz = p->val[2]-z;
X		if (p->val[0]-x > mbb->maxx) mbb->maxx = p->val[0]-x;
X		if (p->val[1]-y > mbb->maxy) mbb->maxy = p->val[1]-y;
X		if (p->val[2]-z > mbb->maxz) mbb->maxz = p->val[2]-z;
X	}
X	obj->user = (void *)mbb;
#ifdef DEBUG
X	fprintf(stderr, "MBB: %lx child:%lx next:%lx (%g,%g,%g)-(%g,%g,%g)\n",
X		(unsigned long)obj,
X		(unsigned long)obj->child,
X		(unsigned long)obj->next,
X		mbb->minx, mbb->miny, mbb->minz,
X		mbb->maxx, mbb->maxy, mbb->maxz);
#endif
}
X
static void write_PS_header()
{
X	fputs("%! PS-Adobe-2.0 EPSF-1.2\n", out);
X	fprintf(out, "%%%%BoundingBox: %g %g %g %g\n",
X		PPI*MARGIN, PPI*MARGIN, PPI*(XSIZE-2.0*MARGIN), PPI*(YSIZE-2.0*MARGIN));
X	fputs("%%Creator: TTDDDLIB by Glenn M. Lewis\n", out);
X	fputs("%%EndComments\n%%BeginSetup\n", out);
X	fputs("/M {moveto} bind def\n", out);
X	fputs("/D {lineto} bind def\n", out);
X	fputs("/S {stroke} bind def\n", out);
X	fputs("%%EndSetup\n", out);
}
X
static void draw_PS_view()
{
X	double xratio, yratio, zratio;
X	OBJECT *obj;
X	fprintf(out, "0 0 M %g 0 D %g %g D 0 %g D 0 0 D S\n",
X		xsize, xsize, ysize, ysize);
X
X	if (mbb.maxx-mbb.minx>0.0) xratio=1.0/(mbb.maxx-mbb.minx); else xratio=1.0;
X	if (mbb.maxy-mbb.miny>0.0) yratio=1.0/(mbb.maxy-mbb.miny); else yratio=1.0;
X	if (mbb.maxz-mbb.minz>0.0) zratio=1.0/(mbb.maxz-mbb.minz); else zratio=1.0;
X	scale = (ysize*yratio < xsize*yratio ? ysize*yratio : xsize*yratio);
X	scale = (scale        < ysize*zratio ? scale        : ysize*zratio);
X	scale = (scale        < xsize*xratio ? scale        : xsize*xratio);
X	/* Scale makes it fit exactly into the area.  Expand it a little */
X	scale *= EXTRASPACE;
X
X	switch(view) {
X		case VIEW_TOP:
X			fputs("% Top view\n", out);
X			xoffset = (xsize-scale/xratio)/2.0;
X			yoffset = (ysize-scale/yratio)/2.0;
X			break;
X		case VIEW_FRONT:
X			fputs("% Front view\n", out);
X			xoffset = (xsize-scale/xratio)/2.0;
X			yoffset = (ysize-scale/zratio)/2.0;
X			break;
X		case VIEW_ISO:
X			fputs("% Isometric view\n", out);
X			xratio = (mbb.maxx-mbb.minx)*COS30+(mbb.maxy-mbb.miny)*COS30;
X			if (xratio>0.0) xratio = 1.0/xratio; else xratio=1.0;
X			ybottom = -(mbb.maxx-mbb.minx)*COS60;
X			yratio = (mbb.maxz-mbb.minz)+(mbb.maxy-mbb.miny)*COS60	/* Top */
X					 - ybottom;
X			if (yratio>0.0) yratio = 1.0/yratio; else yratio=1.0;
X			scale = (xsize*xratio < ysize*yratio ? xsize*xratio : ysize*yratio);
X			scale *= EXTRASPACE;
X			xoffset = (xsize-scale/xratio)/2.0;
X			yoffset = (ysize-scale/yratio)/2.0;
X			break;
X		case VIEW_RIGHT:
X			fputs("% Right view\n", out);
X			xoffset = (xsize-scale/yratio)/2.0;
X			yoffset = (ysize-scale/zratio)/2.0;
X			break;
X	}
X	for (obj=world->object; obj; obj=obj->next)
X		render_PS_object(obj);
}
X
static void render_PS_object(obj)
register OBJECT *obj;
{
X	register UWORD *f;
X	register OBJECT *op;
X	register int i, j;
X	int p[3];
X	double x[3], y[3];
X
X	if (!obj->desc) return;
X	for (op=obj->child; op; op=op->next)	/* render children first */
X		render_PS_object(op);
X	
X	/* Now, the meat... */
X	if (obj->desc->shap && obj->desc->shap[1]!=0) return;	/* A lamp */
X	if (!obj->desc->edge || !obj->desc->pnts || !obj->desc->face) return;
X	for (f=obj->desc->face,i=obj->desc->fcount; i--; f+=3) {
X		p[0] = obj->desc->edge[((*f)<<1)];
X		p[1] = obj->desc->edge[((*f)<<1)+1];
X		if (obj->desc->edge[((f[1])<<1)] == p[0] ||
X			obj->desc->edge[((f[1])<<1)] == p[1])
X			p[2] = obj->desc->edge[((f[1])<<1)+1];
X		else
X			p[2] = obj->desc->edge[((f[1])<<1)];
X		switch(view) {
X			case VIEW_TOP:
X				for (j=3; j--; ) {
X					x[j] = obj->desc->pnts[p[j]].val[0]-mbb.minx;
X					y[j] = obj->desc->pnts[p[j]].val[1]-mbb.miny;
X				}
X				break;
X			case VIEW_FRONT:
X				for (j=3; j--; ) {
X					x[j] = obj->desc->pnts[p[j]].val[0]-mbb.minx;
X					y[j] = obj->desc->pnts[p[j]].val[2]-mbb.minz;
X				}
X				break;
X			case VIEW_ISO:
X				for (j=3; j--; ) {
X					x[j] = (obj->desc->pnts[p[j]].val[0]-mbb.minx)*COS30
X						  +(obj->desc->pnts[p[j]].val[1]-mbb.miny)*COS30;
X					y[j] = (obj->desc->pnts[p[j]].val[2]-mbb.minz)
X						  -(obj->desc->pnts[p[j]].val[0]-mbb.minx)*COS60
X						  +(obj->desc->pnts[p[j]].val[1]-mbb.miny)*COS60
X						  - ybottom;
X				}
X				break;
X			case VIEW_RIGHT:
X				for (j=3; j--; ) {
X					x[j] = obj->desc->pnts[p[j]].val[1]-mbb.miny;
X					y[j] = obj->desc->pnts[p[j]].val[2]-mbb.minz;
X				}
X				break;
X		}
X		if (x[0]==x[1] && x[1]==x[2] && y[0]==y[1] && y[1]==y[2]) continue;
X		fprintf(out, "%0.2lf %0.2lf M ", xoffset+scale*x[0],yoffset+scale*y[0]);
X		if (!(x[0]==x[1] && y[0]==y[1])) {
X			fprintf(out, "%0.2lf %0.2lf D ",
X				xoffset+scale*x[1], yoffset+scale*y[1]);
X		}
X		if (!(x[0]==x[2] && y[0]==y[2]) && !(x[1]==x[2] && y[1]==y[2])) {
X			fprintf(out, "%0.2lf %0.2lf D ",
X				xoffset+scale*x[2], yoffset+scale*y[2]);
X		}
X		fprintf(out, "%0.2lf %0.2lf D S\n",
X			xoffset+scale*x[0],yoffset+scale*y[0]);
X	}
}
SHAR_EOF
chmod 0644 writeps.c ||
echo 'restore of writeps.c failed'
Wc_c="`wc -c < 'writeps.c'`"
test 8813 -eq "$Wc_c" ||
	echo 'writeps.c: original size 8813, current size' "$Wc_c"
fi
# ============= writeray.c ==============
if test -f 'writeray.c' -a X"$1" != X"-c"; then
	echo 'x - skipping writeray.c (File already exists)'
else
echo 'x - extracting writeray.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'writeray.c' &&
/* writeray.c - dump the internal database to a Rayshade 4.0 input file
X *            - written by Glenn M. Lewis - 7/22/91
X */
X
static char rcs_id[] = "$Id: writeray.c,v 1.9 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include <ctype.h>
#include "ttdddlib.h"
X
static void process_DESC();
static void process_EXTR();
static void process_INFO();
static void process_OBJ();
X
/* Two-space tabs */
#define TABSTOP "  "
X
static FILE *out;
static char tab[133];
static int num_OBJ, num_DESC, num_TOBJ;
static int cur_level, cur_objnum;
static int prntline;
X
static struct save_hier {
X	int objnum;
X	struct save_hier *next;
} *root = 0;
typedef struct save_hier HIER;
X
/* Here are a few necessary utilities */
X
static void indent()
{
X	strcat(tab, TABSTOP);
}
X
static void outdent()
{
X	register int i = strlen(tab) - strlen(TABSTOP);
X	if (i<0) {
X		fprintf(stderr, "Whoa, Glenn!  You blew it!\n");
X		tab[0] = '\0';
X		return;
X	}
X	tab[i] = '\0';
}
X
static void send_XYZ(f)			/* Print a common string */
XXYZ_st *f;
{
/* I noticed that with a Ultrix C compiler, these in-line function calls were
X * not executed in the order specified.  Since I want this code to be portable,
X * and since some C compilers are broken, I seperated the following lines.
X * This goes for *all* in-line function calls in this source code.
X */
X	fprintf(out, " %g",   f->val[0]);
X	fprintf(out, " %g",   f->val[1]);
X	fprintf(out, " %g\n", f->val[2]);
}
X
static void send_RGB(rgb)			/* Print a common string */
RGB_st *rgb;
{
X	fprintf(out, " %g",   ((double)rgb->val[0])/255.0);
X	fprintf(out, " %g",   ((double)rgb->val[1])/255.0);
X	fprintf(out, " %g\n", ((double)rgb->val[2])/255.0);
}
X
/********************/
/* The MAIN section */
/********************/
X
int write_Rayshade(world, file)
WORLD *world;
FILE *file;
{
X	register OBJECT *o;
X
X	if (!(out=file) || !world) return(0);	/* File not open */
X
X	tab[0] = '\0';
X	num_OBJ = num_DESC = num_TOBJ = 0;
X
X	fputs("/* TTDDD library - Written by Glenn M. Lewis - 7/22/91*/\n\n", out);
X	if (world->info) process_INFO(world->info);
X	for (o=world->object; o; o=o->next)
X		process_OBJ(o);
X	return(1);
}
X
static void process_INFO(info)
INFO *info;
{
X	fprintf(out, "%s/* INFO Begin */\n", tab);
X	indent();
/*
X	for (i=0; i<8; i++)
X		if (info->brsh[i][0])
X			fprintf(out, "%sBRSH[%d]=\"%s\"\n", tab, i, info->brsh[i]);
X
X	for (i=0; i<8; i++)
X		if (info->stnc[i][0])
X			fprintf(out, "%sSTNC[%d]=\"%s\"\n", tab, i, info->stnc[i]);
X
X	for (i=0; i<8; i++)
X		if (info->txtr[i][0])
X			fprintf(out, "%sTXTR[%d]=\"%s\"\n", tab, i, info->txtr[i]);
*/
X
X	if (info->obsv) {
X		fprintf(out, "%seyep", tab); send_XYZ(&info->obsv->came);
X		fprintf(out, "%s/* OBSV Rotate", tab); send_XYZ(&info->obsv->rota);
X		fprintf(out, "*/%sfocaldist  %g\n", tab, info->obsv->foca);
X	}
X
/*	if (info->otrk[0]) fprintf(out, "%sOTRK \"%s\"\n", tab, info->otrk);	*/
X
/*
X	if (info->ostr) {
X		if (info->ostr->path[0])
X			fprintf(out, "%sOSTR Path \"%s\"\n", tab, info->ostr->path);
X		fprintf(out, "%sOSTR Translate", tab); send_XYZ(&info->ostr->tran);
X		fprintf(out, "%sOSTR Rotate   ", tab); send_XYZ(&info->ostr->rota);
X		fprintf(out, "%sOSTR Scale    ", tab); send_XYZ(&info->ostr->scal);
X		i = info->ostr->info;
X		strin[0] = '\0';
X		if (i&(1<<0))  strcat(strin, " ABS_TRA");
X		if (i&(1<<1))  strcat(strin, " ABS_ROT");
X		if (i&(1<<2))  strcat(strin, " ABS_SCL");
X		if (i&(1<<4))  strcat(strin, " LOC_TRA");
X		if (i&(1<<5))  strcat(strin, " LOC_ROT");
X		if (i&(1<<6))  strcat(strin, " LOC_SCL");
X		if (i&(1<<8))  strcat(strin, " X_ALIGN");
X		if (i&(1<<9))  strcat(strin, " Y_ALIGN");
X		if (i&(1<<10)) strcat(strin, " Z_ALIGN");
X		if (i&(1<<12)) strcat(strin, " FOLLOW_ME");
X		fprintf(out, "%sOSTR Info%s\n", tab, strin);
X	}
*/
X
X	if (info->fade) {
X		fprintf(out, "%s/* FADE FadeAt %g*/\n", tab, info->fade->at);
X		fprintf(out, "%s/* FADE FadeBy %g*/\n", tab, info->fade->by);
X		fprintf(out, "%s/* FADE FadeTo", tab); send_RGB(&info->fade->to);
X		fprintf(out, "*/\n");
X	}
X
X	if (info->skyc) {
X		fprintf(out, "%s/* SKYX Horizon", tab); send_RGB(&info->skyc->hori);
X		fprintf(out, "*/\n");
X		fprintf(out, "%s/* SKYC Zenith ", tab); send_RGB(&info->skyc->zeni);
X		fprintf(out, "*/\n");
X	}
X
X	if (info->ambi)
X		{ fprintf(out, "%sbackground", tab); send_RGB(info->ambi); }
X
/*
X	if (info->glb0)
X		for (i=0; i<8; i++)
X			fprintf(out, "%sGLB0[%d]=%u\n", tab, i, info->glb0[i]);
*/
X
X	outdent();
X	fprintf(out, "%s/* End INFO */\n", tab);
}
X
static void process_OBJ(obj)
register OBJECT *obj;
{
X	register HIER *p;
X	num_OBJ++;
X	fprintf(out, "%s/* OBJ Begin \"Hierarchy %d\" */\n", tab, num_OBJ);
X	num_DESC = num_TOBJ = 0;		/* Reset counters */
X	cur_level = 0;
X	cur_objnum = 1;
X	prntline = 1;
X
X	if (obj->extr) process_EXTR(obj->extr);
X	else process_DESC(obj);
X
X	while (root) {				/* This should happen at most once. */
X		p = root->next;
X		free((char *)root);		/* Delete this from list */
X		root = p;
X		outdent();
X	}
X
X	fprintf(out, "%s/* End OBJ   \"Hierarchy %d\" */\n", tab, num_OBJ);
}
X
static int process_TOBJ()
{
X	register HIER *p;
X	if (num_DESC-num_TOBJ < cur_level) {	/* Pop old level off HIER */
X		cur_level--;
X		cur_objnum = root->objnum;
X		p = root->next;
X		free((char *)root);	/* Delete from list */
X		root = p;
X		outdent();	/* Pretty file formatting */
X	}
X	fprintf(out, "%s/* TOBJ       \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum-1, num_DESC-num_TOBJ, num_OBJ);
X	num_TOBJ++;
X	prntline = 1;
}
X
static void process_EXTR(extr)
EXTR *extr;
{
X	register int i;
X
X	if (!prntline) fprintf(out, "\n");	/* Print one anyway */
X	indent();
X	num_DESC++;
X
X	fprintf(out, "%s/* EXTR Begin \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X	indent();
X	fprintf(out, "%s/* LOAD \"%s\" */\n", tab, extr->filename);
X	fprintf(out, "#include \"%s\"\n", extr->filename);
X	fprintf(out, "%stranslate", tab); send_XYZ(&extr->mtrx.tran);
X	fprintf(out, "%sscale    ", tab); send_XYZ(&extr->mtrx.scal);
X	fprintf(out, "%stransform", tab);
X	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota1.val[i]);
X	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota2.val[i]);
X	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota3.val[i]);
X	fprintf(out, "\n");
X
X	outdent();
X	fprintf(out, "%s/* End EXTR   \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X
X	num_TOBJ++;
X	cur_objnum++;
X	outdent();
X	prntline = 1;
}
X
static void process_DESC(object)
OBJECT *object;
{
X	register int i;
X	register XYZ_st *p1, *p2, *p3;
X	register HIER *p;
X	register OBJECT *obj;
X	register DESC *desc = object->desc;
X
X	num_DESC++;
X	if (num_DESC-num_TOBJ > cur_level) {	/* Push new level in HIER */
X		if (!prntline) fprintf(out, "\n");	/* Print one anyway */
X		if (!(p = (HIER*)malloc(sizeof(HIER)))) {
X			fprintf(stderr, "ERROR!  Out of memory.\n*** ABORT ***\n");
X			exit(20);
X		}
X		p->next = root;		/* Insert into list */
X		root = p;
X		root->objnum = cur_objnum;
X		cur_level++;
X		cur_objnum = 1;
X		indent();	/* Pretty file formatting */
X	}
X
X	if (desc->shap && desc->shap[1]) {
X		fprintf(out, "%slight", tab);
X		if (desc->colr) send_RGB(desc->colr); else fprintf(out, " 1.0 ");
X		if (desc->shap[1]==1)	/* Sunlight */
X			fprintf(out, "directional %g %g %g\n",
X				-(desc->posi->val[0]),
X				-(desc->posi->val[1]),
X				-(desc->posi->val[2]));
X		else	/* Like a lamp */
X			fprintf(out, "point %g %g %g\n",
X				desc->posi->val[0],
X				desc->posi->val[1],
X				desc->posi->val[2]);
X		goto SKIP_REST_LIGHT;
X	}
X
X	fprintf(out,"%s/* DESC Begin \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X	fprintf(out, "%sgrid 20 20 20\n", tab);
X	indent();
X
X	if (desc->name[0]) fprintf(out, "%s/* name \"%s\" */\n", tab, desc->name);
X
X	if (desc->shap) {
X		fprintf(out, "%s/* SHAP Shape = %u */\n", tab, desc->shap[0]);
X		if (desc->shap==0 && !desc->shap[1]) {	/* Sphere */
X			fprintf(out, "%ssphere %g", tab, desc->size->val[0]);
X			send_XYZ(desc->posi);
X			goto SKIP_REST;
X		}
X		fprintf(out, "%s/* SHAP Lamp  = %u */\n", tab, desc->shap[1]);
X	}
X
/*
X	if (desc->axis) {
X		fprintf(out, "%sAXIS XAxis", tab); send_XYZ(&desc->axis->xaxi);
X		fprintf(out, "%sAXIS YAxis", tab); send_XYZ(&desc->axis->yaxi);
X		fprintf(out, "%sAXIS ZAxis", tab); send_XYZ(&desc->axis->zaxi);
X	}
X
X	if (desc->size)
X		{ fprintf(out, "%sSIZE", tab); send_XYZ(desc->size); }
X
X	if (desc->pcount) {
X		fprintf(out, "%sPNTS PCount %u\n", tab, desc->pcount);
X		for (i=0; i<desc->pcount; i++) {
X			fprintf(out, "%sPNTS Point[%d]", tab, i);
X			send_XYZ(&desc->pnts[i]);
X		}
X	}
X
X	if (desc->ecount) {
X		fprintf(out, "%sEDGE ECount %u\n", tab, desc->ecount);
X		for (i=0; i<desc->ecount; i++) {
X			fprintf(out, "%sEDGE Edge[%d] %u %u\n", tab, i,
X				desc->edge[i<<1], desc->edge[(i<<1)+1]);
X		}
X	}
*/
X
X	if (desc->fcount && desc->ecount && desc->pcount) {
X		fprintf(out, "%s/* FACE TCount %u */\n", tab, desc->fcount);
X		for (i=0; i<desc->fcount; i++) {
/*			fprintf(out, "%sFACE Connect[%u] %u %u %u\n", tab, i,
X				desc->face[i*3], desc->face[i*3+1], desc->face[i*3+2]);
*/
X			/* First check and see if the triangle is degenerate */
X			p1 = &desc->pnts[desc->edge[(desc->face[i*3])<<1]];
X			p2 = &desc->pnts[desc->edge[((desc->face[i*3])<<1)+1]];
X			if (desc->edge[(desc->face[i*3+2])<<1] ==
X				desc->edge[(desc->face[i*3])<<1] ||
X				desc->edge[(desc->face[i*3+2])<<1] ==
X				desc->edge[((desc->face[i*3])<<1)+1])
X				p3 = &desc->pnts[desc->edge[((desc->face[i*3+2])<<1)+1]];
X			else
X				p3 = &desc->pnts[desc->edge[(desc->face[i*3+2])<<1]];
#define X val[0]
#define Y val[1]
#define Z val[2]
X			if (!((p1->X==p2->X && p1->Y==p2->Y && p1->Z==p2->Z) ||
X				  (p1->X==p3->X && p1->Y==p3->Y && p1->Z==p3->Z) ||
X				  (p2->X==p3->X && p2->Y==p3->Y && p2->Z==p3->Z))) {
X				fprintf(out, "%striangle", tab);
X				send_XYZ(p1);
X				send_XYZ(p2);
X				send_XYZ(p3);
X			}
X		}
X	}
X
SKIP_REST:
X
X	for (obj=object->child; obj; obj=obj->next) {
X		if (obj->extr) process_EXTR(obj->extr);
X		else process_DESC(obj);
X	}
X
X	outdent();
X	fprintf(out, "%send /* End DESC   \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X
X	if (desc->posi)
X		{ fprintf(out, "%stranslate", tab); send_XYZ(desc->posi); }
X
X	if (desc->colr) { fprintf(out, "%sambient", tab); send_RGB(desc->colr); }
X
X	if (desc->refl) { fprintf(out, "%sspecular", tab); send_RGB(desc->refl); }
X
X	if (desc->tran) { fprintf(out, "%s/* TRAN", tab); send_RGB(desc->tran);
X		fprintf(out, "*/\n");
X	}
X
#ifdef WRITETTDDD
X	if (desc->fcount) {
X		fprintf(out, "%sCLST Count %u\n", tab, i);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->colr) {
X				if (desc->clst[i*3  ]==desc->colr->val[0] &&
X					desc->clst[i*3+1]==desc->colr->val[1] &&
X					desc->clst[i*3+2]==desc->colr->val[2]) continue; /* Skip */
X			} else {
X				if (desc->clst[i*3  ]==255 &&
X					desc->clst[i*3+1]==255 &&
X					desc->clst[i*3+2]==255) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sCLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->clst[i*3]);
X		}
X		fprintf(out, "%sRLST Count %u\n", tab, i);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->refl) {
X				if (desc->rlst[i*3  ]==desc->refl->val[0] &&
X					desc->rlst[i*3+1]==desc->refl->val[1] &&
X					desc->rlst[i*3+2]==desc->refl->val[2]) continue; /* Skip */
X			} else {
X				if (desc->rlst[i*3  ]==0 &&
X					desc->rlst[i*3+1]==0 &&
X					desc->rlst[i*3+2]==0) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sRLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->rlst[i*3]);
X		}
X		fprintf(out, "%sTLST Count %u\n", tab, i);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->tran) {
X				if (desc->tlst[i*3  ]==desc->tran->val[0] &&
X					desc->tlst[i*3+1]==desc->tran->val[1] &&
X					desc->tlst[i*3+2]==desc->tran->val[2]) continue; /* Skip */
X			} else {
X				if (desc->tlst[i*3  ]==0 &&
X					desc->tlst[i*3+1]==0 &&
X					desc->tlst[i*3+2]==0) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sTLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->tlst[i*3]);
X		}
X	}
#endif
X
X	if (desc->tpar) {
X		for (i=0; i<16; i++)
X			fprintf(out, "%s/* TPAR[%u]=%g */\n", tab, i, desc->tpar[i]);
X	}
X
X	if (desc->surf) {
X		for (i=0; i<5; i++)
X			fprintf(out, "%s/* SURF[%u]=%d */\n", tab, i, desc->surf[i]);
X	}
X
X	if (desc->mttr) {
X		fprintf(out, "%s/* MTTR Type =%u */\n", tab, desc->mttr->type);
X		fprintf(out, "%s/* MTTR Index=%g */\n", tab, (double)desc->mttr->indx);
X	}
X
X	if (desc->spec) {
X		fprintf(out, "%s/* SPEC Spec=%u */\n", tab, desc->spec[0]);
X		fprintf(out, "%s/* SPEC Hard=%u */\n", tab, desc->spec[1]);
X	}
X
X	if (desc->prp0) {
X		for (i=0; i<6; i++)
X			fprintf(out, "%s/* PRP0[%u]=%u */\n", tab, i, desc->prp0[i]);
X	}
X
X	if (desc->ints)
X		fprintf(out, "%s/* INTS=%g */\n", tab, desc->ints);
X
#ifdef WRITETDDD
X	if (desc->stry) {
X		fprintf(out, "%sSTRY Path \"%s\"\n", tab, desc->stry->path);
X		fprintf(out, "%sSTRY Translate", tab); send_XYZ(&desc->stry->tran);
X		fprintf(out, "%sSTRY Rotate   ", tab); send_XYZ(&desc->stry->rota);
X		fprintf(out, "%sSTRY Scale    ", tab); send_XYZ(&desc->stry->scal);
X		i = desc->stry->info;
X		strin[0] = '\0';
X		if (i&(1<<0))  strcat(strin, " ABS_TRA");
X		if (i&(1<<1))  strcat(strin, " ABS_ROT");
X		if (i&(1<<2))  strcat(strin, " ABS_SCL");
X		if (i&(1<<4))  strcat(strin, " LOC_TRA");
X		if (i&(1<<5))  strcat(strin, " LOC_ROT");
X		if (i&(1<<6))  strcat(strin, " LOC_SCL");
X		if (i&(1<<8))  strcat(strin, " X_ALIGN");
X		if (i&(1<<9))  strcat(strin, " Y_ALIGN");
X		if (i&(1<<10)) strcat(strin, " Z_ALIGN");
X		if (i&(1<<12)) strcat(strin, " FOLLOW_ME");
X		fprintf(out, "%sSTRY Info%s\n", tab, strin);
X	}
#endif
X
SKIP_REST_LIGHT:
X
X	cur_objnum++;
X	prntline = 0;
X	process_TOBJ();
}
X
SHAR_EOF
chmod 0644 writeray.c ||
echo 'restore of writeray.c failed'
Wc_c="`wc -c < 'writeray.c'`"
test 13541 -eq "$Wc_c" ||
	echo 'writeray.c: original size 13541, current size' "$Wc_c"
fi
# ============= writevort.c ==============
if test -f 'writevort.c' -a X"$1" != X"-c"; then
	echo 'x - skipping writevort.c (File already exists)'
else
echo 'x - extracting writevort.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'writevort.c' &&
/* writevort.c - dump the internal database to a Vort input file
X *             - written by Glenn M. Lewis - 10/11/91
X */
X
static char rcs_id[] = "$Id: writevort.c,v 1.9 1992/07/29 20:46:07 glewis Exp $";
X
#include <stdio.h>
#include <ctype.h>
#include "ttdddlib.h"
X
static void process_DESC();
static void process_EXTR();
static void process_INFO();
static void process_OBJ();
X
/* Two-space tabs */
#define TABSTOP "  "
X
static FILE *out;
static char tab[133];
static int num_OBJ, num_DESC, num_TOBJ;
static int cur_level, cur_objnum;
static int prntline;
X
static struct save_hier {
X	int objnum;
X	struct save_hier *next;
} *root = 0;
typedef struct save_hier HIER;
X
/* Here are a few necessary utilities */
X
static void indent()
{
X	strcat(tab, TABSTOP);
}
X
static void outdent()
{
X	register int i = strlen(tab) - strlen(TABSTOP);
X	if (i<0) {
X		fprintf(stderr, "Whoa, Glenn!  You blew it!\n");
X		tab[0] = '\0';
X		return;
X	}
X	tab[i] = '\0';
}
X
static void send_XYZ(f)			/* Print a common string */
XXYZ_st *f;
{
X	fprintf(out, " %g,%g,%g ", f->val[0], f->val[1], f->val[2]);
}
X
static void send_RGB(rgb)			/* Print a common string */
RGB_st *rgb;
{
X	fprintf(out, " %g,%g,%g ", ((double)rgb->val[0])/255.0,
X		((double)rgb->val[1])/255.0,
X		((double)rgb->val[2])/255.0);
}
X
/********************/
/* The MAIN section */
/********************/
X
int write_Vort(world, file)
WORLD *world;
FILE *file;
{
X	register OBJECT *o;
X
X	if (!(out=file) || !world) return(0);	/* File not open */
X
X	tab[0] = '\0';
X	num_OBJ = num_DESC = num_TOBJ = 0;
X
X	fputs("/* TTDDD library - Written by Glenn M. Lewis - 10/11/91 */\n\n",out);
X	fputs("maxhitlevel 1\n", out);
X	fputs("light {\n  color 1,1,1\n  direction(-1,1,-1)\n}\n", out);
X	fputs("up(0,0,1)\nlookat(10,-100,100,0,0,0,0)\n", out);
X
X	if (world->info) process_INFO(world->info);
X	for (o=world->object; o; o=o->next)
X		process_OBJ(o);
X	return(1);
}
X
static void process_INFO(info)
INFO *info;
{
X	fprintf(out, "%s/* INFO Begin */\n", tab);
X	indent();
/*
X	for (i=0; i<8; i++)
X		if (info->brsh[i][0])
X			fprintf(out, "%sBRSH[%d]=\"%s\"\n", tab, i, info->brsh[i]);
X
X	for (i=0; i<8; i++)
X		if (info->stnc[i][0])
X			fprintf(out, "%sSTNC[%d]=\"%s\"\n", tab, i, info->stnc[i]);
X
X	for (i=0; i<8; i++)
X		if (info->txtr[i][0])
X			fprintf(out, "%sTXTR[%d]=\"%s\"\n", tab, i, info->txtr[i]);
*/
X
X	if (info->obsv) {
X		fprintf(out, "%slookat(", tab); send_XYZ(&info->obsv->came);
X		fprintf(out, "%s/* OBSV Rotate", tab); send_XYZ(&info->obsv->rota);
X		fprintf(out, "%s   focaldist  %g */\n", tab, info->obsv->foca);
X		fprintf(out, "%s)", tab);
X	}
X
/*	if (info->otrk[0]) fprintf(out, "%sOTRK \"%s\"\n", tab, info->otrk);	*/
X
/*
X	if (info->ostr) {
X		if (info->ostr->path[0])
X			fprintf(out, "%sOSTR Path \"%s\"\n", tab, info->ostr->path);
X		fprintf(out, "%sOSTR Translate", tab); send_XYZ(&info->ostr->tran);
X		fprintf(out, "%sOSTR Rotate   ", tab); send_XYZ(&info->ostr->rota);
X		fprintf(out, "%sOSTR Scale    ", tab); send_XYZ(&info->ostr->scal);
X		i = info->ostr->info;
X		strin[0] = '\0';
X		if (i&(1<<0))  strcat(strin, " ABS_TRA");
X		if (i&(1<<1))  strcat(strin, " ABS_ROT");
X		if (i&(1<<2))  strcat(strin, " ABS_SCL");
X		if (i&(1<<4))  strcat(strin, " LOC_TRA");
X		if (i&(1<<5))  strcat(strin, " LOC_ROT");
X		if (i&(1<<6))  strcat(strin, " LOC_SCL");
X		if (i&(1<<8))  strcat(strin, " X_ALIGN");
X		if (i&(1<<9))  strcat(strin, " Y_ALIGN");
X		if (i&(1<<10)) strcat(strin, " Z_ALIGN");
X		if (i&(1<<12)) strcat(strin, " FOLLOW_ME");
X		fprintf(out, "%sOSTR Info%s\n", tab, strin);
X	}
*/
X
X	if (info->fade) {
X		fprintf(out, "%s/* FADE FadeAt %g*/\n", tab, info->fade->at);
X		fprintf(out, "%s/* FADE FadeBy %g*/\n", tab, info->fade->by);
X		fprintf(out, "%s/* FADE FadeTo", tab); send_RGB(&info->fade->to);
X		fprintf(out, "*/\n");
X	}
X
X	if (info->skyc) {
X		fprintf(out, "%s/* SKYX Horizon", tab); send_RGB(&info->skyc->hori);
X		fprintf(out, "*/\n");
X		fprintf(out, "%s/* SKYC Zenith ", tab); send_RGB(&info->skyc->zeni);
X		fprintf(out, "*/\n");
X	}
X
X	if (info->ambi)
X		{ fprintf(out, "%sbackground", tab); send_RGB(info->ambi); }
X
/*
X	if (info->glb0)
X		for (i=0; i<8; i++)
X			fprintf(out, "%sGLB0[%d]=%u\n", tab, i, info->glb0[i]);
*/
X
X	outdent();
X	fprintf(out, "%s/* End INFO */\n", tab);
}
X
static void process_OBJ(obj)
register OBJECT *obj;
{
X	register HIER *p;
X	num_OBJ++;
X	fprintf(out, "%s/* OBJ Begin \"Hierarchy %d\" */\n", tab, num_OBJ);
X	num_DESC = num_TOBJ = 0;		/* Reset counters */
X	cur_level = 0;
X	cur_objnum = 1;
X	prntline = 1;
X
X	if (obj->extr) process_EXTR(obj->extr);
X	else process_DESC(obj);
X
X	while (root) {				/* This should happen at most once. */
X		p = root->next;
X		free((char *)root);		/* Delete this from list */
X		root = p;
X		outdent();
X	}
X
X	fprintf(out, "%s/* End OBJ   \"Hierarchy %d\" */\n", tab, num_OBJ);
}
X
static int process_TOBJ()
{
X	register HIER *p;
X	if (num_DESC-num_TOBJ < cur_level) {	/* Pop old level off HIER */
X		cur_level--;
X		cur_objnum = root->objnum;
X		p = root->next;
X		free((char *)root);	/* Delete from list */
X		root = p;
X		outdent();	/* Pretty file formatting */
X	}
X	fprintf(out, "%s}\n", tab);
X	fprintf(out, "%s/* TOBJ       \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum-1, num_DESC-num_TOBJ, num_OBJ);
X	num_TOBJ++;
X	prntline = 1;
}
X
static void process_EXTR(extr)
EXTR *extr;
{
X	if (!prntline) fprintf(out, "\n");	/* Print one anyway */
X	indent();
X	num_DESC++;
X
X	fprintf(out, "%s/* EXTR Begin \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X	fprintf(out, "%scomposite {\n", tab);
X	indent();
X	fprintf(out, "%s/* LOAD \"%s\" */\n", tab, extr->filename);
X	fprintf(out, "include %s\n", extr->filename);
X	fprintf(out, "%stranslate(", tab); send_XYZ(&extr->mtrx.tran);
X	fprintf(out, ")\n%sscale    (", tab); send_XYZ(&extr->mtrx.scal);
X	fprintf(out, "\n%stransform {\n", tab);
X	indent();
X	fprintf(out, "%s%g,%g,%g,",  tab,
X		extr->mtrx.rota1.val[0],
X		extr->mtrx.rota1.val[1],
X		extr->mtrx.rota1.val[2]);
X	fprintf(out, "%s%g,%g,%g,",  tab,
X		extr->mtrx.rota2.val[0],
X		extr->mtrx.rota2.val[1],
X		extr->mtrx.rota2.val[2]);
X	fprintf(out, "%s%g,%g,%g\n", tab,
X		extr->mtrx.rota3.val[0],
X		extr->mtrx.rota3.val[1],
X		extr->mtrx.rota3.val[2]);
X	outdent();
X	fprintf(out, "%s}\n", tab);
X
X	outdent();
X	fprintf(out, "%s}\n", tab);
X	fprintf(out, "%s/* End EXTR   \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X
X	num_TOBJ++;
X	cur_objnum++;
X	outdent();
X	prntline = 1;
}
X
static void process_DESC(object)
OBJECT *object;
{
X	register int i;
X	register HIER *p;
X	register OBJECT *obj;
X	register DESC *desc = object->desc;
X	register int p1, p2, p3;
X
X	num_DESC++;
X	if (num_DESC-num_TOBJ > cur_level) {	/* Push new level in HIER */
X		if (!prntline) fprintf(out, "\n");	/* Print one anyway */
X		if (!(p = (HIER*)malloc(sizeof(HIER)))) {
X			fprintf(stderr, "ERROR!  Out of memory.\n*** ABORT ***\n");
X			exit(20);
X		}
X		p->next = root;		/* Insert into list */
X		root = p;
X		root->objnum = cur_objnum;
X		cur_level++;
X		cur_objnum = 1;
X		indent();	/* Pretty file formatting */
X	}
X
X	fprintf(out, "%s/* DESC Begin \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
/*	fprintf(out, "%sgrid 20 20 20\n", tab);	*/
X	fprintf(out, "%scomposite {\n", tab);
X	indent();
X
X	if (desc->name[0]) fprintf(out, "%s/* name \"%s\" */\n", tab, desc->name);
X
X	if (desc->posi) {
X		fprintf(out, "%stranslate(", tab);
X		send_XYZ(desc->posi);
X		fprintf(out, ")\n");
X	}
X
X	if (desc->colr) {
X		fprintf(out, "%sambient", tab);
X		send_RGB(desc->colr);
X		fprintf(out, "\n");
X	}
X
X	if (desc->refl) {
X		fprintf(out, "%s/* specular", tab);
X		send_RGB(desc->refl);
X		fprintf(out, "*/\n");
X	}
X
X	if (desc->tran) { fprintf(out, "%s/* TRAN", tab); send_RGB(desc->tran);
X		fprintf(out, "*/\n");
X	}
X
#ifdef WRITETTDDD
X	if (desc->fcount) {
X		fprintf(out, "%sCLST Count %u\n", tab, i);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->colr) {
X				if (desc->clst[i*3  ]==desc->colr->val[0] &&
X					desc->clst[i*3+1]==desc->colr->val[1] &&
X					desc->clst[i*3+2]==desc->colr->val[2]) continue; /* Skip */
X			} else {
X				if (desc->clst[i*3  ]==255 &&
X					desc->clst[i*3+1]==255 &&
X					desc->clst[i*3+2]==255) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sCLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->clst[i*3]);
X		}
X		fprintf(out, "%sRLST Count %u\n", tab, i);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->refl) {
X				if (desc->rlst[i*3  ]==desc->refl->val[0] &&
X					desc->rlst[i*3+1]==desc->refl->val[1] &&
X					desc->rlst[i*3+2]==desc->refl->val[2]) continue; /* Skip */
X			} else {
X				if (desc->rlst[i*3  ]==0 &&
X					desc->rlst[i*3+1]==0 &&
X					desc->rlst[i*3+2]==0) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sRLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->rlst[i*3]);
X		}
X		fprintf(out, "%sTLST Count %u\n", tab, i);
X		for (i=0; i<desc->fcount; i++) {
X			if (desc->tran) {
X				if (desc->tlst[i*3  ]==desc->tran->val[0] &&
X					desc->tlst[i*3+1]==desc->tran->val[1] &&
X					desc->tlst[i*3+2]==desc->tran->val[2]) continue; /* Skip */
X			} else {
X				if (desc->tlst[i*3  ]==0 &&
X					desc->tlst[i*3+1]==0 &&
X					desc->tlst[i*3+2]==0) continue;	/* Skip this one */
X			}
X			fprintf(out, "%sTLST Color[%u]", tab, i);
X			send_RGB((RGB_st*)&desc->tlst[i*3]);
X		}
X	}
#endif
X
X	if (desc->tpar) {
X		for (i=0; i<16; i++)
X			fprintf(out, "%s/* TPAR[%u]=%g */\n", tab, i, desc->tpar[i]);
X	}
X
X	if (desc->surf) {
X		for (i=0; i<5; i++)
X			fprintf(out, "%s/* SURF[%u]=%d */\n", tab, i, desc->surf[i]);
X	}
X
X	if (desc->mttr) {
X		fprintf(out, "%s/* MTTR Type =%u */\n", tab, desc->mttr->type);
X		fprintf(out, "%s/* MTTR Index=%g */\n", tab, (double)desc->mttr->indx);
X	}
X
X	if (desc->spec) {
X		fprintf(out, "%s/* SPEC Spec=%u */\n", tab, desc->spec[0]);
X		fprintf(out, "%s/* SPEC Hard=%u */\n", tab, desc->spec[1]);
X	}
X
X	if (desc->prp0) {
X		for (i=0; i<6; i++)
X			fprintf(out, "%s/* PRP0[%u]=%u */\n", tab, i, desc->prp0[i]);
X	}
X
X	if (desc->ints)
X		fprintf(out, "%s/* INTS=%g */\n", tab, desc->ints);
X
#ifdef WRITETDDD
X	if (desc->stry) {
X		fprintf(out, "%sSTRY Path \"%s\"\n", tab, desc->stry->path);
X		fprintf(out, "%sSTRY Translate", tab); send_XYZ(&desc->stry->tran);
X		fprintf(out, "%sSTRY Rotate   ", tab); send_XYZ(&desc->stry->rota);
X		fprintf(out, "%sSTRY Scale    ", tab); send_XYZ(&desc->stry->scal);
X		i = desc->stry->info;
X		strin[0] = '\0';
X		if (i&(1<<0))  strcat(strin, " ABS_TRA");
X		if (i&(1<<1))  strcat(strin, " ABS_ROT");
X		if (i&(1<<2))  strcat(strin, " ABS_SCL");
X		if (i&(1<<4))  strcat(strin, " LOC_TRA");
X		if (i&(1<<5))  strcat(strin, " LOC_ROT");
X		if (i&(1<<6))  strcat(strin, " LOC_SCL");
X		if (i&(1<<8))  strcat(strin, " X_ALIGN");
X		if (i&(1<<9))  strcat(strin, " Y_ALIGN");
X		if (i&(1<<10)) strcat(strin, " Z_ALIGN");
X		if (i&(1<<12)) strcat(strin, " FOLLOW_ME");
X		fprintf(out, "%sSTRY Info%s\n", tab, strin);
X	}
#endif
X
X	if (desc->shap) {
X		fprintf(out, "%s/* SHAP Shape = %u */\n", tab, desc->shap[0]);
X		if (desc->shap==0 && !desc->shap[1]) {	/* Sphere */
X			fprintf(out, "%ssphere {\n", tab);
X			indent();
X			fprintf(out, "%scenter(", tab);
X			send_XYZ(desc->posi);
X			fprintf(out, ")\n%sradius %g\n", tab, desc->size->val[0]);
X			outdent();
X			fprintf(out, "%s}\n", tab);
X			goto SKIP_REST;
X		}
X		fprintf(out, "%s/* SHAP Lamp  = %u */\n", tab, desc->shap[1]);
X		if (desc->shap[1]) {
X			fprintf(out, "%slight {\n", tab);
X			indent();
X			if (desc->colr) {
X				fprintf(out, "%scolor", tab);
X				send_RGB(desc->colr);
X				fprintf(out, "\n");
X			}
X			if (desc->shap[1]==1)	/* Sunlight */
X				fprintf(out, "%sdirection(%g,%g,%g)\n", tab,
X					-(desc->posi->val[0]),
X					-(desc->posi->val[1]),
X					-(desc->posi->val[2]));
X			else	/* Like a lamp */
X				fprintf(out, "%slocation(%g,%g,%g)\n", tab,
X					desc->posi->val[0],
X					desc->posi->val[1],
X					desc->posi->val[2]);
X			outdent();
X			fprintf(out, "%s}\n", tab);
X			goto SKIP_REST;
X		}
X	}
X
/*
X	if (desc->axis) {
X		fprintf(out, "%sAXIS XAxis", tab); send_XYZ(&desc->axis->xaxi);
X		fprintf(out, "%sAXIS YAxis", tab); send_XYZ(&desc->axis->yaxi);
X		fprintf(out, "%sAXIS ZAxis", tab); send_XYZ(&desc->axis->zaxi);
X	}
X
X	if (desc->size)
X		{ fprintf(out, "%sSIZE", tab); send_XYZ(desc->size); }
X
X	if (desc->pcount) {
X		fprintf(out, "%sPNTS PCount %u\n", tab, desc->pcount);
X		for (i=0; i<desc->pcount; i++) {
X			fprintf(out, "%sPNTS Point[%d]", tab, i);
X			send_XYZ(&desc->pnts[i]);
X		}
X	}
X
X	if (desc->ecount) {
X		fprintf(out, "%sEDGE ECount %u\n", tab, desc->ecount);
X		for (i=0; i<desc->ecount; i++) {
X			fprintf(out, "%sEDGE Edge[%d] %u %u\n", tab, i,
X				desc->edge[i<<1], desc->edge[(i<<1)+1]);
X		}
X	}
*/
X
X	if (desc->fcount && desc->ecount && desc->pcount) {
X		fprintf(out, "%s/* FACE TCount %u */\n", tab, desc->fcount);
X		for (i=0; i<desc->fcount; i++) {
/*			fprintf(out, "%sFACE Connect[%u] %u %u %u\n", tab, i,
X				desc->face[i*3], desc->face[i*3+1], desc->face[i*3+2]);
*/
X		/* First check to make sure that this triangle is real */
X			p1 = desc->edge[(desc->face[i*3])<<1];
X			p2 = desc->edge[((desc->face[i*3])<<1)+1];
X			if (p1 == p2) continue;	/* How did *this* happen? */
X			p3 = desc->edge[(desc->face[i*3+2])<<1];
X			if (p1 == p3 || p2 == p3)
X				p3 = desc->edge[((desc->face[i*3+2])<<1)+1];
X			if (p1 == p3 || p2 == p3) continue; /* How did *this* happen? */
X		/* Now check the actual points for equality */
X			if (bcmp(&desc->pnts[p1], &desc->pnts[p2], sizeof(XYZ_st))==0 ||
X				bcmp(&desc->pnts[p1], &desc->pnts[p3], sizeof(XYZ_st))==0 ||
X				bcmp(&desc->pnts[p2], &desc->pnts[p3], sizeof(XYZ_st))==0)
X				continue;
X
X			fprintf(out, "%spolygon {\n", tab);
X			indent();
X			fprintf(out, "%svertex(", tab);		send_XYZ(&desc->pnts[p1]);
X			fprintf(out, ")\n%svertex(", tab);	send_XYZ(&desc->pnts[p2]);
X			fprintf(out, ")\n%svertex(", tab);	send_XYZ(&desc->pnts[p3]);
X			outdent();
X			fprintf(out, ")\n%s}\n", tab);
X		}
X	}
X
SKIP_REST:
X
X	for (obj=object->child; obj; obj=obj->next) {
X		if (obj->extr) process_EXTR(obj->extr);
X		else process_DESC(obj);
X	}
X
X	outdent();
X	fprintf(out, "%s/* End DESC   \"Object %d at level %d of hierarchy %d\" */\n",
X		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
X
X
X	cur_objnum++;
X	prntline = 0;
X	process_TOBJ();
}
X
SHAR_EOF
chmod 0644 writevort.c ||
echo 'restore of writevort.c failed'
Wc_c="`wc -c < 'writevort.c'`"
test 14117 -eq "$Wc_c" ||
	echo 'writevort.c: original size 14117, current size' "$Wc_c"
fi
# ============= writeim.c ==============
if test -f 'writeim.c' -a X"$1" != X"-c"; then
	echo 'x - skipping writeim.c (File already exists)'
else
echo 'x - extracting writeim.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'writeim.c' &&
/* writeim.c - write an Imagine 2.0 TDDD (3D Data Decription) file
X *           - by traversing the TTDDDLIB database
X *           - written by Glenn M. Lewis - 3/27/92
X */
X
#include <stdio.h>
#include <ctype.h>
#include "ttdddlib.h"
X
#ifdef AZTEC_C
#include <fcntl.h>
#include <exec/types.h>
#endif
X
static void process_INFO();
static void process_OBJ();
static void process_EXTR();
static void process_DESC();
X
/* Here are a few necessary utilities */
X
static void put_name(world, name, size)
WORLD *world;
register char  *name;
register int size;
{
X	while (*name && size) {
X		fputc(*name++, world->inp);
X		size--;
X	}
X	while (size--) fputc(0, world->inp);	/* Pad the rest of the string w/ 0 */
}
X
static void put_UBYTE(world, u)
WORLD *world;
UBYTE u;
{
X	fputc((char)u, world->inp);
}
X
static void put_UWORD(world, w)
WORLD *world;
UWORD w;
{
X	put_UBYTE(world, (UBYTE)(w>>8));
X	put_UBYTE(world, (UBYTE)(w&0xFF));
}
X
static void put_ULONG(world, l)
WORLD *world;
ULONG l;
{
X	put_UWORD(world, (UWORD)(l>>16));
X	put_UWORD(world, (UWORD)(l&0xFFFF));
}
X
static void put_FRACT(world, f)
WORLD *world;
double f;
{
X	put_ULONG(world, (ULONG)(f*65536.0));
}
X
static void put_XYZ(world, st)			/* Write a common string */
WORLD *world;
XXYZ_st *st;
{
X	put_FRACT(world, st->val[0]);
X	put_FRACT(world, st->val[1]);
X	put_FRACT(world, st->val[2]);
}
X
static void put_RGB(world, st)			/* Write a common string */
WORLD *world;
RGB_st *st;
{
X	put_UBYTE(world, 0);	/* PAD */
X	put_UBYTE(world, st->val[0]);
X	put_UBYTE(world, st->val[1]);
X	put_UBYTE(world, st->val[2]);
}
X
static void write_size(world, pos)
WORLD *world;
long pos;
{
X	long size;
X	long cur = ftell(world->inp);
X	size = cur-pos;
X	if (size&1) { size++; put_UBYTE(world, (UBYTE)0); }
X	fseek(world->inp, pos-4L, 0);
X	put_ULONG(world, (ULONG)size);
X	fseek(world->inp, cur, 0);
}
X
/********************/
/* The MAIN section */
/********************/
X
int write_TDDD(world, myfile)
WORLD *world;
FILE *myfile;
{
X	long pos, pos2;
X	OBJECT *obj;
X
X	if (!world || !myfile) return(0);
X	world->inp = myfile;
X
X	/* Start the IFF TDDD file */
X	put_name(world, "FORM", 4);
X	put_ULONG(world, 0L);			/* Fill this in later [seek(,4L,0)] */
X	pos = ftell(world->inp);		/* Save where this starting position is */
X	put_name(world, "TDDD", 4);
X
X	if (world->info) process_INFO(world, world->info);
X	for (obj = world->object; obj; obj=obj->next) {
X		put_name(world, "OBJ ", 4);
X		put_ULONG(world, 0L);
X		pos2 = ftell(world->inp);	/* Save for later */
X		process_OBJ(world, obj);
X		write_size(world, pos2);
X	}
X	write_size(world, pos);
X
/* All done.  Close up shop. */
X	fclose(world->inp);
X	return(1);
}
X
static void process_INFO(world, info)
WORLD *world;
INFO *info;
{
X	register ULONG i;
X	long pos;
X
X	put_name(world, "INFO", 4);
X	put_ULONG(world, 0L);
X	pos = ftell(world->inp);	/* Save for later */
X
X	for (i=0; i<8; i++)
X		if (info->brsh[i][0]) {
X			put_name(world, "BRSH", 4);
X			put_ULONG(world, 82L);
X			put_UWORD(world, (UWORD)i);
X			put_name(world, info->brsh[i], 80);
X		}
X
X	for (i=0; i<8; i++)
X		if (info->stnc[i][0]) {
X			put_name(world, "STNC", 4);
X			put_ULONG(world, 82L);
X			put_UWORD(world, (UWORD)i);
X			put_name(world, info->stnc[i], 80);
X		}
X
X	for (i=0; i<8; i++)
X		if (info->txtr[i][0]) {
X			put_name(world, "TXTR", 4);
X			put_ULONG(world, 82L);
X			put_UWORD(world, (UWORD)i);
X			put_name(world, info->txtr[i], 80);
X		}
X
X	if (info->otrk[0]) {
X		put_name(world, "OTRK", 4);
X		put_ULONG(world, 18L);
X		put_name(world, info->otrk, 18);
X	}
X
X	if (info->ambi) {
X		put_name(world, "AMBI", 4);
X		put_ULONG(world, 4L);
X		put_RGB(world, info->ambi);
X	}
X
X	if (info->obsv) {
X		put_name(world, "OBSV", 4);
X		put_ULONG(world, 28L);
X		put_XYZ(world, &info->obsv->came);
X		put_XYZ(world, &info->obsv->rota);
X		put_FRACT(world, info->obsv->foca);
X	}
X
X	if (info->ostr) {
X		put_name(world, "OSTR", 4);
X		put_ULONG(world, 56L);
X		put_name(world, info->ostr->path, 18);
X		put_XYZ(world, &info->ostr->tran);
X		put_XYZ(world, &info->ostr->rota);
X		put_XYZ(world, &info->ostr->scal);
X		put_UWORD(world, info->ostr->info);
X	}
X
X	if (info->fade) {
X		put_name(world, "FADE", 4);
X		put_ULONG(world, 12L);
X		put_FRACT(world, info->fade->at);
X		put_FRACT(world, info->fade->by);
X		put_RGB(world, &info->fade->to);
X	}
X
X	if (info->skyc) {
X		put_name(world, "SKYC", 4);
X		put_ULONG(world, 8L);
X		put_RGB(world, &info->skyc->hori);
X		put_RGB(world, &info->skyc->zeni);
X	}
X
X	if (info->glb0) {
X		put_name(world, "GLB0", 4);
X		put_ULONG(world, 8L);
X		for (i=0; i<8; i++)
X			put_UBYTE(world, (UBYTE)info->glb0[i]);
X	}
X	write_size(world, pos);
}
X
static void process_OBJ(world, obj)
WORLD *world;
OBJECT *obj;
{
X	OBJECT *o;
X
X	if (obj->extr) process_EXTR(world, obj);
X	else process_DESC(world, obj);
X
X	for (o=obj->child; o; o=o->next)
X		process_OBJ(world, o);
X
X	put_name(world, "TOBJ", 4);
X	put_ULONG(world, 0L);
}
X
static void process_EXTR(world, obj)
WORLD *world;
OBJECT *obj;
{
X	long pos;
X
X	put_name(world, "EXTR", 4);
X	put_ULONG(world, 0L);
X	pos = ftell(world->inp);	/* Save for later */
X
X	put_name(world, "LOAD", 4);
X	put_ULONG(world, 80L);
X	put_name(world, obj->extr->filename, 80);
X
X	put_name(world, "MTRX", 4);
X	put_ULONG(world, 60L);
X	put_XYZ(world, &obj->extr->mtrx.tran);
X	put_XYZ(world, &obj->extr->mtrx.scal);
X	put_XYZ(world, &obj->extr->mtrx.rota1);
X	put_XYZ(world, &obj->extr->mtrx.rota2);
X	put_XYZ(world, &obj->extr->mtrx.rota3);
X
X	write_size(world, pos);
}
X
static void process_DESC(world, obj)
WORLD *world;
OBJECT *obj;
{
X	register int i;
X	register DESC *desc;
X	FGRP *fgrp;
X	long pos;
X
X	if (!obj) return;
X	desc = obj->desc;
X	if (!desc) return;
X
X	put_name(world, "DESC", 4);
X	put_ULONG(world, 0L);
X	pos = ftell(world->inp);	/* Save for later */
X
X	if (desc->name) {
X		put_name(world, "NAME", 4);
X		put_ULONG(world, 18L);
X		put_name(world, desc->name, 18);
X	}
X
X	if (desc->posi) {
X		put_name(world, "POSI", 4);
X		put_ULONG(world, 12L);
X		put_XYZ(world, desc->posi);
X	}
X
X	if (desc->size) {
X		put_name(world, "SIZE", 4);
X		put_ULONG(world, 12L);
X		put_XYZ(world, desc->size);
X	}
X
X	if (desc->colr) {
X		put_name(world, "COLR", 4);
X		put_ULONG(world, 4L);
X		put_RGB(world, desc->colr);
X	}
X
X	if (desc->refl) {
X		put_name(world, "REFL", 4);
X		put_ULONG(world, 4L);
X		put_RGB(world, desc->refl);
X	}
X
X	if (desc->tran) {
X		put_name(world, "TRAN", 4);
X		put_ULONG(world, 4L);
X		put_RGB(world, desc->tran);
X	}
X
X	if (desc->spc1) {
X		put_name(world, "SPC1", 4);
X		put_ULONG(world, 4L);
X		put_RGB(world, desc->spc1);
X	}
X
X	if (desc->ints) {
X		put_name(world, "INTS", 4);
X		put_ULONG(world, 4L);
X		put_FRACT(world, (*desc->ints));
X	}
X
X	/* Mandatory field... stuff it, regardless */
X	if (desc->shap) {
X		put_name(world, "SHAP", 4);
X		put_ULONG(world, 4L);
X		put_UWORD(world, (UWORD)desc->shap[0]);
X		put_UWORD(world, (UWORD)desc->shap[1]);
X	} else {
X		put_name(world, "SHAP", 4);
X		put_ULONG(world, 4L);
X		put_UWORD(world, (UWORD)2);
X		put_UWORD(world, (UWORD)1);
X	}
X
X	if (desc->axis) {
X		put_name(world, "AXIS", 4);
X		put_ULONG(world, 36L);
X		put_XYZ(world, &desc->axis->xaxi);
X		put_XYZ(world, &desc->axis->yaxi);
X		put_XYZ(world, &desc->axis->zaxi);
X	}
X
X	if (desc->tpar) {
X		put_name(world, "TPAR", 4);
X		put_ULONG(world, 64L);
X		for (i=0; i<16; i++) put_FRACT(world, desc->tpar[i]);
X	}
X
X	if (desc->surf) {
X		put_name(world, "SURF", 4);
X		put_ULONG(world, 5L);
X		for (i=0; i<5; i++) put_UBYTE(world, desc->surf[i]);
X		put_UBYTE(world, (UBYTE)0);	/* To make this chunk even-sized */
X	}
X
X	if (desc->mttr) {
X		put_name(world, "MTTR", 4);
X		put_ULONG(world, 2L);
X		put_UBYTE(world, desc->mttr->type);
X		put_UBYTE(world, (UBYTE)(((int)((desc->mttr->indx-1.0)*100.0))&0xFF));
X	}
X
X	if (desc->spec) {
X		put_name(world, "SPEC", 4);
X		put_ULONG(world, 2L);
X		put_UBYTE(world, desc->spec[0]);
X		put_UBYTE(world, desc->spec[1]);
X	}
X
X	if (desc->prp0) {
X		put_name(world, "PRP0", 4);
X		put_ULONG(world, 6L);
X		for (i=0; i<6; i++) put_UBYTE(world, desc->prp0[i]);
X	}
X
X	if (desc->prp1) {
X		put_name(world, "PRP1", 4);
X		put_ULONG(world, 8L);
X		for (i=0; i<8; i++) put_UBYTE(world, desc->prp1[i]);
X	}
X
X	if (desc->stry) {
X		put_name(world, "STRY", 4);
X		put_ULONG(world, 56L);
X		put_name(world, desc->stry->path, 18);
X		put_XYZ(world, &desc->stry->tran);
X		put_XYZ(world, &desc->stry->rota);
X		put_XYZ(world, &desc->stry->scal);
X		put_UWORD(world, desc->stry->info);
X	}
X
X	if (desc->pcount) {
X		put_name(world, "PNTS", 4);
X		put_ULONG(world, (ULONG)desc->pcount*12L+2L);
X		put_UWORD(world, desc->pcount);
X		for (i=0; i<desc->pcount; i++)
X			put_XYZ(world, &desc->pnts[i]);
X	}
X
X	if (desc->ecount) {
X		put_name(world, "EDGE", 4);
X		put_ULONG(world, (ULONG)desc->ecount*4L+2L);
X		put_UWORD(world, desc->ecount);
X		for (i=0; i<2*desc->ecount; i++)
X			put_UWORD(world, desc->edge[i]);
X	}
X
X	if (desc->eflg) {
X		put_name(world, "EFLG", 4);
X		put_ULONG(world, (ULONG)desc->eflg->num+2L);
X		put_UWORD(world, desc->eflg->num);
X		for (i=0; i<desc->eflg->num; i++)
X			put_UBYTE(world, desc->eflg->eflg[i]);
X		if (desc->eflg->num&1) put_UBYTE(world, 0);	/* Pad on even boundary */
X	}
X
X	if (desc->fcount) {
X		put_name(world, "FACE", 4);
X		put_ULONG(world, (ULONG)desc->fcount*6L+2L);
X		put_UWORD(world, desc->fcount);
X		for (i=0; i<3*desc->fcount; i++)
X			put_UWORD(world, desc->face[i]);
X
X		if (desc->clst) {
X			put_name(world, "CLST", 4);
X			put_ULONG(world, (ULONG)desc->fcount*3L+2L);
X			put_UWORD(world, desc->fcount);
X			for (i=0; i<3*desc->fcount; i++)
X				put_UBYTE(world, desc->clst[i]);
X			if (desc->fcount&1) put_UBYTE(world, 0);	/* Pad to even length */
X		}
X		if (desc->rlst) {
X			put_name(world, "RLST", 4);
X			put_ULONG(world, (ULONG)desc->fcount*3L+2L);
X			put_UWORD(world, desc->fcount);
X			for (i=0; i<3*desc->fcount; i++)
X				put_UBYTE(world, desc->rlst[i]);
X			if (desc->fcount&1) put_UBYTE(world, 0);	/* Pad to even length */
X		}
X		if (desc->tlst) {
X			put_name(world, "TLST", 4);
X			put_ULONG(world, (ULONG)desc->fcount*3L+2L);
X			put_UWORD(world, desc->fcount);
X			for (i=0; i<3*desc->fcount; i++)
X				put_UBYTE(world, desc->tlst[i]);
X			if (desc->fcount&1) put_UBYTE(world, 0);	/* Pad to even length */
X		}
X	}
X
X	for (fgrp=desc->fgrp; fgrp; fgrp=fgrp->next) {
X		put_name(world, "FGRP", 4);
X		put_ULONG(world, (ULONG)fgrp->num*2L+2L+18L);
X		put_UWORD(world, fgrp->num);
X		put_name(world, fgrp->name, 18);
X		for (i=0; i<fgrp->num; i++)
X			put_UWORD(world, fgrp->face[i]);
X	}
X	write_size(world, pos);
}
X
SHAR_EOF
chmod 0644 writeim.c ||
echo 'restore of writeim.c failed'
Wc_c="`wc -c < 'writeim.c'`"
test 10283 -eq "$Wc_c" ||
	echo 'writeim.c: original size 10283, current size' "$Wc_c"
fi
exit 0
