<> <> DIRECTORY Basics USING [BITSHIFT, BITOR, BITAND], BasicTime USING [PulsesToSeconds, GetClockPulses], Atom USING [PutPropOnList, GetPropFromList, RemPropFromList], CedarProcess USING [CheckAbort, DoWithPriority], ViewerIO USING [CreateViewerStreams], Terminal USING [Virtual, GetColorMode, SetColor, GetColor, WaitForBWVerticalRetrace, ColorMode, SetRedMap, SetGreenMap, SetBlueMap], IO USING [STREAM, PutRope, Flush, Close, GetLineRope], FS USING [StreamOpen], Rope USING [ROPE, Index, Cat], Convert USING [RopeFromCard], Real USING [Float, FixC, RoundC, FixI], RealFns USING [Sin, Cos, Power], Imager USING [Context, Rectangle, SetColor, Font, SetFont, SetXY, ShowRope], Vector2 USING [ VEC ], ImagerBackdoor USING [ GetBounds ], ImagerColor USING [ ColorFromRGB, RGBFromHSL, RGB ], ImagerFont USING [ Find, Scale ], NamedColors USING [ RopeToHSL ], Pixels USING [ PixelBuffer, Extent, BYTE, ValueOp, Transfer, GetSampleSet, SampleSet, PutPixel, GetScanSeg, PutScanSeg, SampleSetSequence ], Vector3d USING [ Pair, Triple, Quad ], Matrix3d USING [ Matrix ], Plane3d USING [ DistanceToPt ], ScanConvert USING [ IntRGB, GetColorProc, MappedRGB, DitheredRGB, PutLine ], ThreeDScenes USING [ AddShape, ClipState, Context, Create, Error, FillInBackGround, FillViewPort, FindShape, GetShading, InitShades, NewShape, NoneOut, OutCode, PlaceShape, PutShading, ReadColors, ReadNormals, ReadScene, WriteScene, ReadTextureCoords, SetUpStandardFile, SetView, SetViewPort, ShadingProcs, ShadingSequence, ShadingValue, ShapeInstance, ShapeSequence, Vertex, VertexSequence, VtxToRealSeqProc, XfmPtToEyeSpace, XfmPtToDisplay ], ThreeDSurfaces USING [ Patch, PtrPatch, ShowObjects, ShowWireFrameObjects, PtrPatchSequence, LoadShape, GetPolyNormals, GetPatchColors, GetVtxNormals, PatchProcs, RegisterSurfaceType ], Tilers USING [ FancyTiler], TextureMaps USING [ TextureMap ], SolidTextures USING [ RopeToProc, GetLerpedVals ], AISAnimation USING [ StoreFiles, PutAIS ], Animation3D USING [ MoveInOrbit, MoveOnLine ], StandardPatches USING [ BezierExpand, BezierSubdivide, BezierDisplay, BezierDisplayLines ], ThreeDMisc USING [ ]; ThreeDMiscImpl: CEDAR PROGRAM IMPORTS Basics, Imager, Pixels, ThreeDScenes, ThreeDSurfaces, Tilers, Real, RealFns, IO, ImagerFont, AISAnimation, Animation3D, CedarProcess, Atom, Terminal, ImagerColor, NamedColors, ImagerBackdoor, ScanConvert, Rope, ViewerIO, Convert, BasicTime, Plane3d, SolidTextures, StandardPatches, FS EXPORTS ThreeDMisc ~ BEGIN <> Context: TYPE ~ ThreeDScenes.Context; Pair: TYPE ~ Vector3d.Pair; -- RECORD [ x, y: REAL]; Triple: TYPE ~ Vector3d.Triple; RGB: TYPE ~ ImagerColor.RGB; IntRGB: TYPE ~ ScanConvert.IntRGB; IntRGBSequence: TYPE ~RECORD [ SEQUENCE length: NAT OF IntRGB ]; Rectangle: TYPE ~ Pixels.Extent; NatSequence: TYPE ~ RECORD [ SEQUENCE length: NAT OF NAT ]; <> clrValues: Pixels.SampleSet _ Pixels.GetSampleSet[4]; RGBtoPixelValue: PUBLIC PROC[context: REF ThreeDScenes.Context, clr: RGB, values: Pixels.SampleSet] RETURNS[ Pixels.SampleSet ] ~ { base: NAT _ IF context.alphaBuffer THEN 1 ELSE 0; values[0] _ 0; SELECT context.renderMode FROM $FullClr, $Dorado24 => { values[base ] _ Real.RoundC[clr.R*255.0]; values[base+1] _ Real.RoundC[clr.G*255.0]; values[base+2] _ Real.RoundC[clr.B*255.0]; }; $Grey => { values[base] _ Real.RoundC[(clr.R + clr.G + clr.B) / 3.0 * 255.0]; }; $Dithered, $PseudoClr => { values[base] _ ScanConvert.MappedRGB[ context.renderMode, [ Real.RoundC[clr.R*255.0], Real.RoundC[clr.G*255.0], Real.RoundC[clr.B*255.0] ] ]; }; ENDCASE => SIGNAL ThreeDScenes.Error[[$MisMatch, "Improper renderMode"]]; RETURN[values]; }; PutPixel: PUBLIC PROC[context: REF ThreeDScenes.Context, x, y: NAT, clr: RGB] ~ { clrValues _ RGBtoPixelValue[context, clr, clrValues]; Pixels.PutPixel[context.display, x, y, clrValues]; }; ClipLineWithPlane: PUBLIC PROC[plane: Vector3d.Quad, p1, p2: Triple] RETURNS[ insidePt, clippedPt: Triple, state: ThreeDScenes.ClipState ] ~ { alpha: REAL; dist1: REAL _ Plane3d.DistanceToPt[ p1, plane ]; dist2: REAL _ Plane3d.DistanceToPt[ p2, plane ]; IF dist1 > 0.0 AND dist2 > 0.0 THEN RETURN[p1, p2, in] -- all inside, no clipping ELSE IF dist1 < 0.0 AND dist2 < 0.0 THEN RETURN[p1, p2, out] -- all outside, no clipping ELSE { pOut: Triple; alpha _ dist1 / (dist1 - dist2); -- clip it pOut.x _ p1.x * (1.0 - alpha) + p1.x * alpha; pOut.y _ p1.y * (1.0 - alpha) + p1.y * alpha; pOut.z _ p1.z * (1.0 - alpha) + p1.z * alpha; IF dist1 > 0.0 THEN RETURN [p1, pOut, clipped] ELSE RETURN [p2, pOut, clipped]; }; }; DrawRGBLine: PUBLIC PROC[context: REF Context, inP1, inP2: Triple, clr: RGB] ~ { <> p1, p2: Triple; code1, code2, orOfCodes : ThreeDScenes.OutCode; [p1, code1] _ ThreeDScenes.XfmPtToEyeSpace[context, inP1]; -- xfm and get clip code [p2, code2] _ ThreeDScenes.XfmPtToEyeSpace[context, inP2]; orOfCodes _ LOOPHOLE[ Basics.BITOR[ LOOPHOLE[code1], LOOPHOLE[code2] ], ThreeDScenes.OutCode ]; IF orOfCodes # ThreeDScenes.NoneOut -- not all inside? THEN { andOfCodes: ThreeDScenes.OutCode _ LOOPHOLE[ Basics.BITAND[LOOPHOLE[code1], LOOPHOLE[code2] ], ThreeDScenes.OutCode ]; IF andOfCodes # ThreeDScenes.NoneOut -- all outside? THEN RETURN[] ELSE { -- clipping needed, do it clipState: ThreeDScenes.ClipState; IF orOfCodes.near THEN [p1, p2, clipState] _ ClipLineWithPlane[ context.clippingPlanes[Near], p1, p2]; IF orOfCodes.far THEN [p1, p2, clipState] _ ClipLineWithPlane[ context.clippingPlanes[Far], p1, p2]; IF orOfCodes.left THEN [p1, p2, clipState] _ ClipLineWithPlane[ context.clippingPlanes[Left], p1, p2]; IF orOfCodes.right THEN [p1, p2, clipState] _ ClipLineWithPlane[ context.clippingPlanes[Right], p1, p2]; IF orOfCodes.bottom THEN [p1, p2, clipState] _ ClipLineWithPlane[ context.clippingPlanes[Bottom], p1, p2]; IF orOfCodes.top THEN [p1, p2, clipState] _ ClipLineWithPlane[ context.clippingPlanes[Top], p1, p2]; }; }; p1 _ ThreeDScenes.XfmPtToDisplay[context, p1]; -- xfm to screen p2 _ ThreeDScenes.XfmPtToDisplay[context, p2]; clrValues _ RGBtoPixelValue[context, clr, clrValues]; ScanConvert.PutLine[ context.display, [Real.FixC[p1.x], Real.FixC[p1.y] ], [Real.FixC[p2.x], Real.FixC[p2.y] ], clrValues ]; }; PrependWorkingDirectory: PUBLIC PROC[context: REF ThreeDScenes.Context, file: Rope.ROPE] RETURNS[Rope.ROPE] ~ { wDir: Rope.ROPE _ NARROW[ Atom.GetPropFromList[context.props, $WDir] ]; IF wDir = NIL THEN RETURN[file] ELSE IF file = NIL OR (Rope.Index[s1: file, s2: "/"] > 0 AND Rope.Index[s1: file, s2: "["] > 0) THEN file _ Rope.Cat[ wDir, file ]; -- if first char not / or [ then prepend wDir RETURN[ file ]; }; ElapsedTime: PROC[startTime: REAL] RETURNS[Rope.ROPE] ~ { RETURN[ Rope.Cat[ Convert.RopeFromCard[ Real.FixC[BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]] - startTime] ], " secs. " ] ]; }; CurrentTime: PROC[] RETURNS[REAL] ~ { RETURN[ BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]] ]; }; GetImagerContext: PUBLIC PROC[context: REF ThreeDScenes.Context] RETURNS[Imager.Context] ~ { imagerCtx: Imager.Context _ NIL; ref: REF ANY _ Atom.GetPropFromList[context.display.props, $ImagerContext]; IF ref # NIL THEN imagerCtx _ NARROW[ref, Imager.Context] ELSE SIGNAL ThreeDScenes.Error[[$Condition, "No Imager context"]]; RETURN[imagerCtx]; }; SetViewPortFromImager: PUBLIC PROC[context: REF ThreeDScenes.Context, imagerCtx: Imager.Context] ~ { bounds: Imager.Rectangle _ ImagerBackdoor.GetBounds[imagerCtx]; ThreeDScenes.SetViewPort[ context, bounds ]; -- set clippers etc. }; CopyContextData: PUBLIC PROC [dstCtx, srcCtx: REF ThreeDScenes.Context] ~ { dstCtx.shapes _ srcCtx.shapes; dstCtx.lights _ srcCtx.lights; dstCtx.environment _ srcCtx.environment; dstCtx.eyePoint _ srcCtx.eyePoint; dstCtx.ptOfInterest _ srcCtx.ptOfInterest; dstCtx.rollAngle _ srcCtx.rollAngle; dstCtx.upDirection _ srcCtx.upDirection; dstCtx.fieldOfView _ srcCtx.fieldOfView; dstCtx.window _ srcCtx.window; dstCtx.hitherLimit _ srcCtx.hitherLimit; dstCtx.yonLimit _ srcCtx.yonLimit; dstCtx.clippingPlanes _ srcCtx.clippingPlanes; dstCtx.eyeSpaceXfm _ srcCtx.eyeSpaceXfm; dstCtx.eyeToNDC _ srcCtx.eyeToNDC; <> dstCtx.viewPort _ srcCtx.viewPort; dstCtx.renderMode _ srcCtx.renderMode; dstCtx.lineDrawing _ srcCtx.lineDrawing; dstCtx.depthResolution _ srcCtx.depthResolution; dstCtx.sortSequence _ srcCtx.sortSequence; dstCtx.props _ srcCtx.props; }; RegisterSurfaceType: PUBLIC PROC[context: REF Context, type: ATOM] ~ { procRecord: REF ThreeDSurfaces.PatchProcs _ NEW[ThreeDSurfaces.PatchProcs]; SELECT type FROM $ConvexPolygon => RETURN[]; $Bezier => { procRecord.expand _ StandardPatches.BezierExpand; procRecord.subdivide _ StandardPatches.BezierSubdivide; procRecord.display _ StandardPatches.BezierDisplay; procRecord.displayLines _ StandardPatches.BezierDisplayLines; ThreeDSurfaces.RegisterSurfaceType[ context, $Bezier, procRecord]; }; ENDCASE => SIGNAL ThreeDScenes.Error[[$UnImplemented, "Unknown surface type"]]; }; StartLog: PUBLIC PROC [context: REF Context] RETURNS[IO.STREAM] ~ { log: IO.STREAM; [out: log] _ ViewerIO.CreateViewerStreams[ name: "ThreeDWorld.log", backingFile: PrependWorkingDirectory[context, "ThreeDWorld.log"] ]; context.props _ Atom.PutPropOnList[context.props, $Log, log]; RETURN[ log ]; }; FlushLog: PUBLIC PROC [context: REF Context] ~ { log: IO.STREAM _ NARROW[Atom.GetPropFromList[context.props, $Log]]; IF log # NIL THEN IO.Flush[log]; }; CloseLog: PUBLIC PROC [context: REF Context] ~ { log: IO.STREAM _ NARROW[Atom.GetPropFromList[context.props, $Log]]; IF log # NIL THEN IO.Close[log]; }; Sgn: PROC [number: REAL] RETURNS [REAL] ~ INLINE { IF number < 0. THEN RETURN[-1.] ELSE RETURN[1.]; }; <> GetMappedColor: PUBLIC PROC[context: REF ThreeDScenes.Context, clr: IntRGB] RETURNS[Pixels.BYTE] ~ { value: NAT _ ScanConvert.MappedRGB[context.renderMode, clr]; RETURN[value]; }; SetNamedColor: PUBLIC PROC [context: REF ThreeDScenes.Context, color: Rope.ROPE] ~ { clr: RGB _ ImagerColor.RGBFromHSL[ NamedColors.RopeToHSL[color] ]; Imager.SetColor[ GetImagerContext[context], ImagerColor.ColorFromRGB[clr] ]; }; SetRGBColor: PUBLIC PROC [context: REF ThreeDScenes.Context, clr: RGB] ~ { Imager.SetColor[ GetImagerContext[context], ImagerColor.ColorFromRGB[clr] ]; }; LoadStd8BitClrMap: PUBLIC PROC [vt: Terminal.Virtual] ~ { Linearize: PROC [value: REAL] RETURNS[NAT] ~ { RETURN[ Real.RoundC[RealFns.Power[value / 255.0, .43] * 255.0] ]; }; vt.SetColor[0, 0, 0, 0, 0]; vt.SetColor[1, 0, 0, 0, 0]; FOR i: NAT IN [2..254) DO -- 6 x 7 x 6 color cube j: NAT _ i - 2; red: NAT _ Linearize[51.0 * (j/42)]; grn: NAT _ Linearize[42.5 * ((j/6) MOD 7)]; blu: NAT _ Linearize[51.0 * (j MOD 6)]; vt.SetColor[i, 0, red, grn, blu]; ENDLOOP; vt.SetColor[254, 0, 255, 255, 255]; vt.SetColor[255, 0, 255, 255, 255]; }; <<>> Rotate8BitClrMap: PUBLIC PROC [vt: Terminal.Virtual, firstValue, lastValue, duration: NAT _ 0] ~ { <> r, g, b: ARRAY [0..256) OF [0..256); times: NAT; IF lastValue = 0 THEN lastValue _ 255; FOR i: NAT IN [firstValue .. lastValue] DO [r[i], g[i], b[i]] _ Terminal.GetColor[ vt, i]; ENDLOOP; IF duration = 0 THEN times _ 0 -- will be one complete cycle ELSE times _ duration * 75; -- seconds times fields per second times _ times + -- Fill out full cycle (lastValue - firstValue + 1) - times MOD (lastValue - firstValue + 1); FOR i: NAT IN [0..times) DO tr, tg, tb: [0..256); CedarProcess.CheckAbort[]; -- check for external abort request before proceeding vt.WaitForBWVerticalRetrace[]; -- await top of scan (to control update rate) tr _ r[firstValue]; tg _ g[firstValue]; tb _ b[firstValue]; FOR j: NAT IN (firstValue .. lastValue] DO r[j-1] _ r[j]; g[j-1] _ g[j]; b[j-1] _ b[j]; ENDLOOP; r[lastValue] _ tr; g[lastValue] _ tg; b[lastValue] _ tb; FOR i: NAT IN [firstValue .. lastValue] DO Terminal.SetColor[ vt, i, 0, r[i], g[i], b[i]]; ENDLOOP; ENDLOOP; }; Show8BitClrMap: PUBLIC PROC [context: REF ThreeDScenes.Context] ~ { firstBottom: INTEGER _ Real.FixC[.75 * context.viewPort.h]; size: INTEGER _ Real.FixC[ .025 * MIN[context.viewPort.h, context.viewPort.w] ]; firstTop: INTEGER _ firstBottom + size; firstLeft: INTEGER _ Real.FixC[context.viewPort.w/2.0] - 16*size; firstRight: INTEGER _ firstLeft + size; FOR i: NAT IN [0..256) DO top: NAT _ firstTop + size * (i / 32); bottom: NAT _ firstBottom + size * (i / 32); left: NAT _ firstLeft + size * (i MOD 32); right: NAT _ firstRight + size * (i MOD 32); Pixels.ValueOp[context.display, [left, bottom, right-left, top-bottom], i]; ENDLOOP; }; LoadColorRamp: PUBLIC PROC [vt: Terminal.Virtual, clr1, clr2, exponent: RGB] ~ { state: Terminal.ColorMode _ vt.GetColorMode[]; maxVal: REAL _ IF state.full THEN 255.0 ELSE Real.Float[Basics.BITSHIFT[1, state.bitsPerPixelChannelA] - 1]; clr1.R _ MAX[0.0, MIN[1.0, clr1.R]]; clr2.R _ MAX[0.0, MIN[1.0, clr2.R]]; clr1.G _ MAX[0.0, MIN[1.0, clr1.G]]; clr2.G _ MAX[0.0, MIN[1.0, clr2.G]]; clr1.B _ MAX[0.0, MIN[1.0, clr1.B]]; clr2.B _ MAX[0.0, MIN[1.0, clr2.B]]; FOR i: NAT IN [ 0 .. Real.FixC[maxVal] ] DO -- linear ramp exponentiated jr: [0..256) _ Real.FixC[ RealFns.Power[clr1.R + i/maxVal * (clr2.R - clr1.R), exponent.R] * maxVal]; jg: [0..256) _ Real.FixC[ RealFns.Power[clr1.G + i/maxVal * (clr2.G - clr1.G), exponent.G] * maxVal]; jb: [0..256) _ Real.FixC[ RealFns.Power[clr1.B + i/maxVal * (clr2.B - clr1.B), exponent.B] * maxVal]; IF Terminal.GetColorMode[vt].full THEN { vt.SetRedMap[i, jr]; vt.SetGreenMap[i, jg]; vt.SetBlueMap[i, jb]; } ELSE vt.SetColor[i, 0, jr, jg, jb]; ENDLOOP; }; LoadMultiRamps: PUBLIC PROC [vt: Terminal.Virtual, colors: LIST OF RGB] ~ { clr: REF IntRGBSequence _ NEW[ IntRGBSequence[32] ]; numClrs, thisClr, nextClr, rampLength: NAT _ 0; state: Terminal.ColorMode _ vt.GetColorMode[]; maxVal: REAL _ IF state.full THEN 255.0 ELSE Real.Float[Basics.BITSHIFT[1, state.bitsPerPixelChannelA] - 1]; WHILE colors # NIL DO clr[numClrs].r _ Real.FixC[maxVal * MAX[0.0, MIN[1.0, colors.first.R]] ]; clr[numClrs].g _ Real.FixC[maxVal * MAX[0.0, MIN[1.0, colors.first.G]] ]; clr[numClrs].b _ Real.FixC[maxVal * MAX[0.0, MIN[1.0, colors.first.B]] ]; numClrs _ numClrs + 1; colors _ colors.rest; ENDLOOP; rampLength _ Real.FixC[maxVal] / (numClrs-1); FOR i: NAT IN [ 0 .. Real.FixC[maxVal] ] DO jr, jg, jb: [0..256); position: NAT _ i MOD rampLength; IF position = 0 THEN IF nextClr < numClrs-1 THEN { thisClr _ nextClr; nextClr _ nextClr + 1; } ELSE thisClr _ nextClr; jr _ clr[thisClr].r * (rampLength - position) / rampLength + clr[nextClr].r * position / rampLength; jg _ clr[thisClr].g * (rampLength - position) / rampLength + clr[nextClr].g * position / rampLength; jb _ clr[thisClr].b * (rampLength - position) / rampLength + clr[nextClr].b * position / rampLength; IF Terminal.GetColorMode[vt].full THEN { vt.SetRedMap[i, jr]; vt.SetGreenMap[i, jg]; vt.SetBlueMap[i, jb]; } ELSE vt.SetColor[i, 0, jr, jg, jb]; ENDLOOP; }; AdjustValueRamp: PUBLIC PROC[context: REF ThreeDScenes.Context, exponent: RGB] ~ { <> Action: PROC[] ~ { scanSeg: REF Pixels.SampleSetSequence _ NIL; maxValue: REAL _ 255.0; expTableR: REF NatSequence _ NEW[ NatSequence[256] ]; expTableG: REF NatSequence _ NEW[ NatSequence[256] ]; expTableB: REF NatSequence _ NEW[ NatSequence[256] ]; start: NAT _ IF context.alphaBuffer THEN 1 ELSE 0; SELECT context.renderMode FROM $FullClr, $Dorado24 => FOR i: NAT IN [0..256) DO expTableR[i] _ Real.RoundC[ RealFns.Power[ i/255.0, exponent.R] * 255.0 ]; expTableG[i] _ Real.RoundC[ RealFns.Power[ i/255.0, exponent.G] * 255.0 ]; expTableB[i] _ Real.RoundC[ RealFns.Power[ i/255.0, exponent.B] * 255.0 ]; ENDLOOP; $Grey => { exp: REAL _ (exponent.R + exponent.G + exponent.B) / 3.0; FOR i: NAT IN [0..256) DO expTableG[i] _ Real.RoundC[ RealFns.Power[ i/255.0, exp] * 255.0 ]; ENDLOOP; }; ENDCASE => SIGNAL ThreeDScenes.Error[[$MisMatch, "Improper renderMode"]]; FOR y: NAT IN [ 0 .. Real.RoundC[context.viewPort.h] ) DO scanSeg _ Pixels.GetScanSeg[context.display, 0, y, Real.RoundC[context.viewPort.w], scanSeg]; FOR x: NAT IN [ 0 .. Real.RoundC[context.viewPort.w] ) DO SELECT context.renderMode FROM $FullClr, $Dorado24 => FOR i: NAT IN [start .. start+3) DO SELECT i FROM start => scanSeg[i][x] _ expTableR[scanSeg[i][x]]; start+1 => scanSeg[i][x] _ expTableG[scanSeg[i][x]]; start+2 => scanSeg[i][x] _ expTableB[scanSeg[i][x]]; ENDCASE; ENDLOOP; $Grey => scanSeg[start][x] _ expTableG[scanSeg[start][x]]; ENDCASE => SIGNAL ThreeDScenes.Error[[$MisMatch, "Improper renderMode"]]; ENDLOOP; Pixels.PutScanSeg[context.display, 0, y, Real.RoundC[context.viewPort.w], scanSeg]; ENDLOOP; }; CedarProcess.DoWithPriority[background, Action]; }; AdjustSaturation: PUBLIC PROC[context: REF ThreeDScenes.Context, percent: REAL] ~ { <> Action: PROC[] ~ { scanSeg: REF Pixels.SampleSetSequence _ NIL; maxValue: REAL _ 255.0; start: NAT _ IF context.alphaBuffer THEN 1 ELSE 0; FOR y: NAT IN [ 0 .. Real.RoundC[context.viewPort.h] ) DO scanSeg _ Pixels.GetScanSeg[context.display, 0, y, Real.RoundC[context.viewPort.w], scanSeg]; FOR x: NAT IN [ 0 .. Real.RoundC[context.viewPort.w] ) DO SELECT context.renderMode FROM $FullClr, $Dorado24 => { scale: REAL; redVal: CARDINAL _ scanSeg[start][x]; grnVal: CARDINAL _ scanSeg[start+1][x]; bluVal: CARDINAL _ scanSeg[start+2][x]; min: CARDINAL _ MIN[redVal, grnVal, bluVal]; max: CARDINAL _ MAX[redVal, grnVal, bluVal]; newMin: CARDINAL _ MIN[max, Real.FixC[percent * min]]; IF (min = 0) OR (max - min = 0) THEN LOOP; scale _ 1.0 * (max - newMin) / (max - min); redVal _ Real.FixC[ (redVal - min) * scale + newMin ]; grnVal _ Real.FixC[ (grnVal - min) * scale + newMin ]; bluVal _ Real.FixC[ (bluVal - min) * scale + newMin ]; scanSeg[start ][x] _ redVal; scanSeg[start+1][x] _ grnVal; scanSeg[start+2][x] _ bluVal; }; ENDCASE => SIGNAL ThreeDScenes.Error[[$MisMatch, "Improper renderMode"]]; ENDLOOP; Pixels.PutScanSeg[context.display, 0, y, Real.RoundC[context.viewPort.w], scanSeg]; ENDLOOP; }; CedarProcess.DoWithPriority[background, Action]; }; LoadOldStd8BitClrMap: PUBLIC PROC [vt: Terminal.Virtual] ~ { Linearize: PROC [value: REAL] RETURNS[NAT] ~ { RETURN[ Real.RoundC[RealFns.Power[value / 255.0, .43] * 255.0] ]; }; FOR i: NAT IN [0..40) DO -- greyscale grey: NAT _ Linearize[i*6.5]; vt.SetColor[i + 216, 0, grey, grey, grey]; ENDLOOP; FOR i: NAT IN [0..216) DO -- 6 x 6 x 6 color cube vt.SetColor[i, 0, Linearize[42.5 * (i/36 + 1)], Linearize[42.5 * ((i/6) MOD 6 + 1)], Linearize[42.5 * (i MOD 6 + 1)] ]; ENDLOOP; vt.SetColor[0, 0, 0, 0, 0]; }; <<>> SetUpTerrainColors: PUBLIC PROC[vt: Terminal.Virtual] ~ { -- for setting up colors for old terrain pictures terrainHues: ARRAY [0..4) OF RGB _ [[.05, .4, .0], [.5, .6, .1], [.4, .4, .4], [1., 1., 1.]]; <<{ forest, savannah, rock, snow }>> skyHue: RGB _ [.5, .5, 1.0]; waterHue: RGB _ [.2, .2, .8]; start: NAT _ 8; -- start^ _ 8; length: NAT _ 240; valueStepSize, minValue, rampValue, index, hueRampSize: NAT _ 0; hueRampSize _ 238 / (LENGTH[terrainHues] + 1); valueStepSize _ 256 / hueRampSize; minValue _ 256 - valueStepSize*hueRampSize; FOR j: NAT IN [0..4) DO -- do hue steps from each hue to next currentHue: RGB _ [terrainHues[j].R, terrainHues[j].G, terrainHues[j].B]; rampValue _ minValue; FOR i: NAT IN [0..hueRampSize) DO -- build hue ramps r, g, b: NAT; r _ Real.RoundC[ rampValue * currentHue.R ]; g _ Real.RoundC[ rampValue * currentHue.G ]; b _ Real.RoundC[ rampValue * currentHue.B ]; vt.SetColor[index+start, 0, r, g, b ]; rampValue _ rampValue + valueStepSize; index _ index + 1; ENDLOOP; ENDLOOP; vt.SetColor[239+start, 0, Real.FixC[skyHue.R*255], Real.FixC[skyHue.G*255], Real.FixC[skyHue.B*255] ]; vt.SetColor[start, 0, Real.FixC[waterHue.R*255], Real.FixC[waterHue.G*255], Real.FixC[waterHue.B*255] ]; }; <<>> ShowRope: PUBLIC PROC[context: REF ThreeDScenes.Context, x, y: REAL, rope: Rope.ROPE, fontRope: Rope.ROPE _ NIL, size: REAL _ 20] ~{ imagerCtx: Imager.Context _ GetImagerContext[context]; font: Imager.Font; IF fontRope = NIL THEN fontRope _ "Xerox/Pressfonts/TimesRoman-MRR"; font _ ImagerFont.Find[fontRope]; font _ ImagerFont.Scale[font, size]; Imager.SetFont[imagerCtx, font]; Imager.SetXY[imagerCtx, [x, y]]; Imager.ShowRope[imagerCtx, rope]; }; <> DitherImage: PUBLIC PROC[dstContext, rgbContext: REF ThreeDScenes.Context] ~ { Action: PROC ~ { width: NAT _ Real.FixI[MIN[dstContext.viewPort.w, rgbContext.viewPort.w] ]; height: NAT _ Real.FixI[MIN[dstContext.viewPort.h, rgbContext.viewPort.h] ]; scanSegIn, scanSegOut: REF Pixels.SampleSetSequence _ NIL; IF rgbContext.display.samplesPerPixel < 3 THEN SIGNAL ThreeDScenes.Error[[$MisMatch, "24-bit input needed for dithering"]]; FOR y: NAT IN [0..height) DO scanSegIn _ Pixels.GetScanSeg[rgbContext.display, 0, y, Real.RoundC[rgbContext.viewPort.w], scanSegIn]; scanSegOut _ Pixels.GetScanSeg[dstContext.display, 0, y, Real.RoundC[dstContext.viewPort.w], scanSegOut]; FOR x: NAT IN [0..width) DO scanSegOut[0][x] _ ScanConvert.DitheredRGB[$PseudoClr, x, y, scanSegIn[0][x], scanSegIn[1][x], scanSegIn[2][x] ]; ENDLOOP; Pixels.PutScanSeg[dstContext.display, 0, y, Real.RoundC[dstContext.viewPort.w], scanSegOut]; ENDLOOP; }; CedarProcess.DoWithPriority[background, Action]; -- be nice to other processess }; ScaleDownImage: PUBLIC PROC[dstContext, srcContext: REF Context] ~ { <> Action: PROC ~ { srcHght: NAT _ Real.RoundC[srcContext.viewPort.h]; dstHght: NAT _ Real.RoundC[dstContext.viewPort.h]; srcWdth: NAT _ Real.RoundC[srcContext.viewPort.w]; dstWdth: NAT _ Real.RoundC[dstContext.viewPort.w]; numHits: REF NatSequence _ NEW[ NatSequence[dstWdth] ]; xPos, yPos: INTEGER; xCtr, yCtr: NAT _ 0; scanSegIn, scanSegOut: REF Pixels.SampleSetSequence _ NIL; scanSegOut _ Pixels.GetScanSeg[dstContext.display, 0, 0, dstWdth]; FOR x: NAT IN [0..dstWdth) DO -- clear the pixels FOR i: NAT IN [0..scanSegOut.length) DO scanSegOut[i][x] _ 0; ENDLOOP; ENDLOOP; yPos _ 2 * dstHght - srcHght; FOR x: NAT IN [0..dstWdth) DO numHits[x] _ 0; ENDLOOP; FOR y: NAT IN [ 0 .. srcHght ) DO -- work up through source scan lines scanSegIn _ Pixels.GetScanSeg[srcContext.display, 0, y, srcWdth, scanSegIn]; xPos _ 2 * dstWdth - srcWdth; xCtr _ 0; FOR x: NAT IN [ 0 .. srcWdth ) DO -- work across source scan line FOR i: NAT IN [0..scanSegOut.length) DO scanSegOut[i][xCtr] _ scanSegOut[i][xCtr] + scanSegIn[i][x]; -- sum intensities ENDLOOP; numHits[xCtr] _ numHits[xCtr] + 1; -- sum hits per pixel IF xPos > 0 THEN { xCtr _ xCtr + 1; xPos _ xPos - 2 * srcWdth; IF xCtr > dstWdth THEN EXIT; }; xPos _ xPos + 2 * dstWdth; ENDLOOP; IF yPos > 0 THEN { -- big increment exceeded FOR x: NAT IN [0..dstWdth) DO FOR i: NAT IN [0..scanSegOut.length) DO scanSegOut[i][x] _ scanSegOut[i][x] / numHits[x]; ENDLOOP; numHits[x] _ 0; ENDLOOP; Pixels.PutScanSeg[dstContext.display, 0, yCtr, dstWdth, scanSegOut]; FOR x: NAT IN [0..dstWdth) DO -- clear the pixels FOR i: NAT IN [0..scanSegOut.length) DO scanSegOut[i][x] _ 0; ENDLOOP; ENDLOOP; yPos _ yPos - 2 * srcHght; -- subtract big increment from position yCtr _ yCtr + 1; IF yCtr > dstHght THEN EXIT; }; yPos _ yPos + 2 * dstHght; -- add in little incrment until big increment exceeded ENDLOOP; }; CedarProcess.DoWithPriority[background, Action]; -- be nice to other processess }; MakeStripes: PUBLIC PROC[context: REF ThreeDScenes.Context, numStripes, min, max, power: REAL] ~ { factor: REAL _ ( numStripes * 2. * 3.1416 ) / Real.RoundC[context.viewPort.w]; maxValue: REAL _ 255.0; scanSeg: REF Pixels.SampleSetSequence _ Pixels.GetScanSeg[context.display, 0, 0, Real.RoundC[context.viewPort.w], scanSeg]; FOR x: NAT IN [ 0 .. Real.RoundC[context.viewPort.w] ) DO sineValue: REAL _ RealFns.Sin[ factor * x ]; sineValue _ RealFns.Power[ABS[sineValue], power] * Sgn[sineValue]; scanSeg[0][x] _ Real.RoundC[maxValue * (((sineValue + 1.) / 2.0) * (max - min) + min)]; ENDLOOP; FOR y: NAT IN [ 0 .. Real.RoundC[context.viewPort.h] ) DO Pixels.PutScanSeg[context.display, 0, y, Real.RoundC[context.viewPort.w], scanSeg]; ENDLOOP; }; MakeStretchedSpots: PUBLIC PROC[context: REF ThreeDScenes.Context, spotsAcross, min, max, power: REAL, stretched: BOOLEAN _ FALSE] ~ { Action: PROC ~ { maxValue: REAL _ 255.0; factor: REAL _ (spotsAcross * 2 * 3.1416) / Real.RoundC[context.viewPort.w]; map: NAT _ IF context.alphaBuffer THEN 1 ELSE 0; FOR y: NAT IN [ 0 .. Real.RoundC[context.viewPort.h] ) DO scanSeg: REF Pixels.SampleSetSequence _ Pixels.GetScanSeg[context.display, 0, y, Real.RoundC[context.viewPort.w] ]; spread: REAL _ IF stretched THEN RealFns.Cos[ 3.1416 * (y - Real.RoundC[context.viewPort.h] / 2.0) / (Real.RoundC[context.viewPort.h]) ] ELSE 1.0; sineY: REAL _ RealFns.Cos[ factor * y ]; sineY _ RealFns.Power[ABS[sineY], power] * Sgn[sineY]; FOR x: NAT IN [ 0 .. Real.RoundC[context.viewPort.w] ) DO sineX: REAL _ RealFns.Cos[ spread * factor * (x - Real.RoundC[context.viewPort.w]/2.0) ]; sineX _ RealFns.Power[ABS[sineX], power] * Sgn[sineX]; scanSeg[0][x] _ Real.RoundC[ maxValue * (((sineX * sineY + 1.) / 2.0) * (max - min) + min) ]; ENDLOOP; Pixels.PutScanSeg[context.display, 0, y, Real.RoundC[context.viewPort.w], scanSeg]; ENDLOOP; }; CedarProcess.DoWithPriority[background, Action]; -- be nice to other processess }; DrawQuad: PUBLIC PROC[context: REF ThreeDScenes.Context, intensity: REAL, x1, y1, x2, y2, x3, y3, x4, y4: REAL] ~ { poly: REF ThreeDSurfaces.Patch _ NEW[ ThreeDSurfaces.Patch[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; Tilers.FancyTiler[context, poly]; }; <> SetAmbientLight: PUBLIC PROC [context: REF ThreeDScenes.Context, color: Rope.ROPE] ~ { ambientColor: REF RGB _ NEW[ RGB _ ImagerColor.RGBFromHSL[ NamedColors.RopeToHSL[color] ] ]; [] _ Atom.PutPropOnList[context.environment, $AmbientLight, ambientColor]; FOR i: NAT IN [0..context.shapes.length) DO context.shapes[i].shadingInValid _ TRUE; ENDLOOP; }; SetBackground: PUBLIC PROC [context: REF ThreeDScenes.Context, color: Rope.ROPE] ~ { bkgrdColor: REF RGB _ NEW[ RGB _ ImagerColor.RGBFromHSL[ NamedColors.RopeToHSL[color] ] ]; context.props _ Atom.PutPropOnList[context.props, $BackGround, bkgrdColor]; -- set color }; GetBackground: PUBLIC PROC [context: REF ThreeDScenes.Context] RETURNS [color: RGB] ~ { ref: REF _ Atom.GetPropFromList[context.props, $BackGround]; -- get background color IF ref # NIL THEN color _ NARROW[ref, REF RGB]^ ELSE color _ [0., 0., 0.]; }; <> Hide: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE] ~ { <> shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; shape.props _ Atom.PutPropOnList[shape.props, $Hidden, $DoIt]; }; Reveal: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE] ~ { -- undo Hide shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; shape.props _ Atom.RemPropFromList[shape.props, $Hidden]; }; MakePlane: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, squaresPerSide: NAT] ~{ surface: REF ThreeDSurfaces.PtrPatchSequence; shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.NewShape[shapeName]; vtcesPerSide: NAT _ squaresPerSide + 1; shape.numSurfaces _ squaresPerSide * squaresPerSide; shape.vertex _ NEW[ ThreeDScenes.VertexSequence[ vtcesPerSide * vtcesPerSide ] ]; shape.boundingRadius _ 1.414; shape.surface _ NEW[ ThreeDSurfaces.PtrPatchSequence[shape.numSurfaces] ]; surface _ NARROW[shape.surface, REF ThreeDSurfaces.PtrPatchSequence]; FOR i: NAT IN [0..shape.vertex.length) DO IF shape.vertex[i] # NIL THEN { divisor: REAL _ Real.Float[squaresPerSide] / 2.; shape.vertex[i] _ NEW[ThreeDScenes.Vertex]; shape.vertex[i].x _ (i / vtcesPerSide) / divisor - 1.; -- x-coordinate shape.vertex[i].y _ (i MOD vtcesPerSide) / divisor - 1.; -- y-coordinate shape.vertex[i].z _ 0.; -- constant z-coordinate }; ENDLOOP; FOR i: INT IN [0..shape.numSurfaces) DO vtxNumber: NAT _ i + (i / squaresPerSide); -- add one at end of each row surface[i] _ NEW[ThreeDSurfaces.PtrPatch[4]]; surface[i].nVtces _ 4; surface[i].vtxPtr[0] _ vtxNumber; surface[i].vtxPtr[1] _ vtxNumber + 1; surface[i].vtxPtr[2] _ vtxNumber + vtcesPerSide + 1; surface[i].vtxPtr[3] _ vtxNumber + vtcesPerSide; ENDLOOP; context.shapes _ ThreeDScenes.AddShape[context.shapes, shape]; }; AddShapeAt: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, fileName: Rope.ROPE, position: Triple_[0.,0.,0.], type: ATOM _ $ConvexPolygon, insideVisible: BOOLEAN _ FALSE] ~ { shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.NewShape[shapeName]; shape.fileName _ PrependWorkingDirectory[context, fileName]; ThreeDSurfaces.LoadShape[ -- get vertices, polygons, etc. shape, PrependWorkingDirectory[context, fileName], type, -- $ConvexPolygon, $Bezier insideVisible ]; ThreeDScenes.PlaceShape[shape, position]; context.shapes _ ThreeDScenes.AddShape[context.shapes, shape]; IF Atom.GetPropFromList[context.props, type] = NIL THEN RegisterSurfaceType[context, type]; }; SetFacetedColor: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, color: RGB] ~ { shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; IF shape # NIL THEN { patchInfo: REF ThreeDScenes.ShadingSequence _ NARROW[ ThreeDScenes.GetShading[ shape, $PatchColors ] ]; IF patchInfo = NIL THEN patchInfo _ NEW[ThreeDScenes.ShadingSequence[shape.numSurfaces] ] ELSE IF ThreeDScenes.GetShading[ shape, $PatchColorFile ] # NIL THEN SIGNAL ThreeDScenes.Error[[$MisMatch, "Patches individually colored"]]; FOR i: NAT IN [0..shape.numSurfaces) DO patchInfo[i] _ NEW[ ThreeDScenes.ShadingValue ]; patchInfo[i].r _ color.R; patchInfo[i].g _ color.G; patchInfo[i].b _ color.B; ENDLOOP; ThreeDScenes.PutShading[shape, $Type, $Faceted]; ThreeDScenes.PutShading[ shape, $Color, NEW[RGB _ color] ]; ThreeDScenes.PutShading[ shape, $PatchColors, patchInfo ]; shape.shade _ ThreeDScenes.InitShades[ shape ]; ThreeDSurfaces.GetPolyNormals[shape ! ThreeDScenes.Error => IF reason.code = $MisMatch THEN CONTINUE ]; }; }; SetSmoothColor: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, color: RGB] ~ { shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; IF shape # NIL THEN { ThreeDScenes.PutShading[shape, $Type, $Smooth]; ThreeDScenes.PutShading[ shape, $Color, NEW[RGB _ color] ]; IF ThreeDScenes.GetShading[ shape, $VertexColorFile ] # NIL THEN SIGNAL ThreeDScenes.Error[[$MisMatch, "Vertices individually colored"]]; shape.shade _ ThreeDScenes.InitShades[ shape ]; -- color vtces ThreeDSurfaces.GetVtxNormals[ shape ! ThreeDScenes.Error => IF reason.code = $MisMatch THEN CONTINUE ]; }; }; SetLinesColor: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, color: RGB] ~ { shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; IF shape # NIL THEN { ThreeDScenes.PutShading[shape, $Type, $Lines]; ThreeDScenes.PutShading[ shape, $Color, NEW[RGB _ color] ]; IF ThreeDScenes.GetShading[ shape, $VertexColorFile ] # NIL THEN SIGNAL ThreeDScenes.Error[[$MisMatch, "Vertices individually colored"]]; shape.shade _ ThreeDScenes.InitShades[ shape ]; -- color vtces }; }; SetShininess: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, shininess: REAL] ~ { shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; IF shape # NIL THEN ThreeDScenes.PutShading[shape, $Shininess, NEW[REAL _ shininess]]; }; SetTransmittance: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE, t: REAL] ~ { shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; IF shape # NIL THEN { ThreeDScenes.PutShading[ shape, $Transmittance, NEW[REAL _ t] ]; IF shape.shade # NIL THEN FOR i: NAT IN [0..shape.shade.length) DO IF shape.shade[i] # NIL THEN shape.shade[i].t _ t; ENDLOOP; }; }; ShadingProcName: PUBLIC PROC[context: REF Context, shapeName, procName: Rope.ROPE ] ~ { shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; shadeProc: ScanConvert.GetColorProc _ SolidTextures.RopeToProc[procName]; storeProc: ThreeDScenes.VtxToRealSeqProc _ SolidTextures.GetLerpedVals; ThreeDScenes.PutShading[ shape, $ShadingProcs, NEW[ ThreeDScenes.ShadingProcs _ [ storeProc, shadeProc ] ] ]; }; GetShadingProcs: PUBLIC PROC[context: REF ThreeDScenes.Context, shapeName: Rope.ROPE, storeProc: ThreeDScenes.VtxToRealSeqProc, shadeProc: ScanConvert.GetColorProc] ~{ shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; ThreeDScenes.PutShading[ shape, $ShadingProcs, NEW[ ThreeDScenes.ShadingProcs _ [ storeProc, shadeProc ] ] ]; }; GetNormals: PUBLIC PROC[context: REF ThreeDScenes.Context, shapeName, normalFile: Rope.ROPE] ~ { shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; stream: IO.STREAM; numEntries: NAT; [stream, numEntries] _ ThreeDScenes.SetUpStandardFile[ PrependWorkingDirectory[context, normalFile] ]; ThreeDScenes.ReadNormals[ shape.shade, stream, numEntries ]; }; GetVertexColors: PUBLIC PROC[context: REF ThreeDScenes.Context, shapeName, colorFile: Rope.ROPE] ~ { shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; stream: IO.STREAM; numEntries: NAT; [stream, numEntries] _ ThreeDScenes.SetUpStandardFile[ PrependWorkingDirectory[context, colorFile] ]; ThreeDScenes.ReadColors[ shape.shade, stream, numEntries ]; ThreeDScenes.PutShading[ shape, $VertexColorFile, colorFile ]; }; GetPolygonColors: PUBLIC PROC[context: REF ThreeDScenes.Context, shapeName, colorFile:Rope.ROPE] ~ { ThreeDSurfaces.GetPatchColors[ ThreeDScenes.FindShape[ context.shapes, shapeName ], PrependWorkingDirectory[context, colorFile] ]; }; GetTextureCoords: PUBLIC PROC[context: REF ThreeDScenes.Context, shapeName, coordinateFile: Rope.ROPE] ~ { <> texture: REF TextureMaps.TextureMap; shape: REF ThreeDScenes.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, shapeName ]; stream: IO.STREAM; numEntries: NAT; [stream, numEntries] _ ThreeDScenes.SetUpStandardFile[ PrependWorkingDirectory[context, coordinateFile] ]; ThreeDScenes.ReadTextureCoords[ shape.shade, stream, numEntries ]; texture _ NARROW[ThreeDScenes.GetShading[shape, $TextureMap], REF TextureMaps.TextureMap]; IF texture = NIL THEN texture _ NEW[TextureMaps.TextureMap]; texture.props _ Atom.PutPropOnList[texture.props, $CoordType, $File]; texture.props _ Atom.PutPropOnList[texture.props, $Coords, coordinateFile]; ThreeDScenes.PutShading[shape, $TextureMap, texture]; }; <> SaveOnFile: PUBLIC PROC[context: REF Context, fileName: Rope.ROPE] ~ { wDir: Rope.ROPE _ PrependWorkingDirectory[context, NIL]; output: IO.STREAM _ FS.StreamOpen[fileName: fileName, accessOptions: $create, wDir: wDir]; IO.PutRope[ output, Rope.Cat[" -- ", fileName, "\n"] ]; ThreeDScenes.WriteScene[context, output]; IO.Close[output]; }; RestoreFromFile: PUBLIC PROC[context: REF Context, fileName: Rope.ROPE] ~ { wDir: Rope.ROPE _ PrependWorkingDirectory[context, NIL]; input: IO.STREAM _ FS.StreamOpen[fileName: fileName, accessOptions: $read, wDir: wDir]; [] _ IO.GetLineRope[ input ]; -- ignore first line ThreeDScenes.ReadScene[context, input]; IO.Close[input]; }; MakeFrameFromFile: PUBLIC PROC[context: REF Context, fileName: Rope.ROPE] ~ { wDir: Rope.ROPE _ NARROW[ Atom.GetPropFromList[context.props, $WDir] ]; time: REAL; log: IO.STREAM _ NARROW[ Atom.GetPropFromList[context.props, $Log] ]; bufferCtx: REF ThreeDScenes.Context _ ThreeDScenes.Create[ 10, 10, context.renderMode, context.alphaBuffer, context.depthBuffer ]; bufferCtx.display _ context.display; bufferCtx.props _ Atom.PutPropOnList[bufferCtx.props, $WDir, wDir]; time _ CurrentTime[]; RestoreFromFile[bufferCtx, fileName]; -- may mash viewport IF log # NIL THEN log.PutRope[ Rope.Cat[ "Setup Time: ", ElapsedTime[time], "\n"] ]; MakeFrame[bufferCtx]; bufferCtx _ NIL; ThreeDScenes.SetViewPort[context, context.viewPort]; -- restore viewport }; <> MakeFrame: PUBLIC PROC[context: REF ThreeDScenes.Context] ~ { time: REAL _ CurrentTime[]; log: IO.STREAM _ NARROW[ Atom.GetPropFromList[context.props, $Log] ]; IF context.alphaBuffer THEN ThreeDScenes.FillViewPort[context, [0.0,0.0,0.0] ] -- clear screen and alpha buffer ELSE ThreeDScenes.FillInBackGround[context]; -- load background IF context.lineDrawing AND NOT context.alphaBuffer THEN ShowWireFrameShapes[context] ELSE ShowShapes[context]; IF context.alphaBuffer THEN ThreeDScenes.FillInBackGround[context]; -- load background IF log # NIL THEN { log.PutRope[ Rope.Cat[ "Home Processor Frame Time: ", ElapsedTime[time], "\n"] ]; FlushLog[context]; }; }; MakeHiResFrame: PUBLIC PROC[context: REF ThreeDScenes.Context, width, height: NAT, name: Rope.ROPE] ~ { time: REAL _ CurrentTime[]; log: IO.STREAM _ NARROW[ Atom.GetPropFromList[context.props, $Log] ]; hiResCtxt: REF ThreeDScenes.Context _ ThreeDScenes.Create[ width, height, context.renderMode, context.alphaBuffer ]; CopyContextData[dstCtx: hiResCtxt, srcCtx: context]; hiResCtxt.viewPort _ [ x: 0.0, y: 0.0, w: Real.Float[width], h: Real.Float[height] ]; [] _ StartLog[hiResCtxt]; FOR i: NAT IN [0..hiResCtxt.shapes.length) DO hiResCtxt.shapes[i].vtcesInValid _ TRUE; ENDLOOP; IF hiResCtxt.alphaBuffer THEN ThreeDScenes.FillViewPort[hiResCtxt, [0.0,0.0,0.0] ] -- clear screen and alpha buffer ELSE ThreeDScenes.FillInBackGround[hiResCtxt]; -- load background IF hiResCtxt.lineDrawing AND NOT hiResCtxt.alphaBuffer THEN ShowWireFrameShapes[hiResCtxt] ELSE ShowShapes[hiResCtxt]; IF hiResCtxt.alphaBuffer -- load background THEN ThreeDScenes.FillInBackGround[hiResCtxt]; AISAnimation.PutAIS[hiResCtxt, name ]; IF log # NIL THEN { log.PutRope[ Rope.Cat[ "Home Processor Frame Time: ", ElapsedTime[time], "\n"] ]; FlushLog[context]; }; }; ShowShapes: PUBLIC PROC[context: REF ThreeDScenes.Context] ~ { Action: PROC ~ { ThreeDSurfaces.ShowObjects[ context: context, frontToBack: context.alphaBuffer ] }; CedarProcess.DoWithPriority[background, Action]; }; ShowWireFrameShapes: PUBLIC PROC[context: REF ThreeDScenes.Context] ~ { Action: PROC ~ { ThreeDSurfaces.ShowWireFrameObjects[ context ]; }; CedarProcess.DoWithPriority[background, Action]; }; OrbitEye: PUBLIC PROC[context: REF ThreeDScenes.Context, lookingFrom, lookingAt, axis: Triple, framesPerRev: NAT, filename: Rope.ROPE _ NIL, numFrames: NAT _ 32767, startAt: NAT _ 0] ~ { frameNo: NAT _ startAt; bufContext, ditherContext: REF ThreeDScenes.Context _ NIL; NewFrame: PROC[lookingFrom, lookingAt: Triple] ~ { ThreeDScenes.SetView[ bufContext, lookingFrom, lookingAt]; MakeFrame[bufContext]; IF bufContext # context THEN Pixels.Transfer[ context.display, bufContext.display]; CedarProcess.CheckAbort[]; -- check for external abort request before proceeding IF filename # NIL THEN IF context.renderMode = $Dorado24 OR context.renderMode = $FullClr THEN { DitherImage[ditherContext, context]; AISAnimation.StoreFiles[ditherContext, filename, frameNo]; } ELSE AISAnimation.StoreFiles[context, filename, frameNo]; frameNo _ frameNo + 1; }; IF filename = NIL AND context.renderMode # $LF AND context.renderMode # $Dithered THEN { -- double buffer if not storing files bufContext _ ThreeDScenes.Create[ context.display.pixels[0].subMap.size.f, context.display.pixels[0].subMap.size.s, context.renderMode, context.alphaBuffer ]; CopyContextData[dstCtx: bufContext, srcCtx: context]; } ELSE { -- no double buffer if storing files or using Imager bufContext _ context; IF context.renderMode = $Dorado24 OR context.renderMode = $FullClr THEN ditherContext _ ThreeDScenes.Create[ context.display.pixels[context.display.samplesPerPixel-1].subMap.size.f, context.display.pixels[context.display.samplesPerPixel-1].subMap.size.s, $PseudoClr, ]; }; Animation3D.MoveInOrbit[ lookingFrom, lookingAt, axis, NewFrame, framesPerRev, numFrames, startAt ]; }; MakeFramesFromTo: PUBLIC PROC[context: REF ThreeDScenes.Context, lookingFrom, lookingAt, toLookingFrom, toLookingAt: Triple, numFrames: NAT, startAt: NAT _ 0, filename: Rope.ROPE _ NIL] ~ { frameNo: NAT _ startAt; NewFrame: PROC[lookingFrom, lookingAt: Triple] ~ { ThreeDScenes.SetView[ context, lookingFrom, lookingAt]; MakeFrame[context]; CedarProcess.CheckAbort[]; -- check for external abort request before proceeding frameNo _ frameNo + 1; IF filename # NIL THEN AISAnimation.StoreFiles[context, filename, frameNo]; }; Animation3D.MoveOnLine[ lookingFrom, lookingAt, toLookingFrom, toLookingAt, NewFrame, numFrames, startAt ]; }; END.