ImagerObjectsMain.mesa
Last Edited by: Crow, February 29, 1984 12:56:38 pm PST
DIRECTORY
ThreeDPackage  USING [ConcatT, GetIDTransform, Normalize, Rotate3D,
         Transformation3D, Translate3D,
         Triple],
PolygonPackage  USING [BackFacing, ClipPoly, ClipState, ClrTriple, DoForPolygons,
         DoInSequence, GetColors, GetCoords, GetObject,
         GetPolyNormals, GetShades, GetSolidColor, GetTransforms,
         GetVtxNormals, LightList, LoadSortSequence, Object,
         ObjectPolygon, Polygon, PolygonTexture,
         PolygonTextureSequenceRep, PtrPoly, PtrPolySequenceRep,
         ShadingSequenceRep, ShadingValue, SortSequenceRep,
         VertexSequenceRep, XfmVtces],
TilerPackage   USING [FancyTiler, SetTexture, SumTexture, MipMapTexture,
         BlendPixels],
Rope     USING [ROPE, Equal],
Real     USING [RoundC, Fix, FixC, LargestNumber, Float],
RealFns    USING [Power, Sin, ArcTanDeg, SqRt],
MessageWindow  USING [Append],
Imager    USING [Context, Create, SetColor, Pair, SpecialOp, MaskRectangle,
         MaskVector, ShowCharacters, FONT, MakeFont, SetFont, SetXY],
ImagerBasic   USING [IntRectangle],
ImagerDisplay  USING [DisplayData],
ImagerDisplayExtras USING [RGBSequence],
ImagerPixelMaps  USING [GetPixel],
ImagerPixelMapsExtras USING [SetPixel, DrawLine, FillTrap],
ConstantColors  USING [NameToColor, RGBToColor],
ImagerColorAIS  USING [GetAISFile, PutAISFile];
ImagerObjectsMain: CEDAR PROGRAM
IMPORTS ThreeDPackage, PolygonPackage, TilerPackage, Rope, Real, RealFns, Imager, ConstantColors, ImagerColorAIS, ImagerPixelMaps, ImagerPixelMapsExtras, MessageWindow
~ BEGIN
ShadingUnspecified: PUBLIC SIGNAL = CODE;
Triple: TYPE ~ ThreeDPackage.Triple;
Pair: TYPE ~ RECORD [ x, y: REAL];
BooleanSequence: TYPE ~ RECORD [SEQUENCE length: NAT OF BOOLEAN];
ObjectList: TYPE ~ LIST OF REF PolygonPackage.Object;
displayContext, currentContext: Imager.Context;
sortSeq: REF PolygonPackage.SortSequenceRep;
objectList: LIST OF REF PolygonPackage.Object;
resFctrX, resFctrY: REAL;      -- Scale factors for transform to image space
eyeSpaceTransform: ThreeDPackage.Transformation3D;
lights: PolygonPackage.LightList ← NIL;
tempPoly, tempPoly2: REF PolygonPackage.Polygon ← NIL;
Sqr: PROCEDURE [number: REAL] RETURNS [REAL] ~ INLINE { RETURN[number * number]; };
Sgn: PROCEDURE [number: REAL] RETURNS [REAL] ~ INLINE {
IF number < 0. THEN RETURN[-1.] ELSE RETURN[1.];
};
Init: PROC[] ~ {
displayContext ← Imager.Create[$Std8bpp, NIL];
currentContext ← displayContext;
lights ← CONS[ [ThreeDPackage.Normalize[[-100., -200., 50.]], [1., 1., 1.], .2], lights];
};
ClearDisplay: PROC[] ~ {
displayData: ImagerDisplay.DisplayData ← NARROW[currentContext.data,
               ImagerDisplay.DisplayData];
ImagerPixelMapsExtras.FillTrap[
displayData[0],
displayData[0].sMin + displayData[0].sSize,     -- top
displayData[0].sMin,           -- bottom
displayData[0].fMin, displayData[0].fMin,     -- left top and bottom
displayData[0].fMin + displayData[0].fSize, displayData[0].fMin + displayData[0].fSize,
0                -- color
];
};
NameColor: PROC [color: Rope.ROPE] ~ {
Imager.SetColor[displayContext, ConstantColors.NameToColor[color]];
};
RGBColor: PROC [r, g, b: REAL] ~ {
Imager.SetColor[displayContext, ConstantColors.RGBToColor[r, g, b]];
};
LoadAndRotate8BitMap: PROC [duration: NAT] ~ {
start: REF NATNEW[NAT];
length: NAT ← 512;
entries: REF ImagerDisplayExtras.RGBSequence ← NEW[
               ImagerDisplayExtras.RGBSequence[length] ];
data: LIST OF REF ANYNIL;
start^ ← 1;
FOR i: NAT IN [0..40) DO              -- greyscale
entries[i + 216].r ← entries[i + 216].g ← entries[i + 216].b ← i*6;
entries[i + 471].r ← entries[i + 471].g ← entries[i + 471].b ← 255 - i*6;
ENDLOOP;
FOR i: NAT IN [0..216) DO          -- 6 x 6 x 6 color cube
entries[i].r ← 36 * (i/36 + 1);     entries[i + 255].r ← 255 - entries[i].r;
entries[i].g ← 36 * ((i/6) MOD 6 + 1); entries[i + 255].g ← 255 - entries[i].g;
entries[i].b ← 36 * (i MOD 6 + 1);   entries[i + 255].b ← 255 - entries[i].b;
ENDLOOP;
data ← CONS[start, data];
data ← CONS[entries, data];
[] ← Imager.SpecialOp[displayContext, $LoadColorMap, data];
FOR i: NAT IN [0..duration*60) DO
color: RECORD[ r, g, b: [0..256) ] ← [ entries[1].r, entries[1].g, entries[1].b ];
FOR j: NAT IN [2..length) DO entries[j-1] ← entries[j]; ENDLOOP;
entries[length-1] ← [ color.r, color.g, color.b ];
[] ← Imager.SpecialOp[displayContext, $LoadColorMap, data];
ENDLOOP;
};
LoadGrey8BitMap: PROC [] ~ {
start: REF NATNEW[NAT];
length: NAT ← 512;
entries: REF ImagerDisplayExtras.RGBSequence ← NEW[
               ImagerDisplayExtras.RGBSequence[length] ];
data: LIST OF REF ANYNIL;
start^ ← 0;
FOR i: NAT IN [0..256) DO          -- greyscale
j: NAT ← Real.FixC[RealFns.Power[i/256.0, .43] * 256.0];
entries[i].r ← j;    entries[i + 255].r ← 255 - entries[i].r;
entries[i].g ← j;   entries[i + 255].g ← 255 - entries[i].g;
entries[i].b ← j;   entries[i + 255].b ← 255 - entries[i].b;
ENDLOOP;
data ← CONS[start, data];
data ← CONS[entries, data];
[] ← Imager.SpecialOp[displayContext, $LoadColorMap, data];
};
Load8BitRampMap: PROC [r1, g1, b1, r2, g2, b2: REAL] ~ {
start: REF NATNEW[NAT];
length: NAT ← 256;
entries: REF ImagerDisplayExtras.RGBSequence ← NEW[
               ImagerDisplayExtras.RGBSequence[length] ];
data: LIST OF REF ANYNIL;
start^ ← 0;
r1 ← MAX[0.0, MIN[1.0, r1]]; r2 ← MAX[0.0, MIN[1.0, r2]];
g1 ← MAX[0.0, MIN[1.0, g1]]; g2 ← MAX[0.0, MIN[1.0, g2]];
b1 ← MAX[0.0, MIN[1.0, b1]]; b2 ← MAX[0.0, MIN[1.0, b2]];
FOR i: NAT IN [0..256) DO          -- linear ramp
jr: NAT ← Real.FixC[RealFns.Power[r1 + i/255.0 * (r2 - r1), .43] * 255.0]; -- gamma correction
jg: NAT ← Real.FixC[RealFns.Power[g1 + i/255.0 * (g2 - g1), .43] * 255.0];
jb: NAT ← Real.FixC[RealFns.Power[b1 + i/255.0 * (b2 - b1), .43] * 255.0];
entries[i].r ← jr;
entries[i].g ← jg;
entries[i].b ← jb;
ENDLOOP;
data ← CONS[start, data];
data ← CONS[entries, data];
[] ← Imager.SpecialOp[displayContext, $LoadColorMap, data];
};
FillRectangle: PROC [x, y, w, h: REAL] ~ {
Imager.MaskRectangle[displayContext, x, y, w, h];
};
DrawLine: PROC [pt1, pt2: Imager.Pair, width: REAL] ~ {
Imager.MaskVector[displayContext, pt1, pt2, width];
};
ShowRope: PROC[x, y: REAL, rope: Rope.ROPE, fontRope: Rope.ROPENIL, size: REAL ← .008] ~ {
font: Imager.FONT;
IF fontRope = NIL THEN fontRope ← "Xerox/Pressfonts/TimesRoman/MRR";
font ← Imager.MakeFont[fontRope, size];
Imager.SetFont[displayContext, font];
Imager.SetXY[displayContext, [x, y]];
Imager.ShowCharacters[displayContext, rope, ];
};
GetAISFile: PUBLIC PROC[fileName: Rope.ROPE, xOffSet, yOffSet: INTEGER ← 0] ~ {
ImagerColorAIS.GetAISFile[displayContext, fileName, xOffSet, yOffSet];
};
PutAISFile: PUBLIC PROC[fileName: Rope.ROPE] ~ {
ImagerColorAIS.PutAISFile[displayContext, fileName];
};
Create context and load texture into it
TextureFromAIS: PROC[fileName: Rope.ROPE, x, y, w, h: NAT ← 0 ] ~ {
textureContext: Imager.Context;
refBox: REF ImagerBasic.IntRectangle ← NEW[ImagerBasic.IntRectangle];
refBox.x ← x; refBox.y ← y; refBox.w ← w; refBox.h ← h;
textureContext ← Imager.Create[$Std8bpp, refBox];
ImagerColorAIS.GetAISFile[textureContext, fileName];
TilerPackage.SetTexture[textureContext];
};
MakeTxtrCoordsFromVtxNum: PROC[ objectName: Rope.ROPE,
            vtcesAround, vtcesOnProfile: NAT,
        botLeft, topLeft, topRight, botRight: Pair] ~ {
object: REF PolygonPackage.Object ← FindObject[objectName, objectList]; -- get object ref
polygon: REF PolygonPackage.PtrPolySequenceRep ← object.polygon;
texture: REF PolygonPackage.PolygonTextureSequenceRep ← NEW[
        PolygonPackage.PolygonTextureSequenceRep[polygon.length] ];
object.texture ← texture;        -- set object texture ref
IF polygon.length # vtcesAround * vtcesOnProfile THEN {
MessageWindow.Append["Unexpected number of polygons", TRUE];
RETURN[];
};
FOR polyNumber: NAT IN [0..vtcesAround * vtcesOnProfile) DO
minTxtrX, minTxtrY: REAL ← Real.LargestNumber;
maxTxtrX: REAL ← 0.;
texture[polyNumber] ← NEW[PolygonPackage.PolygonTexture[polygon[polyNumber].nVtces] ];
texture[polyNumber].nVtces ← polygon[polyNumber].nVtces;
FOR i: NAT IN [0..polygon[polyNumber].nVtces) DO
OPEN texture[polyNumber].vtx[i];
vtx: NAT ← polygon[polyNumber].vtxPtr[i];
txtrX ← Real.Float[vtx MOD (vtcesAround+1)] / vtcesAround;
txtrY ← Real.Float[vtx / (vtcesAround+1)] / vtcesOnProfile;
IF txtrX < minTxtrX THEN minTxtrX ← txtrX;
IF txtrX > maxTxtrX THEN maxTxtrX ← txtrX;
ENDLOOP;
IF maxTxtrX - minTxtrX > .5 -- wraparound seam
THEN FOR i: NAT IN [0..polygon[polyNumber].nVtces) DO
OPEN texture[polyNumber].vtx[i];
IF maxTxtrX - txtrX > .5 THEN txtrX ← txtrX + 1.;
ENDLOOP;
minTxtrX ← minTxtrY ← Real.LargestNumber;
FOR i: NAT IN [0..polygon[polyNumber].nVtces) DO
OPEN texture[polyNumber].vtx[i];
lPosX: REAL ← botLeft.x + txtrY * (topLeft.x - botLeft.x);
lPosY: REAL ← botLeft.y + txtrY * (topLeft.y - botLeft.y);
rPosX: REAL ← botRight.x + txtrY * (topRight.x - botRight.x);
rPosY: REAL ← botRight.y + txtrY * (topRight.y - botRight.y);
txtrX ← lPosX + txtrX * (rPosX - lPosX);
txtrY ← lPosY + txtrX * (rPosY - lPosY);
IF txtrX < minTxtrX THEN minTxtrX ← txtrX;
IF txtrY < minTxtrY THEN minTxtrY ← txtrY;
ENDLOOP;
minTxtrX ← Real.Float[Real.Fix[minTxtrX]];
minTxtrY ← Real.Float[Real.Fix[minTxtrY]];
FOR i: NAT IN [0..polygon[polyNumber].nVtces) DO
OPEN texture[polyNumber].vtx[i];
txtrX ← txtrX - minTxtrX;
txtrY ← txtrY - minTxtrY;
ENDLOOP;
ENDLOOP;
};
MakeTxtrCoordsFromNormals: PROC[ objectName: Rope.ROPE,
        botLeft, topLeft, topRight, botRight: Pair] ~ {
object: REF PolygonPackage.Object ← FindObject[objectName, objectList]; -- get object ref
polygon: REF PolygonPackage.PtrPolySequenceRep ← object.polygon;
texture: REF PolygonPackage.PolygonTextureSequenceRep ← NEW[
        PolygonPackage.PolygonTextureSequenceRep[polygon.length] ];
polyTags: REF BooleanSequence ← NEW[BooleanSequence[8]];
object.texture ← texture;        -- set object texture ref
IF object.shade.length # object.vertex.length THEN {
MessageWindow.Append["Texture only works with smooth shading", TRUE];
RETURN[];
};
FOR polyNumber: NAT IN [0..polygon.length) DO
minTxtrX, minTxtrY: REAL ← Real.LargestNumber;
maxTxtrX: REAL ← 0.;
texture[polyNumber] ← NEW[PolygonPackage.PolygonTexture[polygon[polyNumber].nVtces] ];
texture[polyNumber].nVtces ← polygon[polyNumber].nVtces;
FOR i: NAT IN [0..polygon[polyNumber].nVtces) DO  -- map from sphere to Cartesian
OPEN texture[polyNumber].vtx[i];       -- map to 1st quadrant 0 - 1 range.
shade: PolygonPackage.ShadingValue ← object.shade[polygon[polyNumber].vtxPtr[i]];
hypotenuse: REAL ← RealFns.SqRt[Sqr[shade.yn] + Sqr[shade.xn]];
txtrX ← RealFns.ArcTanDeg[shade.yn, shade.xn] / 360. + .5;
txtrY ← RealFns.ArcTanDeg[shade.zn, hypotenuse] / 180. + .5;
IF hypotenuse < .00001 THEN polyTags[i] ← TRUE
ELSE {
polyTags[i] ← FALSE;
IF txtrX < minTxtrX THEN minTxtrX ← txtrX;
IF txtrX > maxTxtrX THEN maxTxtrX ← txtrX;
};
ENDLOOP;
IF maxTxtrX - minTxtrX > .5    -- wrapping around seam, fix up coords
THEN FOR i: NAT IN [0..polygon[polyNumber].nVtces) DO
OPEN texture[polyNumber].vtx[i];
IF maxTxtrX - txtrX > .5 THEN txtrX ← txtrX + 1.;
ENDLOOP;
minTxtrX ← Real.LargestNumber;
maxTxtrX ← 0.;
FOR i: NAT IN [0..polygon[polyNumber].nVtces) DO   -- get corrected max and min
IF polyTags[i] = FALSE THEN {
OPEN texture[polyNumber].vtx[i];
IF txtrX < minTxtrX THEN minTxtrX ← txtrX;
IF txtrX > maxTxtrX THEN maxTxtrX ← txtrX;
};
ENDLOOP;
FOR i: NAT IN [0..polygon[polyNumber].nVtces) DO   -- fix up vertical normals
OPEN texture[polyNumber].vtx[i];
IF polyTags[i] = TRUE THEN txtrX ← (maxTxtrX + minTxtrX) / 2.;
ENDLOOP;
minTxtrX ← minTxtrY ← Real.LargestNumber;
FOR i: NAT IN [0..polygon[polyNumber].nVtces) DO  -- slew according to corner coords
OPEN texture[polyNumber].vtx[i];
lPosX: REAL ← botLeft.x + txtrY * (topLeft.x - botLeft.x);
lPosY: REAL ← botLeft.y + txtrY * (topLeft.y - botLeft.y);
rPosX: REAL ← botRight.x + txtrY * (topRight.x - botRight.x);
rPosY: REAL ← botRight.y + txtrY * (topRight.y - botRight.y);
txtrX ← lPosX + txtrX * (rPosX - lPosX);
txtrY ← lPosY + txtrX * (rPosY - lPosY);
IF txtrX < minTxtrX THEN minTxtrX ← txtrX;
IF txtrY < minTxtrY THEN minTxtrY ← txtrY;
ENDLOOP;
minTxtrX ← Real.Float[Real.Fix[minTxtrX]];
minTxtrY ← Real.Float[Real.Fix[minTxtrY]];
FOR i: NAT IN [0..polygon[polyNumber].nVtces) DO
OPEN texture[polyNumber].vtx[i];
txtrX ← txtrX - minTxtrX;
txtrY ← txtrY - minTxtrY;
ENDLOOP;
ENDLOOP;
};
SumTexture: PROC[range, interp: REAL] ~ { TilerPackage.SumTexture[range, interp]; };
MipMapTexture: PROC[range: REAL,showMaps: BOOLEANFALSE] ~ {
TilerPackage.MipMapTexture[range, showMaps];
};
ClearTexture: PROC[] ~ { TilerPackage.SetTexture[ NIL ]; };
MakeStripes: PROC[numStripes: NAT, min, max, power: REAL] ~ {
displayData: ImagerDisplay.DisplayData ←
           NARROW[currentContext.data, ImagerDisplay.DisplayData];
factor: REAL ← ( numStripes * 2. * 3.1416 ) / displayData[0].fSize;
maxValue: REAL ← 256.0;
FOR x: NAT IN [ displayData[0].fMin .. (displayData[0].fSize + displayData[0].fMin) ] DO
pxlValue: CARDINAL;
sineValue: REAL ← RealFns.Sin[ factor * (x - displayData[0].fMin) ];
sineValue ← RealFns.Power[ABS[sineValue], power] * Sgn[sineValue];
pxlValue ← Real.FixC[ maxValue * (((sineValue + 1.) / 2.0) * (max - min) + min) ];
ImagerPixelMapsExtras.SetPixel[displayData[0], displayData[0].sMin, x, pxlValue];
ENDLOOP;
FOR y: NAT IN [ (displayData[0].sMin + 1) .. (displayData[0].sSize + displayData[0].sMin) ] DO
FOR x: NAT IN [ displayData[0].fMin .. (displayData[0].fSize + displayData[0].fMin) ] DO
ImagerPixelMapsExtras.SetPixel[displayData[0], y, x,
        ImagerPixelMaps.GetPixel[displayData[0], displayData[0].sMin, x]];
ENDLOOP;
ENDLOOP;
};
MakeSpots: PROC[spotsAcross: NAT, min, max, power: REAL] ~ {
displayData: ImagerDisplay.DisplayData ←
           NARROW[currentContext.data, ImagerDisplay.DisplayData];
maxValue: REAL ← 256.0;
factor: REAL ← (spotsAcross * 2 * 3.1416) / displayData[0].fSize;
FOR y: NAT IN [ displayData[0].sMin .. (displayData[0].sSize + displayData[0].sMin) ) DO
sineY: REAL ← RealFns.Sin[ factor * (y - displayData[0].sMin) ];
sineY ← RealFns.Power[ABS[sineY], power] * Sgn[sineY];
FOR x: NAT IN [ displayData[0].fMin .. (displayData[0].fSize + displayData[0].fMin) ) DO
pxlValue: LONG CARDINAL;
sineX: REAL ← RealFns.Sin[ factor * (x - displayData[0].fMin) ];
sineX ← RealFns.Power[ABS[sineX], power] * Sgn[sineX];
pxlValue ← Real.FixC[
maxValue * (((sineX * sineY + 1.) / 2.0) * (max - min) + min) ];
ImagerPixelMapsExtras.SetPixel[displayData[0], y, x, pxlValue];
ENDLOOP;
ENDLOOP;
};
MakePlane: PROC[objectName: Rope.ROPE, squaresPerSide: NAT] ~ {
object: REF PolygonPackage.Object ← NEW[PolygonPackage.Object];
vtcesPerSide: NAT ← squaresPerSide + 1;
object.name ← objectName;
object.numPolys ← squaresPerSide * squaresPerSide;
object.numVtces ← vtcesPerSide * vtcesPerSide;
object.shadingInValid ← object.vtcesInValid ← TRUE;
object.centroid ← [0., 0., 0.];
object.boundingRadius ← 1.414;
object.shading ← none;
object.color ← [1., 1., 1.];
object.shininess ← object.transmittance ← 0.;
object.position ← ThreeDPackage.GetIDTransform[];
object.vertex ← NEW[PolygonPackage.VertexSequenceRep[object.numVtces]];
FOR i: INT IN [0..object.numVtces) DO
divisor: REAL ← Real.Float[squaresPerSide] / 2.;
object.vertex[i].x ← (i / vtcesPerSide) / divisor - 1.;   -- x-coordinate
object.vertex[i].y ← (i MOD vtcesPerSide) / divisor - 1.;  -- y-coordinate
object.vertex[i].z ← 0.;    -- constant z-coordinate
ENDLOOP;
object.polygon ← NEW[PolygonPackage.PtrPolySequenceRep[object.numPolys]];
FOR i: INT IN [0..object.numPolys) DO
vtxNumber: NAT ← i + (i / squaresPerSide); -- add one at end of each row
object.polygon[i] ← NEW[PolygonPackage.PtrPoly[4]];
object.polygon[i].nVtces ← 4;
object.polygon[i].vtxPtr[0] ← vtxNumber;
object.polygon[i].vtxPtr[1] ← vtxNumber + 1;
object.polygon[i].vtxPtr[2] ← vtxNumber + vtcesPerSide + 1;
object.polygon[i].vtxPtr[3] ← vtxNumber + vtcesPerSide;
ENDLOOP;
objectList ← CONS[ object, objectList ];
};
AddObject: PROC[fileName: Rope.ROPE, position: Triple ← [0., 0., 0.] ] ~ {
objectList ← CONS[
PolygonPackage.GetObject[fileName],
objectList
];
PolygonPackage.GetPolyNormals[objectList.first]; -- for faceted shading
MoveObject[fileName, position];
sortSeq ← NIL;
};
DeleteObject: PROC[objectName: Rope.ROPE] ~ {
objects: ObjectList ← NIL;
WHILE objectList # NIL DO
IF NOT Rope.Equal[objectList.first.name, objectName, FALSE]
THEN objects ← CONS[objectList.first, objects];
objectList ← objectList.rest;
ENDLOOP;
objectList ← objects;
sortSeq ← NIL;
};
FindObject: PROC[objectName: Rope.ROPE, objectList: ObjectList]
    RETURNS[ REF PolygonPackage.Object ] ~ {
WHILE objectList # NIL DO
IF Rope.Equal[objectList.first.name, objectName, FALSE] THEN RETURN[objectList.first];
objectList ← objectList.rest;
ENDLOOP;
RETURN [ NIL ];
};
MoveObject: PROC[objectName: Rope.ROPE, delta: Triple] ~ {
object: REF PolygonPackage.Object ← FindObject[objectName, objectList];
object.position ← ThreeDPackage.ConcatT[object.position,
             ThreeDPackage.Translate3D[delta] ];
object.shadingInValid ← TRUE;
object.vtcesInValid ← TRUE;
sortSeq ← NIL;
};
ColorFacetedObject: PROC[objectName: Rope.ROPE, color: PolygonPackage.ClrTriple] ~ {
object: REF PolygonPackage.Object ← FindObject[objectName, objectList];
PolygonPackage.GetSolidColor[color, object, object.numPolys];
PolygonPackage.GetPolyNormals[object];
object.shading ← faceted;
object.shadingInValid ← TRUE;
};
ColorSmoothObject: PROC[objectName: Rope.ROPE, color: PolygonPackage.ClrTriple] ~ {
object: REF PolygonPackage.Object ← FindObject[objectName, objectList];
PolygonPackage.GetSolidColor[color, object, object.numVtces];
PolygonPackage.GetVtxNormals[object];
object.shading ← smooth;
object.shadingInValid ← TRUE;
};
ColorFancyObject: PROC[objectName: Rope.ROPE, color: PolygonPackage.ClrTriple] ~ {
object: REF PolygonPackage.Object ← FindObject[objectName, objectList];
PolygonPackage.GetSolidColor[color, object, object.numVtces];
PolygonPackage.GetVtxNormals[object];
object.shading ← fancy;
object.shadingInValid ← TRUE;
};
RotateObject: PROC[objectName: Rope.ROPE, base, axis: Triple, theta: REAL] ~ {
object: REF PolygonPackage.Object ← FindObject[objectName, objectList];
object.position ← ThreeDPackage.ConcatT[
ThreeDPackage.Rotate3D[base, axis, theta],
object.position
];
object.shadingInValid ← TRUE;
object.vtcesInValid ← TRUE;
sortSeq ← NIL;
};
SetLight: PROC[position: Triple,
     color: PolygonPackage.ClrTriple ← [1., 1., 1.], ambient: REAL ← .2] ~ {
objects: ObjectList ← objectList;
lights.first.pos ← ThreeDPackage.Normalize[position];
lights.first.clr ← color;
lights.first.ambient ← ambient;
WHILE objects # NIL DO objects.first.shadingInValid ← TRUE; objects ← objects.rest; ENDLOOP;
};
SetView: PROC[eyePosition, ptOfInterest: Triple, x, y, w, h: NAT ← 0] ~ {
objects: ObjectList ← objectList;
contextData: ImagerDisplay.DisplayData ←
          NARROW[currentContext.data, ImagerDisplay.DisplayData];IF w > 0 AND h > 0 THEN {
contextData[0].fMin ← x + contextData[0].fOrigin;
contextData[0].sMin ← y + contextData[0].sOrigin;
contextData[0].fSize ← w;
contextData[0].sSize ← h;
resFctrX ← (w - 1) / 2.;
resFctrY ← (h - 1) / 2.;
};
eyeSpaceTransform ← PolygonPackage.GetTransforms [
eyePosition,
ptOfInterest,
contextData[0].fSize,
contextData[0].sSize
];
WHILE objects # NIL DO objects.first.vtcesInValid ← TRUE; objects ← objects.rest; ENDLOOP;
sortSeq ← NIL;
};
GetPolygonColors: PROC[objectName, colorFile: Rope.ROPE] ~ {
object: REF PolygonPackage.Object ← FindObject[objectName, objectList];
PolygonPackage.GetColors[colorFile, object, object.numPolys];
PolygonPackage.GetPolyNormals[object];
object.shading ← faceted;
object.shadingInValid ← TRUE;
};
GetVertexColors: PROC[objectName, colorFile: Rope.ROPE] ~ {
object: REF PolygonPackage.Object ← FindObject[objectName, objectList];
PolygonPackage.GetColors[colorFile, object, object.numVtces];
PolygonPackage.GetVtxNormals[object];
object.shading ← smooth;
object.shadingInValid ← TRUE;
};
Get Texture Coordinates for a polygonal object
GetTextureCoords: PROC[objectName, coordinateFile: Rope.ROPE] ~ {
object: REF PolygonPackage.Object ← FindObject[objectName, objectList];
PolygonPackage.GetCoords[coordinateFile, object, object.numPolys];
};
ShowObjects: PROC[objects: LIST OF REF PolygonPackage.Object] ~ {
objectList: LIST OF REF PolygonPackage.Object ← objects;
WHILE objectList # NIL DO
IF objectList.first.vtcesInValid THEN {
compositeTransform: ThreeDPackage.Transformation3D ←
  ThreeDPackage.ConcatT[objectList.first.position, eyeSpaceTransform];
objectList.first.clipState ← PolygonPackage.XfmVtces[objectList.first, compositeTransform];
};
IF objectList.first.shadingInValid AND (objectList.first.clipState # out)
THEN PolygonPackage.GetShades[objectList.first, lights, RGBtoPixel];
objectList ← objectList.rest;
ENDLOOP;
IF sortSeq = NIL THEN sortSeq ← PolygonPackage.LoadSortSequence[objects];
PolygonPackage.DoInSequence[sortSeq, OutputPoly];
};
ShowWireFrameObjects: PROC[objects: LIST OF REF PolygonPackage.Object] ~ {
objectList: LIST OF REF PolygonPackage.Object ← objects;
WHILE objectList # NIL DO
IF objectList.first.vtcesInValid THEN {
compositeTransform: ThreeDPackage.Transformation3D ←
  ThreeDPackage.ConcatT[objectList.first.position, eyeSpaceTransform];
objectList.first.clipState ← PolygonPackage.XfmVtces[objectList.first, compositeTransform];
};
IF objectList.first.shadingInValid AND (objectList.first.clipState # out)
THEN PolygonPackage.GetShades[objectList.first, lights, RGBtoPixel];
objectList ← objectList.rest;
ENDLOOP;
PolygonPackage.DoForPolygons[objects, OutputLines];
};
RGBtoPixel: PROC [r, g, b: REAL] RETURNS [CARDINAL] = {
RETURN [ Real.FixC[255. * (r + g + b) / 3.] ];
};
PixeltoRGB: PROC [pxlValue: CARDINAL] RETURNS [r, g, b: REAL] = TRUSTED {
r ← g ← b ← Real.Float[pxlValue] / 255.;
};
OutputLines: PROC[p: PolygonPackage.ObjectPolygon] ~ {
displayData: ImagerDisplay.DisplayData ←
           NARROW[currentContext.data, ImagerDisplay.DisplayData];
poly: REF PolygonPackage.PtrPoly ← p.object.polygon[p.polygon];
vertex: REF PolygonPackage.VertexSequenceRep ← p.object.vertex;
shadeValue: LONG CARDINAL;
SELECT p.object.shading FROM
faceted => shadeValue ← p.object.shade[p.polygon].value;
smooth => shadeValue ← p.object.shade[poly.vtxPtr[0]].value;
fancy  => shadeValue ← p.object.shade[poly.vtxPtr[0]].value;
ENDCASE => SIGNAL ShadingUnspecified[];
IF poly.clipState = in THEN {
ax, ay, bx, by: INTEGER;
FOR j: NAT IN [0..poly.nVtces] DO
i: NATIF j = poly.nVtces THEN 0 ELSE j;
bx ← vertex[poly.vtxPtr[i]].ix;
by ← vertex[poly.vtxPtr[i]].iy;
bx ← bx + displayData[0].fMin;   -- transform to display
by ← displayData[0].sMin + displayData[0].sSize - (by + 1);
IF j > 0 THEN
ImagerPixelMapsExtras.DrawLine[displayData[0], [ax, ay], [bx, by], shadeValue];
ax ← bx; ay ← by;
ENDLOOP;
}
ELSE IF poly.clipState = clipped THEN {
IF (tempPoly = NIL) OR (tempPoly.length < 2 * poly.nVtces) THEN {
tempPoly ← NEW[PolygonPackage.Polygon[2 * poly.nVtces] ];
tempPoly2 ← NEW[PolygonPackage.Polygon[2 * poly.nVtces] ];
};
tempPoly.nVtces ← poly.nVtces;
FOR i: NAT IN [0..poly.nVtces) DO tempPoly.vtx[i].coord ← vertex[poly.vtxPtr[i]]; ENDLOOP;
[tempPoly, tempPoly2] ← PolygonPackage.ClipPoly[tempPoly, tempPoly2, FALSE, FALSE];
IF tempPoly.nVtces > 2 THEN {
ax, ay, bx, by: INTEGER;
FOR j: NAT IN [0..tempPoly.nVtces] DO
i: NATIF j = tempPoly.nVtces THEN 0 ELSE j;
{ OPEN tempPoly.vtx[i].coord;
bx ← Real.RoundC[ resFctrX * (ex / ez + 1.)];
by ← Real.RoundC[ resFctrY * (ey / ez + 1.)];
bx ← bx + displayData[0].fMin;   -- transform to display
by ← displayData[0].sMin + displayData[0].sSize - (by + 1);
IF j > 0 THEN
ImagerPixelMapsExtras.DrawLine[displayData[0], [ax, ay], [bx, by], shadeValue];
ax ← bx; ay ← by;
};
ENDLOOP;
};
};
};
SetPixelBlending: PROC[onNotOff: BOOLEAN ← TRUE] ~ { TilerPackage.BlendPixels[onNotOff]; };
DrawQuad: PROC[intensity: REAL, x1, y1, x2, y2, x3, y3, x4, y4: REAL] ~ {
poly: REF PolygonPackage.Polygon ← NEW[ PolygonPackage.Polygon[4] ];
poly.nVtces ← 4;
poly.vtx[0].coord.x ← x1; poly.vtx[0].coord.y ← y1; poly.vtx[0].shade.g ← intensity;
poly.vtx[1].coord.x ← x2; poly.vtx[1].coord.y ← y2; poly.vtx[1].shade.g ← intensity;
poly.vtx[2].coord.x ← x3; poly.vtx[2].coord.y ← y3; poly.vtx[2].shade.g ← intensity;
poly.vtx[3].coord.x ← x4; poly.vtx[3].coord.y ← y4; poly.vtx[3].shade.g ← intensity;
TilerPackage.FancyTiler[currentContext, poly];
};
OutputPoly: PROC[p: PolygonPackage.ObjectPolygon] ~ {
SELECT p.object.shading FROM
faceted => OutputFacetedPoly[p];
smooth => OutputSmoothPoly[p];
fancy  => OutputFancyPoly[p];
ENDCASE => SIGNAL ShadingUnspecified[];
};
OutputFacetedPoly: PROC[ p: PolygonPackage.ObjectPolygon] ~ {
poly: REF PolygonPackage.PtrPoly ← p.object.polygon[p.polygon];
vertex: REF PolygonPackage.VertexSequenceRep ← p.object.vertex;
shadeValue: LONG CARDINAL ← p.object.shade[p.polygon].value;
IF poly.clipState = in THEN {
IF (vertices = NIL) OR (vertices.length < poly.nVtces)
THEN vertices ← NEW[ OldImagerDisplay.VtxSequenceRep[poly.nVtces] ];
FOR i: NAT IN [0..poly.nVtces) DO
vertices[i].x ← vertex[poly.vtxPtr[i]].ix;
vertices[i].y ← vertex[poly.vtxPtr[i]].iy;
vertices[i].x ← vertices[i].x + currentContext.clipper.fMin;   -- transform to display
vertices[i].y ← currentContext.clipper.sMin + currentContext.clipper.sSize
     - (vertices[i].y + 1);
ENDLOOP;
currentContext.deviceProcs.ConstantTiler[currentContext, poly.nVtces, vertices, shadeValue];
}
ELSE IF poly.clipState = clipped THEN {
IF (tempPoly = NIL) OR (tempPoly.length < 2 * poly.nVtces) THEN {
tempPoly ← NEW[PolygonPackage.Polygon[2 * poly.nVtces] ];
tempPoly2 ← NEW[PolygonPackage.Polygon[2 * poly.nVtces] ];
};
tempPoly.nVtces ← poly.nVtces;
FOR i: NAT IN [0..poly.nVtces) DO tempPoly.vtx[i].coord ← vertex[poly.vtxPtr[i]]; ENDLOOP;
[tempPoly, tempPoly2] ← PolygonPackage.ClipPoly[tempPoly, tempPoly2, FALSE, FALSE];
IF tempPoly.nVtces > 2 THEN {
IF (vertices = NIL) OR (vertices.length < tempPoly.nVtces)
THEN vertices ← NEW[ OldImagerDisplay.VtxSequenceRep[tempPoly.nVtces] ];
FOR i: NAT IN [0..tempPoly.nVtces) DO OPEN tempPoly.vtx[i].coord;
vertices[i].x ← Real.RoundC[ resFctrX * (ex / ez + 1.)];
vertices[i].y ← Real.RoundC[ resFctrY * (ey / ez + 1.)];
vertices[i].x ← vertices[i].x + currentContext.clipper.fMin;   -- transform to display
vertices[i].y ← currentContext.clipper.sMin + currentContext.clipper.sSize
     - (vertices[i].y + 1);
ENDLOOP;
currentContext.deviceProcs.ConstantTiler[currentContext, tempPoly.nVtces, vertices, shadeValue];
};
};
};
OutputSmoothPoly: PROC[p: PolygonPackage.ObjectPolygon] ~ {
poly: REF PolygonPackage.PtrPoly ← p.object.polygon[p.polygon];
vertex: REF PolygonPackage.VertexSequenceRep ← p.object.vertex;
shade: REF PolygonPackage.ShadingSequenceRep ← p.object.shade;
IF poly.clipState = in THEN {
IF (vertices = NIL) OR (vertices.length < poly.nVtces)
THEN vertices ← NEW[ OldImagerDisplay.VtxSequenceRep[poly.nVtces] ];
FOR i: NAT IN [0..poly.nVtces) DO
k: NAT ← poly.vtxPtr[i];
vertices[i].x ← vertex[k].ix; vertices[i].y ← vertex[k].iy;
vertices[i].pxlValue ← shade[k].value;
vertices[i].x ← vertices[i].x + currentContext.clipper.fMin;   -- transform to display
vertices[i].y ← currentContext.clipper.sMin + currentContext.clipper.sSize
     - (vertices[i].y + 1);
ENDLOOP;
currentContext.deviceProcs.Tiler[currentContext, poly.nVtces, vertices];
}
ELSE IF poly.clipState = clipped THEN {
IF (tempPoly = NIL) OR (tempPoly.length < 2 * poly.nVtces) THEN {
tempPoly ← NEW[PolygonPackage.Polygon[2 * poly.nVtces] ];
tempPoly2 ← NEW[PolygonPackage.Polygon[2 * poly.nVtces] ];
};
tempPoly.nVtces ← poly.nVtces;
FOR i: NAT IN [0..poly.nVtces) DO
k: NAT ← poly.vtxPtr[i];
tempPoly.vtx[i].coord ← vertex[k];
tempPoly.vtx[i].shade ← shade[k];
[tempPoly.vtx[i].shade.r, tempPoly.vtx[i].shade.g, tempPoly.vtx[i].shade.b] ←
           currentContext.deviceProcs.PixeltoRGB[shade[k].value];
ENDLOOP;
[tempPoly, tempPoly2] ← PolygonPackage.ClipPoly[tempPoly, tempPoly2, TRUE, FALSE];
IF tempPoly.nVtces > 2 THEN {
IF (vertices = NIL) OR (vertices.length < tempPoly.nVtces)
THEN vertices ← NEW[ OldImagerDisplay.VtxSequenceRep[tempPoly.nVtces] ];
FOR i: NAT IN [0..tempPoly.nVtces) DO OPEN tempPoly.vtx[i];
vertices[i].x ← Real.RoundC[ resFctrX * (coord.ex / coord.ez + 1.)];
vertices[i].y ← Real.RoundC[ resFctrY * (coord.ey / coord.ez + 1.)];
vertices[i].pxlValue ← currentContext.deviceProcs.RGBtoPixel[shade.r, shade.g, shade.b,
                        TRUE];
vertices[i].x ← vertices[i].x + currentContext.clipper.fMin;   -- transform to display
vertices[i].y ← currentContext.clipper.sMin + currentContext.clipper.sSize
     - (vertices[i].y + 1);
ENDLOOP;
currentContext.deviceProcs.Tiler[currentContext, tempPoly.nVtces, vertices];
};
};
};
OutputFancyPoly: PROC[p: PolygonPackage.ObjectPolygon] ~ {
poly: REF PolygonPackage.PtrPoly ← p.object.polygon[p.polygon];
vertex: REF PolygonPackage.VertexSequenceRep ← p.object.vertex;
shade: REF PolygonPackage.ShadingSequenceRep ← p.object.shade;
texture: REF PolygonPackage.PolygonTextureSequenceRep ← p.object.texture;
tempPoly: REF PolygonPackage.Polygon;
IF poly.clipState = out THEN RETURN[];      -- reject if outside frame
tempPoly ← NEW[ PolygonPackage.Polygon[2 * poly.nVtces] ];
tempPoly.nVtces ← poly.nVtces;
FOR i: NAT IN [0..poly.nVtces) DO
k: NAT ← poly.vtxPtr[i];
tempPoly.vtx[i].coord ← vertex[k];
tempPoly.vtx[i].shade ← shade[k];
[tempPoly.vtx[i].shade.r, tempPoly.vtx[i].shade.g, tempPoly.vtx[i].shade.b] ←
                   PixeltoRGB[shade[k].value];
IF texture # NIL
THEN [tempPoly.vtx[i].shade.txtrX, tempPoly.vtx[i].shade.txtrY] ← texture[p.polygon].vtx[i];
ENDLOOP;
IF PolygonPackage.BackFacing[tempPoly] THEN RETURN[]; -- reject if facing away from viewer
IF poly.clipState = clipped THEN {
tempPoly2 ← NEW[PolygonPackage.Polygon[2 * poly.nVtces] ];
[tempPoly, tempPoly2] ← PolygonPackage.ClipPoly[tempPoly, tempPoly2, TRUE, TRUE];
};
IF tempPoly.nVtces > 2 THEN {
contextData: ImagerDisplay.DisplayData ←
          NARROW[currentContext.data, ImagerDisplay.DisplayData];
FOR i: NAT IN [0..tempPoly.nVtces) DO OPEN tempPoly.vtx[i];
coord.x ← resFctrX * (coord.ex / coord.ez + 1.);
coord.y ← resFctrY * (coord.ey / coord.ez + 1.);
coord.x ← coord.x + contextData[0].fMin;
coord.y ← contextData[0].sMin
   + contextData[0].sSize - (coord.y + 1);
ENDLOOP;
TilerPackage.FancyTiler[currentContext, tempPoly];
};
};
Begin main program
Init[];
END.