File: CSG.mesa
Author: Eric Bier in the summer of 1982
Copyright © 1984 by Xerox Corporation. All rights reserved.
Last edited by Bier on January 16, 1985 4:27:51 pm PST
Contents: The CSG Solids Interface. Essentially maintains a database of csg trees each of which contains one or more combined primitives. Maintaining a tree involves creating primitives and adding them to trees with the CSG operations, intersection, union, and difference.
DIRECTORY
GraphicsColor,
Rope,
SV2d,
SV3d,
SVModelTypes,
SVRayTypes;
CSG: DEFINITIONS =
BEGIN
Artwork: TYPE = SVModelTypes.Artwork;
BoundBox: TYPE = SVModelTypes.BoundBox;
BoundHedron: TYPE = SVModelTypes.BoundHedron;
BoundSphere: TYPE = SVModelTypes.BoundSphere;
Camera: TYPE = SVModelTypes.Camera;
Color: TYPE = GraphicsColor.Color;
CoordSystem: TYPE = SVModelTypes.CoordSystem;
Matrix4by4: TYPE = SV3d.Matrix4by4;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = SV3d.Point3d;
Surface: TYPE = SVRayTypes.Surface;
Vector: TYPE = SV3d.Vector;
LightSourceList: TYPE = SVModelTypes.LightSourceList;
Ray: TYPE = SVRayTypes.Ray;
PointSetOp: TYPE = SVRayTypes.PointSetOp;
Classification: TYPE = SVRayTypes.Classification;
Composite: TYPE = SVRayTypes.Composite;
CSGTree: TYPE = SVRayTypes.CSGTree;
In my current plan, all of the instances of each surface type will refer to the same underlying csg surface expressed in the instance (unit dimensions) coordinate system. Hence, I will build these primitve shapes into the code (this more or less must be done anyway because the formulas - x^2 + y^2 = R^2; z = constant, etc. - are hard to enter symbolically in Mesa).
However, for rapid rendering, I will have a line-drawing approximation to each world surface. These will involve a sweep-based representation with a finite mesh (translational sweep for blocks, rotational for cylinders and spheres). I will create one such representation for each of the primitive solid types in the same instance coordinate system in which the exact csg reps are defined. Rendering line-drawings with the sweep reps will then involve, using the same matrix transforms as are used to place the csg shapes, followed by a perspective transform and a call to 2d graphics routines.
StuffCameraRay:
PROC [ray: Ray, screenPoint: Point2d, camera: Camera];
Creates a ray which passes through screenPoint. screenPoint should be in CAMERA coordinates. If camera.projection = orthogonal, the ray is perpendicular to the screen. If camera.projection = perspective, the ray has the same direction [eyepoint, screenPoint]. In any case, the ray originates from screenPoint (not, alas, eyepoint) and has "length" camera.focalLength.
StuffWorldRayFromCamera:
PROC [ray: Ray, screenPoint: Point2d, camera: Camera];
The ray is in World coordinates but is the same ray as would be computed by StuffCameraRay.
StuffCameraRayLiterally: PROC [ray: Ray, base: Point3d, direction: Vector];
StuffWorldRay: PROC [ray: Ray, basePt: Point3d, direction: Vector, camera: Camera];
StuffWorldOnlyRay: PROC [ray: Ray, basePt: Point3d, direction: Vector];
StuffWorldRayFromPoints:
PROC [ray: Ray, basePt: Point3d, directionPt: Point3d];
Useful for shadow rays which originate in the scene. Assumes basePt and direction are in WORLD coordinates.
StuffLocalRay:
PROC [ray: Ray, basePt: Point3d, direction: Vector, camera: Camera, localCS: CoordSystem];
basePt and direction must be in the frame of localCS.
EvaluateCameraRay: PROC [ray: Ray, t: REAL] RETURNS [pt: Point3d];
EvaluateWorldRay: PROC [ray: Ray, t: REAL] RETURNS [pt: Point3d];
EvaluateLocalRay: PROC [ray: Ray, t: REAL] RETURNS [pt: Point3d];
EvaluateLocalRay2: PROC [ray: Ray, t: REAL] RETURNS [x, y, z: REAL];
GetCameraRay: PROC [ray: Ray] RETURNS [basePt: Point3d, direction: Vector];
GetWorldRay: PROC [ray: Ray] RETURNS [basePt: Point3d, direction: Vector];
GetLocalRay: PROC [ray: Ray] RETURNS [basePt: Point3d, direction: Vector];
CreateRay: PROC RETURNS [ray: Ray];
Pools of Large Records for Recycling.
GetRayFromPool: PROC RETURNS [ray: Ray];
ReturnRayToPool: PROC [ray: Ray];
TransformRay:
PROC [ray: Ray, mat: Matrix4by4]
RETURNS [newRay: Ray];
Say ray is in terms of Coordinate frame CAMERA. Then if mat is CAMERAWORLD, newRay will be in terms of WORLD. Remember to ReturnRayToPool when done.
TransformRayToWorld:
PROC [ray: Ray, camera
WORLD: Matrix4by4]
RETURNS [newRay: Ray];
Exactly like TransformRay except that the ray will remember its WORLD coordinate self even after it is transformed to somewhere else.
TransformNewRay:
PROC [ray: Ray, mat: Matrix4by4]
RETURNS [newRay: Ray];
Like TransformRay except that the ray is allocated with NEW so do NOT ReturnRayToPool.
AddRay:
PROC [ray1, ray2: Ray];
Puts sum in ray2.
SubtractRays:
PROC [ray1, ray2: Ray]
RETURNS [ray1MinusRay2: Ray];
Puts difference in ray2.
CopyClass:
PROC [class: Classification]
RETURNS [copy:
Classification];
Creates a NEW Classification from the Heap (not from the pool -- no need to return).
MakeCompositeCell: PROC [name: Rope.ROPE, operation: PointSetOp, LeftSolidPtr: REF ANY, RightSolidPtr: REF ANY] RETURNS [c: Composite];
MakeCSGTree: PROC [son: REF ANY, backgroundColor: Color, shadows: BOOL] RETURNS [tree: CSGTree];
CombineBoundBoxes:
PROC [bb1, bb2: BoundBox, op: PointSetOp]
RETURNS [newBB: BoundBox];
Dispatches to the appropriate SVBoundBox procedure depending on op.
CombineBoundSpheres:
PROC [bs1, bs2: BoundSphere, op: PointSetOp]
RETURNS [newBS: BoundSphere];
Dispatches to the appropriate SVBoundSphere procedure depending on op.
RayHitsBoundSphere: PROC [worldRay: Ray, boundSphere: BoundSphere] RETURNS [BOOL];
PointSetOpToRope: PROC [pointSetOp: PointSetOp] RETURNS [opRope: Rope.ROPE];
RopeToPointSetOp:
PROC [opRope: Rope.
ROPE]
RETURNS [pointSetOp: PointSetOp];
Hit testing for bounding spheres.
END.