ThreeDBasicsImpl.mesa
Copyright © 1984, 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Crow, February 9, 1988 5:32:02 pm PST
Bloomenthal, August 14, 1988 5:26:51 pm PDT
DIRECTORY
Atom     USING [ GetPropFromList, PutPropOnList, PropList, RemPropFromList ],
Commander   USING [ PrependWorkingDir ],
G3dVector    USING [ Length, Sub ],
G3dMatrix    USING [ Identity, MakeRotate, Mul ],
ImagerColorMap  USING [ SetStandardColorMap ],
Rope     USING [ Length, ROPE, Substr ],
Real     USING [ Fix, Float ],
RealFns    USING [ SqRt ],
RuntimeError  USING [ BoundsFault ],
ThreeDBasics  USING [ Box, Context, ContextClass, ErrorDesc, Patch, Rectangle, RGB,
         ShadingClass, ShapeClass, ShapeInstance, Triple, Xfm3DRep ];
ThreeDBasicsImpl: CEDAR PROGRAM
IMPORTS Atom, Commander, G3dMatrix, G3dVector, ImagerColorMap, Real, RealFns, Rope, RuntimeError
EXPORTS ThreeDBasics
~ BEGIN
Basic Types
Error: PUBLIC SIGNAL [reason: ThreeDBasics.ErrorDesc] = CODE;
Context: TYPE ~ ThreeDBasics.Context;
RGB: TYPE ~ ThreeDBasics.RGB;
Triple: TYPE ~ ThreeDBasics.Triple;
Xfm3DRep: TYPE ~ ThreeDBasics.Xfm3DRep;
Rectangle: TYPE ~ ThreeDBasics.Rectangle;
Box: TYPE ~ ThreeDBasics.Box;
Patch: TYPE ~ ThreeDBasics.Patch;
ShapeInstance: TYPE ~ ThreeDBasics.ShapeInstance;
ContextClass: TYPE ~ ThreeDBasics.ContextClass;
ShadingClass: TYPE ~ ThreeDBasics.ShadingClass;
ShapeClass: TYPE ~ ThreeDBasics.ShapeClass;
Global Variables
registeredDisplayTypes: Atom.PropList ← NIL;   -- keeps active display types
registeredSurfaceTypes: Atom.PropList ← NIL;   -- keeps active surface types
registeredShadingClasses: Atom.PropList ← NIL;   -- keeps active shading classes
Utility Procedures
Sqr: PROCEDURE [number: REAL] RETURNS [REAL] ~ INLINE { RETURN[number * number]; };
RectangleFromBox: PUBLIC PROC[box: Box] RETURNS[ Rectangle] ~ {
RETURN [[
x: Real.Float[box.min.f],
y: Real.Float[box.min.s],
w: Real.Float[box.max.f - box.min.f],
h: Real.Float[box.max.s - box.min.s]
]];
};
BoxFromRectangle: PUBLIC PROC[ rect: Rectangle ] RETURNS[ Box ] ~ {
RETURN [[
min: [ f: Real.Fix[rect.x], s: Real.Fix[rect.y] ],
max: [ f: Real.Fix[rect.x + rect.w], s: Real.Fix[rect.y + rect.h] ]
]];
};
IntersectRectangles: PUBLIC PROC[ rect1, rect2: Rectangle ] RETURNS[ Rectangle ] ~ {
intersection: Rectangle;
intersection.x ← MAX[rect1.x, rect2.x];
intersection.y ← MAX[rect1.y, rect2.y];
intersection.w ← MIN[rect1.w - (intersection.x - rect1.x), rect2.w - (intersection.x - rect2.x)];
intersection.h ← MIN[rect1.h - (intersection.y - rect1.y), rect2.h - (intersection.y - rect2.y)];
RETURN [intersection];
};
Procedures for Registering Classes
RegisterDisplayType: PUBLIC PROC[ class: ContextClass, type: ATOM ] ~ {
registeredDisplayTypes ← Atom.PutPropOnList[registeredDisplayTypes,
              type, NEW[ContextClass ← class] ]; 
};
GetDisplayType: PUBLIC PROC[ type: ATOM ] RETURNS[ class: ContextClass ] ~ {
refClass: REF ContextClass ← NARROW[Atom.GetPropFromList[registeredDisplayTypes, type]];
IF refClass # NIL
THEN class ← refClass^
ELSE SIGNAL Error[[$Unimplemented, "Unregistered display type"]]
};
LoadDisplayType: PUBLIC PROC[ context: REF Context, type: ATOM ] ~ {
class: REF ContextClass ← NARROW[Atom.GetPropFromList[registeredDisplayTypes, type]];
IF class = NIL THEN Error[[$Unimplemented, "Unregistered display type"]];
context.class ← NEW[ ContextClass ← class^ ];
context.pixels ← NIL;          --this and next line for saving VM
context.displayProps ← Atom.RemPropFromList[context.displayProps, $FullDisplayMemory];
context.class.setUpDisplayType[context];   -- maps in pixels, sets up color map
IF Atom.GetPropFromList[context.props, $BufferContext] # NIL THEN {
SIGNAL Error[[$Warning, "Dropping Buffer context"]];  -- insufficient info to update
context.props ← Atom.RemPropFromList[context.props, $BufferContext];
};
WITH Atom.GetPropFromList[context.props, $BackGround] SELECT FROM
backGrdCtx: REF Context => {
SIGNAL Error[[$Warning, "Dropping BackGround context"]]; -- no info for update
context.props ← Atom.RemPropFromList[context.props, $BackGround];
};
ENDCASE;
};
RegisterSurfaceType: PUBLIC PROC[ class: ShapeClass, type: ATOM ] ~ {
registeredSurfaceTypes ← Atom.PutPropOnList[registeredSurfaceTypes,
              type, NEW[ShapeClass ← class] ]; 
};
GetSurfaceType: PUBLIC PROC[ type: ATOM ] RETURNS[ class: ShapeClass ] ~ {
refClass: REF ShapeClass ← NARROW[Atom.GetPropFromList[registeredSurfaceTypes, type]];
IF refClass # NIL
THEN class ← refClass^
ELSE SIGNAL Error[[$Unimplemented, "Unregistered surface type"]];
};
LoadSurfaceType: PUBLIC PROC[shape: REF ShapeInstance, type: ATOM ← $ConvexPolygon] ~{
class: REF ShapeClass ← NARROW[Atom.GetPropFromList[registeredSurfaceTypes, type]];
IF class = NIL THEN SIGNAL Error[[$Unimplemented, "Unregistered surface type"]];
IF shape.class = NIL
THEN shape.class ← NEW[ ShapeClass ← class^ ]
ELSE {
new: REF ShapeClass ← NEW[ ShapeClass ← class^ ];
IF new.validate = NIL THEN new.validate ← shape.class.validate;
IF new.display = NIL THEN new.display ← shape.class.display;
IF new.displayPatch = NIL THEN new.displayPatch ← shape.class.displayPatch;
IF new.doBeforeFrame = NIL THEN new.doBeforeFrame ← shape.class.doBeforeFrame;
shape.class ← new;
};
IF shape.shadingClass = NIL THEN LoadShadingClass[shape];   -- load default class
shape.shadingInValid ← TRUE;  -- in case we're changing the type on an existing shape
shape.vtcesInValid ← TRUE;
shape.props ← Atom.RemPropFromList[ shape.props, $LinesList ];  -- list may not be valid
};
RegisterShadingClass: PUBLIC PROC[ class: ShadingClass, type: ATOM ] ~ {
Adds class to list of registered ShadingClasses, for fancy texturing procs, etc.
registeredShadingClasses ← Atom.PutPropOnList[registeredShadingClasses,
              type, NEW[ShadingClass ← class] ];
};
GetShadingClass: PUBLIC PROC[ type: ATOM ] RETURNS[ class: ShadingClass ] ~ {
Retrieves registered class for use or modification
ref: REF ShadingClass ← NARROW[Atom.GetPropFromList[registeredShadingClasses, type]];
IF ref # NIL
THEN class ← ref^
ELSE SIGNAL Error[[$Unimplemented, "Unregistered shading class"]];
};
LoadShadingClass: PUBLIC PROC[ shape: REF ShapeInstance, type: ATOM ← $Default ] ~ {
Puts ShadingClass in shape record
class: REF ShadingClass ← NARROW[Atom.GetPropFromList[registeredShadingClasses, type]];
IF class = NIL THEN SIGNAL Error[[$Unimplemented, "Unregistered shading class"]];
IF shape.shadingClass = NIL
THEN shape.shadingClass ← NEW[ ShadingClass ← class^ ]
ELSE {
new: REF ShadingClass ← NEW[ ShadingClass ← class^ ];
IF new.shadingType = NIL THEN new.shadingType ← shape.shadingClass.shadingType;
new.color ← shape.shadingClass.color;
new.shininess ← shape.shadingClass.shininess;
new.transmittance ← shape.shadingClass.transmittance;
IF new.patchShade = NIL THEN new.patchShade ← shape.shadingClass.patchShade;
IF new.texture = NIL THEN new.texture ← shape.shadingClass.texture;
IF new.cnvrtVtx = NIL THEN new.cnvrtVtx ← shape.shadingClass.cnvrtVtx;
IF new.getColor = NIL THEN new.getColor ← shape.shadingClass.getColor;
IF new.loadShapeAux = NIL THEN new.loadShapeAux ←
               shape.shadingClass.loadShapeAux;
IF new.loadVtxAux = NIL THEN new.loadVtxAux ← shape.shadingClass.loadVtxAux;
IF new.shadeVtx = NIL THEN new.shadeVtx ← shape.shadingClass.shadeVtx;
shape.shadingClass ← new;
};
shape.shadingProps ← NIL;  -- WHY???
};
Procedures for Standard Operations
Create: PUBLIC PROC[] RETURNS [REF Context] ~ {
context: REF Context ← NEW[Context];
Get Working directory
wDir: Rope.ROPE ← Commander.PrependWorkingDir[" "];  -- add needed space (wierdness)
wDir ← Rope.Substr[ base: wDir, len: Rope.Length[wDir] - 1 ];   -- drop space
context.props ← Atom.PutPropOnList[context.props, $WDir, wDir]; -- keep directory
context.eyeSpaceXfm ← G3dMatrix.Identity[];  -- can't do this in initialization, so do it here
context.stopMe ← NEW[ BOOLEANFALSE ];
RETURN[context];
};
SetView: PUBLIC PROC[context: REF Context, eyePoint, ptOfInterest: Triple,
       fieldOfView: REAL ← 40.0,
       rollAngle: REAL ← 0.0, upDirection: Triple ← [ 0., 0., 1.],
       hitherLimit: REAL ← .01, yonLimit: REAL ← 1000.0] ~ {
context.eyePoint ← eyePoint;
context.ptOfInterest ← ptOfInterest;
context.fieldOfView ← fieldOfView;
context.rollAngle ← rollAngle;
context.upDirection ← upDirection;
context.hitherLimit ← hitherLimit;
context.yonLimit ← yonLimit;
context.viewInValid ← TRUE;
};
SetPosition: PUBLIC PROC[shape: REF ShapeInstance, concat: BOOLEANFALSE] ~ {
Makes matrix from position parameters and either replaces or concatenates to the existing matrix
hypotenuse: REAL ← RealFns.SqRt[ Sqr[shape.orientation.x] + Sqr[shape.orientation.y] ];
IF NOT concat THEN shape.position ← G3dMatrix.Identity[];  -- clear to identity transform
shape.position ← G3dMatrix.Mul[
shape.position,              -- rotation about arbitrary axis
G3dMatrix.MakeRotate[
axis: G3dVector.Sub[shape.axisEnd, shape.axisBase],
theta: shape.rotation,
base: shape.axisBase
]
];
IF hypotenuse > 0.0             -- orientation
THEN {
length: REAL ← G3dVector.Length[shape.orientation];
cosA, sinA, cosB, sinB: REAL;
cosA ← shape.orientation.x / hypotenuse;
sinA ← shape.orientation.y / hypotenuse;
shape.position ← G3dMatrix.Mul[
shape.position,   -- longitudinal rotation into x-z plane, left handed about z-up
NEW[ Xfm3DRep ← [ [cosA,-sinA,0.,0.], [sinA,cosA,0.,0.], [0.,0.,1.,0.], [0.,0.,0.,1.] ] ]
];
cosB ← shape.orientation.z / length;
sinB ← hypotenuse / length;
shape.position ← G3dMatrix.Mul[
shape.position,       -- latitudinal rotation, right-handed about y-north
NEW[ Xfm3DRep ← [ [cosB,0.,-sinB,0.], [0.,1.,0.,0.], [sinB,0.,cosB,0.], [0.,0.,0.,1.] ] ]
];
shape.position ← G3dMatrix.Mul[
shape.position,   -- longitudinal rotation from x-z plane, right handed about z-up
NEW[ Xfm3DRep ← [ [cosA,sinA,0.,0.], [-sinA,cosA,0.,0.], [0.,0.,1.,0.], [0.,0.,0.,1.] ] ]
];
}
ELSE IF shape.orientation.z < 0.0 THEN shape.position ← G3dMatrix.Mul[
shape.position,              -- turn upside down
NEW[ Xfm3DRep ← [ [-1.,0.,0.,0.], [0.,1.,0.,0.], [0.,0.,-1.,0.], [0.,0.,0.,1.] ] ]
];
shape.position ← G3dMatrix.Mul[
shape.position,              -- translation
NEW[ Xfm3DRep ← [[1.,0.,0.,0.], [0.,1.,0.,0.], [0.,0.,1.,0.],
      [shape.location.x, shape.location.y, shape.location.z, 1.]] ]
];
shape.positionInValid ← FALSE;
};
CloseDisplay: PUBLIC PROC[context: REF Context] ~ {
Shuts down display gracefully, restores standard color map
context.pixels ← NIL;           -- throw away buffer bits
context.displayProps ← Atom.RemPropFromList[context.displayProps, $FullDisplayMemory];
ImagerColorMap.SetStandardColorMap[ context.terminal  -- restore standard color map
! RuntimeError.BoundsFault => CONTINUE];
}; 
END.