QuickListProcs.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Frank Crow, July 7, 1989 7:15:46 pm PDT
Quick display lists for lines.
Bloomenthal, September 26, 1988 12:04:42 pm PDT
DIRECTORY Atom, Real, Imager, ImagerBackdoor, ImagerPixel, G3dScanConvert, G3dBasic, G3dMatrix, G3dRenderWithImager, G3dClipXfmShade, G3dRender;
QuickListProcs: CEDAR PROGRAM
IMPORTS Atom, ImagerBackdoor, G3dMatrix, Real, G3dScanConvert, G3dRender, G3dRenderWithImager, G3dClipXfmShade
~ BEGIN
Type Definitions
PropList:      TYPE ~ Atom.PropList;
LORA:      TYPE ~ LIST OF REF ANY;
PixelMap:     TYPE ~ ImagerPixel.PixelMap;
Context:      TYPE ~ G3dRender.Context;
Pixel:      TYPE ~ G3dRender.Pixel;
Matrix:     TYPE ~ G3dRender.Matrix;
OutCode:     TYPE ~ G3dRender.OutCode;
NoneOut:     OutCode ~ G3dRender.NoneOut;
Patch:      TYPE ~ G3dRender.Patch;
PatchProc:    TYPE ~ G3dRender.PatchProc;
RenderData:    TYPE ~ G3dRender.RenderData;
ShapeClass:    TYPE ~ G3dRender.ShapeClass;
ShadingClass:   TYPE ~ G3dRender.ShadingClass;
Shape:     TYPE ~ G3dRender.Shape;
IntegerPairSequence: TYPE ~ G3dRender.IntegerPairSequence;
IntegerPairSequenceRep: TYPE ~ G3dBasic.IntegerPairSequenceRep;
Triple:     TYPE ~ G3dRender.Triple;
TripleSequence:   TYPE ~ G3dRender.TripleSequence;
TripleSequenceRep:  TYPE ~ G3dBasic.TripleSequenceRep;
TripleSeqSequence:  TYPE ~ REF TripleSeqSequenceRep;
TripleSeqSequenceRep: TYPE ~ RECORD[
length: NAT ← 0,
s: SEQUENCE maxLength: CARDINAL OF TripleSequence
];
PatchSequence:   TYPE ~ G3dRender.PatchSequence;
BoolSequence:   TYPE ~ REF BoolSequenceRep;
BoolSequenceRep:  TYPE ~ RECORD[ SEQUENCE length: CARDINAL OF BOOLEAN ];
BoolSeqSequence:  TYPE ~ REF BoolSeqSequenceRep;
BoolSeqSequenceRep: TYPE ~ RECORD[ SEQUENCE length: CARDINAL OF BoolSequence ];
Renamed Procedures
Fix: PROC [REAL] RETURNS [INTEGER] ~ Real.InlineFixI;
PutProp: PROC [propList: Atom.PropList, prop: REF ANY, val: REF ANY]
   RETURNS [Atom.PropList] ~ Atom.PutPropOnList;
Initialization of Classes
InitClasses: PROC[] ~ {    -- register procedures for basic surface types
polygonClass: ShapeClass ← G3dRender.GetShapeClass[$ConvexPolygon];
polygonClass.display ← DoDisplayList;
G3dRender.RegisterShapeClass[polygonClass, polygonClass.type];
};
Line Drawings
DoDisplayList: G3dRender.ShapeProc ~ {
PROC[context: Context, shape: Shape, data: REF ANYNIL]
RETURNS[Shape]
Call this to get through viewer to draw on screen
IF context.viewer # NIL               -- do through viewer
THEN context.class.drawInViewer[
context, NEW[G3dRender.ImagerProcRec ← [ViewerDisplayList, shape]]
]
ELSE DrawShape[context, NIL, shape];  -- do directly
RETURN[shape];
};
ViewerDisplayList: G3dRender.ImagerProc ~ {
PROC[context: Context, imagerCtx: Imager.Context, data: REF ANYNIL]
This gets pixel map and calls proc which draws lines based on display list
DoIt: PROC[pixelMap: PixelMap] ~ {
shape: Shape ← NARROW[ data ];
tempPixels: PixelMap ← context.pixels; context.pixels ← pixelMap;
DrawShape[context, imagerCtx, shape];
context.pixels ← tempPixels;
};
ImagerBackdoor.AccessBufferRectangle[imagerCtx, DoIt, context.viewPort^];
};
DrawShape: PROC [ context: Context, imagerCtx: Imager.Context, shape: Shape ] ~ {
This acquires display list from shape.props and executes it, calls proc to build list if none
imagerUsed: BOOLEANFALSE;
renderData: REF RenderData ← G3dRender.RenderDataFrom[shape];
dList: REF ← Atom.GetPropFromList[renderData.props, $LinesList];
shadingClass: REF ShadingClass ← G3dRender.ShadingClassFrom[shape];
shapeClass: REF ShapeClass ← G3dRender.ShapeClassFrom[shape];
color: Pixel ← [
Fix[shadingClass.color.R * 255.0],
Fix[shadingClass.color.G * 255.0],
Fix[shadingClass.color.B * 255.0],
0, 0
];
SELECT context.class.displayType FROM
$PseudoColor =>
color[r] ← 42 * (color[r] * 6 / 256) + 6 * (color[g] * 7 / 256) + (color[b] * 6 / 256) +2;
$Gray => color[r] ← (color[r] + color[g] + color[b]) / 3;
$Bitmap, $ImagerGray, $ImagerDithered, $ImagerFullClr, $Interpress =>
imagerUsed ← TRUE;
ENDCASE;
IF dList = NIL THEN dList ← MakeDisplayList[context, shape];
IF NOT shape.screenValid THEN [] ← shapeClass.validate[context, shape];
IF imagerUsed THEN G3dRenderWithImager.SetQuickLines[imagerCtx, color];
IF shapeClass.type = $ConvexPolygon
THEN {
list: IntegerPairSequence ← NARROW[dList];
FOR i: NAT IN [0..list.length) DO
IF context.stopMe^ THEN RETURN;
IF imagerUsed
THEN G3dRenderWithImager.DoQuickLine[
imagerCtx, shape.vertices[list[i].x].screen, shape.vertices[list[i].y].screen
]
ELSE G3dScanConvert.PutLine[ context,
[ Fix[shape.vertices[list[i].x].screen.x], Fix[shape.vertices[list[i].x].screen.y] ],
[ Fix[shape.vertices[list[i].y].screen.x], Fix[shape.vertices[list[i].y].screen.y] ],
color, color
];
ENDLOOP;
}
ELSE {   -- not polygonal have to transform curved paths
list: TripleSeqSequence ← NARROW[dList];
xfm: Matrix ← G3dMatrix.Mul[shape.matrix, context.eyeSpaceXfm];
lsx, lsy: INTEGER;
FOR i: NAT IN [0..list.length) DO
FOR j: NAT IN [0..list[i].length) DO
OPEN list[i][j];
clip: OutCode;
ex, ey, ez, sx, sy: REAL; isx, isy: INTEGER;
[[ex, ey, ez], clip] ← G3dClipXfmShade.XfmPtToEyeSpace[context, [x, y, z], xfm];
IF clip # NoneOut   -- oops, G3dRender.XfmToEyeSpace got it wrong
THEN { shape.clipState ← clipped; EXIT; }
ELSE {
sx ← context.eyeToNdc.scaleX * ex / ez + context.eyeToNdc.addX;
sy ← context.eyeToNdc.scaleY * ey / ez + context.eyeToNdc.addY;
isx ← Real.Fix[ context.ndcToPixels.scaleX * sx + context.ndcToPixels.addX ];
isy ← Real.Fix[ context.ndcToPixels.scaleY * sy + context.ndcToPixels.addY ];
IF j > 0 THEN G3dScanConvert.PutLine[context, [isx, isy], [lsx, lsy], color, color];
lsx ← isx; lsy ← isy;
}
ENDLOOP;
ENDLOOP;
};
};
MakeDisplayList: PROC [ context: Context, shape: Shape ]
      RETURNS[REF] ~ {
IF G3dRender.ShapeClassFrom[shape].type = $ConvexPolygon
THEN RETURN[ MakePolygonDisplayList[context, shape] ]
ELSE RETURN[ MakePatchDisplayList[context, shape] ];
};
MakePolygonDisplayList: PROC [ context: Context, shape: Shape ]
         RETURNS[REF] ~ {
Creates display list for line drawings of polygonal object, culls duplicated edges
renderData: REF RenderData ← G3dRender.RenderDataFrom[shape];
shapeClass: REF ShapeClass ← G3dRender.ShapeClassFrom[shape];
size: NAT ← shape.vertices.length;
Allocate display list; Allow room for triangular mesh ( < 3 edges per vertex )
displayList: IntegerPairSequence ← NEW[IntegerPairSequenceRep[3*size]];
connections: BoolSeqSequence ← NEW[BoolSeqSequenceRep[shape.vertices.length]];
c1, c2, count: NAT ← 0;
FOR i: NAT IN (0..shape.vertices.length) DO  -- fill half matrix less diagonal with FALSE
connections[i] ← NEW[ BoolSequenceRep[i] ];
FOR j: NAT IN [0..i) DO connections[i][j] ← FALSE; ENDLOOP;
ENDLOOP;
FOR i: NAT IN [0..shape.surfaces.length) DO
IF shapeClass.type # $ConvexPolygon
THEN SIGNAL G3dRender.Error[$MisMatch, "Operation only for convex polygons"]
ELSE FOR j: NAT IN [0..shape.surfaces[i].vertices.length] DO
k: NATIF j = shape.surfaces[i].vertices.length THEN 0 ELSE j;
c2 ← shape.surfaces[i].vertices[k];
IF j > 0 THEN {
IF c1 > c2 THEN IF connections[c1][c2] = FALSE THEN {
displayList[count] ← [c1, c2]; count ← count + 1;
connections[c1][c2] ← TRUE;
};
IF c2 > c1 THEN IF connections[c2][c1] = FALSE THEN {
displayList[count] ← [c2, c1]; count ← count + 1;
connections[c2][c1] ← TRUE;
};
};
c1 ← c2;
ENDLOOP;
ENDLOOP;
displayList.length ← count;
renderData.props ← PutProp[renderData.props, $LinesList, displayList];
RETURN[displayList];
};
tol: REAL ← .001;     -- tolerance for endpoint matching
GrabEdges: PatchProc ~ {
PROC[context: Context, patch: REF Patch, data: REF ANYNIL] RETURNS[REF Patch]
Used to temporarily replace polygon rendering proc in context, captures calls and culls duplicates, stores result in display list
displayList: TripleSeqSequence ← NARROW[
Atom.GetPropFromList[patch.renderData.props, $LinesList]
];
FOR i: NAT IN [0..displayList.length) DO
OPEN patch[patch.nVtces-1].coord;
pt: Triple ← displayList[i][0];        -- get first point in sequence
IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN {            
OPEN patch[0].coord;      -- opposite endpoints match, try other ends
pt: Triple ← displayList[i][displayList[i].length-1];  -- get last point in sequence
IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN {
OPEN patch[patch.nVtces/2].coord;   -- check middle points
pt: Triple ← displayList[i][displayList[i].length - 1 - patch.nVtces/2];
IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN
RETURN[patch]; -- both ends and middle match, line stored in other direction
};
};
pt ← displayList[i][displayList[i].length-1];
IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN {            
OPEN patch[0].coord;      -- last endpoints match, try other end
pt: Triple ← displayList[i][0];  -- get first point in sequence
IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN {
OPEN patch[patch.nVtces/2].coord;   -- check middle points
pt: Triple ← displayList[i][patch.nVtces/2];
IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN
RETURN[patch]; -- both ends and middle match, line stored in other direction
};
};
ENDLOOP;
IF displayList.length = displayList.maxLength THEN {    -- extend display list
newList: TripleSeqSequence ← NEW[
TripleSeqSequenceRep[displayList.length + displayList.length / 2]
];
FOR i: NAT IN [0..displayList.length) DO newList[i] ← displayList[i] ENDLOOP;
newList.length ← displayList.length;
displayList ← newList;
};
displayList[displayList.length] ← NEW[TripleSequenceRep[patch.nVtces]]; -- add new edge
FOR i: NAT IN [0..patch.nVtces) DO
displayList[displayList.length][i] ← [ patch[i].coord.x, patch[i].coord.y, patch[i].coord.z ];
ENDLOOP;
displayList[displayList.length].length ← patch.nVtces;
displayList.length ← displayList.length + 1;
RETURN[patch];
};
MakePatchDisplayList: PROC [ context: Context, shape: Shape ]
        RETURNS[REF] ~ {
Creates display list for line drawings of patch shape by replacing polygon display proc with GrabEdges then calling for display of all patches of shape to capture the resulting polygon calls
renderData: REF RenderData ← G3dRender.RenderDataFrom[shape];
size: NAT ← shape.vertices.length;
displayList: TripleSeqSequence ← NEW[TripleSeqSequenceRep[3*size]]; -- max. for triangles
tempProc: PatchProc ← context.class.displayPolygon;
context.class.displayPolygon ← GrabEdges;   -- ambush polygon display proc
renderData.props ← PutProp[renderData.props, $LinesList, displayList];
FOR i: NAT IN [0..renderData.patch.length) DO
IF renderData.patch[i] # NIL
THEN [] ← renderData.class.displayPatch[ context, renderData.patch[i] ];
ENDLOOP;
context.class.displayPolygon ← tempProc;    -- restore polygon display proc
RETURN[displayList];
};
InitClasses[];
END.