'boxview' -- Part 1 of 2

Kelvin Thompson kelvin at cs.utexas.edu
Wed Jul 27 13:23:22 AEST 1988


This is the first of two shar files that contain source for 'boxview',
a 3D object viewer.  The program displays a faceted object (read from a
data file) and lets the user rotate it and alter the viewing geometry
used to project it.  'Boxview' is different from other viewers because
it has a unique, intuitive user interface that provides excellent
feedback to the user.  (I consider the standard set of Iris demos to
have *awful* feedback.)  'Boxview' will run only on an Iris, because
it makes extensive use of the Iris' architecture.  I've tested it on
a 3000-series Iris running a fairly old OS, and fairly new 4D.  The
program may not work well on Irises with 8 or fewer bitplanes.

I decided to post the program after I noticed that Siggraph next week
will have a paper entitled (roughly) "A Study in 3D Rotation with a
2D Pointing Device," which is exactly what I think 'boxview' is good at.
I thought I might grab myself some credit by letting people compare
my rotater with the one(s?) from the published paper.

Instructions for unpacking and running:

  (1) Save this article and the accompanying one into two Iris files.

  (2) Trim the text before and after the "--- cut here ---" lines
      in each of the two files.

  (3) Unpack the files by typing "sh file1" and "sh file2".

  (4) If you have a 4D system, edit 'Makefile' and remove the "-Zf"
      from the 'CFLAGS' definition.

  (5) Run "make" without parameters.

  (6) Read the documentation in README and 'boxview.1l' (the latter
      by typing "nroff -man boxview.1l".)

  (7) Run the program by typing either "boxview" or "boxview sticks.geom".

  (8) Exit 'boxview' by hitting the escape key.

Have fun.  I've got gobs more '.geom' files -- most stolen from DEC's
OFF release a year ago.  Send questions or comments to me at:

      kelvin at cs.utexas.edu      {backbone}!cs.utexas.edu!kelvin

If you want to see a live demo at Siggraph, you can contact me (Kelvin
Thompson) at the Nth Graphics booth, or at the Radisson Hotel.  I will
have a tar-tape (cartridge), but not an Iris (but maybe we can find one).

#------------------- cut this line and above ----------------------
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by cs.utexas.edu!kelvin on Tue Jul 26 22:05:00 CDT 1988
# Contents:  Makefile README boxview.1l cube.geom sticks.geom idraw.h ktypes.h
#	cm.c slide.c states.c tables.c wm.c xform.c
 
echo x - Makefile
sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
# This is the makefile to generate 'boxview'.
#
# by Kelvin Thompson, 10/4/87, 7/14/88

# Use the line below on 4D Irises (remove the '#' if you're on a 4D).
#CFLAGS = -Zv -Zg -O -DIRIS

# Use the line below in non-4D Irises (add a '#' if you're on a 4D).
CFLAGS = -Zv -Zg -Zf -O -DIRIS

BVFILES = boxview.o states.o manip.o xform.o tables.o rotate.o \
	view.o wm.o slide.o xh.o cm.o boxobj.o

boxview: $(BVFILES) ktypes.h
	cc $(CFLAGS) -o $@ $(BVFILES)
@//E*O*F Makefile//
chmod u=rw,g=r,o=r Makefile
 
echo x - README
sed 's/^@//' > "README" <<'@//E*O*F README//'
The files in this release will generate the application 'boxview',
which allows users to view 3D objects with an interesting human interface.
This application can only run on Iris workstations from Silicon Graphics
(and I have tested it on only a single Iris 3000-series turbo).

The files are:

    Makefile 
    README      -- This file
    boxobj.c    -- code for generating objects
    boxview.1l  -- application document in nroff format
    boxview.c   -- code for core of the program
    cm.c        -- code for allocating bitplane layers and colors
    cube.geom   -- data file describing a cube
    sticks.geom -- data file describing some sticks
    idraw.h     -- include file for 'boxview' application
    ktypes.h    -- generic inlcude file
    manip.c     -- code for user manipulations
    rotate.c    -- code for object rotations
    slide.c     -- code for sliders
    states.c    -- code for application states
    tables.c    -- code for making database tables
    view.c      -- code for viewing-geometry manipulations
    wm.c        -- code for managing windows
    xform.c     -- code for doing transforms
    xh.c        -- code for manipulating crosshairs

To build the application, type "make" without parameters.

To run the application, type either "boxview" or "boxview sticks.geom".

To read the documentation, type "nroff -man boxview.1l" and
direct output to a file, a pager (like 'more' or 'less'), or
standard output.

If you want to have boxview display something besides polygonal
objects, you can insert your own object-generating code fairly easily.
See the documentation in the file 'boxobj.c'.

Everything in this release is Copyright 1986,1987,1988 by Kelvin 
Thompson and carries GNU-like restrictions:  Permission is granted
to use, copy, modify, and redistribute this software for non-
commercial purposes, as long as copies and derivative works carry
these same restrictions.

Please direct questions and comments to

   ARPA/INTERNET:  kelvin at cs.utexas.edu
   UUCP:           {...,uunet}!cs.utexas.edu!kelvin

Have fun.

	-- Kelvin Thompson, 7/14/88
@//E*O*F README//
chmod u=rw,g=r,o=r README
 
echo x - boxview.1l
sed 's/^@//' > "boxview.1l" <<'@//E*O*F boxview.1l//'
@.TH BOXVIEW 1L
@.SH NAME
boxview \- 3D object viewer
@.SH SYNOPSIS
@.B boxview 
[file]
@.SH DESCRIPTION
@.I Boxview
is an interactive viewer for 3D objects.
@.I Boxview
also acts as a demonstration of an interesting way of manipulating 3D
objects with a mouse.
@.PP
If 
@.I boxview
is called with no parameters, it displays three colored, orthogonal circles.  
If it is called with a single parameter
@.I file,
it draws the 3D polygons described in
@.I file.
The format of 
@.I file
is described later.
@.PP
@.I Boxview
displays a 3D object inside a 3D manipulation cube (or "3D window"), 
which is in
turn inside a normal 2D window.  The 3D window contains a set of 3D
crosshairs for identifying points in 3-space.  In the present 
implementation of
@.I boxview
the user may perform manipulations on the following attributes:
@.TP "\w'\f3\-n\f1\|\ \ 'u"
@.B Object orientation.
Position the mouse cursor over one of the edges of the 3D manipulation cube,
press the left mouse button, and move the cursor slowly, perpendicular 
to the selected edge.  The cube and object will rotate to follow the motion
of the mouse.
@.TP
@.B Projection geometry.
Click the left mouse button on the small red square in the lower left corner
of the 2D window.  A sylized view of the projection geometry will appear in
the lower left corner of the window.  The apex at the left represents the
viewier's eye, the circle at the right represents the sphere enclosing
the 3D manipulation window, and the vertical line in the middle represents
the projection plane.  The red dots may be dragged to
change the viewing geometry.  Click on the small red square to make the
projection window disappear.
@.TP
@.B 3D Crosshair position.
Position the mouse cursor over one of the X, Y, or Z axes, press the mouse
button, and move the mouse.  The 3D crosshairs don't do anything besides
move around.
@.PP
Press the escape key to exit
@.I boxview.
@.SH FILE FORMAT
Input files for
@.I boxview
should be ASCII text files following the form of geometry files from
DEC's OFF format.  Each input file is divided into three parts: a
single line describing the number of verticies and polygons in the
object, several lines containing the coordinates of the verticies of
the object, and several lines describing the polygons themselves.  Each
line consists of floating-point or (decimal) integer numbers separated
by whitespace.
@.PP
The first line contains three integers:
@.I Vcount, Pcount, 
and
@.I Ecount.
@.I Vcount
is the number of verticies in the object,
@.I Pcount
the number of polygons, and
@.I Ecount
the number of edges (actually, 
@.I Ecount
is ignored).  The next
@.I Vcount
lines contain three floating-point numbers apiece, so that each line
has the coorinates of a single vertex.  Then the final
@.I Pcount
lines of the file each describe a polygon.  Each of these lines starts with 
an integer
@.I N,
the number of verticies in the polygon, followed by
@.I N
integers referring back to the table of verticies (1 refers to the first
vertex, 2 the second, and so on).
@.PP
The following file describes a cube centered around the origin:
@.sp
@.nf
@.na
8 6 24
-1.0 -1.0 1.0
-1.0 1.0 1.0
1.0 1.0 1.0
1.0 -1.0 1.0
-1.0 -1.0 -1.0
-1.0 1.0 -1.0
1.0 1.0 -1.0
1.0 -1.0 -1.0
4 1 2 3 4
4 5 6 2 1
4 3 2 6 7
4 3 7 8 4
4 1 4 8 5
4 8 7 6 5
@.fi
@.ad
@.sp
@.SH BUGS
This program has only been exercised on a single, 3000-series Iris.
It may exhibit odd behavior on different Irises, especially those
with 8 or fewer bitplanes.
@.PP
Performance slows down for very large
objects.  Edges on adjacent polygons are drawn twice.
@.SH AUTHOR
Kelvin Thompson, The University of Texas at Austin
@.SH COPYRIGHT
@.I Boxview 
is Copyright 1986,1987,1988 by Kelvin 
Thompson and carries GNU-like restrictions:  Permission is granted
to use, copy, modify, and redistribute this software for non-
commercial purposes, as long as copies and derivative works carry
these same restrictions.
@//E*O*F boxview.1l//
chmod u=rw,g=r,o=r boxview.1l
 
echo x - cube.geom
sed 's/^@//' > "cube.geom" <<'@//E*O*F cube.geom//'
8	6	24
-1.0	-1.0	1.0
-1.0	1.0	1.0
1.0	1.0	1.0
1.0	-1.0	1.0
-1.0	-1.0	-1.0
-1.0	1.0	-1.0
1.0	1.0	-1.0
1.0	-1.0	-1.0
4	1	2	3	4
4	5	6	2	1
4	3	2	6	7
4	3	7	8	4
4	1	4	8	5
4	8	7	6	5
@//E*O*F cube.geom//
chmod u=r,g=r,o=r cube.geom
 
echo x - sticks.geom
sed 's/^@//' > "sticks.geom" <<'@//E*O*F sticks.geom//'
24 18 72
0.967443 0.4 -0.272129
1.00217 0.4 -0.0751674
1.00217 0.2 -0.0751674
0.967443 0.2 -0.272129
-0.967443 0.4 0.272129
-1.00217 0.4 0.0751674
-1.00217 0.2 0.0751674
-0.967443 0.2 0.272129
-0.137311 -1.03783 -0.272129
-0.154676 -1.06791 -0.0751674
-0.327881 -0.967907 -0.0751674
-0.310516 -0.93783 -0.272129
0.830132 0.63783 0.272129
0.847496 0.667907 0.0751674
0.674291 0.767907 0.0751674
0.656927 0.73783 0.272129
-0.830132 0.63783 -0.272129
-0.847496 0.667907 -0.0751674
-0.674291 0.767907 -0.0751674
-0.656927 0.73783 -0.272129
0.137311 -1.03783 0.272129
0.154676 -1.06791 0.0751674
0.327881 -0.967907 0.0751674
0.310516 -0.93783 0.272129
4	1 2 3 4
4	5 6 7 8
4	6 1 4 7
4	5 2 1 6
4	8 3 2 5
4	7 4 3 8
4	9 10 11 12
4	13 14 15 16
4	14 9 12 15
4	13 10 9 14
4	16 11 10 13
4	15 12 11 16
4	17 18 19 20
4	21 22 23 24
4	22 17 20 23
4	21 18 17 22
4	24 19 18 21
4	23 20 19 24
@//E*O*F sticks.geom//
chmod u=r,g=r,o=r sticks.geom
 
echo x - idraw.h
sed 's/^@//' > "idraw.h" <<'@//E*O*F idraw.h//'
/*  FILE:  idraw.h

    DESCRIPTION:  Types, symbols, globals for 'boxview' (previously
      'idraw').

    COPYRIGHT:  This software is Copyright 1986,1987,1988 by Kelvin 
      Thompson and carries GNU-like restrictions:  Permission is granted
      to use, copy, modify, and redistribute this software for non-
      commercial purposes, as long as copies and derivative works carry
      these same restrictions.
*/

#ifndef __IDRAW_H__
#define __IDRAW_H__

#include "ktypes.h"

/* the three directions as offsets */
#define XX 0
#define YY 1
#define ZZ 2

/* macros for accessing bits describing directions */
#define ROLLBIT(ax,dir)  ((1<<(dir))<<(ax))
#define AX_MASK(ax)      (07<<(3*(ax)))

/* types of pickable things */
#define TOK_NULL    0
#define TOKTYP_MASK 0xff00
#define TOKCOD_MASK 0x00ff
#define TOKTYP_AX   0x0100  /* axes */
#define TOKTYP_ROT  0x0200  /* rotation bars */
#define TOKTYP_VW   0x0300  /* view handles */
#define TOKTYP_XH   0x0400  /* crosshair */
#define TOKCOD_DIR  0x0003
#define TOKCOD_DIRp 0x0007
#define TOKCOD_X    XX
#define TOKCOD_Y    YY
#define TOKCOD_Z    ZZ
#define TOKCOD_p    0x0004
#define TOKCOD_Xp   (TOKCOD_p | TOKCOD_X)
#define TOKCOD_Xn   (       0 | TOKCOD_X)
#define TOKCOD_Yp   (TOKCOD_p | TOKCOD_Y)
#define TOKCOD_Yn   (       0 | TOKCOD_Y)
#define TOKCOD_Zp   (TOKCOD_p | TOKCOD_Z)
#define TOKCOD_Zn   (       0 | TOKCOD_Z)
#define TOKPT(a,b)  ( ((a&1)<<3) | ((b&1)<<2) )

/* the axes */
#define TOK_XAXIS   (TOKTYP_AX | TOKCOD_X)
#define TOK_YAXIS   (TOKTYP_AX | TOKCOD_Y)
#define TOK_ZAXIS   (TOKTYP_AX | TOKCOD_Z)

/* the pick window */
#define TOK_VEYE    (TOKTYP_VW | 0x0001)
#define TOK_VORG    (TOKTYP_VW | 0x0002)
#define TOK_VWIND   (TOKTYP_VW | 0x0003)
#define TOK_VWTOP   (TOKTYP_VW | 0x0004)
#define TOK_VWBOT   (TOKTYP_VW | 0x0005)

/* the crosshairs */
#define TOK_XH_Xp   (TOKTYP_XH | TOKCOD_Xp)
#define TOK_XH_Xn   (TOKTYP_XH | TOKCOD_Xn)
#define TOK_XH_Yp   (TOKTYP_XH | TOKCOD_Yp)
#define TOK_XH_Yn   (TOKTYP_XH | TOKCOD_Yn)
#define TOK_XH_Zp   (TOKTYP_XH | TOKCOD_Zp)
#define TOK_XH_Zn   (TOKTYP_XH | TOKCOD_Zn)
#define TOK_XH_O    (TOKTYP_XH | 0x0007)
#define TOK_XH_B    (TOKTYP_XH | 0x0008)

/* screen & pixel entities */
typedef struct SCRNPOINT  {Scoord    x,y}  SCRNPOINT;
typedef struct SCRNRECT   {SCRNPOINT  a,b}  SCRNRECT;

/* window struct */
typedef struct WINDOW
  {
  Matrix    mous_m;
  SCRNRECT  edge;
  RECT      bounds;
  RECT      bord;
  } WINDOW;

/* viewing geometry */
typedef struct VIEWGEOM
  {
  float    R;      /* distance between eye and object */
  float    D;      /* distance between eye and window */
  float    wx,wy;  /* half of height and width of window */
  } VIEWGEOM;

/* viewing data */
typedef struct VIEW
  {
  VIEWGEOM  g;
  WINDOW    *wdw;
  WINDOW    *vw;
  SCRNRECT  butt;
  XFORM     rot_to_ndc;
  XFORM     box_to_rot;
  XFORM     total;
  XFORM     vwtot;
  UNS16     viewon;  /* boolean -- TRUE if visible */
  UNS8      xhon;    /* boolean -- TRUE if crosshair visible */
  UNS8      xhdir;   /* direction of 2-D xh projection */
  VEC3      xhpos;
  } VIEW;

GLOBAL WINDOW *w0ptr;
GLOBAL VIEW *v0ptr;

GLOBAL long wminx,wmaxx,wminy,wmaxy;

/* constants */
#define VP_R    4.0
#define VP_D    2.0
#define VP_WX   1.0
#define VP_WY   0.7
#define VP_XMIN 50
#define VP_XMAX 749
#define VP_YMIN 50
#define VP_YMAX 700
#define NTSC_XMIN 0
#define NTSC_YMIN 0
#define NTSC_XMAX 635
#define NTSC_YMAX 484

GLOBAL UNS16 mexon;

GLOBAL Matrix default_mtx;

/* oft-used rectangles */
#ifdef CENTRAL
RECT ndcrect={ {-1,-1}, {1,1} };
RECT screenrect={ {0,0}, {XMAXSCREEN,YMAXSCREEN} };
#else
extern RECT ndcrect,screenrect;
#endif

/* font containing grab boxes */
#define NUM_GRAB_CHARS  1  /* number of characters in the grab font */
#define GRAB_FONT_IDX   1  /* font number of grab font */
#define GRAB_MAX_HEIGHT 5  /* max height of grab font character */
#define NUM_GRAB_RASTS  5  /* number of raster elements */
#ifdef CENTRAL
Fontchar grabchar[NUM_GRAB_CHARS+1] =
  {
  { 0, 0, 0,  0,  0, 0 },  /* dummy zero-th character */
  { 0, 5, 5, -1, -2, 6 }
  };
short grabrast[NUM_GRAB_RASTS] = 
  {
  /* first grab box -- 5x5 diamond */
  0x2000,
  0x7000,
  0xf800,
  0x7000,
  0x2000
  };
#else
extern Fontchar grabchar[NUM_GRAB_CHARS];
extern short grabrast[NUM_GRAB_RASTS];
#endif

/* the feedback buffer */
#define FB_MAX 128
GLOBAL short fb_buff[FB_MAX];

/* color indicies of various things */
#define MAX_MAPCOLOR   4095
#define CLR_BLACK      0
#define CLR_2CURSOR    1  /* 2-d cursor (little arrow) */
#define CLR_BACKG      2  /* background of everything */
#define CLR_3WDW       3  /* edge of 3-d window */
#define CLR_2WDW       4  /* edge of 2-d window */
#define CLR_AXES       5  /* axes in 3-d window */
#define CLR_AXNAMES    6  /* labels for axes */
#define CLR_VW_BACKG   8  /* background of view-manip window */
#define CLR_VW_LINES   9  /* view-manip lines */
#define CLR_VW_GRABS   10 /* view-manip handles */
#define CLR_VW_AREA    11 /* viewing area in VW window */
#define CLR_VW_BUTT    12 /* selector button for VW window */
#define CLR_SPLAT      13 /* splat color (when drawn) */
#define CLR_3CURS_EDGE 14 /* color of edge of 3-D crosshairs */
#define CLR_OBJSTART   32 /* start of object colors */

/* bitplane segment (segment 0) colors */
#define s0_CLEAR    0  /* transparent color */
#define s0_2CURSOR  1  /* 2-d cursor (little arrow) */
#define s0_3WDW     2  /* edge of 3-d window */
#define s0_2WDW     2  /* edge of 2-d window */
#define s0_AXES     3  /* axes in 3-d window */
#define s0_AXNAMES  4  /* labels for axes */
#define s0_XH_EDGE  5  /* color of edge of 3-D crosshairs */
#define s0_3FADE    6  /* faded 3-D window color */

/* other colors */
#define s1_BLACK    0  /* background black */
#define s1_BACKG    0  /* background of everything */
#define s1_VW_BACKG 0  /* background of view-manip window */
#define s1_VW_LINES 1  /* view-manip lines */
#define s1_VW_GRABS 2  /* view-manip handles */
#define s1_VW_AREA  3  /* viewing area in VW window */
#define s1_VW_BUTT  4  /* selector button for VW window */
#define s1_SPLAT    5  /* splat color (when drawn) */
#define s1_OBJSTART 10 /* start of object colors */

/* globals for two segments */
GLOBAL UNS16 seg0,seg1;

#define WROWS 20
#define WCOLS 20

#endif
@//E*O*F idraw.h//
chmod u=rw,g=r,o=r idraw.h
 
echo x - ktypes.h
sed 's/^@//' > "ktypes.h" <<'@//E*O*F ktypes.h//'
/*  FILENAME:  ktypes.h 

    DESCRIPTION:  Standard datatypes for kelvin's stuff.

    LINK WITH:  everything

    COPYRIGHT:  This software is Copyright 1986,1987,1988 by Kelvin 
      Thompson and carries GNU-like restrictions:  Permission is granted
      to use, copy, modify, and redistribute this software for non-
      commercial purposes, as long as copies and derivative works carry
      these same restrictions.
*/

#ifndef KTYPES_H  /* see if we've been here before */
#define KTYPES_H  /* corresponding #endif at end of file */

/* Boolean values */
#ifndef TRUE
#define TRUE  1
#define FALSE  0
#endif

#ifdef CENTRAL
#define GLOBAL
#else
#define GLOBAL extern
#endif

/* fixed-length integer types */
typedef char INT8;            /* 8-bit signed */
typedef short INT16;          /* 16-bit signed */
typedef int INT32;            /* 32-bit signed */
typedef unsigned char UNS8;   /* 8-bit unsigned */
typedef unsigned short UNS16; /* 16-bit unsigned */
typedef unsigned int UNS32;   /* 32-bit unsigned */

#define PI      3.141592653
#define SQRT_2  1.414213562


/* say what kind of CPU this is */
#define M68000    1
#define M68020    2
#define VAX       3
#define CPU       M68000

#if CPU==M68000

  /* processor-specific integer types */
  typedef int INTREGSIZ;             /* register-sized signed */
  typedef unsigned UNSREGSIZ;        /* register-sized unsigned */
  typedef short INTDATASIZ;          /* data-bus-sized signed */
  typedef unsigned short UNSDATASIZ; /* data-bus-sized unsigned */
  typedef int INTPTRSIZ;             /* pointer-register-sized signed */
  typedef unsigned int UNSPTRSIZ;    /* pointer-register-sized unsiged */
  
  /* processor-specific sizes */
#  define DATAWIDTH  16        /* width of data bus */
#  define REGWIDTH   32        /* width of register */
#  define PTRWIDTH   24        /* meaningful width of pointer */

#endif

#if CPU==M68020

  /* processor-specific integer types */
  typedef int INTREGSIZ;           /* register-sized signed */
  typedef unsigned UNSREGSIZ;      /* register-sized unsigned */
  typedef short INTDATASIZ;        /* data-bus-sized signed */
  typedef unsigned UNSDATASIZ;     /* data-bus-sized unsigned */
  typedef int INTPTRSIZ;           /* pointer-register-sized signed */
  typedef unsigned int UNSPTRSIZ;  /* pointer-register-sized unsiged */
  
  /* processor-specific sizes */
#  define DATAWIDTH 32        /* width of data bus */
#  define REGWIDTH  32        /* width of register */
#  define PTRWIDTH  32        /* meaningful width of pointer */

#endif

#if CPU==VAX

  /* processor-specific integer types */
  typedef int INTREGSIZ;           /* register-sized signed */
  typedef unsigned UNSREGSIZ;      /* register-sized unsigned */
  typedef int INTDATASIZ;          /* data-bus-sized signed */
  typedef unsigned UNSDATASIZ;     /* data-bus-sized unsigned */
  typedef int INTPTRSIZ;           /* pointer-register-sized signed */
  typedef unsigned int UNSPTRSIZ;  /* pointer-register-sized unsiged */
  
  /* processor-specific sizes */
#  define DATAWIDTH  32        /* width of data bus */
#  define REGWIDTH   32        /* width of register */
#  define PTRWIDTH   32        /* meaningful width of pointer */

#endif

/* geometric entities */
typedef float MATRIX[4][4];
typedef struct MTX_STRUCT {MATRIX m} MTX_STRUCT;
typedef struct VEC2    {float x,y}    VEC2;
typedef struct VEC3    {float x,y,z}  VEC3;
typedef struct VEC4    {float x,y,z,w}  VEC4;
typedef struct POINT  {float x,y}    POINT;
typedef struct RECT    {POINT a,b}    RECT;
typedef union 
  {
  MATRIX     m;      /* 4x4 matrix of values */
  MTX_STRUCT a;      /* struct containing 4x4 array */
  VEC4       v[4];   /* 4 homogeneous vectors (rows) */
  float      s[16];  /* array 16 scalars */
  } XFORM;

/* constants */
#ifdef CENTRAL
  MTX_STRUCT I = 
    {{
    {1.0, 0.0, 0.0, 0.0},
    {0.0, 1.0, 0.0, 0.0},
    {0.0, 0.0, 1.0, 0.0},
    {0.0, 0.0, 0.0, 1.0}
    }};
#else
  extern MTX_STRUCT I;
#endif
#define I_INIT            \
    {                     \
    {1.0, 0.0, 0.0, 0.0}, \
    {0.0, 1.0, 0.0, 0.0}, \
    {0.0, 0.0, 1.0, 0.0}, \
    {0.0, 0.0, 0.0, 1.0}  \
    }


#endif        /* end self protection */
@//E*O*F ktypes.h//
chmod u=rw,g=r,o=r ktypes.h
 
echo x - cm.c
sed 's/^@//' > "cm.c" <<'@//E*O*F cm.c//'
/*  FILENAME:  cm.c

    DESCRIPTION:  Programs for allocating different sets of bitplanes
      and assigning color.  Assumes double buffering.

    COPYRIGHT:  This software is Copyright 1986,1987,1988 by Kelvin 
      Thompson and carries GNU-like restrictions:  Permission is granted
      to use, copy, modify, and redistribute this software for non-
      commercial purposes, as long as copies and derivative works carry
      these same restrictions.
*/

#include <stdio.h>
#include <gl.h>
#include <device.h>

/* programs in this file */
extern cm_reset();
extern cm_avail();
extern unsigned cm_alloc();
extern cm_mapcolor();
extern cm_color();
extern Colorindex cm_truecolor();

typedef struct SEG
  {
  unsigned char  start;    /* first bitplane in segment */
  unsigned char  depth;    /* number of bitplanes in segment */
  unsigned short  baseidx; /* base global index */
  unsigned short  maxidx;  /* maximum segment color index */
  unsigned short  mask;    /* mask in global index space */
  } SEG;

static SEG cmseg[64]={ {0,0} };  /* array of segment descriptions */
static unsigned segcount=0;      /* number of segments allocated */



/*  ************************************
    *                                  *
    *           cm_reset               *
    *                                  *
    ************************************

    DESCRIPTION:  Resets the color map and associated allocations.

    EXIT:  Returns number of available bitplanes.
*/

cm_reset ( )
{
/* reset the color map */
mapcolor( 0, 0x0000, 0x0000, 0x0000 );
mapcolor( 1, 0xffff, 0x0000, 0x0000 );
mapcolor( 2, 0x0000, 0xffff, 0x0000 );
mapcolor( 3, 0xffff, 0xffff, 0x0000 );
mapcolor( 4, 0x0000, 0x0000, 0xffff );
mapcolor( 5, 0xffff, 0x0000, 0xffff );
mapcolor( 6, 0x0000, 0xffff, 0xffff );
mapcolor( 7, 0xffff, 0xffff, 0xffff );

/* reset allocations */
cmseg[0].depth = 0;
segcount = 0;
return getplanes();
}




/*  ************************************
    *                                  *
    *       cm_avail                   *
    *                                  *
    ************************************

    DESCRIPTION:  Gives number of unallocated bitplanes left.

    EXIT:  Number of unallocated bitplanes.
*/

cm_avail ( )
{
register unsigned total;
register SEG *sptr;

sptr = & cmseg[ segcount - 1 ];
total = sptr->start + sptr->depth;

return getplanes() - total;
}




/*  ************************************
    *                                  *
    *        cm_alloc                  *
    *                                  *
    ************************************

    DESCRIPTION:  Allocate a set of bitplanes.  Later
      segments occlude earlier segments.  Segments
      use bits starting in the low-order part of the word.

    ENTRY:
      bits -- Number of bits desired for segment.

    EXIT:  Returns two values stored in a single, 32-bit,
      unsigned word.  Upper 16 bits (masked with 0xffff0000)
      contain number of planes actually allocated.  Lower
      16 bits (masked with 0x0000ffff) contain segment id number
      (the index to the 'cmseg' array).  Returns 0 if no more
      bitplanes available.
*/

static unsigned short hibits[]=
  {
  0xffff, 0xfffe, 0xfffc, 0xfff8,
  0xfff0, 0xffe0, 0xffc0, 0xff80,
  0xff00, 0xfe00, 0xfc00, 0xf800,
  0xf000, 0xe000, 0xc000, 0x8000,
  0x0000
  };

unsigned cm_alloc ( bits )
register unsigned bits;
{
register unsigned total,avail;
register SEG *sptr;

/* see what's already been allocated */
if ( segcount != 0 )
  {
  sptr = & cmseg[ segcount - 1];
  total = sptr->start + sptr->depth;
  sptr++;
  }
else
  {
  sptr = cmseg;
  total = 0;
  }

/* quit if everything taken */
avail = getplanes() - total;
if ( avail == 0 )
  return 0;

/* fill the next SEG cell */
sptr->start = total;
sptr->depth = ( avail > bits ) ? bits : avail;
sptr->baseidx = (1 << sptr->start) - 1;
sptr->maxidx = (1 << sptr->depth) - 1;
sptr->mask = sptr->maxidx << sptr->start;
sptr->mask = hibits[ sptr->start ];

/* mark the last SEG cell */
sptr[1].depth = 0;

return (sptr->depth << 16) | segcount++;
}




/*  ************************************
    *                                  *
    *        cm_mapcolor               *
    *                                  *
    ************************************

    DESCRIPTION:  Allocate a color in a bitplane segment.

    ENTRY:
      segid -- ID of segment whose color is to be defined.
      coloridx -- Color index to be defined.
      red,grn,blu -- Color description.  Set red color
        to (int)(-1) or 0xffffffff for transparent color.

    EXIT:  Returns 0 if 'segid' or 'coloridx' was bogus; nonzero
      otherwise.
*/

cm_mapcolor ( segid, coloridx, red, grn, blu )
unsigned segid;
Colorindex color;
unsigned red,grn,blu;
{
register unsigned i,loopmax,newcolor;
register SEG *sptr;
short prevred,prevgrn,prevblu;

/* get segment cell */
if ( segid >= segcount )
  return 0;
sptr = & cmseg[segid];

/* check index */
if ( coloridx > sptr->maxidx )
  return 0;

/* define the color */
loopmax = sptr->baseidx;
newcolor = coloridx << sptr->start;
if ( red == 0xffffffff )
  {
  /* defining transparent color */
  for ( i=0; i<=loopmax; i++ )
    {
    getmcolor( i, &prevred, &prevgrn, &prevblu );
    mapcolor( newcolor, prevred, prevgrn, prevblu );
    newcolor++;
    }
  }
else
  {
  /* defining an occluding color */
  for ( i=0; i<=loopmax; i++ )
    {
    mapcolor( newcolor, red, grn, blu );
    newcolor++;
    }
  }

return 1;
}




/*  ************************************
    *                                  *
    *        cm_color                  *
    *                                  *
    ************************************

    DESCRIPTION:  Set the current color to a segment's color.
      Leaves other segments the same.

    ENTRY:
      segid -- ID of segment being referred to.
      coloridx -- Color index.

    EXIT:  Returns 0 if 'segid' is bogus; nonzero otherwise.
*/

cm_color ( segid, coloridx )
unsigned segid;
Colorindex coloridx;
{
register SEG *sptr;

/* fprintf( stderr, "Called 'cm_color' with %d, %d\n",
  segid, coloridx ); */

/* get segment cell */
if ( segid >= segcount )
  return 0;
sptr = & cmseg[segid];

/* mask planes and set color */
writemask( sptr->mask );
color( (coloridx & sptr->maxidx) << sptr->start );

/* fprintf( stderr, "Mask = 0x%x; color = 0x%x\n",
  sptr->mask, ((coloridx & sptr->maxidx) << sptr->start) ); */

return 1;
}



/*  ************************************
    *                                  *
    *        cm_truecolor              *
    *                                  *
    ************************************

    DESCRIPTION:  Return the true color associated with a
      segment color.  Also turns on all writemasks.

    ENTRY:
*/

Colorindex cm_truecolor ( segid, coloridx )
unsigned segid;
Colorindex coloridx;
{
register SEG *sptr;

/* get segment cell */
if ( segid >= segcount )
  return 0;
sptr = & cmseg[segid];

/* unmask planes and set color */
writemask( 0xffffffff );
return (coloridx & sptr->maxidx) << sptr->start;
}
@//E*O*F cm.c//
chmod u=rw,g=r,o=r cm.c
 
echo x - slide.c
sed 's/^@//' > "slide.c" <<'@//E*O*F slide.c//'
/*  FILENAME: slide.c

    DESCRIPTION:  Routines to implement sliders.

    COPYRIGHT:  This software is Copyright 1986,1987,1988 by Kelvin 
      Thompson and carries GNU-like restrictions:  Permission is granted
      to use, copy, modify, and redistribute this software for non-
      commercial purposes, as long as copies and derivative works carry
      these same restrictions.
*/

#include <gl.h>
#include <device.h>
#include "idraw.h"

/* programs in this file */
extern getslidepts();
extern void doslide();
extern void st_slide();

static SCRNRECT slidept;
static float slidex[3][3];
static void (*runfunc)(),(*donefunc)();




/*  ************************************
    *                                  *
    *        doslide()                 *
    *                                  *
    ************************************

    DESCRIPTION:

    ENTRY:
*/

void doslide ( endpt, rfunc, dfunc )
register SCRNRECT *endpt;
void (*rfunc)(),(*dfunc)();
{
register float dx,dy,denom;

/* store the endpoints and functions in the static location */
slidept = *endpt;
runfunc = rfunc;
donefunc = dfunc;

/* fix up the transform matrix */
dx = endpt->b.x - endpt->a.x;
dy = endpt->b.y - endpt->a.y;
denom = 1.0 / (dx*dx + dy*dy);
slidex[0][0] =  dx * denom;
slidex[0][1] = -dy * denom;
slidex[0][2] = 0.0;
slidex[1][0] = -slidex[0][1];
slidex[1][1] =  slidex[0][0];
slidex[1][2] = 0.0;
slidex[2][0] = -(dy * endpt->a.y + dx * endpt->a.x) * denom;
slidex[2][1] = -(dx * endpt->a.y - dy * endpt->a.x) * denom;
slidex[2][2] = 1.0;

/* perform the sliding action */
st_slide( 0, 0 );
}




/*  ************************************
    *                                  *
    *           st_slide               *
    *                                  *
    ************************************

    DESCRIPTION:

    ENTRY:
*/

void st_slide ( dum1, dum2 )
{
register float newx;
register long mx,my;

/* get mouse location */
mx = getvaluator( MOUSEX );
my = getvaluator( MOUSEY );

/* get the transformed X location */
newx = (float)mx * slidex[0][0] + (float)my * slidex[1][0] + slidex[2][0];

if ( !getbutton(LEFTMOUSE) )
  {
  (*donefunc)( newx );
  readystate();
  }
else
  {
  /* call the update routine */
  (*runfunc)( newx );
  add_state( st_slide, 0, 0 );
  }
}




/*  ************************************
    *                                  *
    *       getslidepts                *
    *                                  *
    ************************************

    DESCRIPTION:  Map a 3D line segment to a clipped screen line segment.

    ENTRY:

    EXIT: Returns TRUE if the mapping was successful, FALSE otherwise.

    PREREQUISITES:  The viewport and transform must be set before
      calling.
*/

getslidepts ( v1, v2, srect )
register VEC3 *v1,*v2;
register SCRNRECT *srect;
{
register long fbcount;

/* check for hits */
feedback( fb_buff, FB_MAX );
move( v1->x, v1->y, v1->z );
draw( v2->x, v2->y, v2->z );
fbcount = endfeedback( fb_buff );

/* make sure it's in a format we want */
if ( fbcount != 6  ||  fb_buff[0] != 16  ||  fb_buff[3] != 17 )
  return FALSE;

/* move the results to the return rectangle */
srect->a.x = fb_buff[1];
srect->a.y = fb_buff[2];
srect->b.x = fb_buff[4];
srect->b.y = fb_buff[5];
return TRUE;
}
@//E*O*F slide.c//
chmod u=rw,g=r,o=r slide.c
 
echo x - states.c
sed 's/^@//' > "states.c" <<'@//E*O*F states.c//'
/*  FILENAME:  states.c

    DESCRIPTION:  Programs that deal with the idraw state machine.

    LINK WITH:
      tables.c -- Handles allocation of fixed-sized things.

    COPYRIGHT:  This software is Copyright 1986,1987,1988 by Kelvin
      Thompson and carries GNU-like restrictions:  Permission is granted
      to use, copy, modify, and redistribute this software for non-
      commercial purposes, as long as copies and derivative works carry
      these same restrictions.
*/

#include <gl.h>
#include <device.h>
#include "ktypes.h"

/* programs in this file */
extern void init_states();
extern void close_states();
extern do_state();

/* constants */
#define MAX_STATES  32    /* maximum number of states allowed */

/* local types */
typedef struct STATE
{
struct STATE *next;
void         (*func)();
int          val1,val2;
} STATE;

/* local variables */
static STATE
*pres_state=0,
*futr_state=0;
static
list1,list2,
futr_list;



/*  ************************************
    *                                  *
    *        init_states               *
    *                                  *
    ************************************

    DESCRIPTION:  Initialize stuff for state parser.
*/

void init_states ( )
{
list1 = init_table( MAX_STATES, sizeof(STATE) );
list2 = init_table( MAX_STATES, sizeof(STATE) );
futr_list = list1;
}




/*  ************************************
    *                                  *
    *         close_states             *
    *                                  *
    ************************************

    DESCRIPTION:  Free space used by state parser.
*/

void close_states ( )
{
close_table( list1 );
close_table( list2 );
}



/*  ************************************
    *                                  *
    *          do_state                *
    *                                  *
    ************************************

    DESCRIPTION:  Execute all state programs.
*/

do_state ( )
{
register STATE *this_state;

/* move the future to the present */
if ( futr_state == 0 )
return FALSE;
pres_state = futr_state;
futr_state = 0;

/* swap lists */
if ( futr_list == list1 )
{
reset_table( list2 );
futr_list = list2;
}
else
{
reset_table( list1 );
futr_list = list1;
}

/* loop through current states */
for ( this_state=pres_state; this_state!=0; this_state=this_state->next )
(*(this_state->func))( this_state->val1, this_state->val2 );

return TRUE;
}




/*  ************************************
    *                                  *
    *       add_state                  *
    *                                  *
    ************************************

    DESCRIPTION:  Add a state to the list to be executed in the future.

    ENTRY:
*/

void add_state ( func, val1, val2 )
void (*func)();
int val1,val2;
{
register STATE *this_state;

/* initialize */
this_state = (STATE *)get_cell( futr_list );
this_state->func = func;
this_state->val1 = val1;
this_state->val2 = val2;

/* put in linked list */
this_state->next = futr_state;
futr_state = this_state;
}
@//E*O*F states.c//
chmod u=rw,g=r,o=r states.c
 
echo x - tables.c
sed 's/^@//' > "tables.c" <<'@//E*O*F tables.c//'
/*  FILENAME: tables.c

    DESCRIPTION:  Utility programs for generic tables.

    COPYRIGHT:  This software is Copyright 1986,1987,1988 by Kelvin 
      Thompson and carries GNU-like restrictions:  Permission is granted
      to use, copy, modify, and redistribute this software for non-
      commercial purposes, as long as copies and derivative works carry
      these same restrictions.
*/

typedef struct TABLE
  {
  unsigned short tblsize;
  unsigned short cellsize;
  char           *nextcell;
  } TABLE;

/* programs in this file */
extern int *init_table();
extern void reset_table();
extern char *get_cell();
extern void close_table();
extern void fill_table();
extern char *next_cell();




/*  *********************
    *                   *
    *    init_table     *
    *                   *
    *********************

    DESCRIPTION:  Create a table.

    ENTRY:

    EXIT:
*/

int *init_table ( tblsize, cellsize )
register tblsize;
register cellsize;
{
register TABLE *out;

/* allocate space for TABLE and init struct */
out = (TABLE *)malloc( sizeof(TABLE) + tblsize * cellsize );
out->tblsize = tblsize;
out->cellsize = cellsize;
out->nextcell = (char *)out + sizeof(TABLE) + (tblsize-1) * cellsize;

/* return pointer to struct */
return (int *)out;
}




/*  *********************
    *                   *
    *   reset_table     *
    *                   *
    *********************

    DESCRIPTION:  Initialize the elements of a table.

    ENTRY:
*/

void reset_table ( tbl )
register TABLE *tbl;
{
tbl->nextcell = (char *)(& tbl[1]) + (tbl->tblsize-1) * tbl->cellsize;
}




/*  *********************
    *                   *
    *    get_cell       *
    *                   *
    *********************

    DESCRIPTION:  Return the next cell from the table.

    ENTRY:

    EXIT:
*/

char *get_cell ( tbl )
register TABLE *tbl;
{
register char *out;

if ( tbl->nextcell != (char *)(&tbl[1]) )
  {
  out = tbl->nextcell;
  tbl->nextcell -= tbl->cellsize;
  }
else
  out = 0;

return out;
}




/*  *********************
    *                   *
    *   close_table     *
    *                   *
    *********************

    DESCRIPTION:  Destroy a table.

    ENTRY:

    EXIT:
*/

void close_table ( tbl )
register TABLE *tbl;
{
free( tbl );
}




/*  *********************
    *                   *
    *   fill_table      *
    *                   *
    *********************

    DESCRIPTION:  Initialize the elements of a table by calling
      a function for every element.

    ENTRY:
*/

void fill_table ( tbl, func )
register TABLE *tbl;
register void (*func)();
{
register idx;
register char *nextcell;

/* initialize for loop */
idx = tbl->tblsize - 1;
tbl->nextcell = nextcell
  = (char *)tbl + sizeof(TABLE) + (tbl->tblsize-1) * tbl->cellsize;

/* loop through all elements in table */
do  {
  /* call the filling function */
  (*func)( nextcell, idx );

  /* decrement counters */
  --idx;
  nextcell -= tbl->cellsize;
  }  while ( idx >= 0 );
}




/*  *********************
    *                   *
    *    next_cell      *
    *                   *
    *********************

    DESCRIPTION:  Return the next cell from the table.

    ENTRY:

    EXIT:
*/

char *next_cell ( tbl )
register TABLE *tbl;
{
register char *out;

/* get contents of next cell */
out = tbl->nextcell;

if ( tbl->nextcell == (char *)(&tbl[1]) )
  tbl->nextcell
    = (char *)tbl + sizeof(TABLE) + (tbl->tblsize-1) * tbl->cellsize;
else
  tbl->nextcell -= tbl->cellsize;

return out;
}
@//E*O*F tables.c//
chmod u=rw,g=r,o=r tables.c
 
echo x - wm.c
sed 's/^@//' > "wm.c" <<'@//E*O*F wm.c//'
/*  FILENAME: wm.c

    DESCRIPTION:  Window manager routines.

    COPYRIGHT:  This software is Copyright 1986,1987,1988 by Kelvin 
      Thompson and carries GNU-like restrictions:  Permission is granted
      to use, copy, modify, and redistribute this software for non-
      commercial purposes, as long as copies and derivative works carry
      these same restrictions.
*/

#include <gl.h>
#include <device.h>
#include "idraw.h"


/* programs in this file */
extern char *open_wdw();
extern void use_wdw();
extern void vp_wdw();
extern void close_wdw();
extern getmousebox();

#define PICK_RAD 4

static WINDOW *curr_wdw;




/*  ************************************
    *                                  *
    *      open_wdw                    *
    *                                  *
    ************************************

    DESCRIPTION:  Open a window on the screen.

    ENTRY:

    EXIT:
*/

char *open_wdw ( minx, maxx, miny, maxy )
long minx,maxx,miny,maxy;
{
register WINDOW *wdw;

wdw = (WINDOW *)malloc( sizeof(WINDOW) );

if ( mexon )
  {
  getorigin( &wminx, &wminy );
  getsize( &wmaxx, &wmaxy );
  wmaxx += wminx - 1;
  wmaxy += wminy - 1;
  minx = wminx;  miny = wminy;
  maxx = wmaxx;  maxy = wmaxy;
  }

/* record bounds of window */
wdw->edge.a.x = minx;
wdw->edge.a.y = miny;
wdw->edge.b.x = maxx;
wdw->edge.b.y = maxy;
wdw->bounds.a.x = minx;
wdw->bounds.a.y = miny;
wdw->bounds.b.x = maxx;
wdw->bounds.b.y = maxy;
wdw->bord.a.x = minx-1;
wdw->bord.a.y = miny-1;
wdw->bord.b.x = maxx+1;
wdw->bord.b.y = maxy+1;

/* calculate mapping from screen to window */
map_rects( wdw->mous_m, &wdw->bounds, &ndcrect );

return (char *)wdw;
}




/*  ************************************
    *                                  *
    *       close_wdw                  *
    *                                  *
    ************************************

    DESCRIPTION:

    ENTRY:
*/

void close_wdw ( wdw )
{
free( wdw );
}



/*  ************************************
    *                                  *
    *         use_wdw                  *
    *                                  *
    ************************************

    DESCRIPTION:  Set the screen mask and current transform to
      reflect a given window.

    ENTRY:
*/

void use_wdw ( wdw )
register WINDOW *wdw;
{
/* draw the window's border */
viewport( 0, XMAXSCREEN, 0, YMAXSCREEN );
loadmatrix( default_mtx );
cm_color( seg0, s0_2WDW );
rect( wdw->bord.a.x, wdw->bord.a.y, wdw->bord.b.x, wdw->bord.b.y );

viewport( wdw->edge.a.x, wdw->edge.b.x, wdw->edge.a.y, wdw->edge.b.y );

curr_wdw = wdw;
}



/*  ************************************
    *                                  *
    *          vp_wdw                  *
    *                                  *
    ************************************

    DESCRIPTION:  Set the viewport to the indicated window.

    ENTRY:
*/

void vp_wdw ( wdw )
register WINDOW *wdw;
{
viewport( wdw->edge.a.x, wdw->edge.b.x, wdw->edge.a.y, wdw->edge.b.y );
curr_wdw = wdw;
}




/*  ************************************
    *                                  *
    *      clear_wdw                   *
    *                                  *
    ************************************

    DESCRIPTION:

    ENTRY:
*/

void clear_wdw ( wdw )
register WINDOW *wdw;
{
pushmatrix();
  loadmatrix( default_mtx );
  rectfi( wdw->edge.a.x, wdw->edge.a.y, wdw->edge.b.x, wdw->edge.b.y );
popmatrix();
}




/*  ************************************
    *                                  *
    *      getmousebox                 *
    *                                  *
    ************************************

    DESCRIPTION:

    ENTRY:

    EXIT:
*/

getmousebox ( wdw, boxptr )
register WINDOW *wdw;
register RECT *boxptr;
{
register long mx,my;

/* init */
mx = getvaluator(MOUSEX);
my = getvaluator(MOUSEY);

/* make sure it's inside the window */
if ( mx < wdw->edge.a.x  ||  wdw->edge.b.x < mx
    ||  my < wdw->edge.a.y  ||  wdw->edge.b.y < my )
  return FALSE;

/* do the transform to window coords by hand */
boxptr->a.x = (mx-PICK_RAD) * wdw->mous_m[0][0] + wdw->mous_m[3][0];
boxptr->a.y = (my-PICK_RAD) * wdw->mous_m[1][1] + wdw->mous_m[3][1];
boxptr->b.x = (mx+PICK_RAD) * wdw->mous_m[0][0] + wdw->mous_m[3][0];
boxptr->b.y = (my+PICK_RAD) * wdw->mous_m[1][1] + wdw->mous_m[3][1];

return TRUE;
}
@//E*O*F wm.c//
chmod u=rw,g=r,o=r wm.c
 
echo x - xform.c
sed 's/^@//' > "xform.c" <<'@//E*O*F xform.c//'
/*  FILENAME: xform.c

    DESCRIPTION:  Various matrix processors for idraw.

    COPYRIGHT:  This software is Copyright 1986,1987,1988 by Kelvin 
      Thompson and carries GNU-like restrictions:  Permission is granted
      to use, copy, modify, and redistribute this software for non-
      commercial purposes, as long as copies and derivative works carry
      these same restrictions.
*/

#include <math.h>
#include <gl.h>
#include "ktypes.h"
#include "idraw.h"

/* programs in this file */
extern XFORM *mmul();
extern VEC4 *vmul();
/* extern void set_vp(); */
extern void rot_x();
extern void rot_y();
extern void rot_z();
extern void set_view();
extern void map_rects(),qmap_rects();
extern unsigned getdirs();
extern XFORM *axslopes();

#define MINISCULE 1.0e-32




/*  *********************
    *                   *
    *      mmul         *
    *                   *
    *********************

    DESCRIPTION:  Multiply two 4x4 matricies.

    ENTRY:
      a,b -- two matricies to be multiplied
      result -- result matrix, perhaps the same as an input matrix
*/

XFORM *mmul ( result, a, b )
register XFORM *a,*b,*result;
{
XFORM tempx;

tempx.m[0][0] =	a->m[0][0] * b->m[0][0]
	     +  a->m[0][1] * b->m[1][0]
	     +  a->m[0][2] * b->m[2][0]
	     +  a->m[0][3] * b->m[3][0];

tempx.m[0][1] =	a->m[0][0] * b->m[0][1]
	     +  a->m[0][1] * b->m[1][1]
	     +  a->m[0][2] * b->m[2][1]
	     +  a->m[0][3] * b->m[3][1];

tempx.m[0][2] =	a->m[0][0] * b->m[0][2]
	     +  a->m[0][1] * b->m[1][2]
	     +  a->m[0][2] * b->m[2][2]
	     +  a->m[0][3] * b->m[3][2];

tempx.m[0][3] =	a->m[0][0] * b->m[0][3]
	     +  a->m[0][1] * b->m[1][3]
	     +  a->m[0][2] * b->m[2][3]
	     +  a->m[0][3] * b->m[3][3];

tempx.m[1][0] =	a->m[1][0] * b->m[0][0]
	     +  a->m[1][1] * b->m[1][0]
	     +  a->m[1][2] * b->m[2][0]
	     +  a->m[1][3] * b->m[3][0];

tempx.m[1][1] =	a->m[1][0] * b->m[0][1]
	     +  a->m[1][1] * b->m[1][1]
	     +  a->m[1][2] * b->m[2][1]
	     +  a->m[1][3] * b->m[3][1];

tempx.m[1][2] =	a->m[1][0] * b->m[0][2]
	     +  a->m[1][1] * b->m[1][2]
	     +  a->m[1][2] * b->m[2][2]
	     +  a->m[1][3] * b->m[3][2];

tempx.m[1][3] =	a->m[1][0] * b->m[0][3]
	     +  a->m[1][1] * b->m[1][3]
	     +  a->m[1][2] * b->m[2][3]
	     +  a->m[1][3] * b->m[3][3];

tempx.m[2][0] =	a->m[2][0] * b->m[0][0]
	     +  a->m[2][1] * b->m[1][0]
	     +  a->m[2][2] * b->m[2][0]
	     +  a->m[2][3] * b->m[3][0];

tempx.m[2][1] =	a->m[2][0] * b->m[0][1]
	     +  a->m[2][1] * b->m[1][1]
	     +  a->m[2][2] * b->m[2][1]
	     +  a->m[2][3] * b->m[3][1];

tempx.m[2][2] =	a->m[2][0] * b->m[0][2]
	     +  a->m[2][1] * b->m[1][2]
	     +  a->m[2][2] * b->m[2][2]
	     +  a->m[2][3] * b->m[3][2];

tempx.m[2][3] =	a->m[2][0] * b->m[0][3]
	     +  a->m[2][1] * b->m[1][3]
	     +  a->m[2][2] * b->m[2][3]
	     +  a->m[2][3] * b->m[3][3];

tempx.m[3][0] =	a->m[3][0] * b->m[0][0]
	     +  a->m[3][1] * b->m[1][0]
	     +  a->m[3][2] * b->m[2][0]
	     +  a->m[3][3] * b->m[3][0];

tempx.m[3][1] =	a->m[3][0] * b->m[0][1]
	     +  a->m[3][1] * b->m[1][1]
	     +  a->m[3][2] * b->m[2][1]
	     +  a->m[3][3] * b->m[3][1];

tempx.m[3][2] =	a->m[3][0] * b->m[0][2]
	     +  a->m[3][1] * b->m[1][2]
	     +  a->m[3][2] * b->m[2][2]
	     +  a->m[3][3] * b->m[3][2];

tempx.m[3][3] =	a->m[3][0] * b->m[0][3]
	     +  a->m[3][1] * b->m[1][3]
	     +  a->m[3][2] * b->m[2][3]
	     +  a->m[3][3] * b->m[3][3];

result->a = tempx.a;	/* copy temporary product to result matrix */
return result;
}



/*  ************************************
    *                                  *
    *         vmul                     *
    *                                  *
    ************************************

    DESCRIPTION:  Multiply a row vector by a matrix.

    ENTRY:

    EXIT:
*/

VEC4 *vmul ( result, v, m )
register XFORM *m;
register VEC4 *result,*v;
{
VEC4 tempv;

tempv.x =   v->x * m->m[0][0]
	 +  v->y * m->m[1][0]
	 +  v->z * m->m[2][0]
	 +  v->w * m->m[3][0];

tempv.y =   v->x * m->m[0][1]
	 +  v->y * m->m[1][1]
	 +  v->z * m->m[2][1]
	 +  v->w * m->m[3][1];

tempv.z =   v->x * m->m[0][2]
	 +  v->y * m->m[1][2]
	 +  v->z * m->m[2][2]
	 +  v->w * m->m[3][2];

tempv.w =   v->x * m->m[0][3]
	 +  v->y * m->m[1][3]
	 +  v->z * m->m[2][3]
	 +  v->w * m->m[3][3];

*result = tempv;
return result;
}



/*  ************************************
    *                                  *
    *         rot_x                    *
    *                                  *
    ************************************

    DESCRIPTION:  Add an X rotation to a matrix.

    ENTRY:
*/

void rot_x ( matx, ang )
register XFORM *matx;
float ang;
{
XFORM rotmatx;
register float sinx,cosx;

/* initialize */
sinx = sin(ang);
cosx = cos(ang);

/* set up the local matrix */
rotmatx.a = I;
rotmatx.m[1][1] =  cosx;  rotmatx.m[1][2] =  sinx;
rotmatx.m[2][1] = -sinx;  rotmatx.m[2][2] =  cosx;

/* multiply */
mmul( matx, &rotmatx, matx );
}



/*  ************************************
    *                                  *
    *         rot_y                    *
    *                                  *
    ************************************

    DESCRIPTION:  Add a Y rotation to a matrix.

    ENTRY:
*/

void rot_y ( matx, ang )
register XFORM *matx;
float ang;
{
XFORM rotmatx;
register float sinx,cosx;

/* initialize */
sinx = sin(ang);
cosx = cos(ang);

/* set up the local matrix */
rotmatx.a = I;
rotmatx.m[0][0] =  cosx;  rotmatx.m[0][2] = -sinx;
rotmatx.m[2][0] =  sinx;  rotmatx.m[2][2] =  cosx;

/* multiply */
mmul( matx, &rotmatx, matx );
}



/*  ************************************
    *                                  *
    *         rot_z                    *
    *                                  *
    ************************************

    DESCRIPTION:  Add a Z rotation to a matrix.

    ENTRY:
*/

void rot_z ( matx, ang )
register XFORM *matx;
float ang;
{
XFORM rotmatx;
register float sinx,cosx;

/* initialize */
sinx = sin(ang);
cosx = cos(ang);

/* set up the local matrix */
rotmatx.a = I;
rotmatx.m[0][0] =  cosx;  rotmatx.m[0][1] =  sinx;
rotmatx.m[1][0] = -sinx;  rotmatx.m[1][1] =  cosx;

/* multiply */
mmul( matx, &rotmatx, matx );
}




/*  ************************************
    *                                  *
    *        set_view                  *
    *                                  *
    ************************************

    DESCRIPTION:

    ENTRY:
*/

void set_view ( matx, r, d, wx, wy )
register XFORM *matx;
register float r,d,wx,wy;
{
matx->a = I;
matx->m[0][0] = d / wx;
matx->m[1][1] = d / wy;
matx->m[2][2] = 0.0;
matx->m[2][3] = -1.0;
matx->m[3][3] = r;
}




/*  ************************************
    *                                  *
    *        map_rects                 *
    *                                  *
    ************************************

    DESCRIPTION:

    ENTRY:
*/

void map_rects ( m, from, to )
register MTX_STRUCT *m;
register RECT *from,*to;
{
register float fromdiff,todiff,ratio;

*m = I;

/* figure X transform */
fromdiff = from->b.x - from->a.x;
todiff = to->b.x - to->a.x;
ratio = todiff / fromdiff;
m->m[0][0] = ratio;
m->m[3][0] = to->a.x - from->a.x * ratio;

/* figure Y transform */
fromdiff = from->b.y - from->a.y;
todiff = to->b.y - to->a.y;
ratio = todiff / fromdiff;
m->m[1][1] = ratio;
m->m[3][1] = to->a.y - from->a.y * ratio;
}




/*  ************************************
    *                                  *
    *        qmap_rects                *
    *                                  *
    ************************************

    DESCRIPTION:

    ENTRY:
*/

void qmap_rects ( m, from, to )
register MTX_STRUCT *m;
register RECT *from,*to;
{
register float fromdiff,todiff,ratio;

/* figure X transform */
fromdiff = from->b.x - from->a.x;
todiff = to->b.x - to->a.x;
ratio = todiff / fromdiff;
m->m[0][0] = ratio;
m->m[3][0] = to->a.x - from->a.x * ratio;

/* figure Y transform */
fromdiff = from->b.y - from->a.y;
todiff = to->b.y - to->a.y;
ratio = todiff / fromdiff;
m->m[1][1] = ratio;
m->m[3][1] = to->a.y - from->a.y * ratio;
}



/*  ************************************
    *                                  *
    *        getdirs                   *
    *                                  *
    ************************************

    DESCRIPTION:  Find out which way coordinate axes are
      pointing on the screen.

    ENTRY:
      mtx -- pointer to an XFORM struct describing
        the world-to-eye transform

    EXIT: Returns 9 bits in an 'unsigned'.  The bits may be
      read via the ROLLBIT macro (in 'idraw.h').

    DERIVATION:
        We want to find out if the positive end of axis A maps
      to a positive D component in eye space.
        Assume we have a general 4x4 transform matrix 'mtx'.
      To see which way the X axis is pointing, we send the
      vector  [+inf 0 0 1]  throuh 'mtx' and see what comes out.
      The signs of things in the result vector tell us which way
      the axes are pointing.  Because of the infinite component
      in the input vector, the bottom row of 'mtx' doesn't
      matter.  Each component of the result vector is a ratio of
      two infinities, but we only care about the sign of each ratio.
      The sign of a ratio is the XOR of the signs of its numerator
      and denominator.
*/


unsigned getdirs ( mtx )
register XFORM *mtx;
{
register unsigned num,den;

/* init */
num = 0;  den = 0;

#define DO_NUM(ax,dir) \
  {if ( mtx->m[ax][dir] > 0.0 )  num |= ROLLBIT(ax,dir);}
DO_NUM(XX,XX);  DO_NUM(XX,YY);  DO_NUM(XX,ZZ);
DO_NUM(YY,XX);  DO_NUM(YY,YY);  DO_NUM(YY,ZZ);
DO_NUM(ZZ,XX);  DO_NUM(ZZ,YY);  DO_NUM(ZZ,ZZ);

#define DO_DEN(ax) \
  {if ( mtx->m[ax][3] > 0.0 )  den |= AX_MASK(ax);}
DO_DEN(XX);
DO_DEN(YY);
DO_DEN(ZZ);

return num ^ den;
}




/*  ************************************
    *                                  *
    *       axslopes                   *
    *                                  *
    ************************************

    DESCRIPTION:  Find out the slopes of the coordinate axes
      in eye space.

    ENTRY:
      mtx -- Pointer to an XFORM union containing the current
        world-to-eye transform.
      slope -- Pointer to another XFORM union to receive the
        slope matrix.  Only the upper left 3x3 submatrix
        will be filled, where each row describes the slope
        of an axis.

    EXIT:  Returns the 'slope' pointer.
*/

XFORM *axslopes ( mtx, slope )
register XFORM *mtx,*slope;
{
register float denom;

#define XXPPQQ(ax,dir)                    \
  slope->m[ax][dir] =                     \
    (mtx->m[ax][dir] + mtx->m[3][dir])    \
      / (mtx->m[ax][3] + mtx->m[3][3]);
#define DO_AX_SLP(ax) \
  { XXPPQQ(ax,XX);  XXPPQQ(ax,YY);  XXPPQQ(ax,ZZ); }

DO_AX_SLP(XX);
DO_AX_SLP(YY);
DO_AX_SLP(ZZ);

return slope;
}
@//E*O*F xform.c//
chmod u=rw,g=r,o=r xform.c
 
echo Inspecting for damage in transit...
temp=/tmp/shar$$; dtemp=/tmp/.shar$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
      15      83     454 Makefile
      53     287    2095 README
     129     686    3892 boxview.1l
      15      57     175 cube.geom
      43     165     872 sticks.geom
     214     909    6298 idraw.h
     135     566    4216 ktypes.h
     300     936    7083 cm.c
     148     429    3269 slide.c
     148     352    3045 states.c
     202     455    3520 tables.c
     209     486    4351 wm.c
     475    1363   10811 xform.c
    2086    6774   50081 total
!!!
wc  Makefile README boxview.1l cube.geom sticks.geom idraw.h ktypes.h cm.c slide.c states.c tables.c wm.c xform.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0
#------------------- cut this line and below ----------------------
-- 
-- Kelvin Thompson, Lone Rider of the Apocalypse
   kelvin at cs.utexas.edu  {...,uunet}!cs.utexas.edu!kelvin 



More information about the Comp.sys.sgi mailing list