DisplayList3dImplB.mesa
Last edited by Bier on December 22, 1982 12:01 am
Author: Eric Bier on August 18, 1983 1:49 pm (when DisplayList3dImpl overflowed)
DIRECTORY
 CastRays,
 CoordSys,
CSG,
 CSGGraphics,
 DisplayList3d,
 DisplayList3dPrivate,
 Graphics,
 GraphicsColor,
 Matrix3d,
 PriorityQueue,
 Rope,
 Shading,
 SV2d,
 SVPolygon3d,
 SVTransforms,
 SVVector3d;

DisplayList3dImplB: PROGRAM
IMPORTS CastRays, CoordSys, CSGGraphics, Graphics, GraphicsColor, DisplayList3d, DisplayList3dPrivate, Matrix3d, PriorityQueue, Rope, SVTransforms
EXPORTS DisplayList3d, DisplayList3dPrivate =
BEGIN
Imported Types
Camera: TYPE = REF CameraObj;
CameraObj: TYPE = CSGGraphics.CameraObj;
Classification: TYPE = REF ClassificationObj;
ClassificationObj: TYPE = CSG.ClassificationObj;
Color: TYPE = GraphicsColor.Color;
CoordSysList: TYPE = CoordSys.CoordSysList;
CoordSysObj: TYPE = CoordSys.CoordSysObj;
CoordSystem: TYPE = REF CoordSysObj;
CSGTree: TYPE = REF CSGTreeObj;
CSGTreeObj: TYPE = CSG.CSGTreeObj;
DrawStyle: TYPE = CSGGraphics.DrawStyle;
FileCamera: TYPE = REF FileCameraObj;
FileCameraObj: TYPE = DisplayList3d.FileCameraObj;
FileCameraList: TYPE = DisplayList3d.FileCameraList;
FrameBox: TYPE = REF FrameBoxObj;
FrameBoxObj: TYPE = CSGGraphics.FrameBoxObj;
Matrix4by4: TYPE = Matrix3d.Matrix4by4;
Plane: TYPE = SVPolygon3d.Plane;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = Matrix3d.Point3d;
PointSetOp: TYPE = CSG.PointSetOp; -- {union, intersection, difference}
Poly3d: TYPE = SVPolygon3d.Poly3d;
Primitive: TYPE = REF PrimitiveObj;
PrimitiveObj: TYPE = CSG.PrimitiveObj;
Ray: TYPE = REF RayObj;
RayObj: TYPE = CSG.RayObj;
Vector: TYPE = SVVector3d.Vector;
DisplayList Types
Databases, Scenes, Assemblies, and Lightsources
Database: TYPE = REF DatabaseObj;
DatabaseObj: TYPE = DisplayList3d.DatabaseObj;
Scene: TYPE = REF SceneObj;
SceneObj: TYPE = DisplayList3d.SceneObj;
Assembly: TYPE = REF AssemblyObj;
AssemblyObj: TYPE = DisplayList3d.AssemblyObj;
AssemblyList: TYPE = REF AssemblyListObj;
AssemblyListObj: TYPE = DisplayList3d.AssemblyListObj;
LightSource: TYPE = REF LightSourceObj;
LightSourceObj: TYPE = Shading.LightSourceObj;
LightSourceList: TYPE = Shading.LightSourceList;
Master Object Class Types
MasterObjectClass: TYPE = REF MasterObjectClassObj;
MasterObjectClassObj: TYPE = DisplayList3d.MasterObjectClassObj;
MasterObjectClassList: TYPE = DisplayList3d.MasterObjectClassList;
FileoutProc: TYPE = DisplayList3d.FileoutProc;
FileinProc: TYPE = DisplayList3d.FileinProc;
Master Object Types
MasterObject: TYPE = REF MasterObjectRec;
MasterObjectRec: TYPE = DisplayList3d.MasterObjectRec;
MasterObjectList: TYPE = DisplayList3d.MasterObjectList;
RayCastProc: TYPE = CSG.RayCastProc;
RayCastNoBBoxesProc: TYPE = CSG.RayCastNoBBoxesProc;
PreprocessProc: TYPE = DisplayList3d.PreprocessProc;
LineDrawProc: TYPE = DisplayList3d.LineDrawProc;
NormalsDrawProc: TYPE = DisplayList3d.NormalsDrawProc;
CountPlanarSurfacesProc: TYPE = DisplayList3d.CountPlanarSurfacesProc;
GetPlanarSurfacesProc: TYPE = DisplayList3d.GetPlanarSurfacesProc;
PlanarSurface: TYPE = REF PlanarSurfaceObj;
PlanarSurfaceObj: TYPE = DisplayList3d.PlanarSurfaceObj;
PlanarSurfaceList: TYPE = DisplayList3d.PlanarSurfaceList;
DrawPlanarSurfaceProc: TYPE = DisplayList3d.DrawPlanarSurfaceProc;
DrawSubBoxesProc: TYPE = DisplayList3d.DrawSubBoxesProc;
Noop Procedures
A master object can use these entries if it doesn't implement one of these procedures
NoOpRayCast: PUBLIC RayCastProc = {
class ← CastRays.GetClassFromPool[];
CastRays.MakeClassAMiss[class];
};
NoOpRayCastNoBBoxes: PUBLIC RayCastNoBBoxesProc = {
class ← CastRays.GetClassFromPool[];
CastRays.MakeClassAMiss[class];
};
NoOpPreprocess: PUBLIC PreprocessProc = {}; -- don't preprocess anything
NoOpLineDraw: PUBLIC LineDrawProc = {}; -- don't draw anything
NoOpNormalsDraw: PUBLIC NormalsDrawProc = {}; -- don't draw anything
NoOpCountPlanarSurfaces: PUBLIC CountPlanarSurfacesProc = {RETURN[0]};
Say you don't have any
NoOpGetPlanarSurfaces: PUBLIC GetPlanarSurfacesProc = {RETURN[NIL]};
Return the empty list
NoOpDrawPlanarSurface: PUBLIC DrawPlanarSurfaceProc = {}; -- don't draw anything
NoOpDrawSubBoxes: PUBLIC DrawSubBoxesProc = {};  -- don't draw anything
Delete Parts of the Scene Tree
DeleteMasterObjectNamed: PUBLIC PROC [moName: Rope.ROPE, scene: Scene] RETURNS [found: BOOL] = {
mo, beforeMo, afterMo: MasterObjectList;
[beforeMo, mo, afterMo, found] ← DisplayList3dPrivate.FindMasterObjectAndNeighborsFromName[moName, scene.masterObjects];
IF NOT found THEN RETURN;
IF beforeMo = NIL THEN scene.masterObjects ← afterMo
ELSE beforeMo.rest ← afterMo;
}; -- end of DeleteMasterObjectNamed
DeleteMasterObjectIfUnused: PUBLIC PROC [mo: MasterObject, scene: Scene] RETURNS [found: BOOL] = {
IF Rope.Equal[mo.class.name, "sphere"] OR Rope.Equal[mo.class.name, "block"] OR Rope.Equal[mo.class.name, "cylinder"] OR Rope.Equal[mo.class.name, "cone"] THEN
RETURN[TRUE];
For now, we won't delete the built-in instances.
FOR primitiveAssemblies: LIST OF Assembly ← DisplayList3d.ListOfPrimAssemblies[scene.assembly, scene], primitiveAssemblies.rest UNTIL primitiveAssemblies = NIL DO
IF primitiveAssemblies.first.object = mo THEN RETURN[TRUE];
ENDLOOP;
found ← DeleteMasterObjectNamed[mo.name, scene];
}; -- end of DeleteMasterObjectIfUnused
DeleteCoordSysNamed: PUBLIC PROC [csName: Rope.ROPE, scene: Scene] = {
cs, beforeCS, afterCS: CoordSysList;
notFound: BOOLFALSE;
[beforeCS, cs, afterCS] ← CoordSys.FindCoordSysAndNeighborsFromName[csName, scene.coordSystems
!CoordSys.CoordSysNotFound => {notFound ← TRUE; CONTINUE}];
IF notFound THEN RETURN;
IF beforeCS = NIL THEN scene.coordSystems ← afterCS
ELSE beforeCS.rest ← afterCS;
}; -- end of DeleteCoordSysNamed
DeleteLightSourceNamed: PUBLIC PROC [lsName: Rope.ROPE, scene: Scene] = {
ls, beforeLS, afterLS: LightSourceList;
notFound: BOOLFALSE;
[beforeLS, ls, afterLS] ← DisplayList3dPrivate.FindLightSourceAndNeighborsFromName[lsName, scene.lightSources
!DisplayList3dPrivate.LightSourceNotFound => {notFound ← TRUE; CONTINUE}];
IF notFound THEN RETURN;
IF beforeLS = NIL THEN scene.lightSources ← afterLS
ELSE beforeLS.rest ← afterLS;
}; -- end of DeleteLightSourceNamed
ClearScene: PUBLIC PROC [scene: Scene] = {
scene.assembly.object ← NEW[AssemblyListObj ← [NIL, union] ];
ClearCoordSystems[scene];
ClearMasterObjects[scene];
};
ClearCoordSystems: PUBLIC PROC [scene: Scene] = {
Removes all but WORLD, SCREEN and sceneAssembly.
Assumes for now that WORLD, and SCREEN are the first 2 coordsystems on the list.
z: CoordSysList ← scene.coordSystems; -- WORLD
z ← z.rest;-- SCREEN
z ← z.rest;-- sceneAssembly
z.rest ← NIL;-- cut off the rest
};
ClearMasterObjects: PUBLIC PROC [scene: Scene] = {
Removes all but "block", "sphere", "cone", and "cylinder" from current scene.
Assumes for now that "sphere","cone", and "cylinder", and "block" are the first five master objects.
z: MasterObjectList ← scene.masterObjects; -- "sphere"
z ← z.rest;-- "block"
z ← z.rest;-- "cone"
z ← z.rest;-- "cylinder"
z.rest ← NIL;-- cut off the rest
};
DeleteSubassemblyFromAssembly: PUBLIC PROC [subassembly: Assembly, assembly: Assembly, scene: Scene] RETURNS [success: BOOL] = {
IF ISTYPE[assembly.object,AssemblyList] THEN
[assembly.object, success] ← RemoveFromAssemblyList[subassembly,
NARROW[assembly.object,AssemblyList], scene]
ELSE ERROR;
};
RemoveFromAssemblyList: PRIVATE PROC [a: Assembly, al: AssemblyList, scene: Scene] RETURNS [newAl: AssemblyList, success: BOOL] = {
Tree walk through the assembly deleting all of its coordinate systems. Then, cut the assembly loose and feed it to the garbage collector.
lastAssemblyList: LIST OF Assembly ← al.list;
IF lastAssemblyList.first = a THEN {-- first item on the list
DeleteAssemblyAndSons[a, scene];
al.list ← lastAssemblyList.rest; RETURN[al, TRUE] };
FOR l: LIST OF Assembly ← lastAssemblyList.rest, l.rest UNTIL l = NIL DO
IF l.first = a THEN {
DeleteAssemblyAndSons[a, scene];
success ← TRUE;
lastAssemblyList.rest ← l.rest; -- splice out a
newAl ← al;
RETURN;
}
ELSE lastAssemblyList ← lastAssemblyList.rest;
ENDLOOP;
success ← FALSE;
};
TemporaryRemoveFromAssemblyList: PUBLIC PROC [a: Assembly, al: AssemblyList, scene: Scene] RETURNS [newAl: AssemblyList, success: BOOL] = {
A simple list remove operation. Not break up the assembly and its sons, nor does it delete their coordinate systems. This routine is called by MoveToFrontOfAssembly to splice an assembly out of an AssemblyList
lastAssemblyList: LIST OF Assembly ← al.list;
IF lastAssemblyList.first = a THEN {-- first item on the list
al.list ← lastAssemblyList.rest; RETURN[al, TRUE] };
FOR l: LIST OF Assembly ← lastAssemblyList.rest, l.rest UNTIL l = NIL DO
IF l.first = a THEN {
success ← TRUE;
lastAssemblyList.rest ← l.rest; -- splice out a
newAl ← al;
RETURN;
}
ELSE lastAssemblyList ← lastAssemblyList.rest;
ENDLOOP;
success ← FALSE;
};
DeleteAssemblyAndSons: PRIVATE PROC [a: Assembly, scene: Scene] = {
DeleteCoordSysNamed[a.coordSys.name, scene];
WITH a.object SELECT FROM
alist: AssemblyList => DeleteAssemblyListAndSons[alist, scene];
mo: MasterObject => RETURN;
ENDCASE => ERROR;
};
DeleteAssemblyListAndSons: PRIVATE PROC [alist: AssemblyList, scene: Scene] = {
FOR list: LIST OF Assembly ← alist.list, list.rest UNTIL list = NIL DO
DeleteAssemblyAndSons[list.first, scene];
ENDLOOP;
};
Other List Auxiliaries
Removing Duplicates
RemoveDuplicateMOs: PUBLIC PROC [moList: MasterObjectList] RETURNS [uniqueList: MasterObjectList] = {
**** Naive algorithm for now. Go through moList. Add anything to uniqueList which it doesn't already have
thisMO: MasterObject;
uniqueList ← NIL;
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
thisMO ← list.first;
IF NOT ObjectNameInList[thisMO.name, uniqueList] THEN
uniqueList ← CONS[thisMO, uniqueList];
ENDLOOP;
};
ObjectNameInList: PRIVATE PROC [moName: Rope.ROPE, moList: MasterObjectList] RETURNS [BOOL]= {
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
IF Rope.Equal[list.first.name, moName, TRUE] THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};
MoListMinusMoList: PUBLIC PROC [moList1, moList2: MasterObjectList] RETURNS [moList1MinusmoList2: MasterObjectList] = {
Find all elements of moList1 which are not in moList2
moList1MinusmoList2 ← NIL;
FOR list: MasterObjectList ← moList1, list.rest UNTIL list = NIL DO
IF NOT ObjectNameInList[list.first.name, moList2] THEN
moList1MinusmoList2 ← CONS[list.first, moList1MinusmoList2];
ENDLOOP;
};
CopyMasterObjectList: PUBLIC PROC [moList: MasterObjectList] RETURNS [copy: MasterObjectList] = {
Currently this has O[n2] behavior. Since moList typically has 4 elements, this is alright. Improve if moList grows.
copy ← NIL;
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
copy ← DisplayList3dPrivate.AppendToMasterObjects[list.first, copy];
ENDLOOP;
};
Draw Parts of the Scene Tree
DrawScene: PUBLIC PROC [dc: Graphics.Context, scene: Scene, camera: Camera] = {
mark: Graphics.Mark;
SVTransforms.TellAboutCameraAndWorld[scene.assembly, camera, scene];
Clip the picture to the camera's frame
mark ← Graphics.Save[dc];
CSGGraphics.Clip[dc, camera];
Draw the current bounding frame if there is one.
IF NOT camera.frame.fullScreen THEN {
SetColor[dc, camera, GraphicsColor.black];
CSGGraphics.DrawFrame[dc, camera];
};
SELECT camera.style FROM
wire => DrawWireAssemblies[dc, scene, camera];
shaded => DrawShadedAssemblies[dc, scene, camera];
normals => DrawNormalsAssemblies[dc, scene, camera];
ENDCASE => SIGNAL NotYetImplemented;
Graphics.Restore[dc, mark];
};
NotYetImplemented: PUBLIC SIGNAL = CODE;
DrawWireAssemblies: PRIVATE PROC [dc: Graphics.Context, scene: Scene, camera: Camera] = {
assemblyName: Rope.ROPE;
found: BOOL;
assembly: Assembly;
FOR list: LIST OF Rope.ROPE ← camera.visibleAssemblies, list.rest UNTIL list = NIL DO
assemblyName ← list.first;
found ← TRUE;
[assembly, ----] ← DisplayList3d.FindAssemblyFromName[assemblyName, scene
!DisplayList3d.AssemblyNotFound => {found ← FALSE; CONTINUE}];
IF found THEN DrawWireAssembly[dc, assembly, scene, camera];
ENDLOOP;
};
DrawShadedAssemblies: PRIVATE PROC [dc: Graphics.Context, scene: Scene, camera: Camera] = {
assemblyName: Rope.ROPE;
assembly: Assembly;
found: BOOL;
FOR list: LIST OF Rope.ROPE ← camera.visibleAssemblies, list.rest UNTIL list = NIL DO
assemblyName ← list.first;
found ← TRUE;
[assembly, ----] ← DisplayList3d.FindAssemblyFromName[assemblyName, scene
!DisplayList3d.AssemblyNotFound => {found ← FALSE; CONTINUE}];
IF found THEN DrawShadedAssembly[dc, assembly, scene, camera];
ENDLOOP;
};
DrawNormalsAssemblies: PRIVATE PROC [dc: Graphics.Context, scene: Scene, camera: Camera] = {
assemblyName: Rope.ROPE;
assembly: Assembly;
found: BOOL;
FOR list: LIST OF Rope.ROPE ← camera.visibleAssemblies, list.rest UNTIL list = NIL DO
assemblyName ← list.first;
found ← TRUE;
[assembly, ----] ← DisplayList3d.FindAssemblyFromName[assemblyName, scene
!DisplayList3d.AssemblyNotFound => {found ← FALSE; CONTINUE}];
IF found THEN DrawNormalsAssembly[dc, assembly, scene, camera];
ENDLOOP;
};
DrawAssembly: PUBLIC PROC [dc: Graphics.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
SVTransforms.TellAboutCameraAndWorld[assembly, camera, scene];
Clip the picture to the camera's frame
CSGGraphics.Clip[dc, camera];
SELECT camera.style FROM
wire => DrawWireAssembly[dc, assembly, scene, camera];
shaded => DrawShadedAssembly[dc, assembly, scene, camera];
normals => DrawNormalsAssembly[dc, assembly, scene, camera];
ENDCASE => SIGNAL NotYetImplemented;
};
SetColor: PRIVATE PROC [dc: Graphics.Context, camera: Camera, color: Color] = {
IF camera.colorFilm THEN Graphics.SetColor[dc, color]
ELSE {
intensity: REAL ← GraphicsColor.ColorToIntensity[color];
Graphics.SetColor[dc, GraphicsColor.IntensityToColor[intensity]]};
};
DrawWireAssembly: PRIVATE PROC [dc: Graphics.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
Graphics.SetColor[dc, GraphicsColor.black];
Draw the current bounding frame if there is one.
IF NOT camera.frame.fullScreen THEN {
CSGGraphics.DrawFrame[dc, camera];
};
DrawWireAssembly2[dc, assembly, scene, camera];
};
DrawWireAssembly2: PRIVATE PROC [dc: Graphics.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
lightSources: LightSourceList ← scene.lightSources;
WITH assembly.object SELECT FROM
assems: AssemblyList => {
FOR subassemblies: LIST OF Assembly ← assems.list, subassemblies.rest
UNTIL subassemblies = NIL DO
DrawWireAssembly2[dc: dc, assembly: subassemblies.first, scene: scene, camera: camera];
ENDLOOP;
};
mo: MasterObject => {
Graphics.SetColor[dc, assembly.color];
mo.class.lineDraw[dc, mo.lineBody, camera, assembly.coordSys];
};
ENDCASE => ERROR;
};
CountSurfacesInAssemblyList: PRIVATE PROC [asl: AssemblyList] RETURNS [surfCount: NAT] = {
surfCount ← 0;
FOR list: LIST OF Assembly ← asl.list, list.rest UNTIL list = NIL DO
surfCount ← surfCount + CountSurfacesInAssembly[list.first];
ENDLOOP;
};
CountSurfacesInAssembly: PRIVATE PROC [assembly: Assembly] RETURNS [surfCount: NAT] = {
WITH assembly.object SELECT FROM
assems: AssemblyList => surfCount ← CountSurfacesInAssemblyList[assems];
mo: MasterObject => surfCount ← mo.class.countSurf[mo];
ENDCASE => ERROR;
};
PutAssemblyListOnQueue: PRIVATE PROC [asl: AssemblyList, q: PriorityQueue.Ref, cameraCS: CoordSystem] = {
FOR list: LIST OF Assembly ← asl.list, list.rest UNTIL list = NIL DO
PutAssemblyOnQueue[list.first, q, cameraCS];
ENDLOOP;
};
PutAssemblyOnQueue: PRIVATE PROC [assembly: Assembly, q: PriorityQueue.Ref, cameraCS: CoordSystem] = {
thisSurf: PlanarSurface;
cameraNormal: Vector;
WITH assembly.object SELECT FROM
assems: AssemblyList => PutAssemblyListOnQueue[assems, q, cameraCS];
mo: MasterObject => {
surfList: PlanarSurfaceList ← mo.class.getSurf[assembly, cameraCS];
FOR surfList ← surfList, surfList.rest UNTIL surfList = NIL DO
thisSurf ← surfList.first;
cameraNormal ← Matrix3d.UpdateVectorWithInverse[thisSurf.assembly.coordSys.cameraWRTlocal, thisSurf.normal];
thisSurf.normal ← cameraNormal;
Eliminate most back-facing surfaces at this point by a simple test.
IF thisSurf.normal[3] >0 THEN PriorityQueue.Insert[q,thisSurf];
ENDLOOP;
};
ENDCASE => ERROR;
}; -- end of PutAssemblyOnQueue
DeeperPlanarSurface: SAFE PROC [x,y: PriorityQueue.Item, data: REFNIL] RETURNS [BOOL] = TRUSTED {
xS: PlanarSurface ← NARROW[x];
yS: PlanarSurface ← NARROW[y];
RETURN[xS.depth < yS.depth];
};
DrawShadedAssembly: PRIVATE PROC [dc: Graphics.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
Get a list of surfaces from each subassembly of "assembly" and draw them with the Painter's Algorithm (back to front)
Count the total number of surfaces and make a priority queue of the appropriate size.
predictedQueueSize: NAT ← CountSurfacesInAssembly[assembly];
surfaceQueue: PriorityQueue.Ref ←
PriorityQueue.Predict[predictedQueueSize, DeeperPlanarSurface];
mo: MasterObject;
thisPlanarSurf: PlanarSurface;
box: Graphics.Box;
mark: Graphics.Mark ← Graphics.Save[dc];
Now put the surfaces on the queue
PutAssemblyOnQueue[assembly, surfaceQueue, camera.coordSys];
Draw a background color.
box ← Graphics.GetBounds[dc];
SetColor[dc, camera, scene.backgroundColor];
Graphics.DrawBox[dc, box];
Draw the current bounding frame if there is one.
IF NOT camera.frame.fullScreen THEN {
SetColor[dc, camera, GraphicsColor.black];
CSGGraphics.DrawFrame[dc, camera];
};
Take the surfaces off the queue in order and draw them
FOR i: NAT IN[1..PriorityQueue.Size[surfaceQueue]] DO
thisPlanarSurf ← NARROW[PriorityQueue.Remove[surfaceQueue]];
mo ← thisPlanarSurf.mo;
mo.class.drawSurf[dc, thisPlanarSurf, scene.lightSources, camera];
ENDLOOP;
Graphics.Restore[dc, mark];
};
DrawNormalsAssembly: PROC [dc: Graphics.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
Graphics.SetColor[dc, GraphicsColor.black];
Draw the current bounding frame if there is one.
IF NOT camera.frame.fullScreen THEN {
CSGGraphics.DrawFrame[dc, camera];
};
DrawNormalsAssembly2[dc, assembly, scene, camera];
};
DrawNormalsAssembly2: PROC [dc: Graphics.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
lightSources: LightSourceList ← scene.lightSources;
WITH assembly.object SELECT FROM
assems: AssemblyList => {
FOR subassemblies: LIST OF Assembly ← assems.list, subassemblies.rest
UNTIL subassemblies = NIL DO
DrawNormalsAssembly2[dc: dc, assembly: subassemblies.first, scene: scene, camera: camera];
ENDLOOP;
};
mo: MasterObject => {
Graphics.SetColor[dc, assembly.color];
mo.class.normalsDraw[dc, mo.shadeBody, camera, assembly.coordSys];
};
ENDCASE => ERROR;
};
END.