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: BOOL ← FALSE;
[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: BOOL ← FALSE;
[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;
};
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:
REF ←
NIL]
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;
};